pidgin.vv: b93709e8: Only create output windows once there's ...
maiku at soc.pidgin.im
maiku at soc.pidgin.im
Tue Feb 24 03:30:26 EST 2009
-----------------------------------------------------------------
Revision: b93709e892e63c46b340b4bac70abe2eeef22a38
Ancestor: c26331159ab2eaaa663def5d6b5eae3a5a2b6d25
Author: maiku at soc.pidgin.im
Date: 2009-02-24T08:11:24
Branch: im.pidgin.pidgin.vv
URL: http://d.pidgin.im/viewmtn/revision/info/b93709e892e63c46b340b4bac70abe2eeef22a38
Modified files:
libpurple/media.c libpurple/media.h libpurple/mediamanager.c
libpurple/mediamanager.h
ChangeLog:
Only create output windows once there's data to be output.
Also, allow multiple output windows per session/stream.
-------------- next part --------------
============================================================
--- libpurple/media.c 9c3c5a8bcdddcaa259986b067a306a009bacbb4b
+++ libpurple/media.c e4f3dbaef5b1789d67f4b0c07a5881d051c09396
@@ -39,7 +39,6 @@
#ifdef USE_VV
#include <gst/interfaces/propertyprobe.h>
-#include <gst/interfaces/xoverlay.h>
#include <gst/farsight/fs-conference-iface.h>
/** @copydoc _PurpleMediaSession */
@@ -1591,7 +1590,7 @@ purple_media_audio_init_recv(GstElement
*recvbin = gst_bin_new("pidginrecvaudiobin");
sink = gst_element_factory_make("alsasink", "asink");
- g_object_set(G_OBJECT(sink), "sync", FALSE, NULL);
+ g_object_set(G_OBJECT(sink), "async", FALSE, "sync", FALSE, NULL);
volume = gst_element_factory_make("volume", "purpleaudiooutputvolume");
g_object_set(volume, "volume", output_volume, NULL);
*recvlevel = gst_element_factory_make("level", "recvlevel");
@@ -1610,17 +1609,9 @@ purple_media_video_init_recv(GstElement
void
purple_media_video_init_recv(GstElement **recvbin)
{
- GstElement *sink;
- GstPad *pad, *ghost;
-
g_return_if_fail(recvbin != NULL);
- *recvbin = gst_bin_new("fakebin");
- sink = gst_element_factory_make("fakesink", NULL);
- gst_bin_add(GST_BIN(*recvbin), sink);
- pad = gst_element_get_pad(sink, "sink");
- ghost = gst_ghost_pad_new("ghostsink", pad);
- gst_element_add_pad(*recvbin, ghost);
+ *recvbin = gst_element_factory_make("autovideosink", NULL);
}
static void
@@ -1736,6 +1727,12 @@ purple_media_connected_cb(PurpleMediaStr
purple_media_connected_cb(PurpleMediaStream *stream)
{
g_return_val_if_fail(stream != NULL, FALSE);
+
+ purple_media_manager_create_output_window(
+ stream->session->media->priv->manager,
+ stream->session->media,
+ stream->session->id, stream->participant);
+
g_signal_emit(stream->session->media,
purple_media_signals[STATE_CHANGED],
0, PURPLE_MEDIA_STATE_CHANGED_CONNECTED,
@@ -1884,6 +1881,11 @@ purple_media_add_stream_internal(PurpleM
purple_media_manager_get_element(
media->priv->manager, session_type));
gst_element_set_state(session->src, GST_STATE_PLAYING);
+
+ purple_media_manager_create_output_window(
+ media->priv->manager,
+ session->media,
+ session->id, NULL);
}
if (!(participant = purple_media_add_participant(media, who))) {
@@ -2303,310 +2305,53 @@ void purple_media_set_output_volume(Purp
}
}
-typedef struct
-{
- gchar *name;
- gulong window_id;
- gulong handler_id;
-} PurpleMediaXOverlayData;
-
-static void
-window_id_cb(GstBus *bus, GstMessage *msg, PurpleMediaXOverlayData *data)
-{
- gchar *name;
-
- if (GST_MESSAGE_TYPE(msg) != GST_MESSAGE_ELEMENT ||
- !gst_structure_has_name(msg->structure,
- "prepare-xwindow-id"))
- return;
-
- name = gst_object_get_name(GST_MESSAGE_SRC(msg));
-
- if (!strncmp(name, data->name, strlen(data->name))) {
- g_signal_handler_disconnect(bus, data->handler_id);
-
- gst_x_overlay_set_xwindow_id(GST_X_OVERLAY(
- GST_MESSAGE_SRC(msg)), data->window_id);
-
- g_free(data->name);
- g_free(data);
- }
-
- g_free(name);
-
- return;
-}
-
-gboolean
+gulong
purple_media_set_output_window(PurpleMedia *media, const gchar *session_id,
const gchar *participant, gulong window_id)
{
g_return_val_if_fail(PURPLE_IS_MEDIA(media), FALSE);
- if (session_id != NULL && participant == NULL) {
-
- PurpleMediaSession *session;
- session = purple_media_get_session(media, session_id);
-
- if (session == NULL)
- return FALSE;
-
- session->window_id = window_id;
-
- if (session->sink == NULL) {
- PurpleMediaXOverlayData *data;
- GstBus *bus;
- GstElement *bin, *queue, *sink;
- GstPad *request_pad, *sinkpad, *ghostpad;
- gchar *name;
-
- /* Create sink */
- bin = gst_bin_new(NULL);
- gst_bin_add(GST_BIN(GST_ELEMENT_PARENT(
- session->tee)), bin);
-
- queue = gst_element_factory_make("queue", NULL);
- name = g_strdup_printf(
- "session-sink_%s", session_id);
- sink = gst_element_factory_make(
- "autovideosink", name);
-
- gst_bin_add_many(GST_BIN(bin), queue, sink, NULL);
- gst_element_link(queue, sink);
-
- sinkpad = gst_element_get_static_pad(queue, "sink");
- ghostpad = gst_ghost_pad_new("ghostsink", sinkpad);
- gst_object_unref(sinkpad);
- gst_element_add_pad(bin, ghostpad);
-
- /* Connect callback for prepared-xwindow-id signal */
- data = g_new0(PurpleMediaXOverlayData, 1);
- data->name = name;
- data->window_id = window_id;
-
- bus = gst_pipeline_get_bus(GST_PIPELINE(
- purple_media_manager_get_pipeline(
- media->priv->manager)));
- data->handler_id = g_signal_connect(bus,
- "sync-message::element",
- G_CALLBACK(window_id_cb), data);
- gst_object_unref(bus);
-
- gst_element_set_state(bin, GST_STATE_PLAYING);
-
- request_pad = gst_element_get_request_pad(
- session->tee, "src%d");
- gst_pad_link(request_pad, ghostpad);
- gst_object_unref(request_pad);
-
- session->sink = bin;
- return TRUE;
- } else {
- /* Changing the XOverlay output window */
- GstElement *xoverlay = gst_bin_get_by_interface(
- GST_BIN(session->sink),
- GST_TYPE_X_OVERLAY);
- if (xoverlay != NULL) {
- gst_x_overlay_set_xwindow_id(
- GST_X_OVERLAY(xoverlay),
- window_id);
- }
- return FALSE;
- }
- } else if (session_id != NULL && participant != NULL) {
- PurpleMediaStream *stream = purple_media_get_stream(
- media, session_id, participant);
- GstBus *bus;
- GstElement *bin, *queue, *sink;
- GstPad *pad, *peer = NULL, *ghostpad;
- PurpleMediaXOverlayData *data;
- gchar *name;
-
- if (stream == NULL)
- return FALSE;
-
- stream->window_id = window_id;
-
- if (stream->sink != NULL) {
- gboolean is_fakebin;
- name = gst_element_get_name(stream->sink);
- is_fakebin = !strcmp(name, "fakebin");
- g_free(name);
-
- if (is_fakebin) {
- pad = gst_element_get_static_pad(
- stream->sink, "ghostsink");
- peer = gst_pad_get_peer(pad);
-
- gst_pad_unlink(peer, pad);
- gst_object_unref(pad);
- gst_element_set_state(stream->sink,
- GST_STATE_NULL);
- gst_bin_remove(GST_BIN(GST_ELEMENT_PARENT(
- stream->sink)), stream->sink);
- } else {
- /* Changing the XOverlay output window */
- GstElement *xoverlay =
- gst_bin_get_by_interface(
- GST_BIN(stream->sink),
- GST_TYPE_X_OVERLAY);
- if (xoverlay != NULL) {
- gst_x_overlay_set_xwindow_id(
- GST_X_OVERLAY(xoverlay),
- window_id);
- return TRUE;
- }
- return FALSE;
- }
- }
-
- bin = gst_bin_new(NULL);
-
- name = g_strdup_printf("stream-sink_%s_%s",
- session_id, participant);
- queue = gst_element_factory_make("queue", NULL);
- sink = gst_element_factory_make("autovideosink", name);
-
- gst_bin_add_many(GST_BIN(bin), queue, sink, NULL);
- gst_element_link(queue, sink);
- pad = gst_element_get_static_pad(queue, "sink");
- ghostpad = gst_ghost_pad_new("ghostsink", pad);
- gst_element_add_pad(bin, ghostpad);
-
- /* Connect callback for prepared-xwindow-id signal */
- data = g_new0(PurpleMediaXOverlayData, 1);
- data->name = name;
- data->window_id = window_id;
-
- bus = gst_pipeline_get_bus(GST_PIPELINE(
- purple_media_manager_get_pipeline(
- media->priv->manager)));
- data->handler_id = g_signal_connect(bus,
- "sync-message::element",
- G_CALLBACK(window_id_cb), data);
- gst_object_unref(bus);
-
- if (stream->tee != NULL) {
- gst_bin_add(GST_BIN(GST_ELEMENT_PARENT(
- stream->tee)), bin);
- gst_element_set_state(bin, GST_STATE_PLAYING);
- gst_element_link(stream->tee, bin);
- }
-
- stream->sink = bin;
- return TRUE;
- }
- return FALSE;
+ return purple_media_manager_set_output_window(media->priv->manager,
+ media, session_id, participant, window_id);
}
-static void
-dummy_block_cb(GstPad *pad, gboolean blocked, gpointer user_data)
-{
-}
-
-gboolean
-purple_media_remove_output_window(PurpleMedia *media, const gchar *session_id,
- const gchar *participant)
-{
- GstElement *parent, *fakesink, *sink;
- GstPad *pad, *peer;
-
- g_return_val_if_fail(PURPLE_IS_MEDIA(media), FALSE);
-
- if (session_id != NULL && participant == NULL) {
- PurpleMediaSession *session;
- GstPad *pad, *peer;
-
- session = purple_media_get_session(media, session_id);
-
- if (session == NULL)
- return FALSE;
-
- sink = session->sink;
-
- if (!GST_IS_ELEMENT(sink))
- return FALSE;
-
- pad = gst_element_get_static_pad(sink, "ghostsink");
- peer = gst_pad_get_peer(pad);
- gst_object_unref(pad);
-
- gst_element_release_request_pad(GST_ELEMENT_PARENT(peer), peer);
- gst_object_unref(peer);
-
- gst_element_set_locked_state(sink, TRUE);
- gst_element_set_state(sink, GST_STATE_NULL);
-
- gst_bin_remove(GST_BIN(GST_ELEMENT_PARENT(sink)), sink);
- session->sink = NULL;
- return TRUE;
- } else if (session_id != NULL && participant != NULL) {
- PurpleMediaStream *stream;
- stream = purple_media_get_stream(media,
- session_id, participant);
-
- if (stream == NULL)
- return FALSE;
-
- sink = stream->sink;
- } else
- return FALSE;
-
- if (!GST_IS_ELEMENT(sink))
- return FALSE;
-
- /* Remove sink */
- parent = GST_ELEMENT(gst_element_get_parent(sink));
-
- if (parent == NULL) {
- /* It's not added and therefore not linked */
- gst_object_unref(sink);
- return FALSE;
- }
-
- pad = gst_element_get_static_pad(sink, "ghostsink");
-
- if (pad == NULL) {
- /* It's already a fakesink */
- gst_object_unref(parent);
- return FALSE;
- }
-
- peer = gst_pad_get_peer(pad);
- gst_object_unref(pad);
- gst_pad_set_blocked_async(peer, TRUE, dummy_block_cb, NULL);
- gst_element_set_locked_state(sink, TRUE);
- gst_element_set_state(sink, GST_STATE_NULL);
- gst_bin_remove(GST_BIN(parent), sink);
-
- /* Add fakesink */
- fakesink = gst_element_factory_make("fakesink", NULL);
- gst_bin_add(GST_BIN(parent), fakesink);
- gst_element_sync_state_with_parent(fakesink);
- gst_object_unref(parent);
- pad = gst_element_get_static_pad(fakesink, "sink");
- gst_pad_link(peer, pad);
- gst_object_unref(pad);
- gst_pad_set_blocked_async(peer, FALSE, dummy_block_cb, NULL);
- gst_object_unref(peer);
- return TRUE;
-}
-
void
purple_media_remove_output_windows(PurpleMedia *media)
{
GList *iter = media->priv->streams;
for (; iter; iter = g_list_next(iter)) {
PurpleMediaStream *stream = iter->data;
- purple_media_remove_output_window(media,
+ purple_media_manager_remove_output_windows(
+ media->priv->manager, media,
stream->session->id, stream->participant);
}
iter = purple_media_get_session_names(media);
for (; iter; iter = g_list_delete_link(iter, iter)) {
gchar *session_name = iter->data;
- purple_media_remove_output_window(media, session_name, NULL);
+ purple_media_manager_remove_output_windows(
+ media->priv->manager, media,
+ session_name, NULL);
}
}
+GstElement *
+purple_media_get_tee(PurpleMedia *media,
+ const gchar *session_id, const gchar *participant)
+{
+ g_return_val_if_fail(PURPLE_IS_MEDIA(media), NULL);
+
+ if (session_id != NULL && participant == NULL) {
+ PurpleMediaSession *session =
+ purple_media_get_session(media, session_id);
+ return (session != NULL) ? session->tee : NULL;
+ } else if (session_id != NULL && participant != NULL) {
+ PurpleMediaStream *stream =
+ purple_media_get_stream(media,
+ session_id, participant);
+ return (stream != NULL) ? stream->tee : NULL;
+ }
+ g_return_val_if_reached(NULL);
+}
+
#endif /* USE_VV */
============================================================
--- libpurple/media.h 50a8ed2781ef0cc3a284c4566d262f895c3aa9d4
+++ libpurple/media.h 3ce7821835d856470067defa7e62a22b79bd1c59
@@ -651,12 +651,14 @@ void purple_media_set_output_volume(Purp
void purple_media_set_output_volume(PurpleMedia *media, const gchar *session_id,
const gchar *participant, double level);
-gboolean purple_media_set_output_window(PurpleMedia *media,
+gulong purple_media_set_output_window(PurpleMedia *media,
const gchar *session_id, const gchar *participant,
gulong window_id);
-gboolean purple_media_remove_output_window(PurpleMedia *media,
+
+void purple_media_remove_output_windows(PurpleMedia *media);
+
+GstElement *purple_media_get_tee(PurpleMedia *media,
const gchar *session_id, const gchar *participant);
-void purple_media_remove_output_windows(PurpleMedia *media);
#ifdef __cplusplus
}
============================================================
--- libpurple/mediamanager.c d4ee3ee46e33b3905c703ab595f14ef264ca2d75
+++ libpurple/mediamanager.c dcb14912e1d1fb5d26794eee952a83a44293ec02
@@ -35,12 +35,27 @@
#ifdef USE_VV
#include <gst/farsight/fs-conference-iface.h>
+#include <gst/interfaces/xoverlay.h>
+typedef struct _PurpleMediaOutputWindow PurpleMediaOutputWindow;
+
+struct _PurpleMediaOutputWindow
+{
+ gulong id;
+ PurpleMedia *media;
+ gchar *session_id;
+ gchar *participant;
+ gulong window_id;
+ GstElement *sink;
+};
+
struct _PurpleMediaManagerPrivate
{
GstElement *pipeline;
GList *medias;
GList *elements;
+ GList *output_windows;
+ gulong next_output_window_id;
PurpleMediaElementInfo *video_src;
PurpleMediaElementInfo *video_sink;
@@ -120,6 +135,7 @@ purple_media_manager_init (PurpleMediaMa
{
media->priv = PURPLE_MEDIA_MANAGER_GET_PRIVATE(media);
media->priv->medias = NULL;
+ media->priv->next_output_window_id = 1;
}
static void
@@ -412,4 +428,180 @@ purple_media_manager_get_active_element(
return NULL;
}
+static void
+window_id_cb(GstBus *bus, GstMessage *msg, PurpleMediaOutputWindow *ow)
+{
+ if (GST_MESSAGE_TYPE(msg) != GST_MESSAGE_ELEMENT ||
+ !gst_structure_has_name(msg->structure,
+ "prepare-xwindow-id"))
+ return;
+
+ if (GST_ELEMENT_PARENT(GST_MESSAGE_SRC(msg)) == ow->sink) {
+ g_signal_handlers_disconnect_matched(bus, G_SIGNAL_MATCH_FUNC
+ | G_SIGNAL_MATCH_DATA, 0, 0, NULL,
+ window_id_cb, ow);
+
+ gst_x_overlay_set_xwindow_id(GST_X_OVERLAY(
+ GST_MESSAGE_SRC(msg)), ow->window_id);
+ }
+}
+
+gboolean
+purple_media_manager_create_output_window(PurpleMediaManager *manager,
+ PurpleMedia *media, const gchar *session_id,
+ const gchar *participant)
+{
+ GList *iter;
+
+ g_return_val_if_fail(PURPLE_IS_MEDIA(media), FALSE);
+
+ iter = manager->priv->output_windows;
+ for(; iter; iter = g_list_next(iter)) {
+ PurpleMediaOutputWindow *ow = iter->data;
+
+ if (ow->sink == NULL && ow->media == media &&
+ ((participant != NULL &&
+ ow->participant != NULL &&
+ !strcmp(participant, ow->participant)) ||
+ (participant == ow->participant)) &&
+ !strcmp(session_id, ow->session_id)) {
+ GstBus *bus;
+ GstElement *queue;
+ GstElement *tee = purple_media_get_tee(media,
+ session_id, participant);
+
+ if (tee == NULL)
+ continue;
+
+ queue = gst_element_factory_make(
+ "queue", NULL);
+ ow->sink = purple_media_manager_get_element(
+ manager, PURPLE_MEDIA_RECV_VIDEO);
+
+ if (participant == NULL)
+ /* aka this is a preview sink */
+ g_object_set(G_OBJECT(ow->sink), "sync", FALSE,
+ "async", "FALSE", NULL);
+
+ gst_bin_add_many(GST_BIN(GST_ELEMENT_PARENT(tee)),
+ queue, ow->sink, NULL);
+
+ bus = gst_pipeline_get_bus(GST_PIPELINE(
+ manager->priv->pipeline));
+ g_signal_connect(bus, "sync-message::element",
+ G_CALLBACK(window_id_cb), ow);
+ gst_object_unref(bus);
+
+ gst_element_sync_state_with_parent(ow->sink);
+ gst_element_link(queue, ow->sink);
+ gst_element_sync_state_with_parent(queue);
+ gst_element_link(tee, queue);
+ }
+ }
+ return TRUE;
+}
+
+gulong
+purple_media_manager_set_output_window(PurpleMediaManager *manager,
+ PurpleMedia *media, const gchar *session_id,
+ const gchar *participant, gulong window_id)
+{
+ PurpleMediaOutputWindow *output_window;
+
+ g_return_val_if_fail(PURPLE_IS_MEDIA_MANAGER(manager), FALSE);
+ g_return_val_if_fail(PURPLE_IS_MEDIA(media), FALSE);
+
+ output_window = g_new0(PurpleMediaOutputWindow, 1);
+ output_window->id = manager->priv->next_output_window_id++;
+ output_window->media = media;
+ output_window->session_id = g_strdup(session_id);
+ output_window->participant = g_strdup(participant);
+ output_window->window_id = window_id;
+
+ manager->priv->output_windows = g_list_prepend(
+ manager->priv->output_windows, output_window);
+
+ if (purple_media_get_tee(media, session_id, participant) != NULL)
+ purple_media_manager_create_output_window(manager,
+ media, session_id, participant);
+
+ return output_window->id;
+}
+
+gboolean
+purple_media_manager_remove_output_window(PurpleMediaManager *manager,
+ gulong output_window_id)
+{
+ PurpleMediaOutputWindow *output_window = NULL;
+ GList *iter;
+
+ g_return_val_if_fail(PURPLE_IS_MEDIA_MANAGER(manager), FALSE);
+
+ iter = manager->priv->output_windows;
+ for (; iter; iter = g_list_next(iter)) {
+ PurpleMediaOutputWindow *ow = iter->data;
+ if (ow->id == output_window_id) {
+ manager->priv->output_windows = g_list_delete_link(
+ manager->priv->output_windows, iter);
+ output_window = ow;
+ break;
+ }
+ }
+
+ if (output_window == NULL)
+ return FALSE;
+
+ if (output_window->sink != NULL) {
+ GstPad *pad = gst_element_get_static_pad(
+ output_window->sink, "sink");
+ GstPad *peer = gst_pad_get_peer(pad);
+ GstElement *queue = GST_ELEMENT_PARENT(peer);
+ gst_object_unref(pad);
+ pad = gst_element_get_static_pad(queue, "sink");
+ peer = gst_pad_get_peer(pad);
+ gst_object_unref(pad);
+ gst_element_release_request_pad(GST_ELEMENT_PARENT(peer), peer);
+ gst_element_set_locked_state(queue, TRUE);
+ gst_element_set_state(queue, GST_STATE_NULL);
+ gst_bin_remove(GST_BIN(GST_ELEMENT_PARENT(queue)), queue);
+ gst_element_set_locked_state(output_window->sink, TRUE);
+ gst_element_set_state(output_window->sink, GST_STATE_NULL);
+ gst_bin_remove(GST_BIN(GST_ELEMENT_PARENT(output_window->sink)),
+ output_window->sink);
+ }
+
+ g_free(output_window->session_id);
+ g_free(output_window->participant);
+ g_free(output_window);
+
+ return TRUE;
+}
+
+void
+purple_media_manager_remove_output_windows(PurpleMediaManager *manager,
+ PurpleMedia *media, const gchar *session_id,
+ const gchar *participant)
+{
+ GList *iter;
+
+ g_return_if_fail(PURPLE_IS_MEDIA(media));
+
+ iter = manager->priv->output_windows;
+
+ for (; iter;) {
+ PurpleMediaOutputWindow *ow = iter->data;
+ iter = g_list_next(iter);
+
+ if (media == ow->media &&
+ ((session_id != NULL && ow->session_id != NULL &&
+ !strcmp(session_id, ow->session_id)) ||
+ (session_id == ow->session_id)) &&
+ ((participant != NULL && ow->participant != NULL &&
+ !strcmp(participant, ow->participant)) ||
+ (participant == ow->participant)))
+ purple_media_manager_remove_output_window(
+ manager, ow->id);
+ }
+}
+
#endif /* USE_VV */
============================================================
--- libpurple/mediamanager.h 5bda569c12d216f19f74f5e2ad3e5a914ab7e4c7
+++ libpurple/mediamanager.h a97d2d3a8d8103b4c1ce5a3e21ebc363c9522456
@@ -184,6 +184,20 @@ PurpleMediaElementInfo *purple_media_man
PurpleMediaElementInfo *info);
PurpleMediaElementInfo *purple_media_manager_get_active_element(
PurpleMediaManager *manager, PurpleMediaElementType type);
+/**
+ * This shouldn't be called outside of mediamanager.c and media.c
+ */
+gboolean purple_media_manager_create_output_window(
+ PurpleMediaManager *manager, PurpleMedia *media,
+ const gchar *session_id, const gchar *participant);
+gulong purple_media_manager_set_output_window(PurpleMediaManager *manager,
+ PurpleMedia *media, const gchar *session_id,
+ const gchar *participant, gulong window_id);
+gboolean purple_media_manager_remove_output_window(
+ PurpleMediaManager *manager, gulong output_window_id);
+void purple_media_manager_remove_output_windows(
+ PurpleMediaManager *manager, PurpleMedia *media,
+ const gchar *session_id, const gchar *participant);
/*}@*/
#ifdef __cplusplus
More information about the Commits
mailing list