xref: /webrtc/rtcp/src/source_description/mod.rs (revision e56a4863)
1ffe74184SMartin Algesten #[cfg(test)]
2ffe74184SMartin Algesten mod source_description_test;
3ffe74184SMartin Algesten 
4ffe74184SMartin Algesten use crate::{error::Error, header::*, packet::*, util::*};
5ffe74184SMartin Algesten use util::marshal::{Marshal, MarshalSize, Unmarshal};
6ffe74184SMartin Algesten 
7ffe74184SMartin Algesten use bytes::{Buf, BufMut, Bytes};
8ffe74184SMartin Algesten use std::any::Any;
9ffe74184SMartin Algesten use std::fmt;
10ffe74184SMartin Algesten 
11ffe74184SMartin Algesten type Result<T> = std::result::Result<T, util::Error>;
12ffe74184SMartin Algesten 
13ffe74184SMartin Algesten const SDES_SOURCE_LEN: usize = 4;
14ffe74184SMartin Algesten const SDES_TYPE_LEN: usize = 1;
15ffe74184SMartin Algesten const SDES_TYPE_OFFSET: usize = 0;
16ffe74184SMartin Algesten const SDES_OCTET_COUNT_LEN: usize = 1;
17ffe74184SMartin Algesten const SDES_OCTET_COUNT_OFFSET: usize = 1;
18ffe74184SMartin Algesten const SDES_MAX_OCTET_COUNT: usize = (1 << 8) - 1;
19ffe74184SMartin Algesten const SDES_TEXT_OFFSET: usize = 2;
20ffe74184SMartin Algesten 
21ffe74184SMartin Algesten /// SDESType is the item type used in the RTCP SDES control packet.
22ffe74184SMartin Algesten /// RTP SDES item types registered with IANA. See: https://www.iana.org/assignments/rtp-parameters/rtp-parameters.xhtml#rtp-parameters-5
23*97921129Syngrtc #[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
24ffe74184SMartin Algesten #[repr(u8)]
25ffe74184SMartin Algesten pub enum SdesType {
26*97921129Syngrtc     #[default]
27ffe74184SMartin Algesten     SdesEnd = 0, // end of SDES list                RFC 3550, 6.5
28ffe74184SMartin Algesten     SdesCname = 1,    // canonical name                  RFC 3550, 6.5.1
29ffe74184SMartin Algesten     SdesName = 2,     // user name                       RFC 3550, 6.5.2
30ffe74184SMartin Algesten     SdesEmail = 3,    // user's electronic mail address  RFC 3550, 6.5.3
31ffe74184SMartin Algesten     SdesPhone = 4,    // user's phone number             RFC 3550, 6.5.4
32ffe74184SMartin Algesten     SdesLocation = 5, // geographic user location        RFC 3550, 6.5.5
33ffe74184SMartin Algesten     SdesTool = 6,     // name of application or tool     RFC 3550, 6.5.6
34ffe74184SMartin Algesten     SdesNote = 7,     // notice about the source         RFC 3550, 6.5.7
35ffe74184SMartin Algesten     SdesPrivate = 8,  // private extensions              RFC 3550, 6.5.8  (not implemented)
36ffe74184SMartin Algesten }
37ffe74184SMartin Algesten 
38ffe74184SMartin Algesten impl fmt::Display for SdesType {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result39ffe74184SMartin Algesten     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
40ffe74184SMartin Algesten         let s = match self {
41ffe74184SMartin Algesten             SdesType::SdesEnd => "END",
42ffe74184SMartin Algesten             SdesType::SdesCname => "CNAME",
43ffe74184SMartin Algesten             SdesType::SdesName => "NAME",
44ffe74184SMartin Algesten             SdesType::SdesEmail => "EMAIL",
45ffe74184SMartin Algesten             SdesType::SdesPhone => "PHONE",
46ffe74184SMartin Algesten             SdesType::SdesLocation => "LOC",
47ffe74184SMartin Algesten             SdesType::SdesTool => "TOOL",
48ffe74184SMartin Algesten             SdesType::SdesNote => "NOTE",
49ffe74184SMartin Algesten             SdesType::SdesPrivate => "PRIV",
50ffe74184SMartin Algesten         };
515d8fe953SJoão Oliveira         write!(f, "{s}")
52ffe74184SMartin Algesten     }
53ffe74184SMartin Algesten }
54ffe74184SMartin Algesten 
55ffe74184SMartin Algesten impl From<u8> for SdesType {
from(b: u8) -> Self56ffe74184SMartin Algesten     fn from(b: u8) -> Self {
57ffe74184SMartin Algesten         match b {
58ffe74184SMartin Algesten             1 => SdesType::SdesCname,
59ffe74184SMartin Algesten             2 => SdesType::SdesName,
60ffe74184SMartin Algesten             3 => SdesType::SdesEmail,
61ffe74184SMartin Algesten             4 => SdesType::SdesPhone,
62ffe74184SMartin Algesten             5 => SdesType::SdesLocation,
63ffe74184SMartin Algesten             6 => SdesType::SdesTool,
64ffe74184SMartin Algesten             7 => SdesType::SdesNote,
65ffe74184SMartin Algesten             8 => SdesType::SdesPrivate,
66ffe74184SMartin Algesten             _ => SdesType::SdesEnd,
67ffe74184SMartin Algesten         }
68ffe74184SMartin Algesten     }
69ffe74184SMartin Algesten }
70ffe74184SMartin Algesten 
71ffe74184SMartin Algesten /// A SourceDescriptionChunk contains items describing a single RTP source
72ffe74184SMartin Algesten #[derive(Debug, PartialEq, Eq, Default, Clone)]
73ffe74184SMartin Algesten pub struct SourceDescriptionChunk {
74ffe74184SMartin Algesten     /// The source (ssrc) or contributing source (csrc) identifier this packet describes
75ffe74184SMartin Algesten     pub source: u32,
76ffe74184SMartin Algesten     pub items: Vec<SourceDescriptionItem>,
77ffe74184SMartin Algesten }
78ffe74184SMartin Algesten 
79ffe74184SMartin Algesten impl SourceDescriptionChunk {
raw_size(&self) -> usize80ffe74184SMartin Algesten     fn raw_size(&self) -> usize {
81ffe74184SMartin Algesten         let mut len = SDES_SOURCE_LEN;
82ffe74184SMartin Algesten         for it in &self.items {
83ffe74184SMartin Algesten             len += it.marshal_size();
84ffe74184SMartin Algesten         }
85ffe74184SMartin Algesten         len += SDES_TYPE_LEN; // for terminating null octet
86ffe74184SMartin Algesten         len
87ffe74184SMartin Algesten     }
88ffe74184SMartin Algesten }
89ffe74184SMartin Algesten 
90ffe74184SMartin Algesten impl MarshalSize for SourceDescriptionChunk {
marshal_size(&self) -> usize91ffe74184SMartin Algesten     fn marshal_size(&self) -> usize {
92ffe74184SMartin Algesten         let l = self.raw_size();
93ffe74184SMartin Algesten         // align to 32-bit boundary
94ffe74184SMartin Algesten         l + get_padding_size(l)
95ffe74184SMartin Algesten     }
96ffe74184SMartin Algesten }
97ffe74184SMartin Algesten 
98ffe74184SMartin Algesten impl Marshal for SourceDescriptionChunk {
99ffe74184SMartin Algesten     /// Marshal encodes the SourceDescriptionChunk in binary
marshal_to(&self, mut buf: &mut [u8]) -> Result<usize>100ffe74184SMartin Algesten     fn marshal_to(&self, mut buf: &mut [u8]) -> Result<usize> {
101ffe74184SMartin Algesten         if buf.remaining_mut() < self.marshal_size() {
102ffe74184SMartin Algesten             return Err(Error::BufferTooShort.into());
103ffe74184SMartin Algesten         }
104ffe74184SMartin Algesten         /*
105ffe74184SMartin Algesten          *  +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
106ffe74184SMartin Algesten          *  |                          SSRC/CSRC_1                          |
107ffe74184SMartin Algesten          *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
108ffe74184SMartin Algesten          *  |                           SDES items                          |
109ffe74184SMartin Algesten          *  |                              ...                              |
110ffe74184SMartin Algesten          *  +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
111ffe74184SMartin Algesten          */
112ffe74184SMartin Algesten 
113ffe74184SMartin Algesten         buf.put_u32(self.source);
114ffe74184SMartin Algesten 
115ffe74184SMartin Algesten         for it in &self.items {
116ffe74184SMartin Algesten             let n = it.marshal_to(buf)?;
117ffe74184SMartin Algesten             buf = &mut buf[n..];
118ffe74184SMartin Algesten         }
119ffe74184SMartin Algesten 
120ffe74184SMartin Algesten         // The list of items in each chunk MUST be terminated by one or more null octets
121ffe74184SMartin Algesten         buf.put_u8(SdesType::SdesEnd as u8);
122ffe74184SMartin Algesten 
123ffe74184SMartin Algesten         // additional null octets MUST be included if needed to pad until the next 32-bit boundary
124ffe74184SMartin Algesten         put_padding(buf, self.raw_size());
125ffe74184SMartin Algesten         Ok(self.marshal_size())
126ffe74184SMartin Algesten     }
127ffe74184SMartin Algesten }
128ffe74184SMartin Algesten 
129ffe74184SMartin Algesten impl Unmarshal for SourceDescriptionChunk {
130ffe74184SMartin Algesten     /// Unmarshal decodes the SourceDescriptionChunk from binary
unmarshal<B>(raw_packet: &mut B) -> Result<Self> where Self: Sized, B: Buf,131ffe74184SMartin Algesten     fn unmarshal<B>(raw_packet: &mut B) -> Result<Self>
132ffe74184SMartin Algesten     where
133ffe74184SMartin Algesten         Self: Sized,
134ffe74184SMartin Algesten         B: Buf,
135ffe74184SMartin Algesten     {
136ffe74184SMartin Algesten         /*
137ffe74184SMartin Algesten          *  +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
138ffe74184SMartin Algesten          *  |                          SSRC/CSRC_1                          |
139ffe74184SMartin Algesten          *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
140ffe74184SMartin Algesten          *  |                           SDES items                          |
141ffe74184SMartin Algesten          *  |                              ...                              |
142ffe74184SMartin Algesten          *  +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
143ffe74184SMartin Algesten          */
144ffe74184SMartin Algesten         let raw_packet_len = raw_packet.remaining();
145ffe74184SMartin Algesten         if raw_packet_len < (SDES_SOURCE_LEN + SDES_TYPE_LEN) {
146ffe74184SMartin Algesten             return Err(Error::PacketTooShort.into());
147ffe74184SMartin Algesten         }
148ffe74184SMartin Algesten 
149ffe74184SMartin Algesten         let source = raw_packet.get_u32();
150ffe74184SMartin Algesten 
151ffe74184SMartin Algesten         let mut offset = SDES_SOURCE_LEN;
152ffe74184SMartin Algesten         let mut items = vec![];
153ffe74184SMartin Algesten         while offset < raw_packet_len {
154ffe74184SMartin Algesten             let item = SourceDescriptionItem::unmarshal(raw_packet)?;
155ffe74184SMartin Algesten             if item.sdes_type == SdesType::SdesEnd {
156ffe74184SMartin Algesten                 // offset + 1 (one byte for SdesEnd)
157ffe74184SMartin Algesten                 let padding_len = get_padding_size(offset + 1);
158ffe74184SMartin Algesten                 if raw_packet.remaining() >= padding_len {
159ffe74184SMartin Algesten                     raw_packet.advance(padding_len);
160ffe74184SMartin Algesten                     return Ok(SourceDescriptionChunk { source, items });
161ffe74184SMartin Algesten                 } else {
162ffe74184SMartin Algesten                     return Err(Error::PacketTooShort.into());
163ffe74184SMartin Algesten                 }
164ffe74184SMartin Algesten             }
165ffe74184SMartin Algesten             offset += item.marshal_size();
166ffe74184SMartin Algesten             items.push(item);
167ffe74184SMartin Algesten         }
168ffe74184SMartin Algesten 
169ffe74184SMartin Algesten         Err(Error::PacketTooShort.into())
170ffe74184SMartin Algesten     }
171ffe74184SMartin Algesten }
172ffe74184SMartin Algesten 
173ffe74184SMartin Algesten /// A SourceDescriptionItem is a part of a SourceDescription that describes a stream.
174ffe74184SMartin Algesten #[derive(Debug, PartialEq, Eq, Default, Clone)]
175ffe74184SMartin Algesten pub struct SourceDescriptionItem {
176ffe74184SMartin Algesten     /// The type identifier for this item. eg, SDESCNAME for canonical name description.
177ffe74184SMartin Algesten     ///
178ffe74184SMartin Algesten     /// Type zero or SDESEnd is interpreted as the end of an item list and cannot be used.
179ffe74184SMartin Algesten     pub sdes_type: SdesType,
180ffe74184SMartin Algesten     /// Text is a unicode text blob associated with the item. Its meaning varies based on the item's Type.
181ffe74184SMartin Algesten     pub text: Bytes,
182ffe74184SMartin Algesten }
183ffe74184SMartin Algesten 
184ffe74184SMartin Algesten impl MarshalSize for SourceDescriptionItem {
marshal_size(&self) -> usize185ffe74184SMartin Algesten     fn marshal_size(&self) -> usize {
186ffe74184SMartin Algesten         /*
187ffe74184SMartin Algesten          *   0                   1                   2                   3
188ffe74184SMartin Algesten          *   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
189ffe74184SMartin Algesten          *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
190ffe74184SMartin Algesten          *  |    CNAME=1    |     length    | user and domain name        ...
191ffe74184SMartin Algesten          *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
192ffe74184SMartin Algesten          */
193ffe74184SMartin Algesten         SDES_TYPE_LEN + SDES_OCTET_COUNT_LEN + self.text.len()
194ffe74184SMartin Algesten     }
195ffe74184SMartin Algesten }
196ffe74184SMartin Algesten 
197ffe74184SMartin Algesten impl Marshal for SourceDescriptionItem {
198ffe74184SMartin Algesten     /// Marshal encodes the SourceDescriptionItem in binary
marshal_to(&self, mut buf: &mut [u8]) -> Result<usize>199ffe74184SMartin Algesten     fn marshal_to(&self, mut buf: &mut [u8]) -> Result<usize> {
200ffe74184SMartin Algesten         /*
201ffe74184SMartin Algesten          *   0                   1                   2                   3
202ffe74184SMartin Algesten          *   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
203ffe74184SMartin Algesten          *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
204ffe74184SMartin Algesten          *  |    CNAME=1    |     length    | user and domain name        ...
205ffe74184SMartin Algesten          *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
206ffe74184SMartin Algesten          */
207ffe74184SMartin Algesten 
208ffe74184SMartin Algesten         if self.sdes_type == SdesType::SdesEnd {
209ffe74184SMartin Algesten             return Err(Error::SdesMissingType.into());
210ffe74184SMartin Algesten         }
211ffe74184SMartin Algesten 
212ffe74184SMartin Algesten         if buf.remaining_mut() < self.marshal_size() {
213ffe74184SMartin Algesten             return Err(Error::BufferTooShort.into());
214ffe74184SMartin Algesten         }
215ffe74184SMartin Algesten 
216ffe74184SMartin Algesten         buf.put_u8(self.sdes_type as u8);
217ffe74184SMartin Algesten 
218ffe74184SMartin Algesten         if self.text.len() > SDES_MAX_OCTET_COUNT {
219ffe74184SMartin Algesten             return Err(Error::SdesTextTooLong.into());
220ffe74184SMartin Algesten         }
221ffe74184SMartin Algesten         buf.put_u8(self.text.len() as u8);
222ffe74184SMartin Algesten         buf.put(self.text.clone());
223ffe74184SMartin Algesten 
224ffe74184SMartin Algesten         //no padding for each SourceDescriptionItem
225ffe74184SMartin Algesten         Ok(self.marshal_size())
226ffe74184SMartin Algesten     }
227ffe74184SMartin Algesten }
228ffe74184SMartin Algesten 
229ffe74184SMartin Algesten impl Unmarshal for SourceDescriptionItem {
230ffe74184SMartin Algesten     /// Unmarshal decodes the SourceDescriptionItem from binary
unmarshal<B>(raw_packet: &mut B) -> Result<Self> where Self: Sized, B: Buf,231ffe74184SMartin Algesten     fn unmarshal<B>(raw_packet: &mut B) -> Result<Self>
232ffe74184SMartin Algesten     where
233ffe74184SMartin Algesten         Self: Sized,
234ffe74184SMartin Algesten         B: Buf,
235ffe74184SMartin Algesten     {
236ffe74184SMartin Algesten         /*
237ffe74184SMartin Algesten          *   0                   1                   2                   3
238ffe74184SMartin Algesten          *   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
239ffe74184SMartin Algesten          *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
240ffe74184SMartin Algesten          *  |    CNAME=1    |     length    | user and domain name        ...
241ffe74184SMartin Algesten          *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
242ffe74184SMartin Algesten          */
243ffe74184SMartin Algesten         let raw_packet_len = raw_packet.remaining();
244ffe74184SMartin Algesten         if raw_packet_len < SDES_TYPE_LEN {
245ffe74184SMartin Algesten             return Err(Error::PacketTooShort.into());
246ffe74184SMartin Algesten         }
247ffe74184SMartin Algesten 
248ffe74184SMartin Algesten         let sdes_type = SdesType::from(raw_packet.get_u8());
249ffe74184SMartin Algesten         if sdes_type == SdesType::SdesEnd {
250ffe74184SMartin Algesten             return Ok(SourceDescriptionItem {
251ffe74184SMartin Algesten                 sdes_type,
252ffe74184SMartin Algesten                 text: Bytes::new(),
253ffe74184SMartin Algesten             });
254ffe74184SMartin Algesten         }
255ffe74184SMartin Algesten 
256ffe74184SMartin Algesten         if raw_packet_len < (SDES_TYPE_LEN + SDES_OCTET_COUNT_LEN) {
257ffe74184SMartin Algesten             return Err(Error::PacketTooShort.into());
258ffe74184SMartin Algesten         }
259ffe74184SMartin Algesten 
260ffe74184SMartin Algesten         let octet_count = raw_packet.get_u8() as usize;
261ffe74184SMartin Algesten         if SDES_TEXT_OFFSET + octet_count > raw_packet_len {
262ffe74184SMartin Algesten             return Err(Error::PacketTooShort.into());
263ffe74184SMartin Algesten         }
264ffe74184SMartin Algesten 
265ffe74184SMartin Algesten         let text = raw_packet.copy_to_bytes(octet_count);
266ffe74184SMartin Algesten 
267ffe74184SMartin Algesten         Ok(SourceDescriptionItem { sdes_type, text })
268ffe74184SMartin Algesten     }
269ffe74184SMartin Algesten }
270ffe74184SMartin Algesten 
271ffe74184SMartin Algesten /// A SourceDescription (SDES) packet describes the sources in an RTP stream.
272ffe74184SMartin Algesten #[derive(Debug, Default, PartialEq, Eq, Clone)]
273ffe74184SMartin Algesten pub struct SourceDescription {
274ffe74184SMartin Algesten     pub chunks: Vec<SourceDescriptionChunk>,
275ffe74184SMartin Algesten }
276ffe74184SMartin Algesten 
277ffe74184SMartin Algesten impl fmt::Display for SourceDescription {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result278ffe74184SMartin Algesten     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
279ffe74184SMartin Algesten         let mut out = "Source Description:\n".to_string();
280ffe74184SMartin Algesten         for c in &self.chunks {
281ffe74184SMartin Algesten             out += format!("\t{:x}\n", c.source).as_str();
282ffe74184SMartin Algesten             for it in &c.items {
2835d8fe953SJoão Oliveira                 out += format!("\t\t{it:?}\n").as_str();
284ffe74184SMartin Algesten             }
285ffe74184SMartin Algesten         }
2865d8fe953SJoão Oliveira         write!(f, "{out}")
287ffe74184SMartin Algesten     }
288ffe74184SMartin Algesten }
289ffe74184SMartin Algesten 
290ffe74184SMartin Algesten impl Packet for SourceDescription {
291ffe74184SMartin Algesten     /// Header returns the Header associated with this packet.
header(&self) -> Header292ffe74184SMartin Algesten     fn header(&self) -> Header {
293ffe74184SMartin Algesten         Header {
294ffe74184SMartin Algesten             padding: get_padding_size(self.raw_size()) != 0,
295ffe74184SMartin Algesten             count: self.chunks.len() as u8,
296ffe74184SMartin Algesten             packet_type: PacketType::SourceDescription,
297ffe74184SMartin Algesten             length: ((self.marshal_size() / 4) - 1) as u16,
298ffe74184SMartin Algesten         }
299ffe74184SMartin Algesten     }
300ffe74184SMartin Algesten 
301ffe74184SMartin Algesten     /// destination_ssrc returns an array of SSRC values that this packet refers to.
destination_ssrc(&self) -> Vec<u32>302ffe74184SMartin Algesten     fn destination_ssrc(&self) -> Vec<u32> {
303ffe74184SMartin Algesten         self.chunks.iter().map(|x| x.source).collect()
304ffe74184SMartin Algesten     }
305ffe74184SMartin Algesten 
raw_size(&self) -> usize306ffe74184SMartin Algesten     fn raw_size(&self) -> usize {
307ffe74184SMartin Algesten         let mut chunks_length = 0;
308ffe74184SMartin Algesten         for c in &self.chunks {
309ffe74184SMartin Algesten             chunks_length += c.marshal_size();
310ffe74184SMartin Algesten         }
311ffe74184SMartin Algesten 
312ffe74184SMartin Algesten         HEADER_LENGTH + chunks_length
313ffe74184SMartin Algesten     }
314ffe74184SMartin Algesten 
as_any(&self) -> &(dyn Any + Send + Sync)315ffe74184SMartin Algesten     fn as_any(&self) -> &(dyn Any + Send + Sync) {
316ffe74184SMartin Algesten         self
317ffe74184SMartin Algesten     }
318ffe74184SMartin Algesten 
equal(&self, other: &(dyn Packet + Send + Sync)) -> bool319ffe74184SMartin Algesten     fn equal(&self, other: &(dyn Packet + Send + Sync)) -> bool {
320ffe74184SMartin Algesten         other
321ffe74184SMartin Algesten             .as_any()
322ffe74184SMartin Algesten             .downcast_ref::<SourceDescription>()
323ffe74184SMartin Algesten             .map_or(false, |a| self == a)
324ffe74184SMartin Algesten     }
325ffe74184SMartin Algesten 
cloned(&self) -> Box<dyn Packet + Send + Sync>326ffe74184SMartin Algesten     fn cloned(&self) -> Box<dyn Packet + Send + Sync> {
327ffe74184SMartin Algesten         Box::new(self.clone())
328ffe74184SMartin Algesten     }
329ffe74184SMartin Algesten }
330ffe74184SMartin Algesten 
331ffe74184SMartin Algesten impl MarshalSize for SourceDescription {
marshal_size(&self) -> usize332ffe74184SMartin Algesten     fn marshal_size(&self) -> usize {
333ffe74184SMartin Algesten         let l = self.raw_size();
334ffe74184SMartin Algesten         // align to 32-bit boundary
335ffe74184SMartin Algesten         l + get_padding_size(l)
336ffe74184SMartin Algesten     }
337ffe74184SMartin Algesten }
338ffe74184SMartin Algesten 
339ffe74184SMartin Algesten impl Marshal for SourceDescription {
340ffe74184SMartin Algesten     /// Marshal encodes the SourceDescription in binary
marshal_to(&self, mut buf: &mut [u8]) -> Result<usize>341ffe74184SMartin Algesten     fn marshal_to(&self, mut buf: &mut [u8]) -> Result<usize> {
342ffe74184SMartin Algesten         if self.chunks.len() > COUNT_MAX {
343ffe74184SMartin Algesten             return Err(Error::TooManyChunks.into());
344ffe74184SMartin Algesten         }
345ffe74184SMartin Algesten 
346ffe74184SMartin Algesten         if buf.remaining_mut() < self.marshal_size() {
347ffe74184SMartin Algesten             return Err(Error::BufferTooShort.into());
348ffe74184SMartin Algesten         }
349ffe74184SMartin Algesten 
350ffe74184SMartin Algesten         /*
351ffe74184SMartin Algesten          *         0                   1                   2                   3
352ffe74184SMartin Algesten          *         0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
353ffe74184SMartin Algesten          *        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
354ffe74184SMartin Algesten          * header |V=2|P|    SC   |  PT=SDES=202  |             length            |
355ffe74184SMartin Algesten          *        +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
356ffe74184SMartin Algesten          * chunk  |                          SSRC/CSRC_1                          |
357ffe74184SMartin Algesten          *   1    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
358ffe74184SMartin Algesten          *        |                           SDES items                          |
359ffe74184SMartin Algesten          *        |                              ...                              |
360ffe74184SMartin Algesten          *        +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
361ffe74184SMartin Algesten          * chunk  |                          SSRC/CSRC_2                          |
362ffe74184SMartin Algesten          *   2    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
363ffe74184SMartin Algesten          *        |                           SDES items                          |
364ffe74184SMartin Algesten          *        |                              ...                              |
365ffe74184SMartin Algesten          *        +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
366ffe74184SMartin Algesten          */
367ffe74184SMartin Algesten 
368ffe74184SMartin Algesten         let h = self.header();
369ffe74184SMartin Algesten         let n = h.marshal_to(buf)?;
370ffe74184SMartin Algesten         buf = &mut buf[n..];
371ffe74184SMartin Algesten 
372ffe74184SMartin Algesten         for c in &self.chunks {
373ffe74184SMartin Algesten             let n = c.marshal_to(buf)?;
374ffe74184SMartin Algesten             buf = &mut buf[n..];
375ffe74184SMartin Algesten         }
376ffe74184SMartin Algesten 
377ffe74184SMartin Algesten         if h.padding {
378ffe74184SMartin Algesten             put_padding(buf, self.raw_size());
379ffe74184SMartin Algesten         }
380ffe74184SMartin Algesten 
381ffe74184SMartin Algesten         Ok(self.marshal_size())
382ffe74184SMartin Algesten     }
383ffe74184SMartin Algesten }
384ffe74184SMartin Algesten 
385ffe74184SMartin Algesten impl Unmarshal for SourceDescription {
386ffe74184SMartin Algesten     /// Unmarshal decodes the SourceDescription from binary
unmarshal<B>(raw_packet: &mut B) -> Result<Self> where Self: Sized, B: Buf,387ffe74184SMartin Algesten     fn unmarshal<B>(raw_packet: &mut B) -> Result<Self>
388ffe74184SMartin Algesten     where
389ffe74184SMartin Algesten         Self: Sized,
390ffe74184SMartin Algesten         B: Buf,
391ffe74184SMartin Algesten     {
392ffe74184SMartin Algesten         /*
393ffe74184SMartin Algesten          *         0                   1                   2                   3
394ffe74184SMartin Algesten          *         0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
395ffe74184SMartin Algesten          *        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
396ffe74184SMartin Algesten          * header |V=2|P|    SC   |  PT=SDES=202  |             length            |
397ffe74184SMartin Algesten          *        +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
398ffe74184SMartin Algesten          * chunk  |                          SSRC/CSRC_1                          |
399ffe74184SMartin Algesten          *   1    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
400ffe74184SMartin Algesten          *        |                           SDES items                          |
401ffe74184SMartin Algesten          *        |                              ...                              |
402ffe74184SMartin Algesten          *        +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
403ffe74184SMartin Algesten          * chunk  |                          SSRC/CSRC_2                          |
404ffe74184SMartin Algesten          *   2    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
405ffe74184SMartin Algesten          *        |                           SDES items                          |
406ffe74184SMartin Algesten          *        |                              ...                              |
407ffe74184SMartin Algesten          *        +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
408ffe74184SMartin Algesten          */
409ffe74184SMartin Algesten         let raw_packet_len = raw_packet.remaining();
410ffe74184SMartin Algesten 
411ffe74184SMartin Algesten         let h = Header::unmarshal(raw_packet)?;
412ffe74184SMartin Algesten         if h.packet_type != PacketType::SourceDescription {
413ffe74184SMartin Algesten             return Err(Error::WrongType.into());
414ffe74184SMartin Algesten         }
415ffe74184SMartin Algesten 
416ffe74184SMartin Algesten         let mut offset = HEADER_LENGTH;
417ffe74184SMartin Algesten         let mut chunks = vec![];
418ffe74184SMartin Algesten         while offset < raw_packet_len {
419ffe74184SMartin Algesten             let chunk = SourceDescriptionChunk::unmarshal(raw_packet)?;
420ffe74184SMartin Algesten             offset += chunk.marshal_size();
421ffe74184SMartin Algesten             chunks.push(chunk);
422ffe74184SMartin Algesten         }
423ffe74184SMartin Algesten 
424ffe74184SMartin Algesten         if chunks.len() != h.count as usize {
425ffe74184SMartin Algesten             return Err(Error::InvalidHeader.into());
426ffe74184SMartin Algesten         }
427ffe74184SMartin Algesten 
428ffe74184SMartin Algesten         if
429ffe74184SMartin Algesten         /*h.padding &&*/
430ffe74184SMartin Algesten         raw_packet.has_remaining() {
431ffe74184SMartin Algesten             raw_packet.advance(raw_packet.remaining());
432ffe74184SMartin Algesten         }
433ffe74184SMartin Algesten 
434ffe74184SMartin Algesten         Ok(SourceDescription { chunks })
435ffe74184SMartin Algesten     }
436ffe74184SMartin Algesten }
437