xmpp-rs/parsers/src/jingle_rtp.rs
Link Mauve 6d18641ace xmpp-parsers: Add support for <bandwidth/> in Jingle RTP Description
This was missing according to the specification, but I have never seen
it used in the wild.
2026-02-21 11:40:46 +01:00

262 lines
8.7 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;
generate_attribute!(
/// Value for the SDP "bwtype" parameter as listed in the IANA Session Description Protocol
/// Parameters Registry: <https://www.iana.org/assignments/sdp-parameters/sdp-parameters.xhtml>
///
/// See RFC8859.
BwType, "type", {
/// Not impacted.
Ct => "CT",
/// For media-level usage, the aggregate of individual bandwidth values is considered.
As => "AS",
/// Session-level usage represents session aggregate, and media-level usage indicates SUM
/// of the individual values while multiplexing.
Rs => "RS",
/// Session-level usage represents session aggregate, and media-level usage indicates SUM
/// of the individual values while multiplexing.
Rr => "RR",
/// Transport Independent Application Specific Maximum (TIAS) bandwidth modifier that does
/// not include transport overhead.
Tias => "TIAS",
}
);
/// Allowable or preferred bandwidth for use by this application type.
#[derive(FromXml, AsXml, PartialEq, Debug, Clone)]
#[xml(namespace = ns::JINGLE_RTP, name = "description")]
pub struct Bandwidth {
/// Value for the SDP "bwtype" parameter as listed in the IANA Session Description Protocol
/// Parameters Registry: <https://www.iana.org/assignments/sdp-parameters/sdp-parameters.xhtml>
#[xml(attribute)]
type_: BwType,
#[xml(text)]
value: u32,
}
/// Wrapper element describing an RTP session.
#[derive(FromXml, AsXml, PartialEq, Debug, Clone)]
#[xml(namespace = ns::JINGLE_RTP, name = "description")]
pub struct Description {
/// Specifies the media type, such as "audio" or "video", where the media type SHOULD be as
/// registered at IANA MIME Media Types Registry.
#[xml(attribute)]
pub media: String,
/// 32-bit synchronization source for this media stream, as defined in RFC3550.
#[xml(attribute(default))]
pub ssrc: Option<u32>,
/// List of encodings that can be used for this RTP stream.
#[xml(child(n = ..))]
pub payload_types: Vec<PayloadType>,
/// Specifies the ability to multiplex RTP Data and Control Packets on a single port as
/// described in RFC 5761.
#[xml(flag(name = "rtcp-mux"))]
pub rtcp_mux: bool,
/// List of ssrc-group.
#[xml(child(n = ..))]
pub ssrc_groups: Vec<Group>,
/// List of ssrc.
#[xml(child(n = ..))]
pub ssrcs: Vec<Source>,
/// List of header extensions.
#[xml(child(n = ..))]
pub hdrexts: Vec<RtpHdrext>,
/// Allowable or preferred bandwidth for use by this application type.
#[xml(child(default))]
pub bandwidth: Option<Bandwidth>,
// TODO: Add support for <encryption/>.
}
impl Description {
/// Create a new RTP description.
pub fn new(media: String) -> Description {
Description {
media,
ssrc: None,
payload_types: Vec::new(),
rtcp_mux: false,
ssrc_groups: Vec::new(),
ssrcs: Vec::new(),
hdrexts: Vec::new(),
bandwidth: None,
}
}
}
generate_attribute!(
/// The number of channels.
Channels,
"channels",
u8,
Default = 1
);
/// An encoding that can be used for an RTP stream.
#[derive(FromXml, AsXml, PartialEq, Debug, Clone)]
#[xml(namespace = ns::JINGLE_RTP, name = "payload-type")]
pub struct PayloadType {
/// The number of channels.
#[xml(attribute(default))]
pub channels: Channels,
/// The sampling frequency in Hertz.
#[xml(attribute(default))]
pub clockrate: Option<u32>,
/// The payload identifier.
#[xml(attribute)]
pub id: u8,
/// Maximum packet time as specified in RFC 4566.
#[xml(attribute(default))]
pub maxptime: Option<u32>,
/// The appropriate subtype of the MIME type.
#[xml(attribute(default))]
pub name: Option<String>,
/// Packet time as specified in RFC 4566.
#[xml(attribute(default))]
pub ptime: Option<u32>,
/// List of parameters specifying this payload-type.
///
/// Their order MUST be ignored.
#[xml(child(n = ..))]
pub parameters: Vec<Parameter>,
/// List of rtcp-fb parameters from XEP-0293.
#[xml(child(n = ..))]
pub rtcp_fbs: Vec<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!(BwType, 1);
assert_size!(Bandwidth, 8);
assert_size!(Description, 80);
assert_size!(Channels, 1);
assert_size!(PayloadType, 64);
assert_size!(Parameter, 24);
}
#[cfg(target_pointer_width = "64")]
#[test]
fn test_size() {
assert_size!(BwType, 1);
assert_size!(Bandwidth, 8);
assert_size!(Description, 144);
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>
<rtcp-mux/>
</description>"
.parse()
.unwrap();
let desc = Description::try_from(elem).unwrap();
assert_eq!(desc.media, "audio");
assert_eq!(desc.ssrc, None);
assert_eq!(desc.rtcp_mux, true);
}
}