bta_hf_client_sdp.cc revision d35a648d39710bbc5ac59f8add85166455af5af7
1/******************************************************************************
2 *
3 *  Copyright (c) 2014 The Android Open Source Project
4 *  Copyright (C) 2003-2012 Broadcom Corporation
5 *
6 *  Licensed under the Apache License, Version 2.0 (the "License");
7 *  you may not use this file except in compliance with the License.
8 *  You may obtain a copy of the License at:
9 *
10 *  http://www.apache.org/licenses/LICENSE-2.0
11 *
12 *  Unless required by applicable law or agreed to in writing, software
13 *  distributed under the License is distributed on an "AS IS" BASIS,
14 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 *  See the License for the specific language governing permissions and
16 *  limitations under the License.
17 *
18 ******************************************************************************/
19
20/******************************************************************************
21 *
22 *  This file contains the audio gateway functions performing SDP
23 *  operations.
24 *
25 ******************************************************************************/
26
27#include <string.h>
28#include "bta_api.h"
29#include "bta_sys.h"
30#include "bt_utils.h"
31#include "bta_hf_client_api.h"
32#include "bta_hf_client_int.h"
33
34/* Number of protocol elements in protocol element list. */
35#define BTA_HF_CLIENT_NUM_PROTO_ELEMS      2
36
37/* Number of elements in service class id list. */
38#define BTA_HF_CLIENT_NUM_SVC_ELEMS        2
39
40/*******************************************************************************
41**
42** Function         bta_hf_client_sdp_cback
43**
44** Description      SDP callback function.
45**
46**
47** Returns          void
48**
49*******************************************************************************/
50static void bta_hf_client_sdp_cback(uint16_t status)
51{
52    uint16_t event;
53    tBTA_HF_CLIENT_DISC_RESULT *p_buf =
54        (tBTA_HF_CLIENT_DISC_RESULT *)osi_malloc(sizeof(tBTA_HF_CLIENT_DISC_RESULT));
55
56    APPL_TRACE_DEBUG("bta_hf_client_sdp_cback status:0x%x", status);
57
58    /* set event according to int/acp */
59    if (bta_hf_client_cb.scb.role == BTA_HF_CLIENT_ACP)
60        event = BTA_HF_CLIENT_DISC_ACP_RES_EVT;
61    else
62        event = BTA_HF_CLIENT_DISC_INT_RES_EVT;
63
64    p_buf->hdr.event = event;
65    p_buf->status = status;
66
67    bta_sys_sendmsg(p_buf);
68}
69
70/******************************************************************************
71**
72** Function         bta_hf_client_add_record
73**
74** Description      This function is called by a server application to add
75**                  HFP Client information to an SDP record.  Prior to
76**                  calling this function the application must call
77**                  SDP_CreateRecord() to create an SDP record.
78**
79** Returns          true if function execution succeeded,
80**                  false if function execution failed.
81**
82******************************************************************************/
83bool bta_hf_client_add_record(char *p_service_name, uint8_t scn,
84                          tBTA_HF_CLIENT_FEAT features, uint32_t sdp_handle)
85{
86    tSDP_PROTOCOL_ELEM  proto_elem_list[BTA_HF_CLIENT_NUM_PROTO_ELEMS];
87    uint16_t              svc_class_id_list[BTA_HF_CLIENT_NUM_SVC_ELEMS];
88    uint16_t              browse_list[] = {UUID_SERVCLASS_PUBLIC_BROWSE_GROUP};
89    uint16_t              version;
90    uint16_t              profile_uuid;
91    bool             result = true;
92    uint8_t               buf[2];
93    uint16_t              sdp_features = 0;
94
95    APPL_TRACE_DEBUG("bta_hf_client_add_record");
96
97    memset( proto_elem_list, 0 , BTA_HF_CLIENT_NUM_PROTO_ELEMS*sizeof(tSDP_PROTOCOL_ELEM));
98
99    /* add the protocol element sequence */
100    proto_elem_list[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
101    proto_elem_list[0].num_params = 0;
102    proto_elem_list[1].protocol_uuid = UUID_PROTOCOL_RFCOMM;
103    proto_elem_list[1].num_params = 1;
104    proto_elem_list[1].params[0] = scn;
105    result &= SDP_AddProtocolList(sdp_handle, BTA_HF_CLIENT_NUM_PROTO_ELEMS, proto_elem_list);
106
107    /* add service class id list */
108    svc_class_id_list[0] = UUID_SERVCLASS_HF_HANDSFREE;
109    svc_class_id_list[1] = UUID_SERVCLASS_GENERIC_AUDIO;
110    result &= SDP_AddServiceClassIdList(sdp_handle, BTA_HF_CLIENT_NUM_SVC_ELEMS, svc_class_id_list);
111
112    /* add profile descriptor list */
113    profile_uuid = UUID_SERVCLASS_HF_HANDSFREE;
114    version = HFP_VERSION_1_6;
115
116    result &= SDP_AddProfileDescriptorList(sdp_handle, profile_uuid, version);
117
118    /* add service name */
119    if (p_service_name != NULL && p_service_name[0] != 0)
120    {
121        result &= SDP_AddAttribute(sdp_handle, ATTR_ID_SERVICE_NAME, TEXT_STR_DESC_TYPE,
122                    (uint32_t)(strlen(p_service_name)+1), (uint8_t *) p_service_name);
123    }
124
125    /* add features */
126    if (features & BTA_HF_CLIENT_FEAT_ECNR)
127       sdp_features |= BTA_HF_CLIENT_FEAT_ECNR;
128
129    if (features & BTA_HF_CLIENT_FEAT_3WAY)
130       sdp_features |= BTA_HF_CLIENT_FEAT_3WAY;
131
132    if (features & BTA_HF_CLIENT_FEAT_CLI)
133       sdp_features |= BTA_HF_CLIENT_FEAT_CLI;
134
135    if (features & BTA_HF_CLIENT_FEAT_VREC)
136       sdp_features |= BTA_HF_CLIENT_FEAT_VREC;
137
138    if (features & BTA_HF_CLIENT_FEAT_VOL)
139       sdp_features |= BTA_HF_CLIENT_FEAT_VOL;
140
141    /* Codec bit position is different in SDP (bit 5) and in BRSF (bit 7) */
142    if (features & BTA_HF_CLIENT_FEAT_CODEC)
143       sdp_features |= 0x0020;
144
145    UINT16_TO_BE_FIELD(buf, sdp_features);
146    result &= SDP_AddAttribute(sdp_handle, ATTR_ID_SUPPORTED_FEATURES, UINT_DESC_TYPE, 2, buf);
147
148    /* add browse group list */
149    result &= SDP_AddUuidSequence(sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, browse_list);
150
151    return result;
152}
153
154/*******************************************************************************
155**
156** Function         bta_hf_client_create_record
157**
158** Description      Create SDP record for registered service.
159**
160**
161** Returns          void
162**
163*******************************************************************************/
164void bta_hf_client_create_record(tBTA_HF_CLIENT_DATA *p_data)
165{
166    /* add sdp record if not already registered */
167    if (bta_hf_client_cb.sdp_handle == 0)
168    {
169        bta_hf_client_cb.sdp_handle = SDP_CreateRecord();
170        bta_hf_client_cb.scn = BTM_AllocateSCN();
171        bta_hf_client_add_record(p_data->api_register.name,
172                                 bta_hf_client_cb.scn,
173                                 p_data->api_register.features,
174                                 bta_hf_client_cb.sdp_handle);
175
176        bta_sys_add_uuid(UUID_SERVCLASS_HF_HANDSFREE);
177    }
178
179}
180
181/*******************************************************************************
182**
183** Function         bta_hf_client_del_record
184**
185** Description      Delete SDP record for registered service.
186**
187**
188** Returns          void
189**
190*******************************************************************************/
191void bta_hf_client_del_record(UNUSED_ATTR tBTA_HF_CLIENT_DATA *p_data)
192{
193    APPL_TRACE_DEBUG("bta_hf_client_del_record");
194
195    if (bta_hf_client_cb.sdp_handle != 0)
196    {
197        SDP_DeleteRecord(bta_hf_client_cb.sdp_handle);
198        bta_hf_client_cb.sdp_handle = 0;
199        BTM_FreeSCN(bta_hf_client_cb.scn);
200        BTM_SecClrService(BTM_SEC_SERVICE_HF_HANDSFREE);
201        bta_sys_remove_uuid(UUID_SERVCLASS_HF_HANDSFREE);
202    }
203}
204
205/*******************************************************************************
206**
207** Function         bta_hf_client_sdp_find_attr
208**
209** Description      Process SDP discovery results to find requested attribute
210**
211**
212** Returns          true if results found, false otherwise.
213**
214*******************************************************************************/
215bool bta_hf_client_sdp_find_attr(void)
216{
217    tSDP_DISC_REC       *p_rec = NULL;
218    tSDP_DISC_ATTR      *p_attr;
219    tSDP_PROTOCOL_ELEM  pe;
220    bool             result = false;
221
222    bta_hf_client_cb.scb.peer_version = HFP_VERSION_1_1;   /* Default version */
223
224    /* loop through all records we found */
225    while (true)
226    {
227        /* get next record; if none found, we're done */
228        if ((p_rec = SDP_FindServiceInDb(bta_hf_client_cb.scb.p_disc_db, UUID_SERVCLASS_AG_HANDSFREE, p_rec)) == NULL)
229        {
230            break;
231        }
232
233        /* get scn from proto desc list if initiator */
234        if (bta_hf_client_cb.scb.role == BTA_HF_CLIENT_INT)
235        {
236            if (SDP_FindProtocolListElemInRec(p_rec, UUID_PROTOCOL_RFCOMM, &pe))
237            {
238                bta_hf_client_cb.scb.peer_scn = (uint8_t) pe.params[0];
239            }
240            else
241            {
242                continue;
243            }
244        }
245
246        /* get profile version (if failure, version parameter is not updated) */
247        SDP_FindProfileVersionInRec(p_rec, UUID_SERVCLASS_HF_HANDSFREE, &bta_hf_client_cb.scb.peer_version);
248
249        /* get features */
250        if ((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_SUPPORTED_FEATURES)) != NULL)
251        {
252            /* Found attribute. Get value. */
253            /* There might be race condition between SDP and BRSF.  */
254            /* Do not update if we already received BRSF.           */
255            if (bta_hf_client_cb.scb.peer_features == 0)
256            {
257                bta_hf_client_cb.scb.peer_features = p_attr->attr_value.v.u16;
258
259                /* SDP and BRSF WBS bit are different, correct it if set */
260                if (bta_hf_client_cb.scb.peer_features & 0x0020)
261                {
262                    bta_hf_client_cb.scb.peer_features &= ~0x0020;
263                    bta_hf_client_cb.scb.peer_features |= BTA_HF_CLIENT_PEER_CODEC;
264                }
265
266                /* get network for ability to reject calls */
267                if ((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_NETWORK)) != NULL)
268                {
269                    if (p_attr->attr_value.v.u16 == 0x01)
270                    {
271                        bta_hf_client_cb.scb.peer_features |= BTA_HF_CLIENT_PEER_REJECT;
272                    }
273                }
274            }
275        }
276
277        /* found what we needed */
278        result = true;
279        break;
280    }
281
282    APPL_TRACE_DEBUG("%s peer_version=0x%x peer_features=0x%x",
283                      __func__, bta_hf_client_cb.scb.peer_version,
284                      bta_hf_client_cb.scb.peer_features);
285
286    return result;
287}
288
289/*******************************************************************************
290**
291** Function         bta_hf_client_do_disc
292**
293** Description      Do service discovery.
294**
295**
296** Returns          void
297**
298*******************************************************************************/
299void bta_hf_client_do_disc(void)
300{
301    tSDP_UUID       uuid_list[2];
302    uint16_t          num_uuid = 1;
303    uint16_t          attr_list[4];
304    uint8_t           num_attr;
305    bool         db_inited = false;
306
307    /* initiator; get proto list and features */
308    if (bta_hf_client_cb.scb.role == BTA_HF_CLIENT_INT)
309    {
310        attr_list[0] = ATTR_ID_SERVICE_CLASS_ID_LIST;
311        attr_list[1] = ATTR_ID_PROTOCOL_DESC_LIST;
312        attr_list[2] = ATTR_ID_BT_PROFILE_DESC_LIST;
313        attr_list[3] = ATTR_ID_SUPPORTED_FEATURES;
314        num_attr = 4;
315        uuid_list[0].uu.uuid16 = UUID_SERVCLASS_AG_HANDSFREE;
316    }
317    /* acceptor; get features */
318    else
319    {
320        attr_list[0] = ATTR_ID_SERVICE_CLASS_ID_LIST;
321        attr_list[1] = ATTR_ID_BT_PROFILE_DESC_LIST;
322        attr_list[2] = ATTR_ID_SUPPORTED_FEATURES;
323        num_attr = 3;
324        uuid_list[0].uu.uuid16 = UUID_SERVCLASS_AG_HANDSFREE;
325    }
326
327    /* allocate buffer for sdp database */
328    bta_hf_client_cb.scb.p_disc_db = (tSDP_DISCOVERY_DB *)osi_malloc(BT_DEFAULT_BUFFER_SIZE);
329
330    /* set up service discovery database; attr happens to be attr_list len */
331    uuid_list[0].len = LEN_UUID_16;
332    uuid_list[1].len = LEN_UUID_16;
333    db_inited = SDP_InitDiscoveryDb(bta_hf_client_cb.scb.p_disc_db,
334                                    BT_DEFAULT_BUFFER_SIZE, num_uuid,
335                                    uuid_list, num_attr, attr_list);
336
337    if (db_inited)
338    {
339        /*Service discovery not initiated */
340        db_inited = SDP_ServiceSearchAttributeRequest(bta_hf_client_cb.scb.peer_addr,
341                            bta_hf_client_cb.scb.p_disc_db, bta_hf_client_sdp_cback);
342    }
343
344    if (!db_inited)
345    {
346        /*free discover db */
347        bta_hf_client_free_db(NULL);
348        /* sent failed event */
349        bta_hf_client_sm_execute(BTA_HF_CLIENT_DISC_FAIL_EVT, NULL);
350    }
351
352}
353
354/*******************************************************************************
355**
356** Function         bta_hf_client_free_db
357**
358** Description      Free discovery database.
359**
360**
361** Returns          void
362**
363*******************************************************************************/
364void bta_hf_client_free_db(UNUSED_ATTR tBTA_HF_CLIENT_DATA *p_data)
365{
366    osi_free_and_reset((void **)&bta_hf_client_cb.scb.p_disc_db);
367}
368