changeset 26402:081a819bc710

Hide and gobjectify PurpleMediaElementInfo.
author Mike Ruprecht <maiku@soc.pidgin.im>
date Thu, 02 Apr 2009 00:11:49 +0000
parents b4621f3c276e
children f0de2405c2f1
files finch/gntmedia.c libpurple/media-gst.h libpurple/mediamanager.c pidgin/gtkmedia.c
diffstat 4 files changed, 416 insertions(+), 100 deletions(-) [+]
line wrap: on
line diff
--- a/finch/gntmedia.c	Wed Apr 01 23:43:38 2009 +0000
+++ b/finch/gntmedia.c	Thu Apr 02 00:11:49 2009 +0000
@@ -465,31 +465,30 @@
 
 	return bin;
 }
-
-static PurpleMediaElementInfo default_audio_src =
-{
-	"finchdefaultaudiosrc",		/* id */
-	PURPLE_MEDIA_ELEMENT_AUDIO	/* type */
-			| PURPLE_MEDIA_ELEMENT_SRC
-			| PURPLE_MEDIA_ELEMENT_ONE_SRC
-			| PURPLE_MEDIA_ELEMENT_UNIQUE,
-	create_default_audio_src,	/* create */
-};
-
-static PurpleMediaElementInfo default_audio_sink =
-{
-	"finchdefaultaudiosink",	/* id */
-	PURPLE_MEDIA_ELEMENT_AUDIO	/* type */
-			| PURPLE_MEDIA_ELEMENT_SINK
-			| PURPLE_MEDIA_ELEMENT_ONE_SINK,
-	create_default_audio_sink,	/* create */
-};
 #endif  /* USE_VV */
 
 void finch_media_manager_init(void)
 {
 #ifdef USE_VV
 	PurpleMediaManager *manager = purple_media_manager_get();
+	PurpleMediaElementInfo *default_audio_src =
+			g_object_new(PURPLE_TYPE_MEDIA_ELEMENT_INFO,
+			"id", "finchdefaultaudiosrc",
+			"name", "Finch Default Audio Source",
+			"type", PURPLE_MEDIA_ELEMENT_AUDIO
+					| PURPLE_MEDIA_ELEMENT_SRC
+					| PURPLE_MEDIA_ELEMENT_ONE_SRC
+					| PURPLE_MEDIA_ELEMENT_UNIQUE,
+			"create-cb", create_default_audio_src, NULL);
+	PurpleMediaElementInfo *default_audio_sink =
+			g_object_new(PURPLE_TYPE_MEDIA_ELEMENT_INFO,
+			"id", "finchdefaultaudiosink",
+			"name", "Finch Default Audio Sink",
+			"type", PURPLE_MEDIA_ELEMENT_AUDIO
+					| PURPLE_MEDIA_ELEMENT_SINK
+					| PURPLE_MEDIA_ELEMENT_ONE_SINK,
+			"create-cb", create_default_audio_sink, NULL);
+
 	g_signal_connect(G_OBJECT(manager), "init-media", G_CALLBACK(finch_new_media), NULL);
 	purple_cmd_register("call", "", PURPLE_CMD_P_DEFAULT,
 			PURPLE_CMD_FLAG_IM, NULL,
@@ -500,8 +499,8 @@
 			PURPLE_MEDIA_CAPS_AUDIO_SINGLE_DIRECTION);
 
 	purple_debug_info("gntmedia", "Registering media element types\n");
-	purple_media_manager_set_active_element(manager, &default_audio_src);
-	purple_media_manager_set_active_element(manager, &default_audio_sink);
+	purple_media_manager_set_active_element(manager, default_audio_src);
+	purple_media_manager_set_active_element(manager, default_audio_sink);
 #endif
 }
 
--- a/libpurple/media-gst.h	Wed Apr 01 23:43:38 2009 +0000
+++ b/libpurple/media-gst.h	Thu Apr 02 00:11:49 2009 +0000
@@ -34,10 +34,22 @@
 
 G_BEGIN_DECLS
 
