summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAyan Ghosh <abghosh@codeaurora.org>2014-07-25 17:51:32 +0530
committerLinux Build Service Account <lnxbuild@localhost>2015-10-06 03:21:46 -0600
commiteceafe97c9a07a5bf4e5f84cadaad3b731c38d21 (patch)
treedaa810c800a3e34ae6c812f51b5d279aeac2fd23
parent0887ba37967b83b0264f9f336f5f3d8074daf761 (diff)
downloadandroid_system_bt-eceafe97c9a07a5bf4e5f84cadaad3b731c38d21.tar.gz
android_system_bt-eceafe97c9a07a5bf4e5f84cadaad3b731c38d21.tar.bz2
android_system_bt-eceafe97c9a07a5bf4e5f84cadaad3b731c38d21.zip
AVRCP 1.5 Implementation.
AVRCP 1.5 Implementation Change-Id: Ia35dc4344b05584cf5ab3b463815c9e6297d24ab Proper check to ensure attributes are populated properly Incorporated proper check to ensure if memory is allocated properly then all requested attributes are populated in response from DUT. CRs-Fixed: 753309 Change-Id: Iead549635cd2059bc8cf33585a5d87ae023149d4 Reset Browsing Bit if carkit is blacklisted - Reset Browsing bit if carkit is blacklisted for avrcp 1.5. - Not to send 1.3+ specific supported events if carkit is blacklisted. CRs-Fixed: 762470 Change-Id: I32ac80c0549b2b89dd2522dbb0dea89d255d33dc Free Browse packet Free Borwse packet in AVRC layer once the same is copied to BTA for further processing. CRs-Fixed: 785286 Change-Id: I8037a649cff5a1e527c28ba36999a1bed34d315a BTIF-AV: Use valid memory for AVRCP message After the context switch to BTIF for META message processing the buffer allocated for tAVRC_MSG will be freed, hence allocate the required memory and free that after handling the META message. Conflicts: stack/avrc/avrc_api.c Crs-Fixed: 651506 Change-Id: Icbf61776a6fb63fac1555bf25d3700beccf2b67a
-rw-r--r--bta/av/bta_av_act.c93
-rw-r--r--bta/av/bta_av_cfg.c17
-rw-r--r--bta/include/bta_av_api.h18
-rw-r--r--btif/src/btif_av.c43
-rw-r--r--btif/src/btif_rc.c1217
-rw-r--r--btif/src/btif_util.c5
-rw-r--r--include/bt_target.h13
-rw-r--r--stack/avct/avct_api.c3
-rw-r--r--stack/avct/avct_ccb.c39
-rw-r--r--stack/avct/avct_int.h2
-rw-r--r--stack/avct/avct_l2c.c396
-rw-r--r--stack/avct/avct_lcb.c155
-rw-r--r--stack/avct/avct_lcb_act.c564
-rwxr-xr-xstack/avrc/avrc_api.c385
-rw-r--r--stack/avrc/avrc_bld_tg.c461
-rw-r--r--stack/avrc/avrc_int.h1
-rw-r--r--stack/avrc/avrc_pars_tg.c24
-rw-r--r--stack/avrc/avrc_sdp.c35
-rw-r--r--stack/avrc/avrc_utils.c2
-rw-r--r--stack/include/avct_api.h16
-rw-r--r--stack/include/avrc_api.h15
-rw-r--r--stack/include/avrc_defs.h14
-rw-r--r--stack/include/bt_types.h5
-rw-r--r--stack/include/sdp_api.h14
-rw-r--r--stack/sdp/sdp_api.c15
-rw-r--r--stack/sdp/sdp_server.c178
-rw-r--r--stack/sdp/sdpint.h2
27 files changed, 3500 insertions, 232 deletions
diff --git a/bta/av/bta_av_act.c b/bta/av/bta_av_act.c
index 429d00d2a..fdb50a6a2 100644
--- a/bta/av/bta_av_act.c
+++ b/bta/av/bta_av_act.c
@@ -270,8 +270,13 @@ static void bta_av_rc_msg_cback(UINT8 handle, UINT8 label, UINT8 opcode, tAVRC_M
} else if (opcode == AVRC_OP_PASS_THRU && p_msg->pass.p_pass_data != NULL) {
p_data_src = p_msg->pass.p_pass_data;
data_len = (UINT16) p_msg->pass.pass_len;
+ } else if (opcode == AVRC_OP_BROWSE && p_msg->browse.p_browse_data != NULL) {
+ APPL_TRACE_EVENT("bta_av_rc_msg_cback Browse Data");
+ p_data_src = p_msg->browse.p_browse_data;
+ data_len = (UINT16) p_msg->browse.browse_len;
}
+
/* Create a copy of the message */
tBTA_AV_RC_MSG *p_buf =
(tBTA_AV_RC_MSG *)GKI_getbuf((UINT16)(sizeof(tBTA_AV_RC_MSG) + data_len));
@@ -289,6 +294,8 @@ static void bta_av_rc_msg_cback(UINT8 handle, UINT8 label, UINT8 opcode, tAVRC_M
p_buf->msg.vendor.p_vendor_data = p_data_dst;
else if (opcode == AVRC_OP_PASS_THRU)
p_buf->msg.pass.p_pass_data = p_data_dst;
+ else if (opcode == AVRC_OP_BROWSE)
+ p_buf->msg.browse.p_browse_data = p_data_dst;
}
bta_sys_sendmsg(p_buf);
}
@@ -777,9 +784,11 @@ static tAVRC_STS bta_av_chk_notif_evt_id(tAVRC_MSG_VENDOR *p_vendor)
tBTA_AV_EVT bta_av_proc_meta_cmd(tAVRC_RESPONSE *p_rc_rsp, tBTA_AV_RC_MSG *p_msg, UINT8 *p_ctype)
{
tBTA_AV_EVT evt = BTA_AV_META_MSG_EVT;
- UINT8 u8, pdu, *p;
+ UINT8 u8, pdu, *p, i;
UINT16 u16;
tAVRC_MSG_VENDOR *p_vendor = &p_msg->msg.vendor;
+ BD_ADDR addr;
+ BOOLEAN is_dev_avrcpv_blacklisted = FALSE;
#if (AVRC_METADATA_INCLUDED == TRUE)
@@ -840,8 +849,31 @@ tBTA_AV_EVT bta_av_proc_meta_cmd(tAVRC_RESPONSE *p_rc_rsp, tBTA_AV_RC_MSG *p_ms
{
*p_ctype = AVRC_RSP_IMPL_STBL;
p_rc_rsp->get_caps.count = p_bta_av_cfg->num_evt_ids;
- memcpy(p_rc_rsp->get_caps.param.event_id, p_bta_av_cfg->p_meta_evt_ids,
- p_bta_av_cfg->num_evt_ids);
+ /* DUT has blacklisted few remote dev for Avrcp Version hence
+ * respose for event supported should not have AVRCP 1.5/1.4
+ * version events
+ */
+ if (avct_get_peer_addr_by_ccb(p_msg->handle, addr) == TRUE)
+ {
+ is_dev_avrcpv_blacklisted = SDP_Dev_Blacklisted_For_Avrcp15(addr);
+ BTIF_TRACE_ERROR("Blacklist for AVRCP1.5 = %d", is_dev_avrcpv_blacklisted);
+ }
+ BTIF_TRACE_DEBUG("Blacklist for AVRCP1.5 = %d", is_dev_avrcpv_blacklisted);
+ if (is_dev_avrcpv_blacklisted == TRUE)
+ {
+ for (i = 0; i <= p_bta_av_cfg->num_evt_ids; ++i)
+ {
+ if (p_bta_av_cfg->p_meta_evt_ids[i] == AVRC_EVT_AVAL_PLAYERS_CHANGE)
+ break;
+ }
+ p_rc_rsp->get_caps.count = i;
+ memcpy(p_rc_rsp->get_caps.param.event_id, p_bta_av_cfg->p_meta_evt_ids, i);
+ }
+ else
+ {
+ memcpy(p_rc_rsp->get_caps.param.event_id, p_bta_av_cfg->p_meta_evt_ids,
+ p_bta_av_cfg->num_evt_ids);
+ }
}
else
{
@@ -872,6 +904,39 @@ tBTA_AV_EVT bta_av_proc_meta_cmd(tAVRC_RESPONSE *p_rc_rsp, tBTA_AV_RC_MSG *p_ms
return evt;
}
+/*****************************************************************************
+**
+** Function bta_av_proc_browse_cmd
+**
+** Description Process and AVRCP browse command from the peer
+**
+** Returns status
+**
+****************************************************************************/
+tBTA_AV_EVT bta_av_proc_browse_cmd(tAVRC_RESPONSE *p_rc_rsp, tBTA_AV_RC_MSG *p_msg)
+{
+ tBTA_AV_EVT evt = BTA_AV_BROWSE_MSG_EVT;
+ UINT8 u8, pdu, *p;
+ UINT16 u16;
+ tAVRC_MSG_BROWSE *p_browse = &p_msg->msg.browse;
+
+ pdu = p_browse->p_browse_data[0];
+ APPL_TRACE_DEBUG("bta_av_proc_browse_cmd browse cmd: %x", pdu);
+ switch (pdu)
+ {
+ case AVRC_PDU_GET_FOLDER_ITEMS:
+ case AVRC_PDU_SET_BROWSED_PLAYER:
+ case AVRC_PDU_CHANGE_PATH:
+ case AVRC_PDU_GET_ITEM_ATTRIBUTES:
+ break;
+ default:
+ evt = 0;
+ p_rc_rsp->rsp.status = AVRC_STS_BAD_CMD;
+ APPL_TRACE_ERROR("### Not supported cmd: %x", pdu);
+ break;
+ }
+ return evt;
+}
/*******************************************************************************
**
@@ -895,6 +960,7 @@ void bta_av_rc_msg(tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data)
rc_rsp.rsp.status = BTA_AV_STS_NO_RSP;
#endif
+ APPL_TRACE_DEBUG("bta_av_rc_msg opcode: %x",p_data->rc_msg.opcode);
if (p_data->rc_msg.opcode == AVRC_OP_PASS_THRU)
{
@@ -939,7 +1005,7 @@ 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)
+ else if (p_data->rc_msg.msg.hdr.ctype >= AVRC_RSP_NOT_IMPL)
{
/* set up for callback */
evt = BTA_AV_REMOTE_RSP_EVT;
@@ -1011,6 +1077,25 @@ void bta_av_rc_msg(tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data)
AVRC_VendorRsp(p_data->rc_msg.handle, p_data->rc_msg.label, &p_data->rc_msg.msg.vendor);
}
}
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+ else if (p_data->rc_msg.opcode == AVRC_OP_BROWSE )
+ {
+ APPL_TRACE_DEBUG("browse len PDU :%x",p_data->rc_msg.msg.browse.browse_len);
+ APPL_TRACE_DEBUG("browse data:%x",p_data->rc_msg.msg.browse.p_browse_data[0]);
+ av.browse_msg.label = p_data->rc_msg.label;
+ av.browse_msg.p_msg = &p_data->rc_msg.msg;
+
+ evt = bta_av_proc_browse_cmd(&rc_rsp, &p_data->rc_msg);
+ if (evt == 0)
+ {
+ APPL_TRACE_ERROR("Browse PDU not supported");
+ rc_rsp.rsp.pdu = AVRC_PDU_GENERAL_REJECT;
+ rc_rsp.rsp.status = AVRC_STS_BAD_CMD;
+ ctype = 0;
+ AVRC_BldBrowseResponse(0, &rc_rsp, &p_pkt);
+ }
+ }
+#endif
#if (AVRC_METADATA_INCLUDED == TRUE)
if (evt == 0 && rc_rsp.rsp.status != BTA_AV_STS_NO_RSP)
{
diff --git a/bta/av/bta_av_cfg.c b/bta/av/bta_av_cfg.c
index 8768934b5..6e9a7b4de 100644
--- a/bta/av/bta_av_cfg.c
+++ b/bta/av/bta_av_cfg.c
@@ -65,21 +65,32 @@ const UINT16 bta_av_audio_flush_to[] = {
/* Note: Android doesnt support AVRC_SUPF_TG_GROUP_NAVI */
/* Note: if AVRC_SUPF_TG_GROUP_NAVI is set, bta_av_cfg.avrc_group should be TRUE */
#if AVRC_METADATA_INCLUDED == TRUE
-#define BTA_AV_RC_SUPF_TG (AVRC_SUPF_TG_CAT1) /* TODO: | AVRC_SUPF_TG_APP_SETTINGS) */
+
+#if AVCT_BROWSE_INCLUDED == TRUE
+#define BTA_AV_RC_SUPF_TG (AVRC_SUPF_TG_CAT1 | AVRC_SUPF_TG_BROWSE | AVRC_SUPF_TG_APP_SETTINGS)
+#else
+#define BTA_AV_RC_SUPF_TG (AVRC_SUPF_TG_CAT1 | AVRC_SUPF_TG_APP_SETTINGS)
+#endif
+
#else
#define BTA_AV_RC_SUPF_TG (AVRC_SUPF_TG_CAT1)
#endif
/*
* If the number of event IDs is changed in this array, BTA_AV_ NUM_RC_EVT_IDS also needs to be changed.
+ * AVRCP 1.3 specific events to be added before AVCT_BROWSE_INCLUDED.
*/
const UINT8 bta_av_meta_caps_evt_ids[] = {
AVRC_EVT_PLAY_STATUS_CHANGE,
AVRC_EVT_TRACK_CHANGE,
AVRC_EVT_PLAY_POS_CHANGED,
- /* TODO: Add support for these events
AVRC_EVT_APP_SETTING_CHANGE,
- */
+#if AVCT_BROWSE_INCLUDED == TRUE
+ AVRC_EVT_NOW_PLAYING_CHANGE,
+ AVRC_EVT_AVAL_PLAYERS_CHANGE,
+ AVRC_EVT_ADDR_PLAYER_CHANGE,
+ AVRC_EVT_NOW_PLAYING_CHANGE,
+#endif
};
#ifndef BTA_AV_NUM_RC_EVT_IDS
#define BTA_AV_NUM_RC_EVT_IDS (sizeof(bta_av_meta_caps_evt_ids) / sizeof(bta_av_meta_caps_evt_ids[0]))
diff --git a/bta/include/bta_av_api.h b/bta/include/bta_av_api.h
index a78796c81..c57c95844 100644
--- a/bta/include/bta_av_api.h
+++ b/bta/include/bta_av_api.h
@@ -249,10 +249,11 @@ typedef UINT8 tBTA_AV_ERR;
#define BTA_AV_META_MSG_EVT 17 /* metadata messages */
#define BTA_AV_REJECT_EVT 18 /* incoming connection rejected */
#define BTA_AV_RC_FEAT_EVT 19 /* remote control channel peer supported features update */
-#define BTA_AV_MEDIA_SINK_CFG_EVT 20 /* command to configure codec */
-#define BTA_AV_MEDIA_DATA_EVT 21 /* sending data to Media Task */
+#define BTA_AV_BROWSE_MSG_EVT 20 /* Browse MSG EVT */
+#define BTA_AV_MEDIA_SINK_CFG_EVT 21 /* command to configure codec */
+#define BTA_AV_MEDIA_DATA_EVT 22 /* sending data to Media Task */
/* Max BTA event */
-#define BTA_AV_MAX_EVT 22
+#define BTA_AV_MAX_EVT 23
typedef UINT8 tBTA_AV_EVT;
@@ -411,6 +412,16 @@ typedef struct
tAVRC_MSG *p_msg;
} tBTA_AV_META_MSG;
+/*data associated with BTA_AV_BROWSE_MSG_EVT */
+typedef struct
+{
+ UINT8 rc_handle;
+ UINT16 len;
+ UINT8 label;
+ UINT8 *p_data;
+ tAVRC_MSG *p_msg;
+}tBTA_AV_BROWSE_MSG;
+
/* data associated with BTA_AV_PENDING_EVT */
typedef struct
{
@@ -446,6 +457,7 @@ typedef union
tBTA_AV_SUSPEND suspend;
tBTA_AV_PEND pend;
tBTA_AV_META_MSG meta_msg;
+ tBTA_AV_BROWSE_MSG browse_msg;
tBTA_AV_REJECT reject;
tBTA_AV_RC_FEAT rc_feat;
} tBTA_AV;
diff --git a/btif/src/btif_av.c b/btif/src/btif_av.c
index ad357d878..c671b33c2 100644
--- a/btif/src/btif_av.c
+++ b/btif/src/btif_av.c
@@ -127,6 +127,7 @@ else\
case BTA_AV_REMOTE_CMD_EVT: \
case BTA_AV_VENDOR_CMD_EVT: \
case BTA_AV_META_MSG_EVT: \
+ case BTA_AV_BROWSE_MSG_EVT: \
case BTA_AV_RC_FEAT_EVT: \
case BTA_AV_REMOTE_RSP_EVT: \
{ \
@@ -358,6 +359,7 @@ static BOOLEAN btif_av_state_idle_handler(btif_sm_event_t event, void *p_data)
case BTA_AV_META_MSG_EVT:
case BTA_AV_RC_FEAT_EVT:
case BTA_AV_REMOTE_RSP_EVT:
+ case BTA_AV_BROWSE_MSG_EVT:
btif_rc_handler(event, (tBTA_AV*)p_data);
break;
@@ -1018,6 +1020,33 @@ void btif_av_event_deep_copy(UINT16 event, char *p_dest, char *p_src)
}
}
break;
+ case BTA_AV_BROWSE_MSG_EVT:
+ if (av_src->browse_msg.p_data && av_src->browse_msg.len)
+ {
+ av_dest->browse_msg.p_data = osi_calloc(av_src->browse_msg.len);
+ assert(av_dest->browse_msg.p_data);
+ memcpy(av_dest->browse_msg.p_data,
+ av_src->browse_msg.p_data, av_src->browse_msg.len);
+ }
+
+ if (av_src->browse_msg.p_msg)
+ {
+ av_dest->browse_msg.p_msg = osi_calloc(sizeof(tAVRC_MSG));
+ assert(av_dest->browse_msg.p_msg);
+ memcpy(av_dest->browse_msg.p_msg, av_src->browse_msg.p_msg, sizeof(tAVRC_MSG));
+
+ if (av_src->browse_msg.p_msg->browse.p_browse_data &&
+ av_src->browse_msg.p_msg->browse.browse_len)
+ {
+ av_dest->browse_msg.p_msg->browse.p_browse_data = osi_calloc(
+ av_src->browse_msg.p_msg->browse.browse_len);
+ assert(av_dest->browse_msg.p_msg->browse.p_browse_data);
+ memcpy(av_dest->browse_msg.p_msg->browse.p_browse_data,
+ av_src->browse_msg.p_msg->browse.p_browse_data,
+ av_src->browse_msg.p_msg->browse.browse_len);
+ }
+ }
+ break;
default:
break;
@@ -1042,6 +1071,20 @@ static void btif_av_event_free_data(btif_sm_event_t event, void *p_data)
}
}
break;
+ case BTA_AV_BROWSE_MSG_EVT:
+ {
+ tBTA_AV *av = (tBTA_AV*)p_data;
+ if (av->browse_msg.p_data)
+ osi_free(av->browse_msg.p_data);
+
+ if (av->browse_msg.p_msg)
+ {
+ if (av->browse_msg.p_msg->browse.p_browse_data)
+ osi_free(av->browse_msg.p_msg->browse.p_browse_data);
+ osi_free(av->browse_msg.p_msg);
+ }
+ }
+ break;
default:
break;
diff --git a/btif/src/btif_rc.c b/btif/src/btif_rc.c
index 93be30f5a..3fefbbaf9 100644
--- a/btif/src/btif_rc.c
+++ b/btif/src/btif_rc.c
@@ -47,21 +47,31 @@
/* 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 IDX_GET_PLAY_STATUS_RSP 0
-#define IDX_LIST_APP_ATTR_RSP 1
-#define IDX_LIST_APP_VALUE_RSP 2
-#define IDX_GET_CURR_APP_VAL_RSP 3
-#define IDX_SET_APP_VAL_RSP 4
-#define IDX_GET_APP_ATTR_TXT_RSP 5
-#define IDX_GET_APP_VAL_TXT_RSP 6
-#define IDX_GET_ELEMENT_ATTR_RSP 7
+#define MAX_RC_NOTIFICATIONS AVRC_EVT_VOLUME_CHANGE
+//#define TEST_BROWSE_RESPONSE
+#define MAX_FOLDER_RSP_SUPPORT 3
+
+#define IDX_GET_PLAY_STATUS_RSP 0
+#define IDX_LIST_APP_ATTR_RSP 1
+#define IDX_LIST_APP_VALUE_RSP 2
+#define IDX_GET_CURR_APP_VAL_RSP 3
+#define IDX_SET_APP_VAL_RSP 4
+#define IDX_GET_APP_ATTR_TXT_RSP 5
+#define IDX_GET_APP_VAL_TXT_RSP 6
+#define IDX_GET_ELEMENT_ATTR_RSP 7
+#define IDX_GET_FOLDER_ITEMS_RSP 8
+#define IDX_SET_FOLDER_ITEM_RSP 9
+#define IDX_SET_ADDRESS_PLAYER_RSP 10
+#define IDX_SET_BROWSE_PLAYER_RSP 11
+#define IDX_CHANGE_PATH_RSP 12
+#define IDX_PLAY_ITEM_RSP 13
+#define IDX_GET_ITEM_ATTR_RSP 14
#define MAX_VOLUME 128
#define MAX_LABEL 16
#define MAX_TRANSACTIONS_PER_SESSION 16
-#define MAX_CMD_QUEUE_LEN 8
#define PLAY_STATUS_PLAYING 1
+#define MAX_CMD_QUEUE_LEN 15
+#define ERR_PLAYER_NOT_ADDRESED 0x13
#define CHECK_RC_CONNECTED \
BTIF_TRACE_DEBUG("## %s ##", __FUNCTION__); \
@@ -92,6 +102,21 @@
btif_rc_cb.rc_pdu_info[index].is_rsp_pending = FALSE; \
}
+
+#define SEND_BROWSEMSG_RSP(index , avrc_rsp) \
+{ \
+ if(btif_rc_cb.rc_pdu_info[index].is_rsp_pending == FALSE) \
+ { \
+ BTIF_TRACE_WARNING("%s Not sending response as no PDU was registered", __FUNCTION__); \
+ return BT_STATUS_UNHANDLED; \
+ } \
+ send_browsemsg_rsp(btif_rc_cb.rc_handle, btif_rc_cb.rc_pdu_info[index].label, \
+ btif_rc_cb.rc_pdu_info[index].ctype, avrc_rsp); \
+ btif_rc_cb.rc_pdu_info[index].ctype = 0; \
+ btif_rc_cb.rc_pdu_info[index].label = 0; \
+ btif_rc_cb.rc_pdu_info[index].is_rsp_pending = FALSE; \
+}
+
/*****************************************************************************
** Local type definitions
******************************************************************************/
@@ -206,6 +231,12 @@ static rc_transaction_t* get_transaction_by_lbl(UINT8 label);
static void handle_rc_metamsg_rsp(tBTA_AV_META_MSG *pmeta_msg);
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);
+static bt_status_t set_addrplayer_rsp(btrc_status_t status_code);
+
+/*Added for Browsing Message Response */
+static void send_browsemsg_rsp (UINT8 rc_handle, UINT8 label,
+ tBTA_AV_CODE code, tAVRC_RESPONSE *pmetamsg_resp);
+
/*****************************************************************************
** Static variables
@@ -223,7 +254,7 @@ static btrc_ctrl_callbacks_t *bt_rc_ctrl_callbacks = NULL;
******************************************************************************/
extern BOOLEAN btif_hf_call_terminated_recently();
extern BOOLEAN check_cod(const bt_bdaddr_t *remote_bdaddr, uint32_t cod);
-
+extern BOOLEAN btif_hf_is_call_idle();
/*****************************************************************************
** Functions
@@ -801,6 +832,277 @@ void handle_rc_metamsg_cmd (tBTA_AV_META_MSG *pmeta_msg)
}
}
+/************************************************************************************
+* Function handle_get_folder_item_mediaplyerlist_cmd
+*
+* - Argument: tBTA_AV_BROWSE_MSG structure containing the received
+* browse message
+* tAVRC_COMMAND structure containing the commands
+* to be updated
+* UINT8 event, variable having value of event.
+*
+* - Description: Handler for get media player list command
+*
+************************************************************************************/
+UINT8 handle_get_folder_item_mediaplyerlist_cmd (tBTA_AV_BROWSE_MSG *pbrowse_msg,
+ tAVRC_COMMAND *cmd, UINT8 *event)
+{
+ UINT8 *p_length, *start_item, *end_item;
+ UINT8 length, xx;
+ *event = pbrowse_msg->p_msg->browse.p_browse_data[0] ;
+ cmd->get_items.pdu = *event;
+ //Check length
+ p_length = &pbrowse_msg->p_msg->browse.p_browse_data[1];
+ BE_STREAM_TO_UINT16(length, p_length);
+ if (length != 10) //Refer to spec
+ {
+ BTIF_TRACE_ERROR("GET_FOLDER_ITEMS: length error: =%d",length);
+ return TRUE;
+ }
+ else
+ {
+ start_item = &pbrowse_msg->p_msg->browse.p_browse_data[4];
+ BE_STREAM_TO_UINT32(cmd->get_items.start_item ,start_item);
+ BTIF_TRACE_EVENT("pbrowse_msg start_item :%x",cmd->get_items.start_item);
+ end_item = &pbrowse_msg->p_msg->browse.p_browse_data[8];
+ BE_STREAM_TO_UINT32(cmd->get_items.end_item,end_item);
+ BTIF_TRACE_EVENT("pbrowse_msg start_item :%x",cmd->get_items.end_item);
+ cmd->get_items.attr_count = 0xff; /* in MediaPlayerList we don't have attr_id */
+ //Update OPCODE
+ cmd->get_items.opcode = AVRC_OP_BROWSE;
+ cmd->get_items.scope = pbrowse_msg->p_msg->browse.p_browse_data[3] ;
+ cmd->get_items.status = AVRC_STS_NO_ERROR ;
+ for (xx = 0; xx < BTRC_MAX_ELEM_ATTR_SIZE ; xx++)
+ {
+ cmd->get_items.attrs[xx] = 0;
+ }
+ return FALSE;
+ }
+}
+
+/************************************************************************************
+* Function handle_get_folder_item_filesystem_cmd
+*
+* - Argument: tBTA_AV_BROWSE_MSG structure containing the received
+* browse message
+* tAVRC_COMMAND structure containing the commands
+* to be updated
+* UINT8 event, variable having value of event.
+*
+* - Description: Handler for get folder item command
+*
+************************************************************************************/
+UINT8 handle_get_folder_item_filesystem_cmd (tBTA_AV_BROWSE_MSG *pbrowse_msg, tAVRC_COMMAND *cmd,
+ UINT8 *event)
+{
+ UINT8 *p_length, *start_item, *end_item, *p_data;
+ UINT8 length, attr_count = 0, xx;
+ *event = pbrowse_msg->p_msg->browse.p_browse_data[0] ;
+ cmd->get_items.pdu = *event;
+ //Check length
+ p_length = &pbrowse_msg->p_msg->browse.p_browse_data[1];
+ BE_STREAM_TO_UINT16(length, p_length);
+ attr_count = pbrowse_msg->p_msg->browse.p_browse_data[12];
+ BTIF_TRACE_ERROR("GET_FOLDER_ITEMS: attr_count: =%d", attr_count);
+ switch (attr_count)
+ {
+ case 0xff:
+ if (length != 10)
+ {
+ BTIF_TRACE_ERROR("GET_FOLDER_ITEMS: length error: =%d", length);
+ return TRUE;
+ }
+ break;
+ default:
+ if (length != ((attr_count * 4) + 10))
+ {
+ BTIF_TRACE_ERROR("GET_FOLDER_ITEMS: length error: =%d", length);
+ return TRUE;
+ }
+ }
+
+ start_item = &pbrowse_msg->p_msg->browse.p_browse_data[4];
+ BE_STREAM_TO_UINT32(cmd->get_items.start_item ,start_item);
+ BTIF_TRACE_EVENT("pbrowse_msg start_item :%x",cmd->get_items.start_item);
+ end_item = &pbrowse_msg->p_msg->browse.p_browse_data[8];
+ BE_STREAM_TO_UINT32(cmd->get_items.end_item,end_item);
+ BTIF_TRACE_EVENT("pbrowse_msg start_item :%x",cmd->get_items.end_item);
+ cmd->get_items.attr_count = attr_count;
+ if (attr_count == 0)
+ {
+ for (xx = 0; xx < BTRC_MAX_ELEM_ATTR_SIZE; xx++)
+ {
+ cmd->get_items.attrs[xx] = xx + 1;
+ }
+ }
+ else if (attr_count == 0xff) /* no attribute requested */
+ {
+ BTIF_TRACE_DEBUG("No attribute requested");
+ }
+ else
+ {
+ p_data = &pbrowse_msg->p_msg->browse.p_browse_data[13];
+ for (xx = 0; xx < attr_count; xx++)
+ BE_STREAM_TO_UINT32(cmd->get_items.attrs[xx], p_data)
+ }
+ //Update OPCODE
+ cmd->get_items.opcode = AVRC_OP_BROWSE;
+ cmd->get_items.scope = pbrowse_msg->p_msg->browse.p_browse_data[3] ;
+ cmd->get_items.status = AVRC_STS_NO_ERROR ;
+ return FALSE;
+}
+
+/************************************************************************************
+* Function handle_rc_browsemsg_cmd
+*
+* - Argument: tBTA_AV_BROWSE_MSG structure containing the recieved
+* browse message
+*
+* - Description: Remote Control browse message handler
+*
+************************************************************************************/
+void handle_rc_browsemsg_cmd (tBTA_AV_BROWSE_MSG *pbrowse_msg)
+{
+ UINT8 event;
+ UINT16 length;
+ tAVRC_COMMAND cmd;
+ UINT8 *start_item, *p_length, *p_data;
+ UINT8 *end_item;
+ tAVRC_RESPONSE avrc_rsp;
+ UINT8 dropmsg = TRUE;
+
+ BTIF_TRACE_EVENT("+ %s", __FUNCTION__);
+ BTIF_TRACE_EVENT("pbrowse_msg PDU_ID :%x",pbrowse_msg->p_msg->browse.p_browse_data[0]);
+ BTIF_TRACE_EVENT("pbrowse_msg length :%x",pbrowse_msg->p_msg->browse.browse_len);
+ switch(pbrowse_msg->p_msg->browse.p_browse_data[0])
+ {
+ case AVRC_PDU_GET_FOLDER_ITEMS:
+ {
+ UINT8 scope = pbrowse_msg->p_msg->browse.p_browse_data[3];
+ switch (scope)
+ {
+ case AVRC_SCOPE_PLAYER_LIST:
+ dropmsg = handle_get_folder_item_mediaplyerlist_cmd(pbrowse_msg, &cmd, &event);
+ break;
+ case AVRC_SCOPE_FILE_SYSTEM:
+ case AVRC_SCOPE_NOW_PLAYING:
+ dropmsg = handle_get_folder_item_filesystem_cmd(pbrowse_msg, &cmd, &event);
+ break;
+ }
+ if (dropmsg == FALSE)
+ {
+ btif_rc_upstreams_evt(event,&cmd,0,pbrowse_msg->label);
+ }
+ }
+ break;
+
+ case AVRC_PDU_SET_BROWSED_PLAYER:
+ event = pbrowse_msg->p_msg->browse.p_browse_data[0] ;
+ cmd.br_player.pdu = event;
+ //Check for length
+ p_length = &pbrowse_msg->p_msg->browse.p_browse_data[1];
+ BE_STREAM_TO_UINT16(length, p_length);
+ if (length != 0x0002)
+ {
+ BTIF_TRACE_ERROR("SET_BROWSED_PLAYERlength error: = %d", length);
+ }
+ else
+ {
+ p_length = &pbrowse_msg->p_msg->browse.p_browse_data[3];
+ BE_STREAM_TO_UINT16(cmd.br_player.player_id, p_length);
+ cmd.br_player.opcode = AVRC_OP_BROWSE;
+ btif_rc_upstreams_evt(event, &cmd, 0, pbrowse_msg->label);
+ dropmsg = FALSE;
+ }
+ break;
+
+ case AVRC_PDU_CHANGE_PATH:
+ event = pbrowse_msg->p_msg->browse.p_browse_data[0] ;
+ cmd.chg_path.pdu = event;
+ p_data = &pbrowse_msg->p_msg->browse.p_browse_data[1];
+ BE_STREAM_TO_UINT16(length, p_data);
+ if (length != 11)
+ {
+ BTIF_TRACE_ERROR("CHANGE_PATH length error: = %d",length);
+ }
+ else
+ {
+ p_data = &pbrowse_msg->p_msg->browse.p_browse_data[3];
+ BE_STREAM_TO_UINT16(cmd.chg_path.uid_counter, p_data);
+ cmd.chg_path.direction = pbrowse_msg->p_msg->browse.p_browse_data[5];
+ cmd.chg_path.opcode = AVRC_OP_BROWSE;
+ cmd.chg_path.status = AVRC_STS_NO_ERROR;
+ p_data = &pbrowse_msg->p_msg->browse.p_browse_data[6];
+ BE_STREAM_TO_UINT64(cmd.chg_path.folder_uid, p_data);
+ btif_rc_upstreams_evt(event, &cmd, 0, pbrowse_msg->label);
+ dropmsg = FALSE;
+ }
+ break;
+
+ case AVRC_PDU_GET_ITEM_ATTRIBUTES:
+ {
+ UINT16 packet_len;
+ UINT8 num_attr, index;
+ event = pbrowse_msg->p_msg->browse.p_browse_data[0] ;
+ cmd.get_attrs.pdu = event;
+ p_data = &pbrowse_msg->p_msg->browse.p_browse_data[1];
+ BE_STREAM_TO_UINT16(packet_len, p_data);
+ p_data = &pbrowse_msg->p_msg->browse.p_browse_data[14];
+ BE_STREAM_TO_UINT8(num_attr, p_data);
+ if (packet_len != ((num_attr * 4) + 12))
+ {
+ BTIF_TRACE_ERROR("Get Item Attributes length error: = %d",packet_len);
+ }
+ else
+ {
+ cmd.get_attrs.status = AVRC_STS_NO_ERROR;
+ cmd.get_attrs.opcode = AVRC_OP_BROWSE;
+ cmd.get_attrs.scope = pbrowse_msg->p_msg->browse.p_browse_data[3];
+ p_data = &pbrowse_msg->p_msg->browse.p_browse_data[4];
+ BE_STREAM_TO_UINT64(cmd.get_attrs.uid, p_data);
+ p_data = &pbrowse_msg->p_msg->browse.p_browse_data[12];
+ BE_STREAM_TO_UINT16(cmd.get_attrs.uid_counter, p_data);
+ cmd.get_attrs.attr_count = num_attr;
+ if (num_attr == 0)
+ {
+ /* remote requested all Attribute ID*/
+ for (index = 0; index < BTRC_MAX_ELEM_ATTR_SIZE; index++)
+ {
+ cmd.get_attrs.attrs[index] = index + 1;
+ }
+ }
+ else
+ {
+ p_data = &pbrowse_msg->p_msg->browse.p_browse_data[15];
+ BTIF_TRACE_ERROR("GetItemAttr num_attr: = %d", cmd.get_attrs.attr_count);
+ for (index = 0; index < num_attr ; index++)
+ {
+ BE_STREAM_TO_UINT32(cmd.get_attrs.attrs[index], p_data);
+ BTIF_TRACE_ERROR("GetItemAttr attrid: = %d", cmd.get_attrs.attrs[index]);
+ }
+ }
+ btif_rc_upstreams_evt(event, &cmd, 0, pbrowse_msg->label);
+ dropmsg = FALSE;
+ }
+ }
+ break;
+
+ default:
+ BTIF_TRACE_ERROR("pbrowse_msg ERROR");
+ break;
+ }
+ if (dropmsg == TRUE)
+ {
+ avrc_rsp.rsp.pdu = pbrowse_msg->p_msg->browse.p_browse_data[0];
+ avrc_rsp.rsp.status = AVRC_STS_BAD_CMD;
+ avrc_rsp.rsp.opcode = AVRC_OP_BROWSE;
+ BTIF_TRACE_ERROR("handle_rc_browsemsg_cmd: pbrowse_msg ERROR: %x", avrc_rsp.rsp.pdu);
+ send_browsemsg_rsp(btif_rc_cb.rc_handle, pbrowse_msg->label, 0, &avrc_rsp);
+ }
+
+}
+
+
/***************************************************************************
**
** Function btif_rc_handler
@@ -886,6 +1188,13 @@ void btif_rc_handler(tBTA_AV_EVT event, tBTA_AV *p_data)
}
}
break;
+ case BTA_AV_BROWSE_MSG_EVT:
+ {
+ BTIF_TRACE_DEBUG("BTA_AV_BROWSE_MSG_EVT label:%d handle:%d", p_data->browse_msg.label,
+ p_data->browse_msg.rc_handle);
+ handle_rc_browsemsg_cmd(&(p_data->browse_msg));
+ }
+ break;
default:
BTIF_TRACE_DEBUG("Unhandled RC event : 0x%x", event);
}
@@ -1116,6 +1425,68 @@ static UINT8 opcode_from_pdu(UINT8 pdu)
return opcode;
}
+/****************************************************************************
+* Function send_browsemsg_rsp
+*
+* Arguments - rc_handle RC handle corresponding to the connected RC
+* label Label of the RC response
+* code Response type---->Not needed for Browsing
+* pmetamsg_resp Vendor response
+*
+* Description - Remote control browse Message Rsp
+*
+*******************************************************************************/
+static void send_browsemsg_rsp (UINT8 rc_handle, UINT8 label, tBTA_AV_CODE code,
+ tAVRC_RESPONSE *pbrowsemsg_resp)
+{
+ tAVRC_STS status;
+ BT_HDR *p_msg = NULL;
+
+ if (!pbrowsemsg_resp)
+ {
+ BTIF_TRACE_WARNING("%s: Invalid response received from application", __FUNCTION__);
+ return;
+ }
+
+ BTIF_TRACE_EVENT("+%s:rc_handle: %d, label: %d, code: 0x%02x, pdu: %s", __FUNCTION__,\
+ rc_handle, label, code, dump_rc_pdu(pbrowsemsg_resp->rsp.pdu));
+ if (pbrowsemsg_resp->rsp.status != AVRC_STS_NO_ERROR)
+ {
+ BTIF_TRACE_ERROR("send_browsemsg_rsp **Error**");
+ }
+ /*Browse Command and Response structure are different
+ *as comapared to Meta data response ,opcode and c-type
+ *not part of browse response hence handling browse response
+ *in seprate function
+ */
+ status = AVRC_BldBrowseResponse(rc_handle, pbrowsemsg_resp, &p_msg);
+ if (status == AVRC_STS_NO_ERROR)
+ {
+ BTA_AvMetaRsp(rc_handle, label, 0, p_msg);
+ }
+ else
+ {
+ BTIF_TRACE_ERROR("%s: failed to build metamsg response. status: 0x%02x",
+ __FUNCTION__, status);
+ }
+}
+
+/****************************************************************************
+* Function app_sendbrowsemsg
+*
+* Arguments - index Of array stored while recieving command
+* avrc_rsp Avrcp response from application
+*
+* Description - Send Browse message
+*
+*******************************************************************************/
+int app_sendbrowsemsg(UINT8 index ,tAVRC_RESPONSE *avrc_rsp)
+{
+ SEND_BROWSEMSG_RSP(index ,avrc_rsp);
+ return 0;
+}
+
+
/*******************************************************************************
**
** Function btif_rc_upstreams_evt
@@ -1134,19 +1505,117 @@ static void btif_rc_upstreams_evt(UINT16 event, tAVRC_COMMAND *pavrc_cmd, UINT8
{
case AVRC_PDU_GET_PLAY_STATUS:
{
+ BTIF_TRACE_DEBUG("AVRC_PDU_GET_PLAY_STATUS ");
FILL_PDU_QUEUE(IDX_GET_PLAY_STATUS_RSP, ctype, label, TRUE)
HAL_CBACK(bt_rc_callbacks, get_play_status_cb);
}
break;
case AVRC_PDU_LIST_PLAYER_APP_ATTR:
+ {
+ BTIF_TRACE_DEBUG("AVRC_PDU_LIST_PLAYER_APP_ATTR ");
+ FILL_PDU_QUEUE(IDX_LIST_APP_ATTR_RSP, ctype, label, TRUE)
+ HAL_CBACK(bt_rc_callbacks, list_player_app_attr_cb);
+ }
+ break;
case AVRC_PDU_LIST_PLAYER_APP_VALUES:
+ {
+ BTIF_TRACE_DEBUG("AVRC_PDU_LIST_PLAYER_APP_VALUES =%d" ,pavrc_cmd->list_app_values.attr_id);
+ if (pavrc_cmd->list_app_values.attr_id == 0)
+ {
+ send_reject_response (btif_rc_cb.rc_handle, label, pavrc_cmd->pdu, AVRC_STS_BAD_PARAM);
+ break;
+ }
+ FILL_PDU_QUEUE(IDX_LIST_APP_VALUE_RSP, ctype, label, TRUE)
+ HAL_CBACK(bt_rc_callbacks, list_player_app_values_cb ,pavrc_cmd->list_app_values.attr_id);
+ }
+ break;
case AVRC_PDU_GET_CUR_PLAYER_APP_VALUE:
+ {
+ btrc_player_attr_t player_attr[BTRC_MAX_ELEM_ATTR_SIZE];
+ UINT8 player_attr_num;
+ BTIF_TRACE_DEBUG("PLAYER_APP_VALUE PDU 0x13 = %d",pavrc_cmd->get_cur_app_val.num_attr);
+ if ((pavrc_cmd->get_cur_app_val.num_attr == 0) ||
+ (pavrc_cmd->get_cur_app_val.num_attr > BTRC_MAX_ELEM_ATTR_SIZE))
+ {
+ send_reject_response (btif_rc_cb.rc_handle, label, pavrc_cmd->pdu, AVRC_STS_BAD_PARAM);
+ break;
+ }
+ memset( player_attr, 0, sizeof(player_attr));
+ for (player_attr_num = 0 ; player_attr_num < pavrc_cmd->get_cur_app_val.num_attr;
+ ++player_attr_num)
+ {
+ player_attr[player_attr_num] = pavrc_cmd->get_cur_app_val.attrs[player_attr_num];
+ }
+ FILL_PDU_QUEUE(IDX_GET_CURR_APP_VAL_RSP, ctype, label, TRUE)
+ HAL_CBACK(bt_rc_callbacks, get_player_app_value_cb ,
+ pavrc_cmd->get_cur_app_val.num_attr, player_attr );
+ }
+ break;
case AVRC_PDU_SET_PLAYER_APP_VALUE:
+ {
+ btrc_player_settings_t attr;
+ UINT8 count;
+ tAVRC_RESPONSE avrc_rsp;
+ if ((pavrc_cmd->set_app_val.num_val== 0) ||
+ (pavrc_cmd->set_app_val.num_val > BTRC_MAX_ELEM_ATTR_SIZE))
+ {
+ send_reject_response (btif_rc_cb.rc_handle, label,
+ pavrc_cmd->pdu, AVRC_STS_BAD_PARAM);
+ break;
+ }
+ else
+ {
+ for(count = 0; count < pavrc_cmd->set_app_val.num_val ; ++count)
+ {
+ attr.attr_ids[count] = pavrc_cmd->set_app_val.p_vals[count].attr_id ;
+ attr.attr_values[count]= pavrc_cmd->set_app_val.p_vals[count].attr_val;
+ }
+ attr.num_attr = pavrc_cmd->set_app_val.num_val ;
+ FILL_PDU_QUEUE(IDX_SET_APP_VAL_RSP, ctype, label, TRUE)
+ HAL_CBACK(bt_rc_callbacks, set_player_app_value_cb, &attr );
+ }
+ }
+ break;
case AVRC_PDU_GET_PLAYER_APP_ATTR_TEXT:
+ {
+ btrc_player_attr_t player_attr_txt [BTRC_MAX_ELEM_ATTR_SIZE];
+ UINT8 count_txt = 0 ;
+ if ((pavrc_cmd->get_app_attr_txt.num_attr == 0) ||
+ (pavrc_cmd->get_app_attr_txt.num_attr > BTRC_MAX_ELEM_ATTR_SIZE))
+ {
+ send_reject_response (btif_rc_cb.rc_handle, label, pavrc_cmd->pdu, AVRC_STS_BAD_PARAM);
+ }
+ else
+ {
+ for (count_txt = 0;count_txt < pavrc_cmd->get_app_attr_txt.num_attr ; ++count_txt)
+ {
+ player_attr_txt[count_txt] = pavrc_cmd->get_app_attr_txt.attrs[count_txt];
+ }
+ FILL_PDU_QUEUE(IDX_GET_APP_ATTR_TXT_RSP, ctype, label, TRUE)
+ HAL_CBACK(bt_rc_callbacks, get_player_app_attrs_text_cb,
+ pavrc_cmd->get_app_attr_txt.num_attr, player_attr_txt );
+ }
+ }
+ break;
case AVRC_PDU_GET_PLAYER_APP_VALUE_TEXT:
{
- /* TODO: Add support for Application Settings */
- send_reject_response (btif_rc_cb.rc_handle, label, pavrc_cmd->pdu, AVRC_STS_BAD_CMD);
+ if (pavrc_cmd->get_app_val_txt.attr_id == 0 ||
+ pavrc_cmd->get_app_val_txt.attr_id > AVRC_PLAYER_VAL_GROUP_REPEAT)
+ {
+ send_reject_response (btif_rc_cb.rc_handle, label, pavrc_cmd->pdu, AVRC_STS_BAD_PARAM);
+ break;
+ }
+ if (pavrc_cmd->get_app_val_txt.num_val == 0)
+ {
+ send_reject_response (btif_rc_cb.rc_handle, label, pavrc_cmd->pdu, AVRC_STS_BAD_PARAM);
+ }
+ else
+ {
+ FILL_PDU_QUEUE(IDX_GET_APP_VAL_TXT_RSP, ctype, label, TRUE)
+ HAL_CBACK(bt_rc_callbacks, get_player_app_values_text_cb,
+ pavrc_cmd->get_app_val_txt.attr_id, pavrc_cmd->get_app_val_txt.num_val,
+ pavrc_cmd->get_app_val_txt.vals);
+ }
}
break;
case AVRC_PDU_GET_ELEMENT_ATTR:
@@ -1207,7 +1676,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.",
@@ -1235,11 +1704,158 @@ static void btif_rc_upstreams_evt(UINT16 event, tAVRC_COMMAND *pavrc_cmd, UINT8
}
}
break;
+ case AVRC_PDU_SET_ADDRESSED_PLAYER:
+ {
+ btrc_status_t status_code = AVRC_STS_NO_ERROR;
+ BTIF_TRACE_EVENT("%s() AVRC_PDU_SET_ADDRESSED_PLAYER", __FUNCTION__);
+ if (!btif_hf_is_call_idle())
+ {
+ set_addrplayer_rsp(ERR_PLAYER_NOT_ADDRESED); // send reject if call is in progress
+ return;
+ }
+ if (btif_rc_cb.rc_connected == TRUE)
+ {
+ FILL_PDU_QUEUE(IDX_SET_ADDRESS_PLAYER_RSP, ctype, label, TRUE);
+ HAL_CBACK(bt_rc_callbacks, set_addrplayer_cb, pavrc_cmd->addr_player.player_id);
+ }
+ }
+ break;
+ case AVRC_PDU_GET_FOLDER_ITEMS:
+ {
+ tAVRC_RESPONSE avrc_rsp;
+ btrc_getfolderitem_t getfolder;
+ btrc_browse_folderitem_t scope;
+ UINT8 player[] = "MusicPlayer1";
+ tAVRC_ITEM tem[1];
+ UINT8 index, numAttr;
+ BTIF_TRACE_EVENT("%s()AVRC_PDU_GET_FOLDER_ITEMS", __FUNCTION__);
+ FILL_PDU_QUEUE(IDX_GET_FOLDER_ITEMS_RSP,ctype, label, TRUE);
+ BTIF_TRACE_EVENT("rc_connected: %d",btif_rc_cb.rc_connected);
+ if (btif_rc_cb.rc_connected == TRUE)
+ {
+ getfolder.start_item = pavrc_cmd->get_items.start_item;
+ getfolder.end_item = pavrc_cmd->get_items.end_item;
+ getfolder.size = AVCT_GetBrowseMtu(btif_rc_cb.rc_handle);
+ getfolder.attr_count = pavrc_cmd->get_items.attr_count;
+ scope = (btrc_browse_folderitem_t)pavrc_cmd->get_items.scope;
+ if (getfolder.attr_count == 255)
+ {
+ numAttr = 0;
+ }
+ else
+ {
+ if (getfolder.attr_count == 0)
+ {
+ numAttr = 7;
+ for (index = 0; index < BTRC_MAX_ELEM_ATTR_SIZE; index++)
+ {
+ getfolder.attrs[index] = index + 1;
+ }
+ }
+ else
+ {
+ numAttr = getfolder.attr_count;
+ for (index = 0; index < numAttr; index++)
+ {
+ getfolder.attrs[index] = pavrc_cmd->get_items.attrs[index];
+ BTIF_TRACE_ERROR("getfolder[%d] = %d", index, getfolder.\
+ attrs[index]);
+ BTIF_TRACE_ERROR("pavrc_cmd->get_items.attrs[%d] = %d",\
+ index, pavrc_cmd->get_items.attrs[index]);
+ }
+ }
+ }
+ HAL_CBACK(bt_rc_callbacks, get_folderitems_cb, scope, &getfolder);
+ }
+ }
+ break;
+ case AVRC_PDU_SET_BROWSED_PLAYER:
+ {
+ BTIF_TRACE_EVENT("%s() AVRC_PDU_SET_BROWSED_PLAYER", __FUNCTION__);
+ if (btif_rc_cb.rc_connected == TRUE)
+ {
+ FILL_PDU_QUEUE(IDX_SET_BROWSE_PLAYER_RSP, ctype, label, TRUE);
+ HAL_CBACK(bt_rc_callbacks, set_browsed_player_cb, pavrc_cmd->br_player.player_id);
+ }
+ }
+ break;
+ case AVRC_PDU_CHANGE_PATH:
+ {
+ BTIF_TRACE_EVENT("%s() AVRC_PDU_CHANGE_PATH", __FUNCTION__);
+ if (btif_rc_cb.rc_connected == TRUE)
+ {
+ FILL_PDU_QUEUE(IDX_CHANGE_PATH_RSP, ctype, label, TRUE);
+ HAL_CBACK(bt_rc_callbacks, change_path_cb, pavrc_cmd->chg_path.direction, \
+ pavrc_cmd->chg_path.folder_uid);
+ }
+ }
+ break;
+ case AVRC_PDU_GET_ITEM_ATTRIBUTES:
+ {
+ UINT8 num_attr = pavrc_cmd->get_attrs.attr_count;
+ UINT8 index, num_attr_requested = 0;
+ BTIF_TRACE_EVENT("%s() AVRC_PDU_GET_ITEM_ATTRIBUTES", __FUNCTION__);
+ btrc_media_attr_t element_attrs[BTRC_MAX_ELEM_ATTR_SIZE];
+ memset(&element_attrs, 0, sizeof(element_attrs));
+ if (num_attr == 0)
+ {
+ /* CT requests for all attributes */
+ for (index = 0; index < BTRC_MAX_ELEM_ATTR_SIZE; index++)
+ {
+ element_attrs[index] = index + 1;
+ }
+ num_attr_requested = 7; /* get all seven */
+ }
+ else if (num_attr == 0xFF)
+ {
+ /* 0xff indicates, no attributes requested - reject */
+ send_reject_response (btif_rc_cb.rc_handle, label, pavrc_cmd->pdu,
+ AVRC_STS_BAD_PARAM);
+ return;
+ }
+ else
+ {
+ /* Attribute IDs from 1 to BTRC_MAX_ELEM_ATTR_SIZE are only valid,
+ * hence HAL definition limits the attributes to BTRC_MAX_ELEM_ATTR_SIZE.
+ * Fill only valid entries.
+ */
+ for (index = 0; (index < num_attr) && (num_attr <= BTRC_MAX_ELEM_ATTR_SIZE); index++)
+ {
+ if ((pavrc_cmd->get_attrs.attrs[index] > 0) &&
+ (pavrc_cmd->get_attrs.attrs[index] <= BTRC_MAX_ELEM_ATTR_SIZE))
+ {
+ element_attrs[index] = pavrc_cmd->get_attrs.attrs[index];
+ BTIF_TRACE_ERROR("element_attrs[%d]: %d", index, element_attrs[index]);
+ }
+ }
+ num_attr_requested = index;
+ BTIF_TRACE_ERROR("num_attr_requested: %d", num_attr_requested);
+ }
+
+ if (btif_rc_cb.rc_connected == TRUE)
+ {
+ FILL_PDU_QUEUE(IDX_GET_ITEM_ATTR_RSP, ctype, label, TRUE);
+ HAL_CBACK(bt_rc_callbacks, get_item_attr_cb, pavrc_cmd->get_attrs.scope,
+ pavrc_cmd->get_attrs.uid, num_attr_requested, element_attrs);
+ }
+ }
+ break;
+ case AVRC_PDU_PLAY_ITEM:
+ {
+ BTIF_TRACE_EVENT("%s() AVRC_PDU_PLAY_ITEM", __FUNCTION__);
+ if (btif_rc_cb.rc_connected == TRUE)
+ {
+ FILL_PDU_QUEUE(IDX_PLAY_ITEM_RSP, ctype, label, TRUE);
+ HAL_CBACK(bt_rc_callbacks, play_item_cb, pavrc_cmd->play_item.scope,
+ pavrc_cmd->play_item.uid);
+ }
+ }
+ break;
default:
{
- send_reject_response (btif_rc_cb.rc_handle, label, pavrc_cmd->pdu,
- (pavrc_cmd->pdu == AVRC_PDU_SEARCH)?AVRC_STS_SEARCH_NOT_SUP:AVRC_STS_BAD_CMD);
- return;
+ send_reject_response(btif_rc_cb.rc_handle, label, pavrc_cmd->pdu,
+ (pavrc_cmd->pdu == AVRC_PDU_SEARCH)? AVRC_STS_SEARCH_NOT_SUP:
+ AVRC_STS_BAD_CMD);
}
break;
}
@@ -1373,12 +1989,239 @@ static bt_status_t get_play_status_rsp(btrc_play_status_t play_status, uint32_t
return BT_STATUS_SUCCESS;
}
+
+/**************************************************************************
+**
+** Function list_player_app_attr_rsp
+**
+** Description ListPlayerApplicationSettingAttributes (PDU ID: 0x11)
+** This method is callled in response to PDU 0x11
+**
+** Returns bt_status_t
+**
+****************************************************************************/
+static bt_status_t list_player_app_attr_rsp( uint8_t num_attr, btrc_player_attr_t *p_attrs)
+{
+ tAVRC_RESPONSE avrc_rsp;
+ UINT32 i;
+
+ CHECK_RC_CONNECTED
+ memset(&(avrc_rsp.list_app_attr), 0, sizeof(tAVRC_LIST_APP_ATTR_RSP));
+ if (num_attr == 0)
+ {
+ avrc_rsp.list_app_attr.status = AVRC_STS_BAD_PARAM;
+ }
+ else
+ {
+ avrc_rsp.list_app_attr.num_attr = num_attr;
+ for (i = 0 ; i < num_attr ; ++i)
+ {
+ avrc_rsp.list_app_attr.attrs[i] = p_attrs[i];
+ }
+ avrc_rsp.list_app_attr.status = AVRC_STS_NO_ERROR;
+ }
+ avrc_rsp.list_app_attr.pdu = AVRC_PDU_LIST_PLAYER_APP_ATTR ;
+ avrc_rsp.list_app_attr.opcode = opcode_from_pdu(AVRC_PDU_LIST_PLAYER_APP_ATTR);
+ /* Send the response */
+ SEND_METAMSG_RSP(IDX_LIST_APP_ATTR_RSP, &avrc_rsp);
+ return BT_STATUS_SUCCESS;
+}
+
+/**********************************************************************
+**
+** Function list_player_app_value_rsp
+**
+** Description ListPlayerApplicationSettingValues (PDU ID: 0x12)
+ This method is called in response to PDU 0x12
+************************************************************************/
+static bt_status_t list_player_app_value_rsp( uint8_t num_val, uint8_t *value)
+{
+ tAVRC_RESPONSE avrc_rsp;
+ UINT32 i;
+
+ CHECK_RC_CONNECTED
+ memset(&(avrc_rsp.list_app_values), 0, sizeof(tAVRC_LIST_APP_VALUES_RSP));
+ if ((num_val == 0) || (num_val > AVRC_MAX_APP_ATTR_SIZE))
+ {
+ avrc_rsp.list_app_values.status = AVRC_STS_BAD_PARAM;
+ }
+ else
+ {
+ avrc_rsp.list_app_values.num_val = num_val;
+ for (i = 0; i < num_val; ++i)
+ {
+ avrc_rsp.list_app_values.vals[i] = value[i];
+ }
+ avrc_rsp.list_app_values.status = AVRC_STS_NO_ERROR;
+ }
+ avrc_rsp.list_app_values.pdu = AVRC_PDU_LIST_PLAYER_APP_VALUES;
+ avrc_rsp.list_app_attr.opcode = opcode_from_pdu(AVRC_PDU_LIST_PLAYER_APP_VALUES);
+ /* Send the response */
+ SEND_METAMSG_RSP(IDX_LIST_APP_VALUE_RSP, &avrc_rsp);
+ return BT_STATUS_SUCCESS;
+}
+
+
+/**********************************************************************
+**
+** Function get_player_app_value_rsp
+**
+** Description This methos is called in response to PDU ID 0x13
+**
+***********************************************************************/
+static bt_status_t get_player_app_value_rsp(btrc_player_settings_t *p_vals)
+{
+ tAVRC_RESPONSE avrc_rsp;
+ UINT32 i;
+ tAVRC_APP_SETTING app_sett[AVRC_MAX_APP_ATTR_SIZE];
+
+ CHECK_RC_CONNECTED
+ memset(&(avrc_rsp.get_cur_app_val) ,0 , sizeof(tAVRC_GET_CUR_APP_VALUE_RSP));
+ avrc_rsp.get_cur_app_val.p_vals = app_sett ;
+ //Check for Error Condition
+ if ((p_vals == NULL) || (p_vals->num_attr== 0) || (p_vals->num_attr > AVRC_MAX_APP_ATTR_SIZE))
+ {
+ avrc_rsp.get_cur_app_val.status = AVRC_STS_BAD_PARAM;
+ }
+ else
+ {
+ memset(app_sett, 0, sizeof(tAVRC_APP_SETTING)*p_vals->num_attr );
+ //update num_val
+ avrc_rsp.get_cur_app_val.num_val = p_vals->num_attr ;
+ avrc_rsp.get_cur_app_val.p_vals = app_sett ;
+ for (i = 0; i < p_vals->num_attr; ++i)
+ {
+ app_sett[i].attr_id = p_vals->attr_ids[i] ;
+ app_sett[i].attr_val = p_vals->attr_values[i];
+ BTIF_TRACE_DEBUG("%s attr_id:0x%x, charset_id:0x%x, num_element:%d",
+ __FUNCTION__, (unsigned int)app_sett[i].attr_id,
+ app_sett[i].attr_val ,p_vals->num_attr );
+ }
+ //Update PDU , status aind
+ avrc_rsp.get_cur_app_val.status = AVRC_STS_NO_ERROR;
+ }
+ avrc_rsp.get_cur_app_val.pdu = AVRC_PDU_GET_CUR_PLAYER_APP_VALUE;
+ avrc_rsp.get_cur_app_val.opcode = opcode_from_pdu(AVRC_PDU_GET_CUR_PLAYER_APP_VALUE);
+ SEND_METAMSG_RSP(IDX_GET_CURR_APP_VAL_RSP, &avrc_rsp);
+ return BT_STATUS_SUCCESS;
+}
+
+/********************************************************************
+**
+** Function set_player_app_value_rsp
+**
+** Description This method is called in response to
+** application value
+**
+** Return bt_staus_t
+**
+*******************************************************************/
+static bt_status_t set_player_app_value_rsp (btrc_status_t rsp_status )
+{
+ tAVRC_RESPONSE avrc_rsp;
+ tAVRC_RSP set_app_val;
+
+ CHECK_RC_CONNECTED
+ avrc_rsp.set_app_val.opcode = opcode_from_pdu(AVRC_PDU_SET_PLAYER_APP_VALUE);
+ avrc_rsp.set_app_val.pdu = AVRC_PDU_SET_PLAYER_APP_VALUE ;
+ avrc_rsp.set_app_val.status = rsp_status ;
+ SEND_METAMSG_RSP(IDX_SET_APP_VAL_RSP, &avrc_rsp);
+ return BT_STATUS_SUCCESS;
+}
+
+/********************************************************************
+**
+** Function get_player_app_attr_text_rsp
+**
+** Description This method is called in response to get player
+** applicaton attribute text response
+**
+**
+*******************************************************************/
+static bt_status_t get_player_app_attr_text_rsp(int num_attr, btrc_player_setting_text_t *p_attrs)
+{
+ tAVRC_RESPONSE avrc_rsp;
+ tAVRC_APP_SETTING_TEXT attr_txt[AVRC_MAX_APP_ATTR_SIZE];
+ int i;
+
+ CHECK_RC_CONNECTED
+ if (num_attr == 0)
+ {
+ avrc_rsp.get_app_attr_txt.status = AVRC_STS_BAD_PARAM;
+ }
+ else
+ {
+ for (i =0; i< num_attr; ++i)
+ {
+ attr_txt[i].charset_id = AVRC_CHARSET_ID_UTF8;
+ attr_txt[i].attr_id = p_attrs[i].id ;
+ attr_txt[i].str_len = (UINT8)strnlen((char *)p_attrs[i].text, BTRC_MAX_ATTR_STR_LEN);
+ attr_txt[i].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)attr_txt[i].attr_id,
+ attr_txt[i].charset_id , attr_txt[i].str_len, attr_txt[i].p_str);
+ }
+ avrc_rsp.get_app_attr_txt.status = AVRC_STS_NO_ERROR;
+ }
+ avrc_rsp.get_app_attr_txt.p_attrs = attr_txt ;
+ avrc_rsp.get_app_attr_txt.num_attr = (UINT8)num_attr;
+ avrc_rsp.get_app_attr_txt.pdu = AVRC_PDU_GET_PLAYER_APP_ATTR_TEXT;
+ avrc_rsp.get_app_attr_txt.opcode = opcode_from_pdu(AVRC_PDU_GET_PLAYER_APP_ATTR_TEXT);
+ /* Send the response */
+ SEND_METAMSG_RSP(IDX_GET_APP_ATTR_TXT_RSP, &avrc_rsp);
+ return BT_STATUS_SUCCESS;
+}
+
+/********************************************************************
+**
+** Function get_player_app_value_text_rsp
+**
+** Description This method is called in response to Player application
+** value text
+**
+** Return bt_status_t
+**
+*******************************************************************/
+static bt_status_t get_player_app_value_text_rsp(int num_attr, btrc_player_setting_text_t *p_attrs)
+{
+ tAVRC_RESPONSE avrc_rsp;
+ tAVRC_APP_SETTING_TEXT attr_txt[AVRC_MAX_APP_ATTR_SIZE];
+ int i;
+
+ CHECK_RC_CONNECTED
+ if (num_attr == 0)
+ {
+ avrc_rsp.get_app_val_txt.status = AVRC_STS_BAD_PARAM;
+ }
+ else
+ {
+ for (i =0; i< num_attr; ++i)
+ {
+ attr_txt[i].charset_id = AVRC_CHARSET_ID_UTF8;
+ attr_txt[i].attr_id = p_attrs[i].id ;
+ attr_txt[i].str_len = (UINT8)strnlen((char *)p_attrs[i].text ,BTRC_MAX_ATTR_STR_LEN );
+ attr_txt[i].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)attr_txt[i].attr_id,
+ attr_txt[i].charset_id , attr_txt[i].str_len,attr_txt[i].p_str);
+ }
+ avrc_rsp.get_app_val_txt.status = AVRC_STS_NO_ERROR;
+ }
+ avrc_rsp.get_app_val_txt.p_attrs = attr_txt;
+ avrc_rsp.get_app_val_txt.num_attr = (UINT8)num_attr;
+ avrc_rsp.get_app_val_txt.pdu = AVRC_PDU_GET_PLAYER_APP_VALUE_TEXT;
+ avrc_rsp.get_app_val_txt.opcode = opcode_from_pdu(AVRC_PDU_GET_PLAYER_APP_VALUE_TEXT);
+ /* Send the response */
+ SEND_METAMSG_RSP(IDX_GET_APP_VAL_TXT_RSP, &avrc_rsp);
+ return BT_STATUS_SUCCESS;
+}
+
/***************************************************************************
**
** Function get_element_attr_rsp
**
** Description Returns the current songs' element attributes
-** in text.
+** in text.
**
** Returns bt_status_t
**
@@ -1397,7 +2240,8 @@ static bt_status_t get_element_attr_rsp(uint8_t num_attr, btrc_element_attr_val_
}
else
{
- for (i=0; i<num_attr; i++) {
+ for (i=0; i<num_attr; i++)
+ {
element_attrs[i].attr_id = p_attrs[i].attr_id;
element_attrs[i].name.charset_id = AVRC_CHARSET_ID_UTF8;
element_attrs[i].name.str_len = (UINT16)strlen((char *)p_attrs[i].text);
@@ -1455,6 +2299,23 @@ static bt_status_t register_notification_rsp(btrc_event_id_t event_id,
case BTRC_EVT_PLAY_POS_CHANGED:
avrc_rsp.reg_notif.param.play_pos = p_param->song_pos;
break;
+ case BTRC_EVT_APP_SETTINGS_CHANGED:
+ avrc_rsp.reg_notif.param.player_setting.num_attr = p_param->player_setting.num_attr;
+ memcpy(&avrc_rsp.reg_notif.param.player_setting.attr_id,
+ p_param->player_setting.attr_ids, 2);
+ memcpy(&avrc_rsp.reg_notif.param.player_setting.attr_value,
+ p_param->player_setting.attr_values, 2);
+ break;
+ case BTRC_EVT_ADDRESSED_PLAYER_CHANGED:
+ avrc_rsp.reg_notif.param.addr_player.player_id = p_param->player_id;
+ avrc_rsp.reg_notif.param.addr_player.uid_counter = 0;
+ break;
+ case BTRC_EVT_AVAILABLE_PLAYERS_CHANGED:
+ avrc_rsp.reg_notif.param.evt = 0x0a;
+ break;
+ case BTRC_EVT_NOW_PLAYING_CONTENT_CHANGED:
+ avrc_rsp.reg_notif.param.evt = 0x09;
+ break;
default:
BTIF_TRACE_WARNING("%s : Unhandled event ID : 0x%x", __FUNCTION__, event_id);
return BT_STATUS_UNHANDLED;
@@ -1462,7 +2323,21 @@ static bt_status_t register_notification_rsp(btrc_event_id_t event_id,
avrc_rsp.reg_notif.pdu = AVRC_PDU_REGISTER_NOTIFICATION;
avrc_rsp.reg_notif.opcode = opcode_from_pdu(AVRC_PDU_REGISTER_NOTIFICATION);
- avrc_rsp.get_play_status.status = AVRC_STS_NO_ERROR;
+ if (type == BTRC_NOTIFICATION_TYPE_REJECT)
+ {
+ /* Spec AVRCP 1.5 ,section 6.9.2.2, on completion
+ * of the addressed player changed notificatons the TG shall
+ * complete all player specific notification with AV/C C-type
+ * Rejected with error code Addressed Player changed.
+ * This will happen in case when music player has changed
+ * Application should take care of sending reject response.
+ */
+ avrc_rsp.get_play_status.status = AVRC_STS_ADDR_PLAYER_CHG;
+ }
+ else
+ {
+ avrc_rsp.get_play_status.status = AVRC_STS_NO_ERROR;
+ }
/* Send the response. */
send_metamsg_rsp(btif_rc_cb.rc_handle, btif_rc_cb.rc_notif[event_id-1].label,
@@ -1470,6 +2345,288 @@ static bt_status_t register_notification_rsp(btrc_event_id_t event_id,
return BT_STATUS_SUCCESS;
}
+
+/***************************************************************************
+**
+** Function get_folderitem_rsp
+**
+** Description Response to Get Folder Items , PDU 0x71
+**
+** Returns bt_status_t
+**
+***************************************************************************/
+static bt_status_t get_folderitem_rsp(btrc_folder_list_entries_t *rsp)
+{
+ tAVRC_RESPONSE avrc_rsp;
+ CHECK_RC_CONNECTED
+ tAVRC_ITEM item[MAX_FOLDER_RSP_SUPPORT]; //Number of players that could be supported
+ UINT8 index, i, xx, media_attr_cnt;
+ UINT8 *p_conversion;
+
+ BTIF_TRACE_EVENT("%s() AVRC_PDU_GET_FOLDER_ITEMS", __FUNCTION__);
+ index = IDX_GET_FOLDER_ITEMS_RSP ;
+ avrc_rsp.get_items.pdu = AVRC_PDU_GET_FOLDER_ITEMS;
+ avrc_rsp.get_items.opcode = AVRC_OP_BROWSE;
+ avrc_rsp.get_items.uid_counter = rsp->uid_counter;
+ avrc_rsp.get_items.status = rsp->status ;//4 means SUCCESS
+ avrc_rsp.get_items.item_count = 0;
+ BTIF_TRACE_EVENT("status =%d, item_count =%d",rsp->status, rsp->item_count);
+
+ for (i=0; (i < rsp->item_count && i < MAX_FOLDER_RSP_SUPPORT) ; ++i)
+ {
+ item[i].item_type = rsp->p_item_list[i].item_type;
+ BTIF_TRACE_EVENT("item_type = %d", rsp->p_item_list[i].item_type);
+ switch (item[i].item_type)
+ {
+ case AVRC_ITEM_PLAYER:
+ memcpy(item[i].u.player.features, rsp->p_item_list[i].u.player.features,
+ AVRC_FEATURE_MASK_SIZE);
+ item[i].u.player.major_type = rsp->p_item_list[i].u.player.major_type;
+ item[i].u.player.sub_type = rsp->p_item_list[i].u.player.sub_type;
+ item[i].u.player.play_status = rsp->p_item_list[i].u.player.play_status;
+ item[i].u.player.player_id = rsp->p_item_list[i].u.player.player_id;
+ item[i].u.player.name.charset_id = rsp->p_item_list[i].u.player.name.charset_id;
+ item[i].u.player.name.str_len = rsp->p_item_list[i].u.player.name.str_len;
+ item[i].u.player.name.p_str = rsp->p_item_list[i].u.player.name.p_str;
+ ++avrc_rsp.get_items.item_count;
+ break;
+
+ case AVRC_ITEM_FOLDER:
+ item[i].u.folder.type = rsp->p_item_list[i].u.folder.type;
+ item[i].u.folder.playable = rsp->p_item_list[i].u.folder.playable;
+ {
+ p_conversion = (UINT8*)&(rsp->p_item_list[i].u.folder.uid);
+ for (xx = 0; xx < AVRC_UID_SIZE; xx++)
+ {
+ ((UINT8 *) item[i].u.folder.uid)[AVRC_UID_SIZE - (xx + 1)] = \
+ *p_conversion++;
+ }
+ }
+
+ item[i].u.folder.name.charset_id = rsp->p_item_list[i].u.folder.name.charset_id;
+ item[i].u.folder.name.str_len = rsp->p_item_list[i].u.folder.name.str_len;
+ item[i].u.folder.name.p_str = rsp->p_item_list[i].u.folder.name.p_str;
+ ++avrc_rsp.get_items.item_count;
+ break;
+
+ case AVRC_ITEM_MEDIA:
+ item[i].u.media.type = rsp->p_item_list[i].u.media.type;
+ {
+ p_conversion = (UINT8*)&(rsp->p_item_list[i].u.media.uid);
+ //BE_STREAM_TO_ARRAY(p_conversion, item[i].u.folder.uid, AVRC_UID_SIZE);
+ for (xx = 0; xx < AVRC_UID_SIZE; xx++)
+ {
+ ((UINT8 *) item[i].u.folder.uid)[AVRC_UID_SIZE - (xx + 1)] = \
+ *p_conversion++;
+ }
+ }
+ item[i].u.media.name.charset_id = rsp->p_item_list[i].u.media.name.charset_id;
+ item[i].u.media.name.str_len = rsp->p_item_list[i].u.media.name.str_len;
+ item[i].u.media.name.p_str = rsp->p_item_list[i].u.media.name.p_str;
+ media_attr_cnt = rsp->p_item_list[i].u.media.attr_count;
+ item[i].u.media.attr_count = rsp->p_item_list[i].u.media.attr_count;
+ BTIF_TRACE_ERROR("attr count = %d", media_attr_cnt);
+ if (media_attr_cnt > 0)
+ {
+ if ((item[i].u.media.p_attr_list = \
+ (tAVRC_ATTR_ENTRY *)GKI_getbuf((UINT16)(media_attr_cnt * \
+ sizeof(tAVRC_ATTR_ENTRY)))) != NULL)
+ {
+ for (xx = 0; xx < media_attr_cnt; xx++)
+ {
+ item[i].u.media.p_attr_list[xx].attr_id = \
+ rsp->p_item_list[i].u.media.p_attr_list[xx].attr_id;
+ item[i].u.media.p_attr_list[xx].name.charset_id = \
+ rsp->p_item_list[i].u.media.p_attr_list[xx].name.charset_id;
+ item[i].u.media.p_attr_list[xx].name.str_len = \
+ rsp->p_item_list[i].u.media.p_attr_list[xx].name.str_len;
+ item[i].u.media.p_attr_list[xx].name.p_str = \
+ rsp->p_item_list[i].u.media.p_attr_list[xx].name.p_str;
+ BTIF_TRACE_ERROR("attr_id = %d", item[i].u.media.p_attr_list[xx].\
+ attr_id);
+ BTIF_TRACE_ERROR("str_len = %d", item[i].u.media.p_attr_list[xx].\
+ name.str_len);
+ }
+ }
+ else
+ {
+ BTIF_TRACE_ERROR("Not enough buffer allocated to accomodate attributes");
+ item[i].u.media.attr_count = 0;
+ }
+ }
+ ++avrc_rsp.get_items.item_count;
+ break;
+
+ default:
+ return BT_STATUS_UNHANDLED;
+ break;
+ }
+ }
+ if (avrc_rsp.get_items.item_count == 0) {
+ /*As per spec Send proper Error if no Music App is registered.*/
+ avrc_rsp.get_items.status = AVRC_STS_BAD_RANGE;
+ }
+ avrc_rsp.get_items.p_item_list = item;
+ app_sendbrowsemsg(IDX_GET_FOLDER_ITEMS_RSP ,&avrc_rsp);
+ BTIF_TRACE_ERROR("free attr list");
+ for (i=0; (i < rsp->item_count && i < MAX_FOLDER_RSP_SUPPORT) ; ++i)
+ {
+ if (item[i].item_type == AVRC_ITEM_MEDIA)
+ {
+ if (rsp->p_item_list[i].u.media.attr_count > 0)
+ {
+ GKI_freebuf(item[i].u.media.p_attr_list);
+ }
+ }
+ }
+ return BT_STATUS_SUCCESS;
+}
+
+/**********************************************************************
+**
+** Function set_addrplayer_rsp
+**
+** Description Response to Set Addressed Player , PDU 0x60
+**
+** Return status
+**
+*********************************************************************/
+
+static bt_status_t set_addrplayer_rsp(btrc_status_t status_code)
+{
+ tAVRC_RESPONSE avrc_rsp;
+ CHECK_RC_CONNECTED
+ avrc_rsp.addr_player.status = status_code;
+ avrc_rsp.addr_player.opcode = opcode_from_pdu(AVRC_PDU_SET_ADDRESSED_PLAYER);
+ avrc_rsp.addr_player.pdu = AVRC_PDU_SET_ADDRESSED_PLAYER;
+ /* Send the response */
+ SEND_METAMSG_RSP(IDX_SET_ADDRESS_PLAYER_RSP, &avrc_rsp);
+ return BT_STATUS_SUCCESS;
+}
+
+/**********************************************************************
+**
+** Function set_browseplayer_rsp
+**
+** Description Response to Set Browsed Player , PDU 0x70
+**
+** Return status
+**
+*********************************************************************/
+
+static bt_status_t set_browseplayer_rsp(btrc_set_browsed_player_rsp_t *p_param)
+{
+ tAVRC_RESPONSE avrc_rsp;
+
+ CHECK_RC_CONNECTED
+ avrc_rsp.br_player.pdu = AVRC_PDU_SET_BROWSED_PLAYER;
+ avrc_rsp.br_player.folder_depth = p_param->folder_depth;
+ avrc_rsp.br_player.charset_id = p_param->charset_id;
+ avrc_rsp.br_player.num_items = p_param->num_items;
+ avrc_rsp.br_player.opcode = opcode_from_pdu(AVRC_PDU_SET_BROWSED_PLAYER);
+ avrc_rsp.br_player.status = p_param->status;
+ avrc_rsp.br_player.uid_counter = p_param->uid_counter;
+ avrc_rsp.br_player.p_folders = (tAVRC_NAME*)p_param->p_folders;
+ /* Send the response */
+ SEND_BROWSEMSG_RSP(IDX_SET_BROWSE_PLAYER_RSP, &avrc_rsp);
+ return BT_STATUS_SUCCESS;
+}
+
+/**********************************************************************
+**
+** Function changepath_rsp
+**
+** Description Response to Change Path , PDU 0x60
+**
+** Return status
+**
+*********************************************************************/
+
+static bt_status_t changepath_rsp(uint8_t status_code, uint32_t item_count)
+{
+ tAVRC_RESPONSE avrc_rsp;
+
+ CHECK_RC_CONNECTED
+ avrc_rsp.chg_path.num_items = item_count;
+ avrc_rsp.chg_path.opcode = opcode_from_pdu(AVRC_PDU_CHANGE_PATH);
+ avrc_rsp.chg_path.pdu = AVRC_PDU_CHANGE_PATH;
+ avrc_rsp.chg_path.status = status_code;
+ /* Send the response */
+ SEND_BROWSEMSG_RSP(IDX_CHANGE_PATH_RSP, &avrc_rsp);
+ return BT_STATUS_SUCCESS;
+}
+
+/**********************************************************************
+**
+** Function playitem_rsp
+**
+** Description Response to Play Item , PDU 0x60
+**
+** Return status
+**
+*********************************************************************/
+
+static bt_status_t playitem_rsp(uint8_t status_code)
+{
+ tAVRC_RESPONSE avrc_rsp;
+
+ CHECK_RC_CONNECTED
+ avrc_rsp.play_item.status = status_code;
+ avrc_rsp.play_item.opcode = opcode_from_pdu(AVRC_PDU_PLAY_ITEM);
+ avrc_rsp.play_item.pdu = AVRC_PDU_PLAY_ITEM;
+ /* Send the response */
+ SEND_METAMSG_RSP(IDX_PLAY_ITEM_RSP, &avrc_rsp);
+ return BT_STATUS_SUCCESS;
+}
+
+/**********************************************************************
+**
+** Function get_itemattr_rsp
+**
+** Description Response to Get Item , PDU 0x60
+**
+** Return status
+**
+*********************************************************************/
+
+static bt_status_t get_itemattr_rsp(uint8_t num_attr, btrc_element_attr_val_t *p_attrs)
+{
+ tAVRC_RESPONSE avrc_rsp;
+ UINT32 i;
+ uint8_t j;
+ tAVRC_ATTR_ENTRY element_attrs[BTRC_MAX_ELEM_ATTR_SIZE];
+
+ CHECK_RC_CONNECTED
+ memset(element_attrs, 0, sizeof(tAVRC_ATTR_ENTRY) * num_attr);
+
+ if (num_attr == 0)
+ {
+ avrc_rsp.get_attrs.status = AVRC_STS_INTERNAL_ERR;
+ }
+ else
+ {
+ for (i=0; i<num_attr; i++)
+ {
+ element_attrs[i].attr_id = p_attrs[i].attr_id;
+ element_attrs[i].name.charset_id = AVRC_CHARSET_ID_UTF8;
+ element_attrs[i].name.str_len = (UINT16)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);
+ }
+ avrc_rsp.get_attrs.status = AVRC_STS_NO_ERROR;
+ }
+ avrc_rsp.get_attrs.attr_count = num_attr;
+ avrc_rsp.get_attrs.p_attr_list = element_attrs;
+ avrc_rsp.get_attrs.pdu = AVRC_PDU_GET_ITEM_ATTRIBUTES;
+ avrc_rsp.get_attrs.opcode = opcode_from_pdu(AVRC_PDU_GET_ITEM_ATTRIBUTES);
+ /* Send the response */
+ SEND_BROWSEMSG_RSP(IDX_GET_ITEM_ATTR_RSP, &avrc_rsp);
+ return BT_STATUS_SUCCESS;
+}
+
/***************************************************************************
**
** Function set_volume
@@ -1747,15 +2904,21 @@ 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 */
- NULL, /* get_player_app_attr_text_rsp */
- NULL, /* get_player_app_value_text_rsp */
+ list_player_app_attr_rsp, /* list_player_app_attr_rsp */
+ list_player_app_value_rsp, /* list_player_app_value_rsp */
+ get_player_app_value_rsp, /* get_player_app_value_rsp PDU 0x13*/
+ get_player_app_attr_text_rsp, /* get_player_app_attr_text_rsp */
+ get_player_app_value_text_rsp,/* get_player_app_value_text_rsp */
get_element_attr_rsp,
- NULL, /* set_player_app_value_rsp */
+ set_player_app_value_rsp, /* set_player_app_value_rsp */
register_notification_rsp,
set_volume,
+ get_folderitem_rsp,
+ set_addrplayer_rsp,
+ set_browseplayer_rsp,
+ changepath_rsp,
+ playitem_rsp,
+ get_itemattr_rsp,
cleanup,
};
diff --git a/btif/src/btif_util.c b/btif/src/btif_util.c
index bc6f99d93..1e7fc7bfd 100644
--- a/btif/src/btif_util.c
+++ b/btif/src/btif_util.c
@@ -512,6 +512,7 @@ const char *dump_rc_event(UINT8 event)
CASE_RETURN_STR(BTA_AV_VENDOR_RSP_EVT)
CASE_RETURN_STR(BTA_AV_META_MSG_EVT)
CASE_RETURN_STR(BTA_AV_RC_FEAT_EVT)
+ CASE_RETURN_STR(BTA_AV_BROWSE_MSG_EVT)
default:
return "UNKNOWN_EVENT";
}
@@ -530,7 +531,7 @@ const char * dump_rc_notification_event_id(UINT8 event_id)
CASE_RETURN_STR(AVRC_EVT_SYSTEM_STATUS_CHANGE)
CASE_RETURN_STR(AVRC_EVT_APP_SETTING_CHANGE)
CASE_RETURN_STR(AVRC_EVT_VOLUME_CHANGE)
-
+ CASE_RETURN_STR(AVRC_EVT_NOW_PLAYING_CHANGE)
default:
return "Unhandled Event ID";
}
@@ -554,6 +555,8 @@ 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)
default:
return "Unknown PDU";
}
diff --git a/include/bt_target.h b/include/bt_target.h
index 7cc4f9e37..47236db2a 100644
--- a/include/bt_target.h
+++ b/include/bt_target.h
@@ -1581,6 +1581,19 @@ Range: 2 octets
#define AVRC_CTLR_INCLUDED TRUE
#endif
+#ifndef SDP_AVRCP_1_5
+#define SDP_AVRCP_1_5 TRUE
+
+#if SDP_AVRCP_1_5 == TRUE
+#ifndef AVCT_BROWSE_INCLUDED
+#define AVCT_BROWSE_INCLUDED TRUE
+#else
+#ifndef AVCT_BROWSE_INCLUDED
+#define AVCT_BROWSE_INCLUDED FALSE
+#endif
+#endif
+#endif
+#endif
/******************************************************************************
**
** MCAP
diff --git a/stack/avct/avct_api.c b/stack/avct/avct_api.c
index bf3dd1854..797e07cb2 100644
--- a/stack/avct/avct_api.c
+++ b/stack/avct/avct_api.c
@@ -112,6 +112,9 @@ void AVCT_Deregister(void)
/* deregister PSM with L2CAP */
L2CA_Deregister(AVCT_PSM);
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+ L2CA_Deregister(AVCT_BR_PSM);
+#endif
}
/*******************************************************************************
diff --git a/stack/avct/avct_ccb.c b/stack/avct/avct_ccb.c
index e0f87de6a..11c45db62 100644
--- a/stack/avct/avct_ccb.c
+++ b/stack/avct/avct_ccb.c
@@ -88,6 +88,7 @@ void avct_ccb_dealloc(tAVCT_CCB *p_ccb, UINT8 event, UINT16 result, BD_ADDR bd_a
/* control channel is down, but the browsing channel is still connected 0 disconnect it now */
avct_bcb_event(p_ccb->p_bcb, AVCT_LCB_UL_UNBIND_EVT, (tAVCT_LCB_EVT *) &p_ccb);
p_ccb->p_lcb = NULL;
+ memset(p_ccb, 0, sizeof(tAVCT_CCB));
}
#else
memset(p_ccb, 0, sizeof(tAVCT_CCB));
@@ -148,3 +149,41 @@ tAVCT_CCB *avct_ccb_by_idx(UINT8 idx)
}
return p_ccb;
}
+
+
+/*******************************************************************************
+**
+** Function avct_get_peer_addr_by_ccb
+**
+** Description Return peer BD address on ccb index (or handle).
+**
+**
+** Returns BD Address.
+**
+*******************************************************************************/
+BOOLEAN avct_get_peer_addr_by_ccb (UINT8 idx, BD_ADDR addr)
+{
+ tAVCT_CCB *p_ccb;
+ BOOLEAN value = FALSE;
+ p_ccb = avct_ccb_by_idx(idx);
+ if (p_ccb == NULL)
+ {
+ AVCT_TRACE_WARNING("No ccb for idx %d", idx);
+ }
+ else
+ {
+ if (p_ccb->p_lcb != NULL)
+ {
+ memcpy(addr, p_ccb->p_lcb->peer_addr, BD_ADDR_LEN);
+ value = TRUE;
+ }
+ else
+ {
+ AVCT_TRACE_WARNING("No lcb for idx %d", idx);
+ }
+ }
+ return value;
+}
+
+
+
diff --git a/stack/avct/avct_int.h b/stack/avct/avct_int.h
index 29300a5cd..1c059ee17 100644
--- a/stack/avct/avct_int.h
+++ b/stack/avct/avct_int.h
@@ -96,6 +96,8 @@ typedef struct {
UINT8 ch_flags; /* L2CAP configuration flags */
BT_HDR *p_tx_msg; /* Message to be sent - in case the browsing channel is not open when MsgReg is called */
UINT8 ch_close; /* CCB index+1, if CCB initiated channel close */
+ BUFFER_Q tx_q; /* Transmit data buffer queue */
+ BOOLEAN cong; /* TRUE, if congested */
} tAVCT_BCB;
#define AVCT_ALOC_LCB 0x01
diff --git a/stack/avct/avct_l2c.c b/stack/avct/avct_l2c.c
index 815fa4b33..39f7147b3 100644
--- a/stack/avct/avct_l2c.c
+++ b/stack/avct/avct_l2c.c
@@ -35,6 +35,13 @@
#define AVCT_L2C_CFG_IND_DONE (1<<0)
#define AVCT_L2C_CFG_CFM_DONE (1<<1)
+/*L2CAP Browsing Parameter */
+#define AVCT_L2C_TX_WINDOW_SIZE 1
+#define AVCT_L2C_MAX_TRANSMISSION 20
+#define AVCT_L2C_RETRANS_TIMEOUT 2000
+#define AVCT_L2C_MONITOR_TIMEOUT 12000
+#define AVCT_L2C_MPS_SEGMENT_SIZE 1000
+
/* callback function declarations */
void avct_l2c_connect_ind_cback(BD_ADDR bd_addr, UINT16 lcid, UINT16 psm, UINT8 id);
void avct_l2c_connect_cfm_cback(UINT16 lcid, UINT16 result);
@@ -45,6 +52,19 @@ void avct_l2c_disconnect_cfm_cback(UINT16 lcid, UINT16 result);
void avct_l2c_congestion_ind_cback(UINT16 lcid, BOOLEAN is_congested);
void avct_l2c_data_ind_cback(UINT16 lcid, BT_HDR *p_buf);
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+const tL2CAP_FCR_OPTS avct_l2c_br_fcr_opts_def =
+{
+ L2CAP_FCR_ERTM_MODE, /* Mandatory for Browsing */
+ AVCT_L2C_TX_WINDOW_SIZE, /* Tx window size to be #define in bt_target.h*/
+ AVCT_L2C_MAX_TRANSMISSION, /* Maximum transmissions before disconnecting */
+ AVCT_L2C_RETRANS_TIMEOUT, /* Retransmission timeout (2 secs) */
+ AVCT_L2C_MONITOR_TIMEOUT, /* Monitor timeout (12 secs) */
+ AVCT_L2C_MPS_SEGMENT_SIZE /* MPS segment size */
+};
+#endif
+
+
/* L2CAP callback function structure */
const tL2CAP_APPL_INFO avct_l2c_appl = {
avct_l2c_connect_ind_cback,
@@ -60,6 +80,36 @@ const tL2CAP_APPL_INFO avct_l2c_appl = {
NULL /* tL2CA_TX_COMPLETE_CB */
};
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+/* L2CAP Callback function for Browsing AVRCP 1.4 structure */
+
+/* callback function declarations */
+/* callback function declarations */
+void avct_l2c_br_connect_ind_cback(BD_ADDR bd_addr, UINT16 lcid, UINT16 psm, UINT8 id);
+void avct_l2c_br_connect_cfm_cback(UINT16 lcid, UINT16 result);
+void avct_l2c_br_config_cfm_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg);
+void avct_l2c_br_config_ind_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg);
+void avct_l2c_br_disconnect_ind_cback(UINT16 lcid, BOOLEAN ack_needed);
+void avct_l2c_br_disconnect_cfm_cback(UINT16 lcid, UINT16 result);
+void avct_l2c_br_congestion_ind_cback(UINT16 lcid, BOOLEAN is_congested);
+void avct_l2c_br_data_ind_cback(UINT16 lcid, BT_HDR *p_buf);
+
+
+
+const tL2CAP_APPL_INFO avct_l2c_br_appl = {
+ avct_l2c_br_connect_ind_cback,
+ avct_l2c_br_connect_cfm_cback,
+ NULL,
+ avct_l2c_br_config_ind_cback,
+ avct_l2c_br_config_cfm_cback,
+ avct_l2c_br_disconnect_ind_cback,
+ avct_l2c_br_disconnect_cfm_cback,
+ NULL,
+ avct_l2c_br_data_ind_cback,
+ avct_l2c_br_congestion_ind_cback,
+ NULL /* tL2CA_TX_COMPLETE_CB */
+};
+#endif
/*******************************************************************************
**
** Function avct_l2c_is_passive
@@ -165,6 +215,100 @@ void avct_l2c_connect_ind_cback(BD_ADDR bd_addr, UINT16 lcid, UINT16 psm, UINT8
#endif
}
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function avct_l2c_br_connect_ind_cback
+**
+** Description This is the L2CAP connect indication callback function.
+**
+** Return void
+**
+*******************************************************************************/
+void avct_l2c_br_connect_ind_cback(BD_ADDR bd_addr, UINT16 lcid, UINT16 psm, UINT8 id)
+{
+ tAVCT_BCB *p_bcb = &avct_cb.bcb[0] ;
+ tAVCT_LCB *p_lcb = NULL;
+ UINT16 result = L2CAP_CONN_OK;
+ tAVCT_CCB *p_ccb = &avct_cb.ccb[0];
+ tL2CAP_ERTM_INFO ertm_info;
+ tL2CAP_ERTM_INFO *p_ertm_info = NULL;
+ tL2CAP_CFG_INFO cfg;
+ UINT8 index;
+
+ AVCT_TRACE_DEBUG("avct_l2c_br_connect_ind_cback lcid:%x, psm:%x, id:%x",
+ lcid , psm , id);
+
+ /*Check for associated lcb*/
+ if ((p_lcb = avct_lcb_by_bd(bd_addr)) == NULL)
+ {
+ AVCT_TRACE_ERROR("### LCB not found");
+ result = L2CAP_CONN_NO_RESOURCES;
+ L2CA_ErtmConnectRsp (bd_addr, id, lcid, result, L2CAP_CONN_OK, p_ertm_info);
+ }
+ else
+ {
+ index = (UINT8) (p_lcb - &avct_cb.lcb[0]); //calculate offset.
+ AVCT_TRACE_DEBUG("index value = %d",index);
+ p_bcb = &avct_cb.bcb[index];
+ if (p_bcb == NULL)
+ {
+ /*Disconnect as browsing channel = NULL */
+ AVCT_TRACE_ERROR("### BCB NULL");
+ result = L2CAP_CONN_NO_RESOURCES;
+ L2CA_ErtmConnectRsp (bd_addr, id, lcid, result, L2CAP_CONN_OK, &ertm_info);
+ }
+ else
+ {
+ p_bcb->allocated = index +1 ;
+ for (index = 0; index < AVCT_NUM_CONN; ++index)
+ {
+ if (avct_cb.ccb[index].p_lcb == p_lcb)
+ {
+ AVCT_TRACE_ERROR("index value = %d",index);
+ avct_cb.ccb[index].p_bcb = p_bcb ;
+ avct_cb.ccb[index].allocated = AVCT_ALOC_BCB ;
+ }
+
+ }
+ AVCT_TRACE_DEBUG("Channel RSP");
+ p_bcb->ch_lcid = lcid; /*Updadate LCID so that on config associated bcb could be found*/
+ ertm_info.preferred_mode = L2CAP_FCR_ERTM_MODE;
+ ertm_info.allowed_modes = L2CAP_FCR_CHAN_OPT_ERTM;
+ ertm_info.user_rx_pool_id = HCI_ACL_POOL_ID;
+ ertm_info.user_tx_pool_id = HCI_ACL_POOL_ID;
+ ertm_info.fcr_rx_pool_id = HCI_ACL_POOL_ID;
+ ertm_info.fcr_tx_pool_id = HCI_ACL_POOL_ID;
+ p_ertm_info = &ertm_info;
+ L2CA_ErtmConnectRsp (bd_addr, id, lcid, result, L2CAP_CONN_OK, p_ertm_info);
+ }
+ /*Send L2CAP Channel Rsp if result = ok
+ * proceed with connection
+ */
+ if (result == L2CAP_CONN_OK)
+ {
+ /* transition to configuration state */
+ p_bcb->ch_state = AVCT_CH_CFG;
+ /* Send L2CAP config req */
+ memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
+ cfg.mtu_present = TRUE;
+ cfg.mtu = avct_cb.mtu_br; //As per initial config it's 1008
+ cfg.fcr_present = TRUE;
+ memcpy(&cfg.fcr, &avct_l2c_br_fcr_opts_def, sizeof (tL2CAP_FCR_OPTS));
+ /*Send Configue Request*/
+ L2CA_ConfigReq(lcid, &cfg);
+ AVCT_TRACE_DEBUG("Browse Channel mtu size = %d",cfg.mtu);
+ }
+ // Send L2CAP Config Rsp
+ }
+
+#if (BT_USE_TRACES == TRUE)
+ if (p_bcb)
+ AVCT_TRACE_DEBUG("ch_state cni: %d ", p_bcb->ch_state);
+#endif
+}
+
+#endif
/*******************************************************************************
**
** Function avct_l2c_connect_cfm_cback
@@ -226,6 +370,21 @@ void avct_l2c_connect_cfm_cback(UINT16 lcid, UINT16 result)
}
}
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+/********************************************************************************
+** Function avct_l2c_br_connect_cfm_cback
+** Description Function is not expected to be called
+** as browsing is initiated by remote device.
+**
+*********************************************************************************/
+
+void avct_l2c_br_connect_cfm_cback(UINT16 lcid, UINT16 result)
+{
+ AVCT_TRACE_ERROR("avct_l2c_br_connect_cfm_cback %x: lcid , %x: result", lcid, result );
+}
+#endif
+
+
/*******************************************************************************
**
** Function avct_l2c_config_cfm_cback
@@ -264,7 +423,7 @@ void avct_l2c_config_cfm_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg)
/* else failure */
else
{
- AVCT_TRACE_DEBUG("ERROR avct_l2c_config_cfm_cback L2CA_DisconnectReq %d ", p_lcb->ch_state);
+ AVCT_TRACE_ERROR("ERROR avct_l2c_config_cfm_cback L2CA_DisconnectReq = %d ", p_lcb->ch_state);
/* store result value */
p_lcb->ch_result = p_cfg->result;
@@ -276,6 +435,66 @@ void avct_l2c_config_cfm_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg)
}
}
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+/*************************************************************************
+** Function : avct_l2c_br_config_cfm_cback
+**
+** Description: This is the L2CAP config confirm callback function.
+**
+**
+** Returns void
+**
+*************************************************************************/
+
+void avct_l2c_br_config_cfm_cback(UINT16 lcid, tL2CAP_CFG_INFO * p_cfg)
+{
+ tAVCT_BCB *p_bcb;
+ AVCT_TRACE_DEBUG("avct_l2c_br_config_cfm_cback lcid : %x",lcid);
+
+ /*lookup for bcb channel, for given lcid there
+ * should be a bcb associated
+ */
+ if ((p_bcb = avct_bcb_by_lcid(lcid)) != NULL)
+ {
+ AVCT_TRACE_DEBUG("avct_l2c_br_config_cfm_cback: 0x%x, ch_state: %d, res: %d, ch_flags",
+ lcid, p_bcb->ch_state, p_cfg->result ,p_bcb->ch_flags );
+ AVCT_TRACE_DEBUG("MTU :%x ",p_cfg->mtu);
+ /*Check for the state , it should be in config*/
+ if (p_bcb->ch_state == AVCT_CH_CFG)
+ {
+ /*Check for remote l2cap response */
+ if (p_cfg->result == L2CAP_CFG_OK)
+ {
+ /*Update BCB ch_flags ,either IND_DONE , CFM_DONE */
+ p_bcb->ch_flags |= AVCT_L2C_CFG_CFM_DONE;
+ /* Check for Configuraiton Flag , if configuration complete*/
+ if (p_bcb->ch_flags & AVCT_L2C_CFG_IND_DONE)
+ {
+ p_bcb->ch_state = AVCT_CH_OPEN;
+ p_bcb->state = 0;
+ avct_bcb_event(p_bcb, AVCT_LCB_LL_OPEN_EVT, NULL);
+ }
+ }
+ /*IF L2CAP response result is != L2CAP_CFG_OK*/
+ else
+ {
+ AVCT_TRACE_ERROR("###config_cfm_cback error, ch_state:%d ", p_bcb->ch_state);
+ /* store result value */
+ p_bcb->ch_result = p_cfg->result;
+ /* Send L2CAP disconnect req */
+ L2CA_DisconnectReq(lcid);
+ }
+ }
+ AVCT_TRACE_DEBUG("ch_state cfc: %d ", p_bcb->ch_state);
+ }
+ else
+ {
+ AVCT_TRACE_ERROR("### BCB NULL");
+ L2CA_DisconnectReq(lcid);
+ }
+}
+#endif
+
/*******************************************************************************
**
** Function avct_l2c_config_ind_cback
@@ -326,6 +545,64 @@ void avct_l2c_config_ind_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg)
}
}
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+/**************************************************************************
+** Function : avct_l2c_config_ind_cback
+**
+** Description: This is the L2CAP config indication callback function.
+**
+**
+** Returns: void
+**
+****************************************************************************/
+void avct_l2c_br_config_ind_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg)
+{
+ tAVCT_BCB *p_bcb;
+
+ AVCT_TRACE_DEBUG("config_ind_cback tx_win_sz:%x, max_transmit:%x, rtrans:%x,mon_tout : %x",p_cfg->fcr.tx_win_sz ,\
+ p_cfg->fcr.max_transmit , p_cfg->fcr.rtrans_tout , p_cfg->fcr.mon_tout);
+
+ if ((p_bcb = avct_bcb_by_lcid(lcid)) != NULL)
+ {
+ AVCT_TRACE_DEBUG("avct_l2c_br_config_ind_cback: 0x%x, ch_state: %d", lcid, p_bcb->ch_state);
+ /* store the mtu in tbl Start from here */
+ AVCT_TRACE_DEBUG("avct_l2c_br_config_ind_cback mtu_present: 0x%x, peer mtu: %d", p_cfg->mtu_present, p_cfg->mtu);
+ if (p_cfg->mtu_present)
+ {
+ AVCT_TRACE_DEBUG("PEER MTU: 0x%x", p_bcb->peer_mtu);
+ p_bcb->peer_mtu = p_cfg->mtu;
+ }
+ else
+ {
+ p_bcb->peer_mtu = L2CAP_DEFAULT_MTU;
+ }
+ /* send L2CAP configure response */
+ memset(p_cfg, 0, sizeof(tL2CAP_CFG_INFO));
+ p_cfg->result = L2CAP_CFG_OK;
+ L2CA_ConfigRsp(lcid, p_cfg);
+ /* if first config ind */
+ if ((p_bcb->ch_flags & AVCT_L2C_CFG_IND_DONE) == 0)
+ {
+ /* update flags */
+ p_bcb->ch_flags |= AVCT_L2C_CFG_IND_DONE;
+
+ /* if configuration complete */
+ if (p_bcb->ch_flags & AVCT_L2C_CFG_CFM_DONE)
+ {
+ p_bcb->ch_state = AVCT_CH_OPEN;
+ avct_bcb_event(p_bcb, AVCT_LCB_LL_OPEN_EVT, NULL);
+ }
+ }
+ AVCT_TRACE_DEBUG("ch_state cfi: %d ", p_bcb->ch_state);
+ }
+ else
+ {
+ AVCT_TRACE_ERROR("### BCB= NULL");
+ L2CA_DisconnectReq(lcid);
+ }
+}
+#endif
+
/*******************************************************************************
**
** Function avct_l2c_disconnect_ind_cback
@@ -356,6 +633,40 @@ void avct_l2c_disconnect_ind_cback(UINT16 lcid, BOOLEAN ack_needed)
}
}
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+/********************************************************************************************
+** Function: avct_l2c_br_disconnect_ind_cback
+**
+** Description: This is the L2CAP disconnect indication callback function.
+**
+**
+** Returns void
+**
+********************************************************************************************/
+void avct_l2c_br_disconnect_ind_cback(UINT16 lcid, BOOLEAN ack_needed)
+{
+ tAVCT_BCB *p_bcb;
+ UINT16 result = AVCT_RESULT_FAIL;
+ AVCT_TRACE_DEBUG("avct_l2c_br_disconnect_ind_cback lcid : %d ", lcid);
+ //Lookup BCB for this event
+ if ((p_bcb = avct_bcb_by_lcid(lcid)) != NULL)
+ {
+ AVCT_TRACE_DEBUG("avct_l2c_disconnect_ind_cback: 0x%x, ch_state: %d",\
+ lcid, p_bcb->ch_state);
+ if (ack_needed)
+ {
+ /* send L2CAP disconnect response */
+ L2CA_DisconnectRsp(lcid);
+ }
+ avct_bcb_event(p_bcb, AVCT_LCB_LL_CLOSE_EVT, (tAVCT_LCB_EVT *) &result);
+ }
+ else
+ {
+ AVCT_TRACE_ERROR("###BCB NULL");
+ }
+}
+#endif
+
/*******************************************************************************
**
** Function avct_l2c_disconnect_cfm_cback
@@ -385,6 +696,32 @@ void avct_l2c_disconnect_cfm_cback(UINT16 lcid, UINT16 result)
}
}
+
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+/*********************************************************************************
+**
+** Function avct_l2c_br_disconnect_cfm_cback
+**
+** Description This is the L2CAP disconnect Confirmation callback function
+**
+**
+** Returns Void
+**
+***********************************************************************************/
+void avct_l2c_br_disconnect_cfm_cback(UINT16 lcid, UINT16 result)
+{
+ tAVCT_BCB *p_bcb;
+ AVCT_TRACE_DEBUG("avct_l2c_br_disconnect_cfm_cback lcid : %d ", lcid);
+
+ if ((p_bcb = avct_bcb_by_lcid(lcid)) != NULL)
+ {
+ AVCT_TRACE_DEBUG("avct_l2c_disconnect_cfm_cback: 0x%x, ch_state: %d, res: %d",
+ lcid, p_bcb->ch_state, result);
+ p_bcb->ch_result = 0;
+ }
+}
+
+#endif
/*******************************************************************************
**
** Function avct_l2c_congestion_ind_cback
@@ -407,6 +744,34 @@ void avct_l2c_congestion_ind_cback(UINT16 lcid, BOOLEAN is_congested)
}
}
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+
+/*********************************************************************************
+** Function avct_l2c_br_congestion_ind_cback
+**
+** Description This is the L2CAP congestion indication callback function.
+**
+** Returns void
+****************************************************************************/
+void avct_l2c_br_congestion_ind_cback(UINT16 lcid, BOOLEAN is_congested)
+{
+ tAVCT_BCB *p_bcb = NULL;
+ AVCT_TRACE_DEBUG("avct_l2c_br_congestion_ind_cback lcid:%d, congestion:%d",
+ lcid,is_congested);
+
+ /* look up for Browse Control Block for this channel */
+ p_bcb = avct_bcb_by_lcid(lcid);
+ if (p_bcb != NULL)
+ {
+ avct_bcb_event(p_bcb, AVCT_LCB_LL_CONG_EVT, (tAVCT_LCB_EVT *) &is_congested);
+ }
+ else
+ {
+ AVCT_TRACE_ERROR("### No BCB associated with lcid");
+ }
+}
+#endif
+
/*******************************************************************************
**
** Function avct_l2c_data_ind_cback
@@ -434,3 +799,32 @@ void avct_l2c_data_ind_cback(UINT16 lcid, BT_HDR *p_buf)
}
}
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+/*****************************************************************************
+**
+** Function avct_l2c_br_data_ind_cback
+**
+** Description This is the L2CAP data indication callback function.
+**
+** Returns void
+**
+*****************************************************************************/
+void avct_l2c_br_data_ind_cback(UINT16 lcid, BT_HDR *p_buf)
+{
+ tAVCT_BCB *p_bcb;
+
+ AVCT_TRACE_DEBUG("avct_l2c_br_data_ind_cback lcid : %d ", lcid);
+ AVCT_TRACE_DEBUG("BT_HDR event: %x , len: %x , offset: %x, layer_spec: %x ", p_buf->event,
+ p_buf->len,p_buf->offset , p_buf->layer_specific );
+ if ((p_bcb = avct_bcb_by_lcid(lcid)) != NULL)
+ {
+ avct_bcb_event(p_bcb, AVCT_LCB_LL_MSG_EVT, (tAVCT_LCB_EVT *) &p_buf);
+ }
+ else /* prevent buffer leak */
+ {
+ AVCT_TRACE_WARNING("avct_l2c_br_data_ind_cback drop buffer");
+ GKI_freebuf(p_buf);
+ }
+
+}
+#endif
diff --git a/stack/avct/avct_lcb.c b/stack/avct/avct_lcb.c
index 26c03c72e..d61a4f6ab 100644
--- a/stack/avct/avct_lcb.c
+++ b/stack/avct/avct_lcb.c
@@ -37,6 +37,7 @@
#if BT_TRACE_VERBOSE == TRUE
+
/* verbose state strings for trace */
const char * const avct_lcb_st_str[] = {
"LCB_IDLE_ST",
@@ -113,6 +114,27 @@ const tAVCT_LCB_ACTION avct_lcb_action[] = {
avct_lcb_free_msg_ind
};
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+const tAVCT_BCB_ACTION avct_bcb_action[] = {
+ avct_bcb_chnl_open,
+ avct_bcb_chnl_disc,
+ avct_bcb_send_msg,
+ avct_bcb_open_ind,
+ avct_bcb_open_fail,
+ avct_bcb_close_ind,
+ avct_bcb_close_cfm,
+ avct_bcb_msg_ind,
+ avct_bcb_cong_ind,
+ avct_bcb_bind_conn,
+ avct_bcb_bind_fail,
+ avct_bcb_unbind_disc,
+ avct_bcb_chk_disc,
+ avct_bcb_discard_msg,
+ avct_bcb_dealloc,
+ avct_bcb_free_msg_ind
+};
+#endif
+
/* state table information */
#define AVCT_LCB_ACTIONS 2 /* number of actions */
#define AVCT_LCB_NEXT_STATE 2 /* position of next state */
@@ -302,6 +324,55 @@ tAVCT_LCB *avct_lcb_by_bd(BD_ADDR bd_addr)
return p_lcb;
}
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+/*****************************************************************************
+**
+** Function avct_bcb_by_lcb
+**
+** Description This function finds bcb associated to a lcb
+**
+** Returns pointer to the bcb , or NULL if none found.
+**
+*******************************************************************************/
+tAVCT_BCB *avct_bcb_by_lcb(tAVCT_LCB *p_lcb)
+{
+ int i;
+ tAVCT_CCB *p_ccb = &avct_cb.ccb[0];
+ for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++)
+ {
+ AVCT_TRACE_DEBUG("avct_bcb_by_lcb %d , ccb ", p_ccb->allocated);
+ if ( p_ccb->p_lcb == p_lcb )
+ {
+ return avct_cb.ccb[i].p_bcb;
+ }
+ }
+ AVCT_TRACE_ERROR("###avct_bcb_by_lcb ERROR");
+ return NULL ;
+}
+
+/*****************************************************************************
+**
+** Function avct_lcb_by_bcb
+**
+** Description This
+**
+** Returns pointer to the lcb, or NULL if none found.
+**
+*******************************************************************************/
+tAVCT_LCB *avct_lcb_by_bcb(tAVCT_BCB *p_bcb)
+{
+ tAVCT_CCB *p_ccb = &avct_cb.ccb[0];
+ int i;
+ for (i = 0; i < AVCT_NUM_CONN; i++)
+ {
+ AVCT_TRACE_DEBUG("avct_lcb_alloc= %d", p_bcb->allocated);
+ if(p_ccb[i].allocated && p_ccb[i].p_bcb == p_bcb)
+ return avct_cb.ccb[i].p_lcb;
+ }
+ AVCT_TRACE_ERROR("###avct_lcb_by_bcb ERROR");
+ return NULL ;
+}
+#endif
/*******************************************************************************
**
** Function avct_lcb_alloc
@@ -383,6 +454,55 @@ void avct_lcb_dealloc(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
}
}
+#if AVCT_BROWSE_INCLUDED
+
+/*******************************************************************************
+**
+** Function avct_bcb_dealloc
+**
+** Description Deallocate a browse control block.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avct_bcb_dealloc(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data)
+{
+ tAVCT_CCB *p_ccb = &avct_cb.ccb[0];
+ BOOLEAN found = FALSE;
+ int i;
+
+ if (p_bcb != NULL)
+ {
+ AVCT_TRACE_DEBUG("avct_bcb_dealloc %d", p_bcb->allocated);
+ for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++)
+ {
+ /* if ccb allocated and */
+ if (p_ccb->allocated)
+ {
+ if (p_ccb->p_bcb == p_bcb)
+ {
+ AVCT_TRACE_DEBUG("avct_lcb_dealloc used by ccb: %d", i);
+ found = TRUE;
+ break;
+ }
+ }
+ }
+
+ if (!found)
+ {
+ AVCT_TRACE_DEBUG("avct_bcb_dealloc now");
+ memset(p_bcb, 0, sizeof(tAVCT_BCB));
+ }
+ }
+ else
+ {
+ AVCT_TRACE_ERROR("### dealloc Null bcb");
+ }
+
+}
+
+#endif
/*******************************************************************************
**
** Function avct_lcb_by_lcid
@@ -416,6 +536,41 @@ tAVCT_LCB *avct_lcb_by_lcid(UINT16 lcid)
return p_lcb;
}
+#if AVCT_BROWSE_INCLUDED
+/******************************************************************************
+**
+** Function avct_bcb_by_lcid(UINT16 lcid);
+**
+** Description Find the BCB associated with the L2CAP LCID
+**
+** Return pointer to browse control block
+**
+*******************************************************************************/
+
+tAVCT_BCB *avct_bcb_by_lcid(UINT16 lcid)
+{
+ AVCT_TRACE_DEBUG("avct_bcb_by_lcid :=%x",lcid);
+ tAVCT_BCB *p_bcb = &avct_cb.bcb[0];
+ int i;
+
+ for (i = 0; i < AVCT_NUM_LINKS; i++, p_bcb++)
+ {
+ if (p_bcb->allocated && ((p_bcb->ch_lcid == lcid)))
+ {
+ AVCT_TRACE_DEBUG("avct_bcb_by_lcid :=%x",p_bcb->ch_lcid);
+ break;
+ }
+ }
+ if (i == AVCT_NUM_LINKS)
+ {
+ /*out of bcbs */
+ p_bcb = NULL;
+ AVCT_TRACE_WARNING("###No bcb for lcid %x", lcid);
+ }
+ return p_bcb;
+}
+
+#endif
/*******************************************************************************
**
** Function avct_lcb_has_pid
diff --git a/stack/avct/avct_lcb_act.c b/stack/avct/avct_lcb_act.c
index 589af0bdf..3ba1d1d41 100644
--- a/stack/avct/avct_lcb_act.c
+++ b/stack/avct/avct_lcb_act.c
@@ -175,6 +175,61 @@ static BT_HDR *avct_lcb_msg_asmbl(tAVCT_LCB *p_lcb, BT_HDR *p_buf)
return p_ret;
}
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+
+/*******************************************************************************
+**
+** Function avct_bcb_msg_asmbl
+**
+** Description Reassemble incoming message.
+**
+**
+** Returns Pointer to reassembled message; NULL if no message
+** available.
+**
+*******************************************************************************/
+static BT_HDR *avct_bcb_msg_asmbl(tAVCT_BCB *p_bcb, BT_HDR *p_buf)
+{
+ UINT8 *p;
+ UINT8 pkt_type;
+ BT_HDR *p_ret;
+ UINT16 buf_len;
+
+ /* parse the message header */
+ AVCT_TRACE_DEBUG("bcb_msg_asmbl peer_mtu:%x, ch_lcid:%x",p_bcb->peer_mtu, \
+ p_bcb->ch_lcid);
+ p = (UINT8 *)(p_buf + 1) + p_buf->offset;
+ AVCT_PRS_PKT_TYPE(p, pkt_type);
+ AVCT_TRACE_DEBUG("bcb_msg_asmbl pkt_type:%d, p_buf->offset:%x",pkt_type, \
+ p_buf->offset);
+ /* quick sanity check on length */
+ if (p_buf->len < avct_lcb_pkt_type_len[pkt_type])
+ {
+ GKI_freebuf(p_buf);
+ AVCT_TRACE_WARNING("### Bad length during reassembly");
+ p_ret = NULL;
+ }
+
+ /* As Per AVRCP 1.5 Spec,Fragmentation is not allowed
+ * Section 7.2 AVCTP fragmentation shall not be used on the AVCTP Browsing Channel.
+ * packet type wil be single else return error
+ */
+ else if (pkt_type == AVCT_PKT_TYPE_SINGLE)
+ {
+ AVCT_TRACE_DEBUG("Got single during reassembly");
+ p_ret = p_buf;
+ }
+ else
+ {
+ GKI_freebuf(p_buf);
+ p_ret =NULL;
+ AVCT_TRACE_WARNING("### Got Fragmented packet");
+ }
+ return p_ret;
+}
+#endif
+
+
/*******************************************************************************
**
@@ -201,6 +256,50 @@ void avct_lcb_chnl_open(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
}
}
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function avct_bcb_chnl_open
+**
+** Description
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avct_bcb_chnl_open(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data)
+{
+ /*DUT does not initiate Browsing channel connect */
+ AVCT_TRACE_ERROR("###avct_bcb_chnl_open");
+}
+
+
+/********************************************************************************
+**
+** Function avct_close_bcb
+**
+** Description Clear BCB data structure
+**
+**
+** Returns void.
+**
+******************************************************************************/
+void avct_close_bcb(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
+{
+ int i;
+ tAVCT_BCB *p_bcb = NULL;
+
+ AVCT_TRACE_DEBUG("avct_close_bcb");
+ p_bcb = avct_bcb_by_lcb(p_lcb);
+ if (p_bcb != NULL)
+ {
+ AVCT_TRACE_DEBUG("Send Disconnect Event");
+ p_bcb->allocated = 0;
+ avct_bcb_event( p_bcb, AVCT_LCB_INT_CLOSE_EVT, p_data);
+ }
+}
+
+#endif
+
/*******************************************************************************
**
** Function avct_lcb_unbind_disc
@@ -218,6 +317,24 @@ void avct_lcb_unbind_disc(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
avct_ccb_dealloc(p_data->p_ccb, AVCT_DISCONNECT_CFM_EVT, 0, NULL);
}
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function avct_bcb_unbind_disc
+**
+** Description Deallocate ccb and call callback with disconnect event.
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avct_bcb_unbind_disc(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data)
+{
+ AVCT_TRACE_ERROR("### avct_bcb_unbind_disc");
+}
+#endif
+
+
/*******************************************************************************
**
** Function avct_lcb_open_ind
@@ -271,6 +388,58 @@ void avct_lcb_open_ind(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
}
}
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function avct_bcb_open_ind
+**
+** Description Handle an LL_OPEN event. For each allocated ccb already
+** bound to this lcb, send a connect event. For each
+** unbound ccb with a new PID, bind that ccb to this lcb and
+** send a connect event.
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avct_bcb_open_ind(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data)
+{
+ tAVCT_CCB *p_ccb = &avct_cb.ccb[0];
+ tAVCT_LCB *p_lcb =NULL;
+ int i;
+ BOOLEAN bind = FALSE;
+
+ for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++)
+ {
+ AVCT_TRACE_DEBUG("avct_bcb_open_ind: %d",p_ccb->allocated);
+ /*if ccb allocated */
+ if (p_ccb->allocated & AVCT_ALOC_BCB)
+ {
+ /* if bound to this bcb then send connect confirm event */
+ if (p_ccb->p_bcb == p_bcb)
+ {
+ AVCT_TRACE_DEBUG("open_ind success");
+ p_lcb = avct_cb.ccb[i].p_lcb;
+ if (p_lcb != NULL)
+ {
+ bind = TRUE;
+ p_ccb->cc.p_ctrl_cback(avct_ccb_to_idx(p_ccb), AVCT_BROWSE_CONN_CFM_EVT,
+ 0, p_lcb->peer_addr);
+ break;
+ }
+ }
+ }
+
+ }
+ if (bind == FALSE)
+ {
+ AVCT_TRACE_ERROR("### open_ind error");
+ avct_bcb_event(p_bcb, AVCT_LCB_INT_CLOSE_EVT, p_data);
+ }
+}
+#endif
+
+
/*******************************************************************************
**
** Function avct_lcb_open_fail
@@ -296,7 +465,25 @@ void avct_lcb_open_fail(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
}
}
}
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function avct_bcb_open_fail
+**
+** Description L2CAP channel open attempt failed. Deallocate any ccbs
+** on this lcb and send connect confirm event with failure.
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avct_bcb_open_fail(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data)
+{
+ /* DUT does not initiate browsing channel open */
+ AVCT_TRACE_ERROR("###avct_bcb_open_fail");
+}
+#endif
/*******************************************************************************
**
** Function avct_lcb_close_ind
@@ -333,6 +520,37 @@ void avct_lcb_close_ind(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
}
}
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function avct_lcb_close_ind
+**
+** Description L2CAP channel closed by peer. Deallocate any initiator
+** ccbs on this lcb and send disconnect ind event.
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avct_bcb_close_ind(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data)
+{
+ tAVCT_CCB *p_ccb = &avct_cb.ccb[0];
+ int i;
+ AVCT_TRACE_DEBUG("avct_bcb_close_ind");
+ for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++)
+ {
+ if (p_ccb->allocated && (p_ccb->p_bcb == p_bcb))
+ {
+ //set avct_cb.bcb to 0
+ memset(p_ccb->p_bcb, 0 ,sizeof(tAVCT_BCB));
+ p_ccb->p_bcb == NULL;
+ AVCT_TRACE_DEBUG("**close_ind");
+ }
+ }
+}
+#endif
+
+
/*******************************************************************************
**
** Function avct_lcb_close_cfm
@@ -379,6 +597,32 @@ void avct_lcb_close_cfm(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
}
}
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function avct_bcb_close_cfm
+**
+** Description
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avct_bcb_close_cfm(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data)
+{
+ AVCT_TRACE_DEBUG("avct_bcb_close_cfm");
+ if (p_bcb != NULL)
+ {
+ memset(p_bcb, 0, sizeof(tAVCT_BCB));
+ }
+ else
+ {
+ AVCT_TRACE_ERROR("### avct_bcb_close_cfm");
+ }
+}
+#endif
+
+
/*******************************************************************************
**
** Function avct_lcb_bind_conn
@@ -396,6 +640,24 @@ void avct_lcb_bind_conn(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
AVCT_CONNECT_CFM_EVT, 0, p_lcb->peer_addr);
}
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function avct_lcb_bind_conn
+**
+** Description Bind ccb to lcb and send connect cfm event.
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avct_bcb_bind_conn(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data)
+{
+ /* DUT does not initiate browse connect*/
+ AVCT_TRACE_ERROR("###avct_bcb_bind_conn");
+}
+
+#endif
/*******************************************************************************
**
** Function avct_lcb_chk_disc
@@ -427,6 +689,23 @@ void avct_lcb_chk_disc(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
}
}
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function avct_bcb_chk_disc
+**
+** Description
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avct_bcb_chk_disc(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data)
+{
+ /* BCB disconnecton done during lcb_chk_disc */
+ AVCT_TRACE_ERROR("### avct_bcb_chk_disc");
+}
+#endif
+
/*******************************************************************************
**
** Function avct_lcb_chnl_disc
@@ -440,10 +719,29 @@ void avct_lcb_chk_disc(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
void avct_lcb_chnl_disc(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
{
UNUSED(p_data);
-
+ AVCT_TRACE_DEBUG("avct_lcb_chnl_disc");
L2CA_DisconnectReq(p_lcb->ch_lcid);
}
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function avct_bcb_chnl_disc
+**
+** Description Disconnect L2CAP channel.
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avct_bcb_chnl_disc(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data)
+{
+ AVCT_TRACE_ERROR("avct_bcb_chnl_disc");
+ /* Disconnect L2CAP Browsing channel */
+ L2CA_DisconnectReq(p_bcb->ch_lcid);
+}
+#endif
+
/*******************************************************************************
**
** Function avct_lcb_bind_fail
@@ -462,6 +760,23 @@ void avct_lcb_bind_fail(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
avct_ccb_dealloc(p_data->p_ccb, AVCT_CONNECT_CFM_EVT, AVCT_RESULT_FAIL, NULL);
}
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function avct_bcb_bind_fail
+**
+** Description
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avct_bcb_bind_fail(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data)
+{
+ /* Not expected to be called */
+ AVCT_TRACE_ERROR("###avct_bcb_bind_fail");
+}
+#endif
+
/*******************************************************************************
**
** Function avct_lcb_cong_ind
@@ -503,6 +818,48 @@ void avct_lcb_cong_ind(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
}
}
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function avct_bcb_cong_ind
+**
+** Description Handle congestion indication from L2CAP.
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avct_bcb_cong_ind(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data)
+{
+ int i;
+ UINT8 event;
+ BT_HDR *p_buf;
+
+ AVCT_TRACE_DEBUG("avct_bcb_cong_ind");
+ if (p_bcb != NULL)
+ {
+ AVCT_TRACE_DEBUG("avct_bcb_cong_ind = %d",p_data->cong);
+ /* set event */
+ event = (p_data->cong) ? AVCT_CONG_IND_EVT : AVCT_UNCONG_IND_EVT;
+ p_bcb->cong = p_data->cong;
+ if (p_bcb->cong == FALSE && GKI_getfirst(&p_bcb->tx_q))
+ {
+ while (!p_bcb->cong && (p_buf = (BT_HDR *)GKI_dequeue(&p_bcb->tx_q)) != NULL)
+ {
+ if (L2CA_DataWrite(p_bcb->ch_lcid, p_buf) == L2CAP_DW_CONGESTED)
+ {
+ p_bcb->cong = TRUE;
+ }
+ }
+ }
+ }
+ else
+ {
+ AVCT_TRACE_ERROR("### bcb NULL");
+ }
+}
+#endif
+
/*******************************************************************************
**
** Function avct_lcb_discard_msg
@@ -522,6 +879,24 @@ void avct_lcb_discard_msg(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
GKI_freebuf(p_data->ul_msg.p_buf);
}
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function avct_bcb_discard_msg
+**
+** Description Discard a message sent in from the API.
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avct_bcb_discard_msg(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data)
+{
+ AVCT_TRACE_ERROR("### avct_bcb_discard_msg");
+ GKI_freebuf(p_data->ul_msg.p_buf);
+}
+#endif
+
/*******************************************************************************
**
** Function avct_lcb_send_msg
@@ -574,7 +949,7 @@ void avct_lcb_send_msg(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
if ((p_buf = (BT_HDR *) GKI_getbuf(buf_size)) == NULL)
{
/* whoops; free original msg buf and bail */
- AVCT_TRACE_ERROR ("avct_lcb_send_msg cannot alloc buffer!!");
+ AVCT_TRACE_ERROR("avct_lcb_send_msg cannot alloc buffer!!");
GKI_freebuf(p_data->ul_msg.p_buf);
break;
}
@@ -639,7 +1014,68 @@ void avct_lcb_send_msg(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
AVCT_TRACE_DEBUG ("avct_lcb_send_msg tx_q_count:%d", GKI_queue_length(&p_lcb->tx_q));
return;
}
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function avct_lcb_send_msg
+**
+** Description Build and send an AVCTP message.
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avct_bcb_send_msg(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data)
+{
+ UINT16 curr_msg_len;
+ UINT8 pkt_type;
+ UINT8 *p;
+ BT_HDR *p_buf;
+ UINT8 nosp = 0; /* number of subsequent packets */
+ UINT16 buf_size = p_bcb->peer_mtu + L2CAP_MIN_OFFSET + BT_HDR_SIZE;
+ /* store msg len */
+ curr_msg_len = p_data->ul_msg.p_buf->len;
+ AVCT_TRACE_DEBUG("avct_bcb_send_msg length: %x",curr_msg_len);
+ AVCT_TRACE_DEBUG("Remote PEER MTU: %x",p_bcb->peer_mtu);
+ /* initialize packet type and other stuff */
+ if (curr_msg_len <= (p_bcb->peer_mtu - AVCT_HDR_LEN_SINGLE))
+ {
+ pkt_type = AVCT_PKT_TYPE_SINGLE;
+ //No need to do segmentation need to send data as a single packet
+ p_buf = p_data->ul_msg.p_buf;
+
+ /* set up to build header */
+ p_buf->len += AVCT_HDR_LEN_SINGLE;
+ p_buf->offset -= AVCT_HDR_LEN_SINGLE;
+ p = (UINT8 *)(p_buf + 1) + p_buf->offset;
+ /* build header */
+ p_data->ul_msg.cr = AVCT_RSP ;
+ AVCT_BLD_HDR(p, p_data->ul_msg.label, pkt_type, p_data->ul_msg.cr);
+ //UINT8_TO_STREAM(p, nosp);
+ p_data->ul_msg.p_ccb->cc.pid = 0x110E;
+ UINT16_TO_BE_STREAM(p, p_data->ul_msg.p_ccb->cc.pid);
+ if (p_bcb->cong == TRUE)
+ {
+ AVCT_TRACE_ERROR("L2CAP congestion");
+ GKI_enqueue (&p_bcb->tx_q, p_buf);
+ }
+ else
+ {
+ if (L2CA_DataWrite(p_bcb->ch_lcid, p_buf) == L2CAP_DW_CONGESTED)
+ {
+ AVCT_TRACE_DEBUG("L2CAP Data Write");
+ p_bcb->cong = TRUE;
+ //Flag to be cleared
+ }
+ }
+ }
+ else
+ {
+ AVCT_TRACE_ERROR("### bcb_send_msg, length incorrect");
+ }
+}
+#endif
/*******************************************************************************
**
** Function avct_lcb_free_msg_ind
@@ -659,6 +1095,26 @@ void avct_lcb_free_msg_ind(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
return;
}
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function avct_bcb_free_msg_ind
+**
+** Description Discard an incoming AVCTP message.
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avct_bcb_free_msg_ind(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data)
+{
+ AVCT_TRACE_DEBUG("avct_bcb_free_msg_ind");
+ if (p_data)
+ GKI_freebuf(p_data->p_buf);
+
+}
+#endif
+
/*******************************************************************************
**
** Function avct_lcb_msg_ind
@@ -732,3 +1188,107 @@ void avct_lcb_msg_ind(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
}
}
}
+
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function avct_bcb_msg_ind
+**
+** Description Handle an incoming AVCTP message.
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avct_bcb_msg_ind(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data)
+{
+ UINT8 *p;
+ UINT8 label, type, cr_ipid;
+ UINT16 pid;
+ tAVCT_LCB *p_lcb;
+ tAVCT_CCB *p_ccb;
+ BT_HDR *p_buf;
+
+ AVCT_TRACE_DEBUG("avct_bcb_msg_ind");
+ /* Update layer specific information so that while
+ * responding AVCT_MsgReq, AVCT layer knows to respond to
+ * Browsing channel
+ */
+ p_data->p_buf->layer_specific = AVCT_DATA_BROWSE;
+
+ /*
+ AVCTP fragmentation shall not be used on the AVCTP Browsing Channel
+ */
+
+ if ((p_data->p_buf = avct_bcb_msg_asmbl(p_bcb, p_data->p_buf)) == NULL)
+ {
+ AVCT_TRACE_ERROR("### Error bcb_msg_asmbl");
+ return;
+ }
+
+ /* Data passed is HCI+L2CAP+AVCT_AVRCP
+ * Point to AVCT start
+ */
+
+ p = (UINT8 *)(p_data->p_buf + 1) + p_data->p_buf->offset;
+
+ /* parse AVCT header byte */
+ AVCT_PRS_HDR(p, label, type, cr_ipid);
+
+ /* check for invalid cr_ipid */
+ if (cr_ipid == AVCT_CR_IPID_INVALID)
+ {
+ AVCT_TRACE_WARNING("### Invalid cr_ipid", cr_ipid);
+ GKI_freebuf(p_data->p_buf);
+ return;
+ }
+ /* parse and lookup PID */
+ BE_STREAM_TO_UINT16(pid, p);
+ p_lcb = avct_lcb_by_bcb(p_bcb);
+ if (p_lcb == NULL)
+ {
+ AVCT_TRACE_ERROR("### Error lcb is NULL");
+ GKI_freebuf(p_data->p_buf);
+ }
+ else
+ {
+ AVCT_TRACE_DEBUG("p_lcb param: p[0]: %x, p[1]: %x,\
+ p[2] : %x, p[3] : %x ",p_lcb->peer_addr[0], p_lcb->peer_addr[1],p_lcb->peer_addr[2],\
+ p_lcb->peer_addr[3]);
+ /* Irrespective of browsing or control
+ * message recieved is passed on to above layer
+ */
+
+ /* Check if p_lcb is correct */
+ if ((p_ccb = avct_lcb_has_pid(p_lcb, pid)) != NULL)
+ {
+ /* PID found, send msg to upper laer, adjust
+ * bt hdr and call msg callback
+ */
+ AVCT_TRACE_DEBUG("label: %x ,cr_ipid : %d ",label, cr_ipid );
+ p_data->p_buf->offset += AVCT_HDR_LEN_SINGLE;
+ p_data->p_buf->len -= AVCT_HDR_LEN_SINGLE;
+ (*p_ccb->cc.p_msg_cback)(avct_ccb_to_idx(p_ccb), label, cr_ipid, p_data->p_buf);
+ }
+ else
+ {
+ /* PID not found; drop message */
+ AVCT_TRACE_WARNING("### No ccb for PID=%x", pid);
+ GKI_freebuf(p_data->p_buf);
+ /* if command send reject */
+ if (cr_ipid == AVCT_CMD)
+ {
+ if ((p_buf = (BT_HDR *) GKI_getpoolbuf(AVCT_CMD_POOL_ID)) != NULL)
+ {
+ p_buf->len = AVCT_HDR_LEN_SINGLE;
+ p_buf->offset = AVCT_MSG_OFFSET - AVCT_HDR_LEN_SINGLE;
+ p = (UINT8 *)(p_buf + 1) + p_buf->offset;
+ AVCT_BLD_HDR(p, label, AVCT_PKT_TYPE_SINGLE, AVCT_REJ);
+ UINT16_TO_BE_STREAM(p, pid);
+ L2CA_DataWrite(p_lcb->ch_lcid, p_buf);
+ }
+ }
+ }
+ }
+}
+#endif
diff --git a/stack/avrc/avrc_api.c b/stack/avrc/avrc_api.c
index 1b874dc8c..359d910ec 100755
--- a/stack/avrc/avrc_api.c
+++ b/stack/avrc/avrc_api.c
@@ -150,7 +150,7 @@ static void avrc_prep_end_frag(UINT8 handle)
UINT8 *p_data, *p_orig_data;
UINT8 rsp_type;
- AVRC_TRACE_DEBUG ("avrc_prep_end_frag" );
+ AVRC_TRACE_DEBUG("avrc_prep_end_frag" );
p_fcb = &avrc_cb.fcb[handle];
/* The response type of the end fragment should be the same as the the PDU of "End Fragment
@@ -226,7 +226,7 @@ static void avrc_send_continue_frag(UINT8 handle, UINT8 label)
p_pkt = p_fcb->p_fmsg;
p_fcb->p_fmsg = NULL;
p_fcb->frag_enabled = FALSE;
- AVRC_TRACE_ERROR ("AVRC_MsgReq no buffers for fragmentation - send internal error" );
+ AVRC_TRACE_ERROR("AVRC_MsgReq no buffers for fragmentation - send internal error" );
p_data = (UINT8 *)(p_pkt+1) + p_pkt->offset;
*p_data++ = AVRC_PDU_REQUEST_CONTINUATION_RSP;
*p_data++ = 0;
@@ -274,7 +274,7 @@ static BT_HDR * avrc_proc_vendor_command(UINT8 handle, UINT8 label,
if (pkt_type != AVRC_PKT_SINGLE)
{
/* reject - commands can only be in single packets at AVRCP level */
- AVRC_TRACE_ERROR ("commands must be in single packet pdu:0x%x", *p_data );
+ AVRC_TRACE_ERROR("commands must be in single packet pdu:0x%x", *p_data );
/* use the current GKI buffer to send the reject */
status = AVRC_STS_BAD_CMD;
}
@@ -390,7 +390,7 @@ static UINT8 avrc_proc_far_msg(UINT8 handle, UINT8 label, UINT8 cr, BT_HDR **pp_
p_data += AVRC_VENDOR_HDR_SIZE;
pkt_type = *(p_data + 1) & AVRC_PKT_TYPE_MASK;
- AVRC_TRACE_DEBUG ("pkt_type %d", pkt_type );
+ AVRC_TRACE_DEBUG("pkt_type %d", pkt_type );
p_rcb = &avrc_cb.rcb[handle];
if (p_msg->company_id == AVRC_CO_METADATA)
{
@@ -433,7 +433,7 @@ static UINT8 avrc_proc_far_msg(UINT8 handle, UINT8 label, UINT8 cr, BT_HDR **pp_
{
/* Unable to allocate buffer for fragmented avrc message. Reuse START
buffer for reassembly (re-assembled message may fit into ACL buf) */
- AVRC_TRACE_DEBUG ("Unable to allocate buffer for fragmented avrc message, \
+ AVRC_TRACE_DEBUG("Unable to allocate buffer for fragmented avrc message, \
reusing START buffer for reassembly");
p_rcb->rasm_offset = p_pkt->offset;
p_rcb->p_rmsg = p_pkt;
@@ -447,7 +447,7 @@ static UINT8 avrc_proc_far_msg(UINT8 handle, UINT8 label, UINT8 cr, BT_HDR **pp_
{
/* Received a CONTINUE/END, but no corresponding START
(or previous fragmented response was dropped) */
- AVRC_TRACE_DEBUG ("Received a CONTINUE/END without no corresponding START \
+ AVRC_TRACE_DEBUG("Received a CONTINUE/END without no corresponding START \
(or previous fragmented response was dropped)");
drop_code = 5;
GKI_freebuf(p_pkt);
@@ -551,6 +551,7 @@ static void avrc_msg_cback(UINT8 handle, UINT8 label, UINT8 cr,
UINT8 opcode;
tAVRC_MSG msg;
UINT8 *p_data;
+ UINT8 *browse_length;
UINT8 *p_begin;
BOOLEAN drop = FALSE;
BOOLEAN do_free = TRUE;
@@ -585,111 +586,100 @@ static void avrc_msg_cback(UINT8 handle, UINT8 label, UINT8 cr,
p_data = (UINT8 *)(p_pkt+1) + p_pkt->offset;
memset(&msg, 0, sizeof(tAVRC_MSG) );
+ /* layer_specific value use to distinguish
+ * Browsing and control channel PDU ID.
+ * AVCT_DATA_BROWSE to be used for browsing
+ * channel
+ */
+ AVRC_TRACE_DEBUG("layer_specific %x",p_pkt->layer_specific);
+ if (p_pkt->layer_specific != AVCT_DATA_BROWSE)
{
- msg.hdr.ctype = p_data[0] & AVRC_CTYPE_MASK;
- AVRC_TRACE_DEBUG("avrc_msg_cback handle:%d, ctype:%d, offset:%d, len: %d",
- handle, msg.hdr.ctype, p_pkt->offset, p_pkt->len);
- msg.hdr.subunit_type = (p_data[1] & AVRC_SUBTYPE_MASK) >> AVRC_SUBTYPE_SHIFT;
- msg.hdr.subunit_id = p_data[1] & AVRC_SUBID_MASK;
- opcode = p_data[2];
- }
-
- if ( ((avrc_cb.ccb[handle].control & AVRC_CT_TARGET) && (cr == AVCT_CMD)) ||
- ((avrc_cb.ccb[handle].control & AVRC_CT_CONTROL) && (cr == AVCT_RSP)) )
- {
-
- switch(opcode)
{
- case AVRC_OP_UNIT_INFO:
- if (cr == AVCT_CMD)
- {
- /* send the response to the peer */
- p_rsp = avrc_copy_packet(p_pkt, AVRC_OP_UNIT_INFO_RSP_LEN);
- p_rsp_data = avrc_get_data_ptr(p_rsp);
- *p_rsp_data = AVRC_RSP_IMPL_STBL;
- /* check & set the offset. set response code, set subunit_type & subunit_id,
- set AVRC_OP_UNIT_INFO */
- /* 3 bytes: ctype, subunit*, opcode */
- p_rsp_data += AVRC_AVC_HDR_SIZE;
- *p_rsp_data++ = 7;
- /* Panel subunit & id=0 */
- *p_rsp_data++ = (AVRC_SUB_PANEL << AVRC_SUBTYPE_SHIFT);
- AVRC_CO_ID_TO_BE_STREAM(p_rsp_data, avrc_cb.ccb[handle].company_id);
- p_rsp->len = (UINT16) (p_rsp_data - (UINT8 *)(p_rsp + 1) - p_rsp->offset);
- cr = AVCT_RSP;
-#if (BT_USE_TRACES == TRUE)
- p_drop_msg = "auto respond";
-#endif
- }
- else
- {
- /* parse response */
- p_data += 4; /* 3 bytes: ctype, subunit*, opcode + octet 3 (is 7)*/
- msg.unit.unit_type = (*p_data & AVRC_SUBTYPE_MASK) >> AVRC_SUBTYPE_SHIFT;
- msg.unit.unit = *p_data & AVRC_SUBID_MASK;
- p_data++;
- AVRC_BE_STREAM_TO_CO_ID(msg.unit.company_id, p_data);
- }
- break;
+ msg.hdr.ctype = p_data[0] & AVRC_CTYPE_MASK;
+ AVRC_TRACE_DEBUG("avrc_msg_cback handle:%d, ctype:%d, offset:%d, len: %d",
+ handle, msg.hdr.ctype, p_pkt->offset, p_pkt->len);
+ msg.hdr.subunit_type = (p_data[1] & AVRC_SUBTYPE_MASK) >> AVRC_SUBTYPE_SHIFT;
+ msg.hdr.subunit_id = p_data[1] & AVRC_SUBID_MASK;
+ opcode = p_data[2];
+ }
- case AVRC_OP_SUB_INFO:
- if (cr == AVCT_CMD)
+ if ( ((avrc_cb.ccb[handle].control & AVRC_CT_TARGET) && (cr == AVCT_CMD)) ||
+ ((avrc_cb.ccb[handle].control & AVRC_CT_CONTROL) && (cr == AVCT_RSP)) )
+ {
+ switch(opcode)
{
- /* send the response to the peer */
- p_rsp = avrc_copy_packet(p_pkt, AVRC_OP_SUB_UNIT_INFO_RSP_LEN);
- p_rsp_data = avrc_get_data_ptr(p_rsp);
- *p_rsp_data = AVRC_RSP_IMPL_STBL;
- /* check & set the offset. set response code, set (subunit_type & subunit_id),
- set AVRC_OP_SUB_INFO, set (page & extention code) */
- p_rsp_data += 4;
- /* Panel subunit & id=0 */
- *p_rsp_data++ = (AVRC_SUB_PANEL << AVRC_SUBTYPE_SHIFT);
- memset(p_rsp_data, AVRC_CMD_OPRND_PAD, AVRC_SUBRSP_OPRND_BYTES);
- p_rsp_data += AVRC_SUBRSP_OPRND_BYTES;
- p_rsp->len = (UINT16) (p_rsp_data - (UINT8 *)(p_rsp + 1) - p_rsp->offset);
- cr = AVCT_RSP;
+ case AVRC_OP_UNIT_INFO:
+ if (cr == AVCT_CMD)
+ {
+ /* send the response to the peer */
+ p_rsp = avrc_copy_packet(p_pkt, AVRC_OP_UNIT_INFO_RSP_LEN);
+ p_rsp_data = avrc_get_data_ptr(p_rsp);
+ *p_rsp_data = AVRC_RSP_IMPL_STBL;
+ /* check & set the offset. set response code, set subunit_type & subunit_id,
+ set AVRC_OP_UNIT_INFO */
+ /* 3 bytes: ctype, subunit*, opcode */
+ p_rsp_data += AVRC_AVC_HDR_SIZE;
+ *p_rsp_data++ = 7;
+ /* Panel subunit & id=0 */
+ *p_rsp_data++ = (AVRC_SUB_PANEL << AVRC_SUBTYPE_SHIFT);
+ AVRC_CO_ID_TO_BE_STREAM(p_rsp_data, avrc_cb.ccb[handle].company_id);
+ p_rsp->len = (UINT16) (p_rsp_data - (UINT8 *)(p_rsp + 1) - p_rsp->offset);
+ cr = AVCT_RSP;
#if (BT_USE_TRACES == TRUE)
- p_drop_msg = "auto responded";
+ p_drop_msg = "auto respond";
#endif
- }
- else
- {
- /* parse response */
- p_data += AVRC_AVC_HDR_SIZE; /* 3 bytes: ctype, subunit*, opcode */
- msg.sub.page = (*p_data++ >> AVRC_SUB_PAGE_SHIFT) & AVRC_SUB_PAGE_MASK;
- xx = 0;
- while (*p_data != AVRC_CMD_OPRND_PAD && xx<AVRC_SUB_TYPE_LEN)
+ }
+ else
{
- msg.sub.subunit_type[xx] = *p_data++ >> AVRC_SUBTYPE_SHIFT;
- if (msg.sub.subunit_type[xx] == AVRC_SUB_PANEL)
- msg.sub.panel = TRUE;
- xx++;
+ /* parse response */
+ p_data += 4; /* 3 bytes: ctype, subunit*, opcode + octet 3 (is 7)*/
+ msg.unit.unit_type = (*p_data & AVRC_SUBTYPE_MASK) >> AVRC_SUBTYPE_SHIFT;
+ msg.unit.unit = *p_data & AVRC_SUBID_MASK;
+ p_data++;
+ AVRC_BE_STREAM_TO_CO_ID(msg.unit.company_id, p_data);
}
- }
- break;
+ break;
- case AVRC_OP_VENDOR:
- p_data = (UINT8 *)(p_pkt+1) + p_pkt->offset;
- p_begin = p_data;
- if (p_pkt->len < AVRC_VENDOR_HDR_SIZE) /* 6 = ctype, subunit*, opcode & CO_ID */
- {
+ case AVRC_OP_SUB_INFO:
if (cr == AVCT_CMD)
- reject = TRUE;
+ {
+ /* send the response to the peer */
+ p_rsp = avrc_copy_packet(p_pkt, AVRC_OP_SUB_UNIT_INFO_RSP_LEN);
+ p_rsp_data = avrc_get_data_ptr(p_rsp);
+ *p_rsp_data = AVRC_RSP_IMPL_STBL;
+ /* check & set the offset. set response code, set (subunit_type & subunit_id),
+ set AVRC_OP_SUB_INFO, set (page & extention code) */
+ p_rsp_data += 4;
+ /* Panel subunit & id=0 */
+ *p_rsp_data++ = (AVRC_SUB_PANEL << AVRC_SUBTYPE_SHIFT);
+ memset(p_rsp_data, AVRC_CMD_OPRND_PAD, AVRC_SUBRSP_OPRND_BYTES);
+ p_rsp_data += AVRC_SUBRSP_OPRND_BYTES;
+ p_rsp->len = (UINT16) (p_rsp_data - (UINT8 *)(p_rsp + 1) - p_rsp->offset);
+ cr = AVCT_RSP;
+#if (BT_USE_TRACES == TRUE)
+ p_drop_msg = "auto responded";
+#endif
+ }
else
- drop = TRUE;
+ {
+ /* parse response */
+ p_data += AVRC_AVC_HDR_SIZE; /* 3 bytes: ctype, subunit*, opcode */
+ msg.sub.page = (*p_data++ >> AVRC_SUB_PAGE_SHIFT) & AVRC_SUB_PAGE_MASK;
+ xx = 0;
+ while (*p_data != AVRC_CMD_OPRND_PAD && xx<AVRC_SUB_TYPE_LEN)
+ {
+ msg.sub.subunit_type[xx] = *p_data++ >> AVRC_SUBTYPE_SHIFT;
+ if (msg.sub.subunit_type[xx] == AVRC_SUB_PANEL)
+ msg.sub.panel = TRUE;
+ xx++;
+ }
+ }
break;
- }
- p_data += AVRC_AVC_HDR_SIZE; /* skip the first 3 bytes: ctype, subunit*, opcode */
- AVRC_BE_STREAM_TO_CO_ID(p_msg->company_id, p_data);
- p_msg->p_vendor_data = p_data;
- p_msg->vendor_len = p_pkt->len - (p_data - p_begin);
-#if (AVRC_METADATA_INCLUDED == TRUE)
- UINT8 drop_code = 0;
- if (p_msg->company_id == AVRC_CO_METADATA)
- {
- /* Validate length for metadata message */
- if (p_pkt->len < (AVRC_VENDOR_HDR_SIZE + AVRC_MIN_META_HDR_SIZE))
+ case AVRC_OP_VENDOR:
+ p_data = (UINT8 *)(p_pkt+1) + p_pkt->offset;
+ p_begin = p_data;
+ if (p_pkt->len < AVRC_VENDOR_HDR_SIZE) /* 6 = ctype, subunit*, opcode & CO_ID */
{
if (cr == AVCT_CMD)
reject = TRUE;
@@ -697,117 +687,144 @@ static void avrc_msg_cback(UINT8 handle, UINT8 label, UINT8 cr,
drop = TRUE;
break;
}
+ p_data += AVRC_AVC_HDR_SIZE; /* skip the first 3 bytes: ctype, subunit*, opcode */
+ AVRC_BE_STREAM_TO_CO_ID(p_msg->company_id, p_data);
+ p_msg->p_vendor_data = p_data;
+ p_msg->vendor_len = p_pkt->len - (p_data - p_begin);
- /* Check+handle fragmented messages */
+#if (AVRC_METADATA_INCLUDED == TRUE)
+ UINT8 drop_code = 0;
drop_code = avrc_proc_far_msg(handle, label, cr, &p_pkt, p_msg);
if (drop_code > 0)
drop = TRUE;
- }
- if (drop_code > 0)
- {
- if (drop_code != 4)
- do_free = FALSE;
-#if (BT_USE_TRACES == TRUE)
- switch (drop_code)
+ if (drop_code > 0)
{
- case 1:
- p_drop_msg = "sent_frag";
- break;
- case 2:
- p_drop_msg = "req_cont";
- break;
- case 3:
- p_drop_msg = "sent_frag3";
- break;
- case 4:
- p_drop_msg = "sent_frag_free";
- break;
- default:
- p_drop_msg = "sent_fragd";
- }
+ if (drop_code != 4)
+ do_free = FALSE;
+#if (BT_USE_TRACES == TRUE)
+ switch (drop_code)
+ {
+ case 1:
+ p_drop_msg = "sent_frag";
+ break;
+ case 2:
+ p_drop_msg = "req_cont";
+ break;
+ case 3:
+ p_drop_msg = "sent_frag3";
+ break;
+ case 4:
+ p_drop_msg = "sent_frag_free";
+ break;
+ default:
+ p_drop_msg = "sent_fragd";
+ }
#endif
- }
+ }
#endif /* (AVRC_METADATA_INCLUDED == TRUE) */
- break;
+ break;
- case AVRC_OP_PASS_THRU:
- if (p_pkt->len < 5) /* 3 bytes: ctype, subunit*, opcode & op_id & len */
- {
- if (cr == AVCT_CMD)
- reject = TRUE;
+ case AVRC_OP_PASS_THRU:
+ if (p_pkt->len < 5) /* 3 bytes: ctype, subunit*, opcode & op_id & len */
+ {
+ if (cr == AVCT_CMD)
+ reject = TRUE;
+ else
+ drop = TRUE;
+ break;
+ }
+ p_data += AVRC_AVC_HDR_SIZE; /* skip the first 3 bytes: ctype, subunit*, opcode */
+ msg.pass.op_id = (AVRC_PASS_OP_ID_MASK & *p_data);
+ if (AVRC_PASS_STATE_MASK & *p_data)
+ msg.pass.state = TRUE;
else
- drop = TRUE;
+ msg.pass.state = FALSE;
+ p_data++;
+ msg.pass.pass_len = *p_data++;
+ if (msg.pass.pass_len != p_pkt->len - 5)
+ msg.pass.pass_len = p_pkt->len - 5;
+ if (msg.pass.pass_len)
+ msg.pass.p_pass_data = p_data;
+ else
+ msg.pass.p_pass_data = NULL;
break;
- }
- p_data += AVRC_AVC_HDR_SIZE; /* skip the first 3 bytes: ctype, subunit*, opcode */
- msg.pass.op_id = (AVRC_PASS_OP_ID_MASK & *p_data);
- if (AVRC_PASS_STATE_MASK & *p_data)
- msg.pass.state = TRUE;
- else
- msg.pass.state = FALSE;
- p_data++;
- msg.pass.pass_len = *p_data++;
- if (msg.pass.pass_len != p_pkt->len - 5)
- msg.pass.pass_len = p_pkt->len - 5;
- if (msg.pass.pass_len)
- msg.pass.p_pass_data = p_data;
- else
- msg.pass.p_pass_data = NULL;
- break;
- default:
- if ((avrc_cb.ccb[handle].control & AVRC_CT_TARGET) && (cr == AVCT_CMD))
- {
- /* reject unsupported opcode */
- reject = TRUE;
+ default:
+ if ((avrc_cb.ccb[handle].control & AVRC_CT_TARGET) && (cr == AVCT_CMD))
+ {
+ /* reject unsupported opcode */
+ reject = TRUE;
+ }
+ drop = TRUE;
+ break;
}
+ }
+ else /* drop the event */
+ {
drop = TRUE;
- break;
}
- }
- else /* drop the event */
- {
+
+ if (reject)
+ {
+ /* reject unsupported opcode */
+ p_rsp = avrc_copy_packet(p_pkt, AVRC_OP_REJ_MSG_LEN);
+ p_rsp_data = avrc_get_data_ptr(p_rsp);
+ *p_rsp_data = AVRC_RSP_REJ;
+#if (BT_USE_TRACES == TRUE)
+ p_drop_msg = "rejected";
+#endif
+ cr = AVCT_RSP;
drop = TRUE;
- }
+ }
- if (reject)
- {
- /* reject unsupported opcode */
- p_rsp = avrc_copy_packet(p_pkt, AVRC_OP_REJ_MSG_LEN);
- p_rsp_data = avrc_get_data_ptr(p_rsp);
- *p_rsp_data = AVRC_RSP_REJ;
+ if (p_rsp)
+ {
+ /* set to send response right away */
+ AVCT_MsgReq( handle, label, cr, p_rsp);
+ drop = TRUE;
+ }
+
+ if (drop == FALSE)
+ {
+ msg.hdr.opcode = opcode;
+ (*avrc_cb.ccb[handle].p_msg_cback)(handle, label, opcode, &msg);
+ }
#if (BT_USE_TRACES == TRUE)
- p_drop_msg = "rejected";
+ else
+ {
+ AVRC_TRACE_WARNING("avrc_msg_cback %s msg handle:%d, control:%d, cr:%d, opcode:x%x",
+ p_drop_msg,
+ handle, avrc_cb.ccb[handle].control, cr, opcode);
+ }
#endif
- cr = AVCT_RSP;
- drop = TRUE;
- }
- if (p_rsp)
- {
- /* set to send response right away */
- AVCT_MsgReq( handle, label, cr, p_rsp);
- drop = TRUE;
- }
- if (drop == FALSE)
- {
- msg.hdr.opcode = opcode;
- (*avrc_cb.ccb[handle].p_msg_cback)(handle, label, opcode, &msg);
+ if (do_free)
+ GKI_freebuf(p_pkt);
}
-#if (BT_USE_TRACES == TRUE)
else
{
- AVRC_TRACE_WARNING("avrc_msg_cback %s msg handle:%d, control:%d, cr:%d, opcode:x%x",
- p_drop_msg,
- handle, avrc_cb.ccb[handle].control, cr, opcode);
+ opcode = p_data[0];
+ AVRC_TRACE_DEBUG("opcode:%x, length:%x",opcode, p_pkt->len);
+ /*Do sanity Check here*/
+ if (cr == AVCT_CMD)
+ {
+ opcode = AVRC_OP_BROWSE;
+ msg.browse.browse_len = p_pkt->len;
+ AVRC_TRACE_DEBUG("Browsing length %x",msg.browse.browse_len);
+ /* Browse data remains same */
+ msg.browse.p_browse_data = (UINT8 *)(p_pkt+1) + p_pkt->offset;
+ (*avrc_cb.ccb[handle].p_msg_cback)(handle, label, opcode, &msg);
+ }
+ else
+ {
+ AVRC_TRACE_ERROR("### expect AVCT_CMD");
+ }
+ /*Free the packet as the same already got copied in BTA*/
+ GKI_freebuf(p_pkt);
}
-#endif
-
- if (do_free)
- GKI_freebuf(p_pkt);
}
@@ -1076,7 +1093,7 @@ UINT16 AVRC_MsgReq (UINT8 handle, UINT8 label, UINT8 ctype, BT_HDR *p_pkt)
}
else
{
- AVRC_TRACE_ERROR ("AVRC_MsgReq no buffers for fragmentation" );
+ AVRC_TRACE_ERROR("AVRC_MsgReq no buffers for fragmentation" );
GKI_freebuf(p_pkt);
return AVRC_NO_RESOURCES;
}
diff --git a/stack/avrc/avrc_bld_tg.c b/stack/avrc/avrc_bld_tg.c
index a9b1a2adf..c4dfcf81e 100644
--- a/stack/avrc/avrc_bld_tg.c
+++ b/stack/avrc/avrc_bld_tg.c
@@ -28,6 +28,10 @@
*****************************************************************************/
#if (AVRC_METADATA_INCLUDED == TRUE)
+#define EVT_AVAIL_PLAYER_CHANGE_RSP_LENGTH 1
+#define EVT_ADDR_PLAYER_CHANGE_RSP_LENGTH 5
+#define EVT_NOW_PLAYING_CHANGE_RSP_LENGTH 1
+
/*******************************************************************************
**
** Function avrc_bld_get_capability_rsp
@@ -639,6 +643,20 @@ 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_AVAL_PLAYERS_CHANGE:
+ len = EVT_AVAIL_PLAYER_CHANGE_RSP_LENGTH;
+ break;
+
+ case AVRC_EVT_ADDR_PLAYER_CHANGE:
+ UINT16_TO_BE_STREAM(p_data,p_rsp->param.addr_player.player_id);
+ UINT16_TO_BE_STREAM(p_data,p_rsp->param.addr_player.uid_counter);
+ len = EVT_ADDR_PLAYER_CHANGE_RSP_LENGTH;
+ break;
+
+ case AVRC_EVT_NOW_PLAYING_CHANGE:
+ len = EVT_NOW_PLAYING_CHANGE_RSP_LENGTH;
+ break;
+
default:
status = AVRC_STS_BAD_PARAM;
AVRC_TRACE_ERROR("unknown event_id");
@@ -671,6 +689,58 @@ static tAVRC_STS avrc_bld_next_rsp (tAVRC_RSP *p_rsp, BT_HDR *p_pkt)
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, if the response is build successfully
+** Otherwise, the error code.
+**
+******************************************************************************/
+static tAVRC_STS avrc_bld_set_address_player_rsp(tAVRC_RSP *p_rsp, BT_HDR *p_pkt)
+{
+ UINT8 *p_data, *p_start;
+ tAVRC_STS status = AVRC_STS_NO_ERROR;
+
+ AVRC_TRACE_API(" avrc_bld_set_address_player_rsp");
+ p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
+ /* To calculate length */
+ 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 status;
+}
+
+/*****************************************************************************
+**
+** 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
+** Otherwise, the error code.
+**
+******************************************************************************/
+static tAVRC_STS avrc_bld_play_item_rsp(tAVRC_RSP *p_rsp, BT_HDR *p_pkt)
+{
+ UINT8 *p_data, *p_start;
+ tAVRC_STS status = AVRC_STS_NO_ERROR;
+
+ AVRC_TRACE_API(" avrc_bld_play_item_rsp");
+ p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
+ /* To calculate length */
+ 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 status;
+}
+
/*******************************************************************************
**
** Function avrc_bld_group_navigation_rsp
@@ -699,6 +769,256 @@ tAVRC_STS avrc_bld_group_navigation_rsp (UINT16 navi_id, BT_HDR *p_pkt)
return AVRC_STS_NO_ERROR;
}
+/*****************************************************************************
+**
+** Function avrc_bld_folder_item_values_rsp
+**
+** Description This function builds the folder item response.
+**
+** Returns AVRC_STS_NO_ERROR,if the response is built successfully
+** otherwise error code
+**
+******************************************************************************/
+static tAVRC_STS avrc_bld_folder_item_values_rsp(tAVRC_GET_ITEMS_RSP *p_rsp, BT_HDR *p_pkt )
+{
+ UINT8 *p_data, *p_start, *p_length, *p_media_element_len;
+ UINT8 *item_length;
+ UINT16 itemlength, param_length;
+ UINT16 length = 0, item_numb = 0, i, xx, media_attr_count;
+
+ AVRC_TRACE_DEBUG(" avrc_bld_folder_item_values_rsp offset :x%x", p_pkt->offset);
+ p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
+ /* As per AVRCP spec, first byte of response is PDU ID
+ * and Response does not have any opcode
+ */
+ p_data = p_start;
+ /*First OCT carry PDU information */
+ *p_data++ = p_rsp->pdu;
+
+ /* Refer Media Play list AVRCP 1.5 22.19 (Get Folder Items)
+ * Mark a pointer to be filled once length is calculated at last
+ */
+ p_length = p_data;
+
+ /*increment to adjust length*/
+ p_data = p_data + 2;
+ /*Status is checked in Btif layer*/
+ *p_data++ = p_rsp->status;
+ if(p_rsp->status != AVRC_STS_NO_ERROR)
+ {
+ //TODO Response
+ AVRC_TRACE_ERROR(" ### Folder_item_values response error");
+ return p_rsp->status;
+ }
+ /*UID Counter OCT 4 and 5*/
+ UINT16_TO_BE_STREAM(p_data, p_rsp->uid_counter);
+ /*Number of Items OCT 6 and 7*/
+ item_numb = p_rsp->item_count;
+ UINT16_TO_BE_STREAM(p_data, p_rsp->item_count);
+ param_length = 0;
+ for (i = 0; i < item_numb; i++)
+ {
+ itemlength = 0;
+ switch(p_rsp->p_item_list[i].item_type)
+ {
+ case AVRC_ITEM_PLAYER:
+ UINT8_TO_BE_STREAM(p_data, p_rsp->p_item_list[i].item_type);
+ itemlength = 28 + p_rsp->p_item_list[i].u.player.name.str_len;
+ UINT16_TO_BE_STREAM(p_data, itemlength);
+ UINT16_TO_BE_STREAM(p_data, p_rsp->p_item_list[i].u.player.player_id);
+ UINT8_TO_BE_STREAM(p_data, p_rsp->p_item_list[i].u.player.major_type);
+ UINT32_TO_BE_STREAM(p_data, p_rsp->p_item_list[i].u.player.sub_type);
+ UINT8_TO_BE_STREAM(p_data, p_rsp->p_item_list[i].u.player.play_status);
+ ARRAY_TO_BE_STREAM(p_data, p_rsp->p_item_list[i].u.player.features,\
+ AVRC_FEATURE_MASK_SIZE);
+ UINT16_TO_BE_STREAM(p_data, p_rsp->p_item_list[i].u.player.name.charset_id);
+ UINT16_TO_BE_STREAM(p_data, p_rsp->p_item_list[i].u.player.name.str_len);
+ ARRAY_TO_BE_STREAM(p_data, p_rsp->p_item_list[i].u.player.name.p_str,\
+ p_rsp->p_item_list[i].u.player.name.str_len);
+ break;
+ case AVRC_ITEM_FOLDER:
+ UINT8_TO_BE_STREAM(p_data, p_rsp->p_item_list[i].item_type);
+ itemlength = 14 + p_rsp->p_item_list[i].u.folder.name.str_len;
+ UINT16_TO_BE_STREAM(p_data, itemlength);
+ ARRAY_TO_BE_STREAM(p_data, p_rsp->p_item_list[i].u.folder.uid ,AVRC_UID_SIZE);
+ UINT8_TO_BE_STREAM(p_data, p_rsp->p_item_list[i].u.folder.type);
+ UINT8_TO_BE_STREAM(p_data, p_rsp->p_item_list[i].u.folder.playable);
+ UINT16_TO_BE_STREAM(p_data, p_rsp->p_item_list[i].u.folder.name.charset_id);
+ UINT16_TO_BE_STREAM(p_data, p_rsp->p_item_list[i].u.folder.name.str_len);
+ ARRAY_TO_BE_STREAM(p_data, p_rsp->p_item_list[i].u.folder.name.p_str,\
+ p_rsp->p_item_list[i].u.folder.name.str_len);
+ break;
+ case AVRC_ITEM_MEDIA:
+ UINT8_TO_BE_STREAM(p_data, p_rsp->p_item_list[i].item_type);
+ p_media_element_len = p_data;
+ itemlength = 13 + p_rsp->p_item_list[i].u.media.name.str_len;
+ p_data = p_data + 2; /* for length */
+ ARRAY_TO_BE_STREAM(p_data, p_rsp->p_item_list[i].u.media.uid ,AVRC_UID_SIZE);
+ UINT8_TO_BE_STREAM(p_data, p_rsp->p_item_list[i].u.media.type);
+ UINT16_TO_BE_STREAM(p_data, p_rsp->p_item_list[i].u.media.name.charset_id);
+ UINT16_TO_BE_STREAM(p_data, p_rsp->p_item_list[i].u.media.name.str_len);
+ ARRAY_TO_BE_STREAM(p_data, p_rsp->p_item_list[i].u.media.name.p_str,\
+ p_rsp->p_item_list[i].u.media.name.str_len);
+ UINT8_TO_BE_STREAM(p_data, p_rsp->p_item_list[i].u.media.attr_count);
+ media_attr_count = p_rsp->p_item_list[i].u.media.attr_count;
+ itemlength += 1; /* for attribute count */
+ for (xx = 0; xx < media_attr_count; xx++)
+ {
+ itemlength += 8 + p_rsp->p_item_list[i].u.media.p_attr_list[xx].name.str_len;
+ UINT32_TO_BE_STREAM(p_data,\
+ p_rsp->p_item_list[i].u.media.p_attr_list[xx].attr_id);
+ UINT16_TO_BE_STREAM(p_data,\
+ p_rsp->p_item_list[i].u.media.p_attr_list[xx].name.charset_id);
+ UINT16_TO_BE_STREAM(p_data,\
+ p_rsp->p_item_list[i].u.media.p_attr_list[xx].name.str_len);
+ ARRAY_TO_BE_STREAM(p_data,\
+ p_rsp->p_item_list[i].u.media.p_attr_list[xx].name.p_str,\
+ p_rsp->p_item_list[i].u.media.p_attr_list[xx].name.str_len);
+ }
+ UINT16_TO_BE_STREAM(p_media_element_len, itemlength);
+ break;
+ }
+ param_length += itemlength + 3; /* 3 to accommodate item_len and item_type */
+ }
+ param_length = param_length + 5; //Add explicit 5, 2 num items+ 2UID Counter + 1 status counter
+ UINT16_TO_BE_STREAM(p_length, param_length);
+ p_pkt->len = p_data - p_start;
+ return AVRC_STS_NO_ERROR;
+}
+
+/**************************************************************************************
+**
+** Function avrc_bld_change_path_rsp
+**
+** Description
+**
+** Returns
+**
+************************************************************************************/
+static tAVRC_STS avrc_bld_change_path_rsp (tAVRC_CHG_PATH_RSP *p_rsp, BT_HDR *p_pkt )
+{
+ UINT8 *p_data, *p_start;
+ UINT16 param_len; /* parameter length feild of Rsp */
+ UINT8 folder_index = 0;
+
+
+ AVRC_TRACE_DEBUG("avrc_bld_change_path_rsp offset :x%x", p_pkt->offset);
+
+ p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
+ p_data = p_start;
+ UINT8_TO_BE_STREAM(p_data, p_rsp->pdu);
+ param_len = 5; /* refer spec */
+ UINT16_TO_BE_STREAM(p_data, param_len);
+ UINT8_TO_BE_STREAM(p_data, p_rsp->status);
+ UINT32_TO_BE_STREAM(p_data, p_rsp->num_items);
+ p_pkt->len = p_data - p_start;
+ AVRC_TRACE_DEBUG("length = %d",p_pkt->len);
+ return AVRC_STS_NO_ERROR ;
+}
+
+/**************************************************************************************
+**
+** Function avrc_bld_set_browse_player_rsp
+**
+** Description
+**
+** Returns
+**
+************************************************************************************/
+static tAVRC_STS avrc_bld_set_browse_player_rsp (tAVRC_SET_BR_PLAYER_RSP *p_rsp, BT_HDR *p_pkt )
+{
+ UINT8 *p_data, *p_start;
+ UINT16 param_len_folder_name = 0;
+ UINT16 param_len; /* parameter length feild of Rsp */
+ UINT8 folder_index = 0;
+
+ AVRC_TRACE_DEBUG("avrc_bld_set_browse_player_rsp offset :x%x", p_pkt->offset);
+
+ p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
+ p_data = p_start;
+ UINT8_TO_BE_STREAM(p_data, p_rsp->pdu);
+
+ for(folder_index = 0; folder_index < p_rsp->folder_depth; folder_index++)
+ {
+ param_len_folder_name += p_rsp->p_folders[folder_index].str_len;
+ }
+ param_len = 10 + (p_rsp->folder_depth * 2) + param_len_folder_name; /* refer spec */
+
+ UINT16_TO_BE_STREAM(p_data, param_len);
+ UINT8_TO_BE_STREAM(p_data, p_rsp->status);
+ UINT16_TO_BE_STREAM(p_data, p_rsp->uid_counter);
+ UINT32_TO_BE_STREAM(p_data, p_rsp->num_items);
+ UINT16_TO_BE_STREAM(p_data, p_rsp->charset_id);
+ UINT8_TO_BE_STREAM(p_data, p_rsp->folder_depth);
+
+ for(folder_index = 0; folder_index < p_rsp->folder_depth; folder_index++)
+ {
+ UINT16_TO_BE_STREAM(p_data, p_rsp->p_folders[folder_index].str_len);
+ ARRAY_TO_BE_STREAM(p_data,p_rsp->p_folders[folder_index].p_str, \
+ p_rsp->p_folders[folder_index].str_len);
+ }
+ p_pkt->len = p_data - p_start;
+ AVRC_TRACE_DEBUG("length = %d",p_pkt->len);
+ return AVRC_STS_NO_ERROR ;
+}
+
+/*******************************************************************************
+**
+** Function avrc_bld_get_item_attrs_rsp
+**
+** Description This function builds the Get Item Attributes
+** response.
+**
+** Returns AVRC_STS_NO_ERROR, if the response is built successfully
+** Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_get_item_attrs_rsp (tAVRC_GET_ATTRS_RSP *p_rsp, BT_HDR *p_pkt)
+{
+ UINT8 *p_data, *p_start;
+ UINT16 param_len;
+ UINT8 xx;
+
+ AVRC_TRACE_API("avrc_bld_get_item_attrs_rsp");
+ if (!p_rsp->p_attr_list)
+ {
+ AVRC_TRACE_ERROR("avrc_bld_get_item_attrs_rsp NULL parameter");
+ return AVRC_STS_BAD_PARAM;
+ }
+
+ /* get the existing length, if any, and also the num attributes */
+ p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
+ p_data = p_start;
+ UINT8_TO_BE_STREAM(p_data, p_rsp->pdu);
+
+ param_len = 2; /* for status and num_attr*/
+ for(xx = 0; xx < p_rsp->attr_count; xx++)
+ {
+ /* 8 for attr_id, char_set_id, attr_value_len */
+ param_len = param_len + 8 + p_rsp->p_attr_list[xx].name.str_len;
+ }
+ AVRC_TRACE_API(" param_len = %d ", param_len);
+ UINT16_TO_BE_STREAM(p_data, param_len);
+ UINT8_TO_BE_STREAM(p_data, p_rsp->status);
+ UINT8_TO_BE_STREAM(p_data, p_rsp->attr_count);
+
+ for (xx=0; xx < p_rsp->attr_count; xx++)
+ {
+ if ( !p_rsp->p_attr_list[xx].name.p_str )
+ {
+ p_rsp->p_attr_list[xx].name.str_len = 0;
+ }
+ UINT32_TO_BE_STREAM(p_data, p_rsp->p_attr_list[xx].attr_id);
+ UINT16_TO_BE_STREAM(p_data, p_rsp->p_attr_list[xx].name.charset_id);
+ UINT16_TO_BE_STREAM(p_data, p_rsp->p_attr_list[xx].name.str_len);
+ ARRAY_TO_BE_STREAM(p_data, p_rsp->p_attr_list[xx].name.p_str, \
+ p_rsp->p_attr_list[xx].name.str_len);
+ }
+ p_pkt->len = (p_data - p_start);
+ return AVRC_STS_NO_ERROR;
+}
+
+
/*******************************************************************************
**
** Function avrc_bld_rejected_rsp
@@ -728,6 +1048,34 @@ static tAVRC_STS avrc_bld_rejected_rsp( tAVRC_RSP *p_rsp, BT_HDR *p_pkt )
/*******************************************************************************
**
+** Function avrc_bld_browse_rejected_rsp
+**
+** Description This function builds the Browse Reject response.
+**
+** Returns AVRC_STS_NO_ERROR, if the response is built successfully
+** Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_browse_rejected_rsp (tAVRC_RSP *p_rsp, BT_HDR *p_pkt)
+{
+ UINT8 *p_data, *p_start;
+
+ AVRC_TRACE_API("avrc_bld_browse_rejected_rsp: status=%d, pdu:x%x, offset=%d", p_rsp->status,
+ p_rsp->pdu, p_pkt->offset);
+
+ p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
+ p_data = p_start;
+ *p_data++ = p_rsp->pdu;
+
+ UINT16_TO_BE_STREAM(p_data, 1); //Parameter length
+ UINT8_TO_BE_STREAM(p_data, p_rsp->status);
+ p_pkt->len = p_data - p_start;
+ AVRC_TRACE_DEBUG("Browse rejected rsp length=%d", p_pkt->len);
+ return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+**
** Function avrc_bld_init_rsp_buffer
**
** Description This function initializes the response buffer based on PDU
@@ -902,6 +1250,14 @@ 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;
}
if (alloc && (status != AVRC_STS_NO_ERROR) )
@@ -913,5 +1269,110 @@ tAVRC_STS AVRC_BldResponse( UINT8 handle, tAVRC_RESPONSE *p_rsp, BT_HDR **pp_pkt
return status;
}
+/*******************************************************************************
+**
+** Function avrc_bld_init_browse_rsp_buffer
+**
+** Description This function initializes the response buffer based on PDU
+**
+** Returns NULL, if no GKI buffer or failure to build the message.
+** Otherwise, the GKI buffer that contains the initialized message.
+**
+*******************************************************************************/
+static BT_HDR *avrc_bld_init_browse_rsp_buffer(tAVRC_RESPONSE *p_rsp)
+{
+ UINT16 offset = AVCT_BROWSE_OFFSET;
+ UINT16 chnl = AVCT_DATA_BROWSE;
+ UINT16 len = AVRC_BROWSE_POOL_SIZE;
+ BT_HDR *p_pkt = NULL;
+
+ AVRC_TRACE_API("avrc_bld_init_browse_rsp_buffer ");
+ /* allocate and initialize the buffer */
+ p_pkt = (BT_HDR *)GKI_getbuf(len);
+
+ if (p_pkt != NULL)
+ {
+ p_pkt->layer_specific = chnl;
+ p_pkt->event = AVRC_OP_BROWSE; /* Browsing Opcode */
+ p_pkt->offset = offset;
+ }
+ else
+ {
+ AVRC_TRACE_ERROR("### browse_rsp_buffer BUFF not allocated");
+ }
+ return p_pkt;
+}
+
+/*******************************************************************************
+**
+** Function AVRC_BldBrowseResponse
+**
+** Description This function builds the given AVRCP response to the given
+** GKI buffer
+**
+** Returns AVRC_STS_NO_ERROR, if the response is built successfully
+** Otherwise, the error code.
+**
+*******************************************************************************/
+tAVRC_STS AVRC_BldBrowseResponse( UINT8 handle, tAVRC_RESPONSE *p_rsp, BT_HDR **pp_pkt)
+{
+ tAVRC_STS status = AVRC_STS_BAD_PARAM;
+ BT_HDR *p_pkt;
+ BOOLEAN alloc = FALSE;
+
+ if (!p_rsp || !pp_pkt)
+ {
+ AVRC_TRACE_ERROR("### BldResponse error p_rsp=%p, pp_pkt=%p",
+ p_rsp, pp_pkt);
+ return AVRC_STS_BAD_PARAM;
+ }
+
+ if (*pp_pkt == NULL)
+ {
+ if ((*pp_pkt = avrc_bld_init_browse_rsp_buffer(p_rsp)) == NULL)
+ {
+ AVRC_TRACE_ERROR("### BldResponse: Failed to initialize response buffer");
+ return AVRC_STS_INTERNAL_ERR;
+ }
+ alloc = TRUE;
+ }
+ status = AVRC_STS_NO_ERROR;
+ p_pkt = *pp_pkt;
+
+ AVRC_TRACE_API("BldResponse: pdu=%x status=%x", p_rsp->rsp.pdu, p_rsp->rsp.status);
+ if (p_rsp->rsp.status != AVRC_STS_NO_ERROR)
+ {
+ AVRC_TRACE_ERROR("###ERROR AVRC_BldBrowseResponse");
+ return (avrc_bld_browse_rejected_rsp(&p_rsp->rsp, p_pkt));
+ }
+
+ switch (p_rsp->pdu)
+ {
+ case AVRC_PDU_GET_FOLDER_ITEMS:
+ status = avrc_bld_folder_item_values_rsp(&p_rsp->get_items, p_pkt);
+ break;
+
+ case AVRC_PDU_SET_BROWSED_PLAYER:
+ status = avrc_bld_set_browse_player_rsp(&p_rsp->br_player, p_pkt);
+ break;
+
+ case AVRC_PDU_CHANGE_PATH:
+ status = avrc_bld_change_path_rsp(&p_rsp->chg_path, p_pkt);
+ break;
+
+ case AVRC_PDU_GET_ITEM_ATTRIBUTES:
+ status = avrc_bld_get_item_attrs_rsp(&p_rsp->get_attrs, p_pkt);
+ break;
+ default :
+ break;
+ }
+ if (alloc && (status != AVRC_STS_NO_ERROR) )
+ {
+ GKI_freebuf(p_pkt);
+ *pp_pkt = NULL;
+ AVRC_TRACE_ERROR("### error status:%d",status);
+ }
+ return status;
+}
#endif /* (AVRC_METADATA_INCLUDED == TRUE)*/
diff --git a/stack/avrc/avrc_int.h b/stack/avrc/avrc_int.h
index 36bb0c5fa..feb2b0e99 100644
--- a/stack/avrc/avrc_int.h
+++ b/stack/avrc/avrc_int.h
@@ -42,6 +42,7 @@
/* Number of protocol elements in protocol element list. */
#define AVRC_NUM_PROTO_ELEMS 2
+#define AVRC_NUM_ADDL_PROTO_ELEMS 1
#ifndef AVRC_MIN_CMD_LEN
#define AVRC_MIN_CMD_LEN 20
diff --git a/stack/avrc/avrc_pars_tg.c b/stack/avrc/avrc_pars_tg.c
index 6e39c1c5a..b75ee907c 100644
--- a/stack/avrc/avrc_pars_tg.c
+++ b/stack/avrc/avrc_pars_tg.c
@@ -267,7 +267,31 @@ static tAVRC_STS avrc_pars_vendor_cmd(tAVRC_MSG_VENDOR *p_msg, tAVRC_COMMAND *p_
/* case AVRC_PDU_REQUEST_CONTINUATION_RSP: 0x40 */
/* case AVRC_PDU_ABORT_CONTINUATION_RSP: 0x41 */
+ case AVRC_PDU_SET_ADDRESSED_PLAYER:
+ if (len != 2)
+ {
+ status = AVRC_STS_NOT_FOUND;
+ AVRC_TRACE_ERROR("AVRC_PDU_SET_ADDRESSED_PLAYER: bad len");
+ }
+ else
+ {
+ BE_STREAM_TO_UINT16 (p_result->addr_player.player_id, p);
+ }
+ break;
+ case AVRC_PDU_PLAY_ITEM:
+ if (len != 11)
+ {
+ status = AVRC_STS_NOT_FOUND;
+ AVRC_TRACE_ERROR("AVRC_PDU_PLAY_ITEM: bad len");
+ }
+ else
+ {
+ BE_STREAM_TO_UINT8 (p_result->play_item.scope, p);
+ BE_STREAM_TO_UINT64(p_result->play_item.uid, p);
+ BE_STREAM_TO_UINT16 (p_result->play_item.uid_counter, p);
+ }
+ break;
default:
status = AVRC_STS_BAD_CMD;
break;
diff --git a/stack/avrc/avrc_sdp.c b/stack/avrc/avrc_sdp.c
index ba10c1c5a..96582110b 100644
--- a/stack/avrc/avrc_sdp.c
+++ b/stack/avrc/avrc_sdp.c
@@ -27,6 +27,7 @@
#include "avrc_api.h"
#include "avrc_int.h"
+
#ifndef SDP_AVRCP_1_4
#define SDP_AVRCP_1_4 FALSE
#endif
@@ -49,6 +50,9 @@ const tSDP_PROTOCOL_ELEM avrc_proto_list [] =
#if SDP_AVCTP_1_4 == TRUE
{UUID_PROTOCOL_AVCTP, 1, {AVCT_REV_1_4, 0} }
#else
+#if SDP_AVRCP_1_5 == TRUE
+ {UUID_PROTOCOL_AVCTP, 1, {AVCT_REV_1_4, 0} }
+#else
#if SDP_AVRCP_1_4 == TRUE
{UUID_PROTOCOL_AVCTP, 1, {AVCT_REV_1_3, 0} }
#else
@@ -59,8 +63,18 @@ const tSDP_PROTOCOL_ELEM avrc_proto_list [] =
#endif
#endif
#endif
+#endif
};
+#if SDP_AVRCP_1_5 == TRUE
+const tSDP_PROTO_LIST_ELEM avrc_add_proto_list [] =
+{
+ {AVRC_NUM_PROTO_ELEMS,
+ {
+ {UUID_PROTOCOL_L2CAP, 1, {AVCT_BR_PSM, 0} },
+ {UUID_PROTOCOL_AVCTP, 1, {AVCT_REV_1_4, 0} }}}
+};
+#else
#if SDP_AVRCP_1_4 == TRUE
const tSDP_PROTO_LIST_ELEM avrc_add_proto_list [] =
{
@@ -70,6 +84,7 @@ const tSDP_PROTO_LIST_ELEM avrc_add_proto_list [] =
{UUID_PROTOCOL_AVCTP, 1, {AVCT_REV_1_3, 0} }}}
};
#endif
+#endif
/******************************************************************************
@@ -242,6 +257,13 @@ UINT16 AVRC_AddRecord(UINT16 service_uuid, char *p_service_name,
count = 2;
}
#else
+#if SDP_AVRCP_1_5 == TRUE
+ if( service_uuid == UUID_SERVCLASS_AV_REMOTE_CONTROL )
+ {
+ class_list[1] = UUID_SERVCLASS_AV_REM_CTRL_CONTROL;
+ count = 2;
+ }
+#else
#if SDP_AVRCP_1_4 == TRUE
if( service_uuid == UUID_SERVCLASS_AV_REMOTE_CONTROL )
{
@@ -250,24 +272,35 @@ UINT16 AVRC_AddRecord(UINT16 service_uuid, char *p_service_name,
}
#endif
#endif
+#endif
result &= SDP_AddServiceClassIdList(sdp_handle, count, class_list);
/* add protocol descriptor list */
result &= SDP_AddProtocolList(sdp_handle, AVRC_NUM_PROTO_ELEMS, (tSDP_PROTOCOL_ELEM *)avrc_proto_list);
/* add profile descriptor list */
+#if SDP_AVRCP_1_5 == TRUE
+ /* additional protocol list to include browsing channel */
+ result &= SDP_AddAdditionProtoLists( sdp_handle, AVRC_NUM_ADDL_PROTO_ELEMS,
+ (tSDP_PROTO_LIST_ELEM *)avrc_add_proto_list);
+
+ result &= SDP_AddProfileDescriptorList(sdp_handle, UUID_SERVCLASS_AV_REMOTE_CONTROL, AVRC_REV_1_5);
+#else
#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);
- result &= SDP_AddProfileDescriptorList(sdp_handle, UUID_SERVCLASS_AV_REMOTE_CONTROL, AVRC_REV_1_4);
+ result &= SDP_AddProfileDescriptorList(sdp_handle, UUID_SERVCLASS_AV_REMOTE_CONTROL, AVRC_REV_1_5);
#else
#if AVRC_METADATA_INCLUDED == TRUE
+
result &= SDP_AddProfileDescriptorList(sdp_handle, UUID_SERVCLASS_AV_REMOTE_CONTROL, AVRC_REV_1_3);
+
#else
result &= SDP_AddProfileDescriptorList(sdp_handle, UUID_SERVCLASS_AV_REMOTE_CONTROL, AVRC_REV_1_0);
#endif
#endif
+#endif
/* add supported categories */
p = temp;
diff --git a/stack/avrc/avrc_utils.c b/stack/avrc/avrc_utils.c
index 432ecc0cd..9c9082f79 100644
--- a/stack/avrc/avrc_utils.c
+++ b/stack/avrc/avrc_utils.c
@@ -59,6 +59,8 @@ 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:
if (avc_type == AVRC_CMD_CTRL)
result=TRUE;
break;
diff --git a/stack/include/avct_api.h b/stack/include/avct_api.h
index c2713fdb4..5feb8c25d 100644
--- a/stack/include/avct_api.h
+++ b/stack/include/avct_api.h
@@ -271,6 +271,22 @@ extern UINT16 AVCT_GetPeerMtu (UINT8 handle);
*******************************************************************************/
extern UINT16 AVCT_MsgReq(UINT8 handle, UINT8 label, UINT8 cr, BT_HDR *p_msg);
+
+/*******************************************************************************
+**
+** Function avct_get_peer_addr_by_ccb
+**
+**
+** Description Return peer BD address on ccb index (or handle).
+**
+**
+**
+**
+** Returns BD Address.
+**
+*******************************************************************************/
+extern BOOLEAN avct_get_peer_addr_by_ccb (UINT8 idx, BD_ADDR addr);
+
#ifdef __cplusplus
}
#endif
diff --git a/stack/include/avrc_api.h b/stack/include/avrc_api.h
index 2198074d9..12601ad47 100644
--- a/stack/include/avrc_api.h
+++ b/stack/include/avrc_api.h
@@ -608,6 +608,21 @@ extern tAVRC_STS AVRC_BldCommand( tAVRC_COMMAND *p_cmd, BT_HDR **pp_pkt);
*******************************************************************************/
extern tAVRC_STS AVRC_BldResponse( UINT8 handle, tAVRC_RESPONSE *p_rsp, BT_HDR **pp_pkt);
+/*******************************************************************************
+**
+** Function AVRC_BldBrowseResponse
+**
+** Description This function builds the given AVRCP response to the given
+** GKI buffer
+**
+** Returns AVRC_STS_NO_ERROR, if the response is built successfully
+** Otherwise, the error code.
+**
+*******************************************************************************/
+tAVRC_STS AVRC_BldBrowseResponse( UINT8 handle, tAVRC_RESPONSE *p_rsp, BT_HDR **pp_pkt);
+
+
+
/**************************************************************************
**
** Function AVRC_IsValidAvcType
diff --git a/stack/include/avrc_defs.h b/stack/include/avrc_defs.h
index d6ff8a0b5..7d63a47b1 100644
--- a/stack/include/avrc_defs.h
+++ b/stack/include/avrc_defs.h
@@ -32,6 +32,7 @@
#define AVRC_REV_1_0 0x0100
#define AVRC_REV_1_3 0x0103
#define AVRC_REV_1_4 0x0104
+#define AVRC_REV_1_5 0x0105
#define AVRC_PACKET_LEN 512 /* Per the spec, you must support 512 byte RC packets */
@@ -839,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_ADDR_PLAYER_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)
@@ -1095,7 +1096,7 @@ typedef struct
UINT32 start_item;
UINT32 end_item;
UINT8 attr_count;
- UINT32 *p_attr_list;
+ UINT32 attrs[AVRC_MAX_ELEM_ATTR_SIZE];
} tAVRC_GET_ITEMS_CMD;
/* ChangePath */
@@ -1106,7 +1107,7 @@ typedef struct
UINT8 opcode; /* Op Code (assigned by AVRC_BldCommand according to pdu) */
UINT16 uid_counter;
UINT8 direction;
- tAVRC_UID folder_uid;
+ UINT64 folder_uid;
} tAVRC_CHG_PATH_CMD;
/* GetItemAttrs */
@@ -1116,10 +1117,10 @@ typedef struct
tAVRC_STS status;
UINT8 opcode; /* Op Code (assigned by AVRC_BldCommand according to pdu) */
UINT8 scope;
- tAVRC_UID uid;
+ UINT64 uid;
UINT16 uid_counter;
UINT8 attr_count;
- UINT32 *p_attr_list;
+ UINT32 attrs[AVRC_MAX_ELEM_ATTR_SIZE];
} tAVRC_GET_ATTRS_CMD;
/* Search */
@@ -1138,7 +1139,7 @@ typedef struct
tAVRC_STS status;
UINT8 opcode; /* Op Code (assigned by AVRC_BldCommand according to pdu) */
UINT8 scope;
- tAVRC_UID uid;
+ UINT64 uid;
UINT16 uid_counter;
} tAVRC_PLAY_ITEM_CMD;
@@ -1301,6 +1302,7 @@ typedef union
tAVRC_ADDR_PLAYER_PARAM addr_player;
UINT16 uid_counter;
UINT8 volume;
+ UINT8 evt;//For Available Player Changed Notification
} tAVRC_NOTIF_RSP_PARAM;
/* RegNotify */
diff --git a/stack/include/bt_types.h b/stack/include/bt_types.h
index 85d41bf47..4ea447eca 100644
--- a/stack/include/bt_types.h
+++ b/stack/include/bt_types.h
@@ -291,6 +291,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++;}
diff --git a/stack/include/sdp_api.h b/stack/include/sdp_api.h
index ff44bf5f6..98bdfafe4 100644
--- a/stack/include/sdp_api.h
+++ b/stack/include/sdp_api.h
@@ -729,6 +729,20 @@ BOOLEAN SDP_ConnClose (UINT32 handle);
*******************************************************************************/
BOOLEAN SDP_FindServiceUUIDInRec(tSDP_DISC_REC *p_rec, tBT_UUID *p_uuid);
+/*********************************************************************************
+**
+** Function SDP_Dev_Blacklisted_For_Avrcp15
+**
+** Description This function is called to know is local Avrcp Version
+** 1.3 as local Avrcp version is send as 1.3 for black listed
+** devices
+**
+** Returns TRUE if AVRCP local Avrcp Version 1.3 else FALSE
+**
+********************************************************************************/
+BOOLEAN SDP_Dev_Blacklisted_For_Avrcp15 (BD_ADDR addr);
+
+
#ifdef __cplusplus
}
#endif
diff --git a/stack/sdp/sdp_api.c b/stack/sdp/sdp_api.c
index 6e84ded80..ee41ff272 100644
--- a/stack/sdp/sdp_api.c
+++ b/stack/sdp/sdp_api.c
@@ -1270,3 +1270,18 @@ UINT8 SDP_SetTraceLevel (UINT8 new_level)
return(sdp_cb.trace_level);
}
+
+/****************************************************************************
+**
+** Function SDP_Dev_Blacklisted_For_Avrcp15
+**
+** Description This function is called to check if Remote device
+** is blacklisted for Avrcp version.
+**
+** Returns BOOLEAN
+**
+*******************************************************************************/
+BOOLEAN SDP_Dev_Blacklisted_For_Avrcp15 (BD_ADDR addr)
+{
+ return sdp_dev_blacklisted_for_avrcp15 (addr);
+}
diff --git a/stack/sdp/sdp_server.c b/stack/sdp/sdp_server.c
index 5dd6b92c3..73715fc8f 100644
--- a/stack/sdp/sdp_server.c
+++ b/stack/sdp/sdp_server.c
@@ -46,6 +46,26 @@
#define SDP_MAX_SERVICE_RSPHDR_LEN 12
#define SDP_MAX_SERVATTR_RSPHDR_LEN 10
#define SDP_MAX_ATTR_RSPHDR_LEN 10
+#define AVRCP_VERSION_POSITION 7
+#define SDP_AVRCP_PROFILE_DESC_LENGTH 8
+#define AVRCP_SUPPORTED_FEATURES_POSITION 1
+#define AVRCP_BROWSE_SUPPORT_BITMASK 0x40
+
+/* Few remote device does not understand AVRCP version greater
+ * than 1.3 and falls back to 1.0, we would like to blacklist
+ * and send AVRCP versio as 1.3.
+ */
+static const UINT8 sdp_black_list_prefix[][3] = {{0x00, 0x1D, 0xBA}, /* JVC carkit */
+ {0x64, 0xD4, 0xBD}, /* Honda handsfree carkit */
+ {0x00, 0x06, 0xF7}, /* Denso carkit */
+ {0x00, 0x1E, 0xB2}, /* AVN 3.0 Hyundai*/
+ {0x00, 0x0E, 0x9F}, /* Porshe car kit */
+ {0x00, 0x13, 0x7B}, /* BYOM Opel*/
+ {0x68, 0x84, 0x70}, /* KIA MOTOR*/
+ {0x00, 0x54, 0xAF}, /* Chrysler*/
+ {0x04, 0x88, 0xE2}, /* BeatsStudio Wireless*/
+ {0xA0, 0x14, 0x3D}, /* VW Sharen*/
+ {0xE0, 0x75, 0x0A} /* VW GOLF*/};
/********************************************************************************/
/* L O C A L F U N C T I O N P R O T O T Y P E S */
@@ -101,6 +121,92 @@ static void process_service_search_attr_req (tCONN_CB *p_ccb, UINT16 trans_num,
#define SDP_TEXT_BAD_MAX_RECORDS_LIST NULL
#endif
+/****************************************************************************
+**
+** Function sdp_dev_blacklisted_for_avrcp15
+**
+** Description This function is called to check if Remote device
+** is blacklisted for Avrcp version.
+**
+** Returns BOOLEAN
+**
+*******************************************************************************/
+BOOLEAN sdp_dev_blacklisted_for_avrcp15 (BD_ADDR addr)
+{
+ int blacklistsize = 0;
+ int i =0;
+
+ blacklistsize = sizeof(sdp_black_list_prefix)/sizeof(sdp_black_list_prefix[0]);
+ for (i=0; i < blacklistsize; i++)
+ {
+ if (0 == memcmp(sdp_black_list_prefix[i], addr, 3))
+ {
+ SDP_TRACE_ERROR("SDP Avrcp Version Black List Device");
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/*************************************************************************************
+**
+** Function sdp_fallback_avrcp_version
+**
+** Description Checks if UUID is AV Remote Control, attribute id
+** is Profile descriptor list and remote BD address
+** matches device blacklist, change Avrcp version to 1.3
+**
+** Returns BOOLEAN
+**
+***************************************************************************************/
+BOOLEAN sdp_fallback_avrcp_version (tSDP_ATTRIBUTE *p_attr, BD_ADDR remote_address)
+{
+ if ((p_attr->id == ATTR_ID_BT_PROFILE_DESC_LIST) &&
+ (p_attr->len >= SDP_AVRCP_PROFILE_DESC_LENGTH))
+ {
+ /* As per current DB implementation UUID is condidered as 16 bit */
+ if (((p_attr->value_ptr[3] << 8) | (p_attr->value_ptr[4])) ==
+ UUID_SERVCLASS_AV_REMOTE_CONTROL)
+ {
+ if (sdp_dev_blacklisted_for_avrcp15 (remote_address))
+ {
+ p_attr->value_ptr[AVRCP_VERSION_POSITION] = 0x03; // Update AVRCP version as 1.3
+ SDP_TRACE_ERROR("SDP Change AVRCP Version = 0x%x",
+ p_attr->value_ptr[AVRCP_VERSION_POSITION]);
+ return TRUE;
+ }
+ }
+ }
+ return FALSE;
+}
+
+/*************************************************************************************
+**
+** Function sdp_reset_avrcp_browsing_bit
+**
+** Description Checks if Service Class ID is AV Remote Control TG, attribute id
+** is Supported features and remote BD address
+** matches device blacklist, reset Browsing Bit
+**
+** Returns BOOLEAN
+**
+***************************************************************************************/
+BOOLEAN sdp_reset_avrcp_browsing_bit (tSDP_ATTRIBUTE attr, tSDP_ATTRIBUTE *p_attr,
+BD_ADDR remote_address)
+{
+ if ((p_attr->id == ATTR_ID_SUPPORTED_FEATURES) && (attr.id == ATTR_ID_SERVICE_CLASS_ID_LIST) &&
+ (((attr.value_ptr[1] << 8) | (attr.value_ptr[2])) == UUID_SERVCLASS_AV_REM_CTRL_TARGET))
+ {
+ if (sdp_dev_blacklisted_for_avrcp15 (remote_address))
+ {
+ SDP_TRACE_ERROR("Reset Browse feature bitmask");
+ p_attr->value_ptr[AVRCP_SUPPORTED_FEATURES_POSITION] &= ~AVRCP_BROWSE_SUPPORT_BITMASK;
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
/*******************************************************************************
**
** Function sdp_server_handle_client_req
@@ -328,6 +434,8 @@ static void process_service_attr_req (tCONN_CB *p_ccb, UINT16 trans_num,
tSDP_ATTRIBUTE *p_attr;
BT_HDR *p_buf;
BOOLEAN is_cont = FALSE;
+ BOOLEAN is_avrcp_fallback = FALSE;
+ BOOLEAN is_avrcp_browse_bit_reset = FALSE;
UINT16 attr_len;
/* Extract the record handle */
@@ -436,6 +544,12 @@ static void process_service_attr_req (tCONN_CB *p_ccb, UINT16 trans_num,
if (p_attr)
{
+#if SDP_AVRCP_1_5 == TRUE
+ /* Check for UUID Remote Control and Remote BD address */
+ is_avrcp_fallback = sdp_fallback_avrcp_version (p_attr, p_ccb->device_address);
+ is_avrcp_browse_bit_reset = sdp_reset_avrcp_browsing_bit(
+ p_rec->attribute[1], p_attr, p_ccb->device_address);
+#endif
/* Check if attribute fits. Assume 3-byte value type/length */
rem_len = max_list_len - (INT16) (p_rsp - &p_ccb->rsp_list[0]);
@@ -488,8 +602,36 @@ static void process_service_attr_req (tCONN_CB *p_ccb, UINT16 trans_num,
xx--;
}
+ if (is_avrcp_fallback)
+ {
+ /* Update AVRCP version back to 1.5 */
+ p_attr->value_ptr[AVRCP_VERSION_POSITION] = 0x05;
+ is_avrcp_fallback = FALSE;
+ }
+ if (is_avrcp_browse_bit_reset)
+ {
+ /* Restore Browsing bit */
+ SDP_TRACE_ERROR("Restore Browsing bit");
+ p_attr->value_ptr[AVRCP_SUPPORTED_FEATURES_POSITION]
+ |= AVRCP_BROWSE_SUPPORT_BITMASK;
+ is_avrcp_browse_bit_reset = FALSE;
+ }
}
}
+ if (is_avrcp_fallback)
+ {
+ /* Update AVRCP version back to 1.5 */
+ p_attr->value_ptr[AVRCP_VERSION_POSITION] = 0x05;
+ is_avrcp_fallback = FALSE;
+ }
+ if (is_avrcp_browse_bit_reset)
+ {
+ /* Restore Browsing bit */
+ SDP_TRACE_ERROR("Restore Browsing bit");
+ p_attr->value_ptr[AVRCP_SUPPORTED_FEATURES_POSITION]
+ |= AVRCP_BROWSE_SUPPORT_BITMASK;
+ is_avrcp_browse_bit_reset = FALSE;
+ }
/* If all the attributes have been accomodated in p_rsp,
reset next_attr_index */
if (xx == attr_seq.num_attr)
@@ -595,6 +737,8 @@ static void process_service_search_attr_req (tCONN_CB *p_ccb, UINT16 trans_num,
tSDP_ATTRIBUTE *p_attr;
BT_HDR *p_buf;
BOOLEAN maxxed_out = FALSE, is_cont = FALSE;
+ BOOLEAN is_avrcp_fallback = FALSE;
+ BOOLEAN is_avrcp_browse_bit_reset = FALSE;
UINT8 *p_seq_start;
UINT16 seq_len, attr_len;
UNUSED(p_req_end);
@@ -719,6 +863,12 @@ static void process_service_search_attr_req (tCONN_CB *p_ccb, UINT16 trans_num,
if (p_attr)
{
+#if SDP_AVRCP_1_5 == TRUE
+ /* Check for UUID Remote Control and Remote BD address */
+ is_avrcp_fallback = sdp_fallback_avrcp_version (p_attr, p_ccb->device_address);
+ is_avrcp_browse_bit_reset = sdp_reset_avrcp_browsing_bit(
+ p_rec->attribute[1], p_attr, p_ccb->device_address);
+#endif
/* Check if attribute fits. Assume 3-byte value type/length */
rem_len = max_list_len - (INT16) (p_rsp - &p_ccb->rsp_list[0]);
@@ -776,8 +926,36 @@ static void process_service_search_attr_req (tCONN_CB *p_ccb, UINT16 trans_num,
xx--;
}
+ if (is_avrcp_fallback)
+ {
+ /* Update AVRCP version back to 1.5 */
+ p_attr->value_ptr[AVRCP_VERSION_POSITION] = 0x05;
+ is_avrcp_fallback = FALSE;
+ }
+ if (is_avrcp_browse_bit_reset)
+ {
+ /* Restore Browsing bit */
+ SDP_TRACE_ERROR("Restore Browsing bit");
+ p_attr->value_ptr[AVRCP_SUPPORTED_FEATURES_POSITION]
+ |= AVRCP_BROWSE_SUPPORT_BITMASK;
+ is_avrcp_browse_bit_reset = FALSE;
+ }
}
}
+ if (is_avrcp_fallback)
+ {
+ /* Update AVRCP version back to 1.5 */
+ p_attr->value_ptr[AVRCP_VERSION_POSITION] = 0x05;
+ is_avrcp_fallback = FALSE;
+ }
+ if (is_avrcp_browse_bit_reset)
+ {
+ /* Restore Browsing bit */
+ SDP_TRACE_ERROR("Restore Browsing bit");
+ p_attr->value_ptr[AVRCP_SUPPORTED_FEATURES_POSITION]
+ |= AVRCP_BROWSE_SUPPORT_BITMASK;
+ is_avrcp_browse_bit_reset = FALSE;
+ }
/* Go back and put the type and length into the buffer */
if (p_ccb->cont_info.last_attr_seq_desc_sent == FALSE)
diff --git a/stack/sdp/sdpint.h b/stack/sdp/sdpint.h
index 262ac89f0..edb1412a2 100644
--- a/stack/sdp/sdpint.h
+++ b/stack/sdp/sdpint.h
@@ -310,6 +310,8 @@ extern void sdp_server_handle_client_req (tCONN_CB *p_ccb, BT_HDR *p_msg);
#define sdp_server_handle_client_req(p_ccb, p_msg)
#endif
+extern BOOLEAN sdp_dev_blacklisted_for_avrcp15 (BD_ADDR addr);
+
/* Functions provided by sdp_discovery.c
*/
#if SDP_CLIENT_ENABLED == TRUE