Index: protocols/telepathy/gossip-telepathy-group.h
===================================================================
--- protocols/telepathy/gossip-telepathy-group.h	(revision 2242)
+++ protocols/telepathy/gossip-telepathy-group.h	(working copy)
@@ -64,6 +64,7 @@
 void                  gossip_telepathy_group_remove_member   (GossipTelepathyGroup *group,
 							      guint                 handle,
 							      const gchar          *message);
+GArray *              gossip_telepathy_group_get_local_pending (GossipTelepathyGroup *group);
 GArray *              gossip_telepathy_group_get_members     (GossipTelepathyGroup *group);
 const gchar *         gossip_telepathy_group_get_name        (GossipTelepathyGroup *group);
 guint                 gossip_telepathy_group_get_self_handle (GossipTelepathyGroup *group);
Index: protocols/telepathy/gossip-telepathy.c
===================================================================
--- protocols/telepathy/gossip-telepathy.c	(revision 2242)
+++ protocols/telepathy/gossip-telepathy.c	(working copy)
@@ -38,6 +38,8 @@
 #include <libgossip/gossip-chatroom.h>
 #include <libgossip/gossip-presence.h>
 #include <libgossip/gossip-chatroom-provider.h>
+#include <libgossip/gossip-ft-provider.h>
+#include <libgossip/gossip-voip-provider.h>
 #include <libgossip/gossip-debug.h>
 #include <libgossip/gossip-message.h>
 #include <libgossip/gossip-chatroom.h>
@@ -51,6 +53,7 @@
 #include "gossip-telepathy-contacts.h"
 #include "gossip-telepathy-message.h"
 #include "gossip-telepathy-chatrooms.h"
+#include "gossip-telepathy-voip.h"
 #include "gossip-telepathy-contact-list.h"
 #include "gossip-telepathy-private.h"
 
@@ -70,6 +73,7 @@
 	GossipTelepathyContactList *contact_list;
 	GossipTelepathyChatrooms   *chatrooms;
 	GossipTelepathyMessage     *message;
+	GossipTelepathyVoip        *voip;
 };
 
 static void             gossip_telepathy_class_init              (GossipTelepathyClass         *klass);
@@ -235,9 +239,35 @@
 								  GossipAccountParam           *param,
 								  GHashTable                   *protocol_params);
 
+/* Voip */
+static void             telepathy_voip_init                      (GossipVoipProviderIface      *iface);
+static void             telepathy_voip_call                      (GossipVoipProvider             *provider,
+								  GossipContact                *contact);
+static void             telepathy_voip_accept                    (GossipVoipProvider             *provider,
+								  GossipContact                *contact);
+static void             telepathy_voip_end                       (GossipVoipProvider             *provider,
+								  GossipContact                *contact);
+static void             telepathy_voip_set_video_output          (GossipVoipProvider             *provider,
+								  GossipContact                *contact,
+								  guint                         window_id);
+static void             telepathy_voip_set_video_preview         (GossipVoipProvider             *provider,
+								  gboolean                      active,
+								  guint                         window_id);
+static void             telepathy_voip_set_output_volume         (GossipVoipProvider             *provider,
+								  GossipContact                *contact,
+								  guint                         volume);
+static void             telepathy_voip_mute_input                (GossipVoipProvider             *provider,
+								  GossipContact                *contact,
+								  gboolean                      muted);
+static void             telepathy_voip_mute_output               (GossipVoipProvider             *provider,
+								  GossipContact                *contact,
+								  gboolean                      muted);
+
 G_DEFINE_TYPE_WITH_CODE (GossipTelepathy, gossip_telepathy, GOSSIP_TYPE_PROTOCOL,
 			 G_IMPLEMENT_INTERFACE (GOSSIP_TYPE_CHATROOM_PROVIDER,
 						telepathy_chatroom_init);
+			 G_IMPLEMENT_INTERFACE (GOSSIP_TYPE_VOIP_PROVIDER,
+						telepathy_voip_init);
 			 G_IMPLEMENT_INTERFACE (GOSSIP_TYPE_FT_PROVIDER,
 						telepathy_ft_init));
 
