[FRWK]Added run time audio role select Feature 59/150159/1
authorAtul Rai <a.rai@samsung.com>
Thu, 14 Sep 2017 11:57:34 +0000 (17:27 +0530)
committerAtul Rai <a.rai@samsung.com>
Thu, 14 Sep 2017 11:57:34 +0000 (17:27 +0530)
Change-Id: I78fe4fb916017f7e19aa610ca90a32cc20bf1134
Signed-off-by: Atul Rai <a.rai@samsung.com>
bt-api/bt-audio.c
bt-service-adaptation/services/adapter/bt-service-core-adapter.c
bt-service-adaptation/services/audio/bt-service-audio.c
bt-service-adaptation/services/bt-request-handler.c
bt-service-adaptation/services/include/bt-service-audio-common.h
include/bluetooth-audio-api.h
include/bt-internal-types.h

index c667d98..d9bbe18 100644 (file)
@@ -417,6 +417,24 @@ BT_EXPORT_API int bluetooth_av_source_disconnect(bluetooth_device_address_t *rem
        return result;
 }
 
+BT_EXPORT_API int bluetooth_audio_select_role(bluetooth_audio_role_t role)
+{
+       int result;
+
+       BT_CHECK_ENABLED(return);
+
+       BT_INIT_PARAMS();
+       BT_ALLOC_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param);
+
+       g_array_append_vals(in_param1, &role, sizeof(bluetooth_audio_role_t));
+
+       result = _bt_send_request(BT_BLUEZ_SERVICE, BT_AUDIO_SELECT_ROLE,
+               in_param1, in_param2, in_param3, in_param4, &out_param);
+
+       BT_FREE_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param);
+       return result;
+}
+
 BT_EXPORT_API int bluetooth_ag_get_headset_volume(unsigned int *speaker_gain)
 {
        int result;
index 5281783..0714f98 100644 (file)
@@ -76,6 +76,8 @@ static bt_adapter_timer_t visible_timer;
 
 static guint timer_id = 0;
 
+static gboolean a2dp_init_pending = FALSE;
+
 
 /* Adapter default states */
 static bt_status_t adapter_state = BT_DEACTIVATED;
@@ -542,6 +544,54 @@ int _bt_adapter_get_bonded_devices(void)
        return result;
 }
 
+static void __bt_handle_pending_a2dp_init(service_uuid_t *service_list, unsigned int count)
+{
+       int ret;
+       unsigned int i;
+       unsigned char *uuid;
+       char uuid_str[BT_UUID_STRING_SIZE];
+
+       if (!a2dp_init_pending)
+               return;
+
+       BT_DBG("+");
+       a2dp_init_pending = FALSE;
+       for (i = 0; i < count; i++) {
+               uuid = service_list[i].uuid;
+               _bt_service_convert_uuid_type_to_string(uuid_str, uuid);
+               BT_INFO("Adapter Service: [%s]", uuid_str);
+               if (!strcasecmp(uuid_str, A2DP_SINK_UUID)) {
+                       BT_INFO("Enable A2DP Sink role");
+                       /* Initialize A2DP Sink */
+                       ret = _bt_audio_initialize(BT_A2DP_SINK_MODULE);
+                       if (ret != BLUETOOTH_ERROR_NONE)
+                               BT_ERR("_bt_audio_initialize(BT_A2DP_SINK_MODULE) Failed");
+
+                       /* Initialize AVRCP Controller */
+                       ret = _bt_audio_initialize(BT_AVRCP_CTRL_MODULE);
+                       if (ret != BLUETOOTH_ERROR_NONE)
+                               BT_ERR("_bt_audio_initialize(BT_AVRCP_CTRL_MODULE) Failed");
+
+                       _bt_audio_set_current_role(BLUETOOTH_A2DP_SINK);
+                       return;
+               }
+       }
+
+       BT_INFO("Enable A2DP Source role by default");
+       /* Initialize A2DP Source */
+       ret = _bt_audio_initialize(BT_A2DP_SOURCE_MODULE);
+       if (ret != BLUETOOTH_ERROR_NONE)
+               BT_ERR("_bt_audio_initialize(BT_A2DP_SOURCE_MODULE) Failed");
+
+       /* Initialize AVRCP Target */
+       ret = _bt_audio_initialize(BT_AVRCP_MODULE);
+       if (ret != BLUETOOTH_ERROR_NONE)
+               BT_ERR("_bt_audio_initialize(BT_AVRCP_MODULE) Failed");
+
+       _bt_audio_set_current_role(BLUETOOTH_A2DP_SOURCE);
+       BT_DBG("-");
+}
+
 static void __bt_adapter_event_handler(int event_type, gpointer event_data)
 {
        int result = BLUETOOTH_ERROR_NONE;
@@ -677,6 +727,7 @@ static void __bt_adapter_event_handler(int event_type, gpointer event_data)
 
                count = list->num;
                service_list = list->service_list;
+               __bt_handle_pending_a2dp_init(service_list, count);
                __bt_adapter_handle_pending_requests(BT_IS_SERVICE_USED, service_list, count);
                break;
        }
