changeset 25656:e17dbd941380

merge of '0685fc29468269a2af68268baa627b09f83339e4' and '8222acabc1382453e8dda5b8d507e4df0f0a91ff'
author Mike Ruprecht <maiku@soc.pidgin.im>
date Tue, 27 May 2008 04:55:10 +0000
parents f47be691e588 (current diff) 5f4807116f8c (diff)
children 7d2e5f57dbca
files
diffstat 16 files changed, 297 insertions(+), 89 deletions(-) [+]
line wrap: on
line diff
--- a/configure.ac	Tue May 27 04:54:12 2008 +0000
+++ b/configure.ac	Tue May 27 04:55:10 2008 +0000
@@ -724,16 +724,15 @@
 dnl #######################################################################
 dnl # Check for Farsight
 dnl #######################################################################
-AC_ARG_ENABLE(farsight2,
+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, [farsight2-0.10], [
+	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
@@ -755,7 +754,6 @@
   		AC_SUBST(GSTPROPS_LIBS)
   		AC_SUBST(GSTPROPS_CFLAGS)
   ], [
-		AC_MSG_RESULT(no)
 		enable_gstprops="no"
   ])
 fi
--- a/finch/gntmedia.c	Tue May 27 04:54:12 2008 +0000
+++ b/finch/gntmedia.c	Tue May 27 04:55:10 2008 +0000
@@ -388,8 +388,6 @@
 				NULL));
 }
 
-#endif  /* USE_FARSIGHT */
-
 static void
 gntmedia_message_cb(FinchMedia *gntmedia, const char *msg, PurpleConversation *conv)
 {
@@ -456,3 +454,5 @@
 			G_CALLBACK(finch_new_media), NULL);
 }
 
+#endif  /* USE_FARSIGHT */
+
--- a/finch/gntui.c	Tue May 27 04:54:12 2008 +0000
+++ b/finch/gntui.c	Tue May 27 04:55:10 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/media.c	Tue May 27 04:54:12 2008 +0000
+++ b/libpurple/media.c	Tue May 27 04:55:10 2008 +0000
@@ -546,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;
@@ -571,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);
 			}
 		}
 	}
@@ -704,7 +710,7 @@
 	gst_element_set_state(pipeline, GST_STATE_PLAYING);
 }
 
-static void
+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)
@@ -718,7 +724,18 @@
 	FsSession *s = NULL;
 
 	if (!*session) {
-		*session = fs_conference_new_session(media->priv->conference, type, NULL);
+		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;
@@ -776,9 +793,11 @@
 		/* change direction */
 		g_object_set(stream, "direction", type_direction, NULL);
 	}
+
+	return TRUE;
 }
 
-void
+gboolean
 purple_media_add_stream(PurpleMedia *media, const gchar *who,
 			PurpleMediaStreamType type,
 			const gchar *transmitter)
@@ -795,11 +814,13 @@
 		else
 			type_direction = FS_DIRECTION_NONE;
 
-		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);
+		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)
@@ -811,12 +832,15 @@
 		else
 			type_direction = FS_DIRECTION_NONE;
 
-		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);
+		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
--- a/libpurple/media.h	Tue May 27 04:54:12 2008 +0000
+++ b/libpurple/media.h	Tue May 27 04:55:10 2008 +0000
@@ -113,7 +113,7 @@
 
 void purple_media_audio_init_recv(GstElement **recvbin, GstElement **recvlevel);
 
-void purple_media_add_stream(PurpleMedia *media, const gchar *who,
+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);
 
--- a/libpurple/mediamanager.c	Tue May 27 04:54:12 2008 +0000
+++ b/libpurple/mediamanager.c	Tue May 27 04:55:10 2008 +0000
@@ -133,13 +133,22 @@
 				  const char *conference_type,
 				  const char *remote_user)
 {
+	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);
 
-	PurpleMedia *media = PURPLE_MEDIA(g_object_new(purple_media_get_type(),
-					  "screenname", remote_user,
-					  "connection", gc, 
-					  "farsight-conference", conference,
-					  NULL));
+	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/protocols/jabber/google.c	Tue May 27 04:54:12 2008 +0000
+++ b/libpurple/protocols/jabber/google.c	Tue May 27 04:55:10 2008 +0000
@@ -18,8 +18,6 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
  */
 
-#include <gst/farsight/fs-conference-iface.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;
@@ -323,10 +324,12 @@
 		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;
 
@@ -372,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 04:54:12 2008 +0000
+++ b/libpurple/protocols/jabber/jabber.c	Tue May 27 04:55:10 2008 +0000
@@ -58,7 +58,9 @@
 #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)
 
@@ -632,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,
@@ -1244,12 +1250,15 @@
 
 #ifdef USE_FARSIGHT
 	/* Close all of the open media sessions on this stream */
-	GList *iter = jabber_jingle_session_find_by_js(js);
+	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
@@ -2475,15 +2484,25 @@
 	}
 }
 
-static void
+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 */
-	purple_media_add_stream(media, remote_jid, PURPLE_MEDIA_AUDIO, "rawudp");
+	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);
@@ -2502,6 +2521,8 @@
 				 G_CALLBACK(jabber_session_candidate_pair_established), session);
 
 	purple_media_ready(media);