@@ -302,6 +332,7 @@
 	priv->chatrooms = gossip_telepathy_chatrooms_init (telepathy);
 	priv->contacts = gossip_telepathy_contacts_init (telepathy);
 	priv->message = gossip_telepathy_message_init (telepathy);
+	priv->voip = gossip_telepathy_voip_init (telepathy);
 }
 
 static void
@@ -327,6 +358,7 @@
 	gossip_telepathy_chatrooms_finalize (priv->chatrooms);
 	gossip_telepathy_contacts_finalize (priv->contacts);
 	gossip_telepathy_message_finalize (priv->message);
+	gossip_telepathy_voip_finalize (priv->voip);
 
 	if (priv->tp_conn) {
 		g_signal_handlers_disconnect_by_func (priv->tp_conn,
@@ -1344,6 +1376,14 @@
 			default:
 				gossip_debug (DEBUG_DOMAIN, "Text channel Handle type unsupported");
 		}
+	}
+	else if (strcmp (channel_type, TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA) == 0)
+	{
+		gossip_telepathy_voip_newchannel (priv->voip,
+						    new_chan,
+						    object_path,
+						    priv->account,
+						    0);
 	} else {
 		gossip_debug (DEBUG_DOMAIN, "Channel type unsupported");
 	}
@@ -1626,6 +1666,191 @@
 }
 
 /*
+ * Voip
+ */
+
+static void
+telepathy_voip_init (GossipVoipProviderIface *iface)
+{
+	iface->call              = telepathy_voip_call;
+	iface->accept            = telepathy_voip_accept;
+	iface->end               = telepathy_voip_end;
+	iface->set_video_output  = telepathy_voip_set_video_output;
+	iface->set_video_preview = telepathy_voip_set_video_preview;
+	iface->set_output_volume = telepathy_voip_set_output_volume;
+	iface->mute_input        = telepathy_voip_mute_input;
+	iface->mute_output       = telepathy_voip_mute_output;
+}
+
+static void
+telepathy_voip_call (GossipVoipProvider *provider,
+		     GossipContact      *contact)
+{
+	GossipTelepathy     *telepathy;
+	GossipTelepathyPriv *priv;
+	guint                handle;
+	const gchar         *id;
+
+	gossip_debug (DEBUG_DOMAIN, "telepathy_voip_call");
+	g_return_if_fail (GOSSIP_IS_TELEPATHY (provider));
+
+	telepathy = GOSSIP_TELEPATHY (provider);
+	priv = GET_PRIV (telepathy);
+
+	id = gossip_contact_get_id (contact);
+	handle = gossip_telepathy_contacts_get_handle (priv->contacts, id);
+
+	gossip_telepathy_voip_call (priv->voip, priv->account, handle);
+}
+
+static void
+telepathy_voip_accept (GossipVoipProvider *provider,
+		GossipContact *contact)
+{
+	GossipTelepathy     *telepathy;
+	GossipTelepathyPriv *priv;
+	guint                handle;
+	const gchar         *id;
+
+	gossip_debug (DEBUG_DOMAIN, "telepathy_voip_accept");
+	g_return_if_fail (GOSSIP_IS_TELEPATHY (provider));
+
+	telepathy = GOSSIP_TELEPATHY (provider);
+	priv = GET_PRIV (telepathy);
+
+	id = gossip_contact_get_id (contact);
+	handle = gossip_telepathy_contacts_get_handle (priv->contacts, id);
+
+	gossip_telepathy_voip_accept (priv->voip, handle);
+}
+
+static void
+telepathy_voip_end (GossipVoipProvider *provider,
+		    GossipContact      *contact)
+{
+	GossipTelepathy     *telepathy;
+	GossipTelepathyPriv *priv;
+	guint                handle;
+	const gchar         *id;
+
+	gossip_debug (DEBUG_DOMAIN, "telepathy_voip_end");
+	g_return_if_fail (GOSSIP_IS_TELEPATHY (provider));
+
+	telepathy = GOSSIP_TELEPATHY (provider);
+	priv = GET_PRIV (telepathy);
+
+	id = gossip_contact_get_id (contact);
+	handle = gossip_telepathy_contacts_get_handle (priv->contacts, id);
+
+	gossip_telepathy_voip_end (priv->voip, handle);
+}
+
+void
+telepathy_voip_set_video_output (GossipVoipProvider *provider,
+				 GossipContact      *contact,
+				 guint               window_id)
+{
+	GossipTelepathy     *telepathy;
+	GossipTelepathyPriv *priv;
+	guint                handle;
+	const gchar         *id;
+
+	gossip_debug (DEBUG_DOMAIN, "telepathy_voip_set_video_output");
+	g_return_if_fail (GOSSIP_IS_TELEPATHY (provider));
+
+	telepathy = GOSSIP_TELEPATHY (provider);
+	priv = GET_PRIV (telepathy);
+
+	id = gossip_contact_get_id (contact);
+	handle = gossip_telepathy_contacts_get_handle (priv->contacts, id);
+	gossip_telepathy_voip_set_video_output (priv->voip, handle, window_id);
+}
+
+void
+telepathy_voip_set_video_preview (GossipVoipProvider *provider,
+					gboolean          active,
+					guint             window_id)
+{
+	GossipTelepathy     *telepathy;
+	GossipTelepathyPriv *priv;
+
+	gossip_debug (DEBUG_DOMAIN, "telepathy_voip_set_video_preview");
+	g_return_if_fail (GOSSIP_IS_TELEPATHY (provider));
+
+	telepathy = GOSSIP_TELEPATHY (provider);
+	priv = GET_PRIV (telepathy);
+
+	gossip_telepathy_voip_set_video_preview (priv->voip, active, window_id);
+}
+
+void
+telepathy_voip_set_output_volume (GossipVoipProvider *provider,
+					GossipContact    *contact,
+					guint             volume)
+{
+	GossipTelepathy     *telepathy;
+	GossipTelepathyPriv *priv;
+	guint                handle;
+	const gchar         *id;
+
+	gossip_debug (DEBUG_DOMAIN, "telepathy_voip_set_output_volume");
+	g_return_if_fail (GOSSIP_IS_TELEPATHY (provider));
+
+	telepathy = GOSSIP_TELEPATHY (provider);
+	priv = GET_PRIV (telepathy);
+
+	id = gossip_contact_get_id (contact);
+	handle = gossip_telepathy_contacts_get_handle (priv->contacts, id);
+
+	gossip_telepathy_voip_set_output_volume (priv->voip, handle, volume);
+}
+
+void
+telepathy_voip_mute_input (GossipVoipProvider *provider,
+			   GossipContact      *contact,
+			   gboolean            muted)
+{
+	GossipTelepathy     *telepathy;
+	GossipTelepathyPriv *priv;
+	guint                handle;
+	const gchar         *id;
+
+	gossip_debug (DEBUG_DOMAIN, "telepathy_voip_mute_input");
+	g_return_if_fail (GOSSIP_IS_TELEPATHY (provider));
+
+	telepathy = GOSSIP_TELEPATHY (provider);
+	priv = GET_PRIV (telepathy);
+
+
+	id = gossip_contact_get_id (contact);
+	handle = gossip_telepathy_contacts_get_handle (priv->contacts, id);
+
+	gossip_telepathy_voip_mute_input (priv->voip, handle, muted);
+}
+
+void
+telepathy_voip_mute_output (GossipVoipProvider *provider,
+			    GossipContact      *contact,
+			    gboolean            muted)
+{
+	GossipTelepathy     *telepathy;
+	GossipTelepathyPriv *priv;
+	guint                handle;
+	const gchar         *id;
+
+	gossip_debug (DEBUG_DOMAIN, "telepathy_voip_mute_output");
+	g_return_if_fail (GOSSIP_IS_TELEPATHY (provider));
+
+	telepathy = GOSSIP_TELEPATHY (provider);
+	priv = GET_PRIV (telepathy);
+
+	id = gossip_contact_get_id (contact);
+	handle = gossip_telepathy_contacts_get_handle (priv->contacts, id);
+
+	gossip_telepathy_voip_mute_output (priv->voip, handle, muted);
+}
+
+/*
  * External functions
  */
 
