try handle more edge cases

This commit is contained in:
Erica Z 2024-10-15 22:45:16 +02:00
parent bac519034d
commit e6f3dc6e7c

View file

@ -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;
}
}