rtp_parse/rtcp/
rtcp_fb_tcc.rs

1use parsely_rs::*;
2
3use super::{rtcp_fb_header::RtcpFbHeader, rtcp_header::RtcpHeader};
4
5const U1_ZERO: u1 = u1::new(0);
6const U1_ONE: u1 = u1::new(1);
7
8const U2_ZERO: u2 = u2::new(0);
9const U2_ONE: u2 = u2::new(1);
10const U2_TWO: u2 = u2::new(2);
11
12/// https://datatracker.ietf.org/doc/html/draft-holmer-rmcat-transport-wide-cc-extensions-01#section-3.1
13///  0                   1                   2                   3
14///  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
15/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
16/// |V=2|P|  FMT=15 |    PT=205     |           length              |
17/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
18/// |                     SSRC of packet sender                     |
19/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
20/// |                      SSRC of media source                     |
21/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
22/// |      base sequence number     |      packet status count      |
23/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
24/// |                 reference time                | fb pkt. count |
25/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
26/// |          packet chunk         |         packet chunk          |
27/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
28/// .                                                               .
29/// .                                                               .
30/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
31/// |         packet chunk          |  recv delta   |  recv delta   |
32/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
33/// .                                                               .
34/// .                                                               .
35/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
36/// |           recv delta          |  recv delta   | zero padding  |
37/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
38///
39/// packet status count:  16 bits The number of packets this feedback
40///  contains status for, starting with the packet identified
41///  by the base sequence number.
42///
43/// feedback packet count:  8 bits A counter incremented by one for each
44///  feedback packet sent.  Used to detect feedback packet
45///  losses.
46#[derive(Debug)]
47pub struct RtcpFbTccPacket {
48    pub header: RtcpHeader,
49    pub fb_header: RtcpFbHeader,
50    pub packet_reports: Vec<PacketReport>,
51    pub reference_time: u24,
52    pub feedback_packet_count: u8,
53}
54
55impl RtcpFbTccPacket {
56    pub const FMT: u5 = u5::new(15);
57
58    pub fn payload_length_bytes(&self) -> usize {
59        todo!()
60    }
61}
62
63impl<B: BitBuf> ParselyRead<B> for RtcpFbTccPacket {
64    type Ctx = (RtcpHeader, RtcpFbHeader);
65
66    fn read<T: ByteOrder>(buf: &mut B, (header, fb_header): Self::Ctx) -> ParselyResult<Self> {
67        let bytes_remaining_start = buf.remaining_bytes();
68        let base_seq_num = buf.get_u16::<T>().context("Reading field 'base_seq_num'")?;
69        let packet_status_count = buf
70            .get_u16::<T>()
71            .context("Reading field 'packet_status_count'")?;
72        let reference_time = buf
73            .get_u24::<T>()
74            .context("Reading field 'reference_time'")?;
75        let feedback_packet_count = buf
76            .get_u8()
77            .context("Reading field 'feedback_packet_count'")?;
78
79        let mut num_status_remaining = packet_status_count;
80        let mut chunks: Vec<SomePacketStatusChunk> = vec![];
81        while num_status_remaining > 0 {
82            let chunk = SomePacketStatusChunk::read::<T>(buf, (num_status_remaining as usize,))
83                .context("packet status chunk")?;
84            num_status_remaining -= chunk.num_symbols();
85            chunks.push(chunk);
86        }
87        let mut packet_reports: Vec<PacketReport> =
88            Vec::with_capacity(packet_status_count as usize);
89        let mut curr_seq_num = base_seq_num;
90        for chunk in &chunks {
91            for status_symbol in chunk.iter() {
92                match status_symbol.delta_size_bytes() {
93                    0 => packet_reports.push(PacketReport::UnreceivedPacket {
94                        seq_num: curr_seq_num,
95                    }),
96                    1 => {
97                        let delta_ticks = buf
98                            .get_u8()
99                            .with_context(|| format!("delta ticks for packet {curr_seq_num}"))?;
100                        packet_reports.push(PacketReport::ReceivedPacketSmallDelta {
101                            seq_num: curr_seq_num,
102                            delta_ticks,
103                        })
104                    }
105                    2 => {
106                        let delta_ticks = buf
107                            .get_u16::<T>()
108                            .with_context(|| format!("delta ticks for packet {curr_seq_num}"))?
109                            as i16;
110                        packet_reports.push(PacketReport::ReceivedPacketLargeOrNegativeDelta {
111                            seq_num: curr_seq_num,
112                            delta_ticks,
113                        })
114                    }
115                    delta_size_bytes => bail!("Invalid delta size: {delta_size_bytes} bytes"),
116                }
117                curr_seq_num = curr_seq_num.wrapping_add(1);
118            }
119        }
120        while (bytes_remaining_start - buf.remaining_bytes()) % 4 != 0 {
121            let _ = buf.get_u8().context("padding")?;
122        }
123        Ok(RtcpFbTccPacket {
124            header,
125            fb_header,
126            packet_reports,
127            reference_time,
128            feedback_packet_count,
129        })
130    }
131}
132
133impl<B: BitBufMut> ParselyWrite<B> for RtcpFbTccPacket {
134    type Ctx = ();
135
136    fn write<T: ByteOrder>(&self, buf: &mut B, _ctx: Self::Ctx) -> ParselyResult<()> {
137        self.header.write::<T>(buf, ()).context("header")?;
138        self.fb_header.write::<T>(buf, ()).context("fb header")?;
139
140        if self.packet_reports.is_empty() {
141            return Ok(());
142        }
143        let base_seq_num = self.packet_reports[0].seq_num();
144        let packet_status_count = self.packet_reports.len() as u16;
145        buf.put_u16::<T>(base_seq_num).context("base_seq_num")?;
146        buf.put_u16::<T>(packet_status_count)
147            .context("packet_status_count")?;
148        buf.put_u24::<T>(self.reference_time)
149            .context("reference_time")?;
150        buf.put_u8(self.feedback_packet_count)
151            .context("feedback_packet_count")?;
152        todo!()
153    }
154}
155
156impl StateSync for RtcpFbTccPacket {
157    type SyncCtx = ();
158
159    fn sync(&mut self, _sync_ctx: Self::SyncCtx) -> ParselyResult<()> {
160        self.header
161            .sync((self.payload_length_bytes() as u16, Self::FMT))?;
162
163        self.packet_reports.sort_by_key(|pr| pr.seq_num());
164
165        Ok(())
166    }
167}
168
169// #[derive(Debug)]
170// enum SomeRecvDelta {
171//     Small(u8),
172//     LargeOrNegative(i16),
173// }
174
175// fn write_some_recv_delta<B: BitBufMut>(buf: &mut B, delta: SomeRecvDelta) -> Result<()> {
176//     match delta {
177//         SomeRecvDelta::Small(d) => Ok(buf.write_u8(d)?),
178//         // TODO: need support for writing a signed int here
179//         SomeRecvDelta::LargeOrNegative(d) => Ok(buf.write_u16::<NetworkOrder>(d as u16)?),
180//     }
181// }
182//
183// fn write_rtcp_fb_tcc<B: BitBufMut>(buf: &mut B, fb_tcc: &RtcpFbTccPacket) -> Result<()> {
184//     write_rtcp_header(buf, &fb_tcc.header).context("rtcp header")?;
185//     write_rtcp_fb_header(buf, &fb_tcc.fb_header).context("fb header")?;
186//
187//     write_rtcp_fb_tcc_data(buf, &fb_tcc.packet_reports, fb_tcc.reference_time)
188//         .context("fb tcc data")?;
189//
190//     Ok(())
191// }
192//
193// /// Write the FB TCC packet data.  Note that `packet_reports` should be a _continuous_ set of
194// /// reports: all NotReceived values should have already been inserted.
195// fn write_rtcp_fb_tcc_data<B: BitBufMut>(
196//     buf: &mut B,
197//     packet_reports: &[PacketReport],
198//     reference_time: u24,
199// ) -> Result<()> {
200//     let base_seq_num = packet_reports[0].seq_num();
201//     buf.write_u16::<NetworkOrder>(base_seq_num)
202//         .context("base seq num")?;
203//     buf.write_u16::<NetworkOrder>(packet_reports.len() as u16)
204//         .context("packet status count")?;
205//     buf.write_u24::<NetworkOrder>(reference_time)
206//         .context("reference time")?;
207//
208//     let (feedback_packet_count, chunks, deltas) = prepare_packet_reports(&packet_reports);
209//     buf.write_u8(feedback_packet_count)
210//         .context("feedback packet count")?;
211//
212//     for chunk in chunks {
213//         write_some_packet_status_chunk(chunk, buf).context("packet status chunk")?;
214//     }
215//
216//     for delta in deltas {
217//         write_some_recv_delta(buf, delta).context("delta")?;
218//     }
219//
220//     Ok(())
221// }
222//
223// fn prepare_packet_reports(
224//     packet_reports: &[PacketReport],
225// ) -> (u8, Vec<SomePacketStatusChunk>, Vec<SomeRecvDelta>) {
226//     let mut expected_seq_num = packet_reports[0].seq_num();
227//     let mut chunks: Vec<SomePacketStatusChunk> = vec![];
228//     let mut deltas: Vec<SomeRecvDelta> = vec![];
229//     let mut curr_chunk = Chunk::default();
230//     let mut seq_num_count = 0u8;
231//     for packet_report in packet_reports {
232//         while expected_seq_num != packet_report.seq_num() {
233//             if !curr_chunk.can_add(PacketStatusSymbol::NotReceived) {
234//                 chunks.push(curr_chunk.emit());
235//             }
236//             curr_chunk.add(PacketStatusSymbol::NotReceived);
237//             expected_seq_num = expected_seq_num.wrapping_add(1);
238//             seq_num_count = seq_num_count.wrapping_add(1);
239//         }
240//
241//         if !curr_chunk.can_add(packet_report.symbol()) {
242//             chunks.push(curr_chunk.emit());
243//         }
244//         match packet_report {
245//             PacketReport::UnreceivedPacket { .. } => (),
246//             PacketReport::ReceivedPacketSmallDelta { delta_ticks, .. } => {
247//                 deltas.push(SomeRecvDelta::Small(*delta_ticks))
248//             }
249//             PacketReport::ReceivedPacketLargeOrNegativeDelta { delta_ticks, .. } => {
250//                 deltas.push(SomeRecvDelta::LargeOrNegative(*delta_ticks))
251//             }
252//         }
253//
254//         expected_seq_num = expected_seq_num.wrapping_add(1);
255//         seq_num_count = seq_num_count.wrapping_add(1);
256//     }
257//     chunks.push(curr_chunk.emit());
258//
259//     (seq_num_count, chunks, deltas)
260// }
261
262#[derive(Debug, PartialEq)]
263pub enum PacketReport {
264    UnreceivedPacket { seq_num: u16 },
265    ReceivedPacketSmallDelta { seq_num: u16, delta_ticks: u8 },
266    ReceivedPacketLargeOrNegativeDelta { seq_num: u16, delta_ticks: i16 },
267}
268
269impl PacketReport {
270    pub fn seq_num(&self) -> u16 {
271        match self {
272            Self::UnreceivedPacket { seq_num } => *seq_num,
273            Self::ReceivedPacketSmallDelta { seq_num, .. } => *seq_num,
274            Self::ReceivedPacketLargeOrNegativeDelta { seq_num, .. } => *seq_num,
275        }
276    }
277
278    pub fn symbol(&self) -> PacketStatusSymbol {
279        match self {
280            PacketReport::UnreceivedPacket { .. } => PacketStatusSymbol::NotReceived,
281            PacketReport::ReceivedPacketSmallDelta { .. } => PacketStatusSymbol::ReceivedSmallDelta,
282            PacketReport::ReceivedPacketLargeOrNegativeDelta { .. } => {
283                PacketStatusSymbol::ReceivedLargeOrNegativeDelta
284            }
285        }
286    }
287}
288
289#[derive(Copy, Clone, Debug, PartialEq, Eq)]
290pub enum PacketStatusSymbol {
291    NotReceived = 0,
292    ReceivedSmallDelta = 1,
293    ReceivedLargeOrNegativeDelta = 2,
294}
295
296impl PacketStatusSymbol {
297    // pub(crate) fn from_delta_size(delta_size: u8) -> Self {
298    //     match delta_size {
299    //         0 => PacketStatusSymbol::NotReceived,
300    //         1 => PacketStatusSymbol::ReceivedSmallDelta,
301    //         2 => PacketStatusSymbol::ReceivedLargeOrNegativeDelta,
302    //         _ => todo!("invalid"),
303    //     }
304    // }
305
306    pub(crate) fn delta_size_bytes(&self) -> u8 {
307        match self {
308            PacketStatusSymbol::NotReceived => 0,
309            PacketStatusSymbol::ReceivedSmallDelta => 1,
310            PacketStatusSymbol::ReceivedLargeOrNegativeDelta => 2,
311        }
312    }
313}
314
315impl From<u1> for PacketStatusSymbol {
316    fn from(value: u1) -> Self {
317        match value {
318            U1_ZERO => PacketStatusSymbol::NotReceived,
319            U1_ONE => PacketStatusSymbol::ReceivedSmallDelta,
320            _ => unreachable!(),
321        }
322    }
323}
324
325impl TryInto<u1> for &PacketStatusSymbol {
326    type Error = anyhow::Error;
327
328    fn try_into(self) -> std::prelude::v1::Result<u1, Self::Error> {
329        match self {
330            PacketStatusSymbol::NotReceived => Ok(U1_ZERO),
331            PacketStatusSymbol::ReceivedSmallDelta => Ok(U1_ONE),
332            PacketStatusSymbol::ReceivedLargeOrNegativeDelta => Err(anyhow!(
333                "PacketStatusSymbol::ReceivedLargeOrNegativeDelta can't be encoded into a u1"
334            )),
335        }
336    }
337}
338
339impl TryInto<u1> for PacketStatusSymbol {
340    type Error = anyhow::Error;
341
342    fn try_into(self) -> std::prelude::v1::Result<u1, Self::Error> {
343        (&self).try_into()
344    }
345}
346
347impl TryFrom<u2> for PacketStatusSymbol {
348    type Error = anyhow::Error;
349
350    fn try_from(value: u2) -> std::prelude::v1::Result<Self, Self::Error> {
351        match value {
352            U2_ZERO => Ok(PacketStatusSymbol::NotReceived),
353            U2_ONE => Ok(PacketStatusSymbol::ReceivedSmallDelta),
354            U2_TWO => Ok(PacketStatusSymbol::ReceivedLargeOrNegativeDelta),
355            pss => Err(anyhow!("Invalid 2 bit packet status symbol: {pss}")),
356        }
357    }
358}
359
360impl From<&PacketStatusSymbol> for u2 {
361    fn from(val: &PacketStatusSymbol) -> Self {
362        match val {
363            PacketStatusSymbol::NotReceived => u2::new(0),
364            PacketStatusSymbol::ReceivedSmallDelta => u2::new(1),
365            PacketStatusSymbol::ReceivedLargeOrNegativeDelta => u2::new(2),
366        }
367    }
368}
369
370impl From<PacketStatusSymbol> for u2 {
371    fn from(val: PacketStatusSymbol) -> Self {
372        (&val).into()
373    }
374}
375
376/// A status vector chunk starts with a 1 bit to identify it as a vector
377/// chunk, followed by a symbol size bit and then 7 or 14 symbols,
378/// depending on the size bit.
379///
380/// ```text
381///      0                   1
382///      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
383///     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
384///     |T|S|       symbol list         |
385///     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
386///
387/// chunk type (T):  1 bit A one identifies this as a status vector
388///             chunk.
389///
390/// symbol size (S):  1 bit A zero means this vector contains only
391///             "packet received" (0) and "packet not received" (1)
392///             symbols.  This means we can compress each symbol to just
393///             one bit, 14 in total.  A one means this vector contains
394///             the normal 2-bit symbols, 7 in total.
395///
396/// symbol list:  14 bits A list of packet status symbols, 7 or 14 in
397///             total.
398/// ```
399#[derive(Debug, Clone, PartialEq)]
400pub struct StatusVectorChunk(pub(crate) Vec<PacketStatusSymbol>);
401
402impl StatusVectorChunk {
403    fn has_two_bit_symbols(&self) -> bool {
404        self.0
405            .iter()
406            .any(|ss| matches!(ss, PacketStatusSymbol::ReceivedLargeOrNegativeDelta))
407    }
408
409    fn iter(&self) -> std::slice::Iter<'_, PacketStatusSymbol> {
410        self.0.iter()
411    }
412}
413
414/// This method assumes buf's position is at the symbol-size bit.
415impl<B: BitBuf> ParselyRead<B> for StatusVectorChunk {
416    type Ctx = (usize,);
417
418    fn read<T: ByteOrder>(buf: &mut B, (max_symbol_count,): Self::Ctx) -> ParselyResult<Self> {
419        let symbol_size = buf.get_u1().context("symbol size")?;
420        let mut packet_status_symbols = match symbol_size {
421            s if s == 0 => {
422                // 1 bit symbols
423                let mut symbols = Vec::with_capacity(14);
424                for i in 0..14 {
425                    let symbol: PacketStatusSymbol = buf
426                        .get_u1()
427                        .with_context(|| format!("packet status symbol {i}"))
428                        .map(|v| v.into())?;
429                    symbols.push(symbol);
430                }
431                symbols
432            }
433            s if s == 1 => {
434                // 2 bit symbols
435                let mut symbols = Vec::with_capacity(7);
436                for i in 0..7 {
437                    let symbol: PacketStatusSymbol = buf
438                        .get_u2()
439                        .with_context(|| format!("packet status symbol {i}"))?
440                        .try_into()
441                        .context("converting u2 to packet status symbol")?;
442                    symbols.push(symbol);
443                }
444                symbols
445            }
446            _ => unreachable!("u1 can only be 1 or 0"),
447        };
448
449        packet_status_symbols.truncate(max_symbol_count);
450
451        Ok(StatusVectorChunk(packet_status_symbols))
452    }
453}
454
455impl<B: BitBufMut> ParselyWrite<B> for StatusVectorChunk {
456    type Ctx = ();
457
458    fn write<T: ByteOrder>(&self, buf: &mut B, _ctx: Self::Ctx) -> ParselyResult<()> {
459        buf.put_u1(u1::new(1)).context("SV chunk type")?;
460        if self.has_two_bit_symbols() {
461            buf.put_u1(u1::new(1)).context("SV chunk symbol size")?;
462            for (i, symbol) in self.iter().enumerate() {
463                buf.put_u2(symbol.into())
464                    .with_context(|| format!("2 bit sv chunk symbol {i}"))?;
465            }
466        } else {
467            buf.put_u1(u1::new(0)).context("SV chunk symbol size")?;
468            for (i, symbol) in self.iter().enumerate() {
469                buf.put_u1(
470                    symbol
471                        .try_into()
472                        .context("Trying to convert status symbol to u1")?,
473                )
474                .with_context(|| format!("2 bit sv chunk symbol {i}"))?;
475            }
476        }
477        Ok(())
478    }
479}
480
481impl_stateless_sync!(StatusVectorChunk);
482
483/// A run length chunk starts with 0 bit, followed by a packet status
484/// symbol and the run length of that symbol.
485/// ```text
486///     0                   1
487///     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
488///    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
489///    |T| S |       Run Length        |
490///    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
491///
492/// chunk type (T):  1 bit A zero identifies this as a run length chunk.
493///
494/// packet status symbol (S):  2 bits The symbol repeated in this run.
495///             See above.
496///
497/// run length (L):  13 bits An unsigned integer denoting the run length.
498/// ```
499#[derive(Debug, Clone, PartialEq, Eq)]
500pub struct RunLengthEncodingChunk {
501    pub symbol: PacketStatusSymbol,
502    pub run_length: u13,
503}
504
505/// Assumes the buf's position is at the packet status symbol bit
506impl<B: BitBuf> ParselyRead<B> for RunLengthEncodingChunk {
507    type Ctx = ();
508
509    fn read<T: ByteOrder>(buf: &mut B, _ctx: Self::Ctx) -> ParselyResult<Self> {
510        let symbol = buf
511            .get_u2()
512            .context("Reading run length encoding symbol")?
513            .try_into()
514            .context("Converting u2 to packet status symbol")?;
515
516        let run_length = buf.get_u13::<T>().context("Reading run length")?;
517
518        Ok(RunLengthEncodingChunk { symbol, run_length })
519    }
520}
521
522impl<B: BitBufMut> ParselyWrite<B> for RunLengthEncodingChunk {
523    type Ctx = ();
524
525    fn write<T: ByteOrder>(&self, buf: &mut B, _ctx: Self::Ctx) -> ParselyResult<()> {
526        buf.put_u1(u1::new(0)).context("rle chunk type")?;
527        buf.put_u2(self.symbol.into()).context("rle chunk symbol")?;
528        buf.put_u13::<T>(self.run_length)
529            .context("rle chunk run length")?;
530
531        Ok(())
532    }
533}
534
535impl_stateless_sync!(RunLengthEncodingChunk);
536
537#[derive(Debug, Clone)]
538pub(crate) enum SomePacketStatusChunk {
539    StatusVectorChunk(StatusVectorChunk),
540    RunLengthEncodingChunk(RunLengthEncodingChunk),
541}
542
543pub(crate) enum SomePacketStatusChunkIterator<'a> {
544    StatusVector(std::slice::Iter<'a, PacketStatusSymbol>),
545    RunLength(std::iter::Repeat<PacketStatusSymbol>, usize), // (iter, remaining count)
546}
547
548impl Iterator for SomePacketStatusChunkIterator<'_> {
549    type Item = PacketStatusSymbol;
550
551    fn next(&mut self) -> Option<Self::Item> {
552        match self {
553            SomePacketStatusChunkIterator::StatusVector(iter) => iter.next().copied(),
554            SomePacketStatusChunkIterator::RunLength(iter, remaining) => {
555                if *remaining == 0 {
556                    None
557                } else {
558                    *remaining -= 1;
559                    iter.next()
560                }
561            }
562        }
563    }
564}
565
566impl SomePacketStatusChunk {
567    pub(crate) fn num_symbols(&self) -> u16 {
568        match self {
569            SomePacketStatusChunk::StatusVectorChunk(svc) => svc.0.len() as u16,
570            SomePacketStatusChunk::RunLengthEncodingChunk(rlec) => rlec.run_length.into(),
571        }
572    }
573
574    pub fn iter(&self) -> SomePacketStatusChunkIterator<'_> {
575        match self {
576            SomePacketStatusChunk::StatusVectorChunk(StatusVectorChunk(vec)) => {
577                SomePacketStatusChunkIterator::StatusVector(vec.iter())
578            }
579            SomePacketStatusChunk::RunLengthEncodingChunk(chunk) => {
580                SomePacketStatusChunkIterator::RunLength(
581                    std::iter::repeat(chunk.symbol),
582                    chunk.run_length.into(),
583                )
584            }
585        }
586    }
587}
588
589impl<B: BitBuf> ParselyRead<B> for SomePacketStatusChunk {
590    type Ctx = (usize,);
591
592    fn read<T: ByteOrder>(buf: &mut B, (max_symbol_count,): Self::Ctx) -> ParselyResult<Self> {
593        let chunk_type = buf.get_u1().context("chunk type")?;
594        match chunk_type {
595            ct if ct == 0 => RunLengthEncodingChunk::read::<T>(buf, ())
596                .map(SomePacketStatusChunk::RunLengthEncodingChunk)
597                .context("run length encoding chunk"),
598            ct if ct == 1 => StatusVectorChunk::read::<T>(buf, (max_symbol_count,))
599                .map(SomePacketStatusChunk::StatusVectorChunk)
600                .context("status vector chunk"),
601            _ => unreachable!(),
602        }
603    }
604}
605
606impl<B: BitBufMut> ParselyWrite<B> for SomePacketStatusChunk {
607    type Ctx = ();
608
609    fn write<T: ByteOrder>(&self, buf: &mut B, _ctx: Self::Ctx) -> ParselyResult<()> {
610        match self {
611            SomePacketStatusChunk::RunLengthEncodingChunk(rle_chunk) => {
612                rle_chunk.write::<T>(buf, ())?
613            }
614            SomePacketStatusChunk::StatusVectorChunk(sv_chunk) => sv_chunk.write::<T>(buf, ())?,
615        }
616        Ok(())
617    }
618}
619
620impl_stateless_sync!(SomePacketStatusChunk);
621
622#[cfg(test)]
623mod test {
624    use super::*;
625    use bits_io::bits;
626    // use bits_io::prelude::*;
627
628    #[test]
629    fn test_sv_chunk_1_bit_symbols() {
630        let chunk_data = bits!(1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1);
631        let mut bits = Bits::copy_from_bit_slice(chunk_data);
632        // Advance past the chunk type bit since we're calling StatusVectorChunk::read directly and
633        // it assumes that bit has already been read
634        bits.advance_bits(1);
635
636        let sv_chunk = StatusVectorChunk::read::<NetworkOrder>(&mut bits, (14,)).unwrap();
637
638        assert_eq!(sv_chunk.0.len(), 14);
639        assert!(bits.is_empty());
640        assert_eq!(
641            sv_chunk.0,
642            vec![
643                PacketStatusSymbol::ReceivedSmallDelta,
644                PacketStatusSymbol::ReceivedSmallDelta,
645                PacketStatusSymbol::NotReceived,
646                PacketStatusSymbol::NotReceived,
647                PacketStatusSymbol::ReceivedSmallDelta,
648                PacketStatusSymbol::ReceivedSmallDelta,
649                PacketStatusSymbol::NotReceived,
650                PacketStatusSymbol::NotReceived,
651                PacketStatusSymbol::ReceivedSmallDelta,
652                PacketStatusSymbol::ReceivedSmallDelta,
653                PacketStatusSymbol::NotReceived,
654                PacketStatusSymbol::NotReceived,
655                PacketStatusSymbol::ReceivedSmallDelta,
656                PacketStatusSymbol::ReceivedSmallDelta,
657            ]
658        );
659
660        let mut bits_mut = BitsMut::new();
661        sv_chunk.write::<NetworkOrder>(&mut bits_mut, ()).unwrap();
662        assert_eq!(chunk_data, bits_mut.as_ref());
663    }
664
665    #[test]
666    fn test_sv_chunk_1_bit_symbols_with_limit() {
667        let mut chunk_data = bits!(0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1);
668
669        let sv_chunk = StatusVectorChunk::read::<NetworkOrder>(&mut chunk_data, (3,)).unwrap();
670        assert_eq!(sv_chunk.0.len(), 3);
671        assert!(chunk_data.is_empty());
672        assert_eq!(
673            sv_chunk.0,
674            vec![
675                PacketStatusSymbol::ReceivedSmallDelta,
676                PacketStatusSymbol::ReceivedSmallDelta,
677                PacketStatusSymbol::NotReceived,
678            ]
679        );
680    }
681
682    #[test]
683    fn test_sv_chunk_2_bit_symbols() {
684        let chunk_data = bits!(1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0);
685        let mut bits = Bits::copy_from_bit_slice(chunk_data);
686        bits.advance_bits(1);
687
688        let sv_chunk = StatusVectorChunk::read::<NetworkOrder>(&mut bits, (15,)).unwrap();
689        assert_eq!(sv_chunk.0.len(), 7);
690        assert!(bits.is_empty());
691        assert_eq!(
692            sv_chunk.0,
693            vec![
694                PacketStatusSymbol::NotReceived,
695                PacketStatusSymbol::ReceivedSmallDelta,
696                PacketStatusSymbol::ReceivedLargeOrNegativeDelta,
697                PacketStatusSymbol::NotReceived,
698                PacketStatusSymbol::ReceivedSmallDelta,
699                PacketStatusSymbol::ReceivedLargeOrNegativeDelta,
700                PacketStatusSymbol::NotReceived,
701            ]
702        );
703
704        let mut bits_mut = BitsMut::new();
705        sv_chunk.write::<NetworkOrder>(&mut bits_mut, ()).unwrap();
706        assert_eq!(chunk_data, bits_mut.as_ref());
707    }
708
709    #[test]
710    fn test_rle_chunk() {
711        let chunk_data = bits!(0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1);
712        let mut bits = Bits::copy_from_bit_slice(chunk_data);
713        bits.advance_bits(1);
714
715        let rle_chunk = RunLengthEncodingChunk::read::<NetworkOrder>(&mut bits, ()).unwrap();
716        assert!(bits.is_empty());
717        assert_eq!(rle_chunk.symbol, PacketStatusSymbol::ReceivedSmallDelta);
718        assert_eq!(rle_chunk.run_length, 0b0000000010101);
719
720        let mut bits_mut = BitsMut::new();
721        rle_chunk.write::<NetworkOrder>(&mut bits_mut, ()).unwrap();
722        assert_eq!(chunk_data, bits_mut.as_ref());
723    }
724
725    #[test]
726    fn test_rtcp_fb_tcc_packet() {
727        #[rustfmt::skip]
728        let data_buf = [
729            // base seq num = 385, packet status count = 8
730            0x01, 0x81, 0x00, 0x08, 
731            // reference time = 1683176, fk pkt count = 69
732            0x19, 0xae, 0xe8, 0x45,
733            
734            0xd9, 0x55, 0x20, 0x01, 
735            0xa8, 0xff, 0xfc, 0x04,
736            0x00, 0x50, 0x04, 0x00, 
737            0x00, 0x00, 0x00, 0x00
738        ];
739        let mut bits = Bits::copy_from_bytes(&data_buf[..]);
740        let tcc_packet = RtcpFbTccPacket::read::<NetworkOrder>(
741            &mut bits,
742            (RtcpHeader::default(), RtcpFbHeader::default()),
743        )
744        .unwrap();
745        assert_eq!(tcc_packet.reference_time, u24::new(1683176));
746        assert_eq!(tcc_packet.feedback_packet_count, 69);
747        assert_eq!(
748            tcc_packet.packet_reports,
749            [
750                PacketReport::ReceivedPacketSmallDelta {
751                    seq_num: 385,
752                    delta_ticks: 168,
753                },
754                PacketReport::ReceivedPacketLargeOrNegativeDelta {
755                    seq_num: 386,
756                    delta_ticks: -4,
757                },
758                PacketReport::ReceivedPacketSmallDelta {
759                    seq_num: 387,
760                    delta_ticks: 4,
761                },
762                PacketReport::ReceivedPacketSmallDelta {
763                    seq_num: 388,
764                    delta_ticks: 0,
765                },
766                PacketReport::ReceivedPacketSmallDelta {
767                    seq_num: 389,
768                    delta_ticks: 80,
769                },
770                PacketReport::ReceivedPacketSmallDelta {
771                    seq_num: 390,
772                    delta_ticks: 4,
773                },
774                PacketReport::ReceivedPacketSmallDelta {
775                    seq_num: 391,
776                    delta_ticks: 0,
777                },
778                PacketReport::ReceivedPacketSmallDelta {
779                    seq_num: 392,
780                    delta_ticks: 0,
781                },
782            ]
783        );
784    }
785}