Index: protocols/telepathy/gossip-telepathy-contacts.c
===================================================================
--- protocols/telepathy/gossip-telepathy-contacts.c	(revision 2242)
+++ protocols/telepathy/gossip-telepathy-contacts.c	(working copy)
@@ -26,6 +26,7 @@
 #include <libtelepathy/tp-conn-iface-aliasing-gen.h>
 #include <libtelepathy/tp-conn-iface-presence-gen.h>
 #include <libtelepathy/tp-conn-iface-avatars-gen.h>
+#include <libtelepathy/tp-conn-iface-capabilities-gen.h>
 
 #include <libgossip/gossip-account.h>
 #include <libgossip/gossip-debug.h>
@@ -43,6 +44,7 @@
 	DBusGProxy      *aliasing_iface;
 	DBusGProxy      *avatars_iface;
 	DBusGProxy      *presence_iface;
+	DBusGProxy      *capabilities_iface;
 
 	GHashTable      *contacts;
 };
@@ -97,6 +99,13 @@
 							    gchar                               **contact_names,
 							    GError                               *error,
 							    TelepathyContactsAliasesRequestData  *data);
+static void     telepathy_contacts_get_capabilities_cb     (DBusGProxy                           *proxy,
+								GPtrArray                            *capabilities,
+								GError                               *error,
+								GossipTelepathyContacts              *contacts);
+static void     telepathy_contacts_capabilities_changed_cb (DBusGProxy                           *proxy,
+								GPtrArray                            *capabilities,
+								GossipTelepathyContacts              *contacts);
 static void     telepathy_contacts_presence_update_cb      (DBusGProxy                           *proxy,
 							    GHashTable                           *handle_table,
 							    GossipTelepathyContacts              *contacts);
@@ -157,6 +166,7 @@
 	contacts->aliasing_iface = NULL;
 	contacts->avatars_iface = NULL;
 	contacts->presence_iface = NULL;
+	contacts->capabilities_iface = NULL;
 }
 
 void
@@ -173,6 +183,8 @@
 							 TELEPATHY_CONN_IFACE_AVATARS_QUARK);
 	contacts->presence_iface = tp_conn_get_interface (tp_conn,
 							  TELEPATHY_CONN_IFACE_PRESENCE_QUARK);
+	contacts->capabilities_iface = tp_conn_get_interface (tp_conn,
+							  TELEPATHY_CONN_IFACE_CAPABILITIES_QUARK);
 
 	if (contacts->aliasing_iface) {
 		dbus_g_proxy_connect_signal (contacts->aliasing_iface,
@@ -194,6 +206,51 @@
 					     G_CALLBACK (telepathy_contacts_presence_update_cb),
 					     contacts, NULL);
 	}
+
+	if (contacts->capabilities_iface) {
+		GPtrArray   *adv_add;
+		GValueArray *adv_add_values;
+		GValue       adv_chan_type = { 0, };
+		GValue       adv_chan_capabilities = { 0, };
+		const char  *adv_rem[1] = {NULL};
+		GError      *error = NULL;
+
+		dbus_g_proxy_connect_signal (contacts->capabilities_iface,
+					     "CapabilitiesChanged",
+					     G_CALLBACK (telepathy_contacts_capabilities_changed_cb),
+					     contacts, NULL);
+
+		g_value_init (&adv_chan_type, G_TYPE_STRING);
+		g_value_init (&adv_chan_capabilities, G_TYPE_UINT);
+
+		g_value_set_string (&adv_chan_type,
+				TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA);
+		g_value_set_uint (&adv_chan_capabilities,
+				TP_CHANNEL_MEDIA_CAPABILITY_AUDIO|TP_CHANNEL_MEDIA_CAPABILITY_VIDEO);
+
+		adv_add_values = g_value_array_new (2);
+		g_value_array_append (adv_add_values, &adv_chan_type);
+		g_value_array_append (adv_add_values, &adv_chan_capabilities);
+
+		adv_add = g_ptr_array_new ();
+		g_ptr_array_add (adv_add, (gpointer) adv_add_values);
+
+		gossip_debug (DEBUG_DOMAIN, "Advertising capabilities: audio+video");
+		if (!tp_conn_iface_capabilities_advertise_capabilities (contacts->capabilities_iface,
+					    adv_add,
+					    adv_rem,
+					    NULL,
+					    &error))
+		{
+			gossip_debug (DEBUG_DOMAIN, "Couldn't advertise capabilities: %s", error->message);
+			g_clear_error (&error);
+		}
+
+		g_value_unset (&adv_chan_type);
+		g_value_unset (&adv_chan_capabilities);
+		g_value_array_free (adv_add_values);
+		g_ptr_array_free (adv_add, TRUE);
+	}
 }
 
 GossipContact *
