Eliminate hang completely by making ALSA interruption immediate

Problem:
Previous fix reduced but didn't eliminate the hang when switching audio
sources. The C layer was still blocking on snd_pcm_readi()/snd_pcm_writei()
while holding the mutex, preventing cleanup from proceeding.

Solution:
Call snd_pcm_drop() BEFORE acquiring the mutex in close functions. This
immediately interrupts any blocking ALSA read/write operations, causing them
to return with -EBADFD or -ESTRPIPE. The sequence is now:

1. Set stop_requested flag
2. Call snd_pcm_drop() to interrupt blocking I/O (no mutex needed - thread-safe)
3. Acquire mutex for cleanup
4. Close handles and free resources
5. Release mutex

This makes audio source switching instantaneous with zero hang.

Changes:
- jetkvm_audio_capture_close(): Drop PCM before mutex
- jetkvm_audio_playback_close(): Drop PCM before mutex

Tested: USB↔HDMI switching now happens instantly with no delay.
This commit is contained in:
Alex P 2025-11-18 01:46:29 +02:00
parent 051950f220
commit a6b7ac50ef
1 changed files with 14 additions and 4 deletions

View File

@ -776,7 +776,13 @@ void jetkvm_audio_playback_close() {
return; return;
} }
// Acquire mutex to prevent concurrent write operations // Drop PCM stream BEFORE acquiring mutex to interrupt any blocking writes
// snd_pcm_drop() is thread-safe and will cause snd_pcm_writei() to return immediately
if (pcm_playback_handle) {
snd_pcm_drop(pcm_playback_handle);
}
// Now acquire mutex for cleanup
pthread_mutex_lock(&playback_mutex); pthread_mutex_lock(&playback_mutex);
if (decoder) { if (decoder) {
@ -784,7 +790,6 @@ void jetkvm_audio_playback_close() {
decoder = NULL; decoder = NULL;
} }
if (pcm_playback_handle) { if (pcm_playback_handle) {
snd_pcm_drop(pcm_playback_handle);
snd_pcm_close(pcm_playback_handle); snd_pcm_close(pcm_playback_handle);
pcm_playback_handle = NULL; pcm_playback_handle = NULL;
} }
@ -807,11 +812,16 @@ void jetkvm_audio_capture_close() {
return; return;
} }
// Acquire mutex to prevent concurrent read operations // Drop PCM stream BEFORE acquiring mutex to interrupt any blocking reads
// snd_pcm_drop() is thread-safe and will cause snd_pcm_readi() to return immediately
if (pcm_capture_handle) {
snd_pcm_drop(pcm_capture_handle);
}
// Now acquire mutex for cleanup
pthread_mutex_lock(&capture_mutex); pthread_mutex_lock(&capture_mutex);
if (pcm_capture_handle) { if (pcm_capture_handle) {
snd_pcm_drop(pcm_capture_handle);
snd_pcm_close(pcm_capture_handle); snd_pcm_close(pcm_capture_handle);
pcm_capture_handle = NULL; pcm_capture_handle = NULL;
} }