File
Blob: firmware/vendor/str0m/src/packet/mod.rs
| 1 | #![allow(clippy::type_complexity)] |
| 2 | |
| 3 | use std::fmt; |
| 4 | use std::panic::UnwindSafe; |
| 5 | |
| 6 | use crate::format::Codec; |
| 7 | use crate::sdp::MediaType; |
| 8 | |
| 9 | use crate::rtp::vla::encode_leb_u63; |
| 10 | |
| 11 | mod av1; |
| 12 | pub use av1::Av1CodecExtra; |
| 13 | pub use av1::detect_av1_keyframe; |
| 14 | use av1::{Av1Depacketizer, Av1Packetizer}; |
| 15 | |
| 16 | mod g7xx; |
| 17 | use g7xx::{G711Depacketizer, G711Packetizer, G722Packetizer}; |
| 18 | |
| 19 | mod h264; |
| 20 | pub use h264::H264CodecExtra; |
| 21 | pub use h264::detect_h264_keyframe; |
| 22 | pub use h264::{H264Depacketizer, H264Packetizer}; |
| 23 | |
| 24 | mod h264_profile; |
| 25 | pub(crate) use h264_profile::H264ProfileLevel; |
| 26 | |
| 27 | mod h265; |
| 28 | pub use h265::H265CodecExtra; |
| 29 | use h265::H265Depacketizer; |
| 30 | pub use h265::H265Packetizer; |
| 31 | pub use h265::detect_h265_keyframe; |
| 32 | |
| 33 | mod h265_profile; |
| 34 | pub use h265_profile::{H265Level, H265Profile, H265ProfileTierLevel, H265Tier}; |
| 35 | |
| 36 | mod h266; |
| 37 | pub use h266::H266CodecExtra; |
| 38 | use h266::H266Depacketizer; |
| 39 | pub use h266::H266Packetizer; |
| 40 | pub use h266::detect_h266_keyframe; |
| 41 | |
| 42 | mod h266_profile; |
| 43 | pub use h266_profile::{H266Level, H266Profile, H266ProfileTierLevel, H266Tier}; |
| 44 | |
| 45 | mod opus; |
| 46 | pub use opus::{OpusDepacketizer, OpusPacketizer}; |
| 47 | |
| 48 | mod vp8; |
| 49 | pub use vp8::Vp8CodecExtra; |
| 50 | pub use vp8::Vp8Descriptor; |
| 51 | pub use vp8::Vp8DescriptorError; |
| 52 | pub use vp8::Vp8Patch; |
| 53 | pub use vp8::Vp8PatchBuilder; |
| 54 | pub use vp8::Vp8PatchError; |
| 55 | pub use vp8::detect_vp8_keyframe; |
| 56 | pub use vp8::{Vp8Depacketizer, Vp8Packetizer}; |
| 57 | |
| 58 | mod vp9; |
| 59 | pub use vp9::Vp9CodecExtra; |
| 60 | pub use vp9::Vp9PacketizerMode; |
| 61 | pub use vp9::detect_vp9_keyframe; |
| 62 | use vp9::{Vp9Depacketizer, Vp9Packetizer}; |
| 63 | |
| 64 | mod null; |
| 65 | use null::{NullDepacketizer, NullPacketizer}; |
| 66 | |
| 67 | mod comfort_noise; |
| 68 | use comfort_noise::{ComfortNoiseDepacketizer, ComfortNoisePacketizer}; |
| 69 | |
| 70 | mod buffer_rx; |
| 71 | pub(crate) use buffer_rx::{DepacketizingBuffer, RtpMeta}; |
| 72 | |
| 73 | mod contiguity; |
| 74 | mod contiguity_vp8; |
| 75 | mod contiguity_vp9; |
| 76 | mod error; |
| 77 | |
| 78 | mod payload; |
| 79 | pub(crate) use payload::Payloader; |
| 80 | |
| 81 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
| 82 | /// Types of media. |
| 83 | pub enum MediaKind { |
| 84 | /// Audio media. |
| 85 | Audio, |
| 86 | /// Video media. |
| 87 | Video, |
| 88 | } |
| 89 | |
| 90 | #[cfg(feature = "drv")] |
| 91 | crate::drv_identity_copy!(MediaKind); |
| 92 | |
| 93 | impl MediaKind { |
| 94 | /// Tests if this is `MediaKind::Audio` |
| 95 | pub fn is_audio(&self) -> bool { |
| 96 | *self == MediaKind::Audio |
| 97 | } |
| 98 | |
| 99 | /// Tests if this is `MediaKind::Video` |
| 100 | pub fn is_video(&self) -> bool { |
| 101 | *self == MediaKind::Video |
| 102 | } |
| 103 | } |
| 104 | |
| 105 | /// Packetizes some bytes for use as RTP packet. |
| 106 | /// |
| 107 | /// ## Unversioned API surface |
| 108 | /// |
| 109 | /// This trait is not currently versioned according to semver rules. |
| 110 | /// Breaking changes may be made in minor or patch releases. |
| 111 | pub trait Packetizer: fmt::Debug { |
| 112 | /// Chunk the data up into RTP packets. |
| 113 | fn packetize(&mut self, mtu: usize, b: &[u8]) -> Result<Vec<Vec<u8>>, PacketError>; |
| 114 | |
| 115 | /// Tell if this is the last packet of a frame. |
| 116 | fn is_marker(&mut self, data: &[u8], previous: Option<&[u8]>, last: bool) -> bool; |
| 117 | } |
| 118 | |
| 119 | /// Codec specific information |
| 120 | /// |
| 121 | /// Contains additional codec specific information which are deemed useful for |
| 122 | /// managing and repackaging the frame |
| 123 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] |
| 124 | #[non_exhaustive] |
| 125 | pub enum CodecExtra { |
| 126 | /// No extra information available |
| 127 | None, |
| 128 | /// Codec extra parameters for VP8. |
| 129 | Vp8(Vp8CodecExtra), |
| 130 | /// Codec extra parameters for VP9. |
| 131 | Vp9(Vp9CodecExtra), |
| 132 | /// Codec extra parameters for H264. |
| 133 | H264(H264CodecExtra), |
| 134 | /// Codec extra parameters for AV1, |
| 135 | Av1(Av1CodecExtra), |
| 136 | /// Codec extra parameters for H265. |
| 137 | H265(H265CodecExtra), |
| 138 | /// Codec extra parameters for H266 (VVC). Prototype. |
| 139 | H266(H266CodecExtra), |
| 140 | } |
| 141 | |
| 142 | /// Depacketizes an RTP payload. |
| 143 | /// |
| 144 | /// Removes any RTP specific data from the payload. |
| 145 | /// |
| 146 | /// ## Unversioned API surface |
| 147 | /// |
| 148 | /// This trait is not currently versioned according to semver rules. |
| 149 | /// Breaking changes may be made in minor or patch releases. |
| 150 | pub trait Depacketizer: fmt::Debug { |
| 151 | /// Provide a size hint for the `out: &mut Vec<u8>` parameter in [`Depacketizer::depacketize`]. |
| 152 | /// The [`packets_size`] parameter is the sum of the size of all packets that will be processed in |
| 153 | /// subsequent calls to [`Depacketizer::depacketize`]. |
| 154 | /// This is used to allocate the vector with upfront capacity. |
| 155 | /// Return [`None`] if it cannot be determined. |
| 156 | fn out_size_hint(&self, packets_size: usize) -> Option<usize>; |
| 157 | |
| 158 | /// Unpack the RTP packet into a provided `Vec<u8>`. |
| 159 | fn depacketize( |
| 160 | &mut self, |
| 161 | packet: &[u8], |
| 162 | out: &mut Vec<u8>, |
| 163 | codec_extra: &mut CodecExtra, |
| 164 | ) -> Result<(), PacketError>; |
| 165 | |
| 166 | /// Checks if the packet is at the beginning of a partition. |
| 167 | /// |
| 168 | /// Returns false if the result could not be determined. |
| 169 | fn is_partition_head(&self, packet: &[u8]) -> bool; |
| 170 | |
| 171 | /// Checks if the packet is at the end of a partition. |
| 172 | /// |
| 173 | /// Returns false if the result could not be determined. |
| 174 | fn is_partition_tail(&self, marker: bool, packet: &[u8]) -> bool; |
| 175 | } |
| 176 | |
| 177 | pub use error::PacketError; |
| 178 | |
| 179 | /// Helper to replace Bytes. Provides get_u8 and get_u16 over some buffer of bytes. |
| 180 | pub(crate) trait BitRead { |
| 181 | fn remaining_bits(&self) -> usize; |
| 182 | fn remaining_bytes(&self) -> usize; |
| 183 | fn byte_offset(&self) -> usize; |
| 184 | fn get_u8(&mut self) -> Option<u8>; |
| 185 | fn get_u16(&mut self) -> Option<u16>; |
| 186 | fn get_remaining(&mut self) -> &[u8]; |
| 187 | fn get_bytes(&mut self, count: usize) -> Option<&[u8]>; |
| 188 | fn get_leb128(&mut self) -> Option<usize>; |
| 189 | fn skip_bytes(&mut self, count: usize); |
| 190 | } |
| 191 | |
| 192 | impl BitRead for (&[u8], usize) { |
| 193 | #[inline(always)] |
| 194 | fn remaining_bits(&self) -> usize { |
| 195 | (self.0.len() * 8).saturating_sub(self.1) |
| 196 | } |
| 197 | |
| 198 | #[inline(always)] |
| 199 | fn remaining_bytes(&self) -> usize { |
| 200 | self.remaining_bits() / 8 |
| 201 | } |
| 202 | |
| 203 | #[inline(always)] |
| 204 | fn byte_offset(&self) -> usize { |
| 205 | self.1 / 8 |
| 206 | } |
| 207 | |
| 208 | #[inline(always)] |
| 209 | fn get_u8(&mut self) -> Option<u8> { |
| 210 | if self.remaining_bits() < 8 { |
| 211 | return None; |
| 212 | } |
| 213 | |
| 214 | let offs = self.1 / 8; |
| 215 | let shift = (self.1 % 8) as u32; |
| 216 | self.1 += 8; |
| 217 | |
| 218 | let mut n = self.0[offs]; |
| 219 | |
| 220 | if shift > 0 { |
| 221 | n <<= shift; |
| 222 | n |= self.0[offs + 1] >> (8 - shift) |
| 223 | } |
| 224 | |
| 225 | Some(n) |
| 226 | } |
| 227 | |
| 228 | fn get_u16(&mut self) -> Option<u16> { |
| 229 | if self.remaining_bits() < 16 { |
| 230 | return None; |
| 231 | } |
| 232 | Some(u16::from_be_bytes([self.get_u8()?, self.get_u8()?])) |
| 233 | } |
| 234 | |
| 235 | fn get_remaining(&mut self) -> &[u8] { |
| 236 | let offset = self.1 / 8; |
| 237 | self.1 = self.0.len() * 8; |
| 238 | &self.0[offset..] |
| 239 | } |
| 240 | |
| 241 | fn get_bytes(&mut self, count: usize) -> Option<&[u8]> { |
| 242 | let count_bits = count.saturating_mul(8); |
| 243 | if self.remaining_bits() < count_bits { |
| 244 | return None; |
| 245 | } |
| 246 | let offset = self.1 / 8; |
| 247 | self.1 += count_bits; |
| 248 | Some(&self.0[offset..offset + count]) |
| 249 | } |
| 250 | |
| 251 | fn get_leb128(&mut self) -> Option<usize> { |
| 252 | let mut temp_value: usize = 0; |
| 253 | |
| 254 | for i in (0..64).step_by(7) { |
| 255 | if self.remaining_bits() < 8 { |
| 256 | return None; |
| 257 | } |
| 258 | let byte = self.get_u8().unwrap(); |
| 259 | temp_value |= ((byte & 0x7f) as usize) << i; |
| 260 | |
| 261 | if byte < 0x80 { |
| 262 | return Some(temp_value); |
| 263 | } |
| 264 | } |
| 265 | |
| 266 | None |
| 267 | } |
| 268 | |
| 269 | fn skip_bytes(&mut self, count: usize) { |
| 270 | let bits = count.saturating_mul(8); |
| 271 | if self.remaining_bits() < bits { |
| 272 | return; |
| 273 | } |
| 274 | |
| 275 | self.1 += bits; |
| 276 | } |
| 277 | } |
| 278 | |
| 279 | #[derive(Debug)] |
| 280 | pub(crate) enum CodecPacketizer { |
| 281 | #[allow(unused)] |
| 282 | G711(G711Packetizer), |
| 283 | #[allow(unused)] |
| 284 | G722(G722Packetizer), |
| 285 | H264(H264Packetizer), |
| 286 | H265(H265Packetizer), |
| 287 | H266(H266Packetizer), |
| 288 | Opus(OpusPacketizer), |
| 289 | ComfortNoise(ComfortNoisePacketizer), |
| 290 | Vp8(Vp8Packetizer), |
| 291 | Vp9(Vp9Packetizer), |
| 292 | Av1(Av1Packetizer), |
| 293 | Null(NullPacketizer), |
| 294 | #[allow(unused)] |
| 295 | Boxed(Box<dyn Packetizer + Send + Sync + UnwindSafe>), |
| 296 | } |
| 297 | |
| 298 | #[derive(Debug)] |
| 299 | pub(crate) enum CodecDepacketizer { |
| 300 | G711(G711Depacketizer), |
| 301 | H264(H264Depacketizer), |
| 302 | H265(H265Depacketizer), |
| 303 | H266(H266Depacketizer), |
| 304 | Opus(OpusDepacketizer), |
| 305 | ComfortNoise(ComfortNoiseDepacketizer), |
| 306 | Vp8(Vp8Depacketizer), |
| 307 | Vp9(Vp9Depacketizer), |
| 308 | Av1(Av1Depacketizer), |
| 309 | Null(NullDepacketizer), |
| 310 | #[allow(unused)] |
| 311 | Boxed(Box<dyn Depacketizer + Send + Sync + UnwindSafe>), |
| 312 | } |
| 313 | |
| 314 | impl CodecPacketizer { |
| 315 | pub(crate) fn new(codec: Codec, vp9_mode: Vp9PacketizerMode) -> Self { |
| 316 | match codec { |
| 317 | Codec::Opus => CodecPacketizer::Opus(OpusPacketizer), |
| 318 | Codec::PCMU => CodecPacketizer::G711(G711Packetizer::default()), |
| 319 | Codec::PCMA => CodecPacketizer::G711(G711Packetizer::default()), |
| 320 | Codec::G722 => CodecPacketizer::G722(G722Packetizer::default()), |
| 321 | Codec::CN => CodecPacketizer::ComfortNoise(ComfortNoisePacketizer), |
| 322 | Codec::H264 => CodecPacketizer::H264(H264Packetizer::default()), |
| 323 | Codec::H265 => CodecPacketizer::H265(H265Packetizer::default()), |
| 324 | Codec::H266 => CodecPacketizer::H266(H266Packetizer::default()), |
| 325 | Codec::Vp8 => CodecPacketizer::Vp8(Vp8Packetizer::default()), |
| 326 | Codec::Vp9 => CodecPacketizer::Vp9(Vp9Packetizer::with_mode(vp9_mode)), |
| 327 | Codec::Av1 => CodecPacketizer::Av1(Av1Packetizer::default()), |
| 328 | Codec::Null => CodecPacketizer::Null(NullPacketizer), |
| 329 | Codec::Rtx => panic!("Cant instantiate packetizer for RTX codec"), |
| 330 | Codec::Unknown => panic!("Cant instantiate packetizer for unknown codec"), |
| 331 | } |
| 332 | } |
| 333 | } |
| 334 | |
| 335 | impl From<Codec> for CodecPacketizer { |
| 336 | fn from(c: Codec) -> Self { |
| 337 | CodecPacketizer::new(c, Vp9PacketizerMode::default()) |
| 338 | } |
| 339 | } |
| 340 | |
| 341 | impl From<Codec> for CodecDepacketizer { |
| 342 | fn from(c: Codec) -> Self { |
| 343 | match c { |
| 344 | Codec::Opus => CodecDepacketizer::Opus(OpusDepacketizer), |
| 345 | Codec::PCMU => CodecDepacketizer::G711(G711Depacketizer), |
| 346 | Codec::PCMA => CodecDepacketizer::G711(G711Depacketizer), |
| 347 | Codec::G722 => CodecDepacketizer::G711(G711Depacketizer), |
| 348 | Codec::CN => CodecDepacketizer::ComfortNoise(ComfortNoiseDepacketizer), |
| 349 | Codec::H264 => CodecDepacketizer::H264(H264Depacketizer::default()), |
| 350 | Codec::H265 => CodecDepacketizer::H265(H265Depacketizer::default()), |
| 351 | Codec::H266 => CodecDepacketizer::H266(H266Depacketizer::default()), |
| 352 | Codec::Vp8 => CodecDepacketizer::Vp8(Vp8Depacketizer::default()), |
| 353 | Codec::Vp9 => CodecDepacketizer::Vp9(Vp9Depacketizer::default()), |
| 354 | Codec::Av1 => CodecDepacketizer::Av1(Av1Depacketizer::default()), |
| 355 | Codec::Null => CodecDepacketizer::Null(NullDepacketizer), |
| 356 | Codec::Rtx => panic!("Cant instantiate depacketizer for RTX codec"), |
| 357 | Codec::Unknown => panic!("Cant instantiate depacketizer for unknown codec"), |
| 358 | } |
| 359 | } |
| 360 | } |
| 361 | |
| 362 | impl Packetizer for CodecPacketizer { |
| 363 | fn packetize(&mut self, mtu: usize, b: &[u8]) -> Result<Vec<Vec<u8>>, PacketError> { |
| 364 | use CodecPacketizer::*; |
| 365 | match self { |
| 366 | G711(v) => v.packetize(mtu, b), |
| 367 | G722(v) => v.packetize(mtu, b), |
| 368 | H264(v) => v.packetize(mtu, b), |
| 369 | H265(v) => v.packetize(mtu, b), |
| 370 | H266(v) => v.packetize(mtu, b), |
| 371 | Opus(v) => v.packetize(mtu, b), |
| 372 | ComfortNoise(v) => v.packetize(mtu, b), |
| 373 | Vp8(v) => v.packetize(mtu, b), |
| 374 | Vp9(v) => v.packetize(mtu, b), |
| 375 | Av1(v) => v.packetize(mtu, b), |
| 376 | Null(v) => v.packetize(mtu, b), |
| 377 | Boxed(v) => v.packetize(mtu, b), |
| 378 | } |
| 379 | } |
| 380 | |
| 381 | fn is_marker(&mut self, data: &[u8], previous: Option<&[u8]>, last: bool) -> bool { |
| 382 | match self { |
| 383 | CodecPacketizer::G711(v) => v.is_marker(data, previous, last), |
| 384 | CodecPacketizer::G722(v) => v.is_marker(data, previous, last), |
| 385 | CodecPacketizer::Opus(v) => v.is_marker(data, previous, last), |
| 386 | CodecPacketizer::ComfortNoise(v) => v.is_marker(data, previous, last), |
| 387 | CodecPacketizer::H264(v) => v.is_marker(data, previous, last), |
| 388 | CodecPacketizer::H265(v) => v.is_marker(data, previous, last), |
| 389 | CodecPacketizer::H266(v) => v.is_marker(data, previous, last), |
| 390 | CodecPacketizer::Vp8(v) => v.is_marker(data, previous, last), |
| 391 | CodecPacketizer::Vp9(v) => v.is_marker(data, previous, last), |
| 392 | CodecPacketizer::Av1(v) => v.is_marker(data, previous, last), |
| 393 | CodecPacketizer::Null(v) => v.is_marker(data, previous, last), |
| 394 | CodecPacketizer::Boxed(v) => v.is_marker(data, previous, last), |
| 395 | } |
| 396 | } |
| 397 | } |
| 398 | |
| 399 | impl Depacketizer for CodecDepacketizer { |
| 400 | fn out_size_hint(&self, packets_size: usize) -> Option<usize> { |
| 401 | use CodecDepacketizer::*; |
| 402 | match self { |
| 403 | H264(v) => v.out_size_hint(packets_size), |
| 404 | H265(v) => v.out_size_hint(packets_size), |
| 405 | H266(v) => v.out_size_hint(packets_size), |
| 406 | Opus(v) => v.out_size_hint(packets_size), |
| 407 | ComfortNoise(v) => v.out_size_hint(packets_size), |
| 408 | G711(v) => v.out_size_hint(packets_size), |
| 409 | Vp8(v) => v.out_size_hint(packets_size), |
| 410 | Vp9(v) => v.out_size_hint(packets_size), |
| 411 | Av1(v) => v.out_size_hint(packets_size), |
| 412 | Null(v) => v.out_size_hint(packets_size), |
| 413 | Boxed(v) => v.out_size_hint(packets_size), |
| 414 | } |
| 415 | } |
| 416 | |
| 417 | fn depacketize( |
| 418 | &mut self, |
| 419 | packet: &[u8], |
| 420 | out: &mut Vec<u8>, |
| 421 | extra: &mut CodecExtra, |
| 422 | ) -> Result<(), PacketError> { |
| 423 | use CodecDepacketizer::*; |
| 424 | match self { |
| 425 | H264(v) => v.depacketize(packet, out, extra), |
| 426 | H265(v) => v.depacketize(packet, out, extra), |
| 427 | H266(v) => v.depacketize(packet, out, extra), |
| 428 | Opus(v) => v.depacketize(packet, out, extra), |
| 429 | ComfortNoise(v) => v.depacketize(packet, out, extra), |
| 430 | G711(v) => v.depacketize(packet, out, extra), |
| 431 | Vp8(v) => v.depacketize(packet, out, extra), |
| 432 | Vp9(v) => v.depacketize(packet, out, extra), |
| 433 | Av1(v) => v.depacketize(packet, out, extra), |
| 434 | Null(v) => v.depacketize(packet, out, extra), |
| 435 | Boxed(v) => v.depacketize(packet, out, extra), |
| 436 | } |
| 437 | } |
| 438 | |
| 439 | fn is_partition_head(&self, packet: &[u8]) -> bool { |
| 440 | use CodecDepacketizer::*; |
| 441 | match self { |
| 442 | H264(v) => v.is_partition_head(packet), |
| 443 | H265(v) => v.is_partition_head(packet), |
| 444 | H266(v) => v.is_partition_head(packet), |
| 445 | Opus(v) => v.is_partition_head(packet), |
| 446 | ComfortNoise(v) => v.is_partition_head(packet), |
| 447 | G711(v) => v.is_partition_head(packet), |
| 448 | Vp8(v) => v.is_partition_head(packet), |
| 449 | Vp9(v) => v.is_partition_head(packet), |
| 450 | Av1(v) => v.is_partition_head(packet), |
| 451 | Null(v) => v.is_partition_head(packet), |
| 452 | Boxed(v) => v.is_partition_head(packet), |
| 453 | } |
| 454 | } |
| 455 | |
| 456 | fn is_partition_tail(&self, marker: bool, packet: &[u8]) -> bool { |
| 457 | use CodecDepacketizer::*; |
| 458 | match self { |
| 459 | H264(v) => v.is_partition_tail(marker, packet), |
| 460 | H265(v) => v.is_partition_tail(marker, packet), |
| 461 | H266(v) => v.is_partition_tail(marker, packet), |
| 462 | Opus(v) => v.is_partition_tail(marker, packet), |
| 463 | ComfortNoise(v) => v.is_partition_tail(marker, packet), |
| 464 | G711(v) => v.is_partition_tail(marker, packet), |
| 465 | Vp8(v) => v.is_partition_tail(marker, packet), |
| 466 | Vp9(v) => v.is_partition_tail(marker, packet), |
| 467 | Av1(v) => v.is_partition_tail(marker, packet), |
| 468 | Null(v) => v.is_partition_tail(marker, packet), |
| 469 | Boxed(v) => v.is_partition_tail(marker, packet), |
| 470 | } |
| 471 | } |
| 472 | } |
| 473 | |
| 474 | impl From<MediaType> for MediaKind { |
| 475 | fn from(v: MediaType) -> Self { |
| 476 | match v { |
| 477 | MediaType::Audio => MediaKind::Audio, |
| 478 | MediaType::Video => MediaKind::Video, |
| 479 | _ => panic!("Not MediaType::Audio or Video"), |
| 480 | } |
| 481 | } |
| 482 | } |
| 483 | |
| 484 | impl fmt::Display for MediaKind { |
| 485 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 486 | match self { |
| 487 | MediaKind::Audio => write!(f, "audio"), |
| 488 | MediaKind::Video => write!(f, "video"), |
| 489 | } |
| 490 | } |
| 491 | } |
| 492 | |
| 493 | #[cfg(test)] |
| 494 | mod test { |
| 495 | use super::*; |
| 496 | |
| 497 | #[test] |
| 498 | fn comfort_noise_packetizer_preserves_payload_and_clears_marker() { |
| 499 | let payload = [42, 128, 64]; |
| 500 | let mut packetizer = CodecPacketizer::from(Codec::CN); |
| 501 | |
| 502 | assert_eq!( |
| 503 | packetizer.packetize(1200, &payload).unwrap(), |
| 504 | vec![payload.to_vec()] |
| 505 | ); |
| 506 | assert!(!packetizer.is_marker(&payload, None, true)); |
| 507 | |
| 508 | let mut depacketizer = CodecDepacketizer::from(Codec::CN); |
| 509 | let mut output = Vec::new(); |
| 510 | depacketizer |
| 511 | .depacketize(&payload, &mut output, &mut CodecExtra::None) |
| 512 | .unwrap(); |
| 513 | assert_eq!(output, payload); |
| 514 | assert!(depacketizer.is_partition_head(&payload)); |
| 515 | assert!(depacketizer.is_partition_tail(false, &payload)); |
| 516 | } |
| 517 | } |