diff -u -u -r1.49 Makefile.am
--- Makefile.am	10 Apr 2006 13:18:03 -0000	1.49
+++ Makefile.am	16 Apr 2006 03:30:05 -0000
@@ -6,11 +6,7 @@
 distuninstallcheck_listfiles = find . -type f -print | grep -v '^\./var/scrollkeeper'
 
 SUBDIRS = macros lib metadata player rhythmdb widgets sources iradio podcast remote \
-	daapsharing
-if ENABLE_TRACK_TRANSFER
-SUBDIRS += backends
-endif
-SUBDIRS += plugins bindings shell data po help tests doc
+	daapsharing backends plugins bindings shell data po help tests doc
 
 EXTRA_DIST = 			\
 	autogen.sh		\
diff -u -u -r1.1 Makefile.am
--- backends/Makefile.am	31 Mar 2006 09:18:42 -0000	1.1
+++ backends/Makefile.am	16 Apr 2006 03:30:05 -0000
@@ -5,12 +5,12 @@
 SUBDIRS = gstreamer
 
 librbbackends_la_SOURCES =	\
-	rb-encoder.h 		\
-	rb-encoder.c
+	rb-player.h		\
+	rb-player.c		\
+	$(NULL)
 
 librbbackends_la_LIBADD =				\
-	$(RHYTHMBOX_LIBS)				\
-	$(top_builddir)/backends/gstreamer/librbbackendsgstreamer.la
+	$(RHYTHMBOX_LIBS)
 
 librbbackends_la_LDFLAGS = -export-dynamic
 
@@ -26,4 +26,12 @@
 	-I$(top_srcdir)/backends/gstreamer		\
 	$(LIBNAUTILUS_BURN_CFLAGS)			\
 	$(RHYTHMBOX_CFLAGS)
+
+if ENABLE_TRACK_TRANSFER
+librbbackends_la_SOURCES +=	\
+	rb-encoder.h 		\
+	rb-encoder.c
+librbbackends_la_LIBADD +=				\
+	$(top_builddir)/backends/gstreamer/librbbackendsgstreamer.la
+endif
 
diff -u -u -r1.2 Makefile.am
--- backends/gstreamer/Makefile.am	10 Apr 2006 13:18:04 -0000	1.2
+++ backends/gstreamer/Makefile.am	16 Apr 2006 03:30:05 -0000
@@ -3,8 +3,9 @@
 noinst_LTLIBRARIES = librbbackendsgstreamer.la
 
 librbbackendsgstreamer_la_SOURCES =	\
-	rb-encoder-gst.h		\
-	rb-encoder-gst.c
+	rb-player-gst.h			\
+	rb-player-gst.c			\
+	$(NULL)
 
 librbbackendsgstreamer_la_LIBADD =				\
 	$(RHYTHMBOX_LIBS)
@@ -25,5 +26,12 @@
 
 if ENABLE_TRACK_TRANSFER
 INCLUDES += $(GNOME_MEDIA_PROFILES_CFLAGS)
+librbbackendsgstreamer_la_SOURCES +=	\
+	rb-encoder-gst.h		\
+	rb-encoder-gst.c
+endif
+
+if USE_DAAP
+INCLUDES += -I$(top_srcdir)/daapsharing			
 endif
 
diff -u -u -r1.15 Makefile.am
--- player/Makefile.am	9 Apr 2006 11:02:16 -0000	1.15
+++ player/Makefile.am	16 Apr 2006 03:30:06 -0000
@@ -3,8 +3,6 @@
 noinst_LTLIBRARIES = librbplayer.la
 
 librbplayer_la_SOURCES =	\
-	rb-player.h 		\
-	rb-player-gst.c		\
 	rb-recorder.h		\
 	rb-recorder-gst.c
 
@@ -27,9 +25,4 @@
 	-I$(top_builddir)/lib                           \
 	$(LIBNAUTILUS_BURN_CFLAGS)			\
 	$(RHYTHMBOX_CFLAGS)
-
-
-if USE_DAAP
-INCLUDES += -I$(top_srcdir)/daapsharing			
-endif
 
diff -u -u -r1.31 rb-audiocd-source.c
--- sources/rb-audiocd-source.c	14 Apr 2006 13:16:12 -0000	1.31
+++ sources/rb-audiocd-source.c	16 Apr 2006 03:30:09 -0000
@@ -42,7 +42,6 @@
 #include "rb-stock-icons.h"
 #include "rb-debug.h"
 #include "rb-dialog.h"
-#include "rb-player.h"
 #include "rhythmdb.h"
 #ifdef HAVE_MUSICBRAINZ
 #include "sj-metadata-musicbrainz.h"
diff -u -u -r1.30 Makefile.am
--- widgets/Makefile.am	10 Apr 2006 21:53:21 -0000	1.30
+++ widgets/Makefile.am	16 Apr 2006 03:30:09 -0000
@@ -60,6 +60,7 @@
 	-I$(top_srcdir)/library				\
 	-I$(top_srcdir)/iradio				\
 	-I$(top_srcdir)/shell				\
+	-I$(top_srcdir)/backends			\
 	$(WARN_CFLAGS)					\
 	$(NOTIFY_CFLAGS)				\
 	$(LIBSEXY_CFLAGS)				\
--- player/rb-player-gst.c	2006-04-16 13:33:43.000000000 +1000
+++ backends/gstreamer/rb-player-gst.c	2006-04-16 13:18:18.000000000 +1000
@@ -37,6 +37,7 @@
 
 #include "rb-debug.h"
 #include "rb-player.h"
+#include "rb-player-gst.h"
 #include "rb-debug.h"
 #include "rb-marshal.h"
 
@@ -44,11 +45,36 @@
 #include "rb-daap-src.h"
 #endif
 
-G_DEFINE_TYPE(RBPlayer, rb_player, G_TYPE_OBJECT)
 
-static void rb_player_finalize (GObject *object);
+static void rb_player_init (RBPlayerIface *iface);
+static void rb_player_gst_finalize (GObject *object);
 