+#define PURPLE_TYPE_MEDIA_ELEMENT_TYPE           (purple_media_element_type_get_type())
+#define PURPLE_TYPE_MEDIA_ELEMENT_INFO           (purple_media_element_info_get_type())
+#define PURPLE_MEDIA_ELEMENT_INFO(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), PURPLE_TYPE_MEDIA_ELEMENT_INFO, PurpleMediaElementInfo))
+#define PURPLE_MEDIA_ELEMENT_INFO_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass), PURPLE_TYPE_MEDIA_ELEMENT_INFO, PurpleMediaElementInfo))
+#define PURPLE_IS_MEDIA_ELEMENT_INFO(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), PURPLE_TYPE_MEDIA_ELEMENT_INFO))
+#define PURPLE_IS_MEDIA_ELEMENT_INFO_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), PURPLE_TYPE_MEDIA_ELEMENT_INFO))
+#define PURPLE_MEDIA_ELEMENT_INFO_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), PURPLE_TYPE_MEDIA_ELEMENT_INFO, PurpleMediaElementInfo))
+
 /** @copydoc _PurpleMediaElementInfo */
 typedef struct _PurpleMediaElementInfo PurpleMediaElementInfo;
+typedef struct _PurpleMediaElementInfoClass PurpleMediaElementInfoClass;
+typedef GstElement *(*PurpleMediaElementCreateCallback)(PurpleMedia *media,
+			const gchar *session_id, const gchar *participant);
 
 typedef enum {
+	PURPLE_MEDIA_ELEMENT_NONE = 0,			/** empty element */
 	PURPLE_MEDIA_ELEMENT_AUDIO = 1,			/** supports audio */
 	PURPLE_MEDIA_ELEMENT_VIDEO = 1 << 1,		/** supports video */
 	PURPLE_MEDIA_ELEMENT_AUDIO_VIDEO = PURPLE_MEDIA_ELEMENT_AUDIO
@@ -61,19 +73,25 @@
 	PURPLE_MEDIA_ELEMENT_SINK = 1 << 10,		/** can be set as an active sink */
 } PurpleMediaElementType;
 
-struct _PurpleMediaElementInfo
-{
-	const gchar *id;
-	PurpleMediaElementType type;
-	GstElement *(*create)(PurpleMedia *media,
-			const gchar *session_id, const gchar *participant);
-};
-
 #ifdef __cplusplus
 extern "C" {
 #endif
 
 /**
+ * Gets the element type's GType.
+ *
+ * @return The element type's GType.
+ */
+GType purple_media_element_type_get_type(void);
+
+/**
+ * Gets the element info's GType.
+ *
+ * @return The element info's GType.
+ */
+GType purple_media_element_info_get_type(void);
+
+/**
  * Gets the source from a session
  *
  * @param media The media object the session is in.
@@ -126,6 +144,14 @@
 PurpleMediaElementInfo *purple_media_manager_get_active_element(
 		PurpleMediaManager *manager, PurpleMediaElementType type);
 
+gchar *purple_media_element_info_get_id(PurpleMediaElementInfo *info);
+gchar *purple_media_element_info_get_name(PurpleMediaElementInfo *info);
+PurpleMediaElementType purple_media_element_info_get_element_type(
+		PurpleMediaElementInfo *info);
+GstElement *purple_media_element_info_call_create(
+		PurpleMediaElementInfo *info, PurpleMedia *media,
+		const gchar *session_id, const gchar *participant);
+
 #ifdef __cplusplus
 }
 #endif
--- a/libpurple/mediamanager.c	Wed Apr 01 23:43:38 2009 +0000
+++ b/libpurple/mediamanager.c	Thu Apr 02 00:11:49 2009 +0000
@@ -42,6 +42,8 @@
 typedef struct _PurpleMediaManagerPrivate PurpleMediaManagerPrivate;
 /** @copydoc _PurpleMediaOutputWindow */
 typedef struct _PurpleMediaOutputWindow PurpleMediaOutputWindow;
+/** @copydoc _PurpleMediaManagerPrivate */
+typedef struct _PurpleMediaElementInfoPrivate PurpleMediaElementInfoPrivate;
 
 /** The media manager class. */
 struct _PurpleMediaManagerClass
@@ -83,6 +85,7 @@
 };
 
 #define PURPLE_MEDIA_MANAGER_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), PURPLE_TYPE_MEDIA_MANAGER, PurpleMediaManagerPrivate))
