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