#include #include #include #include #include #include #include #include // C state for ALSA/Opus with safety flags static snd_pcm_t *pcm_capture_handle = NULL; static snd_pcm_t *pcm_playback_handle = NULL; static OpusEncoder *encoder = NULL; static OpusDecoder *decoder = NULL; // Opus encoder settings - initialized from Go configuration static int opus_bitrate = 96000; // Will be set from Config.CGOOpusBitrate static int opus_complexity = 3; // Will be set from Config.CGOOpusComplexity static int opus_vbr = 1; // Will be set from Config.CGOOpusVBR static int opus_vbr_constraint = 1; // Will be set from Config.CGOOpusVBRConstraint static int opus_signal_type = 3; // Will be set from Config.CGOOpusSignalType static int opus_bandwidth = 1105; // OPUS_BANDWIDTH_WIDEBAND for compatibility (was 1101) static int opus_dtx = 0; // Will be set from Config.CGOOpusDTX static int opus_lsb_depth = 16; // LSB depth for improved bit allocation on constrained hardware static int sample_rate = 48000; // Will be set from Config.CGOSampleRate static int channels = 2; // Will be set from Config.CGOChannels static int frame_size = 960; // Will be set from Config.CGOFrameSize static int max_packet_size = 1500; // Will be set from Config.CGOMaxPacketSize static int sleep_microseconds = 1000; // Will be set from Config.CGOUsleepMicroseconds static int max_attempts_global = 5; // Will be set from Config.CGOMaxAttempts static int max_backoff_us_global = 500000; // Will be set from Config.CGOMaxBackoffMicroseconds // Hardware optimization flags for constrained environments static const int use_mmap_access = 1; // Enable MMAP for improved performance static const int optimized_buffer_size = 0; // Disable optimized buffer sizing for stability (was 1) // C function declarations (implementations are below) int jetkvm_audio_init(); void jetkvm_audio_close(); int jetkvm_audio_read_encode(void *opus_buf); int jetkvm_audio_decode_write(void *opus_buf, int opus_size); int jetkvm_audio_playback_init(); void jetkvm_audio_playback_close(); // Function to update constants from Go configuration void update_audio_constants(int bitrate, int complexity, int vbr, int vbr_constraint, int signal_type, int bandwidth, int dtx, int lsb_depth, int sr, int ch, int fs, int max_pkt, int sleep_us, int max_attempts, int max_backoff) { opus_bitrate = bitrate; opus_complexity = complexity; opus_vbr = vbr; opus_vbr_constraint = vbr_constraint; opus_signal_type = signal_type; opus_bandwidth = bandwidth; opus_dtx = dtx; opus_lsb_depth = lsb_depth; sample_rate = sr; channels = ch; frame_size = fs; max_packet_size = max_pkt; sleep_microseconds = sleep_us; max_attempts_global = max_attempts; max_backoff_us_global = max_backoff; } // State tracking to prevent race conditions during rapid start/stop static volatile int capture_initializing = 0; static volatile int capture_initialized = 0; static volatile int playback_initializing = 0; static volatile int playback_initialized = 0; // Function to dynamically update Opus encoder parameters int update_opus_encoder_params(int bitrate, int complexity, int vbr, int vbr_constraint, int signal_type, int bandwidth, int dtx) { // This function updates encoder parameters for audio input (capture) // Only capture uses the encoder; playback uses a separate decoder if (!encoder || !capture_initialized) { return -1; // Audio encoder not initialized } // Update the static variables opus_bitrate = bitrate; opus_complexity = complexity; opus_vbr = vbr; opus_vbr_constraint = vbr_constraint; opus_signal_type = signal_type; opus_bandwidth = bandwidth; opus_dtx = dtx; // Apply the new settings to the encoder int result = 0; result |= opus_encoder_ctl(encoder, OPUS_SET_BITRATE(opus_bitrate)); result |= opus_encoder_ctl(encoder, OPUS_SET_COMPLEXITY(opus_complexity)); result |= opus_encoder_ctl(encoder, OPUS_SET_VBR(opus_vbr)); result |= opus_encoder_ctl(encoder, OPUS_SET_VBR_CONSTRAINT(opus_vbr_constraint)); result |= opus_encoder_ctl(encoder, OPUS_SET_SIGNAL(opus_signal_type)); result |= opus_encoder_ctl(encoder, OPUS_SET_BANDWIDTH(opus_bandwidth)); result |= opus_encoder_ctl(encoder, OPUS_SET_DTX(opus_dtx)); return result; // 0 on success, non-zero on error } // Enhanced ALSA device opening with exponential backoff retry logic static int safe_alsa_open(snd_pcm_t **handle, const char *device, snd_pcm_stream_t stream) { int attempt = 0; int err; int backoff_us = sleep_microseconds; // Start with base sleep time while (attempt < max_attempts_global) { err = snd_pcm_open(handle, device, stream, SND_PCM_NONBLOCK); if (err >= 0) { // Switch to blocking mode after successful open snd_pcm_nonblock(*handle, 0); return 0; } attempt++; if (attempt >= max_attempts_global) break; // Enhanced error handling with specific retry strategies if (err == -EBUSY || err == -EAGAIN) { // Device busy or temporarily unavailable - retry with backoff usleep(backoff_us); backoff_us = (backoff_us * 2 < max_backoff_us_global) ? backoff_us * 2 : max_backoff_us_global; } else if (err == -ENODEV || err == -ENOENT) { // Device not found - longer wait as device might be initializing usleep(backoff_us * 2); backoff_us = (backoff_us * 2 < max_backoff_us_global) ? backoff_us * 2 : max_backoff_us_global; } else if (err == -EPERM || err == -EACCES) { // Permission denied - shorter wait, likely persistent issue usleep(backoff_us / 2); } else { // Other errors - standard backoff usleep(backoff_us); backoff_us = (backoff_us * 2 < max_backoff_us_global) ? backoff_us * 2 : max_backoff_us_global; } } return err; } // Optimized ALSA configuration with stack allocation and performance tuning static int configure_alsa_device(snd_pcm_t *handle, const char *device_name) { snd_pcm_hw_params_t *params; snd_pcm_sw_params_t *sw_params; int err; if (!handle) return -1; // Use stack allocation for better performance snd_pcm_hw_params_alloca(¶ms); snd_pcm_sw_params_alloca(&sw_params); // Hardware parameters err = snd_pcm_hw_params_any(handle, params); if (err < 0) return err; // Use MMAP access for direct hardware memory access if enabled if (use_mmap_access) { err = snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_MMAP_INTERLEAVED); if (err < 0) { // Fallback to RW access if MMAP fails err = snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED); } } else { err = snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED); } if (err < 0) return err; err = snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE); if (err < 0) return err; err = snd_pcm_hw_params_set_channels(handle, params, channels); if (err < 0) return err; // Set exact rate for better performance err = snd_pcm_hw_params_set_rate(handle, params, sample_rate, 0); if (err < 0) { // Fallback to near rate if exact fails unsigned int rate = sample_rate; err = snd_pcm_hw_params_set_rate_near(handle, params, &rate, 0); if (err < 0) return err; } // Optimize buffer sizes for constrained hardware snd_pcm_uframes_t period_size = frame_size; if (optimized_buffer_size) { // Use smaller periods for lower latency on constrained hardware period_size = frame_size / 2; if (period_size < 64) period_size = 64; // Minimum safe period size } err = snd_pcm_hw_params_set_period_size_near(handle, params, &period_size, 0); if (err < 0) return err; // Optimize buffer size based on hardware constraints snd_pcm_uframes_t buffer_size; if (optimized_buffer_size) { // Use 2 periods for ultra-low latency on constrained hardware buffer_size = period_size * 2; } else { // Standard 4 periods for good latency/stability balance buffer_size = period_size * 4; } err = snd_pcm_hw_params_set_buffer_size_near(handle, params, &buffer_size); if (err < 0) return err; err = snd_pcm_hw_params(handle, params); if (err < 0) return err; // Software parameters for optimal performance err = snd_pcm_sw_params_current(handle, sw_params); if (err < 0) return err; // Start playback/capture when buffer is period_size frames err = snd_pcm_sw_params_set_start_threshold(handle, sw_params, period_size); if (err < 0) return err; // Allow transfers when at least period_size frames are available err = snd_pcm_sw_params_set_avail_min(handle, sw_params, period_size); if (err < 0) return err; err = snd_pcm_sw_params(handle, sw_params); if (err < 0) return err; return snd_pcm_prepare(handle); } // Initialize ALSA and Opus encoder with improved safety int jetkvm_audio_init() { int err; // Prevent concurrent initialization if (__sync_bool_compare_and_swap(&capture_initializing, 0, 1) == 0) { return -EBUSY; // Already initializing } // Check if already initialized if (capture_initialized) { capture_initializing = 0; return 0; } // Clean up any existing resources first if (encoder) { opus_encoder_destroy(encoder); encoder = NULL; } if (pcm_capture_handle) { snd_pcm_close(pcm_capture_handle); pcm_capture_handle = NULL; } // Try to open ALSA capture device err = safe_alsa_open(&pcm_capture_handle, "hw:1,0", SND_PCM_STREAM_CAPTURE); if (err < 0) { capture_initializing = 0; return -1; } // Configure the device err = configure_alsa_device(pcm_capture_handle, "capture"); if (err < 0) { snd_pcm_close(pcm_capture_handle); pcm_capture_handle = NULL; capture_initializing = 0; return -1; } // Initialize Opus encoder with optimized settings int opus_err = 0; encoder = opus_encoder_create(sample_rate, channels, OPUS_APPLICATION_AUDIO, &opus_err); if (!encoder || opus_err != OPUS_OK) { if (pcm_capture_handle) { snd_pcm_close(pcm_capture_handle); pcm_capture_handle = NULL; } capture_initializing = 0; return -2; } // Apply optimized Opus encoder settings for constrained hardware opus_encoder_ctl(encoder, OPUS_SET_BITRATE(opus_bitrate)); opus_encoder_ctl(encoder, OPUS_SET_COMPLEXITY(opus_complexity)); opus_encoder_ctl(encoder, OPUS_SET_VBR(opus_vbr)); opus_encoder_ctl(encoder, OPUS_SET_VBR_CONSTRAINT(opus_vbr_constraint)); opus_encoder_ctl(encoder, OPUS_SET_SIGNAL(opus_signal_type)); opus_encoder_ctl(encoder, OPUS_SET_BANDWIDTH(opus_bandwidth)); // WIDEBAND for compatibility opus_encoder_ctl(encoder, OPUS_SET_DTX(opus_dtx)); // Set LSB depth for improved bit allocation on constrained hardware (disabled for compatibility) // opus_encoder_ctl(encoder, OPUS_SET_LSB_DEPTH(opus_lsb_depth)); // Enable packet loss concealment for better resilience opus_encoder_ctl(encoder, OPUS_SET_PACKET_LOSS_PERC(5)); // Set prediction disabled for lower latency opus_encoder_ctl(encoder, OPUS_SET_PREDICTION_DISABLED(1)); capture_initialized = 1; capture_initializing = 0; return 0; } // jetkvm_audio_read_encode captures audio from ALSA, encodes with Opus, and handles errors. // Implements robust error recovery for buffer underruns and device suspension. // Returns: >0 (bytes written), -1 (init error), -2 (unrecoverable error) int jetkvm_audio_read_encode(void *opus_buf) { short pcm_buffer[1920]; // max 2ch*960 unsigned char *out = (unsigned char*)opus_buf; int err = 0; int recovery_attempts = 0; const int max_recovery_attempts = 3; // Safety checks if (!capture_initialized || !pcm_capture_handle || !encoder || !opus_buf) { return -1; } retry_read: int pcm_rc = snd_pcm_readi(pcm_capture_handle, pcm_buffer, frame_size); // Handle ALSA errors with robust recovery strategies if (pcm_rc < 0) { if (pcm_rc == -EPIPE) { // Buffer underrun - implement progressive recovery recovery_attempts++; if (recovery_attempts > max_recovery_attempts) { return -1; // Give up after max attempts } // Try to recover with prepare err = snd_pcm_prepare(pcm_capture_handle); if (err < 0) { // If prepare fails, try drop and prepare snd_pcm_drop(pcm_capture_handle); err = snd_pcm_prepare(pcm_capture_handle); if (err < 0) return -1; } // Wait before retry to allow device to stabilize usleep(sleep_microseconds * recovery_attempts); goto retry_read; } else if (pcm_rc == -EAGAIN) { // No data available - return 0 to indicate no frame return 0; } else if (pcm_rc == -ESTRPIPE) { // Device suspended, implement robust resume logic recovery_attempts++; if (recovery_attempts > max_recovery_attempts) { return -1; } // Try to resume with timeout int resume_attempts = 0; while ((err = snd_pcm_resume(pcm_capture_handle)) == -EAGAIN && resume_attempts < 10) { usleep(sleep_microseconds); resume_attempts++; } if (err < 0) { // Resume failed, try prepare as fallback err = snd_pcm_prepare(pcm_capture_handle); if (err < 0) return -1; } return 0; // Skip this frame but don't fail } else if (pcm_rc == -ENODEV) { // Device disconnected - critical error return -1; } else if (pcm_rc == -EIO) { // I/O error - try recovery once recovery_attempts++; if (recovery_attempts <= max_recovery_attempts) { snd_pcm_drop(pcm_capture_handle); err = snd_pcm_prepare(pcm_capture_handle); if (err >= 0) { goto retry_read; } } return -1; } else { // Other errors - limited retry for transient issues recovery_attempts++; if (recovery_attempts <= 1) { if (pcm_rc == -EINTR) { // Signal interrupted - wait for device readiness snd_pcm_wait(pcm_capture_handle, sleep_microseconds / 1000); } else if (pcm_rc == -EBUSY) { // Device busy - brief sleep to let conflict resolve usleep(sleep_microseconds / 2); } goto retry_read; } return -1; } } // If we got fewer frames than expected, pad with silence if (pcm_rc < frame_size) { 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); return nb_bytes; } // Initialize ALSA playback with improved safety int jetkvm_audio_playback_init() { int err; // Prevent concurrent initialization if (__sync_bool_compare_and_swap(&playback_initializing, 0, 1) == 0) { return -EBUSY; // Already initializing } // Check if already initialized if (playback_initialized) { playback_initializing = 0; return 0; } // Clean up any existing resources first if (decoder) { opus_decoder_destroy(decoder); decoder = NULL; } if (pcm_playback_handle) { snd_pcm_close(pcm_playback_handle); pcm_playback_handle = NULL; } // Try to open the USB gadget audio device for playback err = safe_alsa_open(&pcm_playback_handle, "hw:1,0", SND_PCM_STREAM_PLAYBACK); if (err < 0) { // Fallback to default device err = safe_alsa_open(&pcm_playback_handle, "default", SND_PCM_STREAM_PLAYBACK); if (err < 0) { playback_initializing = 0; return -1; } } // Configure the device err = configure_alsa_device(pcm_playback_handle, "playback"); if (err < 0) { snd_pcm_close(pcm_playback_handle); pcm_playback_handle = NULL; playback_initializing = 0; return -1; } // Initialize Opus decoder int opus_err = 0; decoder = opus_decoder_create(sample_rate, channels, &opus_err); if (!decoder || opus_err != OPUS_OK) { snd_pcm_close(pcm_playback_handle); pcm_playback_handle = NULL; playback_initializing = 0; return -2; } playback_initialized = 1; playback_initializing = 0; return 0; } // jetkvm_audio_decode_write decodes Opus data and writes PCM to ALSA playback device // with error recovery and packet loss concealment int jetkvm_audio_decode_write(void *opus_buf, int opus_size) { short pcm_buffer[1920]; // max 2ch*960 unsigned char *in = (unsigned char*)opus_buf; int err = 0; int recovery_attempts = 0; const int max_recovery_attempts = 3; // Safety checks if (!playback_initialized || !pcm_playback_handle || !decoder || !opus_buf || opus_size <= 0) { return -1; } // Additional bounds checking if (opus_size > max_packet_size) { return -1; } /** * @note Passing NULL for data and 0 for len is the documented way to indicate * packet loss according to the Opus API documentation. * @see https://www.opus-codec.org/docs/html_api/group__opusdecoder.html#ga1a8b923c1041ad4976ceada237e117ba */ int pcm_frames = opus_decode(decoder, in, opus_size, pcm_buffer, frame_size, 1); if (pcm_frames < 0) { // Try packet loss concealment on decode error pcm_frames = opus_decode(decoder, NULL, 0, pcm_buffer, frame_size, 1); if (pcm_frames < 0) return -1; } retry_write: ; // Write PCM to playback device with robust recovery int pcm_rc = snd_pcm_writei(pcm_playback_handle, pcm_buffer, pcm_frames); if (pcm_rc < 0) { if (pcm_rc == -EPIPE) { // Buffer underrun - implement progressive recovery recovery_attempts++; if (recovery_attempts > max_recovery_attempts) { return -2; } // Try to recover with prepare err = snd_pcm_prepare(pcm_playback_handle); if (err < 0) { // If prepare fails, try drop and prepare snd_pcm_drop(pcm_playback_handle); err = snd_pcm_prepare(pcm_playback_handle); if (err < 0) return -2; } // Wait before retry to allow device to stabilize snd_pcm_wait(pcm_playback_handle, sleep_microseconds * recovery_attempts / 1000); goto retry_write; } else if (pcm_rc == -ESTRPIPE) { // Device suspended, implement robust resume logic recovery_attempts++; if (recovery_attempts > max_recovery_attempts) { return -2; } // Try to resume with timeout int resume_attempts = 0; while ((err = snd_pcm_resume(pcm_playback_handle)) == -EAGAIN && resume_attempts < 10) { usleep(sleep_microseconds); resume_attempts++; } if (err < 0) { // Resume failed, try prepare as fallback err = snd_pcm_prepare(pcm_playback_handle); if (err < 0) return -2; } return 0; // Skip this frame but don't fail } else if (pcm_rc == -ENODEV) { // Device disconnected - critical error return -2; } else if (pcm_rc == -EIO) { // I/O error - try recovery once recovery_attempts++; if (recovery_attempts <= max_recovery_attempts) { snd_pcm_drop(pcm_playback_handle); err = snd_pcm_prepare(pcm_playback_handle); if (err >= 0) { goto retry_write; } } return -2; } else if (pcm_rc == -EAGAIN) { // Device not ready - brief wait and retry recovery_attempts++; if (recovery_attempts <= max_recovery_attempts) { goto retry_write; } return -2; } else { // Other errors - limited retry for transient issues recovery_attempts++; if (recovery_attempts <= 1 && (pcm_rc == -EINTR || pcm_rc == -EBUSY)) { if (pcm_rc == -EINTR) { // Signal interrupted - wait for device readiness snd_pcm_wait(pcm_playback_handle, sleep_microseconds / 1000); } else if (pcm_rc == -EBUSY) { // Device busy - brief sleep to let conflict resolve usleep(sleep_microseconds / 2); } goto retry_write; } return -2; } } return pcm_frames; } // Safe playback cleanup with double-close protection void jetkvm_audio_playback_close() { // Wait for any ongoing operations to complete while (playback_initializing) { usleep(sleep_microseconds); // Use centralized constant } // Atomic check and set to prevent double cleanup if (__sync_bool_compare_and_swap(&playback_initialized, 1, 0) == 0) { return; // Already cleaned up } if (decoder) { opus_decoder_destroy(decoder); decoder = NULL; } if (pcm_playback_handle) { snd_pcm_drain(pcm_playback_handle); snd_pcm_close(pcm_playback_handle); pcm_playback_handle = NULL; } } // Safe capture cleanup void jetkvm_audio_close() { // Wait for any ongoing operations to complete while (capture_initializing) { usleep(sleep_microseconds); } // Atomic check and set to prevent double cleanup if (__sync_bool_compare_and_swap(&capture_initialized, 1, 0) == 0) { return; // Already cleaned up } if (encoder) { opus_encoder_destroy(encoder); encoder = NULL; } if (pcm_capture_handle) { snd_pcm_drain(pcm_capture_handle); snd_pcm_close(pcm_capture_handle); pcm_capture_handle = NULL; } }