Compare commits

..

No commits in common. "64dcceea22837eb4b270d6b4905c245497b16c59" and "2b2ace0f5c54c54879fb1b4bc5e61b35f29de024" have entirely different histories.

9 changed files with 105 additions and 175 deletions

View file

@ -41,8 +41,4 @@ public class Audrey.Application : Adw.Application {
private void on_preferences_action () { private void on_preferences_action () {
message ("app.preferences action activated"); message ("app.preferences action activated");
} }
~Application () {
debug ("destroying application");
}
} }

View file

@ -20,10 +20,6 @@ class Mpris : Object {
public string desktop_entry { owned get { return "eu.callcc.audrey"; } } public string desktop_entry { owned get { return "eu.callcc.audrey"; } }
public string[] supported_uri_schemes { owned get { return {}; } } public string[] supported_uri_schemes { owned get { return {}; } }
public string[] supported_mime_types { owned get { return {}; } } public string[] supported_mime_types { owned get { return {}; } }
~Mpris () {
debug ("destroying mpris");
}
} }
[DBus (name = "org.mpris.MediaPlayer2.Player")] [DBus (name = "org.mpris.MediaPlayer2.Player")]
@ -66,8 +62,4 @@ class MprisPlayer : Object {
public bool can_seek { get; default = false; } public bool can_seek { get; default = false; }
[CCode (notify = false)] [CCode (notify = false)]
public bool can_control { get { return false; } } public bool can_control { get { return false; } }
~MprisPlayer () {
debug ("destroying mpris player");
}
} }

View file

@ -52,11 +52,14 @@ public class Playbin : GLib.Object {
public double position { get; private set; default = 0.0; } public double position { get; private set; default = 0.0; }
public double duration { get; private set; default = 0.0; } public double duration { get; private set; default = 0.0; }
public weak Subsonic.Client api { get; set; default = null; } public Subsonic.Client api { get; set; default = null; }
public ListStore _play_queue; public ListStore _play_queue;
public ListModel play_queue { get { return this._play_queue; } } public ListModel play_queue { get { return this._play_queue; } }
// try to prevent wait_event to be called twice
private bool is_handling_event = false;
private async Mpv.Error mpv_command_async (string[] args) { private async Mpv.Error mpv_command_async (string[] args) {
CommandCallback cc = {}; CommandCallback cc = {};
@ -67,9 +70,6 @@ public class Playbin : GLib.Object {
return cc.error; return cc.error;
} }
// should be Mpv.WakeupCallback, but i think there's a vala bug here
private SourceOnceFunc wakeup_callback; // anchor reference here, mpv won't remind us
public Playbin () { public Playbin () {
this._play_queue = new ListStore (typeof (Subsonic.Song)); this._play_queue = new ListStore (typeof (Subsonic.Song));
@ -83,153 +83,123 @@ public class Playbin : GLib.Object {
assert (this.mpv.observe_property (2, "playlist-pos", Mpv.Format.INT64) >= 0); assert (this.mpv.observe_property (2, "playlist-pos", Mpv.Format.INT64) >= 0);
assert (this.mpv.observe_property (3, "pause", Mpv.Format.FLAG) >= 0); assert (this.mpv.observe_property (3, "pause", Mpv.Format.FLAG) >= 0);
int wakeup_fds[2]; this.mpv.wakeup_callback = () => {
try { Idle.add (() => {
assert (Unix.open_pipe (wakeup_fds, 0)); if (this.is_handling_event) return false;
} catch (Error e) { this.is_handling_event = true;
error (@"could not open pipe for mpv wakeup: $(e.message)");
}
IOChannel wakeup_read = new IOChannel.unix_new (wakeup_fds[0]); while (true) {
IOChannel wakeup_write = new IOChannel.unix_new (wakeup_fds[1]); var event = this.mpv.wait_event (0.0);
if (event.event_id == Mpv.EventId.NONE) break;
wakeup_read.set_close_on_unref (true); switch (event.event_id) {
wakeup_write.set_close_on_unref (true); case Mpv.EventId.PROPERTY_CHANGE:
var data = event.parse_property ();
switch (event.reply_userdata) {
case 0:
assert (data.name == "time-pos");
if (data.format == Mpv.Format.NONE) {
this.position = 0.0;
} else {
this.position = data.parse_double ();
}
break;
try { case 1:
wakeup_read.set_encoding (null); assert (data.name == "duration");
wakeup_write.set_encoding (null); if (data.format == Mpv.Format.NONE) {
wakeup_write.set_buffered (false); // this.duration = 0.0; i think this prevents the fallback below from working
} catch (Error e) { } else {
error (@"could not set up pipes for mpv wakeup: $(e.message)"); this.duration = data.parse_double ();
} }
break;
this.wakeup_callback = () => { case 2:
try { // here as a sanity check
wakeup_write.write_chars ({0}, null); // should always match our own play_queu_position/state
} catch (Error e) { assert (data.name == "playlist-pos");
error (@"could not write to mpv wakeup pipe: $(e.message)"); int64 playlist_pos = data.parse_int64 ();
} if (playlist_pos < 0) {
}; if (this.state != PlaybinState.STOPPED) {
this.mpv.wakeup_callback = this.wakeup_callback; error ("mpv has no current playlist entry, but we think it's index %u", this.play_queue_position);
}
assert (this.play_queue_position == this.play_queue.get_n_items ());
} else {
if (this.state == PlaybinState.STOPPED) {
error ("mpv is at playlist entry %u, but we're stopped", (uint) playlist_pos);
}
if (this.play_queue_position != (uint) playlist_pos) {
error ("mpv is at playlist entry %u, but we think it's %u", (uint) playlist_pos, this.play_queue_position);
}
}
break;
assert (0 < wakeup_read.add_watch (IOCondition.IN, (source, condition) => { case 3:
try { // also here as a sanity check
wakeup_read.read_chars ({0}, null); // should always match our own state
} catch (Error e) { assert (data.name == "pause");
error (@"could not read from mpv wakeup pipe: $(e.message)"); bool pause = data.parse_flag ();
} if (pause && this.state != PlaybinState.PAUSED) {
error (@"mpv is paused, but we are @(this.state)");
}
if (!pause && this.state == PlaybinState.PAUSED) {
error ("mpv is not paused, but we are paused");
}
break;
while (true) { default:
var event = this.mpv.wait_event (0.0); assert (false);
if (event.event_id == Mpv.EventId.NONE) break; break;
switch (event.event_id) {
case Mpv.EventId.PROPERTY_CHANGE:
var data = event.parse_property ();
switch (event.reply_userdata) {
case 0:
assert (data.name == "time-pos");
if (data.format == Mpv.Format.NONE) {
this.position = 0.0;
} else {
this.position = data.parse_double ();
} }
break; break;
case 1: case Mpv.EventId.START_FILE:
assert (data.name == "duration"); debug ("START_FILE received");
if (data.format == Mpv.Format.NONE) {
// this.duration = 0.0; i think this prevents the fallback below from working // estimate duration from api data
} else { // while mpv doesn't know it
this.duration = data.parse_double (); this.duration = ((Subsonic.Song) this._play_queue.get_item (this.play_queue_position)).duration;
}
this.new_track ();
break; break;
case 2: case Mpv.EventId.END_FILE:
// here as a sanity check var data = event.parse_end_file ();
// should always match our own play_queu_position/state debug (@"END_FILE received (reason: $(data.reason))");
assert (data.name == "playlist-pos");
int64 playlist_pos = data.parse_int64 (); if (data.error < 0) {
if (playlist_pos < 0) { warning ("playback of track aborted: %s", data.error.to_string ());
if (this.state != PlaybinState.STOPPED) { }
error ("mpv has no current playlist entry, but we think it's index %u", this.play_queue_position);
} if (data.reason == Mpv.EndFileReason.EOF) {
assert (this.play_queue_position == this.play_queue.get_n_items ()); // assume this is a proper transition
} else { this.play_queue_position += 1;
if (this.state == PlaybinState.STOPPED) {
error ("mpv is at playlist entry %u, but we're stopped", (uint) playlist_pos); if (this.play_queue_position == this._play_queue.get_n_items ()) {
} // reached the end (?)
if (this.play_queue_position != (uint) playlist_pos) { this.state = PlaybinState.STOPPED;
error ("mpv is at playlist entry %u, but we think it's %u", (uint) playlist_pos, this.play_queue_position); this.stopped ();
} }
} }
break; break;
case 3: case Mpv.EventId.COMMAND_REPLY:
// also here as a sanity check unowned CommandCallback *cc = (CommandCallback *) event.reply_userdata;
// should always match our own state cc.error = event.error;
assert (data.name == "pause"); cc.callback ();
bool pause = data.parse_flag ();
if (pause && this.state != PlaybinState.PAUSED) {
error (@"mpv is paused, but we are @(this.state)");
}
if (!pause && this.state == PlaybinState.PAUSED) {
error ("mpv is not paused, but we are paused");
}
break; break;
default: default:
assert (false); // ignore by default
break; break;
} }
break;
case Mpv.EventId.START_FILE:
debug ("START_FILE received");
// estimate duration from api data
// while mpv doesn't know it
this.duration = ((Subsonic.Song) this._play_queue.get_item (this.play_queue_position)).duration;
this.new_track ();
break;
case Mpv.EventId.END_FILE:
var data = event.parse_end_file ();
debug (@"END_FILE received (reason: $(data.reason))");
if (data.error < 0) {
warning ("playback of track aborted: %s", data.error.to_string ());
}
if (data.reason == Mpv.EndFileReason.EOF) {
// assume this is a proper transition
this.play_queue_position += 1;
if (this.play_queue_position == this._play_queue.get_n_items ()) {
// reached the end (?)
this.state = PlaybinState.STOPPED;
this.stopped ();
}
}
break;
case Mpv.EventId.COMMAND_REPLY:
unowned CommandCallback *cc = (CommandCallback *) event.reply_userdata;
cc.error = event.error;
cc.callback ();
break;
default:
// ignore by default
break;
} }
}
return true; this.is_handling_event = false;
})); return false;
});
};
} }
public void seek (double position) { public void seek (double position) {
@ -388,8 +358,4 @@ public class Playbin : GLib.Object {
else if (this.play_queue_position >= to && this.play_queue_position < from) this.play_queue_position += 1; else if (this.play_queue_position >= to && this.play_queue_position < from) this.play_queue_position += 1;
} }
} }
~Playbin () {
debug ("destroying playbin");
}
} }

