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