From e6f3dc6e7c0918eac1d8db88f6c304b8d9112b1e Mon Sep 17 00:00:00 2001 From: Erica Z Date: Tue, 15 Oct 2024 22:45:16 +0200 Subject: [PATCH] try handle more edge cases --- src/playbin.vala | 112 ++++++++++++++++++++++------------------------- 1 file changed, 53 insertions(+), 59 deletions(-) diff --git a/src/playbin.vala b/src/playbin.vala index 2d9e777..deca3b9 100644 --- a/src/playbin.vala +++ b/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 next_uri = new AsyncQueue (); + + 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 (); 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 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; - } }