2
* base-call-content.c - Source for TpyBaseCallContent
3
* Copyright © 2009–2010 Collabora Ltd.
4
* @author Sjoerd Simons <sjoerd.simons@collabora.co.uk>
5
* @author Will Thompson <will.thompson@collabora.co.uk>
7
* This library is free software; you can redistribute it and/or
8
* modify it under the terms of the GNU Lesser General Public
9
* License as published by the Free Software Foundation; either
10
* version 2.1 of the License, or (at your option) any later version.
12
* This library is distributed in the hope that it will be useful,
13
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
* Lesser General Public License for more details.
17
* You should have received a copy of the GNU Lesser General Public
18
* License along with this library; if not, write to the Free Software
19
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22
#include "base-call-content.h"
24
#include "base-call-stream.h"
26
#define DEBUG_FLAG TPY_DEBUG_CALL
29
#include <telepathy-yell/interfaces.h>
30
#include <telepathy-yell/gtypes.h>
31
#include <telepathy-yell/enums.h>
32
#include <telepathy-yell/svc-call.h>
34
static void call_content_iface_init (gpointer g_iface, gpointer iface_data);
36
G_DEFINE_TYPE_WITH_CODE(TpyBaseCallContent, tpy_base_call_content,
38
G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_DBUS_PROPERTIES,
39
tp_dbus_properties_mixin_iface_init);
40
G_IMPLEMENT_INTERFACE (TPY_TYPE_SVC_CALL_CONTENT,
41
call_content_iface_init);
44
struct _TpyBaseCallContentPrivate
46
TpBaseConnection *conn;
47
TpDBusDaemon *dbus_daemon;
52
TpMediaStreamType media_type;
54
TpyCallContentDisposition disposition;
58
gboolean dispose_has_run;
59
gboolean deinit_has_run;
75
static void base_call_content_deinit_real (TpyBaseCallContent *self);
78
tpy_base_call_content_init (TpyBaseCallContent *self)
80
TpyBaseCallContentPrivate *priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
81
TPY_TYPE_BASE_CALL_CONTENT, TpyBaseCallContentPrivate);
87
tpy_base_call_content_constructed (GObject *obj)
89
TpyBaseCallContent *self = TPY_BASE_CALL_CONTENT (obj);
90
TpyBaseCallContentPrivate *priv = self->priv;
92
if (G_OBJECT_CLASS (tpy_base_call_content_parent_class)->constructed != NULL)
93
G_OBJECT_CLASS (tpy_base_call_content_parent_class)->constructed (obj);
95
DEBUG ("Registering %s", priv->object_path);
96
priv->dbus_daemon = g_object_ref (
97
tp_base_connection_get_dbus_daemon ((TpBaseConnection *) priv->conn));
98
tp_dbus_daemon_register_object (priv->dbus_daemon, priv->object_path, obj);
102
tpy_base_call_content_dispose (GObject *object)
104
TpyBaseCallContent *self = TPY_BASE_CALL_CONTENT (object);
105
TpyBaseCallContentPrivate *priv = self->priv;
108
if (priv->dispose_has_run)
111
priv->dispose_has_run = TRUE;
113
for (l = priv->streams; l != NULL; l = g_list_next (l))
114
g_object_unref (l->data);
116
tp_clear_pointer (&priv->streams, g_list_free);
117
tp_clear_object (&priv->conn);
119
if (G_OBJECT_CLASS (tpy_base_call_content_parent_class)->dispose != NULL)
120
G_OBJECT_CLASS (tpy_base_call_content_parent_class)->dispose (object);
124
tpy_base_call_content_finalize (GObject *object)
126
TpyBaseCallContent *self = TPY_BASE_CALL_CONTENT (object);
127
TpyBaseCallContentPrivate *priv = self->priv;
129
/* free any data held directly by the object here */
130
g_free (priv->object_path);
133
G_OBJECT_CLASS (tpy_base_call_content_parent_class)->finalize (object);
137
tpy_base_call_content_get_property (
143
TpyBaseCallContent *content = TPY_BASE_CALL_CONTENT (object);
144
TpyBaseCallContentPrivate *priv = content->priv;
148
case PROP_OBJECT_PATH:
149
g_value_set_string (value, priv->object_path);
151
case PROP_CONNECTION:
152
g_value_set_object (value, priv->conn);
154
case PROP_INTERFACES:
156
TpyBaseCallContentClass *klass =
157
TPY_BASE_CALL_CONTENT_GET_CLASS (content);
159
if (klass->extra_interfaces != NULL)
161
g_value_set_boxed (value, klass->extra_interfaces);
165
static gchar *empty[] = { NULL };
167
g_value_set_boxed (value, empty);
172
g_value_set_string (value, priv->name);
174
case PROP_MEDIA_TYPE:
175
g_value_set_uint (value, priv->media_type);
178
g_value_set_uint (value, priv->creator);
180
case PROP_DISPOSITION:
181
g_value_set_uint (value, priv->disposition);
185
GPtrArray *arr = g_ptr_array_sized_new (2);
188
for (l = priv->streams; l != NULL; l = g_list_next (l))
190
TpyBaseCallStream *s = TPY_BASE_CALL_STREAM (l->data);
191
g_ptr_array_add (arr,
192
g_strdup (tpy_base_call_stream_get_object_path (s)));
195
g_value_take_boxed (value, arr);
199
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
205
tpy_base_call_content_set_property (
211
TpyBaseCallContent *content = TPY_BASE_CALL_CONTENT (object);
212
TpyBaseCallContentPrivate *priv = content->priv;
216
case PROP_OBJECT_PATH:
217
priv->object_path = g_value_dup_string (value);
218
g_assert (priv->object_path != NULL);
220
case PROP_CONNECTION:
221
priv->conn = g_value_dup_object (value);
224
priv->name = g_value_dup_string (value);
226
case PROP_MEDIA_TYPE:
227
priv->media_type = g_value_get_uint (value);
230
priv->creator = g_value_get_uint (value);
232
case PROP_DISPOSITION:
233
priv->disposition = g_value_get_uint (value);
236
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
242
tpy_base_call_content_class_init (
243
TpyBaseCallContentClass *bcc_class)
245
GObjectClass *object_class = G_OBJECT_CLASS (bcc_class);
246
GParamSpec *param_spec;
247
static TpDBusPropertiesMixinPropImpl content_props[] = {
248
{ "Interfaces", "interfaces", NULL },
249
{ "Name", "name", NULL },
250
{ "Type", "media-type", NULL },
251
{ "Disposition", "disposition", NULL },
252
{ "Streams", "streams", NULL },
255
static TpDBusPropertiesMixinIfaceImpl prop_interfaces[] = {
256
{ TPY_IFACE_CALL_CONTENT,
257
tp_dbus_properties_mixin_getter_gobject_properties,
264
g_type_class_add_private (bcc_class, sizeof (TpyBaseCallContentPrivate));
266
object_class->constructed = tpy_base_call_content_constructed;
267
object_class->dispose = tpy_base_call_content_dispose;
268
object_class->finalize = tpy_base_call_content_finalize;
269
object_class->get_property = tpy_base_call_content_get_property;
270
object_class->set_property = tpy_base_call_content_set_property;
272
param_spec = g_param_spec_string ("object-path", "D-Bus object path",
273
"The D-Bus object path used for this object on the bus.",
275
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
276
g_object_class_install_property (object_class, PROP_OBJECT_PATH, param_spec);
278
param_spec = g_param_spec_object ("connection", "TpBaseConnection object",
279
"Tp base connection object that owns this call content",
280
TP_TYPE_BASE_CONNECTION,
281
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
282
g_object_class_install_property (object_class, PROP_CONNECTION, param_spec);
284
param_spec = g_param_spec_boxed ("interfaces", "Extra D-Bus interfaces",
285
"Additional interfaces implemented by this content",
287
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
288
g_object_class_install_property (object_class, PROP_INTERFACES, param_spec);
290
param_spec = g_param_spec_string ("name", "Name",
291
"The name of this content, if any",
293
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
294
g_object_class_install_property (object_class, PROP_NAME, param_spec);
296
param_spec = g_param_spec_uint ("media-type", "Media Type",
297
"The media type of this content",
299
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
300
g_object_class_install_property (object_class, PROP_MEDIA_TYPE, param_spec);
302
param_spec = g_param_spec_uint ("creator", "Creator",
303
"The creator of this content",
305
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
306
g_object_class_install_property (object_class, PROP_CREATOR, param_spec);
308
param_spec = g_param_spec_uint ("disposition", "Disposition",
309
"The disposition of this content",
311
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
312
g_object_class_install_property (object_class, PROP_DISPOSITION, param_spec);
314
param_spec = g_param_spec_boxed ("streams", "Stream",
315
"The streams of this content",
316
TP_ARRAY_TYPE_OBJECT_PATH_LIST,
317
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
318
g_object_class_install_property (object_class, PROP_STREAMS,
321
bcc_class->dbus_props_class.interfaces = prop_interfaces;
322
tp_dbus_properties_mixin_class_init (object_class,
323
G_STRUCT_OFFSET (TpyBaseCallContentClass, dbus_props_class));
325
bcc_class->deinit = base_call_content_deinit_real;
329
tpy_base_call_content_get_connection (TpyBaseCallContent *self)
331
g_return_val_if_fail (TPY_IS_BASE_CALL_CONTENT (self), NULL);
333
return self->priv->conn;
337
tpy_base_call_content_get_object_path (TpyBaseCallContent *self)
339
g_return_val_if_fail (TPY_IS_BASE_CALL_CONTENT (self), NULL);
341
return self->priv->object_path;
345
tpy_base_call_content_get_name (TpyBaseCallContent *self)
347
g_return_val_if_fail (TPY_IS_BASE_CALL_CONTENT (self), NULL);
349
return self->priv->name;
353
tpy_base_call_content_get_media_type (TpyBaseCallContent *self)
355
g_return_val_if_fail (TPY_IS_BASE_CALL_CONTENT (self),
356
TP_MEDIA_STREAM_TYPE_AUDIO);
358
return self->priv->media_type;
361
TpyCallContentDisposition
362
tpy_base_call_content_get_disposition (TpyBaseCallContent *self)
364
g_return_val_if_fail (TPY_IS_BASE_CALL_CONTENT (self),
365
TPY_CALL_CONTENT_DISPOSITION_NONE);
367
return self->priv->disposition;
371
tpy_base_call_content_get_streams (TpyBaseCallContent *self)
373
g_return_val_if_fail (TPY_IS_BASE_CALL_CONTENT (self), NULL);
375
return self->priv->streams;
379
tpy_base_call_content_add_stream (TpyBaseCallContent *self,
380
TpyBaseCallStream *stream)
384
g_return_if_fail (TPY_IS_BASE_CALL_CONTENT (self));
386
self->priv->streams = g_list_prepend (self->priv->streams,
387
g_object_ref (stream));
389
paths = g_ptr_array_new_with_free_func ((GDestroyNotify) g_free);
391
g_ptr_array_add (paths, g_strdup (
392
tpy_base_call_stream_get_object_path (
393
TPY_BASE_CALL_STREAM (stream))));
394
tpy_svc_call_content_emit_streams_added (self, paths);
395
g_ptr_array_unref (paths);
399
tpy_base_call_content_remove_stream (TpyBaseCallContent *self,
400
TpyBaseCallStream *stream)
402
TpyBaseCallContentPrivate *priv;
406
g_return_if_fail (TPY_IS_BASE_CALL_CONTENT (self));
410
l = g_list_find (priv->streams, stream);
411
g_return_if_fail (l != NULL);
413
priv->streams = g_list_remove_link (priv->streams, l);
414
paths = g_ptr_array_new_with_free_func ((GDestroyNotify) g_free);
415
g_ptr_array_add (paths, g_strdup (
416
tpy_base_call_stream_get_object_path (
417
TPY_BASE_CALL_STREAM (stream))));
418
tpy_svc_call_content_emit_streams_removed (self, paths);
419
g_ptr_array_unref (paths);
420
g_object_unref (stream);
424
base_call_content_deinit_real (TpyBaseCallContent *self)
426
TpyBaseCallContentPrivate *priv = self->priv;
428
if (priv->deinit_has_run)
431
priv->deinit_has_run = TRUE;
433
tp_dbus_daemon_unregister_object (priv->dbus_daemon, G_OBJECT (self));
434
tp_clear_object (&priv->dbus_daemon);
436
g_list_foreach (priv->streams, (GFunc) g_object_unref, NULL);
437
tp_clear_pointer (&priv->streams, g_list_free);
441
tpy_base_call_content_deinit (TpyBaseCallContent *self)
443
TpyBaseCallContentClass *klass;
445
g_return_if_fail (TPY_IS_BASE_CALL_CONTENT (self));
447
klass = TPY_BASE_CALL_CONTENT_GET_CLASS (self);
448
g_return_if_fail (klass->deinit != NULL);
449
klass->deinit (self);
453
tpy_base_call_content_accepted (TpyBaseCallContent *self)
455
TpyBaseCallContentPrivate *priv = self->priv;
458
if (priv->disposition != TPY_CALL_CONTENT_DISPOSITION_INITIAL)
461
for (l = priv->streams ; l != NULL; l = g_list_next (l))
463
TpyBaseCallStream *s = TPY_BASE_CALL_STREAM (l->data);
465
if (tpy_base_call_stream_get_local_sending_state (s) ==
466
TPY_SENDING_STATE_PENDING_SEND)
467
tpy_base_call_stream_set_sending (s, TRUE, NULL);
472
tpy_call_content_remove (TpySvcCallContent *content,
473
TpyContentRemovalReason reason,
474
const gchar *detailed_removal_reason,
475
const gchar *message,
476
DBusGMethodInvocation *context)
478
/* TODO: actually do something with this reason and message. */
479
DEBUG ("removing content for reason %u, dbus error: %s, message: %s",
480
reason, detailed_removal_reason, message);
482
tpy_svc_call_content_emit_removed (content);
483
/* it doesn't matter if a ::removed signal handler calls deinit as
484
* there are guards around it being called again and breaking, so
485
* let's just call it be sure it's done. */
486
tpy_base_call_content_deinit (TPY_BASE_CALL_CONTENT (content));
487
tpy_svc_call_content_return_from_remove (context);
491
call_content_iface_init (gpointer g_iface, gpointer iface_data)
493
TpySvcCallContentClass *klass =
494
(TpySvcCallContentClass *) g_iface;
496
#define IMPLEMENT(x) tpy_svc_call_content_implement_##x (\
497
klass, tpy_call_content_##x)