linux.x86.linphone/fixes/hidapi-crash-fix/hidapi_dummy.c
data 3b3bb966d4 Add ringtone selection dropdown and various bugfixes
- Add ComboBox for ringtone selection in Call Settings
- Convert MKV ringtones to WAV format (Linphone only supports WAV)
- Fix ComboSetting to support dialPlan type for international prefix
- Disable account devices feature to prevent API errors
- Disable automatic update check on startup
- Add ringtone fallback to default when custom file not found
- Fix ringtone dropdown to not override setting on initialization

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-08 08:31:15 +01:00

434 lines
11 KiB
C

/**
* @file hidapi_dummy.c
* @brief Stub implementation of HIDAPI 0.15.0 to prevent crashes when HID access fails.
*
* This library provides a complete no-op implementation of the HIDAPI interface.
* All device enumeration returns empty lists, all device operations fail gracefully.
*
* Purpose: Linphone's liblinphone SDK crashes when it cannot access /dev/hidraw* devices
* (for USB headset button support). This stub library prevents those crashes by
* intercepting all HID calls and returning safe, predictable values.
*
* Build: gcc -shared -fPIC -O2 -Wall -Wextra -o libhidapi-hidraw.so.0 hidapi_dummy.c
* Usage: LD_PRELOAD=/path/to/libhidapi-hidraw.so.0 ./application
*
* @author Generated for Linphone crash workaround
* @version 0.15.0 (matching HIDAPI version)
* @see https://github.com/libusb/hidapi
*/
#define _GNU_SOURCE
#include <stddef.h>
#include <wchar.h>
/* ============================================================================
* Type Definitions (matching hidapi.h)
* ============================================================================ */
/** Opaque device handle - we never actually allocate these */
struct hid_device_;
typedef struct hid_device_ hid_device;
/** HID bus types */
typedef enum {
HID_API_BUS_UNKNOWN = 0x00,
HID_API_BUS_USB = 0x01,
HID_API_BUS_BLUETOOTH = 0x02,
HID_API_BUS_I2C = 0x03,
HID_API_BUS_SPI = 0x04,
} hid_bus_type;
/** Device information structure */
struct hid_device_info {
char *path;
unsigned short vendor_id;
unsigned short product_id;
wchar_t *serial_number;
unsigned short release_number;
wchar_t *manufacturer_string;
wchar_t *product_string;
unsigned short usage_page;
unsigned short usage;
int interface_number;
struct hid_device_info *next;
hid_bus_type bus_type;
};
/** Version information structure */
struct hid_api_version {
int major;
int minor;
int patch;
};
/* ============================================================================
* Static Data
* ============================================================================ */
/** Version info matching HIDAPI 0.15.0 */
static const struct hid_api_version g_version = {.major = 0, .minor = 15, .patch = 0};
/** Version string */
static const char g_version_str[] = "0.15.0-stub";
/** Error message for NULL device operations */
static const wchar_t g_error_no_device[] = L"No HID devices available (stub library)";
/** Error message for successful operations */
static const wchar_t g_error_none[] = L"Success";
/** Global initialization state */
static int g_initialized = 0;
/* ============================================================================
* Library Initialization / Cleanup
* ============================================================================ */
/**
* @brief Initialize the HIDAPI library.
* @return 0 on success (always succeeds)
*/
int hid_init(void) {
g_initialized = 1;
return 0;
}
/**
* @brief Finalize the HIDAPI library.
* @return 0 on success (always succeeds)
*/
int hid_exit(void) {
g_initialized = 0;
return 0;
}
/* ============================================================================
* Device Enumeration
* ============================================================================ */
/**
* @brief Enumerate HID devices.
* @param vendor_id Vendor ID filter (0 = any)
* @param product_id Product ID filter (0 = any)
* @return NULL (no devices available in stub)
*/
struct hid_device_info *hid_enumerate(unsigned short vendor_id, unsigned short product_id) {
(void)vendor_id;
(void)product_id;
/* Ensure library is initialized */
if (!g_initialized) {
hid_init();
}
/* Return empty list - no devices */
return NULL;
}
/**
* @brief Free an enumeration linked list.
* @param devs Pointer to device list (ignored, nothing to free)
*/
void hid_free_enumeration(struct hid_device_info *devs) {
(void)devs;
/* Nothing to free - we never allocate device info */
}
/* ============================================================================
* Device Open / Close
* ============================================================================ */
/**
* @brief Open a HID device by VID/PID.
* @param vendor_id Vendor ID
* @param product_id Product ID
* @param serial_number Serial number (optional)
* @return NULL (device not found)
*/
hid_device *hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number) {
(void)vendor_id;
(void)product_id;
(void)serial_number;
if (!g_initialized) {
hid_init();
}
return NULL;
}
/**
* @brief Open a HID device by path.
* @param path Device path (e.g., /dev/hidraw0)
* @return NULL (device not found)
*/
hid_device *hid_open_path(const char *path) {
(void)path;
if (!g_initialized) {
hid_init();
}
return NULL;
}
/**
* @brief Close a HID device.
* @param dev Device handle (ignored)
*/
void hid_close(hid_device *dev) {
(void)dev;
/* Nothing to close */
}
/* ============================================================================
* Device I/O Operations
* ============================================================================ */
/**
* @brief Write an output report to a HID device.
* @param dev Device handle
* @param data Data buffer
* @param length Buffer length
* @return -1 (error - no device)
*/
int hid_write(hid_device *dev, const unsigned char *data, size_t length) {
(void)dev;
(void)data;
(void)length;
return -1;
}
/**
* @brief Read an input report with timeout.
* @param dev Device handle
* @param data Buffer for data
* @param length Buffer size
* @param milliseconds Timeout (-1 for blocking)
* @return 0 (no data available)
*/
int hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds) {
(void)dev;
(void)data;
(void)length;
(void)milliseconds;
return 0;
}
/**
* @brief Read an input report.
* @param dev Device handle
* @param data Buffer for data
* @param length Buffer size
* @return 0 (no data available)
*/
int hid_read(hid_device *dev, unsigned char *data, size_t length) {
(void)dev;
(void)data;
(void)length;
return 0;
}
/**
* @brief Set non-blocking mode.
* @param dev Device handle
* @param nonblock 1 for non-blocking, 0 for blocking
* @return -1 (error - no device)
*/
int hid_set_nonblocking(hid_device *dev, int nonblock) {
(void)dev;
(void)nonblock;
return -1;
}
/* ============================================================================
* Feature / Output / Input Reports
* ============================================================================ */
/**
* @brief Send a feature report.
* @param dev Device handle
* @param data Report data
* @param length Data length
* @return -1 (error - no device)
*/
int hid_send_feature_report(hid_device *dev, const unsigned char *data, size_t length) {
(void)dev;
(void)data;
(void)length;
return -1;
}
/**
* @brief Get a feature report.
* @param dev Device handle
* @param data Buffer for report
* @param length Buffer size
* @return -1 (error - no device)
*/
int hid_get_feature_report(hid_device *dev, unsigned char *data, size_t length) {
(void)dev;
(void)data;
(void)length;
return -1;
}
/**
* @brief Send an output report (since 0.15.0).
* @param dev Device handle
* @param data Report data
* @param length Data length
* @return -1 (error - no device)
*/
int hid_send_output_report(hid_device *dev, const unsigned char *data, size_t length) {
(void)dev;
(void)data;
(void)length;
return -1;
}
/**
* @brief Get an input report.
* @param dev Device handle
* @param data Buffer for report
* @param length Buffer size
* @return -1 (error - no device)
*/
int hid_get_input_report(hid_device *dev, unsigned char *data, size_t length) {
(void)dev;
(void)data;
(void)length;
return -1;
}
/**
* @brief Get a report descriptor (since 0.14.0).
* @param dev Device handle
* @param buf Buffer for descriptor
* @param buf_size Buffer size
* @return -1 (error - no device)
*/
int hid_get_report_descriptor(hid_device *dev, unsigned char *buf, size_t buf_size) {
(void)dev;
(void)buf;
(void)buf_size;
return -1;
}
/* ============================================================================
* Device Information Retrieval
* ============================================================================ */
/**
* @brief Get manufacturer string.
* @param dev Device handle
* @param string Buffer for string
* @param maxlen Buffer size in wchar_t units
* @return -1 (error - no device)
*/
int hid_get_manufacturer_string(hid_device *dev, wchar_t *string, size_t maxlen) {
(void)dev;
(void)string;
(void)maxlen;
return -1;
}
/**
* @brief Get product string.
* @param dev Device handle
* @param string Buffer for string
* @param maxlen Buffer size in wchar_t units
* @return -1 (error - no device)
*/
int hid_get_product_string(hid_device *dev, wchar_t *string, size_t maxlen) {
(void)dev;
(void)string;
(void)maxlen;
return -1;
}
/**
* @brief Get serial number string.
* @param dev Device handle
* @param string Buffer for string
* @param maxlen Buffer size in wchar_t units
* @return -1 (error - no device)
*/
int hid_get_serial_number_string(hid_device *dev, wchar_t *string, size_t maxlen) {
(void)dev;
(void)string;
(void)maxlen;
return -1;
}
/**
* @brief Get device info structure (since 0.13.0).
* @param dev Device handle
* @return NULL (no device info available)
*/
struct hid_device_info *hid_get_device_info(hid_device *dev) {
(void)dev;
return NULL;
}
/**
* @brief Get indexed string.
* @param dev Device handle
* @param string_index String index
* @param string Buffer for string
* @param maxlen Buffer size in wchar_t units
* @return -1 (error - no device)
*/
int hid_get_indexed_string(hid_device *dev, int string_index, wchar_t *string, size_t maxlen) {
(void)dev;
(void)string_index;
(void)string;
(void)maxlen;
return -1;
}
/* ============================================================================
* Error Handling
* ============================================================================ */
/**
* @brief Get last error string.
* @param dev Device handle (NULL for global error)
* @return Error description (never NULL)
*/
const wchar_t *hid_error(hid_device *dev) {
if (dev == NULL) {
return g_error_no_device;
}
return g_error_none;
}
/**
* @brief Get last read error string (since 0.15.0).
* @param dev Device handle
* @return Error description (never NULL)
*/
const wchar_t *hid_read_error(hid_device *dev) {
(void)dev;
return g_error_none;
}
/* ============================================================================
* Version Information
* ============================================================================ */
/**
* @brief Get library version structure.
* @return Pointer to static version info
*/
const struct hid_api_version *hid_version(void) {
return &g_version;
}
/**
* @brief Get library version string.
* @return Version string
*/
const char *hid_version_str(void) {
return g_version_str;
}