xmpp-rs/parsers/src/jingle_rtp.rs
Emmanuel Gil Peyrot 7b66de1166 xmpp-parsers: Stop reexporting extra symbols
Let’s continue reexporting jid and minidom, but not their inner pub
items, users of this crate can go one level deeper if they need that.

Only xso::error::Error is still useful to reexport, as this is part of
the public API of all of our parsers.
2024-07-25 14:36:09 +00:00

209 lines
7.2 KiB
Rust
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Copyright (c) 2019-2020 Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
//
// 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/.
use xso::{AsXml, FromXml};
use crate::jingle_rtcp_fb::RtcpFb;
use crate::jingle_rtp_hdrext::RtpHdrext;
use crate::jingle_ssma::{Group, Source};
use crate::ns;
/// Specifies the ability to multiplex RTP Data and Control Packets on a single port as
/// described in RFC 5761.
#[derive(FromXml, AsXml, PartialEq, Debug, Clone)]
#[xml(namespace = ns::JINGLE_RTP, name = "rtcp-mux")]
pub struct RtcpMux;
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.
payload_types: Vec<PayloadType> = ("payload-type", JINGLE_RTP) => PayloadType,
/// 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,
/// List of ssrc-group.
ssrc_groups: Vec<Group> = ("ssrc-group", JINGLE_SSMA) => Group,
/// List of ssrc.
ssrcs: Vec<Source> = ("source", JINGLE_SSMA) => Source,
/// List of header extensions.
hdrexts: Vec<RtpHdrext> = ("rtp-hdrext", JINGLE_RTP_HDREXT) => RtpHdrext
// TODO: Add support for <encryption/> and <bandwidth/>.
]
);
impl Description {
/// Create a new RTP description.
pub fn new(media: String) -> Description {
Description {
media,
ssrc: None,
payload_types: Vec::new(),
rtcp_mux: None,
ssrc_groups: Vec::new(),
ssrcs: Vec::new(),
hdrexts: Vec::new(),
}
}
}
generate_attribute!(
/// The number of channels.
Channels,
"channels",
u8,
Default = 1
);
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.
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
]
);
impl PayloadType {
/// Create a new RTP payload-type.
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 {
PayloadType {
channels: Default::default(),
clockrate: None,
id,
maxptime: None,
name: Some(name),
ptime: None,
parameters: Vec::new(),
rtcp_fbs: Vec::new(),
}
}
}
/// Parameter related to a payload.
#[derive(FromXml, AsXml, PartialEq, Debug, Clone)]
#[xml(namespace = ns::JINGLE_RTP, name = "parameter")]
pub struct Parameter {
/// The name of the parameter, from the list at
/// <https://www.iana.org/assignments/sdp-parameters/sdp-parameters.xhtml>
#[xml(attribute)]
pub name: String,
/// The value of this parameter.
#[xml(attribute)]
pub value: String,
}
#[cfg(test)]
mod tests {
use super::*;
use minidom::Element;
#[cfg(target_pointer_width = "32")]
#[test]
fn test_size() {
assert_size!(Description, 76);
assert_size!(Channels, 1);
assert_size!(PayloadType, 64);
assert_size!(Parameter, 24);
}
#[cfg(target_pointer_width = "64")]
#[test]
fn test_size() {
assert_size!(Description, 152);
assert_size!(Channels, 1);
assert_size!(PayloadType, 104);
assert_size!(Parameter, 48);
}
#[test]
fn test_simple() {
let elem: Element = "<description xmlns='urn:xmpp:jingle:apps:rtp:1' media='audio'>
<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);
}
}