1use std::collections::BTreeSet;
4
5use crate::feedback::FciFeedbackPacketType;
6use crate::{prelude::*, utils::u16_from_be_bytes};
7use crate::{RtcpParseError, RtcpWriteError};
8
9pub struct NackParserEntryIter<'a> {
11 parser: &'a Nack<'a>,
12 i: usize,
13 mask_i: usize,
14}
15
16impl NackParserEntryIter<'_> {
17 fn decode_entry(entry: &[u8]) -> (u16, u16) {
18 (
19 u16_from_be_bytes(&entry[0..2]),
20 u16_from_be_bytes(&entry[2..4]),
21 )
22 }
23}
24
25impl std::iter::Iterator for NackParserEntryIter<'_> {
26 type Item = u16;
27
28 fn next(&mut self) -> Option<Self::Item> {
29 loop {
30 if self.mask_i > 16 {
31 self.mask_i = 0;
32 self.i += 1;
33 }
34 let idx = self.i * 4;
35 if idx + 3 >= self.parser.data.len() {
36 return None;
37 }
38 let (base, mask) = NackParserEntryIter::decode_entry(&self.parser.data[idx..]);
39 if self.mask_i == 0 {
40 self.mask_i += 1;
41 return Some(base);
42 }
43
44 loop {
45 let mask = mask >> (self.mask_i - 1);
46 if (mask & 0x1) > 0 {
47 self.mask_i += 1;
48 let ret = base.wrapping_add(self.mask_i as u16 - 1);
49 return Some(ret);
50 }
51 self.mask_i += 1;
52 if self.mask_i > 16 {
53 break;
54 }
55 }
56 }
57 }
58}
59
60#[derive(Debug)]
62pub struct Nack<'a> {
63 data: &'a [u8],
64}
65
66impl Nack<'_> {
67 pub fn entries(&self) -> impl Iterator<Item = u16> + '_ {
69 NackParserEntryIter {
70 parser: self,
71 i: 0,
72 mask_i: 0,
73 }
74 }
75
76 pub fn builder() -> NackBuilder {
78 NackBuilder::default()
79 }
80}
81
82impl<'a> FciParser<'a> for Nack<'a> {
83 const PACKET_TYPE: FciFeedbackPacketType = FciFeedbackPacketType::TRANSPORT;
84 const FCI_FORMAT: u8 = 1;
85
86 fn parse(data: &'a [u8]) -> Result<Self, RtcpParseError> {
87 Ok(Self { data })
88 }
89}
90
91struct NackBuilderEntryIter<I: Iterator<Item = u16>> {
92 i: usize,
93 base_entry: Option<u16>,
94 seq_iter: I,
95 last_entry: u16,
96}
97
98fn encode_entry(base: u16, mask: u16) -> [u8; 4] {
99 [
100 ((base & 0xff00) >> 8) as u8,
101 (base & 0xff) as u8,
102 ((mask & 0xff00) >> 8) as u8,
103 (mask & 0xff) as u8,
104 ]
105}
106
107impl<I: Iterator<Item = u16>> std::iter::Iterator for NackBuilderEntryIter<I> {
108 type Item = [u8; 4];
109
110 fn next(&mut self) -> Option<Self::Item> {
111 let mut bitmask = 0;
112 for entry in self.seq_iter.by_ref() {
113 self.last_entry = entry;
114 if let Some(base) = self.base_entry {
115 let diff = entry.wrapping_sub(base);
116 if diff > 16 {
117 let ret = encode_entry(base, bitmask);
119 self.base_entry = Some(entry);
120 return Some(ret);
121 }
122 if diff > 0 {
123 bitmask |= 1 << (diff - 1);
124 }
125 self.i += 1;
126 } else {
127 self.base_entry = Some(entry);
129 self.i += 1;
130 continue;
131 }
132 }
133
134 if let Some(base) = self.base_entry {
135 let ret = encode_entry(base, bitmask);
137 self.base_entry = None;
138 return Some(ret);
139 }
140 None
141 }
142}
143
144#[derive(Debug, Default)]
146pub struct NackBuilder {
147 rtp_seq: BTreeSet<u16>,
148}
149
150impl NackBuilder {
151 pub fn add_rtp_sequence(mut self, rtp_sequence: u16) -> Self {
153 self.rtp_seq.insert(rtp_sequence);
154 self
155 }
156
157 fn entries(&self) -> impl Iterator<Item = [u8; 4]> + '_ {
158 NackBuilderEntryIter {
159 i: 0,
160 base_entry: None,
161 seq_iter: self.rtp_seq.iter().copied(),
162 last_entry: 0,
163 }
164 }
165}
166
167impl FciBuilder<'_> for NackBuilder {
168 fn format(&self) -> u8 {
169 1
170 }
171
172 fn supports_feedback_type(&self) -> FciFeedbackPacketType {
173 FciFeedbackPacketType::TRANSPORT
174 }
175}
176
177impl RtcpPacketWriter for NackBuilder {
178 fn calculate_size(&self) -> Result<usize, RtcpWriteError> {
179 let entries = self.entries().count();
180 if entries > u16::MAX as usize - 2 {
181 return Err(RtcpWriteError::TooManyNack);
182 }
183 Ok(entries * 4)
184 }
185
186 fn write_into_unchecked(&self, buf: &mut [u8]) -> usize {
187 let mut idx = 0;
188 let mut end = idx;
189
190 for entry in self.entries() {
191 end += 4;
192 buf[idx..end].copy_from_slice(&entry);
193 idx = end;
194 }
195 end
196 }
197
198 fn get_padding(&self) -> Option<u8> {
199 None
200 }
201}
202
203#[cfg(test)]
204mod tests {
205 use super::*;
206 use crate::feedback::TransportFeedback;
207
208 fn nack_build_parse_n_consecutive_timestamps(start: u16, n: u16, fci: &[u8]) {
209 nack_build_parse_n_m_timestamps(start, n, 1, fci)
210 }
211
212 fn nack_build_parse_n_m_timestamps(start: u16, n: u16, m: u16, fci: &[u8]) {
213 assert!(n > 1);
214 let r = (n + 1) % m;
215 let req_len = TransportFeedback::MIN_PACKET_LEN + ((n - r + 16) / 17 * 4) as usize;
216 let mut data = vec![0; req_len];
217 let mut expected = vec![0; req_len];
218 const TEMPLATE: [u8; 12] = [
219 0x81, 0xcd, 0x00, 0x00, 0x98, 0x76, 0x54, 0x32, 0x10, 0xfe, 0xdc, 0xba,
220 ];
221 expected[0..12].copy_from_slice(&TEMPLATE);
222 expected[3] = (req_len / 4 - 1) as u8;
223 expected[12..12 + fci.len()].copy_from_slice(fci);
224 let nack = {
225 let mut fci = Nack::builder();
226 for i in (0..=n - 1).step_by(m as usize) {
227 fci = fci.add_rtp_sequence(start + i);
228 }
229 TransportFeedback::builder_owned(fci)
230 .sender_ssrc(0x98765432)
231 .media_ssrc(0x10fedcba)
232 };
233 assert_eq!(nack.calculate_size().unwrap(), req_len);
234 let len = nack.write_into(&mut data).unwrap();
235 assert_eq!(len, req_len);
236 assert_eq!(data, expected);
237
238 let fb = TransportFeedback::parse(&data).unwrap();
239 assert_eq!(fb.sender_ssrc(), 0x98765432);
240 assert_eq!(fb.media_ssrc(), 0x10fedcba);
241 let nack = fb.parse_fci::<Nack>().unwrap();
242 let mut nack_iter = nack.entries();
243 for i in (0..=n - 1).step_by(m as usize) {
244 assert_eq!(nack_iter.next(), Some(0x1234 + i));
245 }
246 assert_eq!(nack_iter.next(), None);
247 }
248
249 #[test]
250 fn nack_build_parse_2_consecutive_timestamps() {
251 nack_build_parse_n_consecutive_timestamps(0x1234, 2, &[0x12, 0x34, 0x00, 0x01]);
252 }
253
254 #[test]
255 fn nack_build_parse_16_consecutive_timestamps() {
256 nack_build_parse_n_consecutive_timestamps(0x1234, 16, &[0x12, 0x34, 0x7f, 0xff]);
257 }
258
259 #[test]
260 fn nack_build_parse_17_consecutive_timestamps() {
261 nack_build_parse_n_consecutive_timestamps(0x1234, 17, &[0x12, 0x34, 0xff, 0xff]);
262 }
263
264 #[test]
265 fn nack_build_parse_18_consecutive_timestamps() {
266 nack_build_parse_n_consecutive_timestamps(
267 0x1234,
268 18,
269 &[0x12, 0x34, 0xff, 0xff, 0x12, 0x45, 0x00, 0x00],
270 );
271 }
272
273 #[test]
274 fn nack_build_parse_12_2_timestamps() {
275 nack_build_parse_n_m_timestamps(0x1234, 12, 2, &[0x12, 0x34, 0x02, 0b1010_1010]);
276 }
277
278 #[test]
279 fn nack_build_ref_2_consecutive_timestamps() {
280 let n = 2;
281 let m = 1;
282 let fci = &[0x12, 0x34, 0x00, 0x01];
283
284 let r = (n + 1) % m;
285 let req_len = TransportFeedback::MIN_PACKET_LEN + ((n - r + 16) / 17 * 4) as usize;
286 let mut data = vec![0; req_len];
287 let mut expected = vec![0; req_len];
288 const TEMPLATE: [u8; 12] = [
289 0x81, 0xcd, 0x00, 0x00, 0x98, 0x76, 0x54, 0x32, 0x10, 0xfe, 0xdc, 0xba,
290 ];
291 expected[0..12].copy_from_slice(&TEMPLATE);
292 expected[3] = (req_len / 4 - 1) as u8;
293 expected[12..12 + fci.len()].copy_from_slice(fci);
294 let mut fci = Nack::builder();
295 for i in (0..=n - 1).step_by(m as usize) {
296 fci = fci.add_rtp_sequence(0x1234 + i);
297 }
298 let nack = TransportFeedback::builder(&fci)
299 .sender_ssrc(0x98765432)
300 .media_ssrc(0x10fedcba);
301 assert_eq!(nack.calculate_size().unwrap(), req_len);
302 let len = nack.write_into(&mut data).unwrap();
303 assert_eq!(len, req_len);
304 assert_eq!(data, expected);
305 }
306}