@@ -678,6 +735,14 @@
 			telepathy_contacts_request_avatar (contacts, handle);
 		}
 	}
+
+	if (contacts->capabilities_iface) {
+		tp_conn_iface_capabilities_get_capabilities_async (contacts->capabilities_iface,
+							      handles,
+							      (tp_conn_iface_capabilities_get_capabilities_reply)
+							      telepathy_contacts_get_capabilities_cb,
+							      contacts);
+	}
 }
 
 static void
@@ -946,3 +1011,82 @@
 	return NULL;
 }
 
+static void
+telepathy_contacts_capabilities_update_contact (GossipTelepathyContacts *contacts,
+					    guint                                            handle,
+					    const gchar                                     *channel_type,
+					    guint                                            generic,
+					    guint                                            specific)
+{
+	GossipContactCapabilities capabilities = 0;
+	GossipContact            *contact;
+
+	contact = gossip_telepathy_contacts_get_from_handle (contacts, handle);
+	gossip_debug (DEBUG_DOMAIN, "Contact capabilities updating: %s old=%d", gossip_contact_get_name (contact), gossip_contact_get_capabilities (contact));
+
+	if (strcmp (channel_type, TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA) == 0)
+	{
+		if (specific & TP_CHANNEL_MEDIA_CAPABILITY_AUDIO)
+			capabilities |= GOSSIP_CONTACT_CAPABILITY_AUDIO;
+		if (specific & TP_CHANNEL_MEDIA_CAPABILITY_VIDEO)
+			capabilities |= GOSSIP_CONTACT_CAPABILITY_VIDEO;
+
+		gossip_debug (DEBUG_DOMAIN, "Contact capabilities set_capa: %s new=%d", gossip_contact_get_name (contact), capabilities);
+		gossip_contact_set_capabilities (contact, capabilities);
+		gossip_debug (DEBUG_DOMAIN, "Contact capabilities set_capa done: %s new=%d", gossip_contact_get_name (contact), gossip_contact_get_capabilities(contact));
+	}
+}
+
+static void
+telepathy_contacts_capabilities_changed_cb (DBusGProxy      *proxy,
+					    GPtrArray               *capabilities,
+					    GossipTelepathyContacts *contacts)
+{
+	guint i;
+
+	for (i = 0; i < capabilities->len; i++)
+	{
+		GValueArray *values = (GValueArray *) g_ptr_array_index (capabilities, i);
+		guint handle        = g_value_get_uint   (g_value_array_get_nth (values, 0));
+		const gchar *channel_type = g_value_get_string (g_value_array_get_nth (values, 1));
+		guint new_generic   = g_value_get_uint   (g_value_array_get_nth (values, 3));
+		guint new_specific  = g_value_get_uint   (g_value_array_get_nth (values, 5));
+
+		gossip_debug (DEBUG_DOMAIN, "Contact capabilities changed_cb: %s", channel_type);
+		telepathy_contacts_capabilities_update_contact (contacts,
+				handle,
+				channel_type,
+				new_generic,
+				new_specific);
+	}
+}
+
+static void
+telepathy_contacts_get_capabilities_cb (DBusGProxy       *proxy,
+					    GPtrArray                        *capabilities,
+					    GError                           *error,
+					    GossipTelepathyContacts          *contacts)
+{
+	guint i;
+
+	if (error != NULL) {
+		gossip_debug (DEBUG_DOMAIN, "Error while getting capabilites: %s", error->message);
+		return;
+	}
+
+	for (i = 0; i < capabilities->len; i++)
+	{
+		GValueArray *values = (GValueArray *) g_ptr_array_index (capabilities, i);
+		guint handle        = g_value_get_uint   (g_value_array_get_nth (values, 0));
+		const gchar *channel_type = g_value_get_string (g_value_array_get_nth (values, 1));
+		guint generic       = g_value_get_uint   (g_value_array_get_nth (values, 2));
+		guint specific      = g_value_get_uint   (g_value_array_get_nth (values, 3));
+
+		gossip_debug (DEBUG_DOMAIN, "Contact capabilities get_cb: %s", channel_type);
+		telepathy_contacts_capabilities_update_contact (contacts,
+				handle,
+				channel_type,
+				generic,
+				specific);
+	}
+}
Index: protocols/telepathy/gossip-telepathy-marshal.list
===================================================================
--- protocols/telepathy/gossip-telepathy-marshal.list	(revision 2242)
+++ protocols/telepathy/gossip-telepathy-marshal.list	(working copy)
@@ -1 +1,2 @@
 VOID:POINTER,UINT,UINT,STRING
