=== modified file 'docs/Banshee/en/Banshee.MediaEngine/PlayerEngineService.xml'
--- docs/Banshee/en/Banshee.MediaEngine/PlayerEngineService.xml	2008-11-07 09:18:37 +0000
+++ docs/Banshee/en/Banshee.MediaEngine/PlayerEngineService.xml	2009-03-19 06:56:17 +0000
@@ -245,5 +245,43 @@
       <ReturnValue><ReturnType>Banshee.Configuration.SchemaEntry&lt;System.Int32&gt;</ReturnType></ReturnValue>
       <Docs><summary>To be added.</summary><remarks>To be added.</remarks></Docs>
     <AssemblyInfo><AssemblyVersion>1.3.1.0</AssemblyVersion><AssemblyVersion>1.4.0.0</AssemblyVersion></AssemblyInfo></Member>
+
+    <Member MemberName="SetNextTrack">
+      <MemberSignature Language="C#" Value="public bool SetNextTrack (TrackInfo track);"/>
+      <MemberType>Method</MemberType>
+      <ReturnValue><ReturnType>System.Boolean</ReturnType></ReturnValue>
+      <AssemblyInfo><AssemblyVersion>1.5.0.0</AssemblyVersion></AssemblyInfo>
+      <Docs>
+        <summary>Give the PlayerEngine the next track, so that it can buffer it for gapless/crossfading playback.</summary>
+        <param name="track">The <see cref="TrackInfo"/> to buffer</param>
+        <returns>
+          True iff the engine successfully set <paramref name="track"/> to be pending.  In this case, playback will automatically
+          continue when the currently playing track ends.
+        </returns>
+        <remarks>
+          This function must only be called in response to a <see cref="PlayerEvent.BufferNextTrack"/> event.  Only engines
+          which raise this event are guaranteed to handle gapless buffering.
+        </remarks>
+      </Docs>
+    </Member>
+
+    <Member MemberName="SetNextTrack">
+      <MemberSignature Language="C#" Value="public bool SetNextTrack (SafeUri uri);"/>
+      <MemberType>Method</MemberType>
+      <ReturnValue><ReturnType>System.Boolean</ReturnType></ReturnValue>
+      <AssemblyInfo><AssemblyVersion>1.5.0.0</AssemblyVersion></AssemblyInfo>
+      <Docs>
+        <summary>Give the PlayerEngine the next track, so that it can buffer it for gapless/crossfading playback.</summary>
+        <param name="uri">The <see cref="SafeUri"/> to buffer</param>
+        <returns>
+          True iff the engine successfully set <paramref name="uri"/> to be pending.  In this case, playback will automatically
+          continue when the currently playing track ends.
+        </returns>
+        <remarks>
+          This function must only be called in response to a <see cref="PlayerEvent.BufferNextTrack"/> event.  Only engines
+          which raise this event are guaranteed to handle gapless buffering.
+        </remarks>
+      </Docs>
+    </Member>
   </Members>
 </Type>

=== modified file 'libbanshee/banshee-player-pipeline.c'
--- libbanshee/banshee-player-pipeline.c	2009-03-14 08:04:48 +0000
+++ libbanshee/banshee-player-pipeline.c	2009-03-26 05:52:44 +0000
@@ -172,6 +172,23 @@
     return TRUE;
 }
 
+static void bp_about_to_finish_callback (GstElement *playbin, BansheePlayer *player)
+{
+    if (player->next_uri != NULL) {
+        bp_debug ("Gapless: Setting uri to: %s", player->next_uri);
+        g_object_set (G_OBJECT (playbin), "uri", player->next_uri, NULL);
+        g_free (player->next_uri);
+        player->next_uri = NULL;
+    } else {
+        bp_debug ("Gapless: about-to-finish called, but player->next_track not set");
+    }
+    //playbin2 currently doesn't (yet) have any way to notify us when it actually starts playing the next track.
+    //On linux, about-to-finish should be called ~200ms before the next track starts.  This'll be good enough for now.
+    if (player->next_track_starting_cb != NULL) {
+        player->next_track_starting_cb (player);
+    }
+}
+
 // ---------------------------------------------------------------------------
 // Internal Functions
 // ---------------------------------------------------------------------------
