OSDN Git Service

Implement AVRCP Controller (Client) Browsing.
authorSanket Agarwal <sanketa@google.com>
Wed, 11 May 2016 19:30:49 +0000 (12:30 -0700)
committerPavlin Radoslavov <pavlin@google.com>
Mon, 17 Oct 2016 19:06:06 +0000 (12:06 -0700)
Following is included as part of the features:
a) Browsing for all 4 scopes (Media, VFS, Player and Now Playing)
b) Player selection and song selection from browse list.

The change constructs the following (from lower to upper protocol
layers):
1. AVCTP Browse (bta/ & stack/)
                -- Connection Handling
                -- Constructing browse commands
                -- Parsing browse responses
2. AVRCP  (btif/)
                -- JNI interaction/API
                -- Connection handling to Java
                -- Delegating request and responses to Java

Bug: 28791287
Change-Id: Ibc97ded93cb9c469778ea1e37733390d561cd4cd
(cherry picked from commit 9ea8d07c9286a1f4d338dd64ee02266e324d28e5)

14 files changed:
bta/av/bta_av_act.cc
bta/av/bta_av_cfg.cc
bta/av/bta_av_main.cc
bta/include/bta_av_api.h
btif/src/btif_av.cc
btif/src/btif_rc.cc
include/bt_target.h
stack/avct/avct_api.c
stack/avct/avct_bcb_act.c
stack/avct/avct_l2c_br.c
stack/avrc/avrc_bld_ct.c
stack/avrc/avrc_int.h
stack/avrc/avrc_pars_ct.c
stack/include/avrc_defs.h

index 38b683a..66d281b 100644 (file)
@@ -535,13 +535,12 @@ 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);
-    }
+    APPL_TRACE_DEBUG("%s local features %d peer features %d",
+                     __func__, p_cb->features, p_cb->rcb[i].peer_features);
+
+    /* listen to browsing channel when the connection is open,
+     * if peer initiated AVRCP connection and local device supports browsing channel */
+    AVRC_OpenBrowse (p_data->rc_conn_chg.handle, AVCT_ACP);
 
     if (p_cb->rcb[i].lidx == (BTA_AV_NUM_LINKS + 1) && shdl != 0)
     {
@@ -588,7 +587,7 @@ void bta_av_rc_opened(tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data)
     bdcpy(rc_open.peer_addr, p_data->rc_conn_chg.peer_addr);
     rc_open.peer_features = p_cb->rcb[i].peer_features;
     rc_open.status = BTA_AV_SUCCESS;
-    APPL_TRACE_DEBUG("local features:x%x peer_features:x%x", p_cb->features,
+    APPL_TRACE_DEBUG("%s local features:x%x peer_features:x%x", __func__, p_cb->features,
                       rc_open.peer_features);
     if (rc_open.peer_features == 0)
     {
@@ -604,14 +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 */
+     * browsing channel, open the browsing channel now
+     * TODO (sanketa): Some TG would not broadcast browse feature hence check inter-op. */
     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))
     {
+        APPL_TRACE_DEBUG("%s opening AVRC Browse channel", __func__);
         AVRC_OpenBrowse (p_data->rc_conn_chg.handle, AVCT_INT);
     }
-
 }
 
 /*******************************************************************************
@@ -1143,6 +1143,20 @@ void bta_av_rc_close (tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data)
 
 /*******************************************************************************
 **
+** Function         bta_av_rc_browse_close
+**
+** Description      Empty placeholder.
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_av_rc_browse_close (tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data)
+{
+    APPL_TRACE_WARNING("%s empty placeholder does nothing!", __func__);
+}
+
+/*******************************************************************************
+**
 ** Function         bta_av_get_shdl
 **
 ** Returns          The index to p_scb[]
@@ -1473,8 +1487,11 @@ void bta_av_disable(tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data)
      * expect BTA_AV_DEREG_COMP_EVT when deregister is complete */
     for(xx=0; xx<BTA_AV_NUM_STRS; xx++)
     {
-        hdr.layer_specific = xx + 1;
-        bta_av_api_deregister((tBTA_AV_DATA *)&hdr);
+        if (p_cb->p_scb[xx] != NULL)
+        {
+            hdr.layer_specific = xx + 1;
+            bta_av_api_deregister((tBTA_AV_DATA *)&hdr);
+        }
     }
 
     alarm_free(p_cb->link_signalling_timer);
@@ -1855,7 +1872,7 @@ tBTA_AV_FEAT bta_avk_check_peer_features (uint16_t service_uuid)
              */
             if (peer_rc_version >= AVRC_REV_1_3)
             {
-                /* get supported categories */
+                /* get supported features */
                 tSDP_DISC_ATTR *p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_SUPPORTED_FEATURES);
                 if (p_attr != NULL)
                 {
@@ -1864,6 +1881,8 @@ tBTA_AV_FEAT bta_avk_check_peer_features (uint16_t service_uuid)
                         peer_features |= (BTA_AV_FEAT_ADV_CTRL);
                     if (categories & AVRC_SUPF_CT_APP_SETTINGS)
                         peer_features |= (BTA_AV_FEAT_APP_SETTING);
+                    if (categories & AVRC_SUPF_CT_BROWSE)
+                        peer_features |= (BTA_AV_FEAT_BROWSE);
                 }
             }
         }
@@ -1930,6 +1949,7 @@ void bta_av_rc_disc_done(tBTA_AV_DATA *p_data)
     {
         /* This is Sink + CT + TG(Abs Vol) */
         peer_features = bta_avk_check_peer_features(UUID_SERVCLASS_AV_REM_CTRL_TARGET);
+        APPL_TRACE_DEBUG("%s populating rem ctrl target features %d", __func__, peer_features);
         if (BTA_AV_FEAT_ADV_CTRL & bta_avk_check_peer_features(UUID_SERVCLASS_AV_REMOTE_CONTROL))
             peer_features |= (BTA_AV_FEAT_ADV_CTRL|BTA_AV_FEAT_RCCT);
     }
index 3113592..34f8363 100644 (file)
@@ -124,10 +124,11 @@ const tBTA_AV_CFG bta_av_cfg =
     BTA_AV_RC_COMP_ID,      /* AVRCP Company ID */
 #if (AVRC_METADATA_INCLUDED == TRUE)
     512,                    /* AVRCP MTU at L2CAP for control channel */
+    BTA_AV_MAX_RC_BR_MTU,   /* AVRCP MTU at L2CAP for browsing channel */
 #else
     48,                     /* AVRCP MTU at L2CAP for control channel */
-#endif
     BTA_AV_MAX_RC_BR_MTU,   /* AVRCP MTU at L2CAP for browsing channel */
+#endif
     BTA_AV_RC_SUPF_CT,      /* AVRCP controller categories */
     BTA_AV_RC_SUPF_TG,      /* AVRCP target categories */
     672,                    /* AVDTP signaling channel MTU at L2CAP */
index 997be12..9dd7c29 100644 (file)
@@ -82,6 +82,7 @@ enum
     BTA_AV_RC_META_RSP,
     BTA_AV_RC_MSG,
     BTA_AV_RC_CLOSE,
+    BTA_AV_RC_BROWSE_CLOSE,
     BTA_AV_NUM_ACTIONS
 };
 
@@ -103,7 +104,6 @@ const tBTA_AV_ACTION bta_av_action[] =
     bta_av_rc_meta_rsp,
     bta_av_rc_msg,
     bta_av_rc_close,
-    NULL
 };
 
 /* state table information */
@@ -114,31 +114,31 @@ const tBTA_AV_ACTION bta_av_action[] =
 /* state table for init state */
 static const uint8_t bta_av_st_init[][BTA_AV_NUM_COLS] =
 {
-/* Event                     Action 1               Next state */
-/* API_DISABLE_EVT */       {BTA_AV_DISABLE,        BTA_AV_INIT_ST },
-/* API_REMOTE_CMD_EVT */    {BTA_AV_IGNORE,         BTA_AV_INIT_ST },
-/* API_VENDOR_CMD_EVT */    {BTA_AV_IGNORE,         BTA_AV_INIT_ST },
-/* API_VENDOR_RSP_EVT */    {BTA_AV_IGNORE,         BTA_AV_INIT_ST },
-/* 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_BROWSE_MSG, BTA_AV_INIT_ST },
-/* AVRC_NONE_EVT */         {BTA_AV_IGNORE,         BTA_AV_INIT_ST },
+/* Event                     Action 1                   Next state */
+/* API_DISABLE_EVT */       {BTA_AV_DISABLE,            BTA_AV_INIT_ST },
+/* API_REMOTE_CMD_EVT */    {BTA_AV_IGNORE,             BTA_AV_INIT_ST },
+/* API_VENDOR_CMD_EVT */    {BTA_AV_IGNORE,             BTA_AV_INIT_ST },
+/* API_VENDOR_RSP_EVT */    {BTA_AV_IGNORE,             BTA_AV_INIT_ST },
+/* 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_BROWSE_MSG, BTA_AV_INIT_ST },
+/* AVRC_NONE_EVT */         {BTA_AV_IGNORE,             BTA_AV_INIT_ST },
 };
 
 /* state table for open state */
 static const uint8_t bta_av_st_open[][BTA_AV_NUM_COLS] =
 {
-/* Event                     Action 1               Next state */
-/* API_DISABLE_EVT */       {BTA_AV_DISABLE,        BTA_AV_INIT_ST },
-/* API_REMOTE_CMD_EVT */    {BTA_AV_RC_REMOTE_CMD,  BTA_AV_OPEN_ST },
-/* API_VENDOR_CMD_EVT */    {BTA_AV_RC_VENDOR_CMD,  BTA_AV_OPEN_ST },
-/* API_VENDOR_RSP_EVT */    {BTA_AV_RC_VENDOR_RSP,  BTA_AV_OPEN_ST },
-/* API_META_RSP_EVT */      {BTA_AV_RC_META_RSP,    BTA_AV_OPEN_ST },
-/* API_RC_CLOSE_EVT */      {BTA_AV_RC_CLOSE,       BTA_AV_OPEN_ST },
-/* AVRC_OPEN_EVT */         {BTA_AV_RC_OPENED,      BTA_AV_OPEN_ST },
-/* AVRC_MSG_EVT */          {BTA_AV_RC_MSG,         BTA_AV_OPEN_ST },
-/* AVRC_NONE_EVT */         {BTA_AV_IGNORE,         BTA_AV_INIT_ST },
+/* Event                     Action 1                   Next state */
+/* API_DISABLE_EVT */       {BTA_AV_DISABLE,            BTA_AV_INIT_ST },
+/* API_REMOTE_CMD_EVT */    {BTA_AV_RC_REMOTE_CMD,      BTA_AV_OPEN_ST },
+/* API_VENDOR_CMD_EVT */    {BTA_AV_RC_VENDOR_CMD,      BTA_AV_OPEN_ST },
+/* API_VENDOR_RSP_EVT */    {BTA_AV_RC_VENDOR_RSP,      BTA_AV_OPEN_ST },
+/* API_META_RSP_EVT */      {BTA_AV_RC_META_RSP,        BTA_AV_OPEN_ST },
+/* API_RC_CLOSE_EVT */      {BTA_AV_RC_CLOSE,           BTA_AV_OPEN_ST },
+/* AVRC_OPEN_EVT */         {BTA_AV_RC_OPENED,          BTA_AV_OPEN_ST },
+/* AVRC_MSG_EVT */          {BTA_AV_RC_MSG,             BTA_AV_OPEN_ST },
+/* AVRC_NONE_EVT */         {BTA_AV_IGNORE,             BTA_AV_INIT_ST },
 };
 
 /* type for state table */
