audio: Replace the playbin audio-filter with the new filter

And wire up the bg-enabled and bg-volume properties from the header to
the playbin properties with the same name.

Implements: #50 ("Background Music Mode")
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This commit is contained in:
Anna Schumaker 2023-05-28 16:51:30 -04:00
parent 84fbd94aa1
commit 8afd1a6240
4 changed files with 50 additions and 14 deletions

View File

@ -127,7 +127,8 @@ class Application(Adw.Application):
def build_header(self) -> header.Header:
"""Build a new header instance."""
hdr = header.Header(sql=self.db, title=VERSION_STRING)
hdr.bind_property("volume", self.player, "volume")
for prop in ["bg-enabled", "bg-volume", "volume"]:
hdr.bind_property(prop, self.player, prop)
for (setting, property) in [("audio.volume", "volume"),
("audio.background.enabled", "bg-enabled"),
("audio.background.volume", "bg-volume"),

View File

@ -4,7 +4,7 @@ import pathlib
from gi.repository import GObject
from gi.repository import GLib
from gi.repository import Gst
from . import replaygain
from . import filter
from .. import path
from .. import tmpdir
@ -35,16 +35,18 @@ class Player(GObject.GObject):
playtime = GObject.Property(type=float)
savedtime = GObject.Property(type=float)
bg_enabled = GObject.Property(type=bool, default=False)
bg_volume = GObject.Property(type=float, default=0.5)
pause_on_load = GObject.Property(type=bool, default=False)
def __init__(self):
"""Initialize the audio Player."""
super().__init__()
self._replaygain = replaygain.Filter()
self._filter = filter.Filter()
self._timeout = None
self._playbin = Gst.ElementFactory.make("playbin")
self._playbin.set_property("audio-filter", self._replaygain)
self._playbin.set_property("audio-filter", self._filter)
self._playbin.set_property("video-sink",
Gst.ElementFactory.make("fakesink"))
self._playbin.set_state(Gst.State.READY)
@ -58,6 +60,8 @@ class Player(GObject.GObject):
bus.connect("message::tag", self.__msg_tags)
self.bind_property("volume", self._playbin, "volume")
self.bind_property("bg-enabled", self._filter, "bg-enabled")
self.bind_property("bg-volume", self._filter, "bg-volume")
self.connect("notify::file", self.__notify_file)
@ -163,7 +167,7 @@ class Player(GObject.GObject):
def get_replaygain(self) -> tuple[bool, str | None]:
"""Get the current ReplayGain mode."""
mode = self._replaygain.mode
mode = self._filter.rg_mode
return (False, None) if mode == "disabled" else (True, mode)
def get_state(self) -> Gst.State:
@ -191,7 +195,7 @@ class Player(GObject.GObject):
def set_replaygain(self, enabled: bool, mode: str) -> None:
"""Set the ReplayGain mode."""
self._replaygain.mode = mode if enabled else "disabled"
self._filter.rg_mode = mode if enabled else "disabled"
def set_state_sync(self, state: Gst.State) -> None:
"""Set the state of the playbin, and wait for it to change."""

View File

@ -53,6 +53,27 @@ class TestAudio(unittest.TestCase):
self.assertRegex(self.player._playbin.get_property("video-sink").name,
r"fakesink\d+")
@unittest.mock.patch("sys.stdout", new_callable=io.StringIO)
def test_filter(self, mock_stdout: io.StringIO):
"""Test the filter element added to the playbin."""
self.assertIsInstance(self.player._filter,
emmental.audio.filter.Filter)
self.assertEqual(self.player._playbin.get_property("audio-filter"),
self.player._filter)
self.assertFalse(self.player.bg_enabled)
self.assertEqual(self.player.bg_volume, 0.5)
self.player.bg_enabled = True
self.player.bg_volume = 0.75
self.assertTrue(self.player._filter.bg_enabled)
self.assertEqual(self.player._filter.bg_volume, 0.75)
self.player.bg_enabled = False
self.player.bg_volume = 0.5
self.assertFalse(self.player._filter.bg_enabled)
self.assertEqual(self.player.bg_volume, 0.5)
@unittest.mock.patch("sys.stdout", new_callable=io.StringIO)
def test_eos(self, mock_stdout: io.StringIO):
"""Test handling an EOS message."""
@ -297,22 +318,17 @@ class TestAudio(unittest.TestCase):
@unittest.mock.patch("sys.stdout", new_callable=io.StringIO)
def test_replaygain(self, mock_stdout: io.StringIO):
"""Test that ReplayGain functions work as expected."""
self.assertIsInstance(self.player._replaygain,
emmental.audio.replaygain.Filter)
self.assertEqual(self.player._playbin.get_property("audio-filter"),
self.player._replaygain)
self.assertEqual(self.player._replaygain.mode, "disabled")
self.assertEqual(self.player._filter.rg_mode, "disabled")
self.assertEqual(self.player.get_replaygain(), (False, None))
self.player.set_replaygain(True, "album")
self.assertEqual(self.player._replaygain.mode, "album")
self.assertEqual(self.player._filter.rg_mode, "album")
self.assertEqual(self.player.get_replaygain(), (True, "album"))
self.assertRegex(mock_stdout.getvalue(),
r"audio: setting ReplayGain mode to 'album'")
self.player.set_replaygain(False, "track")
self.assertEqual(self.player._replaygain.mode, "disabled")
self.assertEqual(self.player._filter.rg_mode, "disabled")
self.assertEqual(self.player.get_replaygain(), (False, None))
self.assertRegex(mock_stdout.getvalue(),
r"audio: setting ReplayGain mode to 'disabled'")

View File

@ -220,3 +220,18 @@ class TestEmmental(unittest.TestCase):
self.assertEqual(player.get_replaygain(), (True, "track"))
win.header.rg_mode = "album"
self.assertEqual(player.get_replaygain(), (True, "album"))
@unittest.mock.patch("sys.stdout", new_callable=io.StringIO)
def test_background_mode(self, mock_stdout: io.StringIO):
"""Test setting background mode."""
self.application.db = emmental.db.Connection()
self.application.factory = emmental.playlist.Factory(
self.application.db)
self.application.player = emmental.audio.Player()
win = self.application.build_window()
player = self.application.player
win.header.bg_enabled = True
win.header.bg_volume = 0.5
self.assertTrue(player.bg_enabled)
self.assertEqual(player.bg_volume, 0.5)