changeset 31869:3fb443b6460c

Allow adding or removing media sessions (voice or video) on-the-fly. This allows, for example, starting a call with only audio and adding video later, followed by removing the audio component of the call. committer: John Bailey <rekkanoryo@rekkanoryo.org>
author jakub.adam@ktknet.cz
date Thu, 24 Mar 2011 23:02:12 +0000
parents a493a43d719b
children 9f8da7c21afd
files libpurple/media/backend-fs2.c
diffstat 1 files changed, 92 insertions(+), 22 deletions(-) [+]
line wrap: on
line diff
--- a/libpurple/media/backend-fs2.c	Thu Mar 24 22:41:12 2011 +0000
+++ b/libpurple/media/backend-fs2.c	Thu Mar 24 23:02:12 2011 +0000
@@ -86,6 +86,9 @@
 		PurpleMediaBackend *self, const gchar *sess_id,
 		PurpleMediaCodec *codec);
 
+static void free_stream(PurpleMediaBackendFs2Stream *stream);
+static void free_session(PurpleMediaBackendFs2Session *session);
+
 struct _PurpleMediaBackendFs2Class
 {
 	GObjectClass parent_class;
@@ -110,6 +113,8 @@
 	GstElement *tee;
 	GstElement *volume;
 	GstElement *level;
+	GstElement *fakesink;
+	GstElement *queue;
 
 	GList *local_candidates;
 	GList *remote_candidates;
@@ -300,20 +305,7 @@
 	for (; priv->streams; priv->streams =
 			g_list_delete_link(priv->streams, priv->streams)) {
 		PurpleMediaBackendFs2Stream *stream = priv->streams->data;
-
-		/* Remove the connected_cb timeout */
-		if (stream->connected_cb_id != 0)
-			purple_timeout_remove(stream->connected_cb_id);
-
-		g_free(stream->participant);
-
-		if (stream->local_candidates)
-			fs_candidate_list_destroy(stream->local_candidates);
-
-		if (stream->remote_candidates)
-			fs_candidate_list_destroy(stream->remote_candidates);
-
-		g_free(stream);
+		free_stream(stream);
 	}
 
 	if (priv->sessions) {
@@ -323,8 +315,7 @@
 				g_list_delete_link(sessions, sessions)) {
 			PurpleMediaBackendFs2Session *session =
 					sessions->data;
-			g_free(session->id);
-			g_free(session);
+			free_session(session);
 		}
 
 		g_hash_table_destroy(priv->sessions);
@@ -1138,9 +1129,62 @@
 }
 
 static void
+remove_element(GstElement *element)
+{
+	if (element) {
+		gst_element_set_locked_state(element, TRUE);
+		gst_element_set_state(element, GST_STATE_NULL);
+		gst_bin_remove(GST_BIN(GST_ELEMENT_PARENT(element)), element);
+	}
+}
+
+static void
 state_changed_cb(PurpleMedia *media, PurpleMediaState state,
 		gchar *sid, gchar *name, PurpleMediaBackendFs2 *self)
 {
+	if (state == PURPLE_MEDIA_STATE_END) {
+		PurpleMediaBackendFs2Private *priv =
+				PURPLE_MEDIA_BACKEND_FS2_GET_PRIVATE(self);
+
+		if (sid && name) {
+			PurpleMediaBackendFs2Stream *stream = get_stream(self, sid, name);
+			gst_object_unref(stream->stream);
+
+			priv->streams = g_list_remove(priv->streams, stream);
+
+			remove_element(stream->src);
+			remove_element(stream->tee);
+			remove_element(stream->volume);
+			remove_element(stream->level);
+			remove_element(stream->fakesink);
+			remove_element(stream->queue);
+
+			free_stream(stream);
+		} else if (sid && !name) {
+			PurpleMediaBackendFs2Session *session = get_session(self, sid);
+			GstPad *pad;
+
+			g_object_get(session->session, "sink-pad", &pad, NULL);
+			gst_pad_unlink(GST_PAD_PEER(pad), pad);
+			gst_object_unref(pad);
+
+			gst_object_unref(session->session);
+			g_hash_table_remove(priv->sessions, session->id);
+
+			pad = gst_pad_get_peer(session->srcpad);
+			gst_element_remove_pad(GST_ELEMENT_PARENT(pad), pad);
+			gst_object_unref(pad);
+			gst_object_unref(session->srcpad);
+
+			remove_element(session->srcvalve);
+			remove_element(session->tee);
+
+			free_session(session);
+		}
+
+		purple_media_manager_remove_output_windows(
+				purple_media_get_manager(media), media, sid, name);
+	}
 }
 
 static void
