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