Skip to main content

rtc_rtp/
header.rs

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