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