[Telepathy-commits] [telepathy-gabble/master] rename gabble-media-stream.c to media-stream.c
Dafydd Harries
dafydd.harries at collabora.co.uk
Tue Aug 19 10:53:18 PDT 2008
20080714115835-c9803-0a4791ee635a50c65a7370d74724441b91f78bcf.gz
---
src/Makefile.am | 2 +-
src/gabble-media-stream.c | 1843 ---------------------------------------------
src/media-stream.c | 1843 +++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 1844 insertions(+), 1844 deletions(-)
delete mode 100644 src/gabble-media-stream.c
create mode 100644 src/media-stream.c
diff --git a/src/Makefile.am b/src/Makefile.am
index 3a0ff48..33c9a25 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -62,7 +62,7 @@ libgabble_convenience_la_our_sources = \
media-session.h \
media-session.c \
media-stream.h \
- gabble-media-stream.c \
+ media-stream.c \
gabble-register.c \
register.h \
roster-channel.h \
diff --git a/src/gabble-media-stream.c b/src/gabble-media-stream.c
deleted file mode 100644
index 11353b1..0000000
--- a/src/gabble-media-stream.c
+++ /dev/null
@@ -1,1843 +0,0 @@
-/*
- * gabble-media-stream.c - Source for GabbleMediaStream
- * Copyright (C) 2006 Collabora Ltd.
- * Copyright (C) 2006 Nokia Corporation
- * @author Ole Andre Vadla Ravnaas <ole.andre.ravnaas at 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 "media-stream.h"
-
-#include <dbus/dbus-glib.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#define DEBUG_FLAG GABBLE_DEBUG_MEDIA
-
-#include <telepathy-glib/debug-ansi.h>
-#include "debug.h"
-#include "namespaces.h"
-
-#include "connection.h"
-#include "media-channel.h"
-#include "media-session.h"
-#include "gabble-media-session-enumtypes.h"
-
-#include <telepathy-glib/dbus.h>
-#include <telepathy-glib/enums.h>
-#include <telepathy-glib/errors.h>
-#include <telepathy-glib/svc-media-interfaces.h>
-
-#include "gabble-signals-marshal.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)
- )
-
-/* signal enum */
-enum
-{
- DESTROY,
-
- NEW_ACTIVE_CANDIDATE_PAIR,
- NEW_NATIVE_CANDIDATE,
- SUPPORTED_CODECS,
- ERROR,
- UNHOLD_FAILED,
-
- LAST_SIGNAL
-};
-
-static guint signals[LAST_SIGNAL] = {0};
-
-/* properties */
-enum
-{
- PROP_CONNECTION = 1,
- PROP_MEDIA_SESSION,
- PROP_OBJECT_PATH,
- PROP_MODE,
- PROP_NAME,
- PROP_ID,
- PROP_INITIATOR,
- PROP_MEDIA_TYPE,
- PROP_CONNECTION_STATE,
- PROP_READY,
- PROP_GOT_LOCAL_CODECS,
- PROP_SIGNALLING_STATE,
- PROP_PLAYING,
- PROP_COMBINED_DIRECTION,
- PROP_LOCAL_HOLD,
- LAST_PROPERTY
-};
-
-/* private structure */
-typedef struct _GabbleMediaStreamPrivate GabbleMediaStreamPrivate;
-
-struct _GabbleMediaStreamPrivate
-{
- GabbleConnection *conn;
- GabbleMediaSession *session;
- GabbleMediaSessionMode mode;
- gchar *object_path;
- guint id;
- guint media_type;
-
- gboolean ready;
- gboolean sending;
-
- GValue native_codecs; /* intersected codec list */
- GValue native_candidates;
-
- GValue remote_codecs;
- GValue remote_candidates;
-
- guint remote_candidate_count;
-
- gboolean closed:1;
- gboolean dispose_has_run:1;
- gboolean local_hold:1;
-};
-
-#define GABBLE_MEDIA_STREAM_GET_PRIVATE(obj) \
- ((GabbleMediaStreamPrivate *)obj->priv)
-
-#ifdef ENABLE_DEBUG
-#if _GMS_DEBUG_LEVEL > 1
-static const char *tp_protocols[] = {
- "TP_MEDIA_STREAM_BASE_PROTO_UDP (0)",
- "TP_MEDIA_STREAM_BASE_PROTO_TCP (1)"
-};
-
-static const char *tp_transports[] = {
- "TP_MEDIA_STREAM_TRANSPORT_TYPE_LOCAL (0)",
- "TP_MEDIA_STREAM_TRANSPORT_TYPE_DERIVED (1)",
- "TP_MEDIA_STREAM_TRANSPORT_TYPE_RELAY (2)"
-};
-#endif
-#endif
-
-static void push_native_candidates (GabbleMediaStream *stream);
-static void push_remote_codecs (GabbleMediaStream *stream);
-static void push_remote_candidates (GabbleMediaStream *stream);
-static void push_playing (GabbleMediaStream *stream);
-static void push_sending (GabbleMediaStream *stream);
-
-static void
-gabble_media_stream_init (GabbleMediaStream *self)
-{
- GabbleMediaStreamPrivate *priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
- GABBLE_TYPE_MEDIA_STREAM, GabbleMediaStreamPrivate);
-
- self->priv = priv;
-
- g_value_init (&priv->native_codecs, GABBLE_TP_TYPE_CODEC_LIST);
- g_value_take_boxed (&priv->native_codecs,
- dbus_g_type_specialized_construct (GABBLE_TP_TYPE_CODEC_LIST));
-
- g_value_init (&priv->native_candidates, GABBLE_TP_TYPE_CANDIDATE_LIST);
- g_value_take_boxed (&priv->native_candidates,
- dbus_g_type_specialized_construct (GABBLE_TP_TYPE_CANDIDATE_LIST));
-
- g_value_init (&priv->remote_codecs, GABBLE_TP_TYPE_CODEC_LIST);
- g_value_take_boxed (&priv->remote_codecs,
- dbus_g_type_specialized_construct (GABBLE_TP_TYPE_CODEC_LIST));
-
- g_value_init (&priv->remote_candidates, GABBLE_TP_TYPE_CANDIDATE_LIST);
- g_value_take_boxed (&priv->remote_candidates,
- dbus_g_type_specialized_construct (GABBLE_TP_TYPE_CANDIDATE_LIST));
-}
-
-static GObject *
-gabble_media_stream_constructor (GType type, guint n_props,
- GObjectConstructParam *props)
-{
- GObject *obj;
- GabbleMediaStreamPrivate *priv;
- DBusGConnection *bus;
-
- /* call base class constructor */
- obj = G_OBJECT_CLASS (gabble_media_stream_parent_class)->
- constructor (type, n_props, props);
- priv = GABBLE_MEDIA_STREAM_GET_PRIVATE (GABBLE_MEDIA_STREAM (obj));
-
- /* go for the bus */
- bus = tp_get_bus ();
- dbus_g_connection_register_g_object (bus, priv->object_path, obj);
-
- 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 = GABBLE_MEDIA_STREAM_GET_PRIVATE (stream);
-
- switch (property_id) {
- case PROP_CONNECTION:
- g_value_set_object (value, priv->conn);
- break;
- case PROP_MEDIA_SESSION:
- g_value_set_object (value, priv->session);
- break;
- case PROP_OBJECT_PATH:
- g_value_set_string (value, priv->object_path);
- break;
- case PROP_MODE:
- g_value_set_enum (value, priv->mode);
- 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_INITIATOR:
- g_value_set_uint (value, stream->initiator);
- 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_GOT_LOCAL_CODECS:
- g_value_set_boolean (value, stream->got_local_codecs);
- break;
- case PROP_SIGNALLING_STATE:
- g_value_set_uint (value, stream->signalling_state);
- 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;
- 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 = GABBLE_MEDIA_STREAM_GET_PRIVATE (stream);
-
- switch (property_id) {
- case PROP_CONNECTION:
- priv->conn = g_value_get_object (value);
- break;
- case PROP_MEDIA_SESSION:
- priv->session = g_value_get_object (value);
- break;
- case PROP_OBJECT_PATH:
- g_free (priv->object_path);
- priv->object_path = g_value_dup_string (value);
- break;
- case PROP_MODE:
- priv->mode = g_value_get_enum (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_INITIATOR:
- stream->initiator = g_value_get_uint (value);
- break;
- case PROP_MEDIA_TYPE:
- priv->media_type = g_value_get_uint (value);
- break;
- case PROP_CONNECTION_STATE:
- GMS_DEBUG_INFO (priv->session, "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_GOT_LOCAL_CODECS:
- stream->got_local_codecs = g_value_get_boolean (value);
- break;
- case PROP_SIGNALLING_STATE:
- {
- StreamSignallingState old = stream->signalling_state;
- stream->signalling_state = g_value_get_uint (value);
- GMS_DEBUG_INFO (priv->session, "stream %s sig_state %d->%d",
- stream->name, old, stream->signalling_state);
- if (stream->signalling_state != old)
- push_native_candidates (stream);
- }
- 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:
- stream->combined_direction = g_value_get_uint (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;
-
- 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 ("connection", "GabbleConnection object",
- "Gabble connection object that owns this "
- "media stream's channel.",
- GABBLE_TYPE_CONNECTION,
- G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_READWRITE |
- G_PARAM_STATIC_NICK |
- G_PARAM_STATIC_BLURB);
- g_object_class_install_property (object_class, PROP_CONNECTION, param_spec);
-
- param_spec = g_param_spec_object ("media-session",
- "GabbleMediaSession object",
- "Gabble media session object that owns this media stream object.",
- GABBLE_TYPE_MEDIA_SESSION,
- G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_NICK |
- G_PARAM_STATIC_BLURB);
- g_object_class_install_property (object_class, PROP_MEDIA_SESSION,
- 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_enum ("mode", "Signalling mode",
- "Which signalling mode used to control the "
- "stream.",
- gabble_media_session_mode_get_type (),
- MODE_JINGLE,
- G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_READWRITE |
- G_PARAM_STATIC_NAME |
- G_PARAM_STATIC_BLURB);
- g_object_class_install_property (object_class, PROP_MODE, 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 ("initiator", "Stream initiator",
- "An enum signifying which end initiated "
- "the stream.",
- INITIATOR_LOCAL,
- INITIATOR_REMOTE,
- INITIATOR_LOCAL,
- G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_READWRITE |
- G_PARAM_STATIC_NAME |
- G_PARAM_STATIC_BLURB);
- g_object_class_install_property (object_class, PROP_INITIATOR, 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_NAME |
- G_PARAM_STATIC_BLURB);
- 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 ("got-local-codecs", "Got local codecs?",
- "A boolean signifying whether we've got the locally supported codecs "
- "from the user.", FALSE,
- G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_NAME |
- G_PARAM_STATIC_BLURB);
- g_object_class_install_property (object_class, PROP_GOT_LOCAL_CODECS,
- param_spec);
-
- param_spec = g_param_spec_uint ("signalling-state", "Signalling state",
- "Whether the stream is newly created, "
- "sent to the peer, or acknowledged.",
- STREAM_SIG_STATE_NEW,
- STREAM_SIG_STATE_REMOVING,
- STREAM_SIG_STATE_NEW,
- G_PARAM_CONSTRUCT |
- G_PARAM_READWRITE |
- G_PARAM_STATIC_NAME |
- G_PARAM_STATIC_BLURB);
- g_object_class_install_property (object_class, PROP_SIGNALLING_STATE,
- 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_BIDIRECTIONAL,
- 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_READABLE |
- G_PARAM_STATIC_NAME | G_PARAM_STATIC_BLURB | G_PARAM_STATIC_NICK);
- g_object_class_install_property (object_class, PROP_LOCAL_HOLD, param_spec);
-
- /* signals not exported by D-Bus interface */
- signals[DESTROY] =
- g_signal_new ("destroy",
- 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);
-
- signals[NEW_ACTIVE_CANDIDATE_PAIR] =
- g_signal_new ("new-active-candidate-pair",
- G_OBJECT_CLASS_TYPE (gabble_media_stream_class),
- G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
- 0,
- NULL, NULL,
- gabble_marshal_VOID__STRING_STRING,
- G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_STRING);
-
- signals[NEW_NATIVE_CANDIDATE] =
- g_signal_new ("new-native-candidate",
- G_OBJECT_CLASS_TYPE (gabble_media_stream_class),
- G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
- 0,
- NULL, NULL,
- gabble_marshal_VOID__STRING_BOXED,
- G_TYPE_NONE, 2, G_TYPE_STRING, GABBLE_TP_TYPE_TRANSPORT_LIST);
-
- signals[SUPPORTED_CODECS] =
- g_signal_new ("supported-codecs",
- G_OBJECT_CLASS_TYPE (gabble_media_stream_class),
- G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
- 0,
- NULL, NULL,
- g_cclosure_marshal_VOID__BOXED,
- G_TYPE_NONE, 1, GABBLE_TP_TYPE_CODEC_LIST);
-
- 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);
-}
-
-void
-gabble_media_stream_dispose (GObject *object)
-{
- GabbleMediaStream *self = GABBLE_MEDIA_STREAM (object);
- GabbleMediaStreamPrivate *priv = GABBLE_MEDIA_STREAM_GET_PRIVATE (self);
-
- if (priv->dispose_has_run)
- return;
-
- _gabble_media_stream_close (self);
-
- g_signal_emit (self, signals[DESTROY], 0);
-
- priv->dispose_has_run = TRUE;
-
- 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 = GABBLE_MEDIA_STREAM_GET_PRIVATE (self);
-
- g_free (priv->object_path);
-
- g_value_unset (&priv->native_codecs);
- g_value_unset (&priv->native_candidates);
-
- g_value_unset (&priv->remote_codecs);
- 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)
-{
- GabbleMediaStream *self = GABBLE_MEDIA_STREAM (iface);
- GabbleMediaStreamPrivate *priv;
-
- g_assert (GABBLE_IS_MEDIA_STREAM (self));
-
- priv = GABBLE_MEDIA_STREAM_GET_PRIVATE (self);
-
- tp_svc_media_stream_handler_return_from_codec_choice (context);
-}
-
-
-gboolean
-gabble_media_stream_error (GabbleMediaStream *self,
- guint errno,
- const gchar *message,
- GError **error)
-{
- GabbleMediaStreamPrivate *priv;
-
- g_assert (GABBLE_IS_MEDIA_STREAM (self));
-
- priv = GABBLE_MEDIA_STREAM_GET_PRIVATE (self);
-
- GMS_DEBUG_WARNING (priv->session,
- "Media.StreamHandler::Error called, error %u (%s) -- emitting signal",
- errno, message);
-
- g_signal_emit (self, signals[ERROR], 0, errno, 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 errno,
- const gchar *message,
- DBusGMethodInvocation *context)
-{
- GabbleMediaStream *self = GABBLE_MEDIA_STREAM (iface);
- GError *error = NULL;
-
- if (gabble_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);
- }
-}
-
-
-/**
- * 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 = GABBLE_MEDIA_STREAM_GET_PRIVATE (self);
-
- 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 = GABBLE_MEDIA_STREAM_GET_PRIVATE (self);
-
- 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)
-{
- GabbleMediaStream *self = GABBLE_MEDIA_STREAM (iface);
- GabbleMediaStreamPrivate *priv;
-
- g_assert (GABBLE_IS_MEDIA_STREAM (self));
-
- priv = GABBLE_MEDIA_STREAM_GET_PRIVATE (self);
-
- 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)
-{
- GabbleMediaStream *self = GABBLE_MEDIA_STREAM (iface);
- GabbleMediaStreamPrivate *priv;
-
- g_assert (GABBLE_IS_MEDIA_STREAM (self));
-
- priv = GABBLE_MEDIA_STREAM_GET_PRIVATE (self);
-
- g_signal_emit (self, signals[NEW_ACTIVE_CANDIDATE_PAIR], 0,
- 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;
- JingleSessionState state;
- GPtrArray *candidates;
- GValue candidate = { 0, };
- GValueArray *transport;
- guint component_id;
- const gchar *addr;
-
- g_assert (GABBLE_IS_MEDIA_STREAM (self));
-
- priv = GABBLE_MEDIA_STREAM_GET_PRIVATE (self);
-
- g_object_get (priv->session, "state", &state, NULL);
-
- /* FIXME: maybe this should be an assertion in case the channel
- * isn't closed early enough right now? */
- if (state > JS_STATE_ACTIVE)
- {
- DEBUG ("state > JS_STATE_ACTIVE, doing nothing");
- tp_svc_media_stream_handler_return_from_new_native_candidate (context);
- return;
- }
-
- candidates = g_value_get_boxed (&priv->native_candidates);
-
- g_value_init (&candidate, GABBLE_TP_TYPE_CANDIDATE_STRUCT);
- g_value_take_boxed (&candidate,
- dbus_g_type_specialized_construct (GABBLE_TP_TYPE_CANDIDATE_STRUCT));
-
- dbus_g_type_struct_set (&candidate,
- 0, candidate_id,
- 1, transports,
- G_MAXUINT);
-
- if (transports->len != 1)
- {
- GError only_one = { TP_ERRORS, TP_ERROR_NOT_IMPLEMENTED, "google p2p "
- "connections only support the concept of one transport per "
- "candidate" };
- GMS_DEBUG_WARNING (priv->session, "%s: number of transports was not 1; "
- "rejecting", G_STRFUNC);
- dbus_g_method_return_error (context, &only_one);
- return;
- }
-
- transport = g_ptr_array_index (transports, 0);
- addr = g_value_get_string (g_value_array_get_nth (transport, 1));
- if (!strcmp (addr, "127.0.0.1"))
- {
- GMS_DEBUG_WARNING (priv->session,
- "%s: ignoring native localhost candidate", G_STRFUNC);
- tp_svc_media_stream_handler_return_from_new_native_candidate (context);
- return;
- }
-
- component_id = g_value_get_uint (g_value_array_get_nth (transport, 0));
- if (component_id != 1)
- {
- GMS_DEBUG_WARNING (priv->session,
- "%s: ignoring native candidate non-1 component", G_STRFUNC);
- tp_svc_media_stream_handler_return_from_new_native_candidate (context);
- return;
- }
-
- g_ptr_array_add (candidates, g_value_get_boxed (&candidate));
-
- GMS_DEBUG_INFO (priv->session,
- "put 1 native candidate from stream-engine into cache");
-
- push_native_candidates (self);
-
- g_signal_emit (self, signals[NEW_NATIVE_CANDIDATE], 0,
- candidate_id, transports);
-
- 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 = GABBLE_MEDIA_STREAM_GET_PRIVATE (self);
-
- GMS_DEBUG_INFO (priv->session, "ready called");
-
- g_object_set (self, "ready", TRUE, NULL);
-
- push_remote_codecs (self);
- push_remote_candidates (self);
- push_playing (self);
- push_sending (self);
-
- /* set_local_codecs and ready return the same thing, so we can do... */
- gabble_media_stream_set_local_codecs (iface, codecs, context);
-}
-
-
-/**
- * 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;
-
- g_assert (GABBLE_IS_MEDIA_STREAM (self));
-
- priv = GABBLE_MEDIA_STREAM_GET_PRIVATE (self);
-
- GMS_DEBUG_INFO (priv->session, "putting list of all %d locally supported "
- "codecs from stream-engine into cache", codecs->len);
-
- g_value_set_boxed (&priv->native_codecs, codecs);
-
- g_object_set (self, "got-local-codecs", TRUE, NULL);
-
- 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);
- g_assert (GABBLE_IS_MEDIA_STREAM (self));
-
- g_object_set (self, "connection-state", connection_state, NULL);
-
- 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;
-
- g_assert (GABBLE_IS_MEDIA_STREAM (self));
-
- priv = GABBLE_MEDIA_STREAM_GET_PRIVATE (self);
-
- GMS_DEBUG_INFO (priv->session, "got codec intersection containing %d "
- "codecs from stream-engine", codecs->len);
-
- /* store the intersection for later on */
- g_value_set_boxed (&priv->native_codecs, codecs);
-
- g_signal_emit (self, signals[SUPPORTED_CODECS], 0, codecs);
-
- tp_svc_media_stream_handler_return_from_supported_codecs (context);
-}
-
-static LmHandlerResult
-candidates_msg_reply_cb (GabbleConnection *conn,
- LmMessage *sent_msg,
- LmMessage *reply_msg,
- GObject *object,
- gpointer user_data)
-{
- GabbleMediaStream *stream = GABBLE_MEDIA_STREAM (object);
- GabbleMediaStreamPrivate *priv;
-
- g_assert (GABBLE_IS_MEDIA_STREAM (stream));
-
- priv = GABBLE_MEDIA_STREAM_GET_PRIVATE (stream);
-
- MSG_REPLY_CB_END_SESSION_IF_NOT_SUCCESSFUL (priv->session,
- "candidates failed");
-
- return LM_HANDLER_RESULT_REMOVE_MESSAGE;
-}
-
-static void
-_add_rtp_candidate_node (GabbleMediaSession *session, LmMessageNode *parent,
- GValueArray *candidate)
-{
- gchar *addr;
- gchar *user;
- gchar *pass;
- gchar *port_str;
- gchar *pref_str;
- gchar *xml;
- const gchar *type_str, *proto_str, *candidate_id;
- guint port;
- gdouble pref;
- TpMediaStreamBaseProto proto;
- TpMediaStreamTransportType type;
- const GPtrArray *transports;
- GValue transport = { 0, };
- LmMessageNode *cand_node;
-
- 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));
-
- /* jingle audio only supports the concept of one transport per candidate */
- g_assert (transports->len == 1);
-
- g_value_init (&transport, GABBLE_TP_TYPE_TRANSPORT_STRUCT);
- g_value_set_static_boxed (&transport, g_ptr_array_index (transports, 0));
-
- dbus_g_type_struct_get (&transport,
- 1, &addr,
- 2, &port,
- 3, &proto,
- 6, &pref,
- 7, &type,
- 8, &user,
- 9, &pass,
- G_MAXUINT);
-
- port_str = g_strdup_printf ("%d", port);
- pref_str = g_strdup_printf ("%f", pref);
-
- switch (type) {
- case TP_MEDIA_STREAM_TRANSPORT_TYPE_LOCAL:
- type_str = "local";
- break;
- case TP_MEDIA_STREAM_TRANSPORT_TYPE_DERIVED:
- type_str = "stun";
- break;
- case TP_MEDIA_STREAM_TRANSPORT_TYPE_RELAY:
- type_str = "relay";
- break;
- default:
- g_warning ("%s: TpMediaStreamTransportType has an invalid value, "
- "ignoring candidate", G_STRFUNC);
- goto out;
- }
-
- switch (proto)
- {
- case TP_MEDIA_STREAM_BASE_PROTO_UDP:
- proto_str = "udp";
- break;
- case TP_MEDIA_STREAM_BASE_PROTO_TCP:
- if (port == 443 && type == TP_MEDIA_STREAM_TRANSPORT_TYPE_RELAY)
- proto_str = "ssltcp";
- else
- proto_str = "tcp";
- break;
- default:
- g_warning ("%s: TpMediaStreamBaseProto has an invalid value, ignoring "
- "candidate", G_STRFUNC);
- goto out;
- }
-
- cand_node = lm_message_node_add_child (parent, "candidate", NULL);
- lm_message_node_set_attributes (cand_node,
- "name", "rtp",
- "address", addr,
- "port", port_str,
- "username", user,
- "password", pass,
- "preference", pref_str,
- "protocol", proto_str,
- "type", type_str,
- "network", "0",
- "generation", "0",
- NULL);
-
- xml = lm_message_node_to_string (cand_node);
- GMS_DEBUG_DUMP (session,
- " from Telepathy D-Bus struct: [%s\"%s\", %s[%s1, \"%s\", %d, %s, "
- "\"%s\", \"%s\", %f, %s, \"%s\", \"%s\"%s]]",
- TP_ANSI_BOLD_OFF, candidate_id, TP_ANSI_BOLD_ON, TP_ANSI_BOLD_OFF,
- addr, port, tp_protocols[proto], "RTP", "AVP", pref, tp_transports[type],
- user, pass, TP_ANSI_BOLD_ON);
- GMS_DEBUG_DUMP (session,
- " to Jingle XML: [%s%s%s]", TP_ANSI_BOLD_OFF, xml, TP_ANSI_BOLD_ON);
- g_free (xml);
-
-out:
- g_free (addr);
- g_free (user);
- g_free (pass);
- g_free (port_str);
- g_free (pref_str);
-}
-
-static LmMessage *
-_gabble_media_stream_message_new (GabbleMediaStream *stream,
- const gchar *action,
- LmMessageNode **content_node)
-{
- GabbleMediaStreamPrivate *priv = GABBLE_MEDIA_STREAM_GET_PRIVATE (stream);
- LmMessage *msg;
- LmMessageNode *session_node = NULL;
-
- /* construct a session message */
- msg = _gabble_media_session_message_new (priv->session, action,
- &session_node);
-
- /* add our content node to it if necessary */
- *content_node = _gabble_media_stream_add_content_node (stream, session_node);
-
- return msg;
-}
-
-
-static void
-push_candidate (GabbleMediaStream *stream, GValueArray *candidate)
-{
- GabbleMediaStreamPrivate *priv = GABBLE_MEDIA_STREAM_GET_PRIVATE (stream);
- LmMessage *msg;
- LmMessageNode *content_node, *transport_node;
- const gchar *action;
-
- if (priv->mode == MODE_GOOGLE)
- action = "candidates";
- else
- action = "transport-info";
-
- /* construct a base message */
- msg = _gabble_media_stream_message_new (stream, action, &content_node);
-
- /* for jingle, add a transport */
- transport_node = _gabble_media_stream_content_node_add_transport (stream,
- content_node);
-
- /* add transport info to it */
- _add_rtp_candidate_node (priv->session, transport_node, candidate);
-
- GMS_DEBUG_INFO (priv->session, "sending jingle session action \"%s\" to "
- "peer", action);
-
- /* send it */
- _gabble_connection_send_with_reply (priv->conn, msg, candidates_msg_reply_cb,
- G_OBJECT (stream), NULL, NULL);
-
- /* clean up */
- lm_message_unref (msg);
-}
-
-static void
-push_native_candidates (GabbleMediaStream *stream)
-{
- GabbleMediaStreamPrivate *priv;
- GPtrArray *candidates;
- guint i;
-
- g_assert (GABBLE_IS_MEDIA_STREAM (stream));
-
- priv = GABBLE_MEDIA_STREAM_GET_PRIVATE (stream);
-
- if (stream->signalling_state == STREAM_SIG_STATE_NEW ||
- stream->signalling_state == STREAM_SIG_STATE_REMOVING)
- return;
-
- candidates = g_value_get_boxed (&priv->native_candidates);
-
- for (i = 0; i < candidates->len; i++)
- push_candidate (stream, g_ptr_array_index (candidates, i));
-
- g_value_take_boxed (&priv->native_candidates,
- dbus_g_type_specialized_construct (GABBLE_TP_TYPE_CANDIDATE_LIST));
-}
-
-void
-_gabble_media_stream_close (GabbleMediaStream *stream)
-{
- GabbleMediaStreamPrivate *priv;
-
- g_assert (GABBLE_IS_MEDIA_STREAM (stream));
-
- priv = GABBLE_MEDIA_STREAM_GET_PRIVATE (stream);
-
- if (!priv->closed)
- {
- priv->closed = TRUE;
- tp_svc_media_stream_handler_emit_close (stream);
- }
-}
-
-gboolean
-_gabble_media_stream_post_remote_codecs (GabbleMediaStream *stream,
- LmMessage *message,
- LmMessageNode *desc_node,
- GError **error)
-{
- GabbleMediaStreamPrivate *priv;
- LmMessageNode *node;
- GPtrArray *codecs;
-
- g_assert (GABBLE_IS_MEDIA_STREAM (stream));
-
- priv = GABBLE_MEDIA_STREAM_GET_PRIVATE (stream);
-
- codecs = g_value_get_boxed (&priv->remote_codecs);
-
- g_assert (codecs->len == 0);
-
- for (node = desc_node->children; node; node = node->next)
- {
- guchar id;
- const gchar *name, *str;
- guint clockrate, channels;
- GHashTable *params;
- GValue codec = { 0, };
-
- if (tp_strdiff (node->name, "payload-type"))
- continue;
-
- /* id of codec */
- str = lm_message_node_get_attribute (node, "id");
- if (str == NULL)
- {
- g_set_error (error, GABBLE_XMPP_ERROR, XMPP_ERROR_BAD_REQUEST,
- "description has no ID");
- return FALSE;
- }
-
- id = atoi (str);
-
- /* codec name */
- name = lm_message_node_get_attribute (node, "name");
- if (name == NULL)
- {
- name = "";
- }
-
- /* clock rate: jingle and newer GTalk */
- str = lm_message_node_get_attribute (node, "clockrate"); /* google */
- if (str == NULL)
- str = lm_message_node_get_attribute (node, "rate"); /* jingle */
-
- if (str != NULL)
- {
- clockrate = atoi (str);
- }
- else
- {
- clockrate = 0;
- }
-
- /* number of channels: jingle only */
- str = lm_message_node_get_attribute (node, "channels");
- if (str != NULL)
- {
- channels = atoi (str);
- }
- else
- {
- channels = 1;
- }
-
- params = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_free);
-
- /* bitrate: newer GTalk only */
- str = lm_message_node_get_attribute (node, "bitrate");
- if (str != NULL)
- {
- g_hash_table_insert (params, "bitrate", g_strdup (str));
- }
-
- g_value_init (&codec, GABBLE_TP_TYPE_CODEC_STRUCT);
- g_value_take_boxed (&codec,
- dbus_g_type_specialized_construct (GABBLE_TP_TYPE_CODEC_STRUCT));
-
- dbus_g_type_struct_set (&codec,
- 0, id,
- 1, name,
- 2, priv->media_type,
- 3, clockrate,
- 4, channels,
- 5, params,
- G_MAXUINT);
-
- g_ptr_array_add (codecs, g_value_get_boxed (&codec));
- }
-
- GMS_DEBUG_INFO (priv->session, "put %d remote codecs from peer into cache",
- codecs->len);
-
- push_remote_codecs (stream);
-
- return TRUE;
-}
-
-static void
-push_remote_codecs (GabbleMediaStream *stream)
-{
- GabbleMediaStreamPrivate *priv;
- GPtrArray *codecs;
-
- g_assert (GABBLE_IS_MEDIA_STREAM (stream));
-
- priv = GABBLE_MEDIA_STREAM_GET_PRIVATE (stream);
-
- if (!priv->ready)
- return;
-
- codecs = g_value_get_boxed (&priv->remote_codecs);
- if (codecs->len == 0)
- return;
-
- GMS_DEBUG_EVENT (priv->session, "passing %d remote codecs to stream-engine",
- codecs->len);
-
- tp_svc_media_stream_handler_emit_set_remote_codecs (stream, codecs);
-
- g_value_take_boxed (&priv->remote_codecs,
- dbus_g_type_specialized_construct (GABBLE_TP_TYPE_CODEC_LIST));
-}
-
-gboolean
-_gabble_media_stream_post_remote_candidates (GabbleMediaStream *stream,
- LmMessage *message,
- LmMessageNode *transport_node,
- GError **error)
-{
- GabbleMediaStreamPrivate *priv;
- LmMessageNode *node;
- const gchar *str;
- GPtrArray *candidates;
-
- g_assert (GABBLE_IS_MEDIA_STREAM (stream));
-
- priv = GABBLE_MEDIA_STREAM_GET_PRIVATE (stream);
-
- candidates = g_value_get_boxed (&priv->remote_candidates);
-
- for (node = transport_node->children; node; node = node->next)
- {
- gchar *candidate_id;
- const gchar *name, *addr;
- guint16 port;
- TpMediaStreamBaseProto proto;
- gdouble pref;
- TpMediaStreamTransportType type;
- const gchar *user, *pass;
- guchar net, gen;
- GValue candidate = { 0, };
- GPtrArray *transports;
- GValue transport = { 0, };
- gchar *xml;
-
- if (tp_strdiff (node->name, "candidate"))
- continue;
-
- /*
- * Candidate
- */
-
- /* stream name */
- name = lm_message_node_get_attribute (node, "name");
- if (name == NULL || strcmp (name, "rtp") != 0)
- goto FAILURE;
-
-
- /*
- * Transport
- */
-
- /* ip address */
- addr = lm_message_node_get_attribute (node, "address");
- if (addr == NULL)
- goto FAILURE;
-
- /* port */
- str = lm_message_node_get_attribute (node, "port");
- if (str == NULL)
- goto FAILURE;
- port = atoi (str);
-
- /* protocol */
- str = lm_message_node_get_attribute (node, "protocol");
- if (str == NULL)
- goto FAILURE;
-
- if (strcmp (str, "udp") == 0)
- {
- proto = TP_MEDIA_STREAM_BASE_PROTO_UDP;
- }
- else if (strcmp (str, "tcp") == 0)
- {
- if (port == 443)
- {
- GMS_DEBUG_WARNING (priv->session, "%s: tcp candidates on port "
- "443 must be ssltcp, ignoring candidate", G_STRFUNC);
- continue;
- }
-
- proto = TP_MEDIA_STREAM_BASE_PROTO_TCP;
- }
- else if (strcmp (str, "ssltcp") == 0)
- {
- if (port != 443)
- {
- GMS_DEBUG_WARNING (priv->session, "%s: ssltcp candidates must "
- "be on port 443, ignoring candidate", G_STRFUNC);
- continue;
- }
-
- proto = TP_MEDIA_STREAM_BASE_PROTO_TCP;
- }
- else
- goto FAILURE;
-
- /* protocol profile: hardcoded to "AVP" for now */
-
- /* preference */
- str = lm_message_node_get_attribute (node, "preference");
- if (str == NULL)
- goto FAILURE;
- pref = g_ascii_strtod (str, NULL);
-
- /* type */
- str = lm_message_node_get_attribute (node, "type");
- if (str == NULL)
- goto FAILURE;
-
- if (strcmp (str, "local") == 0)
- {
- type = TP_MEDIA_STREAM_TRANSPORT_TYPE_LOCAL;
- }
- else if (strcmp (str, "stun") == 0)
- {
- type = TP_MEDIA_STREAM_TRANSPORT_TYPE_DERIVED;
- }
- else if (strcmp (str, "relay") == 0)
- {
- type = TP_MEDIA_STREAM_TRANSPORT_TYPE_RELAY;
- }
- else
- goto FAILURE;
-
- /* username */
- user = lm_message_node_get_attribute (node, "username");
- if (user == NULL)
- goto FAILURE;
-
- /* password */
- pass = lm_message_node_get_attribute (node, "password");
- if (pass == NULL)
- goto FAILURE;
-
- /* unknown */
- str = lm_message_node_get_attribute (node, "network");
- if (str == NULL)
- goto FAILURE;
- net = atoi (str);
-
- /* unknown */
- str = lm_message_node_get_attribute (node, "generation");
- if (str == NULL)
- goto FAILURE;
- gen = atoi (str);
-
-
- g_value_init (&transport, GABBLE_TP_TYPE_TRANSPORT_STRUCT);
- g_value_take_boxed (&transport,
- dbus_g_type_specialized_construct (GABBLE_TP_TYPE_TRANSPORT_STRUCT));
-
- dbus_g_type_struct_set (&transport,
- 0, 1, /* component number */
- 1, addr,
- 2, port,
- 3, proto,
- 4, "RTP",
- 5, "AVP",
- 6, pref,
- 7, type,
- 8, user,
- 9, pass,
- G_MAXUINT);
-
- transports = g_ptr_array_sized_new (1);
- g_ptr_array_add (transports, g_value_get_boxed (&transport));
-
-
- g_value_init (&candidate, GABBLE_TP_TYPE_CANDIDATE_STRUCT);
- g_value_take_boxed (&candidate,
- dbus_g_type_specialized_construct (GABBLE_TP_TYPE_CANDIDATE_STRUCT));
-
- /* FIXME: is this naming scheme sensible? */
- candidate_id = g_strdup_printf ("R%d", ++priv->remote_candidate_count);
-
- dbus_g_type_struct_set (&candidate,
- 0, candidate_id,
- 1, transports,
- G_MAXUINT);
-
- g_ptr_array_add (candidates, g_value_get_boxed (&candidate));
-
- xml = lm_message_node_to_string (node);
- GMS_DEBUG_INFO (priv->session,
- "put 1 remote candidate from peer into cache");
- GMS_DEBUG_DUMP (priv->session, " from Jingle XML: [%s%s%s]",
- TP_ANSI_BOLD_OFF, xml, TP_ANSI_BOLD_ON);
- GMS_DEBUG_DUMP (priv->session,
- " to Telepathy D-Bus struct: [%s\"%s\", %s[%s1, \"%s\", %d, %s, "
- "\"%s\", \"%s\", %f, %s, \"%s\", \"%s\"%s]]",
- TP_ANSI_BOLD_OFF, candidate_id, TP_ANSI_BOLD_ON,
- TP_ANSI_BOLD_OFF, addr, port, tp_protocols[proto],
- "RTP", "AVP", pref, tp_transports[type],
- user, pass, TP_ANSI_BOLD_ON);
- g_free (xml);
-
- g_free (candidate_id);
- }
-
-/*SUCCESS:*/
- push_remote_candidates (stream);
-
- return TRUE;
-
-FAILURE:
- g_set_error (error, GABBLE_XMPP_ERROR, XMPP_ERROR_BAD_REQUEST,
- "unable to parse candidate");
-
- return FALSE;
-}
-
-static void
-push_remote_candidates (GabbleMediaStream *stream)
-{
- GabbleMediaStreamPrivate *priv;
- GPtrArray *candidates;
- guint i;
-
- g_assert (GABBLE_IS_MEDIA_STREAM (stream));
-
- priv = GABBLE_MEDIA_STREAM_GET_PRIVATE (stream);
-
- 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));
-
- GMS_DEBUG_EVENT (priv->session, "passing 1 remote candidate "
- "to stream-engine");
-
- 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 (GABBLE_TP_TYPE_CANDIDATE_LIST));
-}
-
-static void
-push_playing (GabbleMediaStream *stream)
-{
- GabbleMediaStreamPrivate *priv;
-
- g_assert (GABBLE_IS_MEDIA_STREAM (stream));
-
- priv = GABBLE_MEDIA_STREAM_GET_PRIVATE (stream);
-
- if (!priv->ready)
- return;
-
- GMS_DEBUG_INFO (priv->session, "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;
-
- g_assert (GABBLE_IS_MEDIA_STREAM (stream));
-
- priv = GABBLE_MEDIA_STREAM_GET_PRIVATE (stream);
-
- if (!priv->ready)
- return;
-
- GMS_DEBUG_INFO (priv->session, "stream %s emitting SetStreamSending(%s)",
- stream->name, priv->sending ? "true" : "false");
-
- tp_svc_media_stream_handler_emit_set_stream_sending (
- stream, priv->sending);
-}
-
-/*
- * oh sweet g_hash_table_foreach how beautiful thou be'st
- *
- * _\ / ^/
- * \/ \// 7_ __
- * ( 7 ) (__) (__)
- * ^\\ |/__/___/
- * \\/_/ | <-- TP-cable kindly provided by Mika N.
- * \ / O
- * || /|\
- * || / \
- * ||
- * ____||_____________
- */
-
-typedef struct {
- GabbleMediaStreamPrivate *priv;
- LmMessageNode *pt_node;
-} CodecParamsFromTpContext;
-
-static const gchar *video_codec_params[] = {
- "x", "y", "width", "height", "layer", "transparent",
-};
-
-static void
-codec_params_from_tp_foreach (gpointer key, gpointer value, gpointer user_data)
-{
- CodecParamsFromTpContext *ctx = user_data;
- GabbleMediaStreamPrivate *priv = ctx->priv;
- const gchar *pname = key, *pvalue = value;
-
- if (priv->media_type == TP_MEDIA_STREAM_TYPE_AUDIO)
- {
- if (priv->mode == MODE_GOOGLE && strcmp (pname, "bitrate") == 0)
- {
- lm_message_node_set_attribute (ctx->pt_node, pname, pvalue);
- return;
- }
- }
- else if (priv->mode == MODE_JINGLE)
- {
- gint i;
-
- for (i = 0; video_codec_params[i] != NULL; i++)
- {
- if (strcmp (pname, video_codec_params[i]) == 0)
- {
- lm_message_node_set_attribute (ctx->pt_node, pname, pvalue);
- return;
- }
- }
- }
-
- DEBUG ("ignoring %s=%s for %s %s stream", pname, pvalue,
- (priv->mode == MODE_JINGLE) ? "jingle" : "google",
- (priv->media_type == TP_MEDIA_STREAM_TYPE_AUDIO) ? "audio" : "video");
-}
-
-LmMessageNode *
-_gabble_media_stream_add_content_node (GabbleMediaStream *stream,
- LmMessageNode *session_node)
-{
- GabbleMediaStreamPrivate *priv = GABBLE_MEDIA_STREAM_GET_PRIVATE (stream);
- LmMessageNode *node = session_node;
-
- /* add our content node to it if in jingle mode */
- if (priv->mode == MODE_JINGLE)
- {
- node = lm_message_node_add_child (session_node, "content", NULL);
- lm_message_node_set_attribute (node, "name", stream->name);
-
- if (priv->session->initiator == stream->initiator)
- lm_message_node_set_attribute (node, "creator", "initiator");
- else
- lm_message_node_set_attribute (node, "creator", "responder");
- }
-
- return node;
-}
-
-void
-_gabble_media_stream_content_node_add_description (GabbleMediaStream *stream,
- LmMessageNode *content_node)
-{
- GabbleMediaStreamPrivate *priv;
- const GPtrArray *codecs;
- LmMessageNode *desc_node;
- guint i;
- const gchar *xmlns;
-
- g_assert (GABBLE_IS_MEDIA_STREAM (stream));
-
- priv = GABBLE_MEDIA_STREAM_GET_PRIVATE (stream);
-
- codecs = g_value_get_boxed (&priv->native_codecs);
-
- desc_node = lm_message_node_add_child (content_node, "description", NULL);
-
- if (priv->mode == MODE_GOOGLE)
- xmlns = NS_GOOGLE_SESSION_PHONE;
- else if (priv->media_type == TP_MEDIA_STREAM_TYPE_VIDEO)
- xmlns = NS_JINGLE_DESCRIPTION_VIDEO;
- else
- xmlns = NS_JINGLE_DESCRIPTION_AUDIO;
-
- lm_message_node_set_attribute (desc_node, "xmlns", xmlns);
-
- for (i = 0; i < codecs->len; i++)
- {
- GValue codec = { 0, };
- guint id, clock_rate, channels;
- gchar *name, buf[16];
- GHashTable *params;
- LmMessageNode *pt_node;
- CodecParamsFromTpContext ctx;
-
- g_value_init (&codec, GABBLE_TP_TYPE_CODEC_STRUCT);
- 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);
-
- /* create a sub-node called "payload-type" and fill it */
- pt_node = lm_message_node_add_child (desc_node, "payload-type", NULL);
-
- /* id: required */
- sprintf (buf, "%u", id);
- lm_message_node_set_attribute (pt_node, "id", buf);
-
- /* name: optional */
- if (*name != '\0')
- {
- lm_message_node_set_attribute (pt_node, "name", name);
- }
-
- /* clock rate: optional */
- if (clock_rate != 0)
- {
- sprintf (buf, "%u", clock_rate);
- lm_message_node_set_attribute (pt_node,
- (priv->mode == MODE_GOOGLE) ? "clockrate" : "rate", buf);
- }
-
- /* number of channels: optional, jingle only */
- /* FIXME: is it? */
- if (channels != 0 && priv->mode == MODE_JINGLE)
- {
- sprintf (buf, "%u", channels);
- lm_message_node_set_attribute (pt_node, "channels", buf);
- }
-
- /* parse the optional params */
- ctx.priv = priv;
- ctx.pt_node = pt_node;
- g_hash_table_foreach (params, codec_params_from_tp_foreach, &ctx);
-
- /* clean up */
- g_free (name);
- g_hash_table_destroy (params);
- }
-}
-
-LmMessageNode *
-_gabble_media_stream_content_node_add_transport (GabbleMediaStream *stream,
- LmMessageNode *content_node)
-{
- GabbleMediaStreamPrivate *priv;
- LmMessageNode *node;
-
- g_assert (GABBLE_IS_MEDIA_STREAM (stream));
-
- priv = GABBLE_MEDIA_STREAM_GET_PRIVATE (stream);
-
- if (priv->mode != MODE_JINGLE)
- return content_node;
-
- node = lm_message_node_add_child (content_node, "transport", NULL);
-
- lm_message_node_set_attribute (node, "xmlns", NS_GOOGLE_TRANSPORT_P2P);
-
- return node;
-}
-
-void
-_gabble_media_stream_update_sending (GabbleMediaStream *stream,
- gboolean start_sending)
-{
- GabbleMediaStreamPrivate *priv;
- gboolean new_sending;
-
- g_assert (GABBLE_IS_MEDIA_STREAM (stream));
-
- priv = GABBLE_MEDIA_STREAM_GET_PRIVATE (stream);
-
- 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,);
-#undef IMPLEMENT
-}
diff --git a/src/media-stream.c b/src/media-stream.c
new file mode 100644
index 0000000..11353b1
--- /dev/null
+++ b/src/media-stream.c
@@ -0,0 +1,1843 @@
+/*
+ * gabble-media-stream.c - Source for GabbleMediaStream
+ * Copyright (C) 2006 Collabora Ltd.
+ * Copyright (C) 2006 Nokia Corporation
+ * @author Ole Andre Vadla Ravnaas <ole.andre.ravnaas at 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 "media-stream.h"
+
+#include <dbus/dbus-glib.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define DEBUG_FLAG GABBLE_DEBUG_MEDIA
+
+#include <telepathy-glib/debug-ansi.h>
+#include "debug.h"
+#include "namespaces.h"
+
+#include "connection.h"
+#include "media-channel.h"
+#include "media-session.h"
+#include "gabble-media-session-enumtypes.h"
+
+#include <telepathy-glib/dbus.h>
+#include <telepathy-glib/enums.h>
+#include <telepathy-glib/errors.h>
+#include <telepathy-glib/svc-media-interfaces.h>
+
+#include "gabble-signals-marshal.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)
+ )
+
+/* signal enum */
+enum
+{
+ DESTROY,
+
+ NEW_ACTIVE_CANDIDATE_PAIR,
+ NEW_NATIVE_CANDIDATE,
+ SUPPORTED_CODECS,
+ ERROR,
+ UNHOLD_FAILED,
+
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = {0};
+
+/* properties */
+enum
+{
+ PROP_CONNECTION = 1,
+ PROP_MEDIA_SESSION,
+ PROP_OBJECT_PATH,
+ PROP_MODE,
+ PROP_NAME,
+ PROP_ID,
+ PROP_INITIATOR,
+ PROP_MEDIA_TYPE,
+ PROP_CONNECTION_STATE,
+ PROP_READY,
+ PROP_GOT_LOCAL_CODECS,
+ PROP_SIGNALLING_STATE,
+ PROP_PLAYING,
+ PROP_COMBINED_DIRECTION,
+ PROP_LOCAL_HOLD,
+ LAST_PROPERTY
+};
+
+/* private structure */
+typedef struct _GabbleMediaStreamPrivate GabbleMediaStreamPrivate;
+
+struct _GabbleMediaStreamPrivate
+{
+ GabbleConnection *conn;
+ GabbleMediaSession *session;
+ GabbleMediaSessionMode mode;
+ gchar *object_path;
+ guint id;
+ guint media_type;
+
+ gboolean ready;
+ gboolean sending;
+
+ GValue native_codecs; /* intersected codec list */
+ GValue native_candidates;
+
+ GValue remote_codecs;
+ GValue remote_candidates;
+
+ guint remote_candidate_count;
+
+ gboolean closed:1;
+ gboolean dispose_has_run:1;
+ gboolean local_hold:1;
+};
+
+#define GABBLE_MEDIA_STREAM_GET_PRIVATE(obj) \
+ ((GabbleMediaStreamPrivate *)obj->priv)
+
+#ifdef ENABLE_DEBUG
+#if _GMS_DEBUG_LEVEL > 1
+static const char *tp_protocols[] = {
+ "TP_MEDIA_STREAM_BASE_PROTO_UDP (0)",
+ "TP_MEDIA_STREAM_BASE_PROTO_TCP (1)"
+};
+
+static const char *tp_transports[] = {
+ "TP_MEDIA_STREAM_TRANSPORT_TYPE_LOCAL (0)",
+ "TP_MEDIA_STREAM_TRANSPORT_TYPE_DERIVED (1)",
+ "TP_MEDIA_STREAM_TRANSPORT_TYPE_RELAY (2)"
+};
+#endif
+#endif
+
+static void push_native_candidates (GabbleMediaStream *stream);
+static void push_remote_codecs (GabbleMediaStream *stream);
+static void push_remote_candidates (GabbleMediaStream *stream);
+static void push_playing (GabbleMediaStream *stream);
+static void push_sending (GabbleMediaStream *stream);
+
+static void
+gabble_media_stream_init (GabbleMediaStream *self)
+{
+ GabbleMediaStreamPrivate *priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
+ GABBLE_TYPE_MEDIA_STREAM, GabbleMediaStreamPrivate);
+
+ self->priv = priv;
+
+ g_value_init (&priv->native_codecs, GABBLE_TP_TYPE_CODEC_LIST);
+ g_value_take_boxed (&priv->native_codecs,
+ dbus_g_type_specialized_construct (GABBLE_TP_TYPE_CODEC_LIST));
+
+ g_value_init (&priv->native_candidates, GABBLE_TP_TYPE_CANDIDATE_LIST);
+ g_value_take_boxed (&priv->native_candidates,
+ dbus_g_type_specialized_construct (GABBLE_TP_TYPE_CANDIDATE_LIST));
+
+ g_value_init (&priv->remote_codecs, GABBLE_TP_TYPE_CODEC_LIST);
+ g_value_take_boxed (&priv->remote_codecs,
+ dbus_g_type_specialized_construct (GABBLE_TP_TYPE_CODEC_LIST));
+
+ g_value_init (&priv->remote_candidates, GABBLE_TP_TYPE_CANDIDATE_LIST);
+ g_value_take_boxed (&priv->remote_candidates,
+ dbus_g_type_specialized_construct (GABBLE_TP_TYPE_CANDIDATE_LIST));
+}
+
+static GObject *
+gabble_media_stream_constructor (GType type, guint n_props,
+ GObjectConstructParam *props)
+{
+ GObject *obj;
+ GabbleMediaStreamPrivate *priv;
+ DBusGConnection *bus;
+
+ /* call base class constructor */
+ obj = G_OBJECT_CLASS (gabble_media_stream_parent_class)->
+ constructor (type, n_props, props);
+ priv = GABBLE_MEDIA_STREAM_GET_PRIVATE (GABBLE_MEDIA_STREAM (obj));
+
+ /* go for the bus */
+ bus = tp_get_bus ();
+ dbus_g_connection_register_g_object (bus, priv->object_path, obj);
+
+ 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 = GABBLE_MEDIA_STREAM_GET_PRIVATE (stream);
+
+ switch (property_id) {
+ case PROP_CONNECTION:
+ g_value_set_object (value, priv->conn);
+ break;
+ case PROP_MEDIA_SESSION:
+ g_value_set_object (value, priv->session);
+ break;
+ case PROP_OBJECT_PATH:
+ g_value_set_string (value, priv->object_path);
+ break;
+ case PROP_MODE:
+ g_value_set_enum (value, priv->mode);
+ 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_INITIATOR:
+ g_value_set_uint (value, stream->initiator);
+ 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_GOT_LOCAL_CODECS:
+ g_value_set_boolean (value, stream->got_local_codecs);
+ break;
+ case PROP_SIGNALLING_STATE:
+ g_value_set_uint (value, stream->signalling_state);
+ 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;
+ 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 = GABBLE_MEDIA_STREAM_GET_PRIVATE (stream);
+
+ switch (property_id) {
+ case PROP_CONNECTION:
+ priv->conn = g_value_get_object (value);
+ break;
+ case PROP_MEDIA_SESSION:
+ priv->session = g_value_get_object (value);
+ break;
+ case PROP_OBJECT_PATH:
+ g_free (priv->object_path);
+ priv->object_path = g_value_dup_string (value);
+ break;
+ case PROP_MODE:
+ priv->mode = g_value_get_enum (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_INITIATOR:
+ stream->initiator = g_value_get_uint (value);
+ break;
+ case PROP_MEDIA_TYPE:
+ priv->media_type = g_value_get_uint (value);
+ break;
+ case PROP_CONNECTION_STATE:
+ GMS_DEBUG_INFO (priv->session, "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_GOT_LOCAL_CODECS:
+ stream->got_local_codecs = g_value_get_boolean (value);
+ break;
+ case PROP_SIGNALLING_STATE:
+ {
+ StreamSignallingState old = stream->signalling_state;
+ stream->signalling_state = g_value_get_uint (value);
+ GMS_DEBUG_INFO (priv->session, "stream %s sig_state %d->%d",
+ stream->name, old, stream->signalling_state);
+ if (stream->signalling_state != old)
+ push_native_candidates (stream);
+ }
+ 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:
+ stream->combined_direction = g_value_get_uint (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;
+
+ 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 ("connection", "GabbleConnection object",
+ "Gabble connection object that owns this "
+ "media stream's channel.",
+ GABBLE_TYPE_CONNECTION,
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_NICK |
+ G_PARAM_STATIC_BLURB);
+ g_object_class_install_property (object_class, PROP_CONNECTION, param_spec);
+
+ param_spec = g_param_spec_object ("media-session",
+ "GabbleMediaSession object",
+ "Gabble media session object that owns this media stream object.",
+ GABBLE_TYPE_MEDIA_SESSION,
+ G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_NICK |
+ G_PARAM_STATIC_BLURB);
+ g_object_class_install_property (object_class, PROP_MEDIA_SESSION,
+ 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_enum ("mode", "Signalling mode",
+ "Which signalling mode used to control the "
+ "stream.",
+ gabble_media_session_mode_get_type (),
+ MODE_JINGLE,
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_NAME |
+ G_PARAM_STATIC_BLURB);
+ g_object_class_install_property (object_class, PROP_MODE, 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 ("initiator", "Stream initiator",
+ "An enum signifying which end initiated "
+ "the stream.",
+ INITIATOR_LOCAL,
+ INITIATOR_REMOTE,
+ INITIATOR_LOCAL,
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_NAME |
+ G_PARAM_STATIC_BLURB);
+ g_object_class_install_property (object_class, PROP_INITIATOR, 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_NAME |
+ G_PARAM_STATIC_BLURB);
+ 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 ("got-local-codecs", "Got local codecs?",
+ "A boolean signifying whether we've got the locally supported codecs "
+ "from the user.", FALSE,
+ G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_NAME |
+ G_PARAM_STATIC_BLURB);
+ g_object_class_install_property (object_class, PROP_GOT_LOCAL_CODECS,
+ param_spec);
+
+ param_spec = g_param_spec_uint ("signalling-state", "Signalling state",
+ "Whether the stream is newly created, "
+ "sent to the peer, or acknowledged.",
+ STREAM_SIG_STATE_NEW,
+ STREAM_SIG_STATE_REMOVING,
+ STREAM_SIG_STATE_NEW,
+ G_PARAM_CONSTRUCT |
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_NAME |
+ G_PARAM_STATIC_BLURB);
+ g_object_class_install_property (object_class, PROP_SIGNALLING_STATE,
+ 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_BIDIRECTIONAL,
+ 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_READABLE |
+ G_PARAM_STATIC_NAME | G_PARAM_STATIC_BLURB | G_PARAM_STATIC_NICK);
+ g_object_class_install_property (object_class, PROP_LOCAL_HOLD, param_spec);
+
+ /* signals not exported by D-Bus interface */
+ signals[DESTROY] =
+ g_signal_new ("destroy",
+ 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);
+
+ signals[NEW_ACTIVE_CANDIDATE_PAIR] =
+ g_signal_new ("new-active-candidate-pair",
+ G_OBJECT_CLASS_TYPE (gabble_media_stream_class),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
+ 0,
+ NULL, NULL,
+ gabble_marshal_VOID__STRING_STRING,
+ G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_STRING);
+
+ signals[NEW_NATIVE_CANDIDATE] =
+ g_signal_new ("new-native-candidate",
+ G_OBJECT_CLASS_TYPE (gabble_media_stream_class),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
+ 0,
+ NULL, NULL,
+ gabble_marshal_VOID__STRING_BOXED,
+ G_TYPE_NONE, 2, G_TYPE_STRING, GABBLE_TP_TYPE_TRANSPORT_LIST);
+
+ signals[SUPPORTED_CODECS] =
+ g_signal_new ("supported-codecs",
+ G_OBJECT_CLASS_TYPE (gabble_media_stream_class),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
+ 0,
+ NULL, NULL,
+ g_cclosure_marshal_VOID__BOXED,
+ G_TYPE_NONE, 1, GABBLE_TP_TYPE_CODEC_LIST);
+
+ 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);
+}
+
+void
+gabble_media_stream_dispose (GObject *object)
+{
+ GabbleMediaStream *self = GABBLE_MEDIA_STREAM (object);
+ GabbleMediaStreamPrivate *priv = GABBLE_MEDIA_STREAM_GET_PRIVATE (self);
+
+ if (priv->dispose_has_run)
+ return;
+
+ _gabble_media_stream_close (self);
+
+ g_signal_emit (self, signals[DESTROY], 0);
+
+ priv->dispose_has_run = TRUE;
+
+ 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 = GABBLE_MEDIA_STREAM_GET_PRIVATE (self);
+
+ g_free (priv->object_path);
+
+ g_value_unset (&priv->native_codecs);
+ g_value_unset (&priv->native_candidates);
+
+ g_value_unset (&priv->remote_codecs);
+ 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)
+{
+ GabbleMediaStream *self = GABBLE_MEDIA_STREAM (iface);
+ GabbleMediaStreamPrivate *priv;
+
+ g_assert (GABBLE_IS_MEDIA_STREAM (self));
+
+ priv = GABBLE_MEDIA_STREAM_GET_PRIVATE (self);
+
+ tp_svc_media_stream_handler_return_from_codec_choice (context);
+}
+
+
+gboolean
+gabble_media_stream_error (GabbleMediaStream *self,
+ guint errno,
+ const gchar *message,
+ GError **error)
+{
+ GabbleMediaStreamPrivate *priv;
+
+ g_assert (GABBLE_IS_MEDIA_STREAM (self));
+
+ priv = GABBLE_MEDIA_STREAM_GET_PRIVATE (self);
+
+ GMS_DEBUG_WARNING (priv->session,
+ "Media.StreamHandler::Error called, error %u (%s) -- emitting signal",
+ errno, message);
+
+ g_signal_emit (self, signals[ERROR], 0, errno, 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 errno,
+ const gchar *message,
+ DBusGMethodInvocation *context)
+{
+ GabbleMediaStream *self = GABBLE_MEDIA_STREAM (iface);
+ GError *error = NULL;
+
+ if (gabble_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);
+ }
+}
+
+
+/**
+ * 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 = GABBLE_MEDIA_STREAM_GET_PRIVATE (self);
+
+ 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 = GABBLE_MEDIA_STREAM_GET_PRIVATE (self);
+
+ 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)
+{
+ GabbleMediaStream *self = GABBLE_MEDIA_STREAM (iface);
+ GabbleMediaStreamPrivate *priv;
+
+ g_assert (GABBLE_IS_MEDIA_STREAM (self));
+
+ priv = GABBLE_MEDIA_STREAM_GET_PRIVATE (self);
+
+ 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)
+{
+ GabbleMediaStream *self = GABBLE_MEDIA_STREAM (iface);
+ GabbleMediaStreamPrivate *priv;
+
+ g_assert (GABBLE_IS_MEDIA_STREAM (self));
+
+ priv = GABBLE_MEDIA_STREAM_GET_PRIVATE (self);
+
+ g_signal_emit (self, signals[NEW_ACTIVE_CANDIDATE_PAIR], 0,
+ 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;
+ JingleSessionState state;
+ GPtrArray *candidates;
+ GValue candidate = { 0, };
+ GValueArray *transport;
+ guint component_id;
+ const gchar *addr;
+
+ g_assert (GABBLE_IS_MEDIA_STREAM (self));
+
+ priv = GABBLE_MEDIA_STREAM_GET_PRIVATE (self);
+
+ g_object_get (priv->session, "state", &state, NULL);
+
+ /* FIXME: maybe this should be an assertion in case the channel
+ * isn't closed early enough right now? */
+ if (state > JS_STATE_ACTIVE)
+ {
+ DEBUG ("state > JS_STATE_ACTIVE, doing nothing");
+ tp_svc_media_stream_handler_return_from_new_native_candidate (context);
+ return;
+ }
+
+ candidates = g_value_get_boxed (&priv->native_candidates);
+
+ g_value_init (&candidate, GABBLE_TP_TYPE_CANDIDATE_STRUCT);
+ g_value_take_boxed (&candidate,
+ dbus_g_type_specialized_construct (GABBLE_TP_TYPE_CANDIDATE_STRUCT));
+
+ dbus_g_type_struct_set (&candidate,
+ 0, candidate_id,
+ 1, transports,
+ G_MAXUINT);
+
+ if (transports->len != 1)
+ {
+ GError only_one = { TP_ERRORS, TP_ERROR_NOT_IMPLEMENTED, "google p2p "
+ "connections only support the concept of one transport per "
+ "candidate" };
+ GMS_DEBUG_WARNING (priv->session, "%s: number of transports was not 1; "
+ "rejecting", G_STRFUNC);
+ dbus_g_method_return_error (context, &only_one);
+ return;
+ }
+
+ transport = g_ptr_array_index (transports, 0);
+ addr = g_value_get_string (g_value_array_get_nth (transport, 1));
+ if (!strcmp (addr, "127.0.0.1"))
+ {
+ GMS_DEBUG_WARNING (priv->session,
+ "%s: ignoring native localhost candidate", G_STRFUNC);
+ tp_svc_media_stream_handler_return_from_new_native_candidate (context);
+ return;
+ }
+
+ component_id = g_value_get_uint (g_value_array_get_nth (transport, 0));
+ if (component_id != 1)
+ {
+ GMS_DEBUG_WARNING (priv->session,
+ "%s: ignoring native candidate non-1 component", G_STRFUNC);
+ tp_svc_media_stream_handler_return_from_new_native_candidate (context);
+ return;
+ }
+
+ g_ptr_array_add (candidates, g_value_get_boxed (&candidate));
+
+ GMS_DEBUG_INFO (priv->session,
+ "put 1 native candidate from stream-engine into cache");
+
+ push_native_candidates (self);
+
+ g_signal_emit (self, signals[NEW_NATIVE_CANDIDATE], 0,
+ candidate_id, transports);
+
+ 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 = GABBLE_MEDIA_STREAM_GET_PRIVATE (self);
+
+ GMS_DEBUG_INFO (priv->session, "ready called");
+
+ g_object_set (self, "ready", TRUE, NULL);
+
+ push_remote_codecs (self);
+ push_remote_candidates (self);
+ push_playing (self);
+ push_sending (self);
+
+ /* set_local_codecs and ready return the same thing, so we can do... */
+ gabble_media_stream_set_local_codecs (iface, codecs, context);
+}
+
+
+/**
+ * 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;
+
+ g_assert (GABBLE_IS_MEDIA_STREAM (self));
+
+ priv = GABBLE_MEDIA_STREAM_GET_PRIVATE (self);
+
+ GMS_DEBUG_INFO (priv->session, "putting list of all %d locally supported "
+ "codecs from stream-engine into cache", codecs->len);
+
+ g_value_set_boxed (&priv->native_codecs, codecs);
+
+ g_object_set (self, "got-local-codecs", TRUE, NULL);
+
+ 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);
+ g_assert (GABBLE_IS_MEDIA_STREAM (self));
+
+ g_object_set (self, "connection-state", connection_state, NULL);
+
+ 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;
+
+ g_assert (GABBLE_IS_MEDIA_STREAM (self));
+
+ priv = GABBLE_MEDIA_STREAM_GET_PRIVATE (self);
+
+ GMS_DEBUG_INFO (priv->session, "got codec intersection containing %d "
+ "codecs from stream-engine", codecs->len);
+
+ /* store the intersection for later on */
+ g_value_set_boxed (&priv->native_codecs, codecs);
+
+ g_signal_emit (self, signals[SUPPORTED_CODECS], 0, codecs);
+
+ tp_svc_media_stream_handler_return_from_supported_codecs (context);
+}
+
+static LmHandlerResult
+candidates_msg_reply_cb (GabbleConnection *conn,
+ LmMessage *sent_msg,
+ LmMessage *reply_msg,
+ GObject *object,
+ gpointer user_data)
+{
+ GabbleMediaStream *stream = GABBLE_MEDIA_STREAM (object);
+ GabbleMediaStreamPrivate *priv;
+
+ g_assert (GABBLE_IS_MEDIA_STREAM (stream));
+
+ priv = GABBLE_MEDIA_STREAM_GET_PRIVATE (stream);
+
+ MSG_REPLY_CB_END_SESSION_IF_NOT_SUCCESSFUL (priv->session,
+ "candidates failed");
+
+ return LM_HANDLER_RESULT_REMOVE_MESSAGE;
+}
+
+static void
+_add_rtp_candidate_node (GabbleMediaSession *session, LmMessageNode *parent,
+ GValueArray *candidate)
+{
+ gchar *addr;
+ gchar *user;
+ gchar *pass;
+ gchar *port_str;
+ gchar *pref_str;
+ gchar *xml;
+ const gchar *type_str, *proto_str, *candidate_id;
+ guint port;
+ gdouble pref;
+ TpMediaStreamBaseProto proto;
+ TpMediaStreamTransportType type;
+ const GPtrArray *transports;
+ GValue transport = { 0, };
+ LmMessageNode *cand_node;
+
+ 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));
+
+ /* jingle audio only supports the concept of one transport per candidate */
+ g_assert (transports->len == 1);
+
+ g_value_init (&transport, GABBLE_TP_TYPE_TRANSPORT_STRUCT);
+ g_value_set_static_boxed (&transport, g_ptr_array_index (transports, 0));
+
+ dbus_g_type_struct_get (&transport,
+ 1, &addr,
+ 2, &port,
+ 3, &proto,
+ 6, &pref,
+ 7, &type,
+ 8, &user,
+ 9, &pass,
+ G_MAXUINT);
+
+ port_str = g_strdup_printf ("%d", port);
+ pref_str = g_strdup_printf ("%f", pref);
+
+ switch (type) {
+ case TP_MEDIA_STREAM_TRANSPORT_TYPE_LOCAL:
+ type_str = "local";
+ break;
+ case TP_MEDIA_STREAM_TRANSPORT_TYPE_DERIVED:
+ type_str = "stun";
+ break;
+ case TP_MEDIA_STREAM_TRANSPORT_TYPE_RELAY:
+ type_str = "relay";
+ break;
+ default:
+ g_warning ("%s: TpMediaStreamTransportType has an invalid value, "
+ "ignoring candidate", G_STRFUNC);
+ goto out;
+ }
+
+ switch (proto)
+ {
+ case TP_MEDIA_STREAM_BASE_PROTO_UDP:
+ proto_str = "udp";
+ break;
+ case TP_MEDIA_STREAM_BASE_PROTO_TCP:
+ if (port == 443 && type == TP_MEDIA_STREAM_TRANSPORT_TYPE_RELAY)
+ proto_str = "ssltcp";
+ else
+ proto_str = "tcp";
+ break;
+ default:
+ g_warning ("%s: TpMediaStreamBaseProto has an invalid value, ignoring "
+ "candidate", G_STRFUNC);
+ goto out;
+ }
+
+ cand_node = lm_message_node_add_child (parent, "candidate", NULL);
+ lm_message_node_set_attributes (cand_node,
+ "name", "rtp",
+ "address", addr,
+ "port", port_str,
+ "username", user,
+ "password", pass,
+ "preference", pref_str,
+ "protocol", proto_str,
+ "type", type_str,
+ "network", "0",
+ "generation", "0",
+ NULL);
+
+ xml = lm_message_node_to_string (cand_node);
+ GMS_DEBUG_DUMP (session,
+ " from Telepathy D-Bus struct: [%s\"%s\", %s[%s1, \"%s\", %d, %s, "
+ "\"%s\", \"%s\", %f, %s, \"%s\", \"%s\"%s]]",
+ TP_ANSI_BOLD_OFF, candidate_id, TP_ANSI_BOLD_ON, TP_ANSI_BOLD_OFF,
+ addr, port, tp_protocols[proto], "RTP", "AVP", pref, tp_transports[type],
+ user, pass, TP_ANSI_BOLD_ON);
+ GMS_DEBUG_DUMP (session,
+ " to Jingle XML: [%s%s%s]", TP_ANSI_BOLD_OFF, xml, TP_ANSI_BOLD_ON);
+ g_free (xml);
+
+out:
+ g_free (addr);
+ g_free (user);
+ g_free (pass);
+ g_free (port_str);
+ g_free (pref_str);
+}
+
+static LmMessage *
+_gabble_media_stream_message_new (GabbleMediaStream *stream,
+ const gchar *action,
+ LmMessageNode **content_node)
+{
+ GabbleMediaStreamPrivate *priv = GABBLE_MEDIA_STREAM_GET_PRIVATE (stream);
+ LmMessage *msg;
+ LmMessageNode *session_node = NULL;
+
+ /* construct a session message */
+ msg = _gabble_media_session_message_new (priv->session, action,
+ &session_node);
+
+ /* add our content node to it if necessary */
+ *content_node = _gabble_media_stream_add_content_node (stream, session_node);
+
+ return msg;
+}
+
+
+static void
+push_candidate (GabbleMediaStream *stream, GValueArray *candidate)
+{
+ GabbleMediaStreamPrivate *priv = GABBLE_MEDIA_STREAM_GET_PRIVATE (stream);
+ LmMessage *msg;
+ LmMessageNode *content_node, *transport_node;
+ const gchar *action;
+
+ if (priv->mode == MODE_GOOGLE)
+ action = "candidates";
+ else
+ action = "transport-info";
+
+ /* construct a base message */
+ msg = _gabble_media_stream_message_new (stream, action, &content_node);
+
+ /* for jingle, add a transport */
+ transport_node = _gabble_media_stream_content_node_add_transport (stream,
+ content_node);
+
+ /* add transport info to it */
+ _add_rtp_candidate_node (priv->session, transport_node, candidate);
+
+ GMS_DEBUG_INFO (priv->session, "sending jingle session action \"%s\" to "
+ "peer", action);
+
+ /* send it */
+ _gabble_connection_send_with_reply (priv->conn, msg, candidates_msg_reply_cb,
+ G_OBJECT (stream), NULL, NULL);
+
+ /* clean up */
+ lm_message_unref (msg);
+}
+
+static void
+push_native_candidates (GabbleMediaStream *stream)
+{
+ GabbleMediaStreamPrivate *priv;
+ GPtrArray *candidates;
+ guint i;
+
+ g_assert (GABBLE_IS_MEDIA_STREAM (stream));
+
+ priv = GABBLE_MEDIA_STREAM_GET_PRIVATE (stream);
+
+ if (stream->signalling_state == STREAM_SIG_STATE_NEW ||
+ stream->signalling_state == STREAM_SIG_STATE_REMOVING)
+ return;
+
+ candidates = g_value_get_boxed (&priv->native_candidates);
+
+ for (i = 0; i < candidates->len; i++)
+ push_candidate (stream, g_ptr_array_index (candidates, i));
+
+ g_value_take_boxed (&priv->native_candidates,
+ dbus_g_type_specialized_construct (GABBLE_TP_TYPE_CANDIDATE_LIST));
+}
+
+void
+_gabble_media_stream_close (GabbleMediaStream *stream)
+{
+ GabbleMediaStreamPrivate *priv;
+
+ g_assert (GABBLE_IS_MEDIA_STREAM (stream));
+
+ priv = GABBLE_MEDIA_STREAM_GET_PRIVATE (stream);
+
+ if (!priv->closed)
+ {
+ priv->closed = TRUE;
+ tp_svc_media_stream_handler_emit_close (stream);
+ }
+}
+
+gboolean
+_gabble_media_stream_post_remote_codecs (GabbleMediaStream *stream,
+ LmMessage *message,
+ LmMessageNode *desc_node,
+ GError **error)
+{
+ GabbleMediaStreamPrivate *priv;
+ LmMessageNode *node;
+ GPtrArray *codecs;
+
+ g_assert (GABBLE_IS_MEDIA_STREAM (stream));
+
+ priv = GABBLE_MEDIA_STREAM_GET_PRIVATE (stream);
+
+ codecs = g_value_get_boxed (&priv->remote_codecs);
+
+ g_assert (codecs->len == 0);
+
+ for (node = desc_node->children; node; node = node->next)
+ {
+ guchar id;
+ const gchar *name, *str;
+ guint clockrate, channels;
+ GHashTable *params;
+ GValue codec = { 0, };
+
+ if (tp_strdiff (node->name, "payload-type"))
+ continue;
+
+ /* id of codec */
+ str = lm_message_node_get_attribute (node, "id");
+ if (str == NULL)
+ {
+ g_set_error (error, GABBLE_XMPP_ERROR, XMPP_ERROR_BAD_REQUEST,
+ "description has no ID");
+ return FALSE;
+ }
+
+ id = atoi (str);
+
+ /* codec name */
+ name = lm_message_node_get_attribute (node, "name");
+ if (name == NULL)
+ {
+ name = "";
+ }
+
+ /* clock rate: jingle and newer GTalk */
+ str = lm_message_node_get_attribute (node, "clockrate"); /* google */
+ if (str == NULL)
+ str = lm_message_node_get_attribute (node, "rate"); /* jingle */
+
+ if (str != NULL)
+ {
+ clockrate = atoi (str);
+ }
+ else
+ {
+ clockrate = 0;
+ }
+
+ /* number of channels: jingle only */
+ str = lm_message_node_get_attribute (node, "channels");
+ if (str != NULL)
+ {
+ channels = atoi (str);
+ }
+ else
+ {
+ channels = 1;
+ }
+
+ params = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_free);
+
+ /* bitrate: newer GTalk only */
+ str = lm_message_node_get_attribute (node, "bitrate");
+ if (str != NULL)
+ {
+ g_hash_table_insert (params, "bitrate", g_strdup (str));
+ }
+
+ g_value_init (&codec, GABBLE_TP_TYPE_CODEC_STRUCT);
+ g_value_take_boxed (&codec,
+ dbus_g_type_specialized_construct (GABBLE_TP_TYPE_CODEC_STRUCT));
+
+ dbus_g_type_struct_set (&codec,
+ 0, id,
+ 1, name,
+ 2, priv->media_type,
+ 3, clockrate,
+ 4, channels,
+ 5, params,
+ G_MAXUINT);
+
+ g_ptr_array_add (codecs, g_value_get_boxed (&codec));
+ }
+
+ GMS_DEBUG_INFO (priv->session, "put %d remote codecs from peer into cache",
+ codecs->len);
+
+ push_remote_codecs (stream);
+
+ return TRUE;
+}
+
+static void
+push_remote_codecs (GabbleMediaStream *stream)
+{
+ GabbleMediaStreamPrivate *priv;
+ GPtrArray *codecs;
+
+ g_assert (GABBLE_IS_MEDIA_STREAM (stream));
+
+ priv = GABBLE_MEDIA_STREAM_GET_PRIVATE (stream);
+
+ if (!priv->ready)
+ return;
+
+ codecs = g_value_get_boxed (&priv->remote_codecs);
+ if (codecs->len == 0)
+ return;
+
+ GMS_DEBUG_EVENT (priv->session, "passing %d remote codecs to stream-engine",
+ codecs->len);
+
+ tp_svc_media_stream_handler_emit_set_remote_codecs (stream, codecs);
+
+ g_value_take_boxed (&priv->remote_codecs,
+ dbus_g_type_specialized_construct (GABBLE_TP_TYPE_CODEC_LIST));
+}
+
+gboolean
+_gabble_media_stream_post_remote_candidates (GabbleMediaStream *stream,
+ LmMessage *message,
+ LmMessageNode *transport_node,
+ GError **error)
+{
+ GabbleMediaStreamPrivate *priv;
+ LmMessageNode *node;
+ const gchar *str;
+ GPtrArray *candidates;
+
+ g_assert (GABBLE_IS_MEDIA_STREAM (stream));
+
+ priv = GABBLE_MEDIA_STREAM_GET_PRIVATE (stream);
+
+ candidates = g_value_get_boxed (&priv->remote_candidates);
+
+ for (node = transport_node->children; node; node = node->next)
+ {
+ gchar *candidate_id;
+ const gchar *name, *addr;
+ guint16 port;
+ TpMediaStreamBaseProto proto;
+ gdouble pref;
+ TpMediaStreamTransportType type;
+ const gchar *user, *pass;
+ guchar net, gen;
+ GValue candidate = { 0, };
+ GPtrArray *transports;
+ GValue transport = { 0, };
+ gchar *xml;
+
+ if (tp_strdiff (node->name, "candidate"))
+ continue;
+
+ /*
+ * Candidate
+ */
+
+ /* stream name */
+ name = lm_message_node_get_attribute (node, "name");
+ if (name == NULL || strcmp (name, "rtp") != 0)
+ goto FAILURE;
+
+
+ /*
+ * Transport
+ */
+
+ /* ip address */
+ addr = lm_message_node_get_attribute (node, "address");
+ if (addr == NULL)
+ goto FAILURE;
+
+ /* port */
+ str = lm_message_node_get_attribute (node, "port");
+ if (str == NULL)
+ goto FAILURE;
+ port = atoi (str);
+
+ /* protocol */
+ str = lm_message_node_get_attribute (node, "protocol");
+ if (str == NULL)
+ goto FAILURE;
+
+ if (strcmp (str, "udp") == 0)
+ {
+ proto = TP_MEDIA_STREAM_BASE_PROTO_UDP;
+ }
+ else if (strcmp (str, "tcp") == 0)
+ {
+ if (port == 443)
+ {
+ GMS_DEBUG_WARNING (priv->session, "%s: tcp candidates on port "
+ "443 must be ssltcp, ignoring candidate", G_STRFUNC);
+ continue;
+ }
+
+ proto = TP_MEDIA_STREAM_BASE_PROTO_TCP;
+ }
+ else if (strcmp (str, "ssltcp") == 0)
+ {
+ if (port != 443)
+ {
+ GMS_DEBUG_WARNING (priv->session, "%s: ssltcp candidates must "
+ "be on port 443, ignoring candidate", G_STRFUNC);
+ continue;
+ }
+
+ proto = TP_MEDIA_STREAM_BASE_PROTO_TCP;
+ }
+ else
+ goto FAILURE;
+
+ /* protocol profile: hardcoded to "AVP" for now */
+
+ /* preference */
+ str = lm_message_node_get_attribute (node, "preference");
+ if (str == NULL)
+ goto FAILURE;
+ pref = g_ascii_strtod (str, NULL);
+
+ /* type */
+ str = lm_message_node_get_attribute (node, "type");
+ if (str == NULL)
+ goto FAILURE;
+
+ if (strcmp (str, "local") == 0)
+ {
+ type = TP_MEDIA_STREAM_TRANSPORT_TYPE_LOCAL;
+ }
+ else if (strcmp (str, "stun") == 0)
+ {
+ type = TP_MEDIA_STREAM_TRANSPORT_TYPE_DERIVED;
+ }
+ else if (strcmp (str, "relay") == 0)
+ {
+ type = TP_MEDIA_STREAM_TRANSPORT_TYPE_RELAY;
+ }
+ else
+ goto FAILURE;
+
+ /* username */
+ user = lm_message_node_get_attribute (node, "username");
+ if (user == NULL)
+ goto FAILURE;
+
+ /* password */
+ pass = lm_message_node_get_attribute (node, "password");
+ if (pass == NULL)
+ goto FAILURE;
+
+ /* unknown */
+ str = lm_message_node_get_attribute (node, "network");
+ if (str == NULL)
+ goto FAILURE;
+ net = atoi (str);
+
+ /* unknown */
+ str = lm_message_node_get_attribute (node, "generation");
+ if (str == NULL)
+ goto FAILURE;
+ gen = atoi (str);
+
+
+ g_value_init (&transport, GABBLE_TP_TYPE_TRANSPORT_STRUCT);
+ g_value_take_boxed (&transport,
+ dbus_g_type_specialized_construct (GABBLE_TP_TYPE_TRANSPORT_STRUCT));
+
+ dbus_g_type_struct_set (&transport,
+ 0, 1, /* component number */
+ 1, addr,
+ 2, port,
+ 3, proto,
+ 4, "RTP",
+ 5, "AVP",
+ 6, pref,
+ 7, type,
+ 8, user,
+ 9, pass,
+ G_MAXUINT);
+
+ transports = g_ptr_array_sized_new (1);
+ g_ptr_array_add (transports, g_value_get_boxed (&transport));
+
+
+ g_value_init (&candidate, GABBLE_TP_TYPE_CANDIDATE_STRUCT);
+ g_value_take_boxed (&candidate,
+ dbus_g_type_specialized_construct (GABBLE_TP_TYPE_CANDIDATE_STRUCT));
+
+ /* FIXME: is this naming scheme sensible? */
+ candidate_id = g_strdup_printf ("R%d", ++priv->remote_candidate_count);
+
+ dbus_g_type_struct_set (&candidate,
+ 0, candidate_id,
+ 1, transports,
+ G_MAXUINT);
+
+ g_ptr_array_add (candidates, g_value_get_boxed (&candidate));
+
+ xml = lm_message_node_to_string (node);
+ GMS_DEBUG_INFO (priv->session,
+ "put 1 remote candidate from peer into cache");
+ GMS_DEBUG_DUMP (priv->session, " from Jingle XML: [%s%s%s]",
+ TP_ANSI_BOLD_OFF, xml, TP_ANSI_BOLD_ON);
+ GMS_DEBUG_DUMP (priv->session,
+ " to Telepathy D-Bus struct: [%s\"%s\", %s[%s1, \"%s\", %d, %s, "
+ "\"%s\", \"%s\", %f, %s, \"%s\", \"%s\"%s]]",
+ TP_ANSI_BOLD_OFF, candidate_id, TP_ANSI_BOLD_ON,
+ TP_ANSI_BOLD_OFF, addr, port, tp_protocols[proto],
+ "RTP", "AVP", pref, tp_transports[type],
+ user, pass, TP_ANSI_BOLD_ON);
+ g_free (xml);
+
+ g_free (candidate_id);
+ }
+
+/*SUCCESS:*/
+ push_remote_candidates (stream);
+
+ return TRUE;
+
+FAILURE:
+ g_set_error (error, GABBLE_XMPP_ERROR, XMPP_ERROR_BAD_REQUEST,
+ "unable to parse candidate");
+
+ return FALSE;
+}
+
+static void
+push_remote_candidates (GabbleMediaStream *stream)
+{
+ GabbleMediaStreamPrivate *priv;
+ GPtrArray *candidates;
+ guint i;
+
+ g_assert (GABBLE_IS_MEDIA_STREAM (stream));
+
+ priv = GABBLE_MEDIA_STREAM_GET_PRIVATE (stream);
+
+ 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));
+
+ GMS_DEBUG_EVENT (priv->session, "passing 1 remote candidate "
+ "to stream-engine");
+
+ 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 (GABBLE_TP_TYPE_CANDIDATE_LIST));
+}
+
+static void
+push_playing (GabbleMediaStream *stream)
+{
+ GabbleMediaStreamPrivate *priv;
+
+ g_assert (GABBLE_IS_MEDIA_STREAM (stream));
+
+ priv = GABBLE_MEDIA_STREAM_GET_PRIVATE (stream);
+
+ if (!priv->ready)
+ return;
+
+ GMS_DEBUG_INFO (priv->session, "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;
+
+ g_assert (GABBLE_IS_MEDIA_STREAM (stream));
+
+ priv = GABBLE_MEDIA_STREAM_GET_PRIVATE (stream);
+
+ if (!priv->ready)
+ return;
+
+ GMS_DEBUG_INFO (priv->session, "stream %s emitting SetStreamSending(%s)",
+ stream->name, priv->sending ? "true" : "false");
+
+ tp_svc_media_stream_handler_emit_set_stream_sending (
+ stream, priv->sending);
+}
+
+/*
+ * oh sweet g_hash_table_foreach how beautiful thou be'st
+ *
+ * _\ / ^/
+ * \/ \// 7_ __
+ * ( 7 ) (__) (__)
+ * ^\\ |/__/___/
+ * \\/_/ | <-- TP-cable kindly provided by Mika N.
+ * \ / O
+ * || /|\
+ * || / \
+ * ||
+ * ____||_____________
+ */
+
+typedef struct {
+ GabbleMediaStreamPrivate *priv;
+ LmMessageNode *pt_node;
+} CodecParamsFromTpContext;
+
+static const gchar *video_codec_params[] = {
+ "x", "y", "width", "height", "layer", "transparent",
+};
+
+static void
+codec_params_from_tp_foreach (gpointer key, gpointer value, gpointer user_data)
+{
+ CodecParamsFromTpContext *ctx = user_data;
+ GabbleMediaStreamPrivate *priv = ctx->priv;
+ const gchar *pname = key, *pvalue = value;
+
+ if (priv->media_type == TP_MEDIA_STREAM_TYPE_AUDIO)
+ {
+ if (priv->mode == MODE_GOOGLE && strcmp (pname, "bitrate") == 0)
+ {
+ lm_message_node_set_attribute (ctx->pt_node, pname, pvalue);
+ return;
+ }
+ }
+ else if (priv->mode == MODE_JINGLE)
+ {
+ gint i;
+
+ for (i = 0; video_codec_params[i] != NULL; i++)
+ {
+ if (strcmp (pname, video_codec_params[i]) == 0)
+ {
+ lm_message_node_set_attribute (ctx->pt_node, pname, pvalue);
+ return;
+ }
+ }
+ }
+
+ DEBUG ("ignoring %s=%s for %s %s stream", pname, pvalue,
+ (priv->mode == MODE_JINGLE) ? "jingle" : "google",
+ (priv->media_type == TP_MEDIA_STREAM_TYPE_AUDIO) ? "audio" : "video");
+}
+
+LmMessageNode *
+_gabble_media_stream_add_content_node (GabbleMediaStream *stream,
+ LmMessageNode *session_node)
+{
+ GabbleMediaStreamPrivate *priv = GABBLE_MEDIA_STREAM_GET_PRIVATE (stream);
+ LmMessageNode *node = session_node;
+
+ /* add our content node to it if in jingle mode */
+ if (priv->mode == MODE_JINGLE)
+ {
+ node = lm_message_node_add_child (session_node, "content", NULL);
+ lm_message_node_set_attribute (node, "name", stream->name);
+
+ if (priv->session->initiator == stream->initiator)
+ lm_message_node_set_attribute (node, "creator", "initiator");
+ else
+ lm_message_node_set_attribute (node, "creator", "responder");
+ }
+
+ return node;
+}
+
+void
+_gabble_media_stream_content_node_add_description (GabbleMediaStream *stream,
+ LmMessageNode *content_node)
+{
+ GabbleMediaStreamPrivate *priv;
+ const GPtrArray *codecs;
+ LmMessageNode *desc_node;
+ guint i;
+ const gchar *xmlns;
+
+ g_assert (GABBLE_IS_MEDIA_STREAM (stream));
+
+ priv = GABBLE_MEDIA_STREAM_GET_PRIVATE (stream);
+
+ codecs = g_value_get_boxed (&priv->native_codecs);
+
+ desc_node = lm_message_node_add_child (content_node, "description", NULL);
+
+ if (priv->mode == MODE_GOOGLE)
+ xmlns = NS_GOOGLE_SESSION_PHONE;
+ else if (priv->media_type == TP_MEDIA_STREAM_TYPE_VIDEO)
+ xmlns = NS_JINGLE_DESCRIPTION_VIDEO;
+ else
+ xmlns = NS_JINGLE_DESCRIPTION_AUDIO;
+
+ lm_message_node_set_attribute (desc_node, "xmlns", xmlns);
+
+ for (i = 0; i < codecs->len; i++)
+ {
+ GValue codec = { 0, };
+ guint id, clock_rate, channels;
+ gchar *name, buf[16];
+ GHashTable *params;
+ LmMessageNode *pt_node;
+ CodecParamsFromTpContext ctx;
+
+ g_value_init (&codec, GABBLE_TP_TYPE_CODEC_STRUCT);
+ 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);
+
+ /* create a sub-node called "payload-type" and fill it */
+ pt_node = lm_message_node_add_child (desc_node, "payload-type", NULL);
+
+ /* id: required */
+ sprintf (buf, "%u", id);
+ lm_message_node_set_attribute (pt_node, "id", buf);
+
+ /* name: optional */
+ if (*name != '\0')
+ {
+ lm_message_node_set_attribute (pt_node, "name", name);
+ }
+
+ /* clock rate: optional */
+ if (clock_rate != 0)
+ {
+ sprintf (buf, "%u", clock_rate);
+ lm_message_node_set_attribute (pt_node,
+ (priv->mode == MODE_GOOGLE) ? "clockrate" : "rate", buf);
+ }
+
+ /* number of channels: optional, jingle only */
+ /* FIXME: is it? */
+ if (channels != 0 && priv->mode == MODE_JINGLE)
+ {
+ sprintf (buf, "%u", channels);
+ lm_message_node_set_attribute (pt_node, "channels", buf);
+ }
+
+ /* parse the optional params */
+ ctx.priv = priv;
+ ctx.pt_node = pt_node;
+ g_hash_table_foreach (params, codec_params_from_tp_foreach, &ctx);
+
+ /* clean up */
+ g_free (name);
+ g_hash_table_destroy (params);
+ }
+}
+
+LmMessageNode *
+_gabble_media_stream_content_node_add_transport (GabbleMediaStream *stream,
+ LmMessageNode *content_node)
+{
+ GabbleMediaStreamPrivate *priv;
+ LmMessageNode *node;
+
+ g_assert (GABBLE_IS_MEDIA_STREAM (stream));
+
+ priv = GABBLE_MEDIA_STREAM_GET_PRIVATE (stream);
+
+ if (priv->mode != MODE_JINGLE)
+ return content_node;
+
+ node = lm_message_node_add_child (content_node, "transport", NULL);
+
+ lm_message_node_set_attribute (node, "xmlns", NS_GOOGLE_TRANSPORT_P2P);
+
+ return node;
+}
+
+void
+_gabble_media_stream_update_sending (GabbleMediaStream *stream,
+ gboolean start_sending)
+{
+ GabbleMediaStreamPrivate *priv;
+ gboolean new_sending;
+
+ g_assert (GABBLE_IS_MEDIA_STREAM (stream));
+
+ priv = GABBLE_MEDIA_STREAM_GET_PRIVATE (stream);
+
+ 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,);
+#undef IMPLEMENT
+}
--
1.5.6.3
More information about the Telepathy-commits
mailing list