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