1use bytes::{Buf, BufMut};
2use util::marshal::{Marshal, MarshalSize, Unmarshal};
3
4use crate::error::Error;
5
6#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
9#[repr(u8)]
10pub enum PacketType {
11 #[default]
12 Unsupported = 0,
13 SenderReport = 200, ReceiverReport = 201, SourceDescription = 202, Goodbye = 203, ApplicationDefined = 204, TransportSpecificFeedback = 205, PayloadSpecificFeedback = 206, ExtendedReport = 207, }
22
23pub const FORMAT_SLI: u8 = 2;
25pub const FORMAT_PLI: u8 = 1;
27pub const FORMAT_FIR: u8 = 4;
29pub const FORMAT_TLN: u8 = 1;
31pub const FORMAT_RRR: u8 = 5;
33pub const FORMAT_REMB: u8 = 15;
35pub const FORMAT_TCC: u8 = 15;
38
39impl std::fmt::Display for PacketType {
40 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
41 let s = match self {
42 PacketType::Unsupported => "Unsupported",
43 PacketType::SenderReport => "SR",
44 PacketType::ReceiverReport => "RR",
45 PacketType::SourceDescription => "SDES",
46 PacketType::Goodbye => "BYE",
47 PacketType::ApplicationDefined => "APP",
48 PacketType::TransportSpecificFeedback => "TSFB",
49 PacketType::PayloadSpecificFeedback => "PSFB",
50 PacketType::ExtendedReport => "XR",
51 };
52 write!(f, "{s}")
53 }
54}
55
56impl From<u8> for PacketType {
57 fn from(b: u8) -> Self {
58 match b {
59 200 => PacketType::SenderReport, 201 => PacketType::ReceiverReport, 202 => PacketType::SourceDescription, 203 => PacketType::Goodbye, 204 => PacketType::ApplicationDefined, 205 => PacketType::TransportSpecificFeedback, 206 => PacketType::PayloadSpecificFeedback, 207 => PacketType::ExtendedReport, _ => PacketType::Unsupported,
68 }
69 }
70}
71
72pub const RTP_VERSION: u8 = 2;
73pub const VERSION_SHIFT: u8 = 6;
74pub const VERSION_MASK: u8 = 0x3;
75pub const PADDING_SHIFT: u8 = 5;
76pub const PADDING_MASK: u8 = 0x1;
77pub const COUNT_SHIFT: u8 = 0;
78pub const COUNT_MASK: u8 = 0x1f;
79
80pub const HEADER_LENGTH: usize = 4;
81pub const COUNT_MAX: usize = (1 << 5) - 1;
82pub const SSRC_LENGTH: usize = 4;
83pub const SDES_MAX_OCTET_COUNT: usize = (1 << 8) - 1;
84
85#[derive(Debug, PartialEq, Eq, Default, Clone)]
87pub struct Header {
88 pub padding: bool,
92 pub count: u8,
94 pub packet_type: PacketType,
96 pub length: u16,
99}
100
101impl MarshalSize for Header {
103 fn marshal_size(&self) -> usize {
104 HEADER_LENGTH
105 }
106}
107
108impl Marshal for Header {
109 fn marshal_to(&self, mut buf: &mut [u8]) -> Result<usize, util::Error> {
110 if self.count > 31 {
111 return Err(Error::InvalidHeader.into());
112 }
113 if buf.remaining_mut() < HEADER_LENGTH {
114 return Err(Error::BufferTooShort.into());
115 }
116
117 let b0 = (RTP_VERSION << VERSION_SHIFT)
125 | ((self.padding as u8) << PADDING_SHIFT)
126 | (self.count << COUNT_SHIFT);
127
128 buf.put_u8(b0);
129 buf.put_u8(self.packet_type as u8);
130 buf.put_u16(self.length);
131
132 Ok(HEADER_LENGTH)
133 }
134}
135
136impl Unmarshal for Header {
137 fn unmarshal<B>(raw_packet: &mut B) -> Result<Self, util::Error>
139 where
140 Self: Sized,
141 B: Buf,
142 {
143 if raw_packet.remaining() < HEADER_LENGTH {
144 return Err(Error::PacketTooShort.into());
145 }
146
147 let b0 = raw_packet.get_u8();
155 let version = (b0 >> VERSION_SHIFT) & VERSION_MASK;
156 if version != RTP_VERSION {
157 return Err(Error::BadVersion.into());
158 }
159
160 let padding = ((b0 >> PADDING_SHIFT) & PADDING_MASK) > 0;
161 let count = (b0 >> COUNT_SHIFT) & COUNT_MASK;
162 let packet_type = PacketType::from(raw_packet.get_u8());
163 let length = raw_packet.get_u16();
164
165 Ok(Header {
166 padding,
167 count,
168 packet_type,
169 length,
170 })
171 }
172}
173
174#[cfg(test)]
175mod test {
176 use bytes::Bytes;
177
178 use super::*;
179
180 #[test]
181 fn test_header_unmarshal() {
182 let tests = vec![
183 (
184 "valid",
185 Bytes::from_static(&[
186 0x81u8, 0xc9, 0x00, 0x07,
188 ]),
189 Header {
190 padding: false,
191 count: 1,
192 packet_type: PacketType::ReceiverReport,
193 length: 7,
194 },
195 None,
196 ),
197 (
198 "also valid",
199 Bytes::from_static(&[
200 0xa1, 0xcc, 0x00, 0x07,
202 ]),
203 Header {
204 padding: true,
205 count: 1,
206 packet_type: PacketType::ApplicationDefined,
207 length: 7,
208 },
209 None,
210 ),
211 (
212 "bad version",
213 Bytes::from_static(&[
214 0x00, 0xc9, 0x00, 0x04,
216 ]),
217 Header {
218 padding: false,
219 count: 0,
220 packet_type: PacketType::Unsupported,
221 length: 0,
222 },
223 Some(Error::BadVersion),
224 ),
225 ];
226
227 for (name, data, want, want_error) in tests {
228 let buf = &mut data.clone();
229 let got = Header::unmarshal(buf);
230
231 assert_eq!(
232 got.is_err(),
233 want_error.is_some(),
234 "Unmarshal {name}: err = {got:?}, want {want_error:?}"
235 );
236
237 if let Some(want_error) = want_error {
238 let got_err = got.err().unwrap();
239 assert_eq!(
240 want_error, got_err,
241 "Unmarshal {name}: err = {got_err:?}, want {want_error:?}",
242 );
243 } else {
244 let actual = got.unwrap();
245 assert_eq!(
246 actual, want,
247 "Unmarshal {name}: got {actual:?}, want {want:?}"
248 );
249 }
250 }
251 }
252
253 #[test]
254 fn test_header_roundtrip() {
255 let tests = vec![
256 (
257 "valid",
258 Header {
259 padding: true,
260 count: 31,
261 packet_type: PacketType::SenderReport,
262 length: 4,
263 },
264 None,
265 ),
266 (
267 "also valid",
268 Header {
269 padding: false,
270 count: 28,
271 packet_type: PacketType::ReceiverReport,
272 length: 65535,
273 },
274 None,
275 ),
276 (
277 "invalid count",
278 Header {
279 padding: false,
280 count: 40,
281 packet_type: PacketType::Unsupported,
282 length: 0,
283 },
284 Some(Error::InvalidHeader),
285 ),
286 ];
287
288 for (name, want, want_error) in tests {
289 let got = want.marshal();
290
291 assert_eq!(
292 got.is_ok(),
293 want_error.is_none(),
294 "Marshal {name}: err = {got:?}, want {want_error:?}"
295 );
296
297 if let Some(err) = want_error {
298 let got_err = got.err().unwrap();
299 assert_eq!(
300 err, got_err,
301 "Unmarshal {name} rr: err = {got_err:?}, want {err:?}",
302 );
303 } else {
304 let data = got.ok().unwrap();
305 let buf = &mut data.clone();
306 let actual = Header::unmarshal(buf).unwrap_or_else(|_| panic!("Unmarshal {name}"));
307
308 assert_eq!(
309 actual, want,
310 "{name} round trip: got {actual:?}, want {want:?}"
311 )
312 }
313 }
314 }
315}