bta_ag_sdp.c revision 20524d393e8b3bea4c573f7980cd843500b0e6a4
1/****************************************************************************** 2 * 3 * Copyright (C) 2003-2012 Broadcom Corporation 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at: 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 ******************************************************************************/ 18 19/****************************************************************************** 20 * 21 * This file contains the audio gateway functions performing SDP 22 * operations. 23 * 24 ******************************************************************************/ 25 26#include <string.h> 27#include "bta_api.h" 28#include "bta_sys.h" 29#include "bta_ag_api.h" 30#include "bta_ag_int.h" 31#include "sdp_api.h" 32#include "btm_api.h" 33#include "bt_common.h" 34#include "utl.h" 35 36/* Number of protocol elements in protocol element list. */ 37#define BTA_AG_NUM_PROTO_ELEMS 2 38 39/* Number of elements in service class id list. */ 40#define BTA_AG_NUM_SVC_ELEMS 2 41 42/* size of database for service discovery */ 43#ifndef BTA_AG_DISC_BUF_SIZE 44#define BTA_AG_DISC_BUF_SIZE BT_DEFAULT_BUFFER_SIZE 45#endif 46 47/* declare sdp callback functions */ 48void bta_ag_sdp_cback_1(UINT16 status); 49void bta_ag_sdp_cback_2(UINT16 status); 50void bta_ag_sdp_cback_3(UINT16 status); 51 52/* SDP callback function table */ 53typedef tSDP_DISC_CMPL_CB *tBTA_AG_SDP_CBACK; 54const tBTA_AG_SDP_CBACK bta_ag_sdp_cback_tbl[] = 55{ 56 bta_ag_sdp_cback_1, 57 bta_ag_sdp_cback_2, 58 bta_ag_sdp_cback_3 59}; 60 61/******************************************************************************* 62** 63** Function bta_ag_sdp_cback 64** 65** Description SDP callback function. 66** 67** 68** Returns void 69** 70*******************************************************************************/ 71static void bta_ag_sdp_cback(UINT16 status, UINT8 idx) 72{ 73 tBTA_AG_DISC_RESULT *p_buf; 74 UINT16 event; 75 tBTA_AG_SCB *p_scb; 76 77 APPL_TRACE_DEBUG("bta_ag_sdp_cback status:0x%x", status); 78 79 if ((p_scb = bta_ag_scb_by_idx(idx)) != NULL) 80 { 81 /* set event according to int/acp */ 82 if (p_scb->role == BTA_AG_ACP) 83 { 84 event = BTA_AG_DISC_ACP_RES_EVT; 85 } 86 else 87 { 88 event = BTA_AG_DISC_INT_RES_EVT; 89 } 90 91 if ((p_buf = (tBTA_AG_DISC_RESULT *) osi_getbuf(sizeof(tBTA_AG_DISC_RESULT))) != NULL) 92 { 93 p_buf->hdr.event = event; 94 p_buf->hdr.layer_specific = idx; 95 p_buf->status = status; 96 bta_sys_sendmsg(p_buf); 97 } 98 } 99} 100 101/******************************************************************************* 102** 103** Function bta_ag_sdp_cback_1 to 3 104** 105** Description SDP callback functions. Since there is no way to 106** distinguish scb from the callback we need separate 107** callbacks for each scb. 108** 109** 110** Returns void 111** 112*******************************************************************************/ 113void bta_ag_sdp_cback_1(UINT16 status) {bta_ag_sdp_cback(status, 1);} 114void bta_ag_sdp_cback_2(UINT16 status) {bta_ag_sdp_cback(status, 2);} 115void bta_ag_sdp_cback_3(UINT16 status) {bta_ag_sdp_cback(status, 3);} 116 117/****************************************************************************** 118** 119** Function bta_ag_add_record 120** 121** Description This function is called by a server application to add 122** HSP or HFP information to an SDP record. Prior to 123** calling this function the application must call 124** SDP_CreateRecord() to create an SDP record. 125** 126** Returns TRUE if function execution succeeded, 127** FALSE if function execution failed. 128** 129******************************************************************************/ 130BOOLEAN bta_ag_add_record(UINT16 service_uuid, char *p_service_name, UINT8 scn, 131 tBTA_AG_FEAT features, UINT32 sdp_handle) 132{ 133 tSDP_PROTOCOL_ELEM proto_elem_list[BTA_AG_NUM_PROTO_ELEMS]; 134 UINT16 svc_class_id_list[BTA_AG_NUM_SVC_ELEMS]; 135 UINT16 browse_list[] = {UUID_SERVCLASS_PUBLIC_BROWSE_GROUP}; 136 UINT16 version; 137 UINT16 profile_uuid; 138 UINT8 network; 139 BOOLEAN result = TRUE; 140 BOOLEAN codec_supported = FALSE; 141 UINT8 buf[2]; 142 143 APPL_TRACE_DEBUG("bta_ag_add_record uuid: %x", service_uuid); 144 145 memset( proto_elem_list, 0 , BTA_AG_NUM_PROTO_ELEMS*sizeof(tSDP_PROTOCOL_ELEM)); 146 147 /* add the protocol element sequence */ 148 proto_elem_list[0].protocol_uuid = UUID_PROTOCOL_L2CAP; 149 proto_elem_list[0].num_params = 0; 150 proto_elem_list[1].protocol_uuid = UUID_PROTOCOL_RFCOMM; 151 proto_elem_list[1].num_params = 1; 152 proto_elem_list[1].params[0] = scn; 153 result &= SDP_AddProtocolList(sdp_handle, BTA_AG_NUM_PROTO_ELEMS, proto_elem_list); 154 155 /* add service class id list */ 156 svc_class_id_list[0] = service_uuid; 157 svc_class_id_list[1] = UUID_SERVCLASS_GENERIC_AUDIO; 158 result &= SDP_AddServiceClassIdList(sdp_handle, BTA_AG_NUM_SVC_ELEMS, svc_class_id_list); 159 160 /* add profile descriptor list */ 161 if (service_uuid == UUID_SERVCLASS_AG_HANDSFREE) 162 { 163 profile_uuid = UUID_SERVCLASS_HF_HANDSFREE; 164 version = HFP_VERSION_1_6; 165 } 166 else 167 { 168 profile_uuid = UUID_SERVCLASS_HEADSET; 169 version = HSP_VERSION_1_2; 170 } 171 result &= SDP_AddProfileDescriptorList(sdp_handle, profile_uuid, version); 172 173 /* add service name */ 174 if (p_service_name != NULL && p_service_name[0] != 0) 175 { 176 result &= SDP_AddAttribute(sdp_handle, ATTR_ID_SERVICE_NAME, TEXT_STR_DESC_TYPE, 177 (UINT32)(strlen(p_service_name)+1), (UINT8 *) p_service_name); 178 } 179 180 /* add features and network */ 181 if (service_uuid == UUID_SERVCLASS_AG_HANDSFREE) 182 { 183 network = (features & BTA_AG_FEAT_REJECT) ? 1 : 0; 184 result &= SDP_AddAttribute(sdp_handle, ATTR_ID_DATA_STORES_OR_NETWORK, 185 UINT_DESC_TYPE, 1, &network); 186 187 if (features & BTA_AG_FEAT_CODEC) 188 codec_supported = TRUE; 189 190 features &= BTA_AG_SDP_FEAT_SPEC; 191 192 /* Codec bit position is different in SDP and in BRSF */ 193 if (codec_supported) 194 features |= 0x0020; 195 196 UINT16_TO_BE_FIELD(buf, features); 197 result &= SDP_AddAttribute(sdp_handle, ATTR_ID_SUPPORTED_FEATURES, UINT_DESC_TYPE, 2, buf); 198 } 199 200 /* add browse group list */ 201 result &= SDP_AddUuidSequence(sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, browse_list); 202 203 return result; 204} 205 206/******************************************************************************* 207** 208** Function bta_ag_create_records 209** 210** Description Create SDP records for registered services. 211** 212** 213** Returns void 214** 215*******************************************************************************/ 216void bta_ag_create_records(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data) 217{ 218 int i; 219 tBTA_SERVICE_MASK services; 220 221 services = p_scb->reg_services >> BTA_HSP_SERVICE_ID; 222 for (i = 0; i < BTA_AG_NUM_IDX && services != 0; i++, services >>= 1) 223 { 224 /* if service is set in mask */ 225 if (services & 1) 226 { 227 /* add sdp record if not already registered */ 228 if (bta_ag_cb.profile[i].sdp_handle == 0) 229 { 230 bta_ag_cb.profile[i].sdp_handle = SDP_CreateRecord(); 231 bta_ag_cb.profile[i].scn = BTM_AllocateSCN(); 232 bta_ag_add_record(bta_ag_uuid[i], p_data->api_register.p_name[i], 233 bta_ag_cb.profile[i].scn, p_data->api_register.features, 234 bta_ag_cb.profile[i].sdp_handle); 235 bta_sys_add_uuid(bta_ag_uuid[i]); 236 } 237 } 238 } 239 240 p_scb->hsp_version = HSP_VERSION_1_2; 241 242} 243 244/******************************************************************************* 245** 246** Function bta_ag_del_records 247** 248** Description Delete SDP records for any registered services. 249** 250** 251** Returns void 252** 253*******************************************************************************/ 254void bta_ag_del_records(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data) 255{ 256 tBTA_AG_SCB *p = &bta_ag_cb.scb[0]; 257 tBTA_SERVICE_MASK services; 258 tBTA_SERVICE_MASK others = 0; 259 int i; 260 UNUSED(p_data); 261 262 /* get services of all other registered servers */ 263 for (i = 0; i < BTA_AG_NUM_IDX; i++, p++) 264 { 265 if (p_scb == p) 266 { 267 continue; 268 } 269 270 if (p->in_use && p->dealloc == FALSE) 271 { 272 others |= p->reg_services; 273 } 274 } 275 276 others >>= BTA_HSP_SERVICE_ID; 277 services = p_scb->reg_services >> BTA_HSP_SERVICE_ID; 278 for (i = 0; i < BTA_AG_NUM_IDX && services != 0; i++, services >>= 1, others >>= 1) 279 { 280 /* if service registered for this scb and not registered for any other scb */ 281 if (((services & 1) == 1) && ((others & 1) == 0)) 282 { 283 APPL_TRACE_DEBUG("bta_ag_del_records %d", i); 284 if (bta_ag_cb.profile[i].sdp_handle != 0) 285 { 286 SDP_DeleteRecord(bta_ag_cb.profile[i].sdp_handle); 287 bta_ag_cb.profile[i].sdp_handle = 0; 288 } 289 BTM_FreeSCN(bta_ag_cb.profile[i].scn); 290 BTM_SecClrService(bta_ag_sec_id[i]); 291 bta_sys_remove_uuid(bta_ag_uuid[i]); 292 } 293 } 294} 295 296/******************************************************************************* 297** 298** Function bta_ag_sdp_find_attr 299** 300** Description Process SDP discovery results to find requested attributes 301** for requested service. 302** 303** 304** Returns TRUE if results found, FALSE otherwise. 305** 306*******************************************************************************/ 307BOOLEAN bta_ag_sdp_find_attr(tBTA_AG_SCB *p_scb, tBTA_SERVICE_MASK service) 308{ 309 tSDP_DISC_REC *p_rec = NULL; 310 tSDP_DISC_ATTR *p_attr; 311 tSDP_PROTOCOL_ELEM pe; 312 UINT16 uuid; 313 BOOLEAN result = FALSE; 314 315 if (service & BTA_HFP_SERVICE_MASK) 316 { 317 uuid = UUID_SERVCLASS_HF_HANDSFREE; 318 p_scb->peer_version = HFP_VERSION_1_1; /* Default version */ 319 } 320 else if (service & BTA_HSP_SERVICE_MASK && p_scb->role == BTA_AG_INT) 321 { 322 uuid = UUID_SERVCLASS_HEADSET_HS; 323 p_scb->peer_version = 0x0100; /* Default version */ 324 } 325 else 326 { 327 return result; 328 } 329 330 /* loop through all records we found */ 331 while (TRUE) 332 { 333 /* get next record; if none found, we're done */ 334 if ((p_rec = SDP_FindServiceInDb(p_scb->p_disc_db, uuid, p_rec)) == NULL) 335 { 336 if (uuid == UUID_SERVCLASS_HEADSET_HS) 337 { 338 /* Search again in case the peer device is HSP v1.0 */ 339 uuid = UUID_SERVCLASS_HEADSET; 340 if ((p_rec = SDP_FindServiceInDb(p_scb->p_disc_db, uuid, p_rec)) == NULL) 341 { 342 break; 343 } 344 } 345 else 346 break; 347 } 348 349 /* get scn from proto desc list if initiator */ 350 if (p_scb->role == BTA_AG_INT) 351 { 352 if (SDP_FindProtocolListElemInRec(p_rec, UUID_PROTOCOL_RFCOMM, &pe)) 353 { 354 p_scb->peer_scn = (UINT8) pe.params[0]; 355 } 356 else 357 { 358 continue; 359 } 360 } 361 362 /* get profile version (if failure, version parameter is not updated) */ 363 SDP_FindProfileVersionInRec(p_rec, uuid, &p_scb->peer_version); 364 365 /* get features if HFP */ 366 if (service & BTA_HFP_SERVICE_MASK) 367 { 368 if ((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_SUPPORTED_FEATURES)) != NULL) 369 { 370 /* Found attribute. Get value. */ 371 /* There might be race condition between SDP and BRSF. */ 372 /* Do not update if we already received BRSF. */ 373 if (p_scb->peer_features == 0) 374 p_scb->peer_features = p_attr->attr_value.v.u16; 375 } 376 } 377 else /* HSP */ 378 { 379 if ((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_REMOTE_AUDIO_VOLUME_CONTROL)) != NULL) 380 { 381 /* Remote volume control of HSP */ 382 if (p_attr->attr_value.v.u8) 383 p_scb->peer_features |= BTA_AG_PEER_FEAT_VOL; 384 else 385 p_scb->peer_features &= ~BTA_AG_PEER_FEAT_VOL; 386 } 387 388 } 389 390 /* found what we needed */ 391 result = TRUE; 392 break; 393 } 394 return result; 395} 396 397/******************************************************************************* 398** 399** Function bta_ag_do_disc 400** 401** Description Do service discovery. 402** 403** 404** Returns void 405** 406*******************************************************************************/ 407void bta_ag_do_disc(tBTA_AG_SCB *p_scb, tBTA_SERVICE_MASK service) 408{ 409 tSDP_UUID uuid_list[2]; 410 UINT16 num_uuid = 1; 411 UINT16 attr_list[4]; 412 UINT8 num_attr; 413 BOOLEAN db_inited = FALSE; 414 415 /* HFP initiator; get proto list and features */ 416 if (service & BTA_HFP_SERVICE_MASK && p_scb->role == BTA_AG_INT) 417 { 418 attr_list[0] = ATTR_ID_SERVICE_CLASS_ID_LIST; 419 attr_list[1] = ATTR_ID_PROTOCOL_DESC_LIST; 420 attr_list[2] = ATTR_ID_BT_PROFILE_DESC_LIST; 421 attr_list[3] = ATTR_ID_SUPPORTED_FEATURES; 422 num_attr = 4; 423 uuid_list[0].uu.uuid16 = UUID_SERVCLASS_HF_HANDSFREE; 424 } 425 /* HFP acceptor; get features */ 426 else if (service & BTA_HFP_SERVICE_MASK && p_scb->role == BTA_AG_ACP) 427 { 428 attr_list[0] = ATTR_ID_SERVICE_CLASS_ID_LIST; 429 attr_list[1] = ATTR_ID_BT_PROFILE_DESC_LIST; 430 attr_list[2] = ATTR_ID_SUPPORTED_FEATURES; 431 num_attr = 3; 432 uuid_list[0].uu.uuid16 = UUID_SERVCLASS_HF_HANDSFREE; 433 } 434 /* HSP initiator; get proto list */ 435 else if (service & BTA_HSP_SERVICE_MASK && p_scb->role == BTA_AG_INT) 436 { 437 attr_list[0] = ATTR_ID_SERVICE_CLASS_ID_LIST; 438 attr_list[1] = ATTR_ID_PROTOCOL_DESC_LIST; 439 attr_list[2] = ATTR_ID_BT_PROFILE_DESC_LIST; 440 attr_list[3] = ATTR_ID_REMOTE_AUDIO_VOLUME_CONTROL; 441 num_attr = 4; 442 443 uuid_list[0].uu.uuid16 = UUID_SERVCLASS_HEADSET; /* Legacy from HSP v1.0 */ 444 if (p_scb->hsp_version >= HSP_VERSION_1_2) 445 { 446 uuid_list[1].uu.uuid16 = UUID_SERVCLASS_HEADSET_HS; 447 num_uuid = 2; 448 } 449 } 450 /* HSP acceptor; no discovery */ 451 else 452 { 453 return; 454 } 455 456 /* allocate buffer for sdp database */ 457 p_scb->p_disc_db = (tSDP_DISCOVERY_DB *) osi_getbuf(BTA_AG_DISC_BUF_SIZE); 458 459 if(p_scb->p_disc_db) 460 { 461 /* set up service discovery database; attr happens to be attr_list len */ 462 uuid_list[0].len = LEN_UUID_16; 463 uuid_list[1].len = LEN_UUID_16; 464 db_inited = SDP_InitDiscoveryDb(p_scb->p_disc_db, BTA_AG_DISC_BUF_SIZE, num_uuid, 465 uuid_list, num_attr, attr_list); 466 } 467 468 if(db_inited) 469 { 470 /*Service discovery not initiated */ 471 db_inited = SDP_ServiceSearchAttributeRequest(p_scb->peer_addr, p_scb->p_disc_db, 472 bta_ag_sdp_cback_tbl[bta_ag_scb_to_idx(p_scb) - 1]); 473 } 474 475 if(!db_inited) 476 { 477 /*free discover db */ 478 bta_ag_free_db(p_scb, NULL); 479 /* sent failed event */ 480 bta_ag_sm_execute(p_scb, BTA_AG_DISC_FAIL_EVT, NULL); 481 } 482 483} 484 485/******************************************************************************* 486** 487** Function bta_ag_free_db 488** 489** Description Free discovery database. 490** 491** 492** Returns void 493** 494*******************************************************************************/ 495void bta_ag_free_db(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data) 496{ 497 UNUSED(p_data); 498 osi_freebuf_and_reset((void **)&p_scb->p_disc_db); 499} 500