From 64ad1ab3e0c2e4a5d0a33bc11f818b6bcb721f37 Mon Sep 17 00:00:00 2001 From: Storm Dragon Date: Sat, 4 Apr 2026 23:04:33 -0400 Subject: [PATCH] Hopefully fixed weird gstreamer traceback. --- README-DEVELOPMENT.md | 4 ++-- README.md | 2 ++ build-local.sh | 6 ++++++ src/cthulhu/gstreamer_support.py | 29 +++++++++++++++++++++++++++++ src/cthulhu/meson.build | 1 + src/cthulhu/piper_audio_player.py | 8 ++++---- src/cthulhu/sound.py | 12 ++++++------ src/cthulhu/sound_helper.py | 5 +++-- src/cthulhu/sound_sink.py | 6 +++--- tests/test_sound_recovery.py | 19 +++++++++++++++++++ 10 files changed, 75 insertions(+), 17 deletions(-) create mode 100644 src/cthulhu/gstreamer_support.py diff --git a/README-DEVELOPMENT.md b/README-DEVELOPMENT.md index 660c1a7..72f33b2 100644 --- a/README-DEVELOPMENT.md +++ b/README-DEVELOPMENT.md @@ -98,11 +98,11 @@ git status ## Dependencies -- **Runtime**: python3, pygobject-3.0, pluggy, AT-SPI2 +- **Runtime**: python3, pygobject-3.0, pluggy, tomlkit, AT-SPI2 - **Build**: meson, ninja, gettext - **Optional**: dasbus (for D-Bus service), BrlTTY, speech-dispatcher, piper-tts Install build dependencies on Arch Linux: ```bash -sudo pacman -S meson ninja gettext python-dasbus +sudo pacman -S meson ninja gettext python-dasbus python-tomlkit ``` diff --git a/README.md b/README.md index faa9cfb..205da46 100644 --- a/README.md +++ b/README.md @@ -179,6 +179,7 @@ Ensure you have the development dependencies installed: ```bash sudo pacman -S python python-gobject gtk3 at-spi2-core at-spi2-atk \ python-speechd gstreamer python-pluggy python-dasbus \ + python-tomlkit \ meson ninja pkgconf intltool gettext ``` @@ -187,6 +188,7 @@ sudo pacman -S python python-gobject gtk3 at-spi2-core at-spi2-atk \ sudo apt install python3 python3-gi python3-gi-cairo gir1.2-gtk-3.0 \ at-spi2-core libatk-adaptor python3-speechd \ gstreamer1.0-plugins-base python3-pluggy python3-dasbus \ + python3-tomlkit \ meson ninja-build pkg-config intltool gettext ``` diff --git a/build-local.sh b/build-local.sh index 85f0af3..171ad74 100755 --- a/build-local.sh +++ b/build-local.sh @@ -26,6 +26,12 @@ for cmd in meson ninja python3; do fi done +if ! python3 -c "import tomlkit" 2>/dev/null; then + echo "Error: Python module tomlkit is not installed" + echo "Please install: python-tomlkit" + exit 1 +fi + # Check for optional dependencies missingOptional=() if ! python3 -c "import gi" 2>/dev/null; then diff --git a/src/cthulhu/gstreamer_support.py b/src/cthulhu/gstreamer_support.py new file mode 100644 index 0000000..48b1745 --- /dev/null +++ b/src/cthulhu/gstreamer_support.py @@ -0,0 +1,29 @@ +#!/usr/bin/env python3 +# +# Copyright (c) 2026 Stormux +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. + +"""Compatibility helpers for GStreamer GI bindings.""" + +from __future__ import annotations + +from typing import Any + + +def gst_init_check_available(gst: Any) -> bool: + """Return Gst.init_check(None) availability across GI variants.""" + + initCheckResult = gst.init_check(None) + if isinstance(initCheckResult, tuple): + return bool(initCheckResult[0]) + + return bool(initCheckResult) diff --git a/src/cthulhu/meson.build b/src/cthulhu/meson.build index 9f1ed5d..3b9456a 100644 --- a/src/cthulhu/meson.build +++ b/src/cthulhu/meson.build @@ -48,6 +48,7 @@ cthulhu_python_sources = files([ 'formatting.py', 'focus_manager.py', 'generator.py', + 'gstreamer_support.py', 'guilabels.py', 'highlighter.py', 'input_event.py', diff --git a/src/cthulhu/piper_audio_player.py b/src/cthulhu/piper_audio_player.py index 55ad83f..667edaa 100644 --- a/src/cthulhu/piper_audio_player.py +++ b/src/cthulhu/piper_audio_player.py @@ -31,6 +31,9 @@ import threading import gi from gi.repository import GLib +from . import debug +from . import gstreamer_support +from . import sound_sink try: gi.require_version('Gst', '1.0') @@ -38,10 +41,7 @@ try: except Exception: _gstreamerAvailable = False else: - _gstreamerAvailable, args = Gst.init_check(None) - -from . import debug -from . import sound_sink + _gstreamerAvailable = gstreamer_support.gst_init_check_available(Gst) class PiperAudioPlayer: diff --git a/src/cthulhu/sound.py b/src/cthulhu/sound.py index 4077b2d..ed3bb6b 100644 --- a/src/cthulhu/sound.py +++ b/src/cthulhu/sound.py @@ -39,6 +39,11 @@ import threading from typing import Any, Optional, Tuple import gi +from . import debug +from . import gstreamer_support +from . import settings +from . import sound_sink +from .sound_generator import Icon, Tone try: gi.require_version('Gst', '1.0') @@ -46,12 +51,7 @@ try: except Exception: _gstreamerAvailable: bool = False else: - _gstreamerAvailable, _args = Gst.init_check(None) - -from . import debug -from . import settings -from . import sound_sink -from .sound_generator import Icon, Tone + _gstreamerAvailable = gstreamer_support.gst_init_check_available(Gst) _soundSystemFailureReason: Optional[str] = None diff --git a/src/cthulhu/sound_helper.py b/src/cthulhu/sound_helper.py index 2e1ec80..f63132f 100644 --- a/src/cthulhu/sound_helper.py +++ b/src/cthulhu/sound_helper.py @@ -28,6 +28,7 @@ gi.require_version('GLib', '2.0') gi.require_version('Gst', '1.0') from gi.repository import GLib, Gst +from . import gstreamer_support from . import settings from . import sound_sink @@ -75,7 +76,7 @@ class SoundWorker: """Runs a long-lived GStreamer worker for icon and tone playback.""" def __init__(self, soundSink: Optional[str] = None) -> None: - available, _args = Gst.init_check(None) + available = gstreamer_support.gst_init_check_available(Gst) if not available: raise RuntimeError("GStreamer is not available") @@ -371,7 +372,7 @@ def play_file_once( soundSink: Optional[str] = None, volume: float = 1.0, ) -> int: - available, _args = Gst.init_check(None) + available = gstreamer_support.gst_init_check_available(Gst) if not available: print("GStreamer is not available", file=sys.stderr) return 1 diff --git a/src/cthulhu/sound_sink.py b/src/cthulhu/sound_sink.py index f78a7c4..6305cb2 100644 --- a/src/cthulhu/sound_sink.py +++ b/src/cthulhu/sound_sink.py @@ -19,6 +19,8 @@ from __future__ import annotations from typing import Any, Optional, Tuple import gi +from . import gstreamer_support +from . import settings try: gi.require_version('Gst', '1.0') @@ -26,9 +28,7 @@ try: except Exception: _gstreamerAvailable: bool = False else: - _gstreamerAvailable, _args = Gst.init_check(None) - -from . import settings + _gstreamerAvailable = gstreamer_support.gst_init_check_available(Gst) _SINK_ELEMENT_BY_SETTING = { settings.SOUND_SINK_PIPEWIRE: "pipewiresink", diff --git a/tests/test_sound_recovery.py b/tests/test_sound_recovery.py index 86910b2..d6d9560 100644 --- a/tests/test_sound_recovery.py +++ b/tests/test_sound_recovery.py @@ -1,6 +1,7 @@ import sys import types import unittest +import importlib from pathlib import Path from unittest import mock @@ -31,6 +32,7 @@ soundGeneratorStub.Tone = _Tone sys.modules.setdefault("cthulhu.sound_generator", soundGeneratorStub) from cthulhu import settings +from cthulhu import piper_audio_player from cthulhu import sound from cthulhu import sound_sink @@ -46,6 +48,23 @@ class SoundSinkTests(unittest.TestCase): self.assertGreaterEqual(len(candidates), 1) self.assertEqual(candidates[0], "autoaudiosink") + def test_gstreamer_init_check_bool_result_does_not_break_imports(self): + modules = [ + sound_sink, + sound, + piper_audio_player, + ] + + with mock.patch.object(sound_sink.Gst, "init_check", return_value=True): + reloadedModules = [] + for module in modules: + reloaded = importlib.reload(module) + reloadedModules.append(reloaded) + self.assertTrue(reloaded._gstreamerAvailable) + + for module in reloadedModules: + importlib.reload(module) + class PlayerRecoveryTests(unittest.TestCase): def test_worker_diagnostic_marks_restart_required(self):