rpms/rhythmbox/F-8 rhythmbox-0.11.3-xfade-pause-deadlock.patch, NONE, 1.1 rhythmbox.spec, 1.150, 1.151

Bastien Nocera (hadess) fedora-extras-commits at redhat.com
Mon Jan 7 10:05:12 UTC 2008


Author: hadess

Update of /cvs/pkgs/rpms/rhythmbox/F-8
In directory cvs-int.fedora.redhat.com:/tmp/cvs-serv6973

Modified Files:
	rhythmbox.spec 
Added Files:
	rhythmbox-0.11.3-xfade-pause-deadlock.patch 
Log Message:
* Mon Jan 07 2008 - Bastien Nocera <bnocera at redhat.com> - 0.11.3-7
- Add upstream patch to avoid the cross-fade backend hanging when
  skipping and paused (#427612)


rhythmbox-0.11.3-xfade-pause-deadlock.patch:

--- NEW FILE rhythmbox-0.11.3-xfade-pause-deadlock.patch ---
--- trunk/backends/gstreamer/rb-player-gst-xfade.c	2007/11/12 11:55:30	5442
+++ trunk/backends/gstreamer/rb-player-gst-xfade.c	2007/11/25 04:42:24	5455
@@ -97,7 +97,7 @@
  *
  * from PLAYING:
  *
- * - rb_player_pause():  -> PAUSED, block, unlink from adder
+ * - rb_player_pause(): -> FADING_OUT_PAUSE, fade out (short fade)
  * - EOS:  -> PENDING_REMOVE
  * - another stream starts fading in:  -> FADING_OUT
  * - stopped for another stream:  -> PENDING_REMOVE
@@ -114,7 +114,7 @@
  *
  * from PAUSED:
  *
- * - rb_player_play():  -> PLAYING, link to adder, unblock
+ * - rb_player_play():    -> FADING IN, link to adder, unblock (short fade)
  * - stopped for another stream:  -> PENDING_REMOVE
  * - rb_player_set_time(): -> perform seek
  *
@@ -124,6 +124,13 @@
  * - EOS:  -> PENDING_REMOVE
  * - reused for another stream:  -> REUSING; block, unlink
  *
+ * from FADING_OUT_PAUSED:
+ *
+ * - fade out finishes: -> SEEKING_PAUSED, block, unlink
+ * - EOS: -> PENDING_REMOVE
+ * - reused for another stream: -> REUSING, block, unlink
+ * - rb_player_set_time():  -> SEEKING_PAUSED, block, unlink
+ *
  * from PENDING_REMOVE:
  *
  * - reap_streams idle handler called:  -> unlink from adder, stream destroyed
@@ -171,7 +178,6 @@
 static void rb_player_gst_xfade_pause (RBPlayer *player);
 static gboolean rb_player_gst_xfade_playing (RBPlayer *player);
 static gboolean rb_player_gst_xfade_seekable (RBPlayer *player);
-static gboolean rb_player_gst_xfade_in_transition (RBPlayerGstXFade *player);
 static void rb_player_gst_xfade_set_time (RBPlayer *player, long time);
 static long rb_player_gst_xfade_get_time (RBPlayer *player);
 static void rb_player_gst_xfade_set_volume (RBPlayer *player, float volume);
@@ -188,7 +194,7 @@
 static gboolean create_sink (RBPlayerGstXFade *player, GError **error);
 static gboolean start_sink (RBPlayerGstXFade *player);
 static gboolean stop_sink (RBPlayerGstXFade *player);
-static gboolean pause_sink (RBPlayerGstXFade *player);
+static void maybe_stop_sink (RBPlayerGstXFade *player);
 
 GType rb_xfade_stream_get_type (void);
 
@@ -212,6 +218,8 @@
 
 #define MAX_NETWORK_BUFFER_SIZE		(2048)
 
+#define PAUSE_FADE_LENGTH	(GST_SECOND / 2)
+
 enum
 {
 	PROP_0,
@@ -247,7 +255,8 @@
 	SEEKING_PAUSED = 256,
 	WAITING_EOS = 512,
 	FADING_OUT = 1024,
-	PENDING_REMOVE = 2048
+	FADING_OUT_PAUSED = 2048,
+	PENDING_REMOVE = 4096
 } StreamState;
 
 typedef struct
@@ -347,6 +356,7 @@
 
 	GStaticRecMutex stream_list_lock;
 	GList *streams;
+	gint linked_streams;
 
 	gboolean can_signal_direct_error;
 	GError *error;
@@ -496,6 +506,7 @@
 			case SEEKING_PAUSED:	statename = "seeking->paused";	break;
 			case WAITING_EOS: 	statename = "waiting for EOS"; 	break;
 			case FADING_OUT: 	statename = "fading out"; 	break;
+			case FADING_OUT_PAUSED: statename = "fading->paused";   break;
 
 			case PENDING_REMOVE:	statename = "pending remove";	break;
 			}