-struct RBPlayerPrivate
+static gboolean rb_player_gst_open (RBPlayer *player,
+				    const char *uri,
+				    GError **error);
+static gboolean rb_player_gst_opened (RBPlayer *player);
+static gboolean rb_player_gst_close (RBPlayer *player, GError **error);
+static gboolean rb_player_gst_play (RBPlayer *player, GError **error);
+static void rb_player_gst_pause (RBPlayer *player);
+static gboolean rb_player_gst_playing (RBPlayer *player);
+static void rb_player_gst_set_volume (RBPlayer *player, float volume);
+static float rb_player_gst_get_volume (RBPlayer *player);
+static void rb_player_gst_set_replaygain (RBPlayer *player,
+				      double track_gain, double track_peak,
+				      double album_gain, double album_peak);
+static gboolean rb_player_gst_seekable (RBPlayer *player);
+static void rb_player_gst_set_time (RBPlayer *player, long time);
+static long rb_player_gst_get_time (RBPlayer *player);
+
+G_DEFINE_TYPE_WITH_CODE(RBPlayerGst, rb_player_gst, G_TYPE_OBJECT,
+			G_IMPLEMENT_INTERFACE(RB_TYPE_PLAYER,
+					      rb_player_init))
+#define RB_PLAYER_GST_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), RB_TYPE_PLAYER_GST, RBPlayerGstPrivate))
+
+#define RB_PLAYER_GST_TICK_HZ 5
+
+
+struct _RBPlayerGstPrivate
 {
 	char *uri;
 
@@ -74,7 +100,6 @@
 	guint tick_timeout_id;
 };
 
-#define RB_PLAYER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), RB_TYPE_PLAYER, RBPlayerPrivate))
 
 typedef enum
 {
@@ -83,101 +108,65 @@
 	ERROR,
 	TICK,
 	BUFFERING,
-	LAST_SIGNAL
-} RBPlayerSignalType;
+} RBPlayerGstSignalType;
 
 typedef struct
 {
 	int type;
-	RBPlayer *object;
+	RBPlayerGst *object;
 	RBMetaDataField info_field;
 	GError *error;
 	GValue *info;
 	guint id;
-} RBPlayerSignal;
-
-static guint rb_player_signals[LAST_SIGNAL] = { 0 };
+} RBPlayerGstSignal;
 
-static gboolean rb_player_sync_pipeline (RBPlayer *mp);
-static void rb_player_gst_free_playbin (RBPlayer *player);
+static gboolean rb_player_gst_sync_pipeline (RBPlayerGst *mp);
+static void rb_player_gst_gst_free_playbin (RBPlayerGst *player);
 
 static void
-rb_player_class_init (RBPlayerClass *klass)
+rb_player_gst_class_init (RBPlayerGstClass *klass)
 {
 	GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
-	object_class->finalize = rb_player_finalize;
+	object_class->finalize = rb_player_gst_finalize;
 
-	rb_player_signals[EOS] =
-		g_signal_new ("eos",
-			      G_OBJECT_CLASS_TYPE (object_class),
-			      G_SIGNAL_RUN_LAST,
-			      G_STRUCT_OFFSET (RBPlayerClass, eos),
-			      NULL, NULL,
-			      g_cclosure_marshal_VOID__VOID,
-			      G_TYPE_NONE,
-			      0);
-	rb_player_signals[INFO] =
-		g_signal_new ("info",
-			      G_OBJECT_CLASS_TYPE (object_class),
-			      G_SIGNAL_RUN_LAST,
-			      G_STRUCT_OFFSET (RBPlayerClass, info),
-			      NULL, NULL,
-			      rb_marshal_VOID__INT_POINTER,
-			      G_TYPE_NONE,
-			      2, G_TYPE_INT, G_TYPE_POINTER);
-	rb_player_signals[ERROR] =
-		g_signal_new ("error",
-			      G_OBJECT_CLASS_TYPE (object_class),
-			      G_SIGNAL_RUN_LAST,
-			      G_STRUCT_OFFSET (RBPlayerClass, error),
-			      NULL, NULL,
-			      g_cclosure_marshal_VOID__POINTER,
-			      G_TYPE_NONE,
-			      1,
-			      G_TYPE_POINTER);
-	rb_player_signals[TICK] =
-		g_signal_new ("tick",
-			      G_OBJECT_CLASS_TYPE (object_class),
-			      G_SIGNAL_RUN_LAST,
-			      G_STRUCT_OFFSET (RBPlayerClass, tick),
-			      NULL, NULL,
-			      g_cclosure_marshal_VOID__LONG,
-			      G_TYPE_NONE,
-			      1,
-			      G_TYPE_LONG);
-	rb_player_signals[BUFFERING] =
-		g_signal_new ("buffering",
-			      G_OBJECT_CLASS_TYPE (object_class),
-			      G_SIGNAL_RUN_LAST,
-			      G_STRUCT_OFFSET (RBPlayerClass, buffering),
-			      NULL, NULL,
-			      g_cclosure_marshal_VOID__UINT,
-			      G_TYPE_NONE,
-			      1,
-			      G_TYPE_UINT);
+	g_type_class_add_private (klass, sizeof (RBPlayerGstPrivate));
+}
 
-	g_type_class_add_private (klass, sizeof (RBPlayerPrivate));
+static void
+rb_player_init (RBPlayerIface *iface)
+{
+	iface->open = rb_player_gst_open;
+	iface->opened = rb_player_gst_opened;
+	iface->close = rb_player_gst_close;
+	iface->play = rb_player_gst_play;
+	iface->pause = rb_player_gst_pause;
+	iface->playing = rb_player_gst_playing;
+	iface->set_volume = rb_player_gst_set_volume;
+	iface->get_volume = rb_player_gst_get_volume;
+	iface->set_replaygain = rb_player_gst_set_replaygain;
+	iface->seekable = rb_player_gst_seekable;
+	iface->set_time = rb_player_gst_set_time;
+	iface->get_time = rb_player_gst_get_time;
 }
 
 static gboolean
