1 /******************************************************************************
3 * Copyright (C) 2003-2012 Broadcom Corporation
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:
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 ******************************************************************************/
19 /******************************************************************************
21 * This file contains the audio gateway functions performing SDP
24 ******************************************************************************/
32 #include "bta_ag_api.h"
33 #include "bta_ag_int.h"
36 #include "bt_common.h"
40 /* Number of protocol elements in protocol element list. */
41 #define BTA_AG_NUM_PROTO_ELEMS 2
43 /* Number of elements in service class id list. */
44 #define BTA_AG_NUM_SVC_ELEMS 2
46 /* size of database for service discovery */
47 #ifndef BTA_AG_DISC_BUF_SIZE
48 #define BTA_AG_DISC_BUF_SIZE BT_DEFAULT_BUFFER_SIZE
51 /* declare sdp callback functions */
52 void bta_ag_sdp_cback_1(UINT16 status);
53 void bta_ag_sdp_cback_2(UINT16 status);
54 void bta_ag_sdp_cback_3(UINT16 status);
56 /* SDP callback function table */
57 typedef tSDP_DISC_CMPL_CB *tBTA_AG_SDP_CBACK;
58 const tBTA_AG_SDP_CBACK bta_ag_sdp_cback_tbl[] =
65 /*******************************************************************************
67 ** Function bta_ag_sdp_cback
69 ** Description SDP callback function.
74 *******************************************************************************/
75 static void bta_ag_sdp_cback(UINT16 status, UINT8 idx)
80 APPL_TRACE_DEBUG("bta_ag_sdp_cback status:0x%x", status);
82 if ((p_scb = bta_ag_scb_by_idx(idx)) != NULL)
84 /* set event according to int/acp */
85 if (p_scb->role == BTA_AG_ACP)
87 event = BTA_AG_DISC_ACP_RES_EVT;
91 event = BTA_AG_DISC_INT_RES_EVT;
94 tBTA_AG_DISC_RESULT *p_buf =
95 (tBTA_AG_DISC_RESULT *)osi_malloc(sizeof(tBTA_AG_DISC_RESULT));
96 p_buf->hdr.event = event;
97 p_buf->hdr.layer_specific = idx;
98 p_buf->status = status;
99 bta_sys_sendmsg(p_buf);
103 /*******************************************************************************
105 ** Function bta_ag_sdp_cback_1 to 3
107 ** Description SDP callback functions. Since there is no way to
108 ** distinguish scb from the callback we need separate
109 ** callbacks for each scb.
114 *******************************************************************************/
115 void bta_ag_sdp_cback_1(UINT16 status) {bta_ag_sdp_cback(status, 1);}
116 void bta_ag_sdp_cback_2(UINT16 status) {bta_ag_sdp_cback(status, 2);}
117 void bta_ag_sdp_cback_3(UINT16 status) {bta_ag_sdp_cback(status, 3);}
119 /******************************************************************************
121 ** Function bta_ag_add_record
123 ** Description This function is called by a server application to add
124 ** HSP or HFP information to an SDP record. Prior to
125 ** calling this function the application must call
126 ** SDP_CreateRecord() to create an SDP record.
128 ** Returns TRUE if function execution succeeded,
129 ** FALSE if function execution failed.
131 ******************************************************************************/
132 BOOLEAN bta_ag_add_record(UINT16 service_uuid, char *p_service_name, UINT8 scn,
133 tBTA_AG_FEAT features, UINT32 sdp_handle)
135 tSDP_PROTOCOL_ELEM proto_elem_list[BTA_AG_NUM_PROTO_ELEMS];
136 UINT16 svc_class_id_list[BTA_AG_NUM_SVC_ELEMS];
137 UINT16 browse_list[] = {UUID_SERVCLASS_PUBLIC_BROWSE_GROUP};
141 BOOLEAN result = TRUE;
142 BOOLEAN codec_supported = FALSE;
145 APPL_TRACE_DEBUG("bta_ag_add_record uuid: %x", service_uuid);
147 memset( proto_elem_list, 0 , BTA_AG_NUM_PROTO_ELEMS*sizeof(tSDP_PROTOCOL_ELEM));
149 /* add the protocol element sequence */
150 proto_elem_list[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
151 proto_elem_list[0].num_params = 0;
152 proto_elem_list[1].protocol_uuid = UUID_PROTOCOL_RFCOMM;
153 proto_elem_list[1].num_params = 1;
154 proto_elem_list[1].params[0] = scn;
155 result &= SDP_AddProtocolList(sdp_handle, BTA_AG_NUM_PROTO_ELEMS, proto_elem_list);
157 /* add service class id list */
158 svc_class_id_list[0] = service_uuid;
159 svc_class_id_list[1] = UUID_SERVCLASS_GENERIC_AUDIO;
160 result &= SDP_AddServiceClassIdList(sdp_handle, BTA_AG_NUM_SVC_ELEMS, svc_class_id_list);
162 /* add profile descriptor list */
163 if (service_uuid == UUID_SERVCLASS_AG_HANDSFREE)
165 profile_uuid = UUID_SERVCLASS_HF_HANDSFREE;
166 version = HFP_VERSION_1_6;
170 profile_uuid = UUID_SERVCLASS_HEADSET;
171 version = HSP_VERSION_1_2;
173 result &= SDP_AddProfileDescriptorList(sdp_handle, profile_uuid, version);
175 /* add service name */
176 if (p_service_name != NULL && p_service_name[0] != 0)
178 result &= SDP_AddAttribute(sdp_handle, ATTR_ID_SERVICE_NAME, TEXT_STR_DESC_TYPE,
179 (UINT32)(strlen(p_service_name)+1), (UINT8 *) p_service_name);
182 /* add features and network */
183 if (service_uuid == UUID_SERVCLASS_AG_HANDSFREE)
185 network = (features & BTA_AG_FEAT_REJECT) ? 1 : 0;
186 result &= SDP_AddAttribute(sdp_handle, ATTR_ID_DATA_STORES_OR_NETWORK,
187 UINT_DESC_TYPE, 1, &network);
189 if (features & BTA_AG_FEAT_CODEC)
190 codec_supported = TRUE;
192 features &= BTA_AG_SDP_FEAT_SPEC;
194 /* Codec bit position is different in SDP and in BRSF */
198 UINT16_TO_BE_FIELD(buf, features);
199 result &= SDP_AddAttribute(sdp_handle, ATTR_ID_SUPPORTED_FEATURES, UINT_DESC_TYPE, 2, buf);
202 /* add browse group list */
203 result &= SDP_AddUuidSequence(sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, browse_list);
208 /*******************************************************************************
210 ** Function bta_ag_create_records
212 ** Description Create SDP records for registered services.
217 *******************************************************************************/
218 void bta_ag_create_records(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
221 tBTA_SERVICE_MASK services;
223 services = p_scb->reg_services >> BTA_HSP_SERVICE_ID;
224 for (i = 0; i < BTA_AG_NUM_IDX && services != 0; i++, services >>= 1)
226 /* if service is set in mask */
229 /* add sdp record if not already registered */
230 if (bta_ag_cb.profile[i].sdp_handle == 0)
232 bta_ag_cb.profile[i].sdp_handle = SDP_CreateRecord();
233 bta_ag_cb.profile[i].scn = BTM_AllocateSCN();
234 bta_ag_add_record(bta_ag_uuid[i], p_data->api_register.p_name[i],
235 bta_ag_cb.profile[i].scn, p_data->api_register.features,
236 bta_ag_cb.profile[i].sdp_handle);
237 bta_sys_add_uuid(bta_ag_uuid[i]);
242 p_scb->hsp_version = HSP_VERSION_1_2;
246 /*******************************************************************************
248 ** Function bta_ag_del_records
250 ** Description Delete SDP records for any registered services.
255 *******************************************************************************/
256 void bta_ag_del_records(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
258 tBTA_AG_SCB *p = &bta_ag_cb.scb[0];
259 tBTA_SERVICE_MASK services;
260 tBTA_SERVICE_MASK others = 0;
264 /* get services of all other registered servers */
265 for (i = 0; i < BTA_AG_NUM_IDX; i++, p++)
272 if (p->in_use && p->dealloc == FALSE)
274 others |= p->reg_services;
278 others >>= BTA_HSP_SERVICE_ID;
279 services = p_scb->reg_services >> BTA_HSP_SERVICE_ID;
280 for (i = 0; i < BTA_AG_NUM_IDX && services != 0; i++, services >>= 1, others >>= 1)
282 /* if service registered for this scb and not registered for any other scb */
283 if (((services & 1) == 1) && ((others & 1) == 0))
285 APPL_TRACE_DEBUG("bta_ag_del_records %d", i);
286 if (bta_ag_cb.profile[i].sdp_handle != 0)
288 SDP_DeleteRecord(bta_ag_cb.profile[i].sdp_handle);
289 bta_ag_cb.profile[i].sdp_handle = 0;
291 BTM_FreeSCN(bta_ag_cb.profile[i].scn);
292 BTM_SecClrService(bta_ag_sec_id[i]);
293 bta_sys_remove_uuid(bta_ag_uuid[i]);
298 /*******************************************************************************
300 ** Function bta_ag_sdp_find_attr
302 ** Description Process SDP discovery results to find requested attributes
303 ** for requested service.
306 ** Returns TRUE if results found, FALSE otherwise.
308 *******************************************************************************/
309 BOOLEAN bta_ag_sdp_find_attr(tBTA_AG_SCB *p_scb, tBTA_SERVICE_MASK service)
311 tSDP_DISC_REC *p_rec = NULL;
312 tSDP_DISC_ATTR *p_attr;
313 tSDP_PROTOCOL_ELEM pe;
315 BOOLEAN result = FALSE;
317 if (service & BTA_HFP_SERVICE_MASK)
319 uuid = UUID_SERVCLASS_HF_HANDSFREE;
320 p_scb->peer_version = HFP_VERSION_1_1; /* Default version */
322 else if (service & BTA_HSP_SERVICE_MASK && p_scb->role == BTA_AG_INT)
324 uuid = UUID_SERVCLASS_HEADSET_HS;
325 p_scb->peer_version = 0x0100; /* Default version */
332 /* loop through all records we found */
335 /* get next record; if none found, we're done */
336 if ((p_rec = SDP_FindServiceInDb(p_scb->p_disc_db, uuid, p_rec)) == NULL)
338 if (uuid == UUID_SERVCLASS_HEADSET_HS)
340 /* Search again in case the peer device is HSP v1.0 */
341 uuid = UUID_SERVCLASS_HEADSET;
342 if ((p_rec = SDP_FindServiceInDb(p_scb->p_disc_db, uuid, p_rec)) == NULL)
351 /* get scn from proto desc list if initiator */
352 if (p_scb->role == BTA_AG_INT)
354 if (SDP_FindProtocolListElemInRec(p_rec, UUID_PROTOCOL_RFCOMM, &pe))
356 p_scb->peer_scn = (UINT8) pe.params[0];
364 /* get profile version (if failure, version parameter is not updated) */
365 SDP_FindProfileVersionInRec(p_rec, uuid, &p_scb->peer_version);
367 /* get features if HFP */
368 if (service & BTA_HFP_SERVICE_MASK)
370 if ((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_SUPPORTED_FEATURES)) != NULL)
372 /* Found attribute. Get value. */
373 /* There might be race condition between SDP and BRSF. */
374 /* Do not update if we already received BRSF. */
375 if (p_scb->peer_features == 0)
376 p_scb->peer_features = p_attr->attr_value.v.u16;
379 /* Remote supports 1.7, store it in the file */
380 if (p_scb->peer_version == HFP_VERSION_1_7)
383 /* Check if the device is already part of the list, if not store it */
384 ret = is_device_present(IOT_HFP_1_7_BLACKLIST, p_scb->peer_addr);
388 add_iot_device(IOT_DEV_CONF_FILE, IOT_HFP_1_7_BLACKLIST,
389 p_scb->peer_addr, METHOD_BD);
395 if ((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_REMOTE_AUDIO_VOLUME_CONTROL)) != NULL)
397 /* Remote volume control of HSP */
398 if (p_attr->attr_value.v.u8)
399 p_scb->peer_features |= BTA_AG_PEER_FEAT_VOL;
401 p_scb->peer_features &= ~BTA_AG_PEER_FEAT_VOL;
406 /* found what we needed */
413 /*******************************************************************************
415 ** Function bta_ag_do_disc
417 ** Description Do service discovery.
422 *******************************************************************************/
423 void bta_ag_do_disc(tBTA_AG_SCB *p_scb, tBTA_SERVICE_MASK service)
425 tSDP_UUID uuid_list[2];
429 BOOLEAN db_inited = FALSE;
431 /* HFP initiator; get proto list and features */
432 if (service & BTA_HFP_SERVICE_MASK && p_scb->role == BTA_AG_INT)
434 attr_list[0] = ATTR_ID_SERVICE_CLASS_ID_LIST;
435 attr_list[1] = ATTR_ID_PROTOCOL_DESC_LIST;
436 attr_list[2] = ATTR_ID_BT_PROFILE_DESC_LIST;
437 attr_list[3] = ATTR_ID_SUPPORTED_FEATURES;
439 uuid_list[0].uu.uuid16 = UUID_SERVCLASS_HF_HANDSFREE;
441 /* HFP acceptor; get features */
442 else if (service & BTA_HFP_SERVICE_MASK && p_scb->role == BTA_AG_ACP)
444 attr_list[0] = ATTR_ID_SERVICE_CLASS_ID_LIST;
445 attr_list[1] = ATTR_ID_BT_PROFILE_DESC_LIST;
446 attr_list[2] = ATTR_ID_SUPPORTED_FEATURES;
448 uuid_list[0].uu.uuid16 = UUID_SERVCLASS_HF_HANDSFREE;
450 /* HSP initiator; get proto list */
451 else if (service & BTA_HSP_SERVICE_MASK && p_scb->role == BTA_AG_INT)
453 attr_list[0] = ATTR_ID_SERVICE_CLASS_ID_LIST;
454 attr_list[1] = ATTR_ID_PROTOCOL_DESC_LIST;
455 attr_list[2] = ATTR_ID_BT_PROFILE_DESC_LIST;
456 attr_list[3] = ATTR_ID_REMOTE_AUDIO_VOLUME_CONTROL;
459 uuid_list[0].uu.uuid16 = UUID_SERVCLASS_HEADSET; /* Legacy from HSP v1.0 */
460 if (p_scb->hsp_version >= HSP_VERSION_1_2)
462 uuid_list[1].uu.uuid16 = UUID_SERVCLASS_HEADSET_HS;
466 /* HSP acceptor; no discovery */
472 /* allocate buffer for sdp database */
473 p_scb->p_disc_db = (tSDP_DISCOVERY_DB *)osi_malloc(BTA_AG_DISC_BUF_SIZE);
474 /* set up service discovery database; attr happens to be attr_list len */
475 uuid_list[0].len = LEN_UUID_16;
476 uuid_list[1].len = LEN_UUID_16;
477 db_inited = SDP_InitDiscoveryDb(p_scb->p_disc_db, BTA_AG_DISC_BUF_SIZE,
478 num_uuid, uuid_list, num_attr, attr_list);
482 /*Service discovery not initiated */
483 /*Fix for below Klockwork issue
484 *Array 'bta_ag_sdp_cback_tbl' size is 3
485 *Possible attempt to access element -1,3..USHRT_MAX-1 of array 'bta_ag_sdp_cback_tbl' */
486 db_inited = SDP_ServiceSearchAttributeRequest(p_scb->peer_addr, p_scb->p_disc_db,
487 bta_ag_sdp_cback_tbl[(UINT16)(bta_ag_scb_to_idx(p_scb) - 1)]);
492 /*free discover db */
493 bta_ag_free_db(p_scb, NULL);
494 /* sent failed event */
495 bta_ag_sm_execute(p_scb, BTA_AG_DISC_FAIL_EVT, NULL);
500 /*******************************************************************************
502 ** Function bta_ag_free_db
504 ** Description Free discovery database.
509 *******************************************************************************/
510 void bta_ag_free_db(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
513 osi_free_and_reset((void **)&p_scb->p_disc_db);