diff --git a/src/builder.rs b/src/builder.rs index 668cec5..64fd608 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -159,12 +159,12 @@ impl RtpPacketBuilder { pub fn calculate_size(&self) -> Result { let payload_len = self.payloads.iter().map(|p| p.len()).sum::(); let extension_len = if let Some((_ext_id, ext_data)) = self.extension.as_ref() { - if ext_data.len() > u16::MAX as usize { - return Err(RtpWriteError::PacketTooLarge); - } if ext_data.len() % 4 != 0 { return Err(RtpWriteError::ExtensionDataNotPadded); } + if ext_data.len() > u16::MAX as usize { + return Err(RtpWriteError::PacketTooLarge); + } 4 + ext_data.len() } else { 0 @@ -323,7 +323,7 @@ pub trait PayloadLength { fn len(&self) -> usize; /// Whether the data contains any bytes. fn is_empty(&self) -> bool { - self.len() != 0 + self.len() == 0 } } @@ -504,9 +504,8 @@ impl<'b, 'c> RtpPacketWriter for RtpPacketWriterMutSlice<'_, 'b, 'c> { fn finish(&mut self) -> Self::Output { if let Some(padding) = self.padding.take() { - if padding > 1 { - self.output[self.write_i..self.write_i + padding as usize - 1].fill(0); - } + debug_assert!(padding > 0); + self.output[self.write_i..self.write_i + padding as usize - 1].fill(0); self.write_i += padding as usize; self.output[self.write_i - 1] = padding; } @@ -585,14 +584,31 @@ impl<'b, 'c> RtpPacketWriter for RtpPacketWriterMutVec<'_, 'b, 'c> { mod tests { use super::*; + #[test] + fn payload_length() { + let data = [3; 9]; + let data2: [u8; _] = []; + assert!(PayloadLength::is_empty(&data2)); + assert!(!PayloadLength::is_empty(&data)); + assert_eq!(PayloadLength::len(&data), 9); + assert_eq!(PayloadLength::len(&&data), 9); + assert_eq!(PayloadLength::len(&data.as_slice()), 9); + assert_eq!(PayloadLength::len(&data.to_vec()), 9); + } + #[test] fn write_rtp_default() { let mut data = [0; 128]; let mut vec = vec![]; + let mut vec2 = vec![]; let builder = RtpPacketBuilder::new().payload_type(96); let size = builder.write_into(&mut data).unwrap(); let buf = builder.write_vec().unwrap(); + let buf2 = builder.write_vec_unchecked(); + assert_eq!(buf, buf2); builder.write_into_vec(&mut vec).unwrap(); + builder.write_into_vec_unchecked(&mut vec2); + assert_eq!(vec, vec2); drop(builder); let data = &data[..size]; assert_eq!(size, buf.len()); @@ -618,6 +634,7 @@ mod tests { fn write_rtp_header() { let mut data = [0; 128]; let mut vec = vec![]; + let mut vec2 = vec![]; let builder = RtpPacketBuilder::new() .payload_type(96) .marker_bit(true) @@ -627,7 +644,11 @@ mod tests { .add_csrc(0x0b0c0d0e); let size = builder.write_into(&mut data).unwrap(); let buf = builder.write_vec().unwrap(); + let buf2 = builder.write_vec_unchecked(); + assert_eq!(buf, buf2); builder.write_into_vec(&mut vec).unwrap(); + builder.write_into_vec_unchecked(&mut vec2); + assert_eq!(vec, vec2); drop(builder); let data = &data[..size]; assert_eq!(size, buf.len()); @@ -655,13 +676,20 @@ mod tests { fn write_rtp_header_multiple_csrcs() { let mut data = [0; 128]; let mut vec = vec![]; + let mut vec2 = vec![]; let builder = RtpPacketBuilder::new() .payload_type(96) .add_csrc(0x01020304) .add_csrc(0x05060708); let size = builder.write_into(&mut data).unwrap(); + let size2 = builder.write_into_unchecked(&mut data); + assert_eq!(size, size2); let buf = builder.write_vec().unwrap(); + let buf2 = builder.write_vec_unchecked(); + assert_eq!(buf, buf2); builder.write_into_vec(&mut vec).unwrap(); + builder.write_into_vec_unchecked(&mut vec2); + assert_eq!(vec, vec2); drop(builder); let data = &data[..size]; assert_eq!(size, buf.len()); @@ -681,6 +709,7 @@ mod tests { fn write_rtp_multiple_payloads() { let mut data = [0; 128]; let mut vec = vec![]; + let mut vec2 = vec![]; let payload_data = [1, 2, 3, 4, 5, 6, 7, 8]; let more_payload_data = [9, 10, 11]; let builder = RtpPacketBuilder::new() @@ -691,7 +720,11 @@ mod tests { let size = builder.write_into(&mut data).unwrap(); assert_eq!(size, 24); let buf = builder.write_vec().unwrap(); + let buf2 = builder.write_vec_unchecked(); + assert_eq!(buf, buf2); builder.write_into_vec(&mut vec).unwrap(); + builder.write_into_vec_unchecked(&mut vec2); + assert_eq!(vec, vec2); drop(builder); let data = &data[..size]; assert_eq!(size, buf.len()); @@ -709,6 +742,7 @@ mod tests { fn write_rtp_extension() { let mut data = [0; 128]; let mut vec = vec![]; + let mut vec2 = vec![]; let extension_data = [1, 2, 3, 4, 5, 6, 7, 8]; let builder = RtpPacketBuilder::new() .payload_type(96) @@ -720,7 +754,11 @@ mod tests { .extension(0x9876, extension_data.as_ref()); let size = builder.write_into(&mut data).unwrap(); let buf = builder.write_vec().unwrap(); + let buf2 = builder.write_vec_unchecked(); + assert_eq!(buf, buf2); builder.write_into_vec(&mut vec).unwrap(); + builder.write_into_vec_unchecked(&mut vec2); + assert_eq!(vec, vec2); drop(builder); let data = &data[..size]; assert_eq!(size, buf.len()); @@ -744,10 +782,56 @@ mod tests { } } + #[test] + fn write_rtp_extension_clear() { + let mut data = [0; 128]; + let mut vec = vec![]; + let mut vec2 = vec![]; + let extension_data = [1, 2, 3, 4, 5, 6, 7, 8]; + let builder = RtpPacketBuilder::new() + .payload_type(96) + .marker_bit(true) + .sequence_number(0x0102) + .timestamp(0x03040506) + .ssrc(0x0708090a) + .add_csrc(0x0b0c0d0e) + .extension(0x9876, extension_data.as_ref()) + .clear_extension(); + let size = builder.write_into(&mut data).unwrap(); + let buf = builder.write_vec().unwrap(); + let buf2 = builder.write_vec_unchecked(); + assert_eq!(buf, buf2); + builder.write_into_vec(&mut vec).unwrap(); + builder.write_into_vec_unchecked(&mut vec2); + assert_eq!(vec, vec2); + drop(builder); + let data = &data[..size]; + assert_eq!(size, buf.len()); + assert_eq!(size, vec.len()); + for data in [data, buf.as_ref(), vec.as_ref()] { + println!("{data:?}"); + let rtp = RtpPacket::parse(data).unwrap(); + assert_eq!(rtp.version(), 2); + assert_eq!(rtp.padding(), None); + assert_eq!(rtp.n_csrcs(), 1); + assert!(rtp.marker_bit()); + assert_eq!(rtp.payload_type(), 96); + assert_eq!(rtp.sequence_number(), 0x0102); + assert_eq!(rtp.timestamp(), 0x03040506); + assert_eq!(rtp.ssrc(), 0x0708090a); + let mut csrc = rtp.csrc(); + assert_eq!(csrc.next(), Some(0x0b0c0d0e)); + assert_eq!(csrc.next(), None); + assert_eq!(rtp.extension(), None); + assert_eq!(rtp.payload(), &[]); + } + } + #[test] fn write_rtp_extension_payload_padding() { let mut data = [0; 128]; let mut vec = vec![]; + let mut vec2 = vec![]; let extension_data = [1, 2, 3, 4, 5, 6, 7, 8]; let payload_data = [1, 2, 3, 4, 5, 6, 7, 8]; let builder = RtpPacketBuilder::new() @@ -762,7 +846,11 @@ mod tests { .padding(7); let size = builder.write_into(&mut data).unwrap(); let buf = builder.write_vec().unwrap(); + let buf2 = builder.write_vec_unchecked(); + assert_eq!(buf, buf2); builder.write_into_vec(&mut vec).unwrap(); + builder.write_into_vec_unchecked(&mut vec2); + assert_eq!(vec, vec2); drop(builder); let data = &data[..size]; assert_eq!(size, buf.len()); @@ -786,6 +874,49 @@ mod tests { } } + #[test] + fn write_rtp_extension_payload_maybe_padding() { + let mut data = [0; 128]; + let mut vec = vec![]; + let mut vec2 = vec![]; + let builder = RtpPacketBuilder::new() + .payload_type(96) + .marker_bit(true) + .sequence_number(0x0102) + .timestamp(0x03040506) + .ssrc(0x0708090a) + .add_csrc(0x0b0c0d0e) + .maybe_padding(Some(7)); + let size = builder.write_into(&mut data).unwrap(); + let buf = builder.write_vec().unwrap(); + let buf2 = builder.write_vec_unchecked(); + assert_eq!(buf, buf2); + builder.write_into_vec(&mut vec).unwrap(); + builder.write_into_vec_unchecked(&mut vec2); + assert_eq!(vec, vec2); + drop(builder); + let data = &data[..size]; + assert_eq!(size, buf.len()); + assert_eq!(size, vec.len()); + for data in [data, buf.as_ref(), vec.as_ref()] { + println!("{data:?}"); + let rtp = RtpPacket::parse(data).unwrap(); + assert_eq!(rtp.version(), 2); + assert_eq!(rtp.padding(), Some(7)); + assert_eq!(rtp.n_csrcs(), 1); + assert!(rtp.marker_bit()); + assert_eq!(rtp.payload_type(), 96); + assert_eq!(rtp.sequence_number(), 0x0102); + assert_eq!(rtp.timestamp(), 0x03040506); + assert_eq!(rtp.ssrc(), 0x0708090a); + let mut csrc = rtp.csrc(); + assert_eq!(csrc.next(), Some(0x0b0c0d0e)); + assert_eq!(csrc.next(), None); + assert_eq!(rtp.extension(), None); + assert_eq!(rtp.payload(), &[]); + } + } + #[test] fn write_rtp_invalid_padding() { let mut data = [0; 128]; @@ -842,6 +973,65 @@ mod tests { ); } + #[test] + fn write_rtp_max_contributions() { + let mut data = [0; 128]; + let mut vec = vec![]; + let mut vec2 = vec![]; + let builder = RtpPacketBuilder::new() + .payload_type(96) + .marker_bit(true) + .sequence_number(0x0102) + .timestamp(0x03040506) + .ssrc(0x0708090a) + .maybe_padding(Some(7)) + .add_csrc(1) + .add_csrc(2) + .add_csrc(3) + .add_csrc(4) + .add_csrc(5) + .add_csrc(6) + .add_csrc(7) + .add_csrc(8) + .add_csrc(9) + .add_csrc(10) + .add_csrc(11) + .add_csrc(12) + .add_csrc(13) + .add_csrc(14) + .add_csrc(15); + let size = builder.write_into(&mut data).unwrap(); + let buf = builder.write_vec().unwrap(); + let buf2 = builder.write_vec_unchecked(); + assert_eq!(buf, buf2); + builder.write_into_vec(&mut vec).unwrap(); + builder.write_into_vec_unchecked(&mut vec2); + assert_eq!(vec, vec2); + drop(builder); + let data = &data[..size]; + assert_eq!(size, buf.len()); + assert_eq!(size, vec.len()); + for data in [data, buf.as_ref(), vec.as_ref()] { + println!("{data:?}"); + let rtp = RtpPacket::parse(data).unwrap(); + assert_eq!(rtp.version(), 2); + assert_eq!(rtp.padding(), Some(7)); + assert_eq!(rtp.n_csrcs(), 15); + assert!(rtp.marker_bit()); + assert_eq!(rtp.payload_type(), 96); + assert_eq!(rtp.sequence_number(), 0x0102); + assert_eq!(rtp.timestamp(), 0x03040506); + assert_eq!(rtp.ssrc(), 0x0708090a); + let mut csrc = rtp.csrc(); + for i in 1..16 { + assert_eq!(csrc.next(), Some(i)); + } + assert_eq!(csrc.next(), None); + assert_eq!(rtp.extension(), None); + assert_eq!(rtp.payload(), &[]); + } + } + #[test] fn write_rtp_too_many_contributions() { let mut data = [0; 128]; diff --git a/src/edit.rs b/src/edit.rs index fb18b54..ba6f0c8 100644 --- a/src/edit.rs +++ b/src/edit.rs @@ -116,8 +116,8 @@ mod tests { #[test] fn edit_rtp_no_payload_no_extensions_no_csrc() { - let mut data: [u8; 12] = [ - 0x80, 0x60, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, + let mut data: [u8; 13] = [ + 0x80, 0x60, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x11, ]; let mut rtp = RtpPacketMut::parse(data.as_mut_slice()).unwrap(); assert_eq!(rtp.version(), 2); @@ -130,16 +130,146 @@ mod tests { assert_eq!(rtp.ssrc(), 0x07080910); assert_eq!(rtp.csrc().count(), 0); assert_eq!(rtp.extension(), None); + assert_eq!(rtp.payload(), &[0x11]); + assert_eq!(rtp.payload_mut(), [0x11].as_mut_slice()); + rtp.set_marker_bit(true); + assert!(rtp.marker_bit()); + rtp.set_payload_type(0x7F).unwrap(); + assert_eq!(rtp.payload_type(), 0x7F); + rtp.set_sequence_number(0x9876); + assert_eq!(rtp.sequence_number(), 0x9876); + rtp.set_timestamp(0x19283746); + assert_eq!(rtp.timestamp(), 0x19283746); + rtp.set_ssrc(0x90807060); + assert_eq!(rtp.ssrc(), 0x90807060); + } + + #[test] + fn edit_rtp_set_payload_out_of_range() { + let mut data: [u8; 12] = [ + 0x80, 0x60, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, + ]; + let mut rtp = RtpPacketMut::parse(data.as_mut_slice()).unwrap(); + assert_eq!( + rtp.set_payload_type(0xFF), + Err(RtpWriteError::InvalidPayloadType(0xFF)) + ); + assert_eq!( + rtp.set_payload_type(0x80), + Err(RtpWriteError::InvalidPayloadType(0x80)) + ); + } + + #[test] + fn edit_rtp_with_extension() { + let mut data: [u8; 20] = [ + 0x90, 0xE0, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, + 0x00, 0x1, 0x0d, 0x0e, 0x0f, 0x10, + ]; + let mut rtp = RtpPacketMut::parse(data.as_mut_slice()).unwrap(); + assert_eq!(rtp.version(), 2); + assert_eq!(rtp.padding(), None); + assert_eq!(rtp.n_csrcs(), 0); + assert!(rtp.marker_bit()); + assert_eq!(rtp.payload_type(), 96); + assert_eq!(rtp.sequence_number(), 0x0102); + assert_eq!(rtp.timestamp(), 0x03040506); + assert_eq!(rtp.ssrc(), 0x0708090a); + assert_eq!(rtp.csrc().count(), 0); + assert_eq!( + rtp.extension(), + Some((0x0b0c, [0x0d, 0x0e, 0x0f, 0x10].as_ref())) + ); assert_eq!(rtp.payload(), &[]); + assert_eq!(rtp.payload_mut(), &mut []); + + rtp.set_marker_bit(false); + assert!(!rtp.marker_bit()); + rtp.set_payload_type(0x7F).unwrap(); + assert_eq!(rtp.payload_type(), 0x7F); + rtp.set_sequence_number(0x9876); + assert_eq!(rtp.sequence_number(), 0x9876); + rtp.set_timestamp(0x19283746); + assert_eq!(rtp.timestamp(), 0x19283746); + rtp.set_ssrc(0x90807060); + assert_eq!(rtp.ssrc(), 0x90807060); + rtp.set_extension_id(0x1234); + assert_eq!( + rtp.extension(), + Some((0x1234, [0x0d, 0x0e, 0x0f, 0x10].as_ref())) + ); + assert_eq!( + rtp.extension_mut(), + Some([0x0d, 0x0e, 0x0f, 0x10].as_mut_slice()) + ); + } + + #[test] + fn edit_rtp_with_payload() { + let mut data: [u8; 16] = [ + 0x80, 0x60, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, + 0x0d, 0x0e, + ]; + let mut rtp = RtpPacketMut::parse(data.as_mut_slice()).unwrap(); + assert_eq!(rtp.version(), 2); + assert_eq!(rtp.padding(), None); + assert_eq!(rtp.n_csrcs(), 0); + assert!(!rtp.marker_bit()); + assert_eq!(rtp.payload_type(), 96); + assert_eq!(rtp.sequence_number(), 0x0102); + assert_eq!(rtp.timestamp(), 0x03040506); + assert_eq!(rtp.ssrc(), 0x0708090a); + assert_eq!(rtp.csrc().count(), 0); + assert_eq!(rtp.extension(), None); + assert_eq!(rtp.payload(), &[0x0b, 0x0c, 0x0d, 0x0e]); + + rtp.set_marker_bit(true); + assert!(rtp.marker_bit()); + rtp.set_payload_type(0x00).unwrap(); + assert_eq!(rtp.payload_type(), 0x00); + rtp.set_sequence_number(0x9876); + assert_eq!(rtp.sequence_number(), 0x9876); + rtp.set_timestamp(0x19283746); + assert_eq!(rtp.timestamp(), 0x19283746); + rtp.set_ssrc(0x90807060); + assert_eq!(rtp.ssrc(), 0x90807060); + rtp.set_extension_id(0x1234); + assert_eq!(rtp.payload(), [0x0b, 0x0c, 0x0d, 0x0e].as_ref()); + assert_eq!(rtp.payload_mut(), [0x0b, 0x0c, 0x0d, 0x0e].as_mut_slice()); + } + + #[test] + fn parse_rtp_with_padding() { + let mut data: [u8; 16] = [ + 0xa0, 0x60, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x0b, 0x0c, + 0x00, 0x02, + ]; + let mut rtp = RtpPacketMut::parse(data.as_mut_slice()).unwrap(); + assert_eq!(rtp.version(), 2); + assert_eq!(rtp.padding(), Some(2)); + assert_eq!(rtp.n_csrcs(), 0); + assert!(!rtp.marker_bit()); + assert_eq!(rtp.payload_type(), 96); + assert_eq!(rtp.sequence_number(), 0x1234); + assert_eq!(rtp.timestamp(), 0x56789abc); + assert_eq!(rtp.ssrc(), 0xdef01234); + assert_eq!(rtp.csrc().count(), 0); + assert_eq!(rtp.extension(), None); + assert_eq!(rtp.payload(), &[0x0b, 0x0c]); + assert_eq!(rtp.payload_len(), 2); + rtp.set_marker_bit(true); assert!(rtp.marker_bit()); - rtp.set_payload_type(12).unwrap(); - assert_eq!(rtp.payload_type(), 12); + rtp.set_payload_type(0x01).unwrap(); + assert_eq!(rtp.payload_type(), 0x01); rtp.set_sequence_number(0x9876); assert_eq!(rtp.sequence_number(), 0x9876); rtp.set_timestamp(0x19283746); assert_eq!(rtp.timestamp(), 0x19283746); rtp.set_ssrc(0x90807060); assert_eq!(rtp.ssrc(), 0x90807060); + rtp.set_extension_id(0x1234); + assert_eq!(rtp.payload(), &[0x0b, 0x0c]); + assert_eq!(rtp.payload_mut(), &mut [0x0b, 0x0c]); } } diff --git a/src/packet.rs b/src/packet.rs index 8c93188..b6ea01e 100644 --- a/src/packet.rs +++ b/src/packet.rs @@ -82,15 +82,13 @@ impl<'a> RtpPacket<'a> { return Err(RtpParseError::UnsupportedVersion(ret.version())); } - if ret.n_csrcs() > 0 { - // aka the end of the list of csrcs - let expected = ret.extension_offset(); - if ret.data.len() < expected { - return Err(RtpParseError::Truncated { - expected, - actual: ret.data.len(), - }); - } + // aka the end of the list of csrcs + let expected = ret.extension_offset(); + if ret.data.len() < expected { + return Err(RtpParseError::Truncated { + expected, + actual: ret.data.len(), + }); } if ret.extension_bit() { @@ -467,6 +465,7 @@ mod tests { assert_eq!(rtp.csrc().count(), 0); assert_eq!(rtp.extension(), None); assert_eq!(rtp.payload(), &[0x0b, 0x0c]); + assert_eq!(rtp.payload_len(), 2); let built = rtp.as_builder().write_vec().unwrap(); assert_eq!(built, data.as_ref()); }