+#define PURPLE_MEDIA_ELEMENT_INFO_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), PURPLE_TYPE_MEDIA_ELEMENT_INFO, PurpleMediaElementInfoPrivate))
 
 static void purple_media_manager_class_init (PurpleMediaManagerClass *klass);
 static void purple_media_manager_init (PurpleMediaManager *media);
@@ -98,15 +101,6 @@
 };
 static guint purple_media_manager_signals[LAST_SIGNAL] = {0};
 
-enum {
-	PROP_0,
-	PROP_FARSIGHT_SESSION,
-	PROP_NAME,
-	PROP_CONNECTION,
-	PROP_MIC_ELEMENT,
-	PROP_SPEAKER_ELEMENT,
-};
-
 GType
 purple_media_manager_get_type()
 {
@@ -166,7 +160,9 @@
 		g_object_unref(priv->medias->data);
 	}
 	for (; priv->elements; priv->elements =
-			g_list_delete_link(priv->elements, priv->elements));
+			g_list_delete_link(priv->elements, priv->elements)) {
+		g_object_unref(priv->elements->data);
+	}
 	parent_class->finalize(media);
 }
 
@@ -375,6 +371,7 @@
 #ifdef USE_VV
 	GstElement *ret = NULL;
 	PurpleMediaElementInfo *info = NULL;
+	PurpleMediaElementType element_type;
 
 	if (type & PURPLE_MEDIA_SEND_AUDIO)
 		info = manager->priv->audio_src;
@@ -388,20 +385,24 @@
 	if (info == NULL)
 		return NULL;
 
-	if (info->type & PURPLE_MEDIA_ELEMENT_UNIQUE &&
-			info->type & PURPLE_MEDIA_ELEMENT_SRC) {
+	element_type = purple_media_element_info_get_element_type(info);
+
+	if (element_type & PURPLE_MEDIA_ELEMENT_UNIQUE &&
+			element_type & PURPLE_MEDIA_ELEMENT_SRC) {
 		GstElement *tee;
 		GstPad *pad;
 		GstPad *ghost;
+		gchar *id = purple_media_element_info_get_id(info);
 
 		ret = gst_bin_get_by_name(GST_BIN(
 				purple_media_manager_get_pipeline(
-				manager)), info->id);
+				manager)), id);
 
 		if (ret == NULL) {
 			GstElement *bin, *fakesink;
-			ret = info->create(media, session_id, participant);
-			bin = gst_bin_new(info->id);
+			ret = purple_media_element_info_call_create(info,
+					media, session_id, participant);
+			bin = gst_bin_new(id);
 			tee = gst_element_factory_make("tee", "tee");
 			gst_bin_add_many(GST_BIN(bin), ret, tee, NULL);
 			gst_element_link(ret, tee);
@@ -421,6 +422,7 @@
 			gst_bin_add(GST_BIN(purple_media_manager_get_pipeline(
 					manager)), ret);
 		}
+		g_free(id);
 
 		tee = gst_bin_get_by_name(GST_BIN(ret), "tee");
 		pad = gst_element_get_request_pad(tee, "src%d");