@@ -192,6 +209,12 @@
     // source and decoder elements) based on source URI and stream content
     player->playbin = gst_element_factory_make ("playbin2", "playbin");
     g_return_val_if_fail (player->playbin != NULL, FALSE);
+    
+    // It seems that playbin2 is terribly sensitive about precisely when setting "uri" to queue the next track
+    // will work.  So, handle the callback in native code, using player->next_uri which can be set at leisure from
+    // native code.
+    g_signal_connect (player->playbin, "about-to-finish", G_CALLBACK (bp_about_to_finish_callback), player);
+
 
     // Try to find an audio sink, prefer gconf, which typically is set to auto these days,
     // fall back on auto, which should work on windows, and as a last ditch, try alsa

=== modified file 'libbanshee/banshee-player-private.h'
--- libbanshee/banshee-player-private.h	2009-03-14 08:04:48 +0000
+++ libbanshee/banshee-player-private.h	2009-03-26 05:53:30 +0000
@@ -70,7 +70,7 @@
 typedef void (* BansheePlayerBufferingCallback)    (BansheePlayer *player, gint buffering_progress);
 typedef void (* BansheePlayerTagFoundCallback)     (BansheePlayer *player, const gchar *tag, const GValue *value);
 typedef void (* BansheePlayerVisDataCallback)      (BansheePlayer *player, gint channels, gint samples, gfloat *data, gfloat *spectrum);
-typedef void (* BansheeBufferNextTrackCallback)    (GstElement *playbin, gpointer unused);
+typedef void (* BansheePlayerNextTrackStartingCallback)    (BansheePlayer *player);
 
 struct BansheePlayer {
     // Player Callbacks
@@ -81,6 +81,7 @@
     BansheePlayerBufferingCallback buffering_cb;
     BansheePlayerTagFoundCallback tag_found_cb;
     BansheePlayerVisDataCallback vis_data_cb;
+    BansheePlayerNextTrackStartingCallback next_track_starting_cb;
 
     // Pipeline Elements
     GstElement *playbin;
@@ -140,6 +141,8 @@
     gdouble album_peak;
     gdouble track_gain;
     gdouble track_peak;
+    
+    gchar *next_uri;
 };
 
 #endif /* _BANSHEE_PLAYER_PRIVATE_H */

=== modified file 'libbanshee/banshee-player.c'
--- libbanshee/banshee-player.c	2009-03-14 08:04:48 +0000
+++ libbanshee/banshee-player.c	2009-03-26 05:53:59 +0000
@@ -198,6 +198,14 @@
 }
 
 P_INVOKE gboolean
+bp_set_next_track (BansheePlayer *player, const gchar *uri)
+{
+	g_return_val_if_fail (IS_BANSHEE_PLAYER (player), FALSE);
+	player->next_uri = g_strdup(uri);
+	return TRUE;
+}
+
+P_INVOKE gboolean
 bp_set_position (BansheePlayer *player, guint64 time_ms)
 {
     g_return_val_if_fail (IS_BANSHEE_PLAYER (player), FALSE);
@@ -340,14 +348,6 @@
 }
 
 P_INVOKE void
-bp_set_buffer_next_track_callback (BansheePlayer *player, BansheeBufferNextTrackCallback cb)
-{
-    g_return_if_fail (IS_BANSHEE_PLAYER (player));
-    g_return_if_fail (GST_IS_ELEMENT (player->playbin));
-    g_signal_connect (player->playbin, "about-to-finish", G_CALLBACK (cb), NULL);
-}
-
-P_INVOKE void
 bp_get_error_quarks (GQuark *core, GQuark *library, GQuark *resource, GQuark *stream)
 {
     *core = GST_CORE_ERROR;
@@ -355,3 +355,9 @@
     *resource = GST_RESOURCE_ERROR;
     *stream = GST_STREAM_ERROR;
 }
