aboutsummaryrefslogtreecommitdiffstats
path: root/libempathy
diff options
context:
space:
mode:
authorXavier Claessens <xclaesse@gmail.com>2007-09-29 20:08:45 +0800
committerXavier Claessens <xclaesse@src.gnome.org>2007-09-29 20:08:45 +0800
commite3e5702a683c468ccc1742515b4033f32c7d1083 (patch)
tree9036ec7c855079e59ec6b67128ee37134bb79abf /libempathy
parentf5490a416f103d552344f7df0238a39c1e76b537 (diff)
downloadgsoc2013-empathy-e3e5702a683c468ccc1742515b4033f32c7d1083.tar
gsoc2013-empathy-e3e5702a683c468ccc1742515b4033f32c7d1083.tar.gz
gsoc2013-empathy-e3e5702a683c468ccc1742515b4033f32c7d1083.tar.bz2
gsoc2013-empathy-e3e5702a683c468ccc1742515b4033f32c7d1083.tar.lz
gsoc2013-empathy-e3e5702a683c468ccc1742515b4033f32c7d1083.tar.xz
gsoc2013-empathy-e3e5702a683c468ccc1742515b4033f32c7d1083.tar.zst
gsoc2013-empathy-e3e5702a683c468ccc1742515b4033f32c7d1083.zip
Initial Voice+Video support Fixes bug #468204 (Elliot Fairweather, Xavier
2007-09-29 Xavier Claessens <xclaesse@gmail.com> * libempathy-gtk/empathy-call-window.c: * libempathy-gtk/empathy-call-window.h: * libempathy-gtk/empathy-contact-list-view.c: * libempathy-gtk/empathy-call-window.glade: * libempathy-gtk/Makefile.am: * libempathy-gtk/empathy-chat-window.c: * src/empathy-call-chandler.c: * src/empathy-call.chandler: * src/org.gnome.Empathy.Call.service.in: * src/Makefile.am: * libempathy/empathy-utils.c: * libempathy/empathy-utils.h: * libempathy/empathy-tp-call.c: * libempathy/empathy-tp-call.h: * libempathy/Makefile.am: * libempathy/tp-stream-engine.xml: * configure.ac: * doc/libempathy-gtk/libempathy-gtk-docs.sgml: * doc/libempathy/libempathy.types: * doc/libempathy/libempathy-docs.sgml: * doc/libempathy/Makefile.am: * doc/libempathy/tmpl/empathy-utils.sgml: Initial Voice+Video support Fixes bug #468204 (Elliot Fairweather, Xavier Claessens). svn path=/trunk/; revision=339
Diffstat (limited to 'libempathy')
-rw-r--r--libempathy/Makefile.am9
-rw-r--r--libempathy/empathy-tp-call.c655
-rw-r--r--libempathy/empathy-tp-call.h89
-rw-r--r--libempathy/empathy-utils.c62
-rw-r--r--libempathy/empathy-utils.h1
-rw-r--r--libempathy/tp-stream-engine.xml54
6 files changed, 869 insertions, 1 deletions
diff --git a/libempathy/Makefile.am b/libempathy/Makefile.am
index 9dc4021e2..0480d0bff 100644
--- a/libempathy/Makefile.am
+++ b/libempathy/Makefile.am
@@ -34,6 +34,7 @@ libempathy_la_SOURCES = \
empathy-tp-chat.c \
empathy-tp-chatroom.c \
empathy-tp-roomlist.c \
+ empathy-tp-call.c \
empathy-chandler.c \
empathy-filter.c \
empathy-idle.c \
@@ -68,10 +69,12 @@ libempathy_headers = \
empathy-tp-chat.h \
empathy-tp-chatroom.h \
empathy-tp-roomlist.h \
+ empathy-tp-call.h \
empathy-chandler.h \
empathy-filter.h \
empathy-idle.h \
- empathy-log-manager.h
+ empathy-log-manager.h \
+ tp-stream-engine-gen.h
libempathy_includedir = $(includedir)/libempathy/
libempathy_include_HEADERS = \
@@ -90,6 +93,10 @@ empathy-chandler-glue.h: empathy-chandler.xml Makefile
empathy-filter-glue.h: empathy-filter.xml Makefile
$(LIBTOOL) --mode=execute $(DBUS_BINDING_TOOL) --prefix=empathy_filter --mode=glib-server --output=$@ $<
+tp-stream-engine-gen.h: tp-stream-engine.xml Makefile.am
+ $(LIBTOOL) --mode=execute $(DBUS_BINDING_TOOL) --prefix=tp_stream_engine --mode=glib-client --output=$@ $<
+
+
empathy-enum-types.h: stamp-empathy-enum-types.h
@true
stamp-empathy-enum-types.h: $(libempathy_headers) Makefile
diff --git a/libempathy/empathy-tp-call.c b/libempathy/empathy-tp-call.c
new file mode 100644
index 000000000..e0347ba9a
--- /dev/null
+++ b/libempathy/empathy-tp-call.c
@@ -0,0 +1,655 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2007 Elliot Fairweather
+ * Copyright (C) 2007 Collabora Ltd.
+ *
+ * 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
+ *
+ * Authors: Elliot Fairweather <elliot.fairweather@collabora.co.uk>
+ * Xavier Claessens <xclaesse@gmail.com>
+ */
+
+#include "config.h"
+
+#include <libtelepathy/tp-chan-type-streamed-media-gen.h>
+#include <libtelepathy/tp-helpers.h>
+#include <libtelepathy/tp-conn.h>
+
+#include <libmissioncontrol/mission-control.h>
+
+#include "empathy-tp-call.h"
+#include "empathy-tp-group.h"
+#include "empathy-utils.h"
+#include "empathy-debug.h"
+#include "empathy-enum-types.h"
+#include "tp-stream-engine-gen.h"
+
+#define DEBUG_DOMAIN "TpCall"
+
+#define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), EMPATHY_TYPE_TP_CALL, EmpathyTpCallPriv))
+
+#define STREAM_ENGINE_BUS_NAME "org.freedesktop.Telepathy.StreamEngine"
+#define STREAM_ENGINE_OBJECT_PATH "/org/freedesktop/Telepathy/StreamEngine"
+#define STREAM_ENGINE_INTERFACE "org.freedesktop.Telepathy.StreamEngine"
+#define CHANNEL_HANDLER_INTERFACE "org.freedesktop.Telepathy.ChannelHandler"
+
+typedef struct _EmpathyTpCallPriv EmpathyTpCallPriv;
+
+struct _EmpathyTpCallPriv {
+ TpChan *tp_chan;
+ DBusGProxy *streamed_iface;
+ DBusGProxy *se_ch_proxy;
+ DBusGProxy *se_proxy;
+ McAccount *account;
+ EmpathyTpGroup *group;
+ EmpathyContact *contact;
+ EmpathyTpCallStatus status;
+ gboolean is_incoming;
+ guint audio_stream;
+ guint video_stream;
+};
+
+static void empathy_tp_call_class_init (EmpathyTpCallClass *klass);
+static void empathy_tp_call_init (EmpathyTpCall *call);
+
+enum {
+ PROP_0,
+ PROP_ACCOUNT,
+ PROP_TP_CHAN,
+ PROP_STATUS
+};
+
+enum {
+ DESTROY,
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL];
+
+G_DEFINE_TYPE (EmpathyTpCall, empathy_tp_call, G_TYPE_OBJECT)
+
+static void
+tp_call_set_status (EmpathyTpCall *call,
+ EmpathyTpCallStatus status)
+{
+ EmpathyTpCallPriv *priv = GET_PRIV (call);
+
+ priv->status = status;
+ g_object_notify (G_OBJECT (call), "status");
+}
+
+static void
+tp_call_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ EmpathyTpCallPriv *priv = GET_PRIV (object);
+
+ switch (prop_id) {
+ case PROP_ACCOUNT:
+ priv->account = g_object_ref (g_value_get_object (value));
+ break;
+ case PROP_TP_CHAN:
+ priv->tp_chan = g_object_ref (g_value_get_object (value));
+ break;
+ case PROP_STATUS:
+ tp_call_set_status (EMPATHY_TP_CALL (object),
+ g_value_get_enum (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+tp_call_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ EmpathyTpCallPriv *priv = GET_PRIV (object);
+
+ switch (prop_id) {
+ case PROP_ACCOUNT:
+ g_value_set_object (value, priv->account);
+ break;
+ case PROP_TP_CHAN:
+ g_value_set_object (value, priv->tp_chan);
+ break;
+ case PROP_STATUS:
+ g_value_set_enum (value, priv->status);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+tp_call_destroy_cb (TpChan *call_chan,
+ EmpathyTpCall *call)
+{
+ EmpathyTpCallPriv *priv = GET_PRIV (call);
+
+ empathy_debug (DEBUG_DOMAIN, "Channel Closed or CM crashed");
+
+ g_object_unref (priv->tp_chan);
+ priv->tp_chan = NULL;
+ priv->streamed_iface = NULL;
+
+ g_signal_emit (call, signals[DESTROY], 0);
+}
+
+static void
+tp_call_closed_cb (TpChan *call_chan,
+ EmpathyTpCall *call)
+{
+ EmpathyTpCallPriv *priv = GET_PRIV (call);
+
+ /* The channel is closed, do just like if the proxy was destroyed */
+ g_signal_handlers_disconnect_by_func (priv->tp_chan,
+ tp_call_destroy_cb,
+ call);
+ tp_call_destroy_cb (call_chan, call);
+}
+
+static void
+tp_call_stream_added_cb (DBusGProxy *streamed_iface,
+ guint stream_id,
+ guint contact_handle,
+ guint stream_type,
+ EmpathyTpCall *call)
+{
+ EmpathyTpCallPriv *priv = GET_PRIV (call);
+
+ empathy_debug (DEBUG_DOMAIN, "Stream added: id=%d, stream_type=%d",
+ stream_id, stream_type);
+
+ switch (stream_type) {
+ case TP_MEDIA_STREAM_TYPE_AUDIO:
+ priv->audio_stream = stream_id;
+ break;
+ case TP_MEDIA_STREAM_TYPE_VIDEO:
+ priv->video_stream = stream_id;
+ break;
+ default:
+ empathy_debug (DEBUG_DOMAIN, "Unknown stream type: %d", stream_type);
+ }
+}
+
+
+static void
+tp_call_stream_removed_cb (DBusGProxy *streamed_iface,
+ guint stream_id,
+ EmpathyTpCall *call)
+{
+ EmpathyTpCallPriv *priv = GET_PRIV (call);
+
+ empathy_debug (DEBUG_DOMAIN, "Stream removed: %d", stream_id);
+
+ if (stream_id == priv->audio_stream) {
+ priv->audio_stream = 0;
+ }
+ else if (stream_id == priv->video_stream) {
+ priv->video_stream = 0;
+ }
+}
+
+static void
+tp_call_list_streams_cb (DBusGProxy *proxy,
+ GPtrArray *streams,
+ GError *error,
+ gpointer user_data)
+{
+ guint i;
+
+ if (error) {
+ empathy_debug (DEBUG_DOMAIN, "Failed to list streams: %s",
+ error->message);
+ return;
+ }
+
+ for (i = 0; i < streams->len; i++) {
+ GValueArray *values;
+ guint stream_id;
+ guint contact_handle;
+ guint stream_type;
+
+ values = g_ptr_array_index (streams, i);
+ stream_id = g_value_get_uint (g_value_array_get_nth (values, 0));
+ contact_handle = g_value_get_uint (g_value_array_get_nth (values, 1));
+ stream_type = g_value_get_uint (g_value_array_get_nth (values, 2));
+
+ tp_call_stream_added_cb (proxy,
+ stream_id,
+ contact_handle,
+ stream_type,
+ user_data);
+ }
+}
+
+static void
+tp_call_member_added_cb (EmpathyTpGroup *group,
+ EmpathyContact *contact,
+ EmpathyContact *actor,
+ guint reason,
+ const gchar *message,
+ EmpathyTpCall *call)
+{
+ EmpathyTpCallPriv *priv = GET_PRIV (call);
+
+ empathy_debug (DEBUG_DOMAIN, "Members added %s (%d)",
+ empathy_contact_get_id (contact),
+ empathy_contact_get_handle (contact));
+
+ if (!priv->contact) {
+ if (!empathy_contact_is_user (contact)) {
+ priv->is_incoming = TRUE;
+ priv->contact = g_object_ref (contact);
+ tp_call_set_status (call, EMPATHY_TP_CALL_STATUS_RINGING);
+ }
+ return;
+ }
+
+ /* We already have the other contact, that means we now have 2 members,
+ * so we can start the call */
+ tp_call_set_status (call, EMPATHY_TP_CALL_STATUS_RUNNING);
+}
+
+static void
+tp_call_remote_pending_cb (EmpathyTpGroup *group,
+ EmpathyContact *contact,
+ EmpathyContact *actor,
+ guint reason,
+ const gchar *message,
+ EmpathyTpCall *call)
+{
+ EmpathyTpCallPriv *priv = GET_PRIV (call);
+
+ empathy_debug (DEBUG_DOMAIN, "Remote pending: %s (%d)",
+ empathy_contact_get_id (contact),
+ empathy_contact_get_handle (contact));
+
+ if (!priv->contact) {
+ priv->is_incoming = FALSE;
+ priv->contact = g_object_ref (contact);
+ tp_call_set_status (call, EMPATHY_TP_CALL_STATUS_RINGING);
+ }
+}
+
+static void
+tp_call_async_cb (DBusGProxy *proxy,
+ GError *error,
+ gpointer user_data)
+{
+ if (error) {
+ empathy_debug (DEBUG_DOMAIN, "Failed to %s: %s",
+ user_data,
+ error->message);
+ }
+}
+
+static GObject *
+tp_call_constructor (GType type,
+ guint n_props,
+ GObjectConstructParam *props)
+{
+ GObject *call;
+ EmpathyTpCallPriv *priv;
+ TpConn *tp_conn;
+ MissionControl *mc;
+
+ call = G_OBJECT_CLASS (empathy_tp_call_parent_class)->constructor (type, n_props, props);
+ priv = GET_PRIV (call);
+
+ priv->group = empathy_tp_group_new (priv->account, priv->tp_chan);
+ priv->streamed_iface = tp_chan_get_interface (priv->tp_chan,
+ TELEPATHY_CHAN_IFACE_STREAMED_QUARK);
+
+ /* Connect signals */
+ dbus_g_proxy_connect_signal (priv->streamed_iface, "StreamAdded",
+ G_CALLBACK (tp_call_stream_added_cb),
+ call, NULL);
+ dbus_g_proxy_connect_signal (priv->streamed_iface, "StreamRemoved",
+ G_CALLBACK (tp_call_stream_removed_cb),
+ call, NULL);
+ dbus_g_proxy_connect_signal (DBUS_G_PROXY (priv->tp_chan), "Closed",
+ G_CALLBACK (tp_call_closed_cb),
+ call, NULL);
+ g_signal_connect (priv->tp_chan, "destroy",
+ G_CALLBACK (tp_call_destroy_cb),
+ call);
+ g_signal_connect (priv->group, "member-added",
+ G_CALLBACK (tp_call_member_added_cb),
+ call);
+ g_signal_connect (priv->group, "remote-pending",
+ G_CALLBACK (tp_call_remote_pending_cb),
+ call);
+
+ /* Start stream engine */
+ mc = empathy_mission_control_new ();
+ tp_conn = mission_control_get_connection (mc, priv->account, NULL);
+ priv->se_ch_proxy = dbus_g_proxy_new_for_name (tp_get_bus (),
+ STREAM_ENGINE_BUS_NAME,
+ STREAM_ENGINE_OBJECT_PATH,
+ CHANNEL_HANDLER_INTERFACE);
+ priv->se_proxy = dbus_g_proxy_new_for_name (tp_get_bus (),
+ STREAM_ENGINE_BUS_NAME,
+ STREAM_ENGINE_OBJECT_PATH,
+ STREAM_ENGINE_INTERFACE);
+ org_freedesktop_Telepathy_ChannelHandler_handle_channel_async (priv->se_ch_proxy,
+ dbus_g_proxy_get_bus_name (DBUS_G_PROXY (tp_conn)),
+ dbus_g_proxy_get_path (DBUS_G_PROXY (tp_conn)),
+ priv->tp_chan->type,
+ dbus_g_proxy_get_path (DBUS_G_PROXY (priv->tp_chan)),
+ priv->tp_chan->handle_type,
+ priv->tp_chan->handle,
+ tp_call_async_cb,
+ "handle channel");
+ g_object_unref (tp_conn);
+ g_object_unref (mc);
+
+ /* Get streams */
+ tp_chan_type_streamed_media_list_streams_async (priv->streamed_iface,
+ tp_call_list_streams_cb,
+ call);
+
+ return call;
+}
+
+static void
+tp_call_finalize (GObject *object)
+{
+ EmpathyTpCallPriv *priv = GET_PRIV (object);
+
+ empathy_debug (DEBUG_DOMAIN, "Finalizing: %p", object);
+
+ if (priv->tp_chan) {
+ GError *error;
+
+ g_signal_handlers_disconnect_by_func (priv->tp_chan,
+ tp_call_destroy_cb,
+ object);
+ empathy_debug (DEBUG_DOMAIN, "Closing channel...");
+ if (!tp_chan_close (DBUS_G_PROXY (priv->tp_chan), &error)) {
+ empathy_debug (DEBUG_DOMAIN,
+ "Error closing text channel: %s",
+ error ? error->message : "No error given");
+ g_clear_error (&error);
+ }
+ g_object_unref (priv->tp_chan);
+ }
+
+ g_object_unref (priv->group);
+ g_object_unref (priv->contact);
+ g_object_unref (priv->account);
+ g_object_unref (priv->se_ch_proxy);
+ g_object_unref (priv->se_proxy);
+
+ G_OBJECT_CLASS (empathy_tp_call_parent_class)->finalize (object);
+}
+
+static void
+empathy_tp_call_class_init (EmpathyTpCallClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->constructor = tp_call_constructor;
+ object_class->finalize = tp_call_finalize;
+ object_class->set_property = tp_call_set_property;
+ object_class->get_property = tp_call_get_property;
+
+ /* Construct-only properties */
+ g_object_class_install_property (object_class,
+ PROP_ACCOUNT,
+ g_param_spec_object ("account",
+ "channel Account",
+ "The account associated with the channel",
+ MC_TYPE_ACCOUNT,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY));
+ g_object_class_install_property (object_class,
+ PROP_TP_CHAN,
+ g_param_spec_object ("tp-chan",
+ "telepathy channel",
+ "The media channel for the call",
+ TELEPATHY_CHAN_TYPE,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY));
+
+ /* Normal properties */
+ g_object_class_install_property (object_class,
+ PROP_STATUS,
+ g_param_spec_enum ("status",
+ "call status",
+ "The status of the call",
+ EMPATHY_TYPE_TP_CALL_STATUS,
+ EMPATHY_TP_CALL_STATUS_PREPARING,
+ G_PARAM_READABLE));
+
+ /* Signals */
+ signals[DESTROY] =
+ g_signal_new ("destroy",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+
+
+ g_type_class_add_private (klass, sizeof (EmpathyTpCallPriv));
+}
+
+static void
+empathy_tp_call_init (EmpathyTpCall *call)
+{
+}
+
+EmpathyTpCall *
+empathy_tp_call_new (McAccount *account, TpChan *channel)
+{
+ return g_object_new (EMPATHY_TYPE_TP_CALL,
+ "account", account,
+ "tp_chan", channel,
+ NULL);
+}
+
+gboolean
+empathy_tp_call_is_incoming (EmpathyTpCall *call)
+{
+ EmpathyTpCallPriv *priv = GET_PRIV (call);
+
+ return priv->is_incoming;
+}
+
+EmpathyTpCallStatus
+empathy_tp_call_get_status (EmpathyTpCall *call)
+{
+ EmpathyTpCallPriv *priv = GET_PRIV (call);
+
+ return priv->status;
+}
+
+EmpathyContact *
+empathy_tp_call_get_contact (EmpathyTpCall *call)
+{
+ EmpathyTpCallPriv *priv = GET_PRIV (call);
+
+ return priv->contact;
+}
+
+void
+empathy_tp_call_accept (EmpathyTpCall *call)
+{
+ EmpathyTpCallPriv *priv = GET_PRIV (call);
+ EmpathyContact *contact;
+
+ contact = empathy_tp_group_get_self_contact (priv->group);
+ empathy_tp_group_add_member (priv->group, contact, "");
+}
+
+void
+empathy_tp_call_invite (EmpathyTpCall *call,
+ EmpathyContact *contact)
+{
+ EmpathyTpCallPriv *priv = GET_PRIV (call);
+
+ empathy_tp_group_add_member (priv->group, contact, "you're welcome");
+}
+
+void
+empathy_tp_call_request_streams (EmpathyTpCall *call,
+ gboolean audio,
+ gboolean video)
+{
+ EmpathyTpCallPriv *priv = GET_PRIV (call);
+ GArray *stream_types;
+ guint handle;
+ guint type;
+
+ empathy_debug (DEBUG_DOMAIN, "Requesting streams for audio=%s video=%s",
+ audio ? "Yes" : "No",
+ video ? "Yes" : "No");
+
+ stream_types = g_array_new (FALSE, FALSE, sizeof (guint));
+ if (audio) {
+ type = TP_MEDIA_STREAM_TYPE_AUDIO;
+ g_array_append_val (stream_types, type);
+ }
+ if (video) {
+ type = TP_MEDIA_STREAM_TYPE_VIDEO;
+ g_array_append_val (stream_types, type);
+ }
+
+ handle = empathy_contact_get_handle (priv->contact);
+ tp_chan_type_streamed_media_request_streams_async (priv->streamed_iface,
+ handle,
+ stream_types,
+ tp_call_list_streams_cb,
+ call);
+
+ g_array_free (stream_types, TRUE);
+}
+
+void
+empathy_tp_call_send_video (EmpathyTpCall *call,
+ gboolean send)
+{
+ EmpathyTpCallPriv *priv = GET_PRIV (call);
+ guint new_direction;
+
+ if (!priv->video_stream) {
+ return;
+ }
+
+ if (send) {
+ new_direction = TP_MEDIA_STREAM_DIRECTION_BIDIRECTIONAL;
+ } else {
+ new_direction = TP_MEDIA_STREAM_DIRECTION_RECEIVE;
+ }
+
+ tp_chan_type_streamed_media_request_stream_direction_async (priv->streamed_iface,
+ priv->video_stream,
+ new_direction,
+ tp_call_async_cb,
+ "request stream direction");
+}
+
+void
+empathy_tp_call_add_preview_window (EmpathyTpCall *call,
+ guint socket_id)
+{
+ EmpathyTpCallPriv *priv = GET_PRIV (call);
+
+ org_freedesktop_Telepathy_StreamEngine_add_preview_window_async (priv->se_proxy,
+ socket_id,
+ tp_call_async_cb,
+ "add preview window");
+}
+
+void
+empathy_tp_call_remove_preview_window (EmpathyTpCall *call,
+ guint socket_id)
+{
+ EmpathyTpCallPriv *priv = GET_PRIV (call);
+
+ org_freedesktop_Telepathy_StreamEngine_remove_preview_window_async (priv->se_proxy,
+ socket_id,
+ tp_call_async_cb,
+ "remove preview window");
+}
+
+void
+empathy_tp_call_set_output_window (EmpathyTpCall *call,
+ guint socket_id)
+{
+ EmpathyTpCallPriv *priv = GET_PRIV (call);
+
+ org_freedesktop_Telepathy_StreamEngine_set_output_window_async (priv->se_proxy,
+ dbus_g_proxy_get_path (DBUS_G_PROXY (priv->tp_chan)),
+ priv->video_stream,
+ socket_id,
+ tp_call_async_cb,
+ "set output window");
+}
+
+void
+empathy_tp_call_set_output_volume (EmpathyTpCall *call,
+ guint volume)
+{
+ EmpathyTpCallPriv *priv = GET_PRIV (call);
+
+ org_freedesktop_Telepathy_StreamEngine_set_output_volume_async (priv->se_proxy,
+ dbus_g_proxy_get_path (DBUS_G_PROXY (priv->tp_chan)),
+ priv->audio_stream,
+ volume,
+ tp_call_async_cb,
+ "set output volume");
+}
+
+
+void
+empathy_tp_call_mute_output (EmpathyTpCall *call,
+ gboolean is_muted)
+{
+ EmpathyTpCallPriv *priv = GET_PRIV (call);
+
+ org_freedesktop_Telepathy_StreamEngine_mute_output_async (priv->se_proxy,
+ dbus_g_proxy_get_path (DBUS_G_PROXY (priv->tp_chan)),
+ priv->audio_stream,
+ is_muted,
+ tp_call_async_cb,
+ "mute output");
+}
+
+
+void
+empathy_tp_call_mute_input (EmpathyTpCall *call,
+ gboolean is_muted)
+{
+ EmpathyTpCallPriv *priv = GET_PRIV (call);
+
+ org_freedesktop_Telepathy_StreamEngine_mute_input_async (priv->se_proxy,
+ dbus_g_proxy_get_path (DBUS_G_PROXY (priv->tp_chan)),
+ priv->audio_stream,
+ is_muted,
+ tp_call_async_cb,
+ "mute output");
+}
+
diff --git a/libempathy/empathy-tp-call.h b/libempathy/empathy-tp-call.h
new file mode 100644
index 000000000..13ab33fcb
--- /dev/null
+++ b/libempathy/empathy-tp-call.h
@@ -0,0 +1,89 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2007 Elliot Fairweather
+ * Copyright (C) 2007 Collabora Ltd.
+ *
+ * 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
+ *
+ * Authors: Elliot Fairweather <elliot.fairweather@collabora.co.uk>
+ * Xavier Claessens <xclaesse@gmail.com>
+ */
+
+#ifndef __EMPATHY_TP_CALL_H__
+#define __EMPATHY_TP_CALL_H__
+
+#include <libtelepathy/tp-chan.h>
+#include <libtelepathy/tp-constants.h>
+
+#include <libmissioncontrol/mc-account.h>
+
+#include "empathy-contact.h"
+
+G_BEGIN_DECLS
+
+#define EMPATHY_TYPE_TP_CALL (empathy_tp_call_get_type ())
+#define EMPATHY_TP_CALL(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), EMPATHY_TYPE_TP_CALL, EmpathyTpCall))
+#define EMPATHY_TP_CALL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), EMPATHY_TYPE_TP_CALL, EmpathyTpCallClass))
+#define EMPATHY_IS_TP_CALL(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), EMPATHY_TYPE_TP_CALL))
+#define EMPATHY_IS_TP_CALL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EMPATHY_TYPE_TP_CALL))
+#define EMPATHY_TP_CALL_GET_CLASS(object) (G_TYPE_INSTANCE_GET_CLASS ((object), EMPATHY_TYPE_TP_CALL, EmpathyTpCallClass))
+
+typedef struct _EmpathyTpCall EmpathyTpCall;
+typedef struct _EmpathyTpCallClass EmpathyTpCallClass;
+
+struct _EmpathyTpCall {
+ GObject parent;
+};
+
+struct _EmpathyTpCallClass {
+ GObjectClass parent_class;
+};
+
+typedef enum {
+ EMPATHY_TP_CALL_STATUS_PREPARING,
+ EMPATHY_TP_CALL_STATUS_RINGING,
+ EMPATHY_TP_CALL_STATUS_RUNNING
+} EmpathyTpCallStatus;
+
+GType empathy_tp_call_get_type (void) G_GNUC_CONST;
+EmpathyTpCall * empathy_tp_call_new (McAccount *account,
+ TpChan *tp_chan);
+gboolean empathy_tp_call_is_incoming (EmpathyTpCall *call);
+EmpathyTpCallStatus empathy_tp_call_get_status (EmpathyTpCall *call);
+EmpathyContact * empathy_tp_call_get_contact (EmpathyTpCall *call);
+void empathy_tp_call_accept (EmpathyTpCall *call);
+void empathy_tp_call_invite (EmpathyTpCall *call,
+ EmpathyContact *contact);
+void empathy_tp_call_request_streams (EmpathyTpCall *call,
+ gboolean audio,
+ gboolean video);
+void empathy_tp_call_send_video (EmpathyTpCall *call,
+ gboolean send);
+void empathy_tp_call_add_preview_window (EmpathyTpCall *call,
+ guint socket_id);
+void empathy_tp_call_remove_preview_window (EmpathyTpCall *call,
+ guint socket_id);
+void empathy_tp_call_set_output_window (EmpathyTpCall *call,
+ guint socket_id);
+void empathy_tp_call_set_output_volume (EmpathyTpCall *call,
+ guint volume);
+void empathy_tp_call_mute_output (EmpathyTpCall *call,
+ gboolean is_muted);
+void empathy_tp_call_mute_input (EmpathyTpCall *call,
+ gboolean is_muted);
+
+G_END_DECLS
+
+#endif /* __EMPATHY_TP_CALL_H__ */
diff --git a/libempathy/empathy-utils.c b/libempathy/empathy-utils.c
index e0c6cfc9d..f33d83e48 100644
--- a/libempathy/empathy-utils.c
+++ b/libempathy/empathy-utils.c
@@ -38,6 +38,7 @@
#include "empathy-debug.h"
#include "empathy-utils.h"
#include "empathy-contact-manager.h"
+#include "empathy-tp-group.h"
#define DEBUG_DOMAIN "Utils"
@@ -462,3 +463,64 @@ empathy_inspect_handle (McAccount *account,
return name;
}
+void
+empathy_call_contact (EmpathyContact *contact)
+{
+#ifdef HAVE_VOIP
+ MissionControl *mc;
+ McAccount *account;
+ TpConn *tp_conn;
+ gchar *object_path;
+ const gchar *bus_name;
+ TpChan *new_chan;
+ EmpathyTpGroup *group;
+ GError *error;
+
+ /* StreamedMedia channels must have handle=0 and handle_type=none.
+ * To call a contact we have to add him in the group interface of the
+ * channel. MissionControl will detect the channel creation and
+ * dispatch it to the VoIP chandler automatically. */
+
+ mc = empathy_mission_control_new ();
+ account = empathy_contact_get_account (contact);
+ tp_conn = mission_control_get_connection (mc, account, NULL);
+ /* FIXME: Should be async */
+ if (!tp_conn_request_channel (DBUS_G_PROXY (tp_conn),
+ TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA,
+ TP_HANDLE_TYPE_NONE,
+ 0,
+ FALSE,
+ &object_path,
+ &error)) {
+ empathy_debug (DEBUG_DOMAIN,
+ "Couldn't request channel: %s",
+ error ? error->message : "No error given");
+ g_clear_error (&error);
+ g_object_unref (mc);
+ g_object_unref (tp_conn);
+ return;
+ }
+
+ bus_name = dbus_g_proxy_get_bus_name (DBUS_G_PROXY (tp_conn));
+ new_chan = tp_chan_new (tp_get_bus (),
+ bus_name,
+ object_path,
+ TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA,
+ TP_HANDLE_TYPE_NONE,
+ 0);
+
+ /* FIXME: group is leaked, we can't unref it directly because
+ * _add_member is async so we have to wait for it to return before
+ * finalizing the group. I think EmpathyTpGroup should ref itself
+ * when it does async calls to avoid finalizing when there is calls
+ * in fligth like that we could unref it here. */
+ group = empathy_tp_group_new (account, new_chan);
+ empathy_tp_group_add_member (group, contact, "");
+
+ g_object_unref (mc);
+ g_object_unref (tp_conn);
+ g_object_unref (new_chan);
+ g_free (object_path);
+#endif
+}
+
diff --git a/libempathy/empathy-utils.h b/libempathy/empathy-utils.h
index 88d533728..587adaedc 100644
--- a/libempathy/empathy-utils.h
+++ b/libempathy/empathy-utils.h
@@ -91,6 +91,7 @@ gchar * empathy_inspect_handle (McAccount *account,
guint handle_type);
gchar * empathy_inspect_channel (McAccount *account,
TpChan *tp_chan);
+void empathy_call_contact (EmpathyContact *contact);
G_END_DECLS
#endif /* __EMPATHY_UTILS_H__ */
diff --git a/libempathy/tp-stream-engine.xml b/libempathy/tp-stream-engine.xml
new file mode 100644
index 000000000..5a8783d0e
--- /dev/null
+++ b/libempathy/tp-stream-engine.xml
@@ -0,0 +1,54 @@
+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
+<node name="/TpMediaEngine">
+ <interface name="org.freedesktop.Telepathy.ChannelHandler">
+ <method name="HandleChannel">
+ <arg direction="in" type="s" name="bus_name" />
+ <arg direction="in" type="o" name="connection" />
+ <arg direction="in" type="s" name="channel_type" />
+ <arg direction="in" type="o" name="channel" />
+ <arg direction="in" type="u" name="handle_type" />
+ <arg direction="in" type="u" name="handle" />
+ </method>
+ </interface>
+ <interface name="org.freedesktop.Telepathy.StreamEngine">
+ <method name="SetOutputVolume">
+ <arg direction="in" type="o" name="channel_path" />
+ <arg direction="in" type="u" name="stream_id" />
+ <arg direction="in" type="u" name="volume" />
+ </method>
+ <method name="MuteInput">
+ <arg direction="in" type="o" name="channel_path" />
+ <arg direction="in" type="u" name="stream_id" />
+ <arg direction="in" type="b" name="mute_state" />
+ </method>
+ <method name="MuteOutput">
+ <arg direction="in" type="o" name="channel_path" />
+ <arg direction="in" type="u" name="stream_id" />
+ <arg direction="in" type="b" name="mute_state" />
+ </method>
+ <method name="SetOutputWindow">
+ <arg direction="in" type="o" name="channel_path" />
+ <arg direction="in" type="u" name="stream_id" />
+ <arg direction="in" type="u" name="window" />
+ </method>
+ <method name="AddPreviewWindow">
+ <arg direction="in" type="u" name="window" />
+ </method>
+ <method name="RemovePreviewWindow">
+ <arg direction="in" type="u" name="window" />
+ </method>
+ <signal name="Receiving">
+ <arg type="o" name="channel_path" />
+ <arg type="u" name="stream_id" />
+ <arg type="b" name="state" />
+ </signal>
+ <signal name="StreamStateChanged">
+ <arg type="o" name="channel_path" />
+ <arg type="u" name="stream_id" />
+ <arg type="u" name="state" />
+ <arg type="u" name="direction" />
+ </signal>
+ <method name="Shutdown">
+ </method>
+ </interface>
+</node>