@@ -432,7 +434,8 @@
 		gst_pad_set_active(ghost, TRUE);
 		gst_element_add_pad(ret, ghost);
 	} else {
-		ret = info->create(media, session_id, participant);
+		ret = purple_media_element_info_call_create(info,
+				media, session_id, participant);
 	}
 
 	if (ret == NULL)
@@ -456,9 +459,14 @@
 	iter = manager->priv->elements;
 
 	for (; iter; iter = g_list_next(iter)) {
-		PurpleMediaElementInfo *info = iter->data;
-		if (!strcmp(info->id, id))
-			return info;
+		gchar *element_id =
+				purple_media_element_info_get_id(iter->data);
+		if (!strcmp(element_id, id)) {
+			g_free(element_id);
+			g_object_ref(iter->data);
+			return iter->data;
+		}
+		g_free(element_id);
 	}
 #endif
 
@@ -470,11 +478,21 @@
 		PurpleMediaElementInfo *info)
 {
 #ifdef USE_VV
+	PurpleMediaElementInfo *info2;
+	gchar *id;
+
 	g_return_val_if_fail(PURPLE_IS_MEDIA_MANAGER(manager), FALSE);
 	g_return_val_if_fail(info != NULL, FALSE);
 
-	if (purple_media_manager_get_element_info(manager, info->id) != NULL)
+	id = purple_media_element_info_get_id(info);
+	info2 = purple_media_manager_get_element_info(manager, id);
+	g_free(id);
+
+	if (info2 != NULL) {
+		g_object_unref(info2);
 		return FALSE;
+	}
+	g_object_unref(info2);
 
 	manager->priv->elements =
 			g_list_prepend(manager->priv->elements, info);
@@ -495,8 +513,10 @@
 
 	info = purple_media_manager_get_element_info(manager, id);
 
-	if (info == NULL)
+	if (info == NULL) {
+		g_object_unref(info);
 		return FALSE;
+	}
 
 	if (manager->priv->audio_src == info)
 		manager->priv->audio_src = NULL;
@@ -509,6 +529,7 @@
 
 	manager->priv->elements = g_list_remove(
 			manager->priv->elements, info);
+	g_object_unref(info);
 	return TRUE;
 #else
 	return FALSE;
@@ -520,30 +541,40 @@
 		PurpleMediaElementInfo *info)
 {
 #ifdef USE_VV
+	PurpleMediaElementInfo *info2;
+	PurpleMediaElementType type;
 	gboolean ret = FALSE;
+	gchar *id;
 
 	g_return_val_if_fail(PURPLE_IS_MEDIA_MANAGER(manager), FALSE);
 	g_return_val_if_fail(info != NULL, FALSE);
 
-	if (purple_media_manager_get_element_info(manager, info->id) == NULL)
-		purple_media_manager_register_element(manager, info);
+	id = purple_media_element_info_get_id(info);
+	info2 = purple_media_manager_get_element_info(manager, id);
+	g_free(id);
 
-	if (info->type & PURPLE_MEDIA_ELEMENT_SRC) {
-		if (info->type & PURPLE_MEDIA_ELEMENT_AUDIO) {
+	if (info2 == NULL)
+		purple_media_manager_register_element(manager, info);
+	g_object_unref(info2);
+
+	type = purple_media_element_info_get_element_type(info);
+
+	if (type & PURPLE_MEDIA_ELEMENT_SRC) {
+		if (type & PURPLE_MEDIA_ELEMENT_AUDIO) {
 			manager->priv->audio_src = info;
 			ret = TRUE;
 		}
-		if (info->type & PURPLE_MEDIA_ELEMENT_VIDEO) {
+		if (type & PURPLE_MEDIA_ELEMENT_VIDEO) {
 			manager->priv->video_src = info;
 			ret = TRUE;
 		}
 	}
-	if (info->type & PURPLE_MEDIA_ELEMENT_SINK) {
-		if (info->type & PURPLE_MEDIA_ELEMENT_AUDIO) {
+	if (type & PURPLE_MEDIA_ELEMENT_SINK) {
+		if (type & PURPLE_MEDIA_ELEMENT_AUDIO) {
 			manager->priv->audio_sink = info;
 			ret = TRUE;
 		}
-		if (info->type & PURPLE_MEDIA_ELEMENT_VIDEO) {
+		if (type & PURPLE_MEDIA_ELEMENT_VIDEO) {
 			manager->priv->video_sink = info;
 			ret = TRUE;
 		}
@@ -803,3 +834,266 @@
 #endif
 }
 
+
+/*
+ * PurpleMediaElementType
+ */
+
+GType
+purple_media_element_type_get_type()
+{
+	static GType type = 0;
+	if (type == 0) {
+		static const GFlagsValue values[] = {
+			{ PURPLE_MEDIA_ELEMENT_NONE,
+				"PURPLE_MEDIA_ELEMENT_NONE", "none" },
+			{ PURPLE_MEDIA_ELEMENT_AUDIO,
+				"PURPLE_MEDIA_ELEMENT_AUDIO", "audio" },
+			{ PURPLE_MEDIA_ELEMENT_VIDEO,
+				"PURPLE_MEDIA_ELEMENT_VIDEO", "video" },
+			{ PURPLE_MEDIA_ELEMENT_AUDIO_VIDEO,
+				"PURPLE_MEDIA_ELEMENT_AUDIO_VIDEO",
+				"audio-video" },
+			{ PURPLE_MEDIA_ELEMENT_NO_SRCS,
+				"PURPLE_MEDIA_ELEMENT_NO_SRCS", "no-srcs" },
+			{ PURPLE_MEDIA_ELEMENT_ONE_SRC,
+				"PURPLE_MEDIA_ELEMENT_ONE_SRC", "one-src" },
+			{ PURPLE_MEDIA_ELEMENT_MULTI_SRC,
+				"PURPLE_MEDIA_ELEMENT_MULTI_SRC",
+				"multi-src" },
+			{ PURPLE_MEDIA_ELEMENT_REQUEST_SRC,
+				"PURPLE_MEDIA_ELEMENT_REQUEST_SRC",
+				"request-src" },
+			{ PURPLE_MEDIA_ELEMENT_NO_SINKS,
+				"PURPLE_MEDIA_ELEMENT_NO_SINKS", "no-sinks" },
+			{ PURPLE_MEDIA_ELEMENT_ONE_SINK,
+				"PURPLE_MEDIA_ELEMENT_ONE_SINK", "one-sink" },
+			{ PURPLE_MEDIA_ELEMENT_MULTI_SINK,
+				"PURPLE_MEDIA_ELEMENT_MULTI_SINK",
+				"multi-sink" },
+			{ PURPLE_MEDIA_ELEMENT_REQUEST_SINK,
+				"PURPLE_MEDIA_ELEMENT_REQUEST_SINK",
+				"request-sink" },
+			{ PURPLE_MEDIA_ELEMENT_UNIQUE,
+				"PURPLE_MEDIA_ELEMENT_UNIQUE", "unique" },
+			{ PURPLE_MEDIA_ELEMENT_SRC,
+				"PURPLE_MEDIA_ELEMENT_SRC", "src" },
+			{ PURPLE_MEDIA_ELEMENT_SINK,
+				"PURPLE_MEDIA_ELEMENT_SINK", "sink" },
+			{ 0, NULL, NULL }
+		};
+		type = g_flags_register_static(
+				"PurpleMediaElementType", values);
+	}
+	return type;
+}
+
+/*
+ * PurpleMediaElementInfo
+ */
+
+struct _PurpleMediaElementInfoClass
+{
+	GObjectClass parent_class;
+};
+
+struct _PurpleMediaElementInfo
+{
+	GObject parent;
+};
+
+struct _PurpleMediaElementInfoPrivate
+{
+	gchar *id;
+	gchar *name;
+	PurpleMediaElementType type;
+	PurpleMediaElementCreateCallback create;
+};
+
+enum {
+	PROP_0,
+	PROP_ID,
+	PROP_NAME,
+	PROP_TYPE,
+	PROP_CREATE_CB,
+};
+
+static void
+purple_media_element_info_init(PurpleMediaElementInfo *info)
+{
+	PurpleMediaElementInfoPrivate *priv =
+			PURPLE_MEDIA_ELEMENT_INFO_GET_PRIVATE(info);
+	priv->id = NULL;
+	priv->name = NULL;
+	priv->type = PURPLE_MEDIA_ELEMENT_NONE;
+	priv->create = NULL;
+}
+
+static void
+purple_media_element_info_finalize(GObject *info)
+{
+	PurpleMediaElementInfoPrivate *priv =
+			PURPLE_MEDIA_ELEMENT_INFO_GET_PRIVATE(info);
+	g_free(priv->id);
+	g_free(priv->name);
+}
+
+static void
+purple_media_element_info_set_property (GObject *object, guint prop_id,
+		const GValue *value, GParamSpec *pspec)
+{
+	PurpleMediaElementInfoPrivate *priv;
+	g_return_if_fail(PURPLE_IS_MEDIA_ELEMENT_INFO(object));
+
+	priv = PURPLE_MEDIA_ELEMENT_INFO_GET_PRIVATE(object);
+
+	switch (prop_id) {
+		case PROP_ID:
+			g_free(priv->id);
+			priv->id = g_value_dup_string(value);
+			break;
+		case PROP_NAME:
+			g_free(priv->name);
+			priv->name = g_value_dup_string(value);
+			break;
+		case PROP_TYPE: {
+			priv->type = g_value_get_flags(value);
+			break;
+		}
+		case PROP_CREATE_CB:
+			priv->create = g_value_get_pointer(value);
+			break;
+		default:	
+			G_OBJECT_WARN_INVALID_PROPERTY_ID(
+					object, prop_id, pspec);
+			break;
+	}
+}
+
+static void
+purple_media_element_info_get_property (GObject *object, guint prop_id,
+		GValue *value, GParamSpec *pspec)
+{
+	PurpleMediaElementInfoPrivate *priv;
+	g_return_if_fail(PURPLE_IS_MEDIA_ELEMENT_INFO(object));
+	
+	priv = PURPLE_MEDIA_ELEMENT_INFO_GET_PRIVATE(object);
+
+	switch (prop_id) {
+		case PROP_ID:
+			g_value_set_string(value, priv->id);
+			break;
+		case PROP_NAME:
+			g_value_set_string(value, priv->name);
+			break;
+		case PROP_TYPE:
+			g_value_set_flags(value, priv->type);
+			break;
+		case PROP_CREATE_CB:
+			g_value_set_pointer(value, priv->create);
+			break;
+		default:	
+			G_OBJECT_WARN_INVALID_PROPERTY_ID(
+					object, prop_id, pspec);
+			break;
+	}
+}
+
+static void
+purple_media_element_info_class_init(PurpleMediaElementInfoClass *klass)
+{
+	GObjectClass *gobject_class = (GObjectClass*)klass;
+	
+	gobject_class->finalize = purple_media_element_info_finalize;
+	gobject_class->set_property = purple_media_element_info_set_property;
+	gobject_class->get_property = purple_media_element_info_get_property;
+
+	g_object_class_install_property(gobject_class, PROP_ID,
+			g_param_spec_string("id",
+			"ID",
+			"The unique identifier of the element.",
+			NULL,
+			G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
+
+	g_object_class_install_property(gobject_class, PROP_NAME,
+			g_param_spec_string("name",
+			"Name",
+			"The friendly/display name of this element.",
+			NULL,
+			G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
+
+	g_object_class_install_property(gobject_class, PROP_TYPE,
+			g_param_spec_flags("type",
+			"Element Type",
+			"The type of element this is.",
+			PURPLE_TYPE_MEDIA_ELEMENT_TYPE,
+			PURPLE_MEDIA_ELEMENT_NONE,
+			G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
+
+	g_object_class_install_property(gobject_class, PROP_CREATE_CB,
+			g_param_spec_pointer("create-cb",
+			"Create Callback",
+			"The function called to create this element.",
+			G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
+
+	g_type_class_add_private(klass, sizeof(PurpleMediaElementInfoPrivate));
+}
+
+G_DEFINE_TYPE(PurpleMediaElementInfo,
+		purple_media_element_info, G_TYPE_OBJECT);
+
+gchar *
+purple_media_element_info_get_id(PurpleMediaElementInfo *info)
+{
+#ifdef USE_VV
+	gchar *id;
+	g_return_val_if_fail(PURPLE_IS_MEDIA_ELEMENT_INFO(info), NULL);
+	g_object_get(info, "id", &id, NULL);
+	return id;
+#else
+	return NULL;
+#endif
+}
+
+gchar *
+purple_media_element_info_get_name(PurpleMediaElementInfo *info)
+{
+#ifdef USE_VV
+	gchar *name;
+	g_return_val_if_fail(PURPLE_IS_MEDIA_ELEMENT_INFO(info), NULL);
+	g_object_get(info, "name", &name, NULL);
+	return name;
+#else
+	return NULL;
+#endif
+}
+
+PurpleMediaElementType
+purple_media_element_info_get_element_type(PurpleMediaElementInfo *info)
+{
+#ifdef USE_VV
+	PurpleMediaElementType type;
+	g_return_val_if_fail(PURPLE_IS_MEDIA_ELEMENT_INFO(info),
+			PURPLE_MEDIA_ELEMENT_NONE);
+	g_object_get(info, "type", &type, NULL);
+	return type;
+#else
+	return PURPLE_MEDIA_ELEMENT_NONE;
+#endif
+}
+
+GstElement *
+purple_media_element_info_call_create(PurpleMediaElementInfo *info,
+		PurpleMedia *media, const gchar *session_id,
+		const gchar *participant)
+{
+#ifdef USE_VV
+	PurpleMediaElementCreateCallback create;
+	g_return_val_if_fail(PURPLE_IS_MEDIA_ELEMENT_INFO(info), NULL);
+	g_object_get(info, "create-cb", &create, NULL);
+	if (create)
+		return create(media, session_id, participant);
+#endif
+	return NULL;
+}
+
--- a/pidgin/gtkmedia.c	Wed Apr 01 23:43:38 2009 +0000
+++ b/pidgin/gtkmedia.c	Thu Apr 02 00:11:49 2009 +0000
@@ -1009,44 +1009,6 @@
 
 	return bin;
 }
-
-static PurpleMediaElementInfo default_video_src =
-{
-	"pidgindefaultvideosrc",	/* id */
-	PURPLE_MEDIA_ELEMENT_VIDEO	/* type */
-			| PURPLE_MEDIA_ELEMENT_SRC
-			| PURPLE_MEDIA_ELEMENT_ONE_SRC
-			| PURPLE_MEDIA_ELEMENT_UNIQUE,
-	create_default_video_src,	/* create */
-};
-
-static PurpleMediaElementInfo default_video_sink =
-{
-	"pidgindefaultvideosink",	/* id */
-	PURPLE_MEDIA_ELEMENT_VIDEO	/* type */
-			| PURPLE_MEDIA_ELEMENT_SINK
-			| PURPLE_MEDIA_ELEMENT_ONE_SINK,
-	create_default_video_sink,	/* create */
-};
-
-static PurpleMediaElementInfo default_audio_src =
-{
-	"pidgindefaultaudiosrc",	/* id */
-	PURPLE_MEDIA_ELEMENT_AUDIO	/* type */
-			| PURPLE_MEDIA_ELEMENT_SRC
-			| PURPLE_MEDIA_ELEMENT_ONE_SRC
-			| PURPLE_MEDIA_ELEMENT_UNIQUE,
-	create_default_audio_src,	/* create */
-};
-
-static PurpleMediaElementInfo default_audio_sink =
-{
-	"pidgindefaultaudiosink",	/* id */
-	PURPLE_MEDIA_ELEMENT_AUDIO	/* type */
-			| PURPLE_MEDIA_ELEMENT_SINK
-			| PURPLE_MEDIA_ELEMENT_ONE_SINK,
-	create_default_audio_sink,	/* create */
-};
 #endif  /* USE_VV */
 
 void
@@ -1054,6 +1016,41 @@
 {
 #ifdef USE_VV
 	PurpleMediaManager *manager = purple_media_manager_get();
+	PurpleMediaElementInfo *default_video_src =
+			g_object_new(PURPLE_TYPE_MEDIA_ELEMENT_INFO,
+			"id", "pidgindefaultvideosrc",
+			"name", "Pidgin Default Video Source",
+			"type", PURPLE_MEDIA_ELEMENT_VIDEO
+					| PURPLE_MEDIA_ELEMENT_SRC
+					| PURPLE_MEDIA_ELEMENT_ONE_SRC
+					| PURPLE_MEDIA_ELEMENT_UNIQUE,
+			"create-cb", create_default_video_src, NULL);
+	PurpleMediaElementInfo *default_video_sink =
+			g_object_new(PURPLE_TYPE_MEDIA_ELEMENT_INFO,
+			"id", "pidgindefaultvideosink",
+			"name", "Pidgin Default Video Sink",
+			"type", PURPLE_MEDIA_ELEMENT_VIDEO
+					| PURPLE_MEDIA_ELEMENT_SINK
+					| PURPLE_MEDIA_ELEMENT_ONE_SINK,
+			"create-cb", create_default_video_sink, NULL);
+	PurpleMediaElementInfo *default_audio_src =
+			g_object_new(PURPLE_TYPE_MEDIA_ELEMENT_INFO,
+			"id", "pidgindefaultaudiosrc",
+			"name", "Pidgin Default Audio Source",
+			"type", PURPLE_MEDIA_ELEMENT_AUDIO
+					| PURPLE_MEDIA_ELEMENT_SRC
+					| PURPLE_MEDIA_ELEMENT_ONE_SRC
+					| PURPLE_MEDIA_ELEMENT_UNIQUE,
+			"create-cb", create_default_audio_src, NULL);
+	PurpleMediaElementInfo *default_audio_sink =
+			g_object_new(PURPLE_TYPE_MEDIA_ELEMENT_INFO,
+			"id", "pidgindefaultaudiosink",
+			"name", "Pidgin Default Audio Sink",
+			"type", PURPLE_MEDIA_ELEMENT_AUDIO
+					| PURPLE_MEDIA_ELEMENT_SINK
+					| PURPLE_MEDIA_ELEMENT_ONE_SINK,
+			"create-cb", create_default_audio_sink, NULL);
+
 	g_signal_connect(G_OBJECT(manager), "init-media",
 			 G_CALLBACK(pidgin_media_new_cb), NULL);
 
@@ -1065,10 +1062,10 @@
 			PURPLE_MEDIA_CAPS_AUDIO_VIDEO);
 
 	purple_debug_info("gtkmedia", "Registering media element types\n");
-	purple_media_manager_set_active_element(manager, &default_video_src);
-	purple_media_manager_set_active_element(manager, &default_video_sink);
-	purple_media_manager_set_active_element(manager, &default_audio_src);
-	purple_media_manager_set_active_element(manager, &default_audio_sink);
+	purple_media_manager_set_active_element(manager, default_video_src);
+	purple_media_manager_set_active_element(manager, default_video_sink);
+	purple_media_manager_set_active_element(manager, default_audio_src);
+	purple_media_manager_set_active_element(manager, default_audio_sink);
 #endif
 }