+VOID:STRING,UINT,BOOLEAN
Index: protocols/telepathy/Makefile.am
===================================================================
--- protocols/telepathy/Makefile.am	(revision 2242)
+++ protocols/telepathy/Makefile.am	(working copy)
@@ -5,6 +5,14 @@
 	$(GOSSIP_TELEPATHY_CFLAGS) 		\
 	$(WARN_CFLAGS)
 
+dbus_binding_sources = stream-engine.xml
+
+stream-engine-glue.h: $(dbus_binding_sources)
+	$(LIBTOOL) --mode=execute $(DBUSBINDINGTOOL) --prefix=stream_engine \
+	--mode=glib-client --output=stream-engine-glue.h $(dbus_binding_sources)
+
+dbus_generated = stream-engine-glue.h
+
 noinst_LTLIBRARIES = libgossip-telepathy.la
 
 libgossip_telepathy_la_LIBADD = $(GOSSIP_TELEPATHY_LIBS)
@@ -17,6 +25,7 @@
 	gossip-telepathy-chatrooms.c		gossip-telepathy-chatrooms.h	\
 	gossip-telepathy-contact-list.c		gossip-telepathy-contact-list.h	\
 	gossip-telepathy-cmgr.c			gossip-telepathy-cmgr.h		\
+	gossip-telepathy-voip.c			gossip-telepathy-voip.h	\
 	gossip-telepathy-private.h						\
 	gossip-telepathy-marshal-main.c
 
@@ -34,11 +43,13 @@
 
 gossip-telepathy-marshal-main.c: gossip-telepathy-marshal.c gossip-telepathy-marshal.h
 
-BUILT_SOURCES = \
-	gossip-telepathy-marshal.h \
-	gossip-telepathy-marshal.c
+BUILT_SOURCES = 					\
+	gossip-telepathy-marshal.h		\
+	gossip-telepathy-marshal.c		\
+	$(dbus_generated)
 
 EXTRA_DIST = \
+	$(dbus_binding_sources) \
 	gossip-telepathy-marshal.list
 
 CLEANFILES = $(BUILT_SOURCES)
Index: protocols/telepathy/gossip-telepathy-group.c
===================================================================
--- protocols/telepathy/gossip-telepathy-group.c	(revision 2242)
+++ protocols/telepathy/gossip-telepathy-group.c	(working copy)
@@ -362,6 +362,28 @@
 	return members;
 }
 
+GArray *
+gossip_telepathy_group_get_local_pending (GossipTelepathyGroup *group)
+{
+	GossipTelepathyGroupPriv *priv;
+	GArray                   *members;
+	GError                   *error = NULL;
+
+	g_return_val_if_fail (GOSSIP_IS_TELEPATHY_GROUP (group), NULL);
+
+	priv = GET_PRIV (group);
+
+	if (!tp_chan_iface_group_get_local_pending_members (priv->group_iface,
+					      &members,
+					      &error)) {
+		gossip_debug (DEBUG_DOMAIN, "Couldn't get local pending members: %s",
+			      error->message);
+		g_clear_error (&error);
+		return NULL;
+	}
+
+	return members;
+}
 static void
 telepathy_group_destroy_cb (DBusGProxy           *proxy,
 			    GossipTelepathyGroup *group)
