# HG changeset patch # User jakub.adam@ktknet.cz # Date 1301007732 0 # Node ID 3fb443b6460c3f92613577df55030439bd09a19f # Parent a493a43d719b725711d3c77a272f13f439da727b 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 diff -r a493a43d719b -r 3fb443b6460c libpurple/media/backend-fs2.c --- 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,