./ct_report/coverage/sip_to_jingle.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(sip_to_jingle).
19
20
21 -include("mongoose.hrl").
22 -include("jlib.hrl").
23 -include_lib("nksip/include/nksip.hrl").
24
25 -export([parse_sdp_attributes/1]).
26 -export([sdp_media_to_content_el/2]).
27
28 parse_sdp_attributes(Attrs) ->
29
:-(
parse_sdp_attributes(Attrs, []).
30
31 parse_sdp_attributes([], Acc) ->
32
:-(
Acc;
33 parse_sdp_attributes([Attr | Rest], Acc) ->
34
:-(
NewAcc = parse_sdp_attribute(Attr, Acc),
35
:-(
parse_sdp_attributes(Rest, NewAcc).
36
37 parse_sdp_attribute({<<"group">>, [Method | Contents]}, Acc) ->
38
:-(
ContentEls = [sdp_group_content_to_el(Content) || Content <- Contents],
39
:-(
El = #xmlel{name = <<"group">>,
40 attrs = [{<<"xmlns">>, <<"urn:xmpp:jingle:apps:grouping:0">>},
41 {<<"semantics">>, Method}],
42 children = ContentEls},
43
:-(
[El | Acc];
44 parse_sdp_attribute(_, Acc) ->
45
:-(
Acc.
46
47 sdp_group_content_to_el(Content) ->
48
:-(
#xmlel{name = <<"content">>,
49 attrs = [{<<"name">>, Content}]}.
50
51
52 %% This function assumes that all codecs and their attributes were
53 %% extracted from the attributes list.
54 %% There are still attributes in the list describing other content parameters
55 sdp_media_to_content_el(#sdp_m{media = Media, attributes = Attrs}, CodecMap) ->
56
:-(
Codecs = maps:get(Media, CodecMap),
57
:-(
PayloadEls = [codec_to_payload(Codec) || Codec <- Codecs],
58
:-(
Content = parse_nksip_media_attrs(Attrs),
59
:-(
AdditionalDescriptionEls = description_elements_from_content(Content),
60
61
:-(
DescriptionEl = #xmlel{name = <<"description">>,
62 attrs = [{<<"xmlns">>, <<"urn:xmpp:jingle:apps:rtp:1">>},
63 {<<"media">>, Media}],
64 children = PayloadEls ++ AdditionalDescriptionEls},
65
:-(
TransportEl = make_transport_el(maps:get(transport, Content)),
66
67
:-(
#xmlel{name = <<"content">>,
68 attrs = [{<<"creator">>, <<"initiator">>},
69 {<<"name">>, maps:get(name, Content, Media)},
70 {<<"senders">>, maps:get(sender, Content)}],
71 children = [DescriptionEl, TransportEl]}.
72
73 codec_to_payload({ID, RTPMap, Attrs}) ->
74
:-(
Parameters = lists:flatmap(fun codec_attr_to_params/1, Attrs),
75
:-(
{Name, ClockRate, Channels} = parse_codec_rtpmap(RTPMap),
76
:-(
#xmlel{name = <<"payload-type">>,
77 attrs = [{<<"id">>, ID},
78 {<<"name">>, Name},
79 {<<"clockrate">>, ClockRate},
80 {<<"channels">>, Channels}],
81 children = Parameters}.
82
83 parse_codec_rtpmap(RTPMap) ->
84
:-(
case binary:split(RTPMap, <<$/>>, [global]) of
85 [Name, ClockRate] ->
86
:-(
{Name, ClockRate, <<"1">>};
87 [Name, ClockRate, Channels] ->
88
:-(
{Name, ClockRate, Channels}
89 end.
90
91 codec_attr_to_params({<<"rtcp-fb">>, Value}) ->
92
:-(
Attrs = rtcp_fb_value_to_xml_attrs(Value),
93
:-(
[#xmlel{name = <<"rtcp-fb">>,
94 attrs = [{<<"xmlns">>, <<"urn:xmpp:jingle:apps:rtp:rtcp-fb:0">>} | Attrs]}];
95 codec_attr_to_params({<<"fmtp">>, [Value]}) ->
96
:-(
Params = binary:split(Value, <<$;>>, [global]),
97
:-(
[basic_param_to_xml_el(Param) || Param <- Params];
98 codec_attr_to_params(_) ->
99
:-(
[].
100
101 rtcp_fb_value_to_xml_attrs([Type]) ->
102
:-(
[{<<"type">>, Type}];
103 rtcp_fb_value_to_xml_attrs([Type, SubType]) ->
104
:-(
[{<<"type">>, Type}, {<<"subtype">>, SubType}].
105
106 basic_param_to_xml_el(Param) ->
107
:-(
case binary:split(Param, <<$=>>) of
108 [Name, Value] ->
109
:-(
#xmlel{name = <<"parameter">>,
110 attrs = [{<<"name">>, Name},
111 {<<"value">>, Value}]};
112 [Value] ->
113
:-(
#xmlel{name = <<"parameter">>,
114 attrs = [{<<"value">>, Value}]}
115 end.
116
117 parse_nksip_media_attrs(Attrs) ->
118
:-(
parse_nksip_media_attrs(Attrs, #{}).
119
120 parse_nksip_media_attrs([], Acc) ->
121
:-(
Acc;
122 parse_nksip_media_attrs([{AttrName, AttrValue} | Rest], Acc) ->
123
:-(
NewAcc = parse_nksip_media_attr(AttrName, AttrValue, Acc),
124
:-(
parse_nksip_media_attrs(Rest, NewAcc).
125
126 parse_nksip_media_attr(<<"sendrecv">>, _, Acc) ->
127
:-(
Acc#{sender => <<"both">>};
128 parse_nksip_media_attr(<<"recvonly">>, _, Acc) ->
129
:-(
Acc#{sender => <<"responder">>};
130 parse_nksip_media_attr(<<"sendonly">>, _, Acc) ->
131
:-(
Acc#{sender => <<"initiator">>};
132 parse_nksip_media_attr(<<"inactive">>, _, Acc) ->
133
:-(
Acc#{sender => <<"none">>};
134 parse_nksip_media_attr(<<"candidate">>, Params, Acc) ->
135
:-(
[Foundation, Component, Protocol, Priority, IP, Port | ExtraArgs] = Params,
136
:-(
Candidate = #{foundation => Foundation,
137 component => Component,
138 protocol => Protocol,
139 priority => Priority,
140 ip => IP,
141 port => Port,
142 network => <<"0">>, %% no SDP equivalent
143 id => base16:encode(crypto:strong_rand_bytes(5))},
144
:-(
CompleteCandidate = parse_candidate_extra_args(ExtraArgs, Candidate),
145
:-(
Transport = maps:get(transport, Acc, #{}),
146
:-(
Candidates = maps:get(candidates, Transport, []),
147
:-(
NewTransport = Transport#{candidates => [CompleteCandidate | Candidates]},
148
:-(
Acc#{transport => NewTransport};
149 parse_nksip_media_attr(<<"ice-ufrag">>, [Value], Acc) ->
150
:-(
Transport = maps:get(transport, Acc, #{}),
151
:-(
Acc#{transport => Transport#{ufrag => Value}};
152 parse_nksip_media_attr(<<"ice-pwd">>, [Value], Acc) ->
153
:-(
Transport = maps:get(transport, Acc, #{}),
154
:-(
Acc#{transport => Transport#{pwd => Value}};
155 parse_nksip_media_attr(<<"fingerprint">>, [Hash, Fingerprint], Acc) ->
156
:-(
Transport = maps:get(transport, Acc, #{}),
157
:-(
Acc#{transport => Transport#{fingerprint => {Hash, Fingerprint}}};
158 parse_nksip_media_attr(<<"setup">>, [Value], Acc) ->
159
:-(
Transport = maps:get(transport, Acc, #{}),
160
:-(
Acc#{transport => Transport#{setup => Value}};
161 parse_nksip_media_attr(<<"rtcp-mux">>, _, Acc) ->
162
:-(
Acc#{rtcp_mux => true};
163 parse_nksip_media_attr(<<"extmap">>, [IDWithSender, URI], Acc) ->
164
:-(
{ID, Sender} = decode_extmap_id(IDWithSender),
165
:-(
RTPHdrExts = maps:get(rtphdr_ext, Acc, []),
166
:-(
Acc#{rtphdr_ext => [{ID, Sender, URI} | RTPHdrExts]};
167 parse_nksip_media_attr(<<"ssrc">>, [ID | Parameter], Acc) ->
168
:-(
SourceMap = maps:get(source_map, Acc, #{}),
169
:-(
SourceParams = maps:get(ID, SourceMap, []),
170
:-(
Param = decode_ssrc_sdp_param(Parameter),
171
:-(
NewSourceParams = [Param | SourceParams],
172
:-(
NewSourceMap = SourceMap#{ID => NewSourceParams},
173
:-(
Acc#{source_map => NewSourceMap};
174 parse_nksip_media_attr(<<"mid">>, [Name], Acc) ->
175
:-(
Acc#{name => Name};
176 parse_nksip_media_attr(_, _, Acc) ->
177
:-(
Acc.
178
179 decode_extmap_id(IDWithSender) ->
180
:-(
case binary:split(IDWithSender, <<$/>>) of
181 [ID] ->
182
:-(
{ID, <<"both">>};
183 [ID, Sender] ->
184
:-(
{ID, decode_sender(Sender)}
185 end.
186
187
:-(
decode_sender(<<"sendrecv">>) -> <<"both">>;
188
:-(
decode_sender(<<"recvonly">>) -> <<"responder">>;
189
:-(
decode_sender(<<"sendonly">>) -> <<"initiator">>;
190
:-(
decode_sender(<<"inactive">>) -> <<"none">>.
191
192 description_elements_from_content(Content) ->
193
:-(
RTPHdrExts = [rtphdr_ext_to_element(Ext) || Ext <- maps:get(rtphdr_ext, Content, [])],
194
:-(
ElsWithRtcpMux = maybe_add_rtcp_mux(Content, RTPHdrExts),
195
:-(
maybe_add_sources(Content, ElsWithRtcpMux).
196
197 rtphdr_ext_to_element({ID, Sender, URI}) ->
198
:-(
#xmlel{name = <<"rtp-hdrext">>,
199 attrs = [{<<"xmlns">>, <<"urn:xmpp:jingle:apps:rtp:rtp-hdrext:0">>},
200 {<<"id">>, ID},
201 {<<"uri">>, URI},
202 {<<"senders">>, Sender}]}.
203
204 maybe_add_rtcp_mux(#{rtcp_mux := true}, Els) ->
205
:-(
El = #xmlel{name = <<"rtcp-mux">>},
206
:-(
[El | Els];
207 maybe_add_rtcp_mux(_, Els) ->
208
:-(
Els.
209
210 parse_candidate_extra_args([], Candidate) ->
211
:-(
Candidate;
212 parse_candidate_extra_args([<<"typ">>, Value | Rest], Candidate) ->
213
:-(
NewCandidate = Candidate#{type => Value},
214
:-(
parse_candidate_extra_args(Rest, NewCandidate);
215 parse_candidate_extra_args([<<"raddr">>, Value | Rest], Candidate) ->
216
:-(
NewCandidate = Candidate#{raddr => Value},
217
:-(
parse_candidate_extra_args(Rest, NewCandidate);
218 parse_candidate_extra_args([<<"rport">>, Value | Rest], Candidate) ->
219
:-(
NewCandidate = Candidate#{rport => Value},
220
:-(
parse_candidate_extra_args(Rest, NewCandidate);
221 parse_candidate_extra_args([<<"generation">>, Value | Rest], Candidate) ->
222
:-(
NewCandidate = Candidate#{generation => Value},
223
:-(
parse_candidate_extra_args(Rest, NewCandidate);
224 parse_candidate_extra_args([<<"tcptype">>, Value | Rest], Candidate) ->
225
:-(
NewCandidate = Candidate#{tcptype => Value},
226
:-(
parse_candidate_extra_args(Rest, NewCandidate);
227 parse_candidate_extra_args(Rest, Candidate) ->
228
:-(
?LOG_WARNING(#{what => sip_unrecognised_candidate_extra_args,
229 text => <<"Unrecognised candidate extra arg">>,
230
:-(
candidate => Candidate, extra_args => Rest}),
231
:-(
Candidate.
232
233
234 make_transport_el(Transport) ->
235
:-(
CandidateElements = [make_candidate_el(Candidate) || Candidate <- maps:get(candidates, Transport, [])],
236
:-(
AttrsWithUfrag = maybe_add_ice_ufrag(maps:get(ufrag, Transport, undefined), []),
237
:-(
ICEAttrs = maybe_add_ice_pwd(maps:get(pwd, Transport, undefined), AttrsWithUfrag),
238
239
:-(
El = #xmlel{name = <<"transport">>,
240 attrs = [{<<"xmlns">>, <<"urn:xmpp:jingle:transports:ice-udp:1">>} |
241 ICEAttrs],
242 children = CandidateElements},
243
:-(
maybe_add_fingerprint_el(Transport, El).
244
245 make_candidate_el(Candidate) ->
246
:-(
Attrs = maps:fold(fun candidate_kv_to_attr/3, [], Candidate),
247
:-(
#xmlel{name = <<"candidate">>,
248 attrs = Attrs}.
249
250 candidate_kv_to_attr(raddr, Value, Acc) ->
251
:-(
[{<<"rel-addr">>, Value} | Acc];
252 candidate_kv_to_attr(rport, Value, Acc) ->
253
:-(
[{<<"rel-port">>, Value} | Acc];
254 candidate_kv_to_attr(Key, Value, Acc) ->
255
:-(
[{erlang:atom_to_binary(Key, utf8), Value} | Acc].
256
257 maybe_add_ice_ufrag(undefined, Attrs) ->
258
:-(
Attrs;
259 maybe_add_ice_ufrag(Ufrag, Attrs) ->
260
:-(
[{<<"ufrag">>, Ufrag} | Attrs].
261
262 maybe_add_ice_pwd(undefined, Attrs) ->
263
:-(
Attrs;
264 maybe_add_ice_pwd(Pwd, Attrs) ->
265
:-(
[{<<"pwd">>, Pwd} | Attrs].
266
267
268 maybe_add_fingerprint_el(#{fingerprint := {Hash, Fingerprint}} = Transport,
269 #xmlel{children = Children} = El) ->
270
:-(
Attrs = [{<<"xmlns">>, <<"urn:xmpp:jingle:apps:dtls:0">>},
271 {<<"hash">>, Hash}],
272
:-(
AllAttrs = maybe_add_setup_attr(maps:get(setup, Transport, undefined), Attrs),
273
:-(
FingerprintEl = #xmlel{name = <<"fingerprint">>,
274 attrs = AllAttrs,
275 children = [#xmlcdata{content = Fingerprint}]},
276
:-(
El#xmlel{children = [FingerprintEl | Children]}.
277
278 maybe_add_setup_attr(undefined, Attrs) ->
279
:-(
Attrs;
280 maybe_add_setup_attr(Setup, Attrs) ->
281
:-(
[{<<"setup">>, Setup} | Attrs].
282
283 decode_ssrc_sdp_param(Parameter) ->
284
:-(
Bin = list_to_binary(lists:join(" ", Parameter)),
285
:-(
case binary:split(Bin, <<$:>>) of
286 [Attr] ->
287
:-(
Attr;
288 [Attr, Value] ->
289
:-(
{Attr, Value}
290 end.
291
292 maybe_add_sources(#{source_map := SourceMap}, Els) ->
293
:-(
SourceEls = [source_to_el(SSRC, Params) || {SSRC, Params} <- maps:to_list(SourceMap)],
294
:-(
Els ++ SourceEls;
295 maybe_add_sources(_, Els) ->
296
:-(
Els.
297
298 source_to_el(SSRC, Params) ->
299
:-(
Parameters = [ssrc_attr_to_el(Attr) || Attr <- Params],
300
:-(
#xmlel{name = <<"source">>,
301 attrs = [{<<"xmlns">>, <<"urn:xmpp:jingle:apps:rtp:ssma:0">>},
302 {<<"ssrc">>, SSRC}],
303 children = Parameters}.
304
305 ssrc_attr_to_el(Attr) ->
306
:-(
Attrs = make_el_attrs_from_ssrc(Attr),
307
:-(
#xmlel{name = <<"parameter">>,
308 attrs = Attrs}.
309
310 make_el_attrs_from_ssrc({Attr, Value}) ->
311
:-(
[{<<"name">>, Attr},
312 {<<"value">>, Value}];
313 make_el_attrs_from_ssrc(Attr) ->
314
:-(
[{<<"name">>, Attr}].
315
316
Line Hits Source