@@ -503,6 +503,12 @@ 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
+
+                /* Both Audio Source and Audio Sink support AVRCP 1.6 for the
+                 * major roles (i.e. Audio Source -> TG 1.6 and vice versa). For
+                 * Audio Sink role we support additional TG 1.3 to support
+                 * absolute volume. Here we only do TG registration.
+                 */
                 uint16_t profile_version = AVRC_REV_1_0;
                 if (profile_initialized == UUID_SERVCLASS_AUDIO_SOURCE)
                 {
@@ -659,14 +665,21 @@ static void bta_av_api_register(tBTA_AV_DATA *p_data)
                     /* create an SDP record as AVRC CT. We create 1.3 for SOURCE
                      * because we rely on feature bits being scanned by external
                      * devices more than the profile version itself.
+                     *
+                     * We create 1.4 for SINK since we support browsing.
                      */
-                    if ((profile_initialized == UUID_SERVCLASS_AUDIO_SOURCE) ||
-                        (profile_initialized == UUID_SERVCLASS_AUDIO_SINK))
+                    if (profile_initialized == UUID_SERVCLASS_AUDIO_SOURCE)
                     {
                         bta_ar_reg_avrc(UUID_SERVCLASS_AV_REMOTE_CONTROL, NULL, NULL,
                         p_bta_av_cfg->avrc_ct_cat, BTA_ID_AV,
                         (bta_av_cb.features & BTA_AV_FEAT_BROWSE), AVRC_REV_1_3);
                     }
+                    else if (profile_initialized == UUID_SERVCLASS_AUDIO_SINK)
+                    {
+                        bta_ar_reg_avrc(UUID_SERVCLASS_AV_REMOTE_CONTROL, NULL, NULL,
+                        p_bta_av_cfg->avrc_ct_cat, BTA_ID_AV,
+                        (bta_av_cb.features & BTA_AV_FEAT_BROWSE), AVRC_REV_1_4);
+                    }
 #endif
                 }
             }
@@ -1191,11 +1204,12 @@ void bta_av_sm_execute(tBTA_AV_CB *p_cb, uint16_t event, tBTA_AV_DATA *p_data)
 
     /* set next state */
     p_cb->state = state_table[event][BTA_AV_NEXT_STATE];
-    APPL_TRACE_EVENT("next state=%d", p_cb->state);
+    APPL_TRACE_EVENT("next state=%d event offset:%d", p_cb->state, event);
 
     /* execute action functions */
     if ((action = state_table[event][BTA_AV_ACTION_COL]) != BTA_AV_IGNORE)
     {
+        APPL_TRACE_EVENT("%s action executed %d", __func__, action);
         (*bta_av_action[action])(p_cb, p_data);
     }
 }
index f652621..35fb4c7 100644 (file)
@@ -197,39 +197,37 @@ typedef uint8_t tBTA_AV_CODE;
 
 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_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 */
+#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 codec */
+#define BTA_AV_SINK_MEDIA_DATA_EVT     21      /* sending data to Media Task */
+#define BTA_AV_OFFLOAD_START_RSP_EVT   22      /* a2dp offload start response */
+#define BTA_AV_RC_BROWSE_OPEN_EVT      23      /* remote control channel open */
+#define BTA_AV_RC_BROWSE_CLOSE_EVT     24      /* remote control channel closed */
 /* Max BTA event */
-#define BTA_AV_MAX_EVT               25
-
+#define BTA_AV_MAX_EVT                 25
 
 typedef uint8_t tBTA_AV_EVT;
 
index 13c50a2..297f96f 100644 (file)
@@ -116,8 +116,8 @@ else\
 /* Helper macro to avoid code duplication in the state machine handlers */
 #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_CLOSE_EVT: \
     case BTA_AV_RC_BROWSE_CLOSE_EVT: \
     case BTA_AV_REMOTE_CMD_EVT: \
     case BTA_AV_VENDOR_CMD_EVT: \
@@ -1074,12 +1074,12 @@ static void btif_av_handle_event(uint16_t event, char* p_param)
 
 void btif_av_event_deep_copy(uint16_t event, char *p_dest, char *p_src)
 {
+    BTIF_TRACE_DEBUG("%s", __func__);
     tBTA_AV *av_src = (tBTA_AV *)p_src;
     tBTA_AV *av_dest = (tBTA_AV *)p_dest;
 
     // First copy the structure
     maybe_non_aligned_memcpy(av_dest, av_src, sizeof(*av_src));
-
     switch (event)
     {
         case BTA_AV_META_MSG_EVT:
@@ -1594,7 +1594,7 @@ bt_status_t btif_av_sink_execute_service(bool b_enable)
           * be initiated by the app/audioflinger layers */
          BTA_AvEnable(BTA_SEC_AUTHENTICATE, BTA_AV_FEAT_NO_SCO_SSPD|BTA_AV_FEAT_RCCT|
                                             BTA_AV_FEAT_METADATA|BTA_AV_FEAT_VENDOR|
-                                            BTA_AV_FEAT_ADV_CTRL|BTA_AV_FEAT_RCTG,
+                                            BTA_AV_FEAT_ADV_CTRL|BTA_AV_FEAT_RCTG|BTA_AV_FEAT_BROWSE,
                                                                         bte_av_callback);
          BTA_AvRegister(BTA_AV_CHNL_AUDIO, BTIF_AVK_SERVICE_NAME, 0,
                         bte_av_sink_media_callback, UUID_SERVCLASS_AUDIO_SINK);
index e3b6314..d287fe1 100644 (file)
@@ -97,6 +97,16 @@ do { \
     } \
 } while (0)
 
+#define CHECK_BR_CONNECTED(p_dev) \
+do { \
+    BTIF_TRACE_DEBUG("## %s ##", __FUNCTION__);                                            \
+    if (p_dev == NULL || p_dev->br_connected == false) \
+    { \
+        BTIF_TRACE_WARNING("Function %s() called when BR is not connected", __FUNCTION__); \
+        return BT_STATUS_NOT_READY;                                                         \
+    } \
+} while (0)
+
 /*****************************************************************************
 **  Local type definitions
 ******************************************************************************/
@@ -165,6 +175,7 @@ typedef struct {
 /* TODO : Merge btif_rc_reg_notifications_t and btif_rc_cmd_ctxt_t to a single struct */
 typedef struct {
     bool                           rc_connected;
+    bool                           br_connected;  // Browsing channel.
     uint8_t                        rc_handle;
     tBTA_AV_FEAT                   rc_features;
     btrc_connection_state_t        rc_state;
@@ -284,6 +295,7 @@ 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, 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);
@@ -324,10 +336,16 @@ 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);
+void get_folder_item_type_media(const tAVRC_ITEM *avrc_item, btrc_folder_items_t *btrc_item);
+void get_folder_item_type_folder(const tAVRC_ITEM *avrc_item, btrc_folder_items_t *btrc_item);
+void get_folder_item_type_player(const tAVRC_ITEM *avrc_item, btrc_folder_items_t *btrc_item);
+static bt_status_t get_folder_items_cmd(bt_bdaddr_t *bd_addr, uint8_t scope, uint8_t start_item,
+                                        uint8_t num_items);
 #endif
 
 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, btif_rc_device_cb_t *p_dev);
@@ -583,9 +601,14 @@ void handle_rc_ctrl_features(btif_rc_device_cb_t *p_dev)
         if (btif_av_is_sink_enabled())
             getcapabilities_cmd (AVRC_CAP_COMPANY_ID, p_dev);
     }
+
+    /* Add browsing feature capability */
+    if (p_dev->rc_features & BTA_AV_FEAT_BROWSE) {
+        rc_features |= BTRC_FEAT_BROWSE;
+    }
+
     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
 
@@ -673,6 +696,37 @@ void handle_rc_features(btif_rc_device_cb_t *p_dev)
 /***************************************************************************
  *  Function       handle_rc_connect
  *
+ *  - Argument:    tBTA_AV_RC_OPEN  browse RC open data structure
+ *
+ *  - Description: browse RC connection event handler
+ *
+ ***************************************************************************/
+void handle_rc_browse_connect(tBTA_AV_RC_OPEN *p_rc_open) {
+    BTIF_TRACE_DEBUG("%s rc_handle %d status %d",
+                     __func__, p_rc_open->rc_handle, p_rc_open->status);
+#if (AVRC_CTRL_INCLUDED == TRUE)
+    btif_rc_device_cb_t *p_dev = btif_rc_get_device_by_handle(p_rc_open->rc_handle);
+
+    if (!p_dev) {
+        BTIF_TRACE_ERROR("%s p_dev is null", __func__);
+        return;
+    }
+
+    /* check that we are already connected to this address since being connected
+     * to a browse when not connected to the control channel over AVRCP is
+     * probably not preferred anyways. */
+    if (p_rc_open->status == BTA_AV_SUCCESS) {
+        bt_bdaddr_t rc_addr;
+        bdcpy(rc_addr.address, p_dev->rc_addr);
+        p_dev->br_connected = true;
+        HAL_CBACK(bt_rc_ctrl_callbacks, connection_state_cb, true, true, &rc_addr);
+    }
+#endif
+}
+
+/***************************************************************************
+ *  Function       handle_rc_connect
+ *
  *  - Argument:    tBTA_AV_RC_OPEN  RC open data structure
  *
  *  - Description: RC connection event handler
@@ -746,7 +800,7 @@ void handle_rc_connect (tBTA_AV_RC_OPEN *p_rc_open)
     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);
+        HAL_CBACK(bt_rc_ctrl_callbacks, connection_state_cb, true, false, &rc_addr);
     }
     /* report connection state if remote device is AVRCP target */
     handle_rc_ctrl_features(p_dev);