@@ -888,20 +899,24 @@
 	g_object_get (stream->volume, "volume", &vol, NULL);
 	switch (stream->state) {
 	case FADING_IN:
-		if (vol > (stream->fade_end - EPSILON)) {
-			rb_debug ("stream %s fully faded in -> PLAYING state", stream->uri);
+		if (vol > (stream->fade_end - EPSILON) && stream->fading) {
+			rb_debug ("stream %s fully faded in (at %f) -> PLAYING state", stream->uri, vol);
 			/*message = FADE_IN_DONE_MESSAGE;*/		/* not actually used */
 			stream->fading = FALSE;
 			stream->state = PLAYING;
+			
 		/*} else {
 			rb_debug ("fading %s in: %f", stream->uri, (float)vol);*/
 		}
 		break;
 	case FADING_OUT:
+	case FADING_OUT_PAUSED:
 		if (vol < (stream->fade_end + EPSILON)) {
-			rb_debug ("stream %s fully faded out", stream->uri);
-			message = FADE_OUT_DONE_MESSAGE;
-			stream->fading = FALSE;
+			rb_debug ("stream %s fully faded out (at %f)", stream->uri, vol);
+			if (stream->fading) {
+				message = FADE_OUT_DONE_MESSAGE;
+				stream->fading = FALSE;
+			}
 		} else {
 			/*rb_debug ("fading %s out: %f", stream->uri, (float)vol);*/
 			/* force the volume element out of passthrough mode so it
@@ -935,7 +950,7 @@
  * is done.
  */
 static void
-start_stream_fade (RBXFadeStream *stream, double start, double end, gint64 time)
+start_stream_fade (RBXFadeStream *stream, double start, double end, gint64 time, gboolean havelock)
 {
 	GValue v = {0,};
 	gint64 pos = -1;
@@ -967,15 +982,17 @@
 		  (float)start, pos,
 		  (float)end, pos + time);
 
-	/* drop the stream list lock before doing anything to the controller.
-	 * volume changes result in volume_changed_cb being called with the
-	 * controller lock held; volume_changed_cb acquires the stream list lock.
-	 * therefore we can't ever touch the controller with the stream list lock
-	 * held.
-	 */
 
-	g_object_ref (stream);
-	g_static_rec_mutex_unlock (&player->priv->stream_list_lock);
+	if (havelock) {
+		/* drop the stream list lock before doing anything to the controller.
+		 * volume changes result in volume_changed_cb being called with the
+		 * controller lock held; volume_changed_cb acquires the stream list lock.
+		 * therefore we can't ever touch the controller with the stream list lock
+		 * held.
+		 */
+		g_object_ref (stream);
+		g_static_rec_mutex_unlock (&player->priv->stream_list_lock);
+	}
 
 	/* apparently we need to set the starting volume, otherwise fading in doesn't work. */
 	g_object_set (stream->volume, "volume", start, NULL);
@@ -999,8 +1016,10 @@
 	}
 	g_value_unset (&v);
 
-	g_static_rec_mutex_lock (&player->priv->stream_list_lock);
-	g_object_unref (stream);
+	if (havelock) {
+		g_static_rec_mutex_lock (&player->priv->stream_list_lock);
+		g_object_unref (stream);
+	}
 
 	stream->fade_end = end;
 	stream->fading = TRUE;
@@ -1015,6 +1034,8 @@
 static void
 link_unblocked_cb (GstPad *pad, gboolean blocked, RBXFadeStream *stream)
 {
+	GstStateChangeReturn state_ret;
+
 	/* sometimes we seem to get called twice */
 	if (stream->state == FADING_IN || stream->state == PLAYING) {
 		g_object_unref (stream);
@@ -1032,7 +1053,9 @@
 	adjust_stream_base_time (stream);
 
 	/* should handle state change failures here.. */
-	gst_element_set_state (stream->bin, GST_STATE_PLAYING);
+	state_ret = gst_element_set_state (stream->bin, GST_STATE_PLAYING);
+	rb_debug ("stream %s state change returned: %s", stream->uri,
+		  gst_element_state_change_return_get_name (state_ret));
 
 	post_stream_playing_message (stream);
 	g_static_rec_mutex_unlock (&stream->player->priv->stream_list_lock);
@@ -1092,6 +1115,9 @@
 		return FALSE;
 	}
 
+	player->priv->linked_streams++;
+	rb_debug ("now have %d linked streams", player->priv->linked_streams);
+
 	if (stream->src_blocked) {
 		g_object_ref (stream);
 		gst_pad_set_blocked_async (stream->src_pad,
@@ -1199,6 +1225,10 @@
 		g_warning ("Couldn't unlink stream %s: things will probably go quite badly from here on", stream->uri);
 	}
 
+	g_static_rec_mutex_lock (&stream->player->priv->sink_lock);
+	stream->player->priv->linked_streams--;
+	rb_debug ("%d linked streams left", stream->player->priv->linked_streams);
+
 	gst_element_release_request_pad (GST_PAD_PARENT (stream->adder_pad), stream->adder_pad);
 	stream->adder_pad = NULL;
 
@@ -1212,12 +1242,25 @@
 	case SEEKING:
 		perform_seek (stream);
 		break;
+
 	case REUSING:
 		reuse_stream (stream);
 		break;
+
+	case SEEKING_PAUSED:
+		perform_seek (stream);
+		/* fall through.  this only happens when pausing, so it's OK
+		 * to stop the sink here.
+		 */
 	default:
+		/* consider pausing the sink if this is the linked last stream */
+		if (stream->player->priv->linked_streams == 0) {
+			maybe_stop_sink (stream->player);
+		}
+
 		break;
 	}
+	g_static_rec_mutex_unlock (&stream->player->priv->sink_lock);
 }
 
 /*
@@ -1269,6 +1312,15 @@
 
 		gst_element_release_request_pad (GST_PAD_PARENT (stream->adder_pad), stream->adder_pad);
 		stream->adder_pad = NULL;
+
+		g_static_rec_mutex_lock (&player->priv->sink_lock);
+		player->priv->linked_streams--;
+		rb_debug ("now have %d linked streams", player->priv->linked_streams);
+
+		if (player->priv->linked_streams == 0) {
+			maybe_stop_sink (player);
+		}
+		g_static_rec_mutex_unlock (&player->priv->sink_lock);
 	}
 
 	if (GST_ELEMENT_PARENT (stream->bin) == player->priv->pipeline)
@@ -1565,10 +1617,37 @@
 		} else if (strcmp (name, FADE_IN_DONE_MESSAGE) == 0) {
 			/* do something? */
 		} else if (strcmp (name, FADE_OUT_DONE_MESSAGE) == 0) {
-			/* stop the stream and dispose of it */
-			rb_debug ("got fade-out-done for stream %s -> PENDING_REMOVE", stream->uri);
-			stream->state = PENDING_REMOVE;
-			schedule_stream_reap (player);
+			switch (stream->state) {
+			case FADING_OUT:
+				/* stop the stream and dispose of it */
+				rb_debug ("got fade-out-done for stream %s -> PENDING_REMOVE", stream->uri);
+				stream->state = PENDING_REMOVE;
+				schedule_stream_reap (player);
+				break;
+
+			case FADING_OUT_PAUSED:
+				{
+					/* try to seek back a bit to account for the fade */
+					GstFormat format = GST_FORMAT_TIME;
+					gint64 pos = -1;
+					gst_element_query_position (stream->volume, &format, &pos);
+					if (pos != -1) {
+						stream->seek_target = pos > PAUSE_FADE_LENGTH ? pos - PAUSE_FADE_LENGTH : 0;
+						stream->state = SEEKING_PAUSED;
+						rb_debug ("got fade-out-done for stream %s -> SEEKING_PAUSED [%" G_GINT64_FORMAT "]",
+							  stream->uri, stream->seek_target);
+					} else {
+						stream->state = PAUSED;
+						rb_debug ("got fade-out-done for stream %s -> PAUSED (position query failed)",
+							  stream->uri);
+					}
+				}
+				unlink_and_block_stream (stream);
+				break;
+
+			default:
+				g_assert_not_reached ();
+			}
 		} else if (strcmp (name, STREAM_EOS_MESSAGE) == 0) {
 			/* emit EOS, dispose of the stream, and start any
 			 * streams we had waiting for an EOS.
@@ -2094,10 +2173,10 @@
 				/* fall through */
 			case PLAYING:
 				rb_debug ("stream %s is playing; crossfading -> FADING_OUT", pstream->uri);
-				start_stream_fade (pstream, fade_out_start, 0.0f, fade_out_time);
+				start_stream_fade (pstream, fade_out_start, 0.0f, fade_out_time, TRUE);
 				pstream->state = FADING_OUT;
 
-				start_stream_fade (stream, 0.0f, 1.0f, stream->crossfade * GST_SECOND);
+				start_stream_fade (stream, 0.0f, 1.0f, stream->crossfade * GST_SECOND, TRUE);
 				break;
 
 			case PAUSED:
@@ -2306,7 +2385,7 @@
 		return FALSE;
 
 	g_static_rec_mutex_lock (&player->priv->stream_list_lock);
-	stream = find_stream_by_state (player, FADING_IN | PLAYING | PAUSED);
+	stream = find_stream_by_state (player, FADING_IN | PLAYING | FADING_OUT_PAUSED | PAUSED);
 	g_static_rec_mutex_unlock (&player->priv->stream_list_lock);
 
 	if (stream != NULL) {
@@ -2553,6 +2632,13 @@
 			rb_debug ("couldn't stop silence bin");
 			return FALSE;
 		}
+
+		/* try stopping the sink, but don't worry if we can't */
+		sr = gst_element_set_state (player->priv->sink, GST_STATE_NULL);
+		if (sr == GST_STATE_CHANGE_FAILURE) {
+			rb_debug ("couldn't set audio sink to NULL state");
+		}
+
 		player->priv->sink_state = SINK_STOPPED;
 		break;
 
@@ -2564,30 +2650,6 @@
 	return TRUE;
 }
 
-static gboolean
-pause_sink (RBPlayerGstXFade *player)
-{
-	switch (player->priv->sink_state) {
-	case SINK_PLAYING:
-		rb_debug ("pausing sink");
-		gst_element_set_state (player->priv->outputbin, GST_STATE_PAUSED);
-		/* wait for state change? */
-		player->priv->sink_state = SINK_PAUSED;
-		return TRUE;
-
-	case SINK_PAUSED:
-		rb_debug ("sink already paused");
-		return TRUE;
-
-	case SINK_NULL:
-	case SINK_STOPPED:
-		rb_debug ("sink doesn't need pausing");
-		return TRUE;
-	default:
-		g_assert_not_reached ();
-	}
-
-}
 
 static gboolean
 create_sink (RBPlayerGstXFade *player, GError **error)
@@ -2858,6 +2920,7 @@
 		case PLAYING:
 		case FADING_IN:
 		case FADING_OUT:
+		case FADING_OUT_PAUSED:
 		case WAITING_EOS:
 		case PAUSED:
 			g_signal_emit (player,
@@ -2928,23 +2991,27 @@
 static gboolean
 stop_sink_later (RBPlayerGstXFade *player)
 {
-	gboolean stop;
-
 	player->priv->stop_sink_id = 0;
-
-	g_static_rec_mutex_lock (&player->priv->stream_list_lock);
-	stop = (player->priv->streams == NULL);
-	g_static_rec_mutex_unlock (&player->priv->stream_list_lock);
-
-	if (stop) {
-		g_static_rec_mutex_lock (&player->priv->sink_lock);
+	g_static_rec_mutex_lock (&player->priv->sink_lock);
+	if (player->priv->linked_streams == 0) {
 		stop_sink (player);
-		g_static_rec_mutex_unlock (&player->priv->sink_lock);
 	}
+	g_static_rec_mutex_unlock (&player->priv->sink_lock);
 
 	return FALSE;
 }
 
+static void
+maybe_stop_sink (RBPlayerGstXFade *player)
+{
+	if (player->priv->stop_sink_id == 0) {
+		player->priv->stop_sink_id =
+			g_timeout_add (1000,
+				       (GSourceFunc) stop_sink_later,
+				       player);
+	}
+}
+
 static gboolean
 rb_player_gst_xfade_close (RBPlayer *iplayer, const char *uri, GError **error)
 {
@@ -2994,17 +3061,6 @@
 		}
 	}
 
-	g_static_rec_mutex_lock (&player->priv->stream_list_lock);
-	if (player->priv->streams == NULL) {
-		if (player->priv->stop_sink_id == 0) {
-			player->priv->stop_sink_id =
-				g_timeout_add (10000,
-					       (GSourceFunc) stop_sink_later,
-					       player);
-		}
-	}
-	g_static_rec_mutex_unlock (&player->priv->stream_list_lock);
-
 	return ret;
 }
 
@@ -3069,6 +3125,7 @@
 	switch (stream->state) {
 	case FADING_IN:
 	case FADING_OUT:
+	case FADING_OUT_PAUSED:
 	case PLAYING:
 	case SEEKING:
 		rb_debug ("stream %s is already playing", stream->uri);
@@ -3084,7 +3141,7 @@
 
 	case PAUSED:
 		rb_debug ("unpausing stream %s", stream->uri);
-		/* consider fading in here?  and/or seek back a bit? */
+		start_stream_fade (stream, 0.0f, 1.0f, PAUSE_FADE_LENGTH, FALSE);
 		ret = link_and_unblock_stream (stream, error);
 		break;
 
@@ -3120,14 +3177,6 @@
 	GList *l;
 	gboolean done = FALSE;
 
-	/* if we're only playing one stream, just pause the sink */
-	if (rb_player_gst_xfade_in_transition (player) == FALSE) {
-		g_static_rec_mutex_lock (&player->priv->sink_lock);
-		pause_sink (player);
-		g_static_rec_mutex_unlock (&player->priv->sink_lock);
-		return;
-	}
-
 	g_static_rec_mutex_lock (&player->priv->stream_list_lock);
 
 	for (l = player->priv->streams; l != NULL; l = l->next) {
@@ -3150,16 +3199,17 @@
 
 		case PAUSED:
 		case SEEKING_PAUSED:
+		case FADING_OUT_PAUSED:
 			rb_debug ("stream %s is already paused", stream->uri);
 			done = TRUE;
 			break;
 
 		case PLAYING:
 		case FADING_IN:
-			rb_debug ("pausing stream %s -> PAUSED", stream->uri);
-			/* consider fading out here?  or just kill the volume? */
-			unlink_and_block_stream (stream);
-			stream->state = PAUSED;
+			rb_debug ("pausing stream %s -> FADING_OUT_PAUSED", stream->uri);
+
+			stream->state = FADING_OUT_PAUSED;
+			start_stream_fade (stream, 1.0f, 0.0f, PAUSE_FADE_LENGTH, TRUE);
 			done = TRUE;
 			break;
 
@@ -3189,39 +3239,6 @@
 }
 
 static gboolean
-rb_player_gst_xfade_in_transition (RBPlayerGstXFade *player)
-{
-	gboolean playing = FALSE;
-	gboolean transition = FALSE;
-	GList *l;
-
-	g_static_rec_mutex_lock (&player->priv->stream_list_lock);
-	for (l = player->priv->streams; l; l = l->next) {
-		RBXFadeStream *stream;
-
-		stream = (RBXFadeStream *)l->data;
-		switch (stream->state) {
-		case PLAYING:
-		case FADING_IN:
-		case FADING_OUT:
-		case SEEKING:
-		case SEEKING_PAUSED:
-		case REUSING:
-			if (playing)
-				transition = TRUE;
-			else
-				playing = TRUE;
-			break;
-
-		default:
-			break;
-		}
-	}
-	g_static_rec_mutex_unlock (&player->priv->stream_list_lock);
-	return transition;
-}
-
-static gboolean
 rb_player_gst_xfade_playing (RBPlayer *iplayer)
 {
 	RBPlayerGstXFade *player = RB_PLAYER_GST_XFADE (iplayer);
@@ -3302,6 +3319,7 @@
 	case WAITING_EOS:
 	case PREROLLING:
 	case PREROLL_PLAY:
+	case FADING_OUT_PAUSED:
 		g_object_set (stream->volume, "volume", stream->replaygain_scale, NULL);
 		break;
 
@@ -3381,9 +3399,10 @@
 {
 	RBPlayerGstXFade *player = RB_PLAYER_GST_XFADE (iplayer);
 	RBXFadeStream *stream;
+	StreamState seeking_state = SEEKING;
 
 	g_static_rec_mutex_lock (&player->priv->stream_list_lock);
-	stream = find_stream_by_state (player, FADING_IN | PLAYING | PAUSED);
+	stream = find_stream_by_state (player, FADING_IN | PLAYING | PAUSED | FADING_OUT_PAUSED);
 	g_static_rec_mutex_unlock (&player->priv->stream_list_lock);
 
 	if (stream == NULL) {
@@ -3392,15 +3411,26 @@
 	}
 
 	stream->seek_target = time * GST_SECOND;
-	if (stream->state == PAUSED) {
+	switch (stream->state) {
+	case PAUSED:
 		rb_debug ("seeking in paused stream %s; target %" 
 		    G_GINT64_FORMAT, stream->uri, stream->seek_target);
 		perform_seek (stream);
-	} else {
+		break;
+
+	case FADING_OUT_PAUSED:
+		/* don't unblock and relink when the seek is done */
+		seeking_state = SEEKING_PAUSED;
+	case FADING_IN:
+	case PLAYING:
 		rb_debug ("unlinking playing stream %s to seek to %"
 		    G_GINT64_FORMAT, stream->uri, stream->seek_target);
-		stream->state = SEEKING;
+		stream->state = seeking_state;
 		unlink_and_block_stream (stream);
+		break;
+
+	default:
+		g_assert_not_reached ();
 	}
 
 	g_object_unref (stream);


Index: rhythmbox.spec
===================================================================
RCS file: /cvs/pkgs/rpms/rhythmbox/F-8/rhythmbox.spec,v
retrieving revision 1.150
retrieving revision 1.151
diff -u -r1.150 -r1.151
--- rhythmbox.spec	20 Dec 2007 03:34:16 -0000	1.150
+++ rhythmbox.spec	7 Jan 2008 10:04:35 -0000	1.151
@@ -3,7 +3,7 @@
 Name: rhythmbox
 Summary: Music Management Application 
 Version: 0.11.3
-Release: 6%{?dist}
+Release: 7%{?dist}
 License: GPLv2+ and GFDL+
 Group: Applications/Multimedia
 URL: http://www.gnome.org/projects/rhythmbox/
@@ -53,6 +53,10 @@
 Patch2: rb-fix-broken-daap-playback.patch
 # http://bugzilla.gnome.org/show_bug.cgi?id=499208
 Patch3: rhythmbox-0.11.3-force-python-thread-init.patch
+# https://bugzilla.redhat.com/show_bug.cgi?id=427612
+# http://bugzilla.gnome.org/show_bug.cgi?id=507450
+# http://svn.gnome.org/viewvc/rhythmbox?view=revision&revision=5455
+Patch4: rhythmbox-0.11.3-xfade-pause-deadlock.patch
 
 %description
 Rhythmbox is an integrated music management application based on the powerful
@@ -86,6 +90,7 @@
 popd
 %patch2 -p0 -b .broken-daap
 %patch3 -p1 -b .python-threading
+%patch4 -p1 -b .xfade-pause-deadlocks
 
 %build
 
@@ -196,6 +201,10 @@
 %{_libdir}/rhythmbox/plugins/upnp_coherence
 
 %changelog
+* Mon Jan 07 2008 - Bastien Nocera <bnocera at redhat.com> - 0.11.3-7
+- Add upstream patch to avoid the cross-fade backend hanging when
+  skipping and paused (#427612)
+
 * Wed Dec 19 2007 Todd Zullinger <tmz at pobox.com> - 0.11.3-6
 - rebuild for libgpod-0.6.0 
 




More information about the fedora-extras-commits mailing list