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
89#[derive(Debug, PartialEq, Eq, Default, Clone)]
91pub struct Header {
92 pub padding: bool,
96 pub count: u8,
98 pub packet_type: PacketType,
100 pub length: u16,
103}
104
105impl MarshalSize for Header {
107 fn marshal_size(&self) -> usize {
108 HEADER_LENGTH
109 }
110}
111
112impl Marshal for Header {
113 fn marshal_to(&self, mut buf: &mut [u8]) -> Result<usize> {
114 if self.count > 31 {
115 return Err(Error::InvalidHeader);
116 }
117 if buf.remaining_mut() < HEADER_LENGTH {
118 return Err(Error::BufferTooShort);
119 }
120
121 let b0 = (RTP_VERSION << VERSION_SHIFT)
129 | ((self.padding as u8) << PADDING_SHIFT)
130 | (self.count << COUNT_SHIFT);
131
132 buf.put_u8(b0);
133 buf.put_u8(self.packet_type as u8);
134 buf.put_u16(self.length);
135
136 Ok(HEADER_LENGTH)
137 }
138}
139
140impl Unmarshal for Header {
141 fn unmarshal<B>(raw_packet: &mut B) -> Result<Self>
143 where
144 Self: Sized,
145 B: Buf,
146 {
147 if raw_packet.remaining() < HEADER_LENGTH {
148 return Err(Error::PacketTooShort);
149 }
150
151 let b0 = raw_packet.get_u8();
159 let version = (b0 >> VERSION_SHIFT) & VERSION_MASK;
160 if version != RTP_VERSION {
161 return Err(Error::BadVersion);
162 }
163
164 let padding = ((b0 >> PADDING_SHIFT) & PADDING_MASK) > 0;
165 let count = (b0 >> COUNT_SHIFT) & COUNT_MASK;
166 let packet_type = PacketType::from(raw_packet.get_u8());
167 let length = raw_packet.get_u16();
168
169 Ok(Header {
170 padding,
171 count,
172 packet_type,
173 length,
174 })
175 }
176}
177
178#[cfg(test)]
179mod test {
180 use super::*;
181 use bytes::Bytes;
182
183 #[test]
184 fn test_header_unmarshal() {
185 let tests = vec![
186 (
187 "valid",
188 Bytes::from_static(&[
189 0x81u8, 0xc9, 0x00, 0x07,
191 ]),
192 Header {
193 padding: false,
194 count: 1,
195 packet_type: PacketType::ReceiverReport,
196 length: 7,
197 },
198 None,
199 ),
200 (
201 "also valid",
202 Bytes::from_static(&[
203 0xa1, 0xcc, 0x00, 0x07,
205 ]),
206 Header {
207 padding: true,
208 count: 1,
209 packet_type: PacketType::ApplicationDefined,
210 length: 7,
211 },
212 None,
213 ),
214 (
215 "bad version",
216 Bytes::from_static(&[
217 0x00, 0xc9, 0x00, 0x04,
219 ]),
220 Header {
221 padding: false,
222 count: 0,
223 packet_type: PacketType::Unsupported,
224 length: 0,
225 },
226 Some(Error::BadVersion),
227 ),
228 ];
229
230 for (name, data, want, want_error) in tests {
231 let buf = &mut data.clone();
232 let got = Header::unmarshal(buf);
233
234 assert_eq!(
235 got.is_err(),
236 want_error.is_some(),
237 "Unmarshal {name}: err = {got:?}, want {want_error:?}"
238 );
239
240 if let Some(want_error) = want_error {
241 let got_err = got.err().unwrap();
242 assert_eq!(
243 want_error, got_err,
244 "Unmarshal {name}: err = {got_err:?}, want {want_error:?}",
245 );
246 } else {
247 let actual = got.unwrap();
248 assert_eq!(
249 actual, want,
250 "Unmarshal {name}: got {actual:?}, want {want:?}"
251 );
252 }
253 }
254 }
255
256 #[test]
257 fn test_header_roundtrip() {
258 let tests = vec![
259 (
260 "valid",
261 Header {
262 padding: true,
263 count: 31,
264 packet_type: PacketType::SenderReport,
265 length: 4,
266 },
267 None,
268 ),
269 (
270 "also valid",
271 Header {
272 padding: false,
273 count: 28,
274 packet_type: PacketType::ReceiverReport,
275 length: 65535,
276 },
277 None,
278 ),
279 (
280 "invalid count",
281 Header {
282 padding: false,
283 count: 40,
284 packet_type: PacketType::Unsupported,
285 length: 0,
286 },
287 Some(Error::InvalidHeader),
288 ),
289 ];
290
291 for (name, want, want_error) in tests {
292 let got = want.marshal();
293
294 assert_eq!(
295 got.is_ok(),
296 want_error.is_none(),
297 "Marshal {name}: err = {got:?}, want {want_error:?}"
298 );
299
300 if let Some(err) = want_error {
301 let got_err = got.err().unwrap();
302 assert_eq!(
303 err, got_err,
304 "Unmarshal {name} rr: err = {got_err:?}, want {err:?}",
305 );
306 } else {
307 let data = got.ok().unwrap();
308 let buf = &mut data.clone();
309 let actual = Header::unmarshal(buf).unwrap_or_else(|_| panic!("Unmarshal {name}"));
310
311 assert_eq!(
312 actual, want,
313 "{name} round trip: got {actual:?}, want {want:?}"
314 )
315 }
316 }
317 }
318}