2
* call-content.c - Source for TpyCallContent
3
* Copyright © 2009–2011 Collabora Ltd.
4
* @author Emilio Pozuelo Monfort <emilio.pozuelo@collabora.co.uk>
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.
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.
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
21
#include <telepathy-glib/proxy-subclass.h>
23
#include "call-content.h"
25
#define DEBUG_FLAG TPY_DEBUG_CALL
28
#include <telepathy-yell/call-stream.h>
29
#include <telepathy-yell/interfaces.h>
30
#include <telepathy-yell/gtypes.h>
31
#include <telepathy-yell/enums.h>
32
#include <telepathy-yell/cli-call.h>
34
G_DEFINE_TYPE (TpyCallContent, tpy_call_content, TP_TYPE_PROXY)
36
struct _TpyCallContentPrivate
38
const gchar * const *extra_interfaces;
40
TpMediaStreamType media_type;
41
TpyCallContentDisposition disposition;
44
gboolean properties_retrieved;
46
GSimpleAsyncResult *result;
66
static guint _signals[LAST_SIGNAL] = { 0, };
68
static void on_call_content_get_all_properties_cb (TpProxy *proxy,
69
GHashTable *properties,
72
GObject *weak_object);
75
find_stream_for_object_path (gconstpointer a,
78
return g_strcmp0 (tp_proxy_get_object_path ((gpointer) a), b);
82
on_content_removed_cb (TpProxy *proxy,
86
TpyCallContent *self = TPY_CALL_CONTENT (proxy);
88
g_signal_emit (self, _signals[REMOVED], 0);
92
maybe_go_to_ready (TpyCallContent *self)
94
TpyCallContentPrivate *priv = self->priv;
100
if (!priv->properties_retrieved)
104
for (l = priv->streams; l != NULL ; l = g_list_next (l))
106
TpyCallStream *s = l->data;
109
g_object_get (s, "ready", &ready, NULL);
116
g_object_notify (G_OBJECT (self), "ready");
120
on_stream_ready_cb (TpyCallStream *stream,
122
TpyCallContent *self)
124
maybe_go_to_ready (self);
128
add_streams (TpyCallContent *self, const GPtrArray *streams)
130
GPtrArray *object_streams;
133
object_streams = g_ptr_array_sized_new (streams->len);
135
for (i = 0; i < streams->len; i++)
137
TpyCallStream *stream;
138
const gchar *object_path;
140
object_path = g_ptr_array_index (streams, i);
142
stream = g_object_new (TPY_TYPE_CALL_STREAM,
143
"bus-name", tp_proxy_get_bus_name (self),
144
"dbus-daemon", tp_proxy_get_dbus_daemon (self),
145
"dbus-connection", tp_proxy_get_dbus_connection (self),
146
"object-path", object_path,
151
g_warning ("Could not create a CallStream for path %s", object_path);
155
tp_g_signal_connect_object (stream, "notify::ready",
156
G_CALLBACK (on_stream_ready_cb), self, 0);
158
self->priv->streams = g_list_prepend (self->priv->streams, stream);
159
g_ptr_array_add (object_streams, stream);
162
g_signal_emit (self, _signals[STREAMS_ADDED], 0, object_streams);
163
g_ptr_array_unref (object_streams);
167
on_streams_added_cb (TpProxy *proxy,
168
const GPtrArray *streams,
170
GObject *weak_object)
172
TpyCallContent *self = TPY_CALL_CONTENT (proxy);
174
add_streams (self, streams);
178
on_streams_removed_cb (TpProxy *proxy,
179
const GPtrArray *streams,
181
GObject *weak_object)
183
TpyCallContent *self = TPY_CALL_CONTENT (proxy);
184
GPtrArray *object_streams;
187
object_streams = g_ptr_array_sized_new (streams->len);
188
g_ptr_array_set_free_func (object_streams, g_object_unref);
190
for (i = 0; i < streams->len; i++)
193
const gchar *object_path;
195
object_path = g_ptr_array_index (streams, i);
197
s = g_list_find_custom (self->priv->streams,
199
find_stream_for_object_path);
203
g_warning ("Could not find a CallStream for path %s", object_path);
207
self->priv->streams = g_list_remove_link (self->priv->streams, s);
208
g_ptr_array_add (object_streams, s->data);
211
g_signal_emit (self, _signals[STREAMS_REMOVED], 0, object_streams);
213
g_ptr_array_unref (object_streams);
217
tpy_call_content_constructed (GObject *obj)
219
TpyCallContent *self = (TpyCallContent *) obj;
220
GError *error = NULL;
222
((GObjectClass *) tpy_call_content_parent_class)->constructed (obj);
224
tpy_cli_call_content_connect_to_removed (TP_PROXY (self),
225
on_content_removed_cb, NULL, NULL, G_OBJECT (self), &error);
229
g_critical ("Failed to connect to Removed signal: %s",
232
g_error_free (error);
236
tpy_cli_call_content_connect_to_streams_added (TP_PROXY (self),
237
on_streams_added_cb, NULL, NULL, G_OBJECT (self), &error);
241
g_critical ("Failed to connect to StreamsAdded signal: %s",
244
g_error_free (error);
248
tpy_cli_call_content_connect_to_streams_removed (TP_PROXY (self),
249
on_streams_removed_cb, NULL, NULL, G_OBJECT (self), &error);
253
g_critical ("Failed to connect to StreamsRemoved signal: %s",
256
g_error_free (error);
260
tp_cli_dbus_properties_call_get_all (self, -1,
261
TPY_IFACE_CALL_CONTENT,
262
on_call_content_get_all_properties_cb, NULL, NULL, G_OBJECT (self));
266
tpy_call_content_init (TpyCallContent *self)
268
TpyCallContentPrivate *priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
269
TPY_TYPE_CALL_CONTENT, TpyCallContentPrivate);
275
tpy_call_content_dispose (GObject *object)
277
TpyCallContent *self = TPY_CALL_CONTENT (object);
279
tp_clear_pointer (&self->priv->name, g_free);
280
tp_clear_object (&self->priv->result);
282
g_list_free_full (self->priv->streams, g_object_unref);
283
self->priv->streams = NULL;
285
G_OBJECT_CLASS (tpy_call_content_parent_class)->dispose (object);
289
tpy_call_content_get_property (
295
TpyCallContent *self = TPY_CALL_CONTENT (object);
300
g_value_set_string (value, self->priv->name);
302
case PROP_MEDIA_TYPE:
303
g_value_set_uint (value, self->priv->media_type);
305
case PROP_DISPOSITION:
306
g_value_set_uint (value, self->priv->disposition);
309
g_value_set_boxed (value, self->priv->streams);
312
g_value_set_boolean (value, self->priv->ready);
315
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
321
tpy_call_content_set_property (
327
TpyCallContent *self = TPY_CALL_CONTENT (object);
332
g_assert (self->priv->name == NULL);
333
self->priv->name = g_value_dup_string (value);
335
case PROP_MEDIA_TYPE:
336
self->priv->media_type = g_value_get_uint (value);
338
case PROP_DISPOSITION:
339
self->priv->disposition = g_value_get_uint (value);
342
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
348
tpy_call_content_class_init (
349
TpyCallContentClass *klass)
351
GObjectClass *object_class = G_OBJECT_CLASS (klass);
352
TpProxyClass *proxy_class = TP_PROXY_CLASS (klass);
353
GParamSpec *param_spec;
355
g_type_class_add_private (klass, sizeof (TpyCallContentPrivate));
357
object_class->constructed = tpy_call_content_constructed;
358
object_class->dispose = tpy_call_content_dispose;
359
object_class->get_property = tpy_call_content_get_property;
360
object_class->set_property = tpy_call_content_set_property;
362
proxy_class->interface = TPY_IFACE_QUARK_CALL_CONTENT;
364
param_spec = g_param_spec_string ("name", "Name",
365
"The name of this content, if any",
367
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
368
g_object_class_install_property (object_class, PROP_NAME, param_spec);
370
param_spec = g_param_spec_uint ("media-type", "Media Type",
371
"The media type of this content",
373
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
374
g_object_class_install_property (object_class, PROP_MEDIA_TYPE, param_spec);
376
param_spec = g_param_spec_uint ("disposition", "Disposition",
377
"The disposition of this content",
379
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
380
g_object_class_install_property (object_class, PROP_DISPOSITION, param_spec);
382
param_spec = g_param_spec_boxed ("streams", "Stream",
383
"The streams of this content",
384
TP_ARRAY_TYPE_OBJECT_PATH_LIST,
385
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
386
g_object_class_install_property (object_class, PROP_STREAMS,
389
param_spec = g_param_spec_boolean ("ready",
391
"If true the content and all its streams have retrieved all"
392
"all async information from the CM",
394
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
395
g_object_class_install_property (object_class, PROP_READY,
399
* TpyCallContent::removed
400
* @self: the #TpyCallContent
402
* The ::removed signal is emitted when @self is removed from
405
_signals[REMOVED] = g_signal_new ("removed",
406
G_OBJECT_CLASS_TYPE (klass),
409
g_cclosure_marshal_VOID__VOID,
414
* TpyCallContent::streams-added
415
* @self: the #TpyCallContent
416
* @stream: the newly added streams
418
* The ::content-removed signal is emitted whenever
419
* #TpyCallContent are added from @self.
421
_signals[STREAMS_ADDED] = g_signal_new ("streams-added",
422
G_OBJECT_CLASS_TYPE (klass),
425
g_cclosure_marshal_VOID__BOXED,
427
1, G_TYPE_PTR_ARRAY);
430
* TpyCallContent::streams-removed
431
* @self: the #TpyCallContent
432
* @stream: the newly removed streams
434
* The ::content-removed signal is emitted whenever
435
* #TpyCallContent are removed from @self.
437
_signals[STREAMS_REMOVED] = g_signal_new ("streams-removed",
438
G_OBJECT_CLASS_TYPE (klass),
441
g_cclosure_marshal_VOID__BOXED,
443
1, G_TYPE_PTR_ARRAY);
447
tpy_call_content_get_name (TpyCallContent *self)
449
g_return_val_if_fail (TPY_IS_CALL_CONTENT (self), NULL);
451
return self->priv->name;
455
tpy_call_content_get_media_type (TpyCallContent *self)
457
g_return_val_if_fail (TPY_IS_CALL_CONTENT (self),
458
TP_MEDIA_STREAM_TYPE_AUDIO);
460
return self->priv->media_type;
463
TpyCallContentDisposition
464
tpy_call_content_get_disposition (TpyCallContent *self)
466
g_return_val_if_fail (TPY_IS_CALL_CONTENT (self),
467
TPY_CALL_CONTENT_DISPOSITION_NONE);
469
return self->priv->disposition;
473
on_call_content_get_all_properties_cb (TpProxy *proxy,
474
GHashTable *properties,
477
GObject *weak_object)
479
TpyCallContent *self = TPY_CALL_CONTENT (proxy);
484
g_warning ("Could not get the content properties: %s", error->message);
488
self->priv->media_type = tp_asv_get_uint32 (properties, "Type", NULL);
489
g_free (self->priv->name);
490
self->priv->name = g_strdup (tp_asv_get_string (properties, "Name"));
491
self->priv->disposition = tp_asv_get_uint32 (properties, "Disposition",
494
streams = tp_asv_get_boxed (properties, "Streams",
495
TP_ARRAY_TYPE_OBJECT_PATH_LIST);
498
add_streams (self, streams);
500
self->priv->properties_retrieved = TRUE;
501
maybe_go_to_ready (self);
505
on_content_remove_cb (TpProxy *proxy,
508
GObject *weak_object)
510
TpyCallContent *self = TPY_CALL_CONTENT (proxy);
514
DEBUG ("Failed to remove content: %s", error->message);
516
g_simple_async_result_set_from_error (self->priv->result, error);
519
g_simple_async_result_set_op_res_gboolean (self->priv->result, TRUE);
520
g_simple_async_result_complete (self->priv->result);
521
tp_clear_object (&self->priv->result);
525
tpy_call_content_remove_async (TpyCallContent *self,
526
TpyContentRemovalReason reason,
527
const gchar *detailed_removal_reason,
528
const gchar *message,
529
GAsyncReadyCallback callback,
532
DEBUG ("removing content for reason %u, detailed reason: %s, message: %s",
533
reason, detailed_removal_reason, message);
535
tpy_cli_call_content_call_remove (TP_PROXY (self), -1,
536
reason, detailed_removal_reason, message,
537
on_content_remove_cb, NULL, NULL, G_OBJECT (self));
541
tpy_call_content_remove_finish (TpyCallContent *self,
542
GAsyncResult *result,
545
if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result),
549
g_return_val_if_fail (g_simple_async_result_is_valid (result,
550
G_OBJECT (self), tpy_call_content_remove_async),
553
return g_simple_async_result_get_op_res_gboolean (
554
G_SIMPLE_ASYNC_RESULT (result));
558
tpy_call_content_get_streams (TpyCallContent *self)
560
return self->priv->streams;