diff options
Diffstat (limited to 'src/base-call-channel.c')
-rw-r--r-- | src/base-call-channel.c | 754 |
1 files changed, 161 insertions, 593 deletions
diff --git a/src/base-call-channel.c b/src/base-call-channel.c index 9812268..52af824 100644 --- a/src/base-call-channel.c +++ b/src/base-call-channel.c @@ -1,7 +1,8 @@ /* - * base-call-channel.c - Source for GabbleBaseCallChannel + * base-call-channel.c - Source for RingBaseCallChannel * Copyright © 2009–2010 Collabora Ltd. * @author Sjoerd Simons <sjoerd.simons@collabora.co.uk> + * @author Tom Swindell <t.swindell@rubyx.co.uk> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -18,189 +19,86 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "config.h" #include <stdio.h> #include <stdlib.h> #include <gio/gio.h> -#include <telepathy-glib/dbus.h> -#include <telepathy-glib/enums.h> -#include <telepathy-glib/exportable-channel.h> -#include <telepathy-glib/interfaces.h> -#include <telepathy-glib/channel-iface.h> -#include <telepathy-glib/svc-channel.h> -#include <telepathy-glib/svc-properties-interface.h> -#include <telepathy-glib/base-connection.h> -#include <telepathy-glib/gtypes.h> +#include <telepathy-glib/telepathy-glib.h> +#include <telepathy-glib/telepathy-glib-dbus.h> -#include "base-call-channel.h" -#include "base-call-content.h" +#include "util.h" +#include "ring-call-content.h" +#include "ring-call-member.h" +#include "base-call-channel.h" #include "ring-connection.h" +/* #define DEBUG_FLAG RING_DEBUG_MEDIA -#include "ring-debug.h" +#include "debug.h" +*/ -static void call_iface_init (gpointer, gpointer); -static void gabble_base_call_channel_close (TpBaseChannel *base); +G_DEFINE_TYPE(RingBaseCallChannel, ring_base_call_channel, + TP_TYPE_BASE_MEDIA_CALL_CHANNEL); -G_DEFINE_TYPE_WITH_CODE(GabbleBaseCallChannel, gabble_base_call_channel, - TP_TYPE_BASE_CHANNEL, - G_IMPLEMENT_INTERFACE (TP_TYPE_BASE_MEDIA_CALL_CHANNEL, - call_iface_init) -); +static void ring_base_call_channel_hangup ( + TpBaseCallChannel *base, + guint reason, + const gchar *detailed_reason, + const gchar *message); -static const gchar *gabble_base_call_channel_interfaces[] = { - NULL -}; +static void ring_base_call_channel_close (TpBaseChannel *base); /* properties */ enum { PROP_OBJECT_PATH_PREFIX = 1, - - PROP_INITIAL_AUDIO, - PROP_INITIAL_VIDEO, - PROP_MUTABLE_CONTENTS, - PROP_HARDWARE_STREAMING, - PROP_CONTENTS, - - PROP_CALL_STATE, - PROP_CALL_FLAGS, - PROP_CALL_STATE_DETAILS, - PROP_CALL_STATE_REASON, - - PROP_CALL_MEMBERS, - LAST_PROPERTY }; -enum -{ - ENDED, - LAST_SIGNAL -}; - -static guint signals[LAST_SIGNAL] = { 0, }; - - /* private structure */ -struct _GabbleBaseCallChannelPrivate +struct _RingBaseCallChannelPrivate { gchar *object_path_prefix; gboolean dispose_has_run; - GList *contents; - - TpCallState state; - TpCallFlags flags; - GHashTable *details; - GValueArray *reason; - - /* handle -> TpCallMemberFlags hash */ + /* handle -> CallMember object hash */ GHashTable *members; }; static void -gabble_base_call_channel_constructed (GObject *obj) +ring_base_call_channel_init (RingBaseCallChannel *self) { - GabbleBaseCallChannel *self = GABBLE_BASE_CALL_CHANNEL (obj); - TpBaseChannel *base = TP_BASE_CHANNEL (self); - - if (G_OBJECT_CLASS (gabble_base_call_channel_parent_class)->constructed - != NULL) - G_OBJECT_CLASS (gabble_base_call_channel_parent_class)->constructed (obj); - - if (tp_base_channel_is_requested (base)) - gabble_base_call_channel_set_state (self, - TP_CALL_STATE_PENDING_INITIATOR); - else - gabble_base_call_channel_set_state (self, - TP_CALL_STATE_INITIALISING); -} - -static void -gabble_base_call_channel_init (GabbleBaseCallChannel *self) -{ - GabbleBaseCallChannelPrivate *priv = G_TYPE_INSTANCE_GET_PRIVATE (self, - GABBLE_TYPE_BASE_CALL_CHANNEL, GabbleBaseCallChannelPrivate); + RingBaseCallChannelPrivate *priv = G_TYPE_INSTANCE_GET_PRIVATE (self, + RING_TYPE_BASE_CALL_CHANNEL, RingBaseCallChannelPrivate); self->priv = priv; - priv->reason = tp_value_array_build (3, - G_TYPE_UINT, 0, - G_TYPE_UINT, 0, - G_TYPE_STRING, "", - G_TYPE_INVALID); - - priv->details = tp_asv_new (NULL, NULL); - - priv->members = g_hash_table_new (NULL, NULL); + priv->members = g_hash_table_new_full (g_direct_hash, g_direct_equal, + NULL, g_object_unref); } -static void gabble_base_call_channel_dispose (GObject *object); -static void gabble_base_call_channel_finalize (GObject *object); +static void ring_base_call_channel_dispose (GObject *object); +static void ring_base_call_channel_finalize (GObject *object); static void -gabble_base_call_channel_get_property (GObject *object, +ring_base_call_channel_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) { - GabbleBaseCallChannel *self = GABBLE_BASE_CALL_CHANNEL (object); - GabbleBaseCallChannelPrivate *priv = self->priv; - GabbleBaseCallChannelClass *klass = GABBLE_BASE_CALL_CHANNEL_GET_CLASS (self); + RingBaseCallChannel *self = RING_BASE_CALL_CHANNEL (object); + RingBaseCallChannelPrivate *priv = self->priv; switch (property_id) { case PROP_OBJECT_PATH_PREFIX: g_value_set_string (value, priv->object_path_prefix); break; - case PROP_INITIAL_AUDIO: - g_value_set_boolean (value, self->initial_audio); - break; - case PROP_INITIAL_VIDEO: - g_value_set_boolean (value, self->initial_video); - break; - case PROP_MUTABLE_CONTENTS: - g_value_set_boolean (value, klass->mutable_contents); - break; - case PROP_CONTENTS: - { - GPtrArray *arr = g_ptr_array_sized_new (2); - GList *l; - - for (l = priv->contents; l != NULL; l = g_list_next (l)) - { - GabbleBaseCallContent *c = GABBLE_BASE_CALL_CONTENT (l->data); - g_ptr_array_add (arr, - (gpointer) gabble_base_call_content_get_object_path (c)); - } - - g_value_set_boxed (value, arr); - g_ptr_array_free (arr, TRUE); - break; - } - case PROP_HARDWARE_STREAMING: - g_value_set_boolean (value, klass->hardware_streaming); - break; - case PROP_CALL_STATE: - g_value_set_uint (value, priv->state); - break; - case PROP_CALL_FLAGS: - g_value_set_uint (value, priv->flags); - break; - case PROP_CALL_STATE_DETAILS: - g_value_set_boxed (value, priv->details); - break; - case PROP_CALL_STATE_REASON: - g_value_set_boxed (value, priv->reason); - break; - case PROP_CALL_MEMBERS: - g_value_set_boxed (value, priv->members); - break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; @@ -208,25 +106,19 @@ gabble_base_call_channel_get_property (GObject *object, } static void -gabble_base_call_channel_set_property (GObject *object, +ring_base_call_channel_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) { - GabbleBaseCallChannel *self = GABBLE_BASE_CALL_CHANNEL (object); - GabbleBaseCallChannelPrivate *priv = self->priv; + RingBaseCallChannel *self = RING_BASE_CALL_CHANNEL (object); + RingBaseCallChannelPrivate *priv = self->priv; switch (property_id) { case PROP_OBJECT_PATH_PREFIX: priv->object_path_prefix = g_value_dup_string (value); break; - case PROP_INITIAL_AUDIO: - self->initial_audio = g_value_get_boolean (value); - break; - case PROP_INITIAL_VIDEO: - self->initial_video = g_value_get_boolean (value); - break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; @@ -234,10 +126,10 @@ gabble_base_call_channel_set_property (GObject *object, } static gchar * -gabble_base_call_channel_get_object_path_suffix (TpBaseChannel *base) +ring_base_call_channel_get_object_path_suffix (TpBaseChannel *base) { - GabbleBaseCallChannel *self = GABBLE_BASE_CALL_CHANNEL (base); - GabbleBaseCallChannelPrivate *priv = self->priv; + RingBaseCallChannel *self = RING_BASE_CALL_CHANNEL (base); + RingBaseCallChannelPrivate *priv = self->priv; g_assert (priv->object_path_prefix != NULL); @@ -245,70 +137,30 @@ gabble_base_call_channel_get_object_path_suffix (TpBaseChannel *base) } static void -gabble_base_call_channel_fill_immutable_properties ( - TpBaseChannel *chan, - GHashTable *properties) +ring_base_call_channel_class_init ( + RingBaseCallChannelClass *ring_base_call_channel_class) { - TP_BASE_CHANNEL_CLASS (gabble_base_call_channel_parent_class) - ->fill_immutable_properties (chan, properties); - - tp_dbus_properties_mixin_fill_properties_hash ( - G_OBJECT (chan), properties, - TP_IFACE_CHANNEL_TYPE_CALL, "InitialAudio", - TP_IFACE_CHANNEL_TYPE_CALL, "InitialVideo", - TP_IFACE_CHANNEL_TYPE_CALL, "MutableContents", - TP_IFACE_CHANNEL_TYPE_CALL, "HardwareStreaming", - NULL); -} - -static void -gabble_base_call_channel_class_init ( - GabbleBaseCallChannelClass *gabble_base_call_channel_class) -{ - GObjectClass *object_class = G_OBJECT_CLASS (gabble_base_call_channel_class); + GObjectClass *object_class = G_OBJECT_CLASS (ring_base_call_channel_class); TpBaseChannelClass *base_channel_class = - TP_BASE_CHANNEL_CLASS (gabble_base_call_channel_class); + TP_BASE_CHANNEL_CLASS (ring_base_call_channel_class); + TpBaseCallChannelClass *tp_base_call_channel_class = + TP_BASE_CALL_CHANNEL_CLASS (ring_base_call_channel_class); GParamSpec *param_spec; - static TpDBusPropertiesMixinPropImpl call_props[] = { - { "CallMembers", "call-members", NULL }, - { "MutableContents", "mutable-contents", NULL }, - { "InitialAudio", "initial-audio", NULL }, - { "InitialVideo", "initial-video", NULL }, - { "Contents", "contents", NULL }, - { "HardwareStreaming", "hardware-streaming", NULL }, - { "CallState", "call-state", NULL }, - { "CallFlags", "call-flags", NULL }, - { "CallStateReason", "call-state-reason", NULL }, - { "CallStateDetails", "call-state-details", NULL }, - { NULL } - }; - - g_type_class_add_private (gabble_base_call_channel_class, - sizeof (GabbleBaseCallChannelPrivate)); - - object_class->constructed = gabble_base_call_channel_constructed; - - object_class->get_property = gabble_base_call_channel_get_property; - object_class->set_property = gabble_base_call_channel_set_property; - - object_class->dispose = gabble_base_call_channel_dispose; - object_class->finalize = gabble_base_call_channel_finalize; - - base_channel_class->channel_type = TP_IFACE_CHANNEL_TYPE_CALL; - base_channel_class->interfaces = gabble_base_call_channel_interfaces; + + g_type_class_add_private (ring_base_call_channel_class, + sizeof (RingBaseCallChannelPrivate)); + + object_class->get_property = ring_base_call_channel_get_property; + object_class->set_property = ring_base_call_channel_set_property; + + object_class->dispose = ring_base_call_channel_dispose; + object_class->finalize = ring_base_call_channel_finalize; + base_channel_class->get_object_path_suffix = - gabble_base_call_channel_get_object_path_suffix; - base_channel_class->fill_immutable_properties = - gabble_base_call_channel_fill_immutable_properties; - base_channel_class->close = gabble_base_call_channel_close; - - signals[ENDED] = g_signal_new ("ended", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); + ring_base_call_channel_get_object_path_suffix; + base_channel_class->close = ring_base_call_channel_close; + + tp_base_call_channel_class->hangup = ring_base_call_channel_hangup; param_spec = g_param_spec_string ("object-path-prefix", "Object path prefix", "prefix of the object path", @@ -316,446 +168,162 @@ gabble_base_call_channel_class_init ( G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_OBJECT_PATH_PREFIX, param_spec); - - param_spec = g_param_spec_boolean ("initial-audio", "InitialAudio", - "Whether the channel initially contained an audio stream", - FALSE, - G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_INITIAL_AUDIO, - param_spec); - - param_spec = g_param_spec_boolean ("initial-video", "InitialVideo", - "Whether the channel initially contained an video stream", - FALSE, - G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_INITIAL_VIDEO, - param_spec); - - param_spec = g_param_spec_boolean ("mutable-contents", "MutableContents", - "Whether the set of streams on this channel are mutable once requested", - FALSE, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_MUTABLE_CONTENTS, - param_spec); - - param_spec = g_param_spec_boxed ("contents", "Contents", - "The contents of the channel", - TP_ARRAY_TYPE_OBJECT_PATH_LIST, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_CONTENTS, - param_spec); - - param_spec = g_param_spec_boolean ("hardware-streaming", "HardwareStreaming", - "True if all the streaming is done by hardware", - FALSE, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_HARDWARE_STREAMING, - param_spec); - - param_spec = g_param_spec_uint ("call-state", "CallState", - "The status of the call", - TP_CALL_STATE_UNKNOWN, - NUM_TP_CALL_STATES, - TP_CALL_STATE_UNKNOWN, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_CALL_STATE, param_spec); - - param_spec = g_param_spec_uint ("call-flags", "CallFlags", - "Flags representing the status of the call", - 0, G_MAXUINT, 0, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_CALL_FLAGS, - param_spec); - - param_spec = g_param_spec_boxed ("call-state-reason", "CallStateReason", - "The reason why the call is in the current state", - TP_STRUCT_TYPE_CALL_STATE_REASON, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_CALL_STATE_REASON, - param_spec); - - param_spec = g_param_spec_boxed ("call-state-details", "CallStateDetails", - "The reason why the call is in the current state", - TP_HASH_TYPE_QUALIFIED_PROPERTY_VALUE_MAP, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_CALL_STATE_DETAILS, - param_spec); - - param_spec = g_param_spec_boxed ("call-members", "CallMembers", - "The members", - TP_HASH_TYPE_CALL_MEMBER_MAP, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_CALL_MEMBERS, - param_spec); - - tp_dbus_properties_mixin_implement_interface (object_class, - TP_IFACE_QUARK_CHANNEL_TYPE_CALL, - tp_dbus_properties_mixin_getter_gobject_properties, - NULL, - call_props); } void -gabble_base_call_channel_dispose (GObject *object) +ring_base_call_channel_dispose (GObject *object) { - GabbleBaseCallChannel *self = GABBLE_BASE_CALL_CHANNEL (object); - GabbleBaseCallChannelPrivate *priv = self->priv; + RingBaseCallChannel *self = RING_BASE_CALL_CHANNEL (object); + RingBaseCallChannelPrivate *priv = self->priv; if (priv->dispose_has_run) return; self->priv->dispose_has_run = TRUE; - g_list_foreach (priv->contents, (GFunc) gabble_base_call_content_deinit, NULL); - g_list_foreach (priv->contents, (GFunc) g_object_unref, NULL); - tp_clear_pointer (&priv->contents, g_list_free); - tp_clear_pointer (&priv->members, g_hash_table_unref); - if (G_OBJECT_CLASS (gabble_base_call_channel_parent_class)->dispose) - G_OBJECT_CLASS (gabble_base_call_channel_parent_class)->dispose (object); + if (G_OBJECT_CLASS (ring_base_call_channel_parent_class)->dispose) + G_OBJECT_CLASS (ring_base_call_channel_parent_class)->dispose (object); } void -gabble_base_call_channel_finalize (GObject *object) +ring_base_call_channel_finalize (GObject *object) { - GabbleBaseCallChannel *self = GABBLE_BASE_CALL_CHANNEL (object); - GabbleBaseCallChannelPrivate *priv = self->priv; + RingBaseCallChannel *self = RING_BASE_CALL_CHANNEL (object); + RingBaseCallChannelPrivate *priv = self->priv; - g_hash_table_unref (priv->details); - g_value_array_free (priv->reason); - g_free (self->priv->object_path_prefix); + g_free (priv->object_path_prefix); - G_OBJECT_CLASS (gabble_base_call_channel_parent_class)->finalize (object); + G_OBJECT_CLASS (ring_base_call_channel_parent_class)->finalize (object); } -void -gabble_base_call_channel_set_state (GabbleBaseCallChannel *self, - TpCallState state) +RingCallContent * +ring_base_call_channel_add_content (RingBaseCallChannel *self, + const gchar *name, + TpCallContentDisposition disposition) { - GabbleBaseCallChannelPrivate *priv = self->priv; - - DEBUG ("changing from %u to %u", priv->state, state); - - if (state == priv->state) - return; - - /* signal when going to the ended state */ - if (state == TP_CALL_STATE_ENDED) - g_signal_emit (self, signals[ENDED], 0); - - priv->state = state; - - if (priv->state != TP_CALL_STATE_INITIALISING) - priv->flags &= ~TP_CALL_FLAG_LOCALLY_RINGING; - - if (tp_base_channel_is_registered (TP_BASE_CHANNEL (self))) - tp_svc_channel_type_call_emit_call_state_changed (self, priv->state, - priv->flags, priv->reason, priv->details); -} - -TpCallState -gabble_base_call_channel_get_state (GabbleBaseCallChannel *self) -{ - return self->priv->state; -} - -void -gabble_base_call_channel_update_flags (GabbleBaseCallChannel *self, - TpCallFlags set_flags, - TpCallFlags clear_flags) -{ - GabbleBaseCallChannelPrivate *priv = self->priv; - TpCallFlags old_flags = priv->flags; - - priv->flags = (old_flags | set_flags) & ~clear_flags; - DEBUG ("was %u; set %u and cleared %u; now %u", old_flags, set_flags, - clear_flags, priv->flags); - - if (priv->flags != old_flags) - tp_svc_channel_type_call_emit_call_state_changed (self, priv->state, - priv->flags, priv->reason, priv->details); + TpBaseChannel *base = TP_BASE_CHANNEL (self); + gchar *object_path; + TpBaseCallContent *content; + gchar *escaped; + + /* FIXME could clash when other party in a one-to-one call creates a stream + * with the same media type and name */ + escaped = tp_escape_as_identifier (name); + object_path = g_strdup_printf ("%s/Content_%s", + tp_base_channel_get_object_path (base), + escaped); + g_free (escaped); + + content = g_object_new (RING_TYPE_CALL_CONTENT, + "connection", tp_base_channel_get_connection (base), + "object-path", object_path, + "disposition", disposition, + //"media-type", wocky_jingle_media_type_to_tp (mtype), + "name", name, + NULL); + + g_free (object_path); + + tp_base_call_channel_add_content (TP_BASE_CALL_CHANNEL (self), + content); + + return RING_CALL_CONTENT (content); } -static gboolean -base_call_channel_update_member (GabbleBaseCallChannel *self, - TpHandle contact, - TpCallMemberFlags set_flags, - TpCallMemberFlags clear_flags, - TpCallMemberFlags *new_flags) +static void +call_member_flags_changed_cb (RingCallMember *member, + TpCallMemberFlags flags, + gpointer user_data) { - gpointer old_flags_p; - - DEBUG ("updating member #%u, setting %u and clearing %u", contact, set_flags, - clear_flags); - - if (g_hash_table_lookup_extended (self->priv->members, - GUINT_TO_POINTER (contact), NULL, &old_flags_p)) - { - TpCallMemberFlags old_flags = GPOINTER_TO_UINT (old_flags_p); - - *new_flags = (old_flags | set_flags) & ~clear_flags; - - DEBUG ("previous flags: %u; new flags: %u", old_flags, *new_flags); - - if (old_flags == *new_flags) - return FALSE; - } - else - { - *new_flags = set_flags & ~clear_flags; - DEBUG ("not previously a member; new flags: %u", *new_flags); - } + TpBaseCallChannel *base = TP_BASE_CALL_CHANNEL (user_data); - g_hash_table_insert (self->priv->members, GUINT_TO_POINTER (contact), - GUINT_TO_POINTER (*new_flags)); - return TRUE; + tp_base_call_channel_update_member_flags (base, + ring_call_member_get_handle (member), + flags, + 0, TP_CALL_STATE_CHANGE_REASON_PROGRESS_MADE, "", ""); } -gboolean -gabble_base_call_channel_update_members ( - GabbleBaseCallChannel *self, - TpHandle contact, - TpCallMemberFlags set_flags, - TpCallMemberFlags clear_flags, - ...) +RingCallMember * +ring_base_call_channel_get_member_from_handle ( + RingBaseCallChannel *self, + TpHandle handle) { - GHashTable *updates = g_hash_table_new (NULL, NULL); - gboolean updated = FALSE; - va_list args; - - va_start (args, clear_flags); - - do - { - TpCallMemberFlags new_flags; - - if (base_call_channel_update_member (self, contact, set_flags, - clear_flags, &new_flags)) - { - g_hash_table_insert (updates, - GUINT_TO_POINTER (contact), - GUINT_TO_POINTER (new_flags)); - updated = TRUE; - } - - contact = va_arg (args, TpHandle); - - if (contact != 0) - { - set_flags = va_arg (args, TpCallMemberFlags); - clear_flags = va_arg (args, TpCallMemberFlags); - } - } - while (contact != 0); - - if (updated) - { - GArray *empty = g_array_new (FALSE, FALSE, sizeof (TpHandle)); - - tp_svc_channel_type_call_emit_call_members_changed (self, updates, NULL, - empty, empty); - g_array_unref (empty); - } - - g_hash_table_unref (updates); - return updated; + return g_hash_table_lookup (self->priv->members, GUINT_TO_POINTER (handle)); } -gboolean -gabble_base_call_channel_remove_members ( - GabbleBaseCallChannel *self, - TpHandle contact, - ...) +RingCallMember * +ring_base_call_channel_ensure_member_from_handle ( + RingBaseCallChannel *self, + TpHandle handle) { - GArray *removed = g_array_new (FALSE, FALSE, sizeof (TpHandle)); - gboolean updated = FALSE; - va_list args; + RingBaseCallChannelPrivate *priv = self->priv; + RingCallMember *m; - va_start (args, contact); - - do + m = g_hash_table_lookup (priv->members, GUINT_TO_POINTER (handle)); + if (m == NULL) { - if (g_hash_table_remove (self->priv->members, GUINT_TO_POINTER (contact))) - { - g_array_append_val (removed, contact); - updated = TRUE; - } - - contact = va_arg (args, TpHandle); - } - while (contact != 0); - - if (updated) - { - GHashTable *empty = g_hash_table_new (NULL, NULL); - - tp_svc_channel_type_call_emit_call_members_changed (self, empty, - removed); - g_hash_table_unref (empty); + m = RING_CALL_MEMBER (g_object_new (RING_TYPE_CALL_MEMBER, + "target", handle, + "call", self, + NULL)); + g_hash_table_insert (priv->members, GUINT_TO_POINTER (handle), m); + + tp_base_call_channel_update_member_flags (TP_BASE_CALL_CHANNEL (self), + ring_call_member_get_handle (m), + ring_call_member_get_flags (m), + 0, TP_CALL_STATE_CHANGE_REASON_PROGRESS_MADE, "", ""); + + ring_signal_connect_weak (m, "flags-changed", + G_CALLBACK (call_member_flags_changed_cb), G_OBJECT (self)); } - g_array_unref (removed); - return updated; + return m; } void -gabble_base_call_channel_add_content (GabbleBaseCallChannel *self, - GabbleBaseCallContent *content) +ring_base_call_channel_remove_member (RingBaseCallChannel *self, + RingCallMember *member) { - self->priv->contents = g_list_prepend (self->priv->contents, - g_object_ref (content)); + TpHandle h = ring_call_member_get_handle (member); - if (tp_base_channel_is_registered (TP_BASE_CHANNEL (self))) - tp_svc_channel_type_call_emit_content_added (self, - gabble_base_call_content_get_object_path (content), - gabble_base_call_content_get_media_type (content)); -} - -static void -gabble_base_call_channel_close (TpBaseChannel *base) -{ - GabbleBaseCallChannel *self = GABBLE_BASE_CALL_CHANNEL (base); - GabbleBaseCallChannelPrivate *priv = self->priv; - - DEBUG ("Closing media channel %s", tp_base_channel_get_object_path (base)); - - /* shutdown all our contents */ - g_list_foreach (priv->contents, (GFunc) gabble_base_call_content_deinit, - NULL); - g_list_foreach (priv->contents, (GFunc) g_object_unref, NULL); - tp_clear_pointer (&priv->contents, g_list_free); - - tp_base_channel_destroyed (base); -} - -static void -gabble_base_call_channel_ringing (TpSvcChannelTypeCall *iface, - DBusGMethodInvocation *context) -{ - GabbleBaseCallChannel *self = GABBLE_BASE_CALL_CHANNEL (iface); - GabbleBaseCallChannelPrivate *priv = self->priv; - TpBaseChannel *tp_base = TP_BASE_CHANNEL (self); + g_assert (g_hash_table_lookup (self->priv->members, + GUINT_TO_POINTER (h))== member); - if (tp_base_channel_is_requested (tp_base)) - { - GError e = { TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, - "Call was requested. Ringing doesn't make sense." }; - dbus_g_method_return_error (context, &e); - } - else if (priv->state != TP_CALL_STATE_INITIALISING) - { - GError e = { TP_ERRORS, TP_ERROR_NOT_AVAILABLE, - "Call is not in the right state for Ringing." }; - dbus_g_method_return_error (context, &e); - } - else - { - if ((priv->flags & TP_CALL_FLAG_LOCALLY_RINGING) == 0) - { - DEBUG ("Client is ringing"); - priv->flags |= TP_CALL_FLAG_LOCALLY_RINGING; - gabble_base_call_channel_set_state (self, priv->state); - } - - tp_svc_channel_type_call_return_from_ringing (context); - } + ring_call_member_shutdown (member); + tp_base_call_channel_remove_member (TP_BASE_CALL_CHANNEL (self), + ring_call_member_get_handle (member), + 0, TP_CALL_STATE_CHANGE_REASON_PROGRESS_MADE, "", ""); + g_hash_table_remove (self->priv->members, GUINT_TO_POINTER (h)); } static void -gabble_base_call_channel_accept (TpSvcChannelTypeCall *iface, - DBusGMethodInvocation *context) +ring_base_call_channel_shutdown_all_members (RingBaseCallChannel *self) { - GabbleBaseCallChannel *self = GABBLE_BASE_CALL_CHANNEL (iface); - GabbleBaseCallChannelPrivate *priv = self->priv; - GabbleBaseCallChannelClass *base_class = - GABBLE_BASE_CALL_CHANNEL_GET_CLASS (self); - TpBaseChannel *tp_base = TP_BASE_CHANNEL (self); - - DEBUG ("Client accepted the call"); + GHashTableIter iter; + gpointer value; - if (tp_base_channel_is_requested (tp_base)) - { - if (priv->state == TP_CALL_STATE_PENDING_INITIATOR) - { - gabble_base_call_channel_set_state (self, - TP_CALL_STATE_INITIALISING); - } - else - { - DEBUG ("Invalid state for Accept: Channel requested and " - "state == %d", priv->state); - goto err; - } - } - else if (priv->state < TP_CALL_STATE_ACCEPTED) - { - gabble_base_call_channel_set_state (self, - TP_CALL_STATE_ACCEPTED); - } - else - { - DEBUG ("Invalid state for Accept: state == %d", priv->state); - goto err; - } - - if (base_class->accept != NULL) - base_class->accept (self); - - tp_svc_channel_type_call_return_from_accept (context); - return; - -err: - { - GError e = { TP_ERRORS, TP_ERROR_NOT_AVAILABLE, - "Invalid state for Accept" }; - dbus_g_method_return_error (context, &e); - } + g_hash_table_iter_init (&iter, self->priv->members); + while (g_hash_table_iter_next (&iter, NULL, &value)) + ring_call_member_shutdown (RING_CALL_MEMBER (value)); } static void -gabble_base_call_channel_hangup (TpSvcChannelTypeCall *iface, - guint reason, - const gchar *detailed_reason, - const gchar *message, - DBusGMethodInvocation *context) +ring_base_call_channel_hangup (TpBaseCallChannel *base, + guint reason, + const gchar *detailed_reason, + const gchar *message) { - GabbleBaseCallChannel *self = GABBLE_BASE_CALL_CHANNEL (iface); - GabbleBaseCallChannelClass *base_class = - GABBLE_BASE_CALL_CHANNEL_GET_CLASS (self); - - if (base_class->hangup) - base_class->hangup (self, reason, detailed_reason, message); - - gabble_base_call_channel_set_state ( GABBLE_BASE_CALL_CHANNEL (self), - TP_CALL_STATE_ENDED); - - tp_svc_channel_type_call_return_from_hangup (context); + ring_base_call_channel_shutdown_all_members ( + RING_BASE_CALL_CHANNEL (base)); } static void -gabble_base_call_channel_add_content_dbus (RingSvcChannelTypeCall *iface, - const gchar *name, - TpMediaStreamType mtype, - DBusGMethodInvocation *context) +ring_base_call_channel_close (TpBaseChannel *base) { - GError e = { TP_ERRORS, TP_ERROR_NOT_IMPLEMENTED, - "Contents cannot be added; only a single audio content is supported" }; + ring_base_call_channel_shutdown_all_members ( + RING_BASE_CALL_CHANNEL (base)); - dbus_g_method_return_error (context, &e); -} - - -static void -call_iface_init (gpointer g_iface, gpointer iface_data) -{ - RingSvcChannelTypeCallClass *klass = g_iface; - -#define IMPLEMENT(x, suffix) ring_svc_channel_type_call_implement_##x (\ - klass, gabble_base_call_channel_##x##suffix) - IMPLEMENT(ringing,); - IMPLEMENT(accept,); - IMPLEMENT(hangup,); - IMPLEMENT(add_content, _dbus); -#undef IMPLEMENT + TP_BASE_CHANNEL_CLASS (ring_base_call_channel_parent_class)->close (base); } |