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