6 * Copyright (C) 2010 Jakub Adam <jakub.adam@tieto.com>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
32 #include "sipe-common.h"
34 #include "sip-transport.h"
35 #include "sipe-backend.h"
36 #include "sipe-core.h"
37 #include "sipe-core-private.h"
38 #include "sipe-dialog.h"
39 #include "sipe-media.h"
40 #include "sipe-session.h"
41 #include "sipe-utils.h"
45 struct sipe_media_call_private
{
46 struct sipe_media_call
public;
48 /* private part starts here */
49 struct sipe_core_private
*sipe_private
;
50 struct sip_session
*session
;
51 struct sip_dialog
*dialog
;
53 struct sipe_backend_stream
*voice_stream
;
59 struct sipmsg
*invitation
;
60 GList
*remote_candidates
;
64 #define SIPE_MEDIA_CALL ((struct sipe_media_call *) call_private)
65 #define SIPE_MEDIA_CALL_PRIVATE ((struct sipe_media_call_private *) call)
68 sipe_media_get_callid(struct sipe_media_call_private
*call
)
70 return call
->dialog
->callid
;
73 static void sipe_media_codec_list_free(GList
*codecs
)
75 for (; codecs
; codecs
= g_list_delete_link(codecs
, codecs
))
76 sipe_backend_codec_free(codecs
->data
);
79 static void sipe_media_candidate_list_free(GList
*candidates
)
81 for (; candidates
; candidates
= g_list_delete_link(candidates
, candidates
))
82 sipe_backend_candidate_free(candidates
->data
);
86 sipe_media_call_free(struct sipe_media_call_private
*call_private
)
89 sipe_utils_nameval_free(call_private
->sdp_attrs
);
90 if (call_private
->invitation
)
91 sipmsg_free(call_private
->invitation
);
92 sipe_media_codec_list_free(call_private
->public.remote_codecs
);
93 sipe_media_candidate_list_free(call_private
->remote_candidates
);
99 sipe_media_parse_codecs(GSList
*sdp_attrs
)
103 GList
*codecs
= NULL
;
105 while ((attr
= sipe_utils_nameval_find_instance(sdp_attrs
, "rtpmap", i
++))) {
106 gchar
**tokens
= g_strsplit_set(attr
, " /", 3);
108 int id
= atoi(tokens
[0]);
109 gchar
*name
= tokens
[1];
110 int clock_rate
= atoi(tokens
[2]);
111 SipeMediaType type
= SIPE_MEDIA_AUDIO
;
113 struct sipe_backend_codec
*codec
= sipe_backend_codec_new(id
, name
, clock_rate
, type
);
115 // TODO: more secure and effective implementation
118 while((params
= sipe_utils_nameval_find_instance(sdp_attrs
, "fmtp", j
++))) {
119 gchar
**tokens
= g_strsplit_set(params
, " ", 0);
120 gchar
**next
= tokens
+ 1;
122 if (atoi(tokens
[0]) == id
) {
127 if (sscanf(*next
, "%[a-zA-Z0-9]=%s", name
, value
) == 2)
128 sipe_backend_codec_add_optional_parameter(codec
, name
, value
);
137 codecs
= g_list_append(codecs
, codec
);
145 codec_name_compare(struct sipe_backend_codec
*codec1
, struct sipe_backend_codec
*codec2
)
147 gchar
*name1
= sipe_backend_codec_get_name(codec1
);
148 gchar
*name2
= sipe_backend_codec_get_name(codec2
);
150 gint result
= g_strcmp0(name1
, name2
);
159 sipe_media_prune_remote_codecs(GList
*local_codecs
, GList
*remote_codecs
)
161 GList
*remote_codecs_head
= remote_codecs
;
162 GList
*pruned_codecs
= NULL
;
164 while (remote_codecs
) {
165 struct sipe_backend_codec
*c
= remote_codecs
->data
;
167 if (g_list_find_custom(local_codecs
, c
, (GCompareFunc
)codec_name_compare
)) {
168 pruned_codecs
= g_list_append(pruned_codecs
, c
);
169 remote_codecs
->data
= NULL
;
171 remote_codecs
= remote_codecs
->next
;
174 sipe_media_codec_list_free(remote_codecs_head
);
176 return pruned_codecs
;
180 sipe_media_parse_remote_candidates_legacy(gchar
*remote_ip
, guint16 remote_port
)
182 struct sipe_backend_candidate
*candidate
;
183 GList
*candidates
= NULL
;
185 candidate
= sipe_backend_candidate_new("foundation",
187 SIPE_CANDIDATE_TYPE_HOST
,
188 SIPE_NETWORK_PROTOCOL_UDP
,
189 remote_ip
, remote_port
);
190 candidates
= g_list_append(candidates
, candidate
);
192 candidate
= sipe_backend_candidate_new("foundation",
194 SIPE_CANDIDATE_TYPE_HOST
,
195 SIPE_NETWORK_PROTOCOL_UDP
,
196 remote_ip
, remote_port
+ 1);
197 candidates
= g_list_append(candidates
, candidate
);
203 sipe_media_parse_remote_candidates(GSList
*sdp_attrs
)
205 struct sipe_backend_candidate
*candidate
;
206 GList
*candidates
= NULL
;
210 const gchar
* username
= sipe_utils_nameval_find(sdp_attrs
, "ice-ufrag");
211 const gchar
* password
= sipe_utils_nameval_find(sdp_attrs
, "ice-pwd");
213 while ((attr
= sipe_utils_nameval_find_instance(sdp_attrs
, "candidate", i
++))) {
216 SipeComponentType component
;
217 SipeNetworkProtocol protocol
;
221 SipeCandidateType type
;
223 tokens
= g_strsplit_set(attr
, " ", 0);
225 foundation
= tokens
[0];
227 switch (atoi(tokens
[1])) {
229 component
= SIPE_COMPONENT_RTP
;
232 component
= SIPE_COMPONENT_RTCP
;
235 component
= SIPE_COMPONENT_NONE
;
238 if (sipe_strequal(tokens
[2], "UDP"))
239 protocol
= SIPE_NETWORK_PROTOCOL_UDP
;
241 // Ignore TCP candidates, at least for now...
242 // Also, if this is ICEv6 candidate list, candidates are dropped here
247 priority
= atoi(tokens
[3]);
249 port
= atoi(tokens
[5]);
251 if (sipe_strequal(tokens
[7], "host"))
252 type
= SIPE_CANDIDATE_TYPE_HOST
;
253 else if (sipe_strequal(tokens
[7], "relay"))
254 type
= SIPE_CANDIDATE_TYPE_RELAY
;
255 else if (sipe_strequal(tokens
[7], "srflx"))
256 type
= SIPE_CANDIDATE_TYPE_SRFLX
;
257 else if (sipe_strequal(tokens
[7], "prflx"))
258 type
= SIPE_CANDIDATE_TYPE_PRFLX
;
264 candidate
= sipe_backend_candidate_new(foundation
, component
,
265 type
, protocol
, ip
, port
);
266 sipe_backend_candidate_set_priority(candidate
, priority
);
267 candidates
= g_list_append(candidates
, candidate
);
273 GList
*it
= candidates
;
275 sipe_backend_candidate_set_username_and_pwd(it
->data
, username
, password
);
284 sipe_media_sdp_codec_ids_format(GList
*codecs
)
286 GString
*result
= g_string_new(NULL
);
289 struct sipe_backend_codec
*c
= codecs
->data
;
291 gchar
*tmp
= g_strdup_printf(" %d", sipe_backend_codec_get_id(c
));
292 g_string_append(result
,tmp
);
295 codecs
= codecs
->next
;
298 return g_string_free(result
, FALSE
);
302 sipe_media_sdp_codecs_format(GList
*codecs
)
304 GString
*result
= g_string_new(NULL
);
307 struct sipe_backend_codec
*c
= codecs
->data
;
308 GList
*params
= NULL
;
309 gchar
*name
= sipe_backend_codec_get_name(c
);
311 gchar
*tmp
= g_strdup_printf("a=rtpmap:%d %s/%d\r\n",
312 sipe_backend_codec_get_id(c
),
314 sipe_backend_codec_get_clock_rate(c
));
317 g_string_append(result
, tmp
);
320 if ((params
= sipe_backend_codec_get_optional_parameters(c
))) {
321 tmp
= g_strdup_printf("a=fmtp:%d",sipe_backend_codec_get_id(c
));
322 g_string_append(result
, tmp
);
326 struct sipnameval
* par
= params
->data
;
327 tmp
= g_strdup_printf(" %s=%s", par
->name
, par
->value
);
328 g_string_append(result
, tmp
);
330 params
= params
->next
;
332 g_string_append(result
, "\r\n");
335 codecs
= codecs
->next
;
338 return g_string_free(result
, FALSE
);
342 candidate_compare_by_component_id(struct sipe_backend_candidate
*c1
, struct sipe_backend_candidate
*c2
)
344 return sipe_backend_candidate_get_component_type(c1
)
345 - sipe_backend_candidate_get_component_type(c2
);
349 sipe_media_sdp_candidates_format(struct sipe_media_call_private
*call_private
, guint16
*local_port
)
351 struct sipe_backend_media
*backend_media
= call_private
->public.backend_private
;
352 struct sipe_backend_stream
*voice_stream
= call_private
->voice_stream
;
358 GString
*result
= g_string_new("");
360 guint16 rtcp_port
= 0;
362 // If we have established candidate pairs, send them in SDP response.
363 // Otherwise send all available local candidates.
364 l_candidates
= sipe_backend_media_get_active_local_candidates(backend_media
, voice_stream
);
366 l_candidates
= sipe_backend_get_local_candidates(backend_media
, voice_stream
);
368 // If in legacy mode, just fill local_port variable with local host's RTP
369 // component port and return empty string.
370 if (call_private
->legacy_mode
) {
371 for (cand
= l_candidates
; cand
; cand
= cand
->next
) {
372 struct sipe_backend_candidate
*c
= cand
->data
;
373 SipeCandidateType type
= sipe_backend_candidate_get_type(c
);
374 SipeComponentType component
= sipe_backend_candidate_get_component_type(c
);
376 if (type
== SIPE_CANDIDATE_TYPE_HOST
&& component
== SIPE_COMPONENT_RTP
) {
377 *local_port
= sipe_backend_candidate_get_port(c
);
382 sipe_media_candidate_list_free(l_candidates
);
384 return g_string_free(result
, FALSE
);
387 username
= sipe_backend_candidate_get_username(l_candidates
->data
);
388 password
= sipe_backend_candidate_get_password(l_candidates
->data
);
390 tmp
= g_strdup_printf("a=ice-ufrag:%s\r\na=ice-pwd:%s\r\n",username
, password
);
391 g_string_append(result
, tmp
);
397 for (cand
= l_candidates
; cand
; cand
= cand
->next
) {
398 struct sipe_backend_candidate
*c
= cand
->data
;
401 SipeComponentType component
;
405 component
= sipe_backend_candidate_get_component_type(c
);
406 port
= sipe_backend_candidate_get_port(c
);
408 switch (sipe_backend_candidate_get_protocol(c
)) {
409 case SIPE_NETWORK_PROTOCOL_TCP
:
412 case SIPE_NETWORK_PROTOCOL_UDP
:
417 switch (sipe_backend_candidate_get_type(c
)) {
418 case SIPE_CANDIDATE_TYPE_HOST
:
420 if (component
== SIPE_COMPONENT_RTP
)
422 else if (component
== SIPE_COMPONENT_RTCP
)
425 case SIPE_CANDIDATE_TYPE_RELAY
:
428 case SIPE_CANDIDATE_TYPE_SRFLX
:
431 case SIPE_CANDIDATE_TYPE_PRFLX
:
435 // TODO: error unknown/unsupported type
439 tmp
= g_strdup_printf("a=candidate:%s %u %s %u %s %d typ %s \r\n",
440 sipe_backend_candidate_get_foundation(c
),
443 sipe_backend_candidate_get_priority(c
),
444 sipe_backend_candidate_get_ip(c
),
448 g_string_append(result
, tmp
);
452 r_candidates
= sipe_backend_media_get_active_remote_candidates(backend_media
, voice_stream
);
453 r_candidates
= g_list_sort(r_candidates
, (GCompareFunc
)candidate_compare_by_component_id
);
456 g_string_append(result
, "a=remote-candidates:");
457 for (cand
= r_candidates
; cand
; cand
= cand
->next
) {
458 struct sipe_backend_candidate
*candidate
= cand
->data
;
459 tmp
= g_strdup_printf("%u %s %u ",
460 sipe_backend_candidate_get_component_type(candidate
),
461 sipe_backend_candidate_get_ip(candidate
),
462 sipe_backend_candidate_get_port(candidate
));
463 g_string_append(result
, tmp
);
466 g_string_append(result
, "\r\n");
469 sipe_media_candidate_list_free(l_candidates
);
470 sipe_media_candidate_list_free(r_candidates
);
472 if (rtcp_port
!= 0) {
473 tmp
= g_strdup_printf("a=maxptime:200\r\na=rtcp:%u\r\n", rtcp_port
);
474 g_string_append(result
, tmp
);
478 return g_string_free(result
, FALSE
);
482 sipe_media_create_sdp(struct sipe_media_call_private
*call_private
) {
483 GList
*usable_codecs
= sipe_backend_get_local_codecs(SIPE_MEDIA_CALL
,
484 call_private
->voice_stream
);
487 const char *ip
= sipe_utils_get_suitable_local_ip(-1);
488 guint16 local_port
= 0;
490 gchar
*sdp_codecs
= sipe_media_sdp_codecs_format(usable_codecs
);
491 gchar
*sdp_codec_ids
= sipe_media_sdp_codec_ids_format(usable_codecs
);
492 gchar
*sdp_candidates
= sipe_media_sdp_candidates_format(call_private
, &local_port
);
493 gchar
*inactive
= (call_private
->public.local_on_hold
||
494 call_private
->public.remote_on_hold
) ? "a=inactive\r\n" : "";
496 body
= g_strdup_printf(
498 "o=- 0 0 IN IP4 %s\r\n"
503 "m=audio %d RTP/AVP%s\r\n"
507 "a=encryption:rejected\r\n"
508 ,ip
, ip
, local_port
, sdp_codec_ids
, sdp_candidates
, inactive
, sdp_codecs
);
511 g_free(sdp_codec_ids
);
512 g_free(sdp_candidates
);
514 sipe_media_codec_list_free(usable_codecs
);
520 sipe_invite_call(struct sipe_core_private
*sipe_private
, TransCallback tc
)
525 struct sipe_media_call_private
*call_private
= sipe_private
->media_call
;
526 struct sip_dialog
*dialog
= call_private
->dialog
;
528 contact
= get_contact(sipe_private
);
529 hdr
= g_strdup_printf(
530 "Supported: ms-early-media\r\n"
531 "Supported: 100rel\r\n"
532 "ms-keep-alive: UAC;hop-hop=yes\r\n"
534 "Content-Type: application/sdp\r\n",
536 (call_private
->public.local_on_hold
|| call_private
->public.remote_on_hold
) ? ";+sip.rendering=\"no\"" : "");
539 body
= sipe_media_create_sdp(call_private
);
541 sip_transport_invite(sipe_private
,
552 sipe_media_parse_remote_codecs(struct sipe_media_call_private
*call_private
);
555 sipe_media_parse_sdp_attributes_and_candidates(struct sipe_media_call_private
*call_private
, gchar
*frame
) {
556 gchar
**lines
= g_strsplit(frame
, "\r\n", 0);
557 GSList
*sdp_attrs
= NULL
;
558 gchar
*remote_ip
= NULL
;
559 guint16 remote_port
= 0;
560 GList
*remote_candidates
;
562 gboolean no_error
= TRUE
;
564 for (ptr
= lines
; *ptr
!= NULL
; ++ptr
) {
565 if (g_str_has_prefix(*ptr
, "a=")) {
566 gchar
**parts
= g_strsplit(*ptr
+ 2, ":", 2);
569 sipe_utils_nameval_free(sdp_attrs
);
574 sdp_attrs
= sipe_utils_nameval_add(sdp_attrs
, parts
[0], parts
[1]);
577 } else if (g_str_has_prefix(*ptr
, "o=")) {
578 gchar
**parts
= g_strsplit(*ptr
+ 2, " ", 6);
579 remote_ip
= g_strdup(parts
[5]);
581 } else if (g_str_has_prefix(*ptr
, "m=")) {
582 gchar
**parts
= g_strsplit(*ptr
+ 2, " ", 3);
583 remote_port
= atoi(parts
[1]);
590 remote_candidates
= sipe_media_parse_remote_candidates(sdp_attrs
);
591 if (!remote_candidates
) {
592 // No a=candidate in SDP message, revert to OC2005 behaviour
593 remote_candidates
= sipe_media_parse_remote_candidates_legacy(remote_ip
, remote_port
);
594 // This seems to be pre-OC2007 R2 UAC
595 call_private
->legacy_mode
= TRUE
;
599 sipe_utils_nameval_free(call_private
->sdp_attrs
);
600 sipe_media_candidate_list_free(call_private
->remote_candidates
);
602 call_private
->sdp_attrs
= sdp_attrs
;
603 call_private
->remote_ip
= remote_ip
;
604 call_private
->remote_port
= remote_port
;
605 call_private
->remote_candidates
= remote_candidates
;
607 sipe_utils_nameval_free(sdp_attrs
);
608 sipe_media_candidate_list_free(remote_candidates
);
615 sipe_media_parse_remote_codecs(struct sipe_media_call_private
*call_private
)
617 GList
*local_codecs
= sipe_backend_get_local_codecs(SIPE_MEDIA_CALL
,
618 call_private
->voice_stream
);
619 GList
*remote_codecs
;
621 remote_codecs
= sipe_media_parse_codecs(call_private
->sdp_attrs
);
622 remote_codecs
= sipe_media_prune_remote_codecs(local_codecs
, remote_codecs
);
624 sipe_media_codec_list_free(local_codecs
);
627 sipe_media_codec_list_free(call_private
->public.remote_codecs
);
629 call_private
->public.remote_codecs
= remote_codecs
;
631 if (!sipe_backend_set_remote_codecs(SIPE_MEDIA_CALL
,
632 call_private
->voice_stream
)) {
633 SIPE_DEBUG_ERROR_NOFORMAT("ERROR SET REMOTE CODECS"); // TODO
639 sipe_media_codec_list_free(remote_codecs
);
640 SIPE_DEBUG_ERROR_NOFORMAT("ERROR NO CANDIDATES OR CODECS");
646 static struct sip_dialog
*
647 sipe_media_dialog_init(struct sip_session
* session
, struct sipmsg
*msg
)
649 gchar
*newTag
= gentag();
650 const gchar
*oldHeader
;
652 struct sip_dialog
*dialog
;
654 oldHeader
= sipmsg_find_header(msg
, "To");
655 newHeader
= g_strdup_printf("%s;tag=%s", oldHeader
, newTag
);
656 sipmsg_remove_header_now(msg
, "To");
657 sipmsg_add_header_now(msg
, "To", newHeader
);
660 dialog
= sipe_dialog_add(session
);
661 dialog
->callid
= g_strdup(session
->callid
);
662 dialog
->with
= parse_from(sipmsg_find_header(msg
, "From"));
663 sipe_dialog_parse(dialog
, msg
, FALSE
);
669 send_response_with_session_description(struct sipe_media_call_private
*call_private
, int code
, gchar
*text
)
671 gchar
*body
= sipe_media_create_sdp(call_private
);
672 sipmsg_add_header(call_private
->invitation
, "Content-Type", "application/sdp");
673 sip_transport_response(call_private
->sipe_private
, call_private
->invitation
, code
, text
, body
);
678 sipe_media_process_invite_response(struct sipe_core_private
*sipe_private
,
680 struct transaction
*trans
);
682 static void candidates_prepared_cb(struct sipe_media_call
*call
)
684 struct sipe_media_call_private
*call_private
= (struct sipe_media_call_private
*) call
;
686 if (sipe_backend_media_is_initiator(call_private
->public.backend_private
,
687 call_private
->voice_stream
)) {
688 sipe_invite_call(call_private
->sipe_private
, sipe_media_process_invite_response
);
690 if (!sipe_media_parse_remote_codecs(call_private
)) {
691 g_free(call_private
);
695 if (!call_private
->legacy_mode
)
696 send_response_with_session_description(call_private
, 183, "Session Progress");
700 static void media_connected_cb(SIPE_UNUSED_PARAMETER
struct sipe_media_call_private
*call_private
)
704 static void call_accept_cb(struct sipe_media_call
*call
, gboolean local
)
707 send_response_with_session_description(SIPE_MEDIA_CALL_PRIVATE
,
712 static void call_reject_cb(struct sipe_media_call
*call
, gboolean local
)
714 struct sipe_media_call_private
*call_private
= SIPE_MEDIA_CALL_PRIVATE
;
717 sip_transport_response(call_private
->sipe_private
, call_private
->invitation
, 603, "Decline", NULL
);
719 call_private
->sipe_private
->media_call
= NULL
;
720 sipe_media_call_free(call_private
);
724 sipe_media_send_ack(struct sipe_core_private
*sipe_private
, struct sipmsg
*msg
,
725 struct transaction
*trans
);
727 static void call_hold_cb(struct sipe_media_call
*call
, gboolean local
, gboolean state
)
729 struct sipe_media_call_private
*call_private
= SIPE_MEDIA_CALL_PRIVATE
;
731 if (local
&& (call_private
->public.local_on_hold
!= state
)) {
732 call_private
->public.local_on_hold
= state
;
733 sipe_invite_call(call_private
->sipe_private
, sipe_media_send_ack
);
734 } else if (call_private
->public.remote_on_hold
!= state
) {
735 call_private
->public.remote_on_hold
= state
;
736 send_response_with_session_description(call_private
, 200, "OK");
740 static void call_hangup_cb(struct sipe_media_call
*call
, gboolean local
)
742 struct sipe_media_call_private
*call_private
= SIPE_MEDIA_CALL_PRIVATE
;
745 sip_transport_bye(call_private
->sipe_private
, call_private
->dialog
);
747 call_private
->sipe_private
->media_call
= NULL
;
748 sipe_media_call_free(call_private
);
751 static struct sipe_media_call_private
*
752 sipe_media_call_init(struct sipe_core_private
*sipe_private
, const gchar
* participant
, gboolean initiator
)
754 struct sipe_media_call_private
*call_private
= g_new0(struct sipe_media_call_private
, 1);
756 call_private
->sipe_private
= sipe_private
;
757 call_private
->public.backend_private
= sipe_backend_media_new(SIPE_CORE_PUBLIC
,
762 call_private
->legacy_mode
= FALSE
;
763 call_private
->using_nice
= TRUE
;
765 call_private
->public.candidates_prepared_cb
= candidates_prepared_cb
;
766 call_private
->public.media_connected_cb
= media_connected_cb
;
767 call_private
->public.call_accept_cb
= call_accept_cb
;
768 call_private
->public.call_reject_cb
= call_reject_cb
;
769 call_private
->public.call_hold_cb
= call_hold_cb
;
770 call_private
->public.call_hangup_cb
= call_hangup_cb
;
772 call_private
->public.local_on_hold
= FALSE
;
773 call_private
->public.remote_on_hold
= FALSE
;
778 void sipe_media_hangup(struct sipe_core_private
*sipe_private
)
780 struct sipe_media_call_private
*call_private
= sipe_private
->media_call
;
782 sipe_backend_media_hangup(call_private
->public.backend_private
,
787 sipe_core_media_initiate_call(struct sipe_core_public
*sipe_public
,
788 const char *participant
)
790 struct sipe_core_private
*sipe_private
= SIPE_CORE_PRIVATE
;
791 struct sipe_media_call_private
*call_private
;
793 if (sipe_private
->media_call
)
796 call_private
= sipe_media_call_init(sipe_private
, participant
, TRUE
);
798 sipe_private
->media_call
= call_private
;
800 call_private
->session
= sipe_session_add_chat(sipe_private
);
801 call_private
->dialog
= sipe_dialog_add(call_private
->session
);
802 call_private
->dialog
->callid
= gencallid();
803 call_private
->dialog
->with
= g_strdup(participant
);
804 call_private
->dialog
->ourtag
= gentag();
806 call_private
->voice_stream
=
807 sipe_backend_media_add_stream(call_private
->public.backend_private
,
810 call_private
->using_nice
, TRUE
);
815 sipe_media_incoming_invite(struct sipe_core_private
*sipe_private
,
818 const gchar
*callid
= sipmsg_find_header(msg
, "Call-ID");
820 struct sipe_media_call_private
*call_private
= sipe_private
->media_call
;
821 struct sip_session
*session
;
822 struct sip_dialog
*dialog
;
825 if (sipe_strequal(call_private
->dialog
->callid
, callid
)) {
826 if (call_private
->invitation
)
827 sipmsg_free(call_private
->invitation
);
828 call_private
->invitation
= sipmsg_copy(msg
);
830 sipe_utils_nameval_free(call_private
->sdp_attrs
);
831 call_private
->sdp_attrs
= NULL
;
832 if (!sipe_media_parse_sdp_attributes_and_candidates(call_private
,
833 call_private
->invitation
->body
)) {
834 // TODO: handle error
836 if (!sipe_media_parse_remote_codecs(call_private
)) {
837 g_free(call_private
);
841 if (call_private
->legacy_mode
&& !call_private
->public.remote_on_hold
) {
842 sipe_backend_media_hold(call_private
->public.backend_private
,
844 } else if (sipe_utils_nameval_find(call_private
->sdp_attrs
, "inactive")) {
845 sipe_backend_media_hold(call_private
->public.backend_private
, FALSE
);
846 } else if (call_private
->public.remote_on_hold
) {
847 sipe_backend_media_unhold(call_private
->public.backend_private
, FALSE
);
849 send_response_with_session_description(call_private
,
853 sip_transport_response(sipe_private
, msg
, 486, "Busy Here", NULL
);
858 session
= sipe_session_find_or_add_chat_by_callid(sipe_private
, callid
);
859 dialog
= sipe_media_dialog_init(session
, msg
);
861 call_private
= sipe_media_call_init(sipe_private
, dialog
->with
, FALSE
);
862 call_private
->invitation
= sipmsg_copy(msg
);
863 call_private
->session
= session
;
864 call_private
->dialog
= dialog
;
866 sipe_private
->media_call
= call_private
;
868 if (!sipe_media_parse_sdp_attributes_and_candidates(call_private
, msg
->body
)) {
872 call_private
->voice_stream
=
873 sipe_backend_media_add_stream(call_private
->public.backend_private
,
876 !call_private
->legacy_mode
, FALSE
);
877 sipe_backend_media_add_remote_candidates(call_private
->public.backend_private
,
878 call_private
->voice_stream
,
879 call_private
->remote_candidates
);
881 sip_transport_response(sipe_private
, call_private
->invitation
, 180, "Ringing", NULL
);
883 // Processing continues in candidates_prepared_cb
887 sipe_media_send_ack(struct sipe_core_private
*sipe_private
,
888 SIPE_UNUSED_PARAMETER
struct sipmsg
*msg
,
889 struct transaction
*trans
)
891 struct sipe_media_call_private
*call_private
= sipe_private
->media_call
;
892 struct sip_dialog
*dialog
;
896 if (!call_private
|| !call_private
->dialog
)
899 dialog
= call_private
->dialog
;
900 tmp_cseq
= dialog
->cseq
;
902 sscanf(trans
->key
, "<%*[a-zA-Z0-9]><%d INVITE>", &trans_cseq
);
903 dialog
->cseq
= trans_cseq
- 1;
904 sip_transport_ack(sipe_private
, dialog
);
905 dialog
->cseq
= tmp_cseq
;
911 sipe_media_process_invite_response(struct sipe_core_private
*sipe_private
,
913 struct transaction
*trans
)
915 const gchar
*callid
= sipmsg_find_header(msg
, "Call-ID");
917 struct sipe_media_call_private
*call_private
= sipe_private
->media_call
;
918 struct sipe_backend_media
*backend_private
;
921 !sipe_strequal(sipe_media_get_callid(call_private
), callid
))
924 backend_private
= call_private
->public.backend_private
;
925 with
= call_private
->dialog
->with
;
927 if (msg
->response
== 603 || msg
->response
== 605 || msg
->response
== 480) {
928 // Call rejected by remote peer
932 sipe_backend_media_reject(backend_private
, FALSE
);
933 sipe_media_send_ack(sipe_private
, msg
, trans
);
935 if (msg
->response
> 600) {
936 title
= _("Call rejected");
937 errmsg
= g_strdup_printf(_("User %s rejected call"), with
);
939 errmsg
= g_strdup_printf(_("User %s is not available"), with
);
940 title
= _("User unavailable");
942 sipe_backend_notify_error(title
, errmsg
);
948 if (!sipe_media_parse_sdp_attributes_and_candidates(call_private
, msg
->body
)) {
952 if (!sipe_media_parse_remote_codecs(call_private
)) {
953 g_free(call_private
);
957 sipe_backend_media_add_remote_candidates(backend_private
,
958 call_private
->voice_stream
,
959 call_private
->remote_candidates
);
961 sipe_dialog_parse(call_private
->dialog
, msg
, TRUE
);
963 if (msg
->response
== 183) {
964 // Session in progress
965 const gchar
*rseq
= sipmsg_find_header(msg
, "RSeq");
966 const gchar
*cseq
= sipmsg_find_header(msg
, "CSeq");
967 gchar
*rack
= g_strdup_printf("RAck: %s %s\r\n", rseq
, cseq
);
968 sip_transport_request(sipe_private
,
974 call_private
->dialog
,
978 sipe_media_send_ack(sipe_private
, msg
, trans
);
980 if (call_private
->legacy_mode
&& call_private
->using_nice
) {
981 // We created non-legacy stream as we don't know which version of
982 // client is on the other side until first SDP response is received.
983 // This client requires legacy mode, so we must remove current session
984 // (using ICE) and create new using raw UDP transport.
985 struct sipe_backend_stream
*new_stream
;
987 call_private
->using_nice
= FALSE
;
989 new_stream
= sipe_backend_media_add_stream(backend_private
,
995 sipe_backend_media_remove_stream(backend_private
,
996 call_private
->voice_stream
);
997 call_private
->voice_stream
= new_stream
;
999 if (!sipe_media_parse_sdp_attributes_and_candidates(call_private
, msg
->body
)) {
1003 if (!sipe_media_parse_remote_codecs(call_private
)) {
1004 g_free(call_private
);
1008 sipe_backend_media_add_remote_candidates(backend_private
,
1009 call_private
->voice_stream
,
1010 call_private
->remote_candidates
);
1012 // New INVITE will be sent in candidates_prepared_cb
1014 sipe_invite_call(sipe_private
, sipe_media_send_ack
);