banshee r3632 - in trunk/banshee: . libbanshee src/Backends/Banshee.GStreamer/Banshee.GStreamer src/Extensions



Author: abock
Date: Tue Apr  1 00:36:23 2008
New Revision: 3632
URL: http://svn.gnome.org/viewvc/banshee?rev=3632&view=rev

Log:
2008-03-31  Aaron Bockover  <abock gnome org>

    * libbanshee/banshee-player-cdda.c:
    * libbanshee/banshee-player-cdda.h:
    * libbanshee/banshee-player-equalizer.c:
    * libbanshee/banshee-player-missing-elements.c:
    * libbanshee/banshee-player-missing-elements.h:
    * libbanshee/banshee-player-pipeline.c:
    * libbanshee/banshee-player-pipeline.h:
    * libbanshee/banshee-player-private.h:
    * libbanshee/banshee-player-video.h:
    * libbanshee/banshee-player.c:
    * libbanshee/banshee-player.h: Hopefully the last big round of changes
    to the player engine; moved the main pipeline and equalizer code into
    separate modules so banshee-player is basically just the p/invokable
    'public' API and doesn't contain much logic at all
    
    * src/Backends/Banshee.GStreamer/Banshee.GStreamer/PlayerEngine.cs:
    Updated to reflect API changes in libbanshee



Added:
   trunk/banshee/libbanshee/banshee-player-equalizer.c
   trunk/banshee/libbanshee/banshee-player-pipeline.c
   trunk/banshee/libbanshee/banshee-player-pipeline.h
   trunk/banshee/libbanshee/banshee-player-private.h
      - copied, changed from r3627, /trunk/banshee/libbanshee/banshee-player.h
Removed:
   trunk/banshee/libbanshee/banshee-player.h
Modified:
   trunk/banshee/ChangeLog
   trunk/banshee/libbanshee/Makefile.am
   trunk/banshee/libbanshee/banshee-player-cdda.c
   trunk/banshee/libbanshee/banshee-player-cdda.h
   trunk/banshee/libbanshee/banshee-player-missing-elements.c
   trunk/banshee/libbanshee/banshee-player-missing-elements.h
   trunk/banshee/libbanshee/banshee-player-video.h
   trunk/banshee/libbanshee/banshee-player.c
   trunk/banshee/libbanshee/libbanshee.mdp
   trunk/banshee/src/Backends/Banshee.GStreamer/Banshee.GStreamer/PlayerEngine.cs
   trunk/banshee/src/Extensions/Extensions.mds

Modified: trunk/banshee/libbanshee/Makefile.am
==============================================================================
--- trunk/banshee/libbanshee/Makefile.am	(original)
+++ trunk/banshee/libbanshee/Makefile.am	Tue Apr  1 00:36:23 2008
@@ -3,6 +3,7 @@
 	-Wall \
 	-ggdb3 \
 	-D_FORTIFY_SOURCE=2 \
+	-DINSIDE_LIBBANSHEE_I_SWEAR \
 	$(LIBBANSHEE_CFLAGS) \
 	$(GST_CFLAGS) \
 	$(LIBNAUTILUS_BURN_CFLAGS)
@@ -14,16 +15,19 @@
 libbanshee_la_SOURCES =  \
 	banshee-player.c \
 	banshee-player-cdda.c \
+	banshee-player-equalizer.c \
 	banshee-player-missing-elements.c \
+	banshee-player-pipeline.c \
 	banshee-player-video.c \
 	gst-cd-rip-0.10.c \
 	gst-misc-0.10.c \
 	gst-transcode-0.10.c
 
 noinst_HEADERS =  \
-	banshee-player.h \
 	banshee-player-cdda.h \
 	banshee-player-missing-elements.h \
+	banshee-player-pipeline.h \
+	banshee-player-private.h \
 	banshee-player-video.h \
 	gst-cd-rip.h \
 	gst-misc.h \

Modified: trunk/banshee/libbanshee/banshee-player-cdda.c
==============================================================================
--- trunk/banshee/libbanshee/banshee-player-cdda.c	(original)
+++ trunk/banshee/libbanshee/banshee-player-cdda.c	Tue Apr  1 00:36:23 2008
@@ -55,6 +55,36 @@
     return source;
 }
 
