fix: multiple issues preventing NAM from surviving rate/period changes
CI / test (push) Has been cancelled
CI / test (push) Has been cancelled
Root causes of 'changing bit rate / sample rate kills NAM': 1. Zombie jackd from stale second Python process — when stop_jack() kills jackd, the other process's auto-restart respawns jackd with OLD config between stop and start. start_jack() sees a running jackd and returns True immediately without verifying it's actually accepting connections. 2. Zombie Python process from incomplete service restart — two main.py instances running, each with its own AudioSystem and JackAudioClient. Profile change kills one JACK but the other respawns it. jack_client.start() then fails with server_error because the stale SHM conflicts. 3. start_jack() returned True for a dead jackd — process exists but JackServer::Open failed with -1 (bad period/rate for device). No SHM socket was created, but the process check passed. Fixes: - _ensure_singleton(): kill any other main.py process at boot - start_jack(): verify jack_default_0_0 SHM socket exists before returning True; kill zombie process if socket is missing - Profile handler: clean SHM right before jack_client.start() - JackAudioClient.start(): retry once with SHM cleanup on server_error (0x21)
This commit is contained in:
@@ -55,6 +55,28 @@ from src.system.config import DEFAULT_CONFIG_PATH, load_config, save_config, DEF
|
||||
_AUTH_PIN_SEEN = False
|
||||
|
||||
|
||||
def _ensure_singleton() -> None:
|
||||
"""Kill any other main.py processes (from stale service restarts)."""
|
||||
import subprocess, os
|
||||
my_pid = os.getpid()
|
||||
try:
|
||||
r = subprocess.run(
|
||||
["pgrep", "-f", "python3.*main.py"],
|
||||
capture_output=True, text=True, timeout=3,
|
||||
)
|
||||
if r.returncode == 0:
|
||||
for pid_str in r.stdout.strip().split():
|
||||
pid = int(pid_str)
|
||||
if pid != my_pid:
|
||||
try:
|
||||
os.kill(pid, 9)
|
||||
logger.info("Killed stale pedal process PID %d", pid)
|
||||
except (OSError, ProcessLookupError):
|
||||
pass
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
def _ensure_auth_pin(config: dict, config_path: Path) -> str:
|
||||
"""Generate a random 6-digit auth PIN on first boot and persist it to config.
|
||||
|
||||
@@ -790,6 +812,9 @@ def main() -> int:
|
||||
|
||||
Returns exit code 0 on clean shutdown, 1 on boot failure.
|
||||
"""
|
||||
# Kill any stale pedal processes before doing anything else
|
||||
_ensure_singleton()
|
||||
|
||||
# Lock process memory early to prevent page faults in RT callback
|
||||
try:
|
||||
import ctypes
|
||||
|
||||
Reference in New Issue
Block a user