View file

@ -248,8 +248,4 @@ public class Subsonic.Client : Object {
assert (msg.get_status () == Soup.Status.OK); assert (msg.get_status () == Soup.Status.OK);
return yield new Gdk.Pixbuf.from_stream_async (stream, cancellable); return yield new Gdk.Pixbuf.from_stream_async (stream, cancellable);
} }
~Client () {
debug ("destroying subsonic client");
}
} }

View file

@ -23,7 +23,7 @@ class Ui.PlayQueueSong : Gtk.Box {
public string play_icon_name { get; set; default = ""; } public string play_icon_name { get; set; default = ""; }
private weak Playbin playbin; private Playbin playbin;
public PlayQueueSong (Playbin playbin) { public PlayQueueSong (Playbin playbin) {
this.playbin = playbin; this.playbin = playbin;
@ -110,7 +110,7 @@ class Ui.PlayQueueSong : Gtk.Box {
[GtkTemplate (ui = "/eu/callcc/audrey/ui/play_queue.ui")] [GtkTemplate (ui = "/eu/callcc/audrey/ui/play_queue.ui")]
public class Ui.PlayQueue : Gtk.Box { public class Ui.PlayQueue : Gtk.Box {
private weak Playbin _playbin; private Playbin _playbin;
public Playbin playbin { public Playbin playbin {
get { return _playbin; } get { return _playbin; }
set { set {
@ -165,8 +165,4 @@ public class Ui.PlayQueue : Gtk.Box {
[GtkCallback] private string visible_child_name (uint n_items) { [GtkCallback] private string visible_child_name (uint n_items) {
return n_items > 0 ? "not-empty" : "empty"; return n_items > 0 ? "not-empty" : "empty";
} }
~PlayQueue () {
debug ("destroying play queue widget");
}
} }

View file

@ -2,7 +2,7 @@
class Ui.Playbar : Gtk.Box { class Ui.Playbar : Gtk.Box {
public Subsonic.Song? song { get; set; } public Subsonic.Song? song { get; set; }
public Gdk.Paintable? playing_cover_art { get; set; } public Gdk.Paintable? playing_cover_art { get; set; }
public weak Playbin playbin { get; set; } public Playbin playbin { get; set; }
public bool show_cover_art { get; set; default = true; } public bool show_cover_art { get; set; default = true; }
public int volume { public int volume {
@ -82,8 +82,4 @@ class Ui.Playbar : Gtk.Box {
[GtkCallback] private string song_album (Subsonic.Song? song) { [GtkCallback] private string song_album (Subsonic.Song? song) {
return song == null ? "" : song.album; return song == null ? "" : song.album;
} }
~Playbar () {
debug ("destroying playbar widget");
}
} }

View file

@ -128,8 +128,4 @@ public class Ui.Setup : Adw.PreferencesDialog {
this.authn_can_edit = true; this.authn_can_edit = true;
}, "server-url", this.server_url, "username", this.username); }, "server-url", this.server_url, "username", this.username);
} }
~Setup () {
debug ("destroying setup dialog");
}
} }

View file

@ -115,8 +115,4 @@ class Ui.Window : Adw.ApplicationWindow {
[GtkCallback] private bool show_playbar_cover_art (string? stack_child) { [GtkCallback] private bool show_playbar_cover_art (string? stack_child) {
return stack_child != "play-queue"; return stack_child != "play-queue";
} }
~Window () {
debug ("destroying main window");
}
} }

View file

@ -31,7 +31,7 @@ namespace Mpv {
public delegate void WakeupCallback (); public delegate void WakeupCallback ();
[CCode (cname = "mpv_handle", free_function = "mpv_terminate_destroy")] [CCode (cname = "mpv_handle", free_function = "mpv_destroy")]
[Compact] [Compact]
public class Handle { public class Handle {
[CCode (cname = "mpv_create")] [CCode (cname = "mpv_create")]
@ -43,7 +43,7 @@ namespace Mpv {
[CCode (cname = "mpv_wait_event")] [CCode (cname = "mpv_wait_event")]
public unowned Event? wait_event (double timeout); public unowned Event? wait_event (double timeout);
public unowned WakeupCallback wakeup_callback { public WakeupCallback wakeup_callback {
[CCode (cname = "mpv_set_wakeup_callback")] set; [CCode (cname = "mpv_set_wakeup_callback")] set;
} }
@ -70,10 +70,6 @@ namespace Mpv {
[CCode (cname = "mpv_observe_property")] [CCode (cname = "mpv_observe_property")]
public Error observe_property (uint64 reply_userdata, string name, Format format); public Error observe_property (uint64 reply_userdata, string name, Format format);
~Handle () {
GLib.debug ("destroying mpv handle");
}
} }
[CCode (cname = "mpv_format", cprefix = "MPV_FORMAT_", has_type_id = false)] [CCode (cname = "mpv_format", cprefix = "MPV_FORMAT_", has_type_id = false)]