Add a parser for XEP-0339.

Emmanuel Gil Peyrot created

Change summary

doap.xml           |   8 +++
src/jingle_rtp.rs  |  12 ++++
src/jingle_ssma.rs | 114 ++++++++++++++++++++++++++++++++++++++++++++++++
src/lib.rs         |   3 +
src/ns.rs          |   3 +
5 files changed, 139 insertions(+), 1 deletion(-)

Detailed changes

doap.xml 🔗

@@ -417,6 +417,14 @@
             <xmpp:since>NEXT</xmpp:since>
         </xmpp:SupportedXep>
     </implements>
+    <implements>
+        <xmpp:SupportedXep>
+            <xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0339.html"/>
+            <xmpp:status>complete</xmpp:status>
+            <xmpp:version>0.3</xmpp:version>
+            <xmpp:since>NEXT</xmpp:since>
+        </xmpp:SupportedXep>
+    </implements>
     <implements>
         <xmpp:SupportedXep>
             <xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0352.html"/>

src/jingle_rtp.rs 🔗

@@ -4,6 +4,8 @@
 // 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 crate::jingle_ssma::{Source, Group};
+
 generate_element!(
     /// Wrapper element describing an RTP session.
     Description, "description", JINGLE_RTP,
@@ -18,7 +20,13 @@ generate_element!(
     ],
     children: [
         /// List of encodings that can be used for this RTP stream.
-        payload_types: Vec<PayloadType> = ("payload-type", JINGLE_RTP) => PayloadType
+        payload_types: Vec<PayloadType> = ("payload-type", JINGLE_RTP) => PayloadType,
+
+        /// List of ssrc-group.
+        ssrc_groups: Vec<Group> = ("ssrc-group", JINGLE_SSMA) => Group,
+
+        /// List of ssrc.
+        ssrcs: Vec<Source> = ("ssrc", JINGLE_SSMA) => Source
 
         // TODO: Add support for <encryption/> and <bandwidth/>.
     ]
@@ -31,6 +39,8 @@ impl Description {
             media,
             ssrc: None,
             payload_types: Vec::new(),
+            ssrc_groups: Vec::new(),
+            ssrcs: Vec::new(),
         }
     }
 }

src/jingle_ssma.rs 🔗

@@ -0,0 +1,114 @@
+// Copyright (c) 2019 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/.
+
+generate_element!(
+    /// Source element for the ssrc SDP attribute.
+    Source, "source", JINGLE_SSMA,
+    attributes: [
+        /// Maps to the ssrc-id parameter.
+        id: Required<String> = "ssrc",
+    ],
+    children: [
+        /// List of attributes for this source.
+        parameters: Vec<Parameter> = ("parameter", JINGLE_SSMA) => Parameter
+    ]
+);
+
+impl Source {
+    /// Create a new SSMA Source element.
+    pub fn new(id: String) -> Source {
+        Source {
+            id,
+            parameters: Vec::new(),
+        }
+    }
+}
+
+generate_element!(
+    /// Parameter associated with a ssrc.
+    Parameter, "parameter", JINGLE_SSMA,
+    attributes: [
+        /// The name of the parameter.
+        name: Required<String> = "name",
+
+        /// The optional value of the parameter.
+        value: Option<String> = "value",
+    ]
+);
+
+generate_element!(
+    /// Element grouping multiple ssrc.
+    Group, "ssrc-group", JINGLE_SSMA,
+    attributes: [
+        /// The semantics of this group.
+        semantics: Required<String> = "semantics",
+    ],
+    children: [
+        /// The various ssrc concerned by this group.
+        sources: Vec<Source> = ("source", JINGLE_SSMA) => Source
+    ]
+);
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use crate::Element;
+    use std::convert::TryFrom;
+
+    #[cfg(target_pointer_width = "32")]
+    #[test]
+    fn test_size() {
+        assert_size!(Source, 24);
+        assert_size!(Parameter, 24);
+        assert_size!(Group, 24);
+    }
+
+    #[cfg(target_pointer_width = "64")]
+    #[test]
+    fn test_size() {
+        assert_size!(Source, 48);
+        assert_size!(Parameter, 48);
+        assert_size!(Group, 48);
+    }
+
+    #[test]
+    fn parse_source() {
+        let elem: Element = "
+<source ssrc='1656081975' xmlns='urn:xmpp:jingle:apps:rtp:ssma:0'>
+    <parameter name='cname' value='Yv/wvbCdsDW2Prgd'/>
+    <parameter name='msid' value='MLTJKIHilGn71fNQoszkQ4jlPTuS5vJyKVIv MLTJKIHilGn71fNQoszkQ4jlPTuS5vJyKVIva0'/>
+</source>"
+                .parse()
+                .unwrap();
+        let mut ssrc = Source::try_from(elem).unwrap();
+        assert_eq!(ssrc.id, "1656081975");
+        assert_eq!(ssrc.parameters.len(), 2);
+        let parameter = ssrc.parameters.pop().unwrap();
+        assert_eq!(parameter.name, "msid");
+        assert_eq!(parameter.value.unwrap(), "MLTJKIHilGn71fNQoszkQ4jlPTuS5vJyKVIv MLTJKIHilGn71fNQoszkQ4jlPTuS5vJyKVIva0");
+        let parameter = ssrc.parameters.pop().unwrap();
+        assert_eq!(parameter.name, "cname");
+        assert_eq!(parameter.value.unwrap(), "Yv/wvbCdsDW2Prgd");
+    }
+
+    #[test]
+    fn parse_source_group() {
+        let elem: Element = "
+<ssrc-group semantics='FID' xmlns='urn:xmpp:jingle:apps:rtp:ssma:0'>
+    <source ssrc='2301230316'/>
+    <source ssrc='386328120'/>
+</ssrc-group>"
+                .parse()
+                .unwrap();
+        let mut group = Group::try_from(elem).unwrap();
+        assert_eq!(group.semantics, "FID");
+        assert_eq!(group.sources.len(), 2);
+        let source = group.sources.pop().unwrap();
+        assert_eq!(source.id, "386328120");
+        let source = group.sources.pop().unwrap();
+        assert_eq!(source.id, "2301230316");
+    }
+}

src/lib.rs 🔗

@@ -183,6 +183,9 @@ pub mod jingle_dtls_srtp;
 /// XEP-0328: JID Prep
 pub mod jid_prep;
 
+/// XEP-0339: Source-Specific Media Attributes in Jingle
+pub mod jingle_ssma;
+
 /// XEP-0352: Client State Indication
 pub mod csi;
 

src/ns.rs 🔗

@@ -188,6 +188,9 @@ pub const JINGLE_DTLS: &str = "urn:xmpp:jingle:apps:dtls:0";
 /// XEP-0328: JID Prep
 pub const JID_PREP: &str = "urn:xmpp:jidprep:0";
 
+/// XEP-0339: Source-Specific Media Attributes in Jingle
+pub const JINGLE_SSMA: &str = "urn:xmpp:jingle:apps:rtp:ssma:0";
+
 /// XEP-0352: Client State Indication
 pub const CSI: &str = "urn:xmpp:csi:0";