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
31 #include "sipe-common.h"
33 #include "sip-transport.h"
34 #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"
44 struct sipe_media_call_private
{
45 struct sipe_media_call
public;
47 /* private part starts here */
48 struct sipe_core_private
*sipe_private
;
51 struct sipmsg
*invitation
;
54 gboolean encryption_compatible
;
58 #define SIPE_MEDIA_CALL ((struct sipe_media_call *) call_private)
59 #define SIPE_MEDIA_CALL_PRIVATE ((struct sipe_media_call_private *) call)
61 static void sipe_media_codec_list_free(GList
*codecs
)
63 for (; codecs
; codecs
= g_list_delete_link(codecs
, codecs
))
64 sipe_backend_codec_free(codecs
->data
);
67 static void sipe_media_candidate_list_free(GList
*candidates
)
69 for (; candidates
; candidates
= g_list_delete_link(candidates
, candidates
))
70 sipe_backend_candidate_free(candidates
->data
);
74 sipe_media_call_free(struct sipe_media_call_private
*call_private
)
77 struct sip_session
*session
;
78 sipe_backend_media_free(call_private
->public.backend_private
);
80 session
= sipe_session_find_call(call_private
->sipe_private
,
83 sipe_session_remove(call_private
->sipe_private
, session
);
85 if (call_private
->invitation
)
86 sipmsg_free(call_private
->invitation
);
88 sdpmsg_free(call_private
->smsg
);
89 g_free(call_private
->with
);
95 backend_candidates_to_sdpcandidate(GList
*candidates
)
97 GSList
*result
= NULL
;
100 for (i
= candidates
; i
; i
= i
->next
) {
101 struct sipe_backend_candidate
*candidate
= i
->data
;
102 struct sdpcandidate
*c
= g_new(struct sdpcandidate
, 1);
104 c
->foundation
= sipe_backend_candidate_get_foundation(candidate
);
105 c
->component
= sipe_backend_candidate_get_component_type(candidate
);
106 c
->type
= sipe_backend_candidate_get_type(candidate
);
107 c
->protocol
= sipe_backend_candidate_get_protocol(candidate
);
108 c
->ip
= sipe_backend_candidate_get_ip(candidate
);
109 c
->port
= sipe_backend_candidate_get_port(candidate
);
110 c
->base_ip
= sipe_backend_candidate_get_base_ip(candidate
);
111 c
->base_port
= sipe_backend_candidate_get_base_port(candidate
);
112 c
->priority
= sipe_backend_candidate_get_priority(candidate
);
114 result
= g_slist_append(result
, c
);
120 static struct sdpmedia
*
121 backend_stream_to_sdpmedia(struct sipe_media_call_private
*call_private
,
122 struct sipe_backend_stream
*backend_stream
)
124 struct sipe_backend_media
*backend_media
= call_private
->public.backend_private
;
125 struct sdpmedia
*media
= g_new0(struct sdpmedia
, 1);
126 GList
*codecs
= sipe_backend_get_local_codecs(SIPE_MEDIA_CALL
,
130 GSList
*attributes
= NULL
;
135 media
->name
= g_strdup(sipe_backend_stream_get_id(backend_stream
));
137 if (sipe_strequal(media
->name
, "audio"))
138 type
= SIPE_MEDIA_AUDIO
;
139 else if (sipe_strequal(media
->name
, "video"))
140 type
= SIPE_MEDIA_VIDEO
;
142 // TODO: incompatible media, should not happen here
146 for (i
= codecs
; i
; i
= i
->next
) {
147 struct sipe_backend_codec
*codec
= i
->data
;
148 struct sdpcodec
*c
= g_new0(struct sdpcodec
, 1);
151 c
->id
= sipe_backend_codec_get_id(codec
);
152 c
->name
= sipe_backend_codec_get_name(codec
);
153 c
->clock_rate
= sipe_backend_codec_get_clock_rate(codec
);
156 params
= sipe_backend_codec_get_optional_parameters(codec
);
157 for (; params
; params
= params
->next
) {
158 struct sipnameval
*param
= params
->data
;
159 struct sipnameval
*copy
= g_new0(struct sipnameval
, 1);
161 copy
->name
= g_strdup(param
->name
);
162 copy
->value
= g_strdup(param
->value
);
164 c
->parameters
= g_slist_append(c
->parameters
, copy
);
167 media
->codecs
= g_slist_append(media
->codecs
, c
);
170 sipe_media_codec_list_free(codecs
);
172 // Process local candidates
173 // If we have established candidate pairs, send them in SDP response.
174 // Otherwise send all available local candidates.
175 candidates
= sipe_backend_media_get_active_local_candidates(backend_media
,
178 candidates
= sipe_backend_get_local_candidates(backend_media
,
181 media
->candidates
= backend_candidates_to_sdpcandidate(candidates
);
183 // Process stream attributes
184 if (!call_private
->legacy_mode
) {
185 struct sipe_backend_candidate
*candidate
= candidates
->data
;
187 gchar
*username
= sipe_backend_candidate_get_username(candidate
);
188 gchar
*password
= sipe_backend_candidate_get_password(candidate
);
190 attributes
= sipe_utils_nameval_add(attributes
,
191 "ice-ufrag", username
);
192 attributes
= sipe_utils_nameval_add(attributes
,
193 "ice-pwd", password
);
199 sipe_media_candidate_list_free(candidates
);
201 for (j
= media
->candidates
; j
; j
= j
->next
) {
202 struct sdpcandidate
*candidate
= j
->data
;
204 if (candidate
->type
== SIPE_CANDIDATE_TYPE_HOST
) {
205 if (candidate
->component
== SIPE_COMPONENT_RTP
)
206 media
->port
= candidate
->port
;
207 else if (candidate
->component
== SIPE_COMPONENT_RTCP
)
208 rtcp_port
= candidate
->port
;
212 if (sipe_backend_stream_is_held(backend_stream
))
213 attributes
= sipe_utils_nameval_add(attributes
, "inactive", "");
216 gchar
*tmp
= g_strdup_printf("%u", rtcp_port
);
217 attributes
= sipe_utils_nameval_add(attributes
, "rtcp", tmp
);
221 attributes
= sipe_utils_nameval_add(attributes
, "encryption", "rejected");
223 media
->attributes
= attributes
;
225 // Process remote candidates
226 candidates
= sipe_backend_media_get_active_remote_candidates(backend_media
,
228 media
->remote_candidates
= backend_candidates_to_sdpcandidate(candidates
);
229 sipe_media_candidate_list_free(candidates
);
234 static struct sdpmsg
*
235 sipe_media_to_sdpmsg(struct sipe_media_call_private
*call_private
)
237 struct sdpmsg
*msg
= g_new0(struct sdpmsg
, 1);
238 GSList
*streams
= sipe_backend_media_get_streams(call_private
->public.backend_private
);
240 for (; streams
; streams
= streams
->next
) {
241 struct sdpmedia
*media
;
242 media
= backend_stream_to_sdpmedia(call_private
, streams
->data
);
243 msg
->media
= g_slist_append(msg
->media
, media
);
246 msg
->legacy
= call_private
->legacy_mode
;
247 msg
->ip
= g_strdup(sipe_utils_get_suitable_local_ip(-1));
253 sipe_invite_call(struct sipe_core_private
*sipe_private
, TransCallback tc
)
258 struct sipe_media_call_private
*call_private
= sipe_private
->media_call
;
259 struct sip_session
*session
;
260 struct sip_dialog
*dialog
;
263 session
= sipe_session_find_call(sipe_private
, call_private
->with
);
264 dialog
= session
->dialogs
->data
;
266 contact
= get_contact(sipe_private
);
267 hdr
= g_strdup_printf(
268 "Supported: ms-early-media\r\n"
269 "Supported: 100rel\r\n"
270 "ms-keep-alive: UAC;hop-hop=yes\r\n"
272 "Content-Type: application/sdp\r\n",
276 msg
= sipe_media_to_sdpmsg(call_private
);
277 body
= sdpmsg_to_string(msg
);
280 dialog
->outgoing_invite
= sip_transport_invite(sipe_private
,
290 static struct sip_dialog
*
291 sipe_media_dialog_init(struct sip_session
* session
, struct sipmsg
*msg
)
293 gchar
*newTag
= gentag();
294 const gchar
*oldHeader
;
296 struct sip_dialog
*dialog
;
298 oldHeader
= sipmsg_find_header(msg
, "To");
299 newHeader
= g_strdup_printf("%s;tag=%s", oldHeader
, newTag
);
300 sipmsg_remove_header_now(msg
, "To");
301 sipmsg_add_header_now(msg
, "To", newHeader
);
304 dialog
= sipe_dialog_add(session
);
305 dialog
->callid
= g_strdup(sipmsg_find_header(msg
, "Call-ID"));
306 dialog
->with
= parse_from(sipmsg_find_header(msg
, "From"));
307 sipe_dialog_parse(dialog
, msg
, FALSE
);
313 send_response_with_session_description(struct sipe_media_call_private
*call_private
, int code
, gchar
*text
)
315 struct sdpmsg
*msg
= sipe_media_to_sdpmsg(call_private
);
316 gchar
*body
= sdpmsg_to_string(msg
);
318 sipmsg_add_header(call_private
->invitation
, "Content-Type", "application/sdp");
319 sip_transport_response(call_private
->sipe_private
, call_private
->invitation
, code
, text
, body
);
324 encryption_levels_compatible(struct sdpmsg
*msg
)
328 for (i
= msg
->media
; i
; i
= i
->next
) {
329 const gchar
*enc_level
;
330 struct sdpmedia
*m
= i
->data
;
332 enc_level
= sipe_utils_nameval_find(m
->attributes
, "encryption");
334 // Decline call if peer requires encryption as we don't support it yet.
335 if (sipe_strequal(enc_level
, "required"))
343 handle_incompatible_encryption_level(struct sipe_media_call_private
*call_private
)
345 sipmsg_add_header(call_private
->invitation
, "Warning",
346 "308 lcs.microsoft.com \"Encryption Levels not compatible\"");
347 sip_transport_response(call_private
->sipe_private
,
348 call_private
->invitation
,
349 488, "Encryption Levels not compatible",
351 sipe_backend_media_reject(call_private
->public.backend_private
, FALSE
);
352 sipe_backend_notify_error(_("Unable to establish a call"),
353 _("Encryption settings of peer are incompatible with ours."));
357 process_invite_call_response(struct sipe_core_private
*sipe_private
,
359 struct transaction
*trans
);
362 update_remote_media(struct sipe_media_call_private
* call_private
,
363 struct sdpmedia
*media
)
365 struct sipe_backend_media
*backend_media
= SIPE_MEDIA_CALL
->backend_private
;
366 struct sipe_backend_stream
*backend_stream
;
367 GList
*backend_candidates
= NULL
;
368 GList
*backend_codecs
= NULL
;
369 const gchar
*username
= sipe_utils_nameval_find(media
->attributes
, "ice-ufrag");
370 const gchar
*password
= sipe_utils_nameval_find(media
->attributes
, "ice-pwd");
372 gboolean result
= TRUE
;
374 backend_stream
= sipe_backend_media_get_stream_by_id(backend_media
,
376 if (media
->port
== 0) {
378 sipe_backend_media_remove_stream(backend_media
, backend_stream
);
386 for (i
= media
->candidates
; i
; i
= i
->next
) {
387 struct sdpcandidate
*c
= i
->data
;
388 struct sipe_backend_candidate
*candidate
;
389 candidate
= sipe_backend_candidate_new(c
->foundation
,
395 sipe_backend_candidate_set_priority(candidate
, c
->priority
);
398 sipe_backend_candidate_set_username_and_pwd(candidate
,
402 backend_candidates
= g_list_append(backend_candidates
, candidate
);
405 sipe_backend_media_add_remote_candidates(backend_media
,
408 sipe_media_candidate_list_free(backend_candidates
);
410 for (i
= media
->codecs
; i
; i
= i
->next
) {
411 struct sdpcodec
*c
= i
->data
;
412 struct sipe_backend_codec
*codec
;
415 codec
= sipe_backend_codec_new(c
->id
,
420 for (j
= c
->parameters
; j
; j
= j
->next
) {
421 struct sipnameval
*attr
= j
->data
;
423 sipe_backend_codec_add_optional_parameter(codec
,
428 backend_codecs
= g_list_append(backend_codecs
, codec
);
431 result
= sipe_backend_set_remote_codecs(backend_media
,
434 sipe_media_codec_list_free(backend_codecs
);
436 if (sipe_utils_nameval_find(media
->attributes
, "inactive")) {
437 sipe_backend_stream_hold(backend_media
, backend_stream
, FALSE
);
438 } else if (sipe_backend_stream_is_held(backend_stream
)) {
439 sipe_backend_stream_unhold(backend_media
, backend_stream
, FALSE
);
446 apply_remote_message(struct sipe_media_call_private
* call_private
,
450 for (i
= msg
->media
; i
; i
= i
->next
) {
451 if (!update_remote_media(call_private
, i
->data
))
455 call_private
->legacy_mode
= msg
->legacy
;
456 call_private
->encryption_compatible
= encryption_levels_compatible(msg
);
461 void do_apply_remote_message(struct sipe_media_call_private
*call_private
,
464 if (!apply_remote_message(call_private
, smsg
)) {
465 sip_transport_response(call_private
->sipe_private
,
466 call_private
->invitation
,
467 487, "Request Terminated", NULL
);
468 sipe_media_hangup(call_private
->sipe_private
);
472 sdpmsg_free(call_private
->smsg
);
473 call_private
->smsg
= NULL
;
475 if (sipe_backend_media_accepted(call_private
->public.backend_private
)) {
476 send_response_with_session_description(call_private
,
481 if (!call_private
->legacy_mode
&& call_private
->encryption_compatible
)
482 send_response_with_session_description(call_private
,
483 183, "Session Progress");
486 static void candidates_prepared_cb(struct sipe_media_call
*call
,
487 struct sipe_backend_stream
*stream
)
489 struct sipe_media_call_private
*call_private
= SIPE_MEDIA_CALL_PRIVATE
;
491 if (sipe_backend_media_is_initiator(call_private
->public.backend_private
,
493 sipe_invite_call(call_private
->sipe_private
,
494 process_invite_call_response
);
497 struct sdpmsg
*smsg
= call_private
->smsg
;
498 call_private
->smsg
= NULL
;
500 do_apply_remote_message(call_private
, smsg
);
501 sdpmsg_free(call_private
->smsg
);
505 static void media_connected_cb(SIPE_UNUSED_PARAMETER
struct sipe_media_call_private
*call_private
)
509 static void call_accept_cb(struct sipe_media_call
*call
, gboolean local
)
512 struct sipe_media_call_private
*call_private
= SIPE_MEDIA_CALL_PRIVATE
;
514 if (!call_private
->encryption_compatible
) {
515 handle_incompatible_encryption_level(call_private
);
519 send_response_with_session_description(call_private
, 200, "OK");
523 static void call_reject_cb(struct sipe_media_call
*call
, gboolean local
)
525 struct sipe_media_call_private
*call_private
= SIPE_MEDIA_CALL_PRIVATE
;
528 sip_transport_response(call_private
->sipe_private
, call_private
->invitation
, 603, "Decline", NULL
);
530 call_private
->sipe_private
->media_call
= NULL
;
531 sipe_media_call_free(call_private
);
535 sipe_media_send_ack(struct sipe_core_private
*sipe_private
, struct sipmsg
*msg
,
536 struct transaction
*trans
);
538 static void call_hold_cb(struct sipe_media_call
*call
,
540 SIPE_UNUSED_PARAMETER gboolean state
)
543 sipe_invite_call(SIPE_MEDIA_CALL_PRIVATE
->sipe_private
,
544 sipe_media_send_ack
);
547 static void call_hangup_cb(struct sipe_media_call
*call
, gboolean local
)
549 struct sipe_media_call_private
*call_private
= SIPE_MEDIA_CALL_PRIVATE
;
552 struct sip_session
*session
;
553 session
= sipe_session_find_call(call_private
->sipe_private
,
557 sipe_session_close(call_private
->sipe_private
, session
);
560 call_private
->sipe_private
->media_call
= NULL
;
561 sipe_media_call_free(call_private
);
564 static struct sipe_media_call_private
*
565 sipe_media_call_new(struct sipe_core_private
*sipe_private
,
566 const gchar
* with
, gboolean initiator
)
568 struct sipe_media_call_private
*call_private
= g_new0(struct sipe_media_call_private
, 1);
570 call_private
->sipe_private
= sipe_private
;
571 call_private
->public.backend_private
= sipe_backend_media_new(SIPE_CORE_PUBLIC
,
576 call_private
->legacy_mode
= FALSE
;
577 call_private
->using_nice
= TRUE
;
578 call_private
->encryption_compatible
= TRUE
;
580 call_private
->public.candidates_prepared_cb
= candidates_prepared_cb
;
581 call_private
->public.media_connected_cb
= media_connected_cb
;
582 call_private
->public.call_accept_cb
= call_accept_cb
;
583 call_private
->public.call_reject_cb
= call_reject_cb
;
584 call_private
->public.call_hold_cb
= call_hold_cb
;
585 call_private
->public.call_hangup_cb
= call_hangup_cb
;
590 void sipe_media_hangup(struct sipe_core_private
*sipe_private
)
592 struct sipe_media_call_private
*call_private
= sipe_private
->media_call
;
594 sipe_backend_media_hangup(call_private
->public.backend_private
,
599 sipe_core_media_initiate_call(struct sipe_core_public
*sipe_public
,
603 struct sipe_core_private
*sipe_private
= SIPE_CORE_PRIVATE
;
604 struct sipe_media_call_private
*call_private
;
605 struct sipe_backend_media
*backend_media
;
606 struct sip_session
*session
;
607 struct sip_dialog
*dialog
;
609 if (sipe_private
->media_call
)
612 call_private
= sipe_media_call_new(sipe_private
, with
, TRUE
);
614 session
= sipe_session_add_call(sipe_private
, with
);
615 dialog
= sipe_dialog_add(session
);
616 dialog
->callid
= gencallid();
617 dialog
->with
= g_strdup(session
->with
);
618 dialog
->ourtag
= gentag();
620 call_private
->with
= g_strdup(session
->with
);
622 backend_media
= call_private
->public.backend_private
;
624 if (!sipe_backend_media_add_stream(backend_media
,
625 "audio", with
, SIPE_MEDIA_AUDIO
,
626 call_private
->using_nice
, TRUE
)) {
627 sipe_backend_notify_error(_("Error occured"),
628 _("Error creating audio stream"));
629 sipe_media_call_free(call_private
);
634 && !sipe_backend_media_add_stream(backend_media
,
635 "video", with
, SIPE_MEDIA_VIDEO
,
636 call_private
->using_nice
, TRUE
)) {
637 sipe_backend_notify_error(_("Error occured"),
638 _("Error creating video stream"));
639 sipe_media_call_free(call_private
);
643 sipe_private
->media_call
= call_private
;
645 // Processing continues in candidates_prepared_cb
649 process_incoming_invite_call(struct sipe_core_private
*sipe_private
,
652 struct sipe_media_call_private
*call_private
= sipe_private
->media_call
;
653 struct sipe_backend_media
*backend_media
;
655 gboolean has_new_media
= FALSE
;
658 if (call_private
&& !is_media_session_msg(call_private
, msg
)) {
659 sip_transport_response(sipe_private
, msg
, 486, "Busy Here", NULL
);
663 smsg
= sdpmsg_parse_msg(msg
->body
);
665 sip_transport_response(sipe_private
, msg
,
666 488, "Not Acceptable Here", NULL
);
667 sipe_media_hangup(sipe_private
);
672 gchar
*with
= parse_from(sipmsg_find_header(msg
, "From"));
673 struct sip_session
*session
;
674 struct sip_dialog
*dialog
;
676 call_private
= sipe_media_call_new(sipe_private
, with
, FALSE
);
677 session
= sipe_session_add_call(sipe_private
, with
);
678 dialog
= sipe_media_dialog_init(session
, msg
);
680 call_private
->with
= g_strdup(session
->with
);
681 sipe_private
->media_call
= call_private
;
685 backend_media
= call_private
->public.backend_private
;
687 if (call_private
->invitation
)
688 sipmsg_free(call_private
->invitation
);
689 call_private
->invitation
= sipmsg_copy(msg
);
691 // Create any new media streams
692 for (i
= smsg
->media
; i
; i
= i
->next
) {
693 struct sdpmedia
*media
= i
->data
;
694 gchar
*id
= media
->name
;
697 if ( media
->port
!= 0
698 && !sipe_backend_media_get_stream_by_id(backend_media
, id
)) {
701 if (sipe_strequal(id
, "audio"))
702 type
= SIPE_MEDIA_AUDIO
;
703 else if (sipe_strequal(id
, "video"))
704 type
= SIPE_MEDIA_VIDEO
;
708 with
= parse_from(sipmsg_find_header(msg
, "From"));
709 sipe_backend_media_add_stream(backend_media
, id
, with
,
711 !call_private
->legacy_mode
,
713 has_new_media
= TRUE
;
719 call_private
->smsg
= smsg
;
720 sip_transport_response(sipe_private
, call_private
->invitation
,
721 180, "Ringing", NULL
);
722 // Processing continues in candidates_prepared_cb
724 do_apply_remote_message(call_private
, smsg
);
729 void process_incoming_cancel_call(struct sipe_core_private
*sipe_private
,
732 struct sipe_media_call_private
*call_private
= sipe_private
->media_call
;
734 // We respond to the CANCEL request with 200 OK response and
735 // with 487 Request Terminated to the remote INVITE in progress.
736 sip_transport_response(sipe_private
, msg
, 200, "OK", NULL
);
738 if (call_private
->invitation
) {
739 sip_transport_response(sipe_private
, call_private
->invitation
,
740 487, "Request Terminated", NULL
);
743 sipe_media_hangup(sipe_private
);
747 sipe_media_send_ack(struct sipe_core_private
*sipe_private
,
748 SIPE_UNUSED_PARAMETER
struct sipmsg
*msg
,
749 struct transaction
*trans
)
751 struct sipe_media_call_private
*call_private
= sipe_private
->media_call
;
752 struct sip_session
*session
;
753 struct sip_dialog
*dialog
;
757 session
= sipe_session_find_call(sipe_private
, call_private
->with
);
758 dialog
= session
->dialogs
->data
;
762 tmp_cseq
= dialog
->cseq
;
764 sscanf(trans
->key
, "<%*[a-zA-Z0-9]><%d INVITE>", &trans_cseq
);
765 dialog
->cseq
= trans_cseq
- 1;
766 sip_transport_ack(sipe_private
, dialog
);
767 dialog
->cseq
= tmp_cseq
;
769 dialog
->outgoing_invite
= NULL
;
775 sipe_media_send_final_ack(struct sipe_core_private
*sipe_private
,
776 SIPE_UNUSED_PARAMETER
struct sipmsg
*msg
,
777 struct transaction
*trans
)
779 sipe_media_send_ack(sipe_private
, msg
, trans
);
780 sipe_backend_media_accept(sipe_private
->media_call
->public.backend_private
,
787 process_invite_call_response(struct sipe_core_private
*sipe_private
,
789 struct transaction
*trans
)
792 struct sipe_media_call_private
*call_private
= sipe_private
->media_call
;
793 struct sipe_backend_media
*backend_private
;
794 struct sip_session
*session
;
795 struct sip_dialog
*dialog
;
798 if (!is_media_session_msg(call_private
, msg
))
801 session
= sipe_session_find_call(sipe_private
, call_private
->with
);
802 dialog
= session
->dialogs
->data
;
804 backend_private
= call_private
->public.backend_private
;
807 dialog
->outgoing_invite
= NULL
;
809 if (msg
->response
>= 400) {
810 // Call rejected by remote peer or an error occurred
812 GString
*desc
= g_string_new("");
813 gboolean append_responsestr
= FALSE
;
815 switch (msg
->response
) {
817 const gchar
*warn
= sipmsg_find_header(msg
, "Warning");
818 title
= _("User unavailable");
820 if (warn
&& g_str_has_prefix(warn
, "391 lcs.microsoft.com")) {
821 g_string_append_printf(desc
, _("%s does not want to be disturbed"), with
);
823 g_string_append_printf(desc
, _("User %s is not available"), with
);
828 title
= _("Call rejected");
829 g_string_append_printf(desc
, _("User %s rejected call"), with
);
832 title
= _("Error occured");
833 g_string_append(desc
, _("Unable to establish a call"));
834 append_responsestr
= TRUE
;
838 if (append_responsestr
)
839 g_string_append_printf(desc
, "\n%d %s",
840 msg
->response
, msg
->responsestr
);
842 sipe_backend_notify_error(title
, desc
->str
);
843 g_string_free(desc
, TRUE
);
845 sipe_media_send_ack(sipe_private
, msg
, trans
);
846 sipe_media_hangup(sipe_private
);
851 sipe_dialog_parse(dialog
, msg
, TRUE
);
852 smsg
= sdpmsg_parse_msg(msg
->body
);
854 sip_transport_response(sipe_private
, msg
,
855 488, "Not Acceptable Here", NULL
);
856 sipe_media_hangup(sipe_private
);
860 if (!apply_remote_message(call_private
, smsg
)) {
861 sip_transport_response(sipe_private
, msg
,
862 487, "Request Terminated", NULL
);
863 sipe_media_hangup(sipe_private
);
864 } else if (msg
->response
== 183) {
865 // Session in progress
866 const gchar
*rseq
= sipmsg_find_header(msg
, "RSeq");
867 const gchar
*cseq
= sipmsg_find_header(msg
, "CSeq");
868 gchar
*rack
= g_strdup_printf("RAck: %s %s\r\n", rseq
, cseq
);
869 sip_transport_request(sipe_private
,
879 sipe_media_send_ack(sipe_private
, msg
, trans
);
881 if (call_private
->legacy_mode
&& call_private
->using_nice
) {
883 /* // We created non-legacy stream as we don't know which version of
884 // client is on the other side until first SDP response is received.
885 // This client requires legacy mode, so we must remove current session
886 // (using ICE) and create new using raw UDP transport.
887 struct sipe_backend_stream *new_stream;
889 call_private->using_nice = FALSE;
891 new_stream = sipe_backend_media_add_stream(backend_private,
897 sipe_backend_media_remove_stream(backend_private,
898 call_private->voice_stream);
899 call_private->voice_stream = new_stream;
901 apply_remote_message(call_private, smsg);
903 // New INVITE will be sent in candidates_prepared_cb */
905 sipe_invite_call(sipe_private
, sipe_media_send_final_ack
);
914 gboolean
is_media_session_msg(struct sipe_media_call_private
*call_private
,
918 const gchar
*callid
= sipmsg_find_header(msg
, "Call-ID");
919 struct sip_session
*session
;
921 session
= sipe_session_find_call(call_private
->sipe_private
,
924 struct sip_dialog
*dialog
= session
->dialogs
->data
;
925 return sipe_strequal(dialog
->callid
, callid
);
931 void sipe_media_handle_going_offline(struct sipe_media_call_private
*call_private
)
933 struct sipe_backend_media
*backend_private
;
935 backend_private
= call_private
->public.backend_private
;
937 if ( !sipe_backend_media_is_initiator(backend_private
, NULL
)
938 && !sipe_backend_media_accepted(backend_private
)) {
939 sip_transport_response(call_private
->sipe_private
,
940 call_private
->invitation
,
941 480, "Temporarily Unavailable", NULL
);
943 struct sip_session
*session
;
945 session
= sipe_session_find_call(call_private
->sipe_private
,
948 sipe_session_close(call_private
->sipe_private
, session
);
951 sipe_media_hangup(call_private
->sipe_private
);