Skip to main content

rtc_rtp/
header.rs

1use shared::{
2    error::{Error, Result},
3    marshal::{Marshal, MarshalSize, Unmarshal},
4};
5
6use bytes::{Buf, BufMut, Bytes};
7
8pub const HEADER_LENGTH: usize = 4;
9pub const VERSION_SHIFT: u8 = 6;
10pub const VERSION_MASK: u8 = 0x3;
11pub const PADDING_SHIFT: u8 = 5;
12pub const PADDING_MASK: u8 = 0x1;
13pub const EXTENSION_SHIFT: u8 = 4;
14pub const EXTENSION_MASK: u8 = 0x1;
15pub const EXTENSION_PROFILE_ONE_BYTE: u16 = 0xBEDE;
16pub const EXTENSION_PROFILE_TWO_BYTE: u16 = 0x1000;
17pub const EXTENSION_ID_RESERVED: u8 = 0xF;
18pub const CC_MASK: u8 = 0xF;
19pub const MARKER_SHIFT: u8 = 7;
20pub const MARKER_MASK: u8 = 0x1;
21pub const PT_MASK: u8 = 0x7F;
22pub const SEQ_NUM_OFFSET: usize = 2;
23pub const SEQ_NUM_LENGTH: usize = 2;
24pub const TIMESTAMP_OFFSET: usize = 4;
25pub const TIMESTAMP_LENGTH: usize = 4;
26pub const SSRC_OFFSET: usize = 8;
27pub const SSRC_LENGTH: usize = 4;
28pub const CSRC_OFFSET: usize = 12;
29pub const CSRC_LENGTH: usize = 4;
30
31#[derive(Debug, Eq, PartialEq, Default, Clone)]
32pub struct Extension {
33    pub id: u8,
34    pub payload: Bytes,
35}
36
37/// Header represents an RTP packet header
38/// NOTE: PayloadOffset is populated by Marshal/Unmarshal and should not be modified
39#[derive(Debug, Eq, PartialEq, Default, Clone)]
40pub struct Header {
41    pub version: u8,
42    pub padding: bool,
43    pub extension: bool,
44    pub marker: bool,
45    pub payload_type: u8,
46    pub sequence_number: u16,
47    pub timestamp: u32,
48    pub ssrc: u32,
49    pub csrc: Vec<u32>,
50    pub extension_profile: u16,
51    pub extensions: Vec<Extension>,
52    pub extensions_padding: usize,
53}
54
55impl Unmarshal for Header {
56    /// Unmarshal parses the passed byte slice and stores the result in the Header this method is called upon
57    fn unmarshal<B>(raw_packet: &mut B) -> Result<Self>
58    where
59        Self: Sized,
60        B: Buf,
61    {
62        let raw_packet_len = raw_packet.remaining();
63        if raw_packet_len < HEADER_LENGTH {
64            return Err(Error::ErrHeaderSizeInsufficient);
65        }
66        /*
67         *  0                   1                   2                   3
68         *  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
69         * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
70         * |V=2|P|X|  CC   |M|     PT      |       sequence number         |
71         * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
72         * |                           timestamp                           |
73         * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
74         * |           synchronization source (SSRC) identifier            |
75         * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
76         * |            contributing source (CSRC) identifiers             |
77         * |                             ....                              |
78         * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
79         */
80        let b0 = raw_packet.get_u8();
81        let version = b0 >> VERSION_SHIFT & VERSION_MASK;
82        let padding = (b0 >> PADDING_SHIFT & PADDING_MASK) > 0;
83        let extension = (b0 >> EXTENSION_SHIFT & EXTENSION_MASK) > 0;
84        let cc = (b0 & CC_MASK) as usize;
85
86        let mut curr_offset = CSRC_OFFSET + (cc * CSRC_LENGTH);
87        if raw_packet_len < curr_offset {
88            return Err(Error::ErrHeaderSizeInsufficient);
89        }
90
91        let b1 = raw_packet.get_u8();
92        let marker = (b1 >> MARKER_SHIFT & MARKER_MASK) > 0;
93        let payload_type = b1 & PT_MASK;
94
95        let sequence_number = raw_packet.get_u16();
96        let timestamp = raw_packet.get_u32();
97        let ssrc = raw_packet.get_u32();
98
99        let mut csrc = Vec::with_capacity(cc);
100        for _ in 0..cc {
101            csrc.push(raw_packet.get_u32());
102        }
103        let mut extensions_padding: usize = 0;
104        let (extension_profile, extensions) = if extension {
105            let expected = curr_offset + 4;
106            if raw_packet_len < expected {
107                return Err(Error::ErrHeaderSizeInsufficientForExtension);
108            }
109            let extension_profile = raw_packet.get_u16();
110            curr_offset += 2;
111            let extension_length = raw_packet.get_u16() as usize * 4;
112            curr_offset += 2;
113
114            let expected = curr_offset + extension_length;
115            if raw_packet_len < expected {
116                return Err(Error::ErrHeaderSizeInsufficientForExtension);
117            }
118
119            let mut extensions = vec![];
120            match extension_profile {
121                // RFC 8285 RTP One Byte Header Extension
122                EXTENSION_PROFILE_ONE_BYTE => {
123                    let end = curr_offset + extension_length;
124                    while curr_offset < end {
125                        let b = raw_packet.get_u8();
126                        if b == 0x00 {
127                            // padding
128                            curr_offset += 1;
129                            extensions_padding += 1;
130                            continue;
131                        }
132
133                        let extid = b >> 4;
134                        let len = ((b & (0xFF ^ 0xF0)) + 1) as usize;
135                        curr_offset += 1;
136
137                        if extid == EXTENSION_ID_RESERVED {
138                            break;
139                        }
140
141                        if len > raw_packet.remaining() {
142                            return Err(Error::ErrHeaderSizeInsufficientForExtension);
143                        }
144
145                        extensions.push(Extension {
146                            id: extid,
147                            payload: raw_packet.copy_to_bytes(len),
148                        });
149                        curr_offset += len;
150                    }
151                }
152                // RFC 8285 RTP Two Byte Header Extension
153                EXTENSION_PROFILE_TWO_BYTE => {
154                    let end = curr_offset + extension_length;
155                    while curr_offset < end {
156                        let b = raw_packet.get_u8();
157                        if b == 0x00 {
158                            // padding
159                            curr_offset += 1;
160                            extensions_padding += 1;
161                            continue;
162                        }
163
164                        let extid = b;
165                        curr_offset += 1;
166
167                        if curr_offset >= end {
168                            return Err(Error::ErrHeaderSizeInsufficientForExtension);
169                        }
170
171                        let len = raw_packet.get_u8() as usize;
172                        curr_offset += 1;
173
174                        if len > raw_packet.remaining() {
175                            return Err(Error::ErrHeaderSizeInsufficientForExtension);
176                        }
177
178                        extensions.push(Extension {
179                            id: extid,
180                            payload: raw_packet.copy_to_bytes(len),
181                        });
182                        curr_offset += len;
183                    }
184                }
185                // RFC3550 Extension
186                _ => {
187                    if raw_packet_len < curr_offset + extension_length {
188                        return Err(Error::ErrHeaderSizeInsufficientForExtension);
189                    }
190                    extensions.push(Extension {
191                        id: 0,
192                        payload: raw_packet.copy_to_bytes(extension_length),
193                    });
194                }
195            };
196
197            (extension_profile, extensions)
198        } else {
199            (0, vec![])
200        };
201
202        Ok(Header {
203            version,
204            padding,
205            extension,
206            marker,
207            payload_type,
208            sequence_number,
209            timestamp,
210            ssrc,
211            csrc,
212            extension_profile,
213            extensions,
214            extensions_padding,
215        })
216    }
217}
218
219impl Header {
220    /// Marshaled header size given an already-computed extension payload length
221    /// (see [`Header::get_extension_payload_len`]). Lets `marshal_to` size the
222    /// buffer and write the extension length field from a single scan of the
223    /// extensions instead of walking them via `marshal_size` and again directly.
224    fn marshal_size_for(&self, extension_payload_len: usize) -> usize {
225        let mut head_size = 12 + (self.csrc.len() * CSRC_LENGTH);
226        if self.extension {
227            let padded = extension_payload_len + self.extensions_padding;
228            head_size += 4 + padded.div_ceil(4) * 4;
229        }
230        head_size
231    }
232}
233
234impl MarshalSize for Header {
235    /// MarshalSize returns the size of the packet once marshaled.
236    fn marshal_size(&self) -> usize {
237        let extension_payload_len = if self.extension {
238            self.get_extension_payload_len()
239        } else {
240            0
241        };
242        self.marshal_size_for(extension_payload_len)
243    }
244}
245
246impl Marshal for Header {
247    /// Marshal serializes the header and writes to the buffer.
248    fn marshal_to(&self, mut buf: &mut [u8]) -> Result<usize> {
249        /*
250         *  0                   1                   2                   3
251         *  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
252         * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
253         * |V=2|P|X|  CC   |M|     PT      |       sequence number         |
254         * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
255         * |                           timestamp                           |
256         * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
257         * |           synchronization source (SSRC) identifier            |
258         * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
259         * |            contributing source (CSRC) identifiers             |
260         * |                             ....                              |
261         * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
262         */
263        let remaining_before = buf.remaining_mut();
264        // Scan the extensions once here; reused for the bounds check, the
265        // extension length field, and the trailing padding below (previously
266        // walked three times: marshal_size() here plus twice in the body).
267        let extension_payload_len = if self.extension {
268            self.get_extension_payload_len()
269        } else {
270            0
271        };
272        if remaining_before < self.marshal_size_for(extension_payload_len) {
273            return Err(Error::ErrBufferTooSmall);
274        }
275
276        // The first byte contains the version, padding bit, extension bit, and csrc size
277        let mut b0 = (self.version << VERSION_SHIFT) | self.csrc.len() as u8;
278        if self.padding {
279            b0 |= 1 << PADDING_SHIFT;
280        }
281
282        if self.extension {
283            b0 |= 1 << EXTENSION_SHIFT;
284        }
285        buf.put_u8(b0);
286
287        // The second byte contains the marker bit and payload type.
288        let mut b1 = self.payload_type;
289        if self.marker {
290            b1 |= 1 << MARKER_SHIFT;
291        }
292        buf.put_u8(b1);
293
294        buf.put_u16(self.sequence_number);
295        buf.put_u32(self.timestamp);
296        buf.put_u32(self.ssrc);
297
298        for csrc in &self.csrc {
299            buf.put_u32(*csrc);
300        }
301
302        if self.extension {
303            buf.put_u16(self.extension_profile);
304
305            // extension_payload_len computed once at the top of this function.
306            if self.extension_profile != EXTENSION_PROFILE_ONE_BYTE
307                && self.extension_profile != EXTENSION_PROFILE_TWO_BYTE
308                && !extension_payload_len.is_multiple_of(4)
309            {
310                //the payload must be in 32-bit words.
311                return Err(Error::HeaderExtensionPayloadNot32BitWords);
312            }
313            let extension_payload_size = (extension_payload_len as u16).div_ceil(4);
314            buf.put_u16(extension_payload_size);
315
316            match self.extension_profile {
317                // RFC 8285 RTP One Byte Header Extension
318                EXTENSION_PROFILE_ONE_BYTE => {
319                    for extension in &self.extensions {
320                        buf.put_u8((extension.id << 4) | (extension.payload.len() as u8 - 1));
321                        buf.put(&*extension.payload);
322                    }
323                }
324                // RFC 8285 RTP Two Byte Header Extension
325                EXTENSION_PROFILE_TWO_BYTE => {
326                    for extension in &self.extensions {
327                        buf.put_u8(extension.id);
328                        buf.put_u8(extension.payload.len() as u8);
329                        buf.put(&*extension.payload);
330                    }
331                }
332                // RFC3550 Extension
333                _ => {
334                    if self.extensions.len() != 1 {
335                        return Err(Error::ErrRfc3550headerIdrange);
336                    }
337
338                    if let Some(extension) = self.extensions.first() {
339                        let ext_len = extension.payload.len();
340                        if ext_len % 4 != 0 {
341                            return Err(Error::HeaderExtensionPayloadNot32BitWords);
342                        }
343                        buf.put(&*extension.payload);
344                    }
345                }
346            };
347
348            // add padding to reach 4 bytes boundaries
349            for _ in extension_payload_len..extension_payload_size as usize * 4 {
350                buf.put_u8(0);
351            }
352        }
353
354        let remaining_after = buf.remaining_mut();
355        Ok(remaining_before - remaining_after)
356    }
357}
358
359impl Header {
360    pub fn get_extension_payload_len(&self) -> usize {
361        let payload_len: usize = self
362            .extensions
363            .iter()
364            .map(|extension| extension.payload.len())
365            .sum();
366
367        let profile_len = self.extensions.len()
368            * match self.extension_profile {
369                EXTENSION_PROFILE_ONE_BYTE => 1,
370                EXTENSION_PROFILE_TWO_BYTE => 2,
371                _ => 0,
372            };
373
374        payload_len + profile_len
375    }
376
377    /// SetExtension sets an RTP header extension
378    pub fn set_extension(&mut self, id: u8, payload: Bytes) -> Result<()> {
379        let payload_len = payload.len() as isize;
380        if self.extension {
381            let extension_profile_len = match self.extension_profile {
382                EXTENSION_PROFILE_ONE_BYTE => {
383                    if !(1..=14).contains(&id) {
384                        return Err(Error::ErrRfc8285oneByteHeaderIdrange);
385                    }
386                    if payload_len > 16 {
387                        return Err(Error::ErrRfc8285oneByteHeaderSize);
388                    }
389                    1
390                }
391                EXTENSION_PROFILE_TWO_BYTE => {
392                    if id < 1 {
393                        return Err(Error::ErrRfc8285twoByteHeaderIdrange);
394                    }
395                    if payload_len > 255 {
396                        return Err(Error::ErrRfc8285twoByteHeaderSize);
397                    }
398                    2
399                }
400                _ => {
401                    if id != 0 {
402                        return Err(Error::ErrRfc3550headerIdrange);
403                    }
404                    0
405                }
406            };
407
408            let delta;
409            // Update existing if it exists else add new extension
410            if let Some(extension) = self
411                .extensions
412                .iter_mut()
413                .find(|extension| extension.id == id)
414            {
415                delta = payload_len - extension.payload.len() as isize;
416                extension.payload = payload;
417            } else {
418                delta = payload_len + extension_profile_len;
419                self.extensions.push(Extension { id, payload });
420            }
421
422            match delta.cmp(&0) {
423                std::cmp::Ordering::Less => {
424                    self.extensions_padding =
425                        ((self.extensions_padding as isize - delta) % 4) as usize;
426                }
427                std::cmp::Ordering::Greater => {
428                    let extension_padding = (delta % 4) as usize;
429                    if self.extensions_padding < extension_padding {
430                        self.extensions_padding = (self.extensions_padding + 4) - extension_padding;
431                    } else {
432                        self.extensions_padding -= extension_padding
433                    }
434                }
435                _ => {}
436            }
437        } else {
438            // No existing header extensions
439            self.extension = true;
440            let mut extension_profile_len = 0;
441            self.extension_profile = match payload_len {
442                0..=16 => {
443                    extension_profile_len = 1;
444                    EXTENSION_PROFILE_ONE_BYTE
445                }
446                17..=255 => {
447                    extension_profile_len = 2;
448                    EXTENSION_PROFILE_TWO_BYTE
449                }
450                _ => self.extension_profile,
451            };
452
453            let extension_padding = (payload.len() + extension_profile_len) % 4;
454            if self.extensions_padding < extension_padding {
455                self.extensions_padding = self.extensions_padding + 4 - extension_padding;
456            } else {
457                self.extensions_padding -= extension_padding
458            }
459            self.extensions.push(Extension { id, payload });
460        }
461        Ok(())
462    }
463
464    /// returns an extension id array
465    pub fn get_extension_ids(&self) -> Vec<u8> {
466        if self.extension {
467            self.extensions.iter().map(|e| e.id).collect()
468        } else {
469            vec![]
470        }
471    }
472
473    /// returns an RTP header extension
474    pub fn get_extension(&self, id: u8) -> Option<Bytes> {
475        if self.extension {
476            self.extensions
477                .iter()
478                .find(|extension| extension.id == id)
479                .map(|extension| extension.payload.clone())
480        } else {
481            None
482        }
483    }
484
485    /// Removes an RTP Header extension
486    pub fn del_extension(&mut self, id: u8) -> Result<()> {
487        if self.extension {
488            if let Some(index) = self
489                .extensions
490                .iter()
491                .position(|extension| extension.id == id)
492            {
493                let extension = self.extensions.remove(index);
494
495                let extension_profile_len = match self.extension_profile {
496                    EXTENSION_PROFILE_ONE_BYTE => 1,
497                    EXTENSION_PROFILE_TWO_BYTE => 2,
498                    _ => 0,
499                };
500
501                let extension_padding = (extension.payload.len() + extension_profile_len) % 4;
502                self.extensions_padding = (self.extensions_padding + extension_padding) % 4;
503
504                Ok(())
505            } else {
506                Err(Error::ErrHeaderExtensionNotFound)
507            }
508        } else {
509            Err(Error::ErrHeaderExtensionsNotEnabled)
510        }
511    }
512}