1 /******************************************************************************
2 *
3 * Copyright 2003-2016 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
24 #include "osi/include/log.h"
25
26 /*****************************************************************************
27 * Global data
28 ****************************************************************************/
29
30 /*******************************************************************************
31 *
32 * Function avrc_ctrl_pars_vendor_cmd
33 *
34 * Description This function parses the vendor specific commands defined by
35 * Bluetooth SIG for AVRCP Conroller.
36 *
37 * Returns AVRC_STS_NO_ERROR, if the message in p_data is parsed
38 * successfully.
39 * Otherwise, the error code defined by AVRCP 1.4
40 *
41 ******************************************************************************/
avrc_ctrl_pars_vendor_cmd(tAVRC_MSG_VENDOR * p_msg,tAVRC_COMMAND * p_result)42 static tAVRC_STS avrc_ctrl_pars_vendor_cmd(tAVRC_MSG_VENDOR* p_msg,
43 tAVRC_COMMAND* p_result) {
44 tAVRC_STS status = AVRC_STS_NO_ERROR;
45
46 if (p_msg->vendor_len < 4) { // 4 == pdu + reserved byte + len as uint16
47 AVRC_TRACE_WARNING("%s: message length %d too short: must be at least 4",
48 __func__, p_msg->vendor_len);
49 return AVRC_STS_INTERNAL_ERR;
50 }
51 uint8_t* p = p_msg->p_vendor_data;
52 p_result->pdu = *p++;
53 AVRC_TRACE_DEBUG("%s pdu:0x%x", __func__, p_result->pdu);
54 if (!AVRC_IsValidAvcType(p_result->pdu, p_msg->hdr.ctype)) {
55 AVRC_TRACE_DEBUG("%s detects wrong AV/C type!", __func__);
56 status = AVRC_STS_BAD_CMD;
57 }
58
59 p++; /* skip the reserved byte */
60 uint16_t len;
61 BE_STREAM_TO_UINT16(len, p);
62 if ((len + 4) != (p_msg->vendor_len)) {
63 status = AVRC_STS_INTERNAL_ERR;
64 }
65
66 if (status != AVRC_STS_NO_ERROR) return status;
67
68 switch (p_result->pdu) {
69 case AVRC_PDU_SET_ABSOLUTE_VOLUME: {
70 if (len != 1)
71 status = AVRC_STS_INTERNAL_ERR;
72 else {
73 BE_STREAM_TO_UINT8(p_result->volume.volume, p);
74 p_result->volume.volume = AVRC_MAX_VOLUME & p_result->volume.volume;
75 }
76 break;
77 }
78 case AVRC_PDU_REGISTER_NOTIFICATION: /* 0x31 */
79 if (len < 5) return AVRC_STS_INTERNAL_ERR;
80
81 BE_STREAM_TO_UINT8(p_result->reg_notif.event_id, p);
82 BE_STREAM_TO_UINT32(p_result->reg_notif.param, p);
83
84 if (p_result->reg_notif.event_id == 0 ||
85 p_result->reg_notif.event_id > AVRC_NUM_NOTIF_EVENTS) {
86 status = AVRC_STS_BAD_PARAM;
87 }
88 break;
89 default:
90 status = AVRC_STS_BAD_CMD;
91 break;
92 }
93 return status;
94 }
95
96 /*******************************************************************************
97 *
98 * Function avrc_pars_vendor_cmd
99 *
100 * Description This function parses the vendor specific commands defined by
101 * Bluetooth SIG
102 *
103 * Returns AVRC_STS_NO_ERROR, if the message in p_data is parsed
104 * successfully.
105 * Otherwise, the error code defined by AVRCP 1.4
106 *
107 ******************************************************************************/
avrc_pars_vendor_cmd(tAVRC_MSG_VENDOR * p_msg,tAVRC_COMMAND * p_result,uint8_t * p_buf,uint16_t buf_len)108 static tAVRC_STS avrc_pars_vendor_cmd(tAVRC_MSG_VENDOR* p_msg,
109 tAVRC_COMMAND* p_result, uint8_t* p_buf,
110 uint16_t buf_len) {
111 tAVRC_STS status = AVRC_STS_NO_ERROR;
112 uint8_t* p;
113 uint16_t len;
114 uint8_t xx, yy;
115 uint8_t* p_u8;
116 uint16_t* p_u16;
117 uint32_t u32, u32_2, *p_u32;
118 tAVRC_APP_SETTING* p_app_set;
119 uint16_t size_needed;
120
121 /* Check the vendor data */
122 if (p_msg->vendor_len == 0) return AVRC_STS_NO_ERROR;
123 if (p_msg->p_vendor_data == NULL) return AVRC_STS_INTERNAL_ERR;
124
125 if (p_msg->vendor_len < 4) {
126 AVRC_TRACE_WARNING("%s: message length %d too short: must be at least 4",
127 __func__, p_msg->vendor_len);
128 return AVRC_STS_INTERNAL_ERR;
129 }
130
131 p = p_msg->p_vendor_data;
132 p_result->pdu = *p++;
133 AVRC_TRACE_DEBUG("%s pdu:0x%x", __func__, p_result->pdu);
134 if (!AVRC_IsValidAvcType(p_result->pdu, p_msg->hdr.ctype)) {
135 AVRC_TRACE_DEBUG("%s detects wrong AV/C type(0x%x)!", __func__,
136 p_msg->hdr.ctype);
137 status = AVRC_STS_BAD_CMD;
138 }
139
140 p++; /* skip the reserved byte */
141 BE_STREAM_TO_UINT16(len, p);
142 if ((len + 4) != (p_msg->vendor_len)) {
143 AVRC_TRACE_ERROR("%s incorrect length :%d, %d", __func__, len,
144 p_msg->vendor_len);
145 status = AVRC_STS_INTERNAL_ERR;
146 }
147
148 if (status != AVRC_STS_NO_ERROR) return status;
149
150 switch (p_result->pdu) {
151 case AVRC_PDU_GET_CAPABILITIES: /* 0x10 */
152 p_result->get_caps.capability_id = *p++;
153 if (!AVRC_IS_VALID_CAP_ID(p_result->get_caps.capability_id))
154 status = AVRC_STS_BAD_PARAM;
155 else if (len != 1)
156 return AVRC_STS_INTERNAL_ERR;
157 break;
158
159 case AVRC_PDU_LIST_PLAYER_APP_ATTR: /* 0x11 */
160 /* no additional parameters */
161 if (len != 0) return AVRC_STS_INTERNAL_ERR;
162 break;
163
164 case AVRC_PDU_LIST_PLAYER_APP_VALUES: /* 0x12 */
165 if (len == 0) return AVRC_STS_INTERNAL_ERR;
166 p_result->list_app_values.attr_id = *p++;
167 if (!AVRC_IS_VALID_ATTRIBUTE(p_result->list_app_values.attr_id))
168 status = AVRC_STS_BAD_PARAM;
169 else if (len != 1)
170 status = AVRC_STS_INTERNAL_ERR;
171 break;
172
173 case AVRC_PDU_GET_CUR_PLAYER_APP_VALUE: /* 0x13 */
174 case AVRC_PDU_GET_PLAYER_APP_ATTR_TEXT: /* 0x15 */
175 if (len == 0) return AVRC_STS_INTERNAL_ERR;
176 BE_STREAM_TO_UINT8(p_result->get_cur_app_val.num_attr, p);
177 if (len != (p_result->get_cur_app_val.num_attr + 1)) {
178 status = AVRC_STS_INTERNAL_ERR;
179 break;
180 }
181
182 if (p_result->get_cur_app_val.num_attr > AVRC_MAX_APP_ATTR_SIZE) {
183 p_result->get_cur_app_val.num_attr = AVRC_MAX_APP_ATTR_SIZE;
184 }
185
186 p_u8 = p_result->get_cur_app_val.attrs;
187 for (xx = 0, yy = 0; xx < p_result->get_cur_app_val.num_attr; xx++) {
188 /* only report the valid player app attributes */
189 if (AVRC_IsValidPlayerAttr(*p)) p_u8[yy++] = *p;
190 p++;
191 }
192 p_result->get_cur_app_val.num_attr = yy;
193 if (yy == 0) {
194 status = AVRC_STS_BAD_PARAM;
195 }
196 break;
197
198 case AVRC_PDU_SET_PLAYER_APP_VALUE: /* 0x14 */
199 if (len == 0) return AVRC_STS_INTERNAL_ERR;
200 BE_STREAM_TO_UINT8(p_result->set_app_val.num_val, p);
201 size_needed = sizeof(tAVRC_APP_SETTING);
202 if (p_buf && (len == ((p_result->set_app_val.num_val << 1) + 1))) {
203 p_result->set_app_val.p_vals = (tAVRC_APP_SETTING*)p_buf;
204 p_app_set = p_result->set_app_val.p_vals;
205 for (xx = 0;
206 ((xx < p_result->set_app_val.num_val) && (buf_len > size_needed));
207 xx++) {
208 p_app_set[xx].attr_id = *p++;
209 p_app_set[xx].attr_val = *p++;
210 if (!avrc_is_valid_player_attrib_value(p_app_set[xx].attr_id,
211 p_app_set[xx].attr_val))
212 status = AVRC_STS_BAD_PARAM;
213 }
214 if (xx != p_result->set_app_val.num_val) {
215 AVRC_TRACE_ERROR(
216 "%s AVRC_PDU_SET_PLAYER_APP_VALUE not enough room:%d orig "
217 "num_val:%d",
218 __func__, xx, p_result->set_app_val.num_val);
219 p_result->set_app_val.num_val = xx;
220 }
221 } else {
222 AVRC_TRACE_ERROR(
223 "%s AVRC_PDU_SET_PLAYER_APP_VALUE NULL decode buffer or bad len",
224 __func__);
225 status = AVRC_STS_INTERNAL_ERR;
226 }
227 break;
228
229 case AVRC_PDU_GET_PLAYER_APP_VALUE_TEXT: /* 0x16 */
230 if (len < 3)
231 return AVRC_STS_INTERNAL_ERR;
232 else {
233 BE_STREAM_TO_UINT8(p_result->get_app_val_txt.attr_id, p);
234 if (!AVRC_IS_VALID_ATTRIBUTE(p_result->get_app_val_txt.attr_id))
235 status = AVRC_STS_BAD_PARAM;
236 else {
237 BE_STREAM_TO_UINT8(p_result->get_app_val_txt.num_val, p);
238 if ((len - 2 /* attr_id & num_val */) !=
239 p_result->get_app_val_txt.num_val)
240 status = AVRC_STS_INTERNAL_ERR;
241 else {
242 if (p_result->get_app_val_txt.num_val > AVRC_MAX_APP_ATTR_SIZE) {
243 p_result->get_app_val_txt.num_val = AVRC_MAX_APP_ATTR_SIZE;
244 }
245
246 p_u8 = p_result->get_app_val_txt.vals;
247 for (xx = 0; xx < p_result->get_app_val_txt.num_val; xx++) {
248 p_u8[xx] = *p++;
249 if (!avrc_is_valid_player_attrib_value(
250 p_result->get_app_val_txt.attr_id, p_u8[xx])) {
251 status = AVRC_STS_BAD_PARAM;
252 break;
253 }
254 }
255 }
256 }
257 }
258 break;
259
260 case AVRC_PDU_INFORM_DISPLAY_CHARSET: /* 0x17 */
261 if (len < 3)
262 return AVRC_STS_INTERNAL_ERR;
263 else {
264 BE_STREAM_TO_UINT8(p_result->inform_charset.num_id, p);
265 if ((len - 1 /* num_id */) != p_result->inform_charset.num_id * 2)
266 status = AVRC_STS_INTERNAL_ERR;
267 else {
268 p_u16 = p_result->inform_charset.charsets;
269 if (p_result->inform_charset.num_id > AVRC_MAX_CHARSET_SIZE)
270 p_result->inform_charset.num_id = AVRC_MAX_CHARSET_SIZE;
271 for (xx = 0; xx < p_result->inform_charset.num_id; xx++) {
272 BE_STREAM_TO_UINT16(p_u16[xx], p);
273 }
274 }
275 }
276 break;
277
278 case AVRC_PDU_INFORM_BATTERY_STAT_OF_CT: /* 0x18 */
279 if (len != 1)
280 return AVRC_STS_INTERNAL_ERR;
281 else {
282 p_result->inform_battery_status.battery_status = *p++;
283 if (!AVRC_IS_VALID_BATTERY_STATUS(
284 p_result->inform_battery_status.battery_status))
285 status = AVRC_STS_BAD_PARAM;
286 }
287 break;
288
289 case AVRC_PDU_GET_ELEMENT_ATTR: /* 0x20 */
290 if (len < 9) /* UID/8 and num_attr/1 */
291 return AVRC_STS_INTERNAL_ERR;
292 else {
293 BE_STREAM_TO_UINT32(u32, p);
294 BE_STREAM_TO_UINT32(u32_2, p);
295 if (u32 == 0 && u32_2 == 0) {
296 BE_STREAM_TO_UINT8(p_result->get_elem_attrs.num_attr, p);
297 if ((len - 9 /* UID/8 and num_attr/1 */) !=
298 (p_result->get_elem_attrs.num_attr * 4))
299 status = AVRC_STS_INTERNAL_ERR;
300 else {
301 p_u32 = p_result->get_elem_attrs.attrs;
302 if (p_result->get_elem_attrs.num_attr > AVRC_MAX_ELEM_ATTR_SIZE)
303 p_result->get_elem_attrs.num_attr = AVRC_MAX_ELEM_ATTR_SIZE;
304 for (xx = 0; xx < p_result->get_elem_attrs.num_attr; xx++) {
305 BE_STREAM_TO_UINT32(p_u32[xx], p);
306 }
307 }
308 } else
309 status = AVRC_STS_NOT_FOUND;
310 }
311 break;
312
313 case AVRC_PDU_GET_PLAY_STATUS: /* 0x30 */
314 /* no additional parameters */
315 if (len != 0) return AVRC_STS_INTERNAL_ERR;
316 break;
317
318 case AVRC_PDU_REGISTER_NOTIFICATION: /* 0x31 */
319 if (len != 5)
320 return AVRC_STS_INTERNAL_ERR;
321 else {
322 BE_STREAM_TO_UINT8(p_result->reg_notif.event_id, p);
323 if (!AVRC_IS_VALID_EVENT_ID(p_result->reg_notif.event_id)) {
324 AVRC_TRACE_ERROR("%s: Invalid event id: %d", __func__,
325 p_result->reg_notif.event_id);
326 return AVRC_STS_BAD_PARAM;
327 }
328
329 BE_STREAM_TO_UINT32(p_result->reg_notif.param, p);
330 }
331 break;
332
333 case AVRC_PDU_SET_ABSOLUTE_VOLUME: /* 0x50 */
334 if (len != 1)
335 return AVRC_STS_INTERNAL_ERR;
336 else
337 p_result->volume.volume = *p++;
338 break;
339
340 case AVRC_PDU_REQUEST_CONTINUATION_RSP: /* 0x40 */
341 if (len != 1) {
342 return AVRC_STS_INTERNAL_ERR;
343 }
344 BE_STREAM_TO_UINT8(p_result->continu.target_pdu, p);
345 break;
346
347 case AVRC_PDU_ABORT_CONTINUATION_RSP: /* 0x41 */
348 if (len != 1) {
349 return AVRC_STS_INTERNAL_ERR;
350 }
351 BE_STREAM_TO_UINT8(p_result->abort.target_pdu, p);
352 break;
353
354 case AVRC_PDU_SET_ADDRESSED_PLAYER: /* 0x60 */
355 if (len != 2) {
356 AVRC_TRACE_ERROR("AVRC_PDU_SET_ADDRESSED_PLAYER length is incorrect:%d",
357 len);
358 return AVRC_STS_INTERNAL_ERR;
359 }
360 BE_STREAM_TO_UINT16(p_result->addr_player.player_id, p);
361 break;
362
363 case AVRC_PDU_PLAY_ITEM: /* 0x74 */
364 case AVRC_PDU_ADD_TO_NOW_PLAYING: /* 0x90 */
365 if (len != (AVRC_UID_SIZE + 3)) return AVRC_STS_INTERNAL_ERR;
366 BE_STREAM_TO_UINT8(p_result->play_item.scope, p);
367 if (p_result->play_item.scope > AVRC_SCOPE_NOW_PLAYING) {
368 status = AVRC_STS_BAD_SCOPE;
369 }
370 BE_STREAM_TO_ARRAY(p, p_result->play_item.uid, AVRC_UID_SIZE);
371 BE_STREAM_TO_UINT16(p_result->play_item.uid_counter, p);
372 break;
373
374 default:
375 status = AVRC_STS_BAD_CMD;
376 break;
377 }
378
379 return status;
380 }
381
382 /*******************************************************************************
383 *
384 * Function AVRC_Ctrl_ParsCommand
385 *
386 * Description This function is used to parse cmds received for CTRL
387 * Currently it is for SetAbsVolume and Volume Change
388 * Notification.
389 *
390 * Returns AVRC_STS_NO_ERROR, if the message in p_data is parsed
391 * successfully.
392 * Otherwise, the error code defined by AVRCP 1.4
393 *
394 ******************************************************************************/
AVRC_Ctrl_ParsCommand(tAVRC_MSG * p_msg,tAVRC_COMMAND * p_result)395 tAVRC_STS AVRC_Ctrl_ParsCommand(tAVRC_MSG* p_msg, tAVRC_COMMAND* p_result) {
396 tAVRC_STS status = AVRC_STS_INTERNAL_ERR;
397
398 if (p_msg && p_result) {
399 switch (p_msg->hdr.opcode) {
400 case AVRC_OP_VENDOR: /* 0x00 Vendor-dependent commands */
401 status = avrc_ctrl_pars_vendor_cmd(&p_msg->vendor, p_result);
402 break;
403
404 default:
405 AVRC_TRACE_ERROR("%s unknown opcode:0x%x", __func__, p_msg->hdr.opcode);
406 break;
407 }
408 p_result->cmd.opcode = p_msg->hdr.opcode;
409 p_result->cmd.status = status;
410 }
411 AVRC_TRACE_DEBUG("%s return status:0x%x", __func__, status);
412 return status;
413 }
414
415 #define RETURN_STATUS_IF_FALSE(_status_, _b_, _msg_, ...) \
416 if (!(_b_)) { \
417 AVRC_TRACE_DEBUG(_msg_, ##__VA_ARGS__); \
418 return _status_; \
419 }
420
421 /*******************************************************************************
422 *
423 * Function avrc_pars_browsing_cmd
424 *
425 * Description This function parses the commands that go through the
426 * browsing channel
427 *
428 * Returns AVRC_STS_NO_ERROR, if the message in p_data is parsed
429 * successfully.
430 * Otherwise, the error code defined by AVRCP+1
431 *
432 ******************************************************************************/
avrc_pars_browsing_cmd(tAVRC_MSG_BROWSE * p_msg,tAVRC_COMMAND * p_result,uint8_t * p_buf,uint16_t buf_len)433 static tAVRC_STS avrc_pars_browsing_cmd(tAVRC_MSG_BROWSE* p_msg,
434 tAVRC_COMMAND* p_result, uint8_t* p_buf,
435 uint16_t buf_len) {
436 tAVRC_STS status = AVRC_STS_NO_ERROR;
437 uint8_t* p = p_msg->p_browse_data;
438 int count;
439
440 uint32_t min_len = 3;
441 RETURN_STATUS_IF_FALSE(AVRC_STS_BAD_CMD, (p_msg->browse_len >= min_len),
442 "msg too short");
443
444 p_result->pdu = *p++;
445 AVRC_TRACE_DEBUG("avrc_pars_browsing_cmd() pdu:0x%x", p_result->pdu);
446 /* skip over len */
447 p += 2;
448
449 switch (p_result->pdu) {
450 case AVRC_PDU_SET_BROWSED_PLAYER: /* 0x70 */
451 min_len += 2;
452 RETURN_STATUS_IF_FALSE(AVRC_STS_BAD_CMD, (p_msg->browse_len >= min_len),
453 "msg too short");
454
455 // For current implementation all players are browsable.
456 BE_STREAM_TO_UINT16(p_result->br_player.player_id, p);
457 break;
458
459 case AVRC_PDU_GET_FOLDER_ITEMS: /* 0x71 */
460
461 min_len += 10;
462 RETURN_STATUS_IF_FALSE(AVRC_STS_BAD_CMD, (p_msg->browse_len >= min_len),
463 "msg too short");
464
465 STREAM_TO_UINT8(p_result->get_items.scope, p);
466 // To be modified later here (Scope) when all browsing commands are
467 // supported
468 if (p_result->get_items.scope > AVRC_SCOPE_NOW_PLAYING) {
469 status = AVRC_STS_BAD_SCOPE;
470 }
471 BE_STREAM_TO_UINT32(p_result->get_items.start_item, p);
472 BE_STREAM_TO_UINT32(p_result->get_items.end_item, p);
473 if (p_result->get_items.start_item > p_result->get_items.end_item) {
474 status = AVRC_STS_BAD_RANGE;
475 }
476 STREAM_TO_UINT8(p_result->get_items.attr_count, p);
477 p_result->get_items.p_attr_list = NULL;
478 if (p_result->get_items.attr_count && p_buf &&
479 (p_result->get_items.attr_count != AVRC_FOLDER_ITEM_COUNT_NONE)) {
480 p_result->get_items.p_attr_list = (uint32_t*)p_buf;
481 count = p_result->get_items.attr_count;
482 if (buf_len < (count << 2))
483 p_result->get_items.attr_count = count = (buf_len >> 2);
484 for (int idx = 0; idx < count; idx++) {
485 min_len += 4;
486 RETURN_STATUS_IF_FALSE(AVRC_STS_BAD_CMD,
487 (p_msg->browse_len >= min_len),
488 "msg too short");
489
490 BE_STREAM_TO_UINT32(p_result->get_items.p_attr_list[idx], p);
491 }
492 }
493 break;
494
495 case AVRC_PDU_CHANGE_PATH: /* 0x72 */
496 min_len += 11;
497 RETURN_STATUS_IF_FALSE(AVRC_STS_BAD_CMD, (p_msg->browse_len >= min_len),
498 "msg too short");
499
500 BE_STREAM_TO_UINT16(p_result->chg_path.uid_counter, p);
501 BE_STREAM_TO_UINT8(p_result->chg_path.direction, p);
502 if (p_result->chg_path.direction != AVRC_DIR_UP &&
503 p_result->chg_path.direction != AVRC_DIR_DOWN) {
504 status = AVRC_STS_BAD_DIR;
505 }
506 BE_STREAM_TO_ARRAY(p, p_result->chg_path.folder_uid, AVRC_UID_SIZE);
507 break;
508
509 case AVRC_PDU_GET_ITEM_ATTRIBUTES: /* 0x73 */
510 min_len += 12;
511 RETURN_STATUS_IF_FALSE(AVRC_STS_BAD_CMD, (p_msg->browse_len >= min_len),
512 "msg too short");
513
514 BE_STREAM_TO_UINT8(p_result->get_attrs.scope, p);
515
516 if (p_result->get_attrs.scope > AVRC_SCOPE_NOW_PLAYING) {
517 status = AVRC_STS_BAD_SCOPE;
518 break;
519 }
520 BE_STREAM_TO_ARRAY(p, p_result->get_attrs.uid, AVRC_UID_SIZE);
521 BE_STREAM_TO_UINT16(p_result->get_attrs.uid_counter, p);
522 BE_STREAM_TO_UINT8(p_result->get_attrs.attr_count, p);
523 p_result->get_attrs.p_attr_list = NULL;
524 if (p_result->get_attrs.attr_count && p_buf) {
525 p_result->get_attrs.p_attr_list = (uint32_t*)p_buf;
526 count = p_result->get_attrs.attr_count;
527 if (buf_len < (count << 2))
528 p_result->get_attrs.attr_count = count = (buf_len >> 2);
529 for (int idx = 0, count = 0; idx < p_result->get_attrs.attr_count;
530 idx++) {
531 min_len += 4;
532 RETURN_STATUS_IF_FALSE(AVRC_STS_BAD_CMD,
533 (p_msg->browse_len >= min_len),
534 "msg too short");
535
536 BE_STREAM_TO_UINT32(p_result->get_attrs.p_attr_list[count], p);
537 if (AVRC_IS_VALID_MEDIA_ATTRIBUTE(
538 p_result->get_attrs.p_attr_list[count])) {
539 count++;
540 }
541 }
542
543 if (p_result->get_attrs.attr_count != count && count == 0)
544 status = AVRC_STS_BAD_PARAM;
545 else
546 p_result->get_attrs.attr_count = count;
547 }
548 break;
549
550 case AVRC_PDU_GET_TOTAL_NUM_OF_ITEMS: /* 0x75 */
551 ++min_len;
552 RETURN_STATUS_IF_FALSE(AVRC_STS_BAD_CMD, (p_msg->browse_len >= min_len),
553 "msg too short");
554
555 BE_STREAM_TO_UINT8(p_result->get_num_of_items.scope, p);
556 if (p_result->get_num_of_items.scope > AVRC_SCOPE_NOW_PLAYING) {
557 status = AVRC_STS_BAD_SCOPE;
558 }
559 break;
560
561 case AVRC_PDU_SEARCH: /* 0x80 */
562 min_len += 4;
563 RETURN_STATUS_IF_FALSE(AVRC_STS_BAD_CMD, (p_msg->browse_len >= min_len),
564 "msg too short");
565
566 BE_STREAM_TO_UINT16(p_result->search.string.charset_id, p);
567 BE_STREAM_TO_UINT16(p_result->search.string.str_len, p);
568 p_result->search.string.p_str = p_buf;
569 if (p_buf) {
570 if (p_result->search.string.str_len > buf_len) {
571 p_result->search.string.str_len = buf_len;
572 }
573 min_len += p_result->search.string.str_len;
574 RETURN_STATUS_IF_FALSE(AVRC_STS_BAD_CMD, (p_msg->browse_len >= min_len),
575 "msg too short");
576
577 BE_STREAM_TO_ARRAY(p, p_buf, p_result->search.string.str_len);
578 } else {
579 status = AVRC_STS_INTERNAL_ERR;
580 }
581 break;
582
583 default:
584 status = AVRC_STS_BAD_CMD;
585 break;
586 }
587 return status;
588 }
589
590 /*******************************************************************************
591 *
592 * Function AVRC_ParsCommand
593 *
594 * Description This function is a superset of AVRC_ParsMetadata to parse
595 * the command.
596 *
597 * Returns AVRC_STS_NO_ERROR, if the message in p_data is parsed
598 * successfully.
599 * Otherwise, the error code defined by AVRCP 1.4
600 *
601 ******************************************************************************/
AVRC_ParsCommand(tAVRC_MSG * p_msg,tAVRC_COMMAND * p_result,uint8_t * p_buf,uint16_t buf_len)602 tAVRC_STS AVRC_ParsCommand(tAVRC_MSG* p_msg, tAVRC_COMMAND* p_result,
603 uint8_t* p_buf, uint16_t buf_len) {
604 tAVRC_STS status = AVRC_STS_INTERNAL_ERR;
605 uint16_t id;
606
607 if (p_msg && p_result) {
608 switch (p_msg->hdr.opcode) {
609 case AVRC_OP_VENDOR: /* 0x00 Vendor-dependent commands */
610 status = avrc_pars_vendor_cmd(&p_msg->vendor, p_result, p_buf, buf_len);
611 break;
612
613 case AVRC_OP_PASS_THRU: /* 0x7C panel subunit opcode */
614 status = avrc_pars_pass_thru(&p_msg->pass, &id);
615 if (status == AVRC_STS_NO_ERROR) {
616 p_result->pdu = (uint8_t)id;
617 }
618 break;
619
620 case AVRC_OP_BROWSE:
621 status =
622 avrc_pars_browsing_cmd(&p_msg->browse, p_result, p_buf, buf_len);
623 break;
624
625 default:
626 AVRC_TRACE_ERROR("%s unknown opcode:0x%x", __func__, p_msg->hdr.opcode);
627 break;
628 }
629 p_result->cmd.opcode = p_msg->hdr.opcode;
630 p_result->cmd.status = status;
631 }
632 AVRC_TRACE_DEBUG("%s return status:0x%x", __func__, status);
633 return status;
634 }
635