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