[banshee/gapless-ng: 413/836] Merge gapless work to trunk.
- From: Christopher James Halse Rogers <chrishr src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [banshee/gapless-ng: 413/836] Merge gapless work to trunk.
- Date: Thu, 25 Feb 2010 22:44:28 +0000 (UTC)
commit 2966db6bcad05fd2a4d43366e3cd34b6d43aab5c
Merge: 5909a8e aab7faf
Author: Christopher James Halse Rogers <raof ubuntu com>
Date: Mon Nov 16 11:22:42 2009 +1100
Merge gapless work to trunk.
Fix text conflicts caused by the trailing-whitespace fixes
libbanshee/banshee-player-pipeline.c | 107 ++++++++++++++++----
libbanshee/banshee-player-private.h | 14 +++
libbanshee/banshee-player-video.c | 16 ++--
libbanshee/banshee-player.c | 40 +++++++
.../Banshee.GStreamer/PlayerEngine.cs | 104 +++++++++++++++++++
.../Banshee.MediaEngine/PlayerEngine.cs | 50 +++++++++
.../Banshee.MediaEngine/PlayerEngineService.cs | 85 ++++++++++++----
.../Banshee.MediaEngine/PlayerEvent.cs | 3 +-
.../IBasicPlaybackController.cs | 2 +-
.../PlaybackControllerService.cs | 84 +++++++++-------
.../Banshee.InternetRadio/InternetRadioSource.cs | 14 +++-
.../Banshee.Lastfm.Radio/StationSource.cs | 23 +++--
.../Banshee.PlayQueue/PlayQueueSource.cs | 15 ++-
13 files changed, 461 insertions(+), 96 deletions(-)
---
diff --cc src/Backends/Banshee.GStreamer/Banshee.GStreamer/PlayerEngine.cs
index 3193187,788a3e2..589b9b1
--- a/src/Backends/Banshee.GStreamer/Banshee.GStreamer/PlayerEngine.cs
+++ b/src/Backends/Banshee.GStreamer/Banshee.GStreamer/PlayerEngine.cs
@@@ -79,11 -82,16 +82,16 @@@ namespace Banshee.GStreame
private BansheePlayerVisDataCallback vis_data_callback;
private VideoPipelineSetupHandler video_pipeline_setup_callback;
private GstTaggerTagFoundCallback tag_found_callback;
+ private BansheePlayerNextTrackStartingCallback next_track_starting_callback;
+ private BansheePlayerAboutToFinishCallback about_to_finish_callback;
-
+
private bool buffering_finished;
private int pending_volume = -1;
private bool xid_is_set = false;
+ private bool gapless_enabled;
+ private EventWaitHandle next_track_set;
-
++
private event VisualizationDataHandler data_available = null;
public event VisualizationDataHandler DataAvailable {
add {
@@@ -142,9 -152,12 +152,12 @@@
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_next_track_starting_callback (handle, next_track_starting_callback);
bp_set_video_pipeline_setup_callback (handle, video_pipeline_setup_callback);
+
+ next_track_set = new EventWaitHandle (false, EventResetMode.AutoReset);
}
-
+
protected override void Initialize ()
{
if (!bp_initialize_pipeline (handle)) {
@@@ -158,11 -171,12 +171,12 @@@
if (pending_volume >= 0) {
Volume = (ushort)pending_volume;
}
-
+
InstallPreferences ();
ReplayGainEnabled = ReplayGainEnabledSchema.Get ();
+ GaplessEnabled = GaplessEnabledSchema.Get ();
}
-
+
public override void Dispose ()
{
UninstallPreferences ();
@@@ -210,6 -224,23 +224,23 @@@
bp_pause (handle);
}
+ public override void SetNextTrackUri (SafeUri uri)
+ {
+ // If there isn't a next track for us, release the block on the about-to-finish callback.
+ if (uri == null) {
+ next_track_set.Set ();
+ bp_set_next_track (handle, IntPtr.Zero);
+ return;
+ }
+ IntPtr uri_ptr = GLib.Marshaller.StringToPtrGStrdup (uri.AbsoluteUri);
+ try {
+ bp_set_next_track (handle, uri_ptr);
+ } finally {
+ GLib.Marshaller.Free (uri_ptr);
+ }
+ next_track_set.Set ();
+ }
-
++
public override void VideoExpose (IntPtr window, bool direct)
{
bp_video_window_expose (handle, window, direct);
@@@ -230,8 -261,39 +261,39 @@@
{
Close (false);
OnEventChanged (PlayerEvent.EndOfStream);
+ if (!GaplessEnabled) {
+ OnEventChanged (PlayerEvent.RequestNextTrack);
+ }
+ }
+
+ private void OnNextTrackStarting (IntPtr player)
+ {
+ if (GaplessEnabled) {
+ OnEventChanged (PlayerEvent.EndOfStream);
+ OnEventChanged (PlayerEvent.StartOfStream);
+ }
+ }
+
+ private void OnAboutToFinish (IntPtr player)
+ {
+ // This is needed to make Shuffle-by-* work.
+ // Shuffle-by-* uses the LastPlayed field to determine what track in the grouping to play next.
+ // Therefore, we need to update this before requesting the next track.
+ //
+ // This will be overridden by IncrementLastPlayed () called by
+ // PlaybackControllerService's EndOfStream handler.
+ CurrentTrack.LastPlayed = DateTime.Now;
+ CurrentTrack.Save ();
+
+ OnEventChanged (PlayerEvent.RequestNextTrack);
+ // Gapless playback with Playbin2 requires that the about-to-finish callback does not return until
+ // the next uri has been set. Block here for a second or until the RequestNextTrack event has
+ // finished triggering.
+ if (!next_track_set.WaitOne (1000, false)) {
+ Log.Debug ("[Gapless] Timed out while waiting for next_track_set to be raised");
+ }
- }
-
+ }
+
private void OnIterate (IntPtr player)
{
OnEventChanged (PlayerEvent.Iterate);
@@@ -550,37 -627,52 +628,52 @@@
if (service == null) {
return;
}
-
- replaygain_preference = service["general"]["misc"].Add (new SchemaPreference<bool> (ReplayGainEnabledSchema,
+
+ replaygain_preference = service["general"]["misc"].Add (new SchemaPreference<bool> (ReplayGainEnabledSchema,
Catalog.GetString ("_Enable ReplayGain correction"),
- Catalog.GetString ("For tracks that have ReplayGain data, automatically scale (normalize) playback volume."),
+ Catalog.GetString ("For tracks that have ReplayGain data, automatically scale (normalize) playback volume"),
delegate { ReplayGainEnabled = ReplayGainEnabledSchema.Get (); }
));
+ gapless_preference = service["general"]["misc"].Add (new SchemaPreference<bool> (GaplessEnabledSchema,
+ Catalog.GetString ("Enable _gapless playback"),
+ Catalog.GetString ("Eliminate the small playback gap on track change. Useful for concept albums and classical music."),
+ delegate { GaplessEnabled = GaplessEnabledSchema.Get (); }
+ ));
}
-
+
private void UninstallPreferences ()
{
PreferenceService service = ServiceManager.Get<PreferenceService> ();
if (service == null) {
return;
}
-
+
service["general"]["misc"].Remove (replaygain_preference);
+ service["general"]["misc"].Remove (gapless_preference);
replaygain_preference = null;
+ gapless_preference = null;
}
-
+
public static readonly SchemaEntry<bool> ReplayGainEnabledSchema = new SchemaEntry<bool> (
- "player_engine", "replay_gain_enabled",
+ "player_engine", "replay_gain_enabled",
false,
"Enable ReplayGain",
"If ReplayGain data is present on tracks when playing, allow volume scaling"
);
+ public static readonly SchemaEntry<bool> GaplessEnabledSchema = new SchemaEntry<bool> (
+ "player_engine", "gapless_playback_enabled",
+ true,
+ "Enable gapless playback",
+ "Eliminate the small playback gap on track change. Useful for concept albums & classical music. EXPERIMENTAL"
+ );
+
+
#endregion
-
+
[DllImport ("libbanshee.dll")]
private static extern IntPtr bp_new ();
-
+
[DllImport ("libbanshee.dll")]
private static extern bool bp_initialize_pipeline (HandleRef player);
@@@ -617,35 -709,46 +710,46 @@@
GstTaggerTagFoundCallback cb);
[DllImport ("libbanshee.dll")]
+ private static extern void bp_set_next_track_starting_callback (HandleRef player,
+ BansheePlayerNextTrackStartingCallback cb);
+
+ [DllImport ("libbanshee.dll")]
+ private static extern void bp_set_about_to_finish_callback (HandleRef player,
+ BansheePlayerAboutToFinishCallback cb);
-
++
+ [DllImport ("libbanshee.dll")]
private static extern bool bp_open (HandleRef player, IntPtr uri);
-
+
[DllImport ("libbanshee.dll")]
private static extern void bp_stop (HandleRef player, bool nullstate);
-
+
[DllImport ("libbanshee.dll")]
private static extern void bp_pause (HandleRef player);
-
+
[DllImport ("libbanshee.dll")]
private static extern void bp_play (HandleRef player);
-
+
[DllImport ("libbanshee.dll")]
+ private static extern bool bp_set_next_track (HandleRef player, IntPtr uri);
+
+ [DllImport ("libbanshee.dll")]
private static extern void bp_set_volume (HandleRef player, double volume);
-
+
[DllImport("libbanshee.dll")]
private static extern double bp_get_volume (HandleRef player);
-
+
[DllImport ("libbanshee.dll")]
private static extern bool bp_can_seek (HandleRef player);
-
+
[DllImport ("libbanshee.dll")]
private static extern bool bp_set_position (HandleRef player, ulong time_ms);
-
+
[DllImport ("libbanshee.dll")]
private static extern ulong bp_get_position (HandleRef player);
-
+
[DllImport ("libbanshee.dll")]
private static extern ulong bp_get_duration (HandleRef player);
-
+
[DllImport ("libbanshee.dll")]
private static extern bool bp_get_pipeline_elements (HandleRef player, out IntPtr playbin,
out IntPtr audiobin, out IntPtr audiotee);
diff --cc src/Core/Banshee.Services/Banshee.MediaEngine/PlayerEngine.cs
index b074d2b,435b594..e5f31b0
--- a/src/Core/Banshee.Services/Banshee.MediaEngine/PlayerEngine.cs
+++ b/src/Core/Banshee.Services/Banshee.MediaEngine/PlayerEngine.cs
@@@ -42,17 -42,19 +42,19 @@@ namespace Banshee.MediaEngin
{
public const int VolumeDelta = 10;
public const int SkipDelta = 10;
-
+
public event PlayerEventHandler EventChanged;
-
+
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;
-
+
// will be changed to PlayerState.Idle after going to PlayerState.Ready
- private PlayerState idle_state = PlayerState.NotReady;
-
+ private PlayerState idle_state = PlayerState.NotReady;
+
protected abstract void OpenUri (SafeUri uri);
internal protected virtual bool DelayedInitialize {
@@@ -160,9 -203,16 +203,16 @@@
{
OnEventChanged (new PlayerEventArgs (evnt));
}
-
+
protected virtual void OnEventChanged (PlayerEventArgs args)
{
+ if (args.Event == PlayerEvent.StartOfStream && pending_track != null) {
+ Log.DebugFormat ("OnEventChanged called with StartOfStream. Replacing current_track: \"{0}\" with pending_track: \"{1}\"", current_track.DisplayTrackTitle, pending_track.DisplayTrackTitle);
+ current_track = pending_track;
+ current_uri = pending_uri;
+ pending_track = null;
+ pending_uri = null;
+ }
if (ThreadAssist.InMainThread) {
RaiseEventChanged (args);
} else {
diff --cc src/Core/Banshee.Services/Banshee.MediaEngine/PlayerEngineService.cs
index 2ad3f74,fffc1b0..22cd520
--- a/src/Core/Banshee.Services/Banshee.MediaEngine/PlayerEngineService.cs
+++ b/src/Core/Banshee.Services/Banshee.MediaEngine/PlayerEngineService.cs
@@@ -246,10 -246,14 +246,14 @@@ namespace Banshee.MediaEngin
}
}
+ if (args.Event == PlayerEvent.StartOfStream) {
+ incremented_last_played = false;
+ }
-
++
RaiseEvent (args);
-
+
// Do not raise iterate across DBus to avoid so many calls;
- // DBus clients should do their own iterating and
+ // DBus clients should do their own iterating and
// event/state checking locally
if (args.Event == PlayerEvent.Iterate) {
return;
@@@ -303,6 -307,47 +307,46 @@@
OpenCheck (new SafeUri (uri));
}
-
+ public void SetNextTrack (TrackInfo track)
+ {
+ if (track != null && EnsureActiveEngineCanPlay (track.Uri)) {
+ active_engine.SetNextTrack (track);
+ } else {
+ active_engine.SetNextTrack ((TrackInfo) null);
+ }
+ }
+
+ public void SetNextTrack (SafeUri uri)
+ {
+ if (EnsureActiveEngineCanPlay (uri)) {
+ active_engine.SetNextTrack (uri);
+ } else {
+ active_engine.SetNextTrack ((SafeUri) null);
+ }
+ }
+
+ private bool EnsureActiveEngineCanPlay (SafeUri uri)
+ {
+ if (uri == null) {
+ // No engine can play the null URI.
+ return false;
+ }
+ if (active_engine != FindSupportingEngine (uri)) {
+ if (active_engine.CurrentState == PlayerState.Playing) {
+ // If we're currently playing then we can't switch engines now.
+ // We can't ensure the active engine can play this URI.
+ return false;
+ } else {
+ // If we're not playing, we can switch the active engine to
+ // something that will play this URI.
+ SwitchToEngine (FindSupportingEngine (uri));
+ CheckPending ();
+ return true;
+ }
+ }
+ return true;
+ }
+
public void OpenPlay (TrackInfo track)
{
OpenPlay (track, true);
@@@ -349,17 -394,14 +393,14 @@@
return;
}
- IncrementLastPlayed ();
-
- FindSupportingEngine (uri);
+ PlayerEngine supportingEngine = FindSupportingEngine (uri);
+ SwitchToEngine (supportingEngine);
CheckPending ();
-
+
if (track != null) {
active_engine.Open (track);
- incremented_last_played = false;
} else if (uri != null) {
active_engine.Open (uri);
- incremented_last_played = false;
}
if (play) {
@@@ -380,22 -422,18 +421,18 @@@
incremented_last_played = true;
}
}
-
+
- 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;
@@@ -409,8 -442,22 +441,22 @@@
}
}
}
+ // 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 ()
{
Close (false);
@@@ -644,10 -691,11 +690,11 @@@
| PlayerEvent.Error
| PlayerEvent.Volume
| PlayerEvent.Metadata
- | PlayerEvent.TrackInfoUpdated;
+ | PlayerEvent.TrackInfoUpdated
+ | PlayerEvent.RequestNextTrack;
-
+
private const PlayerEvent event_default_mask = event_all_mask & ~PlayerEvent.Iterate;
-
+
private static void VerifyEventMask (PlayerEvent eventMask)
{
if (eventMask <= PlayerEvent.None || eventMask > event_all_mask) {
diff --cc src/Core/Banshee.Services/Banshee.MediaEngine/PlayerEvent.cs
index 96b1b79,aa982ea..a5c714f
--- a/src/Core/Banshee.Services/Banshee.MediaEngine/PlayerEvent.cs
+++ b/src/Core/Banshee.Services/Banshee.MediaEngine/PlayerEvent.cs
@@@ -108,10 -108,11 +108,11 @@@ namespace Banshee.MediaEngin
Error = 64,
Volume = 128,
Metadata = 256,
- TrackInfoUpdated = 512
+ TrackInfoUpdated = 512,
+ RequestNextTrack = 1024
}
-
- public enum PlayerState
+
+ public enum PlayerState
{
NotReady,
Ready,
diff --cc src/Core/Banshee.Services/Banshee.PlaybackController/PlaybackControllerService.cs
index 577c6f8,4e454bc..0376103
--- a/src/Core/Banshee.Services/Banshee.PlaybackController/PlaybackControllerService.cs
+++ b/src/Core/Banshee.Services/Banshee.PlaybackController/PlaybackControllerService.cs
@@@ -90,10 -90,11 +90,11 @@@ namespace Banshee.PlaybackControlle
player_engine = ServiceManager.PlayerEngine;
player_engine.PlayWhenIdleRequest += OnPlayerEnginePlayWhenIdleRequest;
player_engine.ConnectEvent (OnPlayerEvent,
+ PlayerEvent.RequestNextTrack |
- PlayerEvent.EndOfStream |
+ PlayerEvent.EndOfStream |
PlayerEvent.StartOfStream |
PlayerEvent.StateChange |
- PlayerEvent.Error,
+ PlayerEvent.Error,
true);
ServiceManager.SourceManager.ActiveSourceChanged += delegate {
@@@ -164,9 -165,12 +165,12 @@@
transition_track_started = true;
}
break;
+ case PlayerEvent.RequestNextTrack:
+ RequestTrackHandler ();
+ break;
- }
+ }
}
-
+
private void CancelErrorTransition ()
{
if (error_transition_id > 0) {
@@@ -205,29 -215,36 +215,36 @@@
} else {
((IBasicPlaybackController)this).First ();
}
-
+
//OnTransition ();
}
-
+
public void Next ()
{
- Next (RepeatMode == PlaybackRepeatMode.RepeatAll);
+ Next (RepeatMode == PlaybackRepeatMode.RepeatAll, true);
}
public void Next (bool restart)
{
+ Next (restart, true);
+ }
+
+ public void Next (bool restart, bool userRequested)
+ {
CancelErrorTransition ();
-
+
Source = NextSource;
raise_started_after_transition = true;
- player_engine.IncrementLastPlayed ();
+ if (userRequested) {
+ player_engine.IncrementLastPlayed ();
+ }
-
+
- if (Source is IBasicPlaybackController && ((IBasicPlaybackController)Source).Next (restart)) {
+ if (Source is IBasicPlaybackController && ((IBasicPlaybackController)Source).Next (restart, userRequested)) {
} else {
- ((IBasicPlaybackController)this).Next (restart);
+ ((IBasicPlaybackController)this).Next (restart, userRequested);
}
-
+
OnTransition ();
}
@@@ -260,54 -277,51 +277,51 @@@
}
return true;
}
-
+
- bool IBasicPlaybackController.Next (bool restart)
+ bool IBasicPlaybackController.Next (bool restart, bool userRequested)
{
- TrackInfo tmp_track = CurrentTrack;
-
- if (next_stack.Count > 0) {
- CurrentTrack = next_stack.Pop ();
- if (tmp_track != null) {
- previous_stack.Push (tmp_track);
- }
- } else {
- TrackInfo next_track = QueryTrack (Direction.Next, restart);
- if (next_track != null) {
- if (tmp_track != null) {
- previous_stack.Push (tmp_track);
- }
- } else {
- return true;
- }
-
- CurrentTrack = next_track;
+ if (CurrentTrack != null) {
+ previous_stack.Push (CurrentTrack);
}
- QueuePlayTrack ();
+ CurrentTrack = CalcNextTrack (Direction.Next, restart);
+ if (!userRequested) {
+ // A RequestNextTrack event should always result in SetNextTrack being called. null is acceptable.
+ player_engine.SetNextTrack (CurrentTrack);
+ } else if (CurrentTrack != null) {
+ QueuePlayTrack ();
+ }
return true;
}
-
+
bool IBasicPlaybackController.Previous (bool restart)
{
if (CurrentTrack != null && previous_stack.Count > 0) {
next_stack.Push (current_track);
}
- if (previous_stack.Count > 0) {
- CurrentTrack = previous_stack.Pop ();
- } else {
- TrackInfo track = CurrentTrack = QueryTrack (Direction.Previous, restart);
- if (track != null) {
- CurrentTrack = track;
- } else {
- return true;
- }
+ CurrentTrack = CalcNextTrack (Direction.Previous, restart);
+ if (CurrentTrack != null) {
+ QueuePlayTrack ();
}
-
+
return true;
}
+ private TrackInfo CalcNextTrack (Direction direction, bool restart)
+ {
+ if (direction == Direction.Previous) {
+ if (previous_stack.Count > 0) {
+ return previous_stack.Pop ();
+ }
+ } else if (direction == Direction.Next) {
+ if (next_stack.Count > 0) {
+ return next_stack.Pop ();
+ }
+ }
+ return QueryTrack (direction, restart);
+ }
-
++
private TrackInfo QueryTrack (Direction direction, bool restart)
{
Log.DebugFormat ("Querying model for track to play in {0}:{1} mode", ShuffleMode, direction);
diff --cc src/Extensions/Banshee.InternetRadio/Banshee.InternetRadio/InternetRadioSource.cs
index 7447515,e066c5d..5d700b7
--- a/src/Extensions/Banshee.InternetRadio/Banshee.InternetRadio/InternetRadioSource.cs
+++ b/src/Extensions/Banshee.InternetRadio/Banshee.InternetRadio/InternetRadioSource.cs
@@@ -278,9 -278,21 +278,21 @@@ namespace Banshee.InternetRadi
{
return false;
}
-
+
- public bool Next (bool restart)
+ public bool Next (bool restart, bool userRequested)
{
+ /*
+ * TODO: It should be technically possible to handle userRequested=False
+ * correctly here, but the current implementation is quite hostile.
+ * For the moment, just SetNextTrack (null), and go on to OpenPlay if
+ * the engine isn't currently playing.
+ */
+ if (!userRequested) {
+ ServiceManager.PlayerEngine.SetNextTrack ((SafeUri)null);
+ if (ServiceManager.PlayerEngine.IsPlaying ()) {
+ return true;
+ }
+ }
RadioTrackInfo radio_track = ServiceManager.PlaybackController.CurrentTrack as RadioTrackInfo;
if (radio_track != null && radio_track.PlayNextStream ()) {
return true;
diff --cc src/Extensions/Banshee.Lastfm/Banshee.Lastfm.Radio/StationSource.cs
index 2aeffce,bf3651e..6238bd0
--- a/src/Extensions/Banshee.Lastfm/Banshee.Lastfm.Radio/StationSource.cs
+++ b/src/Extensions/Banshee.Lastfm/Banshee.Lastfm.Radio/StationSource.cs
@@@ -294,17 -294,24 +294,24 @@@ namespace Banshee.Lastfm.Radi
bool IBasicPlaybackController.First ()
{
- return ((IBasicPlaybackController)this).Next (false);
+ return ((IBasicPlaybackController)this).Next (false, true);
}
-
+
- private bool playback_requested;
- bool IBasicPlaybackController.Next (bool restart)
+ private bool playback_requested;
+ bool IBasicPlaybackController.Next (bool restart, bool userRequested)
{
TrackInfo next = NextTrack;
- if (next != null) {
- ServiceManager.PlayerEngine.OpenPlay (next);
- } else {
- playback_requested = true;
+ if (userRequested) {
+ if (next != null) {
+ ServiceManager.PlayerEngine.OpenPlay (next);
+ } else {
+ playback_requested = true;
+ }
+ } else {
+ // We want to unconditionally SetNextTrack.
+ // Passing null is OK.
+ ServiceManager.PlayerEngine.SetNextTrack (next);
+ playback_requested = next == null;
}
return true;
}
diff --cc src/Extensions/Banshee.PlayQueue/Banshee.PlayQueue/PlayQueueSource.cs
index 25b1687,6a1d054..6eec3aa
--- a/src/Extensions/Banshee.PlayQueue/Banshee.PlayQueue/PlayQueueSource.cs
+++ b/src/Extensions/Banshee.PlayQueue/Banshee.PlayQueue/PlayQueueSource.cs
@@@ -518,10 -478,10 +518,10 @@@ namespace Banshee.PlayQueu
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 userRequested)
{
if (current_track != null && ServiceManager.PlayerEngine.CurrentTrack == current_track) {
int index = TrackModel.IndexOf (current_track) + 1;
@@@ -539,10 -502,14 +542,14 @@@
return true;
}
- ServiceManager.PlayerEngine.OpenPlay (current_track);
+ if (userRequested) {
+ ServiceManager.PlayerEngine.OpenPlay (current_track);
+ } else {
+ ServiceManager.PlayerEngine.SetNextTrack (current_track);
+ }
return true;
}
-
+
bool IBasicPlaybackController.Previous (bool restart)
{
if (current_track != null && ServiceManager.PlayerEngine.CurrentTrack == current_track) {
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]