banshee r4988 - in trunk/banshee: . src/Core/Banshee.Services/Banshee.MediaEngine src/Core/Banshee.Services/Banshee.Streaming src/Core/Banshee.ThickClient/Banshee.Gui src/Core/Banshee.ThickClient/Banshee.Gui.Widgets src/Core/Banshee.Widgets/Banshee.Widgets
- From: gburt svn gnome org
- To: svn-commits-list gnome org
- Subject: banshee r4988 - in trunk/banshee: . src/Core/Banshee.Services/Banshee.MediaEngine src/Core/Banshee.Services/Banshee.Streaming src/Core/Banshee.ThickClient/Banshee.Gui src/Core/Banshee.ThickClient/Banshee.Gui.Widgets src/Core/Banshee.Widgets/Banshee.Widgets
- Date: Fri, 30 Jan 2009 18:45:53 +0000 (UTC)
Author: gburt
Date: Fri Jan 30 18:45:53 2009
New Revision: 4988
URL: http://svn.gnome.org/viewvc/banshee?rev=4988&view=rev
Log:
2009-01-30 Gabriel Burt <gabriel burt gmail com>
* src/Core/Banshee.ThickClient/Banshee.Gui/PlaybackActions.cs: Show the
pause/stop button when Loading/Loaded.
* src/Core/Banshee.ThickClient/Banshee.Gui.Widgets/ConnectedSeekSlider.cs:
Handle Loading player state, set Live property on the position label, and
use the position label's enum state property instead of a handful of bools
* src/Core/Banshee.Services/Banshee.Streaming/RadioTrackInfo.cs: Start
playing internet radio playlists in a separate thread to avoid blocking
the UI (BGO #548040, BNC #376532). Handle the case where the user
presses stop or switches to a different track while we're
downloading/processing the playlist file (previously we would have started
playing once ready, even if the user had already moved on). Also, fix
bug where errors reported by the MediaEngine (GStreamer) weren't shown to
the user.
* src/Core/Banshee.Services/Banshee.MediaEngine/PlayerEngine.cs: If the
engine is in PlayerState.Contacting, don't Close/stop since this is a
state we set in managed land for loading internet radio tracks.
* src/Core/Banshee.Services/Banshee.MediaEngine/PlayerEngineService.cs:
Add Start/EndSynthesizeContacting internal methods for use by
RadioTrackInfo - basically a hack until we move the playlist loading logic
from RadioTrackInfo to the PlayerENgine to get UI bits updated
appropriately. Fix IsPlaying to include Contacting/Loading/Loaded, so
that TogglePlaying will Pause if in any of those states (not just if in
the Playing state), and Play only when in Ready, Idle, or Paused.
* src/Core/Banshee.Widgets/Banshee.Widgets/StreamPositionLabel.cs: Use an
enum to track the player state instead of a handful of bools. Show the
"Contacting..." label when inthe Loading state (for now - will change to
Loading... in a separate patch).
* src/Core/Banshee.Widgets/Banshee.Widgets/SeekSlider.cs: If the new Value
is more than the Duration, set the Duration to MaxValue so that the slider
stays at the left side of the Range, avoiding the glitchy-looking UI going
from Idle (where the slider is all the way left) to playing radio (where
it was all the way right).
Modified:
trunk/banshee/ChangeLog
trunk/banshee/src/Core/Banshee.Services/Banshee.MediaEngine/PlayerEngine.cs
trunk/banshee/src/Core/Banshee.Services/Banshee.MediaEngine/PlayerEngineService.cs
trunk/banshee/src/Core/Banshee.Services/Banshee.Streaming/RadioTrackInfo.cs
trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Gui.Widgets/ConnectedSeekSlider.cs
trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Gui/PlaybackActions.cs
trunk/banshee/src/Core/Banshee.Widgets/Banshee.Widgets/SeekSlider.cs
trunk/banshee/src/Core/Banshee.Widgets/Banshee.Widgets/StreamPositionLabel.cs
Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.MediaEngine/PlayerEngine.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.MediaEngine/PlayerEngine.cs (original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.MediaEngine/PlayerEngine.cs Fri Jan 30 18:45:53 2009
@@ -90,7 +90,7 @@
private void HandleOpen (SafeUri uri)
{
- if (current_state != PlayerState.Idle && current_state != PlayerState.NotReady) {
+ if (current_state != PlayerState.Idle && current_state != PlayerState.NotReady && current_state != PlayerState.Contacting) {
Close (false);
}
@@ -106,7 +106,7 @@
public abstract void Play ();
public abstract void Pause ();
-
+
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");
Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.MediaEngine/PlayerEngineService.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.MediaEngine/PlayerEngineService.cs (original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.MediaEngine/PlayerEngineService.cs Fri Jan 30 18:45:53 2009
@@ -55,6 +55,7 @@
private PlayerEngine pending_engine;
private object pending_playback_for_not_ready;
private bool pending_playback_for_not_ready_play;
+ private TrackInfo synthesized_contacting_track;
private string preferred_engine_id = null;
@@ -339,9 +340,9 @@
// If we're at least 50% done playing a song, mark it as played, otherwise as skipped
// If the Length <= 0, assume the song was finished and increment its play count
if (active_engine.Length <= 0 || active_engine.Position >= active_engine.Length / 2) {
- active_engine.CurrentTrack.IncrementPlayCount ();
+ CurrentTrack.IncrementPlayCount ();
} else {
- active_engine.CurrentTrack.IncrementSkipCount ();
+ CurrentTrack.IncrementSkipCount ();
}
incremented_last_played = true;
}
@@ -406,12 +407,32 @@
active_engine.Pause ();
}
}
+
+ // For use by RadioTrackInfo
+ // TODO remove this method once RadioTrackInfo playlist downloading/parsing logic moved here?
+ internal void StartSynthesizeContacting (TrackInfo track)
+ {
+ //OnStateChanged (PlayerState.Contacting);
+ RaiseEvent (new PlayerEventStateChangeArgs (CurrentState, PlayerState.Contacting));
+ synthesized_contacting_track = track;
+ }
+
+ internal void EndSynthesizeContacting (TrackInfo track, bool idle)
+ {
+ if (track == synthesized_contacting_track) {
+ synthesized_contacting_track = null;
+
+ if (idle) {
+ RaiseEvent (new PlayerEventStateChangeArgs (PlayerState.Contacting, PlayerState.Idle));
+ }
+ }
+ }
public void TogglePlaying ()
{
- if (CurrentState == PlayerState.Playing) {
+ if (IsPlaying ()) {
Pause ();
- } else {
+ } else if (CurrentState != PlayerState.NotReady) {
Play ();
}
}
@@ -440,7 +461,9 @@
{
return CurrentState == PlayerState.Playing ||
CurrentState == PlayerState.Paused ||
- CurrentState == PlayerState.Loaded;
+ CurrentState == PlayerState.Loaded ||
+ CurrentState == PlayerState.Loading ||
+ CurrentState == PlayerState.Contacting;
}
private void CheckPending ()
@@ -456,7 +479,7 @@
}
public TrackInfo CurrentTrack {
- get { return active_engine.CurrentTrack; }
+ get { return active_engine.CurrentTrack ?? synthesized_contacting_track; }
}
private Dictionary<string, object> dbus_sucks;
@@ -482,7 +505,7 @@
}
public PlayerState CurrentState {
- get { return active_engine.CurrentState; }
+ get { return synthesized_contacting_track != null ? PlayerState.Contacting : active_engine.CurrentState; }
}
string IPlayerEngineService.CurrentState {
@@ -532,11 +555,11 @@
uint length = active_engine.Length;
if (length > 0) {
return length;
- } else if (active_engine.CurrentTrack == null) {
+ } else if (CurrentTrack == null) {
return 0;
}
- return (uint) active_engine.CurrentTrack.Duration.TotalSeconds;
+ return (uint) CurrentTrack.Duration.TotalSeconds;
}
}
Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.Streaming/RadioTrackInfo.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.Streaming/RadioTrackInfo.cs (original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Streaming/RadioTrackInfo.cs Fri Jan 30 18:45:53 2009
@@ -37,6 +37,8 @@
using Banshee.Base;
using Banshee.Collection;
using Banshee.ServiceStack;
+using Banshee.MediaEngine;
+using Banshee.PlaybackController;
using Banshee.Playlists.Formats;
namespace Banshee.Streaming
@@ -75,11 +77,13 @@
try {
RadioTrackInfo radio_track = new RadioTrackInfo (uri);
radio_track.ParsingPlaylistEvent += delegate {
- if (radio_track.PlaybackError != StreamPlaybackError.None) {
- Log.Error (Catalog.GetString ("Error opening stream"),
- Catalog.GetString ("Could not open stream or playlist"), true);
- radio_track = null;
- }
+ ThreadAssist.ProxyToMain (delegate {
+ if (radio_track.PlaybackError != StreamPlaybackError.None) {
+ Log.Error (Catalog.GetString ("Error opening stream"),
+ Catalog.GetString ("Could not open stream or playlist"), true);
+ radio_track = null;
+ }
+ });
};
return radio_track;
@@ -98,6 +102,7 @@
private int stream_index = 0;
private bool loaded = false;
private bool parsing_playlist = false;
+ private bool trying_to_play;
private TrackInfo parent_track;
public TrackInfo ParentTrack {
@@ -135,14 +140,67 @@
public void Play()
{
- if(!loaded) {
- OnParsingPlaylistStarted();
- ThreadPool.QueueUserWorkItem(delegate {
- LoadStreamUris();
- });
+ if (trying_to_play) {
return;
}
-
+
+ trying_to_play = true;
+
+ if (loaded) {
+ PlayCore ();
+ } else {
+ // Stop playing until we load this radio station and play it
+ ServiceManager.PlayerEngine.Close ();
+
+ ServiceManager.PlayerEngine.TrackIntercept += OnTrackIntercept;
+
+ // Tell the seek slider that we're connecting
+ // TODO move all this playlist-downloading/parsing logic into PlayerEngine?
+ ServiceManager.PlayerEngine.StartSynthesizeContacting (this);
+
+ OnParsingPlaylistStarted ();
+ ThreadPool.QueueUserWorkItem (delegate {
+ try {
+ LoadStreamUris ();
+ } catch (Exception e) {
+ trying_to_play = false;
+ Log.Exception (this.ToString (), e);
+ SavePlaybackError (StreamPlaybackError.Unknown);
+ OnParsingPlaylistFinished ();
+ ServiceManager.PlayerEngine.Close ();
+ }
+ });
+ }
+ }
+
+ public override StreamPlaybackError PlaybackError {
+ get { return ParentTrack == null ? base.PlaybackError : ParentTrack.PlaybackError; }
+ set {
+ if (value != StreamPlaybackError.None) {
+ ServiceManager.PlayerEngine.EndSynthesizeContacting (this, true);
+ }
+
+ if (ParentTrack == null) {
+ base.PlaybackError = value;
+ } else {
+ ParentTrack.PlaybackError = value;
+ }
+ }
+ }
+
+ public new void SavePlaybackError (StreamPlaybackError value)
+ {
+ PlaybackError = value;
+ Save ();
+ if (ParentTrack != null) {
+ ParentTrack.Save ();
+ }
+ }
+
+ private void PlayCore ()
+ {
+ ServiceManager.PlayerEngine.EndSynthesizeContacting (this, false);
+
if(track != null) {
TrackTitle = track.Title;
ArtistName = track.Creator;
@@ -158,6 +216,8 @@
ServiceManager.PlayerEngine.OpenPlay(this);
}
}
+
+ trying_to_play = false;
}
public bool PlayNextStream()
@@ -167,6 +227,7 @@
Play();
return true;
}
+ ServiceManager.PlaybackController.StopWhenFinished = true;
return false;
}
@@ -177,9 +238,10 @@
Play();
return true;
}
+ ServiceManager.PlaybackController.StopWhenFinished = true;
return false;
}
-
+
private void LoadStreamUris()
{
lock(stream_uris) {
@@ -193,19 +255,31 @@
loaded = true;
}
-
- ThreadAssist.ProxyToMain(delegate {
- OnParsingPlaylistFinished();
- Play();
- });
+
+ ServiceManager.PlayerEngine.TrackIntercept -= OnTrackIntercept;
+ OnParsingPlaylistFinished();
+
+ if (ServiceManager.PlayerEngine.CurrentTrack == this) {
+ PlayCore();
+ } else {
+ trying_to_play = false;
+ }
+ }
+
+ private bool OnTrackIntercept (TrackInfo track)
+ {
+ if (track != this && track != ParentTrack) {
+ ServiceManager.PlayerEngine.EndSynthesizeContacting (this, false);
+ ServiceManager.PlayerEngine.TrackIntercept -= OnTrackIntercept;
+ }
+ return false;
}
private void LoadStreamUri(string uri)
{
try {
- Log.Debug("Attempting to parse radio playlist", uri);
PlaylistParser parser = new PlaylistParser();
- if(parser.Parse(new SafeUri(uri))) {
+ if (parser.Parse(new SafeUri(uri))) {
foreach(Dictionary<string, object> element in parser.Elements) {
if(element.ContainsKey("uri")) {
stream_uris.Add(new SafeUri(((Uri)element["uri"]).AbsoluteUri));
@@ -214,12 +288,14 @@
} else {
stream_uris.Add(new SafeUri(uri));
}
- } catch(System.Net.WebException) {
- SavePlaybackError (StreamPlaybackError.ResourceNotFound);
- } catch(Exception e) {
- Console.WriteLine(e);
+ Log.DebugFormat ("Parsed {0} URIs out of {1}", stream_uris.Count, this);
+ } catch (System.Net.WebException e) {
+ Hyena.Log.Exception (this.ToString (), e);
SavePlaybackError (StreamPlaybackError.ResourceNotFound);
- }
+ } catch (Exception e) {
+ Hyena.Log.Exception (this.ToString (), e);
+ SavePlaybackError (StreamPlaybackError.Unknown);
+ }
}
private void OnParsingPlaylistStarted()
Modified: trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Gui.Widgets/ConnectedSeekSlider.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Gui.Widgets/ConnectedSeekSlider.cs (original)
+++ trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Gui.Widgets/ConnectedSeekSlider.cs Fri Jan 30 18:45:53 2009
@@ -128,33 +128,41 @@
OnPlayerEngineTick ();
break;
case PlayerEvent.StartOfStream:
- stream_position_label.IsBuffering = false;
- seek_slider.CanSeek = true;
+ stream_position_label.StreamState = StreamLabelState.Playing;
+ seek_slider.CanSeek = ServiceManager.PlayerEngine.CanSeek;
break;
case PlayerEvent.Buffering:
PlayerEventBufferingArgs buffering = (PlayerEventBufferingArgs)args;
if (buffering.Progress >= 1.0) {
- stream_position_label.IsBuffering = false;
+ stream_position_label.StreamState = StreamLabelState.Playing;
break;
}
- stream_position_label.IsBuffering = true;
+ stream_position_label.StreamState = StreamLabelState.Buffering;
stream_position_label.BufferingProgress = buffering.Progress;
seek_slider.SetIdle ();
break;
case PlayerEvent.StateChange:
switch (((PlayerEventStateChangeArgs)args).Current) {
case PlayerState.Contacting:
- stream_position_label.IsContacting = true;
+ transitioning = false;
+ stream_position_label.StreamState = StreamLabelState.Contacting;
seek_slider.SetIdle ();
break;
+ case PlayerState.Loading:
+ transitioning = false;
+ if (((PlayerEventStateChangeArgs)args).Previous == PlayerState.Contacting) {
+ stream_position_label.StreamState = StreamLabelState.Loading;
+ seek_slider.SetIdle ();
+ }
+ break;
case PlayerState.Idle:
seek_slider.CanSeek = false;
if (!transitioning) {
+ stream_position_label.StreamState = StreamLabelState.Idle;
seek_slider.Duration = 0;
seek_slider.SeekValue = 0;
seek_slider.SetIdle ();
- stream_position_label.IsContacting = false;
}
break;
default:
@@ -171,12 +179,13 @@
return;
}
- uint stream_length = ServiceManager.PlayerEngine.Length;
- uint stream_position = ServiceManager.PlayerEngine.Position;
- stream_position_label.IsContacting = false;
+ stream_position_label.StreamState = StreamLabelState.Playing;
+ Banshee.Collection.TrackInfo track = ServiceManager.PlayerEngine.CurrentTrack;
+ stream_position_label.IsLive = track == null ? false : track.IsLive;
+ stream_position_label.StreamState = StreamLabelState.Playing;
+ seek_slider.Duration = ServiceManager.PlayerEngine.Length;
+ seek_slider.SeekValue = ServiceManager.PlayerEngine.Position;
seek_slider.CanSeek = ServiceManager.PlayerEngine.CanSeek;
- seek_slider.Duration = stream_length;
- seek_slider.SeekValue = stream_position;
}
private void OnSeekRequested (object o, EventArgs args)
Modified: trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Gui/PlaybackActions.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Gui/PlaybackActions.cs (original)
+++ trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Gui/PlaybackActions.cs Fri Jan 30 18:45:53 2009
@@ -143,8 +143,10 @@
switch (args.Current) {
case PlayerState.Contacting:
+ case PlayerState.Loading:
+ case PlayerState.Loaded:
case PlayerState.Playing:
- ShowPlayAction ();
+ ShowStopAction ();
break;
case PlayerState.Paused:
ShowPlay ();
@@ -169,10 +171,13 @@
this["RestartSongAction"].Sensitive = false;
this["SeekToAction"].Sensitive = false;
}
+
+ // Disable all actions while NotReady
+ Sensitive = args.Current != PlayerState.NotReady;
}
- private void ShowPlayAction ()
- {
+ private void ShowStopAction ()
+ {
if (ServiceManager.PlayerEngine.CanPause) {
ShowPause ();
} else {
Modified: trunk/banshee/src/Core/Banshee.Widgets/Banshee.Widgets/SeekSlider.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Widgets/Banshee.Widgets/SeekSlider.cs (original)
+++ trunk/banshee/src/Core/Banshee.Widgets/Banshee.Widgets/SeekSlider.cs Fri Jan 30 18:45:53 2009
@@ -107,10 +107,12 @@
raise_seek_requested = false;
if(value > Duration) {
- Duration = value;
+ Duration = Int64.MaxValue;
+ Value = value;
+ } else {
+ Value = value;
}
-
- Value = value;
+
raise_seek_requested = true;
}
}
Modified: trunk/banshee/src/Core/Banshee.Widgets/Banshee.Widgets/StreamPositionLabel.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Widgets/Banshee.Widgets/StreamPositionLabel.cs (original)
+++ trunk/banshee/src/Core/Banshee.Widgets/Banshee.Widgets/StreamPositionLabel.cs Fri Jan 30 18:45:53 2009
@@ -32,14 +32,22 @@
namespace Banshee.Widgets
{
+ public enum StreamLabelState {
+ Idle,
+ Contacting,
+ Loading,
+ Buffering,
+ Playing
+ }
+
public class StreamPositionLabel : Alignment
{
private double buffering_progress;
- private bool is_buffering;
- private bool is_contacting;
+ private bool is_live;
private SeekSlider seekRange;
private string format_string = "<small>{0}</small>";
private Pango.Layout layout;
+ private StreamLabelState state;
public StreamPositionLabel (SeekSlider seekRange) : base (0.0f, 0.0f, 1.0f, 1.0f)
{
@@ -101,7 +109,7 @@
int bar_width = (int)((double)Allocation.Width * buffering_progress);
bool render_bar = false;
- if (bar_width > 0 && is_buffering) {
+ if (bar_width > 0 && IsBuffering) {
bar_width -= 2 * Style.XThickness;
render_bar = true;
@@ -146,15 +154,20 @@
return;
}
- if (is_buffering) {
+ if (IsBuffering) {
double progress = buffering_progress * 100.0;
UpdateLabel (String.Format ("{0}: {1}%", Catalog.GetString("Buffering"), progress.ToString ("0.0")));
- } else if (is_contacting) {
+ } else if (IsContacting) {
UpdateLabel (contacting);
- } else if (seekRange.Value == 0 && seekRange.Duration == 0) {
+ } else if (IsLoading) {
+ // TODO replace w/ "Loading..." after string freeze
+ UpdateLabel (contacting);
+ } else if (IsIdle) {
UpdateLabel (idle);
- } else if (seekRange.Value == seekRange.Duration) {
+ } else if (seekRange.Duration == Int64.MaxValue) {
UpdateLabel (FormatDuration ((long)seekRange.Value));
+ } else if (seekRange.Value == 0 && seekRange.Duration == 0) {
+ // nop
} else {
UpdateLabel (String.Format (Catalog.GetString ("{0} of {1}"),
FormatDuration ((long)seekRange.Value), FormatDuration ((long)seekRange.Adjustment.Upper)));
@@ -193,22 +206,38 @@
}
}
+ public bool IsIdle {
+ get { return StreamState == StreamLabelState.Idle; }
+ }
+
public bool IsBuffering {
- get { return is_buffering; }
+ get { return StreamState == StreamLabelState.Buffering; }
+ }
+
+ public bool IsContacting {
+ get { return StreamState == StreamLabelState.Contacting; }
+ }
+
+ public bool IsLoading {
+ get { return StreamState == StreamLabelState.Loading; }
+ }
+
+ public StreamLabelState StreamState {
+ get { return state; }
set {
- if (is_buffering != value) {
- is_buffering = value;
+ if (state != value) {
+ state = value;
UpdateLabel ();
QueueDraw ();
}
}
}
-
- public bool IsContacting {
- get { return is_contacting; }
+
+ public bool IsLive {
+ get { return is_live; }
set {
- if (is_contacting != value) {
- is_contacting = value;
+ if (is_live != value) {
+ is_live = value;
UpdateLabel ();
QueueDraw ();
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]