1use thiserror::Error;
2
3#[derive(Debug, Clone, PartialEq, Eq)]
17pub struct RtpPacket {
18 pub version: u8,
19 pub padding: bool,
20 pub extension: bool,
21 pub csrc_count: u8,
22 pub marker: bool,
23 pub payload_type: u8,
24 pub sequence_number: u16,
25 pub timestamp: u32,
26 pub ssrc: u32,
27 pub csrc: Vec<u32>,
28 pub payload: Vec<u8>,
29}
30
31#[derive(Debug, Error)]
32pub enum RtpError {
33 #[error("packet too short: {0} bytes")]
34 TooShort(usize),
35 #[error("invalid RTP version: {0}")]
36 InvalidVersion(u8),
37 #[error("buffer too small")]
38 BufferTooSmall,
39}
40
41impl RtpPacket {
42 pub const MIN_HEADER_SIZE: usize = 12;
44
45 pub fn new(payload_type: u8, sequence_number: u16, timestamp: u32, ssrc: u32) -> Self {
47 Self {
48 version: 2,
49 padding: false,
50 extension: false,
51 csrc_count: 0,
52 marker: false,
53 payload_type,
54 sequence_number,
55 timestamp,
56 ssrc,
57 csrc: Vec::new(),
58 payload: Vec::new(),
59 }
60 }
61
62 pub fn with_payload(mut self, payload: Vec<u8>) -> Self {
64 self.payload = payload;
65 self
66 }
67
68 pub fn with_marker(mut self, marker: bool) -> Self {
70 self.marker = marker;
71 self
72 }
73
74 pub fn parse(data: &[u8]) -> Result<Self, RtpError> {
76 if data.len() < Self::MIN_HEADER_SIZE {
77 return Err(RtpError::TooShort(data.len()));
78 }
79
80 let version = (data[0] >> 6) & 0x03;
81 if version != 2 {
82 return Err(RtpError::InvalidVersion(version));
83 }
84
85 let padding = (data[0] >> 5) & 0x01 != 0;
86 let extension = (data[0] >> 4) & 0x01 != 0;
87 let csrc_count = data[0] & 0x0F;
88 let marker = (data[1] >> 7) & 0x01 != 0;
89 let payload_type = data[1] & 0x7F;
90 let sequence_number = u16::from_be_bytes([data[2], data[3]]);
91 let timestamp = u32::from_be_bytes([data[4], data[5], data[6], data[7]]);
92 let ssrc = u32::from_be_bytes([data[8], data[9], data[10], data[11]]);
93
94 let header_size = Self::MIN_HEADER_SIZE + (csrc_count as usize * 4);
95 if data.len() < header_size {
96 return Err(RtpError::TooShort(data.len()));
97 }
98
99 let mut csrc = Vec::with_capacity(csrc_count as usize);
100 for i in 0..csrc_count as usize {
101 let offset = Self::MIN_HEADER_SIZE + (i * 4);
102 let csrc_id = u32::from_be_bytes([
103 data[offset],
104 data[offset + 1],
105 data[offset + 2],
106 data[offset + 3],
107 ]);
108 csrc.push(csrc_id);
109 }
110
111 let mut payload_offset = header_size;
112
113 if extension && data.len() >= payload_offset + 4 {
115 let ext_length =
116 u16::from_be_bytes([data[payload_offset + 2], data[payload_offset + 3]]) as usize;
117 payload_offset += 4 + (ext_length * 4);
118 }
119
120 let payload_end = if padding && !data.is_empty() {
121 let padding_len = data[data.len() - 1] as usize;
122 data.len().saturating_sub(padding_len)
123 } else {
124 data.len()
125 };
126
127 let payload = if payload_offset <= payload_end {
128 data[payload_offset..payload_end].to_vec()
129 } else {
130 Vec::new()
131 };
132
133 Ok(RtpPacket {
134 version,
135 padding,
136 extension,
137 csrc_count,
138 marker,
139 payload_type,
140 sequence_number,
141 timestamp,
142 ssrc,
143 csrc,
144 payload,
145 })
146 }
147
148 pub fn serialize(&self) -> Vec<u8> {
150 let header_size = Self::MIN_HEADER_SIZE + (self.csrc.len() * 4);
151 let mut buf = Vec::with_capacity(header_size + self.payload.len());
152
153 let byte0 = (self.version << 6)
155 | ((self.padding as u8) << 5)
156 | ((self.extension as u8) << 4)
157 | (self.csrc.len() as u8 & 0x0F);
158 buf.push(byte0);
159
160 let byte1 = ((self.marker as u8) << 7) | (self.payload_type & 0x7F);
162 buf.push(byte1);
163
164 buf.extend_from_slice(&self.sequence_number.to_be_bytes());
166
167 buf.extend_from_slice(&self.timestamp.to_be_bytes());
169
170 buf.extend_from_slice(&self.ssrc.to_be_bytes());
172
173 for csrc_id in &self.csrc {
175 buf.extend_from_slice(&csrc_id.to_be_bytes());
176 }
177
178 buf.extend_from_slice(&self.payload);
180
181 buf
182 }
183
184 pub fn size(&self) -> usize {
186 Self::MIN_HEADER_SIZE + (self.csrc.len() * 4) + self.payload.len()
187 }
188}
189
190#[cfg(test)]
191mod tests {
192 use super::*;
193
194 #[test]
195 fn test_new_packet() {
196 let pkt = RtpPacket::new(0, 1, 160, 0x12345678);
197 assert_eq!(pkt.version, 2);
198 assert_eq!(pkt.payload_type, 0);
199 assert_eq!(pkt.sequence_number, 1);
200 assert_eq!(pkt.timestamp, 160);
201 assert_eq!(pkt.ssrc, 0x12345678);
202 assert!(!pkt.marker);
203 assert!(pkt.payload.is_empty());
204 }
205
206 #[test]
207 fn test_with_payload() {
208 let pkt = RtpPacket::new(0, 1, 160, 0x12345678).with_payload(vec![1, 2, 3, 4]);
209 assert_eq!(pkt.payload, vec![1, 2, 3, 4]);
210 }
211
212 #[test]
213 fn test_with_marker() {
214 let pkt = RtpPacket::new(0, 1, 160, 0x12345678).with_marker(true);
215 assert!(pkt.marker);
216 }
217
218 #[test]
219 fn test_serialize_parse_roundtrip() {
220 let original = RtpPacket::new(0, 42, 3360, 0xDEADBEEF)
221 .with_payload(vec![0x80, 0xFF, 0x00, 0x7F, 0x01, 0x02])
222 .with_marker(true);
223
224 let bytes = original.serialize();
225 let parsed = RtpPacket::parse(&bytes).unwrap();
226
227 assert_eq!(parsed.version, 2);
228 assert_eq!(parsed.payload_type, 0);
229 assert_eq!(parsed.sequence_number, 42);
230 assert_eq!(parsed.timestamp, 3360);
231 assert_eq!(parsed.ssrc, 0xDEADBEEF);
232 assert!(parsed.marker);
233 assert_eq!(parsed.payload, vec![0x80, 0xFF, 0x00, 0x7F, 0x01, 0x02]);
234 }
235
236 #[test]
237 fn test_parse_pcmu_packet() {
238 let mut data = vec![
240 0x80, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xA0, 0x00, 0x00, 0x00, 0x01, ];
246 data.extend_from_slice(&vec![0x7F; 160]);
248
249 let pkt = RtpPacket::parse(&data).unwrap();
250 assert_eq!(pkt.version, 2);
251 assert_eq!(pkt.payload_type, 0);
252 assert_eq!(pkt.sequence_number, 1);
253 assert_eq!(pkt.timestamp, 160);
254 assert_eq!(pkt.ssrc, 1);
255 assert_eq!(pkt.payload.len(), 160);
256 }
257
258 #[test]
259 fn test_parse_too_short() {
260 let data = vec![0x80, 0x00, 0x00];
261 let result = RtpPacket::parse(&data);
262 assert!(matches!(result, Err(RtpError::TooShort(3))));
263 }
264
265 #[test]
266 fn test_parse_invalid_version() {
267 let data = vec![
268 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xA0, 0x00, 0x00, 0x00, 0x01,
270 ];
271 let result = RtpPacket::parse(&data);
272 assert!(matches!(result, Err(RtpError::InvalidVersion(0))));
273 }
274
275 #[test]
276 fn test_serialize_header_only() {
277 let pkt = RtpPacket::new(8, 100, 16000, 0xAAAABBBB);
278 let bytes = pkt.serialize();
279 assert_eq!(bytes.len(), RtpPacket::MIN_HEADER_SIZE);
280
281 assert_eq!(bytes[0] & 0xC0, 0x80); assert_eq!(bytes[1] & 0x7F, 8); assert_eq!(u16::from_be_bytes([bytes[2], bytes[3]]), 100);
289 }
290
291 #[test]
292 fn test_multiple_roundtrips() {
293 for pt in [0u8, 8, 111] {
294 for seq in [0u16, 1, 65535] {
295 let pkt = RtpPacket::new(pt, seq, seq as u32 * 160, 0x11223344)
296 .with_payload(vec![0xAA; 20]);
297 let bytes = pkt.serialize();
298 let parsed = RtpPacket::parse(&bytes).unwrap();
299 assert_eq!(parsed.payload_type, pt);
300 assert_eq!(parsed.sequence_number, seq);
301 assert_eq!(parsed.payload.len(), 20);
302 }
303 }
304 }
305
306 #[test]
307 fn test_packet_size() {
308 let pkt = RtpPacket::new(0, 1, 160, 1).with_payload(vec![0; 160]);
309 assert_eq!(pkt.size(), 12 + 160);
310
311 let pkt_empty = RtpPacket::new(0, 1, 160, 1);
312 assert_eq!(pkt_empty.size(), 12);
313 }
314
315 #[test]
316 fn test_csrc_roundtrip() {
317 let mut pkt = RtpPacket::new(0, 1, 160, 0x12345678);
318 pkt.csrc = vec![0xAAAA0001, 0xBBBB0002];
319 pkt.csrc_count = 2;
320 pkt.payload = vec![0xFF; 10];
321
322 let bytes = pkt.serialize();
323 let parsed = RtpPacket::parse(&bytes).unwrap();
324 assert_eq!(parsed.csrc_count, 2);
325 assert_eq!(parsed.csrc, vec![0xAAAA0001, 0xBBBB0002]);
326 assert_eq!(parsed.payload.len(), 10);
327 }
328
329 #[test]
330 fn test_marker_bit_serialization() {
331 let pkt = RtpPacket::new(111, 1, 960, 1).with_marker(true);
332 let bytes = pkt.serialize();
333 assert_eq!(bytes[1] & 0x80, 0x80); let pkt2 = RtpPacket::new(111, 1, 960, 1).with_marker(false);
336 let bytes2 = pkt2.serialize();
337 assert_eq!(bytes2[1] & 0x80, 0x00); }
339}