summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicolas Dufresne <nicolas.dufresne@collabora.co.uk>2011-02-07 18:23:02 +0100
committerNicolas Dufresne <nicolas.dufresne@collabora.co.uk>2011-03-25 14:03:03 -0400
commit7f2f8ff8762e098f049ec90c50cba4520c2d0a01 (patch)
tree8ed4352206c76176b27e858ae1bbfda5198a9985
parent8d2e6cecb2c07bfecb40095519192d65cbc89707 (diff)
Add TplStreamMediaChannel legacy call observer
-rw-r--r--data/Logger.client4
-rw-r--r--src/telepathy-logger.c6
-rw-r--r--telepathy-logger/Makefile.am2
-rw-r--r--telepathy-logger/observer.c9
-rw-r--r--telepathy-logger/streamed-media-channel-internal.h62
-rw-r--r--telepathy-logger/streamed-media-channel.c647
6 files changed, 730 insertions, 0 deletions
diff --git a/data/Logger.client b/data/Logger.client
index 8d96113..a28d298 100644
--- a/data/Logger.client
+++ b/data/Logger.client
@@ -9,5 +9,9 @@ org.freedesktop.Telepathy.Channel.TargetHandleType u=1
org.freedesktop.Telepathy.Channel.ChannelType s=org.freedesktop.Telepathy.Channel.Type.Text
org.freedesktop.Telepathy.Channel.TargetHandleType u=2
+[org.freedesktop.Telepathy.Client.Observer.ObserverChannelFilter 2]
+org.freedesktop.Telepathy.Channel.ChannelType s=org.freedesktop.Telepathy.Channel.Type.StreamedMedia
+org.freedesktop.Telepathy.Channel.TargetHandleType u=1
+
[org.freedesktop.Telepathy.Client.Observer]
Recover=true
diff --git a/src/telepathy-logger.c b/src/telepathy-logger.c
index 6e86753..3e9b42f 100644
--- a/src/telepathy-logger.c
+++ b/src/telepathy-logger.c
@@ -29,6 +29,7 @@
#include <telepathy-logger/text-channel-internal.h>
#include <telepathy-logger/observer-internal.h>
#include <telepathy-logger/dbus-service-internal.h>
+#include <telepathy-logger/streamed-media-channel-internal.h>
#define DEBUG_FLAG TPL_DEBUG_MAIN
#include <telepathy-logger/debug-internal.h>
@@ -168,10 +169,15 @@ main (int argc,
_tpl_channel_factory_init ();
DEBUG ("Initialising TPL Channel Factory");
+
_tpl_channel_factory_add ("org.freedesktop.Telepathy.Channel.Type.Text",
(TplChannelConstructor) _tpl_text_channel_new);
DEBUG ("- TplTextChannel registered.");
+ _tpl_channel_factory_add ("org.freedesktop.Telepathy.Channel.Type.StreamedMedia",
+ (TplChannelConstructor) _tpl_streamed_media_channel_new);
+ DEBUG ("- TplStreamedMediaChannel registered.");
+
observer = _tpl_observer_new ();
DEBUG ("Registering channel factory into TplObserver");
_tpl_observer_set_channel_factory (observer, _tpl_channel_factory_build);
diff --git a/telepathy-logger/Makefile.am b/telepathy-logger/Makefile.am
index 9382acb..657002d 100644
--- a/telepathy-logger/Makefile.am
+++ b/telepathy-logger/Makefile.am
@@ -75,6 +75,8 @@ libtelepathy_logger_la_SOURCES = \
log-store-factory-internal.h \
observer.c \
observer-internal.h \
+ streamed-media-channel.c \
+ streamed-media-channel-internal.h \
text-channel.c \
text-channel-internal.h \
text-event.c \
diff --git a/telepathy-logger/observer.c b/telepathy-logger/observer.c
index 2645e08..4110c25 100644
--- a/telepathy-logger/observer.c
+++ b/telepathy-logger/observer.c
@@ -380,6 +380,15 @@ _tpl_observer_init (TplObserver *self)
TP_HANDLE_TYPE_ROOM,
NULL));
+ /* Observe contact stream media channels */
+ tp_base_client_take_observer_filter (TP_BASE_CLIENT (self),
+ tp_asv_new (
+ TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING,
+ TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA,
+ TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, G_TYPE_UINT,
+ TP_HANDLE_TYPE_CONTACT,
+ NULL));
+
tp_base_client_set_observer_recover (TP_BASE_CLIENT (self), TRUE);
}
diff --git a/telepathy-logger/streamed-media-channel-internal.h b/telepathy-logger/streamed-media-channel-internal.h
new file mode 100644
index 0000000..c61f63d
--- /dev/null
+++ b/telepathy-logger/streamed-media-channel-internal.h
@@ -0,0 +1,62 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2009-2011 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Emilio Pozuelo Monfort <emilio.pozuelo@collabora.co.uk>
+ * Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+ */
+
+#ifndef __TPL_STREAMED_MEDIA_CHANNEL_H__
+#define __TPL_STREAMED_MEDIA_CHANNEL_H__
+
+#include <glib-object.h>
+#include <telepathy-glib/telepathy-glib.h>
+
+#include <telepathy-logger/channel-internal.h>
+
+G_BEGIN_DECLS
+#define TPL_TYPE_STREAMED_MEDIA_CHANNEL (_tpl_streamed_media_channel_get_type ())
+#define TPL_STREAMED_MEDIA_CHANNEL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TPL_TYPE_STREAMED_MEDIA_CHANNEL, TplStreamedMediaChannel))
+#define TPL_STREAMED_MEDIA_CHANNEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TPL_TYPE_STREAMED_MEDIA_CHANNEL, TplStreamedMediaChannelClass))
+#define TPL_IS_CHANNEL_STREAMED_MEDIA(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TPL_TYPE_STREAMED_MEDIA_CHANNEL))
+#define TPL_IS_CHANNEL_STREAMED_MEDIA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TPL_TYPE_STREAMED_MEDIA_CHANNEL))
+#define TPL_STREAMED_MEDIA_CHANNEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TPL_TYPE_STREAMED_MEDIA_CHANNEL, TplStreamedMediaChannelClass))
+
+typedef struct _TplStreamedMediaChannelPriv TplStreamedMediaChannelPriv;
+typedef struct
+{
+ TpChannel parent;
+
+ /* private */
+ TplStreamedMediaChannelPriv *priv;
+} TplStreamedMediaChannel;
+
+typedef struct
+{
+ TpChannelClass parent_class;
+} TplStreamedMediaChannelClass;
+
+GType _tpl_streamed_media_channel_get_type (void);
+
+TplStreamedMediaChannel * _tpl_streamed_media_channel_new (TpConnection *conn,
+ const gchar *object_path,
+ GHashTable *tp_chan_props,
+ TpAccount *account,
+ GError **error);
+
+G_END_DECLS
+#endif /* __TPL_STREAMED_MEDIA_CHANNEL_H__ */
diff --git a/telepathy-logger/streamed-media-channel.c b/telepathy-logger/streamed-media-channel.c
new file mode 100644
index 0000000..b7e469d
--- /dev/null
+++ b/telepathy-logger/streamed-media-channel.c
@@ -0,0 +1,647 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2009-2011 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Emilio Pozuelo Monfort <emilio.pozuelo@collabora.co.uk>
+ * Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+ */
+
+#include "config.h"
+#include "streamed-media-channel-internal.h"
+
+#include <glib.h>
+#include <telepathy-glib/telepathy-glib.h>
+
+#include "action-chain-internal.h"
+#include "call-event.h"
+#include "call-event-internal.h"
+#include "channel-internal.h"
+#include "entity-internal.h"
+#include "event-internal.h"
+#include "log-manager-internal.h"
+#include "observer-internal.h"
+#include "util-internal.h"
+
+#define DEBUG_FLAG TPL_DEBUG_CHANNEL
+#include "debug-internal.h"
+
+
+typedef enum
+{
+ PENDING_INITIATOR_STATE,
+ PENDING_RECEIVER_STATE,
+ ACCEPTED_STATE,
+ ENDED_STATE,
+} CallState;
+
+struct _TplStreamedMediaChannelPriv
+{
+ TpAccount *account;
+ TplEntity *sender;
+ TplEntity *receiver;
+ GDateTime *timestamp;
+ GTimer *timer;
+ gboolean timer_started;
+ CallState state;
+ TplEntity *end_actor;
+ TplCallEndReason end_reason;
+ const gchar *detailed_end_reason;
+};
+
+static TpContactFeature features[3] = {
+ TP_CONTACT_FEATURE_ALIAS,
+ TP_CONTACT_FEATURE_PRESENCE,
+ TP_CONTACT_FEATURE_AVATAR_TOKEN
+};
+
+static void tpl_streamed_media_channel_iface_init (TplChannelInterface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (TplStreamedMediaChannel, _tpl_streamed_media_channel,
+ TP_TYPE_CHANNEL,
+ G_IMPLEMENT_INTERFACE (TPL_TYPE_CHANNEL, tpl_streamed_media_channel_iface_init))
+
+
+static void
+proxy_prepared_cb (GObject *source,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ TplActionChain *ctx = user_data;
+ GError *error = NULL;
+
+ if (!tp_proxy_prepare_finish (source, result, &error))
+ {
+ _tpl_action_chain_terminate (ctx, error);
+ g_error_free (error);
+ return;
+ }
+
+ _tpl_action_chain_continue (ctx);
+}
+
+
+static void
+pendingproc_prepare_tp_connection (TplActionChain *ctx,
+ gpointer user_data)
+{
+ TplStreamedMediaChannel *chan = _tpl_action_chain_get_object (ctx);
+ TpConnection *conn = tp_channel_borrow_connection (TP_CHANNEL (chan));
+ GQuark conn_features[] = { TP_CONNECTION_FEATURE_CORE, 0 };
+
+ tp_proxy_prepare_async (conn, conn_features, proxy_prepared_cb, ctx);
+}
+
+
+static void
+pendingproc_prepare_tp_channel (TplActionChain *ctx,
+ gpointer user_data)
+{
+ TplStreamedMediaChannel *chan = _tpl_action_chain_get_object (ctx);
+ GQuark chan_features[] = {
+ TP_CHANNEL_FEATURE_CORE,
+ TP_CHANNEL_FEATURE_GROUP,
+ 0
+ };
+
+ tp_proxy_prepare_async (chan, chan_features, proxy_prepared_cb, ctx);
+}
+
+
+static void
+get_remote_contact_cb (TpConnection *connection,
+ guint n_contacts,
+ TpContact *const *contacts,
+ guint n_failed,
+ const TpHandle *failed,
+ const GError *error,
+ gpointer user_data,
+ GObject *weak_object)
+{
+ TplStreamedMediaChannel *self = TPL_STREAMED_MEDIA_CHANNEL (weak_object);
+ TplActionChain *ctx = user_data;
+ TplEntity *remote;
+
+ if (error != NULL)
+ {
+ _tpl_action_chain_terminate (ctx, error);
+ return;
+ }
+
+ remote = tpl_entity_new_from_tp_contact (contacts[0], TPL_ENTITY_CONTACT);
+
+ if (tp_channel_get_requested (TP_CHANNEL (self)))
+ self->priv->receiver = remote;
+ else
+ self->priv->sender = remote;
+
+ _tpl_action_chain_continue (ctx);
+}
+
+
+static void
+pendingproc_get_remote_contacts (TplActionChain *ctx,
+ gpointer user_data)
+{
+ TplStreamedMediaChannel *self = _tpl_action_chain_get_object (ctx);
+ TpChannel *chan = TP_CHANNEL (self);
+ TpConnection *tp_conn = tp_channel_borrow_connection (chan);
+ GArray *arr;
+ TpHandle handle;
+
+ arr = g_array_sized_new (FALSE, FALSE, sizeof (TpHandle), 1);
+ handle = tp_channel_get_handle (chan, NULL);
+ g_array_append_val (arr, handle);
+
+ tp_connection_get_contacts_by_handle (tp_conn,
+ arr->len, (TpHandle *) arr->data,
+ G_N_ELEMENTS (features), features, get_remote_contact_cb, ctx, NULL,
+ G_OBJECT (self));
+
+ g_array_free (arr, TRUE);
+}
+
+
+static void
+get_self_contact_cb (TpConnection *connection,
+ guint n_contacts,
+ TpContact *const *contacts,
+ guint n_failed,
+ const TpHandle *failed,
+ const GError *error,
+ gpointer user_data,
+ GObject *weak_object)
+{
+ TplActionChain *ctx = user_data;
+ TplStreamedMediaChannel *tpl_media = _tpl_action_chain_get_object (ctx);
+ TplChannel *tpl_chan = TPL_CHANNEL (tpl_media);
+ TpChannel *tp_chan = TP_CHANNEL (tpl_chan);
+ TplEntity *self;
+
+ g_return_if_fail (TPL_IS_CHANNEL_STREAMED_MEDIA (tpl_media));
+
+ if (n_failed > 0)
+ {
+ TpConnection *tp_conn = tp_channel_borrow_connection (tp_chan);
+ const gchar *conn_path;
+ GError *new_error = NULL;
+
+ conn_path = tp_proxy_get_object_path (TP_PROXY (tp_conn));
+
+ new_error = g_error_new (error->domain, error->code,
+ "Error resolving self handle for connection %s: %s)",
+ conn_path, error->message);
+
+ _tpl_action_chain_terminate (ctx, error);
+ g_error_free (new_error);
+ return;
+ }
+
+ self = tpl_entity_new_from_tp_contact (contacts[0], TPL_ENTITY_SELF);
+
+ if (tp_channel_get_requested (tp_chan))
+ tpl_media->priv->sender = self;
+ else
+ tpl_media->priv->receiver = self;
+
+ _tpl_action_chain_continue (ctx);
+}
+
+
+
+static void
+pendingproc_get_local_contact (TplActionChain *ctx,
+ gpointer user_data)
+{
+ TplStreamedMediaChannel *tpl_media = _tpl_action_chain_get_object (ctx);
+ TpChannel *chan = TP_CHANNEL (tpl_media);
+ TpConnection *tp_conn = tp_channel_borrow_connection (chan);
+ TpHandle my_handle;
+
+ my_handle = tp_channel_group_get_self_handle (chan);
+ if (my_handle == 0)
+ my_handle = tp_connection_get_self_handle (tp_conn);
+
+ tp_connection_get_contacts_by_handle (tp_conn, 1, &my_handle,
+ G_N_ELEMENTS (features), features, get_self_contact_cb, ctx, NULL,
+ G_OBJECT (tpl_media));
+}
+
+
+static void
+on_group_members_changed_cb (TpChannel *chan,
+ gchar *message,
+ GArray *added,
+ GArray *removed,
+ GArray *local_pending,
+ GArray *remote_pending,
+ TpHandle actor,
+ guint reason,
+ gpointer user_data)
+{
+ TplStreamedMediaChannelPriv *priv = TPL_STREAMED_MEDIA_CHANNEL (user_data)->priv;
+ TpHandle *added_handles = (TpHandle *) added->data;
+ TpHandle initiator, self, receiver;
+ guint i;
+
+ const gchar *reasons[] = {
+ "Unknown",
+ "User Requested",
+ "No Answer"
+ };
+
+ initiator = tp_channel_get_initiator_handle (chan);
+ self = tp_channel_group_get_self_handle (chan);
+
+ if (tp_channel_get_requested (chan))
+ receiver = tp_channel_get_handle (chan, NULL);
+ else
+ receiver = self;
+
+ g_return_if_fail (receiver != 0);
+
+ switch (priv->state)
+ {
+ case PENDING_INITIATOR_STATE:
+ /* Check if initiator was added */
+ for (i = 0; i < added->len; i++)
+ {
+ if (added_handles[i] == initiator)
+ {
+ priv->state = PENDING_RECEIVER_STATE;
+ i = added->len;
+ DEBUG ("StreamedMediaChannel Moving to PENDING_RECEIVER_STATE");
+ }
+ }
+ if (priv->state != PENDING_RECEIVER_STATE)
+ break;
+
+ case PENDING_RECEIVER_STATE:
+ for (i = 0; i < added->len; i++)
+ {
+ if (added_handles[i] == receiver)
+ {
+ priv->state = ACCEPTED_STATE;
+ i = added->len;
+ g_timer_start (priv->timer);
+ priv->timer_started = TRUE;
+ DEBUG ("StreamedMediaChannel Moving to ACCEPTED_STATE, start_time=%li",
+ time (NULL));
+ }
+ }
+ break;
+
+ default:
+ /* nothing to do */
+ break;
+ }
+
+ /* If call is not ending we are done */
+ if (priv->state == PENDING_INITIATOR_STATE
+ || tp_intset_size (tp_channel_group_get_members (chan)) != 0)
+ return;
+
+ if (actor == receiver)
+ priv->end_actor = g_object_ref (priv->receiver);
+ else
+ priv->end_actor = g_object_ref (priv->sender);
+
+ switch (reason)
+ {
+ case TP_CHANNEL_GROUP_CHANGE_REASON_NONE:
+ /* This detailed reason may be changed based on the current
+ * call state */
+ priv->detailed_end_reason = "";
+ break;
+
+ case TP_CHANNEL_GROUP_CHANGE_REASON_OFFLINE:
+ priv->detailed_end_reason = TP_ERROR_STR_OFFLINE;
+ break;
+
+ case TP_CHANNEL_GROUP_CHANGE_REASON_KICKED:
+ priv->detailed_end_reason = TP_ERROR_STR_CHANNEL_KICKED;
+ break;
+
+ case TP_CHANNEL_GROUP_CHANGE_REASON_BUSY:
+ priv->detailed_end_reason = TP_ERROR_STR_BUSY;
+ break;
+
+ case TP_CHANNEL_GROUP_CHANGE_REASON_BANNED:
+ priv->detailed_end_reason = TP_ERROR_STR_CHANNEL_BANNED;
+ break;
+
+ case TP_CHANNEL_GROUP_CHANGE_REASON_ERROR:
+ priv->detailed_end_reason = TP_ERROR_STR_NETWORK_ERROR;
+ break;
+
+ case TP_CHANNEL_GROUP_CHANGE_REASON_INVALID_CONTACT:
+ priv->detailed_end_reason = TP_ERROR_STR_DOES_NOT_EXIST;
+ break;
+
+ case TP_CHANNEL_GROUP_CHANGE_REASON_NO_ANSWER:
+ priv->detailed_end_reason = TP_ERROR_STR_NO_ANSWER;
+ break;
+
+ case TP_CHANNEL_GROUP_CHANGE_REASON_PERMISSION_DENIED:
+ priv->detailed_end_reason = TP_ERROR_STR_PERMISSION_DENIED;
+ break;
+
+ default:
+ g_warning ("Invalid change reason for StreamMedia call ending: %i",
+ reason);
+ priv->detailed_end_reason = TP_ERROR_STR_INVALID_ARGUMENT;
+ break;
+ }
+
+ switch (priv->state)
+ {
+ case PENDING_RECEIVER_STATE:
+ /* Workaround missing rejected reason. A call is rejected when the
+ * receiver terminates that call before accepting it, and no other
+ * reason was provided. Also, even if the call was not answered, the
+ * spec enforces that the end_reason must be user_requested */
+ if (reason == TP_CHANNEL_GROUP_CHANGE_REASON_NONE
+ && actor == receiver)
+ {
+ priv->end_reason = TPL_CALL_END_REASON_USER_REQUESTED;
+ priv->detailed_end_reason = TP_ERROR_STR_REJECTED;
+ }
+ else
+ priv->end_reason = TPL_CALL_END_REASON_NO_ANSWER;
+ break;
+
+ case ACCEPTED_STATE:
+ priv->end_reason = TPL_CALL_END_REASON_USER_REQUESTED;
+
+ if (reason == TP_CHANNEL_GROUP_CHANGE_REASON_NONE)
+ {
+ /* If the SelfHandle is removed from a group for this reason and the
+ * actor is not the SelfHandle, the equivalent D-Bus error is
+ * org.freedesktop.Telepathy.Error.Terminated. If the SelfHandle is
+ * removed from a group for this reason and the actor is also the
+ * SelfHandle, the equivalent D-Bus error is
+ * org.freedesktop.Telepathy.Error.Cancelled. */
+ if (actor != self)
+ priv->detailed_end_reason = TP_ERROR_STR_TERMINATED;
+ else
+ priv->detailed_end_reason = TP_ERROR_STR_CANCELLED;
+ }
+ break;
+
+ default:
+ /* somethings wrong */
+ priv->end_reason = TPL_CALL_END_REASON_UNKNOWN;
+ break;
+ }
+
+ priv->state = ENDED_STATE;
+
+ g_timer_stop (priv->timer);
+
+ DEBUG (
+ "Moving to ENDED_STATE, duration=%" G_GINT64_FORMAT " reason=%s details=%s",
+ (gint64) (priv->timer_started ? g_timer_elapsed (priv->timer, NULL) : -1),
+ reasons[priv->end_reason],
+ priv->detailed_end_reason);
+}
+
+
+static void
+store_call (TplStreamedMediaChannel *self)
+{
+ TplStreamedMediaChannelPriv *priv = self->priv;
+ GError *error = NULL;
+ TplCallEvent *call_log;
+ TplLogManager *logmanager;
+ const gchar *channel_path = tp_proxy_get_object_path (TP_PROXY (self));
+ GTimeSpan duration = -1;
+
+ if (priv->timer_started)
+ duration = g_timer_elapsed (priv->timer, NULL);
+
+ if (priv->end_actor == NULL)
+ priv->end_actor = tpl_entity_new ("unknown", TPL_ENTITY_UNKNOWN, NULL, NULL);
+
+ if (priv->detailed_end_reason == NULL)
+ priv->detailed_end_reason = "";
+
+ /* Initialize data for TplEntity */
+ call_log = g_object_new (TPL_TYPE_CALL_EVENT,
+ /* TplEvent */
+ "account", priv->account,
+ "channel-path", channel_path,
+ "receiver", priv->receiver,
+ "sender", priv->sender,
+ "timestamp", g_date_time_to_unix (priv->timestamp),
+ /* TplCallEvent */
+ "duration", duration,
+ "end-actor", priv->end_actor,
+ "end-reason", priv->end_reason,
+ "detailed-end-reason", priv->detailed_end_reason,
+ NULL);
+
+ logmanager = tpl_log_manager_dup_singleton ();
+ _tpl_log_manager_add_event (logmanager, TPL_EVENT (call_log), &error);
+
+ if (error != NULL)
+ {
+ PATH_DEBUG (self, "StreamedMediaChannel: %s", error->message);
+ g_error_free (error);
+ }
+
+ g_object_unref (logmanager);
+ g_object_unref (call_log);
+}
+
+
+static void
+on_channel_invalidated_cb (TpProxy *proxy,
+ guint domain,
+ gint code,
+ gchar *message,
+ gpointer user_data)
+{
+ TplChannel *tpl_chan = TPL_CHANNEL (user_data);
+ TplObserver *observer = _tpl_observer_new ();
+
+ PATH_DEBUG (tpl_chan, "%s #%d %s",
+ g_quark_to_string (domain), code, message);
+
+ store_call (TPL_STREAMED_MEDIA_CHANNEL (user_data));
+
+ if (!_tpl_observer_unregister_channel (observer, tpl_chan))
+ PATH_DEBUG (tpl_chan, "Channel couldn't be unregistered correctly (BUG?)");
+
+ g_object_unref (observer);
+}
+
+
+static void
+tpl_streamed_media_channel_prepare_async (TplChannel *chan,
+ GAsyncReadyCallback cb,
+ gpointer user_data)
+{
+ TplActionChain *actions;
+
+ actions = _tpl_action_chain_new_async (G_OBJECT (chan), cb, user_data);
+ _tpl_action_chain_append (actions, pendingproc_prepare_tp_connection, NULL);
+ _tpl_action_chain_append (actions, pendingproc_prepare_tp_channel, NULL);
+ _tpl_action_chain_append (actions, pendingproc_get_remote_contacts, NULL);
+ _tpl_action_chain_append (actions, pendingproc_get_local_contact, NULL);
+
+ _tpl_action_chain_continue (actions);
+}
+
+
+static gboolean
+tpl_streamed_media_channel_prepare_finish (TplChannel *chan,
+ GAsyncResult *result,
+ GError **error)
+{
+ return _tpl_action_chain_new_finish (G_OBJECT (chan), result, error);
+}
+
+
+static void
+tpl_streamed_media_channel_dispose (GObject *obj)
+{
+ TplStreamedMediaChannelPriv *priv = TPL_STREAMED_MEDIA_CHANNEL (obj)->priv;
+
+ tp_clear_object (&priv->account);
+ tp_clear_object (&priv->sender);
+ tp_clear_object (&priv->receiver);
+ tp_clear_pointer (&priv->timestamp, g_date_time_unref);
+ tp_clear_pointer (&priv->timer, g_timer_destroy);
+ tp_clear_object (&priv->end_actor);
+
+ G_OBJECT_CLASS (_tpl_streamed_media_channel_parent_class)->dispose (obj);
+}
+
+
+static void
+tpl_streamed_media_channel_finalize (GObject *obj)
+{
+ PATH_DEBUG (obj, "finalizing channel %p", obj);
+
+ G_OBJECT_CLASS (_tpl_streamed_media_channel_parent_class)->finalize (obj);
+}
+
+
+static void
+_tpl_streamed_media_channel_class_init (TplStreamedMediaChannelClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->dispose = tpl_streamed_media_channel_dispose;
+ object_class->finalize = tpl_streamed_media_channel_finalize;
+
+ g_type_class_add_private (object_class, sizeof (TplStreamedMediaChannelPriv));
+}
+
+
+static void
+tpl_streamed_media_channel_iface_init (TplChannelInterface *iface)
+{
+ iface->prepare_async = tpl_streamed_media_channel_prepare_async;
+ iface->prepare_finish = tpl_streamed_media_channel_prepare_finish;
+}
+
+
+static void
+_tpl_streamed_media_channel_init (TplStreamedMediaChannel *self)
+{
+ gchar *date;
+
+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
+ TPL_TYPE_STREAMED_MEDIA_CHANNEL, TplStreamedMediaChannelPriv);
+
+ self->priv->timestamp = g_date_time_new_now_utc ();
+ self->priv->timer = g_timer_new ();
+ self->priv->state = PENDING_INITIATOR_STATE;
+
+ date = g_date_time_format (self->priv->timestamp, "%Y-%m-%d %H:%M:%S");
+ DEBUG ("New call, timestamp=%s UTC", date);
+ g_free (date);
+
+ tp_g_signal_connect_object (TP_CHANNEL (self), "group-members-changed",
+ G_CALLBACK (on_group_members_changed_cb), self, 0);
+
+ tp_g_signal_connect_object (TP_CHANNEL (self), "invalidated",
+ G_CALLBACK (on_channel_invalidated_cb), self, 0);
+}
+
+
+/**
+ * _tpl_streamed_media_channel_new
+ * @conn: TpConnection instance owning the channel
+ * @object_path: the channel's DBus path
+ * @tp_chan_props: channel's immutable properties, obtained for example by
+ * %tp_channel_borrow_immutable_properties()
+ * @account: TpAccount instance, related to the new #TplStreamedMediaChannel
+ * @error: location of the GError, used in case a problem is raised while
+ * creating the channel
+ *
+ * Convenience function to create a new TPL Streamed Media Channel proxy.
+ * The returned #TplStreamedMediaChannel is not guaranteed to be ready
+ * at the point of return.
+ *
+ * TplStreamedMediaChannel is actually a subclass of #TpChannel implementing
+ * TplChannel interface. Use #TpChannel methods, casting the
+ * #TplStreamedMediaChannel instance to a TpChannel, to access TpChannel
+ * data/methods from it.
+ *
+ * TplStreamedMediaChannel is usually created using
+ * #tpl_channel_factory_build, from within a #TplObserver singleton,
+ * when its Observer_Channel method is called by the Channel Dispatcher.
+ *
+ * Returns: the TplStreamedMediaChannel instance or %NULL if
+ * @object_path is not valid.
+ */
+TplStreamedMediaChannel *
+_tpl_streamed_media_channel_new (TpConnection *conn,
+ const gchar *object_path,
+ GHashTable *tp_chan_props,
+ TpAccount *account,
+ GError **error)
+{
+ TpProxy *conn_proxy = TP_PROXY (conn);
+ TplStreamedMediaChannel *self;
+
+ /* Do what tpl_channel_new does + set TplStreamedMediaChannel
+ * specific properties */
+
+ g_return_val_if_fail (TP_IS_CONNECTION (conn), NULL);
+ g_return_val_if_fail (TP_IS_ACCOUNT (account), NULL);
+ g_return_val_if_fail (!TPL_STR_EMPTY (object_path), NULL);
+ g_return_val_if_fail (tp_chan_props != NULL, NULL);
+
+ if (!tp_dbus_check_valid_object_path (object_path, error))
+ return NULL;
+
+ self = g_object_new (TPL_TYPE_STREAMED_MEDIA_CHANNEL,
+ /* TpChannel properties */
+ "connection", conn,
+ "dbus-daemon", conn_proxy->dbus_daemon,
+ "bus-name", conn_proxy->bus_name,
+ "object-path", object_path,
+ "handle-type", (guint) TP_UNKNOWN_HANDLE_TYPE,
+ "channel-properties", tp_chan_props,
+ NULL);
+
+ self->priv->account = g_object_ref (account);
+
+ return self;
+}