static void __bt_handle_av_connected_state(bluetooth_device_address_t *address)
{
- char addr[BT_ADDRESS_STRING_SIZE + 1];
+ char addr[BT_ADDRESS_STRING_SIZE] = { 0 };
char connected_address[BT_ADDRESS_STRING_SIZE + 1];
gboolean connected;
- bt_headset_wait_t *wait_device;
+ bt_headset_wait_t *wait_device = NULL;
bluetooth_device_address_t device_address;
+ bluetooth_device_address_t wait_device_address;
GVariant *param;
int result = BLUETOOTH_ERROR_NONE;
ret_if(NULL == address);
_bt_convert_addr_type_to_string(addr, address->addr);
BT_INFO("Address of connected device [%s]", addr);
+ /* Set VCONF Key for A2DP Connected status */
+ _bt_set_device_values(TRUE, VCONFKEY_BT_DEVICE_A2DP_HEADSET_CONNECTED);
+
/* Send A2DP(SRC Role) connected event to Application */
param = g_variant_new("(is)", result, addr);
_bt_send_event(BT_HEADSET_EVENT, BLUETOOTH_EVENT_AV_CONNECTED, param);
if (wait_device != NULL &&
(g_strcmp0(wait_device->address, addr) == 0))
_bt_rel_wait_data();
+ else {
+ if (wait_device != NULL) {
+ BT_INFO("A2DP Profile connected for device [%s] but another device [%s]is waiting to be connnected type [%d]",
+ addr, wait_device->address, wait_device->type);
+ BT_INFO("Trigger connect for the waiting device [%s], audio type [%d]",
+ wait_device->address, wait_device->type);
+ _bt_convert_addr_string_to_type(wait_device_address.addr,
+ wait_device->address);
+ _bt_audio_connect(wait_device->type, &wait_device_address);
+ /* Now free the wait list */
+ //_bt_rel_wait_data();
+ }
+ }
BT_INFO("-");
}
static void __bt_handle_av_disconnected_state(bluetooth_device_address_t *address)
{
- char addr[BT_ADDRESS_STRING_SIZE + 1];
+ char addr[BT_ADDRESS_STRING_SIZE] = { 0 };
int result = BLUETOOTH_ERROR_NONE;
GArray *out_param;
bt_headset_wait_t *wait_device;
bluetooth_device_address_t device_address;
+ bt_pending_audio_conn_t *data = NULL;
GVariant *param;
- invocation_info_t *req_info;
+ invocation_info_t *req_info = NULL;
ret_if(NULL == address);
BT_INFO("+");
_bt_convert_addr_type_to_string(addr, address->addr);
+ if (!_bt_is_service_connected(addr, BT_AUDIO_A2DP)) {
+ BT_ERR("A2DP Disconnected for addr[%s], but it is already disconnected..", addr);
+ return;
+ }
+ /* Set VCONF status for A2DP Disconnection */
+ _bt_set_device_values(FALSE, VCONFKEY_BT_DEVICE_A2DP_HEADSET_CONNECTED);
+
/* Send A2DP(SRC Role) disconnected event to Application */
param = g_variant_new("(is)", result, addr);
_bt_send_event(BT_HEADSET_EVENT, BLUETOOTH_EVENT_AV_DISCONNECTED, param);
if (NULL == req_info) {
/* This means, AV Disconnect request has successfully passed, and real disconnect is completed */
BT_INFO("Neither AV Connect or AV Disconnect request is found..means, AV Profile is disconnected");
+
+ req_info = _bt_get_request_info_data(BT_AUDIO_CONNECT, addr);
+ if (req_info == NULL) {
+ BT_INFO("Audio Connect All request is also Not found..");
+
+ req_info = _bt_get_request_info_data(BT_AUDIO_DISCONNECT, addr);
+ if (req_info == NULL) {
+ BT_INFO("Audio DisConnect All request is also Not found..");
+ } else {
+ BT_INFO("Audio DisConnect All request is found..");
+ /* Check if HFP profile is also connected, if yes, disconnect it too */
+ _bt_audio_check_pending_disconnection(addr, BT_AUDIO_HSP);
+ }
+ } else {
+ BT_INFO("Audio Connect All request is found..");
+ result = BLUETOOTH_ERROR_INTERNAL;
+ data = _bt_get_service_search_info(addr);
+ if (data) {
+ BT_INFO("Pending connect is found, delete it..");
+ _bt_cleanup_search_info_and_reply_pending_req(data, BLUETOOTH_ERROR_NONE);
+ req_info = NULL;
+ } else {
+ BT_INFO("Pending connect is Not found..");
+ }
+ }
goto check_wait_device;
} else {
BT_ERR("AV Connect request has failed.."); /* DBUS return needed */
+ result = BLUETOOTH_ERROR_INTERNAL;
goto check_wait_device;
}
} else {
- /* If AV_DISCONNECT failed, as if it would have passed, then Disconnecting event would have come and
- we must have replied DBUS context */
- BT_ERR("AV Disconnect request found for [%s], means disconnect request has failed", addr); /* DBUS return needed */
+ BT_ERR("AV Disconnect request found for [%s], means disconnect request is successful", addr); /* DBUS return needed */
goto check_wait_device;
}
check_wait_device:
goto dbus_return;
}
- if (g_strcmp0(wait_device->address, addr) != 0) {
- BT_INFO("Trigger connect for the waiting device [%s], audio type [%d]",
- wait_device->address, wait_device->type);
- _bt_convert_addr_string_to_type(device_address.addr,
- wait_device->address);
- _bt_audio_connect(wait_device->type, &device_address);
- /* Now free the wait list */
- _bt_rel_wait_data();
+ if (((wait_device->type == BT_AUDIO_ALL) &&
+ (wait_device->ag_flag == TRUE)) ||
+ (wait_device->type == BT_AUDIO_A2DP) ||
+ (wait_device->disconnection_type == BT_AUDIO_A2DP)) {
+ if (g_strcmp0(wait_device->address, addr) != 0) {
+ BT_INFO("Trigger connect for the waiting device [%s], audio type [%d]",
+ wait_device->address, wait_device->type);
+ _bt_convert_addr_string_to_type(device_address.addr,
+ wait_device->address);
+ _bt_audio_connect(wait_device->type, &device_address);
+ /* Now free the wait list */
+ //_bt_rel_wait_data();
+ }
}
dbus_return:
if (req_info) {
out_param = g_array_new(FALSE, FALSE, sizeof(gchar));
- g_array_append_vals(out_param, &device_address,
- sizeof(bluetooth_device_address_t));
+ g_array_append_vals(out_param, addr, BT_ADDRESS_STRING_SIZE);
_bt_service_method_return(req_info->context,
out_param, result);
g_array_free(out_param, TRUE);
req_info = _bt_get_request_info_data(BT_AV_DISCONNECT, addr);
if (NULL == req_info) {
BT_INFO("AV DisConnect request not found or possibly already replied");
- return;
+ req_info = _bt_get_request_info_data(BT_AUDIO_DISCONNECT, addr);
+ if (req_info == NULL) {
+ BT_INFO("Audio All DisConnect request is also not found or possibly already replied");
+ return;
+ } else {
+ BT_INFO("Audio All DisConnect request found..");
+ }
} else {
BT_INFO("AV DisConnect request found for [%s]", addr);
}
/* In any of the above cases, do DBUS return */
out_param = g_array_new(FALSE, FALSE, sizeof(gchar));
- g_array_append_vals(out_param, &device_address,
- sizeof(bluetooth_device_address_t));
+ g_array_append_vals(out_param, addr, BT_ADDRESS_STRING_SIZE);
_bt_service_method_return(req_info->context,
out_param, result);
g_array_free(out_param, TRUE);
bluetooth_device_address_t device_address;
GArray *out_param;
invocation_info_t *req_info;
+ bt_pending_audio_conn_t *data = NULL;
int result = BLUETOOTH_ERROR_NONE;
memcpy(device_address.addr, address->addr, BLUETOOTH_ADDRESS_LENGTH);
_bt_convert_addr_type_to_string(addr, address->addr);
req_info = _bt_get_request_info_data(BT_AV_CONNECT, addr);
if (NULL == req_info) {
BT_INFO("AV Connect request not found or possibly already replied");
- return;
+ req_info = _bt_get_request_info_data(BT_AUDIO_CONNECT, addr);
+
+ if (req_info == NULL) {
+ BT_INFO("AV Connect request & Audio All connect not found or possibly already replied");
+ return;
+ } else {
+ BT_INFO("Audio All connect request found for address [%s]", addr);
+ /* TODO Delete the search info if present */
+ data = _bt_get_service_search_info(addr);
+ if (data) {
+ BT_INFO("Audio Connect All request present and pending connect is also present, delete info");
+ _bt_cleanup_search_info_and_reply_pending_req(data, BLUETOOTH_ERROR_NONE);
+ } else {
+ BT_ERR("Abnormal: Audio Connect All request present but pending connect absent");
+ }
+ }
} else {
BT_INFO("AV Connect request found for [%s]", addr);
}
- /* TODO: Pending data creation if multiple profile is supported */
-
out_param = g_array_new(FALSE, FALSE, sizeof(gchar));
- g_array_append_vals(out_param, &device_address,
- sizeof(bluetooth_device_address_t));
+ g_array_append_vals(out_param, addr, BT_ADDRESS_STRING_SIZE);
_bt_service_method_return(req_info->context,
out_param, result);
g_array_free(out_param, TRUE);
#include "bt-service-common.h"
#include "bt-request-handler.h"
#include "bt-service-audio-common.h"
+#include "bt-service-core-device.h"
#include "bt-service-a2dp-src.h"
#include "bt-service-hf.h"
char device_address[BT_ADDRESS_STRING_SIZE + 1];
} bt_connected_headset_data_t;
+/* List for saving device service search info */
+static GSList *g_service_search_info_list = NULL;
+
/* Headset connection data structures */
gboolean connection_local = FALSE;
static void __bt_remove_device_from_wait_list(char *prev_waiting_device);
+static void __bt_audio_device_property_event_handler(int oal_event, gpointer event_data);
+
+static int __bt_process_audio_connect_all(bt_pending_audio_conn_t *info);
+
+static int __bt_is_headset_connecting(int type);
+
+static int __bt_is_headset_disconnecting(int type);
+
void _bt_headset_set_local_connection(gboolean value)
{
BT_INFO("setting connection_local to %d", value);
}
connected_device->device_state = status;
- if (status == BT_STATE_CONNECTED)
+ if ((status == BT_STATE_CONNECTED) || (status == BT_STATE_CONNECTING))
connected_device->type |= type;
g_strlcpy(connected_device->device_address, address,
sizeof(connected_device->device_address));
g_connected_list = g_list_append(g_connected_list, connected_device);
+ BT_INFO("Added device[%s] in connected list, device state [%d] Device Type [%d]",
+ address, connected_device->device_state, connected_device->type);
}
gboolean _bt_is_headset_type_connected(int type, char *address)
}
#endif
+static int __bt_is_headset_disconnecting(int type)
+{
+ bt_connected_headset_data_t *connected_device = NULL;
+
+ /* Check if any other headset is connected */
+ GList *node = NULL;
+
+ node = g_list_first(g_connected_list);
+ while (node != NULL) {
+ connected_device = node->data;
+ if (connected_device->device_state == BT_STATE_DISCONNECTING) {
+ return BLUETOOTH_ERROR_CONNECTION_BUSY;
+ }
+ node = g_list_next(node);
+ }
+
+ return BLUETOOTH_ERROR_NONE;
+}
+
+static int __bt_is_headset_connecting(int type)
+{
+ bt_connected_headset_data_t *connected_device = NULL;
+
+ /* Check if any other headset is connected */
+ GList *node = NULL;
+
+ node = g_list_first(g_connected_list);
+ while (node != NULL) {
+ connected_device = node->data;
+ if (connected_device->device_state == BT_STATE_CONNECTING) {
+ BT_ERR("@@Device [%s] is already under connecting state", connected_device->device_address);
+ return BLUETOOTH_ERROR_CONNECTION_BUSY;
+ }
+ node = g_list_next(node);
+ }
+
+ return BLUETOOTH_ERROR_NONE;
+}
+
static int __bt_is_headset_connected(int type, const char *address)
{
gboolean connected = FALSE;
+ int conn_type;
char connected_address[BT_ADDRESS_STRING_SIZE + 1];
bluetooth_device_address_t device_address;
bt_connected_headset_data_t *connected_device = NULL;
/* Check if any other headset is connected */
GList *node = NULL;;
+ BT_INFO("Checking if any Headset connected or not: current device [%s] current dev type [%d]", address, type);
node = g_list_first(g_connected_list);
while (node != NULL) {
connected_device = node->data;
- if ((connected_device->type & type) == type) {
+ BT_INFO(" A Device is already connected found in list [%s] conn type [%d",
+ connected_device->device_address, connected_device->type);
+ if ((connected_device->type & type)) {
g_strlcpy(connected_address, connected_device->device_address,
BT_ADDRESS_STRING_SIZE + 1);
#ifdef TIZEN_SUPPORT_DUAL_HF
node = g_list_next(node);
}
- if (!connected)
+ if (!connected) {
+ BT_INFO("There is no connected device with connection type [%d]", type);
return BLUETOOTH_ERROR_NOT_CONNECTED;
+ }
BT_DBG("connected headset %s", connected_address);
else if (TRUE == __bt_is_companion_device(address))
return BLUETOOTH_ERROR_NOT_CONNECTED;
#endif
+
+ /* Convert BD adress from string type */
+ _bt_convert_addr_string_to_type(device_address.addr, connected_address);
+ int value = BLUETOOTH_ERROR_NONE;
+ BT_DBG("Already connected headset addr [%s] connected headset type [0x%x] current dev conn type [0x%x]",
+ connected_address, connected_device->type, type);
+ conn_type = connected_device->type & type;
+ BT_DBG("Attempt disconnection of Type [0x%x] of already connected device" , conn_type);
+ value = _bt_audio_disconnect(connected_device->type & type, &device_address);
+
/* If already one device is waiting, remove current waiting device and add new */
- if (g_wait_data != NULL) {
- if (g_strcmp0(g_wait_data->address, address) != 0) {
- __bt_remove_device_from_wait_list(g_wait_data->address);
- __bt_free_wait_data();
+ if (value == BLUETOOTH_ERROR_NONE) {
+ if (g_wait_data != NULL) {
+ if (g_strcmp0(g_wait_data->address, address) != 0) {
+ BT_INFO("Already one device was waiting for connection [%s], remove it", g_wait_data->address);
+ __bt_remove_device_from_wait_list(g_wait_data->address);
+ __bt_free_wait_data();
+ }
}
- }
- if (g_wait_data == NULL) {
- g_wait_data = g_malloc0(sizeof(bt_headset_wait_t));
- g_wait_data->address = g_strdup(address);
- g_wait_data->type = type;
- g_wait_data->ag_flag = FALSE;
+ if (g_wait_data == NULL) {
+ BT_INFO("Add current device [%s] into waiting list", address);
+ g_wait_data = g_malloc0(sizeof(bt_headset_wait_t));
+ g_wait_data->address = g_strdup(address);
+ g_wait_data->type = type;
+ g_wait_data->ag_flag = FALSE;
- /* Set disconnection type */
- __bt_set_headset_disconnection_type(connected_address);
+ /* Set disconnection type */
+ __bt_set_headset_disconnection_type(connected_address);
+ }
}
- /* Convert BD adress from string type */
- _bt_convert_addr_string_to_type(device_address.addr, connected_address);
- _bt_audio_disconnect(connected_device->type & type, &device_address);
- return BLUETOOTH_ERROR_NONE;
+ return value;
}
static void __bt_remove_device_from_wait_list(char *prev_waiting_device)
{
char addr[BT_ADDRESS_STRING_SIZE] = { 0 };
int result = BLUETOOTH_ERROR_NONE;
+ GList *node;
BT_INFO("+");
_bt_convert_addr_type_to_string(addr,
}
if (result == BLUETOOTH_ERROR_NONE) {
+ /*
+ * This logic is added for dual HF mode issue.
+ */
+ node = g_list_first(g_connected_list);
+ while (node != NULL) {
+ bt_connected_headset_data_t *connected_device = node->data;
+
+ if (g_strcmp0(connected_device->device_address, addr) == 0) {
+ BT_DBG("Connection type update");
+ type = connected_device->type;
+ break;
+ }
+ node = g_list_next(node);
+ }
+
/* Update device status in connected list */
_bt_add_headset_to_list(type, BT_STATE_DISCONNECTING, addr);
} else {
case BT_AUDIO_ALL_MODULE:
{
/* Register Audio module event handler */
- /*TODO: Register Audio event handler for device services
- will be supported after HSP profile implementation */
- return BLUETOOTH_ERROR_NOT_SUPPORT;
+ _bt_service_register_event_handler_callback(module, __bt_audio_device_property_event_handler);
+ break;
}
default:
BT_ERR("Not Supported: Module [%d]", module);
return ret;
}
+/* This event handler process audio device service search request */
+static void __bt_audio_device_property_event_handler(int oal_event, gpointer event_data)
+{
+ GSList *l;
+ int count;
+ char address[BT_ADDRESS_STRING_SIZE] = { 0 };
+ bt_pending_audio_conn_t *info = NULL;
+ event_dev_properties_t *event;
+ int value = BLUETOOTH_ERROR_NONE;
+ int ret = BLUETOOTH_ERROR_NONE;
+ bt_remote_dev_info_t *rem_info = NULL;
+ BT_INFO("+");
+
+ if (!g_service_search_info_list) {
+ BT_INFO("No Audio Service Search request is pending..");
+ return;
+ }
+
+ /* Device Services are searched */
+ event = (event_dev_properties_t*)event_data;
+
+ rem_info = g_malloc0(sizeof(bt_remote_dev_info_t));
+ memset(rem_info, 0x00, sizeof(bt_remote_dev_info_t));
+ _bt_copy_remote_dev(rem_info, &event->device_info);
+
+ _bt_convert_addr_type_to_string(address,
+ (unsigned char *)event->device_info.address.addr);
+
+ for (l = g_service_search_info_list; l != NULL; l = g_slist_next(l)) {
+ info = (bt_pending_audio_conn_t*)l->data;
+
+ if (info && g_strcmp0(info->address, address) == 0 && info->search_status == SERVICE_SEARCH_STARTED) {
+ BT_INFO("Service searching is ongoing for addr [%s], Services received for the same!", info->address);
+ info->search_status = SERVICE_SEARCH_DONE;
+ for(count=0; count < rem_info->uuid_count; count++) {
+ BT_INFO("Device [%s] has UUID [%s]", address, rem_info->uuids[count]);
+ if (g_strcmp0(A2DP_SINK_UUID, rem_info->uuids[count]) == 0) {
+ BT_INFO("Device supports A2DP Sink Profile");
+ info->is_a2dp_supported = TRUE;
+ }
+ if (g_strcmp0(HFP_HS_UUID, rem_info->uuids[count]) == 0) {
+ BT_INFO("Device supports HFP Profile");
+ info->is_hfp_supported = TRUE;
+ }
+ }
+ if (info->is_a2dp_supported == FALSE && info->is_hfp_supported == FALSE) {
+ ret = BLUETOOTH_ERROR_NOT_SUPPORT;
+ goto fail;
+ }
+ break;
+ }
+ info = NULL;
+ }
+ if (!info) {
+ BT_INFO("Could not find any Audio service searching info..");
+ if (rem_info)
+ _bt_free_remote_dev(rem_info);
+ return;
+ }
+
+ BT_INFO("AUDIO_CONNECT_ALL request is now pending for [%s]", info->address);
+ /* Give preference to HFP over A2DP for outgoing connection sequence for AUDIO_ALL_CONNECT */
+ if (info->is_hfp_supported)
+ info->type = BT_AUDIO_HSP;
+ else
+ info->type = BT_AUDIO_A2DP;
+
+ value = __bt_is_headset_connected(info->type, info->address);
+
+ if (value == BLUETOOTH_ERROR_ALREADY_CONNECT ||
+ value == BLUETOOTH_ERROR_IN_PROGRESS) {
+ BT_ERR("Sorry, can not start Audio All connect for [%s] reason [%d]", info->address, value);
+ if (value == BLUETOOTH_ERROR_ALREADY_CONNECT)
+ BT_ERR("Reason: Already connected...");
+ else if (value == BLUETOOTH_ERROR_IN_PROGRESS)
+ BT_ERR("Reason: Already in progress..");
+ ret = value;
+ goto fail;
+ } else if (value == BLUETOOTH_ERROR_NOT_CONNECTED) {
+ BT_ERR("Great, can start Audio All connect for [%s]", info->address);
+
+ value = __bt_is_headset_connecting(info->type);
+ if (value != BLUETOOTH_ERROR_NONE) {
+ BT_ERR("Sorry, can not start Audio All connect for [%s] as some other device under progress", info->address);
+ ret = BLUETOOTH_ERROR_IN_PROGRESS;
+ goto fail;
+ }
+ ret = __bt_process_audio_connect_all(info);
+ if (ret != BLUETOOTH_ERROR_NONE) {
+ goto fail;
+ } else {
+ /* Check if pending connection is necessary or not */
+ if (info->is_hfp_supported && info->is_a2dp_supported) {
+ /* Remote device supports both A2DP and HFP, keep search info */
+ BT_INFO("[%s] Supports both A2DP and HFP...", info->address);
+ } else {
+ /* Remote device supports either A2DP or HFP, delete search info as no
+ pending connection is required. pending connection is only required
+ when both profiles are supported */
+ BT_INFO("[%s] Supports one profile", info->address);
+ _bt_remove_service_search_request(info->address);
+ }
+ }
+ } else if (value == BLUETOOTH_ERROR_NONE) {
+ BT_INFO("Waiting for disconnection...");
+ /* Above means, we dont need pending connect (as only A2DP or HFP will be connected
+ for present device) So lets delete search info */
+ _bt_remove_service_search_request(info->address);
+ } else if (value == BLUETOOTH_ERROR_IN_PROGRESS) {
+ ret = BLUETOOTH_ERROR_IN_PROGRESS;
+ goto fail;
+ }
+ //__bt_check_pending_service_search();
+ if (rem_info)
+ _bt_free_remote_dev(rem_info);
+ return;
+fail:
+ BT_ERR("Audio COnnect all failed: Either (A2DP Sink & HFP) are not supported or device buzy or already connectede..");
+ if (rem_info)
+ _bt_free_remote_dev(rem_info);
+ _bt_cleanup_search_info_and_reply_pending_req(info, ret);
+ //__bt_check_pending_service_search();
+}
+
+static int __bt_process_audio_connect_all(bt_pending_audio_conn_t *info)
+{
+ bluetooth_device_address_t device_address;
+ int result = BLUETOOTH_ERROR_NONE;
+ int type = BT_AUDIO_ALL;
+ BT_INFO("+");
+
+ _bt_convert_addr_string_to_type(device_address.addr, info->address);
+
+ /* Attempt profile level connection */
+ if (info->is_hfp_supported) {
+ type = BT_AUDIO_HSP;
+ result = _bt_connect_remote_hfp(&device_address);
+
+ if (info->is_a2dp_supported) {
+ BT_INFO("A2DP is supported by [%s]", info->address);
+ } else {
+ BT_INFO("A2DP is not supported");
+ }
+ } else if (info->is_a2dp_supported) {
+ type = BT_AUDIO_A2DP;
+ result = _bt_a2dp_connect_remote_sink(&device_address);
+ }
+ if (result == BLUETOOTH_ERROR_NONE) {
+ _bt_headset_set_local_connection(TRUE);
+ /* Add data to the connected list */
+ _bt_add_headset_to_list(type, BT_STATE_CONNECTING, info->address);
+ } else {
+ BT_ERR("Profile connect failed!!");
+ }
+ BT_INFO("-");
+ return result;
+}
+
+void _bt_remove_service_search_request(char *address)
+{
+ BT_INFO("+");
+ bt_pending_audio_conn_t *info = NULL;
+ GSList *l;
+
+ BT_INFO("Search pending data for address [%s]", address);
+ for (l = g_service_search_info_list; l != NULL; l = g_slist_next(l)) {
+ info = (bt_pending_audio_conn_t*)l->data;
+
+ if (g_strcmp0(info->address, address) == 0 && info->search_status == SERVICE_SEARCH_DONE) {
+ BT_INFO("Pending data found for addr [%s], delete it...", info->address);
+ g_service_search_info_list = g_slist_remove(g_service_search_info_list, info);
+ g_free(info->address);
+ g_free(info);
+ }
+ }
+ BT_INFO("Pending data not found!!");
+}
+
+bt_pending_audio_conn_t* _bt_get_service_search_info(char *address)
+{
+ BT_INFO("+");
+ bt_pending_audio_conn_t *info = NULL;
+ GSList *l;
+
+ for (l = g_service_search_info_list; l != NULL; l = g_slist_next(l)) {
+ info = (bt_pending_audio_conn_t*)l->data;
+
+ if (g_strcmp0(info->address, address) == 0 && info->search_status == SERVICE_SEARCH_DONE) {
+ BT_INFO("Pending data found for addr [%s]", info->address);
+ return info;
+ }
+ }
+ BT_INFO("Pending data not found!!");
+ return NULL;
+}
+
+void _bt_cleanup_search_info_and_reply_pending_req(bt_pending_audio_conn_t *info, int result)
+{
+ GArray *out_param;
+ invocation_info_t *req_info;
+ bluetooth_device_address_t device_address;
+
+ if (info) {
+ g_service_search_info_list = g_slist_remove(g_service_search_info_list, info);
+
+ /* Reply to async request for Audio connect, if any */
+ req_info = _bt_get_request_info_data(BT_AUDIO_CONNECT, info->address);
+ if (NULL != req_info) {
+ BT_INFO("Delete pending data informations..");
+ _bt_convert_addr_string_to_type(device_address.addr, info->address);
+ out_param = g_array_new(FALSE, FALSE, sizeof(gchar));
+ g_array_append_vals(out_param, info->address, BT_ADDRESS_STRING_SIZE);
+ _bt_service_method_return(req_info->context,
+ out_param, result);
+ g_array_free(out_param, TRUE);
+ g_free(req_info->user_data);
+ _bt_free_info_from_invocation_list(req_info);
+ }
+ if (info->address)
+ g_free(info->address);
+ g_free(info);
+ }
+}
+
+void _bt_audio_check_pending_connection(char *address)
+{
+ bt_pending_audio_conn_t *data = NULL;
+ bluetooth_device_address_t device_address;
+ BT_INFO("+");
+
+ data = _bt_get_service_search_info(address);
+
+ if (data) {
+ BT_INFO("A2DP Connection is pending..initiate it...");
+ if (data->is_a2dp_supported) {
+ _bt_convert_addr_string_to_type(device_address.addr, address);
+ if (_bt_audio_connect(BT_AUDIO_A2DP, &device_address) != BLUETOOTH_ERROR_NONE) {
+ BT_INFO("A2DP connect triggered for [%s] but it failed!!", data->address);
+ _bt_cleanup_search_info_and_reply_pending_req(data, BLUETOOTH_ERROR_INTERNAL);
+ } else {
+ BT_INFO("A2DP connect triggered successfully for [%s]", data->address);
+ }
+ }
+ } else {
+ BT_INFO("A2DP Connection is not pending..");
+ }
+ BT_INFO("-");
+}
+
+void _bt_audio_check_pending_disconnection(char *address, int type)
+{
+ int ret = BLUETOOTH_ERROR_NONE;
+ bluetooth_device_address_t device_address;
+ BT_INFO("+");
+
+ if (_bt_is_service_connected(address, type)) {
+ BT_INFO("Service [%d] is connected with device [%s], disconnect it...", type, address);
+ _bt_convert_addr_string_to_type(device_address.addr, address);
+ ret = __bt_process_audio_profile_disconnect(type, &device_address);
+
+ if (ret != BLUETOOTH_ERROR_NONE)
+ BT_ERR("Disconnecting service [%d] with device [%s] failed!!", type, address);
+ } else {
+ BT_INFO("Service [%d] is Not connected with device [%s],..", type, address);
+ }
+ BT_INFO("-");
+}
+
int _bt_audio_connect(int type, bluetooth_device_address_t *device_address)
{
int value = BLUETOOTH_ERROR_NONE;
int ret = BLUETOOTH_ERROR_NONE;
char address[BT_ADDRESS_STRING_SIZE] = { 0 };
+ bt_pending_audio_conn_t *info = NULL;
BT_INFO("+");
BT_CHECK_PARAMETER(device_address, return);
_bt_convert_addr_type_to_string(address, device_address->addr);
+ /* If type is BT_AUDIO_ALL, enqueue search info in order to find out
+ supported services by the remote device */
if (type == BT_AUDIO_ALL) {
- /*TODO: Audio connect All will be supported after HSP profile implementation */
- return BLUETOOTH_ERROR_NOT_SUPPORT;
- }
+ /* Safe operation, cleanup if already any pending request is present in list */
+ _bt_remove_service_search_request(address);
+
+ info = g_malloc(sizeof(bt_pending_audio_conn_t));
+ /* Request bonded device info */
+ BT_INFO("Fire Bonded Device info for address [%s]", address);
+
+ ret = _bt_device_get_bonded_device_info(device_address);
+
+ if (ret != BLUETOOTH_ERROR_NONE)
+ goto fail;
+ info->search_status = SERVICE_SEARCH_STARTED;
+ info->address = g_strdup(address);
+ info->type = type;
+ g_service_search_info_list = g_slist_append(g_service_search_info_list, (gpointer)info);
+ return ret;
+ }
/* If type is A2DP Sink or HSP/HFP, check further */
value = __bt_is_headset_connected(type, address);
}
} else if (value == BLUETOOTH_ERROR_NONE) {
BT_INFO("Waiting for disconnection...");
+ } else if (value == BLUETOOTH_ERROR_IN_PROGRESS) {
+ ret = BLUETOOTH_ERROR_IN_PROGRESS;
+ goto fail;
}
+
return BLUETOOTH_ERROR_NONE;
fail:
+ if (info) {
+ if (info->address)
+ g_free(info->address);
+ g_free(info);
+ }
return ret;
}
int _bt_audio_disconnect(int type, bluetooth_device_address_t *device_address)
{
int ret = BLUETOOTH_ERROR_NONE;
+ int value = BLUETOOTH_ERROR_NONE;
char address[BT_ADDRESS_STRING_SIZE] = { 0 };
_bt_convert_addr_type_to_string(address, device_address->addr);
BT_INFO("Audio Diconnect Request: type[%d] address [%s]", type, address);
if (type == BT_AUDIO_ALL) {
- /*TODO: Audio Disconnect All will be supported after HSP profile implementation */
- return BLUETOOTH_ERROR_NOT_SUPPORT;
+ if (_bt_is_service_connected(address, BT_AUDIO_A2DP)) {
+ type = BT_AUDIO_A2DP;
+ } else if (_bt_is_service_connected(address, BT_AUDIO_HSP)) {
+ type = BT_AUDIO_HSP;
+ } else {
+ BT_ERR("No audio service connected");
+ return BLUETOOTH_ERROR_NOT_CONNECTED;
+ }
+ }
+
+ value = __bt_is_headset_disconnecting(type);
+ if (value != BLUETOOTH_ERROR_NONE) {
+ BT_INFO("Disconnect in progress");
+ return BLUETOOTH_ERROR_IN_PROGRESS;
}
switch (type) {
- case BT_AUDIO_HSP:
- case BT_AUDIO_A2DP:
+ case BT_AUDIO_HSP: /* Remote is HFP HF unit */
+ case BT_AUDIO_A2DP: /* Remote is A2DP Sink */
ret = __bt_process_audio_profile_disconnect(type, device_address);
break;
case BT_AVRCP:
- case BT_AUDIO_A2DP_SOURCE:
+ case BT_AUDIO_A2DP_SOURCE: /* Remote is A2DP Source */
return BLUETOOTH_ERROR_NOT_SUPPORT;
default:
BT_ERR("Unknown role");
if (connected_device->type & BT_AVRCP)
connected_device->type &= ~(BT_AVRCP);
break;
+ case BT_AUDIO_A2DP_SOURCE:
+ if (connected_device->type & BT_AUDIO_A2DP_SOURCE)
+ connected_device->type &= ~(BT_AUDIO_A2DP_SOURCE);
}
BT_DBG("Connection type = %x\n", connected_device->type);
if (connected_device->type == 0x00) {
+ BT_INFO("Device will be completely removed from connected list as the only profile connected or connecting got disconnected");
g_connected_list = g_list_remove(g_connected_list, connected_device);
g_free(connected_device);
+ } else {
+ connected_device->device_state = BT_STATE_CONNECTED;
}
node = g_list_next(node);
BT_DBG("-");
}
-/* Handles both HFP profile disconnect and HF Audio disconnection request */
static void __bt_reply_hf_disconnection_pending_request(bt_address_t *address)
{
BT_DBG("+");
bluetooth_device_address_t device_address;
GArray *out_param;
invocation_info_t *req_info;
+ bt_headset_wait_t *wait_list = NULL;
+ bt_pending_audio_conn_t* data = NULL;
int result = BLUETOOTH_ERROR_NONE;
memcpy(device_address.addr, address->addr, BLUETOOTH_ADDRESS_LENGTH);
_bt_convert_addr_type_to_string(addr, address->addr);
- req_info = _bt_get_request_info_data(BT_AG_DISCONNECT, addr);
+ /* Remove HSP Connection from the device */
+ _bt_remove_headset_from_list(BT_AUDIO_HSP, addr);
+ /* Find Async request information*/
+ req_info = _bt_get_request_info_data(BT_AG_DISCONNECT, addr);
if (NULL == req_info) {
BT_INFO("AG DisConnect request not found or possibly already replied..");
- req_info = _bt_get_request_info_data(BT_AG_CONNECT, addr);
+ req_info = _bt_get_request_info_data(BT_AG_CONNECT, addr);
if (req_info == NULL) {
BT_INFO("AG Connect request also not found..");
- req_info = _bt_get_request_info_data(BT_AUDIO_DISCONNECT, addr);
+ req_info = _bt_get_request_info_data(BT_AUDIO_DISCONNECT, addr);
if (req_info == NULL) {
BT_INFO("AUDIO Disconnect request also not found..");
- req_info = _bt_get_request_info_data(BT_AUDIO_CONNECT, addr);
+ req_info = _bt_get_request_info_data(BT_AUDIO_CONNECT, addr);
if (req_info == NULL) {
BT_INFO("AUDIO Connect request also not found..");
return;
+ } else {
+ BT_INFO("AG Audio All Connect request found..");
+ result = BLUETOOTH_ERROR_INTERNAL;
}
+ } else {
+ BT_INFO("AG Audio All DisConnect request found..");
}
+ } else {
+ BT_INFO("AG Connect request found..");
+ result = BLUETOOTH_ERROR_INTERNAL;
}
+ } else {
+ BT_INFO("AG DisConnect request found..");
}
- if (req_info->service_function == BT_AG_CONNECT ||
- req_info->service_function == BT_AUDIO_CONNECT)
- result = BLUETOOTH_ERROR_INTERNAL;
+ /* Cleanup device service search info if Aysnc request was Audio Connect All */
+ if (req_info->service_function == BT_AUDIO_CONNECT) {
+ /* Check if pending connect was present */
+ data = _bt_get_service_search_info(addr);
+ if (data) {
+ BT_INFO("HF Connection failed during Audio All connect, & pending connect present");
+ _bt_cleanup_search_info_and_reply_pending_req(data, BLUETOOTH_ERROR_INTERNAL);
+ goto try_waiting_device;
+ } else {
+ BT_INFO("Abnormal:HF Connection failed during Audio All connect, but pending connect not present");
+ }
+ }
/* In any of the above cases, reply DBUS context */
out_param = g_array_new(FALSE, FALSE, sizeof(gchar));
- g_array_append_vals(out_param, &device_address,
- sizeof(bluetooth_device_address_t));
+ g_array_append_vals(out_param, addr, BT_ADDRESS_STRING_SIZE);
_bt_service_method_return(req_info->context,
out_param, result);
g_array_free(out_param, TRUE);
g_free(req_info->user_data);
_bt_free_info_from_invocation_list(req_info);
+
+try_waiting_device:
+ wait_list = _bt_get_audio_wait_data();
+ if (wait_list == NULL) {
+ return;
+ }
+ _bt_convert_addr_string_to_type(device_address.addr,
+ wait_list->address);
+ BT_INFO("Trigger connect for the waiting device [%s], audio type [%d]",
+ wait_list->address, wait_list->type);
+ _bt_audio_connect(wait_list->type, &device_address);
+ _bt_rel_wait_data();
}
static void __bt_hf_handle_audio_connection_state(bt_address_t *bd_addr)
{
char address[BT_ADDRESS_STRING_SIZE] = { 0 };
- bt_headset_wait_t *wait_list;
+ bt_headset_wait_t *wait_list = NULL;
unsigned int result = BLUETOOTH_ERROR_NONE;
GVariant *param;
BT_INFO("+");
_bt_convert_addr_type_to_string(address, bd_addr->addr);
BT_INFO("HF(AG Role) Connected for address [%s]", address);
- /* Send HF(AG Role) disconnected event to Application */
- param = g_variant_new("(is)", result, address);
- _bt_send_event(BT_HEADSET_EVENT, BLUETOOTH_EVENT_AG_CONNECTED, param);
+ /* Send HF(AG Role) connected event to Application */
+ param = g_variant_new("(is)", result, address);
+ _bt_send_event(BT_HEADSET_EVENT, BLUETOOTH_EVENT_AG_CONNECTED, param);
/* Add data to the connected list */
_bt_add_headset_to_list(BT_AUDIO_HSP,
wait_list = _bt_get_audio_wait_data();
if (wait_list != NULL &&
- (g_strcmp0(wait_list->address, address) == 0))
+ (g_strcmp0(wait_list->address, address) == 0)) {
+ BT_INFO("Same Device [%s] is under wait, connection type [%d], going to delete it",
+ wait_list->address, wait_list->type);
_bt_rel_wait_data();
+ } else {
+ if (wait_list != NULL)
+ BT_INFO("Some Device [%s] is under wait, connection type [%d], ", wait_list->address, wait_list->type);
+ }
BT_INFO("Check A2DP pending connect");
- /*TODO Check pending A2DP connection */
- //_bt_audio_check_pending_connection(address);
+
+ /* Check pending A2DP connection */
+ _bt_audio_check_pending_connection(address);
}
static void __bt_reply_hf_connection_pending_request(bt_address_t *address)
char addr[BT_ADDRESS_STRING_SIZE] = { 0 };
bluetooth_device_address_t device_address;
invocation_info_t *req_info;
+ GArray *out_param;
+ bt_pending_audio_conn_t* data = NULL;
memcpy(device_address.addr, address->addr, BLUETOOTH_ADDRESS_LENGTH);
_bt_convert_addr_type_to_string(addr, address->addr);
- /* TODO: AG Connect request is currently not handled */
req_info = _bt_get_request_info_data(BT_AUDIO_CONNECT, addr);
if (NULL != req_info) {
BT_INFO("Audio All Connect request found");
-/*
- out_param = g_array_new(FALSE, FALSE, sizeof(gchar));
- g_array_append_vals(out_param, &device_address,
- sizeof(bluetooth_device_address_t));
- _bt_service_method_return(req_info->context,
- out_param, result);
- g_array_free(out_param, TRUE);
- g_free(req_info->user_data);
- _bt_free_info_from_invocation_list(req_info);
-*/
+ /* Check for Pending connect : A2DP connect is pending */
+ data = _bt_get_service_search_info(addr);
+ if (data) {
+ BT_INFO("Pending A2DP connect is present..dont return DBUS for AUDIO_CONNECT_ALL, wait for A2DP connect");
+ } else {
+ BT_INFO("Pending A2DP connect is Not present..return DBUS for AUDIO_CONNECT_ALL");
+ goto dbus_return;
+ }
} else {
BT_INFO("Audio All Connect Request not found..");
+ req_info = _bt_get_request_info_data(BT_AG_CONNECT, addr);
+
+ if (req_info) {
+ BT_INFO("AG Connect Request found..");
+ goto dbus_return;
+ } else {
+ BT_ERR("AG Connect Request also not found..Abnormal Case!!!");
+ return;
+ }
}
+dbus_return:
+ out_param = g_array_new(FALSE, FALSE, sizeof(gchar));
+ g_array_append_vals(out_param, addr, BT_ADDRESS_STRING_SIZE);
+ _bt_service_method_return(req_info->context,
+ out_param, BLUETOOTH_ERROR_NONE);
+ g_array_free(out_param, TRUE);
+ g_free(req_info->user_data);
+ _bt_free_info_from_invocation_list(req_info);
}
/* This event handler process events for HF (AG role) */
switch (oal_event) {
case OAL_EVENT_HFP_DISCONNECTED:
/* Reply to async request for HF connect or disconnect request, if any */
- BT_INFO("HF Profile disconnected, reply pending request and send event");
+ BT_INFO("HF Profile disconnected, reply pending DBUS request and check waiting device");
__bt_reply_hf_disconnection_pending_request(bt_addr);
- __bt_hf_handle_audio_disconnection_state(bt_addr);
break;
case OAL_EVENT_HFP_AUDIO_DISCONNECTED:
/* Reply to async request for HF connect or disconnect request, if any */
BT_INFO("HF SCO disconnected, reply pending request if any and send event");
- __bt_reply_hf_disconnection_pending_request(bt_addr);
__bt_hf_handle_audio_disconnection_state(bt_addr);
break;
case OAL_EVENT_HFP_CONNECTED:
- BT_INFO("HFP Profile conencted, Curently not handled..");
+ BT_INFO("HFP Profile connected, Curently not handled..");
break;
case OAL_EVENT_HFP_AUDIO_CONNECTED:
BT_INFO("HFP SCO conencted, handle the event..");
- /* Reply to async request for HF connect request, if any */
- __bt_reply_hf_connection_pending_request(bt_addr);
__bt_hf_handle_audio_connection_state(bt_addr);
break;
case OAL_EVENT_HFP_CONNECTING:
+ /* Reply to async request for HF connect request, if any */
+ BT_INFO("HFP Profile connection successful, wait for Audio connect..");
+ __bt_reply_hf_connection_pending_request(bt_addr);
+ break;
case OAL_EVENT_HFP_DISCONNECTING:
BT_INFO("HFP Connecting or Disconnecting..No need to send event to app");
+ //__bt_reply_hf_disconnection_pending_request(bt_addr);
break;
case OAL_EVENT_HFP_AUDIO_CONNECTING:
case OAL_EVENT_HFP_AUDIO_DISCONNECTING: