1 /******************************************************************************
2 *
3 * Copyright (C) 2006-2013 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 #include <string.h>
19
20 #include "bt_common.h"
21 #include "avrc_api.h"
22 #include "avrc_defs.h"
23 #include "avrc_int.h"
24
25 /*****************************************************************************
26 ** Global data
27 *****************************************************************************/
28
29
30 #if (AVRC_METADATA_INCLUDED == TRUE)
31 /*******************************************************************************
32 **
33 ** Function avrc_bld_next_cmd
34 **
35 ** Description This function builds the Request Continue or Abort command.
36 **
37 ** Returns AVRC_STS_NO_ERROR, if the command is built successfully
38 ** Otherwise, the error code.
39 **
40 *******************************************************************************/
avrc_bld_next_cmd(tAVRC_NEXT_CMD * p_cmd,BT_HDR * p_pkt)41 static tAVRC_STS avrc_bld_next_cmd (tAVRC_NEXT_CMD *p_cmd, BT_HDR *p_pkt)
42 {
43 UINT8 *p_data, *p_start;
44
45 AVRC_TRACE_API("avrc_bld_next_cmd");
46
47 /* get the existing length, if any, and also the num attributes */
48 p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
49 p_data = p_start + 2; /* pdu + rsvd */
50
51 /* add fixed lenth 1 - pdu_id (1) */
52 UINT16_TO_BE_STREAM(p_data, 1);
53 UINT8_TO_BE_STREAM(p_data, p_cmd->target_pdu);
54 p_pkt->len = (p_data - p_start);
55
56 return AVRC_STS_NO_ERROR;
57 }
58
59 /*****************************************************************************
60 ** the following commands are introduced in AVRCP 1.4
61 *****************************************************************************/
62
63 #if (AVRC_ADV_CTRL_INCLUDED == TRUE)
64 /*******************************************************************************
65 **
66 ** Function avrc_bld_set_abs_volume_cmd
67 **
68 ** Description This function builds the Set Absolute Volume command.
69 **
70 ** Returns AVRC_STS_NO_ERROR, if the command is built successfully
71 ** Otherwise, the error code.
72 **
73 *******************************************************************************/
avrc_bld_set_abs_volume_cmd(tAVRC_SET_VOLUME_CMD * p_cmd,BT_HDR * p_pkt)74 static tAVRC_STS avrc_bld_set_abs_volume_cmd (tAVRC_SET_VOLUME_CMD *p_cmd, BT_HDR *p_pkt)
75 {
76 UINT8 *p_data, *p_start;
77
78 AVRC_TRACE_API("avrc_bld_set_abs_volume_cmd");
79 /* get the existing length, if any, and also the num attributes */
80 p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
81 p_data = p_start + 2; /* pdu + rsvd */
82 /* add fixed lenth 1 - volume (1) */
83 UINT16_TO_BE_STREAM(p_data, 1);
84 UINT8_TO_BE_STREAM(p_data, (AVRC_MAX_VOLUME & p_cmd->volume));
85 p_pkt->len = (p_data - p_start);
86 return AVRC_STS_NO_ERROR;
87 }
88
89 /*******************************************************************************
90 **
91 ** Function avrc_bld_register_notifn
92 **
93 ** Description This function builds the register notification.
94 **
95 ** Returns AVRC_STS_NO_ERROR, if the command is built successfully
96 ** Otherwise, the error code.
97 **
98 *******************************************************************************/
avrc_bld_register_notifn(BT_HDR * p_pkt,UINT8 event_id,UINT32 event_param)99 static tAVRC_STS avrc_bld_register_notifn(BT_HDR * p_pkt, UINT8 event_id, UINT32 event_param)
100 {
101 UINT8 *p_data, *p_start;
102
103 AVRC_TRACE_API("avrc_bld_register_notifn");
104 /* get the existing length, if any, and also the num attributes */
105 // Set the notify value
106 p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
107 p_data = p_start + 2; /* pdu + rsvd */
108 /* add fixed length 5 -*/
109 UINT16_TO_BE_STREAM(p_data, 5);
110 UINT8_TO_BE_STREAM(p_data,event_id);
111 UINT32_TO_BE_STREAM(p_data, event_param);
112 p_pkt->len = (p_data - p_start);
113 return AVRC_STS_NO_ERROR;
114 }
115 #endif
116 #if (AVRC_CTLR_INCLUDED == TRUE)
117 /*******************************************************************************
118 **
119 ** Function avrc_bld_get_capability_cmd
120 **
121 ** Description This function builds the get capability command.
122 **
123 ** Returns AVRC_STS_NO_ERROR, if the command is built successfully
124 ** Otherwise, the error code.
125 **
126 *******************************************************************************/
avrc_bld_get_capability_cmd(BT_HDR * p_pkt,UINT8 cap_id)127 static tAVRC_STS avrc_bld_get_capability_cmd(BT_HDR * p_pkt, UINT8 cap_id)
128 {
129 AVRC_TRACE_API("avrc_bld_get_capability_cmd");
130 UINT8 *p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
131 UINT8 *p_data = p_start + 2; /* pdu + rsvd */
132 /* add fixed length 1 -*/
133 UINT16_TO_BE_STREAM(p_data, 1);
134 UINT8_TO_BE_STREAM(p_data,cap_id);
135 p_pkt->len = (p_data - p_start);
136 return AVRC_STS_NO_ERROR;
137 }
138
139 /*******************************************************************************
140 **
141 ** Function avrc_bld_list_player_app_attr_cmd
142 **
143 ** Description This function builds the list player app attrib command.
144 **
145 ** Returns AVRC_STS_NO_ERROR, if the command is built successfully
146 ** Otherwise, the error code.
147 **
148 *******************************************************************************/
avrc_bld_list_player_app_attr_cmd(BT_HDR * p_pkt)149 static tAVRC_STS avrc_bld_list_player_app_attr_cmd(BT_HDR * p_pkt)
150 {
151 AVRC_TRACE_API("avrc_bld_list_player_app_attr_cmd");
152 UINT8 *p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
153 UINT8 *p_data = p_start + 2; /* pdu + rsvd */
154 /* add fixed length 1 -*/
155 UINT16_TO_BE_STREAM(p_data, 0);
156 p_pkt->len = (p_data - p_start);
157 return AVRC_STS_NO_ERROR;
158 }
159
160 /*******************************************************************************
161 **
162 ** Function avrc_bld_list_player_app_values_cmd
163 **
164 ** Description This function builds the list player app values command.
165 **
166 ** Returns AVRC_STS_NO_ERROR, if the command is built successfully
167 ** Otherwise, the error code.
168 **
169 *******************************************************************************/
avrc_bld_list_player_app_values_cmd(BT_HDR * p_pkt,UINT8 attrib_id)170 static tAVRC_STS avrc_bld_list_player_app_values_cmd(BT_HDR * p_pkt, UINT8 attrib_id)
171 {
172 AVRC_TRACE_API("avrc_bld_list_player_app_values_cmd");
173 UINT8 *p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
174 UINT8 *p_data = p_start + 2; /* pdu + rsvd */
175 /* add fixed length 1 -*/
176 UINT16_TO_BE_STREAM(p_data, 1);
177 UINT8_TO_BE_STREAM(p_data,attrib_id);
178 p_pkt->len = (p_data - p_start);
179 return AVRC_STS_NO_ERROR;
180 }
181
182 /*******************************************************************************
183 **
184 ** Function avrc_bld_get_current_player_app_values_cmd
185 **
186 ** Description This function builds the get current player app setting values command.
187 **
188 ** Returns AVRC_STS_NO_ERROR, if the command is built successfully
189 ** Otherwise, the error code.
190 **
191 *******************************************************************************/
avrc_bld_get_current_player_app_values_cmd(BT_HDR * p_pkt,UINT8 num_attrib_id,UINT8 * attrib_ids)192 static tAVRC_STS avrc_bld_get_current_player_app_values_cmd(
193 BT_HDR * p_pkt, UINT8 num_attrib_id, UINT8* attrib_ids)
194 {
195 AVRC_TRACE_API("avrc_bld_get_current_player_app_values_cmd");
196 UINT8 *p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
197 UINT8 *p_data = p_start + 2; /* pdu + rsvd */
198 UINT8 param_len = num_attrib_id + 1; // 1 additional to hold num attributes feild
199 /* add length -*/
200 UINT16_TO_BE_STREAM(p_data, param_len);
201 UINT8_TO_BE_STREAM(p_data,num_attrib_id);
202 for(int count = 0; count < num_attrib_id; count ++)
203 {
204 UINT8_TO_BE_STREAM(p_data,attrib_ids[count]);
205 }
206 p_pkt->len = (p_data - p_start);
207 return AVRC_STS_NO_ERROR;
208 }
209
210 /*******************************************************************************
211 **
212 ** Function avrc_bld_set_current_player_app_values_cmd
213 **
214 ** Description This function builds the set current player app setting values command.
215 **
216 ** Returns AVRC_STS_NO_ERROR, if the command is built successfully
217 ** Otherwise, the error code.
218 **
219 *******************************************************************************/
avrc_bld_set_current_player_app_values_cmd(BT_HDR * p_pkt,UINT8 num_attrib_id,tAVRC_APP_SETTING * p_val)220 static tAVRC_STS avrc_bld_set_current_player_app_values_cmd(BT_HDR * p_pkt, UINT8 num_attrib_id, tAVRC_APP_SETTING* p_val)
221 {
222 AVRC_TRACE_API("avrc_bld_set_current_player_app_values_cmd");
223 UINT8 *p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
224 UINT8 *p_data = p_start + 2; /* pdu + rsvd */
225 /* we have to store attrib- value pair
226 * 1 additional to store num elements
227 */
228 UINT8 param_len = (2*num_attrib_id) + 1;
229 /* add length */
230 UINT16_TO_BE_STREAM(p_data, param_len);
231 UINT8_TO_BE_STREAM(p_data,num_attrib_id);
232 for(int count = 0; count < num_attrib_id; count ++)
233 {
234 UINT8_TO_BE_STREAM(p_data,p_val[count].attr_id);
235 UINT8_TO_BE_STREAM(p_data,p_val[count].attr_val);
236 }
237 p_pkt->len = (p_data - p_start);
238 return AVRC_STS_NO_ERROR;
239 }
240
241 /*******************************************************************************
242 **
243 ** Function avrc_bld_get_player_app_setting_attr_text_cmd
244 **
245 ** Description This function builds the get player app setting attribute text command.
246 **
247 ** Returns AVRC_STS_NO_ERROR, if the command is built successfully
248 ** Otherwise, the error code.
249 **
250 *******************************************************************************/
avrc_bld_get_player_app_setting_attr_text_cmd(BT_HDR * p_pkt,tAVRC_GET_APP_ATTR_TXT_CMD * p_cmd)251 static tAVRC_STS avrc_bld_get_player_app_setting_attr_text_cmd (BT_HDR * p_pkt, tAVRC_GET_APP_ATTR_TXT_CMD *p_cmd)
252 {
253 AVRC_TRACE_API("%s", __FUNCTION__);
254
255 UINT8 *p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
256 UINT8 *p_data = p_start + 2; /* pdu + rsvd */
257
258 UINT8 param_len = p_cmd->num_attr + 1;
259 /* add length */
260 UINT16_TO_BE_STREAM(p_data, param_len);
261 UINT8_TO_BE_STREAM(p_data, p_cmd->num_attr);
262 for(int count = 0; count < p_cmd->num_attr; count++)
263 {
264 UINT8_TO_BE_STREAM(p_data, p_cmd->attrs[count]);
265 }
266 p_pkt->len = (p_data - p_start);
267 return AVRC_STS_NO_ERROR;
268 }
269
270 /*******************************************************************************
271 **
272 ** Function avrc_bld_get_player_app_setting_value_text_cmd
273 **
274 ** Description This function builds the get player app setting value text command.
275 **
276 ** Returns AVRC_STS_NO_ERROR, if the command is built successfully
277 ** Otherwise, the error code.
278 **
279 *******************************************************************************/
avrc_bld_get_player_app_setting_value_text_cmd(BT_HDR * p_pkt,tAVRC_GET_APP_VAL_TXT_CMD * p_cmd)280 static tAVRC_STS avrc_bld_get_player_app_setting_value_text_cmd (BT_HDR * p_pkt, tAVRC_GET_APP_VAL_TXT_CMD *p_cmd)
281 {
282 AVRC_TRACE_API("%s", __FUNCTION__);
283
284 UINT8 *p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
285 UINT8 *p_data = p_start + 2; /* pdu + rsvd */
286
287 UINT8 param_len = p_cmd->num_val + 1;
288 /* add length */
289 UINT16_TO_BE_STREAM(p_data, param_len);
290 UINT8_TO_BE_STREAM(p_data, p_cmd->num_val);
291 for(int count = 0; count < p_cmd->num_val; count++)
292 {
293 UINT8_TO_BE_STREAM(p_data, p_cmd->vals[count]);
294 }
295 p_pkt->len = (p_data - p_start);
296 return AVRC_STS_NO_ERROR;
297 }
298
299 /*******************************************************************************
300 **
301 ** Function avrc_bld_get_element_attr_cmd
302 **
303 ** Description This function builds the get element attribute command.
304 **
305 ** Returns AVRC_STS_NO_ERROR, if the command is built successfully
306 ** Otherwise, the error code.
307 **
308 *******************************************************************************/
avrc_bld_get_element_attr_cmd(BT_HDR * p_pkt,UINT8 num_attrib,UINT32 * attrib_ids)309 static tAVRC_STS avrc_bld_get_element_attr_cmd(BT_HDR * p_pkt, UINT8 num_attrib, UINT32* attrib_ids)
310 {
311 AVRC_TRACE_API("avrc_bld_get_element_attr_cmd");
312 UINT8 *p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
313 UINT8 *p_data = p_start + 2; /* pdu + rsvd */
314 /* we have to store attrib- value pair
315 * 1 additional to store num elements
316 */
317 UINT8 param_len = (4*num_attrib) + 9;
318 /* add length */
319 UINT16_TO_BE_STREAM(p_data, param_len);
320 /* 8 bytes of identifier as 0 (playing)*/
321 UINT32_TO_BE_STREAM(p_data,0);
322 UINT32_TO_BE_STREAM(p_data,0);
323 UINT8_TO_BE_STREAM(p_data,num_attrib);
324 for(int count = 0; count < num_attrib; count ++)
325 {
326 UINT32_TO_BE_STREAM(p_data,attrib_ids[count]);
327 }
328 p_pkt->len = (p_data - p_start);
329 return AVRC_STS_NO_ERROR;
330 }
331
332 /*******************************************************************************
333 **
334 ** Function avrc_bld_get_play_status_cmd
335 **
336 ** Description This function builds the get play status command.
337 **
338 ** Returns AVRC_STS_NO_ERROR, if the command is built successfully
339 ** Otherwise, the error code.
340 **
341 *******************************************************************************/
avrc_bld_get_play_status_cmd(BT_HDR * p_pkt)342 static tAVRC_STS avrc_bld_get_play_status_cmd(BT_HDR * p_pkt)
343 {
344 AVRC_TRACE_API("avrc_bld_list_player_app_attr_cmd");
345 UINT8 *p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
346 UINT8 *p_data = p_start + 2; /* pdu + rsvd */
347 /* add fixed length 1 -*/
348 UINT16_TO_BE_STREAM(p_data, 0);
349 p_pkt->len = (p_data - p_start);
350 return AVRC_STS_NO_ERROR;
351 }
352 #endif
353
354 /*******************************************************************************
355 **
356 ** Function avrc_bld_init_cmd_buffer
357 **
358 ** Description This function initializes the command buffer based on PDU
359 **
360 ** Returns NULL, if no GKI buffer or failure to build the message.
361 ** Otherwise, the GKI buffer that contains the initialized message.
362 **
363 *******************************************************************************/
avrc_bld_init_cmd_buffer(tAVRC_COMMAND * p_cmd)364 static BT_HDR *avrc_bld_init_cmd_buffer(tAVRC_COMMAND *p_cmd)
365 {
366 UINT8 opcode = avrc_opcode_from_pdu(p_cmd->pdu);
367 AVRC_TRACE_API("avrc_bld_init_cmd_buffer: pdu=%x, opcode=%x", p_cmd->pdu, opcode);
368
369 UINT16 offset = 0;
370 switch (opcode)
371 {
372 case AVRC_OP_PASS_THRU:
373 offset = AVRC_MSG_PASS_THRU_OFFSET;
374 break;
375
376 case AVRC_OP_VENDOR:
377 offset = AVRC_MSG_VENDOR_OFFSET;
378 break;
379 }
380
381 /* allocate and initialize the buffer */
382 BT_HDR *p_pkt = (BT_HDR *)osi_malloc(AVRC_META_CMD_BUF_SIZE);
383 UINT8 *p_data, *p_start;
384
385 p_pkt->layer_specific = AVCT_DATA_CTRL;
386 p_pkt->event = opcode;
387 p_pkt->offset = offset;
388 p_data = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
389 p_start = p_data;
390
391 /* pass thru - group navigation - has a two byte op_id, so dont do it here */
392 if (opcode != AVRC_OP_PASS_THRU)
393 *p_data++ = p_cmd->pdu;
394
395 switch (opcode) {
396 case AVRC_OP_VENDOR:
397 /* reserved 0, packet_type 0 */
398 UINT8_TO_BE_STREAM(p_data, 0);
399 /* continue to the next "case to add length */
400 /* add fixed lenth - 0 */
401 UINT16_TO_BE_STREAM(p_data, 0);
402 break;
403 }
404
405 p_pkt->len = (p_data - p_start);
406 p_cmd->cmd.opcode = opcode;
407
408 return p_pkt;
409 }
410
411 /*******************************************************************************
412 **
413 ** Function AVRC_BldCommand
414 **
415 ** Description This function builds the given AVRCP command to the given
416 ** GKI buffer
417 **
418 ** Returns AVRC_STS_NO_ERROR, if the command is built successfully
419 ** Otherwise, the error code.
420 **
421 *******************************************************************************/
AVRC_BldCommand(tAVRC_COMMAND * p_cmd,BT_HDR ** pp_pkt)422 tAVRC_STS AVRC_BldCommand( tAVRC_COMMAND *p_cmd, BT_HDR **pp_pkt)
423 {
424 tAVRC_STS status = AVRC_STS_BAD_PARAM;
425 BOOLEAN alloc = FALSE;
426 AVRC_TRACE_API("AVRC_BldCommand: pdu=%x status=%x", p_cmd->cmd.pdu, p_cmd->cmd.status);
427 if (!p_cmd || !pp_pkt)
428 {
429 AVRC_TRACE_API("AVRC_BldCommand. Invalid parameters passed. p_cmd=%p, pp_pkt=%p",
430 p_cmd, pp_pkt);
431 return AVRC_STS_BAD_PARAM;
432 }
433
434 if (*pp_pkt == NULL)
435 {
436 if ((*pp_pkt = avrc_bld_init_cmd_buffer(p_cmd)) == NULL)
437 {
438 AVRC_TRACE_API("AVRC_BldCommand: Failed to initialize command buffer");
439 return AVRC_STS_INTERNAL_ERR;
440 }
441 alloc = TRUE;
442 }
443 status = AVRC_STS_NO_ERROR;
444 BT_HDR* p_pkt = *pp_pkt;
445
446 switch (p_cmd->pdu)
447 {
448 case AVRC_PDU_REQUEST_CONTINUATION_RSP: /* 0x40 */
449 status = avrc_bld_next_cmd(&p_cmd->continu, p_pkt);
450 break;
451
452 case AVRC_PDU_ABORT_CONTINUATION_RSP: /* 0x41 */
453 status = avrc_bld_next_cmd(&p_cmd->abort, p_pkt);
454 break;
455 #if (AVRC_ADV_CTRL_INCLUDED == TRUE)
456 case AVRC_PDU_SET_ABSOLUTE_VOLUME: /* 0x50 */
457 status = avrc_bld_set_abs_volume_cmd(&p_cmd->volume, p_pkt);
458 break;
459 #endif
460 case AVRC_PDU_REGISTER_NOTIFICATION: /* 0x31 */
461 #if (AVRC_ADV_CTRL_INCLUDED == TRUE)
462 status=avrc_bld_register_notifn(p_pkt,p_cmd->reg_notif.event_id,p_cmd->reg_notif.param);
463 #endif
464 break;
465 #if (AVRC_CTLR_INCLUDED == TRUE)
466 case AVRC_PDU_GET_CAPABILITIES:
467 status = avrc_bld_get_capability_cmd(p_pkt, p_cmd->get_caps.capability_id);
468 break;
469 case AVRC_PDU_LIST_PLAYER_APP_ATTR:
470 status = avrc_bld_list_player_app_attr_cmd(p_pkt);
471 break;
472 case AVRC_PDU_LIST_PLAYER_APP_VALUES:
473 status = avrc_bld_list_player_app_values_cmd(p_pkt,p_cmd->list_app_values.attr_id);
474 break;
475 case AVRC_PDU_GET_CUR_PLAYER_APP_VALUE:
476 status = avrc_bld_get_current_player_app_values_cmd(p_pkt,
477 p_cmd->get_cur_app_val.num_attr,p_cmd->get_cur_app_val.attrs);
478 break;
479 case AVRC_PDU_SET_PLAYER_APP_VALUE:
480 status = avrc_bld_set_current_player_app_values_cmd(p_pkt,
481 p_cmd->set_app_val.num_val,p_cmd->set_app_val.p_vals);
482 break;
483 case AVRC_PDU_GET_PLAYER_APP_ATTR_TEXT:
484 avrc_bld_get_player_app_setting_attr_text_cmd(p_pkt, &p_cmd->get_app_attr_txt);
485 break;
486 case AVRC_PDU_GET_PLAYER_APP_VALUE_TEXT:
487 avrc_bld_get_player_app_setting_value_text_cmd(p_pkt, &p_cmd->get_app_val_txt);
488 break;
489 case AVRC_PDU_GET_ELEMENT_ATTR:
490 status = avrc_bld_get_element_attr_cmd(p_pkt,
491 p_cmd->get_elem_attrs.num_attr,p_cmd->get_elem_attrs.attrs);
492 break;
493 case AVRC_PDU_GET_PLAY_STATUS:
494 status = avrc_bld_get_play_status_cmd(p_pkt);
495 break;
496 #endif
497 }
498
499 if (alloc && (status != AVRC_STS_NO_ERROR) )
500 {
501 osi_free(p_pkt);
502 *pp_pkt = NULL;
503 }
504 AVRC_TRACE_API("AVRC_BldCommand: returning %d", status);
505 return status;
506 }
507 #endif /* (AVRC_METADATA_INCLUDED == TRUE) */
508