1 /*
2 * sip-media-session.c - Source for SIPMediaSession
3 * Copyright (C) 2005 Collabora Ltd.
4 * Copyright (C) 2005,2006,2007 Nokia Corporation
5 * @author Kai Vehmanen <first.surname@nokia.com>
6 * @author Mikhail Zabaluev <first.surname@nokia.com>
7 *
8 * Based on telepathy-gabble implementation (gabble-media-session).
9 * @author Ole Andre Vadla Ravnaas <ole.andre.ravnaas@collabora.co.uk>
10 *
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public License
13 * version 2.1 as published by the Free Software Foundation.
14 *
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
19 *
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23 */
24
25 #include <dbus/dbus-glib.h>
26 #include <stdlib.h>
27 #include <time.h>
28 #include <string.h>
29
30 #include <sofia-sip/sip_status.h>
31
32 #include <telepathy-glib/interfaces.h>
33 #include <telepathy-glib/dbus.h>
34 #include <telepathy-glib/errors.h>
35 #include <telepathy-glib/svc-media-interfaces.h>
36
37 #include "config.h"
38
39 #include "sip-media-session.h"
40 #include "sip-media-channel.h"
41 #include "sip-media-stream.h"
42 #include "sip-connection-helpers.h"
43 #include "telepathy-helpers.h"
44
45 #define DEBUG_FLAG SIP_DEBUG_MEDIA
46 #include "debug.h"
47
48 static void session_handler_iface_init (gpointer, gpointer);
49
50 G_DEFINE_TYPE_WITH_CODE(SIPMediaSession,
51 sip_media_session,
52 G_TYPE_OBJECT,
53 G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_MEDIA_SESSION_HANDLER,
54 session_handler_iface_init)
55 )
56
57 #define DEFAULT_SESSION_TIMEOUT 50000
58
59 /* signal enum */
60 enum
61 {
62 SIG_STREAM_ADDED,
63 SIG_LAST_SIGNAL
64 };
65
66 /* properties */
67 enum
68 {
69 PROP_MEDIA_CHANNEL = 1,
70 PROP_OBJECT_PATH,
71 PROP_NUA_OP,
72 PROP_PEER,
73 PROP_LOCAL_IP_ADDRESS,
74 PROP_STATE,
75 LAST_PROPERTY
76 };
77
78 static guint signals[SIG_LAST_SIGNAL] = {0};
79
80 #ifdef ENABLE_DEBUG
81
82 /**
83 * StreamEngine session states:
84 * - created, objects created, local cand/codec query ongoing
85 * - invite-sent, an INVITE with local SDP sent, awaiting response
86 * - invite-received, a remote INVITE received, response is pending
87 * - response-received, a 200 OK received, codec intersection is in progress
88 * - active, codecs and candidate pairs have been negotiated (note,
89 * SteamEngine might still fail to verify connectivity and report
90 * an error)
91 * - reinvite-sent, a local re-INVITE sent, response is pending
92 * - reinvite-received, a remote re-INVITE received, response is pending
93 * - ended, session has ended
94 */
95 static const char* session_states[] =
96 {
97 "created",
98 "invite-sent",
99 "invite-received",
100 "response-received",
101 "active",
102 "reinvite-sent",
103 "reinvite-received",
104 "ended"
105 };
106
107 #endif /* ENABLE_DEBUG */
108
109 /* private structure */
110 typedef struct _SIPMediaSessionPrivate SIPMediaSessionPrivate;
111
112 struct _SIPMediaSessionPrivate
113 {
114 SIPMediaChannel *channel; /** see gobj. prop. 'media-channel' */
115 gchar *object_path; /** see gobj. prop. 'object-path' */
116 nua_handle_t *nua_op; /** see gobj. prop. 'nua-handle' */
117 TpHandle peer; /** see gobj. prop. 'peer' */
118 gchar *local_ip_address; /** see gobj. prop. 'local-ip-address' */
119 SIPMediaSessionState state; /** see gobj. prop. 'state' */
120 nua_saved_event_t saved_event[1]; /** Saved incoming request event */
121 gint local_non_ready; /** number of streams with local information update pending */
122 guint catcher_id;
123 guint timer_id;
124 su_home_t *home; /** Sofia memory home for remote SDP session structure */
125 su_home_t *backup_home; /** Sofia memory home for previous generation remote SDP session*/
126 sdp_session_t *remote_sdp; /** last received remote session */
127 sdp_session_t *backup_remote_sdp; /** previous remote session */
128 GPtrArray *streams;
129 gboolean accepted; /**< session has been locally accepted for use */
130 gboolean se_ready; /**< connection established with stream-engine */
131 gboolean pending_offer; /**< local media have been changed, but a re-INVITE is pending */
132 gboolean dispose_has_run;
133 };
134
135 #define SIP_MEDIA_SESSION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SIP_TYPE_MEDIA_SESSION, SIPMediaSessionPrivate))
136
137 static void sip_media_session_get_property (GObject *object,
138 guint property_id,
139 GValue *value,
140 GParamSpec *pspec);
141 static void sip_media_session_set_property (GObject *object,
142 guint property_id,
143 const GValue *value,
144 GParamSpec *pspec);
145
146 static SIPMediaStream *
147 sip_media_session_get_stream (SIPMediaSession *self,
148 guint stream_id,
149 GError **error);
150
151 static void priv_session_state_changed (SIPMediaSession *session,
152 SIPMediaSessionState prev_state);
153 static gboolean priv_catch_remote_nonupdate (gpointer data);
154 static gboolean priv_timeout_session (gpointer data);
155 static SIPMediaStream* priv_create_media_stream (SIPMediaSession *session,
156 guint media_type,
157 guint pending_send_flags);
158 static void priv_request_response_step (SIPMediaSession *session);
159 static void priv_session_invite (SIPMediaSession *session, gboolean reinvite);
160 static void priv_local_media_changed (SIPMediaSession *session);
161 static gboolean priv_update_remote_media (SIPMediaSession *session,
162 gboolean authoritative);
163 static void priv_save_event (SIPMediaSession *self);
164 static void priv_zap_event (SIPMediaSession *self);
165
sip_media_session_init(SIPMediaSession * obj)166 static void sip_media_session_init (SIPMediaSession *obj)
167 {
168 SIPMediaSessionPrivate *priv = SIP_MEDIA_SESSION_GET_PRIVATE (obj);
169
170 priv->state = SIP_MEDIA_SESSION_STATE_CREATED;
171
172 /* allocate any data required by the object here */
173 priv->streams = g_ptr_array_new ();
174 }
175
176 static GObject *
sip_media_session_constructor(GType type,guint n_props,GObjectConstructParam * props)177 sip_media_session_constructor (GType type, guint n_props,
178 GObjectConstructParam *props)
179 {
180 GObject *obj;
181 SIPMediaSessionPrivate *priv;
182 DBusGConnection *bus;
183
184 obj = G_OBJECT_CLASS (sip_media_session_parent_class)->
185 constructor (type, n_props, props);
186 priv = SIP_MEDIA_SESSION_GET_PRIVATE (SIP_MEDIA_SESSION (obj));
187
188 if (priv->nua_op)
189 {
190 nua_hmagic_t *nua_op_magic;
191
192 g_assert (priv->channel != NULL);
193
194 /* migrating a NUA handle between two active media channels
195 * makes no sense either */
196 nua_op_magic = nua_handle_magic (priv->nua_op);
197 g_return_val_if_fail (nua_op_magic == NULL || nua_op_magic == priv->channel, NULL);
198
199 /* tell the NUA that we're handling this call */
200 nua_handle_bind (priv->nua_op, priv->channel);
201 }
202
203 bus = tp_get_bus ();
204 dbus_g_connection_register_g_object (bus, priv->object_path, obj);
205
206 return obj;
207 }
208
sip_media_session_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)209 static void sip_media_session_get_property (GObject *object,
210 guint property_id,
211 GValue *value,
212 GParamSpec *pspec)
213 {
214 SIPMediaSession *session = SIP_MEDIA_SESSION (object);
215 SIPMediaSessionPrivate *priv = SIP_MEDIA_SESSION_GET_PRIVATE (session);
216
217 switch (property_id) {
218 case PROP_MEDIA_CHANNEL:
219 g_value_set_object (value, priv->channel);
220 break;
221 case PROP_OBJECT_PATH:
222 g_value_set_string (value, priv->object_path);
223 break;
224 case PROP_NUA_OP:
225 g_value_set_pointer (value, priv->nua_op);
226 break;
227 case PROP_PEER:
228 g_value_set_uint (value, priv->peer);
229 break;
230 case PROP_LOCAL_IP_ADDRESS:
231 g_value_set_string (value, priv->local_ip_address);
232 break;
233 case PROP_STATE:
234 g_value_set_uint (value, priv->state);
235 break;
236 default:
237 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
238 break;
239 }
240 }
241
sip_media_session_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)242 static void sip_media_session_set_property (GObject *object,
243 guint property_id,
244 const GValue *value,
245 GParamSpec *pspec)
246 {
247 SIPMediaSession *session = SIP_MEDIA_SESSION (object);
248 SIPMediaSessionPrivate *priv = SIP_MEDIA_SESSION_GET_PRIVATE (session);
249
250 switch (property_id) {
251 case PROP_MEDIA_CHANNEL:
252 priv->channel = SIP_MEDIA_CHANNEL (g_value_get_object (value));
253 break;
254 case PROP_OBJECT_PATH:
255 g_assert (priv->object_path == NULL);
256 priv->object_path = g_value_dup_string (value);
257 break;
258 case PROP_NUA_OP:
259 /* you can only set the NUA handle once - migrating a media session
260 * between two NUA handles makes no sense */
261 g_return_if_fail (priv->nua_op == NULL);
262 priv->nua_op = g_value_get_pointer (value);
263 nua_handle_ref (priv->nua_op);
264 break;
265 case PROP_PEER:
266 priv->peer = g_value_get_uint (value);
267 break;
268 case PROP_LOCAL_IP_ADDRESS:
269 g_assert (priv->local_ip_address == NULL);
270 priv->local_ip_address = g_value_dup_string (value);
271 break;
272 case PROP_STATE:
273 priv_session_state_changed (session, g_value_get_uint (value));
274 break;
275 default:
276 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
277 break;
278 }
279 }
280
281 static void sip_media_session_dispose (GObject *object);
282 static void sip_media_session_finalize (GObject *object);
283
284 static void
sip_media_session_class_init(SIPMediaSessionClass * sip_media_session_class)285 sip_media_session_class_init (SIPMediaSessionClass *sip_media_session_class)
286 {
287 GObjectClass *object_class = G_OBJECT_CLASS (sip_media_session_class);
288 GParamSpec *param_spec;
289
290 g_type_class_add_private (sip_media_session_class, sizeof (SIPMediaSessionPrivate));
291
292 object_class->constructor = sip_media_session_constructor;
293
294 object_class->get_property = sip_media_session_get_property;
295 object_class->set_property = sip_media_session_set_property;
296
297 object_class->dispose = sip_media_session_dispose;
298 object_class->finalize = sip_media_session_finalize;
299
300 param_spec = g_param_spec_object ("media-channel", "SIPMediaChannel object",
301 "SIP media channel object that owns this "
302 "media session object (not reference counted).",
303 SIP_TYPE_MEDIA_CHANNEL,
304 G_PARAM_CONSTRUCT_ONLY |
305 G_PARAM_READWRITE |
306 G_PARAM_STATIC_NICK |
307 G_PARAM_STATIC_BLURB);
308 g_object_class_install_property (object_class, PROP_MEDIA_CHANNEL, param_spec);
309
310 param_spec = g_param_spec_string ("object-path", "D-Bus object path",
311 "The D-Bus object path used for this "
312 "object on the bus.",
313 NULL,
314 G_PARAM_CONSTRUCT_ONLY |
315 G_PARAM_READWRITE |
316 G_PARAM_STATIC_NAME |
317 G_PARAM_STATIC_BLURB);
318 g_object_class_install_property (object_class, PROP_OBJECT_PATH, param_spec);
319
320 param_spec = g_param_spec_pointer("nua-handle", "Sofia-SIP NUA operator handle",
321 "NUA stack operation handle associated "
322 "with this media session.",
323 G_PARAM_CONSTRUCT_ONLY |
324 G_PARAM_READWRITE |
325 G_PARAM_STATIC_NAME |
326 G_PARAM_STATIC_BLURB);
327 g_object_class_install_property (object_class, PROP_NUA_OP, param_spec);
328
329 param_spec = g_param_spec_uint ("peer", "Session peer",
330 "The TpHandle representing the contact "
331 "with whom this session communicates.",
332 0, G_MAXUINT32, 0,
333 G_PARAM_CONSTRUCT_ONLY |
334 G_PARAM_READWRITE |
335 G_PARAM_STATIC_NAME |
336 G_PARAM_STATIC_BLURB);
337 g_object_class_install_property (object_class, PROP_PEER, param_spec);
338
339 param_spec = g_param_spec_string ("local-ip-address", "Local IP address",
340 "The local IP address preferred for "
341 "media streams",
342 NULL,
343 G_PARAM_CONSTRUCT_ONLY |
344 G_PARAM_READWRITE |
345 G_PARAM_STATIC_NAME |
346 G_PARAM_STATIC_BLURB);
347 g_object_class_install_property (object_class, PROP_LOCAL_IP_ADDRESS, param_spec);
348
349 param_spec = g_param_spec_uint ("state", "Session state",
350 "The current state that the session is in.",
351 0, G_MAXUINT32, 0,
352 G_PARAM_READWRITE |
353 G_PARAM_STATIC_NAME |
354 G_PARAM_STATIC_BLURB);
355 g_object_class_install_property (object_class, PROP_STATE, param_spec);
356
357 signals[SIG_STREAM_ADDED] =
358 g_signal_new ("stream-added",
359 G_OBJECT_CLASS_TYPE (sip_media_session_class),
360 G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
361 0,
362 NULL, NULL,
363 g_cclosure_marshal_VOID__OBJECT,
364 G_TYPE_NONE, 1, G_TYPE_OBJECT);
365 }
366
367 static void
sip_media_session_dispose(GObject * object)368 sip_media_session_dispose (GObject *object)
369 {
370 SIPMediaSession *self = SIP_MEDIA_SESSION (object);
371 SIPMediaSessionPrivate *priv = SIP_MEDIA_SESSION_GET_PRIVATE (self);
372
373 if (priv->dispose_has_run)
374 return;
375
376 DEBUG("enter");
377
378 priv->dispose_has_run = TRUE;
379
380 if (priv->catcher_id)
381 g_source_remove (priv->catcher_id);
382
383 if (priv->timer_id)
384 g_source_remove (priv->timer_id);
385
386 if (G_OBJECT_CLASS (sip_media_session_parent_class)->dispose)
387 G_OBJECT_CLASS (sip_media_session_parent_class)->dispose (object);
388
389 DEBUG("exit");
390 }
391
392 static void
sip_media_session_finalize(GObject * object)393 sip_media_session_finalize (GObject *object)
394 {
395 SIPMediaSession *self = SIP_MEDIA_SESSION (object);
396 SIPMediaSessionPrivate *priv = SIP_MEDIA_SESSION_GET_PRIVATE (self);
397 guint i;
398
399 /* terminating the session should have discarded the NUA handle */
400 g_assert (priv->nua_op == NULL);
401
402 /* free any data held directly by the object here */
403
404 for (i = 0; i < priv->streams->len; i++) {
405 SIPMediaStream *stream = g_ptr_array_index (priv->streams, i);
406 if (stream != NULL)
407 {
408 g_warning ("stream %u (%p) left over, reaping", i, stream);
409 g_object_unref (stream);
410 }
411 }
412 g_ptr_array_free(priv->streams, TRUE);
413
414 priv_zap_event (self);
415
416 if (priv->home != NULL)
417 su_home_unref (priv->home);
418 if (priv->backup_home != NULL)
419 su_home_unref (priv->backup_home);
420
421 g_free (priv->local_ip_address);
422 g_free (priv->object_path);
423
424 G_OBJECT_CLASS (sip_media_session_parent_class)->finalize (object);
425
426 DEBUG("exit");
427 }
428
429
430
431 /**
432 * sip_media_session_error
433 *
434 * Implements DBus method Error
435 * on interface org.freedesktop.Telepathy.Media.SessionHandler
436 */
437 static void
sip_media_session_error(TpSvcMediaSessionHandler * iface,guint errno,const gchar * message,DBusGMethodInvocation * context)438 sip_media_session_error (TpSvcMediaSessionHandler *iface,
439 guint errno,
440 const gchar *message,
441 DBusGMethodInvocation *context)
442 {
443 SIPMediaSession *obj = SIP_MEDIA_SESSION (iface);
444
445 SESSION_DEBUG(obj, "Media.SessionHandler::Error called (%s) terminating session", message);
446
447 sip_media_session_terminate (obj);
448
449 tp_svc_media_session_handler_return_from_error (context);
450 }
451
priv_emit_new_stream(SIPMediaSession * self,SIPMediaStream * stream)452 static void priv_emit_new_stream (SIPMediaSession *self,
453 SIPMediaStream *stream)
454 {
455 gchar *object_path;
456 guint id;
457 guint media_type;
458 guint direction;
459
460 g_object_get (stream,
461 "object-path", &object_path,
462 "id", &id,
463 "media-type", &media_type,
464 "direction", &direction,
465 NULL);
466
467 /* note: all of the streams are bidirectional from farsight's point of view, it's
468 * just in the signalling they change */
469
470 tp_svc_media_session_handler_emit_new_stream_handler (
471 (TpSvcMediaSessionHandler *)self, object_path, id, media_type,
472 direction);
473
474 g_free (object_path);
475 }
476
477
478 /**
479 * sip_media_session_ready
480 *
481 * Implements DBus method Ready
482 * on interface org.freedesktop.Telepathy.Media.SessionHandler
483 */
484 static void
sip_media_session_ready(TpSvcMediaSessionHandler * iface,DBusGMethodInvocation * context)485 sip_media_session_ready (TpSvcMediaSessionHandler *iface,
486 DBusGMethodInvocation *context)
487 {
488 SIPMediaSession *obj = SIP_MEDIA_SESSION (iface);
489 SIPMediaSessionPrivate *priv;
490 guint i;
491
492 DEBUG ("enter");
493
494 g_assert (SIP_IS_MEDIA_SESSION (obj));
495
496 priv = SIP_MEDIA_SESSION_GET_PRIVATE (obj);
497
498 priv->se_ready = TRUE;
499
500 /* note: streams are generated in priv_create_media_stream() */
501
502 for (i = 0; i < priv->streams->len; i++) {
503 SIPMediaStream *stream = g_ptr_array_index (priv->streams, i);
504 if (stream)
505 priv_emit_new_stream (obj, stream);
506 }
507
508 tp_svc_media_session_handler_return_from_ready (context);
509 }
510
511 /***********************************************************************
512 * Helper functions follow (not based on generated templates)
513 ***********************************************************************/
514
515 TpHandle
sip_media_session_get_peer(SIPMediaSession * session)516 sip_media_session_get_peer (SIPMediaSession *session)
517 {
518 SIPMediaSessionPrivate *priv = SIP_MEDIA_SESSION_GET_PRIVATE (session);
519 return priv->peer;
520 }
521
522 static void
priv_close_all_streams(SIPMediaSession * session)523 priv_close_all_streams (SIPMediaSession *session)
524 {
525 SIPMediaSessionPrivate *priv = SIP_MEDIA_SESSION_GET_PRIVATE (session);
526 guint i;
527 for (i = 0; i < priv->streams->len; i++)
528 {
529 SIPMediaStream *stream;
530 stream = g_ptr_array_index (priv->streams, i);
531 if (stream != NULL)
532 sip_media_stream_close (stream);
533 g_assert (g_ptr_array_index (priv->streams, i) == NULL);
534 }
535 }
536
537 static void
priv_clear_streams_pending_send(SIPMediaSession * session)538 priv_clear_streams_pending_send (SIPMediaSession *session)
539 {
540 SIPMediaSessionPrivate *priv = SIP_MEDIA_SESSION_GET_PRIVATE (session);
541 SIPMediaStream *stream;
542 guint i;
543
544 /* Clear the local pending send flags, enabling sending */
545 for (i = 0; i < priv->streams->len; i++)
546 {
547 stream = g_ptr_array_index(priv->streams, i);
548 if (stream != NULL)
549 {
550 guint direction = TP_MEDIA_STREAM_DIRECTION_BIDIRECTIONAL;
551 g_object_get (stream, "direction", &direction, NULL);
552 if (direction & TP_MEDIA_STREAM_DIRECTION_SEND)
553 sip_media_stream_set_direction (stream, direction, 0);
554 }
555 }
556 }
557
558 static void
priv_session_state_changed(SIPMediaSession * session,SIPMediaSessionState new_state)559 priv_session_state_changed (SIPMediaSession *session,
560 SIPMediaSessionState new_state)
561 {
562 SIPMediaSessionPrivate *priv = SIP_MEDIA_SESSION_GET_PRIVATE (session);
563
564 if (priv->state == new_state)
565 return;
566
567 SESSION_DEBUG(session, "state changed from %s to %s",
568 session_states[priv->state],
569 session_states[new_state]);
570
571 priv->state = new_state;
572
573 switch (new_state)
574 {
575 case SIP_MEDIA_SESSION_STATE_CREATED:
576 break;
577 case SIP_MEDIA_SESSION_STATE_ENDED:
578 priv_close_all_streams (session);
579 DEBUG("freeing the NUA handle %p", priv->nua_op);
580 if (priv->nua_op != NULL)
581 {
582 nua_handle_bind (priv->nua_op, SIP_NH_EXPIRED);
583 nua_handle_unref (priv->nua_op);
584 priv->nua_op = NULL;
585 }
586 break;
587 case SIP_MEDIA_SESSION_STATE_INVITE_RECEIVED:
588 case SIP_MEDIA_SESSION_STATE_REINVITE_RECEIVED:
589 priv->catcher_id = g_idle_add (priv_catch_remote_nonupdate, session);
590 /* Fall through to the next case */
591 case SIP_MEDIA_SESSION_STATE_INVITE_SENT:
592 case SIP_MEDIA_SESSION_STATE_REINVITE_SENT:
593 if (priv->timer_id)
594 {
595 g_source_remove (priv->timer_id);
596 }
597 priv->timer_id =
598 g_timeout_add (DEFAULT_SESSION_TIMEOUT, priv_timeout_session, session);
599 break;
600 case SIP_MEDIA_SESSION_STATE_RESPONSE_RECEIVED:
601 break;
602 case SIP_MEDIA_SESSION_STATE_ACTIVE:
603 if (priv->timer_id)
604 {
605 g_source_remove (priv->timer_id);
606 priv->timer_id = 0;
607 }
608 priv_clear_streams_pending_send (session);
609 if (priv->pending_offer)
610 {
611 priv_session_invite (session, TRUE);
612 }
613 break;
614
615 /* Don't add default because we want to be warned by the compiler
616 * about unhandled states */
617 }
618 }
619
620 #ifdef ENABLE_DEBUG
621 void
sip_media_session_debug(SIPMediaSession * session,const gchar * format,...)622 sip_media_session_debug (SIPMediaSession *session,
623 const gchar *format, ...)
624 {
625 va_list list;
626 gchar buf[512];
627 SIPMediaSessionPrivate *priv;
628
629 g_assert (SIP_IS_MEDIA_SESSION (session));
630
631 priv = SIP_MEDIA_SESSION_GET_PRIVATE (session);
632
633 va_start (list, format);
634
635 g_vsnprintf (buf, sizeof (buf), format, list);
636
637 va_end (list);
638
639 sip_debug (DEBUG_FLAG, "SIP media session [%-17s]: %s",
640 session_states[priv->state],
641 buf);
642 }
643 #endif /* ENABLE_DEBUG */
644
645 static gboolean
priv_catch_remote_nonupdate(gpointer data)646 priv_catch_remote_nonupdate (gpointer data)
647 {
648 SIPMediaSession *session = data;
649
650 DEBUG("called");
651
652 /* Accordingly to the last experimental data, non-modifying INVITEs
653 * cause the stack to emit nua_i_state nonetheless */
654 g_assert_not_reached();
655
656 /* TODO: figure out what happens in the 3pcc scenario when we get
657 * an INVITE but no session offer */
658
659 /* Should do the right thing if there were no remote media updates */
660 priv_request_response_step (session);
661
662 return FALSE;
663 }
664
priv_timeout_session(gpointer data)665 static gboolean priv_timeout_session (gpointer data)
666 {
667 SIPMediaSession *session = data;
668 SIPMediaSessionPrivate *priv;
669 TpChannelGroupChangeReason reason;
670 gboolean change = FALSE;
671 TpHandle actor;
672
673 DEBUG("session timed out");
674
675 priv = SIP_MEDIA_SESSION_GET_PRIVATE (session);
676
677 if (priv->state == SIP_MEDIA_SESSION_STATE_INVITE_SENT)
678 {
679 reason = TP_CHANNEL_GROUP_CHANGE_REASON_NO_ANSWER;
680 actor = 0;
681 change = TRUE;
682 }
683 else if (priv->state == SIP_MEDIA_SESSION_STATE_INVITE_RECEIVED)
684 {
685 reason = TP_CHANNEL_GROUP_CHANGE_REASON_NONE;
686 actor = priv->peer;
687 change = TRUE;
688 }
689
690 if (change)
691 {
692 TpIntSet *set = tp_intset_new ();
693 tp_intset_add (set, priv->peer);
694 tp_group_mixin_change_members (G_OBJECT (priv->channel), "Timed out",
695 NULL, set, NULL, NULL, actor, reason);
696 tp_intset_destroy (set);
697 }
698
699 sip_media_session_terminate (session);
700
701 return FALSE;
702 }
703
sip_media_session_terminate(SIPMediaSession * session)704 void sip_media_session_terminate (SIPMediaSession *session)
705 {
706 SIPMediaSessionPrivate *priv = SIP_MEDIA_SESSION_GET_PRIVATE (session);
707
708 DEBUG ("enter");
709
710 if (priv->state == SIP_MEDIA_SESSION_STATE_ENDED)
711 return;
712
713 /* XXX: taken care of by the state change? */
714 priv_close_all_streams (session);
715
716 if (priv->nua_op != NULL)
717 {
718 g_assert (nua_handle_magic (priv->nua_op) == priv->channel);
719
720 switch (priv->state)
721 {
722 case SIP_MEDIA_SESSION_STATE_ACTIVE:
723 case SIP_MEDIA_SESSION_STATE_RESPONSE_RECEIVED:
724 case SIP_MEDIA_SESSION_STATE_REINVITE_SENT:
725 DEBUG("sending BYE");
726 nua_bye (priv->nua_op, TAG_END());
727 break;
728 case SIP_MEDIA_SESSION_STATE_INVITE_SENT:
729 DEBUG("sending CANCEL");
730 nua_cancel (priv->nua_op, TAG_END());
731 break;
732 case SIP_MEDIA_SESSION_STATE_INVITE_RECEIVED:
733 DEBUG("sending the 480 response to an incoming INVITE");
734 nua_respond (priv->nua_op, 480, "Terminated", TAG_END());
735 break;
736 case SIP_MEDIA_SESSION_STATE_REINVITE_RECEIVED:
737 DEBUG("sending the 480 response to an incoming re-INVITE");
738 {
739 msg_t *msg;
740
741 msg = (priv->saved_event[0])
742 ? nua_saved_event_request (priv->saved_event) : NULL;
743
744 nua_respond (priv->nua_op, 480, "Terminated",
745 TAG_IF(msg, NUTAG_WITH(msg)),
746 TAG_END());
747 }
748 DEBUG("sending BYE to terminate the call itself");
749 nua_bye (priv->nua_op, TAG_END());
750 break;
751 default:
752 /* let the Sofia stack decide what do to */;
753 }
754 }
755
756 g_object_set (session, "state", SIP_MEDIA_SESSION_STATE_ENDED, NULL);
757 }
758
759 gboolean
sip_media_session_set_remote_media(SIPMediaSession * session,const sdp_session_t * sdp)760 sip_media_session_set_remote_media (SIPMediaSession *session,
761 const sdp_session_t* sdp)
762 {
763 SIPMediaSessionPrivate *priv = SIP_MEDIA_SESSION_GET_PRIVATE (session);
764
765 DEBUG ("enter");
766
767 /* Remove the non-update catcher because we've got an update */
768 if (priv->catcher_id)
769 {
770 g_source_remove (priv->catcher_id);
771 priv->catcher_id = 0;
772 }
773
774 /* Switch the state machine to processing the response */
775 if (priv->state == SIP_MEDIA_SESSION_STATE_INVITE_SENT
776 || priv->state == SIP_MEDIA_SESSION_STATE_REINVITE_SENT)
777 g_object_set (session,
778 "state", SIP_MEDIA_SESSION_STATE_RESPONSE_RECEIVED,
779 NULL);
780
781 /* Handle session non-updates */
782 if (!sdp_session_cmp (priv->remote_sdp, sdp))
783 {
784 /* Should do the proper response etc. */
785 priv_request_response_step (session);
786 return TRUE;
787 }
788
789 /* Delete a backup session structure, if any */
790 if (priv->backup_remote_sdp != NULL)
791 {
792 priv->backup_remote_sdp = NULL;
793 g_assert (priv->backup_home != NULL);
794 su_home_unref (priv->backup_home);
795 priv->backup_home = NULL;
796 }
797 /* Back up the old session.
798 * The streams still need the old media descriptions */
799 if (priv->remote_sdp != NULL)
800 {
801 g_assert (priv->home != NULL);
802 g_assert (priv->backup_home == NULL);
803 priv->backup_home = priv->home;
804 priv->backup_remote_sdp = priv->remote_sdp;
805 }
806
807 /* Store the session description structure */
808 priv->home = su_home_create ();
809 priv->remote_sdp = sdp_session_dup (priv->home, sdp);
810 g_return_val_if_fail (priv->remote_sdp != NULL, FALSE);
811
812 return priv_update_remote_media (
813 session,
814 (priv->state == SIP_MEDIA_SESSION_STATE_INVITE_RECEIVED
815 || priv->state == SIP_MEDIA_SESSION_STATE_REINVITE_RECEIVED));
816 }
817
DEFINE_TP_STRUCT_TYPE(sip_tp_stream_struct_type,G_TYPE_UINT,G_TYPE_UINT,G_TYPE_UINT,G_TYPE_UINT,G_TYPE_UINT,G_TYPE_UINT)818 DEFINE_TP_STRUCT_TYPE(sip_tp_stream_struct_type,
819 G_TYPE_UINT,
820 G_TYPE_UINT,
821 G_TYPE_UINT,
822 G_TYPE_UINT,
823 G_TYPE_UINT,
824 G_TYPE_UINT)
825
826 DEFINE_TP_LIST_TYPE(sip_tp_stream_list_type,
827 sip_tp_stream_struct_type ())
828
829
830 void
831 priv_add_stream_list_entry (GPtrArray *list,
832 SIPMediaStream *stream,
833 SIPMediaSession *session)
834 {
835 SIPMediaSessionPrivate *priv = SIP_MEDIA_SESSION_GET_PRIVATE (session);
836 GValue entry = { 0 };
837 GType stream_type;
838 guint id;
839 TpMediaStreamType type = TP_MEDIA_STREAM_TYPE_AUDIO;
840 TpMediaStreamState connection_state = TP_MEDIA_STREAM_STATE_CONNECTED;
841 TpMediaStreamDirection direction = TP_MEDIA_STREAM_DIRECTION_BIDIRECTIONAL;
842 guint pending_send_flags = 0;
843
844 g_assert(stream != NULL);
845
846 g_object_get (stream,
847 "id", &id,
848 "media-type", &type,
849 "state", &connection_state,
850 "direction", &direction,
851 "pending-send-flags", &pending_send_flags,
852 NULL);
853
854 stream_type = sip_tp_stream_struct_type ();
855
856 g_value_init (&entry, stream_type);
857 g_value_take_boxed (&entry,
858 dbus_g_type_specialized_construct (stream_type));
859
860 dbus_g_type_struct_set (&entry,
861 0, id,
862 1, priv->peer,
863 2, type,
864 3, connection_state,
865 4, direction,
866 5, pending_send_flags,
867 G_MAXUINT);
868
869 g_ptr_array_add (list, g_value_get_boxed (&entry));
870 }
871
sip_media_session_request_streams(SIPMediaSession * session,const GArray * media_types,GPtrArray ** ret,GError ** error)872 gboolean sip_media_session_request_streams (SIPMediaSession *session,
873 const GArray *media_types,
874 GPtrArray **ret,
875 GError **error)
876 {
877 guint i;
878
879 DEBUG ("enter");
880
881 *ret = g_ptr_array_sized_new (media_types->len);
882
883 for (i = 0; i < media_types->len; i++) {
884 guint media_type = g_array_index (media_types, guint, i);
885 SIPMediaStream *stream;
886
887 stream = priv_create_media_stream (session,
888 media_type,
889 TP_MEDIA_STREAM_PENDING_REMOTE_SEND);
890
891 priv_add_stream_list_entry (*ret, stream, session);
892 }
893
894 priv_local_media_changed (session);
895
896 return TRUE;
897 }
898
899 gboolean
sip_media_session_remove_streams(SIPMediaSession * self,const GArray * stream_ids,GError ** error)900 sip_media_session_remove_streams (SIPMediaSession *self,
901 const GArray *stream_ids,
902 GError **error)
903 {
904 SIPMediaStream *stream;
905 guint stream_id;
906 guint i;
907
908 DEBUG ("enter");
909
910 for (i = 0; i < stream_ids->len; i++)
911 {
912 stream_id = g_array_index (stream_ids, guint, i);
913 stream = sip_media_session_get_stream (self, stream_id, error);
914 if (stream == NULL)
915 return FALSE;
916 sip_media_stream_close (stream);
917 }
918
919 priv_local_media_changed (self);
920
921 return TRUE;
922 }
923
924 /**
925 * Returns a list of pointers to SIPMediaStream objects
926 * associated with this session.
927 */
sip_media_session_list_streams(SIPMediaSession * session,GPtrArray ** ret)928 gboolean sip_media_session_list_streams (SIPMediaSession *session,
929 GPtrArray **ret)
930 {
931 SIPMediaSessionPrivate *priv = SIP_MEDIA_SESSION_GET_PRIVATE (session);
932 SIPMediaStream *stream;
933 guint i;
934
935 if (priv->streams == NULL || priv->streams->len == 0)
936 return FALSE;
937
938 *ret = g_ptr_array_sized_new (priv->streams->len);
939
940 for (i = 0; i < priv->streams->len; i++)
941 {
942 stream = g_ptr_array_index(priv->streams, i);
943 if (stream)
944 priv_add_stream_list_entry (*ret, stream, session);
945 }
946
947 return TRUE;
948 }
949
950 gboolean
sip_media_session_request_stream_direction(SIPMediaSession * self,guint stream_id,guint direction,GError ** error)951 sip_media_session_request_stream_direction (SIPMediaSession *self,
952 guint stream_id,
953 guint direction,
954 GError **error)
955 {
956 SIPMediaStream *stream;
957 guint old_direction = TP_MEDIA_STREAM_DIRECTION_BIDIRECTIONAL;
958 guint pending_send_flags = 0;
959
960 stream = sip_media_session_get_stream (self, stream_id, error);
961 if (stream == NULL)
962 return FALSE;
963
964 g_object_get (stream,
965 "direction", &old_direction,
966 "pending-send-flags", &pending_send_flags,
967 NULL);
968
969 SESSION_DEBUG(self, "stream %u direction change requested: %u -> %u", stream_id, old_direction, direction);
970
971 /* Set pending send flag if we're going to start sending */
972 if (direction & ~old_direction & TP_MEDIA_STREAM_DIRECTION_SEND)
973 pending_send_flags |= TP_MEDIA_STREAM_PENDING_REMOTE_SEND;
974
975 sip_media_stream_set_direction (stream, direction, pending_send_flags);
976
977 if (direction != old_direction)
978 priv_local_media_changed (self);
979
980 return TRUE;
981 }
982
983 static void
priv_save_event(SIPMediaSession * self)984 priv_save_event (SIPMediaSession *self)
985 {
986 SIPMediaSessionPrivate *priv = SIP_MEDIA_SESSION_GET_PRIVATE (self);
987 SIPConnection *conn = NULL;
988
989 priv_zap_event (self);
990
991 g_object_get (priv->channel, "connection", &conn, NULL);
992
993 g_return_if_fail (conn != NULL);
994
995 sip_conn_save_event (conn, priv->saved_event);
996
997 g_object_unref (conn);
998
999 #ifdef ENABLE_DEBUG
1000 {
1001 nua_event_data_t const *ev_data = nua_event_data (priv->saved_event);
1002 g_assert (ev_data != NULL);
1003 DEBUG("saved the last event: %s %hd %s", nua_event_name (ev_data->e_event), ev_data->e_status, ev_data->e_phrase);
1004 }
1005 #endif
1006 }
1007
1008 static void
priv_zap_event(SIPMediaSession * self)1009 priv_zap_event (SIPMediaSession *self)
1010 {
1011 SIPMediaSessionPrivate *priv = SIP_MEDIA_SESSION_GET_PRIVATE (self);
1012
1013 if (priv->saved_event[0])
1014 {
1015 nua_event_data_t const *ev_data = nua_event_data (priv->saved_event);
1016 g_assert (ev_data != NULL);
1017 g_warning ("zapping unhandled saved event '%s'", nua_event_name (ev_data->e_event));
1018 nua_destroy_event (priv->saved_event);
1019 }
1020 }
1021
1022 void
sip_media_session_receive_invite(SIPMediaSession * self)1023 sip_media_session_receive_invite (SIPMediaSession *self)
1024 {
1025 SIPMediaSessionPrivate *priv = SIP_MEDIA_SESSION_GET_PRIVATE (self);
1026
1027 g_return_if_fail (priv->state == SIP_MEDIA_SESSION_STATE_CREATED);
1028 g_return_if_fail (priv->nua_op != NULL);
1029
1030 nua_respond (priv->nua_op, SIP_180_RINGING, TAG_END());
1031
1032 g_object_set (self, "state", SIP_MEDIA_SESSION_STATE_INVITE_RECEIVED, NULL);
1033 }
1034
1035 void
sip_media_session_receive_reinvite(SIPMediaSession * self)1036 sip_media_session_receive_reinvite (SIPMediaSession *self)
1037 {
1038 SIPMediaSessionPrivate *priv = SIP_MEDIA_SESSION_GET_PRIVATE (self);
1039 g_return_if_fail (priv->state == SIP_MEDIA_SESSION_STATE_ACTIVE
1040 || priv->state == SIP_MEDIA_SESSION_STATE_RESPONSE_RECEIVED);
1041
1042 priv_save_event (self);
1043
1044 g_object_set (self, "state", SIP_MEDIA_SESSION_STATE_REINVITE_RECEIVED, NULL);
1045 }
1046
1047 void
sip_media_session_accept(SIPMediaSession * self)1048 sip_media_session_accept (SIPMediaSession *self)
1049 {
1050 SIPMediaSessionPrivate *priv = SIP_MEDIA_SESSION_GET_PRIVATE (self);
1051
1052 if (priv->accepted)
1053 return;
1054
1055 SESSION_DEBUG(self, "accepting the session");
1056
1057 priv->accepted = TRUE;
1058
1059 /* Will change session state to active when streams are ready
1060 * and clear the pending send flags, enabling sending */
1061 priv_request_response_step (self);
1062 }
1063
1064 void
sip_media_session_reject(SIPMediaSession * self,gint status,const char * message)1065 sip_media_session_reject (SIPMediaSession *self,
1066 gint status,
1067 const char *message)
1068 {
1069 SIPMediaSessionPrivate *priv = SIP_MEDIA_SESSION_GET_PRIVATE (self);
1070
1071 if (message != NULL && !message[0])
1072 message = NULL;
1073
1074 SESSION_DEBUG(self, "responding: %03d %s", status, message == NULL? "" : message);
1075
1076 if (priv->nua_op)
1077 nua_respond (priv->nua_op, status, message, TAG_END());
1078 }
1079
1080 static SIPMediaStream *
sip_media_session_get_stream(SIPMediaSession * self,guint stream_id,GError ** error)1081 sip_media_session_get_stream (SIPMediaSession *self,
1082 guint stream_id,
1083 GError **error)
1084 {
1085 SIPMediaSessionPrivate *priv = SIP_MEDIA_SESSION_GET_PRIVATE (self);
1086 SIPMediaStream *stream;
1087
1088 g_assert (priv->streams != NULL);
1089
1090 if (stream_id >= priv->streams->len)
1091 {
1092 g_set_error (error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT,
1093 "stream ID %u is invalid", stream_id);
1094 return NULL;
1095 }
1096
1097 stream = g_ptr_array_index (priv->streams, stream_id);
1098
1099 if (stream == NULL)
1100 {
1101 g_set_error (error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT,
1102 "stream %u does not exist", stream_id);
1103 return NULL;
1104 }
1105
1106 return stream;
1107 }
1108
1109 gboolean
sip_media_session_start_telephony_event(SIPMediaSession * self,guint stream_id,guchar event,GError ** error)1110 sip_media_session_start_telephony_event (SIPMediaSession *self,
1111 guint stream_id,
1112 guchar event,
1113 GError **error)
1114 {
1115 SIPMediaStream *stream;
1116
1117 stream = sip_media_session_get_stream (self, stream_id, error);
1118 if (stream == NULL)
1119 return FALSE;
1120
1121 if (sip_media_stream_get_media_type (stream) != TP_MEDIA_STREAM_TYPE_AUDIO)
1122 {
1123 g_set_error (error, TP_ERRORS, TP_ERROR_NOT_AVAILABLE,
1124 "non-audio stream %u does not support telephony events", stream_id);
1125 return FALSE;
1126 }
1127
1128 DEBUG("starting telephony event %u on stream %u", (guint) event, stream_id);
1129
1130 sip_media_stream_start_telephony_event (stream, event);
1131
1132 return TRUE;
1133 }
1134
1135 gboolean
sip_media_session_stop_telephony_event(SIPMediaSession * self,guint stream_id,GError ** error)1136 sip_media_session_stop_telephony_event (SIPMediaSession *self,
1137 guint stream_id,
1138 GError **error)
1139 {
1140 SIPMediaStream *stream;
1141
1142 stream = sip_media_session_get_stream (self, stream_id, error);
1143 if (stream == NULL)
1144 return FALSE;
1145
1146 if (sip_media_stream_get_media_type (stream) != TP_MEDIA_STREAM_TYPE_AUDIO)
1147 {
1148 g_set_error (error, TP_ERRORS, TP_ERROR_NOT_AVAILABLE,
1149 "non-audio stream %u does not support telephony events; spurious use of the stop event?", stream_id);
1150 return FALSE;
1151 }
1152
1153 DEBUG("stopping the telephony event on stream %u", stream_id);
1154
1155 sip_media_stream_stop_telephony_event (stream);
1156
1157 return TRUE;
1158 }
1159
1160 gint
sip_media_session_rate_native_transport(SIPMediaSession * session,const GValue * transport)1161 sip_media_session_rate_native_transport (SIPMediaSession *session,
1162 const GValue *transport)
1163 {
1164 SIPMediaSessionPrivate *priv = SIP_MEDIA_SESSION_GET_PRIVATE (session);
1165 gint result = 0;
1166 gchar *address = NULL;
1167 guint proto = TP_MEDIA_STREAM_BASE_PROTO_UDP;
1168
1169 dbus_g_type_struct_get (transport,
1170 1, &address,
1171 3, &proto,
1172 G_MAXUINT);
1173
1174 g_assert (address != NULL);
1175
1176 if (proto != TP_MEDIA_STREAM_BASE_PROTO_UDP)
1177 result = -1;
1178 /* XXX: this will not work properly when IPv6 support comes */
1179 else if (priv->local_ip_address != NULL
1180 && strcmp (address, priv->local_ip_address) == 0)
1181 result = 1;
1182
1183 g_free (address);
1184
1185 return result;
1186 }
1187
priv_session_media_state(SIPMediaSession * session,gboolean playing)1188 static void priv_session_media_state (SIPMediaSession *session, gboolean playing)
1189 {
1190 SIPMediaSessionPrivate *priv = SIP_MEDIA_SESSION_GET_PRIVATE (session);
1191 SIPMediaStream *stream;
1192 guint i;
1193
1194 for (i = 0; i < priv->streams->len; i++)
1195 {
1196 stream = g_ptr_array_index(priv->streams, i);
1197 if (stream != NULL)
1198 sip_media_stream_set_playing (stream, playing);
1199 }
1200 }
1201
1202 static void
priv_local_media_changed(SIPMediaSession * session)1203 priv_local_media_changed (SIPMediaSession *session)
1204 {
1205 SIPMediaSessionPrivate *priv = SIP_MEDIA_SESSION_GET_PRIVATE (session);
1206
1207 switch (priv->state)
1208 {
1209 case SIP_MEDIA_SESSION_STATE_CREATED:
1210 case SIP_MEDIA_SESSION_STATE_INVITE_RECEIVED:
1211 case SIP_MEDIA_SESSION_STATE_REINVITE_RECEIVED:
1212 /* The changes will be sent when all streams are ready;
1213 * check if now's the time */
1214 priv_request_response_step (session);
1215 break;
1216 case SIP_MEDIA_SESSION_STATE_INVITE_SENT:
1217 case SIP_MEDIA_SESSION_STATE_REINVITE_SENT:
1218 case SIP_MEDIA_SESSION_STATE_RESPONSE_RECEIVED:
1219 /* Cannot send another offer right now */
1220 priv->pending_offer = TRUE;
1221 break;
1222 case SIP_MEDIA_SESSION_STATE_ACTIVE:
1223 if (priv->local_non_ready == 0)
1224 priv_session_invite (session, TRUE);
1225 else
1226 priv->pending_offer = TRUE;
1227 break;
1228 default:
1229 g_assert_not_reached();
1230 }
1231 }
1232
1233 static gboolean
priv_update_remote_media(SIPMediaSession * session,gboolean authoritative)1234 priv_update_remote_media (SIPMediaSession *session, gboolean authoritative)
1235 {
1236 SIPMediaSessionPrivate *priv = SIP_MEDIA_SESSION_GET_PRIVATE (session);
1237 const sdp_media_t *media;
1238 gboolean has_supported_media = FALSE;
1239 guint i;
1240
1241 g_return_val_if_fail (priv->remote_sdp != NULL, FALSE);
1242
1243 media = priv->remote_sdp->sdp_media;
1244
1245 /* note: for each session, we maintain an ordered list of
1246 * streams (SDP m-lines) which are matched 1:1 to
1247 * the streams of the remote SDP */
1248
1249 for (i = 0; media; media = media->m_next, i++)
1250 {
1251 SIPMediaStream *stream = NULL;
1252 guint media_type;
1253
1254 media_type = sip_tp_media_type (media->m_type);
1255
1256 if (i >= priv->streams->len)
1257 stream = priv_create_media_stream (
1258 session,
1259 media_type,
1260 (priv->accepted)?
1261 0 : TP_MEDIA_STREAM_PENDING_LOCAL_SEND);
1262 else
1263 stream = g_ptr_array_index(priv->streams, i);
1264
1265 /* note: it is ok for the stream to be NULL (unsupported media type) */
1266 if (stream == NULL)
1267 continue;
1268
1269 DEBUG("setting remote SDP for stream %u", i);
1270
1271 if (media->m_rejected)
1272 {
1273 DEBUG("the stream has been rejected, closing");
1274 }
1275 else if (sip_media_stream_get_media_type (stream) != media_type)
1276 {
1277 /* XXX: close this stream and create a new one in its place? */
1278 g_warning ("The peer has changed the media type, don't know what to do");
1279 }
1280 else
1281 {
1282 if (sip_media_stream_set_remote_media (stream,
1283 media,
1284 authoritative))
1285 {
1286 has_supported_media = TRUE;
1287 continue;
1288 }
1289 }
1290
1291 /* There have been problems with the stream update, kill the stream */
1292 sip_media_stream_close (stream);
1293 }
1294
1295 g_assert(media == NULL);
1296 g_assert(i <= priv->streams->len);
1297 if (i < priv->streams->len)
1298 {
1299 do
1300 {
1301 SIPMediaStream *stream;
1302 stream = g_ptr_array_index(priv->streams, i);
1303 if (stream != NULL)
1304 {
1305 g_message ("closing a mismatched stream %u", i);
1306 sip_media_stream_close (stream);
1307 }
1308 }
1309 while (++i < priv->streams->len);
1310 }
1311
1312 DEBUG("exit");
1313
1314 return has_supported_media;
1315 }
1316
1317 static void
priv_session_rollback(SIPMediaSession * session)1318 priv_session_rollback (SIPMediaSession *session)
1319 {
1320 SIPMediaSessionPrivate *priv = SIP_MEDIA_SESSION_GET_PRIVATE (session);
1321 msg_t *msg;
1322
1323 DEBUG("enter");
1324
1325 if (priv->remote_sdp != NULL)
1326 {
1327 priv->remote_sdp = NULL;
1328 g_assert (priv->home != NULL);
1329 su_home_unref (priv->home);
1330 priv->home = NULL;
1331 }
1332 if (priv->backup_remote_sdp == NULL)
1333 {
1334 sip_media_session_terminate (session);
1335 return;
1336 }
1337
1338 /* restore remote SDP from the backup */
1339 priv->remote_sdp = priv->backup_remote_sdp;
1340 g_assert (priv->backup_home != NULL);
1341 priv->home = priv->backup_home;
1342 priv->backup_remote_sdp = NULL;
1343 priv->backup_home = NULL;
1344
1345 priv_update_remote_media (session, FALSE);
1346
1347 msg = (priv->saved_event[0])
1348 ? nua_saved_event_request (priv->saved_event) : NULL;
1349
1350 nua_respond (priv->nua_op, 488, sip_488_Not_acceptable,
1351 TAG_IF(msg, NUTAG_WITH(msg)),
1352 TAG_END());
1353
1354 if (priv->saved_event[0])
1355 nua_destroy_event (priv->saved_event);
1356
1357 g_object_set (session, "state", SIP_MEDIA_SESSION_STATE_ACTIVE, NULL);
1358 }
1359
1360 static gboolean
priv_session_local_sdp(SIPMediaSession * session,GString * user_sdp)1361 priv_session_local_sdp (SIPMediaSession *session, GString *user_sdp)
1362 {
1363 SIPMediaSessionPrivate *priv = SIP_MEDIA_SESSION_GET_PRIVATE (session);
1364 gboolean has_supported_media = FALSE;
1365 guint i;
1366
1367 g_return_val_if_fail (priv->local_non_ready == 0, FALSE);
1368
1369 g_string_append (user_sdp, "v=0\r\n");
1370
1371 for (i = 0; i < priv->streams->len; i++)
1372 {
1373 SIPMediaStream *stream = g_ptr_array_index (priv->streams, i);
1374 if (stream)
1375 {
1376 user_sdp = g_string_append (user_sdp,
1377 sip_media_stream_local_sdp (stream));
1378 has_supported_media = TRUE;
1379 }
1380 else
1381 {
1382 user_sdp = g_string_append (user_sdp, "m=audio 0 RTP/AVP 0\r\n");
1383 }
1384 }
1385
1386 SESSION_DEBUG(session, "generated SDP: {\n%s}", user_sdp->str);
1387
1388 return has_supported_media;
1389 }
1390
1391 static void
priv_session_invite(SIPMediaSession * session,gboolean reinvite)1392 priv_session_invite (SIPMediaSession *session, gboolean reinvite)
1393 {
1394 SIPMediaSessionPrivate *priv = SIP_MEDIA_SESSION_GET_PRIVATE (session);
1395 GString *user_sdp;
1396
1397 DEBUG("enter");
1398
1399 g_return_if_fail (priv->nua_op != NULL);
1400
1401 user_sdp = g_string_new (NULL);
1402
1403 if (priv_session_local_sdp (session, user_sdp))
1404 {
1405 nua_invite (priv->nua_op,
1406 SOATAG_USER_SDP_STR(user_sdp->str),
1407 SOATAG_RTP_SORT(SOA_RTP_SORT_REMOTE),
1408 SOATAG_RTP_SELECT(SOA_RTP_SELECT_ALL),
1409 NUTAG_AUTOANSWER(0),
1410 TAG_END());
1411 priv->pending_offer = FALSE;
1412 g_object_set (session,
1413 "state", reinvite? SIP_MEDIA_SESSION_STATE_REINVITE_SENT
1414 : SIP_MEDIA_SESSION_STATE_INVITE_SENT,
1415 NULL);
1416 }
1417 else
1418 g_warning ("cannot send a valid SDP offer, are there no streams?");
1419
1420 g_string_free (user_sdp, TRUE);
1421 }
1422
1423 static void
priv_session_respond(SIPMediaSession * session)1424 priv_session_respond (SIPMediaSession *session)
1425 {
1426 SIPMediaSessionPrivate *priv = SIP_MEDIA_SESSION_GET_PRIVATE (session);
1427 GString *user_sdp;
1428
1429 g_return_if_fail (priv->nua_op != NULL);
1430
1431 user_sdp = g_string_new (NULL);
1432
1433 if (priv_session_local_sdp (session, user_sdp))
1434 {
1435 msg_t *msg;
1436
1437 msg = (priv->saved_event[0])
1438 ? nua_saved_event_request (priv->saved_event) : NULL;
1439
1440 nua_respond (priv->nua_op, 200, sip_200_OK,
1441 TAG_IF(msg, NUTAG_WITH(msg)),
1442 SOATAG_USER_SDP_STR (user_sdp->str),
1443 SOATAG_RTP_SORT(SOA_RTP_SORT_REMOTE),
1444 SOATAG_RTP_SELECT(SOA_RTP_SELECT_ALL),
1445 NUTAG_AUTOANSWER(0),
1446 TAG_END());
1447
1448 if (priv->saved_event[0])
1449 nua_destroy_event (priv->saved_event);
1450
1451 g_object_set (session, "state", SIP_MEDIA_SESSION_STATE_ACTIVE, NULL);
1452 }
1453 else
1454 {
1455 g_warning ("cannot respond with a valid SDP answer, were all streams closed?");
1456
1457 priv_session_rollback (session);
1458 }
1459
1460 g_string_free (user_sdp, TRUE);
1461 }
1462
1463 static gboolean
priv_is_codec_intersect_pending(SIPMediaSession * session)1464 priv_is_codec_intersect_pending (SIPMediaSession *session)
1465 {
1466 SIPMediaSessionPrivate *priv = SIP_MEDIA_SESSION_GET_PRIVATE (session);
1467 guint i;
1468
1469 for (i = 0; i < priv->streams->len; i++)
1470 {
1471 SIPMediaStream *stream = g_ptr_array_index (priv->streams, i);
1472 if (stream != NULL
1473 && sip_media_stream_is_codec_intersect_pending (stream))
1474 return TRUE;
1475 }
1476
1477 return FALSE;
1478 }
1479
1480 /**
1481 * Sends requests and responses with an outbound offer/answer
1482 * if all streams of the session are prepared.
1483 *
1484 * Following inputs are considered in decision making:
1485 * - state of the session (is remote INVITE being handled)
1486 * - status of local streams (set up with stream-engine)
1487 * - whether session is locally accepted
1488 */
1489 static void
priv_request_response_step(SIPMediaSession * session)1490 priv_request_response_step (SIPMediaSession *session)
1491 {
1492 SIPMediaSessionPrivate *priv = SIP_MEDIA_SESSION_GET_PRIVATE (session);
1493
1494 DEBUG ("enter, local non ready %d", priv->local_non_ready);
1495
1496 switch (priv->state)
1497 {
1498 case SIP_MEDIA_SESSION_STATE_CREATED:
1499 if (priv->local_non_ready == 0)
1500 {
1501 /* note: we need to be prepared to receive media right after the
1502 * offer is sent, so we must set state to playing */
1503 priv_session_media_state (session, TRUE);
1504
1505 priv_session_invite (session, FALSE);
1506 }
1507 break;
1508 case SIP_MEDIA_SESSION_STATE_RESPONSE_RECEIVED:
1509 if (priv->accepted
1510 && !priv_is_codec_intersect_pending (session))
1511 {
1512 g_assert (priv->local_non_ready == 0);
1513 g_object_set (session,
1514 "state", SIP_MEDIA_SESSION_STATE_ACTIVE,
1515 NULL);
1516 }
1517 break;
1518 case SIP_MEDIA_SESSION_STATE_INVITE_RECEIVED:
1519 /* TODO: if the call has not yet been accepted locally
1520 * and the remote endpoint supports 100rel, send them
1521 * an early session answer in a reliable 183 response */
1522 if (priv->accepted
1523 && priv->local_non_ready == 0
1524 && !priv_is_codec_intersect_pending (session))
1525 {
1526 priv_session_respond (session);
1527
1528 /* note: we have accepted the call, set state to playing */
1529 priv_session_media_state (session, TRUE);
1530 }
1531 break;
1532 case SIP_MEDIA_SESSION_STATE_REINVITE_RECEIVED:
1533 if (priv->local_non_ready == 0
1534 && !priv_is_codec_intersect_pending (session))
1535 {
1536 priv_session_respond (session);
1537 }
1538 break;
1539 case SIP_MEDIA_SESSION_STATE_ACTIVE:
1540 if (priv->pending_offer && priv->local_non_ready == 0)
1541 {
1542 priv_session_invite (session, TRUE);
1543 }
1544 break;
1545 default:
1546 g_assert_not_reached ();
1547 }
1548 }
1549
1550 static void
priv_stream_close_cb(SIPMediaStream * stream,SIPMediaSession * session)1551 priv_stream_close_cb (SIPMediaStream *stream,
1552 SIPMediaSession *session)
1553 {
1554 SIPMediaSessionPrivate *priv;
1555 guint id;
1556
1557 DEBUG("enter");
1558
1559 priv = SIP_MEDIA_SESSION_GET_PRIVATE (session);
1560
1561 id = sip_media_stream_get_id (stream);
1562 g_return_if_fail (g_ptr_array_index(priv->streams, id) == stream);
1563
1564 if (!sip_media_stream_is_ready (stream))
1565 {
1566 g_assert (priv->local_non_ready > 0);
1567 --priv->local_non_ready;
1568 DEBUG("stream wasn't ready, decrement the local non ready counter to %d", priv->local_non_ready);
1569 }
1570
1571 g_object_unref (stream);
1572
1573 g_ptr_array_index(priv->streams, id) = NULL;
1574
1575 tp_svc_channel_type_streamed_media_emit_stream_removed (priv->channel, id);
1576 }
1577
priv_stream_ready_cb(SIPMediaStream * stream,SIPMediaSession * session)1578 static void priv_stream_ready_cb (SIPMediaStream *stream,
1579 SIPMediaSession *session)
1580 {
1581 SIPMediaSessionPrivate *priv;
1582
1583 DEBUG ("enter");
1584
1585 priv = SIP_MEDIA_SESSION_GET_PRIVATE (session);
1586
1587 g_assert (priv->local_non_ready > 0);
1588 --priv->local_non_ready;
1589
1590 priv_request_response_step (session);
1591 }
1592
priv_stream_supported_codecs_cb(SIPMediaStream * stream,guint num_codecs,SIPMediaSession * session)1593 static void priv_stream_supported_codecs_cb (SIPMediaStream *stream,
1594 guint num_codecs,
1595 SIPMediaSession *session)
1596 {
1597 SIPMediaSessionPrivate *priv;
1598
1599 g_assert (SIP_IS_MEDIA_SESSION (session));
1600
1601 priv = SIP_MEDIA_SESSION_GET_PRIVATE (session);
1602
1603 g_assert (!sip_media_stream_is_codec_intersect_pending (stream));
1604
1605 if (num_codecs == 0)
1606 {
1607 /* This remote media description got no codec intersection. */
1608 switch (priv->state)
1609 {
1610 case SIP_MEDIA_SESSION_STATE_RESPONSE_RECEIVED:
1611 case SIP_MEDIA_SESSION_STATE_INVITE_RECEIVED:
1612 DEBUG("no codec intersection, closing the stream");
1613 sip_media_stream_close (stream);
1614 break;
1615 case SIP_MEDIA_SESSION_STATE_REINVITE_RECEIVED:
1616 /* In this case, we have the stream negotiated already,
1617 * and we don't want to close it just because the remote party
1618 * offers a different set of codecs.
1619 * Roll back the whole session to the previously negotiated state. */
1620 priv_session_rollback (session);
1621 return;
1622 default:
1623 g_assert_not_reached();
1624 }
1625 }
1626
1627 priv_request_response_step (session);
1628 }
1629
1630 static void
priv_stream_state_changed_cb(SIPMediaStream * stream,guint state,SIPMediaChannel * channel)1631 priv_stream_state_changed_cb (SIPMediaStream *stream,
1632 guint state,
1633 SIPMediaChannel *channel)
1634 {
1635 g_assert (SIP_IS_MEDIA_CHANNEL (channel));
1636 tp_svc_channel_type_streamed_media_emit_stream_state_changed(
1637 channel,
1638 sip_media_stream_get_id (stream), state);
1639 }
1640
1641 static void
priv_stream_direction_changed_cb(SIPMediaStream * stream,guint direction,guint pending_send_flags,SIPMediaChannel * channel)1642 priv_stream_direction_changed_cb (SIPMediaStream *stream,
1643 guint direction,
1644 guint pending_send_flags,
1645 SIPMediaChannel *channel)
1646 {
1647 g_assert (SIP_IS_MEDIA_CHANNEL (channel));
1648 tp_svc_channel_type_streamed_media_emit_stream_direction_changed (
1649 channel,
1650 sip_media_stream_get_id (stream), direction, pending_send_flags);
1651 }
1652
1653 static SIPMediaStream*
priv_create_media_stream(SIPMediaSession * self,guint media_type,guint pending_send_flags)1654 priv_create_media_stream (SIPMediaSession *self,
1655 guint media_type,
1656 guint pending_send_flags)
1657 {
1658 SIPMediaSessionPrivate *priv;
1659 gchar *object_path;
1660 SIPMediaStream *stream = NULL;
1661
1662 g_assert (SIP_IS_MEDIA_SESSION (self));
1663
1664 DEBUG ("enter");
1665
1666 priv = SIP_MEDIA_SESSION_GET_PRIVATE (self);
1667
1668 if (media_type == TP_MEDIA_STREAM_TYPE_AUDIO ||
1669 media_type == TP_MEDIA_STREAM_TYPE_VIDEO) {
1670
1671 object_path = g_strdup_printf ("%s/MediaStream%u",
1672 priv->object_path,
1673 priv->streams->len);
1674
1675 stream = g_object_new (SIP_TYPE_MEDIA_STREAM,
1676 "media-session", self,
1677 "media-type", media_type,
1678 "object-path", object_path,
1679 "id", priv->streams->len,
1680 "pending-send-flags", pending_send_flags,
1681 NULL);
1682
1683 g_free (object_path);
1684
1685 g_signal_connect (stream, "close",
1686 (GCallback) priv_stream_close_cb,
1687 self);
1688 g_signal_connect (stream, "ready",
1689 (GCallback) priv_stream_ready_cb,
1690 self);
1691 g_signal_connect (stream, "supported-codecs",
1692 (GCallback) priv_stream_supported_codecs_cb,
1693 self);
1694 g_signal_connect (stream, "state-changed",
1695 (GCallback) priv_stream_state_changed_cb,
1696 priv->channel);
1697 g_signal_connect (stream, "direction-changed",
1698 (GCallback) priv_stream_direction_changed_cb,
1699 priv->channel);
1700
1701 g_assert (priv->local_non_ready >= 0);
1702 ++priv->local_non_ready;
1703
1704 if (priv->se_ready == TRUE) {
1705 priv_emit_new_stream (self, stream);
1706 }
1707
1708 g_signal_emit (self, signals[SIG_STREAM_ADDED], 0, stream);
1709 }
1710
1711 /* note: we add an entry even for unsupported media types */
1712 g_ptr_array_add (priv->streams, stream);
1713
1714 DEBUG ("exit");
1715
1716 return stream;
1717 }
1718
1719 static void
session_handler_iface_init(gpointer g_iface,gpointer iface_data)1720 session_handler_iface_init (gpointer g_iface, gpointer iface_data)
1721 {
1722 TpSvcMediaSessionHandlerClass *klass = (TpSvcMediaSessionHandlerClass *)g_iface;
1723
1724 #define IMPLEMENT(x) tp_svc_media_session_handler_implement_##x (\
1725 klass, (tp_svc_media_session_handler_##x##_impl) sip_media_session_##x)
1726 IMPLEMENT(error);
1727 IMPLEMENT(ready);
1728 #undef IMPLEMENT
1729 }
1730