-tick_timeout (RBPlayer *mp)
+tick_timeout (RBPlayerGst *mp)
 {
 	if (mp->priv->playing == FALSE)
 		return TRUE;
 
-	g_signal_emit (G_OBJECT (mp), rb_player_signals[TICK], 0,
-		       rb_player_get_time (mp));
+	_rb_player_emit_tick (RB_PLAYER (mp), rb_player_get_time (RB_PLAYER (mp)));
 
 	return TRUE;
 }
 
 static void
-rb_player_init (RBPlayer *mp)
+rb_player_gst_init (RBPlayerGst *mp)
 {
-	gint ms_period = 1000 / RB_PLAYER_TICK_HZ;
+	gint ms_period = 1000 / RB_PLAYER_GST_TICK_HZ;
 
-	mp->priv = RB_PLAYER_GET_PRIVATE (mp);
+	mp->priv = RB_PLAYER_GST_GET_PRIVATE (mp);
 
 	mp->priv->tick_timeout_id = g_timeout_add (ms_period, (GSourceFunc) tick_timeout, mp);
 	mp->priv->idle_info_ids = g_hash_table_new (NULL, NULL);
@@ -185,11 +174,11 @@
 }
 
 static void
-rb_player_finalize (GObject *object)
+rb_player_gst_finalize (GObject *object)
 {
-	RBPlayer *mp;
+	RBPlayerGst *mp;
 
-	mp = RB_PLAYER (object);
+	mp = RB_PLAYER_GST (object);
 
 	g_source_remove (mp->priv->tick_timeout_id);
 	g_hash_table_destroy (mp->priv->idle_info_ids);
@@ -205,14 +194,14 @@
 		gst_element_set_state (mp->priv->playbin,
 				       GST_STATE_NULL);
 		
-		rb_player_gst_free_playbin (mp);
+		rb_player_gst_gst_free_playbin (mp);
 	}
 
-	G_OBJECT_CLASS (rb_player_parent_class)->finalize (object);
+	G_OBJECT_CLASS (rb_player_gst_parent_class)->finalize (object);
 }
 
 static void
-rb_player_gst_free_playbin (RBPlayer *player)
+rb_player_gst_gst_free_playbin (RBPlayerGst *player)
 {
 	if (player->priv->playbin == NULL)
 		return;
@@ -224,7 +213,7 @@
 static void
 destroy_idle_signal (gpointer signal_pointer)
 {
-	RBPlayerSignal *signal = signal_pointer;
+	RBPlayerGstSignal *signal = signal_pointer;
 
 	if (signal->error)
 		g_error_free (signal->error);
@@ -245,35 +234,29 @@
 }
 
 static gboolean
-emit_signal_idle (RBPlayerSignal *signal)
+emit_signal_idle (RBPlayerGstSignal *signal)
 {
 	switch (signal->type) {
 	case ERROR:
-		g_signal_emit (G_OBJECT (signal->object),
-			       rb_player_signals[ERROR], 0,
-			       signal->error);
+		_rb_player_emit_error (RB_PLAYER (signal->object), signal->error);
 
 		/* close if not already closing */
 		if (signal->object->priv->uri != NULL)
-			rb_player_close (signal->object, NULL);
+			rb_player_close (RB_PLAYER (signal->object), NULL);
 
 		break;
 
 	case EOS:
-		g_signal_emit (G_OBJECT (signal->object), rb_player_signals[EOS], 0);
+		_rb_player_emit_eos (RB_PLAYER (signal->object));
 		signal->object->priv->idle_eos_id = 0;
 		break;
 
 	case INFO:
-		g_signal_emit (G_OBJECT (signal->object),
-			       rb_player_signals[INFO], 0,
-			       signal->info_field, signal->info);
+		_rb_player_emit_info (RB_PLAYER (signal->object), signal->info_field, signal->info);
 		break;
 
 	case BUFFERING:
-		g_signal_emit (G_OBJECT (signal->object),
-			       rb_player_signals[BUFFERING], 0,
-			       g_value_get_uint (signal->info));
+		_rb_player_emit_buffering (RB_PLAYER (signal->object), g_value_get_uint (signal->info));
 		signal->object->priv->idle_buffering_id = 0;
 		break;
 	}
@@ -284,10 +267,10 @@
 #ifdef HAVE_GSTREAMER_0_8
 static void
 eos_cb (GstElement *element,
-	RBPlayer *mp)
+	RBPlayerGst *mp)
 {
-	RBPlayerSignal *signal;
-	signal = g_new0 (RBPlayerSignal, 1);
+	RBPlayerGstSignal *signal;
+	signal = g_new0 (RBPlayerGstSignal, 1);
 	signal->type = EOS;
 	signal->object = mp;
 	g_object_ref (G_OBJECT (mp));
@@ -304,10 +287,10 @@
 	  GstElement *source,
 	  const GError *error,
 	  gchar *debug,
-	  RBPlayer *mp)
+	  RBPlayerGst *mp)
 {
 	int code;
-	RBPlayerSignal *signal;
+	RBPlayerGstSignal *signal;
 
 	/* the handler shouldn't get called with error=NULL, but sometimes it does */
 	if (error == NULL)
@@ -316,9 +299,9 @@
 	if ((error->domain == GST_CORE_ERROR)
 	    || (error->domain == GST_LIBRARY_ERROR)
 	    || (error->code == GST_RESOURCE_ERROR_BUSY)) {
-		code = RB_PLAYER_ERROR_NO_AUDIO;
+		code = RB_PLAYER_GST_ERROR_NO_AUDIO;
 	} else {
-		code = RB_PLAYER_ERROR_GENERAL;
+		code = RB_PLAYER_GST_ERROR_GENERAL;
 	}
 
 	/* If we're in a synchronous op, we can signal the error directly */
@@ -333,10 +316,10 @@
 		return;
 	}
 
