1 /******************************************************************************
2  *
3  *  Copyright 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 "avrc_api.h"
21 #include "avrc_defs.h"
22 #include "avrc_int.h"
23 #include "bt_common.h"
24 
25 /*****************************************************************************
26  *  Global data
27  ****************************************************************************/
28 
29 /*******************************************************************************
30  *
31  * Function         avrc_bld_next_cmd
32  *
33  * Description      This function builds the Request Continue or Abort command.
34  *
35  * Returns          AVRC_STS_NO_ERROR, if the command is built successfully
36  *                  Otherwise, the error code.
37  *
38  ******************************************************************************/
avrc_bld_next_cmd(tAVRC_NEXT_CMD * p_cmd,BT_HDR * p_pkt)39 static tAVRC_STS avrc_bld_next_cmd(tAVRC_NEXT_CMD* p_cmd, BT_HDR* p_pkt) {
40   uint8_t *p_data, *p_start;
41 
42   AVRC_TRACE_API("avrc_bld_next_cmd");
43 
44   /* get the existing length, if any, and also the num attributes */
45   p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
46   p_data = p_start + 2; /* pdu + rsvd */
47 
48   /* add fixed lenth 1 - pdu_id (1) */
49   UINT16_TO_BE_STREAM(p_data, 1);
50   UINT8_TO_BE_STREAM(p_data, p_cmd->target_pdu);
51   p_pkt->len = (p_data - p_start);
52 
53   return AVRC_STS_NO_ERROR;
54 }
55 
56 /*****************************************************************************
57  *  the following commands are introduced in AVRCP 1.4
58  ****************************************************************************/
59 
60 #if (AVRC_ADV_CTRL_INCLUDED == TRUE)
61 /*******************************************************************************
62  *
63  * Function         avrc_bld_set_abs_volume_cmd
64  *
65  * Description      This function builds the Set Absolute Volume command.
66  *
67  * Returns          AVRC_STS_NO_ERROR, if the command is built successfully
68  *                  Otherwise, the error code.
69  *
70  ******************************************************************************/
avrc_bld_set_abs_volume_cmd(tAVRC_SET_VOLUME_CMD * p_cmd,BT_HDR * p_pkt)71 static tAVRC_STS avrc_bld_set_abs_volume_cmd(tAVRC_SET_VOLUME_CMD* p_cmd,
72                                              BT_HDR* p_pkt) {
73   uint8_t *p_data, *p_start;
74 
75   AVRC_TRACE_API("avrc_bld_set_abs_volume_cmd");
76   /* get the existing length, if any, and also the num attributes */
77   p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
78   p_data = p_start + 2; /* pdu + rsvd */
79   /* add fixed lenth 1 - volume (1) */
80   UINT16_TO_BE_STREAM(p_data, 1);
81   UINT8_TO_BE_STREAM(p_data, (AVRC_MAX_VOLUME & p_cmd->volume));
82   p_pkt->len = (p_data - p_start);
83   return AVRC_STS_NO_ERROR;
84 }
85 
86 /*******************************************************************************
87  *
88  * Function         avrc_bld_register_notifn
89  *
90  * Description      This function builds the register notification.
91  *
92  * Returns          AVRC_STS_NO_ERROR, if the command is built successfully
93  *                  Otherwise, the error code.
94  *
95  ******************************************************************************/
avrc_bld_register_notifn(BT_HDR * p_pkt,uint8_t event_id,uint32_t event_param)96 static tAVRC_STS avrc_bld_register_notifn(BT_HDR* p_pkt, uint8_t event_id,
97                                           uint32_t event_param) {
98   uint8_t *p_data, *p_start;
99 
100   AVRC_TRACE_API("avrc_bld_register_notifn");
101   /* get the existing length, if any, and also the num attributes */
102   // Set the notify value
103   p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
104   p_data = p_start + 2; /* pdu + rsvd */
105   /* add fixed length 5 -*/
106   UINT16_TO_BE_STREAM(p_data, 5);
107   UINT8_TO_BE_STREAM(p_data, event_id);
108   UINT32_TO_BE_STREAM(p_data, event_param);
109   p_pkt->len = (p_data - p_start);
110   return AVRC_STS_NO_ERROR;
111 }
112 #endif
113 
114 /*******************************************************************************
115  *
116  * Function         avrc_bld_get_capability_cmd
117  *
118  * Description      This function builds the get capability command.
119  *
120  * Returns          AVRC_STS_NO_ERROR, if the command is built successfully
121  *                  Otherwise, the error code.
122  *
123  ******************************************************************************/
avrc_bld_get_capability_cmd(BT_HDR * p_pkt,uint8_t cap_id)124 static tAVRC_STS avrc_bld_get_capability_cmd(BT_HDR* p_pkt, uint8_t cap_id) {
125   AVRC_TRACE_API("avrc_bld_get_capability_cmd");
126   uint8_t* p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
127   uint8_t* p_data = p_start + 2; /* pdu + rsvd */
128   /* add fixed length 1 -*/
129   UINT16_TO_BE_STREAM(p_data, 1);
130   UINT8_TO_BE_STREAM(p_data, cap_id);
131   p_pkt->len = (p_data - p_start);
132   return AVRC_STS_NO_ERROR;
133 }
134 
135 /*******************************************************************************
136  *
137  * Function         avrc_bld_list_player_app_attr_cmd
138  *
139  * Description      This function builds the list player app attrib command.
140  *
141  * Returns          AVRC_STS_NO_ERROR, if the command is built successfully
142  *                  Otherwise, the error code.
143  *
144  ******************************************************************************/
avrc_bld_list_player_app_attr_cmd(BT_HDR * p_pkt)145 static tAVRC_STS avrc_bld_list_player_app_attr_cmd(BT_HDR* p_pkt) {
146   AVRC_TRACE_API("avrc_bld_list_player_app_attr_cmd");
147   uint8_t* p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
148   uint8_t* p_data = p_start + 2; /* pdu + rsvd */
149   /* add fixed length 1 -*/
150   UINT16_TO_BE_STREAM(p_data, 0);
151   p_pkt->len = (p_data - p_start);
152   return AVRC_STS_NO_ERROR;
153 }
154 
155 /*******************************************************************************
156  *
157  * Function         avrc_bld_list_player_app_values_cmd
158  *
159  * Description      This function builds the list player app values command.
160  *
161  * Returns          AVRC_STS_NO_ERROR, if the command is built successfully
162  *                  Otherwise, the error code.
163  *
164  ******************************************************************************/
avrc_bld_list_player_app_values_cmd(BT_HDR * p_pkt,uint8_t attrib_id)165 static tAVRC_STS avrc_bld_list_player_app_values_cmd(BT_HDR* p_pkt,
166                                                      uint8_t attrib_id) {
167   AVRC_TRACE_API("avrc_bld_list_player_app_values_cmd");
168   uint8_t* p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
169   uint8_t* p_data = p_start + 2; /* pdu + rsvd */
170   /* add fixed length 1 -*/
171   UINT16_TO_BE_STREAM(p_data, 1);
172   UINT8_TO_BE_STREAM(p_data, attrib_id);
173   p_pkt->len = (p_data - p_start);
174   return AVRC_STS_NO_ERROR;
175 }
176 
177 /*******************************************************************************
178  *
179  * Function         avrc_bld_get_current_player_app_values_cmd
180  *
181  * Description      This function builds the get current player app setting
182  *                  values command.
183  *
184  * Returns          AVRC_STS_NO_ERROR, if the command is built successfully
185  *                  Otherwise, the error code.
186  *
187  ******************************************************************************/
avrc_bld_get_current_player_app_values_cmd(BT_HDR * p_pkt,uint8_t num_attrib_id,uint8_t * attrib_ids)188 static tAVRC_STS avrc_bld_get_current_player_app_values_cmd(
189     BT_HDR* p_pkt, uint8_t num_attrib_id, uint8_t* attrib_ids) {
190   AVRC_TRACE_API("avrc_bld_get_current_player_app_values_cmd");
191   uint8_t* p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
192   uint8_t* p_data = p_start + 2; /* pdu + rsvd */
193   uint8_t param_len =
194       num_attrib_id + 1;  // 1 additional to hold num attributes feild
195   /* add length -*/
196   UINT16_TO_BE_STREAM(p_data, param_len);
197   UINT8_TO_BE_STREAM(p_data, num_attrib_id);
198   for (int count = 0; count < num_attrib_id; count++) {
199     UINT8_TO_BE_STREAM(p_data, attrib_ids[count]);
200   }
201   p_pkt->len = (p_data - p_start);
202   return AVRC_STS_NO_ERROR;
203 }
204 
205 /*******************************************************************************
206  *
207  * Function         avrc_bld_set_current_player_app_values_cmd
208  *
209  * Description      This function builds the set current player app setting
210  *                  values command.
211  *
212  * Returns          AVRC_STS_NO_ERROR, if the command is built successfully
213  *                  Otherwise, the error code.
214  *
215  ******************************************************************************/
avrc_bld_set_current_player_app_values_cmd(BT_HDR * p_pkt,uint8_t num_attrib_id,tAVRC_APP_SETTING * p_val)216 static tAVRC_STS avrc_bld_set_current_player_app_values_cmd(
217     BT_HDR* p_pkt, uint8_t num_attrib_id, tAVRC_APP_SETTING* p_val) {
218   AVRC_TRACE_API("avrc_bld_set_current_player_app_values_cmd");
219   uint8_t* p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
220   uint8_t* p_data = p_start + 2; /* pdu + rsvd */
221   /* we have to store attrib- value pair
222    * 1 additional to store num elements
223    */
224   uint8_t param_len = (2 * num_attrib_id) + 1;
225   /* add length */
226   UINT16_TO_BE_STREAM(p_data, param_len);
227   UINT8_TO_BE_STREAM(p_data, num_attrib_id);
228   for (int count = 0; count < num_attrib_id; count++) {
229     UINT8_TO_BE_STREAM(p_data, p_val[count].attr_id);
230     UINT8_TO_BE_STREAM(p_data, p_val[count].attr_val);
231   }
232   p_pkt->len = (p_data - p_start);
233   return AVRC_STS_NO_ERROR;
234 }
235 
236 /*******************************************************************************
237  *
238  * Function         avrc_bld_get_player_app_setting_attr_text_cmd
239  *
240  * Description      This function builds the get player app setting attribute
241  *                  text command.
242  *
243  * Returns          AVRC_STS_NO_ERROR, if the command is built successfully
244  *                  Otherwise, the error code.
245  *
246  ******************************************************************************/
avrc_bld_get_player_app_setting_attr_text_cmd(BT_HDR * p_pkt,tAVRC_GET_APP_ATTR_TXT_CMD * p_cmd)247 static tAVRC_STS avrc_bld_get_player_app_setting_attr_text_cmd(
248     BT_HDR* p_pkt, tAVRC_GET_APP_ATTR_TXT_CMD* p_cmd) {
249   AVRC_TRACE_API("%s", __func__);
250 
251   uint8_t* p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
252   uint8_t* p_data = p_start + 2; /* pdu + rsvd */
253 
254   uint8_t param_len = p_cmd->num_attr + 1;
255   /* add length */
256   UINT16_TO_BE_STREAM(p_data, param_len);
257   UINT8_TO_BE_STREAM(p_data, p_cmd->num_attr);
258   for (int count = 0; count < p_cmd->num_attr; count++) {
259     UINT8_TO_BE_STREAM(p_data, p_cmd->attrs[count]);
260   }
261   p_pkt->len = (p_data - p_start);
262   return AVRC_STS_NO_ERROR;
263 }
264 
265 /*******************************************************************************
266  *
267  * Function         avrc_bld_get_player_app_setting_value_text_cmd
268  *
269  * Description      This function builds the get player app setting value
270  *                  text command.
271  *
272  * Returns          AVRC_STS_NO_ERROR, if the command is built successfully
273  *                  Otherwise, the error code.
274  *
275  ******************************************************************************/
avrc_bld_get_player_app_setting_value_text_cmd(BT_HDR * p_pkt,tAVRC_GET_APP_VAL_TXT_CMD * p_cmd)276 static tAVRC_STS avrc_bld_get_player_app_setting_value_text_cmd(
277     BT_HDR* p_pkt, tAVRC_GET_APP_VAL_TXT_CMD* p_cmd) {
278   AVRC_TRACE_API("%s", __func__);
279 
280   uint8_t* p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
281   uint8_t* p_data = p_start + 2; /* pdu + rsvd */
282 
283   uint8_t param_len = p_cmd->num_val + 1;
284   /* add length */
285   UINT16_TO_BE_STREAM(p_data, param_len);
286   UINT8_TO_BE_STREAM(p_data, p_cmd->num_val);
287   for (int count = 0; count < p_cmd->num_val; count++) {
288     UINT8_TO_BE_STREAM(p_data, p_cmd->vals[count]);
289   }
290   p_pkt->len = (p_data - p_start);
291   return AVRC_STS_NO_ERROR;
292 }
293 
294 /*******************************************************************************
295  *
296  * Function         avrc_bld_get_element_attr_cmd
297  *
298  * Description      This function builds the get element attribute command.
299  *
300  * Returns          AVRC_STS_NO_ERROR, if the command is built successfully
301  *                  Otherwise, the error code.
302  *
303  ******************************************************************************/
avrc_bld_get_element_attr_cmd(BT_HDR * p_pkt,uint8_t num_attrib,uint32_t * attrib_ids)304 static tAVRC_STS avrc_bld_get_element_attr_cmd(BT_HDR* p_pkt,
305                                                uint8_t num_attrib,
306                                                uint32_t* attrib_ids) {
307   AVRC_TRACE_API("avrc_bld_get_element_attr_cmd");
308   uint8_t* p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
309   uint8_t* p_data = p_start + 2; /* pdu + rsvd */
310   /* we have to store attrib- value pair
311    * 1 additional to store num elements
312    */
313   uint8_t param_len = (4 * num_attrib) + 9;
314   /* add length */
315   UINT16_TO_BE_STREAM(p_data, param_len);
316   /* 8 bytes of identifier as 0 (playing)*/
317   UINT32_TO_BE_STREAM(p_data, 0);
318   UINT32_TO_BE_STREAM(p_data, 0);
319   UINT8_TO_BE_STREAM(p_data, num_attrib);
320   for (int count = 0; count < num_attrib; count++) {
321     UINT32_TO_BE_STREAM(p_data, attrib_ids[count]);
322   }
323   p_pkt->len = (p_data - p_start);
324   return AVRC_STS_NO_ERROR;
325 }
326 
327 /*******************************************************************************
328  *
329  * Function         avrc_bld_play_item_cmd
330  *
331  * Description      This function builds the play item cmd
332  *
333  * Returns          AVRC_STS_NO_ERROR, if the command is built successfully
334  *                  Otherwise, the error code.
335  *
336  ******************************************************************************/
avrc_bld_play_item_cmd(BT_HDR * p_pkt,uint8_t scope,uint8_t * uid,uint16_t uid_counter)337 static tAVRC_STS avrc_bld_play_item_cmd(BT_HDR* p_pkt, uint8_t scope,
338                                         uint8_t* uid, uint16_t uid_counter) {
339   AVRC_TRACE_API("avrc_bld_get_element_attr_cmd");
340   uint8_t* p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
341   uint8_t* p_data = p_start + 2; /* pdu + rsvd */
342   /* add fixed length 11 */
343   UINT16_TO_BE_STREAM(p_data, 0xb);
344   /* Add scope */
345   UINT8_TO_BE_STREAM(p_data, scope);
346   /* Add UID */
347   ARRAY_TO_BE_STREAM(p_data, uid, AVRC_UID_SIZE);
348   /* Add UID Counter */
349   UINT16_TO_BE_STREAM(p_data, uid_counter);
350   p_pkt->len = (p_data - p_start);
351   return AVRC_STS_NO_ERROR;
352 }
353 
354 /*******************************************************************************
355  *
356  * Function         avrc_bld_get_play_status_cmd
357  *
358  * Description      This function builds the get play status command.
359  *
360  * Returns          AVRC_STS_NO_ERROR, if the command is built successfully
361  *                  Otherwise, the error code.
362  *
363  ******************************************************************************/
avrc_bld_get_play_status_cmd(BT_HDR * p_pkt)364 static tAVRC_STS avrc_bld_get_play_status_cmd(BT_HDR* p_pkt) {
365   AVRC_TRACE_API("avrc_bld_list_player_app_attr_cmd");
366   uint8_t* p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
367   uint8_t* p_data = p_start + 2; /* pdu + rsvd */
368   /* add fixed length 0 -*/
369   UINT16_TO_BE_STREAM(p_data, 0);
370   p_pkt->len = (p_data - p_start);
371   return AVRC_STS_NO_ERROR;
372 }
373 
374 /*******************************************************************************
375  *
376  * Function         avrc_bld_get_folder_items_cmd
377  *
378  * Description      This function builds the get folder items cmd.
379  *
380  * Returns          AVRC_STS_NO_ERROR, if the command is built successfully
381  *                  Otherwise, the error code.
382  *
383  ******************************************************************************/
avrc_bld_get_folder_items_cmd(BT_HDR * p_pkt,const tAVRC_GET_ITEMS_CMD * cmd)384 static tAVRC_STS avrc_bld_get_folder_items_cmd(BT_HDR* p_pkt,
385                                                const tAVRC_GET_ITEMS_CMD* cmd) {
386   AVRC_TRACE_API(
387       "avrc_bld_get_folder_items_cmd scope %d, start_item %d, end_item %d",
388       cmd->scope, cmd->start_item, cmd->end_item);
389   uint8_t* p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
390   /* This is where the PDU specific for AVRC starts
391    * AVRCP Spec 1.4 section 22.19 */
392   uint8_t* p_data = p_start + 1; /* pdu */
393 
394   /* To get the list of all media players we simply need to use the predefined
395    * PDU mentioned in above spec. */
396   /* scope (1) + st item (4) + end item (4) + attr (1) */
397   UINT16_TO_BE_STREAM(p_data, 10);
398   UINT8_TO_BE_STREAM(p_data, cmd->scope);       /* scope (1bytes) */
399   UINT32_TO_BE_STREAM(p_data, cmd->start_item); /* start item (4bytes) */
400   UINT32_TO_BE_STREAM(p_data, cmd->end_item);   /* end item (4bytes) */
401   UINT8_TO_BE_STREAM(p_data, 0); /* attribute count = 0 (1bytes) */
402   p_pkt->len = (p_data - p_start);
403   return AVRC_STS_NO_ERROR;
404 }
405 
406 /*******************************************************************************
407  *
408  * Function         avrc_bld_change_folder_cmd
409  *
410  * Description      This function builds the change folder command
411  *
412  * Returns          AVRC_STS_NO_ERROR, if the command is built successfully
413  *                  Otherwise, the error code.
414  *
415  ******************************************************************************/
avrc_bld_change_folder_cmd(BT_HDR * p_pkt,const tAVRC_CHG_PATH_CMD * cmd)416 static tAVRC_STS avrc_bld_change_folder_cmd(BT_HDR* p_pkt,
417                                             const tAVRC_CHG_PATH_CMD* cmd) {
418   AVRC_TRACE_API("avrc_bld_change_folder_cmd");
419   uint8_t* p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
420   /* This is where the PDU specific for AVRC starts
421    * AVRCP Spec 1.4 section 22.19 */
422   uint8_t* p_data = p_start + 1; /* pdu */
423 
424   /* To change folder we need to provide the following:
425    * UID Counter (2) + Direction (1) + UID (8) = 11bytes
426    */
427   UINT16_TO_BE_STREAM(p_data, 11);
428   UINT16_TO_BE_STREAM(p_data, cmd->uid_counter);
429   UINT8_TO_BE_STREAM(p_data, cmd->direction);
430   ARRAY_TO_BE_STREAM(p_data, cmd->folder_uid, AVRC_UID_SIZE);
431   p_pkt->len = (p_data - p_start);
432   return AVRC_STS_NO_ERROR;
433 }
avrc_bld_get_item_attributes_cmd(BT_HDR * p_pkt,const tAVRC_GET_ATTRS_CMD * cmd)434 static tAVRC_STS avrc_bld_get_item_attributes_cmd(
435     BT_HDR* p_pkt, const tAVRC_GET_ATTRS_CMD* cmd) {
436   AVRC_TRACE_API("%s", __func__);
437   uint8_t* p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
438   /* This is where the PDU specific for AVRC starts
439    * AVRCP Spec 1.4 section 22.19 */
440   uint8_t* p_data = p_start + 1; /* pdu */
441   UINT16_TO_BE_STREAM(p_data, 12 + 4 * cmd->attr_count);
442   UINT8_TO_BE_STREAM(p_data, cmd->scope);
443   uint64_t uid;
444   memcpy(&uid, cmd->uid, 8);
445   UINT64_TO_BE_STREAM(p_data, uid);
446   UINT16_TO_BE_STREAM(p_data, cmd->uid_counter);
447   UINT8_TO_BE_STREAM(p_data, cmd->attr_count);
448   ARRAY_TO_BE_STREAM(p_data, cmd->p_attr_list, 4 * cmd->attr_count);
449   p_pkt->len = (p_data - p_start);
450   return AVRC_STS_NO_ERROR;
451 }
452 /*******************************************************************************
453  *
454  * Function         avrc_bld_set_browsed_player_cmd
455  *
456  * Description      This function builds the set browsed player cmd.
457  *
458  * Returns          AVRC_STS_NO_ERROR, if the command is built successfully
459  *                  Otherwise, the error code.
460  *
461  ******************************************************************************/
avrc_bld_set_browsed_player_cmd(BT_HDR * p_pkt,const tAVRC_SET_BR_PLAYER_CMD * cmd)462 static tAVRC_STS avrc_bld_set_browsed_player_cmd(
463     BT_HDR* p_pkt, const tAVRC_SET_BR_PLAYER_CMD* cmd) {
464   AVRC_TRACE_API("%s", __func__);
465   uint8_t* p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
466   /* This is where the PDU specific for AVRC starts
467    * AVRCP Spec 1.4 section 22.19 */
468   uint8_t* p_data = p_start + 1; /* pdu */
469 
470   /* To change browsed player the following is the total length:
471    * Player ID (2)
472    */
473   UINT16_TO_BE_STREAM(p_data, 2); /* fixed length */
474   UINT16_TO_BE_STREAM(p_data, cmd->player_id);
475   p_pkt->len = (p_data - p_start);
476   return AVRC_STS_NO_ERROR;
477 }
478 
479 /*******************************************************************************
480  *
481  * Function         avrc_bld_set_addressed_player_cmd
482  *
483  * Description      This function builds the set addressed player cmd.
484  *
485  * Returns          AVRC_STS_NO_ERROR, if the command is built successfully
486  *                  Otherwise, the error code.
487  *
488  ******************************************************************************/
avrc_bld_set_addressed_player_cmd(BT_HDR * p_pkt,const tAVRC_SET_ADDR_PLAYER_CMD * cmd)489 static tAVRC_STS avrc_bld_set_addressed_player_cmd(
490     BT_HDR* p_pkt, const tAVRC_SET_ADDR_PLAYER_CMD* cmd) {
491   AVRC_TRACE_API("%s", __func__);
492   /* get the existing length, if any, and also the num attributes */
493   uint8_t* p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
494   uint8_t* p_data = p_start + 2; /* pdu + rsvd */
495 
496   /* To change addressed player the following is the total length:
497    * Player ID (2)
498    */
499   UINT16_TO_BE_STREAM(p_data, 2); /* fixed length */
500   UINT16_TO_BE_STREAM(p_data, cmd->player_id);
501   p_pkt->len = (p_data - p_start);
502   return AVRC_STS_NO_ERROR;
503 }
504 
505 /*******************************************************************************
506  *
507  * Function         avrc_bld_init_cmd_buffer
508  *
509  * Description      This function initializes the command buffer based on PDU
510  *
511  * Returns          NULL, if no GKI buffer or failure to build the message.
512  *                  Otherwise, the GKI buffer that contains the initialized
513  *                  message.
514  *
515  ******************************************************************************/
avrc_bld_init_cmd_buffer(tAVRC_COMMAND * p_cmd)516 static BT_HDR* avrc_bld_init_cmd_buffer(tAVRC_COMMAND* p_cmd) {
517   uint16_t chnl = AVCT_DATA_CTRL;
518   uint8_t opcode = avrc_opcode_from_pdu(p_cmd->pdu);
519   AVRC_TRACE_API("avrc_bld_init_cmd_buffer: pdu=%x, opcode=%x", p_cmd->pdu,
520                  opcode);
521 
522   uint16_t offset = 0;
523   switch (opcode) {
524     case AVRC_OP_BROWSE:
525       chnl = AVCT_DATA_BROWSE;
526       offset = AVCT_BROWSE_OFFSET;
527       break;
528 
529     case AVRC_OP_PASS_THRU:
530       offset = AVRC_MSG_PASS_THRU_OFFSET;
531       break;
532 
533     case AVRC_OP_VENDOR:
534       offset = AVRC_MSG_VENDOR_OFFSET;
535       break;
536   }
537 
538   /* allocate and initialize the buffer */
539   BT_HDR* p_pkt = (BT_HDR*)osi_calloc(AVRC_META_CMD_BUF_SIZE);
540   uint8_t *p_data, *p_start;
541 
542   p_pkt->layer_specific = chnl;
543   p_pkt->event = opcode;
544   p_pkt->offset = offset;
545   p_data = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
546   p_start = p_data;
547 
548   /* pass thru - group navigation - has a two byte op_id, so dont do it here */
549   if (opcode != AVRC_OP_PASS_THRU) *p_data++ = p_cmd->pdu;
550 
551   switch (opcode) {
552     case AVRC_OP_VENDOR:
553       /* reserved 0, packet_type 0 */
554       UINT8_TO_BE_STREAM(p_data, 0);
555       /* continue to the next "case to add length */
556       /* add fixed lenth - 0 */
557       UINT16_TO_BE_STREAM(p_data, 0);
558       break;
559   }
560 
561   p_pkt->len = (p_data - p_start);
562   p_cmd->cmd.opcode = opcode;
563 
564   return p_pkt;
565 }
566 
567 /*******************************************************************************
568  *
569  * Function         AVRC_BldCommand
570  *
571  * Description      This function builds the given AVRCP command to the given
572  *                  GKI buffer
573  *
574  * Returns          AVRC_STS_NO_ERROR, if the command is built successfully
575  *                  Otherwise, the error code.
576  *
577  ******************************************************************************/
AVRC_BldCommand(tAVRC_COMMAND * p_cmd,BT_HDR ** pp_pkt)578 tAVRC_STS AVRC_BldCommand(tAVRC_COMMAND* p_cmd, BT_HDR** pp_pkt) {
579   tAVRC_STS status = AVRC_STS_BAD_PARAM;
580   bool alloc = false;
581   AVRC_TRACE_API("AVRC_BldCommand: pdu=%x status=%x", p_cmd->cmd.pdu,
582                  p_cmd->cmd.status);
583   if (!p_cmd || !pp_pkt) {
584     AVRC_TRACE_API(
585         "AVRC_BldCommand. Invalid parameters passed. p_cmd=%p, pp_pkt=%p",
586         p_cmd, pp_pkt);
587     return AVRC_STS_BAD_PARAM;
588   }
589 
590   if (*pp_pkt == NULL) {
591     *pp_pkt = avrc_bld_init_cmd_buffer(p_cmd);
592     if (*pp_pkt == NULL) {
593       AVRC_TRACE_API("AVRC_BldCommand: Failed to initialize command buffer");
594       return AVRC_STS_INTERNAL_ERR;
595     }
596     alloc = true;
597   }
598   status = AVRC_STS_NO_ERROR;
599   BT_HDR* p_pkt = *pp_pkt;
600 
601   switch (p_cmd->pdu) {
602     case AVRC_PDU_REQUEST_CONTINUATION_RSP: /*        0x40 */
603       status = avrc_bld_next_cmd(&p_cmd->continu, p_pkt);
604       break;
605 
606     case AVRC_PDU_ABORT_CONTINUATION_RSP: /*          0x41 */
607       status = avrc_bld_next_cmd(&p_cmd->abort, p_pkt);
608       break;
609 #if (AVRC_ADV_CTRL_INCLUDED == TRUE)
610     case AVRC_PDU_SET_ABSOLUTE_VOLUME: /* 0x50 */
611       status = avrc_bld_set_abs_volume_cmd(&p_cmd->volume, p_pkt);
612       break;
613 #endif
614     case AVRC_PDU_REGISTER_NOTIFICATION: /* 0x31 */
615 #if (AVRC_ADV_CTRL_INCLUDED == TRUE)
616       status = avrc_bld_register_notifn(p_pkt, p_cmd->reg_notif.event_id,
617                                         p_cmd->reg_notif.param);
618 #endif
619       break;
620     case AVRC_PDU_GET_CAPABILITIES:
621       status =
622           avrc_bld_get_capability_cmd(p_pkt, p_cmd->get_caps.capability_id);
623       break;
624     case AVRC_PDU_LIST_PLAYER_APP_ATTR:
625       status = avrc_bld_list_player_app_attr_cmd(p_pkt);
626       break;
627     case AVRC_PDU_LIST_PLAYER_APP_VALUES:
628       status = avrc_bld_list_player_app_values_cmd(
629           p_pkt, p_cmd->list_app_values.attr_id);
630       break;
631     case AVRC_PDU_GET_CUR_PLAYER_APP_VALUE:
632       status = avrc_bld_get_current_player_app_values_cmd(
633           p_pkt, p_cmd->get_cur_app_val.num_attr, p_cmd->get_cur_app_val.attrs);
634       break;
635     case AVRC_PDU_SET_PLAYER_APP_VALUE:
636       status = avrc_bld_set_current_player_app_values_cmd(
637           p_pkt, p_cmd->set_app_val.num_val, p_cmd->set_app_val.p_vals);
638       break;
639     case AVRC_PDU_GET_PLAYER_APP_ATTR_TEXT:
640       avrc_bld_get_player_app_setting_attr_text_cmd(p_pkt,
641                                                     &p_cmd->get_app_attr_txt);
642       break;
643     case AVRC_PDU_GET_PLAYER_APP_VALUE_TEXT:
644       avrc_bld_get_player_app_setting_value_text_cmd(p_pkt,
645                                                      &p_cmd->get_app_val_txt);
646       break;
647     case AVRC_PDU_GET_ELEMENT_ATTR:
648       status = avrc_bld_get_element_attr_cmd(
649           p_pkt, p_cmd->get_elem_attrs.num_attr, p_cmd->get_elem_attrs.attrs);
650       break;
651     case AVRC_PDU_PLAY_ITEM:
652       status = avrc_bld_play_item_cmd(p_pkt, p_cmd->play_item.scope,
653                                       p_cmd->play_item.uid,
654                                       p_cmd->play_item.uid_counter);
655       break;
656     case AVRC_PDU_GET_PLAY_STATUS:
657       status = avrc_bld_get_play_status_cmd(p_pkt);
658       break;
659     case AVRC_PDU_GET_FOLDER_ITEMS:
660       status = avrc_bld_get_folder_items_cmd(p_pkt, &(p_cmd->get_items));
661       break;
662     case AVRC_PDU_CHANGE_PATH:
663       status = avrc_bld_change_folder_cmd(p_pkt, &(p_cmd->chg_path));
664       break;
665     case AVRC_PDU_GET_ITEM_ATTRIBUTES:
666       status = avrc_bld_get_item_attributes_cmd(p_pkt, &(p_cmd->get_attrs));
667       break;
668     case AVRC_PDU_SET_BROWSED_PLAYER:
669       status = avrc_bld_set_browsed_player_cmd(p_pkt, &(p_cmd->br_player));
670       break;
671     case AVRC_PDU_SET_ADDRESSED_PLAYER:
672       status = avrc_bld_set_addressed_player_cmd(p_pkt, &(p_cmd->addr_player));
673       break;
674   }
675 
676   if (alloc && (status != AVRC_STS_NO_ERROR)) {
677     osi_free(p_pkt);
678     *pp_pkt = NULL;
679   }
680   AVRC_TRACE_API("AVRC_BldCommand: returning %d", status);
681   return status;
682 }
683