1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
// 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<u32> = "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: u32) -> 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_attribute!(
    /// From RFC5888, the list of allowed semantics.
    Semantics, "semantics", {
        /// Lip Synchronization, defined in RFC5888.
        Ls => "LS",

        /// Flow Identification, defined in RFC5888.
        Fid => "FID",

        /// Single Reservation Flow, defined in RFC3524.
        Srf => "SRF",

        /// Alternative Network Address Types, defined in RFC4091.
        Anat => "ANAT",

        /// Forward Error Correction, defined in RFC4756.
        Fec => "FEC",

        /// Decoding Dependency, defined in RFC5583.
        Ddp => "DDP",
    }
);

generate_element!(
    /// Element grouping multiple ssrc.
    Group, "ssrc-group", JINGLE_SSMA,
    attributes: [
        /// The semantics of this group.
        semantics: Required<Semantics> = "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;

    #[cfg(target_pointer_width = "32")]
    #[test]
    fn test_size() {
        assert_size!(Source, 16);
        assert_size!(Parameter, 24);
        assert_size!(Semantics, 1);
        assert_size!(Group, 16);
    }

    #[cfg(target_pointer_width = "64")]
    #[test]
    fn test_size() {
        assert_size!(Source, 32);
        assert_size!(Parameter, 48);
        assert_size!(Semantics, 1);
        assert_size!(Group, 32);
    }

    #[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, 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);
    }
}