Skip to main content

rtc_rtcp/transport_feedbacks/transport_layer_nack/
mod.rs

1#[cfg(test)]
2mod transport_layer_nack_test;
3
4use crate::{header::*, packet::*, util::*};
5use shared::{
6    error::{Error, Result},
7    marshal::{Marshal, MarshalSize, Unmarshal},
8};
9
10use bytes::{Buf, BufMut};
11use std::any::Any;
12use std::fmt;
13
14/// PacketBitmap shouldn't be used like a normal integral,
15/// so it's type is masked here. Access it with PacketList().
16type PacketBitmap = u16;
17
18/// NackPair is a wire-representation of a collection of
19/// Lost RTP packets
20#[derive(Debug, PartialEq, Eq, Default, Clone, Copy)]
21pub struct NackPair {
22    /// ID of lost packets
23    pub packet_id: u16,
24    /// Bitmask of following lost packets
25    pub lost_packets: PacketBitmap,
26}
27
28pub struct NackIterator {
29    packet_id: u16,
30    bitfield: PacketBitmap,
31    has_yielded_packet_id: bool,
32}
33
34impl Iterator for NackIterator {
35    type Item = u16;
36
37    fn next(&mut self) -> Option<Self::Item> {
38        if !self.has_yielded_packet_id {
39            self.has_yielded_packet_id = true;
40
41            Some(self.packet_id)
42        } else {
43            let mut i = 0;
44
45            while self.bitfield != 0 {
46                if (self.bitfield & (1 << i)) != 0 {
47                    self.bitfield &= !(1 << i);
48
49                    return Some(self.packet_id.wrapping_add(i + 1));
50                }
51
52                i += 1;
53            }
54
55            None
56        }
57    }
58}
59
60impl NackPair {
61    pub fn new(seq: u16) -> Self {
62        Self {
63            packet_id: seq,
64            lost_packets: Default::default(),
65        }
66    }
67
68    /// PacketList returns a list of Nack'd packets that's referenced by a NackPair
69    pub fn packet_list(&self) -> Vec<u16> {
70        self.into_iter().collect()
71    }
72
73    pub fn range<F>(&self, f: F)
74    where
75        F: Fn(u16) -> bool,
76    {
77        for packet_id in self.into_iter() {
78            if !f(packet_id) {
79                return;
80            }
81        }
82    }
83}
84
85/// Create an iterator over all the packet sequence numbers expressed by this NACK pair.
86impl IntoIterator for NackPair {
87    type Item = u16;
88
89    type IntoIter = NackIterator;
90
91    fn into_iter(self) -> Self::IntoIter {
92        NackIterator {
93            packet_id: self.packet_id,
94            bitfield: self.lost_packets,
95            has_yielded_packet_id: false,
96        }
97    }
98}
99
100const TLN_LENGTH: usize = 2;
101const NACK_OFFSET: usize = 8;
102
103// https://datatracker.ietf.org/doc/html/rfc4585#section-6.2.1
104//
105// The FCI field MUST contain at least one and MAY contain more than one
106// Generic NACK.
107const NACK_MIN_OCTET_COUNT: usize = 12;
108
109// The TransportLayerNack packet informs the encoder about the loss of a transport packet
110/// ## Specifications
111///
112/// * [RFC 4585 §6.2.1]
113///
114/// [RFC 4585 §6.2.1]: https://tools.ietf.org/html/rfc4585#section-6.2.1
115#[derive(Debug, PartialEq, Eq, Default, Clone)]
116pub struct TransportLayerNack {
117    /// SSRC of sender
118    pub sender_ssrc: u32,
119    /// SSRC of the media source
120    pub media_ssrc: u32,
121
122    pub nacks: Vec<NackPair>,
123}
124
125impl fmt::Display for TransportLayerNack {
126    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
127        let mut out = format!("TransportLayerNack from {:x}\n", self.sender_ssrc);
128        out += format!("\tMedia Ssrc {:x}\n", self.media_ssrc).as_str();
129        out += "\tID\tLostPackets\n";
130        for nack in &self.nacks {
131            out += format!("\t{}\t{:b}\n", nack.packet_id, nack.lost_packets).as_str();
132        }
133        write!(f, "{out}")
134    }
135}
136
137impl Packet for TransportLayerNack {
138    /// returns the Header associated with this packet.
139    fn header(&self) -> Header {
140        Header {
141            padding: get_padding_size(self.raw_size()) != 0,
142            count: FORMAT_TLN,
143            packet_type: PacketType::TransportSpecificFeedback,
144            length: ((self.marshal_size() / 4) - 1) as u16,
145        }
146    }
147
148    /// destination_ssrc returns an array of SSRC values that this packet refers to.
149    fn destination_ssrc(&self) -> Vec<u32> {
150        vec![self.media_ssrc]
151    }
152
153    fn raw_size(&self) -> usize {
154        HEADER_LENGTH + NACK_OFFSET + self.nacks.len() * 4
155    }
156
157    fn as_any(&self) -> &dyn Any {
158        self
159    }
160
161    fn equal(&self, other: &dyn Packet) -> bool {
162        other.as_any().downcast_ref::<TransportLayerNack>() == Some(self)
163    }
164
165    fn cloned(&self) -> Box<dyn Packet> {
166        Box::new(self.clone())
167    }
168}
169
170impl MarshalSize for TransportLayerNack {
171    fn marshal_size(&self) -> usize {
172        let l = self.raw_size();
173        // align to 32-bit boundary
174        l + get_padding_size(l)
175    }
176}
177
178impl Marshal for TransportLayerNack {
179    /// Marshal encodes the packet in binary.
180    fn marshal_to(&self, mut buf: &mut [u8]) -> Result<usize> {
181        if self.nacks.len() + TLN_LENGTH > u8::MAX as usize {
182            return Err(Error::TooManyReports);
183        }
184        if buf.remaining_mut() < self.marshal_size() {
185            return Err(Error::BufferTooShort);
186        }
187
188        let h = self.header();
189        let n = h.marshal_to(buf)?;
190        buf = &mut buf[n..];
191
192        buf.put_u32(self.sender_ssrc);
193        buf.put_u32(self.media_ssrc);
194
195        for i in 0..self.nacks.len() {
196            buf.put_u16(self.nacks[i].packet_id);
197            buf.put_u16(self.nacks[i].lost_packets);
198        }
199
200        if h.padding {
201            put_padding(buf, self.raw_size());
202        }
203
204        Ok(self.marshal_size())
205    }
206}
207
208impl Unmarshal for TransportLayerNack {
209    /// Unmarshal decodes the ReceptionReport from binary
210    fn unmarshal<B>(raw_packet: &mut B) -> Result<Self>
211    where
212        Self: Sized,
213        B: Buf,
214    {
215        let raw_packet_len = raw_packet.remaining();
216        if raw_packet_len < (HEADER_LENGTH + NACK_MIN_OCTET_COUNT) {
217            return Err(Error::PacketTooShort);
218        }
219
220        let h = Header::unmarshal(raw_packet)?;
221
222        if raw_packet_len < (HEADER_LENGTH + 4 * (h.length as usize)) {
223            return Err(Error::PacketTooShort);
224        }
225
226        if h.packet_type != PacketType::TransportSpecificFeedback || h.count != FORMAT_TLN {
227            return Err(Error::WrongType);
228        }
229
230        let sender_ssrc = raw_packet.get_u32();
231        let media_ssrc = raw_packet.get_u32();
232
233        let mut nacks = vec![];
234        for _i in 0..(h.length as i32 - NACK_OFFSET as i32 / 4) {
235            nacks.push(NackPair {
236                packet_id: raw_packet.get_u16(),
237                lost_packets: raw_packet.get_u16(),
238            });
239        }
240
241        if
242        /*h.padding &&*/
243        raw_packet.has_remaining() {
244            raw_packet.advance(raw_packet.remaining());
245        }
246
247        Ok(TransportLayerNack {
248            sender_ssrc,
249            media_ssrc,
250            nacks,
251        })
252    }
253}
254
255pub fn nack_pairs_from_sequence_numbers(seq_nos: &[u16]) -> Vec<NackPair> {
256    if seq_nos.is_empty() {
257        return vec![];
258    }
259
260    let mut nack_pair = NackPair::new(seq_nos[0]);
261    let mut pairs = vec![];
262
263    for &seq in seq_nos.iter().skip(1) {
264        if seq == nack_pair.packet_id {
265            continue;
266        }
267        if seq <= nack_pair.packet_id || seq > nack_pair.packet_id.saturating_add(16) {
268            pairs.push(nack_pair);
269            nack_pair = NackPair::new(seq);
270            continue;
271        }
272
273        // Subtraction here is safe because the above checks that seqnum > nack_pair.packet_id.
274        nack_pair.lost_packets |= 1 << (seq - nack_pair.packet_id - 1);
275    }
276
277    pairs.push(nack_pair);
278
279    pairs
280}