try handle more edge cases
This commit is contained in:
parent
bac519034d
commit
e6f3dc6e7c
1 changed files with 53 additions and 59 deletions
112
src/playbin.vala
112
src/playbin.vala
|
@ -26,13 +26,16 @@ class Playbin : Object {
|
|||
|
||||
public PlaybinState state { get; private set; default = PlaybinState.STOPPED; }
|
||||
|
||||
// true if a timer should update the postion property
|
||||
private bool update_position = false;
|
||||
public int64 position { get; private set; default = 0; }
|
||||
|
||||
public int64 position { get; private set; }
|
||||
|
||||
public Subsonic api { get; set; }
|
||||
public Subsonic api { get; set; default = null; }
|
||||
|
||||
// sent when a new song starts playing
|
||||
public signal void now_playing (uint index, Song song, int64 duration);
|
||||
|
||||
// FIXME this should be synced with the selection model, right??
|
||||
private uint playing_index;
|
||||
|
||||
private bool next_gapless;
|
||||
|
@ -41,6 +44,37 @@ class Playbin : Object {
|
|||
source.user_agent = "audrey/linux";
|
||||
}
|
||||
|
||||
// ASSUMPTION: about-to-finish will be signalled exactly once per track
|
||||
// even if seeking backwards after
|
||||
AsyncQueue<string> next_uri = new AsyncQueue<string> ();
|
||||
|
||||
private ListModel _play_queue = null;
|
||||
private ulong _play_queue_items_changed;
|
||||
public ListModel play_queue {
|
||||
get { return _play_queue; }
|
||||
set {
|
||||
if (_play_queue != null) {
|
||||
SignalHandler.disconnect (_play_queue, _play_queue_items_changed);
|
||||
}
|
||||
_play_queue = value;
|
||||
_play_queue_items_changed = value.items_changed.connect (on_play_queue_items_changed);
|
||||
}
|
||||
}
|
||||
|
||||
// called when uri can be switched for gapless playback
|
||||
// need async queue because this might be called from a gstreamer thread
|
||||
private void about_to_finish (dynamic Gst.Element playbin) {
|
||||
print ("about to finish\n");
|
||||
|
||||
// will block if the next uri isn't ready yet
|
||||
// leaves the queue empty as per the ASSUMPTION above
|
||||
string? next_uri = this.next_uri.pop ();
|
||||
|
||||
if (next_uri != "") {
|
||||
playbin.uri = next_uri;
|
||||
}
|
||||
}
|
||||
|
||||
private void on_play_queue_items_changed (ListModel play_queue, uint position, uint removed, uint added) {
|
||||
if (this.state == PlaybinState.STOPPED) {
|
||||
return;
|
||||
|
@ -74,26 +108,12 @@ class Playbin : Object {
|
|||
} else {
|
||||
// about-to-finish already triggered
|
||||
// we'll need to stop the new track when it starts playing
|
||||
assert (false); // TODO
|
||||
// but stream-start should already be able to take care of that
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private ListModel _play_queue = null;
|
||||
private ulong _play_queue_items_changed;
|
||||
public ListModel play_queue {
|
||||
get { return _play_queue; }
|
||||
set {
|
||||
if (_play_queue != null) {
|
||||
SignalHandler.disconnect (_play_queue, _play_queue_items_changed);
|
||||
}
|
||||
_play_queue = value;
|
||||
_play_queue_items_changed = value.items_changed.connect (on_play_queue_items_changed);
|
||||
}
|
||||
}
|
||||
|
||||
public Playbin () {
|
||||
this.next_uri = new AsyncQueue<string> ();
|
||||
this.next_uri.push ("");
|
||||
|
||||
// gstreamer docs: GNOME-based applications, for example, will usually
|
||||
|
@ -151,19 +171,19 @@ class Playbin : Object {
|
|||
}
|
||||
|
||||
var now_playing = (Song) play_queue.get_item (this.playing_index);
|
||||
if (this.api.stream_uri (now_playing.id) != (string) this.playbin.current_uri) {
|
||||
if (this.api.stream_uri (now_playing.id) == (string) this.playbin.current_uri) {
|
||||
this.now_playing (this.playing_index, now_playing, duration);
|
||||
|
||||
if (this.playing_index+1 < play_queue.get_n_items ()) {
|
||||
Song song = (Song) play_queue.get_item (this.playing_index+1);
|
||||
this.next_uri.push (this.api.stream_uri (song.id));
|
||||
} else {
|
||||
this.next_uri.push ("");
|
||||
}
|
||||
} else {
|
||||
// edge case
|
||||
assert (false); // TODO
|
||||
}
|
||||
|
||||
this.now_playing (this.playing_index, now_playing, duration);
|
||||
|
||||
if (this.playing_index+1 < play_queue.get_n_items ()) {
|
||||
Song song = (Song) play_queue.get_item (this.playing_index+1);
|
||||
this.next_uri.push (this.api.stream_uri (song.id));
|
||||
} else {
|
||||
this.next_uri.push ("");
|
||||
}
|
||||
});
|
||||
|
||||
bus.message["state-changed"].connect ((message) => {
|
||||
|
@ -195,32 +215,11 @@ class Playbin : Object {
|
|||
this.playbin.set_state (Gst.State.PLAYING);
|
||||
this.next_gapless = false;
|
||||
|
||||
string? next_uri = this.next_uri.try_pop ();
|
||||
if (next_uri != null) {
|
||||
// we're in luck, about-to-finish hasn't been triggered yet
|
||||
} else {
|
||||
// about-to-finish already triggered
|
||||
// we'll need to stop the new track when it starts playing
|
||||
assert (false); // TODO
|
||||
}
|
||||
}
|
||||
|
||||
// ASSUMPTION: about-to-finish will be signalled exactly once per track
|
||||
// even if seeking backwards after
|
||||
AsyncQueue<string?> next_uri;
|
||||
|
||||
// called when uri can be switched for gapless playback
|
||||
// need async queue because this might be called from a gstreamer thread
|
||||
private void about_to_finish (dynamic Gst.Element playbin) {
|
||||
print ("about to finish\n");
|
||||
|
||||
// will block if the next uri isn't ready yet
|
||||
// leaves the queue empty as per the ASSUMPTION above
|
||||
string? next_uri = this.next_uri.pop ();
|
||||
|
||||
if (next_uri != "") {
|
||||
playbin.uri = next_uri;
|
||||
}
|
||||
// make sure the queue is empty, so next stream-changed can fix it up
|
||||
this.next_uri.try_pop ();
|
||||
// if it was already empty then uhhhh if theres any problems then
|
||||
// playbin.uri wont match up with the current track's stream uri and we can
|
||||
// fix it there
|
||||
}
|
||||
|
||||
public void pause () {
|
||||
|
@ -234,9 +233,4 @@ class Playbin : Object {
|
|||
this.playbin.set_state (Gst.State.PLAYING);
|
||||
this.state = PlaybinState.PLAYING;
|
||||
}
|
||||
|
||||
public void stop_playback() {
|
||||
this.playbin.set_state (Gst.State.READY);
|
||||
this.state = PlaybinState.STOPPED;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue