[rhythmbox/v0.13.x] xfade: fix race condition with preroll vs end of previous stream (bug #646405)



commit 8cddf1d9a0fb4fea7a555d7b3d011c00f2a8d616
Author: Jonathan Matthew <jonathan d14n org>
Date:   Sun May 8 11:42:29 2011 +1000

    xfade: fix race condition with preroll vs end of previous stream (bug #646405)
    
    Previously there was a window where a stream would not be started
    if it finished prerolling after the previous stream reached EOS, but
    before the EOS message was processed on the main thread, and the
    new stream needed to wait for the previous stream to finish.
    
    We now check for new streams to start both when the stream reaches EOS
    (processed on the stream thread) and when the EOS bus message is
    processed (on the main thread), so the new stream will always be started.
    If it doesn't preroll in time, there may be a slight gap in the audio
    output, but that's unavoidable if preroll is too slow.

 backends/gstreamer/rb-player-gst-xfade.c |   61 +++++++++++++++++------------
 1 files changed, 36 insertions(+), 25 deletions(-)
---
diff --git a/backends/gstreamer/rb-player-gst-xfade.c b/backends/gstreamer/rb-player-gst-xfade.c
index 3ac7b56..1ff7602 100644
--- a/backends/gstreamer/rb-player-gst-xfade.c
+++ b/backends/gstreamer/rb-player-gst-xfade.c
@@ -1619,6 +1619,35 @@ rb_player_gst_xfade_handle_missing_plugin_message (RBPlayerGstXFade *player, RBX
 	}
 }
 
+static void
+start_waiting_eos_streams (RBPlayerGstXFade *player)
+{
+	GList *l;
+	GList *to_start = NULL;
+
+	g_static_rec_mutex_lock (&player->priv->stream_list_lock);
+	for (l = player->priv->streams; l != NULL; l = l->next) {
+		RBXFadeStream *pstream = l->data;
+		if (pstream->state == WAITING_EOS) {
+			to_start = g_list_prepend (to_start, g_object_ref (pstream));
+		}
+	}
+	g_static_rec_mutex_unlock (&player->priv->stream_list_lock);
+
+	for (l = to_start; l != NULL; l = l->next) {
+		RBXFadeStream *pstream = l->data;
+		GError *error = NULL;
+
+		rb_debug ("starting stream %s on EOS from previous", pstream->uri);
+		if (link_and_unblock_stream (pstream, &error) == FALSE) {
+			emit_stream_error (pstream, error);
+		}
+
+		g_object_unref (pstream);
+	}
+	g_list_free (to_start);
+}
+
 /* gstreamer message bus callback */
 static gboolean
 rb_player_gst_xfade_bus_cb (GstBus *bus, GstMessage *message, RBPlayerGstXFade *player)
@@ -1785,6 +1814,12 @@ rb_player_gst_xfade_bus_cb (GstBus *bus, GstMessage *message, RBPlayerGstXFade *
 				stream->state = PENDING_REMOVE;
 
 				unlink_blocked_cb (stream->src_pad, TRUE, stream);
+
+				/* start playing any streams that were waiting on an EOS
+				 * if they finished preroll between when we posted the EOS
+				 * message on the stream thread and now.
+				 */
+				start_waiting_eos_streams (player);
 			} else {
 				/* no need to emit EOS here, we already know what to do next */
 				rb_debug ("got EOS message for stream %s in REUSING state", stream->uri);
@@ -1940,9 +1975,6 @@ stream_src_event_cb (GstPad *pad, GstEvent *event, RBXFadeStream *stream)
 {
 	GstMessage *msg;
 	GstStructure *s;
-	RBPlayerGstXFade *player;
-	GList *l;
-	GList *to_start = NULL;
 
 	switch (GST_EVENT_TYPE (event)) {
 	case GST_EVENT_EOS:
@@ -1954,28 +1986,7 @@ stream_src_event_cb (GstPad *pad, GstEvent *event, RBXFadeStream *stream)
 		/* start playing any streams that were waiting on an EOS
 		 * (are we really allowed to do this on a stream thread?)
 		 */
-		player = stream->player;
-		g_static_rec_mutex_lock (&player->priv->stream_list_lock);
-		for (l = player->priv->streams; l != NULL; l = l->next) {
-			RBXFadeStream *pstream = l->data;
-			if (pstream->state == WAITING_EOS) {
-				to_start = g_list_prepend (to_start, g_object_ref (pstream));
-			}
-		}
-		g_static_rec_mutex_unlock (&player->priv->stream_list_lock);
-
-		for (l = to_start; l != NULL; l = l->next) {
-			RBXFadeStream *pstream = l->data;
-			GError *error = NULL;
-
-			rb_debug ("starting stream %s on EOS from previous", pstream->uri);
-			if (link_and_unblock_stream (pstream, &error) == FALSE) {
-				emit_stream_error (pstream, error);
-			}
-
-			g_object_unref (pstream);
-		}
-		g_list_free (to_start);
+		start_waiting_eos_streams (stream->player);
 		break;
 
 	case GST_EVENT_NEWSEGMENT:



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]