@@ -718,43 +769,31 @@ int _bt_init_profiles()
                BT_ERR("_bt_hidhost_initialize Failed");
                return ret;
        }
+
        ret = _bt_socket_init();
        if (ret != BLUETOOTH_ERROR_NONE) {
                BT_ERR("_bt_socket_init Failed");
                return ret;
        }
-       /* Initialize A2DP Source */
-       ret = _bt_audio_initialize(BT_A2DP_SOURCE_MODULE);
-       if (ret != BLUETOOTH_ERROR_NONE) {
-               BT_ERR("_bt_audio_initialize(BT_A2DP_SOURCE_MODULE) Failed");
-               return ret;
-       }
 
-       /* Initialize AVRCP Target */
-       ret = _bt_audio_initialize(BT_AVRCP_MODULE);
-       if (ret != BLUETOOTH_ERROR_NONE) {
-               BT_ERR("_bt_audio_initialize(BT_AVRCP_MODULE) Failed");
-               return ret;
+       /*
+        * Query local adapter services and based on a2dp service uuids initialized
+        * in bluetooth stack, enable A2DP sourec or A2DP sink role.
+        */
+       ret =  adapter_get_service_uuids();
+       if (ret != OAL_STATUS_SUCCESS) {
+               BT_ERR("adapter_get_service_uuids failed: %d", ret);
+               return BLUETOOTH_ERROR_INTERNAL;
+       } else {
+               a2dp_init_pending = TRUE;
        }
 
-       /* Initialize A2DP Sink */
-       ret = _bt_audio_initialize(BT_A2DP_SINK_MODULE);
-       if (ret != BLUETOOTH_ERROR_NONE) {
-               BT_ERR("_bt_audio_initialize(BT_A2DP_SINK_MODULE) Failed");
-               return ret;
-       }
        /* Initialize HFP Audio Gateway */
        ret = _bt_audio_initialize(BT_AG_MODULE);
        if (ret != BLUETOOTH_ERROR_NONE) {
                BT_ERR("_bt_audio_initialize(BT_AG_MODULE) Failed");
                return ret;
        }
-       /* Initialize AVRCP Controller */
-       ret = _bt_audio_initialize(BT_AVRCP_CTRL_MODULE);
-       if (ret != BLUETOOTH_ERROR_NONE) {
-               BT_ERR("_bt_audio_initialize(BT_AVRCP_CTRL_MODULE) Failed");
-               return ret;
-       }
        /* Registering callback for receiving audio services searched */
        ret = _bt_audio_initialize(BT_AUDIO_ALL_MODULE);
        if (ret != BLUETOOTH_ERROR_NONE) {
@@ -809,11 +848,7 @@ static void __bt_post_oal_init(void)
        int ret;
        int status = VCONFKEY_BT_STATUS_OFF;
 
-       BT_DBG("OAL initialized, Init profiles..");
-       ret = _bt_init_profiles();
-       if (ret != BLUETOOTH_ERROR_NONE)
-               BT_ERR("Bluetooth profile init error: %d", ret);
-
+       BT_DBG("OAL initialized");
        if (vconf_get_int(VCONFKEY_BT_STATUS, &status) != 0) {
                BT_ERR("Fail to get the enabled value");
        }
@@ -1047,7 +1082,10 @@ static gboolean __bt_adapter_post_set_disabled(gpointer user_data)
 static void __bt_adapter_update_bt_enabled(void)
 {
        int result = BLUETOOTH_ERROR_NONE;
-       BT_INFO("_bt_adapter_update_bt_enabled>>");
+       BT_INFO("_bt_adapter_update_bt_enabled >> Init profiles...");
+       if (BLUETOOTH_ERROR_NONE != _bt_init_profiles())
+               BT_ERR("Bluetooth profile init failed");
+
        /* Update Bluetooth Status to notify other modules */
        if (vconf_set_int(VCONFKEY_BT_STATUS, VCONFKEY_BT_STATUS_ON) != 0)
                BT_ERR("Set vconf failed\n");
@@ -1065,7 +1103,8 @@ static void __bt_adapter_update_bt_enabled(void)
 static void __bt_adapter_update_bt_disabled(void)
 {
        int result = BLUETOOTH_ERROR_NONE;
-       BT_INFO("_bt_adapter_update_bt_disabled>>");
+       BT_INFO("_bt_adapter_update_bt_disabled >> Cleanup profiles...");
+       _bt_cleanup_profiles();
 
        int power_off_status = 0;
        int ret;
index c101216..6fe8ff2 100644 (file)
@@ -60,6 +60,9 @@ static GSList *g_service_search_info_list = NULL;
 /* Headset connection data structures */
 gboolean connection_local = FALSE;
 
+static int curr_audio_role = BLUETOOTH_A2DP_SOURCE;
+static int pending_audio_role = -1;
+
 static void __bt_remove_device_from_wait_list(char *prev_waiting_device);
 
 static void __bt_audio_device_property_event_handler(event_dev_properties_t *event);
@@ -74,6 +77,8 @@ static int __bt_is_headset_disconnecting(int type);
 
 static void __bt_audio_cleanup_resources(void);
 
+static gboolean __handle_pending_audio_select_role(gpointer data);
+
 #if 0
 void _bt_headset_set_local_connection(gboolean value)
 {
@@ -164,7 +169,7 @@ gboolean _bt_is_headset_type_connected(int type, char *address)
                if (connected_device->type & type) {
                        if (address != NULL)
                                g_strlcpy(address, connected_device->device_address,
-                                               BT_ADDRESS_STRING_SIZE + 1);
+                                               BT_ADDRESS_STRING_SIZE);
                        return TRUE;
                }
 
@@ -1059,4 +1064,178 @@ void _bt_remove_headset_from_list(int type, const char *address)
 
                node = g_list_next(node);
        }
+
+       /*
+        * If Audio role selection request is pending (pending_audio_role > 0) then process pending
+        * audio role select request on BT_AUDIO_A2DP/BT_AUDIO_A2DP_SOURCE device dicaonnection.
+        */
+       if (pending_audio_role >= 0 &&
+               (type == BT_AUDIO_A2DP || type == BT_AUDIO_A2DP_SOURCE))
+               g_idle_add(__handle_pending_audio_select_role, NULL);
+}
+
+static void __handle_pending_requests(int result, int service_function, void *user_data, unsigned int size)
+{
+       GSList *l;
+       GArray *out_param;
+       invocation_info_t *req_info;
+
+       BT_DBG("+");
+
+       /* Get method invocation context */
+       for (l = _bt_get_invocation_list(); l != NULL; l = g_slist_next(l)) {
+               req_info = l->data;
+
+               if (req_info == NULL || req_info->service_function != service_function)
+                       continue;
+
+               /* Create out param */
+               out_param = g_array_new(FALSE, FALSE, sizeof(gchar));
+
+               switch (service_function) {
+               case BT_AUDIO_SELECT_ROLE:
+                       _bt_service_method_return(req_info->context, out_param, result);
+                       g_array_free(out_param, TRUE);
+                       _bt_free_info_from_invocation_list(req_info);
+                       return;
+               default:
+                       BT_ERR("Unknown service function[%d]", service_function);
+                       return;
+               }
+       }
+
+       BT_DBG("-");
+}
+
+static gboolean __handle_pending_audio_select_role(gpointer data)
+{
+       int ret;
+       oal_status_t status;
+
+       BT_DBG("+");
+       if (BLUETOOTH_A2DP_SOURCE == pending_audio_role) {
+               /* Disable A2DP Sink role */
+               status = a2dp_sink_disable();
+               if (status != OAL_STATUS_SUCCESS) {
+                       BT_ERR("Failed to Disable Bluetooth A2DP Sink Profile, status: %d", status);
+                       ret = BLUETOOTH_ERROR_INTERNAL;
+                       goto done;
+               }
+
+               /* Disable AVRCP CT role */
+               status = avrcp_ct_disable();
+               if (status != OAL_STATUS_SUCCESS) {
+                       BT_ERR( "Failed to Disable Bluetooth AVRCP Controller Profile, status: %d", status);
+                       ret = BLUETOOTH_ERROR_INTERNAL;
+                       goto done;
+               }
+
+               /* Enable A2DP Source role */
+               ret = _bt_audio_initialize(BT_A2DP_SOURCE_MODULE);
+               if (ret != BLUETOOTH_ERROR_NONE) {
+                       BT_ERR( "Failed to enable Bluetooth A2DP Source Profile");
+                       goto done;
+               }
+
+               /* Enable AVRCP TG role */
+               ret = _bt_audio_initialize(BT_AVRCP_MODULE);
+               if (ret != BLUETOOTH_ERROR_NONE) {
+                       BT_ERR( "Failed to enable Bluetooth AVRCP Target Profile");
+                       goto done;
+               }
+       } else {
+               /* Disable A2DP Source role */
+               status = audio_disable();
+               if (OAL_STATUS_SUCCESS != status) {
+                       BT_ERR("Failed to disable Bluetooth A2DP Source Profile, status: %d", status);
+                       ret = BLUETOOTH_ERROR_INTERNAL;
+                       goto done;
+               }
+
+               /* Disable AVRCP TG role */
+               ret = _bt_service_avrcp_disable();
+               if (ret != BLUETOOTH_ERROR_NONE) {
+                       BT_ERR( "Failed to Disable Bluetooth AVRCP Target Profile");
+                       goto done;
+               }
+
+               /* Enable A2DP Sink role */
+               ret = _bt_audio_initialize(BT_A2DP_SINK_MODULE);
+               if (ret != BLUETOOTH_ERROR_NONE) {
+                       BT_ERR( "Failed to enable Bluetooth A2DP Sink Profile");
+                       goto done;
+               }
+
+               /* Enable AVRCP CT role */
+               ret = _bt_audio_initialize(BT_AVRCP_CTRL_MODULE);
+               if (ret != BLUETOOTH_ERROR_NONE) {
+                       BT_ERR( "Failed to enable Bluetooth AVRCP Controller Profile");
+                       goto done;
+               }
+       }
+
+done:
+       if (ret == BLUETOOTH_ERROR_NONE)
+               _bt_audio_set_current_role(pending_audio_role);
+
+       __handle_pending_requests(ret, BT_AUDIO_SELECT_ROLE, NULL, 0);
+       pending_audio_role = -1;
+       BT_DBG("-");
+       return FALSE;
+}
+
+int _bt_audio_select_role(bluetooth_audio_role_t role)
+{
+       int result = BLUETOOTH_ERROR_NONE;
+       char address[BT_ADDRESS_STRING_SIZE];
+       bluetooth_device_address_t dev_addr;
+
+       retv_if(BLUETOOTH_A2DP_SINK < role, BLUETOOTH_ERROR_INVALID_PARAM);
+       retv_if(pending_audio_role >= 0, BLUETOOTH_ERROR_IN_PROGRESS);
+
+       BT_DBG("+");
+
+       if (curr_audio_role == role) {
+               BT_ERR("Desired audio role already enabled, return");
+               return BLUETOOTH_ERROR_ALREADY_INITIALIZED;
+       }
+
+       pending_audio_role = role;
+
+       if (BLUETOOTH_A2DP_SINK == role) {
+               if (_bt_is_headset_type_connected(BT_AUDIO_A2DP, address)) {
+                       _bt_convert_addr_string_to_type(dev_addr.addr, address);
+                       result = _bt_audio_disconnect(BT_AUDIO_A2DP, &dev_addr);
+                       if (result != BLUETOOTH_ERROR_NONE) {
+                               BT_ERR( "_bt_audio_disconnect(BT_AUDIO_A2DP, %s) Failed", address);
+                               result = BLUETOOTH_ERROR_INTERNAL;
+                       }
+               } else {
+                       BT_INFO("No BT_AUDIO_A2DP device is connected, proceed with role switch");
+                       g_idle_add(__handle_pending_audio_select_role, NULL);
+                       result = BLUETOOTH_ERROR_NONE;
+               }
+       } else {
+               if (_bt_is_headset_type_connected(BT_AUDIO_A2DP_SOURCE, address)) {
+                       _bt_convert_addr_string_to_type(dev_addr.addr, address);
+                       result = _bt_audio_disconnect(BT_AUDIO_A2DP_SOURCE, &dev_addr);
+                       if (result != BLUETOOTH_ERROR_NONE) {
+                               BT_ERR( "_bt_audio_disconnect(BT_AUDIO_A2DP_SOURCE, %s) Failed", address);
+                               result = BLUETOOTH_ERROR_INTERNAL;
+                       }
+               } else {
+                       BT_INFO("No BT_AUDIO_A2DP_SOURCE device is connected, proceed with role switch");
+                       g_idle_add(__handle_pending_audio_select_role, NULL);
+                       result = BLUETOOTH_ERROR_NONE;
+               }
+       }
+
+       BT_DBG("-");
+       return result;
+}
+
+void _bt_audio_set_current_role(bluetooth_audio_role_t role)
+{
+       BT_INFO("role: %s", (role == BLUETOOTH_A2DP_SINK) ? "AUDIO_SINK" : "AUDIO_SOURCE");
+       curr_audio_role = role;
 }
index 8017810..43e327d 100644 (file)
@@ -25,6 +25,7 @@
 #include <cynara-creds-gdbus.h>
 
 #include "bluetooth-api.h"
+#include "bluetooth-audio-api.h"
 #include "bluetooth-gatt-server-api.h"
 #include "bt-request-handler.h"
 #include "bt-service-common.h"
@@ -212,6 +213,7 @@ static gboolean __bt_is_sync_function(int service_function)
                        || service_function == BT_GATT_SERVER_DELETE_SERVICE
                        || service_function == BT_START_LE_DISCOVERY
                        || service_function == BT_STOP_LE_DISCOVERY
+                       || service_function == BT_AUDIO_SELECT_ROLE
                        || service_function == BT_OBEX_SERVER_ACCEPT_CONNECTION)
                return TRUE;
        else
@@ -1155,6 +1157,20 @@ int __bt_bluez_request(int function_name,
                result = BLUETOOTH_ERROR_NONE;
                break;
        }
+       case BT_AUDIO_SELECT_ROLE: {
+               bluetooth_audio_role_t role;
+
+               __bt_service_get_parameters(in_param1,
+                               &role, sizeof(bluetooth_audio_role_t));
+
+               result = _bt_audio_select_role(role);
+               if (result == BLUETOOTH_ERROR_NONE) {
+                       sender = (char*)g_dbus_method_invocation_get_sender(context);
+                       _bt_save_invocation_context(context, result, sender,
+                                       function_name, NULL);
+               }
+               break;
+       }
        case BT_AV_CONNECT: {
                bluetooth_device_address_t address = { {0} };
                __bt_service_get_parameters(in_param1,
@@ -2758,6 +2774,7 @@ gboolean __bt_service_check_privilege(int function_name,
        case BT_OBEX_SERVER_CANCEL_TRANSFER:
        case BT_OBEX_SERVER_CANCEL_ALL_TRANSFERS:
 
+       case BT_AUDIO_SELECT_ROLE:
        case BT_AUDIO_CONNECT:
        case BT_AUDIO_DISCONNECT:
        case BT_AG_CONNECT:
index edeff56..8c4e2d7 100644 (file)
@@ -23,6 +23,7 @@
 #ifndef __BT_SERVICE_AUDIO_COMMON_H__
 #define __BT_SERVICE_AUDIO_COMMON_H__
 
+#include "bluetooth-audio-api.h"
 #include "bt-service-event-receiver.h"
 #include  <bt-service-common.h>
 
@@ -116,6 +117,10 @@ void _bt_audio_check_pending_connection(char *address);
 
 void _bt_audio_check_pending_disconnection(char *address, int type);
 
+int _bt_audio_select_role(bluetooth_audio_role_t role);
+
+void _bt_audio_set_current_role(bluetooth_audio_role_t role);
+
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */
index 0102c86..3fab4c3 100755 (executable)
@@ -87,6 +87,11 @@ typedef enum {
        BLUETOOTH_STATE_A2DP_HEADSET_CONNECTED = 0x0010,
 } bluetooth_device_state_t;
 
+typedef enum {
+       BLUETOOTH_A2DP_SOURCE,
+       BLUETOOTH_A2DP_SINK,
+} bluetooth_audio_role_t;
+
 /**
  * @brief      The function bluetooth_audio_init called to initializes the Audio
  *     service to bluetoothD and Global data related to audio.
@@ -207,6 +212,16 @@ int bluetooth_ag_get_headset_volume(unsigned int *speaker_gain);
  */
 int bluetooth_ag_set_speaker_gain(unsigned int speaker_gain);
 
+/**
+ * @brief      The function bluetooth_audio_select_role is called to set
+ *     A2DP to Source or Sink.
+ *
+ * @param[in]  role SINK/SOURCE.
+ * @return     int     Zero on Success or reason for error if any.
+ *
+ */
+int bluetooth_audio_select_role(bluetooth_audio_role_t role);
+
 typedef struct {
        int event;
        int result;
index 7361455..6fe3288 100644 (file)
@@ -245,6 +245,7 @@ typedef enum {
        BT_GET_SPEAKER_GAIN,
        BT_SET_SPEAKER_GAIN,
        BT_SET_CONTENT_PROTECT,
+       BT_AUDIO_SELECT_ROLE,
        BT_OOB_READ_LOCAL_DATA = BT_FUNC_OOB_BASE,
        BT_OOB_ADD_REMOTE_DATA,
        BT_OOB_REMOVE_REMOTE_DATA,