1/****************************************************************************** 2 * 3 * Copyright (C) 2002-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 * ommon API for the Advanced Audio Distribution Profile (A2DP) 22 * 23 ******************************************************************************/ 24#include <string.h> 25#include "bt_target.h" 26#include "bt_common.h" 27#include "sdpdefs.h" 28#include "a2d_api.h" 29#include "a2d_int.h" 30#include "avdt_api.h" 31 32/***************************************************************************** 33** Global data 34*****************************************************************************/ 35#if A2D_DYNAMIC_MEMORY == FALSE 36tA2D_CB a2d_cb; 37#endif 38 39 40/****************************************************************************** 41** 42** Function a2d_sdp_cback 43** 44** Description This is the SDP callback function used by A2D_FindService. 45** This function will be executed by SDP when the service 46** search is completed. If the search is successful, it 47** finds the first record in the database that matches the 48** UUID of the search. Then retrieves various parameters 49** from the record. When it is finished it calls the 50** application callback function. 51** 52** Returns Nothing. 53** 54******************************************************************************/ 55static void a2d_sdp_cback(UINT16 status) 56{ 57 tSDP_DISC_REC *p_rec = NULL; 58 tSDP_DISC_ATTR *p_attr; 59 BOOLEAN found = FALSE; 60 tA2D_Service a2d_svc; 61 tSDP_PROTOCOL_ELEM elem; 62 63 A2D_TRACE_API("a2d_sdp_cback status: %d", status); 64 65 if (status == SDP_SUCCESS) 66 { 67 /* loop through all records we found */ 68 do 69 { 70 /* get next record; if none found, we're done */ 71 if ((p_rec = SDP_FindServiceInDb(a2d_cb.find.p_db, 72 a2d_cb.find.service_uuid, p_rec)) == NULL) 73 { 74 break; 75 } 76 memset(&a2d_svc, 0, sizeof(tA2D_Service)); 77 78 /* get service name */ 79 if ((p_attr = SDP_FindAttributeInRec(p_rec, 80 ATTR_ID_SERVICE_NAME)) != NULL) 81 { 82 a2d_svc.p_service_name = (char *) p_attr->attr_value.v.array; 83 a2d_svc.service_len = SDP_DISC_ATTR_LEN(p_attr->attr_len_type); 84 } 85 86 /* get provider name */ 87 if ((p_attr = SDP_FindAttributeInRec(p_rec, 88 ATTR_ID_PROVIDER_NAME)) != NULL) 89 { 90 a2d_svc.p_provider_name = (char *) p_attr->attr_value.v.array; 91 a2d_svc.provider_len = SDP_DISC_ATTR_LEN(p_attr->attr_len_type); 92 } 93 94 /* get supported features */ 95 if ((p_attr = SDP_FindAttributeInRec(p_rec, 96 ATTR_ID_SUPPORTED_FEATURES)) != NULL) 97 { 98 a2d_svc.features = p_attr->attr_value.v.u16; 99 } 100 101 /* get AVDTP version */ 102 if (SDP_FindProtocolListElemInRec(p_rec, UUID_PROTOCOL_AVDTP, &elem)) 103 { 104 a2d_svc.avdt_version = elem.params[0]; 105 A2D_TRACE_DEBUG("avdt_version: 0x%x", a2d_svc.avdt_version); 106 } 107 108 /* we've got everything, we're done */ 109 found = TRUE; 110 break; 111 112 } while (TRUE); 113 } 114 115 a2d_cb.find.service_uuid = 0; 116 osi_free_and_reset((void**)&a2d_cb.find.p_db); 117 /* return info from sdp record in app callback function */ 118 if (a2d_cb.find.p_cback != NULL) 119 { 120 (*a2d_cb.find.p_cback)(found, &a2d_svc); 121 } 122 123 return; 124} 125 126/******************************************************************************* 127** 128** Function a2d_set_avdt_sdp_ver 129** 130** Description This function allows the script wrapper to change the 131** avdt version of a2dp. 132** 133** Returns None 134** 135*******************************************************************************/ 136void a2d_set_avdt_sdp_ver (UINT16 avdt_sdp_ver) 137{ 138 a2d_cb.avdt_sdp_ver = avdt_sdp_ver; 139} 140 141/****************************************************************************** 142** 143** Function A2D_AddRecord 144** 145** Description This function is called by a server application to add 146** SRC or SNK information to an SDP record. Prior to 147** calling this function the application must call 148** SDP_CreateRecord() to create an SDP record. 149** 150** Input Parameters: 151** service_uuid: Indicates SRC or SNK. 152** 153** p_service_name: Pointer to a null-terminated character 154** string containing the service name. 155** 156** p_provider_name: Pointer to a null-terminated character 157** string containing the provider name. 158** 159** features: Profile supported features. 160** 161** sdp_handle: SDP handle returned by SDP_CreateRecord(). 162** 163** Output Parameters: 164** None. 165** 166** Returns A2D_SUCCESS if function execution succeeded, 167** A2D_INVALID_PARAMS if bad parameters are given. 168** A2D_FAIL if function execution failed. 169** 170******************************************************************************/ 171tA2D_STATUS A2D_AddRecord(UINT16 service_uuid, char *p_service_name, char *p_provider_name, 172 UINT16 features, UINT32 sdp_handle) 173{ 174 UINT16 browse_list[1]; 175 BOOLEAN result = TRUE; 176 UINT8 temp[8]; 177 UINT8 *p; 178 tSDP_PROTOCOL_ELEM proto_list [A2D_NUM_PROTO_ELEMS]; 179 180 A2D_TRACE_API("A2D_AddRecord uuid: %x", service_uuid); 181 182 if( (sdp_handle == 0) || 183 (service_uuid != UUID_SERVCLASS_AUDIO_SOURCE && service_uuid != UUID_SERVCLASS_AUDIO_SINK) ) 184 return A2D_INVALID_PARAMS; 185 186 /* add service class id list */ 187 result &= SDP_AddServiceClassIdList(sdp_handle, 1, &service_uuid); 188 189 memset((void*) proto_list, 0 , A2D_NUM_PROTO_ELEMS*sizeof(tSDP_PROTOCOL_ELEM)); 190 191 /* add protocol descriptor list */ 192 proto_list[0].protocol_uuid = UUID_PROTOCOL_L2CAP; 193 proto_list[0].num_params = 1; 194 proto_list[0].params[0] = AVDT_PSM; 195 proto_list[1].protocol_uuid = UUID_PROTOCOL_AVDTP; 196 proto_list[1].num_params = 1; 197 proto_list[1].params[0] = a2d_cb.avdt_sdp_ver; 198 199 result &= SDP_AddProtocolList(sdp_handle, A2D_NUM_PROTO_ELEMS, proto_list); 200 201 /* add profile descriptor list */ 202 result &= SDP_AddProfileDescriptorList(sdp_handle, UUID_SERVCLASS_ADV_AUDIO_DISTRIBUTION, A2D_VERSION); 203 204 /* add supported feature */ 205 if (features != 0) 206 { 207 p = temp; 208 UINT16_TO_BE_STREAM(p, features); 209 result &= SDP_AddAttribute(sdp_handle, ATTR_ID_SUPPORTED_FEATURES, UINT_DESC_TYPE, 210 (UINT32)2, (UINT8*)temp); 211 } 212 213 /* add provider name */ 214 if (p_provider_name != NULL) 215 { 216 result &= SDP_AddAttribute(sdp_handle, ATTR_ID_PROVIDER_NAME, TEXT_STR_DESC_TYPE, 217 (UINT32)(strlen(p_provider_name)+1), (UINT8 *) p_provider_name); 218 } 219 220 /* add service name */ 221 if (p_service_name != NULL) 222 { 223 result &= SDP_AddAttribute(sdp_handle, ATTR_ID_SERVICE_NAME, TEXT_STR_DESC_TYPE, 224 (UINT32)(strlen(p_service_name)+1), (UINT8 *) p_service_name); 225 } 226 227 /* add browse group list */ 228 browse_list[0] = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP; 229 result &= SDP_AddUuidSequence(sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, browse_list); 230 231 232 return (result ? A2D_SUCCESS : A2D_FAIL); 233} 234 235/****************************************************************************** 236** 237** Function A2D_FindService 238** 239** Description This function is called by a client application to 240** perform service discovery and retrieve SRC or SNK SDP 241** record information from a server. Information is 242** returned for the first service record found on the 243** server that matches the service UUID. The callback 244** function will be executed when service discovery is 245** complete. There can only be one outstanding call to 246** A2D_FindService() at a time; the application must wait 247** for the callback before it makes another call to 248** the function. 249** 250** Input Parameters: 251** service_uuid: Indicates SRC or SNK. 252** 253** bd_addr: BD address of the peer device. 254** 255** p_db: Pointer to the information to initialize 256** the discovery database. 257** 258** p_cback: Pointer to the A2D_FindService() 259** callback function. 260** 261** Output Parameters: 262** None. 263** 264** Returns A2D_SUCCESS if function execution succeeded, 265** A2D_INVALID_PARAMS if bad parameters are given. 266** A2D_BUSY if discovery is already in progress. 267** A2D_FAIL if function execution failed. 268** 269******************************************************************************/ 270tA2D_STATUS A2D_FindService(UINT16 service_uuid, BD_ADDR bd_addr, 271 tA2D_SDP_DB_PARAMS *p_db, tA2D_FIND_CBACK *p_cback) 272{ 273 tSDP_UUID uuid_list; 274 BOOLEAN result = TRUE; 275 UINT16 a2d_attr_list[] = {ATTR_ID_SERVICE_CLASS_ID_LIST, /* update A2D_NUM_ATTR, if changed */ 276 ATTR_ID_BT_PROFILE_DESC_LIST, 277 ATTR_ID_SUPPORTED_FEATURES, 278 ATTR_ID_SERVICE_NAME, 279 ATTR_ID_PROTOCOL_DESC_LIST, 280 ATTR_ID_PROVIDER_NAME}; 281 282 A2D_TRACE_API("A2D_FindService uuid: %x", service_uuid); 283 if( (service_uuid != UUID_SERVCLASS_AUDIO_SOURCE && service_uuid != UUID_SERVCLASS_AUDIO_SINK) || 284 p_db == NULL || p_cback == NULL) 285 return A2D_INVALID_PARAMS; 286 287 if( a2d_cb.find.service_uuid == UUID_SERVCLASS_AUDIO_SOURCE || 288 a2d_cb.find.service_uuid == UUID_SERVCLASS_AUDIO_SINK) 289 return A2D_BUSY; 290 291 /* set up discovery database */ 292 uuid_list.len = LEN_UUID_16; 293 uuid_list.uu.uuid16 = service_uuid; 294 295 if(p_db->p_attrs == NULL || p_db->num_attr == 0) 296 { 297 p_db->p_attrs = a2d_attr_list; 298 p_db->num_attr = A2D_NUM_ATTR; 299 } 300 301 if(a2d_cb.find.p_db == NULL) 302 a2d_cb.find.p_db = (tSDP_DISCOVERY_DB*)osi_malloc(p_db->db_len); 303 304 result = SDP_InitDiscoveryDb(a2d_cb.find.p_db, p_db->db_len, 1, &uuid_list, p_db->num_attr, 305 p_db->p_attrs); 306 307 if (result == TRUE) 308 { 309 /* store service_uuid */ 310 a2d_cb.find.service_uuid = service_uuid; 311 a2d_cb.find.p_cback = p_cback; 312 313 /* perform service search */ 314 result = SDP_ServiceSearchAttributeRequest(bd_addr, a2d_cb.find.p_db, a2d_sdp_cback); 315 if(FALSE == result) 316 { 317 a2d_cb.find.service_uuid = 0; 318 } 319 } 320 321 return (result ? A2D_SUCCESS : A2D_FAIL); 322} 323 324/****************************************************************************** 325** 326** Function A2D_SetTraceLevel 327** 328** Description Sets the trace level for A2D. If 0xff is passed, the 329** current trace level is returned. 330** 331** Input Parameters: 332** new_level: The level to set the A2D tracing to: 333** 0xff-returns the current setting. 334** 0-turns off tracing. 335** >= 1-Errors. 336** >= 2-Warnings. 337** >= 3-APIs. 338** >= 4-Events. 339** >= 5-Debug. 340** 341** Returns The new trace level or current trace level if 342** the input parameter is 0xff. 343** 344******************************************************************************/ 345UINT8 A2D_SetTraceLevel (UINT8 new_level) 346{ 347 if (new_level != 0xFF) 348 a2d_cb.trace_level = new_level; 349 350 return (a2d_cb.trace_level); 351} 352 353/****************************************************************************** 354** Function A2D_BitsSet 355** 356** Description Check the given num for the number of bits set 357** Returns A2D_SET_ONE_BIT, if one and only one bit is set 358** A2D_SET_ZERO_BIT, if all bits clear 359** A2D_SET_MULTL_BIT, if multiple bits are set 360******************************************************************************/ 361UINT8 A2D_BitsSet(UINT8 num) 362{ 363 UINT8 count; 364 BOOLEAN res; 365 if(num == 0) 366 res = A2D_SET_ZERO_BIT; 367 else 368 { 369 count = (num & (num - 1)); 370 res = ((count==0)?A2D_SET_ONE_BIT:A2D_SET_MULTL_BIT); 371 } 372 return res; 373} 374 375/******************************************************************************* 376** 377** Function A2D_Init 378** 379** Description This function is called to initialize the control block 380** for this layer. It must be called before accessing any 381** other API functions for this layer. It is typically called 382** once during the start up of the stack. 383** 384** Returns void 385** 386*******************************************************************************/ 387void A2D_Init(void) 388{ 389 memset(&a2d_cb, 0, sizeof(tA2D_CB)); 390 391 a2d_cb.avdt_sdp_ver = AVDT_VERSION; 392 393#if defined(A2D_INITIAL_TRACE_LEVEL) 394 a2d_cb.trace_level = A2D_INITIAL_TRACE_LEVEL; 395#else 396 a2d_cb.trace_level = BT_TRACE_LEVEL_NONE; 397#endif 398} 399 400