2
* base-call-stream.c - Source for TpyBaseCallStream
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-stream.h"
24
#define DEBUG_FLAG TPY_DEBUG_CALL
27
#include <telepathy-yell/interfaces.h>
28
#include <telepathy-yell/gtypes.h>
29
#include <telepathy-yell/svc-call.h>
31
static void call_stream_iface_init (gpointer g_iface, gpointer iface_data);
33
G_DEFINE_TYPE_WITH_CODE(TpyBaseCallStream, tpy_base_call_stream,
35
G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_DBUS_PROPERTIES,
36
tp_dbus_properties_mixin_iface_init);
37
G_IMPLEMENT_INTERFACE (TPY_TYPE_SVC_CALL_STREAM, call_stream_iface_init);
45
/* Call interface properties */
48
PROP_LOCAL_SENDING_STATE,
49
PROP_CAN_REQUEST_RECEIVING,
52
struct _TpyBaseCallStreamPrivate
54
gboolean dispose_has_run;
57
TpBaseConnection *conn;
59
GHashTable *remote_members;
61
TpySendingState local_sending_state;
65
tpy_base_call_stream_init (TpyBaseCallStream *self)
67
TpyBaseCallStreamPrivate *priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
68
TPY_TYPE_BASE_CALL_STREAM, TpyBaseCallStreamPrivate);
71
priv->remote_members = g_hash_table_new (g_direct_hash, g_direct_equal);
75
tpy_base_call_stream_constructed (GObject *obj)
77
TpyBaseCallStream *self = TPY_BASE_CALL_STREAM (obj);
78
TpyBaseCallStreamPrivate *priv = self->priv;
79
TpDBusDaemon *bus = tp_base_connection_get_dbus_daemon (
80
(TpBaseConnection *) priv->conn);
82
if (G_OBJECT_CLASS (tpy_base_call_stream_parent_class)->constructed
84
G_OBJECT_CLASS (tpy_base_call_stream_parent_class)->constructed (obj);
86
priv->local_sending_state = TPY_SENDING_STATE_NONE;
88
/* register object on the bus */
89
DEBUG ("Registering %s", priv->object_path);
90
tp_dbus_daemon_register_object (bus, priv->object_path, obj);
94
tpy_base_call_stream_dispose (GObject *object)
96
TpyBaseCallStream *self = TPY_BASE_CALL_STREAM (object);
97
TpyBaseCallStreamPrivate *priv = self->priv;
99
if (priv->dispose_has_run)
102
priv->dispose_has_run = TRUE;
104
tp_clear_object (&priv->conn);
106
if (G_OBJECT_CLASS (tpy_base_call_stream_parent_class)->dispose != NULL)
107
G_OBJECT_CLASS (tpy_base_call_stream_parent_class)->dispose (object);
111
tpy_base_call_stream_finalize (GObject *object)
113
TpyBaseCallStream *self = TPY_BASE_CALL_STREAM (object);
114
TpyBaseCallStreamPrivate *priv = self->priv;
116
/* free any data held directly by the object here */
117
g_free (priv->object_path);
118
g_hash_table_destroy (priv->remote_members);
120
if (G_OBJECT_CLASS (tpy_base_call_stream_parent_class)->finalize != NULL)
121
G_OBJECT_CLASS (tpy_base_call_stream_parent_class)->finalize (object);
125
tpy_base_call_stream_get_property (
131
TpyBaseCallStream *self = TPY_BASE_CALL_STREAM (object);
132
TpyBaseCallStreamPrivate *priv = self->priv;
136
case PROP_CONNECTION:
137
g_value_set_object (value, priv->conn);
139
case PROP_OBJECT_PATH:
140
g_value_set_string (value, priv->object_path);
142
case PROP_REMOTE_MEMBERS:
143
g_value_set_boxed (value, priv->remote_members);
145
case PROP_LOCAL_SENDING_STATE:
146
g_value_set_uint (value, priv->local_sending_state);
148
case PROP_CAN_REQUEST_RECEIVING:
150
TpyBaseCallStreamClass *klass =
151
TPY_BASE_CALL_STREAM_GET_CLASS (self);
153
g_value_set_boolean (value, klass->request_receiving != NULL);
156
case PROP_INTERFACES:
158
TpyBaseCallStreamClass *klass =
159
TPY_BASE_CALL_STREAM_GET_CLASS (self);
161
if (klass->extra_interfaces != NULL)
163
g_value_set_boxed (value, klass->extra_interfaces);
167
gchar *empty[] = { NULL };
169
g_value_set_boxed (value, empty);
174
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
180
tpy_base_call_stream_set_property (
186
TpyBaseCallStream *self = TPY_BASE_CALL_STREAM (object);
187
TpyBaseCallStreamPrivate *priv = self->priv;
191
case PROP_CONNECTION:
192
priv->conn = g_value_dup_object (value);
193
g_assert (priv->conn != NULL);
195
case PROP_OBJECT_PATH:
196
g_free (priv->object_path);
197
priv->object_path = g_value_dup_string (value);
199
case PROP_LOCAL_SENDING_STATE:
200
self->priv->local_sending_state = g_value_get_uint (value);
203
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
209
tpy_base_call_stream_class_init (TpyBaseCallStreamClass *bsc_class)
211
GObjectClass *object_class = G_OBJECT_CLASS (bsc_class);
212
GParamSpec *param_spec;
213
static TpDBusPropertiesMixinPropImpl stream_props[] = {
214
{ "Interfaces", "interfaces", NULL },
215
{ "RemoteMembers", "remote-members", NULL },
216
{ "LocalSendingState", "local-sending-state", NULL },
217
{ "CanRequestReceiving", "can-request-receiving", NULL },
220
static TpDBusPropertiesMixinIfaceImpl prop_interfaces[] = {
221
{ TPY_IFACE_CALL_STREAM,
222
tp_dbus_properties_mixin_getter_gobject_properties,
229
g_type_class_add_private (bsc_class, sizeof (TpyBaseCallStreamPrivate));
231
object_class->constructed = tpy_base_call_stream_constructed;
232
object_class->dispose = tpy_base_call_stream_dispose;
233
object_class->finalize = tpy_base_call_stream_finalize;
234
object_class->set_property = tpy_base_call_stream_set_property;
235
object_class->get_property = tpy_base_call_stream_get_property;
237
param_spec = g_param_spec_object ("connection", "TpBaseConnection object",
238
"Tpy connection object that owns this call stream",
239
TP_TYPE_BASE_CONNECTION,
240
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
241
g_object_class_install_property (object_class, PROP_CONNECTION, param_spec);
243
param_spec = g_param_spec_string ("object-path", "D-Bus object path",
244
"The D-Bus object path used for this "
245
"object on the bus.",
247
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
248
g_object_class_install_property (object_class, PROP_OBJECT_PATH, param_spec);
250
param_spec = g_param_spec_boxed ("interfaces", "Interfaces",
253
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
254
g_object_class_install_property (object_class, PROP_INTERFACES,
257
param_spec = g_param_spec_boxed ("remote-members", "Remote members",
259
TPY_HASH_TYPE_CONTACT_SENDING_STATE_MAP,
260
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
261
g_object_class_install_property (object_class, PROP_REMOTE_MEMBERS,
264
param_spec = g_param_spec_uint ("local-sending-state", "LocalSendingState",
265
"Local sending state",
266
0, NUM_TPY_SENDING_STATES, 0,
267
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
268
g_object_class_install_property (object_class, PROP_LOCAL_SENDING_STATE,
271
param_spec = g_param_spec_boolean ("can-request-receiving",
272
"CanRequestReceiving",
273
"If true, the user can request that a remote contact starts sending on"
276
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
277
g_object_class_install_property (object_class, PROP_CAN_REQUEST_RECEIVING,
280
bsc_class->dbus_props_class.interfaces = prop_interfaces;
281
tp_dbus_properties_mixin_class_init (object_class,
282
G_STRUCT_OFFSET (TpyBaseCallStreamClass, dbus_props_class));
286
tpy_base_call_stream_get_connection (TpyBaseCallStream *self)
288
g_return_val_if_fail (TPY_IS_BASE_CALL_STREAM (self), NULL);
290
return self->priv->conn;
294
tpy_base_call_stream_get_object_path (TpyBaseCallStream *self)
296
g_return_val_if_fail (TPY_IS_BASE_CALL_STREAM (self), NULL);
298
return self->priv->object_path;
302
_remote_member_update_state (TpyBaseCallStream *self,
304
TpySendingState state)
306
TpyBaseCallStreamPrivate *priv = self->priv;
307
gpointer state_p = 0;
310
exists = g_hash_table_lookup_extended (priv->remote_members,
311
GUINT_TO_POINTER (contact),
315
if (exists && GPOINTER_TO_UINT (state_p) == state)
318
DEBUG ("Updating remote member %d state: %d => %d", contact,
319
GPOINTER_TO_UINT (state_p), state);
321
g_hash_table_insert (priv->remote_members,
322
GUINT_TO_POINTER (contact),
323
GUINT_TO_POINTER (state));
329
tpy_base_call_stream_update_remote_member_states (TpyBaseCallStream *self,
330
TpHandle peer, TpySendingState remote_state,
333
GHashTable *updates = g_hash_table_new (g_direct_hash, g_direct_equal);
334
gboolean updated = FALSE;
337
va_start (args, remote_state);
341
if (_remote_member_update_state (self, peer, remote_state))
343
g_hash_table_insert (updates,
344
GUINT_TO_POINTER (peer),
345
GUINT_TO_POINTER (remote_state));
349
peer = va_arg (args, TpHandle);
351
remote_state = va_arg (args, TpySendingState);
357
GArray *empty = g_array_new (FALSE, TRUE, sizeof (TpHandle));
359
tpy_svc_call_stream_emit_remote_members_changed (self, updates, empty);
360
g_array_unref (empty);
363
g_hash_table_unref (updates);
368
tpy_base_call_stream_remove_member (TpyBaseCallStream *self,
371
GArray *removed_array;
374
if (!g_hash_table_remove (self->priv->remote_members,
375
GUINT_TO_POINTER(removed)))
378
empty= g_hash_table_new (g_direct_hash, g_direct_equal);
379
removed_array = g_array_sized_new (FALSE, TRUE, sizeof (TpHandle), 1);
380
g_array_append_val (removed_array, removed);
382
tpy_svc_call_stream_emit_remote_members_changed (self, empty, removed_array);
384
g_hash_table_unref (empty);
385
g_array_free (removed_array, TRUE);
390
tpy_base_call_stream_get_local_sending_state (
391
TpyBaseCallStream *self)
393
return self->priv->local_sending_state;
397
tpy_base_call_stream_update_local_sending_state (TpyBaseCallStream *self,
398
TpySendingState state)
400
TpyBaseCallStreamPrivate *priv = self->priv;
402
if (priv->local_sending_state == state)
405
priv->local_sending_state = state;
406
g_object_notify (G_OBJECT (self), "local-sending-state");
408
tpy_svc_call_stream_emit_local_sending_state_changed (
409
TPY_SVC_CALL_STREAM (self), state);
415
tpy_base_call_stream_set_sending (TpyBaseCallStream *self,
419
TpyBaseCallStreamPrivate *priv = self->priv;
420
TpyBaseCallStreamClass *klass = TPY_BASE_CALL_STREAM_GET_CLASS (self);
422
/* Determine if there is a state change for our sending side */
423
switch (priv->local_sending_state)
425
case TPY_SENDING_STATE_NONE:
426
case TPY_SENDING_STATE_PENDING_SEND:
430
case TPY_SENDING_STATE_SENDING:
431
case TPY_SENDING_STATE_PENDING_STOP_SENDING:
436
g_assert_not_reached ();
439
if (klass->set_sending != NULL)
441
if (!klass->set_sending (self, send, error))
446
g_set_error_literal (error, TP_ERRORS, TP_ERROR_NOT_IMPLEMENTED,
447
"This CM does not implement SetSending");
452
tpy_base_call_stream_update_local_sending_state (self,
453
send ? TPY_SENDING_STATE_SENDING : TPY_SENDING_STATE_NONE);
461
tpy_base_call_stream_set_sending_dbus (TpySvcCallStream *iface,
463
DBusGMethodInvocation *context)
465
GError *error = NULL;
467
if (tpy_base_call_stream_set_sending (TPY_BASE_CALL_STREAM (iface),
469
tpy_svc_call_stream_return_from_set_sending (context);
471
dbus_g_method_return_error (context, error);
473
g_clear_error (&error);
477
tpy_base_call_stream_request_receiving (TpySvcCallStream *iface,
480
DBusGMethodInvocation *context)
482
GError *error = NULL;
483
TpyBaseCallStream *self = TPY_BASE_CALL_STREAM (iface);
484
TpyBaseCallStreamClass *klass = TPY_BASE_CALL_STREAM_GET_CLASS (self);
486
if (klass->request_receiving != NULL)
487
klass->request_receiving (self, handle, receiving, &error);
489
g_set_error_literal (&error, TP_ERRORS, TP_ERROR_NOT_IMPLEMENTED,
490
"This CM does not implement request_receiving");
493
dbus_g_method_return_error (context, error);
495
tpy_svc_call_stream_return_from_request_receiving (context);
497
g_clear_error (&error);
501
call_stream_iface_init (gpointer g_iface, gpointer iface_data)
503
TpySvcCallStreamClass *klass =
504
(TpySvcCallStreamClass *) g_iface;
506
#define IMPLEMENT(x, suffix) tpy_svc_call_stream_implement_##x (\
507
klass, tpy_base_call_stream_##x##suffix)
508
IMPLEMENT(set_sending, _dbus);
509
IMPLEMENT(request_receiving,);