1 /*
2  * sip-media-channel.c - Source for SIPMediaChannel
3  * Copyright (C) 2005-2007 Collabora Ltd.
4  * Copyright (C) 2005-2007 Nokia Corporation
5  *   @author Kai Vehmanen <first.surname@nokia.com>
6  *
7  * Based on telepathy-gabble implementation (gabble-media-channel).
8  *   @author Ole Andre Vadla Ravnaas <ole.andre.ravnaas@collabora.co.uk>
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public License
12  * version 2.1 as published by the Free Software Foundation.
13  *
14  * This library 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 GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
22  */
23 
24 #define DBUS_API_SUBJECT_TO_CHANGE 1
25 #include <dbus/dbus-glib.h>
26 #include <stdlib.h>
27 
28 #include <telepathy-glib/channel-iface.h>
29 #include <telepathy-glib/dbus.h>
30 #include <telepathy-glib/errors.h>
31 #include <telepathy-glib/interfaces.h>
32 #include <telepathy-glib/intset.h>
33 #include <telepathy-glib/svc-channel.h>
34 
35 #include "sip-media-channel.h"
36 #include "media-factory.h"
37 #include "sip-connection.h"
38 #include "sip-media-session.h"
39 #include "sip-media-stream.h"
40 
41 #include "telepathy-helpers.h"
42 #include "sip-connection-helpers.h"
43 
44 #define DEBUG_FLAG SIP_DEBUG_MEDIA
45 #include "debug.h"
46 
47 static void channel_iface_init (gpointer, gpointer);
48 static void media_signalling_iface_init (gpointer, gpointer);
49 static void streamed_media_iface_init (gpointer, gpointer);
50 static void dtmf_iface_init (gpointer, gpointer);
51 static void priv_group_mixin_iface_init (gpointer, gpointer);
52 
53 G_DEFINE_TYPE_WITH_CODE (SIPMediaChannel, sip_media_channel,
54     G_TYPE_OBJECT,
55     G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL, channel_iface_init);
56     G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_INTERFACE_GROUP,
57       priv_group_mixin_iface_init);
58     G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_INTERFACE_MEDIA_SIGNALLING,
59       media_signalling_iface_init);
60     G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_INTERFACE_DTMF,
61       dtmf_iface_init);
62     G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_TYPE_STREAMED_MEDIA,
63       streamed_media_iface_init);
64     G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_PROPERTIES_INTERFACE,
65       tp_properties_mixin_iface_init);
66     G_IMPLEMENT_INTERFACE (TP_TYPE_CHANNEL_IFACE, NULL));
67 
68 /* properties */
69 enum
70 {
71   PROP_CONNECTION = 1,
72   PROP_FACTORY,
73   PROP_OBJECT_PATH,
74   PROP_CHANNEL_TYPE,
75   PROP_HANDLE_TYPE,
76   PROP_HANDLE,
77   /* Telepathy properties (see below too) */
78   PROP_NAT_TRAVERSAL,
79   PROP_STUN_SERVER,
80   PROP_STUN_PORT,
81   LAST_PROPERTY
82 };
83 
84 /* TP channel properties */
85 enum
86 {
87   TP_PROP_NAT_TRAVERSAL = 0,
88   TP_PROP_STUN_SERVER,
89   TP_PROP_STUN_PORT,
90   NUM_TP_PROPS
91 };
92 
93 const TpPropertySignature media_channel_property_signatures[NUM_TP_PROPS] =
94 {
95     { "nat-traversal",          G_TYPE_STRING },
96     { "stun-server",            G_TYPE_STRING },
97     { "stun-port",              G_TYPE_UINT },
98 };
99 
100 /* private structure */
101 typedef struct _SIPMediaChannelPrivate SIPMediaChannelPrivate;
102 
103 struct _SIPMediaChannelPrivate
104 {
105   gboolean dispose_has_run;
106   gboolean closed;
107   SIPConnection *conn;
108   SIPMediaFactory *factory;
109   SIPMediaSession *session;
110   gchar *object_path;
111 };
112 
113 #define SIP_MEDIA_CHANNEL_GET_PRIVATE(o)     (G_TYPE_INSTANCE_GET_PRIVATE ((o), SIP_TYPE_MEDIA_CHANNEL, SIPMediaChannelPrivate))
114 
DEFINE_TP_STRUCT_TYPE(sip_session_handler_type,DBUS_TYPE_G_OBJECT_PATH,G_TYPE_STRING)115 DEFINE_TP_STRUCT_TYPE(sip_session_handler_type,
116                       DBUS_TYPE_G_OBJECT_PATH,
117                       G_TYPE_STRING)
118 
119 
120 /***********************************************************************
121  * Set: Gobject interface
122  ***********************************************************************/
123 
124 static void
125 sip_media_channel_init (SIPMediaChannel *obj)
126 {
127   /* allocate any data required by the object here */
128 
129   /* initialise the properties mixin *before* GObject
130    * sets the construct-time properties */
131   tp_properties_mixin_init (G_OBJECT (obj),
132       G_STRUCT_OFFSET (SIPMediaChannel, properties));
133 }
134 
135 static GObject *
sip_media_channel_constructor(GType type,guint n_props,GObjectConstructParam * props)136 sip_media_channel_constructor (GType type, guint n_props,
137 			       GObjectConstructParam *props)
138 {
139   GObject *obj;
140   SIPMediaChannelPrivate *priv;
141   DBusGConnection *bus;
142   TpBaseConnection *conn;
143   TpHandleRepoIface *contact_repo;
144 
145   DEBUG("enter");
146 
147   obj = G_OBJECT_CLASS (sip_media_channel_parent_class)->
148            constructor (type, n_props, props);
149 
150   priv = SIP_MEDIA_CHANNEL_GET_PRIVATE (SIP_MEDIA_CHANNEL (obj));
151   conn = (TpBaseConnection *)(priv->conn);
152   contact_repo = tp_base_connection_get_handles (conn,
153       TP_HANDLE_TYPE_CONTACT);
154 
155   /* register object on the bus */
156   bus = tp_get_bus ();
157 
158   DEBUG("registering object to dbus path=%s", priv->object_path);
159   dbus_g_connection_register_g_object (bus, priv->object_path, obj);
160 
161   tp_group_mixin_init (obj,
162                        G_STRUCT_OFFSET (SIPMediaChannel, group),
163                        contact_repo,
164                        conn->self_handle);
165 
166   /* allow member adding */
167   tp_group_mixin_change_flags (obj, TP_CHANNEL_GROUP_FLAG_CAN_ADD, 0);
168 
169   return obj;
170 }
171 
172 static void sip_media_channel_dispose (GObject *object);
173 static void sip_media_channel_finalize (GObject *object);
174 static void sip_media_channel_get_property (GObject    *object,
175 					    guint       property_id,
176 					    GValue     *value,
177 					    GParamSpec *pspec);
178 static void sip_media_channel_set_property (GObject     *object,
179 					    guint        property_id,
180 					    const GValue *value,
181 					    GParamSpec   *pspec);
182 
183 static void priv_create_session (SIPMediaChannel *channel,
184                                  nua_handle_t *nh,
185                                  TpHandle peer,
186                                  gboolean remote_initiated);
187 static void priv_destroy_session(SIPMediaChannel *channel);
188 static gboolean sip_media_channel_add_member (GObject *iface,
189                                               TpHandle handle,
190                                               const gchar *message,
191                                               GError **error);
192 static gboolean sip_media_channel_remove_with_reason (
193                                                  GObject *iface,
194                                                  TpHandle handle,
195                                                  const gchar *message,
196                                                  guint reason,
197                                                  GError **error);
198 
199 static void
sip_media_channel_class_init(SIPMediaChannelClass * sip_media_channel_class)200 sip_media_channel_class_init (SIPMediaChannelClass *sip_media_channel_class)
201 {
202   GObjectClass *object_class = G_OBJECT_CLASS (sip_media_channel_class);
203   GParamSpec *param_spec;
204 
205   DEBUG("enter");
206 
207   g_type_class_add_private (sip_media_channel_class, sizeof (SIPMediaChannelPrivate));
208 
209   object_class->constructor = sip_media_channel_constructor;
210 
211   object_class->get_property = sip_media_channel_get_property;
212   object_class->set_property = sip_media_channel_set_property;
213 
214   object_class->dispose = sip_media_channel_dispose;
215   object_class->finalize = sip_media_channel_finalize;
216 
217   tp_group_mixin_class_init (object_class,
218                              G_STRUCT_OFFSET (SIPMediaChannelClass, group_class),
219                              sip_media_channel_add_member,
220                              NULL);
221   tp_group_mixin_class_set_remove_with_reason_func(object_class,
222                              sip_media_channel_remove_with_reason);
223 
224   g_object_class_override_property (object_class, PROP_HANDLE_TYPE,
225       "handle-type");
226   g_object_class_override_property (object_class, PROP_HANDLE, "handle");
227 
228   tp_properties_mixin_class_init (object_class,
229       G_STRUCT_OFFSET (SIPMediaChannelClass, properties_class),
230       media_channel_property_signatures, NUM_TP_PROPS, NULL);
231 
232   param_spec = g_param_spec_object ("connection", "SIPConnection object",
233                                     "SIP connection object that owns this "
234                                     "SIP media channel object.",
235                                     SIP_TYPE_CONNECTION,
236                                     G_PARAM_CONSTRUCT_ONLY |
237                                     G_PARAM_READWRITE |
238                                     G_PARAM_STATIC_NICK |
239                                     G_PARAM_STATIC_BLURB);
240   g_object_class_install_property (object_class, PROP_CONNECTION, param_spec);
241 
242   param_spec = g_param_spec_object ("factory", "SIPMediaFactory object",
243                                     "Channel factory object that owns this "
244                                     "SIP media channel object.",
245                                     SIP_TYPE_MEDIA_FACTORY,
246                                     G_PARAM_CONSTRUCT_ONLY |
247                                     G_PARAM_READWRITE |
248                                     G_PARAM_STATIC_NICK |
249                                     G_PARAM_STATIC_BLURB);
250   g_object_class_install_property (object_class, PROP_FACTORY, param_spec);
251 
252   param_spec = g_param_spec_string ("object-path", "D-Bus object path",
253                                     "The D-Bus object path used for this "
254                                     "object on the bus.",
255                                     NULL,
256                                     G_PARAM_CONSTRUCT_ONLY |
257                                     G_PARAM_READWRITE |
258                                     G_PARAM_STATIC_NAME |
259                                     G_PARAM_STATIC_BLURB);
260   g_object_class_install_property (object_class, PROP_OBJECT_PATH, param_spec);
261 
262   param_spec = g_param_spec_string ("channel-type", "Telepathy channel type",
263                                     "The D-Bus interface representing the "
264                                     "type of this channel.",
265                                     NULL,
266                                     G_PARAM_READABLE |
267                                     G_PARAM_STATIC_NAME |
268                                     G_PARAM_STATIC_BLURB);
269   g_object_class_install_property (object_class, PROP_CHANNEL_TYPE, param_spec);
270 
271   param_spec = g_param_spec_string ("nat-traversal", "NAT traversal mechanism",
272                                     "A string representing the type of NAT "
273                                     "traversal that should be performed for "
274                                     "streams on this channel.",
275                                     "none",
276                                     G_PARAM_CONSTRUCT_ONLY |
277                                     G_PARAM_READWRITE |
278                                     G_PARAM_STATIC_NAME |
279                                     G_PARAM_STATIC_BLURB);
280   g_object_class_install_property (object_class, PROP_NAT_TRAVERSAL, param_spec);
281 
282   param_spec = g_param_spec_string ("stun-server",
283                                     "STUN server",
284                                     "IP or address of STUN server.",
285                                     NULL,
286                                     G_PARAM_READWRITE |
287                                     G_PARAM_STATIC_NAME |
288                                     G_PARAM_STATIC_BLURB);
289   g_object_class_install_property (object_class, PROP_STUN_SERVER, param_spec);
290 
291   param_spec = g_param_spec_uint ("stun-port",
292                                   "STUN port",
293                                   "UDP port of STUN server.",
294                                   0, G_MAXUINT16, 0,
295                                   G_PARAM_READWRITE |
296                                   G_PARAM_STATIC_NAME |
297                                   G_PARAM_STATIC_BLURB);
298   g_object_class_install_property (object_class, PROP_STUN_PORT, param_spec);
299 }
300 
301 static void
sip_media_channel_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)302 sip_media_channel_get_property (GObject    *object,
303                                 guint       property_id,
304                                 GValue     *value,
305                                 GParamSpec *pspec)
306 {
307   SIPMediaChannel *chan = SIP_MEDIA_CHANNEL (object);
308   SIPMediaChannelPrivate *priv = SIP_MEDIA_CHANNEL_GET_PRIVATE (chan);
309 
310   switch (property_id) {
311     case PROP_CONNECTION:
312       g_value_set_object (value, priv->conn);
313       break;
314     case PROP_FACTORY:
315       g_value_set_object (value, priv->factory);
316       break;
317     case PROP_OBJECT_PATH:
318       g_value_set_string (value, priv->object_path);
319       break;
320     case PROP_CHANNEL_TYPE:
321       g_value_set_string (value, TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA);
322       break;
323     case PROP_HANDLE:
324       g_value_set_uint (value, 0);
325       break;
326     case PROP_HANDLE_TYPE:
327       g_value_set_uint (value, TP_HANDLE_TYPE_NONE);
328       break;
329     default:
330       /* the NAT_TRAVERSAL property lives in the mixin */
331       {
332         const gchar *param_name = g_param_spec_get_name (pspec);
333         guint tp_property_id;
334 
335         if (tp_properties_mixin_has_property (object, param_name,
336               &tp_property_id))
337           {
338             GValue *tp_property_value =
339               chan->properties.properties[tp_property_id].value;
340 
341             if (tp_property_value)
342               {
343                 g_value_copy (tp_property_value, value);
344                 return;
345               }
346           }
347       }
348 
349       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
350       break;
351   }
352 }
353 
354 static void
sip_media_channel_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)355 sip_media_channel_set_property (GObject     *object,
356 				guint        property_id,
357 				const GValue *value,
358 				GParamSpec   *pspec)
359 {
360   SIPMediaChannel *chan = SIP_MEDIA_CHANNEL (object);
361   SIPMediaChannelPrivate *priv = SIP_MEDIA_CHANNEL_GET_PRIVATE (chan);
362 
363   switch (property_id) {
364     case PROP_HANDLE:
365       /* this property is writable in the interface, but not actually
366        * meaningfully changable on this channel, so we do nothing */
367       break;
368     case PROP_HANDLE_TYPE:
369       /* this property is writable in the interface, but not actually
370        * meaningfully changable on this channel, so we do nothing */
371       break;
372     case PROP_CONNECTION:
373       priv->conn = SIP_CONNECTION (g_value_dup_object (value));
374       break;
375     case PROP_FACTORY:
376       priv->factory = SIP_MEDIA_FACTORY (g_value_dup_object (value));
377       break;
378     case PROP_OBJECT_PATH:
379       g_free (priv->object_path);
380       priv->object_path = g_value_dup_string (value);
381       break;
382     default:
383       /* the NAT_TRAVERSAL property lives in the mixin */
384       {
385         const gchar *param_name = g_param_spec_get_name (pspec);
386         guint tp_property_id;
387 
388         if (tp_properties_mixin_has_property (object, param_name,
389               &tp_property_id))
390           {
391             tp_properties_mixin_change_value (object, tp_property_id,
392                 value, NULL);
393             tp_properties_mixin_change_flags (object, tp_property_id,
394                 TP_PROPERTY_FLAG_READ, 0, NULL);
395             return;
396           }
397       }
398 
399       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
400       break;
401   }
402 }
403 
404 void
sip_media_channel_dispose(GObject * object)405 sip_media_channel_dispose (GObject *object)
406 {
407   SIPMediaChannel *self = SIP_MEDIA_CHANNEL (object);
408   SIPMediaChannelPrivate *priv = SIP_MEDIA_CHANNEL_GET_PRIVATE (self);
409 
410   if (priv->dispose_has_run)
411     return;
412 
413   DEBUG("enter");
414 
415   priv->dispose_has_run = TRUE;
416 
417   priv_destroy_session(self);
418 
419   if (!priv->closed)
420     sip_media_channel_close (self);
421 
422   if (priv->factory)
423     g_object_unref (priv->factory);
424 
425   if (priv->conn)
426     g_object_unref (priv->conn);
427 
428   if (G_OBJECT_CLASS (sip_media_channel_parent_class)->dispose)
429     G_OBJECT_CLASS (sip_media_channel_parent_class)->dispose (object);
430 
431   DEBUG("exit");
432 }
433 
434 void
sip_media_channel_finalize(GObject * object)435 sip_media_channel_finalize (GObject *object)
436 {
437   SIPMediaChannel *self = SIP_MEDIA_CHANNEL (object);
438   SIPMediaChannelPrivate *priv = SIP_MEDIA_CHANNEL_GET_PRIVATE (self);
439 
440   g_free (priv->object_path);
441 
442   tp_group_mixin_finalize (object);
443 
444   tp_properties_mixin_finalize (object);
445 
446   G_OBJECT_CLASS (sip_media_channel_parent_class)->finalize (object);
447 
448   DEBUG("exit");
449 }
450 
451 /***********************************************************************
452  * Set: Channel interface implementation (same for 0.12/0.13)
453  ***********************************************************************/
454 
455 /**
456  * sip_media_channel_close_async
457  *
458  * Implements DBus method Close
459  * on interface org.freedesktop.Telepathy.Channel
460  */
461 static void
sip_media_channel_close_async(TpSvcChannel * iface,DBusGMethodInvocation * context)462 sip_media_channel_close_async (TpSvcChannel *iface,
463                                DBusGMethodInvocation *context)
464 {
465   SIPMediaChannel *self = SIP_MEDIA_CHANNEL (iface);
466 
467   sip_media_channel_close (self);
468   tp_svc_channel_return_from_close (context);
469 }
470 
471 void
sip_media_channel_close(SIPMediaChannel * obj)472 sip_media_channel_close (SIPMediaChannel *obj)
473 {
474   SIPMediaChannelPrivate *priv;
475 
476   DEBUG("enter");
477 
478   g_assert (SIP_IS_MEDIA_CHANNEL (obj));
479   priv = SIP_MEDIA_CHANNEL_GET_PRIVATE (obj);
480 
481   if (priv->closed)
482     return;
483 
484   priv->closed = TRUE;
485 
486   if (priv->session) {
487     sip_media_session_terminate (priv->session);
488     g_assert (priv->session == NULL);
489   }
490 
491   tp_svc_channel_emit_closed ((TpSvcChannel *)obj);
492 
493   return;
494 }
495 
496 void
sip_media_channel_terminated(SIPMediaChannel * self)497 sip_media_channel_terminated (SIPMediaChannel *self)
498 {
499   SIPMediaChannelPrivate *priv;
500 
501   DEBUG("enter");
502 
503   priv = SIP_MEDIA_CHANNEL_GET_PRIVATE (self);
504 
505   if (priv->session)
506     {
507       g_object_set (priv->session,
508                     "state", SIP_MEDIA_SESSION_STATE_ENDED,
509                     NULL);
510     }
511 }
512 
513 /**
514  * sip_media_channel_get_channel_type
515  *
516  * Implements DBus method GetChannelType
517  * on interface org.freedesktop.Telepathy.Channel
518  */
519 static void
sip_media_channel_get_channel_type(TpSvcChannel * obj,DBusGMethodInvocation * context)520 sip_media_channel_get_channel_type (TpSvcChannel *obj,
521                                     DBusGMethodInvocation *context)
522 {
523   tp_svc_channel_return_from_get_channel_type (context,
524       TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA);
525 }
526 
527 
528 /**
529  * sip_media_channel_get_handle
530  *
531  * Implements DBus method GetHandle
532  * on interface org.freedesktop.Telepathy.Channel
533  */
534 static void
sip_media_channel_get_handle(TpSvcChannel * iface,DBusGMethodInvocation * context)535 sip_media_channel_get_handle (TpSvcChannel *iface,
536                               DBusGMethodInvocation *context)
537 {
538   tp_svc_channel_return_from_get_handle (context, 0, 0);
539 }
540 
541 /**
542  * sip_media_channel_get_interfaces
543  *
544  * Implements DBus method GetInterfaces
545  * on interface org.freedesktop.Telepathy.Channel
546  */
547 static void
sip_media_channel_get_interfaces(TpSvcChannel * iface,DBusGMethodInvocation * context)548 sip_media_channel_get_interfaces (TpSvcChannel *iface,
549                                   DBusGMethodInvocation *context)
550 {
551   const gchar *interfaces[] = {
552     TP_IFACE_CHANNEL_INTERFACE_GROUP,
553     TP_IFACE_CHANNEL_INTERFACE_MEDIA_SIGNALLING,
554     TP_IFACE_CHANNEL_INTERFACE_DTMF,
555     TP_IFACE_PROPERTIES_INTERFACE,
556     NULL
557   };
558 
559   tp_svc_channel_return_from_get_interfaces (context, interfaces);
560 }
561 
562 /***********************************************************************
563  * Set: Channel.Interface.MediaSignalling Telepathy-0.13 interface
564  ***********************************************************************/
565 
566 /**
567  * sip_media_channel_get_session_handlers
568  *
569  * Implements DBus method GetSessionHandlers
570  * on interface org.freedesktop.Telepathy.Channel.Interface.MediaSignalling
571  *
572  * @error: Used to return a pointer to a GError detailing any error
573  *         that occured, DBus will throw the error only if this
574  *         function returns false.
575  *
576  * Returns: TRUE if successful, FALSE if an error was thrown.
577  */
578 static void
sip_media_channel_get_session_handlers(TpSvcChannelInterfaceMediaSignalling * iface,DBusGMethodInvocation * context)579 sip_media_channel_get_session_handlers (TpSvcChannelInterfaceMediaSignalling *iface,
580                                         DBusGMethodInvocation *context)
581 {
582   SIPMediaChannel *self = SIP_MEDIA_CHANNEL (iface);
583   SIPMediaChannelPrivate *priv;
584   GPtrArray *ret;
585   GValue handler = { 0 };
586 
587   DEBUG("enter");
588 
589   g_assert (SIP_IS_MEDIA_CHANNEL (self));
590 
591   priv = SIP_MEDIA_CHANNEL_GET_PRIVATE (self);
592 
593   ret = g_ptr_array_new ();
594 
595   if (priv->session)
596     {
597       GType handler_type;
598       gchar *path;
599 
600       g_object_get (priv->session,
601                     "object-path", &path,
602                     NULL);
603 
604       handler_type = sip_session_handler_type ();
605 
606       g_value_init (&handler, handler_type);
607       g_value_take_boxed (&handler,
608                           dbus_g_type_specialized_construct (handler_type));
609 
610       dbus_g_type_struct_set (&handler,
611                               0, path,
612                               1, "rtp",
613                               G_MAXUINT);
614 
615       g_free (path);
616 
617       g_ptr_array_add (ret, g_value_get_boxed (&handler));
618     }
619 
620   tp_svc_channel_interface_media_signalling_return_from_get_session_handlers (
621       context, ret);
622 
623   if (G_IS_VALUE(&handler))
624     g_value_unset (&handler);
625 
626   g_ptr_array_free (ret, TRUE);
627 }
628 
629 
630 /***********************************************************************
631  * Set: Channel.Type.StreamedMedia Telepathy-0.13 interface
632  ***********************************************************************/
633 
634 /**
635  * sip_media_channel_list_streams
636  *
637  * Implements D-Bus method ListStreams
638  * on interface org.freedesktop.Telepathy.Channel.Type.StreamedMedia
639  */
640 static void
sip_media_channel_list_streams(TpSvcChannelTypeStreamedMedia * iface,DBusGMethodInvocation * context)641 sip_media_channel_list_streams (TpSvcChannelTypeStreamedMedia *iface,
642                                 DBusGMethodInvocation *context)
643 {
644   SIPMediaChannel *self = SIP_MEDIA_CHANNEL (iface);
645   SIPMediaChannelPrivate *priv;
646   GPtrArray *ret = NULL;
647 
648   g_assert (SIP_IS_MEDIA_CHANNEL (self));
649   priv = SIP_MEDIA_CHANNEL_GET_PRIVATE (self);
650 
651   if (!sip_media_session_list_streams (priv->session, &ret))
652     ret = g_ptr_array_new ();
653 
654   tp_svc_channel_type_streamed_media_return_from_list_streams (context, ret);
655 
656   g_boxed_free (SIP_TP_STREAM_LIST_TYPE, ret);
657 }
658 
659 /**
660  * sip_media_channel_remove_streams
661  *
662  * Implements D-Bus method RemoveStreams
663  * on interface org.freedesktop.Telepathy.Channel.Type.StreamedMedia
664  */
665 static void
sip_media_channel_remove_streams(TpSvcChannelTypeStreamedMedia * iface,const GArray * streams,DBusGMethodInvocation * context)666 sip_media_channel_remove_streams (TpSvcChannelTypeStreamedMedia *iface,
667                                   const GArray *streams,
668                                   DBusGMethodInvocation *context)
669 {
670   SIPMediaChannel *self = SIP_MEDIA_CHANNEL (iface);
671   SIPMediaChannelPrivate *priv;
672   GError *error = NULL;
673 
674   priv = SIP_MEDIA_CHANNEL_GET_PRIVATE (self);
675 
676   if (priv->session != NULL)
677     {
678        sip_media_session_remove_streams(priv->session,
679                                         streams,
680                                         &error);
681     }
682   else
683     {
684       error = g_error_new (TP_ERRORS, TP_ERROR_NOT_AVAILABLE,
685                            "No session is available");
686     }
687 
688   if (error != NULL)
689     {
690       dbus_g_method_return_error (context, error);
691       g_error_free (error);
692       return;
693     }
694 
695   tp_svc_channel_type_streamed_media_return_from_remove_streams (context);
696 }
697 
698 /**
699  * sip_media_channel_request_stream_direction
700  *
701  * Implements D-Bus method RequestStreamDirection
702  * on interface org.freedesktop.Telepathy.Channel.Type.StreamedMedia
703  */
704 static void
sip_media_channel_request_stream_direction(TpSvcChannelTypeStreamedMedia * iface,guint stream_id,guint stream_direction,DBusGMethodInvocation * context)705 sip_media_channel_request_stream_direction (TpSvcChannelTypeStreamedMedia *iface,
706                                             guint stream_id,
707                                             guint stream_direction,
708                                             DBusGMethodInvocation *context)
709 {
710   SIPMediaChannel *self = SIP_MEDIA_CHANNEL (iface);
711   SIPMediaChannelPrivate *priv;
712   GError *error = NULL;
713 
714   priv = SIP_MEDIA_CHANNEL_GET_PRIVATE (self);
715 
716   if (priv->session != NULL)
717     {
718        sip_media_session_request_stream_direction (priv->session,
719                                                    stream_id,
720                                                    stream_direction,
721                                                    &error);
722     }
723   else
724     {
725       error = g_error_new (TP_ERRORS, TP_ERROR_NOT_AVAILABLE,
726                            "No session is available");
727     }
728 
729   if (error != NULL)
730     {
731       dbus_g_method_return_error (context, error);
732       g_error_free (error);
733       return;
734     }
735   tp_svc_channel_type_streamed_media_return_from_request_stream_direction (context);
736 }
737 
738 
739 /**
740  * sip_media_channel_request_streams
741  *
742  * Implements D-Bus method RequestStreams
743  * on interface org.freedesktop.Telepathy.Channel.Type.StreamedMedia
744  */
745 static void
sip_media_channel_request_streams(TpSvcChannelTypeStreamedMedia * iface,guint contact_handle,const GArray * types,DBusGMethodInvocation * context)746 sip_media_channel_request_streams (TpSvcChannelTypeStreamedMedia *iface,
747                                    guint contact_handle,
748                                    const GArray *types,
749                                    DBusGMethodInvocation *context)
750 {
751   SIPMediaChannel *self = SIP_MEDIA_CHANNEL (iface);
752   GError *error = NULL;
753   GPtrArray *ret = NULL;
754   SIPMediaChannelPrivate *priv;
755   TpHandleRepoIface *contact_repo;
756 
757   DEBUG("enter");
758 
759   g_assert (SIP_IS_MEDIA_CHANNEL (self));
760 
761   priv = SIP_MEDIA_CHANNEL_GET_PRIVATE (self);
762 
763   contact_repo = tp_base_connection_get_handles (
764       (TpBaseConnection *)(priv->conn), TP_HANDLE_TYPE_CONTACT);
765 
766   if (!tp_handle_is_valid (contact_repo, contact_handle, &error))
767     {
768       dbus_g_method_return_error (context, error);
769       g_error_free (error);
770       return;
771     }
772 
773   if (!tp_handle_set_is_member (self->group.members, contact_handle) &&
774       !tp_handle_set_is_member (self->group.remote_pending, contact_handle))
775     {
776       error = g_error_new (TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, "given handle "
777 			    "%u is not a member of the channel", contact_handle);
778       dbus_g_method_return_error (context, error);
779       g_error_free (error);
780       return;
781     }
782 
783   /* if the person is a channel member, we should have a session */
784   g_assert (priv->session != NULL);
785 
786   if (!sip_media_session_request_streams (priv->session, types, &ret, &error))
787     {
788       dbus_g_method_return_error (context, error);
789       g_error_free (error);
790       return;
791     }
792 
793   g_assert (types->len == ret->len);
794 
795   tp_svc_channel_type_streamed_media_return_from_request_streams (context, ret);
796 
797   g_boxed_free (SIP_TP_STREAM_LIST_TYPE, ret);
798 
799   DEBUG ("exit");
800 }
801 
802 /***********************************************************************
803  * Set: sip-media-channel API towards sip-connection
804  ***********************************************************************/
805 
806 /**
807  * Handle an incoming INVITE, normally called just after the channel
808  * has been created.
809  */
810 void
sip_media_channel_receive_invite(SIPMediaChannel * self,nua_handle_t * nh,TpHandle handle)811 sip_media_channel_receive_invite (SIPMediaChannel *self,
812                                   nua_handle_t *nh,
813                                   TpHandle handle)
814 {
815   SIPMediaChannelPrivate *priv = SIP_MEDIA_CHANNEL_GET_PRIVATE (self);
816   TpGroupMixin *mixin = TP_GROUP_MIXIN (self);
817   GObject *obj = G_OBJECT (self);
818   TpHandleRepoIface *contact_repo;
819   TpIntSet *member_set, *pending_set;
820 
821   contact_repo = tp_base_connection_get_handles (
822         (TpBaseConnection *)(priv->conn), TP_HANDLE_TYPE_CONTACT);
823 
824   if (priv->session == NULL)
825     {
826       priv_create_session (self, nh, handle, TRUE);
827 
828       /* note: start the local stream-engine; once the local
829        *       candidate are ready, reply with nua_respond()
830        *
831        *       with the tp-0.13 API, the streams need to be created
832        *       based on remote SDP (see sip_media_session_set_remote_media()) */
833     }
834   else
835     g_warning ("session already exists");
836 
837   /* XXX: should be attached more data than just the handle?
838    * - yes, we need to be able to access all the <op,handle> pairs */
839 
840   DEBUG("adding handle %d (%s)",
841         handle,
842         tp_handle_inspect (contact_repo, handle));
843 
844   /* add the peer to channel members and self_handle to local pending */
845 
846   member_set = tp_intset_new ();
847   tp_intset_add (member_set, handle);
848 
849   pending_set = tp_intset_new ();
850   tp_intset_add (pending_set, mixin->self_handle);
851 
852   tp_group_mixin_change_members (obj, "INVITE received",
853                                  member_set,    /* add */
854                                  NULL,          /* remove */
855                                  pending_set,   /* local pending */
856                                  NULL,          /* remote pending */
857                                  0, 0);         /* irrelevant */
858 
859   tp_intset_destroy (member_set);
860   tp_intset_destroy (pending_set);
861 }
862 
863 /**
864  * Handle an incoming re-INVITE request.
865  */
866 void
sip_media_channel_receive_reinvite(SIPMediaChannel * self)867 sip_media_channel_receive_reinvite (SIPMediaChannel *self)
868 {
869   SIPMediaChannelPrivate *priv = SIP_MEDIA_CHANNEL_GET_PRIVATE (self);
870 
871   g_return_if_fail (priv->session != NULL);
872 
873   sip_media_session_receive_reinvite (priv->session);
874 }
875 
876 gboolean
sip_media_channel_set_remote_media(SIPMediaChannel * chan,const sdp_session_t * r_sdp)877 sip_media_channel_set_remote_media (SIPMediaChannel *chan,
878                                     const sdp_session_t* r_sdp)
879 {
880   SIPMediaChannelPrivate *priv = SIP_MEDIA_CHANNEL_GET_PRIVATE (chan);
881 
882   g_return_val_if_fail (priv->session != NULL, FALSE);
883 
884   return sip_media_session_set_remote_media (priv->session, r_sdp);
885 }
886 
887 void
sip_media_channel_ready(SIPMediaChannel * self)888 sip_media_channel_ready (SIPMediaChannel *self)
889 {
890   SIPMediaChannelPrivate *priv = SIP_MEDIA_CHANNEL_GET_PRIVATE (self);
891   g_return_if_fail (priv->session != NULL);
892   sip_media_session_accept (priv->session);
893 }
894 
895 void
sip_media_channel_peer_error(SIPMediaChannel * self,guint status,const char * message)896 sip_media_channel_peer_error (SIPMediaChannel *self,
897                               guint status,
898                               const char* message)
899 {
900   SIPMediaChannelPrivate *priv = SIP_MEDIA_CHANNEL_GET_PRIVATE (self);
901   TpIntSet *set;
902   TpHandle peer;
903   guint reason = TP_CHANNEL_GROUP_CHANGE_REASON_ERROR;
904 
905   DEBUG("peer responded with %u %s", status, message);
906 
907   g_return_if_fail (priv->session != NULL);
908 
909   g_assert (status >= 300);
910 
911   switch (status)
912     {
913     case 410:
914     case 604:
915       reason = TP_CHANNEL_GROUP_CHANGE_REASON_INVALID_CONTACT;
916       break;
917     case 486:
918     case 600:
919       reason = TP_CHANNEL_GROUP_CHANGE_REASON_BUSY;
920       break;
921     case 408:
922       reason = TP_CHANNEL_GROUP_CHANGE_REASON_NO_ANSWER;
923       break;
924     case 404:
925     case 480:
926       reason = TP_CHANNEL_GROUP_CHANGE_REASON_OFFLINE;
927       break;
928     case 603:
929       /* No reason means roughly "rejected" */
930       reason = TP_CHANNEL_GROUP_CHANGE_REASON_NONE;
931       break;
932     case 403:
933     case 401:
934     case 407:
935       reason = TP_CHANNEL_GROUP_CHANGE_REASON_PERMISSION_DENIED;
936       break;
937     }
938 
939   peer = sip_media_session_get_peer (priv->session);
940 
941   if (message == NULL || !g_utf8_validate (message, -1, NULL))
942     message = "";
943 
944   set = tp_intset_new ();
945   tp_intset_add (set, peer);
946   tp_group_mixin_change_members ((GObject *)self, message,
947       NULL, set, NULL, NULL, peer, reason);
948   tp_intset_destroy (set);
949 }
950 
951 void
sip_media_channel_peer_cancel(SIPMediaChannel * self,guint cause,const gchar * message)952 sip_media_channel_peer_cancel (SIPMediaChannel *self,
953                                guint cause,
954                                const gchar *message)
955 {
956   SIPMediaChannelPrivate *priv = SIP_MEDIA_CHANNEL_GET_PRIVATE (self);
957   TpGroupMixin *mixin = TP_GROUP_MIXIN (self);
958   TpIntSet *set;
959   TpHandle actor = 0;
960   TpHandle peer;
961 
962   g_return_if_fail (priv->session != NULL);
963 
964   peer = sip_media_session_get_peer (priv->session);
965 
966   switch (cause)
967     {
968     case 200:
969     case 603:
970       /* The user must have acted on another branch of the forked call */
971       actor = mixin->self_handle;
972       break;
973     default:
974       actor = peer;
975     }
976 
977   if (message == NULL || !g_utf8_validate (message, -1, NULL))
978     message = "Cancelled";
979 
980   set = tp_intset_new ();
981   tp_intset_add (set, peer);
982   tp_intset_add (set, mixin->self_handle);
983 
984   tp_group_mixin_change_members ((GObject *) self,
985                                  message,
986                                  NULL, /* add */
987                                  set,  /* remove */
988                                  NULL,
989                                  NULL,
990                                  actor,
991                                  TP_CHANNEL_GROUP_CHANGE_REASON_NONE);
992 
993   tp_intset_destroy (set);
994 }
995 
996 /***********************************************************************
997  * Set: Helper functions follow (not based on generated templates)
998  ***********************************************************************/
999 
priv_session_state_changed_cb(SIPMediaSession * session,GParamSpec * arg1,SIPMediaChannel * channel)1000 static void priv_session_state_changed_cb (SIPMediaSession *session,
1001 					   GParamSpec *arg1,
1002 					   SIPMediaChannel *channel)
1003 {
1004   TpGroupMixin *mixin = TP_GROUP_MIXIN (channel);
1005   SIPMediaSessionState state;
1006   TpHandle peer;
1007   TpIntSet *set;
1008 
1009   DEBUG("enter");
1010 
1011   g_object_get (session,
1012                 "state", &state,
1013                 "peer", &peer,
1014                 NULL);
1015 
1016   if (state == SIP_MEDIA_SESSION_STATE_ACTIVE) {
1017     set = tp_intset_new ();
1018 
1019     /* add the peer to the member list */
1020     tp_intset_add (set, peer);
1021 
1022     tp_group_mixin_change_members ((GObject *)channel,
1023         "", set, NULL, NULL, NULL, 0, 0);
1024 
1025     tp_intset_destroy (set);
1026 
1027     /* update flags accordingly -- allow removal, deny adding and rescinding */
1028     tp_group_mixin_change_flags ((GObject *)channel,
1029 				     TP_CHANNEL_GROUP_FLAG_CAN_REMOVE,
1030 				     TP_CHANNEL_GROUP_FLAG_CAN_ADD |
1031 				     TP_CHANNEL_GROUP_FLAG_CAN_RESCIND);
1032   }
1033   else if (state == SIP_MEDIA_SESSION_STATE_ENDED) {
1034     set = tp_intset_new ();
1035 
1036     /* remove us and the peer from the member list */
1037     tp_intset_add (set, mixin->self_handle);
1038     tp_intset_add (set, peer);
1039     tp_group_mixin_change_members ((GObject *)channel,
1040         "", NULL, set, NULL, NULL, 0, 0);
1041 
1042     tp_intset_destroy (set);
1043 
1044 #if 0
1045     /* update flags accordingly -- allow adding, deny removal */
1046     tp_group_mixin_change_flags ((GObject *)channel,
1047         TP_CHANNEL_GROUP_FLAG_CAN_ADD, TP_CHANNEL_GROUP_FLAG_CAN_REMOVE);
1048 #endif
1049 
1050     priv_destroy_session (channel);
1051     sip_media_channel_close (channel);
1052   }
1053 }
1054 
priv_session_stream_added_cb(SIPMediaSession * session,SIPMediaStream * stream,SIPMediaChannel * chan)1055 static void priv_session_stream_added_cb (SIPMediaSession *session,
1056 					  SIPMediaStream  *stream,
1057 					  SIPMediaChannel *chan)
1058 {
1059   guint id, handle, type;
1060 
1061   DEBUG("enter");
1062 
1063   /* emit StreamAdded */
1064   handle = sip_media_session_get_peer (session);
1065   g_object_get (stream, "id", &id, "media-type", &type, NULL);
1066 
1067   tp_svc_channel_type_streamed_media_emit_stream_added (
1068         (TpSvcChannelTypeStreamedMedia *)chan, id, handle, type);
1069 }
1070 
1071 /**
1072  * priv_create_session:
1073  *
1074  * Creates a SIPMediaSession object for given peer.
1075  **/
1076 static void
priv_create_session(SIPMediaChannel * channel,nua_handle_t * nh,TpHandle peer,gboolean remote_initiated)1077 priv_create_session (SIPMediaChannel *channel,
1078                      nua_handle_t *nh,
1079                      TpHandle peer,
1080                      gboolean remote_initiated)
1081 {
1082   SIPMediaChannelPrivate *priv;
1083   SIPMediaSession *session;
1084   TpBaseConnection *conn;
1085   TpHandleRepoIface *contact_repo;
1086   gchar *object_path;
1087   gchar *local_ip_address = NULL;
1088 
1089   DEBUG("enter");
1090 
1091   priv = SIP_MEDIA_CHANNEL_GET_PRIVATE (channel);
1092   g_assert (priv->session == NULL);
1093   conn = (TpBaseConnection *)(priv->conn);
1094   contact_repo = tp_base_connection_get_handles (conn,
1095       TP_HANDLE_TYPE_CONTACT);
1096 
1097   object_path = g_strdup_printf ("%s/MediaSession%u", priv->object_path, peer);
1098 
1099   DEBUG("allocating session, peer=%u", peer);
1100 
1101   /* The channel manages references to the peer handle for the session */
1102   tp_handle_ref (contact_repo, peer);
1103 
1104   g_object_get (priv->conn,
1105                 "local-ip-address", &local_ip_address,
1106                 NULL);
1107 
1108   session = g_object_new (SIP_TYPE_MEDIA_SESSION,
1109                           "media-channel", channel,
1110                           "object-path", object_path,
1111                           "nua-handle", nh,
1112                           "peer", peer,
1113                           "local-ip-address", local_ip_address,
1114                           NULL);
1115 
1116   g_free (local_ip_address);
1117 
1118   g_signal_connect (session, "notify::state",
1119                     (GCallback) priv_session_state_changed_cb, channel);
1120   g_signal_connect (session, "stream-added",
1121 		    (GCallback) priv_session_stream_added_cb, channel);
1122 
1123   priv->session = session;
1124 
1125   if (remote_initiated)
1126     sip_media_session_receive_invite (session);
1127 
1128   tp_svc_channel_interface_media_signalling_emit_new_session_handler (
1129       (TpSvcChannelInterfaceMediaSignalling *)channel, object_path, "rtp");
1130 
1131   g_free (object_path);
1132 
1133   DEBUG ("exit");
1134 }
1135 
1136 static void
priv_destroy_session(SIPMediaChannel * channel)1137 priv_destroy_session(SIPMediaChannel *channel)
1138 {
1139   SIPMediaChannelPrivate *priv = SIP_MEDIA_CHANNEL_GET_PRIVATE (channel);
1140   SIPMediaSession *session;
1141   TpBaseConnection *conn;
1142   TpHandleRepoIface *contact_repo;
1143 
1144   session = priv->session;
1145   if (session == NULL)
1146     return;
1147 
1148   DEBUG("enter");
1149 
1150   /* Release the peer handle */
1151   conn = (TpBaseConnection *)(priv->conn);
1152   contact_repo = tp_base_connection_get_handles (conn,
1153       TP_HANDLE_TYPE_CONTACT);
1154   tp_handle_unref (contact_repo, sip_media_session_get_peer (session));
1155 
1156   priv->session = NULL;
1157   g_object_unref (session);
1158 
1159   DEBUG("exit");
1160 }
1161 
1162 #if 0
1163 /* Check that self_handle is not already in the members. If it is,
1164  * we're trying to call ourselves. */
1165 static void
1166 priv_add_members (TpSvcChannelInterfaceGroup *obj,
1167                     const GArray *contacts,
1168                     const gchar *message,
1169                     DBusGMethodInvocation *context)
1170 {
1171   TpGroupMixin *mixin = TP_GROUP_MIXIN (obj);
1172   guint i;
1173   TpHandle handle;
1174   GError *error = NULL;
1175 
1176   for (i = 0; i < contacts->len; i++)
1177     {
1178       handle = g_array_index (contacts, TpHandle, i);
1179 
1180       if (handle == mixin->self_handle &&
1181           tp_handle_set_is_member (mixin->members, handle))
1182         {
1183           DEBUG ("attempted to add self_handle into the mixin again");
1184           g_set_error (&error, TP_ERRORS, TP_ERROR_INVALID_HANDLE,
1185             "you cannot call yourself");
1186         }
1187     }
1188 
1189   if (error == NULL)
1190       tp_group_mixin_add_members ((GObject *) obj, contacts, message, &error);
1191 
1192   if (error == NULL)
1193     {
1194       tp_svc_channel_interface_group_return_from_add_members (context);
1195     }
1196   else
1197     {
1198       dbus_g_method_return_error (context, error);
1199       g_error_free (error);
1200     }
1201 }
1202 #endif
1203 
1204 static gboolean
sip_media_channel_add_member(GObject * iface,TpHandle handle,const gchar * message,GError ** error)1205 sip_media_channel_add_member (GObject *iface,
1206                               TpHandle handle,
1207                               const gchar *message,
1208                               GError **error)
1209 {
1210   SIPMediaChannel *self = SIP_MEDIA_CHANNEL (iface);
1211   SIPMediaChannelPrivate *priv = SIP_MEDIA_CHANNEL_GET_PRIVATE (self);
1212   TpGroupMixin *mixin = TP_GROUP_MIXIN (iface);
1213 
1214   DEBUG("mixin->self_handle=%d, handle=%d", mixin->self_handle, handle);
1215 
1216   /* case a: outgoing call (we are the initiator, a new handle added) */
1217   if (mixin->self_handle != handle)
1218     {
1219       TpGroupMixin *mixin = TP_GROUP_MIXIN (self);
1220       TpIntSet *lset, *rset;
1221       nua_handle_t *nh;
1222 
1223       DEBUG("making outbound call - setting peer handle to %u", handle);
1224 
1225       nh = sip_conn_create_request_handle (priv->conn, handle);
1226       priv_create_session (self, nh, handle, FALSE);
1227       nua_handle_unref (nh);
1228 
1229       /* make remote pending */
1230       rset = tp_intset_new ();
1231       lset = tp_intset_new ();
1232       tp_intset_add (lset, mixin->self_handle);
1233       tp_intset_add (rset, handle);
1234       tp_group_mixin_change_members (iface, "Sending INVITE",
1235                                      lset,      /* add */
1236                                      NULL,      /* remove */
1237                                      NULL,      /* local pending */
1238                                      rset,      /* remote pending */
1239                                      0, 0);
1240       tp_intset_destroy (lset);
1241       tp_intset_destroy (rset);
1242 
1243       /* and update flags accordingly */
1244       tp_group_mixin_change_flags (iface,
1245         TP_CHANNEL_GROUP_FLAG_CAN_ADD | TP_CHANNEL_GROUP_FLAG_CAN_REMOVE |
1246         TP_CHANNEL_GROUP_FLAG_CAN_RESCIND,
1247         0);
1248 
1249       return TRUE;
1250     }
1251   /* case b: an incoming invite */
1252   if (tp_handle_set_is_member (mixin->local_pending, handle))
1253     {
1254       TpIntSet *set;
1255 
1256       DEBUG("accepting an incoming invite");
1257 
1258       g_return_val_if_fail (priv->session != NULL, FALSE);
1259 
1260       set = tp_intset_new ();
1261       tp_intset_add (set, handle);
1262       tp_group_mixin_change_members (iface, "Incoming call accepted",
1263                                      set,       /* add */
1264                                      NULL,      /* remove */
1265                                      NULL,      /* local pending */
1266                                      NULL,      /* remote pending */
1267                                      0, 0);
1268       tp_intset_destroy (set);
1269 
1270       sip_media_session_accept (priv->session);
1271 
1272       return TRUE;
1273     }
1274 
1275   /* This can only legitimately happen if the user is trying to call themselves */
1276   g_message ("unsupported member change requested for a media channel");
1277 
1278   g_set_error (error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT,
1279                "Can't call yourself");
1280   return FALSE;
1281 }
1282 
1283 static gint
sip_status_from_tp_reason(TpChannelGroupChangeReason reason)1284 sip_status_from_tp_reason (TpChannelGroupChangeReason reason)
1285 {
1286   switch (reason)
1287     {
1288     case TP_CHANNEL_GROUP_CHANGE_REASON_NONE:
1289       return 603;       /* Decline */
1290     case TP_CHANNEL_GROUP_CHANGE_REASON_NO_ANSWER:
1291     case TP_CHANNEL_GROUP_CHANGE_REASON_OFFLINE:
1292       return 480;       /* Temporarily Unavailable */
1293     case TP_CHANNEL_GROUP_CHANGE_REASON_BUSY:
1294       return 486;       /* Busy Here */
1295     case TP_CHANNEL_GROUP_CHANGE_REASON_PERMISSION_DENIED:
1296     case TP_CHANNEL_GROUP_CHANGE_REASON_BANNED:
1297       return 403;       /* Forbidden */
1298     case TP_CHANNEL_GROUP_CHANGE_REASON_INVALID_CONTACT:
1299       return 404;       /* Not Found */
1300     default:
1301       return 500;       /* Server Internal Error */
1302     }
1303 }
1304 
1305 static gboolean
sip_media_channel_remove_with_reason(GObject * obj,TpHandle handle,const gchar * message,guint reason,GError ** error)1306 sip_media_channel_remove_with_reason (GObject *obj,
1307                                       TpHandle handle,
1308                                       const gchar *message,
1309                                       guint reason,
1310                                       GError **error)
1311 {
1312   SIPMediaChannel *self = SIP_MEDIA_CHANNEL (obj);
1313   SIPMediaChannelPrivate *priv = SIP_MEDIA_CHANNEL_GET_PRIVATE (self);
1314   TpGroupMixin *mixin = TP_GROUP_MIXIN (obj);
1315 
1316   /* We handle only one case: removal of the self handle from local pending
1317    * due to the user rejecting the call */
1318   if (priv->session &&
1319       handle == mixin->self_handle &&
1320       tp_handle_set_is_member (mixin->local_pending, handle))
1321     {
1322       TpIntSet *set;
1323       gint status;
1324 
1325       status = sip_status_from_tp_reason (reason);
1326 
1327       /* XXX: raise NotAvailable if it's the wrong state? */
1328       sip_media_session_reject (priv->session, status, message);
1329 
1330       set = tp_intset_new ();
1331       tp_intset_add (set, handle);
1332       tp_group_mixin_change_members (obj,
1333                                      message,
1334                                      NULL, /* add */
1335                                      set,  /* remove */
1336                                      NULL, /* add local pending */
1337                                      NULL, /* add remote pending */
1338                                      0,    /* actor */
1339                                      reason);
1340       tp_intset_destroy (set);
1341 
1342       /* no more adding to this channel */
1343       tp_group_mixin_change_flags (obj,
1344                                    0,
1345                                    TP_CHANNEL_GROUP_FLAG_CAN_ADD);
1346 
1347       return TRUE;
1348     }
1349 
1350   g_assert_not_reached();
1351 
1352   g_set_error (error, TP_ERRORS, TP_ERROR_NOT_IMPLEMENTED,
1353                "Can't map this member change to protocol behavior");
1354   return FALSE;
1355 }
1356 
1357 static void
sip_media_channel_start_tone(TpSvcChannelInterfaceDTMF * iface,guint stream_id,guchar event,DBusGMethodInvocation * context)1358 sip_media_channel_start_tone (TpSvcChannelInterfaceDTMF *iface,
1359                               guint stream_id,
1360                               guchar event,
1361                               DBusGMethodInvocation *context)
1362 {
1363   SIPMediaChannel *self = SIP_MEDIA_CHANNEL (iface);
1364   SIPMediaChannelPrivate *priv;
1365   GError *error = NULL;
1366 
1367   DEBUG("enter");
1368 
1369   g_assert (SIP_IS_MEDIA_CHANNEL (self));
1370 
1371   if (event >= NUM_TP_DTMF_EVENTS)
1372     {
1373       g_set_error (&error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT,
1374                    "event %u is not a known DTMF event", event);
1375       dbus_g_method_return_error (context, error);
1376       g_error_free (error);
1377       return;
1378     }
1379 
1380   priv = SIP_MEDIA_CHANNEL_GET_PRIVATE (self);
1381 
1382   if (!sip_media_session_start_telephony_event (priv->session,
1383                                                 stream_id,
1384                                                 event,
1385                                                 &error))
1386     {
1387       dbus_g_method_return_error (context, error);
1388       g_error_free (error);
1389       return;
1390     }
1391 
1392   tp_svc_channel_interface_dtmf_return_from_start_tone (context);
1393 }
1394 
1395 static void
sip_media_channel_stop_tone(TpSvcChannelInterfaceDTMF * iface,guint stream_id,DBusGMethodInvocation * context)1396 sip_media_channel_stop_tone (TpSvcChannelInterfaceDTMF *iface,
1397                              guint stream_id,
1398                              DBusGMethodInvocation *context)
1399 {
1400   SIPMediaChannel *self = SIP_MEDIA_CHANNEL (iface);
1401   SIPMediaChannelPrivate *priv;
1402   GError *error = NULL;
1403 
1404   DEBUG("enter");
1405 
1406   g_assert (SIP_IS_MEDIA_CHANNEL (self));
1407 
1408   priv = SIP_MEDIA_CHANNEL_GET_PRIVATE (self);
1409 
1410   if (!sip_media_session_stop_telephony_event (priv->session,
1411                                                stream_id,
1412                                                &error))
1413     {
1414       dbus_g_method_return_error (context, error);
1415       g_error_free (error);
1416       return;
1417     }
1418 
1419   tp_svc_channel_interface_dtmf_return_from_stop_tone (context);
1420 }
1421 
1422 static void
channel_iface_init(gpointer g_iface,gpointer iface_data)1423 channel_iface_init(gpointer g_iface, gpointer iface_data)
1424 {
1425   TpSvcChannelClass *klass = (TpSvcChannelClass *)g_iface;
1426 
1427 #define IMPLEMENT(x, suffix) tp_svc_channel_implement_##x (\
1428     klass, sip_media_channel_##x##suffix)
1429   IMPLEMENT(close,_async);
1430   IMPLEMENT(get_channel_type,);
1431   IMPLEMENT(get_handle,);
1432   IMPLEMENT(get_interfaces,);
1433 #undef IMPLEMENT
1434 }
1435 
1436 static void
streamed_media_iface_init(gpointer g_iface,gpointer iface_data)1437 streamed_media_iface_init(gpointer g_iface, gpointer iface_data)
1438 {
1439   TpSvcChannelTypeStreamedMediaClass *klass = (TpSvcChannelTypeStreamedMediaClass *)g_iface;
1440 
1441 #define IMPLEMENT(x) tp_svc_channel_type_streamed_media_implement_##x (\
1442     klass, sip_media_channel_##x)
1443   IMPLEMENT(list_streams);
1444   IMPLEMENT(remove_streams);
1445   IMPLEMENT(request_stream_direction);
1446   IMPLEMENT(request_streams);
1447 #undef IMPLEMENT
1448 }
1449 
1450 static void
media_signalling_iface_init(gpointer g_iface,gpointer iface_data)1451 media_signalling_iface_init(gpointer g_iface, gpointer iface_data)
1452 {
1453   TpSvcChannelInterfaceMediaSignallingClass *klass = (TpSvcChannelInterfaceMediaSignallingClass *)g_iface;
1454 
1455 #define IMPLEMENT(x) tp_svc_channel_interface_media_signalling_implement_##x (\
1456     klass, sip_media_channel_##x)
1457   IMPLEMENT(get_session_handlers);
1458 #undef IMPLEMENT
1459 }
1460 
1461 static void
dtmf_iface_init(gpointer g_iface,gpointer iface_data)1462 dtmf_iface_init (gpointer g_iface, gpointer iface_data)
1463 {
1464   TpSvcChannelInterfaceDTMFClass *klass = (TpSvcChannelInterfaceDTMFClass *)g_iface;
1465 
1466 #define IMPLEMENT(x) tp_svc_channel_interface_dtmf_implement_##x (\
1467     klass, sip_media_channel_##x)
1468   IMPLEMENT(start_tone);
1469   IMPLEMENT(stop_tone);
1470 #undef IMPLEMENT
1471 }
1472 
1473 static void
priv_group_mixin_iface_init(gpointer g_iface,gpointer iface_data)1474 priv_group_mixin_iface_init (gpointer g_iface, gpointer iface_data)
1475 {
1476 #if 0
1477   TpSvcChannelInterfaceGroupClass *klass =
1478       (TpSvcChannelInterfaceGroupClass *)g_iface;
1479 #endif
1480 
1481   tp_group_mixin_iface_init (g_iface, iface_data);
1482 
1483 #if 0
1484   tp_svc_channel_interface_group_implement_add_members (klass,
1485       priv_add_members);
1486 #endif
1487 }
1488 
1489