@@ -54,7 +54,7 @@ static snd_pcm_t *pcm_playback_handle = NULL; // INPUT: Client microphone → de
5454
5555static const char * alsa_capture_device = NULL ;
5656static const char * alsa_playback_device = NULL ;
57- static bool capture_channels_swapped = false; // True if hardware reports R,L instead of L,R
57+ static bool capture_channels_swapped = false;
5858
5959static OpusEncoder * encoder = NULL ;
6060static OpusDecoder * decoder = NULL ;
@@ -104,11 +104,9 @@ static uint32_t max_backoff_us_global = 500000;
104104static atomic_int capture_stop_requested = 0 ;
105105static atomic_int playback_stop_requested = 0 ;
106106
107- // Mutexes to protect concurrent access to ALSA handles and codecs throughout their lifecycle
108- // These prevent race conditions when jetkvm_audio_*_close() is called while
109- // jetkvm_audio_read_encode() or jetkvm_audio_decode_write() are executing.
110- // The mutexes protect initialization, cleanup, ALSA I/O, codec operations, and handle validation
111- // to ensure handles remain valid from acquisition through release.
107+ // Mutexes protect handle lifecycle and codec operations, NOT the ALSA I/O itself.
108+ // The mutex is temporarily released during snd_pcm_readi/writei to prevent blocking.
109+ // Race conditions are detected via handle pointer comparison after reacquiring the lock.
112110static pthread_mutex_t capture_mutex = PTHREAD_MUTEX_INITIALIZER ;
113111static pthread_mutex_t playback_mutex = PTHREAD_MUTEX_INITIALIZER ;
114112
@@ -187,9 +185,6 @@ static void init_alsa_devices_from_env(void) {
187185
188186// SIMD-OPTIMIZED BUFFER OPERATIONS (ARM NEON)
189187
190- /**
191- * Clear audio buffer using NEON (16 samples/iteration with 2x unrolling)
192- */
193188static inline void simd_clear_samples_s16 (short * __restrict__ buffer , uint32_t samples ) {
194189 const int16x8_t zero = vdupq_n_s16 (0 );
195190 uint32_t i = 0 ;
@@ -293,11 +288,6 @@ static unsigned int get_hdmi_audio_sample_rate(void) {
293288 return detected_rate ;
294289}
295290
296- /**
297- * Open ALSA device with exponential backoff retry
298- * @return 0 on success, negative error code on failure
299- */
300- // High-precision sleep using nanosleep
301291static inline void precise_sleep_us (uint32_t microseconds ) {
302292 struct timespec ts = {
303293 .tv_sec = microseconds / 1000000 ,
@@ -806,11 +796,6 @@ int jetkvm_audio_capture_init() {
806796 return 0 ;
807797}
808798
809- /**
810- * Read HDMI audio, resample with SpeexDSP, encode to Opus (OUTPUT path hot function)
811- * @param opus_buf Output buffer for encoded Opus packet
812- * @return >0 = Opus packet size in bytes, -1 = error
813- */
814799__attribute__((hot )) int jetkvm_audio_read_encode (void * __restrict__ opus_buf ) {
815800 // Two buffers: hardware buffer + resampled buffer (at 48kHz)
816801 static short CACHE_ALIGN pcm_hw_buffer [MAX_HARDWARE_FRAME_SIZE * 2 ]; // Max hardware rate * stereo
@@ -1007,13 +992,6 @@ int jetkvm_audio_playback_init() {
1007992 return 0 ;
1008993}
1009994
1010- /**
1011- * Decode Opus, write to device speakers (INPUT path hot function)
1012- * Processing pipeline: Opus decode (with FEC) → ALSA playback with error recovery
1013- * @param opus_buf Encoded Opus packet from client
1014- * @param opus_size Size of Opus packet in bytes
1015- * @return >0 = PCM frames written, 0 = frame skipped, -1/-2 = error
1016- */
1017995__attribute__((hot )) int jetkvm_audio_decode_write (void * __restrict__ opus_buf , int32_t opus_size ) {
1018996 static short CACHE_ALIGN pcm_buffer [960 * 2 ]; // Cache-aligned
1019997 unsigned char * __restrict__ in = (unsigned char * )opus_buf ;
0 commit comments