bt_avdtp/
rtp.rs

1// Copyright 2019 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use bitfield::bitfield;
6use thiserror::Error;
7
8/// The error types for rtp header parsing.
9#[derive(Error, Debug, PartialEq)]
10pub enum RtpError {
11    /// The buffer used to create the header was too short
12    #[error("The buffer is too short.")]
13    BufferTooShort,
14
15    /// The RTP version of this packet is not supported
16    #[error("Unsupported RTP Version.")]
17    UnsupportedVersion,
18
19    /// The value that was provided is invalid.
20    #[error("Unsupported flags or fields were found in the header.")]
21    UnsupportedFeature,
22
23    #[doc(hidden)]
24    #[error("__Nonexhaustive error should never be created.")]
25    __Nonexhaustive,
26}
27
28bitfield! {
29    pub struct RtpHeaderInner(MSB0 [u8]);
30    impl Debug;
31    pub u8, version, _: 1, 0;
32    pub bool, padding, _: 2;
33    pub bool, extension, _: 3;
34    pub u8, csrc_count, _: 7, 4;
35    pub bool, marker, _: 8;
36    pub u8, payload_type, _: 15, 9;
37    pub u16, sequence_number, _: 31, 16;
38    pub u32, timestamp, _: 63, 32;
39    pub u32, ssrc, _: 95, 64;
40}
41
42/// RTP Packet header as described in https://tools.ietf.org/html/rfc1889 Section 5.1
43///
44/// RTP, the real-time transport protocol, provides end-to-end network transport functions
45/// suitable for applications transmitting real-time data, such as audio, video or
46/// simulation data, over multicast or unicast network services.
47#[cfg_attr(test, derive(Debug))]
48pub struct RtpHeader(RtpHeaderInner<[u8; Self::LENGTH]>);
49
50impl RtpHeader {
51    /// The minimum length of an RTP Header in bytes. This is the length of the header,
52    /// if there are no extension fields or csrc fields.
53    pub const LENGTH: usize = 12;
54
55    /// Parse and validate an RTP Packet from a buffer of bytes. Only packets that do
56    /// not contain extension fields or csrc fields will be parsed. This is done because
57    /// we do not currently use the aformentioned fields and a fixed size header is guaranteed
58    /// when headers to not contain them.
59    pub fn new(buf: &[u8]) -> Result<Self, RtpError> {
60        if buf.len() < Self::LENGTH {
61            return Err(RtpError::BufferTooShort);
62        }
63        let mut b = [0; Self::LENGTH];
64        b.copy_from_slice(&buf[..Self::LENGTH]);
65        let r = RtpHeaderInner(b);
66        if r.version() != 2 {
67            return Err(RtpError::UnsupportedVersion);
68        }
69        if r.extension() {
70            return Err(RtpError::UnsupportedFeature);
71        }
72        if r.csrc_count() > 0 {
73            return Err(RtpError::UnsupportedFeature);
74        }
75        Ok(Self(r))
76    }
77
78    /// The sequence number increments by one for each RTP data packet
79    /// sent, and may be used by the receiver to detect packet loss and
80    /// to restore packet sequence. The initial value of the sequence
81    /// number is random (unpredictable) to make known-plaintext attacks
82    /// on encryption more difficult, even if the source itself does not
83    /// encrypt, because the packets may flow through a translator that
84    /// does.
85    pub fn sequence_number(&self) -> u16 {
86        self.0.sequence_number()
87    }
88
89    /// The timestamp reflects the sampling instant of the first octet
90    /// in the RTP data packet. The sampling instant must be derived
91    /// from a clock that increments monotonically and linearly in time
92    /// to allow synchronization and jitter calculations (see Section
93    /// 6.3.1).  The resolution of the clock must be sufficient for the
94    /// desired synchronization accuracy and for measuring packet
95    /// arrival jitter (one tick per video frame is typically not
96    /// sufficient).  The clock frequency is dependent on the format of
97    /// data carried as payload and is specified statically in the
98    /// profile or payload format specification that defines the format,
99    /// or may be specified dynamically for payload formats defined
100    /// through non-RTP means. If RTP packets are generated
101    /// periodically, the nominal sampling instant as determined from
102    /// the sampling clock is to be used, not a reading of the system
103    /// clock. As an example, for fixed-rate audio the timestamp clock
104    /// would likely increment by one for each sampling period.  If an
105    /// audio application reads blocks covering 160 sampling periods
106    /// from the input device, the timestamp would be increased by 160
107    /// for each such block, regardless of whether the block is
108    /// transmitted in a packet or dropped as silent.
109    ///
110    /// The initial value of the timestamp is random, as for the sequence
111    /// number. Several consecutive RTP packets may have equal timestamps if
112    /// they are (logically) generated at once, e.g., belong to the same
113    /// video frame. Consecutive RTP packets may contain timestamps that are
114    /// not monotonic if the data is not transmitted in the order it was
115    /// sampled, as in the case of MPEG interpolated video frames. (The
116    /// sequence numbers of the packets as transmitted will still be
117    /// monotonic.)
118    pub fn timestamp(&self) -> u32 {
119        self.0.timestamp()
120    }
121}
122
123#[cfg(test)]
124mod tests {
125    use super::*;
126
127    #[test]
128    fn test_valid_rtp_headers() {
129        let raw = [128, 96, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 5];
130        let header = RtpHeader::new(&raw).expect("valid header");
131        assert_eq!(header.sequence_number(), 1);
132        assert_eq!(header.timestamp(), 0);
133
134        let raw_with_payload = [128, 96, 0, 2, 0, 0, 2, 128, 0, 0, 0, 0, 5, 0, 1, 2, 3, 4];
135        let header = RtpHeader::new(&raw_with_payload).expect("valid header");
136        assert_eq!(header.sequence_number(), 2);
137        assert_eq!(header.timestamp(), 640);
138    }
139
140    #[test]
141    fn test_invalid_rtp_headers() {
142        let raw_short = [128, 96];
143        let err = RtpHeader::new(&raw_short).expect_err("invalid header");
144        assert_eq!(err, RtpError::BufferTooShort);
145
146        let raw_unsupported_version =
147            [0b0100_0000, 96, 0, 2, 0, 0, 2, 128, 0, 0, 0, 0, 5, 0, 1, 2, 3, 4];
148        let err = RtpHeader::new(&raw_unsupported_version).expect_err("invalid header");
149        assert_eq!(err, RtpError::UnsupportedVersion);
150
151        let raw_unsupported_extension =
152            [0b1001_0000, 96, 0, 2, 0, 0, 2, 128, 0, 0, 0, 0, 5, 0, 1, 2, 3, 4];
153        let err = RtpHeader::new(&raw_unsupported_extension).expect_err("invalid header");
154        assert_eq!(err, RtpError::UnsupportedFeature);
155
156        let raw_includes_csrc = [0b1000_1000, 96, 0, 2, 0, 0, 2, 128, 0, 0, 0, 0, 5, 0, 1, 2, 3, 4];
157        let err = RtpHeader::new(&raw_includes_csrc).expect_err("invalid header");
158        assert_eq!(err, RtpError::UnsupportedFeature);
159    }
160}