1use crate::Seq;
2
3#[derive(Debug, Ord, PartialOrd, Eq, PartialEq)]
5pub enum RtpPacketBuildError {
6 BufferTooSmall,
8
9 PayloadTypeInvalid,
11
12 ExtensionTooLarge,
14
15 ExtensionMissingPadding,
17}
18
19macro_rules! const_assert {
21 ($x:expr $(,)?) => {
22 #[allow(unknown_lints, clippy::eq_op)]
23 {
24 const ASSERT: [(); 1] = [()];
25 let _ = ASSERT[!($x) as usize];
26 }
27 };
28}
29
30pub struct Pad(PadInner);
42
43impl Pad {
44 pub const fn none() -> Self {
46 Pad(PadInner::None)
47 }
48 pub const fn round_to(pad: u8) -> Self {
53 const_assert!(pad >= 2);
54 Pad(PadInner::RoundTo(pad))
55 }
56}
57
58#[derive(Clone)]
61enum PadInner {
62 None,
63 RoundTo(u8),
64}
65
66impl PadInner {
67 pub fn adjust_len(&self, initial_len: usize) -> Option<usize> {
68 match self {
69 PadInner::None => None,
70 PadInner::RoundTo(n) => {
71 let remainder = initial_len % *n as usize;
72 if remainder == 0 {
73 None
74 } else {
75 Some(*n as usize - remainder)
76 }
77 },
78 }
79 }
80}
81
82#[derive(Clone)]
84pub struct RtpPacketBuilder<'a> {
85 padded: PadInner,
86 marked: bool,
87 payload_type: u8,
88
89 extension: Option<(u16, &'a [u8])>,
90 payload: Option<&'a [u8]>,
91
92 sequence: Seq,
93 timestamp: u32,
94
95 ssrc: u32,
96 csrcs: [u32; 15],
97 csrc_count: u8
98}
99
100impl<'a> RtpPacketBuilder<'a> {
101 pub fn new() -> Self {
103 RtpPacketBuilder {
104 padded: PadInner::None,
105 marked: false,
106 payload_type: 0xFF,
111
112 extension: None,
113 payload: None,
114
115 sequence: Seq::from(0),
116 timestamp: 0,
117
118 ssrc: 0,
119 csrcs: [0u32; 15],
120 csrc_count: 0
121 }
122 }
123
124 pub fn payload_type(mut self, payload_type: u8) -> Self {
128 self.payload_type = payload_type;
129 self
130 }
131
132 pub fn padded(mut self, pad: Pad) -> Self {
139 self.padded = pad.0;
140 self
141 }
142
143 pub fn marked(mut self, flag: bool) -> Self {
145 self.marked = flag;
146 self
147 }
148
149 pub fn add_csrc(mut self, csrc: u32) -> Self {
152 if self.csrc_count == 15 {
153 self
155 } else {
156 self.csrcs[self.csrc_count as usize] = csrc;
157 self.csrc_count = self.csrc_count + 1;
158 self
159 }
160 }
161
162 pub fn set_csrc(mut self, csrcs: &[u32]) -> Self {
165 if csrcs.len() > 15 {
166 self.csrc_count = 15;
167 } else {
168 self.csrc_count = csrcs.len() as u8;
169 }
170
171 self.csrcs[0..self.csrc_count as usize].copy_from_slice(csrcs);
172 self
173 }
174
175 pub fn sequence(mut self, seq: Seq) -> Self {
177 self.sequence = seq;
178 self
179 }
180
181 pub fn ssrc(mut self, ssrc: u32) -> Self {
183 self.ssrc = ssrc;
184 self
185 }
186
187 pub fn timestamp(mut self, timestamp: u32) -> Self {
189 self.timestamp = timestamp;
190 self
191 }
192
193 pub fn extension(mut self, id: u16, payload: &'a [u8]) -> Self {
197 self.extension = Some((id, payload));
198 self
199 }
200
201 pub fn payload(mut self, payload: &'a [u8]) -> Self {
203 self.payload = Some(payload);
204 self
205 }
206
207 pub fn target_length(&self) -> usize {
210 let mut length = 12usize;
212 length += self.csrc_count as usize * 4;
213 length += if let Some((_, ext)) = self.extension { ext.len() + 4 } else { 0 };
214 length += if let Some(payload) = self.payload { payload.len() } else { 0 };
215 if let Some(adj) = self.padded.adjust_len(length) {
216 length += adj;
217 }
218 length
219 }
220
221 pub fn build_into_unchecked(&self, target: &mut [u8]) -> usize {
223 let first_byte = &mut target[0];
224 *first_byte = 2 << 6; if self.extension.is_some() {
226 *first_byte |= 1 << 4; }
228 *first_byte |= self.csrc_count;
229
230 target[1] = self.payload_type;
231 if self.marked {
232 target[1] |= 0x80;
233 }
234
235 target[ 2] = (self.sequence.0 >> 8) as u8;
236 target[ 3] = (self.sequence.0 & 0xFF) as u8;
237
238 target[ 4] = (self.timestamp >> 24) as u8;
239 target[ 5] = (self.timestamp >> 16) as u8;
240 target[ 6] = (self.timestamp >> 8) as u8;
241 target[ 7] = (self.timestamp ) as u8;
242
243 target[ 8] = (self.ssrc >> 24) as u8;
244 target[ 9] = (self.ssrc >> 16) as u8;
245 target[10] = (self.ssrc >> 8) as u8;
246 target[11] = (self.ssrc ) as u8;
247
248 let mut write_index = 12usize;
249 for index in 0..self.csrc_count as usize {
250 let csrc = self.csrcs[index];
251 target[write_index + 0] = (csrc >> 24) as u8;
252 target[write_index + 1] = (csrc >> 16) as u8;
253 target[write_index + 2] = (csrc >> 8) as u8;
254 target[write_index + 3] = (csrc ) as u8;
255
256 write_index = write_index + 4;
257 }
258
259 if let Some((id, payload)) = self.extension {
260 target[write_index + 0] = (id >> 8) as u8;
261 target[write_index + 1] = (id & 0xFF) as u8;
262
263 let len = payload.len() / 4;
264 target[write_index + 2] = (len >> 8) as u8;
265 target[write_index + 3] = (len & 0xFF) as u8;
266
267 write_index = write_index + 4;
268
269 target[write_index..(write_index + payload.len())].copy_from_slice(payload);
271 write_index += payload.len();
272 }
273
274 if let Some(payload) = self.payload {
275 target[write_index..(write_index + payload.len())].copy_from_slice(payload);
277 write_index += payload.len();
278 }
279
280 if let Some(padded_bytes) = self.padded.adjust_len(write_index) {
281 target[0] |= 1 << 5; write_index += padded_bytes;
284 target[write_index - 1] = padded_bytes as u8;
285 }
286
287 write_index
288 }
289
290 pub fn build_into(&self, target: &mut [u8]) -> Result<usize, RtpPacketBuildError> {
293 if target.len() < self.target_length() {
294 return Err(RtpPacketBuildError::BufferTooSmall);
295 }
296
297 self.validate_content()?;
298 Ok(self.build_into_unchecked(target))
299 }
300
301
302 pub fn build(&self) -> Result<Vec<u8>, RtpPacketBuildError> {
305 self.validate_content()?;
306
307 let mut buffer = Vec::<u8>::new();
308 buffer.resize(self.target_length(), 0);
309
310 let length = self.build_into_unchecked(buffer.as_mut_slice());
311 assert_eq!(length, buffer.len());
312
313 Ok(buffer)
314 }
315
316 fn validate_content(&self) -> Result<(), RtpPacketBuildError> {
317 if (self.payload_type & (!0x7F)) != 0 {
318 return Err(RtpPacketBuildError::PayloadTypeInvalid);
319 }
320
321 if let Some((_, payload)) = self.extension {
322 if payload.len() > 0xFFFF {
323 return Err(RtpPacketBuildError::ExtensionTooLarge);
324 }
325
326 if (payload.len() & 0x3) != 0 {
327 return Err(RtpPacketBuildError::ExtensionMissingPadding);
328 }
329 }
330
331 Ok(())
332 }
333}
334
335#[cfg(test)]
336mod test {
337 use crate::{RtpPacketBuilder, Pad};
338
339 #[test]
340 fn test_padded() {
341 let payload = vec![1u8];
342 let packet = RtpPacketBuilder::new()
343 .payload_type(1)
344 .payload(&payload)
345 .padded(Pad::round_to(4))
346 .build().unwrap();
347
348 assert_eq!(packet.len() & 0x03, 0);
349 assert!(crate::reader::RtpReader::new(&packet).unwrap().padding().is_some());
350 }
351
352 #[test]
353 fn test_padding_not_needed() {
354 let payload = vec![1u8; 4];
355 let packet = RtpPacketBuilder::new()
356 .payload_type(1)
357 .payload(&payload)
358 .padded(Pad::round_to(4))
359 .build().unwrap();
360
361 assert_eq!(packet.len(), 12 + payload.len());
363 assert!(crate::reader::RtpReader::new(&packet).unwrap().padding().is_none());
364 }
365
366 #[test]
367 fn test_not_padded() {
368 let payload = vec![1u8];
369 let packet = RtpPacketBuilder::new()
370 .payload_type(1)
371 .payload(&payload)
372 .build().unwrap();
373
374 assert_eq!(packet.len() & 0x03, 1);
375 }
376
377 #[test]
378 fn test_would_run() {
379 let extension = vec![1u8, 2, 3, 4];
380 let builder = RtpPacketBuilder::new()
381 .payload_type(12)
382 .extension(1, &extension);
383
384 let mut buffer = [0u8; 100];
385 builder.build_into(&mut buffer).unwrap();
386 }
387}