fix: clean stale JACK SHM before client creation in profile handler
CI / test (push) Has been cancelled

jack.Client('pi-multifx') fails with server_error (0x21) when stale
jack_sem.0_default_pi-multifx segments remain in /dev/shm from a
previous client instance. This commonly happens after a profile change
(buffer+rate) because:

1. stop_jack() kills jackd and cleans SHM
2. start_jack() starts new JACK server
3. Old process's JackAudioClient.__del__ (garbage collection) recreates
   the pi-multifx semaphore in /dev/shm
4. jack_client.start() → jack.Client('pi-multifx') finds stale SHM
   and fails with server_error → no pi-multifx ports → NAM never
   called → 0% nam_cpu → 'nam is dying'

Fix:
- Clean /dev/shm/jack* in profile handler right before jack_client.start()
- JackAudioClient.start() also retries once with SHM cleanup on
  server_error, so other callers are also protected.
This commit is contained in:
2026-06-18 17:14:35 -04:00
parent de5723f138
commit ce82207d03
2 changed files with 32 additions and 1 deletions
+18 -1
View File
@@ -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()
+14
View File
@@ -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: