#define RFCOMM_DEFAULT_PROFILE_CHANNEL 0
#define BT_AUDIO_SOURCE_MAX 2
-static char *avrcp_control_path = NULL;
-static char *avrcp_transport_path = NULL;
-
static GDBusConnection *system_conn;
static GDBusConnection *session_conn;
static GDBusProxy *manager_gproxy = NULL;
bt_bdaddr_t bd_addr;
};
-struct avrcp_proxy proxy_array[BT_AUDIO_SOURCE_MAX];
+static struct avrcp_proxy proxy_array[BT_AUDIO_SOURCE_MAX];
static guint bus_id;
-GDBusNodeInfo *new_conn_node;
+static GDBusNodeInfo *new_conn_node;
static const gchar rfcomm_agent_xml[] =
"<node name='/'>"
" <interface name='org.bluez.Profile1'>"
" </interface>"
"</node>";
+static GDBusNodeInfo *new_l2cap_le_conn_node;
+static const gchar l2cap_le_agent_xml[] =
+"<node name='/'>"
+" <interface name='org.bluez.l2cap_le'>"
+" <method name='NewConnection'>"
+" <arg type='o' name='object' direction='in'/>"
+" <arg type='h' name='fd' direction='in'/>"
+" </method>"
+" </interface>"
+"</node>";
+
static GDBusConnection *__bt_hal_init_session_conn(void)
{
if (session_conn == NULL)
{
char *object_path = NULL;
char *interface_str = NULL;
+ GVariantIter *interface_iter;
char device_address[BT_HAL_ADDRESS_STRING_SIZE] = { 0 };
/* Parse the signature: oa{sa{sv}}} */
- while (g_variant_iter_loop(iter, "{&oa{sa{sv}}}", &object_path, &interface_str)) {
+ while (g_variant_iter_loop(iter, "{&oa{sa{sv}}}", &object_path, &interface_iter)) {
if (object_path == NULL)
- return NULL;
+ continue;
- if (g_strcmp0(interface_str, BT_HAL_PLAYER_CONTROL_INTERFACE) == 0) {
- _bt_hal_convert_device_path_to_address(object_path, device_address);
- if (g_strcmp0(address, device_address) == 0)
- return g_strdup(object_path);
+ while(g_variant_iter_loop(interface_iter, "{&sa{sv}}", &interface_str, NULL)) {
+ if (g_strcmp0(interface_str, BT_HAL_PLAYER_CONTROL_INTERFACE) == 0) {
+ _bt_hal_convert_device_path_to_address(object_path, device_address);
+ if (g_strcmp0(address, device_address) == 0) {
+ DBG("Object Path: %s", object_path);
+ g_variant_iter_free(interface_iter);
+ return g_strdup(object_path);
+ }
+ }
}
}
return NULL;
{
char *object_path = NULL;
char *interface_str = NULL;
+ GVariantIter *interface_iter;
char device_address[BT_HAL_ADDRESS_STRING_SIZE] = { 0 };
/* Parse the signature: oa{sa{sv}}} */
- while (g_variant_iter_loop(iter, "{&oa{sa{sv}}}", &object_path, &interface_str)) {
+ while (g_variant_iter_loop(iter, "{&oa{sa{sv}}}", &object_path, &interface_iter)) {
if (object_path == NULL)
- return NULL;
+ continue;
- if (g_strcmp0(interface_str, BT_HAL_MEDIATRANSPORT_INTERFACE) == 0) {
- _bt_hal_convert_device_path_to_address(object_path, device_address);
- if (g_strcmp0(address, device_address) == 0)
- return g_strdup(object_path);
+ while(g_variant_iter_loop(interface_iter, "{&sa{sv}}", &interface_str, NULL)) {
+ if (g_strcmp0(interface_str, BT_HAL_MEDIATRANSPORT_INTERFACE) == 0) {
+ _bt_hal_convert_device_path_to_address(object_path, device_address);
+ if (g_strcmp0(address, device_address) == 0) {
+ DBG("Object Path: %s", object_path);
+ g_variant_iter_free(interface_iter);
+ return g_strdup(object_path);
+ }
+ }
}
}
return NULL;
char *control_path;
char connected_address[BT_HAL_ADDRESS_STRING_SIZE];
- if (avrcp_control_path != NULL)
- return avrcp_control_path;
+ /* We can add the cache to get transport path for each device */
_bt_hal_convert_addr_type_to_string(connected_address, bd_addr->address);
if (control_path == NULL)
return NULL;
- avrcp_control_path = control_path;
DBG("control_path = %s", control_path);
return control_path;
}
char *transport_path;
char connected_address[BT_HAL_ADDRESS_STRING_SIZE];
- if (avrcp_transport_path != NULL)
- return avrcp_transport_path;
+ /* We can add the cache to get transport path for each device */
_bt_hal_convert_addr_type_to_string(connected_address, bd_addr->address);
if (transport_path == NULL)
return NULL;
- avrcp_transport_path = transport_path;
DBG("transport_path = %s", transport_path);
return transport_path;
}
}
}
-int _bt_hal_convert_disc_reason_to_status(int reason)
-{
- switch (reason) {
- case 1:
- return BT_STATUS_CONN_TOUT; //"Link loss"
- case 2:
- return BT_STATUS_CONN_TERM_LOCAL_HOST; //"Connection terminated by local host";
- case 3:
- return BT_STATUS_CONN_TERM_RMT_HOST; //"Connection terminated by local host";
- case 0:
- default:
- return BT_STATUS_FAIL;
- }
-}
-
void _bt_hal_logging_connection(gboolean connect, int addr_type)
{
static int le_conn = 0;
GDBusConnection *conn;
GDBusProxy *adapter_proxy;
GError *error = NULL;
+ GVariant *result;
conn = _bt_hal_get_system_gconn();
if (conn == NULL)
if (adapter_proxy == NULL)
return BT_HAL_ERROR_INTERNAL;
- g_dbus_proxy_call_sync(adapter_proxy, "CreateDevice",
+ result = g_dbus_proxy_call_sync(adapter_proxy, "CreateDevice",
g_variant_new("(s)", address),
G_DBUS_CALL_FLAGS_NONE,
-1,
NULL,
&error);
-
- if (error != NULL) {
- ERR("CreateDevice Fail: %s", error->message);
- g_error_free(error);
+ if (!result) {
+ if (error) {
+ ERR("CreateDevice Fail: %s", error->message);
+ g_error_free(error);
+ }
+ } else {
+ g_variant_unref(result);
}
object_path = _bt_hal_get_device_object_path(address);
}
}
+int _bt_hal_connect_l2cap_le(char *address,
+ bt_hal_l2cap_le_profile_info_t *info, void *cb, gpointer func_data)
+{
+ GVariantBuilder *option_builder;
+ char *object_path;
+ GDBusProxy *proxy;
+ GDBusConnection *conn;
+ GDBusProxy *adapter_proxy;
+ GError *error = NULL;
+ GVariant *result;
+
+ DBG("+");
+ conn = _bt_hal_get_system_gconn();
+ if (conn == NULL)
+ return BT_HAL_ERROR_INTERNAL;
+
+ object_path = _bt_hal_get_device_object_path(address);
+ if (object_path == NULL) {
+ ERR("No searched device");
+
+ adapter_proxy = _bt_hal_get_adapter_proxy();
+ if (adapter_proxy == NULL)
+ return BT_HAL_ERROR_INTERNAL;
+
+ result = g_dbus_proxy_call_sync(adapter_proxy, "CreateDevice",
+ g_variant_new("(s)", address), G_DBUS_CALL_FLAGS_NONE,
+ -1, NULL, &error);
+
+ if (!result) {
+ if (error) {
+ ERR("CreateDevice Fail: %s", error->message);
+ g_error_free(error);
+ }
+ } else
+ g_variant_unref(result);
+
+ object_path = _bt_hal_get_device_object_path(address);
+ }
+
+ if (object_path == NULL) {
+ INFO("Not able to find device object");
+ return BT_HAL_ERROR_INTERNAL;
+ }
+
+ proxy = g_dbus_proxy_new_sync(conn, G_DBUS_PROXY_FLAGS_NONE,
+ NULL, BT_HAL_BLUEZ_NAME,
+ object_path, BT_HAL_DEVICE_INTERFACE, NULL, NULL);
+ g_free(object_path);
+
+ if (proxy == NULL) {
+ INFO("proxy is null");
+ return BT_HAL_ERROR_INTERNAL;
+ }
+
+ option_builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
+ if (info->authentication)
+ g_variant_builder_add(option_builder, "{sv}",
+ "RequireAuthentication",
+ g_variant_new_boolean(TRUE));
+
+ if (info->authorization)
+ g_variant_builder_add(option_builder, "{sv}",
+ "RequireAuthorization",
+ g_variant_new_boolean(TRUE));
+
+ g_dbus_proxy_call(proxy, "ConnectL2capLESocket",
+ g_variant_new("(oia{sv})", info->obj_path,
+ info->psm, option_builder),
+ G_DBUS_CALL_FLAGS_NONE, BT_HAL_MAX_DBUS_TIMEOUT, NULL,
+ (GAsyncReadyCallback)cb, func_data);
+
+ g_variant_builder_unref(option_builder);
+
+ DBG("-");
+ return BT_HAL_ERROR_NONE;
+}
+
+int _bt_hal_listen_l2cap_le(bt_hal_l2cap_le_profile_info_t *info)
+{
+ GVariantBuilder *option_builder;
+ GVariant *ret;
+ GDBusProxy *proxy;
+ GError *err = NULL;
+ int result = BT_STATUS_SUCCESS;
+
+ DBG("+");
+ proxy = _bt_hal_get_adapter_proxy();
+ if (proxy == NULL) {
+ ERR("Getting adapter profile proxy failed");
+ return BT_STATUS_FAIL;
+ }
+
+ option_builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
+ if (info->authentication)
+ g_variant_builder_add(option_builder, "{sv}",
+ "RequireAuthentication",
+ g_variant_new_boolean(TRUE));
+
+ if (info->authorization)
+ g_variant_builder_add(option_builder, "{sv}",
+ "RequireAuthorization",
+ g_variant_new_boolean(TRUE));
+
+ ret = g_dbus_proxy_call_sync(proxy, "ListenL2capLESocket",
+ g_variant_new("(oia{sv})", info->obj_path, info->psm,
+ option_builder),
+ G_DBUS_CALL_FLAGS_NONE, -1, NULL, &err);
+
+ if (err) {
+ ERR("Listen L2cap_LE failed: %s", err->message);
+
+ if (g_strrstr(err->message, BT_HAL_ACCESS_DENIED_MSG))
+ result = BT_STATUS_AUTH_REJECTED;
+ else
+ result = BT_STATUS_FAIL;
+
+ g_clear_error(&err);
+ }
+
+ g_variant_builder_unref(option_builder);
+
+ if (ret)
+ g_variant_unref(ret);
+
+ DBG("-");
+ return result;
+}
+
+void _bt_hal_remove_l2cap_le_socket(char *path)
+{
+ GVariant *ret;
+ GDBusProxy *proxy;
+ GError *err = NULL;
+
+ proxy = _bt_hal_get_adapter_proxy();
+ if (proxy == NULL) {
+ ERR("Getting adapter profile proxy failed");
+ return;
+ }
+
+ ret = g_dbus_proxy_call_sync(proxy, "RemoveL2capLESocket",
+ g_variant_new("(o)", path),
+ G_DBUS_CALL_FLAGS_NONE, -1,
+ NULL, &err);
+ if (err) {
+ ERR("Remove socket l2cap le failed : %s", err->message);
+ g_clear_error(&err);
+ }
+
+ if (ret)
+ g_variant_unref(ret);
+
+ return;
+}
+
+int _bt_hal_get_psm_l2cap_le(bt_hal_l2cap_le_profile_info_t *info, uint32_t *psm)
+{
+ GVariant *ret;
+ GDBusProxy *proxy;
+ GError *err = NULL;
+ int result = BT_STATUS_SUCCESS;
+
+ proxy = _bt_hal_get_adapter_proxy();
+ if (proxy == NULL) {
+ ERR("Getting adapter profile proxy failed");
+ return BT_STATUS_FAIL;
+ }
+
+ ret = g_dbus_proxy_call_sync(proxy, "GetPSML2capLE",
+ g_variant_new("(o)", info->obj_path),
+ G_DBUS_CALL_FLAGS_NONE, -1,
+ NULL, &err);
+ if (err) {
+ ERR("Get PSM L2cap_LE failed: %s", err->message);
+ result = BT_STATUS_FAIL;
+ g_clear_error(&err);
+ return result;
+ }
+
+ g_variant_get(ret, "(u)", psm);
+ INFO("PSM: %d", *psm);
+
+ if (ret)
+ g_variant_unref(ret);
+
+ return result;
+}
+
+static void __hal_l2cap_le_new_connection_method(GDBusConnection *connection,
+ const gchar *sender,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *method_name,
+ GVariant *parameters,
+ GDBusMethodInvocation *invocation,
+ gpointer user_data)
+{
+ INFO("method %s", method_name);
+ if (g_strcmp0(method_name, "NewConnection") == 0) {
+ INFO("L2cap_LE New connection method");
+ int index;
+ int fd;
+ GUnixFDList *fd_list;
+ GDBusMessage *msg;
+ char *obj_path;
+ bt_bdaddr_t remote_addr1;
+ char addr[BT_HAL_ADDRESS_STRING_SIZE];
+ bt_hal_new_connection_cb cb = user_data;
+
+ g_variant_get(parameters, "(oh)", &obj_path, &index);
+
+ msg = g_dbus_method_invocation_get_message(invocation);
+ fd_list = g_dbus_message_get_unix_fd_list(msg);
+ if (fd_list == NULL) {
+ ERR("No fd in message");
+ GQuark quark = g_quark_from_string("l2cap_le-app");
+ GError *err = g_error_new(quark, 0, "No fd in message");
+ g_dbus_method_invocation_return_gerror(invocation, err);
+ g_error_free(err);
+ return;
+ }
+
+ fd = g_unix_fd_list_get(fd_list, index, NULL);
+ if (fd == -1) {
+ ERR("Invalid fd return");
+ GQuark quark = g_quark_from_string("l2cap_le-app");
+ GError *err = g_error_new(quark, 0, "Invalid FD return");
+ g_dbus_method_invocation_return_gerror(invocation, err);
+ g_error_free(err);
+ return;
+ }
+
+ _bt_hal_convert_device_path_to_address(obj_path, addr);
+ _bt_hal_convert_addr_string_to_type(remote_addr1.address, (const char *)addr);
+ INFO("Object path %s, fd: %d, address %s", obj_path, fd, addr);
+
+ g_dbus_method_invocation_return_value(invocation, NULL);
+
+ if (cb)
+ cb(object_path, fd, &remote_addr1);
+ else
+ close(fd);
+ }
+}
+
static GDBusNodeInfo *_bt_hal_get_gdbus_node(const gchar *xml_data)
{
if (bus_id == 0) {
NULL,
};
+static const GDBusInterfaceVTable l2cap_le_method_table = {
+ __hal_l2cap_le_new_connection_method,
+ NULL,
+ NULL,
+};
+
int _bt_hal_register_new_gdbus_object(const char *path, bt_hal_new_connection_cb cb)
{
GDBusConnection *gconn;
g_dbus_connection_unregister_object(gconn, object_id);
}
+int _bt_hal_register_new_l2cap_le_gdbus_object(const char *path,
+ bt_hal_new_connection_cb cb)
+{
+ GDBusConnection *gconn;
+ int id;
+ GError *error = NULL;
+
+ gconn = _bt_hal_get_system_gconn();
+ if (gconn == NULL)
+ return -1;
+
+ if (new_l2cap_le_conn_node == NULL)
+ new_l2cap_le_conn_node = _bt_hal_get_gdbus_node(l2cap_le_agent_xml);
+
+ if (new_l2cap_le_conn_node == NULL)
+ return -1;
+
+ id = g_dbus_connection_register_object(gconn, path,
+ new_l2cap_le_conn_node->interfaces[0],
+ &l2cap_le_method_table,
+ cb, NULL, &error);
+ if (id == 0) {
+ ERR("Failed to register: %s", error->message);
+ g_error_free(error);
+ return -1;
+ }
+
+ INFO("L2CAP_LE NEW CONNECTION ID %d", id);
+
+ return id;
+}
+
+void _bt_hal_unregister_l2cap_le_gdbus_object(int object_id)
+{
+ GDBusConnection *gconn;
+
+ gconn = _bt_hal_get_system_gconn();
+ if (gconn == NULL)
+ return;
+
+ g_dbus_connection_unregister_object(gconn, object_id);
+}
+
int _bt_hal_discover_services(char *address, char *uuid, void *cb, gpointer func_data)
{
char *object_path;
GDBusProxy *adapter_proxy;
GError *err = NULL;
GDBusConnection *conn;
+ GVariant *ret = NULL;
conn = _bt_hal_get_system_gconn();
if (conn == NULL)
object_path = _bt_hal_get_device_object_path(address);
if (object_path == NULL) {
- GVariant *ret = NULL;
INFO("No searched device");
adapter_proxy = _bt_hal_get_adapter_proxy();
if (adapter_proxy == NULL) {
G_DBUS_CALL_FLAGS_NONE,
BT_HAL_MAX_DBUS_TIMEOUT, NULL,
&err);
- if (err != NULL) {
- ERR("CreateDevice Failed: %s", err->message);
- g_clear_error(&err);
- }
-
- if (ret)
+ if (!ret) {
+ if (err) {
+ ERR("CreateDevice Failed: %s", err->message);
+ g_clear_error(&err);
+ }
+ } else {
g_variant_unref(ret);
+ }
g_object_unref(adapter_proxy);
BT_HAL_BLUEZ_NAME, object_path,
BT_HAL_DEVICE_INTERFACE, NULL, NULL);
g_free(object_path);
- g_dbus_proxy_call_sync(proxy, "CancelDiscovery",
+ ret = g_dbus_proxy_call_sync(proxy, "CancelDiscovery",
NULL,
G_DBUS_CALL_FLAGS_NONE,
BT_HAL_MAX_DBUS_TIMEOUT, NULL,
&err);
- if (err) {
- ERR("DBus Error message: [%s]", err->message);
- g_clear_error(&err);
- return BT_STATUS_FAIL;
+ if (!ret) {
+ if (err) {
+ ERR("DBus Error message: [%s]", err->message);
+ g_clear_error(&err);
+ return BT_STATUS_FAIL;
+ }
+ } else {
+ g_variant_unref(ret);
}
if (proxy)
return FALSE;
}
- while (g_variant_iter_loop(iter, "s", &uuid_str)) {
+ while (g_variant_iter_loop(iter, "&s", &uuid_str)) {
DBG("UUID string [%s]\n", uuid_str);
if (!strncasecmp(uuid, uuid_str, strlen(uuid))) {
ret = TRUE;