File
Blob: firmware/vendor/str0m/src/rtp/rtcp/remb.rs
| 1 | use crate::rtp::Ssrc; |
| 2 | |
| 3 | use super::RtcpType; |
| 4 | use super::{FeedbackMessageType, PayloadType, RtcpHeader, RtcpPacket}; |
| 5 | |
| 6 | const BITRATE_MAX: f32 = 2.417_842_4e24; //0x3FFFFp+63; |
| 7 | const MANTISSA_MAX: u32 = 0x7FFFFF; |
| 8 | const REMB_OFFSET: usize = 16; |
| 9 | |
| 10 | const UNIQUE_IDENTIFIER: [u8; 4] = *b"REMB"; |
| 11 | |
| 12 | /* |
| 13 | 0 1 2 3 |
| 14 | 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 |
| 15 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| 16 | |V=2|P| FMT=15 | PT=206 | length | |
| 17 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| 18 | | SSRC of packet sender | |
| 19 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| 20 | | SSRC of media source | |
| 21 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| 22 | | Unique identifier 'R' 'E' 'M' 'B' | |
| 23 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| 24 | | Num SSRC | BR Exp | BR Mantissa | |
| 25 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| 26 | | SSRC feedback | |
| 27 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| 28 | | ... | |
| 29 | */ |
| 30 | |
| 31 | #[derive(Debug, Clone)] |
| 32 | pub struct Remb { |
| 33 | /// SSRC of sender |
| 34 | pub sender_ssrc: Ssrc, |
| 35 | |
| 36 | /// SSRC of source, in Remb is default 0 |
| 37 | pub ssrc: Ssrc, |
| 38 | |
| 39 | /// Estimated maximum bitrate |
| 40 | pub bitrate: f32, |
| 41 | |
| 42 | /// SSRC entries which this packet applies to |
| 43 | pub ssrcs: Vec<u32>, |
| 44 | } |
| 45 | |
| 46 | impl Eq for Remb {} |
| 47 | impl PartialEq for Remb { |
| 48 | fn eq(&self, other: &Self) -> bool { |
| 49 | self.sender_ssrc == other.sender_ssrc |
| 50 | && (self.bitrate as u64) == (other.bitrate as u64) |
| 51 | && self.ssrcs == other.ssrcs |
| 52 | } |
| 53 | } |
| 54 | |
| 55 | impl RtcpPacket for Remb { |
| 56 | fn header(&self) -> RtcpHeader { |
| 57 | RtcpHeader { |
| 58 | rtcp_type: RtcpType::PayloadSpecificFeedback, |
| 59 | feedback_message_type: FeedbackMessageType::PayloadFeedback( |
| 60 | PayloadType::ApplicationLayer, |
| 61 | ), |
| 62 | words_less_one: (self.length_words() - 1) as u16, |
| 63 | } |
| 64 | } |
| 65 | |
| 66 | fn length_words(&self) -> usize { |
| 67 | // header |
| 68 | // remb |
| 69 | // ssrcs |
| 70 | 1 + REMB_OFFSET / 4 + self.ssrcs.len() |
| 71 | } |
| 72 | |
| 73 | fn write_to(&self, buf: &mut [u8]) -> usize { |
| 74 | let mut exp = 0; |
| 75 | let mut bitrate = self.bitrate.clamp(0.0, BITRATE_MAX); |
| 76 | |
| 77 | while bitrate >= (1 << 18) as f32 { |
| 78 | bitrate /= 2.0; |
| 79 | exp += 1; |
| 80 | } |
| 81 | |
| 82 | let mantissa = bitrate.floor() as u32; |
| 83 | |
| 84 | self.header().write_to(&mut buf[..4]); |
| 85 | buf[4..8].copy_from_slice(&self.sender_ssrc.to_be_bytes()); |
| 86 | buf[8..12].copy_from_slice(&[0; 4]); |
| 87 | buf[12..16].copy_from_slice(&UNIQUE_IDENTIFIER); |
| 88 | buf[16] = self.ssrcs.len() as u8; |
| 89 | // We can't quite use the binary package because |
| 90 | // a) it's a uint24 and b) the exponent is only 6-bits |
| 91 | // Just trust me; this is big-endian encoding. |
| 92 | buf[17] = (exp << 2) as u8 | (mantissa >> 16) as u8; |
| 93 | buf[18] = (mantissa >> 8) as u8; |
| 94 | buf[19] = mantissa as u8; |
| 95 | |
| 96 | // Write the SSRCs at the very end. |
| 97 | for (index, ssrc) in self.ssrcs.iter().enumerate() { |
| 98 | let begin = 4 + REMB_OFFSET + index * 4; |
| 99 | let end = begin + 4; |
| 100 | buf[begin..end].copy_from_slice(&ssrc.to_be_bytes()); |
| 101 | } |
| 102 | |
| 103 | 4 + REMB_OFFSET + self.ssrcs.len() * 4 |
| 104 | } |
| 105 | } |
| 106 | |
| 107 | impl<'a> TryFrom<&'a [u8]> for Remb { |
| 108 | type Error = &'static str; |
| 109 | |
| 110 | fn try_from(buf: &'a [u8]) -> Result<Self, Self::Error> { |
| 111 | if buf.len() < 16 { |
| 112 | return Err("Remb less than 16 bytes"); |
| 113 | } |
| 114 | |
| 115 | let sender_ssrc = u32::from_be_bytes([buf[0], buf[1], buf[2], buf[3]]).into(); |
| 116 | let media_ssrc = u32::from_be_bytes([buf[4], buf[5], buf[6], buf[7]]); |
| 117 | if media_ssrc != 0 { |
| 118 | return Err("Ssrc must be zero"); |
| 119 | } |
| 120 | |
| 121 | if buf[8] != UNIQUE_IDENTIFIER[0] |
| 122 | || buf[9] != UNIQUE_IDENTIFIER[1] |
| 123 | || buf[10] != UNIQUE_IDENTIFIER[2] |
| 124 | || buf[11] != UNIQUE_IDENTIFIER[3] |
| 125 | { |
| 126 | return Err("Missing remb identifier"); |
| 127 | } |
| 128 | |
| 129 | // The next byte is the number of SSRC entries at the end. |
| 130 | let ssrcs_len = buf[12] as usize; |
| 131 | |
| 132 | // Get the 6-bit exponent value. |
| 133 | let b17 = buf[13]; |
| 134 | let mut exp = (b17 as u64) >> 2; |
| 135 | exp += 127; // bias for IEEE754 |
| 136 | exp += 23; // IEEE754 biases the decimal to the left, abs-send-time biases it to the right |
| 137 | |
| 138 | // The remaining 2-bits plus the next 16-bits are the mantissa. |
| 139 | let b18 = buf[14]; |
| 140 | let b19 = buf[15]; |
| 141 | let mut mantissa = ((b17 & 3) as u32) << 16 | (b18 as u32) << 8 | b19 as u32; |
| 142 | |
| 143 | if mantissa != 0 { |
| 144 | // ieee754 requires an implicit leading bit |
| 145 | while (mantissa & (MANTISSA_MAX + 1)) == 0 { |
| 146 | exp -= 1; |
| 147 | mantissa *= 2; |
| 148 | } |
| 149 | } |
| 150 | |
| 151 | // bitrate = mantissa * 2^exp |
| 152 | let bitrate = f32::from_bits(((exp as u32) << 23) | (mantissa & MANTISSA_MAX)); |
| 153 | |
| 154 | // `ssrcs_len` is attacker-controlled byte (buf[12], 0..=255) |
| 155 | // reject packets too short to hold that many trailing SSRC bytes. |
| 156 | if buf.len() < REMB_OFFSET + ssrcs_len * 4 { |
| 157 | return Err("Remb ssrcs length exceeds buffer"); |
| 158 | } |
| 159 | |
| 160 | let mut ssrcs = vec![]; |
| 161 | for i in 0..ssrcs_len { |
| 162 | let b_index = 16 + i * 4; |
| 163 | ssrcs.push(u32::from_be_bytes([ |
| 164 | buf[b_index], |
| 165 | buf[b_index + 1], |
| 166 | buf[b_index + 2], |
| 167 | buf[b_index + 3], |
| 168 | ])); |
| 169 | } |
| 170 | |
| 171 | Ok(Remb { |
| 172 | sender_ssrc, |
| 173 | ssrc: 0.into(), |
| 174 | ssrcs, |
| 175 | bitrate, |
| 176 | }) |
| 177 | } |
| 178 | } |
| 179 | |
| 180 | #[cfg(test)] |
| 181 | mod tests { |
| 182 | use super::*; |
| 183 | |
| 184 | #[test] |
| 185 | fn test_receiver_estimated_maximum_bitrate_marshal() { |
| 186 | let input = Remb { |
| 187 | sender_ssrc: 1.into(), |
| 188 | ssrc: 0.into(), |
| 189 | bitrate: 8927168.0, |
| 190 | ssrcs: vec![1215622422], |
| 191 | }; |
| 192 | |
| 193 | let expected = [ |
| 194 | 143, 206, 0, 5, 0, 0, 0, 1, 0, 0, 0, 0, 82, 69, 77, 66, 1, 26, 32, 223, 72, 116, 237, |
| 195 | 22, |
| 196 | ]; |
| 197 | |
| 198 | let mut output = [0; 1500]; |
| 199 | let len = input.write_to(&mut output); |
| 200 | assert_eq!(expected, output[0..len]); |
| 201 | } |
| 202 | |
| 203 | #[test] |
| 204 | fn test_receiver_estimated_maximum_bitrate_unmarshal() { |
| 205 | // Real data sent by Chrome while watching a 6Mb/s stream |
| 206 | let input = [ |
| 207 | 143, 206, 0, 5, 0, 0, 0, 1, 0, 0, 0, 0, 82, 69, 77, 66, 1, 26, 32, 223, 72, 116, 237, |
| 208 | 22, |
| 209 | ]; |
| 210 | |
| 211 | // mantissa = []byte{26 & 3, 32, 223} = []byte{2, 32, 223} = 139487 |
| 212 | // exp = 26 >> 2 = 6 |
| 213 | // bitrate = 139487 * 2^6 = 139487 * 64 = 8927168 = 8.9 Mb/s |
| 214 | let expected = Remb { |
| 215 | sender_ssrc: 1.into(), |
| 216 | ssrc: 0.into(), |
| 217 | bitrate: 8927168.0, |
| 218 | ssrcs: vec![1215622422], |
| 219 | }; |
| 220 | |
| 221 | let packet = Remb::try_from(&input[4..]).unwrap(); |
| 222 | assert_eq!(expected, packet); |
| 223 | } |
| 224 | |
| 225 | #[test] |
| 226 | fn test_receiver_estimated_maximum_bitrate_truncate() { |
| 227 | let input = [ |
| 228 | 143, 206, 0, 5, 0, 0, 0, 1, 0, 0, 0, 0, 82, 69, 77, 66, 1, 26, 32, 223, 72, 116, 237, |
| 229 | 22, |
| 230 | ]; |
| 231 | |
| 232 | // Make sure that we're interpreting the bitrate correctly. |
| 233 | // For the above example, we have: |
| 234 | |
| 235 | // mantissa = 139487 |
| 236 | // exp = 6 |
| 237 | // bitrate = 8927168 |
| 238 | |
| 239 | let mut packet = Remb::try_from(&input[4..]).unwrap(); |
| 240 | assert_eq!(8927168.0, packet.bitrate); |
| 241 | |
| 242 | // Just verify marshal produces the same input. |
| 243 | let mut output = [0; 1500]; |
| 244 | let output_len = packet.write_to(&mut output); |
| 245 | assert_eq!(input, output[0..output_len]); |
| 246 | |
| 247 | // If we subtract the bitrate by 1, we'll round down a lower mantissa |
| 248 | packet.bitrate -= 1.0; |
| 249 | |
| 250 | // bitrate = 8927167 |
| 251 | // mantissa = 139486 |
| 252 | // exp = 6 |
| 253 | |
| 254 | let output_len = packet.write_to(&mut output); |
| 255 | assert_ne!(input, output[0..output_len]); |
| 256 | let expected = [ |
| 257 | 143, 206, 0, 5, 0, 0, 0, 1, 0, 0, 0, 0, 82, 69, 77, 66, 1, 26, 32, 222, 72, 116, 237, |
| 258 | 22, |
| 259 | ]; |
| 260 | assert_eq!(expected, output[0..output_len]); |
| 261 | |
| 262 | // Which if we actually unmarshal again, we'll find that it's actually decreased by 63 (which is exp) |
| 263 | // mantissa = 139486 |
| 264 | // exp = 6 |
| 265 | // bitrate = 8927104 |
| 266 | |
| 267 | let packet = Remb::try_from(&output[4..]).unwrap(); |
| 268 | assert_eq!(8927104.0, packet.bitrate); |
| 269 | } |
| 270 | |
| 271 | #[test] |
| 272 | fn test_receiver_estimated_maximum_bitrate_overflow() { |
| 273 | // Marshal a packet with the maximum possible bitrate. |
| 274 | let packet = Remb { |
| 275 | sender_ssrc: 0.into(), |
| 276 | ssrc: 0.into(), |
| 277 | bitrate: f32::MAX, |
| 278 | ssrcs: vec![], |
| 279 | }; |
| 280 | |
| 281 | // mantissa = 262143 = 0x3FFFF |
| 282 | // exp = 63 |
| 283 | |
| 284 | let expected = [ |
| 285 | 143, 206, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 82, 69, 77, 66, 0, 255, 255, 255, |
| 286 | ]; |
| 287 | |
| 288 | let mut output = [0; 1500]; |
| 289 | let output_len = packet.write_to(&mut output); |
| 290 | assert_eq!(expected, output[0..output_len]); |
| 291 | |
| 292 | // mantissa = 262143 |
| 293 | // exp = 63 |
| 294 | // bitrate = 0xFFFFC00000000000 |
| 295 | |
| 296 | let packet = Remb::try_from(&output[4..output_len]).unwrap(); |
| 297 | assert_eq!(f32::from_bits(0x67FFFFC0), packet.bitrate); |
| 298 | |
| 299 | // Make sure we marshal to the same result again. |
| 300 | let output_len = packet.write_to(&mut output); |
| 301 | assert_eq!(expected, output[0..output_len]); |
| 302 | |
| 303 | // Finally, try unmarshalling one number higher than we used to be able to handle. |
| 304 | let input = [ |
| 305 | 143, 206, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 82, 69, 77, 66, 0, 188, 0, 0, |
| 306 | ]; |
| 307 | let packet = Remb::try_from(&input[4..]).unwrap(); |
| 308 | assert_eq!(f32::from_bits(0x62800000), packet.bitrate); |
| 309 | } |
| 310 | } |