changeset 26381:6bcf5ad967ea

Make sharing sources between media sessions work.
author Mike Ruprecht <maiku@soc.pidgin.im>
date Mon, 30 Mar 2009 22:00:35 +0000
parents b0a9c48b5f69
children f42892982e30
files libpurple/media.c libpurple/mediamanager.c
diffstat 2 files changed, 93 insertions(+), 17 deletions(-) [+]
line wrap: on
line diff
--- a/libpurple/media.c	Mon Mar 30 04:15:53 2009 +0000
+++ b/libpurple/media.c	Mon Mar 30 22:00:35 2009 +0000
@@ -1151,12 +1151,21 @@
 		gst_object_unref(session->src);
 	session->src = src;
 	gst_element_set_locked_state(session->src, TRUE);
-	gst_bin_add(GST_BIN(session->media->priv->confbin),
-		    session->src);
 
 	session->tee = gst_element_factory_make("tee", NULL);
 	gst_bin_add(GST_BIN(session->media->priv->confbin), session->tee);
-	gst_element_link(session->src, session->tee);
+
+	/* This supposedly isn't necessary, but it silences some warnings */
+	if (GST_ELEMENT_PARENT(session->media->priv->confbin)
+			== GST_ELEMENT_PARENT(session->src)) {
+		GstPad *pad = gst_element_get_static_pad(session->tee, "sink");
+		GstPad *ghost = gst_ghost_pad_new(NULL, pad);
+		gst_object_unref(pad);
+		gst_pad_set_active(ghost, TRUE);
+		gst_element_add_pad(session->media->priv->confbin, ghost);
+	}
+
+	gst_element_link(session->src, session->media->priv->confbin);
 	gst_element_set_state(session->tee, GST_STATE_PLAYING);
 
 	g_object_get(session->session, "sink-pad", &sinkpad, NULL);
@@ -1165,6 +1174,7 @@
 			  gst_pad_link(srcpad, sinkpad) == GST_PAD_LINK_OK
 			  ? "success" : "failure");
 	gst_element_set_locked_state(session->src, FALSE);
+	gst_object_unref(session->src);
 }
 #endif
 
--- a/libpurple/mediamanager.c	Mon Mar 30 04:15:53 2009 +0000
+++ b/libpurple/mediamanager.c	Mon Mar 30 22:00:35 2009 +0000
@@ -328,28 +328,94 @@
 #endif
 }
 
+#ifdef USE_VV
+static void
+request_pad_unlinked_cb(GstPad *pad, GstPad *peer, gpointer user_data)
+{
+	GstElement *parent = GST_ELEMENT_PARENT(pad);
+	GstIterator *iter;
+	GstPad *remaining_pad;
+
+	gst_element_release_request_pad(GST_ELEMENT_PARENT(pad), pad);
+	iter = gst_element_iterate_pads(parent);
+
+	if (gst_iterator_next(iter, (gpointer)&remaining_pad)
+			== GST_ITERATOR_DONE) {
+		gst_element_set_locked_state(parent, TRUE);
+		gst_element_set_state(parent, GST_STATE_NULL);
+		gst_bin_remove(GST_BIN(GST_ELEMENT_PARENT(parent)), parent);
+	}
+
+	gst_iterator_free(iter);
+}
+#endif
+
 GstElement *
 purple_media_manager_get_element(PurpleMediaManager *manager,
 		PurpleMediaSessionType type)
 {
 #ifdef USE_VV
 	GstElement *ret = NULL;
+	PurpleMediaElementInfo *info = NULL;
 
-	/* TODO: If src, retrieve current src */
-	/* TODO: Send a signal here to allow for overriding the source/sink */
+	if (type & PURPLE_MEDIA_SEND_AUDIO)
+		info = manager->priv->audio_src;
+	else if (type & PURPLE_MEDIA_RECV_AUDIO)
+		info = manager->priv->audio_sink;
+	else if (type & PURPLE_MEDIA_SEND_VIDEO)
+		info = manager->priv->video_src;
+	else if (type & PURPLE_MEDIA_RECV_VIDEO)
+		info = manager->priv->video_sink;
+
+	if (info == NULL)
+		return NULL;
+
+	if (info->type & PURPLE_MEDIA_ELEMENT_UNIQUE &&
+			info->type & PURPLE_MEDIA_ELEMENT_SRC) {
+		GstElement *tee;
+		GstPad *pad;
+		GstPad *ghost;
+
+		ret = gst_bin_get_by_name(GST_BIN(
+				purple_media_manager_get_pipeline(
+				manager)), info->id);
 
-	if (type & PURPLE_MEDIA_SEND_AUDIO
-			&& manager->priv->audio_src != NULL)
-		ret = manager->priv->audio_src->create();
-	else if (type & PURPLE_MEDIA_RECV_AUDIO
-			&& manager->priv->audio_sink != NULL)
-		ret = manager->priv->audio_sink->create();
-	else if (type & PURPLE_MEDIA_SEND_VIDEO
-			&& manager->priv->video_src != NULL)
-		ret = manager->priv->video_src->create();
-	else if (type & PURPLE_MEDIA_RECV_VIDEO
-			&& manager->priv->video_sink != NULL)
-		ret = manager->priv->video_sink->create();
+		if (ret == NULL) {
+			GstElement *bin, *fakesink;
+			ret = info->create();
+			bin = gst_bin_new(info->id);
+			tee = gst_element_factory_make("tee", "tee");
+			gst_bin_add_many(GST_BIN(bin), ret, tee, NULL);
+			gst_element_link(ret, tee);
+
+			/*
+			 * This shouldn't be necessary, but it stops it from
+			 * giving a not-linked error upon destruction
+			 */
+			fakesink = gst_element_factory_make("fakesink", NULL);
+			g_object_set(fakesink, "sync", FALSE, NULL);
+			gst_bin_add(GST_BIN(bin), fakesink);
+			gst_element_link(tee, fakesink);
+
+			ret = bin;
+			gst_element_set_locked_state(ret, TRUE);
+			gst_object_ref(ret);
+			gst_bin_add(GST_BIN(purple_media_manager_get_pipeline(
+					manager)), ret);
+		}
+
+		tee = gst_bin_get_by_name(GST_BIN(ret), "tee");
+		pad = gst_element_get_request_pad(tee, "src%d");
+		gst_object_unref(tee);
+		ghost = gst_ghost_pad_new(NULL, pad);
+		gst_object_unref(pad);
+		g_signal_connect(GST_PAD(ghost), "unlinked",
+				G_CALLBACK(request_pad_unlinked_cb), NULL);
+		gst_pad_set_active(ghost, TRUE);
+		gst_element_add_pad(ret, ghost);
+	} else {
+		ret = info->create();
+	}
 
 	if (ret == NULL)
 		purple_debug_error("media", "Error creating source or sink\n");