blob: 4ff1ea40f1c08ad896c804cd87e1a2fdc83228e0 [file] [log] [blame]
/******************************************************************************
*
* Copyright 2021 The Android Open Source Project
*
* 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
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
#define LOG_TAG "bt_bta_dm_adv_audio"
#include <base/bind.h>
#include <base/callback.h>
#include <base/logging.h>
#include <string.h>
#include "bt_common.h"
#include "bt_target.h"
#include "bt_types.h"
#include "bta_api.h"
#include "bta_dm_api.h"
#include "bta_dm_co.h"
#include "bta/dm/bta_dm_int.h"
#include "bta_csip_api.h"
#include "bta_sys.h"
#include "btif/include/btif_storage.h"
#include "btm_api.h"
#include "btm_int.h"
#include "btu.h"
#include "gap_api.h" /* For GAP_BleReadPeerPrefConnParams */
#include "l2c_api.h"
#include "osi/include/log.h"
#include "osi/include/osi.h"
#include "sdp_api.h"
#include "bta_sdp_api.h"
#include "stack/gatt/connection_manager.h"
#include "stack/include/gatt_api.h"
#include "utl.h"
#include "device/include/interop_config.h"
#include "device/include/profile_config.h"
#include "device/include/interop.h"
#include "stack/sdp/sdpint.h"
#include <inttypes.h>
#include "btif/include/btif_config.h"
#include "device/include/device_iot_config.h"
#include <btcommon_interface_defs.h>
#include <controller.h>
#include "bta_gatt_queue.h"
#include "bta_dm_adv_audio.h"
#include "btif/include/btif_dm_adv_audio.h"
#if (GAP_INCLUDED == TRUE)
#include "gap_api.h"
#endif
using bluetooth::Uuid;
#define ADV_AUDIO_VOICE_ROLE_BIT 2
#define ADV_AUDIO_MEDIA_ROLE_BIT 8
#define CONN_LESS_MEDIA_SINK_ROLE_BIT 32
#define CONN_LESS_ASSIST_ROLE_BIT 64
#define CONN_LESS_DELEGATE_ROLE_BIT 128
#define PACS_CT_SUPPORT_VALUE 2
#define PACS_UMR_SUPPORT_VALUE 4
#define PACS_CONVERSATIONAL_ROLE_VALUE 2
#define PACS_MEDIA_ROLE_VALUE 4
#define BTA_DM_ADV_AUDIO_GATT_CLOSE_DELAY_TOUT 5000
Uuid UUID_SERVCLASS_WMCP = Uuid::FromString
("2587db3c-ce70-4fc9-935f-777ab4188fd7");
std::vector<bluetooth::Uuid> uuid_srv_disc_search;
tBTA_LE_AUDIO_DEV_CB bta_le_audio_dev_cb;
tBTA_LEA_PAIRING_DB bta_lea_pairing_cb;
extern void bta_dm_proc_open_evt(tBTA_GATTC_OPEN* p_data);
bool is_adv_audio_unicast_supported(RawAddress rem_bda, int conn_id);
/***************************************************************************
*
* Function bta_get_lea_ctrl_cb
*
* Description Gets the control block of LE audio device
*
* Parameters: tBTA_LE_AUDIO_DEV_INFO*
*
****************************************************************************/
tBTA_LE_AUDIO_DEV_INFO* bta_get_lea_ctrl_cb(RawAddress peer_addr) {
tBTA_LE_AUDIO_DEV_INFO *p_lea_cb = NULL;
p_lea_cb = &bta_le_audio_dev_cb.bta_lea_dev_info[0];
for (int i = 0; i < MAX_LEA_DEVICES ; i++) {
if (p_lea_cb[i].in_use &&
(p_lea_cb[i].peer_address == peer_addr)) {
APPL_TRACE_DEBUG(" %s Control block Found for addr %s",
__func__, peer_addr.ToString().c_str());
return &p_lea_cb[i];
}
}
APPL_TRACE_DEBUG(" %s Control block Not Found for addr %s",
__func__, peer_addr.ToString().c_str());
return NULL;
}
/* Callback received when remote device Coordinated Sets SIRK is read */
void bta_gap_gatt_read_cb(uint16_t conn_id, tGATT_STATUS status,
uint16_t handle, uint16_t len,
uint8_t* value, void* data) {
tBTA_LE_AUDIO_DEV_INFO *p_lea_cb =
bta_get_lea_ctrl_cb(bta_le_audio_dev_cb.gatt_op_addr);
uint32_t role = 0;
uint8_t *p_val = value;
STREAM_TO_ARRAY(&role, p_val, len);
if (p_lea_cb) {
APPL_TRACE_DEBUG("%s Addr %s ", __func__,
p_lea_cb->peer_address.ToString().c_str());
if (status == GATT_SUCCESS) {
if (p_lea_cb->t_role_handle == handle) {
LOG(INFO) << __func__ << " Role derived by T_ADV_AUDIO "
<< +role;
if (role != 0) {
if (role & ADV_AUDIO_VOICE_ROLE_BIT)
p_lea_cb->uuids.push_back(Uuid::From16Bit
(UUID_SERVCLASS_T_ADV_AUDIO_VOICE));
if (role & ADV_AUDIO_MEDIA_ROLE_BIT)
p_lea_cb->uuids.push_back(Uuid::From16Bit
(UUID_SERVCLASS_T_ADV_AUDIO_MEDIA_SINK));
if (role & CONN_LESS_MEDIA_SINK_ROLE_BIT)
p_lea_cb->uuids.push_back(Uuid::From16Bit
(UUID_SERVCLASS_T_ADV_AUDIO_CONN_LESS_MEDIA_SINK));
if (role & CONN_LESS_ASSIST_ROLE_BIT)
p_lea_cb->uuids.push_back(Uuid::From16Bit
(UUID_SERVCLASS_T_ADV_AUDIO_ASSIST));
if (role & CONN_LESS_DELEGATE_ROLE_BIT)
p_lea_cb->uuids.push_back(Uuid::From16Bit
(UUID_SERVCLASS_T_ADV_AUDIO_DELEGATE));
}
p_lea_cb->disc_progress--;
} else if(handle == p_lea_cb->pacs_char_handle) {
LOG(INFO) << __func__ << " derived by PACS " << +role;
if (role == 0) {
LOG(INFO) << __func__ << " Invalid Information ";
} else {
if (is_adv_audio_unicast_supported(bta_le_audio_dev_cb.gatt_op_addr, conn_id)) {
LOG(INFO) << __func__ << " ASCS Supported by the remote ";
if ((role & PACS_CONVERSATIONAL_ROLE_VALUE) == PACS_CT_SUPPORT_VALUE)
p_lea_cb->uuids.push_back(Uuid::From16Bit(UUID_SERVCLASS_PACS_CT_SUPPORT));
if ((role & PACS_MEDIA_ROLE_VALUE) == PACS_UMR_SUPPORT_VALUE)
p_lea_cb->uuids.push_back(Uuid::From16Bit(UUID_SERVCLASS_PACS_UMR_SUPPORT));
}
//TODO LEA_DBG Call API which will be provided by BAP
}
p_lea_cb->disc_progress--;
} else {
LOG(INFO) << __func__ << " Invalid Handle for LE AUDIO";
}
} else {
p_lea_cb->disc_progress--;
LOG(INFO) << __func__ << " GATT READ FAILED" ;
}
if (p_lea_cb->disc_progress <= 0) {
bta_dm_lea_disc_complete(p_lea_cb->peer_address);
}
} else {
LOG(INFO) << __func__ << " INVALID CONTROL BLOCK" ;
}
}
/*******************************************************************************
*
* Function bta_get_adv_audio_role
*
* Description This API gets role for LE Audio Device after all services
* discovered
*
* Parameters: none
*
******************************************************************************/
void bta_get_adv_audio_role(RawAddress peer_address, uint16_t conn_id,
tGATT_STATUS status) {
tBTA_LE_AUDIO_DEV_INFO *p_lea_cb = bta_get_lea_ctrl_cb(peer_address);
bta_le_audio_dev_cb.gatt_op_addr = peer_address;
if (p_lea_cb == NULL) {
APPL_TRACE_ERROR(" %s Control block didnt find for peer address %s", __func__,
peer_address.ToString().c_str());
return;
}
// Fetch remote device gatt services from database
const std::vector<gatt::Service>* services = BTA_GATTC_GetServices(conn_id);
if (services) {
APPL_TRACE_DEBUG(" bta_get_adv_audio_role SIZE %d addr %s conn_id %d",
(*services).size(),bta_le_audio_dev_cb.gatt_op_addr.ToString().c_str(),
conn_id);
// Search for CSIS service in the database
for (const gatt::Service& service : *services) {
APPL_TRACE_DEBUG("%s: SERVICES IN REMOTE DEVICE %s ", __func__,
service.uuid.ToString().c_str())
if (is_le_audio_service(service.uuid)) {
size_t len = service.uuid.GetShortestRepresentationSize();
uint16_t uuid_val = 0;
if (len == Uuid::kNumBytes16) {
uuid_val = service.uuid.As16Bit();
} else if(len == Uuid::kNumBytes128) {
if (service.uuid == UUID_SERVCLASS_WMCP) {
APPL_TRACE_DEBUG("%s: WMCP Service UUId found", __func__);
std::vector<bluetooth::Uuid>::iterator itr;
itr = std::find(p_lea_cb->uuids.begin(), p_lea_cb->uuids.end(),
UUID_SERVCLASS_WMCP);
if (itr == p_lea_cb->uuids.end()) {
p_lea_cb->uuids.push_back(UUID_SERVCLASS_WMCP);
}
}
}
switch (uuid_val) {
case UUID_SERVCLASS_CSIS:
{
APPL_TRACE_DEBUG("%s:CSIS service found Uuid: %s ", __func__,
service.uuid.ToString().c_str());
p_lea_cb->is_csip_support = true;
bta_dm_csis_disc_complete(bta_dm_search_cb.peer_bdaddr, false);
// Get Characteristic and CCCD handle
for (const gatt::Characteristic& charac : service.characteristics) {
Uuid lock_uuid = charac.uuid;
if (lock_uuid.As16Bit() == UUID_SERVCLASS_CSIS_LOCK) {
APPL_TRACE_DEBUG("%s: CSIS rank found Uuid: %s ", __func__,
lock_uuid.ToString().c_str());
if (p_lea_cb != NULL) {
Uuid csip_lock_uuid = Uuid::FromString("6AD8");
std::vector<bluetooth::Uuid>::iterator itr;
itr = std::find(p_lea_cb->uuids.begin(), p_lea_cb->uuids.end(),
csip_lock_uuid);
if (itr == p_lea_cb->uuids.end()) {
p_lea_cb->uuids.push_back(csip_lock_uuid);
}
} else {
APPL_TRACE_DEBUG(" %s No Control Block", __func__);
}
}
}
}
break;
case UUID_SERVCLASS_T_ADV_AUDIO:
{
if (!p_lea_cb->is_has_found) {
APPL_TRACE_DEBUG("%s: T_ADV_AUDIO service found Uuid: %s ", __func__,
service.uuid.ToString().c_str());
std::vector<bluetooth::Uuid>::iterator itr;
itr = std::find(p_lea_cb->uuids.begin(), p_lea_cb->uuids.end(),
service.uuid);
if (itr == p_lea_cb->uuids.end()) {
p_lea_cb->uuids.push_back(service.uuid);
}
// Get Characteristic and CCCD handle
for (const gatt::Characteristic& charac : service.characteristics) {
Uuid role_uuid = charac.uuid;
if (role_uuid.As16Bit() == UUID_SERVCLASS_T_ADV_AUDIO_ROLE_CHAR) {
APPL_TRACE_DEBUG("%s:T_ADV_AUDIO ROLE CHAR found Uuid: %s ", __func__,
role_uuid.ToString().c_str());
if (p_lea_cb != NULL) {
p_lea_cb->is_t_audio_srvc_found = true;
p_lea_cb->disc_progress++;
p_lea_cb->t_role_handle = charac.value_handle;
} else {
APPL_TRACE_DEBUG(" %s No Control Block", __func__);
}
}
}
if (p_lea_cb->t_role_handle) {
APPL_TRACE_DEBUG("%s t_role_handle %d", __func__,
p_lea_cb->t_role_handle);
BtaGattQueue::ReadCharacteristic(conn_id, p_lea_cb->t_role_handle,
bta_gap_gatt_read_cb, NULL);
}
}
}
break;
case UUID_SERVCLASS_HAS:
if (!p_lea_cb->is_t_audio_srvc_found) {
p_lea_cb->is_has_found = true;
APPL_TRACE_DEBUG("%s: HAS service found Uuid: %s ", __func__,
service.uuid.ToString().c_str());
std::vector<bluetooth::Uuid>::iterator itr;
itr = std::find(p_lea_cb->uuids.begin(), p_lea_cb->uuids.end(),
service.uuid);
if (itr == p_lea_cb->uuids.end()) {
p_lea_cb->uuids.push_back(service.uuid);
}
}
FALLTHROUGH_INTENDED; /* FALLTHROUGH */
case UUID_SERVCLASS_PACS:
{
if ((!p_lea_cb->pacs_char_handle) &&
((!p_lea_cb->is_t_audio_srvc_found))) {
APPL_TRACE_DEBUG("%s:PACS service found Uuid: %s ", __func__,
service.uuid.ToString().c_str());
std::vector<bluetooth::Uuid>::iterator itr;
itr = std::find(p_lea_cb->uuids.begin(), p_lea_cb->uuids.end(),
service.uuid);
if (itr == p_lea_cb->uuids.end()) {
p_lea_cb->uuids.push_back(service.uuid);
}
// Get Characteristic and CCCD handle
for (const gatt::Characteristic& charac : service.characteristics) {
Uuid role_uuid = charac.uuid;
if (role_uuid.As16Bit() == UUID_SERVCLASS_SOURCE_CONTEXT) {
APPL_TRACE_DEBUG("%s: PACS Source context CHAR found Uuid: %s ",
__func__, role_uuid.ToString().c_str());
if (p_lea_cb != NULL) {
p_lea_cb->disc_progress++;
p_lea_cb->pacs_char_handle = charac.value_handle;
} else {
APPL_TRACE_DEBUG(" %s No Control Block", __func__);
}
}
}
if (p_lea_cb->pacs_char_handle) {
BtaGattQueue::ReadCharacteristic(conn_id, p_lea_cb->pacs_char_handle,
bta_gap_gatt_read_cb, NULL);
}
}
}
break;
default:
APPL_TRACE_DEBUG(" Not a LE AUDIO SERVICE-- IGNORE %s ",
service.uuid.ToString().c_str());
}
}
}
}
if (p_lea_cb->disc_progress == 0) {
bta_dm_lea_disc_complete(peer_address);
}
}
/*****************************************************************************
*
* Function bta_dm_csis_disc_complete
*
* Description This API updates csis discovery complete status
*
* Parameters: none
*****************************************************************************/
void bta_dm_csis_disc_complete(RawAddress p_bd_addr, bool status) {
tBTA_LE_AUDIO_DEV_INFO *p_lea_cb = bta_get_lea_ctrl_cb(p_bd_addr);
APPL_TRACE_DEBUG("%s %s %d", __func__, p_bd_addr.ToString().c_str(),
status);
if (p_lea_cb) {
p_lea_cb->csip_disc_progress = status;
} else {
RawAddress pseudo_addr = bta_get_pseudo_addr_with_id_addr(p_bd_addr);
if (pseudo_addr != RawAddress::kEmpty) {
p_lea_cb = bta_get_lea_ctrl_cb(pseudo_addr);
if (p_lea_cb) {
p_lea_cb->csip_disc_progress = status;
APPL_TRACE_DEBUG(" %s Pseudo addr disc_progress resetted", __func__);
} else {
APPL_TRACE_DEBUG(" %s No Control Block for pseudo addr", __func__);
}
} else {
APPL_TRACE_DEBUG(" %s No Control Block", __func__);
}
}
}
/*****************************************************************************
*
* Function bta_dm_lea_disc_complete
*
* Description This API sends the event to upper layer that LE audio
* gatt operations are complete.
*
* Parameters: none
*
****************************************************************************/
void bta_dm_lea_disc_complete(RawAddress p_bd_addr) {
tBTA_DM_SEARCH result;
tBTA_LE_AUDIO_DEV_INFO *p_lea_cb = bta_get_lea_ctrl_cb(p_bd_addr);
APPL_TRACE_DEBUG("%s %s", __func__, p_bd_addr.ToString().c_str());
if (p_lea_cb == NULL) {
RawAddress pseudo_addr = bta_get_pseudo_addr_with_id_addr(p_bd_addr);
p_lea_cb = bta_get_lea_ctrl_cb(pseudo_addr);
p_bd_addr = pseudo_addr;
}
if (p_lea_cb) {
APPL_TRACE_DEBUG("csip_disc_progress %d", p_lea_cb->csip_disc_progress);
if ((p_lea_cb->disc_progress == 0) &&
(p_lea_cb->csip_disc_progress)) { //Add CSIS check also
result.adv_audio_disc_cmpl.num_uuids = 0;
for (uint16_t i = 0; i < p_lea_cb->uuids.size(); i++) {
result.adv_audio_disc_cmpl.adv_audio_uuids[i] = p_lea_cb->uuids[i];
result.adv_audio_disc_cmpl.num_uuids++;
}
result.adv_audio_disc_cmpl.bd_addr = p_bd_addr;
APPL_TRACE_DEBUG("Sending Call back with no of uuids's"
"p_lea_cb->uuids.size() %d", p_lea_cb->uuids.size());
bta_dm_search_cb.p_search_cback(BTA_DM_LE_AUDIO_SEARCH_CMPL_EVT, &result);
} else {
APPL_TRACE_DEBUG("%s Discovery in progress", __func__);
}
} else {
APPL_TRACE_DEBUG(" %s No Control Block", __func__);
}
}
/*****************************************************************************
*
* Function bta_add_adv_audio_uuid
*
* Description This is GATT client callback function used in DM.
*
* Parameters:
*
******************************************************************************/
void bta_add_adv_audio_uuid(RawAddress peer_address,
tBTA_GATT_ID srvc_uuid) {
auto itr = find(uuid_srv_disc_search.begin(),
uuid_srv_disc_search.end(), srvc_uuid.uuid);
if(itr != uuid_srv_disc_search.end()) {
tBTA_LE_AUDIO_DEV_INFO *p_lea_cb = bta_get_lea_ctrl_cb(peer_address);
if (p_lea_cb != NULL) {
APPL_TRACE_DEBUG(" %s Control Block Found", __func__);
std::vector<bluetooth::Uuid>::iterator itr;
itr = std::find(p_lea_cb->uuids.begin(), p_lea_cb->uuids.end(), srvc_uuid.uuid);
if (itr == p_lea_cb->uuids.end()) {
p_lea_cb->uuids.push_back(srvc_uuid.uuid);
}
} else {
APPL_TRACE_DEBUG(" %s No Control Block", __func__);
}
}
}
/*******************************************************************************
*
* Function bta_set_lea_ctrl_cb
*
* Description This is GATT client callback function used in DM.
*
* Parameters:
*
******************************************************************************/
tBTA_LE_AUDIO_DEV_INFO* bta_set_lea_ctrl_cb(RawAddress peer_addr) {
tBTA_LE_AUDIO_DEV_INFO *p_lea_cb = NULL;
p_lea_cb = bta_get_lea_ctrl_cb(peer_addr);
if (p_lea_cb == NULL) {
APPL_TRACE_DEBUG("%s Control block create ", __func__);
for (int i = 0; i < MAX_LEA_DEVICES ; i++) {
if (!bta_le_audio_dev_cb.bta_lea_dev_info[i].in_use) {
bta_le_audio_dev_cb.bta_lea_dev_info[i].peer_address = peer_addr;
bta_le_audio_dev_cb.bta_lea_dev_info[i].in_use = true;
bta_le_audio_dev_cb.bta_lea_dev_info[i].csip_disc_progress = true;
bta_le_audio_dev_cb.bta_lea_dev_info[i].is_csip_support = false;
bta_le_audio_dev_cb.bta_lea_dev_info[i].gatt_disc_progress = true;
bta_le_audio_dev_cb.num_lea_devices++;
return (&(bta_le_audio_dev_cb.bta_lea_dev_info[i]));
}
}
} else {
return p_lea_cb;
}
return NULL;
}
/*******************************************************************************
*
* Function bta_dm_reset_adv_audio_dev_info
*
* Description This is GATT client callback function used in DM.
*
* Parameters:
*
******************************************************************************/
void bta_dm_reset_adv_audio_dev_info(RawAddress p_addr) {
tBTA_LE_AUDIO_DEV_INFO *p_lea_cb = bta_get_lea_ctrl_cb(p_addr);
if (p_lea_cb != NULL) {
p_lea_cb->peer_address = RawAddress::kEmpty;
p_lea_cb->disc_progress = 0;
p_lea_cb->conn_id = 0;
p_lea_cb->transport = 0;
p_lea_cb->in_use = false;
p_lea_cb->t_role_handle = 0;
p_lea_cb->is_has_found = false;
p_lea_cb->is_t_audio_srvc_found = false;
p_lea_cb->pacs_char_handle = 0;
p_lea_cb->using_bredr_bonding = 0;
p_lea_cb->gatt_disc_progress = false;
p_lea_cb->uuids.clear();
bta_le_audio_dev_cb.gatt_op_addr = RawAddress::kEmpty;
bta_le_audio_dev_cb.pending_peer_addr = RawAddress::kEmpty;
bta_le_audio_dev_cb.num_lea_devices--;
bta_le_audio_dev_cb.bond_progress = false;
APPL_TRACE_DEBUG("bta_dm_reset_adv_audio_dev_info %s transport %d ",
p_lea_cb->peer_address.ToString().c_str(), p_lea_cb->transport);
}
}
/*******************************************************************************
*
* Function bta_dm_set_adv_audio_dev_info
*
* Description This is GATT client callback function used in DM.
*
* Parameters:
*
******************************************************************************/
void bta_dm_set_adv_audio_dev_info(tBTA_GATTC_OPEN* p_data) {
tBTA_LE_AUDIO_DEV_INFO *p_lea_cb = bta_set_lea_ctrl_cb(p_data->remote_bda);
if (p_lea_cb != NULL) {
p_lea_cb->peer_address = p_data->remote_bda;
p_lea_cb->disc_progress = 0;
p_lea_cb->conn_id = p_data->conn_id;
p_lea_cb->transport = p_data->transport;//BTM_UseLeLink(p_data->remote_bda);
APPL_TRACE_DEBUG("bta_dm_set_adv_audio_dev_info %s transport %d ",
p_lea_cb->peer_address.ToString().c_str(), p_lea_cb->transport);
}
}
/*******************************************************************************
*
* Function is_adv_audio_unicast_supported
*
* Description This function checks whether unicast support is there or not on
* remote side
*
* Parameters:
*
******************************************************************************/
bool is_adv_audio_unicast_supported(RawAddress rem_bda, int conn_id) {
const std::vector<gatt::Service>* services = BTA_GATTC_GetServices(conn_id);
if (services) {
for (const gatt::Service& service : *services) {
uint16_t uuid_val = service.uuid.As16Bit();
if (uuid_val == UUID_SERVCLASS_ASCS)
return true;
}
}
return false;
}
/*******************************************************************************
*
* Function is_adv_audio_group_supported
*
* Description This function checks whether csip support is there or not on
* remote side
*
* Parameters:
*
******************************************************************************/
bool is_adv_audio_group_supported(RawAddress rem_bda, int conn_id) {
const std::vector<gatt::Service>* services = BTA_GATTC_GetServices(conn_id);
if (services) {
for (const gatt::Service& service : *services) {
if (is_le_audio_service(service.uuid)) {
uint16_t uuid_val = service.uuid.As16Bit();
if (uuid_val == UUID_SERVCLASS_CSIS)
return true;
}
}
}
return false;
}
/*******************************************************************************
*
* Function bta_dm_lea_gattc_callback
*
* Description This is GATT client callback function used in DM.
*
* Parameters:
*
******************************************************************************/
void bta_dm_lea_gattc_callback(tBTA_GATTC_EVT event, tBTA_GATTC* p_data) {
APPL_TRACE_DEBUG("bta_dm_lea_gattc_callback event = %d", event);
switch (event) {
case BTA_GATTC_OPEN_EVT:
if (p_data->status != GATT_SUCCESS) {
btif_dm_release_action_uuid(bta_le_audio_dev_cb.pending_peer_addr);
} else {
if (is_remote_support_adv_audio(bta_le_audio_dev_cb.pending_peer_addr)) {
bta_dm_set_adv_audio_dev_info(&p_data->open);
}
bta_dm_proc_open_evt(&p_data->open);
}
break;
case BTA_GATTC_SEARCH_RES_EVT:
if (is_remote_support_adv_audio(bta_le_audio_dev_cb.pending_peer_addr)) {
bta_add_adv_audio_uuid(bta_le_audio_dev_cb.pending_peer_addr,
p_data->srvc_res.service_uuid);
}
break;
case BTA_GATTC_SEARCH_CMPL_EVT:
if (is_remote_support_adv_audio(bta_le_audio_dev_cb.pending_peer_addr)) {
bta_get_adv_audio_role(bta_le_audio_dev_cb.pending_peer_addr,
p_data->search_cmpl.conn_id,
p_data->search_cmpl.status);
if (is_adv_audio_group_supported(bta_le_audio_dev_cb.pending_peer_addr,
p_data->search_cmpl.conn_id)) {
RawAddress p_id_addr =
bta_get_rem_dev_id_addr(bta_le_audio_dev_cb.pending_peer_addr);
if (p_id_addr != RawAddress::kEmpty) {
BTA_CsipFindCsisInstance(p_data->search_cmpl.conn_id,
p_data->search_cmpl.status,
p_id_addr);
} else {
BTA_CsipFindCsisInstance(p_data->search_cmpl.conn_id,
p_data->search_cmpl.status,
bta_le_audio_dev_cb.pending_peer_addr);
}
}
}
break;
case BTA_GATTC_CLOSE_EVT:
APPL_TRACE_DEBUG("BTA_GATTC_CLOSE_EVT reason = %d, data conn_id %d,"
"search conn_id %d", p_data->close.reason, p_data->close.conn_id,
bta_dm_search_cb.conn_id);
if (is_remote_support_adv_audio(bta_le_audio_dev_cb.pending_peer_addr)) {
bta_dm_reset_adv_audio_dev_info(bta_le_audio_dev_cb.pending_peer_addr);
}
break;
default:
break;
}
}
/******************************************************************************
*
* Function bta_dm_adv_audio_gatt_conn
*
* Description This API opens the gatt conn after finding sdp record
* during BREDR Discovery
*
* Parameters: none
*
******************************************************************************/
void bta_dm_adv_audio_gatt_conn(RawAddress p_bd_addr) {
APPL_TRACE_DEBUG("bta_dm_adv_audio_gatt_conn ");
bta_le_audio_dev_cb.pending_peer_addr = p_bd_addr;
tBTA_LE_AUDIO_DEV_INFO *tmp_lea_cb = bta_get_lea_ctrl_cb(p_bd_addr);
if (tmp_lea_cb && tmp_lea_cb->in_use) {
APPL_TRACE_DEBUG("bta_dm_adv_audio_gatt_conn Already exists %d",
tmp_lea_cb->conn_id);
return;
}
BTA_GATTC_AppRegister(bta_dm_lea_gattc_callback,
base::Bind([](uint8_t client_id, uint8_t status) {
if (status == GATT_SUCCESS) {
tBTA_LE_AUDIO_DEV_INFO *p_lea_cb =
bta_set_lea_ctrl_cb(bta_le_audio_dev_cb.pending_peer_addr);
if (p_lea_cb) {
APPL_TRACE_DEBUG("bta_dm_adv_audio_gatt_conn Client Id: %d",
client_id);
p_lea_cb->gatt_if = client_id;
p_lea_cb->using_bredr_bonding = true;
BTA_GATTC_Open(client_id, bta_le_audio_dev_cb.pending_peer_addr,
true, GATT_TRANSPORT_LE, false);
}
}
}), false);
}
/******************************************************************************
*
* Function bta_dm_adv_audio_close
*
* Description This API closes the gatt conn with was opened by dm layer
* for service discovery (or) opened after finding sdp record
* during BREDR Discovery
*
* Parameters: none
*
******************************************************************************/
void bta_dm_adv_audio_close(RawAddress p_bd_addr) {
tBTA_LE_AUDIO_DEV_INFO *p_lea_cb = bta_get_lea_ctrl_cb(p_bd_addr);
APPL_TRACE_DEBUG("%s", __func__);
if (p_lea_cb) {
APPL_TRACE_DEBUG("%s %d", __func__, p_lea_cb->gatt_if);
if (p_lea_cb->using_bredr_bonding) {
APPL_TRACE_DEBUG("%s closing LE conn est due to bredr bonding %d", __func__,
p_lea_cb->gatt_if);
BTA_GATTC_AppDeregister(p_lea_cb->gatt_if);
} else {
bta_sys_start_timer(bta_dm_search_cb.gatt_close_timer,
BTA_DM_ADV_AUDIO_GATT_CLOSE_DELAY_TOUT,
BTA_DM_DISC_CLOSE_TOUT_EVT, 0);
}
}
}
/*******************************************************************************
*
* Function bta_get_lea_ctrl_cb
*
* Description This API returns pairing control block of LE AUDIO DEVICE
*
* Parameters: tBTA_DEV_PAIRING_CB
*
******************************************************************************/
tBTA_DEV_PAIRING_CB* bta_get_lea_pair_cb(RawAddress peer_addr) {
tBTA_DEV_PAIRING_CB *p_lea_pair_cb = NULL;
p_lea_pair_cb = &bta_lea_pairing_cb.bta_dev_pair_db[0];
APPL_TRACE_DEBUG("%s %s ", __func__, peer_addr.ToString().c_str());
for (int i = 0; i < MAX_LEA_DEVICES; i++) {
if ((p_lea_pair_cb[i].in_use) &&
(p_lea_pair_cb[i].p_addr == peer_addr)) {
APPL_TRACE_DEBUG("%s Found %s index i %d ", __func__,
p_lea_pair_cb[i].p_addr.ToString().c_str(), i);
return &p_lea_pair_cb[i];
}
}
return NULL;
}
/*******************************************************************************
*
* Function bta_set_lea_ctrl_cb
*
* Description This is GATT client callback function used in DM.
*
* Parameters:
*
******************************************************************************/
tBTA_DEV_PAIRING_CB* bta_set_lea_pair_cb(RawAddress peer_addr) {
tBTA_DEV_PAIRING_CB *p_lea_pair_cb = NULL;
APPL_TRACE_DEBUG("bta_set_lea_ctrl_cb %s", peer_addr.ToString().c_str());
p_lea_pair_cb = bta_get_lea_pair_cb(peer_addr);
if (p_lea_pair_cb == NULL) {
APPL_TRACE_DEBUG("bta_set_lea_ctrl_cb Control block create ");
for (int i = 0; i < MAX_LEA_DEVICES ; i++) {
if (!bta_lea_pairing_cb.bta_dev_pair_db[i].in_use) {
bta_lea_pairing_cb.bta_dev_pair_db[i].p_addr = peer_addr;
bta_lea_pairing_cb.bta_dev_pair_db[i].in_use = true;
bta_lea_pairing_cb.is_pairing_progress = true;
bta_lea_pairing_cb.num_devices++;
return (&(bta_lea_pairing_cb.bta_dev_pair_db[i]));
}
}
} else {
return p_lea_pair_cb;
}
return NULL;
}
/*******************************************************************************
*
* Function bta_dm_reset_adv_audio_dev_info
*
* Description This API resets all the pairing information related to le
* audio remote device.
* Parameters: none
*
******************************************************************************/
void bta_dm_reset_lea_pairing_info(RawAddress p_addr) {
APPL_TRACE_DEBUG("%s Addr %s", __func__, p_addr.ToString().c_str());
auto itr = bta_lea_pairing_cb.dev_addr_map.find(p_addr);
if (itr != bta_lea_pairing_cb.dev_addr_map.end()) {
bta_lea_pairing_cb.dev_addr_map.erase(p_addr);
}
itr = bta_lea_pairing_cb.dev_rand_addr_map.find(p_addr);
if (itr != bta_lea_pairing_cb.dev_rand_addr_map.end()) {
bta_lea_pairing_cb.dev_rand_addr_map.erase(p_addr);
}
tBTA_DEV_PAIRING_CB *p_lea_pair_cb = NULL;
p_lea_pair_cb = bta_get_lea_pair_cb(p_addr);
if (p_lea_pair_cb) {
APPL_TRACE_DEBUG("%s RESETTING VALUES", __func__);
p_lea_pair_cb->in_use = false;
p_lea_pair_cb->is_dumo_device = false;
p_lea_pair_cb->is_le_pairing = false;
p_lea_pair_cb->dev_type = 0;
if (p_lea_pair_cb->p_id_addr != RawAddress::kEmpty) {
itr = bta_lea_pairing_cb.dev_addr_map.find(p_lea_pair_cb->p_id_addr);
APPL_TRACE_DEBUG("%s RESETTING Addr %s", __func__,
p_lea_pair_cb->p_id_addr.ToString().c_str());
if (itr != bta_lea_pairing_cb.dev_addr_map.end()) {
APPL_TRACE_DEBUG("%s Clearing INSIDE LEA ADDR DB MAP",
__func__);
bta_lea_pairing_cb.dev_addr_map.erase(p_lea_pair_cb->p_id_addr);
}
p_lea_pair_cb->p_id_addr = RawAddress::kEmpty;
p_lea_pair_cb->transport = 0;
p_lea_pair_cb->p_addr = RawAddress::kEmpty;
}
bta_lea_pairing_cb.is_pairing_progress = false;
bta_lea_pairing_cb.num_devices--;
bta_lea_pairing_cb.is_sdp_discover = true;
} else {
APPL_TRACE_DEBUG("%s INVALID CONTROL BLOCK", __func__);
}
}
/*****************************************************************************
*
* Function bta_dm_ble_adv_audio_idaddr_map
*
* Description storing the identity address information in the device
* control block. It will used for DUMO devices
*
* Returns none
*
*****************************************************************************/
void bta_dm_ble_adv_audio_idaddr_map(RawAddress p_bd_addr,
RawAddress p_id_addr) {
APPL_TRACE_DEBUG("%s p_bd_addr %s id_addr %s ", __func__,
p_bd_addr.ToString().c_str(), p_id_addr.ToString().c_str());
if (is_remote_support_adv_audio(p_bd_addr)) {
bta_lea_pairing_cb.dev_addr_map[p_id_addr] = p_bd_addr;
bta_lea_pairing_cb.dev_rand_addr_map[p_bd_addr] = p_id_addr;
tBTA_DEV_PAIRING_CB *p_lea_pair_cb = NULL;
p_lea_pair_cb = bta_get_lea_pair_cb(p_bd_addr);
if (p_lea_pair_cb) {
if (p_id_addr != p_bd_addr) {
APPL_TRACE_DEBUG("%s is_dumo_device %s", __func__,
p_id_addr.ToString().c_str());
p_lea_pair_cb->p_id_addr = p_id_addr;
p_lea_pair_cb->is_dumo_device = true;
}
}
}
}
bool bta_remote_dev_identity_addr_match(RawAddress p_addr) {
APPL_TRACE_DEBUG("%s ", __func__);
auto itr = bta_lea_pairing_cb.dev_addr_map.find(p_addr);
if (itr != bta_lea_pairing_cb.dev_addr_map.end()) {
APPL_TRACE_DEBUG("%s Identity BD_ADDR %s", __func__,
p_addr.ToString().c_str());
return true;
}
return false;
}
bool bta_is_bredr_primary_transport(RawAddress p_bd_addr) {
tBTA_DEV_PAIRING_CB *p_lea_pair_cb = NULL;
p_lea_pair_cb = bta_get_lea_pair_cb(p_bd_addr);
APPL_TRACE_DEBUG("%s ", __func__);
if (p_lea_pair_cb) {
APPL_TRACE_DEBUG("%s Transport %d ", __func__, p_lea_pair_cb->transport);
if (p_lea_pair_cb->transport == BT_TRANSPORT_BR_EDR) {
return true;
}
}
return false;
}
bool bta_remote_device_is_dumo(RawAddress p_bd_addr) {
auto itr = bta_lea_pairing_cb.dev_addr_map.find(p_bd_addr);
APPL_TRACE_DEBUG("%s Addr %s", __func__, p_bd_addr.ToString().c_str());
if (itr != bta_lea_pairing_cb.dev_addr_map.end()) {
APPL_TRACE_DEBUG("%s DUMO DEVICE Identity BD_ADDR %s", __func__,
p_bd_addr.ToString().c_str());
return true;
}
auto itr2 = bta_lea_pairing_cb.dev_rand_addr_map.find(p_bd_addr);
if (itr2 != bta_lea_pairing_cb.dev_rand_addr_map.end()) {
APPL_TRACE_DEBUG("%s Dumo addressed %s %s ", __func__,
itr2->first.ToString().c_str(), itr2->second.ToString().c_str());
return true;
}
return false;
}
RawAddress bta_get_rem_dev_id_addr(RawAddress p_bd_addr) {
tBTA_DEV_PAIRING_CB *p_lea_pair_cb = NULL;
APPL_TRACE_DEBUG("%s ", __func__);
p_lea_pair_cb = bta_get_lea_pair_cb(p_bd_addr);
if (p_lea_pair_cb) {
APPL_TRACE_DEBUG("%s %s", __func__,
p_lea_pair_cb->p_id_addr.ToString().c_str());
return p_lea_pair_cb->p_id_addr;
}
return RawAddress::kEmpty;
}
/*****************************************************************************
*
* Function bta_adv_audio_update_bond_db
*
* Description Updates pairing control block of the device and the bonding
* is initiated using LE transport or not.
*
* Returns void
*
*****************************************************************************/
void bta_adv_audio_update_bond_db(RawAddress p_bd_addr, uint8_t transport) {
tBTA_DEV_PAIRING_CB *p_dev_pair_cb = bta_set_lea_pair_cb(p_bd_addr);
APPL_TRACE_DEBUG("%s", __func__);
if (p_dev_pair_cb) {
APPL_TRACE_DEBUG("%s Addr %s Transport %d", __func__,
p_bd_addr.ToString().c_str(), transport);
p_dev_pair_cb->p_addr = p_bd_addr;
p_dev_pair_cb->transport = transport;
if (transport == BT_TRANSPORT_LE) {
if (is_remote_support_adv_audio(p_dev_pair_cb->p_addr))
p_dev_pair_cb->is_le_pairing = true;
else
p_dev_pair_cb->is_le_pairing = false;
} else
p_dev_pair_cb->is_le_pairing = false;
}
}
/*****************************************************************************
*
* Function is_le_audio_service
*
* Description It checks whether the given service is related to the LE
* Audio service or not.
*
* Returns true for LE Audio service which are registered.
false by default
*
*****************************************************************************/
bool is_le_audio_service(Uuid uuid) {
uint16_t uuid_val = 0;
bool status = false;
size_t len = uuid.GetShortestRepresentationSize();
if (len == Uuid::kNumBytes16) {
uuid_val = uuid.As16Bit();
APPL_TRACE_DEBUG("is_le_audio_service : 0x%X 0x%X ", uuid.As16Bit(), uuid_val);
//TODO check the service contains any LE AUDIO service or not
switch (uuid_val) {
case UUID_SERVCLASS_CSIS:
FALLTHROUGH_INTENDED; /* FALLTHROUGH */
case UUID_SERVCLASS_BASS:
FALLTHROUGH_INTENDED; /* FALLTHROUGH */
case UUID_SERVCLASS_T_ADV_AUDIO:
FALLTHROUGH_INTENDED; /* FALLTHROUGH */
case UUID_SERVCLASS_ASCS:
FALLTHROUGH_INTENDED; /* FALLTHROUGH */
case UUID_SERVCLASS_BAAS:
FALLTHROUGH_INTENDED; /* FALLTHROUGH */
case UUID_SERVCLASS_PACS:
{
auto itr = find(uuid_srv_disc_search.begin(),
uuid_srv_disc_search.end(), uuid);
if (itr != uuid_srv_disc_search.end())
status = true;
}
break;
default:
APPL_TRACE_DEBUG("%s : Not a LEA service ", __func__);
}
} else if(len == Uuid::kNumBytes128) {
if (uuid == UUID_SERVCLASS_WMCP) {
APPL_TRACE_DEBUG("%s: WMCP Service UUId found", __func__);
auto itr = find(uuid_srv_disc_search.begin(),
uuid_srv_disc_search.end(), uuid);
if (itr != uuid_srv_disc_search.end())
status = true;
}
}
return status;
}
/*****************************************************************************
*
* Function bta_is_adv_audio_valid_bdaddr
*
* Description This API is used for DUMO device. If the device contains
* two address (random and public), it checks for valid
* address.
*
* Returns 0 - for random address in dumo device
* 1 - for public address in dumo device
*
****************************************************************************/
int bta_is_adv_audio_valid_bdaddr(RawAddress p_bd_addr) {
tBTA_DEV_PAIRING_CB *p_lea_pair_cb = NULL;
p_lea_pair_cb = bta_get_lea_pair_cb(p_bd_addr);
if (p_lea_pair_cb) {
APPL_TRACE_DEBUG("%s p_lea_pair_cb %s", __func__,
p_lea_pair_cb->p_addr.ToString().c_str());
auto itr = bta_lea_pairing_cb.dev_addr_map.find(p_bd_addr);
if (itr == bta_lea_pairing_cb.dev_addr_map.end() &&
(p_lea_pair_cb->is_dumo_device)) {
APPL_TRACE_DEBUG("%s Ignore BD_ADDR because of ID %s", __func__,
p_lea_pair_cb->p_id_addr.ToString().c_str());
return 0;
}
}
return 1;
}
/*****************************************************************************
*
* Function devclass2uint
*
* Description This API is to derive the class of device based of dev_class
*
* Returns uint32_t - class of device
*
****************************************************************************/
static uint32_t devclass2uint(DEV_CLASS dev_class) {
uint32_t cod = 0;
if (dev_class != NULL) {
/* if COD is 0, irrespective of the device type set it to Unclassified
* device */
cod = (dev_class[2]) | (dev_class[1] << 8) | (dev_class[0] << 16);
}
return cod;
}
/*****************************************************************************
*
* Function bta_is_remote_support_lea
*
* Description This API is to check the remote device contains LEA service
* or not. It checks in Inquiry database initially.
* If the address is Public identity address then it will
* check in the pairing database of that remote device.
*
* Returns true - if remote device inquiry db contains LEA service
*
****************************************************************************/
bool bta_is_remote_support_lea(RawAddress p_addr) {
tBTM_INQ_INFO* p_inq_info;
p_inq_info = BTM_InqDbRead(p_addr);
if (p_inq_info != NULL) {
uint32_t cod = devclass2uint(p_inq_info->results.dev_class);
BTIF_TRACE_DEBUG("%s cod is 0x%06x", __func__, cod);
if ((cod & MAJOR_LE_AUDIO_VENDOR_COD)
== MAJOR_LE_AUDIO_VENDOR_COD) {
return true;
}
}
/* check the address is public identity address and its related to random
* address which supports to LEA then that Public ID address should return
* true.
*/
auto itr = bta_lea_pairing_cb.dev_addr_map.find(p_addr);
if (itr != bta_lea_pairing_cb.dev_addr_map.end()) {
BTIF_TRACE_DEBUG("%s Idenity address mapping", __func__);
return true;
}
return false;
}
void bta_find_adv_audio_group_instance(uint16_t conn_id, tGATT_STATUS status,
RawAddress p_addr) {
RawAddress p_id_addr =
bta_get_rem_dev_id_addr(p_addr);
if (p_id_addr != RawAddress::kEmpty) {
BTA_CsipFindCsisInstance(conn_id, status, p_id_addr);
} else {
BTA_CsipFindCsisInstance(conn_id, status, p_addr);
}
}
/*******************************************************************************
*
* Function is_gatt_srvc_disc_pending
*
* Description This function checks whether gatt_srvc_disc is processing
* or not
*
* Parameters:
*
******************************************************************************/
bool is_gatt_srvc_disc_pending(RawAddress rem_bda) {
tBTA_LE_AUDIO_DEV_INFO *p_lea_cb = bta_get_lea_ctrl_cb(rem_bda);
APPL_TRACE_DEBUG("%s ", __func__);
if (p_lea_cb == NULL) {
return false;
} else {
APPL_TRACE_DEBUG("%s gatt_disc_progress %d ", __func__,
p_lea_cb->gatt_disc_progress);
return p_lea_cb->gatt_disc_progress;
}
}
/******************************************************************************
*
* Function bta_get_pseudo_addr_with_id_addr
*
* Description This function returns the mapping id_addr(if present) to
* pseudo addr
*
* Parameters:
*
*****************************************************************************/
RawAddress bta_get_pseudo_addr_with_id_addr(RawAddress p_addr) {
auto itr = bta_lea_pairing_cb.dev_addr_map.find(p_addr);
APPL_TRACE_DEBUG("%s p_addr %s ", __func__, p_addr.ToString().c_str());
if (itr != bta_lea_pairing_cb.dev_addr_map.end()) {
APPL_TRACE_DEBUG("%s addr is mapped to %s ", __func__,
itr->second.ToString().c_str());
if (itr->second != RawAddress::kEmpty) {
return itr->second;
}
}
return p_addr;
}