diff options
author | Nicolas Dufresne <nicolas.dufresne@collabora.co.uk> | 2011-02-07 18:23:02 +0100 |
---|---|---|
committer | Nicolas Dufresne <nicolas.dufresne@collabora.co.uk> | 2011-03-25 14:03:03 -0400 |
commit | 7f2f8ff8762e098f049ec90c50cba4520c2d0a01 (patch) | |
tree | 8ed4352206c76176b27e858ae1bbfda5198a9985 | |
parent | 8d2e6cecb2c07bfecb40095519192d65cbc89707 (diff) |
Add TplStreamMediaChannel legacy call observer
-rw-r--r-- | data/Logger.client | 4 | ||||
-rw-r--r-- | src/telepathy-logger.c | 6 | ||||
-rw-r--r-- | telepathy-logger/Makefile.am | 2 | ||||
-rw-r--r-- | telepathy-logger/observer.c | 9 | ||||
-rw-r--r-- | telepathy-logger/streamed-media-channel-internal.h | 62 | ||||
-rw-r--r-- | telepathy-logger/streamed-media-channel.c | 647 |
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; +} |