./ct_report/coverage/jingle_to_sdp.COVER.html

1 %%==============================================================================
2 %% Copyright 2018 Erlang Solutions Ltd.
3 %%
4 %% Licensed under the Apache License, Version 2.0 (the "License");
5 %% you may not use this file except in compliance with the License.
6 %% You may obtain a copy of the License at
7 %%
8 %% http://www.apache.org/licenses/LICENSE-2.0
9 %%
10 %% Unless required by applicable law or agreed to in writing, software
11 %% distributed under the License is distributed on an "AS IS" BASIS,
12 %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 %% See the License for the specific language governing permissions and
14 %% limitations under the License.
15 %%==============================================================================
16 %%
17 %% @author Michal Piotrowski <michal.piotrowski@erlang-solutions.com>
18 -module(jingle_to_sdp).
19
20 %% @doc this modules translates jingle stanza to a sdp packet
21 %%
22
23 -export([from_media/1]).
24 -export([parse_transport_element/1]).
25
26 -include("mongoose.hrl").
27 -include("jlib.hrl").
28 -include_lib("nksip/include/nksip.hrl").
29
30 -type rtphdr_ext() :: {ID :: binary(), URI :: binary(), Senders :: binary()}.
31
32 -type source() :: {SSRC :: binary(), [{binary(), binary()}]}.
33
34 -type content() :: #{media := undefined | binary(),
35 name := undefined | binary(),
36 protocol := binary(),
37 description := description(),
38 transport := transport(),
39 senders := binary()}.
40
41 -type description() :: #{codecs := [codec()],
42 rtphdr_ext := [rtphdr_ext()],
43 rtcp_mux := boolean(),
44 sources := [source()]}.
45
46 -type transport() :: #{ufrag := undefined | binary(),
47 pwd := undefined | binary(),
48 fingerprint => fingerprint(),
49 candidates => candidate()}.
50
51 -type codec() :: #{id := binary(),
52 name := binary(),
53 clock_rate := binary(),
54 channels := binary(),
55 params := [param()], %% basic codec parameters.
56 rtcp_fb_params := rtcp_fb_param()}.
57
58 -type param() :: {binary(), binary()}.
59 -type rtcp_fb_param() :: [binary()].
60
61 -type fingerprint() :: {Hash :: undefined | binary(), Setup :: undefined | binary(),
62 Fingerprint :: binary()}.
63
64 -type candidate() :: any().
65
66 -export_type([content/0]).
67
68 -spec from_media(exml:element()) -> content().
69 from_media(#xmlel{name = <<"content">>} = JingleContent) ->
70
:-(
Content = #{name => exml_query:attr(JingleContent, <<"name">>),
71 protocol => <<"UDP/TLS/RTP/SAVPF">>,
72 senders => decode_senders(JingleContent)},
73
:-(
parse_content_children(Content, JingleContent#xmlel.children).
74
75 -spec parse_content_children(map(), list()) -> content().
76 parse_content_children(Content, []) ->
77
:-(
Content;
78 parse_content_children(Content, [Child | Rest]) ->
79
:-(
NewContent = parse_content_child(Child, Content),
80
:-(
parse_content_children(NewContent, Rest).
81
82
83 parse_content_child(#xmlel{name = <<"description">>} = DescriptionEl, Content) ->
84
:-(
Description = #{codecs => [],
85 rtphdr_ext => [],
86 rtcp_mux => false,
87 sources => []},
88
:-(
Media = exml_query:attr(DescriptionEl, <<"media">>),
89
:-(
NewDescription = parse_description_children(Description, DescriptionEl#xmlel.children),
90
:-(
Content#{description => NewDescription, media => Media};
91 parse_content_child(#xmlel{name = <<"transport">>} = TransportEl, Content) ->
92
:-(
NewTransport = parse_transport_element(TransportEl),
93
:-(
Content#{transport => NewTransport};
94 parse_content_child(_, Content) ->
95
:-(
Content.
96
97 -spec parse_transport_element(exml:element()) -> transport().
98 parse_transport_element(TransportEl) ->
99
:-(
Ufrag = exml_query:attr(TransportEl, <<"ufrag">>),
100
:-(
Pwd = exml_query:attr(TransportEl, <<"pwd">>),
101
:-(
Transport = #{ufrag => Ufrag,
102 pwd => Pwd,
103 candidates => []},
104
:-(
parse_transport_children(Transport, TransportEl#xmlel.children).
105
106 -spec parse_description_children(map(), list()) -> description().
107 parse_description_children(Desc, []) ->
108
:-(
Desc;
109 parse_description_children(Desc, [Child | Rest]) ->
110
:-(
NewDesc = parse_description_child(Child, Desc),
111
:-(
parse_description_children(NewDesc, Rest).
112
113 parse_description_child(#xmlel{name = <<"payload-type">>} = Payload, Description) ->
114
:-(
fill_codec(Description, Payload);
115 parse_description_child(#xmlel{name = <<"rtp-hdrext">>} = RTPHdrExtEl, Description) ->
116
:-(
RTPHdrExts = maps:get(rtphdr_ext, Description),
117
:-(
RTPHdrExt = decode_rtp_hdr_ext(RTPHdrExtEl),
118
:-(
Description#{rtphdr_ext := [RTPHdrExt | RTPHdrExts]};
119 parse_description_child(#xmlel{name = <<"rtcp-mux">>}, Description) ->
120
:-(
Description#{rtcp_mux := true};
121 parse_description_child(#xmlel{name = <<"source">>} = SourceEl, Description) ->
122
:-(
fill_source(Description, SourceEl);
123 parse_description_child(_, Content) ->
124
:-(
Content.
125
126 fill_codec(#{codecs := Codecs} = Desc, Payload) ->
127
:-(
ID = exml_query:attr(Payload, <<"id">>),
128
:-(
Name = exml_query:attr(Payload, <<"name">>),
129
:-(
ClockRate = exml_query:attr(Payload, <<"clockrate">>),
130
:-(
Channels = exml_query:attr(Payload, <<"channels">>, <<"1">>),
131
:-(
Codec = #{id => ID,
132 name => Name,
133 clock_rate => ClockRate,
134 channels => Channels,
135 params => [],
136 rtcp_fb_params => []},
137
:-(
FinalCodec = parse_payload_children(Codec, Payload#xmlel.children),
138
:-(
Desc#{codecs := [FinalCodec | Codecs]}.
139
140 parse_payload_children(Codec, []) ->
141
:-(
Codec;
142 parse_payload_children(Codec, [Child | Rest]) ->
143
:-(
UpdatedCodec = parse_payload_child(Child, Codec),
144
:-(
parse_payload_children(UpdatedCodec, Rest).
145
146 parse_payload_child(#xmlel{name = <<"parameter">>} = BasicParam,
147 #{params := Params} = Codec) ->
148
:-(
Name = exml_query:attr(BasicParam, <<"name">>),
149
:-(
Value = exml_query:attr(BasicParam, <<"value">>),
150
:-(
NewParams = [{Name, Value} | Params],
151
:-(
Codec#{params := NewParams};
152 parse_payload_child(#xmlel{name = <<"rtcp-fb">>} = RTCPParam,
153 #{rtcp_fb_params := Params} = Codec) ->
154
:-(
Param = decode_rtcp_fb_param(RTCPParam),
155
:-(
NewParams = [Param | Params],
156
:-(
Codec#{rtcp_fb_params := NewParams};
157 parse_payload_child(_, Codec) ->
158
:-(
Codec.
159
160 decode_rtcp_fb_param(RTCPParam) ->
161
:-(
Type = exml_query:attr(RTCPParam, <<"type">>),
162
:-(
case exml_query:attr(RTCPParam, <<"subtype">>) of
163 undefined ->
164
:-(
[Type];
165 SubType ->
166
:-(
[Type, SubType]
167 end.
168
169 decode_rtp_hdr_ext(RTPHdrExtEl) ->
170
:-(
ID = exml_query:attr(RTPHdrExtEl, <<"id">>),
171
:-(
URI = exml_query:attr(RTPHdrExtEl, <<"uri">>),
172
:-(
Senders = exml_query:attr(RTPHdrExtEl, <<"senders">>, <<"both">>),
173
:-(
{ID, URI, sender_to_sdp_attr(Senders)}.
174
175 fill_source(#{sources := Sources} = Desc, SourceEl) ->
176
:-(
Params = exml_query:subelements(SourceEl, <<"parameter">>),
177
:-(
KV = [source_param_to_kv(Param) || Param <- Params],
178
:-(
ID = exml_query:attr(SourceEl, <<"ssrc">>),
179
:-(
Desc#{sources := [{ID, KV} | Sources]}.
180
181 source_param_to_kv(El) ->
182
:-(
Name = exml_query:attr(El, <<"name">>),
183
:-(
Value = exml_query:attr(El, <<"value">>),
184
:-(
{Name, Value}.
185
186 decode_senders(ContentEl) ->
187
:-(
SenderValue = exml_query:attr(ContentEl, <<"senders">>, <<"both">>),
188
:-(
sender_to_sdp_attr(SenderValue).
189
190
:-(
sender_to_sdp_attr(<<"both">>) -> <<"sendrecv">>;
191
:-(
sender_to_sdp_attr(<<"initiator">>) -> <<"sendonly">>;
192
:-(
sender_to_sdp_attr(<<"responder">>) -> <<"recvonly">>;
193
:-(
sender_to_sdp_attr(<<"none">>) -> <<"inactive">>.
194
195 parse_transport_children(Transport, []) ->
196
:-(
Transport;
197 parse_transport_children(Transport, [Child | Rest]) ->
198
:-(
NewTransport = parse_transport_child(Child, Transport),
199
:-(
parse_transport_children(NewTransport, Rest).
200
201 parse_transport_child(#xmlel{name = <<"fingerprint">>} = FingerprintEl, Transport) ->
202
:-(
Hash = exml_query:attr(FingerprintEl, <<"hash">>),
203
:-(
Setup = exml_query:attr(FingerprintEl, <<"setup">>),
204
:-(
Fingerprint = exml_query:cdata(FingerprintEl),
205
:-(
Transport#{fingerprint => {Hash, Setup, Fingerprint}};
206 parse_transport_child(#xmlel{name = <<"candidate">>, attrs = Attrs},
207 #{candidates := Candidates} = Transport) ->
208
:-(
NewCandidate = lists:foldl(fun parse_candidate_attr/2, #{}, Attrs),
209
:-(
Transport#{candidates := [NewCandidate | Candidates]};
210 parse_transport_child(_, Transport) ->
211
:-(
Transport.
212
213 -spec parse_candidate_attr({binary(), any()}, map()) -> map().
214 parse_candidate_attr({<<"foundation">>, Val}, Map) ->
215
:-(
Map#{foundation => Val};
216 parse_candidate_attr({<<"component">>, Val}, Map) ->
217
:-(
Map#{component => Val};
218 parse_candidate_attr({<<"generation">>, Val}, Map) ->
219
:-(
Map#{generation => Val};
220 parse_candidate_attr({<<"id">>, Val}, Map) ->
221
:-(
Map#{id => Val};
222 parse_candidate_attr({<<"ip">>, Val}, Map) ->
223
:-(
Map#{ip => Val};
224 parse_candidate_attr({<<"network">>, Val}, Map) ->
225
:-(
Map#{network => Val};
226 parse_candidate_attr({<<"port">>, Val}, Map) ->
227
:-(
Map#{port => Val};
228 parse_candidate_attr({<<"priority">>, Val}, Map) ->
229
:-(
Map#{priority => Val};
230 parse_candidate_attr({<<"protocol">>, Val}, Map) ->
231
:-(
Map#{protocol => Val};
232 parse_candidate_attr({<<"rel-addr">>, Val}, Map) ->
233
:-(
Map#{raddr => Val};
234 parse_candidate_attr({<<"rel-port">>, Val}, Map) ->
235
:-(
Map#{rport => Val};
236 parse_candidate_attr({<<"tcptype">>, Val}, Map) ->
237
:-(
Map#{tcptype => Val};
238 parse_candidate_attr({<<"type">>, Val}, Map) ->
239
:-(
Map#{type => Val};
240 parse_candidate_attr(_, Map) ->
241
:-(
Map.
Line Hits Source