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 sipe_backend_stream
*voice_stream
;
53 struct sipmsg
*invitation
;
56 gboolean encryption_compatible
;
60 #define SIPE_MEDIA_CALL ((struct sipe_media_call *) call_private)
61 #define SIPE_MEDIA_CALL_PRIVATE ((struct sipe_media_call_private *) call)
63 static void sipe_media_codec_list_free(GList
*codecs
)
65 for (; codecs
; codecs
= g_list_delete_link(codecs
, codecs
))
66 sipe_backend_codec_free(codecs
->data
);
69 static void sipe_media_candidate_list_free(GList
*candidates
)
71 for (; candidates
; candidates
= g_list_delete_link(candidates
, candidates
))
72 sipe_backend_candidate_free(candidates
->data
);
76 sipe_media_call_free(struct sipe_media_call_private
*call_private
)
79 struct sip_session
*session
;
80 sipe_backend_media_free(call_private
->public.backend_private
);
82 session
= sipe_session_find_call(call_private
->sipe_private
,
85 sipe_session_remove(call_private
->sipe_private
, session
);
87 if (call_private
->invitation
)
88 sipmsg_free(call_private
->invitation
);
90 sdpmsg_free(call_private
->smsg
);
91 g_free(call_private
->with
);
97 backend_candidates_to_sdpcandidate(GList
*candidates
)
99 GSList
*result
= NULL
;
102 for (i
= candidates
; i
; i
= i
->next
) {
103 struct sipe_backend_candidate
*candidate
= i
->data
;
104 struct sdpcandidate
*c
= g_new(struct sdpcandidate
, 1);
106 c
->foundation
= sipe_backend_candidate_get_foundation(candidate
);
107 c
->component
= sipe_backend_candidate_get_component_type(candidate
);
108 c
->type
= sipe_backend_candidate_get_type(candidate
);
109 c
->protocol
= sipe_backend_candidate_get_protocol(candidate
);
110 c
->ip
= sipe_backend_candidate_get_ip(candidate
);
111 c
->port
= sipe_backend_candidate_get_port(candidate
);
112 c
->base_ip
= sipe_backend_candidate_get_base_ip(candidate
);
113 c
->base_port
= sipe_backend_candidate_get_base_port(candidate
);
114 c
->priority
= sipe_backend_candidate_get_priority(candidate
);
116 result
= g_slist_append(result
, c
);
122 static struct sdpmsg
*
123 sipe_media_to_sdpmsg(struct sipe_media_call_private
*call_private
)
125 struct sdpmsg
*msg
= g_new0(struct sdpmsg
, 1);
126 struct sipe_backend_media
*backend_media
= call_private
->public.backend_private
;
128 GList
*codecs
= sipe_backend_get_local_codecs(SIPE_MEDIA_CALL
,
129 call_private
->voice_stream
);
135 GSList
*attributes
= NULL
;
139 for (i
= codecs
; i
; i
= i
->next
) {
140 struct sipe_backend_codec
*codec
= i
->data
;
141 struct sdpcodec
*c
= g_new0(struct sdpcodec
, 1);
144 c
->id
= sipe_backend_codec_get_id(codec
);
145 c
->name
= sipe_backend_codec_get_name(codec
);
146 c
->clock_rate
= sipe_backend_codec_get_clock_rate(codec
);
147 c
->type
= SIPE_MEDIA_AUDIO
;
149 params
= sipe_backend_codec_get_optional_parameters(codec
);
150 for (; params
; params
= params
->next
) {
151 struct sipnameval
*param
= params
->data
;
152 struct sipnameval
*copy
= g_new0(struct sipnameval
, 1);
154 copy
->name
= g_strdup(param
->name
);
155 copy
->value
= g_strdup(param
->value
);
157 c
->parameters
= g_slist_append(c
->parameters
, copy
);
160 msg
->codecs
= g_slist_append(msg
->codecs
, c
);
163 sipe_media_codec_list_free(codecs
);
165 // Process local candidates
166 // If we have established candidate pairs, send them in SDP response.
167 // Otherwise send all available local candidates.
168 candidates
= sipe_backend_media_get_active_local_candidates(backend_media
,
169 call_private
->voice_stream
);
171 candidates
= sipe_backend_get_local_candidates(backend_media
,
172 call_private
->voice_stream
);
174 msg
->candidates
= backend_candidates_to_sdpcandidate(candidates
);
176 // Process stream attributes
177 if (!call_private
->legacy_mode
) {
178 struct sipe_backend_candidate
*candidate
= candidates
->data
;
180 gchar
*username
= sipe_backend_candidate_get_username(candidate
);
181 gchar
*password
= sipe_backend_candidate_get_password(candidate
);
183 attributes
= sipe_utils_nameval_add(attributes
,
184 "ice-ufrag", username
);
185 attributes
= sipe_utils_nameval_add(attributes
,
186 "ice-pwd", password
);
192 sipe_media_candidate_list_free(candidates
);
194 for (j
= msg
->candidates
; j
; j
= j
->next
) {
195 struct sdpcandidate
*candidate
= j
->data
;
197 if (candidate
->type
== SIPE_CANDIDATE_TYPE_HOST
) {
198 if (candidate
->component
== SIPE_COMPONENT_RTP
)
199 msg
->port
= candidate
->port
;
200 else if (candidate
->component
== SIPE_COMPONENT_RTCP
)
201 rtcp_port
= candidate
->port
;
205 if ( call_private
->public.local_on_hold
206 || call_private
->public.remote_on_hold
) {
207 attributes
= sipe_utils_nameval_add(attributes
, "inactive", "");
211 gchar
*tmp
= g_strdup_printf("%u", rtcp_port
);
212 attributes
= sipe_utils_nameval_add(attributes
, "rtcp", tmp
);
216 attributes
= sipe_utils_nameval_add(attributes
, "encryption", "rejected");
218 msg
->attributes
= attributes
;
219 msg
->legacy
= call_private
->legacy_mode
;
220 msg
->ip
= g_strdup(sipe_utils_get_suitable_local_ip(-1));
222 // Process remote candidates
223 candidates
= sipe_backend_media_get_active_remote_candidates(backend_media
,
224 call_private
->voice_stream
);
225 msg
->remote_candidates
= backend_candidates_to_sdpcandidate(candidates
);
226 sipe_media_candidate_list_free(candidates
);
232 sipe_invite_call(struct sipe_core_private
*sipe_private
, TransCallback tc
)
237 struct sipe_media_call_private
*call_private
= sipe_private
->media_call
;
238 struct sip_session
*session
;
239 struct sip_dialog
*dialog
;
242 session
= sipe_session_find_call(sipe_private
, call_private
->with
);
243 dialog
= session
->dialogs
->data
;
245 contact
= get_contact(sipe_private
);
246 hdr
= g_strdup_printf(
247 "Supported: ms-early-media\r\n"
248 "Supported: 100rel\r\n"
249 "ms-keep-alive: UAC;hop-hop=yes\r\n"
251 "Content-Type: application/sdp\r\n",
253 (call_private
->public.local_on_hold
|| call_private
->public.remote_on_hold
) ? ";+sip.rendering=\"no\"" : "");
256 msg
= sipe_media_to_sdpmsg(call_private
);
257 body
= sdpmsg_to_string(msg
);
260 dialog
->outgoing_invite
= sip_transport_invite(sipe_private
,
270 static struct sip_dialog
*
271 sipe_media_dialog_init(struct sip_session
* session
, struct sipmsg
*msg
)
273 gchar
*newTag
= gentag();
274 const gchar
*oldHeader
;
276 struct sip_dialog
*dialog
;
278 oldHeader
= sipmsg_find_header(msg
, "To");
279 newHeader
= g_strdup_printf("%s;tag=%s", oldHeader
, newTag
);
280 sipmsg_remove_header_now(msg
, "To");
281 sipmsg_add_header_now(msg
, "To", newHeader
);
284 dialog
= sipe_dialog_add(session
);
285 dialog
->callid
= g_strdup(sipmsg_find_header(msg
, "Call-ID"));
286 dialog
->with
= parse_from(sipmsg_find_header(msg
, "From"));
287 sipe_dialog_parse(dialog
, msg
, FALSE
);
293 send_response_with_session_description(struct sipe_media_call_private
*call_private
, int code
, gchar
*text
)
295 struct sdpmsg
*msg
= sipe_media_to_sdpmsg(call_private
);
296 gchar
*body
= sdpmsg_to_string(msg
);
298 sipmsg_add_header(call_private
->invitation
, "Content-Type", "application/sdp");
299 sip_transport_response(call_private
->sipe_private
, call_private
->invitation
, code
, text
, body
);
304 encryption_levels_compatible(struct sdpmsg
*smsg
)
306 const gchar
*encrypion_level
;
308 encrypion_level
= sipe_utils_nameval_find(smsg
->attributes
, "encryption");
310 // Decline call if peer requires encryption as we don't support it yet.
311 return !sipe_strequal(encrypion_level
, "required");
315 handle_incompatible_encryption_level(struct sipe_media_call_private
*call_private
)
317 sipmsg_add_header(call_private
->invitation
, "Warning",
318 "308 lcs.microsoft.com \"Encryption Levels not compatible\"");
319 sip_transport_response(call_private
->sipe_private
,
320 call_private
->invitation
,
321 488, "Encryption Levels not compatible",
323 sipe_backend_media_reject(call_private
->public.backend_private
, FALSE
);
324 sipe_backend_notify_error(_("Unable to establish a call"),
325 _("Encryption settings of peer are incompatible with ours."));
329 process_invite_call_response(struct sipe_core_private
*sipe_private
,
331 struct transaction
*trans
);
334 apply_remote_message(struct sipe_media_call_private
* call_private
,
337 struct sipe_backend_media
*backend_media
= SIPE_MEDIA_CALL
->backend_private
;
338 struct sipe_backend_stream
*backend_stream
= call_private
->voice_stream
;
339 GList
*backend_candidates
= NULL
;
340 GList
*backend_codecs
= NULL
;
343 const gchar
*username
= sipe_utils_nameval_find(msg
->attributes
, "ice-ufrag");
344 const gchar
*password
= sipe_utils_nameval_find(msg
->attributes
, "ice-pwd");
347 for (i
= msg
->candidates
; i
; i
= i
->next
) {
348 struct sdpcandidate
*c
= i
->data
;
349 struct sipe_backend_candidate
*candidate
;
350 candidate
= sipe_backend_candidate_new(c
->foundation
,
356 sipe_backend_candidate_set_priority(candidate
, c
->priority
);
359 sipe_backend_candidate_set_username_and_pwd(candidate
,
363 backend_candidates
= g_list_append(backend_candidates
, candidate
);
366 sipe_backend_media_add_remote_candidates(backend_media
,
369 sipe_media_candidate_list_free(backend_candidates
);
371 for (i
= msg
->codecs
; i
; i
= i
->next
) {
372 struct sdpcodec
*c
= i
->data
;
373 struct sipe_backend_codec
*codec
;
376 codec
= sipe_backend_codec_new(c
->id
,
381 for (j
= c
->parameters
; j
; j
= j
->next
) {
382 struct sipnameval
*attr
= j
->data
;
384 sipe_backend_codec_add_optional_parameter(codec
,
389 backend_codecs
= g_list_append(backend_codecs
, codec
);
392 sipe_backend_set_remote_codecs(backend_media
,
395 sipe_media_codec_list_free(backend_codecs
);
397 call_private
->legacy_mode
= msg
->legacy
;
398 call_private
->encryption_compatible
= encryption_levels_compatible(msg
);
403 static void candidates_prepared_cb(struct sipe_media_call
*call
)
405 struct sipe_media_call_private
*call_private
= SIPE_MEDIA_CALL_PRIVATE
;
407 if (sipe_backend_media_is_initiator(call_private
->public.backend_private
,
408 call_private
->voice_stream
)) {
409 sipe_invite_call(call_private
->sipe_private
,
410 process_invite_call_response
);
414 if (!apply_remote_message(call_private
, call_private
->smsg
)) {
415 sipe_media_hangup(call_private
->sipe_private
);
419 sdpmsg_free(call_private
->smsg
);
420 call_private
->smsg
= NULL
;
422 if (!call_private
->legacy_mode
&& call_private
->encryption_compatible
)
423 send_response_with_session_description(call_private
,
424 183, "Session Progress");
427 static void media_connected_cb(SIPE_UNUSED_PARAMETER
struct sipe_media_call_private
*call_private
)
431 static void call_accept_cb(struct sipe_media_call
*call
, gboolean local
)
434 struct sipe_media_call_private
*call_private
= SIPE_MEDIA_CALL_PRIVATE
;
436 if (!call_private
->encryption_compatible
) {
437 handle_incompatible_encryption_level(call_private
);
441 send_response_with_session_description(call_private
, 200, "OK");
445 static void call_reject_cb(struct sipe_media_call
*call
, gboolean local
)
447 struct sipe_media_call_private
*call_private
= SIPE_MEDIA_CALL_PRIVATE
;
450 sip_transport_response(call_private
->sipe_private
, call_private
->invitation
, 603, "Decline", NULL
);
452 call_private
->sipe_private
->media_call
= NULL
;
453 sipe_media_call_free(call_private
);
457 sipe_media_send_ack(struct sipe_core_private
*sipe_private
, struct sipmsg
*msg
,
458 struct transaction
*trans
);
460 static void call_hold_cb(struct sipe_media_call
*call
, gboolean local
, gboolean state
)
462 struct sipe_media_call_private
*call_private
= SIPE_MEDIA_CALL_PRIVATE
;
464 if (local
&& (call_private
->public.local_on_hold
!= state
)) {
465 call_private
->public.local_on_hold
= state
;
466 sipe_invite_call(call_private
->sipe_private
, sipe_media_send_ack
);
467 } else if (call_private
->public.remote_on_hold
!= state
) {
468 call_private
->public.remote_on_hold
= state
;
469 send_response_with_session_description(call_private
, 200, "OK");
473 static void call_hangup_cb(struct sipe_media_call
*call
, gboolean local
)
475 struct sipe_media_call_private
*call_private
= SIPE_MEDIA_CALL_PRIVATE
;
478 struct sip_session
*session
;
479 session
= sipe_session_find_call(call_private
->sipe_private
,
483 sipe_session_close(call_private
->sipe_private
, session
);
486 call_private
->sipe_private
->media_call
= NULL
;
487 sipe_media_call_free(call_private
);
490 static struct sipe_media_call_private
*
491 sipe_media_call_new(struct sipe_core_private
*sipe_private
,
492 const gchar
* with
, gboolean initiator
)
494 struct sipe_media_call_private
*call_private
= g_new0(struct sipe_media_call_private
, 1);
496 call_private
->sipe_private
= sipe_private
;
497 call_private
->public.backend_private
= sipe_backend_media_new(SIPE_CORE_PUBLIC
,
502 call_private
->legacy_mode
= FALSE
;
503 call_private
->using_nice
= TRUE
;
504 call_private
->encryption_compatible
= TRUE
;
506 call_private
->public.candidates_prepared_cb
= candidates_prepared_cb
;
507 call_private
->public.media_connected_cb
= media_connected_cb
;
508 call_private
->public.call_accept_cb
= call_accept_cb
;
509 call_private
->public.call_reject_cb
= call_reject_cb
;
510 call_private
->public.call_hold_cb
= call_hold_cb
;
511 call_private
->public.call_hangup_cb
= call_hangup_cb
;
513 call_private
->public.local_on_hold
= FALSE
;
514 call_private
->public.remote_on_hold
= FALSE
;
519 void sipe_media_hangup(struct sipe_core_private
*sipe_private
)
521 struct sipe_media_call_private
*call_private
= sipe_private
->media_call
;
523 sipe_backend_media_hangup(call_private
->public.backend_private
,
528 sipe_core_media_initiate_call(struct sipe_core_public
*sipe_public
,
531 struct sipe_core_private
*sipe_private
= SIPE_CORE_PRIVATE
;
532 struct sipe_media_call_private
*call_private
;
533 struct sip_session
*session
;
534 struct sip_dialog
*dialog
;
536 if (sipe_private
->media_call
)
539 call_private
= sipe_media_call_new(sipe_private
, with
, TRUE
);
541 session
= sipe_session_add_call(sipe_private
, with
);
542 dialog
= sipe_dialog_add(session
);
543 dialog
->callid
= gencallid();
544 dialog
->with
= g_strdup(session
->with
);
545 dialog
->ourtag
= gentag();
547 call_private
->with
= g_strdup(session
->with
);
549 call_private
->voice_stream
= sipe_backend_media_add_stream(
550 call_private
->public.backend_private
,
553 call_private
->using_nice
,
556 if (!call_private
->voice_stream
) {
557 sipe_backend_notify_error("Error occured",
558 "Error creating media stream");
559 sipe_media_call_free(call_private
);
563 sipe_private
->media_call
= call_private
;
565 // Processing continues in candidates_prepared_cb
569 process_incoming_invite_call(struct sipe_core_private
*sipe_private
,
572 struct sipe_media_call_private
*call_private
= sipe_private
->media_call
;
575 if (call_private
&& !is_media_session_msg(call_private
, msg
)) {
576 sip_transport_response(sipe_private
, msg
, 486, "Busy Here", NULL
);
580 smsg
= sdpmsg_parse_msg(msg
->body
);
582 sipe_media_hangup(sipe_private
);
587 if (call_private
->invitation
)
588 sipmsg_free(call_private
->invitation
);
589 call_private
->invitation
= sipmsg_copy(msg
);
591 apply_remote_message(call_private
, smsg
);
593 if (!call_private
->encryption_compatible
) {
594 handle_incompatible_encryption_level(call_private
);
595 } else if (call_private
->legacy_mode
&& !call_private
->public.remote_on_hold
) {
596 sipe_backend_media_hold(call_private
->public.backend_private
,
598 } else if (sipe_utils_nameval_find(smsg
->attributes
, "inactive")) {
599 sipe_backend_media_hold(call_private
->public.backend_private
, FALSE
);
600 } else if (call_private
->public.remote_on_hold
) {
601 sipe_backend_media_unhold(call_private
->public.backend_private
, FALSE
);
603 send_response_with_session_description(call_private
,
609 gchar
*with
= parse_from(sipmsg_find_header(msg
, "From"));
610 struct sip_session
*session
;
611 struct sip_dialog
*dialog
;
613 call_private
= sipe_media_call_new(sipe_private
, with
, FALSE
);
614 session
= sipe_session_add_call(sipe_private
, with
);
615 dialog
= sipe_media_dialog_init(session
, msg
);
617 call_private
->with
= g_strdup(session
->with
);
618 call_private
->invitation
= sipmsg_copy(msg
);
619 call_private
->smsg
= smsg
;
620 call_private
->voice_stream
=
621 sipe_backend_media_add_stream(call_private
->public.backend_private
,
624 !call_private
->legacy_mode
, FALSE
);
626 sipe_private
->media_call
= call_private
;
628 sip_transport_response(sipe_private
, call_private
->invitation
, 180, "Ringing", NULL
);
632 // Processing continues in candidates_prepared_cb
636 void process_incoming_cancel_call(struct sipe_core_private
*sipe_private
,
639 struct sipe_media_call_private
*call_private
= sipe_private
->media_call
;
641 // We respond to the CANCEL request with 200 OK response and
642 // with 487 Request Terminated to the remote INVITE in progress.
643 sip_transport_response(sipe_private
, msg
, 200, "OK", NULL
);
645 if (call_private
->invitation
) {
646 sip_transport_response(sipe_private
, call_private
->invitation
,
647 487, "Request Terminated", NULL
);
650 sipe_media_hangup(sipe_private
);
654 sipe_media_send_ack(struct sipe_core_private
*sipe_private
,
655 SIPE_UNUSED_PARAMETER
struct sipmsg
*msg
,
656 struct transaction
*trans
)
658 struct sipe_media_call_private
*call_private
= sipe_private
->media_call
;
659 struct sip_session
*session
;
660 struct sip_dialog
*dialog
;
664 session
= sipe_session_find_call(sipe_private
, call_private
->with
);
665 dialog
= session
->dialogs
->data
;
669 tmp_cseq
= dialog
->cseq
;
671 sscanf(trans
->key
, "<%*[a-zA-Z0-9]><%d INVITE>", &trans_cseq
);
672 dialog
->cseq
= trans_cseq
- 1;
673 sip_transport_ack(sipe_private
, dialog
);
674 dialog
->cseq
= tmp_cseq
;
676 dialog
->outgoing_invite
= NULL
;
682 process_invite_call_response(struct sipe_core_private
*sipe_private
,
684 struct transaction
*trans
)
687 struct sipe_media_call_private
*call_private
= sipe_private
->media_call
;
688 struct sipe_backend_media
*backend_private
;
689 struct sip_session
*session
;
690 struct sip_dialog
*dialog
;
693 if (!is_media_session_msg(call_private
, msg
))
696 session
= sipe_session_find_call(sipe_private
, call_private
->with
);
697 dialog
= session
->dialogs
->data
;
699 backend_private
= call_private
->public.backend_private
;
702 dialog
->outgoing_invite
= NULL
;
704 if (msg
->response
>= 400) {
705 // Call rejected by remote peer or an error occurred
707 GString
*desc
= g_string_new("");
709 switch (msg
->response
) {
711 title
= _("User unavailable");
712 g_string_append_printf(desc
, _("User %s is not available"), with
);
716 title
= _("Call rejected");
717 g_string_append_printf(desc
, _("User %s rejected call"), with
);
720 title
= _("Error occured");
721 g_string_append(desc
, _("Unable to establish a call"));
725 g_string_append_printf(desc
, "\n%d %s", msg
->response
, msg
->responsestr
);
727 sipe_backend_notify_error(title
, desc
->str
);
728 g_string_free(desc
, TRUE
);
730 sipe_media_send_ack(sipe_private
, msg
, trans
);
731 sipe_media_hangup(sipe_private
);
736 sipe_dialog_parse(dialog
, msg
, TRUE
);
737 smsg
= sdpmsg_parse_msg(msg
->body
);
739 sipe_media_hangup(sipe_private
);
743 apply_remote_message(call_private
, smsg
);
745 if (msg
->response
== 183) {
746 // Session in progress
747 const gchar
*rseq
= sipmsg_find_header(msg
, "RSeq");
748 const gchar
*cseq
= sipmsg_find_header(msg
, "CSeq");
749 gchar
*rack
= g_strdup_printf("RAck: %s %s\r\n", rseq
, cseq
);
750 sip_transport_request(sipe_private
,
760 sipe_media_send_ack(sipe_private
, msg
, trans
);
762 if (call_private
->legacy_mode
&& call_private
->using_nice
) {
763 // We created non-legacy stream as we don't know which version of
764 // client is on the other side until first SDP response is received.
765 // This client requires legacy mode, so we must remove current session
766 // (using ICE) and create new using raw UDP transport.
767 struct sipe_backend_stream
*new_stream
;
769 call_private
->using_nice
= FALSE
;
771 new_stream
= sipe_backend_media_add_stream(backend_private
,
777 sipe_backend_media_remove_stream(backend_private
,
778 call_private
->voice_stream
);
779 call_private
->voice_stream
= new_stream
;
781 apply_remote_message(call_private
, smsg
);
783 // New INVITE will be sent in candidates_prepared_cb
785 sipe_invite_call(sipe_private
, sipe_media_send_ack
);
794 gboolean
is_media_session_msg(struct sipe_media_call_private
*call_private
,
798 const gchar
*callid
= sipmsg_find_header(msg
, "Call-ID");
799 struct sip_session
*session
;
801 session
= sipe_session_find_call(call_private
->sipe_private
,
804 struct sip_dialog
*dialog
= session
->dialogs
->data
;
805 return sipe_strequal(dialog
->callid
, callid
);