@@ -827,7 +881,7 @@ void handle_rc_disconnect (tBTA_AV_RC_CLOSE *p_rc_close)
     /* report connection state if device is AVRCP target */
     if (bt_rc_ctrl_callbacks != NULL)
    {
-        HAL_CBACK(bt_rc_ctrl_callbacks, connection_state_cb, false, &rc_addr);
+        HAL_CBACK(bt_rc_ctrl_callbacks, connection_state_cb, false, false, &rc_addr);
    }
 #endif
 }
@@ -950,8 +1004,8 @@ void handle_rc_passthrough_rsp ( tBTA_AV_REMOTE_RSP *p_remote_rsp)
 
         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, \
-                &rc_addr);
+            HAL_CBACK(bt_rc_ctrl_callbacks, passthrough_rsp_cb, &rc_addr,
+                      p_remote_rsp->rc_id, key_state);
         }
     }
     else
@@ -1176,14 +1230,16 @@ void btif_rc_handler(tBTA_AV_EVT event, tBTA_AV *p_data)
             handle_rc_connect( &(p_data->rc_open) );
         }break;
 
-        case BTA_AV_RC_CLOSE_EVT:
+        case BTA_AV_RC_BROWSE_OPEN_EVT:
         {
-            handle_rc_disconnect(&(p_data->rc_close));
+            /* tell the UL that we have connection to browse channel and that
+             * browse commands can be directed accordingly. */
+            handle_rc_browse_connect(&(p_data->rc_open));
         }break;
 
-        case BTA_AV_RC_BROWSE_OPEN_EVT:
+        case BTA_AV_RC_CLOSE_EVT:
         {
-            BTIF_TRACE_DEBUG("%s: BTA_AV_RC_BROWSE_OPEN_EVT", __func__);
+            handle_rc_disconnect(&(p_data->rc_close));
         }break;
 
         case BTA_AV_RC_BROWSE_CLOSE_EVT:
@@ -1269,26 +1325,43 @@ void btif_rc_handler(tBTA_AV_EVT event, tBTA_AV *p_data)
             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",