+
+	return TRUE;
 }
 
 static void
@@ -2572,7 +2593,12 @@
 	/* set ourselves as initiator */
 	me = g_strdup_printf("%s@%s/%s", js->user->node, js->user->domain, js->user->resource);
 
-	jabber_initiate_media_internal(session, me, jid);
+	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);
@@ -2625,7 +2651,7 @@
 	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);
+	JingleSession *session = jabber_jingle_session_find_by_id(js, sid);
 	GList *remote_codecs = NULL;
 	GList *remote_transports = NULL;
 	GList *codec_intersection;
@@ -2706,7 +2732,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));
@@ -2732,7 +2763,7 @@
 	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");
@@ -2757,7 +2788,7 @@
 {
 	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 (!jabber_jingle_session_is_initiator(session) && session->session_started) {
 		JabberIq *result = jabber_iq_new(js, JABBER_IQ_RESULT);
@@ -2799,7 +2830,7 @@
 	sid = xmlnode_get_attrib(jingle, "sid");
 	initiator = xmlnode_get_attrib(jingle, "initiator");
 
-	if (jabber_jingle_session_find_by_id(sid)) {
+	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;
@@ -2822,7 +2853,12 @@
 		return;
 	}
 
-	jabber_initiate_media_internal(session, initiator, initiator);
+	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);
 
--- a/libpurple/protocols/jabber/jabber.h	Tue May 27 04:54:12 2008 +0000
+++ b/libpurple/protocols/jabber/jabber.h	Tue May 27 04:55:10 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 04:54:12 2008 +0000
+++ b/libpurple/protocols/jabber/jingle.c	Tue May 27 04:55:10 2008 +0000
@@ -30,9 +30,6 @@
 
 #include <gst/farsight/fs-candidate.h>
 
-/* keep a hash table of JingleSessions */
-static GHashTable *sessions = NULL;
-
 static gboolean
 jabber_jingle_session_equal(gconstpointer a, gconstpointer b)
 {
@@ -58,13 +55,13 @@
 	}
 	
 	/* 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);
+	g_hash_table_insert(js->sessions, sess->id, sess);
 
 	sess->session_started = FALSE;
 
@@ -102,43 +99,25 @@
 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);
 	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: %p\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: %p\n", g_hash_table_lookup(sessions, id));  
-	return (JingleSession *) g_hash_table_lookup(sessions, id);
-}
-
-GList *
-jabber_jingle_session_find_by_js(JabberStream *js)
-{
-	GList *values = g_hash_table_get_values(sessions);
-	GList *iter = values;
-	GList *found = NULL;
-
-	for (; iter; iter = iter->next) {
-		JingleSession *session = (JingleSession *)iter->data;
-		if (session->js == js) {
-			found = g_list_prepend(found, session);
-		}
-	}
-
-	g_list_free(values);
-	return found;
+					  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(sessions);
+	GList *values = g_hash_table_get_values(js->sessions);
 	GList *iter = values;
 
 	for (; iter; iter = iter->next) {
--- a/libpurple/protocols/jabber/jingle.h	Tue May 27 04:54:12 2008 +0000
+++ b/libpurple/protocols/jabber/jingle.h	Tue May 27 04:55:10 2008 +0000
@@ -47,8 +47,7 @@
 
 void jabber_jingle_session_destroy(JingleSession *sess);
 
-JingleSession *jabber_jingle_session_find_by_id(const char *id);
-GList *jabber_jingle_session_find_by_js(JabberStream *js);
+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);
--- a/libpurple/protocols/jabber/libxmpp.c	Tue May 27 04:54:12 2008 +0000
+++ b/libpurple/protocols/jabber/libxmpp.c	Tue May 27 04:55:10 2008 +0000
@@ -116,8 +116,13 @@
 	jabber_send_attention,			/* send_attention */
 	jabber_attention_types,			/* attention_types */
 	sizeof(PurplePluginProtocolInfo),       /* struct_size */
+#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 04:54:12 2008 +0000
+++ b/libpurple/server.c	Tue May 27 04:55:10 2008 +0000
@@ -1083,5 +1083,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 04:54:12 2008 +0000
+++ b/pidgin/gtkconv.c	Tue May 27 04:55:10 2008 +0000
@@ -7694,7 +7694,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
@@ -7827,9 +7828,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 04:54:12 2008 +0000
+++ b/pidgin/gtkmedia.c	Tue May 27 04:55:10 2008 +0000
@@ -228,7 +228,9 @@
 	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);
-	g_signal_handler_disconnect(G_OBJECT(gst_pipeline_get_bus(GST_PIPELINE(element))), handler_id);
+	if (handler_id)
+		g_signal_handler_disconnect(G_OBJECT(gst_pipeline_get_bus(GST_PIPELINE(element))),
+					    handler_id);
 }
 
 static void
--- a/pidgin/gtkprefs.c	Tue May 27 04:54:12 2008 +0000
+++ b/pidgin/gtkprefs.c	Tue May 27 04:55:10 2008 +0000
@@ -1920,9 +1920,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;
@@ -1930,36 +1930,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);
@@ -1971,17 +2067,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);
 
@@ -1989,8 +2114,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,
@@ -2135,7 +2260,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++);
@@ -2266,6 +2391,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", "");