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 <cstdint>
25
26 #include "avct_api.h"
27 #include "avrc_api.h"
28 #include "avrc_defs.h"
29 #include "avrc_int.h"
30 #include "internal_include/bt_target.h"
31 #include "osi/include/allocator.h"
32 #include "stack/include/bt_hdr.h"
33 #include "stack/include/bt_types.h"
34
35 using namespace bluetooth;
36
37 /*****************************************************************************
38 * Global data
39 ****************************************************************************/
40
41 /*******************************************************************************
42 *
43 * Function avrc_bld_next_cmd
44 *
45 * Description This function builds the Request Continue or Abort command.
46 *
47 * Returns AVRC_STS_NO_ERROR, if the command is built successfully
48 * Otherwise, the error code.
49 *
50 ******************************************************************************/
avrc_bld_next_cmd(tAVRC_NEXT_CMD * p_cmd,BT_HDR * p_pkt)51 static tAVRC_STS avrc_bld_next_cmd(tAVRC_NEXT_CMD* p_cmd, BT_HDR* p_pkt) {
52 uint8_t *p_data, *p_start;
53
54 log::verbose("avrc_bld_next_cmd");
55
56 /* get the existing length, if any, and also the num attributes */
57 p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
58 p_data = p_start + 2; /* pdu + rsvd */
59
60 /* add fixed length 1 - pdu_id (1) */
61 UINT16_TO_BE_STREAM(p_data, 1);
62 UINT8_TO_BE_STREAM(p_data, p_cmd->target_pdu);
63 p_pkt->len = (p_data - p_start);
64
65 return AVRC_STS_NO_ERROR;
66 }
67
68 /*****************************************************************************
69 * the following commands are introduced in AVRCP 1.4
70 ****************************************************************************/
71
72 /*******************************************************************************
73 *
74 * Function avrc_bld_set_abs_volume_cmd
75 *
76 * Description This function builds the Set Absolute Volume command.
77 *
78 * Returns AVRC_STS_NO_ERROR, if the command is built successfully
79 * Otherwise, the error code.
80 *
81 ******************************************************************************/
avrc_bld_set_abs_volume_cmd(tAVRC_SET_VOLUME_CMD * p_cmd,BT_HDR * p_pkt)82 static tAVRC_STS avrc_bld_set_abs_volume_cmd(tAVRC_SET_VOLUME_CMD* p_cmd, BT_HDR* p_pkt) {
83 uint8_t *p_data, *p_start;
84
85 log::verbose("avrc_bld_set_abs_volume_cmd");
86 /* get the existing length, if any, and also the num attributes */
87 p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
88 p_data = p_start + 2; /* pdu + rsvd */
89 /* add fixed length 1 - volume (1) */
90 UINT16_TO_BE_STREAM(p_data, 1);
91 UINT8_TO_BE_STREAM(p_data, (AVRC_MAX_VOLUME & p_cmd->volume));
92 p_pkt->len = (p_data - p_start);
93 return AVRC_STS_NO_ERROR;
94 }
95
96 /*******************************************************************************
97 *
98 * Function avrc_bld_register_notifn
99 *
100 * Description This function builds the register notification.
101 *
102 * Returns AVRC_STS_NO_ERROR, if the command is built successfully
103 * Otherwise, the error code.
104 *
105 ******************************************************************************/
avrc_bld_register_notifn(BT_HDR * p_pkt,uint8_t event_id,uint32_t event_param)106 static tAVRC_STS avrc_bld_register_notifn(BT_HDR* p_pkt, uint8_t event_id, 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, uint8_t attrib_id) {
174 log::verbose("avrc_bld_list_player_app_values_cmd");
175 uint8_t* p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
176 uint8_t* p_data = p_start + 2; /* pdu + rsvd */
177 /* add fixed length 1 -*/
178 UINT16_TO_BE_STREAM(p_data, 1);
179 UINT8_TO_BE_STREAM(p_data, attrib_id);
180 p_pkt->len = (p_data - p_start);
181 return AVRC_STS_NO_ERROR;
182 }
183
184 /*******************************************************************************
185 *
186 * Function avrc_bld_get_current_player_app_values_cmd
187 *
188 * Description This function builds the get current player app setting
189 * values command.
190 *
191 * Returns AVRC_STS_NO_ERROR, if the command is built successfully
192 * Otherwise, the error code.
193 *
194 ******************************************************************************/
avrc_bld_get_current_player_app_values_cmd(BT_HDR * p_pkt,uint8_t num_attrib_id,uint8_t * attrib_ids)195 static tAVRC_STS avrc_bld_get_current_player_app_values_cmd(BT_HDR* p_pkt, uint8_t num_attrib_id,
196 uint8_t* attrib_ids) {
197 log::verbose("avrc_bld_get_current_player_app_values_cmd");
198 uint8_t* p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
199 uint8_t* p_data = p_start + 2; /* pdu + rsvd */
200 uint8_t param_len = num_attrib_id + 1; // 1 additional to hold num attributes field
201 /* add length -*/
202 UINT16_TO_BE_STREAM(p_data, param_len);
203 UINT8_TO_BE_STREAM(p_data, num_attrib_id);
204 for (int count = 0; count < num_attrib_id; count++) {
205 UINT8_TO_BE_STREAM(p_data, attrib_ids[count]);
206 }
207 p_pkt->len = (p_data - p_start);
208 return AVRC_STS_NO_ERROR;
209 }
210
211 /*******************************************************************************
212 *
213 * Function avrc_bld_set_current_player_app_values_cmd
214 *
215 * Description This function builds the set current player app setting
216 * values command.
217 *
218 * Returns AVRC_STS_NO_ERROR, if the command is built successfully
219 * Otherwise, the error code.
220 *
221 ******************************************************************************/
avrc_bld_set_current_player_app_values_cmd(BT_HDR * p_pkt,uint8_t num_attrib_id,tAVRC_APP_SETTING * p_val)222 static tAVRC_STS avrc_bld_set_current_player_app_values_cmd(BT_HDR* p_pkt, uint8_t num_attrib_id,
223 tAVRC_APP_SETTING* p_val) {
224 log::verbose("avrc_bld_set_current_player_app_values_cmd");
225 uint8_t* p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
226 uint8_t* p_data = p_start + 2; /* pdu + rsvd */
227 /* we have to store attrib- value pair
228 * 1 additional to store num elements
229 */
230 uint8_t param_len = (2 * num_attrib_id) + 1;
231 /* add length */
232 UINT16_TO_BE_STREAM(p_data, param_len);
233 UINT8_TO_BE_STREAM(p_data, num_attrib_id);
234 for (int count = 0; count < num_attrib_id; count++) {
235 UINT8_TO_BE_STREAM(p_data, p_val[count].attr_id);
236 UINT8_TO_BE_STREAM(p_data, p_val[count].attr_val);
237 }
238 p_pkt->len = (p_data - p_start);
239 return AVRC_STS_NO_ERROR;
240 }
241
242 /*******************************************************************************
243 *
244 * Function avrc_bld_get_player_app_setting_attr_text_cmd
245 *
246 * Description This function builds the get player app setting attribute
247 * text command.
248 *
249 * Returns AVRC_STS_NO_ERROR, if the command is built successfully
250 * Otherwise, the error code.
251 *
252 ******************************************************************************/
avrc_bld_get_player_app_setting_attr_text_cmd(BT_HDR * p_pkt,tAVRC_GET_APP_ATTR_TXT_CMD * p_cmd)253 static tAVRC_STS avrc_bld_get_player_app_setting_attr_text_cmd(BT_HDR* p_pkt,
254 tAVRC_GET_APP_ATTR_TXT_CMD* p_cmd) {
255 log::verbose("");
256
257 uint8_t* p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
258 uint8_t* p_data = p_start + 2; /* pdu + rsvd */
259
260 uint8_t param_len = p_cmd->num_attr + 1;
261 /* add length */
262 UINT16_TO_BE_STREAM(p_data, param_len);
263 UINT8_TO_BE_STREAM(p_data, p_cmd->num_attr);
264 for (int count = 0; count < p_cmd->num_attr; count++) {
265 UINT8_TO_BE_STREAM(p_data, p_cmd->attrs[count]);
266 }
267 p_pkt->len = (p_data - p_start);
268 return AVRC_STS_NO_ERROR;
269 }
270
271 /*******************************************************************************
272 *
273 * Function avrc_bld_get_player_app_setting_value_text_cmd
274 *
275 * Description This function builds the get player app setting value
276 * text command.
277 *
278 * Returns AVRC_STS_NO_ERROR, if the command is built successfully
279 * Otherwise, the error code.
280 *
281 ******************************************************************************/
avrc_bld_get_player_app_setting_value_text_cmd(BT_HDR * p_pkt,tAVRC_GET_APP_VAL_TXT_CMD * p_cmd)282 static tAVRC_STS avrc_bld_get_player_app_setting_value_text_cmd(BT_HDR* p_pkt,
283 tAVRC_GET_APP_VAL_TXT_CMD* p_cmd) {
284 log::verbose("");
285
286 uint8_t* p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
287 uint8_t* p_data = p_start + 2; /* pdu + rsvd */
288
289 uint8_t param_len = p_cmd->num_val + 1;
290 /* add length */
291 UINT16_TO_BE_STREAM(p_data, param_len);
292 UINT8_TO_BE_STREAM(p_data, p_cmd->num_val);
293 for (int count = 0; count < p_cmd->num_val; count++) {
294 UINT8_TO_BE_STREAM(p_data, p_cmd->vals[count]);
295 }
296 p_pkt->len = (p_data - p_start);
297 return AVRC_STS_NO_ERROR;
298 }
299
300 /*******************************************************************************
301 *
302 * Function avrc_bld_get_element_attr_cmd
303 *
304 * Description This function builds the get element attribute command.
305 *
306 * Returns AVRC_STS_NO_ERROR, if the command is built successfully
307 * Otherwise, the error code.
308 *
309 ******************************************************************************/
avrc_bld_get_element_attr_cmd(BT_HDR * p_pkt,uint8_t num_attrib,uint32_t * attrib_ids)310 static tAVRC_STS avrc_bld_get_element_attr_cmd(BT_HDR* p_pkt, uint8_t num_attrib,
311 uint32_t* attrib_ids) {
312 log::verbose("avrc_bld_get_element_attr_cmd");
313 uint8_t* p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
314 uint8_t* p_data = p_start + 2; /* pdu + rsvd */
315 /* we have to store attrib- value pair
316 * 1 additional to store num elements
317 */
318 uint8_t param_len = (4 * num_attrib) + 9;
319 /* add length */
320 UINT16_TO_BE_STREAM(p_data, param_len);
321 /* 8 bytes of identifier as 0 (playing)*/
322 UINT32_TO_BE_STREAM(p_data, 0);
323 UINT32_TO_BE_STREAM(p_data, 0);
324 UINT8_TO_BE_STREAM(p_data, num_attrib);
325 for (int count = 0; count < num_attrib; count++) {
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_play_item_cmd
335 *
336 * Description This function builds the play item cmd
337 *
338 * Returns AVRC_STS_NO_ERROR, if the command is built successfully
339 * Otherwise, the error code.
340 *
341 ******************************************************************************/
avrc_bld_play_item_cmd(BT_HDR * p_pkt,uint8_t scope,uint8_t * uid,uint16_t uid_counter)342 static tAVRC_STS avrc_bld_play_item_cmd(BT_HDR* p_pkt, uint8_t scope, uint8_t* uid,
343 uint16_t uid_counter) {
344 log::verbose("avrc_bld_get_element_attr_cmd");
345 uint8_t* p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
346 uint8_t* p_data = p_start + 2; /* pdu + rsvd */
347 /* add fixed length 11 */
348 UINT16_TO_BE_STREAM(p_data, 0xb);
349 /* Add scope */
350 UINT8_TO_BE_STREAM(p_data, scope);
351 /* Add UID */
352 ARRAY_TO_BE_STREAM(p_data, uid, AVRC_UID_SIZE);
353 /* Add UID Counter */
354 UINT16_TO_BE_STREAM(p_data, uid_counter);
355 p_pkt->len = (p_data - p_start);
356 return AVRC_STS_NO_ERROR;
357 }
358
359 /*******************************************************************************
360 *
361 * Function avrc_bld_get_play_status_cmd
362 *
363 * Description This function builds the get play status command.
364 *
365 * Returns AVRC_STS_NO_ERROR, if the command is built successfully
366 * Otherwise, the error code.
367 *
368 ******************************************************************************/
avrc_bld_get_play_status_cmd(BT_HDR * p_pkt)369 static tAVRC_STS avrc_bld_get_play_status_cmd(BT_HDR* p_pkt) {
370 log::verbose("avrc_bld_list_player_app_attr_cmd");
371 uint8_t* p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
372 uint8_t* p_data = p_start + 2; /* pdu + rsvd */
373 /* add fixed length 0 -*/
374 UINT16_TO_BE_STREAM(p_data, 0);
375 p_pkt->len = (p_data - p_start);
376 return AVRC_STS_NO_ERROR;
377 }
378
379 /*******************************************************************************
380 *
381 * Function avrc_bld_get_folder_items_cmd
382 *
383 * Description This function builds the get folder items cmd.
384 *
385 * Returns AVRC_STS_NO_ERROR, if the command is built successfully
386 * Otherwise, the error code.
387 *
388 ******************************************************************************/
avrc_bld_get_folder_items_cmd(BT_HDR * p_pkt,const tAVRC_GET_ITEMS_CMD * cmd)389 static tAVRC_STS avrc_bld_get_folder_items_cmd(BT_HDR* p_pkt, const tAVRC_GET_ITEMS_CMD* cmd) {
390 log::verbose("avrc_bld_get_folder_items_cmd scope {}, start_item {}, end_item {}", cmd->scope,
391 cmd->start_item, cmd->end_item);
392 uint8_t* p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
393 /* This is where the PDU specific for AVRC starts
394 * AVRCP Spec 1.4 section 22.19 */
395 uint8_t* p_data = p_start + 1; /* pdu */
396
397 /* To get the list of all media players we simply need to use the predefined
398 * PDU mentioned in above spec. */
399 /* scope (1) + st item (4) + end item (4) + attr (1) */
400 UINT16_TO_BE_STREAM(p_data, 10);
401 UINT8_TO_BE_STREAM(p_data, cmd->scope); /* scope (1bytes) */
402 UINT32_TO_BE_STREAM(p_data, cmd->start_item); /* start item (4bytes) */
403 UINT32_TO_BE_STREAM(p_data, cmd->end_item); /* end item (4bytes) */
404 UINT8_TO_BE_STREAM(p_data, 0); /* attribute count = 0 (1bytes) */
405 p_pkt->len = (p_data - p_start);
406 return AVRC_STS_NO_ERROR;
407 }
408
409 /*******************************************************************************
410 *
411 * Function avrc_bld_change_folder_cmd
412 *
413 * Description This function builds the change folder command
414 *
415 * Returns AVRC_STS_NO_ERROR, if the command is built successfully
416 * Otherwise, the error code.
417 *
418 ******************************************************************************/
avrc_bld_change_folder_cmd(BT_HDR * p_pkt,const tAVRC_CHG_PATH_CMD * cmd)419 static tAVRC_STS avrc_bld_change_folder_cmd(BT_HDR* p_pkt, const tAVRC_CHG_PATH_CMD* cmd) {
420 log::verbose("avrc_bld_change_folder_cmd");
421 uint8_t* p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
422 /* This is where the PDU specific for AVRC starts
423 * AVRCP Spec 1.4 section 22.19 */
424 uint8_t* p_data = p_start + 1; /* pdu */
425
426 /* To change folder we need to provide the following:
427 * UID Counter (2) + Direction (1) + UID (8) = 11bytes
428 */
429 UINT16_TO_BE_STREAM(p_data, 11);
430 UINT16_TO_BE_STREAM(p_data, cmd->uid_counter);
431 UINT8_TO_BE_STREAM(p_data, cmd->direction);
432 ARRAY_TO_BE_STREAM(p_data, cmd->folder_uid, AVRC_UID_SIZE);
433 p_pkt->len = (p_data - p_start);
434 return AVRC_STS_NO_ERROR;
435 }
avrc_bld_get_item_attributes_cmd(BT_HDR * p_pkt,const tAVRC_GET_ATTRS_CMD * cmd)436 static tAVRC_STS avrc_bld_get_item_attributes_cmd(BT_HDR* p_pkt, const tAVRC_GET_ATTRS_CMD* cmd) {
437 log::verbose("");
438 uint8_t* p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
439 /* This is where the PDU specific for AVRC starts
440 * AVRCP Spec 1.4 section 22.19 */
441 uint8_t* p_data = p_start + 1; /* pdu */
442 UINT16_TO_BE_STREAM(p_data, 12 + 4 * cmd->attr_count);
443 UINT8_TO_BE_STREAM(p_data, cmd->scope);
444 uint64_t uid;
445 memcpy(&uid, cmd->uid, 8);
446 UINT64_TO_BE_STREAM(p_data, uid);
447 UINT16_TO_BE_STREAM(p_data, cmd->uid_counter);
448 UINT8_TO_BE_STREAM(p_data, cmd->attr_count);
449 ARRAY_TO_BE_STREAM(p_data, cmd->p_attr_list, 4 * cmd->attr_count);
450 p_pkt->len = (p_data - p_start);
451 return AVRC_STS_NO_ERROR;
452 }
453 /*******************************************************************************
454 *
455 * Function avrc_bld_set_browsed_player_cmd
456 *
457 * Description This function builds the set browsed player cmd.
458 *
459 * Returns AVRC_STS_NO_ERROR, if the command is built successfully
460 * Otherwise, the error code.
461 *
462 ******************************************************************************/
avrc_bld_set_browsed_player_cmd(BT_HDR * p_pkt,const tAVRC_SET_BR_PLAYER_CMD * cmd)463 static tAVRC_STS avrc_bld_set_browsed_player_cmd(BT_HDR* p_pkt,
464 const tAVRC_SET_BR_PLAYER_CMD* cmd) {
465 log::verbose("");
466 uint8_t* p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
467 /* This is where the PDU specific for AVRC starts
468 * AVRCP Spec 1.4 section 22.19 */
469 uint8_t* p_data = p_start + 1; /* pdu */
470
471 /* To change browsed player the following is the total length:
472 * Player ID (2)
473 */
474 UINT16_TO_BE_STREAM(p_data, 2); /* fixed length */
475 UINT16_TO_BE_STREAM(p_data, cmd->player_id);
476 p_pkt->len = (p_data - p_start);
477 return AVRC_STS_NO_ERROR;
478 }
479
480 /*******************************************************************************
481 *
482 * Function avrc_bld_set_addressed_player_cmd
483 *
484 * Description This function builds the set addressed player cmd.
485 *
486 * Returns AVRC_STS_NO_ERROR, if the command is built successfully
487 * Otherwise, the error code.
488 *
489 ******************************************************************************/
avrc_bld_set_addressed_player_cmd(BT_HDR * p_pkt,const tAVRC_SET_ADDR_PLAYER_CMD * cmd)490 static tAVRC_STS avrc_bld_set_addressed_player_cmd(BT_HDR* p_pkt,
491 const tAVRC_SET_ADDR_PLAYER_CMD* cmd) {
492 log::verbose("");
493 /* get the existing length, if any, and also the num attributes */
494 uint8_t* p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
495 uint8_t* p_data = p_start + 2; /* pdu + rsvd */
496
497 /* To change addressed player the following is the total length:
498 * Player ID (2)
499 */
500 UINT16_TO_BE_STREAM(p_data, 2); /* fixed length */
501 UINT16_TO_BE_STREAM(p_data, cmd->player_id);
502 p_pkt->len = (p_data - p_start);
503 return AVRC_STS_NO_ERROR;
504 }
505
506 /*******************************************************************************
507 *
508 * Function avrc_bld_init_cmd_buffer
509 *
510 * Description This function initializes the command buffer based on PDU
511 *
512 * Returns NULL, if no GKI buffer or failure to build the message.
513 * Otherwise, the GKI buffer that contains the initialized
514 * message.
515 *
516 ******************************************************************************/
avrc_bld_init_cmd_buffer(tAVRC_COMMAND * p_cmd)517 static BT_HDR* avrc_bld_init_cmd_buffer(tAVRC_COMMAND* p_cmd) {
518 uint16_t chnl = AVCT_DATA_CTRL;
519 uint8_t opcode = avrc_opcode_from_pdu(p_cmd->pdu);
520 log::verbose("avrc_bld_init_cmd_buffer: pdu={:x}, opcode={:x}", p_cmd->pdu, 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) {
550 *p_data++ = p_cmd->pdu;
551 }
552
553 switch (opcode) {
554 case AVRC_OP_VENDOR:
555 /* reserved 0, packet_type 0 */
556 UINT8_TO_BE_STREAM(p_data, 0);
557 /* continue to the next "case to add length */
558 /* add fixed length - 0 */
559 UINT16_TO_BE_STREAM(p_data, 0);
560 break;
561 }
562
563 p_pkt->len = (p_data - p_start);
564 p_cmd->cmd.opcode = opcode;
565
566 return p_pkt;
567 }
568
569 /*******************************************************************************
570 *
571 * Function AVRC_BldCommand
572 *
573 * Description This function builds the given AVRCP command to the given
574 * GKI buffer
575 *
576 * Returns AVRC_STS_NO_ERROR, if the command is built successfully
577 * Otherwise, the error code.
578 *
579 ******************************************************************************/
AVRC_BldCommand(tAVRC_COMMAND * p_cmd,BT_HDR ** pp_pkt)580 tAVRC_STS AVRC_BldCommand(tAVRC_COMMAND* p_cmd, BT_HDR** pp_pkt) {
581 tAVRC_STS status = AVRC_STS_BAD_PARAM;
582 bool alloc = false;
583 log::verbose("AVRC_BldCommand: pdu={:x} status={:x}", p_cmd->cmd.pdu, p_cmd->cmd.status);
584 if (!p_cmd || !pp_pkt) {
585 log::verbose("AVRC_BldCommand. Invalid parameters passed. p_cmd={}, pp_pkt={}",
586 std::format_ptr(p_cmd), std::format_ptr(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 log::verbose("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 case AVRC_PDU_SET_ABSOLUTE_VOLUME: /* 0x50 */
610 if (!avrcp_absolute_volume_is_enabled()) {
611 break;
612 }
613 status = avrc_bld_set_abs_volume_cmd(&p_cmd->volume, p_pkt);
614 break;
615 case AVRC_PDU_REGISTER_NOTIFICATION: /* 0x31 */
616 if (!avrcp_absolute_volume_is_enabled()) {
617 break;
618 }
619 status = avrc_bld_register_notifn(p_pkt, p_cmd->reg_notif.event_id, p_cmd->reg_notif.param);
620 break;
621 case AVRC_PDU_GET_CAPABILITIES:
622 status = 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(p_pkt, p_cmd->list_app_values.attr_id);
629 break;
630 case AVRC_PDU_GET_CUR_PLAYER_APP_VALUE:
631 status = avrc_bld_get_current_player_app_values_cmd(p_pkt, p_cmd->get_cur_app_val.num_attr,
632 p_cmd->get_cur_app_val.attrs);
633 break;
634 case AVRC_PDU_SET_PLAYER_APP_VALUE:
635 status = avrc_bld_set_current_player_app_values_cmd(p_pkt, p_cmd->set_app_val.num_val,
636 p_cmd->set_app_val.p_vals);
637 break;
638 case AVRC_PDU_GET_PLAYER_APP_ATTR_TEXT:
639 avrc_bld_get_player_app_setting_attr_text_cmd(p_pkt, &p_cmd->get_app_attr_txt);
640 break;
641 case AVRC_PDU_GET_PLAYER_APP_VALUE_TEXT:
642 avrc_bld_get_player_app_setting_value_text_cmd(p_pkt, &p_cmd->get_app_val_txt);
643 break;
644 case AVRC_PDU_GET_ELEMENT_ATTR:
645 status = avrc_bld_get_element_attr_cmd(p_pkt, p_cmd->get_elem_attrs.num_attr,
646 p_cmd->get_elem_attrs.attrs);
647 break;
648 case AVRC_PDU_PLAY_ITEM:
649 status = avrc_bld_play_item_cmd(p_pkt, p_cmd->play_item.scope, p_cmd->play_item.uid,
650 p_cmd->play_item.uid_counter);
651 break;
652 case AVRC_PDU_GET_PLAY_STATUS:
653 status = avrc_bld_get_play_status_cmd(p_pkt);
654 break;
655 case AVRC_PDU_GET_FOLDER_ITEMS:
656 status = avrc_bld_get_folder_items_cmd(p_pkt, &(p_cmd->get_items));
657 break;
658 case AVRC_PDU_CHANGE_PATH:
659 status = avrc_bld_change_folder_cmd(p_pkt, &(p_cmd->chg_path));
660 break;
661 case AVRC_PDU_GET_ITEM_ATTRIBUTES:
662 status = avrc_bld_get_item_attributes_cmd(p_pkt, &(p_cmd->get_attrs));
663 break;
664 case AVRC_PDU_SET_BROWSED_PLAYER:
665 status = avrc_bld_set_browsed_player_cmd(p_pkt, &(p_cmd->br_player));
666 break;
667 case AVRC_PDU_SET_ADDRESSED_PLAYER:
668 status = avrc_bld_set_addressed_player_cmd(p_pkt, &(p_cmd->addr_player));
669 break;
670 }
671
672 if (alloc && (status != AVRC_STS_NO_ERROR)) {
673 osi_free(p_pkt);
674 *pp_pkt = NULL;
675 }
676 log::verbose("AVRC_BldCommand: returning {}", status);
677 return status;
678 }
679