mirror of https://github.com/jetkvm/kvm.git
Fix: linter errors
This commit is contained in:
parent
e360348829
commit
6ecb829334
|
@ -14,7 +14,7 @@ const (
|
||||||
// Input RPC Direct Handlers
|
// Input RPC Direct Handlers
|
||||||
// This module provides optimized direct handlers for high-frequency input events,
|
// This module provides optimized direct handlers for high-frequency input events,
|
||||||
// bypassing the reflection-based RPC system for improved performance.
|
// bypassing the reflection-based RPC system for improved performance.
|
||||||
//
|
//
|
||||||
// Performance benefits:
|
// Performance benefits:
|
||||||
// - Eliminates reflection overhead (~2-3ms per call)
|
// - Eliminates reflection overhead (~2-3ms per call)
|
||||||
// - Reduces memory allocations
|
// - Reduces memory allocations
|
||||||
|
@ -214,4 +214,4 @@ func isInputMethod(method string) bool {
|
||||||
default:
|
default:
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,7 @@ static volatile int playback_initialized = 0;
|
||||||
static int safe_alsa_open(snd_pcm_t **handle, const char *device, snd_pcm_stream_t stream) {
|
static int safe_alsa_open(snd_pcm_t **handle, const char *device, snd_pcm_stream_t stream) {
|
||||||
int attempts = 3;
|
int attempts = 3;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
while (attempts-- > 0) {
|
while (attempts-- > 0) {
|
||||||
err = snd_pcm_open(handle, device, stream, SND_PCM_NONBLOCK);
|
err = snd_pcm_open(handle, device, stream, SND_PCM_NONBLOCK);
|
||||||
if (err >= 0) {
|
if (err >= 0) {
|
||||||
|
@ -47,7 +47,7 @@ static int safe_alsa_open(snd_pcm_t **handle, const char *device, snd_pcm_stream
|
||||||
snd_pcm_nonblock(*handle, 0);
|
snd_pcm_nonblock(*handle, 0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (err == -EBUSY && attempts > 0) {
|
if (err == -EBUSY && attempts > 0) {
|
||||||
// Device busy, wait and retry
|
// Device busy, wait and retry
|
||||||
usleep(50000); // 50ms
|
usleep(50000); // 50ms
|
||||||
|
@ -63,26 +63,26 @@ static int configure_alsa_device(snd_pcm_t *handle, const char *device_name) {
|
||||||
snd_pcm_hw_params_t *params;
|
snd_pcm_hw_params_t *params;
|
||||||
snd_pcm_sw_params_t *sw_params;
|
snd_pcm_sw_params_t *sw_params;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if (!handle) return -1;
|
if (!handle) return -1;
|
||||||
|
|
||||||
// Use stack allocation for better performance
|
// Use stack allocation for better performance
|
||||||
snd_pcm_hw_params_alloca(¶ms);
|
snd_pcm_hw_params_alloca(¶ms);
|
||||||
snd_pcm_sw_params_alloca(&sw_params);
|
snd_pcm_sw_params_alloca(&sw_params);
|
||||||
|
|
||||||
// Hardware parameters
|
// Hardware parameters
|
||||||
err = snd_pcm_hw_params_any(handle, params);
|
err = snd_pcm_hw_params_any(handle, params);
|
||||||
if (err < 0) return err;
|
if (err < 0) return err;
|
||||||
|
|
||||||
err = snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
|
err = snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
|
||||||
if (err < 0) return err;
|
if (err < 0) return err;
|
||||||
|
|
||||||
err = snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE);
|
err = snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE);
|
||||||
if (err < 0) return err;
|
if (err < 0) return err;
|
||||||
|
|
||||||
err = snd_pcm_hw_params_set_channels(handle, params, channels);
|
err = snd_pcm_hw_params_set_channels(handle, params, channels);
|
||||||
if (err < 0) return err;
|
if (err < 0) return err;
|
||||||
|
|
||||||
// Set exact rate for better performance
|
// Set exact rate for better performance
|
||||||
err = snd_pcm_hw_params_set_rate(handle, params, sample_rate, 0);
|
err = snd_pcm_hw_params_set_rate(handle, params, sample_rate, 0);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
|
@ -91,70 +91,70 @@ static int configure_alsa_device(snd_pcm_t *handle, const char *device_name) {
|
||||||
err = snd_pcm_hw_params_set_rate_near(handle, params, &rate, 0);
|
err = snd_pcm_hw_params_set_rate_near(handle, params, &rate, 0);
|
||||||
if (err < 0) return err;
|
if (err < 0) return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Optimize buffer sizes for low latency
|
// Optimize buffer sizes for low latency
|
||||||
snd_pcm_uframes_t period_size = frame_size;
|
snd_pcm_uframes_t period_size = frame_size;
|
||||||
err = snd_pcm_hw_params_set_period_size_near(handle, params, &period_size, 0);
|
err = snd_pcm_hw_params_set_period_size_near(handle, params, &period_size, 0);
|
||||||
if (err < 0) return err;
|
if (err < 0) return err;
|
||||||
|
|
||||||
// Set buffer size to 4 periods for good latency/stability balance
|
// Set buffer size to 4 periods for good latency/stability balance
|
||||||
snd_pcm_uframes_t buffer_size = period_size * 4;
|
snd_pcm_uframes_t buffer_size = period_size * 4;
|
||||||
err = snd_pcm_hw_params_set_buffer_size_near(handle, params, &buffer_size);
|
err = snd_pcm_hw_params_set_buffer_size_near(handle, params, &buffer_size);
|
||||||
if (err < 0) return err;
|
if (err < 0) return err;
|
||||||
|
|
||||||
err = snd_pcm_hw_params(handle, params);
|
err = snd_pcm_hw_params(handle, params);
|
||||||
if (err < 0) return err;
|
if (err < 0) return err;
|
||||||
|
|
||||||
// Software parameters for optimal performance
|
// Software parameters for optimal performance
|
||||||
err = snd_pcm_sw_params_current(handle, sw_params);
|
err = snd_pcm_sw_params_current(handle, sw_params);
|
||||||
if (err < 0) return err;
|
if (err < 0) return err;
|
||||||
|
|
||||||
// Start playback/capture when buffer is period_size frames
|
// Start playback/capture when buffer is period_size frames
|
||||||
err = snd_pcm_sw_params_set_start_threshold(handle, sw_params, period_size);
|
err = snd_pcm_sw_params_set_start_threshold(handle, sw_params, period_size);
|
||||||
if (err < 0) return err;
|
if (err < 0) return err;
|
||||||
|
|
||||||
// Allow transfers when at least period_size frames are available
|
// Allow transfers when at least period_size frames are available
|
||||||
err = snd_pcm_sw_params_set_avail_min(handle, sw_params, period_size);
|
err = snd_pcm_sw_params_set_avail_min(handle, sw_params, period_size);
|
||||||
if (err < 0) return err;
|
if (err < 0) return err;
|
||||||
|
|
||||||
err = snd_pcm_sw_params(handle, sw_params);
|
err = snd_pcm_sw_params(handle, sw_params);
|
||||||
if (err < 0) return err;
|
if (err < 0) return err;
|
||||||
|
|
||||||
return snd_pcm_prepare(handle);
|
return snd_pcm_prepare(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize ALSA and Opus encoder with improved safety
|
// Initialize ALSA and Opus encoder with improved safety
|
||||||
int jetkvm_audio_init() {
|
int jetkvm_audio_init() {
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
// Prevent concurrent initialization
|
// Prevent concurrent initialization
|
||||||
if (__sync_bool_compare_and_swap(&capture_initializing, 0, 1) == 0) {
|
if (__sync_bool_compare_and_swap(&capture_initializing, 0, 1) == 0) {
|
||||||
return -EBUSY; // Already initializing
|
return -EBUSY; // Already initializing
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if already initialized
|
// Check if already initialized
|
||||||
if (capture_initialized) {
|
if (capture_initialized) {
|
||||||
capture_initializing = 0;
|
capture_initializing = 0;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clean up any existing resources first
|
// Clean up any existing resources first
|
||||||
if (encoder) {
|
if (encoder) {
|
||||||
opus_encoder_destroy(encoder);
|
opus_encoder_destroy(encoder);
|
||||||
encoder = NULL;
|
encoder = NULL;
|
||||||
}
|
}
|
||||||
if (pcm_handle) {
|
if (pcm_handle) {
|
||||||
snd_pcm_close(pcm_handle);
|
snd_pcm_close(pcm_handle);
|
||||||
pcm_handle = NULL;
|
pcm_handle = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to open ALSA capture device
|
// Try to open ALSA capture device
|
||||||
err = safe_alsa_open(&pcm_handle, "hw:1,0", SND_PCM_STREAM_CAPTURE);
|
err = safe_alsa_open(&pcm_handle, "hw:1,0", SND_PCM_STREAM_CAPTURE);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
capture_initializing = 0;
|
capture_initializing = 0;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Configure the device
|
// Configure the device
|
||||||
err = configure_alsa_device(pcm_handle, "capture");
|
err = configure_alsa_device(pcm_handle, "capture");
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
|
@ -163,7 +163,7 @@ int jetkvm_audio_init() {
|
||||||
capture_initializing = 0;
|
capture_initializing = 0;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize Opus encoder
|
// Initialize Opus encoder
|
||||||
int opus_err = 0;
|
int opus_err = 0;
|
||||||
encoder = opus_encoder_create(sample_rate, channels, OPUS_APPLICATION_AUDIO, &opus_err);
|
encoder = opus_encoder_create(sample_rate, channels, OPUS_APPLICATION_AUDIO, &opus_err);
|
||||||
|
@ -172,10 +172,10 @@ int jetkvm_audio_init() {
|
||||||
capture_initializing = 0;
|
capture_initializing = 0;
|
||||||
return -2;
|
return -2;
|
||||||
}
|
}
|
||||||
|
|
||||||
opus_encoder_ctl(encoder, OPUS_SET_BITRATE(opus_bitrate));
|
opus_encoder_ctl(encoder, OPUS_SET_BITRATE(opus_bitrate));
|
||||||
opus_encoder_ctl(encoder, OPUS_SET_COMPLEXITY(opus_complexity));
|
opus_encoder_ctl(encoder, OPUS_SET_COMPLEXITY(opus_complexity));
|
||||||
|
|
||||||
capture_initialized = 1;
|
capture_initialized = 1;
|
||||||
capture_initializing = 0;
|
capture_initializing = 0;
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -186,21 +186,21 @@ int jetkvm_audio_read_encode(void *opus_buf) {
|
||||||
short pcm_buffer[1920]; // max 2ch*960
|
short pcm_buffer[1920]; // max 2ch*960
|
||||||
unsigned char *out = (unsigned char*)opus_buf;
|
unsigned char *out = (unsigned char*)opus_buf;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
// Safety checks
|
// Safety checks
|
||||||
if (!capture_initialized || !pcm_handle || !encoder || !opus_buf) {
|
if (!capture_initialized || !pcm_handle || !encoder || !opus_buf) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int pcm_rc = snd_pcm_readi(pcm_handle, pcm_buffer, frame_size);
|
int pcm_rc = snd_pcm_readi(pcm_handle, pcm_buffer, frame_size);
|
||||||
|
|
||||||
// Handle ALSA errors with enhanced recovery
|
// Handle ALSA errors with enhanced recovery
|
||||||
if (pcm_rc < 0) {
|
if (pcm_rc < 0) {
|
||||||
if (pcm_rc == -EPIPE) {
|
if (pcm_rc == -EPIPE) {
|
||||||
// Buffer underrun - try to recover
|
// Buffer underrun - try to recover
|
||||||
err = snd_pcm_prepare(pcm_handle);
|
err = snd_pcm_prepare(pcm_handle);
|
||||||
if (err < 0) return -1;
|
if (err < 0) return -1;
|
||||||
|
|
||||||
pcm_rc = snd_pcm_readi(pcm_handle, pcm_buffer, frame_size);
|
pcm_rc = snd_pcm_readi(pcm_handle, pcm_buffer, frame_size);
|
||||||
if (pcm_rc < 0) return -1;
|
if (pcm_rc < 0) return -1;
|
||||||
} else if (pcm_rc == -EAGAIN) {
|
} else if (pcm_rc == -EAGAIN) {
|
||||||
|
@ -221,12 +221,12 @@ int jetkvm_audio_read_encode(void *opus_buf) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we got fewer frames than expected, pad with silence
|
// If we got fewer frames than expected, pad with silence
|
||||||
if (pcm_rc < frame_size) {
|
if (pcm_rc < frame_size) {
|
||||||
memset(&pcm_buffer[pcm_rc * channels], 0, (frame_size - pcm_rc) * channels * sizeof(short));
|
memset(&pcm_buffer[pcm_rc * channels], 0, (frame_size - pcm_rc) * channels * sizeof(short));
|
||||||
}
|
}
|
||||||
|
|
||||||
int nb_bytes = opus_encode(encoder, pcm_buffer, frame_size, out, max_packet_size);
|
int nb_bytes = opus_encode(encoder, pcm_buffer, frame_size, out, max_packet_size);
|
||||||
return nb_bytes;
|
return nb_bytes;
|
||||||
}
|
}
|
||||||
|
@ -234,28 +234,28 @@ int jetkvm_audio_read_encode(void *opus_buf) {
|
||||||
// Initialize ALSA playback with improved safety
|
// Initialize ALSA playback with improved safety
|
||||||
int jetkvm_audio_playback_init() {
|
int jetkvm_audio_playback_init() {
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
// Prevent concurrent initialization
|
// Prevent concurrent initialization
|
||||||
if (__sync_bool_compare_and_swap(&playback_initializing, 0, 1) == 0) {
|
if (__sync_bool_compare_and_swap(&playback_initializing, 0, 1) == 0) {
|
||||||
return -EBUSY; // Already initializing
|
return -EBUSY; // Already initializing
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if already initialized
|
// Check if already initialized
|
||||||
if (playback_initialized) {
|
if (playback_initialized) {
|
||||||
playback_initializing = 0;
|
playback_initializing = 0;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clean up any existing resources first
|
// Clean up any existing resources first
|
||||||
if (decoder) {
|
if (decoder) {
|
||||||
opus_decoder_destroy(decoder);
|
opus_decoder_destroy(decoder);
|
||||||
decoder = NULL;
|
decoder = NULL;
|
||||||
}
|
}
|
||||||
if (pcm_playback_handle) {
|
if (pcm_playback_handle) {
|
||||||
snd_pcm_close(pcm_playback_handle);
|
snd_pcm_close(pcm_playback_handle);
|
||||||
pcm_playback_handle = NULL;
|
pcm_playback_handle = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to open the USB gadget audio device for playback
|
// Try to open the USB gadget audio device for playback
|
||||||
err = safe_alsa_open(&pcm_playback_handle, "hw:1,0", SND_PCM_STREAM_PLAYBACK);
|
err = safe_alsa_open(&pcm_playback_handle, "hw:1,0", SND_PCM_STREAM_PLAYBACK);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
|
@ -266,7 +266,7 @@ int jetkvm_audio_playback_init() {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Configure the device
|
// Configure the device
|
||||||
err = configure_alsa_device(pcm_playback_handle, "playback");
|
err = configure_alsa_device(pcm_playback_handle, "playback");
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
|
@ -275,7 +275,7 @@ int jetkvm_audio_playback_init() {
|
||||||
playback_initializing = 0;
|
playback_initializing = 0;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize Opus decoder
|
// Initialize Opus decoder
|
||||||
int opus_err = 0;
|
int opus_err = 0;
|
||||||
decoder = opus_decoder_create(sample_rate, channels, &opus_err);
|
decoder = opus_decoder_create(sample_rate, channels, &opus_err);
|
||||||
|
@ -285,7 +285,7 @@ int jetkvm_audio_playback_init() {
|
||||||
playback_initializing = 0;
|
playback_initializing = 0;
|
||||||
return -2;
|
return -2;
|
||||||
}
|
}
|
||||||
|
|
||||||
playback_initialized = 1;
|
playback_initialized = 1;
|
||||||
playback_initializing = 0;
|
playback_initializing = 0;
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -296,21 +296,21 @@ int jetkvm_audio_decode_write(void *opus_buf, int opus_size) {
|
||||||
short pcm_buffer[1920]; // max 2ch*960
|
short pcm_buffer[1920]; // max 2ch*960
|
||||||
unsigned char *in = (unsigned char*)opus_buf;
|
unsigned char *in = (unsigned char*)opus_buf;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
// Safety checks
|
// Safety checks
|
||||||
if (!playback_initialized || !pcm_playback_handle || !decoder || !opus_buf || opus_size <= 0) {
|
if (!playback_initialized || !pcm_playback_handle || !decoder || !opus_buf || opus_size <= 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Additional bounds checking
|
// Additional bounds checking
|
||||||
if (opus_size > max_packet_size) {
|
if (opus_size > max_packet_size) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decode Opus to PCM
|
// Decode Opus to PCM
|
||||||
int pcm_frames = opus_decode(decoder, in, opus_size, pcm_buffer, frame_size, 0);
|
int pcm_frames = opus_decode(decoder, in, opus_size, pcm_buffer, frame_size, 0);
|
||||||
if (pcm_frames < 0) return -1;
|
if (pcm_frames < 0) return -1;
|
||||||
|
|
||||||
// Write PCM to playback device with enhanced recovery
|
// Write PCM to playback device with enhanced recovery
|
||||||
int pcm_rc = snd_pcm_writei(pcm_playback_handle, pcm_buffer, pcm_frames);
|
int pcm_rc = snd_pcm_writei(pcm_playback_handle, pcm_buffer, pcm_frames);
|
||||||
if (pcm_rc < 0) {
|
if (pcm_rc < 0) {
|
||||||
|
@ -318,7 +318,7 @@ int jetkvm_audio_decode_write(void *opus_buf, int opus_size) {
|
||||||
// Buffer underrun - try to recover
|
// Buffer underrun - try to recover
|
||||||
err = snd_pcm_prepare(pcm_playback_handle);
|
err = snd_pcm_prepare(pcm_playback_handle);
|
||||||
if (err < 0) return -2;
|
if (err < 0) return -2;
|
||||||
|
|
||||||
pcm_rc = snd_pcm_writei(pcm_playback_handle, pcm_buffer, pcm_frames);
|
pcm_rc = snd_pcm_writei(pcm_playback_handle, pcm_buffer, pcm_frames);
|
||||||
} else if (pcm_rc == -ESTRPIPE) {
|
} else if (pcm_rc == -ESTRPIPE) {
|
||||||
// Device suspended, try to resume
|
// Device suspended, try to resume
|
||||||
|
@ -333,7 +333,7 @@ int jetkvm_audio_decode_write(void *opus_buf, int opus_size) {
|
||||||
}
|
}
|
||||||
if (pcm_rc < 0) return -2;
|
if (pcm_rc < 0) return -2;
|
||||||
}
|
}
|
||||||
|
|
||||||
return pcm_frames;
|
return pcm_frames;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -343,20 +343,20 @@ void jetkvm_audio_playback_close() {
|
||||||
while (playback_initializing) {
|
while (playback_initializing) {
|
||||||
usleep(1000); // 1ms
|
usleep(1000); // 1ms
|
||||||
}
|
}
|
||||||
|
|
||||||
// Atomic check and set to prevent double cleanup
|
// Atomic check and set to prevent double cleanup
|
||||||
if (__sync_bool_compare_and_swap(&playback_initialized, 1, 0) == 0) {
|
if (__sync_bool_compare_and_swap(&playback_initialized, 1, 0) == 0) {
|
||||||
return; // Already cleaned up
|
return; // Already cleaned up
|
||||||
}
|
}
|
||||||
|
|
||||||
if (decoder) {
|
if (decoder) {
|
||||||
opus_decoder_destroy(decoder);
|
opus_decoder_destroy(decoder);
|
||||||
decoder = NULL;
|
decoder = NULL;
|
||||||
}
|
}
|
||||||
if (pcm_playback_handle) {
|
if (pcm_playback_handle) {
|
||||||
snd_pcm_drain(pcm_playback_handle);
|
snd_pcm_drain(pcm_playback_handle);
|
||||||
snd_pcm_close(pcm_playback_handle);
|
snd_pcm_close(pcm_playback_handle);
|
||||||
pcm_playback_handle = NULL;
|
pcm_playback_handle = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -366,19 +366,19 @@ void jetkvm_audio_close() {
|
||||||
while (capture_initializing) {
|
while (capture_initializing) {
|
||||||
usleep(1000); // 1ms
|
usleep(1000); // 1ms
|
||||||
}
|
}
|
||||||
|
|
||||||
capture_initialized = 0;
|
capture_initialized = 0;
|
||||||
|
|
||||||
if (encoder) {
|
if (encoder) {
|
||||||
opus_encoder_destroy(encoder);
|
opus_encoder_destroy(encoder);
|
||||||
encoder = NULL;
|
encoder = NULL;
|
||||||
}
|
}
|
||||||
if (pcm_handle) {
|
if (pcm_handle) {
|
||||||
snd_pcm_drop(pcm_handle); // Drop pending samples
|
snd_pcm_drop(pcm_handle); // Drop pending samples
|
||||||
snd_pcm_close(pcm_handle);
|
snd_pcm_close(pcm_handle);
|
||||||
pcm_handle = NULL;
|
pcm_handle = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Also clean up playback
|
// Also clean up playback
|
||||||
jetkvm_audio_playback_close();
|
jetkvm_audio_playback_close();
|
||||||
}
|
}
|
||||||
|
@ -387,15 +387,15 @@ import "C"
|
||||||
|
|
||||||
// Optimized Go wrappers with reduced overhead
|
// Optimized Go wrappers with reduced overhead
|
||||||
var (
|
var (
|
||||||
errAudioInitFailed = errors.New("failed to init ALSA/Opus")
|
errAudioInitFailed = errors.New("failed to init ALSA/Opus")
|
||||||
errBufferTooSmall = errors.New("buffer too small")
|
errBufferTooSmall = errors.New("buffer too small")
|
||||||
errAudioReadEncode = errors.New("audio read/encode error")
|
errAudioReadEncode = errors.New("audio read/encode error")
|
||||||
errAudioDecodeWrite = errors.New("audio decode/write error")
|
errAudioDecodeWrite = errors.New("audio decode/write error")
|
||||||
errAudioPlaybackInit = errors.New("failed to init ALSA playback/Opus decoder")
|
errAudioPlaybackInit = errors.New("failed to init ALSA playback/Opus decoder")
|
||||||
errEmptyBuffer = errors.New("empty buffer")
|
errEmptyBuffer = errors.New("empty buffer")
|
||||||
errNilBuffer = errors.New("nil buffer")
|
errNilBuffer = errors.New("nil buffer")
|
||||||
errBufferTooLarge = errors.New("buffer too large")
|
errBufferTooLarge = errors.New("buffer too large")
|
||||||
errInvalidBufferPtr = errors.New("invalid buffer pointer")
|
errInvalidBufferPtr = errors.New("invalid buffer pointer")
|
||||||
)
|
)
|
||||||
|
|
||||||
func cgoAudioInit() error {
|
func cgoAudioInit() error {
|
||||||
|
@ -416,7 +416,7 @@ func cgoAudioReadEncode(buf []byte) (int, error) {
|
||||||
if len(buf) < 1276 {
|
if len(buf) < 1276 {
|
||||||
return 0, errBufferTooSmall
|
return 0, errBufferTooSmall
|
||||||
}
|
}
|
||||||
|
|
||||||
n := C.jetkvm_audio_read_encode(unsafe.Pointer(&buf[0]))
|
n := C.jetkvm_audio_read_encode(unsafe.Pointer(&buf[0]))
|
||||||
if n < 0 {
|
if n < 0 {
|
||||||
return 0, errAudioReadEncode
|
return 0, errAudioReadEncode
|
||||||
|
@ -449,18 +449,18 @@ func cgoAudioDecodeWrite(buf []byte) (int, error) {
|
||||||
if buf == nil {
|
if buf == nil {
|
||||||
return 0, errors.New("nil buffer")
|
return 0, errors.New("nil buffer")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate buffer size to prevent potential overruns
|
// Validate buffer size to prevent potential overruns
|
||||||
if len(buf) > 4096 { // Maximum reasonable Opus frame size
|
if len(buf) > 4096 { // Maximum reasonable Opus frame size
|
||||||
return 0, errors.New("buffer too large")
|
return 0, errors.New("buffer too large")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure buffer is not deallocated by keeping a reference
|
// Ensure buffer is not deallocated by keeping a reference
|
||||||
bufPtr := unsafe.Pointer(&buf[0])
|
bufPtr := unsafe.Pointer(&buf[0])
|
||||||
if bufPtr == nil {
|
if bufPtr == nil {
|
||||||
return 0, errors.New("invalid buffer pointer")
|
return 0, errors.New("invalid buffer pointer")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add recovery mechanism for C function crashes
|
// Add recovery mechanism for C function crashes
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
|
@ -469,7 +469,7 @@ func cgoAudioDecodeWrite(buf []byte) (int, error) {
|
||||||
_ = r // Explicitly ignore the panic value
|
_ = r // Explicitly ignore the panic value
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
n := C.jetkvm_audio_decode_write(bufPtr, C.int(len(buf)))
|
n := C.jetkvm_audio_decode_write(bufPtr, C.int(len(buf)))
|
||||||
if n < 0 {
|
if n < 0 {
|
||||||
return 0, errors.New("audio decode/write error")
|
return 0, errors.New("audio decode/write error")
|
||||||
|
@ -479,10 +479,10 @@ func cgoAudioDecodeWrite(buf []byte) (int, error) {
|
||||||
|
|
||||||
// Wrapper functions for non-blocking audio manager
|
// Wrapper functions for non-blocking audio manager
|
||||||
var (
|
var (
|
||||||
CGOAudioInit = cgoAudioInit
|
CGOAudioInit = cgoAudioInit
|
||||||
CGOAudioClose = cgoAudioClose
|
CGOAudioClose = cgoAudioClose
|
||||||
CGOAudioReadEncode = cgoAudioReadEncode
|
CGOAudioReadEncode = cgoAudioReadEncode
|
||||||
CGOAudioPlaybackInit = cgoAudioPlaybackInit
|
CGOAudioPlaybackInit = cgoAudioPlaybackInit
|
||||||
CGOAudioPlaybackClose = cgoAudioPlaybackClose
|
CGOAudioPlaybackClose = cgoAudioPlaybackClose
|
||||||
CGOAudioDecodeWrite = cgoAudioDecodeWrite
|
CGOAudioDecodeWrite = cgoAudioDecodeWrite
|
||||||
)
|
)
|
||||||
|
|
14
main.go
14
main.go
|
@ -14,10 +14,10 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
appCtx context.Context
|
appCtx context.Context
|
||||||
isAudioServer bool
|
isAudioServer bool
|
||||||
audioProcessDone chan struct{}
|
audioProcessDone chan struct{}
|
||||||
audioSupervisor *audio.AudioServerSupervisor
|
audioSupervisor *audio.AudioServerSupervisor
|
||||||
)
|
)
|
||||||
|
|
||||||
func runAudioServer() {
|
func runAudioServer() {
|
||||||
|
@ -68,7 +68,7 @@ func startAudioSubprocess() error {
|
||||||
// onProcessStart
|
// onProcessStart
|
||||||
func(pid int) {
|
func(pid int) {
|
||||||
logger.Info().Int("pid", pid).Msg("audio server process started")
|
logger.Info().Int("pid", pid).Msg("audio server process started")
|
||||||
|
|
||||||
// Start audio relay system for main process without a track initially
|
// Start audio relay system for main process without a track initially
|
||||||
// The track will be updated when a WebRTC session is created
|
// The track will be updated when a WebRTC session is created
|
||||||
if err := audio.StartAudioRelay(nil); err != nil {
|
if err := audio.StartAudioRelay(nil); err != nil {
|
||||||
|
@ -82,7 +82,7 @@ func startAudioSubprocess() error {
|
||||||
} else {
|
} else {
|
||||||
logger.Info().Int("pid", pid).Msg("audio server process exited gracefully")
|
logger.Info().Int("pid", pid).Msg("audio server process exited gracefully")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stop audio relay when process exits
|
// Stop audio relay when process exits
|
||||||
audio.StopAudioRelay()
|
audio.StopAudioRelay()
|
||||||
},
|
},
|
||||||
|
@ -100,12 +100,12 @@ func startAudioSubprocess() error {
|
||||||
// Monitor supervisor and handle cleanup
|
// Monitor supervisor and handle cleanup
|
||||||
go func() {
|
go func() {
|
||||||
defer close(audioProcessDone)
|
defer close(audioProcessDone)
|
||||||
|
|
||||||
// Wait for supervisor to stop
|
// Wait for supervisor to stop
|
||||||
for audioSupervisor.IsRunning() {
|
for audioSupervisor.IsRunning() {
|
||||||
time.Sleep(100 * time.Millisecond)
|
time.Sleep(100 * time.Millisecond)
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.Info().Msg("audio supervisor stopped")
|
logger.Info().Msg("audio supervisor stopped")
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue