1 /******************************************************************************
2  *
3  *  Copyright (C) 2003-2016 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  *  AVRCP SDP related functions
22  *
23  ******************************************************************************/
24 #include <string.h>
25 
26 #include "avrc_api.h"
27 #include "avrc_int.h"
28 #include "bt_common.h"
29 
30 /*****************************************************************************
31  *  Global data
32  ****************************************************************************/
33 tAVRC_CB avrc_cb;
34 
35 /******************************************************************************
36  *
37  * Function         avrc_sdp_cback
38  *
39  * Description      This is the SDP callback function used by A2DP_FindService.
40  *                  This function will be executed by SDP when the service
41  *                  search is completed.  If the search is successful, it
42  *                  finds the first record in the database that matches the
43  *                  UUID of the search.  Then retrieves various parameters
44  *                  from the record.  When it is finished it calls the
45  *                  application callback function.
46  *
47  * Returns          Nothing.
48  *
49  *****************************************************************************/
avrc_sdp_cback(uint16_t status)50 static void avrc_sdp_cback(uint16_t status) {
51   AVRC_TRACE_API("%s status: %d", __func__, status);
52 
53   /* reset service_uuid, so can start another find service */
54   avrc_cb.service_uuid = 0;
55 
56   /* return info from sdp record in app callback function */
57   (*avrc_cb.p_cback)(status);
58 
59   return;
60 }
61 
62 /******************************************************************************
63  *
64  * Function         AVRC_FindService
65  *
66  * Description      This function is called by the application to perform
67  *                  service discovery and retrieve AVRCP SDP record information
68  *                  from a peer device.  Information is returned for the first
69  *                  service record found on the server that matches the service
70  *                  UUID. The callback function will be executed when service
71  *                  discovery is complete.  There can only be one outstanding
72  *                  call to AVRC_FindService() at a time; the application must
73  *                  wait for the callback before it makes another call to the
74  *                  function.  The application is responsible for allocating
75  *                  memory for the discovery database.  It is recommended that
76  *                  the size of the discovery database be at least 300 bytes.
77  *                  The application can deallocate the memory after the
78  *                  callback function has executed.
79  *
80  *                  Input Parameters:
81  *                      service_uuid: Indicates
82  *                                       TG(UUID_SERVCLASS_AV_REM_CTRL_TARGET)
83  *                                     r CT(UUID_SERVCLASS_AV_REMOTE_CONTROL)
84  *
85  *                      bd_addr:  BD address of the peer device.
86  *
87  *                      p_db:  SDP discovery database parameters.
88  *
89  *                      p_cback:  Pointer to the callback function.
90  *
91  *                  Output Parameters:
92  *                      None.
93  *
94  * Returns          AVRC_SUCCESS if successful.
95  *                  AVRC_BAD_PARAMS if discovery database parameters are
96  *                  invalid.
97  *                  AVRC_NO_RESOURCES if there are not enough resources to
98  *                                    perform the service search.
99  *
100  *****************************************************************************/
AVRC_FindService(uint16_t service_uuid,BD_ADDR bd_addr,tAVRC_SDP_DB_PARAMS * p_db,tAVRC_FIND_CBACK * p_cback)101 uint16_t AVRC_FindService(uint16_t service_uuid, BD_ADDR bd_addr,
102                           tAVRC_SDP_DB_PARAMS* p_db,
103                           tAVRC_FIND_CBACK* p_cback) {
104   tSDP_UUID uuid_list;
105   bool result = true;
106   uint16_t a2dp_attr_list[] = {
107       ATTR_ID_SERVICE_CLASS_ID_LIST, /* update AVRC_NUM_ATTR, if changed */
108       ATTR_ID_PROTOCOL_DESC_LIST,    ATTR_ID_BT_PROFILE_DESC_LIST,
109       ATTR_ID_SERVICE_NAME,          ATTR_ID_SUPPORTED_FEATURES,
110       ATTR_ID_PROVIDER_NAME};
111 
112   AVRC_TRACE_API("%s uuid: %x", __func__, service_uuid);
113   if ((service_uuid != UUID_SERVCLASS_AV_REM_CTRL_TARGET &&
114        service_uuid != UUID_SERVCLASS_AV_REMOTE_CONTROL) ||
115       p_db == NULL || p_db->p_db == NULL || p_cback == NULL)
116     return AVRC_BAD_PARAM;
117 
118   /* check if it is busy */
119   if (avrc_cb.service_uuid == UUID_SERVCLASS_AV_REM_CTRL_TARGET ||
120       avrc_cb.service_uuid == UUID_SERVCLASS_AV_REMOTE_CONTROL)
121     return AVRC_NO_RESOURCES;
122 
123   /* set up discovery database */
124   uuid_list.len = LEN_UUID_16;
125   uuid_list.uu.uuid16 = service_uuid;
126 
127   if (p_db->p_attrs == NULL || p_db->num_attr == 0) {
128     p_db->p_attrs = a2dp_attr_list;
129     p_db->num_attr = AVRC_NUM_ATTR;
130   }
131 
132   result = SDP_InitDiscoveryDb(p_db->p_db, p_db->db_len, 1, &uuid_list,
133                                p_db->num_attr, p_db->p_attrs);
134 
135   if (result == true) {
136     /* store service_uuid and discovery db pointer */
137     avrc_cb.p_db = p_db->p_db;
138     avrc_cb.service_uuid = service_uuid;
139     avrc_cb.p_cback = p_cback;
140 
141     /* perform service search */
142     result =
143         SDP_ServiceSearchAttributeRequest(bd_addr, p_db->p_db, avrc_sdp_cback);
144   }
145 
146   return (result ? AVRC_SUCCESS : AVRC_FAIL);
147 }
148 
149 /******************************************************************************
150  *
151  * Function         AVRC_AddRecord
152  *
153  * Description      This function is called to build an AVRCP SDP record.
154  *                  Prior to calling this function the application must
155  *                  call SDP_CreateRecord() to create an SDP record.
156  *
157  *                  Input Parameters:
158  *                      service_uuid:  Indicates
159  *                                        TG(UUID_SERVCLASS_AV_REM_CTRL_TARGET)
160  *                                     or CT(UUID_SERVCLASS_AV_REMOTE_CONTROL)
161  *
162  *                      p_service_name:  Pointer to a null-terminated character
163  *                      string containing the service name.
164  *                      If service name is not used set this to NULL.
165  *
166  *                      p_provider_name:  Pointer to a null-terminated character
167  *                      string containing the provider name.
168  *                      If provider name is not used set this to NULL.
169  *
170  *                      categories:  Supported categories.
171  *
172  *                      sdp_handle:  SDP handle returned by SDP_CreateRecord().
173  *
174  *                      browse_supported:  browse support info.
175  *
176  *                      profile_version:  profile version of avrcp record.
177  *
178  *                  Output Parameters:
179  *                      None.
180  *
181  * Returns          AVRC_SUCCESS if successful.
182  *                  AVRC_NO_RESOURCES if not enough resources to build the SDP
183  *                                    record.
184  *
185  *****************************************************************************/
AVRC_AddRecord(uint16_t service_uuid,const char * p_service_name,const char * p_provider_name,uint16_t categories,uint32_t sdp_handle,bool browse_supported,uint16_t profile_version)186 uint16_t AVRC_AddRecord(uint16_t service_uuid, const char* p_service_name,
187                         const char* p_provider_name, uint16_t categories,
188                         uint32_t sdp_handle, bool browse_supported,
189                         uint16_t profile_version) {
190   uint16_t browse_list[1];
191   bool result = true;
192   uint8_t temp[8];
193   uint8_t* p;
194   uint16_t count = 1;
195   uint8_t index = 0;
196   uint16_t class_list[2];
197 
198   AVRC_TRACE_API("%s uuid: %x", __func__, service_uuid);
199 
200   if (service_uuid != UUID_SERVCLASS_AV_REM_CTRL_TARGET &&
201       service_uuid != UUID_SERVCLASS_AV_REMOTE_CONTROL)
202     return AVRC_BAD_PARAM;
203 
204   /* add service class id list */
205   class_list[0] = service_uuid;
206   if ((service_uuid == UUID_SERVCLASS_AV_REMOTE_CONTROL) &&
207       (profile_version > AVRC_REV_1_3)) {
208     class_list[1] = UUID_SERVCLASS_AV_REM_CTRL_CONTROL;
209     count = 2;
210   }
211   result &= SDP_AddServiceClassIdList(sdp_handle, count, class_list);
212 
213   /* add protocol descriptor list   */
214   tSDP_PROTOCOL_ELEM avrc_proto_desc_list[AVRC_NUM_PROTO_ELEMS];
215   avrc_proto_desc_list[0].num_params = 1;
216   avrc_proto_desc_list[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
217   avrc_proto_desc_list[0].params[0] = AVCT_PSM;
218   avrc_proto_desc_list[0].params[1] = 0;
219   for (index = 1; index < AVRC_NUM_PROTO_ELEMS; index++) {
220     avrc_proto_desc_list[index].num_params = 1;
221     avrc_proto_desc_list[index].protocol_uuid = UUID_PROTOCOL_AVCTP;
222     avrc_proto_desc_list[index].params[0] = AVCT_REV_1_4;
223     avrc_proto_desc_list[index].params[1] = 0;
224   }
225   result &= SDP_AddProtocolList(sdp_handle, AVRC_NUM_PROTO_ELEMS,
226                                 (tSDP_PROTOCOL_ELEM*)avrc_proto_desc_list);
227 
228   /* additional protocal descriptor, required only for version > 1.3    */
229   if ((profile_version > AVRC_REV_1_3) && (browse_supported)) {
230     tSDP_PROTO_LIST_ELEM avrc_add_proto_desc_list;
231     avrc_add_proto_desc_list.num_elems = 2;
232     avrc_add_proto_desc_list.list_elem[0].num_params = 1;
233     avrc_add_proto_desc_list.list_elem[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
234     avrc_add_proto_desc_list.list_elem[0].params[0] = AVCT_BR_PSM;
235     avrc_add_proto_desc_list.list_elem[0].params[1] = 0;
236     avrc_add_proto_desc_list.list_elem[1].num_params = 1;
237     avrc_add_proto_desc_list.list_elem[1].protocol_uuid = UUID_PROTOCOL_AVCTP;
238     avrc_add_proto_desc_list.list_elem[1].params[0] = AVCT_REV_1_4;
239     avrc_add_proto_desc_list.list_elem[1].params[1] = 0;
240 
241     result &= SDP_AddAdditionProtoLists(
242         sdp_handle, 1, (tSDP_PROTO_LIST_ELEM*)&avrc_add_proto_desc_list);
243   }
244   /* add profile descriptor list   */
245   result &= SDP_AddProfileDescriptorList(
246       sdp_handle, UUID_SERVCLASS_AV_REMOTE_CONTROL, profile_version);
247 
248   /* add supported categories */
249   p = temp;
250   UINT16_TO_BE_STREAM(p, categories);
251   result &= SDP_AddAttribute(sdp_handle, ATTR_ID_SUPPORTED_FEATURES,
252                              UINT_DESC_TYPE, (uint32_t)2, (uint8_t*)temp);
253 
254   /* add provider name */
255   if (p_provider_name != NULL) {
256     result &= SDP_AddAttribute(
257         sdp_handle, ATTR_ID_PROVIDER_NAME, TEXT_STR_DESC_TYPE,
258         (uint32_t)(strlen(p_provider_name) + 1), (uint8_t*)p_provider_name);
259   }
260 
261   /* add service name */
262   if (p_service_name != NULL) {
263     result &= SDP_AddAttribute(
264         sdp_handle, ATTR_ID_SERVICE_NAME, TEXT_STR_DESC_TYPE,
265         (uint32_t)(strlen(p_service_name) + 1), (uint8_t*)p_service_name);
266   }
267 
268   /* add browse group list */
269   browse_list[0] = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP;
270   result &= SDP_AddUuidSequence(sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1,
271                                 browse_list);
272 
273   return (result ? AVRC_SUCCESS : AVRC_FAIL);
274 }
275 
276 /******************************************************************************
277  *
278  * Function         AVRC_SetTraceLevel
279  *
280  * Description      Sets the trace level for AVRC. If 0xff is passed, the
281  *                  current trace level is returned.
282  *
283  *                  Input Parameters:
284  *                      new_level:  The level to set the AVRC tracing to:
285  *                      0xff-returns the current setting.
286  *                      0-turns off tracing.
287  *                      >= 1-Errors.
288  *                      >= 2-Warnings.
289  *                      >= 3-APIs.
290  *                      >= 4-Events.
291  *                      >= 5-Debug.
292  *
293  * Returns          The new trace level or current trace level if
294  *                  the input parameter is 0xff.
295  *
296  *****************************************************************************/
AVRC_SetTraceLevel(uint8_t new_level)297 uint8_t AVRC_SetTraceLevel(uint8_t new_level) {
298   if (new_level != 0xFF) avrc_cb.trace_level = new_level;
299 
300   return (avrc_cb.trace_level);
301 }
302 
303 /*******************************************************************************
304  *
305  * Function         AVRC_Init
306  *
307  * Description      This function is called at stack startup to allocate the
308  *                  control block (if using dynamic memory), and initializes the
309  *                  control block and tracing level.
310  *
311  * Returns          void
312  *
313  ******************************************************************************/
AVRC_Init(void)314 void AVRC_Init(void) {
315   memset(&avrc_cb, 0, sizeof(tAVRC_CB));
316 
317 #if defined(AVRC_INITIAL_TRACE_LEVEL)
318   avrc_cb.trace_level = AVRC_INITIAL_TRACE_LEVEL;
319 #else
320   avrc_cb.trace_level = BT_TRACE_LEVEL_NONE;
321 #endif
322 }
323