]> git.0d.be Git - empathy.git/blob - src/empathy-call-factory.c
Port to new tp-glib client factory
[empathy.git] / src / empathy-call-factory.c
1 /*
2  * empathy-call-factory.c - Source for EmpathyCallFactory
3  * Copyright (C) 2008 Collabora Ltd.
4  * @author Sjoerd Simons <sjoerd.simons@collabora.co.uk>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  */
20
21
22 #include <stdio.h>
23 #include <stdlib.h>
24
25 #include <telepathy-glib/account-channel-request.h>
26 #include <telepathy-glib/simple-handler.h>
27 #include <telepathy-glib/interfaces.h>
28 #include <telepathy-glib/util.h>
29
30 #include <telepathy-yell/telepathy-yell.h>
31
32 #include <libempathy/empathy-request-util.h>
33 #include <libempathy/empathy-tp-contact-factory.h>
34 #include <libempathy/empathy-utils.h>
35
36 #include "empathy-call-factory.h"
37 #include "empathy-call-handler.h"
38 #include "src-marshal.h"
39
40 #define DEBUG_FLAG EMPATHY_DEBUG_VOIP
41 #include <libempathy/empathy-debug.h>
42
43 G_DEFINE_TYPE(EmpathyCallFactory, empathy_call_factory, G_TYPE_OBJECT)
44
45 static void handle_channels_cb (TpSimpleHandler *handler,
46     TpAccount *account,
47     TpConnection *connection,
48     GList *channels,
49     GList *requests_satisfied,
50     gint64 user_action_time,
51     TpHandleChannelsContext *context,
52     gpointer user_data);
53
54 /* signal enum */
55 enum
56 {
57     NEW_CALL_HANDLER,
58     LAST_SIGNAL
59 };
60
61 static guint signals[LAST_SIGNAL] = {0};
62
63 /* private structure */
64 typedef struct {
65   TpBaseClient *handler;
66   gboolean dispose_has_run;
67 } EmpathyCallFactoryPriv;
68
69 #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyCallFactory)
70
71 static GObject *call_factory = NULL;
72
73 static void
74 empathy_call_factory_init (EmpathyCallFactory *obj)
75 {
76   EmpathyCallFactoryPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (obj,
77     EMPATHY_TYPE_CALL_FACTORY, EmpathyCallFactoryPriv);
78   TpAccountManager *am;
79
80   obj->priv = priv;
81
82   am = tp_account_manager_dup ();
83
84   priv->handler = tp_simple_handler_new_with_am (am, FALSE, FALSE,
85       EMPATHY_CALL_BUS_NAME_SUFFIX, FALSE, handle_channels_cb, obj, NULL);
86
87   tp_base_client_take_handler_filter (priv->handler, tp_asv_new (
88         TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING,
89           TPY_IFACE_CHANNEL_TYPE_CALL,
90         TP_PROP_CHANNEL_TARGET_HANDLE_TYPE,
91           G_TYPE_UINT, TP_HANDLE_TYPE_CONTACT,
92         NULL));
93
94   tp_base_client_take_handler_filter (priv->handler, tp_asv_new (
95         TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING,
96           TPY_IFACE_CHANNEL_TYPE_CALL,
97         TP_PROP_CHANNEL_TARGET_HANDLE_TYPE,
98           G_TYPE_UINT, TP_HANDLE_TYPE_CONTACT,
99         TPY_PROP_CHANNEL_TYPE_CALL_INITIAL_AUDIO, G_TYPE_BOOLEAN, TRUE,
100         NULL));
101
102   tp_base_client_take_handler_filter (priv->handler, tp_asv_new (
103         TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING,
104           TPY_IFACE_CHANNEL_TYPE_CALL,
105         TP_PROP_CHANNEL_TARGET_HANDLE_TYPE,
106           G_TYPE_UINT, TP_HANDLE_TYPE_CONTACT,
107         TPY_PROP_CHANNEL_TYPE_CALL_INITIAL_VIDEO, G_TYPE_BOOLEAN, TRUE,
108         NULL));
109
110   tp_base_client_add_handler_capabilities_varargs (priv->handler,
111     "org.freedesktop.Telepathy.Channel.Interface.MediaSignalling/ice-udp",
112     "org.freedesktop.Telepathy.Channel.Interface.MediaSignalling/gtalk-p2p",
113     "org.freedesktop.Telepathy.Channel.Interface.MediaSignalling/video/h264",
114     NULL);
115
116   g_object_unref (am);
117 }
118
119 static GObject *
120 empathy_call_factory_constructor (GType type, guint n_construct_params,
121   GObjectConstructParam *construct_params)
122 {
123   g_return_val_if_fail (call_factory == NULL, NULL);
124
125   call_factory = G_OBJECT_CLASS (empathy_call_factory_parent_class)->constructor
126           (type, n_construct_params, construct_params);
127   g_object_add_weak_pointer (call_factory, (gpointer)&call_factory);
128
129   return call_factory;
130 }
131
132 static void
133 empathy_call_factory_finalize (GObject *object)
134 {
135   /* free any data held directly by the object here */
136
137   if (G_OBJECT_CLASS (empathy_call_factory_parent_class)->finalize)
138     G_OBJECT_CLASS (empathy_call_factory_parent_class)->finalize (object);
139 }
140
141 static void
142 empathy_call_factory_dispose (GObject *object)
143 {
144   EmpathyCallFactoryPriv *priv = GET_PRIV (object);
145
146   if (priv->dispose_has_run)
147     return;
148
149   priv->dispose_has_run = TRUE;
150
151   tp_clear_object (&priv->handler);
152
153   if (G_OBJECT_CLASS (empathy_call_factory_parent_class)->dispose)
154     G_OBJECT_CLASS (empathy_call_factory_parent_class)->dispose (object);
155 }
156
157 static void
158 empathy_call_factory_class_init (
159   EmpathyCallFactoryClass *empathy_call_factory_class)
160 {
161   GObjectClass *object_class = G_OBJECT_CLASS (empathy_call_factory_class);
162
163   g_type_class_add_private (empathy_call_factory_class,
164     sizeof (EmpathyCallFactoryPriv));
165
166   object_class->constructor = empathy_call_factory_constructor;
167   object_class->dispose = empathy_call_factory_dispose;
168   object_class->finalize = empathy_call_factory_finalize;
169
170   signals[NEW_CALL_HANDLER] =
171     g_signal_new ("new-call-handler",
172       G_TYPE_FROM_CLASS (empathy_call_factory_class),
173       G_SIGNAL_RUN_LAST, 0,
174       NULL, NULL,
175       _src_marshal_VOID__OBJECT_BOOLEAN,
176       G_TYPE_NONE,
177       2, EMPATHY_TYPE_CALL_HANDLER, G_TYPE_BOOLEAN);
178 }
179
180 EmpathyCallFactory *
181 empathy_call_factory_initialise (void)
182 {
183   g_return_val_if_fail (call_factory == NULL, NULL);
184
185   return EMPATHY_CALL_FACTORY (g_object_new (EMPATHY_TYPE_CALL_FACTORY, NULL));
186 }
187
188 EmpathyCallFactory *
189 empathy_call_factory_get (void)
190 {
191   g_return_val_if_fail (call_factory != NULL, NULL);
192
193   return EMPATHY_CALL_FACTORY (call_factory);
194 }
195
196 static void
197 call_channel_got_contact (TpConnection *connection,
198   EmpathyContact *contact,
199   const GError *error,
200   gpointer user_data,
201   GObject *weak_object)
202 {
203   EmpathyCallFactory *factory = EMPATHY_CALL_FACTORY (weak_object);
204   EmpathyCallHandler *handler;
205   TpyCallChannel *call = TPY_CALL_CHANNEL (user_data);
206
207   if (contact == NULL)
208     {
209       /* FIXME use hangup with an appropriate error */
210       tp_channel_close_async (TP_CHANNEL (call), NULL, NULL);
211       return;
212     }
213
214   handler = empathy_call_handler_new_for_channel (call, contact);
215
216   g_signal_emit (factory, signals[NEW_CALL_HANDLER], 0,
217     handler, FALSE);
218
219   g_object_unref (handler);
220 }
221
222 static void
223 call_channel_ready (EmpathyCallFactory *factory,
224   TpyCallChannel *call)
225 {
226   TpChannel *channel = TP_CHANNEL (call);
227   const gchar *id;
228
229   id = tp_channel_get_identifier (channel);
230
231   /* The ready callback has a reference, so pass that on */
232   empathy_tp_contact_factory_get_from_id (
233     tp_channel_borrow_connection (channel),
234     id,
235     call_channel_got_contact,
236     channel,
237     g_object_unref,
238     (GObject *) factory);
239 }
240
241 static void
242 call_channel_ready_cb (TpyCallChannel *call,
243   GParamSpec *spec,
244   EmpathyCallFactory *factory)
245 {
246   gboolean ready;
247
248   g_object_get (call, "ready", &ready, NULL);
249   if (!ready)
250     return;
251
252   call_channel_ready (factory, call);
253 }
254
255
256 static void
257 handle_channels_cb (TpSimpleHandler *handler,
258     TpAccount *account,
259     TpConnection *connection,
260     GList *channels,
261     GList *requests_satisfied,
262     gint64 user_action_time,
263     TpHandleChannelsContext *context,
264     gpointer user_data)
265 {
266   EmpathyCallFactory *self = user_data;
267   GList *l;
268
269   for (l = channels; l != NULL; l = g_list_next (l))
270     {
271       TpChannel *channel = l->data;
272       TpyCallChannel *call;
273       gboolean ready;
274
275       if (tp_proxy_get_invalidated (channel) != NULL)
276         continue;
277
278       if (tp_channel_get_channel_type_id (channel) !=
279           TPY_IFACE_QUARK_CHANNEL_TYPE_CALL)
280         continue;
281
282       if (!TPY_IS_CALL_CHANNEL (channel))
283         continue;
284
285       call = TPY_CALL_CHANNEL (channel);
286
287       /* Take a ref to keep while hopping through the async callbacks */
288       g_object_ref (call);
289       g_object_get (call, "ready", &ready, NULL);
290
291       if (!ready)
292         tp_g_signal_connect_object (call, "notify::ready",
293           G_CALLBACK (call_channel_ready_cb), self, 0);
294       else
295         call_channel_ready (self, call);
296     }
297
298   tp_handle_channels_context_accept (context);
299 }
300
301 gboolean
302 empathy_call_factory_register (EmpathyCallFactory *self,
303     GError **error)
304 {
305   EmpathyCallFactoryPriv *priv = GET_PRIV (self);
306
307   return tp_base_client_register (priv->handler, error);
308 }