Fix: extend audio mutex to prevent concurrent initialization crashes

Previous fix protected WriteMessage() but missed Connect() calls. During
session transfers, multiple goroutines could simultaneously initialize the
audio playback system, causing SIGABRT crashes in jetkvm_audio_playback_init.

Extended inputSourceMutex to serialize both Connect() and WriteMessage()
operations, ensuring atomic state transitions and preventing concurrent
C library initialization.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Alex P 2025-11-14 10:21:15 +02:00
parent f6012e5c3f
commit c67b93578f
1 changed files with 5 additions and 4 deletions

View File

@ -14,7 +14,7 @@ import (
var ( var (
audioMutex sync.Mutex audioMutex sync.Mutex
setAudioTrackMutex sync.Mutex // Prevents concurrent setAudioTrack() calls setAudioTrackMutex sync.Mutex // Prevents concurrent setAudioTrack() calls
inputSourceMutex sync.Mutex // Serializes WriteMessage() calls to input source inputSourceMutex sync.Mutex // Serializes Connect() and WriteMessage() calls to input source
outputSource audio.AudioSource outputSource audio.AudioSource
inputSource atomic.Pointer[audio.AudioSource] inputSource atomic.Pointer[audio.AudioSource]
outputRelay *audio.OutputRelay outputRelay *audio.OutputRelay
@ -132,7 +132,6 @@ func onWebRTCDisconnect() {
} }
func setAudioTrack(audioTrack *webrtc.TrackLocalStaticSample) { func setAudioTrack(audioTrack *webrtc.TrackLocalStaticSample) {
// Prevent concurrent calls to avoid creating multiple relays
setAudioTrackMutex.Lock() setAudioTrackMutex.Lock()
defer setAudioTrackMutex.Unlock() defer setAudioTrackMutex.Unlock()
@ -264,18 +263,20 @@ func handleInputTrackForSession(track *webrtc.TrackRemote) {
continue // No relay, drop frame but keep reading continue // No relay, drop frame but keep reading
} }
inputSourceMutex.Lock()
if !(*source).IsConnected() { if !(*source).IsConnected() {
if err := (*source).Connect(); err != nil { if err := (*source).Connect(); err != nil {
inputSourceMutex.Unlock()
continue continue
} }
} }
// Serialize WriteMessage() to prevent concurrent session handlers from corrupting Opus decoder
inputSourceMutex.Lock()
if err := (*source).WriteMessage(0, opusData); err != nil { if err := (*source).WriteMessage(0, opusData); err != nil {
audioLogger.Warn().Err(err).Msg("failed to write audio message") audioLogger.Warn().Err(err).Msg("failed to write audio message")
(*source).Disconnect() (*source).Disconnect()
} }
inputSourceMutex.Unlock() inputSourceMutex.Unlock()
} }
} }