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