pidgin.vv: 2327fc75: Wait to create the sinks until the frame...
maiku at soc.pidgin.im
maiku at soc.pidgin.im
Mon Jan 19 05:56:23 EST 2009
-----------------------------------------------------------------
Revision: 2327fc75d25586f742fc4305b4dfc93a581c1e13
Ancestor: 4af773e4022b42fec537fedc9efee34e4c9a5497
Author: maiku at soc.pidgin.im
Date: 2009-01-19T10:44:07
Branch: im.pidgin.pidgin.vv
URL: http://d.pidgin.im/viewmtn/revision/info/2327fc75d25586f742fc4305b4dfc93a581c1e13
Modified files:
libpurple/media.c libpurple/media.h pidgin/gtkmedia.c
ChangeLog:
Wait to create the sinks until the frames are ready.
This should hopefully be the end of the BadWindow errors.
-------------- next part --------------
============================================================
--- libpurple/media.c a9a97d0c21c174eabe784dcd70800ff38e2947b9
+++ libpurple/media.c 230d96a2a84621cc3ec08eb186108d2e784f25ca
@@ -39,6 +39,7 @@
#ifdef USE_VV
#include <gst/interfaces/propertyprobe.h>
+#include <gst/interfaces/xoverlay.h>
#include <gst/farsight/fs-conference-iface.h>
/** @copydoc _PurpleMediaSession */
@@ -57,6 +58,9 @@ struct _PurpleMediaSession
gboolean codecs_ready;
gboolean accepted;
+
+ GstElement *sink;
+ gulong window_id;
};
struct _PurpleMediaStream
@@ -73,6 +77,8 @@ struct _PurpleMediaStream
FsCandidate *local_candidate;
FsCandidate *remote_candidate;
+
+ gulong window_id;
};
struct _PurpleMediaPrivate
@@ -1365,7 +1371,7 @@ purple_media_video_init_src(GstElement *
void
purple_media_video_init_src(GstElement **sendbin)
{
- GstElement *src, *tee, *queue, *local_sink;
+ GstElement *src, *tee, *queue;
GstPad *pad;
GstPad *ghost;
const gchar *video_plugin = purple_prefs_get_string(
@@ -1395,14 +1401,6 @@ purple_media_video_init_src(GstElement *
gst_object_unref(pad);
gst_element_add_pad(*sendbin, ghost);
- queue = gst_element_factory_make("queue", "purplelocalvideoqueue");
- gst_bin_add(GST_BIN(*sendbin), queue);
- gst_element_link(tee, queue);
-
- local_sink = gst_element_factory_make("autovideosink", "purplelocalvideosink");
- gst_bin_add(GST_BIN(*sendbin), local_sink);
- gst_element_link(queue, local_sink);
-
if (video_device != NULL && strcmp(video_device, ""))
g_object_set(G_OBJECT(src), "device", video_device, NULL);
}
@@ -1436,8 +1434,8 @@ purple_media_video_init_recv(GstElement
GstElement *sink;
GstPad *pad, *ghost;
- *recvbin = gst_bin_new("pidginrecvvideobin");
- sink = gst_element_factory_make("autovideosink", "purplevideosink");
+ *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);
@@ -1526,7 +1524,8 @@ purple_media_src_pad_added_cb(FsStream *
PurpleMediaSessionType type = purple_media_from_fs(codec->media_type, FS_DIRECTION_RECV);
GstPad *sinkpad = NULL;
- stream->sink = purple_media_manager_get_element(
+ if (stream->sink == NULL)
+ stream->sink = purple_media_manager_get_element(
purple_media_manager_get(), type);
gst_bin_add(GST_BIN(purple_media_get_pipeline(stream->session->media)),
@@ -1890,4 +1889,237 @@ void purple_media_set_output_volume(Purp
}
}
+typedef struct
+{
+ PurpleMedia *media;
+ gchar *session_id;
+ gchar *participant;
+ gulong handler_id;
+} PurpleMediaXOverlayData;
+
+static void
+window_id_cb(GstBus *bus, GstMessage *msg, PurpleMediaXOverlayData *data)
+{
+ gchar *name;
+ gchar *cmpname;
+ gulong window_id;
+ gboolean set = FALSE;
+
+ 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 (data->participant == NULL) {
+ cmpname = g_strdup_printf("session-sink_%s",
+ data->session_id);
+ if (!strncmp(name, cmpname, strlen(cmpname))) {
+ PurpleMediaSession *session =
+ purple_media_get_session(
+ data->media, data->session_id);
+ if (session != NULL) {
+ window_id = session->window_id;
+ set = TRUE;
+ }
+ }
+ } else {
+ cmpname = g_strdup_printf("stream-sink_%s_%s",
+ data->session_id, data->participant);
+
+ if (!strncmp(name, cmpname, strlen(cmpname))) {
+ PurpleMediaStream *stream =
+ purple_media_get_stream(
+ data->media, data->session_id,
+ data->participant);
+ if (stream != NULL) {
+ window_id = stream->window_id;
+ set = TRUE;
+ }
+ }
+ }
+ g_free(cmpname);
+ g_free(name);
+
+ if (set == TRUE) {
+ GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(
+ purple_media_get_pipeline(data->media)));
+ g_signal_handler_disconnect(bus, data->handler_id);
+ gst_object_unref(bus);
+
+ gst_x_overlay_set_xwindow_id(GST_X_OVERLAY(
+ GST_MESSAGE_SRC(msg)), window_id);
+
+ g_free(data->session_id);
+ g_free(data->participant);
+ g_free(data);
+ }
+
+ return;
+}
+
+gboolean
+purple_media_set_output_window(PurpleMedia *media, const gchar *session_id,
+ const gchar *participant, gulong window_id)
+{
+
+ 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) {
+ GstBus *bus;
+ GstElement *tee, *bin, *queue, *sink;
+ GstPad *request_pad, *sinkpad, *ghostpad;
+ gchar *name;
+
+ /* Create callback for prepared-xwindow-id signal */
+ PurpleMediaXOverlayData *data =
+ g_new0(PurpleMediaXOverlayData, 1);
+ data->media = media;
+ data->session_id = g_strdup(session_id);
+ data->participant = g_strdup(participant);
+
+ bus = gst_pipeline_get_bus(GST_PIPELINE(
+ purple_media_get_pipeline(media)));
+ data->handler_id = g_signal_connect(bus,
+ "sync-message::element",
+ G_CALLBACK(window_id_cb), data);
+ gst_object_unref(bus);
+
+ /* Create sink */
+ tee = gst_bin_get_by_name(GST_BIN(session->src),
+ "purplevideosrctee");
+ bin = gst_bin_new(NULL);
+ gst_bin_add(GST_BIN(GST_ELEMENT_PARENT(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);
+ g_free(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);
+
+ gst_element_set_state(bin, GST_STATE_PLAYING);
+
+ request_pad = gst_element_get_request_pad(
+ 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, *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;
+ }
+ }
+
+ data = g_new0(PurpleMediaXOverlayData, 1);
+ data->media = media;
+ data->session_id = g_strdup(session_id);
+ data->participant = g_strdup(participant);
+
+ bus = gst_pipeline_get_bus(GST_PIPELINE(
+ purple_media_get_pipeline(media)));
+ data->handler_id = g_signal_connect(bus,
+ "sync-message::element",
+ G_CALLBACK(window_id_cb), data);
+ gst_object_unref(bus);
+
+ bin = gst_bin_new(NULL);
+
+ if (stream->sink != NULL)
+ gst_bin_add(GST_BIN(GST_ELEMENT_PARENT(
+ stream->sink)), bin);
+
+ name = g_strdup_printf("stream-sink_%s_%s",
+ session_id, participant);
+ sink = gst_element_factory_make("autovideosink", name);
+ g_free(name);
+
+ gst_bin_add(GST_BIN(bin), sink);
+ pad = gst_element_get_static_pad(sink, "sink");
+ ghostpad = gst_ghost_pad_new("ghostsink", pad);
+ gst_element_add_pad(bin, ghostpad);
+
+ if (stream->sink != NULL) {
+ gst_element_set_state(bin, GST_STATE_PLAYING);
+ gst_pad_link(peer, ghostpad);
+ }
+
+ stream->sink = bin;
+ return TRUE;
+ }
+ return FALSE;
+}
+
#endif /* USE_VV */
============================================================
--- libpurple/media.h bc9c5718da5f8286d7ee861356d17addfc49d0be
+++ libpurple/media.h 33dad1d2afd351f9bb3cde16cc2713f676aa7795
@@ -624,6 +624,10 @@ 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,
+ const gchar *session_id, const gchar *participant,
+ gulong window_id);
+
#ifdef __cplusplus
}
#endif
============================================================
--- pidgin/gtkmedia.c cdc30ea6b47a669926a415a619e1705339a5189f
+++ pidgin/gtkmedia.c b7f64c774bac6835c2574f54e4f2269ac76dc007
@@ -318,42 +318,37 @@ pidgin_media_emit_message(PidginMedia *g
g_signal_emit(gtkmedia, pidgin_media_signals[MESSAGE], 0, msg);
}
-static gboolean
-create_window (GstBus *bus, GstMessage *message, PidginMedia *gtkmedia)
+typedef struct
{
- char *name;
+ PidginMedia *gtkmedia;
+ gchar *session_id;
+ gchar *participant;
+} PidginMediaRealizeData;
- if (GST_MESSAGE_TYPE(message) != GST_MESSAGE_ELEMENT)
- return TRUE;
+static gboolean
+realize_cb_cb(PidginMediaRealizeData *data)
+{
+ PidginMediaPrivate *priv = data->gtkmedia->priv;
+ gulong window_id;
- if (!gst_structure_has_name(message->structure, "prepare-xwindow-id"))
- return TRUE;
+ if (data->participant == NULL)
+ window_id = GDK_WINDOW_XWINDOW(priv->local_video->window);
+ else
+ window_id = GDK_WINDOW_XWINDOW(priv->remote_video->window);
- name = gst_object_get_name(GST_MESSAGE_SRC (message));
+ purple_media_set_output_window(priv->media, data->session_id,
+ data->participant, window_id);
- /* The XOverlay's name is the sink's name with a suffix */
- if (!strncmp(name, "purplevideosink", strlen("purplevideosink")))
- gst_x_overlay_set_xwindow_id(GST_X_OVERLAY(GST_MESSAGE_SRC(message)),
- GDK_WINDOW_XWINDOW(gtkmedia->priv->remote_video->window));
- else if (!strncmp(name, "purplelocalvideosink", strlen("purplelocalvideosink")))
- gst_x_overlay_set_xwindow_id(GST_X_OVERLAY(GST_MESSAGE_SRC(message)),
- GDK_WINDOW_XWINDOW(gtkmedia->priv->local_video->window));
- g_free(name);
- return TRUE;
-}
-
-static gboolean
-realize_cb_cb(GstElement *element)
-{
- gst_element_set_locked_state(element, FALSE);
- gst_element_set_state(element, GST_STATE_PLAYING);
+ g_free(data->session_id);
+ g_free(data->participant);
+ g_free(data);
return FALSE;
}
static void
-realize_cb(GtkWidget *widget, GstElement *element)
+realize_cb(GtkWidget *widget, PidginMediaRealizeData *data)
{
- g_timeout_add(0, (GSourceFunc)realize_cb_cb, element);
+ g_timeout_add(0, (GSourceFunc)realize_cb_cb, data);
}
static void
@@ -390,7 +385,6 @@ pidgin_media_ready_cb(PurpleMedia *media
GstElement *videosendbin = NULL;
gboolean audiorecvbool = FALSE;
gboolean videorecvbool = FALSE;
- GstBus *bus;
gboolean is_initiator;
PurpleMediaSessionType type = purple_media_get_session_type(media, sid);
@@ -406,8 +400,8 @@ pidgin_media_ready_cb(PurpleMedia *media
} else if (type & PURPLE_MEDIA_VIDEO) {
if (!videosendbin && (type & PURPLE_MEDIA_SEND_VIDEO)) {
purple_media_video_init_src(&videosendbin);
- gst_element_set_locked_state(videosendbin, TRUE);
purple_media_set_src(media, sid, videosendbin);
+ gst_element_set_state(videosendbin, GST_STATE_PLAYING);
}
if (!videorecvbool && (type & PURPLE_MEDIA_RECV_VIDEO)) {
videorecvbool = TRUE;
@@ -432,6 +426,7 @@ pidgin_media_ready_cb(PurpleMedia *media
send_widget = gtkmedia->priv->send_widget;
if (videorecvbool) {
+ PidginMediaRealizeData *data;
GtkWidget *aspect;
GtkWidget *remote_video;
GtkWidget *plug;
@@ -454,7 +449,14 @@ pidgin_media_ready_cb(PurpleMedia *media
gtk_container_add(GTK_CONTAINER(aspect), socket);
gtk_widget_show(socket);
+ data = g_new0(PidginMediaRealizeData, 1);
+ data->gtkmedia = gtkmedia;
+ data->session_id = g_strdup(sid);
+ data->participant = g_strdup(gtkmedia->priv->screenname);
+
remote_video = gtk_drawing_area_new();
+ g_signal_connect(G_OBJECT(remote_video), "realize",
+ G_CALLBACK(realize_cb), data);
gtk_container_add(GTK_CONTAINER(plug), remote_video);
gtk_widget_set_size_request (GTK_WIDGET(remote_video), 100, -1);
gtk_widget_show(remote_video);
@@ -463,6 +465,7 @@ pidgin_media_ready_cb(PurpleMedia *media
gtkmedia->priv->remote_video = remote_video;
}
if (videosendbin) {
+ PidginMediaRealizeData *data;
GtkWidget *aspect;
GtkWidget *local_video;
GtkWidget *plug;
@@ -485,9 +488,14 @@ pidgin_media_ready_cb(PurpleMedia *media
gtk_container_add(GTK_CONTAINER(aspect), socket);
gtk_widget_show(socket);
+ data = g_new0(PidginMediaRealizeData, 1);
+ data->gtkmedia = gtkmedia;
+ data->session_id = g_strdup(sid);
+ data->participant = NULL;
+
local_video = gtk_drawing_area_new();
g_signal_connect(G_OBJECT(local_video), "realize",
- G_CALLBACK(realize_cb), videosendbin);
+ G_CALLBACK(realize_cb), data);
gtk_container_add(GTK_CONTAINER(plug), local_video);
gtk_widget_set_size_request (GTK_WIDGET(local_video), 100, -1);
@@ -518,18 +526,14 @@ pidgin_media_ready_cb(PurpleMedia *media
gtk_widget_show(gtkmedia->priv->mute);
}
- bus = gst_pipeline_get_bus(GST_PIPELINE(pipeline));
- if (videorecvbool || videosendbin)
- g_signal_connect(bus, "sync-message::element",
- G_CALLBACK(create_window), gtkmedia);
-
- if (audiorecvbool || audiosendbin)
+ if (audiorecvbool || audiosendbin) {
+ GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(pipeline));
g_signal_connect(G_OBJECT(bus), "message::element",
G_CALLBACK(level_message_cb), gtkmedia);
+ gst_object_unref(bus);
+ }
- gst_object_unref(bus);
-
if (send_widget != NULL)
gtkmedia->priv->send_widget = send_widget;
if (recv_widget != NULL)
More information about the Commits
mailing list