summaryrefslogtreecommitdiff
path: root/src/media-stream.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/media-stream.c')
-rw-r--r--src/media-stream.c2085
1 files changed, 0 insertions, 2085 deletions
diff --git a/src/media-stream.c b/src/media-stream.c
deleted file mode 100644
index 426aa8a20..000000000
--- a/src/media-stream.c
+++ /dev/null
@@ -1,2085 +0,0 @@
-/*
- * gabble-media-stream.c - Source for GabbleMediaStream
- * Copyright © 2006-2009 Collabora Ltd.
- * Copyright © 2006-2009 Nokia Corporation
- * @author Ole Andre Vadla Ravnaas <ole.andre.ravnaas@collabora.co.uk>
- *
- * 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 <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <dbus/dbus-glib.h>
-
-#include <telepathy-glib/telepathy-glib.h>
-#include <telepathy-glib/telepathy-glib-dbus.h>
-
-#define DEBUG_FLAG GABBLE_DEBUG_MEDIA
-
-#include "connection.h"
-#include "debug.h"
-#include "gabble-signals-marshal.h"
-#include "media-channel.h"
-#include "namespaces.h"
-#include "util.h"
-
-static void stream_handler_iface_init (gpointer, gpointer);
-
-G_DEFINE_TYPE_WITH_CODE(GabbleMediaStream,
- gabble_media_stream,
- G_TYPE_OBJECT,
- G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_MEDIA_STREAM_HANDLER,
- stream_handler_iface_init);
- G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_DBUS_PROPERTIES,
- tp_dbus_properties_mixin_iface_init);
- )
-
-/* signal enum */
-enum
-{
- ERROR,
- UNHOLD_FAILED,
-
- LAST_SIGNAL
-};
-
-static guint signals[LAST_SIGNAL] = {0};
-
-/* properties */
-enum
-{
- PROP_DBUS_DAEMON = 1,
- PROP_OBJECT_PATH,
- PROP_NAME,
- PROP_ID,
- PROP_MEDIA_TYPE,
- PROP_CONNECTION_STATE,
- PROP_READY,
- PROP_PLAYING,
- PROP_COMBINED_DIRECTION,
- PROP_LOCAL_HOLD,
- PROP_CONTENT,
- PROP_STUN_SERVERS,
- PROP_RELAY_INFO,
- PROP_NAT_TRAVERSAL,
- PROP_CREATED_LOCALLY,
- LAST_PROPERTY
-};
-
-/* private structure */
-
-struct _GabbleMediaStreamPrivate
-{
- WockyJingleContent *content;
-
- TpDBusDaemon *dbus_daemon;
- gchar *object_path;
- guint id;
- guint media_type;
-
- gboolean local_codecs_set;
-
- /* Whether we're waiting for a codec intersection from the streaming
- * implementation. If FALSE, SupportedCodecs is a no-op.
- */
- gboolean awaiting_intersection;
-
- GValue local_rtp_hdrexts;
- GValue local_feedback_messages;
-
- GValue remote_codecs;
- GValue remote_rtp_hdrexts;
- GValue remote_feedback_messages;
- GValue remote_candidates;
-
- guint remote_candidate_count;
-
- /* source ID for initial codecs/candidates getter */
- gulong initial_getter_id;
-
- gchar *nat_traversal;
- /* GPtrArray(GValueArray(STRING, UINT)) */
- GPtrArray *stun_servers;
- /* GPtrArray(GHashTable(string => GValue)) */
- GPtrArray *relay_info;
-
- gboolean on_hold;
-
- /* These are really booleans, but gboolean is signed. Thanks, GLib */
- unsigned closed:1;
- unsigned dispose_has_run:1;
- unsigned local_hold:1;
- unsigned ready:1;
- unsigned sending:1;
- unsigned created_locally:1;
-};
-
-static void push_remote_media_description (GabbleMediaStream *stream);
-static void push_remote_candidates (GabbleMediaStream *stream);
-static void push_playing (GabbleMediaStream *stream);
-static void push_sending (GabbleMediaStream *stream);
-
-static void new_remote_candidates_cb (WockyJingleContent *content,
- GList *clist, GabbleMediaStream *stream);
-static void new_remote_media_description_cb (WockyJingleContent *content,
- WockyJingleMediaDescription *md, GabbleMediaStream *stream);
-static void content_state_changed_cb (WockyJingleContent *c,
- GParamSpec *pspec, GabbleMediaStream *stream);
-static void content_senders_changed_cb (WockyJingleContent *c,
- GParamSpec *pspec, GabbleMediaStream *stream);
-static void remote_state_changed_cb (WockyJingleSession *session,
- GabbleMediaStream *stream);
-static void content_removed_cb (WockyJingleContent *content,
- GabbleMediaStream *stream);
-static void update_direction (GabbleMediaStream *stream, WockyJingleContent *c);
-static void update_sending (GabbleMediaStream *stream, gboolean start_sending);
-
-GabbleMediaStream *
-gabble_media_stream_new (
- TpDBusDaemon *dbus_daemon,
- const gchar *object_path,
- WockyJingleContent *content,
- const gchar *name,
- guint id,
- const gchar *nat_traversal,
- const GPtrArray *relay_info,
- gboolean local_hold)
-{
- GPtrArray *empty = NULL;
- GabbleMediaStream *result;
-
- g_return_val_if_fail (WOCKY_IS_JINGLE_MEDIA_RTP (content), NULL);
-
- if (relay_info == NULL)
- {
- empty = g_ptr_array_sized_new (0);
- relay_info = empty;
- }
-
- result = g_object_new (GABBLE_TYPE_MEDIA_STREAM,
- "dbus-daemon", dbus_daemon,
- "object-path", object_path,
- "content", content,
- "name", name,
- "id", id,
- "nat-traversal", nat_traversal,
- "relay-info", relay_info,
- "local-hold", local_hold,
- NULL);
-
- if (empty != NULL)
- g_ptr_array_unref (empty);
-
- return result;
-}
-
-TpMediaStreamType
-gabble_media_stream_get_media_type (GabbleMediaStream *self)
-{
- return self->priv->media_type;
-}
-
-static void
-gabble_media_stream_init (GabbleMediaStream *self)
-{
- GabbleMediaStreamPrivate *priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
- GABBLE_TYPE_MEDIA_STREAM, GabbleMediaStreamPrivate);
- GType candidate_list_type =
- TP_ARRAY_TYPE_MEDIA_STREAM_HANDLER_CANDIDATE_LIST;
- GType codec_list_type =
- TP_ARRAY_TYPE_MEDIA_STREAM_HANDLER_CODEC_LIST;
- GType rtp_hdrext_list_type = TP_ARRAY_TYPE_RTP_HEADER_EXTENSIONS_LIST;
- GType fb_msg_map_type = TP_HASH_TYPE_RTCP_FEEDBACK_MESSAGE_MAP;
-
- self->priv = priv;
-
- g_value_init (&priv->local_rtp_hdrexts, rtp_hdrext_list_type);
- g_value_init (&priv->local_feedback_messages, fb_msg_map_type);
-
- g_value_init (&priv->remote_codecs, codec_list_type);
- g_value_take_boxed (&priv->remote_codecs,
- dbus_g_type_specialized_construct (codec_list_type));
-
- g_value_init (&priv->remote_rtp_hdrexts, rtp_hdrext_list_type);
- g_value_take_boxed (&priv->remote_rtp_hdrexts,
- dbus_g_type_specialized_construct (rtp_hdrext_list_type));
-
- g_value_init (&priv->remote_feedback_messages, fb_msg_map_type);
- g_value_take_boxed (&priv->remote_feedback_messages,
- dbus_g_type_specialized_construct (fb_msg_map_type));
-
- g_value_init (&priv->remote_candidates, candidate_list_type);
- g_value_take_boxed (&priv->remote_candidates,
- dbus_g_type_specialized_construct (candidate_list_type));
-
- priv->stun_servers = g_ptr_array_sized_new (1);
-}
-
-static gboolean
-_get_initial_codecs_and_candidates (gpointer user_data)
-{
- GabbleMediaStream *stream = GABBLE_MEDIA_STREAM (user_data);
- GabbleMediaStreamPrivate *priv = stream->priv;
- WockyJingleMediaDescription *md;
-
- priv->initial_getter_id = 0;
-
- /* we can immediately get the codecs if we're responder */
- md = wocky_jingle_media_rtp_get_remote_media_description (
- WOCKY_JINGLE_MEDIA_RTP (priv->content));
- if (md != NULL)
- new_remote_media_description_cb (priv->content, md, stream);
-
- /* if any candidates arrived before idle loop had the chance to excute
- * us (e.g. specified in session-initiate/content-add), we don't want to
- * miss them */
- new_remote_candidates_cb (priv->content,
- wocky_jingle_content_get_remote_candidates (priv->content), stream);
-
- return FALSE;
-}
-
-static GObject *
-gabble_media_stream_constructor (GType type, guint n_props,
- GObjectConstructParam *props)
-{
- GObject *obj;
- GabbleMediaStream *stream;
- GabbleMediaStreamPrivate *priv;
- WockyJingleFactory *jf;
- GList *stun_servers;
-
- /* call base class constructor */
- obj = G_OBJECT_CLASS (gabble_media_stream_parent_class)->
- constructor (type, n_props, props);
- stream = GABBLE_MEDIA_STREAM (obj);
- priv = stream->priv;
-
- g_assert (priv->content != NULL);
-
- /* STUN servers are needed as soon as the stream appears, so there's little
- * point in waiting for them - either they've already been resolved, or
- * we're too late to use them for this stream */
- jf = wocky_jingle_session_get_factory (priv->content->session);
- stun_servers = wocky_jingle_info_get_stun_servers (
- wocky_jingle_factory_get_jingle_info (jf));
- while (stun_servers != NULL)
- {
- WockyStunServer *stun_server = stun_servers->data;
- GValueArray *va = tp_value_array_build (2,
- G_TYPE_STRING, stun_server->address,
- G_TYPE_UINT, (guint) stun_server->port,
- G_TYPE_INVALID);
-
- g_ptr_array_add (priv->stun_servers, va);
-
- stun_servers = g_list_delete_link (stun_servers, stun_servers);
- }
-
- /* go for the bus */
- g_assert (priv->dbus_daemon != NULL);
- tp_dbus_daemon_register_object (priv->dbus_daemon, priv->object_path, obj);
-
- update_direction (stream, priv->content);
-
- /* MediaStream is created as soon as WockyJingleContent is
- * created, but we want to let it parse the initiation (if
- * initiated by remote end) before we pick up initial
- * codecs and candidates.
- * FIXME: add API for ordering IQs rather than using g_idle_add.
- */
- priv->initial_getter_id =
- g_idle_add (_get_initial_codecs_and_candidates, stream);
-
- 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;
- }
-
- return obj;
-}
-
-static void
-gabble_media_stream_get_property (GObject *object,
- guint property_id,
- GValue *value,
- GParamSpec *pspec)
-{
- GabbleMediaStream *stream = GABBLE_MEDIA_STREAM (object);
- GabbleMediaStreamPrivate *priv = stream->priv;
-
- switch (property_id) {
- case PROP_DBUS_DAEMON:
- g_value_set_object (value, priv->dbus_daemon);
- break;
- case PROP_OBJECT_PATH:
- g_value_set_string (value, priv->object_path);
- break;
- case PROP_NAME:
- g_value_set_string (value, stream->name);
- 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_CONTENT:
- g_value_set_object (value, priv->content);
- 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
-gabble_media_stream_set_property (GObject *object,
- guint property_id,
- const GValue *value,
- GParamSpec *pspec)
-{
- GabbleMediaStream *stream = GABBLE_MEDIA_STREAM (object);
- GabbleMediaStreamPrivate *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);
- 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_ID:
- priv->id = 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:
- {
- gboolean old = stream->playing;
- stream->playing = g_value_get_boolean (value);
- if (stream->playing != old)
- push_playing (stream);
- }
- 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_CONTENT:
- g_assert (priv->content == NULL);
-
- priv->content = g_value_dup_object (value);
-
- {
- guint jtype;
- gboolean locally_created;
-
- g_object_get (priv->content,
- "media-type", &jtype,
- "locally-created", &locally_created,
- NULL);
-
- if (jtype == WOCKY_JINGLE_MEDIA_TYPE_VIDEO)
- priv->media_type = TP_MEDIA_STREAM_TYPE_VIDEO;
- else
- priv->media_type = TP_MEDIA_STREAM_TYPE_AUDIO;
-
- priv->created_locally = locally_created;
- }
-
- DEBUG ("%p: connecting to content %p signals", stream, priv->content);
-
- gabble_signal_connect_weak (priv->content, "new-candidates",
- (GCallback) new_remote_candidates_cb, object);
-
- /* we need this also, if we're the initiator of the stream
- * (so remote codecs arrive later) */
- gabble_signal_connect_weak (priv->content, "remote-media-description",
- (GCallback) new_remote_media_description_cb, object);
-
- gabble_signal_connect_weak (priv->content, "notify::state",
- (GCallback) content_state_changed_cb, object);
-
- gabble_signal_connect_weak (priv->content, "notify::senders",
- (GCallback) content_senders_changed_cb, object);
-
- gabble_signal_connect_weak (priv->content->session,
- "remote-state-changed", (GCallback) remote_state_changed_cb, object);
-
- gabble_signal_connect_weak (priv->content, "removed",
- (GCallback) content_removed_cb, object);
- break;
- case PROP_NAT_TRAVERSAL:
- g_assert (priv->nat_traversal == NULL);
- priv->nat_traversal = g_value_dup_string (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 gabble_media_stream_dispose (GObject *object);
-static void gabble_media_stream_finalize (GObject *object);
-
-static void
-gabble_media_stream_class_init (GabbleMediaStreamClass *gabble_media_stream_class)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (gabble_media_stream_class);
- GParamSpec *param_spec;
- 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 }
- };
-
- g_type_class_add_private (gabble_media_stream_class,
- sizeof (GabbleMediaStreamPrivate));
-
- object_class->constructor = gabble_media_stream_constructor;
-
- object_class->get_property = gabble_media_stream_get_property;
- object_class->set_property = gabble_media_stream_set_property;
-
- object_class->dispose = gabble_media_stream_dispose;
- object_class->finalize = gabble_media_stream_finalize;
-
- param_spec = g_param_spec_object ("dbus-daemon", "TpDBusDaemon",
- "Bus on which to export this object",
- 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 ("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_NAME |
- G_PARAM_STATIC_BLURB);
- g_object_class_install_property (object_class, PROP_OBJECT_PATH, 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_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_READABLE | 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 ("content", "WockyJingleContent object",
- "Jingle content signalling this media stream.",
- WOCKY_TYPE_JINGLE_CONTENT,
- G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_READWRITE |
- G_PARAM_STATIC_NICK |
- G_PARAM_STATIC_BLURB);
- g_object_class_install_property (object_class, PROP_CONTENT, 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_READABLE | G_PARAM_STATIC_STRINGS);
- g_object_class_install_property (object_class, PROP_CREATED_LOCALLY,
- param_spec);
-
- /* signals not exported by D-Bus interface */
-
- signals[ERROR] =
- g_signal_new ("error",
- G_OBJECT_CLASS_TYPE (gabble_media_stream_class),
- G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
- 0,
- NULL, NULL,
- gabble_marshal_VOID__UINT_STRING,
- G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_STRING);
-
- signals[UNHOLD_FAILED] = g_signal_new ("unhold-failed",
- G_OBJECT_CLASS_TYPE (gabble_media_stream_class),
- G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, 0, NULL, NULL,
- g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
-
- gabble_media_stream_class->props_class.interfaces = prop_interfaces;
- tp_dbus_properties_mixin_class_init (object_class,
- G_STRUCT_OFFSET (GabbleMediaStreamClass, props_class));
-}
-
-void
-gabble_media_stream_dispose (GObject *object)
-{
- GabbleMediaStream *self = GABBLE_MEDIA_STREAM (object);
- GabbleMediaStreamPrivate *priv = self->priv;
-
- DEBUG ("called");
-
- if (priv->dispose_has_run)
- return;
-
- if (priv->initial_getter_id != 0)
- {
- g_source_remove (priv->initial_getter_id);
- priv->initial_getter_id = 0;
- }
-
- gabble_media_stream_close (self);
-
- priv->dispose_has_run = TRUE;
-
- tp_clear_object (&priv->content);
- tp_clear_pointer (&self->name, g_free);
- g_clear_object (&priv->dbus_daemon);
-
- if (G_OBJECT_CLASS (gabble_media_stream_parent_class)->dispose)
- G_OBJECT_CLASS (gabble_media_stream_parent_class)->dispose (object);
-}
-
-void
-gabble_media_stream_finalize (GObject *object)
-{
- GabbleMediaStream *self = GABBLE_MEDIA_STREAM (object);
- GabbleMediaStreamPrivate *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_value_unset (&priv->local_rtp_hdrexts);
- g_value_unset (&priv->local_feedback_messages);
-
- g_value_unset (&priv->remote_codecs);
- g_value_unset (&priv->remote_rtp_hdrexts);
- g_value_unset (&priv->remote_feedback_messages);
- g_value_unset (&priv->remote_candidates);
-
- G_OBJECT_CLASS (gabble_media_stream_parent_class)->finalize (object);
-}
-
-/**
- * gabble_media_stream_codec_choice
- *
- * Implements D-Bus method CodecChoice
- * on interface org.freedesktop.Telepathy.Media.StreamHandler
- */
-static void
-gabble_media_stream_codec_choice (TpSvcMediaStreamHandler *iface,
- guint codec_id,
- DBusGMethodInvocation *context)
-{
- tp_svc_media_stream_handler_return_from_codec_choice (context);
-}
-
-
-gboolean
-gabble_media_stream_error (GabbleMediaStream *self,
- guint errnum,
- const gchar *message,
- GError **error)
-{
- g_assert (GABBLE_IS_MEDIA_STREAM (self));
-
- DEBUG ( "Media.StreamHandler::Error called, error %u (%s) -- emitting signal",
- errnum, message);
- g_signal_emit (self, signals[ERROR], 0, errnum, message);
-
- return TRUE;
-}
-
-
-/**
- * gabble_media_stream_error
- *
- * Implements D-Bus method Error
- * on interface org.freedesktop.Telepathy.Media.StreamHandler
- */
-static void
-gabble_media_stream_error_async (TpSvcMediaStreamHandler *iface,
- guint errnum,
- const gchar *message,
- DBusGMethodInvocation *context)
-{
- GabbleMediaStream *self = GABBLE_MEDIA_STREAM (iface);
- GError *error = NULL;
-
- if (gabble_media_stream_error (self, errnum, message, &error))
- {
- tp_svc_media_stream_handler_return_from_error (context);
- }
- else
- {
- dbus_g_method_return_error (context, error);
- g_error_free (error);
- }
-}
-
-
-/**
- * gabble_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
-gabble_media_stream_hold (GabbleMediaStream *self,
- gboolean hold)
-{
- tp_svc_media_stream_handler_emit_set_stream_held (self, hold);
-}
-
-
-/**
- * gabble_media_stream_hold_state:
- *
- * Called by streaming clients when the stream's hold state has been changed
- * successfully in response to SetStreamHeld.
- */
-static void
-gabble_media_stream_hold_state (TpSvcMediaStreamHandler *iface,
- gboolean hold_state,
- DBusGMethodInvocation *context)
-{
- GabbleMediaStream *self = GABBLE_MEDIA_STREAM (iface);
- GabbleMediaStreamPrivate *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);
-}
-
-
-/**
- * gabble_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
-gabble_media_stream_unhold_failure (TpSvcMediaStreamHandler *iface,
- DBusGMethodInvocation *context)
-{
- GabbleMediaStream *self = GABBLE_MEDIA_STREAM (iface);
- GabbleMediaStreamPrivate *priv = self->priv;
-
- DEBUG ("%p", self);
-
- priv->local_hold = TRUE;
-
- g_signal_emit (self, signals[UNHOLD_FAILED], 0);
- g_object_notify ((GObject *) self, "local-hold");
-
- tp_svc_media_stream_handler_return_from_unhold_failure (context);
-}
-
-
-/**
- * gabble_media_stream_native_candidates_prepared
- *
- * Implements D-Bus method NativeCandidatesPrepared
- * on interface org.freedesktop.Telepathy.Media.StreamHandler
- */
-static void
-gabble_media_stream_native_candidates_prepared (TpSvcMediaStreamHandler *iface,
- DBusGMethodInvocation *context)
-{
- tp_svc_media_stream_handler_return_from_native_candidates_prepared (context);
-}
-
-
-/**
- * gabble_media_stream_new_active_candidate_pair
- *
- * Implements D-Bus method NewActiveCandidatePair
- * on interface org.freedesktop.Telepathy.Media.StreamHandler
- */
-static void
-gabble_media_stream_new_active_candidate_pair (TpSvcMediaStreamHandler *iface,
- const gchar *native_candidate_id,
- const gchar *remote_candidate_id,
- DBusGMethodInvocation *context)
-{
- DEBUG ("called (%s, %s); this is a no-op on Jingle", native_candidate_id,
- remote_candidate_id);
-
- tp_svc_media_stream_handler_return_from_new_active_candidate_pair (context);
-}
-
-
-/**
- * gabble_media_stream_new_native_candidate
- *
- * Implements D-Bus method NewNativeCandidate
- * on interface org.freedesktop.Telepathy.Media.StreamHandler
- */
-static void
-gabble_media_stream_new_native_candidate (TpSvcMediaStreamHandler *iface,
- const gchar *candidate_id,
- const GPtrArray *transports,
- DBusGMethodInvocation *context)
-{
- GabbleMediaStream *self = GABBLE_MEDIA_STREAM (iface);
- GabbleMediaStreamPrivate *priv;
- WockyJingleState state;
- GList *li = NULL;
- guint i;
-
- g_assert (GABBLE_IS_MEDIA_STREAM (self));
-
- priv = self->priv;
-
- g_object_get (priv->content->session, "state", &state, NULL);
-
- /* FIXME: maybe this should be an assertion in case the channel
- * isn't closed early enough right now? */
- if (state > WOCKY_JINGLE_STATE_ACTIVE)
- {
- DEBUG ("state > WOCKY_JINGLE_STATE_ACTIVE, doing nothing");
- tp_svc_media_stream_handler_return_from_new_native_candidate (context);
- return;
- }
-
- for (i = 0; i < transports->len; i++)
- {
- GValueArray *transport;
- guint component;
- const gchar *addr;
- WockyJingleCandidate *c;
-
- transport = g_ptr_array_index (transports, i);
- component = g_value_get_uint (g_value_array_get_nth (transport, 0));
-
- /* Farsight 1 compatibility */
- if (component == 0)
- component = 1;
-
- /* We understand RTP and RTCP, and silently ignore the rest */
- if ((component != 1) && (component != 2))
- continue;
-
- addr = g_value_get_string (g_value_array_get_nth (transport, 1));
- if (!strcmp (addr, "127.0.0.1"))
- {
- DEBUG ("ignoring native localhost candidate");
- continue;
- }
-
- c = wocky_jingle_candidate_new (
- /* protocol */
- g_value_get_uint (g_value_array_get_nth (transport, 3)),
- /* candidate type, we're relying on 1:1 candidate type mapping */
- g_value_get_uint (g_value_array_get_nth (transport, 7)),
- /* id */
- candidate_id,
- /* component */
- component,
- /* address */
- g_value_get_string (g_value_array_get_nth (transport, 1)),
- /* port */
- g_value_get_uint (g_value_array_get_nth (transport, 2)),
- /* generation */
- 0,
- /* preference */
- (int) (g_value_get_double (g_value_array_get_nth (transport, 6)) * 65536),
- /* username */
- g_value_get_string (g_value_array_get_nth (transport, 8)),
- /* password */
- g_value_get_string (g_value_array_get_nth (transport, 9)),
- /* network */
- 0);
-
- li = g_list_prepend (li, c);
- }
-
- if (li != NULL)
- wocky_jingle_content_add_candidates (priv->content, li);
-
- tp_svc_media_stream_handler_return_from_new_native_candidate (context);
-}
-
-static void gabble_media_stream_set_local_codecs (TpSvcMediaStreamHandler *,
- const GPtrArray *codecs, DBusGMethodInvocation *);
-
-/**
- * gabble_media_stream_ready
- *
- * Implements D-Bus method Ready
- * on interface org.freedesktop.Telepathy.Media.StreamHandler
- */
-static void
-gabble_media_stream_ready (TpSvcMediaStreamHandler *iface,
- const GPtrArray *codecs,
- DBusGMethodInvocation *context)
-{
- GabbleMediaStream *self = GABBLE_MEDIA_STREAM (iface);
- GabbleMediaStreamPrivate *priv;
-
- g_assert (GABBLE_IS_MEDIA_STREAM (self));
-
- priv = self->priv;
-
- DEBUG ("ready called");
-
- if (priv->ready == FALSE)
- {
- g_object_set (self, "ready", TRUE, NULL);
-
- push_remote_media_description (self);
- push_remote_candidates (self);
- push_playing (self);
- push_sending (self);
-
- /* 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)
- gabble_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... */
- gabble_media_stream_set_local_codecs (iface, codecs, context);
-}
-
-static gboolean
-pass_local_codecs (GabbleMediaStream *stream,
- const GPtrArray *codecs,
- gboolean ready,
- GError **error)
-{
- GabbleMediaStreamPrivate *priv = stream->priv;
- guint i;
- WockyJingleMediaDescription *md;
- const GPtrArray *hdrexts;
- GHashTable *fbs;
- GError *wocky_error = NULL;
-
- DEBUG ("putting list of %d supported codecs from stream-engine into cache",
- codecs->len);
-
- md = wocky_jingle_media_description_new ();
-
- fbs = g_value_get_boxed (&priv->local_feedback_messages);
-
- 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;
- WockyJingleCodec *c;
- GValueArray *fb_codec;
-
- 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, &params,
- G_MAXUINT);
-
- c = jingle_media_rtp_codec_new (id, name,
- clock_rate, channels, params);
-
- if (fbs != NULL)
- {
- fb_codec = g_hash_table_lookup (fbs, GUINT_TO_POINTER (id));
- if (fb_codec != NULL)
- {
- if (G_VALUE_HOLDS_UINT (
- g_value_array_get_nth (fb_codec, 0)) &&
- G_VALUE_TYPE (g_value_array_get_nth (fb_codec, 1)) ==
- TP_ARRAY_TYPE_RTCP_FEEDBACK_MESSAGE_LIST)
- {
- GValue *val;
- const GPtrArray *fb_array;
- guint j;
-
- val = g_value_array_get_nth (fb_codec, 0);
- c->trr_int = g_value_get_uint (val);
-
- val = g_value_array_get_nth (fb_codec, 1);
- fb_array = g_value_get_boxed (val);
-
- for (j = 0; j < fb_array->len; j++)
- {
- GValueArray *message = g_ptr_array_index (fb_array, j);
- const gchar *type;
- const gchar *subtype;
-
- val = g_value_array_get_nth (message, 0);
- type = g_value_get_string (val);
-
- val = g_value_array_get_nth (message, 1);
- subtype = g_value_get_string (val);
-
- c->feedback_msgs = g_list_append (c->feedback_msgs,
- wocky_jingle_feedback_message_new (type, subtype));
- }
- }
- }
- }
- DEBUG ("adding codec %s (%u %u %u)", c->name, c->id, c->clockrate, c->channels);
- md->codecs = g_list_append (md->codecs, c);
- g_free (name);
- g_hash_table_unref (params);
- }
-
- if (fbs != NULL)
- g_value_reset (&priv->local_feedback_messages);
-
- hdrexts = g_value_get_boxed (&priv->local_rtp_hdrexts);
-
- if (hdrexts != NULL)
- {
- gboolean have_initiator = FALSE;
- gboolean initiated_by_us;
-
- for (i = 0; i < hdrexts->len; i++)
- {
- GValueArray *hdrext;
- guint id;
- guint direction;
- WockyJingleContentSenders senders;
- gchar *uri;
- gchar *params;
-
- hdrext = g_ptr_array_index (hdrexts, i);
-
- g_assert (hdrext);
- g_assert (hdrext->n_values == 4);
- g_assert (G_VALUE_HOLDS_UINT (g_value_array_get_nth (hdrext, 0)));
- g_assert (G_VALUE_HOLDS_UINT (g_value_array_get_nth (hdrext, 1)));
- g_assert (G_VALUE_HOLDS_STRING (g_value_array_get_nth (hdrext, 2)));
- g_assert (G_VALUE_HOLDS_STRING (g_value_array_get_nth (hdrext, 3)));
-
- tp_value_array_unpack (hdrext, 4,
- &id,
- &direction,
- &uri,
- &params);
-
- if (!have_initiator)
- {
- g_object_get (priv->content->session, "local-initiator",
- &initiated_by_us, NULL);
- have_initiator = TRUE;
- }
-
- switch (direction)
- {
- case TP_MEDIA_STREAM_DIRECTION_BIDIRECTIONAL:
- senders = WOCKY_JINGLE_CONTENT_SENDERS_BOTH;
- break;
- case TP_MEDIA_STREAM_DIRECTION_NONE:
- senders = WOCKY_JINGLE_CONTENT_SENDERS_NONE;
- break;
- case TP_MEDIA_STREAM_DIRECTION_SEND:
- senders = initiated_by_us ? WOCKY_JINGLE_CONTENT_SENDERS_INITIATOR :
- WOCKY_JINGLE_CONTENT_SENDERS_RESPONDER;
- break;
- case TP_MEDIA_STREAM_DIRECTION_RECEIVE:
- senders = initiated_by_us ? WOCKY_JINGLE_CONTENT_SENDERS_RESPONDER :
- WOCKY_JINGLE_CONTENT_SENDERS_INITIATOR;
- break;
- default:
- g_assert_not_reached ();
- }
-
- md->hdrexts = g_list_append (md->hdrexts,
- wocky_jingle_rtp_header_extension_new (id, senders, uri));
- }
- /* Can only be used once */
- g_value_reset (&priv->local_rtp_hdrexts);
- }
-
- wocky_jingle_media_description_simplify (md);
-
- if (jingle_media_rtp_set_local_media_description (
- WOCKY_JINGLE_MEDIA_RTP (priv->content), md, ready, &wocky_error))
- return TRUE;
-
- g_set_error_literal (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT,
- wocky_error->message);
- g_clear_error (&wocky_error);
- return FALSE;
-}
-
-/**
- * gabble_media_stream_set_local_codecs
- *
- * Implements D-Bus method SetLocalCodecs
- * on interface org.freedesktop.Telepathy.Media.StreamHandler
- */
-static void
-gabble_media_stream_set_local_codecs (TpSvcMediaStreamHandler *iface,
- const GPtrArray *codecs,
- DBusGMethodInvocation *context)
-{
- GabbleMediaStream *self = GABBLE_MEDIA_STREAM (iface);
- GabbleMediaStreamPrivate *priv = self->priv;
- GError *error = NULL;
-
- DEBUG ("called");
-
- if (codecs->len == 0)
- goto done;
-
- priv->local_codecs_set = TRUE;
-
- if (wocky_jingle_content_is_created_by_us (self->priv->content))
- {
- 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");
- }
- done:
-
- tp_svc_media_stream_handler_return_from_set_local_codecs (context);
-}
-
-/**
- * gabble_media_stream_stream_state
- *
- * Implements D-Bus method StreamState
- * on interface org.freedesktop.Telepathy.Media.StreamHandler
- */
-static void
-gabble_media_stream_stream_state (TpSvcMediaStreamHandler *iface,
- guint connection_state,
- DBusGMethodInvocation *context)
-{
- GabbleMediaStream *self = GABBLE_MEDIA_STREAM (iface);
- GabbleMediaStreamPrivate *priv = self->priv;
- WockyJingleTransportState ts = WOCKY_JINGLE_TRANSPORT_STATE_DISCONNECTED;
-
- switch (connection_state) {
- case TP_MEDIA_STREAM_STATE_DISCONNECTED:
- ts = WOCKY_JINGLE_TRANSPORT_STATE_DISCONNECTED;
- break;
- case TP_MEDIA_STREAM_STATE_CONNECTING:
- ts = WOCKY_JINGLE_TRANSPORT_STATE_CONNECTING;
- break;
- case TP_MEDIA_STREAM_STATE_CONNECTED:
- ts = WOCKY_JINGLE_TRANSPORT_STATE_CONNECTED;
- break;
- default:
- DEBUG ("ignoring unknown connection state %u", connection_state);
- goto OUT;
- }
-
- g_object_set (self, "connection-state", connection_state, NULL);
- wocky_jingle_content_set_transport_state (priv->content, ts);
-
-OUT:
- tp_svc_media_stream_handler_return_from_stream_state (context);
-}
-
-
-/**
- * gabble_media_stream_supported_codecs
- *
- * Implements D-Bus method SupportedCodecs
- * on interface org.freedesktop.Telepathy.Media.StreamHandler
- */
-static void
-gabble_media_stream_supported_codecs (TpSvcMediaStreamHandler *iface,
- const GPtrArray *codecs,
- DBusGMethodInvocation *context)
-{
- GabbleMediaStream *self = GABBLE_MEDIA_STREAM (iface);
- GabbleMediaStreamPrivate *priv = self->priv;
- GError *error = NULL;
-
- DEBUG ("called");
-
- if (codecs->len == 0)
- {
- GError e = { TP_ERROR, TP_ERROR_INVALID_ARGUMENT,
- "SupportedCodecs must have a non-empty list of codecs" };
-
- dbus_g_method_return_error (context, &e);
- return;
- }
-
- priv->local_codecs_set = TRUE;
-
- 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);
-}
-
-/**
- * gabble_media_stream_codecs_updated
- *
- * Implements D-Bus method CodecsUpdated
- * on interface org.freedesktop.Telepathy.Media.StreamHandler
- */
-static void
-gabble_media_stream_codecs_updated (TpSvcMediaStreamHandler *iface,
- const GPtrArray *codecs,
- DBusGMethodInvocation *context)
-{
- GabbleMediaStream *self = GABBLE_MEDIA_STREAM (iface);
- GError *error = NULL;
-
- if (!self->priv->local_codecs_set)
- {
- 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);
- }
-}
-
-/**
- * gabble_media_stream_supported_header_extensions
- *
- * Implements D-Bus method SupportedHeaderExtensions
- * on interface org.freedesktop.Telepathy.Media.StreamHandler
- */
-static void
-gabble_media_stream_supported_header_extensions (TpSvcMediaStreamHandler *iface,
- const GPtrArray *hdrexts,
- DBusGMethodInvocation *context)
-{
- GabbleMediaStream *self = GABBLE_MEDIA_STREAM (iface);
-
- g_value_set_boxed (&self->priv->local_rtp_hdrexts, hdrexts);
-
- tp_svc_media_stream_handler_return_from_supported_header_extensions (context);
-}
-
-/**
- * gabble_media_stream_supported_feedback_messages
- *
- * Implements D-Bus method SupportedFeedbackMessages
- * on interface org.freedesktop.Telepathy.Media.StreamHandler
- */
-static void
-gabble_media_stream_supported_feedback_messages (TpSvcMediaStreamHandler *iface,
- GHashTable *messages,
- DBusGMethodInvocation *context)
-{
- GabbleMediaStream *self = GABBLE_MEDIA_STREAM (iface);
-
- g_value_set_boxed (&self->priv->local_feedback_messages, messages);
-
- tp_svc_media_stream_handler_return_from_supported_feedback_messages (context);
-}
-
-void
-gabble_media_stream_close (GabbleMediaStream *stream)
-{
- GabbleMediaStreamPrivate *priv;
-
- g_assert (GABBLE_IS_MEDIA_STREAM (stream));
-
- priv = stream->priv;
-
- if (!priv->closed)
- {
- priv->closed = TRUE;
- tp_svc_media_stream_handler_emit_close (stream);
- }
-}
-
-static void
-insert_feedback_message (WockyJingleFeedbackMessage *fb, GPtrArray *fb_msgs)
-{
- GValueArray *msg;
-
- msg = tp_value_array_build (3,
- G_TYPE_STRING, fb->type,
- G_TYPE_STRING, fb->subtype,
- G_TYPE_STRING, "",
- G_TYPE_INVALID);
-
- g_ptr_array_add (fb_msgs, msg);
-}
-
-static void
-new_remote_media_description_cb (WockyJingleContent *content,
- WockyJingleMediaDescription *md, GabbleMediaStream *stream)
-{
- GabbleMediaStreamPrivate *priv;
- GList *li;
- GPtrArray *codecs;
- GPtrArray *hdrexts;
- GHashTable *fbs;
- GType codec_struct_type = TP_STRUCT_TYPE_MEDIA_STREAM_HANDLER_CODEC;
- gboolean have_initiator = FALSE;
- gboolean initiated_by_us;
-
- DEBUG ("called");
-
- g_assert (GABBLE_IS_MEDIA_STREAM (stream));
-
- priv = stream->priv;
-
- codecs = g_value_get_boxed (&priv->remote_codecs);
-
- if (codecs->len != 0)
- {
- /* We already had some codecs; let's free the old list and make a new,
- * empty one to fill in.
- */
- g_value_reset (&priv->remote_codecs);
- codecs = dbus_g_type_specialized_construct (
- TP_ARRAY_TYPE_MEDIA_STREAM_HANDLER_CODEC_LIST);
- g_value_take_boxed (&priv->remote_codecs, codecs);
- }
-
- hdrexts = g_value_get_boxed (&priv->remote_rtp_hdrexts);
-
- if (hdrexts->len != 0)
- {
- /* We already had some rtp hdrext; let's free the old list and make a new,
- * empty one to fill in.
- */
- g_value_reset (&priv->remote_rtp_hdrexts);
- hdrexts = dbus_g_type_specialized_construct (
- TP_ARRAY_TYPE_RTP_HEADER_EXTENSIONS_LIST);
- g_value_take_boxed (&priv->remote_rtp_hdrexts, hdrexts);
- }
-
- fbs = g_value_get_boxed (&priv->remote_feedback_messages);
-
- if (g_hash_table_size (fbs) != 0)
- {
- /* We already had some rtp hdrext; let's free the old list and make a new,
- * empty one to fill in.
- */
- g_value_reset (&priv->remote_feedback_messages);
- fbs = dbus_g_type_specialized_construct (
- TP_HASH_TYPE_RTCP_FEEDBACK_MESSAGE_MAP);
- g_value_take_boxed (&priv->remote_feedback_messages, fbs);
- }
-
- for (li = md->codecs; li; li = li->next)
- {
- GValue codec = { 0, };
- WockyJingleCodec *c = li->data;
-
- g_value_init (&codec, codec_struct_type);
- g_value_take_boxed (&codec,
- dbus_g_type_specialized_construct (codec_struct_type));
-
- DEBUG ("new remote %s codec: %u '%s' %u %u %u",
- priv->media_type == TP_MEDIA_STREAM_TYPE_AUDIO ? "audio" : "video",
- c->id, c->name, priv->media_type, c->clockrate, c->channels);
-
- dbus_g_type_struct_set (&codec,
- 0, c->id,
- 1, c->name,
- 2, priv->media_type,
- 3, c->clockrate,
- 4, c->channels,
- 5, c->params,
- G_MAXUINT);
-
- if (md->trr_int != G_MAXUINT || c->trr_int != G_MAXUINT ||
- md->feedback_msgs != NULL || c->feedback_msgs != NULL)
- {
- GValueArray *fb_msg_props;
- guint trr_int;
- GPtrArray *fb_msgs = g_ptr_array_new ();
-
- if (c->trr_int != G_MAXUINT)
- trr_int = c->trr_int;
- else
- trr_int = md->trr_int;
-
- g_list_foreach (md->feedback_msgs, (GFunc) insert_feedback_message,
- fb_msgs);
- g_list_foreach (c->feedback_msgs, (GFunc) insert_feedback_message,
- fb_msgs);
-
- fb_msg_props = tp_value_array_build (2,
- G_TYPE_UINT, trr_int,
- TP_ARRAY_TYPE_RTCP_FEEDBACK_MESSAGE_LIST, fb_msgs,
- G_TYPE_INVALID);
-
- g_boxed_free (TP_ARRAY_TYPE_RTCP_FEEDBACK_MESSAGE_LIST, fb_msgs);
-
- g_hash_table_insert (fbs, GUINT_TO_POINTER (c->id), fb_msg_props);
- }
-
- g_ptr_array_add (codecs, g_value_get_boxed (&codec));
- }
-
- for (li = md->hdrexts; li; li = li->next)
- {
- WockyJingleRtpHeaderExtension *h = li->data;
- TpMediaStreamDirection direction;
-
- if (!have_initiator)
- {
- g_object_get (priv->content->session, "local-initiator",
- &initiated_by_us, NULL);
- have_initiator = TRUE;
- }
-
- switch (h->senders)
- {
- case WOCKY_JINGLE_CONTENT_SENDERS_BOTH:
- direction = TP_MEDIA_STREAM_DIRECTION_BIDIRECTIONAL;
- break;
- case WOCKY_JINGLE_CONTENT_SENDERS_NONE:
- direction = TP_MEDIA_STREAM_DIRECTION_NONE;
- break;
- case WOCKY_JINGLE_CONTENT_SENDERS_INITIATOR:
- direction = initiated_by_us ? TP_MEDIA_STREAM_DIRECTION_SEND :
- TP_MEDIA_STREAM_DIRECTION_RECEIVE;
- break;
- case WOCKY_JINGLE_CONTENT_SENDERS_RESPONDER:
- direction = initiated_by_us ? TP_MEDIA_STREAM_DIRECTION_RECEIVE :
- TP_MEDIA_STREAM_DIRECTION_SEND;
- break;
- default:
- g_assert_not_reached ();
- }
-
- DEBUG ("new RTP header ext : %u %s", h->id, h->uri);
-
- g_ptr_array_add (hdrexts,
- tp_value_array_build (4,
- G_TYPE_UINT, h->id,
- G_TYPE_UINT, direction,
- G_TYPE_STRING, h->uri,
- G_TYPE_STRING, "", /* No protocol defines parameters */
- G_TYPE_INVALID));
- }
-
- DEBUG ("pushing remote codecs");
-
- push_remote_media_description (stream);
-}
-
-
-static void
-push_remote_media_description (GabbleMediaStream *stream)
-{
- GabbleMediaStreamPrivate *priv;
- GPtrArray *codecs;
- GPtrArray *hdrexts;
- GHashTable *fbs;
-
- g_assert (GABBLE_IS_MEDIA_STREAM (stream));
-
- priv = stream->priv;
-
- if (!priv->ready)
- return;
-
- codecs = g_value_get_boxed (&priv->remote_codecs);
- if (codecs->len == 0)
- return;
-
- hdrexts = g_value_get_boxed (&priv->remote_rtp_hdrexts);
-
- fbs = g_value_get_boxed (&priv->remote_feedback_messages);
-
- DEBUG ("passing %d remote codecs to stream-engine",
- codecs->len);
-
- tp_svc_media_stream_handler_emit_set_remote_header_extensions (stream,
- hdrexts);
- tp_svc_media_stream_handler_emit_set_remote_feedback_messages (stream, fbs);
- tp_svc_media_stream_handler_emit_set_remote_codecs (stream, codecs);
-}
-
-static void
-new_remote_candidates_cb (WockyJingleContent *content,
- GList *clist, GabbleMediaStream *stream)
-{
- GabbleMediaStreamPrivate *priv = stream->priv;
- GPtrArray *candidates;
- GList *li;
-
- candidates = g_value_get_boxed (&priv->remote_candidates);
-
- DEBUG ("got new remote candidates");
-
- for (li = clist; li; li = li->next)
- {
- gchar *candidate_id;
- GValue candidate = { 0, };
- GPtrArray *transports;
- GValue transport = { 0, };
- WockyJingleCandidate *c = li->data;
- GType transport_struct_type = TP_STRUCT_TYPE_MEDIA_STREAM_HANDLER_TRANSPORT;
- GType candidate_struct_type = TP_STRUCT_TYPE_MEDIA_STREAM_HANDLER_CANDIDATE;
-
- g_value_init (&transport, transport_struct_type);
- g_value_take_boxed (&transport,
- dbus_g_type_specialized_construct (transport_struct_type));
-
- dbus_g_type_struct_set (&transport,
- 0, c->component,
- 1, c->address,
- 2, c->port,
- 3, c->protocol == WOCKY_JINGLE_TRANSPORT_PROTOCOL_UDP ? 0 : 1,
- 4, "RTP",
- 5, "AVP",
- 6, (gdouble) (c->preference / 65536.0),
- 7, c->type, /* FIXME: we're relying on 1:1 tp/jingle candidate type enums */
- 8, c->username,
- 9, c->password,
- G_MAXUINT);
-
- 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));
-
- if (c->id == NULL)
- /* FIXME: is this naming scheme sensible? */
- candidate_id = g_strdup_printf ("R%d", ++priv->remote_candidate_count);
- else
- candidate_id = c->id;
-
- dbus_g_type_struct_set (&candidate,
- 0, candidate_id,
- 1, transports,
- G_MAXUINT);
-
- g_free (candidate_id);
- g_value_unset (&transport);
- g_ptr_array_unref (transports);
-
- g_ptr_array_add (candidates, g_value_get_boxed (&candidate));
- }
-
- push_remote_candidates (stream);
-}
-
-static void
-content_state_changed_cb (WockyJingleContent *c,
- GParamSpec *pspec,
- GabbleMediaStream *stream)
-{
- GabbleMediaStreamPrivate *priv = stream->priv;
- WockyJingleContentState state;
-
- g_object_get (c, "state", &state, NULL);
-
- DEBUG ("called");
-
- switch (state) {
- case WOCKY_JINGLE_CONTENT_STATE_ACKNOWLEDGED:
- /* connected stream means we can play, but sending is determined
- * by content senders (in update_senders) */
- stream->playing = TRUE;
- update_sending (stream, TRUE);
- push_playing (stream);
- push_sending (stream);
- break;
- case WOCKY_JINGLE_CONTENT_STATE_REMOVING:
- stream->playing = FALSE;
- priv->sending = FALSE;
- push_playing (stream);
- break;
- default:
- /* so gcc doesn't cry */
- break;
- }
-}
-
-static void
-push_remote_candidates (GabbleMediaStream *stream)
-{
- GabbleMediaStreamPrivate *priv;
- GPtrArray *candidates;
- guint i;
- GType candidate_list_type =
- TP_ARRAY_TYPE_MEDIA_STREAM_HANDLER_CANDIDATE_LIST;
-
- g_assert (GABBLE_IS_MEDIA_STREAM (stream));
-
- priv = stream->priv;
-
- candidates = g_value_get_boxed (&priv->remote_candidates);
-
- if (candidates->len == 0)
- return;
-
- if (!priv->ready)
- return;
-
- for (i = 0; i < candidates->len; i++)
- {
- GValueArray *candidate = g_ptr_array_index (candidates, i);
- const gchar *candidate_id;
- const GPtrArray *transports;
-
- candidate_id = g_value_get_string (g_value_array_get_nth (candidate, 0));
- transports = g_value_get_boxed (g_value_array_get_nth (candidate, 1));
-
- DEBUG ("passing 1 remote candidate to stream engine: %s", candidate_id);
- tp_svc_media_stream_handler_emit_add_remote_candidate (
- stream, candidate_id, transports);
- }
-
- g_value_take_boxed (&priv->remote_candidates,
- dbus_g_type_specialized_construct (candidate_list_type));
-}
-
-static void
-push_playing (GabbleMediaStream *stream)
-{
- GabbleMediaStreamPrivate *priv;
-
- g_assert (GABBLE_IS_MEDIA_STREAM (stream));
-
- priv = stream->priv;
-
- if (!priv->ready)
- return;
-
- DEBUG ("stream %s emitting SetStreamPlaying(%s)",
- stream->name, stream->playing ? "true" : "false");
-
- tp_svc_media_stream_handler_emit_set_stream_playing (
- stream, stream->playing);
-}
-
-static void
-push_sending (GabbleMediaStream *stream)
-{
- GabbleMediaStreamPrivate *priv;
- gboolean emit;
-
- g_assert (GABBLE_IS_MEDIA_STREAM (stream));
-
- priv = stream->priv;
-
- if (!priv->ready)
- return;
-
- emit = (priv->sending && !(priv->on_hold));
- DEBUG ("stream %s emitting SetStreamSending(%s); sending=%s, on_hold=%s",
- stream->name, emit ? "true" : "false", priv->sending ? "true" : "false",
- priv->on_hold ? "true" : "false");
-
- tp_svc_media_stream_handler_emit_set_stream_sending (
- stream, emit);
-}
-
-static void
-update_direction (GabbleMediaStream *stream, WockyJingleContent *c)
-{
- CombinedStreamDirection new_combined_dir;
- TpMediaStreamDirection requested_dir, current_dir;
- TpMediaStreamPendingSend pending_send;
- WockyJingleContentSenders senders;
- gboolean local_initiator;
-
- DEBUG ("called");
-
- g_object_get (c, "senders", &senders, NULL);
- g_object_get (c->session, "local-initiator", &local_initiator, NULL);
-
- switch (senders) {
- case WOCKY_JINGLE_CONTENT_SENDERS_INITIATOR:
- requested_dir = local_initiator ?
- TP_MEDIA_STREAM_DIRECTION_SEND : TP_MEDIA_STREAM_DIRECTION_RECEIVE;
- break;
- case WOCKY_JINGLE_CONTENT_SENDERS_RESPONDER:
- requested_dir = local_initiator ?
- TP_MEDIA_STREAM_DIRECTION_RECEIVE : TP_MEDIA_STREAM_DIRECTION_SEND;
- break;
- case WOCKY_JINGLE_CONTENT_SENDERS_BOTH:
- requested_dir = TP_MEDIA_STREAM_DIRECTION_BIDIRECTIONAL;
- break;
- default:
- requested_dir = TP_MEDIA_STREAM_DIRECTION_NONE;
- }
-
- current_dir = COMBINED_DIRECTION_GET_DIRECTION (stream->combined_direction);
- pending_send = COMBINED_DIRECTION_GET_PENDING_SEND
- (stream->combined_direction);
-
- /* if local sending has been added, remove it,
- * and set the pending local send flag */
- if (((current_dir & TP_MEDIA_STREAM_DIRECTION_SEND) == 0) &&
- ((requested_dir & TP_MEDIA_STREAM_DIRECTION_SEND) != 0))
- {
- DEBUG ("setting pending local send flag");
- requested_dir &= ~TP_MEDIA_STREAM_DIRECTION_SEND;
- pending_send |= TP_MEDIA_STREAM_PENDING_LOCAL_SEND;
- }
-
- /* make any necessary changes */
- new_combined_dir = MAKE_COMBINED_DIRECTION (requested_dir, pending_send);
- if (new_combined_dir != stream->combined_direction)
- {
- g_object_set (stream, "combined-direction", new_combined_dir, NULL);
- update_sending (stream, FALSE);
- }
-
-}
-
-static void
-content_senders_changed_cb (WockyJingleContent *c,
- GParamSpec *pspec,
- GabbleMediaStream *stream)
-{
- update_direction (stream, c);
-}
-
-static void
-remote_state_changed_cb (WockyJingleSession *session,
- GabbleMediaStream *stream)
-{
- GabbleMediaStreamPrivate *priv = stream->priv;
- gboolean old_hold = priv->on_hold;
-
- priv->on_hold = wocky_jingle_session_get_remote_hold (session);
-
- if (old_hold != priv->on_hold)
- push_sending (stream);
-}
-
-static void
-content_removed_cb (WockyJingleContent *content, GabbleMediaStream *stream)
-{
- gabble_media_stream_close (stream);
-}
-
-
-gboolean
-gabble_media_stream_change_direction (GabbleMediaStream *stream,
- guint requested_dir, GError **error)
-{
- GabbleMediaStreamPrivate *priv = stream->priv;
- CombinedStreamDirection new_combined_dir;
- TpMediaStreamDirection current_dir;
- TpMediaStreamPendingSend pending_send;
- WockyJingleContentSenders senders;
- gboolean local_initiator;
-
- current_dir = COMBINED_DIRECTION_GET_DIRECTION (stream->combined_direction);
- pending_send = COMBINED_DIRECTION_GET_PENDING_SEND
- (stream->combined_direction);
-
- /* if we're awaiting a local decision on sending... */
- if ((pending_send & TP_MEDIA_STREAM_PENDING_LOCAL_SEND) != 0)
- {
- /* clear the flag */
- pending_send &= ~TP_MEDIA_STREAM_PENDING_LOCAL_SEND;
-
- /* make our current_dir match what other end thinks (he thinks we're
- * bidirectional) so that we send the correct transitions */
- current_dir ^= TP_MEDIA_STREAM_DIRECTION_SEND;
- }
-
- /* make any necessary changes */
- new_combined_dir = MAKE_COMBINED_DIRECTION (requested_dir, pending_send);
- if (new_combined_dir != stream->combined_direction)
- {
- WockyJingleContentState state;
- gboolean start_sending;
-
- g_object_set (stream, "combined-direction", new_combined_dir, NULL);
-
- /* We would like to emit SetStreamSending(True) (if appropriate) only if:
- * - the content was locally created, or
- * - the user explicitly okayed the content.
- * This appears to be the meaning of Acknowledged. :-)
- */
- g_object_get (stream->priv->content, "state", &state, NULL);
- start_sending = (state == WOCKY_JINGLE_CONTENT_STATE_ACKNOWLEDGED);
-
- update_sending (stream, start_sending);
- }
-
- DEBUG ("current_dir: %u, requested_dir: %u", current_dir, requested_dir);
-
- /* short-circuit sending a request if we're not asking for anything new */
- if (current_dir == requested_dir)
- return TRUE;
-
- g_object_get (priv->content->session, "local-initiator", &local_initiator, NULL);
-
- switch (requested_dir)
- {
- case TP_MEDIA_STREAM_DIRECTION_SEND:
- senders = local_initiator ?
- WOCKY_JINGLE_CONTENT_SENDERS_INITIATOR : WOCKY_JINGLE_CONTENT_SENDERS_RESPONDER;
- break;
-
- case TP_MEDIA_STREAM_DIRECTION_RECEIVE:
- senders = local_initiator ?
- WOCKY_JINGLE_CONTENT_SENDERS_RESPONDER : WOCKY_JINGLE_CONTENT_SENDERS_INITIATOR;
- break;
-
- case TP_MEDIA_STREAM_DIRECTION_BIDIRECTIONAL:
- senders = WOCKY_JINGLE_CONTENT_SENDERS_BOTH;
- break;
-
- default:
- g_assert_not_reached ();
- }
-
- if (!wocky_jingle_content_change_direction (priv->content, senders))
- {
- g_set_error (error, TP_ERROR, TP_ERROR_NOT_AVAILABLE,
- "stream direction invalid for the Jingle dialect in use");
- return FALSE;
- }
-
- return TRUE;
-}
-
-void
-gabble_media_stream_accept_pending_local_send (GabbleMediaStream *stream)
-{
- CombinedStreamDirection combined_dir = stream->combined_direction;
- TpMediaStreamDirection current_dir;
- TpMediaStreamPendingSend pending_send;
-
- current_dir = COMBINED_DIRECTION_GET_DIRECTION (combined_dir);
- pending_send = COMBINED_DIRECTION_GET_PENDING_SEND (combined_dir);
-
- if ((pending_send & TP_MEDIA_STREAM_PENDING_LOCAL_SEND) != 0)
- {
- DEBUG ("accepting pending local send on stream %s", stream->name);
-
- gabble_media_stream_change_direction (stream,
- current_dir | TP_MEDIA_STREAM_DIRECTION_SEND, NULL);
- }
- else
- {
- DEBUG ("stream %s not pending local send", stream->name);
- }
-}
-
-static void
-update_sending (GabbleMediaStream *stream, gboolean start_sending)
-{
- GabbleMediaStreamPrivate *priv = stream->priv;
- gboolean new_sending;
-
- new_sending =
- ((stream->combined_direction & TP_MEDIA_STREAM_DIRECTION_SEND) != 0);
-
- if (priv->sending == new_sending)
- return;
-
- if (new_sending && !start_sending)
- return;
-
- priv->sending = new_sending;
- push_sending (stream);
-}
-
-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, gabble_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,);
- IMPLEMENT(supported_header_extensions,);
- IMPLEMENT(supported_feedback_messages,);
-#undef IMPLEMENT
-}
-
-WockyJingleMediaRtp *
-gabble_media_stream_get_content (GabbleMediaStream *self)
-{
- /* FIXME: we should fix this whole class up. It relies throughout on
- * self->priv->content actually secretly being a WockyJingleMediaRtp.
- */
- return WOCKY_JINGLE_MEDIA_RTP (self->priv->content);
-}
-
-void
-gabble_media_stream_start_telephony_event (GabbleMediaStream *self,
- guchar event)
-{
- DEBUG ("stream %s: %c", self->name, tp_dtmf_event_to_char (event));
-
- tp_svc_media_stream_handler_emit_start_telephony_event (
- (TpSvcMediaStreamHandler *) self, event);
-}
-
-void
-gabble_media_stream_stop_telephony_event (GabbleMediaStream *self)
-{
- DEBUG ("stream %s", self->name);
-
- tp_svc_media_stream_handler_emit_stop_telephony_event (
- (TpSvcMediaStreamHandler *) self);
-}
-
-void
-gabble_media_stream_add_dtmf_player (GabbleMediaStream *self,
- TpDTMFPlayer *dtmf_player)
-{
- tp_g_signal_connect_object (dtmf_player, "started-tone",
- G_CALLBACK (gabble_media_stream_start_telephony_event), self,
- G_CONNECT_SWAPPED);
- tp_g_signal_connect_object (dtmf_player, "stopped-tone",
- G_CALLBACK (gabble_media_stream_stop_telephony_event), self,
- G_CONNECT_SWAPPED);
-}