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