[banshee/gapless-ng: 11/836] [libbanshee] Explicitly set audiosink's buffer-length This is useful for gapless - it gives more tim



commit b9f04cafe7764673c887be7a49185eff9ce3fdfd
Author: Christopher James Halse Rogers <raof ubuntu com>
Date:   Tue Jun 16 17:39:15 2009 +1000

    [libbanshee] Explicitly set audiosink's buffer-length
    This is useful for gapless - it gives more time to handle the about-to-finish callback

 libbanshee/banshee-player-pipeline.c |   72 ++++++++++++++++++++++++++-------
 libbanshee/banshee-player-private.h  |    3 +
 2 files changed, 59 insertions(+), 16 deletions(-)
---
diff --git a/libbanshee/banshee-player-pipeline.c b/libbanshee/banshee-player-pipeline.c
index d246c92..ca88e20 100644
--- a/libbanshee/banshee-player-pipeline.c
+++ b/libbanshee/banshee-player-pipeline.c
@@ -62,6 +62,38 @@ bp_pipeline_process_tag (const GstTagList *tag_list, const gchar *tag_name, Bans
     }
 }
 
+void bp_try_set_audiosink_buffer (GstElement *element, guint64 *buffer_len)
+{
+    if (g_object_class_find_property (G_OBJECT_GET_CLASS (element), "buffer-time")) {
+        g_object_set (G_OBJECT (element), "buffer-time", *buffer_len, NULL);
+    }
+    gst_object_unref (G_OBJECT (element));
+}
+
+static void
+bp_set_audiosink_buffer_length (BansheePlayer *player, guint64 buffer_len)
+{
+    GstIterator *sink_iterator;
+    GstIteratorResult iter_result;
+    GstElement *audiosink;
+    
+    g_return_if_fail (IS_BANSHEE_PLAYER (player));
+    audiosink = player->audiosink;
+    // If we've directly selected alsasink or directsoundsink then we'll have a
+    // buffer-time property on audiosink.  If so, just set this and return.
+    if (g_object_class_find_property (G_OBJECT_GET_CLASS (audiosink), "buffer-time")) {
+        g_object_set (G_OBJECT (audiosink), "buffer-time", buffer_len, NULL);
+        return;
+    }
+    // If we've selected an auto audio sink, then the real audio sink is a child of the bin.
+    sink_iterator = gst_bin_iterate_recurse (GST_BIN (audiosink));
+    iter_result = gst_iterator_foreach (sink_iterator, (GFunc)&bp_try_set_audiosink_buffer, &buffer_len);
+    if (iter_result == GST_ITERATOR_ERROR) {
+        bp_debug ("Failed to set audio buffer length: failed to find sink");
+    }
+    gst_iterator_free (sink_iterator);
+}
+
 static gboolean
 bp_pipeline_bus_callback (GstBus *bus, GstMessage *message, gpointer userdata)
 {
@@ -81,7 +113,15 @@ bp_pipeline_bus_callback (GstBus *bus, GstMessage *message, gpointer userdata)
         case GST_MESSAGE_STATE_CHANGED: {
             GstState old, new, pending;
             gst_message_parse_state_changed (message, &old, &new, &pending);
-            
+
+            if (new == GST_STATE_READY) {            
+                // Explicitly set the buffer length to a value above the default.
+                // This increases the deadline for setting the URI after about-to-finish is triggered
+                // when using playbin2 for gapless playback.
+                // 
+                // gconfaudiosink only has a real audiosink in it once it's made a transition to READY.
+                bp_set_audiosink_buffer_length (player, BP_BUFFER_LEN_MICROSECONDS);
+            }
             _bp_missing_elements_handle_state_changed (player, old, new);
             _bp_replaygain_handle_state_changed (player, old, new, pending);
             
@@ -194,26 +234,26 @@ _bp_pipeline_construct (BansheePlayer *player)
 
     // Try to find an audio sink, prefer gconf, which typically is set to auto these days,
     // fall back on auto, which should work on windows, and as a last ditch, try alsa
-    audiosink = gst_element_factory_make ("gconfaudiosink", "audiosink");
-    if (audiosink == NULL) {
-        audiosink = gst_element_factory_make ("directsoundsink", "audiosink");
-        if (audiosink != NULL) {
-            g_object_set (G_OBJECT (audiosink), "volume", 1.0, NULL);
+    player->audiosink = gst_element_factory_make ("gconfaudiosink", "audiosink");
+    if (player->audiosink == NULL) {
+        player->audiosink = gst_element_factory_make ("directsoundsink", "audiosink");
+        if (player->audiosink != NULL) {
+            g_object_set (G_OBJECT (player->audiosink), "volume", 1.0, NULL);
         } else {
-            audiosink = gst_element_factory_make ("autoaudiosink", "audiosink");
-            if (audiosink == NULL) {
-                audiosink = gst_element_factory_make ("alsasink", "audiosink");
+            player->audiosink = gst_element_factory_make ("autoaudiosink", "audiosink");
+            if (player->audiosink == NULL) {
+                player->audiosink = gst_element_factory_make ("alsasink", "audiosink");
             }
         }
     }
     
-    g_return_val_if_fail (audiosink != NULL, FALSE);
+    g_return_val_if_fail (player->audiosink != NULL, FALSE);
         
     // Set the profile to "music and movies" (gst-plugins-good 0.10.3)
-    if (g_object_class_find_property (G_OBJECT_GET_CLASS (audiosink), "profile")) {
-        g_object_set (G_OBJECT (audiosink), "profile", 1, NULL);
+    if (g_object_class_find_property (G_OBJECT_GET_CLASS (player->audiosink), "profile")) {
+        g_object_set (G_OBJECT (player->audiosink), "profile", 1, NULL);
     }
-    
+        
     // Create a custom audio sink bin that will hold the real primary sink
     player->audiobin = gst_bin_new ("audiobin");
     g_return_val_if_fail (player->audiobin != NULL, FALSE);
@@ -244,7 +284,7 @@ _bp_pipeline_construct (BansheePlayer *player)
     }
     
     gst_bin_add (GST_BIN (player->audiobin), audiosinkqueue);
-    gst_bin_add (GST_BIN (player->audiobin), audiosink);
+    gst_bin_add (GST_BIN (player->audiobin), player->audiosink);
    
     // Ghost pad the audio bin so audio is passed from the bin into the tee
     teepad = gst_element_get_pad (player->audiotee, "sink");
@@ -255,10 +295,10 @@ _bp_pipeline_construct (BansheePlayer *player)
     if (player->equalizer != NULL) {
         // link in equalizer, preamp and audioconvert.
         gst_element_link_many (audiosinkqueue, eq_audioconvert, player->preamp, 
-            player->equalizer, eq_audioconvert2, audiosink, NULL);
+            player->equalizer, eq_audioconvert2, player->audiosink, NULL);
     } else {
         // link the queue with the real audio sink
-        gst_element_link (audiosinkqueue, audiosink);
+        gst_element_link (audiosinkqueue, player->audiosink);
     }
     
     _bp_vis_pipeline_setup (player);
diff --git a/libbanshee/banshee-player-private.h b/libbanshee/banshee-player-private.h
index 5cbaa40..70b10f0 100644
--- a/libbanshee/banshee-player-private.h
+++ b/libbanshee/banshee-player-private.h
@@ -68,6 +68,8 @@
 #define bp_debug(x...) banshee_log_debug ("player", x)
 #endif
 
+#define BP_BUFFER_LEN_MICROSECONDS 1000000
+
 typedef struct BansheePlayer BansheePlayer;
 
 typedef void (* BansheePlayerEosCallback)          (BansheePlayer *player);
@@ -100,6 +102,7 @@ struct BansheePlayer {
 
     // Pipeline Elements
     GstElement *playbin;
+    GstElement *audiosink;
     GstElement *audiotee;
     GstElement *audiobin;
     GstElement *equalizer;



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