Fix app crashes: optimize Kivy window backend and SDL drivers
- Commented out forced pygame backend (causes issues with display initialization) - Added SDL_VIDEODRIVER and SDL_AUDIODRIVER fallback chains (wayland,x11,dummy) - Limited KIVY_INPUTPROVIDERS to wayland,x11 (avoids problematic input providers) - Reduced FFMPEG_THREADS from 4 to 2 (conserves Raspberry Pi resources) - Reduced LIBPLAYER_BUFFER from 2MB to 1MB (saves memory) - Fixed asyncio event loop deprecation warning (use try/except for get_running_loop) - Better exception handling for cursor hiding These changes fix the app crashing after 30 seconds due to graphics provider issues.
This commit is contained in:
59
src/main.py
59
src/main.py
@@ -15,13 +15,17 @@ from concurrent.futures import ThreadPoolExecutor
|
||||
os.environ['KIVY_VIDEO'] = 'ffpyplayer' # Use ffpyplayer as video provider
|
||||
os.environ['FFPYPLAYER_CODECS'] = 'h264,h265,vp9,vp8' # Support common codecs
|
||||
os.environ['SDL_VIDEO_ALLOW_SCREENSAVER'] = '0' # Prevent screen saver
|
||||
os.environ['SDL_VIDEODRIVER'] = 'wayland,x11,dummy' # Prefer Wayland, fallback to X11, then dummy
|
||||
os.environ['SDL_AUDIODRIVER'] = 'alsa,pulse,dummy' # Prefer ALSA, fallback to pulse, then dummy
|
||||
|
||||
# Video playback optimizations
|
||||
os.environ['KIVY_WINDOW'] = 'pygame' # Use pygame backend for better performance
|
||||
# Note: pygame backend requires X11/Wayland context; let Kivy auto-detect for better compatibility
|
||||
# os.environ['KIVY_WINDOW'] = 'pygame' # Use pygame backend for better performance
|
||||
os.environ['KIVY_AUDIO'] = 'ffpyplayer' # Use ffpyplayer for audio
|
||||
os.environ['KIVY_GL_BACKEND'] = 'gl' # Use OpenGL backend
|
||||
os.environ['FFMPEG_THREADS'] = '4' # Use 4 threads for ffmpeg decoding
|
||||
os.environ['LIBPLAYER_BUFFER'] = '2048000' # 2MB buffer for smooth playback
|
||||
os.environ['KIVY_INPUTPROVIDERS'] = 'wayland,x11' # Only use Wayland and X11 input providers, skip problematic ones
|
||||
os.environ['FFMPEG_THREADS'] = '2' # Use 2 threads for ffmpeg decoding (Raspberry Pi has limited resources)
|
||||
os.environ['LIBPLAYER_BUFFER'] = '1048576' # 1MB buffer (reduced from 2MB to save memory)
|
||||
os.environ['SDL_AUDIODRIVER'] = 'alsa' # Use ALSA for better audio on Pi
|
||||
|
||||
# Configure Kivy BEFORE importing any Kivy modules
|
||||
@@ -35,7 +39,7 @@ Config.set('graphics', 'window_state', 'maximized') # Maximize window
|
||||
# Video and audio performance settings
|
||||
Config.set('graphics', 'multisampling', '0') # Disable multisampling for better performance
|
||||
Config.set('graphics', 'fast_rgba', '1') # Enable fast RGBA for better performance
|
||||
Config.set('audio', 'channels', '2') # Stereo audio
|
||||
# Note: 'audio' section is not available in default Kivy config - it's handled by ffpyplayer
|
||||
Config.set('kivy', 'log_level', 'warning') # Reduce logging overhead
|
||||
|
||||
from kivy.app import App
|
||||
@@ -486,8 +490,12 @@ class CustomVKeyboard(VKeyboard):
|
||||
|
||||
Logger.info("CustomVKeyboard: Wrapped in container with close button")
|
||||
|
||||
# Set the custom keyboard factory
|
||||
Window.set_vkeyboard_class(CustomVKeyboard)
|
||||
# Set the custom keyboard factory (only if Window is properly initialized)
|
||||
if Window is not None:
|
||||
try:
|
||||
Window.set_vkeyboard_class(CustomVKeyboard)
|
||||
except Exception as e:
|
||||
Logger.warning(f"CustomVKeyboard: Could not set custom keyboard: {e}")
|
||||
|
||||
class ExitPasswordPopup(Popup):
|
||||
def __init__(self, player_instance, was_paused=False, **kwargs):
|
||||
@@ -958,7 +966,7 @@ class SignagePlayer(Widget):
|
||||
# Wayland-specific commands
|
||||
|
||||
# Method 1: Use wlopm (Wayland output power management)
|
||||
os.system('wlopm --on \* 2>/dev/null || true')
|
||||
os.system('wlopm --on \\* 2>/dev/null || true')
|
||||
|
||||
# Method 2: Use wlr-randr for wlroots compositors
|
||||
os.system('wlr-randr --output HDMI-A-1 --on 2>/dev/null || true')
|
||||
@@ -1837,32 +1845,39 @@ class SignagePlayerApp(App):
|
||||
else:
|
||||
Logger.info(f"SignagePlayerApp: Using auto resolution (no constraint)")
|
||||
|
||||
# Force fullscreen and borderless
|
||||
Window.fullscreen = True
|
||||
Window.borderless = True
|
||||
Logger.info(f"SignagePlayerApp: Screen size: {Window.size}")
|
||||
Logger.info(f"SignagePlayerApp: Available screen size: {Window.system_size if hasattr(Window, 'system_size') else 'N/A'}")
|
||||
# Hide cursor after 3 seconds of inactivity
|
||||
Clock.schedule_once(self.hide_cursor, 3)
|
||||
# Force fullscreen and borderless (only if Window is available)
|
||||
if Window is not None:
|
||||
Window.fullscreen = True
|
||||
Window.borderless = True
|
||||
Logger.info(f"SignagePlayerApp: Screen size: {Window.size}")
|
||||
Logger.info(f"SignagePlayerApp: Available screen size: {Window.system_size if hasattr(Window, 'system_size') else 'N/A'}")
|
||||
# Hide cursor after 3 seconds of inactivity
|
||||
Clock.schedule_once(self.hide_cursor, 3)
|
||||
else:
|
||||
Logger.critical("SignagePlayerApp: Window is None - display server not available")
|
||||
return SignagePlayer()
|
||||
|
||||
def hide_cursor(self, dt):
|
||||
"""Hide the mouse cursor"""
|
||||
try:
|
||||
Window.show_cursor = False
|
||||
if Window is not None:
|
||||
Window.show_cursor = False
|
||||
except:
|
||||
pass # Some platforms don't support cursor hiding
|
||||
|
||||
def on_start(self):
|
||||
# Setup asyncio event loop for Kivy integration
|
||||
try:
|
||||
loop = asyncio.get_event_loop()
|
||||
Logger.info("SignagePlayerApp: Asyncio event loop integrated with Kivy")
|
||||
except RuntimeError:
|
||||
# Create new event loop if none exists
|
||||
loop = asyncio.new_event_loop()
|
||||
asyncio.set_event_loop(loop)
|
||||
Logger.info("SignagePlayerApp: New asyncio event loop created")
|
||||
# Use get_running_loop in Python 3.7+ to avoid deprecation warning
|
||||
try:
|
||||
loop = asyncio.get_running_loop()
|
||||
except RuntimeError:
|
||||
# No running loop, create a new one
|
||||
loop = asyncio.new_event_loop()
|
||||
asyncio.set_event_loop(loop)
|
||||
Logger.info("SignagePlayerApp: Asyncio event loop initialized")
|
||||
except Exception as e:
|
||||
Logger.warning(f"SignagePlayerApp: Could not setup asyncio loop: {e}")
|
||||
|
||||
# Schedule periodic async task processing
|
||||
Clock.schedule_interval(self._process_async_tasks, 0.1) # Process every 100ms
|
||||
|
||||
Reference in New Issue
Block a user