changeset 23809:7d2e5f57dbca

propagate from branch 'im.pidgin.pidgin.vv' (head 9443004596a4fc55992da8548ef5b438de22c8ef) to branch 'im.pidgin.soc.2008.vv' (head 99d72a9b9b6887865627081565f052f29516d19b)
author Mike Ruprecht <maiku@soc.pidgin.im>
date Tue, 27 May 2008 16:30:26 +0000
parents 903fb6879521 (current diff) e17dbd941380 (diff)
children 10f5a529d2a6
files configure.ac finch/libgnt/pygnt/Files.txt finch/libgnt/pygnt/Makefile.am finch/libgnt/pygnt/Makefile.make finch/libgnt/pygnt/README.txt finch/libgnt/pygnt/common.c finch/libgnt/pygnt/common.h finch/libgnt/pygnt/dbus-gnt finch/libgnt/pygnt/example/rss/gnthtml.py finch/libgnt/pygnt/example/rss/gntrss-ui.py finch/libgnt/pygnt/example/rss/gntrss.py finch/libgnt/pygnt/file.py finch/libgnt/pygnt/gendef.sh finch/libgnt/pygnt/gnt.override finch/libgnt/pygnt/gntbox.override finch/libgnt/pygnt/gntfilesel.override finch/libgnt/pygnt/gntmodule.c finch/libgnt/pygnt/gnttree.override finch/libgnt/pygnt/gntwidget.override finch/libgnt/pygnt/test.py libpurple/Makefile.am libpurple/protocols/jabber/jabber.c libpurple/protocols/jabber/libxmpp.c libpurple/protocols/zephyr/zephyr.h libpurple/server.c pidgin/gtkconv.c pidgin/gtkprefs.c
diffstat 21 files changed, 1092 insertions(+), 745 deletions(-) [+]
line wrap: on
line diff
--- a/configure.ac	Tue May 27 06:51:21 2008 +0000
+++ b/configure.ac	Tue May 27 16:30:26 2008 +0000
@@ -325,6 +325,9 @@
 AC_SUBST(GLIB_CFLAGS)
 AC_SUBST(GLIB_LIBS)
 
+GLIB_GENMARSHAL=`pkg-config --variable=glib_genmarshal glib-2.0`
+AC_SUBST(GLIB_GENMARSHAL)
+
 AC_ARG_WITH([extraversion],
 			AC_HELP_STRING([--with-extraversion=STRING],
 						   [extra version number to be displayed in Help->About and --help (for packagers)]),
@@ -728,16 +731,15 @@
 dnl #######################################################################
 dnl # Check for Farsight
 dnl #######################################################################
-AC_ARG_ENABLE(farsight,
+AC_ARG_ENABLE(vv,
 	[AC_HELP_STRING([--disable-vv], [compile without voice and video support])],
 	enable_farsight="$enableval", enable_farsight="yes")
 if test "x$enable_farsight" != "xno"; then
-	PKG_CHECK_MODULES(FARSIGHT, [farsight-0.1], [
+	PKG_CHECK_MODULES(FARSIGHT, [farsight2-0.10 gstreamer-0.10 gstreamer-plugins-base-0.10 libxml-2.0], [
 		AC_DEFINE(USE_FARSIGHT, 1, [Use Farsight for voice and video])
 		AC_SUBST(FARSIGHT_CFLAGS)
 		AC_SUBST(FARSIGHT_LIBS)
 	], [
-		AC_MSG_RESULT(no)
 		enable_farsight="no"
 	])
 fi
@@ -759,7 +761,6 @@
   		AC_SUBST(GSTPROPS_LIBS)
   		AC_SUBST(GSTPROPS_CFLAGS)
   ], [
-		AC_MSG_RESULT(no)
 		enable_gstprops="no"
   ])
 fi
--- a/finch/gntmedia.c	Tue May 27 06:51:21 2008 +0000
+++ b/finch/gntmedia.c	Tue May 27 16:30:26 2008 +0000
@@ -42,8 +42,6 @@
 /* An incredibly large part of the following is from gtkmedia.c */
 #ifdef USE_FARSIGHT
 
-#include <farsight/farsight.h>
-
 #undef hangup
 
 struct _FinchMediaPrivate
@@ -390,8 +388,6 @@
 				NULL));
 }
 
-#endif  /* USE_FARSIGHT */
-
 static void
 gntmedia_message_cb(FinchMedia *gntmedia, const char *msg, PurpleConversation *conv)
 {
@@ -458,3 +454,5 @@
 			G_CALLBACK(finch_new_media), NULL);
 }
 
+#endif  /* USE_FARSIGHT */
+
--- a/finch/gntmedia.h	Tue May 27 06:51:21 2008 +0000
+++ b/finch/gntmedia.h	Tue May 27 16:30:26 2008 +0000
@@ -33,7 +33,6 @@
 
 #ifdef USE_FARSIGHT
 
-#include <farsight/farsight.h>
 #include <glib-object.h>
 #include "gntbox.h"
 
--- a/finch/gntui.c	Tue May 27 06:51:21 2008 +0000
+++ b/finch/gntui.c	Tue May 27 16:30:26 2008 +0000
@@ -92,8 +92,10 @@
 	finch_roomlist_init();
 	purple_roomlist_set_ui_ops(finch_roomlist_get_ui_ops());
 
+#ifdef USE_FARSIGHT
 	/* Media */
 	finch_media_manager_init();
+#endif
 
 	gnt_register_action(_("Accounts"), finch_accounts_show_all);
 	gnt_register_action(_("Buddy List"), finch_blist_show);
@@ -140,7 +142,9 @@
 	finch_roomlist_uninit();
 	purple_roomlist_set_ui_ops(NULL);
 
+#ifdef USE_FARSIGHT
 	finch_media_manager_uninit();
+#endif
 
 	gnt_quit();
 #endif
--- a/libpurple/Makefile.am	Tue May 27 06:51:21 2008 +0000
+++ b/libpurple/Makefile.am	Tue May 27 16:30:26 2008 +0000
@@ -1,6 +1,7 @@
 EXTRA_DIST = \
 		dbus-analyze-functions.py \
 		dbus-analyze-types.py \
+		marshallers.list \
 		purple-notifications-example \
 		purple-remote \
 		purple-send \
@@ -51,6 +52,7 @@
 	idle.c \
 	imgstore.c \
 	log.c \
+	marshallers.c \
 	media.c \
 	mediamanager.c \
 	mime.c \
@@ -106,6 +108,7 @@
 	idle.h \
 	imgstore.h \
 	log.h \
+	marshallers.h \
 	media.h \
 	mediamanager.h \
 	mime.h \
@@ -141,6 +144,15 @@
 
 purple_builtheaders = purple.h version.h
 
+marshallers.h: marshallers.list
+	@echo "Generating marshallers.h"
+	$(GLIB_GENMARSHAL) --prefix=purple_smarshal $(srcdir)/marshallers.list --header > marshallers.h
+
+marshallers.c: marshallers.list
+	@echo "Generating marshallers.c"
+	echo "#include \"marshallers.h\"" > marshallers.c
+	$(GLIB_GENMARSHAL) --prefix=purple_smarshal $(srcdir)/marshallers.list --body >> marshallers.c
+
 if ENABLE_DBUS
 
 CLEANFILES = \
@@ -149,6 +161,8 @@
 	dbus-client-binding.h \
 	dbus-types.c \
 	dbus-types.h \
+	marshallers.c \
+	marshallers.h \
 	purple-client-bindings.c \
 	purple-client-bindings.h \
 	purple.service
@@ -219,6 +233,8 @@
 	dbus-types.c \
 	dbus-types.h \
 	dbus-bindings.c \
+	marshallers.c \
+	marshallers.h \
 	purple-client-bindings.c \
 	purple-client-bindings.h
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/marshallers.list	Tue May 27 16:30:26 2008 +0000
@@ -0,0 +1,1 @@
+VOID:BOXED,BOXED
--- a/libpurple/media.c	Tue May 27 06:51:21 2008 +0000
+++ b/libpurple/media.c	Tue May 27 16:30:26 2008 +0000
@@ -29,6 +29,7 @@
 
 #include "connection.h"
 #include "media.h"
+#include "marshallers.h"
 
 #include "debug.h"
 
@@ -36,11 +37,11 @@
 #ifdef USE_GSTPROPS
 
 #include <gst/interfaces/propertyprobe.h>
-#include <farsight/farsight.h>
+#include <gst/farsight/fs-conference-iface.h>
 
 struct _PurpleMediaPrivate
 {
-	FarsightSession *farsight_session;
+	FsConference *conference;
 
 	char *name;
 	PurpleConnection *connection;
@@ -49,8 +50,23 @@
 	GstElement *video_src;
 	GstElement *video_sink;
 
-	FarsightStream *audio_stream;
-	FarsightStream *video_stream;
+	FsSession *audio_session;
+	FsSession *video_session;
+
+	GList *participants; 	/* FsParticipant list */
+	GList *audio_streams;	/* FsStream list */
+	GList *video_streams;	/* FsStream list */
+
+	/* might be able to just combine these two */
+	GstElement *audio_pipeline;
+	GstElement *video_pipeline;
+
+	/* this will need to be stored/handled per stream
+	 * once having multiple streams is supported */
+	GList *local_candidates;
+
+	FsCandidate *local_candidate;
+	FsCandidate *remote_candidate;
 };
 
 #define PURPLE_MEDIA_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), PURPLE_TYPE_MEDIA, PurpleMediaPrivate))
@@ -73,21 +89,23 @@
 	REJECT,
 	GOT_HANGUP,
 	GOT_ACCEPT,
+	CANDIDATES_PREPARED,
+	CANDIDATE_PAIR,
 	LAST_SIGNAL
 };
 static guint purple_media_signals[LAST_SIGNAL] = {0};
 
 enum {
 	PROP_0,
-	PROP_FARSIGHT_SESSION,
+	PROP_FS_CONFERENCE,
 	PROP_NAME,
 	PROP_CONNECTION,
 	PROP_AUDIO_SRC,
 	PROP_AUDIO_SINK,
 	PROP_VIDEO_SRC,
 	PROP_VIDEO_SINK,
-	PROP_VIDEO_STREAM,
-	PROP_AUDIO_STREAM
+	PROP_VIDEO_SESSION,
+	PROP_AUDIO_SESSION
 };
 
 GType
@@ -113,7 +131,6 @@
 	return type;
 }
 
-
 static void
 purple_media_class_init (PurpleMediaClass *klass)
 {
@@ -124,11 +141,11 @@
 	gobject_class->set_property = purple_media_set_property;
 	gobject_class->get_property = purple_media_get_property;
 
-	g_object_class_install_property(gobject_class, PROP_FARSIGHT_SESSION,
-			g_param_spec_object("farsight-session",
-			"Farsight session",
-			"The FarsightSession associated with this media.",
-			FARSIGHT_TYPE_SESSION,
+	g_object_class_install_property(gobject_class, PROP_FS_CONFERENCE,
+			g_param_spec_object("farsight-conference",
+			"Farsight conference",
+			"The FsConference associated with this media.",
+			FS_TYPE_CONFERENCE,
 			G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
 
 	g_object_class_install_property(gobject_class, PROP_NAME,
@@ -172,18 +189,18 @@
 			GST_TYPE_ELEMENT,
 			G_PARAM_READWRITE));
 
-	g_object_class_install_property(gobject_class, PROP_VIDEO_STREAM,
-			g_param_spec_object("video-stream",
+	g_object_class_install_property(gobject_class, PROP_VIDEO_SESSION,
+			g_param_spec_object("video-session",
 			"Video stream",
 			"The FarsightStream used for video",
-			FARSIGHT_TYPE_STREAM,
+			FS_TYPE_SESSION,
 			G_PARAM_READWRITE));
 
-	g_object_class_install_property(gobject_class, PROP_AUDIO_STREAM,
-			g_param_spec_object("audio-stream",
+	g_object_class_install_property(gobject_class, PROP_AUDIO_SESSION,
+			g_param_spec_object("audio-session",
 			"Audio stream",
 			"The FarsightStream used for audio",
-			FARSIGHT_TYPE_STREAM,
+			FS_TYPE_SESSION,
 			G_PARAM_READWRITE));
 
 	purple_media_signals[READY] = g_signal_new("ready", G_TYPE_FROM_CLASS(klass),
@@ -214,6 +231,14 @@
 					 G_SIGNAL_RUN_LAST, 0, NULL, NULL,
 					 g_cclosure_marshal_VOID__VOID,
 					 G_TYPE_NONE, 0);
+	purple_media_signals[CANDIDATES_PREPARED] = g_signal_new("candidates-prepared", G_TYPE_FROM_CLASS(klass),
+					 G_SIGNAL_RUN_LAST, 0, NULL, NULL,
+					 g_cclosure_marshal_VOID__VOID,
+					 G_TYPE_NONE, 0);
+	purple_media_signals[CANDIDATE_PAIR] = g_signal_new("candidate-pair", G_TYPE_FROM_CLASS(klass),
+					 G_SIGNAL_RUN_LAST, 0, NULL, NULL,
+					 purple_smarshal_VOID__BOXED_BOXED,
+					 G_TYPE_NONE, 2, FS_TYPE_CANDIDATE, FS_TYPE_CANDIDATE);
 
 	g_type_class_add_private(klass, sizeof(PurpleMediaPrivate));
 }
@@ -241,11 +266,11 @@
 	media = PURPLE_MEDIA(object);
 
 	switch (prop_id) {
-		case PROP_FARSIGHT_SESSION:
-			if (media->priv->farsight_session)
-				g_object_unref(media->priv->farsight_session);
-			media->priv->farsight_session = g_value_get_object(value);
-			g_object_ref(media->priv->farsight_session);
+		case PROP_FS_CONFERENCE:
+			if (media->priv->conference)
+				g_object_unref(media->priv->conference);
+			media->priv->conference = g_value_get_object(value);
+			g_object_ref(media->priv->conference);
 			break;
 		case PROP_NAME:
 			g_free(media->priv->name);
@@ -259,12 +284,16 @@
 				gst_object_unref(media->priv->audio_src);
 			media->priv->audio_src = g_value_get_object(value);
 			gst_object_ref(media->priv->audio_src);
+			gst_bin_add(GST_BIN(purple_media_get_audio_pipeline(media)),
+				    media->priv->audio_src);
 			break;
 		case PROP_AUDIO_SINK:
 			if (media->priv->audio_sink)
 				gst_object_unref(media->priv->audio_sink);
 			media->priv->audio_sink = g_value_get_object(value);
 			gst_object_ref(media->priv->audio_sink);
+			gst_bin_add(GST_BIN(purple_media_get_audio_pipeline(media)),
+				    media->priv->audio_sink);
 			break;
 		case PROP_VIDEO_SRC:
 			if (media->priv->video_src)
@@ -278,17 +307,17 @@
 			media->priv->video_sink = g_value_get_object(value);
 			gst_object_ref(media->priv->video_sink);
 			break;
-		case PROP_VIDEO_STREAM:
-			if (media->priv->video_stream)
-				g_object_unref(media->priv->video_stream);
-			media->priv->video_stream = g_value_get_object(value);
-			gst_object_ref(media->priv->video_stream);
+		case PROP_VIDEO_SESSION:
+			if (media->priv->video_session)
+				g_object_unref(media->priv->video_session);
+			media->priv->video_session = g_value_get_object(value);
+			gst_object_ref(media->priv->video_session);
 			break;
-		case PROP_AUDIO_STREAM:
-			if (media->priv->audio_stream)
-				g_object_unref(media->priv->audio_stream);
-			media->priv->audio_stream = g_value_get_object(value);
-			gst_object_ref(media->priv->audio_stream);
+		case PROP_AUDIO_SESSION:
+			if (media->priv->audio_session)
+				g_object_unref(media->priv->audio_session);
+			media->priv->audio_session = g_value_get_object(value);
+			gst_object_ref(media->priv->audio_session);
 			break;
 
 		default:	
@@ -306,8 +335,8 @@
 	media = PURPLE_MEDIA(object);
 
 	switch (prop_id) {
-		case PROP_FARSIGHT_SESSION:
-			g_value_set_object(value, media->priv->farsight_session);
+		case PROP_FS_CONFERENCE:
+			g_value_set_object(value, media->priv->conference);
 			break;
 		case PROP_NAME:
 			g_value_set_string(value, media->priv->name);
@@ -327,11 +356,11 @@
 		case PROP_VIDEO_SINK:
 			g_value_set_object(value, media->priv->video_sink);
 			break;
-		case PROP_VIDEO_STREAM:
-			g_value_set_object(value, media->priv->video_stream);
+		case PROP_VIDEO_SESSION:
+			g_value_set_object(value, media->priv->video_session);
 			break;
-		case PROP_AUDIO_STREAM:
-			g_value_set_object(value, media->priv->audio_stream);
+		case PROP_AUDIO_SESSION:
+			g_value_set_object(value, media->priv->audio_session);
 			break;
 
 		default:	
@@ -415,12 +444,12 @@
 GstElement *
 purple_media_get_audio_pipeline(PurpleMedia *media)
 {
-	FarsightStream *stream;
-	g_object_get(G_OBJECT(media), "audio-stream", &stream, NULL);
-printf("stream: %d\n\n\n", stream);
-GstElement *l = farsight_stream_get_pipeline(stream);
-printf("Element: %d\n", l);
-	return farsight_stream_get_pipeline(stream);
+	if (!media->priv->audio_pipeline) {
+		media->priv->audio_pipeline = gst_pipeline_new(media->priv->name);
+		gst_bin_add(GST_BIN(media->priv->audio_pipeline), GST_ELEMENT(media->priv->conference));
+	}
+
+	return media->priv->audio_pipeline;
 }
 
 PurpleConnection *
@@ -517,7 +546,7 @@
 			!GST_IS_PROPERTY_PROBE (element) ||
 			!(probe = GST_PROPERTY_PROBE (element)) ||
 			!(pspec = gst_property_probe_get_property (probe, "device"))) {
-		purple_debug_info("Found source '%s' (%s) - no device",
+		purple_debug_info("media", "Found source '%s' (%s) - no device\n",
 				longname, GST_PLUGIN_FEATURE (factory)->name);
 	} else {
 		gint n;
@@ -542,6 +571,12 @@
 				gst_element_set_state (element, GST_STATE_NULL);
 
 				ret = g_list_append(ret, device);
+
+				name = purple_media_get_device_name(GST_ELEMENT(element), device);
+				purple_debug_info("media", "Found source '%s' (%s) - device '%s' (%s)\n",
+						  longname, GST_PLUGIN_FEATURE (factory)->name,
+						  name, g_value_get_string(device));
+				g_free(name);
 			}
 		}
 	}
@@ -631,5 +666,255 @@
 	purple_debug_info("media", "purple_media_audio_init_recv end\n");
 }
 
+static void
+purple_media_new_local_candidate(FsStream *stream,
+				  FsCandidate *local_candidate,
+				  PurpleMedia *media)
+{
+	purple_debug_info("media", "got new local candidate: %s\n", local_candidate->candidate_id);
+	media->priv->local_candidates = g_list_append(media->priv->local_candidates, 
+						      fs_candidate_copy(local_candidate));
+}
+
+static void
+purple_media_candidates_prepared(FsStream *stream, PurpleMedia *media)
+{
+	g_signal_emit(media, purple_media_signals[CANDIDATES_PREPARED], 0);
+}
+
+/* callback called when a pair of transport candidates (local and remote)
+ * has been established */
+static void
+purple_media_candidate_pair_established(FsStream *stream,
+					 FsCandidate *native_candidate,
+					 FsCandidate *remote_candidate,
+					 PurpleMedia *media)
+{
+	media->priv->local_candidate = fs_candidate_copy(native_candidate);
+	media->priv->remote_candidate = fs_candidate_copy(remote_candidate);
+
+	purple_debug_info("media", "candidate pair established\n");
+	g_signal_emit(media, purple_media_signals[CANDIDATE_PAIR], 0,
+		      media->priv->local_candidate,
+		      media->priv->remote_candidate);
+}
+
+static void
+purple_media_src_pad_added(FsStream *stream, GstPad *srcpad,
+			    FsCodec *codec, PurpleMedia *media)
+{
+	GstElement *pipeline = purple_media_get_audio_pipeline(media);
+	GstPad *sinkpad = gst_element_get_static_pad(purple_media_get_audio_sink(media), "ghostsink");
+	purple_debug_info("media", "connecting new src pad: %s\n", 
+			  gst_pad_link(srcpad, sinkpad) == GST_PAD_LINK_OK ? "success" : "failure");
+	gst_element_set_state(pipeline, GST_STATE_PLAYING);
+}
+
+static gboolean
+purple_media_add_stream_internal(PurpleMedia *media, FsSession **session, GList **streams,
+				 GstElement *src, const gchar *who, FsMediaType type,
+				 FsStreamDirection type_direction, const gchar *transmitter)
+{
+	char *cname = NULL;
+	FsParticipant *participant = NULL;
+	GList *l = NULL;
+	FsStream *stream = NULL;
+	FsParticipant *p = NULL;
+	FsStreamDirection *direction = NULL;
+	FsSession *s = NULL;
+
+	if (!*session) {
+		GError *err = NULL;
+		*session = fs_conference_new_session(media->priv->conference, type, &err);
+
+		if (err != NULL) {
+			purple_debug_error("media", "Error creating session: %s\n", err->message);
+			g_error_free(err);
+			purple_conv_present_error(who,
+						  purple_connection_get_account(purple_media_get_connection(media)),
+						  _("Error creating session."));
+			return FALSE;
+		}
+
+		if (src) {
+			GstPad *sinkpad;
+			GstPad *srcpad;
+			g_object_get(*session, "sink-pad", &sinkpad, NULL);
+			srcpad = gst_element_get_static_pad(src, "ghostsrc");
+			purple_debug_info("media", "connecting pad: %s\n", 
+					  gst_pad_link(srcpad, sinkpad) == GST_PAD_LINK_OK
+					  ? "success" : "failure");
+		}
+	}
+	
+	for (l = media->priv->participants; l != NULL; l = g_list_next(l)) {
+		g_object_get(l->data, "cname", cname, NULL);
+		if (!strcmp(cname, who)) {
+			g_free(cname);
+			participant = l->data;
+			break;
+		}
+		g_free(cname);
+	}
+
+	if (!participant) {
+		participant = fs_conference_new_participant(media->priv->conference, (gchar*)who, NULL);
+		media->priv->participants = g_list_prepend(media->priv->participants, participant);
+	}
+	
+	for (l = *streams; l != NULL; l = g_list_next(l)) {
+		g_object_get(l->data, "participant", &p, "direction", &direction, "session", &s, NULL);
+
+		if (participant == p && *session == s) {
+			stream = l->data;
+			break;
+		}
+	}
+
+	if (!stream) {
+		stream = fs_session_new_stream(*session, participant, 
+					       type_direction, transmitter, 0, NULL, NULL);
+		*streams = g_list_prepend(*streams, stream);
+		/* callback for new local candidate (new local candidate retreived) */
+		g_signal_connect(G_OBJECT(stream),
+				 "new-local-candidate", G_CALLBACK(purple_media_new_local_candidate), media);
+		/* callback for source pad added (new stream source ready) */
+		g_signal_connect(G_OBJECT(stream),
+				 "src-pad-added", G_CALLBACK(purple_media_src_pad_added), media);
+		/* callback for local candidates prepared (local candidates ready to send) */
+		g_signal_connect(G_OBJECT(stream), 
+				 "local-candidates-prepared", 
+				 G_CALLBACK(purple_media_candidates_prepared), media);
+		/* callback for new active candidate pair (established connection) */
+		g_signal_connect(G_OBJECT(stream),
+				 "new-active-candidate-pair", 
+				 G_CALLBACK(purple_media_candidate_pair_established), media);
+	} else if (*direction != type_direction) {	
+		/* change direction */
+		g_object_set(stream, "direction", type_direction, NULL);
+	}
+
+	return TRUE;
+}
+
+gboolean
+purple_media_add_stream(PurpleMedia *media, const gchar *who,
+			PurpleMediaStreamType type,
+			const gchar *transmitter)
+{
+	FsStreamDirection type_direction;
+
+	if (type & PURPLE_MEDIA_AUDIO) {
+		if (type & PURPLE_MEDIA_SEND_AUDIO && type & PURPLE_MEDIA_RECV_AUDIO)
+			type_direction = FS_DIRECTION_BOTH;
+		else if (type & PURPLE_MEDIA_SEND_AUDIO)
+			type_direction = FS_DIRECTION_SEND;
+		else if (type & PURPLE_MEDIA_RECV_AUDIO)
+			type_direction = FS_DIRECTION_RECV;
+		else
+			type_direction = FS_DIRECTION_NONE;
+
+		if (!purple_media_add_stream_internal(media, &media->priv->audio_session,
+						      &media->priv->audio_streams,
+				 		      media->priv->audio_src, who,
+						      FS_MEDIA_TYPE_AUDIO, type_direction,
+						      transmitter)) {
+			return FALSE;
+		}
+	}
+	if (type & PURPLE_MEDIA_VIDEO) {
+		if (type & PURPLE_MEDIA_SEND_VIDEO && type & PURPLE_MEDIA_RECV_VIDEO)
+			type_direction = FS_DIRECTION_BOTH;
+		else if (type & PURPLE_MEDIA_SEND_VIDEO)
+			type_direction = FS_DIRECTION_SEND;
+		else if (type & PURPLE_MEDIA_RECV_VIDEO)
+			type_direction = FS_DIRECTION_RECV;
+		else
+			type_direction = FS_DIRECTION_NONE;
+
+		if (!purple_media_add_stream_internal(media, &media->priv->video_session,
+						      &media->priv->video_streams,
+				 		      media->priv->video_src, who,
+						      FS_MEDIA_TYPE_VIDEO, type_direction,
+						      transmitter)) {
+			return FALSE;
+		}
+	}
+	return TRUE;
+}
+
+void
+purple_media_remove_stream(PurpleMedia *media, const gchar *who, PurpleMediaStreamType type)
+{
+	
+}
+
+static FsStream *
+purple_media_get_audio_stream(PurpleMedia *media, const gchar *name)
+{
+	GList *streams = media->priv->audio_streams;
+	for (; streams; streams = streams->next) {
+		FsParticipant *participant;
+		gchar *cname;
+		g_object_get(streams->data, "participant", &participant, NULL);
+		g_object_get(participant, "cname", &cname, NULL);
+
+		if (!strcmp(cname, name)) {
+			return streams->data;
+		}
+	}
+
+	return NULL;
+}
+
+GList *
+purple_media_get_local_audio_codecs(PurpleMedia *media)
+{
+	GList *codecs;
+	g_object_get(G_OBJECT(media->priv->audio_session), "local-codecs", &codecs, NULL);
+	return codecs;
+}
+
+GList *
+purple_media_get_local_audio_candidates(PurpleMedia *media)
+{
+	return media->priv->local_candidates;
+}
+
+GList *
+purple_media_get_negotiated_audio_codecs(PurpleMedia *media)
+{
+	GList *codec_intersection;
+	g_object_get(media->priv->audio_session, "negotiated-codecs", &codec_intersection, NULL);
+	return codec_intersection;
+}
+
+void
+purple_media_add_remote_audio_candidates(PurpleMedia *media, const gchar *name, GList *remote_candidates)
+{
+	FsStream *stream = purple_media_get_audio_stream(media, name);
+	GList *candidates = remote_candidates;
+	for (; candidates; candidates = candidates->next)
+		fs_stream_add_remote_candidate(stream, candidates->data, NULL);
+}
+
+FsCandidate *
+purple_media_get_local_candidate(PurpleMedia *media)
+{
+	return media->priv->local_candidate;
+}
+
+FsCandidate *
+purple_media_get_remote_candidate(PurpleMedia *media)
+{
+	return media->priv->remote_candidate;
+}
+
+void
+purple_media_set_remote_audio_codecs(PurpleMedia *media, const gchar *name, GList *codecs)
+{
+	fs_stream_set_remote_codecs(purple_media_get_audio_stream(media, name), codecs, NULL);
+}
+
 #endif  /* USE_GSTPROPS */
 #endif  /* USE_FARSIGHT */
--- a/libpurple/media.h	Tue May 27 06:51:21 2008 +0000
+++ b/libpurple/media.h	Tue May 27 16:30:26 2008 +0000
@@ -29,7 +29,9 @@
 #ifdef USE_FARSIGHT
 #ifdef USE_GSTPROPS
 
-#include <farsight/farsight.h>
+#include <gst/gst.h>
+#include <gst/farsight/fs-stream.h>
+#include <gst/farsight/fs-session.h>
 #include <glib.h>
 #include <glib-object.h>
 
@@ -53,6 +55,8 @@
 	PURPLE_MEDIA_SEND_AUDIO = 1 << 1,
 	PURPLE_MEDIA_RECV_VIDEO = 1 << 2,
 	PURPLE_MEDIA_SEND_VIDEO = 1 << 3,
+	PURPLE_MEDIA_AUDIO = PURPLE_MEDIA_RECV_AUDIO | PURPLE_MEDIA_SEND_AUDIO,
+	PURPLE_MEDIA_VIDEO = PURPLE_MEDIA_RECV_VIDEO | PURPLE_MEDIA_SEND_VIDEO
 } PurpleMediaStreamType;
 
 struct _PurpleMediaClass
@@ -109,6 +113,20 @@
 
 void purple_media_audio_init_recv(GstElement **recvbin, GstElement **recvlevel);
 
+gboolean purple_media_add_stream(PurpleMedia *media, const gchar *who,
+			     PurpleMediaStreamType type, const gchar *transmitter);
+void purple_media_remove_stream(PurpleMedia *media, const gchar *who, PurpleMediaStreamType type);
+
+GList *purple_media_get_local_audio_candidates(PurpleMedia *media);
+GList *purple_media_get_negotiated_audio_codecs(PurpleMedia *media);
+
+GList *purple_media_get_local_audio_codecs(PurpleMedia *media);
+void purple_media_add_remote_audio_candidates(PurpleMedia *media, const gchar *name,	
+					       GList *remote_candidates);
+FsCandidate *purple_media_get_local_candidate(PurpleMedia *media);
+FsCandidate *purple_media_get_remote_candidate(PurpleMedia *media);
+void purple_media_set_remote_audio_codecs(PurpleMedia *media, const gchar *name, GList *codecs);
+
 G_END_DECLS
 
 #endif  /* USE_GSTPROPS */
--- a/libpurple/mediamanager.c	Tue May 27 06:51:21 2008 +0000
+++ b/libpurple/mediamanager.c	Tue May 27 16:30:26 2008 +0000
@@ -31,7 +31,7 @@
 
 #ifdef USE_FARSIGHT
 
-#include <farsight/farsight.h>
+#include <gst/farsight/fs-conference-iface.h>
 
 struct _PurpleMediaManagerPrivate
 {
@@ -127,18 +127,28 @@
 	return manager;
 }
 
-PurpleMedia*
-purple_media_manager_create_media(PurpleMediaManager *manager, 
+PurpleMedia *
+purple_media_manager_create_media(PurpleMediaManager *manager,
 				  PurpleConnection *gc,
-				  const char *screenname,
-				  FarsightStream *audio_stream,
-				  FarsightStream *video_stream)
+				  const char *conference_type,
+				  const char *remote_user)
 {
-	PurpleMedia *media = PURPLE_MEDIA(g_object_new(purple_media_get_type(),
-					  "screenname", screenname,
-					  "connection", gc, 
-					  "audio-stream", audio_stream,
-					  "video-stream", video_stream, NULL));
+	PurpleMedia *media;
+	FsConference *conference = FS_CONFERENCE(gst_element_factory_make(conference_type, NULL));
+	GstStateChangeReturn ret = gst_element_set_state(GST_ELEMENT(conference), GST_STATE_READY);
+
+	if (ret == GST_STATE_CHANGE_FAILURE) {
+		purple_conv_present_error(remote_user,
+					  purple_connection_get_account(gc),
+					  _("Error creating conference."));
+		return NULL;
+	}
+
+	media = PURPLE_MEDIA(g_object_new(purple_media_get_type(),
+			     "screenname", remote_user,
+			     "connection", gc, 
+			     "farsight-conference", conference,
+			     NULL));
 	manager->priv->medias = g_list_append(manager->priv->medias, media);
 	g_signal_emit(manager, purple_media_manager_signals[INIT_MEDIA], 0, media);
 	return media;
--- a/libpurple/mediamanager.h	Tue May 27 06:51:21 2008 +0000
+++ b/libpurple/mediamanager.h	Tue May 27 16:30:26 2008 +0000
@@ -28,7 +28,7 @@
 
 #ifdef USE_FARSIGHT
 
-#include <farsight/farsight.h>
+#include <gst/farsight/fs-session.h>
 #include <glib.h>
 #include <glib-object.h>
 
@@ -61,12 +61,10 @@
 
 GType purple_media_manager_get_type(void);
 PurpleMediaManager *purple_media_manager_get(void);
-
 PurpleMedia *purple_media_manager_create_media(PurpleMediaManager *manager,
-					       PurpleConnection *gc,
-					       const char *screenname,
-					       FarsightStream *audio_stream,
-					       FarsightStream *video_stream);
+						PurpleConnection *gc,
+						const char *conference_type,
+						const char *remote_user);
 
 G_END_DECLS
 
--- a/libpurple/protocols/jabber/google.c	Tue May 27 06:51:21 2008 +0000
+++ b/libpurple/protocols/jabber/google.c	Tue May 27 16:30:26 2008 +0000
@@ -18,8 +18,6 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
  */
 
-#include <farsight/farsight-transport.h>
-
 #include "internal.h"
 #include "debug.h"
 #include "mediamanager.h"
@@ -32,6 +30,9 @@
 #include "presence.h"
 #include "iq.h"
 
+#ifdef USE_FARSIGHT
+#include <gst/farsight/fs-conference-iface.h>
+
 typedef struct {
 	char *id;
 	char *initiator;
@@ -49,7 +50,6 @@
 	GoogleSessionId id;
 	GoogleSessionState state;
 	PurpleMedia *media;
-	FarsightStream *stream;
 	JabberStream *js; 
 	char *remote_jid;
 } GoogleSession;
@@ -84,7 +84,6 @@
 	g_free(session->id.initiator);
 	g_free(session->remote_jid);
 	g_object_unref(session->media);
-	g_object_unref(session->stream);
 	g_free(session);
 }
 
@@ -103,7 +102,7 @@
 google_session_send_accept(GoogleSession *session)
 {
 	xmlnode *sess, *desc, *payload;
-	GList *codecs = farsight_stream_get_codec_intersection(session->stream);
+	GList *codecs = purple_media_get_negotiated_audio_codecs(session->media);
 	JabberIq *iq = jabber_iq_new(session->js, JABBER_IQ_SET);
 
 	xmlnode_set_attrib(iq->node, "to", session->remote_jid);
@@ -113,7 +112,7 @@
 	xmlnode_set_namespace(desc, "http://www.google.com/session/phone");
 
 	for (;codecs; codecs = codecs->next) {
-		FarsightCodec *codec = (FarsightCodec*)codecs->data;
+		FsCodec *codec = (FsCodec*)codecs->data;
 		char id[8], clockrate[10];
 		payload = xmlnode_new_child(desc, "payload-type");
 		g_snprintf(id, sizeof(id), "%d", codec->id);
@@ -123,15 +122,15 @@
 		xmlnode_set_attrib(payload, "clockrate", clockrate);
 	}
 
+	fs_codec_list_destroy(codecs);
 	jabber_iq_send(iq);
-	farsight_stream_start(session->stream);
+	gst_element_set_state(purple_media_get_audio_pipeline(session->media), GST_STATE_PLAYING);
 }
 
 static void
 google_session_send_terminate(GoogleSession *session)
 {
 	xmlnode *sess;
-	GList *codecs = farsight_stream_get_codec_intersection(session->stream);
 	JabberIq *iq = jabber_iq_new(session->js, JABBER_IQ_SET);
 
 	xmlnode_set_attrib(iq->node, "to", session->remote_jid);
@@ -139,7 +138,6 @@
 	xmlnode_insert_child(iq->node, sess);
 	
 	jabber_iq_send(iq);
-	farsight_stream_stop(session->stream);
 	google_session_destroy(session);
 }
 
@@ -147,7 +145,6 @@
 google_session_send_reject(GoogleSession *session)
 {
 	xmlnode *sess;
-	GList *codecs = farsight_stream_get_codec_intersection(session->stream);
 	JabberIq *iq = jabber_iq_new(session->js, JABBER_IQ_SET);
 
 	xmlnode_set_attrib(iq->node, "to", session->remote_jid);
@@ -155,17 +152,16 @@
 	xmlnode_insert_child(iq->node, sess);
 	
 	jabber_iq_send(iq);
-	farsight_stream_stop(session->stream);
 	google_session_destroy(session);
 }
 
 
 static void 
-google_session_candidates_prepared (FarsightStream *stream, gchar *candidate_id, GoogleSession *session)
+google_session_candidates_prepared (PurpleMedia *media, GoogleSession *session)
 {
 	JabberIq *iq = jabber_iq_new(session->js, JABBER_IQ_SET);
-	GList *candidates = farsight_stream_get_native_candidate_list(stream);
-	FarsightTransportInfo *transport;
+	GList *candidates = purple_media_get_local_audio_candidates(session->media);
+	FsCandidate *transport;
 	xmlnode *sess;
 	xmlnode *candidate;
 	sess = google_session_create_xmlnode(session, "candidates");
@@ -173,9 +169,9 @@
 	xmlnode_set_attrib(iq->node, "to", session->remote_jid);
 	
 	for (;candidates;candidates = candidates->next) {
-		transport = (FarsightTransportInfo*)(candidates->data);
 		char port[8];
 		char pref[8];
+		transport = (FsCandidate*)(candidates->data);
 
 		if (!strcmp(transport->ip, "127.0.0.1"))
 			continue;
@@ -183,7 +179,7 @@
 		candidate = xmlnode_new("candidate");
 
 		g_snprintf(port, sizeof(port), "%d", transport->port);
-		g_snprintf(pref, sizeof(pref), "%f", transport->preference);
+		g_snprintf(pref, sizeof(pref), "%d", transport->priority);
 
 		xmlnode_set_attrib(candidate, "address", transport->ip);
 		xmlnode_set_attrib(candidate, "port", port);
@@ -191,10 +187,10 @@
 		xmlnode_set_attrib(candidate, "username", transport->username);
 		xmlnode_set_attrib(candidate, "password", transport->password);
 		xmlnode_set_attrib(candidate, "preference", pref);
-		xmlnode_set_attrib(candidate, "protocol", transport->proto == FARSIGHT_NETWORK_PROTOCOL_UDP ? "udp" : "tcp");
-		xmlnode_set_attrib(candidate, "type", transport->type == FARSIGHT_CANDIDATE_TYPE_LOCAL ? "local" :
-						      transport->type == FARSIGHT_CANDIDATE_TYPE_DERIVED ? "stun" :
-					       	      transport->type == FARSIGHT_CANDIDATE_TYPE_RELAY ? "relay" : NULL);
+		xmlnode_set_attrib(candidate, "protocol", transport->proto == FS_NETWORK_PROTOCOL_UDP ? "udp" : "tcp");
+		xmlnode_set_attrib(candidate, "type", transport->type == FS_CANDIDATE_TYPE_HOST ? "local" :
+						      transport->type == FS_CANDIDATE_TYPE_PRFLX ? "stun" :
+					       	      transport->type == FS_CANDIDATE_TYPE_RELAY ? "relay" : NULL);
 		xmlnode_set_attrib(candidate, "generation", "0");
 		xmlnode_set_attrib(candidate, "network", "0");
 		xmlnode_insert_child(sess, candidate);
@@ -206,30 +202,24 @@
 static void
 google_session_handle_initiate(JabberStream *js, GoogleSession *session, xmlnode *packet, xmlnode *sess)
 {
-	PurpleMedia *media;
 	JabberIq *result;
-	FarsightSession *fs;
 	GList *codecs = NULL;
 	xmlnode *desc_element, *codec_element;
-	FarsightCodec *codec;
+	FsCodec *codec;
 	const char *id, *encoding_name,  *clock_rate;
-	int res;
 		
 	if (session->state != UNINIT) {
 		purple_debug_error("jabber", "Received initiate for active session.\n");
-		return FALSE;
+		return;
 	}
 
-	fs = farsight_session_factory_make("rtp");
-	if (!fs) {
-		purple_debug_error("jabber", "Farsight's rtp plugin not installed");
-		return FALSE;
-	}
-	
-	session->stream = farsight_session_create_stream(fs, FARSIGHT_MEDIA_TYPE_AUDIO, FARSIGHT_STREAM_DIRECTION_BOTH);
+	session->media = purple_media_manager_create_media(purple_media_manager_get(), js->gc,
+							   "fsrtpconference", session->remote_jid);
 
-	g_object_set(G_OBJECT(session->stream), "transmitter", "libjingle", NULL);
-	
+	/* "rawudp" will need to be changed to "nice" when libnice is finished */
+	purple_media_add_stream(session->media, session->remote_jid, 
+				PURPLE_MEDIA_AUDIO, "rawudp");
+
 	desc_element = xmlnode_get_child(sess, "description");
 	
 	for (codec_element = xmlnode_get_child(desc_element, "payload-type"); 
@@ -239,31 +229,25 @@
 		id = xmlnode_get_attrib(codec_element, "id");
 		clock_rate = xmlnode_get_attrib(codec_element, "clockrate");
 
-		codec = g_new0(FarsightCodec, 1);
-		farsight_codec_init(codec, atoi(id), encoding_name, FARSIGHT_MEDIA_TYPE_AUDIO, clock_rate ? atoi(clock_rate) : 0);
+		codec = fs_codec_new(atoi(id), encoding_name, FS_MEDIA_TYPE_AUDIO,
+				     clock_rate ? atoi(clock_rate) : 0);
 		codecs = g_list_append(codecs, codec);
 	}
 
-	session->media = media = purple_media_manager_create_media(purple_media_manager_get(), js->gc, session->remote_jid, session->stream, NULL);
+	purple_media_set_remote_audio_codecs(session->media, session->remote_jid, codecs);
 
-	g_signal_connect_swapped(G_OBJECT(media), "accepted", G_CALLBACK(google_session_send_accept), session);
-	g_signal_connect_swapped(G_OBJECT(media), "reject", G_CALLBACK(google_session_send_reject), session);
-	g_signal_connect_swapped(G_OBJECT(media), "hangup", G_CALLBACK(google_session_send_terminate), session);
+	g_signal_connect_swapped(G_OBJECT(session->media), "accepted",
+				 G_CALLBACK(google_session_send_accept), session);
+	g_signal_connect_swapped(G_OBJECT(session->media), "reject",
+				 G_CALLBACK(google_session_send_reject), session);
+	g_signal_connect_swapped(G_OBJECT(session->media), "hangup",
+				 G_CALLBACK(google_session_send_terminate), session);
+	g_signal_connect(G_OBJECT(session->media), "candidates-prepared", 
+			 G_CALLBACK(google_session_candidates_prepared), session);
+	purple_media_ready(session->media);
 
-	
-	GstElement *e = purple_media_get_audio_src(media);
-	farsight_stream_set_source(session->stream, e);	
+	fs_codec_list_destroy(codecs);
 	
-	e = purple_media_get_audio_sink(media);
-	farsight_stream_set_sink(session->stream, e);
-	
-	farsight_stream_prepare_transports(session->stream);
-	res = farsight_stream_set_remote_codecs(session->stream, codecs);
-	
-	purple_media_ready(media);
-
-	farsight_codec_list_destroy(codecs);
-	g_signal_connect(G_OBJECT(session->stream), "new-native-candidate", G_CALLBACK(google_session_candidates_prepared), session);
 	result = jabber_iq_new(js, JABBER_IQ_RESULT);
 	jabber_iq_set_id(result, xmlnode_get_attrib(packet, "id"));
 	xmlnode_set_attrib(result->node, "to", session->remote_jid);
@@ -280,24 +264,26 @@
 	char n[4];	
 		
 	for (cand = xmlnode_get_child(sess, "candidate"); cand; cand = xmlnode_get_next_twin(cand)) {
-		FarsightTransportInfo *info = g_new0(FarsightTransportInfo, 1);
+		FsCandidate *info;
 		g_snprintf(n, sizeof(n), "S%d", name++);
-		info->ip = xmlnode_get_attrib(cand, "address");
-		info->port = atoi(xmlnode_get_attrib(cand, "port"));
-		info->proto = !strcmp(xmlnode_get_attrib(cand, "protocol"),"udp") ? FARSIGHT_NETWORK_PROTOCOL_UDP : FARSIGHT_NETWORK_PROTOCOL_TCP;
-		info->preference = atof(xmlnode_get_attrib(cand, "preference"));
-		info->type = !strcmp(xmlnode_get_attrib(cand, "type"), "local") ? FARSIGHT_CANDIDATE_TYPE_LOCAL :
-			     !strcmp(xmlnode_get_attrib(cand, "type"), "stun") ? FARSIGHT_CANDIDATE_TYPE_DERIVED :
-			     !strcmp(xmlnode_get_attrib(cand, "type"), "relay") ? FARSIGHT_CANDIDATE_TYPE_RELAY : FARSIGHT_CANDIDATE_TYPE_LOCAL;
-		info->candidate_id = n;
-		info->username = xmlnode_get_attrib(cand, "username");
-		info->password = xmlnode_get_attrib(cand, "password");
+		info = fs_candidate_new(n, FS_COMPONENT_RTP, !strcmp(xmlnode_get_attrib(cand, "type"), "local") ?
+					FS_CANDIDATE_TYPE_HOST :
+			     		!strcmp(xmlnode_get_attrib(cand, "type"), "stun") ?
+						FS_CANDIDATE_TYPE_PRFLX :
+			     			!strcmp(xmlnode_get_attrib(cand, "type"), "relay") ?
+							FS_CANDIDATE_TYPE_RELAY : FS_CANDIDATE_TYPE_HOST,
+						!strcmp(xmlnode_get_attrib(cand, "protocol"),"udp") ?
+							FS_NETWORK_PROTOCOL_UDP : FS_NETWORK_PROTOCOL_TCP,
+					xmlnode_get_attrib(cand, "address"), atoi(xmlnode_get_attrib(cand, "port")));
+
+		info->username = g_strdup(xmlnode_get_attrib(cand, "username"));
+		info->password = g_strdup(xmlnode_get_attrib(cand, "password"));
+
 		list = g_list_append(list, info);
 	}
 
-	farsight_stream_add_remote_candidate(session->stream, list);
-	g_list_foreach(list, g_free, NULL);
-	g_list_free(list);
+	purple_media_add_remote_audio_candidates(session->media, session->remote_jid, list);
+	fs_candidate_list_destroy(list);
 
 	result = jabber_iq_new(js, JABBER_IQ_RESULT);
 	jabber_iq_set_id(result, xmlnode_get_attrib(packet, "id"));
@@ -308,7 +294,6 @@
 static void
 google_session_handle_reject(JabberStream *js, GoogleSession *session, xmlnode *packet, xmlnode *sess)
 {
-	farsight_stream_stop(session->stream);
 	purple_media_got_hangup(session->media);
 	
 	google_session_destroy(session);
@@ -317,7 +302,6 @@
 static void
 google_session_handle_terminate(JabberStream *js, GoogleSession *session, xmlnode *packet, xmlnode *sess)
 {
-	farsight_stream_stop(session->stream);
 	purple_media_got_hangup(session->media);
 
 	google_session_destroy(session);
@@ -340,13 +324,14 @@
 		google_session_handle_candidates(js, session, packet, sess);
 	}
 }
+#endif /* USE_FARSIGHT */
 
 void
 jabber_google_session_parse(JabberStream *js, xmlnode *packet)
 {
+#ifdef USE_FARSIGHT
 	GoogleSession *session;
 	GoogleSessionId id;
-	JabberIq *result;
 
 	xmlnode *session_node;
 	xmlnode *desc_node;
@@ -358,11 +343,11 @@
 	if (!session_node)
 		return;
 
-	id.id = xmlnode_get_attrib(session_node, "id");
+	id.id = (gchar*)xmlnode_get_attrib(session_node, "id");
 	if (!id.id)
 		return;
 
-	id.initiator = xmlnode_get_attrib(session_node, "initiator");
+	id.initiator = (gchar*)xmlnode_get_attrib(session_node, "initiator");
 	if (!id.initiator)
 		return;
 
@@ -390,6 +375,9 @@
 	g_hash_table_insert(sessions, &(session->id), session);
 
 	google_session_parse_iq(js, session, packet);
+#else
+	/* TODO: send proper error response */
+#endif /* USE_FARSIGHT */
 }
 
 static void
--- a/libpurple/protocols/jabber/jabber.c	Tue May 27 06:51:21 2008 +0000
+++ b/libpurple/protocols/jabber/jabber.c	Tue May 27 16:30:26 2008 +0000
@@ -58,6 +58,10 @@
 #include "adhoccommands.h"
 #include "jingle.h"
 
+#ifdef USE_FARSIGHT
+#include <gst/farsight/fs-conference-iface.h>
+#endif
+
 #define JABBER_CONNECT_STEPS (js->gsc ? 9 : 5)
 
 static PurplePlugin *my_protocol = NULL;
@@ -630,6 +634,10 @@
 	js->keepalive_timeout = -1;
 	js->certificate_CN = g_strdup(connect_server[0] ? connect_server : js->user->domain);
 
+#ifdef USE_FARSIGHT
+	js->sessions = NULL;
+#endif
+
 	if(!js->user) {
 		purple_connection_error_reason (gc,
 			PURPLE_CONNECTION_ERROR_INVALID_SETTINGS,
@@ -1240,6 +1248,19 @@
 {
 	JabberStream *js = gc->proto_data;
 
+#ifdef USE_FARSIGHT
+	/* Close all of the open media sessions on this stream */
+	GList *values = g_hash_table_get_values(js->sessions);
+	GList *iter = values;
+
+	for (; iter; iter = iter->next) {
+		JingleSession *session = (JingleSession *)iter->data;
+		purple_media_hangup(session->media);
+	}
+
+	g_list_free(values);
+#endif
+
 	/* Don't perform any actions on the ssl connection
 	 * if we were forcibly disconnected because it will crash
 	 * on some SSL backends.
@@ -1863,10 +1884,20 @@
 	JabberID *jid;
 	JabberBuddy *jb;
 	JabberBuddyResource *jbr;
-
+#ifdef USE_FARSIGHT
+	JingleSession *session;
+#endif
 	if(!(jid = jabber_id_new(who)))
 		return;
 
+#ifdef USE_FARSIGHT
+	session = jabber_jingle_session_find_by_jid(js, who);
+
+	if (session) {
+		purple_media_hangup(session->media);
+	}
+
+#endif
 	if((jb = jabber_buddy_find(js, who, TRUE)) &&
 			(jbr = jabber_buddy_find_resource(jb, jid->resource))) {
 		if(jbr->thread_id) {
@@ -2358,11 +2389,9 @@
 	xmlnode_insert_child(result->node, jingle);
 	jabber_iq_send(result);
 	purple_debug_info("jabber", "Sent session accept, starting stream\n");
-	farsight_stream_start(jabber_jingle_session_get_stream(session));
-	farsight_stream_set_remote_codecs(
-			jabber_jingle_session_get_stream(session),
-			jabber_jingle_session_get_remote_codecs(session));
-
+	gst_element_set_state(purple_media_get_audio_pipeline(session->media), GST_STATE_PLAYING);
+
+	session->session_started = TRUE;
 }
 
 static void
@@ -2389,7 +2418,6 @@
 					   jabber_jingle_session_get_remote_jid(session));
 	xmlnode_insert_child(result->node, jingle);
 	jabber_iq_send(result);
-	farsight_stream_stop(jabber_jingle_session_get_stream(session));
 	jabber_jingle_session_destroy(session);
 }
 
@@ -2404,117 +2432,147 @@
 					   jabber_jingle_session_get_remote_jid(session));
 	xmlnode_insert_child(result->node, jingle);
 	jabber_iq_send(result);
-	farsight_stream_stop(jabber_jingle_session_get_stream(session));
 	jabber_jingle_session_destroy(session);
 }
 
 /* callback called when new local transport candidate(s) are available on the
 	Farsight stream */
 static void
-jabber_session_candidates_prepared(FarsightStream *stream, gchar *candidate_id, 
-								   JingleSession *session)
+jabber_session_candidates_prepared(PurpleMedia *media, JingleSession *session)
 {
-	/* create transport-info package */
-	JabberIq *result = jabber_iq_new(jabber_jingle_session_get_js(session),
-									 JABBER_IQ_SET);
-	xmlnode *jingle = jabber_jingle_session_create_transport_info(session,
-																  candidate_id);
-	purple_debug_info("jabber", "jabber_session_candidates_prepared called for candidate_id = %s\n",
-					  candidate_id);
-	xmlnode_set_attrib(result->node, "to",
-					   jabber_jingle_session_get_remote_jid(session));
-	
-	xmlnode_insert_child(result->node, jingle);
-	jabber_iq_send(result);
+	if (!jabber_jingle_session_is_initiator(session)) {
+		/* create transport-info package */
+		JabberIq *result = jabber_iq_new(jabber_jingle_session_get_js(session),
+						 JABBER_IQ_SET);
+		xmlnode *jingle = jabber_jingle_session_create_transport_info(session);
+		purple_debug_info("jabber", "jabber_session_candidates_prepared: %d candidates\n",
+				  g_list_length(purple_media_get_local_audio_candidates(session->media)));
+		xmlnode_set_attrib(result->node, "to",
+				   jabber_jingle_session_get_remote_jid(session));
+
+		xmlnode_insert_child(result->node, jingle);
+		jabber_iq_send(result);
+	}
 }
 
 /* callback called when a pair of transport candidates (local and remote)
 	has been established */
 static void
-jabber_session_candidate_pair_established(FarsightStream *stream,
-										  gchar *native_candidate_id,
-										  gchar *remote_candidate_id,
-										  JingleSession *session)
+jabber_session_candidate_pair_established(PurpleMedia *media,
+					  FsCandidate *native_candidate,
+					  FsCandidate *remote_candidate,
+					  JingleSession *session)
 {	
-	purple_debug_info("jabber", "jabber_candidate_pair_established called");
+	purple_debug_info("jabber", "jabber_candidate_pair_established called\n");
 	/* if we are the initiator, we should send a content-modify message */
 	if (jabber_jingle_session_is_initiator(session)) {
-		purple_debug_info("jabber", 
-						  "we are the initiator, let's send conten-modify\n");
-		JabberIq *result = jabber_iq_new(jabber_jingle_session_get_js(session),
-										 JABBER_IQ_SET);
+		JabberIq *result;
+		xmlnode *jingle;
+		
+		purple_debug_info("jabber", "we are the initiator, let's send content-modify\n");
+
+		result = jabber_iq_new(jabber_jingle_session_get_js(session), JABBER_IQ_SET);
+
 		/* shall change this to a "content-replace" */
-		xmlnode *jingle = 
+		jingle =
 			jabber_jingle_session_create_content_replace(session,
-														 native_candidate_id,
-														 remote_candidate_id);
+								     native_candidate,
+								     remote_candidate);
 		xmlnode_set_attrib(result->node, "to",
 						   jabber_jingle_session_get_remote_jid(session));
 		xmlnode_insert_child(result->node, jingle);
 		jabber_iq_send(result);
 	}
-	/*
-	farsight_stream_set_active_candidate_pair(stream, native_candidate_id,
-											  remote_candidate_id);
-	*/
 }
 
-
-PurpleMedia *jabber_initiate_media(PurpleConnection *gc, const char *who, 
+static gboolean
+jabber_initiate_media_internal(JingleSession *session, const char *initiator, const char *remote_jid)
+{
+	PurpleMedia *media = NULL;
+
+	media = purple_media_manager_create_media(purple_media_manager_get(), 
+						  session->js->gc, "fsrtpconference", remote_jid);
+
+	if (!media) {
+		purple_debug_error("jabber", "Couldn't create fsrtpconference\n");
+		return FALSE;
+	}
+
+	/* this will need to be changed to "nice" once the libnice transmitter is finished */
+	if (!purple_media_add_stream(media, remote_jid, PURPLE_MEDIA_AUDIO, "rawudp")) {
+		purple_debug_error("jabber", "Couldn't create audio stream\n");
+		purple_media_reject(media);
+		return FALSE;
+	}
+
+	jabber_jingle_session_set_remote_jid(session, remote_jid);
+	jabber_jingle_session_set_initiator(session, initiator);
+	jabber_jingle_session_set_media(session, media);
+	
+	/* connect callbacks */
+	g_signal_connect_swapped(G_OBJECT(media), "accepted", 
+				 G_CALLBACK(jabber_session_send_accept), session);
+	g_signal_connect_swapped(G_OBJECT(media), "reject", 
+				 G_CALLBACK(jabber_session_send_reject), session);
+	g_signal_connect_swapped(G_OBJECT(media), "hangup", 
+				 G_CALLBACK(jabber_session_send_terminate), session);
+	g_signal_connect(G_OBJECT(media), "candidates-prepared", 
+				 G_CALLBACK(jabber_session_candidates_prepared), session);
+	g_signal_connect(G_OBJECT(media), "candidate-pair", 
+				 G_CALLBACK(jabber_session_candidate_pair_established), session);
+
+	purple_media_ready(media);
+
+	return TRUE;
+}
+
+static void
+jabber_session_initiate_result_cb(JabberStream *js, xmlnode *packet, gpointer data)
+{
+	const char *from = xmlnode_get_attrib(packet, "from");
+	JingleSession *session = jabber_jingle_session_find_by_jid(js, from);
+	PurpleMedia *media = session->media;
+	JabberIq *result;
+	xmlnode *jingle;
+
+	if (!strcmp(xmlnode_get_attrib(packet, "type"), "error")) {
+		purple_media_got_hangup(media);
+		return;
+	}
+
+	/* catch errors */
+	if (xmlnode_get_child(packet, "error")) {
+		purple_media_got_hangup(media);
+		return;
+	}
+
+	/* create transport-info package */
+	result = jabber_iq_new(jabber_jingle_session_get_js(session), JABBER_IQ_SET);
+	jingle = jabber_jingle_session_create_transport_info(session);
+	purple_debug_info("jabber", "jabber_session_candidates_prepared: %d candidates\n",
+			  g_list_length(purple_media_get_local_audio_candidates(session->media)));
+	xmlnode_set_attrib(result->node, "to",
+			   jabber_jingle_session_get_remote_jid(session));
+
+	xmlnode_insert_child(result->node, jingle);
+	jabber_iq_send(result);
+}
+
+PurpleMedia *
+jabber_initiate_media(PurpleConnection *gc, const char *who, 
 								   PurpleMediaStreamType type)
 {
 	/* create content negotiation */
 	JabberStream *js = gc->proto_data;
 	JabberIq *request = jabber_iq_new(js, JABBER_IQ_SET);
-	xmlnode *jingle, *content, *description, *payload_type, *transport;
-	FarsightSession *fs = NULL;
-	FarsightStream *audio = NULL; /* only audio for now... */
+	xmlnode *jingle, *content, *description, *transport;
 	GList *codecs;
-	GList *codec_iter = NULL;
-	FarsightCodec *codec = NULL;
-	PurpleMedia *media = NULL;
 	JingleSession *session;
 	JabberBuddy *jb;
 	JabberBuddyResource *jbr;
 	
-	char id[10];
-	char clock_rate[10];
-	char channels[10];
-	char jid[256];
-	char me[256];
-	
-	/* for debug */
-	char *output;
-	int len;
-		
-	/* setup stream */
-	fs = farsight_session_factory_make("rtp");
-	if (fs == NULL) {
-		purple_debug_error("jabber", "Farsight's rtp plugin not installed");
-		return NULL;
-	}
-	
-	/* check media stream type, and so on... */
-	/* only do audio for now... */
-	
-	/* get stuff from Farsight... */
-	audio = farsight_session_create_stream(fs, FARSIGHT_MEDIA_TYPE_AUDIO, 
-										   FARSIGHT_STREAM_DIRECTION_BOTH);
-	g_object_set(G_OBJECT(audio), "transmitter", "libjingle", NULL);
-	
-	purple_debug_info("jabber", "Getting local codecs\n");
-	codecs = farsight_stream_get_local_codecs(audio);
-	purple_debug_info("jabber", "number of codecs: %d\n", g_list_length(codecs));
-	
- 	if (audio == NULL) {
-		purple_debug_error("jabber", "Unable to create Farsight stream for audio");
-		/* destroy FarsightSession? */
-		return NULL;
-	}
-	
-	media = purple_media_manager_create_media(purple_media_manager_get(),
-											  gc, who, audio, NULL);
-	purple_debug_info("jabber", "After purple_media_manager_create_media\n");
+	char *jid = NULL, *me = NULL;
+
 	/* construct JID to send to */
 	jb = jabber_buddy_find(js, who, FALSE);
 	if (!jb) {
@@ -2525,42 +2583,29 @@
 	if (!jbr) {
 		purple_debug_error("jabber", "Could not find buddy's resource\n");
 	}
-	
-	g_snprintf(jid, 255, "%s/%s", who, jbr->name);
+
+	if ((strchr(who, '/') == NULL) && jbr && (jbr->name != NULL)) {
+		jid = g_strdup_printf("%s/%s", who, jbr->name);
+	} else {
+		jid = g_strdup(who);
+	}
 	
 	session = jabber_jingle_session_create(js);
-	jabber_jingle_session_set_remote_jid(session, jid);
 	/* set ourselves as initiator */
-	g_snprintf(me, sizeof(me), "%s@%s/%s", js->user->node, js->user->domain,
-			   js->user->resource);
-	jabber_jingle_session_set_initiator(session, me);
-	
-	jabber_jingle_session_set_stream(session, audio);
-	jabber_jingle_session_set_media(session, media);
-	
-	g_signal_connect_swapped(G_OBJECT(media), "accepted", 
-							 G_CALLBACK(jabber_session_send_accept), session);
-	g_signal_connect_swapped(G_OBJECT(media), "reject", 
-							 G_CALLBACK(jabber_session_send_reject), session);
-	g_signal_connect_swapped(G_OBJECT(media), "hangup", 
-							 G_CALLBACK(jabber_session_send_terminate), session);
-	
-	GstElement *e = purple_media_get_audio_src(media);
-	farsight_stream_set_source(jabber_jingle_session_get_stream(session), e);	
-	e = purple_media_get_audio_sink(media);
-	farsight_stream_set_sink(jabber_jingle_session_get_stream(session), e);
-	
-	farsight_stream_prepare_transports(audio);
-	/* callback for new native (local) transport candidates for the stream */
-	g_signal_connect(G_OBJECT(audio), 
-					 "new-native-candidate", 
-					 G_CALLBACK(jabber_session_candidates_prepared), session);
-	/* callback for new active candidate pair (established connection) */
-	g_signal_connect(G_OBJECT(audio),
-					 "new-active-candidate-pair",
-					 G_CALLBACK(jabber_session_candidate_pair_established),
-					 session);
-	
+	me = g_strdup_printf("%s@%s/%s", js->user->node, js->user->domain, js->user->resource);
+
+	if (!jabber_initiate_media_internal(session, me, jid)) {
+		g_free(jid);
+		g_free(me);
+		jabber_jingle_session_destroy(session);
+		return NULL;
+	}
+
+	g_free(jid);
+	g_free(me);
+
+	codecs = purple_media_get_local_audio_codecs(session->media);
+
 	/* create request */
 	
 	xmlnode_set_attrib(request->node, "to", 
@@ -2569,40 +2614,27 @@
 	xmlnode_set_namespace(jingle, "urn:xmpp:tmp:jingle");
 	xmlnode_set_attrib(jingle, "action", "session-initiate");
 	/* get our JID and a session id... */
-	xmlnode_set_attrib(jingle, "initiator", me);
+	xmlnode_set_attrib(jingle, "initiator", jabber_jingle_session_get_initiator(session));
 	xmlnode_set_attrib(jingle, "sid", jabber_jingle_session_get_id(session));
 	
 	content = xmlnode_new_child(jingle, "content");
 	xmlnode_set_attrib(content, "name", "audio-content");
 	xmlnode_set_attrib(content, "profile", "RTP/AVP");
-	
-	description = xmlnode_new_child(content, "description");
-	xmlnode_set_namespace(description, "urn:xmpp:tmp:jingle:apps:audio-rtp");
-	
-	/* create payload-type nodes */
-	purple_debug_info("jabber", "Generating payload_type elements\n");
-	for (; codecs ; codecs = codecs->next) {
-		codec = (FarsightCodec *) codecs->data;
-		purple_debug_info("jabber", "Generating payload_type for (%d) %s\n",
-						  codec->id, codec->encoding_name);
-		sprintf(id, "%d", codec->id);
-		sprintf(clock_rate, "%d", codec->clock_rate);
-		sprintf(channels, "%d", codec->channels);
-		
-		payload_type = xmlnode_new_child(description, "payload-type");
-		xmlnode_set_attrib(payload_type, "id", id);
-		xmlnode_set_attrib(payload_type, "name", codec->encoding_name);
-		xmlnode_set_attrib(payload_type, "clockrate", clock_rate);
-		xmlnode_set_attrib(payload_type, "channels", channels);
-	}
-		
+
+	description = jabber_jingle_session_create_description(session);
+	xmlnode_insert_child(content, description);
+
 	transport = xmlnode_new_child(content, "transport");
-	xmlnode_set_namespace(transport, "urn:xmpp:tmp:jingle:transports:ice-tcp");
-	
+	xmlnode_set_namespace(transport, "urn:xmpp:tmp:jingle:transports:ice-udp");
+
+	jabber_iq_set_callback(request, jabber_session_initiate_result_cb, NULL);
+
 	/* send request to other part */	
 	jabber_iq_send(request);
 
-	return media;
+	fs_codec_list_destroy(codecs);
+
+	return session->media;
 }
 
 gboolean jabber_can_do_media(PurpleConnection *gc, const char *who, 
@@ -2620,12 +2652,11 @@
 	xmlnode *content = xmlnode_get_child(jingle, "content");
 	const char *sid = xmlnode_get_attrib(jingle, "sid");
 	const char *action = xmlnode_get_attrib(jingle, "action");
-	JingleSession *session = jabber_jingle_session_find_by_id(sid);
-	FarsightStream *stream = jabber_jingle_session_get_stream(session);
+	JingleSession *session = jabber_jingle_session_find_by_id(js, sid);
 	GList *remote_codecs = NULL;
 	GList *remote_transports = NULL;
-	GList *codec_intersection = NULL;
-	FarsightCodec *top = NULL;
+	GList *codec_intersection;
+	FsCodec *top = NULL;
 	xmlnode *description = NULL;
 	xmlnode *transport = NULL;
 
@@ -2635,7 +2666,7 @@
 			jabber_jingle_session_get_remote_jid(session));
 	jabber_iq_set_id(result, xmlnode_get_attrib(packet, "id"));
 
-	description = xmlnode_get_child(jingle, "description");
+	description = xmlnode_get_child(content, "description");
 	transport = xmlnode_get_child(content, "transport");
 
 	/* fetch codecs from remote party */
@@ -2651,27 +2682,29 @@
 
 	purple_debug_info("jabber", "Setting remote codecs on stream\n");
 
-	farsight_stream_set_remote_codecs(stream, remote_codecs);
-	if (!strcmp(action, "session-accept")) {
-		jabber_jingle_session_set_remote_codecs(session, remote_codecs);
-	}
-
-	codec_intersection = farsight_stream_get_codec_intersection(stream);
+	purple_media_set_remote_audio_codecs(session->media, 
+					     jabber_jingle_session_get_remote_jid(session),
+					     remote_codecs);
+
+	codec_intersection = purple_media_get_negotiated_audio_codecs(session->media);
 	purple_debug_info("jabber", "codec_intersection contains %d elems\n",
 			g_list_length(codec_intersection));
 	/* get the top codec */
 	if (g_list_length(codec_intersection) > 0) {
-		top = (FarsightCodec *) codec_intersection->data;
-		purple_debug_info("jabber", "setting active codec on stream = %d\n",
+		top = (FsCodec *) codec_intersection->data;
+		purple_debug_info("jabber", "Found a suitable codec on stream = %d\n",
 				top->id);
-		farsight_stream_set_active_codec(stream, top->id);
+
 		/* we have found a suitable codec, but we will not start the stream
 		   just yet, wait for transport negotiation to complete... */
 	}
 	/* if we also got transport candidates, add them to our streams
 	   list of known remote candidates */
 	if (g_list_length(remote_transports) > 0) {
-		farsight_stream_set_remote_candidate_list(stream, remote_transports);
+		purple_media_add_remote_audio_candidates(session->media,
+							 jabber_jingle_session_get_remote_jid(session),
+							 remote_transports);
+		fs_candidate_list_destroy(remote_transports);
 	}
 	if (g_list_length(codec_intersection) == 0 &&
 			g_list_length(remote_transports)) {
@@ -2686,10 +2719,12 @@
 	if (!strcmp(action, "session-accept")) {
 		purple_media_got_accept(jabber_jingle_session_get_media(session));
 		purple_debug_info("jabber", "Got session-accept, starting stream\n");
-		farsight_stream_start(jabber_jingle_session_get_stream(session));
+		gst_element_set_state(purple_media_get_audio_pipeline(session->media), GST_STATE_PLAYING);
 	}
 
 	jabber_iq_send(result);
+
+	session->session_started = TRUE;
 }
 
 void
@@ -2698,7 +2733,12 @@
 	JabberIq *result = jabber_iq_new(js, JABBER_IQ_SET);
 	xmlnode *jingle = xmlnode_get_child(packet, "jingle");
 	const char *sid = xmlnode_get_attrib(jingle, "sid");
-	JingleSession *session = jabber_jingle_session_find_by_id(sid);
+	JingleSession *session = jabber_jingle_session_find_by_id(js, sid);
+
+	if(!session) {
+		purple_debug_error("jabber", "jabber_handle_session_terminate couldn't find session\n");
+		return;
+	}
 
 	xmlnode_set_attrib(result->node, "to",
 			jabber_jingle_session_get_remote_jid(session));
@@ -2708,11 +2748,10 @@
 
 	/* maybe we should look at the reasoncode to determine if it was
 	   a hangup or a reject, and call different callbacks to purple_media */
-
+	gst_element_set_state(purple_media_get_audio_pipeline(session->media), GST_STATE_NULL);
 
 	purple_media_got_hangup(jabber_jingle_session_get_media(session));
 	jabber_iq_send(result);
-	farsight_stream_stop(jabber_jingle_session_get_stream(session));
 	jabber_jingle_session_destroy(session);
 }
 
@@ -2725,7 +2764,10 @@
 	xmlnode *transport = xmlnode_get_child(content, "transport");
 	GList *remote_candidates = jabber_jingle_get_candidates(transport);
 	const char *sid = xmlnode_get_attrib(jingle, "sid");
-	JingleSession *session = jabber_jingle_session_find_by_id(sid);
+	JingleSession *session = jabber_jingle_session_find_by_id(js, sid);
+
+	if(!session)
+		purple_debug_error("jabber", "jabber_handle_session_candidates couldn't find session\n");
 
 	/* send acknowledement */
 	xmlnode_set_attrib(result->node, "id", xmlnode_get_attrib(packet, "id"));
@@ -2734,10 +2776,10 @@
 
 	/* add candidates to our list of remote candidates */
 	if (g_list_length(remote_candidates) > 0) {
-		farsight_stream_add_remote_candidate(
-				jabber_jingle_session_get_stream(session),
-				remote_candidates);
-		jabber_jingle_session_add_remote_candidate(session, remote_candidates);
+		purple_media_add_remote_audio_candidates(session->media,
+							 xmlnode_get_attrib(packet, "from"),
+							 remote_candidates);
+		fs_candidate_list_destroy(remote_candidates);
 	}
 }
 
@@ -2745,25 +2787,28 @@
 void
 jabber_handle_session_content_replace(JabberStream *js, xmlnode *packet)
 {
-	JabberIq *result = jabber_iq_new(js, JABBER_IQ_RESULT);
-	JabberIq *accept = jabber_iq_new(js, JABBER_IQ_SET);
-	xmlnode *content_accept = NULL;
 	xmlnode *jingle = xmlnode_get_child(packet, "jingle");
 	const char *sid = xmlnode_get_attrib(jingle, "sid");
-	JingleSession *session = jabber_jingle_session_find_by_id(sid);
-
-	/* send acknowledement */
-	xmlnode_set_attrib(result->node, "id", xmlnode_get_attrib(packet, "id"));
-	xmlnode_set_attrib(result->node, "to", xmlnode_get_attrib(packet, "from"));
-	jabber_iq_send(result);
-
-	/* send content-accept */
-	content_accept = jabber_jingle_session_create_content_accept(session);
-	xmlnode_set_attrib(accept->node, "id", xmlnode_get_attrib(packet, "id"));
-	xmlnode_set_attrib(accept->node, "to", xmlnode_get_attrib(packet, "from"));
-	xmlnode_insert_child(accept->node, content_accept);
-
-	jabber_iq_send(accept);
+	JingleSession *session = jabber_jingle_session_find_by_id(js, sid);
+
+	if (!jabber_jingle_session_is_initiator(session) && session->session_started) {
+		JabberIq *result = jabber_iq_new(js, JABBER_IQ_RESULT);
+		JabberIq *accept = jabber_iq_new(js, JABBER_IQ_SET);
+		xmlnode *content_accept = NULL;
+
+		/* send acknowledement */
+		xmlnode_set_attrib(result->node, "id", xmlnode_get_attrib(packet, "id"));
+		xmlnode_set_attrib(result->node, "to", xmlnode_get_attrib(packet, "from"));
+		jabber_iq_send(result);
+
+		/* send content-accept */
+		content_accept = jabber_jingle_session_create_content_accept(session);
+		xmlnode_set_attrib(accept->node, "id", xmlnode_get_attrib(packet, "id"));
+		xmlnode_set_attrib(accept->node, "to", xmlnode_get_attrib(packet, "from"));
+		xmlnode_insert_child(accept->node, content_accept);
+
+		jabber_iq_send(accept);
+	}
 }
 
 void 
@@ -2773,18 +2818,10 @@
 	xmlnode *jingle = xmlnode_get_child(packet, "jingle");
 	xmlnode *content = NULL;
 	xmlnode *description = NULL;
-	char *sid = NULL;
-	char *initiator = NULL;
+	const char *sid = NULL;
+	const char *initiator = NULL;
 	GList *codecs = NULL;
-	FarsightSession *fs = NULL;
-	FarsightStream *audio = NULL;
-	PurpleMedia *media = NULL;
 	JabberIq *result = NULL;
-	JabberIq *content_accept = NULL;
-	xmlnode *content_accept_jingle = NULL;
-	GList *codec_intersection = NULL;
-
-	int res;
 
 	if (!jingle) {
 		purple_debug_error("jabber", "Malformed request");
@@ -2792,14 +2829,14 @@
 	}
 
 	sid = xmlnode_get_attrib(jingle, "sid");
-	//initiator = xmlnode_get_attrib(jingle, "initiator");
-	initiator = xmlnode_get_attrib(packet, "from");
+	initiator = xmlnode_get_attrib(jingle, "initiator");
+
+	if (jabber_jingle_session_find_by_id(js, sid)) {
+		/* This should only happen if you start a session with yourself */
+		purple_debug_error("jabber", "Jingle session with id={%s} already exists\n", sid);
+		return;
+	}
 	session = jabber_jingle_session_create_by_id(js, sid);
-	jabber_jingle_session_set_remote_jid(session,
-			xmlnode_get_attrib(packet, "from"));
-	/* set "from" as iniator (we are responder) */
-	jabber_jingle_session_set_initiator(session,
-			xmlnode_get_attrib(packet, "from"));
 
 	/* init media */
 	content = xmlnode_get_child(jingle, "content");
@@ -2812,92 +2849,26 @@
 	description = xmlnode_get_child(content, "description");
 
 	if (!description) {
-		purple_debug_error("jabber", "content tag must contain description tag");
+		purple_debug_error("jabber", "content tag must contain description tag\n");
+		/* we should create an error iq here */
+		return;
+	}
+
+	if (!jabber_initiate_media_internal(session, initiator, initiator)) {
+		purple_debug_error("jabber", "Couldn't start media session with %s\n", initiator);
+		jabber_jingle_session_destroy(session);
 		/* we should create an error iq here */
 		return;
 	}
 
 	codecs = jabber_jingle_get_codecs(description);
 
-	fs = farsight_session_factory_make("rtp");
-	if (!fs) {
-		purple_debug_error("jabber", 
-				"Could not initialize Farsight's RTP plugin");
-		return;
-	}
-
-	audio = farsight_session_create_stream(fs, 
-			FARSIGHT_MEDIA_TYPE_AUDIO, 
-			FARSIGHT_STREAM_DIRECTION_BOTH);
-
-	g_object_set(G_OBJECT(audio), "transmitter", "libjingle", NULL);
-
-	media = purple_media_manager_create_media(purple_media_manager_get(), 
-			js->gc, initiator, audio, NULL);
-	jabber_jingle_session_set_media(session, media);
-	jabber_jingle_session_set_stream(session, audio);
-
-
-	g_signal_connect_swapped(G_OBJECT(media), "accepted", 
-			G_CALLBACK(jabber_session_send_accept), session);
-	g_signal_connect_swapped(G_OBJECT(media), "reject", 
-			G_CALLBACK(jabber_session_send_reject), session);
-	g_signal_connect_swapped(G_OBJECT(media), "hangup", 
-			G_CALLBACK(jabber_session_send_terminate), session);
-
-
-	GstElement *e = purple_media_get_audio_src(media);
-	farsight_stream_set_source(jabber_jingle_session_get_stream(session), e);	
-
-	e = purple_media_get_audio_sink(media);
-	farsight_stream_set_sink(jabber_jingle_session_get_stream(session), e);
-
-	farsight_stream_prepare_transports(jabber_jingle_session_get_stream(session));
-	/* For some reason Farsight starts the stream immediatly when calling
-	   farsight_stream_set_remote_codecs, before having called farsight_stream_start
-	   As a "workaround" (maybe this gets fixed in FS2) I'll store the list in
-	   the session to call it later when accepting the call */
-	/*
-	   res = 
-	   farsight_stream_set_remote_codecs(jabber_jingle_session_get_stream(session), 
-	   codecs);
-	   */
-	jabber_jingle_session_set_remote_codecs(session, codecs);
-
-	purple_media_ready(media);
-
-	/* We store the remote candidates in the session object... */
-	/*
-	   farsight_codec_list_destroy(codecs);
-	   */
-
-	/* callback for new native (local) transport candidates for the stream */
-	g_signal_connect(G_OBJECT(jabber_jingle_session_get_stream(session)),
-			"new-native-candidate",
-			G_CALLBACK(jabber_session_candidates_prepared), session);
-	/* callback for new active candidate pair (established connection) */
-	g_signal_connect(G_OBJECT(jabber_jingle_session_get_stream(session)),
-			"new-active-candidate-pair",
-			G_CALLBACK(jabber_session_candidate_pair_established),
-			session);
+	purple_media_set_remote_audio_codecs(session->media, initiator, codecs);
 
 	result = jabber_iq_new(js, JABBER_IQ_RESULT);
 	jabber_iq_set_id(result, xmlnode_get_attrib(packet, "id"));
 	xmlnode_set_attrib(result->node, "to", xmlnode_get_attrib(packet, "from"));
 	jabber_iq_send(result);
-
-	/* should send a content-accept */
-	/* It crashes after this gets sent, also the id of this iq is set to
-	   "purple0", that seems odd... maybe I'm making some mistake here... */
-	/*
-	   content_accept = jabber_iq_new(jabber_jingle_session_get_stream(session),
-	   JABBER_IQ_SET);
-	   content_accept_jingle = jabber_jingle_session_create_content_accept(session);
-	   xmlnode_set_attrib(content_accept->node, "to", 
-	   jabber_jingle_session_get_remote_jid(session));
-	   xmlnode_insert_child(content_accept->node, content_accept_jingle);
-	   jabber_iq_send(content_accept);
-	   */
 }
 
 #endif
--- a/libpurple/protocols/jabber/jabber.h	Tue May 27 06:51:21 2008 +0000
+++ b/libpurple/protocols/jabber/jabber.h	Tue May 27 16:30:26 2008 +0000
@@ -203,6 +203,11 @@
 	
 	/* A purple timeout tag for the keepalive */
 	int keepalive_timeout;
+
+#ifdef USE_FARSIGHT
+	/* keep a hash table of JingleSessions */
+	GHashTable *sessions;
+#endif
 };
 
 typedef gboolean (JabberFeatureEnabled)(JabberStream *js, const gchar *shortname, const gchar *namespace);
--- a/libpurple/protocols/jabber/jingle.c	Tue May 27 06:51:21 2008 +0000
+++ b/libpurple/protocols/jabber/jingle.c	Tue May 27 16:30:26 2008 +0000
@@ -28,11 +28,7 @@
 
 #ifdef USE_FARSIGHT
 
-#include <farsight/farsight.h>
-#include <farsight/farsight-transport.h>
-
-/* keep a hash table of JingleSessions */
-static GHashTable *sessions = NULL;
+#include <gst/farsight/fs-candidate.h>
 
 static gboolean
 jabber_jingle_session_equal(gconstpointer a, gconstpointer b)
@@ -59,17 +55,16 @@
 	}
 	
 	/* insert it into the hash table */
-	if (!sessions) {
+	if (!js->sessions) {
 		purple_debug_info("jingle", "Creating hash table for sessions\n");
-		sessions = g_hash_table_new(g_str_hash, g_str_equal);
+		js->sessions = g_hash_table_new(g_str_hash, g_str_equal);
 	}
 	purple_debug_info("jingle", "inserting session with key: %s into table\n",
 					  sess->id);
-	g_hash_table_insert(sessions, sess->id, sess);
-	
-	sess->remote_candidates = NULL;
-    sess->remote_codecs = NULL;
-	
+	g_hash_table_insert(js->sessions, sess->id, sess);
+
+	sess->session_started = FALSE;
+
 	return sess;
 }
 
@@ -104,22 +99,37 @@
 void
 jabber_jingle_session_destroy(JingleSession *sess)
 {
-	g_hash_table_remove(sessions, sess->id);
+	g_hash_table_remove(sess->js->sessions, sess->id);
 	g_free(sess->id);
-    farsight_codec_list_destroy(sess->remote_codecs);
-    g_list_free(sess->remote_candidates);
 	g_free(sess);
 }
 
 JingleSession *
-jabber_jingle_session_find_by_id(const char *id)
+jabber_jingle_session_find_by_id(JabberStream *js, const char *id)
 {
 	purple_debug_info("jingle", "find_by_id %s\n", id);
-	purple_debug_info("jingle", "hash table: %lx\n", sessions);
+	purple_debug_info("jingle", "hash table: %p\n", js->sessions);
 	purple_debug_info("jingle", "hash table size %d\n",
-					  g_hash_table_size(sessions));
-	purple_debug_info("jingle", "lookup: %lx\n", g_hash_table_lookup(sessions, id));  
-	return (JingleSession *) g_hash_table_lookup(sessions, id);
+					  g_hash_table_size(js->sessions));
+	purple_debug_info("jingle", "lookup: %p\n", g_hash_table_lookup(js->sessions, id));  
+	return (JingleSession *) g_hash_table_lookup(js->sessions, id);
+}
+
+JingleSession *jabber_jingle_session_find_by_jid(JabberStream *js, const char *jid)
+{
+	GList *values = g_hash_table_get_values(js->sessions);
+	GList *iter = values;
+
+	for (; iter; iter = iter->next) {
+		JingleSession *session = (JingleSession *)iter->data;
+		if (session->js == js && !strcmp(jid, session->remote_jid)) {
+			g_list_free(values);
+			return session;
+		}
+	}
+
+	g_list_free(values);
+	return NULL;	
 }
 
 GList *
@@ -128,7 +138,7 @@
 	GList *codecs = NULL;
 	xmlnode *codec_element = NULL;
 	const char *encoding_name,*id, *clock_rate;
-	FarsightCodec *codec;
+	FsCodec *codec;
 	
 	for (codec_element = xmlnode_get_child(description, "payload-type") ;
 		 codec_element ;
@@ -137,10 +147,9 @@
 		id = xmlnode_get_attrib(codec_element, "id");
 		clock_rate = xmlnode_get_attrib(codec_element, "clockrate");
 
-		codec = g_new0(FarsightCodec, 1);
-		farsight_codec_init(codec, atoi(id), encoding_name, 
-							FARSIGHT_MEDIA_TYPE_AUDIO, 
-							clock_rate ? atoi(clock_rate) : 0);
+		codec = fs_codec_new(atoi(id), encoding_name, 
+				     FS_MEDIA_TYPE_AUDIO, 
+				     clock_rate ? atoi(clock_rate) : 0);
 		codecs = g_list_append(codecs, codec);		 
 	}
 	return codecs;
@@ -151,48 +160,31 @@
 {
 	GList *candidates = NULL;
 	xmlnode *candidate = NULL;
-	FarsightTransportInfo *ti;
+	FsCandidate *c;
 	
 	for (candidate = xmlnode_get_child(transport, "candidate") ;
 		 candidate ;
 		 candidate = xmlnode_get_next_twin(candidate)) {
 		const char *type = xmlnode_get_attrib(candidate, "type");
-		ti = g_new0(FarsightTransportInfo, 1);
-		ti->component = atoi(xmlnode_get_attrib(candidate, "component"));
-		ti->ip = xmlnode_get_attrib(candidate, "ip");
-		ti->port = atoi(xmlnode_get_attrib(candidate, "port"));
-		ti->proto = strcmp(xmlnode_get_attrib(candidate, "protocol"),
+		c = fs_candidate_new(xmlnode_get_attrib(candidate, "component"), 
+							atoi(xmlnode_get_attrib(candidate, "component")),
+							strcmp(type, "host") == 0 ?
+								FS_CANDIDATE_TYPE_HOST :
+								strcmp(type, "prflx") == 0 ?
+									FS_CANDIDATE_TYPE_PRFLX :
+									FS_CANDIDATE_TYPE_RELAY,
+							strcmp(xmlnode_get_attrib(candidate, "protocol"),
 							  "udp") == 0 ? 
-				 				FARSIGHT_NETWORK_PROTOCOL_UDP :
-				 				FARSIGHT_NETWORK_PROTOCOL_TCP;
-		/* it seems Farsight RTP doesn't handle this correctly right now */
-		ti->username = xmlnode_get_attrib(candidate, "ufrag");
-		ti->password = xmlnode_get_attrib(candidate, "pwd");
-		/* not quite sure about this */
-		ti->type = strcmp(type, "host") == 0 ?
-					FARSIGHT_CANDIDATE_TYPE_LOCAL :
-					strcmp(type, "prflx") == 0 ?
-					 FARSIGHT_CANDIDATE_TYPE_DERIVED :
-					 FARSIGHT_CANDIDATE_TYPE_RELAY;
-			 
-		candidates = g_list_append(candidates, ti);
+				 				FS_NETWORK_PROTOCOL_UDP :
+				 				FS_NETWORK_PROTOCOL_TCP,
+							xmlnode_get_attrib(candidate, "ip"),
+							atoi(xmlnode_get_attrib(candidate, "port")));
+		candidates = g_list_append(candidates, c);
 	}
 	
 	return candidates;
 }
 
-FarsightStream *
-jabber_jingle_session_get_stream(const JingleSession *sess)
-{
-	return sess->stream;
-}
-
-void
-jabber_jingle_session_set_stream(JingleSession *sess, FarsightStream *stream)
-{
-	sess->stream = stream;
-}
-
 PurpleMedia *
 jabber_jingle_session_get_media(const JingleSession *sess)
 {
@@ -237,36 +229,6 @@
 	return sess->is_initiator;
 }
 
-void
-jabber_jingle_session_add_remote_candidate(JingleSession *sess,
-										   const GList *candidate)
-{
-	/* the length of the candidate list should be 1... */
-	GList *cand = candidate;
-	for (; cand ; cand = cand->next) {
-		purple_debug_info("jingle", "Adding remote candidate with id = %s\n",
-						  ((FarsightTransportInfo *) cand->data)->candidate_id);
-		sess->remote_candidates = g_list_append(sess->remote_candidates, 
-												cand->data);
-	}
-}
-
-static GList *
-jabber_jingle_session_get_remote_candidate(const JingleSession *sess,
-										   const gchar *id)
-{
-	GList *candidates = NULL;
-	GList *find = sess->remote_candidates;
-	for (; find ; find = find->next) {
-		const FarsightTransportInfo *candidate =
-			(FarsightTransportInfo *) find->data;
-		if (!strcmp(candidate->candidate_id, id)) {
-			candidates = g_list_append(candidates, (void *) candidate);
-		}
-	}
-	return candidates;
-}
-
 static xmlnode *
 jabber_jingle_session_create_jingle_element(const JingleSession *sess,
 											const char *action)
@@ -301,32 +263,105 @@
 	return jingle;
 }
 
-static xmlnode *
+xmlnode *
 jabber_jingle_session_create_description(const JingleSession *sess)
 {
-    GList *codecs =
-		farsight_stream_get_local_codecs(jabber_jingle_session_get_stream(sess));
-    
+    GList *codecs = purple_media_get_local_audio_codecs(sess->media);
     xmlnode *description = xmlnode_new("description");
+
 	xmlnode_set_namespace(description, "urn:xmpp:tmp:jingle:apps:audio-rtp");
 	
 	/* get codecs */
 	for (; codecs ; codecs = codecs->next) {
-		FarsightCodec *codec = (FarsightCodec*)codecs->data;
-		char id[8], clockrate[10];
+		FsCodec *codec = (FsCodec*)codecs->data;
+		char id[8], clockrate[10], channels[10];
 		xmlnode *payload = xmlnode_new_child(description, "payload-type");
 		
 		g_snprintf(id, sizeof(id), "%d", codec->id);
 		g_snprintf(clockrate, sizeof(clockrate), "%d", codec->clock_rate);
+		g_snprintf(channels, sizeof(channels), "%d", codec->channels);
 		
 		xmlnode_set_attrib(payload, "name", codec->encoding_name);
 		xmlnode_set_attrib(payload, "id", id);
 		xmlnode_set_attrib(payload, "clockrate", clockrate);
+		xmlnode_set_attrib(payload, "channels", channels);
     }
     
+    fs_codec_list_destroy(codecs);
     return description;
 }
     
+static guint
+jabber_jingle_get_priority(guint type, guint network)
+{
+	switch (type) {
+		case FS_CANDIDATE_TYPE_HOST:
+			return network == 0 ? 4096 : network == 1 ? 2048 : 1024;
+			break;
+		case FS_CANDIDATE_TYPE_PRFLX:
+			return 126;
+			break;
+		case FS_CANDIDATE_TYPE_RELAY:
+			return 100;
+			break;
+		default:
+			return 0; /* unknown type, should not happen */
+	}
+}
+
+static xmlnode *
+jabber_jingle_session_create_candidate_info(FsCandidate *c, FsCandidate *remote)
+{
+	char port[8];
+	char prio[8];
+	char component[8];
+	xmlnode *candidate = NULL;
+	
+	candidate = xmlnode_new("candidate");
+	
+	g_snprintf(port, sizeof(port), "%d", c->port);
+	g_snprintf(prio, sizeof(prio), "%d", 
+		   jabber_jingle_get_priority(c->type, 0));
+	g_snprintf(component, sizeof(component), "%d", c->component_id);
+	
+	xmlnode_set_attrib(candidate, "component", component);
+	xmlnode_set_attrib(candidate, "foundation", "1"); /* what about this? */
+	xmlnode_set_attrib(candidate, "generation", "0"); /* ? */
+	xmlnode_set_attrib(candidate, "ip", c->ip);
+	xmlnode_set_attrib(candidate, "network", "0"); /* ? */
+	xmlnode_set_attrib(candidate, "port", port);
+	xmlnode_set_attrib(candidate, "priority", prio); /* Is this correct? */
+	xmlnode_set_attrib(candidate, "protocol",
+			   c->proto == FS_NETWORK_PROTOCOL_UDP ?
+			   "udp" : "tcp");
+	if (c->username)
+		xmlnode_set_attrib(candidate, "ufrag", c->username);
+	if (c->password)
+		xmlnode_set_attrib(candidate, "pwd", c->password);
+	
+	xmlnode_set_attrib(candidate, "type", 
+			   c->type == FS_CANDIDATE_TYPE_HOST ? 
+			   "host" :
+			   c->type == FS_CANDIDATE_TYPE_PRFLX ? 
+			   "prflx" :
+		       	   c->type == FS_CANDIDATE_TYPE_RELAY ? 
+			   "relay" : NULL);
+
+	/* relay */
+	if (c->type == FS_CANDIDATE_TYPE_RELAY) {
+		/* set rel-addr and rel-port? How? */
+	}
+
+	if (remote) {
+		char remote_port[8];
+		g_snprintf(remote_port, sizeof(remote_port), "%d", remote->port);
+		xmlnode_set_attrib(candidate, "rem-addr", remote->ip);
+		xmlnode_set_attrib(candidate, "rem-port", remote_port);
+	}
+
+	return candidate;
+}
+
 /* split into two separate methods, one to generate session-accept
 	(includes codecs) and one to generate transport-info (includes transports
 	candidates) */
@@ -337,6 +372,8 @@
 		jabber_jingle_session_create_jingle_element(sess, "session-accept");
 	xmlnode *content = NULL;
 	xmlnode *description = NULL;
+	xmlnode *transport = NULL;
+	xmlnode *candidate = NULL;
 	
 	
 	content = xmlnode_new_child(jingle, "content");
@@ -345,199 +382,82 @@
 	xmlnode_set_attrib(content, "profile", "RTP/AVP");
 	
 	description = jabber_jingle_session_create_description(sess);
-    xmlnode_insert_child(jingle, description);
-	
+	xmlnode_insert_child(content, description);
+
+	transport = xmlnode_new_child(content, "transport");
+	xmlnode_set_namespace(transport, "urn:xmpp:tmp:jingle:transports:ice-udp");
+	candidate = jabber_jingle_session_create_candidate_info(
+			purple_media_get_local_candidate(sess->media),
+			purple_media_get_remote_candidate(sess->media));
+	xmlnode_insert_child(transport, candidate);
+
 	return jingle;
 }
 
-static guint
-jabber_jingle_get_priority(guint type, guint network)
-{
-	switch (type) {
-		case FARSIGHT_CANDIDATE_TYPE_LOCAL:
-			return network == 0 ? 4096 : network == 1 ? 2048 : 1024;
-			break;
-		case FARSIGHT_CANDIDATE_TYPE_DERIVED:
-			return 126;
-			break;
-		case FARSIGHT_CANDIDATE_TYPE_RELAY:
-			return 100;
-			break;
-		default:
-			return 0; /* unknown type, should not happen */
-	}
-}
 
 xmlnode *
-jabber_jingle_session_create_transport_info(const JingleSession *sess,
-											gchar *candidate_id)
+jabber_jingle_session_create_transport_info(const JingleSession *sess)
 {
 	xmlnode *jingle = 
 		jabber_jingle_session_create_jingle_element(sess, "transport-info");
 	xmlnode *content = NULL;
 	xmlnode *transport = NULL;
-	GList *candidates =
-		farsight_stream_get_native_candidate(
-			jabber_jingle_session_get_stream(sess), candidate_id);
-	
+	GList *candidates = purple_media_get_local_audio_candidates(sess->media);
+
 	content = xmlnode_new_child(jingle, "content");
 	xmlnode_set_attrib(content, "creator", "initiator");
 	xmlnode_set_attrib(content, "name", "audio-content");
 	xmlnode_set_attrib(content, "profile", "RTP/AVP");
 		
 	transport = xmlnode_new_child(content, "transport");
-	xmlnode_set_namespace(transport, "urn:xmpp:tmp:jingle:transports:ice-tcp");
+	xmlnode_set_namespace(transport, "urn:xmpp:tmp:jingle:transports:ice-udp");
 	
 	/* get transport candidate */
 	for (; candidates ; candidates = candidates->next) {
-		FarsightTransportInfo *transport_info = 
-			(FarsightTransportInfo *) candidates->data;
-		char port[8];
-		char prio[8];
-		char component[8];
-		xmlnode *candidate = NULL;
-		
-		if (!strcmp(transport_info->ip, "127.0.0.1")) {
+		FsCandidate *c = (FsCandidate *) candidates->data;
+
+		if (!strcmp(c->ip, "127.0.0.1")) {
 			continue;
 		}
-		
-		candidate = xmlnode_new_child(transport, "candidate");
-		
-		g_snprintf(port, sizeof(port), "%d", transport_info->port);
-		g_snprintf(prio, sizeof(prio), "%d", 
-				   jabber_jingle_get_priority(transport_info->type, 0));
-		g_snprintf(component, sizeof(component), "%d", transport_info->component);
-		
-		xmlnode_set_attrib(candidate, "component", component);
-		xmlnode_set_attrib(candidate, "foundation", "1"); /* what about this? */
-		xmlnode_set_attrib(candidate, "generation", "0"); /* ? */
-		xmlnode_set_attrib(candidate, "ip", transport_info->ip);
-		xmlnode_set_attrib(candidate, "network", "0"); /* ? */
-		xmlnode_set_attrib(candidate, "port", port);
-		xmlnode_set_attrib(candidate, "priority", prio); /* Is this correct? */
-		xmlnode_set_attrib(candidate, "protocol",
-						   transport_info->proto == FARSIGHT_NETWORK_PROTOCOL_UDP ?
-						   "udp" : "tcp");
-		if (transport_info->username)
-			xmlnode_set_attrib(candidate, "ufrag", transport_info->username);
-		if (transport_info->password)
-			xmlnode_set_attrib(candidate, "pwd", transport_info->password);
-		
-		xmlnode_set_attrib(candidate, "type", 
-						   transport_info->type == FARSIGHT_CANDIDATE_TYPE_LOCAL ? 
-						   "host" :
-						   transport_info->type == FARSIGHT_CANDIDATE_TYPE_DERIVED ? 
-						   "prflx" :
-					       transport_info->type == FARSIGHT_CANDIDATE_TYPE_RELAY ? 
-						   "relay" : NULL);
-		
+
+		xmlnode_insert_child(transport,
+				     jabber_jingle_session_create_candidate_info(c, NULL));
 	}
-	farsight_transport_list_destroy(candidates);
+	fs_candidate_list_destroy(candidates);
 	
 	return jingle;
 }
 
 xmlnode *
 jabber_jingle_session_create_content_replace(const JingleSession *sess,
-											 gchar *native_candidate_id,
-											 gchar *remote_candidate_id)
+					     FsCandidate *native_candidate,
+					     FsCandidate *remote_candidate)
 {
 	xmlnode *jingle = 
 		jabber_jingle_session_create_jingle_element(sess, "content-replace");
 	xmlnode *content = NULL;
 	xmlnode *transport = NULL;
-	xmlnode *candidate = NULL;
-	xmlnode *description = NULL;
-	xmlnode *payload_type = NULL;
-	char local_port[8];
-	char remote_port[8];
-	char prio[8];
-	char component[8];
-	
+
 	purple_debug_info("jingle", "creating content-modify for native candidate %s " \
-					  ", remote candidate %s\n", native_candidate_id,
-					  remote_candidate_id);
-	
-	/* It seems the ID's we get from the Farsight callback is phony... */
-	/*
-	GList *native_candidates = 
-		farsight_stream_get_native_candidate(jabber_jingle_session_get_stream(sess),
-											 native_candidate_id);
-	purple_debug_info("jingle", "found %d native candidates with id %s\n",
-					  g_list_length(native_candidates), native_candidate_id);
-	GList *remote_candidates =
-		jabber_jingle_session_get_remote_candidate(sess, remote_candidate_id);
-	*/
-	
-	/* we assume lists have length == 1, I think they must... */
-	/*
-	FarsightTransportInfo *native = 
-		(FarsightTransportInfo *) native_candidates->data;
-	FarsightTransportInfo *remote =
-		(FarsightTransportInfo *) remote_candidates->data;
-	*/
-	
+			  ", remote candidate %s\n", native_candidate->candidate_id,
+			  remote_candidate->candidate_id);
+
 	content = xmlnode_new_child(jingle, "content");
 	xmlnode_set_attrib(content, "creator", "initiator");
 	xmlnode_set_attrib(content, "name", "audio-content");
 	xmlnode_set_attrib(content, "profile", "RTP/AVP");
 	
-	description = xmlnode_new_child(content, "description");
-	xmlnode_set_namespace(description, "urn:xmpp:tmp:jingle:apps:audio-rtp");
-	
-	payload_type = xmlnode_new_child(description, "payload-type");
 	/* get top codec from codec_intersection to put here... */
 	/* later on this should probably handle changing codec */
-	
-	/* Skip creating the actual "content" element for now, since we don't
-		get enough info in the Farsight callback */
-#if 0
-	transport = xmlnode_new_child(content, "transport");
-	xmlnode_set_namespace(transport, "urn:xmpp:tmp:jingle:transports:ice-tcp");
-	
-	candidate = xmlnode_new_child(transport, "candidate");
-	
-	g_snprintf(local_port, sizeof(local_port), "%d", native->port);
-	g_snprintf(remote_port, sizeof(remote_port), "%d", remote->port);
-	g_snprintf(prio, sizeof(prio), "%d",
-			   jabber_jingle_get_priority(native->type, 0));
-	g_snprintf(component, sizeof(component), "%d", native->component);
+
+	xmlnode_insert_child(content, jabber_jingle_session_create_description(sess));
 
-	xmlnode_set_attrib(candidate, "component", component);
-	xmlnode_set_attrib(candidate, "foundation", "1"); /* what about this? */
-	xmlnode_set_attrib(candidate, "generation", "0"); /* ? */
-	xmlnode_set_attrib(candidate, "ip", native->ip);
-	xmlnode_set_attrib(candidate, "network", "1"); /* ? */
-	xmlnode_set_attrib(candidate, "port", local_port);
-	xmlnode_set_attrib(candidate, "priority", prio); /* Is this correct? */
-	xmlnode_set_attrib(candidate, "protocol", 
-					   native->proto == FARSIGHT_NETWORK_PROTOCOL_UDP ? 
-					   "udp" : "tcp");
-	if (native->username)
-		xmlnode_set_attrib(candidate, "ufrag", native->username);
-	if (native->password)
-		xmlnode_set_attrib(candidate, "pwd", native->password);
-		
-	xmlnode_set_attrib(candidate, "type", 
-					   native->type == FARSIGHT_CANDIDATE_TYPE_LOCAL ? 
-					   "host" : 
-					   native->type == FARSIGHT_CANDIDATE_TYPE_DERIVED ? 
-					   "prflx" : 
-					   native->type == FARSIGHT_CANDIDATE_TYPE_RELAY ? 
-					   "relay" : NULL);
-	/* relay */
-	if (native->type == FARSIGHT_CANDIDATE_TYPE_RELAY) {
-		/* set rel-addr and rel-port? How? */
-	}
-	
-	xmlnode_set_attrib(candidate, "rem-addr", remote->ip);
-	xmlnode_set_attrib(candidate, "rem-port", remote_port);
-	
-	farsight_transport_list_destroy(native_candidates);
-	farsight_transport_list_destroy(remote_candidates);
-	
-#endif /* 0 */
-	
+	transport = xmlnode_new_child(content, "transport");
+	xmlnode_set_namespace(transport, "urn:xmpp:tmp:jingle:transports:ice-udp");
+	xmlnode_insert_child(transport,
+			     jabber_jingle_session_create_candidate_info(native_candidate,
+									 remote_candidate));
+
 	purple_debug_info("jingle", "End create content modify\n");
 	
 	return jingle;
@@ -556,24 +476,9 @@
 	xmlnode_set_attrib(content, "name", "audio-content");
 	xmlnode_set_attrib(content, "profile", "RTP/AVP");
 	
-    xmlnode_insert_child(jingle, description);
+    xmlnode_insert_child(content, description);
     
 	return jingle;
 }
 
-void
-jabber_jingle_session_set_remote_codecs(JingleSession *sess, GList *codecs)
-{
-    if (sess->remote_codecs) {
-        farsight_codec_list_destroy(sess->remote_codecs);
-    }
-    sess->remote_codecs = codecs;
-}
-
-GList *
-jabber_jingle_session_get_remote_codecs(const JingleSession *sess)
-{
-    return sess->remote_codecs;
-}
-
 #endif /* USE_FARSIGHT */
--- a/libpurple/protocols/jabber/jingle.h	Tue May 27 06:51:21 2008 +0000
+++ b/libpurple/protocols/jabber/jingle.h	Tue May 27 16:30:26 2008 +0000
@@ -26,20 +26,16 @@
 
 #ifdef USE_FARSIGHT
 
-#include <farsight/farsight.h>
-
 G_BEGIN_DECLS
 
 typedef struct {
 	char *id;
 	JabberStream *js;
-	FarsightStream *stream;
 	PurpleMedia *media;
 	char *remote_jid;
 	char *initiator;
 	gboolean is_initiator;
-	GList *remote_candidates;
-    GList *remote_codecs;
+	gboolean session_started;
 } JingleSession;
 
 JingleSession *jabber_jingle_session_create(JabberStream *js);
@@ -51,10 +47,8 @@
 
 void jabber_jingle_session_destroy(JingleSession *sess);
 
-JingleSession *jabber_jingle_session_find_by_id(const char *id);
-
-FarsightStream *jabber_jingle_session_get_stream(const JingleSession *sess);
-void jabber_jingle_session_set_stream(JingleSession *sess, FarsightStream *stream);
+JingleSession *jabber_jingle_session_find_by_id(JabberStream *js, const char *id);
+JingleSession *jabber_jingle_session_find_by_jid(JabberStream *js, const char *jid);
 
 PurpleMedia *jabber_jingle_session_get_media(const JingleSession *sess);
 void jabber_jingle_session_set_media(JingleSession *sess, PurpleMedia *media);
@@ -70,20 +64,16 @@
 void jabber_jingle_session_set_initiator(JingleSession *sess, 
 										 const char *initiator);
 
-void jabber_jingle_session_add_remote_candidate(JingleSession *sess,
-												const GList *candidate);
-
 xmlnode *jabber_jingle_session_create_terminate(const JingleSession *sess,
 												const char *reasoncode,
 												const char *reasontext);
-
 xmlnode *jabber_jingle_session_create_session_accept(const JingleSession *sess);
-xmlnode *jabber_jingle_session_create_transport_info(const JingleSession *sess,
-													 gchar *candidate_id);
+xmlnode *jabber_jingle_session_create_transport_info(const JingleSession *sess);
 xmlnode *jabber_jingle_session_create_content_replace(const JingleSession *sess,
-													  gchar *native_candidate_id,
-													  gchar *remote_candidate_id);
+						      FsCandidate *native_candidate,
+						      FsCandidate *remote_candidate);
 xmlnode *jabber_jingle_session_create_content_accept(const JingleSession *sess);
+xmlnode *jabber_jingle_session_create_description(const JingleSession *sess);
 
 /**
  * Gets a list of Farsight codecs from a Jingle <description> tag
@@ -95,10 +85,6 @@
 
 GList *jabber_jingle_get_candidates(const xmlnode *transport);
 
-void jabber_jingle_session_set_remote_codecs(JingleSession *sess,
-                                             GList *codecs);
-GList *jabber_jingle_session_get_remote_codecs(const JingleSession *sess);
-
 G_END_DECLS
 
 #endif /* USE_FARSIGHT */
--- a/libpurple/protocols/jabber/libxmpp.c	Tue May 27 06:51:21 2008 +0000
+++ b/libpurple/protocols/jabber/libxmpp.c	Tue May 27 16:30:26 2008 +0000
@@ -117,8 +117,13 @@
 	jabber_attention_types,			/* attention_types */
 	sizeof(PurplePluginProtocolInfo),       /* struct_size */
 	NULL, /* get_account_text_table */
+#ifdef USE_FARSIGHT
 	jabber_initiate_media,          /* initiate_media */
 	jabber_can_do_media             /* can_do_media */
+#else
+	NULL,					/* initiate_media */
+	NULL					/* can_do_media */
+#endif
 };
 
 static gboolean load_plugin(PurplePlugin *plugin)
--- a/libpurple/server.c	Tue May 27 06:51:21 2008 +0000
+++ b/libpurple/server.c	Tue May 27 16:30:26 2008 +0000
@@ -1095,5 +1095,18 @@
 		return FALSE;
 	}
 }
-    
-#endif
+#else
+void *
+serv_initiate_media(void *gc, void *who, void *type)
+{
+	purple_debug_info("serv", "Blank serv_initiate_media called\n");
+	return NULL;
+}
+
+void *
+serv_can_do_media(void *gc, void *who, void *type)
+{
+	purple_debug_info("serv", "Blank serv_can_do_media called\n");
+	return NULL;
+}
+#endif /* USE_FARSIGHT */
--- a/pidgin/gtkconv.c	Tue May 27 06:51:21 2008 +0000
+++ b/pidgin/gtkconv.c	Tue May 27 16:30:26 2008 +0000
@@ -7652,7 +7652,8 @@
 							purple_conversation_get_name(conv),
 							PURPLE_MEDIA_RECV_AUDIO & PURPLE_MEDIA_SEND_AUDIO);
 
-	purple_media_wait(media);
+	if (media)
+		purple_media_wait(media);
 }
 
 static void
@@ -7789,9 +7790,10 @@
 								show_protocol_icons_pref_cb, NULL);
 	purple_prefs_connect_callback(handle, PIDGIN_PREFS_ROOT "/conversations/im/hide_new",
                                 hide_new_pref_cb, NULL);
-
+#ifdef USE_FARSIGHT
 	g_signal_connect(G_OBJECT(purple_media_manager_get()), "init-media",
 			 G_CALLBACK(pidgin_conv_new_media_cb), NULL);
+#endif
 
 
 	/**********************************************************************
--- a/pidgin/gtkmedia.c	Tue May 27 06:51:21 2008 +0000
+++ b/pidgin/gtkmedia.c	Tue May 27 16:30:26 2008 +0000
@@ -32,8 +32,6 @@
 
 #ifdef USE_FARSIGHT
 
-#include <farsight/farsight.h>
-
 typedef enum
 {
 	/* Waiting for response */
@@ -181,37 +179,18 @@
 	gtk_widget_show_all(media->priv->reject);
 }
 
-static void
-pidgin_media_finalize (GObject *media)
-{
-	PidginMedia *gtkmedia = PIDGIN_MEDIA(media);
-	if (gtkmedia->priv->media)
-		g_object_unref(gtkmedia->priv->media);
-	if (gtkmedia->priv->send_level)
-		gst_object_unref(gtkmedia->priv->send_level);
-	if (gtkmedia->priv->recv_level)
-		gst_object_unref(gtkmedia->priv->recv_level);
-}
-
-static void
-pidgin_media_emit_message(PidginMedia *gtkmedia, const char *msg)
-{
-	g_signal_emit(gtkmedia, pidgin_media_signals[MESSAGE], 0, msg);
-}
-
 static gboolean
 level_message_cb(GstBus *bus, GstMessage *message, PidginMedia *gtkmedia)
 {
 	const GstStructure *s;
 	const gchar *name;
 
-	int channels;
-	gdouble rms_db, peak_db, decay_db;
-	gdouble rms;
+	gdouble rms_db;
+	gdouble percent;
 	const GValue *list;
 	const GValue *value;
 
-	GstElement *src = GST_ELEMENT(message);
+	GstElement *src = GST_ELEMENT(GST_MESSAGE_SRC(message));
 
 	if (message->type != GST_MESSAGE_ELEMENT)
 		return TRUE;
@@ -228,14 +207,52 @@
 	value = gst_value_list_get_value(list, 0);
 	rms_db = g_value_get_double(value);
 
+	percent = pow(10, rms_db / 20) * 5;
+
+	if(percent > 1.0)
+		percent = 1.0;
+
 	if (!strcmp(gst_element_get_name(src), "sendlevel"))	
-		gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(gtkmedia->priv->send_progress), pow(10, rms_db / 20) * 5);
+		gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(gtkmedia->priv->send_progress), percent);
 	else
-		gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(gtkmedia->priv->recv_progress), pow(10, rms_db / 20) * 5);
+		gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(gtkmedia->priv->recv_progress), percent);
 
 	return TRUE;
 }
 
+
+static void
+pidgin_media_disconnect_levels(PurpleMedia *media, PidginMedia *gtkmedia)
+{
+	GstElement *element = purple_media_get_audio_pipeline(media);
+	gulong handler_id = g_signal_handler_find(G_OBJECT(gst_pipeline_get_bus(GST_PIPELINE(element))),
+						  G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA, 0, 0, 
+						  NULL, G_CALLBACK(level_message_cb), gtkmedia);
+	if (handler_id)
+		g_signal_handler_disconnect(G_OBJECT(gst_pipeline_get_bus(GST_PIPELINE(element))),
+					    handler_id);
+}
+
+static void
+pidgin_media_finalize (GObject *media)
+{
+	PidginMedia *gtkmedia = PIDGIN_MEDIA(media);
+	if (gtkmedia->priv->media) {
+		pidgin_media_disconnect_levels(gtkmedia->priv->media, gtkmedia);
+		g_object_unref(gtkmedia->priv->media);
+	}
+	if (gtkmedia->priv->send_level)
+		gst_object_unref(gtkmedia->priv->send_level);
+	if (gtkmedia->priv->recv_level)
+		gst_object_unref(gtkmedia->priv->recv_level);
+}
+
+static void
+pidgin_media_emit_message(PidginMedia *gtkmedia, const char *msg)
+{
+	g_signal_emit(gtkmedia, pidgin_media_signals[MESSAGE], 0, msg);
+}
+
 static void
 pidgin_media_ready_cb(PurpleMedia *media, PidginMedia *gtkmedia)
 {
--- a/pidgin/gtkmedia.h	Tue May 27 06:51:21 2008 +0000
+++ b/pidgin/gtkmedia.h	Tue May 27 16:30:26 2008 +0000
@@ -28,7 +28,6 @@
 
 #ifdef USE_FARSIGHT
 
-#include <farsight/farsight.h>
 #include <gtk/gtk.h>
 #include <glib-object.h>
 
--- a/pidgin/gtkprefs.c	Tue May 27 06:51:21 2008 +0000
+++ b/pidgin/gtkprefs.c	Tue May 27 16:30:26 2008 +0000
@@ -2027,9 +2027,9 @@
 	GList *ret = NULL;
 
 	for(; devices ; devices = devices->next) {
-		gchar *name = purple_media_get_device_name(element, devices->data);
+		gchar *name = purple_media_get_device_name(GST_ELEMENT(element), devices->data);
 		ret = g_list_append(ret, name);
-		ret = g_list_append(ret, name);
+		ret = g_list_append(ret, g_value_dup_string(devices->data));
 	}
 
 	return ret;
@@ -2037,36 +2037,132 @@
 
 /*
  * Test functions to run video preview
- * (this is not really functional right now...)
- *
  */
+static gboolean
+preview_video_bus_call(GstBus *bus, GstMessage *msg, gpointer pipeline)
+{
+	switch(GST_MESSAGE_TYPE(msg)) {
+		case GST_MESSAGE_EOS:
+			purple_debug_info("preview-video", "End of Stream\n");
+			break;
+		case GST_MESSAGE_ERROR: {
+			gchar *debug = NULL;
+			GError *err = NULL;
+
+			gst_message_parse_error(msg, &err, &debug);
+
+			purple_debug_error("preview-video", "Error: %s\n", err->message);
+			g_error_free(err);
+
+			if (debug) {
+				purple_debug_error("preview-video", "details: %s\n", debug);
+				g_free (debug);
+			}
+			break;
+		}
+		default:
+			return TRUE;
+	}
+
+	gst_element_set_state(pipeline, GST_STATE_NULL);
+	gst_object_unref(GST_PIPELINE(pipeline));
+	return TRUE;
+}
+
 static void
 preview_button_clicked(GtkWidget *widget, gpointer *data)
 {
-	GstElement *video = (GstElement *) data;
+	const char *plugin = purple_prefs_get_string("/purple/media/video/plugin");
+	const char *device = purple_prefs_get_string("/purple/media/video/device");
+	GstBus *bus;
 
 	/* create a preview window... */
-	GstElement *output = gst_element_factory_make("autovideosink", NULL);
 	GstElement *pipeline = NULL;
 	GError *p_err;
 
-	gchar test_pipeline_str[50] = "v4lsrc ! ffmpegcolorspace ! autovideosink";
+	gchar *test_pipeline_str = NULL;
+
+	if (strlen(device) > 0)
+		test_pipeline_str = g_strdup_printf("%s device=\"%s\" !" \
+						    " ffmpegcolorspace !" \
+						    " autovideosink",
+						    plugin, device);
+	else
+		test_pipeline_str = g_strdup_printf("%s ! ffmpegcolorspace !" \
+						    " autovideosink", plugin);
+
 	pipeline = gst_parse_launch (test_pipeline_str, &p_err);
 
+	g_free(test_pipeline_str);
+
+	bus = gst_pipeline_get_bus(GST_PIPELINE(pipeline));
+	gst_bus_add_watch(bus, preview_video_bus_call, pipeline);
+	gst_object_unref(bus);
+
 	gst_element_set_state(pipeline, GST_STATE_PLAYING);
 }
 
+static void
+media_plugin_changed_cb(const gchar *name, PurplePrefType type,
+			gconstpointer value, gpointer data)
+{
+	GtkWidget *hbox = data;
+	GtkWidget *dd = NULL;
+	GtkWidget *preview_button = NULL;
+	const char *plugin = value;
+	const char *device = purple_prefs_get_string("/purple/media/video/device");
+	GstElement *video = purple_media_get_element(plugin);
+	GList *video_devices = purple_media_get_devices(video);
+	GList *video_items = get_device_items(video, video_devices);
+	GList *list;
+	g_list_free(video_devices);
+
+	if (video_items == NULL) {
+		video_items = g_list_prepend(video_items, g_strdup(""));
+		video_items = g_list_prepend(video_items, g_strdup("Default"));
+	}
+
+	if (g_list_find(video_items, device) == NULL)
+	{
+		purple_prefs_set_string("/purple/media/video/device", 
+					g_list_next(video_items)->data);
+	}
+
+	list = gtk_container_get_children(GTK_CONTAINER(hbox));
+
+	while (list) {
+		gtk_widget_destroy(list->data);
+		list = g_list_delete_link(list, list);
+	}
+
+	dd = pidgin_prefs_dropdown_from_list(hbox, _("_Device:"), PURPLE_PREF_STRING,
+					     "/purple/media/video/device",
+					     video_items);
+
+	gtk_misc_set_alignment(GTK_MISC(dd), 0, 0.5);
+
+	preview_button = gtk_button_new_with_mnemonic(_("_Preview"));
+	g_signal_connect(G_OBJECT(preview_button), "clicked",
+			 G_CALLBACK(preview_button_clicked), video);
+
+	gtk_container_add(GTK_CONTAINER(hbox), preview_button);
+
+	gtk_widget_show_all(hbox);
+}
+
 static GtkWidget *
 media_page()
 {
 	GtkWidget *ret;
-	GtkWidget *sg;
 	GtkWidget *vbox;
 	GtkWidget *hbox;
 	GtkWidget *dd;
 	GtkWidget *preview_button;
-
-	GstElement *video = purple_media_get_element("v4lsrc");
+	GtkSizeGroup *sg;
+	const char *plugin = purple_prefs_get_string("/purple/media/video/plugin");
+	const char *device = purple_prefs_get_string("/purple/media/video/device");
+
+	GstElement *video = purple_media_get_element(plugin);
 	GstElement *audio = purple_media_get_element("alsasrc");
 
 	GList *video_devices = purple_media_get_devices(video);
@@ -2078,17 +2174,46 @@
 	g_list_free(video_devices);
 	g_list_free(audio_devices);
 
+	if (video_items == NULL) {
+		video_items = g_list_prepend(video_items, "");
+		video_items = g_list_prepend(video_items, "Default");
+	}
+
+	if (g_list_find(video_items, device) == NULL)
+	{
+		purple_prefs_set_string("/purple/media/video/device", 
+					g_list_next(video_items)->data);
+	}
+
 	ret = gtk_vbox_new(FALSE, PIDGIN_HIG_CAT_SPACE);
 	gtk_container_set_border_width (GTK_CONTAINER (ret), PIDGIN_HIG_BORDER);
 
 	sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
 
 	vbox = pidgin_make_frame (ret, _("Video Input"));
+
+	hbox = gtk_hbox_new(FALSE, PIDGIN_HIG_BOX_SPACE);
+	dd = pidgin_prefs_dropdown(vbox, _("_Plugin:"), PURPLE_PREF_STRING,
+				   "/purple/media/video/plugin",
+				   _("Default"), "gconfvideosrc",
+				   _("Video4Linux"), "v4lsrc",
+				   _("Video4Linux2"), "v4l2src",
+				   NULL);
+
+	gtk_size_group_add_widget(sg, dd);
+	gtk_misc_set_alignment(GTK_MISC(dd), 0, 0.5);
+
 	hbox = gtk_hbox_new(FALSE, PIDGIN_HIG_BOX_SPACE);
 	dd = pidgin_prefs_dropdown_from_list(hbox, _("_Device:"), PURPLE_PREF_STRING,
 			"/purple/media/video/device",
 			video_items);
 
+	purple_prefs_connect_callback(prefs, "/purple/media/video/plugin",
+				      media_plugin_changed_cb, hbox);
+
+	g_signal_connect_swapped(hbox, "destroy",
+				 G_CALLBACK(purple_prefs_disconnect_by_handle), hbox);
+
 	gtk_size_group_add_widget(sg, dd);
 	gtk_misc_set_alignment(GTK_MISC(dd), 0, 0.5);
 
@@ -2096,8 +2221,8 @@
 	g_signal_connect(G_OBJECT(preview_button), "clicked",
 			G_CALLBACK(preview_button_clicked), video);
 
-	gtk_container_add(hbox, preview_button);
-	gtk_container_add(vbox, hbox);
+	gtk_container_add(GTK_CONTAINER(hbox), preview_button);
+	gtk_container_add(GTK_CONTAINER(vbox), hbox);
 
 	vbox = pidgin_make_frame (ret, _("Audio Input"));
 	dd = pidgin_prefs_dropdown_from_list(vbox, _("_Device:"), PURPLE_PREF_STRING,
@@ -2242,7 +2367,7 @@
 	prefs_notebook_add_page(_("Smiley Themes"), theme_page(), notebook_page++);
 	prefs_notebook_add_page(_("Sounds"), sound_page(), notebook_page++);
 
-#if USE_FARSIGHT
+#ifdef USE_FARSIGHT
 	prefs_notebook_add_page(_("Media"), media_page(), notebook_page++);
 #endif	
 	prefs_notebook_add_page(_("Network"), network_page(), notebook_page++);
@@ -2373,6 +2498,7 @@
 #ifdef USE_FARSIGHT
 	purple_prefs_add_none("/purple/media");
 	purple_prefs_add_none("/purple/media/video");
+	purple_prefs_add_string("/purple/media/video/plugin", "gconfvideosrc");
 	purple_prefs_add_string("/purple/media/video/device", "");
 	purple_prefs_add_none("/purple/media/audio");
 	purple_prefs_add_string("/purple/media/audio/device", "");