jingle_rtp.rs

  1// Copyright (c) 2019-2020 Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
  2//
  3// This Source Code Form is subject to the terms of the Mozilla Public
  4// License, v. 2.0. If a copy of the MPL was not distributed with this
  5// file, You can obtain one at http://mozilla.org/MPL/2.0/.
  6
  7use xso::{AsXml, FromXml};
  8
  9use crate::jingle_rtcp_fb::RtcpFb;
 10use crate::jingle_rtp_hdrext::RtpHdrext;
 11use crate::jingle_ssma::{Group, Source};
 12use crate::ns;
 13
 14/// Specifies the ability to multiplex RTP Data and Control Packets on a single port as
 15/// described in RFC 5761.
 16#[derive(FromXml, AsXml, PartialEq, Debug, Clone)]
 17#[xml(namespace = ns::JINGLE_RTP, name = "rtcp-mux")]
 18pub struct RtcpMux;
 19
 20/// Wrapper element describing an RTP session.
 21#[derive(FromXml, AsXml, PartialEq, Debug, Clone)]
 22#[xml(namespace = ns::JINGLE_RTP, name = "description")]
 23pub struct Description {
 24    /// Specifies the media type, such as "audio" or "video", where the media type SHOULD be as
 25    /// registered at IANA MIME Media Types Registry.
 26    #[xml(attribute)]
 27    pub media: String,
 28
 29    /// 32-bit synchronization source for this media stream, as defined in RFC 3550.
 30    #[xml(attribute(default))]
 31    pub ssrc: Option<u32>,
 32
 33    /// List of encodings that can be used for this RTP stream.
 34    #[xml(child(n = ..))]
 35    pub payload_types: Vec<PayloadType>,
 36
 37    /// Specifies the ability to multiplex RTP Data and Control Packets on a single port as
 38    /// described in RFC 5761.
 39    #[xml(child(default))]
 40    pub rtcp_mux: Option<RtcpMux>,
 41
 42    /// List of ssrc-group.
 43    #[xml(child(n = ..))]
 44    pub ssrc_groups: Vec<Group>,
 45
 46    /// List of ssrc.
 47    #[xml(child(n = ..))]
 48    pub ssrcs: Vec<Source>,
 49
 50    /// List of header extensions.
 51    #[xml(child(n = ..))]
 52    pub hdrexts: Vec<RtpHdrext>,
 53    // TODO: Add support for <encryption/> and <bandwidth/>.
 54}
 55
 56impl Description {
 57    /// Create a new RTP description.
 58    pub fn new(media: String) -> Description {
 59        Description {
 60            media,
 61            ssrc: None,
 62            payload_types: Vec::new(),
 63            rtcp_mux: None,
 64            ssrc_groups: Vec::new(),
 65            ssrcs: Vec::new(),
 66            hdrexts: Vec::new(),
 67        }
 68    }
 69}
 70
 71generate_attribute!(
 72    /// The number of channels.
 73    Channels,
 74    "channels",
 75    u8,
 76    Default = 1
 77);
 78
 79/// An encoding that can be used for an RTP stream.
 80#[derive(FromXml, AsXml, PartialEq, Debug, Clone)]
 81#[xml(namespace = ns::JINGLE_RTP, name = "payload-type")]
 82pub struct PayloadType {
 83    /// The number of channels.
 84    #[xml(attribute(default))]
 85    pub channels: Channels,
 86
 87    /// The sampling frequency in Hertz.
 88    #[xml(attribute(default))]
 89    pub clockrate: Option<u32>,
 90
 91    /// The payload identifier.
 92    #[xml(attribute)]
 93    pub id: u8,
 94
 95    /// Maximum packet time as specified in RFC 4566.
 96    #[xml(attribute(default))]
 97    pub maxptime: Option<u32>,
 98
 99    /// The appropriate subtype of the MIME type.
100    #[xml(attribute(default))]
101    pub name: Option<String>,
102
103    /// Packet time as specified in RFC 4566.
104    #[xml(attribute(default))]
105    pub ptime: Option<u32>,
106
107    /// List of parameters specifying this payload-type.
108    ///
109    /// Their order MUST be ignored.
110    #[xml(child(n = ..))]
111    pub parameters: Vec<Parameter>,
112
113    /// List of rtcp-fb parameters from XEP-0293.
114    #[xml(child(n = ..))]
115    pub rtcp_fbs: Vec<RtcpFb>,
116}
117
118impl PayloadType {
119    /// Create a new RTP payload-type.
120    pub fn new(id: u8, name: String, clockrate: u32, channels: u8) -> PayloadType {
121        PayloadType {
122            channels: Channels(channels),
123            clockrate: Some(clockrate),
124            id,
125            maxptime: None,
126            name: Some(name),
127            ptime: None,
128            parameters: Vec::new(),
129            rtcp_fbs: Vec::new(),
130        }
131    }
132
133    /// Create a new RTP payload-type without a clockrate.  Warning: this is invalid as per
134    /// RFC 4566!
135    pub fn without_clockrate(id: u8, name: String) -> PayloadType {
136        PayloadType {
137            channels: Default::default(),
138            clockrate: None,
139            id,
140            maxptime: None,
141            name: Some(name),
142            ptime: None,
143            parameters: Vec::new(),
144            rtcp_fbs: Vec::new(),
145        }
146    }
147}
148
149/// Parameter related to a payload.
150#[derive(FromXml, AsXml, PartialEq, Debug, Clone)]
151#[xml(namespace = ns::JINGLE_RTP, name = "parameter")]
152pub struct Parameter {
153    /// The name of the parameter, from the list at
154    /// <https://www.iana.org/assignments/sdp-parameters/sdp-parameters.xhtml>
155    #[xml(attribute)]
156    pub name: String,
157
158    /// The value of this parameter.
159    #[xml(attribute)]
160    pub value: String,
161}
162
163#[cfg(test)]
164mod tests {
165    use super::*;
166    use minidom::Element;
167
168    #[cfg(target_pointer_width = "32")]
169    #[test]
170    fn test_size() {
171        assert_size!(Description, 72);
172        assert_size!(Channels, 1);
173        assert_size!(PayloadType, 64);
174        assert_size!(Parameter, 24);
175    }
176
177    #[cfg(target_pointer_width = "64")]
178    #[test]
179    fn test_size() {
180        assert_size!(Description, 136);
181        assert_size!(Channels, 1);
182        assert_size!(PayloadType, 104);
183        assert_size!(Parameter, 48);
184    }
185
186    #[test]
187    fn test_simple() {
188        let elem: Element = "<description xmlns='urn:xmpp:jingle:apps:rtp:1' media='audio'>
189    <payload-type xmlns='urn:xmpp:jingle:apps:rtp:1' channels='2' clockrate='48000' id='96' name='OPUS'/>
190    <payload-type xmlns='urn:xmpp:jingle:apps:rtp:1' channels='1' clockrate='32000' id='105' name='SPEEX'/>
191    <payload-type xmlns='urn:xmpp:jingle:apps:rtp:1' channels='1' clockrate='8000' id='9' name='G722'/>
192    <payload-type xmlns='urn:xmpp:jingle:apps:rtp:1' channels='1' clockrate='16000' id='106' name='SPEEX'/>
193    <payload-type xmlns='urn:xmpp:jingle:apps:rtp:1' clockrate='8000' id='8' name='PCMA'/>
194    <payload-type xmlns='urn:xmpp:jingle:apps:rtp:1' clockrate='8000' id='0' name='PCMU'/>
195    <payload-type xmlns='urn:xmpp:jingle:apps:rtp:1' channels='1' clockrate='8000' id='107' name='SPEEX'/>
196    <payload-type xmlns='urn:xmpp:jingle:apps:rtp:1' channels='1' clockrate='8000' id='99' name='AMR'>
197        <parameter xmlns='urn:xmpp:jingle:apps:rtp:1' name='octet-align' value='1'/>
198        <parameter xmlns='urn:xmpp:jingle:apps:rtp:1' name='crc' value='0'/>
199        <parameter xmlns='urn:xmpp:jingle:apps:rtp:1' name='robust-sorting' value='0'/>
200        <parameter xmlns='urn:xmpp:jingle:apps:rtp:1' name='interleaving' value='0'/>
201    </payload-type>
202    <payload-type xmlns='urn:xmpp:jingle:apps:rtp:1' clockrate='48000' id='100' name='telephone-event'>
203        <parameter xmlns='urn:xmpp:jingle:apps:rtp:1' name='events' value='0-15'/>
204    </payload-type>
205    <payload-type xmlns='urn:xmpp:jingle:apps:rtp:1' clockrate='16000' id='101' name='telephone-event'>
206        <parameter xmlns='urn:xmpp:jingle:apps:rtp:1' name='events' value='0-15'/>
207    </payload-type>
208    <payload-type xmlns='urn:xmpp:jingle:apps:rtp:1' clockrate='8000' id='102' name='telephone-event'>
209        <parameter xmlns='urn:xmpp:jingle:apps:rtp:1' name='events' value='0-15'/>
210    </payload-type>
211</description>"
212                .parse()
213                .unwrap();
214        let desc = Description::try_from(elem).unwrap();
215        assert_eq!(desc.media, "audio");
216        assert_eq!(desc.ssrc, None);
217    }
218}