media: avoid superfluous "Call rejected" popups
[siplcs.git] / src / core / sipe-media.c
blobfb7fcc3887871f2b35bf37842c8a612422bfe31a
1 /**
2 * @file sipe-media.c
4 * pidgin-sipe
6 * Copyright (C) 2011-2016 SIPE Project <http://sipe.sourceforge.net/>
7 * Copyright (C) 2010 Jakub Adam <jakub.adam@ktknet.cz>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
32 #include <glib.h>
34 #include "sipe-common.h"
35 #include "sipmsg.h"
36 #include "sip-transport.h"
37 #include "sipe-backend.h"
38 #include "sdpmsg.h"
39 #include "sipe-chat.h"
40 #include "sipe-conf.h"
41 #include "sipe-core.h"
42 #include "sipe-core-private.h"
43 #include "sipe-dialog.h"
44 #include "sipe-media.h"
45 #include "sipe-ocs2007.h"
46 #include "sipe-session.h"
47 #include "sipe-utils.h"
48 #include "sipe-nls.h"
49 #include "sipe-schedule.h"
50 #include "sipe-xml.h"
52 struct sipe_media_call_private {
53 struct sipe_media_call public;
55 /* private part starts here */
56 struct sipe_core_private *sipe_private;
58 struct sip_session *conference_session;
60 GSList *streams;
62 struct sipmsg *invitation;
63 SipeIceVersion ice_version;
64 gboolean encryption_compatible;
65 gchar *extra_invite_section;
66 gchar *invite_content_type;
68 struct sdpmsg *smsg;
69 GSList *failed_media;
71 #define SIPE_MEDIA_CALL ((struct sipe_media_call *) call_private)
72 #define SIPE_MEDIA_CALL_PRIVATE ((struct sipe_media_call_private *) call)
74 struct sipe_media_stream_private {
75 struct sipe_media_stream public;
77 guchar *encryption_key;
78 int encryption_key_id;
79 gboolean remote_candidates_and_codecs_set;
80 gboolean established;
82 GSList *extra_sdp;
84 gboolean writable;
86 GQueue *write_queue;
87 GQueue *async_reads;
88 gssize read_pos;
90 /* User data associated with the stream. */
91 gpointer data;
92 GDestroyNotify data_free_func;
94 #define SIPE_MEDIA_STREAM ((struct sipe_media_stream *) stream_private)
95 #define SIPE_MEDIA_STREAM_PRIVATE ((struct sipe_media_stream_private *) stream)
97 struct async_read_data {
98 guint8 *buffer;
99 gssize len;
100 sipe_media_stream_read_callback callback;
103 static void sipe_media_codec_list_free(GList *codecs)
105 for (; codecs; codecs = g_list_delete_link(codecs, codecs))
106 sipe_backend_codec_free(codecs->data);
109 static void sipe_media_candidate_list_free(GList *candidates)
111 for (; candidates; candidates = g_list_delete_link(candidates, candidates))
112 sipe_backend_candidate_free(candidates->data);
115 static void
116 remove_stream(struct sipe_media_call* call,
117 struct sipe_media_stream_private *stream_private)
119 struct sipe_media_call_private *call_private = SIPE_MEDIA_CALL_PRIVATE;
121 sipe_media_stream_set_data(SIPE_MEDIA_STREAM, NULL, NULL);
123 call_private->streams =
124 g_slist_remove(call_private->streams, stream_private);
125 sipe_backend_media_stream_free(SIPE_MEDIA_STREAM->backend_private);
126 g_free(SIPE_MEDIA_STREAM->id);
127 g_free(stream_private->encryption_key);
128 g_queue_free_full(stream_private->write_queue,
129 (GDestroyNotify)g_byte_array_unref);
130 g_queue_free_full(stream_private->async_reads, g_free);
131 sipe_utils_nameval_free(stream_private->extra_sdp);
132 g_free(stream_private);
135 static gboolean
136 call_private_equals(SIPE_UNUSED_PARAMETER const gchar *callid,
137 struct sipe_media_call_private *call_private1,
138 struct sipe_media_call_private *call_private2)
140 return call_private1 == call_private2;
143 static void
144 sipe_media_call_free(struct sipe_media_call_private *call_private)
146 if (call_private) {
147 struct sip_session *session;
149 g_hash_table_foreach_remove(call_private->sipe_private->media_calls,
150 (GHRFunc) call_private_equals, call_private);
152 while (call_private->streams) {
153 remove_stream(SIPE_MEDIA_CALL,
154 call_private->streams->data);
157 sipe_backend_media_free(call_private->public.backend_private);
159 session = sipe_session_find_call(call_private->sipe_private,
160 SIPE_MEDIA_CALL->with);
161 if (session)
162 sipe_session_remove(call_private->sipe_private, session);
164 if (call_private->invitation)
165 sipmsg_free(call_private->invitation);
167 // Frees any referenced extra invite data.
168 sipe_media_add_extra_invite_section(SIPE_MEDIA_CALL, NULL, NULL);
170 sdpmsg_free(call_private->smsg);
171 sipe_utils_slist_free_full(call_private->failed_media,
172 (GDestroyNotify)sdpmedia_free);
173 g_free(SIPE_MEDIA_CALL->with);
174 g_free(call_private);
178 static gint
179 candidate_sort_cb(struct sdpcandidate *c1, struct sdpcandidate *c2)
181 int cmp = sipe_strcompare(c1->foundation, c2->foundation);
182 if (cmp == 0) {
183 cmp = sipe_strcompare(c1->username, c2->username);
184 if (cmp == 0)
185 cmp = c1->component - c2->component;
188 return cmp;
191 static GSList *
192 backend_candidates_to_sdpcandidate(GList *candidates)
194 GSList *result = NULL;
195 GList *i;
197 for (i = candidates; i; i = i->next) {
198 struct sipe_backend_candidate *candidate = i->data;
199 struct sdpcandidate *c;
201 gchar *ip = sipe_backend_candidate_get_ip(candidate);
202 gchar *base_ip = sipe_backend_candidate_get_base_ip(candidate);
203 if (is_empty(ip) || strchr(ip, ':') ||
204 (base_ip && strchr(base_ip, ':'))) {
205 /* Ignore IPv6 candidates. */
206 g_free(ip);
207 g_free(base_ip);
208 continue;
211 c = g_new(struct sdpcandidate, 1);
212 c->foundation = sipe_backend_candidate_get_foundation(candidate);
213 c->component = sipe_backend_candidate_get_component_type(candidate);
214 c->type = sipe_backend_candidate_get_type(candidate);
215 c->protocol = sipe_backend_candidate_get_protocol(candidate);
216 c->ip = ip;
217 c->port = sipe_backend_candidate_get_port(candidate);
218 c->base_ip = base_ip;
219 c->base_port = sipe_backend_candidate_get_base_port(candidate);
220 c->priority = sipe_backend_candidate_get_priority(candidate);
221 c->username = sipe_backend_candidate_get_username(candidate);
222 c->password = sipe_backend_candidate_get_password(candidate);
224 result = g_slist_insert_sorted(result, c,
225 (GCompareFunc)candidate_sort_cb);
228 return result;
231 static void
232 get_stream_ip_and_ports(GSList *candidates,
233 gchar **ip, guint *rtp_port, guint *rtcp_port)
235 guint32 rtp_max_priority = 0;
236 guint32 rtcp_max_priority = 0;
238 *ip = 0;
239 *rtp_port = 0;
240 *rtcp_port = 0;
242 for (; candidates; candidates = candidates->next) {
243 struct sdpcandidate *candidate = candidates->data;
245 if (candidate->component == SIPE_COMPONENT_RTP &&
246 candidate->priority > rtp_max_priority) {
247 rtp_max_priority = candidate->priority;
248 *rtp_port = candidate->port;
250 g_free(*ip);
251 *ip = g_strdup(candidate->ip);
252 } else if (candidate->component == SIPE_COMPONENT_RTCP &&
253 candidate->priority > rtcp_max_priority) {
254 rtcp_max_priority = candidate->priority;
255 *rtcp_port = candidate->port;
260 static gint
261 sdpcodec_compare(gconstpointer a, gconstpointer b)
263 return ((const struct sdpcodec *)a)->id -
264 ((const struct sdpcodec *)b)->id;
267 static GList *
268 remove_wrong_farstream_0_1_tcp_candidates(GList *candidates)
270 GList *i = candidates;
271 GHashTable *foundation_to_candidate = g_hash_table_new_full(g_str_hash,
272 g_str_equal,
273 g_free,
274 NULL);
276 while (i) {
277 GList *next = i->next;
278 struct sipe_backend_candidate *c1 = i->data;
280 if (sipe_backend_candidate_get_protocol(c1) == SIPE_NETWORK_PROTOCOL_UDP) {
281 gchar *foundation = sipe_backend_candidate_get_foundation(c1);
282 struct sipe_backend_candidate *c2 = g_hash_table_lookup(foundation_to_candidate,
283 foundation);
285 if (c2) {
286 g_free(foundation);
288 if (sipe_backend_candidate_get_port(c1) ==
289 sipe_backend_candidate_get_port(c2) ||
290 (sipe_backend_candidate_get_type(c1) !=
291 SIPE_CANDIDATE_TYPE_HOST &&
292 sipe_backend_candidate_get_base_port(c1) ==
293 sipe_backend_candidate_get_base_port(c2))) {
295 * We assume that RTP+RTCP UDP pairs
296 * that share the same port are
297 * actually mistagged TCP candidates.
299 candidates = g_list_remove(candidates, c2);
300 candidates = g_list_delete_link(candidates, i);
301 sipe_backend_candidate_free(c1);
302 sipe_backend_candidate_free(c2);
304 } else
305 /* hash table takes ownership of "foundation" */
306 g_hash_table_insert(foundation_to_candidate, foundation, c1);
309 i = next;
312 g_hash_table_destroy(foundation_to_candidate);
314 return candidates;
317 static void
318 fill_zero_tcp_act_ports_from_tcp_pass(GSList *candidates, GSList *all_candidates)
320 GSList *i;
321 GHashTable *ip_to_port = g_hash_table_new(g_str_hash, g_str_equal);
323 for (i = candidates; i; i = i->next) {
324 struct sdpcandidate *c = i->data;
325 GSList *j;
327 if (c->protocol != SIPE_NETWORK_PROTOCOL_TCP_ACTIVE) {
328 continue;
331 for (j = all_candidates; j; j = j->next) {
332 struct sdpcandidate *passive = j->data;
333 if (passive->protocol != SIPE_NETWORK_PROTOCOL_TCP_PASSIVE ||
334 c->type != passive->type) {
335 continue;
338 if (sipe_strequal(c->ip, passive->ip) &&
339 sipe_strequal(c->base_ip, passive->base_ip)) {
340 if (c->port == 0) {
341 c->port = passive->port;
344 if (c->base_port == 0) {
345 c->base_port = passive->base_port;
347 break;
352 for (i = all_candidates; i; i = i->next) {
353 struct sdpcandidate *c = i->data;
355 if (c->protocol == SIPE_NETWORK_PROTOCOL_TCP_PASSIVE &&
356 c->type == SIPE_CANDIDATE_TYPE_HOST) {
357 g_hash_table_insert(ip_to_port, c->ip, &c->port);
361 /* Fill base ports of all TCP relay candidates using what we have
362 * collected from host candidates. */
363 for (i = candidates; i; i = i->next) {
364 struct sdpcandidate *c = i->data;
365 if (c->type == SIPE_CANDIDATE_TYPE_RELAY && c->base_port == 0) {
366 guint *base_port = (guint*)g_hash_table_lookup(ip_to_port, c->base_ip);
367 if (base_port) {
368 c->base_port = *base_port;
369 } else {
370 SIPE_DEBUG_WARNING("Couldn't determine base port for candidate "
371 "with foundation %s", c->foundation);
376 g_hash_table_destroy(ip_to_port);
379 static SipeEncryptionPolicy
380 get_encryption_policy(struct sipe_core_private *sipe_private)
382 SipeEncryptionPolicy result =
383 sipe_backend_media_get_encryption_policy(SIPE_CORE_PUBLIC);
384 if (result == SIPE_ENCRYPTION_POLICY_OBEY_SERVER) {
385 result = sipe_private->server_av_encryption_policy;
388 return result;
391 static struct sdpmedia *
392 media_stream_to_sdpmedia(struct sipe_media_call_private *call_private,
393 struct sipe_media_stream_private *stream_private)
395 struct sdpmedia *sdpmedia = g_new0(struct sdpmedia, 1);
396 GList *codecs = sipe_backend_get_local_codecs(SIPE_MEDIA_CALL,
397 SIPE_MEDIA_STREAM);
398 SipeEncryptionPolicy encryption_policy =
399 get_encryption_policy(call_private->sipe_private);
400 guint rtcp_port = 0;
401 SipeMediaType type;
402 GSList *attributes = NULL;
403 GSList *sdpcandidates;
404 GSList *all_sdpcandidates;
405 GList *candidates;
406 GList *i;
407 GSList *j;
409 sdpmedia->name = g_strdup(SIPE_MEDIA_STREAM->id);
411 if (sipe_strequal(sdpmedia->name, "audio"))
412 type = SIPE_MEDIA_AUDIO;
413 else if (sipe_strequal(sdpmedia->name, "video"))
414 type = SIPE_MEDIA_VIDEO;
415 else if (sipe_strequal(sdpmedia->name, "data"))
416 type = SIPE_MEDIA_APPLICATION;
417 else {
418 // TODO: incompatible media, should not happen here
419 g_free(sdpmedia->name);
420 g_free(sdpmedia);
421 sipe_media_codec_list_free(codecs);
422 return(NULL);
425 // Process codecs
426 for (i = codecs; i; i = i->next) {
427 struct sipe_backend_codec *codec = i->data;
428 struct sdpcodec *c = g_new0(struct sdpcodec, 1);
429 GList *params;
431 c->id = sipe_backend_codec_get_id(codec);
432 c->name = sipe_backend_codec_get_name(codec);
433 c->clock_rate = sipe_backend_codec_get_clock_rate(codec);
434 c->type = type;
436 params = sipe_backend_codec_get_optional_parameters(codec);
437 for (; params; params = params->next) {
438 struct sipnameval *param = params->data;
439 struct sipnameval *copy = g_new0(struct sipnameval, 1);
441 copy->name = g_strdup(param->name);
442 copy->value = g_strdup(param->value);
444 c->parameters = g_slist_append(c->parameters, copy);
447 /* Buggy(?) codecs may report non-unique id (a.k.a. payload
448 * type) that must not appear in SDP messages we send. Thus,
449 * let's ignore any codec having the same id as one we already
450 * have in the converted list. */
451 sdpmedia->codecs = sipe_utils_slist_insert_unique_sorted(
452 sdpmedia->codecs, c, sdpcodec_compare,
453 (GDestroyNotify)sdpcodec_free);
456 sipe_media_codec_list_free(codecs);
458 // Process local candidates
459 // If we have established candidate pairs, send them in SDP response.
460 // Otherwise send all available local candidates.
461 candidates = sipe_backend_media_stream_get_active_local_candidates(SIPE_MEDIA_STREAM);
462 sdpcandidates = backend_candidates_to_sdpcandidate(candidates);
463 sipe_media_candidate_list_free(candidates);
465 candidates = sipe_backend_get_local_candidates(SIPE_MEDIA_CALL,
466 SIPE_MEDIA_STREAM);
467 candidates = remove_wrong_farstream_0_1_tcp_candidates(candidates);
468 all_sdpcandidates = backend_candidates_to_sdpcandidate(candidates);
469 sipe_media_candidate_list_free(candidates);
471 if (!sdpcandidates) {
472 sdpcandidates = all_sdpcandidates;
475 fill_zero_tcp_act_ports_from_tcp_pass(sdpcandidates, all_sdpcandidates);
477 sdpmedia->candidates = sdpcandidates;
479 if (all_sdpcandidates != sdpcandidates) {
480 sipe_utils_slist_free_full(all_sdpcandidates,
481 (GDestroyNotify)sdpcandidate_free);
484 get_stream_ip_and_ports(sdpmedia->candidates, &sdpmedia->ip,
485 &sdpmedia->port, &rtcp_port);
487 if (sipe_backend_stream_is_held(SIPE_MEDIA_STREAM))
488 attributes = sipe_utils_nameval_add(attributes, "inactive", "");
490 if (rtcp_port) {
491 gchar *tmp = g_strdup_printf("%u", rtcp_port);
492 attributes = sipe_utils_nameval_add(attributes, "rtcp", tmp);
493 g_free(tmp);
496 if (encryption_policy != call_private->sipe_private->server_av_encryption_policy) {
497 const gchar *encryption = NULL;
498 switch (encryption_policy) {
499 case SIPE_ENCRYPTION_POLICY_REJECTED:
500 encryption = "rejected";
501 break;
502 case SIPE_ENCRYPTION_POLICY_OPTIONAL:
503 encryption = "optional";
504 break;
505 case SIPE_ENCRYPTION_POLICY_REQUIRED:
506 default:
507 encryption = "required";
508 break;
511 attributes = sipe_utils_nameval_add(attributes, "encryption", encryption);
514 // Process remote candidates
515 candidates = sipe_backend_media_stream_get_active_remote_candidates(SIPE_MEDIA_STREAM);
516 sdpmedia->remote_candidates = backend_candidates_to_sdpcandidate(candidates);
517 sipe_media_candidate_list_free(candidates);
519 sdpmedia->encryption_active = stream_private->encryption_key &&
520 call_private->encryption_compatible &&
521 stream_private->remote_candidates_and_codecs_set &&
522 encryption_policy != SIPE_ENCRYPTION_POLICY_REJECTED;
524 // Set our key if encryption is enabled.
525 if (stream_private->encryption_key &&
526 encryption_policy != SIPE_ENCRYPTION_POLICY_REJECTED) {
527 sdpmedia->encryption_key = g_memdup(stream_private->encryption_key,
528 SIPE_SRTP_KEY_LEN);
529 sdpmedia->encryption_key_id = stream_private->encryption_key_id;
532 // Append extra attributes assigned to the stream.
533 for (j = stream_private->extra_sdp; j; j = g_slist_next(j)) {
534 struct sipnameval *attr = j->data;
535 attributes = sipe_utils_nameval_add(attributes,
536 attr->name, attr->value);
539 sdpmedia->attributes = attributes;
541 return sdpmedia;
544 static struct sdpmsg *
545 sipe_media_to_sdpmsg(struct sipe_media_call_private *call_private)
547 struct sdpmsg *msg = g_new0(struct sdpmsg, 1);
548 GSList *streams = call_private->streams;
550 for (; streams; streams = streams->next) {
551 struct sdpmedia *media = media_stream_to_sdpmedia(call_private,
552 streams->data);
553 if (media) {
554 msg->media = g_slist_append(msg->media, media);
556 if (msg->ip == NULL)
557 msg->ip = g_strdup(media->ip);
561 msg->media = g_slist_concat(msg->media, call_private->failed_media);
562 call_private->failed_media = NULL;
564 msg->ice_version = call_private->ice_version;
566 return msg;
569 static void
570 sipe_invite_call(struct sipe_media_call_private *call_private, TransCallback tc)
572 struct sipe_core_private *sipe_private = call_private->sipe_private;
573 gchar *hdr;
574 gchar *contact;
575 gchar *p_preferred_identity = NULL;
576 gchar *body;
577 struct sip_session *session;
578 struct sip_dialog *dialog;
579 struct sdpmsg *msg;
581 session = sipe_session_find_call(sipe_private, SIPE_MEDIA_CALL->with);
582 dialog = session->dialogs->data;
584 contact = get_contact(sipe_private);
586 if (sipe_private->uc_line_uri) {
587 gchar *self = sip_uri_self(sipe_private);
588 p_preferred_identity = g_strdup_printf(
589 "P-Preferred-Identity: <%s>, <%s>\r\n",
590 self, sipe_private->uc_line_uri);
591 g_free(self);
594 hdr = g_strdup_printf(
595 "ms-keep-alive: UAC;hop-hop=yes\r\n"
596 "Contact: %s\r\n"
597 "%s"
598 "Content-Type: %s%s\r\n",
599 contact,
600 p_preferred_identity ? p_preferred_identity : "",
601 call_private->invite_content_type ?
602 call_private->invite_content_type : "application/sdp",
603 call_private->invite_content_type ?
604 ";boundary=\"----=_NextPart_000_001E_01CB4397.0B5EB570\"" : "");
606 g_free(contact);
607 g_free(p_preferred_identity);
609 msg = sipe_media_to_sdpmsg(call_private);
610 body = sdpmsg_to_string(msg);
612 if (call_private->extra_invite_section) {
613 gchar *tmp;
614 tmp = g_strdup_printf(
615 "------=_NextPart_000_001E_01CB4397.0B5EB570\r\n"
616 "%s"
617 "\r\n"
618 "------=_NextPart_000_001E_01CB4397.0B5EB570\r\n"
619 "Content-Type: application/sdp\r\n"
620 "Content-Transfer-Encoding: 7bit\r\n"
621 "Content-Disposition: session; handling=optional\r\n"
622 "\r\n"
623 "%s"
624 "\r\n"
625 "------=_NextPart_000_001E_01CB4397.0B5EB570--\r\n",
626 call_private->extra_invite_section, body);
627 g_free(body);
628 body = tmp;
629 sipe_media_add_extra_invite_section(SIPE_MEDIA_CALL, NULL, NULL);
632 sdpmsg_free(msg);
634 dialog->outgoing_invite = sip_transport_invite(sipe_private,
635 hdr,
636 body,
637 dialog,
638 tc);
640 g_free(body);
641 g_free(hdr);
644 static void
645 send_response_with_session_description(struct sipe_media_call_private *call_private, int code, gchar *text)
647 struct sdpmsg *msg = sipe_media_to_sdpmsg(call_private);
648 gchar *body = sdpmsg_to_string(msg);
649 sdpmsg_free(msg);
650 sipmsg_add_header(call_private->invitation, "Content-Type", "application/sdp");
651 sip_transport_response(call_private->sipe_private, call_private->invitation, code, text, body);
652 g_free(body);
655 static gboolean
656 process_invite_call_response(struct sipe_core_private *sipe_private,
657 struct sipmsg *msg,
658 struct transaction *trans);
660 struct sipe_media_stream *
661 sipe_core_media_get_stream_by_id(struct sipe_media_call *call, const gchar *id)
663 GSList *i;
664 for (i = SIPE_MEDIA_CALL_PRIVATE->streams; i; i = i->next) {
665 struct sipe_media_stream *stream = i->data;
666 if (sipe_strequal(stream->id, id))
667 return stream;
669 return NULL;
672 static gboolean
673 update_call_from_remote_sdp(struct sipe_media_call_private* call_private,
674 struct sdpmedia *media)
676 struct sipe_media_stream *stream;
677 GList *backend_candidates = NULL;
678 GList *backend_codecs = NULL;
679 GSList *i;
680 gboolean result = TRUE;
682 stream = sipe_core_media_get_stream_by_id(SIPE_MEDIA_CALL, media->name);
683 if (media->port == 0) {
684 if (stream) {
685 sipe_backend_media_stream_end(SIPE_MEDIA_CALL, stream);
687 return TRUE;
690 if (!stream)
691 return FALSE;
693 if (sipe_utils_nameval_find(media->attributes, "inactive")) {
694 sipe_backend_stream_hold(SIPE_MEDIA_CALL, stream, FALSE);
695 } else if (sipe_backend_stream_is_held(stream)) {
696 sipe_backend_stream_unhold(SIPE_MEDIA_CALL, stream, FALSE);
699 if (SIPE_MEDIA_STREAM_PRIVATE->remote_candidates_and_codecs_set) {
700 return TRUE;
703 for (i = media->codecs; i; i = i->next) {
704 struct sdpcodec *c = i->data;
705 struct sipe_backend_codec *codec;
706 GSList *j;
708 codec = sipe_backend_codec_new(c->id,
709 c->name,
710 c->type,
711 c->clock_rate);
713 for (j = c->parameters; j; j = j->next) {
714 struct sipnameval *attr = j->data;
716 sipe_backend_codec_add_optional_parameter(codec,
717 attr->name,
718 attr->value);
721 backend_codecs = g_list_append(backend_codecs, codec);
724 if (media->encryption_key && SIPE_MEDIA_STREAM_PRIVATE->encryption_key) {
725 sipe_backend_media_set_encryption_keys(SIPE_MEDIA_CALL, stream,
726 SIPE_MEDIA_STREAM_PRIVATE->encryption_key,
727 media->encryption_key);
728 SIPE_MEDIA_STREAM_PRIVATE->encryption_key_id = media->encryption_key_id;
731 result = sipe_backend_set_remote_codecs(SIPE_MEDIA_CALL, stream,
732 backend_codecs);
733 sipe_media_codec_list_free(backend_codecs);
735 if (result == FALSE) {
736 sipe_backend_media_stream_end(SIPE_MEDIA_CALL, stream);
737 return FALSE;
740 for (i = media->candidates; i; i = i->next) {
741 struct sdpcandidate *c = i->data;
742 struct sipe_backend_candidate *candidate;
743 candidate = sipe_backend_candidate_new(c->foundation,
744 c->component,
745 c->type,
746 c->protocol,
747 c->ip,
748 c->port,
749 c->username,
750 c->password);
751 sipe_backend_candidate_set_priority(candidate, c->priority);
753 backend_candidates = g_list_append(backend_candidates, candidate);
756 sipe_backend_media_add_remote_candidates(SIPE_MEDIA_CALL, stream,
757 backend_candidates);
758 sipe_media_candidate_list_free(backend_candidates);
760 SIPE_MEDIA_STREAM_PRIVATE->remote_candidates_and_codecs_set = TRUE;
762 return TRUE;
765 static void
766 apply_remote_message(struct sipe_media_call_private* call_private,
767 struct sdpmsg* msg)
769 GSList *i;
771 sipe_utils_slist_free_full(call_private->failed_media, (GDestroyNotify)sdpmedia_free);
772 call_private->failed_media = NULL;
773 call_private->encryption_compatible = TRUE;
775 for (i = msg->media; i; i = i->next) {
776 struct sdpmedia *media = i->data;
777 const gchar *enc_level =
778 sipe_utils_nameval_find(media->attributes, "encryption");
779 if (sipe_strequal(enc_level, "rejected") &&
780 get_encryption_policy(call_private->sipe_private) == SIPE_ENCRYPTION_POLICY_REQUIRED) {
781 call_private->encryption_compatible = FALSE;
784 if (!update_call_from_remote_sdp(call_private, media)) {
785 media->port = 0;
786 call_private->failed_media =
787 g_slist_append(call_private->failed_media, media);
791 /* We need to keep failed medias until response is sent, remove them
792 * from sdpmsg that is to be freed. */
793 for (i = call_private->failed_media; i; i = i->next) {
794 msg->media = g_slist_remove(msg->media, i->data);
798 static gboolean
799 call_initialized(struct sipe_media_call *call)
801 GSList *streams = SIPE_MEDIA_CALL_PRIVATE->streams;
802 for (; streams; streams = streams->next) {
803 if (!sipe_backend_stream_initialized(call, streams->data)) {
804 return FALSE;
808 return TRUE;
811 // Sends an invite response when the call is accepted and local candidates were
812 // prepared, otherwise does nothing. If error response is sent, call_private is
813 // disposed before function returns.
814 static void
815 maybe_send_first_invite_response(struct sipe_media_call_private *call_private)
817 struct sipe_backend_media *backend_media;
819 backend_media = call_private->public.backend_private;
821 if (!sipe_backend_media_accepted(backend_media) ||
822 !call_initialized(&call_private->public))
823 return;
825 if (!call_private->encryption_compatible) {
826 struct sipe_core_private *sipe_private = call_private->sipe_private;
828 sipmsg_add_header(call_private->invitation, "Warning",
829 "308 lcs.microsoft.com \"Encryption Levels not compatible\"");
830 sip_transport_response(sipe_private,
831 call_private->invitation,
832 488, "Encryption Levels not compatible",
833 NULL);
834 sipe_backend_media_reject(backend_media, FALSE);
835 sipe_backend_notify_error(SIPE_CORE_PUBLIC,
836 _("Unable to establish a call"),
837 _("Encryption settings of peer are incompatible with ours."));
838 } else {
839 send_response_with_session_description(call_private, 200, "OK");
840 sipmsg_free(call_private->invitation);
841 call_private->invitation = NULL;
845 static void
846 stream_initialized_cb(struct sipe_media_call *call,
847 struct sipe_media_stream *stream)
849 if (call_initialized(call)) {
850 struct sipe_media_call_private *call_private = SIPE_MEDIA_CALL_PRIVATE;
852 if (sipe_backend_media_is_initiator(call, stream)) {
853 sipe_invite_call(call_private,
854 process_invite_call_response);
855 } else if (call_private->smsg) {
856 struct sdpmsg *smsg = call_private->smsg;
857 call_private->smsg = NULL;
859 apply_remote_message(call_private, smsg);
860 maybe_send_first_invite_response(call_private);
861 sdpmsg_free(smsg);
866 static void phone_state_publish(struct sipe_core_private *sipe_private)
868 if (SIPE_CORE_PRIVATE_FLAG_IS(OCS2007)) {
869 sipe_ocs2007_phone_state_publish(sipe_private);
870 } else {
871 // TODO: OCS 2005 support. Is anyone still using it at all?
875 static void
876 stream_end_cb(struct sipe_media_call* call, struct sipe_media_stream* stream)
878 remove_stream(call, SIPE_MEDIA_STREAM_PRIVATE);
881 static void
882 media_end_cb(struct sipe_media_call *call)
884 struct sipe_core_private *sipe_private;
886 g_return_if_fail(call);
888 sipe_private = SIPE_MEDIA_CALL_PRIVATE->sipe_private;
890 sipe_media_call_free(SIPE_MEDIA_CALL_PRIVATE);
891 phone_state_publish(sipe_private);
894 static void
895 call_accept_cb(struct sipe_media_call *call, gboolean local)
897 if (local) {
898 maybe_send_first_invite_response(SIPE_MEDIA_CALL_PRIVATE);
900 phone_state_publish(SIPE_MEDIA_CALL_PRIVATE->sipe_private);
903 static void
904 call_reject_cb(struct sipe_media_call *call, gboolean local)
906 if (local) {
907 struct sipe_media_call_private *call_private = SIPE_MEDIA_CALL_PRIVATE;
908 struct sip_session *session = NULL;
910 sip_transport_response(call_private->sipe_private,
911 call_private->invitation,
912 603, "Decline", NULL);
914 session = sipe_session_find_call(call_private->sipe_private,
915 call->with);
916 if (session) {
917 sipe_session_remove(call_private->sipe_private, session);
922 static void
923 av_call_reject_cb(struct sipe_media_call *call, gboolean local)
925 if (!local) {
926 struct sipe_core_private *sipe_private;
927 gchar *desc;
929 sipe_private = SIPE_MEDIA_CALL_PRIVATE->sipe_private;
931 desc = g_strdup_printf(_("User %s rejected call"), call->with);
932 sipe_backend_notify_error(SIPE_CORE_PUBLIC, _("Call rejected"),
933 desc);
934 g_free(desc);
937 call_reject_cb(call, local);
940 static gboolean
941 sipe_media_send_ack(struct sipe_core_private *sipe_private, struct sipmsg *msg,
942 struct transaction *trans);
944 static void call_hold_cb(struct sipe_media_call *call,
945 gboolean local,
946 SIPE_UNUSED_PARAMETER gboolean state)
948 if (local) {
949 sipe_invite_call(SIPE_MEDIA_CALL_PRIVATE, sipe_media_send_ack);
953 static void call_hangup_cb(struct sipe_media_call *call, gboolean local)
955 if (local) {
956 struct sipe_media_call_private *call_private = SIPE_MEDIA_CALL_PRIVATE;
957 struct sip_session *session;
958 session = sipe_session_find_call(call_private->sipe_private,
959 call->with);
961 if (session) {
962 sipe_session_close(call_private->sipe_private, session);
967 static void
968 error_cb(struct sipe_media_call *call, gchar *message)
970 struct sipe_media_call_private *call_private = SIPE_MEDIA_CALL_PRIVATE;
971 struct sipe_core_private *sipe_private = call_private->sipe_private;
972 gboolean initiator = sipe_backend_media_is_initiator(call, NULL);
973 gboolean accepted = sipe_backend_media_accepted(call->backend_private);
975 gchar *title = g_strdup_printf("Call with %s failed", call->with);
976 sipe_backend_notify_error(SIPE_CORE_PUBLIC, title, message);
977 g_free(title);
979 if (!initiator && !accepted) {
980 sip_transport_response(sipe_private,
981 call_private->invitation,
982 488, "Not Acceptable Here", NULL);
985 sipe_backend_media_hangup(call->backend_private, initiator || accepted);
988 struct sipe_media_call *
989 sipe_media_call_new(struct sipe_core_private *sipe_private, const gchar* with,
990 struct sipmsg *msg, SipeIceVersion ice_version,
991 SipeMediaCallFlags flags)
993 struct sipe_media_call_private *call_private;
994 struct sip_session *session;
995 struct sip_dialog *dialog;
996 gchar *cname;
998 session = sipe_session_add_call(sipe_private, with);
1000 dialog = sipe_dialog_add(session);
1001 dialog->with = g_strdup(with);
1003 if (msg) {
1004 gchar *newTag = gentag();
1005 const gchar *oldHeader;
1006 gchar *newHeader;
1008 oldHeader = sipmsg_find_header(msg, "To");
1009 newHeader = g_strdup_printf("%s;tag=%s", oldHeader, newTag);
1010 sipmsg_remove_header_now(msg, "To");
1011 sipmsg_add_header_now(msg, "To", newHeader);
1012 g_free(newTag);
1013 g_free(newHeader);
1015 dialog->callid = g_strdup(sipmsg_find_header(msg, "Call-ID"));
1016 sipe_dialog_parse(dialog, msg, FALSE);
1017 } else {
1018 dialog->callid = gencallid();
1019 dialog->ourtag = gentag();
1020 flags |= SIPE_MEDIA_CALL_INITIATOR;
1023 if (g_hash_table_lookup(sipe_private->media_calls, dialog->callid)) {
1024 SIPE_DEBUG_ERROR("sipe_media_call_new: call already exists for "
1025 "Call-ID %s", dialog->callid);
1026 sipe_session_remove(sipe_private, session);
1027 return NULL;
1030 call_private = g_new0(struct sipe_media_call_private, 1);
1031 call_private->sipe_private = sipe_private;
1032 SIPE_MEDIA_CALL->with = g_strdup(with);
1034 g_hash_table_insert(sipe_private->media_calls,
1035 g_strdup(dialog->callid), call_private);
1037 cname = g_strdup(sipe_private->contact + 1);
1038 cname[strlen(cname) - 1] = '\0';
1040 call_private->public.backend_private = sipe_backend_media_new(SIPE_CORE_PUBLIC,
1041 SIPE_MEDIA_CALL,
1042 with,
1043 flags);
1044 sipe_backend_media_set_cname(call_private->public.backend_private, cname);
1046 call_private->ice_version = ice_version;
1047 call_private->encryption_compatible = TRUE;
1049 call_private->public.stream_initialized_cb = stream_initialized_cb;
1050 call_private->public.stream_end_cb = stream_end_cb;
1051 call_private->public.media_end_cb = media_end_cb;
1052 call_private->public.call_accept_cb = call_accept_cb;
1053 call_private->public.call_reject_cb = call_reject_cb;
1054 call_private->public.call_hold_cb = call_hold_cb;
1055 call_private->public.call_hangup_cb = call_hangup_cb;
1056 call_private->public.error_cb = error_cb;
1058 g_free(cname);
1060 return SIPE_MEDIA_CALL;
1063 void sipe_media_hangup(struct sipe_media_call_private *call_private)
1065 if (call_private) {
1066 sipe_backend_media_hangup(call_private->public.backend_private,
1067 FALSE);
1071 struct sipe_media_stream *
1072 sipe_media_stream_add(struct sipe_media_call *call, const gchar *id,
1073 SipeMediaType type, SipeIceVersion ice_version,
1074 gboolean initiator)
1076 struct sipe_core_private *sipe_private;
1077 struct sipe_media_stream_private *stream_private;
1078 struct sipe_backend_media_stream *backend_stream;
1079 struct sipe_backend_media_relays *backend_media_relays;
1081 sipe_private = SIPE_MEDIA_CALL_PRIVATE->sipe_private;
1083 backend_media_relays = sipe_backend_media_relays_convert(
1084 sipe_private->media_relays,
1085 sipe_private->media_relay_username,
1086 sipe_private->media_relay_password);
1088 backend_stream = sipe_backend_media_add_stream(call, id, call->with,
1089 type, ice_version,
1090 initiator,
1091 backend_media_relays);
1093 sipe_backend_media_relays_free(backend_media_relays);
1095 if (!backend_stream) {
1096 return NULL;
1099 stream_private = g_new0(struct sipe_media_stream_private, 1);
1100 SIPE_MEDIA_STREAM->call = call;
1101 SIPE_MEDIA_STREAM->id = g_strdup(id);
1102 SIPE_MEDIA_STREAM->backend_private = backend_stream;
1104 #ifdef HAVE_SRTP
1106 int i;
1107 stream_private->encryption_key = g_new0(guchar, SIPE_SRTP_KEY_LEN);
1108 for (i = 0; i != SIPE_SRTP_KEY_LEN; ++i) {
1109 stream_private->encryption_key[i] = rand() & 0xff;
1111 stream_private->encryption_key_id = 1;
1113 #endif
1115 stream_private->write_queue = g_queue_new();
1116 stream_private->async_reads = g_queue_new();
1118 SIPE_MEDIA_CALL_PRIVATE->streams =
1119 g_slist_append(SIPE_MEDIA_CALL_PRIVATE->streams,
1120 stream_private);
1122 return SIPE_MEDIA_STREAM;
1125 static void
1126 append_2007_fallback_if_needed(struct sipe_media_call_private *call_private)
1128 struct sipe_core_private *sipe_private = call_private->sipe_private;
1129 const gchar *ip = sipe_backend_network_ip_address(SIPE_CORE_PUBLIC);
1130 gchar *body;
1132 if (sipe_media_get_sip_dialog(SIPE_MEDIA_CALL)->cseq != 0 ||
1133 call_private->ice_version != SIPE_ICE_RFC_5245 ||
1134 sipe_strequal(SIPE_MEDIA_CALL->with, sipe_private->test_call_bot_uri)) {
1135 return;
1138 body = g_strdup_printf("Content-Type: application/sdp\r\n"
1139 "Content-Transfer-Encoding: 7bit\r\n"
1140 "Content-Disposition: session; handling=optional; ms-proxy-2007fallback\r\n"
1141 "\r\n"
1142 "o=- 0 0 IN IP4 %s\r\n"
1143 "s=session\r\n"
1144 "c=IN IP4 %s\r\n"
1145 "m=audio 0 RTP/AVP\r\n",
1146 ip, ip);
1147 sipe_media_add_extra_invite_section(SIPE_MEDIA_CALL,
1148 "multipart/alternative", body);
1151 static void
1152 sipe_media_initiate_call(struct sipe_core_private *sipe_private,
1153 const char *with, SipeIceVersion ice_version,
1154 gboolean with_video)
1156 struct sipe_media_call_private *call_private;
1158 if (sipe_core_media_get_call(SIPE_CORE_PUBLIC)) {
1159 return;
1162 call_private = (struct sipe_media_call_private *)
1163 sipe_media_call_new(sipe_private, with, NULL,
1164 ice_version, 0);
1166 SIPE_MEDIA_CALL->call_reject_cb = av_call_reject_cb;
1168 if (!sipe_media_stream_add(SIPE_MEDIA_CALL, "audio", SIPE_MEDIA_AUDIO,
1169 call_private->ice_version,
1170 TRUE)) {
1171 sipe_backend_notify_error(SIPE_CORE_PUBLIC,
1172 _("Error occured"),
1173 _("Error creating audio stream"));
1174 sipe_media_hangup(call_private);
1175 return;
1178 if (with_video &&
1179 !sipe_media_stream_add(SIPE_MEDIA_CALL, "video", SIPE_MEDIA_VIDEO,
1180 call_private->ice_version,
1181 TRUE)) {
1182 sipe_backend_notify_error(SIPE_CORE_PUBLIC,
1183 _("Error occured"),
1184 _("Error creating video stream"));
1185 sipe_media_hangup(call_private);
1186 return;
1189 append_2007_fallback_if_needed(call_private);
1191 // Processing continues in stream_initialized_cb
1194 void
1195 sipe_core_media_initiate_call(struct sipe_core_public *sipe_public,
1196 const char *with,
1197 gboolean with_video)
1199 sipe_media_initiate_call(SIPE_CORE_PRIVATE, with,
1200 SIPE_ICE_RFC_5245, with_video);
1203 static void
1204 conference_audio_muted_cb(struct sipe_media_stream *stream, gboolean is_muted)
1206 struct sipe_media_call *call = stream->call;
1208 if (!SIPE_MEDIA_CALL_PRIVATE->conference_session) {
1209 return;
1212 sipe_conf_announce_audio_mute_state(SIPE_MEDIA_CALL_PRIVATE->sipe_private,
1213 SIPE_MEDIA_CALL_PRIVATE->conference_session,
1214 is_muted);
1217 void sipe_core_media_connect_conference(struct sipe_core_public *sipe_public,
1218 struct sipe_chat_session *chat_session)
1220 struct sipe_core_private *sipe_private = SIPE_CORE_PRIVATE;
1221 struct sipe_media_call_private *call_private;
1222 struct sipe_media_stream *stream;
1223 struct sip_session *session;
1224 SipeIceVersion ice_version;
1225 gchar *av_uri;
1227 if (!sipe_conf_supports_mcu_type(sipe_private, "audio-video")) {
1228 sipe_backend_notify_error(sipe_public, _("Join conference call"),
1229 _("Conference calls are not supported on this server."));
1230 return;
1233 session = sipe_session_find_chat(sipe_private, chat_session);
1235 if (sipe_core_media_get_call(sipe_public) || !session) {
1236 return;
1239 av_uri = sipe_conf_build_uri(chat_session->id, "audio-video");
1240 if (!av_uri) {
1241 return;
1244 session->is_call = TRUE;
1246 ice_version = SIPE_CORE_PRIVATE_FLAG_IS(LYNC2013) ? SIPE_ICE_RFC_5245 :
1247 SIPE_ICE_DRAFT_6;
1249 call_private = (struct sipe_media_call_private *)
1250 sipe_media_call_new(sipe_private, av_uri, NULL,
1251 ice_version, 0);
1252 call_private->conference_session = session;
1253 SIPE_MEDIA_CALL->call_reject_cb = av_call_reject_cb;
1255 stream = sipe_media_stream_add(SIPE_MEDIA_CALL, "audio",
1256 SIPE_MEDIA_AUDIO,
1257 call_private->ice_version,
1258 TRUE);
1259 if (!stream) {
1260 sipe_backend_notify_error(sipe_public,
1261 _("Error occurred"),
1262 _("Error creating audio stream"));
1264 sipe_media_hangup(call_private);
1267 stream->mute_cb = conference_audio_muted_cb;
1269 g_free(av_uri);
1271 // Processing continues in stream_initialized_cb
1274 struct sipe_media_call *
1275 sipe_core_media_get_call(struct sipe_core_public *sipe_public)
1277 struct sipe_media_call * result = NULL;
1278 GList *calls = g_hash_table_get_values(SIPE_CORE_PRIVATE->media_calls);
1280 for (; calls; calls = g_list_delete_link(calls, calls)) {
1281 if (sipe_core_media_get_stream_by_id(calls->data, "audio")) {
1282 result = calls->data;
1283 break;
1287 return result;
1290 static gboolean phone_number_is_valid(const gchar *phone_number)
1292 if (!phone_number || sipe_strequal(phone_number, "")) {
1293 return FALSE;
1296 if (*phone_number == '+') {
1297 ++phone_number;
1300 while (*phone_number != '\0') {
1301 if (!g_ascii_isdigit(*phone_number)) {
1302 return FALSE;
1304 ++phone_number;
1307 return TRUE;
1310 void sipe_core_media_phone_call(struct sipe_core_public *sipe_public,
1311 const gchar *phone_number)
1313 g_return_if_fail(sipe_public);
1315 if (phone_number_is_valid(phone_number)) {
1316 gchar *phone_uri = g_strdup_printf("sip:%s@%s;user=phone",
1317 phone_number, sipe_public->sip_domain);
1319 sipe_core_media_initiate_call(sipe_public, phone_uri, FALSE);
1321 g_free(phone_uri);
1322 } else {
1323 sipe_backend_notify_error(sipe_public,
1324 _("Unable to establish a call"),
1325 _("Invalid phone number"));
1329 void sipe_core_media_test_call(struct sipe_core_public *sipe_public)
1331 struct sipe_core_private *sipe_private = SIPE_CORE_PRIVATE;
1332 if (!sipe_private->test_call_bot_uri) {
1333 sipe_backend_notify_error(sipe_public,
1334 _("Unable to establish a call"),
1335 _("Audio Test Service is not available."));
1336 return;
1339 sipe_core_media_initiate_call(sipe_public,
1340 sipe_private->test_call_bot_uri, FALSE);
1343 static struct sipe_media_call_private *
1344 sipe_media_from_sipmsg(struct sipe_core_private *sipe_private,
1345 struct sipmsg *msg)
1347 return g_hash_table_lookup(sipe_private->media_calls,
1348 sipmsg_find_header(msg, "Call-ID"));
1351 static void
1352 transport_response_unsupported_sdp(struct sipe_core_private *sipe_private,
1353 struct sipmsg *msg)
1355 sipmsg_add_header(msg, "ms-client-diagnostics",
1356 "52063;reason=\"Unsupported session description\"");
1357 sip_transport_response(sipe_private, msg,
1358 488, "Not Acceptable Here", NULL);
1361 static void
1362 maybe_send_second_invite_response(struct sipe_media_call_private *call_private)
1364 GSList *it;
1366 /* Second INVITE request had to be received and all streams must have
1367 * established candidate pairs before the response can be sent. */
1369 if (!call_private->invitation) {
1370 return;
1373 for (it = call_private->streams; it; it = it->next) {
1374 struct sipe_media_stream_private *stream_private = it->data;
1375 if (!stream_private->established) {
1376 return;
1380 send_response_with_session_description(call_private, 200, "OK");
1383 struct sipe_media_call *
1384 process_incoming_invite_call(struct sipe_core_private *sipe_private,
1385 struct sipmsg *msg)
1387 struct sipe_media_call_private *call_private;
1388 struct sdpmsg *smsg;
1389 gboolean has_new_media = FALSE;
1390 GSList *i;
1392 // Don't allow two voice calls in parallel.
1393 if (!strstr(msg->body, "m=data") &&
1394 !strstr(msg->body, "m=applicationsharing")) {
1395 struct sipe_media_call *call =
1396 sipe_core_media_get_call(SIPE_CORE_PUBLIC);
1397 if (call && !is_media_session_msg(SIPE_MEDIA_CALL_PRIVATE, msg)) {
1398 sip_transport_response(sipe_private, msg,
1399 486, "Busy Here", NULL);
1400 return NULL;
1404 call_private = sipe_media_from_sipmsg(sipe_private, msg);
1406 if (call_private) {
1407 char *self = sip_uri_self(sipe_private);
1408 if (sipe_strequal(SIPE_MEDIA_CALL->with, self)) {
1409 g_free(self);
1410 sip_transport_response(sipe_private, msg, 488, "Not Acceptable Here", NULL);
1411 return NULL;
1413 g_free(self);
1416 smsg = sdpmsg_parse_msg(msg->body);
1417 if (!smsg) {
1418 transport_response_unsupported_sdp(sipe_private, msg);
1419 if (call_private) {
1420 sipe_media_hangup(call_private);
1422 return NULL;
1425 if (!call_private) {
1426 gchar *with = parse_from(sipmsg_find_header(msg, "From"));
1427 SipeMediaCallFlags flags = 0;
1429 if (strstr(msg->body, "m=data")) {
1430 flags |= SIPE_MEDIA_CALL_NO_UI;
1433 call_private = (struct sipe_media_call_private *)
1434 sipe_media_call_new(sipe_private, with,
1435 msg, smsg->ice_version,
1436 flags);
1438 if (!(flags & SIPE_MEDIA_CALL_NO_UI)) {
1439 SIPE_MEDIA_CALL->call_reject_cb = av_call_reject_cb;
1441 g_free(with);
1444 if (call_private->invitation)
1445 sipmsg_free(call_private->invitation);
1446 call_private->invitation = sipmsg_copy(msg);
1448 // Create any new media streams
1449 for (i = smsg->media; i; i = i->next) {
1450 struct sdpmedia *media = i->data;
1451 gchar *id = media->name;
1452 SipeMediaType type;
1454 if ( media->port != 0
1455 && !sipe_core_media_get_stream_by_id(SIPE_MEDIA_CALL, id)) {
1456 if (sipe_strequal(id, "audio"))
1457 type = SIPE_MEDIA_AUDIO;
1458 else if (sipe_strequal(id, "video"))
1459 type = SIPE_MEDIA_VIDEO;
1460 else if (sipe_strequal(id, "data"))
1461 type = SIPE_MEDIA_APPLICATION;
1462 else
1463 continue;
1465 sipe_media_stream_add(SIPE_MEDIA_CALL, id, type,
1466 smsg->ice_version, FALSE);
1467 has_new_media = TRUE;
1471 if (has_new_media) {
1472 sdpmsg_free(call_private->smsg);
1473 call_private->smsg = smsg;
1474 sip_transport_response(sipe_private, call_private->invitation,
1475 180, "Ringing", NULL);
1476 // Processing continues in stream_initialized_cb
1477 } else {
1478 apply_remote_message(call_private, smsg);
1479 sdpmsg_free(smsg);
1480 maybe_send_second_invite_response(call_private);
1483 return SIPE_MEDIA_CALL;
1486 void process_incoming_cancel_call(struct sipe_media_call_private *call_private,
1487 struct sipmsg *msg)
1489 // We respond to the CANCEL request with 200 OK response and
1490 // with 487 Request Terminated to the remote INVITE in progress.
1491 sip_transport_response(call_private->sipe_private, msg, 200, "OK", NULL);
1493 if (call_private->invitation) {
1494 sip_transport_response(call_private->sipe_private,
1495 call_private->invitation,
1496 487, "Request Terminated", NULL);
1499 sipe_backend_media_reject(SIPE_MEDIA_CALL->backend_private, FALSE);
1502 static gboolean
1503 sipe_media_send_ack(struct sipe_core_private *sipe_private,
1504 struct sipmsg *msg,
1505 struct transaction *trans)
1507 struct sipe_media_call_private *call_private;
1508 struct sip_session *session;
1509 struct sip_dialog *dialog;
1510 int tmp_cseq;
1512 call_private = sipe_media_from_sipmsg(sipe_private, msg);
1514 if (!is_media_session_msg(call_private, msg))
1515 return FALSE;
1517 session = sipe_session_find_call(sipe_private, SIPE_MEDIA_CALL->with);
1518 dialog = session->dialogs->data;
1519 if (!dialog)
1520 return FALSE;
1522 tmp_cseq = dialog->cseq;
1524 dialog->cseq = sip_transaction_cseq(trans) - 1;
1525 sip_transport_ack(sipe_private, dialog);
1526 dialog->cseq = tmp_cseq;
1528 dialog->outgoing_invite = NULL;
1530 return TRUE;
1533 static gboolean
1534 sipe_media_send_final_ack(struct sipe_core_private *sipe_private,
1535 struct sipmsg *msg,
1536 struct transaction *trans)
1538 struct sipe_media_call_private *call_private;
1540 if (!sipe_media_send_ack(sipe_private, msg, trans))
1541 return FALSE;
1543 call_private = sipe_media_from_sipmsg(sipe_private, msg);
1545 sipe_backend_media_accept(SIPE_MEDIA_CALL->backend_private, FALSE);
1547 return TRUE;
1550 void
1551 sipe_core_media_stream_candidate_pair_established(struct sipe_media_stream *stream)
1553 struct sipe_media_call *call = stream->call;
1555 GList *active_candidates =
1556 sipe_backend_media_stream_get_active_local_candidates(stream);
1557 guint ready_components = g_list_length(active_candidates);
1559 sipe_media_candidate_list_free(active_candidates);
1561 if (ready_components != 2) {
1562 // We must have both RTP+RTCP candidate pairs established first.
1563 return;
1566 if (SIPE_MEDIA_STREAM_PRIVATE->established) {
1567 return;
1569 SIPE_MEDIA_STREAM_PRIVATE->established = TRUE;
1571 if (stream->candidate_pairs_established_cb) {
1572 stream->candidate_pairs_established_cb(stream);
1575 if (sipe_backend_media_is_initiator(stream->call, NULL)) {
1576 GSList *streams = SIPE_MEDIA_CALL_PRIVATE->streams;
1577 for (; streams; streams = streams->next) {
1578 struct sipe_media_stream_private *s = streams->data;
1579 if (!s->established) {
1580 break;
1584 if (streams == NULL) {
1585 // All call streams have been established.
1586 sipe_invite_call(SIPE_MEDIA_CALL_PRIVATE,
1587 sipe_media_send_final_ack);
1589 } else {
1590 maybe_send_second_invite_response(SIPE_MEDIA_CALL_PRIVATE);
1594 static gboolean
1595 maybe_retry_call_with_ice_version(struct sipe_media_call_private *call_private,
1596 SipeIceVersion ice_version,
1597 struct transaction *trans)
1599 if (call_private->ice_version != ice_version &&
1600 sip_transaction_cseq(trans) == 1) {
1601 GSList *i;
1602 gchar *with;
1603 gboolean with_video = FALSE;
1605 for (i = call_private->streams; i; i = i->next) {
1606 struct sipe_media_stream *stream = i->data;
1608 if (sipe_strequal(stream->id, "video")) {
1609 with_video = TRUE;
1610 } else if (!sipe_strequal(stream->id, "audio")) {
1611 /* Don't retry calls which are neither audio
1612 * nor video. */
1613 return FALSE;
1617 with = g_strdup(SIPE_MEDIA_CALL->with);
1619 sipe_media_hangup(call_private);
1620 SIPE_DEBUG_INFO("Retrying call with ICEv%d.",
1621 ice_version == SIPE_ICE_DRAFT_6 ? 6 : 19);
1622 sipe_media_initiate_call(call_private->sipe_private, with,
1623 ice_version, with_video);
1625 g_free(with);
1626 return TRUE;
1629 return FALSE;
1632 static gboolean
1633 process_invite_call_response(struct sipe_core_private *sipe_private,
1634 struct sipmsg *msg,
1635 struct transaction *trans)
1637 const gchar *with;
1638 struct sipe_media_call_private *call_private;
1639 struct sip_session *session;
1640 struct sip_dialog *dialog;
1641 struct sdpmsg *smsg;
1643 call_private = sipe_media_from_sipmsg(sipe_private,msg);
1645 if (!is_media_session_msg(call_private, msg))
1646 return FALSE;
1648 session = sipe_session_find_call(sipe_private, SIPE_MEDIA_CALL->with);
1649 dialog = session->dialogs->data;
1651 with = dialog->with;
1653 dialog->outgoing_invite = NULL;
1655 if (msg->response == 603 || msg->response == 605) {
1656 // Call rejected by remote peer
1657 sipe_media_send_ack(sipe_private, msg, trans);
1658 sipe_backend_media_reject(SIPE_MEDIA_CALL->backend_private, FALSE);
1660 return TRUE;
1663 if (msg->response >= 400) {
1664 // An error occurred
1665 const gchar *title;
1666 GString *desc = g_string_new("");
1667 gboolean append_responsestr = FALSE;
1669 switch (msg->response) {
1670 case 480: {
1671 title = _("User unavailable");
1673 if (sipmsg_parse_warning(msg, NULL) == 391) {
1674 g_string_append_printf(desc, _("%s does not want to be disturbed"), with);
1675 } else
1676 g_string_append_printf(desc, _("User %s is not available"), with);
1677 break;
1679 case 415:
1680 // OCS/Lync really sends response string with 'Mutipart' typo.
1681 if (sipe_strequal(msg->responsestr, "Mutipart mime in content type not supported by Archiving CDR service") &&
1682 maybe_retry_call_with_ice_version(call_private, SIPE_ICE_DRAFT_6, trans)) {
1683 return TRUE;
1685 title = _("Unsupported media type");
1686 break;
1687 case 488: {
1688 /* Check for incompatible encryption levels error.
1690 * MS Lync 2010:
1691 * 488 Not Acceptable Here
1692 * ms-client-diagnostics: 52017;reason="Encryption levels dont match"
1694 * older clients (and SIPE itself):
1695 * 488 Encryption Levels not compatible
1697 const gchar *ms_diag = sipmsg_find_header(msg, "ms-client-diagnostics");
1698 SipeIceVersion retry_ice_version = SIPE_ICE_DRAFT_6;
1700 if (sipe_strequal(msg->responsestr, "Encryption Levels not compatible") ||
1701 (ms_diag && g_str_has_prefix(ms_diag, "52017;"))) {
1702 title = _("Unable to establish a call");
1703 g_string_append(desc, _("Encryption settings of peer are incompatible with ours."));
1704 break;
1707 /* Check if this is failed conference using
1708 * ICEv6 with reason "Error parsing SDP" and
1709 * retry using ICEv19. */
1710 ms_diag = sipmsg_find_header(msg, "ms-diagnostics");
1711 if (ms_diag && g_str_has_prefix(ms_diag, "7008;")) {
1712 retry_ice_version = SIPE_ICE_RFC_5245;
1715 if (maybe_retry_call_with_ice_version(call_private, retry_ice_version, trans)) {
1716 return TRUE;
1718 // Break intentionally omitted
1720 default:
1721 title = _("Error occured");
1722 g_string_append(desc, _("Unable to establish a call"));
1723 append_responsestr = TRUE;
1724 break;
1727 if (append_responsestr) {
1728 gchar *reason = sipmsg_get_ms_diagnostics_reason(msg);
1730 g_string_append_printf(desc, "\n%d %s",
1731 msg->response, msg->responsestr);
1732 if (reason) {
1733 g_string_append_printf(desc, "\n\n%s", reason);
1734 g_free(reason);
1738 sipe_backend_notify_error(SIPE_CORE_PUBLIC, title, desc->str);
1739 g_string_free(desc, TRUE);
1741 sipe_media_send_ack(sipe_private, msg, trans);
1742 sipe_media_hangup(call_private);
1744 return TRUE;
1747 sipe_dialog_parse(dialog, msg, TRUE);
1748 smsg = sdpmsg_parse_msg(msg->body);
1749 if (!smsg) {
1750 transport_response_unsupported_sdp(sipe_private, msg);
1751 sipe_media_hangup(call_private);
1752 return FALSE;
1755 apply_remote_message(call_private, smsg);
1756 sdpmsg_free(smsg);
1758 sipe_media_send_ack(sipe_private, msg, trans);
1760 return TRUE;
1762 // Waits until sipe_core_media_candidate_pair_established() is invoked.
1765 gboolean is_media_session_msg(struct sipe_media_call_private *call_private,
1766 struct sipmsg *msg)
1768 if (!call_private) {
1769 return FALSE;
1772 return sipe_media_from_sipmsg(call_private->sipe_private, msg) == call_private;
1775 static void
1776 end_call(SIPE_UNUSED_PARAMETER gpointer key,
1777 struct sipe_media_call_private *call_private,
1778 SIPE_UNUSED_PARAMETER gpointer user_data)
1780 struct sipe_backend_media *backend_private;
1782 backend_private = call_private->public.backend_private;
1784 if (!sipe_backend_media_is_initiator(SIPE_MEDIA_CALL, NULL) &&
1785 !sipe_backend_media_accepted(backend_private)) {
1786 sip_transport_response(call_private->sipe_private,
1787 call_private->invitation,
1788 480, "Temporarily Unavailable", NULL);
1789 } else {
1790 struct sip_session *session;
1792 session = sipe_session_find_call(call_private->sipe_private,
1793 SIPE_MEDIA_CALL->with);
1794 if (session)
1795 sipe_session_close(call_private->sipe_private, session);
1798 sipe_media_hangup(call_private);
1801 void
1802 sipe_media_handle_going_offline(struct sipe_core_private *sipe_private)
1804 g_hash_table_foreach(sipe_private->media_calls, (GHFunc) end_call, NULL);
1807 gboolean sipe_media_is_conference_call(struct sipe_media_call_private *call_private)
1809 return g_strstr_len(SIPE_MEDIA_CALL->with, -1, "app:conf:audio-video:") != NULL;
1812 struct sipe_core_private *
1813 sipe_media_get_sipe_core_private(struct sipe_media_call *call)
1815 g_return_val_if_fail(call, NULL);
1817 return SIPE_MEDIA_CALL_PRIVATE->sipe_private;
1820 struct sip_dialog *
1821 sipe_media_get_sip_dialog(struct sipe_media_call *call)
1823 struct sip_session *session;
1825 g_return_val_if_fail(call, NULL);
1827 session = sipe_session_find_call(SIPE_MEDIA_CALL_PRIVATE->sipe_private,
1828 call->with);
1830 if (!session || !session->dialogs) {
1831 return NULL;
1834 return session->dialogs->data;
1837 static void
1838 sipe_media_relay_free(struct sipe_media_relay *relay)
1840 g_free(relay->hostname);
1841 if (relay->dns_query)
1842 sipe_backend_dns_query_cancel(relay->dns_query);
1843 g_free(relay);
1846 void
1847 sipe_media_relay_list_free(GSList *list)
1849 for (; list; list = g_slist_delete_link(list, list))
1850 sipe_media_relay_free(list->data);
1853 static void
1854 relay_ip_resolved_cb(struct sipe_media_relay* relay,
1855 const gchar *ip, SIPE_UNUSED_PARAMETER guint port)
1857 gchar *hostname = relay->hostname;
1858 relay->dns_query = NULL;
1860 if (ip && port) {
1861 relay->hostname = g_strdup(ip);
1862 SIPE_DEBUG_INFO("Media relay %s resolved to %s.", hostname, ip);
1863 } else {
1864 relay->hostname = NULL;
1865 SIPE_DEBUG_INFO("Unable to resolve media relay %s.", hostname);
1868 g_free(hostname);
1871 static gboolean
1872 process_get_av_edge_credentials_response(struct sipe_core_private *sipe_private,
1873 struct sipmsg *msg,
1874 SIPE_UNUSED_PARAMETER struct transaction *trans)
1876 g_free(sipe_private->media_relay_username);
1877 g_free(sipe_private->media_relay_password);
1878 sipe_media_relay_list_free(sipe_private->media_relays);
1879 sipe_private->media_relay_username = NULL;
1880 sipe_private->media_relay_password = NULL;
1881 sipe_private->media_relays = NULL;
1883 if (msg->response >= 400) {
1884 SIPE_DEBUG_INFO_NOFORMAT("process_get_av_edge_credentials_response: SERVICE response is not 200. "
1885 "Failed to obtain A/V Edge credentials.");
1886 return FALSE;
1889 if (msg->response == 200) {
1890 sipe_xml *xn_response = sipe_xml_parse(msg->body, msg->bodylen);
1892 if (sipe_strequal("OK", sipe_xml_attribute(xn_response, "reasonPhrase"))) {
1893 const sipe_xml *xn_credentials = sipe_xml_child(xn_response, "credentialsResponse/credentials");
1894 const sipe_xml *xn_relays = sipe_xml_child(xn_response, "credentialsResponse/mediaRelayList");
1895 const sipe_xml *item;
1896 GSList *relays = NULL;
1898 item = sipe_xml_child(xn_credentials, "username");
1899 sipe_private->media_relay_username = sipe_xml_data(item);
1900 item = sipe_xml_child(xn_credentials, "password");
1901 sipe_private->media_relay_password = sipe_xml_data(item);
1903 for (item = sipe_xml_child(xn_relays, "mediaRelay"); item; item = sipe_xml_twin(item)) {
1904 struct sipe_media_relay *relay = g_new0(struct sipe_media_relay, 1);
1905 const sipe_xml *node;
1906 gchar *tmp;
1908 node = sipe_xml_child(item, "hostName");
1909 relay->hostname = sipe_xml_data(node);
1911 node = sipe_xml_child(item, "udpPort");
1912 if (node) {
1913 tmp = sipe_xml_data(node);
1914 if (tmp) {
1915 relay->udp_port = atoi(tmp);
1916 g_free(tmp);
1920 node = sipe_xml_child(item, "tcpPort");
1921 if (node) {
1922 tmp = sipe_xml_data(node);
1923 if (tmp) {
1924 relay->tcp_port = atoi(tmp);
1925 g_free(tmp);
1929 relays = g_slist_append(relays, relay);
1931 relay->dns_query = sipe_backend_dns_query_a(
1932 SIPE_CORE_PUBLIC,
1933 relay->hostname,
1934 relay->udp_port,
1935 (sipe_dns_resolved_cb) relay_ip_resolved_cb,
1936 relay);
1938 SIPE_DEBUG_INFO("Media relay: %s TCP: %d UDP: %d",
1939 relay->hostname,
1940 relay->tcp_port, relay->udp_port);
1943 sipe_private->media_relays = relays;
1946 sipe_xml_free(xn_response);
1949 return TRUE;
1952 void
1953 sipe_media_get_av_edge_credentials(struct sipe_core_private *sipe_private)
1955 // TODO: re-request credentials after duration expires?
1956 static const char CRED_REQUEST_XML[] =
1957 "<request requestID=\"%d\" "
1958 "from=\"%s\" "
1959 "version=\"1.0\" "
1960 "to=\"%s\" "
1961 "xmlns=\"http://schemas.microsoft.com/2006/09/sip/mrasp\" "
1962 "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">"
1963 "<credentialsRequest credentialsRequestID=\"%d\">"
1964 "<identity>%s</identity>"
1965 "<location>%s</location>"
1966 "<duration>480</duration>"
1967 "</credentialsRequest>"
1968 "</request>";
1970 int request_id = rand();
1971 gchar *self;
1972 gchar *body;
1974 if (!sipe_private->mras_uri)
1975 return;
1977 self = sip_uri_self(sipe_private);
1979 body = g_strdup_printf(
1980 CRED_REQUEST_XML,
1981 request_id,
1982 self,
1983 sipe_private->mras_uri,
1984 request_id,
1985 self,
1986 SIPE_CORE_PRIVATE_FLAG_IS(REMOTE_USER) ? "internet" : "intranet");
1987 g_free(self);
1989 sip_transport_service(sipe_private,
1990 sipe_private->mras_uri,
1991 "Content-Type: application/msrtc-media-relay-auth+xml\r\n",
1992 body,
1993 process_get_av_edge_credentials_response);
1995 g_free(body);
1998 void
1999 sipe_media_add_extra_invite_section(struct sipe_media_call *call,
2000 const gchar *invite_content_type,
2001 gchar *body)
2003 g_free(SIPE_MEDIA_CALL_PRIVATE->extra_invite_section);
2004 g_free(SIPE_MEDIA_CALL_PRIVATE->invite_content_type);
2005 SIPE_MEDIA_CALL_PRIVATE->extra_invite_section = body;
2006 SIPE_MEDIA_CALL_PRIVATE->invite_content_type =
2007 g_strdup(invite_content_type);
2010 void
2011 sipe_media_stream_add_extra_attribute(struct sipe_media_stream *stream,
2012 const gchar *name, const gchar *value)
2014 SIPE_MEDIA_STREAM_PRIVATE->extra_sdp =
2015 sipe_utils_nameval_add(SIPE_MEDIA_STREAM_PRIVATE->extra_sdp,
2016 name, value);
2019 #ifdef HAVE_XDATA
2020 void
2021 sipe_core_media_stream_readable(struct sipe_media_stream *stream)
2023 g_return_if_fail(stream);
2025 if (g_queue_is_empty(SIPE_MEDIA_STREAM_PRIVATE->async_reads) &&
2026 stream->read_cb) {
2027 stream->read_cb(stream);
2030 while (!g_queue_is_empty(SIPE_MEDIA_STREAM_PRIVATE->async_reads)) {
2031 struct async_read_data *data;
2032 guint8 *pos;
2033 gssize len;
2034 gssize bytes_read;
2036 data = g_queue_peek_head(SIPE_MEDIA_STREAM_PRIVATE->async_reads);
2037 pos = data->buffer + SIPE_MEDIA_STREAM_PRIVATE->read_pos;
2038 len = data->len - SIPE_MEDIA_STREAM_PRIVATE->read_pos;
2040 bytes_read = sipe_backend_media_stream_read(stream, pos, len);
2041 if (bytes_read == -1) {
2042 struct sipe_media_call *call = stream->call;
2043 struct sipe_core_private *sipe_private =
2044 SIPE_MEDIA_CALL_PRIVATE->sipe_private;
2046 sipe_backend_notify_error(SIPE_CORE_PUBLIC,
2047 _("Media error"),
2048 _("Error while reading from stream"));
2049 sipe_media_hangup(SIPE_MEDIA_CALL_PRIVATE);
2050 return;
2053 SIPE_MEDIA_STREAM_PRIVATE->read_pos += bytes_read;
2055 if (SIPE_MEDIA_STREAM_PRIVATE->read_pos == data->len) {
2056 data->callback(stream, data->buffer, data->len);
2057 SIPE_MEDIA_STREAM_PRIVATE->read_pos = 0;
2058 g_queue_pop_head(SIPE_MEDIA_STREAM_PRIVATE->async_reads);
2059 g_free(data);
2060 } else {
2061 // Still not enough data to finish the read.
2062 return;
2067 void
2068 sipe_media_stream_read_async(struct sipe_media_stream *stream,
2069 gpointer buffer, gsize len,
2070 sipe_media_stream_read_callback callback)
2072 struct async_read_data *data;
2074 g_return_if_fail(stream && buffer && callback);
2076 data = g_new0(struct async_read_data, 1);
2077 data->buffer = buffer;
2078 data->len = len;
2079 data->callback = callback;
2081 g_queue_push_tail(SIPE_MEDIA_STREAM_PRIVATE->async_reads, data);
2084 static void
2085 stream_append_buffer(struct sipe_media_stream *stream,
2086 guint8 *buffer, guint len)
2088 GByteArray *b = g_byte_array_sized_new(len);
2089 g_byte_array_append(b, buffer, len);
2090 g_queue_push_tail(SIPE_MEDIA_STREAM_PRIVATE->write_queue, b);
2093 gboolean
2094 sipe_media_stream_write(struct sipe_media_stream *stream,
2095 gpointer buffer, gsize len)
2097 if (!sipe_media_stream_is_writable(stream)) {
2098 stream_append_buffer(stream, buffer, len);
2099 return FALSE;
2100 } else {
2101 guint written;
2103 written = sipe_backend_media_stream_write(stream, buffer, len);
2104 if (written == len) {
2105 return TRUE;
2108 stream_append_buffer(stream,
2109 (guint8 *)buffer + written, len - written);
2110 return FALSE;
2114 void
2115 sipe_core_media_stream_writable(struct sipe_media_stream *stream,
2116 gboolean writable)
2118 SIPE_MEDIA_STREAM_PRIVATE->writable = writable;
2120 if (!writable) {
2121 return;
2124 while (!g_queue_is_empty(SIPE_MEDIA_STREAM_PRIVATE->write_queue)) {
2125 GByteArray *b;
2126 guint written;
2128 b = g_queue_peek_head(SIPE_MEDIA_STREAM_PRIVATE->write_queue);
2130 written = sipe_backend_media_stream_write(stream, b->data, b->len);
2131 if (written != b->len) {
2132 g_byte_array_remove_range(b, 0, written);
2133 return;
2136 g_byte_array_unref(b);
2137 g_queue_pop_head(SIPE_MEDIA_STREAM_PRIVATE->write_queue);
2140 if (sipe_media_stream_is_writable(stream) && stream->writable_cb) {
2141 stream->writable_cb(stream);
2145 gboolean
2146 sipe_media_stream_is_writable(struct sipe_media_stream *stream)
2148 return SIPE_MEDIA_STREAM_PRIVATE->writable &&
2149 g_queue_is_empty(SIPE_MEDIA_STREAM_PRIVATE->write_queue);
2151 #endif
2153 void
2154 sipe_media_stream_set_data(struct sipe_media_stream *stream, gpointer data,
2155 GDestroyNotify free_func)
2157 struct sipe_media_stream_private *stream_private =
2158 SIPE_MEDIA_STREAM_PRIVATE;
2160 g_return_if_fail(stream_private);
2162 if (stream_private->data && stream_private->data_free_func) {
2163 stream_private->data_free_func(stream_private->data);
2166 stream_private->data = data;
2167 stream_private->data_free_func = free_func;
2170 gpointer
2171 sipe_media_stream_get_data(struct sipe_media_stream *stream)
2173 g_return_val_if_fail(stream, NULL);
2175 return SIPE_MEDIA_STREAM_PRIVATE->data;
2179 Local Variables:
2180 mode: c
2181 c-file-style: "bsd"
2182 indent-tabs-mode: t
2183 tab-width: 8
2184 End: