audio: Implement our own about-to-finish handling

The playbin's about-to-finish signal triggers in a different thread,
which Gtk is very much not happy about, and often results in both the
about-to-finish and eos handlers getting called (and therefore multiple
tracks getting picked from the queue).

Fix this by checking how much time is left during the regular position
changed timeout function and triggering about-to-finish manually

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This commit is contained in:
Anna Schumaker 2021-12-09 17:22:25 -05:00
parent 8f26cf9fee
commit 4cdf4c528a
2 changed files with 8 additions and 10 deletions

View File

@ -11,6 +11,8 @@ Gst.init(sys.argv)
from . import replaygain from . import replaygain
TIMEOUT = 100
class BassPlayer(GObject.GObject): class BassPlayer(GObject.GObject):
def __init__(self): def __init__(self):
@ -22,7 +24,6 @@ class BassPlayer(GObject.GObject):
self.video = Gst.ElementFactory.make("fakesink") self.video = Gst.ElementFactory.make("fakesink")
self.playbin = Gst.ElementFactory.make("playbin") self.playbin = Gst.ElementFactory.make("playbin")
self.playbin.connect("about-to-finish", self.__about_to_finish__)
self.playbin.set_property("audio-sink", self.audio) self.playbin.set_property("audio-sink", self.audio)
self.playbin.set_property("video-sink", self.video) self.playbin.set_property("video-sink", self.video)
self.playbin.set_property("volume", lib.settings.get_float("audio.volume")) self.playbin.set_property("volume", lib.settings.get_float("audio.volume"))
@ -38,9 +39,6 @@ class BassPlayer(GObject.GObject):
self.timeout = None self.timeout = None
def __about_to_finish__(self, playbin):
self.emit("about-to-finish")
def __eos__(self, bus, message): def __eos__(self, bus, message):
self.emit("eos") self.emit("eos")
@ -110,9 +108,6 @@ class BassPlayer(GObject.GObject):
self.playbin.set_property("volume", vol) self.playbin.set_property("volume", vol)
lib.settings.set("audio.volume", vol) lib.settings.set("audio.volume", vol)
def about_to_finish(self, playbin):
pass
def state_changed(self, bus, message): def state_changed(self, bus, message):
if message.src == self.playbin: if message.src == self.playbin:
(old, new, pending) = message.parse_state_changed() (old, new, pending) = message.parse_state_changed()
@ -152,7 +147,7 @@ class BassPlayer(GObject.GObject):
@GObject.Signal @GObject.Signal
def playback_start(self): def playback_start(self):
if not self.timeout: if not self.timeout:
self.timeout = GLib.timeout_add(200, self.timeout_function) self.timeout = GLib.timeout_add(TIMEOUT, self.timeout_function)
@GObject.Signal @GObject.Signal
def playback_paused(self): def playback_paused(self):
@ -162,4 +157,7 @@ class BassPlayer(GObject.GObject):
@GObject.Signal @GObject.Signal
def position_changed(self): def position_changed(self):
pass remaining = self.duration - self.position
if remaining < 2 * Gst.SECOND:
if remaining + (TIMEOUT * Gst.MSECOND) >= 2 * Gst.SECOND:
self.emit("about-to-finish")

View File

@ -32,7 +32,7 @@ class TestBassPlayer(unittest.TestCase):
self.assertEqual(base.playbin.get_property("video-sink"), base.video) self.assertEqual(base.playbin.get_property("video-sink"), base.video)
self.assertEqual(base.playbin.get_state(Gst.CLOCK_TIME_NONE)[1], self.assertEqual(base.playbin.get_state(Gst.CLOCK_TIME_NONE)[1],
Gst.State.READY) Gst.State.READY)
self.assertIsNone(base.timeout, 0) self.assertIsNone(base.timeout)
def test_bass_player_bus(self): def test_bass_player_bus(self):
base = bass.BassPlayer() base = bass.BassPlayer()