From a2f92739791ed49d7d38b1d3748158d8120b93f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Kelemen=20=28vudiq=29?= Date: Wed, 17 Nov 2021 21:25:06 +0100 Subject: [PATCH] Bluetooth: add option to remove pairing Pressing the START button removes the device pairing. Useful in case the device (e.g. gamepad) was paired with a different adapter/computer and needs to be paired again with current adapter/computer. To pair again, RetroArch needs to be restarted, so the device list is populated again. Upstream of patch used by Lakka at build time https://github.com/libretro/Lakka-LibreELEC/blob/1943ad296eaf7c01040f02aa8f5dff3d2f37309f/packages/libretro/retroarch/patches/retroarch-98-remove_bluetooth_pairing.patch --- bluetooth/bluetooth_driver.h | 3 +++ bluetooth/drivers/bluetoothctl.c | 40 ++++++++++++++++++++++++++++++++ bluetooth/drivers/bluez.c | 22 ++++++++++++++++++ driver.c | 1 + intl/msg_hash_us.h | 4 ++++ menu/cbs/menu_cbs_start.c | 19 +++++++++++++++ msg_hash.h | 1 + retroarch.c | 8 +++++++ 8 files changed, 98 insertions(+) diff --git a/bluetooth/bluetooth_driver.h b/bluetooth/bluetooth_driver.h index 498bd23804..5ce5268abb 100644 --- a/bluetooth/bluetooth_driver.h +++ b/bluetooth/bluetooth_driver.h @@ -43,6 +43,7 @@ typedef struct bluetooth_driver bool (*device_is_connected)(void *data, unsigned i); void (*device_get_sublabel)(void *data, char *s, unsigned i, size_t len); bool (*connect_device)(void *data, unsigned i); + bool (*remove_device)(void *data, unsigned i); const char *ident; } bluetooth_driver_t; @@ -71,6 +72,8 @@ void driver_bluetooth_device_get_sublabel(char *s, unsigned i, size_t len); bool driver_bluetooth_connect_device(unsigned i); +bool driver_bluetooth_remove_device(unsigned i); + bool bluetooth_driver_ctl(enum rarch_bluetooth_ctl_state state, void *data); extern const bluetooth_driver_t *bluetooth_drivers[]; diff --git a/bluetooth/drivers/bluetoothctl.c b/bluetooth/drivers/bluetoothctl.c index 6741931454..f3205c8ee9 100644 --- a/bluetooth/drivers/bluetoothctl.c +++ b/bluetooth/drivers/bluetoothctl.c @@ -191,6 +191,45 @@ static bool bluetoothctl_connect_device(void *data, unsigned idx) return true; } +static bool bluetoothctl_remove_device(void *data, unsigned idx) +{ + unsigned i; + bluetoothctl_t *btctl = (bluetoothctl_t*) data; + char device[18] = {0}; + const char *line = btctl->lines->elems[idx].data; + static struct string_list* list = NULL; + + /* bluetoothctl devices outputs lines of the format: + * $ bluetoothctl devices + * 'Device (mac address) (device name)' + */ + list = string_split(line, " "); + if (!list) + return false; + + if (list->size == 0) + { + string_list_free(list); + return false; + } + + strlcpy(device, list->elems[1].data, sizeof(device)); + string_list_free(list); + + snprintf(btctl->command, sizeof(btctl->command), "\ + echo -e \"disconnect %s\\nremove %s\\n\" | bluetoothctl", + device, device); + + pclose(popen(btctl->command, "r")); + + runloop_msg_queue_push(msg_hash_to_str(MSG_BLUETOOTH_PAIRING_REMOVED), + 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, + MESSAGE_QUEUE_CATEGORY_INFO); + + btctl->bluetoothctl_counter[idx] = 0; + return true; +} + static void bluetoothctl_device_get_sublabel( void *data, char *s, unsigned i, size_t len) { @@ -211,5 +250,6 @@ bluetooth_driver_t bluetooth_bluetoothctl = { bluetoothctl_device_is_connected, bluetoothctl_device_get_sublabel, bluetoothctl_connect_device, + bluetoothctl_remove_device, "bluetoothctl", }; diff --git a/bluetooth/drivers/bluez.c b/bluetooth/drivers/bluez.c index 82239c319d..f0bfdb2973 100644 --- a/bluetooth/drivers/bluez.c +++ b/bluetooth/drivers/bluez.c @@ -604,6 +604,27 @@ static bool bluez_connect_device(void *data, unsigned i) return true; } +static bool bluez_remove_device(void *data, unsigned i) +{ + bluez_t *bluez = (bluez_t*)data; + bluez_dbus_connect(bluez); + + /* Disconnect the device */ + device_method(bluez, bluez->devices->data[i].path, "Disconnect"); + + /* Remove the device */ + if (device_method(bluez, bluez->devices->data[i].path, "RemoveDevice")) + return false; + + runloop_msg_queue_push(msg_hash_to_str(MSG_BLUETOOTH_PAIRING_REMOVED), + 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, + MESSAGE_QUEUE_CATEGORY_INFO); + + bluez_dbus_disconnect(bluez); + bluez->bluez_cache_counter[i] = 0; + return true; +} + bluetooth_driver_t bluetooth_bluez = { bluez_init, bluez_free, @@ -612,5 +633,6 @@ bluetooth_driver_t bluetooth_bluez = { bluez_device_is_connected, bluez_device_get_sublabel, bluez_connect_device, + bluez_remove_device, "bluez", }; diff --git a/driver.c b/driver.c index cc498e390f..54d7e702ce 100644 --- a/driver.c +++ b/driver.c @@ -53,6 +53,7 @@ static bluetooth_driver_t bluetooth_null = { NULL, /* device_is_connected */ NULL, /* device_get_sublabel */ NULL, /* connect_device */ + NULL, /* remove_device */ "null", }; diff --git a/intl/msg_hash_us.h b/intl/msg_hash_us.h index 068de0158f..dedec1f092 100644 --- a/intl/msg_hash_us.h +++ b/intl/msg_hash_us.h @@ -11889,6 +11889,10 @@ MSG_HASH( MSG_BLUETOOTH_SCAN_COMPLETE, "Bluetooth scan complete." ) +MSG_HASH( + MSG_BLUETOOTH_PAIRING_REMOVED, + "Pairing removed. Restart RetroArch to connect/pair again." + ) MSG_HASH( MSG_WIFI_SCAN_COMPLETE, "Wi-Fi scan complete." diff --git a/menu/cbs/menu_cbs_start.c b/menu/cbs/menu_cbs_start.c index c884df9015..3569f912f0 100644 --- a/menu/cbs/menu_cbs_start.c +++ b/menu/cbs/menu_cbs_start.c @@ -48,6 +48,10 @@ #include "../../config.def.h" +#ifdef HAVE_BLUETOOTH +#include "../../bluetooth/bluetooth_driver.h" +#endif + #ifdef HAVE_NETWORKING #include "../../core_updater_list.h" #endif @@ -539,6 +543,16 @@ static int action_start_load_core( return ret; } +#ifdef HAVE_BLUETOOTH +static int action_start_bluetooth(const char *path, const char *label, + unsigned menu_type, size_t idx, size_t entry_idx) +{ + driver_bluetooth_remove_device((unsigned)idx); + + return 0; +} +#endif + #ifdef HAVE_NETWORKING static int action_start_core_updater_entry( const char *path, const char *label, @@ -711,6 +725,11 @@ static int menu_cbs_init_bind_start_compare_label(menu_file_list_cbs_t *cbs) case MENU_ENUM_LABEL_MANUAL_CONTENT_SCAN_CORE_NAME: BIND_ACTION_START(cbs, action_start_manual_content_scan_core_name); break; +#ifdef HAVE_BLUETOOTH + case MENU_ENUM_LABEL_CONNECT_BLUETOOTH: + BIND_ACTION_START(cbs, action_start_bluetooth); + break; +#endif default: return -1; } diff --git a/msg_hash.h b/msg_hash.h index ea33750180..1e2412d669 100644 --- a/msg_hash.h +++ b/msg_hash.h @@ -386,6 +386,7 @@ enum msg_hash_enums MSG_TOGGLE_CONTENT_METADATA, MSG_NO_THUMBNAIL_AVAILABLE, MSG_PRESS_AGAIN_TO_QUIT, + MSG_BLUETOOTH_PAIRING_REMOVED, MSG_BLUETOOTH_SCAN_COMPLETE, MSG_WIFI_SCAN_COMPLETE, MSG_WIFI_CONNECTING_TO, diff --git a/retroarch.c b/retroarch.c index 3bd493ec05..8bb251ab16 100644 --- a/retroarch.c +++ b/retroarch.c @@ -9977,6 +9977,14 @@ bool driver_bluetooth_connect_device(unsigned i) return false; } +bool driver_bluetooth_remove_device(unsigned i) +{ + struct rarch_state *p_rarch = &rarch_st; + if (p_rarch->bluetooth_driver_active) + return p_rarch->bluetooth_driver->remove_device(p_rarch->bluetooth_data, i); + return false; +} + bool bluetooth_driver_ctl(enum rarch_bluetooth_ctl_state state, void *data) { struct rarch_state *p_rarch = &rarch_st;