return;
}
- if (p_cb->features & BTA_AV_FEAT_RCTG)
- {
- /* listen to browsing channel when the connection is open,
- * if peer initiated AVRCP connection and local device supports browsing channel */
- if ((p_cb->features & BTA_AV_FEAT_BROWSE) && (p_cb->rcb[i].peer_features == 0))
- AVRC_OpenBrowse(p_data->rc_conn_chg.handle, AVCT_ACP);
- }
+ APPL_TRACE_DEBUG("%s local features %d peer features %d",
+ __func__, p_cb->features, p_cb->rcb[i].peer_features);
+
+ /* listen to browsing channel when the connection is open,
+ * if peer initiated AVRCP connection and local device supports browsing channel */
+ AVRC_OpenBrowse (p_data->rc_conn_chg.handle, AVCT_ACP);
if (p_cb->rcb[i].lidx == (BTA_AV_NUM_LINKS + 1) && shdl != 0)
{
bdcpy(rc_open.peer_addr, p_data->rc_conn_chg.peer_addr);
rc_open.peer_features = p_cb->rcb[i].peer_features;
rc_open.status = BTA_AV_SUCCESS;
- APPL_TRACE_DEBUG("local features:x%x peer_features:x%x", p_cb->features,
+ APPL_TRACE_DEBUG("%s local features:x%x peer_features:x%x", __func__, p_cb->features,
rc_open.peer_features);
if (rc_open.peer_features == 0)
{
(*p_cb->p_cback)(BTA_AV_RC_OPEN_EVT, (tBTA_AV *) &rc_open);
/* if local initiated AVRCP connection and both peer and locals device support
- * browsing channel, open the browsing channel now */
+ * browsing channel, open the browsing channel now
+ * TODO (sanketa): Some TG would not broadcast browse feature hence check inter-op. */
if ((p_cb->features & BTA_AV_FEAT_BROWSE) &&
(rc_open.peer_features & BTA_AV_FEAT_BROWSE) &&
((p_cb->rcb[i].status & BTA_AV_RC_ROLE_MASK) == BTA_AV_RC_ROLE_INT))
{
+ APPL_TRACE_DEBUG("%s opening AVRC Browse channel", __func__);
AVRC_OpenBrowse (p_data->rc_conn_chg.handle, AVCT_INT);
}
-
}
/*******************************************************************************
/*******************************************************************************
**
+** Function bta_av_rc_browse_close
+**
+** Description Empty placeholder.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_av_rc_browse_close (tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data)
+{
+ APPL_TRACE_WARNING("%s empty placeholder does nothing!", __func__);
+}
+
+/*******************************************************************************
+**
** Function bta_av_get_shdl
**
** Returns The index to p_scb[]
* expect BTA_AV_DEREG_COMP_EVT when deregister is complete */
for(xx=0; xx<BTA_AV_NUM_STRS; xx++)
{
- hdr.layer_specific = xx + 1;
- bta_av_api_deregister((tBTA_AV_DATA *)&hdr);
+ if (p_cb->p_scb[xx] != NULL)
+ {
+ hdr.layer_specific = xx + 1;
+ bta_av_api_deregister((tBTA_AV_DATA *)&hdr);
+ }
}
alarm_free(p_cb->link_signalling_timer);
*/
if (peer_rc_version >= AVRC_REV_1_3)
{
- /* get supported categories */
+ /* get supported features */
tSDP_DISC_ATTR *p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_SUPPORTED_FEATURES);
if (p_attr != NULL)
{
peer_features |= (BTA_AV_FEAT_ADV_CTRL);
if (categories & AVRC_SUPF_CT_APP_SETTINGS)
peer_features |= (BTA_AV_FEAT_APP_SETTING);
+ if (categories & AVRC_SUPF_CT_BROWSE)
+ peer_features |= (BTA_AV_FEAT_BROWSE);
}
}
}
{
/* This is Sink + CT + TG(Abs Vol) */
peer_features = bta_avk_check_peer_features(UUID_SERVCLASS_AV_REM_CTRL_TARGET);
+ APPL_TRACE_DEBUG("%s populating rem ctrl target features %d", __func__, peer_features);
if (BTA_AV_FEAT_ADV_CTRL & bta_avk_check_peer_features(UUID_SERVCLASS_AV_REMOTE_CONTROL))
peer_features |= (BTA_AV_FEAT_ADV_CTRL|BTA_AV_FEAT_RCCT);
}
BTA_AV_RC_COMP_ID, /* AVRCP Company ID */
#if (AVRC_METADATA_INCLUDED == TRUE)
512, /* AVRCP MTU at L2CAP for control channel */
+ BTA_AV_MAX_RC_BR_MTU, /* AVRCP MTU at L2CAP for browsing channel */
#else
48, /* AVRCP MTU at L2CAP for control channel */
-#endif
BTA_AV_MAX_RC_BR_MTU, /* AVRCP MTU at L2CAP for browsing channel */
+#endif
BTA_AV_RC_SUPF_CT, /* AVRCP controller categories */
BTA_AV_RC_SUPF_TG, /* AVRCP target categories */
672, /* AVDTP signaling channel MTU at L2CAP */
BTA_AV_RC_META_RSP,
BTA_AV_RC_MSG,
BTA_AV_RC_CLOSE,
+ BTA_AV_RC_BROWSE_CLOSE,
BTA_AV_NUM_ACTIONS
};
bta_av_rc_meta_rsp,
bta_av_rc_msg,
bta_av_rc_close,
- NULL
};
/* state table information */
/* state table for init state */
static const uint8_t bta_av_st_init[][BTA_AV_NUM_COLS] =
{
-/* Event Action 1 Next state */
-/* API_DISABLE_EVT */ {BTA_AV_DISABLE, BTA_AV_INIT_ST },
-/* API_REMOTE_CMD_EVT */ {BTA_AV_IGNORE, BTA_AV_INIT_ST },
-/* API_VENDOR_CMD_EVT */ {BTA_AV_IGNORE, BTA_AV_INIT_ST },
-/* API_VENDOR_RSP_EVT */ {BTA_AV_IGNORE, BTA_AV_INIT_ST },
-/* API_META_RSP_EVT */ {BTA_AV_RC_FREE_RSP, BTA_AV_INIT_ST },
-/* API_RC_CLOSE_EVT */ {BTA_AV_IGNORE, BTA_AV_INIT_ST },
-/* AVRC_OPEN_EVT */ {BTA_AV_RC_OPENED, BTA_AV_OPEN_ST },
-/* AVRC_MSG_EVT */ {BTA_AV_RC_FREE_BROWSE_MSG, BTA_AV_INIT_ST },
-/* AVRC_NONE_EVT */ {BTA_AV_IGNORE, BTA_AV_INIT_ST },
+/* Event Action 1 Next state */
+/* API_DISABLE_EVT */ {BTA_AV_DISABLE, BTA_AV_INIT_ST },
+/* API_REMOTE_CMD_EVT */ {BTA_AV_IGNORE, BTA_AV_INIT_ST },
+/* API_VENDOR_CMD_EVT */ {BTA_AV_IGNORE, BTA_AV_INIT_ST },
+/* API_VENDOR_RSP_EVT */ {BTA_AV_IGNORE, BTA_AV_INIT_ST },
+/* API_META_RSP_EVT */ {BTA_AV_RC_FREE_RSP, BTA_AV_INIT_ST },
+/* API_RC_CLOSE_EVT */ {BTA_AV_IGNORE, BTA_AV_INIT_ST },
+/* AVRC_OPEN_EVT */ {BTA_AV_RC_OPENED, BTA_AV_OPEN_ST },
+/* AVRC_MSG_EVT */ {BTA_AV_RC_FREE_BROWSE_MSG, BTA_AV_INIT_ST },
+/* AVRC_NONE_EVT */ {BTA_AV_IGNORE, BTA_AV_INIT_ST },
};
/* state table for open state */
static const uint8_t bta_av_st_open[][BTA_AV_NUM_COLS] =
{
-/* Event Action 1 Next state */
-/* API_DISABLE_EVT */ {BTA_AV_DISABLE, BTA_AV_INIT_ST },
-/* API_REMOTE_CMD_EVT */ {BTA_AV_RC_REMOTE_CMD, BTA_AV_OPEN_ST },
-/* API_VENDOR_CMD_EVT */ {BTA_AV_RC_VENDOR_CMD, BTA_AV_OPEN_ST },
-/* API_VENDOR_RSP_EVT */ {BTA_AV_RC_VENDOR_RSP, BTA_AV_OPEN_ST },
-/* API_META_RSP_EVT */ {BTA_AV_RC_META_RSP, BTA_AV_OPEN_ST },
-/* API_RC_CLOSE_EVT */ {BTA_AV_RC_CLOSE, BTA_AV_OPEN_ST },
-/* AVRC_OPEN_EVT */ {BTA_AV_RC_OPENED, BTA_AV_OPEN_ST },
-/* AVRC_MSG_EVT */ {BTA_AV_RC_MSG, BTA_AV_OPEN_ST },
-/* AVRC_NONE_EVT */ {BTA_AV_IGNORE, BTA_AV_INIT_ST },
+/* Event Action 1 Next state */
+/* API_DISABLE_EVT */ {BTA_AV_DISABLE, BTA_AV_INIT_ST },
+/* API_REMOTE_CMD_EVT */ {BTA_AV_RC_REMOTE_CMD, BTA_AV_OPEN_ST },
+/* API_VENDOR_CMD_EVT */ {BTA_AV_RC_VENDOR_CMD, BTA_AV_OPEN_ST },
+/* API_VENDOR_RSP_EVT */ {BTA_AV_RC_VENDOR_RSP, BTA_AV_OPEN_ST },
+/* API_META_RSP_EVT */ {BTA_AV_RC_META_RSP, BTA_AV_OPEN_ST },
+/* API_RC_CLOSE_EVT */ {BTA_AV_RC_CLOSE, BTA_AV_OPEN_ST },
+/* AVRC_OPEN_EVT */ {BTA_AV_RC_OPENED, BTA_AV_OPEN_ST },
+/* AVRC_MSG_EVT */ {BTA_AV_RC_MSG, BTA_AV_OPEN_ST },
+/* AVRC_NONE_EVT */ {BTA_AV_IGNORE, BTA_AV_INIT_ST },
};
/* type for state table */
bta_ar_reg_avct(p_bta_av_cfg->avrc_mtu, p_bta_av_cfg->avrc_br_mtu,
(uint8_t)(bta_av_cb.sec_mask & (~BTA_SEC_AUTHORIZE)), BTA_ID_AV);
#endif
+
+ /* Both Audio Source and Audio Sink support AVRCP 1.6 for the
+ * major roles (i.e. Audio Source -> TG 1.6 and vice versa). For
+ * Audio Sink role we support additional TG 1.3 to support
+ * absolute volume. Here we only do TG registration.
+ */
uint16_t profile_version = AVRC_REV_1_0;
if (profile_initialized == UUID_SERVCLASS_AUDIO_SOURCE)
{
/* create an SDP record as AVRC CT. We create 1.3 for SOURCE
* because we rely on feature bits being scanned by external
* devices more than the profile version itself.
+ *
+ * We create 1.4 for SINK since we support browsing.
*/
- if ((profile_initialized == UUID_SERVCLASS_AUDIO_SOURCE) ||
- (profile_initialized == UUID_SERVCLASS_AUDIO_SINK))
+ if (profile_initialized == UUID_SERVCLASS_AUDIO_SOURCE)
{
bta_ar_reg_avrc(UUID_SERVCLASS_AV_REMOTE_CONTROL, NULL, NULL,
p_bta_av_cfg->avrc_ct_cat, BTA_ID_AV,
(bta_av_cb.features & BTA_AV_FEAT_BROWSE), AVRC_REV_1_3);
}
+ else if (profile_initialized == UUID_SERVCLASS_AUDIO_SINK)
+ {
+ bta_ar_reg_avrc(UUID_SERVCLASS_AV_REMOTE_CONTROL, NULL, NULL,
+ p_bta_av_cfg->avrc_ct_cat, BTA_ID_AV,
+ (bta_av_cb.features & BTA_AV_FEAT_BROWSE), AVRC_REV_1_4);
+ }
#endif
}
}
/* set next state */
p_cb->state = state_table[event][BTA_AV_NEXT_STATE];
- APPL_TRACE_EVENT("next state=%d", p_cb->state);
+ APPL_TRACE_EVENT("next state=%d event offset:%d", p_cb->state, event);
/* execute action functions */
if ((action = state_table[event][BTA_AV_ACTION_COL]) != BTA_AV_IGNORE)
{
+ APPL_TRACE_EVENT("%s action executed %d", __func__, action);
(*bta_av_action[action])(p_cb, p_data);
}
}
typedef uint8_t tBTA_AV_ERR;
-
/* AV callback events */
-#define BTA_AV_ENABLE_EVT 0 /* AV enabled */
-#define BTA_AV_REGISTER_EVT 1 /* registered to AVDT */
-#define BTA_AV_OPEN_EVT 2 /* connection opened */
-#define BTA_AV_CLOSE_EVT 3 /* connection closed */
-#define BTA_AV_START_EVT 4 /* stream data transfer started */
-#define BTA_AV_STOP_EVT 5 /* stream data transfer stopped */
-#define BTA_AV_PROTECT_REQ_EVT 6 /* content protection request */
-#define BTA_AV_PROTECT_RSP_EVT 7 /* content protection response */
-#define BTA_AV_RC_OPEN_EVT 8 /* remote control channel open */
-#define BTA_AV_RC_CLOSE_EVT 9 /* remote control channel closed */
-#define BTA_AV_RC_BROWSE_OPEN_EVT 10 /* remote control browse channel open */
-#define BTA_AV_RC_BROWSE_CLOSE_EVT 11 /* remote control browse channel closed */
-#define BTA_AV_REMOTE_CMD_EVT 12 /* remote control command */
-#define BTA_AV_REMOTE_RSP_EVT 13 /* remote control response */
-#define BTA_AV_VENDOR_CMD_EVT 14 /* vendor dependent remote control command */
-#define BTA_AV_VENDOR_RSP_EVT 15 /* vendor dependent remote control response */
-#define BTA_AV_RECONFIG_EVT 16 /* reconfigure response */
-#define BTA_AV_SUSPEND_EVT 17 /* suspend response */
-#define BTA_AV_PENDING_EVT 18 /* incoming connection pending:
- * signal channel is open and stream is
- * not open after
- * BTA_AV_SIGNALLING_TIMEOUT_MS */
-#define BTA_AV_META_MSG_EVT 19 /* metadata messages */
-#define BTA_AV_REJECT_EVT 20 /* incoming connection rejected */
-#define BTA_AV_RC_FEAT_EVT 21 /* remote control channel peer supported features update */
-#define BTA_AV_SINK_MEDIA_CFG_EVT 22 /* command to configure sink codec */
-#define BTA_AV_SINK_MEDIA_DATA_EVT 23 /* sending sink data to Media Task */
-#define BTA_AV_OFFLOAD_START_RSP_EVT 24 /* a2dp offload start response */
+#define BTA_AV_ENABLE_EVT 0 /* AV enabled */
+#define BTA_AV_REGISTER_EVT 1 /* registered to AVDT */
+#define BTA_AV_OPEN_EVT 2 /* connection opened */
+#define BTA_AV_CLOSE_EVT 3 /* connection closed */
+#define BTA_AV_START_EVT 4 /* stream data transfer started */
+#define BTA_AV_STOP_EVT 5 /* stream data transfer stopped */
+#define BTA_AV_PROTECT_REQ_EVT 6 /* content protection request */
+#define BTA_AV_PROTECT_RSP_EVT 7 /* content protection response */
+#define BTA_AV_RC_OPEN_EVT 8 /* remote control channel open */
+#define BTA_AV_RC_CLOSE_EVT 9 /* remote control channel closed */
+#define BTA_AV_REMOTE_CMD_EVT 10 /* remote control command */
+#define BTA_AV_REMOTE_RSP_EVT 11 /* remote control response */
+#define BTA_AV_VENDOR_CMD_EVT 12 /* vendor dependent remote control command */
+#define BTA_AV_VENDOR_RSP_EVT 13 /* vendor dependent remote control response */
+#define BTA_AV_RECONFIG_EVT 14 /* reconfigure response */
+#define BTA_AV_SUSPEND_EVT 15 /* suspend response */
+#define BTA_AV_PENDING_EVT 16 /* incoming connection pending:
+ * signal channel is open and stream is
+ * not open after
+ * BTA_AV_SIGNALLING_TIMEOUT_MS */
+#define BTA_AV_META_MSG_EVT 17 /* metadata messages */
+#define BTA_AV_REJECT_EVT 18 /* incoming connection rejected */
+#define BTA_AV_RC_FEAT_EVT 19 /* remote control channel peer supported features update */
+#define BTA_AV_SINK_MEDIA_CFG_EVT 20 /* command to configure codec */
+#define BTA_AV_SINK_MEDIA_DATA_EVT 21 /* sending data to Media Task */
+#define BTA_AV_OFFLOAD_START_RSP_EVT 22 /* a2dp offload start response */
+#define BTA_AV_RC_BROWSE_OPEN_EVT 23 /* remote control channel open */
+#define BTA_AV_RC_BROWSE_CLOSE_EVT 24 /* remote control channel closed */
/* Max BTA event */
-#define BTA_AV_MAX_EVT 25
-
+#define BTA_AV_MAX_EVT 25
typedef uint8_t tBTA_AV_EVT;
/* Helper macro to avoid code duplication in the state machine handlers */
#define CHECK_RC_EVENT(e, d) \
case BTA_AV_RC_OPEN_EVT: \
- case BTA_AV_RC_CLOSE_EVT: \
case BTA_AV_RC_BROWSE_OPEN_EVT: \
+ case BTA_AV_RC_CLOSE_EVT: \
case BTA_AV_RC_BROWSE_CLOSE_EVT: \
case BTA_AV_REMOTE_CMD_EVT: \
case BTA_AV_VENDOR_CMD_EVT: \
void btif_av_event_deep_copy(uint16_t event, char *p_dest, char *p_src)
{
+ BTIF_TRACE_DEBUG("%s", __func__);
tBTA_AV *av_src = (tBTA_AV *)p_src;
tBTA_AV *av_dest = (tBTA_AV *)p_dest;
// First copy the structure
maybe_non_aligned_memcpy(av_dest, av_src, sizeof(*av_src));
-
switch (event)
{
case BTA_AV_META_MSG_EVT:
* be initiated by the app/audioflinger layers */
BTA_AvEnable(BTA_SEC_AUTHENTICATE, BTA_AV_FEAT_NO_SCO_SSPD|BTA_AV_FEAT_RCCT|
BTA_AV_FEAT_METADATA|BTA_AV_FEAT_VENDOR|
- BTA_AV_FEAT_ADV_CTRL|BTA_AV_FEAT_RCTG,
+ BTA_AV_FEAT_ADV_CTRL|BTA_AV_FEAT_RCTG|BTA_AV_FEAT_BROWSE,
bte_av_callback);
BTA_AvRegister(BTA_AV_CHNL_AUDIO, BTIF_AVK_SERVICE_NAME, 0,
bte_av_sink_media_callback, UUID_SERVCLASS_AUDIO_SINK);
} \
} while (0)
+#define CHECK_BR_CONNECTED(p_dev) \
+do { \
+ BTIF_TRACE_DEBUG("## %s ##", __FUNCTION__); \
+ if (p_dev == NULL || p_dev->br_connected == false) \
+ { \
+ BTIF_TRACE_WARNING("Function %s() called when BR is not connected", __FUNCTION__); \
+ return BT_STATUS_NOT_READY; \
+ } \
+} while (0)
+
/*****************************************************************************
** Local type definitions
******************************************************************************/
/* TODO : Merge btif_rc_reg_notifications_t and btif_rc_cmd_ctxt_t to a single struct */
typedef struct {
bool rc_connected;
+ bool br_connected; // Browsing channel.
uint8_t rc_handle;
tBTA_AV_FEAT rc_features;
btrc_connection_state_t rc_state;
#if (AVRC_ADV_CTRL_INCLUDED == TRUE)
static void handle_rc_metamsg_rsp(tBTA_AV_META_MSG *pmeta_msg, btif_rc_device_cb_t *p_dev);
#endif
+
#if (AVRC_CTRL_INCLUDED == TRUE)
static void handle_avk_rc_metamsg_cmd(tBTA_AV_META_MSG *pmeta_msg);
static void handle_avk_rc_metamsg_rsp(tBTA_AV_META_MSG *pmeta_msg);
btif_rc_device_cb_t *p_dev);
static bt_status_t get_player_app_setting_cmd(uint8_t num_attrib, uint8_t* attrib_ids,
btif_rc_device_cb_t *p_dev);
+void get_folder_item_type_media(const tAVRC_ITEM *avrc_item, btrc_folder_items_t *btrc_item);
+void get_folder_item_type_folder(const tAVRC_ITEM *avrc_item, btrc_folder_items_t *btrc_item);
+void get_folder_item_type_player(const tAVRC_ITEM *avrc_item, btrc_folder_items_t *btrc_item);
+static bt_status_t get_folder_items_cmd(bt_bdaddr_t *bd_addr, uint8_t scope, uint8_t start_item,
+ uint8_t num_items);
#endif
static void btif_rc_upstreams_evt(uint16_t event, tAVRC_COMMAND* p_param, uint8_t ctype, uint8_t label,
btif_rc_device_cb_t *p_dev);
+
#if (AVRC_ADV_CTRL_INCLUDED == TRUE)
static void btif_rc_upstreams_rsp_evt(uint16_t event, tAVRC_RESPONSE *pavrc_resp, uint8_t ctype,
uint8_t label, btif_rc_device_cb_t *p_dev);
if (btif_av_is_sink_enabled())
getcapabilities_cmd (AVRC_CAP_COMPANY_ID, p_dev);
}
+
+ /* Add browsing feature capability */
+ if (p_dev->rc_features & BTA_AV_FEAT_BROWSE) {
+ rc_features |= BTRC_FEAT_BROWSE;
+ }
+
BTIF_TRACE_DEBUG("%s: Update rc features to CTRL: %d", __func__, rc_features);
HAL_CBACK(bt_rc_ctrl_callbacks, getrcfeatures_cb, &rc_addr, rc_features);
-
}
#endif
/***************************************************************************
* Function handle_rc_connect
*
+ * - Argument: tBTA_AV_RC_OPEN browse RC open data structure
+ *
+ * - Description: browse RC connection event handler
+ *
+ ***************************************************************************/
+void handle_rc_browse_connect(tBTA_AV_RC_OPEN *p_rc_open) {
+ BTIF_TRACE_DEBUG("%s rc_handle %d status %d",
+ __func__, p_rc_open->rc_handle, p_rc_open->status);
+#if (AVRC_CTRL_INCLUDED == TRUE)
+ btif_rc_device_cb_t *p_dev = btif_rc_get_device_by_handle(p_rc_open->rc_handle);
+
+ if (!p_dev) {
+ BTIF_TRACE_ERROR("%s p_dev is null", __func__);
+ return;
+ }
+
+ /* check that we are already connected to this address since being connected
+ * to a browse when not connected to the control channel over AVRCP is
+ * probably not preferred anyways. */
+ if (p_rc_open->status == BTA_AV_SUCCESS) {
+ bt_bdaddr_t rc_addr;
+ bdcpy(rc_addr.address, p_dev->rc_addr);
+ p_dev->br_connected = true;
+ HAL_CBACK(bt_rc_ctrl_callbacks, connection_state_cb, true, true, &rc_addr);
+ }
+#endif
+}
+
+/***************************************************************************
+ * Function handle_rc_connect
+ *
* - Argument: tBTA_AV_RC_OPEN RC open data structure
*
* - Description: RC connection event handler
bdcpy(rc_addr.address, p_dev->rc_addr);
if (bt_rc_ctrl_callbacks != NULL)
{
- HAL_CBACK(bt_rc_ctrl_callbacks, connection_state_cb, true, &rc_addr);
+ HAL_CBACK(bt_rc_ctrl_callbacks, connection_state_cb, true, false, &rc_addr);
}
/* report connection state if remote device is AVRCP target */
handle_rc_ctrl_features(p_dev);
/* report connection state if device is AVRCP target */
if (bt_rc_ctrl_callbacks != NULL)
{
- HAL_CBACK(bt_rc_ctrl_callbacks, connection_state_cb, false, &rc_addr);
+ HAL_CBACK(bt_rc_ctrl_callbacks, connection_state_cb, false, false, &rc_addr);
}
#endif
}
release_transaction(p_remote_rsp->label);
if (bt_rc_ctrl_callbacks != NULL) {
- HAL_CBACK(bt_rc_ctrl_callbacks, passthrough_rsp_cb, p_remote_rsp->rc_id, key_state, \
- &rc_addr);
+ HAL_CBACK(bt_rc_ctrl_callbacks, passthrough_rsp_cb, &rc_addr,
+ p_remote_rsp->rc_id, key_state);
}
}
else
handle_rc_connect( &(p_data->rc_open) );
}break;
- case BTA_AV_RC_CLOSE_EVT:
+ case BTA_AV_RC_BROWSE_OPEN_EVT:
{
- handle_rc_disconnect(&(p_data->rc_close));
+ /* tell the UL that we have connection to browse channel and that
+ * browse commands can be directed accordingly. */
+ handle_rc_browse_connect(&(p_data->rc_open));
}break;
- case BTA_AV_RC_BROWSE_OPEN_EVT:
+ case BTA_AV_RC_CLOSE_EVT:
{
- BTIF_TRACE_DEBUG("%s: BTA_AV_RC_BROWSE_OPEN_EVT", __func__);
+ handle_rc_disconnect(&(p_data->rc_close));
}break;
case BTA_AV_RC_BROWSE_CLOSE_EVT:
else if ((bt_rc_callbacks == NULL)&&(bt_rc_ctrl_callbacks != NULL))
{
/* This is case of Sink + CT + TG(for abs vol)) */
- BTIF_TRACE_DEBUG("%s: BTA_AV_META_MSG_EVT code: %d label: %d",
- __func__,
- p_data->meta_msg.code,
- p_data->meta_msg.label);
- BTIF_TRACE_DEBUG("%s: company_id: 0x%x len: %d handle: %d",
- __func__,
+ BTIF_TRACE_DEBUG(
+ "%s BTA_AV_META_MSG_EVT code:%d label:%d opcode %d ctype %d",
+ __FUNCTION__,
+ p_data->meta_msg.code,
+ p_data->meta_msg.label,
+ p_data->meta_msg.p_msg->hdr.opcode,
+ p_data->meta_msg.p_msg->hdr.ctype);
+ BTIF_TRACE_DEBUG("%s company_id:0x%x len:%d handle:%d",
+ __FUNCTION__,
p_data->meta_msg.company_id,
p_data->meta_msg.len,
p_data->meta_msg.rc_handle);
+ switch (p_data->meta_msg.p_msg->hdr.opcode) {
+ case AVRC_OP_VENDOR:
+ if ((p_data->meta_msg.code >= AVRC_RSP_NOT_IMPL)&&
+ (p_data->meta_msg.code <= AVRC_RSP_INTERIM))
+ {
+ /* Its a response */
+ handle_avk_rc_metamsg_rsp(&(p_data->meta_msg));
+ }
+ else if (p_data->meta_msg.code <= AVRC_CMD_GEN_INQ)
+ {
+ /* Its a command */
+ handle_avk_rc_metamsg_cmd(&(p_data->meta_msg));
+ }
+ break;
- if ((p_data->meta_msg.code >= AVRC_RSP_NOT_IMPL)&&
- (p_data->meta_msg.code <= AVRC_RSP_INTERIM))
- {
- /* Its a response */
- handle_avk_rc_metamsg_rsp(&(p_data->meta_msg));
- }
- else if (p_data->meta_msg.code <= AVRC_CMD_GEN_INQ)
- {
- /* Its a command */
- handle_avk_rc_metamsg_cmd(&(p_data->meta_msg));
+ case AVRC_OP_BROWSE:
+ if (p_data->meta_msg.p_msg->hdr.ctype == AVRC_CMD)
+ {
+ handle_avk_rc_metamsg_cmd(&(p_data->meta_msg));
+ }
+ else if (p_data->meta_msg.p_msg->hdr.ctype == AVRC_RSP)
+ {
+ handle_avk_rc_metamsg_rsp(&(p_data->meta_msg));
+ }
+ break;
}
}
memset(&(avrc_rsp.get_play_status), 0, sizeof(tAVRC_GET_PLAY_STATUS_RSP));
+ BTIF_TRACE_DEBUG("%s song len %d song pos %d", __func__, song_len, song_pos);
avrc_rsp.get_play_status.song_len = song_len;
avrc_rsp.get_play_status.song_pos = song_pos;
avrc_rsp.get_play_status.play_status = play_status;
/***************************************************************************
**
+** Function handle_get_folder_items_response
+**
+** Description handles the the get folder items response, calls
+** HAL callback to send the folder items.
+** Returns None
+**
+***************************************************************************/
+static void handle_get_folder_items_response (
+ tBTA_AV_META_MSG *pmeta_msg, tAVRC_GET_ITEMS_RSP *p_rsp)
+{
+ btif_rc_device_cb_t *p_dev = btif_rc_get_device_by_handle(pmeta_msg->rc_handle);
+ bt_bdaddr_t rc_addr;
+ bdcpy(rc_addr.address, p_dev->rc_addr);
+
+ if (p_rsp->status == AVRC_STS_NO_ERROR)
+ {
+ /* Convert the internal folder listing into a response that can
+ * be passed onto JNI via HAL_CBACK
+ */
+ uint8_t item_count = p_rsp->item_count;
+ btrc_folder_items_t *btrc_items =
+ (btrc_folder_items_t *) osi_malloc(sizeof(btrc_folder_items_t) * item_count);
+ for (uint8_t i = 0; i < item_count; i++) {
+ const tAVRC_ITEM *avrc_item = &(p_rsp->p_item_list[i]);
+ btrc_folder_items_t *btrc_item = &(btrc_items[i]);
+ BTIF_TRACE_DEBUG("%s folder item type %d", __func__, avrc_item->item_type);
+ switch (avrc_item->item_type) {
+ case AVRC_ITEM_MEDIA:
+ BTIF_TRACE_DEBUG("%s setting type to %d", __func__, BTRC_ITEM_MEDIA);
+ get_folder_item_type_media(avrc_item, btrc_item);
+ break;
+
+ case AVRC_ITEM_FOLDER:
+ BTIF_TRACE_DEBUG("%s setting type to BTRC_ITEM_FOLDER", __func__);
+ get_folder_item_type_folder(avrc_item, btrc_item);
+ break;
+
+ case AVRC_ITEM_PLAYER:
+ BTIF_TRACE_DEBUG("%s setting type to BTRC_ITEM_PLAYER", __func__);
+ get_folder_item_type_player(avrc_item, btrc_item);
+ break;
+
+ default:
+ BTIF_TRACE_ERROR("%s cannot understand folder item type %d",
+ __func__, avrc_item->item_type);
+ }
+ }
+
+ HAL_CBACK(bt_rc_ctrl_callbacks,
+ get_folder_items_cb,
+ &rc_addr,
+ /* We want to make the ownership explicit in native */
+ (const btrc_folder_items_t *) btrc_items,
+ item_count);
+ BTIF_TRACE_DEBUG("%s HAL CBACK get_folder_items_cb finished", __func__);
+
+ /* Release the memory block for items since we OWN the object */
+ osi_free(btrc_items);
+ }
+ else
+ {
+ BTIF_TRACE_ERROR("%s: Error %d", __func__, p_rsp->status);
+ }
+}
+
+/***************************************************************************
+**
+** Function get_folder_item_type_media
+**
+** Description Converts the AVRC representation of a folder item with
+** TYPE media to BTIF representation.
+** Returns None
+**
+***************************************************************************/
+void get_folder_item_type_media(
+ const tAVRC_ITEM *avrc_item, btrc_folder_items_t *btrc_item)
+{
+ btrc_item->item_type = BTRC_ITEM_MEDIA;
+ const tAVRC_ITEM_MEDIA *avrc_item_media = &(avrc_item->u.media);
+ btrc_item_media_t *btrc_item_media = &(btrc_item->media);
+ /* UID */
+ memset(btrc_item_media->uid, 0, BTRC_UID_SIZE * sizeof (uint8_t));
+ memcpy(btrc_item_media->uid,
+ avrc_item_media->uid,
+ sizeof(uint8_t) * BTRC_UID_SIZE);
+
+ /* Audio/Video type */
+ switch (avrc_item_media->type) {
+ case AVRC_MEDIA_TYPE_AUDIO:
+ btrc_item_media->type = BTRC_MEDIA_TYPE_AUDIO;
+ break;
+ case AVRC_MEDIA_TYPE_VIDEO:
+ btrc_item_media->type = BTRC_MEDIA_TYPE_VIDEO;
+ break;
+ }
+
+ /* Charset ID */
+ btrc_item_media->charset_id = avrc_item_media->name.charset_id;
+
+ /* Copy the name */
+ BTIF_TRACE_DEBUG("%s max len %d str len %d", __func__, BTRC_MAX_ATTR_STR_LEN,
+ avrc_item_media->name.str_len);
+ memset(btrc_item_media->name, 0, BTRC_MAX_ATTR_STR_LEN * sizeof (uint8_t));
+ memcpy(btrc_item_media->name,
+ avrc_item_media->name.p_str,
+ sizeof(uint8_t) * (avrc_item_media->name.str_len));
+
+ /* Copy the parameters */
+ btrc_item_media->num_attrs = avrc_item_media->attr_count;
+ btrc_item_media->p_attrs = (btrc_element_attr_val_t *) osi_malloc (
+ btrc_item_media->num_attrs * sizeof (btrc_element_attr_val_t));
+
+ /* Extract each attribute */
+ for (int i = 0; i < avrc_item_media->attr_count; i++) {
+ btrc_element_attr_val_t *btrc_attr_pair =
+ &(btrc_item_media->p_attrs[i]);
+ tAVRC_ATTR_ENTRY *avrc_attr_pair =
+ &(avrc_item_media->p_attr_list[i]);
+
+ BTIF_TRACE_DEBUG("%s media attr id 0x%x", __func__,
+ avrc_attr_pair->attr_id);
+
+ switch (avrc_attr_pair->attr_id) {
+ case AVRC_MEDIA_ATTR_ID_TITLE:
+ btrc_attr_pair->attr_id = BTRC_MEDIA_ATTR_ID_TITLE;
+ break;
+ case AVRC_MEDIA_ATTR_ID_ARTIST:
+ btrc_attr_pair->attr_id = BTRC_MEDIA_ATTR_ID_ARTIST;
+ break;
+ case AVRC_MEDIA_ATTR_ID_ALBUM:
+ btrc_attr_pair->attr_id = BTRC_MEDIA_ATTR_ID_ALBUM;
+ break;
+ case AVRC_MEDIA_ATTR_ID_TRACK_NUM:
+ btrc_attr_pair->attr_id = BTRC_MEDIA_ATTR_ID_TRACK_NUM;
+ break;
+ case AVRC_MEDIA_ATTR_ID_NUM_TRACKS:
+ btrc_attr_pair->attr_id = BTRC_MEDIA_ATTR_ID_NUM_TRACKS;
+ break;
+ case AVRC_MEDIA_ATTR_ID_GENRE:
+ btrc_attr_pair->attr_id = BTRC_MEDIA_ATTR_ID_GENRE;
+ break;
+ case AVRC_MEDIA_ATTR_ID_PLAYING_TIME:
+ btrc_attr_pair->attr_id = BTRC_MEDIA_ATTR_ID_PLAYING_TIME;
+ break;
+ default:
+ BTIF_TRACE_ERROR("%s invalid media attr id: 0x%x",
+ __func__, avrc_attr_pair->attr_id);
+ btrc_attr_pair->attr_id = BTRC_MEDIA_ATTR_ID_INVALID;
+ }
+
+ memset(btrc_attr_pair->text, 0,
+ BTRC_MAX_ATTR_STR_LEN * sizeof (uint8_t));
+ memcpy(btrc_attr_pair->text,
+ avrc_attr_pair->name.p_str,
+ avrc_attr_pair->name.str_len);
+ }
+}
+
+/***************************************************************************
+**
+** Function get_folder_item_type_folder
+**
+** Description Converts the AVRC representation of a folder item with
+** TYPE folder to BTIF representation.
+** Returns None
+**
+***************************************************************************/
+void get_folder_item_type_folder(
+ const tAVRC_ITEM *avrc_item, btrc_folder_items_t *btrc_item)
+{
+ btrc_item->item_type = BTRC_ITEM_FOLDER;
+ const tAVRC_ITEM_FOLDER *avrc_item_folder = &(avrc_item->u.folder);
+ btrc_item_folder_t *btrc_item_folder = &(btrc_item->folder);
+ /* Copy the UID */
+ memset(btrc_item_folder->uid, 0, BTRC_UID_SIZE * sizeof (uint8_t));
+ memcpy(btrc_item_folder->uid, avrc_item_folder->uid, sizeof(uint8_t) * BTRC_UID_SIZE);
+
+ /* Copy the type */
+ switch (avrc_item_folder->type) {
+ case AVRC_FOLDER_TYPE_MIXED:
+ btrc_item_folder->type = BTRC_FOLDER_TYPE_MIXED;
+ break;
+ case AVRC_FOLDER_TYPE_TITLES:
+ btrc_item_folder->type = BTRC_FOLDER_TYPE_TITLES;
+ break;
+ case AVRC_FOLDER_TYPE_ALNUMS:
+ btrc_item_folder->type = BTRC_FOLDER_TYPE_ALBUMS;
+ break;
+ case AVRC_FOLDER_TYPE_ARTISTS:
+ btrc_item_folder->type = BTRC_FOLDER_TYPE_ARTISTS;
+ break;
+ case AVRC_FOLDER_TYPE_GENRES:
+ btrc_item_folder->type = BTRC_FOLDER_TYPE_GENRES;
+ break;
+ case AVRC_FOLDER_TYPE_PLAYLISTS:
+ btrc_item_folder->type = BTRC_FOLDER_TYPE_PLAYLISTS;
+ break;
+ case AVRC_FOLDER_TYPE_YEARS:
+ btrc_item_folder->type = BTRC_FOLDER_TYPE_YEARS;
+ break;
+ }
+
+ /* Copy if playable */
+ btrc_item_folder->playable = avrc_item_folder->playable;
+
+ /* Copy name */
+ BTIF_TRACE_DEBUG("%s max len %d str len %d", __func__, BTRC_MAX_ATTR_STR_LEN,
+ avrc_item_folder->name.str_len);
+ memset(btrc_item_folder->name, 0, BTRC_MAX_ATTR_STR_LEN * sizeof (uint8_t));
+ memcpy(btrc_item_folder->name,
+ avrc_item_folder->name.p_str,
+ avrc_item_folder->name.str_len * sizeof (uint8_t));
+
+ /* Copy charset */
+ btrc_item_folder->charset_id = avrc_item_folder->name.charset_id;
+}
+
+/***************************************************************************
+**
+** Function get_folder_item_type_player
+**
+** Description Converts the AVRC representation of a folder item with
+** TYPE player to BTIF representation.
+** Returns None
+**
+***************************************************************************/
+void get_folder_item_type_player(
+ const tAVRC_ITEM *avrc_item, btrc_folder_items_t *btrc_item)
+{
+ btrc_item->item_type = BTRC_ITEM_PLAYER;
+ const tAVRC_ITEM_PLAYER *avrc_item_player = &(avrc_item->u.player);
+ btrc_item_player_t *btrc_item_player = &(btrc_item->player);
+ /* Player ID */
+ btrc_item_player->player_id = avrc_item_player->player_id;
+ /* Major type */
+ btrc_item_player->major_type = avrc_item_player->major_type;
+ /* Sub type */
+ btrc_item_player->sub_type = avrc_item_player->sub_type;
+ /* Features */
+ memcpy(btrc_item_player->features, avrc_item_player->features,
+ BTRC_FEATURE_BIT_MASK_SIZE);
+
+ memset(btrc_item_player->name, 0,
+ BTRC_MAX_ATTR_STR_LEN * sizeof(uint8_t));
+ memcpy(btrc_item_player->name,
+ avrc_item_player->name.p_str,
+ avrc_item_player->name.str_len);
+}
+
+/***************************************************************************
+**
+** Function handle_change_path_response
+**
+** Description handles the the change path response, calls
+** HAL callback to send the updated folder
+** Returns None
+**
+***************************************************************************/
+static void handle_change_path_response (
+ tBTA_AV_META_MSG *pmeta_msg, tAVRC_CHG_PATH_RSP *p_rsp)
+{
+ btif_rc_device_cb_t *p_dev = btif_rc_get_device_by_handle(pmeta_msg->rc_handle);
+ bt_bdaddr_t rc_addr;
+ bdcpy(rc_addr.address, p_dev->rc_addr);
+
+ if (p_rsp->status == AVRC_STS_NO_ERROR)
+ {
+ HAL_CBACK(bt_rc_ctrl_callbacks, change_folder_path_cb,
+ &rc_addr, p_rsp->num_items);
+ }
+ else
+ {
+ BTIF_TRACE_ERROR("%s error in handle_change_path_response %d",
+ __func__, p_rsp->status);
+ }
+}
+
+/***************************************************************************
+**
+** Function handle_set_browsed_player_response
+**
+** Description handles the the change path response, calls
+** HAL callback to send the updated folder
+** Returns None
+**
+***************************************************************************/
+static void handle_set_browsed_player_response(
+ tBTA_AV_META_MSG *pmeta_msg, tAVRC_SET_BR_PLAYER_RSP *p_rsp)
+{
+ btif_rc_device_cb_t *p_dev = btif_rc_get_device_by_handle(pmeta_msg->rc_handle);
+ bt_bdaddr_t rc_addr;
+ bdcpy(rc_addr.address, p_dev->rc_addr);
+
+ if (p_rsp->status == AVRC_STS_NO_ERROR)
+ {
+ HAL_CBACK(bt_rc_ctrl_callbacks, set_browsed_player_cb,
+ &rc_addr, p_rsp->num_items, p_rsp->folder_depth);
+ }
+ else
+ {
+ BTIF_TRACE_ERROR("%s error %d", __func__, p_rsp->status);
+ }
+}
+
+
+/***************************************************************************
+**
** Function clear_cmd_timeout
**
** Description helper function to stop the command timeout timer
BTIF_TRACE_DEBUG("%s: opcode: %d rsp_code: %d ", __func__,
pmeta_msg->p_msg->hdr.opcode, pmeta_msg->code);
+ status = AVRC_Ctrl_ParsResponse(pmeta_msg->p_msg, &avrc_response, scratch_buf, &buf_len);
if ((AVRC_OP_VENDOR == pmeta_msg->p_msg->hdr.opcode)&&
(pmeta_msg->code >= AVRC_RSP_NOT_IMPL)&&
(pmeta_msg->code <= AVRC_RSP_INTERIM))
{
- status = AVRC_Ctrl_ParsResponse(pmeta_msg->p_msg, &avrc_response, scratch_buf, &buf_len);
- BTIF_TRACE_DEBUG("%s: parse status: %d pdu: %d rsp_status: %d",
- __func__, status, avrc_response.pdu,
+ BTIF_TRACE_DEBUG("%s parse status %d pdu = %d rsp_status = %d",
+ __FUNCTION__, status, avrc_response.pdu,
pmeta_msg->p_msg->vendor.hdr.ctype);
switch (avrc_response.pdu)
handle_get_playstatus_response(pmeta_msg, &avrc_response.get_play_status);
break;
}
- release_transaction(pmeta_msg->label);
+ }
+ else if (AVRC_OP_BROWSE == pmeta_msg->p_msg->hdr.opcode)
+ {
+ BTIF_TRACE_DEBUG("%s AVRC_OP_BROWSE pdu %d", __func__, avrc_response.pdu);
+ /* check what kind of command it is for browsing */
+ switch (avrc_response.pdu) {
+ case AVRC_PDU_GET_FOLDER_ITEMS:
+ handle_get_folder_items_response(pmeta_msg, &avrc_response.get_items);
+ break;
+ case AVRC_PDU_CHANGE_PATH:
+ handle_change_path_response(pmeta_msg, &avrc_response.chg_path);
+ break;
+ case AVRC_PDU_SET_BROWSED_PLAYER:
+ handle_set_browsed_player_response(pmeta_msg, &avrc_response.br_player);
+ break;
+ default:
+ BTIF_TRACE_ERROR("%s cannot handle browse pdu %d", __func__,
+ pmeta_msg->p_msg->hdr.opcode);
+ }
}
else
{
__func__, pmeta_msg->code, pmeta_msg->len);
return;
}
+ BTIF_TRACE_DEBUG("XX __func__ release transaction %d", pmeta_msg->label);
+ release_transaction(pmeta_msg->label);
}
/***************************************************************************
BTIF_TRACE_DEBUG("%s: opcode: %d rsp_code: %d",__func__,
pmeta_msg->p_msg->hdr.opcode,pmeta_msg->code);
+ status = AVRC_Ctrl_ParsCommand(pmeta_msg->p_msg, &avrc_cmd);
if ((AVRC_OP_VENDOR==pmeta_msg->p_msg->hdr.opcode)&&
(pmeta_msg->code <= AVRC_CMD_GEN_INQ))
{
- status = AVRC_Ctrl_ParsCommand(pmeta_msg->p_msg, &avrc_cmd);
- BTIF_TRACE_DEBUG("%s: Received vendor command.code: %d, PDU: %d label: %d",
- __func__, pmeta_msg->code, avrc_cmd.pdu, pmeta_msg->label);
+ BTIF_TRACE_DEBUG("%s Received vendor command.code %d, PDU %d label %d",
+ __FUNCTION__, pmeta_msg->code, avrc_cmd.pdu, pmeta_msg->label);
if (status != AVRC_STS_NO_ERROR)
{
/***************************************************************************
**
+** Function get_now_playing_list_cmd
+**
+** Description Fetch the now playing list
+**
+** Paramters start_item: First item to fetch (0 to fetch from beganning)
+** end_item: Last item to fetch (0xff to fetch until end)
+**
+** Returns BT_STATUS_SUCCESS if command issued successfully otherwise
+** BT_STATUS_FAIL.
+**
+***************************************************************************/
+static bt_status_t get_now_playing_list_cmd(bt_bdaddr_t *bd_addr, uint8_t start_item,
+ uint8_t num_items) {
+ BTIF_TRACE_DEBUG("%s start, end: (%d, %d)", __func__, start_item, num_items);
+#if (AVRC_CTRL_INCLUDED == TRUE)
+ return get_folder_items_cmd(bd_addr, AVRC_SCOPE_NOW_PLAYING, start_item, num_items);
+#else
+ BTIF_TRACE_ERROR("%s AVRCP controller role is not enabled", __func__);
+ return BT_STATUS_FAIL;
+#endif
+}
+
+/***************************************************************************
+**
+** Function get_folder_list_cmd
+**
+** Description Fetch the currently selected folder list
+**
+** Paramters start_item: First item to fetch (0 to fetch from beganning)
+** end_item: Last item to fetch (0xff to fetch until end)
+**
+** Returns BT_STATUS_SUCCESS if command issued successfully otherwise
+** BT_STATUS_FAIL.
+**
+***************************************************************************/
+static bt_status_t get_folder_list_cmd(bt_bdaddr_t *bd_addr, uint8_t start_item,
+ uint8_t num_items) {
+ BTIF_TRACE_DEBUG("%s start, end: (%d, %d)", __func__, start_item, num_items);
+#if (AVRC_CTRL_INCLUDED == TRUE)
+ return get_folder_items_cmd(bd_addr, AVRC_SCOPE_FILE_SYSTEM, start_item, num_items);
+#else
+ BTIF_TRACE_ERROR("%s AVRCP controller role is not enabled", __func__);
+ return BT_STATUS_FAIL;
+#endif
+}
+
+/***************************************************************************
+**
+** Function get_player_list_cmd
+**
+** Description Fetch the player list
+**
+** Paramters start_item: First item to fetch (0 to fetch from beganning)
+** end_item: Last item to fetch (0xff to fetch until end)
+**
+** Returns BT_STATUS_SUCCESS if command issued successfully otherwise
+** BT_STATUS_FAIL.
+**
+***************************************************************************/
+static bt_status_t get_player_list_cmd(bt_bdaddr_t *bd_addr, uint8_t start_item,
+ uint8_t num_items) {
+ BTIF_TRACE_DEBUG("%s start, end: (%d, %d)", __func__, start_item, num_items);
+#if (AVRC_CTRL_INCLUDED == TRUE)
+ return get_folder_items_cmd(bd_addr, AVRC_SCOPE_PLAYER_LIST, start_item, num_items);
+#else
+ BTIF_TRACE_ERROR("%s AVRCP controller role is not enabled", __func__);
+ return BT_STATUS_FAIL;
+#endif
+}
+
+/***************************************************************************
+**
+** Function change_folder_path_cmd
+**
+** Description Change the folder.
+**
+** Paramters direction: Direction (Up/Down) to change folder
+** uid: The UID of folder to move to
+** start_item: First item to fetch (0 to fetch from beganning)
+** end_item: Last item to fetch (0xff to fetch until end)
+**
+** Returns BT_STATUS_SUCCESS if command issued successfully otherwise
+** BT_STATUS_FAIL.
+**
+***************************************************************************/
+static bt_status_t change_folder_path_cmd(bt_bdaddr_t *bd_addr, uint8_t direction, uint8_t *uid)
+{
+ BTIF_TRACE_DEBUG("%s direction (%d)", __func__, direction);
+#if (AVRC_CTRL_INCLUDED == TRUE)
+ btif_rc_device_cb_t *p_dev = btif_rc_get_device_by_bda(bd_addr);
+
+ CHECK_RC_CONNECTED(p_dev);
+ CHECK_BR_CONNECTED(p_dev);
+
+ tAVRC_STS status = BT_STATUS_UNSUPPORTED;
+ rc_transaction_t *p_transaction = NULL;
+
+ if (p_dev->br_connected)
+ {
+ tAVRC_COMMAND avrc_cmd = {0};
+ BT_HDR *p_msg = NULL;
+
+ avrc_cmd.chg_path.pdu = AVRC_PDU_CHANGE_PATH;
+ avrc_cmd.chg_path.status = AVRC_STS_NO_ERROR;
+ // TODO(sanketa): Improve for database aware clients.
+ avrc_cmd.chg_path.uid_counter = 0;
+ avrc_cmd.chg_path.direction = direction;
+
+ memset(avrc_cmd.chg_path.folder_uid, 0, AVRC_UID_SIZE * sizeof (uint8_t));
+ memcpy(avrc_cmd.chg_path.folder_uid, uid, AVRC_UID_SIZE * sizeof (uint8_t));
+
+ if (AVRC_BldCommand(&avrc_cmd, &p_msg) == AVRC_STS_NO_ERROR)
+ {
+ bt_status_t tran_status = get_transaction(&p_transaction);
+ if (BT_STATUS_SUCCESS == tran_status && p_transaction != NULL)
+ {
+ BTIF_TRACE_DEBUG("%s msgreq being sent out with label %d",
+ __func__, p_transaction->lbl);
+ BTA_AvMetaCmd(p_dev->rc_handle, p_transaction->lbl, AVRC_CMD_CTRL, p_msg);
+ status = BT_STATUS_SUCCESS;
+ }
+ else
+ {
+ osi_free(p_msg);
+ BTIF_TRACE_ERROR("%s: failed to obtain transaction details. status: 0x%02x",
+ __func__, tran_status);
+ status = BT_STATUS_FAIL;
+ }
+ }
+ else
+ {
+ BTIF_TRACE_ERROR("%s failed to build command status %d", __func__, status);
+ status = BT_STATUS_FAIL;
+ }
+ }
+ else
+ {
+ BTIF_TRACE_ERROR("%s command not supported by peer features %d",
+ __func__, p_dev->rc_features);
+ status = BT_STATUS_FAIL;
+ }
+ return (bt_status_t) status;
+#else
+ BTIF_TRACE_ERROR("%s AVRCP controller role is not enabled", __func__);
+ return BT_STATUS_FAIL;
+#endif
+}
+
+/***************************************************************************
+**
+** Function set_browsed_player_cmd
+**
+** Description Change the browsed player.
+**
+** Paramters id: The UID of player to move to
+**
+** Returns BT_STATUS_SUCCESS if command issued successfully otherwise
+** BT_STATUS_FAIL.
+**
+***************************************************************************/
+static bt_status_t set_browsed_player_cmd(bt_bdaddr_t *bd_addr, uint16_t id)
+{
+ BTIF_TRACE_DEBUG("%s id (%d)", __func__, id);
+#if (AVRC_CTRL_INCLUDED == TRUE)
+ btif_rc_device_cb_t *p_dev = btif_rc_get_device_by_bda(bd_addr);
+ CHECK_RC_CONNECTED(p_dev);
+ CHECK_BR_CONNECTED(p_dev);
+
+ tAVRC_STS status = BT_STATUS_UNSUPPORTED;
+ rc_transaction_t *p_transaction = NULL;
+
+ if (p_dev->br_connected)
+ {
+ tAVRC_COMMAND avrc_cmd = {0};
+ BT_HDR *p_msg = NULL;
+
+ avrc_cmd.br_player.pdu = AVRC_PDU_SET_BROWSED_PLAYER;
+ avrc_cmd.br_player.status = AVRC_STS_NO_ERROR;
+ // TODO(sanketa): Improve for database aware clients.
+ avrc_cmd.br_player.player_id = id;
+
+ if (AVRC_BldCommand(&avrc_cmd, &p_msg) == AVRC_STS_NO_ERROR)
+ {
+ bt_status_t tran_status = get_transaction(&p_transaction);
+ if (BT_STATUS_SUCCESS == tran_status && p_transaction != NULL)
+ {
+ BTIF_TRACE_DEBUG("%s msgreq being sent out with label %d",
+ __func__, p_transaction->lbl);
+ BTA_AvMetaCmd(p_dev->rc_handle, p_transaction->lbl, AVRC_CMD_CTRL, p_msg);
+ status = BT_STATUS_SUCCESS;
+ }
+ else
+ {
+ osi_free(p_msg);
+ BTIF_TRACE_ERROR("%s: failed to obtain transaction details. status: 0x%02x",
+ __func__, tran_status);
+ status = BT_STATUS_FAIL;
+ }
+ }
+ else
+ {
+ BTIF_TRACE_ERROR("%s failed to build command status %d", __func__, status);
+ status = BT_STATUS_FAIL;
+ }
+ }
+ else
+ {
+ BTIF_TRACE_ERROR("%s command not supported by peer features %d",
+ __func__, p_dev->rc_features);
+ status = BT_STATUS_FAIL;
+ }
+ return (bt_status_t) status;
+#else
+ BTIF_TRACE_ERROR("%s AVRCP controller role is not enabled", __func__);
+ return BT_STATUS_FAIL;
+#endif
+}
+
+#if (AVRC_CTRL_INCLUDED == TRUE)
+/***************************************************************************
+**
+** Function get_folder_items_cmd
+**
+** Description Helper function to browse the content hierarchy of the
+** TG device.
+**
+** Paramters scope: AVRC_SCOPE_NOW_PLAYING (etc) for various browseable
+** content
+** start_item: First item to fetch (0 to fetch from beganning)
+** end_item: Last item to fetch (0xff to fetch until end)
+**
+** Returns BT_STATUS_SUCCESS if command issued successfully otherwise
+** BT_STATUS_FAIL.
+**
+***************************************************************************/
+static bt_status_t get_folder_items_cmd(bt_bdaddr_t *bd_addr, uint8_t scope, uint8_t start_item,
+ uint8_t num_items)
+{
+ BTIF_TRACE_DEBUG("%s", __func__);
+ /* Check that both avrcp and browse channel are connected. */
+ btif_rc_device_cb_t *p_dev = btif_rc_get_device_by_bda(bd_addr);
+ CHECK_RC_CONNECTED(p_dev);
+ CHECK_BR_CONNECTED(p_dev);
+
+ tAVRC_STS status = BT_STATUS_UNSUPPORTED;
+ rc_transaction_t *p_transaction=NULL;
+
+ if (p_dev->br_connected) {
+ tAVRC_COMMAND avrc_cmd = {0};
+ BT_HDR *p_msg = NULL;
+
+ /* Set the layer specific to point to browse although this should really
+ * be done by lower layers and looking at the PDU
+ */
+ avrc_cmd.get_items.pdu = AVRC_PDU_GET_FOLDER_ITEMS;
+ avrc_cmd.get_items.status = AVRC_STS_NO_ERROR;
+ avrc_cmd.get_items.scope = scope;
+ avrc_cmd.get_items.start_item = start_item;
+ avrc_cmd.get_items.end_item = (start_item + num_items - 1);
+ avrc_cmd.get_items.attr_count = 0; /* p_attr_list does not matter hence */
+
+ if (AVRC_BldCommand(&avrc_cmd, &p_msg) == AVRC_STS_NO_ERROR)
+ {
+ bt_status_t tran_status = get_transaction(&p_transaction);
+ if (BT_STATUS_SUCCESS == tran_status && p_transaction != NULL)
+ {
+ BTIF_TRACE_DEBUG("%s msgreq being sent out with label %d",
+ __func__, p_transaction->lbl);
+ BTA_AvMetaCmd(p_dev->rc_handle, p_transaction->lbl, AVRC_CMD_CTRL, p_msg);
+ status = BT_STATUS_SUCCESS;
+ }
+ else
+ {
+ osi_free(p_msg);
+ BTIF_TRACE_ERROR("%s: failed to obtain transaction details. status: 0x%02x",
+ __FUNCTION__, tran_status);
+ status = BT_STATUS_FAIL;
+ }
+ }
+ else
+ {
+ BTIF_TRACE_ERROR("%s failed to build command status %d", __func__, status);
+ status = BT_STATUS_FAIL;
+ }
+ } else {
+ BTIF_TRACE_ERROR("%s command not supported by peer features %d",
+ __func__, p_dev->rc_features);
+ status = BT_STATUS_FAIL;
+ }
+ return (bt_status_t) status;
+}
+#endif
+
+/***************************************************************************
+**
** Function change_player_app_setting
**
** Description Set current values of Player Attributes
/***************************************************************************
**
+** Function play_item_cmd
+**
+** Description Play the item specified by UID & scope
+**
+** Returns void
+**
+***************************************************************************/
+static bt_status_t play_item_cmd(
+ bt_bdaddr_t *bd_addr, uint8_t scope, uint8_t *uid, uint16_t uid_counter)
+{
+ tAVRC_STS status = BT_STATUS_UNSUPPORTED;
+#if (AVRC_CTRL_INCLUDED == TRUE)
+ rc_transaction_t *p_transaction = NULL;
+ BTIF_TRACE_DEBUG("%s: scope %d uid_counter %d", __FUNCTION__, scope, uid_counter);
+ btif_rc_device_cb_t *p_dev = btif_rc_get_device_by_bda(bd_addr);
+ CHECK_RC_CONNECTED(p_dev);
+ CHECK_BR_CONNECTED(p_dev);
+
+ bt_status_t tran_status = get_transaction(&p_transaction);
+ if (BT_STATUS_SUCCESS != tran_status)
+ return BT_STATUS_FAIL;
+
+ tAVRC_COMMAND avrc_cmd = {0};
+ BT_HDR *p_msg = NULL;
+ avrc_cmd.pdu = AVRC_PDU_PLAY_ITEM;
+ avrc_cmd.play_item.opcode = AVRC_OP_VENDOR;
+ avrc_cmd.play_item.status = AVRC_STS_NO_ERROR;
+ avrc_cmd.play_item.scope = scope;
+ memcpy(avrc_cmd.play_item.uid, uid, AVRC_UID_SIZE);
+ avrc_cmd.play_item.uid_counter = uid_counter;
+
+ status = AVRC_BldCommand(&avrc_cmd, &p_msg);
+ if ((status == AVRC_STS_NO_ERROR) && (p_msg != NULL))
+ {
+ uint8_t* data_start = (uint8_t *)(p_msg + 1) + p_msg->offset;
+ BTIF_TRACE_DEBUG("%s msgreq being sent out with label %d",
+ __FUNCTION__,p_transaction->lbl);
+ BTA_AvVendorCmd(p_dev->rc_handle,p_transaction->lbl,AVRC_CMD_CTRL,
+ data_start, p_msg->len);
+ status = BT_STATUS_SUCCESS;
+ // start_control_command_timer (AVRC_PDU_PLAY_ITEM, p_transaction);
+ }
+ else
+ {
+ BTIF_TRACE_ERROR("%s: failed to build command. status: 0x%02x",
+ __FUNCTION__, status);
+ }
+ osi_free(p_msg);
+#else
+ BTIF_TRACE_DEBUG("%s: feature not enabled", __FUNCTION__);
+#endif
+ return (bt_status_t) status;
+}
+
+/***************************************************************************
+**
** Function get_player_app_setting_attr_text_cmd
**
** Description Get text description for app attribute
send_passthrough_cmd,
send_groupnavigation_cmd,
change_player_app_setting,
+ play_item_cmd,
+ get_now_playing_list_cmd,
+ get_folder_list_cmd,
+ get_player_list_cmd,
+ change_folder_path_cmd,
+ set_browsed_player_cmd,
set_volume_rsp,
volume_change_notification_rsp,
cleanup_ctrl,
*******************************************************************************/
void release_transaction(uint8_t lbl)
{
+ BTIF_TRACE_DEBUG("%s %d", __func__, lbl);
rc_transaction_t *transaction = get_transaction_by_lbl(lbl);
/* If the transaction is in use... */
#define AVCT_CMD_BUF_SIZE 288
#endif
+#ifndef AVCT_USER_TX_BUF_SIZE
+#define AVCT_USER_TX_BUF_SIZE BT_DEFAULT_BUFFER_SIZE
+#endif
+
+#ifndef AVCT_USER_RX_BUF_SIZE
+#define AVCT_USER_RX_BUF_SIZE BT_DEFAULT_BUFFER_SIZE
+#endif
+
+#ifndef AVCT_FCR_TX_BUF_SIZE
+#define AVCT_FCR_TX_BUF_SIZE BT_DEFAULT_BUFFER_SIZE
+#endif
+
+#ifndef AVCT_FCR_RX_BUF_SIZE
+#define AVCT_FCR_RX_BUF_SIZE BT_DEFAULT_BUFFER_SIZE
+#endif
+
/* AVRCP buffer size for protocol messages */
#ifndef AVRC_CMD_BUF_SIZE
#define AVRC_CMD_BUF_SIZE 288
#define AVCT_NUM_CONN 3
#endif
+/* AVCTP Browsing channel FCR Option:
+ * Size of the transmission window when using enhanced retransmission mode. Not used
+ * in basic and streaming modes. Range: 1 - 63
+ */
+#ifndef AVCT_BR_FCR_OPT_TX_WINDOW_SIZE
+#define AVCT_BR_FCR_OPT_TX_WINDOW_SIZE 10
+#endif
+
+/* AVCTP Browsing channel FCR Option:
+ * Number of transmission attempts for a single I-Frame before taking
+ * Down the connection. Used In ERTM mode only. Value is Ignored in basic and
+ * Streaming modes.
+ * Range: 0, 1-0xFF
+ * 0 - infinite retransmissions
+ * 1 - single transmission
+ */
+#ifndef AVCT_BR_FCR_OPT_MAX_TX_B4_DISCNT
+#define AVCT_BR_FCR_OPT_MAX_TX_B4_DISCNT 20
+#endif
+
+/* AVCTP Browsing channel FCR Option: Retransmission Timeout
+ * The AVRCP specification set a value in the range of 300 - 2000 ms
+ * Timeout (in msecs) to detect Lost I-Frames. Only used in Enhanced retransmission mode.
+ * Range: Minimum 2000 (2 secs) when supporting PBF.
+ */
+#ifndef AVCT_BR_FCR_OPT_RETX_TOUT
+#define AVCT_BR_FCR_OPT_RETX_TOUT 2000
+#endif
+
+/* AVCTP Browsing channel FCR Option: Monitor Timeout
+ * The AVRCP specification set a value in the range of 300 - 2000 ms
+ * Timeout (in msecs) to detect Lost S-Frames. Only used in Enhanced retransmission mode.
+ * Range: Minimum 12000 (12 secs) when supporting PBF.
+ */
+#ifndef AVCT_BR_FCR_OPT_MONITOR_TOUT
+#define AVCT_BR_FCR_OPT_MONITOR_TOUT 12000
+#endif
+
+#ifndef AVCT_BROWSE_INCLUDED
+#define AVCT_BROWSE_INCLUDED TRUE
+#endif
+
/******************************************************************************
**
** AVRCP
#define DUMP_PCM_DATA FALSE
#endif
+/* TRUE to support the AVRCP 1.6 (GetTotalNumOfItems). */
+#ifndef AVRC_1_6_INCLUDED
+#define AVRC_1_6_INCLUDED TRUE
+#endif
+
/******************************************************************************
**
** MCAP
tAVCT_CCB *p_ccb;
tAVCT_UL_MSG ul_msg;
- AVCT_TRACE_API("AVCT_MsgReq");
+ AVCT_TRACE_API("%s", __func__);
/* verify p_msg parameter */
if (p_msg == NULL)
{
return AVCT_NO_RESOURCES;
}
- AVCT_TRACE_API("len: %d", p_msg->len);
+ AVCT_TRACE_API("%s len: %d layer_specific: %d", __func__, p_msg->len, p_msg->layer_specific);
/* map handle to ccb */
if ((p_ccb = avct_ccb_by_idx(handle)) == NULL)
*******************************************************************************/
void avct_bcb_discard_msg(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data)
{
-
osi_free_and_reset((void **)&p_bcb->p_tx_msg);
/* if control channel is up, save the message and open the browsing channel */
*/
#define AVCT_BR_FCR_OPT_MONITOR_TOUT 12000
-
/* callback function declarations */
void avct_l2c_br_connect_ind_cback(BD_ADDR bd_addr, uint16_t lcid, uint16_t psm, uint8_t id);
void avct_l2c_br_connect_cfm_cback(uint16_t lcid, uint16_t result);
void avct_l2c_br_congestion_ind_cback(uint16_t lcid, bool is_congested);
void avct_l2c_br_data_ind_cback(uint16_t lcid, BT_HDR *p_buf);
-
/* L2CAP callback function structure */
const tL2CAP_APPL_INFO avct_l2c_br_appl = {
avct_l2c_br_connect_ind_cback,
/*******************************************************************************
**
+** Function avrc_bld_play_item_cmd
+**
+** Description This function builds the play item cmd
+**
+** Returns AVRC_STS_NO_ERROR, if the command is built successfully
+** Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_play_item_cmd(
+ BT_HDR * p_pkt, uint8_t scope, uint8_t *uid, uint16_t uid_counter)
+{
+ AVRC_TRACE_API("avrc_bld_get_element_attr_cmd");
+ uint8_t *p_start = (uint8_t *)(p_pkt + 1) + p_pkt->offset;
+ uint8_t *p_data = p_start + 2; /* pdu + rsvd */
+ /* add fixed length 11 */
+ UINT16_TO_BE_STREAM(p_data, 0xb);
+ /* Add scope */
+ UINT8_TO_BE_STREAM(p_data, scope);
+ /* Add UID */
+ ARRAY_TO_BE_STREAM(p_data, uid, AVRC_UID_SIZE);
+ /* Add UID Counter */
+ UINT16_TO_BE_STREAM(p_data, uid_counter);
+ p_pkt->len = (p_data - p_start);
+ return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+**
** Function avrc_bld_get_play_status_cmd
**
** Description This function builds the get play status command.
AVRC_TRACE_API("avrc_bld_list_player_app_attr_cmd");
uint8_t *p_start = (uint8_t *)(p_pkt + 1) + p_pkt->offset;
uint8_t *p_data = p_start + 2; /* pdu + rsvd */
- /* add fixed length 1 -*/
+ /* add fixed length 0 -*/
UINT16_TO_BE_STREAM(p_data, 0);
p_pkt->len = (p_data - p_start);
return AVRC_STS_NO_ERROR;
}
+
+/*******************************************************************************
+**
+** Function avrc_bld_get_folder_items_cmd
+**
+** Description This function builds the get folder items cmd.
+**
+** Returns AVRC_STS_NO_ERROR, if the command is built successfully
+** Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_get_folder_items_cmd(BT_HDR *p_pkt, const tAVRC_GET_ITEMS_CMD *cmd)
+{
+ AVRC_TRACE_API("avrc_bld_get_folder_items_cmd");
+ uint8_t *p_start = (uint8_t *)(p_pkt + 1) + p_pkt->offset;
+ /* This is where the PDU specific for AVRC starts
+ * AVRCP Spec 1.4 section 22.19 */
+ uint8_t *p_data = p_start + 1; /* pdu */
+
+ /* To get the list of all media players we simply need to use the predefined
+ * PDU mentioned in above spec. */
+ /* scope (1) + st item (4) + end item (4) + attr (1) */
+ UINT16_TO_BE_STREAM(p_data, 10);
+ UINT8_TO_BE_STREAM(p_data, cmd->scope); /* scope (1bytes) */
+ UINT32_TO_BE_STREAM(p_data, cmd->start_item); /* start item (4bytes) */
+ UINT32_TO_BE_STREAM(p_data, cmd->end_item); /* end item (4bytes) */
+ UINT8_TO_BE_STREAM(p_data, 0); /* attribute count = 0 (1bytes) */
+ p_pkt->len = (p_data - p_start);
+ return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+**
+** Function avrc_bld_change_folder_cmd
+**
+** Description This function builds the change folder command
+**
+** Returns AVRC_STS_NO_ERROR, if the command is built successfully
+** Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_change_folder_cmd(BT_HDR *p_pkt, const tAVRC_CHG_PATH_CMD *cmd)
+{
+ AVRC_TRACE_API("avrc_bld_change_folder_cmd");
+ uint8_t *p_start = (uint8_t *)(p_pkt + 1) + p_pkt->offset;
+ /* This is where the PDU specific for AVRC starts
+ * AVRCP Spec 1.4 section 22.19 */
+ uint8_t *p_data = p_start + 1; /* pdu */
+
+ /* To change folder we need to provide the following:
+ * UID Counter (2) + Direction (1) + UID (8) = 11bytes
+ */
+ UINT16_TO_BE_STREAM(p_data, 11);
+ UINT16_TO_BE_STREAM(p_data, cmd->uid_counter);
+ UINT8_TO_BE_STREAM(p_data, cmd->direction);
+ ARRAY_TO_BE_STREAM(p_data, cmd->folder_uid, AVRC_UID_SIZE);
+ p_pkt->len = (p_data - p_start);
+ return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+**
+** Function avrc_bld_set_browsed_player_cmd
+**
+** Description This function builds the set addressed player cmd.
+**
+** Returns AVRC_STS_NO_ERROR, if the command is built successfully
+** Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_set_browsed_player_cmd(BT_HDR *p_pkt, const tAVRC_SET_BR_PLAYER_CMD *cmd)
+{
+ AVRC_TRACE_API("%s", __func__);
+ uint8_t *p_start = (uint8_t *)(p_pkt + 1) + p_pkt->offset;
+ /* This is where the PDU specific for AVRC starts
+ * AVRCP Spec 1.4 section 22.19 */
+ uint8_t *p_data = p_start + 1; /* pdu */
+
+ /* To change browsed player the following is the total length:
+ * Player ID (2)
+ */
+ UINT16_TO_BE_STREAM(p_data, 2); /* fixed length */
+ UINT16_TO_BE_STREAM(p_data, cmd->player_id);
+ p_pkt->len = (p_data - p_start);
+ return AVRC_STS_NO_ERROR;
+}
#endif
/*******************************************************************************
*******************************************************************************/
static BT_HDR *avrc_bld_init_cmd_buffer(tAVRC_COMMAND *p_cmd)
{
- uint8_t opcode = avrc_opcode_from_pdu(p_cmd->pdu);
+ uint16_t chnl = AVCT_DATA_CTRL;
+ uint8_t opcode = avrc_opcode_from_pdu(p_cmd->pdu);
AVRC_TRACE_API("avrc_bld_init_cmd_buffer: pdu=%x, opcode=%x", p_cmd->pdu, opcode);
uint16_t offset = 0;
switch (opcode)
{
+ case AVRC_OP_BROWSE:
+ chnl = AVCT_DATA_BROWSE;
+ offset = AVCT_BROWSE_OFFSET;
+ break;
+
case AVRC_OP_PASS_THRU:
offset = AVRC_MSG_PASS_THRU_OFFSET;
break;
BT_HDR *p_pkt = (BT_HDR *)osi_malloc(AVRC_META_CMD_BUF_SIZE);
uint8_t *p_data, *p_start;
- p_pkt->layer_specific = AVCT_DATA_CTRL;
+ p_pkt->layer_specific = chnl;
p_pkt->event = opcode;
p_pkt->offset = offset;
p_data = (uint8_t *)(p_pkt + 1) + p_pkt->offset;
status = avrc_bld_get_element_attr_cmd(p_pkt,
p_cmd->get_elem_attrs.num_attr,p_cmd->get_elem_attrs.attrs);
break;
+ case AVRC_PDU_PLAY_ITEM:
+ status = avrc_bld_play_item_cmd(
+ p_pkt, p_cmd->play_item.scope, p_cmd->play_item.uid, p_cmd->play_item.uid_counter);
+ break;
case AVRC_PDU_GET_PLAY_STATUS:
status = avrc_bld_get_play_status_cmd(p_pkt);
break;
+ case AVRC_PDU_GET_FOLDER_ITEMS:
+ status = avrc_bld_get_folder_items_cmd(p_pkt, &(p_cmd->get_items));
+ break;
+ case AVRC_PDU_CHANGE_PATH:
+ status = avrc_bld_change_folder_cmd(p_pkt, &(p_cmd->chg_path));
+ break;
+ case AVRC_PDU_SET_BROWSED_PLAYER:
+ status = avrc_bld_set_browsed_player_cmd(p_pkt, &(p_cmd->br_player));
+ break;
#endif
}
#include "avct_defs.h"
#include "avrc_api.h"
#include "osi/include/alarm.h"
-
#include "osi/include/fixed_queue.h"
#ifdef __cplusplus
/* AVRC internal connection control block */
typedef struct
{
- fixed_queue_t *cmd_q; /* Command queue for serializing vendor specific commands */
- uint8_t flags; /* See AVRC_CB_FLAGS_* definitions */
+ fixed_queue_t *cmd_q; /* Command queue for serializing vendor specific commands */
+ uint8_t flags; /* See AVRC_CB_FLAGS_* definitions */
alarm_t * tle; /* Command timeout timer */
} tAVRC_CONN_INT_CB;
}
}
+static tAVRC_STS avrc_pars_browse_rsp(tAVRC_MSG_BROWSE *p_msg, tAVRC_RESPONSE *p_rsp)
+{
+ tAVRC_STS status = AVRC_STS_NO_ERROR;
+ uint8_t pdu;
+
+ if (p_msg->browse_len == 0)
+ {
+ AVRC_TRACE_ERROR("%s length ", p_msg->browse_len);
+ return AVRC_STS_BAD_PARAM;
+ }
+
+ uint8_t *p = p_msg->p_browse_data;
+
+ /* read the pdu */
+ BE_STREAM_TO_UINT8(pdu, p);
+ uint8_t pkt_len;
+ /* read the entire packet len */
+ BE_STREAM_TO_UINT16(pkt_len, p);
+
+ AVRC_TRACE_DEBUG("%s pdu %d", __func__, pdu);
+
+ /* used to track how much we have read, if we cannot read anymore but the
+ * packet says so then we have a malformed packet. Also vice versa. */
+ uint16_t pkt_len_read = 0;
+
+
+ switch (pdu)
+ {
+ case AVRC_PDU_GET_FOLDER_ITEMS:
+ {
+ tAVRC_GET_ITEMS_RSP *get_item_rsp = &(p_rsp->get_items);
+ /* Copy back the PDU */
+ get_item_rsp->pdu = pdu;
+ /* read the status */
+ BE_STREAM_TO_UINT8(get_item_rsp->status, p);
+ /* read the UID counter */
+ BE_STREAM_TO_UINT16(get_item_rsp->uid_counter, p);
+ /* read the number of items */
+ BE_STREAM_TO_UINT16(get_item_rsp->item_count, p);
+ pkt_len_read += 5;
+
+ AVRC_TRACE_DEBUG("%s pdu %d status %d pkt_len %d uid counter %d item count %d",
+ __func__, get_item_rsp->pdu, get_item_rsp->status, pkt_len,
+ get_item_rsp->uid_counter, get_item_rsp->item_count);
+
+ /* get each of the items */
+ get_item_rsp->p_item_list =
+ (tAVRC_ITEM *) osi_malloc (get_item_rsp->item_count * (sizeof(tAVRC_ITEM)));
+ tAVRC_ITEM *curr_item = get_item_rsp->p_item_list;
+ for (int i = 0; i < get_item_rsp->item_count; i++)
+ {
+ BE_STREAM_TO_UINT8(curr_item->item_type, p);
+ pkt_len_read += 1;
+ AVRC_TRACE_DEBUG("%s item type %d", __func__, curr_item->item_type);
+ switch (curr_item->item_type)
+ {
+ case AVRC_ITEM_PLAYER:
+ {
+ /* Handle player */
+ tAVRC_ITEM_PLAYER *player = &(curr_item->u.player);
+ uint8_t player_len;
+ BE_STREAM_TO_UINT16(player_len, p);
+ BE_STREAM_TO_UINT16(player->player_id, p);
+ BE_STREAM_TO_UINT8(player->major_type, p);
+ BE_STREAM_TO_UINT32(player->sub_type, p);
+ BE_STREAM_TO_UINT8(player->play_status, p);
+ BE_STREAM_TO_ARRAY(p, player->features, AVRC_FEATURE_MASK_SIZE);
+ pkt_len_read += (10 + AVRC_FEATURE_MASK_SIZE);
+
+ /* read str */
+ BE_STREAM_TO_UINT16(player->name.charset_id, p);
+ BE_STREAM_TO_UINT16(player->name.str_len, p);
+ player->name.p_str = (uint8_t *) osi_malloc (
+ (player->name.str_len + 1) * sizeof (uint8_t));
+ BE_STREAM_TO_ARRAY(p, player->name.p_str, player->name.str_len);
+ pkt_len_read += (4 + player->name.str_len);
+ AVRC_TRACE_DEBUG(
+ "%s type %d id %d mtype %d stype %d ps %d cs %d name len %d",
+ __func__, curr_item->item_type, player->player_id,
+ player->major_type, player->sub_type, player->play_status,
+ player->name.charset_id, player->name.str_len);
+ } break;
+
+ case AVRC_ITEM_FOLDER:
+ {
+ tAVRC_ITEM_FOLDER *folder = &(curr_item->u.folder);
+ uint16_t folder_len;
+ BE_STREAM_TO_UINT16(folder_len, p);
+
+ BE_STREAM_TO_ARRAY(p, folder->uid, AVRC_UID_SIZE);
+ BE_STREAM_TO_UINT8(folder->type, p);
+ BE_STREAM_TO_UINT8(folder->playable, p);
+ pkt_len_read += (4 + AVRC_UID_SIZE);
+
+ /* read str, encoding to be handled by upper layers */
+ BE_STREAM_TO_UINT16(folder->name.charset_id, p);
+ BE_STREAM_TO_UINT16(folder->name.str_len, p);
+ folder->name.p_str = (uint8_t *) osi_malloc (
+ (folder->name.str_len + 1) * sizeof (uint8_t));
+ BE_STREAM_TO_ARRAY(p, folder->name.p_str, folder->name.str_len);
+ pkt_len_read += (4 + folder->name.str_len);
+ AVRC_TRACE_DEBUG(
+ "%s type %d playable %d cs %d name len %d",
+ __func__, folder->type, folder->playable, folder->name.charset_id,
+ folder->name.str_len);
+ } break;
+
+ case AVRC_ITEM_MEDIA:
+ {
+ tAVRC_ITEM_MEDIA *media = &(curr_item->u.media);
+ uint8_t media_len;
+ BE_STREAM_TO_UINT16(media_len, p);
+ BE_STREAM_TO_ARRAY(p, media->uid, AVRC_UID_SIZE);
+ BE_STREAM_TO_UINT8(media->type, p);
+ pkt_len_read += (3 + AVRC_UID_SIZE);
+
+ /* read str, encoding to be handled by upper layers */
+ BE_STREAM_TO_UINT16(media->name.charset_id, p);
+ BE_STREAM_TO_UINT16(media->name.str_len, p);
+ media->name.p_str = (uint8_t *) osi_malloc (
+ (media->name.str_len) * sizeof (uint8_t));
+ BE_STREAM_TO_ARRAY(p, media->name.p_str, media->name.str_len);
+
+ BE_STREAM_TO_UINT8(media->attr_count, p);
+ AVRC_TRACE_DEBUG("%s media type %d charset id %d len %d attr ct %d",
+ __func__, media->type, media->name.charset_id,
+ media->name.str_len, media->attr_count);
+ pkt_len_read += (5 + media->name.str_len);
+
+ media->p_attr_list = (tAVRC_ATTR_ENTRY *) osi_malloc (
+ media->attr_count * sizeof (tAVRC_ATTR_ENTRY));
+ for (int jk = 0; jk < media->attr_count; jk++)
+ {
+ tAVRC_ATTR_ENTRY *attr_entry = &(media->p_attr_list[jk]);
+ BE_STREAM_TO_UINT32(attr_entry->attr_id, p);
+
+ /* Parse the name now */
+ BE_STREAM_TO_UINT16(attr_entry->name.charset_id, p);
+ BE_STREAM_TO_UINT16(attr_entry->name.str_len, p);
+ attr_entry->name.p_str = (uint8_t *) osi_malloc (
+ attr_entry->name.str_len * sizeof (uint8_t));
+ BE_STREAM_TO_ARRAY(p, attr_entry->name.p_str, attr_entry->name.str_len);
+ pkt_len_read += (8 + attr_entry->name.str_len);
+ AVRC_TRACE_DEBUG("%s media attr id %d cs %d name len %d",
+ __func__, attr_entry->attr_id,
+ attr_entry->name.charset_id, attr_entry->name.str_len);
+ }
+ } break;
+
+ default:
+ AVRC_TRACE_ERROR("%s item type not handled %d", __func__, curr_item->item_type);
+ return AVRC_STS_INTERNAL_ERR;
+ }
+
+ /* we check if we have overrun */
+ if (pkt_len_read > pkt_len)
+ {
+ AVRC_TRACE_ERROR("%s overflow in read pkt_len %d pkt_len_read %d",
+ __func__, pkt_len, pkt_len_read);
+ return AVRC_STS_BAD_CMD;
+ }
+ AVRC_TRACE_DEBUG("%s pkt_len %d pkt_len_read %d", __func__, pkt_len, pkt_len_read);
+
+ /* advance to populate the next item */
+ curr_item++;
+ }
+ break;
+ }
+
+ case AVRC_PDU_CHANGE_PATH:
+ {
+ tAVRC_CHG_PATH_RSP *change_path_rsp = &(p_rsp->chg_path);
+ /* Copyback the PDU */
+ change_path_rsp->pdu = pdu;
+ /* Read the status */
+ BE_STREAM_TO_UINT8(change_path_rsp->status, p);
+ /* Read the number of items in folder */
+ BE_STREAM_TO_UINT32(change_path_rsp->num_items, p);
+ pkt_len_read += 5;
+
+ AVRC_TRACE_DEBUG("%s pdu %d status %d item count %d",
+ __func__, change_path_rsp->pdu, change_path_rsp->status,
+ change_path_rsp->num_items);
+ break;
+ }
+
+ case AVRC_PDU_SET_BROWSED_PLAYER:
+ {
+ tAVRC_SET_BR_PLAYER_RSP *set_br_pl_rsp = &(p_rsp->br_player);
+ /* Copyback the PDU */
+ set_br_pl_rsp->pdu = pdu;
+
+ /* Read the status */
+ BE_STREAM_TO_UINT8(set_br_pl_rsp->status, p);
+
+ if (set_br_pl_rsp->status != AVRC_STS_NO_ERROR) {
+ AVRC_TRACE_ERROR(
+ "%s Stopping further parsing because player not browsable sts %d",
+ __func__, set_br_pl_rsp->status);
+ break;
+ }
+ BE_STREAM_TO_UINT16(set_br_pl_rsp->uid_counter, p);
+ BE_STREAM_TO_UINT32(set_br_pl_rsp->num_items, p);
+ BE_STREAM_TO_UINT16(set_br_pl_rsp->charset_id, p);
+ BE_STREAM_TO_UINT8(set_br_pl_rsp->folder_depth, p);
+ AVRC_TRACE_DEBUG("%s AVRC_PDU_SET_BROWSED_PLAYER status %d items %d cs %d depth %d",
+ __func__,
+ set_br_pl_rsp->status,
+ set_br_pl_rsp->num_items,
+ set_br_pl_rsp->charset_id,
+ set_br_pl_rsp->folder_depth);
+ pkt_len_read += 10;
+
+ set_br_pl_rsp->p_folders = (tAVRC_NAME *) osi_malloc (
+ set_br_pl_rsp->num_items * sizeof (tAVRC_NAME));
+
+ /* Read each of the folder in the depth */
+ for (uint32_t i = 0; i < set_br_pl_rsp->folder_depth; i++) {
+ tAVRC_NAME *folder_name = &(set_br_pl_rsp->p_folders[i]);
+ BE_STREAM_TO_UINT16(folder_name->str_len, p);
+ AVRC_TRACE_DEBUG("%s AVRC_PDU_SET_BROWSED_PLAYER item: %d len: %d",
+ __func__, i, folder_name->str_len);
+ folder_name->p_str = (uint8_t *) osi_malloc (
+ (folder_name->str_len + 1) * sizeof (uint8_t));
+ BE_STREAM_TO_ARRAY(p, folder_name->p_str, folder_name->str_len);
+ pkt_len_read += (2 + folder_name->str_len);
+ }
+ break;
+ }
+
+ default:
+ AVRC_TRACE_ERROR("%s pdu %d not handled", __func__, pdu);
+ }
+
+ if (pkt_len != pkt_len_read)
+ {
+ AVRC_TRACE_ERROR("%s finished pkt_len %d pkt_len_read %d", __func__, pkt_len, pkt_len_read);
+ return AVRC_STS_BAD_CMD;
+ }
+ return status;
+}
+
#if (AVRC_CTRL_INCLUDED == TRUE)
/*******************************************************************************
**
status = avrc_ctrl_pars_vendor_rsp(&p_msg->vendor, p_result, p_buf,buf_len);
break;
+ case AVRC_OP_BROWSE: /* 0xff Browse commands */
+ status = avrc_pars_browse_rsp(&p_msg->browse, p_result);
+ break;
+
default:
AVRC_TRACE_ERROR("%s unknown opcode:0x%x", __func__, p_msg->hdr.opcode);
break;
((a) <= AVRC_EVT_VOLUME_CHANGE)) ? true : false)
#define AVRC_IS_VALID_ATTRIBUTE(a) ((((((a) > 0) && (a) <= AVRC_PLAYER_SETTING_SCAN)) || \
- ((a) >= AVRC_PLAYER_SETTING_LOW_MENU_EXT)) ? true : false)
+ ((a) >= AVRC_PLAYER_SETTING_LOW_MENU_EXT)) ? true : false)
#define AVRC_IS_VALID_MEDIA_ATTRIBUTE(a) (((a) >= AVRC_MEDIA_ATTR_ID_TITLE) && \
((a) <= AVRC_MEDIA_ATTR_ID_PLAYING_TIME) ? true : false)
typedef struct
{
uint8_t pdu;
- tAVRC_STS status;
+ tAVRC_STS status;
uint8_t opcode; /* Op Code (assigned by AVRC_BldCommand according to pdu) */
uint8_t scope;
} tAVRC_GET_NUM_OF_ITEMS_CMD;