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