[rhythmbox] playbin: bounce about-to-finish and playing stream events to main thread



commit 256f7eb568dd3c4713c2a3b8e1bafe06270e7e18
Author: Jonathan Matthew <jonathan d14n org>
Date:   Fri Dec 6 09:59:03 2013 +1000

    playbin: bounce about-to-finish and playing stream events to main thread
    
    We need these to happen on the main thread so code dealing with eos
    and playing-stream signals elsewhere can assume it's safe to do things
    that would previously have required taking the gdk lock.
    
    Since playbin only guarantees gapless transitions if the next track is
    set before returning from the about-to-finish handler, use a GCond to
    block until the idle handler has run.

 backends/gstreamer/rb-player-gst.c |   68 +++++++++++++++++++++++++++++-------
 1 files changed, 55 insertions(+), 13 deletions(-)
---
diff --git a/backends/gstreamer/rb-player-gst.c b/backends/gstreamer/rb-player-gst.c
index 326e7b8..1cb7152 100644
--- a/backends/gstreamer/rb-player-gst.c
+++ b/backends/gstreamer/rb-player-gst.c
@@ -120,6 +120,7 @@ struct _RBPlayerGstPrivate
        float cur_volume;
 
        guint tick_timeout_id;
+       guint emit_stream_idle_id;
 
        GList *waiting_tees;
        GstElement *sinkbin;
@@ -127,6 +128,9 @@ struct _RBPlayerGstPrivate
 
        GList *waiting_filters; /* in reverse order */
        GstElement *filterbin;
+
+       GMutex eos_lock;
+       GCond eos_cond;
 };
 
 static void
@@ -149,6 +153,17 @@ _destroy_next_stream_data (RBPlayerGst *player)
        player->priv->next_stream_data_destroy = NULL;
 }
 
+static gboolean
+about_to_finish_idle (RBPlayerGst *player)
+{
+       _rb_player_emit_eos (RB_PLAYER (player), player->priv->stream_data, TRUE);
+
+       g_mutex_lock (&player->priv->eos_lock);
+       g_cond_signal (&player->priv->eos_cond);
+       g_mutex_unlock (&player->priv->eos_lock);
+       return FALSE;
+}
+
 static void
 about_to_finish_cb (GstElement *playbin, RBPlayerGst *player)
 {
@@ -164,10 +179,13 @@ about_to_finish_cb (GstElement *playbin, RBPlayerGst *player)
                return;
        }
 
-       /* emit EOS now and hope we get something to play */
        player->priv->current_track_finishing = TRUE;
 
-       _rb_player_emit_eos (RB_PLAYER (player), player->priv->stream_data, TRUE);
+       g_mutex_lock (&player->priv->eos_lock);
+       g_idle_add_full (G_PRIORITY_HIGH, (GSourceFunc) about_to_finish_idle, player, NULL);
+
+       g_cond_wait (&player->priv->eos_cond, &player->priv->eos_lock);
+       g_mutex_unlock (&player->priv->eos_lock);
 }
 
 static gboolean
@@ -222,20 +240,11 @@ process_tag (const GstTagList *list, const gchar *tag, RBPlayerGst *player)
        }
 }
 
-static void
-emit_playing_stream_and_tags (RBPlayerGst *player, gboolean track_change)
+static gboolean
+actually_emit_stream_and_tags (RBPlayerGst *player)
 {
        GList *t;
 
-       if (track_change) {
-               /* swap stream data */
-               _destroy_stream_data (player);
-               player->priv->stream_data = player->priv->next_stream_data;
-               player->priv->stream_data_destroy = player->priv->next_stream_data_destroy;
-               player->priv->next_stream_data = NULL;
-               player->priv->next_stream_data_destroy = NULL;
-       }
-
        _rb_player_emit_playing_stream (RB_PLAYER (player), player->priv->stream_data);
 
        /* process any tag lists we received while starting the stream */
@@ -249,6 +258,31 @@ emit_playing_stream_and_tags (RBPlayerGst *player, gboolean track_change)
        }
        g_list_free (player->priv->stream_tags);
        player->priv->stream_tags = NULL;
+
+       player->priv->emit_stream_idle_id = 0;
+       return FALSE;
+}
+
+static void
+emit_playing_stream_and_tags (RBPlayerGst *player, gboolean track_change)
+{
+       if (track_change) {
+               /* swap stream data */
+               _destroy_stream_data (player);
+               player->priv->stream_data = player->priv->next_stream_data;
+               player->priv->stream_data_destroy = player->priv->next_stream_data_destroy;
+               player->priv->next_stream_data = NULL;
+               player->priv->next_stream_data_destroy = NULL;
+       }
+
+       if (rb_is_main_thread ()) {
+               if (player->priv->emit_stream_idle_id != 0) {
+                       g_source_remove (player->priv->emit_stream_idle_id);
+               }
+               actually_emit_stream_and_tags (player);
+       } else if (player->priv->emit_stream_idle_id == 0) {
+               player->priv->emit_stream_idle_id = g_idle_add ((GSourceFunc) actually_emit_stream_and_tags, 
player);
+       }
 }
 
 static void
@@ -1065,6 +1099,9 @@ rb_player_gst_init (RBPlayerGst *mp)
        mp->priv = (G_TYPE_INSTANCE_GET_PRIVATE ((mp),
                    RB_TYPE_PLAYER_GST,
                    RBPlayerGstPrivate));
+
+       g_mutex_init (&mp->priv->eos_lock);
+       g_cond_init (&mp->priv->eos_cond);
 }
 
 static void
@@ -1120,6 +1157,11 @@ impl_dispose (GObject *object)
                mp->priv->tick_timeout_id = 0;
        }
 
+       if (mp->priv->emit_stream_idle_id != 0) {
+               g_source_remove (mp->priv->emit_stream_idle_id);
+               mp->priv->emit_stream_idle_id = 0;
+       }
+
        if (mp->priv->playbin != NULL) {
                gst_element_set_state (mp->priv->playbin, GST_STATE_NULL);
                g_object_unref (mp->priv->playbin);


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