+static void
+bp_cdda_on_notify_source (GstElement *playbin, gpointer unknown, BansheePlayer *player)
+{
+    GstElement *cdda_src = NULL;
+    
+    g_return_if_fail (IS_BANSHEE_PLAYER (player));
+    
+    if (player->cdda_device == NULL) {
+        return;
+    }
+    
+    cdda_src = bp_cdda_get_cdda_source (playbin);
+    if (cdda_src == NULL) {
+        return;
+    }
+    
+    // Technically don't need to check the class, since GstCddaBaseSrc elements will always have this
+    if (G_LIKELY (g_object_class_find_property (G_OBJECT_GET_CLASS (cdda_src), "device"))) {
+        bp_debug ("bp_cdda: setting device property on source (%s)", player->cdda_device);
+        g_object_set (cdda_src, "device", player->cdda_device, NULL);
+    }
+    
+    // If the GstCddaBaseSrc is cdparanoia, it will have this property, so set it
+    if (g_object_class_find_property (G_OBJECT_GET_CLASS (cdda_src), "paranoia-mode")) {
+        g_object_set (cdda_src, "paranoia-mode", 0, NULL);
+    }
+    
+    g_object_unref (cdda_src);
+}
+
 static gboolean
 bp_cdda_source_seek_to_track (GstElement *playbin, guint track)
 {
@@ -96,33 +126,11 @@
 // ---------------------------------------------------------------------------
 
 void
-_bp_cdda_on_notify_source (GstElement *playbin, gpointer unknown, BansheePlayer *player)
+_bp_cdda_pipeline_setup (BansheePlayer *player)
 {
-    GstElement *cdda_src = NULL;
-    
-    g_return_if_fail (IS_BANSHEE_PLAYER (player));
-    
-    if (player->cdda_device == NULL) {
-        return;
-    }
-    
-    cdda_src = bp_cdda_get_cdda_source (playbin);
-    if (cdda_src == NULL) {
-        return;
+    if (player != NULL && player->playbin != NULL) {
+        g_signal_connect (player->playbin, "notify::source", G_CALLBACK (bp_cdda_on_notify_source), player);
     }
-    
-    // Technically don't need to check the class, since GstCddaBaseSrc elements will always have this
-    if (G_LIKELY (g_object_class_find_property (G_OBJECT_GET_CLASS (cdda_src), "device"))) {
-        bp_debug ("bp_cdda: setting device property on source (%s)", player->cdda_device);
-        g_object_set (cdda_src, "device", player->cdda_device, NULL);
-    }
-    
-    // If the GstCddaBaseSrc is cdparanoia, it will have this property, so set it
-    if (g_object_class_find_property (G_OBJECT_GET_CLASS (cdda_src), "paranoia-mode")) {
-        g_object_set (cdda_src, "paranoia-mode", 0, NULL);
-    }
-    
-    g_object_unref (cdda_src);
 }
 
 gboolean

Modified: trunk/banshee/libbanshee/banshee-player-cdda.h
==============================================================================
--- trunk/banshee/libbanshee/banshee-player-cdda.h	(original)
+++ trunk/banshee/libbanshee/banshee-player-cdda.h	Tue Apr  1 00:36:23 2008
@@ -29,9 +29,9 @@
 #ifndef _BANSHEE_PLAYER_CDDA_H
 #define _BANSHEE_PLAYER_CDDA_H
 
-#include "banshee-player.h"
+#include "banshee-player-private.h"
 
-void      _bp_cdda_on_notify_source  (GstElement *playbin, gpointer unknown, BansheePlayer *player);
+void      _bp_cdda_pipeline_setup    (BansheePlayer *player);
 gboolean  _bp_cdda_handle_uri        (BansheePlayer *player, const gchar *uri);
 
 #endif /* _BANSHEE_PLAYER_CDDA_H */

Added: trunk/banshee/libbanshee/banshee-player-equalizer.c
==============================================================================
--- (empty file)
+++ trunk/banshee/libbanshee/banshee-player-equalizer.c	Tue Apr  1 00:36:23 2008
@@ -0,0 +1,123 @@
+//
+// banshee-player-equalizer.c
+//
+// Authors:
+//   Alexander Hixon <hixon alexander mediati org>
+//   Aaron Bockover <abockover novell com>
+//
+// Copyright (C) 2005-2008 Novell, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+#include "banshee-player-private.h"
+
+// ---------------------------------------------------------------------------
+// Public Functions
+// ---------------------------------------------------------------------------
+
+P_INVOKE gboolean
+bp_equalizer_is_supported (BansheePlayer *player)
+{
+    return player != NULL && player->equalizer != NULL && player->preamp != NULL;
+}
+
+P_INVOKE void
+bp_equalizer_set_preamp_level (BansheePlayer *player, gdouble level)
+{
+    g_return_if_fail (IS_BANSHEE_PLAYER (player));
+
+    if (player->equalizer != NULL && player->preamp != NULL) {
+        g_object_set (player->preamp, "volume", level, NULL);
+    }
+}
+
+P_INVOKE void
+bp_equalizer_set_gain (BansheePlayer *player, guint bandnum, gdouble gain)
+{
+    g_return_if_fail (IS_BANSHEE_PLAYER (player));
+    
+    if (player->equalizer != NULL) {
+        GstObject *band = gst_child_proxy_get_child_by_index (GST_CHILD_PROXY (player->equalizer), bandnum);
+        g_object_set (band, "gain", gain, NULL);
+        g_object_unref (band);
+    }
+}
+
+P_INVOKE void
+bp_equalizer_get_bandrange (BansheePlayer *player, gint *min, gint *max)
+{    
+    // NOTE: This only refers to the newer version of the equalizer element.
+    //
+    // GStreamer's equalizer goes from -24 to +12, but -12 to +12 is much better:
+    //  - Equal levels on both sides, which means we get a nice linear y=x
+    //  - This also makes converting other eq presets easier.
+    //  - We get a nice roud 0 dB in the middle of the band range, instead of -6, which is stupid
+    //    since 0 dB gives us no gain, yet its not in the middle - less sense to the end user.
+    
+    GParamSpecDouble *pspec;
+    
+    g_return_if_fail (IS_BANSHEE_PLAYER (player));
+    
+    if (player->equalizer == NULL) {
+        return;
+    }
+    
+    // Fetch gain range of first band (since it should be the same for the rest)
+    pspec = (GParamSpecDouble*)g_object_class_find_property (G_OBJECT_GET_CLASS (player->equalizer), "band0");
+    if (pspec != NULL) {
+        // Assume old equalizer.
+        *min = pspec->minimum;
+        *max = pspec->maximum;
+        return;
+    } 
+    
+    pspec = (GParamSpecDouble*)g_object_class_find_property (G_OBJECT_GET_CLASS (player->equalizer), "band0::gain");
+    if (pspec != NULL && pspec->maximum == 12) {
+        // New equalizer - return even scale.
+        *min = -12;
+        *max = 12;
+    } else if (pspec != NULL) {
+        // Return just the ranges the equalizer supports
+        *min = pspec->minimum;
+        *max = pspec->maximum;
+    } else {
+       g_warning ("Could not find valid gain range for equalizer element");
+    }
+}
+
+P_INVOKE void
+bp_equalizer_get_frequencies (BansheePlayer *player, gdouble **freq)
+{
+    gint i;
+    gdouble bandfreq[10];
+    
+    g_return_if_fail (IS_BANSHEE_PLAYER (player));
+    
+    for (i = 0; i < 10; i++) {
+        GstObject *band;
+        
+        band = gst_child_proxy_get_child_by_index (GST_CHILD_PROXY (player->equalizer), i);
+        g_object_get (G_OBJECT (band), "freq", &bandfreq[i], NULL);
+        g_object_unref (band);
+    }
+    
+    *freq = bandfreq;
+}

Modified: trunk/banshee/libbanshee/banshee-player-missing-elements.c
==============================================================================
--- trunk/banshee/libbanshee/banshee-player-missing-elements.c	(original)
+++ trunk/banshee/libbanshee/banshee-player-missing-elements.c	Tue Apr  1 00:36:23 2008
@@ -51,6 +51,10 @@
 {   
     GSList *node = list;
     
+    if (node == NULL) {
+        return;
+    }
+    
     for (; node != NULL; node = node->next) {
         g_free (node->data);
     }

Modified: trunk/banshee/libbanshee/banshee-player-missing-elements.h
==============================================================================
--- trunk/banshee/libbanshee/banshee-player-missing-elements.h	(original)
+++ trunk/banshee/libbanshee/banshee-player-missing-elements.h	Tue Apr  1 00:36:23 2008
@@ -29,7 +29,7 @@
 #ifndef _BANSHEE_PLAYER_MISSING_ELEMENTS_H
 #define _BANSHEE_PLAYER_MISSING_ELEMENTS_H
 
-#include "banshee-player.h"
+#include "banshee-player-private.h"
 
 void  _bp_missing_elements_destroy               (BansheePlayer *player);
 void  _bp_missing_elements_process_message       (BansheePlayer *player, GstMessage *message);

Added: trunk/banshee/libbanshee/banshee-player-pipeline.c
==============================================================================
--- (empty file)
+++ trunk/banshee/libbanshee/banshee-player-pipeline.c	Tue Apr  1 00:36:23 2008
@@ -0,0 +1,281 @@
+//
+// banshee-player-pipeline.c
+//
+// Author:
+//   Aaron Bockover <abockover novell com>
+//
+// Copyright (C) 2005-2008 Novell, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+#include "banshee-player-pipeline.h"
+#include "banshee-player-cdda.h"
+#include "banshee-player-video.h"
+#include "banshee-player-missing-elements.h"
+
+// ---------------------------------------------------------------------------
+// Private Functions
+// ---------------------------------------------------------------------------
+
+static void
+bp_pipeline_process_tag (const GstTagList *tag_list, const gchar *tag_name, BansheePlayer *player)
+{
+    const GValue *value;
+    gint value_count;
+    
+    g_return_if_fail (IS_BANSHEE_PLAYER (player));
+
+    value_count = gst_tag_list_get_tag_size (tag_list, tag_name);
+    if (value_count < 1) {
+        return;
+    }
+    
+    value = gst_tag_list_get_value_index (tag_list, tag_name, 0);
+
+    if (value != NULL && player->tag_found_cb != NULL) {
+        player->tag_found_cb (player, tag_name, value);
+    }
+}
+
+static gboolean
+bp_pipeline_bus_callback (GstBus *bus, GstMessage *message, gpointer userdata)
+{
+    BansheePlayer *player = (BansheePlayer *)userdata;
+
+    g_return_val_if_fail (IS_BANSHEE_PLAYER (player), FALSE);
+    g_return_val_if_fail (message != NULL, FALSE);
+
+    switch (GST_MESSAGE_TYPE (message)) {
+        case GST_MESSAGE_EOS: {
+            if (player->eos_cb != NULL) {
+                player->eos_cb (player);
+            }
+            break;
+        }
+            
+        case GST_MESSAGE_STATE_CHANGED: {
+            GstState old, new, pending;
+            gst_message_parse_state_changed (message, &old, &new, &pending);
+            
+            _bp_missing_elements_handle_state_changed (player, old, new);
+            
+            if (player->state_changed_cb != NULL) {
+                player->state_changed_cb (player, old, new, pending);
+            }
+            break;
+        }
+        
+        case GST_MESSAGE_BUFFERING: {
+            const GstStructure *buffering_struct;
+            gint buffering_progress = 0;
+            
+            buffering_struct = gst_message_get_structure (message);
+            if (!gst_structure_get_int (buffering_struct, "buffer-percent", &buffering_progress)) {
+                g_warning ("Could not get completion percentage from BUFFERING message");
+                break;
+            }
+            
+            if (buffering_progress >= 100) {
+                player->buffering = FALSE;
+                if (player->target_state == GST_STATE_PLAYING) {
+                    gst_element_set_state (player->playbin, GST_STATE_PLAYING);
+                }
+            } else if (!player->buffering && player->target_state == GST_STATE_PLAYING) {
+                GstState current_state;
+                gst_element_get_state (player->playbin, &current_state, NULL, 0);
+                if (current_state == GST_STATE_PLAYING) {
+                    gst_element_set_state (player->playbin, GST_STATE_PAUSED);
+                }
+                player->buffering = TRUE;
+            } 
+
+            if (player->buffering_cb != NULL) {
+                player->buffering_cb (player, buffering_progress);
+            }
+            break;
+        }
+        
+        case GST_MESSAGE_TAG: {
+            GstTagList *tags;
+            
+            if (GST_MESSAGE_TYPE (message) != GST_MESSAGE_TAG) {
+                break;
+            }
+            
+            gst_message_parse_tag (message, &tags);
+            
+            if (GST_IS_TAG_LIST (tags)) {
+                gst_tag_list_foreach (tags, (GstTagForeachFunc)bp_pipeline_process_tag, player);
+                gst_tag_list_free (tags);
+            }
+            break;
+        }
+    
+        case GST_MESSAGE_ERROR: {
+            GError *error;
+            gchar *debug;
+            
+            // FIXME: This is to work around a bug in qtdemux in
+            // -good <= 0.10.6
+            if (message->src != NULL && message->src->name != NULL && 
+                strncmp (message->src->name, "qtdemux", 7) == 0) {
+                break;
+            }
+            
+            _bp_pipeline_destroy (player);
+            
+            if (player->error_cb != NULL) {
+                gst_message_parse_error (message, &error, &debug);
+                player->error_cb (player, error->domain, error->code, error->message, debug);
+                g_error_free (error);
+                g_free (debug);
+            }
+            
+            break;
+        } 
+        
+        case GST_MESSAGE_ELEMENT: {
+            _bp_missing_elements_process_message (player, message);
+            break;
+        }
+        
+        default: break;
+    }
+    
+    return TRUE;
+}
+
+// ---------------------------------------------------------------------------
+// Internal Functions
+// ---------------------------------------------------------------------------
+
+gboolean 
+_bp_pipeline_construct (BansheePlayer *player)
+{
+    GstBus *bus;
+    GstPad *teepad;
+    GstElement *audiosink;
+    GstElement *audiosinkqueue;
+    // GstElement *audioconvert;
+    
+    g_return_val_if_fail (IS_BANSHEE_PLAYER (player), FALSE);
+    
+    // Playbin is the core element that handles autoplugging (finding the right
+    // source and decoder elements) based on source URI and stream content
+    player->playbin = gst_element_factory_make ("playbin", "playbin");
+    g_return_val_if_fail (player->playbin != NULL, FALSE);
+
+    // 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 ("autoaudiosink", "audiosink");
+        if (audiosink == NULL) {
+            audiosink = gst_element_factory_make ("alsasink", "audiosink");
+        }
+    }
+    
+    g_return_val_if_fail (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);
+    }
+    
+    // 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);
+    
+    // Our audio sink is a tee, so plugins can attach their own pipelines
+    player->audiotee = gst_element_factory_make ("tee", "audiotee");
+    g_return_val_if_fail (player->audiotee != NULL, FALSE);
+    
+    audiosinkqueue = gst_element_factory_make ("queue", "audiosinkqueue");
+    g_return_val_if_fail (audiosinkqueue != NULL, FALSE);
+    
+    // FIXME: Make the equalizer work properly
+    // audioconvert = gst_element_factory_make("audioconvert", "audioconvert");
+    // player->equalizer = gst_element_factory_make("equalizer-10bands", "equalizer-10bands");
+    // player->preamp = gst_element_factory_make("volume", "preamp");
+    
+    // Add elements to custom audio sink
+    gst_bin_add (GST_BIN (player->audiobin), player->audiotee);
+    // FIXME: Make the equalizer work properly
+    //if (player->equalizer != NULL) {
+    //    gst_bin_add (GST_BIN (player->audiobin), audioconvert);
+    //    gst_bin_add (GST_BIN (player->audiobin), player->equalizer);
+    //    gst_bin_add (GST_BIN (player->audiobin), player->preamp);
+    //}
+    gst_bin_add (GST_BIN (player->audiobin), audiosinkqueue);
+    gst_bin_add (GST_BIN (player->audiobin), audiosink);
+   
+    // Ghost pad the audio bin so audio is passed from the bin into the tee
+    teepad = gst_element_get_pad (player->audiotee, "sink");
+    gst_element_add_pad (player->audiobin, gst_ghost_pad_new ("sink", teepad));
+    gst_object_unref (teepad);
+
+    // Link the first tee pad to the primary audio sink queue
+    gst_pad_link (gst_element_get_request_pad (player->audiotee, "src0"), 
+        gst_element_get_pad (audiosinkqueue, "sink"));
+
+    // Link the queue and the actual audio sink
+    // FIXME: Make the equalizer work properly
+    // if (player->equalizer != NULL) {
+    //     // link in equalizer, preamp and audioconvert.
+    //     gst_element_link_many (audiosinkqueue, player->preamp, player->equalizer, audioconvert, audiosink)
+    // } else {
+    //     // link the queue with the real audio sink
+    //     gst_element_link (audiosinkqueue, audiosink);
+    // }
+    
+    gst_element_link (audiosinkqueue, audiosink);
+    
+    // Now that our internal audio sink is constructed, tell playbin to use it
+    g_object_set (G_OBJECT (player->playbin), "audio-sink", player->audiobin, NULL);
+    
+    // Connect to the bus to get messages
+    bus = gst_pipeline_get_bus (GST_PIPELINE (player->playbin));    
+    gst_bus_add_watch (bus, bp_pipeline_bus_callback, player);
+    
+    // Now allow specialized pipeline setups
+    _bp_cdda_pipeline_setup (player);
+    _bp_video_pipeline_setup (player, bus);
+
+    return TRUE;
+}
+
+void
+_bp_pipeline_destroy (BansheePlayer *player)
+{
+    g_return_if_fail (IS_BANSHEE_PLAYER (player));
+    
+    if (player->playbin == NULL) {
+        return;
+    }
+    
+    if (GST_IS_ELEMENT (player->playbin)) {
+        player->target_state = GST_STATE_NULL;
+        gst_element_set_state (player->playbin, GST_STATE_NULL);
+        gst_object_unref (GST_OBJECT(player->playbin));
+    }
+    
+    player->playbin = NULL;
+}

Added: trunk/banshee/libbanshee/banshee-player-pipeline.h
==============================================================================
--- (empty file)
+++ trunk/banshee/libbanshee/banshee-player-pipeline.h	Tue Apr  1 00:36:23 2008
@@ -0,0 +1,37 @@
+//
+// banshee-player-pipeline.h
+//
+// Author:
+//   Aaron Bockover <abockover novell com>
+//
+// Copyright (C) 2005-2008 Novell, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+#ifndef _BANSHEE_PLAYER_PIPELINE_H
+#define _BANSHEE_PLAYER_PIPELINE_H
+
+#include "banshee-player-private.h"
+
+gboolean  _bp_pipeline_construct (BansheePlayer *player);
+void      _bp_pipeline_destroy   (BansheePlayer *player);
+
+#endif /* _BANSHEE_PLAYER_PIPELINE_H */

Copied: trunk/banshee/libbanshee/banshee-player-private.h (from r3627, /trunk/banshee/libbanshee/banshee-player.h)
==============================================================================
--- /trunk/banshee/libbanshee/banshee-player.h	(original)
+++ trunk/banshee/libbanshee/banshee-player-private.h	Tue Apr  1 00:36:23 2008
@@ -1,5 +1,37 @@
-#ifndef _BANSHEE_PLAYER_H
-#define _BANSHEE_PLAYER_H
+//
+// banshee-player-private.h
+//
+// Author:
+//   Aaron Bockover <abockover novell com>
+//
+// Copyright (C) 2005-2008 Novell, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+#ifndef _BANSHEE_PLAYER_PRIVATE_H
+#define _BANSHEE_PLAYER_PRIVATE_H
+
+#ifndef INSIDE_LIBBANSHEE_I_SWEAR
+#error libbanshee is not a stable API and is not meant to be used by third party applications
+#endif
 
 #ifdef HAVE_CONFIG_H
 #  include "config.h"
@@ -74,4 +106,4 @@
     #endif
 };
 
-#endif /* _BANSHEE_PLAYER_H */
+#endif /* _BANSHEE_PLAYER_PRIVATE_H */

Modified: trunk/banshee/libbanshee/banshee-player-video.h
==============================================================================
--- trunk/banshee/libbanshee/banshee-player-video.h	(original)
+++ trunk/banshee/libbanshee/banshee-player-video.h	Tue Apr  1 00:36:23 2008
@@ -29,7 +29,7 @@
 #ifndef _BANSHEE_PLAYER_VIDEO_H
 #define _BANSHEE_PLAYER_VIDEO_H
 
-#include "banshee-player.h"
+#include "banshee-player-private.h"
 
 void  _bp_video_pipeline_setup  (BansheePlayer *player, GstBus *bus);
 

Modified: trunk/banshee/libbanshee/banshee-player.c
==============================================================================
--- trunk/banshee/libbanshee/banshee-player.c	(original)
+++ trunk/banshee/libbanshee/banshee-player.c	Tue Apr  1 00:36:23 2008
@@ -1,329 +1,111 @@
-/***************************************************************************
- *  gst-playback-0.10.c
- *
- *  Copyright (C) 2005-2007 Novell, Inc.
- *  Written by Aaron Bockover <aaron abock org>
- *  Contributions by Alexander Hixon <hixon alexander mediati org>
- ****************************************************************************/
-
-/*  THIS FILE IS LICENSED UNDER THE MIT LICENSE AS OUTLINED IMMEDIATELY BELOW: 
- *
- *  Permission is hereby granted, free of charge, to any person obtaining a
- *  copy of this software and associated documentation files (the "Software"),  
- *  to deal in the Software without restriction, including without limitation  
- *  the rights to use, copy, modify, merge, publish, distribute, sublicense,  
- *  and/or sell copies of the Software, and to permit persons to whom the  
- *  Software is furnished to do so, subject to the following conditions:
- *
- *  The above copyright notice and this permission notice shall be included in 
- *  all copies or substantial portions of the Software.
- *
- *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
- *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
- *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
- *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
- *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
- *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
- *  DEALINGS IN THE SOFTWARE.
- */
+//
+// banshee-player.c
+//
+// Author:
+//   Aaron Bockover <abockover novell com>
+//
+// Copyright (C) 2005-2008 Novell, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
 
-#include "banshee-player.h"
+#include "banshee-player-private.h"
+#include "banshee-player-pipeline.h"
 #include "banshee-player-cdda.h"
-#include "banshee-player-video.h"
 #include "banshee-player-missing-elements.h"
 
-static void
-bp_process_tag(const GstTagList *tag_list, const gchar *tag_name, BansheePlayer *player)
-{
-    const GValue *value;
-    gint value_count;
-
-    value_count = gst_tag_list_get_tag_size(tag_list, tag_name);
-    if(value_count < 1) {
-        return;
-    }
-    
-    value = gst_tag_list_get_value_index(tag_list, tag_name, 0);
-
-    if(player != NULL && player->tag_found_cb != NULL) {
-        player->tag_found_cb(player, tag_name, value);
-    }
-}
-
-static void
-bp_destroy_pipeline(BansheePlayer *player)
-{
-    g_return_if_fail(IS_BANSHEE_PLAYER(player));
-    
-    if(player->playbin == NULL) {
-        return;
-    }
-    
-    if(GST_IS_ELEMENT(player->playbin)) {
-        player->target_state = GST_STATE_NULL;
-        gst_element_set_state(player->playbin, GST_STATE_NULL);
-        gst_object_unref(GST_OBJECT(player->playbin));
-    }
-    
-    player->playbin = NULL;
-}
-
-static gboolean
-bp_bus_callback(GstBus *bus, GstMessage *message, gpointer data)
-{
-    BansheePlayer *player = (BansheePlayer *)data;
-
-    g_return_val_if_fail(IS_BANSHEE_PLAYER(player), FALSE);
-
-    switch(GST_MESSAGE_TYPE(message)) {
-        case GST_MESSAGE_ERROR: {
-            GError *error;
-            gchar *debug;
-            
-            // FIXME: This is to work around a bug in qtdemux in
-            // -good <= 0.10.6
-            if(message->src != NULL && message->src->name != NULL &&
-                strncmp(message->src->name, "qtdemux", 0) == 0) {
-                break;
-            }
-            
-            bp_destroy_pipeline(player);
-            
-            if(player->error_cb != NULL) {
-                gst_message_parse_error(message, &error, &debug);
-                player->error_cb(player, error->domain, error->code, error->message, debug);
-                g_error_free(error);
-                g_free(debug);
-            }
-            
-            break;
-        } 
-        
-        case GST_MESSAGE_ELEMENT: {
-            _bp_missing_elements_process_message (player, message);
-            break;
-        }
-        
-        case GST_MESSAGE_EOS: {
-            if(player->eos_cb != NULL) {
-                player->eos_cb(player);
-            }
-            break;
-        }
-            
-        case GST_MESSAGE_STATE_CHANGED: {
-            GstState old, new, pending;
-            gst_message_parse_state_changed (message, &old, &new, &pending);
-            
-            _bp_missing_elements_handle_state_changed (player, old, new);
-            
-            if (player->state_changed_cb != NULL) {
-                player->state_changed_cb (player, old, new, pending);
-            }
-            break;
-        }
-        
-        case GST_MESSAGE_BUFFERING: {
-            const GstStructure *buffering_struct;
-            gint buffering_progress = 0;
-            
-            buffering_struct = gst_message_get_structure(message);
-            if(!gst_structure_get_int(buffering_struct, "buffer-percent", &buffering_progress)) {
-                g_warning("Could not get completion percentage from BUFFERING message");
-                break;
-            }
-            
-            if(buffering_progress >= 100) {
-                player->buffering = FALSE;
-                if(player->target_state == GST_STATE_PLAYING) {
-                    gst_element_set_state(player->playbin, GST_STATE_PLAYING);
-                }
-            } else if(!player->buffering && player->target_state == GST_STATE_PLAYING) {
-                GstState current_state;
-                gst_element_get_state(player->playbin, &current_state, NULL, 0);
-                if(current_state == GST_STATE_PLAYING) {
-                    gst_element_set_state(player->playbin, GST_STATE_PAUSED);
-                }
-                player->buffering = TRUE;
-            } 
-
-            if(player->buffering_cb != NULL) {
-                player->buffering_cb(player, buffering_progress);
-            }
-        }
-        case GST_MESSAGE_TAG: {
-            GstTagList *tags;
-            
-            if(GST_MESSAGE_TYPE(message) != GST_MESSAGE_TAG) {
-                break;
-            }
-            
-            gst_message_parse_tag(message, &tags);
-            
-            if(GST_IS_TAG_LIST(tags)) {
-                gst_tag_list_foreach(tags, (GstTagForeachFunc)bp_process_tag, player);
-                gst_tag_list_free(tags);
-            }
-            break;
-        }
-        default:
-            break;
-    }
-    
-    return TRUE;
-}
-
-static gboolean 
-bp_construct(BansheePlayer *player)
-{
-    GstBus *bus;
-    GstElement *audiosink;
-    GstElement *audiosinkqueue;
-    //GstElement *audioconvert;
-    GstPad *teepad;
-    
-    g_return_val_if_fail(IS_BANSHEE_PLAYER(player), FALSE);
-    
-    // create necessary elements
-    player->playbin = gst_element_factory_make("playbin", "playbin");
-    g_return_val_if_fail(player->playbin != NULL, FALSE);
-
-    audiosink = gst_element_factory_make("gconfaudiosink", "audiosink");
-    g_return_val_if_fail(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);
-    }
-    
-    player->audiobin = gst_bin_new("audiobin");
-    g_return_val_if_fail(player->audiobin != NULL, FALSE);
-    
-    player->audiotee = gst_element_factory_make("tee", "audiotee");
-    g_return_val_if_fail(player->audiotee != NULL, FALSE);
-    
-    audiosinkqueue = gst_element_factory_make("queue", "audiosinkqueue");
-    g_return_val_if_fail(audiosinkqueue != NULL, FALSE);
-    
-    //audioconvert = gst_element_factory_make("audioconvert", "audioconvert");
-    //player->equalizer = gst_element_factory_make("equalizer-10bands", "equalizer-10bands");
-    //player->preamp = gst_element_factory_make("volume", "preamp");
-    
-    // add elements to custom audio sink
-    gst_bin_add(GST_BIN(player->audiobin), player->audiotee);
-    //if(player->equalizer != NULL) {
-    //    gst_bin_add(GST_BIN(player->audiobin), audioconvert);
-    //    gst_bin_add(GST_BIN(player->audiobin), player->equalizer);
-    //    gst_bin_add(GST_BIN(player->audiobin), player->preamp);
-    //}
-    gst_bin_add(GST_BIN(player->audiobin), audiosinkqueue);
-    gst_bin_add(GST_BIN(player->audiobin), audiosink);
-   
-    // ghost pad the audio bin
-    teepad = gst_element_get_pad(player->audiotee, "sink");
-    gst_element_add_pad(player->audiobin, gst_ghost_pad_new("sink", teepad));
-    gst_object_unref(teepad);
-
-    // link the tee/queue pads for the default
-    gst_pad_link(gst_element_get_request_pad(player->audiotee, "src0"), 
-        gst_element_get_pad(audiosinkqueue, "sink"));
-
-    //if (player->equalizer != NULL)
-    //{
-    //    //link in equalizer, preamp and audioconvert.
-    //    gst_element_link(audiosinkqueue, player->preamp);
-    //    gst_element_link(player->preamp, player->equalizer);
-    //    gst_element_link(player->equalizer, audioconvert);
-    //    gst_element_link(audioconvert, audiosink);
-    //} else {
-    //    // link the queue with the real audio sink
-        gst_element_link(audiosinkqueue, audiosink);
-    //}
-    
-    g_object_set (G_OBJECT (player->playbin), "audio-sink", player->audiobin, NULL);
-    
-    bus = gst_pipeline_get_bus (GST_PIPELINE (player->playbin));    
-    gst_bus_add_watch (bus, bp_bus_callback, player);
-    
-    g_signal_connect (player->playbin, "notify::source", G_CALLBACK (_bp_cdda_on_notify_source), player);
-
-    _bp_video_pipeline_setup (player, bus);
-
-    return TRUE;
-}
+// ---------------------------------------------------------------------------
+// Private Functions
+// ---------------------------------------------------------------------------
 
 static gboolean
