# HG changeset patch
# Node ID b6a26c6f9f1f
# Parent  d2a2cc448987
diff --git a/libpurple/media.c b/libpurple/media.c
--- a/libpurple/media.c
+++ b/libpurple/media.c
@@ -27,7 +27,6 @@
 
 #include "debug.h"
 
-#include "media/backend-fs2.h"
 #include "media-gst.h"
 
 #ifdef USE_VV
@@ -520,11 +519,8 @@
 purple_media_get_src(PurpleMedia *media, const gchar *sess_id)
 {
 	g_return_val_if_fail(PURPLE_IS_MEDIA(media), NULL);
-	g_return_val_if_fail(PURPLE_MEDIA_IS_BACKEND_FS2(media->priv->backend),
-	                     NULL);
 
-	return purple_media_backend_fs2_get_src(
-	        PURPLE_MEDIA_BACKEND_FS2(media->priv->backend), sess_id);
+	return NULL;
 }
 #endif /* USE_VV */
 
@@ -1341,12 +1337,6 @@
 {
 #ifdef USE_VV
 	g_return_if_fail(PURPLE_IS_MEDIA(media));
-	g_return_if_fail(PURPLE_MEDIA_IS_BACKEND_FS2(media->priv->backend));
-
-	purple_media_backend_fs2_set_input_volume(
-			PURPLE_MEDIA_BACKEND_FS2(
-			media->priv->backend),
-			session_id, level);
 #endif
 }
 
@@ -1356,12 +1346,6 @@
 {
 #ifdef USE_VV
 	g_return_if_fail(PURPLE_IS_MEDIA(media));
-	g_return_if_fail(PURPLE_MEDIA_IS_BACKEND_FS2(media->priv->backend));
-
-	purple_media_backend_fs2_set_output_volume(
-			PURPLE_MEDIA_BACKEND_FS2(
-			media->priv->backend),
-			session_id, participant, level);
 #endif
 }
 
@@ -1407,12 +1391,8 @@
 		const gchar *session_id, const gchar *participant)
 {
 	g_return_val_if_fail(PURPLE_IS_MEDIA(media), NULL);
-	g_return_val_if_fail(PURPLE_MEDIA_IS_BACKEND_FS2(media->priv->backend),
-	                     NULL);
 
-	return purple_media_backend_fs2_get_tee(
-	        PURPLE_MEDIA_BACKEND_FS2(media->priv->backend),
-	        session_id, participant);
+	return NULL;
 }
 #endif /* USE_VV */
 
