Skip to main content

rtc_rtcp/extended_report/
rle.rs

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