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}