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