Home | History | Annotate | Download | only in a2dp
      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