86 lines
3.0 KiB
Python
86 lines
3.0 KiB
Python
# Copyright 2022 (c) Anna Schumaker.
|
|
"""A custom GObject managing a GStreamer playbin."""
|
|
import pathlib
|
|
from gi.repository import GObject
|
|
from gi.repository import Gst
|
|
from . import replaygain
|
|
from .. import path
|
|
|
|
|
|
class Player(GObject.GObject):
|
|
"""Wraps a GStreamer Playbin with an interface for our application."""
|
|
|
|
volume = GObject.Property(type=float, default=1.0)
|
|
|
|
file = GObject.Property(type=GObject.TYPE_PYOBJECT)
|
|
have_track = GObject.Property(type=bool, default=False)
|
|
|
|
def __init__(self):
|
|
"""Initialize the audio Player."""
|
|
super().__init__()
|
|
self._replaygain = replaygain.Filter()
|
|
|
|
self._playbin = Gst.ElementFactory.make("playbin")
|
|
self._playbin.set_property("audio-filter", self._replaygain)
|
|
self._playbin.set_property("video-sink",
|
|
Gst.ElementFactory.make("fakesink"))
|
|
self._playbin.set_state(Gst.State.READY)
|
|
|
|
bus = self._playbin.get_bus()
|
|
bus.add_signal_watch()
|
|
bus.connect("message::eos", self.__msg_eos)
|
|
bus.connect("message::stream-start", self.__msg_stream_start)
|
|
|
|
self.bind_property("volume", self._playbin, "volume")
|
|
|
|
self.connect("notify::file", self.__notify_file)
|
|
|
|
def __msg_eos(self, bus: Gst.Bus, message: Gst.Message) -> None:
|
|
self.emit("eos")
|
|
|
|
def __msg_stream_start(self, bus: Gst.Bus, message: Gst.Message) -> None:
|
|
self.emit("file-loaded",
|
|
path.from_uri(self._playbin.get_property("current-uri")))
|
|
|
|
def __notify_file(self, player: GObject.GObject, param) -> None:
|
|
if self.file:
|
|
uri = self.file.as_uri()
|
|
print(f"audio: loading {uri}")
|
|
self._playbin.set_property("uri", uri)
|
|
|
|
def get_replaygain(self) -> tuple[bool, str | None]:
|
|
"""Get the current ReplayGain mode."""
|
|
mode = self._replaygain.mode
|
|
return (False, None) if mode == "disabled" else (True, mode)
|
|
|
|
def get_state(self) -> Gst.State:
|
|
"""Get the current state of the Player."""
|
|
return self._playbin.get_state(Gst.CLOCK_TIME_NONE).state
|
|
|
|
def set_replaygain(self, enabled: bool, mode: str) -> None:
|
|
"""Set the ReplayGain mode."""
|
|
self._replaygain.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."""
|
|
if self._playbin.set_state(state) == Gst.StateChangeReturn.ASYNC:
|
|
self.get_state()
|
|
|
|
def shutdown(self) -> None:
|
|
"""Shut down the player."""
|
|
self._playbin.set_state(Gst.State.NULL)
|
|
|
|
@GObject.Signal(arg_types=(GObject.TYPE_PYOBJECT,))
|
|
def file_loaded(self, file: pathlib.Path) -> None:
|
|
"""Signal that a new URI has started."""
|
|
print("audio: file loaded")
|
|
self.have_track = True
|
|
|
|
@GObject.Signal
|
|
def eos(self) -> None:
|
|
"""Signal that the current track has ended."""
|
|
print("audio: end of stream")
|
|
self.set_state_sync(Gst.State.READY)
|
|
self.have_track = False
|
|
self.file = None
|