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