-                                 __func__,
-                                 p_data->meta_msg.code,
-                                 p_data->meta_msg.label);
-                BTIF_TRACE_DEBUG("%s: company_id: 0x%x len: %d handle: %d",
-                                 __func__,
+                BTIF_TRACE_DEBUG(
+                    "%s BTA_AV_META_MSG_EVT code:%d label:%d opcode %d ctype %d",
+                    __FUNCTION__,
+                    p_data->meta_msg.code,
+                    p_data->meta_msg.label,
+                    p_data->meta_msg.p_msg->hdr.opcode,
+                    p_data->meta_msg.p_msg->hdr.ctype);
+                BTIF_TRACE_DEBUG("%s company_id:0x%x len:%d handle:%d",
+                                 __FUNCTION__,
                                  p_data->meta_msg.company_id,
                                  p_data->meta_msg.len,
                                  p_data->meta_msg.rc_handle);
+                switch (p_data->meta_msg.p_msg->hdr.opcode) {
+                    case AVRC_OP_VENDOR:
+                        if ((p_data->meta_msg.code >= AVRC_RSP_NOT_IMPL)&&
+                            (p_data->meta_msg.code <= AVRC_RSP_INTERIM))
+                        {
+                            /* Its a response */
+                            handle_avk_rc_metamsg_rsp(&(p_data->meta_msg));
+                        }
+                        else if (p_data->meta_msg.code <= AVRC_CMD_GEN_INQ)
+                        {
+                            /* Its a command  */
+                            handle_avk_rc_metamsg_cmd(&(p_data->meta_msg));
+                        }
+                        break;
 
-                if ((p_data->meta_msg.code >= AVRC_RSP_NOT_IMPL)&&
-                    (p_data->meta_msg.code <= AVRC_RSP_INTERIM))
-                {
-                    /* Its a response */
-                    handle_avk_rc_metamsg_rsp(&(p_data->meta_msg));
-                }
-                else if (p_data->meta_msg.code <= AVRC_CMD_GEN_INQ)
-                {
-                    /* Its a command  */
-                    handle_avk_rc_metamsg_cmd(&(p_data->meta_msg));
+                    case AVRC_OP_BROWSE:
+                        if (p_data->meta_msg.p_msg->hdr.ctype == AVRC_CMD)
+                        {
+                            handle_avk_rc_metamsg_cmd(&(p_data->meta_msg));
+                        }
+                        else if (p_data->meta_msg.p_msg->hdr.ctype == AVRC_RSP)
+                        {
+                            handle_avk_rc_metamsg_rsp(&(p_data->meta_msg));
+                        }
+                        break;
                 }
 
             }
@@ -2094,6 +2167,7 @@ static bt_status_t get_play_status_rsp(bt_bdaddr_t *bd_addr, btrc_play_status_t
 
     memset(&(avrc_rsp.get_play_status), 0, sizeof(tAVRC_GET_PLAY_STATUS_RSP));
 
+    BTIF_TRACE_DEBUG("%s song len %d song pos %d", __func__, song_len, song_pos);
     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;
@@ -4283,6 +4357,313 @@ static void handle_get_playstatus_response (tBTA_AV_META_MSG *pmeta_msg,
 
 /***************************************************************************
 **
+** Function         handle_get_folder_items_response
+**
+** Description      handles the the get folder items response, calls
+**                  HAL callback to send the folder items.
+** Returns          None
+**
+***************************************************************************/
+static void handle_get_folder_items_response (
+    tBTA_AV_META_MSG *pmeta_msg, tAVRC_GET_ITEMS_RSP *p_rsp)
+{
+    btif_rc_device_cb_t *p_dev = btif_rc_get_device_by_handle(pmeta_msg->rc_handle);
+    bt_bdaddr_t rc_addr;
+    bdcpy(rc_addr.address, p_dev->rc_addr);
+
+    if (p_rsp->status == AVRC_STS_NO_ERROR)
+    {
+        /* Convert the internal folder listing into a response that can
+         * be passed onto JNI via HAL_CBACK
+         */
+        uint8_t item_count = p_rsp->item_count;
+        btrc_folder_items_t *btrc_items =
+            (btrc_folder_items_t *) osi_malloc(sizeof(btrc_folder_items_t) * item_count);
+        for (uint8_t i = 0; i < item_count; i++) {
+            const tAVRC_ITEM *avrc_item = &(p_rsp->p_item_list[i]);
+            btrc_folder_items_t *btrc_item = &(btrc_items[i]);
+            BTIF_TRACE_DEBUG("%s folder item type %d", __func__, avrc_item->item_type);
+            switch (avrc_item->item_type) {
+                case AVRC_ITEM_MEDIA:
+                    BTIF_TRACE_DEBUG("%s setting type to %d", __func__, BTRC_ITEM_MEDIA);
+                    get_folder_item_type_media(avrc_item, btrc_item);
+                    break;
+
+                case AVRC_ITEM_FOLDER:
+                    BTIF_TRACE_DEBUG("%s setting type to BTRC_ITEM_FOLDER", __func__);
+                    get_folder_item_type_folder(avrc_item, btrc_item);
+                    break;
+
+                case AVRC_ITEM_PLAYER:
+                    BTIF_TRACE_DEBUG("%s setting type to BTRC_ITEM_PLAYER", __func__);
+                    get_folder_item_type_player(avrc_item, btrc_item);
+                    break;
+
+                default:
+                    BTIF_TRACE_ERROR("%s cannot understand folder item type %d",
+                          __func__, avrc_item->item_type);
+            }
+        }
+
+        HAL_CBACK(bt_rc_ctrl_callbacks,
+                  get_folder_items_cb,
+                  &rc_addr,
+                  /* We want to make the ownership explicit in native */
+                  (const btrc_folder_items_t *) btrc_items,
+                  item_count);
+        BTIF_TRACE_DEBUG("%s HAL CBACK get_folder_items_cb finished", __func__);
+
+        /* Release the memory block for items since we OWN the object */
+        osi_free(btrc_items);
+    }
+    else
+    {
+        BTIF_TRACE_ERROR("%s: Error %d", __func__, p_rsp->status);
+    }
+}
+
+/***************************************************************************
+**
+** Function         get_folder_item_type_media
+**
+** Description      Converts the AVRC representation of a folder item with
+**                  TYPE media to BTIF representation.
+** Returns          None
+**
+***************************************************************************/
+void get_folder_item_type_media(
+    const tAVRC_ITEM *avrc_item, btrc_folder_items_t *btrc_item)
+{
+    btrc_item->item_type = BTRC_ITEM_MEDIA;
+    const tAVRC_ITEM_MEDIA *avrc_item_media = &(avrc_item->u.media);
+    btrc_item_media_t *btrc_item_media = &(btrc_item->media);
+    /* UID */
+    memset(btrc_item_media->uid, 0, BTRC_UID_SIZE * sizeof (uint8_t));
+    memcpy(btrc_item_media->uid,
+           avrc_item_media->uid,
+           sizeof(uint8_t) * BTRC_UID_SIZE);
+
+    /* Audio/Video type */
+    switch (avrc_item_media->type) {
+        case AVRC_MEDIA_TYPE_AUDIO:
+            btrc_item_media->type = BTRC_MEDIA_TYPE_AUDIO;
+            break;
+        case AVRC_MEDIA_TYPE_VIDEO:
+            btrc_item_media->type = BTRC_MEDIA_TYPE_VIDEO;
+            break;
+    }
+
+    /* Charset ID */
+    btrc_item_media->charset_id = avrc_item_media->name.charset_id;
+
+    /* Copy the name */
+    BTIF_TRACE_DEBUG("%s max len %d str len %d", __func__, BTRC_MAX_ATTR_STR_LEN,
+                     avrc_item_media->name.str_len);
+    memset(btrc_item_media->name, 0, BTRC_MAX_ATTR_STR_LEN * sizeof (uint8_t));
+    memcpy(btrc_item_media->name,
+           avrc_item_media->name.p_str,
+           sizeof(uint8_t) * (avrc_item_media->name.str_len));
+
+    /* Copy the parameters */
+    btrc_item_media->num_attrs = avrc_item_media->attr_count;
+    btrc_item_media->p_attrs = (btrc_element_attr_val_t *) osi_malloc (
+        btrc_item_media->num_attrs * sizeof (btrc_element_attr_val_t));
+
+    /* Extract each attribute */
+    for (int i = 0; i < avrc_item_media->attr_count; i++) {
+        btrc_element_attr_val_t *btrc_attr_pair =
+            &(btrc_item_media->p_attrs[i]);
+        tAVRC_ATTR_ENTRY *avrc_attr_pair =
+            &(avrc_item_media->p_attr_list[i]);
+
+        BTIF_TRACE_DEBUG("%s media attr id 0x%x", __func__,
+                         avrc_attr_pair->attr_id);
+
+        switch (avrc_attr_pair->attr_id) {
+            case AVRC_MEDIA_ATTR_ID_TITLE:
+                btrc_attr_pair->attr_id = BTRC_MEDIA_ATTR_ID_TITLE;
+                break;
+            case AVRC_MEDIA_ATTR_ID_ARTIST:
+                btrc_attr_pair->attr_id = BTRC_MEDIA_ATTR_ID_ARTIST;
+                break;
+            case AVRC_MEDIA_ATTR_ID_ALBUM:
+                btrc_attr_pair->attr_id = BTRC_MEDIA_ATTR_ID_ALBUM;
+                break;
+            case AVRC_MEDIA_ATTR_ID_TRACK_NUM:
+                btrc_attr_pair->attr_id = BTRC_MEDIA_ATTR_ID_TRACK_NUM;
+                break;
+            case AVRC_MEDIA_ATTR_ID_NUM_TRACKS:
+                btrc_attr_pair->attr_id = BTRC_MEDIA_ATTR_ID_NUM_TRACKS;
+                break;
+            case AVRC_MEDIA_ATTR_ID_GENRE:
+                btrc_attr_pair->attr_id = BTRC_MEDIA_ATTR_ID_GENRE;
+                break;
+            case AVRC_MEDIA_ATTR_ID_PLAYING_TIME:
+                btrc_attr_pair->attr_id = BTRC_MEDIA_ATTR_ID_PLAYING_TIME;
+                break;
+            default:
+                BTIF_TRACE_ERROR("%s invalid media attr id: 0x%x",
+                                 __func__, avrc_attr_pair->attr_id);
+                btrc_attr_pair->attr_id = BTRC_MEDIA_ATTR_ID_INVALID;
+        }
+
+        memset(btrc_attr_pair->text, 0,
+               BTRC_MAX_ATTR_STR_LEN * sizeof (uint8_t));
+        memcpy(btrc_attr_pair->text,
+               avrc_attr_pair->name.p_str,
+               avrc_attr_pair->name.str_len);
+    }
+}
+
+/***************************************************************************
+**
+** Function         get_folder_item_type_folder
+**
+** Description      Converts the AVRC representation of a folder item with
+**                  TYPE folder to BTIF representation.
+** Returns          None
+**
+***************************************************************************/
+void get_folder_item_type_folder(
+    const tAVRC_ITEM *avrc_item, btrc_folder_items_t *btrc_item)
+{
+    btrc_item->item_type = BTRC_ITEM_FOLDER;
+    const tAVRC_ITEM_FOLDER *avrc_item_folder = &(avrc_item->u.folder);
+    btrc_item_folder_t *btrc_item_folder = &(btrc_item->folder);
+    /* Copy the UID */
+    memset(btrc_item_folder->uid, 0, BTRC_UID_SIZE * sizeof (uint8_t));
+    memcpy(btrc_item_folder->uid, avrc_item_folder->uid, sizeof(uint8_t) * BTRC_UID_SIZE);
+
+    /* Copy the type */
+    switch (avrc_item_folder->type) {
+        case AVRC_FOLDER_TYPE_MIXED:
+            btrc_item_folder->type = BTRC_FOLDER_TYPE_MIXED;
+            break;
+        case AVRC_FOLDER_TYPE_TITLES:
+            btrc_item_folder->type = BTRC_FOLDER_TYPE_TITLES;
+            break;
+        case AVRC_FOLDER_TYPE_ALNUMS:
+            btrc_item_folder->type = BTRC_FOLDER_TYPE_ALBUMS;
+            break;
+        case AVRC_FOLDER_TYPE_ARTISTS:
+            btrc_item_folder->type = BTRC_FOLDER_TYPE_ARTISTS;
+            break;
+        case AVRC_FOLDER_TYPE_GENRES:
+            btrc_item_folder->type = BTRC_FOLDER_TYPE_GENRES;
+            break;
+        case AVRC_FOLDER_TYPE_PLAYLISTS:
+            btrc_item_folder->type = BTRC_FOLDER_TYPE_PLAYLISTS;
+            break;
+        case AVRC_FOLDER_TYPE_YEARS:
+            btrc_item_folder->type = BTRC_FOLDER_TYPE_YEARS;
+            break;
+    }
+
+    /* Copy if playable */
+    btrc_item_folder->playable = avrc_item_folder->playable;
+
+    /* Copy name */
+    BTIF_TRACE_DEBUG("%s max len %d str len %d", __func__, BTRC_MAX_ATTR_STR_LEN,
+                     avrc_item_folder->name.str_len);
+    memset(btrc_item_folder->name, 0, BTRC_MAX_ATTR_STR_LEN * sizeof (uint8_t));
+    memcpy(btrc_item_folder->name,
+           avrc_item_folder->name.p_str,
+           avrc_item_folder->name.str_len * sizeof (uint8_t));
+
+    /* Copy charset */
+    btrc_item_folder->charset_id = avrc_item_folder->name.charset_id;
+}
+
+/***************************************************************************
+**
+** Function         get_folder_item_type_player
+**
+** Description      Converts the AVRC representation of a folder item with
+**                  TYPE player to BTIF representation.
+** Returns          None
+**
+***************************************************************************/
+void get_folder_item_type_player(
+    const tAVRC_ITEM *avrc_item, btrc_folder_items_t *btrc_item)
+{
+    btrc_item->item_type = BTRC_ITEM_PLAYER;
+    const tAVRC_ITEM_PLAYER *avrc_item_player = &(avrc_item->u.player);
+    btrc_item_player_t *btrc_item_player = &(btrc_item->player);
+    /* Player ID */
+    btrc_item_player->player_id = avrc_item_player->player_id;
+    /* Major type */
+    btrc_item_player->major_type = avrc_item_player->major_type;
+    /* Sub type */
+    btrc_item_player->sub_type = avrc_item_player->sub_type;
+    /* Features */
+    memcpy(btrc_item_player->features, avrc_item_player->features,
+           BTRC_FEATURE_BIT_MASK_SIZE);
+
+    memset(btrc_item_player->name, 0,
+           BTRC_MAX_ATTR_STR_LEN * sizeof(uint8_t));
+    memcpy(btrc_item_player->name,
+           avrc_item_player->name.p_str,
+           avrc_item_player->name.str_len);
+}
+
+/***************************************************************************
+**
+** Function         handle_change_path_response
+**
+** Description      handles the the change path response, calls
+**                  HAL callback to send the updated folder
+** Returns          None
+**
+***************************************************************************/
+static void handle_change_path_response (
+    tBTA_AV_META_MSG *pmeta_msg, tAVRC_CHG_PATH_RSP *p_rsp)
+{
+    btif_rc_device_cb_t *p_dev = btif_rc_get_device_by_handle(pmeta_msg->rc_handle);
+    bt_bdaddr_t rc_addr;
+    bdcpy(rc_addr.address, p_dev->rc_addr);
+
+    if (p_rsp->status == AVRC_STS_NO_ERROR)
+    {
+        HAL_CBACK(bt_rc_ctrl_callbacks, change_folder_path_cb,
+                  &rc_addr, p_rsp->num_items);
+    }
+    else
+    {
+        BTIF_TRACE_ERROR("%s error in handle_change_path_response %d",
+                         __func__, p_rsp->status);
+    }
+}
+
+/***************************************************************************
+**
+** Function         handle_set_browsed_player_response
+**
+** Description      handles the the change path response, calls
+**                  HAL callback to send the updated folder
+** Returns          None
+**
+***************************************************************************/
+static void handle_set_browsed_player_response(
+    tBTA_AV_META_MSG *pmeta_msg, tAVRC_SET_BR_PLAYER_RSP *p_rsp)
+{
+    btif_rc_device_cb_t *p_dev = btif_rc_get_device_by_handle(pmeta_msg->rc_handle);
+    bt_bdaddr_t rc_addr;
+    bdcpy(rc_addr.address, p_dev->rc_addr);
+
+    if (p_rsp->status == AVRC_STS_NO_ERROR)
+    {
+        HAL_CBACK(bt_rc_ctrl_callbacks, set_browsed_player_cb,
+                  &rc_addr, p_rsp->num_items, p_rsp->folder_depth);
+    }
+    else
+    {
+        BTIF_TRACE_ERROR("%s error %d", __func__, p_rsp->status);
+    }
+}
+
+
+/***************************************************************************
+**
 ** Function         clear_cmd_timeout
 **
 ** Description      helper function to stop the command timeout timer
@@ -4323,13 +4704,13 @@ static void handle_avk_rc_metamsg_rsp(tBTA_AV_META_MSG *pmeta_msg)
     BTIF_TRACE_DEBUG("%s: opcode: %d rsp_code: %d  ", __func__,
                         pmeta_msg->p_msg->hdr.opcode, pmeta_msg->code);
 
+    status = AVRC_Ctrl_ParsResponse(pmeta_msg->p_msg, &avrc_response, scratch_buf, &buf_len);
     if ((AVRC_OP_VENDOR == pmeta_msg->p_msg->hdr.opcode)&&
                 (pmeta_msg->code >= AVRC_RSP_NOT_IMPL)&&
                 (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",
-                         __func__, status, avrc_response.pdu,
+        BTIF_TRACE_DEBUG("%s parse status %d pdu = %d rsp_status = %d",
+                         __FUNCTION__, status, avrc_response.pdu,
                          pmeta_msg->p_msg->vendor.hdr.ctype);
 
         switch (avrc_response.pdu)
@@ -4380,7 +4761,25 @@ static void handle_avk_rc_metamsg_rsp(tBTA_AV_META_MSG *pmeta_msg)
                 handle_get_playstatus_response(pmeta_msg, &avrc_response.get_play_status);
                 break;
         }
-        release_transaction(pmeta_msg->label);
+    }
+    else if (AVRC_OP_BROWSE == pmeta_msg->p_msg->hdr.opcode)
+    {
+        BTIF_TRACE_DEBUG("%s AVRC_OP_BROWSE pdu %d", __func__, avrc_response.pdu);
+        /* check what kind of command it is for browsing */
+        switch (avrc_response.pdu) {
+            case AVRC_PDU_GET_FOLDER_ITEMS:
+                handle_get_folder_items_response(pmeta_msg, &avrc_response.get_items);
+                break;
+            case AVRC_PDU_CHANGE_PATH:
+                handle_change_path_response(pmeta_msg, &avrc_response.chg_path);
+                break;
+            case AVRC_PDU_SET_BROWSED_PLAYER:
+                handle_set_browsed_player_response(pmeta_msg, &avrc_response.br_player);
+                break;
+            default:
+                BTIF_TRACE_ERROR("%s cannot handle browse pdu %d", __func__,
+                                 pmeta_msg->p_msg->hdr.opcode);
+        }
     }
     else
     {
@@ -4388,6 +4787,8 @@ static void handle_avk_rc_metamsg_rsp(tBTA_AV_META_MSG *pmeta_msg)
             __func__, pmeta_msg->code, pmeta_msg->len);
         return;
     }
+    BTIF_TRACE_DEBUG("XX __func__ release transaction %d", pmeta_msg->label);
+    release_transaction(pmeta_msg->label);
 }
 
 /***************************************************************************
@@ -4407,12 +4808,12 @@ static void handle_avk_rc_metamsg_cmd(tBTA_AV_META_MSG *pmeta_msg)
 
     BTIF_TRACE_DEBUG("%s: opcode: %d rsp_code: %d",__func__,
                      pmeta_msg->p_msg->hdr.opcode,pmeta_msg->code);
+    status = AVRC_Ctrl_ParsCommand(pmeta_msg->p_msg, &avrc_cmd);
     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",
-                         __func__, pmeta_msg->code, avrc_cmd.pdu, pmeta_msg->label);
+        BTIF_TRACE_DEBUG("%s Received vendor command.code %d, PDU %d label %d",
+                         __FUNCTION__, pmeta_msg->code, avrc_cmd.pdu, pmeta_msg->label);
 
         if (status != AVRC_STS_NO_ERROR)
         {
@@ -4720,6 +5121,301 @@ static bt_status_t get_player_app_setting_cmd(uint8_t num_attrib, uint8_t* attri
 
 /***************************************************************************
 **
+** Function         get_now_playing_list_cmd
+**
+** Description      Fetch the now playing list
+**
+** Paramters        start_item: First item to fetch (0 to fetch from beganning)
+**                  end_item: Last item to fetch (0xff to fetch until end)
+**
+** Returns          BT_STATUS_SUCCESS if command issued successfully otherwise
+**                  BT_STATUS_FAIL.
+**
+***************************************************************************/
+static bt_status_t get_now_playing_list_cmd(bt_bdaddr_t *bd_addr, uint8_t start_item,
+                                            uint8_t num_items) {
+    BTIF_TRACE_DEBUG("%s start, end: (%d, %d)", __func__, start_item, num_items);
+#if (AVRC_CTRL_INCLUDED == TRUE)
+    return get_folder_items_cmd(bd_addr, AVRC_SCOPE_NOW_PLAYING, start_item, num_items);
+#else
+    BTIF_TRACE_ERROR("%s AVRCP controller role is not enabled", __func__);
+    return BT_STATUS_FAIL;
+#endif
+}
+
+/***************************************************************************
+**
+** Function         get_folder_list_cmd
+**
+** Description      Fetch the currently selected folder list
+**
+** Paramters        start_item: First item to fetch (0 to fetch from beganning)
+**                  end_item: Last item to fetch (0xff to fetch until end)
+**
+** Returns          BT_STATUS_SUCCESS if command issued successfully otherwise
+**                  BT_STATUS_FAIL.
+**
+***************************************************************************/
+static bt_status_t get_folder_list_cmd(bt_bdaddr_t *bd_addr, uint8_t start_item,
+                                            uint8_t num_items) {
+    BTIF_TRACE_DEBUG("%s start, end: (%d, %d)", __func__, start_item, num_items);
+#if (AVRC_CTRL_INCLUDED == TRUE)
+    return get_folder_items_cmd(bd_addr, AVRC_SCOPE_FILE_SYSTEM, start_item, num_items);
+#else
+    BTIF_TRACE_ERROR("%s AVRCP controller role is not enabled", __func__);
+    return BT_STATUS_FAIL;
+#endif
+}
+
+/***************************************************************************
+**
+** Function         get_player_list_cmd
+**
+** Description      Fetch the player list
+**
+** Paramters        start_item: First item to fetch (0 to fetch from beganning)
+**                  end_item: Last item to fetch (0xff to fetch until end)
+**
+** Returns          BT_STATUS_SUCCESS if command issued successfully otherwise
+**                  BT_STATUS_FAIL.
+**
+***************************************************************************/
+static bt_status_t get_player_list_cmd(bt_bdaddr_t *bd_addr, uint8_t start_item,
+                                            uint8_t num_items) {
+    BTIF_TRACE_DEBUG("%s start, end: (%d, %d)", __func__, start_item, num_items);
+#if (AVRC_CTRL_INCLUDED == TRUE)
+    return get_folder_items_cmd(bd_addr, AVRC_SCOPE_PLAYER_LIST, start_item, num_items);
+#else
+    BTIF_TRACE_ERROR("%s AVRCP controller role is not enabled", __func__);
+    return BT_STATUS_FAIL;
+#endif
+}
+
+/***************************************************************************
+**
+** Function         change_folder_path_cmd
+**
+** Description      Change the folder.
+**
+** Paramters        direction: Direction (Up/Down) to change folder
+**                  uid: The UID of folder to move to
+**                  start_item: First item to fetch (0 to fetch from beganning)
+**                  end_item: Last item to fetch (0xff to fetch until end)
+**
+** Returns          BT_STATUS_SUCCESS if command issued successfully otherwise
+**                  BT_STATUS_FAIL.
+**
+***************************************************************************/
+static bt_status_t change_folder_path_cmd(bt_bdaddr_t *bd_addr, uint8_t direction, uint8_t *uid)
+{
+    BTIF_TRACE_DEBUG("%s direction (%d)", __func__, direction);
+#if (AVRC_CTRL_INCLUDED == TRUE)
+    btif_rc_device_cb_t *p_dev = btif_rc_get_device_by_bda(bd_addr);
+
+    CHECK_RC_CONNECTED(p_dev);
+    CHECK_BR_CONNECTED(p_dev);
+
+    tAVRC_STS status = BT_STATUS_UNSUPPORTED;
+    rc_transaction_t *p_transaction = NULL;
+
+    if (p_dev->br_connected)
+    {
+        tAVRC_COMMAND avrc_cmd = {0};
+        BT_HDR *p_msg = NULL;
+
+        avrc_cmd.chg_path.pdu = AVRC_PDU_CHANGE_PATH;
+        avrc_cmd.chg_path.status = AVRC_STS_NO_ERROR;
+        // TODO(sanketa): Improve for database aware clients.
+        avrc_cmd.chg_path.uid_counter = 0;
+        avrc_cmd.chg_path.direction = direction;
+
+        memset(avrc_cmd.chg_path.folder_uid, 0, AVRC_UID_SIZE * sizeof (uint8_t));
+        memcpy(avrc_cmd.chg_path.folder_uid, uid, AVRC_UID_SIZE * sizeof (uint8_t));
+
+        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 && p_transaction != NULL)
+            {
+                BTIF_TRACE_DEBUG("%s msgreq being sent out with label %d",
+                                 __func__, p_transaction->lbl);
+                BTA_AvMetaCmd(p_dev->rc_handle, p_transaction->lbl, AVRC_CMD_CTRL, p_msg);
+                status = BT_STATUS_SUCCESS;
+            }
+            else
+            {
+                osi_free(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 command status %d", __func__, status);
+            status = BT_STATUS_FAIL;
+        }
+    }
+    else
+    {
+        BTIF_TRACE_ERROR("%s command not supported by peer features %d",
+                         __func__, p_dev->rc_features);
+        status = BT_STATUS_FAIL;
+    }
+    return (bt_status_t) status;
+#else
+    BTIF_TRACE_ERROR("%s AVRCP controller role is not enabled", __func__);
+    return BT_STATUS_FAIL;
+#endif
+}
+
+/***************************************************************************
+**
+** Function         set_browsed_player_cmd
+**
+** Description      Change the browsed player.
+**
+** Paramters        id: The UID of player to move to
+**
+** Returns          BT_STATUS_SUCCESS if command issued successfully otherwise
+**                  BT_STATUS_FAIL.
+**
+***************************************************************************/
+static bt_status_t set_browsed_player_cmd(bt_bdaddr_t *bd_addr, uint16_t id)
+{
+    BTIF_TRACE_DEBUG("%s id (%d)", __func__, id);
+#if (AVRC_CTRL_INCLUDED == TRUE)
+    btif_rc_device_cb_t *p_dev = btif_rc_get_device_by_bda(bd_addr);
+    CHECK_RC_CONNECTED(p_dev);
+    CHECK_BR_CONNECTED(p_dev);
+
+    tAVRC_STS status = BT_STATUS_UNSUPPORTED;
+    rc_transaction_t *p_transaction = NULL;
+
+    if (p_dev->br_connected)
+    {
+        tAVRC_COMMAND avrc_cmd = {0};
+        BT_HDR *p_msg = NULL;
+
+        avrc_cmd.br_player.pdu = AVRC_PDU_SET_BROWSED_PLAYER;
+        avrc_cmd.br_player.status = AVRC_STS_NO_ERROR;
+        // TODO(sanketa): Improve for database aware clients.
+        avrc_cmd.br_player.player_id = id;
+
+        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 && p_transaction != NULL)
+            {
+                BTIF_TRACE_DEBUG("%s msgreq being sent out with label %d",
+                                 __func__, p_transaction->lbl);
+                BTA_AvMetaCmd(p_dev->rc_handle, p_transaction->lbl, AVRC_CMD_CTRL, p_msg);
+                status = BT_STATUS_SUCCESS;
+            }
+            else
+            {
+                osi_free(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 command status %d", __func__, status);
+            status = BT_STATUS_FAIL;
+        }
+    }
+    else
+    {
+        BTIF_TRACE_ERROR("%s command not supported by peer features %d",
+                         __func__, p_dev->rc_features);
+        status = BT_STATUS_FAIL;
+    }
+    return (bt_status_t) status;
+#else
+    BTIF_TRACE_ERROR("%s AVRCP controller role is not enabled", __func__);
+    return BT_STATUS_FAIL;
+#endif
+}
+
+#if (AVRC_CTRL_INCLUDED == TRUE)
+/***************************************************************************
+**
+** Function         get_folder_items_cmd
+**
+** Description      Helper function to browse the content hierarchy of the
+**                  TG device.
+**
+** Paramters        scope: AVRC_SCOPE_NOW_PLAYING (etc) for various browseable
+**                  content
+**                  start_item: First item to fetch (0 to fetch from beganning)
+**                  end_item: Last item to fetch (0xff to fetch until end)
+**
+** Returns          BT_STATUS_SUCCESS if command issued successfully otherwise
+**                  BT_STATUS_FAIL.
+**
+***************************************************************************/
+static bt_status_t get_folder_items_cmd(bt_bdaddr_t *bd_addr, uint8_t scope, uint8_t start_item,
+                                        uint8_t num_items)
+{
+    BTIF_TRACE_DEBUG("%s", __func__);
+    /* Check that both avrcp and browse channel are connected. */
+    btif_rc_device_cb_t *p_dev = btif_rc_get_device_by_bda(bd_addr);
+    CHECK_RC_CONNECTED(p_dev);
+    CHECK_BR_CONNECTED(p_dev);
+
+    tAVRC_STS status = BT_STATUS_UNSUPPORTED;
+    rc_transaction_t *p_transaction=NULL;
+
+    if (p_dev->br_connected) {
+        tAVRC_COMMAND avrc_cmd = {0};
+        BT_HDR *p_msg = NULL;
+
+        /* Set the layer specific to point to browse although this should really
+         * be done by lower layers and looking at the PDU
+         */
+        avrc_cmd.get_items.pdu = AVRC_PDU_GET_FOLDER_ITEMS;
+        avrc_cmd.get_items.status = AVRC_STS_NO_ERROR;
+        avrc_cmd.get_items.scope = scope;
+        avrc_cmd.get_items.start_item = start_item;
+        avrc_cmd.get_items.end_item = (start_item + num_items - 1);
+        avrc_cmd.get_items.attr_count = 0; /* p_attr_list does not matter hence */
+
+        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 && p_transaction != NULL)
+            {
+                BTIF_TRACE_DEBUG("%s msgreq being sent out with label %d",
+                                   __func__, p_transaction->lbl);
+                BTA_AvMetaCmd(p_dev->rc_handle, p_transaction->lbl, AVRC_CMD_CTRL, p_msg);
+                status =  BT_STATUS_SUCCESS;
+            }
+            else
+            {
+                osi_free(p_msg);
+                BTIF_TRACE_ERROR("%s: failed to obtain transaction details. status: 0x%02x",
+                                    __FUNCTION__, tran_status);
+                status = BT_STATUS_FAIL;
+            }
+        }
+        else
+        {
+            BTIF_TRACE_ERROR("%s failed to build command status %d", __func__, status);
+            status = BT_STATUS_FAIL;
+        }
+    } else {
+        BTIF_TRACE_ERROR("%s command not supported by peer features %d",
+                         __func__, p_dev->rc_features);
+        status = BT_STATUS_FAIL;
+    }
+    return (bt_status_t) status;
+}
+#endif
+
+/***************************************************************************
+**
 ** Function         change_player_app_setting
 **
 ** Description      Set current values of Player Attributes
@@ -4782,6 +5478,62 @@ static bt_status_t change_player_app_setting(bt_bdaddr_t *bd_addr, uint8_t num_a
 
 /***************************************************************************
 **
+** Function         play_item_cmd
+**
+** Description      Play the item specified by UID & scope
+**
+** Returns          void
+**
+***************************************************************************/
+static bt_status_t play_item_cmd(
+    bt_bdaddr_t *bd_addr, uint8_t scope, uint8_t *uid, uint16_t uid_counter)
+{
+    tAVRC_STS status = BT_STATUS_UNSUPPORTED;
+#if (AVRC_CTRL_INCLUDED == TRUE)
+    rc_transaction_t *p_transaction = NULL;
+    BTIF_TRACE_DEBUG("%s: scope %d uid_counter %d", __FUNCTION__, scope, uid_counter);
+    btif_rc_device_cb_t *p_dev = btif_rc_get_device_by_bda(bd_addr);
+    CHECK_RC_CONNECTED(p_dev);
+    CHECK_BR_CONNECTED(p_dev);
+
+    bt_status_t tran_status = get_transaction(&p_transaction);
+    if (BT_STATUS_SUCCESS != tran_status)
+        return BT_STATUS_FAIL;
+
+     tAVRC_COMMAND avrc_cmd = {0};
+     BT_HDR *p_msg = NULL;
+     avrc_cmd.pdu = AVRC_PDU_PLAY_ITEM;
+     avrc_cmd.play_item.opcode = AVRC_OP_VENDOR;
+     avrc_cmd.play_item.status = AVRC_STS_NO_ERROR;
+     avrc_cmd.play_item.scope = scope;
+     memcpy(avrc_cmd.play_item.uid, uid, AVRC_UID_SIZE);
+     avrc_cmd.play_item.uid_counter = uid_counter;
+
+     status = AVRC_BldCommand(&avrc_cmd, &p_msg);
+     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",
+                            __FUNCTION__,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_PLAY_ITEM, p_transaction);
+     }
+     else
+     {
+         BTIF_TRACE_ERROR("%s: failed to build command. status: 0x%02x",
+                            __FUNCTION__, status);
+     }
+     osi_free(p_msg);
+#else
+    BTIF_TRACE_DEBUG("%s: feature not enabled", __FUNCTION__);
+#endif
+    return (bt_status_t) status;
+}
+
+/***************************************************************************
+**
 ** Function         get_player_app_setting_attr_text_cmd
 **
 ** Description      Get text description for app attribute
@@ -5309,6 +6061,12 @@ static const btrc_ctrl_interface_t bt_rc_ctrl_interface = {
     send_passthrough_cmd,
     send_groupnavigation_cmd,
     change_player_app_setting,
+    play_item_cmd,
+    get_now_playing_list_cmd,
+    get_folder_list_cmd,
+    get_player_list_cmd,
+    change_folder_path_cmd,
+    set_browsed_player_cmd,
     set_volume_rsp,
     volume_change_notification_rsp,
     cleanup_ctrl,
@@ -5466,6 +6224,7 @@ bt_status_t  get_transaction(rc_transaction_t **ptransaction)
 *******************************************************************************/
 void release_transaction(uint8_t lbl)
 {
+    BTIF_TRACE_DEBUG("%s %d", __func__, lbl);
     rc_transaction_t *transaction = get_transaction_by_lbl(lbl);
 
     /* If the transaction is in use... */
index b48692a..2adc6fb 100644 (file)
 #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 7519cb7..1ea88ef 100644 (file)
@@ -402,14 +402,14 @@ uint16_t AVCT_MsgReq(uint8_t handle, uint8_t label, uint8_t cr, BT_HDR *p_msg)
     tAVCT_CCB       *p_ccb;
     tAVCT_UL_MSG    ul_msg;
 
-    AVCT_TRACE_API("AVCT_MsgReq");
+    AVCT_TRACE_API("%s", __func__);
 
     /* verify p_msg parameter */
     if (p_msg == NULL)
     {
         return AVCT_NO_RESOURCES;
     }
-    AVCT_TRACE_API("len: %d", p_msg->len);
+    AVCT_TRACE_API("%s len: %d layer_specific: %d", __func__, p_msg->len, p_msg->layer_specific);
 
     /* map handle to ccb */
     if ((p_ccb = avct_ccb_by_idx(handle)) == NULL)
index 520c811..ac5cb33 100644 (file)
@@ -435,7 +435,6 @@ void avct_bcb_cong_ind(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data)
 *******************************************************************************/
 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 */
index cf026c2..6dee799 100644 (file)
@@ -66,7 +66,6 @@
  */
 #define AVCT_BR_FCR_OPT_MONITOR_TOUT        12000
 
-
 /* 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);
@@ -77,7 +76,6 @@ 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,
index ab33913..bb7afb1 100644 (file)
@@ -331,6 +331,34 @@ static tAVRC_STS avrc_bld_get_element_attr_cmd(BT_HDR * p_pkt, uint8_t num_attri
 
 /*******************************************************************************
 **
+** Function         avrc_bld_play_item_cmd
+**
+** Description      This function builds the play item cmd
+**
+** Returns          AVRC_STS_NO_ERROR, if the command is built successfully
+**                  Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_play_item_cmd(
+    BT_HDR * p_pkt, uint8_t scope, uint8_t *uid, uint16_t uid_counter)
+{
+    AVRC_TRACE_API("avrc_bld_get_element_attr_cmd");
+    uint8_t *p_start = (uint8_t *)(p_pkt + 1) + p_pkt->offset;
+    uint8_t *p_data = p_start + 2; /* pdu + rsvd */
+    /* add fixed length 11 */
+    UINT16_TO_BE_STREAM(p_data, 0xb);
+    /* Add scope */
+    UINT8_TO_BE_STREAM(p_data, scope);
+    /* Add UID */
+    ARRAY_TO_BE_STREAM(p_data, uid, AVRC_UID_SIZE);
+    /* Add UID Counter */
+    UINT16_TO_BE_STREAM(p_data, uid_counter);
+    p_pkt->len = (p_data - p_start);
+    return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+**
 ** Function         avrc_bld_get_play_status_cmd
 **
 ** Description      This function builds the get play status command.
@@ -344,11 +372,97 @@ static tAVRC_STS avrc_bld_get_play_status_cmd(BT_HDR * p_pkt)
     AVRC_TRACE_API("avrc_bld_list_player_app_attr_cmd");
     uint8_t *p_start = (uint8_t *)(p_pkt + 1) + p_pkt->offset;
     uint8_t *p_data = p_start + 2; /* pdu + rsvd */
-    /* add fixed length 1 -*/
+    /* add fixed length 0 -*/
     UINT16_TO_BE_STREAM(p_data, 0);
     p_pkt->len = (p_data - p_start);
     return AVRC_STS_NO_ERROR;
 }
