OSDN Git Service

Support for A2DP Sink and Proper initialization of profiles
authorAnubhav Gupta <anubhavg@codeaurora.org>
Tue, 5 May 2015 07:45:07 +0000 (13:15 +0530)
committerSanket Agarwal <sanketa@google.com>
Thu, 14 Jan 2016 22:01:37 +0000 (22:01 +0000)
 - Register SDP and SEP (Stream End Point) for the profile
   whose init is called. We achieve this by making registration
   api aware of profile id being called.
 - Register A2DP Src + Avrcp Target + Avrcp Controller. We need
   to support Absolute Volume as well, so Avrcp Controller is
   required here.
 - Register A2DP Sink + Avrcp Controller. In this case we do not
   support absolute volume. Support would be added in AVRCP
   controller change
 - Adapter property is updated with profile ID for which init is
   called.This is required to make changes in btService for Profile
   initialization
 - Start listening for incoming AVRCP connection if we have
   only AVRCP Controller
 - Update default peer_features based on feature mask. In case
   of incoming AVRCP connection, SDP will be done later.
   In such a scenario default peer features sent to btif should
   be based on  features-set selected during initialization.
 - Drop Control, Meta and Browse commands when TG is not up.
 - Not to call AVRCP app callbacks when mentioned service is down.
 - Close audio socket on suspend

A2DP Sink: Support for AudioTrack

 - implemetation for audiotrack to take care of audio rendering
 - support for audio focus state in bluedroid

Bluetooth: Support for Avrcp 1.3  Controller

- support for SDP registration
- support for sending vendor dependant commands
- support for abs vol
- support for receiving vendor dependant response
- serialization of connection and rc_features callback

Avrcp_Ctrl: handling of commands and events for AVRCP Controller

- support of parsing cmd and event pdus
- timeout handling

Change-Id: I1e8d49b087eff6301373e1e90e8d868f15847c34

38 files changed:
bta/ar/bta_ar.c
bta/av/bta_av_aact.c
bta/av/bta_av_act.c
bta/av/bta_av_api.c
bta/av/bta_av_cfg.c
bta/av/bta_av_int.h
bta/av/bta_av_main.c
bta/include/bta_ar_api.h
bta/include/bta_av_api.h
btif/include/btif_api.h
btif/include/btif_av.h
btif/include/btif_avrcp_audio_track.h [new file with mode: 0644]
btif/include/btif_media.h
btif/src/btif_av.c
btif/src/btif_avrcp_audio_track.cpp [new file with mode: 0644]
btif/src/btif_media_task.c
btif/src/btif_rc.c
btif/src/btif_storage.c
btif/src/btif_util.c
include/bt_target.h
main/Android.mk
osi/include/list.h
osi/src/list.c
osi/test/list_test.cpp
stack/avdt/avdt_api.c
stack/avdt/avdt_int.h
stack/avdt/avdt_scb.c
stack/avdt/avdt_scb_act.c
stack/avrc/avrc_api.c [changed mode: 0755->0644]
stack/avrc/avrc_bld_ct.c
stack/avrc/avrc_bld_tg.c
stack/avrc/avrc_pars_ct.c
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
stack/include/bt_types.h

index d58fe7b..5b16b8f 100644 (file)
@@ -243,7 +243,7 @@ void bta_ar_dereg_avct(tBTA_SYS_ID sys_id)
 **
 ******************************************************************************/
 void bta_ar_reg_avrc(UINT16 service_uuid, char *service_name, char *provider_name,
-                                        UINT16 categories, tBTA_SYS_ID sys_id)
+                     UINT16 categories, tBTA_SYS_ID sys_id, BOOLEAN browse_supported)
 {
     UINT8   mask = bta_ar_id (sys_id);
     UINT8   temp[8], *p;
@@ -257,20 +257,23 @@ void bta_ar_reg_avrc(UINT16 service_uuid, char *service_name, char *provider_nam
         {
             bta_ar_cb.tg_registered = mask;
             bta_ar_cb.sdp_tg_handle = SDP_CreateRecord();
-            AVRC_AddRecord(service_uuid, service_name, provider_name, categories, bta_ar_cb.sdp_tg_handle);
+            AVRC_AddRecord(service_uuid, service_name, provider_name, categories,
+                           bta_ar_cb.sdp_tg_handle, browse_supported);
             bta_sys_add_uuid(service_uuid);
         }
         /* only one TG is allowed (first-come, first-served).
          * If sdp_tg_handle is non-0, ignore this request */
     }
-    else if ((service_uuid == UUID_SERVCLASS_AV_REMOTE_CONTROL) || (service_uuid == UUID_SERVCLASS_AV_REM_CTRL_CONTROL))
+    else if ((service_uuid == UUID_SERVCLASS_AV_REMOTE_CONTROL)||
+             (service_uuid == UUID_SERVCLASS_AV_REM_CTRL_CONTROL))
     {
         bta_ar_cb.ct_categories [mask - 1] = categories;
         categories = bta_ar_cb.ct_categories[0]|bta_ar_cb.ct_categories[1];
         if (bta_ar_cb.sdp_ct_handle == 0)
         {
             bta_ar_cb.sdp_ct_handle = SDP_CreateRecord();
-            AVRC_AddRecord(service_uuid, service_name, provider_name, categories, bta_ar_cb.sdp_ct_handle);
+            AVRC_AddRecord(service_uuid, service_name, provider_name, categories,
+                           bta_ar_cb.sdp_ct_handle, browse_supported);
             bta_sys_add_uuid(service_uuid);
         }
         else
index d4e2e57..137767e 100644 (file)
@@ -1311,9 +1311,13 @@ void bta_av_setconfig_rsp (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
     APPL_TRACE_DEBUG("bta_av_setconfig_rsp: sep_idx: %d cur_psc_mask:0x%x", p_scb->sep_idx, p_scb->cur_psc_mask);
 
     if ((AVDT_TSEP_SNK == local_sep) && (p_data->ci_setconfig.err_code == AVDT_SUCCESS) &&
-                                     (p_scb->seps[p_scb->sep_idx].p_app_data_cback != NULL))
+                                     (p_scb->seps[p_scb->sep_idx].p_app_data_cback != NULL)) {
+        tBTA_AV_MEDIA av_sink_codec_info;
+        memcpy(av_sink_codec_info.avk_config.bd_addr,p_scb->peer_addr,sizeof(BD_ADDR));
+        av_sink_codec_info.avk_config.codec_info = p_scb->cfg.codec_info;
         p_scb->seps[p_scb->sep_idx].p_app_data_cback(BTA_AV_MEDIA_SINK_CFG_EVT,
-                                              (tBTA_AV_MEDIA*)p_scb->cfg.codec_info);
+                                              &av_sink_codec_info);
+    }
 
 
     AVDT_ConfigRsp(p_scb->avdt_handle, p_scb->avdt_label, p_data->ci_setconfig.err_code,
@@ -1696,7 +1700,7 @@ void bta_av_disc_res_as_acp (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
         }
     }
     p_scb->p_cos->disc_res(p_scb->hndl, p_scb->num_seps, num_snks, 0, p_scb->peer_addr,
-                                                          UUID_SERVCLASS_AUDIO_SOURCE);
+                           UUID_SERVCLASS_AUDIO_SOURCE);
     p_scb->num_disc_snks = num_snks;
     p_scb->num_disc_srcs = 0;
 
@@ -1918,9 +1922,12 @@ void bta_av_getcap_results (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
         if ((uuid_int == UUID_SERVCLASS_AUDIO_SINK) &&
             (p_scb->seps[p_scb->sep_idx].p_app_data_cback != NULL))
         {
-            APPL_TRACE_DEBUG(" Configure Deoder for Sink Connection ");
+            APPL_TRACE_DEBUG("%s Configure Decoder for Sink Connection.", __func__);
+            tBTA_AV_MEDIA av_sink_codec_info;
+            memcpy(av_sink_codec_info.avk_config.bd_addr,p_scb->peer_addr,sizeof(BD_ADDR));
+            av_sink_codec_info.avk_config.codec_info = p_scb->cfg.codec_info;
             p_scb->seps[p_scb->sep_idx].p_app_data_cback(BTA_AV_MEDIA_SINK_CFG_EVT,
-                     (tBTA_AV_MEDIA*)p_scb->cfg.codec_info);
+                                                         &av_sink_codec_info);
         }
 
         /* open the stream */
index 06e1de0..fad6e23 100644 (file)
 #include "osi/include/osi.h"
 #include "utl.h"
 
-#if( defined BTA_AR_INCLUDED ) && (BTA_AR_INCLUDED == TRUE)
+#if ( defined BTA_AR_INCLUDED ) && (BTA_AR_INCLUDED == TRUE)
 #include "bta_ar_api.h"
 #endif
 
 #include "osi/include/log.h"
 
+#if (AVRC_CTLR_INCLUDED == TRUE)
+#include <cutils/properties.h>
+#endif
+
 /*****************************************************************************
 **  Constants
 *****************************************************************************/
@@ -102,23 +106,23 @@ void bta_av_del_rc(tBTA_AV_RCB *p_rcb)
     UINT8        rc_handle;      /* connected AVRCP handle */
 
     p_scb = NULL;
-    if(p_rcb->handle != BTA_AV_RC_HANDLE_NONE)
+    if (p_rcb->handle != BTA_AV_RC_HANDLE_NONE)
     {
-        if(p_rcb->shdl)
+        if (p_rcb->shdl)
         {
             /* Validate array index*/
             if ((p_rcb->shdl - 1) < BTA_AV_NUM_STRS)
             {
                 p_scb = bta_av_cb.p_scb[p_rcb->shdl - 1];
             }
-            if(p_scb)
+            if (p_scb)
             {
                 APPL_TRACE_DEBUG("bta_av_del_rc shdl:%d, srch:%d rc_handle:%d", p_rcb->shdl,
                                   p_scb->rc_handle, p_rcb->handle);
-                if(p_scb->rc_handle == p_rcb->handle)
+                if (p_scb->rc_handle == p_rcb->handle)
                     p_scb->rc_handle = BTA_AV_RC_HANDLE_NONE;
                 /* just in case the RC timer is active
-                if(bta_av_cb.features & BTA_AV_FEAT_RCCT && p_scb->chnl == BTA_AV_CHNL_AUDIO) */
+                if (bta_av_cb.features & BTA_AV_FEAT_RCCT && p_scb->chnl == BTA_AV_CHNL_AUDIO) */
                     bta_sys_stop_timer(&p_scb->timer);
             }
         }
@@ -126,7 +130,7 @@ void bta_av_del_rc(tBTA_AV_RCB *p_rcb)
         APPL_TRACE_EVENT("bta_av_del_rc  handle: %d status=0x%x, rc_acp_handle:%d, idx:%d",
             p_rcb->handle, p_rcb->status, bta_av_cb.rc_acp_handle, bta_av_cb.rc_acp_idx);
         rc_handle = p_rcb->handle;
-        if(!(p_rcb->status & BTA_AV_RC_CONN_MASK) ||
+        if (!(p_rcb->status & BTA_AV_RC_CONN_MASK) ||
             ((p_rcb->status & BTA_AV_RC_ROLE_MASK) == BTA_AV_RC_ROLE_INT) )
         {
             p_rcb->status = 0;
@@ -174,7 +178,7 @@ static void bta_av_close_all_rc(tBTA_AV_CB *p_cb)
 *******************************************************************************/
 static void bta_av_del_sdp_rec(UINT32 *p_sdp_handle)
 {
-    if(*p_sdp_handle != 0)
+    if (*p_sdp_handle != 0)
     {
         SDP_DeleteRecord(*p_sdp_handle);
         *p_sdp_handle = 0;
@@ -240,7 +244,7 @@ static void bta_av_rc_ctrl_cback(UINT8 handle, UINT8 event, UINT16 result, BD_AD
         {
             p_msg->hdr.event = msg_event;
             p_msg->handle    = handle;
-            if(peer_addr)
+            if (peer_addr)
                 bdcpy(p_msg->peer_addr, peer_addr);
             bta_sys_sendmsg(p_msg);
         }
@@ -313,7 +317,7 @@ UINT8 bta_av_rc_create(tBTA_AV_CB *p_cb, UINT8 role, UINT8 shdl, UINT8 lidx)
     UINT8   rc_handle;
     tBTA_AV_RCB *p_rcb;
 
-    if(role == AVCT_INT)
+    if (role == AVCT_INT)
     {
         bda = p_scb->peer_addr;
         status = BTA_AV_RC_ROLE_INT;
@@ -350,7 +354,7 @@ UINT8 bta_av_rc_create(tBTA_AV_CB *p_cb, UINT8 role, UINT8 shdl, UINT8 lidx)
     p_rcb->shdl = shdl;
     p_rcb->lidx = lidx;
     p_rcb->peer_features = 0;
-    if(lidx == (BTA_AV_NUM_LINKS + 1))
+    if (lidx == (BTA_AV_NUM_LINKS + 1))
     {
         /* this LIDX is reserved for the AVRCP ACP connection */
         p_cb->rc_acp_handle = p_rcb->handle;
@@ -464,10 +468,10 @@ tBTA_AV_LCB * bta_av_find_lcb(BD_ADDR addr, UINT8 op)
     for(xx=0; xx<BTA_AV_NUM_LINKS; xx++)
     {
         mask = 1 << xx; /* the used mask for this lcb */
-        if((mask & p_cb->conn_lcb) && 0 ==( bdcmp(p_cb->lcb[xx].addr, addr)))
+        if ((mask & p_cb->conn_lcb) && 0 ==( bdcmp(p_cb->lcb[xx].addr, addr)))
         {
             p_lcb = &p_cb->lcb[xx];
-            if(op == BTA_AV_LCB_FREE)
+            if (op == BTA_AV_LCB_FREE)
             {
                 p_cb->conn_lcb &= ~mask; /* clear the connect mask */
                 APPL_TRACE_DEBUG("conn_lcb: 0x%x", p_cb->conn_lcb);
@@ -502,7 +506,7 @@ void bta_av_rc_opened(tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data)
     for(i=0; i<BTA_AV_NUM_STRS; i++)
     {
         p_scb = p_cb->p_scb[i];
-        if(p_scb && bdcmp(p_scb->peer_addr, p_data->rc_conn_chg.peer_addr) == 0)
+        if (p_scb && bdcmp(p_scb->peer_addr, p_data->rc_conn_chg.peer_addr) == 0)
         {
             p_scb->rc_handle = p_data->rc_conn_chg.handle;
             APPL_TRACE_DEBUG("bta_av_rc_opened shdl:%d, srch %d", i + 1, p_scb->rc_handle);
@@ -545,7 +549,7 @@ void bta_av_rc_opened(tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data)
             i, shdl, p_cb->rcb[i].lidx, p_cb->lcb[BTA_AV_NUM_LINKS].lidx);
     p_cb->rcb[i].status |= BTA_AV_RC_CONN_MASK;
 
-    if(!shdl && 0 == p_cb->lcb[BTA_AV_NUM_LINKS].lidx)
+    if (!shdl && 0 == p_cb->lcb[BTA_AV_NUM_LINKS].lidx)
     {
         /* no associated SCB -> connected to an RC only device
          * update the index to the extra LCB */
@@ -568,11 +572,15 @@ void bta_av_rc_opened(tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data)
     rc_open.status = BTA_AV_SUCCESS;
     APPL_TRACE_DEBUG("local features:x%x peer_features:x%x", p_cb->features,
                       rc_open.peer_features);
-    if(rc_open.peer_features == 0)
+    if (rc_open.peer_features == 0)
     {
         /* we have not done SDP on peer RC capabilities.
-         * peer must have initiated the RC connection */
-        rc_open.peer_features = BTA_AV_FEAT_RCCT;
+         * peer must have initiated the RC connection
+         * We Don't have SDP records of Peer, so we by
+         * default will take values depending upon registered
+         * features */
+        if (p_cb->features & BTA_AV_FEAT_RCTG)
+            rc_open.peer_features |= BTA_AV_FEAT_RCCT;
         bta_av_rc_disc(disc);
     }
     (*p_cb->p_cback)(BTA_AV_RC_OPEN_EVT, (tBTA_AV *) &rc_open);
@@ -593,10 +601,10 @@ void bta_av_rc_remote_cmd(tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data)
     tBTA_AV_RCB    *p_rcb;
     if (p_cb->features & BTA_AV_FEAT_RCCT)
     {
-        if(p_data->hdr.layer_specific < BTA_AV_NUM_RCB)
+        if (p_data->hdr.layer_specific < BTA_AV_NUM_RCB)
         {
             p_rcb = &p_cb->rcb[p_data->hdr.layer_specific];
-            if(p_rcb->status & BTA_AV_RC_CONN_MASK)
+            if (p_rcb->status & BTA_AV_RC_CONN_MASK)
             {
                 AVRC_PassCmd(p_rcb->handle, p_data->api_remote_cmd.label,
                      &p_data->api_remote_cmd.msg);
@@ -620,7 +628,7 @@ void bta_av_rc_vendor_cmd(tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data)
     if ( (p_cb->features & (BTA_AV_FEAT_RCCT | BTA_AV_FEAT_VENDOR)) ==
          (BTA_AV_FEAT_RCCT | BTA_AV_FEAT_VENDOR))
     {
-        if(p_data->hdr.layer_specific < BTA_AV_NUM_RCB)
+        if (p_data->hdr.layer_specific < BTA_AV_NUM_RCB)
         {
             p_rcb = &p_cb->rcb[p_data->hdr.layer_specific];
             AVRC_VendorCmd(p_rcb->handle, p_data->api_vendor.label, &p_data->api_vendor.msg);
@@ -643,7 +651,7 @@ void bta_av_rc_vendor_rsp(tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data)
     if ( (p_cb->features & (BTA_AV_FEAT_RCTG | BTA_AV_FEAT_VENDOR)) ==
          (BTA_AV_FEAT_RCTG | BTA_AV_FEAT_VENDOR))
     {
-        if(p_data->hdr.layer_specific < BTA_AV_NUM_RCB)
+        if (p_data->hdr.layer_specific < BTA_AV_NUM_RCB)
         {
             p_rcb = &p_cb->rcb[p_data->hdr.layer_specific];
             AVRC_VendorRsp(p_rcb->handle, p_data->api_vendor.label, &p_data->api_vendor.msg);
@@ -868,7 +876,9 @@ void bta_av_rc_msg(tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data)
     tBTA_AV     av;
     BT_HDR      *p_pkt = NULL;
     tAVRC_MSG_VENDOR    *p_vendor = &p_data->rc_msg.msg.vendor;
-    BOOLEAN is_inquiry = ((p_data->rc_msg.msg.hdr.ctype == AVRC_CMD_SPEC_INQ) || p_data->rc_msg.msg.hdr.ctype == AVRC_CMD_GEN_INQ);
+    BOOLEAN is_inquiry =
+        ((p_data->rc_msg.msg.hdr.ctype == AVRC_CMD_SPEC_INQ) ||
+         p_data->rc_msg.msg.hdr.ctype == AVRC_CMD_GEN_INQ);
 #if (AVRC_METADATA_INCLUDED == TRUE)
     UINT8       ctype = 0;
     tAVRC_RESPONSE  rc_rsp;
@@ -878,13 +888,15 @@ void bta_av_rc_msg(tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data)
 
     if (p_data->rc_msg.opcode == AVRC_OP_PASS_THRU)
     {
-    /* if this is a pass thru command */
+        /* if this is a pass thru command */
         if ((p_data->rc_msg.msg.hdr.ctype == AVRC_CMD_CTRL) ||
             (p_data->rc_msg.msg.hdr.ctype == AVRC_CMD_SPEC_INQ) ||
             (p_data->rc_msg.msg.hdr.ctype == AVRC_CMD_GEN_INQ)
             )
         {
-        /* check if operation is supported */
+            /* check if operation is supported */
+            char avrcp_ct_support[PROPERTY_VALUE_MAX];
+            property_get("bluetooth.pts.avrcp_ct.support", avrcp_ct_support, "false");
             if (p_data->rc_msg.msg.pass.op_id == AVRC_ID_VENDOR)
             {
                 p_data->rc_msg.msg.hdr.ctype = BTA_AV_RSP_NOT_IMPL;
@@ -895,9 +907,18 @@ 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)
+            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"))
+            {
+                p_data->rc_msg.msg.hdr.ctype = BTA_AV_RSP_ACCEPT;
+            }
+#endif
             else
             {
-                p_data->rc_msg.msg.hdr.ctype = bta_av_op_supported(p_data->rc_msg.msg.pass.op_id, is_inquiry);
+                p_data->rc_msg.msg.hdr.ctype =
+                    bta_av_op_supported(p_data->rc_msg.msg.pass.op_id, is_inquiry);
             }
 
             APPL_TRACE_DEBUG("ctype %d",p_data->rc_msg.msg.hdr.ctype)
@@ -919,7 +940,8 @@ void bta_av_rc_msg(tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data)
             }
         }
         /* else if this is a pass thru response */
-        else if (p_data->rc_msg.msg.hdr.ctype >= AVRC_RSP_ACCEPT)
+        /* id response type is not impl, we have to release label */
+        else if (p_data->rc_msg.msg.hdr.ctype >= AVRC_RSP_NOT_IMPL)
         {
             /* set up for callback */
             evt = BTA_AV_REMOTE_RSP_EVT;
@@ -927,6 +949,19 @@ void bta_av_rc_msg(tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data)
             av.remote_rsp.key_state = p_data->rc_msg.msg.pass.state;
             av.remote_rsp.rsp_code = p_data->rc_msg.msg.hdr.ctype;
             av.remote_rsp.label = p_data->rc_msg.label;
+
+            /* If this response is for vendor unique command  */
+            if ((p_data->rc_msg.msg.pass.op_id == AVRC_ID_VENDOR) &&
+              (p_data->rc_msg.msg.pass.pass_len > 0))
+            {
+                av.remote_rsp.p_data = (UINT8*)osi_getbuf(p_data->rc_msg.msg.pass.pass_len);
+                if (av.remote_rsp.p_data != NULL)
+                {
+                    APPL_TRACE_DEBUG("Vendor Unique data len = %d",p_data->rc_msg.msg.pass.pass_len);
+                    memcpy(av.remote_rsp.p_data,p_data->rc_msg.msg.pass.p_pass_data,
+                                             p_data->rc_msg.msg.pass.pass_len);
+                }
+            }
         }
         /* must be a bad ctype -> reject*/
         else
@@ -962,7 +997,7 @@ void bta_av_rc_msg(tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data)
         }
         /* else if configured to support vendor specific and it's a response */
         else if ((p_cb->features & BTA_AV_FEAT_VENDOR) &&
-                 p_data->rc_msg.msg.hdr.ctype >= AVRC_RSP_ACCEPT)
+                 p_data->rc_msg.msg.hdr.ctype >= AVRC_RSP_NOT_IMPL)
         {
 #if (AVRC_METADATA_INCLUDED == TRUE)
             if ((p_cb->features & BTA_AV_FEAT_METADATA) &&
@@ -980,7 +1015,7 @@ void bta_av_rc_msg(tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data)
         else if (!(p_cb->features & BTA_AV_FEAT_VENDOR)  &&
             p_data->rc_msg.msg.hdr.ctype <= AVRC_CMD_GEN_INQ)
         {
-           if(p_data->rc_msg.msg.vendor.p_vendor_data[0] == AVRC_PDU_INVALID)
+           if (p_data->rc_msg.msg.vendor.p_vendor_data[0] == AVRC_PDU_INVALID)
            {
            /* reject it */
               p_data->rc_msg.msg.hdr.ctype = BTA_AV_RSP_REJ;
@@ -1027,20 +1062,20 @@ void bta_av_rc_close (tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data)
     tBTA_AV_SCB  *p_scb;
     tBTA_AV_RCB *p_rcb;
 
-    if(handle < BTA_AV_NUM_RCB)
+    if (handle < BTA_AV_NUM_RCB)
     {
         p_rcb = &p_cb->rcb[handle];
 
         APPL_TRACE_DEBUG("bta_av_rc_close handle: %d, status=0x%x", p_rcb->handle, p_rcb->status);
-        if(p_rcb->handle != BTA_AV_RC_HANDLE_NONE)
+        if (p_rcb->handle != BTA_AV_RC_HANDLE_NONE)
         {
-            if(p_rcb->shdl)
+            if (p_rcb->shdl)
             {
                 p_scb = bta_av_cb.p_scb[p_rcb->shdl - 1];
-                if(p_scb)
+                if (p_scb)
                 {
                     /* just in case the RC timer is active
-                    if(bta_av_cb.features & BTA_AV_FEAT_RCCT &&
+                    if (bta_av_cb.features & BTA_AV_FEAT_RCCT &&
                        p_scb->chnl == BTA_AV_CHNL_AUDIO) */
                         bta_sys_stop_timer(&p_scb->timer);
                 }
@@ -1065,7 +1100,7 @@ static UINT8 bta_av_get_shdl(tBTA_AV_SCB *p_scb)
     /* find the SCB & stop the timer */
     for(i=0; i<BTA_AV_NUM_STRS; i++)
     {
-        if(p_scb == bta_av_cb.p_scb[i])
+        if (p_scb == bta_av_cb.p_scb[i])
         {
             shdl = i+1;
             break;
@@ -1181,12 +1216,12 @@ void bta_av_conn_chg(tBTA_AV_DATA *p_data)
     mask = BTA_AV_HNDL_TO_MSK(index);
     p_lcb = bta_av_find_lcb(p_data->conn_chg.peer_addr, BTA_AV_LCB_FIND);
     conn_msk = 1 << (index + 1);
-    if(p_data->conn_chg.is_up)
+    if (p_data->conn_chg.is_up)
     {
         /* set the conned mask for this channel */
-        if(p_scb)
+        if (p_scb)
         {
-            if(p_lcb)
+            if (p_lcb)
             {
                 p_lcb->conn_msk |= conn_msk;
                 for (i=0; i<BTA_AV_NUM_RCB; i++)
@@ -1220,7 +1255,7 @@ void bta_av_conn_chg(tBTA_AV_DATA *p_data)
 
             APPL_TRACE_DEBUG("rc_acp_handle:%d rc_acp_idx:%d", p_cb->rc_acp_handle, p_cb->rc_acp_idx);
             /* check if the AVRCP ACP channel is already connected */
-            if(p_lcb && p_cb->rc_acp_handle != BTA_AV_RC_HANDLE_NONE && p_cb->rc_acp_idx)
+            if (p_lcb && p_cb->rc_acp_handle != BTA_AV_RC_HANDLE_NONE && p_cb->rc_acp_idx)
             {
                 p_lcb_rc = &p_cb->lcb[BTA_AV_NUM_LINKS];
                 APPL_TRACE_DEBUG("rc_acp is connected && conn_chg on same addr p_lcb_rc->conn_msk:x%x",
@@ -1276,20 +1311,20 @@ void bta_av_conn_chg(tBTA_AV_DATA *p_data)
         /* clear the conned mask for this channel */
         p_cb->conn_audio &= ~mask;
         p_cb->conn_video &= ~mask;
-        if(p_scb)
+        if (p_scb)
         {
             /* the stream is closed.
              * clear the peer address, so it would not mess up the AVRCP for the next round of operation */
             bdcpy(p_scb->peer_addr, bd_addr_null);
-            if(p_scb->chnl == BTA_AV_CHNL_AUDIO)
+            if (p_scb->chnl == BTA_AV_CHNL_AUDIO)
             {
-                if(p_lcb)
+                if (p_lcb)
                 {
                     p_lcb->conn_msk &= ~conn_msk;
                 }
                 /* audio channel is down. make sure the INT channel is down */
                 /* just in case the RC timer is active
-                if(p_cb->features & BTA_AV_FEAT_RCCT) */
+                if (p_cb->features & BTA_AV_FEAT_RCCT) */
                 {
                     bta_sys_stop_timer(&p_scb->timer);
                 }
@@ -1304,14 +1339,14 @@ void bta_av_conn_chg(tBTA_AV_DATA *p_data)
             APPL_TRACE_DEBUG("conn_chg dn[%d]: %d, status=0x%x, shdl:%d, lidx:%d", i,
                               bta_av_cb.rcb[i].handle, bta_av_cb.rcb[i].status,
                               bta_av_cb.rcb[i].shdl, bta_av_cb.rcb[i].lidx);
-            if(bta_av_cb.rcb[i].shdl == index + 1)
+            if (bta_av_cb.rcb[i].shdl == index + 1)
             {
                 bta_av_del_rc(&bta_av_cb.rcb[i]);
                 break;
             }
         }
 
-        if(p_cb->conn_audio == 0 && p_cb->conn_video == 0)
+        if (p_cb->conn_audio == 0 && p_cb->conn_video == 0)
         {
             /* if both channels are not connected,
              * close all RC channels */
@@ -1419,10 +1454,10 @@ void bta_av_sig_chg(tBTA_AV_DATA *p_data)
     tBTA_AV_LCB *p_lcb = NULL;
 
     APPL_TRACE_DEBUG("bta_av_sig_chg event: %d", event);
-    if(event == AVDT_CONNECT_IND_EVT)
+    if (event == AVDT_CONNECT_IND_EVT)
     {
         p_lcb = bta_av_find_lcb(p_data->str_msg.bd_addr, BTA_AV_LCB_FIND);
-        if(!p_lcb)
+        if (!p_lcb)
         {
             /* if the address does not have an LCB yet, alloc one */
             for(xx=0; xx<BTA_AV_NUM_LINKS; xx++)
@@ -1431,7 +1466,7 @@ void bta_av_sig_chg(tBTA_AV_DATA *p_data)
                 APPL_TRACE_DEBUG("conn_lcb: 0x%x", p_cb->conn_lcb);
 
                 /* look for a p_lcb with its p_scb registered */
-                if((!(mask & p_cb->conn_lcb)) && (p_cb->p_scb[xx] != NULL))
+                if ((!(mask & p_cb->conn_lcb)) && (p_cb->p_scb[xx] != NULL))
                 {
                     p_lcb = &p_cb->lcb[xx];
                     p_lcb->lidx = xx + 1;
@@ -1486,7 +1521,7 @@ void bta_av_sig_chg(tBTA_AV_DATA *p_data)
             }
         }
     }
-#if( defined BTA_AR_INCLUDED ) && (BTA_AR_INCLUDED == TRUE)
+#if ( defined BTA_AR_INCLUDED ) && (BTA_AR_INCLUDED == TRUE)
     else if (event == BTA_AR_AVDT_CONN_EVT)
     {
         bta_sys_stop_timer(&bta_av_cb.sig_tmr);
@@ -1496,7 +1531,7 @@ void bta_av_sig_chg(tBTA_AV_DATA *p_data)
     {
         /* disconnected. */
         p_lcb = bta_av_find_lcb(p_data->str_msg.bd_addr, BTA_AV_LCB_FREE);
-        if(p_lcb && p_lcb->conn_msk)
+        if (p_lcb && p_lcb->conn_msk)
         {
             APPL_TRACE_DEBUG("conn_msk: 0x%x", p_lcb->conn_msk);
             /* clean up ssm  */
@@ -1538,11 +1573,11 @@ void bta_av_sig_timer(tBTA_AV_DATA *p_data)
     for(xx=0; xx<BTA_AV_NUM_LINKS; xx++)
     {
         mask = 1 << xx;
-        if(mask & p_cb->conn_lcb)
+        if (mask & p_cb->conn_lcb)
         {
             /* this entry is used. check if it is connected */
             p_lcb = &p_cb->lcb[xx];
-            if(!p_lcb->conn_msk)
+            if (!p_lcb->conn_msk)
             {
                 bta_sys_start_timer(&p_cb->sig_tmr, BTA_AV_SIG_TIMER_EVT, BTA_AV_SIG_TIME_VAL);
                 bdcpy(pend.bd_addr, p_lcb->addr);
@@ -1664,7 +1699,8 @@ tBTA_AV_FEAT bta_av_check_peer_features (UINT16 service_uuid)
         if (( SDP_FindAttributeInRec(p_rec, ATTR_ID_BT_PROFILE_DESC_LIST)) != NULL)
         {
             /* get profile version (if failure, version parameter is not updated) */
-            SDP_FindProfileVersionInRec(p_rec, UUID_SERVCLASS_AV_REMOTE_CONTROL, &peer_rc_version);
+            SDP_FindProfileVersionInRec(p_rec, UUID_SERVCLASS_AV_REMOTE_CONTROL,
+                                                                &peer_rc_version);
             APPL_TRACE_DEBUG("peer_rc_version 0x%x", peer_rc_version);
 
             if (peer_rc_version >= AVRC_REV_1_3)
@@ -1690,6 +1726,80 @@ tBTA_AV_FEAT bta_av_check_peer_features (UINT16 service_uuid)
 
 /*******************************************************************************
 **
+** Function         bta_avk_check_peer_features
+**
+** Description      check supported features on the peer device from the SDP record
+**                  and return the feature mask
+**
+** Returns          tBTA_AV_FEAT peer device feature mask
+**
+*******************************************************************************/
+tBTA_AV_FEAT bta_avk_check_peer_features (UINT16 service_uuid)
+{
+    tBTA_AV_FEAT peer_features = 0;
+    tBTA_AV_CB *p_cb = &bta_av_cb;
+
+    APPL_TRACE_DEBUG("%s service_uuid:x%x", __FUNCTION__, service_uuid);
+
+    /* loop through all records we found */
+    tSDP_DISC_REC *p_rec = SDP_FindServiceInDb(p_cb->p_disc_db, service_uuid, NULL);
+    while (p_rec)
+    {
+        APPL_TRACE_DEBUG("%s found Service record for x%x", __FUNCTION__, service_uuid);
+
+        if (( SDP_FindAttributeInRec(p_rec, ATTR_ID_SERVICE_CLASS_ID_LIST)) != NULL)
+        {
+            /* find peer features */
+            if (SDP_FindServiceInDb(p_cb->p_disc_db, UUID_SERVCLASS_AV_REMOTE_CONTROL, NULL))
+            {
+                peer_features |= BTA_AV_FEAT_RCCT;
+            }
+            if (SDP_FindServiceInDb(p_cb->p_disc_db, UUID_SERVCLASS_AV_REM_CTRL_TARGET, NULL))
+            {
+                peer_features |= BTA_AV_FEAT_RCTG;
+            }
+        }
+
+        if (( SDP_FindAttributeInRec(p_rec, ATTR_ID_BT_PROFILE_DESC_LIST)) != NULL)
+        {
+            /* get profile version (if failure, version parameter is not updated) */
+            UINT16 peer_rc_version = 0;
+            BOOLEAN val = SDP_FindProfileVersionInRec(
+                p_rec, UUID_SERVCLASS_AV_REMOTE_CONTROL, &peer_rc_version);
+            APPL_TRACE_DEBUG("%s peer_rc_version for TG 0x%x, profile_found %d",
+                             __FUNCTION__, peer_rc_version, val);
+
+            if (peer_rc_version >= AVRC_REV_1_3)
+                peer_features |= (BTA_AV_FEAT_VENDOR | BTA_AV_FEAT_METADATA);
+
+            /*
+             * Though Absolute Volume came after in 1.4 and above, but there are few devices
+             * in market which supports absolute Volume and they are still 1.3
+             * TO avoid IOT issuses with those devices, we check for 1.3 as minimum version
+             */
+            if (peer_rc_version >= AVRC_REV_1_3)
+            {
+                /* get supported categories */
+                tSDP_DISC_ATTR *p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_SUPPORTED_FEATURES);
+                if (p_attr != NULL)
+                {
+                    UINT16 categories = p_attr->attr_value.v.u16;
+                    if (categories & AVRC_SUPF_CT_CAT2)
+                        peer_features |= (BTA_AV_FEAT_ADV_CTRL);
+                    if (categories & AVRC_SUPF_CT_APP_SETTINGS)
+                        peer_features |= (BTA_AV_FEAT_APP_SETTING);
+                }
+            }
+        }
+        /* get next record; if none found, we're done */
+        p_rec = SDP_FindServiceInDb(p_cb->p_disc_db, service_uuid, p_rec);
+    }
+    APPL_TRACE_DEBUG("%s peer_features:x%x", __FUNCTION__, peer_features);
+    return peer_features;
+}
+
+/*******************************************************************************
+**
 ** Function         bta_av_rc_disc_done
 **
 ** Description      Handle AVRCP service discovery results.  If matching
@@ -1706,10 +1816,10 @@ void bta_av_rc_disc_done(tBTA_AV_DATA *p_data)
     tBTA_AV_RC_OPEN rc_open;
     tBTA_AV_RC_FEAT rc_feat;
     UINT8               rc_handle;
-    tBTA_AV_FEAT        peer_features;  /* peer features mask */
+    tBTA_AV_FEAT        peer_features = 0;  /* peer features mask */
     UNUSED(p_data);
 
-    APPL_TRACE_DEBUG("bta_av_rc_disc_done disc:x%x", p_cb->disc);
+    APPL_TRACE_DEBUG("%s bta_av_rc_disc_done disc:x%x", __FUNCTION__, p_cb->disc);
     if (!p_cb->disc)
     {
         return;
@@ -1728,7 +1838,9 @@ void bta_av_rc_disc_done(tBTA_AV_DATA *p_data)
             p_scb = p_cb->p_scb[(p_cb->disc & BTA_AV_HNDL_MSK) - 1];
         }
         if (p_scb)
+        {
             rc_handle = p_scb->rc_handle;
+        }
         else
         {
             p_cb->disc = 0;
@@ -1736,14 +1848,25 @@ void bta_av_rc_disc_done(tBTA_AV_DATA *p_data)
         }
     }
 
-    APPL_TRACE_DEBUG("rc_handle %d", rc_handle);
-    /* check peer version and whether support CT and TG role */
-    peer_features = bta_av_check_peer_features (UUID_SERVCLASS_AV_REMOTE_CONTROL);
-    if ((p_cb->features & BTA_AV_FEAT_ADV_CTRL) && ((peer_features&BTA_AV_FEAT_ADV_CTRL) == 0))
+    APPL_TRACE_DEBUG("%s rc_handle %d", __FUNCTION__, rc_handle);
+    if (p_cb->sdp_a2d_snk_handle)
     {
-        /* if we support advance control and peer does not, check their support on TG role
-         * some implementation uses 1.3 on CT ans 1.4 on TG */
-        peer_features |= bta_av_check_peer_features (UUID_SERVCLASS_AV_REM_CTRL_TARGET);
+        /* This is Sink + CT + TG(Abs Vol) */
+        peer_features = bta_avk_check_peer_features(UUID_SERVCLASS_AV_REM_CTRL_TARGET);
+        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);
+    }
+    else if (p_cb->sdp_a2d_handle)
+    {
+        /* check peer version and whether support CT and TG role */
+        peer_features = bta_av_check_peer_features(UUID_SERVCLASS_AV_REMOTE_CONTROL);
+        if ((p_cb->features & BTA_AV_FEAT_ADV_CTRL) &&
+            ((peer_features & BTA_AV_FEAT_ADV_CTRL) == 0))
+        {
+            /* if we support advance control and peer does not, check their support on TG role
+             * some implementation uses 1.3 on CT ans 1.4 on TG */
+            peer_features |= bta_av_check_peer_features(UUID_SERVCLASS_AV_REM_CTRL_TARGET);
+        }
     }
 
     p_cb->disc = 0;
@@ -1761,7 +1884,7 @@ void bta_av_rc_disc_done(tBTA_AV_DATA *p_data)
                  ((p_cb->features & BTA_AV_FEAT_RCTG) && (peer_features & BTA_AV_FEAT_RCCT))) )
             {
                 p_lcb = bta_av_find_lcb(p_scb->peer_addr, BTA_AV_LCB_FIND);
-                if(p_lcb)
+                if (p_lcb)
                 {
                     rc_handle = bta_av_rc_create(p_cb, AVCT_INT, (UINT8)(p_scb->hdi + 1), p_lcb->lidx);
                     p_cb->rcb[rc_handle].peer_features = peer_features;
@@ -1773,7 +1896,7 @@ void bta_av_rc_disc_done(tBTA_AV_DATA *p_data)
                 }
 #endif
             }
-            else if(p_scb->use_rc)
+            else if (p_scb->use_rc)
             {
                 /* can not find AVRC on peer device. report failure */
                 p_scb->use_rc = FALSE;
@@ -1789,6 +1912,17 @@ void bta_av_rc_disc_done(tBTA_AV_DATA *p_data)
         p_cb->rcb[rc_handle].peer_features = peer_features;
         rc_feat.rc_handle =  rc_handle;
         rc_feat.peer_features = peer_features;
+        if (p_scb == NULL)
+        {
+            /*
+             * In case scb is not created by the time we are done with SDP
+             * we still need to send RC feature event. So we need to get BD
+             * from Message
+             */
+            bdcpy(rc_feat.peer_addr, p_cb->lcb[p_cb->rcb[rc_handle].lidx].addr);
+        }
+        else
+            bdcpy(rc_feat.peer_addr, p_scb->peer_addr);
         (*p_cb->p_cback)(BTA_AV_RC_FEAT_EVT, (tBTA_AV *) &rc_feat);
     }
 }
@@ -1820,28 +1954,28 @@ void bta_av_rc_closed(tBTA_AV_DATA *p_data)
     {
         p_rcb = &p_cb->rcb[i];
         APPL_TRACE_DEBUG("bta_av_rc_closed rcb[%d] rc_handle:%d, status=0x%x", i, p_rcb->handle, p_rcb->status);
-        if(p_rcb->handle == p_msg->handle)
+        if (p_rcb->handle == p_msg->handle)
         {
             rc_close.rc_handle = i;
             p_rcb->status &= ~BTA_AV_RC_CONN_MASK;
             p_rcb->peer_features = 0;
             APPL_TRACE_DEBUG("       shdl:%d, lidx:%d", p_rcb->shdl, p_rcb->lidx);
-            if(p_rcb->shdl)
+            if (p_rcb->shdl)
             {
                 if ((p_rcb->shdl - 1) < BTA_AV_NUM_STRS)
                 {
                     p_scb = bta_av_cb.p_scb[p_rcb->shdl - 1];
                 }
-                if(p_scb)
+                if (p_scb)
                 {
                     bdcpy(rc_close.peer_addr, p_scb->peer_addr);
-                    if(p_scb->rc_handle == p_rcb->handle)
+                    if (p_scb->rc_handle == p_rcb->handle)
                         p_scb->rc_handle = BTA_AV_RC_HANDLE_NONE;
                     APPL_TRACE_DEBUG("shdl:%d, srch:%d", p_rcb->shdl, p_scb->rc_handle);
                 }
                 p_rcb->shdl = 0;
             }
-            else if(p_rcb->lidx == (BTA_AV_NUM_LINKS + 1) )
+            else if (p_rcb->lidx == (BTA_AV_NUM_LINKS + 1))
             {
                 /* if the RCB uses the extra LCB, use the addr for event and clean it */
                 p_lcb = &p_cb->lcb[BTA_AV_NUM_LINKS];
@@ -1855,7 +1989,7 @@ void bta_av_rc_closed(tBTA_AV_DATA *p_data)
             }
             p_rcb->lidx = 0;
 
-            if((p_rcb->status & BTA_AV_RC_ROLE_MASK) == BTA_AV_RC_ROLE_INT)
+            if ((p_rcb->status & BTA_AV_RC_ROLE_MASK) == BTA_AV_RC_ROLE_INT)
             {
                 /* AVCT CCB is deallocated */
                 p_rcb->handle = BTA_AV_RC_HANDLE_NONE;
@@ -1871,14 +2005,14 @@ void bta_av_rc_closed(tBTA_AV_DATA *p_data)
                     bta_av_rc_create(&bta_av_cb, AVCT_ACP, 0, BTA_AV_NUM_LINKS + 1);
             }
         }
-        else if((p_rcb->handle != BTA_AV_RC_HANDLE_NONE) && (p_rcb->status & BTA_AV_RC_CONN_MASK))
+        else if ((p_rcb->handle != BTA_AV_RC_HANDLE_NONE) && (p_rcb->status & BTA_AV_RC_CONN_MASK))
         {
             /* at least one channel is still connected */
             conn = TRUE;
         }
     }
 
-    if(!conn)
+    if (!conn)
     {
         /* no AVRC channels are connected, go back to INIT state */
         bta_av_sm_execute(p_cb, BTA_AV_AVRC_NONE_EVT, NULL);
@@ -1985,11 +2119,11 @@ void bta_av_dereg_comp(tBTA_AV_DATA *p_data)
     /* find the stream control block */
     p_scb = bta_av_hndl_to_scb(p_data->hdr.layer_specific);
 
-    if(p_scb)
+    if (p_scb)
     {
         APPL_TRACE_DEBUG("deregistered %d(h%d)", p_scb->chnl, p_scb->hndl);
         mask = BTA_AV_HNDL_TO_MSK(p_scb->hdi);
-        if(p_scb->chnl == BTA_AV_CHNL_AUDIO)
+        if (p_scb->chnl == BTA_AV_CHNL_AUDIO)
         {
             p_cb->reg_audio  &= ~mask;
             if ((p_cb->conn_audio & mask) && bta_av_cb.audio_open_cnt)
@@ -2009,17 +2143,25 @@ void bta_av_dereg_comp(tBTA_AV_DATA *p_data)
             }
 
             /* remove the A2DP SDP record, if no more audio stream is left */
-            if(!p_cb->reg_audio)
+            if (!p_cb->reg_audio)
             {
-#if( defined BTA_AR_INCLUDED ) && (BTA_AR_INCLUDED == TRUE)
+#if ( defined BTA_AR_INCLUDED ) && (BTA_AR_INCLUDED == TRUE)
                 bta_ar_dereg_avrc (UUID_SERVCLASS_AV_REMOTE_CONTROL, BTA_ID_AV);
 #endif
-                bta_av_del_sdp_rec(&p_cb->sdp_a2d_handle);
-                bta_sys_remove_uuid(UUID_SERVCLASS_AUDIO_SOURCE);
+                if (p_cb->sdp_a2d_handle)
+                {
+                    bta_av_del_sdp_rec(&p_cb->sdp_a2d_handle);
+                    p_cb->sdp_a2d_handle = 0;
+                    bta_sys_remove_uuid(UUID_SERVCLASS_AUDIO_SOURCE);
+                }
 
 #if (BTA_AV_SINK_INCLUDED == TRUE)
-                bta_av_del_sdp_rec(&p_cb->sdp_a2d_snk_handle);
-                bta_sys_remove_uuid(UUID_SERVCLASS_AUDIO_SINK);
+                if (p_cb->sdp_a2d_snk_handle)
+                {
+                    bta_av_del_sdp_rec(&p_cb->sdp_a2d_snk_handle);
+                    p_cb->sdp_a2d_snk_handle = 0;
+                    bta_sys_remove_uuid(UUID_SERVCLASS_AUDIO_SINK);
+                }
 #endif
             }
         }
@@ -2041,9 +2183,9 @@ void bta_av_dereg_comp(tBTA_AV_DATA *p_data)
     APPL_TRACE_DEBUG("audio 0x%x, video: 0x%x, disable:%d",
         p_cb->reg_audio, p_cb->reg_video, p_cb->disabling);
     /* if no stream control block is active */
-    if((p_cb->reg_audio + p_cb->reg_video) == 0)
+    if ((p_cb->reg_audio + p_cb->reg_video) == 0)
     {
-#if( defined BTA_AR_INCLUDED ) && (BTA_AR_INCLUDED == TRUE)
+#if ( defined BTA_AR_INCLUDED ) && (BTA_AR_INCLUDED == TRUE)
         /* deregister from AVDT */
         bta_ar_dereg_avdt(BTA_ID_AV);
 
@@ -2052,7 +2194,7 @@ void bta_av_dereg_comp(tBTA_AV_DATA *p_data)
         bta_ar_dereg_avct(BTA_ID_AV);
 #endif
 
-        if(p_cb->disabling)
+        if (p_cb->disabling)
         {
             p_cb->disabling     = FALSE;
             bta_av_cb.features  = 0;
index 8686a90..932ee33 100644 (file)
@@ -24,6 +24,8 @@
  *
  ******************************************************************************/
 
+#include <assert.h>
+
 #include "bt_target.h"
 #if defined(BTA_AV_INCLUDED) && (BTA_AV_INCLUDED == TRUE)
 
@@ -110,7 +112,8 @@ void BTA_AvDisable(void)
 ** Returns          void
 **
 *******************************************************************************/
-void BTA_AvRegister(tBTA_AV_CHNL chnl, const char *p_service_name, UINT8 app_id, tBTA_AV_DATA_CBACK  *p_data_cback)
+void BTA_AvRegister(tBTA_AV_CHNL chnl, const char *p_service_name, UINT8 app_id,
+                    tBTA_AV_DATA_CBACK  *p_data_cback, UINT16 service_uuid)
 {
     tBTA_AV_API_REG  *p_buf;
 
@@ -121,7 +124,9 @@ void BTA_AvRegister(tBTA_AV_CHNL chnl, const char *p_service_name, UINT8 app_id,
         p_buf->hdr.event = BTA_AV_API_REGISTER_EVT;
         if(p_service_name)
         {
-            BCM_STRNCPY_S(p_buf->p_service_name, sizeof(p_buf->p_service_name), p_service_name, BTA_SERVICE_NAME_LEN);
+            BCM_STRNCPY_S(
+                p_buf->p_service_name, sizeof(p_buf->p_service_name), p_service_name,
+                BTA_SERVICE_NAME_LEN);
             p_buf->p_service_name[BTA_SERVICE_NAME_LEN-1] = 0;
         }
         else
@@ -130,6 +135,7 @@ void BTA_AvRegister(tBTA_AV_CHNL chnl, const char *p_service_name, UINT8 app_id,
         }
         p_buf->app_id = app_id;
         p_buf->p_app_data_cback = p_data_cback;
+        p_buf->service_uuid = service_uuid;
         bta_sys_sendmsg(p_buf);
     }
 }
@@ -463,6 +469,32 @@ void BTA_AvRemoteCmd(UINT8 rc_handle, UINT8 label, tBTA_AV_RC rc_id, tBTA_AV_STA
 
 /*******************************************************************************
 **
+** Function         BTA_AvRemoteVendorUniqueCmd
+**
+** Description      Send a remote control command with Vendor Unique rc_id. This function can only
+**                  be used if AV is enabled with feature BTA_AV_FEAT_RCCT.
+**
+** Returns          void
+**
+*******************************************************************************/
+void BTA_AvRemoteVendorUniqueCmd(UINT8 rc_handle, UINT8 label, tBTA_AV_STATE key_state,
+                                 UINT8* p_msg, UINT8 buf_len)
+{
+    tBTA_AV_API_REMOTE_CMD  *p_buf =
+        (tBTA_AV_API_REMOTE_CMD *) osi_getbuf(sizeof(tBTA_AV_API_REMOTE_CMD));
+    assert(p_buf);
+    p_buf->hdr.event = BTA_AV_API_REMOTE_CMD_EVT;
+    p_buf->hdr.layer_specific   = rc_handle;
+    p_buf->msg.op_id = AVRC_ID_VENDOR;
+    p_buf->msg.state = key_state;
+    p_buf->msg.p_pass_data = p_msg;
+    p_buf->msg.pass_len = buf_len;
+    p_buf->label = label;
+    bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+**
 ** Function         BTA_AvVendorCmd
 **
 ** Description      Send a vendor dependent remote control command.  This
index 285e078..47b8795 100644 (file)
@@ -40,7 +40,16 @@ const UINT32  bta_av_meta_caps_co_ids[] = {
 };
 
 /* AVRCP cupported categories */
+#if (AVRC_CTLR_INCLUDED == TRUE)
+#define BTA_AV_RC_SUPF_CT       (AVRC_SUPF_CT_CAT1 | AVRC_SUPF_CT_CAT2)
+#else
 #define BTA_AV_RC_SUPF_CT       (AVRC_SUPF_CT_CAT2)
+#endif
+
+#if (AVRC_CTLR_INCLUDED == TRUE)
+#define BTA_AVK_RC_SUPF_CT       (AVRC_SUPF_CT_CAT1)
+#define BTA_AVK_RC_SUPF_TG       (AVRC_SUPF_TG_CAT2)
+#endif
 
 /* Added to modify
 **     1. flush timeout
@@ -81,11 +90,22 @@ const UINT8  bta_av_meta_caps_evt_ids[] = {
 #define BTA_AV_NUM_RC_EVT_IDS   (sizeof(bta_av_meta_caps_evt_ids) / sizeof(bta_av_meta_caps_evt_ids[0]))
 #endif /* BTA_AV_NUM_RC_EVT_IDS */
 
+const UINT8  bta_avk_meta_caps_evt_ids[] = {
+#if AVRC_ADV_CTRL_INCLUDED == TRUE
+    AVRC_EVT_VOLUME_CHANGE,
+#endif
+};
+#ifndef BTA_AVK_NUM_RC_EVT_IDS
+#define BTA_AVK_NUM_RC_EVT_IDS   (sizeof(bta_avk_meta_caps_evt_ids) / sizeof(bta_avk_meta_caps_evt_ids[0]))
+#endif /* BTA_AVK_NUM_RC_EVT_IDS */
+
+
 /* the MTU for the AVRCP browsing channel */
 #ifndef BTA_AV_MAX_RC_BR_MTU
 #define BTA_AV_MAX_RC_BR_MTU      1008
 #endif
 
+/* 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 */
@@ -115,7 +135,37 @@ const tBTA_AV_CFG bta_av_cfg =
     {0},                    /* Default AVRCP target name */
 };
 
-tBTA_AV_CFG *p_bta_av_cfg = (tBTA_AV_CFG *) &bta_av_cfg;
+/* This configuration to be used when we are Sink + CT + TG( only for abs vol) */
+const tBTA_AV_CFG bta_avk_cfg =
+{
+    AVRC_CO_METADATA,       /* AVRCP Company ID */
+#if AVRC_METADATA_INCLUDED == TRUE
+    512,                    /* AVRCP MTU at L2CAP for control channel */
+#else
+    48,                     /* AVRCP MTU at L2CAP for control channel */
+#endif
+    BTA_AV_MAX_RC_BR_MTU,   /* AVRCP MTU at L2CAP for browsing channel */
+    BTA_AVK_RC_SUPF_CT,      /* AVRCP controller categories */
+    BTA_AVK_RC_SUPF_TG,      /* AVRCP target categories */
+    672,                    /* AVDTP signaling channel MTU at L2CAP */
+    BTA_AV_MAX_A2DP_MTU,    /* AVDTP audio transport channel MTU at L2CAP */
+    bta_av_audio_flush_to,  /* AVDTP audio transport channel flush timeout */
+    6,                      /* AVDTP audio channel max data queue size */
+    BTA_AV_MAX_VDP_MTU,     /* AVDTP video transport channel MTU at L2CAP */
+    600,                    /* AVDTP video transport channel flush timeout */
+    FALSE,                   /* TRUE, to accept AVRC 1.3 group nevigation command */
+    2,                      /* company id count in p_meta_co_ids */
+    BTA_AVK_NUM_RC_EVT_IDS, /* event id count in p_meta_evt_ids */
+    BTA_AV_RC_PASS_RSP_CODE,/* the default response code for pass through commands */
+    bta_av_meta_caps_co_ids,/* the metadata Get Capabilities response for company id */
+    bta_avk_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 */
+};
+
+tBTA_AV_CFG *p_bta_av_cfg = NULL;
 
 const UINT16 bta_av_rc_id[] =
 {
index 2151209..d2c3cc1 100644 (file)
@@ -212,6 +212,7 @@ typedef struct
     char                p_service_name[BTA_SERVICE_NAME_LEN+1];
     UINT8               app_id;
     tBTA_AV_DATA_CBACK       *p_app_data_cback;
+    UINT16              service_uuid;
 } tBTA_AV_API_REG;
 
 
@@ -617,6 +618,8 @@ extern tBTA_AV_CB *bta_av_cb_ptr;
 
 /* config struct */
 extern tBTA_AV_CFG *p_bta_av_cfg;
+extern const tBTA_AV_CFG bta_avk_cfg;
+extern const tBTA_AV_CFG bta_av_cfg;
 
 /* rc id config struct */
 extern UINT16 *p_bta_av_rc_id;
index 7706252..8f6a5df 100644 (file)
@@ -536,14 +536,23 @@ static void bta_av_api_register(tBTA_AV_DATA *p_data)
     tBTA_AV_CODEC   codec_type;
     tBTA_UTL_COD    cod;
     UINT8           index = 0;
-    char p_avk_service_name[BTA_SERVICE_NAME_LEN+1];
-    BCM_STRNCPY_S(p_avk_service_name, sizeof(p_avk_service_name), BTIF_AVK_SERVICE_NAME, BTA_SERVICE_NAME_LEN);
 
     memset(&cs,0,sizeof(tAVDT_CS));
 
     registr.status = BTA_AV_FAIL_RESOURCES;
     registr.app_id = p_data->api_reg.app_id;
     registr.chnl   = (tBTA_AV_CHNL)p_data->hdr.layer_specific;
+
+    UINT16 profile_initialized = p_data->api_reg.service_uuid;
+    if (profile_initialized == UUID_SERVCLASS_AUDIO_SINK)
+    {
+        p_bta_av_cfg  = (tBTA_AV_CFG *) &bta_avk_cfg;
+    }
+    else if (profile_initialized == UUID_SERVCLASS_AUDIO_SOURCE)
+    {
+        p_bta_av_cfg  = (tBTA_AV_CFG *) &bta_av_cfg;
+    }
+
     do
     {
         p_scb = bta_av_alloc_scb(registr.chnl);
@@ -587,23 +596,23 @@ static void bta_av_api_register(tBTA_AV_DATA *p_data)
 #endif
 
                 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);
+                                p_bta_av_cfg->avrc_tg_cat, BTA_ID_AV,
+                                (bta_av_cb.features & BTA_AV_FEAT_BROWSE));
 #endif
             }
 
             /* Set the Capturing service class bit */
-#if (BTA_AV_SINK_INCLUDED == TRUE)
-            cod.service = BTM_COD_SERVICE_CAPTURING | BTM_COD_SERVICE_RENDERING;
-#else
-            cod.service = BTM_COD_SERVICE_CAPTURING;
-#endif
+            if (profile_initialized == UUID_SERVCLASS_AUDIO_SOURCE)
+                cod.service = BTM_COD_SERVICE_CAPTURING;
+            else if (profile_initialized == UUID_SERVCLASS_AUDIO_SINK)
+                cod.service = BTM_COD_SERVICE_RENDERING;
             utl_set_device_class(&cod, BTA_UTL_SET_COD_SERVICE_CLASS);
         } /* if 1st channel */
 
         /* get stream configuration and create stream */
         /* memset(&cs.cfg,0,sizeof(tAVDT_CFG)); */
         cs.cfg.num_codec = 1;
-        cs.tsep = AVDT_TSEP_SRC;
+
 
         /*
          * memset of cs takes care setting call back pointers to null.
@@ -650,55 +659,64 @@ static void bta_av_api_register(tBTA_AV_DATA *p_data)
             if(bta_av_cb.features & BTA_AV_FEAT_DELAY_RPT)
                 cs.cfg.psc_mask |= AVDT_PSC_DELAY_RPT;
 
-            /* keep the configuration in the stream control block */
-            memcpy(&p_scb->cfg, &cs.cfg, sizeof(tAVDT_CFG));
-            while(index < BTA_AV_MAX_SEPS &&
-                (*bta_av_a2d_cos.init)(&codec_type, cs.cfg.codec_info,
-                &cs.cfg.num_protect, cs.cfg.protect_info, index) == TRUE)
+            if (profile_initialized == UUID_SERVCLASS_AUDIO_SOURCE)
             {
-
-#if (BTA_AV_SINK_INCLUDED == TRUE)
-            if(index == 1)
+                cs.tsep = AVDT_TSEP_SRC;
+                index = 0;
+            }
+            else if (profile_initialized == UUID_SERVCLASS_AUDIO_SINK)
             {
                 cs.tsep = AVDT_TSEP_SNK;
                 cs.p_data_cback = bta_av_stream_data_cback;
+                index = 1;
             }
-                APPL_TRACE_DEBUG(" SEP Type = %d",cs.tsep);
-#endif
+
+            /* Initialize Handles to zero */
+            for (int xx=0; xx < BTA_AV_MAX_SEPS; xx++)
+            {
+                p_scb->seps[xx].av_handle = 0;
+            }
+
+            /* keep the configuration in the stream control block */
+            memcpy(&p_scb->cfg, &cs.cfg, sizeof(tAVDT_CFG));
+            if ((*bta_av_a2d_cos.init)(&codec_type, cs.cfg.codec_info,
+                &cs.cfg.num_protect, cs.cfg.protect_info, index) == TRUE)
+            {
                 if(AVDT_CreateStream(&p_scb->seps[index].av_handle, &cs) == AVDT_SUCCESS)
                 {
                     p_scb->seps[index].codec_type = codec_type;
-
-#if (BTA_AV_SINK_INCLUDED == TRUE)
                     p_scb->seps[index].tsep = cs.tsep;
                     if(cs.tsep == AVDT_TSEP_SNK)
                         p_scb->seps[index].p_app_data_cback = p_data->api_reg.p_app_data_cback;
                     else
                         p_scb->seps[index].p_app_data_cback = NULL; /* In case of A2DP SOURCE we don't need a callback to handle media packets */
-#endif
 
-                    APPL_TRACE_DEBUG("audio[%d] av_handle: %d codec_type: %d",
-                        index, p_scb->seps[index].av_handle, p_scb->seps[index].codec_type);
-                    index++;
                 }
-                else
-                    break;
             }
 
             if(!bta_av_cb.reg_audio)
             {
-                /* create the SDP records on the 1st audio channel */
-                bta_av_cb.sdp_a2d_handle = SDP_CreateRecord();
-                A2D_AddRecord(UUID_SERVCLASS_AUDIO_SOURCE, p_service_name, NULL,
+                bta_av_cb.sdp_a2d_handle = 0;
+#if (BTA_AV_SINK_INCLUDED == TRUE)
+                bta_av_cb.sdp_a2d_snk_handle = 0;
+#endif
+                if (profile_initialized == UUID_SERVCLASS_AUDIO_SOURCE)
+                {
+                    /* create the SDP records on the 1st audio channel */
+                    bta_av_cb.sdp_a2d_handle = SDP_CreateRecord();
+                    A2D_AddRecord(UUID_SERVCLASS_AUDIO_SOURCE, p_service_name, NULL,
                                   A2D_SUPF_PLAYER, bta_av_cb.sdp_a2d_handle);
-                bta_sys_add_uuid(UUID_SERVCLASS_AUDIO_SOURCE);
-
+                    bta_sys_add_uuid(UUID_SERVCLASS_AUDIO_SOURCE);
+                }
+                else if (profile_initialized == UUID_SERVCLASS_AUDIO_SINK)
+                {
 #if (BTA_AV_SINK_INCLUDED == TRUE)
-                bta_av_cb.sdp_a2d_snk_handle = SDP_CreateRecord();
-                A2D_AddRecord(UUID_SERVCLASS_AUDIO_SINK, p_avk_service_name, NULL,
+                    bta_av_cb.sdp_a2d_snk_handle = SDP_CreateRecord();
+                    A2D_AddRecord(UUID_SERVCLASS_AUDIO_SINK, p_service_name, NULL,
                                   A2D_SUPF_PLAYER, bta_av_cb.sdp_a2d_snk_handle);
-                bta_sys_add_uuid(UUID_SERVCLASS_AUDIO_SINK);
+                    bta_sys_add_uuid(UUID_SERVCLASS_AUDIO_SINK);
 #endif
+                }
                 /* start listening when A2DP is registered */
                 if (bta_av_cb.features & BTA_AV_FEAT_RCTG)
                     bta_av_rc_create(&bta_av_cb, AVCT_ACP, 0, BTA_AV_NUM_LINKS + 1);
@@ -718,11 +736,12 @@ static void bta_av_api_register(tBTA_AV_DATA *p_data)
                                         (UINT8)(bta_av_cb.sec_mask & (~BTA_SEC_AUTHORIZE)), BTA_ID_AV);
 #endif
 #endif
+                        bta_av_rc_create(&bta_av_cb, AVCT_ACP, 0, BTA_AV_NUM_LINKS + 1);
                     }
 #if( defined BTA_AR_INCLUDED ) && (BTA_AR_INCLUDED == TRUE)
                     /* create an SDP record as AVRC CT. */
                     bta_ar_reg_avrc(UUID_SERVCLASS_AV_REMOTE_CONTROL, NULL, NULL,
-                           p_bta_av_cfg->avrc_ct_cat, BTA_ID_AV);
+                    p_bta_av_cfg->avrc_ct_cat, BTA_ID_AV,(bta_av_cb.features & BTA_AV_FEAT_BROWSE));
 #endif
                 }
             }
index b451cb4..f9c35ff 100644 (file)
@@ -119,7 +119,8 @@ extern void bta_ar_dereg_avct(tBTA_SYS_ID sys_id);
 **
 ******************************************************************************/
 extern void bta_ar_reg_avrc(UINT16 service_uuid, char *p_service_name,
-                                                        char *p_provider_name, UINT16 categories, tBTA_SYS_ID sys_id);
+                            char *p_provider_name, UINT16 categories, tBTA_SYS_ID sys_id,
+                            BOOLEAN browse_supported);
 
 /******************************************************************************
 **
index 8b92d30..04ba603 100644 (file)
@@ -64,6 +64,7 @@ typedef UINT8 tBTA_AV_STATUS;
 #define BTA_AV_FEAT_ADV_CTRL    0x0200  /* remote control Advanced Control command/response */
 #define BTA_AV_FEAT_DELAY_RPT   0x0400  /* allow delay reporting */
 #define BTA_AV_FEAT_ACP_START   0x0800  /* start stream when 2nd SNK was accepted   */
+#define BTA_AV_FEAT_APP_SETTING 0x2000  /* Player app setting support */
 
 /* Internal features */
 #define BTA_AV_FEAT_NO_SCO_SSPD 0x8000  /* Do not suspend av streaming as to AG events(SCO or Call) */
@@ -363,6 +364,7 @@ typedef struct
 {
     UINT8           rc_handle;
     tBTA_AV_FEAT    peer_features;
+    BD_ADDR         peer_addr;
 } tBTA_AV_RC_FEAT;
 
 /* data associated with BTA_AV_REMOTE_CMD_EVT */
@@ -452,11 +454,17 @@ typedef union
     tBTA_AV_STATUS      status;
 } tBTA_AV;
 
+typedef struct
+{
+    UINT8 *codec_info;
+    BD_ADDR bd_addr;;
+} tBTA_AVK_CONFIG;
+
 /* union of data associated with AV Media callback */
 typedef union
 {
     BT_HDR     *p_data;
-    UINT8      *codec_info;
+    tBTA_AVK_CONFIG avk_config;
 } tBTA_AV_MEDIA;
 
 
@@ -562,7 +570,7 @@ void BTA_AvDisable(void);
 **
 *******************************************************************************/
 void BTA_AvRegister(tBTA_AV_CHNL chnl, const char *p_service_name,
-                            UINT8 app_id, tBTA_AV_DATA_CBACK  *p_data_cback);
+                    UINT8 app_id, tBTA_AV_DATA_CBACK  *p_data_cback, UINT16 service_uuid);
 
 /*******************************************************************************
 **
@@ -704,6 +712,20 @@ void BTA_AvRemoteCmd(UINT8 rc_handle, UINT8 label, tBTA_AV_RC rc_id,
 
 /*******************************************************************************
 **
+** Function         BTA_AvRemoteVendorUniqueCmd
+**
+** Description      Send a remote control command with Vendor Unique rc_id.
+**                  This function can only be used if AV is enabled with
+**                  feature BTA_AV_FEAT_RCCT.
+**
+** Returns          void
+**
+*******************************************************************************/
+void BTA_AvRemoteVendorUniqueCmd(UINT8 rc_handle, UINT8 label, tBTA_AV_STATE key_state,
+                                         UINT8* p_msg, UINT8 buf_len);
+
+/*******************************************************************************
+**
 ** Function         BTA_AvVendorCmd
 **
 ** Description      Send a vendor dependent remote control command.  This
index 75bfebf..273fb2f 100644 (file)
@@ -30,6 +30,8 @@
 #ifndef BTIF_API_H
 #define BTIF_API_H
 
+#include <hardware/bluetooth.h>
+
 #include "btif_common.h"
 #include "btif_dm.h"
 
index 4b116ee..2f245ed 100644 (file)
@@ -46,6 +46,8 @@ typedef enum {
     BTIF_AV_SUSPEND_STREAM_REQ_EVT,
     BTIF_AV_SINK_CONFIG_REQ_EVT,
     BTIF_AV_OFFLOAD_START_REQ_EVT,
+    BTIF_AV_SINK_FOCUS_REQ_EVT,
+    BTIF_AV_CLEANUP_REQ_EVT,
 } btif_av_sm_event_t;
 
 
@@ -112,7 +114,7 @@ void btif_dispatch_sm_event(btif_av_sm_event_t event, void *p_data, int len);
 **
 *******************************************************************************/
 
-bt_status_t btif_av_init(void);
+bt_status_t btif_av_init(int service_id);
 
 /*******************************************************************************
 **
@@ -142,6 +144,31 @@ BOOLEAN btif_av_is_connected(void);
 
 BOOLEAN btif_av_is_peer_edr(void);
 
+#ifdef USE_AUDIO_TRACK
+/*******************************************************************************
+**
+** Function         audio_focus_status
+**
+** Description      Update Audio Focus State
+**
+** Returns          None
+**
+*******************************************************************************/
+void audio_focus_status(int state);
+
+/*******************************************************************************
+**
+** Function         btif_queue_focus_request
+**
+** Description      This is used to move context to btif and
+**                  queue audio_focus_request
+**
+** Returns          none
+**
+*******************************************************************************/
+void btif_queue_focus_request(void);
+#endif
+
 /******************************************************************************
 **
 ** Function         btif_av_clear_remote_suspend_flag
diff --git a/btif/include/btif_avrcp_audio_track.h b/btif/include/btif_avrcp_audio_track.h
new file mode 100644 (file)
index 0000000..407732a
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * 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.
+ */
+
+#if defined (__cplusplus) || (cplusplus)
+extern "C" {
+#endif
+
+/**
+ * Implements an API to be used by A2DP to do streaming of music over a media
+ * stream. This API provides mechanism to create and control playback of the
+ * media stream depending on the data bits coming from the remote device. The
+ * media stream is played over the default audio media stream type and hence
+ * volume control is handled entirely by the Audio Manager (which is also the
+ * original motivation for this solution.
+ *
+ * TODO: Once the AudioManager provides support for patching audio sources with
+ * volume control we should deprecate this file.
+ */
+
+/**
+ * Creates an audio track object and returns a void handle. Use this handle to the
+ * following functions.
+ *
+ * The ownership of the handle is maintained by the caller of this API and it should eventually be
+ * deleted using BtifAvrcpAudioTrackDelete (see below).
+ */
+void* BtifAvrcpAudioTrackCreate(int trackFreq, int channelType);
+
+/**
+ * Starts the audio track.
+ */
+void BtifAvrcpAudioTrackStart(void *handle);
+
+/**
+ * Pauses the audio track.
+ */
+void BtifAvrcpAudioTrackPause(void *handle);
+
+/**
+ * Stop / Delete the audio track.
+ * Delete should usually be called stop.
+ */
+void BtifAvrcpAudioTrackStop(void *handle);
+void BtifAvrcpAudioTrackDelete(void *handle);
+
+/**
+ * Writes the audio track data to file.
+ *
+ * Used only for debugging.
+ */
+int BtifAvrcpAudioTrackWriteData(void *handle, void *audioBuffer, int bufferlen);
+
+#if defined (__cplusplus) || (cplusplus)
+}
+#endif
index 9602d6a..2bf0e8d 100644 (file)
@@ -99,6 +99,21 @@ typedef struct
 } tBTIF_MEDIA_SINK_CFG_UPDATE;
 #endif
 
+#ifdef USE_AUDIO_TRACK
+typedef enum {
+        BTIF_MEDIA_FOCUS_IDLE = 0,
+        BTIF_MEDIA_FOCUS_READY,
+        BTIF_MEDIA_FOCUS_REQUESTED,
+        BTIF_MEDIA_FOCUS_GRANTED
+} btif_media_audio_focus_state;
+
+typedef struct
+{
+        BT_HDR hdr;
+        UINT8 focus_state;
+} tBTIF_MEDIA_SINK_FOCUS_UPDATE;
+#endif
+
 /*******************************************************************************
  **  Public functions
  *******************************************************************************/
@@ -280,5 +295,7 @@ void btif_a2dp_on_offload_started(tBTA_AV_STATUS status);
 int btif_a2dp_get_track_frequency(UINT8 frequency);
 int btif_a2dp_get_track_channel_count(UINT8 channeltype);
 void btif_a2dp_set_peer_sep(UINT8 sep);
-
+#ifdef USE_AUDIO_TRACK
+void btif_a2dp_set_audio_focus_state(btif_media_audio_focus_state state);
+#endif
 #endif
index f8e7771..ff3c8c2 100644 (file)
@@ -38,6 +38,7 @@
 **  Constants & Macros
 ******************************************************************************/
 #define BTIF_AV_SERVICE_NAME "Advanced Audio"
+#define BTIF_AVK_SERVICE_NAME "Advanced Audio Sink"
 
 #define BTIF_TIMEOUT_AV_OPEN_ON_RC_SECS  2
 
@@ -83,6 +84,7 @@ typedef struct
 {
     int sample_rate;
     int channel_count;
+    bt_bdaddr_t peer_bd;
 } btif_av_sink_config_req_t;
 
 /*****************************************************************************
@@ -140,6 +142,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 BOOLEAN btif_rc_get_connected_peer(BD_ADDR peer_addr);
+extern UINT8 btif_rc_get_connected_peer_handle(void);
 extern void btif_rc_check_handle_pending_play (BD_ADDR peer_addr, BOOLEAN bSendToApp);
 
 /*****************************************************************************
@@ -193,6 +196,9 @@ const char *dump_av_sm_event_name(btif_av_sm_event_t event)
         CASE_RETURN_STR(BTIF_AV_SUSPEND_STREAM_REQ_EVT)
         CASE_RETURN_STR(BTIF_AV_SINK_CONFIG_REQ_EVT)
         CASE_RETURN_STR(BTIF_AV_OFFLOAD_START_REQ_EVT)
+#ifdef USE_AUDIO_TRACK
+        CASE_RETURN_STR(BTIF_AV_SINK_FOCUS_REQ_EVT)
+#endif
         default: return "UNKNOWN_EVENT";
    }
 }
@@ -221,7 +227,10 @@ static void btif_initiate_av_open_tmr_hdlr(timer_entry_t *p_te)
        BTIF_TRACE_DEBUG("%s Issuing connect to the remote RC peer", __FUNCTION__);
        /* In case of AVRCP connection request, we will initiate SRC connection */
        connect_req.target_bda = (bt_bdaddr_t*)&peer_addr;
-       connect_req.uuid = UUID_SERVCLASS_AUDIO_SOURCE;
+       if(bt_av_sink_callbacks != NULL)
+           connect_req.uuid = UUID_SERVCLASS_AUDIO_SINK;
+       else if(bt_av_src_callbacks != NULL)
+           connect_req.uuid = UUID_SERVCLASS_AUDIO_SOURCE;
        btif_sm_dispatch(btif_av_cb.sm_handle, BTIF_AV_CONNECT_REQ_EVT, (char*)&connect_req);
     }
     else
@@ -300,8 +309,16 @@ static BOOLEAN btif_av_state_idle_handler(btif_sm_event_t event, void *p_data)
              else if (event == BTA_AV_PENDING_EVT)
              {
                   bdcpy(btif_av_cb.peer_bda.address, ((tBTA_AV*)p_data)->pend.bd_addr);
-                  BTA_AvOpen(btif_av_cb.peer_bda.address, btif_av_cb.bta_handle,
-                    TRUE, BTA_SEC_AUTHENTICATE, UUID_SERVCLASS_AUDIO_SOURCE);
+                  if (bt_av_src_callbacks != NULL)
+                  {
+                      BTA_AvOpen(btif_av_cb.peer_bda.address, btif_av_cb.bta_handle,
+                        TRUE, BTA_SEC_AUTHENTICATE, UUID_SERVCLASS_AUDIO_SOURCE);
+                  }
+                  if (bt_av_sink_callbacks != NULL)
+                  {
+                      BTA_AvOpen(btif_av_cb.peer_bda.address, btif_av_cb.bta_handle,
+                                 TRUE, BTA_SEC_AUTHENTICATE, UUID_SERVCLASS_AUDIO_SINK);
+                  }
              }
              btif_sm_change_state(btif_av_cb.sm_handle, BTIF_AV_STATE_OPENING);
         } break;
@@ -325,6 +342,72 @@ static BOOLEAN btif_av_state_idle_handler(btif_sm_event_t event, void *p_data)
             btif_rc_handler(event, p_data);
             break;
 
+           /*
+            * In case Signalling channel is not down
+            * and remote started Streaming Procedure
+            * we have to handle config and open event in
+            * idle_state. We hit these scenarios while running
+            * PTS test case for AVRCP Controller
+            */
+        case BTIF_AV_SINK_CONFIG_REQ_EVT:
+        {
+            btif_av_sink_config_req_t req;
+            // copy to avoid alignment problems
+            memcpy(&req, p_data, sizeof(req));
+
+            BTIF_TRACE_WARNING("BTIF_AV_SINK_CONFIG_REQ_EVT %d %d", req.sample_rate,
+                    req.channel_count);
+            if (bt_av_sink_callbacks != NULL) {
+                HAL_CBACK(bt_av_sink_callbacks, audio_config_cb, &(req.peer_bd),
+                        req.sample_rate, req.channel_count);
+            }
+        } break;
+
+        case BTA_AV_OPEN_EVT:
+        {
+            tBTA_AV *p_bta_data = (tBTA_AV*)p_data;
+            btav_connection_state_t state;
+            btif_sm_state_t av_state;
+            BTIF_TRACE_DEBUG("status:%d, edr 0x%x",p_bta_data->open.status,
+                               p_bta_data->open.edr);
+
+            if (p_bta_data->open.status == BTA_AV_SUCCESS)
+            {
+                 state = BTAV_CONNECTION_STATE_CONNECTED;
+                 av_state = BTIF_AV_STATE_OPENED;
+                 btif_av_cb.edr = p_bta_data->open.edr;
+
+                 btif_av_cb.peer_sep = p_bta_data->open.sep;
+                 btif_a2dp_set_peer_sep(p_bta_data->open.sep);
+            }
+            else
+            {
+                BTIF_TRACE_WARNING("BTA_AV_OPEN_EVT::FAILED status: %d",
+                                     p_bta_data->open.status );
+                state = BTAV_CONNECTION_STATE_DISCONNECTED;
+                av_state  = BTIF_AV_STATE_IDLE;
+            }
+
+            /* inform the application of the event */
+            btif_report_connection_state(state, &(btif_av_cb.peer_bda));
+            /* change state to open/idle based on the status */
+            btif_sm_change_state(btif_av_cb.sm_handle, av_state);
+            if (btif_av_cb.peer_sep == AVDT_TSEP_SNK)
+            {
+                /* if queued PLAY command,  send it now */
+                btif_rc_check_handle_pending_play(p_bta_data->open.bd_addr,
+                                             (p_bta_data->open.status == BTA_AV_SUCCESS));
+            }
+            else if (btif_av_cb.peer_sep == AVDT_TSEP_SRC)
+            {
+                /* if queued PLAY command,  send it now */
+                btif_rc_check_handle_pending_play(p_bta_data->open.bd_addr, FALSE);
+                /* Bring up AVRCP connection too */
+                BTA_AvOpenRc(btif_av_cb.bta_handle);
+            }
+            btif_queue_advance();
+        } break;
+
         case BTA_AV_REMOTE_CMD_EVT:
         case BTA_AV_VENDOR_CMD_EVT:
         case BTA_AV_META_MSG_EVT:
@@ -408,6 +491,17 @@ static BOOLEAN 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;
+                if ((btif_rc_get_connected_peer(peer_addr))
+                    &&(!bdcmp(btif_av_cb.peer_bda.address, peer_addr)))
+                {
+                    /*
+                     * Disconnect AVRCP connection, if
+                     * A2DP conneciton failed, for any reason
+                     */
+                    BTIF_TRACE_WARNING(" Disconnecting AVRCP ");
+                    BTA_AvCloseRc(btif_rc_get_connected_peer_handle());
+                }
                 state = BTAV_CONNECTION_STATE_DISCONNECTED;
                 av_state  = BTIF_AV_STATE_IDLE;
             }
@@ -650,6 +744,9 @@ static BOOLEAN btif_av_state_opened_handler(btif_sm_event_t event, void *p_data)
             if (btif_av_cb.peer_sep == AVDT_TSEP_SRC)
             {
                 btif_a2dp_set_rx_flush(FALSE); /*  remove flush state, ready for streaming*/
+#ifdef USE_AUDIO_TRACK
+                audio_focus_status(BTIF_MEDIA_FOCUS_READY);
+#endif
             }
 
             /* change state to started, send acknowledgement if start is pending */
@@ -861,6 +958,13 @@ static BOOLEAN btif_av_state_started_handler(btif_sm_event_t event, void *p_data
             btif_av_cb.flags &= ~BTIF_AV_FLAG_LOCAL_SUSPEND_PENDING;
             break;
 
+#ifdef USE_AUDIO_TRACK
+            case BTIF_AV_SINK_FOCUS_REQ_EVT:
+                HAL_CBACK(bt_av_sink_callbacks, audio_focus_request_cb,
+                                                   &(btif_av_cb.peer_bda));
+            break;
+#endif
+
         case BTA_AV_STOP_EVT:
 
             btif_av_cb.flags |= BTIF_AV_FLAG_PENDING_STOP;
@@ -913,8 +1017,17 @@ static BOOLEAN btif_av_state_started_handler(btif_sm_event_t event, void *p_data
 
 static void btif_av_handle_event(UINT16 event, char* p_param)
 {
-    btif_sm_dispatch(btif_av_cb.sm_handle, event, (void*)p_param);
-    btif_av_event_free_data(event, p_param);
+    switch(event)
+    {
+        case BTIF_AV_CLEANUP_REQ_EVT:
+            BTIF_TRACE_EVENT("%s: BTIF_AV_CLEANUP_REQ_EVT", __FUNCTION__);
+            btif_a2dp_stop_media_task();
+            break;
+
+        default:
+            btif_sm_dispatch(btif_av_cb.sm_handle, event, (void*)p_param);
+            btif_av_event_free_data(event, p_param);
+    }
 }
 
 void btif_av_event_deep_copy(UINT16 event, char *p_dest, char *p_src)
@@ -1012,13 +1125,14 @@ static void bte_av_media_callback(tBTA_AV_EVT event, tBTA_AV_MEDIA *p_data)
 
     if (event == BTA_AV_MEDIA_SINK_CFG_EVT) {
         /* send a command to BT Media Task */
-        btif_reset_decoder((UINT8*)p_data);
-
-        a2d_status = A2D_ParsSbcInfo(&sbc_cie, (UINT8 *)p_data, FALSE);
+        btif_reset_decoder((UINT8*)(p_data->avk_config.codec_info));
+        a2d_status = A2D_ParsSbcInfo(&sbc_cie, (UINT8 *)(p_data->avk_config.codec_info), FALSE);
         if (a2d_status == A2D_SUCCESS) {
             /* Switch to BTIF context */
             config_req.sample_rate = btif_a2dp_get_track_frequency(sbc_cie.samp_freq);
             config_req.channel_count = btif_a2dp_get_track_channel_count(sbc_cie.ch_mode);
+            memcpy(&config_req.peer_bd,(UINT8*)(p_data->avk_config.bd_addr),
+                                                              sizeof(config_req.peer_bd));
             btif_transfer_context(btif_av_handle_event, BTIF_AV_SINK_CONFIG_REQ_EVT,
                                      (char*)&config_req, sizeof(config_req), NULL);
         } else {
@@ -1036,22 +1150,19 @@ static void bte_av_media_callback(tBTA_AV_EVT event, tBTA_AV_MEDIA *p_data)
 **
 *******************************************************************************/
 
-bt_status_t btif_av_init()
+bt_status_t btif_av_init(int service_id)
 {
     if (btif_av_cb.sm_handle == NULL)
     {
         if (!btif_a2dp_start_media_task())
             return BT_STATUS_FAIL;
 
+        btif_enable_service(service_id);
+
         /* Also initialize the AV state machine */
         btif_av_cb.sm_handle =
                 btif_sm_init((const btif_sm_handler_t*)btif_av_state_handlers, BTIF_AV_STATE_IDLE);
 
-        btif_enable_service(BTA_A2DP_SOURCE_SERVICE_ID);
-#if (BTA_AV_SINK_INCLUDED == TRUE)
-        btif_enable_service(BTA_A2DP_SINK_SERVICE_ID);
-#endif
-
         btif_a2dp_on_init();
     }
 
@@ -1072,7 +1183,7 @@ static bt_status_t init_src(btav_callbacks_t* callbacks)
 {
     BTIF_TRACE_EVENT("%s()", __func__);
 
-    bt_status_t status = btif_av_init();
+    bt_status_t status = btif_av_init(BTA_A2DP_SOURCE_SERVICE_ID);
     if (status == BT_STATUS_SUCCESS)
         bt_av_src_callbacks = callbacks;
 
@@ -1093,13 +1204,44 @@ static bt_status_t init_sink(btav_callbacks_t* callbacks)
 {
     BTIF_TRACE_EVENT("%s()", __func__);
 
-    bt_status_t status = btif_av_init();
+    bt_status_t status = btif_av_init(BTA_A2DP_SINK_SERVICE_ID);
     if (status == BT_STATUS_SUCCESS)
         bt_av_sink_callbacks = callbacks;
 
     return status;
 }
 
+#ifdef USE_AUDIO_TRACK
+/*******************************************************************************
+**
+** Function         audio_focus_status
+**
+** Description      Update Audio Focus State
+**
+** Returns          None
+**
+*******************************************************************************/
+void audio_focus_status(int state)
+{
+    BTIF_TRACE_DEBUG("%s state %d ",__func__, state);
+    btif_a2dp_set_audio_focus_state(state);
+}
+
+/*******************************************************************************
+**
+** Function         btif_queue_focus_request
+**
+** Description      This is used to move context to btif and queue audio_focus_request
+**
+** Returns          none
+**
+*******************************************************************************/
+void btif_queue_focus_request(void)
+{
+    btif_transfer_context(btif_av_handle_event, BTIF_AV_SINK_FOCUS_REQ_EVT, NULL, 0, NULL);
+}
+#endif
+
 /*******************************************************************************
 **
 ** Function         connect
@@ -1167,16 +1309,13 @@ static bt_status_t disconnect(bt_bdaddr_t *bd_addr)
 ** Returns          None
 **
 *******************************************************************************/
-static void cleanup(void)
+static void cleanup(int service_uuid)
 {
     BTIF_TRACE_EVENT("%s", __FUNCTION__);
 
-    btif_a2dp_stop_media_task();
+    btif_transfer_context(btif_av_handle_event, BTIF_AV_CLEANUP_REQ_EVT, NULL, 0, NULL);
 
-    btif_disable_service(BTA_A2DP_SOURCE_SERVICE_ID);
-#if (BTA_AV_SINK_INCLUDED == TRUE)
-    btif_disable_service(BTA_A2DP_SINK_SERVICE_ID);
-#endif
+    btif_disable_service(service_uuid);
 
     /* Also shut down the AV state machine */
     btif_sm_shutdown(btif_av_cb.sm_handle);
@@ -1190,7 +1329,7 @@ static void cleanup_src(void) {
     {
         bt_av_src_callbacks = NULL;
         if (bt_av_sink_callbacks == NULL)
-            cleanup();
+            cleanup(BTA_A2DP_SOURCE_SERVICE_ID);
     }
 }
 
@@ -1201,7 +1340,7 @@ static void cleanup_sink(void) {
     {
         bt_av_sink_callbacks = NULL;
         if (bt_av_src_callbacks == NULL)
-            cleanup();
+            cleanup(BTA_A2DP_SINK_SERVICE_ID);
     }
 }
 
@@ -1211,6 +1350,7 @@ static const btav_interface_t bt_av_src_interface = {
     src_connect_sink,
     disconnect,
     cleanup_src,
+    NULL,
 };
 
 static const btav_interface_t bt_av_sink_interface = {
@@ -1219,6 +1359,11 @@ static const btav_interface_t bt_av_sink_interface = {
     sink_connect_src,
     disconnect,
     cleanup_sink,
+#ifdef USE_AUDIO_TRACK
+    audio_focus_status,
+#else
+    NULL,
+#endif
 };
 
 /*******************************************************************************
@@ -1330,19 +1475,23 @@ bt_status_t btif_av_execute_service(BOOLEAN b_enable)
          /* Added BTA_AV_FEAT_NO_SCO_SSPD - this ensures that the BTA does not
           * auto-suspend av streaming on AG events(SCO or Call). The suspend shall
           * be initiated by the app/audioflinger layers */
+         /* Support for browsing for SDP record should work only if we enable BROWSE
+          * while registering. */
 #if (AVRC_METADATA_INCLUDED == TRUE)
          BTA_AvEnable(BTA_SEC_AUTHENTICATE,
              BTA_AV_FEAT_RCTG|BTA_AV_FEAT_METADATA|BTA_AV_FEAT_VENDOR|BTA_AV_FEAT_NO_SCO_SSPD
 #if (AVRC_ADV_CTRL_INCLUDED == TRUE)
              |BTA_AV_FEAT_RCCT
              |BTA_AV_FEAT_ADV_CTRL
+             |BTA_AV_FEAT_BROWSE
 #endif
              ,bte_av_callback);
 #else
          BTA_AvEnable(BTA_SEC_AUTHENTICATE, (BTA_AV_FEAT_RCTG | BTA_AV_FEAT_NO_SCO_SSPD),
                       bte_av_callback);
 #endif
-         BTA_AvRegister(BTA_AV_CHNL_AUDIO, BTIF_AV_SERVICE_NAME, 0, bte_av_media_callback);
+         BTA_AvRegister(BTA_AV_CHNL_AUDIO, BTIF_AV_SERVICE_NAME, 0, bte_av_media_callback,
+                                                             UUID_SERVCLASS_AUDIO_SOURCE);
      }
      else {
          BTA_AvDeregister(btif_av_cb.bta_handle);
@@ -1362,10 +1511,23 @@ bt_status_t btif_av_execute_service(BOOLEAN b_enable)
 *******************************************************************************/
 bt_status_t btif_av_sink_execute_service(BOOLEAN b_enable)
 {
-#if (BTA_AV_SINK_INCLUDED == TRUE)
-    BTA_AvEnable_Sink(b_enable);
-#endif
-    return BT_STATUS_SUCCESS;
+     if (b_enable)
+     {
+         /* Added BTA_AV_FEAT_NO_SCO_SSPD - this ensures that the BTA does not
+          * auto-suspend av streaming on AG events(SCO or Call). The suspend shall
+          * 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,
+                                                                        bte_av_callback);
+         BTA_AvRegister(BTA_AV_CHNL_AUDIO, BTIF_AVK_SERVICE_NAME, 0, bte_av_media_callback,
+                                                                UUID_SERVCLASS_AUDIO_SINK);
+     }
+     else {
+         BTA_AvDeregister(btif_av_cb.bta_handle);
+         BTA_AvDisable();
+     }
+     return BT_STATUS_SUCCESS;
 }
 
 /*******************************************************************************
diff --git a/btif/src/btif_avrcp_audio_track.cpp b/btif/src/btif_avrcp_audio_track.cpp
new file mode 100644 (file)
index 0000000..222b6c9
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#include "btif_avrcp_audio_track.h"
+
+#include <media/AudioTrack.h>
+#include <utils/StrongPointer.h>
+
+#include "osi/include/log.h"
+
+using namespace android;
+
+typedef struct {
+    android::sp<android::AudioTrack> track;
+} BtifAvrcpAudioTrack;
+
+//#define DUMP_PCM_DATA TRUE
+#if (defined(DUMP_PCM_DATA) && (DUMP_PCM_DATA == TRUE))
+FILE *outputPcmSampleFile;
+char outputFilename[50] = "/data/misc/bluedroid/output_sample.pcm";
+#endif
+
+void *BtifAvrcpAudioTrackCreate(int trackFreq, int channelType)
+{
+    LOG_VERBOSE(LOG_TAG, "%s Track.cpp: btCreateTrack freq %d  channel %d ",
+                     __func__, trackFreq, channelType);
+    int ret = -1;
+    sp<android::AudioTrack> track =
+        new android::AudioTrack(AUDIO_STREAM_MUSIC, trackFreq, AUDIO_FORMAT_PCM_16_BIT,
+                                channelType, (int)0, (audio_output_flags_t)AUDIO_OUTPUT_FLAG_FAST,
+                                NULL, NULL, 0, 0, android::AudioTrack::TRANSFER_SYNC);
+    assert(track != NULL);
+
+    BtifAvrcpAudioTrack *trackHolder = new BtifAvrcpAudioTrack;
+    assert(trackHolder);
+    trackHolder->track = track;
+
+    if (trackHolder->track->initCheck() != 0)
+    {
+        return nullptr;
+    }
+
+#if (defined(DUMP_PCM_DATA) && (DUMP_PCM_DATA == TRUE))
+    outputPcmSampleFile = fopen(outputFilename, "ab");
+#endif
+    trackHolder->track->setVolume(1, 1);
+    return (void *)trackHolder;
+}
+
+void BtifAvrcpAudioTrackStart(void *handle)
+{
+    BtifAvrcpAudioTrack *trackHolder = static_cast<BtifAvrcpAudioTrack*>(handle);
+    assert(trackHolder);
+    assert(trackHolder->track != NULL);
+    LOG_VERBOSE(LOG_TAG, "%s Track.cpp: btStartTrack", __func__);
+    trackHolder->track->start();
+}
+
+void BtifAvrcpAudioTrackStop(void *handle)
+{
+    BtifAvrcpAudioTrack *trackHolder = static_cast<BtifAvrcpAudioTrack*>(handle);
+    if (trackHolder != NULL && trackHolder->track != NULL) {
+        LOG_VERBOSE(LOG_TAG, "%s Track.cpp: btStartTrack", __func__);
+        trackHolder->track->stop();
+    }
+}
+
+void BtifAvrcpAudioTrackDelete(void *handle)
+{
+    BtifAvrcpAudioTrack *trackHolder = static_cast<BtifAvrcpAudioTrack*>(handle);
+    if (trackHolder != NULL && trackHolder->track != NULL) {
+        LOG_VERBOSE(LOG_TAG, "%s Track.cpp: btStartTrack", __func__);
+        delete trackHolder;
+    }
+
+#if (defined(DUMP_PCM_DATA) && (DUMP_PCM_DATA == TRUE))
+    if (outputPcmSampleFile)
+    {
+        fclose(outputPcmSampleFile);
+    }
+    outputPcmSampleFile = NULL;
+#endif
+}
+
+void BtifAvrcpAudioTrackPause(void *handle)
+{
+    BtifAvrcpAudioTrack *trackHolder = static_cast<BtifAvrcpAudioTrack*>(handle);
+    if (trackHolder != NULL && trackHolder->track != NULL) {
+        LOG_VERBOSE(LOG_TAG, "%s Track.cpp: btStartTrack", __func__);
+        trackHolder->track->pause();
+        trackHolder->track->flush();
+    }
+}
+
+int BtifAvrcpAudioTrackWriteData(void *handle, void *audioBuffer, int bufferlen)
+{
+    BtifAvrcpAudioTrack *trackHolder = static_cast<BtifAvrcpAudioTrack*>(handle);
+    assert(trackHolder);
+    assert(trackHolder->track != NULL);
+    int retval = -1;
+#if (defined(DUMP_PCM_DATA) && (DUMP_PCM_DATA == TRUE))
+    if (outputPcmSampleFile)
+    {
+        fwrite ((audioBuffer), 1, (size_t)bufferlen, outputPcmSampleFile);
+    }
+#endif
+    retval = trackHolder->track->write(audioBuffer, (size_t)bufferlen);
+    LOG_VERBOSE(LOG_TAG, "%s Track.cpp: btWriteData len = %d ret = %d",
+                     __func__, bufferlen, retval);
+    return retval;
+}
index 772bdce..2eefcb1 100644 (file)
@@ -29,8 +29,6 @@
 #define LOG_TAG "bt_btif_media"
 
 #include <assert.h>
-#include <dlfcn.h>
-#include <errno.h>
 #include <fcntl.h>
 #include <pthread.h>
 #include <stdint.h>
 #include "oi_status.h"
 #endif
 
+#ifdef USE_AUDIO_TRACK
+#include "btif_avrcp_audio_track.h"
+#endif
+
 #if (BTA_AV_SINK_INCLUDED == TRUE)
 OI_CODEC_SBC_DECODER_CONTEXT context;
 OI_UINT32 contextData[CODEC_DATA_WORDS(2, SBC_CODEC_FAST_FILTER_BUFFERS)];
@@ -113,7 +115,8 @@ enum
     BTIF_MEDIA_AUDIO_FEEDING_INIT,
     BTIF_MEDIA_AUDIO_RECEIVING_INIT,
     BTIF_MEDIA_AUDIO_SINK_CFG_UPDATE,
-    BTIF_MEDIA_AUDIO_SINK_CLEAR_TRACK
+    BTIF_MEDIA_AUDIO_SINK_CLEAR_TRACK,
+    BTIF_MEDIA_AUDIO_SINK_SET_FOCUS_STATE
 };
 
 enum {
@@ -240,6 +243,10 @@ typedef struct
 
     UINT32  sample_rate;
     UINT8   channel_count;
+#ifdef USE_AUDIO_TRACK
+    btif_media_audio_focus_state rx_audio_focus_state;
+    void *audio_track;
+#endif
     alarm_t *media_alarm;
     alarm_t *decode_alarm;
 #endif
@@ -352,6 +359,7 @@ UNUSED_ATTR static const char *dump_media_event(UINT16 event)
         CASE_RETURN_STR(BTIF_MEDIA_AUDIO_RECEIVING_INIT)
         CASE_RETURN_STR(BTIF_MEDIA_AUDIO_SINK_CFG_UPDATE)
         CASE_RETURN_STR(BTIF_MEDIA_AUDIO_SINK_CLEAR_TRACK)
+        CASE_RETURN_STR(BTIF_MEDIA_AUDIO_SINK_SET_FOCUS_STATE)
 
         default:
             return "UNKNOWN MEDIA EVENT";
@@ -855,6 +863,9 @@ void btif_a2dp_on_idle(void)
         btif_media_task_aa_rx_flush_req();
         btif_media_task_aa_handle_stop_decoding();
         btif_media_task_clear_track();
+#ifdef USE_AUDIO_TRACK
+        btif_media_cb.rx_audio_focus_state = BTIF_MEDIA_FOCUS_IDLE;
+#endif
         APPL_TRACE_DEBUG("Stopped BT track");
     }
 #endif
@@ -1019,7 +1030,9 @@ void btif_a2dp_on_stopped(tBTA_AV_SUSPEND *p_av)
         btif_media_cb.rx_flush = TRUE;
         btif_media_task_aa_rx_flush_req();
         btif_media_task_aa_handle_stop_decoding();
+#ifndef USE_AUDIO_TRACK
         UIPC_Close(UIPC_CH_ID_AV_AUDIO);
+#endif
         btif_media_cb.data_channel_open = FALSE;
         return;
     }
@@ -1065,6 +1078,9 @@ void btif_a2dp_on_suspended(tBTA_AV_SUSPEND *p_av)
         btif_media_cb.rx_flush = TRUE;
         btif_media_task_aa_rx_flush_req();
         btif_media_task_aa_handle_stop_decoding();
+#ifndef USE_AUDIO_TRACK
+        UIPC_Close(UIPC_CH_ID_AV_AUDIO);
+#endif
         return;
     }
 
@@ -1130,6 +1146,23 @@ void btif_a2dp_set_tx_flush(BOOLEAN enable)
     btif_media_cb.tx_flush = enable;
 }
 
+#ifdef USE_AUDIO_TRACK
+void btif_a2dp_set_audio_focus_state(btif_media_audio_focus_state state)
+{
+    APPL_TRACE_EVENT("btif_a2dp_set_audio_focus_state");
+    tBTIF_MEDIA_SINK_FOCUS_UPDATE *p_buf;
+    if (NULL == (p_buf = osi_getbuf(sizeof(tBTIF_MEDIA_SINK_FOCUS_UPDATE))))
+    {
+        APPL_TRACE_EVENT("btif_a2dp_set_audio_focus_state No Buffer ");
+        return;
+    }
+
+    p_buf->focus_state = state;
+    p_buf->hdr.event = BTIF_MEDIA_AUDIO_SINK_SET_FOCUS_STATE;
+    fixed_queue_enqueue(btif_media_cmd_msg_queue, p_buf);
+}
+#endif
+
 #if (BTA_AV_SINK_INCLUDED == TRUE)
 static void btif_media_task_avk_handle_timer(UNUSED_ATTR void *context)
 {
@@ -1143,6 +1176,24 @@ static void btif_media_task_avk_handle_timer(UNUSED_ATTR void *context)
     }
     else
     {
+
+#ifdef USE_AUDIO_TRACK
+        switch(btif_media_cb.rx_audio_focus_state)
+        {
+            /* Don't Do anything in case of Idle, Requested */
+            case BTIF_MEDIA_FOCUS_REQUESTED:
+            case BTIF_MEDIA_FOCUS_IDLE:
+                return;
+            /* In case of Ready, request for focus and wait to move in granted */
+            case BTIF_MEDIA_FOCUS_READY:
+                btif_queue_focus_request();
+                btif_media_cb.rx_audio_focus_state = BTIF_MEDIA_FOCUS_REQUESTED;
+                return;
+            /* play only in this case */
+            case BTIF_MEDIA_FOCUS_GRANTED:
+                break;
+        }
+#endif
         if (btif_media_cb.rx_flush == TRUE)
         {
             btif_media_flush_q(btif_media_cb.RxSbcQ);
@@ -1320,6 +1371,14 @@ static void btif_media_thread_handle_cmd(fixed_queue_t *queue, UNUSED_ATTR void
     case BTIF_MEDIA_UIPC_RX_RDY:
         btif_media_task_aa_handle_uipc_rx_rdy();
         break;
+#ifdef USE_AUDIO_TRACK
+    case BTIF_MEDIA_AUDIO_SINK_SET_FOCUS_STATE:
+        if(!btif_av_is_connected())
+            break;
+        btif_media_cb.rx_audio_focus_state = ((tBTIF_MEDIA_SINK_FOCUS_UPDATE *)p_msg)->focus_state;
+        APPL_TRACE_DEBUG("Setting focus state to %d ",btif_media_cb.rx_audio_focus_state);
+        break;
+#endif
     case BTIF_MEDIA_AUDIO_SINK_CFG_UPDATE:
 #if (BTA_AV_SINK_INCLUDED == TRUE)
         btif_media_task_aa_handle_decoder_reset(p_msg);
@@ -1360,19 +1419,23 @@ static void btif_media_task_handle_inc_media(tBT_SBC_HDR*p_msg)
     OI_STATUS status;
     int num_sbc_frames = p_msg->num_frames_to_be_processed;
     UINT32 sbc_frame_len = p_msg->len - 1;
-    availPcmBytes = 2*sizeof(pcmData);
+    availPcmBytes = sizeof(pcmData);
 
     if ((btif_media_cb.peer_sep == AVDT_TSEP_SNK) || (btif_media_cb.rx_flush))
     {
         APPL_TRACE_DEBUG(" State Changed happened in this tick ");
         return;
     }
-
+#ifndef USE_AUDIO_TRACK
     // ignore data if no one is listening
     if (!btif_media_cb.data_channel_open)
+    {
+        APPL_TRACE_ERROR("%s Channel not open, returning", __func__);
         return;
-
-    APPL_TRACE_DEBUG("Number of sbc frames %d, frame_len %d", num_sbc_frames, sbc_frame_len);
+    }
+#endif
+    APPL_TRACE_DEBUG("%s Number of sbc frames %d, frame_len %d",
+                     __func__, num_sbc_frames, sbc_frame_len);
 
     for(count = 0; count < num_sbc_frames && sbc_frame_len != 0; count ++)
     {
@@ -1391,7 +1454,12 @@ static void btif_media_task_handle_inc_media(tBT_SBC_HDR*p_msg)
         p_msg->len = sbc_frame_len + 1;
     }
 
-    UIPC_Send(UIPC_CH_ID_AV_AUDIO, 0, (UINT8 *)pcmData, (2*sizeof(pcmData) - availPcmBytes));
+#ifdef USE_AUDIO_TRACK
+    BtifAvrcpAudioTrackWriteData(
+        btif_media_cb.audio_track, (void*)pcmData, (sizeof(pcmData) - availPcmBytes));
+#else
+    UIPC_Send(UIPC_CH_ID_AV_AUDIO, 0, (UINT8 *)pcmData, (sizeof(pcmData) - availPcmBytes));
+#endif
 }
 #endif
 
@@ -1971,23 +2039,46 @@ int btif_a2dp_get_track_channel_count(UINT8 channeltype) {
     return count;
 }
 
+#ifdef USE_AUDIO_TRACK
+int a2dp_get_track_channel_type(UINT8 channeltype) {
+    int count = 1;
+    switch (channeltype) {
+        case A2D_SBC_IE_CH_MD_MONO:
+            count = 1;
+            break;
+        case A2D_SBC_IE_CH_MD_DUAL:
+        case A2D_SBC_IE_CH_MD_STEREO:
+        case A2D_SBC_IE_CH_MD_JOINT:
+            count = 3;
+            break;
+    }
+    return count;
+}
+#endif
+
 void btif_a2dp_set_peer_sep(UINT8 sep) {
     btif_media_cb.peer_sep = sep;
 }
 
 static void btif_decode_alarm_cb(UNUSED_ATTR void *context) {
-  thread_post(worker_thread, btif_media_task_avk_handle_timer, NULL);
+  if(worker_thread != NULL)
+      thread_post(worker_thread, btif_media_task_avk_handle_timer, NULL);
 }
 
 static void btif_media_task_aa_handle_stop_decoding(void) {
   alarm_free(btif_media_cb.decode_alarm);
   btif_media_cb.decode_alarm = NULL;
+#ifdef USE_AUDIO_TRACK
+  BtifAvrcpAudioTrackPause(btif_media_cb.audio_track);
+#endif
 }
 
 static void btif_media_task_aa_handle_start_decoding(void) {
   if (btif_media_cb.decode_alarm)
     return;
-
+#ifdef USE_AUDIO_TRACK
+  BtifAvrcpAudioTrackStart(btif_media_cb.audio_track);
+#endif
   btif_media_cb.decode_alarm = alarm_new();
   if (!btif_media_cb.decode_alarm) {
     LOG_ERROR(LOG_TAG, "%s unable to allocate decode alarm.", __func__);
@@ -2002,6 +2093,10 @@ static void btif_media_task_aa_handle_start_decoding(void) {
 static void btif_media_task_aa_handle_clear_track (void)
 {
     APPL_TRACE_DEBUG("btif_media_task_aa_handle_clear_track");
+#ifdef USE_AUDIO_TRACK
+    BtifAvrcpAudioTrackStop(btif_media_cb.audio_track);
+    BtifAvrcpAudioTrackDelete(btif_media_cb.audio_track);
+#endif
 }
 
 /*******************************************************************************
@@ -2044,7 +2139,18 @@ static void btif_media_task_aa_handle_decoder_reset(BT_HDR *p_msg)
         APPL_TRACE_ERROR("OI_CODEC_SBC_DecoderReset failed with error code %d\n", status);
     }
 
+#ifdef USE_AUDIO_TRACK
+    APPL_TRACE_DEBUG("%s A2dpSink: sbc Create Track", __func__);
+    btif_media_cb.audio_track =
+        BtifAvrcpAudioTrackCreate(btif_a2dp_get_track_frequency(sbc_cie.samp_freq),
+                                  a2dp_get_track_channel_type(sbc_cie.ch_mode));
+    if (btif_media_cb.audio_track == NULL) {
+        APPL_TRACE_ERROR("%s A2dpSink: Track creation fails!!!", __func__);
+        return;
+    }
+#else
     UIPC_Open(UIPC_CH_ID_AV_AUDIO, btif_a2dp_data_cb);
+#endif
 
     switch(sbc_cie.samp_freq)
     {
@@ -2336,19 +2442,25 @@ UINT8 btif_media_sink_enque_buf(BT_HDR *p_pkt)
         return fixed_queue_length(btif_media_cb.RxSbcQ);
     if (fixed_queue_length(btif_media_cb.RxSbcQ) == MAX_OUTPUT_A2DP_FRAME_QUEUE_SZ)
     {
+        UINT8 ret = fixed_queue_length(btif_media_cb.RxSbcQ);
         osi_freebuf(fixed_queue_try_dequeue(btif_media_cb.RxSbcQ));
+        return ret;
     }
 
-    BTIF_TRACE_VERBOSE("btif_media_sink_enque_buf + ");
+    BTIF_TRACE_VERBOSE("%s +", __func__);
     /* allocate and Queue this buffer */
     if ((p_msg = (tBT_SBC_HDR *) osi_getbuf(sizeof(tBT_SBC_HDR) +
                         p_pkt->offset+ p_pkt->len)) != NULL)
     {
-        memcpy(p_msg, p_pkt, (sizeof(BT_HDR) + p_pkt->offset + p_pkt->len));
-        p_msg->num_frames_to_be_processed = (*((UINT8*)(p_msg + 1) + p_msg->offset)) & 0x0f;
-        BTIF_TRACE_VERBOSE("btif_media_sink_enque_buf + ", p_msg->num_frames_to_be_processed);
+        memcpy((UINT8*)(p_msg + 1), (UINT8*)(p_pkt + 1) + p_pkt->offset, p_pkt->len);
+        p_msg->num_frames_to_be_processed = (*((UINT8*)(p_pkt + 1) + p_pkt->offset))& 0x0f;
+        p_msg->len = p_pkt->len;
+        p_msg->offset = 0;
+        p_msg->layer_specific = p_pkt->layer_specific;
+        BTIF_TRACE_VERBOSE("%s frames to process %d, len %d  ",
+                           __func__, p_msg->num_frames_to_be_processed,p_msg->len);
         fixed_queue_enqueue(btif_media_cb.RxSbcQ, p_msg);
-        if (fixed_queue_length(btif_media_cb.RxSbcQ) == MAX_A2DP_DELAYED_START_FRAME_COUNT)
+        if(fixed_queue_length(btif_media_cb.RxSbcQ) == MAX_A2DP_DELAYED_START_FRAME_COUNT)
         {
             BTIF_TRACE_DEBUG(" Initiate Decoding ");
             btif_media_task_aa_handle_start_decoding();
index 7462561..f871b69 100644 (file)
@@ -1,20 +1,18 @@
-/******************************************************************************
+/*
+ * Copyright (C) 2015 The Android Open Source Project
  *
- *  Copyright (C) 2009-2012 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
  *
- *  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
  *
- *  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.
- *
- ******************************************************************************/
+ * 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.
+ */
 
 /*****************************************************************************
  *
@@ -45,7 +43,9 @@
 #include "bt_common.h"
 #include "device/include/interop.h"
 #include "uinput.h"
-
+#include "osi/include/list.h"
+#include "btu.h"
+#define RC_INVALID_TRACK_ID (0xFFFFFFFFFFFFFFFFULL)
 /*****************************************************************************
 **  Constants & Macros
 ******************************************************************************/
@@ -53,7 +53,7 @@
 /* cod value for Headsets */
 #define COD_AV_HEADSETS        0x0404
 /* for AVRC 1.4 need to change this */
-#define MAX_RC_NOTIFICATIONS AVRC_EVT_APP_SETTING_CHANGE
+#define MAX_RC_NOTIFICATIONS AVRC_EVT_VOLUME_CHANGE
 
 #define IDX_GET_PLAY_STATUS_RSP   0
 #define IDX_LIST_APP_ATTR_RSP     1
@@ -71,7 +71,7 @@
 
 #define CHECK_RC_CONNECTED                                                                  \
     BTIF_TRACE_DEBUG("## %s ##", __FUNCTION__);                                            \
-    if(btif_rc_cb.rc_connected == FALSE)                                                    \
+    if (btif_rc_cb.rc_connected == FALSE)                                                    \
     {                                                                                       \
         BTIF_TRACE_WARNING("Function %s() called when RC is not connected", __FUNCTION__); \
         return BT_STATUS_NOT_READY;                                                         \
@@ -86,7 +86,7 @@
 
 #define SEND_METAMSG_RSP(index, avrc_rsp)                                                      \
 {                                                                                              \
-    if(btif_rc_cb.rc_pdu_info[index].is_rsp_pending == FALSE)                                  \
+    if (btif_rc_cb.rc_pdu_info[index].is_rsp_pending == FALSE)                                  \
     {                                                                                          \
         BTIF_TRACE_WARNING("%s Not sending response as no PDU was registered", __FUNCTION__); \
         return BT_STATUS_UNHANDLED;                                                            \
@@ -113,6 +113,61 @@ typedef struct
     BOOLEAN is_rsp_pending;
 } btif_rc_cmd_ctxt_t;
 
+/* 2 second timeout to get interim response */
+#define BTIF_TIMEOUT_RC_INTERIM_RSP     2
+#define BTIF_TIMEOUT_RC_STATUS_CMD      2
+#define BTIF_TIMEOUT_RC_CONTROL_CMD     2
+
+
+typedef enum
+{
+    eNOT_REGISTERED,
+    eREGISTERED,
+    eINTERIM
+} btif_rc_nfn_reg_status_t;
+
+typedef struct {
+    UINT8                       event_id;
+    UINT8                       label;
+    btif_rc_nfn_reg_status_t    status;
+} btif_rc_supported_event_t;
+
+#define RC_TIMER_STATUS_CMD     0
+#define RC_TIMER_CONTROL_CMD    1
+#define RC_TIMER_PLAY_STATUS    2
+
+#define BTIF_RC_STS_TIMEOUT     0xFE
+typedef struct {
+    UINT8   label;
+    UINT8   pdu_id;
+} btif_rc_status_cmd_timer_t;
+
+typedef struct {
+    UINT8   label;
+    UINT8   pdu_id;
+} btif_rc_control_cmd_timer_t;
+
+typedef struct {
+    UINT8   timer_id;
+    union {
+        btif_rc_status_cmd_timer_t rc_status_cmd;
+        btif_rc_control_cmd_timer_t rc_control_cmd;
+    };
+    timer_entry_t tle;
+} btif_rc_timer_context_t;
+
+typedef struct {
+    BOOLEAN  query_started;
+    UINT8 num_attrs;
+    UINT8 num_ext_attrs;
+
+    UINT8 attr_index;
+    UINT8 ext_attr_index;
+    UINT8 ext_val_index;
+    btrc_player_app_attr_t attrs[AVRC_MAX_APP_ATTR_SIZE];
+    btrc_player_app_ext_attr_t ext_attrs[AVRC_MAX_APP_ATTR_SIZE];
+} btif_rc_player_app_settings_t;
+
 /* TODO : Merge btif_rc_reg_notifications_t and btif_rc_cmd_ctxt_t to a single struct */
 typedef struct {
     BOOLEAN                     rc_connected;
@@ -124,12 +179,19 @@ typedef struct {
     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;
+    timer_entry_t               tle_rc_play_status;
+    BOOLEAN                     rc_features_processed;
+    UINT64                      rc_playing_uid;
+    BOOLEAN                     rc_procedure_complete;
 } btif_rc_cb_t;
 
 typedef struct {
     BOOLEAN in_use;
     UINT8 lbl;
     UINT8 handle;
+    timer_entry_t tle_txn;
 } rc_transaction_t;
 
 typedef struct
@@ -182,6 +244,36 @@ static bt_status_t  get_transaction(rc_transaction_t **ptransaction);
 static void release_transaction(UINT8 label);
 static rc_transaction_t* get_transaction_by_lbl(UINT8 label);
 static void handle_rc_metamsg_rsp(tBTA_AV_META_MSG *pmeta_msg);
+#if (AVRC_CTLR_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 event, tAVRC_COMMAND *pavrc_cmd, UINT8 label);
+static void btif_rc_ctrl_upstreams_rsp_evt(
+    UINT16 event, tAVRC_RESPONSE *pavrc_resp, UINT8* p_buf, UINT16 buf_len, UINT8 rsp_type);
+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 rc_timeout_handler (UINT16 event, char* p_data);
+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_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 *attrs, UINT8 num_attrs);
+static bt_status_t get_player_app_setting_value_text_cmd (UINT8 *vals, UINT8 num_vals);
+static bt_status_t register_notification_cmd (UINT8 label, UINT8 event_id, UINT32 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);
+#endif
 static void btif_rc_upstreams_evt(UINT16 event, tAVRC_COMMAND* p_param, UINT8 ctype, UINT8 label);
 static void btif_rc_upstreams_rsp_evt(UINT16 event, tAVRC_RESPONSE *pavrc_resp, UINT8 ctype, UINT8 label);
 
@@ -324,8 +416,50 @@ void close_uinput (void)
     }
 }
 
-void handle_rc_features()
+#if (AVRC_CTLR_INCLUDED == TRUE)
+void rc_cleanup_sent_cmd (void *p_data)
+{
+    BTIF_TRACE_DEBUG("%s", __FUNCTION__);
+
+}
+
+void handle_rc_ctrl_features(BD_ADDR bd_addr)
+{
+    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)))
+    {
+        bt_bdaddr_t rc_addr;
+        int rc_features = 0;
+        bdcpy(rc_addr.address,bd_addr);
+
+        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;
+            getcapabilities_cmd (AVRC_CAP_COMPANY_ID);
+        }
+        BTIF_TRACE_DEBUG("%s Update rc features to CTRL %d", __FUNCTION__, rc_features);
+        HAL_CBACK(bt_rc_ctrl_callbacks, getrcfeatures_cb, &rc_addr, rc_features);
+    }
+}
+#endif
+
+void handle_rc_features(BD_ADDR bd_addr)
 {
+    if (bt_rc_callbacks != NULL)
+    {
     btrc_remote_features_t rc_features = BTRC_FEAT_NONE;
     bt_bdaddr_t rc_addr;
     bdcpy(rc_addr.address, btif_rc_cb.rc_addr);
@@ -355,38 +489,39 @@ void handle_rc_features()
     HAL_CBACK(bt_rc_callbacks, remote_features_cb, &rc_addr, rc_features)
 
 #if (AVRC_ADV_CTRL_INCLUDED == TRUE)
-     BTIF_TRACE_DEBUG("Checking for feature flags in btif_rc_handler with label %d",
-                        btif_rc_cb.rc_vol_label);
+     BTIF_TRACE_DEBUG("%s Checking for feature flags in btif_rc_handler with label %d",
+                        __FUNCTION__, btif_rc_cb.rc_vol_label);
      // Register for volume change on connect
-      if(btif_rc_cb.rc_features & BTA_AV_FEAT_ADV_CTRL &&
+      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)
+         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);
-            if(NULL!=p_transaction)
+            if (NULL!=p_transaction)
             {
-               BTIF_TRACE_DEBUG("register_volumechange already in progress for label %d",
-                                  btif_rc_cb.rc_vol_label);
+               BTIF_TRACE_DEBUG("%s register_volumechange already in progress for label %d",
+                                  __FUNCTION__, btif_rc_cb.rc_vol_label);
                return;
             }
             else
               status=get_transaction(&p_transaction);
          }
 
-         if(BT_STATUS_SUCCESS == status && NULL!=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
+    }
 }
 
 /***************************************************************************
@@ -405,17 +540,17 @@ 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)
+    if (p_rc_open->status == BTA_AV_SUCCESS)
     {
         //check if already some RC is connected
         if (btif_rc_cb.rc_connected)
         {
-            BTIF_TRACE_ERROR("Got RC OPEN in connected state, Connected RC: %d \
-                and Current RC: %d", btif_rc_cb.rc_handle,p_rc_open->rc_handle );
+            BTIF_TRACE_ERROR("%s Got RC OPEN in connected state, Connected RC: %d \
+                and Current RC: %d", __FUNCTION__, 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("Got RC connected for some other handle");
+                BTIF_TRACE_DEBUG("%s Got RC connected for some other handle", __FUNCTION__);
                 BTA_AvCloseRc(p_rc_open->rc_handle);
                 return;
             }
@@ -430,20 +565,34 @@ void handle_rc_connect (tBTA_AV_RC_OPEN *p_rc_open)
 
         /* on locally initiated connection we will get remote features as part of connect */
         if (btif_rc_cb.rc_features != 0)
-            handle_rc_features();
-
-        result = uinput_driver_check();
-        if(result == BT_STATUS_SUCCESS)
+            handle_rc_features(btif_rc_cb.rc_addr);
+        if (bt_rc_callbacks)
+        {
+            result = uinput_driver_check();
+            if (result == BT_STATUS_SUCCESS)
+            {
+                init_uinput();
+            }
+        }
+        else
         {
-            init_uinput();
+            BTIF_TRACE_WARNING("%s Avrcp TG role not enabled, not initializing UInput",
+                               __FUNCTION__);
         }
+        BTIF_TRACE_DEBUG("%s handle_rc_connect features %d ",__FUNCTION__, btif_rc_cb.rc_features);
 #if (AVRC_CTLR_INCLUDED == TRUE)
+        btif_rc_cb.rc_playing_uid = RC_INVALID_TRACK_ID;
         bdcpy(rc_addr.address, btif_rc_cb.rc_addr);
-        /* report connection state if device is AVRCP target */
-        if (btif_rc_cb.rc_features & BTA_AV_FEAT_RCTG) {
-            if (bt_rc_ctrl_callbacks != NULL) {
-                HAL_CBACK(bt_rc_ctrl_callbacks, connection_state_cb, TRUE, &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 */
+        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)))
+        {
+            handle_rc_ctrl_features(btif_rc_cb.rc_addr);
         }
 #endif
     }
@@ -476,30 +625,51 @@ void handle_rc_disconnect (tBTA_AV_RC_CLOSE *p_rc_close)
         BTIF_TRACE_ERROR("Got disconnect of unknown device");
         return;
     }
-
+#if (AVRC_CTLR_INCLUDED == TRUE)
+    bdcpy(rc_addr.address, btif_rc_cb.rc_addr);
+    features = btif_rc_cb.rc_features;
+        /* Clean up AVRCP procedure flags */
+    memset(&btif_rc_cb.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;
+    /* Check and stop play status timer */
+    if (btif_rc_cb.tle_rc_play_status.in_use == TRUE)
+    {
+        rc_stop_play_status_timer();
+    }
+    /* Check and clear the notification event list */
+    if (btif_rc_cb.rc_supported_event_list != NULL)
+    {
+        list_clear(btif_rc_cb.rc_supported_event_list);
+        btif_rc_cb.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));
-#if (AVRC_CTLR_INCLUDED == TRUE)
-    features = btif_rc_cb.rc_features;
-#endif
+
     btif_rc_cb.rc_features = 0;
     btif_rc_cb.rc_vol_label=MAX_LABEL;
     btif_rc_cb.rc_volume=MAX_VOLUME;
     init_all_transactions();
-    close_uinput();
-#if (AVRC_CTLR_INCLUDED == TRUE)
-    bdcpy(rc_addr.address, btif_rc_cb.rc_addr);
-#endif
+    if (bt_rc_callbacks != NULL)
+    {
+        close_uinput();
+    }
+    else
+    {
+        BTIF_TRACE_WARNING("%s Avrcp TG role not enabled, not closing UInput", __FUNCTION__);
+    }
+
     memset(btif_rc_cb.rc_addr, 0, sizeof(BD_ADDR));
 #if (AVRC_CTLR_INCLUDED == TRUE)
     /* report connection state if device is AVRCP target */
-    if (features & BTA_AV_FEAT_RCTG) {
-        if (bt_rc_ctrl_callbacks != NULL) {
-            HAL_CBACK(bt_rc_ctrl_callbacks, connection_state_cb, FALSE, &rc_addr);
-        }
-    }
+    if (bt_rc_ctrl_callbacks != NULL)
+   {
+        HAL_CBACK(bt_rc_ctrl_callbacks, connection_state_cb, FALSE, &rc_addr);
+   }
 #endif
 }
 
@@ -539,6 +709,8 @@ void handle_rc_passthrough_cmd ( tBTA_AV_REMOTE_CMD *p_remote_cmd)
             btif_rc_cb.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))
+            return; // this command is not to be sent to UINPUT, only needed for PTS
     }
 
     if ((p_remote_cmd->rc_id == BTA_AV_RC_STOP) && (!btif_av_stream_started_ready()))
@@ -562,7 +734,7 @@ void handle_rc_passthrough_cmd ( tBTA_AV_REMOTE_CMD *p_remote_cmd)
      * This fix is to interop with certain carkits which sends an automatic  PLAY  or PAUSE
      * commands right after call ends
      */
-    if((p_remote_cmd->rc_id == BTA_AV_RC_PLAY || p_remote_cmd->rc_id == BTA_AV_RC_PAUSE)&&
+    if ((p_remote_cmd->rc_id == BTA_AV_RC_PLAY || p_remote_cmd->rc_id == BTA_AV_RC_PAUSE)&&
        (btif_hf_call_terminated_recently() == TRUE) &&
        (check_cod( (const bt_bdaddr_t*)&(btif_rc_cb.rc_addr), COD_AV_HEADSETS) != TRUE))
     {
@@ -652,6 +824,53 @@ void handle_rc_passthrough_rsp ( tBTA_AV_REMOTE_RSP *p_remote_rsp)
 #endif
 }
 
+/***************************************************************************
+ *  Function       handle_rc_vendorunique_rsp
+ *
+ *  - Argument:    tBTA_AV_REMOTE_RSP  command response
+ *
+ *  - Description: Remote control vendor unique response handler
+ *
+ ***************************************************************************/
+void handle_rc_vendorunique_rsp ( tBTA_AV_REMOTE_RSP *p_remote_rsp)
+{
+#if (AVRC_CTLR_INCLUDED == TRUE)
+    const char *status;
+    UINT8 vendor_id = 0;
+    if (btif_rc_cb.rc_features & BTA_AV_FEAT_RCTG)
+    {
+        int key_state;
+        if (p_remote_rsp->key_state == AVRC_STATE_RELEASE)
+        {
+            status = "released";
+            key_state = 1;
+        }
+        else
+        {
+            status = "pressed";
+            key_state = 0;
+        }
+
+        if (p_remote_rsp->len > 0)
+        {
+            if (p_remote_rsp->len >= AVRC_PASS_THRU_GROUP_LEN)
+                vendor_id = p_remote_rsp->p_data[AVRC_PASS_THRU_GROUP_LEN -1];
+            osi_freebuf(p_remote_rsp->p_data);
+        }
+        BTIF_TRACE_DEBUG("%s: vendor_id=%d status=%s", __FUNCTION__, 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", __FUNCTION__);
+    }
+#else
+    BTIF_TRACE_ERROR("%s AVRCP controller role is not enabled", __FUNCTION__);
+#endif
+}
+
 void handle_uid_changed_notification(tBTA_AV_META_MSG *pmeta_msg, tAVRC_COMMAND *pavrc_command)
 {
     tAVRC_RESPONSE avrc_rsp = {0};
@@ -703,7 +922,7 @@ void handle_rc_metamsg_cmd (tBTA_AV_META_MSG *pmeta_msg)
 {
      rc_transaction_t *transaction=NULL;
      transaction=get_transaction_by_lbl(pmeta_msg->label);
-     if(NULL!=transaction)
+     if (NULL!=transaction)
      {
         handle_rc_metamsg_rsp(pmeta_msg);
      }
@@ -724,8 +943,8 @@ 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("Received vendor command.code,PDU and label: %d, %d,%d",pmeta_msg->code,
-                       avrc_command.cmd.pdu, pmeta_msg->label);
+    BTIF_TRACE_DEBUG("%s Received vendor command.code,PDU and label: %d, %d,%d",
+                     __FUNCTION__, pmeta_msg->code, avrc_command.cmd.pdu, pmeta_msg->label);
 
     if (status != AVRC_STS_NO_ERROR)
     {
@@ -746,7 +965,7 @@ void handle_rc_metamsg_cmd (tBTA_AV_META_MSG *pmeta_msg)
             btif_rc_cb.rc_notif[event_id-1].bNotify = TRUE;
             btif_rc_cb.rc_notif[event_id-1].label = pmeta_msg->label;
 
-            if(event_id == AVRC_EVT_UIDS_CHANGE)
+            if (event_id == AVRC_EVT_UIDS_CHANGE)
             {
                 handle_uid_changed_notification(pmeta_msg, &avrc_command);
                 return;
@@ -779,7 +998,7 @@ void btif_rc_handler(tBTA_AV_EVT event, tBTA_AV *p_data)
     {
         case BTA_AV_RC_OPEN_EVT:
         {
-            BTIF_TRACE_DEBUG("Peer_features:%x", p_data->rc_open.peer_features);
+            BTIF_TRACE_DEBUG("%s Peer_features:%x", __FUNCTION__, p_data->rc_open.peer_features);
             handle_rc_connect( &(p_data->rc_open) );
         }break;
 
@@ -790,39 +1009,115 @@ void btif_rc_handler(tBTA_AV_EVT event, tBTA_AV *p_data)
 
         case BTA_AV_REMOTE_CMD_EVT:
         {
-            BTIF_TRACE_DEBUG("rc_id:0x%x key_state:%d", p_data->remote_cmd.rc_id,
+            if (bt_rc_callbacks != NULL)
+            {
+              BTIF_TRACE_DEBUG("%s rc_id:0x%x key_state:%d",
+                               __FUNCTION__, p_data->remote_cmd.rc_id,
                                p_data->remote_cmd.key_state);
-            handle_rc_passthrough_cmd( (&p_data->remote_cmd) );
+                /** 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", __FUNCTION__);
+                }
+            }
+            else
+            {
+                BTIF_TRACE_ERROR("AVRCP TG role not up, drop passthrough commands");
+            }
         }
         break;
+
 #if (AVRC_CTLR_INCLUDED == TRUE)
         case BTA_AV_REMOTE_RSP_EVT:
         {
-            BTIF_TRACE_DEBUG("RSP: rc_id:0x%x key_state:%d", p_data->remote_rsp.rc_id,
-                               p_data->remote_rsp.key_state);
-            handle_rc_passthrough_rsp( (&p_data->remote_rsp) );
+            BTIF_TRACE_DEBUG("%s %s RSP: rc_id:0x%x key_state:%d",
+                             __FUNCTION__, 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);
+            }
+            else
+            {
+                handle_rc_passthrough_rsp(&p_data->remote_rsp);
+            }
         }
         break;
+
 #endif
         case BTA_AV_RC_FEAT_EVT:
         {
-            BTIF_TRACE_DEBUG("Peer_features:%x", p_data->rc_feat.peer_features);
+            BTIF_TRACE_DEBUG("%s Peer_features:%x", __FUNCTION__, p_data->rc_feat.peer_features);
             btif_rc_cb.rc_features = p_data->rc_feat.peer_features;
-            handle_rc_features();
+            handle_rc_features(p_data->rc_feat.peer_addr);
+#if (AVRC_CTLR_INCLUDED == TRUE)
+            if ((btif_rc_cb.rc_connected) && (bt_rc_ctrl_callbacks != NULL))
+            {
+                handle_rc_ctrl_features(btif_rc_cb.rc_addr);
+            }
+#endif
         }
         break;
+
         case BTA_AV_META_MSG_EVT:
         {
-            BTIF_TRACE_DEBUG("BTA_AV_META_MSG_EVT  code:%d label:%d", p_data->meta_msg.code,
-                p_data->meta_msg.label);
-            BTIF_TRACE_DEBUG("  company_id:0x%x len:%d handle:%d", 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));
+            if (bt_rc_callbacks != NULL)
+            {
+                BTIF_TRACE_DEBUG("%s BTA_AV_META_MSG_EVT  code:%d label:%d",
+                                 __FUNCTION__,
+                                 p_data->meta_msg.code,
+                                 p_data->meta_msg.label);
+                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);
+                /* handle the metamsg command */
+                handle_rc_metamsg_cmd(&(p_data->meta_msg));
+                /* Free the Memory allocated for tAVRC_MSG */
+            }
+#if (AVRC_CTLR_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",
+                                 __FUNCTION__,
+                                 p_data->meta_msg.code,
+                                 p_data->meta_msg.label);
+                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);
+                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));
+                }
+
+            }
+#endif
+            else
+            {
+                BTIF_TRACE_ERROR("Neither CTRL, nor TG is up, drop meta commands");
+            }
         }
         break;
+
         default:
-            BTIF_TRACE_DEBUG("Unhandled RC event : 0x%x", event);
+            BTIF_TRACE_DEBUG("%s Unhandled RC event : 0x%x", __FUNCTION__, event);
     }
 }
 
@@ -844,6 +1139,18 @@ BOOLEAN btif_rc_get_connected_peer(BD_ADDR peer_addr)
 
 /***************************************************************************
  **
+ ** Function       btif_rc_get_connected_peer_handle
+ **
+ ** Description    Fetches the connected headset's handle if any
+ **
+ ***************************************************************************/
+UINT8 btif_rc_get_connected_peer_handle(void)
+{
+    return btif_rc_cb.rc_handle;
+}
+
+/***************************************************************************
+ **
  ** Function       btif_rc_check_handle_pending_play
  **
  ** Description    Clears the queued PLAY command. if bSend is TRUE, forwards to app
@@ -961,7 +1268,7 @@ static void send_metamsg_rsp (UINT8 rc_handle, UINT8 label, tBTA_AV_CODE 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))
+    if ((pmetamsg_resp->rsp.pdu == AVRC_PDU_REGISTER_NOTIFICATION) && (code == AVRC_RSP_CHANGED))
     {
         BOOLEAN bSent = FALSE;
         UINT8   event_id = pmetamsg_resp->reg_notif.event_id;
@@ -1130,7 +1437,7 @@ static void btif_rc_upstreams_evt(UINT16 event, tAVRC_COMMAND *pavrc_cmd, UINT8
         break;
         case AVRC_PDU_REGISTER_NOTIFICATION:
         {
-            if(pavrc_cmd->reg_notif.event_id == BTRC_EVT_PLAY_POS_CHANGED &&
+            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.",
@@ -1148,7 +1455,7 @@ static void btif_rc_upstreams_evt(UINT16 event, tAVRC_COMMAND *pavrc_cmd, UINT8
         {
             tAVRC_RESPONSE avrc_rsp;
             BTIF_TRACE_EVENT("%s() AVRC_PDU_INFORM_DISPLAY_CHARSET", __FUNCTION__);
-            if(btif_rc_cb.rc_connected == TRUE)
+            if (btif_rc_cb.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);
@@ -1166,8 +1473,48 @@ static void btif_rc_upstreams_evt(UINT16 event, tAVRC_COMMAND *pavrc_cmd, UINT8
         }
         break;
     }
+}
+
+#if (AVRC_CTLR_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function         btif_rc_ctrl_upstreams_rsp_cmd
+**
+** Description      Executes AVRC UPSTREAMS response events in btif context.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void btif_rc_ctrl_upstreams_rsp_cmd(UINT8 event, tAVRC_COMMAND *pavrc_cmd,
+        UINT8 label)
+{
+    BTIF_TRACE_DEBUG("%s pdu: %s handle: 0x%x", __FUNCTION__,
+        dump_rc_pdu(pavrc_cmd->pdu), btif_rc_cb.rc_handle);
+    bt_bdaddr_t rc_addr;
+    bdcpy(rc_addr.address, btif_rc_cb.rc_addr);
+#if (AVRC_CTLR_INCLUDED == TRUE)
+    switch (event)
+    {
+    case AVRC_PDU_SET_ABSOLUTE_VOLUME:
+         HAL_CBACK(bt_rc_ctrl_callbacks,setabsvol_cmd_cb, &rc_addr,
+                 pavrc_cmd->volume.volume, label);
+         break;
+    case AVRC_PDU_REGISTER_NOTIFICATION:
+         if (pavrc_cmd->reg_notif.event_id == AVRC_EVT_VOLUME_CHANGE)
+         {
+             HAL_CBACK(bt_rc_ctrl_callbacks, registernotification_absvol_cb,
+                    &rc_addr, label);
+         }
+         break;
+    }
+#endif
+}
 
+static void rc_supported_event_free(void* p_data)
+{
+    osi_freebuf (p_data);
 }
+#endif
 
 /*******************************************************************************
 **
@@ -1188,7 +1535,7 @@ static void btif_rc_upstreams_rsp_evt(UINT16 event, tAVRC_RESPONSE *pavrc_resp,
     {
         case AVRC_PDU_REGISTER_NOTIFICATION:
         {
-             if(AVRC_RSP_CHANGED==ctype)
+             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)
         }
@@ -1196,9 +1543,9 @@ static void btif_rc_upstreams_rsp_evt(UINT16 event, tAVRC_RESPONSE *pavrc_resp,
 
         case AVRC_PDU_SET_ABSOLUTE_VOLUME:
         {
-            BTIF_TRACE_DEBUG("Set absolute volume change event received: volume %d,ctype %d",
-                pavrc_resp->volume.volume,ctype);
-            if(AVRC_RSP_ACCEPT==ctype)
+            BTIF_TRACE_DEBUG("%s Set absolute volume change event received: volume %d,ctype %d",
+                             __FUNCTION__, 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)
         }
@@ -1266,6 +1613,25 @@ static bt_status_t init_ctrl(btrc_ctrl_callbacks_t* callbacks )
     return result;
 }
 
+static void rc_ctrl_procedure_complete ()
+{
+    if (btif_rc_cb.rc_procedure_complete == TRUE)
+    {
+        return;
+    }
+    btif_rc_cb.rc_procedure_complete = TRUE;
+    UINT32 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);
+}
+
 /***************************************************************************
 **
 ** Function         get_play_status_rsp
@@ -1325,9 +1691,9 @@ static bt_status_t get_element_attr_rsp(uint8_t num_attr, btrc_element_attr_val_
             element_attrs[i].name.str_len = (UINT16)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",
-                __FUNCTION__, (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);
+                             __FUNCTION__, (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;
     }
@@ -1413,7 +1779,7 @@ static bt_status_t set_volume(uint8_t volume)
     tAVRC_STS status = BT_STATUS_UNSUPPORTED;
     rc_transaction_t *p_transaction=NULL;
 
-    if(btif_rc_cb.rc_volume==volume)
+    if (btif_rc_cb.rc_volume==volume)
     {
         status=BT_STATUS_DONE;
         BTIF_TRACE_ERROR("%s: volume value already set earlier: 0x%02x",__FUNCTION__, volume);
@@ -1435,7 +1801,7 @@ static bt_status_t set_volume(uint8_t 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)
+            if (BT_STATUS_SUCCESS == tran_status && NULL!=p_transaction)
             {
                 BTIF_TRACE_DEBUG("%s msgreq being sent out with label %d",
                                    __FUNCTION__,p_transaction->lbl);
@@ -1444,7 +1810,7 @@ static bt_status_t set_volume(uint8_t volume)
             }
             else
             {
-                if(NULL!=p_msg)
+                if (NULL!=p_msg)
                    osi_freebuf(p_msg);
                 BTIF_TRACE_ERROR("%s: failed to obtain transaction details. status: 0x%02x",
                                     __FUNCTION__, tran_status);
@@ -1486,19 +1852,20 @@ static void register_volumechange (UINT8 lbl)
     avrc_cmd.pdu = AVRC_PDU_REGISTER_NOTIFICATION;
     avrc_cmd.reg_notif.event_id = AVRC_EVT_VOLUME_CHANGE;
     avrc_cmd.reg_notif.status = AVRC_STS_NO_ERROR;
+    avrc_cmd.reg_notif.param = 0;
 
     BldResp=AVRC_BldCommand(&avrc_cmd, &p_msg);
-    if(AVRC_STS_NO_ERROR==BldResp && p_msg)
+    if (AVRC_STS_NO_ERROR==BldResp && p_msg)
     {
          p_transaction=get_transaction_by_lbl(lbl);
-         if(NULL!=p_transaction)
+         if (NULL!=p_transaction)
          {
              BTA_AvMetaCmd(btif_rc_cb.rc_handle,p_transaction->lbl, AVRC_CMD_NOTIF, p_msg);
              BTIF_TRACE_DEBUG("%s:BTA_AvMetaCmd called",__FUNCTION__);
          }
          else
          {
-            if(NULL!=p_msg)
+            if (NULL!=p_msg)
                osi_freebuf(p_msg);
             BTIF_TRACE_ERROR("%s transaction not obtained with label: %d",__FUNCTION__,lbl);
          }
@@ -1522,7 +1889,7 @@ static void handle_rc_metamsg_rsp(tBTA_AV_META_MSG *pmeta_msg)
     UINT8             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
+    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))
     {
@@ -1533,20 +1900,20 @@ static void handle_rc_metamsg_rsp(tBTA_AV_META_MSG *pmeta_msg)
 
         if (status != AVRC_STS_NO_ERROR)
         {
-            if(AVRC_PDU_REGISTER_NOTIFICATION==avrc_response.rsp.pdu
+            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)
             {
                 btif_rc_cb.rc_vol_label=MAX_LABEL;
                 release_transaction(btif_rc_cb.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
+        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)
             {
@@ -1563,7 +1930,7 @@ static void handle_rc_metamsg_rsp(tBTA_AV_META_MSG *pmeta_msg)
         return;
     }
 
-    if(AVRC_PDU_REGISTER_NOTIFICATION==avrc_response.rsp.pdu
+    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)
      {
@@ -1571,7 +1938,7 @@ static void handle_rc_metamsg_rsp(tBTA_AV_META_MSG *pmeta_msg)
          // Do not re-register for rejected case, as it might get into endless loop
          register_volumechange(btif_rc_cb.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)
      {
           /* free up the label here */
           release_transaction(pmeta_msg->label);
@@ -1583,89 +1950,2113 @@ static void handle_rc_metamsg_rsp(tBTA_AV_META_MSG *pmeta_msg)
                                 pmeta_msg->label);
 }
 
+#if (AVRC_CTLR_INCLUDED == TRUE)
 /***************************************************************************
 **
-** Function         cleanup
-**
-** Description      Closes the AVRC interface
+** Function         iterate_supported_event_list_for_interim_rsp
 **
-** Returns          void
+** Description      iterator callback function to match the event and handle
+**                  timer cleanup
+** Returns          true if matches with the event, flase otherwise
 **
 ***************************************************************************/
-static void cleanup()
+bool iterate_supported_event_list_for_interim_rsp(void *data, void *cb_data)
 {
-    BTIF_TRACE_EVENT("## %s ##", __FUNCTION__);
-    close_uinput();
-    if (bt_rc_callbacks)
+    UINT8 *p_event_id;
+    btif_rc_supported_event_t *p_event = (btif_rc_supported_event_t *)data;
+
+    p_event_id = (UINT8*)cb_data;
+
+    if (p_event->event_id == *p_event_id)
     {
-        bt_rc_callbacks = NULL;
+        p_event->status = eINTERIM;
+        return true;
     }
-    memset(&btif_rc_cb, 0, sizeof(btif_rc_cb_t));
-    lbl_destroy();
-    BTIF_TRACE_EVENT("## %s ## completed", __FUNCTION__);
+    return false;
 }
 
 /***************************************************************************
 **
-** Function         cleanup_ctrl
-**
-** Description      Closes the AVRC Controller interface
+** Function         iterate_supported_event_list_for_timeout
 **
-** Returns          void
+** Description      Iterator callback function for timeout handling.
+**                  As part of the failure handling, it releases the
+**                  transaction label and removes the event from list,
+**                  this event will not be requested again during
+**                  the lifetime of the connection.
+** Returns          true if matches with the event, flase otherwise
 **
 ***************************************************************************/
-static void cleanup_ctrl()
+bool iterate_supported_event_list_for_timeout(void *data, void *cb_data)
 {
-    BTIF_TRACE_EVENT("## %s ##", __FUNCTION__);
+    UINT8 label;
+    UINT32 cb_value;
+    btif_rc_supported_event_t *p_event = (btif_rc_supported_event_t *)data;
 
-    if (bt_rc_ctrl_callbacks)
+    cb_value = (UINT32)cb_data;
+
+    label = cb_value & 0xFF;
+
+    if (p_event->label == label)
     {
-        bt_rc_ctrl_callbacks = NULL;
+        list_remove(btif_rc_cb.rc_supported_event_list, p_event);
+        return true;
     }
-    memset(&btif_rc_cb, 0, sizeof(btif_rc_cb_t));
-    lbl_destroy();
-    BTIF_TRACE_EVENT("## %s ## completed", __FUNCTION__);
+    return false;
 }
 
-static bt_status_t send_passthrough_cmd(bt_bdaddr_t *bd_addr, uint8_t key_code, uint8_t key_state)
+/***************************************************************************
+**
+** Function         rc_notification_interim_timout
+**
+** Description      Interim response timeout handler.
+**                  Runs the iterator to check and clear the timed out event.
+**                  Proceeds to register for the unregistered events.
+** Returns          None
+**
+***************************************************************************/
+static void rc_notification_interim_timout (UINT8 label)
 {
-    tAVRC_STS status = BT_STATUS_UNSUPPORTED;
-#if (AVRC_CTLR_INCLUDED == TRUE)
-    CHECK_RC_CONNECTED
-    rc_transaction_t *p_transaction=NULL;
-    BTIF_TRACE_DEBUG("%s: key-code: %d, key-state: %d", __FUNCTION__,
-                                                    key_code, key_state);
-    if (btif_rc_cb.rc_features & BTA_AV_FEAT_RCTG)
+    list_node_t *node;
+    UINT32 cb_data;
+
+    cb_data = label;
+    list_foreach_ext(btif_rc_cb.rc_supported_event_list,
+                     iterate_supported_event_list_for_timeout, (void*)cb_data);
+    /* 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);
+    while (node != NULL)
     {
-        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,
-                (tBTA_AV_RC)key_code, (tBTA_AV_STATE)key_state);
-            status =  BT_STATUS_SUCCESS;
-            BTIF_TRACE_DEBUG("%s: succesfully sent passthrough command to BTA", __FUNCTION__);
-        }
-        else
+        btif_rc_supported_event_t *p_event;
+
+        p_event = (btif_rc_supported_event_t *)list_node(node);
+        if ((p_event != NULL) && (p_event->status == eNOT_REGISTERED))
         {
-            status =  BT_STATUS_FAIL;
-            BTIF_TRACE_DEBUG("%s: error in fetching transaction", __FUNCTION__);
+            register_for_event_notification(p_event);
+            break;
         }
+        node = list_next (node);
     }
-    else
-    {
-        status =  BT_STATUS_FAIL;
-        BTIF_TRACE_DEBUG("%s: feature not supported", __FUNCTION__);
-    }
-#else
-    BTIF_TRACE_DEBUG("%s: feature not enabled", __FUNCTION__);
-#endif
-    return status;
+    /* Todo. Need to initiate application settings query if this
+     * is the last event registration.
+     */
 }
 
-static const btrc_interface_t bt_rc_interface = {
-    sizeof(bt_rc_interface),
-    init,
-    get_play_status_rsp,
+/***************************************************************************
+**
+** Function         rc_timeout_callback
+**
+** Description      RC timeout callback.
+**                  This is called from BTU context and switches to BTIF
+**                  context to handle the timeout events
+** Returns          None
+**
+***************************************************************************/
+static void rc_timeout_callback (timer_entry_t *tle)
+{
+    char *p_data = (char*)tle->data;
+
+    tle->data = NULL;
+    btif_transfer_context(rc_timeout_handler, 0,
+                  p_data, sizeof(btif_rc_timer_context_t), NULL);
+    osi_freebuf (p_data);
+}
+
+/***************************************************************************
+**
+** Function         rc_start_play_status_timer
+**
+** Description      Helper function to start the timer to fetch play status.
+** Returns          None
+**
+***************************************************************************/
+void rc_start_play_status_timer ()
+{
+    btif_rc_timer_context_t *p_rc_timer_context;
+    /* Start the Play status timer only if it is not started */
+    if (btif_rc_cb.tle_rc_play_status.data == NULL)
+    {
+        p_rc_timer_context = (btif_rc_timer_context_t*) osi_getbuf(sizeof(btif_rc_timer_context_t));
+        if (p_rc_timer_context != NULL)
+        {
+            p_rc_timer_context->timer_id = RC_TIMER_PLAY_STATUS;
+            memset(&btif_rc_cb.tle_rc_play_status, 0, sizeof(timer_entry_t));
+            btif_rc_cb.tle_rc_play_status.param = rc_timeout_callback;
+            btif_rc_cb.tle_rc_play_status.data = p_rc_timer_context;
+            btu_start_timer(&btif_rc_cb.tle_rc_play_status, BTU_TTYPE_USER_FUNC,
+                    BTIF_TIMEOUT_RC_INTERIM_RSP);
+        }
+    }
+}
+
+/***************************************************************************
+**
+** Function         rc_stop_play_status_timer
+**
+** Description      Helper function to stop the play status timer.
+** Returns          None
+**
+***************************************************************************/
+void rc_stop_play_status_timer ()
+{
+    if (btif_rc_cb.tle_rc_play_status.data != NULL)
+    {
+        btu_stop_timer (&btif_rc_cb.tle_rc_play_status);
+        osi_freebuf(btif_rc_cb.tle_rc_play_status.data);
+        btif_rc_cb.tle_rc_play_status.data = NULL;
+    }
+}
+
+/***************************************************************************
+**
+** Function         rc_timeout_handler
+**
+** Description      RC timeout handler (Runs in BTIF context).
+**                  main handler for all the timers created from RC module
+** Returns          None
+**
+***************************************************************************/
+static void rc_timeout_handler (UINT16 event, char* p_data)
+{
+    btif_rc_timer_context_t *p_rc_timer_context;
+    tAVRC_RESPONSE      avrc_response = {0};
+    tBTA_AV_META_MSG    meta_msg;
+
+    p_rc_timer_context = (btif_rc_timer_context_t *)p_data;
+    memset(&meta_msg, 0, sizeof(tBTA_AV_META_MSG));
+    meta_msg.rc_handle = btif_rc_cb.rc_handle;
+
+    switch (p_rc_timer_context->timer_id)
+    {
+        case RC_TIMER_STATUS_CMD:
+            switch (p_rc_timer_context->rc_status_cmd.pdu_id)
+            {
+                case AVRC_PDU_REGISTER_NOTIFICATION:
+                    rc_notification_interim_timout(
+                                    p_rc_timer_context->rc_status_cmd.label);
+                    break;
+
+                case AVRC_PDU_GET_CAPABILITIES:
+                    avrc_response.get_caps.status = BTIF_RC_STS_TIMEOUT;
+                    handle_get_capability_response(&meta_msg, &avrc_response.get_caps);
+                    break;
+
+                case AVRC_PDU_LIST_PLAYER_APP_ATTR:
+                    avrc_response.list_app_attr.status = BTIF_RC_STS_TIMEOUT;
+                    handle_app_attr_response(&meta_msg, &avrc_response.list_app_attr);
+                    break;
+
+                case AVRC_PDU_LIST_PLAYER_APP_VALUES:
+                    avrc_response.list_app_values.status = BTIF_RC_STS_TIMEOUT;
+                    handle_app_val_response(&meta_msg, &avrc_response.list_app_values);
+                    break;
+
+                case AVRC_PDU_GET_CUR_PLAYER_APP_VALUE:
+                    avrc_response.get_cur_app_val.status = BTIF_RC_STS_TIMEOUT;
+                    handle_app_cur_val_response(&meta_msg, &avrc_response.get_cur_app_val);
+                    break;
+
+                case AVRC_PDU_GET_PLAYER_APP_ATTR_TEXT:
+                    avrc_response.get_app_attr_txt.status = BTIF_RC_STS_TIMEOUT;
+                    handle_app_attr_txt_response(&meta_msg, &avrc_response.get_app_attr_txt);
+                    break;
+
+                case AVRC_PDU_GET_PLAYER_APP_VALUE_TEXT:
+                    avrc_response.get_app_val_txt.status = BTIF_RC_STS_TIMEOUT;
+                    handle_app_attr_txt_response(&meta_msg, &avrc_response.get_app_val_txt);
+                    break;
+
+                case AVRC_PDU_GET_ELEMENT_ATTR:
+                    avrc_response.get_elem_attrs.status = BTIF_RC_STS_TIMEOUT;
+                    handle_get_elem_attr_response(&meta_msg, &avrc_response.get_elem_attrs);
+                    break;
+
+                case AVRC_PDU_GET_PLAY_STATUS:
+                    avrc_response.get_caps.status = BTIF_RC_STS_TIMEOUT;
+                    handle_get_capability_response(&meta_msg, &avrc_response.get_caps);
+                    break;
+            }
+            release_transaction (p_rc_timer_context->rc_status_cmd.label);
+            break;
+
+        case RC_TIMER_CONTROL_CMD:
+            switch (p_rc_timer_context->rc_control_cmd.pdu_id)
+            {
+                case AVRC_PDU_SET_PLAYER_APP_VALUE:
+                    avrc_response.set_app_val.status = BTIF_RC_STS_TIMEOUT;
+                    handle_set_app_attr_val_response(&meta_msg, &avrc_response.set_app_val);
+                    break;
+            }
+            release_transaction (p_rc_timer_context->rc_control_cmd.label);
+            break;
+
+        case RC_TIMER_PLAY_STATUS:
+            get_play_status_cmd();
+            rc_start_play_status_timer();
+            break;
+
+        default:
+            BTIF_TRACE_ERROR("%s Error unknown timer id %d",
+                __FUNCTION__, p_rc_timer_context->timer_id);
+            break;
+    }
+}
+
+/***************************************************************************
+**
+** Function         register_for_event_notification
+**
+** Description      Helper function registering notification events
+**                  sets an interim response timeout to handle if the remote
+**                  does not respond.
+** Returns          None
+**
+***************************************************************************/
+static void register_for_event_notification (btif_rc_supported_event_t *p_event)
+{
+    bt_status_t status;
+    rc_transaction_t *p_transaction;
+
+    status = get_transaction(&p_transaction);
+    if (status == BT_STATUS_SUCCESS)
+    {
+        btif_rc_timer_context_t *p_rc_timer_context;
+
+        status = register_notification_cmd (p_transaction->lbl, p_event->event_id, 0);
+        if (status != BT_STATUS_SUCCESS)
+        {
+            BTIF_TRACE_ERROR("%s Error in Notification registration %d",
+                __FUNCTION__, status);
+            release_transaction (p_transaction->lbl);
+            return;
+        }
+        p_event->label = p_transaction->lbl;
+        p_event->status = eREGISTERED;
+        p_rc_timer_context = (btif_rc_timer_context_t*) osi_getbuf(sizeof(btif_rc_timer_context_t));
+        if (p_rc_timer_context != NULL)
+        {
+            p_rc_timer_context->timer_id = RC_TIMER_STATUS_CMD;
+            p_rc_timer_context->rc_status_cmd.label = p_transaction->lbl;
+            p_rc_timer_context->rc_status_cmd.pdu_id = AVRC_PDU_REGISTER_NOTIFICATION;
+            memset(&p_transaction->tle_txn, 0, sizeof(timer_entry_t));
+            p_transaction->tle_txn.param = rc_timeout_callback;
+            p_transaction->tle_txn.data = p_rc_timer_context;
+            btu_start_timer(&p_transaction->tle_txn, BTU_TTYPE_USER_FUNC,
+                    BTIF_TIMEOUT_RC_INTERIM_RSP);
+        }
+    }
+    else
+    {
+        BTIF_TRACE_ERROR("%s Error No more Transaction label %d",
+            __FUNCTION__, status);
+    }
+}
+
+static void start_status_command_timer (UINT8 pdu_id, rc_transaction_t *p_txn)
+{
+    bt_status_t status;
+    btif_rc_timer_context_t *p_rc_timer_context;
+
+    p_rc_timer_context = (btif_rc_timer_context_t*) osi_getbuf(sizeof(btif_rc_timer_context_t));
+    if (p_rc_timer_context != NULL)
+    {
+        p_rc_timer_context->timer_id = RC_TIMER_STATUS_CMD;
+        p_rc_timer_context->rc_status_cmd.label = p_txn->lbl;
+        p_rc_timer_context->rc_status_cmd.pdu_id = pdu_id;
+
+        memset(&p_txn->tle_txn, 0, sizeof(timer_entry_t));
+        p_txn->tle_txn.param = rc_timeout_callback;
+        p_txn->tle_txn.data = p_rc_timer_context;
+        btu_start_timer(&p_txn->tle_txn, BTU_TTYPE_USER_FUNC,
+                BTIF_TIMEOUT_RC_STATUS_CMD);
+    }
+    else
+    {
+        BTIF_TRACE_ERROR("%s Getbuf failed while starting command timer",
+            __FUNCTION__);
+    }
+}
+
+static void start_control_command_timer (UINT8 pdu_id, rc_transaction_t *p_txn)
+{
+    bt_status_t status;
+    btif_rc_timer_context_t *p_rc_timer_context;
+
+    p_rc_timer_context = (btif_rc_timer_context_t*) osi_getbuf(sizeof(btif_rc_timer_context_t));
+    if (p_rc_timer_context != NULL)
+    {
+        p_rc_timer_context->timer_id = RC_TIMER_CONTROL_CMD;
+        p_rc_timer_context->rc_control_cmd.label = p_txn->lbl;
+        p_rc_timer_context->rc_control_cmd.pdu_id = pdu_id;
+
+        memset(&p_txn->tle_txn, 0, sizeof(timer_entry_t));
+        p_txn->tle_txn.param = rc_timeout_callback;
+        p_txn->tle_txn.data = p_rc_timer_context;
+        btu_start_timer(&p_txn->tle_txn, BTU_TTYPE_USER_FUNC,
+                BTIF_TIMEOUT_RC_CONTROL_CMD);
+    }
+    else
+    {
+        BTIF_TRACE_ERROR("%s Getbuf failed while starting command timer",
+            __FUNCTION__);
+    }
+}
+
+/***************************************************************************
+**
+** Function         handle_get_capability_response
+**
+** Description      Handles the get_cap_response to populate company id info
+**                  and query the supported events.
+**                  Initiates Notification registration for events supported
+** Returns          None
+**
+***************************************************************************/
+static void handle_get_capability_response (tBTA_AV_META_MSG *pmeta_msg, tAVRC_GET_CAPS_RSP *p_rsp)
+{
+    int xx = 0;
+
+    /* 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",
+                __FUNCTION__, p_rsp->status);
+        return;
+    }
+
+    if (p_rsp->capability_id == AVRC_CAP_EVENTS_SUPPORTED)
+    {
+        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(rc_supported_event_free);
+        for (xx = 0; xx < p_rsp->count; xx++)
+        {
+            /* Skip registering for Play position change notification */
+            if ((p_rsp->param.event_id[xx] == AVRC_EVT_PLAY_STATUS_CHANGE)||
+                (p_rsp->param.event_id[xx] == AVRC_EVT_TRACK_CHANGE)||
+                (p_rsp->param.event_id[xx] == AVRC_EVT_APP_SETTING_CHANGE))
+            {
+                p_event = (btif_rc_supported_event_t*) osi_getbuf(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);
+            }
+        }
+        p_event = list_front(btif_rc_cb.rc_supported_event_list);
+        if (p_event != NULL)
+        {
+            register_for_event_notification(p_event);
+        }
+    }
+    else if (p_rsp->capability_id == AVRC_CAP_COMPANY_ID)
+    {
+        getcapabilities_cmd (AVRC_CAP_EVENTS_SUPPORTED);
+        BTIF_TRACE_EVENT("%s AVRC_CAP_COMPANY_ID: ", __FUNCTION__);
+        for (xx = 0; xx < p_rsp->count; xx++)
+        {
+            BTIF_TRACE_EVENT("%s    : %d", __FUNCTION__, p_rsp->param.company_id[xx]);
+        }
+    }
+}
+
+bool rc_is_track_id_valid (tAVRC_UID uid)
+{
+    tAVRC_UID invalid_uid = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
+
+    if (memcmp(uid, invalid_uid, sizeof(tAVRC_UID)) == 0)
+    {
+        return false;
+    }
+    else
+    {
+        return true;
+    }
+}
+
+/***************************************************************************
+**
+** Function         handle_notification_response
+**
+** Description      Main handler for notification responses to registered events
+**                  1. Register for unregistered event(in interim response path)
+**                  2. After registering for all supported events, start
+**                     retrieving application settings and values
+**                  3. Reregister for events on getting changed response
+**                  4. Run play status timer for getting position when the
+**                     status changes to playing
+**                  5. Get the Media details when the track change happens
+**                     or track change interim response is received with
+**                     valid track id
+**                  6. HAL callback for play status change and application
+**                     setting change
+** Returns          None
+**
+***************************************************************************/
+static void handle_notification_response (tBTA_AV_META_MSG *pmeta_msg, tAVRC_REG_NOTIF_RSP *p_rsp)
+{
+    bt_bdaddr_t rc_addr;
+    UINT32 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
+        };
+
+
+    bdcpy(rc_addr.address, btif_rc_cb.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 ", __FUNCTION__, p_rsp->event_id);
+        switch (p_rsp->event_id)
+        {
+            case AVRC_EVT_PLAY_STATUS_CHANGE:
+                /* Start timer to get play status periodically
+                 * if the play state is playing.
+                 */
+                if (p_rsp->param.play_status == AVRC_PLAYSTATE_PLAYING)
+                {
+                    rc_start_play_status_timer();
+                }
+                HAL_CBACK(bt_rc_ctrl_callbacks, play_status_changed_cb,
+                    &rc_addr, p_rsp->param.play_status);
+                break;
+
+            case AVRC_EVT_TRACK_CHANGE:
+                if (rc_is_track_id_valid (p_rsp->param.track) != true)
+                {
+                    break;
+                }
+                else
+                {
+                    UINT8 *p_data = p_rsp->param.track;
+                    /* 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);
+                }
+                break;
+
+            case AVRC_EVT_APP_SETTING_CHANGE:
+                break;
+
+            case AVRC_EVT_NOW_PLAYING_CHANGE:
+                break;
+
+            case AVRC_EVT_AVAL_PLAYERS_CHANGE:
+                break;
+
+            case AVRC_EVT_ADDR_PLAYER_CHANGE:
+                break;
+
+            case AVRC_EVT_UIDS_CHANGE:
+                break;
+
+            case AVRC_EVT_TRACK_REACHED_END:
+            case AVRC_EVT_TRACK_REACHED_START:
+            case AVRC_EVT_PLAY_POS_CHANGED:
+            case AVRC_EVT_BATTERY_STATUS_CHANGE:
+            case AVRC_EVT_SYSTEM_STATUS_CHANGE:
+            default:
+                BTIF_TRACE_ERROR("%s  Unhandled interim response 0x%2X", __FUNCTION__,
+                    p_rsp->event_id);
+                return;
+        }
+        list_foreach_ext(btif_rc_cb.rc_supported_event_list,
+                iterate_supported_event_list_for_interim_rsp,
+                (void*)&p_rsp->event_id);
+
+        node = list_begin(btif_rc_cb.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);
+                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))
+        {
+            /* 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)
+            {
+                list_player_app_setting_attrib_cmd();
+            }
+            else
+            {
+                BTIF_TRACE_DEBUG("%s App setting not supported, complete procedure", __FUNCTION__);
+                rc_ctrl_procedure_complete();
+            }
+        }
+    }
+    else if (pmeta_msg->code == AVRC_RSP_CHANGED)
+    {
+        btif_rc_supported_event_t *p_event;
+        list_node_t *node;
+
+        BTIF_TRACE_DEBUG("%s Notification completed : 0x%2X ", __FUNCTION__,
+            p_rsp->event_id);
+
+        node = list_begin(btif_rc_cb.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))
+            {
+                p_event->status = eNOT_REGISTERED;
+                register_for_event_notification(p_event);
+                break;
+            }
+            node = list_next (node);
+        }
+
+        switch (p_rsp->event_id)
+        {
+            case AVRC_EVT_PLAY_STATUS_CHANGE:
+                /* Start timer to get play status periodically
+                 * if the play state is playing.
+                 */
+                if (p_rsp->param.play_status == AVRC_PLAYSTATE_PLAYING)
+                {
+                    rc_start_play_status_timer();
+                }
+                else
+                {
+                    rc_stop_play_status_timer();
+                }
+                HAL_CBACK(bt_rc_ctrl_callbacks, play_status_changed_cb,
+                    &rc_addr, p_rsp->param.play_status);
+                break;
+
+            case AVRC_EVT_TRACK_CHANGE:
+                if (rc_is_track_id_valid (p_rsp->param.track) != true)
+                {
+                    break;
+                }
+                get_element_attribute_cmd (AVRC_MAX_NUM_MEDIA_ATTR_ID, attr_list);
+                break;
+
+            case AVRC_EVT_APP_SETTING_CHANGE:
+            {
+                btrc_player_settings_t app_settings;
+                UINT16 xx;
+
+                app_settings.num_attr = p_rsp->param.player_setting.num_attr;
+                for (xx = 0; xx < app_settings.num_attr; xx++)
+                {
+                    app_settings.attr_ids[xx] = p_rsp->param.player_setting.attr_id[xx];
+                    app_settings.attr_values[xx] = p_rsp->param.player_setting.attr_value[xx];
+                }
+                HAL_CBACK(bt_rc_ctrl_callbacks, playerapplicationsetting_changed_cb,
+                    &rc_addr, &app_settings);
+            }
+                break;
+
+            case AVRC_EVT_NOW_PLAYING_CHANGE:
+                break;
+
+            case AVRC_EVT_AVAL_PLAYERS_CHANGE:
+                break;
+
+            case AVRC_EVT_ADDR_PLAYER_CHANGE:
+                break;
+
+            case AVRC_EVT_UIDS_CHANGE:
+                break;
+
+            case AVRC_EVT_TRACK_REACHED_END:
+            case AVRC_EVT_TRACK_REACHED_START:
+            case AVRC_EVT_PLAY_POS_CHANGED:
+            case AVRC_EVT_BATTERY_STATUS_CHANGE:
+            case AVRC_EVT_SYSTEM_STATUS_CHANGE:
+            default:
+                BTIF_TRACE_ERROR("%s  Unhandled completion response 0x%2X",
+                    __FUNCTION__, p_rsp->event_id);
+                return;
+        }
+    }
+}
+
+/***************************************************************************
+**
+** Function         handle_app_attr_response
+**
+** Description      handles the the application attributes response and
+**                  initiates procedure to fetch the attribute values
+** Returns          None
+**
+***************************************************************************/
+static void handle_app_attr_response (tBTA_AV_META_MSG *pmeta_msg, tAVRC_LIST_APP_ATTR_RSP *p_rsp)
+{
+    UINT8 xx;
+
+    if (p_rsp->status != AVRC_STS_NO_ERROR)
+    {
+        BTIF_TRACE_ERROR("%s Error getting Player application settings: 0x%2X",
+                __FUNCTION__, p_rsp->status);
+        rc_ctrl_procedure_complete();
+        return;
+    }
+
+    for (xx = 0; xx < p_rsp->num_attr; xx++)
+    {
+        UINT8 st_index;
+
+        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++;
+        }
+        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++;
+        }
+    }
+    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;
+    if (p_rsp->num_attr)
+    {
+        list_player_app_setting_value_cmd (btif_rc_cb.rc_app_settings.attrs[0].attr_id);
+    }
+    else
+    {
+        BTIF_TRACE_ERROR("%s No Player application settings found",
+                __FUNCTION__);
+    }
+}
+
+/***************************************************************************
+**
+** Function         handle_app_val_response
+**
+** Description      handles the the attributes value response and if extended
+**                  menu is available, it initiates query for the attribute
+**                  text. If not, it initiates procedure to get the current
+**                  attribute values and calls the HAL callback for provding
+**                  application settings information.
+** Returns          None
+**
+***************************************************************************/
+static void handle_app_val_response (tBTA_AV_META_MSG *pmeta_msg, tAVRC_LIST_APP_VALUES_RSP *p_rsp)
+{
+    UINT8 xx, attr_index;
+    int i,j;
+    UINT8 attrs[AVRC_MAX_APP_ATTR_SIZE];
+    btif_rc_player_app_settings_t *p_app_settings;
+    bt_bdaddr_t rc_addr;
+
+    /* Todo: Do we need to retry on command timeout */
+    if (p_rsp->status != AVRC_STS_NO_ERROR)
+    {
+        BTIF_TRACE_ERROR("%s Error fetching attribute values 0x%02X",
+                __FUNCTION__, p_rsp->status);
+        return;
+    }
+
+    p_app_settings = &btif_rc_cb.rc_app_settings;
+    bdcpy(rc_addr.address, btif_rc_cb.rc_addr);
+
+    if (p_app_settings->attr_index < p_app_settings->num_attrs)
+    {
+        attr_index = p_app_settings->attr_index;
+        p_app_settings->attrs[attr_index].num_val = p_rsp->num_val;
+        for (xx = 0; xx < p_rsp->num_val; xx++)
+        {
+            p_app_settings->attrs[attr_index].attr_val[xx] = p_rsp->vals[xx];
+        }
+        attr_index++;
+        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);
+        }
+        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);
+        }
+        else
+        {
+            for (xx = 0; xx < p_app_settings->num_attrs; xx++)
+            {
+                attrs[xx] = p_app_settings->attrs[xx].attr_id;
+            }
+            get_player_app_setting_cmd (p_app_settings->num_attrs, attrs);
+            HAL_CBACK (bt_rc_ctrl_callbacks, playerapplicationsetting_cb, &rc_addr,
+                        p_app_settings->num_attrs, &p_app_settings->attrs, 0, NULL);
+        }
+    }
+    else if (p_app_settings->ext_attr_index < p_app_settings->num_ext_attrs)
+    {
+        attr_index = p_app_settings->ext_attr_index;
+        p_app_settings->ext_attrs[attr_index].num_val = p_rsp->num_val;
+        for (xx = 0; xx < p_rsp->num_val; xx++)
+        {
+            p_app_settings->ext_attrs[attr_index].ext_attr_val[xx].val = p_rsp->vals[xx];
+        }
+        attr_index++;
+        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);
+        }
+        else
+        {
+            UINT8 attr[AVRC_MAX_APP_ATTR_SIZE];
+            UINT8 xx;
+
+            for (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);
+        }
+    }
+}
+
+/***************************************************************************
+**
+** Function         handle_app_cur_val_response
+**
+** Description      handles the the get attributes value response.
+**
+** Returns          None
+**
+***************************************************************************/
+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 xx;
+
+    /* 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",
+                __FUNCTION__, p_rsp->status);
+        return;
+    }
+
+    bdcpy(rc_addr.address, btif_rc_cb.rc_addr);
+
+    app_settings.num_attr = p_rsp->num_val;
+    for (xx = 0; xx < app_settings.num_attr; xx++)
+    {
+        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 ();
+    osi_freebuf(p_rsp->p_vals);
+}
+
+/***************************************************************************
+**
+** Function         handle_app_attr_txt_response
+**
+** Description      handles the the get attributes text response, if fails
+**                  calls HAL callback with just normal settings and initiates
+**                  query for current settings else initiates query for value text
+** Returns          None
+**
+***************************************************************************/
+static void handle_app_attr_txt_response (tBTA_AV_META_MSG *pmeta_msg, tAVRC_GET_APP_ATTR_TXT_RSP *p_rsp)
+{
+    UINT8 xx, attr_index;
+    UINT8 vals[AVRC_MAX_APP_ATTR_SIZE];
+    btif_rc_player_app_settings_t *p_app_settings;
+    bt_bdaddr_t rc_addr;
+
+    p_app_settings = &btif_rc_cb.rc_app_settings;
+    bdcpy(rc_addr.address, btif_rc_cb.rc_addr);
+
+    /* Todo: Do we need to retry on command timeout */
+    if (p_rsp->status != AVRC_STS_NO_ERROR)
+    {
+        UINT8 attrs[AVRC_MAX_APP_ATTR_SIZE];
+
+        BTIF_TRACE_ERROR("%s Error fetching attribute text: 0x%02X",
+                __FUNCTION__, p_rsp->status);
+        /* Not able to fetch Text for extended Menu, skip the process
+         * and cleanup used memory. Proceed to get the current settings
+         * for standard attributes.
+         */
+        p_app_settings->num_ext_attrs = 0;
+        for (xx = 0; xx < p_app_settings->ext_attr_index; xx++)
+        {
+            osi_freebuf (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++)
+        {
+            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);
+
+        get_player_app_setting_cmd (xx, attrs);
+        return;
+    }
+
+    for (xx = 0; xx < p_rsp->num_attr; xx++)
+    {
+        UINT8 x;
+        for (x = 0; x < p_app_settings->num_ext_attrs; x++)
+        {
+            if (p_app_settings->ext_attrs[x].attr_id == p_rsp->p_attrs[xx].attr_id)
+            {
+                p_app_settings->ext_attrs[x].charset_id = p_rsp->p_attrs[xx].charset_id;
+                p_app_settings->ext_attrs[x].str_len = p_rsp->p_attrs[xx].str_len;
+                p_app_settings->ext_attrs[x].p_str = p_rsp->p_attrs[xx].p_str;
+                break;
+            }
+        }
+    }
+
+    for (xx = 0; xx < p_app_settings->ext_attrs[0].num_val; xx++)
+    {
+        vals[xx] = p_app_settings->ext_attrs[0].ext_attr_val[xx].val;
+    }
+    get_player_app_setting_value_text_cmd(vals, xx);
+}
+
+
+/***************************************************************************
+**
+** Function         handle_app_attr_val_txt_response
+**
+** Description      handles the the get attributes value text response, if fails
+**                  calls HAL callback with just normal settings and initiates
+**                  query for current settings
+** Returns          None
+**
+***************************************************************************/
+static void handle_app_attr_val_txt_response (tBTA_AV_META_MSG *pmeta_msg, tAVRC_GET_APP_ATTR_TXT_RSP *p_rsp)
+{
+    UINT8 xx, attr_index;
+    UINT8 vals[AVRC_MAX_APP_ATTR_SIZE];
+    UINT8 attrs[AVRC_MAX_APP_ATTR_SIZE];
+    btif_rc_player_app_settings_t *p_app_settings;
+    bt_bdaddr_t rc_addr;
+
+    bdcpy(rc_addr.address, btif_rc_cb.rc_addr);
+    p_app_settings = &btif_rc_cb.rc_app_settings;
+
+    /* Todo: Do we need to retry on command timeout */
+    if (p_rsp->status != AVRC_STS_NO_ERROR)
+    {
+        UINT8 attrs[AVRC_MAX_APP_ATTR_SIZE];
+
+        BTIF_TRACE_ERROR("%s Error fetching attribute value text: 0x%02X",
+                __FUNCTION__, p_rsp->status);
+
+        /* Not able to fetch Text for extended Menu, skip the process
+         * and cleanup used memory. Proceed to get the current settings
+         * for standard attributes.
+         */
+        p_app_settings->num_ext_attrs = 0;
+        for (xx = 0; xx < p_app_settings->ext_attr_index; xx++)
+        {
+            int x;
+            btrc_player_app_ext_attr_t *p_ext_attr = &p_app_settings->ext_attrs[xx];
+
+            for (x = 0; x < p_ext_attr->num_val; x++)
+            {
+                osi_freebuf (p_ext_attr->ext_attr_val[x].p_str);
+            }
+            p_ext_attr->num_val = 0;
+            osi_freebuf (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++)
+        {
+            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);
+
+        get_player_app_setting_cmd (xx, attrs);
+        return;
+    }
+
+    for (xx = 0; xx < p_rsp->num_attr; xx++)
+    {
+        UINT8 x;
+        btrc_player_app_ext_attr_t *p_ext_attr;
+        p_ext_attr = &p_app_settings->ext_attrs[p_app_settings->ext_val_index];
+        for (x = 0; x < p_rsp->num_attr; x++)
+        {
+            if (p_ext_attr->ext_attr_val[x].val == p_rsp->p_attrs[xx].attr_id)
+            {
+                p_ext_attr->ext_attr_val[x].charset_id = p_rsp->p_attrs[xx].charset_id;
+                p_ext_attr->ext_attr_val[x].str_len = p_rsp->p_attrs[xx].str_len;
+                p_ext_attr->ext_attr_val[x].p_str = p_rsp->p_attrs[xx].p_str;
+                break;
+            }
+        }
+    }
+    p_app_settings->ext_val_index++;
+
+    if (p_app_settings->ext_val_index < p_app_settings->num_ext_attrs)
+    {
+        attr_index = p_app_settings->ext_val_index;
+        for (xx = 0; xx < p_app_settings->ext_attrs[attr_index].num_val; xx++)
+        {
+            vals[xx] = p_app_settings->ext_attrs[attr_index].ext_attr_val[xx].val;
+        }
+        get_player_app_setting_value_text_cmd(vals, xx);
+    }
+    else
+    {
+        UINT8 x;
+
+        for (xx = 0; xx < p_app_settings->num_attrs; xx++)
+        {
+            attrs[xx] = p_app_settings->attrs[xx].attr_id;
+        }
+        for (x = 0; x < p_app_settings->num_ext_attrs; x++)
+        {
+            attrs[xx+x] = p_app_settings->ext_attrs[x].attr_id;
+        }
+        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);
+
+        /* Free the application settings information after sending to
+         * application.
+         */
+        for (xx = 0; xx < p_app_settings->ext_attr_index; xx++)
+        {
+            int x;
+            btrc_player_app_ext_attr_t *p_ext_attr = &p_app_settings->ext_attrs[xx];
+
+            for (x = 0; x < p_ext_attr->num_val; x++)
+            {
+                osi_freebuf (p_ext_attr->ext_attr_val[x].p_str);
+            }
+            p_ext_attr->num_val = 0;
+            osi_freebuf (p_app_settings->ext_attrs[xx].p_str);
+        }
+        p_app_settings->num_attrs = 0;
+    }
+}
+
+/***************************************************************************
+**
+** Function         handle_set_app_attr_val_response
+**
+** Description      handles the the set attributes value response, if fails
+**                  calls HAL callback to indicate the failure
+** Returns          None
+**
+***************************************************************************/
+static void handle_set_app_attr_val_response (tBTA_AV_META_MSG *pmeta_msg, tAVRC_RSP *p_rsp)
+{
+    uint8_t accepted = 0;
+    bt_bdaddr_t rc_addr;
+
+    bdcpy(rc_addr.address, btif_rc_cb.rc_addr);
+
+    /* For timeout pmeta_msg will be NULL, else we need to
+     * check if this is accepted by TG
+     */
+    if (pmeta_msg && (pmeta_msg->code == AVRC_RSP_ACCEPT))
+    {
+        accepted = 1;
+    }
+    HAL_CBACK(bt_rc_ctrl_callbacks, setplayerappsetting_rsp_cb, &rc_addr, accepted);
+}
+
+/***************************************************************************
+**
+** Function         handle_get_elem_attr_response
+**
+** Description      handles the the element attributes response, calls
+**                  HAL callback to update track change information.
+** Returns          None
+**
+***************************************************************************/
+static void handle_get_elem_attr_response (tBTA_AV_META_MSG *pmeta_msg, tAVRC_GET_ELEM_ATTRS_RSP *p_rsp)
+{
+    btrc_element_attr_val_t *p_attr;
+    bt_bdaddr_t rc_addr;
+    UINT16 xx;
+
+    bdcpy(rc_addr.address, btif_rc_cb.rc_addr);
+
+    if (p_rsp->status == AVRC_STS_NO_ERROR)
+    {
+        p_attr = (btrc_element_attr_val_t*)osi_getbuf (p_rsp->num_attr * sizeof(btrc_element_attr_val_t));
+        if (p_attr != NULL)
+        {
+            memset(p_attr, 0, osi_get_buf_size (p_attr));
+            for (xx = 0; xx < p_rsp->num_attr; xx++)
+            {
+                p_attr[xx].attr_id = p_rsp->p_attrs[xx].attr_id;
+                /* Todo. Legth limit check to include null */
+                if (p_rsp->p_attrs[xx].name.str_len && p_rsp->p_attrs[xx].name.p_str)
+                {
+                    memcpy(p_attr[xx].text, p_rsp->p_attrs[xx].name.p_str,
+                            p_rsp->p_attrs[xx].name.str_len);
+                    osi_freebuf (p_rsp->p_attrs[xx].name.p_str);
+                }
+            }
+            HAL_CBACK(bt_rc_ctrl_callbacks, track_changed_cb,
+                &rc_addr, p_rsp->num_attr, p_attr);
+            osi_freebuf (p_attr);
+        }
+    }
+    else if (p_rsp->status == BTIF_RC_STS_TIMEOUT)
+    {
+        /* Retry for timeout case, this covers error handling
+         * for continuation failure also.
+         */
+        UINT32 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
+    {
+        BTIF_TRACE_ERROR("%s: Error in get element attr procedure %d",
+            __FUNCTION__, p_rsp->status);
+    }
+}
+
+/***************************************************************************
+**
+** Function         handle_get_playstatus_response
+**
+** Description      handles the the play status response, calls
+**                  HAL callback to update play position.
+** Returns          None
+**
+***************************************************************************/
+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);
+
+    if (p_rsp->status == AVRC_STS_NO_ERROR)
+    {
+        HAL_CBACK(bt_rc_ctrl_callbacks, play_position_changed_cb,
+            &rc_addr, p_rsp->song_len, p_rsp->song_pos);
+    }
+    else
+    {
+        BTIF_TRACE_ERROR("%s: Error in get play status procedure %d",
+            __FUNCTION__, p_rsp->status);
+    }
+}
+
+/***************************************************************************
+**
+** Function         clear_cmd_timeout
+**
+** Description      helper function to stop the command timeout timer
+** Returns          None
+**
+***************************************************************************/
+static void clear_cmd_timeout (UINT8 label)
+{
+    rc_transaction_t *p_txn;
+
+    p_txn = get_transaction_by_lbl (label);
+    if (p_txn == NULL)
+    {
+        BTIF_TRACE_ERROR("%s: Error in transaction label lookup", __FUNCTION__);
+        return;
+    }
+
+    btu_stop_timer (&p_txn->tle_txn);
+    if (p_txn->tle_txn.data != NULL)
+    {
+        osi_freebuf (p_txn->tle_txn.data);
+        p_txn->tle_txn.data = NULL;
+    }
+}
+
+/***************************************************************************
+**
+** Function         handle_avk_rc_metamsg_rsp
+**
+** Description      Handle RC metamessage response
+**
+** Returns          void
+**
+***************************************************************************/
+static void handle_avk_rc_metamsg_rsp(tBTA_AV_META_MSG *pmeta_msg)
+{
+    tAVRC_RESPONSE    avrc_response = {0};
+    UINT8             scratch_buf[512] = {0};// this variable is unused
+    UINT16            buf_len;
+    tAVRC_STS         status;
+
+    BTIF_TRACE_DEBUG("%s opcode = %d rsp_code = %d  ", __FUNCTION__,
+                        pmeta_msg->p_msg->hdr.opcode, pmeta_msg->code);
+
+    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",
+                         __FUNCTION__, status, avrc_response.pdu,
+                         pmeta_msg->p_msg->vendor.hdr.ctype);
+
+        switch (avrc_response.pdu)
+        {
+            case AVRC_PDU_REGISTER_NOTIFICATION:
+                handle_notification_response(pmeta_msg, &avrc_response.reg_notif);
+                if (pmeta_msg->code == AVRC_RSP_INTERIM)
+                {
+                    /* Don't free the transaction Id */
+                    clear_cmd_timeout (pmeta_msg->label);
+                    return;
+                }
+                break;
+
+            case AVRC_PDU_GET_CAPABILITIES:
+                handle_get_capability_response(pmeta_msg, &avrc_response.get_caps);
+                break;
+
+            case AVRC_PDU_LIST_PLAYER_APP_ATTR:
+                handle_app_attr_response(pmeta_msg, &avrc_response.list_app_attr);
+                break;
+
+            case AVRC_PDU_LIST_PLAYER_APP_VALUES:
+                handle_app_val_response(pmeta_msg, &avrc_response.list_app_values);
+                break;
+
+            case AVRC_PDU_GET_CUR_PLAYER_APP_VALUE:
+                handle_app_cur_val_response(pmeta_msg, &avrc_response.get_cur_app_val);
+                break;
+
+            case AVRC_PDU_GET_PLAYER_APP_ATTR_TEXT:
+                handle_app_attr_txt_response(pmeta_msg, &avrc_response.get_app_attr_txt);
+                break;
+
+            case AVRC_PDU_GET_PLAYER_APP_VALUE_TEXT:
+                handle_app_attr_val_txt_response(pmeta_msg, &avrc_response.get_app_val_txt);
+                break;
+
+            case AVRC_PDU_SET_PLAYER_APP_VALUE:
+                handle_set_app_attr_val_response(pmeta_msg, &avrc_response.set_app_val);
+                break;
+
+            case AVRC_PDU_GET_ELEMENT_ATTR:
+                handle_get_elem_attr_response(pmeta_msg, &avrc_response.get_elem_attrs);
+                break;
+
+            case AVRC_PDU_GET_PLAY_STATUS:
+                handle_get_playstatus_response(pmeta_msg, &avrc_response.get_play_status);
+                break;
+        }
+        release_transaction(pmeta_msg->label);
+    }
+    else
+    {
+        BTIF_TRACE_DEBUG("%s:Invalid Vendor Command  code: %d len: %d. Not processing it.",
+            __FUNCTION__, pmeta_msg->code, pmeta_msg->len);
+        return;
+    }
+}
+
+/***************************************************************************
+**
+** Function         handle_avk_rc_metamsg_cmd
+**
+** Description      Handle RC metamessage response
+**
+** Returns          void
+**
+***************************************************************************/
+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  ",__FUNCTION__,
+                     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",
+                         __FUNCTION__, pmeta_msg->code, avrc_cmd.pdu, pmeta_msg->label);
+
+        if (status != AVRC_STS_NO_ERROR)
+        {
+            /* return error */
+            BTIF_TRACE_WARNING("%s: Error in parsing received metamsg command. status: 0x%02x",
+                __FUNCTION__, status);
+            send_reject_response(pmeta_msg->rc_handle, pmeta_msg->label, avrc_cmd.pdu, status);
+        }
+        else
+        {
+            if (avrc_cmd.pdu == AVRC_PDU_REGISTER_NOTIFICATION)
+            {
+                UINT8 event_id = avrc_cmd.reg_notif.event_id;
+                BTIF_TRACE_EVENT("%s:Register notification event_id: %s",
+                        __FUNCTION__, 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", __FUNCTION__);
+            }
+            btif_rc_ctrl_upstreams_rsp_cmd(avrc_cmd.pdu, &avrc_cmd, pmeta_msg->label);
+        }
+    }
+    else
+    {
+      BTIF_TRACE_DEBUG("%s:Invalid Vendor Command  code: %d len: %d. Not processing it.",
+                       __FUNCTION__, pmeta_msg->code, pmeta_msg->len);
+        return;
+    }
+}
+#endif
+
+/***************************************************************************
+**
+** Function         cleanup
+**
+** Description      Closes the AVRC interface
+**
+** Returns          void
+**
+***************************************************************************/
+static void cleanup()
+{
+    BTIF_TRACE_EVENT("## %s ##", __FUNCTION__);
+    close_uinput();
+    if (bt_rc_callbacks)
+    {
+        bt_rc_callbacks = NULL;
+    }
+    memset(&btif_rc_cb, 0, sizeof(btif_rc_cb_t));
+    lbl_destroy();
+    BTIF_TRACE_EVENT("## %s ## completed", __FUNCTION__);
+}
+
+/***************************************************************************
+**
+** Function         cleanup_ctrl
+**
+** Description      Closes the AVRC Controller interface
+**
+** Returns          void
+**
+***************************************************************************/
+static void cleanup_ctrl()
+{
+    BTIF_TRACE_EVENT("## %s ##", __FUNCTION__);
+
+    if (bt_rc_ctrl_callbacks)
+    {
+        bt_rc_ctrl_callbacks = NULL;
+    }
+    memset(&btif_rc_cb, 0, sizeof(btif_rc_cb_t));
+    lbl_destroy();
+    BTIF_TRACE_EVENT("## %s ## completed", __FUNCTION__);
+}
+
+/***************************************************************************
+**
+** Function         getcapabilities_cmd
+**
+** Description      GetCapabilties from Remote(Company_ID, Events_Supported)
+**
+** Returns          void
+**
+***************************************************************************/
+static bt_status_t getcapabilities_cmd (uint8_t cap_id)
+{
+    tAVRC_STS status = BT_STATUS_UNSUPPORTED;
+    rc_transaction_t *p_transaction = NULL;
+#if (AVRC_CTLR_INCLUDED == TRUE)
+    BTIF_TRACE_DEBUG("%s: cap_id %d", __FUNCTION__, cap_id);
+    CHECK_RC_CONNECTED
+    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.get_caps.opcode = AVRC_OP_VENDOR;
+     avrc_cmd.get_caps.capability_id = cap_id;
+     avrc_cmd.get_caps.pdu = AVRC_PDU_GET_CAPABILITIES;
+     avrc_cmd.get_caps.status = AVRC_STS_NO_ERROR;
+     status = AVRC_BldCommand(&avrc_cmd, &p_msg);
+     if ((status == AVRC_STS_NO_ERROR)&&(p_msg != NULL))
+     {
+         UINT8* data_start = (UINT8*)(p_msg + 1) + p_msg->offset;
+         BTIF_TRACE_DEBUG("%s msgreq being sent out with label %d",
+                            __FUNCTION__,p_transaction->lbl);
+         BTA_AvVendorCmd(btif_rc_cb.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);
+     }
+     else
+     {
+         BTIF_TRACE_ERROR("%s: failed to build command. status: 0x%02x",
+                             __FUNCTION__, status);
+     }
+     if (p_msg != NULL)
+         osi_freebuf(p_msg);
+#else
+    BTIF_TRACE_DEBUG("%s: feature not enabled", __FUNCTION__);
+#endif
+    return status;
+}
+
+/***************************************************************************
+**
+** Function         list_player_app_setting_attrib_cmd
+**
+** Description      Get supported List Player Attributes
+**
+** Returns          void
+**
+***************************************************************************/
+static bt_status_t list_player_app_setting_attrib_cmd(void)
+{
+    tAVRC_STS status = BT_STATUS_UNSUPPORTED;
+    rc_transaction_t *p_transaction = NULL;
+#if (AVRC_CTLR_INCLUDED == TRUE)
+    BTIF_TRACE_DEBUG("%s: ", __FUNCTION__);
+    CHECK_RC_CONNECTED
+    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.list_app_attr.opcode = AVRC_OP_VENDOR;
+     avrc_cmd.list_app_attr.pdu = AVRC_PDU_LIST_PLAYER_APP_ATTR;
+     avrc_cmd.list_app_attr.status = AVRC_STS_NO_ERROR;
+     status = AVRC_BldCommand(&avrc_cmd, &p_msg);
+     if ((status == AVRC_STS_NO_ERROR)&&(p_msg != NULL))
+     {
+         UINT8* data_start = (UINT8*)(p_msg + 1) + p_msg->offset;
+         BTIF_TRACE_DEBUG("%s msgreq being sent out with label %d",
+                            __FUNCTION__,p_transaction->lbl);
+         BTA_AvVendorCmd(btif_rc_cb.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);
+     }
+     else
+     {
+
+         BTIF_TRACE_ERROR("%s: failed to build command. status: 0x%02x",
+                            __FUNCTION__, status);
+     }
+     if (NULL!=p_msg)
+         osi_freebuf(p_msg);
+#else
+    BTIF_TRACE_DEBUG("%s: feature not enabled", __FUNCTION__);
+#endif
+    return status;
+}
+
+/***************************************************************************
+**
+** Function         list_player_app_setting_value_cmd
+**
+** Description      Get values of supported Player Attributes
+**
+** Returns          void
+**
+***************************************************************************/
+static bt_status_t list_player_app_setting_value_cmd(uint8_t attrib_id)
+{
+    tAVRC_STS status = BT_STATUS_UNSUPPORTED;
+    rc_transaction_t *p_transaction=NULL;
+#if (AVRC_CTLR_INCLUDED == TRUE)
+    BTIF_TRACE_DEBUG("%s: attrib_id %d", __FUNCTION__, attrib_id);
+    CHECK_RC_CONNECTED
+    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.list_app_values.attr_id = attrib_id;
+     avrc_cmd.list_app_values.opcode = AVRC_OP_VENDOR;
+     avrc_cmd.list_app_values.pdu = AVRC_PDU_LIST_PLAYER_APP_VALUES;
+     avrc_cmd.list_app_values.status = AVRC_STS_NO_ERROR;
+     status = AVRC_BldCommand(&avrc_cmd, &p_msg);
+     if ((status == AVRC_STS_NO_ERROR) && (p_msg != NULL))
+     {
+         UINT8* data_start = (UINT8*)(p_msg + 1) + p_msg->offset;
+         BTIF_TRACE_DEBUG("%s msgreq being sent out with label %d",
+                            __FUNCTION__,p_transaction->lbl);
+         BTA_AvVendorCmd(btif_rc_cb.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);
+     }
+     else
+     {
+         BTIF_TRACE_ERROR("%s: failed to build command. status: 0x%02x", __FUNCTION__, status);
+     }
+     if (NULL!=p_msg)
+        osi_freebuf(p_msg);
+#else
+    BTIF_TRACE_DEBUG("%s: feature not enabled", __FUNCTION__);
+#endif
+    return status;
+}
+
+/***************************************************************************
+**
+** Function         get_player_app_setting_cmd
+**
+** Description      Get current values of Player Attributes
+**
+** Returns          void
+**
+***************************************************************************/
+static bt_status_t get_player_app_setting_cmd(uint8_t num_attrib, uint8_t* attrib_ids)
+{
+    tAVRC_STS status = BT_STATUS_UNSUPPORTED;
+    rc_transaction_t *p_transaction = NULL;
+    int count  = 0;
+#if (AVRC_CTLR_INCLUDED == TRUE)
+    BTIF_TRACE_DEBUG("%s: num attrib_id %d", __FUNCTION__, num_attrib);
+    CHECK_RC_CONNECTED
+    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.get_cur_app_val.opcode = AVRC_OP_VENDOR;
+     avrc_cmd.get_cur_app_val.status = AVRC_STS_NO_ERROR;
+     avrc_cmd.get_cur_app_val.num_attr = num_attrib;
+     avrc_cmd.get_cur_app_val.pdu = AVRC_PDU_GET_CUR_PLAYER_APP_VALUE;
+
+     for (count = 0; count < num_attrib; count++)
+     {
+         avrc_cmd.get_cur_app_val.attrs[count] = attrib_ids[count];
+     }
+     status = AVRC_BldCommand(&avrc_cmd, &p_msg);
+     if ((status == AVRC_STS_NO_ERROR) && (p_msg != NULL))
+     {
+         UINT8* data_start = (UINT8*)(p_msg + 1) + p_msg->offset;
+         BTIF_TRACE_DEBUG("%s msgreq being sent out with label %d",
+                            __FUNCTION__,p_transaction->lbl);
+         BTA_AvVendorCmd(btif_rc_cb.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);
+     }
+     else
+     {
+         BTIF_TRACE_ERROR("%s: failed to build command. status: 0x%02x",
+                            __FUNCTION__, status);
+     }
+     if (p_msg != NULL)
+         osi_freebuf(p_msg);
+#else
+    BTIF_TRACE_DEBUG("%s: feature not enabled", __FUNCTION__);
+#endif
+    return status;
+}
+
+/***************************************************************************
+**
+** Function         change_player_app_setting
+**
+** Description      Set current values of Player Attributes
+**
+** 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)
+{
+    tAVRC_STS status = BT_STATUS_UNSUPPORTED;
+    rc_transaction_t *p_transaction = NULL;
+    int count  = 0;
+#if (AVRC_CTLR_INCLUDED == TRUE)
+    BTIF_TRACE_DEBUG("%s: num attrib_id %d", __FUNCTION__, num_attrib);
+    CHECK_RC_CONNECTED
+    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.set_app_val.opcode = AVRC_OP_VENDOR;
+     avrc_cmd.set_app_val.status = AVRC_STS_NO_ERROR;
+     avrc_cmd.set_app_val.num_val = num_attrib;
+     avrc_cmd.set_app_val.pdu = AVRC_PDU_SET_PLAYER_APP_VALUE;
+     avrc_cmd.set_app_val.p_vals =
+           (tAVRC_APP_SETTING*)osi_getbuf(sizeof(tAVRC_APP_SETTING)*num_attrib);
+    if (avrc_cmd.set_app_val.p_vals == NULL)
+    {
+        BTIF_TRACE_ERROR("%s: alloc failed", __FUNCTION__);
+        return BT_STATUS_FAIL;
+    }
+     for (count = 0; count < num_attrib; count++)
+     {
+         avrc_cmd.set_app_val.p_vals[count].attr_id = attrib_ids[count];
+         avrc_cmd.set_app_val.p_vals[count].attr_val = attrib_vals[count];
+     }
+     status = AVRC_BldCommand(&avrc_cmd, &p_msg);
+     if ((status == AVRC_STS_NO_ERROR) && (p_msg != NULL))
+     {
+         UINT8* data_start = (UINT8*)(p_msg + 1) + p_msg->offset;
+         BTIF_TRACE_DEBUG("%s msgreq being sent out with label %d",
+                            __FUNCTION__,p_transaction->lbl);
+         BTA_AvVendorCmd(btif_rc_cb.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);
+     }
+     else
+     {
+         BTIF_TRACE_ERROR("%s: failed to build command. status: 0x%02x",
+                            __FUNCTION__, status);
+     }
+     if (p_msg != NULL)
+         osi_freebuf(p_msg);
+     osi_freebuf(avrc_cmd.set_app_val.p_vals);
+#else
+    BTIF_TRACE_DEBUG("%s: feature not enabled", __FUNCTION__);
+#endif
+    return status;
+}
+
+/***************************************************************************
+**
+** Function         get_player_app_setting_attr_text_cmd
+**
+** Description      Get text description for app attribute
+**
+** Returns          void
+**
+***************************************************************************/
+static bt_status_t get_player_app_setting_attr_text_cmd (UINT8 *attrs, UINT8 num_attrs)
+{
+    tAVRC_STS status = BT_STATUS_UNSUPPORTED;
+    rc_transaction_t *p_transaction = NULL;
+    int count  = 0;
+#if (AVRC_CTLR_INCLUDED == TRUE)
+    tAVRC_COMMAND avrc_cmd = {0};
+    BT_HDR *p_msg = NULL;
+    bt_status_t tran_status;
+    CHECK_RC_CONNECTED
+
+    BTIF_TRACE_DEBUG("%s: num attrs %d", __FUNCTION__, num_attrs);
+
+    tran_status = get_transaction(&p_transaction);
+    if (BT_STATUS_SUCCESS != tran_status)
+        return BT_STATUS_FAIL;
+
+    avrc_cmd.pdu = AVRC_PDU_GET_PLAYER_APP_ATTR_TEXT;
+    avrc_cmd.get_app_attr_txt.opcode = AVRC_OP_VENDOR;
+    avrc_cmd.get_app_attr_txt.num_attr = num_attrs;
+
+    for (count = 0; count < num_attrs; count++)
+    {
+        avrc_cmd.get_app_attr_txt.attrs[count] = attrs[count];
+    }
+    status = AVRC_BldCommand(&avrc_cmd, &p_msg);
+    if (status == AVRC_STS_NO_ERROR)
+    {
+        UINT8* data_start = (UINT8*)(p_msg + 1) + p_msg->offset;
+                BTIF_TRACE_DEBUG("%s msgreq being sent out with label %d",
+                __FUNCTION__, p_transaction->lbl);
+        BTA_AvVendorCmd(btif_rc_cb.rc_handle, p_transaction->lbl,
+                AVRC_CMD_STATUS, data_start, p_msg->len);
+        if (p_msg != NULL)
+            osi_freebuf(p_msg);
+        status =  BT_STATUS_SUCCESS;
+        start_status_command_timer (AVRC_PDU_GET_PLAYER_APP_ATTR_TEXT, p_transaction);
+    }
+    else
+    {
+        BTIF_TRACE_ERROR("%s: failed to build command. status: 0x%02x", __FUNCTION__, status);
+    }
+    if (NULL != p_msg)
+        osi_freebuf(p_msg);
+#else
+    BTIF_TRACE_DEBUG("%s: feature not enabled", __FUNCTION__);
+#endif
+    return status;
+}
+
+/***************************************************************************
+**
+** Function         get_player_app_setting_val_text_cmd
+**
+** Description      Get text description for app attribute values
+**
+** Returns          void
+**
+***************************************************************************/
+static bt_status_t get_player_app_setting_value_text_cmd (UINT8 *vals, UINT8 num_vals)
+{
+    tAVRC_STS status = BT_STATUS_UNSUPPORTED;
+    rc_transaction_t *p_transaction = NULL;
+    int count  = 0;
+#if (AVRC_CTLR_INCLUDED == TRUE)
+    tAVRC_COMMAND avrc_cmd = {0};
+    BT_HDR *p_msg = NULL;
+    bt_status_t tran_status;
+    CHECK_RC_CONNECTED
+
+    BTIF_TRACE_DEBUG("%s: num_vals %d", __FUNCTION__, num_vals);
+
+    tran_status = get_transaction(&p_transaction);
+    if (BT_STATUS_SUCCESS != tran_status)
+        return BT_STATUS_FAIL;
+
+    avrc_cmd.pdu = AVRC_PDU_GET_PLAYER_APP_VALUE_TEXT;
+    avrc_cmd.get_app_val_txt.opcode = AVRC_OP_VENDOR;
+    avrc_cmd.get_app_val_txt.num_val = num_vals;
+
+    for (count = 0; count < num_vals; count++)
+    {
+        avrc_cmd.get_app_val_txt.vals[count] = vals[count];
+    }
+    status = AVRC_BldCommand(&avrc_cmd, &p_msg);
+    if (status == AVRC_STS_NO_ERROR)
+    {
+        UINT8* data_start = (UINT8*)(p_msg + 1) + p_msg->offset;
+        BTIF_TRACE_DEBUG("%s msgreq being sent out with label %d",
+                         __FUNCTION__, p_transaction->lbl);
+        if (p_msg != NULL)
+        {
+            BTA_AvVendorCmd(btif_rc_cb.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);
+        }
+    }
+    else
+    {
+        BTIF_TRACE_ERROR("%s: failed to build command. status: 0x%02x",
+                __FUNCTION__, status);
+    }
+    if (NULL != p_msg)
+        osi_freebuf(p_msg);
+#else
+    BTIF_TRACE_DEBUG("%s: feature not enabled", __FUNCTION__);
+#endif
+    return status;
+}
+
+/***************************************************************************
+**
+** Function         register_notification_cmd
+**
+** Description      Send Command to register for a Notification ID
+**
+** Returns          void
+**
+***************************************************************************/
+static bt_status_t register_notification_cmd (UINT8 label, UINT8 event_id, UINT32 event_value)
+{
+
+    tAVRC_STS status = BT_STATUS_UNSUPPORTED;
+#if (AVRC_CTLR_INCLUDED == TRUE)
+    tAVRC_COMMAND avrc_cmd = {0};
+    BT_HDR *p_msg = NULL;
+    CHECK_RC_CONNECTED
+
+
+    BTIF_TRACE_DEBUG("%s: event_id %d  event_value", __FUNCTION__, event_id, event_value);
+
+    avrc_cmd.reg_notif.opcode = AVRC_OP_VENDOR;
+    avrc_cmd.reg_notif.status = AVRC_STS_NO_ERROR;
+    avrc_cmd.reg_notif.event_id = event_id;
+    avrc_cmd.reg_notif.pdu = AVRC_PDU_REGISTER_NOTIFICATION;
+    avrc_cmd.reg_notif.param = event_value;
+    status = AVRC_BldCommand(&avrc_cmd, &p_msg);
+    if (status == AVRC_STS_NO_ERROR)
+    {
+        UINT8* data_start = (UINT8*)(p_msg + 1) + p_msg->offset;
+        BTIF_TRACE_DEBUG("%s msgreq being sent out with label %d",
+                __FUNCTION__, label);
+        if (p_msg != NULL)
+        {
+            BTA_AvVendorCmd(btif_rc_cb.rc_handle, label, AVRC_CMD_NOTIF,
+                    data_start, p_msg->len);
+            status =  BT_STATUS_SUCCESS;
+        }
+    }
+    else
+    {
+         BTIF_TRACE_ERROR("%s: failed to build command. status: 0x%02x",
+                            __FUNCTION__, status);
+    }
+    if (p_msg != NULL)
+        osi_freebuf(p_msg);
+#else
+    BTIF_TRACE_DEBUG("%s: feature not enabled", __FUNCTION__);
+#endif
+    return status;
+}
+
+/***************************************************************************
+**
+** Function         get_element_attribute_cmd
+**
+** Description      Get Element Attribute for  attributeIds
+**
+** Returns          void
+**
+***************************************************************************/
+static bt_status_t get_element_attribute_cmd (uint8_t num_attribute, uint32_t *p_attr_ids)
+{
+    tAVRC_STS status = BT_STATUS_UNSUPPORTED;
+    rc_transaction_t *p_transaction=NULL;
+    int count  = 0;
+#if (AVRC_CTLR_INCLUDED == TRUE)
+    tAVRC_COMMAND avrc_cmd = {0};
+    BT_HDR *p_msg = NULL;
+    bt_status_t tran_status;
+    CHECK_RC_CONNECTED
+
+    BTIF_TRACE_DEBUG("%s: num_attribute  %d attribute_id %d",
+                   __FUNCTION__, num_attribute, p_attr_ids[0]);
+
+    tran_status = get_transaction(&p_transaction);
+    if (BT_STATUS_SUCCESS != tran_status)
+        return BT_STATUS_FAIL;
+
+    avrc_cmd.get_elem_attrs.opcode = AVRC_OP_VENDOR;
+    avrc_cmd.get_elem_attrs.status = AVRC_STS_NO_ERROR;
+    avrc_cmd.get_elem_attrs.num_attr = num_attribute;
+    avrc_cmd.get_elem_attrs.pdu = AVRC_PDU_GET_ELEMENT_ATTR;
+    for (count = 0; count < num_attribute; count++)
+    {
+        avrc_cmd.get_elem_attrs.attrs[count] = p_attr_ids[count];
+    }
+
+    status = AVRC_BldCommand(&avrc_cmd, &p_msg);
+    if (status == AVRC_STS_NO_ERROR)
+    {
+        UINT8* data_start = (UINT8*)(p_msg + 1) + p_msg->offset;
+        BTIF_TRACE_DEBUG("%s msgreq being sent out with label %d",
+                __FUNCTION__, p_transaction->lbl);
+        if (p_msg != NULL)
+        {
+            BTA_AvVendorCmd(btif_rc_cb.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);
+        }
+    }
+    else
+    {
+         BTIF_TRACE_ERROR("%s: failed to build command. status: 0x%02x",
+                            __FUNCTION__, status);
+    }
+    if (p_msg != NULL)
+        osi_freebuf(p_msg);
+#else
+    BTIF_TRACE_DEBUG("%s: feature not enabled", __FUNCTION__);
+#endif
+    return status;
+}
+
+/***************************************************************************
+**
+** Function         get_play_status_cmd
+**
+** Description      Get Element Attribute for  attributeIds
+**
+** Returns          void
+**
+***************************************************************************/
+static bt_status_t get_play_status_cmd(void)
+{
+    tAVRC_STS status = BT_STATUS_UNSUPPORTED;
+    rc_transaction_t *p_transaction = NULL;
+#if (AVRC_CTLR_INCLUDED == TRUE)
+    tAVRC_COMMAND avrc_cmd = {0};
+    BT_HDR *p_msg = NULL;
+    bt_status_t tran_status;
+    CHECK_RC_CONNECTED
+
+    BTIF_TRACE_DEBUG("%s: ", __FUNCTION__);
+    tran_status = get_transaction(&p_transaction);
+    if (BT_STATUS_SUCCESS != tran_status)
+        return BT_STATUS_FAIL;
+
+    avrc_cmd.get_play_status.opcode = AVRC_OP_VENDOR;
+    avrc_cmd.get_play_status.pdu = AVRC_PDU_GET_PLAY_STATUS;
+    avrc_cmd.get_play_status.status = AVRC_STS_NO_ERROR;
+    status = AVRC_BldCommand(&avrc_cmd, &p_msg);
+    if (status == AVRC_STS_NO_ERROR)
+    {
+        UINT8* data_start = (UINT8*)(p_msg + 1) + p_msg->offset;
+        BTIF_TRACE_DEBUG("%s msgreq being sent out with label %d",
+                __FUNCTION__, p_transaction->lbl);
+        if (p_msg != NULL)
+        {
+            BTA_AvVendorCmd(btif_rc_cb.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);
+        }
+    }
+    else
+    {
+         BTIF_TRACE_ERROR("%s: failed to build command. status: 0x%02x",
+                            __FUNCTION__, status);
+    }
+    if (p_msg != NULL)
+        osi_freebuf(p_msg);
+#else
+    BTIF_TRACE_DEBUG("%s: feature not enabled", __FUNCTION__);
+#endif
+    return status;
+
+}
+
+/***************************************************************************
+**
+** Function         set_volume_rsp
+**
+** Description      Rsp for SetAbsoluteVolume Command
+**
+** Returns          void
+**
+***************************************************************************/
+static bt_status_t set_volume_rsp(bt_bdaddr_t *bd_addr, uint8_t abs_vol, uint8_t label)
+{
+    tAVRC_STS status = BT_STATUS_UNSUPPORTED;
+#if (AVRC_CTLR_INCLUDED == TRUE)
+    tAVRC_RESPONSE avrc_rsp;
+    BT_HDR *p_msg = NULL;
+    CHECK_RC_CONNECTED
+
+    BTIF_TRACE_DEBUG("%s: abs_vol %d", __FUNCTION__, 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);
+    if (status == AVRC_STS_NO_ERROR)
+    {
+        UINT8* data_start = (UINT8*)(p_msg + 1) + p_msg->offset;
+        BTIF_TRACE_DEBUG("%s msgreq being sent out with label %d",
+                __FUNCTION__, btif_rc_cb.rc_vol_label);
+        if (p_msg != NULL)
+        {
+            BTA_AvVendorRsp(btif_rc_cb.rc_handle, label,
+                    BTA_AV_RSP_ACCEPT, data_start, p_msg->len, 0);
+            status =  BT_STATUS_SUCCESS;
+        }
+    }
+    else
+    {
+         BTIF_TRACE_ERROR("%s: failed to build command. status: 0x%02x",
+                            __FUNCTION__, status);
+    }
+    if (p_msg != NULL)
+        osi_freebuf(p_msg);
+#else
+    BTIF_TRACE_DEBUG("%s: feature not enabled", __FUNCTION__);
+#endif
+    return status;
+}
+
+/***************************************************************************
+**
+** Function         send_register_abs_vol_rsp
+**
+** Description      Rsp for Notification of Absolute Volume
+**
+** 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)
+{
+    tAVRC_STS status = BT_STATUS_UNSUPPORTED;
+    tAVRC_RESPONSE avrc_rsp;
+    BT_HDR *p_msg = NULL;
+#if (AVRC_CTLR_INCLUDED == TRUE)
+    BTIF_TRACE_DEBUG("%s: rsp_type  %d abs_vol %d", __FUNCTION__, rsp_type, abs_vol);
+    CHECK_RC_CONNECTED
+
+     avrc_rsp.reg_notif.opcode = AVRC_OP_VENDOR;
+     avrc_rsp.reg_notif.pdu = AVRC_PDU_REGISTER_NOTIFICATION;
+     avrc_rsp.reg_notif.status = AVRC_STS_NO_ERROR;
+     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);
+     if (status == AVRC_STS_NO_ERROR)
+     {
+         BTIF_TRACE_DEBUG("%s msgreq being sent out with label %d",
+                            __FUNCTION__,label);
+         UINT8* data_start = (UINT8*)(p_msg + 1) + p_msg->offset;
+                     BTA_AvVendorRsp(btif_rc_cb.rc_handle, label,
+                (rsp_type == BTRC_NOTIFICATION_TYPE_INTERIM) ? AVRC_RSP_INTERIM : AVRC_RSP_CHANGED,
+                data_start, p_msg->len, 0);
+         if (p_msg != NULL)
+             osi_freebuf(p_msg);
+         status =  BT_STATUS_SUCCESS;
+     }
+     else
+     {
+         if (NULL!=p_msg)
+            osi_freebuf(p_msg);
+         BTIF_TRACE_ERROR("%s: failed to build command. status: 0x%02x",
+                            __FUNCTION__, status);
+     }
+#else
+    BTIF_TRACE_DEBUG("%s: feature not enabled", __FUNCTION__);
+#endif
+    return status;
+}
+
+/***************************************************************************
+**
+** Function         send_groupnavigation_cmd
+**
+** Description      Send Pass-Through command
+**
+** Returns          void
+**
+***************************************************************************/
+static bt_status_t send_groupnavigation_cmd(bt_bdaddr_t *bd_addr, uint8_t key_code,
+                                            uint8_t key_state)
+{
+    tAVRC_STS status = BT_STATUS_UNSUPPORTED;
+#if (AVRC_CTLR_INCLUDED == TRUE)
+    rc_transaction_t *p_transaction=NULL;
+    BTIF_TRACE_DEBUG("%s: key-code: %d, key-state: %d", __FUNCTION__,
+                                                    key_code, key_state);
+    CHECK_RC_CONNECTED
+    if (btif_rc_cb.rc_features & BTA_AV_FEAT_RCTG)
+    {
+        bt_status_t tran_status = get_transaction(&p_transaction);
+        if ((BT_STATUS_SUCCESS == tran_status) && (NULL != p_transaction))
+        {
+             UINT8* p_buf = (UINT8*)osi_getbuf(AVRC_PASS_THRU_GROUP_LEN);
+             if (p_buf != NULL)
+             {
+                 UINT8* start = p_buf;
+                 UINT24_TO_BE_STREAM(start, AVRC_CO_METADATA);
+                 *(start)++ = 0;
+                 UINT8_TO_BE_STREAM(start, key_code);
+                 BTA_AvRemoteVendorUniqueCmd(btif_rc_cb.rc_handle, p_transaction->lbl,
+                    (tBTA_AV_STATE)key_state, p_buf, AVRC_PASS_THRU_GROUP_LEN);
+                status =  BT_STATUS_SUCCESS;
+                BTIF_TRACE_DEBUG("%s: succesfully sent group_navigation command to BTA",
+                                                                          __FUNCTION__);
+             }
+        }
+        else
+        {
+            status =  BT_STATUS_FAIL;
+            BTIF_TRACE_DEBUG("%s: error in fetching transaction", __FUNCTION__);
+        }
+    }
+    else
+    {
+        status =  BT_STATUS_FAIL;
+        BTIF_TRACE_DEBUG("%s: feature not supported", __FUNCTION__);
+    }
+#else
+    BTIF_TRACE_DEBUG("%s: feature not enabled", __FUNCTION__);
+#endif
+    return status;
+}
+
+/***************************************************************************
+**
+** Function         send_passthrough_cmd
+**
+** Description      Send Pass-Through command
+**
+** Returns          void
+**
+***************************************************************************/
+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;
+#if (AVRC_CTLR_INCLUDED == TRUE)
+    CHECK_RC_CONNECTED
+    rc_transaction_t *p_transaction=NULL;
+    BTIF_TRACE_DEBUG("%s: key-code: %d, key-state: %d", __FUNCTION__,
+                                                    key_code, key_state);
+    if (btif_rc_cb.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,
+                (tBTA_AV_RC)key_code, (tBTA_AV_STATE)key_state);
+            status =  BT_STATUS_SUCCESS;
+            BTIF_TRACE_DEBUG("%s: succesfully sent passthrough command to BTA", __FUNCTION__);
+        }
+        else
+        {
+            status =  BT_STATUS_FAIL;
+            BTIF_TRACE_DEBUG("%s: error in fetching transaction", __FUNCTION__);
+        }
+    }
+    else
+    {
+        status =  BT_STATUS_FAIL;
+        BTIF_TRACE_DEBUG("%s: feature not supported", __FUNCTION__);
+    }
+#else
+    BTIF_TRACE_DEBUG("%s: feature not enabled", __FUNCTION__);
+#endif
+    return status;
+}
+
+static const btrc_interface_t bt_rc_interface = {
+    sizeof(bt_rc_interface),
+    init,
+    get_play_status_rsp,
     NULL, /* list_player_app_attr_rsp */
     NULL, /* list_player_app_value_rsp */
     NULL, /* get_player_app_value_rsp */
@@ -1682,6 +4073,10 @@ static const btrc_ctrl_interface_t bt_rc_ctrl_interface = {
     sizeof(bt_rc_ctrl_interface),
     init_ctrl,
     send_passthrough_cmd,
+    send_groupnavigation_cmd,
+    change_player_app_setting,
+    set_volume_rsp,
+    volume_change_notification_rsp,
     cleanup_ctrl,
 };
 
@@ -1725,8 +4120,12 @@ const btrc_ctrl_interface_t *btif_rc_ctrl_get_interface(void)
 static void initialize_transaction(int lbl)
 {
     pthread_mutex_lock(&device.lbllock);
-    if(lbl < MAX_TRANSACTIONS_PER_SESSION)
+    if (lbl < MAX_TRANSACTIONS_PER_SESSION)
     {
+        if (device.transaction[lbl].tle_txn.in_use == TRUE)
+        {
+            clear_cmd_timeout (lbl);
+        }
        device.transaction[lbl].lbl = lbl;
        device.transaction[lbl].in_use=FALSE;
        device.transaction[lbl].handle=0;
@@ -1746,6 +4145,7 @@ void lbl_init()
     memset(&device,0,sizeof(rc_device_t));
     pthread_mutexattr_t attr;
     pthread_mutexattr_init(&attr);
+    pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
     pthread_mutex_init(&(device.lbllock), &attr);
     pthread_mutexattr_destroy(&attr);
     init_all_transactions();
index fc8f166..6da4514 100644 (file)
@@ -670,6 +670,12 @@ bt_status_t btif_storage_get_adapter_property(bt_property_t *property)
                                               p_uuid+num_uuids);
                             num_uuids++;
                         }break;
+                    case BTA_A2DP_SINK_SERVICE_ID:
+                        {
+                            uuid16_to_uuid128(UUID_SERVCLASS_AUDIO_SINK,
+                                              p_uuid+num_uuids);
+                            num_uuids++;
+                        }break;
                     case BTA_HFP_HS_SERVICE_ID:
                         {
                             uuid16_to_uuid128(UUID_SERVCLASS_HF_HANDSFREE,
index fffd61d..45aa1b8 100644 (file)
@@ -525,6 +525,9 @@ const char*  dump_rc_pdu(UINT8 pdu)
         CASE_RETURN_STR(AVRC_PDU_REQUEST_CONTINUATION_RSP)
         CASE_RETURN_STR(AVRC_PDU_ABORT_CONTINUATION_RSP)
         CASE_RETURN_STR(AVRC_PDU_SET_ABSOLUTE_VOLUME)
+        CASE_RETURN_STR(AVRC_PDU_SET_ADDRESSED_PLAYER)
+        CASE_RETURN_STR(AVRC_PDU_CHANGE_PATH)
+        CASE_RETURN_STR(AVRC_PDU_GET_CAPABILITIES)
         default:
             return "Unknown PDU";
     }
index eff6485..e41f036 100644 (file)
@@ -87,7 +87,7 @@
 #endif
 
 #ifndef BTA_AV_SINK_INCLUDED
-#define BTA_AV_SINK_INCLUDED FALSE
+#define BTA_AV_SINK_INCLUDED TRUE
 #endif
 
 #ifndef BTA_DISABLE_DELAY
index 2ae5783..c68c17f 100644 (file)
@@ -21,6 +21,7 @@ LOCAL_SRC_FILES+= \
 # BTIF
 LOCAL_SRC_FILES += \
     ../btif/src/btif_av.c \
+    ../btif/src/btif_avrcp_audio_track.cpp \
     ../btif/src/btif_config.c \
     ../btif/src/btif_config_transcode.cpp \
     ../btif/src/btif_core.c \
@@ -127,7 +128,10 @@ LOCAL_SHARED_LIBRARIES := \
     libcutils \
     libdl \
     liblog \
-    libz
+    libz \
+    libpower \
+    libmedia \
+    libutils
 
 LOCAL_STATIC_LIBRARIES := \
     libtinyxml2 \
index da38c2f..8a06cfb 100644 (file)
@@ -11,6 +11,7 @@ typedef struct list_t list_t;
 
 typedef void (*list_free_cb)(void *data);
 typedef bool (*list_iter_cb)(void *data);
+typedef bool (*list_iter_cb_ext)(void *data, void *cb_data);
 
 // Returns a new, empty list. Returns NULL if not enough memory could be allocated
 // for the list structure. The returned list must be freed with |list_free|. The
@@ -80,6 +81,12 @@ void list_clear(list_t *list);
 // |callback| may be NULL.
 void list_foreach(const list_t *list, list_iter_cb callback);
 
+// Iterates through the entire |list| and calls |callback| for each data element but also passes
+// an additional |cb_data|. The callback should hence accept two arguments.
+//
+// see list_foreach() for other details.
+void list_foreach_ext(const list_t *list, list_iter_cb_ext callback, void *cb_data);
+
 // Returns an iterator to the first element in |list|. |list| may not be NULL.
 // The returned iterator is valid as long as it does not equal the value returned
 // by |list_end|.
index f5f5889..219306f 100644 (file)
@@ -179,6 +179,18 @@ void list_foreach(const list_t *list, list_iter_cb callback) {
   }
 }
 
+void list_foreach_ext(const list_t *list, list_iter_cb_ext callback, void *cb_data) {
+  list_node_t *node;
+
+  assert(list != NULL);
+  assert(callback != NULL);
+  for (node = list->head; node; ) {
+    list_node_t *next = node->next;
+    callback(node->data, cb_data);
+    node = next;
+  }
+}
+
 list_node_t *list_begin(const list_t *list) {
   assert(list != NULL);
   return list->head;
index ce5a158..5e2059d 100644 (file)
@@ -146,3 +146,56 @@ TEST_F(ListTest, test_list_next) {
   EXPECT_EQ(list_next(list_begin(list)), list_end(list));
   list_free(list);
 }
+
+bool iterate_increment_items(void *data) {
+  int *data_cast = (int *)data;
+  *data_cast += 1;
+  return true;
+}
+
+TEST_F(ListTest, test_list_foreach) {
+  list_t *list = list_new(NULL);
+  int item1 = 1;
+  int item2 = 2;
+  list_append(list, &item1);
+  list_append(list, &item2);
+
+  // Increment the items using foreach.
+  list_foreach(list, iterate_increment_items);
+
+  // Check the values to be incremented.
+  // Since we inserted values *1* and *2* in that order we should get *2* and
+  // *3* in that order.
+  const void *node1 = list_node(list_begin(list));
+  EXPECT_EQ(*((int*)(node1)), 2);  /* item1 + 1 = 2 */
+  const void *node2 = list_node(list_next(list_begin(list)));
+  EXPECT_EQ(*((int*)(node2)), 3);  /* item2 + 1 = 3 */
+  list_free(list);
+}
+
+bool iterate_increment_items_with_data(void *data, void *cb_data) {
+  int *data_cast = (int *)data;
+  int *cb_data_cast = (int *)cb_data;
+  // Multiply them.
+  *data_cast = (*data_cast) * (*cb_data_cast);
+  return true;
+}
+
+TEST_F(ListTest, test_list_foreach_ext) {
+  list_t *list = list_new(NULL);
+  int item1 = 10;
+  int item2 = 20;
+  list_append(list, &item1);
+  list_append(list, &item2);
+
+  // Increment the items using foreach.
+  int m_factor = 2;
+  list_foreach_ext(list, iterate_increment_items_with_data, &m_factor);
+
+  // Check that values get multiplied correctly.
+  const void *node1 = list_node(list_begin(list));
+  EXPECT_EQ(*((int*)(node1)), 20);  /* item1 * m_factor = 20 */
+  const void *node2 = list_node(list_next(list_begin(list)));
+  EXPECT_EQ(*((int*)(node2)), 40);  /* item2 * m_factor = 40 */
+  list_free(list);
+}
index fa9f9cc..ea754c7 100644 (file)
@@ -183,7 +183,6 @@ void AVDT_SINK_Activate()
         if ((p_scb->allocated) && (p_scb->cs.tsep == AVDT_TSEP_SNK))
         {
             AVDT_TRACE_DEBUG("AVDT_SINK_Activate found scb");
-            p_scb->sink_activated = TRUE;
             /* update in_use */
             p_scb->in_use = FALSE;
             break;
@@ -214,7 +213,6 @@ void AVDT_SINK_Deactivate()
         if ((p_scb->allocated) && (p_scb->cs.tsep == AVDT_TSEP_SNK))
         {
             AVDT_TRACE_DEBUG("AVDT_SINK_Deactivate, found scb");
-            p_scb->sink_activated = FALSE;
             /* update in_use */
             p_scb->in_use = TRUE;
             break;
index e3c9f3f..f87fcfa 100644 (file)
@@ -489,7 +489,6 @@ typedef struct {
     UINT16          media_seq;      /* media packet sequence number */
     BOOLEAN         allocated;      /* whether scb is allocated or unused */
     BOOLEAN         in_use;         /* whether stream being used by peer */
-    BOOLEAN         sink_activated; /* A2DP Sink activated/de-activated from Application */
     UINT8           role;           /* initiator/acceptor role in current procedure */
     BOOLEAN         remove;         /* whether CB is marked for removal */
     UINT8           state;          /* state machine state */
index 6e73c2e..f7d3c9c 100644 (file)
@@ -599,12 +599,6 @@ tAVDT_SCB *avdt_scb_alloc(tAVDT_CS *p_cs)
             p_scb->allocated = TRUE;
             p_scb->p_ccb = NULL;
 
-            /* initialize sink as activated */
-            if (p_cs->tsep == AVDT_TSEP_SNK)
-            {
-                p_scb->sink_activated = TRUE;
-            }
-
             memcpy(&p_scb->cs, p_cs, sizeof(tAVDT_CS));
 #if AVDT_MULTIPLEXING == TRUE
             /* initialize fragments gueue */
index de072b3..8e74520 100644 (file)
@@ -2073,15 +2073,7 @@ void avdt_scb_tc_timer(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
 void avdt_scb_clr_vars(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
 {
     UNUSED(p_data);
-
-    if ((p_scb->cs.tsep == AVDT_TSEP_SNK) && (!p_scb->sink_activated))
-    {
-        p_scb->in_use = TRUE;
-    }
-    else
-    {
-        p_scb->in_use = FALSE;
-    }
+    p_scb->in_use = FALSE;
     p_scb->p_ccb = NULL;
     p_scb->peer_seid = 0;
 }
old mode 100755 (executable)
new mode 100644 (file)
index a4357cf..88758cf
@@ -375,6 +375,7 @@ static UINT8 avrc_proc_far_msg(UINT8 handle, UINT8 label, UINT8 cr, BT_HDR **pp_
     BT_HDR      *p_pkt = *pp_pkt;
     UINT8       *p_data;
     UINT8       drop_code = 0;
+    BOOLEAN     buf_overflow = FALSE;
     BT_HDR      *p_rsp = NULL;
     BT_HDR      *p_cmd = NULL;
     BOOLEAN     req_continue = FALSE;
@@ -466,6 +467,7 @@ static UINT8 avrc_proc_far_msg(UINT8 handle, UINT8 label, UINT8 cr, BT_HDR **pp_
                     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 */
@@ -529,6 +531,20 @@ static UINT8 avrc_proc_far_msg(UINT8 handle, UINT8 label, UINT8 cr, BT_HDR **pp_
                 AVRC_MsgReq (handle, (UINT8)(label), AVRC_CMD_CTRL, p_cmd);
             }
         }
+        /*
+         * Drop it if we are out of buffer
+         */
+        else if (cr == AVCT_RSP && req_continue == FALSE  && buf_overflow == TRUE)
+        {
+            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)(label), AVRC_CMD_CTRL, p_cmd);
+            }
+        }
     }
 
     return drop_code;
@@ -856,6 +872,7 @@ static BT_HDR  * avrc_pass_msg(tAVRC_MSG_PASS *p_msg)
             {
                 memcpy(p_data, p_msg->p_pass_data, p_msg->pass_len);
                 p_data += p_msg->pass_len;
+                osi_freebuf(p_msg->p_pass_data);
             }
         }
         else /* set msg len to 0 for other op_id */
index 2e4f89a..f09d9a5 100644 (file)
@@ -88,27 +88,263 @@ static tAVRC_STS avrc_bld_set_abs_volume_cmd (tAVRC_SET_VOLUME_CMD *p_cmd, BT_HD
 
 /*******************************************************************************
 **
-** Function         avrc_bld_vol_change_notfn
+** Function         avrc_bld_register_notifn
 **
-** Description      This function builds the register notification for volume change.
+** Description      This function builds the register notification.
 **
 ** Returns          AVRC_STS_NO_ERROR, if the command is built successfully
 **                  Otherwise, the error code.
 **
 *******************************************************************************/
-static tAVRC_STS avrc_bld_vol_change_notfn(BT_HDR * p_pkt)
+static tAVRC_STS avrc_bld_register_notifn(BT_HDR * p_pkt, UINT8 event_id, UINT32 event_param)
 {
     UINT8   *p_data, *p_start;
 
-    AVRC_TRACE_API("avrc_bld_vol_change");
+    AVRC_TRACE_API("avrc_bld_register_notifn");
     /* get the existing length, if any, and also the num attributes */
     // Set the notify value
     p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
     p_data = p_start + 2; /* pdu + rsvd */
     /* add fixed length 5 -*/
     UINT16_TO_BE_STREAM(p_data, 5);
-    UINT8_TO_BE_STREAM(p_data,AVRC_EVT_VOLUME_CHANGE);
-    UINT32_TO_BE_STREAM(p_data, 0);
+    UINT8_TO_BE_STREAM(p_data,event_id);
+    UINT32_TO_BE_STREAM(p_data, event_param);
+    p_pkt->len = (p_data - p_start);
+    return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+**
+** Function         avrc_bld_get_capability_cmd
+**
+** Description      This function builds the get capability command.
+**
+** Returns          AVRC_STS_NO_ERROR, if the command is built successfully
+**                  Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_get_capability_cmd(BT_HDR * p_pkt, UINT8 cap_id)
+{
+    AVRC_TRACE_API("avrc_bld_get_capability_cmd");
+    UINT8 *p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
+    UINT8 *p_data = p_start + 2; /* pdu + rsvd */
+    /* add fixed length 1 -*/
+    UINT16_TO_BE_STREAM(p_data, 1);
+    UINT8_TO_BE_STREAM(p_data,cap_id);
+    p_pkt->len = (p_data - p_start);
+    return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+**
+** Function         avrc_bld_list_player_app_attr_cmd
+**
+** Description      This function builds the list player app attrib command.
+**
+** Returns          AVRC_STS_NO_ERROR, if the command is built successfully
+**                  Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_list_player_app_attr_cmd(BT_HDR * p_pkt)
+{
+    AVRC_TRACE_API("avrc_bld_list_player_app_attr_cmd");
+    UINT8 *p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
+    UINT8 *p_data = p_start + 2; /* pdu + rsvd */
+    /* add fixed length 1 -*/
+    UINT16_TO_BE_STREAM(p_data, 0);
+    p_pkt->len = (p_data - p_start);
+    return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+**
+** Function         avrc_bld_list_player_app_values_cmd
+**
+** Description      This function builds the list player app values command.
+**
+** Returns          AVRC_STS_NO_ERROR, if the command is built successfully
+**                  Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_list_player_app_values_cmd(BT_HDR * p_pkt, UINT8 attrib_id)
+{
+    AVRC_TRACE_API("avrc_bld_list_player_app_values_cmd");
+    UINT8 *p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
+    UINT8 *p_data = p_start + 2; /* pdu + rsvd */
+    /* add fixed length 1 -*/
+    UINT16_TO_BE_STREAM(p_data, 1);
+    UINT8_TO_BE_STREAM(p_data,attrib_id);
+    p_pkt->len = (p_data - p_start);
+    return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+**
+** Function         avrc_bld_get_current_player_app_values_cmd
+**
+** Description      This function builds the get current player app setting values command.
+**
+** Returns          AVRC_STS_NO_ERROR, if the command is built successfully
+**                  Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_get_current_player_app_values_cmd(
+    BT_HDR * p_pkt, UINT8 num_attrib_id, UINT8* attrib_ids)
+{
+    AVRC_TRACE_API("avrc_bld_get_current_player_app_values_cmd");
+    UINT8 *p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
+    UINT8 *p_data = p_start + 2; /* pdu + rsvd */
+    UINT8 param_len = num_attrib_id + 1; // 1 additional to hold num attributes feild
+    /* add length -*/
+    UINT16_TO_BE_STREAM(p_data, param_len);
+    UINT8_TO_BE_STREAM(p_data,num_attrib_id);
+    for(int count = 0; count < num_attrib_id; count ++)
+    {
+        UINT8_TO_BE_STREAM(p_data,attrib_ids[count]);
+    }
+    p_pkt->len = (p_data - p_start);
+    return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+**
+** Function         avrc_bld_set_current_player_app_values_cmd
+**
+** Description      This function builds the set current player app setting values command.
+**
+** Returns          AVRC_STS_NO_ERROR, if the command is built successfully
+**                  Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_set_current_player_app_values_cmd(BT_HDR * p_pkt, UINT8 num_attrib_id, tAVRC_APP_SETTING* p_val)
+{
+    AVRC_TRACE_API("avrc_bld_set_current_player_app_values_cmd");
+    UINT8 *p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
+    UINT8 *p_data = p_start + 2; /* pdu + rsvd */
+    /* we have to store attrib- value pair
+     * 1 additional to store num elements
+     */
+    UINT8 param_len = (2*num_attrib_id) + 1;
+    /* add length */
+    UINT16_TO_BE_STREAM(p_data, param_len);
+    UINT8_TO_BE_STREAM(p_data,num_attrib_id);
+    for(int count = 0; count < num_attrib_id; count ++)
+    {
+        UINT8_TO_BE_STREAM(p_data,p_val[count].attr_id);
+        UINT8_TO_BE_STREAM(p_data,p_val[count].attr_val);
+    }
+    p_pkt->len = (p_data - p_start);
+    return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+**
+** Function         avrc_bld_get_player_app_setting_attr_text_cmd
+**
+** Description      This function builds the get player app setting attribute text command.
+**
+** Returns          AVRC_STS_NO_ERROR, if the command is built successfully
+**                  Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_get_player_app_setting_attr_text_cmd (BT_HDR * p_pkt, tAVRC_GET_APP_ATTR_TXT_CMD *p_cmd)
+{
+    AVRC_TRACE_API("%s", __FUNCTION__);
+
+    UINT8 *p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
+    UINT8 *p_data = p_start + 2; /* pdu + rsvd */
+
+    UINT8 param_len = p_cmd->num_attr + 1;
+    /* add length */
+    UINT16_TO_BE_STREAM(p_data, param_len);
+    UINT8_TO_BE_STREAM(p_data, p_cmd->num_attr);
+    for(int count = 0; count < p_cmd->num_attr; count++)
+    {
+        UINT8_TO_BE_STREAM(p_data, p_cmd->attrs[count]);
+    }
+    p_pkt->len = (p_data - p_start);
+    return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+**
+** Function         avrc_bld_get_player_app_setting_value_text_cmd
+**
+** Description      This function builds the get player app setting value text command.
+**
+** Returns          AVRC_STS_NO_ERROR, if the command is built successfully
+**                  Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_get_player_app_setting_value_text_cmd (BT_HDR * p_pkt, tAVRC_GET_APP_VAL_TXT_CMD *p_cmd)
+{
+    AVRC_TRACE_API("%s", __FUNCTION__);
+
+    UINT8 *p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
+    UINT8 *p_data = p_start + 2; /* pdu + rsvd */
+
+    UINT8 param_len = p_cmd->num_val + 1;
+    /* add length */
+    UINT16_TO_BE_STREAM(p_data, param_len);
+    UINT8_TO_BE_STREAM(p_data, p_cmd->num_val);
+    for(int count = 0; count < p_cmd->num_val; count++)
+    {
+        UINT8_TO_BE_STREAM(p_data, p_cmd->vals[count]);
+    }
+    p_pkt->len = (p_data - p_start);
+    return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+**
+** Function         avrc_bld_get_element_attr_cmd
+**
+** Description      This function builds the get element attribute command.
+**
+** Returns          AVRC_STS_NO_ERROR, if the command is built successfully
+**                  Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_get_element_attr_cmd(BT_HDR * p_pkt, UINT8 num_attrib, UINT32* attrib_ids)
+{
+    AVRC_TRACE_API("avrc_bld_get_element_attr_cmd");
+    UINT8 *p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
+    UINT8 *p_data = p_start + 2; /* pdu + rsvd */
+    /* we have to store attrib- value pair
+     * 1 additional to store num elements
+     */
+    UINT8 param_len = (4*num_attrib) + 9;
+    /* add length */
+    UINT16_TO_BE_STREAM(p_data, param_len);
+    /* 8 bytes of identifier as 0 (playing)*/
+    UINT32_TO_BE_STREAM(p_data,0);
+    UINT32_TO_BE_STREAM(p_data,0);
+    UINT8_TO_BE_STREAM(p_data,num_attrib);
+    for(int count = 0; count < num_attrib; count ++)
+    {
+        UINT32_TO_BE_STREAM(p_data,attrib_ids[count]);
+    }
+    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.
+**
+** Returns          AVRC_STS_NO_ERROR, if the command is built successfully
+**                  Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_get_play_status_cmd(BT_HDR * p_pkt)
+{
+    AVRC_TRACE_API("avrc_bld_list_player_app_attr_cmd");
+    UINT8 *p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
+    UINT8 *p_data = p_start + 2; /* pdu + rsvd */
+    /* add fixed length 1 -*/
+    UINT16_TO_BE_STREAM(p_data, 0);
     p_pkt->len = (p_data - p_start);
     return AVRC_STS_NO_ERROR;
 }
@@ -126,14 +362,10 @@ static tAVRC_STS avrc_bld_vol_change_notfn(BT_HDR * p_pkt)
 *******************************************************************************/
 static BT_HDR *avrc_bld_init_cmd_buffer(tAVRC_COMMAND *p_cmd)
 {
-    UINT16 offset = 0;
-    UINT16 chnl = AVCT_DATA_CTRL;
-    UINT16 len = AVRC_META_CMD_BUF_SIZE;
-    BT_HDR *p_pkt = NULL;
     UINT8  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 offset = 0;
     switch (opcode)
     {
     case AVRC_OP_PASS_THRU:
@@ -146,12 +378,12 @@ static BT_HDR *avrc_bld_init_cmd_buffer(tAVRC_COMMAND *p_cmd)
     }
 
     /* allocate and initialize the buffer */
-    p_pkt = (BT_HDR *)osi_getbuf(len);
+    BT_HDR *p_pkt = (BT_HDR *)osi_getbuf(AVRC_META_CMD_BUF_SIZE);
     if (p_pkt)
     {
         UINT8 *p_data, *p_start;
 
-        p_pkt->layer_specific = chnl;
+        p_pkt->layer_specific = AVCT_DATA_CTRL;
         p_pkt->event    = opcode;
         p_pkt->offset   = offset;
         p_data = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
@@ -192,9 +424,7 @@ static BT_HDR *avrc_bld_init_cmd_buffer(tAVRC_COMMAND *p_cmd)
 tAVRC_STS AVRC_BldCommand( tAVRC_COMMAND *p_cmd, BT_HDR **pp_pkt)
 {
     tAVRC_STS status = AVRC_STS_BAD_PARAM;
-    BT_HDR  *p_pkt;
     BOOLEAN alloc = FALSE;
-
     AVRC_TRACE_API("AVRC_BldCommand: pdu=%x status=%x", p_cmd->cmd.pdu, p_cmd->cmd.status);
     if (!p_cmd || !pp_pkt)
     {
@@ -213,7 +443,7 @@ tAVRC_STS AVRC_BldCommand( tAVRC_COMMAND *p_cmd, BT_HDR **pp_pkt)
         alloc = TRUE;
     }
     status = AVRC_STS_NO_ERROR;
-    p_pkt = *pp_pkt;
+    BT_HDR* p_pkt = *pp_pkt;
 
     switch (p_cmd->pdu)
     {
@@ -229,14 +459,41 @@ tAVRC_STS AVRC_BldCommand( tAVRC_COMMAND *p_cmd, BT_HDR **pp_pkt)
         status = avrc_bld_set_abs_volume_cmd(&p_cmd->volume, p_pkt);
         break;
 #endif
-
-    case AVRC_PDU_REGISTER_NOTIFICATION:      /* 0x31 */
 #if (AVRC_ADV_CTRL_INCLUDED == TRUE)
-        if(AVRC_EVT_VOLUME_CHANGE==p_cmd->reg_notif.event_id)
-           status=avrc_bld_vol_change_notfn(p_pkt);
-#endif
+    case AVRC_PDU_REGISTER_NOTIFICATION:      /* 0x31 */
+        status=avrc_bld_register_notifn(p_pkt,p_cmd->reg_notif.event_id,p_cmd->reg_notif.param);
         break;
-
+    case AVRC_PDU_GET_CAPABILITIES:
+        status = avrc_bld_get_capability_cmd(p_pkt, p_cmd->get_caps.capability_id);
+        break;
+    case AVRC_PDU_LIST_PLAYER_APP_ATTR:
+        status = avrc_bld_list_player_app_attr_cmd(p_pkt);
+        break;
+    case AVRC_PDU_LIST_PLAYER_APP_VALUES:
+        status = avrc_bld_list_player_app_values_cmd(p_pkt,p_cmd->list_app_values.attr_id);
+        break;
+    case AVRC_PDU_GET_CUR_PLAYER_APP_VALUE:
+        status = avrc_bld_get_current_player_app_values_cmd(p_pkt,
+             p_cmd->get_cur_app_val.num_attr,p_cmd->get_cur_app_val.attrs);
+        break;
+    case AVRC_PDU_SET_PLAYER_APP_VALUE:
+        status = avrc_bld_set_current_player_app_values_cmd(p_pkt,
+                     p_cmd->set_app_val.num_val,p_cmd->set_app_val.p_vals);
+        break;
+    case AVRC_PDU_GET_PLAYER_APP_ATTR_TEXT:
+        avrc_bld_get_player_app_setting_attr_text_cmd(p_pkt, &p_cmd->get_app_attr_txt);
+        break;
+    case AVRC_PDU_GET_PLAYER_APP_VALUE_TEXT:
+        avrc_bld_get_player_app_setting_value_text_cmd(p_pkt, &p_cmd->get_app_val_txt);
+        break;
+    case AVRC_PDU_GET_ELEMENT_ATTR:
+        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_GET_PLAY_STATUS:
+        status = avrc_bld_get_play_status_cmd(p_pkt);
+        break;
+#endif
     }
 
     if (alloc && (status != AVRC_STS_NO_ERROR) )
@@ -248,4 +505,3 @@ tAVRC_STS AVRC_BldCommand( tAVRC_COMMAND *p_cmd, BT_HDR **pp_pkt)
     return status;
 }
 #endif /* (AVRC_METADATA_INCLUDED == TRUE) */
-
index 90f2769..e06f711 100644 (file)
@@ -49,12 +49,12 @@ static tAVRC_STS avrc_bld_get_capability_rsp (tAVRC_GET_CAPS_RSP *p_rsp, BT_HDR
 
     if (!(AVRC_IS_VALID_CAP_ID(p_rsp->capability_id)))
     {
-        AVRC_TRACE_ERROR("avrc_bld_get_capability_rsp bad parameter. p_rsp: %x", p_rsp);
+        AVRC_TRACE_ERROR("%s bad parameter. p_rsp: %x", __func__, p_rsp);
         status = AVRC_STS_BAD_PARAM;
         return status;
     }
 
-    AVRC_TRACE_API("avrc_bld_get_capability_rsp");
+    AVRC_TRACE_API("%s", __func__);
     /* get the existing length, if any, and also the num attributes */
     p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
     p_data = p_len = p_start + 2; /* pdu + rsvd */
@@ -122,7 +122,7 @@ static tAVRC_STS avrc_bld_list_app_settings_attr_rsp (tAVRC_LIST_APP_ATTR_RSP *p
     UINT16  len = 0;
     UINT8   xx;
 
-    AVRC_TRACE_API("avrc_bld_list_app_settings_attr_rsp");
+    AVRC_TRACE_API("%s", __func__);
     /* get the existing length, if any, and also the num attributes */
     p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
     p_data = p_len = p_start + 2; /* pdu + rsvd */
@@ -174,7 +174,7 @@ static tAVRC_STS avrc_bld_list_app_settings_values_rsp (tAVRC_LIST_APP_VALUES_RS
     UINT8   xx;
     UINT16  len;
 
-    AVRC_TRACE_API("avrc_bld_list_app_settings_values_rsp");
+    AVRC_TRACE_API("%s", __func__);
 
     p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
     p_data = p_len = p_start + 2; /* pdu + rsvd */
@@ -226,11 +226,11 @@ static tAVRC_STS avrc_bld_get_cur_app_setting_value_rsp (tAVRC_GET_CUR_APP_VALUE
 
     if (!p_rsp->p_vals)
     {
-        AVRC_TRACE_ERROR("avrc_bld_get_cur_app_setting_value_rsp NULL parameter");
+        AVRC_TRACE_ERROR("%s NULL parameter", __func__);
         return AVRC_STS_BAD_PARAM;
     }
 
-    AVRC_TRACE_API("avrc_bld_get_cur_app_setting_value_rsp");
+    AVRC_TRACE_API("%s", __func__);
     /* get the existing length, if any, and also the num attributes */
     p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
     p_data = p_len = p_start + 2; /* pdu + rsvd */
@@ -281,7 +281,7 @@ static tAVRC_STS avrc_bld_set_app_setting_value_rsp (tAVRC_RSP *p_rsp, BT_HDR *p
     UNUSED(p_pkt);
 
     /* nothing to be added. */
-    AVRC_TRACE_API("avrc_bld_set_app_setting_value_rsp");
+    AVRC_TRACE_API("%s", __func__);
     return AVRC_STS_NO_ERROR;
 }
 
@@ -306,7 +306,7 @@ static tAVRC_STS avrc_bld_app_setting_text_rsp (tAVRC_GET_APP_ATTR_TXT_RSP *p_rs
 
     if (!p_rsp->p_attrs)
     {
-        AVRC_TRACE_ERROR("avrc_bld_app_setting_text_rsp NULL parameter");
+        AVRC_TRACE_ERROR("%s NULL parameter", __func__);
         return AVRC_STS_BAD_PARAM;
     }
     /* get the existing length, if any, and also the num attributes */
@@ -331,15 +331,15 @@ static tAVRC_STS avrc_bld_app_setting_text_rsp (tAVRC_GET_APP_ATTR_TXT_RSP *p_rs
     {
         if  (len_left < (p_rsp->p_attrs[xx].str_len + 4))
         {
-            AVRC_TRACE_ERROR("avrc_bld_app_setting_text_rsp out of room (str_len:%d, left:%d)",
-                xx, p_rsp->p_attrs[xx].str_len, len_left);
+            AVRC_TRACE_ERROR("%s out of room (str_len:%d, left:%d)",
+                             __func__, xx, p_rsp->p_attrs[xx].str_len, len_left);
             p_rsp->num_attr = num_added;
             sts = AVRC_STS_INTERNAL_ERR;
             break;
         }
         if ( !p_rsp->p_attrs[xx].str_len || !p_rsp->p_attrs[xx].p_str )
         {
-            AVRC_TRACE_ERROR("avrc_bld_app_setting_text_rsp NULL attr text[%d]", xx);
+            AVRC_TRACE_ERROR("%s NULL attr text[%d]", __func__, xx);
             continue;
         }
         UINT8_TO_BE_STREAM(p_data, p_rsp->p_attrs[xx].attr_id);
@@ -370,7 +370,7 @@ static tAVRC_STS avrc_bld_app_setting_text_rsp (tAVRC_GET_APP_ATTR_TXT_RSP *p_rs
 static tAVRC_STS avrc_bld_get_app_setting_attr_text_rsp (tAVRC_GET_APP_ATTR_TXT_RSP *p_rsp,
     BT_HDR *p_pkt)
 {
-    AVRC_TRACE_API("avrc_bld_get_app_setting_attr_text_rsp");
+    AVRC_TRACE_API("%s", __func__);
     return avrc_bld_app_setting_text_rsp(p_rsp, p_pkt);
 }
 
@@ -388,7 +388,7 @@ static tAVRC_STS avrc_bld_get_app_setting_attr_text_rsp (tAVRC_GET_APP_ATTR_TXT_
 static tAVRC_STS avrc_bld_get_app_setting_value_text_rsp (tAVRC_GET_APP_ATTR_TXT_RSP *p_rsp,
     BT_HDR *p_pkt)
 {
-    AVRC_TRACE_API("avrc_bld_get_app_setting_value_text_rsp");
+    AVRC_TRACE_API("%s", __func__);
     return avrc_bld_app_setting_text_rsp(p_rsp, p_pkt);
 }
 
@@ -409,7 +409,7 @@ static tAVRC_STS avrc_bld_inform_charset_rsp (tAVRC_RSP *p_rsp, BT_HDR *p_pkt)
     UNUSED(p_pkt);
 
     /* nothing to be added. */
-    AVRC_TRACE_API("avrc_bld_inform_charset_rsp");
+    AVRC_TRACE_API("%s", __func__);
     return AVRC_STS_NO_ERROR;
 }
 
@@ -430,7 +430,7 @@ static tAVRC_STS avrc_bld_inform_battery_status_rsp (tAVRC_RSP *p_rsp, BT_HDR *p
     UNUSED(p_pkt);
 
     /* nothing to be added. */
-    AVRC_TRACE_API("avrc_bld_inform_battery_status_rsp");
+    AVRC_TRACE_API("%s", __func__);
     return AVRC_STS_NO_ERROR;
 }
 
@@ -451,10 +451,10 @@ static tAVRC_STS avrc_bld_get_elem_attrs_rsp (tAVRC_GET_ELEM_ATTRS_RSP *p_rsp, B
     UINT16  len;
     UINT8   xx;
 
-    AVRC_TRACE_API("avrc_bld_get_elem_attrs_rsp");
+    AVRC_TRACE_API("%s", __func__);
     if (!p_rsp->p_attrs)
     {
-        AVRC_TRACE_ERROR("avrc_bld_get_elem_attrs_rsp NULL parameter");
+        AVRC_TRACE_ERROR("%s NULL parameter", __func__);
         return AVRC_STS_BAD_PARAM;
     }
 
@@ -479,7 +479,8 @@ 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("avrc_bld_get_elem_attrs_rsp invalid attr id[%d]: %d", xx, 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);
             continue;
         }
         if ( !p_rsp->p_attrs[xx].name.p_str )
@@ -545,7 +546,7 @@ static tAVRC_STS avrc_bld_notify_rsp (tAVRC_REG_NOTIF_RSP *p_rsp, BT_HDR *p_pkt)
     UINT8   xx;
     tAVRC_STS status = AVRC_STS_NO_ERROR;
 
-    AVRC_TRACE_API("avrc_bld_notify_rsp");
+    AVRC_TRACE_API("%s event_id %d", __func__, p_rsp->event_id);
 
     p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
     p_data = p_len = p_start + 2; /* pdu + rsvd */
@@ -564,7 +565,7 @@ static tAVRC_STS avrc_bld_notify_rsp (tAVRC_REG_NOTIF_RSP *p_rsp, BT_HDR *p_pkt)
         }
         else
         {
-            AVRC_TRACE_ERROR("bad play state");
+            AVRC_TRACE_ERROR("%s bad play state", __func__);
             status = AVRC_STS_BAD_PARAM;
         }
         break;
@@ -592,7 +593,7 @@ static tAVRC_STS avrc_bld_notify_rsp (tAVRC_REG_NOTIF_RSP *p_rsp, BT_HDR *p_pkt)
         }
         else
         {
-            AVRC_TRACE_ERROR("bad battery status");
+            AVRC_TRACE_ERROR("%s bad battery status", __func__);
             status = AVRC_STS_BAD_PARAM;
         }
         break;
@@ -605,7 +606,7 @@ static tAVRC_STS avrc_bld_notify_rsp (tAVRC_REG_NOTIF_RSP *p_rsp, BT_HDR *p_pkt)
         }
         else
         {
-            AVRC_TRACE_ERROR("bad system status");
+            AVRC_TRACE_ERROR("%s bad system status", __func__);
             status = AVRC_STS_BAD_PARAM;
         }
         break;
@@ -628,7 +629,7 @@ static tAVRC_STS avrc_bld_notify_rsp (tAVRC_REG_NOTIF_RSP *p_rsp, BT_HDR *p_pkt)
                 }
                 else
                 {
-                    AVRC_TRACE_ERROR("bad player app seeting attribute or value");
+                    AVRC_TRACE_ERROR("%s bad player app seeting attribute or value", __func__);
                     status = AVRC_STS_BAD_PARAM;
                     break;
                 }
@@ -639,9 +640,14 @@ 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:
+        len = 2;
+        UINT8_TO_BE_STREAM(p_data, (AVRC_MAX_VOLUME & p_rsp->param.volume));
+        break;
+
     default:
         status = AVRC_STS_BAD_PARAM;
-        AVRC_TRACE_ERROR("unknown event_id");
+        AVRC_TRACE_ERROR("%s unknown event_id", __func__);
     }
 
     UINT16_TO_BE_STREAM(p_len, len);
@@ -667,7 +673,73 @@ static tAVRC_STS avrc_bld_next_rsp (tAVRC_RSP *p_rsp, BT_HDR *p_pkt)
     UNUSED(p_pkt);
 
     /* nothing to be added. */
-    AVRC_TRACE_API("avrc_bld_next_rsp");
+    AVRC_TRACE_API("%s", __func__);
+    return AVRC_STS_NO_ERROR;
+}
+
+/*****************************************************************************
+**
+** Function      avrc_bld_set_address_player_rsp
+**
+** Description   This function builds the set address player response
+**
+** Returns       AVRC_STS_NO_ERROR
+**
+******************************************************************************/
+static tAVRC_STS avrc_bld_set_address_player_rsp(tAVRC_RSP *p_rsp, BT_HDR *p_pkt)
+{
+    AVRC_TRACE_API("%s", __func__);
+    UINT8 *p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
+    /* To calculate length */
+    UINT8 *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);
+    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 build successfully
+**
+******************************************************************************/
+static tAVRC_STS avrc_bld_play_item_rsp(tAVRC_RSP *p_rsp, BT_HDR *p_pkt)
+{
+    AVRC_TRACE_API("%s", __func__);
+    UINT8 *p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
+    /* To calculate length */
+    UINT8 *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);
+    p_pkt->len = (p_data - p_start);
+    return AVRC_STS_NO_ERROR;
+}
+
+/*****************************************************************************
+**
+** Function      avrc_bld_set_absolute_volume_rsp
+**
+** Description   This function builds the set absolute volume response
+**
+** Returns       AVRC_STS_NO_ERROR, if the response is build successfully
+**
+******************************************************************************/
+static tAVRC_STS avrc_bld_set_absolute_volume_rsp(uint8_t abs_vol, BT_HDR *p_pkt)
+{
+    AVRC_TRACE_API("%s", __func__);
+    UINT8 *p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
+    /* To calculate length */
+    UINT8 *p_data = p_start + 2;
+    /* add fixed lenth status(1) */
+    UINT16_TO_BE_STREAM(p_data, 1);
+    UINT8_TO_BE_STREAM(p_data, abs_vol);
+    p_pkt->len = (p_data - p_start);
     return AVRC_STS_NO_ERROR;
 }
 
@@ -684,16 +756,13 @@ static tAVRC_STS avrc_bld_next_rsp (tAVRC_RSP *p_rsp, BT_HDR *p_pkt)
 *******************************************************************************/
 tAVRC_STS avrc_bld_group_navigation_rsp (UINT16 navi_id, BT_HDR *p_pkt)
 {
-    UINT8   *p_data;
-
     if (!AVRC_IS_VALID_GROUP(navi_id))
     {
-        AVRC_TRACE_ERROR("avrc_bld_group_navigation_rsp bad navigation op id: %d", navi_id);
+        AVRC_TRACE_ERROR("%s bad navigation op id: %d", __func__, navi_id);
         return AVRC_STS_BAD_PARAM;
     }
-
-    AVRC_TRACE_API("avrc_bld_group_navigation_rsp");
-    p_data = (UINT8 *)(p_pkt+1) + p_pkt->offset;
+    AVRC_TRACE_API("%s", __func__);
+    UINT8 *p_data = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
     UINT16_TO_BE_STREAM(p_data, navi_id);
     p_pkt->len = 2;
     return AVRC_STS_NO_ERROR;
@@ -706,18 +775,15 @@ tAVRC_STS avrc_bld_group_navigation_rsp (UINT16 navi_id, BT_HDR *p_pkt)
 ** Description      This function builds the General Response response.
 **
 ** Returns          AVRC_STS_NO_ERROR, if the response is built successfully
-**                  Otherwise, the error code.
 **
 *******************************************************************************/
 static tAVRC_STS avrc_bld_rejected_rsp( tAVRC_RSP *p_rsp, BT_HDR *p_pkt )
 {
-    UINT8 *p_data, *p_start;
+    AVRC_TRACE_API("%s: status=%d, pdu:x%x", __func__, p_rsp->status, p_rsp->pdu);
 
-    AVRC_TRACE_API("avrc_bld_rejected_rsp: status=%d, pdu:x%x", p_rsp->status, p_rsp->pdu);
-
-    p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
-    p_data = p_start + 2;
-    AVRC_TRACE_DEBUG("pdu:x%x", *p_start);
+    UINT8 *p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
+    UINT8 *p_data = p_start + 2;
+    AVRC_TRACE_DEBUG("%s pdu:x%x", __func__, *p_start);
 
     UINT16_TO_BE_STREAM(p_data, 1);
     UINT8_TO_BE_STREAM(p_data, p_rsp->status);
@@ -744,13 +810,12 @@ static BT_HDR *avrc_bld_init_rsp_buffer(tAVRC_RESPONSE *p_rsp)
     BT_HDR *p_pkt = NULL;
     UINT8  opcode = avrc_opcode_from_pdu(p_rsp->pdu);
 
-    AVRC_TRACE_API("avrc_bld_init_rsp_buffer: pdu=%x, opcode=%x/%x", p_rsp->pdu, opcode,
-        p_rsp->rsp.opcode);
+    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 &&
         avrc_is_valid_opcode(p_rsp->rsp.opcode))
     {
         opcode = p_rsp->rsp.opcode;
-        AVRC_TRACE_API("opcode=%x", opcode);
+        AVRC_TRACE_API("%s opcode=%x", __func__, opcode);
     }
 
     switch (opcode)
@@ -819,8 +884,8 @@ tAVRC_STS AVRC_BldResponse( UINT8 handle, tAVRC_RESPONSE *p_rsp, BT_HDR **pp_pkt
 
     if (!p_rsp || !pp_pkt)
     {
-        AVRC_TRACE_API("AVRC_BldResponse. Invalid parameters passed. p_rsp=%p, pp_pkt=%p",
-            p_rsp, pp_pkt);
+        AVRC_TRACE_API("%s Invalid parameters passed. p_rsp=%p, pp_pkt=%p",
+                       __func__, p_rsp, pp_pkt);
         return AVRC_STS_BAD_PARAM;
     }
 
@@ -828,7 +893,7 @@ tAVRC_STS AVRC_BldResponse( UINT8 handle, tAVRC_RESPONSE *p_rsp, BT_HDR **pp_pkt
     {
         if ((*pp_pkt = avrc_bld_init_rsp_buffer(p_rsp)) == NULL)
         {
-            AVRC_TRACE_API("AVRC_BldResponse: Failed to initialize response buffer");
+            AVRC_TRACE_API("%s Failed to initialize response buffer", __func__);
             return AVRC_STS_INTERNAL_ERR;
         }
         alloc = TRUE;
@@ -836,7 +901,7 @@ tAVRC_STS AVRC_BldResponse( UINT8 handle, tAVRC_RESPONSE *p_rsp, BT_HDR **pp_pkt
     status = AVRC_STS_NO_ERROR;
     p_pkt = *pp_pkt;
 
-    AVRC_TRACE_API("AVRC_BldResponse: pdu=%x status=%x", p_rsp->rsp.pdu, p_rsp->rsp.status);
+    AVRC_TRACE_API("%s pdu=%x status=%x", __func__, p_rsp->rsp.pdu, p_rsp->rsp.status);
     if (p_rsp->rsp.status != AVRC_STS_NO_ERROR)
     {
         return( avrc_bld_rejected_rsp(&p_rsp->rsp, p_pkt) );
@@ -904,6 +969,18 @@ tAVRC_STS AVRC_BldResponse( UINT8 handle, tAVRC_RESPONSE *p_rsp, BT_HDR **pp_pkt
     case AVRC_PDU_ABORT_CONTINUATION_RSP:       /*          0x41 */
         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);
+        break;
+
+    case AVRC_PDU_PLAY_ITEM:
+        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;
     }
 
     if (alloc && (status != AVRC_STS_NO_ERROR) )
@@ -911,7 +988,7 @@ tAVRC_STS AVRC_BldResponse( UINT8 handle, tAVRC_RESPONSE *p_rsp, BT_HDR **pp_pkt
         osi_freebuf(p_pkt);
         *pp_pkt = NULL;
     }
-    AVRC_TRACE_API("AVRC_BldResponse: returning %d", status);
+    AVRC_TRACE_API("%s returning %d", __func__, status);
     return status;
 }
 
index a1f5c37..d6b2d14 100644 (file)
@@ -57,7 +57,8 @@ static tAVRC_STS avrc_pars_vendor_rsp(tAVRC_MSG_VENDOR *p_msg, tAVRC_RESPONSE *p
     BE_STREAM_TO_UINT8 (p_result->pdu, p);
     p++; /* skip the reserved/packe_type byte */
     BE_STREAM_TO_UINT16 (len, p);
-    AVRC_TRACE_DEBUG("avrc_pars_vendor_rsp() ctype:0x%x pdu:0x%x, len:%d/0x%x", p_msg->hdr.ctype, p_result->pdu, len, len);
+    AVRC_TRACE_DEBUG("%s ctype:0x%x pdu:0x%x, len:%d/0x%x",
+                     __func__, p_msg->hdr.ctype, p_result->pdu, len, len);
     if (p_msg->hdr.ctype == AVRC_RSP_REJ)
     {
         p_result->rsp.status = *p;
@@ -91,8 +92,8 @@ static tAVRC_STS avrc_pars_vendor_rsp(tAVRC_MSG_VENDOR *p_msg, tAVRC_RESPONSE *p
             p_result->reg_notif.event_id=eventid;
             BE_STREAM_TO_UINT8 (p_result->reg_notif.param.volume, p);
         }
-        AVRC_TRACE_DEBUG("avrc_pars_vendor_rsp PDU reg notif response:event %x, volume %x",eventid,
-            p_result->reg_notif.param.volume);
+        AVRC_TRACE_DEBUG("%s PDU reg notif response:event %x, volume %x",
+                         __func__, eventid, p_result->reg_notif.param.volume);
 #endif /* (AVRC_ADV_CTRL_INCLUDED == TRUE) */
         break;
     default:
@@ -102,6 +103,357 @@ static tAVRC_STS avrc_pars_vendor_rsp(tAVRC_MSG_VENDOR *p_msg, tAVRC_RESPONSE *p
 
     return status;
 }
+#if (AVRC_ADV_CTRL_INCLUDED == TRUE)
+void avrc_parse_notification_rsp (UINT8 *p_stream, tAVRC_REG_NOTIF_RSP *p_rsp)
+{
+    BE_STREAM_TO_UINT8(p_rsp->event_id, p_stream);
+    switch (p_rsp->event_id)
+    {
+        case AVRC_EVT_PLAY_STATUS_CHANGE:
+            BE_STREAM_TO_UINT8(p_rsp->param.play_status, p_stream);
+            break;
+
+        case AVRC_EVT_TRACK_CHANGE:
+            BE_STREAM_TO_ARRAY(p_stream, p_rsp->param.track, 8);
+            break;
+
+        case AVRC_EVT_APP_SETTING_CHANGE:
+            BE_STREAM_TO_UINT8(p_rsp->param.player_setting.num_attr, p_stream);
+            for (int index = 0; index < p_rsp->param.player_setting.num_attr; index++)
+            {
+                BE_STREAM_TO_UINT8(p_rsp->param.player_setting.attr_id[index], p_stream);
+                BE_STREAM_TO_UINT8(p_rsp->param.player_setting.attr_value[index], p_stream);
+            }
+            break;
+
+        case AVRC_EVT_NOW_PLAYING_CHANGE:
+            break;
+
+        case AVRC_EVT_AVAL_PLAYERS_CHANGE:
+            break;
+
+        case AVRC_EVT_ADDR_PLAYER_CHANGE:
+            break;
+
+        case AVRC_EVT_UIDS_CHANGE:
+            break;
+
+        case AVRC_EVT_TRACK_REACHED_END:
+        case AVRC_EVT_TRACK_REACHED_START:
+        case AVRC_EVT_PLAY_POS_CHANGED:
+        case AVRC_EVT_BATTERY_STATUS_CHANGE:
+        case AVRC_EVT_SYSTEM_STATUS_CHANGE:
+        default:
+            break;
+    }
+}
+
+/*******************************************************************************
+**
+** Function         avrc_ctrl_pars_vendor_rsp
+**
+** Description      This function parses the vendor specific commands defined by
+**                  Bluetooth SIG
+**
+** Returns          AVRC_STS_NO_ERROR, if the message in p_data is parsed successfully.
+**                  Otherwise, the error code defined by AVRCP 1.4
+**
+*******************************************************************************/
+static tAVRC_STS avrc_ctrl_pars_vendor_rsp(
+    tAVRC_MSG_VENDOR *p_msg, tAVRC_RESPONSE *p_result, UINT8* p_buf, UINT16* buf_len)
+{
+    UINT8   *p = p_msg->p_vendor_data;
+    BE_STREAM_TO_UINT8 (p_result->pdu, p);
+    p++; /* skip the reserved/packe_type byte */
+
+    UINT16  len;
+    BE_STREAM_TO_UINT16 (len, p);
+    AVRC_TRACE_DEBUG("%s ctype:0x%x pdu:0x%x, len:%d",
+                     __func__, p_msg->hdr.ctype, p_result->pdu, len);
+    /* Todo: Issue in handling reject, check */
+    if (p_msg->hdr.ctype == AVRC_RSP_REJ)
+    {
+        p_result->rsp.status = *p;
+        return p_result->rsp.status;
+    }
+
+    /* TODO: Break the big switch into functions. */
+    switch (p_result->pdu)
+    {
+    /* case AVRC_PDU_REQUEST_CONTINUATION_RSP: 0x40 */
+    /* case AVRC_PDU_ABORT_CONTINUATION_RSP:   0x41 */
+
+    case AVRC_PDU_REGISTER_NOTIFICATION:
+        avrc_parse_notification_rsp(p, &p_result->reg_notif);
+        break;
+
+    case AVRC_PDU_GET_CAPABILITIES:
+        if (len == 0)
+        {
+            p_result->get_caps.count = 0;
+            p_result->get_caps.capability_id = 0;
+            break;
+        }
+        BE_STREAM_TO_UINT8(p_result->get_caps.capability_id, p);
+        BE_STREAM_TO_UINT8(p_result->get_caps.count, p);
+        AVRC_TRACE_DEBUG("%s cap id = %d, cap_count = %d ",
+                         __func__, p_result->get_caps.capability_id, p_result->get_caps.count);
+        if (p_result->get_caps.capability_id == AVRC_CAP_COMPANY_ID)
+        {
+            for(int xx = 0; ((xx < p_result->get_caps.count) && (xx < AVRC_CAP_MAX_NUM_COMP_ID));
+                xx++)
+            {
+                BE_STREAM_TO_UINT24(p_result->get_caps.param.company_id[xx], p);
+            }
+        }
+        else if (p_result->get_caps.capability_id == AVRC_CAP_EVENTS_SUPPORTED)
+        {
+            for(int xx = 0; ((xx < p_result->get_caps.count) && (xx < AVRC_CAP_MAX_NUM_EVT_ID));
+                xx++)
+            {
+                BE_STREAM_TO_UINT8(p_result->get_caps.param.event_id[xx], p);
+            }
+        }
+        break;
+
+    case AVRC_PDU_LIST_PLAYER_APP_ATTR:
+        if (len == 0)
+        {
+            p_result->list_app_attr.num_attr = 0;
+            break;
+        }
+        BE_STREAM_TO_UINT8(p_result->list_app_attr.num_attr, p);
+        AVRC_TRACE_DEBUG("%s attr count = %d ", __func__, p_result->list_app_attr.num_attr);
+        for(int xx = 0; xx < p_result->list_app_attr.num_attr; xx++)
+        {
+            BE_STREAM_TO_UINT8(p_result->list_app_attr.attrs[xx], p);
+        }
+        break;
+
+    case AVRC_PDU_LIST_PLAYER_APP_VALUES:
+        if (len == 0)
+        {
+            p_result->list_app_values.num_val = 0;
+            break;
+        }
+        BE_STREAM_TO_UINT8(p_result->list_app_values.num_val, p);
+        AVRC_TRACE_DEBUG("%s value count = %d ", __func__, p_result->list_app_values.num_val);
+        for(int xx = 0; xx < p_result->list_app_values.num_val; xx++)
+        {
+            BE_STREAM_TO_UINT8(p_result->list_app_values.vals[xx], p);
+        }
+        break;
+
+    case AVRC_PDU_GET_CUR_PLAYER_APP_VALUE:
+    {
+        tAVRC_APP_SETTING *app_sett;
+        if (len == 0)
+        {
+            p_result->get_cur_app_val.num_val = 0;
+            break;
+        }
+        BE_STREAM_TO_UINT8(p_result->get_cur_app_val.num_val, p);
+        app_sett =
+            (tAVRC_APP_SETTING*)osi_getbuf(p_result->get_cur_app_val.num_val*sizeof(tAVRC_APP_SETTING));
+        AVRC_TRACE_DEBUG("%s attr count = %d ", __func__, p_result->get_cur_app_val.num_val);
+        for (int xx = 0; xx < p_result->get_cur_app_val.num_val; xx++)
+        {
+            BE_STREAM_TO_UINT8(app_sett[xx].attr_id, p);
+            BE_STREAM_TO_UINT8(app_sett[xx].attr_val, p);
+        }
+        p_result->get_cur_app_val.p_vals = app_sett;
+    }
+        break;
+
+    case AVRC_PDU_GET_PLAYER_APP_ATTR_TEXT:
+    {
+        tAVRC_APP_SETTING_TEXT   *p_setting_text;
+        UINT8                    num_attrs;
+
+        if (len == 0)
+        {
+            p_result->get_app_attr_txt.num_attr = 0;
+            break;
+        }
+        BE_STREAM_TO_UINT8(num_attrs, p);
+        AVRC_TRACE_DEBUG("%s attr count = %d ", __func__, p_result->get_app_attr_txt.num_attr);
+        p_result->get_app_attr_txt.num_attr = num_attrs;
+        p_setting_text = (tAVRC_APP_SETTING_TEXT*)osi_getbuf(num_attrs * sizeof(tAVRC_APP_SETTING_TEXT));
+        if (p_setting_text == NULL)
+        {
+            p_result->get_app_attr_txt.num_attr = 0;
+            AVRC_TRACE_ERROR("%s alloc fail", __FUNCTION__);
+            break;
+        }
+        for (int xx = 0; xx < num_attrs; xx++)
+        {
+            UINT8 *p_str;
+
+            BE_STREAM_TO_UINT8(p_result->get_app_attr_txt.p_attrs[xx].attr_id, p);
+            BE_STREAM_TO_UINT16(p_result->get_app_attr_txt.p_attrs[xx].charset_id, p);
+            BE_STREAM_TO_UINT8(p_result->get_app_attr_txt.p_attrs[xx].str_len, p);
+            if (p_result->get_app_attr_txt.p_attrs[xx].str_len != 0)
+            {
+                p_str = (UINT8*)osi_getbuf(p_result->get_app_attr_txt.p_attrs[xx].str_len);
+                if (p_str != NULL)
+                {
+                    BE_STREAM_TO_ARRAY(p, p_str, p_result->get_app_attr_txt.p_attrs[xx].str_len);
+                    p_result->get_app_attr_txt.p_attrs[xx].p_str = p_str;
+                }
+                else
+                {
+                    p_result->get_app_attr_txt.p_attrs[xx].str_len = 0;
+                    AVRC_TRACE_ERROR("%s alloc failed for text", __FUNCTION__);
+                }
+            }
+            else
+            {
+                p_result->get_app_attr_txt.p_attrs[xx].p_str = NULL;
+            }
+        }
+    }
+        break;
+
+    case AVRC_PDU_GET_PLAYER_APP_VALUE_TEXT:
+    {
+        tAVRC_APP_SETTING_TEXT   *p_setting_text;
+        UINT8                    num_vals;
+
+        if (len == 0)
+        {
+            p_result->get_app_val_txt.num_attr = 0;
+            break;
+        }
+        BE_STREAM_TO_UINT8(num_vals, p);
+        p_result->get_app_val_txt.num_attr = num_vals;
+        AVRC_TRACE_DEBUG("%s value count = %d ", __func__, p_result->get_app_val_txt.num_attr);
+
+        p_setting_text = (tAVRC_APP_SETTING_TEXT*)osi_getbuf(num_vals * sizeof(tAVRC_APP_SETTING_TEXT));
+        if (p_setting_text == NULL)
+        {
+            p_result->get_app_attr_txt.num_attr = 0;
+            AVRC_TRACE_ERROR("%s alloc fail", __FUNCTION__);
+            break;
+        }
+        for (int xx = 0; xx < num_vals; xx++)
+        {
+            UINT8 *p_str;
+
+            BE_STREAM_TO_UINT8(p_result->get_app_val_txt.p_attrs[xx].attr_id, p);
+            BE_STREAM_TO_UINT16(p_result->get_app_val_txt.p_attrs[xx].charset_id, p);
+            BE_STREAM_TO_UINT8(p_result->get_app_val_txt.p_attrs[xx].str_len, p);
+            if (p_result->get_app_val_txt.p_attrs[xx].str_len != 0)
+            {
+                p_str = (UINT8*)osi_getbuf(p_result->get_app_val_txt.p_attrs[xx].str_len);
+                if (p_str != NULL)
+                {
+                    BE_STREAM_TO_ARRAY(p, p_str, p_result->get_app_val_txt.p_attrs[xx].str_len);
+                    p_result->get_app_val_txt.p_attrs[xx].p_str = p_str;
+                }
+                else
+                {
+                    p_result->get_app_val_txt.p_attrs[xx].str_len = 0;
+                    AVRC_TRACE_ERROR("%s alloc failed for value text", __FUNCTION__);
+                }
+            }
+            else
+            {
+                p_result->get_app_val_txt.p_attrs[xx].p_str = NULL;
+            }
+        }
+    }
+        break;
+
+    case AVRC_PDU_SET_PLAYER_APP_VALUE:
+        /* nothing comes as part of this rsp */
+        break;
+
+    case AVRC_PDU_GET_ELEMENT_ATTR:
+    {
+        tAVRC_ATTR_ENTRY    *p_attrs;
+        UINT8               num_attrs;
+
+        if (len <= 0)
+        {
+            p_result->get_elem_attrs.num_attr = 0;
+            break;
+        }
+        BE_STREAM_TO_UINT8(num_attrs, p);
+        p_result->get_elem_attrs.num_attr = num_attrs;
+        if (num_attrs)
+        {
+            p_attrs = (tAVRC_ATTR_ENTRY*)osi_getbuf(num_attrs * sizeof(tAVRC_ATTR_ENTRY));
+            for (int xx = 0; xx < num_attrs; xx++)
+            {
+                BE_STREAM_TO_UINT32(p_attrs[xx].attr_id, p);
+                BE_STREAM_TO_UINT16(p_attrs[xx].name.charset_id, p);
+                BE_STREAM_TO_UINT16(p_attrs[xx].name.str_len, p);
+                if (p_attrs[xx].name.str_len > 0)
+                {
+                    p_attrs[xx].name.p_str = (UINT8*)osi_getbuf(p_attrs[xx].name.str_len);
+                    if (p_attrs[xx].name.p_str != NULL)
+                    {
+                        BE_STREAM_TO_ARRAY(p, p_attrs[xx].name.p_str, p_attrs[xx].name.str_len);
+                    }
+                    else
+                    {
+                        p_attrs[xx].name.str_len = 0;
+                        AVRC_TRACE_ERROR("%s : alloc failed for attribute", __FUNCTION__);
+                    }
+                }
+            }
+            p_result->get_elem_attrs.p_attrs = p_attrs;
+        }
+    }
+        break;
+
+    case AVRC_PDU_GET_PLAY_STATUS:
+        if (len == 0)
+        {
+            break;
+        }
+        BE_STREAM_TO_UINT32(p_result->get_play_status.song_len, p);
+        BE_STREAM_TO_UINT32(p_result->get_play_status.song_pos, p);
+        BE_STREAM_TO_UINT8(p_result->get_play_status.status, p);
+        break;
+
+    default:
+        return AVRC_STS_BAD_CMD;
+    }
+    return AVRC_STS_NO_ERROR;
+}
+#endif /* (AVRC_ADV_CTRL_INCLUDED == TRUE) */
+
+/*******************************************************************************
+**
+** Function         AVRC_Ctrl_ParsResponse
+**
+** Description      This function is a parse response for AVRCP Controller.
+**
+** Returns          AVRC_STS_NO_ERROR, if the message in p_data is parsed successfully.
+**                  Otherwise, the error code defined by AVRCP 1.4
+**
+*******************************************************************************/
+tAVRC_STS AVRC_Ctrl_ParsResponse (tAVRC_MSG *p_msg, tAVRC_RESPONSE *p_result, UINT8 *p_buf, UINT16* buf_len)
+{
+    tAVRC_STS  status = AVRC_STS_INTERNAL_ERR;
+    if (p_msg && p_result)
+    {
+        switch (p_msg->hdr.opcode)
+        {
+        case AVRC_OP_VENDOR:     /*  0x00    Vendor-dependent commands */
+            status = avrc_ctrl_pars_vendor_rsp(&p_msg->vendor, p_result, p_buf,buf_len);
+            break;
+
+        default:
+            AVRC_TRACE_ERROR("%s unknown opcode:0x%x", __func__, p_msg->hdr.opcode);
+            break;
+        }
+        p_result->rsp.opcode = p_msg->hdr.opcode;
+        p_result->rsp.status = status;
+    }
+    return status;
+}
 
 /*******************************************************************************
 **
@@ -137,7 +489,7 @@ tAVRC_STS AVRC_ParsResponse (tAVRC_MSG *p_msg, tAVRC_RESPONSE *p_result, UINT8 *
             break;
 
         default:
-            AVRC_TRACE_ERROR("AVRC_ParsResponse() unknown opcode:0x%x", p_msg->hdr.opcode);
+            AVRC_TRACE_ERROR("%s unknown opcode:0x%x", __func__, p_msg->hdr.opcode);
             break;
         }
         p_result->rsp.opcode = p_msg->hdr.opcode;
@@ -145,6 +497,4 @@ tAVRC_STS AVRC_ParsResponse (tAVRC_MSG *p_msg, tAVRC_RESPONSE *p_result, UINT8 *
     }
     return status;
 }
-
-
 #endif /* (AVRC_METADATA_INCLUDED == TRUE) */
index 60503c9..3f3fe93 100644 (file)
 *****************************************************************************/
 #if (AVRC_METADATA_INCLUDED == TRUE)
 
+#if (AVRC_CTLR_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function         avrc_ctrl_pars_vendor_cmd
+**
+** Description      This function parses the vendor specific commands defined by
+**                  Bluetooth SIG for AVRCP Conroller.
+**
+** Returns          AVRC_STS_NO_ERROR, if the message in p_data is parsed successfully.
+**                  Otherwise, the error code defined by AVRCP 1.4
+**
+*******************************************************************************/
+static tAVRC_STS avrc_ctrl_pars_vendor_cmd(tAVRC_MSG_VENDOR *p_msg, tAVRC_COMMAND *p_result)
+{
+    tAVRC_STS  status = AVRC_STS_NO_ERROR;
+
+    UINT8   *p = p_msg->p_vendor_data;
+    p_result->pdu = *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__);
+        status = AVRC_STS_BAD_CMD;
+    }
+
+    p++; /* skip the reserved byte */
+    UINT16  len;
+    BE_STREAM_TO_UINT16 (len, p);
+    if ((len+4) != (p_msg->vendor_len))
+    {
+        status = AVRC_STS_INTERNAL_ERR;
+    }
+
+    if (status != AVRC_STS_NO_ERROR)
+        return status;
+
+    switch (p_result->pdu)
+    {
+        case AVRC_PDU_SET_ABSOLUTE_VOLUME:
+        {
+            if(len!=1)
+                status = AVRC_STS_INTERNAL_ERR;
+            else
+            {
+                BE_STREAM_TO_UINT8 (p_result->volume.volume, p);
+                p_result->volume.volume = AVRC_MAX_VOLUME & p_result->volume.volume;
+            }
+            break;
+        }
+        case AVRC_PDU_REGISTER_NOTIFICATION:    /* 0x31 */
+            BE_STREAM_TO_UINT8 (p_result->reg_notif.event_id, p);
+            BE_STREAM_TO_UINT32 (p_result->reg_notif.param, p);
+            break;
+        default:
+            status = AVRC_STS_BAD_CMD;
+            break;
+    }
+    return status;
+}
+#endif
+
 /*******************************************************************************
 **
 ** Function         avrc_pars_vendor_cmd
@@ -59,10 +120,10 @@ static tAVRC_STS avrc_pars_vendor_cmd(tAVRC_MSG_VENDOR *p_msg, tAVRC_COMMAND *p_
 
     p = p_msg->p_vendor_data;
     p_result->pdu = *p++;
-    AVRC_TRACE_DEBUG("avrc_pars_vendor_cmd() pdu:0x%x", p_result->pdu);
+    AVRC_TRACE_DEBUG("%s pdu:0x%x", __func__, p_result->pdu);
     if (!AVRC_IsValidAvcType (p_result->pdu, p_msg->hdr.ctype))
     {
-        AVRC_TRACE_DEBUG("avrc_pars_vendor_cmd() detects wrong AV/C type!");
+        AVRC_TRACE_DEBUG("%s detects wrong AV/C type!", __func__);
         status = AVRC_STS_BAD_CMD;
     }
 
@@ -139,14 +200,16 @@ static tAVRC_STS avrc_pars_vendor_cmd(tAVRC_MSG_VENDOR *p_msg, tAVRC_COMMAND *p_
             }
             if (xx != p_result->set_app_val.num_val)
             {
-                AVRC_TRACE_ERROR("AVRC_PDU_SET_PLAYER_APP_VALUE not enough room:%d orig num_val:%d",
-                    xx, p_result->set_app_val.num_val);
+                AVRC_TRACE_ERROR(
+                    "%s AVRC_PDU_SET_PLAYER_APP_VALUE not enough room:%d orig num_val:%d",
+                    __func__, xx, p_result->set_app_val.num_val);
                 p_result->set_app_val.num_val = xx;
             }
         }
         else
         {
-            AVRC_TRACE_ERROR("AVRC_PDU_SET_PLAYER_APP_VALUE NULL decode buffer or bad len");
+            AVRC_TRACE_ERROR("%s AVRC_PDU_SET_PLAYER_APP_VALUE NULL decode buffer or bad len",
+                             __func__);
             status = AVRC_STS_INTERNAL_ERR;
         }
         break;
@@ -276,6 +339,42 @@ static tAVRC_STS avrc_pars_vendor_cmd(tAVRC_MSG_VENDOR *p_msg, tAVRC_COMMAND *p_
     return status;
 }
 
+#if (AVRC_CTLR_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function         AVRC_Ctrl_ParsCommand
+**
+** Description      This function is used to parse cmds received for CTRL
+**                  Currently it is for SetAbsVolume and Volume Change Notification..
+**
+** Returns          AVRC_STS_NO_ERROR, if the message in p_data is parsed successfully.
+**                  Otherwise, the error code defined by AVRCP 1.4
+**
+*******************************************************************************/
+tAVRC_STS AVRC_Ctrl_ParsCommand (tAVRC_MSG *p_msg, tAVRC_COMMAND *p_result)
+{
+    tAVRC_STS  status = AVRC_STS_INTERNAL_ERR;
+
+    if (p_msg && p_result)
+    {
+        switch (p_msg->hdr.opcode)
+        {
+        case AVRC_OP_VENDOR:     /*  0x00    Vendor-dependent commands */
+            status = avrc_ctrl_pars_vendor_cmd(&p_msg->vendor, p_result);
+            break;
+
+        default:
+            AVRC_TRACE_ERROR("%s unknown opcode:0x%x", __func__, p_msg->hdr.opcode);
+            break;
+        }
+        p_result->cmd.opcode = p_msg->hdr.opcode;
+        p_result->cmd.status = status;
+    }
+    AVRC_TRACE_DEBUG("%s return status:0x%x", __FUNCTION__, status);
+    return status;
+}
+#endif
+
 /*******************************************************************************
 **
 ** Function         AVRC_ParsCommand
@@ -308,13 +407,13 @@ tAVRC_STS AVRC_ParsCommand (tAVRC_MSG *p_msg, tAVRC_COMMAND *p_result, UINT8 *p_
             break;
 
         default:
-            AVRC_TRACE_ERROR("AVRC_ParsCommand() unknown opcode:0x%x", p_msg->hdr.opcode);
+            AVRC_TRACE_ERROR("%s unknown opcode:0x%x", __func__, p_msg->hdr.opcode);
             break;
         }
         p_result->cmd.opcode = p_msg->hdr.opcode;
         p_result->cmd.status = status;
     }
-    AVRC_TRACE_DEBUG("AVRC_ParsCommand() return status:0x%x", status);
+    AVRC_TRACE_DEBUG("%s return status:0x%x", __func__, status);
     return status;
 }
 
index c005788..4b668c4 100644 (file)
@@ -28,7 +28,7 @@
 #include "avrc_int.h"
 
 #ifndef SDP_AVRCP_1_4
-#define SDP_AVRCP_1_4      FALSE
+#define SDP_AVRCP_1_4      TRUE
 #endif
 
 #ifndef SDP_AVCTP_1_4
@@ -218,7 +218,8 @@ UINT16 AVRC_FindService(UINT16 service_uuid, BD_ADDR bd_addr,
 **
 ******************************************************************************/
 UINT16 AVRC_AddRecord(UINT16 service_uuid, char *p_service_name,
-                char *p_provider_name, UINT16 categories, UINT32 sdp_handle)
+                char *p_provider_name, UINT16 categories, UINT32 sdp_handle,
+                BOOLEAN browse_supported)
 {
     UINT16      browse_list[1];
     BOOLEAN     result = TRUE;
@@ -257,9 +258,11 @@ UINT16 AVRC_AddRecord(UINT16 service_uuid, char *p_service_name,
 
     /* add profile descriptor list   */
 #if SDP_AVRCP_1_4 == TRUE
-    /* additional protocol list to include browsing channel */
-    result &= SDP_AddAdditionProtoLists( sdp_handle, 1, (tSDP_PROTO_LIST_ELEM *)avrc_add_proto_list);
-
+    if (browse_supported)
+    {
+        /* additional protocol list to include browsing channel */
+        result &= SDP_AddAdditionProtoLists( sdp_handle, 1, (tSDP_PROTO_LIST_ELEM *)avrc_add_proto_list);
+    }
     result &= SDP_AddProfileDescriptorList(sdp_handle, UUID_SERVCLASS_AV_REMOTE_CONTROL, AVRC_REV_1_4);
 #else
 #if AVRC_METADATA_INCLUDED == TRUE
index 18373c4..b381e84 100644 (file)
@@ -59,6 +59,9 @@ BOOLEAN AVRC_IsValidAvcType(UINT8 pdu_id, UINT8 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;
index 2198074..f1681d5 100644 (file)
@@ -98,6 +98,7 @@
 #define AVRC_SUPF_CT_CAT3               0x0004      /* Category 3 */
 #define AVRC_SUPF_CT_CAT4               0x0008      /* Category 4 */
 #define AVRC_SUPF_CT_BROWSE             0x0040      /* Browsing */
+#define AVRC_SUPF_CT_APP_SETTINGS       0x0010      /* Player Application Settings */
 
 #define AVRC_SUPF_TG_CAT1               0x0001      /* Category 1 */
 #define AVRC_SUPF_TG_CAT2               0x0002      /* Category 2 */
@@ -204,7 +205,7 @@ extern "C"
 **
 ******************************************************************************/
 extern UINT16 AVRC_AddRecord(UINT16 service_uuid, char *p_service_name,
-                char *p_provider_name, UINT16 categories, UINT32 sdp_handle);
+                char *p_provider_name, UINT16 categories, UINT32 sdp_handle, BOOLEAN browse_supported);
 
 /******************************************************************************
 **
@@ -558,6 +559,19 @@ extern void AVRC_Init(void);
 
 /*******************************************************************************
 **
+** Function         AVRC_Ctrl_ParsCommand
+**
+** Description      This function is used to parse cmds received for CTRL
+**                  Currently it is for SetAbsVolume and Volume Change Notification..
+**
+** Returns          AVRC_STS_NO_ERROR, if the message in p_data is parsed successfully.
+**                  Otherwise, the error code defined by AVRCP 1.4
+**
+*******************************************************************************/
+extern tAVRC_STS AVRC_Ctrl_ParsCommand (tAVRC_MSG *p_msg, tAVRC_COMMAND *p_result);
+
+/*******************************************************************************
+**
 ** Function         AVRC_ParsCommand
 **
 ** Description      This function is used to parse the received command.
@@ -584,6 +598,19 @@ extern tAVRC_STS AVRC_ParsResponse (tAVRC_MSG *p_msg, tAVRC_RESPONSE *p_result,
 
 /*******************************************************************************
 **
+** Function         AVRC_Ctrl_ParsResponse
+**
+** Description      This function is a parse response for AVRCP Controller.
+**
+** Returns          AVRC_STS_NO_ERROR, if the message in p_data is parsed successfully.
+**                  Otherwise, the error code defined by AVRCP 1.4
+**
+*******************************************************************************/
+extern tAVRC_STS AVRC_Ctrl_ParsResponse (tAVRC_MSG *p_msg, tAVRC_RESPONSE *p_result,
+   UINT8 *p_buf, UINT16* buf_len);
+
+/*******************************************************************************
+**
 ** Function         AVRC_BldCommand
 **
 ** Description      This function builds the given AVRCP command to the given
index e3e7f6e..cb6178c 100644 (file)
@@ -840,7 +840,7 @@ typedef union
 #define AVRC_IS_VALID_CAP_ID(a)           (((a == AVRC_CAP_COMPANY_ID) || (a == AVRC_CAP_EVENTS_SUPPORTED)) ? TRUE : FALSE)
 
 #define AVRC_IS_VALID_EVENT_ID(a)           (((a >= AVRC_EVT_PLAY_STATUS_CHANGE) && \
-                                              (a <= AVRC_EVT_APP_SETTING_CHANGE)) ? TRUE : FALSE)
+                                              (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)
index 8d76143..688ffb4 100644 (file)
@@ -238,6 +238,8 @@ typedef struct
 /********************************************************************************
 ** Macros to get and put bytes to and from a stream (Little Endian format).
 */
+#define UINT64_TO_BE_STREAM(p, u64) {*(p)++ = (UINT8)((u64) >> 56);  *(p)++ = (UINT8)((u64) >> 48); *(p)++ = (UINT8)((u64) >> 40); *(p)++ = (UINT8)((u64) >> 32); \
+                                     *(p)++ = (UINT8)((u64) >> 24);  *(p)++ = (UINT8)((u64) >> 16); *(p)++ = (UINT8)((u64) >> 8); *(p)++ = (UINT8)(u64); }
 #define UINT32_TO_STREAM(p, u32) {*(p)++ = (UINT8)(u32); *(p)++ = (UINT8)((u32) >> 8); *(p)++ = (UINT8)((u32) >> 16); *(p)++ = (UINT8)((u32) >> 24);}
 #define UINT24_TO_STREAM(p, u24) {*(p)++ = (UINT8)(u24); *(p)++ = (UINT8)((u24) >> 8); *(p)++ = (UINT8)((u24) >> 16);}
 #define UINT16_TO_STREAM(p, u16) {*(p)++ = (UINT8)(u16); *(p)++ = (UINT8)((u16) >> 8);}
@@ -292,6 +294,11 @@ typedef struct
 #define BE_STREAM_TO_UINT16(u16, p) {u16 = (UINT16)(((UINT16)(*(p)) << 8) + (UINT16)(*((p) + 1))); (p) += 2;}
 #define BE_STREAM_TO_UINT24(u32, p) {u32 = (((UINT32)(*((p) + 2))) + ((UINT32)(*((p) + 1)) << 8) + ((UINT32)(*(p)) << 16)); (p) += 3;}
 #define BE_STREAM_TO_UINT32(u32, p) {u32 = ((UINT32)(*((p) + 3)) + ((UINT32)(*((p) + 2)) << 8) + ((UINT32)(*((p) + 1)) << 16) + ((UINT32)(*(p)) << 24)); (p) += 4;}
+#define BE_STREAM_TO_UINT64(u64, p) {u64 = ((UINT64)(*((p) + 7)) + ((UINT64)(*((p) + 6)) << 8) + \
+                                    ((UINT64)(*((p) + 5)) << 16) + ((UINT64)(*((p) + 4)) << 24) + \
+                                    ((UINT64)(*((p) + 3)) << 32) + ((UINT64)(*((p) + 2)) << 40) + \
+                                    ((UINT64)(*((p) + 1)) << 48) + ((UINT64)(*(p)) << 56)); \
+                                    (p) += 8;}
 #define BE_STREAM_TO_ARRAY(p, a, len) {register int ijk; for (ijk = 0; ijk < len; ijk++) ((UINT8 *) a)[ijk] = *p++;}