2020-06-24 02:51:42 +03:00
|
|
|
|
/* RetroArch - A frontend for libretro.
|
|
|
|
|
*
|
|
|
|
|
* RetroArch is free software: you can redistribute it and/or modify it under the terms
|
|
|
|
|
* of the GNU General Public License as published by the Free Software Found-
|
|
|
|
|
* ation, either version 3 of the License, or (at your option) any later version.
|
|
|
|
|
*
|
|
|
|
|
* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
|
|
|
|
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
|
|
|
* PURPOSE. See the GNU General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU General Public License along with RetroArch.
|
|
|
|
|
* If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include <dbus/dbus.h>
|
|
|
|
|
#include <compat/strl.h>
|
|
|
|
|
#include <configuration.h>
|
|
|
|
|
#include <retro_timers.h>
|
2020-06-27 19:46:27 +02:00
|
|
|
|
#include <string/stdstring.h>
|
2020-06-24 02:51:42 +03:00
|
|
|
|
|
|
|
|
|
#include "../bluetooth_driver.h"
|
|
|
|
|
#include "../../retroarch.h"
|
|
|
|
|
|
2020-06-27 19:46:27 +02:00
|
|
|
|
typedef struct
|
|
|
|
|
{
|
2020-06-24 02:51:42 +03:00
|
|
|
|
/* object path. usually looks like /org/bluez/hci0/dev_AA_BB_CC_DD_EE_FF
|
|
|
|
|
* technically unlimited, but should be enough */
|
|
|
|
|
char path[128];
|
|
|
|
|
|
|
|
|
|
/* for display purposes 64 bytes should be enough */
|
|
|
|
|
char name[64];
|
|
|
|
|
|
|
|
|
|
/* MAC address, 17 bytes */
|
|
|
|
|
char address[18];
|
|
|
|
|
|
|
|
|
|
/* freedesktop.org icon name
|
|
|
|
|
* See bluez/src/dbus-common.c
|
|
|
|
|
* Can be NULL */
|
|
|
|
|
char icon[64];
|
|
|
|
|
|
|
|
|
|
int connected;
|
|
|
|
|
int paired;
|
|
|
|
|
int trusted;
|
|
|
|
|
} device_info_t;
|
|
|
|
|
|
|
|
|
|
#define VECTOR_LIST_TYPE device_info_t
|
|
|
|
|
#define VECTOR_LIST_NAME device_info
|
|
|
|
|
#include "../../libretro-common/lists/vector_list.c"
|
|
|
|
|
#undef VECTOR_LIST_TYPE
|
|
|
|
|
#undef VECTOR_LIST_NAME
|
|
|
|
|
|
2020-06-28 22:02:48 +03:00
|
|
|
|
typedef struct
|
|
|
|
|
{
|
|
|
|
|
struct device_info_vector_list *devices;
|
|
|
|
|
char adapter[256];
|
|
|
|
|
DBusConnection* dbus_connection;
|
|
|
|
|
bool bluez_cache[256];
|
|
|
|
|
int bluez_cache_counter[256];
|
|
|
|
|
} bluez_t;
|
2020-06-24 02:51:42 +03:00
|
|
|
|
|
|
|
|
|
static void *bluez_init (void)
|
|
|
|
|
{
|
2020-06-28 22:02:48 +03:00
|
|
|
|
return calloc(1, sizeof(bluez_t));
|
2020-06-24 02:51:42 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void bluez_free (void *data)
|
|
|
|
|
{
|
2020-06-28 22:02:48 +03:00
|
|
|
|
if (data)
|
|
|
|
|
free(data);
|
2020-06-24 02:51:42 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
set_bool_property (
|
2020-06-28 22:02:48 +03:00
|
|
|
|
bluez_t *bluez,
|
2020-06-24 02:51:42 +03:00
|
|
|
|
const char *path,
|
|
|
|
|
const char *arg_adapter,
|
|
|
|
|
const char *arg_property,
|
|
|
|
|
int value)
|
|
|
|
|
{
|
|
|
|
|
DBusError err;
|
2020-06-29 00:25:37 +02:00
|
|
|
|
DBusMessage *message, *reply;
|
|
|
|
|
DBusMessageIter req_iter, req_subiter;
|
2020-06-24 02:51:42 +03:00
|
|
|
|
|
|
|
|
|
dbus_error_init(&err);
|
|
|
|
|
|
|
|
|
|
message = dbus_message_new_method_call(
|
|
|
|
|
"org.bluez",
|
|
|
|
|
path,
|
|
|
|
|
"org.freedesktop.DBus.Properties",
|
|
|
|
|
"Set"
|
|
|
|
|
);
|
|
|
|
|
if (!message)
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
|
|
dbus_message_iter_init_append(message, &req_iter);
|
2020-06-27 19:46:27 +02:00
|
|
|
|
if (!dbus_message_iter_append_basic(
|
|
|
|
|
&req_iter, DBUS_TYPE_STRING, &arg_adapter))
|
2020-06-24 02:51:42 +03:00
|
|
|
|
goto fault;
|
2020-06-27 19:46:27 +02:00
|
|
|
|
if (!dbus_message_iter_append_basic(
|
|
|
|
|
&req_iter, DBUS_TYPE_STRING, &arg_property))
|
2020-06-24 02:51:42 +03:00
|
|
|
|
goto fault;
|
2020-06-27 19:46:27 +02:00
|
|
|
|
if (!dbus_message_iter_open_container(
|
|
|
|
|
&req_iter, DBUS_TYPE_VARIANT,
|
|
|
|
|
DBUS_TYPE_BOOLEAN_AS_STRING, &req_subiter))
|
2020-06-24 02:51:42 +03:00
|
|
|
|
goto fault;
|
2020-06-27 19:46:27 +02:00
|
|
|
|
if (!dbus_message_iter_append_basic(
|
|
|
|
|
&req_subiter, DBUS_TYPE_BOOLEAN, &value))
|
2020-06-24 02:51:42 +03:00
|
|
|
|
goto fault;
|
2020-06-27 19:46:27 +02:00
|
|
|
|
if (!dbus_message_iter_close_container(
|
|
|
|
|
&req_iter, &req_subiter))
|
2020-06-24 02:51:42 +03:00
|
|
|
|
goto fault;
|
|
|
|
|
|
2020-06-28 22:02:48 +03:00
|
|
|
|
reply = dbus_connection_send_with_reply_and_block(bluez->dbus_connection,
|
2020-06-24 02:51:42 +03:00
|
|
|
|
message, 1000, &err);
|
|
|
|
|
if (!reply)
|
|
|
|
|
goto fault;
|
|
|
|
|
dbus_message_unref(reply);
|
|
|
|
|
dbus_message_unref(message);
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
fault:
|
|
|
|
|
dbus_message_iter_abandon_container_if_open(&req_iter, &req_subiter);
|
|
|
|
|
dbus_message_unref(message);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-27 19:46:27 +02:00
|
|
|
|
static int get_bool_property(
|
2020-06-28 22:02:48 +03:00
|
|
|
|
bluez_t *bluez,
|
2020-06-24 02:51:42 +03:00
|
|
|
|
const char *path,
|
|
|
|
|
const char *arg_adapter,
|
|
|
|
|
const char *arg_property,
|
|
|
|
|
int *value)
|
|
|
|
|
{
|
|
|
|
|
DBusMessage *message, *reply;
|
|
|
|
|
DBusError err;
|
|
|
|
|
DBusMessageIter root_iter, variant_iter;
|
|
|
|
|
|
|
|
|
|
dbus_error_init(&err);
|
|
|
|
|
|
|
|
|
|
message = dbus_message_new_method_call( "org.bluez", path,
|
|
|
|
|
"org.freedesktop.DBus.Properties", "Get");
|
|
|
|
|
if (!message)
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
|
|
if (!dbus_message_append_args(message,
|
|
|
|
|
DBUS_TYPE_STRING, &arg_adapter,
|
|
|
|
|
DBUS_TYPE_STRING, &arg_property,
|
|
|
|
|
DBUS_TYPE_INVALID))
|
|
|
|
|
return 1;
|
|
|
|
|
|
2020-06-28 22:02:48 +03:00
|
|
|
|
reply = dbus_connection_send_with_reply_and_block(bluez->dbus_connection,
|
2020-06-24 02:51:42 +03:00
|
|
|
|
message, 1000, &err);
|
|
|
|
|
|
|
|
|
|
dbus_message_unref(message);
|
|
|
|
|
|
|
|
|
|
if (!reply)
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
|
|
if (!dbus_message_iter_init(reply, &root_iter))
|
|
|
|
|
return 1;
|
2020-06-27 19:46:27 +02:00
|
|
|
|
|
2020-06-24 02:51:42 +03:00
|
|
|
|
if (DBUS_TYPE_VARIANT != dbus_message_iter_get_arg_type(&root_iter))
|
|
|
|
|
return 1;
|
2020-06-27 19:46:27 +02:00
|
|
|
|
|
2020-06-24 02:51:42 +03:00
|
|
|
|
dbus_message_iter_recurse(&root_iter, &variant_iter);
|
|
|
|
|
dbus_message_iter_get_basic(&variant_iter, value);
|
|
|
|
|
|
|
|
|
|
dbus_message_unref(reply);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-28 22:02:48 +03:00
|
|
|
|
static int adapter_discovery (bluez_t *bluez, const char *method)
|
2020-06-24 02:51:42 +03:00
|
|
|
|
{
|
2020-06-27 19:46:27 +02:00
|
|
|
|
DBusMessage *message = dbus_message_new_method_call(
|
2020-06-28 22:02:48 +03:00
|
|
|
|
"org.bluez", bluez->adapter,
|
2020-06-27 19:46:27 +02:00
|
|
|
|
"org.bluez.Adapter1", method);
|
2020-06-24 02:51:42 +03:00
|
|
|
|
if (!message)
|
|
|
|
|
return 1;
|
|
|
|
|
|
2020-06-28 22:02:48 +03:00
|
|
|
|
if (!dbus_connection_send(bluez->dbus_connection, message, NULL))
|
2020-06-24 02:51:42 +03:00
|
|
|
|
return 1;
|
|
|
|
|
|
2020-06-28 22:02:48 +03:00
|
|
|
|
dbus_connection_flush(bluez->dbus_connection);
|
2020-06-24 02:51:42 +03:00
|
|
|
|
dbus_message_unref(message);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-28 22:02:48 +03:00
|
|
|
|
static int get_managed_objects (bluez_t *bluez, DBusMessage **reply)
|
2020-06-24 02:51:42 +03:00
|
|
|
|
{
|
|
|
|
|
DBusMessage *message;
|
|
|
|
|
DBusError err;
|
|
|
|
|
|
|
|
|
|
dbus_error_init(&err);
|
|
|
|
|
|
2020-06-27 19:46:27 +02:00
|
|
|
|
message = dbus_message_new_method_call("org.bluez", "/",
|
|
|
|
|
"org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
|
2020-06-24 02:51:42 +03:00
|
|
|
|
if (!message)
|
|
|
|
|
return 1;
|
|
|
|
|
|
2020-06-28 22:02:48 +03:00
|
|
|
|
*reply = dbus_connection_send_with_reply_and_block(bluez->dbus_connection,
|
2020-06-27 19:46:27 +02:00
|
|
|
|
message, -1, &err);
|
2020-06-24 02:51:42 +03:00
|
|
|
|
/* if (!reply) is done by the caller in this one */
|
|
|
|
|
|
|
|
|
|
dbus_message_unref(message);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-28 22:02:48 +03:00
|
|
|
|
static int device_method (bluez_t *bluez, const char *path, const char *method)
|
2020-06-24 02:51:42 +03:00
|
|
|
|
{
|
|
|
|
|
DBusMessage *message, *reply;
|
|
|
|
|
DBusError err;
|
|
|
|
|
|
|
|
|
|
dbus_error_init(&err);
|
|
|
|
|
|
|
|
|
|
message = dbus_message_new_method_call( "org.bluez", path,
|
2020-06-27 19:46:27 +02:00
|
|
|
|
"org.bluez.Device1", method);
|
2020-06-24 02:51:42 +03:00
|
|
|
|
if (!message)
|
|
|
|
|
return 1;
|
|
|
|
|
|
2020-06-28 22:02:48 +03:00
|
|
|
|
reply = dbus_connection_send_with_reply_and_block(bluez->dbus_connection,
|
2020-06-27 19:46:27 +02:00
|
|
|
|
message, 10000, &err);
|
2020-06-24 02:51:42 +03:00
|
|
|
|
if (!reply)
|
|
|
|
|
return 1;
|
|
|
|
|
|
2020-06-28 22:02:48 +03:00
|
|
|
|
dbus_connection_flush(bluez->dbus_connection);
|
2020-06-24 02:51:42 +03:00
|
|
|
|
dbus_message_unref(message);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-28 22:02:48 +03:00
|
|
|
|
static int get_default_adapter(bluez_t *bluez, DBusMessage *reply)
|
2020-06-24 02:51:42 +03:00
|
|
|
|
{
|
|
|
|
|
/* "...an application would discover the available adapters by
|
|
|
|
|
* performing a ObjectManager.GetManagedObjects call and look for any
|
|
|
|
|
* returned objects with an “org.bluez.Adapter1″ interface.
|
|
|
|
|
* The concept of a default adapter was always a bit fuzzy and the
|
|
|
|
|
* value could’t be changed, so if applications need something like it
|
|
|
|
|
* they could e.g. just pick the first adapter they encounter in the
|
|
|
|
|
* GetManagedObjects reply."
|
|
|
|
|
* -- http://www.bluez.org/bluez-5-api-introduction-and-porting-guide/
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
DBusMessageIter root_iter;
|
|
|
|
|
DBusMessageIter dict_1_iter, dict_2_iter;
|
|
|
|
|
DBusMessageIter array_1_iter, array_2_iter;
|
|
|
|
|
|
|
|
|
|
char *obj_path, *interface_name;
|
|
|
|
|
|
|
|
|
|
/* a{oa{sa{sv}}} */
|
|
|
|
|
if (!dbus_message_iter_init(reply, &root_iter))
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
|
|
/* a */
|
|
|
|
|
if (DBUS_TYPE_ARRAY != dbus_message_iter_get_arg_type(&root_iter))
|
|
|
|
|
return 1;
|
|
|
|
|
dbus_message_iter_recurse(&root_iter, &array_1_iter);
|
2020-06-27 19:46:27 +02:00
|
|
|
|
do
|
|
|
|
|
{
|
2020-06-24 02:51:42 +03:00
|
|
|
|
/* a{...} */
|
|
|
|
|
if (DBUS_TYPE_DICT_ENTRY != dbus_message_iter_get_arg_type(&array_1_iter))
|
|
|
|
|
return 1;
|
|
|
|
|
dbus_message_iter_recurse(&array_1_iter, &dict_1_iter);
|
|
|
|
|
|
|
|
|
|
/* a{o...} */
|
|
|
|
|
if (DBUS_TYPE_OBJECT_PATH != dbus_message_iter_get_arg_type(&dict_1_iter))
|
|
|
|
|
return 1;
|
|
|
|
|
dbus_message_iter_get_basic(&dict_1_iter, &obj_path);
|
|
|
|
|
|
|
|
|
|
if (!dbus_message_iter_next(&dict_1_iter))
|
|
|
|
|
return 1;
|
|
|
|
|
/* a{oa} */
|
|
|
|
|
if (DBUS_TYPE_ARRAY != dbus_message_iter_get_arg_type(&dict_1_iter))
|
|
|
|
|
return 1;
|
|
|
|
|
dbus_message_iter_recurse(&dict_1_iter, &array_2_iter);
|
2020-06-27 19:46:27 +02:00
|
|
|
|
do
|
|
|
|
|
{
|
2020-06-24 02:51:42 +03:00
|
|
|
|
/* empty array? */
|
2020-06-27 19:46:27 +02:00
|
|
|
|
if (DBUS_TYPE_INVALID ==
|
|
|
|
|
dbus_message_iter_get_arg_type(&array_2_iter))
|
2020-06-24 02:51:42 +03:00
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
/* a{oa{...}} */
|
2020-06-27 19:46:27 +02:00
|
|
|
|
if (DBUS_TYPE_DICT_ENTRY !=
|
|
|
|
|
dbus_message_iter_get_arg_type(&array_2_iter))
|
2020-06-24 02:51:42 +03:00
|
|
|
|
return 1;
|
|
|
|
|
dbus_message_iter_recurse(&array_2_iter, &dict_2_iter);
|
|
|
|
|
|
|
|
|
|
/* a{oa{s...}} */
|
2020-06-27 19:46:27 +02:00
|
|
|
|
if (DBUS_TYPE_STRING !=
|
|
|
|
|
dbus_message_iter_get_arg_type(&dict_2_iter))
|
2020-06-24 02:51:42 +03:00
|
|
|
|
return 1;
|
|
|
|
|
dbus_message_iter_get_basic(&dict_2_iter, &interface_name);
|
2020-06-27 19:46:27 +02:00
|
|
|
|
|
|
|
|
|
if (string_is_equal(interface_name, "org.bluez.Adapter1"))
|
|
|
|
|
{
|
2020-06-28 22:02:48 +03:00
|
|
|
|
strlcpy(bluez->adapter, obj_path, 256);
|
2020-06-24 02:51:42 +03:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
} while (dbus_message_iter_next(&array_2_iter));
|
|
|
|
|
} while (dbus_message_iter_next(&array_1_iter));
|
|
|
|
|
|
|
|
|
|
/* Couldn't find an adapter */
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-28 22:02:48 +03:00
|
|
|
|
static int read_scanned_devices (bluez_t *bluez, DBusMessage *reply)
|
2020-06-24 02:51:42 +03:00
|
|
|
|
{
|
2020-06-27 19:46:27 +02:00
|
|
|
|
device_info_t device;
|
2020-06-24 02:51:42 +03:00
|
|
|
|
DBusMessageIter root_iter;
|
|
|
|
|
DBusMessageIter dict_1_iter, dict_2_iter, dict_3_iter;
|
|
|
|
|
DBusMessageIter array_1_iter, array_2_iter, array_3_iter;
|
|
|
|
|
DBusMessageIter variant_iter;
|
|
|
|
|
char *obj_path, *interface_name, *interface_property_name;
|
|
|
|
|
char *found_device_address, *found_device_name, *found_device_icon;
|
|
|
|
|
|
|
|
|
|
/* a{oa{sa{sv}}} */
|
|
|
|
|
if (!dbus_message_iter_init(reply, &root_iter))
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
|
|
/* a */
|
|
|
|
|
if (DBUS_TYPE_ARRAY != dbus_message_iter_get_arg_type(&root_iter))
|
|
|
|
|
return 1;
|
2020-06-27 19:46:27 +02:00
|
|
|
|
|
2020-06-24 02:51:42 +03:00
|
|
|
|
dbus_message_iter_recurse(&root_iter, &array_1_iter);
|
2020-06-27 19:46:27 +02:00
|
|
|
|
|
|
|
|
|
do
|
|
|
|
|
{
|
2020-06-24 02:51:42 +03:00
|
|
|
|
/* a{...} */
|
2020-06-27 19:46:27 +02:00
|
|
|
|
if (DBUS_TYPE_DICT_ENTRY !=
|
|
|
|
|
dbus_message_iter_get_arg_type(&array_1_iter))
|
2020-06-24 02:51:42 +03:00
|
|
|
|
return 1;
|
2020-06-27 19:46:27 +02:00
|
|
|
|
|
2020-06-24 02:51:42 +03:00
|
|
|
|
dbus_message_iter_recurse(&array_1_iter, &dict_1_iter);
|
|
|
|
|
|
|
|
|
|
/* a{o...} */
|
2020-06-27 19:46:27 +02:00
|
|
|
|
if (DBUS_TYPE_OBJECT_PATH !=
|
|
|
|
|
dbus_message_iter_get_arg_type(&dict_1_iter))
|
2020-06-24 02:51:42 +03:00
|
|
|
|
return 1;
|
2020-06-27 19:46:27 +02:00
|
|
|
|
|
2020-06-24 02:51:42 +03:00
|
|
|
|
dbus_message_iter_get_basic(&dict_1_iter, &obj_path);
|
|
|
|
|
|
|
|
|
|
if (!dbus_message_iter_next(&dict_1_iter))
|
|
|
|
|
return 1;
|
2020-06-27 19:46:27 +02:00
|
|
|
|
|
2020-06-24 02:51:42 +03:00
|
|
|
|
/* a{oa} */
|
2020-06-27 19:46:27 +02:00
|
|
|
|
if (DBUS_TYPE_ARRAY !=
|
|
|
|
|
dbus_message_iter_get_arg_type(&dict_1_iter))
|
2020-06-24 02:51:42 +03:00
|
|
|
|
return 1;
|
2020-06-27 19:46:27 +02:00
|
|
|
|
|
2020-06-24 02:51:42 +03:00
|
|
|
|
dbus_message_iter_recurse(&dict_1_iter, &array_2_iter);
|
2020-06-27 19:46:27 +02:00
|
|
|
|
do
|
|
|
|
|
{
|
2020-06-24 02:51:42 +03:00
|
|
|
|
/* empty array? */
|
2020-06-27 19:46:27 +02:00
|
|
|
|
if (DBUS_TYPE_INVALID ==
|
|
|
|
|
dbus_message_iter_get_arg_type(&array_2_iter))
|
2020-06-24 02:51:42 +03:00
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
/* a{oa{...}} */
|
2020-06-27 19:46:27 +02:00
|
|
|
|
if (DBUS_TYPE_DICT_ENTRY !=
|
|
|
|
|
dbus_message_iter_get_arg_type(&array_2_iter))
|
2020-06-24 02:51:42 +03:00
|
|
|
|
return 1;
|
|
|
|
|
dbus_message_iter_recurse(&array_2_iter, &dict_2_iter);
|
|
|
|
|
|
|
|
|
|
/* a{oa{s...}} */
|
2020-06-27 19:46:27 +02:00
|
|
|
|
if (DBUS_TYPE_STRING !=
|
|
|
|
|
dbus_message_iter_get_arg_type(&dict_2_iter))
|
2020-06-24 02:51:42 +03:00
|
|
|
|
return 1;
|
|
|
|
|
dbus_message_iter_get_basic(&dict_2_iter, &interface_name);
|
2020-06-27 19:46:27 +02:00
|
|
|
|
|
|
|
|
|
if (!string_is_equal(interface_name, "org.bluez.Device1"))
|
2020-06-24 02:51:42 +03:00
|
|
|
|
continue;
|
2020-06-27 19:46:27 +02:00
|
|
|
|
|
2020-06-24 02:51:42 +03:00
|
|
|
|
memset(&device, 0, sizeof(device));
|
|
|
|
|
strlcpy(device.path, obj_path, 128);
|
|
|
|
|
|
|
|
|
|
if (!dbus_message_iter_next(&dict_2_iter))
|
|
|
|
|
return 1;
|
2020-06-27 19:46:27 +02:00
|
|
|
|
|
2020-06-24 02:51:42 +03:00
|
|
|
|
/* a{oa{sa}} */
|
|
|
|
|
if (DBUS_TYPE_ARRAY != dbus_message_iter_get_arg_type(&dict_2_iter))
|
|
|
|
|
return 1;
|
2020-06-27 19:46:27 +02:00
|
|
|
|
|
2020-06-24 02:51:42 +03:00
|
|
|
|
dbus_message_iter_recurse(&dict_2_iter, &array_3_iter);
|
|
|
|
|
|
|
|
|
|
do {
|
|
|
|
|
/* empty array? */
|
2020-06-27 19:46:27 +02:00
|
|
|
|
if (DBUS_TYPE_INVALID ==
|
|
|
|
|
dbus_message_iter_get_arg_type(&array_3_iter))
|
2020-06-24 02:51:42 +03:00
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
/* a{oa{sa{...}}} */
|
2020-06-27 19:46:27 +02:00
|
|
|
|
if (DBUS_TYPE_DICT_ENTRY !=
|
|
|
|
|
dbus_message_iter_get_arg_type(&array_3_iter))
|
2020-06-24 02:51:42 +03:00
|
|
|
|
return 1;
|
|
|
|
|
dbus_message_iter_recurse(&array_3_iter, &dict_3_iter);
|
|
|
|
|
|
|
|
|
|
/* a{oa{sa{s...}}} */
|
2020-06-27 19:46:27 +02:00
|
|
|
|
if (DBUS_TYPE_STRING !=
|
|
|
|
|
dbus_message_iter_get_arg_type(&dict_3_iter))
|
2020-06-24 02:51:42 +03:00
|
|
|
|
return 1;
|
2020-06-27 19:46:27 +02:00
|
|
|
|
|
|
|
|
|
dbus_message_iter_get_basic(&dict_3_iter,
|
|
|
|
|
&interface_property_name);
|
2020-06-24 02:51:42 +03:00
|
|
|
|
|
|
|
|
|
if (!dbus_message_iter_next(&dict_3_iter))
|
|
|
|
|
return 1;
|
|
|
|
|
/* a{oa{sa{sv}}} */
|
2020-06-27 19:46:27 +02:00
|
|
|
|
if (DBUS_TYPE_VARIANT !=
|
|
|
|
|
dbus_message_iter_get_arg_type(&dict_3_iter))
|
2020-06-24 02:51:42 +03:00
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
|
|
/* Below, "Alias" property is used instead of "Name".
|
|
|
|
|
* "This value ("Name") is only present for
|
|
|
|
|
* completeness. It is better to always use
|
|
|
|
|
* the Alias property when displaying the
|
|
|
|
|
* devices name."
|
|
|
|
|
* -- bluez/doc/device-api.txt
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/* DBUS_TYPE_VARIANT is a container type */
|
|
|
|
|
dbus_message_iter_recurse(&dict_3_iter, &variant_iter);
|
2020-06-27 19:46:27 +02:00
|
|
|
|
if (string_is_equal(interface_property_name, "Address"))
|
|
|
|
|
{
|
|
|
|
|
dbus_message_iter_get_basic(&variant_iter,
|
|
|
|
|
&found_device_address);
|
2020-06-24 02:51:42 +03:00
|
|
|
|
strlcpy(device.address, found_device_address, 18);
|
2020-06-27 19:46:27 +02:00
|
|
|
|
}
|
|
|
|
|
else if (string_is_equal(interface_property_name, "Alias"))
|
|
|
|
|
{
|
|
|
|
|
dbus_message_iter_get_basic(&variant_iter,
|
|
|
|
|
&found_device_name);
|
2020-06-24 02:51:42 +03:00
|
|
|
|
strlcpy(device.name, found_device_name, 64);
|
2020-06-27 19:46:27 +02:00
|
|
|
|
}
|
|
|
|
|
else if (string_is_equal(interface_property_name, "Icon"))
|
|
|
|
|
{
|
|
|
|
|
dbus_message_iter_get_basic(&variant_iter,
|
|
|
|
|
&found_device_icon);
|
2020-06-24 02:51:42 +03:00
|
|
|
|
strlcpy(device.icon, found_device_icon, 64);
|
2020-06-27 19:46:27 +02:00
|
|
|
|
}
|
|
|
|
|
else if (string_is_equal(interface_property_name, "Connected"))
|
|
|
|
|
{
|
|
|
|
|
dbus_message_iter_get_basic(&variant_iter,
|
|
|
|
|
&device.connected);
|
|
|
|
|
}
|
|
|
|
|
else if (string_is_equal(interface_property_name, "Paired"))
|
|
|
|
|
{
|
|
|
|
|
dbus_message_iter_get_basic(&variant_iter,
|
|
|
|
|
&device.paired);
|
|
|
|
|
}
|
|
|
|
|
else if (string_is_equal(interface_property_name, "Trusted"))
|
|
|
|
|
{
|
|
|
|
|
dbus_message_iter_get_basic(&variant_iter,
|
|
|
|
|
&device.trusted);
|
2020-06-24 02:51:42 +03:00
|
|
|
|
}
|
|
|
|
|
} while (dbus_message_iter_next(&array_3_iter));
|
2020-06-27 19:46:27 +02:00
|
|
|
|
|
2020-06-28 22:02:48 +03:00
|
|
|
|
if (!device_info_vector_list_append(bluez->devices, device))
|
2020-06-24 02:51:42 +03:00
|
|
|
|
return 1;
|
2020-06-27 19:46:27 +02:00
|
|
|
|
|
2020-06-24 02:51:42 +03:00
|
|
|
|
} while (dbus_message_iter_next(&array_2_iter));
|
|
|
|
|
} while (dbus_message_iter_next(&array_1_iter));
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-29 00:25:37 +02:00
|
|
|
|
static void bluez_dbus_connect(bluez_t *bluez)
|
2020-06-24 02:51:42 +03:00
|
|
|
|
{
|
|
|
|
|
DBusError err;
|
|
|
|
|
dbus_error_init(&err);
|
2020-06-28 22:02:48 +03:00
|
|
|
|
bluez->dbus_connection = dbus_bus_get_private(DBUS_BUS_SYSTEM, &err);
|
2020-06-24 02:51:42 +03:00
|
|
|
|
}
|
|
|
|
|
|
2020-06-29 00:25:37 +02:00
|
|
|
|
static void bluez_dbus_disconnect(bluez_t *bluez)
|
2020-06-24 02:51:42 +03:00
|
|
|
|
{
|
2020-06-28 22:02:48 +03:00
|
|
|
|
if (!bluez->dbus_connection)
|
2020-06-24 02:51:42 +03:00
|
|
|
|
return;
|
|
|
|
|
|
2020-06-28 22:02:48 +03:00
|
|
|
|
dbus_connection_close(bluez->dbus_connection);
|
|
|
|
|
dbus_connection_unref(bluez->dbus_connection);
|
|
|
|
|
bluez->dbus_connection = NULL;
|
2020-06-24 02:51:42 +03:00
|
|
|
|
}
|
|
|
|
|
|
2020-06-29 00:25:37 +02:00
|
|
|
|
static void bluez_scan(void *data)
|
2020-06-24 02:51:42 +03:00
|
|
|
|
{
|
|
|
|
|
DBusError err;
|
|
|
|
|
DBusMessage *reply;
|
2020-06-29 00:25:37 +02:00
|
|
|
|
bluez_t *bluez = (bluez_t*)data;
|
2020-06-24 02:51:42 +03:00
|
|
|
|
|
2020-06-28 22:02:48 +03:00
|
|
|
|
bluez_dbus_connect(bluez);
|
2020-06-24 02:51:42 +03:00
|
|
|
|
|
2020-06-28 22:02:48 +03:00
|
|
|
|
if (get_managed_objects(bluez, &reply))
|
2020-06-24 02:51:42 +03:00
|
|
|
|
return;
|
|
|
|
|
if (!reply)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
/* Get default adapter */
|
2020-06-28 22:02:48 +03:00
|
|
|
|
if (get_default_adapter(bluez, reply))
|
2020-06-24 02:51:42 +03:00
|
|
|
|
return;
|
|
|
|
|
dbus_message_unref(reply);
|
|
|
|
|
|
|
|
|
|
/* Power device on */
|
2020-06-29 00:25:37 +02:00
|
|
|
|
if (set_bool_property(bluez, bluez->adapter,
|
|
|
|
|
"org.bluez.Adapter1", "Powered", 1))
|
2020-06-24 02:51:42 +03:00
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
/* Start discovery */
|
2020-06-28 22:02:48 +03:00
|
|
|
|
if (adapter_discovery(bluez, "StartDiscovery"))
|
2020-06-24 02:51:42 +03:00
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
retro_sleep(10000);
|
|
|
|
|
|
|
|
|
|
/* Stop discovery */
|
2020-06-28 22:02:48 +03:00
|
|
|
|
if (adapter_discovery(bluez, "StopDiscovery"))
|
2020-06-24 02:51:42 +03:00
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
/* Get scanned devices */
|
2020-06-28 22:02:48 +03:00
|
|
|
|
if (get_managed_objects(bluez, &reply))
|
2020-06-24 02:51:42 +03:00
|
|
|
|
return;
|
|
|
|
|
if (!reply)
|
|
|
|
|
return;
|
|
|
|
|
|
2020-06-28 22:02:48 +03:00
|
|
|
|
if (bluez->devices)
|
|
|
|
|
device_info_vector_list_free(bluez->devices);
|
|
|
|
|
bluez->devices = device_info_vector_list_new();
|
2020-06-24 02:51:42 +03:00
|
|
|
|
|
2020-06-28 22:02:48 +03:00
|
|
|
|
read_scanned_devices(bluez, reply);
|
2020-06-24 02:51:42 +03:00
|
|
|
|
dbus_message_unref(reply);
|
2020-06-28 22:02:48 +03:00
|
|
|
|
bluez_dbus_disconnect(bluez);
|
2020-06-24 02:51:42 +03:00
|
|
|
|
}
|
|
|
|
|
|
2020-06-29 00:25:37 +02:00
|
|
|
|
static void bluez_get_devices(void *data,
|
|
|
|
|
struct string_list* devices_string_list)
|
2020-06-24 02:51:42 +03:00
|
|
|
|
{
|
|
|
|
|
unsigned i;
|
|
|
|
|
union string_list_elem_attr attr;
|
2020-06-29 00:25:37 +02:00
|
|
|
|
bluez_t *bluez = (bluez_t*)data;
|
|
|
|
|
|
2020-06-24 02:51:42 +03:00
|
|
|
|
attr.i = 0;
|
|
|
|
|
|
2020-06-28 22:02:48 +03:00
|
|
|
|
if (!bluez->devices)
|
2020-06-24 02:51:42 +03:00
|
|
|
|
return;
|
|
|
|
|
|
2020-06-28 22:02:48 +03:00
|
|
|
|
for (i = 0; i < bluez->devices->count; i++)
|
2020-06-24 02:51:42 +03:00
|
|
|
|
{
|
|
|
|
|
char device[64];
|
2020-06-28 22:02:48 +03:00
|
|
|
|
strlcpy(device, bluez->devices->data[i].name, sizeof(device));
|
2020-06-24 02:51:42 +03:00
|
|
|
|
string_list_append(devices_string_list, device, attr);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-29 00:25:37 +02:00
|
|
|
|
static bool bluez_device_is_connected(void *data, unsigned i)
|
2020-06-24 02:51:42 +03:00
|
|
|
|
{
|
|
|
|
|
int value;
|
2020-06-29 00:25:37 +02:00
|
|
|
|
bluez_t *bluez = (bluez_t*)data;
|
2020-06-24 02:51:42 +03:00
|
|
|
|
|
2020-06-28 22:02:48 +03:00
|
|
|
|
if (bluez->bluez_cache_counter[i] == 60)
|
2020-06-27 19:46:27 +02:00
|
|
|
|
{
|
2020-06-28 22:02:48 +03:00
|
|
|
|
bluez->bluez_cache_counter[i] = 0;
|
|
|
|
|
bluez_dbus_connect(bluez);
|
2020-06-29 00:25:37 +02:00
|
|
|
|
|
|
|
|
|
/* Device disappeared */
|
2020-06-28 22:02:48 +03:00
|
|
|
|
if (get_bool_property(bluez, bluez->devices->data[i].path,
|
|
|
|
|
"org.bluez.Device1", "Connected", &value))
|
|
|
|
|
value = false;
|
2020-06-29 00:25:37 +02:00
|
|
|
|
|
2020-06-28 22:02:48 +03:00
|
|
|
|
bluez_dbus_disconnect(bluez);
|
2020-06-24 02:51:42 +03:00
|
|
|
|
|
2020-06-28 22:02:48 +03:00
|
|
|
|
bluez->bluez_cache[i] = value;
|
2020-06-24 02:51:42 +03:00
|
|
|
|
return value;
|
|
|
|
|
}
|
2020-06-27 19:46:27 +02:00
|
|
|
|
|
2020-06-28 22:02:48 +03:00
|
|
|
|
bluez->bluez_cache_counter[i]++;
|
|
|
|
|
return bluez->bluez_cache[i];
|
2020-06-24 02:51:42 +03:00
|
|
|
|
}
|
|
|
|
|
|
2020-06-29 00:25:37 +02:00
|
|
|
|
static void bluez_device_get_sublabel(
|
|
|
|
|
void *data, char *s, unsigned i, size_t len)
|
2020-06-24 12:53:08 +03:00
|
|
|
|
{
|
2020-06-28 22:02:48 +03:00
|
|
|
|
bluez_t *bluez = (bluez_t*)data;
|
|
|
|
|
strlcpy(s, bluez->devices->data[i].address, len);
|
2020-06-24 12:53:08 +03:00
|
|
|
|
}
|
|
|
|
|
|
2020-06-28 22:02:48 +03:00
|
|
|
|
static bool bluez_connect_device(void *data, unsigned i)
|
2020-06-24 02:51:42 +03:00
|
|
|
|
{
|
2020-06-28 22:02:48 +03:00
|
|
|
|
bluez_t *bluez = (bluez_t*)data;
|
|
|
|
|
bluez_dbus_connect(bluez);
|
2020-06-24 02:51:42 +03:00
|
|
|
|
|
|
|
|
|
/* Trust the device */
|
2020-06-28 22:02:48 +03:00
|
|
|
|
if (set_bool_property(bluez, bluez->devices->data[i].path,
|
2020-06-27 19:46:27 +02:00
|
|
|
|
"org.bluez.Device1", "Trusted", 1))
|
2020-06-24 02:51:42 +03:00
|
|
|
|
return false;
|
2020-06-29 00:25:37 +02:00
|
|
|
|
|
2020-06-24 02:51:42 +03:00
|
|
|
|
/* Pair the device */
|
2020-06-28 22:02:48 +03:00
|
|
|
|
device_method(bluez, bluez->devices->data[i].path, "Pair");
|
2020-06-29 00:25:37 +02:00
|
|
|
|
|
2020-06-28 22:02:48 +03:00
|
|
|
|
/* Can be "Already Exists" */
|
2020-06-24 02:51:42 +03:00
|
|
|
|
/* Connect the device */
|
2020-06-28 22:02:48 +03:00
|
|
|
|
if (device_method(bluez, bluez->devices->data[i].path, "Connect"))
|
2020-06-24 02:51:42 +03:00
|
|
|
|
return false;
|
|
|
|
|
|
2020-06-28 22:02:48 +03:00
|
|
|
|
bluez_dbus_disconnect(bluez);
|
|
|
|
|
bluez->bluez_cache_counter[i] = 0;
|
2020-06-24 02:51:42 +03:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-17 21:25:06 +01:00
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-24 02:51:42 +03:00
|
|
|
|
bluetooth_driver_t bluetooth_bluez = {
|
|
|
|
|
bluez_init,
|
|
|
|
|
bluez_free,
|
|
|
|
|
bluez_scan,
|
|
|
|
|
bluez_get_devices,
|
|
|
|
|
bluez_device_is_connected,
|
2020-06-24 12:53:08 +03:00
|
|
|
|
bluez_device_get_sublabel,
|
2020-06-24 02:51:42 +03:00
|
|
|
|
bluez_connect_device,
|
2021-11-17 21:25:06 +01:00
|
|
|
|
bluez_remove_device,
|
2020-06-24 02:51:42 +03:00
|
|
|
|
"bluez",
|
|
|
|
|
};
|