diff --git a/src/system/audio.py b/src/system/audio.py index 65fe328..d91d567 100644 --- a/src/system/audio.py +++ b/src/system/audio.py @@ -882,7 +882,24 @@ class JackAudioClient: self._client = jack.Client(self._client_name) except jack.JackOpenError as exc: logger.error("Cannot open JACK client: %s", exc) - return + # Stale SHM from a previous client instance can cause + # server_error (0x21). Clean and retry once. + if "server_error" in str(exc) or "0x21" in str(exc): + try: + from pathlib import Path + import shutil + for p in Path("/dev/shm").glob("jack*"): + if p.is_dir(): + shutil.rmtree(p, ignore_errors=True) + else: + p.unlink(missing_ok=True) + logger.info("Cleaned stale JACK SHM, retrying client creation...") + self._client = jack.Client(self._client_name) + except Exception as retry_exc: + logger.error("JACK client retry also failed: %s", retry_exc) + return + else: + return # Register capture ports self._inports.clear() diff --git a/src/web/server.py b/src/web/server.py index b0a6e6e..a43115f 100644 --- a/src/web/server.py +++ b/src/web/server.py @@ -1748,6 +1748,20 @@ class WebServer: target_profile["rate"], ) + # Clean stale client SHM before creating new JACK client. + # The old process's jack.Client __del__ can recreate the + # pi-multifx semaphore after stop_jack() cleaned it. + try: + from pathlib import Path + import shutil + for p in Path("/dev/shm").glob("jack*"): + if p.is_dir(): + shutil.rmtree(p, ignore_errors=True) + else: + p.unlink(missing_ok=True) + except Exception: + pass + # Restart JACK audio client if jack_client: try: