[Telepathy-commits] [telepathy-glib/master] ExampleCallableMediaStream: add an example implementation of a media stream
Simon McVittie
simon.mcvittie at collabora.co.uk
Wed Mar 11 05:55:23 PDT 2009
---
examples/cm/callable/Makefile.am | 4 +-
examples/cm/callable/media-stream.c | 374 +++++++++++++++++++++++++++++++++++
examples/cm/callable/media-stream.h | 77 +++++++
3 files changed, 454 insertions(+), 1 deletions(-)
create mode 100644 examples/cm/callable/media-stream.c
create mode 100644 examples/cm/callable/media-stream.h
diff --git a/examples/cm/callable/Makefile.am b/examples/cm/callable/Makefile.am
index a60ef40..312b36d 100644
--- a/examples/cm/callable/Makefile.am
+++ b/examples/cm/callable/Makefile.am
@@ -17,7 +17,9 @@ libexample_cm_callable_la_SOURCES = \
media-channel.c \
media-channel.h \
media-manager.c \
- media-manager.h
+ media-manager.h \
+ media-stream.c \
+ media-stream.h
# In an external project you'd use $(TP_GLIB_LIBS) (obtained from
# pkg-config via autoconf) instead of the .la path
diff --git a/examples/cm/callable/media-stream.c b/examples/cm/callable/media-stream.c
new file mode 100644
index 0000000..744ad57
--- /dev/null
+++ b/examples/cm/callable/media-stream.c
@@ -0,0 +1,374 @@
+/*
+ * media-stream.c - a stream in a streamed media call.
+ *
+ * In connection managers with MediaSignalling, this object would be a D-Bus
+ * object in its own right. In this CM, MediaSignalling is not used, and this
+ * object just represents internal state of the MediaChannel.
+ *
+ * Copyright © 2007-2009 Collabora Ltd. <http://www.collabora.co.uk/>
+ * Copyright © 2007-2009 Nokia Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "media-stream.h"
+
+#include <telepathy-glib/base-connection.h>
+
+#include "media-channel.h"
+
+G_DEFINE_TYPE (ExampleCallableMediaStream,
+ example_callable_media_stream,
+ G_TYPE_OBJECT)
+
+enum
+{
+ PROP_CHANNEL = 1,
+ PROP_ID,
+ PROP_HANDLE,
+ PROP_TYPE,
+ PROP_STATE,
+ PROP_PENDING_SEND,
+ PROP_DIRECTION,
+ N_PROPS
+};
+
+enum
+{
+ SIGNAL_REMOVED,
+ SIGNAL_DIRECTION_CHANGED,
+ N_SIGNALS
+};
+
+static guint signals[N_SIGNALS] = { 0 };
+
+struct _ExampleCallableMediaStreamPrivate
+{
+ TpBaseConnection *conn;
+ ExampleCallableMediaChannel *channel;
+ guint id;
+ TpHandle handle;
+ TpMediaStreamType type;
+ TpMediaStreamState state;
+ TpMediaStreamDirection direction;
+ TpMediaStreamPendingSend pending_send;
+};
+
+static void
+example_callable_media_stream_init (ExampleCallableMediaStream *self)
+{
+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
+ EXAMPLE_TYPE_CALLABLE_MEDIA_STREAM,
+ ExampleCallableMediaStreamPrivate);
+}
+
+static void
+call_terminated_cb (ExampleCallableMediaChannel *channel,
+ ExampleCallableMediaStream *self)
+{
+ example_callable_media_stream_close (self);
+}
+
+static void
+constructed (GObject *object)
+{
+ ExampleCallableMediaStream *self = EXAMPLE_CALLABLE_MEDIA_STREAM (object);
+ void (*chain_up) (GObject *) =
+ ((GObjectClass *) example_callable_media_stream_parent_class)->constructed;
+
+ if (chain_up != NULL)
+ chain_up (object);
+
+ g_object_get (self->priv->channel,
+ "connection", &self->priv->conn,
+ NULL);
+ g_signal_connect (self->priv->channel, "call-terminated",
+ G_CALLBACK (call_terminated_cb), self);
+
+ if (self->priv->handle != 0)
+ {
+ TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (
+ self->priv->conn, TP_HANDLE_TYPE_CONTACT);
+
+ tp_handle_ref (contact_repo, self->priv->handle);
+ }
+}
+
+static void
+get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ ExampleCallableMediaStream *self = EXAMPLE_CALLABLE_MEDIA_STREAM (object);
+
+ switch (property_id)
+ {
+ case PROP_ID:
+ g_value_set_uint (value, self->priv->id);
+ break;
+
+ case PROP_HANDLE:
+ g_value_set_uint (value, self->priv->handle);
+ break;
+
+ case PROP_TYPE:
+ g_value_set_uint (value, self->priv->type);
+ break;
+
+ case PROP_STATE:
+ g_value_set_uint (value, self->priv->state);
+ break;
+
+ case PROP_PENDING_SEND:
+ g_value_set_uint (value, self->priv->pending_send);
+ break;
+
+ case PROP_DIRECTION:
+ g_value_set_uint (value, self->priv->direction);
+ break;
+
+ case PROP_CHANNEL:
+ g_value_set_object (value, self->priv->channel);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ ExampleCallableMediaStream *self = EXAMPLE_CALLABLE_MEDIA_STREAM (object);
+
+ switch (property_id)
+ {
+ case PROP_ID:
+ self->priv->id = g_value_get_uint (value);
+ break;
+
+ case PROP_HANDLE:
+ self->priv->handle = g_value_get_uint (value);
+ break;
+
+ case PROP_TYPE:
+ self->priv->type = g_value_get_uint (value);
+ break;
+
+ case PROP_CHANNEL:
+ g_assert (self->priv->channel == NULL);
+ self->priv->channel = g_value_dup_object (value);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+dispose (GObject *object)
+{
+ ExampleCallableMediaStream *self = EXAMPLE_CALLABLE_MEDIA_STREAM (object);
+ TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (
+ self->priv->conn, TP_HANDLE_TYPE_CONTACT);
+
+ if (self->priv->handle != 0)
+ {
+ tp_handle_unref (contact_repo, self->priv->handle);
+ self->priv->handle = 0;
+ }
+
+ if (self->priv->channel != NULL)
+ {
+ g_object_unref (self->priv->channel);
+ self->priv->channel = NULL;
+ }
+
+ if (self->priv->conn != NULL)
+ {
+ g_object_unref (self->priv->conn);
+ self->priv->conn = NULL;
+ }
+
+ ((GObjectClass *) example_callable_media_stream_parent_class)->dispose (object);
+}
+
+static void
+example_callable_media_stream_class_init (ExampleCallableMediaStreamClass *klass)
+{
+ GObjectClass *object_class = (GObjectClass *) klass;
+ GParamSpec *param_spec;
+
+ g_type_class_add_private (klass,
+ sizeof (ExampleCallableMediaStreamPrivate));
+
+ object_class->constructed = constructed;
+ object_class->set_property = set_property;
+ object_class->get_property = get_property;
+ object_class->dispose = dispose;
+
+ param_spec = g_param_spec_object ("channel", "ExampleCallableMediaChannel",
+ "Media channel that owns this stream",
+ EXAMPLE_TYPE_CALLABLE_MEDIA_CHANNEL,
+ G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (object_class, PROP_CHANNEL, param_spec);
+
+ param_spec = g_param_spec_uint ("id", "Stream ID",
+ "ID of this stream",
+ 0, G_MAXUINT32, 0,
+ G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (object_class, PROP_ID, param_spec);
+
+ param_spec = g_param_spec_uint ("handle", "Peer's TpHandle",
+ "The handle with which this stream communicates or 0 if not applicable",
+ 0, G_MAXUINT32, 0,
+ G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (object_class, PROP_HANDLE, param_spec);
+
+ param_spec = g_param_spec_uint ("type", "TpMediaStreamType",
+ "Media stream type",
+ 0, NUM_TP_MEDIA_STREAM_TYPES - 1, 0,
+ G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (object_class, PROP_TYPE, param_spec);
+
+ param_spec = g_param_spec_uint ("state", "TpMediaStreamState",
+ "Media stream connection state",
+ 0, NUM_TP_MEDIA_STREAM_STATES - 1, 0,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (object_class, PROP_STATE, param_spec);
+
+ param_spec = g_param_spec_uint ("direction", "TpMediaStreamDirection",
+ "Media stream direction",
+ 0, NUM_TP_MEDIA_STREAM_DIRECTIONS - 1, 0,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (object_class, PROP_DIRECTION, param_spec);
+
+ param_spec = g_param_spec_uint ("pending-send", "TpMediaStreamPendingSend",
+ "Requested media stream directions pending approval",
+ 0,
+ TP_MEDIA_STREAM_PENDING_LOCAL_SEND | TP_MEDIA_STREAM_PENDING_REMOTE_SEND,
+ 0,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (object_class, PROP_PENDING_SEND, param_spec);
+
+ signals[SIGNAL_REMOVED] = g_signal_new ("removed",
+ G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ signals[SIGNAL_DIRECTION_CHANGED] = g_signal_new ("direction-changed",
+ G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+}
+
+void
+example_callable_media_stream_close (ExampleCallableMediaStream *self)
+{
+ g_message ("Sending to server: Closing stream %u",
+ self->priv->id);
+
+ g_signal_emit (self, signals[SIGNAL_REMOVED], 0);
+}
+
+gboolean
+example_callable_media_stream_change_direction (
+ ExampleCallableMediaStream *self,
+ TpMediaStreamDirection direction,
+ GError **error)
+{
+ gboolean sending =
+ ((self->priv->direction & TP_MEDIA_STREAM_DIRECTION_SEND) != 0);
+ gboolean receiving =
+ ((self->priv->direction & TP_MEDIA_STREAM_DIRECTION_RECEIVE) != 0);
+ gboolean want_to_send =
+ ((direction & TP_MEDIA_STREAM_DIRECTION_RECEIVE) != 0);
+ gboolean want_to_receive =
+ ((direction & TP_MEDIA_STREAM_DIRECTION_RECEIVE) != 0);
+ gboolean pending_remote_send =
+ ((self->priv->pending_send & TP_MEDIA_STREAM_PENDING_REMOTE_SEND) != 0);
+ gboolean pending_local_send =
+ ((self->priv->pending_send & TP_MEDIA_STREAM_PENDING_LOCAL_SEND) != 0);
+ gboolean changed = FALSE;
+
+ if (want_to_send)
+ {
+ if (!sending)
+ {
+ if (pending_local_send)
+ {
+ g_message ("SIGNALLING: send: I will now send you media on "
+ "stream %u", self->priv->id);
+ }
+
+ g_message ("MEDIA: Sending media to peer for stream %u",
+ self->priv->id);
+ changed = TRUE;
+ self->priv->direction |= TP_MEDIA_STREAM_DIRECTION_SEND;
+ }
+ }
+ else
+ {
+ if (sending)
+ {
+ g_message ("SIGNALLING: send: I will no longer send you media on "
+ "stream %u", self->priv->id);
+ g_message ("MEDIA: No longer sending media to peer for stream %u",
+ self->priv->id);
+ changed = TRUE;
+ self->priv->direction &= ~TP_MEDIA_STREAM_DIRECTION_SEND;
+ }
+ else if (pending_local_send)
+ {
+ g_message ("SIGNALLING: send: No, I refuse to send you media on "
+ "stream %u", self->priv->id);
+ changed = TRUE;
+ self->priv->pending_send &= ~TP_MEDIA_STREAM_PENDING_LOCAL_SEND;
+ }
+ }
+
+ if (want_to_receive)
+ {
+ if (!receiving && !pending_remote_send)
+ {
+ g_message ("SIGNALLING: send: Please start sending me stream %u",
+ self->priv->id);
+ changed = TRUE;
+ self->priv->pending_send |= TP_MEDIA_STREAM_PENDING_REMOTE_SEND;
+ /* FIXME: schedule a timeout, after which the sender will accept
+ * our request */
+ }
+ }
+ else
+ {
+ if (receiving)
+ {
+ g_message ("SIGNALLING: send: Please stop sending me stream %u",
+ self->priv->id);
+ g_message ("MEDIA: Suppressing output of stream %u",
+ self->priv->id);
+ changed = TRUE;
+ self->priv->direction &= ~TP_MEDIA_STREAM_DIRECTION_RECEIVE;
+ }
+ }
+
+ return TRUE;
+}
diff --git a/examples/cm/callable/media-stream.h b/examples/cm/callable/media-stream.h
new file mode 100644
index 0000000..4f1a508
--- /dev/null
+++ b/examples/cm/callable/media-stream.h
@@ -0,0 +1,77 @@
+/*
+ * media-stream.h - header for an example stream
+ *
+ * Copyright © 2007-2009 Collabora Ltd. <http://www.collabora.co.uk/>
+ * Copyright © 2007-2009 Nokia Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __EXAMPLE_CALLABLE_MEDIA_STREAM_H__
+#define __EXAMPLE_CALLABLE_MEDIA_STREAM_H__
+
+#include <glib-object.h>
+
+#include <telepathy-glib/enums.h>
+
+G_BEGIN_DECLS
+
+typedef struct _ExampleCallableMediaStream ExampleCallableMediaStream;
+typedef struct _ExampleCallableMediaStreamPrivate
+ ExampleCallableMediaStreamPrivate;
+
+typedef struct _ExampleCallableMediaStreamClass
+ ExampleCallableMediaStreamClass;
+typedef struct _ExampleCallableMediaStreamClassPrivate
+ ExampleCallableMediaStreamClassPrivate;
+
+GType example_callable_media_stream_get_type (void);
+
+#define EXAMPLE_TYPE_CALLABLE_MEDIA_STREAM \
+ (example_callable_media_stream_get_type ())
+#define EXAMPLE_CALLABLE_MEDIA_STREAM(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), EXAMPLE_TYPE_CALLABLE_MEDIA_STREAM, \
+ ExampleCallableMediaStream))
+#define EXAMPLE_CALLABLE_MEDIA_STREAM_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST ((klass), EXAMPLE_TYPE_CALLABLE_MEDIA_STREAM, \
+ ExampleCallableMediaStreamClass))
+#define EXAMPLE_IS_CALLABLE_MEDIA_STREAM(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EXAMPLE_TYPE_CALLABLE_MEDIA_STREAM))
+#define EXAMPLE_IS_CALLABLE_MEDIA_STREAM_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE ((klass), EXAMPLE_TYPE_CALLABLE_MEDIA_STREAM))
+#define EXAMPLE_CALLABLE_MEDIA_STREAM_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), EXAMPLE_TYPE_CALLABLE_MEDIA_STREAM, \
+ ExampleCallableMediaStreamClass))
+
+struct _ExampleCallableMediaStreamClass {
+ GObjectClass parent_class;
+
+ ExampleCallableMediaStreamClassPrivate *priv;
+};
+
+struct _ExampleCallableMediaStream {
+ GObject parent;
+
+ ExampleCallableMediaStreamPrivate *priv;
+};
+
+void example_callable_media_stream_close (ExampleCallableMediaStream *self);
+gboolean example_callable_media_stream_change_direction (
+ ExampleCallableMediaStream *self, TpMediaStreamDirection direction,
+ GError **error);
+
+G_END_DECLS
+
+#endif
--
1.5.6.5
More information about the telepathy-commits
mailing list