+
+/*******************************************************************************
+**
+** Function         avrc_bld_get_folder_items_cmd
+**
+** Description      This function builds the get folder items cmd.
+**
+** Returns          AVRC_STS_NO_ERROR, if the command is built successfully
+**                  Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_get_folder_items_cmd(BT_HDR *p_pkt, const tAVRC_GET_ITEMS_CMD *cmd)
+{
+    AVRC_TRACE_API("avrc_bld_get_folder_items_cmd");
+    uint8_t *p_start = (uint8_t *)(p_pkt + 1) + p_pkt->offset;
+    /* This is where the PDU specific for AVRC starts
+     * AVRCP Spec 1.4 section 22.19 */
+    uint8_t *p_data = p_start + 1; /* pdu */
+
+    /* To get the list of all media players we simply need to use the predefined
+     * PDU mentioned in above spec. */
+    /* scope (1) + st item (4) + end item (4) + attr (1) */
+    UINT16_TO_BE_STREAM(p_data, 10);
+    UINT8_TO_BE_STREAM(p_data, cmd->scope); /* scope (1bytes) */
+    UINT32_TO_BE_STREAM(p_data, cmd->start_item); /* start item (4bytes) */
+    UINT32_TO_BE_STREAM(p_data, cmd->end_item); /* end item (4bytes) */
+    UINT8_TO_BE_STREAM(p_data, 0); /* attribute count = 0 (1bytes) */
+    p_pkt->len = (p_data - p_start);
+    return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+**
+** Function         avrc_bld_change_folder_cmd
+**
+** Description      This function builds the change folder command
+**
+** Returns          AVRC_STS_NO_ERROR, if the command is built successfully
+**                  Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_change_folder_cmd(BT_HDR *p_pkt, const tAVRC_CHG_PATH_CMD *cmd)
+{
+    AVRC_TRACE_API("avrc_bld_change_folder_cmd");
+    uint8_t *p_start = (uint8_t *)(p_pkt + 1) + p_pkt->offset;
+    /* This is where the PDU specific for AVRC starts
+     * AVRCP Spec 1.4 section 22.19 */
+    uint8_t *p_data = p_start + 1; /* pdu */
+
+    /* To change folder we need to provide the following:
+     * UID Counter (2) + Direction (1) + UID (8) = 11bytes
+     */
+    UINT16_TO_BE_STREAM(p_data, 11);
+    UINT16_TO_BE_STREAM(p_data, cmd->uid_counter);
+    UINT8_TO_BE_STREAM(p_data, cmd->direction);
+    ARRAY_TO_BE_STREAM(p_data, cmd->folder_uid, AVRC_UID_SIZE);
+    p_pkt->len = (p_data - p_start);
+    return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+**
+** Function         avrc_bld_set_browsed_player_cmd
+**
+** Description      This function builds the set addressed player cmd.
+**
+** Returns          AVRC_STS_NO_ERROR, if the command is built successfully
+**                  Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_set_browsed_player_cmd(BT_HDR *p_pkt, const tAVRC_SET_BR_PLAYER_CMD *cmd)
+{
+    AVRC_TRACE_API("%s", __func__);
+    uint8_t *p_start = (uint8_t *)(p_pkt + 1) + p_pkt->offset;
+    /* This is where the PDU specific for AVRC starts
+     * AVRCP Spec 1.4 section 22.19 */
+    uint8_t *p_data = p_start + 1; /* pdu */
+
+    /* To change browsed player the following is the total length:
+     * Player ID (2)
+     */
+    UINT16_TO_BE_STREAM(p_data, 2); /* fixed length */
+    UINT16_TO_BE_STREAM(p_data, cmd->player_id);
+    p_pkt->len = (p_data - p_start);
+    return AVRC_STS_NO_ERROR;
+}
 #endif
 
 /*******************************************************************************
@@ -363,12 +477,18 @@ static tAVRC_STS avrc_bld_get_play_status_cmd(BT_HDR * p_pkt)
 *******************************************************************************/
 static BT_HDR *avrc_bld_init_cmd_buffer(tAVRC_COMMAND *p_cmd)
 {
-    uint8_t opcode = avrc_opcode_from_pdu(p_cmd->pdu);
+    uint16_t chnl = AVCT_DATA_CTRL;
+    uint8_t  opcode = avrc_opcode_from_pdu(p_cmd->pdu);
     AVRC_TRACE_API("avrc_bld_init_cmd_buffer: pdu=%x, opcode=%x", p_cmd->pdu, opcode);
 
     uint16_t offset = 0;
     switch (opcode)
     {
+    case AVRC_OP_BROWSE:
+        chnl = AVCT_DATA_BROWSE;
+        offset = AVCT_BROWSE_OFFSET;
+        break;
+
     case AVRC_OP_PASS_THRU:
         offset  = AVRC_MSG_PASS_THRU_OFFSET;
         break;
@@ -382,7 +502,7 @@ static BT_HDR *avrc_bld_init_cmd_buffer(tAVRC_COMMAND *p_cmd)
     BT_HDR *p_pkt = (BT_HDR *)osi_malloc(AVRC_META_CMD_BUF_SIZE);
     uint8_t *p_data, *p_start;
 
-    p_pkt->layer_specific = AVCT_DATA_CTRL;
+    p_pkt->layer_specific = chnl;
     p_pkt->event = opcode;
     p_pkt->offset = offset;
     p_data = (uint8_t *)(p_pkt + 1) + p_pkt->offset;
@@ -490,9 +610,22 @@ tAVRC_STS AVRC_BldCommand( tAVRC_COMMAND *p_cmd, BT_HDR **pp_pkt)
         status = avrc_bld_get_element_attr_cmd(p_pkt,
               p_cmd->get_elem_attrs.num_attr,p_cmd->get_elem_attrs.attrs);
         break;
+    case AVRC_PDU_PLAY_ITEM:
+        status = avrc_bld_play_item_cmd(
+            p_pkt, p_cmd->play_item.scope, p_cmd->play_item.uid, p_cmd->play_item.uid_counter);
+        break;
     case AVRC_PDU_GET_PLAY_STATUS:
         status = avrc_bld_get_play_status_cmd(p_pkt);
         break;
+    case AVRC_PDU_GET_FOLDER_ITEMS:
+        status = avrc_bld_get_folder_items_cmd(p_pkt, &(p_cmd->get_items));
+        break;
+    case AVRC_PDU_CHANGE_PATH:
+        status = avrc_bld_change_folder_cmd(p_pkt, &(p_cmd->chg_path));
+        break;
+    case AVRC_PDU_SET_BROWSED_PLAYER:
+        status = avrc_bld_set_browsed_player_cmd(p_pkt, &(p_cmd->br_player));
+        break;
 #endif
     }
 
index 53b79f8..d55c061 100644 (file)
@@ -29,7 +29,6 @@
 #include "avct_defs.h"
 #include "avrc_api.h"
 #include "osi/include/alarm.h"
-
 #include "osi/include/fixed_queue.h"
 
 #ifdef __cplusplus
@@ -132,8 +131,8 @@ typedef struct
 /* AVRC internal connection control block */
 typedef struct
 {
-    fixed_queue_t       *cmd_q;          /* Command queue for serializing vendor specific commands */
-    uint8_t               flags;          /* See AVRC_CB_FLAGS_* definitions */
+    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;
 
index fd58c77..aa3e1c7 100644 (file)
@@ -150,6 +150,248 @@ void avrc_parse_notification_rsp (uint8_t *p_stream, tAVRC_REG_NOTIF_RSP *p_rsp)
     }
 }
 
+static tAVRC_STS avrc_pars_browse_rsp(tAVRC_MSG_BROWSE *p_msg, tAVRC_RESPONSE *p_rsp)
+{
+    tAVRC_STS status = AVRC_STS_NO_ERROR;
+    uint8_t pdu;
+
+    if (p_msg->browse_len == 0)
+    {
+        AVRC_TRACE_ERROR("%s length ", p_msg->browse_len);
+        return AVRC_STS_BAD_PARAM;
+    }
+
+    uint8_t *p = p_msg->p_browse_data;
+
+    /* read the pdu */
+    BE_STREAM_TO_UINT8(pdu, p);
+    uint8_t pkt_len;
+    /* read the entire packet len */
+    BE_STREAM_TO_UINT16(pkt_len, p);
+
+    AVRC_TRACE_DEBUG("%s pdu %d", __func__, pdu);
+
+    /* used to track how much we have read, if we cannot read anymore but the
+     * packet says so then we have a malformed packet. Also vice versa. */
+    uint16_t pkt_len_read = 0;
+
+
+    switch (pdu)
+    {
+    case AVRC_PDU_GET_FOLDER_ITEMS:
+    {
+        tAVRC_GET_ITEMS_RSP *get_item_rsp = &(p_rsp->get_items);
+        /* Copy back the PDU */
+        get_item_rsp->pdu = pdu;
+        /* read the status */
+        BE_STREAM_TO_UINT8(get_item_rsp->status, p);
+        /* read the UID counter */
+        BE_STREAM_TO_UINT16(get_item_rsp->uid_counter, p);
+        /* read the number of items */
+        BE_STREAM_TO_UINT16(get_item_rsp->item_count, p);
+        pkt_len_read += 5;
+
+        AVRC_TRACE_DEBUG("%s pdu %d status %d pkt_len %d uid counter %d item count %d",
+                            __func__, get_item_rsp->pdu, get_item_rsp->status, pkt_len,
+                            get_item_rsp->uid_counter, get_item_rsp->item_count);
+
+        /* get each of the items */
+        get_item_rsp->p_item_list =
+            (tAVRC_ITEM *) osi_malloc (get_item_rsp->item_count * (sizeof(tAVRC_ITEM)));
+        tAVRC_ITEM *curr_item = get_item_rsp->p_item_list;
+        for (int i = 0; i < get_item_rsp->item_count; i++)
+        {
+            BE_STREAM_TO_UINT8(curr_item->item_type, p);
+            pkt_len_read += 1;
+            AVRC_TRACE_DEBUG("%s item type %d", __func__, curr_item->item_type);
+            switch (curr_item->item_type)
+            {
+                case AVRC_ITEM_PLAYER:
+                {
+                    /* Handle player */
+                    tAVRC_ITEM_PLAYER *player = &(curr_item->u.player);
+                    uint8_t player_len;
+                    BE_STREAM_TO_UINT16(player_len, p);
+                    BE_STREAM_TO_UINT16(player->player_id, p);
+                    BE_STREAM_TO_UINT8(player->major_type, p);
+                    BE_STREAM_TO_UINT32(player->sub_type, p);
+                    BE_STREAM_TO_UINT8(player->play_status, p);
+                    BE_STREAM_TO_ARRAY(p, player->features, AVRC_FEATURE_MASK_SIZE);
+                    pkt_len_read += (10 + AVRC_FEATURE_MASK_SIZE);
+
+                    /* read str */
+                    BE_STREAM_TO_UINT16(player->name.charset_id, p);
+                    BE_STREAM_TO_UINT16(player->name.str_len, p);
+                    player->name.p_str = (uint8_t *) osi_malloc (
+                        (player->name.str_len + 1) * sizeof (uint8_t));
+                    BE_STREAM_TO_ARRAY(p, player->name.p_str, player->name.str_len);
+                    pkt_len_read += (4 + player->name.str_len);
+                    AVRC_TRACE_DEBUG(
+                        "%s type %d id %d mtype %d stype %d ps %d cs %d name len %d",
+                        __func__, curr_item->item_type, player->player_id,
+                        player->major_type, player->sub_type, player->play_status,
+                        player->name.charset_id, player->name.str_len);
+                } break;
+
+                case AVRC_ITEM_FOLDER:
+                {
+                    tAVRC_ITEM_FOLDER *folder = &(curr_item->u.folder);
+                    uint16_t folder_len;
+                    BE_STREAM_TO_UINT16(folder_len, p);
+
+                    BE_STREAM_TO_ARRAY(p, folder->uid, AVRC_UID_SIZE);
+                    BE_STREAM_TO_UINT8(folder->type, p);
+                    BE_STREAM_TO_UINT8(folder->playable, p);
+                    pkt_len_read += (4 + AVRC_UID_SIZE);
+
+                    /* read str, encoding to be handled by upper layers */
+                    BE_STREAM_TO_UINT16(folder->name.charset_id, p);
+                    BE_STREAM_TO_UINT16(folder->name.str_len, p);
+                    folder->name.p_str = (uint8_t *) osi_malloc (
+                        (folder->name.str_len + 1) * sizeof (uint8_t));
+                    BE_STREAM_TO_ARRAY(p, folder->name.p_str, folder->name.str_len);
+                    pkt_len_read += (4 + folder->name.str_len);
+                    AVRC_TRACE_DEBUG(
+                        "%s type %d playable %d cs %d name len %d",
+                        __func__, folder->type, folder->playable, folder->name.charset_id,
+                        folder->name.str_len);
+                } break;
+
+                case AVRC_ITEM_MEDIA:
+                {
+                    tAVRC_ITEM_MEDIA *media = &(curr_item->u.media);
+                    uint8_t media_len;
+                    BE_STREAM_TO_UINT16(media_len, p);
+                    BE_STREAM_TO_ARRAY(p, media->uid, AVRC_UID_SIZE);
+                    BE_STREAM_TO_UINT8(media->type, p);
+                    pkt_len_read += (3 + AVRC_UID_SIZE);
+
+                    /* read str, encoding to be handled by upper layers */
+                    BE_STREAM_TO_UINT16(media->name.charset_id, p);
+                    BE_STREAM_TO_UINT16(media->name.str_len, p);
+                    media->name.p_str = (uint8_t *) osi_malloc (
+                        (media->name.str_len) * sizeof (uint8_t));
+                    BE_STREAM_TO_ARRAY(p, media->name.p_str, media->name.str_len);
+
+                    BE_STREAM_TO_UINT8(media->attr_count, p);
+                    AVRC_TRACE_DEBUG("%s media type %d charset id %d len %d attr ct %d",
+                                        __func__, media->type, media->name.charset_id,
+                                        media->name.str_len, media->attr_count);
+                    pkt_len_read += (5 + media->name.str_len);
+
+                    media->p_attr_list = (tAVRC_ATTR_ENTRY *) osi_malloc (
+                        media->attr_count * sizeof (tAVRC_ATTR_ENTRY));
+                    for (int jk = 0; jk < media->attr_count; jk++)
+                    {
+                        tAVRC_ATTR_ENTRY *attr_entry = &(media->p_attr_list[jk]);
+                        BE_STREAM_TO_UINT32(attr_entry->attr_id, p);
+
+                        /* Parse the name now */
+                        BE_STREAM_TO_UINT16(attr_entry->name.charset_id, p);
+                        BE_STREAM_TO_UINT16(attr_entry->name.str_len, p);
+                        attr_entry->name.p_str = (uint8_t *) osi_malloc (
+                            attr_entry->name.str_len * sizeof (uint8_t));
+                        BE_STREAM_TO_ARRAY(p, attr_entry->name.p_str, attr_entry->name.str_len);
+                        pkt_len_read += (8 + attr_entry->name.str_len);
+                        AVRC_TRACE_DEBUG("%s media attr id %d cs %d name len %d",
+                                         __func__, attr_entry->attr_id,
+                                         attr_entry->name.charset_id, attr_entry->name.str_len);
+                    }
+                } break;
+
+                default:
+                    AVRC_TRACE_ERROR("%s item type not handled %d", __func__, curr_item->item_type);
+                    return AVRC_STS_INTERNAL_ERR;
+            }
+
+            /* we check if we have overrun */
+            if (pkt_len_read > pkt_len)
+            {
+                AVRC_TRACE_ERROR("%s overflow in read pkt_len %d pkt_len_read %d",
+                                    __func__, pkt_len, pkt_len_read);
+                return AVRC_STS_BAD_CMD;
+            }
+            AVRC_TRACE_DEBUG("%s pkt_len %d pkt_len_read %d", __func__, pkt_len, pkt_len_read);
+
+            /* advance to populate the next item */
+            curr_item++;
+        }
+        break;
+    }
+
+    case AVRC_PDU_CHANGE_PATH:
+    {
+        tAVRC_CHG_PATH_RSP *change_path_rsp = &(p_rsp->chg_path);
+        /* Copyback the PDU */
+        change_path_rsp->pdu = pdu;
+        /* Read the status */
+        BE_STREAM_TO_UINT8(change_path_rsp->status, p);
+        /* Read the number of items in folder */
+        BE_STREAM_TO_UINT32(change_path_rsp->num_items, p);
+        pkt_len_read += 5;
+
+        AVRC_TRACE_DEBUG("%s pdu %d status %d item count %d",
+                         __func__, change_path_rsp->pdu, change_path_rsp->status,
+                         change_path_rsp->num_items);
+        break;
+    }
+
+    case AVRC_PDU_SET_BROWSED_PLAYER:
+    {
+        tAVRC_SET_BR_PLAYER_RSP *set_br_pl_rsp = &(p_rsp->br_player);
+        /* Copyback the PDU */
+        set_br_pl_rsp->pdu = pdu;
+
+        /* Read the status */
+        BE_STREAM_TO_UINT8(set_br_pl_rsp->status, p);
+
+        if (set_br_pl_rsp->status != AVRC_STS_NO_ERROR) {
+            AVRC_TRACE_ERROR(
+                "%s Stopping further parsing because player not browsable sts %d",
+                __func__, set_br_pl_rsp->status);
+            break;
+        }
+        BE_STREAM_TO_UINT16(set_br_pl_rsp->uid_counter, p);
+        BE_STREAM_TO_UINT32(set_br_pl_rsp->num_items, p);
+        BE_STREAM_TO_UINT16(set_br_pl_rsp->charset_id, p);
+        BE_STREAM_TO_UINT8(set_br_pl_rsp->folder_depth, p);
+        AVRC_TRACE_DEBUG("%s AVRC_PDU_SET_BROWSED_PLAYER status %d items %d cs %d depth %d",
+                         __func__,
+                         set_br_pl_rsp->status,
+                         set_br_pl_rsp->num_items,
+                         set_br_pl_rsp->charset_id,
+                         set_br_pl_rsp->folder_depth);
+        pkt_len_read += 10;
+
+        set_br_pl_rsp->p_folders = (tAVRC_NAME *) osi_malloc (
+            set_br_pl_rsp->num_items * sizeof (tAVRC_NAME));
+
+        /* Read each of the folder in the depth */
+        for (uint32_t i = 0; i < set_br_pl_rsp->folder_depth; i++) {
+            tAVRC_NAME *folder_name = &(set_br_pl_rsp->p_folders[i]);
+            BE_STREAM_TO_UINT16(folder_name->str_len, p);
+            AVRC_TRACE_DEBUG("%s AVRC_PDU_SET_BROWSED_PLAYER item: %d len: %d",
+                             __func__, i, folder_name->str_len);
+            folder_name->p_str = (uint8_t *) osi_malloc (
+                (folder_name->str_len + 1) * sizeof (uint8_t));
+            BE_STREAM_TO_ARRAY(p, folder_name->p_str, folder_name->str_len);
+            pkt_len_read += (2 + folder_name->str_len);
+        }
+        break;
+    }
+
+    default:
+        AVRC_TRACE_ERROR("%s pdu %d not handled", __func__, pdu);
+    }
+
+    if (pkt_len != pkt_len_read)
+    {
+        AVRC_TRACE_ERROR("%s finished pkt_len %d pkt_len_read %d", __func__, pkt_len, pkt_len_read);
+        return AVRC_STS_BAD_CMD;
+    }
+    return status;
+}
+
 #if (AVRC_CTRL_INCLUDED == TRUE)
 /*******************************************************************************
 **
@@ -398,6 +640,10 @@ tAVRC_STS AVRC_Ctrl_ParsResponse (tAVRC_MSG *p_msg, tAVRC_RESPONSE *p_result, ui
             status = avrc_ctrl_pars_vendor_rsp(&p_msg->vendor, p_result, p_buf,buf_len);
             break;
 
+        case AVRC_OP_BROWSE:  /* 0xff Browse commands */
+            status = avrc_pars_browse_rsp(&p_msg->browse, p_result);
+            break;
+
         default:
             AVRC_TRACE_ERROR("%s unknown opcode:0x%x", __func__, p_msg->hdr.opcode);
             break;
index 018eaac..f865054 100644 (file)
@@ -853,7 +853,7 @@ typedef union
                                               ((a) <= AVRC_EVT_VOLUME_CHANGE)) ? true : false)
 
 #define AVRC_IS_VALID_ATTRIBUTE(a)          ((((((a) > 0) && (a) <= AVRC_PLAYER_SETTING_SCAN)) || \
-                                             ((a) >= AVRC_PLAYER_SETTING_LOW_MENU_EXT)) ? true : false)
+                                              ((a) >= AVRC_PLAYER_SETTING_LOW_MENU_EXT)) ? true : false)
 
 #define AVRC_IS_VALID_MEDIA_ATTRIBUTE(a)    (((a) >= AVRC_MEDIA_ATTR_ID_TITLE) && \
                                              ((a) <= AVRC_MEDIA_ATTR_ID_PLAYING_TIME) ? true : false)
@@ -1166,7 +1166,7 @@ typedef struct
 typedef struct
 {
     uint8_t       pdu;
-    tAVRC_STS   status;
+    tAVRC_STS     status;
     uint8_t       opcode;         /* Op Code (assigned by AVRC_BldCommand according to pdu) */
     uint8_t       scope;
 } tAVRC_GET_NUM_OF_ITEMS_CMD;