1use std::str::from_utf8;
2
3use anyhow::{Context, Result};
4use parsely_rs::*;
5
6use super::rtcp_header::RtcpHeader;
7
8#[derive(Debug, ParselyRead, ParselyWrite, PartialEq)]
35#[parsely_read(required_context("header: RtcpHeader"))]
36pub struct RtcpSdesPacket {
37 #[parsely_read(assign_from = "header")]
38 #[parsely_write(sync_with("self.payload_length_bytes()", "self.chunks.len().try_into()"))]
39 #[parsely(assertion = "|header: &RtcpHeader| header.packet_type == RtcpSdesPacket::PT")]
40 pub header: RtcpHeader,
41 #[parsely_read(count = "header.report_count.into()")]
42 pub chunks: Vec<SdesChunk>,
43}
44
45impl Default for RtcpSdesPacket {
46 fn default() -> Self {
47 Self {
48 header: RtcpHeader {
49 packet_type: RtcpSdesPacket::PT,
50 ..Default::default()
51 },
52 chunks: Default::default(),
53 }
54 }
55}
56
57impl RtcpSdesPacket {
58 pub const PT: u8 = 202;
59
60 pub fn add_chunk(mut self, chunk: SdesChunk) -> Self {
61 self.chunks.push(chunk);
62 self
63 }
64
65 pub fn payload_length_bytes(&self) -> u16 {
66 self.chunks.iter().map(|i| i.length_bytes()).sum()
67 }
68}
69
70#[derive(Debug, PartialEq)]
77pub enum SdesItem {
78 Empty,
79 Cname(String),
80 Unknown { item_type: u8, data: Vec<u8> },
81}
82
83impl SdesItem {
84 pub fn cname(cname: &str) -> Self {
85 SdesItem::Cname(cname.to_owned())
86 }
87
88 pub fn length_bytes(&self) -> u16 {
89 match self {
94 SdesItem::Empty => 1,
95 SdesItem::Cname(s) => 1 + 1 + s.len() as u16,
96 SdesItem::Unknown { data, .. } => 1 + 1 + data.len() as u16,
97 }
98 }
99}
100
101impl<B: BitBuf> ParselyRead<B> for SdesItem {
102 type Ctx = ();
103 fn read<T: ByteOrder>(buf: &mut B, _ctx: ()) -> ParselyResult<Self> {
104 let id = buf.get_u8().context("id")?;
105
106 if id == 0 {
107 return Ok(SdesItem::Empty);
108 }
109 let length = buf.get_u8().context("length")? as usize;
110 let mut value_bytes = vec![0u8; length];
111 buf.try_copy_to_slice_bytes(&mut value_bytes)
112 .context("value")?;
113 match id {
114 1 => Ok(SdesItem::Cname(from_utf8(&value_bytes)?.to_owned())),
115 t => Ok(SdesItem::Unknown {
116 item_type: t,
117 data: value_bytes.to_vec(),
118 }),
119 }
120 }
121}
122
123impl_stateless_sync!(SdesItem);
124
125impl<B: BitBufMut> ParselyWrite<B> for SdesItem {
126 type Ctx = ();
127 fn write<T: ByteOrder>(&self, buf: &mut B, _ctx: Self::Ctx) -> ParselyResult<()> {
128 match self {
129 SdesItem::Empty => {
130 buf.put_u8(0).context("id")?;
131 }
132 SdesItem::Cname(value) => {
133 buf.put_u8(1).context("id")?;
134 let bytes = value.as_bytes();
135 buf.put_u8(bytes.len() as u8).context("length")?;
136 buf.try_put_slice_bytes(bytes).context("value")?;
137 }
138 SdesItem::Unknown { item_type, data } => {
139 buf.put_u8(*item_type).context("id")?;
140 buf.put_u8(data.len() as u8).context("length")?;
141 buf.try_put_slice_bytes(&data[..]).context("value")?;
142 }
143 }
144 Ok(())
145 }
146}
147
148#[derive(Debug, PartialEq)]
158pub struct SdesChunk {
159 pub ssrc: u32,
160 pub sdes_items: Vec<SdesItem>,
163}
164
165impl SdesChunk {
166 pub fn new(ssrc: u32) -> Self {
167 Self {
168 ssrc,
169 sdes_items: Vec::new(),
170 }
171 }
172
173 pub fn new_with_items(ssrc: u32, sdes_items: Vec<SdesItem>) -> Self {
174 Self { ssrc, sdes_items }
175 }
176
177 pub fn add_item(mut self, item: SdesItem) -> Self {
178 self.sdes_items.push(item);
179 self
180 }
181
182 pub fn length_bytes(&self) -> u16 {
183 let mut length_bytes = 4 + self
184 .sdes_items
185 .iter()
186 .map(|i| i.length_bytes())
187 .sum::<u16>();
188
189 while length_bytes % 4 != 0 {
190 length_bytes += 1;
191 }
192
193 length_bytes
194 }
195}
196
197impl<B: BitBuf> ParselyRead<B> for SdesChunk {
198 type Ctx = ();
199 fn read<T: ByteOrder>(buf: &mut B, _ctx: ()) -> ParselyResult<Self> {
200 let remaining_start = buf.remaining_bytes();
201 let ssrc = buf.get_u32::<NetworkOrder>().context("ssrc")?;
202 let mut sdes_items: Vec<SdesItem> = Vec::new();
203 loop {
204 let sdes_item = SdesItem::read::<T>(buf, ()).context("item")?;
205 if matches!(sdes_item, SdesItem::Empty) {
206 break;
207 }
208 sdes_items.push(sdes_item);
209 }
210 let mut consumed = remaining_start - buf.remaining_bytes();
211 while consumed % 4 != 0 {
212 buf.get_u8().unwrap();
213 consumed += 1;
214 }
215
216 Ok(SdesChunk { ssrc, sdes_items })
217 }
218}
219
220impl_stateless_sync!(SdesChunk);
221
222impl<B: BitBufMut> ParselyWrite<B> for SdesChunk {
223 type Ctx = ();
224 fn write<T: ByteOrder>(&self, buf: &mut B, _ctx: Self::Ctx) -> ParselyResult<()> {
225 let remaining_start = buf.remaining_mut_bytes();
226 buf.put_u32::<NetworkOrder>(self.ssrc).context("ssrc")?;
227 self.sdes_items
228 .iter()
229 .enumerate()
230 .map(|(i, sdes_item)| {
231 sdes_item
232 .write::<T>(buf, ())
233 .with_context(|| format!("Sdes item {i}"))
234 })
235 .collect::<Result<Vec<()>>>()
236 .context("Sdes items")?;
237
238 SdesItem::Empty
239 .write::<T>(buf, ())
240 .context("Terminating empty sdes item")?;
241
242 let mut amount_written = remaining_start - buf.remaining_mut_bytes();
243 while amount_written % 4 != 0 {
244 buf.put_u8(0).context("padding")?;
245 amount_written += 1;
246 }
247
248 Ok(())
249 }
250}
251
252#[cfg(test)]
253mod tests {
254 use super::*;
255
256 fn create_cname_item_bytes(str: &str) -> Vec<u8> {
257 let data = str.bytes();
258 let mut item_data = vec![0x1, data.len() as u8];
259 item_data.extend(data.collect::<Vec<u8>>());
260
261 item_data
262 }
263
264 #[test]
265 fn test_read_sdes_item_success() {
266 let str = "hello, world!";
267 let item_data = create_cname_item_bytes(str);
268
269 let mut bits = Bits::from_owner_bytes(item_data);
270 let sdes_item = SdesItem::read::<NetworkOrder>(&mut bits, ()).expect("successful read");
271 match sdes_item {
272 SdesItem::Cname(v) => assert_eq!(v, str),
273 _ => panic!("Wrong SdesItem type"),
274 }
275 }
276
277 #[test]
278 fn test_read_sdes_item_bad_data() {
279 let data: Vec<u8> = vec![0xDE, 0xAD, 0xBE, 0xEF];
280 let mut item_data = vec![0x1, data.len() as u8];
281 item_data.extend(data);
282
283 let mut bits = Bits::from_owner_bytes(item_data);
284 let res = SdesItem::read::<NetworkOrder>(&mut bits, ());
285 assert!(res.is_err());
286 }
287
288 #[test]
289 fn test_read_sdes_item() {
290 let data = create_cname_item_bytes("hello");
292 let mut bits = Bits::from_owner_bytes(data);
293
294 let item = SdesItem::read::<NetworkOrder>(&mut bits, ()).expect("successful read");
295 match item {
296 SdesItem::Cname(s) => assert_eq!("hello", s),
297 _ => panic!("Expected cname item"),
298 }
299 let data: Vec<u8> = vec![0x6, 0x4, 0xDE, 0xAD, 0xBE, 0xEF];
301 let mut bits = Bits::from_owner_bytes(data);
302
303 let item = SdesItem::read::<NetworkOrder>(&mut bits, ()).expect("successful read");
304 match item {
305 SdesItem::Unknown { item_type, data } => {
306 assert_eq!(item_type, 6);
307 assert_eq!(&data[..], [0xDE, 0xAD, 0xBE, 0xEF]);
308 }
309 _ => panic!("Expected unknown item"),
310 }
311 }
312
313 #[test]
314 fn test_write_sdes_item() {
315 let item = SdesItem::cname("hello");
316 let mut bits_mut = BitsMut::new();
317
318 item.write::<NetworkOrder>(&mut bits_mut, ())
319 .expect("successful write");
320
321 let mut bits = bits_mut.freeze();
322
323 let read_item = SdesItem::read::<NetworkOrder>(&mut bits, ()).expect("successful read");
324 assert_eq!(item, read_item);
325 }
326
327 #[test]
328 fn test_write_unknown_sdes_item() {
329 let item = SdesItem::Unknown {
330 item_type: 0x5,
331 data: vec![0x42, 0x24],
332 };
333 let mut bits_mut = BitsMut::new();
334
335 item.write::<NetworkOrder>(&mut bits_mut, ())
336 .expect("successful write");
337
338 let mut bits = bits_mut.freeze();
339
340 let read_item = SdesItem::read::<NetworkOrder>(&mut bits, ()).expect("successful read");
341 assert_eq!(item, read_item);
342 }
343
344 #[test]
345 fn test_read_sdes_chunk() {
346 #[rustfmt::skip]
347 let mut bits = Bits::from_static_bytes(&[
348 0x00, 0x00, 0x00, 0x2a,
350 0x01, 0x5, 0x68, 0x65, 0x6c, 0x6c, 0x6f,
352 0x00,
354 ]);
355
356 let chunk = SdesChunk::read::<NetworkOrder>(&mut bits, ()).expect("successful read");
357 assert_eq!(bits.remaining_bytes(), 0);
358 assert_eq!(chunk.ssrc, 42);
359 assert_eq!(chunk.sdes_items.len(), 1);
360 let item = &chunk.sdes_items[0];
361 assert_eq!(item, &SdesItem::cname("hello"));
362 }
363
364 #[test]
365 fn tesd_read_sdes_chunks() {
366 #[rustfmt::skip]
367 let mut bits = Bits::from_static_bytes(&[
368 0x00, 0x00, 0x00, 0x2a,
370 0x01, 0x5, 0x68, 0x65, 0x6c, 0x6c, 0x6f,
372 0x04, 0x2, 0x42, 0x24,
374 0x00,
376 ]);
377
378 let chunk = SdesChunk::read::<NetworkOrder>(&mut bits, ()).expect("successful read");
379 assert_eq!(bits.remaining_bytes(), 0);
380 assert_eq!(chunk.ssrc, 42);
381 assert_eq!(chunk.sdes_items.len(), 2);
382 let item = &chunk.sdes_items[0];
383 assert_eq!(item, &SdesItem::cname("hello"));
384 let item = &chunk.sdes_items[1];
385 assert_eq!(
386 item,
387 &SdesItem::Unknown {
388 item_type: 0x4,
389 data: vec![0x42, 0x24]
390 }
391 );
392 }
393
394 #[test]
395 fn test_read_sdes_chunks_no_termination() {
396 #[rustfmt::skip]
397 let mut bits = Bits::from_static_bytes(&[
398 0x00, 0x00, 0x00, 0x2a,
400 0x01, 0x05, 0x68, 0x65, 0x6c, 0x6c, 0x6f,
402 0x04, 0x2, 0x42, 0x24,
404 ]);
406
407 let chunk = SdesChunk::read::<NetworkOrder>(&mut bits, ());
408 assert!(chunk.is_err());
409 }
410
411 #[test]
412 fn test_write_sdes_chunk() {
413 let chunk = SdesChunk::new(42)
414 .add_item(SdesItem::cname("hello"))
415 .add_item(SdesItem::Unknown {
416 item_type: 5,
417 data: vec![0x42, 0x24],
418 });
419
420 let mut bits_mut = BitsMut::new();
421 chunk
422 .write::<NetworkOrder>(&mut bits_mut, ())
423 .expect("successful write");
424 let mut bits = bits_mut.freeze();
425 let read_chunk = SdesChunk::read::<NetworkOrder>(&mut bits, ()).expect("successful read");
426 assert_eq!(chunk, read_chunk);
427 }
428
429 #[test]
430 fn test_read_sdes() {
431 let header = RtcpHeader {
432 version: u2::new(2),
433 has_padding: false,
434 report_count: u5::new(1),
435 packet_type: 202,
436 length_field: 4,
437 };
438 #[rustfmt::skip]
439 let mut sdes_chunk_bits = Bits::from_static_bytes(&[
440 0x00, 0x00, 0x00, 0x2a,
442 0x01, 0x05, 0x68, 0x65, 0x6c, 0x6c, 0x6f,
444 0x04, 0x2, 0x42, 0x24,
446 0x00,
448 ]);
449
450 let sdes = RtcpSdesPacket::read::<NetworkOrder>(&mut sdes_chunk_bits, (header,))
451 .expect("Successful read");
452 assert_eq!(sdes_chunk_bits.remaining_bytes(), 0);
453 assert_eq!(sdes.chunks.len(), 1);
454 let chunk = &sdes.chunks[0];
455 assert_eq!(chunk.ssrc, 42);
456 assert_eq!(chunk.sdes_items.len(), 2);
457 }
458
459 #[test]
460 fn test_read_sdes_multiple_chunks() {
461 let header = RtcpHeader {
462 version: u2::new(2),
463 has_padding: false,
464 report_count: u5::new(2),
465 packet_type: 202,
466 length_field: 9,
467 };
468 #[rustfmt::skip]
469 let mut sdes_chunks_bits = Bits::from_static_bytes(&[
470 0x00, 0x00, 0x00, 0x2a,
472 0x01, 0x05, 0x68, 0x65, 0x6c, 0x6c, 0x6f,
474 0x04, 0x2, 0x42, 0x24,
476 0x00,
478 0x00, 0x00, 0x00, 0x2b,
480 0x04, 0x4, 0x42, 0x24, 0x42, 0x24,
482 0x01, 0x05, 0x68, 0x65, 0x6c, 0x6c, 0x6f,
484 0x00,
486 0x00, 0x00
488 ]);
489
490 let sdes = RtcpSdesPacket::read::<NetworkOrder>(&mut sdes_chunks_bits, (header,))
491 .expect("Successful read");
492 assert_eq!(sdes_chunks_bits.remaining_bytes(), 0);
493 assert_eq!(sdes.chunks.len(), 2);
494 let chunk = &sdes.chunks[0];
495 assert_eq!(chunk.ssrc, 42);
496 assert_eq!(chunk.sdes_items.len(), 2);
497 let chunk = &sdes.chunks[1];
498 assert_eq!(chunk.ssrc, 43);
499 assert_eq!(chunk.sdes_items.len(), 2);
500 }
501
502 #[test]
503 fn test_sync_rtcp_sdes() {
504 let mut rtcp_sdes = RtcpSdesPacket::default()
505 .add_chunk(SdesChunk::new(42).add_item(SdesItem::cname("hello")))
506 .add_chunk(SdesChunk::new(43).add_item(SdesItem::cname("world")));
507
508 rtcp_sdes.sync(()).expect("successful sync");
509 assert_eq!(rtcp_sdes.header.packet_type, RtcpSdesPacket::PT);
510 assert_eq!(rtcp_sdes.header.report_count, 2);
511 assert_eq!(rtcp_sdes.header.length_field, 6);
519 }
520
521 #[test]
522 fn test_write_rtcp_sdes() {
523 let mut rtcp_sdes = RtcpSdesPacket::default()
524 .add_chunk(SdesChunk::new(42).add_item(SdesItem::cname("hello")))
525 .add_chunk(SdesChunk::new(43).add_item(SdesItem::cname("world")));
526
527 rtcp_sdes.sync(()).expect("successful sync");
528
529 let mut bits_mut = BitsMut::new();
530
531 rtcp_sdes
532 .write::<NetworkOrder>(&mut bits_mut, ())
533 .expect("successful write");
534
535 let mut bits = bits_mut.freeze();
536 let rtcp_header = RtcpHeader::read::<NetworkOrder>(&mut bits, ()).expect("rtcp header");
537 let read_rtcp_sdes = RtcpSdesPacket::read::<NetworkOrder>(&mut bits, (rtcp_header,))
538 .expect("successful read");
539 assert_eq!(read_rtcp_sdes, rtcp_sdes);
540 }
541}