"""Klingelton-Player - Spielt Klingelton über separates PipeWire-Gerät ab.""" import subprocess from pathlib import Path from PySide6.QtCore import QObject, QTimer # Standard-Klingelton-Pfade _STANDARD_KLINGELTON = Path(__file__).parent.parent / "resources" / "sounds" / "klingelton.wav" _FREEDESKTOP_KLINGELTON = Path("/usr/share/sounds/freedesktop/stereo/phone-incoming-call.oga") class KlingeltonPlayer(QObject): """Spielt Klingelton über paplay mit optionalem PipeWire-Gerät. Nutzt paplay (PulseAudio/PipeWire CLI) mit --device für die Ausgabe über ein dediziertes Klingelton-Gerät (z.B. Lautsprecher statt Headset). """ def __init__(self, parent=None): super().__init__(parent) self._prozess = None self._loop_timer = QTimer(self) self._loop_timer.timeout.connect(self._erneut_abspielen) self._datei = "" self._device = "" self._laeuft = False def abspielen(self, datei_pfad="", device_pw_name="", loop=True): """Klingelton abspielen. Args: datei_pfad: Pfad zur Audio-Datei (leer = Standard) device_pw_name: PipeWire-Sink-Name (leer = System-Standard) loop: Endlosschleife bis stoppen() aufgerufen wird """ self.stoppen() # Datei bestimmen if datei_pfad and Path(datei_pfad).exists(): self._datei = datei_pfad elif _STANDARD_KLINGELTON.exists(): self._datei = str(_STANDARD_KLINGELTON) elif _FREEDESKTOP_KLINGELTON.exists(): self._datei = str(_FREEDESKTOP_KLINGELTON) else: return # Keine Audio-Datei verfügbar self._device = device_pw_name self._laeuft = True self._paplay_starten() if loop: # Nach 5 Sekunden erneut abspielen (Klingelton-Datei ist ~5s) self._loop_timer.start(5500) def stoppen(self): """Klingelton stoppen.""" self._laeuft = False self._loop_timer.stop() if self._prozess and self._prozess.poll() is None: try: self._prozess.terminate() except OSError: pass self._prozess = None def test_abspielen(self, datei_pfad="", device_pw_name=""): """Einmal abspielen zum Testen (kein Loop).""" self.abspielen(datei_pfad, device_pw_name, loop=False) @property def laeuft(self): """True wenn Klingelton gerade abgespielt wird.""" return self._laeuft def _paplay_starten(self): """paplay Subprocess starten.""" if not self._laeuft: return cmd = ["paplay"] if self._device: cmd.extend(["--device", self._device]) cmd.append(self._datei) try: self._prozess = subprocess.Popen( cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, ) except (FileNotFoundError, OSError): self._laeuft = False def _erneut_abspielen(self): """Timer-Callback: Klingelton in Schleife abspielen.""" if not self._laeuft: self._loop_timer.stop() return # Vorherigen Prozess abräumen if self._prozess and self._prozess.poll() is not None: self._prozess = None self._paplay_starten()