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