X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=bt-service%2Fbt-service-audio.c;h=7dd091c6c86f88450155ef01935805a515a7b63a;hb=1fa07edcd0e77a445700975773db3300f556caf5;hp=994e4a79805925abb4aa29c678821ade2cb320c6;hpb=2005d3d7687dec234f6bea0f778d81a1e424da12;p=platform%2Fcore%2Fconnectivity%2Fbluetooth-frwk.git diff --git a/bt-service/bt-service-audio.c b/bt-service/bt-service-audio.c index 994e4a7..7dd091c 100644 --- a/bt-service/bt-service-audio.c +++ b/bt-service/bt-service-audio.c @@ -1,13 +1,11 @@ /* - * bluetooth-frwk - * - * Copyright (c) 2012-2013 Samsung Electronics Co., Ltd. + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -17,14 +15,14 @@ * */ -#include -#include +#include #include #include #include -#ifndef LIBNOTIFY_SUPPORT -#include +#ifdef TIZEN_BT_A2DP_SINK_AUTO_CONNECT +#include #endif +#include #include "bluetooth-api.h" #include "bt-internal-types.h" @@ -32,35 +30,61 @@ #include "bt-service-audio.h" #include "bt-service-adapter.h" #include "bt-service-common.h" +#include "bt-service-device.h" #include "bt-service-event.h" #include "bt-service-util.h" +#include "bt-service-headset-connection.h" + +#ifdef TIZEN_SUPPORT_DUAL_HF +#ifdef TIZEN_PROFILE_WEARABLE +#define VCONF_KEY_BT_HOST_BT_MAC_ADDR "db/wms/host_bt_mac" +#endif +#endif + typedef struct { unsigned int type; int device_state; char device_address[BT_ADDRESS_STRING_SIZE + 1]; } bt_connected_headset_data_t; +#ifdef TIZEN_BT_A2DP_SINK_AUTO_CONNECT +typedef struct { + int alarm_id; + int retry_count; +} bt_auto_connect_timer_t; + +bt_auto_connect_timer_t auto_connect_timer = {0, }; +#endif + static GList *g_connected_list; static bt_headset_wait_t *g_wait_data; +static bt_audio_function_data_t *pdata; + static void __bt_remove_device_from_wait_list(); static void __bt_free_wait_data(); -static void __bt_audio_request_cb(DBusGProxy *proxy, DBusGProxyCall *call, +static gboolean __bt_device_support_uuid(char *remote_address, + bt_audio_type_t type); + +#ifdef TIZEN_BT_A2DP_SINK_AUTO_CONNECT +static int __bt_auto_connect_alarm_cb(alarm_id_t alarm_id, void* user_param); +#endif + +static void __bt_hf_request_cb(GDBusProxy *proxy, GAsyncResult *res, gpointer user_data) { GError *g_error = NULL; - GArray *out_param1 = NULL; - GArray *out_param2 = NULL; + GVariant *out_param1 = NULL; + GVariant *reply = NULL; int result = BLUETOOTH_ERROR_NONE; bt_function_data_t *func_data; request_info_t *req_info; - dbus_g_proxy_end_call(proxy, call, &g_error, G_TYPE_INVALID); - + reply = g_dbus_proxy_call_finish(proxy, res, &g_error); g_object_unref(proxy); func_data = user_data; @@ -77,127 +101,167 @@ static void __bt_audio_request_cb(DBusGProxy *proxy, DBusGProxyCall *call, goto done; } - if (g_error == NULL) - goto dbus_return; - - BT_ERR("Audio Connect Dbus Call Error: %s\n", g_error->message); - - result = BLUETOOTH_ERROR_INTERNAL; - - /* Remove the device from the list */ - _bt_remove_headset_from_list(BT_AUDIO_ALL, func_data->address); - - /* Error, check if any waiting device is there */ - if (g_wait_data == NULL) - goto dbus_return; - - if (g_strcmp0(g_wait_data->address, func_data->address) != 0) { - bluetooth_device_address_t device_address; - _bt_convert_addr_string_to_type(device_address.addr, - g_wait_data->address); - _bt_audio_connect(g_wait_data->req_id, g_wait_data->type, - &device_address, g_wait_data->out_param1); + if (reply == NULL) { + BT_ERR("HF Connect Dbus Call Error"); + result = _bt_convert_gerror(g_error); + if (g_error) { + BT_ERR("Error: %s\n", g_error->message); + g_clear_error(&g_error); + } + } else { + g_variant_unref(reply); } - /* Event will be sent by the event reciever */ -dbus_return: if (req_info->context == NULL) goto done; - out_param1 = g_array_new(FALSE, FALSE, sizeof(gchar)); - out_param2 = g_array_new(FALSE, FALSE, sizeof(gchar)); - - g_array_append_vals(out_param1, func_data->address, - BT_ADDRESS_STR_LEN); - g_array_append_vals(out_param2, &result, sizeof(int)); + out_param1 = g_variant_new_from_data((const GVariantType *)"ay", + func_data->address, BT_ADDRESS_STR_LEN, TRUE, NULL, NULL); - dbus_g_method_return(req_info->context, out_param1, out_param2); - - g_array_free(out_param1, TRUE); - g_array_free(out_param2, TRUE); + g_dbus_method_invocation_return_value(req_info->context, + g_variant_new("(iv)", result, out_param1)); _bt_delete_request_list(req_info->req_id); -done: - if (g_error) - g_error_free(g_error); +done: if (func_data) { g_free(func_data->address); g_free(func_data); } } -static char *__bt_get_audio_path(bluetooth_device_address_t *address) +void _bt_audio_check_pending_connect() { + BT_DBG("+"); + bluetooth_device_address_t device_address; - char *object_path = NULL; - char addr_str[BT_ADDRESS_STRING_SIZE + 1] = { 0 }; - DBusGProxy *audio_proxy; - DBusGProxy *adapter_proxy; - DBusGConnection *g_conn; - GError *error = NULL; + if (pdata == NULL) + return; - retv_if(address == NULL, NULL); + if (pdata->pending == BT_PENDING_CONNECT) { - g_conn = _bt_get_system_gconn(); - retv_if(g_conn == NULL, NULL); + _bt_convert_addr_string_to_type(device_address.addr, + pdata->address); + _bt_audio_connect(pdata->req_id, + BT_AUDIO_A2DP, + &device_address, + NULL); + + g_free(pdata->address); + g_free(pdata); + pdata = NULL; + } - adapter_proxy = _bt_get_adapter_proxy(); - retv_if(adapter_proxy == NULL, NULL); + BT_DBG("-"); + return; +} - _bt_convert_addr_type_to_string(addr_str, address->addr); +static void __bt_audio_request_cb(GDBusProxy *proxy, GAsyncResult *res, + gpointer user_data) +{ + GError *g_error = NULL; + GVariant *out_param1 = NULL; + GVariant *reply = NULL; + int result = BLUETOOTH_ERROR_NONE; + bt_audio_function_data_t *func_data; + request_info_t *req_info; - object_path = _bt_get_device_object_path(addr_str); + reply = g_dbus_proxy_call_finish(proxy, res, &g_error); + g_object_unref(proxy); + g_variant_unref(reply); - retv_if(object_path == NULL, BLUETOOTH_ERROR_NOT_FOUND); + func_data = user_data; - audio_proxy = dbus_g_proxy_new_for_name(g_conn, - BT_BLUEZ_NAME, - object_path, - BT_HFP_AGENT_INTERFACE); + if (func_data == NULL) { + /* Send reply */ + BT_ERR("func_data == NULL"); + goto done; + } - retv_if(audio_proxy == NULL, NULL); + if (func_data->pending != BT_PENDING_NONE && g_error == NULL) { + bluetooth_device_address_t device_address; + _bt_convert_addr_string_to_type(device_address.addr, + func_data->address); - g_object_unref(audio_proxy); + if (func_data->pending == BT_PENDING_CONNECT) { - return object_path; -} + if (__bt_device_support_uuid(func_data->address, + BT_AUDIO_A2DP)) { -static char *__bt_get_connected_audio_path(void) -{ - int i; - guint size; - char *audio_path = NULL; - GArray *device_list; - bluetooth_device_info_t info; + pdata = g_new0(bt_audio_function_data_t, 1); + pdata->req_id = func_data->req_id; + pdata->address = strdup(func_data->address); + pdata->pending = func_data->pending; + } else + goto check_req_info; - /* allocate the g_pointer_array */ - device_list = g_array_new(FALSE, FALSE, sizeof(gchar)); + } else { + if (_bt_is_service_connected(func_data->address + , BT_AUDIO_HSP)) { + _bt_audio_disconnect(func_data->req_id, + BT_AUDIO_HSP, &device_address, NULL); + } else + goto check_req_info; + } - if (_bt_get_bonded_devices(&device_list) - != BLUETOOTH_ERROR_NONE) { - g_array_free(device_list, TRUE); - return NULL; + goto done; } - size = device_list->len; - size = (device_list->len) / sizeof(bluetooth_device_info_t); +check_req_info: + req_info = _bt_get_request_info(func_data->req_id); + if (req_info == NULL) { + BT_ERR("req_info == NULL"); + goto done; + } - for (i = 0; i < size; i++) { + if (g_error == NULL) + goto dbus_return; - info = g_array_index(device_list, - bluetooth_device_info_t, i); + BT_ERR("Audio Connect/Disconnect Dbus Call Error: %s\n", g_error->message); - if (info.connected == TRUE) { - audio_path = __bt_get_audio_path(&info.device_address); - if (audio_path) - break; - } + result = BLUETOOTH_ERROR_INTERNAL; + /* If there is error then we need to set local initiated connection as false + * If don't do this then when headset initiate connection for HFP then we don't + * initiate connection for A2dp to headset as this flag was set to true in first + * connection failure attempt and not set in error case.*/ + _bt_headset_set_local_connection(FALSE); + + /* Remove the device from the list */ + _bt_remove_headset_from_list(func_data->type, func_data->address); + + /* Error, check if any waiting device is there */ + if (g_wait_data == NULL) + goto dbus_return; + + if (g_strcmp0(g_wait_data->address, func_data->address) != 0) { + bluetooth_device_address_t device_address; + _bt_convert_addr_string_to_type(device_address.addr, + g_wait_data->address); + _bt_audio_connect(g_wait_data->req_id, g_wait_data->type, + &device_address, NULL); + } + + /* Event will be sent by the event reciever */ +dbus_return: + if (req_info->context == NULL) { + BT_DBG("req_info->context is NULL"); + goto done; } - g_array_free(device_list, TRUE); + out_param1 = g_variant_new_from_data((const GVariantType *)"ay", + func_data->address, BT_ADDRESS_STR_LEN, TRUE, NULL, NULL); + + g_dbus_method_invocation_return_value(req_info->context, + g_variant_new("(iv)", result, out_param1)); - return audio_path; + _bt_delete_request_list(req_info->req_id); +done: + g_clear_error(&g_error); + + if (func_data) { + g_free(func_data->address); + g_free(func_data); + } } static void __bt_free_wait_data() @@ -212,8 +276,7 @@ static void __bt_free_wait_data() static void __bt_remove_device_from_wait_list() { /* Before deleting the request update the UI */ - GArray *out_param_1 = NULL; - GArray *out_param_2 = NULL; + GVariant *out_param_1 = NULL; int result = BLUETOOTH_ERROR_INTERNAL; request_info_t *req_info; @@ -223,15 +286,12 @@ static void __bt_remove_device_from_wait_list() return; } - out_param_1 = g_array_new(FALSE, FALSE, sizeof(gchar)); - out_param_2 = g_array_new(FALSE, FALSE, sizeof(gchar)); - g_array_append_vals(out_param_1, g_wait_data->address, - BT_ADDRESS_STR_LEN); - g_array_append_vals(out_param_2, &result, sizeof(int)); - dbus_g_method_return(req_info->context, - out_param_1, out_param_2); - g_array_free(out_param_1, TRUE); - g_array_free(out_param_2, TRUE); + out_param_1 = g_variant_new_from_data((const GVariantType *)"ay", + g_wait_data->address, BT_ADDRESS_STR_LEN, TRUE, NULL, NULL); + + g_dbus_method_invocation_return_value(req_info->context, + g_variant_new("(iv)", result, out_param_1)); + _bt_delete_request_list(g_wait_data->req_id); } @@ -240,8 +300,6 @@ static void __bt_set_headset_disconnection_type(const char *address) bt_connected_headset_data_t *connected_device; GList *node; - BT_DBG("__bt_set_headset_disconnection_type \n"); - node = g_list_first(g_connected_list); while (node != NULL) { connected_device = node->data; @@ -257,8 +315,6 @@ gboolean _bt_is_headset_type_connected(int type, char *address) { GList *node; - BT_DBG("_bt_is_headset_type_connected \n"); - node = g_list_first(g_connected_list); while (node != NULL) { bt_connected_headset_data_t *connected_device = node->data; @@ -275,45 +331,145 @@ gboolean _bt_is_headset_type_connected(int type, char *address) return FALSE; } -static gboolean __bt_is_headset_connected(int type, int req_id, - const char *address, GArray **out_param1) +#ifdef TIZEN_SUPPORT_DUAL_HF +gboolean __bt_is_companion_device(const char *addr) { - gboolean connected; +#ifdef TIZEN_PROFILE_WEARABLE + char *host_device_address = NULL; + host_device_address = vconf_get_str(VCONF_KEY_BT_HOST_BT_MAC_ADDR); + + if (!host_device_address) { + BT_INFO("Failed to get a companion device address"); + return FALSE; + } + + if (g_strcmp0(host_device_address, addr) == 0) { + BT_INFO("Found companion device"); + free(host_device_address); + return TRUE; + } + + free(host_device_address); + return FALSE; +#else + /* TODO : Need to add companion device check condition for Phone models */ + return FALSE; +#endif +} +#endif + +static int __bt_is_headset_connected(int type, int req_id, + const char *address) +{ + gboolean connected = FALSE; char connected_address[BT_ADDRESS_STRING_SIZE + 1]; bluetooth_device_address_t device_address; - - BT_DBG("__bt_is_headset_connected \n"); + bt_connected_headset_data_t *connected_device = NULL; +#ifdef TIZEN_SUPPORT_DUAL_HF + gboolean is_companion_device = FALSE; +#endif /* Check if any other headset is connected */ - connected = _bt_is_headset_type_connected(type, connected_address); + GList *node = NULL;; + + node = g_list_first(g_connected_list); + while (node != NULL) { + connected_device = node->data; + if ((connected_device->type & type)) { + g_strlcpy(connected_address, connected_device->device_address, + BT_ADDRESS_STRING_SIZE + 1); +#ifdef TIZEN_SUPPORT_DUAL_HF + is_companion_device = __bt_is_companion_device(connected_address); + BT_INFO(" is_companion_device[%d]", is_companion_device); + + if (!is_companion_device) { + connected = TRUE; + break; + } +#else + connected = TRUE; + break; +#endif + } + node = g_list_next(node); + } if (!connected) - return FALSE; + return BLUETOOTH_ERROR_NOT_CONNECTED; + + BT_DBG("connected headset %s", connected_address); + + if (g_strcmp0(connected_address, address) == 0) + return BLUETOOTH_ERROR_ALREADY_CONNECT; +#ifdef TIZEN_SUPPORT_DUAL_HF + else if (TRUE == __bt_is_companion_device(address)) + return BLUETOOTH_ERROR_NOT_CONNECTED; +#endif + + /* Convert BD address from string type */ + _bt_convert_addr_string_to_type(device_address.addr, connected_address); + int value = BLUETOOTH_ERROR_NONE; + value = _bt_audio_disconnect(0, connected_device->type & type, &device_address, NULL); /* 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(); - __bt_free_wait_data(); + if (value == BLUETOOTH_ERROR_NONE) { + if (g_wait_data != NULL) { + if (g_strcmp0(g_wait_data->address, address) != 0) { + __bt_remove_device_from_wait_list(); + __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->req_id = req_id; + g_wait_data->type = type; + g_wait_data->ag_flag = FALSE; + + /* Set disconnection type */ + __bt_set_headset_disconnection_type(connected_address); + } + } + + return value; +} + +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) + return BLUETOOTH_ERROR_CONNECTION_BUSY; + node = g_list_next(node); } - 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->req_id = req_id; - g_wait_data->type = type; - g_wait_data->ag_flag = FALSE; - g_wait_data->out_param1 = out_param1; + return BLUETOOTH_ERROR_NONE; +} + +int __bt_is_headset_disconnecting(int type) +{ + bt_connected_headset_data_t *connected_device = NULL; - /* Set disconnection type */ - __bt_set_headset_disconnection_type(connected_address); + /* 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); } - /* Convert BD adress from string type */ - _bt_convert_addr_string_to_type(device_address.addr, connected_address); - _bt_audio_disconnect(0, type, &device_address, NULL); - return TRUE; + return BLUETOOTH_ERROR_NONE; } void _bt_set_audio_wait_data_flag(gboolean flag) @@ -328,6 +484,12 @@ bt_headset_wait_t *_bt_get_audio_wait_data(void) return g_wait_data; } +void _bt_rel_wait_data(void) +{ + BT_DBG("_bt_rel_wait_data \n"); + __bt_free_wait_data(); +} + void _bt_add_headset_to_list(int type, int status, const char *address) { bt_connected_headset_data_t *connected_device; @@ -342,7 +504,8 @@ void _bt_add_headset_to_list(int type, int status, const char *address) if (g_strcmp0(device->device_address, address) == 0) { BT_DBG("Address match, update connection type \n"); - device->type |= type; + if (status == BT_STATE_CONNECTED) + device->type |= type; device->device_state = status; return; } @@ -350,13 +513,35 @@ void _bt_add_headset_to_list(int type, int status, const char *address) } connected_device = g_malloc0(sizeof(bt_connected_headset_data_t)); - connected_device->type |= type; + connected_device->device_state = status; + 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)); + sizeof(connected_device->device_address)); g_connected_list = g_list_append(g_connected_list, connected_device); } +int _bt_get_device_state_from_list(int type, const char *address) +{ + GList *node; + bt_connected_headset_data_t *device; + + BT_DBG("+"); + node = g_list_first(g_connected_list); + while (node != NULL) { + device = (bt_connected_headset_data_t *)node->data; + if (g_strcmp0(device->device_address, address) == 0) { + BT_DBG("Device found"); + return device->device_state; + } + node = g_list_next(node); + } + + BT_DBG("Device not found"); + return BLUETOOTH_ERROR_INTERNAL; +} + void _bt_remove_headset_from_list(int type, const char *address) { GList *node; @@ -389,6 +574,13 @@ void _bt_remove_headset_from_list(int type, const char *address) if (connected_device->type & BT_AUDIO_ALL) connected_device->type &= ~(BT_AUDIO_ALL); break; + case BT_AVRCP: + 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); @@ -396,29 +588,124 @@ void _bt_remove_headset_from_list(int type, const char *address) if (connected_device->type == 0x00) { 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); + } +} + +static gboolean __bt_device_support_uuid(char *remote_address, + bt_audio_type_t type) +{ + GArray *dev_list = NULL; + int size; + int i; + int j; + bluetooth_device_info_t *info; + char bond_address[BT_ADDRESS_STRING_SIZE] = { 0 }; + gboolean ret = FALSE; + + BT_DBG("+"); + + dev_list = g_array_new(FALSE, FALSE, sizeof(gchar)); + + _bt_get_bonded_devices(&dev_list); + size = (dev_list->len) / sizeof(bluetooth_device_info_t); + + for (i = 0; i < size; i++) { + info = &g_array_index(dev_list, bluetooth_device_info_t, i); + _bt_convert_addr_type_to_string(bond_address, + info->device_address.addr); + if (strcmp(bond_address, remote_address) != 0) + continue; + + BT_INFO("Device address Matched"); + j = 0; + while (j != info->service_index) { + if (type == BT_AUDIO_HSP) { + if (strcmp(info->uuids[j], HFP_HS_UUID) == 0) { + BT_INFO("HFP HS UUID exists"); + ret = TRUE; + goto end; + } + } else if (type == BT_AUDIO_A2DP) { + if (strcmp(info->uuids[j], A2DP_SINK_UUID) == 0) { + BT_INFO("A2DP SINK UUID exists"); + ret = TRUE; + goto end; + } + } + j++; + } + } +end: + g_array_free(dev_list, TRUE); + BT_DBG("-"); + return ret; +} + +gboolean _bt_is_service_connected(char* address, int type) +{ + GList *node; + + node = g_list_first(g_connected_list); + while (node != NULL) { + bt_connected_headset_data_t *conn_device = node->data; + + if ((g_strcmp0(conn_device->device_address, address) == 0) && + (conn_device->type & type)) { + BT_INFO("Service connected"); + return TRUE; } node = g_list_next(node); } + BT_INFO("Service not connected"); + return FALSE; } int _bt_audio_connect(int request_id, int type, bluetooth_device_address_t *device_address, - GArray **out_param1) + GArray *out_param1) { int result = BLUETOOTH_ERROR_NONE; - gchar *device_path = NULL; - char *uuid = NULL; char address[BT_ADDRESS_STRING_SIZE] = { 0 }; - bt_function_data_t *func_data; - DBusGProxy *adapter_proxy; - DBusGProxy *profile_proxy; - DBusGConnection *g_conn; + GDBusProxy *adapter_proxy; + GDBusConnection *g_conn; + int ret; + char *uuid = NULL; + int value = BLUETOOTH_ERROR_NONE; + bt_audio_function_data_t *func_data; + guint hfp_hs_restricted = 0x0; /* set default "allowed" */ + guint a2dp_restricted = 0x0; BT_CHECK_PARAMETER(device_address, return); + adapter_proxy = _bt_get_adapter_proxy(); + retv_if(adapter_proxy == NULL, BLUETOOTH_ERROR_INTERNAL); + + g_conn = _bt_gdbus_get_system_gconn(); + retv_if(g_conn == NULL, BLUETOOTH_ERROR_INTERNAL); + _bt_convert_addr_type_to_string(address, device_address->addr); + func_data = g_malloc0(sizeof(bt_audio_function_data_t)); + + func_data->address = g_strdup(address); + func_data->req_id = request_id; + func_data->type = type; + func_data->pending = BT_PENDING_NONE; + + result = _bt_get_restrict_profile(device_address, RESTRICTED_PROFILE_HFP_HS, &hfp_hs_restricted); + if (result != BLUETOOTH_ERROR_NONE) + BT_ERR("Can't get hfp_hs restriction info"); + + result = _bt_get_restrict_profile(device_address, RESTRICTED_PROFILE_A2DP, &a2dp_restricted); + if (result != BLUETOOTH_ERROR_NONE) + BT_ERR("Can't get a2dp restriction info"); + switch (type) { case BT_AUDIO_HSP: uuid = HFP_HS_UUID; @@ -426,87 +713,95 @@ int _bt_audio_connect(int request_id, int type, case BT_AUDIO_A2DP: uuid = A2DP_SINK_UUID; break; + case BT_AVRCP: + uuid = AVRCP_TARGET_UUID; + break; + case BT_AUDIO_A2DP_SOURCE: + uuid = A2DP_SOURCE_UUID; + break; case BT_AUDIO_ALL: - uuid = GENERIC_AUDIO_UUID; + if ((hfp_hs_restricted == 0x0) && (a2dp_restricted == 0x0)) { /* in case of both profiles are not restricted */ + if (__bt_device_support_uuid(address, BT_AUDIO_HSP)) { + uuid = HFP_HS_UUID; + func_data->pending = BT_PENDING_CONNECT; + type = BT_AUDIO_HSP; + } else if (__bt_device_support_uuid(address, BT_AUDIO_A2DP)) { + uuid = A2DP_SINK_UUID; + type = BT_AUDIO_A2DP; + } else { + BT_ERR("No audio role supported"); + result = BLUETOOTH_ERROR_SERVICE_NOT_FOUND; + goto fail; + } + } else if ((hfp_hs_restricted == 0x1) && (a2dp_restricted == 0x1)) { /* in case of both profiles are restricted */ + BT_ERR("All profiles are restricted"); + result = BLUETOOTH_ERROR_INTERNAL; + goto fail; + } else if (a2dp_restricted == 0x01) { /* in case of a2dp is restricted, only connection for hfp_hs */ + if (__bt_device_support_uuid(address, BT_AUDIO_HSP)) { + uuid = HFP_HS_UUID; + type = BT_AUDIO_HSP; + } else { + BT_ERR("HFP_HS role is not supported"); + result = BLUETOOTH_ERROR_SERVICE_NOT_FOUND; + goto fail; + } + } else if (hfp_hs_restricted == 0x01) { /* in case of hfp_hs is restricted, only connection for a2dp */ + if (__bt_device_support_uuid(address, BT_AUDIO_A2DP)) { + uuid = A2DP_SINK_UUID; + type = BT_AUDIO_A2DP; + } else { + BT_ERR("A2DP role is not supported"); + result = BLUETOOTH_ERROR_SERVICE_NOT_FOUND; + goto fail; + } + } + break; + case BT_AVRCP_TARGET: + uuid = AVRCP_REMOTE_UUID; break; default: BT_ERR("Unknown role"); result = BLUETOOTH_ERROR_INTERNAL; goto fail; } + BT_INFO("Connecting to service %s", uuid); - if (__bt_is_headset_connected(type, request_id, address, out_param1)) - return BLUETOOTH_ERROR_NONE; - - adapter_proxy = _bt_get_adapter_proxy(); - if (adapter_proxy == NULL) { - result = BLUETOOTH_ERROR_INTERNAL; - goto fail; - } - - device_path = _bt_get_device_object_path(address); - if (device_path == NULL) { - result = BLUETOOTH_ERROR_INTERNAL; - goto fail; - } - - g_conn = _bt_get_system_gconn(); - if (g_conn == NULL) { - result = BLUETOOTH_ERROR_INTERNAL; - goto fail; - } - - profile_proxy = dbus_g_proxy_new_for_name(g_conn, BT_BLUEZ_NAME, - device_path, BT_DEVICE_INTERFACE); - - g_free(device_path); - - if (profile_proxy == NULL) { - result = BLUETOOTH_ERROR_INTERNAL; - goto fail; - } - - func_data = g_malloc0(sizeof(bt_function_data_t)); - func_data->address = g_strdup(address); - func_data->req_id = request_id; + value = __bt_is_headset_connected(type, request_id, address); - if (g_strcmp0(uuid, GENERIC_AUDIO_UUID) == 0){ - if (!dbus_g_proxy_begin_call(profile_proxy, "Connect", - (DBusGProxyCallNotify)__bt_audio_request_cb, - func_data, NULL, - G_TYPE_INVALID)) { - BT_ERR("Audio connect Dbus Call Error"); - g_object_unref(profile_proxy); - - g_free(func_data->address); - g_free(func_data); - - result = BLUETOOTH_ERROR_INTERNAL; + if (value == BLUETOOTH_ERROR_ALREADY_CONNECT) { + return BLUETOOTH_ERROR_ALREADY_CONNECT; + } else if (value == BLUETOOTH_ERROR_NOT_CONNECTED) { + value = __bt_is_headset_connecting(type); + if (value != BLUETOOTH_ERROR_NONE) { + result = BLUETOOTH_ERROR_IN_PROGRESS; goto fail; } - }else { - if (!dbus_g_proxy_begin_call(profile_proxy, "ConnectProfile", - (DBusGProxyCallNotify)__bt_audio_request_cb, - func_data, NULL, - G_TYPE_STRING, uuid, - G_TYPE_INVALID)) { - BT_ERR("Audio connect Dbus Call Error"); - g_object_unref(profile_proxy); + _bt_headset_set_local_connection(TRUE); + ret = _bt_connect_profile(address, uuid, + __bt_audio_request_cb, func_data); + if (ret != BLUETOOTH_ERROR_NONE) { + BT_ERR("_bt_connect_profile Error"); + _bt_headset_set_local_connection(FALSE); g_free(func_data->address); g_free(func_data); - - result = BLUETOOTH_ERROR_INTERNAL; - goto fail; + return ret; } + + /* Add data to the connected list */ + _bt_add_headset_to_list(type, BT_STATE_CONNECTING, address); + } else if (value == BLUETOOTH_ERROR_IN_PROGRESS) { + return BLUETOOTH_ERROR_IN_PROGRESS; } - /* Add data to the connected list */ - _bt_add_headset_to_list(type, BT_STATE_CONNECTING, address); - __bt_free_wait_data(); + + if (out_param1) + g_array_free(out_param1, TRUE); return BLUETOOTH_ERROR_NONE; fail: - g_array_append_vals(*out_param1, address, + if (out_param1 != NULL) + g_array_append_vals(out_param1, address, BT_ADDRESS_STR_LEN); return result; @@ -514,21 +809,34 @@ fail: int _bt_audio_disconnect(int request_id, int type, bluetooth_device_address_t *device_address, - GArray **out_param1) + GArray *out_param1) { int result = BLUETOOTH_ERROR_NONE; - gchar *device_path = NULL; - char *uuid = NULL; char address[BT_ADDRESS_STRING_SIZE] = { 0 }; - bt_function_data_t *func_data; - DBusGProxy *adapter_proxy; - DBusGProxy *profile_proxy; - DBusGConnection *g_conn; + bt_audio_function_data_t *func_data; + GDBusProxy *adapter_proxy; + GDBusConnection *g_conn; + GList *node; + int ret; + char *uuid; + int value = BLUETOOTH_ERROR_NONE; BT_CHECK_PARAMETER(device_address, return); + adapter_proxy = _bt_get_adapter_proxy(); + retv_if(adapter_proxy == NULL, BLUETOOTH_ERROR_INTERNAL); + + g_conn = _bt_gdbus_get_system_gconn(); + retv_if(g_conn == NULL, BLUETOOTH_ERROR_INTERNAL); + _bt_convert_addr_type_to_string(address, device_address->addr); + func_data = g_malloc0(sizeof(bt_audio_function_data_t)); + func_data->address = g_strdup(address); + func_data->req_id = request_id; + func_data->pending = BT_PENDING_NONE; + func_data->type = type; + switch (type) { case BT_AUDIO_HSP: uuid = HFP_HS_UUID; @@ -536,13 +844,112 @@ int _bt_audio_disconnect(int request_id, int type, case BT_AUDIO_A2DP: uuid = A2DP_SINK_UUID; break; + case BT_AVRCP: + uuid = AVRCP_TARGET_UUID; + break; + case BT_AUDIO_A2DP_SOURCE: + uuid = A2DP_SOURCE_UUID; + break; case BT_AUDIO_ALL: - uuid = GENERIC_AUDIO_UUID; + if (_bt_is_service_connected(address, BT_AUDIO_A2DP)) { + uuid = A2DP_SINK_UUID; + func_data->pending = BT_PENDING_DISCONNECT; + } else if (_bt_is_service_connected(address, BT_AUDIO_HSP)) { + uuid = HFP_HS_UUID; + } else { + BT_ERR("No audio service connected"); + result = BLUETOOTH_ERROR_NOT_CONNECTED; + goto fail; + } + break; + case BT_AVRCP_TARGET: + uuid = AVRCP_REMOTE_UUID; break; default: BT_ERR("Unknown role"); - return BLUETOOTH_ERROR_INTERNAL; + result = BLUETOOTH_ERROR_INTERNAL; + goto fail; + } + value = __bt_is_headset_disconnecting(type); + if (value != BLUETOOTH_ERROR_NONE) { + BT_INFO("Disconnect in progress"); + result = BLUETOOTH_ERROR_IN_PROGRESS; + goto fail; + } + BT_INFO("Disconnecting service %s", uuid); + ret = _bt_disconnect_profile(address, uuid, + __bt_audio_request_cb, func_data); + + if (ret != BLUETOOTH_ERROR_NONE) { + BT_ERR("_bt_disconnect_profile Error"); + g_free(func_data->address); + g_free(func_data); + return ret; + } + + /* + * 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, address) == 0) { + BT_DBG("Connection type update"); + type = connected_device->type; + break; + } + node = g_list_next(node); + } + _bt_add_headset_to_list(type, BT_STATE_DISCONNECTING, address); + + if (out_param1) + g_array_free(out_param1, TRUE); + + return BLUETOOTH_ERROR_NONE; +fail: + if (out_param1 != NULL) + g_array_append_vals(out_param1, address, + BT_ADDRESS_STR_LEN); + + return result; +} + +void _bt_remove_from_connected_list(const char *address) +{ + bt_connected_headset_data_t *connected_device; + GList *node; + + node = g_list_first(g_connected_list); + while (node != NULL) { + connected_device = node->data; + if (connected_device != NULL && + g_strcmp0(connected_device->device_address, address) == 0) { + BT_ERR("Device is removed from the list"); + g_connected_list = g_list_remove(g_connected_list, connected_device); + g_free(connected_device); + return; + } + node = g_list_next(node); } +} + +int _bt_hf_connect(int request_id, + bluetooth_device_address_t *device_address, + GArray *out_param1) +{ + int result = BLUETOOTH_ERROR_NONE; + char address[BT_ADDRESS_STRING_SIZE] = { 0 }; + bt_function_data_t *func_data; + GDBusProxy *adapter_proxy; + GDBusConnection *g_conn; + gboolean connected = FALSE; + int ret; + char *uuid; + + BT_CHECK_PARAMETER(device_address, return); + + _bt_convert_addr_type_to_string(address, device_address->addr); adapter_proxy = _bt_get_adapter_proxy(); if (adapter_proxy == NULL) { @@ -550,176 +957,295 @@ int _bt_audio_disconnect(int request_id, int type, goto fail; } - device_path = _bt_get_device_object_path(address); - if (device_path == NULL) { + g_conn = _bt_gdbus_get_system_gconn(); + if (g_conn == NULL) { result = BLUETOOTH_ERROR_INTERNAL; goto fail; } - g_conn = _bt_get_system_gconn(); - if (g_conn == NULL) { - result = BLUETOOTH_ERROR_INTERNAL; + /* Check if HF is connected or not */ + result = _bt_is_device_connected(device_address, BT_PROFILE_CONN_HFG, &connected); + if (connected == TRUE) { + BT_ERR("HF is already connected"); + result = BLUETOOTH_ERROR_ALREADY_CONNECT; goto fail; } - profile_proxy = dbus_g_proxy_new_for_name(g_conn, BT_BLUEZ_NAME, - device_path, BT_DEVICE_INTERFACE); + func_data = g_malloc0(sizeof(bt_function_data_t)); + func_data->address = g_strdup(address); + func_data->req_id = request_id; + uuid = g_strdup(HFP_AG_UUID); + + BT_DBG("Connecting to service %s", uuid); + + ret = _bt_connect_profile(address, uuid, + __bt_hf_request_cb, func_data); + + if (ret != BLUETOOTH_ERROR_NONE) { + BT_ERR("_bt_connect_profile Error"); + g_free(func_data->address); + g_free(func_data); + g_free(uuid); + return ret; + } + g_free(uuid); + if (out_param1) + g_array_free(out_param1, TRUE); + + return BLUETOOTH_ERROR_NONE; +fail: + if (out_param1 != NULL) + g_array_append_vals(out_param1, address, + BT_ADDRESS_STR_LEN); + + return result; +} + +int _bt_hf_disconnect(int request_id, + bluetooth_device_address_t *device_address, + GArray *out_param1) +{ + int result = BLUETOOTH_ERROR_NONE; + char address[BT_ADDRESS_STRING_SIZE] = { 0 }; + bt_function_data_t *func_data; + GDBusProxy *adapter_proxy; + GDBusConnection *g_conn; + + int ret; + char *uuid; + + BT_CHECK_PARAMETER(device_address, return); + + _bt_convert_addr_type_to_string(address, device_address->addr); - g_free(device_path); + adapter_proxy = _bt_get_adapter_proxy(); + if (adapter_proxy == NULL) { + result = BLUETOOTH_ERROR_INTERNAL; + goto fail; + } - if (profile_proxy == NULL) { + g_conn = _bt_gdbus_get_system_gconn(); + if (g_conn == NULL) { result = BLUETOOTH_ERROR_INTERNAL; goto fail; } - if (g_wait_data != NULL) { - if (g_strcmp0(uuid, GENERIC_AUDIO_UUID) == 0){ - if (!dbus_g_proxy_begin_call(profile_proxy, - "Disconnect",NULL, NULL, NULL, - G_TYPE_INVALID)) { - BT_ERR("Audio disconnect Dbus Call Error"); - g_object_unref(profile_proxy); - return BLUETOOTH_ERROR_INTERNAL; - } - } else { - if (!dbus_g_proxy_begin_call(profile_proxy, - "DisconnectProfile",NULL, NULL, NULL, - G_TYPE_STRING, uuid, - G_TYPE_INVALID)) { - BT_ERR("Audio disconnect Dbus Call Error"); - g_object_unref(profile_proxy); - return BLUETOOTH_ERROR_INTERNAL; - } - } - } else { - func_data = g_malloc0(sizeof(bt_function_data_t)); - func_data->address = g_strdup(address); - func_data->req_id = request_id; - if (g_strcmp0(uuid, GENERIC_AUDIO_UUID) == 0){ - if (!dbus_g_proxy_begin_call(profile_proxy, - "Disconnect", - (DBusGProxyCallNotify)__bt_audio_request_cb, - func_data, NULL, - G_TYPE_INVALID)) { - BT_ERR("Audio disconnect Dbus Call Error"); - g_object_unref(profile_proxy); - - g_free(func_data->address); - g_free(func_data); - - result = BLUETOOTH_ERROR_INTERNAL; - goto fail; - } - } else { - if (!dbus_g_proxy_begin_call(profile_proxy, - "DisconnectProfile", - (DBusGProxyCallNotify)__bt_audio_request_cb, - func_data, NULL, - G_TYPE_STRING, uuid, - G_TYPE_INVALID)) { - BT_ERR("Audio disconnect Dbus Call Error"); - g_object_unref(profile_proxy); - - g_free(func_data->address); - g_free(func_data); - - result = BLUETOOTH_ERROR_INTERNAL; - goto fail; - } - } + func_data = g_malloc0(sizeof(bt_function_data_t)); + func_data->address = g_strdup(address); + func_data->req_id = request_id; + uuid = g_strdup(HFP_AG_UUID); + + BT_DBG("Disconnecting service %s", uuid); + ret = _bt_disconnect_profile(address, uuid, + __bt_hf_request_cb, func_data); + + if (ret != BLUETOOTH_ERROR_NONE) { + BT_ERR("_bt_disconnect_profile Error"); + g_free(func_data->address); + g_free(func_data); + g_free(uuid); + return ret; } + g_free(uuid); + if (out_param1) + g_array_free(out_param1, TRUE); return BLUETOOTH_ERROR_NONE; fail: - g_array_append_vals(*out_param1, address, + if (out_param1 != NULL) + g_array_append_vals(out_param1, address, BT_ADDRESS_STR_LEN); return result; } -int _bt_audio_get_speaker_gain(unsigned int *gain) +int _bt_audio_set_content_protect(gboolean status) { - char *device_path = NULL; - DBusGProxy *adapter_proxy; - DBusGProxy *profile_proxy; - DBusGConnection *g_conn; - GHashTable *hash = NULL; - GValue *value; + GDBusConnection *conn; + GError *error = NULL; - adapter_proxy = _bt_get_adapter_proxy(); - retv_if(adapter_proxy == NULL, BLUETOOTH_ERROR_INTERNAL); + BT_DBG("+\n"); - g_conn = _bt_get_system_gconn(); - retv_if(g_conn == NULL, BLUETOOTH_ERROR_INTERNAL); + conn = _bt_gdbus_get_system_gconn(); + retv_if(conn == NULL, BLUETOOTH_ERROR_INTERNAL); - device_path = __bt_get_connected_audio_path(); - retv_if(device_path == NULL, BLUETOOTH_ERROR_NOT_CONNECTED); + BT_DBG("Content Protection status = [%d]", status); - profile_proxy = dbus_g_proxy_new_for_name(g_conn, BT_BLUEZ_NAME, - device_path, BT_HFP_AGENT_INTERFACE); + g_dbus_connection_emit_signal(conn, + NULL, BT_CONTENT_PROTECTION_PATH, + BT_CONTENT_PROTECTION_INTERFACE, + "ProtectionRequired", + g_variant_new("(b)", status), + &error); - g_free(device_path); + if (error) { + /* dBUS gives error cause */ + ERR("Could not Emit Signal: errCode[%x], message[%s]", + error->code, error->message); + g_clear_error(&error); + return BLUETOOTH_ERROR_INTERNAL; + } - retv_if(profile_proxy == NULL, BLUETOOTH_ERROR_INTERNAL); + BT_DBG("Emit Signal done = [ProtectionRequired]"); + return BLUETOOTH_ERROR_NONE; +} - dbus_g_proxy_call(profile_proxy, "GetProperties", NULL, - G_TYPE_INVALID, - dbus_g_type_get_map("GHashTable", - G_TYPE_STRING, G_TYPE_VALUE), - &hash, G_TYPE_INVALID); +#ifdef TIZEN_BT_A2DP_SINK_AUTO_CONNECT +static void __bt_auto_connect_request_cb(GDBusProxy *proxy, GAsyncResult *res, + gpointer user_data) +{ + GError *err = NULL; + GVariant *reply = NULL; - g_object_unref(profile_proxy); + reply = g_dbus_proxy_call_finish(proxy, res, &err); + g_object_unref(proxy); + g_variant_unref(reply); - retv_if(hash == NULL, BLUETOOTH_ERROR_INTERNAL); + BT_DBG("+"); + if (err != NULL) { + g_dbus_error_strip_remote_error(err); + BT_INFO("Auto_connect_request Dbus Call Error: %s", err->message); - value = g_hash_table_lookup(hash, "SpeakerGain"); - *gain = value ? g_value_get_uint(value) : 0; - g_hash_table_destroy(hash); - return BLUETOOTH_ERROR_NONE; + if (strcmp("Host is down", err->message)) { + BT_INFO("Fail reason is not 'Host Down'. Terminate auto connect"); + _bt_audio_stop_auto_connect(); + vconf_set_str(BT_LAST_CONNECTED_DEVICE, ""); + } + } + g_clear_error(&err); } -int _bt_audio_set_speaker_gain(unsigned int gain) + +// It is the function that retry to create alarm. +// Sometimes alarm mgr service is created later than bluetooth-frwk service in booting time. +// So, in this case, we have to retry alarmmgr_add_alarm. +static gboolean __bt_audio_alarm_retry_cb(gpointer data) { - char *device_path = NULL; - char *gain_str = "SpeakerGain"; - char sig[2] = {DBUS_TYPE_UINT16, '\0'}; - int ret = BLUETOOTH_ERROR_NONE; - DBusMessage *msg; - DBusMessageIter iter; - DBusMessageIter value; - DBusConnection *conn; + int result; + alarm_id_t alarm_id; - conn = _bt_get_system_conn(); - retv_if(conn == NULL, BLUETOOTH_ERROR_INTERNAL); + BT_DBG("__bt_audio_alarm_retry_cb called."); + result = _bt_service_set_alarm(BT_AUTO_CONNECT_TIMEOUT_AFTER_LINKLOSS, + __bt_auto_connect_alarm_cb, NULL, &alarm_id); - device_path = __bt_get_connected_audio_path(); - retv_if(device_path == NULL, BLUETOOTH_ERROR_NOT_CONNECTED); + if (result != BLUETOOTH_ERROR_NONE) + return TRUE; + else + auto_connect_timer.alarm_id = alarm_id; - msg = dbus_message_new_method_call(BT_BLUEZ_NAME, - device_path, BT_HFP_AGENT_INTERFACE, - "SetProperty"); + return FALSE; +} - g_free(device_path); +static int __bt_auto_connect_alarm_cb(alarm_id_t alarm_id, void* user_param) +{ + int result = BLUETOOTH_ERROR_NONE; + char *address = NULL; + alarm_id_t new_alarm_id; - retv_if(msg == NULL, BLUETOOTH_ERROR_INTERNAL); + BT_INFO("alram id = [%d] , retry_count [%d] ", + alarm_id, auto_connect_timer.retry_count); - dbus_message_iter_init_append(msg, &iter); - dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, - &gain_str); - dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, - sig, &value); - dbus_message_iter_append_basic(&value, DBUS_TYPE_UINT16, - &gain); - dbus_message_iter_close_container(&iter, &value); + if (alarm_id != auto_connect_timer.alarm_id) + return 0; - if (dbus_message_get_type(msg) == DBUS_MESSAGE_TYPE_METHOD_CALL) - dbus_message_set_no_reply(msg, TRUE); + address = vconf_get_str(BT_LAST_CONNECTED_DEVICE); - if (!dbus_connection_send(conn, msg, NULL)) { - BT_ERR("Dbus sending failed\n"); - ret = BLUETOOTH_ERROR_INTERNAL; + if (address == NULL) { + BT_ERR("Address vconf is null"); + auto_connect_timer.alarm_id = 0; + return 0; } - dbus_message_unref(msg); - return ret; + BT_DBG("ADDRESS [%s]", address); + + result = _bt_connect_profile(address, A2DP_SOURCE_UUID, + __bt_auto_connect_request_cb, NULL); + + auto_connect_timer.retry_count--; + + BT_DBG("result [%d]", result); + + if (auto_connect_timer.retry_count <= 0) { + BT_INFO(" ### Stopping Auto connect retry"); + auto_connect_timer.alarm_id = 0; + } else { + result = _bt_service_set_alarm(BT_AUTO_CONNECT_TIMEOUT_AFTER_LINKLOSS, + __bt_auto_connect_alarm_cb, NULL, &new_alarm_id); + if (result == BLUETOOTH_ERROR_NONE) + auto_connect_timer.alarm_id = new_alarm_id; + } + + free(address); + return 0; +} + +static void __bt_auto_connect_alarm_remove() +{ + BT_DBG(""); + if (auto_connect_timer.alarm_id > 0) { + _bt_service_remove_alarm(auto_connect_timer.alarm_id); + auto_connect_timer.alarm_id = 0; + } + auto_connect_timer.retry_count = 0; +} + +int _bt_audio_start_auto_connect(gboolean linkloss_flag) +{ + int result = BLUETOOTH_ERROR_NONE; + char *address = NULL; + alarm_id_t alarm_id = 0; + + BT_DBG(""); + + address = vconf_get_str(BT_LAST_CONNECTED_DEVICE); + + if (address == NULL) { + BT_ERR("No target device"); + return 0; + } + + __bt_auto_connect_alarm_remove(); + + auto_connect_timer.retry_count = BT_AUTO_CONNECT_TIMEOUT_RETRY_TIME / + BT_AUTO_CONNECT_TIMEOUT_AFTER_LINKLOSS; + + if (linkloss_flag) { + BT_INFO(" ### Start auto connection after linkloss"); + result = _bt_service_set_alarm(BT_AUTO_CONNECT_TIMEOUT_AFTER_LINKLOSS, + __bt_auto_connect_alarm_cb, NULL, &alarm_id); + if (result != BLUETOOTH_ERROR_NONE) + g_timeout_add(500, (GSourceFunc)__bt_audio_alarm_retry_cb, NULL); + else + auto_connect_timer.alarm_id = alarm_id; + + } else { + BT_INFO(" ### Start auto connection after BT activated"); + result = _bt_service_set_alarm(BT_AUTO_CONNECT_TIMEOUT_AFTER_BT_ACTIVATED, + __bt_auto_connect_alarm_cb, NULL, &alarm_id); + if (result == BLUETOOTH_ERROR_NONE) + auto_connect_timer.alarm_id = alarm_id; + } + + free(address); + return BLUETOOTH_ERROR_NONE; +} + +int _bt_audio_stop_auto_connect(void) +{ + BT_DBG(""); + __bt_auto_connect_alarm_remove(); + + return BLUETOOTH_ERROR_NONE; +} + +void _bt_audio_set_auto_connect_device_addr(const char *address) +{ + if (address == NULL) { + BT_ERR("address is null"); + return; + } + + BT_INFO("Last connected device is [%s]", address); + vconf_set_str(BT_LAST_CONNECTED_DEVICE, address); } +#endif /*TIZEN_BT_A2DP_SINK_AUTO_CONNECT */