OSDN Git Service

AVRCP 1.6: media browsing support on Target(1/3)
authorAvish Shah <avish.shah@broadcom.com>
Wed, 22 Jun 2016 01:17:20 +0000 (06:47 +0530)
committerAjay Panicker <apanicke@google.com>
Thu, 1 Sep 2016 23:26:00 +0000 (23:26 +0000)
-> As a part of Avrcp 1.6 upgrade, added support
   for following features:
   [1] setAddressedPlayer
   [2] setBrowsedPlayer
   [3] getFolderItems scope=VFS/NowPlaying/Search
   [4] changePath
   [5] getItemAttributes
   [6] playItem
   [7] getTotalNumberOfItems
   [8] search string in current browsed path.
   [9] AddToNowPlaying
-> Defined functions and enhanced structures to
   support above mentioned features.
-> Added Dual RC support.

Bug: 19361366
Change-Id: I45ed60e337b57c686d9693e19993fee1ce3c2504

24 files changed:
bta/av/bta_av_act.c
bta/av/bta_av_cfg.c
bta/av/bta_av_int.h
bta/av/bta_av_main.c
bta/include/bta_av_api.h
btif/src/btif_av.cc
btif/src/btif_rc.cc
btif/src/btif_util.cc
include/bt_target.h
stack/Android.mk
stack/avct/avct_api.c
stack/avct/avct_bcb_act.c [new file with mode: 0644]
stack/avct/avct_defs.h
stack/avct/avct_int.h
stack/avct/avct_l2c_br.c [new file with mode: 0644]
stack/avct/avct_lcb_act.c
stack/avrc/avrc_api.c
stack/avrc/avrc_bld_tg.c
stack/avrc/avrc_int.h
stack/avrc/avrc_pars_tg.c
stack/avrc/avrc_sdp.c
stack/avrc/avrc_utils.c
stack/include/avrc_api.h
stack/include/avrc_defs.h

index 7de96e9..f2814ae 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2004-2012 Broadcom Corporation
+ *  Copyright (C) 2004-2016 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -227,6 +227,14 @@ static void bta_av_rc_ctrl_cback(uint8_t handle, uint8_t event, uint16_t result,
     {
         msg_event = BTA_AV_AVRC_CLOSE_EVT;
     }
+    else if (event == AVRC_BROWSE_OPEN_IND_EVT)
+    {
+        msg_event = BTA_AV_AVRC_BROWSE_OPEN_EVT;
+    }
+    else if (event == AVRC_BROWSE_CLOSE_IND_EVT)
+    {
+        msg_event = BTA_AV_AVRC_BROWSE_CLOSE_EVT;
+    }
 
     if (msg_event) {
         tBTA_AV_RC_CONN_CHG *p_msg =
@@ -255,7 +263,10 @@ static void bta_av_rc_msg_cback(uint8_t handle, uint8_t label, uint8_t opcode, t
 
     APPL_TRACE_DEBUG("%s handle: %u opcode=0x%x", __func__, handle, opcode);
 
-    /* Determine the size of the buffer we need */
+    /* Copy avrc packet into BTA message buffer (for sending to BTA state machine) */
+
+    /* Get size of payload data  (for vendor and passthrough messages only; for browsing
+     * messages, use zero-copy) */
     if (opcode == AVRC_OP_VENDOR && p_msg->vendor.p_vendor_data != NULL) {
         p_data_src = p_msg->vendor.p_vendor_data;
         data_len = (uint16_t) p_msg->vendor.vendor_len;
@@ -267,6 +278,7 @@ static void bta_av_rc_msg_cback(uint8_t handle, uint8_t label, uint8_t opcode, t
     /* Create a copy of the message */
     tBTA_AV_RC_MSG *p_buf =
         (tBTA_AV_RC_MSG *)osi_malloc(sizeof(tBTA_AV_RC_MSG) + data_len);
+
     p_buf->hdr.event = BTA_AV_AVRC_MSG_EVT;
     p_buf->handle = handle;
     p_buf->label = label;
@@ -276,13 +288,23 @@ static void bta_av_rc_msg_cback(uint8_t handle, uint8_t label, uint8_t opcode, t
     if (p_data_src != NULL) {
         uint8_t *p_data_dst = (uint8_t *)(p_buf + 1);
         memcpy(p_data_dst, p_data_src, data_len);
+
+        /* Update bta message buffer to point to payload data */
+        /* (Note AVRC_OP_BROWSING uses zero-copy: p_buf->msg.browse.p_browse_data
+         * already points to original avrc buffer) */
         if (opcode == AVRC_OP_VENDOR)
             p_buf->msg.vendor.p_vendor_data = p_data_dst;
         else if (opcode == AVRC_OP_PASS_THRU)
             p_buf->msg.pass.p_pass_data = p_data_dst;
     }
 
+    if (opcode == AVRC_OP_BROWSE) {
+        /* set p_pkt to NULL, so avrc would not free the buffer */
+        p_msg->browse.p_browse_pkt = NULL;
+    }
+
     bta_sys_sendmsg(p_buf);
+
 }
 
 /*******************************************************************************
@@ -323,7 +345,8 @@ uint8_t bta_av_rc_create(tBTA_AV_CB *p_cb, uint8_t role, uint8_t shdl, uint8_t l
     ccb.company_id = p_bta_av_cfg->company_id;
     ccb.conn = role;
     /* note: BTA_AV_FEAT_RCTG = AVRC_CT_TARGET, BTA_AV_FEAT_RCCT = AVRC_CT_CONTROL */
-    ccb.control = p_cb->features & (BTA_AV_FEAT_RCTG | BTA_AV_FEAT_RCCT | AVRC_CT_PASSIVE);
+    ccb.control = p_cb->features & (BTA_AV_FEAT_RCTG | BTA_AV_FEAT_RCCT | BTA_AV_FEAT_METADATA |
+        AVRC_CT_PASSIVE);
 
     if (AVRC_Open(&rc_handle, &ccb, bda) != AVRC_SUCCESS)
         return BTA_AV_RC_HANDLE_NONE;
@@ -512,6 +535,14 @@ void bta_av_rc_opened(tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data)
         return;
     }
 
+    if (p_cb->features & BTA_AV_FEAT_RCTG)
+    {
+        /* listen to browsing channel when the connection is open,
+         * if peer initiated AVRCP connection and local device supports browsing channel */
+        if ((p_cb->features & BTA_AV_FEAT_BROWSE) && (p_cb->rcb[i].peer_features == 0))
+            AVRC_OpenBrowse(p_data->rc_conn_chg.handle, AVCT_ACP);
+    }
+
     if (p_cb->rcb[i].lidx == (BTA_AV_NUM_LINKS + 1) && shdl != 0)
     {
         /* rc is opened on the RC only ACP channel, but is for a specific
@@ -572,6 +603,15 @@ void bta_av_rc_opened(tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data)
     }
     (*p_cb->p_cback)(BTA_AV_RC_OPEN_EVT, (tBTA_AV *) &rc_open);
 
+    /* if local initiated AVRCP connection and both peer and locals device support
+     * browsing channel, open the browsing channel now */
+    if ((p_cb->features & BTA_AV_FEAT_BROWSE) &&
+        (rc_open.peer_features & BTA_AV_FEAT_BROWSE) &&
+        ((p_cb->rcb[i].status & BTA_AV_RC_ROLE_MASK) == BTA_AV_RC_ROLE_INT))
+    {
+        AVRC_OpenBrowse (p_data->rc_conn_chg.handle, AVCT_INT);
+    }
+
 }
 
 /*******************************************************************************
@@ -696,17 +736,20 @@ void bta_av_rc_free_rsp (tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data)
 
 /*******************************************************************************
 **
-** Function         bta_av_rc_meta_req
+** Function         bta_av_rc_free_browse_msg
 **
-** Description      Send an AVRCP metadata command.
+** Description      free an AVRCP browse message buffer.
 **
 ** Returns          void
 **
 *******************************************************************************/
-void bta_av_rc_free_msg (tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data)
+void bta_av_rc_free_browse_msg (tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data)
 {
     UNUSED(p_cb);
-    UNUSED(p_data);
+    if (p_data->rc_msg.opcode == AVRC_OP_BROWSE)
+    {
+        osi_free_and_reset((void **)&p_data->rc_msg.msg.browse.p_browse_pkt);
+    }
 }
 
 /*******************************************************************************
@@ -778,7 +821,8 @@ tBTA_AV_EVT bta_av_proc_meta_cmd(tAVRC_RESPONSE  *p_rc_rsp, tBTA_AV_RC_MSG *p_ms
         /* reject it */
         evt=0;
         p_vendor->hdr.ctype = BTA_AV_RSP_NOT_IMPL;
-        AVRC_VendorRsp(p_msg->handle, p_msg->label, &p_msg->msg.vendor);
+        p_vendor->vendor_len = 0;
+        p_rc_rsp->rsp.status = AVRC_STS_BAD_PARAM;
     }
     else if (!AVRC_IsValidAvcType(pdu, p_vendor->hdr.ctype) )
     {
@@ -872,6 +916,15 @@ void bta_av_rc_msg(tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data)
     rc_rsp.rsp.status = BTA_AV_STS_NO_RSP;
 #endif
 
+    if (NULL == p_data)
+    {
+        APPL_TRACE_ERROR("Message from peer with no data in %s", __func__);
+        return;
+    }
+
+    APPL_TRACE_DEBUG("%s: opcode=%x, ctype=%x", __func__, p_data->rc_msg.opcode,
+            p_data->rc_msg.msg.hdr.ctype);
+
     if (p_data->rc_msg.opcode == AVRC_OP_PASS_THRU)
     {
         /* if this is a pass thru command */
@@ -893,7 +946,7 @@ void bta_av_rc_msg(tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data)
                         p_data->rc_msg.msg.pass.p_pass_data, is_inquiry);
 #endif
             }
-#if (AVRC_CTLR_INCLUDED == TRUE)
+#if (AVRC_CTRL_INCLUDED == TRUE)
             else if (((p_data->rc_msg.msg.pass.op_id == AVRC_ID_VOL_UP)||
                       (p_data->rc_msg.msg.pass.op_id == AVRC_ID_VOL_DOWN)) &&
                      !strcmp(avrcp_ct_support, "true"))
@@ -974,6 +1027,7 @@ void bta_av_rc_msg(tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data)
                (p_vendor->company_id == AVRC_CO_METADATA))
             {
                 av.meta_msg.p_msg = &p_data->rc_msg.msg;
+                rc_rsp.rsp.status = BTA_AV_STS_NO_RSP;
                 evt = bta_av_proc_meta_cmd (&rc_rsp, &p_data->rc_msg, &ctype);
             }
             else
@@ -1011,6 +1065,19 @@ void bta_av_rc_msg(tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data)
            AVRC_VendorRsp(p_data->rc_msg.handle, p_data->rc_msg.label, &p_data->rc_msg.msg.vendor);
         }
     }
+    else if (p_data->rc_msg.opcode == AVRC_OP_BROWSE)
+    {
+        /* set up for callback */
+        av.meta_msg.rc_handle = p_data->rc_msg.handle;
+        av.meta_msg.company_id = p_vendor->company_id;
+        av.meta_msg.code = p_data->rc_msg.msg.hdr.ctype;
+        av.meta_msg.label = p_data->rc_msg.label;
+        av.meta_msg.p_msg = &p_data->rc_msg.msg;
+        av.meta_msg.p_data = p_data->rc_msg.msg.browse.p_browse_data;
+        av.meta_msg.len = p_data->rc_msg.msg.browse.browse_len;
+        evt = BTA_AV_META_MSG_EVT;
+    }
+
 #if (AVRC_METADATA_INCLUDED == TRUE)
     if (evt == 0 && rc_rsp.rsp.status != BTA_AV_STS_NO_RSP)
     {
@@ -1029,6 +1096,8 @@ void bta_av_rc_msg(tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data)
     {
         av.remote_cmd.rc_handle = p_data->rc_msg.handle;
         (*p_cb->p_cback)(evt, &av);
+        /* If browsing message, then free the browse message buffer */
+        bta_av_rc_free_browse_msg(p_cb, p_data);
     }
 }
 
@@ -1328,6 +1397,8 @@ void bta_av_conn_chg(tBTA_AV_DATA *p_data)
             if (bta_av_cb.rcb[i].shdl == index + 1)
             {
                 bta_av_del_rc(&bta_av_cb.rcb[i]);
+                /* since the connection is already down and info was removed, clean reference */
+                bta_av_cb.rcb[i].shdl = 0;
                 break;
             }
         }
@@ -2036,6 +2107,61 @@ void bta_av_rc_closed(tBTA_AV_DATA *p_data)
 
 /*******************************************************************************
 **
+** Function         bta_av_rc_browse_opened
+**
+** Description      AVRC browsing channel is opened
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_av_rc_browse_opened(tBTA_AV_DATA *p_data)
+{
+    tBTA_AV_CB   *p_cb = &bta_av_cb;
+    tBTA_AV_RC_CONN_CHG *p_msg = (tBTA_AV_RC_CONN_CHG *)p_data;
+    tBTA_AV_RC_BROWSE_OPEN  rc_browse_open;
+
+    APPL_TRACE_DEBUG("bta_av_rc_browse_opened bd_addr:%02x-%02x-%02x-%02x-%02x-%02x",
+              p_msg->peer_addr[0], p_msg->peer_addr[1],
+              p_msg->peer_addr[2], p_msg->peer_addr[3],
+              p_msg->peer_addr[4], p_msg->peer_addr[5]);
+    APPL_TRACE_DEBUG("bta_av_rc_browse_opened rc_handle:%d", p_msg->handle);
+
+    rc_browse_open.status = BTA_AV_SUCCESS;
+    rc_browse_open.rc_handle = p_msg->handle;
+    bdcpy(rc_browse_open.peer_addr, p_msg->peer_addr);
+
+    (*p_cb->p_cback)(BTA_AV_RC_BROWSE_OPEN_EVT, (tBTA_AV *)&rc_browse_open);
+}
+
+/*******************************************************************************
+**
+** Function         bta_av_rc_browse_closed
+**
+** Description      AVRC browsing channel is closed
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_av_rc_browse_closed(tBTA_AV_DATA *p_data)
+{
+    tBTA_AV_CB   *p_cb = &bta_av_cb;
+    tBTA_AV_RC_CONN_CHG *p_msg = (tBTA_AV_RC_CONN_CHG *)p_data;
+    tBTA_AV_RC_BROWSE_CLOSE  rc_browse_close;
+
+    APPL_TRACE_DEBUG("bta_av_rc_browse_closed bd_addr:%02x-%02x-%02x-%02x-%02x-%02x",
+              p_msg->peer_addr[0], p_msg->peer_addr[1],
+              p_msg->peer_addr[2], p_msg->peer_addr[3],
+              p_msg->peer_addr[4], p_msg->peer_addr[5]);
+    APPL_TRACE_DEBUG("bta_av_rc_browse_closed rc_handle:%d", p_msg->handle);
+
+    rc_browse_close.rc_handle = p_msg->handle;
+    bdcpy(rc_browse_close.peer_addr, p_msg->peer_addr);
+
+    (*p_cb->p_cback)(BTA_AV_RC_BROWSE_CLOSE_EVT, (tBTA_AV *)&rc_browse_close);
+}
+
+/*******************************************************************************
+**
 ** Function         bta_av_rc_disc
 **
 ** Description      start AVRC SDP discovery.
index 0b6f4be..3113592 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2005-2012 Broadcom Corporation
+ *  Copyright (C) 2005-2016 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
 #include "bta_api.h"
 #include "bta_av_int.h"
 
+#ifndef BTA_AV_RC_COMP_ID
+#define BTA_AV_RC_COMP_ID    AVRC_CO_GOOGLE
+#endif
+
 #ifndef BTA_AV_RC_PASS_RSP_CODE
 #define BTA_AV_RC_PASS_RSP_CODE     BTA_AV_RSP_NOT_IMPL
 #endif
@@ -39,13 +43,22 @@ const uint32_t  bta_av_meta_caps_co_ids[] = {
     AVRC_CO_BROADCOM
 };
 
-/* AVRCP cupported categories */
+/* AVRCP supported categories */
 #if (AVRC_CTRL_INCLUDED == TRUE)
 #define BTA_AV_RC_SUPF_CT       (AVRC_SUPF_CT_CAT2)
 #define BTA_AVK_RC_SUPF_CT       (AVRC_SUPF_CT_CAT1)
 #define BTA_AVK_RC_SUPF_TG       (AVRC_SUPF_TG_CAT2)
 #endif
 
+/* AVRCP Controller and Targer default name */
+#ifndef BTA_AV_RC_CT_NAME
+#define BTA_AV_RC_CT_NAME    "AVRC Controller"
+#endif
+
+#ifndef BTA_AV_RC_TG_NAME
+#define BTA_AV_RC_TG_NAME    "AVRC Target"
+#endif
+
 /* Added to modify
 **     1. flush timeout
 **     2. Remove Group navigation support in SupportedFeatures
@@ -65,7 +78,8 @@ const uint16_t  bta_av_audio_flush_to[] = {
 /* Note: Android doesnt support AVRC_SUPF_TG_GROUP_NAVI  */
 /* Note: if AVRC_SUPF_TG_GROUP_NAVI is set, bta_av_cfg.avrc_group should be true */
 #if (AVRC_METADATA_INCLUDED == TRUE)
-#define BTA_AV_RC_SUPF_TG       (AVRC_SUPF_TG_CAT1) /* TODO: | AVRC_SUPF_TG_APP_SETTINGS) */
+#define BTA_AV_RC_SUPF_TG    (AVRC_SUPF_TG_CAT1 | AVRC_SUPF_TG_MULTI_PLAYER | \
+                                 AVRC_SUPF_TG_BROWSE) /* TODO: | AVRC_SUPF_TG_APP_SETTINGS) */
 #else
 #define BTA_AV_RC_SUPF_TG       (AVRC_SUPF_TG_CAT1)
 #endif
@@ -77,6 +91,10 @@ const uint8_t  bta_av_meta_caps_evt_ids[] = {
     AVRC_EVT_PLAY_STATUS_CHANGE,
     AVRC_EVT_TRACK_CHANGE,
     AVRC_EVT_PLAY_POS_CHANGED,
+    AVRC_EVT_AVAL_PLAYERS_CHANGE,
+    AVRC_EVT_ADDR_PLAYER_CHANGE,
+    AVRC_EVT_UIDS_CHANGE,
+    AVRC_EVT_NOW_PLAYING_CHANGE,
     /* TODO: Add support for these events
     AVRC_EVT_APP_SETTING_CHANGE,
     */
@@ -103,7 +121,7 @@ const uint8_t  bta_avk_meta_caps_evt_ids[] = {
 /* This configuration to be used when we are Src + TG + CT( only for abs vol) */
 const tBTA_AV_CFG bta_av_cfg =
 {
-    AVRC_CO_BROADCOM,       /* AVRCP Company ID */
+    BTA_AV_RC_COMP_ID,      /* AVRCP Company ID */
 #if (AVRC_METADATA_INCLUDED == TRUE)
     512,                    /* AVRCP MTU at L2CAP for control channel */
 #else
@@ -126,8 +144,8 @@ const tBTA_AV_CFG bta_av_cfg =
     bta_av_meta_caps_evt_ids,/* the the metadata Get Capabilities response for event id */
     NULL,                   /* the action function table for VDP stream */
     NULL,                   /* action function to register VDP */
-    {0},                    /* Default AVRCP controller name */
-    {0},                    /* Default AVRCP target name */
+    BTA_AV_RC_CT_NAME,      /* Default AVRCP controller name */
+    BTA_AV_RC_TG_NAME       /* Default AVRCP target name */
 };
 
 /* This configuration to be used when we are Sink + CT + TG( only for abs vol) */
index b60c935..9665976 100644 (file)
@@ -97,6 +97,8 @@ enum
     BTA_AV_SIGNALLING_TIMER_EVT,
     BTA_AV_SDP_AVRC_DISC_EVT,
     BTA_AV_AVRC_CLOSE_EVT,
+    BTA_AV_AVRC_BROWSE_OPEN_EVT,
+    BTA_AV_AVRC_BROWSE_CLOSE_EVT,
     BTA_AV_CONN_CHG_EVT,
     BTA_AV_DEREG_COMP_EVT,
 #if (AVDT_REPORTING == TRUE)
@@ -651,6 +653,8 @@ extern void bta_av_sig_chg(tBTA_AV_DATA *p_data);
 extern void bta_av_signalling_timer(tBTA_AV_DATA *p_data);
 extern void bta_av_rc_disc_done(tBTA_AV_DATA *p_data);
 extern void bta_av_rc_closed(tBTA_AV_DATA *p_data);
+extern void bta_av_rc_browse_opened(tBTA_AV_DATA *p_data);
+extern void bta_av_rc_browse_closed(tBTA_AV_DATA *p_data);
 extern void bta_av_rc_disc(uint8_t disc);
 extern void bta_av_conn_chg(tBTA_AV_DATA *p_data);
 extern void bta_av_dereg_comp(tBTA_AV_DATA *p_data);
@@ -665,7 +669,7 @@ extern void bta_av_rc_msg (tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data);
 extern void bta_av_rc_close (tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data);
 extern void bta_av_rc_meta_rsp (tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data);
 extern void bta_av_rc_free_rsp (tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data);
-extern void bta_av_rc_free_msg (tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data);
+extern void bta_av_rc_free_browse_msg (tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data);
 
 extern tBTA_AV_RCB * bta_av_get_rcb_by_shdl(uint8_t shdl);
 extern void bta_av_del_rc(tBTA_AV_RCB *p_rcb);
index 83ecd3a..000d133 100644 (file)
@@ -78,7 +78,7 @@ enum
     BTA_AV_RC_VENDOR_CMD,
     BTA_AV_RC_VENDOR_RSP,
     BTA_AV_RC_FREE_RSP,
-    BTA_AV_RC_FREE_MSG,
+    BTA_AV_RC_FREE_BROWSE_MSG,
     BTA_AV_RC_META_RSP,
     BTA_AV_RC_MSG,
     BTA_AV_RC_CLOSE,
@@ -99,7 +99,7 @@ const tBTA_AV_ACTION bta_av_action[] =
     bta_av_rc_vendor_cmd,
     bta_av_rc_vendor_rsp,
     bta_av_rc_free_rsp,
-    bta_av_rc_free_msg,
+    bta_av_rc_free_browse_msg,
     bta_av_rc_meta_rsp,
     bta_av_rc_msg,
     bta_av_rc_close,
@@ -122,7 +122,7 @@ static const uint8_t bta_av_st_init[][BTA_AV_NUM_COLS] =
 /* API_META_RSP_EVT */      {BTA_AV_RC_FREE_RSP,    BTA_AV_INIT_ST },
 /* API_RC_CLOSE_EVT */      {BTA_AV_IGNORE,         BTA_AV_INIT_ST },
 /* AVRC_OPEN_EVT */         {BTA_AV_RC_OPENED,      BTA_AV_OPEN_ST },
-/* AVRC_MSG_EVT */          {BTA_AV_RC_FREE_MSG,    BTA_AV_INIT_ST },
+/* AVRC_MSG_EVT */         {BTA_AV_RC_FREE_BROWSE_MSG, BTA_AV_INIT_ST },
 /* AVRC_NONE_EVT */         {BTA_AV_IGNORE,         BTA_AV_INIT_ST },
 };
 
@@ -176,6 +176,8 @@ const tBTA_AV_NSM_ACT bta_av_nsm_act[] =
     bta_av_signalling_timer, /* BTA_AV_SIGNALLING_TIMER_EVT */
     bta_av_rc_disc_done,    /* BTA_AV_SDP_AVRC_DISC_EVT */
     bta_av_rc_closed,       /* BTA_AV_AVRC_CLOSE_EVT */
+    bta_av_rc_browse_opened,/* BTA_AV_AVRC_BROWSE_OPEN_EVT */
+    bta_av_rc_browse_closed,/* BTA_AV_AVRC_BROWSE_CLOSE_EVT */
     bta_av_conn_chg,        /* BTA_AV_CONN_CHG_EVT */
     bta_av_dereg_comp,      /* BTA_AV_DEREG_COMP_EVT */
 #if (AVDT_REPORTING == TRUE)
@@ -456,10 +458,16 @@ static void bta_av_api_register(tBTA_AV_DATA *p_data)
         p_bta_av_cfg  = (tBTA_AV_CFG *) &bta_av_cfg;
     }
 
+    if (p_bta_av_cfg == NULL)
+    {
+        APPL_TRACE_ERROR("AV configuration is null!");
+        return;
+    }
+
     do
     {
         p_scb = bta_av_alloc_scb(registr.chnl);
-        if(p_scb == NULL)
+        if (p_scb == NULL)
         {
             APPL_TRACE_ERROR("failed to alloc SCB");
             break;
@@ -471,7 +479,7 @@ static void bta_av_api_register(tBTA_AV_DATA *p_data)
         /* initialize the stream control block */
         registr.status = BTA_AV_SUCCESS;
 
-        if((bta_av_cb.reg_audio + bta_av_cb.reg_video) == 0)
+        if ((bta_av_cb.reg_audio + bta_av_cb.reg_video) == 0)
         {
             /* the first channel registered. register to AVDTP */
             reg.ctrl_mtu = p_bta_av_cfg->sig_mtu;
@@ -496,20 +504,26 @@ static void bta_av_api_register(tBTA_AV_DATA *p_data)
                 bta_ar_reg_avct(p_bta_av_cfg->avrc_mtu, p_bta_av_cfg->avrc_br_mtu,
                                 (uint8_t)(bta_av_cb.sec_mask & (~BTA_SEC_AUTHORIZE)), BTA_ID_AV);
 #endif
+
+                uint16_t profile_version = AVRC_REV_1_0;
                 if (profile_initialized == UUID_SERVCLASS_AUDIO_SOURCE)
                 {
-                    bta_ar_reg_avrc(UUID_SERVCLASS_AV_REM_CTRL_TARGET, "AV Remote Control Target",
-                                   NULL, p_bta_av_cfg->avrc_tg_cat, BTA_ID_AV,
-                                   (bta_av_cb.features & BTA_AV_FEAT_BROWSE), AVRC_REV_1_3);
+#if AVRC_1_6_INCLUDED == TRUE
+                    profile_version = AVRC_REV_1_6;
+#else
+                    profile_version = AVRC_REV_1_3;
+#endif
                 }
                 else if (profile_initialized == UUID_SERVCLASS_AUDIO_SINK)
                 {
                     // Initialize AVRCP1.4 to provide Absolute Volume control.
-                    bta_ar_reg_avrc(UUID_SERVCLASS_AV_REM_CTRL_TARGET, "AV Remote Control Target",
-                                   NULL, p_bta_av_cfg->avrc_tg_cat, BTA_ID_AV,
-                                   (bta_av_cb.features & BTA_AV_FEAT_BROWSE), AVRC_REV_1_4);
+                    profile_version = AVRC_REV_1_4;
                 }
+                bta_ar_reg_avrc(UUID_SERVCLASS_AV_REM_CTRL_TARGET, "AV Remote Control Target",
+                               NULL, p_bta_av_cfg->avrc_tg_cat, BTA_ID_AV,
+                               (bta_av_cb.features & BTA_AV_FEAT_BROWSE), profile_version);
 #endif
+
             }
 
             /* Set the Capturing service class bit */
@@ -1331,6 +1345,8 @@ char *bta_av_evt_code(uint16_t evt_code)
     case BTA_AV_SIGNALLING_TIMER_EVT: return "SIGNALLING_TIMER";
     case BTA_AV_SDP_AVRC_DISC_EVT: return "SDP_AVRC_DISC";
     case BTA_AV_AVRC_CLOSE_EVT: return "AVRC_CLOSE";
+    case BTA_AV_AVRC_BROWSE_OPEN_EVT: return "AVRC_BROWSE_OPEN";
+    case BTA_AV_AVRC_BROWSE_CLOSE_EVT: return "AVRC_BROWSE_CLOSE";
     case BTA_AV_CONN_CHG_EVT: return "CONN_CHG";
     case BTA_AV_DEREG_COMP_EVT: return "DEREG_COMP";
 #if (AVDT_REPORTING == TRUE)
index d5f17f9..e04c2f1 100644 (file)
@@ -203,34 +203,36 @@ typedef uint8_t tBTA_AV_ERR;
 
 
 /* AV callback events */
-#define BTA_AV_ENABLE_EVT       0       /* AV enabled */
-#define BTA_AV_REGISTER_EVT     1       /* registered to AVDT */
-#define BTA_AV_OPEN_EVT         2       /* connection opened */
-#define BTA_AV_CLOSE_EVT        3       /* connection closed */
-#define BTA_AV_START_EVT        4       /* stream data transfer started */
-#define BTA_AV_STOP_EVT         5       /* stream data transfer stopped */
-#define BTA_AV_PROTECT_REQ_EVT  6       /* content protection request */
-#define BTA_AV_PROTECT_RSP_EVT  7       /* content protection response */
-#define BTA_AV_RC_OPEN_EVT      8       /* remote control channel open */
-#define BTA_AV_RC_CLOSE_EVT     9       /* remote control channel closed */
-#define BTA_AV_REMOTE_CMD_EVT   10      /* remote control command */
-#define BTA_AV_REMOTE_RSP_EVT   11      /* remote control response */
-#define BTA_AV_VENDOR_CMD_EVT   12      /* vendor dependent remote control command */
-#define BTA_AV_VENDOR_RSP_EVT   13      /* vendor dependent remote control response */
-#define BTA_AV_RECONFIG_EVT     14      /* reconfigure response */
-#define BTA_AV_SUSPEND_EVT      15      /* suspend response */
-#define BTA_AV_PENDING_EVT      16      /* incoming connection pending:
-                                         * signal channel is open and stream is
-                                         * not open after
-                                         * BTA_AV_SIGNALLING_TIMEOUT_MS */
-#define BTA_AV_META_MSG_EVT     17      /* metadata messages */
-#define BTA_AV_REJECT_EVT       18      /* incoming connection rejected */
-#define BTA_AV_RC_FEAT_EVT      19      /* remote control channel peer supported features update */
-#define BTA_AV_SINK_MEDIA_CFG_EVT    20 /* command to configure sink codec */
-#define BTA_AV_SINK_MEDIA_DATA_EVT   21 /* sending sink data to Media Task */
-#define BTA_AV_OFFLOAD_START_RSP_EVT 22 /* a2dp offload start response */
+#define BTA_AV_ENABLE_EVT            0  /* AV enabled */
+#define BTA_AV_REGISTER_EVT          1  /* registered to AVDT */
+#define BTA_AV_OPEN_EVT              2  /* connection opened */
+#define BTA_AV_CLOSE_EVT             3  /* connection closed */
+#define BTA_AV_START_EVT             4  /* stream data transfer started */
+#define BTA_AV_STOP_EVT              5  /* stream data transfer stopped */
+#define BTA_AV_PROTECT_REQ_EVT       6  /* content protection request */
+#define BTA_AV_PROTECT_RSP_EVT       7  /* content protection response */
+#define BTA_AV_RC_OPEN_EVT           8  /* remote control channel open */
+#define BTA_AV_RC_CLOSE_EVT          9  /* remote control channel closed */
+#define BTA_AV_RC_BROWSE_OPEN_EVT    10 /* remote control browse channel open */
+#define BTA_AV_RC_BROWSE_CLOSE_EVT   11 /* remote control browse channel closed */
+#define BTA_AV_REMOTE_CMD_EVT        12 /* remote control command */
+#define BTA_AV_REMOTE_RSP_EVT        13 /* remote control response */
+#define BTA_AV_VENDOR_CMD_EVT        14 /* vendor dependent remote control command */
+#define BTA_AV_VENDOR_RSP_EVT        15 /* vendor dependent remote control response */
+#define BTA_AV_RECONFIG_EVT          16 /* reconfigure response */
+#define BTA_AV_SUSPEND_EVT           17 /* suspend response */
+#define BTA_AV_PENDING_EVT           18 /* incoming connection pending:
+                                        * signal channel is open and stream is
+                                        * not open after
+                                        * BTA_AV_SIGNALLING_TIMEOUT_MS */
+#define BTA_AV_META_MSG_EVT          19 /* metadata messages */
+#define BTA_AV_REJECT_EVT            20 /* incoming connection rejected */
+#define BTA_AV_RC_FEAT_EVT           21 /* remote control channel peer supported features update */
+#define BTA_AV_SINK_MEDIA_CFG_EVT    22 /* command to configure sink codec */
+#define BTA_AV_SINK_MEDIA_DATA_EVT   23 /* sending sink data to Media Task */
+#define BTA_AV_OFFLOAD_START_RSP_EVT 24 /* a2dp offload start response */
 /* Max BTA event */
-#define BTA_AV_MAX_EVT          23
+#define BTA_AV_MAX_EVT               25
 
 
 typedef uint8_t tBTA_AV_EVT;
@@ -305,8 +307,8 @@ typedef struct
 {
     tBTA_AV_CHNL    chnl;
     tBTA_AV_HNDL    hndl;
-    uint8_t           *p_data;
-    uint16_t          len;
+    uint8_t         *p_data;
+    uint16_t        len;
 } tBTA_AV_PROTECT_REQ;
 
 /* data associated with BTA_AV_PROTECT_RSP_EVT */
@@ -314,15 +316,15 @@ typedef struct
 {
     tBTA_AV_CHNL    chnl;
     tBTA_AV_HNDL    hndl;
-    uint8_t           *p_data;
-    uint16_t          len;
+    uint8_t         *p_data;
+    uint16_t        len;
     tBTA_AV_ERR     err_code;
 } tBTA_AV_PROTECT_RSP;
 
 /* data associated with BTA_AV_RC_OPEN_EVT */
 typedef struct
 {
-    uint8_t           rc_handle;
+    uint8_t         rc_handle;
     tBTA_AV_FEAT    peer_features;
     BD_ADDR         peer_addr;
     tBTA_AV_STATUS  status;
@@ -331,10 +333,25 @@ typedef struct
 /* data associated with BTA_AV_RC_CLOSE_EVT */
 typedef struct
 {
-    uint8_t           rc_handle;
+    uint8_t         rc_handle;
     BD_ADDR         peer_addr;
 } tBTA_AV_RC_CLOSE;
 
+/* data associated with BTA_AV_RC_BROWSE_OPEN_EVT */
+typedef struct
+{
+    uint8_t             rc_handle;
+    BD_ADDR             peer_addr;
+    tBTA_AV_STATUS      status;
+} tBTA_AV_RC_BROWSE_OPEN;
+
+/* data associated with BTA_AV_RC_BROWSE_CLOSE_EVT */
+typedef struct
+{
+    uint8_t             rc_handle;
+    BD_ADDR             peer_addr;
+} tBTA_AV_RC_BROWSE_CLOSE;
+
 /* data associated with BTA_AV_RC_FEAT_EVT */
 typedef struct
 {
@@ -417,6 +434,8 @@ typedef union
     tBTA_AV_PROTECT_RSP protect_rsp;
     tBTA_AV_RC_OPEN     rc_open;
     tBTA_AV_RC_CLOSE    rc_close;
+    tBTA_AV_RC_BROWSE_OPEN  rc_browse_open;
+    tBTA_AV_RC_BROWSE_CLOSE rc_browse_close;
     tBTA_AV_REMOTE_CMD  remote_cmd;
     tBTA_AV_REMOTE_RSP  remote_rsp;
     tBTA_AV_VENDOR      vendor_cmd;
index d41b77d..06429d1 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2009-2012 Broadcom Corporation
+ *  Copyright (C) 2009-2016 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -26,6 +26,7 @@
 #include <system/audio.h>
 #include <hardware/bluetooth.h>
 #include <hardware/bt_av.h>
+#include <hardware/bt_rc.h>
 
 #include "bt_utils.h"
 #include "bta_api.h"
@@ -113,6 +114,8 @@ else\
 #define CHECK_RC_EVENT(e, d) \
     case BTA_AV_RC_OPEN_EVT: \
     case BTA_AV_RC_CLOSE_EVT: \
+    case BTA_AV_RC_BROWSE_OPEN_EVT: \
+    case BTA_AV_RC_BROWSE_CLOSE_EVT: \
     case BTA_AV_REMOTE_CMD_EVT: \
     case BTA_AV_VENDOR_CMD_EVT: \
     case BTA_AV_META_MSG_EVT: \
@@ -144,7 +147,7 @@ static void btif_av_event_free_data(btif_sm_event_t event, void *p_data);
 *************************************************************************/
 extern void btif_rc_handler(tBTA_AV_EVT event, tBTA_AV *p_data);
 extern bool btif_rc_get_connected_peer(BD_ADDR peer_addr);
-extern uint8_t btif_rc_get_connected_peer_handle(void);
+extern uint8_t btif_rc_get_connected_peer_handle(BD_ADDR peer_addr);
 extern void btif_rc_check_handle_pending_play (BD_ADDR peer_addr, bool bSendToApp);
 
 extern fixed_queue_t *btu_general_alarm_queue;
@@ -180,6 +183,8 @@ const char *dump_av_sm_event_name(btif_av_sm_event_t event)
         CASE_RETURN_STR(BTA_AV_PROTECT_RSP_EVT)
         CASE_RETURN_STR(BTA_AV_RC_OPEN_EVT)
         CASE_RETURN_STR(BTA_AV_RC_CLOSE_EVT)
+        CASE_RETURN_STR(BTA_AV_RC_BROWSE_OPEN_EVT)
+        CASE_RETURN_STR(BTA_AV_RC_BROWSE_CLOSE_EVT)
         CASE_RETURN_STR(BTA_AV_REMOTE_CMD_EVT)
         CASE_RETURN_STR(BTA_AV_REMOTE_RSP_EVT)
         CASE_RETURN_STR(BTA_AV_VENDOR_CMD_EVT)
@@ -369,6 +374,11 @@ static bool btif_av_state_idle_handler(btif_sm_event_t event, void *p_data)
             btif_rc_handler(event, (tBTA_AV*)p_data);
             break;
 
+       case BTA_AV_RC_BROWSE_OPEN_EVT:
+           BTIF_TRACE_DEBUG("BTA_AV_RC_BROWSE_OPEN_EVT received");
+           btif_rc_handler(event, (tBTA_AV*)p_data);
+           break;
+
            /*
             * In case Signalling channel is not down
             * and remote started Streaming Procedure
@@ -516,6 +526,7 @@ static bool btif_av_state_opening_handler(btif_sm_event_t event, void *p_data)
                 BTIF_TRACE_WARNING("BTA_AV_OPEN_EVT::FAILED status: %d",
                                      p_bta_data->open.status );
                 BD_ADDR peer_addr;
+                uint8_t peer_handle = BTRC_HANDLE_NONE;
                 if ((btif_rc_get_connected_peer(peer_addr))
                     &&(!bdcmp(btif_av_cb.peer_bda.address, peer_addr)))
                 {
@@ -524,7 +535,10 @@ static bool btif_av_state_opening_handler(btif_sm_event_t event, void *p_data)
                      * A2DP conneciton failed, for any reason
                      */
                     BTIF_TRACE_WARNING(" Disconnecting AVRCP ");
-                    BTA_AvCloseRc(btif_rc_get_connected_peer_handle());
+                    peer_handle = btif_rc_get_connected_peer_handle(peer_addr);
+                    if (peer_handle != BTRC_HANDLE_NONE) {
+                        BTA_AvCloseRc(peer_handle);
+                    }
                 }
                 state = BTAV_CONNECTION_STATE_DISCONNECTED;
                 av_state  = BTIF_AV_STATE_IDLE;
@@ -680,6 +694,11 @@ static bool btif_av_state_closing_handler(btif_sm_event_t event, void *p_data)
             btif_rc_handler(event, (tBTA_AV*)p_data);
             break;
 
+        /* Handle the RC_BROWSE_CLOSE event for tetsing*/
+        case BTA_AV_RC_BROWSE_CLOSE_EVT:
+            btif_rc_handler(event, (tBTA_AV*)p_data);
+            break;
+
         case BTIF_AV_OFFLOAD_START_REQ_EVT:
             btif_a2dp_on_offload_started(BTA_AV_FAIL);
             BTIF_TRACE_ERROR("BTIF_AV_OFFLOAD_START_REQ_EVT: Stream not Started Closing");
@@ -1086,14 +1105,17 @@ void btif_av_event_deep_copy(uint16_t event, char *p_dest, char *p_src)
                 memcpy(av_dest->meta_msg.p_msg, av_src->meta_msg.p_msg,
                        sizeof(tAVRC_MSG));
 
-                if (av_src->meta_msg.p_msg->vendor.p_vendor_data &&
-                    av_src->meta_msg.p_msg->vendor.vendor_len)
-                {
-                    av_dest->meta_msg.p_msg->vendor.p_vendor_data = (uint8_t *)osi_calloc(
-                        av_src->meta_msg.p_msg->vendor.vendor_len);
-                    memcpy(av_dest->meta_msg.p_msg->vendor.p_vendor_data,
-                        av_src->meta_msg.p_msg->vendor.p_vendor_data,
-                        av_src->meta_msg.p_msg->vendor.vendor_len);
+                tAVRC_MSG *p_msg_src = av_src->meta_msg.p_msg;
+                tAVRC_MSG *p_msg_dest = av_dest->meta_msg.p_msg;
+
+                if ((p_msg_src->hdr.opcode == AVRC_OP_VENDOR) &&
+                        (p_msg_src->vendor.p_vendor_data &&
+                         p_msg_src->vendor.vendor_len)) {
+                    p_msg_dest->vendor.p_vendor_data = (uint8_t *)osi_calloc(
+                        p_msg_src->vendor.vendor_len);
+                    memcpy(p_msg_dest->vendor.p_vendor_data,
+                        p_msg_src->vendor.p_vendor_data,
+                        p_msg_src->vendor.vendor_len);
                 }
             }
             break;
@@ -1113,7 +1135,9 @@ static void btif_av_event_free_data(btif_sm_event_t event, void *p_data)
                 osi_free_and_reset((void **)&av->meta_msg.p_data);
 
                 if (av->meta_msg.p_msg) {
-                    osi_free(av->meta_msg.p_msg->vendor.p_vendor_data);
+                    if (av->meta_msg.p_msg->hdr.opcode == AVRC_OP_VENDOR) {
+                        osi_free(av->meta_msg.p_msg->vendor.p_vendor_data);
+                    }
                     osi_free_and_reset((void **)&av->meta_msg.p_msg);
                 }
             }
@@ -1541,6 +1565,7 @@ bt_status_t btif_av_execute_service(bool b_enable)
 #if (AVRC_ADV_CTRL_INCLUDED == TRUE)
              |BTA_AV_FEAT_RCCT
              |BTA_AV_FEAT_ADV_CTRL
+             |BTA_AV_FEAT_BROWSE
 #endif
              ,bte_av_callback);
 #else
index 6a6c93e..051f1ab 100644 (file)
 /* for AVRC 1.4 need to change this */
 #define MAX_RC_NOTIFICATIONS AVRC_EVT_VOLUME_CHANGE
 
-#define IDX_GET_PLAY_STATUS_RSP   0
-#define IDX_LIST_APP_ATTR_RSP     1
-#define IDX_LIST_APP_VALUE_RSP    2
-#define IDX_GET_CURR_APP_VAL_RSP  3
-#define IDX_SET_APP_VAL_RSP       4
-#define IDX_GET_APP_ATTR_TXT_RSP  5
-#define IDX_GET_APP_VAL_TXT_RSP   6
-#define IDX_GET_ELEMENT_ATTR_RSP  7
+#define IDX_GET_PLAY_STATUS_RSP         0
+#define IDX_LIST_APP_ATTR_RSP           1
+#define IDX_LIST_APP_VALUE_RSP          2
+#define IDX_GET_CURR_APP_VAL_RSP        3
+#define IDX_SET_APP_VAL_RSP             4
+#define IDX_GET_APP_ATTR_TXT_RSP        5
+#define IDX_GET_APP_VAL_TXT_RSP         6
+#define IDX_GET_ELEMENT_ATTR_RSP        7
+#define IDX_SET_ADDR_PLAYER_RSP         8
+#define IDX_SET_BROWSED_PLAYER_RSP      9
+#define IDX_GET_FOLDER_ITEMS_RSP        10
+#define IDX_CHG_PATH_RSP                11
+#define IDX_GET_ITEM_ATTR_RSP           12
+#define IDX_PLAY_ITEM_RSP               13
+#define IDX_GET_TOTAL_NUM_OF_ITEMS_RSP  14
+#define IDX_SEARCH_RSP                  15
+#define IDX_ADD_TO_NOW_PLAYING_RSP      16
+
+/* Update MAX value whenever IDX will be changed */
+#define MAX_CMD_QUEUE_LEN               17
+
 #define MAX_VOLUME 128
 #define MAX_LABEL 16
 #define MAX_TRANSACTIONS_PER_SESSION 16
-#define MAX_CMD_QUEUE_LEN 8
 #define PLAY_STATUS_PLAYING 1
-
-#define CHECK_RC_CONNECTED                                                                  \
-    BTIF_TRACE_DEBUG("## %s ##", __func__);                                            \
-    if (btif_rc_cb.rc_connected == false)                                                    \
-    {                                                                                       \
-        BTIF_TRACE_WARNING("Function %s() called when RC is not connected", __func__); \
-        return BT_STATUS_NOT_READY;                                                         \
+#define BTIF_RC_NUM_CONN  BT_RC_NUM_APP
+
+#define CHECK_RC_CONNECTED(p_dev)                                                      \
+    BTIF_TRACE_DEBUG("%s: ", __func__);                                            \
+    if (p_dev == NULL || p_dev->rc_connected == false)                                 \
+    {                                                                                  \
+        BTIF_TRACE_WARNING("%s: called when RC is not connected", __func__); \
+        return BT_STATUS_NOT_READY;                                                    \
     }
 
-#define FILL_PDU_QUEUE(index, ctype, label, pending)        \
-{                                                           \
-    btif_rc_cb.rc_pdu_info[index].ctype = ctype;            \
-    btif_rc_cb.rc_pdu_info[index].label = label;            \
-    btif_rc_cb.rc_pdu_info[index].is_rsp_pending = pending; \
-}
-
-#define SEND_METAMSG_RSP(index, avrc_rsp)                                                      \
-{                                                                                              \
-    if (btif_rc_cb.rc_pdu_info[index].is_rsp_pending == false)                                  \
-    {                                                                                          \
-        BTIF_TRACE_WARNING("%s Not sending response as no PDU was registered", __func__); \
-        return BT_STATUS_UNHANDLED;                                                            \
-    }                                                                                          \
-    send_metamsg_rsp(btif_rc_cb.rc_handle, btif_rc_cb.rc_pdu_info[index].label,                \
-        btif_rc_cb.rc_pdu_info[index].ctype, avrc_rsp);                                        \
-    btif_rc_cb.rc_pdu_info[index].ctype = 0;                                                   \
-    btif_rc_cb.rc_pdu_info[index].label = 0;                                                   \
-    btif_rc_cb.rc_pdu_info[index].is_rsp_pending = false;                                      \
-}
-
 /*****************************************************************************
 **  Local type definitions
 ******************************************************************************/
@@ -113,7 +105,7 @@ typedef struct
 {
     uint8_t   label;
     uint8_t   ctype;
-    bool is_rsp_pending;
+    bool      is_rsp_pending;
 } btif_rc_cmd_ctxt_t;
 
 /* 2 second timeout to get interim response */
@@ -132,7 +124,7 @@ typedef enum
 typedef struct {
     uint8_t                       event_id;
     uint8_t                       label;
-    btif_rc_nfn_reg_status_t    status;
+    btif_rc_nfn_reg_status_t      status;
 } btif_rc_supported_event_t;
 
 #define BTIF_RC_STS_TIMEOUT     0xFE
@@ -148,13 +140,14 @@ typedef struct {
 
 typedef struct {
     union {
-        btif_rc_status_cmd_timer_t rc_status_cmd;
+        btif_rc_status_cmd_timer_t  rc_status_cmd;
         btif_rc_control_cmd_timer_t rc_control_cmd;
     };
+    BD_ADDR rc_addr;
 } btif_rc_timer_context_t;
 
 typedef struct {
-    bool  query_started;
+    bool    query_started;
     uint8_t num_attrs;
     uint8_t num_ext_attrs;
 
@@ -167,37 +160,49 @@ typedef struct {
 
 /* TODO : Merge btif_rc_reg_notifications_t and btif_rc_cmd_ctxt_t to a single struct */
 typedef struct {
-    bool                     rc_connected;
-    uint8_t                       rc_handle;
-    tBTA_AV_FEAT                rc_features;
-    BD_ADDR                     rc_addr;
-    uint16_t                      rc_pending_play;
-    btif_rc_cmd_ctxt_t          rc_pdu_info[MAX_CMD_QUEUE_LEN];
-    btif_rc_reg_notifications_t rc_notif[MAX_RC_NOTIFICATIONS];
-    unsigned int                rc_volume;
-    uint8_t                     rc_vol_label;
-    list_t                      *rc_supported_event_list;
-    btif_rc_player_app_settings_t   rc_app_settings;
-    alarm_t                     *rc_play_status_timer;
-    bool                     rc_features_processed;
-    uint64_t                      rc_playing_uid;
-    bool                     rc_procedure_complete;
-} btif_rc_cb_t;
+    bool                           rc_connected;
+    uint8_t                        rc_handle;
+    tBTA_AV_FEAT                   rc_features;
+    btrc_connection_state_t        rc_state;
+    BD_ADDR                        rc_addr;
+    uint16_t                       rc_pending_play;
+    btif_rc_cmd_ctxt_t             rc_pdu_info[MAX_CMD_QUEUE_LEN];
+    btif_rc_reg_notifications_t    rc_notif[MAX_RC_NOTIFICATIONS];
+    unsigned int                   rc_volume;
+    uint8_t                        rc_vol_label;
+    list_t                         *rc_supported_event_list;
+    btif_rc_player_app_settings_t  rc_app_settings;
+    alarm_t                        *rc_play_status_timer;
+    bool                           rc_features_processed;
+    uint64_t                       rc_playing_uid;
+    bool                           rc_procedure_complete;
+} btif_rc_device_cb_t;
+
+typedef struct {
+    pthread_mutex_t     lock;
+    btif_rc_device_cb_t rc_multi_cb[BTIF_RC_NUM_CONN];
+} rc_cb_t;
 
 typedef struct {
-    bool in_use;
-    uint8_t lbl;
-    uint8_t handle;
+    bool                    in_use;
+    uint8_t                 lbl;
+    uint8_t                 handle;
     btif_rc_timer_context_t txn_timer_context;
-    alarm_t *txn_timer;
+    alarm_t                 *txn_timer;
 } rc_transaction_t;
 
 typedef struct
 {
-    pthread_mutex_t lbllock;
+    pthread_mutex_t  lbllock;
     rc_transaction_t transaction[MAX_TRANSACTIONS_PER_SESSION];
 } rc_device_t;
 
+typedef struct
+{
+    uint8_t       label;
+    BD_ADDR       rc_addr;
+} rc_context_t;
+
 rc_device_t device;
 
 #define MAX_UINPUT_PATHS 3
@@ -205,8 +210,6 @@ static const char* uinput_dev_path[] =
                        {"/dev/uinput", "/dev/input/uinput", "/dev/misc/uinput" };
 static int uinput_fd = -1;
 
-static int  send_event (int fd, uint16_t type, uint16_t code, int32_t value);
-static void send_key (int fd, uint16_t key, int pressed);
 static int  uinput_driver_check();
 static int  uinput_create(const char *name);
 static int  init_uinput (void);
@@ -229,13 +232,45 @@ static const struct {
     { NULL,           0,                0,                0 }
 };
 
+/* Response status code - Unknown Error - this is changed to "reserved" */
+#define BTIF_STS_GEN_ERROR      0x06
+
+/* Utility table to map hal status codes to bta status codes for the response status */
+static const uint8_t status_code_map[] =
+{
+    /* BTA_Status codes        HAL_Status codes */
+    AVRC_STS_BAD_CMD,          /* BTRC_STS_BAD_CMD */
+    AVRC_STS_BAD_PARAM,        /* BTRC_STS_BAD_PARAM */
+    AVRC_STS_NOT_FOUND,        /* BTRC_STS_NOT_FOUND */
+    AVRC_STS_INTERNAL_ERR,     /* BTRC_STS_INTERNAL_ERR */
+    AVRC_STS_NO_ERROR,         /* BTRC_STS_NO_ERROR */
+    AVRC_STS_UID_CHANGED,      /* BTRC_STS_UID_CHANGED */
+    BTIF_STS_GEN_ERROR,        /* BTRC_STS_RESERVED */
+    AVRC_STS_BAD_DIR,          /* BTRC_STS_INV_DIRN */
+    AVRC_STS_NOT_DIR,          /* BTRC_STS_INV_DIRECTORY */
+    AVRC_STS_NOT_EXIST,        /* BTRC_STS_INV_ITEM */
+    AVRC_STS_BAD_SCOPE,        /* BTRC_STS_INV_SCOPE */
+    AVRC_STS_BAD_RANGE,        /* BTRC_STS_INV_RANGE */
+    AVRC_STS_UID_IS_DIR,       /* BTRC_STS_DIRECTORY */
+    AVRC_STS_IN_USE,           /* BTRC_STS_MEDIA_IN_USE */
+    AVRC_STS_NOW_LIST_FULL,    /* BTRC_STS_PLAY_LIST_FULL */
+    AVRC_STS_SEARCH_NOT_SUP,   /* BTRC_STS_SRCH_NOT_SPRTD */
+    AVRC_STS_SEARCH_BUSY,      /* BTRC_STS_SRCH_IN_PROG */
+    AVRC_STS_BAD_PLAYER_ID,    /* BTRC_STS_INV_PLAYER */
+    AVRC_STS_PLAYER_N_BR,      /* BTRC_STS_PLAY_NOT_BROW */
+    AVRC_STS_PLAYER_N_ADDR,    /* BTRC_STS_PLAY_NOT_ADDR */
+    AVRC_STS_BAD_SEARCH_RES,   /* BTRC_STS_INV_RESULTS */
+    AVRC_STS_NO_AVAL_PLAYER,   /* BTRC_STS_NO_AVBL_PLAY */
+    AVRC_STS_ADDR_PLAYER_CHG,  /* BTRC_STS_ADDR_PLAY_CHGD */
+};
+
 static void send_reject_response (uint8_t rc_handle, uint8_t label,
-    uint8_t pdu, uint8_t status);
+    uint8_t pdu, uint8_t status, uint8_t opcode);
 static uint8_t opcode_from_pdu(uint8_t pdu);
-static void send_metamsg_rsp (uint8_t rc_handle, uint8_t label,
+static void send_metamsg_rsp (btif_rc_device_cb_t *p_dev, int index, uint8_t label,
     tBTA_AV_CODE code, tAVRC_RESPONSE *pmetamsg_resp);
 #if (AVRC_ADV_CTRL_INCLUDED == TRUE)
-static void register_volumechange(uint8_t label);
+static void register_volumechange(uint8_t label, btif_rc_device_cb_t *p_dev);
 #endif
 static void lbl_init();
 static void lbl_destroy();
@@ -244,47 +279,63 @@ static bt_status_t  get_transaction(rc_transaction_t **ptransaction);
 static void release_transaction(uint8_t label);
 static rc_transaction_t* get_transaction_by_lbl(uint8_t label);
 #if (AVRC_ADV_CTRL_INCLUDED == TRUE)
-static void handle_rc_metamsg_rsp(tBTA_AV_META_MSG *pmeta_msg);
+static void handle_rc_metamsg_rsp(tBTA_AV_META_MSG *pmeta_msg, btif_rc_device_cb_t *p_dev);
 #endif
 #if (AVRC_CTRL_INCLUDED == TRUE)
 static void handle_avk_rc_metamsg_cmd(tBTA_AV_META_MSG *pmeta_msg);
 static void handle_avk_rc_metamsg_rsp(tBTA_AV_META_MSG *pmeta_msg);
 static void btif_rc_ctrl_upstreams_rsp_cmd(
-    uint8_t event, tAVRC_COMMAND *pavrc_cmd, uint8_t label);
-static void rc_ctrl_procedure_complete();
-static void rc_stop_play_status_timer();
-static void register_for_event_notification (btif_rc_supported_event_t *p_event);
-static void handle_get_capability_response (tBTA_AV_META_MSG *pmeta_msg, tAVRC_GET_CAPS_RSP *p_rsp);
+    uint8_t event, tAVRC_COMMAND *pavrc_cmd, uint8_t label, btif_rc_device_cb_t *p_dev);
+static void rc_ctrl_procedure_complete(btif_rc_device_cb_t *p_dev);
+static void rc_stop_play_status_timer(btif_rc_device_cb_t *p_dev);
+static void register_for_event_notification (btif_rc_supported_event_t *p_event,
+    btif_rc_device_cb_t *p_dev);
+static void handle_get_capability_response (tBTA_AV_META_MSG *pmeta_msg,
+    tAVRC_GET_CAPS_RSP *p_rsp);
 static void handle_app_attr_response (tBTA_AV_META_MSG *pmeta_msg, tAVRC_LIST_APP_ATTR_RSP *p_rsp);
-static void handle_app_val_response (tBTA_AV_META_MSG *pmeta_msg, tAVRC_LIST_APP_VALUES_RSP *p_rsp);
-static void handle_app_cur_val_response (tBTA_AV_META_MSG *pmeta_msg, tAVRC_GET_CUR_APP_VALUE_RSP *p_rsp);
-static void handle_app_attr_txt_response (tBTA_AV_META_MSG *pmeta_msg, tAVRC_GET_APP_ATTR_TXT_RSP *p_rsp);
-static void handle_app_attr_val_txt_response (tBTA_AV_META_MSG *pmeta_msg, tAVRC_GET_APP_ATTR_TXT_RSP *p_rsp);
-static void handle_get_playstatus_response (tBTA_AV_META_MSG *pmeta_msg, tAVRC_GET_PLAY_STATUS_RSP *p_rsp);
-static void handle_get_elem_attr_response (tBTA_AV_META_MSG *pmeta_msg, tAVRC_GET_ELEM_ATTRS_RSP *p_rsp);
+static void handle_app_val_response (tBTA_AV_META_MSG *pmeta_msg,
+    tAVRC_LIST_APP_VALUES_RSP *p_rsp);
+static void handle_app_cur_val_response (tBTA_AV_META_MSG *pmeta_msg,
+    tAVRC_GET_CUR_APP_VALUE_RSP *p_rsp);
+static void handle_app_attr_txt_response (tBTA_AV_META_MSG *pmeta_msg,
+    tAVRC_GET_APP_ATTR_TXT_RSP *p_rsp);
+static void handle_app_attr_val_txt_response (tBTA_AV_META_MSG *pmeta_msg,
+    tAVRC_GET_APP_ATTR_TXT_RSP *p_rsp);
+static void handle_get_playstatus_response (tBTA_AV_META_MSG *pmeta_msg,
+    tAVRC_GET_PLAY_STATUS_RSP *p_rsp);
+static void handle_get_elem_attr_response (tBTA_AV_META_MSG *pmeta_msg,
+    tAVRC_GET_ELEM_ATTRS_RSP *p_rsp);
 static void handle_set_app_attr_val_response (tBTA_AV_META_MSG *pmeta_msg, tAVRC_RSP *p_rsp);
-static bt_status_t get_play_status_cmd(void);
-static bt_status_t get_player_app_setting_attr_text_cmd (uint8_t *attrs, uint8_t num_attrs);
-static bt_status_t get_player_app_setting_value_text_cmd (uint8_t *vals, uint8_t num_vals);
-static bt_status_t register_notification_cmd (uint8_t label, uint8_t event_id, uint32_t event_value);
-static bt_status_t get_element_attribute_cmd (uint8_t num_attribute, uint32_t *p_attr_ids);
-static bt_status_t getcapabilities_cmd (uint8_t cap_id);
-static bt_status_t list_player_app_setting_attrib_cmd(void);
-static bt_status_t list_player_app_setting_value_cmd(uint8_t attrib_id);
-static bt_status_t get_player_app_setting_cmd(uint8_t num_attrib, uint8_t* attrib_ids);
+static bt_status_t get_play_status_cmd(btif_rc_device_cb_t *p_dev);
+static bt_status_t get_player_app_setting_attr_text_cmd (uint8_t *attrs, uint8_t num_attrs,
+    btif_rc_device_cb_t *p_dev);
+static bt_status_t get_player_app_setting_value_text_cmd (uint8_t *vals, uint8_t num_vals,
+    btif_rc_device_cb_t *p_dev);
+static bt_status_t register_notification_cmd (uint8_t label, uint8_t event_id, uint32_t event_value,
+    btif_rc_device_cb_t *p_dev);
+static bt_status_t get_element_attribute_cmd (uint8_t num_attribute, uint32_t *p_attr_ids,
+    btif_rc_device_cb_t *p_dev);
+static bt_status_t getcapabilities_cmd (uint8_t cap_id, btif_rc_device_cb_t *p_dev);
+static bt_status_t list_player_app_setting_attrib_cmd(btif_rc_device_cb_t *p_dev);
+static bt_status_t list_player_app_setting_value_cmd(uint8_t attrib_id,
+    btif_rc_device_cb_t *p_dev);
+static bt_status_t get_player_app_setting_cmd(uint8_t num_attrib, uint8_t* attrib_ids,
+    btif_rc_device_cb_t *p_dev);
 #endif
-static void btif_rc_upstreams_evt(uint16_t event, tAVRC_COMMAND* p_param, uint8_t ctype, uint8_t label);
+
+static void btif_rc_upstreams_evt(uint16_t event, tAVRC_COMMAND* p_param, uint8_t ctype, uint8_t label,
+    btif_rc_device_cb_t *p_dev);
 #if (AVRC_ADV_CTRL_INCLUDED == TRUE)
-static void btif_rc_upstreams_rsp_evt(uint16_t event, tAVRC_RESPONSE *pavrc_resp, uint8_t ctype, uint8_t label);
+static void btif_rc_upstreams_rsp_evt(uint16_t event, tAVRC_RESPONSE *pavrc_resp, uint8_t ctype,
+    uint8_t label, btif_rc_device_cb_t *p_dev);
 #endif
-static void rc_start_play_status_timer(void);
+static void rc_start_play_status_timer(btif_rc_device_cb_t *p_dev);
 static bool absolute_volume_disabled(void);
-static char const* key_id_to_str(uint16_t id);
 
 /*****************************************************************************
 **  Static variables
 ******************************************************************************/
-static btif_rc_cb_t btif_rc_cb;
+static rc_cb_t  btif_rc_cb;
 static btrc_callbacks_t *bt_rc_callbacks = NULL;
 static btrc_ctrl_callbacks_t *bt_rc_ctrl_callbacks = NULL;
 
@@ -303,40 +354,105 @@ extern fixed_queue_t *btu_general_alarm_queue;
 /*****************************************************************************
 **  Functions
 ******************************************************************************/
-
-/*****************************************************************************
-**   Local uinput helper functions
-******************************************************************************/
-int send_event (int fd, uint16_t type, uint16_t code, int32_t value)
+static btif_rc_device_cb_t *alloc_device()
 {
-    struct uinput_event event;
-    BTIF_TRACE_DEBUG("%s type:%u code:%u value:%d", __func__,
-        type, code, value);
-    memset(&event, 0, sizeof(event));
-    event.type  = type;
-    event.code  = code;
-    event.value = value;
+    for (int idx = 0; idx < BTIF_RC_NUM_CONN; idx++) {
+        if (btif_rc_cb.rc_multi_cb[idx].rc_state == BTRC_CONNECTION_STATE_DISCONNECTED) {
+            return (&btif_rc_cb.rc_multi_cb[idx]);
+        }
+    }
+    return NULL;
+}
 
-    ssize_t ret;
-    OSI_NO_INTR(ret = write(fd, &event, sizeof(event)));
-    return (int)ret;
+static btif_rc_device_cb_t *get_connected_device(int index)
+{
+    BTIF_TRACE_DEBUG("%s: index: %d", __func__, index);
+    if (index > BTIF_RC_NUM_CONN) {
+        BTIF_TRACE_ERROR("%s: can't support more than %d connections", __func__, BTIF_RC_NUM_CONN);
+        return NULL;
+    }
+    if (btif_rc_cb.rc_multi_cb[index].rc_state != BTRC_CONNECTION_STATE_CONNECTED) {
+        BTIF_TRACE_ERROR("%s: returning NULL", __func__);
+        return NULL;
+    }
+    return (&btif_rc_cb.rc_multi_cb[index]);
 }
 
-void send_key (int fd, uint16_t key, int pressed)
+static int get_num_connected_devices()
+{
+    int connected_devices = 0;
+    for (int idx = 0; idx < BTIF_RC_NUM_CONN; idx++)
+    {
+        if (btif_rc_cb.rc_multi_cb[idx].rc_state == BTRC_CONNECTION_STATE_CONNECTED)
+        {
+            connected_devices++;
+        }
+    }
+    BTIF_TRACE_DEBUG("%s: returning connected_devices: %d", __func__, connected_devices);
+    return connected_devices;
+}
+btif_rc_device_cb_t *btif_rc_get_device_by_bda(bt_bdaddr_t *bd_addr)
 {
-    BTIF_TRACE_DEBUG("%s fd:%d key:%u pressed:%d", __func__,
-        fd, key, pressed);
+    BTIF_TRACE_DEBUG("%s: bd_addr: %02x-%02x-%02x-%02x-%02x-%02x", __func__,
+            bd_addr[0], bd_addr[1],bd_addr[2], bd_addr[3], bd_addr[4], bd_addr[5]);
 
-    if (fd < 0)
+    for (int idx = 0; idx < BTIF_RC_NUM_CONN; idx++)
     {
-        return;
+        if ((btif_rc_cb.rc_multi_cb[idx].rc_state != BTRC_CONNECTION_STATE_DISCONNECTED) &&
+             (bdcmp(btif_rc_cb.rc_multi_cb[idx].rc_addr, bd_addr->address) == 0))
+        {
+            return (&btif_rc_cb.rc_multi_cb[idx]);
+        }
+    }
+    BTIF_TRACE_ERROR("%s: device not found, returning NULL!", __func__);
+    return NULL;
+}
+
+btif_rc_device_cb_t *btif_rc_get_device_by_handle(uint8_t handle)
+{
+    BTIF_TRACE_DEBUG("%s: handle: 0x%x", __func__, handle);
+    for (int idx = 0; idx < BTIF_RC_NUM_CONN; idx++)
+    {
+        if ((btif_rc_cb.rc_multi_cb[idx].rc_state != BTRC_CONNECTION_STATE_DISCONNECTED) &&
+             (btif_rc_cb.rc_multi_cb[idx].rc_handle == handle))
+        {
+            BTIF_TRACE_DEBUG("%s: btif_rc_cb.rc_multi_cb[idx].rc_handle: 0x%x",
+                    __func__, btif_rc_cb.rc_multi_cb[idx].rc_handle);
+            return (&btif_rc_cb.rc_multi_cb[idx]);
+        }
     }
+    BTIF_TRACE_ERROR("%s: returning NULL", __func__);
+    return NULL;
+}
+
+void fill_pdu_queue(int index, uint8_t ctype, uint8_t label, bool pending,
+         btif_rc_device_cb_t *p_dev)
+{
+    p_dev->rc_pdu_info[index].ctype = ctype;
+    p_dev->rc_pdu_info[index].label = label;
+    p_dev->rc_pdu_info[index].is_rsp_pending = pending;
+}
 
-    LOG_INFO(LOG_TAG, "AVRCP: Send key %s (%d) fd=%d", key_id_to_str(key), pressed, fd);
-    send_event(fd, EV_KEY, key, pressed);
-    send_event(fd, EV_SYN, SYN_REPORT, 0);
+void fill_avrc_attr_entry(tAVRC_ATTR_ENTRY *attr_vals, int num_attrs,
+        btrc_element_attr_val_t* p_attrs)
+{
+    for (int attr_cnt = 0; attr_cnt < num_attrs; attr_cnt++)
+    {
+        attr_vals[attr_cnt].attr_id =  p_attrs[attr_cnt].attr_id;
+        attr_vals[attr_cnt].name.charset_id = AVRC_CHARSET_ID_UTF8;
+        attr_vals[attr_cnt].name.str_len =
+                (uint16_t)strlen((char *)p_attrs[attr_cnt].text);
+        attr_vals[attr_cnt].name.p_str = p_attrs[attr_cnt].text;
+        BTIF_TRACE_DEBUG("%s: attr_id: 0x%x, charset_id: 0x%x, str_len: %d, str: %s",
+            __func__, (unsigned int)attr_vals[attr_cnt].attr_id,
+            attr_vals[attr_cnt].name.charset_id, attr_vals[attr_cnt].name.str_len,
+            attr_vals[attr_cnt].name.p_str);
+    }
 }
 
+/*****************************************************************************
+**   Local uinput helper functions
+******************************************************************************/
 /************** uinput related functions **************/
 int uinput_driver_check()
 {
@@ -347,7 +463,7 @@ int uinput_driver_check()
            return 0;
         }
     }
-    BTIF_TRACE_ERROR("%s ERROR: uinput device is not in the system", __func__);
+    BTIF_TRACE_ERROR("%s: ERROR: uinput device is not in the system", __func__);
     return -1;
 }
 
@@ -364,7 +480,7 @@ int uinput_create(const char *name)
         break;
     }
     if (x == MAX_UINPUT_PATHS) {
-        BTIF_TRACE_ERROR("%s ERROR: uinput device open failed", __func__);
+        BTIF_TRACE_ERROR("%s: ERROR: uinput device open failed", __func__);
         return -1;
     }
     memset(&dev, 0, sizeof(dev));
@@ -379,7 +495,7 @@ int uinput_create(const char *name)
     ssize_t ret;
     OSI_NO_INTR(ret = write(fd, &dev, sizeof(dev)));
     if (ret < 0) {
-        BTIF_TRACE_ERROR("%s Unable to write device information", __func__);
+        BTIF_TRACE_ERROR("%s: Unable to write device information", __func__);
         close(fd);
         return -1;
     }
@@ -392,7 +508,7 @@ int uinput_create(const char *name)
         ioctl(fd, UI_SET_KEYBIT, key_map[x].mapped_id);
 
     if (ioctl(fd, UI_DEV_CREATE, NULL) < 0) {
-        BTIF_TRACE_ERROR("%s Unable to create uinput device", __func__);
+        BTIF_TRACE_ERROR("%s: Unable to create uinput device", __func__);
         close(fd);
         return -1;
     }
@@ -403,13 +519,13 @@ int init_uinput (void)
 {
     const char *name = "AVRCP";
 
-    BTIF_TRACE_DEBUG("%s", __func__);
+    BTIF_TRACE_DEBUG("%s", __func__);
     uinput_fd = uinput_create(name);
     if (uinput_fd < 0) {
-        BTIF_TRACE_ERROR("%s AVRCP: Failed to initialize uinput for %s (%d)",
+        BTIF_TRACE_ERROR("%s: AVRCP: Failed to initialize uinput for %s (%d)",
                           __func__, name, uinput_fd);
     } else {
-        BTIF_TRACE_DEBUG("%s AVRCP: Initialized uinput for %s (fd=%d)",
+        BTIF_TRACE_DEBUG("%s: AVRCP: Initialized uinput for %s (fd: %d)",
                           __func__, name, uinput_fd);
     }
     return uinput_fd;
@@ -417,7 +533,7 @@ int init_uinput (void)
 
 void close_uinput (void)
 {
-    BTIF_TRACE_DEBUG("%s", __func__);
+    BTIF_TRACE_DEBUG("%s", __func__);
     if (uinput_fd > 0) {
         ioctl(uinput_fd, UI_DEV_DESTROY);
 
@@ -429,53 +545,59 @@ void close_uinput (void)
 #if (AVRC_CTRL_INCLUDED == TRUE)
 void rc_cleanup_sent_cmd (void *p_data)
 {
-    BTIF_TRACE_DEBUG("%s", __func__);
+    BTIF_TRACE_DEBUG("%s", __func__);
 
 }
 
-void handle_rc_ctrl_features(BD_ADDR bd_addr)
+void handle_rc_ctrl_features(btif_rc_device_cb_t *p_dev)
 {
-    if ((btif_rc_cb.rc_features & BTA_AV_FEAT_RCTG)||
-       ((btif_rc_cb.rc_features & BTA_AV_FEAT_RCCT)&&
-        (btif_rc_cb.rc_features & BTA_AV_FEAT_ADV_CTRL)))
+    if (!(p_dev->rc_features & BTA_AV_FEAT_RCTG) &&
+       (!(p_dev->rc_features & BTA_AV_FEAT_RCCT) ||
+        !(p_dev->rc_features & BTA_AV_FEAT_ADV_CTRL)))
     {
-        bt_bdaddr_t rc_addr;
-        int rc_features = 0;
-        bdcpy(rc_addr.address,bd_addr);
+        return;
+    }
 
-        if ((btif_rc_cb.rc_features & BTA_AV_FEAT_ADV_CTRL)&&
-             (btif_rc_cb.rc_features & BTA_AV_FEAT_RCCT))
-        {
-            rc_features |= BTRC_FEAT_ABSOLUTE_VOLUME;
-        }
-        if ((btif_rc_cb.rc_features & BTA_AV_FEAT_METADATA)&&
-            (btif_rc_cb.rc_features & BTA_AV_FEAT_VENDOR)&&
-            (btif_rc_cb.rc_features_processed != true))
-        {
-            rc_features |= BTRC_FEAT_METADATA;
-            /* Mark rc features processed to avoid repeating
-             * the AVRCP procedure every time on receiving this
-             * update.
-             */
-            btif_rc_cb.rc_features_processed = true;
+    bt_bdaddr_t rc_addr;
+    int rc_features = 0;
+    bdcpy(rc_addr.address, p_dev->rc_addr);
 
-            if (btif_av_is_sink_enabled())
-                getcapabilities_cmd (AVRC_CAP_COMPANY_ID);
-        }
-        BTIF_TRACE_DEBUG("%s Update rc features to CTRL %d", __func__, rc_features);
-        HAL_CBACK(bt_rc_ctrl_callbacks, getrcfeatures_cb, &rc_addr, rc_features);
+    if ((p_dev->rc_features & BTA_AV_FEAT_ADV_CTRL)&&
+         (p_dev->rc_features & BTA_AV_FEAT_RCCT))
+    {
+        rc_features |= BTRC_FEAT_ABSOLUTE_VOLUME;
+    }
+    if ((p_dev->rc_features & BTA_AV_FEAT_METADATA)&&
+        (p_dev->rc_features & BTA_AV_FEAT_VENDOR)&&
+        (p_dev->rc_features_processed != true))
+    {
+        rc_features |= BTRC_FEAT_METADATA;
+        /* Mark rc features processed to avoid repeating
+         * the AVRCP procedure every time on receiving this
+         * update.
+         */
+        p_dev->rc_features_processed = true;
+        if (btif_av_is_sink_enabled())
+            getcapabilities_cmd (AVRC_CAP_COMPANY_ID, p_dev);
     }
+    BTIF_TRACE_DEBUG("%s: Update rc features to CTRL: %d", __func__, rc_features);
+    HAL_CBACK(bt_rc_ctrl_callbacks, getrcfeatures_cb, &rc_addr, rc_features);
+
 }
 #endif
 
-void handle_rc_features(BD_ADDR bd_addr)
+void handle_rc_features(btif_rc_device_cb_t *p_dev)
 {
     if (bt_rc_callbacks != NULL)
     {
+        BTIF_TRACE_ERROR("%s: bt_rc_callbacks NULL, returning", __func__);
+        return;
+    }
+
     btrc_remote_features_t rc_features = BTRC_FEAT_NONE;
     bt_bdaddr_t rc_addr;
 
-    bdcpy(rc_addr.address, btif_rc_cb.rc_addr);
+    bdcpy(rc_addr.address, p_dev->rc_addr);
     bt_bdaddr_t avdtp_addr  = btif_av_get_addr();
 
     bdstr_t addr1, addr2;
@@ -486,63 +608,63 @@ void handle_rc_features(BD_ADDR bd_addr)
     if (interop_match_addr(INTEROP_DISABLE_ABSOLUTE_VOLUME, &rc_addr)
         || absolute_volume_disabled()
         || bdcmp(avdtp_addr.address, rc_addr.address))
-        btif_rc_cb.rc_features &= ~BTA_AV_FEAT_ADV_CTRL;
+    {
+        p_dev->rc_features &= ~BTA_AV_FEAT_ADV_CTRL;
+    }
 
-    if (btif_rc_cb.rc_features & BTA_AV_FEAT_BROWSE)
+    if (p_dev->rc_features & BTA_AV_FEAT_BROWSE)
     {
         rc_features = (btrc_remote_features_t)(rc_features | BTRC_FEAT_BROWSE);
     }
 
 #if (AVRC_ADV_CTRL_INCLUDED == TRUE)
-    if ( (btif_rc_cb.rc_features & BTA_AV_FEAT_ADV_CTRL) &&
-         (btif_rc_cb.rc_features & BTA_AV_FEAT_RCTG))
+    if ( (p_dev->rc_features & BTA_AV_FEAT_ADV_CTRL) &&
+         (p_dev->rc_features & BTA_AV_FEAT_RCTG))
     {
         rc_features = (btrc_remote_features_t)(rc_features | BTRC_FEAT_ABSOLUTE_VOLUME);
     }
 #endif
 
-    if (btif_rc_cb.rc_features & BTA_AV_FEAT_METADATA)
+    if (p_dev->rc_features & BTA_AV_FEAT_METADATA)
     {
         rc_features = (btrc_remote_features_t)(rc_features | BTRC_FEAT_METADATA);
     }
 
-    BTIF_TRACE_DEBUG("%s: rc_features=0x%x", __func__, rc_features);
+    BTIF_TRACE_DEBUG("%s: rc_features0x%x", __func__, rc_features);
     HAL_CBACK(bt_rc_callbacks, remote_features_cb, &rc_addr, rc_features)
 
 #if (AVRC_ADV_CTRL_INCLUDED == TRUE)
-     BTIF_TRACE_DEBUG("%s Checking for feature flags in btif_rc_handler with label %d",
-                        __func__, btif_rc_cb.rc_vol_label);
-     // Register for volume change on connect
-      if (btif_rc_cb.rc_features & BTA_AV_FEAT_ADV_CTRL &&
-         btif_rc_cb.rc_features & BTA_AV_FEAT_RCTG)
-      {
-         rc_transaction_t *p_transaction=NULL;
-         bt_status_t status = BT_STATUS_NOT_READY;
-         if (MAX_LABEL==btif_rc_cb.rc_vol_label)
-         {
-            status=get_transaction(&p_transaction);
-         }
-         else
-         {
-            p_transaction=get_transaction_by_lbl(btif_rc_cb.rc_vol_label);
+    BTIF_TRACE_DEBUG("%s: Checking for feature flags in btif_rc_handler with label: %d",
+                        __func__, p_dev->rc_vol_label);
+    // Register for volume change on connect
+    if (p_dev->rc_features & BTA_AV_FEAT_ADV_CTRL &&
+        p_dev->rc_features & BTA_AV_FEAT_RCTG)
+    {
+        rc_transaction_t *p_transaction = NULL;
+        bt_status_t status = BT_STATUS_NOT_READY;
+        if (MAX_LABEL == p_dev->rc_vol_label)
+        {
+            status = get_transaction(&p_transaction);
+        }
+        else
+        {
+            p_transaction=get_transaction_by_lbl(p_dev->rc_vol_label);
             if (NULL!=p_transaction)
             {
-               BTIF_TRACE_DEBUG("%s register_volumechange already in progress for label %d",
-                                  __func__, btif_rc_cb.rc_vol_label);
-               return;
+                BTIF_TRACE_DEBUG("%s: register_volumechange already in progress for label: %d",
+                                   __func__, p_dev->rc_vol_label);
+                return;
             }
             else
-              status=get_transaction(&p_transaction);
-         }
-
-         if (BT_STATUS_SUCCESS == status && NULL!=p_transaction)
-         {
-            btif_rc_cb.rc_vol_label=p_transaction->lbl;
-            register_volumechange(btif_rc_cb.rc_vol_label);
-         }
-       }
-#endif
+                status = get_transaction(&p_transaction);
+        }
+        if (BT_STATUS_SUCCESS == status && NULL != p_transaction)
+        {
+            p_dev->rc_vol_label = p_transaction->lbl;
+            register_volumechange(p_dev->rc_vol_label, p_dev);
+        }
     }
+#endif
 }
 
 /***************************************************************************
@@ -561,68 +683,71 @@ void handle_rc_connect (tBTA_AV_RC_OPEN *p_rc_open)
     bt_bdaddr_t rc_addr;
 #endif
 
-    if (p_rc_open->status == BTA_AV_SUCCESS)
+    btif_rc_device_cb_t *p_dev = alloc_device();
+    if ( p_dev == NULL )
     {
-        //check if already some RC is connected
-        if (btif_rc_cb.rc_connected)
-        {
-            BTIF_TRACE_ERROR("%s Got RC OPEN in connected state, Connected RC: %d \
-                and Current RC: %d", __func__, btif_rc_cb.rc_handle,p_rc_open->rc_handle );
-            if ((btif_rc_cb.rc_handle != p_rc_open->rc_handle)
-                && (bdcmp(btif_rc_cb.rc_addr, p_rc_open->peer_addr)))
-            {
-                BTIF_TRACE_DEBUG("%s Got RC connected for some other handle", __func__);
-                BTA_AvCloseRc(p_rc_open->rc_handle);
-                return;
-            }
-        }
-        memcpy(btif_rc_cb.rc_addr, p_rc_open->peer_addr, sizeof(BD_ADDR));
-        btif_rc_cb.rc_features = p_rc_open->peer_features;
-        btif_rc_cb.rc_vol_label=MAX_LABEL;
-        btif_rc_cb.rc_volume=MAX_VOLUME;
-
-        btif_rc_cb.rc_connected = true;
-        btif_rc_cb.rc_handle = p_rc_open->rc_handle;
-
-        /* on locally initiated connection we will get remote features as part of connect */
-        if (btif_rc_cb.rc_features != 0)
-            handle_rc_features(btif_rc_cb.rc_addr);
-        if (bt_rc_callbacks)
-        {
-            result = (bt_status_t)uinput_driver_check();
-            if (result == BT_STATUS_SUCCESS)
-            {
-                init_uinput();
-            }
-        }
-        else
-        {
-            BTIF_TRACE_WARNING("%s Avrcp TG role not enabled, not initializing UInput",
-                               __func__);
-        }
-        BTIF_TRACE_DEBUG("%s handle_rc_connect features %d ",__func__, btif_rc_cb.rc_features);
-#if (AVRC_CTRL_INCLUDED == TRUE)
-        btif_rc_cb.rc_playing_uid = RC_INVALID_TRACK_ID;
-        bdcpy(rc_addr.address, btif_rc_cb.rc_addr);
-        if (bt_rc_ctrl_callbacks != NULL)
+        BTIF_TRACE_ERROR("%s: p_dev is NULL", __func__);
+        return;
+    }
+
+    if (!(p_rc_open->status == BTA_AV_SUCCESS))
+    {
+        BTIF_TRACE_ERROR("%s: Connect failed with error code: %d",
+            __func__, p_rc_open->status);
+        p_dev->rc_connected = false;
+    }
+
+    //check if already some RC is connected
+    if (p_dev->rc_connected)
+    {
+        BTIF_TRACE_ERROR("%s: Got RC OPEN in connected state, Connected RC: %d \
+            and Current RC: %d", __func__, p_dev->rc_handle, p_rc_open->rc_handle );
+        if ((p_dev->rc_handle != p_rc_open->rc_handle)
+            && (bdcmp(p_dev->rc_addr, p_rc_open->peer_addr)))
         {
-            HAL_CBACK(bt_rc_ctrl_callbacks, connection_state_cb, true, &rc_addr);
+            BTIF_TRACE_DEBUG("%s: Got RC connected for some other handle", __func__);
+            BTA_AvCloseRc(p_rc_open->rc_handle);
+            return;
         }
-        /* report connection state if remote device is AVRCP target */
-        if ((btif_rc_cb.rc_features & BTA_AV_FEAT_RCTG)||
-           ((btif_rc_cb.rc_features & BTA_AV_FEAT_RCCT)&&
-            (btif_rc_cb.rc_features & BTA_AV_FEAT_ADV_CTRL)))
+    }
+    memcpy(p_dev->rc_addr, p_rc_open->peer_addr, sizeof(BD_ADDR));
+    p_dev->rc_features = p_rc_open->peer_features;
+    p_dev->rc_vol_label = MAX_LABEL;
+    p_dev->rc_volume = MAX_VOLUME;
+
+    p_dev->rc_connected = true;
+    p_dev->rc_handle = p_rc_open->rc_handle;
+    p_dev->rc_state = BTRC_CONNECTION_STATE_CONNECTED;
+    /* on locally initiated connection we will get remote features as part of connect */
+    if (p_dev->rc_features != 0)
+    {
+        handle_rc_features(p_dev);
+    }
+
+    if (bt_rc_callbacks)
+    {
+        result = (bt_status_t)uinput_driver_check();
+        if (result == BT_STATUS_SUCCESS)
         {
-            handle_rc_ctrl_features(btif_rc_cb.rc_addr);
+            init_uinput();
         }
-#endif
     }
     else
     {
-        BTIF_TRACE_ERROR("%s Connect failed with error code: %d",
-            __func__, p_rc_open->status);
-        btif_rc_cb.rc_connected = false;
+        BTIF_TRACE_WARNING("%s: Avrcp TG role not enabled, not initializing UInput",
+                           __func__);
+    }
+    BTIF_TRACE_DEBUG("%s: handle_rc_connect features: %d ",__func__, p_dev->rc_features);
+#if (AVRC_CTRL_INCLUDED == TRUE)
+    p_dev->rc_playing_uid = RC_INVALID_TRACK_ID;
+    bdcpy(rc_addr.address, p_dev->rc_addr);
+    if (bt_rc_ctrl_callbacks != NULL)
+    {
+        HAL_CBACK(bt_rc_ctrl_callbacks, connection_state_cb, true, &rc_addr);
     }
+    /* report connection state if remote device is AVRCP target */
+    handle_rc_ctrl_features(p_dev);
+#endif
 }
 
 /***************************************************************************
@@ -635,52 +760,66 @@ void handle_rc_connect (tBTA_AV_RC_OPEN *p_rc_open)
  ***************************************************************************/
 void handle_rc_disconnect (tBTA_AV_RC_CLOSE *p_rc_close)
 {
+    btif_rc_device_cb_t *p_dev = NULL;
 #if (AVRC_CTRL_INCLUDED == TRUE)
     bt_bdaddr_t rc_addr;
-    tBTA_AV_FEAT features;
+    tBTA_AV_FEAT features = 0;
 #endif
     BTIF_TRACE_DEBUG("%s: rc_handle: %d", __func__, p_rc_close->rc_handle);
-    if ((p_rc_close->rc_handle != btif_rc_cb.rc_handle)
-        && (bdcmp(btif_rc_cb.rc_addr, p_rc_close->peer_addr)))
+
+    p_dev = btif_rc_get_device_by_handle(p_rc_close->rc_handle);
+    if (p_dev == NULL)
+    {
+        BTIF_TRACE_ERROR("%s: Got disconnect from invalid rc handle", __func__);
+        return;
+    }
+
+    if ((p_rc_close->rc_handle != p_dev->rc_handle)
+        && (bdcmp(p_dev->rc_addr, p_rc_close->peer_addr)))
     {
         BTIF_TRACE_ERROR("Got disconnect of unknown device");
         return;
     }
 #if (AVRC_CTRL_INCLUDED == TRUE)
-    bdcpy(rc_addr.address, btif_rc_cb.rc_addr);
-    features = btif_rc_cb.rc_features;
+    bdcpy(rc_addr.address, p_dev->rc_addr);
+    features = p_dev->rc_features;
         /* Clean up AVRCP procedure flags */
-    memset(&btif_rc_cb.rc_app_settings, 0,
+    memset(&p_dev->rc_app_settings, 0,
         sizeof(btif_rc_player_app_settings_t));
-    btif_rc_cb.rc_features_processed = false;
-    btif_rc_cb.rc_procedure_complete = false;
-    rc_stop_play_status_timer();
+    p_dev->rc_features_processed = false;
+    p_dev->rc_procedure_complete = false;
+    rc_stop_play_status_timer(p_dev);
     /* Check and clear the notification event list */
-    if (btif_rc_cb.rc_supported_event_list != NULL)
+    if (p_dev->rc_supported_event_list != NULL)
     {
-        list_clear(btif_rc_cb.rc_supported_event_list);
-        btif_rc_cb.rc_supported_event_list = NULL;
+        list_clear(p_dev->rc_supported_event_list);
+        p_dev->rc_supported_event_list = NULL;
     }
 #endif
-    btif_rc_cb.rc_handle = 0;
-    btif_rc_cb.rc_connected = false;
-    memset(btif_rc_cb.rc_addr, 0, sizeof(BD_ADDR));
-    memset(btif_rc_cb.rc_notif, 0, sizeof(btif_rc_cb.rc_notif));
-
-    btif_rc_cb.rc_features = 0;
-    btif_rc_cb.rc_vol_label=MAX_LABEL;
-    btif_rc_cb.rc_volume=MAX_VOLUME;
-    init_all_transactions();
-    if (bt_rc_callbacks != NULL)
+
+    /* check if there is another device connected */
+    if (p_dev->rc_state == BTRC_CONNECTION_STATE_CONNECTED)
     {
-        close_uinput();
+        p_dev->rc_handle = 0;
+        p_dev->rc_connected = false;
+        p_dev->rc_state = BTRC_CONNECTION_STATE_DISCONNECTED;
+
+        memset(p_dev->rc_notif, 0, sizeof(p_dev->rc_notif));
+
+        p_dev->rc_features = 0;
+        p_dev->rc_vol_label=MAX_LABEL;
+        p_dev->rc_volume=MAX_VOLUME;
+
+        memset(p_dev->rc_addr, 0, sizeof(BD_ADDR));
+
     }
-    else
+    if (get_num_connected_devices() == 0)
     {
-        BTIF_TRACE_WARNING("%s Avrcp TG role not enabled, not closing UInput", __func__);
+        BTIF_TRACE_DEBUG("%s: Closing all handles", __func__);
+        init_all_transactions();
     }
 
-    memset(btif_rc_cb.rc_addr, 0, sizeof(BD_ADDR));
+    memset(p_dev->rc_addr, 0, sizeof(BD_ADDR));
 #if (AVRC_CTRL_INCLUDED == TRUE)
     /* report connection state if device is AVRCP target */
     if (bt_rc_ctrl_callbacks != NULL)
@@ -699,12 +838,23 @@ void handle_rc_disconnect (tBTA_AV_RC_CLOSE *p_rc_close)
  *  - Description: Remote control command handler
  *
  ***************************************************************************/
-void handle_rc_passthrough_cmd ( tBTA_AV_REMOTE_CMD *p_remote_cmd)
+void handle_rc_passthrough_cmd (tBTA_AV_REMOTE_CMD *p_remote_cmd)
 {
+    btif_rc_device_cb_t *p_dev = NULL;
     const char *status;
-    int pressed, i;
+    int pressed;
+    bt_bdaddr_t rc_addr;
+
+    p_dev = btif_rc_get_device_by_handle(p_remote_cmd->rc_handle);
+    if (p_dev == NULL)
+    {
+        BTIF_TRACE_ERROR("%s: Got passthrough command from invalid rc handle", __func__);
+        return;
+    }
+
+    bdcpy(rc_addr.address, p_dev->rc_addr);
 
-    BTIF_TRACE_DEBUG("%s: p_remote_cmd->rc_id=%d", __func__, p_remote_cmd->rc_id);
+    BTIF_TRACE_DEBUG("%s: p_remote_cmd->rc_id%d", __func__, p_remote_cmd->rc_id);
 
     /* If AVRC is open and peer sends PLAY but there is no AVDT, then we queue-up this PLAY */
     if (p_remote_cmd)
@@ -715,15 +865,14 @@ void handle_rc_passthrough_cmd ( tBTA_AV_REMOTE_CMD *p_remote_cmd)
             if (p_remote_cmd->key_state == AVRC_STATE_PRESS)
             {
                 APPL_TRACE_WARNING("%s: AVDT not open, queuing the PLAY command", __func__);
-                btif_rc_cb.rc_pending_play = true;
+                p_dev->rc_pending_play = true;
             }
             return;
         }
-
-        if ((p_remote_cmd->rc_id == BTA_AV_RC_PAUSE) && (btif_rc_cb.rc_pending_play))
+        if ((p_remote_cmd->rc_id == BTA_AV_RC_PAUSE) && (p_dev->rc_pending_play))
         {
             APPL_TRACE_WARNING("%s: Clear the pending PLAY on PAUSE received", __func__);
-            btif_rc_cb.rc_pending_play = false;
+            p_dev->rc_pending_play = false;
             return;
         }
         if ((p_remote_cmd->rc_id == BTA_AV_RC_VOL_UP)||(p_remote_cmd->rc_id == BTA_AV_RC_VOL_DOWN))
@@ -732,7 +881,7 @@ void handle_rc_passthrough_cmd ( tBTA_AV_REMOTE_CMD *p_remote_cmd)
 
     if ((p_remote_cmd->rc_id == BTA_AV_RC_STOP) && (!btif_av_stream_started_ready()))
     {
-        APPL_TRACE_WARNING("%s: Stream suspended, ignore STOP cmd",__func__);
+        APPL_TRACE_WARNING("%s: Stream suspended, ignore STOP cmd", __func__);
         return;
     }
 
@@ -745,42 +894,15 @@ void handle_rc_passthrough_cmd ( tBTA_AV_REMOTE_CMD *p_remote_cmd)
     }
 
     if (p_remote_cmd->rc_id == BTA_AV_RC_FAST_FOR || p_remote_cmd->rc_id == BTA_AV_RC_REWIND) {
-        HAL_CBACK(bt_rc_callbacks, passthrough_cmd_cb, p_remote_cmd->rc_id, pressed);
+        HAL_CBACK(bt_rc_callbacks, passthrough_cmd_cb, p_remote_cmd->rc_id, pressed, &rc_addr);
         return;
     }
 
-    for (i = 0; key_map[i].name != NULL; i++) {
-        if (p_remote_cmd->rc_id == key_map[i].avrcp) {
-            BTIF_TRACE_DEBUG("%s: %s %s", __func__, key_map[i].name, status);
-
-           /* MusicPlayer uses a long_press_timeout of 1 second for PLAYPAUSE button
-            * and maps that to autoshuffle. So if for some reason release for PLAY/PAUSE
-            * comes 1 second after the press, the MediaPlayer UI goes into a bad state.
-            * The reason for the delay could be sniff mode exit or some AVDTP procedure etc.
-            * The fix is to generate a release right after the press and drown the 'actual'
-            * release.
-            */
-            if ((key_map[i].release_quirk == 1) && (pressed == 0))
-            {
-                BTIF_TRACE_DEBUG("%s: AVRC %s Release Faked earlier, drowned now",
-                                  __func__, key_map[i].name);
-                return;
-            }
-            send_key(uinput_fd, key_map[i].mapped_id, pressed);
-            if ((key_map[i].release_quirk == 1) && (pressed == 1))
-            {
-                sleep_ms(30);
-                BTIF_TRACE_DEBUG("%s: AVRC %s Release quirk enabled, send release now",
-                                  __func__, key_map[i].name);
-                send_key(uinput_fd, key_map[i].mapped_id, 0);
-            }
-            break;
-        }
-    }
+    /* handle all pass through commands in upper layers through Android media apis */
+    BTIF_TRACE_DEBUG("%s: rc_features: %d, cmd->rc_id: %d, pressed: %d", __func__,
+        p_dev->rc_features, p_remote_cmd->rc_id, pressed);
+    HAL_CBACK(bt_rc_callbacks, passthrough_cmd_cb, p_remote_cmd->rc_id, pressed, &rc_addr);
 
-    if (key_map[i].name == NULL)
-        BTIF_TRACE_ERROR("%s AVRCP: unknown button 0x%02X %s", __func__,
-                        p_remote_cmd->rc_id, status);
 }
 
 /***************************************************************************
@@ -793,9 +915,21 @@ void handle_rc_passthrough_cmd ( tBTA_AV_REMOTE_CMD *p_remote_cmd)
  ***************************************************************************/
 void handle_rc_passthrough_rsp ( tBTA_AV_REMOTE_RSP *p_remote_rsp)
 {
+    btif_rc_device_cb_t *p_dev = NULL;
+    bt_bdaddr_t rc_addr;
+
+    p_dev = btif_rc_get_device_by_handle(p_remote_rsp->rc_handle);
+    if (p_dev == NULL)
+    {
+        BTIF_TRACE_ERROR("%s: passthrough response for Invalid rc handle", __func__);
+        return;
+    }
+
+    bdcpy(rc_addr.address, p_dev->rc_addr);
+
 #if (AVRC_CTRL_INCLUDED == TRUE)
     const char *status;
-    if (btif_rc_cb.rc_features & BTA_AV_FEAT_RCTG)
+    if (p_dev->rc_features & BTA_AV_FEAT_RCTG)
     {
         int key_state;
         if (p_remote_rsp->key_state == AVRC_STATE_RELEASE)
@@ -809,19 +943,20 @@ void handle_rc_passthrough_rsp ( tBTA_AV_REMOTE_RSP *p_remote_rsp)
             key_state = 0;
         }
 
-        BTIF_TRACE_DEBUG("%s: rc_id=%d status=%s", __func__, p_remote_rsp->rc_id, status);
+        BTIF_TRACE_DEBUG("%s: rc_id: %d status: %s", __func__, p_remote_rsp->rc_id, status);
 
         release_transaction(p_remote_rsp->label);
         if (bt_rc_ctrl_callbacks != NULL) {
-            HAL_CBACK(bt_rc_ctrl_callbacks, passthrough_rsp_cb, p_remote_rsp->rc_id, key_state);
+            HAL_CBACK(bt_rc_ctrl_callbacks, passthrough_rsp_cb, p_remote_rsp->rc_id, key_state, \
+                &rc_addr);
         }
     }
     else
     {
-        BTIF_TRACE_ERROR("%s DUT does not support AVRCP controller role", __func__);
+        BTIF_TRACE_ERROR("%s: DUT does not support AVRCP controller role", __func__);
     }
 #else
-    BTIF_TRACE_ERROR("%s AVRCP controller role is not enabled", __func__);
+    BTIF_TRACE_ERROR("%s: AVRCP controller role is not enabled", __func__);
 #endif
 }
 
@@ -836,9 +971,18 @@ void handle_rc_passthrough_rsp ( tBTA_AV_REMOTE_RSP *p_remote_rsp)
 void handle_rc_vendorunique_rsp ( tBTA_AV_REMOTE_RSP *p_remote_rsp)
 {
 #if (AVRC_CTRL_INCLUDED == TRUE)
+    btif_rc_device_cb_t *p_dev = NULL;
     const char *status;
     uint8_t vendor_id = 0;
-    if (btif_rc_cb.rc_features & BTA_AV_FEAT_RCTG)
+
+    p_dev = btif_rc_get_device_by_handle(p_remote_rsp->rc_handle);
+    if (p_dev == NULL)
+    {
+        BTIF_TRACE_ERROR("%s: Got vendorunique rsp from invalid rc handle", __func__);
+        return;
+    }
+
+    if (p_dev->rc_features & BTA_AV_FEAT_RCTG)
     {
         int key_state;
         if (p_remote_rsp->key_state == AVRC_STATE_RELEASE)
@@ -858,21 +1002,21 @@ void handle_rc_vendorunique_rsp ( tBTA_AV_REMOTE_RSP *p_remote_rsp)
                 vendor_id = p_remote_rsp->p_data[AVRC_PASS_THRU_GROUP_LEN -1];
             osi_free_and_reset((void **)&p_remote_rsp->p_data);
         }
-        BTIF_TRACE_DEBUG("%s: vendor_id=%d status=%s", __func__, vendor_id, status);
+        BTIF_TRACE_DEBUG("%s: vendor_id: %d status: %s", __func__, vendor_id, status);
 
         release_transaction(p_remote_rsp->label);
         HAL_CBACK(bt_rc_ctrl_callbacks, groupnavigation_rsp_cb, vendor_id, key_state);
     }
     else
     {
-        BTIF_TRACE_ERROR("%s Remote does not support AVRCP TG role", __func__);
+        BTIF_TRACE_ERROR("%s: Remote does not support AVRCP TG role", __func__);
     }
 #else
-    BTIF_TRACE_ERROR("%s AVRCP controller role is not enabled", __func__);
+    BTIF_TRACE_ERROR("%s: AVRCP controller role is not enabled", __func__);
 #endif
 }
 
-void handle_uid_changed_notification(tBTA_AV_META_MSG *pmeta_msg, tAVRC_COMMAND *pavrc_command)
+void handle_uid_changed_notification(btif_rc_device_cb_t *p_dev, uint8_t label, tAVRC_COMMAND *pavrc_command)
 {
     tAVRC_RESPONSE avrc_rsp = {0};
     avrc_rsp.rsp.pdu = pavrc_command->pdu;
@@ -882,8 +1026,8 @@ void handle_uid_changed_notification(tBTA_AV_META_MSG *pmeta_msg, tAVRC_COMMAND
     avrc_rsp.reg_notif.event_id = pavrc_command->reg_notif.event_id;
     avrc_rsp.reg_notif.param.uid_counter = 0;
 
-    send_metamsg_rsp(pmeta_msg->rc_handle, pmeta_msg->label, AVRC_RSP_INTERIM, &avrc_rsp);
-    send_metamsg_rsp(pmeta_msg->rc_handle, pmeta_msg->label, AVRC_RSP_CHANGED, &avrc_rsp);
+    send_metamsg_rsp(p_dev, -1, label, AVRC_RSP_INTERIM, &avrc_rsp);
+    send_metamsg_rsp(p_dev, -1, label, AVRC_RSP_CHANGED, &avrc_rsp);
 
 }
 
@@ -902,18 +1046,41 @@ void handle_rc_metamsg_cmd (tBTA_AV_META_MSG *pmeta_msg)
     uint8_t             scratch_buf[512] = {0};
     tAVRC_COMMAND    avrc_command = {0};
     tAVRC_STS status;
+    btif_rc_device_cb_t *p_dev = NULL;
+
+    if (NULL == pmeta_msg)
+    {
+        BTIF_TRACE_EVENT("%s: Exiting as pmeta_msg is NULL", __func__);
+        return;
+    }
+
+    if (NULL == pmeta_msg->p_msg)
+    {
+        BTIF_TRACE_EVENT("%s: Exiting as pmeta_msg->p_msg is NULL", __func__);
+        return;
+    }
+
+    BTIF_TRACE_EVENT("%s: pmeta_msg: opcode: %x, code: %x", __func__,
+            pmeta_msg->p_msg->hdr.opcode, pmeta_msg->code);
 
-    BTIF_TRACE_EVENT("+ %s", __func__);
+    p_dev = btif_rc_get_device_by_handle(pmeta_msg->rc_handle);
+    if (p_dev == NULL)
+    {
+        BTIF_TRACE_ERROR("%s: Meta msg event for Invalid rc handle", __func__);
+        return;
+    }
 
-    if (pmeta_msg->p_msg->hdr.opcode != AVRC_OP_VENDOR)
+    if (pmeta_msg->p_msg->hdr.opcode != AVRC_OP_VENDOR &&
+        pmeta_msg->p_msg->hdr.opcode != AVRC_OP_BROWSE)
     {
         BTIF_TRACE_WARNING("Invalid opcode: %x", pmeta_msg->p_msg->hdr.opcode);
         return;
     }
+
     if (pmeta_msg->len < 3)
     {
-        BTIF_TRACE_WARNING("Invalid length.Opcode: 0x%x, len: 0x%x", pmeta_msg->p_msg->hdr.opcode,
-            pmeta_msg->len);
+        BTIF_TRACE_WARNING("%s: Invalid length. opcode: 0x%x, len: 0x%x", __func__,
+            pmeta_msg->p_msg->hdr.opcode, pmeta_msg->len);
         return;
     }
 
@@ -921,22 +1088,22 @@ void handle_rc_metamsg_cmd (tBTA_AV_META_MSG *pmeta_msg)
     {
 #if (AVRC_ADV_CTRL_INCLUDED == TRUE)
 {
-     rc_transaction_t *transaction=NULL;
-     transaction=get_transaction_by_lbl(pmeta_msg->label);
-     if (NULL!=transaction)
+     rc_transaction_t *transaction = NULL;
+     transaction = get_transaction_by_lbl(pmeta_msg->label);
+     if (NULL != transaction)
      {
-        handle_rc_metamsg_rsp(pmeta_msg);
+        handle_rc_metamsg_rsp(pmeta_msg, p_dev);
      }
      else
      {
-         BTIF_TRACE_DEBUG("%s:Discard vendor dependent rsp. code: %d label:%d.",
+         BTIF_TRACE_DEBUG("%s: Discard vendor dependent rsp. code: %d label: %d.",
              __func__, pmeta_msg->code, pmeta_msg->label);
      }
      return;
 }
 #else
 {
-        BTIF_TRACE_DEBUG("%s:Received vendor dependent rsp. code: %d len: %d. Not processing it.",
+        BTIF_TRACE_DEBUG("%s: Received vendor dependent rsp. code: %d len: %d. Not processing it.",
             __func__, pmeta_msg->code, pmeta_msg->len);
         return;
 }
@@ -944,7 +1111,7 @@ void handle_rc_metamsg_cmd (tBTA_AV_META_MSG *pmeta_msg)
       }
 
     status=AVRC_ParsCommand(pmeta_msg->p_msg, &avrc_command, scratch_buf, sizeof(scratch_buf));
-    BTIF_TRACE_DEBUG("%s Received vendor command.code,PDU and label: %d, %d,%d",
+    BTIF_TRACE_DEBUG("%s: Received vendor command.code,PDU and label: %d, %d, %d",
                      __func__, pmeta_msg->code, avrc_command.cmd.pdu, pmeta_msg->label);
 
     if (status != AVRC_STS_NO_ERROR)
@@ -952,7 +1119,8 @@ void handle_rc_metamsg_cmd (tBTA_AV_META_MSG *pmeta_msg)
         /* return error */
         BTIF_TRACE_WARNING("%s: Error in parsing received metamsg command. status: 0x%02x",
             __func__, status);
-        send_reject_response(pmeta_msg->rc_handle, pmeta_msg->label, avrc_command.pdu, status);
+        send_reject_response(pmeta_msg->rc_handle, pmeta_msg->label, avrc_command.pdu, status,
+                   pmeta_msg->p_msg->hdr.opcode);
     }
     else
     {
@@ -961,14 +1129,15 @@ void handle_rc_metamsg_cmd (tBTA_AV_META_MSG *pmeta_msg)
         if (avrc_command.cmd.pdu == AVRC_PDU_REGISTER_NOTIFICATION)
         {
             uint8_t event_id = avrc_command.reg_notif.event_id;
-            BTIF_TRACE_EVENT("%s:New register notification received.event_id:%s,label:0x%x,code:%x",
-            __func__,dump_rc_notification_event_id(event_id), pmeta_msg->label,pmeta_msg->code);
-            btif_rc_cb.rc_notif[event_id-1].bNotify = true;
-            btif_rc_cb.rc_notif[event_id-1].label = pmeta_msg->label;
+
+            BTIF_TRACE_EVENT("%s: New register notification received.event_id: %s, label: 0x%x, code: %x",
+            __func__,dump_rc_notification_event_id(event_id), pmeta_msg->label, pmeta_msg->code);
+            p_dev->rc_notif[event_id-1].bNotify = true;
+            p_dev->rc_notif[event_id-1].label = pmeta_msg->label;
 
             if (event_id == AVRC_EVT_UIDS_CHANGE)
             {
-                handle_uid_changed_notification(pmeta_msg, &avrc_command);
+                handle_uid_changed_notification(p_dev, pmeta_msg->label, &avrc_command);
                 return;
             }
 
@@ -981,7 +1150,7 @@ void handle_rc_metamsg_cmd (tBTA_AV_META_MSG *pmeta_msg)
             *btif context, no context switching is required. Invoke
             * btif_rc_upstreams_evt directly from here. */
         btif_rc_upstreams_evt((uint16_t)avrc_command.cmd.pdu, &avrc_command, pmeta_msg->code,
-                               pmeta_msg->label);
+                               pmeta_msg->label, p_dev);
     }
 }
 
@@ -994,43 +1163,42 @@ void handle_rc_metamsg_cmd (tBTA_AV_META_MSG *pmeta_msg)
  ***************************************************************************/
 void btif_rc_handler(tBTA_AV_EVT event, tBTA_AV *p_data)
 {
-    BTIF_TRACE_DEBUG ("%s event:%s", __func__, dump_rc_event(event));
+    BTIF_TRACE_DEBUG ("%s: event: %s", __func__, dump_rc_event(event));
+    btif_rc_device_cb_t *p_dev = NULL;
     switch (event)
     {
         case BTA_AV_RC_OPEN_EVT:
         {
-            BTIF_TRACE_DEBUG("%s Peer_features:%x", __func__, p_data->rc_open.peer_features);
+            BTIF_TRACE_DEBUG("%s: Peer_features: %x", __func__, p_data->rc_open.peer_features);
             handle_rc_connect( &(p_data->rc_open) );
         }break;
 
         case BTA_AV_RC_CLOSE_EVT:
         {
-            handle_rc_disconnect( &(p_data->rc_close) );
+            handle_rc_disconnect(&(p_data->rc_close));
+        }break;
+
+        case BTA_AV_RC_BROWSE_OPEN_EVT:
+        {
+            BTIF_TRACE_DEBUG("%s: BTA_AV_RC_BROWSE_OPEN_EVT", __func__);
+        }break;
+
+        case BTA_AV_RC_BROWSE_CLOSE_EVT:
+        {
+            BTIF_TRACE_DEBUG("%s: BTA_AV_RC_BROWSE_CLOSE_EVT", __func__);
         }break;
 
         case BTA_AV_REMOTE_CMD_EVT:
         {
             if (bt_rc_callbacks != NULL)
             {
-              BTIF_TRACE_DEBUG("%s rc_id:0x%x key_state:%d",
-                               __func__, p_data->remote_cmd.rc_id,
+                BTIF_TRACE_DEBUG("%s: rc_id: 0x%x key_state: %d", __func__, p_data->remote_cmd.rc_id,
                                p_data->remote_cmd.key_state);
-                /** In race conditions just after 2nd AVRCP is connected
-                 *  remote might send pass through commands, so check for
-                 *  Rc handle before processing pass through commands
-                 **/
-                if (btif_rc_cb.rc_handle == p_data->remote_cmd.rc_handle)
-                {
-                    handle_rc_passthrough_cmd( (&p_data->remote_cmd) );
-                }
-                else
-                {
-                    BTIF_TRACE_DEBUG("%s Pass-through command for Invalid rc handle", __func__);
-                }
+                handle_rc_passthrough_cmd( (&p_data->remote_cmd) );
             }
             else
             {
-                BTIF_TRACE_ERROR("AVRCP TG role not up, drop passthrough commands");
+                BTIF_TRACE_ERROR("%s: AVRCP TG role not up, drop passthrough commands", __func__);
             }
         }
         break;
@@ -1038,15 +1206,16 @@ void btif_rc_handler(tBTA_AV_EVT event, tBTA_AV *p_data)
 #if (AVRC_CTRL_INCLUDED == TRUE)
         case BTA_AV_REMOTE_RSP_EVT:
         {
-            BTIF_TRACE_DEBUG("%s RSP: rc_id:0x%x key_state:%d",
+            BTIF_TRACE_DEBUG("%s: RSP: rc_id: 0x%x key_state: %d",
                              __func__, p_data->remote_rsp.rc_id, p_data->remote_rsp.key_state);
+
             if (p_data->remote_rsp.rc_id == AVRC_ID_VENDOR)
             {
-                handle_rc_vendorunique_rsp(&p_data->remote_rsp);
+                handle_rc_vendorunique_rsp((&p_data->remote_rsp));
             }
             else
             {
-                handle_rc_passthrough_rsp(&p_data->remote_rsp);
+                handle_rc_passthrough_rsp((&p_data->remote_rsp));
             }
         }
         break;
@@ -1054,13 +1223,21 @@ void btif_rc_handler(tBTA_AV_EVT event, tBTA_AV *p_data)
 #endif
         case BTA_AV_RC_FEAT_EVT:
         {
-            BTIF_TRACE_DEBUG("%s Peer_features:%x", __func__, p_data->rc_feat.peer_features);
-            btif_rc_cb.rc_features = p_data->rc_feat.peer_features;
-            handle_rc_features(p_data->rc_feat.peer_addr);
+            BTIF_TRACE_DEBUG("%s: Peer_features: %x", __func__, p_data->rc_feat.peer_features);
+            p_dev = btif_rc_get_device_by_handle(p_data->rc_feat.rc_handle);
+            if (p_dev == NULL)
+            {
+                BTIF_TRACE_ERROR("%s: RC Feature event for Invalid rc handle", __func__);
+                break;
+            }
+
+            p_dev->rc_features = p_data->rc_feat.peer_features;
+            handle_rc_features(p_dev);
+
 #if (AVRC_CTRL_INCLUDED == TRUE)
-            if ((btif_rc_cb.rc_connected) && (bt_rc_ctrl_callbacks != NULL))
+            if ((p_dev->rc_connected) && (bt_rc_ctrl_callbacks != NULL))
             {
-                handle_rc_ctrl_features(btif_rc_cb.rc_addr);
+                handle_rc_ctrl_features(p_dev);
             }
 #endif
         }
@@ -1070,32 +1247,35 @@ void btif_rc_handler(tBTA_AV_EVT event, tBTA_AV *p_data)
         {
             if (bt_rc_callbacks != NULL)
             {
-                BTIF_TRACE_DEBUG("%s BTA_AV_META_MSG_EVT  code:%d label:%d",
+                BTIF_TRACE_DEBUG("%s: BTA_AV_META_MSG_EVT code: %d label: %d",
                                  __func__,
                                  p_data->meta_msg.code,
                                  p_data->meta_msg.label);
-                BTIF_TRACE_DEBUG("%s company_id:0x%x len:%d handle:%d",
+                BTIF_TRACE_DEBUG("%s: company_id: 0x%x len: %d handle: %d",
                                  __func__,
                                  p_data->meta_msg.company_id,
                                  p_data->meta_msg.len,
                                  p_data->meta_msg.rc_handle);
+
                 /* handle the metamsg command */
                 handle_rc_metamsg_cmd(&(p_data->meta_msg));
+
                 /* Free the Memory allocated for tAVRC_MSG */
             }
 #if (AVRC_CTRL_INCLUDED == TRUE)
             else if ((bt_rc_callbacks == NULL)&&(bt_rc_ctrl_callbacks != NULL))
             {
                 /* This is case of Sink + CT + TG(for abs vol)) */
-                BTIF_TRACE_DEBUG("%s BTA_AV_META_MSG_EVT  code:%d label:%d",
+                BTIF_TRACE_DEBUG("%s: BTA_AV_META_MSG_EVT code: %d label: %d",
                                  __func__,
                                  p_data->meta_msg.code,
                                  p_data->meta_msg.label);
-                BTIF_TRACE_DEBUG("%s company_id:0x%x len:%d handle:%d",
+                BTIF_TRACE_DEBUG("%s: company_id: 0x%x len: %d handle: %d",
                                  __func__,
                                  p_data->meta_msg.company_id,
                                  p_data->meta_msg.len,
                                  p_data->meta_msg.rc_handle);
+
                 if ((p_data->meta_msg.code >= AVRC_RSP_NOT_IMPL)&&
                     (p_data->meta_msg.code <= AVRC_RSP_INTERIM))
                 {
@@ -1118,7 +1298,7 @@ void btif_rc_handler(tBTA_AV_EVT event, tBTA_AV *p_data)
         break;
 
         default:
-            BTIF_TRACE_DEBUG("%s Unhandled RC event : 0x%x", __func__, event);
+            BTIF_TRACE_DEBUG("%s: Unhandled RC event : 0x%x", __func__, event);
     }
 }
 
@@ -1131,9 +1311,18 @@ void btif_rc_handler(tBTA_AV_EVT event, tBTA_AV *p_data)
  ***************************************************************************/
 bool btif_rc_get_connected_peer(BD_ADDR peer_addr)
 {
-    if (btif_rc_cb.rc_connected == true) {
-        bdcpy(peer_addr, btif_rc_cb.rc_addr);
-        return true;
+    bt_bdaddr_t rc_addr;
+    bdcpy(rc_addr.address, peer_addr);
+    btif_rc_device_cb_t *p_dev = NULL;
+
+    for (int idx = 0; idx < BTIF_RC_NUM_CONN; idx++)
+    {
+        p_dev = get_connected_device(idx);
+        if (p_dev != NULL && (p_dev->rc_connected == TRUE))
+        {
+            bdcpy(peer_addr, p_dev->rc_addr);
+            return TRUE;
+        }
     }
     return false;
 }
@@ -1145,26 +1334,45 @@ bool btif_rc_get_connected_peer(BD_ADDR peer_addr)
  ** Description    Fetches the connected headset's handle if any
  **
  ***************************************************************************/
-uint8_t btif_rc_get_connected_peer_handle(void)
+uint8_t btif_rc_get_connected_peer_handle(BD_ADDR peer_addr)
 {
-    return btif_rc_cb.rc_handle;
+    bt_bdaddr_t rc_addr;
+    bdcpy(rc_addr.address, peer_addr);
+
+    btif_rc_device_cb_t *p_dev = NULL;
+    p_dev = btif_rc_get_device_by_bda(&rc_addr);
+
+    if (p_dev == NULL){
+        BTIF_TRACE_ERROR("%s: p_dev NULL", __func__);
+        return BTRC_HANDLE_NONE;
+    }
+    return p_dev->rc_handle;
 }
 
 /***************************************************************************
  **
  ** Function       btif_rc_check_handle_pending_play
  **
- ** Description    Clears the queued PLAY command. if bSend is true, forwards to app
+ ** Description    Clears the queued PLAY command. if |bSendToApp| is true, forwards to app
  **
  ***************************************************************************/
 
-/* clear the queued PLAY command. if bSend is true, forward to app */
+/* clear the queued PLAY command. if |bSendToApp| is true, forward to app */
 void btif_rc_check_handle_pending_play (BD_ADDR peer_addr, bool bSendToApp)
 {
-    UNUSED(peer_addr);
+    bt_bdaddr_t rc_addr;
+    bdcpy(rc_addr.address, peer_addr);
 
-    BTIF_TRACE_DEBUG("%s: bSendToApp=%d", __func__, bSendToApp);
-    if (btif_rc_cb.rc_pending_play)
+    btif_rc_device_cb_t *p_dev = NULL;
+    p_dev = btif_rc_get_device_by_bda(&rc_addr);
+
+    if( p_dev == NULL ){
+        BTIF_TRACE_ERROR("%s: p_dev NULL", __func__);
+        return;
+    }
+
+    BTIF_TRACE_DEBUG("%s: bSendToApp: %d", __func__, bSendToApp);
+    if ( p_dev->rc_pending_play )
     {
         if (bSendToApp)
         {
@@ -1172,7 +1380,7 @@ void btif_rc_check_handle_pending_play (BD_ADDR peer_addr, bool bSendToApp)
             APPL_TRACE_DEBUG("%s: Sending queued PLAYED event to app", __func__);
 
             memset (&remote_cmd, 0, sizeof(tBTA_AV_REMOTE_CMD));
-            remote_cmd.rc_handle  = btif_rc_cb.rc_handle;
+            remote_cmd.rc_handle  = p_dev->rc_handle;
             remote_cmd.rc_id      = AVRC_ID_PLAY;
             remote_cmd.hdr.ctype  = AVRC_CMD_CTRL;
             remote_cmd.hdr.opcode = AVRC_OP_PASS_THRU;
@@ -1184,118 +1392,142 @@ void btif_rc_check_handle_pending_play (BD_ADDR peer_addr, bool bSendToApp)
             sleep_ms(200);
             /* send to app - both PRESSED & RELEASED */
             remote_cmd.key_state  = AVRC_STATE_PRESS;
-            handle_rc_passthrough_cmd( &remote_cmd );
+            handle_rc_passthrough_cmd(&remote_cmd);
 
             sleep_ms(100);
 
             remote_cmd.key_state  = AVRC_STATE_RELEASE;
-            handle_rc_passthrough_cmd( &remote_cmd );
+            handle_rc_passthrough_cmd(&remote_cmd);
         }
-        btif_rc_cb.rc_pending_play = false;
+        p_dev->rc_pending_play = false;
     }
 }
 
 /* Generic reject response */
-static void send_reject_response (uint8_t rc_handle, uint8_t label, uint8_t pdu, uint8_t status)
+static void send_reject_response (uint8_t rc_handle, uint8_t label, uint8_t pdu, uint8_t status,
+                                        uint8_t opcode)
 {
     uint8_t ctype = AVRC_RSP_REJ;
     tAVRC_RESPONSE avrc_rsp;
     BT_HDR *p_msg = NULL;
     memset (&avrc_rsp, 0, sizeof(tAVRC_RESPONSE));
 
-    avrc_rsp.rsp.opcode = opcode_from_pdu(pdu);
+    avrc_rsp.rsp.opcode = opcode;
     avrc_rsp.rsp.pdu    = pdu;
     avrc_rsp.rsp.status = status;
 
-    if (AVRC_STS_NO_ERROR == (status = AVRC_BldResponse(rc_handle, &avrc_rsp, &p_msg)) )
+    status = AVRC_BldResponse(rc_handle, &avrc_rsp, &p_msg);
+
+    if (status != AVRC_STS_NO_ERROR)
+    {
+        BTIF_TRACE_ERROR("%s: status not AVRC_STS_NO_ERROR", __func__);
+        return;
+    }
+
+    BTIF_TRACE_DEBUG("%s: Sending error notification to handle: %d. pdu: %s,status: 0x%02x",
+        __func__, rc_handle, dump_rc_pdu(pdu), status);
+    BTA_AvMetaRsp(rc_handle, label, ctype, p_msg);
+}
+
+/***************************************************************************
+ *  Function         get_rsp_type_code
+ *
+ *  - Argument:   status
+ *  - Description: Returns response type codes for particular command code and status.
+ *
+ ***************************************************************************/
+static tBTA_AV_CODE get_rsp_type_code(tAVRC_STS status, tBTA_AV_CODE code)
+{
+    if (status != AVRC_STS_NO_ERROR)
+    {
+        return AVRC_RSP_REJ;
+    }
+
+    if (code < AVRC_RSP_NOT_IMPL)
     {
-        BTIF_TRACE_DEBUG("%s:Sending error notification to handle:%d. pdu:%s,status:0x%02x",
-            __func__, rc_handle, dump_rc_pdu(pdu), status);
-        BTA_AvMetaRsp(rc_handle, label, ctype, p_msg);
+        if (code == AVRC_CMD_NOTIF)
+            return AVRC_RSP_INTERIM;
+
+        if (code == AVRC_CMD_STATUS)
+            return AVRC_RSP_IMPL_STBL;
+
+        return AVRC_RSP_ACCEPT;
     }
+
+    return code;
 }
 
 /***************************************************************************
  *  Function       send_metamsg_rsp
  *
  *  - Argument:
- *                  rc_handle     RC handle corresponding to the connected RC
- *                  label            Label of the RC response
+ *                  p_dev           Dev pointer
+ *                  index           Command index (= -1 if not used)
+ *                  label           Label of the RC response
  *                  code            Response type
- *                  pmetamsg_resp    Vendor response
+ *                  pmetamsg_resp   Vendor response
  *
- *  - Description: Remote control metamsg response handler (AVRCP 1.3)
+ *  - Description: Remote control metamsg response handler
  *
  ***************************************************************************/
-static void send_metamsg_rsp (uint8_t rc_handle, uint8_t label, tBTA_AV_CODE code,
+static void send_metamsg_rsp (btif_rc_device_cb_t *p_dev, int index, uint8_t label, tBTA_AV_CODE code,
     tAVRC_RESPONSE *pmetamsg_resp)
 {
     uint8_t ctype;
 
-    if (!pmetamsg_resp)
+    if (p_dev == NULL)
+    {
+        BTIF_TRACE_ERROR("%s: p_dev NULL", __func__);
+        return;
+    }
+
+    if (pmetamsg_resp == NULL)
     {
         BTIF_TRACE_WARNING("%s: Invalid response received from application", __func__);
         return;
     }
 
-    BTIF_TRACE_EVENT("+%s: rc_handle: %d, label: %d, code: 0x%02x, pdu: %s", __func__,
-        rc_handle, label, code, dump_rc_pdu(pmetamsg_resp->rsp.pdu));
+    BTIF_TRACE_EVENT("%s: rc_handle: %d, index: %d, label: %d, code: 0x%02x, pdu: %s", __func__,
+        p_dev->rc_handle, index, label, code, dump_rc_pdu(pmetamsg_resp->rsp.pdu));
 
-    if (pmetamsg_resp->rsp.status != AVRC_STS_NO_ERROR)
+    if (index >= 0 && p_dev->rc_pdu_info[index].is_rsp_pending == false)
     {
-        ctype = AVRC_RSP_REJ;
+        BTIF_TRACE_ERROR("%s: is_rsp_pending false, returning", __func__);
+        return;
     }
-    else
+
+    ctype = get_rsp_type_code(pmetamsg_resp->rsp.status, code);
+
+    /* if response is for register_notification, make sure the rc has
+    actually registered for this */
+    if ((pmetamsg_resp->rsp.pdu == AVRC_PDU_REGISTER_NOTIFICATION) && ((code == AVRC_RSP_CHANGED)
+        || (code == AVRC_RSP_INTERIM)))
     {
-        if ( code < AVRC_RSP_NOT_IMPL)
-        {
-            if (code == AVRC_CMD_NOTIF)
-            {
-               ctype = AVRC_RSP_INTERIM;
-            }
-            else if (code == AVRC_CMD_STATUS)
-            {
-               ctype = AVRC_RSP_IMPL_STBL;
-            }
-            else
-            {
-               ctype = AVRC_RSP_ACCEPT;
-            }
-        }
-        else
-        {
-            ctype = code;
-        }
-    }
-    /* if response is for register_notification, make sure the rc has
-    actually registered for this */
-    if ((pmetamsg_resp->rsp.pdu == AVRC_PDU_REGISTER_NOTIFICATION) && (code == AVRC_RSP_CHANGED))
-    {
-        bool bSent = false;
-        uint8_t   event_id = pmetamsg_resp->reg_notif.event_id;
-        bool bNotify = (btif_rc_cb.rc_connected) && (btif_rc_cb.rc_notif[event_id-1].bNotify);
-
-        /* de-register this notification for a CHANGED response */
-        btif_rc_cb.rc_notif[event_id-1].bNotify = false;
-        BTIF_TRACE_DEBUG("%s rc_handle: %d. event_id: 0x%02d bNotify:%u", __func__,
-             btif_rc_cb.rc_handle, event_id, bNotify);
-        if (bNotify)
+        bool bSent = false;
+        uint8_t   event_id = pmetamsg_resp->reg_notif.event_id;
+        bool bNotify = (p_dev->rc_connected) && (p_dev->rc_notif[event_id-1].bNotify);
+
+        /* de-register this notification for a CHANGED response */
+        p_dev->rc_notif[event_id-1].bNotify = false;
+        BTIF_TRACE_DEBUG("%s: rc_handle: %d. event_id: 0x%02d bNotify: %u", __func__,
+             p_dev->rc_handle, event_id, bNotify);
+        if (bNotify)
         {
             BT_HDR *p_msg = NULL;
             tAVRC_STS status;
 
-            if (AVRC_STS_NO_ERROR == (status = AVRC_BldResponse(btif_rc_cb.rc_handle,
+            if (AVRC_STS_NO_ERROR == (status = AVRC_BldResponse(p_dev->rc_handle,
                 pmetamsg_resp, &p_msg)) )
             {
-                BTIF_TRACE_DEBUG("%s Sending notification to rc_handle: %d. event_id: 0x%02d",
-                     __func__, btif_rc_cb.rc_handle, event_id);
+                BTIF_TRACE_DEBUG("%s: Sending notification to rc_handle: %d. event_id: 0x%02d",
+                     __func__, p_dev->rc_handle, event_id);
                 bSent = true;
-                BTA_AvMetaRsp(btif_rc_cb.rc_handle, btif_rc_cb.rc_notif[event_id-1].label,
+                BTA_AvMetaRsp(p_dev->rc_handle, p_dev->rc_notif[event_id-1].label,
                     ctype, p_msg);
             }
             else
             {
-                BTIF_TRACE_WARNING("%s failed to build metamsg response. status: 0x%02x",
+                BTIF_TRACE_WARNING("%s: failed to build metamsg response. status: 0x%02x",
                     __func__, status);
             }
 
@@ -1314,11 +1546,11 @@ static void send_metamsg_rsp (uint8_t rc_handle, uint8_t label, tBTA_AV_CODE cod
         BT_HDR *p_msg = NULL;
         tAVRC_STS status;
 
-        status = AVRC_BldResponse(rc_handle, pmetamsg_resp, &p_msg);
+        status = AVRC_BldResponse(p_dev->rc_handle, pmetamsg_resp, &p_msg);
 
         if (status == AVRC_STS_NO_ERROR)
         {
-            BTA_AvMetaRsp(rc_handle, label, ctype, p_msg);
+            BTA_AvMetaRsp(p_dev->rc_handle, label, ctype, p_msg);
         }
         else
         {
@@ -1326,6 +1558,13 @@ static void send_metamsg_rsp (uint8_t rc_handle, uint8_t label, tBTA_AV_CODE cod
                 __func__, status);
         }
     }
+
+    if (index >= 0)
+    {
+        p_dev->rc_pdu_info[index].ctype = 0;
+        p_dev->rc_pdu_info[index].label = 0;
+        p_dev->rc_pdu_info[index].is_rsp_pending = false;
+    }
 }
 
 static uint8_t opcode_from_pdu(uint8_t pdu)
@@ -1334,6 +1573,17 @@ static uint8_t opcode_from_pdu(uint8_t pdu)
 
     switch (pdu)
     {
+    case AVRC_PDU_SET_BROWSED_PLAYER:
+    case AVRC_PDU_GET_FOLDER_ITEMS:
+    case AVRC_PDU_CHANGE_PATH:
+    case AVRC_PDU_GET_ITEM_ATTRIBUTES:
+    case AVRC_PDU_ADD_TO_NOW_PLAYING:
+    case AVRC_PDU_SEARCH:
+    case AVRC_PDU_GET_TOTAL_NUM_OF_ITEMS:
+    case AVRC_PDU_GENERAL_REJECT:
+        opcode  = AVRC_OP_BROWSE;
+        break;
+
     case AVRC_PDU_NEXT_GROUP:
     case AVRC_PDU_PREV_GROUP: /* pass thru */
         opcode  = AVRC_OP_PASS_THRU;
@@ -1356,17 +1606,22 @@ static uint8_t opcode_from_pdu(uint8_t pdu)
 ** Returns          void
 **
 *******************************************************************************/
-static void btif_rc_upstreams_evt(uint16_t event, tAVRC_COMMAND *pavrc_cmd, uint8_t ctype, uint8_t label)
+static void btif_rc_upstreams_evt(uint16_t event, tAVRC_COMMAND *pavrc_cmd, uint8_t ctype,
+                                  uint8_t label, btif_rc_device_cb_t *p_dev)
 {
-    BTIF_TRACE_EVENT("%s pdu: %s handle: 0x%x ctype:%x label:%x", __func__,
-        dump_rc_pdu(pavrc_cmd->pdu), btif_rc_cb.rc_handle, ctype, label);
+    BTIF_TRACE_EVENT("%s: pdu: %s handle: 0x%x ctype: %x label: %x event ID: %x", __func__,
+        dump_rc_pdu(pavrc_cmd->pdu), p_dev->rc_handle, ctype, label,
+    pavrc_cmd->reg_notif.event_id);
+    bt_bdaddr_t rc_addr;
+
+    bdcpy(rc_addr.address, p_dev->rc_addr);
 
     switch (event)
     {
         case AVRC_PDU_GET_PLAY_STATUS:
         {
-            FILL_PDU_QUEUE(IDX_GET_PLAY_STATUS_RSP, ctype, label, true)
-            HAL_CBACK(bt_rc_callbacks, get_play_status_cb);
+            fill_pdu_queue(IDX_GET_PLAY_STATUS_RSP, ctype, label, true, p_dev);
+            HAL_CBACK(bt_rc_callbacks, get_play_status_cb, &rc_addr);
         }
         break;
         case AVRC_PDU_LIST_PLAYER_APP_ATTR:
@@ -1377,7 +1632,8 @@ static void btif_rc_upstreams_evt(uint16_t event, tAVRC_COMMAND *pavrc_cmd, uint
         case AVRC_PDU_GET_PLAYER_APP_VALUE_TEXT:
         {
             /* TODO: Add support for Application Settings */
-            send_reject_response (btif_rc_cb.rc_handle, label, pavrc_cmd->pdu, AVRC_STS_BAD_CMD);
+            send_reject_response (p_dev->rc_handle, label, pavrc_cmd->pdu,
+                AVRC_STS_BAD_CMD, pavrc_cmd->cmd.opcode);
         }
         break;
         case AVRC_PDU_GET_ELEMENT_ATTR:
@@ -1398,8 +1654,8 @@ static void btif_rc_upstreams_evt(uint16_t event, tAVRC_COMMAND *pavrc_cmd, uint
             else if (pavrc_cmd->get_elem_attrs.num_attr == 0xFF)
             {
                 /* 0xff indicates, no attributes requested - reject */
-                send_reject_response (btif_rc_cb.rc_handle, label, pavrc_cmd->pdu,
-                    AVRC_STS_BAD_PARAM);
+                send_reject_response (p_dev->rc_handle, label, pavrc_cmd->pdu,
+                    AVRC_STS_BAD_PARAM, pavrc_cmd->cmd.opcode);
                 return;
             }
             else
@@ -1432,8 +1688,9 @@ static void btif_rc_upstreams_evt(uint16_t event, tAVRC_COMMAND *pavrc_cmd, uint
                     }
                 }
             }
-            FILL_PDU_QUEUE(IDX_GET_ELEMENT_ATTR_RSP, ctype, label, true);
-            HAL_CBACK(bt_rc_callbacks, get_element_attr_cb, num_attr, element_attrs);
+            fill_pdu_queue(IDX_GET_ELEMENT_ATTR_RSP, ctype, label, true, p_dev);
+            HAL_CBACK(bt_rc_callbacks, get_element_attr_cb, num_attr,
+                element_attrs, &rc_addr);
         }
         break;
         case AVRC_PDU_REGISTER_NOTIFICATION:
@@ -1441,29 +1698,79 @@ static void btif_rc_upstreams_evt(uint16_t event, tAVRC_COMMAND *pavrc_cmd, uint
             if (pavrc_cmd->reg_notif.event_id == BTRC_EVT_PLAY_POS_CHANGED &&
                 pavrc_cmd->reg_notif.param == 0)
             {
-                BTIF_TRACE_WARNING("%s Device registering position changed with illegal param 0.",
+                BTIF_TRACE_WARNING("%s: Device registering position changed with illegal param 0.",
                     __func__);
-                send_reject_response (btif_rc_cb.rc_handle, label, pavrc_cmd->pdu, AVRC_STS_BAD_PARAM);
+                send_reject_response (p_dev->rc_handle, label, pavrc_cmd->pdu,
+                    AVRC_STS_BAD_PARAM, pavrc_cmd->cmd.opcode);
                 /* de-register this notification for a rejected response */
-                btif_rc_cb.rc_notif[BTRC_EVT_PLAY_POS_CHANGED - 1].bNotify = false;
+                p_dev->rc_notif[BTRC_EVT_PLAY_POS_CHANGED - 1].bNotify = false;
                 return;
             }
             HAL_CBACK(bt_rc_callbacks, register_notification_cb, (btrc_event_id_t)pavrc_cmd->reg_notif.event_id,
-                pavrc_cmd->reg_notif.param);
+                pavrc_cmd->reg_notif.param, &rc_addr);
         }
         break;
         case AVRC_PDU_INFORM_DISPLAY_CHARSET:
         {
             tAVRC_RESPONSE avrc_rsp;
-            BTIF_TRACE_EVENT("%s() AVRC_PDU_INFORM_DISPLAY_CHARSET", __func__);
-            if (btif_rc_cb.rc_connected == true)
+            BTIF_TRACE_EVENT("%s: AVRC_PDU_INFORM_DISPLAY_CHARSET", __func__);
+            if (p_dev->rc_connected == true)
             {
                 memset(&(avrc_rsp.inform_charset), 0, sizeof(tAVRC_RSP));
-                avrc_rsp.inform_charset.opcode=opcode_from_pdu(AVRC_PDU_INFORM_DISPLAY_CHARSET);
-                avrc_rsp.inform_charset.pdu=AVRC_PDU_INFORM_DISPLAY_CHARSET;
-                avrc_rsp.inform_charset.status=AVRC_STS_NO_ERROR;
-                send_metamsg_rsp(btif_rc_cb.rc_handle, label, ctype, &avrc_rsp);
+                avrc_rsp.inform_charset.opcode = opcode_from_pdu(AVRC_PDU_INFORM_DISPLAY_CHARSET);
+                avrc_rsp.inform_charset.pdu = AVRC_PDU_INFORM_DISPLAY_CHARSET;
+                avrc_rsp.inform_charset.status = AVRC_STS_NO_ERROR;
+                send_metamsg_rsp(p_dev, -1, label, ctype, &avrc_rsp);
+            }
+        }
+        break;
+
+        case AVRC_PDU_GET_FOLDER_ITEMS:
+        {
+            uint32_t attr_ids[BTRC_MAX_ELEM_ATTR_SIZE];
+            uint8_t num_attr;
+            num_attr = pavrc_cmd->get_items.attr_count;
+
+            BTIF_TRACE_EVENT("%s: AVRC_PDU_GET_FOLDER_ITEMS num_attr: %d, start_item [%d] \
+                end_item [%d]", __func__, num_attr, pavrc_cmd->get_items.start_item,
+                pavrc_cmd->get_items.end_item);
+
+            /* num_attr requested:
+             *     0x00: All attributes requested
+             *     0xFF: No Attributes requested
+             *     0x01 to 0x07: Specified number of attributes
+             */
+            if ((num_attr != 0xFF &&  num_attr > BTRC_MAX_ELEM_ATTR_SIZE)) {
+                send_reject_response (p_dev->rc_handle, label, pavrc_cmd->pdu,
+                    AVRC_STS_BAD_PARAM, pavrc_cmd->cmd.opcode);
+                return;
+            }
+
+            /* Except num_attr is None(0xff) / All(0x00), request follows with an Attribute List */
+            if ((num_attr != 0xFF) && (num_attr != 0x00)) {
+                memcpy(attr_ids, pavrc_cmd->get_items.p_attr_list, sizeof(uint32_t)*num_attr);
             }
+
+            fill_pdu_queue(IDX_GET_FOLDER_ITEMS_RSP, ctype, label, true, p_dev);
+            HAL_CBACK(bt_rc_callbacks, get_folder_items_cb, pavrc_cmd->get_items.scope,
+                pavrc_cmd->get_items.start_item, pavrc_cmd->get_items.end_item,
+                num_attr, attr_ids, &rc_addr);
+        }
+        break;
+
+        case AVRC_PDU_SET_ADDRESSED_PLAYER:
+        {
+            fill_pdu_queue(IDX_SET_ADDR_PLAYER_RSP, ctype, label, true, p_dev);
+            HAL_CBACK(bt_rc_callbacks, set_addressed_player_cb, pavrc_cmd->addr_player.player_id,
+                &rc_addr);
+        }
+        break;
+
+        case AVRC_PDU_SET_BROWSED_PLAYER:
+        {
+            fill_pdu_queue(IDX_SET_BROWSED_PLAYER_RSP, ctype, label, true, p_dev);
+            HAL_CBACK(bt_rc_callbacks, set_browsed_player_cb, pavrc_cmd->br_player.player_id,
+                &rc_addr);
         }
         break;
 
@@ -1472,14 +1779,14 @@ static void btif_rc_upstreams_evt(uint16_t event, tAVRC_COMMAND *pavrc_cmd, uint
             BTIF_TRACE_EVENT("%s() REQUEST CONTINUATION: target_pdu: 0x%02d",
                              __func__, pavrc_cmd->continu.target_pdu);
             tAVRC_RESPONSE avrc_rsp;
-            if (btif_rc_cb.rc_connected == TRUE)
+            if (p_dev->rc_connected == TRUE)
             {
                 memset(&(avrc_rsp.continu), 0, sizeof(tAVRC_NEXT_RSP));
                 avrc_rsp.continu.opcode = opcode_from_pdu(AVRC_PDU_REQUEST_CONTINUATION_RSP);
                 avrc_rsp.continu.pdu = AVRC_PDU_REQUEST_CONTINUATION_RSP;
                 avrc_rsp.continu.status = AVRC_STS_NO_ERROR;
                 avrc_rsp.continu.target_pdu = pavrc_cmd->continu.target_pdu;
-                send_metamsg_rsp(btif_rc_cb.rc_handle, label, ctype, &avrc_rsp);
+                send_metamsg_rsp(p_dev, -1, label, ctype, &avrc_rsp);
             }
         }
         break;
@@ -1489,23 +1796,107 @@ static void btif_rc_upstreams_evt(uint16_t event, tAVRC_COMMAND *pavrc_cmd, uint
             BTIF_TRACE_EVENT("%s() ABORT CONTINUATION: target_pdu: 0x%02d",
                              __func__, pavrc_cmd->abort.target_pdu);
             tAVRC_RESPONSE avrc_rsp;
-            if (btif_rc_cb.rc_connected == TRUE)
+            if (p_dev->rc_connected == TRUE)
             {
                 memset(&(avrc_rsp.abort), 0, sizeof(tAVRC_NEXT_RSP));
                 avrc_rsp.abort.opcode = opcode_from_pdu(AVRC_PDU_ABORT_CONTINUATION_RSP);
                 avrc_rsp.abort.pdu = AVRC_PDU_ABORT_CONTINUATION_RSP;
                 avrc_rsp.abort.status = AVRC_STS_NO_ERROR;
                 avrc_rsp.abort.target_pdu = pavrc_cmd->continu.target_pdu;
-                send_metamsg_rsp(btif_rc_cb.rc_handle, label, ctype, &avrc_rsp);
+                send_metamsg_rsp(p_dev, -1, label, ctype, &avrc_rsp);
             }
         }
         break;
 
+        case AVRC_PDU_CHANGE_PATH:
+        {
+            fill_pdu_queue(IDX_CHG_PATH_RSP, ctype, label, true, p_dev);
+            HAL_CBACK(bt_rc_callbacks, change_path_cb, pavrc_cmd->chg_path.direction,
+                    pavrc_cmd->chg_path.folder_uid, &rc_addr);
+        }
+        break;
+
+        case AVRC_PDU_SEARCH:
+        {
+            fill_pdu_queue(IDX_SEARCH_RSP, ctype, label, true, p_dev);
+            HAL_CBACK(bt_rc_callbacks, search_cb, pavrc_cmd->search.string.charset_id,
+                pavrc_cmd->search.string.str_len, pavrc_cmd->search.string.p_str, &rc_addr);
+        }
+        break;
+
+        case AVRC_PDU_GET_ITEM_ATTRIBUTES:
+        {
+            btrc_media_attr_t item_attrs[BTRC_MAX_ELEM_ATTR_SIZE];
+            uint8_t num_attr;
+            uint8_t scope;
+            uint16_t uid_counter;
+
+            scope = pavrc_cmd->get_attrs.scope;
+            uid_counter = pavrc_cmd->get_attrs.uid_counter;
+            memset(&item_attrs, 0, sizeof(item_attrs));
+
+            if (pavrc_cmd->get_attrs.attr_count == 0xFF)
+            {
+                BTIF_TRACE_ERROR("%s: No attributes are requested in GET_ITEM_ATTRIBUTES", __func__);
+                /* 0xff indicates, no attributes requested - reject this */
+                send_reject_response (p_dev->rc_handle, label, pavrc_cmd->pdu,
+                    AVRC_STS_BAD_PARAM, pavrc_cmd->cmd.opcode);
+                return;
+            }
+
+            if (pavrc_cmd->get_attrs.attr_count == 0)
+            {
+                /* CT requests for all attributes */
+                int attr_cnt;
+                num_attr = BTRC_MAX_ELEM_ATTR_SIZE;
+                for (attr_cnt = 0; attr_cnt < BTRC_MAX_ELEM_ATTR_SIZE; attr_cnt++)
+                {
+                    item_attrs[attr_cnt] = (btrc_media_attr_t)(attr_cnt + 1);
+                }
+            }
+            else
+            {
+                num_attr = pavrc_cmd->get_attrs.attr_count;
+                memcpy(item_attrs, pavrc_cmd->get_attrs.p_attr_list, sizeof(uint32_t)
+                        *pavrc_cmd->get_attrs.attr_count);
+            }
+            fill_pdu_queue(IDX_GET_ITEM_ATTR_RSP, ctype, label, true, p_dev);
+            BTIF_TRACE_DEBUG("%s: GET_ITEM_ATTRIBUTES: num_attr: %d", __func__, num_attr);
+            HAL_CBACK(bt_rc_callbacks, get_item_attr_cb, scope, pavrc_cmd->get_attrs.uid,
+                    uid_counter, num_attr, item_attrs, &rc_addr);
+        }
+        break;
+
+        case AVRC_PDU_GET_TOTAL_NUM_OF_ITEMS:
+        {
+            fill_pdu_queue(IDX_GET_TOTAL_NUM_OF_ITEMS_RSP, ctype, label, true, p_dev);
+            HAL_CBACK(bt_rc_callbacks, get_total_num_of_items_cb,
+                    pavrc_cmd->get_num_of_items.scope, &rc_addr);
+        }
+        break;
+
+        case AVRC_PDU_ADD_TO_NOW_PLAYING:
+        {
+            fill_pdu_queue(IDX_ADD_TO_NOW_PLAYING_RSP, ctype, label, true, p_dev);
+            HAL_CBACK(bt_rc_callbacks, add_to_now_playing_cb, pavrc_cmd->add_to_play.scope,
+                        pavrc_cmd->add_to_play.uid, pavrc_cmd->add_to_play.uid_counter,
+                        &rc_addr);
+        }
+        break;
+
+        case AVRC_PDU_PLAY_ITEM:
+        {
+            fill_pdu_queue(IDX_PLAY_ITEM_RSP, ctype, label, true, p_dev);
+            HAL_CBACK(bt_rc_callbacks, play_item_cb, pavrc_cmd->play_item.scope,
+                pavrc_cmd->play_item.uid_counter, pavrc_cmd->play_item.uid, &rc_addr);
+        }
+        break;
+
         default:
         {
-        send_reject_response (btif_rc_cb.rc_handle, label, pavrc_cmd->pdu,
-            (pavrc_cmd->pdu == AVRC_PDU_SEARCH)?AVRC_STS_SEARCH_NOT_SUP:AVRC_STS_BAD_CMD);
-        return;
+            send_reject_response(p_dev->rc_handle, label, pavrc_cmd->pdu, AVRC_STS_BAD_CMD,
+                pavrc_cmd->cmd.opcode);
+            return;
         }
         break;
     }
@@ -1522,12 +1913,12 @@ static void btif_rc_upstreams_evt(uint16_t event, tAVRC_COMMAND *pavrc_cmd, uint
 **
 *******************************************************************************/
 static void btif_rc_ctrl_upstreams_rsp_cmd(uint8_t event, tAVRC_COMMAND *pavrc_cmd,
-        uint8_t label)
+        uint8_t label, btif_rc_device_cb_t *p_dev)
 {
-    BTIF_TRACE_DEBUG("%s pdu: %s handle: 0x%x", __func__,
-        dump_rc_pdu(pavrc_cmd->pdu), btif_rc_cb.rc_handle);
+    BTIF_TRACE_DEBUG("%s: pdu: %s: handle: 0x%x", __func__,
+        dump_rc_pdu(pavrc_cmd->pdu), p_dev->rc_handle);
     bt_bdaddr_t rc_addr;
-    bdcpy(rc_addr.address, btif_rc_cb.rc_addr);
+    bdcpy(rc_addr.address, p_dev->rc_addr);
     switch (event)
     {
     case AVRC_PDU_SET_ABSOLUTE_VOLUME:
@@ -1545,7 +1936,6 @@ static void btif_rc_ctrl_upstreams_rsp_cmd(uint8_t event, tAVRC_COMMAND *pavrc_c
 }
 #endif
 
-#if (AVRC_ADV_CTRL_INCLUDED == TRUE)
 /*******************************************************************************
 **
 ** Function         btif_rc_upstreams_rsp_evt
@@ -1555,235 +1945,887 @@ static void btif_rc_ctrl_upstreams_rsp_cmd(uint8_t event, tAVRC_COMMAND *pavrc_c
 ** Returns          void
 **
 *******************************************************************************/
-static void btif_rc_upstreams_rsp_evt(uint16_t event, tAVRC_RESPONSE *pavrc_resp, uint8_t ctype, uint8_t label)
+static void btif_rc_upstreams_rsp_evt(uint16_t event, tAVRC_RESPONSE *pavrc_resp, uint8_t ctype,
+                                            uint8_t label, btif_rc_device_cb_t *p_dev)
 {
-    BTIF_TRACE_EVENT("%s pdu: %s handle: 0x%x ctype:%x label:%x", __func__,
-        dump_rc_pdu(pavrc_resp->pdu), btif_rc_cb.rc_handle, ctype, label);
+    BTIF_TRACE_EVENT("%s: pdu: %s: handle: 0x%x ctype: %x label: %x", __func__,
+        dump_rc_pdu(pavrc_resp->pdu), p_dev->rc_handle, ctype, label);
+    bt_bdaddr_t rc_addr;
+    bdcpy(rc_addr.address, p_dev->rc_addr);
 
+#if (AVRC_ADV_CTRL_INCLUDED == TRUE)
     switch (event)
     {
         case AVRC_PDU_REGISTER_NOTIFICATION:
         {
-             if (AVRC_RSP_CHANGED==ctype)
-                 btif_rc_cb.rc_volume=pavrc_resp->reg_notif.param.volume;
-             HAL_CBACK(bt_rc_callbacks, volume_change_cb, pavrc_resp->reg_notif.param.volume,ctype)
+             if (AVRC_RSP_CHANGED == ctype)
+                 p_dev->rc_volume = pavrc_resp->reg_notif.param.volume;
+             HAL_CBACK(bt_rc_callbacks, volume_change_cb, pavrc_resp->reg_notif.param.volume,
+                ctype, &rc_addr)
         }
         break;
 
-        case AVRC_PDU_SET_ABSOLUTE_VOLUME:
-        {
-            BTIF_TRACE_DEBUG("%s Set absolute volume change event received: volume %d,ctype %d",
-                             __func__, pavrc_resp->volume.volume,ctype);
-            if (AVRC_RSP_ACCEPT==ctype)
-                btif_rc_cb.rc_volume=pavrc_resp->volume.volume;
-            HAL_CBACK(bt_rc_callbacks,volume_change_cb,pavrc_resp->volume.volume,ctype)
-        }
-        break;
+        case AVRC_PDU_SET_ABSOLUTE_VOLUME:
+        {
+            BTIF_TRACE_DEBUG("%s: Set absolute volume change event received: volume: %d, ctype: %d",
+                             __func__, pavrc_resp->volume.volume, ctype);
+            if (AVRC_RSP_ACCEPT == ctype)
+                p_dev->rc_volume = pavrc_resp->volume.volume;
+            HAL_CBACK(bt_rc_callbacks, volume_change_cb, pavrc_resp->volume.volume, ctype,
+                &rc_addr);
+        }
+        break;
+
+        default:
+            return;
+    }
+#endif
+}
+
+/************************************************************************************
+**  AVRCP API Functions
+************************************************************************************/
+
+/*******************************************************************************
+**
+** Function         init
+**
+** Description      Initializes the AVRC interface
+**
+** Returns          bt_status_t
+**
+*******************************************************************************/
+static bt_status_t init(btrc_callbacks_t* callbacks)
+{
+    BTIF_TRACE_EVENT("%s: ", __func__);
+    bt_status_t result = BT_STATUS_SUCCESS;
+
+    if (bt_rc_callbacks)
+        return BT_STATUS_DONE;
+
+    bt_rc_callbacks = callbacks;
+    for (int idx = 0; idx < BTIF_RC_NUM_CONN; idx++)
+    {
+        memset (&btif_rc_cb.rc_multi_cb[idx], 0, sizeof(btif_rc_cb.rc_multi_cb[idx]));
+        btif_rc_cb.rc_multi_cb[idx].rc_vol_label = MAX_LABEL;
+        btif_rc_cb.rc_multi_cb[idx].rc_volume = MAX_VOLUME;
+        btif_rc_cb.rc_multi_cb[idx].rc_state = BTRC_CONNECTION_STATE_DISCONNECTED;
+    }
+    lbl_init();
+
+    return result;
+}
+
+/*******************************************************************************
+**
+** Function         init_ctrl
+**
+** Description      Initializes the AVRC interface
+**
+** Returns          bt_status_t
+**
+*******************************************************************************/
+static bt_status_t init_ctrl(btrc_ctrl_callbacks_t* callbacks)
+{
+    BTIF_TRACE_EVENT("%s: ", __func__);
+    bt_status_t result = BT_STATUS_SUCCESS;
+
+    if (bt_rc_ctrl_callbacks)
+        return BT_STATUS_DONE;
+
+    bt_rc_ctrl_callbacks = callbacks;
+    for (int idx = 0; idx < BTIF_RC_NUM_CONN; idx++)
+    {
+        memset (&btif_rc_cb.rc_multi_cb[idx], 0, sizeof(btif_rc_cb.rc_multi_cb[idx]));
+        btif_rc_cb.rc_multi_cb[idx].rc_vol_label = MAX_LABEL;
+        btif_rc_cb.rc_multi_cb[idx].rc_volume = MAX_VOLUME;
+    }
+    lbl_init();
+
+    return result;
+}
+
+static void rc_ctrl_procedure_complete(btif_rc_device_cb_t *p_dev)
+{
+    if (p_dev == NULL)
+    {
+        BTIF_TRACE_ERROR("%s: p_dev NULL", __func__);
+        return;
+    }
+
+    if (p_dev->rc_procedure_complete == true)
+    {
+        return;
+    }
+    p_dev->rc_procedure_complete = true;
+    uint32_t attr_list[] = {
+            AVRC_MEDIA_ATTR_ID_TITLE,
+            AVRC_MEDIA_ATTR_ID_ARTIST,
+            AVRC_MEDIA_ATTR_ID_ALBUM,
+            AVRC_MEDIA_ATTR_ID_TRACK_NUM,
+            AVRC_MEDIA_ATTR_ID_NUM_TRACKS,
+            AVRC_MEDIA_ATTR_ID_GENRE,
+            AVRC_MEDIA_ATTR_ID_PLAYING_TIME
+            };
+    get_element_attribute_cmd (AVRC_MAX_NUM_MEDIA_ATTR_ID, attr_list, p_dev);
+}
+
+/***************************************************************************
+**
+** Function         get_play_status_rsp
+**
+** Description      Returns the current play status.
+**                      This method is called in response to
+**                      GetPlayStatus request.
+**
+** Returns          bt_status_t
+**
+***************************************************************************/
+static bt_status_t get_play_status_rsp(bt_bdaddr_t *bd_addr, btrc_play_status_t play_status,
+    uint32_t song_len, uint32_t song_pos)
+{
+    tAVRC_RESPONSE avrc_rsp;
+    btif_rc_device_cb_t *p_dev = btif_rc_get_device_by_bda(bd_addr);
+
+    CHECK_RC_CONNECTED(p_dev)
+    memset(&(avrc_rsp.get_play_status), 0, sizeof(tAVRC_GET_PLAY_STATUS_RSP));
+
+    avrc_rsp.get_play_status.song_len = song_len;
+    avrc_rsp.get_play_status.song_pos = song_pos;
+    avrc_rsp.get_play_status.play_status = play_status;
+
+    avrc_rsp.get_play_status.pdu = AVRC_PDU_GET_PLAY_STATUS;
+    avrc_rsp.get_play_status.opcode = opcode_from_pdu(AVRC_PDU_GET_PLAY_STATUS);
+    avrc_rsp.get_play_status.status = ((play_status != BTRC_PLAYSTATE_ERROR)?
+        AVRC_STS_NO_ERROR:AVRC_STS_BAD_PARAM);
+
+    /* Send the response */
+    send_metamsg_rsp(p_dev, IDX_GET_PLAY_STATUS_RSP,
+        p_dev->rc_pdu_info[IDX_GET_PLAY_STATUS_RSP].label, p_dev->rc_pdu_info[IDX_GET_PLAY_STATUS_RSP].ctype,
+        &avrc_rsp);
+
+    return BT_STATUS_SUCCESS;
+}
+
+/***************************************************************************
+**
+** Function         get_element_attr_rsp
+**
+** Description      Returns the current songs' element attributes
+**                      in text.
+**
+** Returns          bt_status_t
+**
+***************************************************************************/
+static bt_status_t get_element_attr_rsp(bt_bdaddr_t *bd_addr, uint8_t num_attr,
+        btrc_element_attr_val_t *p_attrs)
+{
+    tAVRC_RESPONSE avrc_rsp;
+    uint32_t i;
+    tAVRC_ATTR_ENTRY element_attrs[BTRC_MAX_ELEM_ATTR_SIZE];
+    btif_rc_device_cb_t *p_dev = btif_rc_get_device_by_bda(bd_addr);
+
+    CHECK_RC_CONNECTED(p_dev)
+    memset(element_attrs, 0, sizeof(tAVRC_ATTR_ENTRY) * num_attr);
+    BTIF_TRACE_ERROR("%s: calling btif_rc_get_device_by_bda",__func__);
+
+    if (num_attr == 0)
+    {
+        avrc_rsp.get_play_status.status = AVRC_STS_BAD_PARAM;
+    }
+    else
+    {
+        for (i=0; i<num_attr; i++) {
+            element_attrs[i].attr_id = p_attrs[i].attr_id;
+            element_attrs[i].name.charset_id = AVRC_CHARSET_ID_UTF8;
+            element_attrs[i].name.str_len = (uint16_t)strlen((char *)p_attrs[i].text);
+            element_attrs[i].name.p_str = p_attrs[i].text;
+            BTIF_TRACE_DEBUG("%s: attr_id: 0x%x, charset_id: 0x%x, str_len: %d, str: %s",
+                             __func__, (unsigned int)element_attrs[i].attr_id,
+                             element_attrs[i].name.charset_id, element_attrs[i].name.str_len,
+                             element_attrs[i].name.p_str);
+        }
+        avrc_rsp.get_play_status.status = AVRC_STS_NO_ERROR;
+    }
+    avrc_rsp.get_elem_attrs.num_attr = num_attr;
+    avrc_rsp.get_elem_attrs.p_attrs = element_attrs;
+    avrc_rsp.get_elem_attrs.pdu = AVRC_PDU_GET_ELEMENT_ATTR;
+    avrc_rsp.get_elem_attrs.opcode = opcode_from_pdu(AVRC_PDU_GET_ELEMENT_ATTR);
+
+    /* Send the response */
+    send_metamsg_rsp(p_dev, IDX_GET_ELEMENT_ATTR_RSP,
+        p_dev->rc_pdu_info[IDX_GET_ELEMENT_ATTR_RSP].label, p_dev->rc_pdu_info[IDX_GET_ELEMENT_ATTR_RSP].ctype,
+        &avrc_rsp);
+
+    return BT_STATUS_SUCCESS;
+}
+
+/***************************************************************************
+**
+** Function         reject_pending_notification
+**
+** Description      Utility function to reject a pending notification. When AddressedPlayer
+**                  change is received, all pending notifications should be completed.
+**
+** Returns          void
+**
+***************************************************************************/
+static void reject_pending_notification (btrc_event_id_t event_id, int idx)
+{
+    tAVRC_RESPONSE avrc_rsp;
+    memset(&(avrc_rsp.reg_notif), 0, sizeof(tAVRC_REG_NOTIF_RSP));
+
+    avrc_rsp.reg_notif.event_id = event_id;
+    avrc_rsp.reg_notif.pdu = AVRC_PDU_REGISTER_NOTIFICATION;
+    avrc_rsp.reg_notif.opcode = opcode_from_pdu(AVRC_PDU_REGISTER_NOTIFICATION);
+    avrc_rsp.reg_notif.status = AVRC_STS_ADDR_PLAYER_CHG;
+    BTIF_TRACE_WARNING("%s: Handling event ID: 0x%x", __func__, event_id);
+
+    send_metamsg_rsp(&btif_rc_cb.rc_multi_cb[idx], -1,
+        btif_rc_cb.rc_multi_cb[idx].rc_notif[event_id-1].label, AVRC_RSP_REJ,
+        &avrc_rsp);
+}
+
+/***************************************************************************
+**
+** Function         register_notification_rsp
+**
+** Description      Response to the register notification request.
+**
+** Returns          bt_status_t
+**
+***************************************************************************/
+static bt_status_t register_notification_rsp(btrc_event_id_t event_id,
+    btrc_notification_type_t type, btrc_register_notification_t *p_param)
+{
+    tAVRC_RESPONSE avrc_rsp;
+    BTIF_TRACE_EVENT("%s: event_id: %s", __func__, dump_rc_notification_event_id(event_id));
+    pthread_mutex_lock(&btif_rc_cb.lock);
+
+    memset(&(avrc_rsp.reg_notif), 0, sizeof(tAVRC_REG_NOTIF_RSP));
+
+    avrc_rsp.reg_notif.event_id = event_id;
+    avrc_rsp.reg_notif.pdu = AVRC_PDU_REGISTER_NOTIFICATION;
+    avrc_rsp.reg_notif.opcode = opcode_from_pdu(AVRC_PDU_REGISTER_NOTIFICATION);
+    avrc_rsp.get_play_status.status = AVRC_STS_NO_ERROR;
+
+    for (int idx = 0; idx < BTIF_RC_NUM_CONN; idx++)
+    {
+        memset(&(avrc_rsp.reg_notif.param), 0, sizeof(tAVRC_NOTIF_RSP_PARAM));
+
+        if (!(btif_rc_cb.rc_multi_cb[idx].rc_connected))
+        {
+            BTIF_TRACE_ERROR("%s: Avrcp device is not connected, handle: 0x%x", __func__,
+                    btif_rc_cb.rc_multi_cb[idx].rc_handle);
+            continue;
+        }
+
+        if (btif_rc_cb.rc_multi_cb[idx].rc_notif[event_id-1].bNotify == false)
+        {
+            BTIF_TRACE_WARNING("%s: Avrcp Event id is not registered: event_id: %x, handle: 0x%x",
+                    __func__, event_id, btif_rc_cb.rc_multi_cb[idx].rc_handle);
+            continue;
+        }
+
+        BTIF_TRACE_DEBUG("%s: Avrcp Event id is registered: event_id: %x handle: 0x%x",
+            __func__, event_id, btif_rc_cb.rc_multi_cb[idx].rc_handle);
+
+        switch (event_id)
+        {
+            case BTRC_EVT_PLAY_STATUS_CHANGED:
+                avrc_rsp.reg_notif.param.play_status = p_param->play_status;
+                if (avrc_rsp.reg_notif.param.play_status == PLAY_STATUS_PLAYING)
+                    btif_av_clear_remote_suspend_flag();
+                break;
+            case BTRC_EVT_TRACK_CHANGE:
+                memcpy(&(avrc_rsp.reg_notif.param.track), &(p_param->track),
+                    sizeof(btrc_uid_t));
+                break;
+            case BTRC_EVT_PLAY_POS_CHANGED:
+                avrc_rsp.reg_notif.param.play_pos = p_param->song_pos;
+                break;
+            case BTRC_EVT_AVAL_PLAYER_CHANGE:
+                break;
+            case BTRC_EVT_ADDR_PLAYER_CHANGE:
+                avrc_rsp.reg_notif.param.addr_player.player_id =
+                    p_param->addr_player_changed.player_id;
+                avrc_rsp.reg_notif.param.addr_player.uid_counter =
+                    p_param->addr_player_changed.uid_counter;
+                break;
+            case BTRC_EVT_UIDS_CHANGED:
+                avrc_rsp.reg_notif.param.uid_counter = p_param->uids_changed.uid_counter;
+                break;
+            case BTRC_EVT_NOW_PLAYING_CONTENT_CHANGED:
+                break;
+
+            default:
+                BTIF_TRACE_WARNING("%s: Unhandled event ID: 0x%x", __func__, event_id);
+                pthread_mutex_unlock(&btif_rc_cb.lock);
+                return BT_STATUS_UNHANDLED;
+        }
+
+        /* Send the response. */
+        send_metamsg_rsp(&btif_rc_cb.rc_multi_cb[idx], -1,
+            btif_rc_cb.rc_multi_cb[idx].rc_notif[event_id-1].label,
+            ((type == BTRC_NOTIFICATION_TYPE_INTERIM)?AVRC_CMD_NOTIF:AVRC_RSP_CHANGED),
+            &avrc_rsp);
+
+        /* if notification type is address player changed, then complete all player specific
+        * notifications with AV/C C-Type REJECTED with error code Addressed Player Changed. */
+        if(event_id == BTRC_EVT_ADDR_PLAYER_CHANGE && type == BTRC_NOTIFICATION_TYPE_CHANGED)
+        {
+            /* array includes notifications to be completed on addressed player change */
+            btrc_event_id_t evt_id[] = {BTRC_EVT_PLAY_STATUS_CHANGED,
+                                        BTRC_EVT_TRACK_CHANGE,
+                                        BTRC_EVT_PLAY_POS_CHANGED,
+                                        BTRC_EVT_NOW_PLAYING_CONTENT_CHANGED};
+            for (uint8_t id = 0; id < sizeof(evt_id) / sizeof((evt_id)[0]); id++)
+            {
+                reject_pending_notification(evt_id[id], idx);
+            }
+        }
+    }
+    pthread_mutex_unlock(&btif_rc_cb.lock);
+    return BT_STATUS_SUCCESS;
+}
+
+/***************************************************************************
+**
+** Function         get_folder_items_list_rsp
+**
+** Description      Returns the list of media items in current folder along with requested
+**                  attributes. This is called in response to GetFolderItems request.
+**
+** Returns          bt_status_t
+**                      BT_STATUS_NOT_READY - when RC is not connected.
+**                      BT_STATUS_SUCCESS   - always if RC is connected
+**                      BT_STATUS_UNHANDLED - when rsp is not pending for get_folder_items_list PDU
+**
+***************************************************************************/
+static bt_status_t get_folder_items_list_rsp(bt_bdaddr_t *bd_addr, btrc_status_t rsp_status,
+                uint16_t uid_counter, uint8_t num_items, btrc_folder_items_t *p_items)
+{
+    tAVRC_RESPONSE avrc_rsp;
+    tAVRC_ITEM item;
+    tBTA_AV_CODE code = 0, ctype = 0;
+    BT_HDR *p_msg = NULL;
+    int item_cnt;
+    tAVRC_STS status = AVRC_STS_NO_ERROR;
+    btif_rc_device_cb_t *p_dev = btif_rc_get_device_by_bda(bd_addr);
+    btrc_folder_items_t* cur_item = NULL;
+
+    CHECK_RC_CONNECTED(p_dev)
+
+    /* check if rsp to previous cmd was completed */
+    if (p_dev->rc_pdu_info[IDX_GET_FOLDER_ITEMS_RSP].is_rsp_pending == false)
+    {
+        BTIF_TRACE_WARNING("%s: Not sending response as no PDU was registered", __func__); \
+        return BT_STATUS_UNHANDLED;
+    }
+
+    memset(&avrc_rsp, 0, sizeof(tAVRC_RESPONSE));
+    memset(&item, 0, sizeof(tAVRC_ITEM));
+
+    avrc_rsp.get_items.pdu = AVRC_PDU_GET_FOLDER_ITEMS;
+    avrc_rsp.get_items.opcode = opcode_from_pdu(AVRC_PDU_GET_FOLDER_ITEMS);
+    avrc_rsp.get_items.status = status_code_map[rsp_status];
+
+    if (avrc_rsp.get_items.status != AVRC_STS_NO_ERROR)
+    {
+        BTIF_TRACE_WARNING("%s: Error in parsing the received getfolderitems cmd. status: 0x%02x",
+                __func__, avrc_rsp.get_items.status);
+        status = avrc_rsp.get_items.status;
+    }
+    else
+    {
+        avrc_rsp.get_items.uid_counter = uid_counter;
+        avrc_rsp.get_items.item_count = 1;
+
+        /* create single item and build response iteratively for all num_items */
+        for (item_cnt=0; item_cnt < num_items; item_cnt++)
+        {
+            cur_item = &p_items[item_cnt];
+            item.item_type = p_items->item_type;
+            /* build respective item based on item_type. All items should be of same type within
+             * a response */
+            switch (p_items->item_type)
+            {
+                case AVRC_ITEM_PLAYER:
+                {
+                    item.u.player.name.charset_id = cur_item->player.charset_id;
+                    memcpy(&(item.u.player.features), \
+                        &(cur_item->player.features), \
+                        sizeof(cur_item->player.features));
+                    item.u.player.major_type = cur_item->player.major_type;
+                    item.u.player.sub_type = cur_item->player.sub_type;
+                    item.u.player.play_status = cur_item->player.play_status;
+                    item.u.player.player_id = cur_item->player.player_id;
+                    item.u.player.name.p_str = cur_item->player.name;
+                    item.u.player.name.str_len = \
+                        (uint16_t)strlen((char*)(cur_item->player.name));
+                }
+                break;
+
+                case AVRC_ITEM_FOLDER:
+                {
+                    memcpy(item.u.folder.uid, cur_item->folder.uid,
+                        sizeof(tAVRC_UID));
+                    item.u.folder.type = cur_item->folder.type;
+                    item.u.folder.playable = cur_item->folder.playable;
+                    item.u.folder.name.charset_id = AVRC_CHARSET_ID_UTF8;
+                    item.u.folder.name.str_len =
+                        strlen((char*)cur_item->folder.name);
+                    item.u.folder.name.p_str = cur_item->folder.name;
+                }
+                break;
+
+                case AVRC_ITEM_MEDIA:
+                {
+                    tAVRC_ATTR_ENTRY attr_vals[BTRC_MAX_ELEM_ATTR_SIZE];
+
+                    memcpy(item.u.media.uid, cur_item->media.uid, sizeof(tAVRC_UID));
+                    item.u.media.type = cur_item->media.type;
+                    item.u.media.name.charset_id = cur_item->media.charset_id;
+                    item.u.media.name.str_len = strlen((char*)cur_item->media.name);
+                    item.u.media.name.p_str = cur_item->media.name;
+                    item.u.media.attr_count = cur_item->media.num_attrs;
+
+                    /* Handle attributes of given item */
+                    if(item.u.media.attr_count == 0)
+                    {
+                        item.u.media.p_attr_list = NULL;
+                    }
+                    else
+                    {
+                        memset(&attr_vals, 0, sizeof(tAVRC_ATTR_ENTRY)*BTRC_MAX_ELEM_ATTR_SIZE);
+                        fill_avrc_attr_entry(attr_vals, item.u.media.attr_count,
+                                cur_item->media.p_attrs);
+                        item.u.media.p_attr_list = attr_vals;
+                    }
+                }
+                break;
+
+                default:
+                {
+                    BTIF_TRACE_ERROR ("%s: Unknown item_type: %d. Internal Error", __func__, p_items->item_type);
+                    status = AVRC_STS_INTERNAL_ERR;
+                }
+                break;
+            }
+
+            avrc_rsp.get_items.p_item_list = &item;
+
+            /* Add current item to buffer and build response if no error in item type */
+            if (status != AVRC_STS_NO_ERROR)
+            {
+                /* Reject response due to error occured for unknown item_type, break the loop */
+                break;
+            }
+
+            int len_before = p_msg ? p_msg->len : 0;
+            BTIF_TRACE_DEBUG ("%s: item_cnt: %d len: %d", __func__, item_cnt, len_before);
+            status = AVRC_BldResponse(p_dev->rc_handle, &avrc_rsp, &p_msg);
+            BTIF_TRACE_DEBUG ("%s: Build rsp status: %d len: %d", __func__, status,
+                    (p_msg ? p_msg->len : 0));
+            int len_after = p_msg ? p_msg->len : 0;
+            if (status != AVRC_STS_NO_ERROR || len_before == len_after)
+            {
+                /* Error occured in build response or we ran out of buffer so break the loop */
+                break;
+            }
+        }
+
+        /* setting the error status */
+        avrc_rsp.get_items.status = status;
+    }
+
+    /* if packet built successfully, send the built items to BTA layer */
+    if (status == AVRC_STS_NO_ERROR)
+    {
+        code = p_dev->rc_pdu_info[IDX_GET_FOLDER_ITEMS_RSP].ctype;
+        ctype = get_rsp_type_code(avrc_rsp.get_items.status, code);
+        BTA_AvMetaRsp(p_dev->rc_handle,
+                p_dev->rc_pdu_info[IDX_GET_FOLDER_ITEMS_RSP].label, ctype, p_msg);
+    }
+    else /* Error occured, send reject response */
+    {
+        BTIF_TRACE_ERROR("%s: Error status: 0x%02X. Sending reject rsp",
+                __func__, avrc_rsp.rsp.status);
+        send_reject_response(p_dev->rc_handle,
+                         p_dev->rc_pdu_info[IDX_GET_FOLDER_ITEMS_RSP].label,
+                         avrc_rsp.pdu, avrc_rsp.get_items.status, avrc_rsp.get_items.opcode);
+    }
+
+    /* Reset values for current pdu. */
+    p_dev->rc_pdu_info[IDX_GET_FOLDER_ITEMS_RSP].ctype = 0;
+    p_dev->rc_pdu_info[IDX_GET_FOLDER_ITEMS_RSP].label = 0;
+    p_dev->rc_pdu_info[IDX_GET_FOLDER_ITEMS_RSP].is_rsp_pending = false;
+
+    return status == AVRC_STS_NO_ERROR ? BT_STATUS_SUCCESS : BT_STATUS_FAIL;
+}
+
+/***************************************************************************
+**
+** Function         set_addressed_player_rsp
+**
+** Description      Response to set the addressed player for specified media player based on
+**                  id in the media player list.
+**
+** Returns          bt_status_t
+**                      BT_STATUS_NOT_READY - when RC is not connected.
+**                      BT_STATUS_SUCCESS   - always if RC is connected
+**
+***************************************************************************/
+static bt_status_t set_addressed_player_rsp(bt_bdaddr_t *bd_addr, btrc_status_t rsp_status)
+{
+    tAVRC_RESPONSE avrc_rsp;
+    btif_rc_device_cb_t *p_dev = btif_rc_get_device_by_bda(bd_addr);
+
+    CHECK_RC_CONNECTED(p_dev)
+
+    avrc_rsp.addr_player.pdu = AVRC_PDU_SET_ADDRESSED_PLAYER;
+    avrc_rsp.addr_player.opcode = opcode_from_pdu(AVRC_PDU_SET_ADDRESSED_PLAYER);
+    avrc_rsp.addr_player.status = status_code_map[rsp_status];
+
+    /* Send the response. */
+    send_metamsg_rsp(p_dev, IDX_SET_ADDR_PLAYER_RSP,
+        p_dev->rc_pdu_info[IDX_SET_ADDR_PLAYER_RSP].label, p_dev->rc_pdu_info[IDX_SET_ADDR_PLAYER_RSP].ctype,
+        &avrc_rsp);
+
+    return BT_STATUS_SUCCESS;
+}
+
+/***************************************************************************
+**
+** Function         set_browsed_player_rsp
+**
+** Description      Response to set the browsed player command which contains current browsed path
+**                  of the media player. By default, current_path = root and folder_depth = 0 for
+**                  every set_browsed_player request.
+**
+** Returns          bt_status_t
+**                      BT_STATUS_NOT_READY - when RC is not connected.
+**                      BT_STATUS_SUCCESS   - if RC is connected and reponse sent successfully
+**                      BT_STATUS_UNHANDLED - when rsp is not pending for set_browsed_player PDU
+**
+***************************************************************************/
+static bt_status_t set_browsed_player_rsp(bt_bdaddr_t *bd_addr, btrc_status_t rsp_status,
+    uint32_t num_items, uint16_t charset_id, uint8_t folder_depth, btrc_br_folder_name_t *p_folders)
+{
+    tAVRC_RESPONSE avrc_rsp;
+    tAVRC_NAME item;
+    BT_HDR *p_msg = NULL;
+    tBTA_AV_CODE code = 0;
+    tBTA_AV_CODE ctype = 0;
+    unsigned int item_cnt;
+    tAVRC_STS status = AVRC_STS_NO_ERROR;
+    btif_rc_device_cb_t *p_dev = btif_rc_get_device_by_bda(bd_addr);
+
+    CHECK_RC_CONNECTED(p_dev)
+
+    memset(&avrc_rsp, 0, sizeof(tAVRC_RESPONSE));
+    memset(&item, 0, sizeof(tAVRC_NAME));
+
+    avrc_rsp.br_player.status = status_code_map[rsp_status];
+    avrc_rsp.br_player.pdu = AVRC_PDU_SET_BROWSED_PLAYER;
+    avrc_rsp.br_player.opcode = opcode_from_pdu(AVRC_PDU_SET_BROWSED_PLAYER);
+
+    BTIF_TRACE_DEBUG("%s: rsp_status: 0x%02X avrc_rsp.br_player.status: 0x%02X", __func__, \
+        rsp_status, avrc_rsp.br_player.status);
+
+    /* check if rsp to previous cmd was completed */
+    if (p_dev->rc_pdu_info[IDX_SET_BROWSED_PLAYER_RSP].is_rsp_pending == false)
+    {
+        BTIF_TRACE_WARNING("%s: Not sending response as no PDU was registered", __func__);
+        return BT_STATUS_UNHANDLED;
+    }
+
+    if (AVRC_STS_NO_ERROR == avrc_rsp.get_items.status)
+    {
+        avrc_rsp.br_player.num_items = num_items;
+        avrc_rsp.br_player.charset_id = charset_id;
+        avrc_rsp.br_player.folder_depth = folder_depth;
+        avrc_rsp.br_player.p_folders = (tAVRC_NAME*) p_folders;
+
+        BTIF_TRACE_DEBUG("%s: folder_depth: 0x%02X num_items: %d", __func__,
+                folder_depth, num_items);
+
+        if (folder_depth > 0)
+        {
+            /* Iteratively build response for all folders across folder depth upto current path */
+            avrc_rsp.br_player.folder_depth = 1;
+            for(item_cnt=0; item_cnt < folder_depth; item_cnt++)
+            {
+                BTIF_TRACE_DEBUG("%s: iteration: %d", __func__, item_cnt);
+                item.str_len = p_folders[item_cnt].str_len;
+                item.p_str = p_folders[item_cnt].p_str;
+                avrc_rsp.br_player.p_folders = &item;
+
+                /* Add current item to buffer and build response */
+                status = AVRC_BldResponse(p_dev->rc_handle, &avrc_rsp, &p_msg);
+                if (AVRC_STS_NO_ERROR != status)
+                {
+                    BTIF_TRACE_WARNING("%s: Build rsp status: %d", __func__, status);
+                    /* if the build fails, it is likely that we ran out of buffer. so if we have
+                  * some items to send, reset this error to no error for sending what we have */
+                    if (item_cnt > 0)
+                        status = AVRC_STS_NO_ERROR;
+
+                    /* Error occured in build response so break the loop */
+                    break;
+                }
+            }
+        }
+        else /* current path is root folder, no folders navigated yet */
+        {
+            status = AVRC_BldResponse(p_dev->rc_handle, &avrc_rsp, &p_msg);
+        }
+
+        /* setting the error status */
+        avrc_rsp.br_player.status = status;
+    }
+    else /* error received from above layer */
+    {
+        BTIF_TRACE_WARNING("%s: Error in parsing the received setbrowsed command. status: 0x%02x",
+                __func__, avrc_rsp.br_player.status);
+        status = avrc_rsp.br_player.status;
+    }
+
+    /* if packet built successfully, send the built items to BTA layer */
+    if (status == AVRC_STS_NO_ERROR)
+    {
+        code = p_dev->rc_pdu_info[IDX_SET_BROWSED_PLAYER_RSP].ctype;
+        ctype  = get_rsp_type_code(avrc_rsp.br_player.status, code);
+        BTA_AvMetaRsp(p_dev->rc_handle,
+                p_dev->rc_pdu_info[IDX_SET_BROWSED_PLAYER_RSP].label, ctype, p_msg);
+    }
+    else /* Error occured, send reject response */
+    {
+        BTIF_TRACE_ERROR("%s: Error status: 0x%02X. Sending reject rsp",
+                __func__, avrc_rsp.br_player.status);
+        send_reject_response(p_dev->rc_handle,
+                         p_dev->rc_pdu_info[IDX_SET_BROWSED_PLAYER_RSP].label,
+                         avrc_rsp.pdu, avrc_rsp.br_player.status, avrc_rsp.get_items.opcode);
+    }
+
+    /* Reset values for set_browsed_player pdu.*/
+    p_dev->rc_pdu_info[IDX_SET_BROWSED_PLAYER_RSP].ctype = 0;
+    p_dev->rc_pdu_info[IDX_SET_BROWSED_PLAYER_RSP].label = 0;
+    p_dev->rc_pdu_info[IDX_SET_BROWSED_PLAYER_RSP].is_rsp_pending = false;
 
-        default:
-            return;
-    }
+    return status == AVRC_STS_NO_ERROR ? BT_STATUS_SUCCESS : BT_STATUS_FAIL;
 }
-#endif
 
-/************************************************************************************
-**  AVRCP API Functions
-************************************************************************************/
 
+#if (AVRC_ADV_CTRL_INCLUDED == TRUE)
 /*******************************************************************************
 **
-** Function         init
+** Function         change_path_rsp
 **
-** Description      Initializes the AVRC interface
+** Description      Response to the change path command which
+**                  contains number of items in the changed path.
 **
 ** Returns          bt_status_t
+**                      BT_STATUS_NOT_READY - when RC is not connected.
+**                      BT_STATUS_SUCCESS   - always if RC is connected
 **
-*******************************************************************************/
-static bt_status_t init(btrc_callbacks_t* callbacks )
+***************************************************************************/
+static bt_status_t change_path_rsp(bt_bdaddr_t *bd_addr, btrc_status_t rsp_status,
+            uint32_t num_items)
 {
-    BTIF_TRACE_EVENT("## %s ##", __func__);
-    bt_status_t result = BT_STATUS_SUCCESS;
+    tAVRC_RESPONSE avrc_rsp;
+    btif_rc_device_cb_t *p_dev = btif_rc_get_device_by_bda(bd_addr);
 
-    if (bt_rc_callbacks)
-        return BT_STATUS_DONE;
+    CHECK_RC_CONNECTED(p_dev)
 
-    bt_rc_callbacks = callbacks;
-    memset (&btif_rc_cb, 0, sizeof(btif_rc_cb));
-    btif_rc_cb.rc_vol_label=MAX_LABEL;
-    btif_rc_cb.rc_volume=MAX_VOLUME;
-    lbl_init();
+    avrc_rsp.chg_path.pdu = AVRC_PDU_CHANGE_PATH;
+    avrc_rsp.chg_path.opcode = opcode_from_pdu(AVRC_PDU_CHANGE_PATH);
+    avrc_rsp.chg_path.num_items = num_items;
+    avrc_rsp.chg_path.status = status_code_map[rsp_status];
 
-    return result;
+    /* Send the response. */
+    send_metamsg_rsp(p_dev, IDX_CHG_PATH_RSP,
+        p_dev->rc_pdu_info[IDX_CHG_PATH_RSP].label, p_dev->rc_pdu_info[IDX_CHG_PATH_RSP].ctype,
+        &avrc_rsp);
+
+    return BT_STATUS_SUCCESS;
 }
+#endif
 
-/*******************************************************************************
+/***************************************************************************
 **
-** Function         init_ctrl
+** Function         search_rsp
 **
-** Description      Initializes the AVRC interface
+** Description      Response to search a string from media content command.
 **
 ** Returns          bt_status_t
+**                      BT_STATUS_NOT_READY - when RC is not connected.
+**                      BT_STATUS_SUCCESS   - always if RC is connected
 **
-*******************************************************************************/
-static bt_status_t init_ctrl(btrc_ctrl_callbacks_t* callbacks )
+***************************************************************************/
+static bt_status_t search_rsp(bt_bdaddr_t *bd_addr, btrc_status_t rsp_status,
+        uint32_t uid_counter, uint32_t num_items)
 {
-    BTIF_TRACE_EVENT("## %s ##", __func__);
-    bt_status_t result = BT_STATUS_SUCCESS;
+    tAVRC_RESPONSE avrc_rsp;
+    btif_rc_device_cb_t *p_dev = btif_rc_get_device_by_bda(bd_addr);
 
-    if (bt_rc_ctrl_callbacks)
-        return BT_STATUS_DONE;
+    CHECK_RC_CONNECTED(p_dev)
 
-    bt_rc_ctrl_callbacks = callbacks;
-    memset (&btif_rc_cb, 0, sizeof(btif_rc_cb));
-    btif_rc_cb.rc_vol_label=MAX_LABEL;
-    btif_rc_cb.rc_volume=MAX_VOLUME;
-    lbl_init();
+    avrc_rsp.search.pdu = AVRC_PDU_SEARCH;
+    avrc_rsp.search.opcode = opcode_from_pdu(AVRC_PDU_SEARCH);
+    avrc_rsp.search.num_items = num_items;
+    avrc_rsp.search.uid_counter = uid_counter;
+    avrc_rsp.search.status = status_code_map[rsp_status];
 
-    return result;
-}
+    /* Send the response. */
+    send_metamsg_rsp(p_dev, IDX_SEARCH_RSP,
+        p_dev->rc_pdu_info[IDX_SEARCH_RSP].label, p_dev->rc_pdu_info[IDX_SEARCH_RSP].ctype,
+        &avrc_rsp);
 
-static void rc_ctrl_procedure_complete ()
+    return BT_STATUS_SUCCESS;
+}
+/***************************************************************************
+**
+** Function         get_item_attr_rsp
+**
+** Description      Response to the get item's attributes command which
+**                  contains number of attributes and values list in text.
+**
+** Returns          bt_status_t
+**                      BT_STATUS_NOT_READY - when RC is not connected.
+**                      BT_STATUS_SUCCESS   - always if RC is connected
+**
+***************************************************************************/
+static bt_status_t get_item_attr_rsp(bt_bdaddr_t *bd_addr, btrc_status_t rsp_status,
+        uint8_t num_attr, btrc_element_attr_val_t *p_attrs)
 {
-    if (btif_rc_cb.rc_procedure_complete == true)
+    tAVRC_RESPONSE avrc_rsp;
+    tAVRC_ATTR_ENTRY item_attrs[BTRC_MAX_ELEM_ATTR_SIZE];
+    btif_rc_device_cb_t *p_dev = btif_rc_get_device_by_bda(bd_addr);
+
+    CHECK_RC_CONNECTED(p_dev)
+
+    memset(item_attrs, 0, sizeof(tAVRC_ATTR_ENTRY) * num_attr);
+
+    if (num_attr == 0)
     {
-        return;
+        avrc_rsp.get_attrs.status = AVRC_STS_INTERNAL_ERR;
+        BTIF_TRACE_ERROR("%s: num_attr in rsp is 0, sending internal error: 0x%02X",
+                        __func__, avrc_rsp.get_attrs.status);
     }
-    btif_rc_cb.rc_procedure_complete = true;
-    uint32_t attr_list[] = {
-            AVRC_MEDIA_ATTR_ID_TITLE,
-            AVRC_MEDIA_ATTR_ID_ARTIST,
-            AVRC_MEDIA_ATTR_ID_ALBUM,
-            AVRC_MEDIA_ATTR_ID_TRACK_NUM,
-            AVRC_MEDIA_ATTR_ID_NUM_TRACKS,
-            AVRC_MEDIA_ATTR_ID_GENRE,
-            AVRC_MEDIA_ATTR_ID_PLAYING_TIME
-            };
-    get_element_attribute_cmd (AVRC_MAX_NUM_MEDIA_ATTR_ID, attr_list);
+    else
+    {
+        avrc_rsp.get_attrs.status = status_code_map[rsp_status];
+        if (rsp_status == BTRC_STS_NO_ERROR)
+        {
+            fill_avrc_attr_entry(item_attrs, num_attr, p_attrs);
+        }
+    }
+    avrc_rsp.get_attrs.attr_count = num_attr;
+    avrc_rsp.get_attrs.p_attr_list = item_attrs;
+    avrc_rsp.get_attrs.pdu = AVRC_PDU_GET_ITEM_ATTRIBUTES;
+    avrc_rsp.get_attrs.opcode = opcode_from_pdu(AVRC_PDU_GET_ITEM_ATTRIBUTES);
+
+    /* Send the response. */
+    send_metamsg_rsp(p_dev, IDX_GET_ITEM_ATTR_RSP,
+        p_dev->rc_pdu_info[IDX_GET_ITEM_ATTR_RSP].label, p_dev->rc_pdu_info[IDX_GET_ITEM_ATTR_RSP].ctype,
+        &avrc_rsp);
+
+    return BT_STATUS_SUCCESS;
 }
 
 /***************************************************************************
 **
-** Function         get_play_status_rsp
+** Function         add_to_now_playing_rsp
 **
-** Description      Returns the current play status.
-**                      This method is called in response to
-**                      GetPlayStatus request.
+** Description      Response to command for adding speciafied media item
+**                  to Now Playing queue.
 **
 ** Returns          bt_status_t
+**                      BT_STATUS_NOT_READY - when RC is not connected.
+**                      BT_STATUS_SUCCESS   - always if RC is connected
 **
 ***************************************************************************/
-static bt_status_t get_play_status_rsp(btrc_play_status_t play_status, uint32_t song_len,
-    uint32_t song_pos)
+static bt_status_t add_to_now_playing_rsp(bt_bdaddr_t *bd_addr, btrc_status_t rsp_status)
 {
     tAVRC_RESPONSE avrc_rsp;
-    CHECK_RC_CONNECTED
-    memset(&(avrc_rsp.get_play_status), 0, sizeof(tAVRC_GET_PLAY_STATUS_RSP));
-    avrc_rsp.get_play_status.song_len = song_len;
-    avrc_rsp.get_play_status.song_pos = song_pos;
-    avrc_rsp.get_play_status.play_status = play_status;
+    btif_rc_device_cb_t *p_dev = btif_rc_get_device_by_bda(bd_addr);
+
+    CHECK_RC_CONNECTED(p_dev)
+
+    avrc_rsp.add_to_play.pdu = AVRC_PDU_ADD_TO_NOW_PLAYING;
+    avrc_rsp.add_to_play.opcode = opcode_from_pdu(AVRC_PDU_ADD_TO_NOW_PLAYING);
+    avrc_rsp.add_to_play.status = status_code_map[rsp_status];
+
+    /* Send the response. */
+    send_metamsg_rsp(p_dev, IDX_ADD_TO_NOW_PLAYING_RSP,
+        p_dev->rc_pdu_info[IDX_ADD_TO_NOW_PLAYING_RSP].label, p_dev->rc_pdu_info[IDX_ADD_TO_NOW_PLAYING_RSP].ctype,
+        &avrc_rsp);
 
-    avrc_rsp.get_play_status.pdu = AVRC_PDU_GET_PLAY_STATUS;
-    avrc_rsp.get_play_status.opcode = opcode_from_pdu(AVRC_PDU_GET_PLAY_STATUS);
-    avrc_rsp.get_play_status.status = AVRC_STS_NO_ERROR;
-    /* Send the response */
-    SEND_METAMSG_RSP(IDX_GET_PLAY_STATUS_RSP, &avrc_rsp);
     return BT_STATUS_SUCCESS;
 }
 
 /***************************************************************************
 **
-** Function         get_element_attr_rsp
+** Function         play_item_rsp
 **
-** Description      Returns the current songs' element attributes
-**                      in text.
+** Description      Response to command for playing the specified media item.
 **
 ** Returns          bt_status_t
+**                      BT_STATUS_NOT_READY - when RC is not connected.
+**                      BT_STATUS_SUCCESS   - always if RC is connected
 **
 ***************************************************************************/
-static bt_status_t get_element_attr_rsp(uint8_t num_attr, btrc_element_attr_val_t *p_attrs)
+static bt_status_t play_item_rsp(bt_bdaddr_t *bd_addr, btrc_status_t rsp_status)
 {
     tAVRC_RESPONSE avrc_rsp;
-    uint32_t i;
-    tAVRC_ATTR_ENTRY element_attrs[BTRC_MAX_ELEM_ATTR_SIZE];
-    CHECK_RC_CONNECTED
-    memset(element_attrs, 0, sizeof(tAVRC_ATTR_ENTRY) * num_attr);
+    btif_rc_device_cb_t *p_dev = btif_rc_get_device_by_bda(bd_addr);
+
+    CHECK_RC_CONNECTED(p_dev)
+
+    avrc_rsp.play_item.pdu = AVRC_PDU_PLAY_ITEM;
+    avrc_rsp.play_item.opcode = opcode_from_pdu(AVRC_PDU_PLAY_ITEM);
+    avrc_rsp.play_item.status = status_code_map[rsp_status];
+
+    /* Send the response. */
+    send_metamsg_rsp(p_dev, IDX_PLAY_ITEM_RSP,
+        p_dev->rc_pdu_info[IDX_PLAY_ITEM_RSP].label, p_dev->rc_pdu_info[IDX_PLAY_ITEM_RSP].ctype,
+        &avrc_rsp);
 
-    if (num_attr == 0)
-    {
-        avrc_rsp.get_play_status.status = AVRC_STS_BAD_PARAM;
-    }
-    else
-    {
-        for (i=0; i<num_attr; i++) {
-            element_attrs[i].attr_id = p_attrs[i].attr_id;
-            element_attrs[i].name.charset_id = AVRC_CHARSET_ID_UTF8;
-            element_attrs[i].name.str_len = (uint16_t)strlen((char *)p_attrs[i].text);
-            element_attrs[i].name.p_str = p_attrs[i].text;
-            BTIF_TRACE_DEBUG("%s attr_id:0x%x, charset_id:0x%x, str_len:%d, str:%s",
-                             __func__, (unsigned int)element_attrs[i].attr_id,
-                             element_attrs[i].name.charset_id, element_attrs[i].name.str_len,
-                             element_attrs[i].name.p_str);
-        }
-        avrc_rsp.get_play_status.status = AVRC_STS_NO_ERROR;
-    }
-    avrc_rsp.get_elem_attrs.num_attr = num_attr;
-    avrc_rsp.get_elem_attrs.p_attrs = element_attrs;
-    avrc_rsp.get_elem_attrs.pdu = AVRC_PDU_GET_ELEMENT_ATTR;
-    avrc_rsp.get_elem_attrs.opcode = opcode_from_pdu(AVRC_PDU_GET_ELEMENT_ATTR);
-    /* Send the response */
-    SEND_METAMSG_RSP(IDX_GET_ELEMENT_ATTR_RSP, &avrc_rsp);
     return BT_STATUS_SUCCESS;
 }
 
 /***************************************************************************
 **
-** Function         register_notification_rsp
+** Function         get_total_num_of_items_rsp
 **
-** Description      Response to the register notification request.
-**                      in text.
+** Description      response to command to get the Number of Items
+**                  in the selected folder at the selected scope
 **
 ** Returns          bt_status_t
+**                      BT_STATUS_NOT_READY - when RC is not connected.
+**                      BT_STATUS_SUCCESS   - always if RC is connected
 **
 ***************************************************************************/
-static bt_status_t register_notification_rsp(btrc_event_id_t event_id,
-    btrc_notification_type_t type, btrc_register_notification_t *p_param)
+static bt_status_t get_total_num_of_items_rsp(bt_bdaddr_t *bd_addr, btrc_status_t rsp_status,
+        uint32_t uid_counter, uint32_t num_items)
 {
     tAVRC_RESPONSE avrc_rsp;
-    CHECK_RC_CONNECTED
-    BTIF_TRACE_EVENT("## %s ## event_id:%s", __func__, dump_rc_notification_event_id(event_id));
-    if (btif_rc_cb.rc_notif[event_id-1].bNotify == false)
-    {
-        BTIF_TRACE_ERROR("Avrcp Event id not registered: event_id = %x", event_id);
-        return BT_STATUS_NOT_READY;
-    }
-    memset(&(avrc_rsp.reg_notif), 0, sizeof(tAVRC_REG_NOTIF_RSP));
-    avrc_rsp.reg_notif.event_id = event_id;
+    btif_rc_device_cb_t *p_dev = btif_rc_get_device_by_bda(bd_addr);
 
-    switch(event_id)
-    {
-        case BTRC_EVT_PLAY_STATUS_CHANGED:
-            avrc_rsp.reg_notif.param.play_status = p_param->play_status;
-            if (avrc_rsp.reg_notif.param.play_status == PLAY_STATUS_PLAYING)
-                btif_av_clear_remote_suspend_flag();
-            break;
-        case BTRC_EVT_TRACK_CHANGE:
-            memcpy(&(avrc_rsp.reg_notif.param.track), &(p_param->track), sizeof(btrc_uid_t));
-            break;
-        case BTRC_EVT_PLAY_POS_CHANGED:
-            avrc_rsp.reg_notif.param.play_pos = p_param->song_pos;
-            break;
-        default:
-            BTIF_TRACE_WARNING("%s : Unhandled event ID : 0x%x", __func__, event_id);
-            return BT_STATUS_UNHANDLED;
-    }
+    CHECK_RC_CONNECTED(p_dev)
 
-    avrc_rsp.reg_notif.pdu = AVRC_PDU_REGISTER_NOTIFICATION;
-    avrc_rsp.reg_notif.opcode = opcode_from_pdu(AVRC_PDU_REGISTER_NOTIFICATION);
-    avrc_rsp.get_play_status.status = AVRC_STS_NO_ERROR;
+    avrc_rsp.get_num_of_items.pdu = AVRC_PDU_GET_TOTAL_NUM_OF_ITEMS;
+    avrc_rsp.get_num_of_items.opcode = opcode_from_pdu(AVRC_PDU_GET_TOTAL_NUM_OF_ITEMS);
+    avrc_rsp.get_num_of_items.num_items = num_items;
+    avrc_rsp.get_num_of_items.uid_counter = uid_counter;
+    avrc_rsp.get_num_of_items.status = status_code_map[rsp_status];
 
     /* Send the response. */
-    send_metamsg_rsp(btif_rc_cb.rc_handle, btif_rc_cb.rc_notif[event_id-1].label,
-        ((type == BTRC_NOTIFICATION_TYPE_INTERIM)?AVRC_CMD_NOTIF:AVRC_RSP_CHANGED), &avrc_rsp);
+    send_metamsg_rsp(p_dev, IDX_GET_TOTAL_NUM_OF_ITEMS_RSP,
+        p_dev->rc_pdu_info[IDX_GET_TOTAL_NUM_OF_ITEMS_RSP].label, p_dev->rc_pdu_info[IDX_GET_TOTAL_NUM_OF_ITEMS_RSP].ctype,
+        &avrc_rsp);
+
     return BT_STATUS_SUCCESS;
 }
 
@@ -1803,57 +2845,82 @@ static bt_status_t register_notification_rsp(btrc_event_id_t event_id,
 ***************************************************************************/
 static bt_status_t set_volume(uint8_t volume)
 {
-    BTIF_TRACE_DEBUG("%s", __func__);
-    CHECK_RC_CONNECTED
+    BTIF_TRACE_DEBUG("%s: volume: %d", __func__, volume);
     tAVRC_STS status = BT_STATUS_UNSUPPORTED;
     rc_transaction_t *p_transaction=NULL;
 
-    if (btif_rc_cb.rc_volume==volume)
+    for (int idx = 0; idx < BTIF_RC_NUM_CONN; idx++)
     {
-        status=BT_STATUS_DONE;
-        BTIF_TRACE_ERROR("%s: volume value already set earlier: 0x%02x",__func__, volume);
-        return (bt_status_t)status;
-    }
 
-    if ((btif_rc_cb.rc_features & BTA_AV_FEAT_RCTG) &&
-        (btif_rc_cb.rc_features & BTA_AV_FEAT_ADV_CTRL))
-    {
-        tAVRC_COMMAND avrc_cmd = {0};
-        BT_HDR *p_msg = NULL;
+        if (btif_rc_cb.rc_multi_cb[idx].rc_connected) {
+            status = BT_STATUS_NOT_READY;
+            BTIF_TRACE_ERROR("%s: RC is not connected for device: 0x%x",__func__,
+                btif_rc_cb.rc_multi_cb[idx].rc_addr);
+            continue;
+        }
 
-        BTIF_TRACE_DEBUG("%s: Peer supports absolute volume. newVolume=%d", __func__, volume);
-        avrc_cmd.volume.opcode = AVRC_OP_VENDOR;
-        avrc_cmd.volume.pdu = AVRC_PDU_SET_ABSOLUTE_VOLUME;
-        avrc_cmd.volume.status = AVRC_STS_NO_ERROR;
-        avrc_cmd.volume.volume = volume;
+        if (btif_rc_cb.rc_multi_cb[idx].rc_volume == volume)
+        {
+            status = BT_STATUS_DONE;
+            BTIF_TRACE_ERROR("%s: volume value already set earlier: 0x%02x",__func__, volume);
+            continue;
+        }
 
-        if (AVRC_BldCommand(&avrc_cmd, &p_msg) == AVRC_STS_NO_ERROR)
+        if ((btif_rc_cb.rc_multi_cb[idx].rc_volume != volume) &&
+            btif_rc_cb.rc_multi_cb[idx].rc_state == BTRC_CONNECTION_STATE_CONNECTED)
         {
-            bt_status_t tran_status=get_transaction(&p_transaction);
-            if (BT_STATUS_SUCCESS == tran_status && NULL!=p_transaction)
+            if ((btif_rc_cb.rc_multi_cb[idx].rc_features & BTA_AV_FEAT_RCTG) == 0)
             {
-                BTIF_TRACE_DEBUG("%s msgreq being sent out with label %d",
-                                   __func__,p_transaction->lbl);
-                BTA_AvMetaCmd(btif_rc_cb.rc_handle,p_transaction->lbl, AVRC_CMD_CTRL, p_msg);
-                status =  BT_STATUS_SUCCESS;
+                status = BT_STATUS_NOT_READY;
+                continue;
             }
             else
             {
-                osi_free(p_msg);
-                BTIF_TRACE_ERROR("%s: failed to obtain transaction details. status: 0x%02x",
-                                    __func__, tran_status);
-                status = BT_STATUS_FAIL;
+                tAVRC_COMMAND avrc_cmd = {0};
+                BT_HDR *p_msg = NULL;
+
+                if (btif_rc_cb.rc_multi_cb[idx].rc_features & BTA_AV_FEAT_ADV_CTRL)
+                {
+
+                    BTIF_TRACE_DEBUG("%s: Peer supports absolute volume. newVolume: %d",
+                        __func__, volume);
+                    avrc_cmd.volume.opcode = AVRC_OP_VENDOR;
+                    avrc_cmd.volume.pdu = AVRC_PDU_SET_ABSOLUTE_VOLUME;
+                    avrc_cmd.volume.status = AVRC_STS_NO_ERROR;
+                    avrc_cmd.volume.volume = volume;
+
+                    if (AVRC_BldCommand(&avrc_cmd, &p_msg) == AVRC_STS_NO_ERROR)
+                    {
+                        bt_status_t tran_status = get_transaction(&p_transaction);
+
+                        if(BT_STATUS_SUCCESS == tran_status && NULL!=p_transaction)
+                        {
+                            BTIF_TRACE_DEBUG("%s: msgreq being sent out with label: %d",
+                                               __func__, p_transaction->lbl);
+                            BTA_AvMetaCmd(btif_rc_cb.rc_multi_cb[idx].rc_handle,p_transaction->lbl,
+                                AVRC_CMD_CTRL, p_msg);
+                            status =  BT_STATUS_SUCCESS;
+                        }
+                        else
+                        {
+                            osi_free_and_reset((void **)&p_msg);
+                            BTIF_TRACE_ERROR(
+                                    "%s: failed to obtain transaction details. status: 0x%02x",
+                                               __func__, tran_status);
+                           status = BT_STATUS_FAIL;
+                       }
+                    }
+                    else
+                    {
+                        BTIF_TRACE_ERROR(
+                                    "%s: failed to build absolute volume command. status: 0x%02x",
+                                            __func__, status);
+                        status = BT_STATUS_FAIL;
+                    }
+                }
             }
         }
-        else
-        {
-            BTIF_TRACE_ERROR("%s: failed to build absolute volume command. status: 0x%02x",
-                                __func__, status);
-            status = BT_STATUS_FAIL;
-        }
     }
-    else
-        status=BT_STATUS_NOT_READY;
     return (bt_status_t)status;
 }
 
@@ -1868,14 +2935,14 @@ static bt_status_t set_volume(uint8_t volume)
 **
 ***************************************************************************/
 
-static void register_volumechange (uint8_t lbl)
+static void register_volumechange (uint8_t lbl, btif_rc_device_cb_t *p_dev)
 {
     tAVRC_COMMAND avrc_cmd = {0};
     BT_HDR *p_msg = NULL;
-    tAVRC_STS BldResp=AVRC_STS_BAD_CMD;
-    rc_transaction_t *p_transaction=NULL;
+    tAVRC_STS BldResp = AVRC_STS_BAD_CMD;
+    rc_transaction_t *p_transaction = NULL;
 
-    BTIF_TRACE_DEBUG("%s called with label:%d",__func__,lbl);
+    BTIF_TRACE_DEBUG("%s: label: %d", __func__, lbl);
 
     avrc_cmd.cmd.opcode=0x00;
     avrc_cmd.pdu = AVRC_PDU_REGISTER_NOTIFICATION;
@@ -1887,16 +2954,16 @@ static void register_volumechange (uint8_t lbl)
     if (AVRC_STS_NO_ERROR == BldResp && p_msg) {
         p_transaction = get_transaction_by_lbl(lbl);
         if (p_transaction != NULL) {
-            BTA_AvMetaCmd(btif_rc_cb.rc_handle, p_transaction->lbl,
+            BTA_AvMetaCmd(p_dev->rc_handle, p_transaction->lbl,
                           AVRC_CMD_NOTIF, p_msg);
-            BTIF_TRACE_DEBUG("%s:BTA_AvMetaCmd called", __func__);
+            BTIF_TRACE_DEBUG("%s: BTA_AvMetaCmd called", __func__);
          } else {
             osi_free(p_msg);
-            BTIF_TRACE_ERROR("%s transaction not obtained with label: %d",
+            BTIF_TRACE_ERROR("%s: transaction not obtained with label: %d",
                              __func__, lbl);
          }
     } else {
-        BTIF_TRACE_ERROR("%s failed to build command:%d", __func__, BldResp);
+        BTIF_TRACE_ERROR("%s: failed to build command: %d", __func__, BldResp);
     }
 }
 
@@ -1909,62 +2976,67 @@ static void register_volumechange (uint8_t lbl)
 ** Returns          void
 **
 ***************************************************************************/
-static void handle_rc_metamsg_rsp(tBTA_AV_META_MSG *pmeta_msg)
+static void handle_rc_metamsg_rsp(tBTA_AV_META_MSG *pmeta_msg, btif_rc_device_cb_t *p_dev)
 {
     tAVRC_RESPONSE    avrc_response = {0};
     uint8_t             scratch_buf[512] = {0};
     tAVRC_STS status = BT_STATUS_UNSUPPORTED;
 
-    if (AVRC_OP_VENDOR==pmeta_msg->p_msg->hdr.opcode &&(AVRC_RSP_CHANGED==pmeta_msg->code
-      || AVRC_RSP_INTERIM==pmeta_msg->code || AVRC_RSP_ACCEPT==pmeta_msg->code
-      || AVRC_RSP_REJ==pmeta_msg->code || AVRC_RSP_NOT_IMPL==pmeta_msg->code))
+    BTIF_TRACE_DEBUG("%s: ", __func__);
+
+    if (AVRC_OP_VENDOR == pmeta_msg->p_msg->hdr.opcode && (AVRC_RSP_CHANGED == pmeta_msg->code
+       || AVRC_RSP_INTERIM == pmeta_msg->code || AVRC_RSP_ACCEPT == pmeta_msg->code
+       || AVRC_RSP_REJ == pmeta_msg->code || AVRC_RSP_NOT_IMPL == pmeta_msg->code))
     {
-        status=AVRC_ParsResponse(pmeta_msg->p_msg, &avrc_response, scratch_buf, sizeof(scratch_buf));
-        BTIF_TRACE_DEBUG("%s: code %d,event ID %d,PDU %x,parsing status %d, label:%d",
-          __func__,pmeta_msg->code,avrc_response.reg_notif.event_id,avrc_response.reg_notif.pdu,
-          status, pmeta_msg->label);
+        status = AVRC_ParsResponse(pmeta_msg->p_msg, &avrc_response, scratch_buf,
+            sizeof(scratch_buf));
+        BTIF_TRACE_DEBUG("%s: code:%d, event ID: %d, PDU: %x, parsing status: %d, label: %d",
+            __func__, pmeta_msg->code, avrc_response.reg_notif.event_id,
+            avrc_response.reg_notif.pdu, status, pmeta_msg->label);
 
         if (status != AVRC_STS_NO_ERROR)
         {
-            if (AVRC_PDU_REGISTER_NOTIFICATION==avrc_response.rsp.pdu
-                && AVRC_EVT_VOLUME_CHANGE==avrc_response.reg_notif.event_id
-                && btif_rc_cb.rc_vol_label==pmeta_msg->label)
+            if (AVRC_PDU_REGISTER_NOTIFICATION == avrc_response.rsp.pdu
+                && AVRC_EVT_VOLUME_CHANGE == avrc_response.reg_notif.event_id
+                && p_dev->rc_vol_label == pmeta_msg->label)
             {
-                btif_rc_cb.rc_vol_label=MAX_LABEL;
-                release_transaction(btif_rc_cb.rc_vol_label);
+                p_dev->rc_vol_label = MAX_LABEL;
+                release_transaction(p_dev->rc_vol_label);
             }
-            else if (AVRC_PDU_SET_ABSOLUTE_VOLUME==avrc_response.rsp.pdu)
+            else if (AVRC_PDU_SET_ABSOLUTE_VOLUME == avrc_response.rsp.pdu)
             {
                 release_transaction(pmeta_msg->label);
             }
             return;
         }
-        else if (AVRC_PDU_REGISTER_NOTIFICATION==avrc_response.rsp.pdu
-            && AVRC_EVT_VOLUME_CHANGE==avrc_response.reg_notif.event_id
-            && btif_rc_cb.rc_vol_label!=pmeta_msg->label)
-            {
-                // Just discard the message, if the device sends back with an incorrect label
-                BTIF_TRACE_DEBUG("%s:Discarding register notfn in rsp.code: %d and label %d",
+
+        if (AVRC_PDU_REGISTER_NOTIFICATION == avrc_response.rsp.pdu
+            && AVRC_EVT_VOLUME_CHANGE == avrc_response.reg_notif.event_id
+            && p_dev->rc_vol_label != pmeta_msg->label)
+        {
+            // Just discard the message, if the device sends back with an incorrect label
+            BTIF_TRACE_DEBUG("%s: Discarding register notification in rsp.code: %d and label: %d",
                 __func__, pmeta_msg->code, pmeta_msg->label);
-                return;
-            }
+            return;
+        }
     }
     else
     {
-        BTIF_TRACE_DEBUG("%s:Received vendor dependent in adv ctrl rsp. code: %d len: %d. Not processing it.",
-        __func__, pmeta_msg->code, pmeta_msg->len);
+        BTIF_TRACE_DEBUG(
+            "%s: Received vendor dependent in adv ctrl rsp. code: %d len: %d. Not processing it.",
+            __func__, pmeta_msg->code, pmeta_msg->len);
         return;
     }
 
-    if (AVRC_PDU_REGISTER_NOTIFICATION==avrc_response.rsp.pdu
-        && AVRC_EVT_VOLUME_CHANGE==avrc_response.reg_notif.event_id
-        && AVRC_RSP_CHANGED==pmeta_msg->code)
+    if (AVRC_PDU_REGISTER_NOTIFICATION == avrc_response.rsp.pdu
+        && AVRC_EVT_VOLUME_CHANGE == avrc_response.reg_notif.event_id
+        && AVRC_RSP_CHANGED == pmeta_msg->code)
      {
          /* re-register for volume change notification */
          // Do not re-register for rejected case, as it might get into endless loop
-         register_volumechange(btif_rc_cb.rc_vol_label);
+         register_volumechange(p_dev->rc_vol_label, p_dev);
      }
-     else if (AVRC_PDU_SET_ABSOLUTE_VOLUME==avrc_response.rsp.pdu)
+     else if (AVRC_PDU_SET_ABSOLUTE_VOLUME == avrc_response.rsp.pdu)
      {
           /* free up the label here */
           release_transaction(pmeta_msg->label);
@@ -1973,7 +3045,7 @@ static void handle_rc_metamsg_rsp(tBTA_AV_META_MSG *pmeta_msg)
      BTIF_TRACE_EVENT("%s: Passing received metamsg response to app. pdu: %s",
              __func__, dump_rc_pdu(avrc_response.pdu));
      btif_rc_upstreams_rsp_evt((uint16_t)avrc_response.rsp.pdu, &avrc_response, pmeta_msg->code,
-                                pmeta_msg->label);
+                                pmeta_msg->label, p_dev);
 }
 #endif
 
@@ -2016,14 +3088,16 @@ bool iterate_supported_event_list_for_interim_rsp(void *data, void *cb_data)
 ***************************************************************************/
 bool iterate_supported_event_list_for_timeout(void *data, void *cb_data)
 {
-    uint8_t label;
+    bt_bdaddr_t bd_addr;
+    rc_context_t *cntxt = (rc_context_t*)cb_data;
+    uint8_t label = cntxt->label & 0xFF;
+    bdcpy(bd_addr.address, cntxt->rc_addr);
+    btif_rc_device_cb_t *p_dev = btif_rc_get_device_by_bda(&bd_addr);
     btif_rc_supported_event_t *p_event = (btif_rc_supported_event_t *)data;
 
-    label = (*(uint8_t*)cb_data) & 0xFF;
-
     if (p_event->label == label)
     {
-        list_remove(btif_rc_cb.rc_supported_event_list, p_event);
+        list_remove(p_dev->rc_supported_event_list, p_event);
         return false;
     }
     return true;
@@ -2039,16 +3113,20 @@ bool iterate_supported_event_list_for_timeout(void *data, void *cb_data)
 ** Returns          None
 **
 ***************************************************************************/
-static void rc_notification_interim_timout (uint8_t label)
+static void rc_notification_interim_timout (uint8_t label, btif_rc_device_cb_t *p_dev)
 {
     list_node_t *node;
+    rc_context_t cntxt;
+    memset(&cntxt, 0, sizeof(rc_context_t));
+    cntxt.label = label;
+    bdcpy(cntxt.rc_addr, p_dev->rc_addr);
 
-    list_foreach(btif_rc_cb.rc_supported_event_list,
-                     iterate_supported_event_list_for_timeout, &label);
+    list_foreach(p_dev->rc_supported_event_list,
+                     iterate_supported_event_list_for_timeout, &cntxt);
     /* Timeout happened for interim response for the registered event,
      * check if there are any pending for registration
      */
-    node = list_begin(btif_rc_cb.rc_supported_event_list);
+    node = list_begin(p_dev->rc_supported_event_list);
     while (node != NULL)
     {
         btif_rc_supported_event_t *p_event;
@@ -2056,7 +3134,7 @@ static void rc_notification_interim_timout (uint8_t label)
         p_event = (btif_rc_supported_event_t *)list_node(node);
         if ((p_event != NULL) && (p_event->status == eNOT_REGISTERED))
         {
-            register_for_event_notification(p_event);
+            register_for_event_notification(p_event, p_dev);
             break;
         }
         node = list_next (node);
@@ -2080,14 +3158,22 @@ static void btif_rc_status_cmd_timeout_handler(UNUSED_ATTR uint16_t event,
     btif_rc_timer_context_t *p_context;
     tAVRC_RESPONSE      avrc_response = {0};
     tBTA_AV_META_MSG    meta_msg;
+    btif_rc_device_cb_t *p_dev = NULL;
+    bt_bdaddr_t bd_addr;
 
     p_context = (btif_rc_timer_context_t *)data;
+    bdcpy(bd_addr.address, p_context->rc_addr);
     memset(&meta_msg, 0, sizeof(tBTA_AV_META_MSG));
-    meta_msg.rc_handle = btif_rc_cb.rc_handle;
+    p_dev = btif_rc_get_device_by_bda(&bd_addr);
+    if( p_dev == NULL ){
+        BTIF_TRACE_ERROR("%s: p_dev NULL", __func__);
+        return;
+    }
+    meta_msg.rc_handle = p_dev->rc_handle;
 
     switch (p_context->rc_status_cmd.pdu_id) {
     case AVRC_PDU_REGISTER_NOTIFICATION:
-        rc_notification_interim_timout(p_context->rc_status_cmd.label);
+        rc_notification_interim_timout(p_context->rc_status_cmd.label, p_dev);
         break;
 
     case AVRC_PDU_GET_CAPABILITIES:
@@ -2166,9 +3252,16 @@ static void btif_rc_control_cmd_timeout_handler(UNUSED_ATTR uint16_t event,
     btif_rc_timer_context_t *p_context = (btif_rc_timer_context_t *)data;
     tAVRC_RESPONSE      avrc_response = {0};
     tBTA_AV_META_MSG    meta_msg;
+    bt_bdaddr_t bd_addr;
+    bdcpy(bd_addr.address, p_context->rc_addr);
+    btif_rc_device_cb_t *p_dev = btif_rc_get_device_by_bda(&bd_addr);
+    if( p_dev == NULL ){
+        BTIF_TRACE_ERROR("%s: p_dev NULL", __func__);
+        return;
+    }
 
     memset(&meta_msg, 0, sizeof(tBTA_AV_META_MSG));
-    meta_msg.rc_handle = btif_rc_cb.rc_handle;
+    meta_msg.rc_handle = p_dev->rc_handle;
 
     switch (p_context->rc_control_cmd.pdu_id) {
     case AVRC_PDU_SET_PLAYER_APP_VALUE:
@@ -2208,10 +3301,11 @@ static void btif_rc_control_cmd_timer_timeout(void *data)
 **
 ***************************************************************************/
 static void btif_rc_play_status_timeout_handler(UNUSED_ATTR uint16_t event,
-                                                UNUSED_ATTR char *p_data)
+                                                char *p_data)
 {
-    get_play_status_cmd();
-    rc_start_play_status_timer();
+    btif_rc_device_cb_t *p_dev = (btif_rc_device_cb_t*)p_data;
+    get_play_status_cmd(p_dev);
+    rc_start_play_status_timer(p_dev);
 }
 
 /***************************************************************************
@@ -2224,9 +3318,10 @@ static void btif_rc_play_status_timeout_handler(UNUSED_ATTR uint16_t event,
 ** Returns          None
 **
 ***************************************************************************/
-static void btif_rc_play_status_timer_timeout(UNUSED_ATTR void *data)
+static void btif_rc_play_status_timer_timeout(void *data)
 {
-    btif_transfer_context(btif_rc_play_status_timeout_handler, 0, 0, 0, NULL);
+    btif_rc_device_cb_t *p_dev = (btif_rc_device_cb_t*)data;
+    btif_transfer_context(btif_rc_play_status_timeout_handler, 0, (char*)p_dev, 0, NULL);
 }
 
 /***************************************************************************
@@ -2237,17 +3332,17 @@ static void btif_rc_play_status_timer_timeout(UNUSED_ATTR void *data)
 ** Returns          None
 **
 ***************************************************************************/
-static void rc_start_play_status_timer(void)
+static void rc_start_play_status_timer(btif_rc_device_cb_t *p_dev)
 {
     /* Start the Play status timer only if it is not started */
-    if (!alarm_is_scheduled(btif_rc_cb.rc_play_status_timer)) {
-        if (btif_rc_cb.rc_play_status_timer == NULL) {
-            btif_rc_cb.rc_play_status_timer =
-                alarm_new("btif_rc.rc_play_status_timer");
+    if (!alarm_is_scheduled(p_dev->rc_play_status_timer)) {
+        if (p_dev->rc_play_status_timer == NULL) {
+            p_dev->rc_play_status_timer =
+                alarm_new("p_dev->rc_play_status_timer");
         }
-        alarm_set_on_queue(btif_rc_cb.rc_play_status_timer,
+        alarm_set_on_queue(p_dev->rc_play_status_timer,
                            BTIF_TIMEOUT_RC_INTERIM_RSP_MS,
-                           btif_rc_play_status_timer_timeout, NULL,
+                           btif_rc_play_status_timer_timeout, p_dev,
                            btu_general_alarm_queue);
     }
 }
@@ -2260,10 +3355,9 @@ static void rc_start_play_status_timer(void)
 ** Returns          None
 **
 ***************************************************************************/
-void rc_stop_play_status_timer()
+void rc_stop_play_status_timer(btif_rc_device_cb_t *p_dev)
 {
-    if (btif_rc_cb.rc_play_status_timer != NULL)
-        alarm_cancel(btif_rc_cb.rc_play_status_timer);
+    alarm_cancel(p_dev->rc_play_status_timer);
 }
 
 /***************************************************************************
@@ -2276,7 +3370,8 @@ void rc_stop_play_status_timer()
 ** Returns          None
 **
 ***************************************************************************/
-static void register_for_event_notification(btif_rc_supported_event_t *p_event)
+static void register_for_event_notification(btif_rc_supported_event_t *p_event,
+    btif_rc_device_cb_t *p_dev)
 {
     bt_status_t status;
     rc_transaction_t *p_transaction;
@@ -2286,10 +3381,10 @@ static void register_for_event_notification(btif_rc_supported_event_t *p_event)
     {
         btif_rc_timer_context_t *p_context = &p_transaction->txn_timer_context;
 
-        status = register_notification_cmd (p_transaction->lbl, p_event->event_id, 0);
+        status = register_notification_cmd (p_transaction->lbl, p_event->event_id, 0, p_dev);
         if (status != BT_STATUS_SUCCESS)
         {
-            BTIF_TRACE_ERROR("%s Error in Notification registration %d",
+            BTIF_TRACE_ERROR("%s: Error in Notification registration: %d",
                 __func__, status);
             release_transaction (p_transaction->lbl);
             return;
@@ -2298,6 +3393,7 @@ static void register_for_event_notification(btif_rc_supported_event_t *p_event)
         p_event->status = eREGISTERED;
         p_context->rc_status_cmd.label = p_transaction->lbl;
         p_context->rc_status_cmd.pdu_id = AVRC_PDU_REGISTER_NOTIFICATION;
+        bdcpy(p_context->rc_addr, p_dev->rc_addr);
 
         alarm_free(p_transaction->txn_timer);
         p_transaction->txn_timer =
@@ -2309,16 +3405,18 @@ static void register_for_event_notification(btif_rc_supported_event_t *p_event)
     }
     else
     {
-        BTIF_TRACE_ERROR("%s Error No more Transaction label %d",
+        BTIF_TRACE_ERROR("%s: Error No more Transaction label: %d",
             __func__, status);
     }
 }
 
-static void start_status_command_timer(uint8_t pdu_id, rc_transaction_t *p_txn)
+static void start_status_command_timer(uint8_t pdu_id, rc_transaction_t *p_txn,
+    btif_rc_device_cb_t *p_dev)
 {
     btif_rc_timer_context_t *p_context = &p_txn->txn_timer_context;
     p_context->rc_status_cmd.label = p_txn->lbl;
     p_context->rc_status_cmd.pdu_id = pdu_id;
+    bdcpy(p_context->rc_addr, p_dev->rc_addr);
 
     alarm_free(p_txn->txn_timer);
     p_txn->txn_timer = alarm_new("btif_rc.status_command_txn_timer");
@@ -2327,11 +3425,13 @@ static void start_status_command_timer(uint8_t pdu_id, rc_transaction_t *p_txn)
                        btu_general_alarm_queue);
 }
 
-static void start_control_command_timer(uint8_t pdu_id, rc_transaction_t *p_txn)
+static void start_control_command_timer(uint8_t pdu_id, rc_transaction_t *p_txn,
+    btif_rc_device_cb_t *p_dev)
 {
     btif_rc_timer_context_t *p_context = &p_txn->txn_timer_context;
     p_context->rc_control_cmd.label = p_txn->lbl;
     p_context->rc_control_cmd.pdu_id = pdu_id;
+    bdcpy(p_context->rc_addr, p_dev->rc_addr);
 
     alarm_free(p_txn->txn_timer);
     p_txn->txn_timer = alarm_new("btif_rc.control_command_txn_timer");
@@ -2354,11 +3454,12 @@ static void start_control_command_timer(uint8_t pdu_id, rc_transaction_t *p_txn)
 static void handle_get_capability_response (tBTA_AV_META_MSG *pmeta_msg, tAVRC_GET_CAPS_RSP *p_rsp)
 {
     int xx = 0;
+    btif_rc_device_cb_t *p_dev = btif_rc_get_device_by_handle(pmeta_msg->rc_handle);
 
     /* Todo: Do we need to retry on command timeout */
     if (p_rsp->status != AVRC_STS_NO_ERROR)
     {
-        BTIF_TRACE_ERROR("%s Error capability response 0x%02X",
+        BTIF_TRACE_ERROR("%s: Error capability response: 0x%02X",
                 __func__, p_rsp->status);
         return;
     }
@@ -2368,7 +3469,7 @@ static void handle_get_capability_response (tBTA_AV_META_MSG *pmeta_msg, tAVRC_G
         btif_rc_supported_event_t *p_event;
 
         /* Todo: Check if list can be active when we hit here */
-        btif_rc_cb.rc_supported_event_list = list_new(osi_free);
+        p_dev->rc_supported_event_list = list_new(osi_free);
         for (xx = 0; xx < p_rsp->count; xx++)
         {
             /* Skip registering for Play position change notification */
@@ -2379,22 +3480,22 @@ static void handle_get_capability_response (tBTA_AV_META_MSG *pmeta_msg, tAVRC_G
                 p_event = (btif_rc_supported_event_t *)osi_malloc(sizeof(btif_rc_supported_event_t));
                 p_event->event_id = p_rsp->param.event_id[xx];
                 p_event->status = eNOT_REGISTERED;
-                list_append(btif_rc_cb.rc_supported_event_list, p_event);
+                list_append(p_dev->rc_supported_event_list, p_event);
             }
         }
-        p_event = (btif_rc_supported_event_t*)list_front(btif_rc_cb.rc_supported_event_list);
+        p_event = (btif_rc_supported_event_t*)list_front(p_dev->rc_supported_event_list);
         if (p_event != NULL)
         {
-            register_for_event_notification(p_event);
+            register_for_event_notification(p_event, p_dev);
         }
     }
     else if (p_rsp->capability_id == AVRC_CAP_COMPANY_ID)
     {
-        getcapabilities_cmd (AVRC_CAP_EVENTS_SUPPORTED);
-        BTIF_TRACE_EVENT("%s AVRC_CAP_COMPANY_ID: ", __func__);
+        getcapabilities_cmd(AVRC_CAP_EVENTS_SUPPORTED, p_dev);
+        BTIF_TRACE_EVENT("%s: AVRC_CAP_COMPANY_ID: ", __func__);
         for (xx = 0; xx < p_rsp->count; xx++)
         {
-            BTIF_TRACE_EVENT("%s    : %d", __func__, p_rsp->param.company_id[xx]);
+            BTIF_TRACE_EVENT("%s: company_id: %d", __func__, p_rsp->param.company_id[xx]);
         }
     }
 }
@@ -2435,6 +3536,7 @@ bool rc_is_track_id_valid (tAVRC_UID uid)
 static void handle_notification_response (tBTA_AV_META_MSG *pmeta_msg, tAVRC_REG_NOTIF_RSP *p_rsp)
 {
     bt_bdaddr_t rc_addr;
+    btif_rc_device_cb_t *p_dev = btif_rc_get_device_by_handle(pmeta_msg->rc_handle);
     uint32_t attr_list[] = {
         AVRC_MEDIA_ATTR_ID_TITLE,
         AVRC_MEDIA_ATTR_ID_ARTIST,
@@ -2445,15 +3547,20 @@ static void handle_notification_response (tBTA_AV_META_MSG *pmeta_msg, tAVRC_REG
         AVRC_MEDIA_ATTR_ID_PLAYING_TIME
         };
 
+    if (p_dev == NULL)
+    {
+        BTIF_TRACE_ERROR("%s: p_dev NULL", __func__);
+        return;
+    }
 
-    bdcpy(rc_addr.address, btif_rc_cb.rc_addr);
+    bdcpy(rc_addr.address, p_dev->rc_addr);
 
     if (pmeta_msg->code == AVRC_RSP_INTERIM)
     {
         btif_rc_supported_event_t *p_event;
         list_node_t *node;
 
-        BTIF_TRACE_DEBUG("%s Interim response : 0x%2X ", __func__, p_rsp->event_id);
+        BTIF_TRACE_DEBUG("%s: Interim response: 0x%2X ", __func__, p_rsp->event_id);
         switch (p_rsp->event_id)
         {
             case AVRC_EVT_PLAY_STATUS_CHANGE:
@@ -2462,7 +3569,7 @@ static void handle_notification_response (tBTA_AV_META_MSG *pmeta_msg, tAVRC_REG
                  */
                 if (p_rsp->param.play_status == AVRC_PLAYSTATE_PLAYING)
                 {
-                    rc_start_play_status_timer();
+                    rc_start_play_status_timer(p_dev);
                 }
                 HAL_CBACK(bt_rc_ctrl_callbacks, play_status_changed_cb,
                     &rc_addr, (btrc_play_status_t)p_rsp->param.play_status);
@@ -2479,7 +3586,7 @@ static void handle_notification_response (tBTA_AV_META_MSG *pmeta_msg, tAVRC_REG
                     /* Update the UID for current track
                      * Attributes will be fetched after the AVRCP procedure
                      */
-                    BE_STREAM_TO_UINT64(btif_rc_cb.rc_playing_uid, p_data);
+                    BE_STREAM_TO_UINT64(p_dev->rc_playing_uid, p_data);
                 }
                 break;
 
@@ -2504,41 +3611,43 @@ static void handle_notification_response (tBTA_AV_META_MSG *pmeta_msg, tAVRC_REG
             case AVRC_EVT_BATTERY_STATUS_CHANGE:
             case AVRC_EVT_SYSTEM_STATUS_CHANGE:
             default:
-                BTIF_TRACE_ERROR("%s  Unhandled interim response 0x%2X", __func__,
+                BTIF_TRACE_ERROR("%s: Unhandled interim response: 0x%2X", __func__,
                     p_rsp->event_id);
                 return;
         }
-        list_foreach(btif_rc_cb.rc_supported_event_list,
+
+        list_foreach(p_dev->rc_supported_event_list,
                 iterate_supported_event_list_for_interim_rsp,
                 &p_rsp->event_id);
 
-        node = list_begin(btif_rc_cb.rc_supported_event_list);
+        node = list_begin(p_dev->rc_supported_event_list);
+
         while (node != NULL)
         {
             p_event = (btif_rc_supported_event_t *)list_node(node);
             if ((p_event != NULL) && (p_event->status == eNOT_REGISTERED))
             {
-                register_for_event_notification(p_event);
+                register_for_event_notification(p_event, p_dev);
                 break;
             }
             node = list_next (node);
             p_event = NULL;
         }
         /* Registered for all events, we can request application settings */
-        if ((p_event == NULL) && (btif_rc_cb.rc_app_settings.query_started == false))
+        if (p_event == NULL && p_dev->rc_app_settings.query_started == false)
         {
             /* we need to do this only if remote TG supports
              * player application settings
              */
-            btif_rc_cb.rc_app_settings.query_started = true;
-            if (btif_rc_cb.rc_features & BTA_AV_FEAT_APP_SETTING)
+            p_dev->rc_app_settings.query_started = true;
+            if (p_dev->rc_features & BTA_AV_FEAT_APP_SETTING)
             {
-                list_player_app_setting_attrib_cmd();
+                list_player_app_setting_attrib_cmd(p_dev);
             }
             else
             {
-                BTIF_TRACE_DEBUG("%s App setting not supported, complete procedure", __func__);
-                rc_ctrl_procedure_complete();
+                BTIF_TRACE_DEBUG("%s: App setting not supported, complete procedure", __func__);
+                rc_ctrl_procedure_complete(p_dev);
             }
         }
     }
@@ -2547,17 +3656,18 @@ static void handle_notification_response (tBTA_AV_META_MSG *pmeta_msg, tAVRC_REG
         btif_rc_supported_event_t *p_event;
         list_node_t *node;
 
-        BTIF_TRACE_DEBUG("%s Notification completed : 0x%2X ", __func__,
+        BTIF_TRACE_DEBUG("%s: Notification completed: 0x%2X ", __func__,
             p_rsp->event_id);
 
-        node = list_begin(btif_rc_cb.rc_supported_event_list);
+        node = list_begin(p_dev->rc_supported_event_list);
+
         while (node != NULL)
         {
             p_event = (btif_rc_supported_event_t *)list_node(node);
-            if ((p_event != NULL) && (p_event->event_id == p_rsp->event_id))
+            if (p_event != NULL && p_event->event_id == p_rsp->event_id)
             {
                 p_event->status = eNOT_REGISTERED;
-                register_for_event_notification(p_event);
+                register_for_event_notification(p_event, p_dev);
                 break;
             }
             node = list_next (node);
@@ -2571,14 +3681,15 @@ static void handle_notification_response (tBTA_AV_META_MSG *pmeta_msg, tAVRC_REG
                  */
                 if (p_rsp->param.play_status == AVRC_PLAYSTATE_PLAYING)
                 {
-                    rc_start_play_status_timer();
+                    rc_start_play_status_timer(p_dev);
                 }
                 else
                 {
-                    rc_stop_play_status_timer();
+                    rc_stop_play_status_timer(p_dev);
                 }
                 HAL_CBACK(bt_rc_ctrl_callbacks, play_status_changed_cb,
                     &rc_addr, (btrc_play_status_t)p_rsp->param.play_status);
+
                 break;
 
             case AVRC_EVT_TRACK_CHANGE:
@@ -2586,7 +3697,7 @@ static void handle_notification_response (tBTA_AV_META_MSG *pmeta_msg, tAVRC_REG
                 {
                     break;
                 }
-                get_element_attribute_cmd (AVRC_MAX_NUM_MEDIA_ATTR_ID, attr_list);
+                get_element_attribute_cmd(AVRC_MAX_NUM_MEDIA_ATTR_ID, attr_list, p_dev);
                 break;
 
             case AVRC_EVT_APP_SETTING_CHANGE:
@@ -2623,7 +3734,7 @@ static void handle_notification_response (tBTA_AV_META_MSG *pmeta_msg, tAVRC_REG
             case AVRC_EVT_BATTERY_STATUS_CHANGE:
             case AVRC_EVT_SYSTEM_STATUS_CHANGE:
             default:
-                BTIF_TRACE_ERROR("%s  Unhandled completion response 0x%2X",
+                BTIF_TRACE_ERROR("%s: Unhandled completion response: 0x%2X",
                     __func__, p_rsp->event_id);
                 return;
         }
@@ -2642,12 +3753,13 @@ static void handle_notification_response (tBTA_AV_META_MSG *pmeta_msg, tAVRC_REG
 static void handle_app_attr_response (tBTA_AV_META_MSG *pmeta_msg, tAVRC_LIST_APP_ATTR_RSP *p_rsp)
 {
     uint8_t xx;
+    btif_rc_device_cb_t *p_dev = btif_rc_get_device_by_handle(pmeta_msg->rc_handle);
 
-    if (p_rsp->status != AVRC_STS_NO_ERROR)
+    if (p_dev == NULL || p_rsp->status != AVRC_STS_NO_ERROR)
     {
-        BTIF_TRACE_ERROR("%s Error getting Player application settings: 0x%2X",
+        BTIF_TRACE_ERROR("%s: Error getting Player application settings: 0x%2X",
                 __func__, p_rsp->status);
-        rc_ctrl_procedure_complete();
+        rc_ctrl_procedure_complete(p_dev);
         return;
     }
 
@@ -2657,27 +3769,27 @@ static void handle_app_attr_response (tBTA_AV_META_MSG *pmeta_msg, tAVRC_LIST_AP
 
         if (p_rsp->attrs[xx] > AVRC_PLAYER_SETTING_LOW_MENU_EXT)
         {
-            st_index = btif_rc_cb.rc_app_settings.num_ext_attrs;
-            btif_rc_cb.rc_app_settings.ext_attrs[st_index].attr_id = p_rsp->attrs[xx];
-            btif_rc_cb.rc_app_settings.num_ext_attrs++;
+            st_index = p_dev->rc_app_settings.num_ext_attrs;
+            p_dev->rc_app_settings.ext_attrs[st_index].attr_id = p_rsp->attrs[xx];
+            p_dev->rc_app_settings.num_ext_attrs++;
         }
         else
         {
-            st_index = btif_rc_cb.rc_app_settings.num_attrs;
-            btif_rc_cb.rc_app_settings.attrs[st_index].attr_id = p_rsp->attrs[xx];
-            btif_rc_cb.rc_app_settings.num_attrs++;
+            st_index = p_dev->rc_app_settings.num_attrs;
+            p_dev->rc_app_settings.attrs[st_index].attr_id = p_rsp->attrs[xx];
+            p_dev->rc_app_settings.num_attrs++;
         }
     }
-    btif_rc_cb.rc_app_settings.attr_index = 0;
-    btif_rc_cb.rc_app_settings.ext_attr_index = 0;
-    btif_rc_cb.rc_app_settings.ext_val_index = 0;
+    p_dev->rc_app_settings.attr_index = 0;
+    p_dev->rc_app_settings.ext_attr_index = 0;
+    p_dev->rc_app_settings.ext_val_index = 0;
     if (p_rsp->num_attr)
     {
-        list_player_app_setting_value_cmd (btif_rc_cb.rc_app_settings.attrs[0].attr_id);
+        list_player_app_setting_value_cmd (p_dev->rc_app_settings.attrs[0].attr_id, p_dev);
     }
     else
     {
-        BTIF_TRACE_ERROR("%s No Player application settings found",
+        BTIF_TRACE_ERROR("%s: No Player application settings found",
                 __func__);
     }
 }
@@ -2700,17 +3812,18 @@ static void handle_app_val_response (tBTA_AV_META_MSG *pmeta_msg, tAVRC_LIST_APP
     uint8_t attrs[AVRC_MAX_APP_ATTR_SIZE];
     btif_rc_player_app_settings_t *p_app_settings;
     bt_bdaddr_t rc_addr;
+    btif_rc_device_cb_t *p_dev = btif_rc_get_device_by_handle(pmeta_msg->rc_handle);
 
     /* Todo: Do we need to retry on command timeout */
-    if (p_rsp->status != AVRC_STS_NO_ERROR)
+    if (p_dev == NULL || p_rsp->status != AVRC_STS_NO_ERROR)
     {
-        BTIF_TRACE_ERROR("%s Error fetching attribute values 0x%02X",
+        BTIF_TRACE_ERROR("%s: Error fetching attribute values: 0x%02X",
                 __func__, p_rsp->status);
         return;
     }
 
-    p_app_settings = &btif_rc_cb.rc_app_settings;
-    bdcpy(rc_addr.address, btif_rc_cb.rc_addr);
+    p_app_settings = &p_dev->rc_app_settings;
+    bdcpy(rc_addr.address, p_dev->rc_addr);
 
     if (p_app_settings->attr_index < p_app_settings->num_attrs)
     {
@@ -2724,13 +3837,17 @@ static void handle_app_val_response (tBTA_AV_META_MSG *pmeta_msg, tAVRC_LIST_APP
         p_app_settings->attr_index++;
         if (attr_index < p_app_settings->num_attrs)
         {
-            list_player_app_setting_value_cmd (p_app_settings->attrs[p_app_settings->attr_index].attr_id);
+            list_player_app_setting_value_cmd(
+                p_app_settings->attrs[p_app_settings->attr_index].attr_id,
+                p_dev);
         }
         else if (p_app_settings->ext_attr_index < p_app_settings->num_ext_attrs)
         {
             attr_index = 0;
             p_app_settings->ext_attr_index = 0;
-            list_player_app_setting_value_cmd (p_app_settings->ext_attrs[attr_index].attr_id);
+            list_player_app_setting_value_cmd(
+                p_app_settings->ext_attrs[attr_index].attr_id,
+                p_dev);
         }
         else
         {
@@ -2738,7 +3855,7 @@ static void handle_app_val_response (tBTA_AV_META_MSG *pmeta_msg, tAVRC_LIST_APP
             {
                 attrs[xx] = p_app_settings->attrs[xx].attr_id;
             }
-            get_player_app_setting_cmd (p_app_settings->num_attrs, attrs);
+            get_player_app_setting_cmd (p_app_settings->num_attrs, attrs, p_dev);
             HAL_CBACK (bt_rc_ctrl_callbacks, playerapplicationsetting_cb, &rc_addr,
                         p_app_settings->num_attrs, p_app_settings->attrs, 0, NULL);
         }
@@ -2755,18 +3872,18 @@ static void handle_app_val_response (tBTA_AV_META_MSG *pmeta_msg, tAVRC_LIST_APP
         p_app_settings->ext_attr_index++;
         if (attr_index < p_app_settings->num_ext_attrs)
         {
-            list_player_app_setting_value_cmd (p_app_settings->ext_attrs[p_app_settings->ext_attr_index].attr_id);
+            list_player_app_setting_value_cmd(
+                p_app_settings->ext_attrs[p_app_settings->ext_attr_index].attr_id, p_dev);
         }
         else
         {
             uint8_t attr[AVRC_MAX_APP_ATTR_SIZE];
-            uint8_t xx;
 
-            for (xx = 0; xx < p_app_settings->num_ext_attrs; xx++)
+            for (uint8_t xx = 0; xx < p_app_settings->num_ext_attrs; xx++)
             {
                 attr[xx] = p_app_settings->ext_attrs[xx].attr_id;
             }
-            get_player_app_setting_attr_text_cmd(attr, xx);
+            get_player_app_setting_attr_text_cmd(attr, p_app_settings->num_ext_attrs, p_dev);
         }
     }
 }
@@ -2780,21 +3897,30 @@ static void handle_app_val_response (tBTA_AV_META_MSG *pmeta_msg, tAVRC_LIST_APP
 ** Returns          None
 **
 ***************************************************************************/
-static void handle_app_cur_val_response (tBTA_AV_META_MSG *pmeta_msg, tAVRC_GET_CUR_APP_VALUE_RSP *p_rsp)
+static void handle_app_cur_val_response (tBTA_AV_META_MSG *pmeta_msg,
+        tAVRC_GET_CUR_APP_VALUE_RSP *p_rsp)
 {
     btrc_player_settings_t app_settings;
     bt_bdaddr_t rc_addr;
     uint16_t xx;
+    btif_rc_device_cb_t *p_dev = NULL;
 
     /* Todo: Do we need to retry on command timeout */
     if (p_rsp->status != AVRC_STS_NO_ERROR)
     {
-        BTIF_TRACE_ERROR("%s Error fetching current settings: 0x%02X",
+        BTIF_TRACE_ERROR("%s: Error fetching current settings: 0x%02X",
                 __func__, p_rsp->status);
         return;
     }
+    p_dev = btif_rc_get_device_by_handle(pmeta_msg->rc_handle);
+    if(p_dev == NULL)
+    {
+        BTIF_TRACE_ERROR("%s: Error in getting Device Address", __func__);
+        osi_free_and_reset((void **)&p_rsp->p_vals);
+        return;
+    }
 
-    bdcpy(rc_addr.address, btif_rc_cb.rc_addr);
+    bdcpy(rc_addr.address, p_dev->rc_addr);
 
     app_settings.num_attr = p_rsp->num_val;
     for (xx = 0; xx < app_settings.num_attr; xx++)
@@ -2802,13 +3928,14 @@ static void handle_app_cur_val_response (tBTA_AV_META_MSG *pmeta_msg, tAVRC_GET_
         app_settings.attr_ids[xx] = p_rsp->p_vals[xx].attr_id;
         app_settings.attr_values[xx] = p_rsp->p_vals[xx].attr_val;
     }
+
     HAL_CBACK(bt_rc_ctrl_callbacks, playerapplicationsetting_changed_cb,
         &rc_addr, &app_settings);
     /* Application settings are fetched only once for initial values
      * initiate anything that follows after RC procedure.
      * Defer it if browsing is supported till players query
      */
-    rc_ctrl_procedure_complete ();
+    rc_ctrl_procedure_complete(p_dev);
     osi_free_and_reset((void **)&p_rsp->p_vals);
 }
 
@@ -2822,22 +3949,30 @@ static void handle_app_cur_val_response (tBTA_AV_META_MSG *pmeta_msg, tAVRC_GET_
 ** Returns          None
 **
 ***************************************************************************/
-static void handle_app_attr_txt_response (tBTA_AV_META_MSG *pmeta_msg, tAVRC_GET_APP_ATTR_TXT_RSP *p_rsp)
+static void handle_app_attr_txt_response (tBTA_AV_META_MSG *pmeta_msg,
+        tAVRC_GET_APP_ATTR_TXT_RSP *p_rsp)
 {
     uint8_t xx;
     uint8_t vals[AVRC_MAX_APP_ATTR_SIZE];
     btif_rc_player_app_settings_t *p_app_settings;
     bt_bdaddr_t rc_addr;
+    btif_rc_device_cb_t *p_dev = btif_rc_get_device_by_handle(pmeta_msg->rc_handle);
+
+    if (p_dev == NULL)
+    {
+        BTIF_TRACE_ERROR("%s: p_dev NULL", __func__);
+        return;
+    }
 
-    p_app_settings = &btif_rc_cb.rc_app_settings;
-    bdcpy(rc_addr.address, btif_rc_cb.rc_addr);
+    bdcpy(rc_addr.address, p_dev->rc_addr);
+    p_app_settings = &p_dev->rc_app_settings;
 
     /* Todo: Do we need to retry on command timeout */
     if (p_rsp->status != AVRC_STS_NO_ERROR)
     {
         uint8_t attrs[AVRC_MAX_APP_ATTR_SIZE];
 
-        BTIF_TRACE_ERROR("%s Error fetching attribute text: 0x%02X",
+        BTIF_TRACE_ERROR("%s: Error fetching attribute text: 0x%02X",
                 __func__, p_rsp->status);
         /* Not able to fetch Text for extended Menu, skip the process
          * and cleanup used memory. Proceed to get the current settings
@@ -2845,17 +3980,22 @@ static void handle_app_attr_txt_response (tBTA_AV_META_MSG *pmeta_msg, tAVRC_GET
          */
         p_app_settings->num_ext_attrs = 0;
         for (xx = 0; xx < p_app_settings->ext_attr_index; xx++)
+        {
             osi_free_and_reset((void **)&p_app_settings->ext_attrs[xx].p_str);
+        }
         p_app_settings->ext_attr_index = 0;
 
-        for (xx = 0; xx < p_app_settings->num_attrs; xx++)
+        if (p_dev)
         {
-            attrs[xx] = p_app_settings->attrs[xx].attr_id;
-        }
-        HAL_CBACK (bt_rc_ctrl_callbacks, playerapplicationsetting_cb, &rc_addr,
-                    p_app_settings->num_attrs, p_app_settings->attrs, 0, NULL);
+            for (xx = 0; xx < p_app_settings->num_attrs; xx++)
+            {
+                attrs[xx] = p_app_settings->attrs[xx].attr_id;
+            }
 
-        get_player_app_setting_cmd (xx, attrs);
+            HAL_CBACK(bt_rc_ctrl_callbacks, playerapplicationsetting_cb, &rc_addr,
+                        p_app_settings->num_attrs, p_app_settings->attrs, 0, NULL);
+            get_player_app_setting_cmd (xx, attrs, p_dev);
+        }
         return;
     }
 
@@ -2878,7 +4018,7 @@ static void handle_app_attr_txt_response (tBTA_AV_META_MSG *pmeta_msg, tAVRC_GET
     {
         vals[xx] = p_app_settings->ext_attrs[0].ext_attr_val[xx].val;
     }
-    get_player_app_setting_value_text_cmd(vals, xx);
+    get_player_app_setting_value_text_cmd(vals, xx, p_dev);
 }
 
 
@@ -2892,23 +4032,31 @@ static void handle_app_attr_txt_response (tBTA_AV_META_MSG *pmeta_msg, tAVRC_GET
 ** Returns          None
 **
 ***************************************************************************/
-static void handle_app_attr_val_txt_response (tBTA_AV_META_MSG *pmeta_msg, tAVRC_GET_APP_ATTR_TXT_RSP *p_rsp)
+static void handle_app_attr_val_txt_response (tBTA_AV_META_MSG *pmeta_msg,
+        tAVRC_GET_APP_ATTR_TXT_RSP *p_rsp)
 {
     uint8_t xx, attr_index;
     uint8_t vals[AVRC_MAX_APP_ATTR_SIZE];
     uint8_t attrs[AVRC_MAX_APP_ATTR_SIZE];
     btif_rc_player_app_settings_t *p_app_settings;
     bt_bdaddr_t rc_addr;
+    btif_rc_device_cb_t *p_dev = btif_rc_get_device_by_handle(pmeta_msg->rc_handle);
+
+    if (p_dev == NULL)
+    {
+        BTIF_TRACE_ERROR("%s: p_dev NULL", __func__);
+        return;
+    }
 
-    bdcpy(rc_addr.address, btif_rc_cb.rc_addr);
-    p_app_settings = &btif_rc_cb.rc_app_settings;
+    bdcpy(rc_addr.address, p_dev->rc_addr);
+    p_app_settings = &p_dev->rc_app_settings;
 
     /* Todo: Do we need to retry on command timeout */
     if (p_rsp->status != AVRC_STS_NO_ERROR)
     {
         uint8_t attrs[AVRC_MAX_APP_ATTR_SIZE];
 
-        BTIF_TRACE_ERROR("%s Error fetching attribute value text: 0x%02X",
+        BTIF_TRACE_ERROR("%s: Error fetching attribute value text: 0x%02X",
                 __func__, p_rsp->status);
 
         /* Not able to fetch Text for extended Menu, skip the process
@@ -2935,7 +4083,7 @@ static void handle_app_attr_val_txt_response (tBTA_AV_META_MSG *pmeta_msg, tAVRC
         HAL_CBACK (bt_rc_ctrl_callbacks, playerapplicationsetting_cb, &rc_addr,
                     p_app_settings->num_attrs, p_app_settings->attrs, 0, NULL);
 
-        get_player_app_setting_cmd (xx, attrs);
+        get_player_app_setting_cmd (xx, attrs, p_dev);
         return;
     }
 
@@ -2964,7 +4112,7 @@ static void handle_app_attr_val_txt_response (tBTA_AV_META_MSG *pmeta_msg, tAVRC
         {
             vals[xx] = p_app_settings->ext_attrs[attr_index].ext_attr_val[xx].val;
         }
-        get_player_app_setting_value_text_cmd(vals, xx);
+        get_player_app_setting_value_text_cmd(vals, xx, p_dev);
     }
     else
     {
@@ -2981,7 +4129,7 @@ static void handle_app_attr_val_txt_response (tBTA_AV_META_MSG *pmeta_msg, tAVRC
         HAL_CBACK (bt_rc_ctrl_callbacks, playerapplicationsetting_cb, &rc_addr,
                     p_app_settings->num_attrs, p_app_settings->attrs,
                     p_app_settings->num_ext_attrs, p_app_settings->ext_attrs);
-        get_player_app_setting_cmd (xx + x, attrs);
+        get_player_app_setting_cmd (xx + x, attrs, p_dev);
 
         /* Free the application settings information after sending to
          * application.
@@ -3013,8 +4161,15 @@ static void handle_set_app_attr_val_response (tBTA_AV_META_MSG *pmeta_msg, tAVRC
 {
     uint8_t accepted = 0;
     bt_bdaddr_t rc_addr;
+    btif_rc_device_cb_t *p_dev = btif_rc_get_device_by_handle(pmeta_msg->rc_handle);
+
+    if (p_dev == NULL)
+    {
+        BTIF_TRACE_ERROR("%s: p_dev NULL", __func__);
+        return;
+    }
 
-    bdcpy(rc_addr.address, btif_rc_cb.rc_addr);
+    bdcpy(rc_addr.address, p_dev->rc_addr);
 
     /* For timeout pmeta_msg will be NULL, else we need to
      * check if this is accepted by TG
@@ -3038,13 +4193,21 @@ static void handle_set_app_attr_val_response (tBTA_AV_META_MSG *pmeta_msg, tAVRC
 static void handle_get_elem_attr_response (tBTA_AV_META_MSG *pmeta_msg,
                                            tAVRC_GET_ELEM_ATTRS_RSP *p_rsp)
 {
+    btif_rc_device_cb_t *p_dev = btif_rc_get_device_by_handle(pmeta_msg->rc_handle);
+
     if (p_rsp->status == AVRC_STS_NO_ERROR) {
         bt_bdaddr_t rc_addr;
         size_t buf_size = p_rsp->num_attr * sizeof(btrc_element_attr_val_t);
         btrc_element_attr_val_t *p_attr =
             (btrc_element_attr_val_t *)osi_calloc(buf_size);
 
-        bdcpy(rc_addr.address, btif_rc_cb.rc_addr);
+        if (p_dev == NULL)
+        {
+            BTIF_TRACE_ERROR("%s: p_dev NULL", __func__);
+            return;
+        }
+
+        bdcpy(rc_addr.address, p_dev->rc_addr);
 
         for (int i = 0; i < p_rsp->num_attr; i++) {
             p_attr[i].attr_id = p_rsp->p_attrs[i].attr_id;
@@ -3072,9 +4235,9 @@ static void handle_get_elem_attr_response (tBTA_AV_META_MSG *pmeta_msg,
             AVRC_MEDIA_ATTR_ID_GENRE,
             AVRC_MEDIA_ATTR_ID_PLAYING_TIME
             };
-        get_element_attribute_cmd (AVRC_MAX_NUM_MEDIA_ATTR_ID, attr_list);
+        get_element_attribute_cmd (AVRC_MAX_NUM_MEDIA_ATTR_ID, attr_list, p_dev);
     } else {
-        BTIF_TRACE_ERROR("%s: Error in get element attr procedure %d",
+        BTIF_TRACE_ERROR("%s: Error in get element attr procedure: %d",
                          __func__, p_rsp->status);
     }
 }
@@ -3088,11 +4251,20 @@ static void handle_get_elem_attr_response (tBTA_AV_META_MSG *pmeta_msg,
 ** Returns          None
 **
 ***************************************************************************/
-static void handle_get_playstatus_response (tBTA_AV_META_MSG *pmeta_msg, tAVRC_GET_PLAY_STATUS_RSP *p_rsp)
+static void handle_get_playstatus_response (tBTA_AV_META_MSG *pmeta_msg,
+        tAVRC_GET_PLAY_STATUS_RSP *p_rsp)
 {
     bt_bdaddr_t rc_addr;
 
-    bdcpy(rc_addr.address, btif_rc_cb.rc_addr);
+    btif_rc_device_cb_t *p_dev = btif_rc_get_device_by_handle(pmeta_msg->rc_handle);
+
+    if (p_dev == NULL)
+    {
+        BTIF_TRACE_ERROR("%s: p_dev NULL", __func__);
+        return;
+    }
+
+    bdcpy(rc_addr.address, p_dev->rc_addr);
 
     if (p_rsp->status == AVRC_STS_NO_ERROR)
     {
@@ -3101,7 +4273,7 @@ static void handle_get_playstatus_response (tBTA_AV_META_MSG *pmeta_msg, tAVRC_G
     }
     else
     {
-        BTIF_TRACE_ERROR("%s: Error in get play status procedure %d",
+        BTIF_TRACE_ERROR("%s: Error in get play status procedure: %d",
             __func__, p_rsp->status);
     }
 }
@@ -3145,7 +4317,7 @@ static void handle_avk_rc_metamsg_rsp(tBTA_AV_META_MSG *pmeta_msg)
     uint16_t            buf_len;
     tAVRC_STS         status;
 
-    BTIF_TRACE_DEBUG("%s opcode = %d rsp_code = %d  ", __func__,
+    BTIF_TRACE_DEBUG("%s: opcode: %d rsp_code: %d  ", __func__,
                         pmeta_msg->p_msg->hdr.opcode, pmeta_msg->code);
 
     if ((AVRC_OP_VENDOR == pmeta_msg->p_msg->hdr.opcode)&&
@@ -3153,7 +4325,7 @@ static void handle_avk_rc_metamsg_rsp(tBTA_AV_META_MSG *pmeta_msg)
                 (pmeta_msg->code <= AVRC_RSP_INTERIM))
     {
         status = AVRC_Ctrl_ParsResponse(pmeta_msg->p_msg, &avrc_response, scratch_buf, &buf_len);
-        BTIF_TRACE_DEBUG("%s parse status %d pdu = %d rsp_status = %d",
+        BTIF_TRACE_DEBUG("%s: parse status: %d pdu: %d rsp_status: %d",
                          __func__, status, avrc_response.pdu,
                          pmeta_msg->p_msg->vendor.hdr.ctype);
 
@@ -3209,7 +4381,7 @@ static void handle_avk_rc_metamsg_rsp(tBTA_AV_META_MSG *pmeta_msg)
     }
     else
     {
-        BTIF_TRACE_DEBUG("%s:Invalid Vendor Command  code: %d len: %d. Not processing it.",
+        BTIF_TRACE_DEBUG("%s: Invalid Vendor Command code: %d len: %d. Not processing it.",
             __func__, pmeta_msg->code, pmeta_msg->len);
         return;
     }
@@ -3228,13 +4400,15 @@ static void handle_avk_rc_metamsg_cmd(tBTA_AV_META_MSG *pmeta_msg)
 {
     tAVRC_COMMAND    avrc_cmd = {0};
     tAVRC_STS status = BT_STATUS_UNSUPPORTED;
-    BTIF_TRACE_DEBUG("%s opcode = %d rsp_code = %d  ",__func__,
+    btif_rc_device_cb_t *p_dev = NULL;
+
+    BTIF_TRACE_DEBUG("%s: opcode: %d rsp_code: %d",__func__,
                      pmeta_msg->p_msg->hdr.opcode,pmeta_msg->code);
     if ((AVRC_OP_VENDOR==pmeta_msg->p_msg->hdr.opcode)&&
                 (pmeta_msg->code <= AVRC_CMD_GEN_INQ))
     {
         status = AVRC_Ctrl_ParsCommand(pmeta_msg->p_msg, &avrc_cmd);
-        BTIF_TRACE_DEBUG("%s Received vendor command.code %d, PDU %d label %d",
+        BTIF_TRACE_DEBUG("%s: Received vendor command.code: %d, PDU: %d label: %d",
                          __func__, pmeta_msg->code, avrc_cmd.pdu, pmeta_msg->label);
 
         if (status != AVRC_STS_NO_ERROR)
@@ -3242,26 +4416,35 @@ static void handle_avk_rc_metamsg_cmd(tBTA_AV_META_MSG *pmeta_msg)
             /* return error */
             BTIF_TRACE_WARNING("%s: Error in parsing received metamsg command. status: 0x%02x",
                 __func__, status);
-            send_reject_response(pmeta_msg->rc_handle, pmeta_msg->label, avrc_cmd.pdu, status);
+            send_reject_response(pmeta_msg->rc_handle, pmeta_msg->label, avrc_cmd.pdu, status,
+                pmeta_msg->p_msg->hdr.opcode);
         }
         else
         {
+            p_dev = btif_rc_get_device_by_handle(pmeta_msg->rc_handle);
+            if (p_dev == NULL)
+            {
+                BTIF_TRACE_ERROR("%s: avk rc meta msg cmd for Invalid rc handle", __func__);
+                return;
+            }
+
             if (avrc_cmd.pdu == AVRC_PDU_REGISTER_NOTIFICATION)
             {
                 uint8_t event_id = avrc_cmd.reg_notif.event_id;
-                BTIF_TRACE_EVENT("%s:Register notification event_id: %s",
+                BTIF_TRACE_EVENT("%s: Register notification event_id: %s",
                         __func__, dump_rc_notification_event_id(event_id));
             }
             else if (avrc_cmd.pdu == AVRC_PDU_SET_ABSOLUTE_VOLUME)
             {
                 BTIF_TRACE_EVENT("%s: Abs Volume Cmd Recvd", __func__);
             }
-            btif_rc_ctrl_upstreams_rsp_cmd(avrc_cmd.pdu, &avrc_cmd, pmeta_msg->label);
+
+            btif_rc_ctrl_upstreams_rsp_cmd(avrc_cmd.pdu, &avrc_cmd, pmeta_msg->label, p_dev);
         }
     }
     else
     {
-      BTIF_TRACE_DEBUG("%s:Invalid Vendor Command  code: %d len: %d. Not processing it.",
+      BTIF_TRACE_DEBUG("%s: Invalid Vendor Command  code: %d len: %d. Not processing it.",
                        __func__, pmeta_msg->code, pmeta_msg->len);
         return;
     }
@@ -3279,16 +4462,20 @@ static void handle_avk_rc_metamsg_cmd(tBTA_AV_META_MSG *pmeta_msg)
 ***************************************************************************/
 static void cleanup()
 {
-    BTIF_TRACE_EVENT("## %s ##", __func__);
+    BTIF_TRACE_EVENT("%s: ", __func__);
     close_uinput();
     if (bt_rc_callbacks)
     {
         bt_rc_callbacks = NULL;
     }
-    alarm_free(btif_rc_cb.rc_play_status_timer);
-    memset(&btif_rc_cb, 0, sizeof(btif_rc_cb_t));
+
+    for (int idx = 0; idx < BTIF_RC_NUM_CONN; idx++) {
+        alarm_free(btif_rc_cb.rc_multi_cb[idx].rc_play_status_timer);
+        memset(&btif_rc_cb.rc_multi_cb[idx], 0, sizeof(btif_rc_cb.rc_multi_cb[idx]));
+    }
+
     lbl_destroy();
-    BTIF_TRACE_EVENT("## %s ## completed", __func__);
+    BTIF_TRACE_EVENT("%s: completed", __func__);
 }
 
 /***************************************************************************
@@ -3302,16 +4489,21 @@ static void cleanup()
 ***************************************************************************/
 static void cleanup_ctrl()
 {
-    BTIF_TRACE_EVENT("## %s ##", __func__);
+    BTIF_TRACE_EVENT("%s: ", __func__);
 
     if (bt_rc_ctrl_callbacks)
     {
         bt_rc_ctrl_callbacks = NULL;
     }
-    alarm_free(btif_rc_cb.rc_play_status_timer);
-    memset(&btif_rc_cb, 0, sizeof(btif_rc_cb_t));
+
+    for (int idx = 0; idx < BTIF_RC_NUM_CONN; idx++) {
+        alarm_free(btif_rc_cb.rc_multi_cb[idx].rc_play_status_timer);
+        memset(&btif_rc_cb.rc_multi_cb[idx], 0, sizeof(btif_rc_cb.rc_multi_cb[idx]));
+    }
+
+    memset(&btif_rc_cb, 0, sizeof(rc_cb_t));
     lbl_destroy();
-    BTIF_TRACE_EVENT("## %s ## completed", __func__);
+    BTIF_TRACE_EVENT("%s: completed", __func__);
 }
 
 /***************************************************************************
@@ -3323,13 +4515,13 @@ static void cleanup_ctrl()
 ** Returns          void
 **
 ***************************************************************************/
-static bt_status_t getcapabilities_cmd (uint8_t cap_id)
+static bt_status_t getcapabilities_cmd (uint8_t cap_id, btif_rc_device_cb_t *p_dev)
 {
     tAVRC_STS status = BT_STATUS_UNSUPPORTED;
     rc_transaction_t *p_transaction = NULL;
 #if (AVRC_CTRL_INCLUDED == TRUE)
-    BTIF_TRACE_DEBUG("%s: cap_id %d", __func__, cap_id);
-    CHECK_RC_CONNECTED
+    BTIF_TRACE_DEBUG("%s: cap_id: %d", __func__, cap_id);
+    CHECK_RC_CONNECTED(p_dev)
     bt_status_t tran_status=get_transaction(&p_transaction);
     if (BT_STATUS_SUCCESS != tran_status)
         return BT_STATUS_FAIL;
@@ -3344,12 +4536,12 @@ static bt_status_t getcapabilities_cmd (uint8_t cap_id)
      if ((status == AVRC_STS_NO_ERROR)&&(p_msg != NULL))
      {
          uint8_t* data_start = (uint8_t*)(p_msg + 1) + p_msg->offset;
-         BTIF_TRACE_DEBUG("%s msgreq being sent out with label %d",
+         BTIF_TRACE_DEBUG("%s: msgreq being sent out with label: %d",
                             __func__,p_transaction->lbl);
-         BTA_AvVendorCmd(btif_rc_cb.rc_handle,p_transaction->lbl,AVRC_CMD_STATUS,
+         BTA_AvVendorCmd(p_dev->rc_handle,p_transaction->lbl,AVRC_CMD_STATUS,
                                                           data_start, p_msg->len);
          status =  BT_STATUS_SUCCESS;
-         start_status_command_timer (AVRC_PDU_GET_CAPABILITIES, p_transaction);
+         start_status_command_timer (AVRC_PDU_GET_CAPABILITIES, p_transaction, p_dev);
      }
      else
      {
@@ -3372,13 +4564,13 @@ static bt_status_t getcapabilities_cmd (uint8_t cap_id)
 ** Returns          void
 **
 ***************************************************************************/
-static bt_status_t list_player_app_setting_attrib_cmd(void)
+static bt_status_t list_player_app_setting_attrib_cmd(btif_rc_device_cb_t *p_dev)
 {
     tAVRC_STS status = BT_STATUS_UNSUPPORTED;
     rc_transaction_t *p_transaction = NULL;
 #if (AVRC_CTRL_INCLUDED == TRUE)
     BTIF_TRACE_DEBUG("%s: ", __func__);
-    CHECK_RC_CONNECTED
+    CHECK_RC_CONNECTED(p_dev)
     bt_status_t tran_status=get_transaction(&p_transaction);
     if (BT_STATUS_SUCCESS != tran_status)
         return BT_STATUS_FAIL;
@@ -3392,12 +4584,12 @@ static bt_status_t list_player_app_setting_attrib_cmd(void)
      if ((status == AVRC_STS_NO_ERROR)&&(p_msg != NULL))
      {
          uint8_t* data_start = (uint8_t*)(p_msg + 1) + p_msg->offset;
-         BTIF_TRACE_DEBUG("%s msgreq being sent out with label %d",
-                            __func__,p_transaction->lbl);
-         BTA_AvVendorCmd(btif_rc_cb.rc_handle,p_transaction->lbl,AVRC_CMD_STATUS,
+         BTIF_TRACE_DEBUG("%s: msgreq being sent out with label: %d",
+                            __func__, p_transaction->lbl);
+         BTA_AvVendorCmd(p_dev->rc_handle, p_transaction->lbl, AVRC_CMD_STATUS,
                                                           data_start, p_msg->len);
          status =  BT_STATUS_SUCCESS;
-         start_status_command_timer (AVRC_PDU_LIST_PLAYER_APP_ATTR, p_transaction);
+         start_status_command_timer (AVRC_PDU_LIST_PLAYER_APP_ATTR, p_transaction, p_dev);
      }
      else
      {
@@ -3421,13 +4613,14 @@ static bt_status_t list_player_app_setting_attrib_cmd(void)
 ** Returns          void
 **
 ***************************************************************************/
-static bt_status_t list_player_app_setting_value_cmd(uint8_t attrib_id)
+static bt_status_t list_player_app_setting_value_cmd(uint8_t attrib_id,
+    btif_rc_device_cb_t *p_dev)
 {
     tAVRC_STS status = BT_STATUS_UNSUPPORTED;
     rc_transaction_t *p_transaction=NULL;
 #if (AVRC_CTRL_INCLUDED == TRUE)
-    BTIF_TRACE_DEBUG("%s: attrib_id %d", __func__, attrib_id);
-    CHECK_RC_CONNECTED
+    BTIF_TRACE_DEBUG("%s: attrib_id: %d", __func__, attrib_id);
+    CHECK_RC_CONNECTED(p_dev)
     bt_status_t tran_status=get_transaction(&p_transaction);
     if (BT_STATUS_SUCCESS != tran_status)
         return BT_STATUS_FAIL;
@@ -3442,12 +4635,12 @@ static bt_status_t list_player_app_setting_value_cmd(uint8_t attrib_id)
      if ((status == AVRC_STS_NO_ERROR) && (p_msg != NULL))
      {
          uint8_t* data_start = (uint8_t*)(p_msg + 1) + p_msg->offset;
-         BTIF_TRACE_DEBUG("%s msgreq being sent out with label %d",
+         BTIF_TRACE_DEBUG("%s: msgreq being sent out with label: %d",
                             __func__,p_transaction->lbl);
-         BTA_AvVendorCmd(btif_rc_cb.rc_handle,p_transaction->lbl,AVRC_CMD_STATUS,
+         BTA_AvVendorCmd(p_dev->rc_handle, p_transaction->lbl, AVRC_CMD_STATUS,
                                data_start, p_msg->len);
          status =  BT_STATUS_SUCCESS;
-         start_status_command_timer (AVRC_PDU_LIST_PLAYER_APP_VALUES, p_transaction);
+         start_status_command_timer (AVRC_PDU_LIST_PLAYER_APP_VALUES, p_transaction, p_dev);
      }
      else
      {
@@ -3469,14 +4662,15 @@ static bt_status_t list_player_app_setting_value_cmd(uint8_t attrib_id)
 ** Returns          void
 **
 ***************************************************************************/
-static bt_status_t get_player_app_setting_cmd(uint8_t num_attrib, uint8_t* attrib_ids)
+static bt_status_t get_player_app_setting_cmd(uint8_t num_attrib, uint8_t* attrib_ids,
+    btif_rc_device_cb_t *p_dev)
 {
     tAVRC_STS status = BT_STATUS_UNSUPPORTED;
     rc_transaction_t *p_transaction = NULL;
     int count  = 0;
 #if (AVRC_CTRL_INCLUDED == TRUE)
-    BTIF_TRACE_DEBUG("%s: num attrib_id %d", __func__, num_attrib);
-    CHECK_RC_CONNECTED
+    BTIF_TRACE_DEBUG("%s: num attrib_id: %d", __func__, num_attrib);
+    CHECK_RC_CONNECTED(p_dev)
     bt_status_t tran_status=get_transaction(&p_transaction);
     if (BT_STATUS_SUCCESS != tran_status)
         return BT_STATUS_FAIL;
@@ -3496,12 +4690,12 @@ static bt_status_t get_player_app_setting_cmd(uint8_t num_attrib, uint8_t* attri
      if ((status == AVRC_STS_NO_ERROR) && (p_msg != NULL))
      {
          uint8_t* data_start = (uint8_t*)(p_msg + 1) + p_msg->offset;
-         BTIF_TRACE_DEBUG("%s msgreq being sent out with label %d",
-                            __func__,p_transaction->lbl);
-         BTA_AvVendorCmd(btif_rc_cb.rc_handle,p_transaction->lbl,AVRC_CMD_STATUS,
+         BTIF_TRACE_DEBUG("%s: msgreq being sent out with label: %d",
+                            __func__, p_transaction->lbl);
+         BTA_AvVendorCmd(p_dev->rc_handle,p_transaction->lbl,AVRC_CMD_STATUS,
                           data_start, p_msg->len);
          status =  BT_STATUS_SUCCESS;
-         start_status_command_timer (AVRC_PDU_GET_CUR_PLAYER_APP_VALUE, p_transaction);
+         start_status_command_timer (AVRC_PDU_GET_CUR_PLAYER_APP_VALUE, p_transaction, p_dev);
      }
      else
      {
@@ -3524,14 +4718,16 @@ static bt_status_t get_player_app_setting_cmd(uint8_t num_attrib, uint8_t* attri
 ** Returns          void
 **
 ***************************************************************************/
-static bt_status_t change_player_app_setting(bt_bdaddr_t *bd_addr, uint8_t num_attrib, uint8_t* attrib_ids, uint8_t* attrib_vals)
+static bt_status_t change_player_app_setting(bt_bdaddr_t *bd_addr, uint8_t num_attrib,
+        uint8_t* attrib_ids, uint8_t* attrib_vals)
 {
     tAVRC_STS status = BT_STATUS_UNSUPPORTED;
     rc_transaction_t *p_transaction = NULL;
     int count  = 0;
+    btif_rc_device_cb_t *p_dev = btif_rc_get_device_by_bda(bd_addr);
 #if (AVRC_CTRL_INCLUDED == TRUE)
-    BTIF_TRACE_DEBUG("%s: num attrib_id %d", __func__, num_attrib);
-    CHECK_RC_CONNECTED
+    BTIF_TRACE_DEBUG("%s: num attrib_id: %d", __func__, num_attrib);
+    CHECK_RC_CONNECTED(p_dev)
     bt_status_t tran_status=get_transaction(&p_transaction);
     if (BT_STATUS_SUCCESS != tran_status)
         return BT_STATUS_FAIL;
@@ -3553,12 +4749,12 @@ static bt_status_t change_player_app_setting(bt_bdaddr_t *bd_addr, uint8_t num_a
      if ((status == AVRC_STS_NO_ERROR) && (p_msg != NULL))
      {
          uint8_t* data_start = (uint8_t*)(p_msg + 1) + p_msg->offset;
-         BTIF_TRACE_DEBUG("%s msgreq being sent out with label %d",
-                            __func__,p_transaction->lbl);
-         BTA_AvVendorCmd(btif_rc_cb.rc_handle,p_transaction->lbl,AVRC_CMD_CTRL,
+         BTIF_TRACE_DEBUG("%s: msgreq being sent out with label: %d",
+                            __func__, p_transaction->lbl);
+         BTA_AvVendorCmd(p_dev->rc_handle, p_transaction->lbl, AVRC_CMD_CTRL,
                               data_start, p_msg->len);
          status =  BT_STATUS_SUCCESS;
-         start_control_command_timer (AVRC_PDU_SET_PLAYER_APP_VALUE, p_transaction);
+         start_control_command_timer (AVRC_PDU_SET_PLAYER_APP_VALUE, p_transaction, p_dev);
      }
      else
      {
@@ -3582,7 +4778,8 @@ static bt_status_t change_player_app_setting(bt_bdaddr_t *bd_addr, uint8_t num_a
 ** Returns          void
 **
 ***************************************************************************/
-static bt_status_t get_player_app_setting_attr_text_cmd (uint8_t *attrs, uint8_t num_attrs)
+static bt_status_t get_player_app_setting_attr_text_cmd (uint8_t *attrs, uint8_t num_attrs,
+    btif_rc_device_cb_t *p_dev)
 {
     tAVRC_STS status = BT_STATUS_UNSUPPORTED;
     rc_transaction_t *p_transaction = NULL;
@@ -3591,9 +4788,9 @@ static bt_status_t get_player_app_setting_attr_text_cmd (uint8_t *attrs, uint8_t
     tAVRC_COMMAND avrc_cmd = {0};
     BT_HDR *p_msg = NULL;
     bt_status_t tran_status;
-    CHECK_RC_CONNECTED
+    CHECK_RC_CONNECTED(p_dev)
 
-    BTIF_TRACE_DEBUG("%s: num attrs %d", __func__, num_attrs);
+    BTIF_TRACE_DEBUG("%s: num attrs: %d", __func__, num_attrs);
 
     tran_status = get_transaction(&p_transaction);
     if (BT_STATUS_SUCCESS != tran_status)
@@ -3611,13 +4808,13 @@ static bt_status_t get_player_app_setting_attr_text_cmd (uint8_t *attrs, uint8_t
     if (status == AVRC_STS_NO_ERROR)
     {
         uint8_t* data_start = (uint8_t*)(p_msg + 1) + p_msg->offset;
-                BTIF_TRACE_DEBUG("%s msgreq being sent out with label %d",
+                BTIF_TRACE_DEBUG("%s: msgreq being sent out with label: %d",
                 __func__, p_transaction->lbl);
-        BTA_AvVendorCmd(btif_rc_cb.rc_handle, p_transaction->lbl,
+        BTA_AvVendorCmd(p_dev->rc_handle, p_transaction->lbl,
                 AVRC_CMD_STATUS, data_start, p_msg->len);
         osi_free(p_msg);
         status =  BT_STATUS_SUCCESS;
-        start_status_command_timer (AVRC_PDU_GET_PLAYER_APP_ATTR_TEXT, p_transaction);
+        start_status_command_timer (AVRC_PDU_GET_PLAYER_APP_ATTR_TEXT, p_transaction, p_dev);
     }
     else
     {
@@ -3639,7 +4836,8 @@ static bt_status_t get_player_app_setting_attr_text_cmd (uint8_t *attrs, uint8_t
 ** Returns          void
 **
 ***************************************************************************/
-static bt_status_t get_player_app_setting_value_text_cmd (uint8_t *vals, uint8_t num_vals)
+static bt_status_t get_player_app_setting_value_text_cmd (uint8_t *vals, uint8_t num_vals,
+    btif_rc_device_cb_t *p_dev)
 {
     tAVRC_STS status = BT_STATUS_UNSUPPORTED;
     rc_transaction_t *p_transaction = NULL;
@@ -3648,9 +4846,9 @@ static bt_status_t get_player_app_setting_value_text_cmd (uint8_t *vals, uint8_t
     tAVRC_COMMAND avrc_cmd = {0};
     BT_HDR *p_msg = NULL;
     bt_status_t tran_status;
-    CHECK_RC_CONNECTED
+    CHECK_RC_CONNECTED(p_dev)
 
-    BTIF_TRACE_DEBUG("%s: num_vals %d", __func__, num_vals);
+    BTIF_TRACE_DEBUG("%s: num_vals: %d", __func__, num_vals);
 
     tran_status = get_transaction(&p_transaction);
     if (BT_STATUS_SUCCESS != tran_status)
@@ -3668,14 +4866,14 @@ static bt_status_t get_player_app_setting_value_text_cmd (uint8_t *vals, uint8_t
     if (status == AVRC_STS_NO_ERROR)
     {
         uint8_t* data_start = (uint8_t*)(p_msg + 1) + p_msg->offset;
-        BTIF_TRACE_DEBUG("%s msgreq being sent out with label %d",
+        BTIF_TRACE_DEBUG("%s: msgreq being sent out with label: %d",
                          __func__, p_transaction->lbl);
         if (p_msg != NULL)
         {
-            BTA_AvVendorCmd(btif_rc_cb.rc_handle, p_transaction->lbl,
+            BTA_AvVendorCmd(p_dev->rc_handle, p_transaction->lbl,
                     AVRC_CMD_STATUS, data_start, p_msg->len);
             status =  BT_STATUS_SUCCESS;
-            start_status_command_timer (AVRC_PDU_GET_PLAYER_APP_VALUE_TEXT, p_transaction);
+            start_status_command_timer (AVRC_PDU_GET_PLAYER_APP_VALUE_TEXT, p_transaction, p_dev);
         }
     }
     else
@@ -3699,17 +4897,18 @@ static bt_status_t get_player_app_setting_value_text_cmd (uint8_t *vals, uint8_t
 ** Returns          void
 **
 ***************************************************************************/
-static bt_status_t register_notification_cmd (uint8_t label, uint8_t event_id, uint32_t event_value)
+static bt_status_t register_notification_cmd (uint8_t label, uint8_t event_id, uint32_t event_value,
+    btif_rc_device_cb_t *p_dev)
 {
 
     tAVRC_STS status = BT_STATUS_UNSUPPORTED;
 #if (AVRC_CTRL_INCLUDED == TRUE)
     tAVRC_COMMAND avrc_cmd = {0};
     BT_HDR *p_msg = NULL;
-    CHECK_RC_CONNECTED
+    CHECK_RC_CONNECTED(p_dev)
 
 
-    BTIF_TRACE_DEBUG("%s: event_id %d  event_value", __func__, event_id, event_value);
+    BTIF_TRACE_DEBUG("%s: event_id: %d  event_value", __func__, event_id, event_value);
 
     avrc_cmd.reg_notif.opcode = AVRC_OP_VENDOR;
     avrc_cmd.reg_notif.status = AVRC_STS_NO_ERROR;
@@ -3720,11 +4919,11 @@ static bt_status_t register_notification_cmd (uint8_t label, uint8_t event_id, u
     if (status == AVRC_STS_NO_ERROR)
     {
         uint8_t* data_start = (uint8_t*)(p_msg + 1) + p_msg->offset;
-        BTIF_TRACE_DEBUG("%s msgreq being sent out with label %d",
+        BTIF_TRACE_DEBUG("%s: msgreq being sent out with label: %d",
                 __func__, label);
         if (p_msg != NULL)
         {
-            BTA_AvVendorCmd(btif_rc_cb.rc_handle, label, AVRC_CMD_NOTIF,
+            BTA_AvVendorCmd(p_dev->rc_handle, label, AVRC_CMD_NOTIF,
                     data_start, p_msg->len);
             status =  BT_STATUS_SUCCESS;
         }
@@ -3750,7 +4949,8 @@ static bt_status_t register_notification_cmd (uint8_t label, uint8_t event_id, u
 ** Returns          void
 **
 ***************************************************************************/
-static bt_status_t get_element_attribute_cmd (uint8_t num_attribute, uint32_t *p_attr_ids)
+static bt_status_t get_element_attribute_cmd (uint8_t num_attribute, uint32_t *p_attr_ids,
+    btif_rc_device_cb_t *p_dev)
 {
     tAVRC_STS status = BT_STATUS_UNSUPPORTED;
     rc_transaction_t *p_transaction=NULL;
@@ -3759,9 +4959,9 @@ static bt_status_t get_element_attribute_cmd (uint8_t num_attribute, uint32_t *p
     tAVRC_COMMAND avrc_cmd = {0};
     BT_HDR *p_msg = NULL;
     bt_status_t tran_status;
-    CHECK_RC_CONNECTED
+    CHECK_RC_CONNECTED(p_dev)
 
-    BTIF_TRACE_DEBUG("%s: num_attribute  %d attribute_id %d",
+    BTIF_TRACE_DEBUG("%s: num_attribute: %d attribute_id: %d",
                    __func__, num_attribute, p_attr_ids[0]);
 
     tran_status = get_transaction(&p_transaction);
@@ -3781,15 +4981,15 @@ static bt_status_t get_element_attribute_cmd (uint8_t num_attribute, uint32_t *p
     if (status == AVRC_STS_NO_ERROR)
     {
         uint8_t* data_start = (uint8_t*)(p_msg + 1) + p_msg->offset;
-        BTIF_TRACE_DEBUG("%s msgreq being sent out with label %d",
+        BTIF_TRACE_DEBUG("%s: msgreq being sent out with label: %d",
                 __func__, p_transaction->lbl);
         if (p_msg != NULL)
         {
-            BTA_AvVendorCmd(btif_rc_cb.rc_handle, p_transaction->lbl,
+            BTA_AvVendorCmd(p_dev->rc_handle, p_transaction->lbl,
                     AVRC_CMD_STATUS, data_start, p_msg->len);
             status =  BT_STATUS_SUCCESS;
             start_status_command_timer (AVRC_PDU_GET_ELEMENT_ATTR,
-                    p_transaction);
+                    p_transaction, p_dev);
         }
     }
     else
@@ -3808,12 +5008,12 @@ static bt_status_t get_element_attribute_cmd (uint8_t num_attribute, uint32_t *p
 **
 ** Function         get_play_status_cmd
 **
-** Description      Get Element Attribute for  attributeIds
+** Description      Get Playing Status of a Device
 **
-** Returns          void
+** Returns          bt_status_t
 **
 ***************************************************************************/
-static bt_status_t get_play_status_cmd(void)
+static bt_status_t get_play_status_cmd(btif_rc_device_cb_t *p_dev)
 {
     tAVRC_STS status = BT_STATUS_UNSUPPORTED;
     rc_transaction_t *p_transaction = NULL;
@@ -3821,7 +5021,7 @@ static bt_status_t get_play_status_cmd(void)
     tAVRC_COMMAND avrc_cmd = {0};
     BT_HDR *p_msg = NULL;
     bt_status_t tran_status;
-    CHECK_RC_CONNECTED
+    CHECK_RC_CONNECTED(p_dev)
 
     BTIF_TRACE_DEBUG("%s: ", __func__);
     tran_status = get_transaction(&p_transaction);
@@ -3835,14 +5035,14 @@ static bt_status_t get_play_status_cmd(void)
     if (status == AVRC_STS_NO_ERROR)
     {
         uint8_t* data_start = (uint8_t*)(p_msg + 1) + p_msg->offset;
-        BTIF_TRACE_DEBUG("%s msgreq being sent out with label %d",
+        BTIF_TRACE_DEBUG("%s: msgreq being sent out with label: %d",
                 __func__, p_transaction->lbl);
         if (p_msg != NULL)
         {
-            BTA_AvVendorCmd(btif_rc_cb.rc_handle,p_transaction->lbl,
+            BTA_AvVendorCmd(p_dev->rc_handle,p_transaction->lbl,
                     AVRC_CMD_STATUS, data_start, p_msg->len);
             status =  BT_STATUS_SUCCESS;
-            start_status_command_timer (AVRC_PDU_GET_PLAY_STATUS, p_transaction);
+            start_status_command_timer (AVRC_PDU_GET_PLAY_STATUS, p_transaction, p_dev);
         }
     }
     else
@@ -3873,23 +5073,24 @@ static bt_status_t set_volume_rsp(bt_bdaddr_t *bd_addr, uint8_t abs_vol, uint8_t
 #if (AVRC_CTRL_INCLUDED == TRUE)
     tAVRC_RESPONSE avrc_rsp;
     BT_HDR *p_msg = NULL;
-    CHECK_RC_CONNECTED
+    btif_rc_device_cb_t *p_dev = btif_rc_get_device_by_bda(bd_addr);
+    CHECK_RC_CONNECTED(p_dev)
 
-    BTIF_TRACE_DEBUG("%s: abs_vol %d", __func__, abs_vol);
+    BTIF_TRACE_DEBUG("%s: abs_vol: %d", __func__, abs_vol);
 
     avrc_rsp.volume.opcode = AVRC_OP_VENDOR;
     avrc_rsp.volume.pdu = AVRC_PDU_SET_ABSOLUTE_VOLUME;
     avrc_rsp.volume.status = AVRC_STS_NO_ERROR;
     avrc_rsp.volume.volume = abs_vol;
-    status = AVRC_BldResponse(btif_rc_cb.rc_handle, &avrc_rsp, &p_msg);
+    status = AVRC_BldResponse(p_dev->rc_handle, &avrc_rsp, &p_msg);
     if (status == AVRC_STS_NO_ERROR)
     {
         uint8_t* data_start = (uint8_t*)(p_msg + 1) + p_msg->offset;
-        BTIF_TRACE_DEBUG("%s msgreq being sent out with label %d",
-                __func__, btif_rc_cb.rc_vol_label);
+        BTIF_TRACE_DEBUG("%s: msgreq being sent out with label: %d",
+                __func__, p_dev->rc_vol_label);
         if (p_msg != NULL)
         {
-            BTA_AvVendorRsp(btif_rc_cb.rc_handle, label,
+            BTA_AvVendorRsp(p_dev->rc_handle, label,
                     BTA_AV_RSP_ACCEPT, data_start, p_msg->len, 0);
             status =  BT_STATUS_SUCCESS;
         }
@@ -3915,15 +5116,17 @@ static bt_status_t set_volume_rsp(bt_bdaddr_t *bd_addr, uint8_t abs_vol, uint8_t
 ** Returns          void
 **
 ***************************************************************************/
-static bt_status_t volume_change_notification_rsp(bt_bdaddr_t *bd_addr, btrc_notification_type_t rsp_type,
-            uint8_t abs_vol, uint8_t label)
+static bt_status_t volume_change_notification_rsp(bt_bdaddr_t *bd_addr,
+        btrc_notification_type_t rsp_type, uint8_t abs_vol, uint8_t label)
 {
     tAVRC_STS status = BT_STATUS_UNSUPPORTED;
     tAVRC_RESPONSE avrc_rsp;
     BT_HDR *p_msg = NULL;
 #if (AVRC_CTRL_INCLUDED == TRUE)
-    BTIF_TRACE_DEBUG("%s: rsp_type  %d abs_vol %d", __func__, rsp_type, abs_vol);
-    CHECK_RC_CONNECTED
+    BTIF_TRACE_DEBUG("%s: rsp_type: %d abs_vol: %d", __func__, rsp_type, abs_vol);
+
+    btif_rc_device_cb_t *p_dev = btif_rc_get_device_by_bda(bd_addr);
+    CHECK_RC_CONNECTED(p_dev)
 
     avrc_rsp.reg_notif.opcode = AVRC_OP_VENDOR;
     avrc_rsp.reg_notif.pdu = AVRC_PDU_REGISTER_NOTIFICATION;
@@ -3931,12 +5134,12 @@ static bt_status_t volume_change_notification_rsp(bt_bdaddr_t *bd_addr, btrc_not
     avrc_rsp.reg_notif.param.volume = abs_vol;
     avrc_rsp.reg_notif.event_id = AVRC_EVT_VOLUME_CHANGE;
 
-    status = AVRC_BldResponse(btif_rc_cb.rc_handle, &avrc_rsp, &p_msg);
+    status = AVRC_BldResponse(p_dev->rc_handle, &avrc_rsp, &p_msg);
     if (status == AVRC_STS_NO_ERROR) {
-        BTIF_TRACE_DEBUG("%s msgreq being sent out with label %d",
+        BTIF_TRACE_DEBUG("%s: msgreq being sent out with label: %d",
                          __func__, label);
         uint8_t* data_start = (uint8_t*)(p_msg + 1) + p_msg->offset;
-        BTA_AvVendorRsp(btif_rc_cb.rc_handle, label,
+        BTA_AvVendorRsp(p_dev->rc_handle, label,
                         (rsp_type == BTRC_NOTIFICATION_TYPE_INTERIM) ?
                             AVRC_RSP_INTERIM : AVRC_RSP_CHANGED,
                         data_start, p_msg->len, 0);
@@ -3970,8 +5173,10 @@ static bt_status_t send_groupnavigation_cmd(bt_bdaddr_t *bd_addr, uint8_t key_co
     rc_transaction_t *p_transaction=NULL;
     BTIF_TRACE_DEBUG("%s: key-code: %d, key-state: %d", __func__,
                                                     key_code, key_state);
-    CHECK_RC_CONNECTED
-    if (btif_rc_cb.rc_features & BTA_AV_FEAT_RCTG)
+    btif_rc_device_cb_t *p_dev = btif_rc_get_device_by_bda(bd_addr);
+    CHECK_RC_CONNECTED(p_dev)
+
+    if (p_dev->rc_features & BTA_AV_FEAT_RCTG)
     {
         bt_status_t tran_status = get_transaction(&p_transaction);
         if ((BT_STATUS_SUCCESS == tran_status) && (NULL != p_transaction)) {
@@ -3980,7 +5185,7 @@ static bt_status_t send_groupnavigation_cmd(bt_bdaddr_t *bd_addr, uint8_t key_co
              UINT24_TO_BE_STREAM(start, AVRC_CO_METADATA);
              *(start)++ = 0;
              UINT8_TO_BE_STREAM(start, key_code);
-             BTA_AvRemoteVendorUniqueCmd(btif_rc_cb.rc_handle,
+             BTA_AvRemoteVendorUniqueCmd(p_dev->rc_handle,
                                          p_transaction->lbl,
                                          (tBTA_AV_STATE)key_state, buffer,
                                          AVRC_PASS_THRU_GROUP_LEN);
@@ -4014,20 +5219,24 @@ static bt_status_t send_groupnavigation_cmd(bt_bdaddr_t *bd_addr, uint8_t key_co
 ** Returns          void
 **
 ***************************************************************************/
-static bt_status_t send_passthrough_cmd(bt_bdaddr_t *bd_addr, uint8_t key_code, uint8_t key_state)
+static bt_status_t send_passthrough_cmd(bt_bdaddr_t *bd_addr, uint8_t key_code,
+    uint8_t key_state)
 {
     tAVRC_STS status = BT_STATUS_UNSUPPORTED;
+    btif_rc_device_cb_t *p_dev = NULL;
+    BTIF_TRACE_ERROR("%s: calling btif_rc_get_device_by_bda", __func__);
+    p_dev = btif_rc_get_device_by_bda(bd_addr);
 #if (AVRC_CTRL_INCLUDED == TRUE)
-    CHECK_RC_CONNECTED
+    CHECK_RC_CONNECTED(p_dev)
     rc_transaction_t *p_transaction=NULL;
     BTIF_TRACE_DEBUG("%s: key-code: %d, key-state: %d", __func__,
                                                     key_code, key_state);
-    if (btif_rc_cb.rc_features & BTA_AV_FEAT_RCTG)
+    if (p_dev->rc_features & BTA_AV_FEAT_RCTG)
     {
         bt_status_t tran_status = get_transaction(&p_transaction);
         if (BT_STATUS_SUCCESS == tran_status && NULL != p_transaction)
         {
-            BTA_AvRemoteCmd(btif_rc_cb.rc_handle, p_transaction->lbl,
+            BTA_AvRemoteCmd(p_dev->rc_handle, p_transaction->lbl,
                 (tBTA_AV_RC)key_code, (tBTA_AV_STATE)key_state);
             status =  BT_STATUS_SUCCESS;
             BTIF_TRACE_DEBUG("%s: succesfully sent passthrough command to BTA", __func__);
@@ -4062,6 +5271,15 @@ static const btrc_interface_t bt_rc_interface = {
     NULL, /* set_player_app_value_rsp */
     register_notification_rsp,
     set_volume,
+    set_addressed_player_rsp,
+    set_browsed_player_rsp,
+    get_folder_items_list_rsp,
+    change_path_rsp,
+    get_item_attr_rsp,
+    play_item_rsp,
+    get_total_num_of_items_rsp,
+    search_rsp,
+    add_to_now_playing_rsp,
     cleanup,
 };
 
@@ -4087,7 +5305,7 @@ static const btrc_ctrl_interface_t bt_rc_ctrl_interface = {
 *******************************************************************************/
 const btrc_interface_t *btif_rc_get_interface(void)
 {
-    BTIF_TRACE_EVENT("%s", __func__);
+    BTIF_TRACE_EVENT("%s", __func__);
     return &bt_rc_interface;
 }
 
@@ -4102,7 +5320,7 @@ const btrc_interface_t *btif_rc_get_interface(void)
 *******************************************************************************/
 const btrc_ctrl_interface_t *btif_rc_ctrl_get_interface(void)
 {
-    BTIF_TRACE_EVENT("%s", __func__);
+    BTIF_TRACE_EVENT("%s", __func__);
     return &bt_rc_ctrl_interface;
 }
 
@@ -4214,7 +5432,7 @@ bt_status_t  get_transaction(rc_transaction_t **ptransaction)
     {
         if (false==device.transaction[i].in_use)
         {
-            BTIF_TRACE_DEBUG("%s:Got transaction.label: %d",__func__,device.transaction[i].lbl);
+            BTIF_TRACE_DEBUG("%s: Got transaction.label: %d",__func__,device.transaction[i].lbl);
             device.transaction[i].in_use = true;
             *ptransaction = &(device.transaction[i]);
             result = BT_STATUS_SUCCESS;
@@ -4284,11 +5502,3 @@ static bool absolute_volume_disabled() {
     }
     return false;
 }
-
-static char const* key_id_to_str(uint16_t id) {
-    for (int i = 0; key_map[i].name != NULL; i++) {
-        if (id == key_map[i].mapped_id)
-            return key_map[i].name;
-    }
-    return "UNKNOWN KEY";
-}
index 688cd74..ad1e9f1 100644 (file)
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  *  Copyright (c) 2014 The Android Open Source Project
- *  Copyright (C) 2009-2012 Broadcom Corporation
+ *  Copyright (C) 2009-2016 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -485,6 +485,8 @@ const char *dump_rc_event(uint8_t event)
    switch(event) {
         CASE_RETURN_STR(BTA_AV_RC_OPEN_EVT)
         CASE_RETURN_STR(BTA_AV_RC_CLOSE_EVT)
+        CASE_RETURN_STR(BTA_AV_RC_BROWSE_OPEN_EVT)
+        CASE_RETURN_STR(BTA_AV_RC_BROWSE_CLOSE_EVT)
         CASE_RETURN_STR(BTA_AV_REMOTE_CMD_EVT)
         CASE_RETURN_STR(BTA_AV_REMOTE_RSP_EVT)
         CASE_RETURN_STR(BTA_AV_VENDOR_CMD_EVT)
@@ -509,6 +511,10 @@ const char * dump_rc_notification_event_id(uint8_t event_id)
         CASE_RETURN_STR(AVRC_EVT_SYSTEM_STATUS_CHANGE)
         CASE_RETURN_STR(AVRC_EVT_APP_SETTING_CHANGE)
         CASE_RETURN_STR(AVRC_EVT_VOLUME_CHANGE)
+        CASE_RETURN_STR(AVRC_EVT_ADDR_PLAYER_CHANGE)
+        CASE_RETURN_STR(AVRC_EVT_AVAL_PLAYERS_CHANGE)
+        CASE_RETURN_STR(AVRC_EVT_NOW_PLAYING_CHANGE)
+        CASE_RETURN_STR(AVRC_EVT_UIDS_CHANGE)
 
         default:
             return "Unhandled Event ID";
@@ -536,6 +542,15 @@ const char*  dump_rc_pdu(uint8_t pdu)
         CASE_RETURN_STR(AVRC_PDU_SET_ADDRESSED_PLAYER)
         CASE_RETURN_STR(AVRC_PDU_CHANGE_PATH)
         CASE_RETURN_STR(AVRC_PDU_GET_CAPABILITIES)
+        CASE_RETURN_STR(AVRC_PDU_SET_BROWSED_PLAYER)
+        CASE_RETURN_STR(AVRC_PDU_GET_FOLDER_ITEMS)
+        CASE_RETURN_STR(AVRC_PDU_GET_ITEM_ATTRIBUTES)
+        CASE_RETURN_STR(AVRC_PDU_PLAY_ITEM)
+        CASE_RETURN_STR(AVRC_PDU_SEARCH)
+        CASE_RETURN_STR(AVRC_PDU_ADD_TO_NOW_PLAYING)
+        CASE_RETURN_STR(AVRC_PDU_GET_TOTAL_NUM_OF_ITEMS)
+        CASE_RETURN_STR(AVRC_PDU_GENERAL_REJECT)
+
         default:
             return "Unknown PDU";
     }
index 3e792d8..f339cb4 100644 (file)
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  *  Copyright (c) 2014 The Android Open Source Project
- *  Copyright (C) 1999-2012 Broadcom Corporation
+ *  Copyright (C) 1999-2016 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
 #define AVCT_CMD_BUF_SIZE               288
 #endif
 
+#ifndef AVCT_USER_TX_BUF_SIZE
+#define AVCT_USER_TX_BUF_SIZE           BT_DEFAULT_BUFFER_SIZE
+#endif
+
+#ifndef AVCT_USER_RX_BUF_SIZE
+#define AVCT_USER_RX_BUF_SIZE           BT_DEFAULT_BUFFER_SIZE
+#endif
+
+#ifndef AVCT_FCR_TX_BUF_SIZE
+#define AVCT_FCR_TX_BUF_SIZE            BT_DEFAULT_BUFFER_SIZE
+#endif
+
+#ifndef AVCT_FCR_RX_BUF_SIZE
+#define AVCT_FCR_RX_BUF_SIZE            BT_DEFAULT_BUFFER_SIZE
+#endif
+
 /* AVRCP buffer size for protocol messages */
 #ifndef AVRC_CMD_BUF_SIZE
 #define AVRC_CMD_BUF_SIZE               288
 #define AVCT_NUM_CONN               3
 #endif
 
+/* AVCTP Browsing channel FCR Option:
+ * Size of the transmission window when using enhanced retransmission mode. Not used
+ * in basic and streaming modes. Range: 1 - 63
+ */
+#ifndef AVCT_BR_FCR_OPT_TX_WINDOW_SIZE
+#define AVCT_BR_FCR_OPT_TX_WINDOW_SIZE      10
+#endif
+
+/* AVCTP Browsing channel FCR Option:
+ * Number of transmission attempts for a single I-Frame before taking
+ * Down the connection. Used In ERTM mode only. Value is Ignored in basic and
+ * Streaming modes.
+ * Range: 0, 1-0xFF
+ *     0 - infinite retransmissions
+ *     1 - single transmission
+ */
+#ifndef AVCT_BR_FCR_OPT_MAX_TX_B4_DISCNT
+#define AVCT_BR_FCR_OPT_MAX_TX_B4_DISCNT    20
+#endif
+
+/* AVCTP Browsing channel FCR Option: Retransmission Timeout
+ * The AVRCP specification set a value in the range of 300 - 2000 ms
+ * Timeout (in msecs) to detect Lost I-Frames. Only used in Enhanced retransmission mode.
+ * Range: Minimum 2000 (2 secs) when supporting PBF.
+ */
+#ifndef AVCT_BR_FCR_OPT_RETX_TOUT
+#define AVCT_BR_FCR_OPT_RETX_TOUT           2000
+#endif
+
+/* AVCTP Browsing channel FCR Option: Monitor Timeout
+ * The AVRCP specification set a value in the range of 300 - 2000 ms
+ * Timeout (in msecs) to detect Lost S-Frames. Only used in Enhanced retransmission mode.
+ * Range: Minimum 12000 (12 secs) when supporting PBF.
+ */
+#ifndef AVCT_BR_FCR_OPT_MONITOR_TOUT
+#define AVCT_BR_FCR_OPT_MONITOR_TOUT        12000
+#endif
+
+#ifndef AVCT_BROWSE_INCLUDED
+#define AVCT_BROWSE_INCLUDED        TRUE
+#endif
+
 /******************************************************************************
 **
 ** AVRCP
 #define DUMP_PCM_DATA               FALSE
 #endif
 
+/* TRUE to support the AVRCP 1.6 (GetTotalNumOfItems). */
+#ifndef AVRC_1_6_INCLUDED
+#define AVRC_1_6_INCLUDED           TRUE
+#endif
+
 /******************************************************************************
 **
 ** MCAP
index 924f9b1..ac2070f 100644 (file)
@@ -97,6 +97,8 @@ LOCAL_SRC_FILES := \
     ./gatt/gatt_attr.c \
     ./gatt/gatt_db.c \
     ./avct/avct_api.c \
+    ./avct/avct_l2c_br.c \
+    ./avct/avct_bcb_act.c \
     ./avct/avct_l2c.c \
     ./avct/avct_lcb.c \
     ./avct/avct_ccb.c \
index bd45e9f..bedac10 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2003-2012 Broadcom Corporation
+ *  Copyright (C) 2003-2016 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -72,8 +72,9 @@ void AVCT_Register(uint16_t mtu, uint16_t mtu_br, uint8_t sec_mask)
     /* Include the browsing channel which uses eFCR */
     L2CA_Register(AVCT_BR_PSM, (tL2CAP_APPL_INFO *) &avct_l2c_br_appl);
 
-    BTM_SetSecurityLevel(true, "", BTM_SEC_SERVICE_AVCTP_BROWSE, sec_mask, AVCT_BR_PSM, 0, 0);
-    BTM_SetSecurityLevel(false, "", BTM_SEC_SERVICE_AVCTP_BROWSE, sec_mask, AVCT_BR_PSM, 0, 0);
+    /* AVCTP browsing channel uses the same security service as AVCTP control channel */
+    BTM_SetSecurityLevel(true, "", BTM_SEC_SERVICE_AVCTP, sec_mask, AVCT_BR_PSM, 0, 0);
+    BTM_SetSecurityLevel(false, "", BTM_SEC_SERVICE_AVCTP, sec_mask, AVCT_BR_PSM, 0, 0);
 
     if (mtu_br < AVCT_MIN_BROWSE_MTU)
         mtu_br = AVCT_MIN_BROWSE_MTU;
@@ -285,6 +286,7 @@ uint16_t AVCT_CreateBrowse (uint8_t handle, uint8_t role)
         {
             /* bind bcb to ccb */
             p_ccb->p_bcb = p_bcb;
+            memcpy(p_bcb->peer_addr, p_ccb->p_lcb->peer_addr, BD_ADDR_LEN);
             AVCT_TRACE_DEBUG("ch_state: %d", p_bcb->ch_state);
             avct_bcb_event(p_bcb, AVCT_LCB_UL_BIND_EVT, (tAVCT_LCB_EVT *) &p_ccb);
         }
diff --git a/stack/avct/avct_bcb_act.c b/stack/avct/avct_bcb_act.c
new file mode 100644 (file)
index 0000000..eadc1b0
--- /dev/null
@@ -0,0 +1,743 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2003-2016 Broadcom Corporation
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
+/*****************************************************************************
+*
+*  Name:           avct_bcb_act.c
+*
+*  Description:    This module contains action functions of the browsing control
+*                  state machine.
+*
+******************************************************************************/
+
+
+#include <string.h>
+#include "bt_target.h"
+#include "bt_utils.h"
+#include "avct_api.h"
+#include "avct_int.h"
+#include "btm_api.h"
+
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+/* action function list */
+const tAVCT_BCB_ACTION avct_bcb_action[] = {
+    avct_bcb_chnl_open,     /* AVCT_LCB_CHNL_OPEN */
+    avct_bcb_chnl_disc,     /* AVCT_LCB_CHNL_DISC */
+    avct_bcb_send_msg,      /* AVCT_LCB_SEND_MSG */
+    avct_bcb_open_ind,      /* AVCT_LCB_OPEN_IND */
+    avct_bcb_open_fail,     /* AVCT_LCB_OPEN_FAIL */
+    avct_bcb_close_ind,     /* AVCT_LCB_CLOSE_IND */
+    avct_bcb_close_cfm,     /* AVCT_LCB_CLOSE_CFM */
+    avct_bcb_msg_ind,       /* AVCT_LCB_MSG_IND */
+    avct_bcb_cong_ind,      /* AVCT_LCB_CONG_IND */
+    avct_bcb_bind_conn,     /* AVCT_LCB_BIND_CONN */
+    avct_bcb_bind_fail,     /* AVCT_LCB_BIND_FAIL */
+    avct_bcb_unbind_disc,   /* AVCT_LCB_UNBIND_DISC */
+    avct_bcb_chk_disc,      /* AVCT_LCB_CHK_DISC */
+    avct_bcb_discard_msg,   /* AVCT_LCB_DISCARD_MSG */
+    avct_bcb_dealloc,       /* AVCT_LCB_DEALLOC */
+    avct_bcb_free_msg_ind   /* AVCT_LCB_FREE_MSG_IND */
+};
+
+
+/*******************************************************************************
+**
+** Function         avct_bcb_msg_asmbl
+**
+** Description      Reassemble incoming message.
+**
+**
+** Returns          Pointer to reassembled message;  NULL if no message
+**                  available.
+**
+*******************************************************************************/
+static BT_HDR *avct_bcb_msg_asmbl(tAVCT_BCB *p_bcb, BT_HDR *p_buf)
+{
+    uint8_t   *p;
+    uint8_t   pkt_type;
+    UNUSED(p_bcb);
+
+    /* parse the message header */
+    p = (uint8_t *)(p_buf + 1) + p_buf->offset;
+    pkt_type = AVCT_PKT_TYPE(p);
+
+    /* must be single packet - can not fragment */
+    if (pkt_type != AVCT_PKT_TYPE_SINGLE)
+    {
+        osi_free_and_reset((void **)&p_buf);
+        AVCT_TRACE_WARNING("Pkt type=%d - fragmentation not allowed. drop it", pkt_type);
+    }
+    return p_buf;
+}
+
+
+/*******************************************************************************
+**
+** Function         avct_bcb_chnl_open
+**
+** Description      Open L2CAP channel to peer
+**
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avct_bcb_chnl_open(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data)
+{
+    uint16_t              result = AVCT_RESULT_FAIL;
+    tAVCT_LCB           *p_lcb = avct_lcb_by_bcb(p_bcb);
+    tL2CAP_ERTM_INFO    ertm_info;
+    UNUSED(p_data);
+
+    BTM_SetOutService(p_lcb->peer_addr, BTM_SEC_SERVICE_AVCTP_BROWSE, 0);
+
+    /* Set the FCR options: Browsing channel mandates ERTM */
+    ertm_info.preferred_mode  = avct_l2c_br_fcr_opts_def.mode;
+    ertm_info.allowed_modes = L2CAP_FCR_CHAN_OPT_ERTM;
+    ertm_info.user_rx_buf_size = AVCT_USER_RX_BUF_SIZE;
+    ertm_info.user_tx_buf_size = AVCT_USER_TX_BUF_SIZE;
+    ertm_info.fcr_rx_buf_size = AVCT_FCR_RX_BUF_SIZE;
+    ertm_info.fcr_tx_buf_size = AVCT_FCR_TX_BUF_SIZE;
+
+    /* call l2cap connect req */
+    p_bcb->ch_state = AVCT_CH_CONN;
+    p_bcb->ch_lcid = L2CA_ErtmConnectReq(AVCT_BR_PSM, p_lcb->peer_addr, &ertm_info);
+    if (p_bcb->ch_lcid == 0)
+    {
+        /* if connect req failed, send ourselves close event */
+        avct_bcb_event(p_bcb, AVCT_LCB_LL_CLOSE_EVT, (tAVCT_LCB_EVT *) &result);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         avct_bcb_unbind_disc
+**
+** Description      call callback with disconnect event.
+**
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avct_bcb_unbind_disc(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data)
+{
+    UNUSED(p_bcb);
+    p_data->p_ccb->p_bcb = NULL;
+    (*p_data->p_ccb->cc.p_ctrl_cback)(avct_ccb_to_idx(p_data->p_ccb),
+            AVCT_BROWSE_DISCONN_CFM_EVT, 0, NULL);
+}
+
+/*******************************************************************************
+**
+** Function         avct_bcb_open_ind
+**
+** Description      Handle an LL_OPEN event.
+**                  For the allocated ccb already bound to the bcb, send a connect event.
+**                  For the unbound ccb with a new PID, bind that ccb to the bcb with the
+**                  same bd_addr and send a connect event.
+**
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avct_bcb_open_ind(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data)
+{
+    tAVCT_CCB       *p_ccb = &avct_cb.ccb[0];
+    tAVCT_CCB       *p_ccb_bind = NULL;
+    bool         bind = false;
+    tAVCT_UL_MSG    ul_msg;
+
+    for (int idx = 0; idx < AVCT_NUM_CONN; idx++, p_ccb++)
+    {
+        /* if ccb allocated and */
+        if (p_ccb->allocated)
+        {
+            /* if bound to this bcb send connect confirm event */
+            if (p_ccb->p_bcb == p_bcb)
+            {
+                bind = true;
+                p_ccb_bind = p_ccb;
+                p_ccb->cc.p_ctrl_cback(avct_ccb_to_idx(p_ccb), AVCT_BROWSE_CONN_CFM_EVT,
+                                       0, p_ccb->p_lcb->peer_addr);
+            }
+            /* if unbound acceptor and lcb allocated and bd_addr are the same for bcb and lcb */
+            else if ((p_ccb->p_bcb == NULL) && (p_ccb->cc.role == AVCT_ACP) &&
+                     (p_ccb->p_lcb != NULL) &&
+                     (!memcmp(p_bcb->peer_addr, p_ccb->p_lcb->peer_addr, BD_ADDR_LEN)))
+            {
+                /* bind bcb to ccb and send connect ind event */
+                bind = true;
+                p_ccb_bind = p_ccb;
+                p_ccb->p_bcb = p_bcb;
+                p_ccb->cc.p_ctrl_cback(avct_ccb_to_idx(p_ccb), AVCT_BROWSE_CONN_IND_EVT,
+                                    0, p_ccb->p_lcb->peer_addr);
+            }
+        }
+    }
+
+    /* if no ccbs bound to this lcb, disconnect */
+    if (bind == false)
+    {
+        avct_bcb_event(p_bcb, AVCT_LCB_INT_CLOSE_EVT, p_data);
+        return;
+    }
+
+    if (!p_bcb->p_tx_msg || !p_ccb_bind)
+    {
+        return;
+    }
+
+    ul_msg.p_buf = p_bcb->p_tx_msg;
+    ul_msg.p_ccb = p_ccb_bind;
+    ul_msg.label = (uint8_t)(p_bcb->p_tx_msg->layer_specific & 0xFF);
+    ul_msg.cr = (uint8_t)((p_bcb->p_tx_msg->layer_specific & 0xFF00) >> 8);
+    p_bcb->p_tx_msg->layer_specific = AVCT_DATA_BROWSE;
+    p_bcb->p_tx_msg = NULL;
+
+    /* send msg event to bcb */
+    avct_bcb_event(p_bcb, AVCT_LCB_UL_MSG_EVT, (tAVCT_LCB_EVT *) &ul_msg);
+}
+
+/*******************************************************************************
+**
+** Function         avct_bcb_open_fail
+**
+** Description      L2CAP channel open attempt failed.  Mark the ccbs
+**                  as NULL bcb.
+**
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avct_bcb_open_fail(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data)
+{
+    tAVCT_CCB   *p_ccb = &avct_cb.ccb[0];
+    UNUSED(p_data);
+
+    for (int idx = 0; idx < AVCT_NUM_CONN; idx++, p_ccb++)
+    {
+        if (p_ccb->allocated && (p_ccb->p_bcb == p_bcb))
+        {
+            p_ccb->p_bcb = NULL;
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         avct_bcb_close_ind
+**
+** Description      L2CAP channel closed by peer.  Deallocate any initiator
+**                  ccbs on this lcb and send disconnect ind event.
+**
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avct_bcb_close_ind(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data)
+{
+    tAVCT_CCB   *p_ccb = &avct_cb.ccb[0];
+    tAVCT_LCB   *p_lcb = avct_lcb_by_bcb(p_bcb);
+    UNUSED(p_data);
+
+    for (int idx = 0; idx < AVCT_NUM_CONN; idx++, p_ccb++)
+    {
+        if (p_ccb->allocated && (p_ccb->p_bcb == p_bcb))
+        {
+            if (p_ccb->cc.role == AVCT_INT)
+            {
+                (*p_ccb->cc.p_ctrl_cback)(avct_ccb_to_idx(p_ccb), AVCT_BROWSE_DISCONN_CFM_EVT,
+                        0, p_lcb->peer_addr);
+            }
+            else
+            {
+                (*p_ccb->cc.p_ctrl_cback)(avct_ccb_to_idx(p_ccb), AVCT_BROWSE_DISCONN_IND_EVT,
+                        0, NULL);
+            }
+            p_ccb->p_bcb = NULL;
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         avct_bcb_close_cfm
+**
+** Description      L2CAP channel closed by us.  Deallocate any initiator
+**                  ccbs on this lcb and send disconnect ind or cfm event.
+**
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avct_bcb_close_cfm(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data)
+{
+    tAVCT_CCB           *p_ccb = &avct_cb.ccb[0];
+    uint8_t               event = 0;
+    bool             ch_close = p_bcb->ch_close;    /* Whether BCB initiated channel close */
+    tAVCT_CTRL_CBACK    *p_cback;
+
+    p_bcb->ch_close = false;
+    p_bcb->allocated = 0;
+    for (int idx = 0; idx < AVCT_NUM_CONN; idx++, p_ccb++)
+    {
+        if (p_ccb->allocated && (p_ccb->p_bcb == p_bcb))
+        {
+            /* if this ccb initiated close send disconnect cfm otherwise ind */
+            if (ch_close)
+            {
+                event = AVCT_BROWSE_DISCONN_CFM_EVT;
+            }
+            else
+            {
+                event = AVCT_BROWSE_DISCONN_IND_EVT;
+            }
+
+            p_cback = p_ccb->cc.p_ctrl_cback;
+            p_ccb->p_bcb = NULL;
+            if (p_ccb->p_lcb == NULL)
+                avct_ccb_dealloc(p_ccb, AVCT_NO_EVT, 0, NULL);
+            (*p_cback)(avct_ccb_to_idx(p_ccb), event,
+                                       p_data->result, p_bcb->peer_addr);
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         avct_bcb_bind_conn
+**
+** Description      Bind ccb to lcb and send connect cfm event.
+**
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avct_bcb_bind_conn(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data)
+{
+    tAVCT_LCB *p_lcb = avct_lcb_by_bcb(p_bcb);
+    p_data->p_ccb->p_bcb = p_bcb;
+    (*p_data->p_ccb->cc.p_ctrl_cback)(avct_ccb_to_idx(p_data->p_ccb),
+                                      AVCT_BROWSE_CONN_CFM_EVT, 0, p_lcb->peer_addr);
+}
+
+/*******************************************************************************
+**
+** Function         avct_bcb_chk_disc
+**
+** Description      A ccb wants to close; if it is the last ccb on this lcb,
+**                  close channel.  Otherwise just deallocate and call
+**                  callback.
+**
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avct_bcb_chk_disc(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data)
+{
+    p_bcb->ch_close = avct_bcb_get_last_ccb_index(p_bcb, p_data->p_ccb);
+    if (p_bcb->ch_close)
+    {
+        avct_bcb_event(p_bcb, AVCT_LCB_INT_CLOSE_EVT, p_data);
+        return;
+    }
+
+    avct_bcb_unbind_disc(p_bcb, p_data);
+}
+
+/*******************************************************************************
+**
+** Function         avct_bcb_chnl_disc
+**
+** Description      Disconnect L2CAP channel.
+**
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avct_bcb_chnl_disc(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data)
+{
+    UNUSED(p_data);
+    L2CA_DisconnectReq(p_bcb->ch_lcid);
+}
+
+/*******************************************************************************
+**
+** Function         avct_bcb_bind_fail
+**
+** Description      Deallocate ccb and call callback with connect event
+**                  with failure result.
+**
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avct_bcb_bind_fail(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data)
+{
+    UNUSED(p_bcb);
+    p_data->p_ccb->p_bcb = NULL;
+    (*p_data->p_ccb->cc.p_ctrl_cback)(avct_ccb_to_idx(p_data->p_ccb),
+            AVCT_BROWSE_CONN_CFM_EVT, AVCT_RESULT_FAIL, NULL);
+}
+
+/*******************************************************************************
+**
+** Function         avct_bcb_cong_ind
+**
+** Description      Handle congestion indication from L2CAP.
+**
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avct_bcb_cong_ind(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data)
+{
+    tAVCT_CCB   *p_ccb = &avct_cb.ccb[0];
+    uint8_t       event;
+    tAVCT_LCB   *p_lcb = avct_lcb_by_bcb(p_bcb);
+
+    /* set event */
+    event = (p_data->cong) ? AVCT_BROWSE_CONG_IND_EVT : AVCT_BROWSE_UNCONG_IND_EVT;
+
+    /* send event to all ccbs on this lcb */
+    for (int idx = 0; idx < AVCT_NUM_CONN; idx++, p_ccb++)
+    {
+        if (p_ccb->allocated && (p_ccb->p_bcb == p_bcb))
+        {
+            (*p_ccb->cc.p_ctrl_cback)(avct_ccb_to_idx(p_ccb), event, 0, p_lcb->peer_addr);
+        }
+    }
+
+}
+
+/*******************************************************************************
+**
+** Function         avct_bcb_discard_msg
+**
+** Description      Discard a message sent in from the API.
+**
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avct_bcb_discard_msg(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data)
+{
+
+    osi_free_and_reset((void **)&p_bcb->p_tx_msg);
+
+    /* if control channel is up, save the message and open the browsing channel */
+    if (p_data->ul_msg.p_ccb->p_lcb == NULL)
+    {
+        osi_free_and_reset((void **)&p_data->ul_msg.p_buf);
+        return;
+    }
+    p_bcb->p_tx_msg = p_data->ul_msg.p_buf;
+
+    if (p_bcb->p_tx_msg)
+    {
+        p_bcb->p_tx_msg->layer_specific = (p_data->ul_msg.cr << 8) + p_data->ul_msg.label;
+
+        /* the channel is closed, opening or closing - open it again */
+        AVCT_TRACE_DEBUG("ch_state: %d, allocated:%d->%d", p_bcb->ch_state, p_bcb->allocated,
+            p_data->ul_msg.p_ccb->p_lcb->allocated);
+        p_bcb->allocated = p_data->ul_msg.p_ccb->p_lcb->allocated;
+        avct_bcb_event(p_bcb, AVCT_LCB_UL_BIND_EVT, (tAVCT_LCB_EVT *) p_data->ul_msg.p_ccb);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         avct_bcb_send_msg
+**
+** Description      Build and send an AVCTP message.
+**
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avct_bcb_send_msg(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data)
+{
+    uint16_t  curr_msg_len;
+    uint8_t   pkt_type = AVCT_PKT_TYPE_SINGLE;
+    uint8_t   hdr_len;
+    BT_HDR  *p_buf;
+    uint8_t   *p;
+
+    /* store msg len */
+    curr_msg_len = p_data->ul_msg.p_buf->len;
+
+    /* initialize packet type and other stuff */
+    if (curr_msg_len > (p_bcb->peer_mtu - AVCT_HDR_LEN_SINGLE))
+    {
+        AVCT_TRACE_ERROR ("%s msg len (%d) exceeds peer mtu(%d-%d)!!", __func__,
+                    curr_msg_len, p_bcb->peer_mtu, AVCT_HDR_LEN_SINGLE);
+        osi_free_and_reset((void **)&p_data->ul_msg.p_buf);
+        return;
+    }
+
+    /* set header len */
+    hdr_len = avct_lcb_pkt_type_len[pkt_type];
+    p_buf = p_data->ul_msg.p_buf;
+
+    /* set up to build header */
+    p_buf->len += hdr_len;
+    p_buf->offset -= hdr_len;
+    p = (uint8_t *)(p_buf + 1) + p_buf->offset;
+
+    /* build header */
+    AVCT_BUILD_HDR(p, p_data->ul_msg.label, pkt_type, p_data->ul_msg.cr);
+    UINT16_TO_BE_STREAM(p, p_data->ul_msg.p_ccb->cc.pid);
+
+    p_buf->layer_specific = AVCT_DATA_BROWSE;
+
+    /* send message to L2CAP */
+    L2CA_DataWrite(p_bcb->ch_lcid, p_buf);
+}
+
+/*******************************************************************************
+**
+** Function         avct_bcb_free_msg_ind
+**
+** Description      Discard an incoming AVCTP message.
+**
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avct_bcb_free_msg_ind(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data)
+{
+    UNUSED(p_bcb);
+    if (p_data)
+        osi_free_and_reset((void **)&p_data->p_buf);
+}
+
+/*******************************************************************************
+**
+** Function         avct_bcb_msg_ind
+**
+** Description      Handle an incoming AVCTP message.
+**
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avct_bcb_msg_ind(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data)
+{
+    uint8_t       *p;
+    uint8_t       label, type, cr_ipid;
+    uint16_t      pid;
+    tAVCT_CCB   *p_ccb;
+    tAVCT_LCB   *p_lcb = avct_lcb_by_bcb(p_bcb);
+
+    if ((p_data == NULL) || (p_data->p_buf == NULL))
+    {
+        AVCT_TRACE_WARNING("%s p_data is NULL, returning!", __func__);
+        return;
+    }
+
+    /* this p_buf is to be reported through p_msg_cback. The layer_specific
+     * needs to be set properly to indicate that it is received through
+     * browsing channel */
+    p_data->p_buf->layer_specific = AVCT_DATA_BROWSE;
+
+    /* reassemble message; if no message available (we received a fragment) return */
+    p_data->p_buf = avct_bcb_msg_asmbl(p_bcb, p_data->p_buf);
+    if (p_data->p_buf == NULL)
+    {
+        return;
+    }
+
+    p = (uint8_t *)(p_data->p_buf + 1) + p_data->p_buf->offset;
+
+    /* parse header byte */
+    AVCT_PARSE_HDR(p, label, type, cr_ipid);
+    UNUSED(type);
+
+    /* check for invalid cr_ipid */
+    if (cr_ipid == AVCT_CR_IPID_INVALID)
+    {
+        AVCT_TRACE_WARNING("Invalid cr_ipid", cr_ipid);
+        osi_free_and_reset((void **)&p_data->p_buf);
+        return;
+    }
+
+    /* parse and lookup PID */
+    BE_STREAM_TO_UINT16(pid, p);
+    p_ccb = avct_lcb_has_pid(p_lcb, pid);
+    if (p_ccb)
+    {
+        /* PID found; send msg up, adjust bt hdr and call msg callback */
+        p_data->p_buf->offset += AVCT_HDR_LEN_SINGLE;
+        p_data->p_buf->len -= AVCT_HDR_LEN_SINGLE;
+        (*p_ccb->cc.p_msg_cback)(avct_ccb_to_idx(p_ccb), label, cr_ipid, p_data->p_buf);
+        return;
+    }
+
+    /* PID not found; drop message */
+    AVCT_TRACE_WARNING("No ccb for PID=%x", pid);
+    osi_free_and_reset((void **)&p_data->p_buf);
+
+    /* if command send reject */
+    if (cr_ipid == AVCT_CMD)
+    {
+        BT_HDR *p_buf = (BT_HDR *) osi_malloc(AVRC_CMD_BUF_SIZE);
+        p_buf->len = AVCT_HDR_LEN_SINGLE;
+        p_buf->offset = AVCT_MSG_OFFSET - AVCT_HDR_LEN_SINGLE;
+        p = (uint8_t *)(p_buf + 1) + p_buf->offset;
+        AVCT_BUILD_HDR(p, label, AVCT_PKT_TYPE_SINGLE, AVCT_REJ);
+        UINT16_TO_BE_STREAM(p, pid);
+        p_buf->layer_specific = AVCT_DATA_BROWSE;
+        L2CA_DataWrite(p_bcb->ch_lcid, p_buf);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         avct_bcb_dealloc
+**
+** Description      Deallocate a browse control block.
+**
+**
+** Returns          void.
+**
+*******************************************************************************/
+void avct_bcb_dealloc(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data)
+{
+    tAVCT_CCB   *p_ccb = &avct_cb.ccb[0];
+    UNUSED(p_data);
+
+    AVCT_TRACE_DEBUG("%s %d", __func__, p_bcb->allocated);
+
+    for (int idx = 0; idx < AVCT_NUM_CONN; idx++, p_ccb++)
+    {
+        /* if ccb allocated and */
+        if ((p_ccb->allocated) && (p_ccb->p_bcb == p_bcb))
+        {
+            p_ccb->p_bcb = NULL;
+            AVCT_TRACE_DEBUG("%s used by ccb: %d", __func__, idx);
+            break;
+        }
+    }
+
+    /* the browsing channel is down. Check if we have pending messages */
+    osi_free_and_reset((void **)&p_bcb->p_tx_msg);
+    memset(p_bcb, 0, sizeof(tAVCT_BCB));
+}
+
+/*******************************************************************************
+**
+** Function         avct_close_bcb
+**
+** Description      this function is called right before LCB disconnects.
+**
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avct_close_bcb(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
+{
+    tAVCT_BCB   *p_bcb = avct_bcb_by_lcb(p_lcb);
+    if (p_bcb->allocated)
+    {
+        avct_bcb_event(p_bcb, AVCT_LCB_UL_UNBIND_EVT, p_data);
+    }
+}
+
+
+/*******************************************************************************
+**
+** Function         avct_lcb_by_bcb
+**
+** Description      This lookup function finds the lcb for a bcb.
+**
+** Returns          pointer to the lcb.
+**
+*******************************************************************************/
+tAVCT_LCB *avct_lcb_by_bcb(tAVCT_BCB *p_bcb)
+{
+    return &avct_cb.lcb[p_bcb->allocated - 1];
+}
+
+/*******************************************************************************
+**
+** Function         avct_bcb_by_lcb
+**
+** Description      This lookup function finds the bcb for a lcb.
+**
+** Returns          pointer to the lcb.
+**
+*******************************************************************************/
+tAVCT_BCB *avct_bcb_by_lcb(tAVCT_LCB *p_lcb)
+{
+    return &avct_cb.bcb[p_lcb->allocated - 1];
+}
+
+/*******************************************************************************
+**
+** Function         avct_bcb_get_last_ccb_index
+**
+** Description      See if given ccb is only one on the bcb.
+**
+**
+** Returns          0, if ccb is last,  (ccb index + 1) otherwise.
+**
+*******************************************************************************/
+uint8_t avct_bcb_get_last_ccb_index(tAVCT_BCB *p_bcb, tAVCT_CCB *p_ccb_last)
+{
+    tAVCT_CCB   *p_ccb = &avct_cb.ccb[0];
+    uint8_t       idx = 0;
+
+    for (int i = 0; i < AVCT_NUM_CONN; i++, p_ccb++)
+    {
+        if (p_ccb->allocated && (p_ccb->p_bcb == p_bcb))
+        {
+            if (p_ccb != p_ccb_last)
+                return 0;
+            idx = (uint8_t)(i + 1);
+        }
+    }
+    return idx;
+}
+
+/*******************************************************************************
+**
+** Function         avct_bcb_by_lcid
+**
+** Description      Find the BCB associated with the L2CAP LCID
+**
+**
+** Returns          pointer to the lcb, or NULL if none found.
+**
+*******************************************************************************/
+tAVCT_BCB *avct_bcb_by_lcid(uint16_t lcid)
+{
+    tAVCT_BCB   *p_bcb = &avct_cb.bcb[0];
+    int         idx;
+
+    for (idx = 0; idx < AVCT_NUM_LINKS; idx++, p_bcb++)
+    {
+        if (p_bcb->allocated && (p_bcb->ch_lcid == lcid))
+        {
+            return p_bcb;
+        }
+    }
+
+    /* out of lcbs */
+    AVCT_TRACE_WARNING("No bcb for lcid %x", lcid);
+    return NULL;
+}
+#endif /* (AVCT_BROWSE_INCLUDED == true) */
index 939f37e..726067e 100644 (file)
 ** message parsing and building macros
 *****************************************************************************/
 
-#define AVCT_BLD_HDR(p, label, type, cr_ipid) \
+#define AVCT_BUILD_HDR(p, label, type, cr_ipid) \
     *(p)++ = ((label) << 4) | ((type) << 2) | (cr_ipid);
 
-#define AVCT_PRS_HDR(p, label, type, cr_ipid) \
+#define AVCT_PARSE_HDR(p, label, type, cr_ipid) \
     label = *(p) >> 4; \
     (type) = (*(p) >> 2) & 3; \
     (cr_ipid) = *(p)++ & 3;
 
-#define AVCT_PRS_PKT_TYPE(p, type) \
-    type = (*(p) >> 2) & 3;
+#define AVCT_PKT_TYPE(p) \
+    ((*(p) >> 2) & 3);
 
 #endif /* AVCT_DEFS_H */
index 2d19c44..831e9f4 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2003-2012 Broadcom Corporation
+ *  Copyright (C) 2003-2016 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -101,6 +101,7 @@ typedef struct {
     uint8_t             ch_flags;       /* L2CAP configuration flags */
     BT_HDR              *p_tx_msg;      /* Message to be sent - in case the browsing channel is not open when MsgReg is called */
     uint8_t             ch_close;       /* CCB index+1, if CCB initiated channel close */
+    BD_ADDR             peer_addr;      /* BD address of peer */
 } tAVCT_BCB;
 
 #define AVCT_ALOC_LCB       0x01
@@ -153,7 +154,7 @@ extern void avct_bcb_event(tAVCT_BCB *p_bcb, uint8_t event, tAVCT_LCB_EVT *p_dat
 extern void avct_close_bcb(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data);
 extern tAVCT_LCB *avct_lcb_by_bcb(tAVCT_BCB *p_bcb);
 extern tAVCT_BCB *avct_bcb_by_lcb(tAVCT_LCB *p_lcb);
-extern bool    avct_bcb_last_ccb(tAVCT_BCB *p_bcb, tAVCT_CCB *p_ccb_last);
+extern uint8_t avct_bcb_get_last_ccb_index(tAVCT_BCB *p_bcb, tAVCT_CCB *p_ccb_last);
 extern tAVCT_BCB *avct_bcb_by_lcid(uint16_t lcid);
 #endif
 extern tAVCT_LCB *avct_lcb_by_bd(BD_ADDR bd_addr);
diff --git a/stack/avct/avct_l2c_br.c b/stack/avct/avct_l2c_br.c
new file mode 100644 (file)
index 0000000..4eaaf15
--- /dev/null
@@ -0,0 +1,411 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2008-2016 Broadcom Corporation
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
+/*****************************************************************************
+**
+**  Name:           avct_l2c_br.c
+**
+**  Description:    This AVCTP module interfaces to L2CAP
+**
+******************************************************************************/
+
+#include <string.h>
+#include "bt_target.h"
+#include "bt_utils.h"
+#include "avct_api.h"
+#include "avct_int.h"
+#include "l2c_api.h"
+#include "l2cdefs.h"
+
+/* Configuration flags. */
+#define AVCT_L2C_CFG_IND_DONE   (1<<0)
+#define AVCT_L2C_CFG_CFM_DONE   (1<<1)
+
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+/* callback function declarations */
+void avct_l2c_br_connect_ind_cback(BD_ADDR bd_addr, uint16_t lcid, uint16_t psm, uint8_t id);
+void avct_l2c_br_connect_cfm_cback(uint16_t lcid, uint16_t result);
+void avct_l2c_br_config_cfm_cback(uint16_t lcid, tL2CAP_CFG_INFO *p_cfg);
+void avct_l2c_br_config_ind_cback(uint16_t lcid, tL2CAP_CFG_INFO *p_cfg);
+void avct_l2c_br_disconnect_ind_cback(uint16_t lcid, bool ack_needed);
+void avct_l2c_br_disconnect_cfm_cback(uint16_t lcid, uint16_t result);
+void avct_l2c_br_congestion_ind_cback(uint16_t lcid, bool is_congested);
+void avct_l2c_br_data_ind_cback(uint16_t lcid, BT_HDR *p_buf);
+
+/* L2CAP callback function structure */
+const tL2CAP_APPL_INFO avct_l2c_br_appl = {
+    avct_l2c_br_connect_ind_cback,
+    avct_l2c_br_connect_cfm_cback,
+    NULL,
+    avct_l2c_br_config_ind_cback,
+    avct_l2c_br_config_cfm_cback,
+    avct_l2c_br_disconnect_ind_cback,
+    avct_l2c_br_disconnect_cfm_cback,
+    NULL,
+    avct_l2c_br_data_ind_cback,
+    avct_l2c_br_congestion_ind_cback,
+    NULL                                /* tL2CA_TX_COMPLETE_CB */
+};
+
+/* Browsing channel eL2CAP default options */
+const tL2CAP_FCR_OPTS avct_l2c_br_fcr_opts_def = {
+    L2CAP_FCR_ERTM_MODE,                /* Mandatory for Browsing channel */
+    AVCT_BR_FCR_OPT_TX_WINDOW_SIZE,     /* Tx window size */
+    AVCT_BR_FCR_OPT_MAX_TX_B4_DISCNT,   /* Maximum transmissions before disconnecting */
+    AVCT_BR_FCR_OPT_RETX_TOUT,          /* Retransmission timeout (2 secs) */
+    AVCT_BR_FCR_OPT_MONITOR_TOUT,       /* Monitor timeout (12 secs) */
+    L2CAP_DEFAULT_ERM_MPS               /* MPS segment size */
+};
+
+/*******************************************************************************
+**
+** Function         avct_l2c_br_connect_ind_cback
+**
+** Description      This is the L2CAP connect indication callback function.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void avct_l2c_br_connect_ind_cback(BD_ADDR bd_addr, uint16_t lcid, uint16_t psm, uint8_t id)
+{
+    tAVCT_LCB           *p_lcb;
+    uint16_t              result = L2CAP_CONN_NO_RESOURCES;
+    tL2CAP_CFG_INFO     cfg;
+    tAVCT_BCB           *p_bcb;
+    tL2CAP_ERTM_INFO    ertm_info;
+    UNUSED(psm);
+
+    memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
+    cfg.mtu_present = true;
+
+    if ((p_lcb = avct_lcb_by_bd(bd_addr)) != NULL)
+    {
+        /* control channel exists */
+        p_bcb = avct_bcb_by_lcb(p_lcb);
+        memcpy(p_bcb->peer_addr, bd_addr, BD_ADDR_LEN);
+
+        if (p_bcb->allocated == 0)
+        {
+            /* browsing channel does not exist yet and the browsing channel is registered
+             * - accept connection */
+            p_bcb->allocated = p_lcb->allocated; /* copy the index from lcb */
+
+            result = L2CAP_CONN_OK;
+            cfg.mtu = avct_cb.mtu_br;
+
+            cfg.fcr_present = true;
+            cfg.fcr         = avct_l2c_br_fcr_opts_def;
+        }
+    }
+    /* else no control channel yet, reject */
+
+    /* Set the FCR options: Browsing channel mandates ERTM */
+    ertm_info.preferred_mode = cfg.fcr.mode;
+    ertm_info.allowed_modes = L2CAP_FCR_CHAN_OPT_ERTM;
+    ertm_info.user_rx_buf_size = AVCT_USER_RX_BUF_SIZE;
+    ertm_info.user_tx_buf_size = AVCT_USER_TX_BUF_SIZE;
+    ertm_info.fcr_rx_buf_size = AVCT_FCR_RX_BUF_SIZE;
+    ertm_info.fcr_tx_buf_size = AVCT_FCR_TX_BUF_SIZE;
+
+    /* Send L2CAP connect rsp */
+    L2CA_ErtmConnectRsp(bd_addr, id, lcid, result, 0, &ertm_info);
+
+    /* if result ok, proceed with connection */
+    if (result == L2CAP_CONN_OK)
+    {
+        /* store LCID */
+        p_bcb->ch_lcid = lcid;
+
+        /* transition to configuration state */
+        p_bcb->ch_state = AVCT_CH_CFG;
+
+        /* Send L2CAP config req */
+        L2CA_ConfigReq(lcid, &cfg);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         avct_l2c_br_connect_cfm_cback
+**
+** Description      This is the L2CAP connect confirm callback function.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void avct_l2c_br_connect_cfm_cback(uint16_t lcid, uint16_t result)
+{
+    tAVCT_BCB       *p_lcb;
+    tL2CAP_CFG_INFO cfg;
+
+    /* look up lcb for this channel */
+    p_lcb = avct_bcb_by_lcid(lcid);
+    if ((p_lcb == NULL) || (p_lcb->ch_state != AVCT_CH_CONN))
+        return;
+
+    if (result != L2CAP_CONN_OK)
+    {
+        /* failure */
+        avct_bcb_event(p_lcb, AVCT_LCB_LL_CLOSE_EVT, (tAVCT_LCB_EVT *) &result);
+        return;
+    }
+
+    /* result is successful */
+    /* set channel state */
+    p_lcb->ch_state = AVCT_CH_CFG;
+
+    /* Send L2CAP config req */
+    memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
+
+    cfg.mtu_present = true;
+    cfg.mtu = avct_cb.mtu_br;
+
+    cfg.fcr_present  = true;
+    cfg.fcr          = avct_l2c_br_fcr_opts_def;
+
+    L2CA_ConfigReq(lcid, &cfg);
+}
+
+/*******************************************************************************
+**
+** Function         avct_l2c_br_config_cfm_cback
+**
+** Description      This is the L2CAP config confirm callback function.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void avct_l2c_br_config_cfm_cback(uint16_t lcid, tL2CAP_CFG_INFO *p_cfg)
+{
+    tAVCT_BCB   *p_lcb;
+
+    /* look up lcb for this channel */
+    p_lcb = avct_bcb_by_lcid(lcid);
+    if ((p_lcb == NULL) || (p_lcb->ch_state != AVCT_CH_CFG))
+        return;
+
+    /* if result successful */
+    if (p_cfg->result == L2CAP_CFG_OK)
+    {
+        /* update flags */
+        p_lcb->ch_flags |= AVCT_L2C_CFG_CFM_DONE;
+
+        /* if configuration complete */
+        if (p_lcb->ch_flags & AVCT_L2C_CFG_IND_DONE)
+        {
+            p_lcb->ch_state = AVCT_CH_OPEN;
+            avct_bcb_event(p_lcb, AVCT_LCB_LL_OPEN_EVT, NULL);
+        }
+    }
+    /* else failure */
+    else
+    {
+        /* store result value */
+        p_lcb->ch_result = p_cfg->result;
+
+        /* Send L2CAP disconnect req */
+        L2CA_DisconnectReq(lcid);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         avct_l2c_br_config_ind_cback
+**
+** Description      This is the L2CAP config indication callback function.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void avct_l2c_br_config_ind_cback(uint16_t lcid, tL2CAP_CFG_INFO *p_cfg)
+{
+    tAVCT_BCB   *p_lcb;
+    uint16_t      max_mtu = BT_DEFAULT_BUFFER_SIZE - L2CAP_MIN_OFFSET - BT_HDR_SIZE;
+
+    /* Don't include QoS nor flush timeout in the response since we
+       currently always accept these values.  Note: fcr_present is left
+       untouched since l2cap negotiates this internally
+    */
+    p_cfg->flush_to_present = false;
+    p_cfg->qos_present = false;
+
+    /* look up lcb for this channel */
+    p_lcb = avct_bcb_by_lcid(lcid);
+    if (p_lcb == NULL)
+        return;
+
+    /* store the mtu in tbl */
+    p_lcb->peer_mtu = L2CAP_DEFAULT_MTU;
+    if (p_cfg->mtu_present)
+    {
+        p_lcb->peer_mtu = p_cfg->mtu;
+    }
+
+    if (p_lcb->peer_mtu > max_mtu)
+    {
+        p_lcb->peer_mtu = p_cfg->mtu = max_mtu;
+
+        /* Must tell the peer what the adjusted value is */
+        p_cfg->mtu_present = true;
+    }
+    else    /* Don't include in the response */
+        p_cfg->mtu_present = false;
+
+    AVCT_TRACE_DEBUG ("%s peer_mtu:%d use:%d", __func__,
+            p_lcb->peer_mtu, max_mtu);
+
+    if (p_lcb->peer_mtu >= AVCT_MIN_BROWSE_MTU)
+        p_cfg->result = L2CAP_CFG_OK;
+    else
+    {
+        p_cfg->result       = L2CAP_CFG_UNACCEPTABLE_PARAMS;
+        p_cfg->mtu_present  = true;
+        p_cfg->mtu          = AVCT_MIN_BROWSE_MTU;
+    }
+
+    /* send L2CAP configure response */
+    L2CA_ConfigRsp(lcid, p_cfg);
+
+    if (p_cfg->result != L2CAP_CFG_OK)
+    {
+        return;
+    }
+
+    /* if first config ind */
+    if ((p_lcb->ch_flags & AVCT_L2C_CFG_IND_DONE) == 0)
+    {
+        /* update flags */
+        p_lcb->ch_flags |= AVCT_L2C_CFG_IND_DONE;
+
+        /* if configuration complete */
+        if (p_lcb->ch_flags & AVCT_L2C_CFG_CFM_DONE)
+        {
+            p_lcb->ch_state = AVCT_CH_OPEN;
+            avct_bcb_event(p_lcb, AVCT_LCB_LL_OPEN_EVT, NULL);
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         avct_l2c_br_disconnect_ind_cback
+**
+** Description      This is the L2CAP disconnect indication callback function.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void avct_l2c_br_disconnect_ind_cback(uint16_t lcid, bool ack_needed)
+{
+    tAVCT_BCB   *p_lcb;
+    uint16_t      result = AVCT_RESULT_FAIL;
+
+    /* look up lcb for this channel */
+    p_lcb = avct_bcb_by_lcid(lcid);
+    if (p_lcb == NULL)
+        return;
+
+    if (ack_needed)
+    {
+        /* send L2CAP disconnect response */
+        L2CA_DisconnectRsp(lcid);
+    }
+
+    avct_bcb_event(p_lcb, AVCT_LCB_LL_CLOSE_EVT, (tAVCT_LCB_EVT *) &result);
+}
+
+/*******************************************************************************
+**
+** Function         avct_l2c_br_disconnect_cfm_cback
+**
+** Description      This is the L2CAP disconnect confirm callback function.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void avct_l2c_br_disconnect_cfm_cback(uint16_t lcid, uint16_t result)
+{
+    tAVCT_BCB   *p_lcb;
+    uint16_t      res;
+
+    /* look up lcb for this channel */
+    p_lcb = avct_bcb_by_lcid(lcid);
+    if (p_lcb == NULL)
+        return;
+
+    /* result value may be previously stored */
+    res = (p_lcb->ch_result != 0) ? p_lcb->ch_result : result;
+    p_lcb->ch_result = 0;
+
+    avct_bcb_event(p_lcb, AVCT_LCB_LL_CLOSE_EVT, (tAVCT_LCB_EVT *) &res);
+}
+
+/*******************************************************************************
+**
+** Function         avct_l2c_br_congestion_ind_cback
+**
+** Description      This is the L2CAP congestion indication callback function.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void avct_l2c_br_congestion_ind_cback(uint16_t lcid, bool is_congested)
+{
+    tAVCT_BCB   *p_lcb;
+
+    /* look up lcb for this channel */
+    p_lcb = avct_bcb_by_lcid(lcid);
+    if (p_lcb == NULL)
+        return;
+
+    avct_bcb_event(p_lcb, AVCT_LCB_LL_CONG_EVT, (tAVCT_LCB_EVT *) &is_congested);
+}
+
+/*******************************************************************************
+**
+** Function         avct_l2c_br_data_ind_cback
+**
+** Description      This is the L2CAP data indication callback function.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void avct_l2c_br_data_ind_cback(uint16_t lcid, BT_HDR *p_buf)
+{
+    tAVCT_BCB   *p_lcb;
+
+    /* look up lcb for this channel */
+    p_lcb = avct_bcb_by_lcid(lcid);
+    if (p_lcb == NULL)
+    {
+        /* prevent buffer leak */
+        osi_free_and_reset((void **)&p_buf);
+        return;
+    }
+
+    avct_bcb_event(p_lcb, AVCT_LCB_LL_MSG_EVT, (tAVCT_LCB_EVT *) &p_buf);
+}
+#endif /* (AVCT_BROWSE_INCLUDED == true) */
index 48d36e6..3d33d75 100644 (file)
@@ -58,7 +58,7 @@ static BT_HDR *avct_lcb_msg_asmbl(tAVCT_LCB *p_lcb, BT_HDR *p_buf)
 
     /* parse the message header */
     p = (uint8_t *)(p_buf + 1) + p_buf->offset;
-    AVCT_PRS_PKT_TYPE(p, pkt_type);
+    pkt_type = AVCT_PKT_TYPE(p);
 
     /* quick sanity check on length */
     if (p_buf->len < avct_lcb_pkt_type_len[pkt_type])
@@ -187,7 +187,8 @@ void avct_lcb_chnl_open(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
     BTM_SetOutService(p_lcb->peer_addr, BTM_SEC_SERVICE_AVCTP, 0);
     /* call l2cap connect req */
     p_lcb->ch_state = AVCT_CH_CONN;
-    if ((p_lcb->ch_lcid = L2CA_ConnectReq(AVCT_PSM, p_lcb->peer_addr)) == 0)
+    p_lcb->ch_lcid = L2CA_ConnectReq(AVCT_PSM, p_lcb->peer_addr);
+    if (p_lcb->ch_lcid == 0)
     {
         /* if connect req failed, send ourselves close event */
         avct_lcb_event(p_lcb, AVCT_LCB_LL_CLOSE_EVT, (tAVCT_LCB_EVT *) &result);
@@ -511,7 +512,7 @@ void avct_lcb_discard_msg(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
 {
     UNUSED(p_lcb);
 
-    AVCT_TRACE_WARNING("Dropping message");
+    AVCT_TRACE_WARNING("%s Dropping message", __func__);
     osi_free_and_reset((void **)&p_data->ul_msg.p_buf);
 }
 
@@ -589,7 +590,7 @@ void avct_lcb_send_msg(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
         p = (uint8_t *)(p_buf + 1) + p_buf->offset;
 
         /* build header */
-        AVCT_BLD_HDR(p, p_data->ul_msg.label, pkt_type, p_data->ul_msg.cr);
+        AVCT_BUILD_HDR(p, p_data->ul_msg.label, pkt_type, p_data->ul_msg.cr);
         if (pkt_type == AVCT_PKT_TYPE_START)
         {
             UINT8_TO_STREAM(p, nosp);
@@ -623,7 +624,7 @@ void avct_lcb_send_msg(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
             pkt_type = AVCT_PKT_TYPE_END;
         }
     }
-    AVCT_TRACE_DEBUG ("avct_lcb_send_msg tx_q_count:%d",
+    AVCT_TRACE_DEBUG ("%s tx_q_count:%d", __func__,
                       fixed_queue_length(p_lcb->tx_q));
     return;
 }
@@ -679,7 +680,7 @@ void avct_lcb_msg_ind(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
     p = (uint8_t *)(p_data->p_buf + 1) + p_data->p_buf->offset;
 
     /* parse header byte */
-    AVCT_PRS_HDR(p, label, type, cr_ipid);
+    AVCT_PARSE_HDR(p, label, type, cr_ipid);
     UNUSED(type);
 
     /* check for invalid cr_ipid */
@@ -692,29 +693,29 @@ void avct_lcb_msg_ind(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
 
     /* parse and lookup PID */
     BE_STREAM_TO_UINT16(pid, p);
-    if ((p_ccb = avct_lcb_has_pid(p_lcb, pid)) != NULL)
+    p_ccb = avct_lcb_has_pid(p_lcb, pid);
+    if (p_ccb)
     {
         /* PID found; send msg up, adjust bt hdr and call msg callback */
         p_data->p_buf->offset += AVCT_HDR_LEN_SINGLE;
         p_data->p_buf->len -= AVCT_HDR_LEN_SINGLE;
         (*p_ccb->cc.p_msg_cback)(avct_ccb_to_idx(p_ccb), label, cr_ipid, p_data->p_buf);
+        return;
     }
-    else
-    {
-        /* PID not found; drop message */
-        AVCT_TRACE_WARNING("No ccb for PID=%x", pid);
-        osi_free_and_reset((void **)&p_data->p_buf);
 
-        /* if command send reject */
-        if (cr_ipid == AVCT_CMD)
-        {
-            BT_HDR *p_buf = (BT_HDR *)osi_malloc(AVCT_CMD_BUF_SIZE);
-            p_buf->len = AVCT_HDR_LEN_SINGLE;
-            p_buf->offset = AVCT_MSG_OFFSET - AVCT_HDR_LEN_SINGLE;
-            p = (uint8_t *)(p_buf + 1) + p_buf->offset;
-            AVCT_BLD_HDR(p, label, AVCT_PKT_TYPE_SINGLE, AVCT_REJ);
-            UINT16_TO_BE_STREAM(p, pid);
-            L2CA_DataWrite(p_lcb->ch_lcid, p_buf);
-        }
+    /* PID not found; drop message */
+    AVCT_TRACE_WARNING("No ccb for PID=%x", pid);
+    osi_free_and_reset((void **)&p_data->p_buf);
+
+    /* if command send reject */
+    if (cr_ipid == AVCT_CMD)
+    {
+        BT_HDR *p_buf = (BT_HDR *)osi_malloc(AVCT_CMD_BUF_SIZE);
+        p_buf->len = AVCT_HDR_LEN_SINGLE;
+        p_buf->offset = AVCT_MSG_OFFSET - AVCT_HDR_LEN_SINGLE;
+        p = (uint8_t *)(p_buf + 1) + p_buf->offset;
+        AVCT_BUILD_HDR(p, label, AVCT_PKT_TYPE_SINGLE, AVCT_REJ);
+        UINT16_TO_BE_STREAM(p, pid);
+        L2CA_DataWrite(p_lcb->ch_lcid, p_buf);
     }
 }
index ea07612..70048c1 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2003-2012 Broadcom Corporation
+ *  Copyright (C) 2003-2016 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
 #include <string.h>
 
 #include "bt_common.h"
+#include "btu.h"
 #include "avrc_api.h"
 #include "avrc_int.h"
+#include "osi/include/fixed_queue.h"
+#include "osi/include/osi.h"
 
 /*****************************************************************************
 **  Global data
 *****************************************************************************/
+extern fixed_queue_t *btu_general_alarm_queue;
 
 
 #define AVRC_MAX_RCV_CTRL_EVT   AVCT_BROWSE_UNCONG_IND_EVT
@@ -62,6 +66,10 @@ static const uint8_t avrc_ctrl_event_map[] =
 #define AVRC_OP_SUB_UNIT_INFO_RSP_LEN   8
 #define AVRC_OP_REJ_MSG_LEN            11
 
+/* Flags definitions for AVRC_MsgReq */
+#define AVRC_MSG_MASK_IS_VENDOR_CMD         0x01
+#define AVRC_MSG_MASK_IS_CONTINUATION_RSP   0x02
+
 /******************************************************************************
 **
 ** Function         avrc_ctrl_cback
@@ -87,7 +95,124 @@ static void avrc_ctrl_cback(uint8_t handle, uint8_t event, uint16_t result,
         }
         (*avrc_cb.ccb[handle].p_ctrl_cback)(handle, avrc_event, result, peer_addr);
     }
-    /* else drop the unknown event*/
+
+    if ((event ==  AVCT_DISCONNECT_CFM_EVT) || (event == AVCT_DISCONNECT_IND_EVT))
+    {
+        avrc_flush_cmd_q(handle);
+        alarm_free(avrc_cb.ccb_int[handle].tle);
+    }
+}
+
+/******************************************************************************
+**
+** Function         avrc_flush_cmd_q
+**
+** Description      Flush command queue for the specified avrc handle
+**
+** Returns          Nothing.
+**
+******************************************************************************/
+void avrc_flush_cmd_q(uint8_t handle)
+{
+    AVRC_TRACE_DEBUG("AVRC: Flushing command queue for handle=0x%02x", handle);
+    avrc_cb.ccb_int[handle].flags &= ~AVRC_CB_FLAGS_RSP_PENDING;
+
+    alarm_cancel(avrc_cb.ccb_int[handle].tle);
+    fixed_queue_free(avrc_cb.ccb_int[handle].cmd_q, osi_free);
+}
+
+/******************************************************************************
+**
+** Function         avrc_process_timeout
+**
+** Description      Handle avrc command timeout
+**
+** Returns          Nothing.
+**
+******************************************************************************/
+void avrc_process_timeout(void *data)
+{
+    tAVRC_PARAM *param = (tAVRC_PARAM *)data;
+
+    AVRC_TRACE_DEBUG("AVRC: command timeout (handle=0x%02x, label=0x%02x)", param->handle,
+            param->label);
+
+    /* Notify app */
+    if (avrc_cb.ccb[param->handle].p_ctrl_cback)
+    {
+        (*avrc_cb.ccb[param->handle].p_ctrl_cback)(param->handle, AVRC_CMD_TIMEOUT_EVT,
+                param->label, NULL);
+    }
+
+    /* If vendor command timed-out, then send next command in the queue */
+    if (param->msg_mask & AVRC_MSG_MASK_IS_VENDOR_CMD)
+    {
+        avrc_send_next_vendor_cmd(param->handle);
+    }
+    osi_free(param);
+}
+
+/******************************************************************************
+**
+** Function         avrc_send_next_vendor_cmd
+**
+** Description      Dequeue and send next vendor command for given handle
+**
+** Returns          Nothing.
+**
+******************************************************************************/
+void avrc_send_next_vendor_cmd(uint8_t handle)
+{
+    BT_HDR *p_next_cmd;
+    uint8_t   next_label;
+
+    while ((p_next_cmd = (BT_HDR *)fixed_queue_try_dequeue(avrc_cb.ccb_int[handle].cmd_q)) != NULL)
+    {
+        p_next_cmd->event &= 0xFF;                      /* opcode */
+        next_label = (p_next_cmd->layer_specific) >> 8; /* extract label */
+        p_next_cmd->layer_specific &= 0xFF;             /* AVCT_DATA_CTRL or AVCT_DATA_BROWSE */
+
+        AVRC_TRACE_DEBUG("AVRC: Dequeuing command 0x%08x (handle=0x%02x, label=0x%02x)",
+            p_next_cmd, handle, next_label);
+
+        /* Send the message */
+        if ((AVCT_MsgReq(handle, next_label, AVCT_CMD, p_next_cmd)) == AVCT_SUCCESS)
+        {
+            /* Start command timer to wait for response */
+            avrc_start_cmd_timer(handle, next_label, AVRC_MSG_MASK_IS_VENDOR_CMD);
+            return;
+        }
+    }
+
+    if (p_next_cmd == NULL)
+    {
+        /* cmd queue empty */
+        avrc_cb.ccb_int[handle].flags &= ~AVRC_CB_FLAGS_RSP_PENDING;
+    }
+}
+
+/******************************************************************************
+**
+** Function         avrc_start_cmd_timer
+**
+** Description      Start timer for waiting for responses
+**
+** Returns          Nothing.
+**
+******************************************************************************/
+void avrc_start_cmd_timer(uint8_t handle, uint8_t label, uint8_t msg_mask)
+{
+    tAVRC_PARAM *param = osi_malloc(sizeof(tAVRC_PARAM));
+    param->handle = handle;
+    param->label = label;
+    param->msg_mask = msg_mask;
+
+    AVRC_TRACE_DEBUG("AVRC: starting timer (handle=0x%02x, label=0x%02x)", handle, label);
+
+    alarm_set_on_queue(avrc_cb.ccb_int[handle].tle,
+                       AVRC_CMD_TOUT_MS,
+                       avrc_process_timeout, param,
+                       btu_general_alarm_queue);
 }
 
 /******************************************************************************
@@ -147,7 +272,7 @@ static void avrc_prep_end_frag(uint8_t handle)
     uint8_t *p_data, *p_orig_data;
     uint8_t rsp_type;
 
-    AVRC_TRACE_DEBUG ("avrc_prep_end_frag" );
+    AVRC_TRACE_DEBUG ("%s", __func__ );
     p_fcb = &avrc_cb.fcb[handle];
 
     /* The response type of the end fragment should be the same as the the PDU of "End Fragment
@@ -289,9 +414,8 @@ static BT_HDR * avrc_proc_vendor_command(uint8_t handle, uint8_t label,
                 else
                 {
                     /* the pdu id does not match - reject the command using the current GKI buffer */
-                    AVRC_TRACE_ERROR("avrc_proc_vendor_command continue pdu: 0x%x does not match \
-                    current re-assembly pdu: 0x%x",
-                        *(p_data + 4), p_fcb->frag_pdu);
+                    AVRC_TRACE_ERROR("%s continue pdu: 0x%x does not match the current pdu: 0x%x",
+                            __func__, *(p_data + 4), p_fcb->frag_pdu);
                     status = AVRC_STS_BAD_PARAM;
                     abort_frag = true;
                 }
@@ -355,6 +479,7 @@ static uint8_t avrc_proc_far_msg(uint8_t handle, uint8_t label, uint8_t cr, BT_H
     uint8_t     pkt_type;
     tAVRC_RASM_CB   *p_rcb;
     tAVRC_NEXT_CMD   avrc_cmd;
+    tAVRC_STS   status;
 
     p_data  = (uint8_t *)(p_pkt+1) + p_pkt->offset;
 
@@ -364,149 +489,147 @@ static uint8_t avrc_proc_far_msg(uint8_t handle, uint8_t label, uint8_t cr, BT_H
     pkt_type = *(p_data + 1) & AVRC_PKT_TYPE_MASK;
     AVRC_TRACE_DEBUG ("pkt_type %d", pkt_type );
     p_rcb = &avrc_cb.rcb[handle];
-    if (p_msg->company_id == AVRC_CO_METADATA)
+
+    /* check if the message needs to be re-assembled */
+    if (pkt_type == AVRC_PKT_SINGLE || pkt_type == AVRC_PKT_START)
     {
-        /* check if the message needs to be re-assembled */
-        if (pkt_type == AVRC_PKT_SINGLE || pkt_type == AVRC_PKT_START)
-        {
-            /* previous fragments need to be dropped, when received another new message */
-            p_rcb->rasm_offset = 0;
-            osi_free_and_reset((void **)&p_rcb->p_rmsg);
-        }
+        /* previous fragments need to be dropped, when received another new message */
+        p_rcb->rasm_offset = 0;
+        osi_free_and_reset((void **)&p_rcb->p_rmsg);
+    }
 
-        if (pkt_type != AVRC_PKT_SINGLE && cr == AVCT_RSP)
+    if (pkt_type != AVRC_PKT_SINGLE && cr == AVCT_RSP)
+    {
+        /* not a single response packet - need to re-assemble metadata messages */
+        if (pkt_type == AVRC_PKT_START) {
+            /* Allocate buffer for re-assembly */
+            p_rcb->rasm_pdu = *p_data;
+            p_rcb->p_rmsg = (BT_HDR *)osi_malloc(BT_DEFAULT_BUFFER_SIZE);
+            /* Copy START packet to buffer for re-assembling fragments */
+            memcpy(p_rcb->p_rmsg, p_pkt, sizeof(BT_HDR)); /* Copy bt hdr */
+
+            /* Copy metadata message */
+            memcpy((uint8_t *)(p_rcb->p_rmsg + 1),
+                    (uint8_t *)(p_pkt+1) + p_pkt->offset, p_pkt->len);
+
+            /* offset of start of metadata response in reassembly buffer */
+            p_rcb->p_rmsg->offset = p_rcb->rasm_offset = 0;
+
+            /*
+                * Free original START packet, replace with pointer to
+                * reassembly buffer.
+                */
+            osi_free(p_pkt);
+            *pp_pkt = p_rcb->p_rmsg;
+
+            /*
+                * Set offset to point to where to copy next - use the same
+                * reassembly logic as AVCT.
+                */
+            p_rcb->p_rmsg->offset += p_rcb->p_rmsg->len;
+            req_continue = true;
+        } else if (p_rcb->p_rmsg == NULL) {
+            /* Received a CONTINUE/END, but no corresponding START
+                            (or previous fragmented response was dropped) */
+            AVRC_TRACE_DEBUG ("Received a CONTINUE/END without no corresponding START \
+                                (or previous fragmented response was dropped)");
+            drop_code = 5;
+            osi_free(p_pkt);
+            *pp_pkt = NULL;
+        }
+        else
         {
-            /* not a single response packet - need to re-assemble metadata messages */
-            if (pkt_type == AVRC_PKT_START) {
-                /* Allocate buffer for re-assembly */
-                p_rcb->rasm_pdu = *p_data;
-                p_rcb->p_rmsg = (BT_HDR *)osi_malloc(BT_DEFAULT_BUFFER_SIZE);
-                /* Copy START packet to buffer for re-assembling fragments */
-                memcpy(p_rcb->p_rmsg, p_pkt, sizeof(BT_HDR)); /* Copy bt hdr */
-
-                /* Copy metadata message */
-                memcpy((uint8_t *)(p_rcb->p_rmsg + 1),
-                       (uint8_t *)(p_pkt+1) + p_pkt->offset, p_pkt->len);
-
-                /* offset of start of metadata response in reassembly buffer */
-                p_rcb->p_rmsg->offset = p_rcb->rasm_offset = 0;
-
-                /*
-                 * Free original START packet, replace with pointer to
-                 * reassembly buffer.
-                 */
-                osi_free(p_pkt);
-                *pp_pkt = p_rcb->p_rmsg;
-
-                /*
-                 * Set offset to point to where to copy next - use the same
-                 * reassembly logic as AVCT.
-                 */
-                p_rcb->p_rmsg->offset += p_rcb->p_rmsg->len;
-                req_continue = true;
-            } else if (p_rcb->p_rmsg == NULL) {
-                /* Received a CONTINUE/END, but no corresponding START
-                              (or previous fragmented response was dropped) */
-                AVRC_TRACE_DEBUG ("Received a CONTINUE/END without no corresponding START \
-                                   (or previous fragmented response was dropped)");
-                drop_code = 5;
-                osi_free(p_pkt);
-                *pp_pkt = NULL;
-            }
-            else
+            /* get size of buffer holding assembled message */
+            /*
+                * NOTE: The buffer is allocated above at the beginning of the
+                * reassembly, and is always of size BT_DEFAULT_BUFFER_SIZE.
+                */
+            uint16_t buf_len = BT_DEFAULT_BUFFER_SIZE - sizeof(BT_HDR);
+            /* adjust offset and len of fragment for header byte */
+            p_pkt->offset += (AVRC_VENDOR_HDR_SIZE + AVRC_MIN_META_HDR_SIZE);
+            p_pkt->len -= (AVRC_VENDOR_HDR_SIZE + AVRC_MIN_META_HDR_SIZE);
+            /* verify length */
+            if ((p_rcb->p_rmsg->offset + p_pkt->len) > buf_len)
             {
-                /* get size of buffer holding assembled message */
-                /*
-                 * NOTE: The buffer is allocated above at the beginning of the
-                 * reassembly, and is always of size BT_DEFAULT_BUFFER_SIZE.
-                 */
-                uint16_t buf_len = BT_DEFAULT_BUFFER_SIZE - sizeof(BT_HDR);
-                /* adjust offset and len of fragment for header byte */
-                p_pkt->offset += (AVRC_VENDOR_HDR_SIZE + AVRC_MIN_META_HDR_SIZE);
-                p_pkt->len -= (AVRC_VENDOR_HDR_SIZE + AVRC_MIN_META_HDR_SIZE);
-                /* verify length */
-                if ((p_rcb->p_rmsg->offset + p_pkt->len) > buf_len)
-                {
-                    AVRC_TRACE_WARNING("Fragmented message too big! - report the partial message");
-                    p_pkt->len = buf_len - p_rcb->p_rmsg->offset;
-                    pkt_type = AVRC_PKT_END;
-                    buf_overflow = true;
-                }
-
-                /* copy contents of p_pkt to p_rx_msg */
-                memcpy((uint8_t *)(p_rcb->p_rmsg + 1) + p_rcb->p_rmsg->offset,
-                       (uint8_t *)(p_pkt + 1) + p_pkt->offset, p_pkt->len);
-
-                if (pkt_type == AVRC_PKT_END)
-                {
-                    p_rcb->p_rmsg->offset = p_rcb->rasm_offset;
-                    p_rcb->p_rmsg->len += p_pkt->len;
-                    p_pkt_new = p_rcb->p_rmsg;
-                    p_rcb->rasm_offset = 0;
-                    p_rcb->p_rmsg = NULL;
-                    p_msg->p_vendor_data   = (uint8_t *)(p_pkt_new+1) + p_pkt_new->offset;
-                    p_msg->hdr.ctype       = p_msg->p_vendor_data[0] & AVRC_CTYPE_MASK;
-                    /* 6 = ctype, subunit*, opcode & CO_ID */
-                    p_msg->p_vendor_data  += AVRC_VENDOR_HDR_SIZE;
-                    p_msg->vendor_len      = p_pkt_new->len - AVRC_VENDOR_HDR_SIZE;
-                    p_data = p_msg->p_vendor_data + 1; /* skip pdu */
-                    *p_data++ = AVRC_PKT_SINGLE;
-                    UINT16_TO_BE_STREAM(p_data, (p_msg->vendor_len - AVRC_MIN_META_HDR_SIZE));
-                    AVRC_TRACE_DEBUG("end frag:%d, total len:%d, offset:%d", p_pkt->len,
-                        p_pkt_new->len, p_pkt_new->offset);
-                }
-                else
-                {
-                    p_rcb->p_rmsg->offset += p_pkt->len;
-                    p_rcb->p_rmsg->len += p_pkt->len;
-                    p_pkt_new = NULL;
-                    req_continue = true;
-                }
-                osi_free(p_pkt);
-                *pp_pkt = p_pkt_new;
+                AVRC_TRACE_WARNING("Fragmented message too big! - report the partial message");
+                p_pkt->len = buf_len - p_rcb->p_rmsg->offset;
+                pkt_type = AVRC_PKT_END;
+                buf_overflow = true;
             }
-        }
 
-        if (cr == AVCT_CMD)
-        {
-            p_rsp = avrc_proc_vendor_command(handle, label, *pp_pkt, p_msg);
-            if (p_rsp)
+            /* copy contents of p_pkt to p_rx_msg */
+            memcpy((uint8_t *)(p_rcb->p_rmsg + 1) + p_rcb->p_rmsg->offset,
+                    (uint8_t *)(p_pkt + 1) + p_pkt->offset, p_pkt->len);
+
+            if (pkt_type == AVRC_PKT_END)
             {
-                AVCT_MsgReq( handle, label, AVCT_RSP, p_rsp);
-                drop_code = 3;
+                p_rcb->p_rmsg->offset = p_rcb->rasm_offset;
+                p_rcb->p_rmsg->len += p_pkt->len;
+                p_pkt_new = p_rcb->p_rmsg;
+                p_rcb->rasm_offset = 0;
+                p_rcb->p_rmsg = NULL;
+                p_msg->p_vendor_data   = (uint8_t *)(p_pkt_new+1) + p_pkt_new->offset;
+                p_msg->hdr.ctype       = p_msg->p_vendor_data[0] & AVRC_CTYPE_MASK;
+                /* 6 = ctype, subunit*, opcode & CO_ID */
+                p_msg->p_vendor_data  += AVRC_VENDOR_HDR_SIZE;
+                p_msg->vendor_len      = p_pkt_new->len - AVRC_VENDOR_HDR_SIZE;
+                p_data = p_msg->p_vendor_data + 1; /* skip pdu */
+                *p_data++ = AVRC_PKT_SINGLE;
+                UINT16_TO_BE_STREAM(p_data, (p_msg->vendor_len - AVRC_MIN_META_HDR_SIZE));
+                AVRC_TRACE_DEBUG("end frag:%d, total len:%d, offset:%d", p_pkt->len,
+                    p_pkt_new->len, p_pkt_new->offset);
             }
-            else if (p_msg->hdr.opcode == AVRC_OP_DROP)
+            else
             {
-                drop_code = 1;
+                p_rcb->p_rmsg->offset += p_pkt->len;
+                p_rcb->p_rmsg->len += p_pkt->len;
+                p_pkt_new = NULL;
+                req_continue = true;
             }
-            else if (p_msg->hdr.opcode == AVRC_OP_DROP_N_FREE)
-                drop_code = 4;
+            osi_free(p_pkt);
+            *pp_pkt = p_pkt_new;
+        }
+    }
 
+    if (cr == AVCT_CMD)
+    {
+        p_rsp = avrc_proc_vendor_command(handle, label, *pp_pkt, p_msg);
+        if (p_rsp)
+        {
+            AVCT_MsgReq( handle, label, AVCT_RSP, p_rsp);
+            drop_code = 3;
         }
-        else if (cr == AVCT_RSP && req_continue == true)
+        else if (p_msg->hdr.opcode == AVRC_OP_DROP)
+        {
+            drop_code = 1;
+        }
+        else if (p_msg->hdr.opcode == AVRC_OP_DROP_N_FREE)
+            drop_code = 4;
+
+    }
+    else if (cr == AVCT_RSP)
+    {
+        if (req_continue == true)
         {
             avrc_cmd.pdu    = AVRC_PDU_REQUEST_CONTINUATION_RSP;
-            avrc_cmd.status = AVRC_STS_NO_ERROR;
-            avrc_cmd.target_pdu = p_rcb->rasm_pdu;
-            if (AVRC_BldCommand ((tAVRC_COMMAND *)&avrc_cmd, &p_cmd) == AVRC_STS_NO_ERROR)
-            {
-                drop_code = 2;
-                AVRC_MsgReq (handle, (uint8_t)(label), AVRC_CMD_CTRL, p_cmd);
-            }
+            drop_code = 2;
         }
-        /*
-         * Drop it if we are out of buffer
-         */
-        else if (cr == AVCT_RSP && req_continue == false  && buf_overflow == true)
+        else if (buf_overflow == true)
         {
+            /* Incoming message too big to fit in BT_DEFAULT_BUFFER_SIZE. Send abort to peer  */
             avrc_cmd.pdu    = AVRC_PDU_ABORT_CONTINUATION_RSP;
-            avrc_cmd.status = AVRC_STS_NO_ERROR;
-            avrc_cmd.target_pdu = p_rcb->rasm_pdu;
-            if (AVRC_BldCommand ((tAVRC_COMMAND *)&avrc_cmd, &p_cmd) == AVRC_STS_NO_ERROR)
-            {
-                drop_code = 4;
-                AVRC_MsgReq (handle, (uint8_t)(label), AVRC_CMD_CTRL, p_cmd);
-            }
+            drop_code = 4;
+        }
+        else
+        {
+            return drop_code;
+        }
+        avrc_cmd.status = AVRC_STS_NO_ERROR;
+        avrc_cmd.target_pdu = p_rcb->rasm_pdu;
+        status = AVRC_BldCommand ((tAVRC_COMMAND *)&avrc_cmd, &p_cmd);
+        if (status == AVRC_STS_NO_ERROR)
+        {
+            AVRC_MsgReq (handle, (uint8_t)(label), AVRC_CMD_CTRL, p_cmd);
         }
     }
 
@@ -561,12 +684,28 @@ static void avrc_msg_cback(uint8_t handle, uint8_t label, uint8_t cr,
         AVCT_RemoveConn(handle);
         return;
     }
+    else if (cr == AVCT_RSP)
+    {
+        /* Received response. Stop command timeout timer */
+        AVRC_TRACE_DEBUG("AVRC: stopping timer (handle=0x%02x)", handle);
+        alarm_cancel(avrc_cb.ccb_int[handle].tle);
+    }
 
     p_data  = (uint8_t *)(p_pkt+1) + p_pkt->offset;
     memset(&msg, 0, sizeof(tAVRC_MSG) );
+
+    if (p_pkt->layer_specific == AVCT_DATA_BROWSE)
+    {
+        opcode = AVRC_OP_BROWSE;
+        msg.browse.hdr.ctype= cr;
+        msg.browse.p_browse_data   = p_data;
+        msg.browse.browse_len      = p_pkt->len;
+        msg.browse.p_browse_pkt    = p_pkt;
+    }
+    else
     {
         msg.hdr.ctype           = p_data[0] & AVRC_CTYPE_MASK;
-        AVRC_TRACE_DEBUG("avrc_msg_cback handle:%d, ctype:%d, offset:%d, len: %d",
+        AVRC_TRACE_DEBUG("%s handle:%d, ctype:%d, offset:%d, len: %d", __func__,
                 handle, msg.hdr.ctype, p_pkt->offset, p_pkt->len);
         msg.hdr.subunit_type    = (p_data[1] & AVRC_SUBTYPE_MASK) >> AVRC_SUBTYPE_SHIFT;
         msg.hdr.subunit_id      = p_data[1] & AVRC_SUBID_MASK;
@@ -707,6 +846,12 @@ static void avrc_msg_cback(uint8_t handle, uint8_t label, uint8_t cr,
 #endif
             }
 #endif /* (AVRC_METADATA_INCLUDED == TRUE) */
+           /* If vendor response received, and did not ask for continuation */
+           /* then check queue for addition commands to send */
+            if ((cr == AVCT_RSP) && (drop_code != 2))
+            {
+                avrc_send_next_vendor_cmd(handle);
+            }
             break;
 
         case AVRC_OP_PASS_THRU:
@@ -734,6 +879,13 @@ static void avrc_msg_cback(uint8_t handle, uint8_t label, uint8_t cr,
                 msg.pass.p_pass_data = NULL;
             break;
 
+         case AVRC_OP_BROWSE:
+             /* If browse response received, then check queue for addition commands to send */
+             if (cr == AVCT_RSP)
+             {
+                 avrc_send_next_vendor_cmd(handle);
+             }
+             break;
 
         default:
             if ((avrc_cb.ccb[handle].control & AVRC_CT_TARGET) && (cr == AVCT_CMD))
@@ -747,6 +899,7 @@ static void avrc_msg_cback(uint8_t handle, uint8_t label, uint8_t cr,
     }
     else /* drop the event */
     {
+        if (opcode != AVRC_OP_BROWSE)
             drop    = true;
     }
 
@@ -778,12 +931,16 @@ static void avrc_msg_cback(uint8_t handle, uint8_t label, uint8_t cr,
 #if (BT_USE_TRACES == TRUE)
     else
     {
-        AVRC_TRACE_WARNING("avrc_msg_cback %s msg handle:%d, control:%d, cr:%d, opcode:x%x",
-                p_drop_msg,
+        AVRC_TRACE_WARNING("%s %s msg handle:%d, control:%d, cr:%d, opcode:x%x",
+                __func__, p_drop_msg,
                 handle, avrc_cb.ccb[handle].control, cr, opcode);
     }
 #endif
 
+    if (opcode == AVRC_OP_BROWSE && msg.browse.p_browse_pkt == NULL)
+    {
+        do_free = false;
+    }
 
     if (do_free)
         osi_free(p_pkt);
@@ -955,13 +1112,16 @@ uint16_t AVRC_Open(uint8_t *p_handle, tAVRC_CONN_CB *p_ccb, BD_ADDR_PTR peer_add
     if (status == AVCT_SUCCESS)
     {
         memcpy(&avrc_cb.ccb[*p_handle], p_ccb, sizeof(tAVRC_CONN_CB));
+        memset(&avrc_cb.ccb_int[*p_handle], 0, sizeof(tAVRC_CONN_INT_CB));
 #if (AVRC_METADATA_INCLUDED == TRUE)
         memset(&avrc_cb.fcb[*p_handle], 0, sizeof(tAVRC_FRAG_CB));
         memset(&avrc_cb.rcb[*p_handle], 0, sizeof(tAVRC_RASM_CB));
 #endif
+        avrc_cb.ccb_int[*p_handle].tle = alarm_new("avrcp.commandTimer");
+        avrc_cb.ccb_int[*p_handle].cmd_q = fixed_queue_new(SIZE_MAX);
     }
-    AVRC_TRACE_DEBUG("AVRC_Open role: %d, control:%d status:%d, handle:%d", cc.role, cc.control,
-        status, *p_handle);
+    AVRC_TRACE_DEBUG("%s role: %d, control:%d status:%d, handle:%d", __func__,
+                      cc.role, cc.control, status, *p_handle);
 
     return status;
 }
@@ -986,10 +1146,45 @@ uint16_t AVRC_Open(uint8_t *p_handle, tAVRC_CONN_CB *p_ccb, BD_ADDR_PTR peer_add
 ******************************************************************************/
 uint16_t AVRC_Close(uint8_t handle)
 {
-    AVRC_TRACE_DEBUG("AVRC_Close handle:%d", handle);
+    AVRC_TRACE_DEBUG("%s handle:%d", __func__, handle);
     return AVCT_RemoveConn(handle);
 }
 
+/******************************************************************************
+**
+** Function         AVRC_OpenBrowse
+**
+** Description      This function is called to open a browsing connection to AVCTP.
+**                  The connection can be either an initiator or acceptor, as
+**                  determined by the p_conn_role.
+**                  The handle is returned by a previous call to AVRC_Open.
+**
+** Returns          AVRC_SUCCESS if successful.
+**                  AVRC_NO_RESOURCES if there are not enough resources to open
+**                  the connection.
+**
+******************************************************************************/
+uint16_t AVRC_OpenBrowse(uint8_t handle, uint8_t conn_role)
+{
+    return AVCT_CreateBrowse(handle, conn_role);
+}
+
+/******************************************************************************
+**
+** Function         AVRC_CloseBrowse
+**
+** Description      Close a connection opened with AVRC_OpenBrowse().
+**                  This function is called when the
+**                  application is no longer using a connection.
+**
+** Returns          AVRC_SUCCESS if successful.
+**                  AVRC_BAD_HANDLE if handle is invalid.
+**
+******************************************************************************/
+uint16_t AVRC_CloseBrowse(uint8_t handle)
+{
+    return AVCT_RemoveBrowse(handle);
+}
 
 /******************************************************************************
 **
@@ -1016,6 +1211,9 @@ uint16_t AVRC_MsgReq (uint8_t handle, uint8_t label, uint8_t ctype, BT_HDR *p_pk
     uint8_t *p_start = NULL;
     tAVRC_FRAG_CB   *p_fcb;
     uint16_t len;
+    uint16_t status;
+    bool msg_mask = 0;
+    uint16_t  peer_mtu;
 
     if (!p_pkt)
         return AVRC_BAD_PARAM;
@@ -1043,6 +1241,18 @@ uint16_t AVRC_MsgReq (uint8_t handle, uint8_t label, uint8_t ctype, BT_HDR *p_pk
         *p_data++       = (AVRC_SUB_PANEL << AVRC_SUBTYPE_SHIFT);
         *p_data++       = AVRC_OP_VENDOR;
         AVRC_CO_ID_TO_BE_STREAM(p_data, AVRC_CO_METADATA);
+
+        /* Check if this is a AVRC_PDU_REQUEST_CONTINUATION_RSP */
+        if (cr == AVCT_CMD)
+        {
+            msg_mask |= AVRC_MSG_MASK_IS_VENDOR_CMD;
+
+            if ((*p_start == AVRC_PDU_REQUEST_CONTINUATION_RSP)
+                || (*p_start == AVRC_PDU_ABORT_CONTINUATION_RSP))
+            {
+                msg_mask |= AVRC_MSG_MASK_IS_CONTINUATION_RSP;
+            }
+        }
     }
     else if (p_pkt->event == AVRC_OP_PASS_THRU)
     {
@@ -1058,9 +1268,29 @@ uint16_t AVRC_MsgReq (uint8_t handle, uint8_t label, uint8_t ctype, BT_HDR *p_pk
         *p_data++       = 5;                /* operation data len */
         AVRC_CO_ID_TO_BE_STREAM(p_data, AVRC_CO_METADATA);
     }
+    else
+    {
+        chk_frag = false;
+        peer_mtu = AVCT_GetBrowseMtu (handle);
+        if (p_pkt->len > (peer_mtu-AVCT_HDR_LEN_SINGLE))
+        {
+            AVRC_TRACE_ERROR ("%s bigger than peer mtu (p_pkt->len(%d) > peer_mtu(%d-%d))",
+                               __func__, p_pkt->len, peer_mtu, AVCT_HDR_LEN_SINGLE );
+            osi_free_and_reset((void **)&p_pkt);
+            return AVRC_MSG_TOO_BIG;
+        }
+    }
 
     /* abandon previous fragments */
     p_fcb = &avrc_cb.fcb[handle];
+
+    if(p_fcb == NULL)
+    {
+        AVRC_TRACE_ERROR ("%s p_fcb is NULL", __func__ );
+        osi_free_and_reset((void **)&p_pkt);
+        return AVRC_NOT_OPEN;
+    }
+
     if (p_fcb->frag_enabled)
         p_fcb->frag_enabled = false;
 
@@ -1092,6 +1322,7 @@ uint16_t AVRC_MsgReq (uint8_t handle, uint8_t label, uint8_t ctype, BT_HDR *p_pk
                 p_data += AVRC_VENDOR_HDR_SIZE;
                 p_data++; /* pdu */
                 *p_data++ = AVRC_PKT_START;
+
                 /* 4 pdu, pkt_type & len */
                 len = (AVRC_MAX_CTRL_DATA_LEN - AVRC_VENDOR_HDR_SIZE - AVRC_MIN_META_HDR_SIZE);
                 UINT16_TO_BE_STREAM(p_data, len);
@@ -1102,14 +1333,44 @@ uint16_t AVRC_MsgReq (uint8_t handle, uint8_t label, uint8_t ctype, BT_HDR *p_pk
                                   p_pkt->len, len, p_fcb->p_fmsg->len );
             } else {
                 /* TODO: Is this "else" block valid? Remove it? */
-                AVRC_TRACE_ERROR ("AVRC_MsgReq no buffers for fragmentation" );
+                AVRC_TRACE_ERROR ("%s no buffers for fragmentation", __func__ );
                 osi_free(p_pkt);
                 return AVRC_NO_RESOURCES;
             }
         }
     }
+    else if ((p_pkt->event == AVRC_OP_VENDOR) && (cr == AVCT_CMD) &&
+        (avrc_cb.ccb_int[handle].flags & AVRC_CB_FLAGS_RSP_PENDING) &&
+        !(msg_mask & AVRC_MSG_MASK_IS_CONTINUATION_RSP))
+    {
+        /* If we are sending a vendor specific command, and a response is pending,
+         * then enqueue the command until the response has been received.
+         * This is to interop with TGs that abort sending responses whenever a new command
+         * is received (exception is continuation request command
+         * must sent that to get additional response frags) */
+        AVRC_TRACE_DEBUG("AVRC: Enqueuing command 0x%08x (handle=0x%02x, label=0x%02x)",
+                           p_pkt, handle, label);
+
+        /* label in BT_HDR (will need this later when the command is dequeued) */
+        p_pkt->layer_specific = (label << 8) | (p_pkt->layer_specific & 0xFF);
+
+        /* Enqueue the command */
+        fixed_queue_enqueue(avrc_cb.ccb_int[handle].cmd_q, p_pkt);
+        return AVRC_SUCCESS;
+    }
 
-    return AVCT_MsgReq( handle, label, cr, p_pkt);
+    /* Send the message */
+    status = AVCT_MsgReq( handle, label, cr, p_pkt);
+    if ((status == AVCT_SUCCESS) && (cr == AVCT_CMD))
+    {
+        /* If a command was successfully sent, indicate that a response is pending */
+        avrc_cb.ccb_int[handle].flags |= AVRC_CB_FLAGS_RSP_PENDING;
+
+        /* Start command timer to wait for response */
+        avrc_start_cmd_timer(handle, label, msg_mask);
+    }
+
+    return status;
 #else
     return AVRC_NO_RESOURCES;
 #endif
@@ -1142,15 +1403,22 @@ uint16_t AVRC_MsgReq (uint8_t handle, uint8_t label, uint8_t ctype, BT_HDR *p_pk
 uint16_t AVRC_PassCmd(uint8_t handle, uint8_t label, tAVRC_MSG_PASS *p_msg)
 {
     BT_HDR *p_buf;
-    assert(p_msg != NULL);
-    if (p_msg)
+    uint16_t status = AVRC_NO_RESOURCES;
+    if (!p_msg)
+        return AVRC_BAD_PARAM;
+
+    p_msg->hdr.ctype    = AVRC_CMD_CTRL;
+    p_buf = avrc_pass_msg(p_msg);
+    if (p_buf)
     {
-        p_msg->hdr.ctype    = AVRC_CMD_CTRL;
-        p_buf = avrc_pass_msg(p_msg);
-        if (p_buf)
-            return AVCT_MsgReq( handle, label, AVCT_CMD, p_buf);
+        status = AVCT_MsgReq( handle, label, AVCT_CMD, p_buf);
+        if (status == AVCT_SUCCESS)
+        {
+            /* Start command timer to wait for response */
+            avrc_start_cmd_timer(handle, label, 0);
+        }
     }
-    return AVRC_NO_RESOURCES;
+    return (status);
 }
 
 /******************************************************************************
@@ -1181,13 +1449,12 @@ uint16_t AVRC_PassCmd(uint8_t handle, uint8_t label, tAVRC_MSG_PASS *p_msg)
 uint16_t AVRC_PassRsp(uint8_t handle, uint8_t label, tAVRC_MSG_PASS *p_msg)
 {
     BT_HDR *p_buf;
-    assert(p_msg != NULL);
-    if (p_msg)
-    {
-        p_buf = avrc_pass_msg(p_msg);
-        if (p_buf)
-            return AVCT_MsgReq( handle, label, AVCT_RSP, p_buf);
-    }
+    if (!p_msg)
+        return AVRC_BAD_PARAM;
+
+    p_buf = avrc_pass_msg(p_msg);
+    if (p_buf)
+        return AVCT_MsgReq( handle, label, AVCT_RSP, p_buf);
     return AVRC_NO_RESOURCES;
 }
 
index 72c7435..6f07da0 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2003-2013 Broadcom Corporation
+ *  Copyright (C) 2003-2016 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
 **  Global data
 *****************************************************************************/
 #if (AVRC_METADATA_INCLUDED == TRUE)
+#define AVRC_ITEM_PLAYER_IS_VALID(_p_player) ((_p_player)->name.p_str && \
+               ((_p_player)->major_type & AVRC_MJ_TYPE_INVALID) == 0 && \
+               ((_p_player)->sub_type & AVRC_SUB_TYPE_INVALID) == 0 && \
+               (((_p_player)->play_status <= AVRC_PLAYSTATE_REV_SEEK) || \
+                ((_p_player)->play_status == AVRC_PLAYSTATE_ERROR)) )
 
 /*******************************************************************************
 **
@@ -116,7 +121,8 @@ static tAVRC_STS avrc_bld_get_capability_rsp (tAVRC_GET_CAPS_RSP *p_rsp, BT_HDR
 **                  Otherwise, the error code.
 **
 *******************************************************************************/
-static tAVRC_STS avrc_bld_list_app_settings_attr_rsp (tAVRC_LIST_APP_ATTR_RSP *p_rsp, BT_HDR *p_pkt)
+static tAVRC_STS avrc_bld_list_app_settings_attr_rsp (tAVRC_LIST_APP_ATTR_RSP *p_rsp,
+        BT_HDR *p_pkt)
 {
     uint8_t *p_data, *p_start, *p_len, *p_num;
     uint16_t len = 0;
@@ -250,7 +256,8 @@ static tAVRC_STS avrc_bld_get_cur_app_setting_value_rsp (tAVRC_GET_CUR_APP_VALUE
 
     for (xx=0; xx<p_rsp->num_val; xx++)
     {
-        if (avrc_is_valid_player_attrib_value(p_rsp->p_vals[xx].attr_id, p_rsp->p_vals[xx].attr_val))
+        if (avrc_is_valid_player_attrib_value(p_rsp->p_vals[xx].attr_id,
+            p_rsp->p_vals[xx].attr_val))
         {
             (*p_count)++;
             UINT8_TO_BE_STREAM(p_data, p_rsp->p_vals[xx].attr_id);
@@ -296,7 +303,8 @@ static tAVRC_STS avrc_bld_set_app_setting_value_rsp (tAVRC_RSP *p_rsp, BT_HDR *p
 **                  Otherwise, the error code.
 **
 *******************************************************************************/
-static tAVRC_STS avrc_bld_app_setting_text_rsp (tAVRC_GET_APP_ATTR_TXT_RSP *p_rsp, BT_HDR *p_pkt)
+static tAVRC_STS avrc_bld_app_setting_text_rsp (tAVRC_GET_APP_ATTR_TXT_RSP *p_rsp,
+    BT_HDR *p_pkt)
 {
     uint8_t *p_data, *p_start, *p_len, *p_count;
     uint16_t len, len_left;
@@ -485,7 +493,7 @@ static tAVRC_STS avrc_bld_get_elem_attrs_rsp (tAVRC_GET_ELEM_ATTRS_RSP *p_rsp, B
         if (!AVRC_IS_VALID_MEDIA_ATTRIBUTE(p_rsp->p_attrs[xx].attr_id))
         {
             AVRC_TRACE_ERROR("%s invalid attr id[%d]: %d",
-                             __func__, xx, p_rsp->p_attrs[xx].attr_id);
+                __func__, xx, p_rsp->p_attrs[xx].attr_id);
             continue;
         }
         if ( !p_rsp->p_attrs[xx].name.p_str )
@@ -515,11 +523,12 @@ static tAVRC_STS avrc_bld_get_elem_attrs_rsp (tAVRC_GET_ELEM_ATTRS_RSP *p_rsp, B
 **                  Otherwise, the error code.
 **
 *******************************************************************************/
-static tAVRC_STS avrc_bld_get_play_status_rsp (tAVRC_GET_PLAY_STATUS_RSP *p_rsp, BT_HDR *p_pkt)
+static tAVRC_STS avrc_bld_get_play_status_rsp (tAVRC_GET_PLAY_STATUS_RSP *p_rsp,
+    BT_HDR *p_pkt)
 {
     uint8_t *p_data, *p_start;
 
-    AVRC_TRACE_API("avrc_bld_get_play_status_rsp");
+    AVRC_TRACE_API("%s", __func__);
     p_start = (uint8_t *)(p_pkt + 1) + p_pkt->offset;
     p_data = p_start + 2;
 
@@ -582,6 +591,8 @@ static tAVRC_STS avrc_bld_notify_rsp (tAVRC_REG_NOTIF_RSP *p_rsp, BT_HDR *p_pkt)
 
     case AVRC_EVT_TRACK_REACHED_END:        /* 0x03 */
     case AVRC_EVT_TRACK_REACHED_START:      /* 0x04 */
+    case AVRC_EVT_NOW_PLAYING_CHANGE:       /* 0x09 */
+    case AVRC_EVT_AVAL_PLAYERS_CHANGE:      /* 0x0a */
         len = 1;
         break;
 
@@ -645,11 +656,22 @@ static tAVRC_STS avrc_bld_notify_rsp (tAVRC_REG_NOTIF_RSP *p_rsp, BT_HDR *p_pkt)
             status = AVRC_STS_BAD_PARAM;
         break;
 
-    case AVRC_EVT_VOLUME_CHANGE:
+    case AVRC_EVT_VOLUME_CHANGE:            /* 0x0d */
         len = 2;
         UINT8_TO_BE_STREAM(p_data, (AVRC_MAX_VOLUME & p_rsp->param.volume));
         break;
 
+    case AVRC_EVT_ADDR_PLAYER_CHANGE:       /* 0x0b */
+        UINT16_TO_BE_STREAM(p_data, p_rsp->param.addr_player.player_id); /* player_id */
+        UINT16_TO_BE_STREAM(p_data, p_rsp->param.addr_player.uid_counter); /* uid counter */
+        len = 5;
+        break;
+
+    case AVRC_EVT_UIDS_CHANGE:              /* 0x0c */
+        UINT16_TO_BE_STREAM(p_data, p_rsp->param.uid_counter); /* uid counter */
+        len = 3;
+        break;
+
     default:
         status = AVRC_STS_BAD_PARAM;
         AVRC_TRACE_ERROR("%s unknown event_id", __func__);
@@ -686,14 +708,14 @@ static tAVRC_STS avrc_bld_next_rsp (tAVRC_NEXT_RSP *p_rsp, BT_HDR *p_pkt)
 
 /*****************************************************************************
 **
-** Function      avrc_bld_set_address_player_rsp
+** Function      avrc_bld_set_absolute_volume_rsp
 **
-** Description   This function builds the set address player response
+** Description   This function builds the set absolute volume response
 **
-** Returns       AVRC_STS_NO_ERROR
+** Returns       AVRC_STS_NO_ERROR, if the response is build successfully
 **
 ******************************************************************************/
-static tAVRC_STS avrc_bld_set_address_player_rsp(tAVRC_RSP *p_rsp, BT_HDR *p_pkt)
+static tAVRC_STS avrc_bld_set_absolute_volume_rsp(uint8_t abs_vol, BT_HDR *p_pkt)
 {
     AVRC_TRACE_API("%s", __func__);
     uint8_t *p_start = (uint8_t *)(p_pkt + 1) + p_pkt->offset;
@@ -701,119 +723,671 @@ static tAVRC_STS avrc_bld_set_address_player_rsp(tAVRC_RSP *p_rsp, BT_HDR *p_pkt
     uint8_t *p_data = p_start + 2;
     /* add fixed lenth status(1) */
     UINT16_TO_BE_STREAM(p_data, 1);
-    UINT8_TO_BE_STREAM(p_data, p_rsp->status);
+    UINT8_TO_BE_STREAM(p_data, abs_vol);
     p_pkt->len = (p_data - p_start);
     return AVRC_STS_NO_ERROR;
 }
 
-/*****************************************************************************
+/*******************************************************************************
 **
-** Function      avrc_bld_play_item_rsp
+** Function         avrc_bld_group_navigation_rsp
 **
-** Description   This function builds the play item response
+** Description      This function builds the Group Navigation
+**                  response.
 **
-** Returns       AVRC_STS_NO_ERROR, if the response is build successfully
+** Returns          AVRC_STS_NO_ERROR, if the response is built successfully
+**                  Otherwise, the error code.
 **
-******************************************************************************/
-static tAVRC_STS avrc_bld_play_item_rsp(tAVRC_RSP *p_rsp, BT_HDR *p_pkt)
+*******************************************************************************/
+tAVRC_STS avrc_bld_group_navigation_rsp (uint16_t navi_id, BT_HDR *p_pkt)
 {
+    if (!AVRC_IS_VALID_GROUP(navi_id))
+    {
+        AVRC_TRACE_ERROR("%s bad navigation op id: %d", __func__, navi_id);
+        return AVRC_STS_BAD_PARAM;
+    }
     AVRC_TRACE_API("%s", __func__);
+    uint8_t *p_data = (uint8_t *)(p_pkt + 1) + p_pkt->offset;
+    UINT16_TO_BE_STREAM(p_data, navi_id);
+    p_pkt->len = 2;
+    return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+**
+** Function         avrc_bld_rejected_rsp
+**
+** Description      This function builds the General Response response.
+**
+** Returns          AVRC_STS_NO_ERROR, if the response is built successfully
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_rejected_rsp( tAVRC_RSP *p_rsp, BT_HDR *p_pkt )
+{
     uint8_t *p_start = (uint8_t *)(p_pkt + 1) + p_pkt->offset;
-    /* To calculate length */
-    uint8_t *p_data = p_start + 2;
-    /* add fixed lenth status(1) */
+    uint8_t *p_data;
+    uint8_t opcode = p_rsp->opcode;
+
+    AVRC_TRACE_API("%s: status=%d, pdu:x%x, opcode=%x", __func__, p_rsp->status,
+                     p_rsp->pdu, opcode);
+
+    if (opcode == AVRC_OP_BROWSE)
+    {
+        p_data = p_start + 1;
+        if ((AVRC_PDU_INVALID == *p_start) || (avrc_opcode_from_pdu(*p_start) != AVRC_OP_BROWSE))
+        {
+            /* if invalid or the given opcode is not recognized as a browsing command opcode, */
+            /* use general reject command */
+            *p_start = AVRC_PDU_GENERAL_REJECT;
+        }
+    }
+    else
+    {
+        p_data = p_start + 2;
+    }
+    AVRC_TRACE_DEBUG("%s pdu:x%x, Opcode:%x", __func__, *p_start,opcode);
     UINT16_TO_BE_STREAM(p_data, 1);
     UINT8_TO_BE_STREAM(p_data, p_rsp->status);
-    p_pkt->len = (p_data - p_start);
+    p_pkt->len = p_data - p_start;
     return AVRC_STS_NO_ERROR;
 }
 
 /*****************************************************************************
+**  the following commands are introduced in AVRCP 1.4
+*****************************************************************************/
+
+/*******************************************************************************
 **
-** Function      avrc_bld_set_absolute_volume_rsp
+** Function         avrc_bld_ctrl_status_rsp
 **
-** Description   This function builds the set absolute volume response
+** Description      This function builds the responses with a uint8_t parameter.
 **
-** Returns       AVRC_STS_NO_ERROR, if the response is build successfully
+** Returns          AVRC_STS_NO_ERROR, if the response is built successfully
+**                  Otherwise, the error code.
 **
-******************************************************************************/
-static tAVRC_STS avrc_bld_set_absolute_volume_rsp(uint8_t abs_vol, BT_HDR *p_pkt)
+*******************************************************************************/
+static tAVRC_STS avrc_bld_ctrl_status_rsp (tAVRC_RSP *p_rsp, BT_HDR *p_pkt)
 {
-    AVRC_TRACE_API("%s", __func__);
     uint8_t *p_start = (uint8_t *)(p_pkt + 1) + p_pkt->offset;
+    AVRC_TRACE_DEBUG("pdu:x%x", *p_start);
+
     /* To calculate length */
-    uint8_t *p_data = p_start + 2;
-    /* add fixed lenth status(1) */
+    uint8_t *p_data = p_start + 2; /* pdu + rsvd */
+
+    /* add fixed lenth - status(1) */
     UINT16_TO_BE_STREAM(p_data, 1);
-    UINT8_TO_BE_STREAM(p_data, abs_vol);
+    UINT8_TO_BE_STREAM(p_data, p_rsp->status);
     p_pkt->len = (p_data - p_start);
     return AVRC_STS_NO_ERROR;
 }
 
 /*******************************************************************************
 **
-** Function         avrc_bld_group_navigation_rsp
+** Function         avrc_bld_set_addr_player_rsp
 **
-** Description      This function builds the Group Navigation
-**                  response.
+** Description      This function builds the Set Addresses Player response.
 **
 ** Returns          AVRC_STS_NO_ERROR, if the response is built successfully
 **                  Otherwise, the error code.
 **
 *******************************************************************************/
-tAVRC_STS avrc_bld_group_navigation_rsp (uint16_t navi_id, BT_HDR *p_pkt)
+static tAVRC_STS avrc_bld_set_addr_player_rsp (tAVRC_RSP *p_rsp, BT_HDR *p_pkt)
 {
-    if (!AVRC_IS_VALID_GROUP(navi_id))
+    AVRC_TRACE_API("%s", __func__);
+    return avrc_bld_ctrl_status_rsp(p_rsp, p_pkt);
+}
+
+/*******************************************************************************
+**
+** Function         avrc_bld_set_browsed_player_rsp
+**
+** Description      This function builds the Set Browsed Player response.
+**
+**                  This message goes through the Browsing channel and is
+**                  valid only when AVCT_BROWSE_INCLUDED compile option is true
+**
+** Returns          AVRC_STS_NO_ERROR, if the response is built successfully
+**                  Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_set_browsed_player_rsp (tAVRC_SET_BR_PLAYER_RSP *p_rsp,
+    BT_HDR *p_pkt)
+{
+    uint8_t   *p_data, *p_start;
+    uint8_t   *p_len;
+    uint16_t  len;
+    tAVRC_NAME  *p_folders = p_rsp->p_folders;
+    uint16_t  len_left;
+    uint8_t   *p_folder_depth;
+    uint16_t  mtu;
+
+    /* make sure the given buffer can accomodate this response */
+    len_left = BT_DEFAULT_BUFFER_SIZE - BT_HDR_SIZE;
+    p_data = (uint8_t *)(p_pkt + 1);
+    BE_STREAM_TO_UINT16 (mtu, p_data);
+    if (len_left > mtu)
     {
-        AVRC_TRACE_ERROR("%s bad navigation op id: %d", __func__, navi_id);
-        return AVRC_STS_BAD_PARAM;
+        len_left = mtu;
     }
-    AVRC_TRACE_API("%s", __func__);
-    uint8_t *p_data = (uint8_t *)(p_pkt + 1) + p_pkt->offset;
-    UINT16_TO_BE_STREAM(p_data, navi_id);
-    p_pkt->len = 2;
+    len_left = len_left - p_pkt->offset - p_pkt->len;
+    AVRC_TRACE_DEBUG("len_left:%d, mtu:%d ", len_left, mtu);
+
+    /* get the existing length, if any, and also the num attributes */
+    p_start = (uint8_t *)(p_pkt + 1) + p_pkt->offset;
+    p_data = p_len = p_start + 1; /* pdu */
+
+    /* the existing len */
+    BE_STREAM_TO_UINT16(len, p_data);
+    /* find the position to add the folder depth.
+     * 9 is sizeof (status + uid_counter + num_items + charset_id) */
+    p_folder_depth = p_data + 9;
+    if (len == 0)
+    {
+        /* first time initialize the attribute count */
+        UINT8_TO_BE_STREAM(p_data, p_rsp->status);
+        UINT16_TO_BE_STREAM(p_data, p_rsp->uid_counter);
+        UINT32_TO_BE_STREAM(p_data, p_rsp->num_items);
+        UINT16_TO_BE_STREAM(p_data, p_rsp->charset_id);
+        *p_folder_depth = 0;
+        p_data++;
+        len = 10;
+        /* assuming that we would never use a buffer that is too small for headers */
+        len_left -= 12;
+    }
+    else
+    {
+        p_data = p_start + p_pkt->len;
+    }
+
+    for (uint8_t xx = 0; (xx < p_rsp->folder_depth) && (len_left > (p_folders[xx].str_len + 2)); xx++)
+    {
+        (*p_folder_depth)++;
+        UINT16_TO_BE_STREAM(p_data, p_folders[xx].str_len);
+        ARRAY_TO_BE_STREAM(p_data, p_folders[xx].p_str, p_folders[xx].str_len);
+        len += (p_folders[xx].str_len + 2);
+    }
+    UINT16_TO_BE_STREAM(p_len, len);
+    p_pkt->len = (p_data - p_start);
     return AVRC_STS_NO_ERROR;
 }
 
 /*******************************************************************************
 **
-** Function         avrc_bld_rejected_rsp
+** Function         avrc_bld_get_folder_items_rsp
 **
-** Description      This function builds the General Response response.
+** Description      This function builds the Get Folder Items response.
+**                  The error code is returned in *p_status.
+**                  AVRC_STS_INTERNAL_ERR means no buffers.
+**                  Try again later or with smaller item_count
+**
+**                  This message goes through the Browsing channel and is
+**                  valid only when AVCT_BROWSE_INCLUDED compile option is true
 **
 ** Returns          AVRC_STS_NO_ERROR, if the response is built successfully
+**                  AVRC_STS_INTERNAL_ERR, if the given buffer does not have enough room
+**                  Otherwise, the error code.
 **
 *******************************************************************************/
-static tAVRC_STS avrc_bld_rejected_rsp( tAVRC_RSP *p_rsp, BT_HDR *p_pkt )
+static tAVRC_STS avrc_bld_get_folder_items_rsp (tAVRC_GET_ITEMS_RSP *p_rsp, BT_HDR *p_pkt)
 {
-    AVRC_TRACE_API("%s: status=%d, pdu:x%x", __func__, p_rsp->status, p_rsp->pdu);
+    uint8_t   *p_data, *p_start;
+    uint8_t   *p_len, xx;
+    uint16_t  len;
+    uint16_t  item_len;
+    uint8_t   *p_item_len, yy;
+    tAVRC_ITEM_PLAYER   *p_player;
+    tAVRC_ITEM_FOLDER   *p_folder;
+    tAVRC_ITEM_MEDIA    *p_media;
+    tAVRC_ATTR_ENTRY    *p_attr;
+    tAVRC_ITEM          *p_item_list = p_rsp->p_item_list;
+    tAVRC_STS           status = AVRC_STS_NO_ERROR;
+    uint16_t  len_left;
+    uint8_t   *p_num, *p;
+    uint8_t   *p_item_start, *p_attr_count;
+    uint16_t  item_count;
+    uint16_t  mtu;
+    bool multi_items_add_fail = FALSE;
+    AVRC_TRACE_API("%s", __func__);
 
-    uint8_t *p_start = (uint8_t *)(p_pkt + 1) + p_pkt->offset;
-    uint8_t *p_data = p_start + 2;
-    AVRC_TRACE_DEBUG("%s pdu:x%x", __func__, *p_start);
+    /* make sure the given buffer can accomodate this response */
+    len_left = BT_DEFAULT_BUFFER_SIZE - BT_HDR_SIZE;
+    p = (uint8_t *)(p_pkt + 1);
+    BE_STREAM_TO_UINT16 (mtu, p);
+    if (len_left > mtu)
+        len_left = mtu;
+    len_left = len_left - p_pkt->offset - p_pkt->len;
 
-    UINT16_TO_BE_STREAM(p_data, 1);
+    /* get the existing length, if any, and also the num attributes */
+    p_start = (uint8_t *)(p_pkt + 1) + p_pkt->offset;
+    p_data = p_len = p_start + 1; /* pdu */
+
+    /* the existing len */
+    BE_STREAM_TO_UINT16(len, p_data);
+    p_num = p_data + 3;
+    if (len == 0)
+    {
+        /* first time initialize the attribute count */
+        UINT8_TO_BE_STREAM(p_data, p_rsp->status);
+        UINT16_TO_BE_STREAM(p_data, p_rsp->uid_counter);
+        item_count = 0;
+        p_data += 2;
+        len = 5;
+        len_left -= 5;
+    }
+    else
+    {
+        p_data = p_start + p_pkt->len;
+        p = p_num;
+        BE_STREAM_TO_UINT16 (item_count, p);
+    }
+    AVRC_TRACE_DEBUG("len:%d, len_left:%d, num:%d", len, len_left, item_count);
+
+    /* min len required = item_type(1) + item len(2) + min item (14) = 17 */
+    for (xx = 0; xx < p_rsp->item_count && len_left > 17 && multi_items_add_fail == FALSE; xx++)
+    {
+        p_item_start = p_data;
+        UINT8_TO_BE_STREAM(p_data, p_item_list[xx].item_type);
+        /* variable item lenth - save the location to add length */
+        p_item_len = p_data;
+        p_data += 2;
+        item_len = 0;
+        len_left -= 3; /* item_type(1) + item len(2) */
+        switch (p_item_list[xx].item_type)
+        {
+        case AVRC_ITEM_PLAYER:
+            /* min len required: 2 + 1 + 4 + 1 + 16 + 2 + 2 = 30 + str_len */
+            p_player = &p_item_list[xx].u.player;
+            item_len = AVRC_FEATURE_MASK_SIZE + p_player->name.str_len + 12;
+
+            if ((len_left <= item_len) || AVRC_ITEM_PLAYER_IS_VALID(p_player) == false)
+            {
+                p_data = p_item_start;
+            }
+            else
+            {
+                UINT16_TO_BE_STREAM(p_data, p_player->player_id);
+                UINT8_TO_BE_STREAM(p_data, p_player->major_type);
+                UINT32_TO_BE_STREAM(p_data, p_player->sub_type);
+                UINT8_TO_BE_STREAM(p_data, p_player->play_status);
+                ARRAY_TO_BE_STREAM(p_data, p_player->features, AVRC_FEATURE_MASK_SIZE);
+                UINT16_TO_BE_STREAM(p_data, p_player->name.charset_id);
+                UINT16_TO_BE_STREAM(p_data, p_player->name.str_len);
+                ARRAY_TO_BE_STREAM(p_data, p_player->name.p_str, p_player->name.str_len);
+            }
+            break;
+
+        case AVRC_ITEM_FOLDER:
+            /* min len required: 8 + 1 + 1 + 2 + 2 = 14 + str_len */
+            p_folder = &p_item_list[xx].u.folder;
+            item_len = AVRC_UID_SIZE + p_folder->name.str_len + 6;
+
+            if ((len_left > item_len) &&
+                p_folder->name.p_str &&
+                p_folder->type <= AVRC_FOLDER_TYPE_YEARS)
+            {
+                ARRAY_TO_BE_STREAM(p_data, p_folder->uid, AVRC_UID_SIZE);
+                UINT8_TO_BE_STREAM(p_data, p_folder->type);
+                UINT8_TO_BE_STREAM(p_data, p_folder->playable);
+                UINT16_TO_BE_STREAM(p_data, p_folder->name.charset_id);
+                UINT16_TO_BE_STREAM(p_data, p_folder->name.str_len);
+                ARRAY_TO_BE_STREAM(p_data, p_folder->name.p_str, p_folder->name.str_len);
+            }
+            else
+            {
+                p_data = p_item_start;
+            }
+            break;
+
+        case AVRC_ITEM_MEDIA:
+            /* min len required: 8 + 1 + 2 + 2 + 1 = 14 + str_len */
+            p_media = &p_item_list[xx].u.media;
+            item_len = AVRC_UID_SIZE + p_media->name.str_len + 6;
+
+            if ((len_left >= item_len) &&
+                p_media->name.p_str &&
+                p_media->type <= AVRC_MEDIA_TYPE_VIDEO)
+            {
+                ARRAY_TO_BE_STREAM(p_data, p_media->uid, AVRC_UID_SIZE);
+                UINT8_TO_BE_STREAM(p_data, p_media->type);
+                UINT16_TO_BE_STREAM(p_data, p_media->name.charset_id);
+                UINT16_TO_BE_STREAM(p_data, p_media->name.str_len);
+                ARRAY_TO_BE_STREAM(p_data, p_media->name.p_str, p_media->name.str_len);
+                p_attr_count = p_data++;
+                *p_attr_count = 0;
+                len_left -= item_len;
+                if (p_media->attr_count > 0)
+                {
+                    p_attr = p_media->p_attr_list;
+                    for (yy = 0; yy < p_media->attr_count; yy++)
+                    {
+                        if (p_attr[yy].name.p_str &&
+                            AVRC_IS_VALID_MEDIA_ATTRIBUTE(p_attr[yy].attr_id) &&
+                            (len_left >= (p_attr[yy].name.str_len + 8)) )
+                        {
+                            (*p_attr_count) ++;
+                            UINT32_TO_BE_STREAM(p_data, p_attr[yy].attr_id);
+                            UINT16_TO_BE_STREAM(p_data, p_attr[yy].name.charset_id);
+                            UINT16_TO_BE_STREAM(p_data, p_attr[yy].name.str_len);
+                            ARRAY_TO_BE_STREAM(p_data, p_attr[yy].name.p_str,
+                                p_attr[yy].name.str_len);
+                            item_len += (p_attr[yy].name.str_len + 8);
+                            len_left -= (p_attr[yy].name.str_len + 8);
+                        }
+                        else if ((len_left < (p_attr[yy].name.str_len + 8)) && item_count > 0)
+                        {
+                            p_data = p_item_start;
+                            multi_items_add_fail = TRUE;
+                            break;
+                        }
+                    }
+                }
+            }
+            else
+            {
+                if (len_left < item_len && item_count > 0)
+                    multi_items_add_fail = TRUE;
+                p_data = p_item_start;
+            }
+            break;
+        } /* switch item_type */
+
+        if (p_item_start != p_data)
+        {
+            /* successfully added the item */
+            item_count++;
+            /* fill in variable item lenth */
+            UINT16_TO_BE_STREAM(p_item_len, item_len);
+        }
+        else
+        {
+            if (multi_items_add_fail == FALSE)
+            {
+                /* some item is not added properly - set an error status */
+                if (len_left < item_len)
+                    status = AVRC_STS_INTERNAL_ERR;
+                else
+                    status = AVRC_STS_BAD_PARAM;
+            }
+        }
+        if (multi_items_add_fail == FALSE)
+        {
+            len += item_len;
+            len += 3; /* the item_type(1) and item_len(2) */
+        }
+        AVRC_TRACE_DEBUG("len:%d, len_left:%d, num:%d, item_len:%d",
+            len, len_left, item_count, item_len);
+    } /* for item_count */
+
+    UINT16_TO_BE_STREAM(p_num, item_count);
+    UINT16_TO_BE_STREAM(p_len, len);
+    p_pkt->len = (p_data - p_start);
+
+    if (p_rsp->item_count != xx)
+    {
+        p_rsp->item_count = xx;
+        AVRC_TRACE_DEBUG("xx value = 0x%02X", xx);
+        if (status == AVRC_STS_NO_ERROR)
+            status = AVRC_STS_INTERNAL_ERR;
+    }
+
+    return status;
+}
+
+/*******************************************************************************
+**
+** Function         avrc_bld_change_path_rsp
+**
+** Description      This function builds the Change Path response.
+**
+**                  This message goes through the Browsing channel and is
+**                  valid only when AVCT_BROWSE_INCLUDED compile option is true
+**
+** Returns          AVRC_STS_NO_ERROR, if the response is built successfully
+**                  Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_change_path_rsp (tAVRC_CHG_PATH_RSP *p_rsp, BT_HDR *p_pkt)
+{
+    uint8_t   *p_data, *p_start;
+
+    /* get the existing length, if any, and also the num attributes */
+    p_start = (uint8_t *)(p_pkt + 1) + p_pkt->offset;
+    p_data = p_start + 1; /* pdu */
+    /* add fixed length - status(1) + num_items(4) */
+    UINT16_TO_BE_STREAM(p_data, 5);
     UINT8_TO_BE_STREAM(p_data, p_rsp->status);
-    p_pkt->len = p_data - p_start;
+    UINT32_TO_BE_STREAM(p_data, p_rsp->num_items);
+    p_pkt->len = (p_data - p_start);
+    return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+**
+** Function         avrc_bld_get_item_attrs_rsp
+**
+** Description      This function builds the Get Item Attributes response.
+**
+**                  This message goes through the Browsing channel and is
+**                  valid only when AVCT_BROWSE_INCLUDED compile option is true
+**
+** Returns          AVRC_STS_NO_ERROR, if the response is built successfully
+**                  AVRC_STS_INTERNAL_ERR, if the given buffer does not have enough room
+**                  Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_get_item_attrs_rsp (tAVRC_GET_ATTRS_RSP *p_rsp, BT_HDR *p_pkt)
+{
+    uint8_t   *p_data, *p_start;
+    uint8_t   *p_len;
+    uint16_t  len, len_left;
+    uint8_t   *p_num;
+    uint16_t  mtu;
+
+    AVRC_TRACE_API("%s", __func__);
+    /* calculate the buffer size needed and validate the parameters */
+    if (!p_rsp || !p_rsp->p_attr_list)
+    {
+        AVRC_TRACE_ERROR("NULL p_attr_list");
+        return AVRC_STS_BAD_PARAM;
+    }
+
+    /* check the length before adding the attr to the message */
+    len = 2;
+    for (uint8_t xx = 0; xx < p_rsp->attr_count; xx++)
+    {
+        if(p_rsp->p_attr_list[xx].name.p_str == 0 ||
+            !AVRC_IS_VALID_MEDIA_ATTRIBUTE(p_rsp->p_attr_list[xx].attr_id))
+        {
+            AVRC_TRACE_ERROR("[%d] NULL p_attr_list str or bad attr_id:%d", xx,
+                p_rsp->p_attr_list[xx].attr_id);
+            return AVRC_STS_BAD_PARAM;
+        }
+        len += (p_rsp->p_attr_list[xx].name.str_len + 8);
+    }
+    len_left = BT_DEFAULT_BUFFER_SIZE - BT_HDR_SIZE;
+    p_data = (uint8_t *)(p_pkt + 1);
+    BE_STREAM_TO_UINT16 (mtu, p_data);
+    if (len_left > mtu)
+    {
+        len_left = mtu;
+    }
+    len_left = len_left - p_pkt->offset - p_pkt->len;
+
+    AVRC_TRACE_DEBUG("len_left:%d, mtu:%d len needed:%d", len_left, mtu, len);
+    if (len_left < 11) /* 11 is 4/attr_id + 2/charset_id + 2/str_len + 3/1st timer/attr cnt & len */
+    {
+        return AVRC_STS_INTERNAL_ERR;
+    }
+    if (len > len_left)
+    {
+        AVRC_TRACE_ERROR("The buffer does not have enough room to hold the given data.");
+    }
+
+    /* get the existing length, if any, and also the num attributes */
+    p_start = (uint8_t *)(p_pkt + 1) + p_pkt->offset;
+    p_data = p_len = p_start + 1; /* pdu */
+
+    /* the existing len */
+    BE_STREAM_TO_UINT16(len, p_data);
+    p_num = p_data + 1;
+    if (len == 0)
+    {
+        /* first time initialize the attribute count */
+        UINT8_TO_BE_STREAM(p_data, p_rsp->status);
+        *p_num = 0;
+        p_data++;
+        len = 2;
+        len_left -= 3;
+    }
+    else
+    {
+        p_data = p_start + p_pkt->len;
+    }
+
+
+    for (uint8_t xx = 0; (xx < p_rsp->attr_count) && (len_left > 9); xx++)
+    {
+        (*p_num)++;
+        UINT32_TO_BE_STREAM(p_data, p_rsp->p_attr_list[xx].attr_id);
+        UINT16_TO_BE_STREAM(p_data, p_rsp->p_attr_list[xx].name.charset_id);
+        UINT16_TO_BE_STREAM(p_data, p_rsp->p_attr_list[xx].name.str_len);
+        len_left -= 8;
+        if (p_rsp->p_attr_list[xx].name.str_len > len_left)
+            p_rsp->p_attr_list[xx].name.str_len = len_left;
+        ARRAY_TO_BE_STREAM(p_data, p_rsp->p_attr_list[xx].name.p_str,
+            p_rsp->p_attr_list[xx].name.str_len);
+        len_left -= p_rsp->p_attr_list[xx].name.str_len;
+        len += (p_rsp->p_attr_list[xx].name.str_len + 8);
+    }
+
+    UINT16_TO_BE_STREAM(p_len, len);
+    p_pkt->len = (p_data - p_start);
+    return AVRC_STS_NO_ERROR;
+}
 
+/*******************************************************************************
+**
+** Function         avrc_bld_get_num_of_item_rsp
+**
+** Description      This function builds the Get Total Number of Items response.
+**
+**                  This message goes through the Browsing channel and is
+**                  valid only when AVCT_BROWSE_INCLUDED compile option is true
+**
+** Returns          AVRC_STS_NO_ERROR, if the response is built successfully
+**                  AVRC_STS_INTERNAL_ERR, if the given buffer does not have enough room
+**                  Otherwise, the error code.
+**
+*******************************************************************************/
+#if (AVRC_1_6_INCLUDED == TRUE)
+static tAVRC_STS avrc_bld_get_num_of_item_rsp (tAVRC_GET_NUM_OF_ITEMS_RSP *p_rsp, BT_HDR *p_pkt)
+{
+    uint8_t   *p_data, *p_start, *p_len;
+
+    AVRC_TRACE_API("%s", __func__);
+    /* get the existing length, if any, and also the num attributes */
+    p_start = (uint8_t *)(p_pkt + 1) + p_pkt->offset;
+    p_data = p_len = p_start + 1; /* pdu */
+
+    if (p_rsp->status == AVRC_STS_NO_ERROR)
+    {
+        /* add fixed lenth - status(1) + uid_counter(2) + num_items(4) */
+        UINT16_TO_BE_STREAM(p_data, 7);
+        UINT8_TO_BE_STREAM(p_data, p_rsp->status);
+        UINT16_TO_BE_STREAM(p_data, p_rsp->uid_counter);
+        UINT32_TO_BE_STREAM(p_data, p_rsp->num_items);
+        p_pkt->len = (p_data - p_start);
+        return AVRC_STS_NO_ERROR;
+    }
+    else
+    {
+        /* add fixed lenth - status(1) */
+        UINT16_TO_BE_STREAM(p_data, 7);
+        UINT8_TO_BE_STREAM(p_data, p_rsp->status);
+        p_pkt->len = (p_data - p_start);
+        return p_rsp->status;
+    }
+}
+#endif  /* (AVRC_1_6_INCLUDED == TRUE) */
+
+/*******************************************************************************
+**
+** Function         avrc_bld_search_rsp
+**
+** Description      This function builds the Search response.
+**
+**                  This message goes through the Browsing channel and is
+**                  valid only when AVCT_BROWSE_INCLUDED compile option is true
+**
+** Returns          AVRC_STS_NO_ERROR, if the response is built successfully
+**                  Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_search_rsp (tAVRC_SEARCH_RSP *p_rsp, BT_HDR *p_pkt)
+{
+    uint8_t   *p_data, *p_start, *p_len;
+
+    AVRC_TRACE_API("%s", __func__);
+    /* get the existing length, if any, and also the num attributes */
+    p_start = (uint8_t *)(p_pkt + 1) + p_pkt->offset;
+    p_data = p_len = p_start + 1; /* pdu */
+
+    /* add fixed lenth - status(1) + uid_counter(2) + num_items(4) */
+    UINT16_TO_BE_STREAM(p_data, 7);
+    UINT8_TO_BE_STREAM(p_data, p_rsp->status);
+    UINT16_TO_BE_STREAM(p_data, p_rsp->uid_counter);
+    UINT32_TO_BE_STREAM(p_data, p_rsp->num_items);
+    p_pkt->len = (p_data - p_start);
     return AVRC_STS_NO_ERROR;
 }
 
 /*******************************************************************************
 **
+** Function         avrc_bld_play_item_rsp
+**
+** Description      This function builds the Play Item response.
+**
+** Returns          AVRC_STS_NO_ERROR, if the response is built successfully
+**                  Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_play_item_rsp (tAVRC_RSP *p_rsp, BT_HDR *p_pkt)
+{
+    AVRC_TRACE_API("%s", __func__);
+    return avrc_bld_ctrl_status_rsp(p_rsp, p_pkt);
+}
+
+/*******************************************************************************
+**
+** Function         avrc_bld_add_to_now_playing_rsp
+**
+** Description      This function builds the Add to Now Playing response.
+**
+** Returns          AVRC_STS_NO_ERROR, if the response is built successfully
+**                  Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_add_to_now_playing_rsp (tAVRC_RSP *p_rsp, BT_HDR *p_pkt)
+{
+    AVRC_TRACE_API("%s", __func__);
+    return avrc_bld_ctrl_status_rsp(p_rsp, p_pkt);
+}
+
+/*******************************************************************************
+**
 ** Function         avrc_bld_init_rsp_buffer
 **
 ** Description      This function initializes the response buffer based on PDU
 **
-** Returns          NULL, if no GKI buffer or failure to build the message.
-**                  Otherwise, the GKI buffer that contains the initialized message.
+** Returns          NULL, if no buffer or failure to build the message.
+**                  Otherwise, the buffer that contains the initialized message.
 **
 *******************************************************************************/
 static BT_HDR *avrc_bld_init_rsp_buffer(tAVRC_RESPONSE *p_rsp)
 {
-    uint16_t offset = AVRC_MSG_PASS_THRU_OFFSET;
+    uint16_t offset = 0;
     uint16_t chnl = AVCT_DATA_CTRL;
-    uint8_t opcode = avrc_opcode_from_pdu(p_rsp->pdu);
+    uint8_t  opcode = avrc_opcode_from_pdu(p_rsp->pdu);
 
     AVRC_TRACE_API("%s: pdu=%x, opcode=%x/%x", __func__, p_rsp->pdu, opcode, p_rsp->rsp.opcode);
     if (opcode != p_rsp->rsp.opcode && p_rsp->rsp.status != AVRC_STS_NO_ERROR &&
@@ -825,13 +1399,18 @@ static BT_HDR *avrc_bld_init_rsp_buffer(tAVRC_RESPONSE *p_rsp)
 
     switch (opcode)
     {
-    case AVRC_OP_PASS_THRU:
-        offset = AVRC_MSG_PASS_THRU_OFFSET;
-        break;
+        case AVRC_OP_BROWSE:
+            chnl    = AVCT_DATA_BROWSE;
+            offset  = AVCT_BROWSE_OFFSET;
+            break;
 
-    case AVRC_OP_VENDOR:
-        offset = AVRC_MSG_VENDOR_OFFSET;
-        break;
+        case AVRC_OP_PASS_THRU:
+            offset  = AVRC_MSG_PASS_THRU_OFFSET;
+            break;
+
+        case AVRC_OP_VENDOR:
+            offset  = AVRC_MSG_VENDOR_OFFSET;
+            break;
     }
 
     /* allocate and initialize the buffer */
@@ -853,6 +1432,8 @@ static BT_HDR *avrc_bld_init_rsp_buffer(tAVRC_RESPONSE *p_rsp)
         /* reserved 0, packet_type 0 */
         UINT8_TO_BE_STREAM(p_data, 0);
         /* continue to the next "case to add length */
+
+    case AVRC_OP_BROWSE:
         /* add fixed lenth - 0 */
         UINT16_TO_BE_STREAM(p_data, 0);
         break;
@@ -869,7 +1450,7 @@ static BT_HDR *avrc_bld_init_rsp_buffer(tAVRC_RESPONSE *p_rsp)
 ** Function         AVRC_BldResponse
 **
 ** Description      This function builds the given AVRCP response to the given
-**                  GKI buffer
+**                  buffer
 **
 ** Returns          AVRC_STS_NO_ERROR, if the response is built successfully
 **                  Otherwise, the error code.
@@ -879,8 +1460,9 @@ tAVRC_STS AVRC_BldResponse( uint8_t handle, tAVRC_RESPONSE *p_rsp, BT_HDR **pp_p
 {
     tAVRC_STS status = AVRC_STS_BAD_PARAM;
     BT_HDR *p_pkt;
-    bool    alloc = false;
-    UNUSED(handle);
+    bool alloc = false;
+    uint8_t   *p;
+    uint16_t  peer_mtu;
 
     if (!p_rsp || !pp_pkt)
     {
@@ -896,6 +1478,14 @@ tAVRC_STS AVRC_BldResponse( uint8_t handle, tAVRC_RESPONSE *p_rsp, BT_HDR **pp_p
             AVRC_TRACE_API("%s Failed to initialize response buffer", __func__);
             return AVRC_STS_INTERNAL_ERR;
         }
+
+        if ((*pp_pkt)->layer_specific == AVCT_DATA_BROWSE)
+        {
+            p = (uint8_t *)((*pp_pkt) + 1);
+            peer_mtu = AVCT_GetBrowseMtu(handle) - AVCT_HDR_LEN_SINGLE;
+            UINT16_TO_BE_STREAM(p, peer_mtu);
+        }
+
         alloc = true;
     }
     status = AVRC_STS_NO_ERROR;
@@ -970,17 +1560,46 @@ tAVRC_STS AVRC_BldResponse( uint8_t handle, tAVRC_RESPONSE *p_rsp, BT_HDR **pp_p
         status = avrc_bld_next_rsp(&p_rsp->abort, p_pkt);
         break;
 
-    case AVRC_PDU_SET_ADDRESSED_PLAYER: /*PDU 0x60*/
-        status = avrc_bld_set_address_player_rsp(&p_rsp->addr_player, p_pkt);
+    case AVRC_PDU_SET_ADDRESSED_PLAYER:        /* 0x60 */
+        status = avrc_bld_set_addr_player_rsp(&p_rsp->addr_player, p_pkt);
         break;
 
-    case AVRC_PDU_PLAY_ITEM:
+    case AVRC_PDU_PLAY_ITEM:                   /* 0x74 */
         status = avrc_bld_play_item_rsp(&p_rsp->play_item, p_pkt);
         break;
 
     case AVRC_PDU_SET_ABSOLUTE_VOLUME:
         status = avrc_bld_set_absolute_volume_rsp(p_rsp->volume.volume, p_pkt);
         break;
+
+    case AVRC_PDU_ADD_TO_NOW_PLAYING:          /* 0x90 */
+        status = avrc_bld_add_to_now_playing_rsp(&p_rsp->add_to_play, p_pkt);
+        break;
+
+    case AVRC_PDU_SET_BROWSED_PLAYER:          /* 0x70 */
+        status = avrc_bld_set_browsed_player_rsp(&p_rsp->br_player, p_pkt);
+        break;
+
+    case AVRC_PDU_GET_FOLDER_ITEMS:            /* 0x71 */
+        status = avrc_bld_get_folder_items_rsp(&p_rsp->get_items, p_pkt);
+        break;
+
+    case AVRC_PDU_CHANGE_PATH:                 /* 0x72 */
+        status = avrc_bld_change_path_rsp(&p_rsp->chg_path, p_pkt);
+        break;
+
+    case AVRC_PDU_GET_ITEM_ATTRIBUTES:         /* 0x73 */
+        status = avrc_bld_get_item_attrs_rsp(&p_rsp->get_attrs, p_pkt);
+        break;
+#if (AVRC_1_6_INCLUDED == TRUE)
+    case AVRC_PDU_GET_TOTAL_NUM_OF_ITEMS:      /* 0x75 */
+        status = avrc_bld_get_num_of_item_rsp(&p_rsp->get_num_of_items, p_pkt);
+        break;
+#endif
+
+    case AVRC_PDU_SEARCH:                      /* 0x80 */
+       status = avrc_bld_search_rsp(&p_rsp->search, p_pkt);
+       break;
     }
 
     if (alloc && (status != AVRC_STS_NO_ERROR) )
@@ -992,5 +1611,5 @@ tAVRC_STS AVRC_BldResponse( uint8_t handle, tAVRC_RESPONSE *p_rsp, BT_HDR **pp_p
     return status;
 }
 
-#endif /* (AVRC_METADATA_INCLUDED == TRUE)*/
+#endif /* (AVRC_METADATA_INCLUDED == true)*/
 
index a80e696..2bbe72c 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2003-2012 Broadcom Corporation
+ *  Copyright (C) 2003-2016 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -28,6 +28,9 @@
 
 #include "avct_defs.h"
 #include "avrc_api.h"
+#include "osi/include/alarm.h"
+
+#include "osi/include/fixed_queue.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -96,6 +99,14 @@ extern "C" {
 
 #define AVRC_MAX_CTRL_DATA_LEN      (AVRC_PACKET_LEN)
 
+/* Timeout for waiting for avrc command responses (in milliseconds) */
+#ifndef AVRC_CMD_TOUT_MS
+#define AVRC_CMD_TOUT_MS               (2*1000)
+#endif
+
+/* Flags for avrc_cb.ccb_int[].flags */
+#define AVRC_CB_FLAGS_RSP_PENDING   0x01        /* Waiting for AVRC response */
+
 /*****************************************************************************
 **  Type definitions
 *****************************************************************************/
@@ -118,9 +129,17 @@ typedef struct
 } tAVRC_RASM_CB;
 #endif
 
+/* AVRC internal connection control block */
 typedef struct
 {
-    tAVRC_CONN_CB       ccb[AVCT_NUM_CONN];
+    fixed_queue_t       *cmd_q;          /* Command queue for serializing vendor specific commands */
+    uint8_t               flags;          /* See AVRC_CB_FLAGS_* definitions */
+    alarm_t *           tle;            /* Command timeout timer */
+} tAVRC_CONN_INT_CB;
+
+typedef struct {
+    tAVRC_CONN_CB       ccb[AVCT_NUM_CONN];     /* Connection control block from AVRC_Open API */
+    tAVRC_CONN_INT_CB   ccb_int[AVCT_NUM_CONN]; /* Internal connection control block  */
 #if (AVRC_METADATA_INCLUDED == TRUE)
     tAVRC_FRAG_CB       fcb[AVCT_NUM_CONN];
     tAVRC_RASM_CB       rcb[AVCT_NUM_CONN];
@@ -141,12 +160,15 @@ extern tAVRC_CB *avrc_cb_ptr;
 #define avrc_cb (*avrc_cb_ptr)
 #endif
 
-extern bool    avrc_is_valid_pdu_id(uint8_t pdu_id);
-extern bool    avrc_is_valid_player_attrib_value(uint8_t attrib, uint8_t value);
+extern bool avrc_is_valid_pdu_id(uint8_t pdu_id);
+extern bool avrc_is_valid_player_attrib_value(uint8_t attrib, uint8_t value);
 extern BT_HDR * avrc_alloc_ctrl_pkt (uint8_t pdu);
 extern tAVRC_STS avrc_pars_pass_thru(tAVRC_MSG_PASS *p_msg, uint16_t *p_vendor_unique_id);
 extern uint8_t avrc_opcode_from_pdu(uint8_t pdu);
-extern bool    avrc_is_valid_opcode(uint8_t opcode);
+extern bool avrc_is_valid_opcode(uint8_t opcode);
+extern void avrc_flush_cmd_q(uint8_t handle);
+void avrc_start_cmd_timer(uint8_t handle, uint8_t label, uint8_t msg_mask);
+void avrc_send_next_vendor_cmd (uint8_t handle);
 
 #ifdef __cplusplus
 }
index 5fbf451..737fc62 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2003-2013 Broadcom Corporation
+ *  Copyright (C) 2003-2016 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -123,7 +123,8 @@ static tAVRC_STS avrc_pars_vendor_cmd(tAVRC_MSG_VENDOR *p_msg, tAVRC_COMMAND *p_
     AVRC_TRACE_DEBUG("%s pdu:0x%x", __func__, p_result->pdu);
     if (!AVRC_IsValidAvcType (p_result->pdu, p_msg->hdr.ctype))
     {
-        AVRC_TRACE_DEBUG("%s detects wrong AV/C type!", __func__);
+        AVRC_TRACE_DEBUG("%s detects wrong AV/C type(0x%x)!", __func__,
+                           p_msg->hdr.ctype);
         status = AVRC_STS_BAD_CMD;
     }
 
@@ -131,6 +132,7 @@ static tAVRC_STS avrc_pars_vendor_cmd(tAVRC_MSG_VENDOR *p_msg, tAVRC_COMMAND *p_
     BE_STREAM_TO_UINT16 (len, p);
     if ((len+4) != (p_msg->vendor_len))
     {
+        AVRC_TRACE_ERROR("%s incorrect length :%d, %d", __func__, len, p_msg->vendor_len);
         status = AVRC_STS_INTERNAL_ERR;
     }
 
@@ -195,7 +197,8 @@ static tAVRC_STS avrc_pars_vendor_cmd(tAVRC_MSG_VENDOR *p_msg, tAVRC_COMMAND *p_
             {
                 p_app_set[xx].attr_id = *p++;
                 p_app_set[xx].attr_val = *p++;
-                if (!avrc_is_valid_player_attrib_value(p_app_set[xx].attr_id, p_app_set[xx].attr_val))
+                if (!avrc_is_valid_player_attrib_value(p_app_set[xx].attr_id,
+                    p_app_set[xx].attr_val))
                     status = AVRC_STS_BAD_PARAM;
             }
             if (xx != p_result->set_app_val.num_val)
@@ -321,9 +324,11 @@ static tAVRC_STS avrc_pars_vendor_cmd(tAVRC_MSG_VENDOR *p_msg, tAVRC_COMMAND *p_
         }
         break;
 
-    case AVRC_PDU_SET_ABSOLUTE_VOLUME:
+    case AVRC_PDU_SET_ABSOLUTE_VOLUME:      /* 0x50 */
         if (len != 1)
             status = AVRC_STS_INTERNAL_ERR;
+        else
+            p_result->volume.volume = *p++;
         break;
 
     case AVRC_PDU_REQUEST_CONTINUATION_RSP: /* 0x40 */
@@ -340,6 +345,28 @@ static tAVRC_STS avrc_pars_vendor_cmd(tAVRC_MSG_VENDOR *p_msg, tAVRC_COMMAND *p_
         BE_STREAM_TO_UINT8(p_result->abort.target_pdu, p);
         break;
 
+    case AVRC_PDU_SET_ADDRESSED_PLAYER:     /* 0x60 */
+        if (len != 2)
+        {
+            AVRC_TRACE_ERROR("AVRC_PDU_SET_ADDRESSED_PLAYER length is incorrect:%d",len);
+            status = AVRC_STS_INTERNAL_ERR;
+        }
+        BE_STREAM_TO_UINT16 (p_result->addr_player.player_id, p);
+        break;
+
+    case AVRC_PDU_PLAY_ITEM:                /* 0x74 */
+    case AVRC_PDU_ADD_TO_NOW_PLAYING:       /* 0x90 */
+        if (len != (AVRC_UID_SIZE + 3))
+            status = AVRC_STS_INTERNAL_ERR;
+        BE_STREAM_TO_UINT8 (p_result->play_item.scope, p);
+        if (p_result->play_item.scope > AVRC_SCOPE_NOW_PLAYING)
+        {
+            status = AVRC_STS_BAD_SCOPE;
+        }
+        BE_STREAM_TO_ARRAY (p, p_result->play_item.uid, AVRC_UID_SIZE);
+        BE_STREAM_TO_UINT16 (p_result->play_item.uid_counter, p);
+        break;
+
     default:
         status = AVRC_STS_BAD_CMD;
         break;
@@ -386,6 +413,142 @@ tAVRC_STS AVRC_Ctrl_ParsCommand (tAVRC_MSG *p_msg, tAVRC_COMMAND *p_result)
 
 /*******************************************************************************
 **
+** Function         avrc_pars_browsing_cmd
+**
+** Description      This function parses the commands that go through the
+**                  browsing channel
+**
+** Returns          AVRC_STS_NO_ERROR, if the message in p_data is parsed successfully.
+**                  Otherwise, the error code defined by AVRCP+1
+**
+*******************************************************************************/
+static tAVRC_STS avrc_pars_browsing_cmd(tAVRC_MSG_BROWSE *p_msg, tAVRC_COMMAND *p_result,
+                                                uint8_t *p_buf, uint16_t buf_len)
+{
+    tAVRC_STS  status = AVRC_STS_NO_ERROR;
+    uint8_t   *p = p_msg->p_browse_data;
+    int     count;
+
+    p_result->pdu = *p++;
+    AVRC_TRACE_DEBUG("avrc_pars_browsing_cmd() pdu:0x%x", p_result->pdu);
+    /* skip over len */
+    p += 2;
+
+    switch (p_result->pdu)
+    {
+    case AVRC_PDU_SET_BROWSED_PLAYER:   /* 0x70 */
+        // For current implementation all players are browsable.
+        BE_STREAM_TO_UINT16 (p_result->br_player.player_id, p);
+        break;
+
+    case AVRC_PDU_GET_FOLDER_ITEMS:     /* 0x71 */
+        STREAM_TO_UINT8 (p_result->get_items.scope, p);
+        // To be modified later here (Scope) when all browsing commands are supported
+        if (p_result->get_items.scope > AVRC_SCOPE_NOW_PLAYING)
+        {
+            status = AVRC_STS_BAD_SCOPE;
+        }
+        BE_STREAM_TO_UINT32 (p_result->get_items.start_item, p);
+        BE_STREAM_TO_UINT32 (p_result->get_items.end_item, p);
+        if (p_result->get_items.start_item > p_result->get_items.end_item)
+        {
+            status = AVRC_STS_BAD_RANGE;
+        }
+        STREAM_TO_UINT8 (p_result->get_items.attr_count, p);
+        p_result->get_items.p_attr_list = NULL;
+        if (p_result->get_items.attr_count && p_buf &&
+            (p_result->get_items.attr_count != AVRC_FOLDER_ITEM_COUNT_NONE))
+        {
+            p_result->get_items.p_attr_list = (uint32_t *)p_buf;
+            count = p_result->get_items.attr_count;
+            if (buf_len < (count << 2))
+                p_result->get_items.attr_count = count = (buf_len >> 2);
+            for (int idx = 0; idx < count; idx++)
+            {
+                BE_STREAM_TO_UINT32 (p_result->get_items.p_attr_list[idx], p);
+            }
+        }
+        break;
+
+    case AVRC_PDU_CHANGE_PATH:          /* 0x72 */
+        BE_STREAM_TO_UINT16 (p_result->chg_path.uid_counter, p);
+        BE_STREAM_TO_UINT8 (p_result->chg_path.direction, p);
+        if (p_result->chg_path.direction != AVRC_DIR_UP
+            && p_result->chg_path.direction != AVRC_DIR_DOWN)
+        {
+            status = AVRC_STS_BAD_DIR;
+        }
+        BE_STREAM_TO_ARRAY (p, p_result->chg_path.folder_uid, AVRC_UID_SIZE);
+        break;
+
+    case AVRC_PDU_GET_ITEM_ATTRIBUTES:  /* 0x73 */
+        BE_STREAM_TO_UINT8 (p_result->get_attrs.scope, p);
+        if (p_result->get_attrs.scope > AVRC_SCOPE_NOW_PLAYING)
+        {
+            status = AVRC_STS_BAD_SCOPE;
+            break;
+        }
+        BE_STREAM_TO_ARRAY (p, p_result->get_attrs.uid, AVRC_UID_SIZE);
+        BE_STREAM_TO_UINT16 (p_result->get_attrs.uid_counter, p);
+        BE_STREAM_TO_UINT8 (p_result->get_attrs.attr_count, p);
+        p_result->get_attrs.p_attr_list = NULL;
+        if (p_result->get_attrs.attr_count && p_buf)
+        {
+            p_result->get_attrs.p_attr_list = (uint32_t *)p_buf;
+            count = p_result->get_attrs.attr_count;
+            if (buf_len < (count << 2))
+                p_result->get_attrs.attr_count = count = (buf_len >> 2);
+            for (int idx = 0, count = 0; idx < p_result->get_attrs.attr_count; idx++)
+            {
+                BE_STREAM_TO_UINT32 (p_result->get_attrs.p_attr_list[count], p);
+                if (AVRC_IS_VALID_MEDIA_ATTRIBUTE(p_result->get_attrs.p_attr_list[count]))
+                {
+                    count++;
+                }
+            }
+
+            if (p_result->get_attrs.attr_count != count && count == 0)
+                status = AVRC_STS_BAD_PARAM;
+            else
+                p_result->get_attrs.attr_count = count;
+        }
+        break;
+
+#if (AVRC_1_6_INCLUDED == TRUE)
+    case AVRC_PDU_GET_TOTAL_NUM_OF_ITEMS:   /* 0x75 */
+        BE_STREAM_TO_UINT8 (p_result->get_num_of_items.scope, p);
+        if (p_result->get_num_of_items.scope > AVRC_SCOPE_NOW_PLAYING)
+        {
+            status = AVRC_STS_BAD_SCOPE;
+        }
+        break;
+#endif
+
+    case AVRC_PDU_SEARCH:               /* 0x80 */
+        BE_STREAM_TO_UINT16 (p_result->search.string.charset_id, p);
+        BE_STREAM_TO_UINT16 (p_result->search.string.str_len, p);
+        p_result->search.string.p_str = p_buf;
+        if (p_buf)
+        {
+            if (buf_len > p_result->search.string.str_len)
+                buf_len = p_result->search.string.str_len;
+            BE_STREAM_TO_ARRAY (p, p_buf, p_result->search.string.str_len);
+        }
+        else
+        {
+            status = AVRC_STS_INTERNAL_ERR;
+        }
+        break;
+
+    default:
+        status = AVRC_STS_BAD_CMD;
+        break;
+    }
+    return status;
+}
+
+/*******************************************************************************
+**
 ** Function         AVRC_ParsCommand
 **
 ** Description      This function is a superset of AVRC_ParsMetadata to parse the command.
@@ -394,10 +557,11 @@ tAVRC_STS AVRC_Ctrl_ParsCommand (tAVRC_MSG *p_msg, tAVRC_COMMAND *p_result)
 **                  Otherwise, the error code defined by AVRCP 1.4
 **
 *******************************************************************************/
-tAVRC_STS AVRC_ParsCommand (tAVRC_MSG *p_msg, tAVRC_COMMAND *p_result, uint8_t *p_buf, uint16_t buf_len)
+tAVRC_STS AVRC_ParsCommand (tAVRC_MSG *p_msg, tAVRC_COMMAND *p_result,
+                                     uint8_t *p_buf, uint16_t buf_len)
 {
     tAVRC_STS  status = AVRC_STS_INTERNAL_ERR;
-    uint16_t id;
+    uint16_t  id;
 
     if (p_msg && p_result)
     {
@@ -415,6 +579,10 @@ tAVRC_STS AVRC_ParsCommand (tAVRC_MSG *p_msg, tAVRC_COMMAND *p_result, uint8_t *
             }
             break;
 
+        case AVRC_OP_BROWSE:
+            status = avrc_pars_browsing_cmd(&p_msg->browse, p_result, p_buf, buf_len);
+            break;
+
         default:
             AVRC_TRACE_ERROR("%s unknown opcode:0x%x", __func__, p_msg->hdr.opcode);
             break;
@@ -426,5 +594,5 @@ tAVRC_STS AVRC_ParsCommand (tAVRC_MSG *p_msg, tAVRC_COMMAND *p_result, uint8_t *
     return status;
 }
 
-#endif /* (AVRC_METADATA_INCLUDED == TRUE) */
+#endif /* (AVRC_METADATA_INCLUDED == true) */
 
index 93017e8..b0e1812 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2003-2013 Broadcom Corporation
+ *  Copyright (C) 2003-2016 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
 #include "avrc_api.h"
 #include "avrc_int.h"
 
-#ifndef SDP_AVRCP_1_4
-#define SDP_AVRCP_1_4      true
-#endif
-
-#ifndef SDP_AVCTP_1_4
-#define SDP_AVCTP_1_4      true
-#endif
-
 /*****************************************************************************
 **  Global data
 *****************************************************************************/
@@ -59,7 +51,7 @@ tAVRC_CB avrc_cb;
 ******************************************************************************/
 static void avrc_sdp_cback(uint16_t status)
 {
-    AVRC_TRACE_API("avrc_sdp_cback status: %d", status);
+    AVRC_TRACE_API("%s status: %d", __func__, status);
 
     /* reset service_uuid, so can start another find service */
     avrc_cb.service_uuid = 0;
@@ -119,7 +111,7 @@ uint16_t AVRC_FindService(uint16_t service_uuid, BD_ADDR bd_addr,
                                    ATTR_ID_SUPPORTED_FEATURES,
                                    ATTR_ID_PROVIDER_NAME};
 
-    AVRC_TRACE_API("AVRC_FindService uuid: %x", service_uuid);
+    AVRC_TRACE_API("%s uuid: %x", __func__, service_uuid);
     if( (service_uuid != UUID_SERVCLASS_AV_REM_CTRL_TARGET && service_uuid != UUID_SERVCLASS_AV_REMOTE_CONTROL) ||
         p_db == NULL || p_db->p_db == NULL || p_cback == NULL)
         return AVRC_BAD_PARAM;
@@ -204,7 +196,7 @@ uint16_t AVRC_AddRecord(uint16_t service_uuid, char *p_service_name,
     uint16_t    class_list[2];
 
 
-    AVRC_TRACE_API("AVRC_AddRecord uuid: %x", service_uuid);
+    AVRC_TRACE_API("%s uuid: %x", __func__, service_uuid);
 
     if( service_uuid != UUID_SERVCLASS_AV_REM_CTRL_TARGET && service_uuid != UUID_SERVCLASS_AV_REMOTE_CONTROL )
         return AVRC_BAD_PARAM;
index 7d1d98b..352df47 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2003-2013 Broadcom Corporation
+ *  Copyright (C) 2003-2016 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -34,9 +34,9 @@
 **
 **
 *******************************************************************************/
-bool    AVRC_IsValidAvcType(uint8_t pdu_id, uint8_t avc_type)
+bool AVRC_IsValidAvcType(uint8_t pdu_id, uint8_t avc_type)
 {
-    bool    result=false;
+    bool result=false;
 
     if (avc_type < AVRC_RSP_NOT_IMPL) /* command msg */
     {
@@ -59,9 +59,18 @@ bool    AVRC_IsValidAvcType(uint8_t pdu_id, uint8_t avc_type)
         case AVRC_PDU_INFORM_BATTERY_STAT_OF_CT:   /* 0x18 */
         case AVRC_PDU_REQUEST_CONTINUATION_RSP:    /* 0x40 */
         case AVRC_PDU_ABORT_CONTINUATION_RSP:      /* 0x41 */
-        case AVRC_PDU_SET_ADDRESSED_PLAYER:
-        case AVRC_PDU_PLAY_ITEM:
-        case AVRC_PDU_SET_ABSOLUTE_VOLUME:
+             if (avc_type == AVRC_CMD_CTRL)
+                result=true;
+             break;
+
+        case AVRC_PDU_GET_FOLDER_ITEMS:            /* 0x71 */
+            result = true;
+            break;
+
+        case AVRC_PDU_SET_ABSOLUTE_VOLUME:         /* 0x50 */
+        case AVRC_PDU_SET_ADDRESSED_PLAYER:        /* 0x60 */
+        case AVRC_PDU_PLAY_ITEM:                   /* 0x74 */
+        case AVRC_PDU_ADD_TO_NOW_PLAYING:          /* 0x90 */
              if (avc_type == AVRC_CMD_CTRL)
                 result=true;
              break;
@@ -121,10 +130,10 @@ bool    avrc_is_valid_player_attrib_value(uint8_t attrib, uint8_t value)
        result = true;
 
     if (!result)
-        AVRC_TRACE_ERROR(
-            "avrc_is_valid_player_attrib_value() found not matching attrib(x%x)-value(x%x) pair!",
-            attrib, value);
-
+    {
+        AVRC_TRACE_ERROR(" %s found not matching attrib(x%x)-value(x%x) pair!",
+                          __FUNCTION__, attrib, value);
+    }
     return result;
 }
 
@@ -202,6 +211,18 @@ uint8_t avrc_opcode_from_pdu(uint8_t pdu)
 
     switch (pdu)
     {
+    case AVRC_PDU_SET_BROWSED_PLAYER:
+    case AVRC_PDU_GET_FOLDER_ITEMS:
+    case AVRC_PDU_CHANGE_PATH:
+    case AVRC_PDU_GET_ITEM_ATTRIBUTES:
+    case AVRC_PDU_SEARCH:
+    case AVRC_PDU_GENERAL_REJECT:
+#if (AVRC_1_6_INCLUDED == TRUE)
+    case AVRC_PDU_GET_TOTAL_NUM_OF_ITEMS:
+#endif
+        opcode  = AVRC_OP_BROWSE;
+        break;
+
     case AVRC_PDU_NEXT_GROUP:
     case AVRC_PDU_PREV_GROUP: /* pass thru */
         opcode  = AVRC_OP_PASS_THRU;
index 8ef3f47..ff2a8ca 100644 (file)
@@ -172,6 +172,11 @@ typedef struct
     uint8_t             control;        /* Control role (Control/Target) */
 } tAVRC_CONN_CB;
 
+typedef struct {
+    uint8_t handle;
+    uint8_t label;
+    uint8_t msg_mask;
+} tAVRC_PARAM;
 
 
 /*****************************************************************************
index 86b1941..018eaac 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2006-2012 Broadcom Corporation
+ *  Copyright (C) 2006-2016 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -34,6 +34,8 @@
 #define AVRC_REV_1_0        0x0100
 #define AVRC_REV_1_3        0x0103
 #define AVRC_REV_1_4        0x0104
+#define AVRC_REV_1_5        0x0105
+#define AVRC_REV_1_6        0x0106
 
 #define AVRC_PACKET_LEN             512 /* Per the spec, you must support 512 byte RC packets */
 
 #define AVRC_CO_BLUETOOTH_SIG   0x00FFFFFF
 #define AVRC_CO_WIDCOMM         0x00000361
 #define AVRC_CO_BROADCOM        0x00001018
+#define AVRC_CO_GOOGLE          0x00DAA119
 #define AVRC_CO_METADATA        0x00001958  /* Unique COMPANY ID for Metadata messages */
 
 /* State flag for Passthrough commands
 #define AVRC_PDU_CHANGE_PATH                    0x72
 #define AVRC_PDU_GET_ITEM_ATTRIBUTES            0x73
 #define AVRC_PDU_PLAY_ITEM                      0x74
+#define AVRC_PDU_GET_TOTAL_NUM_OF_ITEMS         0x75        /* Added in post 1.5 */
 #define AVRC_PDU_SEARCH                         0x80
 #define AVRC_PDU_ADD_TO_NOW_PLAYING             0x90
 #define AVRC_PDU_GENERAL_REJECT                 0xA0
@@ -748,6 +752,12 @@ typedef uint8_t tAVRC_UID[AVRC_UID_SIZE];
 #define AVRC_PF_UID_PERSIST_OFF         8
 #define AVRC_PF_UID_PERSIST_SUPPORTED(x) ((x)[AVRC_PF_UID_PERSIST_OFF] & AVRC_PF_UID_PERSIST_MASK)
 
+/* NumberOfItems. This bit is set if player supports the GetTotalNumberOfItems browsing command. */
+#define AVRC_PF_GET_NUM_OF_ITEMS_BIT_NO    67
+#define AVRC_PF_GET_NUM_OF_ITEMS_MASK      0x08
+#define AVRC_PF_GET_NUM_OF_ITEMS_OFF       8
+#define AVRC_PF_GET_NUM_OF_ITEMS_SUPPORTED(x) ((x)[AVRC_PF_GET_NUM_OF_ITEMS_OFF] & AVRC_PF_GET_NUM_OF_ITEMS_MASK)
+
 /*****************************************************************************
 **  data type definitions
 *****************************************************************************/
@@ -1152,6 +1162,15 @@ typedef struct
     uint16_t    uid_counter;
 } tAVRC_ADD_TO_PLAY_CMD;
 
+/* GetTotalNumOfItems */
+typedef struct
+{
+    uint8_t       pdu;
+    tAVRC_STS   status;
+    uint8_t       opcode;         /* Op Code (assigned by AVRC_BldCommand according to pdu) */
+    uint8_t       scope;
+} tAVRC_GET_NUM_OF_ITEMS_CMD;
+
 typedef struct
 {
     uint8_t     pdu;
@@ -1196,6 +1215,7 @@ typedef union
     tAVRC_SEARCH_CMD            search;                 /* Search */
     tAVRC_PLAY_ITEM_CMD         play_item;              /* PlayItem */
     tAVRC_ADD_TO_PLAY_CMD       add_to_play;            /* AddToNowPlaying */
+    tAVRC_GET_NUM_OF_ITEMS_CMD  get_num_of_items;       /* GetTotalNumOfItems */
 } tAVRC_COMMAND;
 
 /* GetCapability */
@@ -1364,6 +1384,16 @@ typedef struct
     tAVRC_ATTR_ENTRY    *p_attr_list;
 } tAVRC_GET_ATTRS_RSP;
 
+/* Get Total Number of Items */
+typedef struct
+{
+    uint8_t               pdu;
+    tAVRC_STS           status;
+    uint8_t               opcode;         /* Op Code (copied from avrc_cmd.opcode by AVRC_BldResponse user. invalid one to generate according to pdu) */
+    uint16_t              uid_counter;
+    uint32_t              num_items;
+} tAVRC_GET_NUM_OF_ITEMS_RSP;
+
 /* Search */
 typedef struct
 {
@@ -1414,6 +1444,7 @@ typedef union
     tAVRC_GET_ITEMS_RSP             get_items;              /* GetFolderItems */
     tAVRC_CHG_PATH_RSP              chg_path;               /* ChangePath */
     tAVRC_GET_ATTRS_RSP             get_attrs;              /* GetItemAttrs */
+    tAVRC_GET_NUM_OF_ITEMS_RSP      get_num_of_items;       /* GetTotalNumberOfItems */
     tAVRC_SEARCH_RSP                search;                 /* Search */
     tAVRC_RSP                       play_item;              /* PlayItem */
     tAVRC_RSP                       add_to_play;            /* AddToNowPlaying */