File
Blob: firmware/vendor/str0m/src/rtp/rtcp/nack.rs
| 1 | use super::extend_u16; |
| 2 | use super::{FeedbackMessageType, ReportList, RtcpHeader, RtcpPacket, SeqNo}; |
| 3 | use super::{RtcpType, Ssrc, TransportType}; |
| 4 | |
| 5 | use super::list::private::WordSized; |
| 6 | |
| 7 | /// A NACK entry indiciating packets missing. |
| 8 | #[derive(Debug, Clone, PartialEq, Eq)] |
| 9 | pub struct Nack { |
| 10 | /// Sender of this feedback. Mostly irrelevant, but part of RTCP packets. |
| 11 | pub sender_ssrc: Ssrc, |
| 12 | /// The SSRC this nack reports missing packets for. |
| 13 | pub ssrc: Ssrc, |
| 14 | /// The missing nack. This can be multiple segments. |
| 15 | pub reports: ReportList<NackEntry>, |
| 16 | } |
| 17 | |
| 18 | /// A range of sequence numbers missing. |
| 19 | #[allow(missing_docs)] |
| 20 | #[derive(Debug, PartialEq, Eq, Default, Clone, Copy)] |
| 21 | pub struct NackEntry { |
| 22 | pub pid: u16, |
| 23 | pub blp: u16, |
| 24 | } |
| 25 | |
| 26 | impl RtcpPacket for Nack { |
| 27 | fn header(&self) -> RtcpHeader { |
| 28 | RtcpHeader { |
| 29 | rtcp_type: RtcpType::TransportLayerFeedback, |
| 30 | feedback_message_type: FeedbackMessageType::TransportFeedback(TransportType::Nack), |
| 31 | words_less_one: (self.length_words() - 1) as u16, |
| 32 | } |
| 33 | } |
| 34 | |
| 35 | fn length_words(&self) -> usize { |
| 36 | // header |
| 37 | // sender SSRC |
| 38 | // media SSRC |
| 39 | // 1 word per NackPair |
| 40 | 1 + 2 + self.reports.len() |
| 41 | } |
| 42 | |
| 43 | fn write_to(&self, buf: &mut [u8]) -> usize { |
| 44 | self.header().write_to(&mut buf[..4]); |
| 45 | buf[4..8].copy_from_slice(&self.sender_ssrc.to_be_bytes()); |
| 46 | buf[8..12].copy_from_slice(&self.ssrc.to_be_bytes()); |
| 47 | let mut buf = &mut buf[12..]; |
| 48 | for r in &self.reports { |
| 49 | buf[0..2].copy_from_slice(&r.pid.to_be_bytes()); |
| 50 | buf[2..4].copy_from_slice(&r.blp.to_be_bytes()); |
| 51 | buf = &mut buf[4..]; |
| 52 | } |
| 53 | self.length_words() * 4 |
| 54 | } |
| 55 | } |
| 56 | |
| 57 | impl WordSized for NackEntry { |
| 58 | fn word_size(&self) -> usize { |
| 59 | 1 |
| 60 | } |
| 61 | } |
| 62 | |
| 63 | impl<'a> TryFrom<&'a [u8]> for Nack { |
| 64 | type Error = &'static str; |
| 65 | |
| 66 | fn try_from(buf: &'a [u8]) -> Result<Self, Self::Error> { |
| 67 | if buf.len() < 12 { |
| 68 | return Err("Nack less than 12 bytes"); |
| 69 | } |
| 70 | |
| 71 | let sender_ssrc = u32::from_be_bytes([buf[0], buf[1], buf[2], buf[3]]).into(); |
| 72 | let ssrc = u32::from_be_bytes([buf[4], buf[5], buf[6], buf[7]]).into(); |
| 73 | |
| 74 | let mut reports = ReportList::new(); |
| 75 | |
| 76 | let mut buf = &buf[8..]; |
| 77 | let count = buf.len() / 4; |
| 78 | let max = count.min(31); |
| 79 | |
| 80 | for _ in 0..max { |
| 81 | let pid = u16::from_be_bytes([buf[0], buf[1]]); |
| 82 | let blp = u16::from_be_bytes([buf[2], buf[3]]); |
| 83 | reports.push(NackEntry { pid, blp }); |
| 84 | buf = &buf[4..]; |
| 85 | } |
| 86 | |
| 87 | Ok(Nack { |
| 88 | sender_ssrc, |
| 89 | ssrc, |
| 90 | reports, |
| 91 | }) |
| 92 | } |
| 93 | } |
| 94 | |
| 95 | impl NackEntry { |
| 96 | /// Iterator over sequence numbers missing. |
| 97 | /// |
| 98 | /// The given sequence number is used to interpret ROC. |
| 99 | pub fn into_iter(self, seq_no: SeqNo) -> impl Iterator<Item = SeqNo> { |
| 100 | NackEntryIterator(self, 0, seq_no) |
| 101 | } |
| 102 | } |
| 103 | |
| 104 | pub struct NackEntryIterator(NackEntry, u16, SeqNo); |
| 105 | |
| 106 | impl Iterator for NackEntryIterator { |
| 107 | type Item = SeqNo; |
| 108 | |
| 109 | fn next(&mut self) -> Option<Self::Item> { |
| 110 | let seq_16 = if self.1 == 0 { |
| 111 | self.1 += 1; |
| 112 | self.0.pid |
| 113 | } else { |
| 114 | loop { |
| 115 | if self.1 >= 17 { |
| 116 | return None; |
| 117 | } |
| 118 | let i = self.1 - 1; |
| 119 | self.1 += 1; |
| 120 | if 1 << i & self.0.blp > 0 { |
| 121 | break self.0.pid.wrapping_add(self.1 - 1); |
| 122 | } |
| 123 | } |
| 124 | }; |
| 125 | let l = extend_u16(Some(*self.2), seq_16); |
| 126 | Some(l.into()) |
| 127 | } |
| 128 | } |
| 129 | |
| 130 | #[cfg(test)] |
| 131 | mod test { |
| 132 | use super::*; |
| 133 | |
| 134 | #[test] |
| 135 | fn nack_entry_iter() { |
| 136 | // 196_618 |
| 137 | let seq_no: SeqNo = (65_536_u64 * 3 + 10).into(); |
| 138 | |
| 139 | // 196_508 |
| 140 | let pid = (65_536_u32 - 100) as u16; |
| 141 | |
| 142 | println!("{seq_no:?} {pid:?}"); |
| 143 | |
| 144 | // 196_509, 196_512, 196_524 |
| 145 | let blp = 0b1000_0000_0000_1001; |
| 146 | |
| 147 | let entry = NackEntry { pid, blp }; |
| 148 | |
| 149 | let nacks: Vec<_> = entry.into_iter(seq_no).collect(); |
| 150 | |
| 151 | assert_eq!( |
| 152 | nacks, |
| 153 | vec![196508.into(), 196509.into(), 196512.into(), 196524.into()] |
| 154 | ); |
| 155 | } |
| 156 | } |