diff --git a/libpurple/media/backend-fs2.h b/libpurple/media/backend-fs2.h
deleted file mode 100644
--- a/libpurple/media/backend-fs2.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/* purple
- *
- * Purple is the legal property of its developers, whose names are too numerous
- * to list here.  Please refer to the COPYRIGHT file distributed with this
- * source distribution.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
- */
-
-#if !defined(PURPLE_GLOBAL_HEADER_INSIDE) && !defined(PURPLE_COMPILATION)
-# error "only <purple.h> may be included directly"
-#endif
-
-#ifndef PURPLE_MEDIA_BACKEND_FS2_H
-#define PURPLE_MEDIA_BACKEND_FS2_H
-
-#include <glib-object.h>
-
-G_BEGIN_DECLS
-
-#define PURPLE_MEDIA_TYPE_BACKEND_FS2  purple_media_backend_fs2_get_type()
-
-/**
- * purple_media_backend_fs2_get_type:
- *
- * Gets the type of the Farstream media backend object.
- *
- * Returns: The Farstream media backend's GType
- */
-G_DECLARE_FINAL_TYPE(PurpleMediaBackendFs2, purple_media_backend_fs2,
-                     PURPLE_MEDIA, BACKEND_FS2, GObject)
-
-/*
- * Temporary function in order to be able to test while
- * integrating with PurpleMedia
- */
-#include <gst/gst.h>
-GstElement *purple_media_backend_fs2_get_src(
-		PurpleMediaBackendFs2 *self,
-		const gchar *sess_id);
-GstElement *purple_media_backend_fs2_get_tee(
-		PurpleMediaBackendFs2 *self,
-		const gchar *sess_id, const gchar *who);
-void purple_media_backend_fs2_set_input_volume(PurpleMediaBackendFs2 *self,
-		const gchar *sess_id, double level);
-void purple_media_backend_fs2_set_output_volume(PurpleMediaBackendFs2 *self,
-		const gchar *sess_id, const gchar *who, double level);
-/* end tmp */
-
-G_END_DECLS
-
-#endif /* PURPLE_MEDIA_BACKEND_FS2_H */
diff --git a/libpurple/media/backend-fs2.c b/libpurple/media/backend-fs2.c
deleted file mode 100644
--- a/libpurple/media/backend-fs2.c
+++ /dev/null
@@ -1,2676 +0,0 @@
-/* purple
- *
- * Purple is the legal property of its developers, whose names are too numerous
- * to list here.  Please refer to the COPYRIGHT file distributed with this
- * source distribution.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
- */
-
-#include <glib/gi18n-lib.h>
-
-#include "internal.h"
-
-#include "backend-fs2.h"
-
-#ifdef USE_VV
-#include "backend-iface.h"
-#include "debug.h"
-#include "network.h"
-#include "media-gst.h"
-#include <libpurple/purplepath.h>
-#include <libpurple/purplekeyvaluepair.h>
-
-/* Ignore deprecations of GParameter in FarStream's headers. */
-G_GNUC_BEGIN_IGNORE_DEPRECATIONS
-#include <farstream/fs-conference.h>
-G_GNUC_END_IGNORE_DEPRECATIONS
-#include <farstream/fs-element-added-notifier.h>
-#include <farstream/fs-utils.h>
-#include <gst/gststructure.h>
-
-/** @copydoc _PurpleMediaBackendFs2Session */
-typedef struct _PurpleMediaBackendFs2Session PurpleMediaBackendFs2Session;
-/** @copydoc _PurpleMediaBackendFs2Stream */
-typedef struct _PurpleMediaBackendFs2Stream PurpleMediaBackendFs2Stream;
-
-static void purple_media_backend_iface_init(PurpleMediaBackendInterface *iface);
-
-static gboolean
-gst_bus_cb(GstBus *bus, GstMessage *msg, PurpleMediaBackendFs2 *self);
-static void
-state_changed_cb(PurpleMedia *media, PurpleMediaState state,
-		gchar *sid, gchar *name, PurpleMediaBackendFs2 *self);
-static void
-stream_info_cb(PurpleMedia *media, PurpleMediaInfoType type,
-		gchar *sid, gchar *name, gboolean local,
-		PurpleMediaBackendFs2 *self);
-
-static gboolean purple_media_backend_fs2_add_stream(PurpleMediaBackend *self,
-		const gchar *sess_id, const gchar *who,
-		PurpleMediaSessionType type, gboolean initiator,
-		const gchar *transmitter, GHashTable *params);
-static void purple_media_backend_fs2_add_remote_candidates(
-		PurpleMediaBackend *self,
-		const gchar *sess_id, const gchar *participant,
-		GList *remote_candidates);
-static gboolean purple_media_backend_fs2_codecs_ready(PurpleMediaBackend *self,
-		const gchar *sess_id);
-static GList *purple_media_backend_fs2_get_codecs(PurpleMediaBackend *self,
-		const gchar *sess_id);
-static GList *purple_media_backend_fs2_get_local_candidates(
-		PurpleMediaBackend *self,
-		const gchar *sess_id, const gchar *participant);
-static gboolean purple_media_backend_fs2_set_encryption_parameters (
-		PurpleMediaBackend *self, const gchar *sess_id, const gchar *cipher,
-		const gchar *auth, const gchar *key, gsize key_len);
-static gboolean purple_media_backend_fs2_set_decryption_parameters(
-		PurpleMediaBackend *self, const gchar *sess_id,
-		const gchar *participant, const gchar *cipher,
-		const gchar *auth, const gchar *key, gsize key_len);
-static gboolean purple_media_backend_fs2_set_require_encryption(
-		PurpleMediaBackend *self, const gchar *sess_id,
-		const gchar *participant, gboolean require_encryption);
-static gboolean purple_media_backend_fs2_set_remote_codecs(
-		PurpleMediaBackend *self,
-		const gchar *sess_id, const gchar *participant,
-		GList *codecs);
-static gboolean purple_media_backend_fs2_set_send_codec(
-		PurpleMediaBackend *self, const gchar *sess_id,
-		PurpleMediaCodec *codec);
-static void purple_media_backend_fs2_set_params(PurpleMediaBackend *self,
-		GHashTable *params);
-static const gchar **purple_media_backend_fs2_get_available_params(void);
-static gboolean purple_media_backend_fs2_send_dtmf(
-		PurpleMediaBackend *self, const gchar *sess_id,
-		gchar dtmf, guint8 volume, guint16 duration);
-static gboolean purple_media_backend_fs2_set_send_rtcp_mux(
-		PurpleMediaBackend *self,
-		const gchar *sess_id, const gchar *participant,
-		gboolean send_rtcp_mux);
-
-static void free_stream(PurpleMediaBackendFs2Stream *stream);
-static void free_session(PurpleMediaBackendFs2Session *session);
-
-/**
- * PurpleMediaBackendFs2:
- *
- * An opaque structure representing the Farstream media backend.
- */
-struct _PurpleMediaBackendFs2
-{
-	GObject parent;
-};
-
-struct _PurpleMediaBackendFs2Stream
-{
-	PurpleMediaBackendFs2Session *session;
-	gchar *participant;
-	FsStream *stream;
-
-	gboolean supports_add;
-
-	GstElement *src;
-	GstElement *tee;
-	GstElement *volume;
-	GstElement *level;
-	GstElement *fakesink;
-	GstElement *queue;
-
-	GList *local_candidates;
-	GList *remote_candidates;
-
-	guint connected_cb_id;
-};
-
-struct _PurpleMediaBackendFs2Session
-{
-	PurpleMediaBackendFs2 *backend;
-	gchar *id;
-	FsSession *session;
-
-	GstElement *src;
-	GstElement *tee;
-	GstElement *srcvalve;
-
-	GstPad *srcpad;
-
-	PurpleMediaSessionType type;
-};
-
-typedef struct
-{
-	PurpleMedia *media;
-	GstElement *confbin;
-	FsConference *conference;
-	gchar *conference_type;
-
-	FsElementAddedNotifier *notifier;
-
-	GHashTable *sessions;
-	GHashTable *participants;
-
-	GList *streams;
-
-	gdouble silence_threshold;
-} PurpleMediaBackendFs2Private;
-
-enum {
-	PROP_0,
-	PROP_CONFERENCE_TYPE,
-	PROP_MEDIA,
-};
-
-G_DEFINE_TYPE_WITH_CODE(PurpleMediaBackendFs2, purple_media_backend_fs2,
-		G_TYPE_OBJECT,
-		G_ADD_PRIVATE(PurpleMediaBackendFs2)
-		G_IMPLEMENT_INTERFACE(PURPLE_MEDIA_TYPE_BACKEND,
-				purple_media_backend_iface_init));
-
-static void
-purple_media_backend_fs2_init(PurpleMediaBackendFs2 *self)
-{
-}
-
-static FsCandidateType
-purple_media_candidate_type_to_fs(PurpleMediaCandidateType type)
-{
-	switch (type) {
-		case PURPLE_MEDIA_CANDIDATE_TYPE_HOST:
-			return FS_CANDIDATE_TYPE_HOST;
-		case PURPLE_MEDIA_CANDIDATE_TYPE_SRFLX:
-			return FS_CANDIDATE_TYPE_SRFLX;
-		case PURPLE_MEDIA_CANDIDATE_TYPE_PRFLX:
-			return FS_CANDIDATE_TYPE_PRFLX;
-		case PURPLE_MEDIA_CANDIDATE_TYPE_RELAY:
-			return FS_CANDIDATE_TYPE_RELAY;
-		case PURPLE_MEDIA_CANDIDATE_TYPE_MULTICAST:
-			return FS_CANDIDATE_TYPE_MULTICAST;
-	}
-	g_return_val_if_reached(FS_CANDIDATE_TYPE_HOST);
-}
-
-static PurpleMediaCandidateType
-purple_media_candidate_type_from_fs(FsCandidateType type)
-{
-	switch (type) {
-		case FS_CANDIDATE_TYPE_HOST:
-			return PURPLE_MEDIA_CANDIDATE_TYPE_HOST;
-		case FS_CANDIDATE_TYPE_SRFLX:
-			return PURPLE_MEDIA_CANDIDATE_TYPE_SRFLX;
-		case FS_CANDIDATE_TYPE_PRFLX:
-			return PURPLE_MEDIA_CANDIDATE_TYPE_PRFLX;
-		case FS_CANDIDATE_TYPE_RELAY:
-			return PURPLE_MEDIA_CANDIDATE_TYPE_RELAY;
-		case FS_CANDIDATE_TYPE_MULTICAST:
-			return PURPLE_MEDIA_CANDIDATE_TYPE_MULTICAST;
-	}
-	g_return_val_if_reached(PURPLE_MEDIA_CANDIDATE_TYPE_HOST);
-}
-
-static FsNetworkProtocol
-purple_media_network_protocol_to_fs(PurpleMediaNetworkProtocol protocol)
-{
-	switch (protocol) {
-		case PURPLE_MEDIA_NETWORK_PROTOCOL_UDP:
-			return FS_NETWORK_PROTOCOL_UDP;
-		case PURPLE_MEDIA_NETWORK_PROTOCOL_TCP_PASSIVE:
-			return FS_NETWORK_PROTOCOL_TCP_PASSIVE;
-		case PURPLE_MEDIA_NETWORK_PROTOCOL_TCP_ACTIVE:
-			return FS_NETWORK_PROTOCOL_TCP_ACTIVE;
-		case PURPLE_MEDIA_NETWORK_PROTOCOL_TCP_SO:
-			return FS_NETWORK_PROTOCOL_TCP_SO;
-		default:
-			g_return_val_if_reached(FS_NETWORK_PROTOCOL_TCP);
-	}
-}
-
-static PurpleMediaNetworkProtocol
-purple_media_network_protocol_from_fs(FsNetworkProtocol protocol)
-{
-	switch (protocol) {
-		case FS_NETWORK_PROTOCOL_UDP:
-			return PURPLE_MEDIA_NETWORK_PROTOCOL_UDP;
-		case FS_NETWORK_PROTOCOL_TCP_PASSIVE:
-			return PURPLE_MEDIA_NETWORK_PROTOCOL_TCP_PASSIVE;
-		case FS_NETWORK_PROTOCOL_TCP_ACTIVE:
-			return PURPLE_MEDIA_NETWORK_PROTOCOL_TCP_ACTIVE;
-		case FS_NETWORK_PROTOCOL_TCP_SO:
-			return PURPLE_MEDIA_NETWORK_PROTOCOL_TCP_SO;
-		default:
-			g_return_val_if_reached(PURPLE_MEDIA_NETWORK_PROTOCOL_TCP_PASSIVE);
-	}
-}
-
-static GstPadProbeReturn
-event_probe_cb(GstPad *srcpad, GstPadProbeInfo *info, gpointer unused)
-{
-	GstEvent *event = GST_PAD_PROBE_INFO_EVENT(info);
-	if (GST_EVENT_TYPE(event) == GST_EVENT_CUSTOM_DOWNSTREAM
-		&& gst_event_has_name(event, "purple-unlink-tee")) {
-
-		const GstStructure *s = gst_event_get_structure(event);
-
-		gst_pad_unlink(srcpad, gst_pad_get_peer(srcpad));
-
-		gst_pad_remove_probe(srcpad,
-			g_value_get_ulong(gst_structure_get_value(s, "handler-id")));
-
-		if (g_value_get_boolean(gst_structure_get_value(s, "release-pad")))
-			gst_element_release_request_pad(GST_ELEMENT_PARENT(srcpad), srcpad);
-
-		return GST_PAD_PROBE_DROP;
-	}
-
-	return GST_PAD_PROBE_OK;
-}
-
-static void
-unlink_teepad_dynamic(GstPad *srcpad, gboolean release_pad)
-{
-	gulong id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM,
-	                              event_probe_cb, NULL, NULL);
-
-	if (GST_IS_GHOST_PAD(srcpad))
-		srcpad = gst_ghost_pad_get_target(GST_GHOST_PAD(srcpad));
-
-	gst_element_send_event(gst_pad_get_parent_element(srcpad),
-		gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM,
-			gst_structure_new("purple-unlink-tee",
-				"release-pad", G_TYPE_BOOLEAN, release_pad,
-				"handler-id", G_TYPE_ULONG, id,
-				NULL)));
-}
-
-static void
-purple_media_backend_fs2_dispose(GObject *obj)
-{
-	PurpleMediaBackendFs2Private *priv =
-			purple_media_backend_fs2_get_instance_private(
-					PURPLE_MEDIA_BACKEND_FS2(obj));
-	GList *iter = NULL;
-
-	purple_debug_info("backend-fs2", "purple_media_backend_fs2_dispose\n");
-
-	if (priv->notifier) {
-		g_object_unref(priv->notifier);
-		priv->notifier = NULL;
-	}
-
-	if (priv->confbin) {
-		GstElement *pipeline;
-
-		pipeline = purple_media_manager_get_pipeline(
-				purple_media_get_manager(priv->media));
-
-		/* All connections to media sources should be blocked before confbin is
-		 * removed, to prevent freezing of any other simultaneously running
-		 * media calls. */
-		if (priv->sessions) {
-			GList *sessions = g_hash_table_get_values(priv->sessions);
-			for (; sessions; sessions =
-					g_list_delete_link(sessions, sessions)) {
-				PurpleMediaBackendFs2Session *session = sessions->data;
-				if (session->srcpad) {
-					unlink_teepad_dynamic(session->srcpad, FALSE);
-					gst_object_unref(session->srcpad);
-					session->srcpad = NULL;
-				}
-			}
-		}
-
-		gst_element_set_locked_state(priv->confbin, TRUE);
-		gst_element_set_state(GST_ELEMENT(priv->confbin),
-				GST_STATE_NULL);
-
-		if (pipeline) {
-			GstBus *bus;
-			gst_bin_remove(GST_BIN(pipeline), priv->confbin);
-			bus = gst_pipeline_get_bus(GST_PIPELINE(pipeline));
-			g_signal_handlers_disconnect_matched(G_OBJECT(bus),
-					G_SIGNAL_MATCH_FUNC |
-					G_SIGNAL_MATCH_DATA,
-					0, 0, 0, gst_bus_cb, obj);
-			gst_object_unref(bus);
-		} else {
-			purple_debug_warning("backend-fs2", "Unable to "
-					"properly dispose the conference. "
-					"Couldn't get the pipeline.\n");
-		}
-
-		priv->confbin = NULL;
-		priv->conference = NULL;
-
-	}
-
-	if (priv->sessions) {
-		GList *sessions = g_hash_table_get_values(priv->sessions);
-
-		for (; sessions; sessions =
-				g_list_delete_link(sessions, sessions)) {
-			PurpleMediaBackendFs2Session *session =
-					sessions->data;
-
-			if (session->session) {
-				g_object_unref(session->session);
-				session->session = NULL;
-			}
-		}
-	}
-
-	if (priv->participants) {
-		g_hash_table_destroy(priv->participants);
-		priv->participants = NULL;
-	}
-
-	for (iter = priv->streams; iter; iter = g_list_next(iter)) {
-		PurpleMediaBackendFs2Stream *stream = iter->data;
-		if (stream->stream) {
-			g_object_unref(stream->stream);
-			stream->stream = NULL;
-		}
-	}
-
-	if (priv->media) {
-		g_object_remove_weak_pointer(G_OBJECT(priv->media),
-				(gpointer*)&priv->media);
-		priv->media = NULL;
-	}
-
-	G_OBJECT_CLASS(purple_media_backend_fs2_parent_class)->dispose(obj);
-}
-
-static void
-purple_media_backend_fs2_finalize(GObject *obj)
-{
-	PurpleMediaBackendFs2Private *priv =
-			purple_media_backend_fs2_get_instance_private(
-					PURPLE_MEDIA_BACKEND_FS2(obj));
-
-	purple_debug_info("backend-fs2", "purple_media_backend_fs2_finalize\n");
-
-	g_free(priv->conference_type);
-	g_list_free_full(priv->streams, (GDestroyNotify)free_stream);
-
-	if (priv->sessions) {
-		GList *sessions = g_hash_table_get_values(priv->sessions);
-
-		g_list_free_full(sessions, (GDestroyNotify)free_session);
-		g_hash_table_destroy(priv->sessions);
-	}
-
-	G_OBJECT_CLASS(purple_media_backend_fs2_parent_class)->finalize(obj);
-}
-
-static void
-purple_media_backend_fs2_set_property(GObject *object, guint prop_id,
-		const GValue *value, GParamSpec *pspec)
-{
-	PurpleMediaBackendFs2Private *priv;
-	g_return_if_fail(PURPLE_MEDIA_IS_BACKEND_FS2(object));
-
-	priv = purple_media_backend_fs2_get_instance_private(
-			PURPLE_MEDIA_BACKEND_FS2(object));
-
-	switch (prop_id) {
-		case PROP_CONFERENCE_TYPE:
-			priv->conference_type = g_value_dup_string(value);
-			break;
-		case PROP_MEDIA:
-			priv->media = g_value_get_object(value);
-
-			if (priv->media == NULL)
-				break;
-
-			g_object_add_weak_pointer(G_OBJECT(priv->media),
-					(gpointer*)&priv->media);
-
-			g_signal_connect(G_OBJECT(priv->media),
-					"state-changed",
-					G_CALLBACK(state_changed_cb),
-					PURPLE_MEDIA_BACKEND_FS2(object));
-			g_signal_connect(G_OBJECT(priv->media), "stream-info",
-					G_CALLBACK(stream_info_cb),
-					PURPLE_MEDIA_BACKEND_FS2(object));
-			break;
-		default:
-			G_OBJECT_WARN_INVALID_PROPERTY_ID(
-					object, prop_id, pspec);
-			break;
-	}
-}
-
-static void
-purple_media_backend_fs2_get_property(GObject *object, guint prop_id,
-		GValue *value, GParamSpec *pspec)
-{
-	PurpleMediaBackendFs2Private *priv;
-	g_return_if_fail(PURPLE_MEDIA_IS_BACKEND_FS2(object));
-
-	priv = purple_media_backend_fs2_get_instance_private(
-			PURPLE_MEDIA_BACKEND_FS2(object));
-
-	switch (prop_id) {
-		case PROP_CONFERENCE_TYPE:
-			g_value_set_string(value, priv->conference_type);
-			break;
-		case PROP_MEDIA:
-			g_value_set_object(value, priv->media);
-			break;
-		default:
-			G_OBJECT_WARN_INVALID_PROPERTY_ID(
-					object, prop_id, pspec);
-			break;
-	}
-}
-
-static void
-purple_media_backend_fs2_class_init(PurpleMediaBackendFs2Class *klass)
-{
-	GObjectClass *gobject_class = (GObjectClass*)klass;
-	GList *features;
-
-	gobject_class->dispose = purple_media_backend_fs2_dispose;
-	gobject_class->finalize = purple_media_backend_fs2_finalize;
-	gobject_class->set_property = purple_media_backend_fs2_set_property;
-	gobject_class->get_property = purple_media_backend_fs2_get_property;
-
-	g_object_class_override_property(gobject_class, PROP_CONFERENCE_TYPE,
-			"conference-type");
-	g_object_class_override_property(gobject_class, PROP_MEDIA, "media");
-
-	/* VA-API elements aren't well supported in Farstream. Ignore them. */
-	features = gst_registry_get_feature_list_by_plugin(gst_registry_get(),
-			"vaapi");
-	g_list_foreach(features, (GFunc)gst_plugin_feature_set_rank, GINT_TO_POINTER(GST_RANK_NONE));
-	gst_plugin_feature_list_free(features);
-}
-
-static void
-purple_media_backend_iface_init(PurpleMediaBackendInterface *iface)
-{
-	iface->add_stream = purple_media_backend_fs2_add_stream;
-	iface->add_remote_candidates =
-			purple_media_backend_fs2_add_remote_candidates;
-	iface->codecs_ready = purple_media_backend_fs2_codecs_ready;
-	iface->get_codecs = purple_media_backend_fs2_get_codecs;
-	iface->get_local_candidates =
-			purple_media_backend_fs2_get_local_candidates;
-	iface->set_remote_codecs = purple_media_backend_fs2_set_remote_codecs;
-	iface->set_send_codec = purple_media_backend_fs2_set_send_codec;
-	iface->set_encryption_parameters =
-			purple_media_backend_fs2_set_encryption_parameters;
-	iface->set_decryption_parameters =
-			purple_media_backend_fs2_set_decryption_parameters;
-	iface->set_require_encryption =
-			purple_media_backend_fs2_set_require_encryption;
-	iface->set_params = purple_media_backend_fs2_set_params;
-	iface->get_available_params = purple_media_backend_fs2_get_available_params;
-	iface->send_dtmf = purple_media_backend_fs2_send_dtmf;
-	iface->set_send_rtcp_mux = purple_media_backend_fs2_set_send_rtcp_mux;
-}
-
-static FsMediaType
-session_type_to_fs_media_type(PurpleMediaSessionType type)
-{
-	if (type & PURPLE_MEDIA_AUDIO)
-		return FS_MEDIA_TYPE_AUDIO;
-	else if (type & PURPLE_MEDIA_VIDEO)
-		return FS_MEDIA_TYPE_VIDEO;
-#ifdef HAVE_MEDIA_APPLICATION
-	else if (type & PURPLE_MEDIA_APPLICATION)
-		return FS_MEDIA_TYPE_APPLICATION;
-#endif
-	else
-		return 0;
-}
-
-static FsStreamDirection
-session_type_to_fs_stream_direction(PurpleMediaSessionType type)
-{
-	if ((type & PURPLE_MEDIA_AUDIO) == PURPLE_MEDIA_AUDIO ||
-		(type & PURPLE_MEDIA_VIDEO) == PURPLE_MEDIA_VIDEO)
-		return FS_DIRECTION_BOTH;
-	else if ((type & PURPLE_MEDIA_SEND_AUDIO) ||
-			(type & PURPLE_MEDIA_SEND_VIDEO))
-		return FS_DIRECTION_SEND;
-	else if ((type & PURPLE_MEDIA_RECV_AUDIO) ||
-			(type & PURPLE_MEDIA_RECV_VIDEO))
-		return FS_DIRECTION_RECV;
-#ifdef HAVE_MEDIA_APPLICATION
-	else if ((type & PURPLE_MEDIA_APPLICATION) == PURPLE_MEDIA_APPLICATION)
-		return FS_DIRECTION_BOTH;
-	else if (type & PURPLE_MEDIA_SEND_APPLICATION)
-		return FS_DIRECTION_SEND;
-	else if (type & PURPLE_MEDIA_RECV_APPLICATION)
-		return FS_DIRECTION_RECV;
-#endif
-	else
-		return FS_DIRECTION_NONE;
-}
-
-static PurpleMediaSessionType
-session_type_from_fs(FsMediaType type, FsStreamDirection direction)
-{
-	PurpleMediaSessionType result = PURPLE_MEDIA_NONE;
-	if (type == FS_MEDIA_TYPE_AUDIO) {
-		if (direction & FS_DIRECTION_SEND)
-			result |= PURPLE_MEDIA_SEND_AUDIO;
-		if (direction & FS_DIRECTION_RECV)
-			result |= PURPLE_MEDIA_RECV_AUDIO;
-	} else if (type == FS_MEDIA_TYPE_VIDEO) {
-		if (direction & FS_DIRECTION_SEND)
-			result |= PURPLE_MEDIA_SEND_VIDEO;
-		if (direction & FS_DIRECTION_RECV)
-			result |= PURPLE_MEDIA_RECV_VIDEO;
-#ifdef HAVE_MEDIA_APPLICATION
-	} else if (type == FS_MEDIA_TYPE_APPLICATION) {
-		if (direction & FS_DIRECTION_SEND)
-			result |= PURPLE_MEDIA_SEND_APPLICATION;
-		if (direction & FS_DIRECTION_RECV)
-			result |= PURPLE_MEDIA_RECV_APPLICATION;
-#endif
-	}
-	return result;
-}
-
-static FsCandidate *
-candidate_to_fs(PurpleMediaCandidate *candidate)
-{
-	FsCandidate *fscandidate;
-	gchar *foundation;
-	guint component_id;
-	gchar *ip;
-	guint port;
-	gchar *base_ip;
-	guint base_port;
-	PurpleMediaNetworkProtocol proto;
-	guint32 priority;
-	PurpleMediaCandidateType type;
-	gchar *username;
-	gchar *password;
-	guint ttl;
-
-	if (candidate == NULL)
-		return NULL;
-
-	g_object_get(G_OBJECT(candidate),
-			"foundation", &foundation,
-			"component-id", &component_id,
-			"ip", &ip,
-			"port", &port,
-			"base-ip", &base_ip,
-			"base-port", &base_port,
-			"protocol", &proto,
-			"priority", &priority,
-			"type", &type,
-			"username", &username,
-			"password", &password,
-			"ttl", &ttl,
-			NULL);
-
-	fscandidate = fs_candidate_new(foundation,
-			component_id, purple_media_candidate_type_to_fs(type),
-			purple_media_network_protocol_to_fs(proto), ip, port);
-
-	fscandidate->base_ip = base_ip;
-	fscandidate->base_port = base_port;
-	fscandidate->priority = priority;
-	fscandidate->username = username;
-	fscandidate->password = password;
-	fscandidate->ttl = ttl;
-
-	g_free(foundation);
-	g_free(ip);
-	return fscandidate;
-}
-
-static PurpleMediaCandidate *
-candidate_from_fs(FsCandidate *fscandidate)
-{
-	PurpleMediaCandidate *candidate;
-
-	if (fscandidate == NULL)
-		return NULL;
-
-	candidate = purple_media_candidate_new(fscandidate->foundation,
-		fscandidate->component_id,
-		purple_media_candidate_type_from_fs(fscandidate->type),
-		purple_media_network_protocol_from_fs(fscandidate->proto),
-		fscandidate->ip, fscandidate->port);
-	g_object_set(candidate,
-			"base-ip", fscandidate->base_ip,
-			"base-port", fscandidate->base_port,
-			"priority", fscandidate->priority,
-			"username", fscandidate->username,
-			"password", fscandidate->password,
-			"ttl", fscandidate->ttl, NULL);
-	return candidate;
-}
-
-static FsCodec *
-codec_to_fs(const PurpleMediaCodec *codec)
-{
-	FsCodec *new_codec;
-	gint id;
-	char *encoding_name;
-	PurpleMediaSessionType media_type;
-	guint clock_rate;
-	guint channels;
-	GList *iter;
-
-	if (codec == NULL)
-		return NULL;
-
-	g_object_get(G_OBJECT(codec),
-			"id", &id,
-			"encoding-name", &encoding_name,
-			"media-type", &media_type,
-			"clock-rate", &clock_rate,
-			"channels", &channels,
-			"optional-params", &iter,
-			NULL);
-
-	new_codec = fs_codec_new(id, encoding_name,
-			session_type_to_fs_media_type(media_type),
-			clock_rate);
-	new_codec->channels = channels;
-
-	for (; iter; iter = g_list_next(iter)) {
-		PurpleKeyValuePair *param = (PurpleKeyValuePair*)iter->data;
-		fs_codec_add_optional_parameter(new_codec,
-				param->key, param->value);
-	}
-
-	g_free(encoding_name);
-	return new_codec;
-}
-
-static PurpleMediaCodec *
-codec_from_fs(const FsCodec *codec)
-{
-	PurpleMediaCodec *new_codec;
-	GList *iter;
-
-	if (codec == NULL)
-		return NULL;
-
-	new_codec = purple_media_codec_new(codec->id, codec->encoding_name,
-			session_type_from_fs(codec->media_type,
-			FS_DIRECTION_BOTH), codec->clock_rate);
-	g_object_set(new_codec, "channels", codec->channels, NULL);
-
-	for (iter = codec->optional_params; iter; iter = g_list_next(iter)) {
-		FsCodecParameter *param = (FsCodecParameter*)iter->data;
-		purple_media_codec_add_optional_parameter(new_codec,
-				param->name, param->value);
-	}
-
-	return new_codec;
-}
-
-static PurpleMediaBackendFs2Session *
-get_session(PurpleMediaBackendFs2 *self, const gchar *sess_id)
-{
-	PurpleMediaBackendFs2Private *priv;
-	PurpleMediaBackendFs2Session *session = NULL;
-
-	g_return_val_if_fail(PURPLE_MEDIA_IS_BACKEND_FS2(self), NULL);
-
-	priv = purple_media_backend_fs2_get_instance_private(self);
-
-	if (priv->sessions != NULL)
-		session = g_hash_table_lookup(priv->sessions, sess_id);
-
-	return session;
-}
-
-static FsParticipant *
-get_participant(PurpleMediaBackendFs2 *self, const gchar *name)
-{
-	PurpleMediaBackendFs2Private *priv;
-	FsParticipant *participant = NULL;
-
-	g_return_val_if_fail(PURPLE_MEDIA_IS_BACKEND_FS2(self), NULL);
-
-	priv = purple_media_backend_fs2_get_instance_private(self);
-
-	if (priv->participants != NULL)
-		participant = g_hash_table_lookup(priv->participants, name);
-
-	return participant;
-}
-
-static PurpleMediaBackendFs2Stream *
-get_stream(PurpleMediaBackendFs2 *self,
-		const gchar *sess_id, const gchar *name)
-{
-	PurpleMediaBackendFs2Private *priv;
-	GList *streams;
-
-	g_return_val_if_fail(PURPLE_MEDIA_IS_BACKEND_FS2(self), NULL);
-
-	priv = purple_media_backend_fs2_get_instance_private(self);
-	streams = priv->streams;
-
-	for (; streams; streams = g_list_next(streams)) {
-		PurpleMediaBackendFs2Stream *stream = streams->data;
-		if (purple_strequal(stream->session->id, sess_id) &&
-				purple_strequal(stream->participant, name))
-			return stream;
-	}
-
-	return NULL;
-}
-
-static GList *
-get_streams(PurpleMediaBackendFs2 *self,
-		const gchar *sess_id, const gchar *name)
-{
-	PurpleMediaBackendFs2Private *priv;
-	GList *streams, *ret = NULL;
-
-	g_return_val_if_fail(PURPLE_MEDIA_IS_BACKEND_FS2(self), NULL);
-
-	priv = purple_media_backend_fs2_get_instance_private(self);
-	streams = priv->streams;
-
-	for (; streams; streams = g_list_next(streams)) {
-		PurpleMediaBackendFs2Stream *stream = streams->data;
-
-		if (sess_id != NULL && !purple_strequal(stream->session->id, sess_id))
-			continue;
-		else if (name != NULL && !purple_strequal(stream->participant, name))
-			continue;
-		else
-			ret = g_list_prepend(ret, stream);
-	}
-
-	ret = g_list_reverse(ret);
-	return ret;
-}
-
-static PurpleMediaBackendFs2Session *
-get_session_from_fs_stream(PurpleMediaBackendFs2 *self, FsStream *stream)
-{
-	PurpleMediaBackendFs2Private *priv =
-			purple_media_backend_fs2_get_instance_private(self);
-	FsSession *fssession;
-	GList *values;
-
-	g_return_val_if_fail(PURPLE_MEDIA_IS_BACKEND_FS2(self), NULL);
-	g_return_val_if_fail(FS_IS_STREAM(stream), NULL);
-
-	g_object_get(stream, "session", &fssession, NULL);
-
-	values = g_hash_table_get_values(priv->sessions);
-
-	for (; values; values = g_list_delete_link(values, values)) {
-		PurpleMediaBackendFs2Session *session = values->data;
-
-		if (session->session == fssession) {
-			g_list_free(values);
-			g_object_unref(fssession);
-			return session;
-		}
-	}
-
-	g_object_unref(fssession);
-	return NULL;
-}
-
-static gdouble
-gst_msg_db_to_percent(GstMessage *msg, gchar *value_name)
-{
-	const GValue *list;
-	const GValue *value;
-	gdouble value_db;
-	gdouble percent;
-
-	list = gst_structure_get_value(gst_message_get_structure(msg), value_name);
-G_GNUC_BEGIN_IGNORE_DEPRECATIONS
-	value = g_value_array_get_nth(g_value_get_boxed(list), 0);
-G_GNUC_END_IGNORE_DEPRECATIONS
-	value_db = g_value_get_double(value);
-	percent = pow(10, value_db / 20);
-	return (percent > 1.0) ? 1.0 : percent;
-}
-
-static void
-purple_media_error_fs(PurpleMedia *media, const gchar *error,
-		const GstStructure *fs_error)
-{
-	const gchar *error_msg = gst_structure_get_string(fs_error, "error-msg");
-
-	purple_media_error(media, "%s%s%s", error,
-	                   error_msg ? _("\n\nMessage from Farstream: ") : "",
-	                   error_msg ? error_msg : "");
-}
-
-static void
-gst_handle_message_element(GstBus *bus, GstMessage *msg,
-		PurpleMediaBackendFs2 *self)
-{
-	PurpleMediaBackendFs2Private *priv =
-			purple_media_backend_fs2_get_instance_private(self);
-	GstElement *src = GST_ELEMENT(GST_MESSAGE_SRC(msg));
-	static guint level_id = 0;
-	const GstStructure *structure = gst_message_get_structure(msg);
-
-	if (level_id == 0)
-		level_id = g_signal_lookup("level", PURPLE_TYPE_MEDIA);
-
-	if (gst_structure_has_name(structure, "level")) {
-		GstElement *src = GST_ELEMENT(GST_MESSAGE_SRC(msg));
-		gchar *name;
-		gchar *participant = NULL;
-		PurpleMediaBackendFs2Session *session = NULL;
-		gdouble percent;
-
-		if (!PURPLE_IS_MEDIA(priv->media) ||
-				GST_ELEMENT_PARENT(src) != priv->confbin)
-			return;
-
-		name = gst_element_get_name(src);
-
-		if (!strncmp(name, "sendlevel_", 10)) {
-			session = get_session(self, name+10);
-			if (priv->silence_threshold > 0) {
-				percent = gst_msg_db_to_percent(msg, "decay");
-				g_object_set(session->srcvalve,
-						"drop", (percent < priv->silence_threshold), NULL);
-			}
-		}
-
-		g_free(name);
-
-		if (!g_signal_has_handler_pending(priv->media, level_id, 0, FALSE))
-			return;
-
-		if (!session) {
-			GList *iter = priv->streams;
-			PurpleMediaBackendFs2Stream *stream;
-			for (; iter; iter = g_list_next(iter)) {
-				stream = iter->data;
-				if (stream->level == src) {
-					session = stream->session;
-					participant = stream->participant;
-					break;
-				}
-			}
-		}
-
-		if (!session)
-			return;
-
-		percent = gst_msg_db_to_percent(msg, "rms");
-
-		g_signal_emit(priv->media, level_id, 0,
-				session->id, participant, percent);
-		return;
-	}
-
-	if (!FS_IS_CONFERENCE(src) || !PURPLE_MEDIA_IS_BACKEND(self) ||
-			priv->conference != FS_CONFERENCE(src))
-		return;
-
-	if (gst_structure_has_name(structure, "farstream-error")) {
-		FsError error_no;
-		gboolean error_emitted = FALSE;
-		gst_structure_get_enum(structure, "error-no",
-				FS_TYPE_ERROR, (gint*)&error_no);
-		switch (error_no) {
-			case FS_ERROR_CONSTRUCTION:
-				purple_media_error_fs(priv->media,
-				                      _("Error initializing the call. "
-				                        "This probably denotes problem in "
-				                        "installation of GStreamer or Farstream."),
-				                      structure);
-				error_emitted = TRUE;
-				break;
-			case FS_ERROR_NETWORK:
-				purple_media_error_fs(priv->media, _("Network error."),
-				                      structure);
-				error_emitted = TRUE;
-				purple_media_end(priv->media, NULL, NULL);
-				break;
-			case FS_ERROR_NEGOTIATION_FAILED:
-				purple_media_error_fs(priv->media,
-				                      _("Codec negotiation failed. "
-				                        "This problem might be resolved by installing "
-				                        "more GStreamer codecs."),
-				                      structure);
-				error_emitted = TRUE;
-				purple_media_end(priv->media, NULL, NULL);
-				break;
-			case FS_ERROR_NO_CODECS:
-				purple_media_error(priv->media,
-				                   _("No codecs found. "
-				                     "Install some GStreamer codecs found "
-				                     "in GStreamer plugins packages."));
-				error_emitted = TRUE;
-				purple_media_end(priv->media, NULL, NULL);
-				break;
-			default:
-				purple_debug_error("backend-fs2",
-						"farstream-error: %i: %s\n",
-						error_no,
-						gst_structure_get_string(structure, "error-msg"));
-				break;
-		}
-
-		if (FS_ERROR_IS_FATAL(error_no)) {
-			if (!error_emitted)
-			purple_media_error(priv->media,
-			                   _("A non-recoverable Farstream error has occurred."));
-			purple_media_end(priv->media, NULL, NULL);
-		}
-	} else if (gst_structure_has_name(structure,
-			"farstream-new-local-candidate")) {
-		const GValue *value;
-		FsStream *stream;
-		FsCandidate *local_candidate;
-		PurpleMediaCandidate *candidate;
-		FsParticipant *participant;
-		PurpleMediaBackendFs2Session *session;
-		PurpleMediaBackendFs2Stream *media_stream;
-		const gchar *name;
-
-		value = gst_structure_get_value(structure, "stream");
-		stream = g_value_get_object(value);
-		value = gst_structure_get_value(structure, "candidate");
-		local_candidate = g_value_get_boxed(value);
-
-		session = get_session_from_fs_stream(self, stream);
-
-		purple_debug_info("backend-fs2",
-				"got new local candidate: %s\n",
-				local_candidate->foundation);
-
-		g_object_get(stream, "participant", &participant, NULL);
-		name = g_object_get_data(G_OBJECT(participant), "purple-name");
-
-		media_stream = get_stream(self, session->id, name);
-		media_stream->local_candidates = g_list_append(
-				media_stream->local_candidates,
-				fs_candidate_copy(local_candidate));
-
-		candidate = candidate_from_fs(local_candidate);
-		g_signal_emit_by_name(self, "new-candidate",
-				session->id, name, candidate);
-		g_object_unref(candidate);
-		g_object_unref(participant);
-	} else if (gst_structure_has_name(structure,
-			"farstream-local-candidates-prepared")) {
-		const GValue *value;
-		FsStream *stream;
-		FsParticipant *participant;
-		PurpleMediaBackendFs2Session *session;
-
-		value = gst_structure_get_value(structure, "stream");
-		stream = g_value_get_object(value);
-		session = get_session_from_fs_stream(self, stream);
-
-		g_object_get(stream, "participant", &participant, NULL);
-
-		g_signal_emit_by_name(self, "candidates-prepared",
-				session->id,
-				g_object_get_data(G_OBJECT(participant), "purple-name"));
-
-		g_object_unref(participant);
-	} else if (gst_structure_has_name(structure,
-			"farstream-new-active-candidate-pair")) {
-		const GValue *value;
-		FsStream *stream;
-		FsCandidate *local_candidate;
-		FsCandidate *remote_candidate;
-		FsParticipant *participant;
-		PurpleMediaBackendFs2Session *session;
-		PurpleMediaCandidate *lcandidate, *rcandidate;
-
-		value = gst_structure_get_value(structure, "stream");
-		stream = g_value_get_object(value);
-		value = gst_structure_get_value(structure, "local-candidate");
-		local_candidate = g_value_get_boxed(value);
-		value = gst_structure_get_value(structure, "remote-candidate");
-		remote_candidate = g_value_get_boxed(value);
-
-		g_object_get(stream, "participant", &participant, NULL);
-
-		session = get_session_from_fs_stream(self, stream);
-
-		lcandidate = candidate_from_fs(local_candidate);
-		rcandidate = candidate_from_fs(remote_candidate);
-
-		g_signal_emit_by_name(self, "active-candidate-pair",
-				session->id,
-				g_object_get_data(G_OBJECT(participant), "purple-name"),
-				lcandidate, rcandidate);
-
-		g_object_unref(participant);
-		g_object_unref(lcandidate);
-		g_object_unref(rcandidate);
-	} else if (gst_structure_has_name(structure,
-			"farstream-recv-codecs-changed")) {
-		const GValue *value;
-		GList *codecs;
-		FsCodec *codec;
-
-		value = gst_structure_get_value(structure, "codecs");
-		codecs = g_value_get_boxed(value);
-		codec = codecs->data;
-
-		purple_debug_info("backend-fs2",
-				"farstream-recv-codecs-changed: %s\n",
-				codec->encoding_name);
-	} else if (gst_structure_has_name(structure,
-			"farstream-component-state-changed")) {
-		const GValue *value;
-		FsStreamState fsstate;
-		guint component;
-		const gchar *state;
-
-		value = gst_structure_get_value(structure, "state");
-		fsstate = g_value_get_enum(value);
-		value = gst_structure_get_value(structure, "component");
-		component = g_value_get_uint(value);
-
-		switch (fsstate) {
-			case FS_STREAM_STATE_FAILED:
-				state = "FAILED";
-				break;
-			case FS_STREAM_STATE_DISCONNECTED:
-				state = "DISCONNECTED";
-				break;
-			case FS_STREAM_STATE_GATHERING:
-				state = "GATHERING";
-				break;
-			case FS_STREAM_STATE_CONNECTING:
-				state = "CONNECTING";
-				break;
-			case FS_STREAM_STATE_CONNECTED:
-				state = "CONNECTED";
-				break;
-			case FS_STREAM_STATE_READY:
-				state = "READY";
-				break;
-			default:
-				state = "UNKNOWN";
-				break;
-		}
-
-		purple_debug_info("backend-fs2",
-				"farstream-component-state-changed: "
-				"component: %u state: %s\n",
-				component, state);
-	} else if (gst_structure_has_name(structure,
-			"farstream-send-codec-changed")) {
-		const GValue *value;
-		FsCodec *codec;
-		gchar *codec_str;
-
-		value = gst_structure_get_value(structure, "codec");
-		codec = g_value_get_boxed(value);
-		codec_str = fs_codec_to_string(codec);
-
-		purple_debug_info("backend-fs2",
-				"farstream-send-codec-changed: codec: %s\n",
-				codec_str);
-
-		g_free(codec_str);
-	} else if (gst_structure_has_name(structure,
-			"farstream-codecs-changed")) {
-		const GValue *value;
-		FsSession *fssession;
-		GList *sessions;
-
-		value = gst_structure_get_value(structure, "session");
-		fssession = g_value_get_object(value);
-		sessions = g_hash_table_get_values(priv->sessions);
-
-		for (; sessions; sessions =
-				g_list_delete_link(sessions, sessions)) {
-			PurpleMediaBackendFs2Session *session = sessions->data;
-			gchar *session_id;
-
-			if (session->session != fssession)
-				continue;
-
-			session_id = g_strdup(session->id);
-			g_signal_emit_by_name(self, "codecs-changed",
-					session_id);
-			g_free(session_id);
-			g_list_free(sessions);
-			break;
-		}
-	}
-}
-
-static void
-gst_handle_message_error(GstBus *bus, GstMessage *msg,
-		PurpleMediaBackendFs2 *self)
-{
-	PurpleMediaBackendFs2Private *priv =
-			purple_media_backend_fs2_get_instance_private(self);
-	GstElement *element = GST_ELEMENT(GST_MESSAGE_SRC(msg));
-	GstElement *lastElement = NULL;
-	GList *sessions;
-
-	GError *error = NULL;
-	gchar *debug_msg = NULL;
-
-	gst_message_parse_error(msg, &error, &debug_msg);
-	purple_debug_error("backend-fs2", "gst error %s\ndebugging: %s\n",
-			error->message, debug_msg);
-
-	g_error_free(error);
-	g_free(debug_msg);
-
-	while (element && !GST_IS_PIPELINE(element)) {
-		if (element == priv->confbin)
-			break;
-
-		lastElement = element;
-		element = GST_ELEMENT_PARENT(element);
-	}
-
-	if (!element || !GST_IS_PIPELINE(element))
-		return;
-
-	sessions = purple_media_get_session_ids(priv->media);
-
-	for (; sessions; sessions = g_list_delete_link(sessions, sessions)) {
-		if (purple_media_get_src(priv->media, sessions->data)
-				!= lastElement)
-			continue;
-
-		if (purple_media_get_session_type(priv->media, sessions->data)
-				& PURPLE_MEDIA_AUDIO)
-			purple_media_error(priv->media,
-					_("Error with your microphone"));
-		else if (purple_media_get_session_type(priv->media,
-                        sessions->data) & PURPLE_MEDIA_VIDEO)
-			purple_media_error(priv->media,
-					_("Error with your webcam"));
-
-		break;
-	}
-
-	g_list_free(sessions);
-
-	purple_media_error(priv->media, _("Conference error"));
-	purple_media_end(priv->media, NULL, NULL);
-}
-
-static gboolean
-gst_bus_cb(GstBus *bus, GstMessage *msg, PurpleMediaBackendFs2 *self)
-{
-	switch(GST_MESSAGE_TYPE(msg)) {
-		case GST_MESSAGE_ELEMENT:
-			gst_handle_message_element(bus, msg, self);
-			break;
-		case GST_MESSAGE_ERROR:
-			gst_handle_message_error(bus, msg, self);
-			break;
-		default:
-			break;
-	}
-
-	return TRUE;
-}
-
-static void
-remove_element(GstElement *element)
-{
-	if (element) {
-		gst_element_set_locked_state(element, TRUE);
-		gst_element_set_state(element, GST_STATE_NULL);
-		gst_bin_remove(GST_BIN(GST_ELEMENT_PARENT(element)), element);
-	}
-}
-
-static void
-state_changed_cb(PurpleMedia *media, PurpleMediaState state,
-		gchar *sid, gchar *name, PurpleMediaBackendFs2 *self)
-{
-	if (state == PURPLE_MEDIA_STATE_END) {
-		PurpleMediaBackendFs2Private *priv =
-				purple_media_backend_fs2_get_instance_private(
-						self);
-
-		if (sid && name) {
-			PurpleMediaBackendFs2Stream *stream = get_stream(self, sid, name);
-			gst_object_unref(stream->stream);
-
-			priv->streams = g_list_remove(priv->streams, stream);
-
-			remove_element(stream->src);
-			remove_element(stream->tee);
-			remove_element(stream->volume);
-			remove_element(stream->level);
-			remove_element(stream->fakesink);
-			remove_element(stream->queue);
-
-			free_stream(stream);
-		} else if (sid && !name) {
-			PurpleMediaBackendFs2Session *session = get_session(self, sid);
-			GstPad *pad;
-
-			g_object_get(session->session, "sink-pad", &pad, NULL);
-			gst_pad_unlink(GST_PAD_PEER(pad), pad);
-			gst_object_unref(pad);
-
-			gst_object_unref(session->session);
-			g_hash_table_remove(priv->sessions, session->id);
-
-			pad = gst_pad_get_peer(session->srcpad);
-			gst_element_remove_pad(GST_ELEMENT_PARENT(pad), pad);
-			gst_object_unref(pad);
-			gst_object_unref(session->srcpad);
-
-			remove_element(session->srcvalve);
-			remove_element(session->tee);
-
-			free_session(session);
-		}
-
-		purple_media_manager_remove_output_windows(
-				purple_media_get_manager(media), media, sid, name);
-	}
-}
-
-static void
-stream_info_cb(PurpleMedia *media, PurpleMediaInfoType type,
-		gchar *sid, gchar *name, gboolean local,
-		PurpleMediaBackendFs2 *self)
-{
-	if (type == PURPLE_MEDIA_INFO_ACCEPT && sid != NULL && name != NULL) {
-		PurpleMediaBackendFs2Stream *stream =
-				get_stream(self, sid, name);
-		GError *err = NULL;
-
-		g_object_set(G_OBJECT(stream->stream), "direction",
-				session_type_to_fs_stream_direction(
-				stream->session->type), NULL);
-
-		if (stream->remote_candidates == NULL ||
-				purple_media_is_initiator(media, sid, name))
-			return;
-
-		if (stream->supports_add)
-			fs_stream_add_remote_candidates(stream->stream,
-					stream->remote_candidates, &err);
-		else
-			fs_stream_force_remote_candidates(stream->stream,
-					stream->remote_candidates, &err);
-
-		if (err == NULL)
-			return;
-
-		purple_debug_error("backend-fs2", "Error adding "
-				"remote candidates: %s\n",
-				err->message);
-		g_error_free(err);
-	} else if (local == TRUE && (type == PURPLE_MEDIA_INFO_MUTE ||
-			type == PURPLE_MEDIA_INFO_UNMUTE)) {
-		PurpleMediaBackendFs2Private *priv =
-				purple_media_backend_fs2_get_instance_private(
-						self);
-		gboolean active = (type == PURPLE_MEDIA_INFO_MUTE);
-		GList *sessions;
-
-		if (sid == NULL)
-			sessions = g_hash_table_get_values(priv->sessions);
-		else
-			sessions = g_list_prepend(NULL,
-					get_session(self, sid));
-
-		purple_debug_info("media", "Turning mute %s\n",
-				active ? "on" : "off");
-
-		for (; sessions; sessions = g_list_delete_link(
-				sessions, sessions)) {
-			PurpleMediaBackendFs2Session *session =
-					sessions->data;
-
-			if (session->type & PURPLE_MEDIA_SEND_AUDIO) {
-				gchar *name = g_strdup_printf("volume_%s",
-						session->id);
-				GstElement *volume = gst_bin_get_by_name(
-						GST_BIN(priv->confbin), name);
-				g_free(name);
-				g_object_set(volume, "mute", active, NULL);
-			}
-		}
-	} else if (local == TRUE && (type == PURPLE_MEDIA_INFO_HOLD ||
-			type == PURPLE_MEDIA_INFO_UNHOLD)) {
-		gboolean active = (type == PURPLE_MEDIA_INFO_HOLD);
-		GList *streams = get_streams(self, sid, name);
-		for (; streams; streams =
-				g_list_delete_link(streams, streams)) {
-			PurpleMediaBackendFs2Stream *stream = streams->data;
-			if (stream->session->type & PURPLE_MEDIA_SEND_AUDIO) {
-				g_object_set(stream->stream, "direction",
-						session_type_to_fs_stream_direction(
-						stream->session->type & ((active) ?
-						~PURPLE_MEDIA_SEND_AUDIO :
-						PURPLE_MEDIA_AUDIO)), NULL);
-			}
-		}
-	} else if (local == TRUE && (type == PURPLE_MEDIA_INFO_PAUSE ||
-			type == PURPLE_MEDIA_INFO_UNPAUSE)) {
-		gboolean active = (type == PURPLE_MEDIA_INFO_PAUSE);
-		GList *streams = get_streams(self, sid, name);
-		for (; streams; streams =
-				g_list_delete_link(streams, streams)) {
-			PurpleMediaBackendFs2Stream *stream = streams->data;
-			if (stream->session->type & PURPLE_MEDIA_SEND_VIDEO) {
-				g_object_set(stream->stream, "direction",
-						session_type_to_fs_stream_direction(
-						stream->session->type & ((active) ?
-						~PURPLE_MEDIA_SEND_VIDEO :
-						PURPLE_MEDIA_VIDEO)), NULL);
-			}
-		}
-	}
-}
-
-static gboolean
-init_conference(PurpleMediaBackendFs2 *self)
-{
-	PurpleMediaBackendFs2Private *priv =
-			purple_media_backend_fs2_get_instance_private(self);
-	GstElement *pipeline;
-	GstBus *bus;
-	gchar *name;
-	GKeyFile *default_props;
-	PurpleAccount *account;
-
-	priv->conference = FS_CONFERENCE(
-			gst_element_factory_make(priv->conference_type, NULL));
-
-	if (priv->conference == NULL) {
-		purple_debug_error("backend-fs2", "Conference == NULL\n");
-		return FALSE;
-	}
-
-	account = purple_media_get_account(priv->media);
-	if (purple_account_get_silence_suppression(account))
-		priv->silence_threshold = purple_prefs_get_int(
-				"/purple/media/audio/silence_threshold") / 100.0;
-	else
-		priv->silence_threshold = 0;
-	g_object_unref(account);
-
-	pipeline = purple_media_manager_get_pipeline(
-			purple_media_get_manager(priv->media));
-
-	if (pipeline == NULL) {
-		purple_debug_error("backend-fs2",
-				"Couldn't retrieve pipeline.\n");
-		return FALSE;
-	}
-
-	name = g_strdup_printf("conf_%p", priv->conference);
-	priv->confbin = gst_bin_new(name);
-	if (priv->confbin == NULL) {
-		purple_debug_error("backend-fs2",
-				"Couldn't create confbin.\n");
-		return FALSE;
-	}
-
-	g_free(name);
-
-	bus = gst_pipeline_get_bus(GST_PIPELINE(pipeline));
-	if (bus == NULL) {
-		purple_debug_error("backend-fs2",
-				"Couldn't get the pipeline's bus.\n");
-		return FALSE;
-	}
-
-	default_props = fs_utils_get_default_element_properties(GST_ELEMENT(priv->conference));
-	if (default_props != NULL) {
-		priv->notifier = fs_element_added_notifier_new();
-		fs_element_added_notifier_add(priv->notifier,
-				GST_BIN(priv->confbin));
-		fs_element_added_notifier_set_properties_from_keyfile(priv->notifier, default_props);
-	}
-
-	g_signal_connect(G_OBJECT(bus), "message",
-			G_CALLBACK(gst_bus_cb), self);
-	gst_object_unref(bus);
-
-	if (!gst_bin_add(GST_BIN(pipeline),
-			GST_ELEMENT(priv->confbin))) {
-		purple_debug_error("backend-fs2", "Couldn't add confbin "
-				"element to the pipeline\n");
-		return FALSE;
-	}
-
-	if (!gst_bin_add(GST_BIN(priv->confbin),
-			GST_ELEMENT(priv->conference))) {
-		purple_debug_error("backend-fs2", "Couldn't add conference "
-				"element to the confbin\n");
-		return FALSE;
-	}
-
-	if (gst_element_set_state(GST_ELEMENT(priv->confbin),
-			GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) {
-		purple_debug_error("backend-fs2",
-				"Failed to start conference.\n");
-		return FALSE;
-	}
-
-	return TRUE;
-}
-
-static gboolean
-create_src(PurpleMediaBackendFs2 *self, const gchar *sess_id,
-		PurpleMediaSessionType type)
-{
-	PurpleMediaBackendFs2Private *priv =
-			purple_media_backend_fs2_get_instance_private(self);
-	PurpleMediaBackendFs2Session *session;
-	PurpleMediaSessionType session_type;
-	FsMediaType media_type = session_type_to_fs_media_type(type);
-	FsStreamDirection type_direction =
-			session_type_to_fs_stream_direction(type);
-	GstElement *src;
-	GstPad *sinkpad, *srcpad;
-	GstPad *ghost = NULL;
-
-	if ((type_direction & FS_DIRECTION_SEND) == 0)
-		return TRUE;
-
-	session_type = session_type_from_fs(
-			media_type, FS_DIRECTION_SEND);
-	src = purple_media_manager_get_element(
-			purple_media_get_manager(priv->media),
-			session_type, priv->media, sess_id, NULL);
-
-	if (!GST_IS_ELEMENT(src)) {
-		purple_debug_error("backend-fs2",
-				"Error creating src for session %s\n",
-				sess_id);
-		return FALSE;
-	}
-
-	session = get_session(self, sess_id);
-
-	if (session == NULL) {
-		purple_debug_warning("backend-fs2",
-				"purple_media_set_src: trying to set"
-				" src on non-existent session\n");
-		return FALSE;
-	}
-
-	if (session->src)
-		gst_object_unref(session->src);
-
-	session->src = src;
-	gst_element_set_locked_state(session->src, TRUE);
-
-	session->tee = gst_element_factory_make("tee", NULL);
-	gst_bin_add(GST_BIN(priv->confbin), session->tee);
-
-	/* This supposedly isn't necessary, but it silences some warnings */
-	if (GST_ELEMENT_PARENT(priv->confbin)
-			== GST_ELEMENT_PARENT(session->src)) {
-		GstPad *pad = gst_element_get_static_pad(session->tee, "sink");
-		ghost = gst_ghost_pad_new(NULL, pad);
-		gst_object_unref(pad);
-		gst_pad_set_active(ghost, TRUE);
-		gst_element_add_pad(priv->confbin, ghost);
-	}
-
-	gst_element_set_state(session->tee, GST_STATE_PLAYING);
-	gst_element_link(session->src, priv->confbin);
-	if (ghost)
-		session->srcpad = gst_pad_get_peer(ghost);
-
-	g_object_get(session->session, "sink-pad", &sinkpad, NULL);
-	if (session->type & PURPLE_MEDIA_SEND_AUDIO) {
-		gchar *name = g_strdup_printf("volume_%s", session->id);
-		GstElement *level;
-		GstElement *volume = gst_element_factory_make("volume", name);
-		double input_volume = purple_prefs_get_int(
-				"/purple/media/audio/volume/input")/10.0;
-		g_free(name);
-		name = g_strdup_printf("sendlevel_%s", session->id);
-		level = gst_element_factory_make("level", name);
-		g_free(name);
-		session->srcvalve = gst_element_factory_make("valve", NULL);
-		gst_bin_add(GST_BIN(priv->confbin), volume);
-		gst_bin_add(GST_BIN(priv->confbin), level);
-		gst_bin_add(GST_BIN(priv->confbin), session->srcvalve);
-		gst_element_set_state(level, GST_STATE_PLAYING);
-		gst_element_set_state(volume, GST_STATE_PLAYING);
-		gst_element_set_state(session->srcvalve, GST_STATE_PLAYING);
-		gst_element_link(level, session->srcvalve);
-		gst_element_link(volume, level);
-		gst_element_link(session->tee, volume);
-		srcpad = gst_element_get_static_pad(session->srcvalve, "src");
-		g_object_set(volume, "volume", input_volume, NULL);
-	} else {
-#if GST_CHECK_VERSION(1, 19, 1)
-		srcpad = gst_element_request_pad_simple(session->tee, "src_%u");
-#else
-		srcpad = gst_element_get_request_pad(session->tee, "src_%u");
-#endif
-	}
-
-	purple_debug_info("backend-fs2", "connecting pad: %s\n",
-			  gst_pad_link(srcpad, sinkpad) == GST_PAD_LINK_OK
-			  ? "success" : "failure");
-	gst_element_set_locked_state(session->src, FALSE);
-	gst_object_unref(session->src);
-	gst_object_unref(sinkpad);
-	gst_object_unref(srcpad);
-
-	purple_media_manager_create_output_window(purple_media_get_manager(
-			priv->media), priv->media, sess_id, NULL);
-
-	purple_debug_info("backend-fs2", "create_src: setting source "
-		"state to GST_STATE_PLAYING - it may hang here on win32\n");
-	gst_element_set_state(session->src, GST_STATE_PLAYING);
-	purple_debug_info("backend-fs2", "create_src: state set\n");
-
-	return TRUE;
-}
-
-static gboolean
-create_session(PurpleMediaBackendFs2 *self, const gchar *sess_id,
-		PurpleMediaSessionType type, gboolean initiator,
-		const gchar *transmitter)
-{
-	PurpleMediaBackendFs2Private *priv =
-			purple_media_backend_fs2_get_instance_private(self);
-	PurpleMediaBackendFs2Session *session;
-	GError *err = NULL;
-	GList *codec_conf = NULL;
-	gchar *filename = NULL;
-
-	session = g_new0(PurpleMediaBackendFs2Session, 1);
-
-	session->session = fs_conference_new_session(priv->conference,
-			session_type_to_fs_media_type(type), &err);
-
-#ifdef HAVE_MEDIA_APPLICATION
-	if (type == PURPLE_MEDIA_APPLICATION) {
-		GstCaps *caps;
-		GObject *rtpsession = NULL;
-
-		caps = gst_caps_new_empty_simple ("application/octet-stream");
-		fs_session_set_allowed_caps (session->session, caps, caps, NULL);
-		gst_caps_unref (caps);
-		g_object_get (session->session, "internal-session", &rtpsession, NULL);
-		if (rtpsession) {
-			g_object_set (rtpsession, "probation", 0, NULL);
-			g_object_unref (rtpsession);
-		}
-	}
-#endif
-	if (err != NULL) {
-		purple_media_error(priv->media,
-				_("Error creating session: %s"),
-				err->message);
-		g_error_free(err);
-		g_free(session);
-		return FALSE;
-	}
-
-	filename = g_build_filename(purple_config_dir(), "fs-codec.conf", NULL);
-	codec_conf = fs_codec_list_from_keyfile(filename, &err);
-	g_free(filename);
-
-	if (err != NULL) {
-		if (err->code == G_KEY_FILE_ERROR_NOT_FOUND)
-			purple_debug_info("backend-fs2", "Couldn't read "
-					"fs-codec.conf: %s\n",
-					err->message);
-		else
-			purple_debug_error("backend-fs2", "Error reading "
-					"fs-codec.conf: %s\n",
-					err->message);
-		g_error_free(err);
-
-		purple_debug_info("backend-fs2",
-				"Loading default codec conf instead\n");
-		codec_conf = fs_utils_get_default_codec_preferences(
-				GST_ELEMENT(priv->conference));
-	}
-
-	fs_session_set_codec_preferences(session->session, codec_conf, NULL);
-	fs_codec_list_destroy(codec_conf);
-
-	/*
-	 * Removes a 5-7 second delay before
-	 * receiving the src-pad-added signal.
-	 * Only works for non-multicast FsRtpSessions.
-	 */
-	if (!purple_strequal(transmitter, "multicast"))
-		g_object_set(G_OBJECT(session->session),
-				"no-rtcp-timeout", 0, NULL);
-
-	session->id = g_strdup(sess_id);
-	session->backend = self;
-	session->type = type;
-
-	if (!priv->sessions) {
-		purple_debug_info("backend-fs2",
-				"Creating hash table for sessions\n");
-		priv->sessions = g_hash_table_new_full(g_str_hash, g_str_equal,
-		                                       g_free, NULL);
-	}
-
-	g_hash_table_insert(priv->sessions, g_strdup(session->id), session);
-
-	if (!create_src(self, sess_id, type)) {
-		purple_debug_info("backend-fs2", "Error creating the src\n");
-		return FALSE;
-	}
-
-	return TRUE;
-}
-
-static void
-free_session(PurpleMediaBackendFs2Session *session)
-{
-	g_free(session->id);
-	g_free(session);
-}
-
-static gboolean
-create_participant(PurpleMediaBackendFs2 *self, const gchar *name)
-{
-	PurpleMediaBackendFs2Private *priv =
-			purple_media_backend_fs2_get_instance_private(self);
-	FsParticipant *participant;
-	GError *err = NULL;
-
-	participant = fs_conference_new_participant(
-			priv->conference, &err);
-
-	if (err) {
-		purple_debug_error("backend-fs2",
-				"Error creating participant: %s\n",
-				err->message);
-		g_error_free(err);
-		return FALSE;
-	}
-
-	g_object_set_data_full(G_OBJECT(participant), "purple-name",
-			g_strdup(name), g_free);
-
-	if (g_object_class_find_property(G_OBJECT_GET_CLASS(participant),
-			"cname")) {
-		g_object_set(participant, "cname", name, NULL);
-	}
-
-	if (!priv->participants) {
-		purple_debug_info("backend-fs2",
-				"Creating hash table for participants\n");
-		priv->participants = g_hash_table_new_full(g_str_hash,
-				g_str_equal, g_free, g_object_unref);
-	}
-
-	g_hash_table_insert(priv->participants, g_strdup(name), participant);
-
-	return TRUE;
-}
-
-static gboolean
-src_pad_added_cb_cb(PurpleMediaBackendFs2Stream *stream)
-{
-	PurpleMediaBackendFs2Private *priv;
-
-	g_return_val_if_fail(stream != NULL, FALSE);
-
-	priv = purple_media_backend_fs2_get_instance_private(
-			stream->session->backend);
-	stream->connected_cb_id = 0;
-
-	purple_media_manager_create_output_window(
-			purple_media_get_manager(priv->media), priv->media,
-			stream->session->id, stream->participant);
-
-	g_signal_emit_by_name(priv->media, "state-changed",
-			PURPLE_MEDIA_STATE_CONNECTED,
-			stream->session->id, stream->participant);
-	return FALSE;
-}
-
-static void
-src_pad_added_cb(FsStream *fsstream, GstPad *srcpad,
-		FsCodec *codec, PurpleMediaBackendFs2Stream *stream)
-{
-	PurpleMediaBackendFs2Private *priv;
-	GstPad *sinkpad;
-
-	g_return_if_fail(FS_IS_STREAM(fsstream));
-	g_return_if_fail(stream != NULL);
-
-	priv = purple_media_backend_fs2_get_instance_private(
-			stream->session->backend);
-
-	if (stream->src == NULL) {
-		GstElement *sink = NULL;
-
-		if (codec->media_type == FS_MEDIA_TYPE_AUDIO) {
-			double output_volume = purple_prefs_get_int(
-					"/purple/media/audio/volume/output")/10.0;
-			stream->queue = gst_element_factory_make("queue", NULL);
-			stream->volume = gst_element_factory_make("volume", NULL);
-			g_object_set(stream->volume, "volume", output_volume, NULL);
-			stream->level = gst_element_factory_make("level", NULL);
-			stream->src = gst_element_factory_make("audiomixer", NULL);
-			sink = purple_media_manager_get_element(
-					purple_media_get_manager(priv->media),
-					PURPLE_MEDIA_RECV_AUDIO, priv->media,
-					stream->session->id,
-					stream->participant);
-			gst_bin_add(GST_BIN(priv->confbin), stream->queue);
-			gst_bin_add(GST_BIN(priv->confbin), stream->volume);
-			gst_bin_add(GST_BIN(priv->confbin), stream->level);
-			gst_bin_add(GST_BIN(priv->confbin), sink);
-			gst_element_set_state(sink, GST_STATE_PLAYING);
-			gst_element_set_state(stream->level, GST_STATE_PLAYING);
-			gst_element_set_state(stream->volume, GST_STATE_PLAYING);
-			gst_element_set_state(stream->queue, GST_STATE_PLAYING);
-			gst_element_link(stream->level, sink);
-			gst_element_link(stream->volume, stream->level);
-			gst_element_link(stream->queue, stream->volume);
-			sink = stream->queue;
-		} else if (codec->media_type == FS_MEDIA_TYPE_VIDEO) {
-			stream->src = gst_element_factory_make("funnel", NULL);
-			sink = gst_element_factory_make("fakesink", NULL);
-			g_object_set(G_OBJECT(sink), "async", FALSE, NULL);
-			gst_bin_add(GST_BIN(priv->confbin), sink);
-			gst_element_set_state(sink, GST_STATE_PLAYING);
-			stream->fakesink = sink;
-#ifdef HAVE_MEDIA_APPLICATION
-		} else if (codec->media_type == FS_MEDIA_TYPE_APPLICATION) {
-			stream->src = gst_element_factory_make("funnel", NULL);
-			sink = purple_media_manager_get_element(
-					purple_media_get_manager(priv->media),
-					PURPLE_MEDIA_RECV_APPLICATION, priv->media,
-					stream->session->id,
-					stream->participant);
-			gst_bin_add(GST_BIN(priv->confbin), sink);
-			gst_element_set_state(sink, GST_STATE_PLAYING);
-#endif
-		}
-		stream->tee = gst_element_factory_make("tee", NULL);
-		gst_bin_add_many(GST_BIN(priv->confbin),
-				stream->src, stream->tee, NULL);
-		gst_element_set_state(stream->tee, GST_STATE_PLAYING);
-		gst_element_set_state(stream->src, GST_STATE_PLAYING);
-		gst_element_link_many(stream->src, stream->tee, sink, NULL);
-	} else {
-		if (codec->media_type == FS_MEDIA_TYPE_AUDIO) {
-			GstElement *convert, *resample, *capsfilter;
-			GstPad *mixer_srcpad;
-			GstCaps *caps;
-
-			/* The audiomixer element requires that all input
-			 * streams have the same rate, so resample if
-			 * needed
-			 */
-			mixer_srcpad = gst_element_get_static_pad(stream->src, "src");
-			caps = gst_pad_get_current_caps(mixer_srcpad);
-
-			if (caps) {
-				convert = gst_element_factory_make("audioconvert", NULL);
-				resample = gst_element_factory_make("audioresample", NULL);
-				capsfilter = gst_element_factory_make("capsfilter", NULL);
-
-				gst_bin_add_many(GST_BIN(priv->confbin), convert,
-						resample, capsfilter, NULL);
-				gst_element_link_many(gst_pad_get_parent_element(srcpad),
-						convert, resample, capsfilter, NULL);
-
-				g_object_set(capsfilter, "caps", caps, NULL);
-				gst_element_set_state(convert, GST_STATE_PLAYING);
-				gst_element_set_state(resample, GST_STATE_PLAYING);
-				gst_element_set_state(capsfilter, GST_STATE_PLAYING);
-
-				srcpad = gst_element_get_static_pad(capsfilter, "src");
-				gst_object_unref(caps);
-			}
-			gst_object_unref(mixer_srcpad);
-		}
-	}
-
-#if GST_CHECK_VERSION(1, 19, 1)
-	sinkpad = gst_element_request_pad_simple(stream->src, "sink_%u");
-#else
-	sinkpad = gst_element_get_request_pad(stream->src, "sink_%u");
-#endif
-	gst_pad_link(srcpad, sinkpad);
-	gst_object_unref(sinkpad);
-
-	stream->connected_cb_id = g_timeout_add(0,
-			(GSourceFunc)src_pad_added_cb_cb, stream);
-}
-
-static gboolean
-create_stream(PurpleMediaBackendFs2 *self,
-		const gchar *sess_id, const gchar *who,
-		PurpleMediaSessionType type, gboolean initiator,
-		const gchar *transmitter,
-		GHashTable *params)
-{
-	PurpleMediaBackendFs2Private *priv =
-			purple_media_backend_fs2_get_instance_private(self);
-	GError *err = NULL;
-	FsStream *fsstream = NULL;
-	const gchar *stun_ip = purple_network_get_stun_ip();
-	const gchar *turn_ip = purple_network_get_turn_ip();
-	GHashTableIter iter;
-	GHashTable *our_params = NULL;
-	gchar *key = NULL;
-	GValue *value = NULL;
-	GList *our_values = NULL;
-	FsStreamDirection type_direction =
-			session_type_to_fs_stream_direction(type);
-	PurpleMediaBackendFs2Session *session;
-	PurpleMediaBackendFs2Stream *stream;
-	FsParticipant *participant;
-	/* check if the protocol has already specified a relay-info
-	  we need to do this to allow them to override when using non-standard
-	  TURN modes, like Google f.ex. */
-	gboolean got_turn_from_protocol = FALSE;
-	gboolean ret;
-
-	session = get_session(self, sess_id);
-
-	if (session == NULL) {
-		purple_debug_error("backend-fs2",
-				"Couldn't find session to create stream.\n");
-		return FALSE;
-	}
-
-	participant = get_participant(self, who);
-
-	if (participant == NULL) {
-		purple_debug_error("backend-fs2", "Couldn't find "
-				"participant to create stream.\n");
-		return FALSE;
-	}
-
-	fsstream = fs_session_new_stream(session->session, participant,
-			initiator == TRUE ? type_direction :
-			(type_direction & FS_DIRECTION_RECV), &err);
-
-	if (fsstream == NULL) {
-		if (err) {
-			purple_debug_error("backend-fs2", "Error creating stream: %s\n",
-			                   err->message ? err->message : "NULL");
-			g_error_free(err);
-		} else
-			purple_debug_error("backend-fs2",
-					"Error creating stream\n");
-		return FALSE;
-	}
-
-	our_params = g_hash_table_new(g_str_hash, g_str_equal);
-	if (params != NULL) {
-		g_hash_table_iter_init(&iter, params);
-		while (g_hash_table_iter_next(&iter, (gpointer)&key, (gpointer)&value)) {
-			if (purple_strequal(key, "relay-info")) {
-				got_turn_from_protocol = TRUE;
-			}
-			g_hash_table_insert(our_params, key, value);
-		}
-	}
-
-	/* set the controlling mode parameter */
-	value = g_new(GValue, 1);
-	g_value_init(value, G_TYPE_BOOLEAN);
-	g_value_set_boolean(value, initiator);
-	our_values = g_list_prepend(our_values, value);
-	g_hash_table_insert(our_params, "controlling-mode", value);
-
-	if (stun_ip) {
-		purple_debug_info("backend-fs2",
-			"Setting stun-ip on new stream: %s\n", stun_ip);
-
-		value = g_new(GValue, 1);
-		g_value_init(value, G_TYPE_STRING);
-		g_value_set_string(value, stun_ip);
-		our_values = g_list_prepend(our_values, value);
-		g_hash_table_insert(our_params, "stun-ip", value);
-	}
-
-	if (turn_ip && purple_strequal("nice", transmitter) && !got_turn_from_protocol) {
-		GPtrArray *relay_info = g_ptr_array_new_full(1, (GDestroyNotify)gst_structure_free);
-		gint port;
-		const gchar *username =	purple_prefs_get_string(
-				"/purple/network/turn_username");
-		const gchar *password = purple_prefs_get_string(
-				"/purple/network/turn_password");
-
-		/* UDP */
-		port = purple_prefs_get_int("/purple/network/turn_port");
-		if (port > 0) {
-			g_ptr_array_add (relay_info,
-				gst_structure_new ("relay-info",
-				"ip", G_TYPE_STRING, turn_ip,
-				"port", G_TYPE_UINT, port,
-				"username", G_TYPE_STRING, username,
-				"password", G_TYPE_STRING, password,
-				"relay-type", G_TYPE_STRING, "udp",
-				NULL));
-		}
-
-		/* TCP */
-		port = purple_prefs_get_int("/purple/network/turn_port_tcp");
-		if (port > 0) {
-			g_ptr_array_add (relay_info,
-				gst_structure_new ("relay-info",
-				"ip", G_TYPE_STRING, turn_ip,
-				"port", G_TYPE_UINT, port,
-				"username", G_TYPE_STRING, username,
-				"password", G_TYPE_STRING, password,
-				"relay-type", G_TYPE_STRING, "tcp",
-				NULL));
-		}
-
-		/* TURN over SSL is only supported by libnice for Google's "pseudo" SSL mode
-			at this time */
-
-		purple_debug_info("backend-fs2",
-			"Setting relay-info on new stream\n");
-		value = g_new(GValue, 1);
-		g_value_init(value, G_TYPE_PTR_ARRAY);
-		g_value_take_boxed(value, relay_info);
-		our_values = g_list_prepend(our_values, value);
-		g_hash_table_insert(our_params, "relay-info", value);
-	}
-
-	ret = fs_stream_set_transmitter_ht(fsstream, transmitter, our_params, &err);
-
-	while (our_values != NULL) {
-		value = (GValue *)our_values->data;
-		g_value_unset(value);
-		g_free(value);
-		our_values = g_list_delete_link(our_values, our_values);
-	}
-	g_hash_table_destroy(our_params);
-	if (ret == FALSE) {
-		purple_debug_error("backend-fs2",
-			"Could not set transmitter %s: %s.\n",
-			transmitter, err ? err->message : NULL);
-		g_clear_error(&err);
-		return FALSE;
-	}
-
-	stream = g_new0(PurpleMediaBackendFs2Stream, 1);
-	stream->participant = g_strdup(who);
-	stream->session = session;
-	stream->stream = fsstream;
-	stream->supports_add = purple_strequal(transmitter, "nice");
-
-	priv->streams =	g_list_append(priv->streams, stream);
-
-	g_signal_connect(G_OBJECT(fsstream), "src-pad-added",
-			G_CALLBACK(src_pad_added_cb), stream);
-
-	return TRUE;
-}
-
-static void
-free_stream(PurpleMediaBackendFs2Stream *stream)
-{
-	/* Remove the connected_cb timeout */
-	if (stream->connected_cb_id != 0)
-		g_source_remove(stream->connected_cb_id);
-
-	g_free(stream->participant);
-
-	if (stream->local_candidates)
-		fs_candidate_list_destroy(stream->local_candidates);
-
-	if (stream->remote_candidates)
-		fs_candidate_list_destroy(stream->remote_candidates);
-
-	g_free(stream);
-}
-
-static gboolean
-purple_media_backend_fs2_add_stream(PurpleMediaBackend *self,
-		const gchar *sess_id, const gchar *who,
-		PurpleMediaSessionType type, gboolean initiator,
-		const gchar *transmitter, GHashTable *params)
-{
-	PurpleMediaBackendFs2 *backend = PURPLE_MEDIA_BACKEND_FS2(self);
-	PurpleMediaBackendFs2Private *priv =
-			purple_media_backend_fs2_get_instance_private(backend);
-	PurpleMediaBackendFs2Stream *stream;
-
-	if (priv->conference == NULL && !init_conference(backend)) {
-		purple_debug_error("backend-fs2",
-				"Error initializing the conference.\n");
-		return FALSE;
-	}
-
-	if (get_session(backend, sess_id) == NULL &&
-			!create_session(backend, sess_id, type,
-			initiator, transmitter)) {
-		purple_debug_error("backend-fs2",
-				"Error creating the session.\n");
-		return FALSE;
-	}
-
-	if (get_participant(backend, who) == NULL &&
-			!create_participant(backend, who)) {
-		purple_debug_error("backend-fs2",
-				"Error creating the participant.\n");
-		return FALSE;
-	}
-
-	stream = get_stream(backend, sess_id, who);
-
-	if (stream != NULL) {
-		FsStreamDirection type_direction =
-				session_type_to_fs_stream_direction(type);
-
-		if (session_type_to_fs_stream_direction(
-				stream->session->type) != type_direction) {
-			/* change direction */
-			g_object_set(stream->stream, "direction",
-					type_direction, NULL);
-		}
-	} else if (!create_stream(backend, sess_id, who, type,
-			initiator, transmitter, params)) {
-		purple_debug_error("backend-fs2",
-				"Error creating the stream.\n");
-		return FALSE;
-	}
-
-	return TRUE;
-}
-
-static void
-purple_media_backend_fs2_add_remote_candidates(PurpleMediaBackend *self,
-		const gchar *sess_id, const gchar *participant,
-		GList *remote_candidates)
-{
-	PurpleMediaBackendFs2Private *priv;
-	PurpleMediaBackendFs2Stream *stream;
-	GError *err = NULL;
-
-	g_return_if_fail(PURPLE_MEDIA_IS_BACKEND_FS2(self));
-
-	priv = purple_media_backend_fs2_get_instance_private(
-			PURPLE_MEDIA_BACKEND_FS2(self));
-	stream = get_stream(PURPLE_MEDIA_BACKEND_FS2(self),
-			sess_id, participant);
-
-	if (stream == NULL) {
-		purple_debug_error("backend-fs2",
-				"purple_media_add_remote_candidates: "
-				"couldn't find stream %s %s.\n",
-				sess_id ? sess_id : "(null)",
-				participant ? participant : "(null)");
-		return;
-	}
-
-	stream->remote_candidates = g_list_concat(stream->remote_candidates,
-	        g_list_copy_deep(remote_candidates, (GCopyFunc)candidate_to_fs, NULL));
-
-	if (purple_media_is_initiator(priv->media, sess_id, participant) ||
-			purple_media_accepted(
-			priv->media, sess_id, participant)) {
-
-		if (stream->supports_add)
-			fs_stream_add_remote_candidates(stream->stream,
-					stream->remote_candidates, &err);
-		else
-			fs_stream_force_remote_candidates(stream->stream,
-					stream->remote_candidates, &err);
-
-		if (err) {
-			purple_debug_error("backend-fs2", "Error adding remote"
-					" candidates: %s\n", err->message);
-			g_error_free(err);
-		}
-	}
-}
-
-static gboolean
-purple_media_backend_fs2_codecs_ready(PurpleMediaBackend *self,
-		const gchar *sess_id)
-{
-	PurpleMediaBackendFs2Private *priv;
-	gboolean ret = FALSE;
-
-	g_return_val_if_fail(PURPLE_MEDIA_IS_BACKEND_FS2(self), FALSE);
-
-	priv = purple_media_backend_fs2_get_instance_private(
-			PURPLE_MEDIA_BACKEND_FS2(self));
-
-	if (sess_id != NULL) {
-		PurpleMediaBackendFs2Session *session = get_session(
-				PURPLE_MEDIA_BACKEND_FS2(self), sess_id);
-
-		if (session == NULL)
-			return FALSE;
-
-		if (session->type & (PURPLE_MEDIA_SEND_AUDIO |
-#ifdef HAVE_MEDIA_APPLICATION
-				PURPLE_MEDIA_SEND_APPLICATION |
-#endif
-				PURPLE_MEDIA_SEND_VIDEO)) {
-
-			GList *codecs = NULL;
-
-			g_object_get(session->session,
-					"codecs", &codecs, NULL);
-			if (codecs) {
-				fs_codec_list_destroy (codecs);
-				ret = TRUE;
-			}
-		} else
-			ret = TRUE;
-	} else {
-		GList *values = g_hash_table_get_values(priv->sessions);
-
-		for (; values; values = g_list_delete_link(values, values)) {
-			PurpleMediaBackendFs2Session *session = values->data;
-
-			if (session->type & (PURPLE_MEDIA_SEND_AUDIO |
-#ifdef HAVE_MEDIA_APPLICATION
-					PURPLE_MEDIA_SEND_APPLICATION |
-#endif
-					PURPLE_MEDIA_SEND_VIDEO)) {
-
-				GList *codecs = NULL;
-
-				g_object_get(session->session,
-						"codecs", &codecs, NULL);
-				if (codecs) {
-					fs_codec_list_destroy (codecs);
-					ret = TRUE;
-				} else {
-					ret = FALSE;
-					break;
-				}
-			} else
-				ret = TRUE;
-		}
-
-		if (values != NULL)
-			g_list_free(values);
-	}
-
-	return ret;
-}
-
-static GList *
-purple_media_backend_fs2_get_codecs(PurpleMediaBackend *self,
-		const gchar *sess_id)
-{
-	PurpleMediaBackendFs2Session *session;
-	GList *fscodecs;
-	GList *codecs;
-
-	g_return_val_if_fail(PURPLE_MEDIA_IS_BACKEND_FS2(self), NULL);
-
-	session = get_session(PURPLE_MEDIA_BACKEND_FS2(self), sess_id);
-
-	if (session == NULL)
-		return NULL;
-
-	g_object_get(G_OBJECT(session->session),
-		     "codecs", &fscodecs, NULL);
-	codecs = g_list_copy_deep(fscodecs, (GCopyFunc)codec_from_fs, NULL);
-	fs_codec_list_destroy(fscodecs);
-
-	return codecs;
-}
-
-static GList *
-purple_media_backend_fs2_get_local_candidates(PurpleMediaBackend *self,
-		const gchar *sess_id, const gchar *participant)
-{
-	PurpleMediaBackendFs2Stream *stream;
-	GList *candidates = NULL;
-
-	g_return_val_if_fail(PURPLE_MEDIA_IS_BACKEND_FS2(self), NULL);
-
-	stream = get_stream(PURPLE_MEDIA_BACKEND_FS2(self),
-			sess_id, participant);
-
-	if (stream != NULL) {
-		candidates = g_list_copy_deep(stream->local_candidates,
-		                              (GCopyFunc)candidate_from_fs, NULL);
-	}
-	return candidates;
-}
-
-static gboolean
-purple_media_backend_fs2_set_remote_codecs(PurpleMediaBackend *self,
-		const gchar *sess_id, const gchar *participant,
-		GList *codecs)
-{
-	PurpleMediaBackendFs2Stream *stream;
-	GList *fscodecs;
-	GError *err = NULL;
-
-	g_return_val_if_fail(PURPLE_MEDIA_IS_BACKEND_FS2(self), FALSE);
-	stream = get_stream(PURPLE_MEDIA_BACKEND_FS2(self),
-			sess_id, participant);
-
-	if (stream == NULL)
-		return FALSE;
-
-	fscodecs = g_list_copy_deep(codecs, (GCopyFunc)codec_to_fs, NULL);
-	fs_stream_set_remote_codecs(stream->stream, fscodecs, &err);
-	fs_codec_list_destroy(fscodecs);
-
-	if (err) {
-		purple_debug_error("backend-fs2",
-				"Error setting remote codecs: %s\n",
-				err->message);
-		g_error_free(err);
-		return FALSE;
-	}
-
-	return TRUE;
-}
-
-static GstStructure *
-create_fs2_srtp_structure(const gchar *cipher, const gchar *auth,
-	const gchar *key, gsize key_len)
-{
-	GstStructure *result;
-	GstBuffer *buffer;
-	GstMapInfo info;
-
-	buffer = gst_buffer_new_allocate(NULL, key_len, NULL);
-	gst_buffer_map(buffer, &info, GST_MAP_WRITE);
-	memcpy(info.data, key, key_len);
-	gst_buffer_unmap(buffer, &info);
-
-	result = gst_structure_new("FarstreamSRTP",
-			"cipher", G_TYPE_STRING, cipher,
-			"auth", G_TYPE_STRING, auth,
-			"key", GST_TYPE_BUFFER, buffer,
-			NULL);
-	gst_buffer_unref(buffer);
-
-	return result;
-}
-
-static gboolean
-purple_media_backend_fs2_set_encryption_parameters (PurpleMediaBackend *self,
-		const gchar *sess_id, const gchar *cipher, const gchar *auth,
-		const gchar *key, gsize key_len)
-{
-	PurpleMediaBackendFs2Session *session;
-	GstStructure *srtp;
-	GError *err = NULL;
-	gboolean result;
-
-	g_return_val_if_fail(PURPLE_MEDIA_IS_BACKEND_FS2(self), FALSE);
-
-	session = get_session(PURPLE_MEDIA_BACKEND_FS2(self), sess_id);
-	if (!session)
-		return FALSE;
-
-	srtp = create_fs2_srtp_structure(cipher, auth, key, key_len);
-	if (!srtp)
-		return FALSE;
-
-	result = fs_session_set_encryption_parameters(session->session, srtp,
-						&err);
-	if (!result) {
-		purple_debug_error("backend-fs2",
-				"Error setting encryption parameters: %s\n", err->message);
-		g_error_free(err);
-	}
-
-	gst_structure_free(srtp);
-	return result;
-}
-
-static gboolean
-purple_media_backend_fs2_set_decryption_parameters (PurpleMediaBackend *self,
-		const gchar *sess_id, const gchar *participant,
-		const gchar *cipher, const gchar *auth,
-		const gchar *key, gsize key_len)
-{
-	PurpleMediaBackendFs2Stream *stream;
-	GstStructure *srtp;
-	GError *err = NULL;
-	gboolean result;
-
-	g_return_val_if_fail(PURPLE_MEDIA_IS_BACKEND_FS2(self), FALSE);
-
-	stream = get_stream(PURPLE_MEDIA_BACKEND_FS2(self), sess_id,
-			participant);
-	if (!stream)
-		return FALSE;
-
-	srtp = create_fs2_srtp_structure(cipher, auth, key, key_len);
-	if (!srtp)
-		return FALSE;
-
-	result = fs_stream_set_decryption_parameters(stream->stream, srtp,
-						&err);
-	if (!result) {
-		purple_debug_error("backend-fs2",
-				"Error setting decryption parameters: %s\n", err->message);
-		g_error_free(err);
-	}
-
-	gst_structure_free(srtp);
-	return result;
-}
-
-static gboolean
-purple_media_backend_fs2_set_require_encryption(PurpleMediaBackend *self,
-		const gchar *sess_id, const gchar *participant,
-		gboolean require_encryption)
-{
-	PurpleMediaBackendFs2Stream *stream;
-
-	stream = get_stream(PURPLE_MEDIA_BACKEND_FS2(self), sess_id,
-			participant);
-	if (!stream) {
-		return FALSE;
-	}
-
-	g_object_set(stream->stream, "require-encryption",
-			require_encryption, NULL);
-	return TRUE;
-}
-
-static gboolean
-purple_media_backend_fs2_set_send_codec(PurpleMediaBackend *self,
-		const gchar *sess_id, PurpleMediaCodec *codec)
-{
-	PurpleMediaBackendFs2Session *session;
-	FsCodec *fscodec;
-	GError *err = NULL;
-
-	g_return_val_if_fail(PURPLE_MEDIA_IS_BACKEND_FS2(self), FALSE);
-
-	session = get_session(PURPLE_MEDIA_BACKEND_FS2(self), sess_id);
-
-	if (session == NULL)
-		return FALSE;
-
-	fscodec = codec_to_fs(codec);
-	fs_session_set_send_codec(session->session, fscodec, &err);
-	fs_codec_destroy(fscodec);
-
-	if (err) {
-		purple_debug_error("media", "Error setting send codec\n");
-		g_error_free(err);
-		return FALSE;
-	}
-
-	return TRUE;
-}
-
-static const gchar **
-purple_media_backend_fs2_get_available_params(void)
-{
-	static const gchar *supported_params[] = {
-		"sdes-cname", "sdes-email", "sdes-location", "sdes-name", "sdes-note",
-		"sdes-phone", "sdes-tool", NULL
-	};
-
-	return supported_params;
-}
-
-static const gchar*
-param_to_sdes_type(const gchar *param)
-{
-	const gchar **supported = purple_media_backend_fs2_get_available_params();
-	static const gchar *sdes_types[] = {
-		"cname", "email", "location", "name", "note", "phone", "tool", NULL
-	};
-	guint i;
-
-	for (i = 0; supported[i] != NULL; ++i) {
-		if (purple_strequal(param, supported[i])) {
-			return sdes_types[i];
-		}
-	}
-
-	return NULL;
-}
-
-static void
-purple_media_backend_fs2_set_params(PurpleMediaBackend *self,
-		GHashTable *params)
-{
-	PurpleMediaBackendFs2Private *priv;
-	GHashTableIter iter;
-	gchar *name = NULL;
-	GValue *value = NULL;
-	GstStructure *sdes;
-
-	g_return_if_fail(PURPLE_MEDIA_IS_BACKEND_FS2(self));
-
-	priv = purple_media_backend_fs2_get_instance_private(
-			PURPLE_MEDIA_BACKEND_FS2(self));
-
-	if (priv->conference == NULL &&
-		!init_conference(PURPLE_MEDIA_BACKEND_FS2(self))) {
-		purple_debug_error("backend-fs2",
-				"Error initializing the conference.\n");
-		return;
-	}
-
-	g_object_get(G_OBJECT(priv->conference), "sdes", &sdes, NULL);
-
-	g_hash_table_iter_init(&iter, params);
-	while (g_hash_table_iter_next(&iter, (gpointer)&name, (gpointer)&value)) {
-		const gchar *sdes_type = param_to_sdes_type(name);
-		if (!sdes_type) {
-			continue;
-		}
-
-		gst_structure_set(sdes, sdes_type,
-		                  G_TYPE_STRING, g_value_get_string(value),
-		                  NULL);
-	}
-
-	g_object_set(G_OBJECT(priv->conference), "sdes", sdes, NULL);
-	gst_structure_free(sdes);
-}
-static gboolean
-send_dtmf_callback(gpointer userdata)
-{
-	FsSession *session = userdata;
-
-	fs_session_stop_telephony_event(session);
-
-	return FALSE;
-}
-static gboolean
-purple_media_backend_fs2_send_dtmf(PurpleMediaBackend *self,
-		const gchar *sess_id, gchar dtmf, guint8 volume,
-		guint16 duration)
-{
-	PurpleMediaBackendFs2Session *session;
-	FsDTMFEvent event;
-
-	g_return_val_if_fail(PURPLE_MEDIA_IS_BACKEND_FS2(self), FALSE);
-
-	session = get_session(PURPLE_MEDIA_BACKEND_FS2(self), sess_id);
-	if (session == NULL)
-		return FALSE;
-
-	/* Convert DTMF char into FsDTMFEvent enum */
-	switch(dtmf) {
-		case '0': event = FS_DTMF_EVENT_0; break;
-		case '1': event = FS_DTMF_EVENT_1; break;
-		case '2': event = FS_DTMF_EVENT_2; break;
-		case '3': event = FS_DTMF_EVENT_3; break;
-		case '4': event = FS_DTMF_EVENT_4; break;
-		case '5': event = FS_DTMF_EVENT_5; break;
-		case '6': event = FS_DTMF_EVENT_6; break;
-		case '7': event = FS_DTMF_EVENT_7; break;
-		case '8': event = FS_DTMF_EVENT_8; break;
-		case '9': event = FS_DTMF_EVENT_9; break;
-		case '*': event = FS_DTMF_EVENT_STAR; break;
-		case '#': event = FS_DTMF_EVENT_POUND; break;
-		case 'A': event = FS_DTMF_EVENT_A; break;
-		case 'B': event = FS_DTMF_EVENT_B; break;
-		case 'C': event = FS_DTMF_EVENT_C; break;
-		case 'D': event = FS_DTMF_EVENT_D; break;
-		default:
-			return FALSE;
-	}
-
-	if (!fs_session_start_telephony_event(session->session,
-			event, volume)) {
-		return FALSE;
-	}
-
-	if (duration <= 50) {
-		fs_session_stop_telephony_event(session->session);
-	} else {
-		g_timeout_add(duration, send_dtmf_callback,
-				session->session);
-	}
-
-	return TRUE;
-}
-#else
-GType
-purple_media_backend_fs2_get_type(void)
-{
-	return G_TYPE_NONE;
-}
-#endif /* USE_VV */
-
-GstElement *
-purple_media_backend_fs2_get_src(PurpleMediaBackendFs2 *self,
-		const gchar *sess_id)
-{
-#ifdef USE_VV
-	PurpleMediaBackendFs2Session *session = get_session(self, sess_id);
-	return session != NULL ? session->src : NULL;
-#else
-	return NULL;
-#endif
-}
-
-GstElement *
-purple_media_backend_fs2_get_tee(PurpleMediaBackendFs2 *self,
-		const gchar *sess_id, const gchar *who)
-{
-#ifdef USE_VV
-	if (sess_id != NULL && who == NULL) {
-		PurpleMediaBackendFs2Session *session =
-				get_session(self, sess_id);
-		return (session != NULL) ? session->tee : NULL;
-	} else if (sess_id != NULL && who != NULL) {
-		PurpleMediaBackendFs2Stream *stream =
-				get_stream(self, sess_id, who);
-		return (stream != NULL) ? stream->tee : NULL;
-	}
-
-#endif /* USE_VV */
-	g_return_val_if_reached(NULL);
-}
-
-void
-purple_media_backend_fs2_set_input_volume(PurpleMediaBackendFs2 *self,
-		const gchar *sess_id, double level)
-{
-#ifdef USE_VV
-	PurpleMediaBackendFs2Private *priv;
-	GList *sessions;
-
-	g_return_if_fail(PURPLE_MEDIA_IS_BACKEND_FS2(self));
-
-	priv = purple_media_backend_fs2_get_instance_private(self);
-
-	purple_prefs_set_int("/purple/media/audio/volume/input", level);
-
-	if (sess_id == NULL)
-		sessions = g_hash_table_get_values(priv->sessions);
-	else
-		sessions = g_list_append(NULL, get_session(self, sess_id));
-
-	for (; sessions; sessions = g_list_delete_link(sessions, sessions)) {
-		PurpleMediaBackendFs2Session *session = sessions->data;
-
-		if (session->type & PURPLE_MEDIA_SEND_AUDIO) {
-			gchar *name = g_strdup_printf("volume_%s",
-					session->id);
-			GstElement *volume = gst_bin_get_by_name(
-					GST_BIN(priv->confbin), name);
-			g_free(name);
-			g_object_set(volume, "volume", level/10.0, NULL);
-		}
-	}
-#endif /* USE_VV */
-}
-
-void
-purple_media_backend_fs2_set_output_volume(PurpleMediaBackendFs2 *self,
-		const gchar *sess_id, const gchar *who, double level)
-{
-#ifdef USE_VV
-	GList *streams;
-
-	g_return_if_fail(PURPLE_MEDIA_IS_BACKEND_FS2(self));
-
-	purple_prefs_set_int("/purple/media/audio/volume/output", level);
-
-	streams = get_streams(self, sess_id, who);
-
-	for (; streams; streams = g_list_delete_link(streams, streams)) {
-		PurpleMediaBackendFs2Stream *stream = streams->data;
-
-		if (stream->session->type & PURPLE_MEDIA_RECV_AUDIO
-				&& GST_IS_ELEMENT(stream->volume)) {
-			g_object_set(stream->volume, "volume",
-					level/10.0, NULL);
-		}
-	}
-#endif /* USE_VV */
-}
-
-#ifdef USE_VV
-static gboolean
-purple_media_backend_fs2_set_send_rtcp_mux(PurpleMediaBackend *self,
-		const gchar *sess_id, const gchar *participant,
-		gboolean send_rtcp_mux)
-{
-	PurpleMediaBackendFs2Stream *stream;
-
-	g_return_val_if_fail(PURPLE_MEDIA_IS_BACKEND_FS2(self), FALSE);
-	stream = get_stream(PURPLE_MEDIA_BACKEND_FS2(self),
-			sess_id, participant);
-
-	if (stream != NULL &&
-		g_object_class_find_property (G_OBJECT_GET_CLASS (stream->stream),
-			"send-rtcp-mux") != NULL) {
-		g_object_set (stream->stream, "send-rtcp-mux", send_rtcp_mux, NULL);
-		return TRUE;
-	}
-
-	return FALSE;
-}
-#endif /* USE_VV */
diff --git a/libpurple/mediamanager.c b/libpurple/mediamanager.c
--- a/libpurple/mediamanager.c
+++ b/libpurple/mediamanager.c
@@ -31,10 +31,8 @@
 #include "purplepath.h"
 
 #include "media-gst.h"
-#include <media/backend-fs2.h>
 
 #ifdef USE_VV
-#include <farstream/fs-element-added-notifier.h>
 #include <gst/video/videooverlay.h>
 #ifdef HAVE_MEDIA_APPLICATION
 #include <gst/app/app.h>
@@ -194,7 +192,6 @@
 	media->priv->medias = NULL;
 	media->priv->private_medias = NULL;
 	media->priv->next_output_window_id = 1;
-	media->priv->backend_type = PURPLE_MEDIA_TYPE_BACKEND_FS2;
 #ifdef HAVE_MEDIA_APPLICATION
 	media->priv->appdata_info = NULL;
 	g_mutex_init (&media->priv->appdata_mutex);
@@ -300,10 +297,6 @@
 	g_return_val_if_fail(PURPLE_IS_MEDIA_MANAGER(manager), NULL);
 
 	if (manager->priv->pipeline == NULL) {
-		FsElementAddedNotifier *notifier;
-		gchar *filename;
-		GError *err = NULL;
-		GKeyFile *keyfile;
 		GstBus *bus;
 		manager->priv->pipeline = gst_pipeline_new(NULL);
 
@@ -315,38 +308,6 @@
 		gst_bus_set_sync_handler(bus, gst_bus_sync_signal_handler, NULL, NULL);
 		gst_object_unref(bus);
 
-		filename = g_build_filename(purple_config_dir(),
-				"fs-element.conf", NULL);
-		keyfile = g_key_file_new();
-		if (!g_key_file_load_from_file(keyfile, filename,
-				G_KEY_FILE_NONE, &err)) {
-			if (err->code == 4)
-				purple_debug_info("mediamanager",
-						"Couldn't read "
-						"fs-element.conf: %s\n",
-						err->message);
-			else
-				purple_debug_error("mediamanager",
-						"Error reading "
-						"fs-element.conf: %s\n",
-						err->message);
-			g_error_free(err);
-		}
-		g_free(filename);
-
-		/* Hack to make alsasrc stop messing up audio timestamps */
-		if (!g_key_file_has_key(keyfile,
-				"alsasrc", "slave-method", NULL)) {
-			g_key_file_set_integer(keyfile,
-					"alsasrc", "slave-method", 2);
-		}
-
-		notifier = fs_element_added_notifier_new();
-		fs_element_added_notifier_add(notifier,
-				GST_BIN(manager->priv->pipeline));
-		fs_element_added_notifier_set_properties_from_keyfile(
-				notifier, keyfile);
-
 		gst_element_set_state(manager->priv->pipeline,
 				GST_STATE_PLAYING);
 	}
diff --git a/libpurple/meson.build b/libpurple/meson.build
--- a/libpurple/meson.build
+++ b/libpurple/meson.build
@@ -20,7 +20,6 @@
 	'idle.c',
 	'image.c',
 	'image-store.c',
-	'media/backend-fs2.c',
 	'media/backend-iface.c',
 	'media/candidate.c',
 	'media/codec.c',
@@ -296,7 +295,7 @@
                     version : PURPLE_LIB_VERSION,
                     dependencies : # static_link_libs
                         [dnsapi, ws2_32, glib, gio, gplugin_dep, libsoup,
-                         libxml, farstream, gstreamer, gstreamer_video,
+                         libxml, gstreamer, gstreamer_video,
                          gstreamer_app, json, sqlite3, math])
 
 install_headers(purple_coreheaders,
diff --git a/meson.build b/meson.build
--- a/meson.build
+++ b/meson.build
@@ -329,23 +329,17 @@
 conf.set('USE_GSTVIDEO', gstreamer_video.found())
 
 #######################################################################
-# Check for Farstream
-#######################################################################
-farstream = dependency('farstream-0.2', version : '>= 0.2.7',
-                       required : get_option('farstream'))
-
-#######################################################################
 # Check for Voice and Video support
 #######################################################################
 if get_option('vv').enabled() or get_option('vv').auto()
-	if gstreamer_video.found() and farstream.found()
+	if gstreamer_video.found()
 		conf.set('USE_VV', true)
 		enable_vv = true
 	else
 		if get_option('vv').enabled()
 			error('''
 Dependencies for voice/video were not met.
-Install the necessary gstreamer and farstream packages first.
+Install the necessary gstreamer packages first.
 Or use -Dvv=disabled if you do not need voice/video support.
 			''')
 		endif
diff --git a/po/POTFILES.in b/po/POTFILES.in
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -43,7 +43,6 @@
 libpurple/idle.c
 libpurple/image.c
 libpurple/image-store.c
-libpurple/media/backend-fs2.c
 libpurple/media/backend-iface.c
 libpurple/media.c
 libpurple/media/candidate.c
