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
TIMEOUT = 100
class BassPlayer(GObject.GObject):
def __init__(self):
@ -22,7 +24,6 @@ class BassPlayer(GObject.GObject):
self.video = Gst.ElementFactory.make("fakesink")
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("video-sink", self.video)
self.playbin.set_property("volume", lib.settings.get_float("audio.volume"))
@ -38,9 +39,6 @@ class BassPlayer(GObject.GObject):
self.timeout = None
def __about_to_finish__(self, playbin):
self.emit("about-to-finish")
def __eos__(self, bus, message):
self.emit("eos")
@ -110,9 +108,6 @@ class BassPlayer(GObject.GObject):
self.playbin.set_property("volume", vol)
lib.settings.set("audio.volume", vol)
def about_to_finish(self, playbin):
pass
def state_changed(self, bus, message):
if message.src == self.playbin:
(old, new, pending) = message.parse_state_changed()
@ -152,7 +147,7 @@ class BassPlayer(GObject.GObject):
@GObject.Signal
def playback_start(self):
if not self.timeout:
self.timeout = GLib.timeout_add(200, self.timeout_function)
self.timeout = GLib.timeout_add(TIMEOUT, self.timeout_function)
@GObject.Signal
def playback_paused(self):
@ -162,4 +157,7 @@ class BassPlayer(GObject.GObject):
@GObject.Signal
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_state(Gst.CLOCK_TIME_NONE)[1],
Gst.State.READY)
self.assertIsNone(base.timeout, 0)
self.assertIsNone(base.timeout)
def test_bass_player_bus(self):
base = bass.BassPlayer()