-	signal = g_new0 (RBPlayerSignal, 1);
+	signal = g_new0 (RBPlayerGstSignal, 1);
 	signal->type = ERROR;
 	signal->object = mp;
-	signal->error = g_error_new_literal (RB_PLAYER_ERROR,
+	signal->error = g_error_new_literal (RB_PLAYER_GST_ERROR,
 					     code,
 					     error->message);
 
@@ -352,11 +335,11 @@
 #endif
 
 static void
-process_tag (const GstTagList *list, const gchar *tag, RBPlayer *player)
+process_tag (const GstTagList *list, const gchar *tag, RBPlayerGst *player)
 {
 	int count;
 	RBMetaDataField field;
-	RBPlayerSignal *signal;
+	RBPlayerGstSignal *signal;
 	const GValue *val;
 	GValue *newval;
 
@@ -398,7 +381,7 @@
 		return;
 	}
 
-	signal = g_new0 (RBPlayerSignal, 1);
+	signal = g_new0 (RBPlayerGstSignal, 1);
 	signal->object = player;
 	signal->info_field = field;
 	signal->info = newval;
@@ -414,17 +397,17 @@
 
 #ifdef HAVE_GSTREAMER_0_8
 static void
-found_tag_cb (GObject *pipeline, GstElement *source, GstTagList *tags, RBPlayer *player)
+found_tag_cb (GObject *pipeline, GstElement *source, GstTagList *tags, RBPlayerGst *player)
 {
 	gst_tag_list_foreach (tags, (GstTagForeachFunc) process_tag, player);
 }
 
 static void
-buffering_cb (GstElement *element, gint progress, RBPlayer *mp)
+buffering_cb (GstElement *element, gint progress, RBPlayerGst *mp)
 {
-	RBPlayerSignal *signal;
+	RBPlayerGstSignal *signal;
 
-	signal = g_new0 (RBPlayerSignal, 1);
+	signal = g_new0 (RBPlayerGstSignal, 1);
 	signal->type = BUFFERING;
 
 	g_object_ref (G_OBJECT (mp));
@@ -439,7 +422,7 @@
 }
 #elif HAVE_GSTREAMER_0_10
 static gboolean
-rb_player_bus_cb (GstBus * bus, GstMessage * message, RBPlayer *mp)
+rb_player_gst_bus_cb (GstBus * bus, GstMessage * message, RBPlayerGst *mp)
 {
 	g_return_val_if_fail (mp != NULL, FALSE);
 
@@ -462,20 +445,18 @@
 		sig_error = g_error_new_literal (RB_PLAYER_ERROR,
 						 code,
 						 error->message);
-		g_signal_emit (G_OBJECT (mp),
-			       rb_player_signals[ERROR], 0,
-			       sig_error);
+		_rb_player_emit_error (RB_PLAYER (mp), sig_error);
 
 		/* close if not already closing */
 		if (mp->priv->uri != NULL)
-			rb_player_close (mp, NULL);
+			rb_player_close (RB_PLAYER (mp), NULL);
 
 		g_error_free (error);
 		g_free (debug);
 		break;
 	}
 	case GST_MESSAGE_EOS:
-		g_signal_emit (G_OBJECT (mp), rb_player_signals[EOS], 0);
+		_rb_player_emit_eos (RB_PLAYER (mp));
 		break;
 	case GST_MESSAGE_TAG: {
 		GstTagList *tags;
@@ -486,7 +467,7 @@
 		break;
 	}
 	case GST_MESSAGE_BUFFERING: {
-		RBPlayerSignal *signal;
+		RBPlayerGstSignal *signal;
 		const GstStructure *s;
 		gint progress;
 
@@ -495,7 +476,7 @@
 			g_warning ("Could not get value from BUFFERING message");
 			break;
 		}
-		signal = g_new0 (RBPlayerSignal, 1);
+		signal = g_new0 (RBPlayerGstSignal, 1);
 		signal->type = BUFFERING;
 
 		g_object_ref (G_OBJECT (mp));
@@ -516,7 +497,7 @@
 #endif
 
 static gboolean
-rb_player_construct (RBPlayer *mp, GError **error)
+rb_player_gst_construct (RBPlayerGst *mp, GError **error)
 {
 	char *element_name = NULL;
 	GstElement *sink, *fakesink;
@@ -557,7 +538,7 @@
 #endif
 #ifdef HAVE_GSTREAMER_0_10
 	gst_bus_add_watch (gst_element_get_bus (GST_ELEMENT (mp->priv->playbin)),
-			     (GstBusFunc) rb_player_bus_cb, mp);
+			     (GstBusFunc) rb_player_gst_bus_cb, mp);
 
 	/* Output sink */
 	sink = gst_element_factory_make ("gconfaudiosink", "audiosink");
@@ -571,7 +552,7 @@
 		mp->priv->cur_volume = 1.0;
 	if (mp->priv->cur_volume < 0.0)
 		mp->priv->cur_volume = 0;
-	rb_player_set_volume (mp, mp->priv->cur_volume);
+	rb_player_set_volume (RB_PLAYER (mp), mp->priv->cur_volume);
 
 	rb_debug ("pipeline construction complete");
 	return TRUE;
@@ -584,47 +565,23 @@
 			     RB_PLAYER_ERROR_GENERAL,
 			     err);
 		g_free (err);
-		rb_player_gst_free_playbin (mp);
+		rb_player_gst_gst_free_playbin (mp);
 		return FALSE;
 	}
 }
 
 RBPlayer *