+
+P_INVOKE void
+bp_set_next_track_starting_callback (BansheePlayer *player, BansheePlayerNextTrackStartingCallback *cb)
+{
+    SET_CALLBACK (next_track_starting_cb);
+}

=== modified file 'src/Backends/Banshee.GStreamer/Banshee.GStreamer/PlayerEngine.cs'
--- src/Backends/Banshee.GStreamer/Banshee.GStreamer/PlayerEngine.cs	2009-03-14 08:04:48 +0000
+++ src/Backends/Banshee.GStreamer/Banshee.GStreamer/PlayerEngine.cs	2009-03-30 05:03:18 +0000
@@ -57,7 +57,7 @@
     internal delegate void BansheePlayerIterateCallback (IntPtr player);
     internal delegate void BansheePlayerBufferingCallback (IntPtr player, int buffering_progress);
     internal delegate void BansheePlayerVisDataCallback (IntPtr player, int channels, int samples, IntPtr data, IntPtr spectrum);
-    internal delegate void BansheePlayerBufferNextTrackCallback (IntPtr element, IntPtr unused);
+    internal delegate void BansheePlayerNextTrackStartingCallback (IntPtr player);
 
     internal delegate void GstTaggerTagFoundCallback (IntPtr player, string tagName, ref GLib.Value value);
     
@@ -77,11 +77,13 @@
         private BansheePlayerBufferingCallback buffering_callback;
         private BansheePlayerVisDataCallback vis_data_callback;
         private GstTaggerTagFoundCallback tag_found_callback;
-        private BansheePlayerBufferNextTrackCallback buffer_next_track_callback;
+        private BansheePlayerNextTrackStartingCallback next_track_starting_callback;
         
         private bool buffering_finished;
         private int pending_volume = -1;
         private bool xid_is_set = false;
