ref: 3d909f5bf38b1c6fb00742f82980c03fb8ecd24f
parent: c3a336812cedf3024dfa1cdf059a0a91649830fc
author: Maido <v3rm0n@users.noreply.github.com>
date: Mon Aug 25 05:32:34 EDT 2025
Fix libusb audio and serial (#195) * Fix libusb audio and serial * Fix warnings
--- a/Android.mk
+++ b/Android.mk
@@ -10,7 +10,7 @@
LOCAL_CFLAGS += -DUSE_LIBUSB
-LOCAL_SHARED_LIBRARIES := usb-1.0 SDL2
+LOCAL_SHARED_LIBRARIES := usb-1.0 SDL3
LOCAL_LDLIBS := -lGLESv1_CM -lGLESv2 -lOpenSLES -llog -landroid
--- a/src/backends/audio_libusb.c
+++ b/src/backends/audio_libusb.c
@@ -1,3 +1,5 @@
+#include "SDL3/SDL_audio.h"
+#include "SDL3/SDL_error.h"
#ifdef USE_LIBUSB
#include "m8.h"
@@ -15,47 +17,109 @@
extern libusb_device_handle *devh;
-SDL_AudioDeviceID sdl_audio_device_id = 0;
+SDL_AudioStream *sdl_audio_stream = NULL;
int audio_initialized = 0;
RingBuffer *audio_buffer = NULL;
+static uint8_t *audio_callback_buffer = NULL;
+static size_t audio_callback_buffer_size = 0;
+static int audio_prebuffer_filled = 0;
+#define PREBUFFER_SIZE (8 * 1024) // Wait for 8KB before starting playback
-static void audio_callback(void *userdata, Uint8 *stream, int len) {- uint32_t read_len = ring_buffer_pop(audio_buffer, stream, len);
+static void audio_callback(void *userdata, SDL_AudioStream *stream, int additional_amount, int total_amount) {+ (void)userdata; // Suppress unused parameter warning
+ (void)additional_amount; // Suppress unused parameter warning
+
+ // Reallocate callback buffer if needed
+ if (audio_callback_buffer_size < (size_t)total_amount) {+ audio_callback_buffer = SDL_realloc(audio_callback_buffer, total_amount);
+ if (audio_callback_buffer == NULL) {+ SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to allocate audio buffer");
+ return;
+ }
+ audio_callback_buffer_size = (size_t)total_amount;
+ }
- if (read_len == -1) {- SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION, "Buffer underflow!");
+ // Try to get audio data from ring buffer
+ uint32_t available_bytes = audio_buffer->size;
+
+ // Check if we have enough data for initial buffering
+ if (!audio_prebuffer_filled && available_bytes < PREBUFFER_SIZE) {+ // Not enough data yet, output silence and wait
+ SDL_memset(audio_callback_buffer, 0, total_amount);
+ if(!SDL_PutAudioStreamData(stream, audio_callback_buffer, total_amount)) {+ SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to put audio stream data: %s", SDL_GetError());
+ }
+ return;
}
+
+ // Mark prebuffer as filled once we have enough data
+ if (!audio_prebuffer_filled) {+ audio_prebuffer_filled = 1;
+ SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION, "Audio prebuffer filled, starting playback");
+ }
- // If we didn't read the full len bytes, fill the rest with zeros
- if (read_len < len) {- SDL_memset(&stream[read_len], 0, len - read_len);
+ if (available_bytes >= (uint32_t)total_amount) {+ // We have enough data, read it
+ uint32_t read_len = ring_buffer_pop(audio_buffer, audio_callback_buffer, total_amount);
+ if (read_len > 0) {+ if(!SDL_PutAudioStreamData(stream, audio_callback_buffer, read_len)) {+ SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to put audio stream data: %s", SDL_GetError());
+ }
+ }
+ } else if (available_bytes > 0) {+ // We have some data but not enough - read what we can and pad with silence
+ uint32_t read_len = ring_buffer_pop(audio_buffer, audio_callback_buffer, available_bytes);
+ SDL_memset(audio_callback_buffer + read_len, 0, total_amount - read_len);
+ if(!SDL_PutAudioStreamData(stream, audio_callback_buffer, total_amount)) {+ SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to put audio stream data: %s", SDL_GetError());
+ }
+ SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION, "Partial buffer: %d/%d bytes", available_bytes, total_amount);
+ } else {+ // No data available - put silence and reset prebuffer flag
+ SDL_memset(audio_callback_buffer, 0, total_amount);
+ if(!SDL_PutAudioStreamData(stream, audio_callback_buffer, total_amount)) {+ SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to put audio stream data: %s", SDL_GetError());
+ }
+ audio_prebuffer_filled = 0; // Reset prebuffer to avoid continuous dropouts
+ SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION, "Buffer underflow! Resetting prebuffer");
}
}
static void cb_xfr(struct libusb_transfer *xfr) {unsigned int i;
+ static int error_count = 0;
- for (i = 0; i < xfr->num_iso_packets; i++) {+ for (i = 0; i < (unsigned int)xfr->num_iso_packets; i++) {struct libusb_iso_packet_descriptor *pack = &xfr->iso_packet_desc[i];
if (pack->status != LIBUSB_TRANSFER_COMPLETED) {- SDL_LogError(SDL_LOG_CATEGORY_SYSTEM, "XFR callback error (status %d: %s)", pack->status,
- libusb_error_name(pack->status));
- /* This doesn't happen, so bail out if it does. */
- return;
+ error_count++;
+ if (error_count % 100 == 1) { // Log only every 100th error to avoid spam+ SDL_LogError(SDL_LOG_CATEGORY_SYSTEM, "XFR callback error (status %d: %s)", pack->status,
+ libusb_error_name(pack->status));
+ }
+ continue; // Skip this packet but continue processing others
}
- const uint8_t *data = libusb_get_iso_packet_buffer_simple(xfr, i);
- if (sdl_audio_device_id != 0) {- uint32_t actual = ring_buffer_push(audio_buffer, data, pack->actual_length);
- if (actual == -1) {- SDL_LogDebug(SDL_LOG_CATEGORY_SYSTEM, "Buffer overflow!");
+ if (pack->actual_length > 0) {+ const uint8_t *data = libusb_get_iso_packet_buffer_simple(xfr, i);
+ if (sdl_audio_stream != 0 && audio_buffer != NULL) {+ uint32_t actual = ring_buffer_push(audio_buffer, data, pack->actual_length);
+ if (actual == (uint32_t)-1) {+ SDL_LogDebug(SDL_LOG_CATEGORY_SYSTEM, "Buffer overflow!");
+ }
}
}
}
- if (libusb_submit_transfer(xfr) < 0) {- SDL_LogError(SDL_LOG_CATEGORY_SYSTEM, "error re-submitting URB\n");
+ // Reset error count on successful transfer
+ if (xfr->status == LIBUSB_TRANSFER_COMPLETED) {+ error_count = 0;
+ }
+
+ int submit_result = libusb_submit_transfer(xfr);
+ if (submit_result < 0) {+ SDL_LogError(SDL_LOG_CATEGORY_SYSTEM, "error re-submitting URB: %s", libusb_error_name(submit_result));
SDL_free(xfr->buffer);
}
}
@@ -84,20 +148,28 @@
return 1;
}
-int audio_initialize(int audio_buffer_size, const char *output_device_name) {- SDL_LogError(SDL_LOG_CATEGORY_AUDIO,"LIBUSB audio not implemented yet");
- return -1;
- /*
+int audio_initialize(const char *output_device_name, unsigned int audio_buffer_size) {+ (void)audio_buffer_size; // Suppress unused parameter warning
+
SDL_Log("USB audio setup");+ if (devh == NULL) {+ SDL_LogError(SDL_LOG_CATEGORY_SYSTEM, "Device handle is NULL - cannot initialize audio");
+ return -1;
+ }
+
int rc;
rc = libusb_kernel_driver_active(devh, IFACE_NUM);
+ if (rc < 0) {+ SDL_LogError(SDL_LOG_CATEGORY_SYSTEM, "Error checking kernel driver status: %s", libusb_error_name(rc));
+ return rc;
+ }
if (rc == 1) { SDL_Log("Detaching kernel driver");rc = libusb_detach_kernel_driver(devh, IFACE_NUM);
if (rc < 0) {- SDL_Log("Could not detach kernel driver: %s\n", libusb_error_name(rc));+ SDL_LogError(SDL_LOG_CATEGORY_SYSTEM, "Could not detach kernel driver: %s", libusb_error_name(rc));
return rc;
}
}
@@ -115,7 +187,7 @@
}
if (!SDL_WasInit(SDL_INIT_AUDIO)) {- if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) {+ if (!SDL_InitSubSystem(SDL_INIT_AUDIO)) {SDL_LogError(SDL_LOG_CATEGORY_SYSTEM, "Init audio failed %s", SDL_GetError());
return -1;
}
@@ -127,29 +199,29 @@
audio_spec.format = SDL_AUDIO_S16;
audio_spec.channels = 2;
audio_spec.freq = 44100;
- audio_spec.samples = audio_buffer_size;
- audio_spec.callback = audio_callback;
- SDL_AudioSpec _obtained;
- SDL_zero(_obtained);
-
SDL_Log("Current audio driver is %s and device %s", SDL_GetCurrentAudioDriver(),output_device_name);
+ // Create larger ring buffer for stable audio - about 1.5 seconds at 44.1kHz stereo 16-bit
+ audio_buffer = ring_buffer_create(256 * 1024);
+
if (SDL_strcasecmp(SDL_GetCurrentAudioDriver(), "openslES") == 0 || output_device_name == NULL) { SDL_Log("Using default audio device");- sdl_audio_device_id = SDL_OpenAudioDevice(NULL, 0, &audio_spec, &_obtained, 0);
+ sdl_audio_stream = SDL_OpenAudioDeviceStream(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &audio_spec, &audio_callback, &audio_buffer);
} else {- sdl_audio_device_id = SDL_OpenAudioDevice(output_device_name, 0, &audio_spec, &_obtained, 0);
+ // TODO: Implement audio device selection
+ sdl_audio_stream = SDL_OpenAudioDeviceStream(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &audio_spec, &audio_callback, &audio_buffer);
}
- audio_buffer = ring_buffer_create(4 * _obtained.size);
+ if (sdl_audio_stream == NULL) {+ SDL_LogError(SDL_LOG_CATEGORY_SYSTEM, "Failed to open audio stream: %s", SDL_GetError());
+ ring_buffer_free(audio_buffer);
+ return -1;
+ }
- SDL_Log("Obtained audio spec. Sample rate: %d, channels: %d, samples: %d, size: %d",- _obtained.freq, _obtained.channels, _obtained.samples, +_obtained.size);
+ SDL_ResumeAudioStreamDevice(sdl_audio_stream);
- SDL_PauseAudioDevice(sdl_audio_device_id, 0);
-
// Good to go
SDL_LogDebug(SDL_LOG_CATEGORY_SYSTEM, "Starting capture");
if ((rc = benchmark_in()) < 0) {@@ -157,15 +229,22 @@
return rc;
}
+ audio_initialized = 1;
+ audio_prebuffer_filled = 0; // Reset prebuffer state
SDL_Log("Successful init");return 1;
- */
+
}
void audio_close() {- if (devh == NULL || !audio_initialized) {+ if (devh == NULL) {+ SDL_LogDebug(SDL_LOG_CATEGORY_AUDIO, "Device handle is NULL - audio already closed or not initialized");
return;
}
+ if (!audio_initialized) {+ SDL_LogDebug(SDL_LOG_CATEGORY_AUDIO, "Audio not initialized - nothing to close");
+ return;
+ }
SDL_LogDebug(SDL_LOG_CATEGORY_AUDIO, "Closing audio");
@@ -187,19 +266,30 @@
return;
}
- if (sdl_audio_device_id != 0) {- SDL_Log("Closing audio device %d", sdl_audio_device_id);- const SDL_AudioDeviceID device = sdl_audio_device_id;
- sdl_audio_device_id = 0;
- SDL_CloseAudioDevice(device);
+ if (sdl_audio_stream != NULL) {+ SDL_Log("Closing audio device");+ SDL_DestroyAudioStream(sdl_audio_stream);
+ sdl_audio_stream = 0;
}
SDL_LogDebug(SDL_LOG_CATEGORY_SYSTEM, "Audio closed");
ring_buffer_free(audio_buffer);
+
+ // Free callback buffer
+ if (audio_callback_buffer) {+ SDL_free(audio_callback_buffer);
+ audio_callback_buffer = NULL;
+ audio_callback_buffer_size = 0;
+ }
+
+ audio_initialized = 0;
+ audio_prebuffer_filled = 0;
}
-void audio_toggle(unsigned int audio_buffer_size, const char *output_device_name) {+void audio_toggle(const char *output_device_name, unsigned int audio_buffer_size) {+ (void)output_device_name; // Suppress unused parameter warning
+ (void)audio_buffer_size; // Suppress unused parameter warning
SDL_Log("Libusb audio toggling not implemented yet");}
--- a/src/backends/m8_libusb.c
+++ b/src/backends/m8_libusb.c
@@ -3,6 +3,7 @@
// Contains portions of code from libserialport's examples released to the
// public domain
+#include "m8.h"
#ifdef USE_LIBUSB
#include <SDL3/SDL.h>
@@ -9,6 +10,9 @@
#include <libusb.h>
#include <stdlib.h>
#include <string.h>
+#include "../command.h"
+#include "queue.h"
+#include "slip.h"
static int ep_out_addr = 0x03;
static int ep_in_addr = 0x83;
@@ -19,11 +23,24 @@
#define M8_VID 0x16c0
#define M8_PID 0x048a
+#define SERIAL_READ_SIZE 1024 // maximum amount of bytes to read from the serial in one pass
+
libusb_context *ctx = NULL;
libusb_device_handle *devh = NULL;
-
+static uint8_t serial_buffer[SERIAL_READ_SIZE] = {0};+static uint8_t slip_buffer[SERIAL_READ_SIZE] = {0};+static slip_handler_s slip;
+message_queue_s queue;
static int do_exit = 0;
+static int async_transfer_active = 0;
+static struct libusb_transfer *async_transfer = NULL;
+static int shutdown_in_progress = 0;
+static int send_message_to_queue(uint8_t *data, const uint32_t size) {+ push_message(&queue, data, size);
+ return 1;
+}
+
int m8_list_devices() {int r;
r = libusb_init(&ctx);
@@ -34,7 +51,7 @@
libusb_device **device_list = NULL;
int count = libusb_get_device_list(ctx, &device_list);
- for (size_t idx = 0; idx < count; ++idx) {+ for (size_t idx = 0; idx < (size_t)count; ++idx) {libusb_device *device = device_list[idx];
struct libusb_device_descriptor desc;
int rc = libusb_get_device_descriptor(device, &desc);
@@ -53,7 +70,9 @@
return 0;
}
-int usb_loop(void *data) {+static int usb_loop(void *data) {+ (void)data; // Suppress unused parameter warning
+
SDL_SetCurrentThreadPriority(SDL_THREAD_PRIORITY_TIME_CRITICAL);
while (!do_exit) {int rc = libusb_handle_events(ctx);
@@ -72,7 +91,7 @@
*completed = 1;
}
-int bulk_transfer(int endpoint, uint8_t *serial_buf, int count, unsigned int timeout_ms) {+static int bulk_transfer(int endpoint, uint8_t *serial_buf, int count, unsigned int timeout_ms) { if (devh == NULL) {return -1;
}
@@ -113,10 +132,153 @@
return bulk_transfer(ep_out_addr, buf, count, timeout_ms);
}
-int m8_process_data(uint8_t *serial_buf, int count) {- return bulk_transfer(ep_in_addr, serial_buf, count, 1);
+// This function is currently unused but kept for potential future use
+__attribute__((unused))
+static int bulk_async_transfer(int endpoint, uint8_t *serial_buf, int count, unsigned int timeout_ms,
+ void (*f)(struct libusb_transfer *), void *user_data) {+ struct libusb_transfer *transfer;
+ transfer = libusb_alloc_transfer(1);
+ libusb_fill_bulk_stream_transfer(transfer, devh, endpoint, 0, serial_buf, count, f, user_data,
+ timeout_ms);
+ int r = libusb_submit_transfer(transfer);
+
+ if (r < 0) {+ SDL_Log("Error");+ libusb_free_transfer(transfer);
+ return r;
+ }
+ return 0;
}
+static void async_callback(struct libusb_transfer *xfr) {+ if (shutdown_in_progress) {+ async_transfer_active = 0;
+ return;
+ }
+
+ if (xfr->status != LIBUSB_TRANSFER_COMPLETED) {+ if (xfr->status == LIBUSB_TRANSFER_CANCELLED) {+ SDL_LogDebug(SDL_LOG_CATEGORY_SYSTEM, "Async transfer cancelled");
+ async_transfer_active = 0;
+ return;
+ }
+ SDL_LogError(SDL_LOG_CATEGORY_SYSTEM, "Async transfer failed with status: %s",
+ libusb_error_name(xfr->status));
+ if (!shutdown_in_progress && libusb_submit_transfer(xfr) < 0) {+ SDL_LogError(SDL_LOG_CATEGORY_SYSTEM, "Error re-submitting failed transfer");
+ async_transfer_active = 0;
+ }
+ return;
+ }
+
+ int bytes_read = xfr->actual_length;
+ if (bytes_read < 0) {+ SDL_LogCritical(SDL_LOG_CATEGORY_ERROR, "Error %d reading serial", (int)bytes_read);
+ } else if (bytes_read > 0) {+ SDL_LogDebug(SDL_LOG_CATEGORY_SYSTEM, "Received %d bytes from M8", bytes_read);
+ uint8_t *serial_buf = xfr->buffer;
+ uint8_t *cur = serial_buf;
+ const uint8_t *end = serial_buf + bytes_read;
+ slip_handler_s *slip = (slip_handler_s *)xfr->user_data;
+ while (cur < end) {+ // process the incoming bytes into commands and draw them
+ int n = slip_read_byte(slip, *(cur++));
+ if (n != SLIP_NO_ERROR) {+ if (n == SLIP_ERROR_INVALID_PACKET) {+ SDL_LogError(SDL_LOG_CATEGORY_ERROR, "Invalid SLIP packet!\n");
+
+ } else {+ SDL_LogError(SDL_LOG_CATEGORY_ERROR, "SLIP error %d\n", n);
+ }
+ }
+ }
+ }
+ if (!shutdown_in_progress) {+ int submit_result = libusb_submit_transfer(xfr);
+ if (submit_result < 0) {+ SDL_LogError(SDL_LOG_CATEGORY_SYSTEM, "Error re-submitting URB: %s",
+ libusb_error_name(submit_result));
+ async_transfer_active = 0;
+ }
+ } else {+ async_transfer_active = 0;
+ }
+}
+
+int async_read_start(uint8_t *serial_buf, int count, slip_handler_s *slip) {+ if (async_transfer_active) {+ SDL_LogDebug(SDL_LOG_CATEGORY_SYSTEM, "Async transfer already active, skipping");
+ return 0; // Already active
+ }
+
+ if (devh == NULL) {+ SDL_LogError(SDL_LOG_CATEGORY_SYSTEM, "Device handle is NULL, cannot start async transfer");
+ return -1;
+ }
+
+ async_transfer = libusb_alloc_transfer(1);
+ if (!async_transfer) {+ SDL_LogError(SDL_LOG_CATEGORY_SYSTEM, "Failed to allocate async transfer");
+ return -1;
+ }
+
+ libusb_fill_bulk_stream_transfer(async_transfer, devh, ep_in_addr, 0, serial_buf, count,
+ &async_callback, slip, 300);
+ int r = libusb_submit_transfer(async_transfer);
+
+ if (r < 0) {+ SDL_LogError(SDL_LOG_CATEGORY_SYSTEM, "Error starting async transfer: %s", libusb_error_name(r));
+ libusb_free_transfer(async_transfer);
+ async_transfer = NULL;
+ return r;
+ }
+
+ async_transfer_active = 1;
+ SDL_LogDebug(SDL_LOG_CATEGORY_SYSTEM, "Async transfer started successfully");
+ return 0;
+}
+
+void async_read_stop() {+ shutdown_in_progress = 1;
+
+ if (async_transfer_active && async_transfer) {+ SDL_LogDebug(SDL_LOG_CATEGORY_SYSTEM, "Stopping async transfer");
+ int cancel_result = libusb_cancel_transfer(async_transfer);
+ if (cancel_result < 0) {+ if (cancel_result == LIBUSB_ERROR_NOT_FOUND) {+ SDL_LogDebug(SDL_LOG_CATEGORY_SYSTEM, "Transfer already completed or cancelled");
+ } else if (cancel_result == LIBUSB_ERROR_INVALID_PARAM) {+ SDL_LogDebug(SDL_LOG_CATEGORY_SYSTEM, "Transfer not valid for cancellation");
+ } else {+ SDL_LogDebug(SDL_LOG_CATEGORY_SYSTEM, "Transfer cancellation returned: %s",
+ libusb_error_name(cancel_result));
+ }
+ }
+ // Wait briefly for the callback to complete
+ for (int i = 0; i < 10 && async_transfer_active; i++) {+ SDL_Delay(1);
+ }
+ // Force cleanup if still active
+ async_transfer_active = 0;
+ }
+}
+
+int m8_process_data(const config_params_s *conf) {+ (void)conf; // Suppress unused parameter warning
+ // Process any queued messages
+ if (queue_size(&queue) > 0) {+ unsigned char *command;
+ size_t length = 0;
+ while ((command = pop_message(&queue, &length)) != NULL) {+ if (length > 0) {+ process_command(command, length);
+ }
+ SDL_free(command);
+ }
+ }
+ return DEVICE_PROCESSING;
+}
+
int check_serial_port() {// Reading will fail anyway when the device is not present anymore
return 1;
@@ -166,8 +328,15 @@
return 0;
}
+ init_queue(&queue);
+
usb_thread = SDL_CreateThread(&usb_loop, "USB", NULL);
+ // Start async transfer for reading data from M8
+ if (async_read_start(serial_buffer, SERIAL_READ_SIZE, &slip) < 0) {+ SDL_LogError(SDL_LOG_CATEGORY_SYSTEM, "Failed to start async transfer during initialization");
+ }
+
return 1;
}
@@ -203,12 +372,22 @@
return init_interface();
}
-int m8_initialize(int verbose, char *preferred_device) {+int m8_initialize(int verbose, const char *preferred_device) {+ (void)verbose; // Suppress unused parameter warning
+ (void)preferred_device; // Suppress unused parameter warning
if (devh != NULL) {return 1;
}
+ // Initialize slip descriptor
+ static const slip_descriptor_s slip_descriptor = {+ .buf = slip_buffer,
+ .buf_size = sizeof(slip_buffer),
+ .recv_message = send_message_to_queue,
+ };
+ slip_init(&slip, &slip_descriptor);
+
int r;
r = libusb_init(&ctx);
if (r < 0) {@@ -221,11 +400,16 @@
char *port;
char *saveptr = NULL;
char *bus;
- port = SDL_strtok_r(preferred_device, ":", &saveptr);
+ char *device_copy = SDL_strdup(preferred_device); // Create a copy to avoid const qualifier warning
+ if (device_copy == NULL) {+ SDL_Log("Failed to allocate memory for device string");+ return 0;
+ }
+ port = SDL_strtok_r(device_copy, ":", &saveptr);
bus = SDL_strtok_r(NULL, ":", &saveptr);
libusb_device **device_list = NULL;
int count = libusb_get_device_list(ctx, &device_list);
- for (size_t idx = 0; idx < count; ++idx) {+ for (size_t idx = 0; idx < (size_t)count; ++idx) {libusb_device *device = device_list[idx];
struct libusb_device_descriptor desc;
r = libusb_get_device_descriptor(device, &desc);
@@ -232,6 +416,7 @@
if (r < 0) { SDL_Log("libusb_get_device_descriptor failed: %s", libusb_error_name(r));libusb_free_device_list(device_list, 1);
+ SDL_free(device_copy);
return 0;
}
@@ -243,6 +428,8 @@
r = libusb_open(device, &devh);
if (r < 0) { SDL_Log("libusb_open failed: %s", libusb_error_name(r));+ libusb_free_device_list(device_list, 1);
+ SDL_free(device_copy);
return 0;
}
}
@@ -249,6 +436,7 @@
}
}
libusb_free_device_list(device_list, 1);
+ SDL_free(device_copy); // Free the allocated copy
if (devh == NULL) { SDL_Log("Preferred device %s not found, using first available", preferred_device);devh = libusb_open_device_with_vid_pid(ctx, M8_VID, M8_PID);
@@ -280,6 +468,7 @@
}
int m8_enable_display(const unsigned char reset_display) {+ (void)reset_display; // Suppress unused parameter warning
if (devh == NULL) {return 0;
}
@@ -296,8 +485,7 @@
}
SDL_Delay(5);
- if ()
- result = m8_reset_display();
+ result = m8_reset_display();
return result;
}
@@ -308,6 +496,9 @@
SDL_Log("Disconnecting M8\n");+ // Stop async transfer first
+ async_read_stop();
+
result = blocking_write(buf, 1, 5);
if (result != 1) {SDL_LogError(SDL_LOG_CATEGORY_SYSTEM, "Error sending disconnect, code %d", result);
@@ -334,6 +525,15 @@
SDL_WaitThread(usb_thread, NULL);
libusb_exit(ctx);
+
+ destroy_queue(&queue);
+
+ if (async_transfer) {+ libusb_free_transfer(async_transfer);
+ async_transfer = NULL;
+ }
+ async_transfer_active = 0;
+ shutdown_in_progress = 0;
return 1;
}
--- a/src/input.c
+++ b/src/input.c
@@ -366,6 +366,7 @@
// Touch screen double tap: switch between integer scaling / full screen scaling
void input_handle_finger_down(struct app_context *ctx, const SDL_Event *event) {+ (void)event; // Suppress unused parameter warning
static Uint64 last_finger_down_time = 0;
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, "Finger down");
const Uint64 current_time = SDL_GetTicks();
--
⑨