// Copyright (c) 2019-2020 Emmanuel Gil Peyrot // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. use xso::{FromXml, IntoXml}; use crate::jingle_rtcp_fb::RtcpFb; use crate::jingle_rtp_hdrext::RtpHdrext; use crate::jingle_ssma::{Group, Source}; use crate::ns; /// Specifies the ability to multiplex RTP Data and Control Packets on a single port as /// described in RFC 5761. #[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] #[xml(namespace = ns::JINGLE_RTP, name = "rtcp-mux")] pub struct RtcpMux; generate_element!( /// Wrapper element describing an RTP session. Description, "description", JINGLE_RTP, attributes: [ /// Namespace of the encryption scheme used. media: Required = "media", /// User-friendly name for the encryption scheme, should be `None` for OTR, /// legacy OpenPGP and OX. // XXX: is this a String or an u32?! Refer to RFC 3550. ssrc: Option = "ssrc", ], children: [ /// List of encodings that can be used for this RTP stream. payload_types: Vec = ("payload-type", JINGLE_RTP) => PayloadType, /// Specifies the ability to multiplex RTP Data and Control Packets on a single port as /// described in RFC 5761. rtcp_mux: Option = ("rtcp-mux", JINGLE_RTP) => RtcpMux, /// List of ssrc-group. ssrc_groups: Vec = ("ssrc-group", JINGLE_SSMA) => Group, /// List of ssrc. ssrcs: Vec = ("source", JINGLE_SSMA) => Source, /// List of header extensions. hdrexts: Vec = ("rtp-hdrext", JINGLE_RTP_HDREXT) => RtpHdrext // TODO: Add support for and . ] ); impl Description { /// Create a new RTP description. pub fn new(media: String) -> Description { Description { media, ssrc: None, payload_types: Vec::new(), rtcp_mux: None, ssrc_groups: Vec::new(), ssrcs: Vec::new(), hdrexts: Vec::new(), } } } generate_attribute!( /// The number of channels. Channels, "channels", u8, Default = 1 ); generate_element!( /// An encoding that can be used for an RTP stream. PayloadType, "payload-type", JINGLE_RTP, attributes: [ /// The number of channels. channels: Default = "channels", /// The sampling frequency in Hertz. clockrate: Option = "clockrate", /// The payload identifier. id: Required = "id", /// Maximum packet time as specified in RFC 4566. maxptime: Option = "maxptime", /// The appropriate subtype of the MIME type. name: Option = "name", /// Packet time as specified in RFC 4566. ptime: Option = "ptime", ], children: [ /// List of parameters specifying this payload-type. /// /// Their order MUST be ignored. parameters: Vec = ("parameter", JINGLE_RTP) => Parameter, /// List of rtcp-fb parameters from XEP-0293. rtcp_fbs: Vec = ("rtcp-fb", JINGLE_RTCP_FB) => RtcpFb ] ); impl PayloadType { /// Create a new RTP payload-type. pub fn new(id: u8, name: String, clockrate: u32, channels: u8) -> PayloadType { PayloadType { channels: Channels(channels), clockrate: Some(clockrate), id, maxptime: None, name: Some(name), ptime: None, parameters: Vec::new(), rtcp_fbs: Vec::new(), } } /// Create a new RTP payload-type without a clockrate. Warning: this is invalid as per /// RFC 4566! pub fn without_clockrate(id: u8, name: String) -> PayloadType { PayloadType { channels: Default::default(), clockrate: None, id, maxptime: None, name: Some(name), ptime: None, parameters: Vec::new(), rtcp_fbs: Vec::new(), } } } generate_element!( /// Parameter related to a payload. Parameter, "parameter", JINGLE_RTP, attributes: [ /// The name of the parameter, from the list at /// name: Required = "name", /// The value of this parameter. value: Required = "value", ] ); #[cfg(test)] mod tests { use super::*; use crate::Element; #[cfg(target_pointer_width = "32")] #[test] fn test_size() { assert_size!(Description, 76); assert_size!(Channels, 1); assert_size!(PayloadType, 64); assert_size!(Parameter, 24); } #[cfg(target_pointer_width = "64")] #[test] fn test_size() { assert_size!(Description, 152); assert_size!(Channels, 1); assert_size!(PayloadType, 104); assert_size!(Parameter, 48); } #[test] fn test_simple() { let elem: Element = " " .parse() .unwrap(); let desc = Description::try_from(elem).unwrap(); assert_eq!(desc.media, "audio"); assert_eq!(desc.ssrc, None); } }