audio: Send ACK to error invite response before media call structures are deallocated
[siplcs.git] / src / core / sipe-media.c
blobcdc0fcd21c1f251c1cc68ed4c730f9e90679b075
1 /**
2 * @file sipe-media.c
4 * pidgin-sipe
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
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
27 #include <stdio.h>
29 #include <glib.h>
31 #include "sipe-common.h"
32 #include "sipmsg.h"
33 #include "sip-transport.h"
34 #include "sipe-backend.h"
35 #include "sdpmsg.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"
42 #include "sipe-nls.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;
49 gchar *with;
51 struct sipe_backend_stream *voice_stream;
53 struct sipmsg *invitation;
54 gboolean legacy_mode;
55 gboolean using_nice;
56 gboolean encryption_compatible;
58 struct sdpmsg *smsg;
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);
75 static void
76 sipe_media_call_free(struct sipe_media_call_private *call_private)
78 if (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,
83 call_private->with);
84 if (session)
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);
92 g_free(call_private);
96 static GSList *
97 backend_candidates_to_sdpcandidate(GList *candidates)
99 GSList *result = NULL;
100 GList *i;
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);
119 return result;
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);
130 GList *candidates;
132 GList *i;
133 GSList *j;
135 GSList *attributes = NULL;
136 guint rtcp_port;
138 // Process codecs
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);
142 GList *params;
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);
170 if (!candidates)
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);
188 g_free(username);
189 g_free(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", "");
210 if (rtcp_port) {
211 gchar *tmp = g_strdup_printf("%u", rtcp_port);
212 attributes = sipe_utils_nameval_add(attributes, "rtcp", tmp);
213 g_free(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);
228 return msg;
231 static void
232 sipe_invite_call(struct sipe_core_private *sipe_private, TransCallback tc)
234 gchar *hdr;
235 gchar *contact;
236 gchar *body;
237 struct sipe_media_call_private *call_private = sipe_private->media_call;
238 struct sip_session *session;
239 struct sip_dialog *dialog;
240 struct sdpmsg *msg;
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"
250 "Contact: %s%s\r\n"
251 "Content-Type: application/sdp\r\n",
252 contact,
253 (call_private->public.local_on_hold || call_private->public.remote_on_hold) ? ";+sip.rendering=\"no\"" : "");
254 g_free(contact);
256 msg = sipe_media_to_sdpmsg(call_private);
257 body = sdpmsg_to_string(msg);
258 sdpmsg_free(msg);
260 dialog->outgoing_invite = sip_transport_invite(sipe_private,
261 hdr,
262 body,
263 dialog,
264 tc);
266 g_free(body);
267 g_free(hdr);
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;
275 gchar *newHeader;
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);
282 g_free(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);
289 return dialog;
292 static void
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);
297 sdpmsg_free(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);
300 g_free(body);
303 static gboolean
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");
314 static void
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",
322 NULL);
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."));
328 static gboolean
329 process_invite_call_response(struct sipe_core_private *sipe_private,
330 struct sipmsg *msg,
331 struct transaction *trans);
333 static gboolean
334 apply_remote_message(struct sipe_media_call_private* call_private,
335 struct sdpmsg* msg)
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;
341 GSList *i;
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,
351 c->component,
352 c->type,
353 c->protocol,
354 c->ip,
355 c->port);
356 sipe_backend_candidate_set_priority(candidate, c->priority);
358 if (username)
359 sipe_backend_candidate_set_username_and_pwd(candidate,
360 username,
361 password);
363 backend_candidates = g_list_append(backend_candidates, candidate);
366 sipe_backend_media_add_remote_candidates(backend_media,
367 backend_stream,
368 backend_candidates);
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;
374 GSList *j;
376 codec = sipe_backend_codec_new(c->id,
377 c->name,
378 c->clock_rate,
379 c->type);
381 for (j = c->parameters; j; j = j->next) {
382 struct sipnameval *attr = j->data;
384 sipe_backend_codec_add_optional_parameter(codec,
385 attr->name,
386 attr->value);
389 backend_codecs = g_list_append(backend_codecs, codec);
392 sipe_backend_set_remote_codecs(backend_media,
393 backend_stream,
394 backend_codecs);
395 sipe_media_codec_list_free(backend_codecs);
397 call_private->legacy_mode = msg->legacy;
398 call_private->encryption_compatible = encryption_levels_compatible(msg);
400 return TRUE;
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);
411 return;
414 if (!apply_remote_message(call_private, call_private->smsg)) {
415 sipe_media_hangup(call_private->sipe_private);
416 return;
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)
433 if (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);
438 return;
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;
449 if (local) {
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);
456 static gboolean
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;
477 if (local) {
478 struct sip_session *session;
479 session = sipe_session_find_call(call_private->sipe_private,
480 call_private->with);
482 if (session) {
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,
498 SIPE_MEDIA_CALL,
499 with,
500 initiator);
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;
516 return call_private;
519 void sipe_media_hangup(struct sipe_core_private *sipe_private)
521 struct sipe_media_call_private *call_private = sipe_private->media_call;
522 if (call_private)
523 sipe_backend_media_hangup(call_private->public.backend_private,
524 FALSE);
527 void
528 sipe_core_media_initiate_call(struct sipe_core_public *sipe_public,
529 const char *with)
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)
537 return;
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,
551 with,
552 SIPE_MEDIA_AUDIO,
553 call_private->using_nice,
554 TRUE);
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);
560 return;
563 sipe_private->media_call = call_private;
565 // Processing continues in candidates_prepared_cb
568 void
569 process_incoming_invite_call(struct sipe_core_private *sipe_private,
570 struct sipmsg *msg)
572 struct sipe_media_call_private *call_private = sipe_private->media_call;
573 struct sdpmsg *smsg;
575 if (call_private && !is_media_session_msg(call_private, msg)) {
576 sip_transport_response(sipe_private, msg, 486, "Busy Here", NULL);
577 return;
580 smsg = sdpmsg_parse_msg(msg->body);
581 if (!smsg) {
582 sipe_media_hangup(sipe_private);
583 return;
586 if (call_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,
597 FALSE);
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);
602 } else {
603 send_response_with_session_description(call_private,
604 200, "OK");
607 sdpmsg_free(smsg);
608 } else {
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,
622 with,
623 SIPE_MEDIA_AUDIO,
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);
630 g_free(with);
632 // Processing continues in candidates_prepared_cb
636 void process_incoming_cancel_call(struct sipe_core_private *sipe_private,
637 struct sipmsg *msg)
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);
653 static gboolean
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;
661 int trans_cseq;
662 int tmp_cseq;
664 session = sipe_session_find_call(sipe_private, call_private->with);
665 dialog = session->dialogs->data;
666 if (!dialog)
667 return FALSE;
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;
678 return TRUE;
681 static gboolean
682 process_invite_call_response(struct sipe_core_private *sipe_private,
683 struct sipmsg *msg,
684 struct transaction *trans)
686 const gchar *with;
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;
691 struct sdpmsg *smsg;
693 if (!is_media_session_msg(call_private, msg))
694 return FALSE;
696 session = sipe_session_find_call(sipe_private, call_private->with);
697 dialog = session->dialogs->data;
699 backend_private = call_private->public.backend_private;
700 with = dialog->with;
702 dialog->outgoing_invite = NULL;
704 if (msg->response >= 400) {
705 // Call rejected by remote peer or an error occurred
706 gchar *title;
707 GString *desc = g_string_new("");
709 switch (msg->response) {
710 case 480:
711 title = _("User unavailable");
712 g_string_append_printf(desc, _("User %s is not available"), with);
713 break;
714 case 603:
715 case 605:
716 title = _("Call rejected");
717 g_string_append_printf(desc, _("User %s rejected call"), with);
718 break;
719 default:
720 title = _("Error occured");
721 g_string_append(desc, _("Unable to establish a call"));
722 break;
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);
733 return TRUE;
736 sipe_dialog_parse(dialog, msg, TRUE);
737 smsg = sdpmsg_parse_msg(msg->body);
738 if (!smsg) {
739 sipe_media_hangup(sipe_private);
740 return FALSE;
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,
751 "PRACK",
752 with,
753 with,
754 rack,
755 NULL,
756 dialog,
757 NULL);
758 g_free(rack);
759 } else {
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,
772 with,
773 SIPE_MEDIA_AUDIO,
774 FALSE,
775 TRUE);
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
784 } else {
785 sipe_invite_call(sipe_private, sipe_media_send_ack);
789 sdpmsg_free(smsg);
791 return TRUE;
794 gboolean is_media_session_msg(struct sipe_media_call_private *call_private,
795 struct sipmsg *msg)
797 if (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,
802 call_private->with);
803 if (session) {
804 struct sip_dialog *dialog = session->dialogs->data;
805 return sipe_strequal(dialog->callid, callid);
808 return FALSE;
812 Local Variables:
813 mode: c
814 c-file-style: "bsd"
815 indent-tabs-mode: t
816 tab-width: 8
817 End: