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; }
|
public PlaybinState state { get; private set; default = PlaybinState.STOPPED; }
|
||||||
|
|
||||||
|
// true if a timer should update the postion property
|
||||||
private bool update_position = false;
|
private bool update_position = false;
|
||||||
|
public int64 position { get; private set; default = 0; }
|
||||||
|
|
||||||
public int64 position { get; private set; }
|
public Subsonic api { get; set; default = null; }
|
||||||
|
|
||||||
public Subsonic api { get; set; }
|
|
||||||
|
|
||||||
|
// sent when a new song starts playing
|
||||||
public signal void now_playing (uint index, Song song, int64 duration);
|
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 uint playing_index;
|
||||||
|
|
||||||
private bool next_gapless;
|
private bool next_gapless;
|
||||||
|
@ -41,6 +44,37 @@ class Playbin : Object {
|
||||||
source.user_agent = "audrey/linux";
|
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) {
|
private void on_play_queue_items_changed (ListModel play_queue, uint position, uint removed, uint added) {
|
||||||
if (this.state == PlaybinState.STOPPED) {
|
if (this.state == PlaybinState.STOPPED) {
|
||||||
return;
|
return;
|
||||||
|
@ -74,26 +108,12 @@ class Playbin : Object {
|
||||||
} else {
|
} else {
|
||||||
// about-to-finish already triggered
|
// about-to-finish already triggered
|
||||||
// we'll need to stop the new track when it starts playing
|
// 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 () {
|
public Playbin () {
|
||||||
this.next_uri = new AsyncQueue<string> ();
|
|
||||||
this.next_uri.push ("");
|
this.next_uri.push ("");
|
||||||
|
|
||||||
// gstreamer docs: GNOME-based applications, for example, will usually
|
// 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);
|
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
|
// edge case
|
||||||
assert (false); // TODO
|
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) => {
|
bus.message["state-changed"].connect ((message) => {
|
||||||
|
@ -195,32 +215,11 @@ class Playbin : Object {
|
||||||
this.playbin.set_state (Gst.State.PLAYING);
|
this.playbin.set_state (Gst.State.PLAYING);
|
||||||
this.next_gapless = false;
|
this.next_gapless = false;
|
||||||
|
|
||||||
string? next_uri = this.next_uri.try_pop ();
|
// make sure the queue is empty, so next stream-changed can fix it up
|
||||||
if (next_uri != null) {
|
this.next_uri.try_pop ();
|
||||||
// we're in luck, about-to-finish hasn't been triggered yet
|
// if it was already empty then uhhhh if theres any problems then
|
||||||
} else {
|
// playbin.uri wont match up with the current track's stream uri and we can
|
||||||
// about-to-finish already triggered
|
// fix it there
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void pause () {
|
public void pause () {
|
||||||
|
@ -234,9 +233,4 @@ class Playbin : Object {
|
||||||
this.playbin.set_state (Gst.State.PLAYING);
|
this.playbin.set_state (Gst.State.PLAYING);
|
||||||
this.state = PlaybinState.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