Skip to main content

xmpp_parsers/
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
14generate_attribute!(
15    /// Value for the SDP "bwtype" parameter as listed in the IANA Session Description Protocol
16    /// Parameters Registry: <https://www.iana.org/assignments/sdp-parameters/sdp-parameters.xhtml>
17    ///
18    /// See RFC8859.
19    BwType, "type", {
20        /// Not impacted.
21        Ct => "CT",
22
23        /// For media-level usage, the aggregate of individual bandwidth values is considered.
24        As => "AS",
25
26        /// Session-level usage represents session aggregate, and media-level usage indicates SUM
27        /// of the individual values while multiplexing.
28        Rs => "RS",
29
30        /// Session-level usage represents session aggregate, and media-level usage indicates SUM
31        /// of the individual values while multiplexing.
32        Rr => "RR",
33
34        /// Transport Independent Application Specific Maximum (TIAS) bandwidth modifier that does
35        /// not include transport overhead.
36        Tias => "TIAS",
37    }
38);
39
40/// Allowable or preferred bandwidth for use by this application type.
41#[derive(FromXml, AsXml, PartialEq, Debug, Clone)]
42#[xml(namespace = ns::JINGLE_RTP, name = "description")]
43pub struct Bandwidth {
44    /// Value for the SDP "bwtype" parameter as listed in the IANA Session Description Protocol
45    /// Parameters Registry: <https://www.iana.org/assignments/sdp-parameters/sdp-parameters.xhtml>
46    #[xml(attribute)]
47    type_: BwType,
48
49    #[xml(text)]
50    value: u32,
51}
52
53/// Wrapper element describing an RTP session.
54#[derive(FromXml, AsXml, PartialEq, Debug, Clone)]
55#[xml(namespace = ns::JINGLE_RTP, name = "description")]
56pub struct Description {
57    /// Specifies the media type, such as "audio" or "video", where the media type SHOULD be as
58    /// registered at IANA MIME Media Types Registry.
59    #[xml(attribute)]
60    pub media: String,
61
62    /// 32-bit synchronization source for this media stream, as defined in RFC 3550.
63    #[xml(attribute(default))]
64    pub ssrc: Option<u32>,
65
66    /// List of encodings that can be used for this RTP stream.
67    #[xml(child(n = ..))]
68    pub payload_types: Vec<PayloadType>,
69
70    /// Specifies the ability to multiplex RTP Data and Control Packets on a single port as
71    /// described in RFC 5761.
72    #[xml(flag(name = "rtcp-mux"))]
73    pub rtcp_mux: bool,
74
75    /// List of ssrc-group.
76    #[xml(child(n = ..))]
77    pub ssrc_groups: Vec<Group>,
78
79    /// List of ssrc.
80    #[xml(child(n = ..))]
81    pub ssrcs: Vec<Source>,
82
83    /// List of header extensions.
84    #[xml(child(n = ..))]
85    pub hdrexts: Vec<RtpHdrext>,
86
87    /// Allowable or preferred bandwidth for use by this application type.
88    #[xml(child(default))]
89    pub bandwidth: Option<Bandwidth>,
90    // TODO: Add support for <encryption/>.
91}
92
93impl Description {
94    /// Create a new RTP description.
95    pub fn new(media: String) -> Description {
96        Description {
97            media,
98            ssrc: None,
99            payload_types: Vec::new(),
100            rtcp_mux: false,
101            ssrc_groups: Vec::new(),
102            ssrcs: Vec::new(),
103            hdrexts: Vec::new(),
104            bandwidth: None,
105        }
106    }
107}
108
109generate_attribute!(
110    /// The number of channels.
111    Channels,
112    "channels",
113    u8,
114    Default = 1
115);
116
117/// An encoding that can be used for an RTP stream.
118#[derive(FromXml, AsXml, PartialEq, Debug, Clone)]
119#[xml(namespace = ns::JINGLE_RTP, name = "payload-type")]
120pub struct PayloadType {
121    /// The number of channels.
122    #[xml(attribute(default))]
123    pub channels: Channels,
124
125    /// The sampling frequency in Hertz.
126    #[xml(attribute(default))]
127    pub clockrate: Option<u32>,
128
129    /// The payload identifier.
130    #[xml(attribute)]
131    pub id: u8,
132
133    /// Maximum packet time as specified in RFC 4566.
134    #[xml(attribute(default))]
135    pub maxptime: Option<u32>,
136
137    /// The appropriate subtype of the MIME type.
138    #[xml(attribute(default))]
139    pub name: Option<String>,
140
141    /// Packet time as specified in RFC 4566.
142    #[xml(attribute(default))]
143    pub ptime: Option<u32>,
144
145    /// List of parameters specifying this payload-type.
146    ///
147    /// Their order MUST be ignored.
148    #[xml(child(n = ..))]
149    pub parameters: Vec<Parameter>,
150
151    /// List of rtcp-fb parameters from XEP-0293.
152    #[xml(child(n = ..))]
153    pub rtcp_fbs: Vec<RtcpFb>,
154}
155
156impl PayloadType {
157    /// Create a new RTP payload-type.
158    pub fn new(id: u8, name: String, clockrate: u32, channels: u8) -> PayloadType {
159        PayloadType {
160            channels: Channels(channels),
161            clockrate: Some(clockrate),
162            id,
163            maxptime: None,
164            name: Some(name),
165            ptime: None,
166            parameters: Vec::new(),
167            rtcp_fbs: Vec::new(),
168        }
169    }
170
171    /// Create a new RTP payload-type without a clockrate.  Warning: this is invalid as per
172    /// RFC 4566!
173    pub fn without_clockrate(id: u8, name: String) -> PayloadType {
174        PayloadType {
175            channels: Default::default(),
176            clockrate: None,
177            id,
178            maxptime: None,
179            name: Some(name),
180            ptime: None,
181            parameters: Vec::new(),
182            rtcp_fbs: Vec::new(),
183        }
184    }
185}
186
187/// Parameter related to a payload.
188#[derive(FromXml, AsXml, PartialEq, Debug, Clone)]
189#[xml(namespace = ns::JINGLE_RTP, name = "parameter")]
190pub struct Parameter {
191    /// The name of the parameter, from the list at
192    /// <https://www.iana.org/assignments/sdp-parameters/sdp-parameters.xhtml>
193    #[xml(attribute)]
194    pub name: String,
195
196    /// The value of this parameter.
197    #[xml(attribute)]
198    pub value: String,
199}
200
201#[cfg(test)]
202mod tests {
203    use super::*;
204    use minidom::Element;
205
206    #[cfg(target_pointer_width = "32")]
207    #[test]
208    fn test_size() {
209        assert_size!(BwType, 1);
210        assert_size!(Bandwidth, 8);
211        assert_size!(Description, 80);
212        assert_size!(Channels, 1);
213        assert_size!(PayloadType, 64);
214        assert_size!(Parameter, 24);
215    }
216
217    #[cfg(target_pointer_width = "64")]
218    #[test]
219    fn test_size() {
220        assert_size!(BwType, 1);
221        assert_size!(Bandwidth, 8);
222        assert_size!(Description, 144);
223        assert_size!(Channels, 1);
224        assert_size!(PayloadType, 104);
225        assert_size!(Parameter, 48);
226    }
227
228    #[test]
229    fn test_simple() {
230        let elem: Element = "<description xmlns='urn:xmpp:jingle:apps:rtp:1' media='audio'>
231    <payload-type xmlns='urn:xmpp:jingle:apps:rtp:1' channels='2' clockrate='48000' id='96' name='OPUS'/>
232    <payload-type xmlns='urn:xmpp:jingle:apps:rtp:1' channels='1' clockrate='32000' id='105' name='SPEEX'/>
233    <payload-type xmlns='urn:xmpp:jingle:apps:rtp:1' channels='1' clockrate='8000' id='9' name='G722'/>
234    <payload-type xmlns='urn:xmpp:jingle:apps:rtp:1' channels='1' clockrate='16000' id='106' name='SPEEX'/>
235    <payload-type xmlns='urn:xmpp:jingle:apps:rtp:1' clockrate='8000' id='8' name='PCMA'/>
236    <payload-type xmlns='urn:xmpp:jingle:apps:rtp:1' clockrate='8000' id='0' name='PCMU'/>
237    <payload-type xmlns='urn:xmpp:jingle:apps:rtp:1' channels='1' clockrate='8000' id='107' name='SPEEX'/>
238    <payload-type xmlns='urn:xmpp:jingle:apps:rtp:1' channels='1' clockrate='8000' id='99' name='AMR'>
239        <parameter xmlns='urn:xmpp:jingle:apps:rtp:1' name='octet-align' value='1'/>
240        <parameter xmlns='urn:xmpp:jingle:apps:rtp:1' name='crc' value='0'/>
241        <parameter xmlns='urn:xmpp:jingle:apps:rtp:1' name='robust-sorting' value='0'/>
242        <parameter xmlns='urn:xmpp:jingle:apps:rtp:1' name='interleaving' value='0'/>
243    </payload-type>
244    <payload-type xmlns='urn:xmpp:jingle:apps:rtp:1' clockrate='48000' id='100' name='telephone-event'>
245        <parameter xmlns='urn:xmpp:jingle:apps:rtp:1' name='events' value='0-15'/>
246    </payload-type>
247    <payload-type xmlns='urn:xmpp:jingle:apps:rtp:1' clockrate='16000' id='101' name='telephone-event'>
248        <parameter xmlns='urn:xmpp:jingle:apps:rtp:1' name='events' value='0-15'/>
249    </payload-type>
250    <payload-type xmlns='urn:xmpp:jingle:apps:rtp:1' clockrate='8000' id='102' name='telephone-event'>
251        <parameter xmlns='urn:xmpp:jingle:apps:rtp:1' name='events' value='0-15'/>
252    </payload-type>
253    <rtcp-mux/>
254</description>"
255                .parse()
256                .unwrap();
257        let desc = Description::try_from(elem).unwrap();
258        assert_eq!(desc.media, "audio");
259        assert_eq!(desc.ssrc, None);
260        assert_eq!(desc.rtcp_mux, true);
261    }
262}