Skip to main content

rtc_rtcp/transport_feedbacks/transport_layer_cc/
mod.rs

1//! Transport-wide congestion control feedback.
2//!
3//! Reports the arrival status and time of packets by their *transport-wide* sequence number — the
4//! one the `TransportCcExtension` RTP header extension stamps on every packet
5//! regardless of stream, which is why one report can cover audio and video together.
6//!
7//! Status is run-length or bit-vector encoded ([`StatusChunkTypeTcc`](crate::transport_feedbacks::transport_layer_cc::StatusChunkTypeTcc)) so a report covering
8//! hundreds of packets stays small.
9#[cfg(test)]
10mod transport_layer_cc_test;
11
12use crate::{header::*, packet::*, util::*};
13use shared::{
14    error::{Error, Result},
15    marshal::{Marshal, MarshalSize, Unmarshal},
16};
17
18use bytes::{Buf, BufMut};
19use std::any::Any;
20use std::fmt;
21
22/// <https://tools.ietf.org/html/draft-holmer-rmcat-transport-wide-cc-extensions-01#page-5>
23/// 0                   1                   2                   3
24/// 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
25/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
26/// |V=2|P|  FMT=15 |    PT=205     |           length              |
27/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
28/// |                     SSRC of packet sender                     |
29/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
30/// |                      SSRC of media source                     |
31/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
32/// |      base sequence number     |      packet status count      |
33/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
34/// |                 reference time                | fb pkt. count |
35/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
36/// |          packet chunk         |         packet chunk          |
37/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
38/// .                                                               .
39/// .                                                               .
40/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
41/// |         packet chunk          |  recv delta   |  recv delta   |
42/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
43/// .                                                               .
44/// .                                                               .
45/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
46/// |           recv delta          |  recv delta   | zero padding  |
47/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
48// for packet status chunk
49/// type of packet status chunk
50///
51/// ## Specifications
52///
53/// * [draft-holmer-rmcat-transport-wide-cc-extensions-01, page 5]
54///
55/// [draft-holmer-rmcat-transport-wide-cc-extensions-01, page 5]: https://tools.ietf.org/html/draft-holmer-rmcat-transport-wide-cc-extensions-01#page-5
56#[derive(Default, PartialEq, Eq, Debug, Clone)]
57#[repr(u16)]
58pub enum StatusChunkTypeTcc {
59    #[default]
60    /// A run-length chunk: one status repeated for a stated number of packets.
61    RunLengthChunk = 0,
62    /// A status-vector chunk: explicit per-packet status for a small group.
63    StatusVectorChunk = 1,
64}
65
66/// type of packet status symbol and recv delta
67#[derive(Default, PartialEq, Eq, Debug, Copy, Clone)]
68#[repr(u16)]
69pub enum SymbolTypeTcc {
70    /// <https://tools.ietf.org/html/draft-holmer-rmcat-transport-wide-cc-extensions-01#section-3.1.1>
71    #[default]
72    PacketNotReceived = 0,
73    /// <https://tools.ietf.org/html/draft-holmer-rmcat-transport-wide-cc-extensions-01#section-3.1.1>
74    PacketReceivedSmallDelta = 1,
75    /// <https://tools.ietf.org/html/draft-holmer-rmcat-transport-wide-cc-extensions-01#section-3.1.1>
76    PacketReceivedLargeDelta = 2,
77    /// <https://tools.ietf.org/html/draft-holmer-rmcat-transport-wide-cc-extensions-01#page-7>
78    /// see Example 2: "packet received, w/o recv delta"
79    PacketReceivedWithoutDelta = 3,
80}
81
82/// for status vector chunk
83#[derive(Default, PartialEq, Eq, Debug, Copy, Clone)]
84#[repr(u16)]
85pub enum SymbolSizeTypeTcc {
86    /// <https://tools.ietf.org/html/draft-holmer-rmcat-transport-wide-cc-extensions-01#section-3.1.4>
87    #[default]
88    OneBit = 0,
89    /// Two-bit symbols, which can also express "received, large delta".
90    TwoBit = 1,
91}
92
93impl From<u16> for SymbolSizeTypeTcc {
94    fn from(val: u16) -> Self {
95        match val {
96            0 => SymbolSizeTypeTcc::OneBit,
97            _ => SymbolSizeTypeTcc::TwoBit,
98        }
99    }
100}
101
102impl From<u16> for StatusChunkTypeTcc {
103    fn from(val: u16) -> Self {
104        match val {
105            0 => StatusChunkTypeTcc::RunLengthChunk,
106            _ => StatusChunkTypeTcc::StatusVectorChunk,
107        }
108    }
109}
110
111impl From<u16> for SymbolTypeTcc {
112    fn from(val: u16) -> Self {
113        match val {
114            0 => SymbolTypeTcc::PacketNotReceived,
115            1 => SymbolTypeTcc::PacketReceivedSmallDelta,
116            2 => SymbolTypeTcc::PacketReceivedLargeDelta,
117            _ => SymbolTypeTcc::PacketReceivedWithoutDelta,
118        }
119    }
120}
121
122/// PacketStatusChunk has two kinds:
123/// RunLengthChunk and StatusVectorChunk
124#[derive(Debug, Clone, PartialEq, Eq)]
125pub enum PacketStatusChunk {
126    /// A run-length encoded chunk.
127    RunLengthChunk(RunLengthChunk),
128    /// A status-vector chunk.
129    StatusVectorChunk(StatusVectorChunk),
130}
131
132impl MarshalSize for PacketStatusChunk {
133    fn marshal_size(&self) -> usize {
134        match self {
135            PacketStatusChunk::RunLengthChunk(c) => c.marshal_size(),
136            PacketStatusChunk::StatusVectorChunk(c) => c.marshal_size(),
137        }
138    }
139}
140
141impl Marshal for PacketStatusChunk {
142    /// Marshal ..
143    fn marshal_to(&self, buf: &mut [u8]) -> Result<usize> {
144        match self {
145            PacketStatusChunk::RunLengthChunk(c) => c.marshal_to(buf),
146            PacketStatusChunk::StatusVectorChunk(c) => c.marshal_to(buf),
147        }
148    }
149}
150
151/// RunLengthChunk T=TypeTCCRunLengthChunk
152/// 0                   1
153/// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
154/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
155/// |T| S |       Run Length        |
156/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
157#[derive(Debug, Clone, PartialEq, Eq, Default)]
158pub struct RunLengthChunk {
159    /// T = TypeTCCRunLengthChunk
160    pub type_tcc: StatusChunkTypeTcc,
161    /// S: type of packet status
162    /// kind: TypeTCCPacketNotReceived or...
163    pub packet_status_symbol: SymbolTypeTcc,
164    /// run_length: count of S
165    pub run_length: u16,
166}
167
168impl MarshalSize for RunLengthChunk {
169    fn marshal_size(&self) -> usize {
170        PACKET_STATUS_CHUNK_LENGTH
171    }
172}
173
174impl Marshal for RunLengthChunk {
175    /// Marshal ..
176    fn marshal_to(&self, mut buf: &mut [u8]) -> Result<usize> {
177        // append 1 bit '0'
178        let mut dst = set_nbits_of_uint16(0, 1, 0, 0)?;
179
180        // append 2 bit packet_status_symbol
181        dst = set_nbits_of_uint16(dst, 2, 1, self.packet_status_symbol as u16)?;
182
183        // append 13 bit run_length
184        dst = set_nbits_of_uint16(dst, 13, 3, self.run_length)?;
185
186        buf.put_u16(dst);
187
188        Ok(PACKET_STATUS_CHUNK_LENGTH)
189    }
190}
191
192impl Unmarshal for RunLengthChunk {
193    /// Unmarshal ..
194    fn unmarshal<B>(raw_packet: &mut B) -> Result<Self>
195    where
196        Self: Sized,
197        B: Buf,
198    {
199        let raw_packet_len = raw_packet.remaining();
200        if raw_packet_len < PACKET_STATUS_CHUNK_LENGTH {
201            return Err(Error::PacketStatusChunkLength);
202        }
203
204        // record type
205        let type_tcc = StatusChunkTypeTcc::RunLengthChunk;
206
207        let b0 = raw_packet.get_u8();
208        let b1 = raw_packet.get_u8();
209
210        // get PacketStatusSymbol
211        let packet_status_symbol = get_nbits_from_byte(b0, 1, 2).into();
212
213        // get RunLength
214        let run_length = ((get_nbits_from_byte(b0, 3, 5) as usize) << 8) as u16 + (b1 as u16);
215
216        Ok(RunLengthChunk {
217            type_tcc,
218            packet_status_symbol,
219            run_length,
220        })
221    }
222}
223
224/// StatusVectorChunk T=typeStatusVectorChunk
225/// 0                   1
226/// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
227/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
228/// |T|S|       symbol list         |
229/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
230#[derive(Debug, Clone, PartialEq, Eq, Default)]
231pub struct StatusVectorChunk {
232    /// T = TypeTCCRunLengthChunk
233    pub type_tcc: StatusChunkTypeTcc,
234
235    /// TypeTCCSymbolSizeOneBit or TypeTCCSymbolSizeTwoBit
236    pub symbol_size: SymbolSizeTypeTcc,
237
238    /// when symbol_size = TypeTCCSymbolSizeOneBit, symbol_list is 14*1bit:
239    /// TypeTCCSymbolListPacketReceived or TypeTCCSymbolListPacketNotReceived
240    /// when symbol_size = TypeTCCSymbolSizeTwoBit, symbol_list is 7*2bit:
241    /// TypeTCCPacketNotReceived TypeTCCPacketReceivedSmallDelta TypeTCCPacketReceivedLargeDelta or typePacketReserved
242    pub symbol_list: Vec<SymbolTypeTcc>,
243}
244
245impl MarshalSize for StatusVectorChunk {
246    fn marshal_size(&self) -> usize {
247        PACKET_STATUS_CHUNK_LENGTH
248    }
249}
250
251impl Marshal for StatusVectorChunk {
252    /// Marshal ..
253    fn marshal_to(&self, mut buf: &mut [u8]) -> Result<usize> {
254        // set first bit '1'
255        let mut dst = set_nbits_of_uint16(0, 1, 0, 1)?;
256
257        // set second bit symbol_size
258        dst = set_nbits_of_uint16(dst, 1, 1, self.symbol_size as u16)?;
259
260        let num_of_bits = NUM_OF_BITS_OF_SYMBOL_SIZE[self.symbol_size as usize];
261        // append 14 bit symbol_list
262        for (i, s) in self.symbol_list.iter().enumerate() {
263            let index = num_of_bits * (i as u16) + 2;
264            dst = set_nbits_of_uint16(dst, num_of_bits, index, *s as u16)?;
265        }
266
267        buf.put_u16(dst);
268
269        Ok(PACKET_STATUS_CHUNK_LENGTH)
270    }
271}
272
273impl Unmarshal for StatusVectorChunk {
274    /// Unmarshal ..
275    fn unmarshal<B>(raw_packet: &mut B) -> Result<Self>
276    where
277        Self: Sized,
278        B: Buf,
279    {
280        let raw_packet_len = raw_packet.remaining();
281        if raw_packet_len < PACKET_STATUS_CHUNK_LENGTH {
282            return Err(Error::PacketBeforeCname);
283        }
284
285        let type_tcc = StatusChunkTypeTcc::StatusVectorChunk;
286
287        let b0 = raw_packet.get_u8();
288        let b1 = raw_packet.get_u8();
289
290        let symbol_size = get_nbits_from_byte(b0, 1, 1).into();
291
292        let mut symbol_list: Vec<SymbolTypeTcc> = vec![];
293        match symbol_size {
294            SymbolSizeTypeTcc::OneBit => {
295                for i in 0..6u16 {
296                    symbol_list.push(get_nbits_from_byte(b0, 2 + i, 1).into());
297                }
298
299                for i in 0..8u16 {
300                    symbol_list.push(get_nbits_from_byte(b1, i, 1).into())
301                }
302            }
303
304            SymbolSizeTypeTcc::TwoBit => {
305                for i in 0..3u16 {
306                    symbol_list.push(get_nbits_from_byte(b0, 2 + i * 2, 2).into());
307                }
308
309                for i in 0..4u16 {
310                    symbol_list.push(get_nbits_from_byte(b1, i * 2, 2).into());
311                }
312            }
313        }
314
315        Ok(StatusVectorChunk {
316            type_tcc,
317            symbol_size,
318            symbol_list,
319        })
320    }
321}
322
323/// RecvDelta are represented as multiples of 250us
324/// small delta is 1 byte: [0,63.75]ms = [0, 63750]us = [0, 255]*250us
325/// big delta is 2 bytes: [-8192.0, 8191.75]ms = [-8192000, 8191750]us = [-32768, 32767]*250us
326/// <https://tools.ietf.org/html/draft-holmer-rmcat-transport-wide-cc-extensions-01#section-3.1.5>
327#[derive(Debug, Clone, PartialEq, Eq, Default)]
328pub struct RecvDelta {
329    /// Which symbol size this chunk uses.
330    pub type_tcc_packet: SymbolTypeTcc,
331    /// us
332    pub delta: i64,
333}
334
335impl MarshalSize for RecvDelta {
336    fn marshal_size(&self) -> usize {
337        let delta = self.delta / TYPE_TCC_DELTA_SCALE_FACTOR;
338
339        // small delta
340        if self.type_tcc_packet == SymbolTypeTcc::PacketReceivedSmallDelta
341            && delta >= 0
342            && delta <= u8::MAX as i64
343        {
344            return 1;
345        }
346
347        // big delta
348        if self.type_tcc_packet == SymbolTypeTcc::PacketReceivedLargeDelta
349            && delta >= i16::MIN as i64
350            && delta <= i16::MAX as i64
351        {
352            return 2;
353        }
354
355        0
356    }
357}
358
359impl Marshal for RecvDelta {
360    /// Marshal ..
361    fn marshal_to(&self, mut buf: &mut [u8]) -> Result<usize> {
362        let delta = self.delta / TYPE_TCC_DELTA_SCALE_FACTOR;
363
364        // small delta
365        if self.type_tcc_packet == SymbolTypeTcc::PacketReceivedSmallDelta
366            && delta >= 0
367            && delta <= u8::MAX as i64
368            && buf.remaining_mut() >= 1
369        {
370            buf.put_u8(delta as u8);
371            return Ok(1);
372        }
373
374        // big delta
375        if self.type_tcc_packet == SymbolTypeTcc::PacketReceivedLargeDelta
376            && delta >= i16::MIN as i64
377            && delta <= i16::MAX as i64
378            && buf.remaining_mut() >= 2
379        {
380            buf.put_i16(delta as i16);
381            return Ok(2);
382        }
383
384        // overflow
385        Err(Error::DeltaExceedLimit)
386    }
387}
388
389impl Unmarshal for RecvDelta {
390    /// Unmarshal ..
391    fn unmarshal<B>(raw_packet: &mut B) -> Result<Self>
392    where
393        Self: Sized,
394        B: Buf,
395    {
396        let chunk_len = raw_packet.remaining();
397
398        // must be 1 or 2 bytes
399        if chunk_len != 1 && chunk_len != 2 {
400            return Err(Error::DeltaExceedLimit);
401        }
402
403        let (type_tcc_packet, delta) = if chunk_len == 1 {
404            (
405                SymbolTypeTcc::PacketReceivedSmallDelta,
406                TYPE_TCC_DELTA_SCALE_FACTOR * raw_packet.get_u8() as i64,
407            )
408        } else {
409            (
410                SymbolTypeTcc::PacketReceivedLargeDelta,
411                TYPE_TCC_DELTA_SCALE_FACTOR * raw_packet.get_i16() as i64,
412            )
413        };
414
415        Ok(RecvDelta {
416            type_tcc_packet,
417            delta,
418        })
419    }
420}
421
422/// The offset after header
423const BASE_SEQUENCE_NUMBER_OFFSET: usize = 8;
424/// The offset after header
425const PACKET_STATUS_COUNT_OFFSET: usize = 10;
426/// The offset after header
427const REFERENCE_TIME_OFFSET: usize = 12;
428/// The offset after header
429const FB_PKT_COUNT_OFFSET: usize = 15;
430/// The offset after header
431const PACKET_CHUNK_OFFSET: usize = 16;
432/// len of packet status chunk
433const TYPE_TCC_STATUS_VECTOR_CHUNK: usize = 1;
434
435/// <https://tools.ietf.org/html/draft-holmer-rmcat-transport-wide-cc-extensions-01#section-3.1.5>
436pub const TYPE_TCC_DELTA_SCALE_FACTOR: i64 = 250;
437
438// Notice: RFC is wrong: "packet received" (0) and "packet not received" (1)
439// if S == TYPE_TCCSYMBOL_SIZE_ONE_BIT, symbol list will be: TypeTCCPacketNotReceived TypeTCCPacketReceivedSmallDelta
440// if S == TYPE_TCCSYMBOL_SIZE_TWO_BIT, symbol list will be same as above:
441
442static NUM_OF_BITS_OF_SYMBOL_SIZE: [u16; 2] = [1, 2];
443
444/// len of packet status chunk
445const PACKET_STATUS_CHUNK_LENGTH: usize = 2;
446
447/// TransportLayerCC for sender-BWE
448/// <https://tools.ietf.org/html/draft-holmer-rmcat-transport-wide-cc-extensions-01#page-5>
449#[derive(Debug, Default, PartialEq, Eq, Clone)]
450pub struct TransportLayerCc {
451    /// SSRC of sender
452    pub sender_ssrc: u32,
453    /// SSRC of the media source
454    pub media_ssrc: u32,
455    /// Transport wide sequence of rtp extension
456    pub base_sequence_number: u16,
457    /// packet_status_count
458    pub packet_status_count: u16,
459    /// reference_time
460    pub reference_time: u32,
461    /// fb_pkt_count
462    pub fb_pkt_count: u8,
463    /// packet_chunks
464    pub packet_chunks: Vec<PacketStatusChunk>,
465    /// recv_deltas
466    pub recv_deltas: Vec<RecvDelta>,
467}
468
469impl fmt::Display for TransportLayerCc {
470    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
471        let mut out = String::new();
472        out += format!("TransportLayerCC:\n\tSender Ssrc {}\n", self.sender_ssrc).as_str();
473        out += format!("\tMedia Ssrc {}\n", self.media_ssrc).as_str();
474        out += format!("\tBase Sequence Number {}\n", self.base_sequence_number).as_str();
475        out += format!("\tStatus Count {}\n", self.packet_status_count).as_str();
476        out += format!("\tReference Time {}\n", self.reference_time).as_str();
477        out += format!("\tFeedback Packet Count {}\n", self.fb_pkt_count).as_str();
478        out += "\tpacket_chunks ";
479        out += "\n\trecv_deltas ";
480        for delta in &self.recv_deltas {
481            out += format!("{delta:?} ").as_str();
482        }
483        out += "\n";
484
485        write!(f, "{out}")
486    }
487}
488
489impl Packet for TransportLayerCc {
490    fn header(&self) -> Header {
491        Header {
492            padding: get_padding_size(self.raw_size()) != 0,
493            count: FORMAT_TCC,
494            packet_type: PacketType::TransportSpecificFeedback,
495            length: ((self.marshal_size() / 4) - 1) as u16,
496        }
497    }
498
499    /// destination_ssrc returns an array of SSRC values that this packet refers to.
500    fn destination_ssrc(&self) -> Vec<u32> {
501        vec![self.media_ssrc]
502    }
503
504    fn raw_size(&self) -> usize {
505        let mut n = HEADER_LENGTH + PACKET_CHUNK_OFFSET + self.packet_chunks.len() * 2;
506        for d in &self.recv_deltas {
507            // small delta
508            if d.type_tcc_packet == SymbolTypeTcc::PacketReceivedSmallDelta {
509                n += 1;
510            } else {
511                n += 2
512            }
513        }
514        n
515    }
516
517    fn as_any(&self) -> &dyn Any {
518        self
519    }
520
521    fn equal(&self, other: &dyn Packet) -> bool {
522        other.as_any().downcast_ref::<TransportLayerCc>() == Some(self)
523    }
524
525    fn cloned(&self) -> Box<dyn Packet> {
526        Box::new(self.clone())
527    }
528}
529
530impl MarshalSize for TransportLayerCc {
531    fn marshal_size(&self) -> usize {
532        let l = self.raw_size();
533        // align to 32-bit boundary
534        l + get_padding_size(l)
535    }
536}
537
538impl Marshal for TransportLayerCc {
539    fn marshal_to(&self, mut buf: &mut [u8]) -> Result<usize> {
540        if buf.remaining_mut() < self.marshal_size() {
541            return Err(Error::BufferTooShort);
542        }
543
544        let h = self.header();
545        let n = h.marshal_to(buf)?;
546        buf = &mut buf[n..];
547
548        buf.put_u32(self.sender_ssrc);
549        buf.put_u32(self.media_ssrc);
550        buf.put_u16(self.base_sequence_number);
551        buf.put_u16(self.packet_status_count);
552
553        let reference_time_and_fb_pkt_count = append_nbits_to_uint32(0, 24, self.reference_time);
554        let reference_time_and_fb_pkt_count =
555            append_nbits_to_uint32(reference_time_and_fb_pkt_count, 8, self.fb_pkt_count as u32);
556
557        buf.put_u32(reference_time_and_fb_pkt_count);
558
559        for chunk in &self.packet_chunks {
560            let n = chunk.marshal_to(buf)?;
561            buf = &mut buf[n..];
562        }
563
564        for delta in &self.recv_deltas {
565            let n = delta.marshal_to(buf)?;
566            buf = &mut buf[n..];
567        }
568
569        if h.padding {
570            put_padding(buf, self.raw_size());
571        }
572
573        Ok(self.marshal_size())
574    }
575}
576
577impl Unmarshal for TransportLayerCc {
578    /// Unmarshal ..
579    fn unmarshal<B>(raw_packet: &mut B) -> Result<Self>
580    where
581        Self: Sized,
582        B: Buf,
583    {
584        let raw_packet_len = raw_packet.remaining();
585        if raw_packet_len < (HEADER_LENGTH + SSRC_LENGTH) {
586            return Err(Error::PacketTooShort);
587        }
588
589        let h = Header::unmarshal(raw_packet)?;
590
591        // https://tools.ietf.org/html/rfc4585#page-33
592        // header's length + payload's length
593        let total_length = 4 * (h.length + 1) as usize;
594
595        if total_length < HEADER_LENGTH + PACKET_CHUNK_OFFSET {
596            return Err(Error::PacketTooShort);
597        }
598
599        if raw_packet_len < total_length {
600            return Err(Error::PacketTooShort);
601        }
602
603        if h.packet_type != PacketType::TransportSpecificFeedback || h.count != FORMAT_TCC {
604            return Err(Error::WrongType);
605        }
606
607        let sender_ssrc = raw_packet.get_u32();
608        let media_ssrc = raw_packet.get_u32();
609        let base_sequence_number = raw_packet.get_u16();
610        let packet_status_count = raw_packet.get_u16();
611
612        let mut buf = vec![0u8; 3];
613        buf[0] = raw_packet.get_u8();
614        buf[1] = raw_packet.get_u8();
615        buf[2] = raw_packet.get_u8();
616        let reference_time = get_24bits_from_bytes(&buf);
617        let fb_pkt_count = raw_packet.get_u8();
618        let mut packet_chunks = vec![];
619        let mut recv_deltas = vec![];
620
621        let mut packet_status_pos = HEADER_LENGTH + PACKET_CHUNK_OFFSET;
622        let mut processed_packet_num = 0u16;
623        while processed_packet_num < packet_status_count {
624            if packet_status_pos + PACKET_STATUS_CHUNK_LENGTH >= total_length {
625                return Err(Error::PacketTooShort);
626            }
627
628            let mut chunk_reader = raw_packet.copy_to_bytes(PACKET_STATUS_CHUNK_LENGTH);
629            let b0 = chunk_reader[0];
630
631            let typ = get_nbits_from_byte(b0, 0, 1);
632            let initial_packet_status: PacketStatusChunk;
633            match typ.into() {
634                StatusChunkTypeTcc::RunLengthChunk => {
635                    let packet_status = RunLengthChunk::unmarshal(&mut chunk_reader)?;
636                    let packet_number_to_process =
637                        (packet_status_count - processed_packet_num).min(packet_status.run_length);
638
639                    if packet_status.packet_status_symbol == SymbolTypeTcc::PacketReceivedSmallDelta
640                        || packet_status.packet_status_symbol
641                            == SymbolTypeTcc::PacketReceivedLargeDelta
642                    {
643                        let mut j = 0u16;
644
645                        while j < packet_number_to_process {
646                            recv_deltas.push(RecvDelta {
647                                type_tcc_packet: packet_status.packet_status_symbol,
648                                ..Default::default()
649                            });
650
651                            j += 1;
652                        }
653                    }
654
655                    initial_packet_status = PacketStatusChunk::RunLengthChunk(packet_status);
656
657                    processed_packet_num =
658                        processed_packet_num.saturating_add(packet_number_to_process);
659                }
660
661                StatusChunkTypeTcc::StatusVectorChunk => {
662                    let packet_status = StatusVectorChunk::unmarshal(&mut chunk_reader)?;
663
664                    match packet_status.symbol_size {
665                        SymbolSizeTypeTcc::OneBit => {
666                            for sym in &packet_status.symbol_list {
667                                if *sym == SymbolTypeTcc::PacketReceivedSmallDelta {
668                                    recv_deltas.push(RecvDelta {
669                                        type_tcc_packet: SymbolTypeTcc::PacketReceivedSmallDelta,
670                                        ..Default::default()
671                                    })
672                                }
673                            }
674                        }
675
676                        SymbolSizeTypeTcc::TwoBit => {
677                            for sym in &packet_status.symbol_list {
678                                if *sym == SymbolTypeTcc::PacketReceivedSmallDelta
679                                    || *sym == SymbolTypeTcc::PacketReceivedLargeDelta
680                                {
681                                    recv_deltas.push(RecvDelta {
682                                        type_tcc_packet: *sym,
683                                        ..Default::default()
684                                    })
685                                }
686                            }
687                        }
688                    }
689
690                    processed_packet_num =
691                        processed_packet_num.saturating_add(packet_status.symbol_list.len() as u16);
692                    initial_packet_status = PacketStatusChunk::StatusVectorChunk(packet_status);
693                }
694            }
695
696            packet_status_pos += PACKET_STATUS_CHUNK_LENGTH;
697            packet_chunks.push(initial_packet_status);
698        }
699
700        let mut recv_deltas_pos = packet_status_pos;
701
702        for delta in &mut recv_deltas {
703            if recv_deltas_pos >= total_length {
704                return Err(Error::PacketTooShort);
705            }
706
707            if delta.type_tcc_packet == SymbolTypeTcc::PacketReceivedSmallDelta {
708                let mut delta_reader = raw_packet.take(1);
709                *delta = RecvDelta::unmarshal(&mut delta_reader)?;
710                recv_deltas_pos += 1;
711            }
712
713            if delta.type_tcc_packet == SymbolTypeTcc::PacketReceivedLargeDelta {
714                let mut delta_reader = raw_packet.take(2);
715                *delta = RecvDelta::unmarshal(&mut delta_reader)?;
716                recv_deltas_pos += 2;
717            }
718        }
719
720        if
721        /*h.padding &&*/
722        raw_packet.has_remaining() {
723            raw_packet.advance(raw_packet.remaining());
724        }
725
726        Ok(TransportLayerCc {
727            sender_ssrc,
728            media_ssrc,
729            base_sequence_number,
730            packet_status_count,
731            reference_time,
732            fb_pkt_count,
733            packet_chunks,
734            recv_deltas,
735        })
736    }
737}