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