Hopefully fixed weird gstreamer traceback.
This commit is contained in:
@@ -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
|
||||
```
|
||||
|
||||
@@ -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
|
||||
```
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
29
src/cthulhu/gstreamer_support.py
Normal file
29
src/cthulhu/gstreamer_support.py
Normal file
@@ -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)
|
||||
@@ -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',
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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):
|
||||
|
||||
Reference in New Issue
Block a user