Skip to main content

rtc_rtcp/extended_report/
rle.rs

1//! Loss and Duplicate RLE report blocks.
2//!
3//! Both blocks report per-packet status over a sequence-number range, run-length encoded: a
4//! [`Chunk`](crate::extended_report::rle::Chunk) is either a run of identical values or an explicit 15-bit vector. That keeps a report
5//! covering a long range compact while still describing individual packets.
6//!
7//! The same structure serves both blocks; [`RLEReportBlock::is_loss_rle`](crate::extended_report::rle::RLEReportBlock::is_loss_rle) selects which.
8use super::*;
9
10const RLE_REPORT_BLOCK_MIN_LENGTH: u16 = 8;
11
12/// ChunkType enumerates the three kinds of chunks described in RFC 3611 section 4.1.
13#[derive(Debug, Copy, Clone, PartialEq, Eq)]
14pub enum ChunkType {
15    /// A run-length chunk: a bit value repeated a stated number of times.
16    RunLength = 0,
17    /// A bit-vector chunk: 15 explicit per-packet bits.
18    BitVector = 1,
19    /// The terminating null chunk, which pads the block to a word boundary.
20    TerminatingNull = 2,
21}
22
23/// Chunk as defined in RFC 3611, section 4.1. These represent information
24/// about packet losses and packet duplication. They have three representations:
25///
26/// Run Length Chunk:
27///
28///   0                   1
29///   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
30///  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
31///  |C|R|        run length         |
32///  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
33///
34/// Bit Vector Chunk:
35///
36///   0                   1
37///   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
38///  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
39///  |C|        bit vector           |
40///  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
41///
42/// Terminating Null Chunk:
43///
44///   0                   1
45///   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
46///  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
47///  |0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0|
48///  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
49#[derive(Debug, Default, PartialEq, Eq, Clone)]
50pub struct Chunk(pub u16);
51
52impl fmt::Display for Chunk {
53    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
54        match self.chunk_type() {
55            ChunkType::RunLength => {
56                let run_type = self.run_type().unwrap_or(0);
57                write!(f, "[RunLength type={}, length={}]", run_type, self.value())
58            }
59            ChunkType::BitVector => write!(f, "[BitVector {:#b}", self.value()),
60            ChunkType::TerminatingNull => write!(f, "[TerminatingNull]"),
61        }
62    }
63}
64impl Chunk {
65    /// chunk_type returns the ChunkType that this Chunk represents
66    pub fn chunk_type(&self) -> ChunkType {
67        if self.0 == 0 {
68            ChunkType::TerminatingNull
69        } else if (self.0 >> 15) == 0 {
70            ChunkType::RunLength
71        } else {
72            ChunkType::BitVector
73        }
74    }
75
76    /// run_type returns the run_type that this Chunk represents. It is
77    /// only valid if ChunkType is RunLengthChunkType.
78    pub fn run_type(&self) -> Result<u8> {
79        if self.chunk_type() != ChunkType::RunLength {
80            Err(Error::WrongChunkType)
81        } else {
82            Ok((self.0 >> 14) as u8 & 0x01)
83        }
84    }
85
86    /// value returns the value represented in this Chunk
87    pub fn value(&self) -> u16 {
88        match self.chunk_type() {
89            ChunkType::RunLength => self.0 & 0x3FFF,
90            ChunkType::BitVector => self.0 & 0x7FFF,
91            ChunkType::TerminatingNull => 0,
92        }
93    }
94}
95
96/// RleReportBlock defines the common structure used by both
97/// Loss RLE report blocks (RFC 3611 §4.1) and Duplicate RLE
98/// report blocks (RFC 3611 §4.2).
99///
100///  0                   1                   2                   3
101///  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
102/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
103/// |  BT = 1 or 2  | rsvd. |   t   |         block length          |
104/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
105/// |                        ssrc of source                         |
106/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
107/// |          begin_seq            |             end_seq           |
108/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
109/// |          chunk 1              |             chunk 2           |
110/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
111/// :                              ...                              :
112/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
113/// |          chunk n-1            |             chunk n           |
114/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
115#[derive(Debug, Default, PartialEq, Eq, Clone)]
116pub struct RLEReportBlock {
117    //not included in marshal/unmarshal
118    /// `true` for a Loss RLE block, `false` for a Duplicate RLE block.
119    pub is_loss_rle: bool,
120    /// The block's `T` field.
121    pub t: u8,
122
123    //marshal/unmarshal
124    /// The SSRC whose packets are reported on.
125    pub ssrc: u32,
126    /// The first sequence number covered by this block.
127    pub begin_seq: u16,
128    /// One past the last sequence number covered.
129    pub end_seq: u16,
130    /// The run-length and bit-vector chunks encoding per-packet status.
131    pub chunks: Vec<Chunk>,
132}
133
134/// LossRLEReportBlock is used to report information about packet
135/// losses, as described in RFC 3611, section 4.1
136/// make sure to set is_loss_rle = true
137pub type LossRLEReportBlock = RLEReportBlock;
138
139/// DuplicateRLEReportBlock is used to report information about packet
140/// duplication, as described in RFC 3611, section 4.1
141/// make sure to set is_loss_rle = false
142pub type DuplicateRLEReportBlock = RLEReportBlock;
143
144impl RLEReportBlock {
145    /// The XR block header describing this block's type and length.
146    pub fn xr_header(&self) -> XRHeader {
147        XRHeader {
148            block_type: if self.is_loss_rle {
149                BlockType::LossRLE
150            } else {
151                BlockType::DuplicateRLE
152            },
153            type_specific: self.t & 0x0F,
154            block_length: (self.raw_size() / 4 - 1) as u16,
155        }
156    }
157}
158
159impl fmt::Display for RLEReportBlock {
160    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
161        write!(f, "{self:?}")
162    }
163}
164
165impl Packet for RLEReportBlock {
166    fn header(&self) -> Header {
167        Header::default()
168    }
169
170    /// destination_ssrc returns an array of ssrc values that this report block refers to.
171    fn destination_ssrc(&self) -> Vec<u32> {
172        vec![self.ssrc]
173    }
174
175    fn raw_size(&self) -> usize {
176        XR_HEADER_LENGTH + RLE_REPORT_BLOCK_MIN_LENGTH as usize + self.chunks.len() * 2
177    }
178
179    fn as_any(&self) -> &dyn Any {
180        self
181    }
182    fn equal(&self, other: &dyn Packet) -> bool {
183        other.as_any().downcast_ref::<RLEReportBlock>() == Some(self)
184    }
185    fn cloned(&self) -> Box<dyn Packet> {
186        Box::new(self.clone())
187    }
188}
189
190impl MarshalSize for RLEReportBlock {
191    fn marshal_size(&self) -> usize {
192        self.raw_size()
193    }
194}
195
196impl Marshal for RLEReportBlock {
197    /// marshal_to encodes the RLEReportBlock in binary
198    fn marshal_to(&self, mut buf: &mut [u8]) -> Result<usize> {
199        if buf.remaining_mut() < self.marshal_size() {
200            return Err(Error::BufferTooShort);
201        }
202
203        let h = self.xr_header();
204        let n = h.marshal_to(buf)?;
205        buf = &mut buf[n..];
206
207        buf.put_u32(self.ssrc);
208        buf.put_u16(self.begin_seq);
209        buf.put_u16(self.end_seq);
210        for chunk in &self.chunks {
211            buf.put_u16(chunk.0);
212        }
213
214        Ok(self.marshal_size())
215    }
216}
217
218impl Unmarshal for RLEReportBlock {
219    /// Unmarshal decodes the RLEReportBlock from binary
220    fn unmarshal<B>(raw_packet: &mut B) -> Result<Self>
221    where
222        Self: Sized,
223        B: Buf,
224    {
225        if raw_packet.remaining() < XR_HEADER_LENGTH {
226            return Err(Error::PacketTooShort);
227        }
228
229        let xr_header = XRHeader::unmarshal(raw_packet)?;
230        let block_length = match xr_header.block_length.checked_mul(4) {
231            Some(length) => length,
232            None => return Err(Error::InvalidBlockSize),
233        };
234        if block_length < RLE_REPORT_BLOCK_MIN_LENGTH
235            || !(block_length - RLE_REPORT_BLOCK_MIN_LENGTH).is_multiple_of(2)
236            || raw_packet.remaining() < block_length as usize
237        {
238            return Err(Error::PacketTooShort);
239        }
240
241        let is_loss_rle = xr_header.block_type == BlockType::LossRLE;
242        let t = xr_header.type_specific & 0x0F;
243
244        let ssrc = raw_packet.get_u32();
245        let begin_seq = raw_packet.get_u16();
246        let end_seq = raw_packet.get_u16();
247
248        let remaining = block_length - RLE_REPORT_BLOCK_MIN_LENGTH;
249        let mut chunks = vec![];
250        for _ in 0..remaining / 2 {
251            chunks.push(Chunk(raw_packet.get_u16()));
252        }
253
254        Ok(RLEReportBlock {
255            is_loss_rle,
256            t,
257            ssrc,
258            begin_seq,
259            end_seq,
260            chunks,
261        })
262    }
263}