From 6e58cd16c4106c40daaa926de841b24c56b07aa8 Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Tue, 17 Sep 2013 13:30:50 +0100 Subject: [PATCH] Remove StreamedMedia support In Pidgin, it's only implemented for XMPP (for which we have Gabble), MSNP (which will disappear soon), and mxit (which I doubt anyone's actually tested). Empathy can't do StreamedMedia any more, only Call, and Telepathy 1.0 will only have Call. --- configure.ac | 10 - src/Makefile.am | 15 +- src/connection-capabilities.c | 198 ----- src/connection-capabilities.h | 2 - src/connection.c | 13 - src/connection.h | 8 - src/main.c | 13 - src/media-backend.c | 614 -------------- src/media-backend.h | 68 -- src/media-channel.c | 1760 ----------------------------------------- src/media-channel.h | 79 -- src/media-manager.c | 576 -------------- src/media-manager.h | 65 -- src/media-stream.c | 1396 -------------------------------- src/media-stream.h | 126 --- src/protocol.c | 3 - tests/twisted/Makefile.am | 12 - tests/twisted/simple-caps.py | 28 - 18 files changed, 1 insertion(+), 4985 deletions(-) delete mode 100644 src/media-backend.c delete mode 100644 src/media-backend.h delete mode 100644 src/media-channel.c delete mode 100644 src/media-channel.h delete mode 100644 src/media-manager.c delete mode 100644 src/media-manager.h delete mode 100644 src/media-stream.c delete mode 100644 src/media-stream.h diff --git a/configure.ac b/configure.ac index ae9c28f..80f47ca 100644 --- a/configure.ac +++ b/configure.ac @@ -114,16 +114,6 @@ AC_MSG_RESULT([$TEST_PYTHON]) AC_SUBST(TEST_PYTHON) AM_CONDITIONAL([WANT_TWISTED_TESTS], test false != "$TEST_PYTHON") -AC_ARG_ENABLE(media, - AC_HELP_STRING([--disable-media],[disable audio/video calls]), - [ - AM_CONDITIONAL([MEDIA_ENABLED], false) - ],[ - AC_DEFINE(ENABLE_MEDIA, [], [Enable audio/video calls]) - AM_CONDITIONAL([MEDIA_ENABLED], true) - ]) -AC_SUBST(ENABLE_MEDIA) - #AS_AC_EXPAND(DATADIR, $datadir) #DBUS_SERVICES_DIR="$DATADIR/dbus-1/services" #AC_SUBST(DBUS_SERVICES_DIR) diff --git a/src/Makefile.am b/src/Makefile.am index bc9fd28..59bae17 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -8,19 +8,6 @@ man_MANS = telepathy-haze.8 EXTRA_DIST = telepathy-haze.8.in CLEANFILES = $(man_MANS) -if MEDIA_ENABLED -haze_media_sources = media-backend.c \ - media-backend.h \ - media-channel.c \ - media-channel.h \ - media-manager.c \ - media-manager.h \ - media-stream.c \ - media-stream.h -else -haze_media_sources = -endif - telepathy_haze_SOURCES = main.c \ defines.h \ debug.c \ @@ -53,7 +40,7 @@ telepathy_haze_SOURCES = main.c \ request.h \ util.c \ util.h \ - $(haze_media_sources) + $(NULL) telepathy_haze_LDADD = $(top_builddir)/extensions/libhaze-extensions.la diff --git a/src/connection-capabilities.c b/src/connection-capabilities.c index 5ccb37c..ce6fd8f 100644 --- a/src/connection-capabilities.c +++ b/src/connection-capabilities.c @@ -28,9 +28,6 @@ #include "connection.h" #include "debug.h" -#ifdef ENABLE_MEDIA -#include "mediamanager.h" -#endif static void free_rcc_list (GPtrArray *rccs) @@ -38,33 +35,6 @@ free_rcc_list (GPtrArray *rccs) g_boxed_free (TP_ARRAY_TYPE_REQUESTABLE_CHANNEL_CLASS_LIST, rccs); } -#ifdef ENABLE_MEDIA -static GPtrArray * haze_connection_get_handle_contact_capabilities ( - HazeConnection *self, TpHandle handle); - -static void -_emit_capabilities_changed (HazeConnection *conn, - TpHandle handle, - PurpleMediaCaps old_caps, - PurpleMediaCaps new_caps) -{ - if (old_caps != new_caps) - { - GHashTable *ret = g_hash_table_new_full (g_direct_hash, g_direct_equal, - NULL, (GDestroyNotify) free_rcc_list); - GPtrArray *arr; - - arr = haze_connection_get_handle_contact_capabilities (conn, handle); - g_hash_table_insert (ret, GUINT_TO_POINTER (handle), arr); - - tp_svc_connection_interface_contact_capabilities_emit_contact_capabilities_changed ( - conn, ret); - - g_hash_table_unref (ret); - } -} -#endif - static void haze_connection_update_capabilities (TpSvcConnectionInterfaceContactCapabilities *iface, const GPtrArray *clients, @@ -72,72 +42,9 @@ haze_connection_update_capabilities (TpSvcConnectionInterfaceContactCapabilities { HazeConnection *self = HAZE_CONNECTION (iface); TpBaseConnection *base = (TpBaseConnection *) self; -#ifdef ENABLE_MEDIA - guint i; - PurpleMediaCaps old_caps, caps; - GHashTableIter iter; - gpointer value; -#endif TP_BASE_CONNECTION_ERROR_IF_NOT_CONNECTED (base, context); -#ifdef ENABLE_MEDIA - caps = PURPLE_MEDIA_CAPS_NONE; - old_caps = purple_media_manager_get_ui_caps ( - purple_media_manager_get ()); - - DEBUG ("enter"); - - /* go through all the clients and if they can do audio or video save - * it in the client_caps hash table */ - for (i = 0; i < clients->len; i++) - { - GValueArray *va = g_ptr_array_index (clients, i); - const gchar *client_name = g_value_get_string (va->values + 0); - const GPtrArray *rccs = g_value_get_boxed (va->values + 1); - guint j; - PurpleMediaCaps flags = 0; - - g_hash_table_remove (self->client_caps, client_name); - - for (j = 0; j < rccs->len; j++) - { - GHashTable *class = g_ptr_array_index (rccs, i); - - if (tp_strdiff (tp_asv_get_string (class, TP_PROP_CHANNEL_CHANNEL_TYPE), - TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA)) - continue; - - if (tp_asv_get_boolean (class, - TP_PROP_CHANNEL_TYPE_STREAMED_MEDIA_INITIAL_AUDIO, NULL)) - flags |= PURPLE_MEDIA_CAPS_AUDIO; - - if (tp_asv_get_boolean (class, - TP_PROP_CHANNEL_TYPE_STREAMED_MEDIA_INITIAL_VIDEO, NULL)) - flags |= PURPLE_MEDIA_CAPS_VIDEO; - } - - if (flags != 0) - { - g_hash_table_insert (self->client_caps, g_strdup (client_name), - GUINT_TO_POINTER (flags)); - } - } - - /* now we have an updated client_caps hash table, go through it and - * let libpurple know */ - g_hash_table_iter_init (&iter, self->client_caps); - while (g_hash_table_iter_next (&iter, NULL, &value)) - { - caps |= GPOINTER_TO_UINT (value); - } - - purple_media_manager_set_ui_caps (purple_media_manager_get(), caps); - - _emit_capabilities_changed (self, tp_base_connection_get_self_handle (base), - old_caps, caps); -#endif - tp_svc_connection_interface_contact_capabilities_return_from_update_capabilities ( context); } @@ -146,21 +53,6 @@ static GPtrArray * haze_connection_get_handle_contact_capabilities (HazeConnection *self, TpHandle handle) { -#ifdef ENABLE_MEDIA - PurpleAccount *account = self->account; - TpBaseConnection *conn = TP_BASE_CONNECTION (self); - TpHandleRepoIface *contact_handles = - tp_base_connection_get_handles (conn, TP_HANDLE_TYPE_CONTACT); - const gchar *bname; - PurpleMediaCaps caps; - GValue media_monster = {0, }; - const gchar * const sm_allowed_audio[] = { - TP_PROP_CHANNEL_TYPE_STREAMED_MEDIA_INITIAL_AUDIO, NULL }; - const gchar * const sm_allowed_video[] = { - TP_PROP_CHANNEL_TYPE_STREAMED_MEDIA_INITIAL_AUDIO, - TP_PROP_CHANNEL_TYPE_STREAMED_MEDIA_INITIAL_VIDEO, - NULL }; -#endif GPtrArray *arr = g_ptr_array_new (); GValue monster = {0, }; GHashTable *fixed_properties; @@ -177,56 +69,6 @@ haze_connection_get_handle_contact_capabilities (HazeConnection *self, /* TODO: Check for presence */ -#ifdef ENABLE_MEDIA - if (handle == tp_base_connection_get_self_handle (conn)) - caps = purple_media_manager_get_ui_caps (purple_media_manager_get ()); - else - { - bname = tp_handle_inspect (contact_handles, handle); - caps = purple_prpl_get_media_caps (account, bname); - } - - /* we assume that VIDEO won't be present without AUDIO */ - if ((caps & PURPLE_MEDIA_CAPS_AUDIO) != 0) - { - const gchar * const *allowed; - - g_value_init (&media_monster, - TP_STRUCT_TYPE_REQUESTABLE_CHANNEL_CLASS); - g_value_take_boxed (&media_monster, - dbus_g_type_specialized_construct ( - TP_STRUCT_TYPE_REQUESTABLE_CHANNEL_CLASS)); - - fixed_properties = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, - (GDestroyNotify) tp_g_value_slice_free); - - channel_type_value = tp_g_value_slice_new (G_TYPE_STRING); - g_value_set_static_string (channel_type_value, - TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA); - g_hash_table_insert (fixed_properties, TP_PROP_CHANNEL_CHANNEL_TYPE, - channel_type_value); - - target_handle_type_value = tp_g_value_slice_new (G_TYPE_UINT); - g_value_set_uint (target_handle_type_value, TP_HANDLE_TYPE_CONTACT); - g_hash_table_insert (fixed_properties, TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, - target_handle_type_value); - - if (caps & PURPLE_MEDIA_CAPS_VIDEO) - allowed = sm_allowed_video; - else - allowed = sm_allowed_audio; - - dbus_g_type_struct_set (&media_monster, - 0, fixed_properties, - 1, allowed, - G_MAXUINT); - - g_hash_table_unref (fixed_properties); - - g_ptr_array_add (arr, g_value_get_boxed (&media_monster)); - } -#endif - g_value_init (&monster, TP_STRUCT_TYPE_REQUESTABLE_CHANNEL_CLASS); g_value_take_boxed (&monster, dbus_g_type_specialized_construct ( @@ -343,50 +185,10 @@ haze_connection_contact_capabilities_iface_init (gpointer g_iface, #undef IMPLEMENT } -#ifdef ENABLE_MEDIA -static void -caps_changed_cb (PurpleBuddy *buddy, - PurpleMediaCaps caps, - PurpleMediaCaps oldcaps) -{ - PurpleAccount *account = purple_buddy_get_account (buddy); - HazeConnection *conn = ACCOUNT_GET_HAZE_CONNECTION (account); - TpBaseConnection *base_conn = TP_BASE_CONNECTION (conn); - TpHandleRepoIface *contact_repo = - tp_base_connection_get_handles (base_conn, TP_HANDLE_TYPE_CONTACT); - const gchar *bname = purple_buddy_get_name(buddy); - TpHandle contact = tp_handle_ensure (contact_repo, bname, NULL, NULL); - - _emit_capabilities_changed (conn, contact, oldcaps, caps); -} -#endif - -void -haze_connection_capabilities_class_init (GObjectClass *object_class) -{ -#ifdef ENABLE_MEDIA - purple_signal_connect (purple_blist_get_handle (), "buddy-caps-changed", - object_class, PURPLE_CALLBACK (caps_changed_cb), NULL); -#endif -} - void haze_connection_capabilities_init (GObject *object) { - HazeConnection *self = HAZE_CONNECTION (object); - tp_contacts_mixin_add_contact_attributes_iface (object, TP_IFACE_CONNECTION_INTERFACE_CONTACT_CAPABILITIES, conn_capabilities_fill_contact_attributes_contact_caps); - - self->client_caps = g_hash_table_new_full (g_str_hash, g_str_equal, - (GDestroyNotify) g_free, NULL); -} - -void -haze_connection_capabilities_finalize (GObject *object) -{ - HazeConnection *self = HAZE_CONNECTION (object); - - tp_clear_pointer (&self->client_caps, g_hash_table_unref); } diff --git a/src/connection-capabilities.h b/src/connection-capabilities.h index 791581b..e98bf98 100644 --- a/src/connection-capabilities.h +++ b/src/connection-capabilities.h @@ -25,8 +25,6 @@ void haze_connection_contact_capabilities_iface_init (gpointer g_iface, gpointer iface_data); -void haze_connection_capabilities_class_init (GObjectClass *object_class); void haze_connection_capabilities_init (GObject *object); -void haze_connection_capabilities_finalize (GObject *object); #endif diff --git a/src/connection.c b/src/connection.c index 67da039..3c98304 100644 --- a/src/connection.c +++ b/src/connection.c @@ -615,16 +615,6 @@ _haze_connection_create_channel_managers (TpBaseConnection *base) g_object_new (HAZE_TYPE_IM_CHANNEL_FACTORY, "connection", self, NULL)); g_ptr_array_add (channel_managers, self->im_factory); -#ifdef ENABLE_MEDIA - /* Instantiate the media manager only if the protocol support calls */ - if (PURPLE_PROTOCOL_PLUGIN_HAS_FUNC (self->priv->prpl_info, initiate_media)) - { - self->media_manager = HAZE_MEDIA_MANAGER ( - g_object_new (HAZE_TYPE_MEDIA_MANAGER, "connection", self, NULL)); - g_ptr_array_add (channel_managers, self->media_manager); - } -#endif - self->contact_list = HAZE_CONTACT_LIST ( g_object_new (HAZE_TYPE_CONTACT_LIST, "connection", self, NULL)); g_ptr_array_add (channel_managers, self->contact_list); @@ -769,8 +759,6 @@ haze_connection_finalize (GObject *object) tp_contacts_mixin_finalize (object); tp_presence_mixin_finalize (object); - haze_connection_capabilities_finalize (object); - g_strfreev (self->acceptable_avatar_mime_types); g_free (priv->username); g_free (priv->password); @@ -867,7 +855,6 @@ haze_connection_class_init (HazeConnectionClass *klass) haze_connection_presence_class_init (object_class); haze_connection_aliasing_class_init (object_class); haze_connection_avatars_class_init (object_class); - haze_connection_capabilities_class_init (object_class); } static void diff --git a/src/connection.h b/src/connection.h index ce4b67f..1677bf1 100644 --- a/src/connection.h +++ b/src/connection.h @@ -29,7 +29,6 @@ #include "contact-list.h" #include "im-channel-factory.h" -#include "media-manager.h" G_BEGIN_DECLS @@ -51,7 +50,6 @@ struct _HazeConnection { HazeContactList *contact_list; HazeImChannelFactory *im_factory; - HazeMediaManager *media_manager; TpSimplePasswordManager *password_manager; TpContactsMixin contacts; @@ -59,12 +57,6 @@ struct _HazeConnection { gchar **acceptable_avatar_mime_types; - /* Telepathy client's bus name => PurpleMediaCaps */ - GHashTable *client_caps; - - /* Part of the hack for Jabber media caps */ - gulong status_changed_id; - HazeConnectionPrivate *priv; }; diff --git a/src/main.c b/src/main.c index 3f9b38f..bf4b601 100644 --- a/src/main.c +++ b/src/main.c @@ -39,10 +39,6 @@ #include #include -#ifdef ENABLE_MEDIA -#include -#endif - #ifdef HAVE_PURPLE_DBUS_UNINIT #include #endif @@ -56,10 +52,6 @@ #include "request.h" #include "util.h" -#ifdef ENABLE_MEDIA -#include "media-backend.h" -#endif - /* Copied verbatim from nullclient, modulo changing whitespace. */ #define PURPLE_GLIB_READ_COND (G_IO_IN | G_IO_HUP | G_IO_ERR) #define PURPLE_GLIB_WRITE_COND (G_IO_OUT | G_IO_HUP | G_IO_ERR | G_IO_NVAL) @@ -212,11 +204,6 @@ init_libpurple (void) PURPLE_MAJOR_VERSION, PURPLE_MINOR_VERSION, PURPLE_MICRO_VERSION); set_libpurple_preferences (); - -#ifdef ENABLE_MEDIA - purple_media_manager_set_backend_type (purple_media_manager_get (), - HAZE_TYPE_MEDIA_BACKEND); -#endif } static TpBaseConnectionManager * diff --git a/src/media-backend.c b/src/media-backend.c deleted file mode 100644 index 99f0545..0000000 --- a/src/media-backend.c +++ /dev/null @@ -1,614 +0,0 @@ -/* - * media-backend.c - Source for HazeMediaBackend - * Copyright © 2006-2009 Collabora Ltd. - * Copyright © 2006-2009 Nokia Corporation - * - * 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 - */ - -#include "config.h" -#include "media-backend.h" - -#include -#include -#include - -#include - -#include "debug.h" - -static void media_backend_iface_init(PurpleMediaBackendIface *iface); -static void session_handler_iface_init (gpointer g_iface, - gpointer iface_data); -static void haze_backend_state_changed_cb (PurpleMedia *media, - PurpleMediaState state, - const gchar *sid, - const gchar *name, - HazeMediaBackend *backend); - -G_DEFINE_TYPE_WITH_CODE (HazeMediaBackend, - haze_media_backend, - G_TYPE_OBJECT, - G_IMPLEMENT_INTERFACE (PURPLE_TYPE_MEDIA_BACKEND, - media_backend_iface_init); - G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_MEDIA_SESSION_HANDLER, - session_handler_iface_init); - ) - -/* properties */ -enum -{ - PROP_CONFERENCE_TYPE = 1, - PROP_MEDIA, - PROP_OBJECT_PATH, - PROP_STREAMS, - LAST_PROPERTY -}; - -/* private structure */ -struct _HazeMediaBackendPrivate -{ - gchar *conference_type; - gchar *object_path; - gpointer media; - GPtrArray *streams; - - guint next_stream_id; - gboolean ready; -}; - -static void -haze_media_backend_init (HazeMediaBackend *self) -{ - HazeMediaBackendPrivate *priv = G_TYPE_INSTANCE_GET_PRIVATE (self, - HAZE_TYPE_MEDIA_BACKEND, HazeMediaBackendPrivate); - - self->priv = priv; - - priv->next_stream_id = 1; - priv->streams = g_ptr_array_sized_new (1); -} - -static void -haze_media_backend_get_property (GObject *object, - guint property_id, - GValue *value, - GParamSpec *pspec) -{ - HazeMediaBackend *backend = HAZE_MEDIA_BACKEND (object); - HazeMediaBackendPrivate *priv = backend->priv; - - switch (property_id) - { - case PROP_CONFERENCE_TYPE: - g_value_set_string (value, priv->conference_type); - break; - case PROP_MEDIA: - g_value_set_object (value, priv->media); - break; - case PROP_OBJECT_PATH: - g_value_set_string (value, priv->object_path); - break; - case PROP_STREAMS: - g_value_set_boxed (value, priv->streams); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - break; - } -} - -static void -haze_media_backend_set_property (GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec) -{ - HazeMediaBackend *backend = HAZE_MEDIA_BACKEND (object); - HazeMediaBackendPrivate *priv = backend->priv; - - switch (property_id) - { - case PROP_CONFERENCE_TYPE: - g_free (priv->conference_type); - priv->conference_type = g_value_dup_string (value); - break; - case PROP_MEDIA: - g_assert (priv->media == NULL); - priv->media = g_value_get_object (value); - - g_object_add_weak_pointer(G_OBJECT(priv->media), &priv->media); - g_signal_connect (priv->media, "state-changed", - G_CALLBACK (haze_backend_state_changed_cb), backend); - break; - case PROP_OBJECT_PATH: - g_assert (priv->object_path == NULL); - priv->object_path = g_value_dup_string (value); - - if (priv->object_path != NULL) - { - TpDBusDaemon *dbus_daemon = tp_dbus_daemon_dup (NULL); - - g_return_if_fail (dbus_daemon != NULL); - tp_dbus_daemon_register_object (dbus_daemon, - priv->object_path, G_OBJECT (backend)); - g_object_unref (dbus_daemon); - } - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - break; - } -} - -static void haze_media_backend_dispose (GObject *object); -static void haze_media_backend_finalize (GObject *object); - -static void -haze_media_backend_class_init (HazeMediaBackendClass *haze_media_backend_class) -{ - GObjectClass *object_class = G_OBJECT_CLASS (haze_media_backend_class); - GParamSpec *param_spec; - - g_type_class_add_private (haze_media_backend_class, - sizeof (HazeMediaBackendPrivate)); - - object_class->get_property = haze_media_backend_get_property; - object_class->set_property = haze_media_backend_set_property; - - object_class->dispose = haze_media_backend_dispose; - object_class->finalize = haze_media_backend_finalize; - - g_object_class_override_property(object_class, PROP_CONFERENCE_TYPE, - "conference-type"); - g_object_class_override_property(object_class, PROP_MEDIA, "media"); - - param_spec = g_param_spec_string ("object-path", "D-Bus object path", - "The D-Bus object path used for this " - "object on the bus.", - NULL, - G_PARAM_READWRITE | - G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_OBJECT_PATH, param_spec); - - param_spec = g_param_spec_boxed ("streams", "Streams", - "List of streams handled by this backend.", - G_TYPE_PTR_ARRAY, - G_PARAM_READABLE | - G_PARAM_STATIC_NAME | - G_PARAM_STATIC_BLURB); - g_object_class_install_property (object_class, PROP_STREAMS, param_spec); -} - -void -haze_media_backend_dispose (GObject *object) -{ - DEBUG ("called"); - - if (G_OBJECT_CLASS (haze_media_backend_parent_class)->dispose) - G_OBJECT_CLASS (haze_media_backend_parent_class)->dispose (object); -} - -void -haze_media_backend_finalize (GObject *object) -{ - HazeMediaBackend *self = HAZE_MEDIA_BACKEND (object); - HazeMediaBackendPrivate *priv = self->priv; - - g_free (priv->conference_type); - g_free (priv->object_path); - - if (priv->streams != NULL) - g_ptr_array_free (priv->streams, TRUE); - - G_OBJECT_CLASS (haze_media_backend_parent_class)->finalize (object); -} - -static HazeMediaStream * -get_stream_by_name (HazeMediaBackend *self, - const gchar *sid) -{ - HazeMediaBackendPrivate *priv = self->priv; - guint i; - - for (i = 0; i < priv->streams->len; ++i) - { - HazeMediaStream *stream = g_ptr_array_index (priv->streams, i); - - if (!strcmp (sid, stream->name)) - return stream; - } - - return NULL; -} - -HazeMediaStream * -haze_media_backend_get_stream_by_name (HazeMediaBackend *self, - const gchar *sid) -{ - return get_stream_by_name (self, sid); -} - -static void -haze_backend_state_changed_cb (PurpleMedia *media, - PurpleMediaState state, - const gchar *sid, - const gchar *name, - HazeMediaBackend *backend) -{ - HazeMediaBackendPrivate *priv = backend->priv; - - if (state == PURPLE_MEDIA_STATE_END && sid != NULL && name == NULL) - { - HazeMediaStream *stream = get_stream_by_name (backend, sid); - - if (stream != NULL) - { - g_ptr_array_remove_fast (priv->streams, stream); - g_object_unref (stream); - } - } -} - -static void -_emit_new_stream (HazeMediaBackend *self, - HazeMediaStream *stream) -{ - gchar *object_path; - guint id, media_type; - - g_object_get (stream, - "object-path", &object_path, - "id", &id, - "media-type", &media_type, - NULL); - - /* all of the streams are bidirectional from farsight's point of view, it's - * just in the signalling they change */ - DEBUG ("emitting MediaSessionHandler:NewStreamHandler signal for %s stream %d", - media_type == TP_MEDIA_STREAM_TYPE_AUDIO ? "audio" : "video", id); - tp_svc_media_session_handler_emit_new_stream_handler (self, - object_path, id, media_type, TP_MEDIA_STREAM_DIRECTION_BIDIRECTIONAL); - - g_free (object_path); -} - -static gboolean -haze_media_backend_add_stream (PurpleMediaBackend *self, - const gchar *sid, const gchar *who, - PurpleMediaSessionType type, gboolean initiator, - const gchar *transmitter, - guint num_params, GParameter *params) -{ - HazeMediaBackendPrivate *priv = HAZE_MEDIA_BACKEND (self)->priv; - HazeMediaStream *stream; - gchar *object_path; - guint media_type, id, stun_port = 3478; /* default stun port */ - const gchar *nat_traversal = NULL, *stun_server = NULL; - TpDBusDaemon *dbus_daemon = tp_dbus_daemon_dup (NULL); - - DEBUG ("called"); - - g_return_val_if_fail (dbus_daemon != NULL, FALSE); - - id = priv->next_stream_id++; - - object_path = g_strdup_printf ("%s/MediaStream%u", - priv->object_path, id); - - if (type & PURPLE_MEDIA_AUDIO) - media_type = TP_MEDIA_STREAM_TYPE_AUDIO; - else - media_type = TP_MEDIA_STREAM_TYPE_VIDEO; - - if (!strcmp (transmitter, "nice")) - { - guint i; - - for (i = 0; i < num_params; ++i) - { - if (!strcmp (params[i].name, "compatibility-mode") && - G_VALUE_HOLDS (¶ms[i].value, G_TYPE_UINT)) - { - guint mode = g_value_get_uint (¶ms[i].value); - - switch (mode) - { - case 0: /* NICE_COMPATIBILITY_DRAFT19 */ - nat_traversal = "ice-udp"; - break; - case 1: /* NICE_COMPATIBILITY_GOOGLE */ - nat_traversal = "gtalk-p2p"; - break; - case 2: /* NICE_COMPATIBILITY_MSN */ - nat_traversal = "wlm-8.5"; - break; - case 3: /* NICE_COMPATIBILITY_WLM2009 */ - nat_traversal = "wlm-2009"; - break; - default: - g_assert_not_reached (); - } - } - else if (!strcmp (params[i].name, "stun-ip") && - G_VALUE_HOLDS (¶ms[i].value, G_TYPE_STRING)) - { - stun_server = g_value_get_string (¶ms[i].value); - } - else if (!strcmp (params[i].name, "stun-port") && - G_VALUE_HOLDS (¶ms[i].value, G_TYPE_UINT)) - { - stun_port = g_value_get_uint (¶ms[i].value); - } - } - - if (nat_traversal == NULL) - nat_traversal = "ice-udp"; - } - else if (!strcmp (transmitter, "rawudp")) - { - nat_traversal = "none"; - } - else - { - g_assert_not_reached (); - } - - stream = haze_media_stream_new (object_path, dbus_daemon, priv->media, - sid, who, media_type, id, initiator, nat_traversal, NULL, FALSE); - - if (stun_server != NULL) - haze_media_stream_add_stun_server (stream, stun_server, stun_port); - - g_free (object_path); - - DEBUG ("%p: created new MediaStream %p for sid '%s'", - self, stream, sid); - - g_ptr_array_add (priv->streams, stream); - - if (priv->ready) - _emit_new_stream (HAZE_MEDIA_BACKEND (self), stream); - - g_object_unref (dbus_daemon); - - return TRUE; -} - -static void -haze_media_backend_add_remote_candidates (PurpleMediaBackend *self, - const gchar *sid, - const gchar *who, - GList *remote_candidates) -{ - HazeMediaStream *stream; - - DEBUG ("called"); - - stream = get_stream_by_name (HAZE_MEDIA_BACKEND (self), sid); - - if (stream != NULL) - haze_media_stream_add_remote_candidates (stream, remote_candidates); - else - DEBUG ("Couldn't find stream"); -} - -static gboolean -haze_media_backend_codecs_ready (PurpleMediaBackend *self, - const gchar *sid) -{ - HazeMediaStream *stream; - gboolean ready = FALSE; - - DEBUG ("called"); - - if (sid != NULL) - { - stream = get_stream_by_name (HAZE_MEDIA_BACKEND (self), sid); - - if (stream != NULL) - g_object_get (stream, "codecs-ready", &ready, NULL); - - return ready; - } - else - { - HazeMediaBackendPrivate *priv = HAZE_MEDIA_BACKEND (self)->priv; - guint i; - - for (i = 0; i < priv->streams->len; ++i) - { - stream = g_ptr_array_index (priv->streams, i); - - if (stream != NULL) - g_object_get (stream, "codecs-ready", &ready, NULL); - - if (!ready) - return FALSE; - } - - return TRUE; - } -} - -static GList * -haze_media_backend_get_codecs (PurpleMediaBackend *self, - const gchar *sid) -{ - HazeMediaStream *stream; - GList *ret = NULL; - - DEBUG ("called"); - - stream = get_stream_by_name (HAZE_MEDIA_BACKEND (self), sid); - - if (stream != NULL) - ret = haze_media_stream_get_codecs (stream); - - return ret; -} - -static GList * -haze_media_backend_get_local_candidates (PurpleMediaBackend *self, - const gchar *sid, - const gchar *who) -{ - HazeMediaStream *stream; - GList *ret = NULL; - - DEBUG ("called"); - - stream = get_stream_by_name (HAZE_MEDIA_BACKEND (self), sid); - - if (stream != NULL) - ret = haze_media_stream_get_local_candidates (stream); - - return ret; -} - -static gboolean -haze_media_backend_set_remote_codecs (PurpleMediaBackend *self, - const gchar *sid, - const gchar *who, - GList *codecs) -{ - HazeMediaStream *stream; - - DEBUG ("called"); - - stream = get_stream_by_name (HAZE_MEDIA_BACKEND (self), sid); - - if (stream != NULL) - haze_media_stream_set_remote_codecs (stream, codecs); - else - DEBUG ("Couldn't find stream"); - - return TRUE; -} - -static gboolean -haze_media_backend_set_send_codec (PurpleMediaBackend *self, - const gchar *sid, - PurpleMediaCodec *codec) -{ - return FALSE; -} - -static void -haze_media_backend_ready (TpSvcMediaSessionHandler *iface, - DBusGMethodInvocation *context) -{ - HazeMediaBackend *self = HAZE_MEDIA_BACKEND (iface); - HazeMediaBackendPrivate *priv = self->priv; - - if (!priv->ready) - { - guint i; - - DEBUG ("emitting NewStreamHandler for each stream"); - - priv->ready = TRUE; - - for (i = 0; i < priv->streams->len; i++) - _emit_new_stream (self, g_ptr_array_index (priv->streams, i)); - } - - tp_svc_media_session_handler_return_from_ready (context); -} - -static void -haze_media_backend_error (TpSvcMediaSessionHandler *iface, - guint errno, - const gchar *message, - DBusGMethodInvocation *context) -{ - HazeMediaBackend *self = HAZE_MEDIA_BACKEND (iface); - HazeMediaBackendPrivate *priv; - GPtrArray *tmp; - guint i; - - g_assert (HAZE_IS_MEDIA_BACKEND (self)); - - priv = self->priv; - - if (priv->media == NULL) - { - /* This could also be because someone called Error() before the - * SessionHandler was announced. But the fact that the SessionHandler is - * actually also the Channel, and thus this method is available before - * NewSessionHandler is emitted, is an implementation detail. So the - * error message describes the only legitimate situation in which this - * could arise. - */ - GError e = { TP_ERROR, TP_ERROR_NOT_AVAILABLE, "call has already ended" }; - - DEBUG ("no session, returning an error."); - dbus_g_method_return_error (context, &e); - return; - } - - DEBUG ("Media.SessionHandler::Error called, error %u (%s) -- " - "emitting error on each stream", errno, message); - - purple_media_end (priv->media, NULL, NULL); - - /* Calling haze_media_stream_error () on all the streams will ultimately - * cause them all to emit 'closed'. In response to 'closed', stream_close_cb - * unrefs them, and removes them from priv->streams. So, we copy the stream - * list to avoid it being modified from underneath us. - */ - tmp = g_ptr_array_sized_new (priv->streams->len); - - for (i = 0; i < priv->streams->len; i++) - g_ptr_array_add (tmp, g_ptr_array_index (priv->streams, i)); - - for (i = 0; i < tmp->len; i++) - { - HazeMediaStream *stream = g_ptr_array_index (tmp, i); - - haze_media_stream_error (stream, errno, message, NULL); - } - - g_ptr_array_free (tmp, TRUE); - - tp_svc_media_session_handler_return_from_error (context); -} - -static void -media_backend_iface_init (PurpleMediaBackendIface *iface) -{ -#define IMPLEMENT(x) iface->x = haze_media_backend_##x - IMPLEMENT(add_stream); - IMPLEMENT(add_remote_candidates); - IMPLEMENT(codecs_ready); - IMPLEMENT(get_codecs); - IMPLEMENT(get_local_candidates); - IMPLEMENT(set_remote_codecs); - IMPLEMENT(set_send_codec); -#undef IMPLEMENT -} - -static void -session_handler_iface_init (gpointer g_iface, gpointer iface_data) -{ - TpSvcMediaSessionHandlerClass *klass = - (TpSvcMediaSessionHandlerClass *) g_iface; - -#define IMPLEMENT(x) tp_svc_media_session_handler_implement_##x (\ - klass, haze_media_backend_##x) - IMPLEMENT(error); - IMPLEMENT(ready); -#undef IMPLEMENT -} diff --git a/src/media-backend.h b/src/media-backend.h deleted file mode 100644 index d673c55..0000000 --- a/src/media-backend.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * media-backend.h - Header for HazeMediaBackend - * Copyright (C) 2006, 2009 Collabora Ltd. - * Copyright (C) 2006 Nokia Corporation - * - * 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 - */ - -#ifndef __HAZE_MEDIA_BACKEND__ -#define __HAZE_MEDIA_BACKEND__ - -#include - -#include "media-stream.h" - -G_BEGIN_DECLS - -typedef struct _HazeMediaBackend HazeMediaBackend; -typedef struct _HazeMediaBackendClass HazeMediaBackendClass; -typedef struct _HazeMediaBackendPrivate HazeMediaBackendPrivate; - -struct _HazeMediaBackendClass { - GObjectClass parent_class; -}; - -struct _HazeMediaBackend { - GObject parent; - - HazeMediaBackendPrivate *priv; -}; - -GType haze_media_backend_get_type (void); -HazeMediaStream *haze_media_backend_get_stream_by_name ( - HazeMediaBackend *self, - const gchar *sid); - -/* TYPE MACROS */ -#define HAZE_TYPE_MEDIA_BACKEND \ - (haze_media_backend_get_type ()) -#define HAZE_MEDIA_BACKEND(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), HAZE_TYPE_MEDIA_BACKEND, \ - HazeMediaBackend)) -#define HAZE_MEDIA_BACKEND_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), HAZE_TYPE_MEDIA_BACKEND, \ - HazeMediaBackendClass)) -#define HAZE_IS_MEDIA_BACKEND(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj), HAZE_TYPE_MEDIA_BACKEND)) -#define HAZE_IS_MEDIA_BACKEND_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass), HAZE_TYPE_MEDIA_BACKEND)) -#define HAZE_MEDIA_BACKEND_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS ((obj), HAZE_TYPE_MEDIA_BACKEND, \ - HazeMediaBackendClass)) - -G_END_DECLS - -#endif /* #ifndef __HAZE_MEDIA_BACKEND__ */ diff --git a/src/media-channel.c b/src/media-channel.c deleted file mode 100644 index 1cfd4d8..0000000 --- a/src/media-channel.c +++ /dev/null @@ -1,1760 +0,0 @@ -/* - * media-channel.c - Source for HazeMediaChannel - * Copyright (C) 2006, 2009 Collabora Ltd. - * Copyright (C) 2006 Nokia Corporation - * - * Copied heavily from telepathy-gabble - * - * 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 - */ - -#include "config.h" -#include "media-channel.h" - -#include -#include -#include - -#include "connection.h" -#include "debug.h" -#include "media-backend.h" -#include "media-stream.h" - -static void channel_iface_init (gpointer, gpointer); -static void media_signalling_iface_init (gpointer, gpointer); -static void streamed_media_iface_init (gpointer, gpointer); -static gboolean haze_media_channel_add_member (GObject *obj, - TpHandle handle, - const gchar *message, - GError **error); -static gboolean haze_media_channel_remove_member (GObject *obj, - TpHandle handle, const gchar *message, guint reason, GError **error); - -G_DEFINE_TYPE_WITH_CODE (HazeMediaChannel, haze_media_channel, - G_TYPE_OBJECT, - G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL, channel_iface_init); - G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_INTERFACE_GROUP, - tp_group_mixin_iface_init); - G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_TYPE_STREAMED_MEDIA, - streamed_media_iface_init); - G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_INTERFACE_MEDIA_SIGNALLING, - media_signalling_iface_init); - G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_DBUS_PROPERTIES, - tp_dbus_properties_mixin_iface_init); - G_IMPLEMENT_INTERFACE (TP_TYPE_EXPORTABLE_CHANNEL, NULL); - G_IMPLEMENT_INTERFACE (TP_TYPE_CHANNEL_IFACE, NULL)); - -static const gchar *haze_media_channel_interfaces[] = { - TP_IFACE_CHANNEL_INTERFACE_GROUP, - TP_IFACE_CHANNEL_INTERFACE_MEDIA_SIGNALLING, - NULL -}; - -/* properties */ -enum -{ - PROP_OBJECT_PATH = 1, - PROP_CHANNEL_TYPE, - PROP_HANDLE_TYPE, - PROP_HANDLE, - PROP_TARGET_ID, - PROP_INITIAL_PEER, - PROP_PEER, - PROP_REQUESTED, - PROP_CONNECTION, - PROP_CREATOR, - PROP_CREATOR_ID, - PROP_INTERFACES, - PROP_CHANNEL_DESTROYED, - PROP_CHANNEL_PROPERTIES, - PROP_INITIAL_AUDIO, - PROP_INITIAL_VIDEO, - PROP_MEDIA, - LAST_PROPERTY -}; - -struct _HazeMediaChannelPrivate -{ - HazeConnection *conn; - gchar *object_path; - TpHandle creator; - TpHandle initial_peer; - - PurpleMedia *media; - - guint next_stream_id; - - /* list of PendingStreamRequest* in no particular order */ - GList *pending_stream_requests; - - TpLocalHoldState hold_state; - TpLocalHoldStateReason hold_state_reason; - - TpChannelCallStateFlags call_state; - - gboolean initial_audio; - gboolean initial_video; - - gboolean ready; - gboolean media_ended; - gboolean closed; - gboolean dispose_has_run; -}; - -static void -haze_media_channel_init (HazeMediaChannel *self) -{ - HazeMediaChannelPrivate *priv = G_TYPE_INSTANCE_GET_PRIVATE (self, - HAZE_TYPE_MEDIA_CHANNEL, HazeMediaChannelPrivate); - - self->priv = priv; - - priv->next_stream_id = 1; -} - -/** - * make_stream_list: - * - * Creates an array of MediaStreamInfo structs. - */ -static GPtrArray * -make_stream_list (HazeMediaChannel *self, - guint len, - HazeMediaStream **streams) -{ - HazeMediaChannelPrivate *priv = self->priv; - GPtrArray *ret; - guint i; - GType info_type = TP_STRUCT_TYPE_MEDIA_STREAM_INFO; - - ret = g_ptr_array_sized_new (len); - - for (i = 0; i < len; i++) - { - GValue entry = { 0, }; - guint id; - TpHandle peer; - TpMediaStreamType type; - TpMediaStreamState connection_state; - CombinedStreamDirection combined_direction; - - g_object_get (streams[i], - "id", &id, - "media-type", &type, - "connection-state", &connection_state, - "combined-direction", &combined_direction, - NULL); - - peer = priv->initial_peer; - - g_value_init (&entry, info_type); - g_value_take_boxed (&entry, - dbus_g_type_specialized_construct (info_type)); - - dbus_g_type_struct_set (&entry, - 0, id, - 1, peer, - 2, type, - 3, connection_state, - 4, COMBINED_DIRECTION_GET_DIRECTION (combined_direction), - 5, COMBINED_DIRECTION_GET_PENDING_SEND (combined_direction), - G_MAXUINT); - - g_ptr_array_add (ret, g_value_get_boxed (&entry)); - } - - return ret; -} - -typedef struct { - /* number of streams requested == number of content objects */ - guint len; - /* array of @len borrowed pointers */ - guint *types; - /* accumulates borrowed pointers to streams. Initially @len NULL pointers; - * when the stream for contents[i] is created, it is stored at streams[i]. - */ - HazeMediaStream **streams; - /* number of non-NULL elements in streams (0 <= satisfied <= contents) */ - guint satisfied; - /* succeeded_cb(context, GPtrArray) - * will be called if the stream request succeeds. - */ - GFunc succeeded_cb; - /* failed_cb(context, GError *) will be called if the stream request fails. - */ - GFunc failed_cb; - gpointer context; -} PendingStreamRequest; - -static PendingStreamRequest * -pending_stream_request_new (const GArray *types, - GFunc succeeded_cb, - GFunc failed_cb, - gpointer context) -{ - PendingStreamRequest *p = g_slice_new0 (PendingStreamRequest); - - g_assert (succeeded_cb); - g_assert (failed_cb); - - p->len = types->len; - p->types = g_memdup (types->data, types->len * sizeof (gpointer)); - p->streams = g_new0 (HazeMediaStream *, types->len); - p->satisfied = 0; - p->succeeded_cb = succeeded_cb; - p->failed_cb = failed_cb; - p->context = context; - - return p; -} - -static gboolean -pending_stream_request_maybe_satisfy (PendingStreamRequest *p, - HazeMediaChannel *channel, - guint type, - HazeMediaStream *stream) -{ - guint i; - - for (i = 0; i < p->len; i++) - { - if (p->types[i] == type) - { - g_assert (p->streams[i] == NULL); - p->streams[i] = stream; - - if (++p->satisfied == p->len && p->context != NULL) - { - GPtrArray *ret = make_stream_list (channel, p->len, p->streams); - - p->succeeded_cb (p->context, ret); - g_ptr_array_foreach (ret, (GFunc) g_value_array_free, NULL); - g_ptr_array_free (ret, TRUE); - p->context = NULL; - return TRUE; - } - } - } - - return FALSE; -} - -static void -pending_stream_request_free (gpointer data) -{ - PendingStreamRequest *p = data; - - if (p->context != NULL) - { - GError e = { TP_ERROR, TP_ERROR_CANCELLED, - "The session terminated before the requested streams could be added" - }; - - p->failed_cb (p->context, &e); - } - - g_free (p->types); - g_free (p->streams); - - g_slice_free (PendingStreamRequest, p); -} - -static void -stream_direction_changed_cb (HazeMediaStream *stream, - GParamSpec *pspec, - HazeMediaChannel *chan) -{ - guint id; - CombinedStreamDirection combined; - TpMediaStreamDirection direction; - TpMediaStreamPendingSend pending_send; - - g_object_get (stream, - "id", &id, - "combined-direction", &combined, - NULL); - - direction = COMBINED_DIRECTION_GET_DIRECTION (combined); - pending_send = COMBINED_DIRECTION_GET_PENDING_SEND (combined); - - DEBUG ("direction: %u, pending_send: %u", direction, pending_send); - - tp_svc_channel_type_streamed_media_emit_stream_direction_changed ( - chan, id, direction, pending_send); -} - -static void -media_error_cb (PurpleMedia *media, - const gchar *error, - HazeMediaChannel *chan) -{ - g_assert (HAZE_MEDIA_CHANNEL(chan)->priv != NULL); - DEBUG ("Media error on %s: %s", chan->priv->object_path, error); -} - -static void -media_state_changed_cb (PurpleMedia *media, - PurpleMediaState state, - gchar *sid, gchar *name, - HazeMediaChannel *chan) -{ - HazeMediaChannelPrivate *priv = chan->priv; - - DEBUG ("%s %s %s", - state == PURPLE_MEDIA_STATE_NEW ? "NEW" : - state == PURPLE_MEDIA_STATE_CONNECTED ? "CONNECTED" : - state == PURPLE_MEDIA_STATE_END ? "END" : - "UNKNOWN", sid, name); - - if (state == PURPLE_MEDIA_STATE_NEW) - { - if (sid != NULL && name != NULL) - { - HazeMediaBackend *backend; - HazeMediaStream *stream; - TpMediaStreamType type; - guint id; - - g_object_get (priv->media, "backend", &backend, NULL); - stream = haze_media_backend_get_stream_by_name (backend, sid); - g_object_unref (backend); - - g_object_get (G_OBJECT (stream), "id", &id, NULL); - type = haze_media_stream_get_media_type (stream); - - /* if any RequestStreams call was waiting for a stream to be created for - * that content, return from it successfully */ - { - GList *iter = priv->pending_stream_requests; - - while (iter != NULL) - { - if (pending_stream_request_maybe_satisfy (iter->data, - chan, type, stream)) - { - GList *dead = iter; - - pending_stream_request_free (dead->data); - - iter = dead->next; - priv->pending_stream_requests = g_list_delete_link ( - priv->pending_stream_requests, dead); - } - else - { - iter = iter->next; - } - } - } - - g_signal_connect (stream, "notify::combined-direction", - (GCallback) stream_direction_changed_cb, chan); - - tp_svc_channel_type_streamed_media_emit_stream_added ( - chan, id, priv->initial_peer, type); - - stream_direction_changed_cb (stream, NULL, chan); - } - } - - if (sid != NULL && name == NULL) - { - TpMediaStreamState tp_state; - HazeMediaBackend *backend; - HazeMediaStream *stream; - - if (state == PURPLE_MEDIA_STATE_NEW) - tp_state = TP_MEDIA_STREAM_STATE_CONNECTING; - else if (state == PURPLE_MEDIA_STATE_CONNECTED) - tp_state = TP_MEDIA_STREAM_STATE_CONNECTED; - else if (state == PURPLE_MEDIA_STATE_END) - tp_state = TP_MEDIA_STREAM_STATE_DISCONNECTED; - else - { - DEBUG ("Invalid state %d", state); - return; - } - - g_object_get (G_OBJECT (priv->media), "backend", &backend, NULL); - stream = haze_media_backend_get_stream_by_name (backend, sid); - g_object_unref (backend); - - if (stream != NULL) - { - guint id; - g_object_get (stream, "id", &id, NULL); - tp_svc_channel_type_streamed_media_emit_stream_state_changed (chan, - id, tp_state); - } - } - - if (state == PURPLE_MEDIA_STATE_END) - { - if (sid != NULL && name == NULL) - { - HazeMediaBackend *backend; - HazeMediaStream *stream; - - g_object_get (G_OBJECT (priv->media), "backend", &backend, NULL); - stream = haze_media_backend_get_stream_by_name (backend, sid); - g_object_unref (backend); - - if (stream != NULL) - { - guint id; - g_object_get (stream, "id", &id, NULL); - tp_svc_channel_type_streamed_media_emit_stream_removed ( - chan, id); - } - } - else if (sid == NULL && name == NULL) - { - TpGroupMixin *mixin = TP_GROUP_MIXIN (chan); - guint terminator; - TpHandle peer; - TpIntset *set; - - priv->media_ended = TRUE; - - peer = priv->initial_peer; - - /* - * Primarily, sessions will be ended with hangup or reject. Any that - * aren't are because of local errors so set the terminator to self. - */ - terminator = mixin->self_handle; - - set = tp_intset_new (); - - /* remove us and the peer from the member list */ - tp_intset_add (set, mixin->self_handle); - tp_intset_add (set, peer); - - tp_group_mixin_change_members ((GObject *) chan, - "Media session ended", NULL, set, NULL, NULL, - terminator, TP_CHANNEL_GROUP_CHANGE_REASON_NONE); - - tp_intset_destroy (set); - - /* any contents that we were waiting for have now lost */ - g_list_foreach (priv->pending_stream_requests, - (GFunc) pending_stream_request_free, NULL); - g_list_free (priv->pending_stream_requests); - priv->pending_stream_requests = NULL; - - if (!priv->closed) - { - DEBUG ("calling media channel close from state changed cb"); - haze_media_channel_close (chan); - } - } - } -} - -static void -media_stream_info_cb(PurpleMedia *media, - PurpleMediaInfoType type, - gchar *sid, - gchar *name, - gboolean local, - HazeMediaChannel *chan) -{ - HazeMediaChannelPrivate *priv = chan->priv; - TpBaseConnection *conn = (TpBaseConnection *)priv->conn; - - if (type == PURPLE_MEDIA_INFO_ACCEPT) - { - TpIntset *set; - TpHandle actor; - - if (local == FALSE) - actor = priv->initial_peer; - else - actor = tp_base_connection_get_self_handle (conn); - - set = tp_intset_new_containing (actor); - - /* add the peer to the member list */ - tp_group_mixin_change_members (G_OBJECT (chan), "", set, NULL, NULL, - NULL, actor, TP_CHANNEL_GROUP_CHANGE_REASON_NONE); - - if (sid != NULL && name == NULL && purple_media_is_initiator ( - media, sid, name) == FALSE) - { - HazeMediaBackend *backend; - HazeMediaStream *stream; - - g_object_get (G_OBJECT (priv->media), "backend", &backend, NULL); - stream = haze_media_backend_get_stream_by_name (backend, sid); - g_object_unref (backend); - - g_object_set (stream, "combined-direction", - MAKE_COMBINED_DIRECTION ( - TP_MEDIA_STREAM_DIRECTION_BIDIRECTIONAL, 0), NULL); - } - } - else if (type == PURPLE_MEDIA_INFO_REJECT || - type == PURPLE_MEDIA_INFO_HANGUP) - { - TpGroupMixin *mixin = TP_GROUP_MIXIN (chan); - guint terminator; - TpIntset *set; - - if (sid != NULL) - return; - - if (local == TRUE) - terminator = tp_base_connection_get_self_handle (conn); - else - /* This will need to get the handle from name for multi-user calls */ - terminator = priv->initial_peer; - - set = tp_intset_new (); - - if (name != NULL) - /* Remove participant */ - tp_intset_add (set, priv->initial_peer); - else - /* Remove us */ - tp_intset_add (set, mixin->self_handle); - - tp_group_mixin_change_members ((GObject *) chan, - NULL, NULL, set, NULL, NULL, terminator, - TP_CHANNEL_GROUP_CHANGE_REASON_NONE); - - tp_intset_destroy (set); - } -} - -static void -_latch_to_session (HazeMediaChannel *chan) -{ - HazeMediaChannelPrivate *priv = chan->priv; - HazeMediaBackend *backend; - gchar *object_path; - - g_assert (priv->media != NULL); - - DEBUG ("%p: Latching onto session %p", chan, priv->media); - - g_signal_connect(G_OBJECT(priv->media), "error", - G_CALLBACK(media_error_cb), chan); - g_signal_connect(G_OBJECT(priv->media), "state-changed", - G_CALLBACK(media_state_changed_cb), chan); - g_signal_connect(G_OBJECT(priv->media), "stream-info", - G_CALLBACK(media_stream_info_cb), chan); - - object_path = g_strdup_printf ("%s/MediaSession0", priv->object_path); - - g_object_get (G_OBJECT (priv->media), "backend", &backend, NULL); - g_object_set (G_OBJECT (backend), "object-path", object_path, NULL); - g_object_unref (backend); - - tp_svc_channel_interface_media_signalling_emit_new_session_handler ( - G_OBJECT (chan), object_path, "rtp"); - - g_free (object_path); -} - -static GObject * -haze_media_channel_constructor (GType type, guint n_props, - GObjectConstructParam *props) -{ - GObject *obj; - HazeMediaChannelPrivate *priv; - TpBaseConnection *conn; - TpDBusDaemon *bus; - TpIntset *set; - TpHandleRepoIface *contact_handles; - TpHandle self_handle; - - obj = G_OBJECT_CLASS (haze_media_channel_parent_class)-> - constructor (type, n_props, props); - - priv = HAZE_MEDIA_CHANNEL (obj)->priv; - conn = (TpBaseConnection *) priv->conn; - contact_handles = tp_base_connection_get_handles (conn, - TP_HANDLE_TYPE_CONTACT); - self_handle = tp_base_connection_get_self_handle (conn); - - /* register object on the bus */ - bus = tp_base_connection_get_dbus_daemon (conn); - tp_dbus_daemon_register_object (bus, priv->object_path, obj); - - tp_group_mixin_init (obj, G_STRUCT_OFFSET (HazeMediaChannel, group), - contact_handles, self_handle); - - if (priv->media != NULL) - priv->creator = priv->initial_peer; - else - priv->creator = self_handle; - - /* automatically add creator to channel, but also ref them again (because - * priv->creator is the InitiatorHandle) */ - g_assert (priv->creator != 0); - - set = tp_intset_new_containing (priv->creator); - tp_group_mixin_change_members (obj, "", set, NULL, NULL, NULL, 0, - TP_CHANNEL_GROUP_CHANGE_REASON_NONE); - tp_intset_destroy (set); - - /* We implement the 0.17.6 properties correctly, and can include a message - * when ending a call. - */ - tp_group_mixin_change_flags (obj, - TP_CHANNEL_GROUP_FLAG_PROPERTIES | - TP_CHANNEL_GROUP_FLAG_MESSAGE_REMOVE | - TP_CHANNEL_GROUP_FLAG_MESSAGE_REJECT | - TP_CHANNEL_GROUP_FLAG_MESSAGE_RESCIND, - 0); - - - if (priv->media != NULL) - { - /* This is an incoming call; make us local pending and don't set any - * group flags (all we can do is add or remove ourselves, which is always - * valid per the spec) - */ - set = tp_intset_new_containing (self_handle); - tp_group_mixin_change_members (obj, "", NULL, NULL, set, NULL, - priv->initial_peer, TP_CHANNEL_GROUP_CHANGE_REASON_INVITED); - tp_intset_destroy (set); - - /* Set up signal callbacks */ - _latch_to_session (HAZE_MEDIA_CHANNEL (obj)); - } - - return obj; -} - -static void -haze_media_channel_get_property (GObject *object, - guint property_id, - GValue *value, - GParamSpec *pspec) -{ - HazeMediaChannel *chan = HAZE_MEDIA_CHANNEL (object); - HazeMediaChannelPrivate *priv = chan->priv; - TpBaseConnection *base_conn = (TpBaseConnection *) priv->conn; - - switch (property_id) { - case PROP_OBJECT_PATH: - g_value_set_string (value, priv->object_path); - break; - case PROP_CHANNEL_TYPE: - g_value_set_static_string (value, TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA); - break; - case PROP_HANDLE_TYPE: - /* This is used to implement TargetHandleType, which is immutable. If - * the peer was known at channel-creation time, this will be Contact; - * otherwise, it must be None even if we subsequently learn who the peer - * is. - */ - if (priv->initial_peer != 0) - g_value_set_uint (value, TP_HANDLE_TYPE_CONTACT); - else - g_value_set_uint (value, TP_HANDLE_TYPE_NONE); - break; - case PROP_INITIAL_PEER: - case PROP_HANDLE: - /* As above: TargetHandle is immutable, so non-0 only if the peer handle - * was known at creation time. - */ - g_value_set_uint (value, priv->initial_peer); - break; - case PROP_TARGET_ID: - /* As above. */ - if (priv->initial_peer != 0) - { - TpHandleRepoIface *repo = tp_base_connection_get_handles ( - base_conn, TP_HANDLE_TYPE_CONTACT); - const gchar *target_id = tp_handle_inspect (repo, priv->initial_peer); - - g_value_set_string (value, target_id); - } - else - { - g_value_set_static_string (value, ""); - } - - break; - case PROP_PEER: - { - TpHandle peer = 0; - - if (priv->initial_peer != 0) - peer = priv->initial_peer; - - g_value_set_uint (value, peer); - break; - } - case PROP_CONNECTION: - g_value_set_object (value, priv->conn); - break; - case PROP_CREATOR: - g_value_set_uint (value, priv->creator); - break; - case PROP_CREATOR_ID: - { - TpHandleRepoIface *repo = tp_base_connection_get_handles ( - base_conn, TP_HANDLE_TYPE_CONTACT); - - g_value_set_string (value, tp_handle_inspect (repo, priv->creator)); - } - break; - case PROP_REQUESTED: - g_value_set_boolean (value, (priv->creator == - tp_base_connection_get_self_handle (base_conn))); - break; - case PROP_INTERFACES: - g_value_set_boxed (value, haze_media_channel_interfaces); - break; - case PROP_CHANNEL_DESTROYED: - g_value_set_boolean (value, priv->closed); - break; - case PROP_CHANNEL_PROPERTIES: - g_value_take_boxed (value, - tp_dbus_properties_mixin_make_properties_hash (object, - TP_IFACE_CHANNEL, "TargetHandle", - TP_IFACE_CHANNEL, "TargetHandleType", - TP_IFACE_CHANNEL, "ChannelType", - TP_IFACE_CHANNEL, "TargetID", - TP_IFACE_CHANNEL, "InitiatorHandle", - TP_IFACE_CHANNEL, "InitiatorID", - TP_IFACE_CHANNEL, "Requested", - TP_IFACE_CHANNEL, "Interfaces", - TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA, "InitialAudio", - TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA, "InitialVideo", - NULL)); - break; - case PROP_MEDIA: - g_value_set_object (value, priv->media); - break; - case PROP_INITIAL_AUDIO: - g_value_set_boolean (value, priv->initial_audio); - break; - case PROP_INITIAL_VIDEO: - g_value_set_boolean (value, priv->initial_video); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - break; - } -} - -static void -haze_media_channel_set_property (GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec) -{ - HazeMediaChannel *chan = HAZE_MEDIA_CHANNEL (object); - HazeMediaChannelPrivate *priv = chan->priv; - - switch (property_id) { - case PROP_OBJECT_PATH: - g_free (priv->object_path); - priv->object_path = g_value_dup_string (value); - break; - case PROP_HANDLE_TYPE: - case PROP_HANDLE: - case PROP_CHANNEL_TYPE: - /* these properties are writable in the interface, but not actually - * meaningfully changable on this channel, so we do nothing */ - break; - case PROP_CONNECTION: - priv->conn = g_value_get_object (value); - break; - case PROP_CREATOR: - priv->creator = g_value_get_uint (value); - break; - case PROP_INITIAL_PEER: - priv->initial_peer = g_value_get_uint (value); - break; - case PROP_MEDIA: - g_assert (priv->media == NULL); - priv->media = g_value_dup_object (value); - break; - case PROP_INITIAL_AUDIO: - priv->initial_audio = g_value_get_boolean (value); - break; - case PROP_INITIAL_VIDEO: - priv->initial_video = g_value_get_boolean (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - break; - } -} - -static void haze_media_channel_dispose (GObject *object); -static void haze_media_channel_finalize (GObject *object); - -static void -haze_media_channel_class_init (HazeMediaChannelClass *haze_media_channel_class) -{ - static TpDBusPropertiesMixinPropImpl channel_props[] = { - { "TargetHandleType", "handle-type", NULL }, - { "TargetHandle", "handle", NULL }, - { "TargetID", "target-id", NULL }, - { "ChannelType", "channel-type", NULL }, - { "Interfaces", "interfaces", NULL }, - { "Requested", "requested", NULL }, - { "InitiatorHandle", "creator", NULL }, - { "InitiatorID", "creator-id", NULL }, - { NULL } - }; - static TpDBusPropertiesMixinPropImpl streamed_media_props[] = { - { "InitialAudio", "initial-audio", NULL }, - { "InitialVideo", "initial-video", NULL }, - { NULL } - }; - static TpDBusPropertiesMixinIfaceImpl prop_interfaces[] = { - { TP_IFACE_CHANNEL, - tp_dbus_properties_mixin_getter_gobject_properties, - NULL, - channel_props, - }, - { TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA, - tp_dbus_properties_mixin_getter_gobject_properties, - NULL, - streamed_media_props, - }, - { NULL } - }; - GObjectClass *object_class = G_OBJECT_CLASS (haze_media_channel_class); - GParamSpec *param_spec; - - g_type_class_add_private (haze_media_channel_class, - sizeof (HazeMediaChannelPrivate)); - - object_class->constructor = haze_media_channel_constructor; - - object_class->get_property = haze_media_channel_get_property; - object_class->set_property = haze_media_channel_set_property; - - object_class->dispose = haze_media_channel_dispose; - object_class->finalize = haze_media_channel_finalize; - - g_object_class_override_property (object_class, PROP_OBJECT_PATH, - "object-path"); - g_object_class_override_property (object_class, PROP_CHANNEL_TYPE, - "channel-type"); - g_object_class_override_property (object_class, PROP_HANDLE_TYPE, - "handle-type"); - g_object_class_override_property (object_class, PROP_HANDLE, "handle"); - - g_object_class_override_property (object_class, PROP_CHANNEL_DESTROYED, - "channel-destroyed"); - g_object_class_override_property (object_class, PROP_CHANNEL_PROPERTIES, - "channel-properties"); - - param_spec = g_param_spec_string ("target-id", "Target ID", - "The string that would result from inspecting TargetHandle", - NULL, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_TARGET_ID, param_spec); - - param_spec = g_param_spec_uint ("initial-peer", "Other participant", - "The TpHandle representing the other participant in the channel if known " - "at construct-time; 0 if the other participant was unknown at the time " - "of channel creation", - 0, G_MAXUINT32, 0, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_INITIAL_PEER, param_spec); - - param_spec = g_param_spec_uint ("peer", "Other participant", - "The TpHandle representing the other participant in the channel if " - "currently known; 0 if this is an anonymous channel on which " - "RequestStreams has not yet been called.", - 0, G_MAXUINT32, 0, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_PEER, param_spec); - - param_spec = g_param_spec_object ("connection", "HazeConnection object", - "Haze connection object that owns this media channel object.", - HAZE_TYPE_CONNECTION, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_CONNECTION, param_spec); - - param_spec = g_param_spec_uint ("creator", "Channel creator", - "The TpHandle representing the contact who created the channel.", - 0, G_MAXUINT32, 0, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_CREATOR, param_spec); - - param_spec = g_param_spec_string ("creator-id", "Creator ID", - "The ID obtained by inspecting the creator handle.", - NULL, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_CREATOR_ID, param_spec); - - param_spec = g_param_spec_boolean ("requested", "Requested?", - "True if this channel was requested by the local user", - FALSE, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_REQUESTED, param_spec); - - param_spec = g_param_spec_boxed ("interfaces", "Extra D-Bus interfaces", - "Additional Channel.Interface.* interfaces", - G_TYPE_STRV, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_INTERFACES, param_spec); - - param_spec = g_param_spec_object ("media", "PurpleMedia object", - "Purple media associated with this media channel object.", - PURPLE_TYPE_MEDIA, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | - G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB); - g_object_class_install_property (object_class, PROP_MEDIA, param_spec); - - param_spec = g_param_spec_boolean ("initial-audio", "InitialAudio", - "Whether the channel initially contained an audio stream", - FALSE, - G_PARAM_CONSTRUCT_ONLY | 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_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_INITIAL_VIDEO, - param_spec); - - haze_media_channel_class->dbus_props_class.interfaces = prop_interfaces; - tp_dbus_properties_mixin_class_init (object_class, - G_STRUCT_OFFSET (HazeMediaChannelClass, dbus_props_class)); - - tp_group_mixin_class_init (object_class, - G_STRUCT_OFFSET (HazeMediaChannelClass, group_class), - haze_media_channel_add_member, NULL); - tp_group_mixin_class_set_remove_with_reason_func (object_class, - haze_media_channel_remove_member); - tp_group_mixin_class_allow_self_removal (object_class); - - tp_group_mixin_init_dbus_properties (object_class); -} - -void -haze_media_channel_dispose (GObject *object) -{ - HazeMediaChannel *self = HAZE_MEDIA_CHANNEL (object); - HazeMediaChannelPrivate *priv = self->priv; - - if (priv->dispose_has_run) - return; - - DEBUG ("called"); - - priv->dispose_has_run = TRUE; - - if (!priv->closed) - haze_media_channel_close (self); - - g_assert (priv->closed); - - if (priv->media != NULL) - g_object_unref (priv->media); - priv->media = NULL; - - if (G_OBJECT_CLASS (haze_media_channel_parent_class)->dispose) - G_OBJECT_CLASS (haze_media_channel_parent_class)->dispose (object); -} - -void -haze_media_channel_finalize (GObject *object) -{ - HazeMediaChannel *self = HAZE_MEDIA_CHANNEL (object); - HazeMediaChannelPrivate *priv = self->priv; - - g_free (priv->object_path); - - tp_group_mixin_finalize (object); - - G_OBJECT_CLASS (haze_media_channel_parent_class)->finalize (object); -} - - -/** - * haze_media_channel_close_async: - * - * Implements D-Bus method Close - * on interface org.freedesktop.Telepathy.Channel - */ -static void -haze_media_channel_close_async (TpSvcChannel *iface, - DBusGMethodInvocation *context) -{ - HazeMediaChannel *self = HAZE_MEDIA_CHANNEL (iface); - - DEBUG ("called"); - haze_media_channel_close (self); - tp_svc_channel_return_from_close (context); -} - -void -haze_media_channel_close (HazeMediaChannel *self) -{ - HazeMediaChannelPrivate *priv = self->priv; - - DEBUG ("called on %p", self); - - if (!priv->closed) - { - priv->closed = TRUE; - - if (priv->media && !priv->media_ended) - { - priv->media_ended = TRUE; - purple_media_stream_info (priv->media, - PURPLE_MEDIA_INFO_HANGUP, NULL, NULL, FALSE); - } - - tp_svc_channel_emit_closed (self); - } -} - - -/** - * haze_media_channel_get_channel_type - * - * Implements D-Bus method GetChannelType - * on interface org.freedesktop.Telepathy.Channel - */ -static void -haze_media_channel_get_channel_type (TpSvcChannel *iface, - DBusGMethodInvocation *context) -{ - tp_svc_channel_return_from_get_channel_type (context, - TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA); -} - - -/** - * haze_media_channel_get_handle - * - * Implements D-Bus method GetHandle - * on interface org.freedesktop.Telepathy.Channel - */ -static void -haze_media_channel_get_handle (TpSvcChannel *iface, - DBusGMethodInvocation *context) -{ - HazeMediaChannel *self = HAZE_MEDIA_CHANNEL (iface); - - if (self->priv->initial_peer == 0) - tp_svc_channel_return_from_get_handle (context, TP_HANDLE_TYPE_NONE, 0); - else - tp_svc_channel_return_from_get_handle (context, TP_HANDLE_TYPE_CONTACT, - self->priv->initial_peer); -} - - -/** - * haze_media_channel_get_interfaces - * - * Implements D-Bus method GetInterfaces - * on interface org.freedesktop.Telepathy.Channel - */ -static void -haze_media_channel_get_interfaces (TpSvcChannel *iface, - DBusGMethodInvocation *context) -{ - tp_svc_channel_return_from_get_interfaces (context, - haze_media_channel_interfaces); -} - -/** - * haze_media_channel_list_streams - * - * Implements D-Bus method ListStreams - * on interface org.freedesktop.Telepathy.Channel.Type.StreamedMedia - */ -static void -haze_media_channel_list_streams (TpSvcChannelTypeStreamedMedia *iface, - DBusGMethodInvocation *context) -{ - HazeMediaChannel *self = HAZE_MEDIA_CHANNEL (iface); - HazeMediaChannelPrivate *priv; - GPtrArray *ret; - - g_assert (HAZE_IS_MEDIA_CHANNEL (self)); - - priv = self->priv; - - /* If the session has not yet started, return an empty array. */ - if (priv->media == NULL) - { - ret = g_ptr_array_new (); - } - else - { - HazeMediaBackend *backend; - GPtrArray *streams; - - g_object_get (G_OBJECT (priv->media), "backend", &backend, NULL); - g_object_get (G_OBJECT (backend), "streams", &streams, NULL); - - ret = make_stream_list (self, streams->len, - (HazeMediaStream **) streams->pdata); - - g_ptr_array_unref (streams); - g_object_unref (backend); - } - - tp_svc_channel_type_streamed_media_return_from_list_streams (context, ret); - g_ptr_array_foreach (ret, (GFunc) g_value_array_free, NULL); - g_ptr_array_free (ret, TRUE); -} - -/** - * haze_media_channel_remove_streams - * - * Implements DBus method RemoveStreams - * on interface org.freedesktop.Telepathy.Channel.Type.StreamedMedia - */ -static void -haze_media_channel_remove_streams (TpSvcChannelTypeStreamedMedia *iface, - const GArray * streams, - DBusGMethodInvocation *context) -{ - HazeMediaChannel *obj = HAZE_MEDIA_CHANNEL (iface); - HazeMediaChannelPrivate *priv; - HazeMediaBackend *backend; - GPtrArray *backend_streams; - guint i, j; - GPtrArray *media_ids; - const gchar *target_id; - - g_assert (HAZE_IS_MEDIA_CHANNEL (obj)); - - priv = obj->priv; - - g_object_get (obj, "target-id", &target_id, NULL); - - if ((purple_prpl_get_media_caps (priv->conn->account, target_id) & - PURPLE_MEDIA_CAPS_MODIFY_SESSION) == 0) - { - TpBaseConnection *base_conn = TP_BASE_CONNECTION (priv->conn); - gchar *name; - GError *e; - - g_object_get (base_conn, "protocol", &name, NULL); - g_set_error (&e, TP_ERROR, TP_ERROR_NOT_IMPLEMENTED, - "Streams can't be removed in Haze's \"%s\" protocol's calls", name); - g_free (name); - - DEBUG ("%s", e->message); - dbus_g_method_return_error (context, e); - - g_error_free(e); - return; - } - - media_ids = g_ptr_array_new (); - - g_object_get (G_OBJECT (priv->media), "backend", &backend, NULL); - g_object_get (G_OBJECT (backend), "streams", &backend_streams, NULL); - g_object_unref (backend); - - for (i = 0; i < streams->len; ++i) - { - guint id = g_array_index (streams, guint, i); - - for (j = 0; j < backend_streams->len; j++) - { - HazeMediaStream *stream = g_ptr_array_index (backend_streams, j); - guint stream_id; - - g_object_get (G_OBJECT (stream), "id", &stream_id, NULL); - - if (id == stream_id) - { - g_ptr_array_add (media_ids, stream->name); - break; - } - } - - if (j >= backend_streams->len) - { - GError e = { TP_ERROR, TP_ERROR_INVALID_ARGUMENT, - "Requested stream wasn't found" }; - DEBUG ("%s", e.message); - dbus_g_method_return_error (context, &e); - g_ptr_array_free (media_ids, TRUE); - return; - } - } - - for (i = 0; i < media_ids->len; ++i) - { - gchar *id = g_ptr_array_index (media_ids, i); - for (j = i + 1; j < media_ids->len; ++j) - { - if (id == g_ptr_array_index (media_ids, j)) - { - g_ptr_array_remove_index (media_ids, j); - --j; - } - } - } - - for (i = 0; i < media_ids->len; ++i) - { - purple_media_end (priv->media, g_ptr_array_index (media_ids, i), NULL); - } - - g_ptr_array_unref (backend_streams); - g_ptr_array_free (media_ids, TRUE); - tp_svc_channel_type_streamed_media_return_from_remove_streams (context); -} - -/** - * haze_media_channel_request_stream_direction - * - * Implements D-Bus method RequestStreamDirection - * on interface org.freedesktop.Telepathy.Channel.Type.StreamedMedia - */ -static void -haze_media_channel_request_stream_direction (TpSvcChannelTypeStreamedMedia *iface, - guint stream_id, - guint stream_direction, - DBusGMethodInvocation *context) -{ - /* Libpurple doesn't have API for this yet */ - GError e = { TP_ERROR, TP_ERROR_NOT_IMPLEMENTED, - "Stream direction can't be set Haze calls" }; - DEBUG ("%s", e.message); - dbus_g_method_return_error (context, &e); -} - - -static gboolean -init_media_cb (PurpleMediaManager *manager, - PurpleMedia *media, - PurpleAccount *account, - const gchar *username, - HazeMediaChannel *self) -{ - HazeMediaChannelPrivate *priv = self->priv; - TpBaseConnection *base_conn = TP_BASE_CONNECTION (priv->conn); - TpHandleRepoIface *contact_repo = - tp_base_connection_get_handles (base_conn, TP_HANDLE_TYPE_CONTACT); - TpHandle contact = tp_handle_ensure (contact_repo, username, NULL, NULL); - - if (priv->conn->account != account || priv->initial_peer != contact) - return TRUE; - - g_assert (priv->media == NULL); - priv->media = g_object_ref (media); - if (priv->media != NULL) - { - _latch_to_session (self); - } - - g_signal_handlers_disconnect_by_func (manager, init_media_cb, self); - - return TRUE; -} - -static gboolean -_haze_media_channel_request_contents (HazeMediaChannel *chan, - TpHandle peer, - const GArray *media_types, - GError **error) -{ - HazeMediaChannelPrivate *priv = chan->priv; - gboolean want_audio, want_video; - guint idx; - TpHandleRepoIface *contact_handles; - const gchar *contact_id; - guint audio_count = 0, video_count = 0; - - DEBUG ("called"); - - want_audio = want_video = FALSE; - - for (idx = 0; idx < media_types->len; idx++) - { - guint media_type = g_array_index (media_types, guint, idx); - - if (media_type == TP_MEDIA_STREAM_TYPE_AUDIO) - { - want_audio = TRUE; - } - else if (media_type == TP_MEDIA_STREAM_TYPE_VIDEO) - { - want_video = TRUE; - } - else - { - g_set_error (error, TP_ERROR, TP_ERROR_NOT_IMPLEMENTED, - "given media type %u is invalid", media_type); - return FALSE; - } - } - - /* existing call; the recipient and the mode has already been decided */ - if (priv->media != NULL) - { - PurpleMediaCaps caps; - const gchar *target_id; - g_object_get (chan, "target-id", &target_id, NULL); - caps = purple_prpl_get_media_caps (priv->conn->account, target_id); - - /* Check if the contact supports modifying the session */ - if ((caps & PURPLE_MEDIA_CAPS_MODIFY_SESSION) == 0) - { - TpBaseConnection *base_conn = TP_BASE_CONNECTION (priv->conn); - gchar *name; - - g_object_get (base_conn, "protocol", &name, NULL); - g_set_error (error, TP_ERROR, TP_ERROR_NOT_AVAILABLE, - "Streams can't be added in Haze's \"%s\" protocol's calls", - name); - - g_free (name); - return FALSE; - } - - /* Check if contact supports the desired media type */ - if ((want_audio == FALSE || caps & PURPLE_MEDIA_CAPS_AUDIO) && - (want_video == FALSE || caps & PURPLE_MEDIA_CAPS_VIDEO)) - { - g_set_error (error, TP_ERROR, TP_ERROR_NOT_AVAILABLE, - "Member does not have the desired audio/video capabilities"); - return FALSE; - } - } - - /* if we've got here, we're good to make the streams */ - - contact_handles = tp_base_connection_get_handles ( - TP_BASE_CONNECTION (priv->conn), TP_HANDLE_TYPE_CONTACT); - contact_id = tp_handle_inspect (contact_handles, peer); - - /* Be ready to retrieve the newly created media object */ - if (priv->media == NULL) - g_signal_connect (purple_media_manager_get (), "init-media", - G_CALLBACK (init_media_cb), chan); - - for (idx = 0; idx < media_types->len; idx++) - { - guint media_type = g_array_index (media_types, guint, idx); - - if (media_type == TP_MEDIA_STREAM_TYPE_AUDIO) - ++audio_count; - else if (media_type == TP_MEDIA_STREAM_TYPE_VIDEO) - ++video_count; - } - - while (audio_count > 0 || video_count > 0) - { - PurpleMediaSessionType type = PURPLE_MEDIA_NONE; - - if (audio_count > 0) - { - type |= PURPLE_MEDIA_AUDIO; - --audio_count; - } - - if (video_count > 0) - { - type |= PURPLE_MEDIA_VIDEO; - --video_count; - } - - if (purple_prpl_initiate_media (priv->conn->account, - contact_id, type) == FALSE) - return FALSE; - } - - return TRUE; -} - -static void -media_channel_request_streams (HazeMediaChannel *self, - TpHandle contact_handle, - const GArray *types, - GFunc succeeded_cb, - GFunc failed_cb, - gpointer context) -{ - HazeMediaChannelPrivate *priv = self->priv; - PendingStreamRequest *psr = NULL; - GError *error = NULL; - - if (types->len == 0) - { - GPtrArray *empty = g_ptr_array_sized_new (0); - - DEBUG ("no streams to request"); - succeeded_cb (context, empty); - g_ptr_array_free (empty, TRUE); - - return; - } - - if (priv->media != NULL) - { - TpHandle peer; - - peer = priv->initial_peer; - - if (peer != contact_handle) - { - g_set_error (&error, TP_ERROR, TP_ERROR_NOT_AVAILABLE, - "cannot add streams for %u: this channel's peer is %u", - contact_handle, peer); - goto error; - } - } - - /* - * Pending stream requests can be completed before request_contents returns. - * Add the pending stream request up here so it isn't missed. - */ - psr = pending_stream_request_new (types, succeeded_cb, failed_cb, - context); - priv->pending_stream_requests = g_list_prepend (priv->pending_stream_requests, - psr); - - if (!_haze_media_channel_request_contents (self, contact_handle, - types, &error)) - goto error; - - return; - -error: - if (psr != NULL) - { - priv->pending_stream_requests = g_list_remove ( - priv->pending_stream_requests, psr); - pending_stream_request_free (psr); - } - - DEBUG ("returning error %u: %s", error->code, error->message); - failed_cb (context, error); - g_error_free (error); -} - -/** - * haze_media_channel_request_streams - * - * Implements D-Bus method RequestStreams - * on interface org.freedesktop.Telepathy.Channel.Type.StreamedMedia - */ -static void -haze_media_channel_request_streams (TpSvcChannelTypeStreamedMedia *iface, - guint contact_handle, - const GArray *types, - DBusGMethodInvocation *context) -{ - HazeMediaChannel *self = HAZE_MEDIA_CHANNEL (iface); - TpBaseConnection *base_conn = (TpBaseConnection *) self->priv->conn; - TpHandleRepoIface *contact_handles = tp_base_connection_get_handles ( - base_conn, TP_HANDLE_TYPE_CONTACT); - GError *error = NULL; - - if (!tp_handle_is_valid (contact_handles, contact_handle, &error)) - { - DEBUG ("that's not a handle, sonny! (%u)", contact_handle); - dbus_g_method_return_error (context, error); - g_error_free (error); - return; - } - else - { - /* FIXME: disallow this if we've put the peer on hold? */ - - media_channel_request_streams (self, contact_handle, types, - (GFunc) tp_svc_channel_type_streamed_media_return_from_request_streams, - (GFunc) dbus_g_method_return_error, - context); - } -} - -/** - * haze_media_channel_request_initial_streams: - * @chan: an outgoing call, which must have just been constructed. - * @succeeded_cb: called with arguments @user_data and a GPtrArray of - * TP_STRUCT_TYPE_MEDIA_STREAM_INFO if the request succeeds. - * @failed_cb: called with arguments @user_data and a GError * if the request - * fails. - * @user_data: context for the callbacks. - * - * Request streams corresponding to the values of InitialAudio and InitialVideo - * in the channel request. - */ -void -haze_media_channel_request_initial_streams (HazeMediaChannel *chan, - GFunc succeeded_cb, - GFunc failed_cb, - gpointer user_data) -{ - HazeMediaChannelPrivate *priv = chan->priv; - GArray *types = g_array_sized_new (FALSE, FALSE, sizeof (guint), 2); - guint media_type; - - /* This has to be an outgoing call... */ - g_assert (priv->creator == tp_base_connection_get_self_handle ( - TP_BASE_CONNECTION (priv->conn))); - - if (priv->initial_audio) - { - media_type = TP_MEDIA_STREAM_TYPE_AUDIO; - g_array_append_val (types, media_type); - } - - if (priv->initial_video) - { - media_type = TP_MEDIA_STREAM_TYPE_VIDEO; - g_array_append_val (types, media_type); - } - - media_channel_request_streams (chan, priv->initial_peer, types, - succeeded_cb, failed_cb, user_data); - - g_array_free (types, TRUE); -} - -static gboolean -haze_media_channel_add_member (GObject *obj, - TpHandle handle, - const gchar *message, - GError **error) -{ - HazeMediaChannel *chan = HAZE_MEDIA_CHANNEL (obj); - HazeMediaChannelPrivate *priv = chan->priv; - TpGroupMixin *mixin = TP_GROUP_MIXIN (obj); - TpIntset *set; - - /* did we create this channel? */ - if (priv->creator == mixin->self_handle) - { - /* yes: check we don't have a peer already, and if not add this one to - * remote pending (but don't send an invitation yet). - */ - if (priv->media != NULL) - { - TpHandle peer; - - peer = priv->initial_peer; - - if (peer != handle) - { - g_set_error (error, TP_ERROR, TP_ERROR_NOT_AVAILABLE, - "handle %u cannot be added: this channel's peer is %u", - handle, peer); - return FALSE; - } - } - - /* make the peer remote pending */ - set = tp_intset_new_containing (handle); - tp_group_mixin_change_members (obj, "", NULL, NULL, NULL, set, - mixin->self_handle, TP_CHANNEL_GROUP_CHANGE_REASON_INVITED); - tp_intset_destroy (set); - - /* and remove CanAdd, since it was only here to allow this deprecated - * API. */ - tp_group_mixin_change_flags (obj, 0, TP_CHANNEL_GROUP_FLAG_CAN_ADD); - - return TRUE; - } - else - { - /* no: has a session been created, is the handle being added ours, - * and are we in local pending? (call answer) */ - if (priv->media && - handle == mixin->self_handle && - tp_handle_set_is_member (mixin->local_pending, handle)) - { - /* is the call on hold? */ - if (priv->hold_state != TP_LOCAL_HOLD_STATE_UNHELD) - { - g_set_error (error, TP_ERROR, TP_ERROR_NOT_AVAILABLE, - "Can't answer a call while it's on hold"); - return FALSE; - } - - /* make us a member */ - set = tp_intset_new_containing (handle); - tp_group_mixin_change_members (obj, "", set, NULL, NULL, NULL, - handle, TP_CHANNEL_GROUP_CHANGE_REASON_NONE); - tp_intset_destroy (set); - - /* signal acceptance */ - purple_media_stream_info(priv->media, - PURPLE_MEDIA_INFO_ACCEPT, NULL, NULL, TRUE); - - return TRUE; - } - } - - g_set_error (error, TP_ERROR, TP_ERROR_NOT_AVAILABLE, - "handle %u cannot be added in the current state", handle); - return FALSE; -} - -static gboolean -haze_media_channel_remove_member (GObject *obj, - TpHandle handle, - const gchar *message, - guint reason, - GError **error) -{ - HazeMediaChannel *chan = HAZE_MEDIA_CHANNEL (obj); - HazeMediaChannelPrivate *priv = chan->priv; - TpGroupMixin *mixin = TP_GROUP_MIXIN (obj); - - /* We don't set CanRemove, and did allow self removal. So tp-glib should - * ensure this. - */ - g_assert (handle == mixin->self_handle); - - /* Closing up might make HazeMediaManager release its ref. */ - g_object_ref (chan); - - if (priv->media == NULL) - { - haze_media_channel_close (chan); - } - else - { - switch (reason) - { - /* Should one of these trigger reject? */ - case TP_CHANNEL_GROUP_CHANGE_REASON_NONE: - case TP_CHANNEL_GROUP_CHANGE_REASON_OFFLINE: - case TP_CHANNEL_GROUP_CHANGE_REASON_BUSY: - case TP_CHANNEL_GROUP_CHANGE_REASON_ERROR: - case TP_CHANNEL_GROUP_CHANGE_REASON_NO_ANSWER: - purple_media_stream_info(priv->media, - PURPLE_MEDIA_INFO_HANGUP, NULL, NULL, TRUE); - break; - default: - /* The remaining options don't make sense */ - g_object_unref (chan); - return FALSE; - } - } - - /* Remove CanAdd if it was there for the deprecated anonymous channel - * semantics, since the channel will go away RSN. */ - tp_group_mixin_change_flags (obj, 0, TP_CHANNEL_GROUP_FLAG_CAN_ADD); - - g_object_unref (chan); - - return TRUE; -} - -/** - * haze_media_channel_get_session_handlers - * - * Implements D-Bus method GetSessionHandlers - * on interface org.freedesktop.Telepathy.Channel.Interface.MediaSignalling - */ -static void -haze_media_channel_get_session_handlers ( - TpSvcChannelInterfaceMediaSignalling *iface, - DBusGMethodInvocation *context) -{ - HazeMediaChannel *self = HAZE_MEDIA_CHANNEL (iface); - HazeMediaChannelPrivate *priv; - GPtrArray *ret; - GType info_type = TP_STRUCT_TYPE_MEDIA_SESSION_HANDLER_INFO; - - g_assert (HAZE_IS_MEDIA_CHANNEL (self)); - - priv = self->priv; - - if (priv->media) - { - GValue handler = { 0, }; - HazeMediaBackend *backend; - gchar *object_path; - - g_object_get (G_OBJECT (priv->media), "backend", &backend, NULL); - g_object_get (G_OBJECT (backend), "object-path", &object_path, NULL); - g_object_unref (backend); - - g_value_init (&handler, info_type); - g_value_take_boxed (&handler, - dbus_g_type_specialized_construct (info_type)); - - dbus_g_type_struct_set (&handler, - 0, object_path, - 1, "rtp", - G_MAXUINT); - - g_free (object_path); - - ret = g_ptr_array_sized_new (1); - g_ptr_array_add (ret, g_value_get_boxed (&handler)); - } - else - { - ret = g_ptr_array_sized_new (0); - } - - tp_svc_channel_interface_media_signalling_return_from_get_session_handlers ( - context, ret); - g_ptr_array_foreach (ret, (GFunc) g_value_array_free, NULL); - g_ptr_array_free (ret, TRUE); -} - -static void -channel_iface_init (gpointer g_iface, gpointer iface_data) -{ - TpSvcChannelClass *klass = (TpSvcChannelClass *) g_iface; - -#define IMPLEMENT(x, suffix) tp_svc_channel_implement_##x (\ - klass, haze_media_channel_##x##suffix) - IMPLEMENT(close,_async); - IMPLEMENT(get_channel_type,); - IMPLEMENT(get_handle,); - IMPLEMENT(get_interfaces,); -#undef IMPLEMENT -} - -static void -streamed_media_iface_init (gpointer g_iface, gpointer iface_data) -{ - TpSvcChannelTypeStreamedMediaClass *klass = - (TpSvcChannelTypeStreamedMediaClass *) g_iface; - -#define IMPLEMENT(x) tp_svc_channel_type_streamed_media_implement_##x (\ - klass, haze_media_channel_##x) - IMPLEMENT(list_streams); - IMPLEMENT(remove_streams); - IMPLEMENT(request_stream_direction); - IMPLEMENT(request_streams); -#undef IMPLEMENT -} - -static void -media_signalling_iface_init (gpointer g_iface, gpointer iface_data) -{ - TpSvcChannelInterfaceMediaSignallingClass *klass = - (TpSvcChannelInterfaceMediaSignallingClass *) g_iface; - -#define IMPLEMENT(x) tp_svc_channel_interface_media_signalling_implement_##x (\ - klass, haze_media_channel_##x) - IMPLEMENT(get_session_handlers); -#undef IMPLEMENT -} diff --git a/src/media-channel.h b/src/media-channel.h deleted file mode 100644 index ce76440..0000000 --- a/src/media-channel.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * media-channel.h - Header for HazeMediaChannel - * Copyright (C) 2006, 2009 Collabora Ltd. - * Copyright (C) 2006 Nokia Corporation - * - * Copied heavily from telepathy-gabble - * - * 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 - */ - -#ifndef __HAZE_MEDIA_CHANNEL_H__ -#define __HAZE_MEDIA_CHANNEL_H__ - -#include - -#include - -G_BEGIN_DECLS - -typedef struct _HazeMediaChannel HazeMediaChannel; -typedef struct _HazeMediaChannelPrivate HazeMediaChannelPrivate; -typedef struct _HazeMediaChannelClass HazeMediaChannelClass; - -struct _HazeMediaChannelClass { - GObjectClass parent_class; - - TpGroupMixinClass group_class; - TpDBusPropertiesMixinClass dbus_props_class; -}; - -struct _HazeMediaChannel { - GObject parent; - - TpGroupMixin group; - - HazeMediaChannelPrivate *priv; -}; - -GType haze_media_channel_get_type (void); - -/* TYPE MACROS */ -#define HAZE_TYPE_MEDIA_CHANNEL \ - (haze_media_channel_get_type ()) -#define HAZE_MEDIA_CHANNEL(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), HAZE_TYPE_MEDIA_CHANNEL,\ - HazeMediaChannel)) -#define HAZE_MEDIA_CHANNEL_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), HAZE_TYPE_MEDIA_CHANNEL,\ - HazeMediaChannelClass)) -#define HAZE_IS_MEDIA_CHANNEL(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj), HAZE_TYPE_MEDIA_CHANNEL)) -#define HAZE_IS_MEDIA_CHANNEL_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass), HAZE_TYPE_MEDIA_CHANNEL)) -#define HAZE_MEDIA_CHANNEL_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS ((obj), HAZE_TYPE_MEDIA_CHANNEL, \ - HazeMediaChannelClass)) - -void haze_media_channel_request_initial_streams (HazeMediaChannel *chan, - GFunc succeeded_cb, - GFunc failed_cb, - gpointer user_data); - -void haze_media_channel_close (HazeMediaChannel *self); - -G_END_DECLS - -#endif /* #ifndef __HAZE_MEDIA_CHANNEL_H__*/ diff --git a/src/media-manager.c b/src/media-manager.c deleted file mode 100644 index 406b952..0000000 --- a/src/media-manager.c +++ /dev/null @@ -1,576 +0,0 @@ -/* - * media-manager.c - Source for HazeMediaManager - * Copyright (C) 2006, 2009 Collabora Ltd. - * - * Copied heavily from telepathy-gabble - * - * 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 - */ - -#include "config.h" -#include "media-manager.h" - -#include -#include - -#include "connection.h" -#include "debug.h" -#include "media-channel.h" - -static void channel_manager_iface_init (gpointer, gpointer); -static void haze_media_manager_close_all (HazeMediaManager *self); -static void haze_media_manager_constructed (GObject *object); - -G_DEFINE_TYPE_WITH_CODE (HazeMediaManager, haze_media_manager, - G_TYPE_OBJECT, - G_IMPLEMENT_INTERFACE (TP_TYPE_CHANNEL_MANAGER, - channel_manager_iface_init)); - -/* properties */ -enum -{ - PROP_CONNECTION = 1, - LAST_PROPERTY -}; - -struct _HazeMediaManagerPrivate -{ - HazeConnection *conn; - gulong status_changed_id; - - GPtrArray *channels; - guint channel_index; - - gboolean dispose_has_run; -}; - -static void -haze_media_manager_init (HazeMediaManager *self) -{ - HazeMediaManagerPrivate *priv = G_TYPE_INSTANCE_GET_PRIVATE (self, - HAZE_TYPE_MEDIA_MANAGER, HazeMediaManagerPrivate); - - self->priv = priv; - - priv->channels = g_ptr_array_sized_new (1); - priv->channel_index = 0; - - priv->conn = NULL; - priv->dispose_has_run = FALSE; -} - -static void -haze_media_manager_dispose (GObject *object) -{ - HazeMediaManager *self = HAZE_MEDIA_MANAGER (object); - HazeMediaManagerPrivate *priv = self->priv; - - if (priv->dispose_has_run) - return; - - DEBUG ("dispose called"); - priv->dispose_has_run = TRUE; - - haze_media_manager_close_all (self); - g_assert (priv->channels->len == 0); - g_ptr_array_free (priv->channels, TRUE); - - if (G_OBJECT_CLASS (haze_media_manager_parent_class)->dispose) - G_OBJECT_CLASS (haze_media_manager_parent_class)->dispose (object); -} - -static void -haze_media_manager_get_property (GObject *object, - guint property_id, - GValue *value, - GParamSpec *pspec) -{ - HazeMediaManager *self = HAZE_MEDIA_MANAGER (object); - HazeMediaManagerPrivate *priv = self->priv; - - switch (property_id) { - case PROP_CONNECTION: - g_value_set_object (value, priv->conn); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - break; - } -} - -static void -haze_media_manager_set_property (GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec) -{ - HazeMediaManager *self = HAZE_MEDIA_MANAGER (object); - HazeMediaManagerPrivate *priv = self->priv; - - switch (property_id) { - case PROP_CONNECTION: - priv->conn = g_value_get_object (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - break; - } -} - -static void -haze_media_manager_class_init (HazeMediaManagerClass *haze_media_manager_class) -{ - GObjectClass *object_class = G_OBJECT_CLASS (haze_media_manager_class); - GParamSpec *param_spec; - - g_type_class_add_private (haze_media_manager_class, - sizeof (HazeMediaManagerPrivate)); - - object_class->constructed = haze_media_manager_constructed; - object_class->dispose = haze_media_manager_dispose; - - object_class->get_property = haze_media_manager_get_property; - object_class->set_property = haze_media_manager_set_property; - - param_spec = g_param_spec_object ("connection", "HazeConnection object", - "Haze connection object that owns this media channel manager object.", - HAZE_TYPE_CONNECTION, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_CONNECTION, param_spec); - -} - -/** - * media_channel_closed_cb: - * - * Signal callback for when a media channel is closed. Removes the references - * that #HazeMediaManager holds to them. - */ -static void -media_channel_closed_cb (HazeMediaChannel *chan, gpointer user_data) -{ - HazeMediaManager *self = HAZE_MEDIA_MANAGER (user_data); - HazeMediaManagerPrivate *priv = self->priv; - - tp_channel_manager_emit_channel_closed_for_object (self, - TP_EXPORTABLE_CHANNEL (chan)); - - DEBUG ("removing media channel %p with ref count %d", - chan, G_OBJECT (chan)->ref_count); - - g_ptr_array_remove (priv->channels, chan); - g_object_unref (chan); -} - -/** - * new_media_channel - * - * Creates a new empty HazeMediaChannel. - */ -static HazeMediaChannel * -new_media_channel (HazeMediaManager *self, - PurpleMedia *media, - TpHandle peer, - gboolean initial_audio, - gboolean initial_video) -{ - HazeMediaManagerPrivate *priv; - TpBaseConnection *conn; - - HazeMediaChannel *chan; - gchar *object_path; - - g_assert (HAZE_IS_MEDIA_MANAGER (self)); - - priv = self->priv; - conn = (TpBaseConnection *) priv->conn; - - object_path = g_strdup_printf ("%s/MediaChannel%u", - tp_base_connection_get_object_path (conn), priv->channel_index); - priv->channel_index += 1; - - chan = g_object_new (HAZE_TYPE_MEDIA_CHANNEL, - "connection", priv->conn, - "object-path", object_path, - "media", media, - "initial-peer", peer, - "initial-audio", initial_audio, - "initial-video", initial_video, - NULL); - - DEBUG ("object path %s", object_path); - - g_signal_connect (chan, "closed", (GCallback) media_channel_closed_cb, self); - - g_ptr_array_add (priv->channels, chan); - - g_free (object_path); - - return chan; -} - -static void -haze_media_manager_close_all (HazeMediaManager *self) -{ - HazeMediaManagerPrivate *priv = self->priv; - GPtrArray *tmp = g_ptr_array_sized_new (priv->channels->len); - guint i; - - for (i = 0; i < priv->channels->len; i++) - g_ptr_array_add (tmp, g_ptr_array_index (priv->channels, i)); - - DEBUG ("closing channels"); - - for (i = 0; i < tmp->len; i++) - { - HazeMediaChannel *chan = g_ptr_array_index (tmp, i); - - DEBUG ("closing %p", chan); - haze_media_channel_close (chan); - } - - if (priv->status_changed_id != 0) - { - g_signal_handler_disconnect (priv->conn, - priv->status_changed_id); - priv->status_changed_id = 0; - } -} - -static gboolean -init_media_cb (PurpleMediaManager *manager, - PurpleMedia *media, - PurpleAccount *account, - const gchar *username, - HazeMediaManager *self) -{ - HazeMediaManagerPrivate *priv = self->priv; - TpBaseConnection *base_conn = TP_BASE_CONNECTION (priv->conn); - TpHandleRepoIface *contact_repo = - tp_base_connection_get_handles (base_conn, TP_HANDLE_TYPE_CONTACT); - TpHandle contact = tp_handle_ensure (contact_repo, username, NULL, NULL); - HazeMediaChannel *chan; - - if (purple_media_is_initiator (media, NULL, NULL) == TRUE) - return TRUE; - - chan = new_media_channel (self, media, contact, FALSE, FALSE); - tp_channel_manager_emit_new_channel (self, - TP_EXPORTABLE_CHANNEL (chan), NULL); - DEBUG ("called"); - return TRUE; -} - -static void -connection_status_changed_cb (HazeConnection *conn, - guint status, - guint reason, - HazeMediaManager *self) -{ - switch (status) - { - case TP_CONNECTION_STATUS_CONNECTING: - g_signal_connect (purple_media_manager_get (), "init-media", - G_CALLBACK (init_media_cb), self); - break; - - case TP_CONNECTION_STATUS_DISCONNECTED: - g_signal_handlers_disconnect_by_func (purple_media_manager_get (), - G_CALLBACK (init_media_cb), self); - haze_media_manager_close_all (self); - break; - } -} - -static void -haze_media_manager_constructed (GObject *object) -{ - void (*chain_up) (GObject *) = - G_OBJECT_CLASS (haze_media_manager_parent_class)->constructed; - HazeMediaManager *self = HAZE_MEDIA_MANAGER (object); - HazeMediaManagerPrivate *priv = self->priv; - - if (chain_up != NULL) - chain_up (object); - - priv->status_changed_id = g_signal_connect (priv->conn, - "status-changed", (GCallback) connection_status_changed_cb, object); -} - -static void -haze_media_manager_foreach_channel (TpChannelManager *manager, - TpExportableChannelFunc foreach, - gpointer user_data) -{ - HazeMediaManager *self = HAZE_MEDIA_MANAGER (manager); - HazeMediaManagerPrivate *priv = self->priv; - guint i; - - for (i = 0; i < priv->channels->len; i++) - { - TpExportableChannel *channel = TP_EXPORTABLE_CHANNEL ( - g_ptr_array_index (priv->channels, i)); - - foreach (channel, user_data); - } -} - -static const gchar * const media_channel_fixed_properties[] = { - TP_IFACE_CHANNEL ".ChannelType", - TP_IFACE_CHANNEL ".TargetHandleType", - NULL -}; - -static const gchar * const named_channel_allowed_properties[] = { - TP_IFACE_CHANNEL ".TargetHandle", - TP_IFACE_CHANNEL ".TargetID", - TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA ".InitialAudio", - TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA ".InitialVideo", - NULL -}; - -/* not advertised in foreach_channel_class - can only be requested with - * RequestChannel, not with CreateChannel/EnsureChannel */ -static const gchar * const anon_channel_allowed_properties[] = { - NULL -}; - -static GHashTable * -haze_media_manager_channel_class (void) -{ - return tp_asv_new ( - TP_IFACE_CHANNEL ".ChannelType", G_TYPE_STRING, - TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA, - TP_IFACE_CHANNEL ".TargetHandleType", G_TYPE_UINT, - TP_HANDLE_TYPE_CONTACT, - NULL); -} - -static void -haze_media_manager_foreach_channel_class (TpChannelManager *manager, - TpChannelManagerChannelClassFunc func, - gpointer user_data) -{ - GHashTable *table = haze_media_manager_channel_class (); - - func (manager, table, named_channel_allowed_properties, user_data); - - g_hash_table_destroy (table); -} - -typedef enum -{ - METHOD_REQUEST, - METHOD_CREATE, - METHOD_ENSURE, -} RequestMethod; - -typedef struct -{ - HazeMediaManager *self; - HazeMediaChannel *channel; - gpointer request_token; -} MediaChannelRequest; - -static MediaChannelRequest * -media_channel_request_new (HazeMediaManager *self, - HazeMediaChannel *channel, - gpointer request_token) -{ - MediaChannelRequest *mcr = g_slice_new0 (MediaChannelRequest); - - mcr->self = self; - mcr->channel = channel; - mcr->request_token = request_token; - - return mcr; -} - -static void -media_channel_request_free (MediaChannelRequest *mcr) -{ - g_slice_free (MediaChannelRequest, mcr); -} - -static void -media_channel_request_succeeded_cb (MediaChannelRequest *mcr, - GPtrArray *streams) -{ - GSList *request_tokens; - - request_tokens = g_slist_prepend (NULL, mcr->request_token); - tp_channel_manager_emit_new_channel (mcr->self, - TP_EXPORTABLE_CHANNEL (mcr->channel), request_tokens); - g_slist_free (request_tokens); - - media_channel_request_free (mcr); -} - -static void -media_channel_request_failed_cb (MediaChannelRequest *mcr, - GError *error) -{ - tp_channel_manager_emit_request_failed (mcr->self, mcr->request_token, - error->domain, error->code, error->message); - - media_channel_request_free (mcr); -} - -static gboolean -haze_media_manager_requestotron (TpChannelManager *manager, - gpointer request_token, - GHashTable *request_properties, - RequestMethod method) -{ - HazeMediaManager *self = HAZE_MEDIA_MANAGER (manager); - HazeMediaManagerPrivate *priv = self->priv; - TpHandleType handle_type; - TpHandle handle; - HazeMediaChannel *channel = NULL; - GError *error = NULL; - gboolean initial_audio, initial_video; - - /* Supported modes of operation: - * - CreateChannel({THT: Contact, TH: n}): - * channel has TargetHandle=n - * n is not in the group interface at all - * call is started when caller calls RequestStreams. - * - EnsureChannel({THT: Contact, TH: n}): - * look for a channel whose peer is n, and return that if found with - * whatever properties and group membership it has; - * otherwise the same as into CreateChannel - */ - - if (tp_strdiff (tp_asv_get_string (request_properties, - TP_IFACE_CHANNEL ".ChannelType"), - TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA)) - return FALSE; - - handle_type = tp_asv_get_uint32 (request_properties, - TP_IFACE_CHANNEL ".TargetHandleType", NULL); - - handle = tp_asv_get_uint32 (request_properties, - TP_IFACE_CHANNEL ".TargetHandle", NULL); - - initial_audio = tp_asv_get_boolean (request_properties, - TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA ".InitialAudio", NULL); - initial_video = tp_asv_get_boolean (request_properties, - TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA ".InitialVideo", NULL); - - switch (handle_type) - { - case TP_HANDLE_TYPE_NONE: - /* already checked by TpBaseConnection */ - g_assert (handle == 0); - - g_set_error (&error, TP_ERROR, TP_ERROR_NOT_IMPLEMENTED, - "A valid Contact handle must be provided when requesting a media " - "channel"); - - goto error; - case TP_HANDLE_TYPE_CONTACT: - /* validity already checked by TpBaseConnection */ - g_assert (handle != 0); - - if (tp_channel_manager_asv_has_unknown_properties (request_properties, - media_channel_fixed_properties, named_channel_allowed_properties, - &error)) - goto error; - - if (method == METHOD_ENSURE) - { - guint i; - TpHandle peer = 0; - - for (i = 0; i < priv->channels->len; i++) - { - channel = g_ptr_array_index (priv->channels, i); - g_object_get (channel, "peer", &peer, NULL); - - if (peer == handle) - { - /* Per the spec, we ignore InitialAudio and InitialVideo when - * looking for an existing channel. - */ - tp_channel_manager_emit_request_already_satisfied (self, - request_token, TP_EXPORTABLE_CHANNEL (channel)); - return TRUE; - } - } - } - - channel = new_media_channel (self, NULL, handle, - initial_audio, initial_video); - break; - default: - return FALSE; - } - - g_assert (channel != NULL); - - haze_media_channel_request_initial_streams (channel, - (GFunc) media_channel_request_succeeded_cb, - (GFunc) media_channel_request_failed_cb, - media_channel_request_new (self, channel, request_token)); - - return TRUE; - -error: - tp_channel_manager_emit_request_failed (self, request_token, - error->domain, error->code, error->message); - g_error_free (error); - return TRUE; -} - -static gboolean -haze_media_manager_request_channel (TpChannelManager *manager, - gpointer request_token, - GHashTable *request_properties) -{ - return haze_media_manager_requestotron (manager, request_token, - request_properties, METHOD_REQUEST); -} - - -static gboolean -haze_media_manager_create_channel (TpChannelManager *manager, - gpointer request_token, - GHashTable *request_properties) -{ - return haze_media_manager_requestotron (manager, request_token, - request_properties, METHOD_CREATE); -} - -static gboolean -haze_media_manager_ensure_channel (TpChannelManager *manager, - gpointer request_token, - GHashTable *request_properties) -{ - return haze_media_manager_requestotron (manager, request_token, - request_properties, METHOD_ENSURE); -} - -static void -channel_manager_iface_init (gpointer g_iface, - gpointer iface_data) -{ - TpChannelManagerIface *iface = g_iface; - - iface->foreach_channel = haze_media_manager_foreach_channel; - iface->foreach_channel_class = haze_media_manager_foreach_channel_class; - iface->request_channel = haze_media_manager_request_channel; - iface->create_channel = haze_media_manager_create_channel; - iface->ensure_channel = haze_media_manager_ensure_channel; -} diff --git a/src/media-manager.h b/src/media-manager.h deleted file mode 100644 index 72a0409..0000000 --- a/src/media-manager.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * media-manager.h - Header for HazeMediaManager - * Copyright (C) 2006, 2009 Collabora Ltd. - * - * Copied heavily from telepathy-gabble - * - * 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 - */ - -#ifndef __MEDIA_MANAGER_H__ -#define __MEDIA_MANAGER_H__ - -#include - -G_BEGIN_DECLS - -typedef struct _HazeMediaManager HazeMediaManager; -typedef struct _HazeMediaManagerClass HazeMediaManagerClass; -typedef struct _HazeMediaManagerPrivate HazeMediaManagerPrivate; - -struct _HazeMediaManagerClass { - GObjectClass parent_class; -}; - -struct _HazeMediaManager { - GObject parent; - - HazeMediaManagerPrivate *priv; -}; - -GType haze_media_manager_get_type (void); - -/* TYPE MACROS */ -#define HAZE_TYPE_MEDIA_MANAGER \ - (haze_media_manager_get_type ()) -#define HAZE_MEDIA_MANAGER(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), HAZE_TYPE_MEDIA_MANAGER,\ - HazeMediaManager)) -#define HAZE_MEDIA_MANAGER_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), HAZE_TYPE_MEDIA_MANAGER,\ - HazeMediaManagerClass)) -#define HAZE_IS_MEDIA_MANAGER(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj), HAZE_TYPE_MEDIA_MANAGER)) -#define HAZE_IS_MEDIA_MANAGER_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass), HAZE_TYPE_MEDIA_MANAGER)) -#define HAZE_MEDIA_MANAGER_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS ((obj), HAZE_TYPE_MEDIA_MANAGER,\ - HazeMediaManagerClass)) - -G_END_DECLS - -#endif /* #ifndef __MEDIA_MANAGER_H__ */ - diff --git a/src/media-stream.c b/src/media-stream.c deleted file mode 100644 index 969d5ac..0000000 --- a/src/media-stream.c +++ /dev/null @@ -1,1396 +0,0 @@ -/* - * media-stream.c - Source for HazeMediaStream - * Copyright © 2006-2009 Collabora Ltd. - * Copyright © 2006-2009 Nokia Corporation - * - * Copied heavily from telepathy-gabble. - * - * 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 - */ - -#include "config.h" -#include "media-stream.h" - -#include -#include -#include -#include - -#define DEBUG_FLAG HAZE_DEBUG_MEDIA - -#include "debug.h" - -static void stream_handler_iface_init (gpointer, gpointer); - -G_DEFINE_TYPE_WITH_CODE (HazeMediaStream, - haze_media_stream, - G_TYPE_OBJECT, - G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_DBUS_PROPERTIES, - tp_dbus_properties_mixin_iface_init); - G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_MEDIA_STREAM_HANDLER, - stream_handler_iface_init) - ) - -/* properties */ -enum -{ - PROP_OBJECT_PATH = 1, - PROP_DBUS_DAEMON, - PROP_NAME, - PROP_PEER, - PROP_ID, - PROP_MEDIA_TYPE, - PROP_CONNECTION_STATE, - PROP_READY, - PROP_PLAYING, - PROP_COMBINED_DIRECTION, - PROP_LOCAL_HOLD, - PROP_MEDIA, - PROP_CODECS_READY, - PROP_STUN_SERVERS, - PROP_RELAY_INFO, - PROP_NAT_TRAVERSAL, - PROP_CREATED_LOCALLY, - LAST_PROPERTY -}; - -/* private structure */ - -struct _HazeMediaStreamPrivate -{ - PurpleMedia *media; - - gchar *object_path; - TpDBusDaemon *dbus_daemon; - guint id; - guint media_type; - - GList *codecs; - GList *remote_codecs; - GList *local_candidates; - GList *remote_candidates; - - /* Whether we're waiting for a codec intersection from the streaming - * implementation. If FALSE, SupportedCodecs is a no-op. - */ - gboolean awaiting_intersection; - - guint remote_candidate_count; - - gchar *nat_traversal; - /* GPtrArray(GValueArray(STRING, UINT)) */ - GPtrArray *stun_servers; - /* GPtrArray(GHashTable(string => GValue)) */ - GPtrArray *relay_info; - - gboolean on_hold; - - gboolean closed; - gboolean dispose_has_run; - gboolean local_hold; - gboolean ready; - gboolean sending; - gboolean created_locally; -}; - -HazeMediaStream * -haze_media_stream_new (const gchar *object_path, - TpDBusDaemon *dbus_daemon, - PurpleMedia *media, - const gchar *name, - const gchar *peer, - guint media_type, - guint id, - gboolean created_locally, - const gchar *nat_traversal, - const GPtrArray *relay_info, - gboolean local_hold) -{ - GPtrArray *empty = NULL; - HazeMediaStream *result; - - g_return_val_if_fail (PURPLE_IS_MEDIA (media), NULL); - - if (relay_info == NULL) - { - empty = g_ptr_array_sized_new (0); - relay_info = empty; - } - - result = g_object_new (HAZE_TYPE_MEDIA_STREAM, - "object-path", object_path, - "dbus-daemon", dbus_daemon, - "media", media, - "name", name, - "peer", peer, - "media-type", media_type, - "id", id, - "created-locally", created_locally, - "nat-traversal", nat_traversal, - "relay-info", relay_info, - "local-hold", local_hold, - NULL); - - if (empty != NULL) - g_ptr_array_free (empty, TRUE); - - return result; -} - -TpMediaStreamType -haze_media_stream_get_media_type (HazeMediaStream *self) -{ - return self->priv->media_type; -} - -static void -haze_media_stream_init (HazeMediaStream *self) -{ - HazeMediaStreamPrivate *priv = G_TYPE_INSTANCE_GET_PRIVATE (self, - HAZE_TYPE_MEDIA_STREAM, HazeMediaStreamPrivate); - - self->priv = priv; - - priv->stun_servers = g_ptr_array_sized_new (1); -} - -static GObject * -haze_media_stream_constructor (GType type, guint n_props, - GObjectConstructParam *props) -{ - GObject *obj; - HazeMediaStream *stream; - HazeMediaStreamPrivate *priv; - - /* call base class constructor */ - obj = G_OBJECT_CLASS (haze_media_stream_parent_class)-> - constructor (type, n_props, props); - stream = HAZE_MEDIA_STREAM (obj); - priv = stream->priv; - - g_assert (priv->media != NULL); - - /* go for the bus */ - tp_dbus_daemon_register_object (priv->dbus_daemon, priv->object_path, obj); - - if (priv->created_locally) - { - g_object_set (stream, "combined-direction", - MAKE_COMBINED_DIRECTION (TP_MEDIA_STREAM_DIRECTION_BIDIRECTIONAL, - 0), NULL); - } - else - { - priv->awaiting_intersection = TRUE; - g_object_set (stream, "combined-direction", - MAKE_COMBINED_DIRECTION (TP_MEDIA_STREAM_DIRECTION_BIDIRECTIONAL, - TP_MEDIA_STREAM_PENDING_LOCAL_SEND), NULL); - } - - return obj; -} - -static void -haze_media_stream_get_property (GObject *object, - guint property_id, - GValue *value, - GParamSpec *pspec) -{ - HazeMediaStream *stream = HAZE_MEDIA_STREAM (object); - HazeMediaStreamPrivate *priv = stream->priv; - - switch (property_id) { - case PROP_OBJECT_PATH: - g_value_set_string (value, priv->object_path); - break; - case PROP_DBUS_DAEMON: - g_value_set_object (value, priv->dbus_daemon); - break; - case PROP_NAME: - g_value_set_string (value, stream->name); - break; - case PROP_PEER: - g_value_set_string (value, stream->peer); - break; - case PROP_ID: - g_value_set_uint (value, priv->id); - break; - case PROP_MEDIA_TYPE: - g_value_set_uint (value, priv->media_type); - break; - case PROP_CONNECTION_STATE: - g_value_set_uint (value, stream->connection_state); - break; - case PROP_READY: - g_value_set_boolean (value, priv->ready); - break; - case PROP_PLAYING: - g_value_set_boolean (value, stream->playing); - break; - case PROP_COMBINED_DIRECTION: - g_value_set_uint (value, stream->combined_direction); - break; - case PROP_LOCAL_HOLD: - g_value_set_boolean (value, priv->local_hold); - break; - case PROP_MEDIA: - g_value_set_object (value, priv->media); - break; - case PROP_CODECS_READY: - g_value_set_boolean (value, priv->codecs != NULL); - break; - case PROP_STUN_SERVERS: - g_value_set_boxed (value, priv->stun_servers); - break; - case PROP_NAT_TRAVERSAL: - g_value_set_string (value, priv->nat_traversal); - break; - case PROP_CREATED_LOCALLY: - g_value_set_boolean (value, priv->created_locally); - break; - case PROP_RELAY_INFO: - g_value_set_boxed (value, priv->relay_info); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - break; - } -} - -static void -haze_media_stream_set_property (GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec) -{ - HazeMediaStream *stream = HAZE_MEDIA_STREAM (object); - HazeMediaStreamPrivate *priv = stream->priv; - - switch (property_id) { - case PROP_OBJECT_PATH: - g_free (priv->object_path); - priv->object_path = g_value_dup_string (value); - break; - case PROP_DBUS_DAEMON: - g_assert (priv->dbus_daemon == NULL); /* construct-only */ - priv->dbus_daemon = g_value_dup_object (value); - break; - case PROP_NAME: - g_free (stream->name); - stream->name = g_value_dup_string (value); - break; - case PROP_PEER: - g_free (stream->peer); - stream->peer = g_value_dup_string (value); - break; - case PROP_ID: - priv->id = g_value_get_uint (value); - break; - case PROP_MEDIA_TYPE: - priv->media_type = g_value_get_uint (value); - break; - case PROP_CONNECTION_STATE: - DEBUG ("stream %s connection state %d", - stream->name, stream->connection_state); - stream->connection_state = g_value_get_uint (value); - break; - case PROP_READY: - priv->ready = g_value_get_boolean (value); - break; - case PROP_PLAYING: - break; - case PROP_COMBINED_DIRECTION: - DEBUG ("changing combined direction from %u to %u", - stream->combined_direction, g_value_get_uint (value)); - stream->combined_direction = g_value_get_uint (value); - break; - case PROP_MEDIA: - g_assert (priv->media == NULL); - priv->media = g_value_dup_object (value); - break; - case PROP_NAT_TRAVERSAL: - g_assert (priv->nat_traversal == NULL); - priv->nat_traversal = g_value_dup_string (value); - break; - case PROP_CREATED_LOCALLY: - priv->created_locally = g_value_get_boolean (value); - break; - case PROP_RELAY_INFO: - g_assert (priv->relay_info == NULL); - priv->relay_info = g_value_dup_boxed (value); - break; - case PROP_LOCAL_HOLD: - priv->local_hold = g_value_get_boolean (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - break; - } -} - -static void haze_media_stream_dispose (GObject *object); -static void haze_media_stream_finalize (GObject *object); - -static void -haze_media_stream_class_init (HazeMediaStreamClass *haze_media_stream_class) -{ - static TpDBusPropertiesMixinPropImpl stream_handler_props[] = { - { "RelayInfo", "relay-info", NULL }, - { "STUNServers", "stun-servers", NULL }, - { "NATTraversal", "nat-traversal", NULL }, - { "CreatedLocally", "created-locally", NULL }, - { NULL } - }; - static TpDBusPropertiesMixinIfaceImpl prop_interfaces[] = { - { TP_IFACE_MEDIA_STREAM_HANDLER, - tp_dbus_properties_mixin_getter_gobject_properties, - NULL, - stream_handler_props, - }, - { NULL } - }; - GObjectClass *object_class = G_OBJECT_CLASS (haze_media_stream_class); - GParamSpec *param_spec; - - g_type_class_add_private (haze_media_stream_class, - sizeof (HazeMediaStreamPrivate)); - - object_class->constructor = haze_media_stream_constructor; - - object_class->get_property = haze_media_stream_get_property; - object_class->set_property = haze_media_stream_set_property; - - object_class->dispose = haze_media_stream_dispose; - object_class->finalize = haze_media_stream_finalize; - - param_spec = g_param_spec_string ("object-path", "D-Bus object path", - "The D-Bus object path used for this " - "object on the bus.", - NULL, - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_READWRITE | - G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_OBJECT_PATH, param_spec); - - param_spec = g_param_spec_object ("dbus-daemon", "D-Bus connection", - "Connection to D-Bus", - TP_TYPE_DBUS_DAEMON, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_DBUS_DAEMON, param_spec); - - param_spec = g_param_spec_string ("name", "Stream name", - "An opaque name for the stream used in the signalling.", NULL, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_NAME | - G_PARAM_STATIC_BLURB); - g_object_class_install_property (object_class, PROP_NAME, param_spec); - - param_spec = g_param_spec_string ("peer", "Peer name", - "The name for the peer used in the signalling.", NULL, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_NAME | - G_PARAM_STATIC_BLURB); - g_object_class_install_property (object_class, PROP_PEER, param_spec); - - param_spec = g_param_spec_uint ("id", "Stream ID", - "A stream number for the stream used in the " - "D-Bus API.", - 0, G_MAXUINT, 0, - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_READWRITE | - G_PARAM_STATIC_NAME | - G_PARAM_STATIC_BLURB); - g_object_class_install_property (object_class, PROP_ID, param_spec); - - param_spec = g_param_spec_uint ("media-type", "Stream media type", - "A constant indicating which media type the stream carries.", - TP_MEDIA_STREAM_TYPE_AUDIO, TP_MEDIA_STREAM_TYPE_VIDEO, - TP_MEDIA_STREAM_TYPE_AUDIO, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_MEDIA_TYPE, param_spec); - - param_spec = g_param_spec_uint ("connection-state", "Stream connection state", - "An integer indicating the state of the" - "stream's connection.", - TP_MEDIA_STREAM_STATE_DISCONNECTED, - TP_MEDIA_STREAM_STATE_CONNECTED, - TP_MEDIA_STREAM_STATE_DISCONNECTED, - G_PARAM_CONSTRUCT | - G_PARAM_READWRITE | - G_PARAM_STATIC_NAME | - G_PARAM_STATIC_BLURB); - g_object_class_install_property (object_class, PROP_CONNECTION_STATE, - param_spec); - - param_spec = g_param_spec_boolean ("ready", "Ready?", - "A boolean signifying whether the user " - "is ready to handle signals from this " - "object.", - FALSE, - G_PARAM_CONSTRUCT | - G_PARAM_READWRITE | - G_PARAM_STATIC_NAME | - G_PARAM_STATIC_BLURB); - g_object_class_install_property (object_class, PROP_READY, param_spec); - - param_spec = g_param_spec_boolean ("playing", "Set playing", - "A boolean signifying whether the stream " - "has been set playing yet.", - FALSE, - G_PARAM_CONSTRUCT | - G_PARAM_READWRITE | - G_PARAM_STATIC_NAME | - G_PARAM_STATIC_BLURB); - g_object_class_install_property (object_class, PROP_PLAYING, param_spec); - - param_spec = g_param_spec_uint ("combined-direction", - "Combined direction", - "An integer indicating the directions the stream currently sends in, " - "and the peers who have been asked to send.", - TP_MEDIA_STREAM_DIRECTION_NONE, - MAKE_COMBINED_DIRECTION (TP_MEDIA_STREAM_DIRECTION_BIDIRECTIONAL, - TP_MEDIA_STREAM_PENDING_LOCAL_SEND | - TP_MEDIA_STREAM_PENDING_REMOTE_SEND), - TP_MEDIA_STREAM_DIRECTION_NONE, - G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_NAME | - G_PARAM_STATIC_BLURB); - g_object_class_install_property (object_class, PROP_COMBINED_DIRECTION, - param_spec); - - param_spec = g_param_spec_boolean ("local-hold", "Local hold?", - "True if resources used for this stream have been freed.", FALSE, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_NAME | G_PARAM_STATIC_BLURB | G_PARAM_STATIC_NICK); - g_object_class_install_property (object_class, PROP_LOCAL_HOLD, param_spec); - - param_spec = g_param_spec_object ("media", "PurpleMedia object", - "Media object signalling this media stream.", - PURPLE_TYPE_MEDIA, - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_READWRITE | - G_PARAM_STATIC_NICK | - G_PARAM_STATIC_BLURB); - g_object_class_install_property (object_class, PROP_MEDIA, param_spec); - - param_spec = g_param_spec_boxed ("stun-servers", "STUN servers", - "Array of (STRING: address literal, UINT: port) pairs", - /* FIXME: use correct macro when available */ - tp_type_dbus_array_su (), - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_STUN_SERVERS, param_spec); - - param_spec = g_param_spec_boxed ("relay-info", "Relay info", - "Array of mappings containing relay server information", - TP_ARRAY_TYPE_STRING_VARIANT_MAP_LIST, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_RELAY_INFO, param_spec); - - param_spec = g_param_spec_string ("nat-traversal", "NAT traversal", - "NAT traversal mechanism for this stream", NULL, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_NAT_TRAVERSAL, - param_spec); - - param_spec = g_param_spec_boolean ("created-locally", "Created locally?", - "True if this stream was created by the local user", FALSE, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_CREATED_LOCALLY, - param_spec); - - param_spec = g_param_spec_boolean ("codecs-ready", "Codecs ready", - "True if the codecs for this stream are ready to be used", FALSE, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_CODECS_READY, - param_spec); - - haze_media_stream_class->dbus_props_class.interfaces = prop_interfaces; - tp_dbus_properties_mixin_class_init (object_class, - G_STRUCT_OFFSET (HazeMediaStreamClass, dbus_props_class)); -} - -void -haze_media_stream_dispose (GObject *object) -{ - HazeMediaStream *self = HAZE_MEDIA_STREAM (object); - HazeMediaStreamPrivate *priv = self->priv; - - DEBUG ("called"); - - if (priv->dispose_has_run) - return; - - priv->dispose_has_run = TRUE; - - tp_clear_object (&priv->dbus_daemon); - - if (priv->local_candidates) - { - purple_media_candidate_list_free (priv->local_candidates); - priv->local_candidates = NULL; - } - - if (priv->remote_candidates) - { - purple_media_candidate_list_free (priv->remote_candidates); - priv->remote_candidates = NULL; - } - - if (priv->codecs) - { - purple_media_codec_list_free (priv->codecs); - priv->codecs = NULL; - } - - if (priv->remote_codecs) - { - purple_media_codec_list_free (priv->remote_codecs); - priv->remote_codecs = NULL; - } - - g_object_unref (priv->media); - priv->media = NULL; - - if (G_OBJECT_CLASS (haze_media_stream_parent_class)->dispose) - G_OBJECT_CLASS (haze_media_stream_parent_class)->dispose (object); -} - -void -haze_media_stream_finalize (GObject *object) -{ - HazeMediaStream *self = HAZE_MEDIA_STREAM (object); - HazeMediaStreamPrivate *priv = self->priv; - - g_free (priv->object_path); - g_free (priv->nat_traversal); - - /* FIXME: use correct macro when available */ - if (priv->stun_servers != NULL) - g_boxed_free (tp_type_dbus_array_su (), priv->stun_servers); - - if (priv->relay_info != NULL) - g_boxed_free (TP_ARRAY_TYPE_STRING_VARIANT_MAP_LIST, priv->relay_info); - - G_OBJECT_CLASS (haze_media_stream_parent_class)->finalize (object); -} - - -GList * -haze_media_stream_get_local_candidates (HazeMediaStream *self) -{ - HazeMediaStreamPrivate *priv = self->priv; - return g_list_copy (priv->local_candidates); -} - - -GList * -haze_media_stream_get_codecs (HazeMediaStream *self) -{ - HazeMediaStreamPrivate *priv = self->priv; - return purple_media_codec_list_copy (priv->codecs); -} - - -static void -pass_remote_candidates (HazeMediaStream *self) -{ - HazeMediaStreamPrivate *priv = self->priv; - GType transport_struct_type = TP_STRUCT_TYPE_MEDIA_STREAM_HANDLER_TRANSPORT; - GType candidate_struct_type = TP_STRUCT_TYPE_MEDIA_STREAM_HANDLER_CANDIDATE; - GList *iter = priv->remote_candidates; - - for (; iter; iter = g_list_next (iter)) - { - gchar *address, *username, *password, *candidate_id; - GValue candidate = { 0, }; - GPtrArray *transports; - GValue transport = { 0, }; - PurpleMediaCandidate *c = iter->data; - PurpleMediaCandidateType candidate_type; - guint type = TP_MEDIA_STREAM_TRANSPORT_TYPE_LOCAL; - - g_value_init (&transport, transport_struct_type); - g_value_take_boxed (&transport, - dbus_g_type_specialized_construct (transport_struct_type)); - - address = purple_media_candidate_get_ip (c); - username = purple_media_candidate_get_username (c); - password = purple_media_candidate_get_password (c); - candidate_type = purple_media_candidate_get_candidate_type (c); - - if (candidate_type == PURPLE_MEDIA_CANDIDATE_TYPE_HOST) - type = TP_MEDIA_STREAM_TRANSPORT_TYPE_LOCAL; - else if (candidate_type == PURPLE_MEDIA_CANDIDATE_TYPE_SRFLX) - type = TP_MEDIA_STREAM_TRANSPORT_TYPE_DERIVED; - else if (candidate_type == PURPLE_MEDIA_CANDIDATE_TYPE_RELAY) - type = TP_MEDIA_STREAM_TRANSPORT_TYPE_RELAY; - else - DEBUG ("Unknown candidate type"); - - dbus_g_type_struct_set (&transport, - 0, purple_media_candidate_get_component_id (c), - 1, address, - 2, purple_media_candidate_get_port (c), - 3, purple_media_candidate_get_protocol (c) == - PURPLE_MEDIA_NETWORK_PROTOCOL_UDP ? - TP_MEDIA_STREAM_BASE_PROTO_UDP : - TP_MEDIA_STREAM_BASE_PROTO_TCP, - 4, "RTP", - 5, "AVP", - 6, (double)purple_media_candidate_get_priority (c), - 7, type, - 8, username, - 9, password, - G_MAXUINT); - - g_free (password); - g_free (username); - g_free (address); - - transports = g_ptr_array_sized_new (1); - g_ptr_array_add (transports, g_value_get_boxed (&transport)); - - g_value_init (&candidate, candidate_struct_type); - g_value_take_boxed (&candidate, - dbus_g_type_specialized_construct (candidate_struct_type)); - - candidate_id = purple_media_candidate_get_foundation (c); - - dbus_g_type_struct_set (&candidate, - 0, candidate_id, - 1, transports, - G_MAXUINT); - - DEBUG ("passing 1 remote candidate to stream engine: %s", candidate_id); - - tp_svc_media_stream_handler_emit_add_remote_candidate ( - self, candidate_id, transports); - - g_free (candidate_id); - } -} - - -void -haze_media_stream_add_remote_candidates (HazeMediaStream *self, - GList *remote_candidates) -{ - HazeMediaStreamPrivate *priv = self->priv; - - priv->remote_candidates = g_list_concat ( - priv->remote_candidates, - purple_media_candidate_list_copy (remote_candidates)); - - if (priv->ready == TRUE) - pass_remote_candidates (self); -} - - -static void -pass_remote_codecs (HazeMediaStream *self) -{ - HazeMediaStreamPrivate *priv = self->priv; - GType codec_struct_type = TP_STRUCT_TYPE_MEDIA_STREAM_HANDLER_CODEC; - GPtrArray *codecs = g_ptr_array_new (); - GList *iter = priv->remote_codecs; - - for (; iter; iter = g_list_next (iter)) - { - GValue codec = { 0, }; - PurpleMediaCodec *c = iter->data; - gchar *name; - GList *codec_params; - GHashTable *params; - - g_value_init (&codec, codec_struct_type); - g_value_take_boxed (&codec, - dbus_g_type_specialized_construct (codec_struct_type)); - - name = purple_media_codec_get_encoding_name (c); - codec_params = purple_media_codec_get_optional_parameters (c); - params = g_hash_table_new_full (g_str_hash, g_str_equal, - g_free, g_free); - - for (; codec_params; codec_params = g_list_next (codec_params)) - { - PurpleKeyValuePair *pair = codec_params->data; - g_hash_table_insert (params, pair->key, pair->value); - } - - DEBUG ("new remote %s codec: %u '%s' %u %u %u", - priv->media_type == TP_MEDIA_STREAM_TYPE_AUDIO ? "audio" : "video", - purple_media_codec_get_id (c), name, priv->media_type, - purple_media_codec_get_clock_rate (c), - purple_media_codec_get_channels (c)); - - dbus_g_type_struct_set (&codec, - 0, purple_media_codec_get_id (c), - 1, name, - 2, priv->media_type, - 3, purple_media_codec_get_clock_rate (c), - 4, purple_media_codec_get_channels (c), - 5, params, - G_MAXUINT); - - g_free (name); - g_hash_table_destroy (params); - - g_ptr_array_add (codecs, g_value_get_boxed (&codec)); - } - - DEBUG ("passing %d remote codecs to stream-engine", codecs->len); - - tp_svc_media_stream_handler_emit_set_remote_codecs (self, codecs); -} - - -void -haze_media_stream_set_remote_codecs (HazeMediaStream *self, - GList *remote_codecs) -{ - HazeMediaStreamPrivate *priv = self->priv; - GList *iter = priv->remote_codecs; - - for (; iter; iter = g_list_delete_link (iter, iter)) - g_object_unref (iter->data); - - priv->remote_codecs = purple_media_codec_list_copy (remote_codecs); - - if (priv->ready == TRUE) - pass_remote_codecs (self); -} - -void -haze_media_stream_add_stun_server (HazeMediaStream *self, - const gchar *stun_ip, - guint stun_port) -{ - HazeMediaStreamPrivate *priv = self->priv; - GValueArray *va; - GValue ip = {0}, port = {0}; - - if (stun_ip == NULL || stun_ip[0] == 0) - { - DEBUG ("Invalid STUN address passed: %s", stun_ip); - return; - } - else if (stun_port > 65535) - { - DEBUG ("Invalid STUN port passed: %d", stun_port); - return; - } - - g_value_init (&ip, G_TYPE_STRING); - g_value_set_string (&ip, stun_ip); - g_value_init (&port, G_TYPE_UINT); - g_value_set_uint (&port, stun_port); - - va = g_value_array_new (2); - g_value_array_append (va, &ip); - g_value_array_append (va, &port); - - g_ptr_array_add (priv->stun_servers, va); -} - - -/** - * haze_media_stream_codec_choice - * - * Implements D-Bus method CodecChoice - * on interface org.freedesktop.Telepathy.Media.StreamHandler - */ -static void -haze_media_stream_codec_choice (TpSvcMediaStreamHandler *iface, - guint codec_id, - DBusGMethodInvocation *context) -{ - HazeMediaStream *self = HAZE_MEDIA_STREAM (iface); - - g_assert (HAZE_IS_MEDIA_STREAM (self)); - - tp_svc_media_stream_handler_return_from_codec_choice (context); -} - - -gboolean -haze_media_stream_error (HazeMediaStream *self, - guint err_no, - const gchar *message, - GError **error) -{ - g_assert (HAZE_IS_MEDIA_STREAM (self)); - - DEBUG ( "Media.StreamHandler::Error called, error %u (%s) -- emitting signal", - err_no, message); - - purple_media_error (self->priv->media, message); - - return TRUE; -} - - -/** - * haze_media_stream_error - * - * Implements D-Bus method Error - * on interface org.freedesktop.Telepathy.Media.StreamHandler - */ -static void -haze_media_stream_error_async (TpSvcMediaStreamHandler *iface, - guint errno, - const gchar *message, - DBusGMethodInvocation *context) -{ - HazeMediaStream *self = HAZE_MEDIA_STREAM (iface); - GError *error = NULL; - - if (haze_media_stream_error (self, errno, message, &error)) - { - tp_svc_media_stream_handler_return_from_error (context); - } - else - { - dbus_g_method_return_error (context, error); - g_error_free (error); - } -} - - -/** - * haze_media_stream_hold: - * - * Tell streaming clients that the stream is going on hold, so they should - * stop streaming and free up any resources they are currently holding - * (e.g. close hardware devices); or that the stream is coming off hold, - * so they should reacquire those resources. - */ -void -haze_media_stream_hold (HazeMediaStream *self, - gboolean hold) -{ - tp_svc_media_stream_handler_emit_set_stream_held (self, hold); -} - - -/** - * haze_media_stream_hold_state: - * - * Called by streaming clients when the stream's hold state has been changed - * successfully in response to SetStreamHeld. - */ -static void -haze_media_stream_hold_state (TpSvcMediaStreamHandler *iface, - gboolean hold_state, - DBusGMethodInvocation *context) -{ - HazeMediaStream *self = HAZE_MEDIA_STREAM (iface); - HazeMediaStreamPrivate *priv = self->priv; - - DEBUG ("%p: %s", self, hold_state ? "held" : "unheld"); - priv->local_hold = hold_state; - - g_object_notify ((GObject *) self, "local-hold"); - - tp_svc_media_stream_handler_return_from_hold_state (context); -} - - -/** - * haze_media_stream_unhold_failure: - * - * Called by streaming clients when an attempt to reacquire the necessary - * hardware or software resources to unhold the stream, in response to - * SetStreamHeld, has failed. - */ -static void -haze_media_stream_unhold_failure (TpSvcMediaStreamHandler *iface, - DBusGMethodInvocation *context) -{ - HazeMediaStream *self = HAZE_MEDIA_STREAM (iface); - HazeMediaStreamPrivate *priv = self->priv; - - DEBUG ("%p", self); - - priv->local_hold = TRUE; - -// maybe emit unhold failed here? - g_object_notify ((GObject *) self, "local-hold"); - - tp_svc_media_stream_handler_return_from_unhold_failure (context); -} - - -/** - * haze_media_stream_native_candidates_prepared - * - * Implements D-Bus method NativeCandidatesPrepared - * on interface org.freedesktop.Telepathy.Media.StreamHandler - */ -static void -haze_media_stream_native_candidates_prepared (TpSvcMediaStreamHandler *iface, - DBusGMethodInvocation *context) -{ - HazeMediaStream *self = HAZE_MEDIA_STREAM (iface); - HazeMediaStreamPrivate *priv; - PurpleMediaBackend *backend; - - g_assert (HAZE_IS_MEDIA_STREAM (self)); - - priv = self->priv; - - g_object_get (G_OBJECT (priv->media), "backend", &backend, NULL); - g_signal_emit_by_name (backend, "candidates-prepared", - self->name, self->peer); - g_object_unref (backend); - - tp_svc_media_stream_handler_return_from_native_candidates_prepared (context); -} - - -/** - * haze_media_stream_new_active_candidate_pair - * - * Implements D-Bus method NewActiveCandidatePair - * on interface org.freedesktop.Telepathy.Media.StreamHandler - */ -static void -haze_media_stream_new_active_candidate_pair (TpSvcMediaStreamHandler *iface, - const gchar *native_candidate_id, - const gchar *remote_candidate_id, - DBusGMethodInvocation *context) -{ - HazeMediaStream *self = HAZE_MEDIA_STREAM (iface); - HazeMediaStreamPrivate *priv; - PurpleMediaBackend *backend; - GList *l_iter; - - /* - * This appears to be called for each pair of components. - * I'm not sure how to go about differentiating between the two - * components as the ids are the same. - */ - - DEBUG ("called (%s, %s)", native_candidate_id, remote_candidate_id); - - g_assert (HAZE_IS_MEDIA_STREAM (self)); - - priv = self->priv; - l_iter = priv->local_candidates; - g_object_get (priv->media, "backend", &backend, NULL); - - for (; l_iter; l_iter = g_list_next (l_iter)) - { - PurpleMediaCandidate *lc = l_iter->data; - GList *r_iter = priv->remote_candidates; - - for (; r_iter; r_iter = g_list_next (r_iter)) - { - PurpleMediaCandidate *rc = r_iter->data; - - if (purple_media_candidate_get_component_id (lc) == - purple_media_candidate_get_component_id (rc)) - { - gchar *l_name = purple_media_candidate_get_foundation (lc); - gchar *r_name = purple_media_candidate_get_foundation (rc); - - if (!strcmp (l_name, native_candidate_id) && - !strcmp (r_name, remote_candidate_id)) - { - DEBUG ("Emitting new active candidate pair %d: %s - %s", - purple_media_candidate_get_component_id (lc), - l_name, r_name); - - g_signal_emit_by_name (backend, "active-candidate-pair", - self->name, self->peer, lc, rc); - } - - g_free (l_name); - g_free (r_name); - } - } - } - - g_object_unref (backend); - tp_svc_media_stream_handler_return_from_new_active_candidate_pair (context); -} - - -/** - * haze_media_stream_new_native_candidate - * - * Implements D-Bus method NewNativeCandidate - * on interface org.freedesktop.Telepathy.Media.StreamHandler - */ -static void -haze_media_stream_new_native_candidate (TpSvcMediaStreamHandler *iface, - const gchar *candidate_id, - const GPtrArray *transports, - DBusGMethodInvocation *context) -{ - HazeMediaStream *self = HAZE_MEDIA_STREAM (iface); - HazeMediaStreamPrivate *priv; - PurpleMediaBackend *backend; - guint i; - - g_assert (HAZE_IS_MEDIA_STREAM (self)); - - priv = self->priv; - - g_object_get (G_OBJECT (priv->media), "backend", &backend, NULL); - - for (i = 0; i < transports->len; i++) - { - GValueArray *transport; - guint component, type, proto; - PurpleMediaCandidate *c; - PurpleMediaCandidateType candidate_type = - PURPLE_MEDIA_CANDIDATE_TYPE_HOST; - PurpleMediaNetworkProtocol protocol = PURPLE_MEDIA_NETWORK_PROTOCOL_UDP; - - transport = g_ptr_array_index (transports, i); - component = g_value_get_uint (g_value_array_get_nth (transport, 0)); - type = g_value_get_uint (g_value_array_get_nth (transport, 7)); - proto = g_value_get_uint (g_value_array_get_nth (transport, 3)); - - if (type == TP_MEDIA_STREAM_TRANSPORT_TYPE_LOCAL) - candidate_type = PURPLE_MEDIA_CANDIDATE_TYPE_HOST; - else if (type == TP_MEDIA_STREAM_TRANSPORT_TYPE_DERIVED) - candidate_type = PURPLE_MEDIA_CANDIDATE_TYPE_SRFLX; - else if (type == TP_MEDIA_STREAM_TRANSPORT_TYPE_RELAY) - candidate_type = PURPLE_MEDIA_CANDIDATE_TYPE_RELAY; - else - DEBUG ("Unknown candidate type"); - - if (proto == TP_MEDIA_STREAM_BASE_PROTO_UDP) - protocol = PURPLE_MEDIA_NETWORK_PROTOCOL_UDP; - else if (proto == TP_MEDIA_STREAM_BASE_PROTO_TCP) - protocol = PURPLE_MEDIA_NETWORK_PROTOCOL_TCP; - else - DEBUG ("Unknown network protocol"); - - c = purple_media_candidate_new (candidate_id, component, candidate_type, - protocol, - /* address */ - g_value_get_string (g_value_array_get_nth (transport, 1)), - /* port */ - g_value_get_uint (g_value_array_get_nth (transport, 2))); - - g_object_set (c, "username", - g_value_get_string (g_value_array_get_nth (transport, 8)), NULL); - g_object_set (c, "password", - g_value_get_string (g_value_array_get_nth (transport, 9)), NULL); - g_object_set (c, "priority", - (guint)g_value_get_double ( - g_value_array_get_nth (transport, 6)), NULL); - - DEBUG ("new-candidate: %s %s %p", self->name, self->peer, c); - - priv->local_candidates = g_list_append (priv->local_candidates, c); - - g_signal_emit_by_name (backend, "new-candidate", self->name, self->peer, c); - } - - g_object_unref (backend); - - tp_svc_media_stream_handler_return_from_new_native_candidate (context); -} - -static void haze_media_stream_set_local_codecs (TpSvcMediaStreamHandler *, - const GPtrArray *codecs, DBusGMethodInvocation *); - -/** - * haze_media_stream_ready - * - * Implements D-Bus method Ready - * on interface org.freedesktop.Telepathy.Media.StreamHandler - */ -static void -haze_media_stream_ready (TpSvcMediaStreamHandler *iface, - const GPtrArray *codecs, - DBusGMethodInvocation *context) -{ - HazeMediaStream *self = HAZE_MEDIA_STREAM (iface); - HazeMediaStreamPrivate *priv; - - g_assert (HAZE_IS_MEDIA_STREAM (self)); - - priv = self->priv; - - DEBUG ("ready called"); - - if (priv->ready == FALSE) - { - g_object_set (self, "ready", TRUE, NULL); - - tp_svc_media_stream_handler_emit_set_stream_playing (self, TRUE); - - if (purple_media_get_session_type (priv->media, self->name) & - (PURPLE_MEDIA_SEND_AUDIO | PURPLE_MEDIA_SEND_VIDEO)) - { - g_object_set (self, "combined-direction", - MAKE_COMBINED_DIRECTION (TP_MEDIA_STREAM_DIRECTION_BIDIRECTIONAL, - 0), NULL); - tp_svc_media_stream_handler_emit_set_stream_sending (self, TRUE); - } - - /* If a new stream is added while the call's on hold, it will have - * local_hold set at construct time. So once tp-fs has called Ready(), we - * should let it know this stream's on hold. - */ - if (priv->local_hold) - haze_media_stream_hold (self, priv->local_hold); - } - else - { - DEBUG ("Ready called twice, running plain SetLocalCodecs instead"); - } - - /* set_local_codecs and ready return the same thing, so we can do... */ - haze_media_stream_set_local_codecs (iface, codecs, context); - pass_remote_codecs (self); - pass_remote_candidates (self); -} - -static void -convert_param (gchar *key, gchar *value, PurpleMediaCodec *codec) -{ - purple_media_codec_add_optional_parameter (codec, key, value); -} - -static gboolean -pass_local_codecs (HazeMediaStream *stream, - const GPtrArray *codecs, - gboolean ready, - GError **error) -{ - HazeMediaStreamPrivate *priv = stream->priv; - PurpleMediaSessionType type = PURPLE_MEDIA_AUDIO; - PurpleMediaCodec *c; - guint i; - - DEBUG ("putting list of %d supported codecs from stream-engine into cache", - codecs->len); - - if (priv->media_type == TP_MEDIA_STREAM_TYPE_AUDIO) - type = PURPLE_MEDIA_AUDIO; - else if (priv->media_type == TP_MEDIA_STREAM_TYPE_VIDEO) - type = PURPLE_MEDIA_VIDEO; - else - g_assert_not_reached (); - - for (i = 0; i < codecs->len; i++) - { - GType codec_struct_type = TP_STRUCT_TYPE_MEDIA_STREAM_HANDLER_CODEC; - - GValue codec = { 0, }; - guint id, clock_rate, channels; - gchar *name; - GHashTable *params; - - g_value_init (&codec, codec_struct_type); - g_value_set_static_boxed (&codec, g_ptr_array_index (codecs, i)); - - dbus_g_type_struct_get (&codec, - 0, &id, - 1, &name, - 3, &clock_rate, - 4, &channels, - 5, ¶ms, - G_MAXUINT); - - c = purple_media_codec_new (id, name, type, clock_rate); - g_object_set (c, "channels", channels, NULL); - - g_hash_table_foreach (params, (GHFunc)convert_param, c); - - DEBUG ("adding codec: %s", purple_media_codec_to_string (c)); - - priv->codecs = g_list_append (priv->codecs, c); - - g_signal_emit_by_name (priv->media, "codecs-changed", stream->name); - } - - return TRUE; -} - -/** - * haze_media_stream_set_local_codecs - * - * Implements D-Bus method SetLocalCodecs - * on interface org.freedesktop.Telepathy.Media.StreamHandler - */ -static void -haze_media_stream_set_local_codecs (TpSvcMediaStreamHandler *iface, - const GPtrArray *codecs, - DBusGMethodInvocation *context) -{ - HazeMediaStream *self = HAZE_MEDIA_STREAM (iface); - HazeMediaStreamPrivate *priv = self->priv; - GError *error = NULL; - - DEBUG ("called"); - - if (PURPLE_IS_MEDIA (priv->media) && - purple_media_is_initiator (priv->media, self->name, self->peer)) - { - if (!pass_local_codecs (self, codecs, self->priv->created_locally, - &error)) - { - DEBUG ("failed: %s", error->message); - - dbus_g_method_return_error (context, error); - g_error_free (error); - return; - } - } - else - { - DEBUG ("ignoring local codecs, waiting for codec intersection"); - } - - tp_svc_media_stream_handler_return_from_set_local_codecs (context); -} - -/** - * haze_media_stream_stream_state - * - * Implements D-Bus method StreamState - * on interface org.freedesktop.Telepathy.Media.StreamHandler - */ -static void -haze_media_stream_stream_state (TpSvcMediaStreamHandler *iface, - guint connection_state, - DBusGMethodInvocation *context) -{ - HazeMediaStream *self = HAZE_MEDIA_STREAM (iface); - - g_object_set (self, "connection-state", connection_state, NULL); - - // emit connection state here - - tp_svc_media_stream_handler_return_from_stream_state (context); -} - - -/** - * haze_media_stream_supported_codecs - * - * Implements D-Bus method SupportedCodecs - * on interface org.freedesktop.Telepathy.Media.StreamHandler - */ -static void -haze_media_stream_supported_codecs (TpSvcMediaStreamHandler *iface, - const GPtrArray *codecs, - DBusGMethodInvocation *context) -{ - HazeMediaStream *self = HAZE_MEDIA_STREAM (iface); - HazeMediaStreamPrivate *priv = self->priv; - GError *error = NULL; - - DEBUG ("called"); - - if (priv->awaiting_intersection) - { - if (!pass_local_codecs (self, codecs, TRUE, &error)) - { - DEBUG ("failed: %s", error->message); - - dbus_g_method_return_error (context, error); - g_error_free (error); - return; - } - - priv->awaiting_intersection = FALSE; - } - else - { - /* If we created the stream, we don't need to send the intersection. If - * we didn't create it, but have already sent the intersection once, we - * don't need to send it again. In either case, extra calls to - * SupportedCodecs are in response to an incoming description-info, which - * can only change parameters and which XEP-0167 §10 says is purely - * advisory. - */ - DEBUG ("we already sent, or don't need to send, our codecs"); - } - - tp_svc_media_stream_handler_return_from_supported_codecs (context); -} - -/** - * haze_media_stream_codecs_updated - * - * Implements D-Bus method CodecsUpdated - * on interface org.freedesktop.Telepathy.Media.StreamHandler - */ -static void -haze_media_stream_codecs_updated (TpSvcMediaStreamHandler *iface, - const GPtrArray *codecs, - DBusGMethodInvocation *context) -{ - HazeMediaStream *self = HAZE_MEDIA_STREAM (iface); - GError *error = NULL; - - if (self->priv->codecs == NULL) - { - GError e = { TP_ERROR, TP_ERROR_NOT_AVAILABLE, - "CodecsUpdated may only be called once an initial set of codecs " - "has been set" }; - - dbus_g_method_return_error (context, &e); - return; - } - - if (self->priv->awaiting_intersection) - { - /* When awaiting an intersection the initial set of codecs should be set - * by calling SupportedCodecs as that is the canonical set of codecs, - * updates are only meaningful afterwards */ - tp_svc_media_stream_handler_return_from_codecs_updated (context); - return; - } - - if (pass_local_codecs (self, codecs, self->priv->created_locally, &error)) - { - tp_svc_media_stream_handler_return_from_codecs_updated (context); - } - else - { - DEBUG ("failed: %s", error->message); - - dbus_g_method_return_error (context, error); - g_error_free (error); - } -} - -static void -stream_handler_iface_init (gpointer g_iface, gpointer iface_data) -{ - TpSvcMediaStreamHandlerClass *klass = - (TpSvcMediaStreamHandlerClass *) g_iface; - -#define IMPLEMENT(x,suffix) tp_svc_media_stream_handler_implement_##x (\ - klass, haze_media_stream_##x##suffix) - IMPLEMENT(codec_choice,); - IMPLEMENT(error,_async); - IMPLEMENT(hold_state,); - IMPLEMENT(native_candidates_prepared,); - IMPLEMENT(new_active_candidate_pair,); - IMPLEMENT(new_native_candidate,); - IMPLEMENT(ready,); - IMPLEMENT(set_local_codecs,); - IMPLEMENT(stream_state,); - IMPLEMENT(supported_codecs,); - IMPLEMENT(unhold_failure,); - IMPLEMENT(codecs_updated,); -#undef IMPLEMENT -} diff --git a/src/media-stream.h b/src/media-stream.h deleted file mode 100644 index 0d6f328..0000000 --- a/src/media-stream.h +++ /dev/null @@ -1,126 +0,0 @@ -/* - * media-stream.h - Header for HazeMediaStream - * Copyright (C) 2006, 2009 Collabora Ltd. - * Copyright (C) 2006 Nokia Corporation - * - * Copied heavily from telepathy-gabble. - * - * 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 - */ - -#ifndef __HAZE_MEDIA_STREAM_H__ -#define __HAZE_MEDIA_STREAM_H__ - -#include -#include -#include - -G_BEGIN_DECLS - -typedef enum -{ - STREAM_SIG_STATE_NEW, - STREAM_SIG_STATE_SENT, - STREAM_SIG_STATE_ACKNOWLEDGED, - STREAM_SIG_STATE_REMOVING -} StreamSignallingState; - -typedef guint32 CombinedStreamDirection; - -typedef struct _HazeMediaStream HazeMediaStream; -typedef struct _HazeMediaStreamClass HazeMediaStreamClass; -typedef struct _HazeMediaStreamPrivate HazeMediaStreamPrivate; - -struct _HazeMediaStreamClass { - GObjectClass parent_class; - - TpDBusPropertiesMixinClass dbus_props_class; -}; - -struct _HazeMediaStream { - GObject parent; - - gchar *name; - gchar *peer; - - TpMediaStreamState connection_state; - - CombinedStreamDirection combined_direction; - gboolean playing; - - HazeMediaStreamPrivate *priv; -}; - -GType haze_media_stream_get_type (void); - -/* TYPE MACROS */ -#define HAZE_TYPE_MEDIA_STREAM \ - (haze_media_stream_get_type ()) -#define HAZE_MEDIA_STREAM(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), HAZE_TYPE_MEDIA_STREAM, \ - HazeMediaStream)) -#define HAZE_MEDIA_STREAM_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), HAZE_TYPE_MEDIA_STREAM, \ - HazeMediaStreamClass)) -#define HAZE_IS_MEDIA_STREAM(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj), HAZE_TYPE_MEDIA_STREAM)) -#define HAZE_IS_MEDIA_STREAM_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass), HAZE_TYPE_MEDIA_STREAM)) -#define HAZE_MEDIA_STREAM_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS ((obj), HAZE_TYPE_MEDIA_STREAM, \ - HazeMediaStreamClass)) - -#define COMBINED_DIRECTION_GET_DIRECTION(d) \ - ((TpMediaStreamDirection) ((d) & TP_MEDIA_STREAM_DIRECTION_BIDIRECTIONAL)) -#define COMBINED_DIRECTION_GET_PENDING_SEND(d) \ - ((TpMediaStreamPendingSend) ((d) >> 2)) -#define MAKE_COMBINED_DIRECTION(d, p) \ - ((CombinedStreamDirection) ((d) | ((p) << 2))) - -gboolean haze_media_stream_error (HazeMediaStream *self, guint err_no, - const gchar *message, GError **error); - -void haze_media_stream_close (HazeMediaStream *close); -void haze_media_stream_hold (HazeMediaStream *stream, gboolean hold); -gboolean haze_media_stream_change_direction (HazeMediaStream *stream, - guint requested_dir, GError **error); -void haze_media_stream_accept_pending_local_send (HazeMediaStream *stream); - -HazeMediaStream *haze_media_stream_new (const gchar *object_path, - TpDBusDaemon *dbus_daemon, - PurpleMedia *media, - const gchar *name, - const gchar *peer, - guint media_type, - guint id, - gboolean created_locally, - const gchar *nat_traversal, - const GPtrArray *relay_info, - gboolean local_hold); -TpMediaStreamType haze_media_stream_get_media_type (HazeMediaStream *self); - -GList *haze_media_stream_get_local_candidates (HazeMediaStream *self); -GList *haze_media_stream_get_codecs (HazeMediaStream *self); -void haze_media_stream_add_remote_candidates (HazeMediaStream *self, - GList *remote_candidates); -void haze_media_stream_set_remote_codecs (HazeMediaStream *self, - GList *remote_codecs); -void haze_media_stream_add_stun_server (HazeMediaStream *self, - const gchar *stun_ip, - guint stun_port); - -G_END_DECLS - -#endif /* #ifndef __HAZE_MEDIA_STREAM_H__*/ diff --git a/src/protocol.c b/src/protocol.c index aa4d864..df56071 100644 --- a/src/protocol.c +++ b/src/protocol.c @@ -913,9 +913,6 @@ haze_protocol_get_connection_details (TpBaseProtocol *base, { GType types[] = { HAZE_TYPE_IM_CHANNEL_FACTORY, HAZE_TYPE_CONTACT_LIST, -#ifdef ENABLE_MEDIA - HAZE_TYPE_MEDIA_MANAGER, -#endif G_TYPE_INVALID }; *channel_manager_types = g_memdup (types, sizeof (types)); diff --git a/tests/twisted/Makefile.am b/tests/twisted/Makefile.am index 81b9118..da5d473 100644 --- a/tests/twisted/Makefile.am +++ b/tests/twisted/Makefile.am @@ -52,22 +52,10 @@ EXTRA_DIST = \ servicetest.py \ ns.py -if MEDIA_ENABLED -MEDIA_ENABLED_PYBOOL = True -else -MEDIA_ENABLED_PYBOOL = False -endif - -config.py: Makefile - $(AM_V_GEN) { \ - echo "MEDIA_ENABLED = $(MEDIA_ENABLED_PYBOOL)"; \ - } > $@ - haze-twisted-tests.list: Makefile $(AM_V_GEN)echo $(TWISTED_TESTS) > $@ BUILT_SOURCES = \ - config.py \ haze-twisted-tests.list \ run-test.sh \ $(NULL) diff --git a/tests/twisted/simple-caps.py b/tests/twisted/simple-caps.py index d0088d3..862a2de 100644 --- a/tests/twisted/simple-caps.py +++ b/tests/twisted/simple-caps.py @@ -9,8 +9,6 @@ from servicetest import assertEquals, assertContains, EventPattern from hazetest import exec_test, sync_stream, JabberXmlStream import constants as cs -import config - import ns # assert this list of RCCs is only text @@ -66,32 +64,6 @@ def test_someone_else(q, bus, conn, stream): amy_handle = conn.RequestHandles(cs.HT_CONTACT, ['amy@foo.com'])[0] check_rccs(conn, amy_handle) -def test_media(q, bus, conn, stream): - sync_stream(q, stream) - - conn.ContactCapabilities.UpdateCapabilities([( - 'im.telepathy1.Client.Foobar', - [{ cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_STREAMED_MEDIA, - cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT, - cs.INITIAL_AUDIO: True }, - { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_STREAMED_MEDIA, - cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT, - cs.INITIAL_VIDEO: True }], - [], - )]) - - q.expect('stream-presence') # can't be bothered checking this - - conn.ContactCapabilities.UpdateCapabilities([( - 'im.telepathy1.Client.Foobar', - [], [])]) - - q.expect('stream-presence') # can't be bothered checking this - if __name__ == '__main__': exec_test(test_self_handle) exec_test(test_someone_else, do_connect=False, protocol=JabberXmlStream) - - if config.MEDIA_ENABLED: - exec_test(test_media) - -- 1.8.4.rc3