Fix audio timeout when changing buffer size/sample rate
Two bugs: 1. **Deadlock in set_audio_profile() (root cause of timeout)** jack_client.stop() was called BEFORE killing the JACK server. jack.Client.deactivate() is a synchronous call that blocks until the JACK RT callback thread acknowledges. When ALSA reconfigures (period/rate change), the RT thread can stall and deactivate() hangs permanently. Reversed order: kill JACK server first (via killall jackd) to force-kill the RT thread, then clean up the Python client. Same fix applied to device hot-swap path. 2. **Pipeline crash after period change** _CombFilter.buf and _AllpassFilter.buf were fixed-size arrays at BLOCK_SIZE (256). If JACK restarts with a different period (e.g. 512), self.buf[:] = block throws a shape mismatch in the RT callback -> audio dies permanently. Made internal buffers dynamically resize to match input block size.
This commit is contained in:
+10
-7
@@ -1480,17 +1480,18 @@ class WebServer:
|
||||
target_profile["period"], target_profile["rate"],
|
||||
)
|
||||
|
||||
# Stop JACK audio client first
|
||||
jack_client = self.deps.jack_audio
|
||||
if jack_client:
|
||||
jack_client.stop()
|
||||
|
||||
# Update LATENCY_PROFILES with custom entry so latency_profile resolves it
|
||||
LATENCY_PROFILES[effective_key] = target_profile
|
||||
|
||||
# ── Kill JACK server FIRST (breaks any client deadlock) ──
|
||||
# This interrupts the audio callback thread, releasing any lock
|
||||
# that jack_client.stop() would need.
|
||||
# jack.Client.deactivate() is a synchronous JACK protocol call
|
||||
# that blocks until the RT callback thread acknowledges. If the
|
||||
# RT thread is stuck (ALSA reconfiguring, xruns), deactivate()
|
||||
# hangs permanently. Kill the server first to force-kill the
|
||||
# RT thread, then clean up the client.
|
||||
# See also: JackAudioClient.stop() which calls deactivate().
|
||||
try:
|
||||
audio_sys.stop_jack()
|
||||
except Exception:
|
||||
@@ -1634,13 +1635,15 @@ class WebServer:
|
||||
try:
|
||||
audio_sys = self.deps.audio_system
|
||||
jack_client = self.deps.jack_audio
|
||||
if jack_client:
|
||||
jack_client.stop()
|
||||
# Kill JACK server FIRST to avoid deadlock on
|
||||
# jack.Client.deactivate() (same pattern as profile switch)
|
||||
if "input_device" in data:
|
||||
audio_sys.config.input_device = str(data["input_device"])
|
||||
if "output_device" in data:
|
||||
audio_sys.config.output_device = str(data["output_device"])
|
||||
audio_sys.stop_jack()
|
||||
if jack_client:
|
||||
jack_client.stop()
|
||||
ok = audio_sys.start_jack(timeout=10)
|
||||
if not ok:
|
||||
logger.warning("JACK restart failed after device change — rolling back")
|
||||
|
||||
Reference in New Issue
Block a user