-bp_iterate_timeout(BansheePlayer *player)
+bp_iterate_timeout_handler (BansheePlayer *player)
 {
-    g_return_val_if_fail(IS_BANSHEE_PLAYER(player), FALSE);
+    g_return_val_if_fail (IS_BANSHEE_PLAYER (player), FALSE);
     
     if(player->iterate_cb != NULL) {
-        player->iterate_cb(player);
+        player->iterate_cb (player);
     }
     
     return TRUE;
 }
 
 static void
-bp_start_iterate_timeout(BansheePlayer *player)
+bp_iterate_timeout_start (BansheePlayer *player)
 {
-    g_return_if_fail(IS_BANSHEE_PLAYER(player));
+    g_return_if_fail (IS_BANSHEE_PLAYER(player));
 
-    if(player->iterate_timeout_id != 0) {
-        return;
+    if (player->iterate_timeout_id == 0) {
+        player->iterate_timeout_id = g_timeout_add (200, 
+            (GSourceFunc)bp_iterate_timeout_handler, player);
     }
-    
-    player->iterate_timeout_id = g_timeout_add(200, 
-        (GSourceFunc)bp_iterate_timeout, player);
 }
 
 static void
-bp_stop_iterate_timeout(BansheePlayer *player)
+bp_iterate_timeout_stop (BansheePlayer *player)
 {
-    g_return_if_fail(IS_BANSHEE_PLAYER(player));
+    g_return_if_fail (IS_BANSHEE_PLAYER (player));
     
-    if(player->iterate_timeout_id == 0) {
-        return;
+    if (player->iterate_timeout_id != 0) {
+        g_source_remove (player->iterate_timeout_id);
+        player->iterate_timeout_id = 0;
     }
-    
-    g_source_remove(player->iterate_timeout_id);
-    player->iterate_timeout_id = 0;
 }
 
-// public methods
-
-BansheePlayer *
-bp_new()
+static void
+bp_pipeline_set_state (BansheePlayer *player, GstState state)
 {
-    BansheePlayer *player = g_new0(BansheePlayer, 1);
+    g_return_if_fail (IS_BANSHEE_PLAYER (player));
     
-    player->mutex = g_mutex_new ();
+    if (state == GST_STATE_NULL || state == GST_STATE_PAUSED) {
+        bp_iterate_timeout_stop (player);
+    }
     
-    if(!bp_construct(player)) {
-        g_free(player);
-        return NULL;
+    if (GST_IS_ELEMENT (player->playbin)) {
+        player->target_state = state;
+        gst_element_set_state (player->playbin, state);
     }
     
-    return player;
+    if (state == GST_STATE_PLAYING) {
+        bp_iterate_timeout_start (player);
+    }
 }
 
-void
-bp_free (BansheePlayer *player)
+// ---------------------------------------------------------------------------
+// Public Functions
+// ---------------------------------------------------------------------------
+
+P_INVOKE void
+bp_destroy (BansheePlayer *player)
 {
     g_return_if_fail (IS_BANSHEE_PLAYER (player));
     
-    g_mutex_free (player->mutex);
-    
-    if (GST_IS_OBJECT (player->playbin)) {
-        player->target_state = GST_STATE_NULL;
-        gst_element_set_state (player->playbin, GST_STATE_NULL);
-        gst_object_unref (GST_OBJECT (player->playbin));
+    if (player->mutex != NULL) {
+        g_mutex_free (player->mutex);
     }
     
     if (player->cdda_device != NULL) {
         g_free (player->cdda_device);
     }
     
+    _bp_pipeline_destroy (player);
     _bp_missing_elements_destroy (player);
     
     memset (player, 0, sizeof (BansheePlayer));
@@ -334,192 +116,161 @@
     bp_debug ("bp: disposed player");
 }
 
-void
-bp_set_eos_callback(BansheePlayer *player, 
-    BansheePlayerEosCallback cb)
-{
-    SET_CALLBACK(eos_cb);
-}
-
-void
-bp_set_error_callback(BansheePlayer *player, 
-    BansheePlayerErrorCallback cb)
+P_INVOKE BansheePlayer *
+bp_new ()
 {
-    SET_CALLBACK(error_cb);
-}
-
-void
-bp_set_state_changed_callback(BansheePlayer *player, 
-    BansheePlayerStateChangedCallback cb)
-{
-    SET_CALLBACK(state_changed_cb);
-}
-
-void
-bp_set_iterate_callback(BansheePlayer *player, 
-    BansheePlayerIterateCallback cb)
-{
-    SET_CALLBACK(iterate_cb);
-}
-
-void
-bp_set_buffering_callback(BansheePlayer *player, 
-    BansheePlayerBufferingCallback cb)
-{
-    SET_CALLBACK(buffering_cb);
-}
-
-void
-bp_set_tag_found_callback(BansheePlayer *player, 
-    BansheePlayerTagFoundCallback cb)
-{
-    SET_CALLBACK(tag_found_cb);
+    BansheePlayer *player = g_new0 (BansheePlayer, 1);
+    
+    player->mutex = g_mutex_new ();
+    
+    if (!_bp_pipeline_construct (player)) {
+        bp_destroy (player);
+        return NULL;
+    }
+    
+    return player;
 }
 
-void
-bp_open(BansheePlayer *player, const gchar *uri)
+P_INVOKE gboolean
+bp_open (BansheePlayer *player, const gchar *uri)
 {
     GstState state;
     
-    g_return_if_fail(IS_BANSHEE_PLAYER(player));
+    g_return_val_if_fail (IS_BANSHEE_PLAYER (player), FALSE);
     
-    if(player->playbin == NULL && !bp_construct(player)) {
-        return;
+    // Build the pipeline if we need to
+    if (player->playbin == NULL && !_bp_pipeline_construct (player)) {
+        return FALSE;
     }
 
+    // Give the CDDA code a chance to intercept the open request
+    // in case it is able to perform a fast seek to a track
     if (_bp_cdda_handle_uri (player, uri)) {
-        return;
+        return TRUE;
     }
     
-    gst_element_get_state(player->playbin, &state, NULL, 0);
-    if(state >= GST_STATE_PAUSED) {
+    // Set the pipeline to the proper state
+    gst_element_get_state (player->playbin, &state, NULL, 0);
+    if (state >= GST_STATE_PAUSED) {
         player->target_state = GST_STATE_READY;
-        gst_element_set_state(player->playbin, GST_STATE_READY);
+        gst_element_set_state (player->playbin, GST_STATE_READY);
     }
     
-    g_object_set(G_OBJECT(player->playbin), "uri", uri, NULL);
-}
-
-void
-bp_stop(BansheePlayer *player, gboolean nullstate)
-{
-    GstState state = nullstate ? GST_STATE_NULL : GST_STATE_PAUSED;
-    g_return_if_fail(IS_BANSHEE_PLAYER(player));
-    bp_stop_iterate_timeout(player);
-    if(GST_IS_ELEMENT(player->playbin)) {
-        player->target_state = state;
-        gst_element_set_state(player->playbin, state);
-    }
+    // Pass the request off to playbin
+    g_object_set (G_OBJECT (player->playbin), "uri", uri, NULL);
+    
+    return TRUE;
 }
 
-void
-bp_pause(BansheePlayer *player)
+P_INVOKE void
+bp_stop (BansheePlayer *player, gboolean nullstate)
 {
-    g_return_if_fail(IS_BANSHEE_PLAYER(player));
-    bp_stop_iterate_timeout(player);
-    player->target_state = GST_STATE_PAUSED;
-    gst_element_set_state(player->playbin, GST_STATE_PAUSED);
+    // Some times "stop" really means "pause", particularly with
+    // CDDA track transitioning; a NULL state will release resources
+    bp_pipeline_set_state (player, nullstate ? GST_STATE_NULL : GST_STATE_PAUSED);
 }
 
-void
-bp_play(BansheePlayer *player)
+P_INVOKE void
+bp_pause (BansheePlayer *player)
 {
-    g_return_if_fail(IS_BANSHEE_PLAYER(player));
-    player->target_state = GST_STATE_PLAYING;
-    gst_element_set_state(player->playbin, GST_STATE_PLAYING);
-    bp_start_iterate_timeout(player);
+    bp_pipeline_set_state (player, GST_STATE_PAUSED);
 }
 
-void
-bp_set_volume(BansheePlayer *player, gint volume)
+P_INVOKE void
+bp_play (BansheePlayer *player)
 {
-    gdouble act_volume;
-    g_return_if_fail(IS_BANSHEE_PLAYER(player));
-    act_volume = CLAMP(volume, 0, 100) / 100.0;
-    g_object_set(G_OBJECT(player->playbin), "volume", act_volume, NULL);
+    bp_pipeline_set_state (player, GST_STATE_PLAYING);
 }
 
-gint
-bp_get_volume(BansheePlayer *player)
-{
-    gdouble volume = 0.0;
-    g_return_val_if_fail(IS_BANSHEE_PLAYER(player), 0);
-    g_object_get(player->playbin, "volume", &volume, NULL);
-    return (gint)(volume * 100.0);
-}
 
-void
-bp_set_position(BansheePlayer *player, guint64 time_ms)
+P_INVOKE gboolean
+bp_set_position (BansheePlayer *player, guint64 time_ms)
 {
-    g_return_if_fail(IS_BANSHEE_PLAYER(player));
+    g_return_val_if_fail (IS_BANSHEE_PLAYER (player), FALSE);
     
-    if(!gst_element_seek(player->playbin, 1.0, 
-        GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH,
-        GST_SEEK_TYPE_SET, time_ms * GST_MSECOND, 
-        GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
-        g_warning("Could not seek in stream");
+    if (!gst_element_seek (player->playbin, 1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH,
+        GST_SEEK_TYPE_SET, time_ms * GST_MSECOND, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
+        g_warning ("Could not seek in stream");
+        return FALSE;
     }
+    
+    return TRUE;
 }
 
-guint64
-bp_get_position(BansheePlayer *player)
+P_INVOKE guint64
+bp_get_position (BansheePlayer *player)
 {
-    GstFormat format = GST_FORMAT_TIME;
+    static GstFormat format = GST_FORMAT_TIME;
     gint64 position;
 
-    g_return_val_if_fail(IS_BANSHEE_PLAYER(player), 0);
+    g_return_val_if_fail (IS_BANSHEE_PLAYER (player), 0);
 
-    if(gst_element_query_position(player->playbin, &format, &position)) {
-        return position / 1000000;
+    if (gst_element_query_position (player->playbin, &format, &position)) {
+        return position / GST_MSECOND;
     }
     
     return 0;
 }
 
-guint64
-bp_get_duration(BansheePlayer *player)
+P_INVOKE guint64
+bp_get_duration (BansheePlayer *player)
 {
-    GstFormat format = GST_FORMAT_TIME;
+    static GstFormat format = GST_FORMAT_TIME;
     gint64 duration;
 
-    g_return_val_if_fail(IS_BANSHEE_PLAYER(player), 0);
+    g_return_val_if_fail (IS_BANSHEE_PLAYER (player), 0);
 
-    if(gst_element_query_duration(player->playbin, &format, &duration)) {
-        return duration / 1000000;
+    if (gst_element_query_duration (player->playbin, &format, &duration)) {
+        return duration / GST_MSECOND;
     }
     
     return 0;
 }
 
-gboolean
-bp_can_seek(BansheePlayer *player)
+P_INVOKE gboolean
+bp_can_seek (BansheePlayer *player)
 {
     GstQuery *query;
     gboolean can_seek = TRUE;
     
-    g_return_val_if_fail(IS_BANSHEE_PLAYER(player), FALSE);
-    g_return_val_if_fail(player->playbin != NULL, FALSE);
+    g_return_val_if_fail (IS_BANSHEE_PLAYER (player), FALSE);
+    g_return_val_if_fail (player->playbin != NULL, FALSE);
     
-    query = gst_query_new_seeking(GST_FORMAT_TIME);
-    if(!gst_element_query(player->playbin, query)) {
+    query = gst_query_new_seeking (GST_FORMAT_TIME);
+    if (!gst_element_query (player->playbin, query)) {
         // This will probably fail, 100% of the time, because it's apparently 
         // very unimplemented in GStreamer... when it's fixed
         // we will return FALSE here, and show the warning
-        // g_warning("Could not query pipeline for seek ability");
-        return bp_get_duration(player) > 0;
+        // g_warning ("Could not query pipeline for seek ability");
+        return bp_get_duration (player) > 0;
     }
     
-    gst_query_parse_seeking(query, NULL, &can_seek, NULL, NULL);
-    gst_query_unref(query);
+    gst_query_parse_seeking (query, NULL, &can_seek, NULL, NULL);
+    gst_query_unref (query);
     
     return can_seek;
 }
 
-gboolean
-bp_get_pipeline_elements(BansheePlayer *player, GstElement **playbin, GstElement **audiobin, 
-    GstElement **audiotee)
+P_INVOKE void
+bp_set_volume (BansheePlayer *player, gint volume)
+{
+    g_return_if_fail (IS_BANSHEE_PLAYER (player));
+    g_object_set (G_OBJECT (player->playbin), "volume", CLAMP (volume, 0, 100) / 100.0, NULL);
+}
+
+P_INVOKE gint
+bp_get_volume (BansheePlayer *player)
 {
-    g_return_val_if_fail(IS_BANSHEE_PLAYER(player), FALSE);
+    gdouble volume = 0.0;
+    g_return_val_if_fail (IS_BANSHEE_PLAYER (player), 0);
+    g_object_get (player->playbin, "volume", &volume, NULL);
+    return (gint)(volume * 100.0);
+}
+
+P_INVOKE gboolean
+bp_get_pipeline_elements (BansheePlayer *player, GstElement **playbin, GstElement **audiobin, GstElement **audiotee)
+{
+    g_return_val_if_fail (IS_BANSHEE_PLAYER (player), FALSE);
     
     *playbin = player->playbin;
     *audiobin = player->audiobin;
@@ -528,104 +279,53 @@
     return TRUE;
 }
 
-void
+P_INVOKE void
 bp_set_application_gdk_window(BansheePlayer *player, GdkWindow *window)
 {
     player->window = window;
 }
 
-void
-bp_get_error_quarks(GQuark *core, GQuark *library, GQuark *resource, GQuark *stream)
+P_INVOKE void
+bp_set_eos_callback (BansheePlayer *player, BansheePlayerEosCallback cb)
 {
-    *core = GST_CORE_ERROR;
-    *library = GST_LIBRARY_ERROR;
-    *resource = GST_RESOURCE_ERROR;
-    *stream = GST_STREAM_ERROR;
+    SET_CALLBACK(eos_cb);
 }
 
-/* Region Equalizer */
+P_INVOKE void
+bp_set_error_callback (BansheePlayer *player, BansheePlayerErrorCallback cb)
+{
+    SET_CALLBACK (error_cb);
+}
 
-gboolean
-gst_equalizer_is_supported(BansheePlayer *player)
+P_INVOKE void
+bp_set_state_changed_callback (BansheePlayer *player, BansheePlayerStateChangedCallback cb)
 {
-    return player != NULL && player->equalizer != NULL && player->preamp != NULL;
+    SET_CALLBACK (state_changed_cb);
 }
 
-void
-gst_equalizer_set_preamp_level(BansheePlayer *player, gdouble level)
-{
-    if (player->equalizer != NULL && player->preamp != NULL)
-        g_object_set (player->preamp, "volume", level, NULL);
-}
-
-void
-gst_equalizer_set_gain(BansheePlayer *player, guint bandnum, gdouble gain)
-{
-    if (player->equalizer != NULL) {
-        GstObject *band;   
-        band = gst_child_proxy_get_child_by_index (GST_CHILD_PROXY (player->equalizer), bandnum);
-        g_object_set (band, "gain", gain, NULL);
-        g_object_unref (band);
-    }
-}
-
-void
-gst_equalizer_get_bandrange(BansheePlayer *player, gint *min, gint *max)
-{    
-    /*
-     * NOTE: This only refers to the newer version of the equalizer element.
-     *
-     * Yes, I know GStreamer's equalizer goes from -24 to +12, but -12 to +12 is much better for two reasons:
-     * (x) Equal levels on both sides, which means we get a nice linear y=x
-     * (x) This also makes converting other eq presets easier.
-     * (x) We get a nice roud 0 dB in the middle of the band range, instead of -6, which is stupid
-     *     since 0 dB gives us no gain, yet its not in the middle - less sense to the end user.
-     *
-     * If that didn't make any sense, yay for late-night coding. :)
-     */
-    
-    if (player->equalizer != NULL) {
-        GParamSpecDouble *pspec;
-        
-        // Fetch gain range of first band (since it should be the same for the rest)
-        pspec = (GParamSpecDouble*) g_object_class_find_property (G_OBJECT_GET_CLASS (player->equalizer), "band0");
-        if (pspec) {
-            // Assume old equalizer.
-            *min = pspec->minimum;
-            *max = pspec->maximum;
-        }
-        else {
-            pspec = (GParamSpecDouble*) g_object_class_find_property (G_OBJECT_GET_CLASS (player->equalizer), "band0::gain");
-            if (pspec && pspec->maximum == 12) {
-                // New equalizer - return even scale.
-                *min = -12;
-                *max = 12;
-            }
-            else if (pspec) {
-                // Return just the ranges the equalizer supports
-                *min = pspec->minimum;
-                *max = pspec->maximum;
-            }
-            else {
-                g_warning("Could not find valid gain range for equalizer.");
-            }
-        }
-    }
-}
-
-void
-gst_equalizer_get_frequencies(BansheePlayer *player, gdouble *freq[])
-{
-    gint i;
-    gdouble bandfreq[10];
-    
-    for(i = 0; i < 10; i++) {
-        GstObject *band;
-        
-        band = gst_child_proxy_get_child_by_index (GST_CHILD_PROXY (player->equalizer), i);
-        g_object_get (G_OBJECT (band), "freq", &bandfreq[i], NULL);
-        g_object_unref (band);
-    }
-    
-    *freq = bandfreq;
+P_INVOKE void
+bp_set_iterate_callback (BansheePlayer *player, BansheePlayerIterateCallback cb)
+{
+    SET_CALLBACK (iterate_cb);
+}
+
+P_INVOKE void
+bp_set_buffering_callback (BansheePlayer *player, BansheePlayerBufferingCallback cb)
+{
+    SET_CALLBACK(buffering_cb);
+}
+
+P_INVOKE void
+bp_set_tag_found_callback (BansheePlayer *player, BansheePlayerTagFoundCallback cb)
+{
+    SET_CALLBACK (tag_found_cb);
+}
+
+P_INVOKE void
+bp_get_error_quarks (GQuark *core, GQuark *library, GQuark *resource, GQuark *stream)
+{
+    *core = GST_CORE_ERROR;
+    *library = GST_LIBRARY_ERROR;
+    *resource = GST_RESOURCE_ERROR;
+    *stream = GST_STREAM_ERROR;
 }

Modified: trunk/banshee/libbanshee/libbanshee.mdp
==============================================================================
--- trunk/banshee/libbanshee/libbanshee.mdp	(original)
+++ trunk/banshee/libbanshee/libbanshee.mdp	Tue Apr  1 00:36:23 2008
@@ -12,7 +12,7 @@
     <File name="gst-misc-0.10.c" subtype="Code" buildaction="Compile" />
     <File name="banshee-player.c" subtype="Code" buildaction="Compile" />
     <File name="gst-transcode-0.10.c" subtype="Code" buildaction="Compile" />
-    <File name="banshee-player.h" subtype="Code" buildaction="Nothing" />
+    <File name="banshee-player-private.h" subtype="Code" buildaction="Nothing" />
     <File name="banshee-player-cdda.h" subtype="Code" buildaction="Nothing" />
     <File name="gst-cd-rip.h" subtype="Code" buildaction="Nothing" />
     <File name="gst-misc.h" subtype="Code" buildaction="Nothing" />
@@ -22,6 +22,9 @@
     <File name="banshee-player-missing-elements.h" subtype="Code" buildaction="Nothing" />
     <File name="banshee-player-video.c" subtype="Code" buildaction="Compile" />
     <File name="banshee-player-video.h" subtype="Code" buildaction="Nothing" />
+    <File name="banshee-player-equalizer.c" subtype="Code" buildaction="Compile" />
+    <File name="banshee-player-pipeline.c" subtype="Code" buildaction="Compile" />
+    <File name="banshee-player-pipeline.h" subtype="Code" buildaction="Nothing" />
   </Contents>
   <compiler ctype="GccCompiler" />
   <MonoDevelop.Autotools.MakefileInfo IntegrationEnabled="True" RelativeMakefileName="Makefile.am">

Modified: trunk/banshee/src/Backends/Banshee.GStreamer/Banshee.GStreamer/PlayerEngine.cs
==============================================================================
--- trunk/banshee/src/Backends/Banshee.GStreamer/Banshee.GStreamer/PlayerEngine.cs	(original)
+++ trunk/banshee/src/Backends/Banshee.GStreamer/Banshee.GStreamer/PlayerEngine.cs	Tue Apr  1 00:36:23 2008
@@ -120,7 +120,7 @@
         public override void Dispose ()
         {
             base.Dispose ();
-            bp_free (handle);
+            bp_destroy (handle);
         }
         
         public override void Close ()
@@ -321,7 +321,7 @@
         public override bool SupportsEqualizer {
             get { 
                 if (supports_equalizer == null) {
-                    supports_equalizer = gst_equalizer_is_supported (handle); 
+                    supports_equalizer = bp_equalizer_is_supported (handle); 
                 }
                 
                 return supports_equalizer.Value;
@@ -346,7 +346,7 @@
         public double AmplifierLevel {
             set {
                 double db = Math.Pow (10.0, value / 20.0);
-                gst_equalizer_set_preamp_level (handle, db);
+                bp_equalizer_set_preamp_level (handle, db);
             }
         }
         
@@ -355,7 +355,7 @@
                 int min = -1;
                 int max = -1;
                 
-                gst_equalizer_get_bandrange (handle, out min, out max);
+                bp_equalizer_get_bandrange (handle, out min, out max);
                 
                 return new int [] { min, max };
             }
@@ -364,7 +364,7 @@
         public uint [] EqualizerFrequencies {
             get {
                 double [] freq = new double[10];
-                gst_equalizer_get_frequencies (handle, out freq);
+                bp_equalizer_get_frequencies (handle, out freq);
                 
                 uint [] ret = new uint[freq.Length];
                 for (int i = 0; i < freq.Length; i++) {
@@ -377,7 +377,7 @@
         
         public void SetEqualizerGain (uint band, double gain)
         {
-            gst_equalizer_set_gain (handle, band, gain);
+            bp_equalizer_set_gain (handle, band, gain);
         }
         
         private static string [] source_capabilities = { "file", "http", "cdda" };
@@ -394,7 +394,7 @@
         private static extern IntPtr bp_new ();
         
         [DllImport ("libbanshee")]
-        private static extern void bp_free (HandleRef player);
+        private static extern void bp_destroy (HandleRef player);
         
         [DllImport ("libbanshee")]
         private static extern void bp_set_eos_callback (HandleRef player, BansheePlayerEosCallback cb);
@@ -419,7 +419,7 @@
             GstTaggerTagFoundCallback cb);
         
         [DllImport ("libbanshee")]
-        private static extern void bp_open (HandleRef player, IntPtr uri);
+        private static extern bool bp_open (HandleRef player, IntPtr uri);
         
         [DllImport ("libbanshee")]
         private static extern void bp_stop (HandleRef player, bool nullstate);
@@ -440,7 +440,7 @@
         private static extern bool bp_can_seek (HandleRef player);
         
         [DllImport ("libbanshee")]
-        private static extern void bp_set_position (HandleRef player, ulong time_ms);
+        private static extern bool bp_set_position (HandleRef player, ulong time_ms);
         
         [DllImport ("libbanshee")]
         private static extern ulong bp_get_position (HandleRef player);
@@ -469,19 +469,19 @@
             out uint resource, out uint stream);
         
         [DllImport ("libbanshee")]
-        private static extern bool gst_equalizer_is_supported (HandleRef player);
+        private static extern bool bp_equalizer_is_supported (HandleRef player);
         
         [DllImport ("libbanshee")]
-        private static extern void gst_equalizer_set_preamp_level (HandleRef player, double level);
+        private static extern void bp_equalizer_set_preamp_level (HandleRef player, double level);
         
         [DllImport ("libbanshee")]
-        private static extern void gst_equalizer_set_gain (HandleRef player, uint bandnum, double gain);
+        private static extern void bp_equalizer_set_gain (HandleRef player, uint bandnum, double gain);
         
         [DllImport ("libbanshee")]
-        private static extern void gst_equalizer_get_bandrange (HandleRef player, out int min, out int max);
+        private static extern void bp_equalizer_get_bandrange (HandleRef player, out int min, out int max);
         
         [DllImport ("libbanshee")]
-        private static extern void gst_equalizer_get_frequencies (HandleRef player,
+        private static extern void bp_equalizer_get_frequencies (HandleRef player,
             [MarshalAs (UnmanagedType.LPArray)] out double [] freq);
     }
 }

Modified: trunk/banshee/src/Extensions/Extensions.mds
==============================================================================
--- trunk/banshee/src/Extensions/Extensions.mds	(original)
+++ trunk/banshee/src/Extensions/Extensions.mds	Tue Apr  1 00:36:23 2008
@@ -30,4 +30,4 @@
     <Entry filename="Banshee.Bookmarks/Banshee.Bookmarks.mdp" />
     <Entry filename="Banshee.AudioCd/Banshee.AudioCd.mdp" />
   </Entries>
-</Combine>
+</Combine>
\ No newline at end of file



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