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