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