rtp_parse/rtcp/
rtcp_fb_tcc.rs

1use anyhow::{anyhow, bail, Context, Result};
2use bit_cursor::{
3    bit_read_exts::BitReadExts,
4    byte_order::NetworkOrder,
5    nsw_types::{
6        num_traits::{ConstOne, ConstZero},
7        *,
8    },
9};
10
11use crate::{util::consume_padding, PacketBuffer};
12
13use super::{rtcp_fb_header::RtcpFbHeader, rtcp_header::RtcpHeader};
14
15const U2_TWO: u2 = u2::new(2);
16
17/// https://datatracker.ietf.org/doc/html/draft-holmer-rmcat-transport-wide-cc-extensions-01#section-3.1
18///  0                   1                   2                   3
19///  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
20/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
21/// |V=2|P|  FMT=15 |    PT=205     |           length              |
22/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
23/// |                     SSRC of packet sender                     |
24/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
25/// |                      SSRC of media source                     |
26/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
27/// |      base sequence number     |      packet status count      |
28/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
29/// |                 reference time                | fb pkt. count |
30/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
31/// |          packet chunk         |         packet chunk          |
32/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
33/// .                                                               .
34/// .                                                               .
35/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
36/// |         packet chunk          |  recv delta   |  recv delta   |
37/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
38/// .                                                               .
39/// .                                                               .
40/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
41/// |           recv delta          |  recv delta   | zero padding  |
42/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
43///
44/// packet status count:  16 bits The number of packets this feedback
45///  contains status for, starting with the packet identified
46///  by the base sequence number.
47///
48/// feedback packet count:  8 bits A counter incremented by one for each
49///  feedback packet sent.  Used to detect feedback packet
50///  losses.
51#[derive(Debug)]
52pub struct RtcpFbTccPacket {
53    pub header: RtcpHeader,
54    pub fb_header: RtcpFbHeader,
55    pub packet_reports: Vec<PacketReport>,
56    pub reference_time: u24,
57    pub feedback_packet_count: u8,
58}
59
60impl RtcpFbTccPacket {
61    pub const FMT: u5 = u5::new(15);
62}
63
64pub fn read_rtcp_fb_tcc<B: PacketBuffer>(
65    buf: &mut B,
66    header: RtcpHeader,
67    fb_header: RtcpFbHeader,
68) -> Result<RtcpFbTccPacket> {
69    let (packet_reports, reference_time, feedback_packet_count) = read_rtcp_fb_tcc_data(buf)?;
70    Ok(RtcpFbTccPacket {
71        header,
72        fb_header,
73        packet_reports,
74        reference_time,
75        feedback_packet_count,
76    })
77}
78
79fn read_rtcp_fb_tcc_data<B: PacketBuffer>(buf: &mut B) -> Result<(Vec<PacketReport>, u24, u8)> {
80    let base_seq_num = buf.read_u16::<NetworkOrder>().context("base seq num")?;
81    let packet_status_count = buf
82        .read_u16::<NetworkOrder>()
83        .context("packet status count")?;
84    let reference_time = buf.read_u24::<NetworkOrder>().context("reference time")?;
85    let feedback_packet_count = buf.read_u8().context("feedback packet count")?;
86
87    let mut num_status_remaining = packet_status_count;
88
89    let mut chunks: Vec<SomePacketStatusChunk> = Vec::new();
90    while num_status_remaining > 0 {
91        let chunk = read_some_packet_status_chunk(buf, num_status_remaining as usize)
92            .context("packet status chunk")?;
93        num_status_remaining -= chunk.num_symbols();
94        chunks.push(chunk);
95    }
96    let mut curr_seq_num = base_seq_num;
97    let mut packet_reports: Vec<PacketReport> = Vec::new();
98    for chunk in chunks {
99        for status_symbol in chunk {
100            match status_symbol.delta_size_bytes() {
101                0 => packet_reports.push(PacketReport::UnreceivedPacket {
102                    seq_num: curr_seq_num,
103                }),
104                1 => {
105                    let delta_ticks = buf
106                        .read_u8()
107                        .with_context(|| format!("delta ticks for packet {curr_seq_num}"))?;
108                    packet_reports.push(PacketReport::ReceivedPacketSmallDelta {
109                        seq_num: curr_seq_num,
110                        delta_ticks,
111                    });
112                }
113                2 => {
114                    let delta_ticks = buf
115                        .read_u16::<NetworkOrder>()
116                        .with_context(|| format!("delta ticks for packet {curr_seq_num}"))?
117                        as i16;
118                    packet_reports.push(PacketReport::ReceivedPacketLargeOrNegativeDelta {
119                        seq_num: curr_seq_num,
120                        delta_ticks,
121                    });
122                }
123                delta_size_bytes => bail!("Invalid delta size: {delta_size_bytes} bytes"),
124            }
125            curr_seq_num = curr_seq_num.wrapping_add(1);
126        }
127    }
128    consume_padding(buf);
129    Ok((packet_reports, reference_time, feedback_packet_count))
130}
131
132#[derive(Debug, PartialEq)]
133pub enum PacketReport {
134    UnreceivedPacket { seq_num: u16 },
135    ReceivedPacketSmallDelta { seq_num: u16, delta_ticks: u8 },
136    ReceivedPacketLargeOrNegativeDelta { seq_num: u16, delta_ticks: i16 },
137}
138
139#[derive(Copy, Clone, Debug, PartialEq, Eq)]
140pub enum PacketStatusSymbol {
141    NotReceived = 0,
142    ReceivedSmallDelta = 1,
143    ReceivedLargeOrNegativeDelta = 2,
144}
145
146impl PacketStatusSymbol {
147    fn delta_size_bytes(&self) -> usize {
148        match self {
149            PacketStatusSymbol::NotReceived => 0,
150            PacketStatusSymbol::ReceivedSmallDelta => 1,
151            PacketStatusSymbol::ReceivedLargeOrNegativeDelta => 2,
152        }
153    }
154}
155
156impl From<u1> for PacketStatusSymbol {
157    fn from(value: u1) -> Self {
158        match value {
159            u1::ZERO => PacketStatusSymbol::NotReceived,
160            u1::ONE => PacketStatusSymbol::ReceivedSmallDelta,
161            _ => unreachable!(),
162        }
163    }
164}
165
166impl TryFrom<u2> for PacketStatusSymbol {
167    type Error = anyhow::Error;
168
169    fn try_from(value: u2) -> std::prelude::v1::Result<Self, Self::Error> {
170        match value {
171            u2::ZERO => Ok(PacketStatusSymbol::NotReceived),
172            u2::ONE => Ok(PacketStatusSymbol::ReceivedSmallDelta),
173            U2_TWO => Ok(PacketStatusSymbol::ReceivedLargeOrNegativeDelta),
174            pss => Err(anyhow!("Invalid 2 bit packet status symbol: {pss}")),
175        }
176    }
177}
178
179/// A status vector chunk starts with a 1 bit to identify it as a vector
180/// chunk, followed by a symbol size bit and then 7 or 14 symbols,
181/// depending on the size bit.
182///
183/// ```text
184///      0                   1
185///      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
186///     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
187///     |T|S|       symbol list         |
188///     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
189///
190/// chunk type (T):  1 bit A one identifies this as a status vector
191///             chunk.
192///
193/// symbol size (S):  1 bit A zero means this vector contains only
194///             "packet received" (0) and "packet not received" (1)
195///             symbols.  This means we can compress each symbol to just
196///             one bit, 14 in total.  A one means this vector contains
197///             the normal 2-bit symbols, 7 in total.
198///
199/// symbol list:  14 bits A list of packet status symbols, 7 or 14 in
200///             total.
201/// ```
202#[derive(Debug, Clone, PartialEq)]
203pub struct StatusVectorChunk(Vec<PacketStatusSymbol>);
204
205impl IntoIterator for StatusVectorChunk {
206    type Item = PacketStatusSymbol;
207
208    type IntoIter = <Vec<PacketStatusSymbol> as IntoIterator>::IntoIter;
209
210    fn into_iter(self) -> Self::IntoIter {
211        self.0.into_iter()
212    }
213}
214
215///
216/// This method assumes buf's position is at the symbol-size bit.
217pub fn read_status_vector_chunk<B: PacketBuffer>(
218    buf: &mut B,
219    max_symbol_count: usize,
220) -> Result<StatusVectorChunk> {
221    let symbol_size = buf.read_u1().context("symbol size")?;
222    let mut packet_status_symbols = match symbol_size {
223        u1::ZERO => {
224            // 1 bit symbols
225            (0..14)
226                .map(|i| {
227                    buf.read_u1()
228                        .with_context(|| format!("packet status symbol {i}"))
229                        .map(|v| v.into())
230                })
231                .collect::<Result<Vec<PacketStatusSymbol>>>()
232                .context("1 bit packet status symbols")
233        }
234        u1::ONE => {
235            // 2 bit symbols
236            (0..7)
237                .map(|i| {
238                    buf.read_u2()
239                        .with_context(|| format!("packet status symbol {i}"))?
240                        .try_into()
241                        .context("converting u2 to packet status symbol")
242                })
243                .collect::<Result<Vec<PacketStatusSymbol>>>()
244                .context("2 bit packet status symbols")
245        }
246        _ => unreachable!("u1 can only be 0 or 1"),
247    }?;
248
249    // Even when the number of packet status symbols is less than the entire 14 bits, we still need
250    // to consume the entire chunk, so we read all the symbols above to consume the proper amount
251    // of the buffer and then chop off any symbols that shouldn't actually be included here.
252    packet_status_symbols.truncate(max_symbol_count);
253
254    Ok(StatusVectorChunk(packet_status_symbols))
255}
256
257/// A run length chunk starts with 0 bit, followed by a packet status
258/// symbol and the run length of that symbol.
259/// ```text
260///     0                   1
261///     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
262///    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
263///    |T| S |       Run Length        |
264///    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
265///
266/// chunk type (T):  1 bit A zero identifies this as a run length chunk.
267///
268/// packet status symbol (S):  2 bits The symbol repeated in this run.
269///             See above.
270///
271/// run length (L):  13 bits An unsigned integer denoting the run length.
272/// ```
273#[derive(Debug, Clone, PartialEq, Eq)]
274pub struct RunLengthEncodingChunk {
275    pub symbol: PacketStatusSymbol,
276    pub run_length: u13,
277}
278
279pub struct RunLengthEncodingIterator {
280    symbol: PacketStatusSymbol,
281    curr_idx: u32,
282    length: u32,
283}
284
285impl Iterator for RunLengthEncodingIterator {
286    type Item = PacketStatusSymbol;
287
288    fn next(&mut self) -> Option<Self::Item> {
289        if self.curr_idx < self.length {
290            self.curr_idx += 1;
291            Some(self.symbol)
292        } else {
293            None
294        }
295    }
296}
297
298impl IntoIterator for RunLengthEncodingChunk {
299    type Item = PacketStatusSymbol;
300
301    type IntoIter = RunLengthEncodingIterator;
302
303    fn into_iter(self) -> Self::IntoIter {
304        RunLengthEncodingIterator {
305            symbol: self.symbol,
306            curr_idx: 0,
307            length: self.run_length.into(),
308        }
309    }
310}
311
312///
313/// This method assumes buf's position is at the packet status symbol bit
314pub fn read_run_length_encoding_chunk<B: PacketBuffer>(
315    buf: &mut B,
316) -> Result<RunLengthEncodingChunk> {
317    let symbol = buf
318        .read_u2()
319        .context("packet status symbol")?
320        .try_into()
321        .context("convert u2 to packet status symbol")?;
322    let run_length = buf.read_u13::<NetworkOrder>().context("run length")?;
323
324    Ok(RunLengthEncodingChunk { symbol, run_length })
325}
326
327enum SomePacketStatusChunk {
328    StatusVectorChunk(StatusVectorChunk),
329    RunLengthEncodingChunk(RunLengthEncodingChunk),
330}
331
332enum SomePacketStatusChunkIterator {
333    RunLengthEncodingChunkIterator(RunLengthEncodingIterator),
334    StatusVectorChunkIterator(<StatusVectorChunk as IntoIterator>::IntoIter),
335}
336
337impl Iterator for SomePacketStatusChunkIterator {
338    type Item = PacketStatusSymbol;
339
340    fn next(&mut self) -> Option<Self::Item> {
341        match self {
342            SomePacketStatusChunkIterator::StatusVectorChunkIterator(i) => i.next(),
343            SomePacketStatusChunkIterator::RunLengthEncodingChunkIterator(i) => i.next(),
344        }
345    }
346}
347
348impl SomePacketStatusChunk {
349    fn num_symbols(&self) -> u16 {
350        match self {
351            SomePacketStatusChunk::StatusVectorChunk(svc) => svc.0.len() as u16,
352            SomePacketStatusChunk::RunLengthEncodingChunk(rlec) => rlec.run_length.into(),
353        }
354    }
355}
356
357impl IntoIterator for SomePacketStatusChunk {
358    type Item = PacketStatusSymbol;
359
360    type IntoIter = SomePacketStatusChunkIterator;
361
362    fn into_iter(self) -> Self::IntoIter {
363        match self {
364            SomePacketStatusChunk::StatusVectorChunk(svc) => {
365                SomePacketStatusChunkIterator::StatusVectorChunkIterator(svc.into_iter())
366            }
367            SomePacketStatusChunk::RunLengthEncodingChunk(rlec) => {
368                SomePacketStatusChunkIterator::RunLengthEncodingChunkIterator(rlec.into_iter())
369            }
370        }
371    }
372}
373
374fn read_some_packet_status_chunk<B: PacketBuffer>(
375    buf: &mut B,
376    max_symbol_count: usize,
377) -> Result<SomePacketStatusChunk> {
378    let chunk_type = buf.read_u1().context("chunk type")?;
379    match chunk_type {
380        u1::ZERO => read_run_length_encoding_chunk(buf)
381            .map(SomePacketStatusChunk::RunLengthEncodingChunk)
382            .context("run length encoding chunk"),
383        u1::ONE => read_status_vector_chunk(buf, max_symbol_count)
384            .map(SomePacketStatusChunk::StatusVectorChunk)
385            .context("status vector chunk"),
386        _ => unreachable!(),
387    }
388}
389
390#[cfg(test)]
391mod test {
392    use bit_cursor::{bit_cursor::BitCursor, nsw_types::u24};
393    use bitvec::{bits, order::Msb0, vec::BitVec};
394
395    use crate::rtcp::rtcp_fb_tcc::{PacketReport, PacketStatusSymbol};
396
397    use super::{read_rtcp_fb_tcc_data, read_status_vector_chunk};
398
399    #[test]
400    fn test_sv_chunk_1_bit_symbols() {
401        let chunk = bits!(u8, Msb0; 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1);
402        let mut cursor = BitCursor::new(chunk);
403
404        let sv_chunk = read_status_vector_chunk(&mut cursor, 14).unwrap();
405        assert_eq!(sv_chunk.0.len(), 14);
406        assert!(cursor.remaining_slice().is_empty());
407        assert_eq!(
408            sv_chunk.0,
409            vec![
410                PacketStatusSymbol::ReceivedSmallDelta,
411                PacketStatusSymbol::ReceivedSmallDelta,
412                PacketStatusSymbol::NotReceived,
413                PacketStatusSymbol::NotReceived,
414                PacketStatusSymbol::ReceivedSmallDelta,
415                PacketStatusSymbol::ReceivedSmallDelta,
416                PacketStatusSymbol::NotReceived,
417                PacketStatusSymbol::NotReceived,
418                PacketStatusSymbol::ReceivedSmallDelta,
419                PacketStatusSymbol::ReceivedSmallDelta,
420                PacketStatusSymbol::NotReceived,
421                PacketStatusSymbol::NotReceived,
422                PacketStatusSymbol::ReceivedSmallDelta,
423                PacketStatusSymbol::ReceivedSmallDelta,
424            ]
425        );
426    }
427
428    #[test]
429    fn test_sv_chunk_1_bit_symbols_with_limit() {
430        let chunk = bits!(u8, Msb0; 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1);
431        let mut cursor = BitCursor::new(chunk);
432
433        let sv_chunk = read_status_vector_chunk(&mut cursor, 3).unwrap();
434        assert_eq!(sv_chunk.0.len(), 3);
435        assert!(cursor.remaining_slice().is_empty());
436        assert_eq!(
437            sv_chunk.0,
438            vec![
439                PacketStatusSymbol::ReceivedSmallDelta,
440                PacketStatusSymbol::ReceivedSmallDelta,
441                PacketStatusSymbol::NotReceived,
442            ]
443        );
444    }
445
446    #[test]
447    fn test_sv_chunk_2_bit_symbols() {
448        let chunk = bits!(u8, Msb0; 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0);
449        let mut cursor = BitCursor::new(chunk);
450
451        let sv_chunk = read_status_vector_chunk(&mut cursor, 14).unwrap();
452        assert_eq!(sv_chunk.0.len(), 7);
453        assert!(cursor.remaining_slice().is_empty());
454        assert_eq!(
455            sv_chunk.0,
456            vec![
457                PacketStatusSymbol::NotReceived,
458                PacketStatusSymbol::ReceivedSmallDelta,
459                PacketStatusSymbol::ReceivedLargeOrNegativeDelta,
460                PacketStatusSymbol::NotReceived,
461                PacketStatusSymbol::ReceivedSmallDelta,
462                PacketStatusSymbol::ReceivedLargeOrNegativeDelta,
463                PacketStatusSymbol::NotReceived,
464            ]
465        );
466    }
467
468    #[test]
469    fn test_read_tcc_fb_data() {
470        #[rustfmt::skip]
471        let data_buf = [
472            0x01, 0x81, 0x00, 0x08, 0x19, 0xae, 0xe8, 0x45,
473            0xd9, 0x55, 0x20, 0x01, 0xa8, 0xff, 0xfc, 0x04,
474            0x00, 0x50, 0x04, 0x00, 0x00, 0x00, 0x00, 00
475        ];
476        let mut cursor = BitCursor::new(BitVec::<u8, Msb0>::from_slice(&data_buf));
477        let (packet_reports, reference_time, feedback_packet_count) =
478            read_rtcp_fb_tcc_data(&mut cursor).unwrap();
479
480        assert_eq!(reference_time, u24::new(1683176));
481        assert_eq!(feedback_packet_count, 69);
482        assert_eq!(
483            packet_reports,
484            [
485                PacketReport::ReceivedPacketSmallDelta {
486                    seq_num: 385,
487                    delta_ticks: 168,
488                },
489                PacketReport::ReceivedPacketLargeOrNegativeDelta {
490                    seq_num: 386,
491                    delta_ticks: -4,
492                },
493                PacketReport::ReceivedPacketSmallDelta {
494                    seq_num: 387,
495                    delta_ticks: 4,
496                },
497                PacketReport::ReceivedPacketSmallDelta {
498                    seq_num: 388,
499                    delta_ticks: 0,
500                },
501                PacketReport::ReceivedPacketSmallDelta {
502                    seq_num: 389,
503                    delta_ticks: 80,
504                },
505                PacketReport::ReceivedPacketSmallDelta {
506                    seq_num: 390,
507                    delta_ticks: 4,
508                },
509                PacketReport::ReceivedPacketSmallDelta {
510                    seq_num: 391,
511                    delta_ticks: 0,
512                },
513                PacketReport::ReceivedPacketSmallDelta {
514                    seq_num: 392,
515                    delta_ticks: 0,
516                },
517            ]
518        );
519        dbg!(packet_reports);
520    }
521}