2020-11-27 19:46:09 +00:00
|
|
|
|
// Copyright (c) 2019-2020 Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
|
2019-02-27 17:13:06 +00:00
|
|
|
|
//
|
|
|
|
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
|
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
|
|
2024-06-21 15:54:12 +00:00
|
|
|
|
use xso::{FromXml, IntoXml};
|
|
|
|
|
|
2019-10-12 17:10:50 +00:00
|
|
|
|
use crate::jingle_rtcp_fb::RtcpFb;
|
2020-11-27 19:51:49 +00:00
|
|
|
|
use crate::jingle_rtp_hdrext::RtpHdrext;
|
2019-10-22 23:32:41 +00:00
|
|
|
|
use crate::jingle_ssma::{Group, Source};
|
2024-06-21 15:54:12 +00:00
|
|
|
|
use crate::ns;
|
2019-10-12 16:17:04 +00:00
|
|
|
|
|
2024-06-21 15:54:12 +00:00
|
|
|
|
/// Specifies the ability to multiplex RTP Data and Control Packets on a single port as
|
|
|
|
|
/// described in RFC 5761.
|
|
|
|
|
#[derive(FromXml, IntoXml, PartialEq, Debug, Clone)]
|
|
|
|
|
#[xml(namespace = ns::JINGLE_RTP, name = "rtcp-mux")]
|
|
|
|
|
pub struct RtcpMux;
|
2020-11-27 19:46:09 +00:00
|
|
|
|
|
2019-02-27 17:13:06 +00:00
|
|
|
|
generate_element!(
|
|
|
|
|
/// Wrapper element describing an RTP session.
|
|
|
|
|
Description, "description", JINGLE_RTP,
|
|
|
|
|
attributes: [
|
|
|
|
|
/// Namespace of the encryption scheme used.
|
|
|
|
|
media: Required<String> = "media",
|
|
|
|
|
|
|
|
|
|
/// User-friendly name for the encryption scheme, should be `None` for OTR,
|
|
|
|
|
/// legacy OpenPGP and OX.
|
|
|
|
|
// XXX: is this a String or an u32?! Refer to RFC 3550.
|
|
|
|
|
ssrc: Option<String> = "ssrc",
|
|
|
|
|
],
|
|
|
|
|
children: [
|
|
|
|
|
/// List of encodings that can be used for this RTP stream.
|
2019-10-12 16:17:04 +00:00
|
|
|
|
payload_types: Vec<PayloadType> = ("payload-type", JINGLE_RTP) => PayloadType,
|
|
|
|
|
|
2020-11-27 19:46:09 +00:00
|
|
|
|
/// Specifies the ability to multiplex RTP Data and Control Packets on a single port as
|
|
|
|
|
/// described in RFC 5761.
|
|
|
|
|
rtcp_mux: Option<RtcpMux> = ("rtcp-mux", JINGLE_RTP) => RtcpMux,
|
|
|
|
|
|
2019-10-12 16:17:04 +00:00
|
|
|
|
/// List of ssrc-group.
|
|
|
|
|
ssrc_groups: Vec<Group> = ("ssrc-group", JINGLE_SSMA) => Group,
|
|
|
|
|
|
|
|
|
|
/// List of ssrc.
|
2020-11-27 19:51:49 +00:00
|
|
|
|
ssrcs: Vec<Source> = ("source", JINGLE_SSMA) => Source,
|
|
|
|
|
|
|
|
|
|
/// List of header extensions.
|
|
|
|
|
hdrexts: Vec<RtpHdrext> = ("rtp-hdrext", JINGLE_RTP_HDREXT) => RtpHdrext
|
2019-02-27 17:13:06 +00:00
|
|
|
|
|
|
|
|
|
// TODO: Add support for <encryption/> and <bandwidth/>.
|
|
|
|
|
]
|
|
|
|
|
);
|
|
|
|
|
|
2019-10-12 15:16:36 +00:00
|
|
|
|
impl Description {
|
|
|
|
|
/// Create a new RTP description.
|
|
|
|
|
pub fn new(media: String) -> Description {
|
|
|
|
|
Description {
|
|
|
|
|
media,
|
|
|
|
|
ssrc: None,
|
|
|
|
|
payload_types: Vec::new(),
|
2020-11-27 19:46:09 +00:00
|
|
|
|
rtcp_mux: None,
|
2019-10-12 16:17:04 +00:00
|
|
|
|
ssrc_groups: Vec::new(),
|
|
|
|
|
ssrcs: Vec::new(),
|
2020-11-27 19:51:49 +00:00
|
|
|
|
hdrexts: Vec::new(),
|
2019-10-12 15:16:36 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-28 02:10:21 +00:00
|
|
|
|
generate_attribute!(
|
|
|
|
|
/// The number of channels.
|
2019-10-22 23:32:41 +00:00
|
|
|
|
Channels,
|
|
|
|
|
"channels",
|
|
|
|
|
u8,
|
|
|
|
|
Default = 1
|
2019-02-28 02:10:21 +00:00
|
|
|
|
);
|
2019-02-27 17:13:06 +00:00
|
|
|
|
|
|
|
|
|
generate_element!(
|
|
|
|
|
/// An encoding that can be used for an RTP stream.
|
|
|
|
|
PayloadType, "payload-type", JINGLE_RTP,
|
|
|
|
|
attributes: [
|
|
|
|
|
/// The number of channels.
|
|
|
|
|
channels: Default<Channels> = "channels",
|
|
|
|
|
|
|
|
|
|
/// The sampling frequency in Hertz.
|
|
|
|
|
clockrate: Option<u32> = "clockrate",
|
|
|
|
|
|
|
|
|
|
/// The payload identifier.
|
|
|
|
|
id: Required<u8> = "id",
|
|
|
|
|
|
|
|
|
|
/// Maximum packet time as specified in RFC 4566.
|
|
|
|
|
maxptime: Option<u32> = "maxptime",
|
|
|
|
|
|
|
|
|
|
/// The appropriate subtype of the MIME type.
|
|
|
|
|
name: Option<String> = "name",
|
|
|
|
|
|
|
|
|
|
/// Packet time as specified in RFC 4566.
|
|
|
|
|
ptime: Option<u32> = "ptime",
|
|
|
|
|
],
|
|
|
|
|
children: [
|
|
|
|
|
/// List of parameters specifying this payload-type.
|
|
|
|
|
///
|
|
|
|
|
/// Their order MUST be ignored.
|
2019-10-12 17:10:50 +00:00
|
|
|
|
parameters: Vec<Parameter> = ("parameter", JINGLE_RTP) => Parameter,
|
|
|
|
|
|
|
|
|
|
/// List of rtcp-fb parameters from XEP-0293.
|
|
|
|
|
rtcp_fbs: Vec<RtcpFb> = ("rtcp-fb", JINGLE_RTCP_FB) => RtcpFb
|
2019-02-27 17:13:06 +00:00
|
|
|
|
]
|
|
|
|
|
);
|
|
|
|
|
|
2019-10-12 15:16:36 +00:00
|
|
|
|
impl PayloadType {
|
|
|
|
|
/// Create a new RTP payload-type.
|
2020-11-30 01:04:13 +00:00
|
|
|
|
pub fn new(id: u8, name: String, clockrate: u32, channels: u8) -> PayloadType {
|
|
|
|
|
PayloadType {
|
|
|
|
|
channels: Channels(channels),
|
|
|
|
|
clockrate: Some(clockrate),
|
|
|
|
|
id,
|
|
|
|
|
maxptime: None,
|
|
|
|
|
name: Some(name),
|
|
|
|
|
ptime: None,
|
|
|
|
|
parameters: Vec::new(),
|
|
|
|
|
rtcp_fbs: Vec::new(),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Create a new RTP payload-type without a clockrate. Warning: this is invalid as per
|
|
|
|
|
/// RFC 4566!
|
|
|
|
|
pub fn without_clockrate(id: u8, name: String) -> PayloadType {
|
2019-10-12 15:16:36 +00:00
|
|
|
|
PayloadType {
|
|
|
|
|
channels: Default::default(),
|
|
|
|
|
clockrate: None,
|
|
|
|
|
id,
|
|
|
|
|
maxptime: None,
|
|
|
|
|
name: Some(name),
|
|
|
|
|
ptime: None,
|
|
|
|
|
parameters: Vec::new(),
|
2019-10-12 17:10:50 +00:00
|
|
|
|
rtcp_fbs: Vec::new(),
|
2019-10-12 15:16:36 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-27 17:13:06 +00:00
|
|
|
|
generate_element!(
|
|
|
|
|
/// Parameter related to a payload.
|
|
|
|
|
Parameter, "parameter", JINGLE_RTP,
|
|
|
|
|
attributes: [
|
|
|
|
|
/// The name of the parameter, from the list at
|
2022-12-27 15:31:58 +00:00
|
|
|
|
/// <https://www.iana.org/assignments/sdp-parameters/sdp-parameters.xhtml>
|
2019-02-27 17:13:06 +00:00
|
|
|
|
name: Required<String> = "name",
|
|
|
|
|
|
|
|
|
|
/// The value of this parameter.
|
|
|
|
|
value: Required<String> = "value",
|
|
|
|
|
]
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
|
mod tests {
|
|
|
|
|
use super::*;
|
2019-09-25 08:28:44 +00:00
|
|
|
|
use crate::Element;
|
2019-02-27 17:13:06 +00:00
|
|
|
|
|
2019-02-28 02:47:04 +00:00
|
|
|
|
#[cfg(target_pointer_width = "32")]
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_size() {
|
2020-11-27 19:51:49 +00:00
|
|
|
|
assert_size!(Description, 76);
|
2019-02-28 02:47:04 +00:00
|
|
|
|
assert_size!(Channels, 1);
|
2020-04-05 17:05:12 +00:00
|
|
|
|
assert_size!(PayloadType, 64);
|
2019-02-28 02:47:04 +00:00
|
|
|
|
assert_size!(Parameter, 24);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(target_pointer_width = "64")]
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_size() {
|
2020-11-27 19:51:49 +00:00
|
|
|
|
assert_size!(Description, 152);
|
2019-02-28 02:47:04 +00:00
|
|
|
|
assert_size!(Channels, 1);
|
2019-10-12 17:10:50 +00:00
|
|
|
|
assert_size!(PayloadType, 104);
|
2019-02-28 02:47:04 +00:00
|
|
|
|
assert_size!(Parameter, 48);
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-27 17:13:06 +00:00
|
|
|
|
#[test]
|
|
|
|
|
fn test_simple() {
|
2022-03-22 22:29:25 +00:00
|
|
|
|
let elem: Element = "<description xmlns='urn:xmpp:jingle:apps:rtp:1' media='audio'>
|
2019-02-27 17:13:06 +00:00
|
|
|
|
<payload-type xmlns='urn:xmpp:jingle:apps:rtp:1' channels='2' clockrate='48000' id='96' name='OPUS'/>
|
|
|
|
|
<payload-type xmlns='urn:xmpp:jingle:apps:rtp:1' channels='1' clockrate='32000' id='105' name='SPEEX'/>
|
|
|
|
|
<payload-type xmlns='urn:xmpp:jingle:apps:rtp:1' channels='1' clockrate='8000' id='9' name='G722'/>
|
|
|
|
|
<payload-type xmlns='urn:xmpp:jingle:apps:rtp:1' channels='1' clockrate='16000' id='106' name='SPEEX'/>
|
|
|
|
|
<payload-type xmlns='urn:xmpp:jingle:apps:rtp:1' clockrate='8000' id='8' name='PCMA'/>
|
|
|
|
|
<payload-type xmlns='urn:xmpp:jingle:apps:rtp:1' clockrate='8000' id='0' name='PCMU'/>
|
|
|
|
|
<payload-type xmlns='urn:xmpp:jingle:apps:rtp:1' channels='1' clockrate='8000' id='107' name='SPEEX'/>
|
|
|
|
|
<payload-type xmlns='urn:xmpp:jingle:apps:rtp:1' channels='1' clockrate='8000' id='99' name='AMR'>
|
|
|
|
|
<parameter xmlns='urn:xmpp:jingle:apps:rtp:1' name='octet-align' value='1'/>
|
|
|
|
|
<parameter xmlns='urn:xmpp:jingle:apps:rtp:1' name='crc' value='0'/>
|
|
|
|
|
<parameter xmlns='urn:xmpp:jingle:apps:rtp:1' name='robust-sorting' value='0'/>
|
|
|
|
|
<parameter xmlns='urn:xmpp:jingle:apps:rtp:1' name='interleaving' value='0'/>
|
|
|
|
|
</payload-type>
|
|
|
|
|
<payload-type xmlns='urn:xmpp:jingle:apps:rtp:1' clockrate='48000' id='100' name='telephone-event'>
|
|
|
|
|
<parameter xmlns='urn:xmpp:jingle:apps:rtp:1' name='events' value='0-15'/>
|
|
|
|
|
</payload-type>
|
|
|
|
|
<payload-type xmlns='urn:xmpp:jingle:apps:rtp:1' clockrate='16000' id='101' name='telephone-event'>
|
|
|
|
|
<parameter xmlns='urn:xmpp:jingle:apps:rtp:1' name='events' value='0-15'/>
|
|
|
|
|
</payload-type>
|
|
|
|
|
<payload-type xmlns='urn:xmpp:jingle:apps:rtp:1' clockrate='8000' id='102' name='telephone-event'>
|
|
|
|
|
<parameter xmlns='urn:xmpp:jingle:apps:rtp:1' name='events' value='0-15'/>
|
|
|
|
|
</payload-type>
|
|
|
|
|
</description>"
|
|
|
|
|
.parse()
|
|
|
|
|
.unwrap();
|
|
|
|
|
let desc = Description::try_from(elem).unwrap();
|
|
|
|
|
assert_eq!(desc.media, "audio");
|
|
|
|
|
assert_eq!(desc.ssrc, None);
|
|
|
|
|
}
|
|
|
|
|
}
|