+		private uint last_position;
+		private bool next_track_set = false;
         
         private event VisualizationDataHandler data_available = null;
         public event VisualizationDataHandler DataAvailable {
@@ -145,7 +147,7 @@
             buffering_callback = new BansheePlayerBufferingCallback (OnBuffering);
             vis_data_callback = new BansheePlayerVisDataCallback (OnVisualizationData);
             tag_found_callback = new GstTaggerTagFoundCallback (OnTagFound);
-            buffer_next_track_callback = new BansheePlayerBufferNextTrackCallback (OnBufferNextTrack);
+            next_track_starting_callback = new BansheePlayerNextTrackStartingCallback (OnNextTrackStarting);
 
             bp_set_eos_callback (handle, eos_callback);
             bp_set_iterate_callback (handle, iterate_callback);
@@ -153,7 +155,7 @@
             bp_set_state_changed_callback (handle, state_changed_callback);
             bp_set_buffering_callback (handle, buffering_callback);
             bp_set_tag_found_callback (handle, tag_found_callback);
-            bp_set_buffer_next_track_callback (handle, buffer_next_track_callback);
+            bp_set_next_track_starting_callback (handle, next_track_starting_callback);
             
             OnStateChanged (PlayerState.Ready);
             
@@ -210,6 +212,17 @@
         {
             bp_pause (handle);
         }
+
+		public override bool SetNextTrackUri (SafeUri uri)
+		{
+			IntPtr uri_ptr = GLib.Marshaller.StringToPtrGStrdup (uri.AbsoluteUri);
+			try {
+			     bp_set_next_track (handle, uri_ptr);
+			} finally {
+				GLib.Marshaller.Free (uri_ptr);
+			}
+            return true;
+		}
         
         public override void VideoExpose (IntPtr window, bool direct)
         {
@@ -232,9 +245,20 @@
             Close (false);
             OnEventChanged (PlayerEvent.EndOfStream);
         }
+
+        private void OnNextTrackStarting (IntPtr player)
+        {
+            OnEventChanged (PlayerEvent.StartOfStream);
+            next_track_set = false;
+        }
         
         private void OnIterate (IntPtr player)
         {
+			if (((Length - Position) < 1000 * 5) && !next_track_set) {
+				OnEventChanged (PlayerEvent.BufferNextTrack);
+				next_track_set = true;
+			}
+
             OnEventChanged (PlayerEvent.Iterate);
         }
         
@@ -325,11 +349,6 @@
         {
             OnTagFound (ProcessNativeTagResult (tagName, ref value));
         }
-
-		private void OnBufferNextTrack (IntPtr element, IntPtr unused)
-		{
-			Log.Debug ("************** Receiving about_to_finish callback ************************");
-		}
         
         private void OnVisualizationData (IntPtr player, int channels, int samples, IntPtr data, IntPtr spectrum)
         {
@@ -565,8 +584,8 @@
             GstTaggerTagFoundCallback cb);
 
         [DllImport ("libbanshee")]
-        private static extern void bp_set_buffer_next_track_callback (HandleRef player,
-            BansheePlayerBufferNextTrackCallback cb);
+        private static extern void bp_set_next_track_starting_callback (HandleRef player,
+            BansheePlayerNextTrackStartingCallback cb);
         
         [DllImport ("libbanshee")]
         private static extern bool bp_open (HandleRef player, IntPtr uri);
@@ -581,6 +600,9 @@
         private static extern void bp_play (HandleRef player);
         
         [DllImport ("libbanshee")]
+        private static extern bool bp_set_next_track (HandleRef player, IntPtr uri);
+
+		[DllImport ("libbanshee")]
         private static extern void bp_set_volume (HandleRef player, double volume);
         
         [DllImport("libbanshee")]

=== modified file 'src/Clients/Halie/Halie/Client.cs'
--- src/Clients/Halie/Halie/Client.cs	2009-02-25 17:31:27 +0000
+++ src/Clients/Halie/Halie/Client.cs	2009-03-29 20:44:58 +0000
@@ -131,7 +131,7 @@
                     
                     // For the playback controller
                     case "first":    controller.First ();                                    break;
-                    case "next":     controller.Next (ParseBool (arg.Value, "restart"));     break;
+                    case "next":     controller.Next (ParseBool (arg.Value, "restart"), true);     break;
                     case "previous": controller.Previous (ParseBool (arg.Value, "restart")); break;
                     case "stop-when-finished": 
                         controller.StopWhenFinished = !ParseBool (arg.Value);

=== modified file 'src/Core/Banshee.Services/Banshee.MediaEngine/PlayerEngine.cs'
--- src/Core/Banshee.Services/Banshee.MediaEngine/PlayerEngine.cs	2009-01-30 17:45:53 +0000
+++ src/Core/Banshee.Services/Banshee.MediaEngine/PlayerEngine.cs	2009-03-30 05:04:12 +0000
@@ -47,6 +47,8 @@
         
         private TrackInfo current_track;
         private SafeUri current_uri;
+		private TrackInfo pending_track;
+		private SafeUri pending_uri;
         private PlayerState current_state = PlayerState.NotReady;
         private PlayerState last_state = PlayerState.NotReady;
         
@@ -86,7 +88,42 @@
             current_track = new UnknownTrackInfo (uri);
             
             HandleOpen (uri);
-        }
+		}
+
+		public bool SetNextTrack (TrackInfo track)
+		{
+			pending_uri = track.Uri;
+			pending_track = track;
+
+			return HandleNextTrack (pending_uri);
+		}
+		
+		public bool SetNextTrack (SafeUri uri)
+		{
+			pending_uri = uri;
+			pending_track = new UnknownTrackInfo (uri);
+
+			return HandleNextTrack (uri);
+		}
+
+		private bool HandleNextTrack (SafeUri uri)
+		{
+			if (current_state != PlayerState.Playing) {
+				// Pre-buffering the next track only makes sense when we're currently playing
+                // Instead, just open.
+				HandleOpen (uri);
+                return true;
+			}
+
+			try {
+				// Setting the next track doesn't change the player state.
+				SetNextTrackUri (uri);
+			} catch (Exception e) {
+				Log.Exception ("Failed to pre-buffer next track", e);
+				return false;
+			}
+			return true;
+		}
 
         private void HandleOpen (SafeUri uri)
         {
@@ -107,6 +144,11 @@
 
         public abstract void Pause ();
 
+		public virtual bool SetNextTrackUri (SafeUri uri)
+		{
+            return false;
+        }
+
         public virtual void VideoExpose (IntPtr displayContext, bool direct)
         {
             throw new NotImplementedException ("Engine must implement VideoExpose since this method only gets called when SupportsVideo is true");
@@ -148,6 +190,12 @@
         
         protected void OnEventChanged (PlayerEvent evnt)
         {
+			if (evnt == PlayerEvent.StartOfStream && pending_track != null) {
+				current_track = pending_track;
+				current_uri = pending_uri;
+				pending_track = null;
+				pending_uri = null;
+			}
             OnEventChanged (new PlayerEventArgs (evnt));
         }
         

=== modified file 'src/Core/Banshee.Services/Banshee.MediaEngine/PlayerEngineService.cs'
--- src/Core/Banshee.Services/Banshee.MediaEngine/PlayerEngineService.cs	2009-02-02 19:25:23 +0000
+++ src/Core/Banshee.Services/Banshee.MediaEngine/PlayerEngineService.cs	2009-03-19 06:56:24 +0000
@@ -268,7 +268,26 @@
         {
             OpenCheck (new SafeUri (uri));
         }
-        
+
+
+		public bool SetNextTrack (TrackInfo track)
+		{
+			if (active_engine != FindSupportingEngine (track.Uri)) {
+				// If the current engine does not support the next track, it will be extremely difficult to make the
+				// transition across playback engines gapless.  Just refuse to try, instead.
+				return false;
+			}
+			return active_engine.SetNextTrack (track);
+		}
+
+		public bool SetNextTrack (SafeUri uri)
+		{
+			if (active_engine != FindSupportingEngine (uri)) {
+				return false;
+			}
+			return active_engine.SetNextTrack (uri);
+		}
+
         public void OpenPlay (TrackInfo track)
         {
             OpenPlay (track, true);
@@ -317,7 +336,8 @@
 
             IncrementLastPlayed ();
             
-            FindSupportingEngine (uri);
+            PlayerEngine supportingEngine = FindSupportingEngine (uri);
+			SwitchToEngine (supportingEngine);
             CheckPending ();
             
             if (track != null) {
@@ -348,35 +368,40 @@
             }
         }
         
-        private void FindSupportingEngine (SafeUri uri)
+        private PlayerEngine FindSupportingEngine (SafeUri uri)
         {
             foreach (PlayerEngine engine in engines) {
                 foreach (string extension in engine.ExplicitDecoderCapabilities) {
                     if (!uri.AbsoluteUri.EndsWith (extension)) {
                         continue;
-                    } else if (active_engine != engine) {
-                        Close ();
-                        pending_engine = engine;
-                        Log.DebugFormat ("Switching engine to: {0}", engine.GetType ());
                     }
-                    return;
+					return engine;
                 }
             }
         
             foreach (PlayerEngine engine in engines) {
                 foreach (string scheme in engine.SourceCapabilities) {
                     bool supported = scheme == uri.Scheme;
-                    if (supported && active_engine != engine) {
-                        Close ();
-                        pending_engine = engine;
-                        Log.DebugFormat ("Switching engine to: {0}", engine.GetType ());
-                        return;
-                    } else if (supported) {
-                        return;
+                    if (supported) {
+						return engine;
                     }
                 }
             }
+			// If none of our engines support this URI, return the currently active one.
+			// There doesn't seem to be anything better to do.
+			return active_engine;
         }
+
+		private bool SwitchToEngine (PlayerEngine switchTo)
+		{
+			if (active_engine != switchTo) {
+				Close ();
+				pending_engine = switchTo;
+				Log.DebugFormat ("Switching engine to: {0}", switchTo.GetType ());
+				return true;
+			}
+			return false;
+		}
         
         public void Close ()
         {
@@ -611,7 +636,8 @@
             | PlayerEvent.Error
             | PlayerEvent.Volume
             | PlayerEvent.Metadata
-            | PlayerEvent.TrackInfoUpdated;
+            | PlayerEvent.TrackInfoUpdated
+            | PlayerEvent.BufferNextTrack;
         
         private const PlayerEvent event_default_mask = event_all_mask & ~PlayerEvent.Iterate;
         

=== modified file 'src/Core/Banshee.Services/Banshee.MediaEngine/PlayerEvent.cs'
--- src/Core/Banshee.Services/Banshee.MediaEngine/PlayerEvent.cs	2008-05-04 21:42:09 +0000
+++ src/Core/Banshee.Services/Banshee.MediaEngine/PlayerEvent.cs	2009-03-19 06:26:29 +0000
@@ -108,7 +108,8 @@
         Error = 64,
         Volume = 128,
         Metadata = 256,
-        TrackInfoUpdated = 512
+        TrackInfoUpdated = 512,
+        BufferNextTrack = 1024
     }
     
     public enum PlayerState 

=== modified file 'src/Core/Banshee.Services/Banshee.PlaybackController/IBasicPlaybackController.cs'
--- src/Core/Banshee.Services/Banshee.PlaybackController/IBasicPlaybackController.cs	2008-10-02 00:36:15 +0000
+++ src/Core/Banshee.Services/Banshee.PlaybackController/IBasicPlaybackController.cs	2009-03-29 20:45:31 +0000
@@ -31,7 +31,7 @@
     public interface IBasicPlaybackController
     {
         bool First ();
-        bool Next (bool restart);
+        bool Next (bool restart, bool immediate);
         bool Previous (bool restart);
     }
 }

=== modified file 'src/Core/Banshee.Services/Banshee.PlaybackController/IPlaybackControllerService.cs'
--- src/Core/Banshee.Services/Banshee.PlaybackController/IPlaybackControllerService.cs	2008-05-28 17:27:30 +0000
+++ src/Core/Banshee.Services/Banshee.PlaybackController/IPlaybackControllerService.cs	2009-03-27 10:45:42 +0000
@@ -46,7 +46,7 @@
         event PlaybackControllerStoppedHandler Stopped;
         
         void First ();
-        void Next (bool restart);
+        void Next (bool restart, bool immediate);
         void Previous (bool restart);
         
         PlaybackShuffleMode ShuffleMode { get; set; }

=== modified file 'src/Core/Banshee.Services/Banshee.PlaybackController/PlaybackControllerService.cs'
--- src/Core/Banshee.Services/Banshee.PlaybackController/PlaybackControllerService.cs	2008-10-09 19:13:48 +0000
+++ src/Core/Banshee.Services/Banshee.PlaybackController/PlaybackControllerService.cs	2009-03-30 04:58:30 +0000
@@ -90,8 +90,9 @@
                 PlayerEvent.EndOfStream | 
                 PlayerEvent.StartOfStream |
                 PlayerEvent.StateChange |
-                PlayerEvent.Error, 
-                true);
+                PlayerEvent.Error |
+			    PlayerEvent.BufferNextTrack,
+			    true);
 
             ServiceManager.SourceManager.ActiveSourceChanged += delegate {
                 ITrackModelSource active_source = ServiceManager.SourceManager.ActiveSource as ITrackModelSource;
@@ -126,9 +127,15 @@
             switch (args.Event) {
                 case PlayerEvent.StartOfStream:
                     consecutive_errors = 0;
+				Log.DebugFormat ("ControllerService: StartOfStream signalled.  Our current track: {0}, playback_engine.CurrentTrack: {1}", CurrentTrack == null ? "None" : CurrentTrack.Uri.AbsoluteUri,
+				                 player_engine.CurrentTrack == null ? "None" : player_engine.CurrentTrack.Uri.AbsoluteUri);
+				CurrentTrack = player_engine.CurrentTrack;
                     break;
                 case PlayerEvent.EndOfStream:
-                    EosTransition ();
+                    NextTrackTransition (true);
+                    break;
+                case PlayerEvent.BufferNextTrack:
+                    NextTrackTransition (false);
                     break;
                 case PlayerEvent.Error:
                     if (++consecutive_errors >= 5) {
@@ -140,7 +147,7 @@
                     
                     CancelErrorTransition ();
                     // TODO why is this so long? any reason not to be instantaneous?
-                    Application.RunTimeout (250, EosTransition);
+                    Application.RunTimeout (250, delegate {return NextTrackTransition (true);});
                     break;
                 case PlayerEvent.StateChange:
                     if (((PlayerEventStateChangeArgs)args).Current != PlayerState.Loading) {
@@ -172,13 +179,13 @@
             }
         }
         
-        private bool EosTransition ()
+        private bool NextTrackTransition (bool immediate)
         {
             if (!StopWhenFinished) {
                 if (RepeatMode == PlaybackRepeatMode.RepeatSingle) {
                     QueuePlayTrack ();
                 } else {
-                    Next ();
+                    Next (RepeatMode == PlaybackRepeatMode.RepeatAll, immediate);
                 }
             } else {
                 OnStopped ();
@@ -207,10 +214,10 @@
         
         public void Next ()
         {
-            Next (RepeatMode == PlaybackRepeatMode.RepeatAll);
+            Next (RepeatMode == PlaybackRepeatMode.RepeatAll, true);
         }
         
-        public void Next (bool restart)
+        public void Next (bool restart, bool immediate)
         {
             CancelErrorTransition ();
             
@@ -219,9 +226,9 @@
 
             player_engine.IncrementLastPlayed ();
             
-            if (Source is IBasicPlaybackController && ((IBasicPlaybackController)Source).Next (restart)) {
+            if (Source is IBasicPlaybackController && ((IBasicPlaybackController)Source).Next (restart, immediate)) {
             } else {
-                ((IBasicPlaybackController)this).Next (restart);
+                ((IBasicPlaybackController)this).Next (restart, immediate);
             }
             
             OnTransition ();
@@ -257,12 +264,12 @@
             return true;
         }
         
-        bool IBasicPlaybackController.Next (bool restart)
+        bool IBasicPlaybackController.Next (bool restart, bool immediate)
         {
             TrackInfo tmp_track = CurrentTrack;
 
             if (next_stack.Count > 0) {
-                CurrentTrack = next_stack.Pop ();
+                changing_to_track = next_stack.Pop ();
                 if (tmp_track != null) {
                     previous_stack.Push (tmp_track);
                 }
@@ -275,11 +282,15 @@
                 } else {
                     return true;
                 }
-                
-                CurrentTrack = next_track;
+
+                changing_to_track = next_track;
             }
             
-            QueuePlayTrack ();
+            if (immediate) {
+                QueuePlayTrack ();
+            } else {
+                player_engine.SetNextTrack (changing_to_track);
+            }
             return true;
         }
         

=== modified file 'src/Extensions/Banshee.InternetRadio/Banshee.InternetRadio/InternetRadioSource.cs'
--- src/Extensions/Banshee.InternetRadio/Banshee.InternetRadio/InternetRadioSource.cs	2009-02-09 20:28:02 +0000
+++ src/Extensions/Banshee.InternetRadio/Banshee.InternetRadio/InternetRadioSource.cs	2009-03-29 20:42:29 +0000
@@ -279,7 +279,7 @@
             return false;
         }
         
-        public bool Next (bool restart)
+        public bool Next (bool restart, bool immediate)
         {
             RadioTrackInfo radio_track = ServiceManager.PlaybackController.CurrentTrack as RadioTrackInfo;
             if (radio_track != null && radio_track.PlayNextStream ()) {

=== modified file 'src/Extensions/Banshee.Lastfm/Banshee.Lastfm.Radio/StationSource.cs'
--- src/Extensions/Banshee.Lastfm/Banshee.Lastfm.Radio/StationSource.cs	2009-02-27 22:23:02 +0000
+++ src/Extensions/Banshee.Lastfm/Banshee.Lastfm.Radio/StationSource.cs	2009-03-29 20:43:27 +0000
@@ -294,15 +294,19 @@
 
         bool IBasicPlaybackController.First ()
         {
-            return ((IBasicPlaybackController)this).Next (false);
+            return ((IBasicPlaybackController)this).Next (false, true);
         }
         
         private bool playback_requested;    
-        bool IBasicPlaybackController.Next (bool restart)
+        bool IBasicPlaybackController.Next (bool restart, bool immediate)
         {
             TrackInfo next = NextTrack;
             if (next != null) {
-                ServiceManager.PlayerEngine.OpenPlay (next);
+                if (immediate) {
+                    ServiceManager.PlayerEngine.OpenPlay (next);
+                } else {
+                    ServiceManager.PlayerEngine.SetNextTrack (next);
+                }
             }  else {
                 playback_requested = true;
             }
@@ -372,7 +376,7 @@
 
                             if (playback_requested) {
                                 if (this == ServiceManager.PlaybackController.Source ) {
-                                    ((IBasicPlaybackController)this).Next (false);
+                                    ((IBasicPlaybackController)this).Next (false, true);
                                 }
                                 playback_requested = false;
                             }

=== modified file 'src/Extensions/Banshee.PlayQueue/Banshee.PlayQueue/PlayQueueSource.cs'
--- src/Extensions/Banshee.PlayQueue/Banshee.PlayQueue/PlayQueueSource.cs	2008-10-31 19:56:47 +0000
+++ src/Extensions/Banshee.PlayQueue/Banshee.PlayQueue/PlayQueueSource.cs	2009-04-07 07:51:43 +0000
@@ -235,25 +235,32 @@
 
         bool IBasicPlaybackController.First ()
         {
-            return ((IBasicPlaybackController)this).Next (false);
+            return ((IBasicPlaybackController)this).Next (false, true);
         }
         
-        bool IBasicPlaybackController.Next (bool restart)
+        bool IBasicPlaybackController.Next (bool restart, bool immediate)
         {
+            
+           Hyena.Log.DebugFormat ("PlayQueue.Next({0},{1}) called", restart, immediate);
+//            Hyena.Log.DebugFormat ("{0} - {1} - {2}", TrackModel[0].LocalPath, TrackModel[1].LocalPath, TrackModel[2].LocalPath);
             RemovePlayingTrack ();
             
             if (Count == 0) {
                 ServiceManager.PlaybackController.Source = PriorSource;
                 if (was_playing) {
                     ServiceManager.PlaybackController.PriorTrack = prior_playback_track;
-                    ServiceManager.PlaybackController.Next (restart);
+                    ServiceManager.PlaybackController.Next (restart, immediate);
                 } else {
                     ServiceManager.PlayerEngine.Close ();
                 }
                 return true;
             }
-            
-            ServiceManager.PlayerEngine.OpenPlay ((DatabaseTrackInfo)TrackModel[0]);
+
+            if (immediate) {
+                ServiceManager.PlayerEngine.OpenPlay ((DatabaseTrackInfo)TrackModel[0]);
+            } else {
+                ServiceManager.PlayerEngine.SetNextTrack ((DatabaseTrackInfo)TrackModel[0]);
+            }
             return true;
         }
         
@@ -264,7 +271,9 @@
         
         private bool RemovePlayingTrack ()
         {
+            Hyena.Log.Debug ("RemovePlayingTrack called..");
             if (playing_track != null) {
+                Hyena.Log.DebugFormat ("...playing_track is {0}", playing_track.LocalPath);
                 RemoveTrack (playing_track);
                 playing_track = null;
                 return true;

