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