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 36 tA2D_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 ******************************************************************************/ 55 static 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 *******************************************************************************/ 136 void 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 ******************************************************************************/ 171 tA2D_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 ******************************************************************************/ 270 tA2D_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 ******************************************************************************/ 345 UINT8 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 ******************************************************************************/ 361 UINT8 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 *******************************************************************************/ 387 void 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