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}