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