@@ -1420,6 +1464,7 @@
 			  ? "success" : "failure");
 	gst_element_set_locked_state(session->src, FALSE);
 	gst_object_unref(session->src);
+	gst_object_unref(sinkpad);
 
 	gst_element_set_state(session->src, GST_STATE_PLAYING);
 
@@ -1536,6 +1581,13 @@
 	return TRUE;
 }
 
+static void
+free_session(PurpleMediaBackendFs2Session *session)
+{
+	g_free(session->id);
+	g_free(session);
+}
+
 static gboolean
 create_participant(PurpleMediaBackendFs2 *self, const gchar *name)
 {
@@ -1603,7 +1655,6 @@
 		GstElement *sink = NULL;
 
 		if (codec->media_type == FS_MEDIA_TYPE_AUDIO) {
-			GstElement *queue = NULL;
 			double output_volume = purple_prefs_get_int(
 					"/purple/media/audio/volume/output")/10.0;
 			/*
@@ -1611,7 +1662,7 @@
 			 *  audioconvert ! audioresample ! liveadder !
 			 *   audioresample ! audioconvert ! realsink
 			 */
-			queue = gst_element_factory_make("queue", NULL);
+			stream->queue = gst_element_factory_make("queue", NULL);
 			stream->volume = gst_element_factory_make(
 					"volume", NULL);
 			g_object_set(stream->volume, "volume",
@@ -1625,18 +1676,18 @@
 					PURPLE_MEDIA_RECV_AUDIO, priv->media,
 					stream->session->id,
 					stream->participant);
-			gst_bin_add(GST_BIN(priv->confbin), queue);
+			gst_bin_add(GST_BIN(priv->confbin), stream->queue);
 			gst_bin_add(GST_BIN(priv->confbin), stream->volume);
 			gst_bin_add(GST_BIN(priv->confbin), stream->level);
 			gst_bin_add(GST_BIN(priv->confbin), sink);
 			gst_element_set_state(sink, GST_STATE_PLAYING);
 			gst_element_set_state(stream->level, GST_STATE_PLAYING);
 			gst_element_set_state(stream->volume, GST_STATE_PLAYING);
-			gst_element_set_state(queue, GST_STATE_PLAYING);
+			gst_element_set_state(stream->queue, GST_STATE_PLAYING);
 			gst_element_link(stream->level, sink);
 			gst_element_link(stream->volume, stream->level);
-			gst_element_link(queue, stream->volume);
-			sink = queue;
+			gst_element_link(stream->queue, stream->volume);
+			sink = stream->queue;
 		} else if (codec->media_type == FS_MEDIA_TYPE_VIDEO) {
 			stream->src = gst_element_factory_make(
 					"fsfunnel", NULL);
@@ -1645,6 +1696,7 @@
 			g_object_set(G_OBJECT(sink), "async", FALSE, NULL);
 			gst_bin_add(GST_BIN(priv->confbin), sink);
 			gst_element_set_state(sink, GST_STATE_PLAYING);
+			stream->fakesink = sink;
 		}
 		stream->tee = gst_element_factory_make("tee", NULL);
 		gst_bin_add_many(GST_BIN(priv->confbin),
@@ -1814,6 +1866,24 @@
 	return TRUE;
 }
 
+static void
+free_stream(PurpleMediaBackendFs2Stream *stream)
+{
+	/* Remove the connected_cb timeout */
+	if (stream->connected_cb_id != 0)
+		purple_timeout_remove(stream->connected_cb_id);
+
+	g_free(stream->participant);
+
+	if (stream->local_candidates)
+		fs_candidate_list_destroy(stream->local_candidates);
+
+	if (stream->remote_candidates)
+		fs_candidate_list_destroy(stream->remote_candidates);
+
+	g_free(stream);
+}
+
 static gboolean
 purple_media_backend_fs2_add_stream(PurpleMediaBackend *self,
 		const gchar *sess_id, const gchar *who,