-rb_player_new (GError **error)
+rb_player_gst_new (GError **error)
 {
-	RBPlayer *mp;
-
-#ifdef HAVE_GSTREAMER_0_8
-	GstElement *dummy;
-
-	dummy = gst_element_factory_make ("fakesink", "fakesink");
-	if (!dummy
-	    || !gst_scheduler_factory_make (NULL, GST_ELEMENT (dummy))) {
-		g_set_error (error, RB_PLAYER_ERROR,
-			     RB_PLAYER_ERROR_GENERAL,
-			     "%s",
-			     _("Couldn't initialize scheduler.  Did you run gst-register?"));
-		return NULL;
-	}
-#endif
+	RBPlayerGst *mp;
 
-	mp = RB_PLAYER (g_object_new (RB_TYPE_PLAYER, NULL, NULL));
+	mp = RB_PLAYER_GST (g_object_new (RB_TYPE_PLAYER, NULL, NULL));
 
-	return mp;
-}
-
-GQuark
-rb_player_error_quark (void)
-{
-	static GQuark quark = 0;
-	if (!quark)
-		quark = g_quark_from_static_string ("rb_player_error");
-
-	return quark;
+	return RB_PLAYER (mp);
 }
 
 static gboolean
-rb_player_sync_pipeline (RBPlayer *mp)
+rb_player_gst_sync_pipeline (RBPlayerGst *mp)
 {
 	rb_debug ("syncing pipeline");
 	if (mp->priv->playing) {
@@ -658,7 +615,7 @@
  * can receive an error signal.
  */
 static void
-begin_gstreamer_operation (RBPlayer *mp)
+begin_gstreamer_operation (RBPlayerGst *mp)
 {
 	g_assert (mp->priv->error == NULL);
 	mp->priv->can_signal_direct_error = TRUE;
@@ -668,7 +625,7 @@
  * error from the sequence into error.
  */
 static void
-end_gstreamer_operation (RBPlayer *mp, gboolean op_failed, GError **error)
+end_gstreamer_operation (RBPlayerGst *mp, gboolean op_failed, GError **error)
 {
 	mp->priv->can_signal_direct_error = FALSE;
 	if (mp->priv->error) {
@@ -704,20 +661,19 @@
 	}
 }
 
-gboolean
-rb_player_open (RBPlayer *mp,
+static gboolean
+rb_player_gst_open (RBPlayer *player,
 		const char *uri,
 		GError **error)
-{	
+{
+	RBPlayerGst *mp = RB_PLAYER_GST (player);
 	gboolean cdda_seek = FALSE;
 
-	g_return_val_if_fail (RB_IS_PLAYER (mp), TRUE);
-
 	if (mp->priv->playbin == NULL) {
-		if (!rb_player_construct (mp, error))
+		if (!rb_player_gst_construct (mp, error))
 			return FALSE;
 	} else {
-		if (!rb_player_close (mp, error))
+		if (!rb_player_close (player, error))
 			return FALSE;
 	}
 
@@ -778,9 +734,9 @@
 		g_object_set (G_OBJECT (mp->priv->playbin), "uri", uri, NULL);
 	}
 
-	if (!rb_player_sync_pipeline (mp)) {
+	if (!rb_player_gst_sync_pipeline (mp)) {
 		end_gstreamer_operation (mp, TRUE, error);
-		rb_player_close (mp, NULL);
+		rb_player_gst_close (player, NULL);
 		return FALSE;
 	}
 
@@ -796,11 +752,11 @@
 	g_source_remove (id);
 }
 
-gboolean
-rb_player_close (RBPlayer *mp, GError **error)
+static gboolean
+rb_player_gst_close (RBPlayer *player, GError **error)
 {
+	RBPlayerGst *mp = RB_PLAYER_GST (player);
 	gboolean ret;
-	g_return_val_if_fail (RB_IS_PLAYER (mp), TRUE);
 
 	mp->priv->playing = FALSE;
 
@@ -834,34 +790,34 @@
 	return ret;
 }
 
-gboolean
-rb_player_opened (RBPlayer *mp)
+static gboolean
+rb_player_gst_opened (RBPlayer *player)
 {
-	g_return_val_if_fail (RB_IS_PLAYER (mp), FALSE);
+	RBPlayerGst *mp = RB_PLAYER_GST (player);
 
 	return mp->priv->uri != NULL;
 }
 
-gboolean
-rb_player_play (RBPlayer *mp, GError **error)
+static gboolean
+rb_player_gst_play (RBPlayer *player, GError **error)
 {
+	RBPlayerGst *mp = RB_PLAYER_GST (player);
 	gboolean ret;
-	g_return_val_if_fail (RB_IS_PLAYER (mp), TRUE);
 
 	mp->priv->playing = TRUE;
 
 	g_return_val_if_fail (mp->priv->playbin != NULL, FALSE);
 
 	begin_gstreamer_operation (mp);
-	ret = rb_player_sync_pipeline (mp);
+	ret = rb_player_gst_sync_pipeline (mp);
 	end_gstreamer_operation (mp, !ret, error);
 	return ret;
 }
 
-void
-rb_player_pause (RBPlayer *mp)
+static void
+rb_player_gst_pause (RBPlayer *player)
 {
-	g_return_if_fail (RB_IS_PLAYER (mp));
+	RBPlayerGst *mp = RB_PLAYER_GST (player);
 
 	if (!mp->priv->playing)
 		return;
@@ -870,27 +826,27 @@
 
 	g_return_if_fail (mp->priv->playbin != NULL);
 
-	rb_player_sync_pipeline (mp);
+	rb_player_gst_sync_pipeline (mp);
 }
 
-gboolean
-rb_player_playing (RBPlayer *mp)
+static gboolean
+rb_player_gst_playing (RBPlayer *player)
 {
-	g_return_val_if_fail (RB_IS_PLAYER (mp), FALSE);
+	RBPlayerGst *mp = RB_PLAYER_GST (player);
 
 	return mp->priv->playing;
 }
 
-void
-rb_player_set_replaygain (RBPlayer *mp,
-				    double track_gain, double track_peak, double album_gain, double album_peak)
+static void
+rb_player_gst_set_replaygain (RBPlayer *player,
+			      double track_gain, double track_peak,
+			      double album_gain, double album_peak)
 {
+	RBPlayerGst *mp = RB_PLAYER_GST (player);
 	double scale;
 	double gain = 0;
 	double peak = 0;
 
-	g_return_if_fail (RB_IS_PLAYER (mp));
-
 	if (album_gain != 0)
 	  gain = album_gain;
 	else
@@ -933,11 +889,11 @@
 	}
 }
 
-void
-rb_player_set_volume (RBPlayer *mp,
-		      float volume)
+static void
+rb_player_gst_set_volume (RBPlayer *player,
+			  float volume)
 {
-	g_return_if_fail (RB_IS_PLAYER (mp));
+	RBPlayerGst *mp = RB_PLAYER_GST (player);
 	g_return_if_fail (volume >= 0.0 && volume <= 1.0);
 
 	if (mp->priv->playbin != NULL) {
@@ -950,17 +906,18 @@
 	mp->priv->cur_volume = volume;
 }
 
-float
-rb_player_get_volume (RBPlayer *mp)
+static float
+rb_player_gst_get_volume (RBPlayer *player)
 {
-	g_return_val_if_fail (RB_IS_PLAYER (mp), 0.0);
+	RBPlayerGst *mp = RB_PLAYER_GST (player);
 
 	return mp->priv->cur_volume;
 }
 
-gboolean
-rb_player_seekable (RBPlayer *mp)
+static gboolean
+rb_player_gst_seekable (RBPlayer *player)
 {
+	RBPlayerGst *mp = RB_PLAYER_GST (player);
 #ifdef HAVE_GSTREAMER_0_8
 	/* FIXME we're lying here,
 	 * (0.8) trying a seek might disrupt playback */
@@ -971,7 +928,6 @@
 	GstQuery *query;
 #endif
 
-	g_return_val_if_fail (RB_IS_PLAYER (mp), FALSE);
 	g_return_val_if_fail (mp->priv->playbin != NULL, FALSE);
 #ifdef HAVE_GSTREAMER_0_10
 	query = gst_query_new_seeking (GST_FORMAT_TIME);
@@ -984,10 +940,10 @@
 	return can_seek;
 }
 
-void
-rb_player_set_time (RBPlayer *mp, long time)
+static void
+rb_player_gst_set_time (RBPlayer *player, long time)
 {
-	g_return_if_fail (RB_IS_PLAYER (mp));
+	RBPlayerGst *mp = RB_PLAYER_GST (player);
 	g_return_if_fail (time >= 0);
 
 	g_return_if_fail (mp->priv->playbin != NULL);
@@ -1042,10 +998,10 @@
 	}
 }
 
-long
-rb_player_get_time (RBPlayer *mp)
+static long
+rb_player_gst_get_time (RBPlayer *player)
 {
-	g_return_val_if_fail (RB_IS_PLAYER (mp), -1);
+	RBPlayerGst *mp = RB_PLAYER_GST (player);
 
 	if (mp->priv->playbin != NULL) {
 		gint64 position = -1;
@@ -1078,3 +1034,4 @@
 	} else
 		return -1;
 }
+
--- player/rb-player.h	2006-04-16 13:33:43.000000000 +1000
+++ backends/rb-player.h	2006-04-16 12:59:30.000000000 +1000
@@ -30,80 +30,96 @@
 
 typedef enum
 {
-	RB_PLAYER_ERROR_NO_INPUT_PLUGIN,
-	RB_PLAYER_ERROR_NO_QUEUE_PLUGIN,
-	RB_PLAYER_ERROR_NO_TYPEFIND_PLUGIN,
-	RB_PLAYER_ERROR_NO_DEMUX_PLUGIN,
-	RB_PLAYER_ERROR_NO_VOLUME_PLUGIN,
-	RB_PLAYER_ERROR_DEMUX_FAILED,
 	RB_PLAYER_ERROR_NO_AUDIO,
 	RB_PLAYER_ERROR_GENERAL,
 	RB_PLAYER_ERROR_INTERNAL
 } RBPlayerError;
 
-#define RB_PLAYER_TICK_HZ 5
-
 #define RB_PLAYER_ERROR rb_player_error_quark ()
 
 GQuark rb_player_error_quark (void);
 
 #define RB_TYPE_PLAYER         (rb_player_get_type ())
 #define RB_PLAYER(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), RB_TYPE_PLAYER, RBPlayer))
-#define RB_PLAYER_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), RB_TYPE_PLAYER, RBPlayerClass))
 #define RB_IS_PLAYER(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), RB_TYPE_PLAYER))
-#define RB_IS_PLAYER_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), RB_TYPE_PLAYER))
-#define RB_PLAYER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), RB_TYPE_PLAYER, RBPlayerClass))
+#define RB_PLAYER_GET_IFACE(o) (G_TYPE_INSTANCE_GET_INTERFACE ((o), RB_TYPE_PLAYER, RBPlayerIface))
 
-typedef struct RBPlayerPrivate RBPlayerPrivate;
+typedef struct _RBPlayer RBPlayer;
 
 typedef struct
 {
-	GObject parent;
-
-	RBPlayerPrivate *priv;
-} RBPlayer;
+	GTypeInterface	g_iface;
 
-typedef struct
-{
-	GObjectClass parent_class;
-
-	void (*eos)             	(RBPlayer *mp);
-	void (*info)            	(RBPlayer *mp, RBMetaDataField field, GValue *value);
-	void (*buffering)		(RBPlayer *mp, guint progress);
-	void (*error)           	(RBPlayer *mp, GError *error);
-	void (*tick)            	(RBPlayer *mp, long elapsed);
-} RBPlayerClass;
+	/* virtual functions */
+	gboolean        (*open)			(RBPlayer *player,
+						 const char *uri,
+						 GError **error);
+	gboolean	(*opened)		(RBPlayer *player);
+	gboolean        (*close)		(RBPlayer *player,
+						 GError **error);
+
+	gboolean	(*play)			(RBPlayer *player,
+						 GError **error);
+	void		(*pause)		(RBPlayer *player);
+	gboolean	(*playing)		(RBPlayer *player);
+
+	void		(*set_volume)		(RBPlayer *player,
+						 float volume);
+	float		(*get_volume)		(RBPlayer *player);
+	void		(*set_replaygain)	(RBPlayer *player,
+						 double track_gain,
+						 double track_peak,
+						 double album_gain,
+						 double album_peak);
+
+	gboolean	(*seekable)		(RBPlayer *player);
+	void		(*set_time)		(RBPlayer *player,
+						 long time);
+	long		(*get_time)		(RBPlayer *player);
+
+	/* signals */
+	void		(*eos)			(RBPlayer *player);
+	void		(*info)			(RBPlayer *player,
+						 RBMetaDataField field,
+						 GValue *value);
+	void		(*buffering)		(RBPlayer *player,
+						 guint progress);
+	void		(*error)           	(RBPlayer *player,
+						 GError *error);
+	void		(*tick)            	(RBPlayer *player,
+						 long elapsed);
+} RBPlayerIface;
 
 GType		rb_player_get_type   (void);
-
 RBPlayer *	rb_player_new        (GError **error);
 
-gboolean        rb_player_open       (RBPlayer *mp,
+gboolean        rb_player_open       (RBPlayer *player,
 				      const char *uri,
 				      GError **error);
+gboolean	rb_player_opened     (RBPlayer *player);
+gboolean        rb_player_close      (RBPlayer *player, GError **error);
 
-gboolean	rb_player_opened     (RBPlayer *mp);
-
-gboolean        rb_player_close      (RBPlayer *mp, GError **error);
-
-gboolean	rb_player_play       (RBPlayer *mp, GError **error);
-
-void		rb_player_pause      (RBPlayer *mp);
-
-gboolean	rb_player_playing    (RBPlayer *mp);
-
-void		rb_player_set_volume (RBPlayer *mp,
-				      float volume);
-float		rb_player_get_volume (RBPlayer *mp);
-
-void		rb_player_set_replaygain (RBPlayer *mp,
-					  double track_gain, double track_peak, double album_gain, double album_peak);
-
-gboolean	rb_player_seekable   (RBPlayer *mp);
-
-void		rb_player_set_time   (RBPlayer *mp,
-				      long time);
-long		rb_player_get_time   (RBPlayer *mp);
+gboolean	rb_player_play       (RBPlayer *player, GError **error);
+void		rb_player_pause      (RBPlayer *player);
+gboolean	rb_player_playing    (RBPlayer *player);
+
+void		rb_player_set_volume (RBPlayer *player, float volume);
+float		rb_player_get_volume (RBPlayer *player);
+void		rb_player_set_replaygain (RBPlayer *player,
+					  double track_gain, double track_peak,
+					  double album_gain, double album_peak);
+
+gboolean	rb_player_seekable   (RBPlayer *player);
+void		rb_player_set_time   (RBPlayer *player, long time);
+long		rb_player_get_time   (RBPlayer *player);
+
+
+/* only to be used by subclasses */
+void	_rb_player_emit_eos (RBPlayer *player);
+void	_rb_player_emit_info (RBPlayer *player, RBMetaDataField field, GValue *value);
+void	_rb_player_emit_buffering (RBPlayer *player, guint progress);
+void	_rb_player_emit_error (RBPlayer *player, GError *error);
+void	_rb_player_emit_tick (RBPlayer *player, long elapsed);
 
 G_END_DECLS
 
--- /dev/null	2006-04-04 03:40:38.000000000 +1000
+++ backends/gstreamer/rb-player-gst.h	2006-04-16 13:16:47.000000000 +1000
@@ -0,0 +1,54 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2006 James Livingston <jrl@ids.org.au>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __RB_PLAYER_GST_H__
+#define __RB_PLAYER_GST_H__
+
+#include <glib-object.h>
+
+#include "rb-player.h"
+
+G_BEGIN_DECLS
+
+
+#define RB_TYPE_PLAYER_GST            (rb_player_gst_get_type ())
+#define RB_PLAYER_GST(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), RB_TYPE_PLAYER, RBPlayerGst))
+#define RB_IS_PLAYERER_GST(obj)       (G_TYPE_CHECK_INSTANCE_TYPE ((obj), RB_TYPE_PLAYER))
+
+typedef struct _RBPlayerGstPrivate RBPlayerGstPrivate;
+
+typedef struct
+{
+	GObjectClass obj_class;
+} RBPlayerGstClass;
+
+typedef struct
+{
+	GObject obj;
+	RBPlayerGstPrivate *priv;
+} RBPlayerGst;
+
+RBPlayer*	rb_player_gst_new (GError **error);
+GType		rb_player_gst_get_type (void);
+
+
+G_END_DECLS
+
+#endif /* __RB_PLAYER_GST_H__ */
--- /dev/null	2006-04-04 03:40:38.000000000 +1000
+++ backends/rb-player.c	2006-04-16 13:19:30.000000000 +1000
@@ -0,0 +1,264 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ *  Copyright (C) 2006  James Livingston  <jrl@ids.org.au>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include <config.h>
+
+#include "rb-player.h"
+#include "rb-player-gst.h"
+#include "rb-marshal.h"
+
+/* Signals */
+enum {
+	EOS,
+	INFO,
+	BUFFERING,
+	ERROR,
+	TICK,
+	LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+static void
+rb_player_interface_init (RBPlayerIface *iface)
+{
+	signals[EOS] =
+		g_signal_new ("eos",
+			      G_TYPE_FROM_INTERFACE (iface),
+			      G_SIGNAL_RUN_LAST,
+			      G_STRUCT_OFFSET (RBPlayerIface, eos),
+			      NULL, NULL,
+			      g_cclosure_marshal_VOID__VOID,
+			      G_TYPE_NONE,
+			      0);
+	signals[INFO] =
+		g_signal_new ("info",
+			      G_TYPE_FROM_INTERFACE (iface),
+			      G_SIGNAL_RUN_LAST,
+			      G_STRUCT_OFFSET (RBPlayerIface, info),
+			      NULL, NULL,
+			      rb_marshal_VOID__INT_POINTER,
+			      G_TYPE_NONE,
+			      2, G_TYPE_INT, G_TYPE_POINTER);
+	signals[ERROR] =
+		g_signal_new ("error",
+			      G_TYPE_FROM_INTERFACE (iface),
+			      G_SIGNAL_RUN_LAST,
+			      G_STRUCT_OFFSET (RBPlayerIface, error),
+			      NULL, NULL,
+			      g_cclosure_marshal_VOID__POINTER,
+			      G_TYPE_NONE,
+			      1,
+			      G_TYPE_POINTER);
+	signals[TICK] =
+		g_signal_new ("tick",
+			      G_TYPE_FROM_INTERFACE (iface),
+			      G_SIGNAL_RUN_LAST,
+			      G_STRUCT_OFFSET (RBPlayerIface, tick),
+			      NULL, NULL,
+			      g_cclosure_marshal_VOID__LONG,
+			      G_TYPE_NONE,
+			      1,
+			      G_TYPE_LONG);
+	signals[BUFFERING] =
+		g_signal_new ("buffering",
+			      G_TYPE_FROM_INTERFACE (iface),
+			      G_SIGNAL_RUN_LAST,
+			      G_STRUCT_OFFSET (RBPlayerIface, buffering),
+			      NULL, NULL,
+			      g_cclosure_marshal_VOID__UINT,
+			      G_TYPE_NONE,
+			      1,
+			      G_TYPE_UINT);
+}
+
+GType
+rb_player_get_type (void)
+{
+	static GType our_type = 0;
+
+	if (!our_type) {
+		static const GTypeInfo our_info = {
+			sizeof (RBPlayerIface),
+			NULL,	/* base_init */
+			NULL,	/* base_finalize */
+			(GClassInitFunc)rb_player_interface_init,
+			NULL,	/* class_finalize */
+			NULL,	/* class_data */
+			0,
+			0,
+			NULL
+		};
+
+		our_type = g_type_register_static (G_TYPE_INTERFACE, "RBPlayer", &our_info, 0);
+	}
+
+	return our_type;
+}
+
+
+gboolean
+rb_player_open (RBPlayer *player, const char *uri, GError **error)
+{
+	RBPlayerIface *iface = RB_PLAYER_GET_IFACE (player);
+
+	return iface->open (player, uri, error);
+}
+
+gboolean
+rb_player_opened (RBPlayer *player)
+{
+	RBPlayerIface *iface = RB_PLAYER_GET_IFACE (player);
+
+	return iface->opened (player);
+}
+
+gboolean
+rb_player_close (RBPlayer *player, GError **error)
+{
+	RBPlayerIface *iface = RB_PLAYER_GET_IFACE (player);
+
+	return iface->close (player, error);
+}
+
+gboolean
+rb_player_play (RBPlayer *player, GError **error)
+{
+	RBPlayerIface *iface = RB_PLAYER_GET_IFACE (player);
+
+	return iface->play (player, error);
+}
+
+void
+rb_player_pause (RBPlayer *player)
+{
+	RBPlayerIface *iface = RB_PLAYER_GET_IFACE (player);
+
+	iface->pause (player);
+}
+
+gboolean
+rb_player_playing (RBPlayer *player)
+{
+	RBPlayerIface *iface = RB_PLAYER_GET_IFACE (player);
+
+	return iface->playing (player);
+}
+
+void
+rb_player_set_volume (RBPlayer *player, float volume)
+{
+	RBPlayerIface *iface = RB_PLAYER_GET_IFACE (player);
+
+	iface->set_volume (player, volume);
+}
+
+float
+rb_player_get_volume (RBPlayer *player)
+{
+	RBPlayerIface *iface = RB_PLAYER_GET_IFACE (player);
+
+	return iface->get_volume (player);
+}
+
+void
+rb_player_set_replaygain (RBPlayer *player,
+			  double track_gain, double track_peak,
+			  double album_gain, double album_peak)
+{
+	RBPlayerIface *iface = RB_PLAYER_GET_IFACE (player);
+
+	iface->set_replaygain (player, track_gain, track_peak, album_gain, album_peak);
+}
+
+gboolean
+rb_player_seekable (RBPlayer *player)
+{
+	RBPlayerIface *iface = RB_PLAYER_GET_IFACE (player);
+
+	return iface->seekable (player);
+}
+
+void
+rb_player_set_time (RBPlayer *player, long time)
+{
+	RBPlayerIface *iface = RB_PLAYER_GET_IFACE (player);
+
+	iface->set_time (player, time);
+}
+
+long
+rb_player_get_time (RBPlayer *player)
+{
+	RBPlayerIface *iface = RB_PLAYER_GET_IFACE (player);
+
+	return iface->get_time (player);
+}
+
+
+RBPlayer*
+rb_player_new (GError **error)
+{
+	return rb_player_gst_new (error);
+}
+
+
+void
+_rb_player_emit_eos (RBPlayer *player)
+{
+	g_signal_emit (player, signals[EOS], 0);
+}
+
+void
+_rb_player_emit_info (RBPlayer *player,
+		      RBMetaDataField field,
+		      GValue *value)
+{
+	g_signal_emit (player, signals[INFO], 0, field, value);
+}
+
+void
+_rb_player_emit_buffering (RBPlayer *player, guint progress)
+{
+	g_signal_emit (player, signals[BUFFERING], 0, progress);
+}
+
+void
+_rb_player_emit_error (RBPlayer *player, GError *error)
+{
+	g_signal_emit (player, signals[ERROR], 0, error);
+}
+
+void
+_rb_player_emit_tick (RBPlayer *player, long elapsed)
+{
+	g_signal_emit (player, signals[TICK], 0, elapsed);
+}
+
+
+GQuark
+rb_player_error_quark (void)
+{
+	static GQuark quark = 0;
+	if (!quark)
+		quark = g_quark_from_static_string ("rb_player_error");
+
+	return quark;
+}
