X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=bt-service%2Fbt-service-audio.c;h=ff76b58d5b186e5954f4ff1aaecf1bbdc99bf9fe;hb=4d6168053c283df60726c35d3dc99882c1a325b1;hp=a85d4ed30424c2c286fb5434a737b03914085c9a;hpb=45b67c424f9352ccdce42e96542132ac069ddd2b;p=platform%2Fcore%2Fconnectivity%2Fbluetooth-frwk.git diff --git a/bt-service/bt-service-audio.c b/bt-service/bt-service-audio.c index a85d4ed..ff76b58 100644 --- a/bt-service/bt-service-audio.c +++ b/bt-service/bt-service-audio.c @@ -1,11 +1,5 @@ /* - * Bluetooth-frwk - * - * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. - * - * Contact: Hocheol Seo - * Girishashok Joshi - * Chanyeol Park + * 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. @@ -21,14 +15,14 @@ * */ -#include -#include +#include #include #include #include -#if !defined(LIBNOTIFY_SUPPORT) && !defined(LIBNOTIFICATION_SUPPORT) -#include +#ifdef TIZEN_BT_A2DP_SINK_AUTO_CONNECT +#include #endif +#include #include "bluetooth-api.h" #include "bt-internal-types.h" @@ -43,7 +37,7 @@ #include "bt-service-headset-connection.h" #ifdef TIZEN_SUPPORT_DUAL_HF -#ifdef TIZEN_WEARABLE +#ifdef TIZEN_PROFILE_WEARABLE #define VCONF_KEY_BT_HOST_BT_MAC_ADDR "db/wms/host_bt_mac" #endif #endif @@ -54,6 +48,15 @@ typedef struct { 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; @@ -67,18 +70,21 @@ static void __bt_free_wait_data(); static gboolean __bt_device_support_uuid(char *remote_address, bt_audio_type_t type); -static void __bt_hf_request_cb(DBusGProxy *proxy, DBusGProxyCall *call, +#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; @@ -95,34 +101,29 @@ static void __bt_hf_request_cb(DBusGProxy *proxy, DBusGProxyCall *call, goto done; } - if (g_error == NULL) - goto dbus_return; - - BT_ERR("HFG request Dbus Call Error: %s\n", g_error->message); - - result = BLUETOOTH_ERROR_INTERNAL; + 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); + } -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)); - - dbus_g_method_return(req_info->context, out_param1, out_param2); + out_param1 = g_variant_new_from_data((const GVariantType *)"ay", + func_data->address, BT_ADDRESS_STR_LEN, TRUE, NULL, NULL); - 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); @@ -141,11 +142,10 @@ void _bt_audio_check_pending_connect() _bt_convert_addr_string_to_type(device_address.addr, pdata->address); - _bt_audio_connect(pdata->req_id, BT_AUDIO_A2DP, &device_address, - pdata->out_param); + NULL); g_free(pdata->address); g_free(pdata); @@ -156,21 +156,19 @@ void _bt_audio_check_pending_connect() return; } -static void __bt_audio_request_cb(DBusGProxy *proxy, DBusGProxyCall *call, +static void __bt_audio_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_audio_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); + g_variant_unref(reply); func_data = user_data; @@ -181,7 +179,6 @@ static void __bt_audio_request_cb(DBusGProxy *proxy, DBusGProxyCall *call, } 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); @@ -193,20 +190,16 @@ static void __bt_audio_request_cb(DBusGProxy *proxy, DBusGProxyCall *call, pdata = g_new0(bt_audio_function_data_t, 1); pdata->req_id = func_data->req_id; - pdata->out_param = func_data->out_param; pdata->address = strdup(func_data->address); pdata->pending = func_data->pending; } else goto check_req_info; } else { - if (_bt_is_service_connected(func_data->address - , BT_AUDIO_A2DP)) { + , BT_AUDIO_HSP)) { _bt_audio_disconnect(func_data->req_id, - BT_AUDIO_A2DP, - &device_address, - func_data->out_param); + BT_AUDIO_HSP, &device_address, NULL); } else goto check_req_info; } @@ -227,6 +220,11 @@ check_req_info: BT_ERR("Audio Connect/Disconnect Dbus Call Error: %s\n", g_error->message); 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); @@ -240,7 +238,7 @@ check_req_info: _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); + &device_address, NULL); } /* Event will be sent by the event reciever */ @@ -250,22 +248,15 @@ dbus_return: goto done; } - out_param1 = g_array_new(FALSE, FALSE, sizeof(gchar)); - out_param2 = g_array_new(FALSE, FALSE, sizeof(gchar)); + out_param1 = g_variant_new_from_data((const GVariantType *)"ay", + func_data->address, BT_ADDRESS_STR_LEN, TRUE, NULL, NULL); - g_array_append_vals(out_param1, func_data->address, - BT_ADDRESS_STR_LEN); - g_array_append_vals(out_param2, &result, sizeof(int)); - - 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); + g_clear_error(&g_error); if (func_data) { g_free(func_data->address); @@ -273,78 +264,6 @@ done: } } -static char *__bt_get_audio_path(bluetooth_device_address_t *address) -{ - - char *object_path = NULL; - char addr_str[BT_ADDRESS_STRING_SIZE + 1] = { 0 }; - DBusGProxy *audio_proxy; - DBusGProxy *adapter_proxy; - DBusGConnection *g_conn; - - retv_if(address == NULL, NULL); - - g_conn = _bt_get_system_gconn(); - retv_if(g_conn == NULL, NULL); - - adapter_proxy = _bt_get_adapter_proxy(); - retv_if(adapter_proxy == NULL, NULL); - - _bt_convert_addr_type_to_string(addr_str, address->addr); - - object_path = _bt_get_device_object_path(addr_str); - - retv_if(object_path == NULL, BLUETOOTH_ERROR_NOT_FOUND); - - audio_proxy = dbus_g_proxy_new_for_name(g_conn, - BT_BLUEZ_NAME, - object_path, - BT_HFP_AGENT_INTERFACE); - - retv_if(audio_proxy == NULL, NULL); - - g_object_unref(audio_proxy); - - return object_path; -} - -static char *__bt_get_connected_audio_path(void) -{ - int i; - guint size; - char *audio_path = NULL; - GArray *device_list; - bluetooth_device_info_t info; - - /* allocate the g_pointer_array */ - device_list = g_array_new(FALSE, FALSE, sizeof(gchar)); - - if (_bt_get_bonded_devices(&device_list) - != BLUETOOTH_ERROR_NONE) { - g_array_free(device_list, TRUE); - return NULL; - } - - size = device_list->len; - size = (device_list->len) / sizeof(bluetooth_device_info_t); - - for (i = 0; i < size; i++) { - - info = g_array_index(device_list, - bluetooth_device_info_t, i); - - if (info.connected == TRUE) { - audio_path = __bt_get_audio_path(&info.device_address); - if (audio_path) - break; - } - } - - g_array_free(device_list, TRUE); - - return audio_path; -} - static void __bt_free_wait_data() { if (g_wait_data != NULL) { @@ -357,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; @@ -368,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); } @@ -419,7 +334,7 @@ gboolean _bt_is_headset_type_connected(int type, char *address) #ifdef TIZEN_SUPPORT_DUAL_HF gboolean __bt_is_companion_device(const char *addr) { -#ifdef TIZEN_WEARABLE +#ifdef TIZEN_PROFILE_WEARABLE char *host_device_address = NULL; host_device_address = vconf_get_str(VCONF_KEY_BT_HOST_BT_MAC_ADDR); @@ -429,10 +344,12 @@ gboolean __bt_is_companion_device(const char *addr) } if (g_strcmp0(host_device_address, addr) == 0) { - BT_INFO("addr[%s] is companion device", addr); + 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 */ @@ -442,7 +359,7 @@ gboolean __bt_is_companion_device(const char *addr) #endif static int __bt_is_headset_connected(int type, int req_id, - const char *address, GArray **out_param1) + const char *address) { gboolean connected = FALSE; char connected_address[BT_ADDRESS_STRING_SIZE + 1]; @@ -458,7 +375,7 @@ static int __bt_is_headset_connected(int type, int req_id, node = g_list_first(g_connected_list); while (node != NULL) { connected_device = node->data; - if ((connected_device->type & type) == type) { + if ((connected_device->type & type)) { g_strlcpy(connected_address, connected_device->device_address, BT_ADDRESS_STRING_SIZE + 1); #ifdef TIZEN_SUPPORT_DUAL_HF @@ -489,29 +406,69 @@ static int __bt_is_headset_connected(int type, int req_id, 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); } } - 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 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; - /* Set disconnection type */ - __bt_set_headset_disconnection_type(connected_address); + 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); + } + + return BLUETOOTH_ERROR_NONE; +} + +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); } - /* Convert BD adress from string type */ - _bt_convert_addr_string_to_type(device_address.addr, connected_address); - _bt_audio_disconnect(0, connected_device->type & type, &device_address, NULL); return BLUETOOTH_ERROR_NONE; } @@ -556,8 +513,9 @@ 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->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)); @@ -620,6 +578,9 @@ void _bt_remove_headset_from_list(int type, const char *address) 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); @@ -627,6 +588,8 @@ 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); @@ -637,36 +600,38 @@ static gboolean __bt_device_support_uuid(char *remote_address, bt_audio_type_t type) { GArray *dev_list = NULL; - int size,i,j; - bluetooth_device_info_t info; + 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)); + 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); + 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); + info->device_address.addr); if (strcmp(bond_address, remote_address) != 0) continue; BT_INFO("Device address Matched"); j = 0; - while (j != info.service_index) { + while (j != info->service_index) { if (type == BT_AUDIO_HSP) { - if (strcmp(info.uuids[j], HFP_HS_UUID) == 0) { + 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) { + if (strcmp(info->uuids[j], A2DP_SINK_UUID) == 0) { BT_INFO("A2DP SINK UUID exists"); ret = TRUE; goto end; @@ -703,23 +668,25 @@ gboolean _bt_is_service_connected(char* address, int type) 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; char address[BT_ADDRESS_STRING_SIZE] = { 0 }; - DBusGProxy *adapter_proxy; - DBusGConnection *g_conn; + GDBusProxy *adapter_proxy; + GDBusConnection *g_conn; int ret; - char *uuid; + 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_get_system_gconn(); + 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); @@ -730,7 +697,14 @@ int _bt_audio_connect(int request_id, int type, func_data->req_id = request_id; func_data->type = type; func_data->pending = BT_PENDING_NONE; - func_data->out_param = out_param1; + + 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: @@ -742,18 +716,50 @@ int _bt_audio_connect(int request_id, int type, case BT_AVRCP: uuid = AVRCP_TARGET_UUID; break; + case BT_AUDIO_A2DP_SOURCE: + uuid = A2DP_SOURCE_UUID; + break; case BT_AUDIO_ALL: - if (__bt_device_support_uuid(address, BT_AUDIO_HSP)) { - uuid = HFP_HS_UUID; - func_data->pending = BT_PENDING_CONNECT; - } else if (__bt_device_support_uuid(address, BT_AUDIO_A2DP)) { - uuid = A2DP_SINK_UUID; - } else { - BT_ERR("No audio role supported"); - result = BLUETOOTH_ERROR_SERVICE_NOT_FOUND; + 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; @@ -761,11 +767,16 @@ int _bt_audio_connect(int request_id, int type, } BT_INFO("Connecting to service %s", uuid); - value = __bt_is_headset_connected(type, request_id, address, out_param1); + value = __bt_is_headset_connected(type, request_id, address); 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; + } _bt_headset_set_local_connection(TRUE); ret = _bt_connect_profile(address, uuid, __bt_audio_request_cb, func_data); @@ -780,45 +791,50 @@ int _bt_audio_connect(int request_id, int type, /* 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; } + if (out_param1) + g_array_free(out_param1, TRUE); + return BLUETOOTH_ERROR_NONE; fail: - g_array_append_vals(*out_param1, address, - BT_ADDRESS_STR_LEN); + if (out_param1 != NULL) + g_array_append_vals(out_param1, address, + BT_ADDRESS_STR_LEN); return result; } 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; char address[BT_ADDRESS_STRING_SIZE] = { 0 }; bt_audio_function_data_t *func_data; - DBusGProxy *adapter_proxy; - DBusGConnection *g_conn; + 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_get_system_gconn(); + 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->out_param = out_param1; func_data->type = type; switch (type) { @@ -831,24 +847,35 @@ int _bt_audio_disconnect(int request_id, int type, case BT_AVRCP: uuid = AVRCP_TARGET_UUID; break; + case BT_AUDIO_A2DP_SOURCE: + uuid = A2DP_SOURCE_UUID; + break; case BT_AUDIO_ALL: - if (_bt_is_service_connected(address, BT_AUDIO_HSP)) { - uuid = HFP_HS_UUID; - func_data->pending = BT_PENDING_DISCONNECT; - } else if (_bt_is_service_connected(address, BT_AUDIO_A2DP)) { + 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"); 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); @@ -876,10 +903,13 @@ int _bt_audio_disconnect(int request_id, int type, } _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, + g_array_append_vals(out_param1, address, BT_ADDRESS_STR_LEN); return result; @@ -906,18 +936,17 @@ void _bt_remove_from_connected_list(const char *address) int _bt_hf_connect(int request_id, bluetooth_device_address_t *device_address, - GArray **out_param1) + GArray *out_param1) { int result = BLUETOOTH_ERROR_NONE; char address[BT_ADDRESS_STRING_SIZE] = { 0 }; bt_function_data_t *func_data; - DBusGProxy *adapter_proxy; - DBusGConnection *g_conn; - + 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); @@ -928,14 +957,21 @@ int _bt_hf_connect(int request_id, goto fail; } - g_conn = _bt_get_system_gconn(); + g_conn = _bt_gdbus_get_system_gconn(); if (g_conn == NULL) { result = BLUETOOTH_ERROR_INTERNAL; goto fail; } - func_data = g_malloc0(sizeof(bt_function_data_t)); + /* 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; + } + 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); @@ -953,10 +989,13 @@ int _bt_hf_connect(int request_id, 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, + g_array_append_vals(out_param1, address, BT_ADDRESS_STR_LEN); return result; @@ -964,13 +1003,13 @@ fail: int _bt_hf_disconnect(int request_id, bluetooth_device_address_t *device_address, - GArray **out_param1) + GArray *out_param1) { int result = BLUETOOTH_ERROR_NONE; char address[BT_ADDRESS_STRING_SIZE] = { 0 }; bt_function_data_t *func_data; - DBusGProxy *adapter_proxy; - DBusGConnection *g_conn; + GDBusProxy *adapter_proxy; + GDBusConnection *g_conn; int ret; char *uuid; @@ -985,14 +1024,13 @@ int _bt_hf_disconnect(int request_id, goto fail; } - g_conn = _bt_get_system_gconn(); + g_conn = _bt_gdbus_get_system_gconn(); if (g_conn == 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; uuid = g_strdup(HFP_AG_UUID); @@ -1009,135 +1047,205 @@ int _bt_hf_disconnect(int request_id, 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, + 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); + + BT_DBG("Content Protection status = [%d]", status); + + g_dbus_connection_emit_signal(conn, + NULL, BT_CONTENT_PROTECTION_PATH, + BT_CONTENT_PROTECTION_INTERFACE, + "ProtectionRequired", + g_variant_new("(b)", status), + &error); + + 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; + } + + BT_DBG("Emit Signal done = [ProtectionRequired]"); + return BLUETOOTH_ERROR_NONE; +} - device_path = __bt_get_connected_audio_path(); - retv_if(device_path == NULL, BLUETOOTH_ERROR_NOT_CONNECTED); +#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; - profile_proxy = dbus_g_proxy_new_for_name(g_conn, BT_BLUEZ_NAME, - device_path, BT_HEADSET_INTERFACE); + reply = g_dbus_proxy_call_finish(proxy, res, &err); + g_object_unref(proxy); + g_variant_unref(reply); - g_free(device_path); + BT_DBG("+"); + if (err != NULL) { + g_dbus_error_strip_remote_error(err); + BT_INFO("Auto_connect_request Dbus Call Error: %s", err->message); + + 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); +} - retv_if(profile_proxy == NULL, BLUETOOTH_ERROR_INTERNAL); - 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); +// 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) +{ + int result; + alarm_id_t alarm_id; - g_object_unref(profile_proxy); + 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); - retv_if(hash == NULL, BLUETOOTH_ERROR_INTERNAL); + if (result != BLUETOOTH_ERROR_NONE) + return TRUE; + else + auto_connect_timer.alarm_id = alarm_id; - value = g_hash_table_lookup(hash, "SpeakerGain"); - *gain = value ? g_value_get_uint(value) : 0; - g_hash_table_destroy(hash); - return BLUETOOTH_ERROR_NONE; + return FALSE; } -int _bt_audio_set_speaker_gain(unsigned int gain) +static int __bt_auto_connect_alarm_cb(alarm_id_t alarm_id, void* user_param) { - 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; - - conn = _bt_get_system_conn(); - retv_if(conn == NULL, BLUETOOTH_ERROR_INTERNAL); + int result = BLUETOOTH_ERROR_NONE; + char *address = NULL; + alarm_id_t new_alarm_id; - device_path = __bt_get_connected_audio_path(); - retv_if(device_path == NULL, BLUETOOTH_ERROR_NOT_CONNECTED); + BT_INFO("alram id = [%d] , retry_count [%d] ", + alarm_id, auto_connect_timer.retry_count); - msg = dbus_message_new_method_call(BT_BLUEZ_NAME, - device_path, BT_HEADSET_INTERFACE, - "SetProperty"); + if (alarm_id != auto_connect_timer.alarm_id) + return 0; - g_free(device_path); + address = vconf_get_str(BT_LAST_CONNECTED_DEVICE); - retv_if(msg == NULL, BLUETOOTH_ERROR_INTERNAL); + if (address == NULL) { + BT_ERR("Address vconf is null"); + auto_connect_timer.alarm_id = 0; + return 0; + } - 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); + BT_DBG("ADDRESS [%s]", address); - if (dbus_message_get_type(msg) == DBUS_MESSAGE_TYPE_METHOD_CALL) - dbus_message_set_no_reply(msg, TRUE); + result = _bt_connect_profile(address, A2DP_SOURCE_UUID, + __bt_auto_connect_request_cb, NULL); - if (!dbus_connection_send(conn, msg, NULL)) { - BT_ERR("Dbus sending failed\n"); - ret = BLUETOOTH_ERROR_INTERNAL; + 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; } - dbus_message_unref(msg); - return ret; + free(address); + return 0; } -int _bt_audio_set_content_protect(gboolean status) +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) { - DBusConnection *conn; - DBusMessage *signal; + int result = BLUETOOTH_ERROR_NONE; + char *address = NULL; + alarm_id_t alarm_id = 0; - BT_DBG("+\n"); + BT_DBG(""); - conn = _bt_get_system_conn(); - retv_if(conn == NULL, BLUETOOTH_ERROR_INTERNAL); + address = vconf_get_str(BT_LAST_CONNECTED_DEVICE); - BT_DBG("Content Protection status = [%d] \n", status); - - /*Emit Content protection Status change signal with value*/ - signal = dbus_message_new_signal(BT_CONTENT_PROTECTION_PATH, - BT_CONTENT_PROTECTION_INTERFACE, - "ProtectionRequired"); - if (!signal) - goto err; - - if (!dbus_message_append_args(signal, - DBUS_TYPE_BOOLEAN, &status, - DBUS_TYPE_INVALID)) { - BT_ERR("Signal appending failed\n"); - dbus_message_unref(signal); - goto err; + if (address == NULL) { + BT_ERR("No target device"); + return 0; } - dbus_connection_send(conn, signal, NULL); - dbus_message_unref(signal); + __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; + } - BT_DBG("-\n"); + free(address); return BLUETOOTH_ERROR_NONE; +} -err: - return BLUETOOTH_ERROR_INTERNAL; +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 */