CASE_RETURN_STR(A2DP_CTRL_CMD_START)
CASE_RETURN_STR(A2DP_CTRL_CMD_STOP)
CASE_RETURN_STR(A2DP_CTRL_CMD_SUSPEND)
+ CASE_RETURN_STR(A2DP_CTRL_CMD_CHECK_STREAM_STARTED)
default:
return "UNKNOWN MSG ID";
}
}
+static int check_a2dp_stream_started(struct a2dp_stream_out *out)
+{
+ if (a2dp_command(&out->common, A2DP_CTRL_CMD_CHECK_STREAM_STARTED) < 0)
+ {
+ INFO("Btif not in stream state");
+ return -1;
+ }
+ return 0;
+}
+
+
/*****************************************************************************
**
** audio output callbacks
if (!params)
return status;
- pthread_mutex_lock(&out->common.lock);
-
/* dump params */
hash_map_utils_dump_string_keys_string_values(params);
if (keyval && strcmp(keyval, "true") == 0)
{
DEBUG("stream closing, disallow any writes");
+ pthread_mutex_lock(&out->common.lock);
out->common.state = AUDIO_A2DP_STATE_STOPPING;
+ pthread_mutex_unlock(&out->common.lock);
}
keyval = (char *)hash_map_get(params, "A2dpSuspended");
if (keyval && strcmp(keyval, "true") == 0)
{
+ pthread_mutex_lock(&out->common.lock);
if (out->common.state == AUDIO_A2DP_STATE_STARTED)
status = suspend_audio_datapath(&out->common, false);
+ else
+ {
+ if (check_a2dp_stream_started(out) == 0)
+ /*Btif and A2dp HAL state can be out of sync
+ *check state of btif and suspend audio.
+ *Happens when remote initiates start.*/
+ status = suspend_audio_datapath(&out->common, false);
+ else
+ out->common.state = AUDIO_A2DP_STATE_SUSPENDED;
+ }
+ pthread_mutex_unlock(&out->common.lock);
}
else
{
+ pthread_mutex_lock(&out->common.lock);
/* Do not start the streaming automatically. If the phone was streaming
* prior to being suspended, the next out_write shall trigger the
* AVDTP start procedure */
if (out->common.state == AUDIO_A2DP_STATE_SUSPENDED)
out->common.state = AUDIO_A2DP_STATE_STANDBY;
/* Irrespective of the state, return 0 */
+ pthread_mutex_unlock(&out->common.lock);
}
- pthread_mutex_unlock(&out->common.lock);
hash_map_free(params);
return status;
typedef enum {
A2DP_CTRL_CMD_NONE,
A2DP_CTRL_CMD_CHECK_READY,
+ A2DP_CTRL_CMD_CHECK_STREAM_STARTED,
A2DP_CTRL_CMD_START,
A2DP_CTRL_CMD_STOP,
A2DP_CTRL_CMD_SUSPEND,
#define BTA_AV_RECONFIG_RETRY 6
#endif
+static const size_t SBC_MAX_BITPOOL_OFFSET = 6;
+static const size_t SBC_MAX_BITPOOL = 53;
+
/* ACL quota we are letting FW use for A2DP Offload Tx. */
#define BTA_AV_A2DP_OFFLOAD_XMIT_QUOTA 4
static void bta_av_st_rc_timer(tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data);
-static const size_t SBC_MAX_BITPOOL_OFFSET = 6;
-static const size_t SBC_MAX_BITPOOL = 53;
-
/* state machine states */
enum
{
***********************************************/
static UINT8 bta_av_get_scb_handle(tBTA_AV_SCB *p_scb, UINT8 local_sep)
{
- for (int i = 0; i < BTA_AV_MAX_SEPS; i++) {
- if ((p_scb->seps[i].tsep == local_sep) &&
- (p_scb->seps[i].codec_type == p_scb->codec_type))
- return (p_scb->seps[i].av_handle);
+ UINT8 xx =0;
+ for (xx = 0; xx<BTA_AV_MAX_SEPS; xx++)
+ {
+ if ((p_scb->seps[xx].tsep == local_sep) &&
+ (p_scb->seps[xx].codec_type == p_scb->codec_type))
+ return (p_scb->seps[xx].av_handle);
}
APPL_TRACE_DEBUG(" bta_av_get_scb_handle appropiate sep_type not found")
return 0; /* return invalid handle */
***********************************************/
static UINT8 bta_av_get_scb_sep_type(tBTA_AV_SCB *p_scb, UINT8 tavdt_handle)
{
- for (int i = 0; i < BTA_AV_MAX_SEPS; i++) {
- if (p_scb->seps[i].av_handle == tavdt_handle)
- return (p_scb->seps[i].tsep);
+ UINT8 xx =0;
+ for (xx = 0; xx<BTA_AV_MAX_SEPS; xx++)
+ {
+ if (p_scb->seps[xx].av_handle == tavdt_handle)
+ return (p_scb->seps[xx].tsep);
}
APPL_TRACE_DEBUG(" bta_av_get_scb_sep_type appropiate handle not found")
return 3; /* return invalid sep type */
/* we got a stream; get its capabilities */
if (p_scb->p_cap == NULL)
p_scb->p_cap = (tAVDT_CFG *)osi_malloc(sizeof(tAVDT_CFG));
- if (p_scb->avdt_version >= AVDT_VERSION_SYNC)
+ if ((p_scb->avdt_version >= AVDT_VERSION_SYNC) && (a2d_get_avdt_sdp_ver() >= AVDT_VERSION_SYNC) )
{
p_req = AVDT_GetAllCapReq;
}
{
UINT16 sec_len = 0;
tBTA_AV_SCB *p_scb = bta_av_cb.p_scb[index];
+ int xx;
+ APPL_TRACE_VERBOSE("bta_av_proc_stream_evt on the index : %d", index);
if (p_data)
{
* If we already have a signalling connection with the bd_addr and the streaming
* SST is at INIT state, change it to INCOMING state to handle the signalling
* from the 2nd SEP. */
- if ((bta_av_find_lcb(bd_addr, BTA_AV_LCB_FIND) != NULL) && (bta_av_is_scb_init(p_scb)))
+ /* Fix for below klockwork issue
+ * Pointer 'bd_addr' checked for NULL at line 465 may be passed to function and
+ * may be dereferenced there by passing argument 1 to function 'bta_av_find_lcb' at line 500
+ * added another null check for below condition to get rid of kw error */
+ if (bd_addr != NULL && (bta_av_find_lcb(bd_addr, BTA_AV_LCB_FIND) != NULL) && (bta_av_is_scb_init(p_scb)))
{
bta_av_set_scb_sst_incoming (p_scb);
* Later when we receive AVDT_CONFIG_IND_EVT, we use a new p_scb and set its state to
* incoming which we do it above.
* We also have to set the old p_scb state to init to be used later */
- for (int i = 0; i < BTA_AV_NUM_STRS; i++) {
- if ((bta_av_cb.p_scb[i]) && (i != index)) {
- if (bta_av_cb.p_scb[i]->state == BTA_AV_INCOMING_SST) {
- bta_av_cb.p_scb[i]->state = BTA_AV_INIT_SST;
- bta_av_cb.p_scb[i]->coll_mask = 0;
+ for (xx = 0; xx < BTA_AV_NUM_STRS; xx++)
+ {
+ if ((bta_av_cb.p_scb[xx]) && (xx != index))
+ {
+ if (bta_av_cb.p_scb[xx]->state == BTA_AV_INCOMING_SST)
+ {
+ bta_av_cb.p_scb[xx]->state = BTA_AV_INIT_SST;
+ bta_av_cb.p_scb[xx]->coll_mask = 0;
break;
}
}
/* coverity[var_deref_model] */
/* false-positive: bta_av_conn_cback only processes AVDT_CONNECT_IND_EVT and AVDT_DISCONNECT_IND_EVT event
* these 2 events always have associated p_data */
- if (p_data)
+/* Fix for below klockwork issue
+ * Pointer 'bd_addr' checked for NULL at line 465 may be passed to function and may be dereferenced there
+ * by passing argument 2 to function 'bta_av_conn_cback'. */
+ if (p_data && bd_addr)
{
bta_av_conn_cback(handle, bd_addr, event, p_data);
}
- else
+ else if (!p_data)
{
APPL_TRACE_ERROR("%s: p_data is null", __func__);
}
p_msg->hdr.layer_specific = bta_av_cb.handle;
bta_sys_sendmsg(p_msg);
+ if (!found)
+ APPL_TRACE_ERROR ("bta_av_a2d_sdp_cback, SDP record not found");
+ bta_sys_conn_close(BTA_ID_AV, p_scb->hdi, p_scb->peer_addr);
}
/*******************************************************************************
*******************************************************************************/
static void bta_av_adjust_seps_idx(tBTA_AV_SCB *p_scb, UINT8 avdt_handle)
{
+ int xx;
APPL_TRACE_DEBUG("bta_av_adjust_seps_idx codec_type: %d", p_scb->codec_type);
- for (int i = 0; i < BTA_AV_MAX_SEPS; i++) {
+ for(xx=0; xx<BTA_AV_MAX_SEPS; xx++)
+ {
APPL_TRACE_DEBUG("av_handle: %d codec_type: %d",
- p_scb->seps[i].av_handle, p_scb->seps[i].codec_type);
- if((p_scb->seps[i].av_handle && p_scb->codec_type == p_scb->seps[i].codec_type)
- && (p_scb->seps[i].av_handle == avdt_handle))
+ p_scb->seps[xx].av_handle, p_scb->seps[xx].codec_type);
+ if((p_scb->seps[xx].av_handle && p_scb->codec_type == p_scb->seps[xx].codec_type)
+ && (p_scb->seps[xx].av_handle == avdt_handle))
{
- p_scb->sep_idx = i;
- p_scb->avdt_handle = p_scb->seps[i].av_handle;
+ p_scb->sep_idx = xx;
+ p_scb->avdt_handle = p_scb->seps[xx].av_handle;
break;
}
}
BOOLEAN initiator = FALSE;
tBTA_AV_START start;
tBTA_AV_OPEN av_open;
+ tBTA_AV_ROLE_CHANGED role_changed;
+
+ UINT8 cur_role = BTM_ROLE_UNDEFINED;
APPL_TRACE_DEBUG("bta_av_role_res q_tag:%d, wait:x%x, role:x%x", p_scb->q_tag, p_scb->wait, p_scb->role);
if (p_scb->role & BTA_AV_ROLE_START_INT)
initiator = TRUE;
+ /* Multicast: update BTIF about role switch
+ * If role switch succeeded, we need to update multicast state
+ * from BTIF.
+ */
+ if (p_data->role_res.hci_status == HCI_SUCCESS)
+ {
+ APPL_TRACE_DEBUG("bta_av_role_res: Master update upper layer");
+
+ bdcpy(role_changed.bd_addr, p_scb->peer_addr);
+ role_changed.hndl = p_scb->hndl;
+
+ if (BTM_GetRole (p_scb->peer_addr, &cur_role) == BTM_SUCCESS)
+ {
+ role_changed.new_role = cur_role;
+ }
+ (*bta_av_cb.p_cback)(BTA_AV_ROLE_CHANGED_EVT, (tBTA_AV *)&role_changed);
+ }
+
if (p_scb->q_tag == BTA_AV_Q_TAG_START)
{
if (p_scb->wait & BTA_AV_WAIT_ROLE_SW_STARTED)
if (p_data->role_res.hci_status != HCI_SUCCESS)
{
p_scb->role &= ~BTA_AV_ROLE_START_INT;
- bta_sys_idle(BTA_ID_AV, bta_av_cb.audio_open_cnt, p_scb->peer_addr);
+ bta_sys_idle(BTA_ID_AV, p_scb->hdi, p_scb->peer_addr);
/* start failed because of role switch. */
start.chnl = p_scb->chnl;
start.status = BTA_AV_FAIL_ROLE;
bdcpy(av_open.bd_addr, p_scb->peer_addr);
av_open.chnl = p_scb->chnl;
av_open.hndl = p_scb->hndl;
+ // update Master/Slave Role for open event
+ if (BTM_GetRole (p_scb->peer_addr, &cur_role) == BTM_SUCCESS)
+ {
+ av_open.role = cur_role;
+ }
start.status = BTA_AV_FAIL_ROLE;
if(p_scb->seps[p_scb->sep_idx].tsep == AVDT_TSEP_SRC )
av_open.sep = AVDT_TSEP_SNK;
p_scb->sec_mask = p_data->api_open.sec_mask;
p_scb->use_rc = p_data->api_open.use_rc;
- bta_sys_conn_open(BTA_ID_AV, p_scb->app_id, p_scb->peer_addr);
+ bta_sys_conn_open(BTA_ID_AV, p_scb->hdi, p_scb->peer_addr);
if (p_scb->skip_sdp == TRUE)
{
bta_av_a2d_sdp_cback(TRUE, &a2d_ser);
return;
}
+ else
+ {
+ /* only one A2D find service is active at a time */
+ bta_av_cb.handle = p_scb->hndl;
- /* only one A2D find service is active at a time */
- bta_av_cb.handle = p_scb->hndl;
-
- /* set up parameters */
- db_params.db_len = BTA_AV_DISC_BUF_SIZE;
- db_params.num_attr = 3;
- db_params.p_attrs = attr_list;
- p_scb->uuid_int = p_data->api_open.uuid;
- p_scb->sdp_discovery_started = TRUE;
- if (p_scb->uuid_int == UUID_SERVCLASS_AUDIO_SINK)
- sdp_uuid = UUID_SERVCLASS_AUDIO_SOURCE;
- else if (p_scb->uuid_int == UUID_SERVCLASS_AUDIO_SOURCE)
- sdp_uuid = UUID_SERVCLASS_AUDIO_SINK;
+ /* set up parameters */
+ db_params.db_len = BTA_AV_DISC_BUF_SIZE;
+ db_params.num_attr = 3;
+ db_params.p_attrs = attr_list;
+ p_scb->uuid_int = p_data->api_open.uuid;
+ p_scb->sdp_discovery_started = TRUE;
+ if (p_scb->uuid_int == UUID_SERVCLASS_AUDIO_SINK)
+ sdp_uuid = UUID_SERVCLASS_AUDIO_SOURCE;
+ else if (p_scb->uuid_int == UUID_SERVCLASS_AUDIO_SOURCE)
+ sdp_uuid = UUID_SERVCLASS_AUDIO_SINK;
- APPL_TRACE_DEBUG("%s: uuid_int 0x%x, Doing SDP For 0x%x", __func__,
+ APPL_TRACE_DEBUG("%s: uuid_int 0x%x, Doing SDP For 0x%x", __func__,
p_scb->uuid_int, sdp_uuid);
- if (A2D_FindService(sdp_uuid, p_scb->peer_addr, &db_params,
+ if (A2D_FindService(sdp_uuid, p_scb->peer_addr, &db_params,
bta_av_a2d_sdp_cback) == A2D_SUCCESS)
- return;
+ return;
- /* when the code reaches here, either the DB is NULL
- * or A2D_FindService is not successful */
- bta_av_a2d_sdp_cback(FALSE, NULL);
+ /* when the code reaches here, either the DB is NULL
+ * or A2D_FindService is not successful */
+ bta_av_a2d_sdp_cback(FALSE, NULL);
+ }
}
/*******************************************************************************
void bta_av_cleanup(tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
{
tBTA_AV_CONN_CHG msg;
- UINT8 role = BTA_AV_ROLE_AD_INT;
+ int xx;
+ UINT8 role = BTA_AV_ROLE_AD_INT;
UNUSED(p_data);
APPL_TRACE_DEBUG("bta_av_cleanup");
(*bta_av_cb.p_cback)(BTA_AV_OFFLOAD_START_RSP_EVT, (tBTA_AV *)&status);
}
p_scb->offload_start_pending = FALSE;
+ p_scb->skip_sdp = FALSE;
+ p_scb->coll_mask = 0;
p_scb->skip_sdp = FALSE;
if (p_scb->deregistring)
{
/* remove stream */
- for (int i = 0; i < BTA_AV_MAX_SEPS; i++) {
- if (p_scb->seps[i].av_handle)
- AVDT_RemoveStream(p_scb->seps[i].av_handle);
- p_scb->seps[i].av_handle = 0;
+ for(xx=0; xx<BTA_AV_MAX_SEPS; xx++)
+ {
+ if(p_scb->seps[xx].av_handle)
+ AVDT_RemoveStream(p_scb->seps[xx].av_handle);
+ p_scb->seps[xx].av_handle = 0;
}
bta_av_dereg_comp((tBTA_AV_DATA *) &msg);
p_scb->codec_type = p_evt_cfg->codec_info[BTA_AV_CODEC_TYPE_IDX];
bta_av_save_addr(p_scb, p_data->str_msg.bd_addr);
- /* Clear collision mask */
- p_scb->coll_mask = 0;
+ if (p_scb->coll_mask & BTA_AV_COLL_API_CALLED)
+ {
+ APPL_TRACE_DEBUG(" bta_av_config_ind ReSetting collision mask ");
+ /* Clear collision mask */
+ p_scb->coll_mask = 0;
+ }
+ else
+ {
+ APPL_TRACE_WARNING(" bta_av_config_ind config_ind called before Open");
+ p_scb->coll_mask |= BTA_AV_COLL_SETCONFIG_IND;
+ }
alarm_cancel(bta_av_cb.accept_signalling_timer);
/* if no codec parameters in configuration, fail */
/* Make sure UUID has been initialized... */
if (p_scb->uuid_int == 0)
p_scb->uuid_int = p_scb->open_api.uuid;
+ if (p_scb->uuid_int == 0)
+ p_scb->uuid_int = UUID_SERVCLASS_AUDIO_SOURCE;
bta_av_next_getcap(p_scb, p_data);
}
}
tBTA_AV_OPEN open;
UINT8 *p;
UINT16 mtu;
+ UINT8 cur_role;
msg.hdr.layer_specific = p_scb->hndl;
msg.is_up = TRUE;
if(mtu == 0 || mtu > p_scb->stream_mtu)
mtu = p_scb->stream_mtu;
- /* Set the media channel as medium priority */
- L2CA_SetTxPriority(p_scb->l2c_cid, L2CAP_CHNL_PRIORITY_MEDIUM);
+ /* Set the media channel as high priority */
+ L2CA_SetTxPriority(p_scb->l2c_cid, L2CAP_CHNL_PRIORITY_HIGH);
L2CA_SetChnlFlushability (p_scb->l2c_cid, TRUE);
- bta_sys_conn_open(BTA_ID_AV, bta_av_cb.audio_open_cnt, p_scb->peer_addr);
+ bta_sys_conn_open(BTA_ID_AV, p_scb->hdi, p_scb->peer_addr);
memset(&p_scb->q_info, 0, sizeof(tBTA_AV_Q_INFO));
p_scb->l2c_bufs = 0;
open.status = BTA_AV_SUCCESS;
open.starting = bta_av_chk_start(p_scb);
open.edr = 0;
+ // update Master/Slave Role for start
+ if (BTM_GetRole (p_scb->peer_addr, &cur_role) == BTM_SUCCESS)
+ {
+ open.role = cur_role;
+ }
if( NULL != (p = BTM_ReadRemoteFeatures(p_scb->peer_addr)))
{
if(HCI_EDR_ACL_2MPS_SUPPORTED(p))
*******************************************************************************/
void bta_av_connect_req(tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
{
+ UINT16 result;
UNUSED(p_data);
p_scb->sdp_discovery_started = FALSE;
return;
}
- AVDT_ConnectReq(p_scb->peer_addr, p_scb->sec_mask, bta_av_dt_cback[p_scb->hdi]);
+ result = AVDT_ConnectReq(p_scb->peer_addr, p_scb->sec_mask, bta_av_dt_cback[p_scb->hdi]);
+ if(result != AVDT_SUCCESS)
+ {
+ /* AVDT connect failed because of resource issue
+ * trigger the SDP fail event to enable the cleanup
+ * and set the stream to proper state.
+ */
+ p_scb->open_status = BTA_AV_FAIL_RESOURCES;
+ APPL_TRACE_ERROR("bta_av_connect_req: AVDT_ConnectReq failed: %d", result);
+ bta_av_ssm_execute(p_scb, BTA_AV_SDP_DISC_FAIL_EVT, NULL);
+ }
}
/*******************************************************************************
if (!p_scb->open_status)
p_scb->open_status = BTA_AV_FAIL_SDP;
- p_scb->sdp_discovery_started = FALSE;
+ p_scb->sdp_discovery_started = TRUE;
bta_av_str_closed(p_scb, p_data);
}
tBTA_AV_SCB * p_opened_scb = NULL;
UINT8 idx;
tBTA_AV_OPEN open;
+ UINT8 cur_role;
APPL_TRACE_DEBUG("bta_av_open_failed");
p_scb->open_status = BTA_AV_FAIL_STREAM;
open.status = BTA_AV_FAIL_GET_CAP;
open.starting = bta_av_chk_start(p_scb);
open.edr = 0;
+ // update Master/Slave Role for open event
+ if (BTM_GetRole (p_scb->peer_addr, &cur_role) == BTM_SUCCESS)
+ {
+ open.role = cur_role;
+ }
+
/* set the state back to initial state */
bta_av_set_scb_sst_init(p_scb);
if ((p_scb->started == FALSE) && ((p_scb->role & BTA_AV_ROLE_START_INT) == 0))
{
p_scb->role |= BTA_AV_ROLE_START_INT;
- bta_sys_busy(BTA_ID_AV, bta_av_cb.audio_open_cnt, p_scb->peer_addr);
+ bta_sys_busy(BTA_ID_AV, p_scb->hdi, p_scb->peer_addr);
AVDT_StartReq(&p_scb->avdt_handle, 1);
}
if ( p_scb->wait == 0 ) {
if (p_scb->role & BTA_AV_ROLE_SUSPEND) {
notify_start_failed(p_scb);
- } else {
+ }
+ else
+ {
bta_av_start_ok(p_scb, NULL);
}
}
APPL_TRACE_ERROR("bta_av_str_stopped:audio_open_cnt=%d, p_data %x",
bta_av_cb.audio_open_cnt, p_data);
- bta_sys_idle(BTA_ID_AV, bta_av_cb.audio_open_cnt, p_scb->peer_addr);
+ bta_sys_idle(BTA_ID_AV, p_scb->hdi, p_scb->peer_addr);
if ((bta_av_cb.features & BTA_AV_FEAT_MASTER) == 0 || bta_av_cb.audio_open_cnt == 1)
policy |= HCI_ENABLE_MASTER_SLAVE_SWITCH;
bta_sys_set_policy(BTA_ID_AV, policy, p_scb->peer_addr);
{
tAVDT_CFG *p_cfg;
tBTA_AV_API_STOP stop;
+ tBTA_AV_RECONFIG evt;
tBTA_AV_API_RCFG *p_rcfg = &p_data->api_reconfig;
APPL_TRACE_DEBUG("bta_av_reconfig r:%d, s:%d idx: %d (o:%d)",
/* store the new configuration in control block */
if (p_scb->p_cap == NULL)
p_scb->p_cap = (tAVDT_CFG *)osi_malloc(sizeof(tAVDT_CFG));
- p_cfg = p_scb->p_cap;
+ if((p_cfg = p_scb->p_cap) == NULL)
+ {
+ /* report failure */
+ evt.status = BTA_AV_FAIL_RESOURCES;
+ evt.chnl = p_scb->chnl;
+ evt.hndl = p_scb->hndl;
+ (*bta_av_cb.p_cback)(BTA_AV_RECONFIG_EVT, (tBTA_AV *)&evt);
+
+ /* this event is not possible in this state.
+ * use it to bring the SSM back to open state */
+ bta_av_ssm_execute(p_scb, BTA_AV_SDP_DISC_OK_EVT, NULL);
+ return;
+ }
alarm_cancel(p_scb->avrc_ct_timer);
UINT8 new_role = p_scb->role;
BT_HDR hdr;
UINT8 policy = HCI_ENABLE_SNIFF_MODE;
- UINT8 cur_role;
+ /* Fix for below klockwork issue
+ * 'cur_role' might be used uninitialized in this function */
+ UINT8 cur_role = BTM_ROLE_UNDEFINED;
APPL_TRACE_DEBUG("bta_av_start_ok wait:x%x, role:x%x", p_scb->wait, p_scb->role);
p_scb->wait &= ~BTA_AV_WAIT_ROLE_SW_BITS;
if (p_data->hdr.offset == BTA_AV_RS_FAIL)
{
- bta_sys_idle(BTA_ID_AV, bta_av_cb.audio_open_cnt, p_scb->peer_addr);
+ bta_sys_idle(BTA_ID_AV, p_scb->hdi, p_scb->peer_addr);
start.chnl = p_scb->chnl;
start.status = BTA_AV_FAIL_ROLE;
start.hndl = p_scb->hndl;
}
/* tell role manager to check M/S role */
- bta_sys_conn_open(BTA_ID_AV, bta_av_cb.audio_open_cnt, p_scb->peer_addr);
+ bta_sys_conn_open(BTA_ID_AV, p_scb->hdi, p_scb->peer_addr);
- bta_sys_busy(BTA_ID_AV, bta_av_cb.audio_open_cnt, p_scb->peer_addr);
+ bta_sys_busy(BTA_ID_AV, p_scb->hdi, p_scb->peer_addr);
if(p_scb->media_type == AVDT_MEDIA_AUDIO)
{
}
else if ((new_role & BTA_AV_ROLE_AD_ACP) && (new_role & BTA_AV_ROLE_SUSPEND_OPT))
{
- suspend = TRUE;
+
+ if (bta_av_is_multicast_enabled() == TRUE &&
+ (BTM_GetRole (p_scb->peer_addr, &cur_role) == BTM_SUCCESS)
+ && (cur_role == BTM_ROLE_MASTER))
+ {
+ /* If playing on other stream, dont suspend this. */
+ if (bta_av_chk_start(p_scb))
+ {
+ suspend = FALSE;
+ APPL_TRACE_DEBUG("cur_role: %d suspend: %d", cur_role, suspend);
+ }
+ }
+ else
+ {
+ suspend = TRUE;
+ APPL_TRACE_DEBUG("cur_role: %d suspend: %d", cur_role, suspend);
+
+ }
}
if (!suspend)
start.chnl = p_scb->chnl;
start.status = BTA_AV_SUCCESS;
start.hndl = p_scb->hndl;
+ // update Master/Slave Role for start event
+ if (BTM_GetRole (p_scb->peer_addr, &cur_role) == BTM_SUCCESS)
+ {
+ start.role = cur_role;
+ }
(*bta_av_cb.p_cback)(BTA_AV_START_EVT, (tBTA_AV *) &start);
if(suspend)
if(p_scb->started == FALSE && p_scb->co_started == FALSE)
{
- bta_sys_idle(BTA_ID_AV, bta_av_cb.audio_open_cnt, p_scb->peer_addr);
+ bta_sys_idle(BTA_ID_AV, p_scb->hdi, p_scb->peer_addr);
notify_start_failed(p_scb);
}
event = BTA_AV_OPEN_EVT;
p_scb->open_status = BTA_AV_SUCCESS;
- bta_sys_conn_close(BTA_ID_AV, bta_av_cb.audio_open_cnt, p_scb->peer_addr);
+ bta_sys_conn_close(BTA_ID_AV, p_scb->hdi, p_scb->peer_addr);
bta_av_cleanup(p_scb, p_data);
(*bta_av_cb.p_cback)(event, &data);
}
data.close.hndl = p_scb->hndl;
event = BTA_AV_CLOSE_EVT;
- bta_sys_conn_close(BTA_ID_AV, bta_av_cb.audio_open_cnt, p_scb->peer_addr);
+ bta_sys_conn_close(BTA_ID_AV, p_scb->hdi, p_scb->peer_addr);
bta_av_cleanup(p_scb, p_data);
(*bta_av_cb.p_cback)(event, &data);
}
p_scb->cong = FALSE;
}
- bta_sys_idle(BTA_ID_AV, bta_av_cb.audio_open_cnt, p_scb->peer_addr);
+ bta_sys_idle(BTA_ID_AV, p_scb->hdi, p_scb->peer_addr);
if ((bta_av_cb.features & BTA_AV_FEAT_MASTER) == 0 || bta_av_cb.audio_open_cnt == 1)
policy |= HCI_ENABLE_MASTER_SLAVE_SWITCH;
bta_sys_set_policy(BTA_ID_AV, policy, p_scb->peer_addr);
*******************************************************************************/
void bta_av_open_at_inc (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
{
+ if (!p_scb)
+ {
+ APPL_TRACE_WARNING("scb is NULL, bailing out!");
+ return;
+ }
+
memcpy (&(p_scb->open_api), &(p_data->api_open), sizeof(tBTA_AV_API_OPEN));
+ if (p_scb->coll_mask & BTA_AV_COLL_SETCONFIG_IND)
+ {
+ APPL_TRACE_WARNING(" SetConfig is already called, timer stopped");
+ /* make mask 0, timer shld have already been closed in setconfig_ind */
+ p_scb->coll_mask = 0;
+ return;
+ }
+
if (p_scb->coll_mask & BTA_AV_COLL_INC_TMR)
{
p_scb->coll_mask |= BTA_AV_COLL_API_CALLED;
{
/* SNK did not start signalling, API was called N seconds timeout. */
/* We need to switch to INIT state and start opening connection. */
+ APPL_TRACE_ERROR(" bta_av_open_at_inc ReSetting collision mask ");
p_scb->coll_mask = 0;
bta_av_set_scb_sst_init(p_scb);
#define AVRC_MIN_META_CMD_LEN 20
#endif
+/* state machine states */
+enum
+{
+ BTA_AV_INIT_SST,
+ BTA_AV_INCOMING_SST,
+ BTA_AV_OPENING_SST,
+ BTA_AV_OPEN_SST,
+ BTA_AV_RCFG_SST,
+ BTA_AV_CLOSING_SST
+};
+
/*******************************************************************************
**
** Function bta_av_get_rcb_by_shdl
tAVRC_CONN_CB ccb;
BD_ADDR_PTR bda = (BD_ADDR_PTR)bd_addr_any;
UINT8 status = BTA_AV_RC_ROLE_ACP;
- tBTA_AV_SCB *p_scb = p_cb->p_scb[shdl - 1];
+ tBTA_AV_SCB *p_scb;
int i;
UINT8 rc_handle;
tBTA_AV_RCB *p_rcb;
if (role == AVCT_INT)
{
+ p_scb = p_cb->p_scb[shdl - 1];
bda = p_scb->peer_addr;
status = BTA_AV_RC_ROLE_INT;
}
if (rc_open.peer_features == 0)
{
/* we have not done SDP on peer RC capabilities.
- * peer must have initiated the RC connection
- * We Don't have SDP records of Peer, so we by
- * default will take values depending upon registered
- * features */
- if (p_cb->features & BTA_AV_FEAT_RCTG)
+ * peer must have initiated the RC connection */
+ /*To update default features based on the local features we support*/
+ if (bta_av_cb.features & BTA_AV_FEAT_RCTG)
+ {
rc_open.peer_features |= BTA_AV_FEAT_RCCT;
+ }
+ if (bta_av_cb.features & BTA_AV_FEAT_RCCT)
+ {
+ rc_open.peer_features |= BTA_AV_FEAT_RCTG;
+ }
bta_av_rc_disc(disc);
}
(*p_cb->p_cback)(BTA_AV_RC_OPEN_EVT, (tBTA_AV *) &rc_open);
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;
+ UINT8 pdu;
tAVRC_MSG_BROWSE *p_browse = &p_msg->msg.browse;
pdu = p_browse->p_browse_data[0];
bta_av_close_all_rc(p_cb);
- osi_free_and_reset((void **)&p_cb->p_disc_db);
+ if(p_cb->p_disc_db) {
+ (void)SDP_CancelServiceSearch (p_cb->p_disc_db);
+ osi_free_and_reset((void **)&p_cb->p_disc_db);
+ }
/* disable audio/video - de-register all channels,
* expect BTA_AV_DEREG_COMP_EVT when deregister is complete */
p_lcb = bta_av_find_lcb(p_data->str_msg.bd_addr, BTA_AV_LCB_FIND);
if (!p_lcb)
{
+ if (p_cb->conn_lcb > 0)
+ {
+ APPL_TRACE_DEBUG("Already connected to LCBs: 0x%x", p_cb->conn_lcb);
+ }
+ /* Check if busy processing a connection, if yes, Reject the
+ * new incoming connection.
+ * This is very rare case to happen as the timeout to start
+ * signalling procedure is just 2 sec.
+ * Also sink initiators will have retry machanism.
+ * Even though busy flag is set during outgoing connection to
+ * reject incoming connection at L2CAP connect request, there
+ * is a chance to get here if the incoming connection has passed
+ * the L2CAP connection stage.
+ */
+ if((p_data->hdr.offset == AVDT_ACP) && (AVDT_GetServiceBusyState() == TRUE))
+ {
+ APPL_TRACE_ERROR("%s Incoming conn while processing another.. Reject",
+ __FUNCTION__);
+ AVDT_DisconnectReq (p_data->str_msg.bd_addr, NULL);
+ return;
+ }
+
/* if the address does not have an LCB yet, alloc one */
for(xx=0; xx<BTA_AV_NUM_LINKS; xx++)
{
mask = 1 << xx;
- APPL_TRACE_DEBUG("conn_lcb: 0x%x", p_cb->conn_lcb);
+ APPL_TRACE_DEBUG("The current conn_lcb: 0x%x", p_cb->conn_lcb);
/* look for a p_lcb with its p_scb registered */
if ((!(mask & p_cb->conn_lcb)) && (p_cb->p_scb[xx] != NULL))
{
+ /* Check if the SCB is Free before using for
+ * ACP connection
+ */
+ if ((p_data->hdr.offset == AVDT_ACP) &&
+ (p_cb->p_scb[xx]->state != BTA_AV_INIT_SST))
+ {
+ APPL_TRACE_DEBUG("SCB in use %d", xx);
+ continue;
+ }
+
+ APPL_TRACE_DEBUG("Found a free p_lcb : 0x%x", xx);
p_lcb = &p_cb->lcb[xx];
p_lcb->lidx = xx + 1;
bdcpy(p_lcb->addr, p_data->str_msg.bd_addr);
BTA_AV_SIGNALLING_TIMEOUT_MS,
BTA_AV_SIGNALLING_TIMER_EVT, 0);
bdcpy(pend.bd_addr, p_lcb->addr);
+ APPL_TRACE_DEBUG("bta_av_sig_timer on IDX = %d",xx);
+ //Copy the handle of SCB
+ pend.hndl = p_cb->p_scb[xx]->hndl;
(*p_cb->p_cback)(BTA_AV_PENDING_EVT, (tBTA_AV *) &pend);
}
}
UINT32 inx = PTR_TO_UINT(data);
tBTA_AV_CB *p_cb = &bta_av_cb;
tBTA_AV_SCB *p_scb = NULL;
+
if (inx < BTA_AV_NUM_STRS)
{
p_scb = p_cb->p_scb[inx];
else
{
/* Validate array index*/
- if (((p_cb->disc & BTA_AV_HNDL_MSK) - 1) < BTA_AV_NUM_STRS)
+ /* Fix for below klockwork issue
+ * Array 'p_scb' size is 2
+ * Possible attempt to access element -1 of array 'p_scb' */
+ if ((((p_cb->disc & BTA_AV_HNDL_MSK) - 1) < BTA_AV_NUM_STRS) && (((p_cb->disc & BTA_AV_HNDL_MSK) - 1) >= 0))
{
p_scb = p_cb->p_scb[(p_cb->disc & BTA_AV_HNDL_MSK) - 1];
}
if (p_lcb)
{
rc_handle = bta_av_rc_create(p_cb, AVCT_INT, (UINT8)(p_scb->hdi + 1), p_lcb->lidx);
- p_cb->rcb[rc_handle].peer_features = peer_features;
+ if(rc_handle != BTA_AV_RC_HANDLE_NONE)
+ {
+ p_cb->rcb[rc_handle].peer_features = peer_features;
+ }
+ else
+ {
+ /* cannot create valid rc_handle for current device */
+ APPL_TRACE_ERROR(" No link resources available");
+ p_scb->use_rc = FALSE;
+ bdcpy(rc_open.peer_addr, p_scb->peer_addr);
+ rc_open.peer_features = 0;
+ rc_open.status = BTA_AV_FAIL_RESOURCES;
+ (*p_cb->p_cback)(BTA_AV_RC_CLOSE_EVT, (tBTA_AV *) &rc_open);
+ }
}
#if (BT_USE_TRACES == TRUE || BT_TRACE_APPL == TRUE)
else
** Returns void
**
*******************************************************************************/
-void BTA_AvStart(void)
+void BTA_AvStart(tBTA_AV_HNDL handle)
{
BT_HDR *p_buf = (BT_HDR *) osi_malloc(sizeof(BT_HDR));
p_buf->event = BTA_AV_API_START_EVT;
+ p_buf->layer_specific = handle;
bta_sys_sendmsg(p_buf);
}
** Returns void
**
*******************************************************************************/
-void BTA_AvStop(BOOLEAN suspend)
+void BTA_AvStop(BOOLEAN suspend, tBTA_AV_HNDL handle)
{
tBTA_AV_API_STOP *p_buf =
(tBTA_AV_API_STOP *)osi_malloc(sizeof(tBTA_AV_API_STOP));
p_buf->hdr.event = BTA_AV_API_STOP_EVT;
p_buf->flush = TRUE;
p_buf->suspend = suspend;
+ p_buf->hdr.layer_specific = handle;
bta_sys_sendmsg(p_buf);
}
/*******************************************************************************
**
+** Function BTA_AvEnableMultiCast
+**
+** Description Enable/Disable Avdtp MultiCast
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_AvEnableMultiCast(BOOLEAN state, tBTA_AV_HNDL handle)
+{
+ tBTA_AV_ENABLE_MULTICAST *p_buf;
+
+ if ((p_buf = (tBTA_AV_ENABLE_MULTICAST *) osi_malloc(sizeof(tBTA_AV_ENABLE_MULTICAST))) != NULL)
+ {
+ p_buf->hdr.event = BTA_AV_ENABLE_MULTICAST_EVT;
+ p_buf->hdr.layer_specific = handle;
+ p_buf->is_multicast_enabled = state;
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
** Function BTA_AvReconfig
**
** Description Reconfigure the audio/video stream.
BTA_AV_AVDT_RPT_CONN_EVT,
#endif
BTA_AV_API_START_EVT, /* the following 2 events must be in the same order as the *AP_*EVT */
- BTA_AV_API_STOP_EVT
+ BTA_AV_API_STOP_EVT,
+ BTA_AV_ENABLE_MULTICAST_EVT /* Event for enable and disable multicast */
};
/* events for AV control block state machine */
/* events that do not go through state machine */
#define BTA_AV_FIRST_NSM_EVT BTA_AV_API_ENABLE_EVT
-#define BTA_AV_LAST_NSM_EVT BTA_AV_API_STOP_EVT
+#define BTA_AV_LAST_NSM_EVT BTA_AV_ENABLE_MULTICAST_EVT
/* API events passed to both SSMs (by bta_av_api_to_ssm) */
#define BTA_AV_FIRST_A2S_API_EVT BTA_AV_API_START_EVT
#define BTA_AV_FIRST_A2S_SSM_EVT BTA_AV_AP_START_EVT
-#define BTA_AV_LAST_EVT BTA_AV_API_STOP_EVT
+#define BTA_AV_LAST_EVT BTA_AV_ENABLE_MULTICAST_EVT
/* maximum number of SEPS in stream discovery results */
#define BTA_AV_NUM_SEPS 32
#define BTA_AV_MULTI_AV_SUPPORTED 0x01
#define BTA_AV_MULTI_AV_IN_USE 0x02
-
/*****************************************************************************
** Data types
*****************************************************************************/
BOOLEAN flush;
} tBTA_AV_API_STOP;
+/* data type for BTA_AV_ENABLE_MULTICAST_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ BOOLEAN is_multicast_enabled;
+} tBTA_AV_ENABLE_MULTICAST;
+
/* data type for BTA_AV_API_DISCONNECT_EVT */
typedef struct
{
tBTA_AV_SDP_RES sdp_res;
tBTA_AV_API_META_RSP api_meta_rsp;
tBTA_AV_API_STATUS_RSP api_status_rsp;
+ tBTA_AV_ENABLE_MULTICAST multicast_state;
} tBTA_AV_DATA;
typedef void (tBTA_AV_VDP_DATA_ACT)(void *p_scb);
/* Bitmap for collision, coll_mask */
#define BTA_AV_COLL_INC_TMR 0x01 /* Timer is running for incoming L2C connection */
#define BTA_AV_COLL_API_CALLED 0x02 /* API open was called while incoming timer is running */
+#define BTA_AV_COLL_SETCONFIG_IND 0x04 /* SetConfig indication has been called by remote */
/* type for AV stream control block */
typedef struct
extern BOOLEAN bta_av_is_scb_init (tBTA_AV_SCB *p_scb);
extern void bta_av_set_scb_sst_incoming (tBTA_AV_SCB *p_scb);
extern tBTA_AV_LCB * bta_av_find_lcb(BD_ADDR addr, UINT8 op);
-
+extern BOOLEAN bta_av_is_multicast_enabled();
/* main functions */
extern void bta_av_api_deregister(tBTA_AV_DATA *p_data);
/* 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 },
+/* API_RC_CLOSE_EVT */ {BTA_AV_RC_CLOSE, BTA_AV_INIT_ST },
/* AVRC_OPEN_EVT */ {BTA_AV_RC_OPENED, BTA_AV_OPEN_ST },
/* AVRC_MSG_EVT */ {BTA_AV_RC_FREE_MSG, BTA_AV_INIT_ST },
/* AVRC_NONE_EVT */ {BTA_AV_IGNORE, BTA_AV_INIT_ST },
app_id, BD_ADDR peer_addr);
static void bta_av_sys_rs_cback (tBTA_SYS_CONN_STATUS status,UINT8 id, UINT8 app_id, BD_ADDR peer_addr);
+static void bta_av_api_enable_multicast(tBTA_AV_DATA *p_data);
+
/* action functions */
const tBTA_AV_NSM_ACT bta_av_nsm_act[] =
{
bta_av_conn_chg, /* BTA_AV_CONN_CHG_EVT */
bta_av_dereg_comp, /* BTA_AV_DEREG_COMP_EVT */
#if (BTA_AV_SINK_INCLUDED == TRUE)
- bta_av_api_sink_enable, /* BTA_AV_API_SINK_ENABLE_EVT */
+ bta_av_api_sink_enable, /* BTA_AV_API_SINK_ENABLE_EVT */
#endif
#if (AVDT_REPORTING == TRUE)
- bta_av_rpc_conn, /* BTA_AV_AVDT_RPT_CONN_EVT */
+ bta_av_rpc_conn, /* BTA_AV_AVDT_RPT_CONN_EVT */
#endif
- bta_av_api_to_ssm, /* BTA_AV_API_START_EVT */
- bta_av_api_to_ssm, /* BTA_AV_API_STOP_EVT */
+ bta_av_api_to_ssm, /* BTA_AV_API_START_EVT */
+ bta_av_api_to_ssm, /* BTA_AV_API_STOP_EVT */
+ bta_av_api_enable_multicast, /* BTA_AV_ENABLE_MULTICAST_EVT */
};
/*****************************************************************************
static char *bta_av_st_code(UINT8 state);
#endif
+static BOOLEAN is_multicast_enabled = FALSE;
/*******************************************************************************
**
** Function bta_av_api_enable
p_ret->a2d_list = list_new(NULL);
p_ret->avrc_ct_timer = alarm_new("bta_av.avrc_ct_timer");
bta_av_cb.p_scb[xx] = p_ret;
+ APPL_TRACE_EVENT("AV: Alloc success, handle is =%d", p_ret->hndl);
break;
}
}
tBTA_AV_CODEC codec_type;
tBTA_UTL_COD cod;
UINT8 index = 0;
+ UINT8 xx;
+ UINT16 profile_initialized;
memset(&cs,0,sizeof(tAVDT_CS));
registr.app_id = p_data->api_reg.app_id;
registr.chnl = (tBTA_AV_CHNL)p_data->hdr.layer_specific;
- UINT16 profile_initialized = p_data->api_reg.service_uuid;
- if (profile_initialized == UUID_SERVCLASS_AUDIO_SINK)
+ APPL_TRACE_DEBUG("bta_av_api_register : channel %d", registr.chnl);
+
+ profile_initialized = p_data->api_reg.service_uuid;
+ if(profile_initialized == UUID_SERVCLASS_AUDIO_SINK)
{
p_bta_av_cfg = (tBTA_AV_CFG *) &bta_avk_cfg;
}
if(registr.chnl == BTA_AV_CHNL_AUDIO)
{
/* set up the audio stream control block */
+ APPL_TRACE_EVENT("AV: set up the audio stream control block ");
p_scb->p_act_tbl = (const tBTA_AV_ACT *)bta_av_a2d_action;
p_scb->p_cos = &bta_av_a2d_cos;
p_scb->media_type= AVDT_MEDIA_AUDIO;
}
/* Initialize Handles to zero */
- for (int xx=0; xx < BTA_AV_MAX_SEPS; xx++)
+ for(xx=0; xx<BTA_AV_MAX_SEPS; xx++)
{
p_scb->seps[xx].av_handle = 0;
}
bta_sys_add_uuid(UUID_SERVCLASS_AUDIO_SINK);
#endif
}
+
/* start listening when A2DP is registered */
if (bta_av_cb.features & BTA_AV_FEAT_RCTG)
- bta_av_rc_create(&bta_av_cb, AVCT_ACP, 0, BTA_AV_NUM_LINKS + 1);
+ bta_av_rc_create(&bta_av_cb, AVCT_ACP, p_scb->hdi, BTA_AV_NUM_LINKS + 1);
/* if the AV and AVK are both supported, it cannot support the CT role */
if (bta_av_cb.features & (BTA_AV_FEAT_RCCT))
}
}
bta_av_cb.reg_audio |= BTA_AV_HNDL_TO_MSK(p_scb->hdi);
- APPL_TRACE_DEBUG("reg_audio: 0x%x",bta_av_cb.reg_audio);
+ APPL_TRACE_DEBUG("reg_audio: 0x%x", bta_av_cb.reg_audio);
}
else
{
tBTA_AV_SCB *p_scb;
int i;
UINT8 chnl = (UINT8)p_data->hdr.layer_specific;
-
for( i=0; i < BTA_AV_NUM_STRS; i++ )
{
p_scb = bta_av_cb.p_scb[i];
-
- if(p_scb && p_scb->chnl == chnl)
+ //Check if the Stream is in Started state before sending data
+ //in Dual Handoff mode, get SCB where START is done.
+ if(p_scb && (p_scb->chnl == chnl) && (p_scb->started))
{
bta_av_ssm_execute(p_scb, BTA_AV_SRC_DATA_READY_EVT, p_data);
}
}
#endif
+BOOLEAN bta_av_multiple_streams_started(void)
+{
+ int xx, stream_count = 0;
+
+ for(xx = 0; xx < BTA_AV_NUM_STRS; xx++)
+ {
+ if((bta_av_cb.p_scb[xx] != NULL) && bta_av_cb.p_scb[xx]->started == TRUE)
+ {
+ stream_count++;
+ }
+ }
+ return (stream_count > 1);
+}
+
/*******************************************************************************
**
** Function bta_av_api_to_ssm
int xx;
UINT16 event = p_data->hdr.event - BTA_AV_FIRST_A2S_API_EVT + BTA_AV_FIRST_A2S_SSM_EVT;
- for(xx=0; xx<BTA_AV_NUM_STRS; xx++)
+ /* Multicast: Corner case handling for multicast state getting
+ * updated for ACL connected during the stream start where both
+ * streams are not yet started. We need to take care of this
+ * during suspend to ensure we suspend both streams.
+ */
+ if ((is_multicast_enabled == TRUE) ||
+ ((event == BTA_AV_AP_STOP_EVT) && (bta_av_multiple_streams_started() == TRUE)))
+ {
+ /* Send START request to all Open Stream connections.*/
+ for(xx=0; xx<BTA_AV_NUM_STRS; xx++)
+ {
+ bta_av_ssm_execute(bta_av_cb.p_scb[xx], event, p_data);
+ }
+ }
+ else
{
- bta_av_ssm_execute(bta_av_cb.p_scb[xx], event, p_data);
+ /*In Dual A2dp Handoff, process this fucntion on specific handles.*/
+ APPL_TRACE_DEBUG("bta_av_api_to_ssm: on Handle 0x%x",p_data->hdr.layer_specific);
+ bta_av_ssm_execute(bta_av_hndl_to_scb(p_data->hdr.layer_specific), event, p_data);
}
}
/*******************************************************************************
**
+** Function bta_av_api_enable_multicast
+**
+** Description Enable/Disable Avdtp multicast
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_av_api_enable_multicast(tBTA_AV_DATA *p_data)
+{
+ is_multicast_enabled = p_data->multicast_state.is_multicast_enabled;
+ APPL_TRACE_DEBUG("is_multicast_enabled :%d", is_multicast_enabled);
+}
+
+/*******************************************************************************
+**
** Function bta_av_chk_start
**
** Description if this is audio channel, check if more than one audio
BOOLEAN start = FALSE;
tBTA_AV_SCB *p_scbi;
int i;
-
+ APPL_TRACE_DEBUG("bta_av_chk_start: Audio open count: 0x%x",bta_av_cb.audio_open_cnt);
if(p_scb->chnl == BTA_AV_CHNL_AUDIO)
{
if ((bta_av_cb.audio_open_cnt >= 2) &&
p_scbi = bta_av_cb.p_scb[i];
if(p_scbi && p_scbi->chnl == BTA_AV_CHNL_AUDIO && p_scbi->co_started)
{
- start = TRUE;
+ if (is_multicast_enabled == TRUE)
+ {
+ start = TRUE;
+ }
+ else
+ {
+ start = FALSE;
+ APPL_TRACE_DEBUG("bta_av_chk_start: Already playing");
+ break;
+ }
/* may need to update the flush timeout of this already started stream */
if(p_scbi->co_started != bta_av_cb.audio_open_cnt)
{
{
APPL_TRACE_DEBUG ("bta_av_sys_rs_cback: rs_idx(%d), hndl:x%x q_tag: %d",
bta_av_cb.rs_idx, p_scb->hndl, p_scb->q_tag);
-
+ /* Multicast:
+ * As per Multicast feature implementation, fallback
+ * happens to soft hand-off when DUT is in scatternet
+ * scenario. Hence, don't fail the connection if
+ * role switch fails because of remote disallowing.
+ * Set switch_res to BTA_AV_RS_DONE on failure.
+ */
if(HCI_SUCCESS == app_id || HCI_ERR_NO_CONNECTION == app_id)
p_scb->q_info.open.switch_res = BTA_AV_RS_OK;
else
- p_scb->q_info.open.switch_res = BTA_AV_RS_FAIL;
+ p_scb->q_info.open.switch_res = BTA_AV_RS_DONE;
/* Continue av open process */
bta_av_do_disc_a2d (p_scb, (tBTA_AV_DATA *)&(p_scb->q_info.open));
APPL_TRACE_VERBOSE("AV nsm event=0x%x", event);
#endif
/* non state machine events */
+
(*bta_av_nsm_act[event - BTA_AV_FIRST_NSM_EVT]) ((tBTA_AV_DATA *) p_msg);
}
else if (event >= BTA_AV_FIRST_SM_EVT && event <= BTA_AV_LAST_SM_EVT)
return TRUE;
}
+/*******************************************************************************
+**
+** Function bta_av_is_multicast_enabled
+**
+** Description return status of Avdtp multicast
+**
+**
+** Returns BOOLEAN
+**
+*******************************************************************************/
+BOOLEAN bta_av_is_multicast_enabled()
+{
+ return is_multicast_enabled;
+}
/*****************************************************************************
** Debug Functions
*****************************************************************************/
#endif
case BTA_AV_API_START_EVT: return "API_START";
case BTA_AV_API_STOP_EVT: return "API_STOP";
+ case BTA_AV_ENABLE_MULTICAST_EVT: return "MULTICAST_ENABLE";
default: return "unknown";
}
}
/* STR_DISC_OK_EVT */ {BTA_AV_DISC_RES_AS_ACP,BTA_AV_SIGNORE, BTA_AV_INCOMING_SST },
/* STR_DISC_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST },
/* STR_GETCAP_OK_EVT */ {BTA_AV_SAVE_CAPS, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST },
-/* STR_GETCAP_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST },
+/* STR_GETCAP_FAIL_EVT */ {BTA_AV_OPEN_FAILED, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST },
/* STR_OPEN_OK_EVT */ {BTA_AV_STR_OPENED, BTA_AV_SIGNORE, BTA_AV_OPEN_SST },
/* STR_OPEN_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST },
/* STR_START_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST },
event -= BTA_AV_FIRST_SSM_EVT;
+ if((p_scb->state != BTA_AV_OPENING_SST) &&
+ (state_table[event][BTA_AV_SNEXT_STATE] == BTA_AV_OPENING_SST))
+ {
+ AVDT_UpdateServiceBusyState(TRUE);
+ }
+ else if(AVDT_GetServiceBusyState() == TRUE)
+ {
+ BOOLEAN keep_busy = TRUE;
+
+ for (xx = 0; xx < BTA_AV_NUM_STRS; xx++)
+ {
+ if (bta_av_cb.p_scb[xx])
+ {
+ if ((bta_av_cb.p_scb[xx]->state == BTA_AV_OPENING_SST) &&
+ (bta_av_cb.p_scb[xx] != p_scb))
+ {
+ /* There is other SCB in opening state
+ * keep the service state in progress
+ */
+ APPL_TRACE_VERBOSE("SCB in opening state. Keep Busy");
+ keep_busy = TRUE;
+ break;
+ }
+ else if ((bta_av_cb.p_scb[xx]->state == BTA_AV_OPENING_SST) &&
+ (bta_av_cb.p_scb[xx] == p_scb) &&
+ (state_table[event][BTA_AV_SNEXT_STATE] != BTA_AV_OPENING_SST))
+ {
+ keep_busy = FALSE;
+ }
+ }
+ }
+ if (keep_busy == FALSE)
+ {
+ AVDT_UpdateServiceBusyState(FALSE);
+ }
+ }
+
/* set next state */
p_scb->state = state_table[event][BTA_AV_SNEXT_STATE];
#define BTA_AV_MEDIA_DATA_EVT 21 /* sending data to Media Task */
#define BTA_AV_OFFLOAD_START_RSP_EVT 22 /* a2dp offload start response */
#define BTA_AV_BROWSE_MSG_EVT 23 /* Browse MSG EVT */
+#define BTA_AV_ROLE_CHANGED_EVT 24
/* Max BTA event */
-#define BTA_AV_MAX_EVT 24
-
+#define BTA_AV_MAX_EVT 25
typedef UINT8 tBTA_AV_EVT;
BOOLEAN starting;
tBTA_AV_EDR edr; /* 0, if peer device does not support EDR */
UINT8 sep; /* sep type of peer device */
+ UINT8 role; /* 0x00 master, 0x01 slave , 0xFF unkown*/
} tBTA_AV_OPEN;
/* data associated with BTA_AV_CLOSE_EVT */
tBTA_AV_STATUS status;
BOOLEAN initiator; /* TRUE, if local device initiates the START */
BOOLEAN suspending;
+ UINT8 role; /* 0x00 master, 0x01 slave , 0xFF unkown*/
} tBTA_AV_START;
/* data associated with BTA_AV_SUSPEND_EVT */
typedef struct
{
BD_ADDR bd_addr;
+ tBTA_AV_HNDL hndl; /* Handle associated with the stream. */
} tBTA_AV_PEND;
/* data associated with BTA_AV_REJECT_EVT */
tBTA_AV_HNDL hndl; /* Handle associated with the stream that rejected the connection. */
} tBTA_AV_REJECT;
+/* data associated with BTA_AV_ROLE_CHANGED */
+typedef struct
+{
+ BD_ADDR bd_addr;
+ UINT8 new_role;
+ tBTA_AV_HNDL hndl; /* Handle associated with role change event */
+} tBTA_AV_ROLE_CHANGED;
/* union of data associated with AV callback */
typedef union
tBTA_AV_REJECT reject;
tBTA_AV_RC_FEAT rc_feat;
tBTA_AV_STATUS status;
+ tBTA_AV_ROLE_CHANGED role_changed;
} tBTA_AV;
typedef struct
**
** Function BTA_AvStart
**
-** Description Start audio/video stream data transfer.
+** Description Start audio/video stream data transfer on the AV handle.
**
** Returns void
**
*******************************************************************************/
-void BTA_AvStart(void);
+void BTA_AvStart(tBTA_AV_HNDL hndl);
/*******************************************************************************
**
** Function BTA_AvStop
**
-** Description Stop audio/video stream data transfer.
+** Description Stop audio/video stream data transfer on the AV handle.
** If suspend is TRUE, this function sends AVDT suspend signal
** to the connected peer(s).
**
** Returns void
**
*******************************************************************************/
-void BTA_AvStop(BOOLEAN suspend);
+void BTA_AvStop(BOOLEAN suspend, tBTA_AV_HNDL handle);
+
+/*******************************************************************************
+**
+** Function BTA_AvEnableMultiCast
+**
+** Description Enable/disable Avdtp MultiCast
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_AvEnableMultiCast(BOOLEAN state, tBTA_AV_HNDL handle);
/*******************************************************************************
**
APPL_TRACE_DEBUG("bta_av_co_audio_codec_supported sink %d of peer %d doesn't support cp",
snk_index, index);
*p_status = BTIF_ERROR_SRV_AV_CP_NOT_SUPPORTED;
+#if defined(BTA_AV_CO_CP_SCMS_T) && (BTA_AV_CO_CP_SCMS_T == TRUE)
+ if (!bta_av_co_audio_codec_build_config(p_sink->codec_caps, codec_cfg))
+ {
+ APPL_TRACE_DEBUG2("%s:index %d doesn't support codec", __FUNCTION__, index);
+ return FALSE;
+ }
+ return TRUE;
+#else
return FALSE;
+#endif
}
/* Build the codec configuration for this sink */
p_peer = &bta_av_co_cb.peers[index];
if (p_peer->opened)
{
+ APPL_TRACE_EVENT("bta_av_co_audio_get_sbc_config on index= %d", index);
if (p_peer->mtu < *p_minmtu)
{
*p_minmtu = p_peer->mtu;
if (p_sink->codec_type == A2D_MEDIA_CT_SBC)
{
/* Update the bitpool boundaries of the current config */
+ APPL_TRACE_EVENT("Update the bitpool boundaries on index= %d", jndex);
p_sbc_config->min_bitpool =
BTA_AV_CO_MAX(p_sink->codec_caps[BTA_AV_CO_SBC_MIN_BITPOOL_OFF],
p_sbc_config->min_bitpool);
if (!result)
{
/* Not SBC, still return the default values */
+ APPL_TRACE_EVENT("Not SBC, still return the default values");
*p_sbc_config = btif_av_sbc_default_config;
}
mutex_global_unlock();
BTIF_AV_SINK_FOCUS_REQ_EVT,
BTIF_AV_CLEANUP_REQ_EVT,
BTIF_AV_UPDATE_ENCODER_REQ_EVT,
+ BTIF_AV_INIT_REQ_EVT,
+
} btif_av_sm_event_t;
**
*******************************************************************************/
-bt_bdaddr_t btif_av_get_addr(void);
+bt_bdaddr_t btif_av_get_addr(BD_ADDR address);
/*******************************************************************************
** Function btif_av_is_sink_enabled
/*******************************************************************************
**
+** Function btif_av_any_br_peer
+**
+** Description Check if the any of connected devices is BR device.
+**
+** Returns TRUE if connected to any BR device, FALSE otherwise.
+**
+*******************************************************************************/
+
+BOOLEAN btif_av_any_br_peer(void);
+
+/*******************************************************************************
+**
** Function btif_av_peer_supports_3mbps
**
** Description Check if the connected A2DP device supports
bool btif_a2dp_start_media_task(void);
void btif_a2dp_stop_media_task(void);
-
+bool btif_a2dp_is_media_task_stopped(void);
void btif_a2dp_on_init(void);
-void btif_a2dp_setup_codec(void);
+tBTIF_STATUS btif_a2dp_setup_codec(void);
void btif_a2dp_update_codec(void);
void btif_a2dp_on_idle(void);
void btif_a2dp_on_open(void);
typedef UINT32 btif_sm_state_t;
typedef UINT32 btif_sm_event_t;
typedef void* btif_sm_handle_t;
-typedef BOOLEAN(*btif_sm_handler_t)(btif_sm_event_t event, void *data);
+typedef BOOLEAN(*btif_sm_handler_t)(btif_sm_event_t event, void *data, int index);
/*****************************************************************************
** Functions
**
******************************************************************************/
btif_sm_handle_t btif_sm_init(const btif_sm_handler_t *p_handlers,
- btif_sm_state_t initial_state);
+ btif_sm_state_t initial_state, int index);
/*****************************************************************************
**
/******************************************************************************
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
*
* Copyright (C) 2009-2012 Broadcom Corporation
*
#include "btu.h"
#include "bt_common.h"
#include "osi/include/allocator.h"
+#include <cutils/properties.h>
/*****************************************************************************
** Constants & Macros
#define BTIF_TIMEOUT_AV_OPEN_ON_RC_MS (2 * 1000)
+/* Number of BTIF-AV control blocks */
+/* Now supports Two AV connections. */
+#define BTIF_AV_NUM_CB 2
+#define HANDLE_TO_INDEX(x) ((x & BTA_AV_HNDL_MSK) - 1)
+
typedef enum {
BTIF_AV_STATE_IDLE = 0x0,
BTIF_AV_STATE_OPENING,
#define BTIF_AV_FLAG_REMOTE_SUSPEND 0x2
#define BTIF_AV_FLAG_PENDING_START 0x4
#define BTIF_AV_FLAG_PENDING_STOP 0x8
+/* Host role defenitions */
+#define HOST_ROLE_MASTER 0x00
+#define HOST_ROLE_SLAVE 0x01
+#define HOST_ROLE_UNKNOWN 0xff
/*****************************************************************************
** Local type definitions
UINT8 flags;
tBTA_AV_EDR edr;
UINT8 peer_sep; /* sep type of peer device */
+ UINT8 edr_3mbps;
+ BOOLEAN dual_handoff;
+ BOOLEAN current_playing;
+ btif_sm_state_t state;
+ int service;
+ BOOLEAN is_slave;
+ BOOLEAN is_device_playing;
} btif_av_cb_t;
typedef struct
******************************************************************************/
static btav_callbacks_t *bt_av_src_callbacks = NULL;
static btav_callbacks_t *bt_av_sink_callbacks = NULL;
-static btif_av_cb_t btif_av_cb = {0, {{0}}, 0, 0, 0, 0};
static alarm_t *av_open_on_rc_timer = NULL;
+static btif_av_cb_t btif_av_cb[BTIF_AV_NUM_CB];
+static btif_sm_event_t idle_rc_event;
+static tBTA_AV idle_rc_data;
+static int btif_max_av_clients = 1;
+static BOOLEAN enable_multicast = FALSE;
+static BOOLEAN is_multicast_supported = FALSE;
+static BOOLEAN multicast_disabled = FALSE;
/* both interface and media task needs to be ready to alloc incoming request */
#define CHECK_BTAV_INIT() if (((bt_av_src_callbacks == NULL) &&(bt_av_sink_callbacks == NULL)) \
- || (btif_av_cb.sm_handle == NULL))\
+ || (btif_av_cb[0].sm_handle == NULL))\
{\
BTIF_TRACE_WARNING("%s: BTAV not initialized", __FUNCTION__);\
return BT_STATUS_NOT_READY;\
/* 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_REMOTE_CMD_EVT: \
case BTA_AV_VENDOR_CMD_EVT: \
btif_rc_handler(e, d);\
}break; \
-static BOOLEAN btif_av_state_idle_handler(btif_sm_event_t event, void *data);
-static BOOLEAN btif_av_state_opening_handler(btif_sm_event_t event, void *data);
-static BOOLEAN btif_av_state_opened_handler(btif_sm_event_t event, void *data);
-static BOOLEAN btif_av_state_started_handler(btif_sm_event_t event, void *data);
-static BOOLEAN btif_av_state_closing_handler(btif_sm_event_t event, void *data);
+static BOOLEAN btif_av_state_idle_handler(btif_sm_event_t event, void *data, int index);
+static BOOLEAN btif_av_state_opening_handler(btif_sm_event_t event, void *data, int index);
+static BOOLEAN btif_av_state_opened_handler(btif_sm_event_t event, void *data, int index);
+static BOOLEAN btif_av_state_started_handler(btif_sm_event_t event, void *data,int index);
+
+static BOOLEAN btif_av_state_closing_handler(btif_sm_event_t event, void *data,int index);
+
+static BOOLEAN btif_av_get_valid_idx(int idx);
+static UINT8 btif_av_idx_by_bdaddr( BD_ADDR bd_addr);
+static int btif_get_latest_playing_device_idx();
+static int btif_get_latest_device_idx_to_start();
+static int btif_av_get_valid_idx_for_rc_events(BD_ADDR bd_addr, int rc_handle);
+static int btif_get_conn_state_of_device(BD_ADDR address);
+static bt_status_t connect_int(bt_bdaddr_t *bd_addr, uint16_t uuid);
+static void btif_av_update_current_playing_device(int index);
+static void btif_av_check_rc_connection_priority(void *p_data);
+#ifdef AVK_BACKPORT
+void btif_av_request_audio_focus( BOOLEAN enable);
+#endif
static const btif_sm_handler_t btif_av_state_handlers[] =
{
btif_av_state_idle_handler,
extern BOOLEAN btif_rc_get_connected_peer(BD_ADDR peer_addr);
extern UINT8 btif_rc_get_connected_peer_handle(BD_ADDR peer_addr);
extern void btif_rc_check_handle_pending_play (BD_ADDR peer_addr, BOOLEAN bSendToApp);
+extern void btif_rc_get_playing_device(BD_ADDR address);
+extern void btif_rc_clear_playing_state(BOOLEAN play);
+extern void btif_rc_clear_priority(BD_ADDR address);
+extern void btif_rc_send_pause_command();
+extern UINT16 btif_dm_get_br_edr_links();
+extern UINT16 btif_dm_get_le_links();
+extern UINT16 btif_hf_is_call_idle();
extern fixed_queue_t *btu_general_alarm_queue;
/*****************************************************************************
** Local helper functions
******************************************************************************/
+void btif_av_trigger_dual_handoff(BOOLEAN handoff, BD_ADDR address);
+BOOLEAN btif_av_is_device_connected(BD_ADDR address);
+
+BOOLEAN btif_av_is_connected_on_other_idx(int current_index);
+BOOLEAN btif_av_is_playing_on_other_idx(int current_index);
+BOOLEAN btif_av_is_playing();
+void btif_av_update_multicast_state(int index);
+BOOLEAN btif_av_get_ongoing_multicast();
const char *dump_av_sm_state_name(btif_av_state_t state)
{
default: return "UNKNOWN_EVENT";
}
}
+//TODO.. We will remove this data structure
+static BD_ADDR bd_null= {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
/****************************************************************************
** Local helper functions
static void btif_initiate_av_open_timer_timeout(UNUSED_ATTR void *data)
{
BD_ADDR peer_addr;
- btif_av_connect_req_t connect_req;
/* is there at least one RC connection - There should be */
- if (btif_rc_get_connected_peer(peer_addr)) {
- BTIF_TRACE_DEBUG("%s Issuing connect to the remote RC peer", __FUNCTION__);
- btif_sm_state_t state = btif_sm_get_state(btif_av_cb.sm_handle);
- if ((state == BTIF_AV_STATE_STARTED) || (state == BTIF_AV_STATE_OPENED) ||
- (state == BTIF_AV_STATE_OPENING)) {
- if(bdcmp(btif_av_cb.peer_bda.address, peer_addr))
- {
- BTIF_TRACE_DEBUG("%s A2DP Connection Already UP", __FUNCTION__);
- BTA_AvCloseRc(btif_rc_get_connected_peer_handle(peer_addr));
- BTIF_TRACE_WARNING("%s Disconnecting AVRCP", __FUNCTION__);
- return;
- }
- }
- /* In case of AVRCP connection request, we will initiate SRC connection */
- connect_req.target_bda = (bt_bdaddr_t*)&peer_addr;
- if(bt_av_sink_callbacks != NULL)
- connect_req.uuid = UUID_SERVCLASS_AUDIO_SINK;
- else if(bt_av_src_callbacks != NULL)
- connect_req.uuid = UUID_SERVCLASS_AUDIO_SOURCE;
- btif_sm_dispatch(btif_av_cb.sm_handle, BTIF_AV_CONNECT_REQ_EVT, (char*)&connect_req);
+ /*We have Two Connections.*/
+ if (btif_rc_get_connected_peer(peer_addr))
+ {
+ /*Check if this peer_addr is same as currently connected AV*/
+ if (btif_get_conn_state_of_device(peer_addr) == BTIF_AV_STATE_OPENED)
+ {
+ BTIF_TRACE_DEBUG("AV is already connected");
+ }
+ else
+ {
+ UINT8 rc_handle;
+ int index;
+ /* Multicast: Check if AV slot is available for connection
+ * If not available, AV got connected to different devices.
+ * Disconnect this RC connection without AV connection.
+ */
+ rc_handle = btif_rc_get_connected_peer_handle(peer_addr);
+ index = btif_av_get_valid_idx_for_rc_events(peer_addr, rc_handle);
+ if(index >= btif_max_av_clients)
+ {
+ BTIF_TRACE_ERROR("%s No slot free for AV connection, back off",
+ __FUNCTION__);
+ return;
+ }
+ BTIF_TRACE_DEBUG("%s Issuing connect to the remote RC peer", __FUNCTION__);
+ if(bt_av_sink_callbacks != NULL)
+ btif_queue_connect(UUID_SERVCLASS_AUDIO_SINK, (bt_bdaddr_t*)&peer_addr,
+ connect_int);
+ if(bt_av_src_callbacks != NULL)
+ btif_queue_connect(UUID_SERVCLASS_AUDIO_SOURCE, (bt_bdaddr_t*)&peer_addr,
+ connect_int);
+ }
}
else
{
BTIF_TRACE_ERROR("%s No connected RC peers", __FUNCTION__);
}
+
}
+
/*****************************************************************************
** Static functions
******************************************************************************/
{
if (bt_av_sink_callbacks != NULL) {
HAL_CBACK(bt_av_sink_callbacks, connection_state_cb, state, bd_addr);
- } else if (bt_av_src_callbacks != NULL) {
+ } else if ( bt_av_src_callbacks != NULL) {
HAL_CBACK(bt_av_src_callbacks, connection_state_cb, state, bd_addr);
}
}
**
*******************************************************************************/
-static BOOLEAN btif_av_state_idle_handler(btif_sm_event_t event, void *p_data)
+static BOOLEAN btif_av_state_idle_handler(btif_sm_event_t event, void *p_data, int index)
{
- BTIF_TRACE_IMP("%s event:%s flags %x", __FUNCTION__,
- dump_av_sm_event_name(event), btif_av_cb.flags);
+ char a2dp_role[255] = "false";
+
+ BTIF_TRACE_IMP("%s event:%s flags %x on Index = %d", __FUNCTION__,
+ dump_av_sm_event_name(event), btif_av_cb[index].flags, index);
switch (event)
{
case BTIF_SM_ENTER_EVT:
/* clear the peer_bda */
- memset(&btif_av_cb.peer_bda, 0, sizeof(bt_bdaddr_t));
- btif_av_cb.flags = 0;
- btif_av_cb.edr = 0;
- btif_a2dp_on_idle();
+ BTIF_TRACE_EVENT("IDLE state for index: %d", index);
+ memset(&btif_av_cb[index].peer_bda, 0, sizeof(bt_bdaddr_t));
+ btif_av_cb[index].flags = 0;
+ btif_av_cb[index].edr_3mbps = 0;
+ btif_av_cb[index].edr = 0;
+ btif_av_cb[index].current_playing = FALSE;
+ btif_av_cb[index].is_slave = FALSE;
+ btif_av_cb[index].is_device_playing = FALSE;
+ for (int i = 0; i < btif_max_av_clients; i++)
+ {
+ btif_av_cb[i].dual_handoff = FALSE;
+ }
+ property_get("persist.service.bt.a2dp.sink", a2dp_role, "false");
+ if (!strncmp("false", a2dp_role, 5)) {
+ btif_av_cb[index].peer_sep = AVDT_TSEP_SNK;
+ btif_a2dp_set_peer_sep(AVDT_TSEP_SNK);
+ } else {
+ btif_av_cb[index].peer_sep = AVDT_TSEP_SRC;
+ btif_a2dp_set_peer_sep(AVDT_TSEP_SRC);
+ }
+ /* This API will be called twice at initialization
+ ** Idle can be moved when device is disconnected too.
+ ** Take care of other connected device here.*/
+ if (!btif_av_is_connected())
+ {
+ BTIF_TRACE_EVENT("reset A2dp states in IDLE ");
+ btif_a2dp_on_idle();
+ }
+ else
+ {
+ //There is another AV connection, update current playin
+ BTIF_TRACE_EVENT("reset A2dp states in IDLE ");
+ btif_av_update_current_playing_device(index);
+ }
break;
case BTIF_SM_EXIT_EVT:
break;
case BTA_AV_ENABLE_EVT:
+ BTIF_TRACE_EVENT("AV is enabled now for index: %d", index);
break;
case BTA_AV_REGISTER_EVT:
- btif_av_cb.bta_handle = ((tBTA_AV*)p_data)->registr.hndl;
- break;
-
- case BTA_AV_PENDING_EVT:
- case BTIF_AV_CONNECT_REQ_EVT:
- {
- if (event == BTIF_AV_CONNECT_REQ_EVT)
- {
- memcpy(&btif_av_cb.peer_bda, ((btif_av_connect_req_t*)p_data)->target_bda,
- sizeof(bt_bdaddr_t));
- BTA_AvOpen(btif_av_cb.peer_bda.address, btif_av_cb.bta_handle,
- TRUE, BTA_SEC_AUTHENTICATE, ((btif_av_connect_req_t*)p_data)->uuid);
- }
- else if (event == BTA_AV_PENDING_EVT)
- {
- bdcpy(btif_av_cb.peer_bda.address, ((tBTA_AV*)p_data)->pend.bd_addr);
- if (bt_av_src_callbacks != NULL)
- {
- BTA_AvOpen(btif_av_cb.peer_bda.address, btif_av_cb.bta_handle,
- TRUE, BTA_SEC_AUTHENTICATE, UUID_SERVCLASS_AUDIO_SOURCE);
- }
- if (bt_av_sink_callbacks != NULL)
- {
- BTA_AvOpen(btif_av_cb.peer_bda.address, btif_av_cb.bta_handle,
- TRUE, BTA_SEC_AUTHENTICATE, UUID_SERVCLASS_AUDIO_SINK);
- }
- }
- btif_sm_change_state(btif_av_cb.sm_handle, BTIF_AV_STATE_OPENING);
- } break;
-
- case BTA_AV_RC_OPEN_EVT:
- /* IOP_FIX: Jabra 620 only does RC open without AV open whenever it connects. So
- * as per the AV WP, an AVRC connection cannot exist without an AV connection. Therefore,
- * we initiate an AV connection if an RC_OPEN_EVT is received when we are in AV_CLOSED state.
- * We initiate the AV connection after a small 3s timeout to avoid any collisions from the
- * headsets, as some headsets initiate the AVRC connection first and then
- * immediately initiate the AV connection
- *
- * TODO: We may need to do this only on an AVRCP Play. FixMe
- */
-
- BTIF_TRACE_DEBUG("BTA_AV_RC_OPEN_EVT received w/o AV");
- alarm_set_on_queue(av_open_on_rc_timer,
- BTIF_TIMEOUT_AV_OPEN_ON_RC_MS,
- btif_initiate_av_open_timer_timeout, NULL,
- btu_general_alarm_queue);
- btif_rc_handler(event, p_data);
+ BTIF_TRACE_EVENT("The AV Handle:%d", ((tBTA_AV*)p_data)->registr.hndl);
+ btif_av_cb[index].bta_handle = ((tBTA_AV*)p_data)->registr.hndl;
break;
/*
}
} break;
+ case BTIF_AV_CONNECT_REQ_EVT:
+ /* For outgoing connect stack and app are in sync.
+ */
+ memcpy(&btif_av_cb[index].peer_bda, ((btif_av_connect_req_t*)p_data)->target_bda,
+ sizeof(bt_bdaddr_t));
+ BTA_AvOpen(btif_av_cb[index].peer_bda.address, btif_av_cb[index].bta_handle,
+ TRUE, BTA_SEC_NONE, ((btif_av_connect_req_t*)p_data)->uuid);
+ btif_sm_change_state(btif_av_cb[index].sm_handle, BTIF_AV_STATE_OPENING);
+ break;
+
+ case BTA_AV_PENDING_EVT:
+ case BTA_AV_RC_OPEN_EVT:
+ /* IOP_FIX: Jabra 620 only does RC open without AV open whenever it connects. So
+ * as per the AV WP, an AVRC connection cannot exist without an AV connection. Therefore,
+ * we initiate an AV connection if an RC_OPEN_EVT is received when we are in AV_CLOSED state.
+ * We initiate the AV connection after a small 3s timeout to avoid any collisions from the
+ * headsets, as some headsets initiate the AVRC connection first and then
+ * immediately initiate the AV connection
+ *
+ * TODO: We may need to do this only on an AVRCP Play. FixMe
+ */
+ /* Check if connection allowed with this device */
+ /* In Dual A2dp case, this event can come for both the headsets.
+ * Reject second connection request as we are already checking
+ * for device priority for first device and we cannot queue
+ * incoming connections requests.
+ */
+
+ if (idle_rc_event != 0)
+ {
+ BTIF_TRACE_DEBUG("Processing another RC Event ");
+ return FALSE;
+ }
+ memcpy(&idle_rc_data, ((tBTA_AV*)p_data), sizeof(tBTA_AV));
+ if (event == BTA_AV_RC_OPEN_EVT)
+ {
+ if (((tBTA_AV*)p_data)->rc_open.status == BTA_AV_SUCCESS)
+ {
+ bdcpy(btif_av_cb[index].peer_bda.address,
+ ((tBTA_AV*)p_data)->rc_open.peer_addr);
+ }
+ else
+ {
+ idle_rc_event = 0;
+ return TRUE;
+ }
+ }
+ else
+ {
+ bdcpy(btif_av_cb[index].peer_bda.address, ((tBTA_AV*)p_data)->pend.bd_addr);
+ }
+
+ // Only for AVDTP connection request move to opening state
+ if (event == BTA_AV_PENDING_EVT)
+ btif_sm_change_state(btif_av_cb[index].sm_handle, BTIF_AV_STATE_OPENING);
+
+ if (bt_av_src_callbacks != NULL)
+ {
+ BTIF_TRACE_DEBUG("Calling connection priority callback ");
+ idle_rc_event = event;
+ HAL_CBACK(bt_av_src_callbacks, connection_priority_cb,
+ &(btif_av_cb[index].peer_bda));
+ }
+ if (bt_av_sink_callbacks != NULL)
+ {
+ if(event == BTA_AV_PENDING_EVT)
+ {
+ BTA_AvOpen(btif_av_cb[index].peer_bda.address, btif_av_cb[index].bta_handle,
+ TRUE, BTA_SEC_NONE, UUID_SERVCLASS_AUDIO_SINK);
+ }
+ else if(event == BTA_AV_RC_OPEN_EVT)
+ {
+ alarm_set_on_queue(av_open_on_rc_timer,
+ BTIF_TIMEOUT_AV_OPEN_ON_RC_MS,
+ btif_initiate_av_open_timer_timeout, NULL,
+ btu_general_alarm_queue);
+ btif_rc_handler(event, p_data);
+ }
+ }
+ break;
+
case BTA_AV_OPEN_EVT:
{
+ /* We get this event in Idle State if Signaling
+ * channel is not closed, only Streaming channel was
+ * closed earlier, and now only stream setup process is
+ * initiated.
+ */
tBTA_AV *p_bta_data = (tBTA_AV*)p_data;
btav_connection_state_t state;
- btif_sm_state_t av_state;
BTIF_TRACE_DEBUG("status:%d, edr 0x%x",p_bta_data->open.status,
p_bta_data->open.edr);
if (p_bta_data->open.status == BTA_AV_SUCCESS)
{
state = BTAV_CONNECTION_STATE_CONNECTED;
- av_state = BTIF_AV_STATE_OPENED;
- btif_av_cb.edr = p_bta_data->open.edr;
-
- btif_av_cb.peer_sep = p_bta_data->open.sep;
+ btif_av_cb[index].edr = p_bta_data->open.edr;
+ if (p_bta_data->open.role == HOST_ROLE_SLAVE)
+ {
+ btif_av_cb[index].is_slave = TRUE;
+ }
+ btif_av_cb[index].peer_sep = p_bta_data->open.sep;
btif_a2dp_set_peer_sep(p_bta_data->open.sep);
+
+ if (p_bta_data->open.edr & BTA_AV_EDR_3MBPS)
+ {
+ BTIF_TRACE_DEBUG("remote supports 3 mbps");
+ btif_av_cb[index].edr_3mbps = TRUE;
+ }
+
+ bdcpy(btif_av_cb[index].peer_bda.address, ((tBTA_AV*)p_data)->open.bd_addr);
}
else
{
BTIF_TRACE_WARNING("BTA_AV_OPEN_EVT::FAILED status: %d",
p_bta_data->open.status );
state = BTAV_CONNECTION_STATE_DISCONNECTED;
- av_state = BTIF_AV_STATE_IDLE;
}
- /* inform the application of the event */
- btif_report_connection_state(state, &(btif_av_cb.peer_bda));
- /* change state to open/idle based on the status */
- btif_sm_change_state(btif_av_cb.sm_handle, av_state);
- if (btif_av_cb.peer_sep == AVDT_TSEP_SNK)
+ /* change state to open based on the status */
+ if (p_bta_data->open.status == BTA_AV_SUCCESS)
+ {
+ /* inform the application of the event */
+ btif_report_connection_state(state, &(btif_av_cb[index].peer_bda));
+ btif_sm_change_state(btif_av_cb[index].sm_handle, BTIF_AV_STATE_OPENED);
+ /* BTIF AV State updated, now check
+ * and update multicast state
+ */
+ btif_av_update_multicast_state(index);
+ }
+
+ if (btif_av_cb[index].peer_sep == AVDT_TSEP_SNK)
{
/* if queued PLAY command, send it now */
btif_rc_check_handle_pending_play(p_bta_data->open.bd_addr,
(p_bta_data->open.status == BTA_AV_SUCCESS));
}
- else if ((btif_av_cb.peer_sep == AVDT_TSEP_SRC) &&
+ else if ((btif_av_cb[index].peer_sep == AVDT_TSEP_SRC) &&
(p_bta_data->open.status == BTA_AV_SUCCESS))
{
/* Bring up AVRCP connection too */
- BTA_AvOpenRc(btif_av_cb.bta_handle);
+ BTA_AvOpenRc(btif_av_cb[index].bta_handle);
}
btif_queue_advance();
} break;
**
*******************************************************************************/
-static BOOLEAN btif_av_state_opening_handler(btif_sm_event_t event, void *p_data)
+static BOOLEAN btif_av_state_opening_handler(btif_sm_event_t event, void *p_data, int index)
{
- BTIF_TRACE_IMP("%s event:%s flags %x", __FUNCTION__,
- dump_av_sm_event_name(event), btif_av_cb.flags);
-
- if (event == BTA_AV_RC_OPEN_EVT)
- {
- tBTA_AV *p_av = (tBTA_AV*)p_data;
- if(bdcmp(btif_av_cb.peer_bda.address, p_av->rc_open.peer_addr))
- {
- BTIF_TRACE_WARNING("%s A2dp connected to other device, close this Avrcp", __FUNCTION__);
- BTA_AvCloseRc(p_av->rc_open.rc_handle);
- }
- else
- {
- BTIF_TRACE_DEBUG("%s A2dp connected to same device, continue with Avrcp", __FUNCTION__);
- }
- }
-
+ int i;
+ BTIF_TRACE_IMP("%s event:%s flags %x on index = %d", __FUNCTION__,
+ dump_av_sm_event_name(event), btif_av_cb[index].flags, index);
switch (event)
{
case BTIF_SM_ENTER_EVT:
/* inform the application that we are entering connecting state */
- btif_report_connection_state(BTAV_CONNECTION_STATE_CONNECTING, &(btif_av_cb.peer_bda));
+ if (bt_av_sink_callbacks != NULL)
+ {
+ HAL_CBACK(bt_av_sink_callbacks, connection_state_cb,
+ BTAV_CONNECTION_STATE_CONNECTING, &(btif_av_cb[index].peer_bda));
+ }
+ else if (bt_av_src_callbacks != NULL)
+ {
+ HAL_CBACK(bt_av_src_callbacks, connection_state_cb,
+ BTAV_CONNECTION_STATE_CONNECTING, &(btif_av_cb[index].peer_bda));
+ }
break;
case BTIF_SM_EXIT_EVT:
case BTA_AV_REJECT_EVT:
BTIF_TRACE_DEBUG(" Received BTA_AV_REJECT_EVT ");
- btif_report_connection_state(BTAV_CONNECTION_STATE_DISCONNECTED, &(btif_av_cb.peer_bda));
- btif_sm_change_state(btif_av_cb.sm_handle, BTIF_AV_STATE_IDLE);
+ btif_report_connection_state(BTAV_CONNECTION_STATE_DISCONNECTED,
+ &(btif_av_cb[index].peer_bda));
+ btif_sm_change_state(btif_av_cb[index].sm_handle, BTIF_AV_STATE_IDLE);
break;
case BTA_AV_OPEN_EVT:
tBTA_AV *p_bta_data = (tBTA_AV*)p_data;
btav_connection_state_t state;
btif_sm_state_t av_state;
- BTIF_TRACE_DEBUG("status:%d, edr 0x%x",p_bta_data->open.status,
- p_bta_data->open.edr);
+ BTIF_TRACE_DEBUG("status:%d, edr 0x%x, role: 0x%x",p_bta_data->open.status,
+ p_bta_data->open.edr, p_bta_data->open.role);
if (p_bta_data->open.status == BTA_AV_SUCCESS)
{
state = BTAV_CONNECTION_STATE_CONNECTED;
av_state = BTIF_AV_STATE_OPENED;
- btif_av_cb.edr = p_bta_data->open.edr;
-
- btif_av_cb.peer_sep = p_bta_data->open.sep;
+ btif_av_cb[index].edr = p_bta_data->open.edr;
+ if (p_bta_data->open.role == HOST_ROLE_SLAVE)
+ {
+ btif_av_cb[index].is_slave = TRUE;
+ }
+ btif_av_cb[index].peer_sep = p_bta_data->open.sep;
btif_a2dp_set_peer_sep(p_bta_data->open.sep);
+ if (p_bta_data->open.edr & BTA_AV_EDR_3MBPS)
+ {
+ BTIF_TRACE_DEBUG("remote supports 3 mbps");
+ btif_av_cb[index].edr_3mbps = TRUE;
+ }
}
else
{
BTIF_TRACE_WARNING("BTA_AV_OPEN_EVT::FAILED status: %d",
p_bta_data->open.status );
+ /* Multicast: Check if connected to AVRC only device
+ * disconnect when Dual A2DP/Multicast is supported.
+ */
BD_ADDR peer_addr;
if ((btif_rc_get_connected_peer(peer_addr))
- &&(!bdcmp(btif_av_cb.peer_bda.address, peer_addr)))
+ &&(!bdcmp(btif_av_cb[index].peer_bda.address, peer_addr)))
{
- /*
- * Disconnect AVRCP connection, if
- * A2DP conneciton failed, for any reason
+ /* Disconnect AVRCP connection, if A2DP
+ * conneciton failed, for any reason
*/
BTIF_TRACE_WARNING(" Disconnecting AVRCP ");
BTA_AvCloseRc(btif_rc_get_connected_peer_handle(peer_addr));
}
/* inform the application of the event */
- btif_report_connection_state(state, &(btif_av_cb.peer_bda));
+ btif_report_connection_state(state, &(btif_av_cb[index].peer_bda));
/* change state to open/idle based on the status */
- btif_sm_change_state(btif_av_cb.sm_handle, av_state);
- if (btif_av_cb.peer_sep == AVDT_TSEP_SNK)
- {
- /* if queued PLAY command, send it now */
- btif_rc_check_handle_pending_play(p_bta_data->open.bd_addr,
- (p_bta_data->open.status == BTA_AV_SUCCESS));
- }
- else if ((btif_av_cb.peer_sep == AVDT_TSEP_SRC) &&
- (p_bta_data->open.status == BTA_AV_SUCCESS))
+ btif_sm_change_state(btif_av_cb[index].sm_handle, av_state);
+ /* Check if the other connected AV is playing,
+ * If YES, trigger DUAL Handoff. */
+ if (p_bta_data->open.status == BTA_AV_SUCCESS)
{
- /* Bring up AVRCP connection too */
- BTA_AvOpenRc(btif_av_cb.bta_handle);
+ /* BTIF AV State updated, now check
+ * and update multicast state
+ */
+ btif_av_update_multicast_state(index);
+
+ /*This device should be now ready for all next playbacks*/
+ btif_av_cb[index].current_playing = TRUE;
+ if (enable_multicast == FALSE)
+ {
+ for (i = 0; i < btif_max_av_clients; i++)
+ {
+ //Other device is not current playing
+ if (i != index)
+ btif_av_cb[i].current_playing = FALSE;
+ }
+ /* In A2dp Multicast, stack will take care of starting
+ * the stream on newly connected A2dp device. If Handoff
+ * is supported, trigger Handoff here. */
+ if (btif_av_is_playing())
+ {
+ BTIF_TRACE_DEBUG("Trigger Dual A2dp Handoff on %d", index);
+ btif_av_trigger_dual_handoff(TRUE, btif_av_cb[index].peer_bda.address);
+ }
+ }
+ if (btif_av_cb[index].peer_sep == AVDT_TSEP_SNK)
+ {
+ /* if queued PLAY command, send it now */
+ btif_rc_check_handle_pending_play(p_bta_data->open.bd_addr,
+ (p_bta_data->open.status == BTA_AV_SUCCESS));
+ }
+ else if (btif_av_cb[index].peer_sep == AVDT_TSEP_SRC)
+ {
+ /* if queued PLAY command, send it now */
+ btif_rc_check_handle_pending_play(p_bta_data->open.bd_addr, FALSE);
+ /* Bring up AVRCP connection too */
+ BTA_AvOpenRc(btif_av_cb[index].bta_handle);
+ }
}
btif_queue_advance();
} break;
BTIF_TRACE_WARNING("BTIF_AV_SINK_CONFIG_REQ_EVT %d %d", req.sample_rate,
req.channel_count);
- if (btif_av_cb.peer_sep == AVDT_TSEP_SRC && bt_av_sink_callbacks != NULL) {
- HAL_CBACK(bt_av_sink_callbacks, audio_config_cb, &(btif_av_cb.peer_bda),
+ if (btif_av_cb[index].peer_sep == AVDT_TSEP_SRC && bt_av_sink_callbacks != NULL) {
+ HAL_CBACK(bt_av_sink_callbacks, audio_config_cb, &(btif_av_cb[index].peer_bda),
req.sample_rate, req.channel_count);
}
} break;
case BTIF_AV_CONNECT_REQ_EVT:
// Check for device, if same device which moved to opening then ignore callback
- if (memcmp ((bt_bdaddr_t*)p_data, &(btif_av_cb.peer_bda),
- sizeof(btif_av_cb.peer_bda)) == 0)
+ if (memcmp ((bt_bdaddr_t*)p_data, &(btif_av_cb[index].peer_bda),
+ sizeof(btif_av_cb[index].peer_bda)) == 0)
{
BTIF_TRACE_DEBUG("%s: Same device moved to Opening state,ignore Connect Req", __func__);
btif_queue_advance();
case BTA_AV_PENDING_EVT:
// Check for device, if same device which moved to opening then ignore callback
- if (memcmp (((tBTA_AV*)p_data)->pend.bd_addr, &(btif_av_cb.peer_bda),
- sizeof(btif_av_cb.peer_bda)) == 0)
+ if (memcmp (((tBTA_AV*)p_data)->pend.bd_addr, &(btif_av_cb[index].peer_bda),
+ sizeof(btif_av_cb[index].peer_bda)) == 0)
{
BTIF_TRACE_DEBUG("%s: Same device moved to Opening state,ignore Pending Req", __func__);
break;
break;
case BTA_AV_CLOSE_EVT:
- btif_a2dp_on_stopped(NULL);
+ /* avdtp link is closed */
+ /* Check if any other device is playing
+ * and this is not the one.*/
+ if (!btif_av_is_playing())
+ {
+ btif_a2dp_on_stopped(NULL);
+ }
+ /* inform the application that we are disconnected */
btif_report_connection_state(BTAV_CONNECTION_STATE_DISCONNECTED,
- &(btif_av_cb.peer_bda));
- btif_sm_change_state(btif_av_cb.sm_handle, BTIF_AV_STATE_IDLE);
+ &(btif_av_cb[index].peer_bda));
+ btif_sm_change_state(btif_av_cb[index].sm_handle, BTIF_AV_STATE_IDLE);
break;
case BTIF_AV_DISCONNECT_REQ_EVT:
btif_report_connection_state(BTAV_CONNECTION_STATE_DISCONNECTED,
- &(btif_av_cb.peer_bda));
- BTA_AvClose(btif_av_cb.bta_handle);
+ &(btif_av_cb[index].peer_bda));
+ BTA_AvClose(btif_av_cb[index].bta_handle);
btif_queue_advance();
- btif_sm_change_state(btif_av_cb.sm_handle, BTIF_AV_STATE_IDLE);
+ btif_sm_change_state(btif_av_cb[index].sm_handle, BTIF_AV_STATE_IDLE);
+ break;
+
+ case BTA_AV_RC_OPEN_EVT:
+ btif_rc_handler(event, p_data);;
break;
CHECK_RC_EVENT(event, p_data);
**
*******************************************************************************/
-static BOOLEAN btif_av_state_closing_handler(btif_sm_event_t event, void *p_data)
+static BOOLEAN btif_av_state_closing_handler(btif_sm_event_t event, void *p_data, int index)
{
- BTIF_TRACE_IMP("%s event:%s flags %x", __FUNCTION__,
- dump_av_sm_event_name(event), btif_av_cb.flags);
+ BTIF_TRACE_IMP("%s event:%s flags %x and index = %d", __FUNCTION__,
+ dump_av_sm_event_name(event), btif_av_cb[index].flags, index);
switch (event)
{
case BTIF_SM_ENTER_EVT:
- if (btif_av_cb.peer_sep == AVDT_TSEP_SNK)
+ if (btif_av_cb[index].peer_sep == AVDT_TSEP_SNK)
{
- /* immediately stop transmission of frames */
- btif_a2dp_set_tx_flush(TRUE);
- /* wait for audioflinger to stop a2dp */
+ /* Multicast/Soft Hand-off:
+ * If MC/SHO is enabled we need to keep/start playing on
+ * other device.
+ */
+ if (btif_av_is_connected_on_other_idx(index))
+ {
+ if (btif_av_is_playing())
+ {
+ APPL_TRACE_DEBUG("Keep playing on other device");
+ }
+ else
+ {
+ APPL_TRACE_DEBUG("Not playing on other devie: Set Flush");
+ btif_a2dp_set_tx_flush(TRUE);
+ }
+ }
+ else
+ {
+ /* Single connections scenario:
+ * Immediately stop transmission of frames
+ * wait for audioflinger to stop a2dp
+ */
+ btif_a2dp_set_tx_flush(TRUE);
+ }
}
- if (btif_av_cb.peer_sep == AVDT_TSEP_SRC)
+ if (btif_av_cb[index].peer_sep == AVDT_TSEP_SRC)
{
btif_a2dp_set_rx_flush(TRUE);
}
case BTA_AV_STOP_EVT:
case BTIF_AV_STOP_STREAM_REQ_EVT:
- if (btif_av_cb.peer_sep == AVDT_TSEP_SNK)
+ if (btif_av_cb[index].peer_sep == AVDT_TSEP_SNK)
{
- /* immediately flush any pending tx frames while suspend is pending */
- btif_a2dp_set_tx_flush(TRUE);
+ /* Dont stop in DUAL A2dp connections, as
+ * UIPC will keep waiting for Audio CTRL channel
+ * to get closed which is not required in Dual A2dp.
+ * We will stop only when only single A2dp conn is present.*/
+ if (btif_av_is_connected_on_other_idx(index))
+ {
+ if (!btif_av_is_playing())
+ {
+ APPL_TRACE_WARNING("Suspend the AV Data channel");
+ //Flush and close media channel
+ btif_a2dp_set_tx_flush(TRUE);
+ btif_media_task_stop_aa_req();
+ }
+ }
+ else
+ {
+ /* immediately flush any pending tx frames while suspend is pending */
+ APPL_TRACE_WARNING("Stop the AV Data channel");
+ btif_a2dp_set_tx_flush(TRUE);
+ btif_a2dp_on_stopped(NULL);
+ }
}
- if (btif_av_cb.peer_sep == AVDT_TSEP_SRC)
+ if (btif_av_cb[index].peer_sep == AVDT_TSEP_SRC)
{
btif_a2dp_set_rx_flush(TRUE);
+ btif_a2dp_on_stopped(NULL);
}
-
- btif_a2dp_on_stopped(NULL);
break;
case BTIF_SM_EXIT_EVT:
case BTA_AV_CLOSE_EVT:
/* inform the application that we are disconnecting */
- btif_report_connection_state(BTAV_CONNECTION_STATE_DISCONNECTED, &(btif_av_cb.peer_bda));
+ btif_report_connection_state(BTAV_CONNECTION_STATE_DISCONNECTED, &(btif_av_cb[index].peer_bda));
- btif_sm_change_state(btif_av_cb.sm_handle, BTIF_AV_STATE_IDLE);
+ btif_sm_change_state(btif_av_cb[index].sm_handle, BTIF_AV_STATE_IDLE);
break;
/* Handle the RC_CLOSE event for the cleanup */
**
*******************************************************************************/
-static BOOLEAN btif_av_state_opened_handler(btif_sm_event_t event, void *p_data)
+static BOOLEAN btif_av_state_opened_handler(btif_sm_event_t event, void *p_data, int index)
{
tBTA_AV *p_av = (tBTA_AV*)p_data;
- BTIF_TRACE_IMP("%s event:%s flags %x", __FUNCTION__,
- dump_av_sm_event_name(event), btif_av_cb.flags);
+ BTIF_TRACE_IMP("%s event:%s flags %x and index = %d", __FUNCTION__,
+ dump_av_sm_event_name(event), btif_av_cb[index].flags, index);
- if ( (event == BTA_AV_REMOTE_CMD_EVT) && (btif_av_cb.flags & BTIF_AV_FLAG_REMOTE_SUSPEND) &&
+ if ((event == BTA_AV_REMOTE_CMD_EVT) &&
(p_av->remote_cmd.rc_id == BTA_AV_RC_PLAY) )
{
- BTIF_TRACE_EVENT("%s: Resetting remote suspend flag on RC PLAY", __FUNCTION__);
- btif_av_cb.flags &= ~BTIF_AV_FLAG_REMOTE_SUSPEND;
- }
-
- if (event == BTA_AV_RC_OPEN_EVT)
- {
- if(bdcmp(btif_av_cb.peer_bda.address, p_av->rc_open.peer_addr))
- {
- BTIF_TRACE_WARNING("%s A2dp connected to other device, close this Avrcp", __FUNCTION__);
- BTA_AvCloseRc(p_av->rc_open.rc_handle);
- }
- else
+ for (int i = 0; i < btif_max_av_clients; i++)
{
- BTIF_TRACE_DEBUG("%s A2dp connected to same device, continue with Avrcp", __FUNCTION__);
+ if (btif_av_cb[i].flags & BTIF_AV_FLAG_REMOTE_SUSPEND)
+ {
+ BTIF_TRACE_EVENT("%s: Resetting remote suspend flag on RC PLAY",
+ __FUNCTION__);
+ btif_av_cb[i].flags &= ~BTIF_AV_FLAG_REMOTE_SUSPEND;
+ }
}
}
switch (event)
{
case BTIF_SM_ENTER_EVT:
- btif_av_cb.flags &= ~BTIF_AV_FLAG_PENDING_STOP;
- btif_av_cb.flags &= ~BTIF_AV_FLAG_PENDING_START;
+ btif_av_cb[index].flags &= ~BTIF_AV_FLAG_PENDING_STOP;
+ btif_av_cb[index].flags &= ~BTIF_AV_FLAG_PENDING_START;
break;
case BTIF_SM_EXIT_EVT:
- btif_av_cb.flags &= ~BTIF_AV_FLAG_PENDING_START;
+ btif_av_cb[index].flags &= ~BTIF_AV_FLAG_PENDING_START;
break;
case BTIF_AV_START_STREAM_REQ_EVT:
- if (btif_av_cb.peer_sep != AVDT_TSEP_SRC)
- btif_a2dp_setup_codec();
- BTA_AvStart();
- btif_av_cb.flags |= BTIF_AV_FLAG_PENDING_START;
+ /* update multicast state here if new device is connected
+ * after A2dp connection. New A2dp device is connected
+ * whlie playing */
+ btif_av_update_multicast_state(index);
+ if (btif_av_cb[index].peer_sep == AVDT_TSEP_SRC)
+ {
+ BTA_AvStart(btif_av_cb[index].bta_handle);
+ btif_av_cb[index].flags |= BTIF_AV_FLAG_PENDING_START;
+ break;
+ }
+ tBTIF_STATUS status = btif_a2dp_setup_codec();
+ if (status == BTIF_SUCCESS)
+ {
+ int idx = 0;
+ BTA_AvStart(btif_av_cb[index].bta_handle);
+ if (enable_multicast == TRUE)
+ {
+ /* In A2dp Multicast, DUT initiated stream request
+ * should be true for all connected A2dp devices. */
+ for (; idx < btif_max_av_clients; idx++)
+ {
+ btif_av_cb[idx].flags |= BTIF_AV_FLAG_PENDING_START;
+ }
+ }
+ else
+ {
+ btif_av_cb[index].flags |= BTIF_AV_FLAG_PENDING_START;
+ }
+ }
+ else if (status == BTIF_ERROR_SRV_AV_CP_NOT_SUPPORTED)
+ {
+#if defined(BTA_AV_DISCONNECT_IF_NO_SCMS_T) && (BTA_AV_DISCONNECT_IF_NO_SCMS_T == TRUE)
+ BTIF_TRACE_ERROR0("SCMST enabled, disconnect as remote does not support SCMST");
+ BTA_AvDisconnect(btif_av_cb[index].peer_bda.address);
+#else
+ BTIF_TRACE_WARNING("SCMST enabled, connecting to non SCMST SEP");
+ BTA_AvStart(btif_av_cb[index].bta_handle);
+ btif_av_cb[index].flags |= BTIF_AV_FLAG_PENDING_START;
+#endif
+ }
+ else
+ {
+ BTIF_TRACE_ERROR("## AV Disconnect## status : %x",status);
+ BTA_AvDisconnect(btif_av_cb[index].peer_bda.address);
+ }
break;
case BTIF_AV_UPDATE_ENCODER_REQ_EVT:
case BTA_AV_START_EVT:
{
- BTIF_TRACE_EVENT("BTA_AV_START_EVT status %d, suspending %d, init %d",
+ BTIF_TRACE_DEBUG("BTA_AV_START_EVT status %d, suspending %d, init %d",
p_av->start.status, p_av->start.suspending, p_av->start.initiator);
+ BTIF_TRACE_DEBUG("BTA_AV_START_EVT role: %d", p_av->start.role);
+ if (p_av->start.role == HOST_ROLE_SLAVE)
+ {
+ btif_av_cb[index].is_slave = TRUE;
+ }
+ else
+ {
+ // update if we are master after role switch before start
+ btif_av_cb[index].is_slave = FALSE;
+ }
+ /* There can be role switch after device is connected,
+ * hence check for role before starting multicast, and
+ * disable if we are in slave role for any connection
+ */
+ btif_av_update_multicast_state(index);
if ((p_av->start.status == BTA_SUCCESS) && (p_av->start.suspending == TRUE))
return TRUE;
+ /* if remote tries to start a2dp when call is in progress, suspend it right away */
+ if ((!(btif_av_cb[index].flags & BTIF_AV_FLAG_PENDING_START)) && (!btif_hf_is_call_idle())) {
+ BTIF_TRACE_EVENT("%s: trigger suspend as call is in progress!!", __FUNCTION__);
+ btif_dispatch_sm_event(BTIF_AV_SUSPEND_STREAM_REQ_EVT, NULL, 0);
+ }
+
/* if remote tries to start a2dp when DUT is a2dp source
* then suspend. In case a2dp is sink and call is active
* then disconnect the AVDTP channel
*/
- if (!(btif_av_cb.flags & BTIF_AV_FLAG_PENDING_START))
+ if (!(btif_av_cb[index].flags & BTIF_AV_FLAG_PENDING_START))
{
- if (btif_av_cb.peer_sep == AVDT_TSEP_SNK)
+ if (btif_av_cb[index].peer_sep == AVDT_TSEP_SNK)
{
- BTIF_TRACE_EVENT("%s: trigger suspend as remote initiated!!", __FUNCTION__);
- btif_dispatch_sm_event(BTIF_AV_SUSPEND_STREAM_REQ_EVT, NULL, 0);
+ if (enable_multicast)
+ {
+ /* Stack will start the playback on newly connected
+ * A2dp device, if the playback is already happening on
+ * other connected device.*/
+ if (btif_av_is_playing())
+ {
+ /* when HS2 is connected during HS1 playing, stack directly
+ * sends start event hence update encoder so that least L2CAP
+ * MTU is selected.*/
+ //btif_a2dp_update_codec();
+ BTIF_TRACE_DEBUG("%s: A2dp Multicast playback",
+ __FUNCTION__);
+ }
+ /* initiate suspend if start is initiate by remote and multicast
+ * is enabled.
+ * Avoid suspend if stream is started as quick suspend-start
+ * creates IOT issue, seen with SBH50.
+ */
+
+ if (!p_av->start.initiator && !btif_av_is_playing())
+ {
+ BTIF_TRACE_DEBUG("initiate suspend for remote start");
+ btif_dispatch_sm_event(BTIF_AV_SUSPEND_STREAM_REQ_EVT, NULL, 0);
+ }
+ }
+ else
+ {
+ BTIF_TRACE_DEBUG("%s: trigger suspend as remote initiated!!",
+ __FUNCTION__);
+ btif_dispatch_sm_event(BTIF_AV_SUSPEND_STREAM_REQ_EVT, NULL, 0);
+ }
}
}
/* In case peer is A2DP SRC we do not want to ack commands on UIPC*/
- if (btif_av_cb.peer_sep == AVDT_TSEP_SNK)
+ if (btif_av_cb[index].peer_sep == AVDT_TSEP_SNK)
{
if (btif_a2dp_on_started(&p_av->start,
- ((btif_av_cb.flags & BTIF_AV_FLAG_PENDING_START) != 0)))
+ ((btif_av_cb[index].flags & BTIF_AV_FLAG_PENDING_START) != 0)))
{
/* only clear pending flag after acknowledgement */
- btif_av_cb.flags &= ~BTIF_AV_FLAG_PENDING_START;
+ btif_av_cb[index].flags &= ~BTIF_AV_FLAG_PENDING_START;
}
}
/* remain in open state if status failed */
+ /* Multicast-soft Handoff:
+ * START failed, cleanup Handoff flag.
+ */
if (p_av->start.status != BTA_AV_SUCCESS)
+ {
+ int i;
+
+ for (i = 0; i < btif_max_av_clients; i++)
+ {
+ btif_av_cb[i].dual_handoff = FALSE;
+ }
return FALSE;
+ }
- if (btif_av_cb.peer_sep == AVDT_TSEP_SRC)
+#ifndef AVK_BACKPORT
+ if (btif_av_cb[index].peer_sep == AVDT_TSEP_SRC)
{
btif_a2dp_set_rx_flush(FALSE); /* remove flush state, ready for streaming*/
}
+#endif
/* change state to started, send acknowledgement if start is pending */
- if (btif_av_cb.flags & BTIF_AV_FLAG_PENDING_START) {
- if (btif_av_cb.peer_sep == AVDT_TSEP_SNK)
+ if (btif_av_cb[index].flags & BTIF_AV_FLAG_PENDING_START) {
+ if (btif_av_cb[index].peer_sep == AVDT_TSEP_SNK)
btif_a2dp_on_started(NULL, TRUE);
/* pending start flag will be cleared when exit current state */
}
- btif_sm_change_state(btif_av_cb.sm_handle, BTIF_AV_STATE_STARTED);
+ btif_sm_change_state(btif_av_cb[index].sm_handle, BTIF_AV_STATE_STARTED);
} break;
case BTIF_AV_DISCONNECT_REQ_EVT:
- BTA_AvClose(btif_av_cb.bta_handle);
- if (btif_av_cb.peer_sep == AVDT_TSEP_SRC) {
- BTA_AvCloseRc(btif_av_cb.bta_handle);
+ BTA_AvClose(btif_av_cb[index].bta_handle);
+ if (btif_av_cb[index].peer_sep == AVDT_TSEP_SRC) {
+ BTA_AvCloseRc(btif_av_cb[index].bta_handle);
}
/* inform the application that we are disconnecting */
- btif_report_connection_state(BTAV_CONNECTION_STATE_DISCONNECTING, &(btif_av_cb.peer_bda));
+ btif_report_connection_state(BTAV_CONNECTION_STATE_DISCONNECTING, &(btif_av_cb[index].peer_bda));
break;
case BTA_AV_CLOSE_EVT:
/* avdtp link is closed */
- btif_a2dp_on_stopped(NULL);
+ /*Dont close the A2dp when Dual playback is happening*/
+ if (btif_av_is_connected_on_other_idx(index))
+ {
+ APPL_TRACE_WARNING("Conn is closing,close AV data channel");
+ if (!btif_av_is_playing())
+ {
+ APPL_TRACE_WARNING("Suspend the AV Data channel");
+ /* ensure tx frames are immediately suspended */
+ btif_a2dp_set_tx_flush(TRUE);
+ btif_media_task_stop_aa_req();
+ }
+ }
+ else
+ {
+ APPL_TRACE_WARNING("Stop the AV Data channel");
+ btif_a2dp_on_stopped(NULL);
+ }
/* inform the application that we are disconnected */
- btif_report_connection_state(BTAV_CONNECTION_STATE_DISCONNECTED, &(btif_av_cb.peer_bda));
+ btif_report_connection_state(BTAV_CONNECTION_STATE_DISCONNECTED,
+ &(btif_av_cb[index].peer_bda));
/* change state to idle, send acknowledgement if start is pending */
- if (btif_av_cb.flags & BTIF_AV_FLAG_PENDING_START) {
+ if (btif_av_cb[index].flags & BTIF_AV_FLAG_PENDING_START) {
btif_a2dp_ack_fail();
/* pending start flag will be cleared when exit current state */
}
- btif_sm_change_state(btif_av_cb.sm_handle, BTIF_AV_STATE_IDLE);
+
+ btif_sm_change_state(btif_av_cb[index].sm_handle, BTIF_AV_STATE_IDLE);
break;
case BTA_AV_RECONFIG_EVT:
- if((btif_av_cb.flags & BTIF_AV_FLAG_PENDING_START) &&
+ if((btif_av_cb[index].flags & BTIF_AV_FLAG_PENDING_START) &&
(p_av->reconfig.status == BTA_AV_SUCCESS))
{
APPL_TRACE_WARNING("reconfig done BTA_AVstart()");
- BTA_AvStart();
+ BTA_AvStart(btif_av_cb[index].bta_handle);
}
- else if(btif_av_cb.flags & BTIF_AV_FLAG_PENDING_START)
+ else if(btif_av_cb[index].flags & BTIF_AV_FLAG_PENDING_START)
{
- btif_av_cb.flags &= ~BTIF_AV_FLAG_PENDING_START;
+ btif_av_cb[index].flags &= ~BTIF_AV_FLAG_PENDING_START;
btif_a2dp_ack_fail();
}
break;
case BTIF_AV_CONNECT_REQ_EVT:
- if (memcmp ((bt_bdaddr_t*)p_data, &(btif_av_cb.peer_bda),
- sizeof(btif_av_cb.peer_bda)) == 0)
+ if (memcmp ((bt_bdaddr_t*)p_data, &(btif_av_cb[index].peer_bda),
+ sizeof(btif_av_cb[index].peer_bda)) == 0)
{
BTIF_TRACE_DEBUG("%s: Ignore BTIF_AV_CONNECT_REQ_EVT for same device", __func__);
}
BTIF_TRACE_ERROR("BTIF_AV_OFFLOAD_START_REQ_EVT: Stream not Started Opened");
break;
+ case BTA_AV_RC_OPEN_EVT:
+ btif_av_check_rc_connection_priority(p_data);
+ break;
CHECK_RC_EVENT(event, p_data);
default:
**
*******************************************************************************/
-static BOOLEAN btif_av_state_started_handler(btif_sm_event_t event, void *p_data)
+static BOOLEAN btif_av_state_started_handler(btif_sm_event_t event, void *p_data, int index)
{
tBTA_AV *p_av = (tBTA_AV*)p_data;
+ btif_sm_state_t state = BTIF_AV_STATE_IDLE;
+ int i;
- BTIF_TRACE_IMP("%s event:%s flags %x", __FUNCTION__,
- dump_av_sm_event_name(event), btif_av_cb.flags);
-
-
- if (event == BTA_AV_RC_OPEN_EVT)
- {
- if(bdcmp(btif_av_cb.peer_bda.address, p_av->rc_open.peer_addr))
- {
- BTIF_TRACE_WARNING("%s A2dp connected to other device, close this Avrcp", __FUNCTION__);
- BTA_AvCloseRc(p_av->rc_open.rc_handle);
- }
- else
- {
- BTIF_TRACE_DEBUG("%s A2dp connected to same device, continue with Avrcp", __FUNCTION__);
- }
- }
+ BTIF_TRACE_IMP("%s event:%s flags %x index =%d", __FUNCTION__,
+ dump_av_sm_event_name(event), btif_av_cb[index].flags, index);
switch (event)
{
case BTIF_SM_ENTER_EVT:
-
/* we are again in started state, clear any remote suspend flags */
- btif_av_cb.flags &= ~BTIF_AV_FLAG_REMOTE_SUSPEND;
+ btif_av_cb[index].flags &= ~BTIF_AV_FLAG_REMOTE_SUSPEND;
- /**
- * Report to components above that we have entered the streaming
- * stage, this should usually be followed by focus grant.
- * see update_audio_focus_state()
- */
- btif_report_audio_state(BTAV_AUDIO_STATE_STARTED, &(btif_av_cb.peer_bda));
+ btif_report_audio_state(BTAV_AUDIO_STATE_STARTED, &(btif_av_cb[index].peer_bda));
+ btif_av_cb[index].is_device_playing = TRUE;
/* increase the a2dp consumer task priority temporarily when start
** audio playing, to avoid overflow the audio packet queue. */
adjust_priority_a2dp(TRUE);
-
+#ifdef AVK_BACKPORT
+ if (btif_av_cb[index].peer_sep == AVDT_TSEP_SRC)
+ {
+ btif_av_request_audio_focus(TRUE);
+ }
+#endif
+ //Clear Dual Handoff for all SCBs
+ for (i = 0; i < btif_max_av_clients; i++)
+ {
+ btif_av_cb[i].dual_handoff = FALSE;
+ //Other device is not current playing
+ if (i != index)
+ btif_av_cb[i].current_playing = FALSE;
+ }
+ //This is latest device to play now
+ btif_av_cb[index].current_playing = TRUE;
break;
case BTIF_SM_EXIT_EVT:
case BTIF_AV_START_STREAM_REQ_EVT:
/* we were remotely started, just ack back the local request */
- if (btif_av_cb.peer_sep == AVDT_TSEP_SNK)
+ if (btif_av_cb[index].peer_sep == AVDT_TSEP_SNK)
btif_a2dp_on_started(NULL, TRUE);
break;
case BTIF_AV_SUSPEND_STREAM_REQ_EVT:
/* set pending flag to ensure btif task is not trying to restart
- stream while suspend is in progress */
- btif_av_cb.flags |= BTIF_AV_FLAG_LOCAL_SUSPEND_PENDING;
+ * stream while suspend is in progress.
+ * Multicast: If streaming is happening on both devices, we need
+ * to update flag for both connections as SUSPEND request will
+ * be sent to only one stream as internally BTA takes care of
+ * suspending both streams.
+ */
+ for(i = 0; i < btif_max_av_clients; i++)
+ {
+ state = btif_sm_get_state(btif_av_cb[i].sm_handle);
+ if (state == BTIF_AV_STATE_STARTED)
+ {
+ btif_av_cb[i].flags |= BTIF_AV_FLAG_LOCAL_SUSPEND_PENDING;
+ }
+ }
/* if we were remotely suspended but suspend locally, local suspend
always overrides */
- btif_av_cb.flags &= ~BTIF_AV_FLAG_REMOTE_SUSPEND;
+ btif_av_cb[index].flags &= ~BTIF_AV_FLAG_REMOTE_SUSPEND;
- if (btif_av_cb.peer_sep == AVDT_TSEP_SNK)
+ if (btif_av_cb[index].peer_sep == AVDT_TSEP_SNK)
{
/* immediately stop transmission of frames while suspend is pending */
btif_a2dp_set_tx_flush(TRUE);
}
- if (btif_av_cb.peer_sep == AVDT_TSEP_SRC) {
+ if (btif_av_cb[index].peer_sep == AVDT_TSEP_SRC) {
btif_a2dp_set_rx_flush(TRUE);
btif_a2dp_on_stopped(NULL);
}
- BTA_AvStop(TRUE);
+ BTA_AvStop(TRUE, btif_av_cb[index].bta_handle);
break;
case BTIF_AV_DISCONNECT_REQ_EVT:
+ //Now it is not the current playing
+ btif_av_cb[index].current_playing = FALSE;
+ btif_av_update_current_playing_device(index);
+ btif_rc_clear_priority(btif_av_cb[index].peer_bda.address);
/* request avdtp to close */
- BTA_AvClose(btif_av_cb.bta_handle);
- if (btif_av_cb.peer_sep == AVDT_TSEP_SRC) {
- BTA_AvCloseRc(btif_av_cb.bta_handle);
+ BTA_AvClose(btif_av_cb[index].bta_handle);
+ if (btif_av_cb[index].peer_sep == AVDT_TSEP_SRC) {
+ BTA_AvCloseRc(btif_av_cb[index].bta_handle);
}
/* inform the application that we are disconnecting */
- btif_report_connection_state(BTAV_CONNECTION_STATE_DISCONNECTING, &(btif_av_cb.peer_bda));
+ btif_report_connection_state(BTAV_CONNECTION_STATE_DISCONNECTING, &(btif_av_cb[index].peer_bda));
/* wait in closing state until fully closed */
- btif_sm_change_state(btif_av_cb.sm_handle, BTIF_AV_STATE_CLOSING);
+ btif_sm_change_state(btif_av_cb[index].sm_handle, BTIF_AV_STATE_CLOSING);
break;
case BTA_AV_SUSPEND_EVT:
BTIF_TRACE_EVENT("BTA_AV_SUSPEND_EVT status %d, init %d",
p_av->suspend.status, p_av->suspend.initiator);
+ //Check if this suspend is due to DUAL_Handoff
+ if ((btif_av_cb[index].dual_handoff) &&
+ (p_av->suspend.status == BTA_AV_SUCCESS))
+ {
+ BTIF_TRACE_EVENT("BTA_AV_SUSPEND_EVT: Dual handoff");
+ btif_dispatch_sm_event(BTIF_AV_START_STREAM_REQ_EVT, NULL, 0);
+ }
+ if (p_av->suspend.initiator != TRUE)
+ {
+ /* remote suspend, notify HAL and await audioflinger to
+ * suspend/stop stream
+ * set remote suspend flag to block media task from restarting
+ * stream only if we did not already initiate a local suspend
+ * set remote suspend flag before suspending stream as in race conditions
+ * when stream is suspended, but flag is things ge tossed up
+ */
+ BTIF_TRACE_EVENT("Clear before suspending");
+ if ((btif_av_cb[index].flags & BTIF_AV_FLAG_LOCAL_SUSPEND_PENDING) == 0)
+ btif_av_cb[index].flags |= BTIF_AV_FLAG_REMOTE_SUSPEND;
+ for (int i = 0; i < btif_max_av_clients; i++)
+ {
+ if ((i != index) && btif_av_get_ongoing_multicast())
+ {
+ multicast_disabled = TRUE;
+ btif_av_update_multicast_state(index);
+ BTIF_TRACE_EVENT("Initiate suspend for other HS also");
+ btif_sm_dispatch(btif_av_cb[i].sm_handle,
+ BTIF_AV_SUSPEND_STREAM_REQ_EVT, NULL);
+ }
+ }
+ }
/* a2dp suspended, stop media task until resumed */
- btif_a2dp_on_suspended(&p_av->suspend);
+ /* Multicast: If streaming on other device, don't call onsuspended
+ * as it unblocks the audio process and audio process may send
+ * subsequent commands and create problem during the time where we
+ * still did not receive response for SUSPEND sent to other device.
+ * Keep the suspend failure handling untouched and handle
+ * only success case to check and avoid calling onsuspended.
+ */
+ if ((p_av->suspend.status != BTA_AV_SUCCESS) ||
+ !btif_av_is_playing_on_other_idx(index))
+ {
+ btif_a2dp_on_suspended(&p_av->suspend);
+ }
+ else if(btif_av_is_playing_on_other_idx(index))
+ {
+ BTIF_TRACE_DEBUG("Other device not suspended, don't ack the suspend");
+ }
/* if not successful, remain in current state */
if (p_av->suspend.status != BTA_AV_SUCCESS)
{
- btif_av_cb.flags &= ~BTIF_AV_FLAG_LOCAL_SUSPEND_PENDING;
+ btif_av_cb[index].flags &= ~BTIF_AV_FLAG_LOCAL_SUSPEND_PENDING;
- if (btif_av_cb.peer_sep == AVDT_TSEP_SNK)
+ if (btif_av_cb[index].peer_sep == AVDT_TSEP_SNK)
{
/* suspend failed, reset back tx flush state */
btif_a2dp_set_tx_flush(FALSE);
if (p_av->suspend.initiator != TRUE)
{
- /* remote suspend, notify HAL and await audioflinger to
- suspend/stop stream */
-
- /* set remote suspend flag to block media task from restarting
- stream only if we did not already initiate a local suspend */
- if ((btif_av_cb.flags & BTIF_AV_FLAG_LOCAL_SUSPEND_PENDING) == 0)
- btif_av_cb.flags |= BTIF_AV_FLAG_REMOTE_SUSPEND;
-
- btif_report_audio_state(BTAV_AUDIO_STATE_REMOTE_SUSPEND, &(btif_av_cb.peer_bda));
+ btif_report_audio_state(BTAV_AUDIO_STATE_REMOTE_SUSPEND, &(btif_av_cb[index].peer_bda));
}
else
{
- btif_report_audio_state(BTAV_AUDIO_STATE_STOPPED, &(btif_av_cb.peer_bda));
+ btif_report_audio_state(BTAV_AUDIO_STATE_REMOTE_SUSPEND, &(btif_av_cb[index].peer_bda));
}
-
- btif_sm_change_state(btif_av_cb.sm_handle, BTIF_AV_STATE_OPENED);
+ btif_av_cb[index].is_device_playing = FALSE;
+ btif_sm_change_state(btif_av_cb[index].sm_handle, BTIF_AV_STATE_OPENED);
/* suspend completed and state changed, clear pending status */
- btif_av_cb.flags &= ~BTIF_AV_FLAG_LOCAL_SUSPEND_PENDING;
+ btif_av_cb[index].flags &= ~BTIF_AV_FLAG_LOCAL_SUSPEND_PENDING;
break;
case BTA_AV_STOP_EVT:
- btif_av_cb.flags |= BTIF_AV_FLAG_PENDING_STOP;
- btif_a2dp_on_stopped(&p_av->suspend);
+ btif_av_cb[index].flags |= BTIF_AV_FLAG_PENDING_STOP;
+ btif_av_cb[index].current_playing = FALSE;
+ if (btif_av_is_connected_on_other_idx(index))
+ {
+ if (enable_multicast == FALSE)
+ {
+ APPL_TRACE_WARNING("other Idx is connected, move to SUSPENDED");
+ btif_rc_send_pause_command();
+ btif_a2dp_on_stopped(&p_av->suspend);
+ }
+ }
+ else
+ {
+ APPL_TRACE_WARNING("Stop the AV Data channel as no connection is present");
+ btif_a2dp_on_stopped(&p_av->suspend);
+ }
+ btif_av_cb[index].is_device_playing = FALSE;
- btif_report_audio_state(BTAV_AUDIO_STATE_STOPPED, &(btif_av_cb.peer_bda));
+ btif_report_audio_state(BTAV_AUDIO_STATE_STOPPED, &(btif_av_cb[index].peer_bda));
/* if stop was successful, change state to open */
if (p_av->suspend.status == BTA_AV_SUCCESS)
- btif_sm_change_state(btif_av_cb.sm_handle, BTIF_AV_STATE_OPENED);
+ btif_sm_change_state(btif_av_cb[index].sm_handle, BTIF_AV_STATE_OPENED);
break;
case BTA_AV_CLOSE_EVT:
- btif_av_cb.flags |= BTIF_AV_FLAG_PENDING_STOP;
+ btif_av_cb[index].flags |= BTIF_AV_FLAG_PENDING_STOP;
/* avdtp link is closed */
+ APPL_TRACE_WARNING("Stop the AV Data channel");
btif_a2dp_on_stopped(NULL);
/* inform the application that we are disconnected */
- btif_report_connection_state(BTAV_CONNECTION_STATE_DISCONNECTED, &(btif_av_cb.peer_bda));
+ btif_report_connection_state(BTAV_CONNECTION_STATE_DISCONNECTED,
+ &(btif_av_cb[index].peer_bda));
+
+ btif_sm_change_state(btif_av_cb[index].sm_handle, BTIF_AV_STATE_IDLE);
+ break;
- btif_sm_change_state(btif_av_cb.sm_handle, BTIF_AV_STATE_IDLE);
+ case BTA_AV_RC_OPEN_EVT:
+ btif_av_check_rc_connection_priority(p_data);
break;
case BTIF_AV_OFFLOAD_START_REQ_EVT:
- BTA_AvOffloadStart(btif_av_cb.bta_handle);
+ BTA_AvOffloadStart(btif_av_cb[index].bta_handle);
break;
case BTA_AV_OFFLOAD_START_RSP_EVT:
-
btif_a2dp_on_offload_started(p_av->status);
break;
return TRUE;
}
-/*****************************************************************************
-** Local event handlers
-******************************************************************************/
-
-static void btif_av_handle_event(UINT16 event, char* p_param)
-{
- switch(event)
- {
- case BTIF_AV_CLEANUP_REQ_EVT:
- BTIF_TRACE_EVENT("%s: BTIF_AV_CLEANUP_REQ_EVT", __FUNCTION__);
- btif_a2dp_stop_media_task();
- break;
-
- default:
- btif_sm_dispatch(btif_av_cb.sm_handle, event, (void*)p_param);
- btif_av_event_free_data(event, p_param);
- }
-}
void btif_av_event_deep_copy(UINT16 event, char *p_dest, char *p_src)
{
}
}
+/*****************************************************************************
+** Local event handlers
+******************************************************************************/
+
+static void btif_av_handle_event(UINT16 event, char* p_param)
+{
+ int index = 0;
+ tBTA_AV *p_bta_data = (tBTA_AV*)p_param;
+ bt_bdaddr_t * bt_addr;
+ UINT8 role;
+ int uuid;
+
+ switch (event)
+ {
+ case BTIF_AV_INIT_REQ_EVT:
+ BTIF_TRACE_DEBUG("%s: BTIF_AV_INIT_REQ_EVT", __FUNCTION__);
+ if(btif_a2dp_start_media_task())
+ btif_a2dp_on_init();
+ break;
+ /*events from Upper layer and Media Task*/
+ case BTIF_AV_CLEANUP_REQ_EVT: /*Clean up to be called on default index*/
+ BTIF_TRACE_DEBUG("%s: BTIF_AV_CLEANUP_REQ_EVT", __FUNCTION__);
+ uuid = (int)*p_param;
+ if (uuid == BTA_A2DP_SOURCE_SERVICE_ID)
+ {
+ if (bt_av_src_callbacks)
+ {
+ bt_av_src_callbacks = NULL;
+ if (bt_av_sink_callbacks != NULL)
+ break;
+ }
+ }
+ else
+ {
+ if (bt_av_sink_callbacks)
+ {
+ bt_av_sink_callbacks = NULL;
+ if (bt_av_src_callbacks != NULL)
+ break;
+ }
+ }
+
+ btif_a2dp_stop_media_task();
+ return;
+ case BTIF_AV_CONNECT_REQ_EVT:
+ break;
+ case BTIF_AV_DISCONNECT_REQ_EVT:
+ /*Bd address passed should help us in getting the handle*/
+ bt_addr = (bt_bdaddr_t *)p_param;
+ index = btif_av_idx_by_bdaddr(bt_addr->address);
+ break;
+ case BTIF_AV_UPDATE_ENCODER_REQ_EVT:
+ case BTIF_AV_START_STREAM_REQ_EVT:
+ /* Get the last connected device on which START can be issued
+ * Get the Dual A2dp Handoff Device first, if none is present,
+ * go for lastest connected.
+ * In A2dp Multicast, the index selected can be any of the
+ * connected device. Stack will ensure to START the steaming
+ * on both the devices. */
+ index = btif_get_latest_device_idx_to_start();
+ break;
+ case BTIF_AV_STOP_STREAM_REQ_EVT:
+ case BTIF_AV_SUSPEND_STREAM_REQ_EVT:
+ /*Should be handled by current STARTED*/
+ index = btif_get_latest_playing_device_idx();
+ break;
+ /*Events from the stack, BTA*/
+ case BTA_AV_ENABLE_EVT:
+ index = 0;
+ break;
+ case BTA_AV_REGISTER_EVT:
+ index = HANDLE_TO_INDEX(p_bta_data->registr.hndl);
+ break;
+ case BTA_AV_OPEN_EVT:
+ index = HANDLE_TO_INDEX(p_bta_data->open.hndl);
+ break;
+ case BTA_AV_ROLE_CHANGED_EVT:
+ index = HANDLE_TO_INDEX(p_bta_data->role_changed.hndl);
+ role = p_bta_data->role_changed.new_role;
+ BTIF_TRACE_EVENT("Role change: 0x%x: new role: %s",
+ p_bta_data->role_changed.hndl, (role == HOST_ROLE_SLAVE) ? "Slave" : "Master");
+ if (index >= 0 && index < btif_max_av_clients)
+ {
+ btif_av_cb[index].is_slave = (role == HOST_ROLE_SLAVE) ? TRUE : FALSE;
+ btif_av_update_multicast_state(index);
+ }
+ else
+ {
+ BTIF_TRACE_ERROR("%s: Invalid index for connection", __FUNCTION__);
+ }
+ return;
+ case BTA_AV_PENDING_EVT:
+ index = HANDLE_TO_INDEX(p_bta_data->pend.hndl);
+ break;
+ case BTA_AV_REJECT_EVT:
+ index = HANDLE_TO_INDEX(p_bta_data->reject.hndl);
+ break;
+ case BTA_AV_STOP_EVT:
+ index = HANDLE_TO_INDEX(p_bta_data->suspend.hndl);
+ break;
+ case BTA_AV_CLOSE_EVT:
+ index = HANDLE_TO_INDEX(p_bta_data->close.hndl);
+ break;
+ case BTA_AV_START_EVT:
+ index = HANDLE_TO_INDEX(p_bta_data->start.hndl);
+ break;
+ case BTA_AV_RECONFIG_EVT:
+ index = HANDLE_TO_INDEX(p_bta_data->reconfig.hndl);
+ break;
+ case BTA_AV_SUSPEND_EVT:
+ index = HANDLE_TO_INDEX(p_bta_data->suspend.hndl);
+ break;
+
+ /* Handle all RC events on default index. RC handling should take
+ * care of the events. All events come with BD Address
+ * Handled well in AV Opening, opened and started state
+ * AV Idle handler needs to take care of this event properly.
+ */
+ case BTA_AV_RC_OPEN_EVT:
+ index = btif_av_get_valid_idx_for_rc_events(p_bta_data->rc_open.peer_addr,
+ p_bta_data->rc_open.rc_handle);
+ break;
+ case BTA_AV_RC_CLOSE_EVT:
+ /* If there is no entry in the connection table
+ * RC handler has to be called for cleanup.
+ * Directly call the RC handler as we cannot
+ * associate any AV handle to it.
+ */
+ index = btif_av_idx_by_bdaddr(p_bta_data->rc_open.peer_addr);
+ if (index == btif_max_av_clients)
+ {
+ btif_rc_handler(event, p_bta_data);
+ }
+ break;
+ /* Let the RC handler decide on these passthrough cmds
+ * Use rc_handle to get the active AV device and use that mapping.
+ */
+ case BTA_AV_REMOTE_CMD_EVT:
+ case BTA_AV_VENDOR_CMD_EVT:
+ case BTA_AV_META_MSG_EVT:
+ case BTA_AV_RC_FEAT_EVT:
+ case BTA_AV_BROWSE_MSG_EVT:
+ index = 0;
+ BTIF_TRACE_EVENT("RC events: on index = %d", index);
+ break;
+ default:
+ BTIF_TRACE_ERROR("Unhandled event = %d", event);
+ break;
+ }
+ BTIF_TRACE_DEBUG("Handle the AV event = %x on index = %d", event, index);
+ if (index >= 0 && index < btif_max_av_clients)
+ btif_sm_dispatch(btif_av_cb[index].sm_handle, event, (void*)p_param);
+ else
+ BTIF_TRACE_ERROR("Unhandled Index = %d", index);
+ btif_av_event_free_data(event, p_param);
+
+}
+
+/*******************************************************************************
+**
+** Function btif_av_get_valid_idx
+**
+** Description Check the validity of the current index for the connection
+**
+** Returns Boolean
+**
+*******************************************************************************/
+
+static BOOLEAN btif_av_get_valid_idx(int idx)
+{
+ btif_sm_state_t state = btif_sm_get_state(btif_av_cb[idx].sm_handle);
+ return ((state == BTIF_AV_STATE_OPENED) ||
+ (state == BTIF_AV_STATE_STARTED) ||
+ (state == BTIF_AV_STATE_OPENING));
+}
+
+/*******************************************************************************
+**
+** Function btif_av_idx_by_bdaddr
+**
+** Description Get the index corresponding to BD addr
+**
+** Returns UNIT8
+**
+*******************************************************************************/
+
+static UINT8 btif_av_idx_by_bdaddr(BD_ADDR bd_addr)
+{
+ int i;
+ for (i = 0; i < btif_max_av_clients; i++)
+ {
+ if ((bdcmp(bd_addr,
+ btif_av_cb[i].peer_bda.address) == 0))
+ return i;
+ }
+ return i;
+}
+
+BOOLEAN btif_av_is_current_device(BD_ADDR address)
+{
+ UINT8 index;
+
+ index = btif_av_idx_by_bdaddr(address);
+ if((index < btif_max_av_clients) && btif_av_cb[index].current_playing)
+ {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*******************************************************************************
+**
+** Function btif_get_latest_device_idx_to_start
+**
+** Description Get the index of the AV where streaming is to be started
+**
+** Returns int
+**
+*******************************************************************************/
+
+static int btif_get_latest_device_idx_to_start()
+{
+ int i, j;
+ BD_ADDR playing_address;
+
+ /* Get the device which sent PLAY command
+ * If found, START on that index.
+ */
+ memset(playing_address, 0, sizeof(BD_ADDR));
+ btif_rc_get_playing_device(playing_address);
+ if (bdcmp(playing_address, bd_addr_null) != 0)
+ {
+ /* Got some valid Playing device.
+ * Get the AV index for this device.
+ */
+ i = btif_av_idx_by_bdaddr(playing_address);
+ if (i == btif_max_av_clients)
+ return btif_max_av_clients;
+ BTIF_TRACE_EVENT("Got some valid Playing device; %d", i);
+ /*Clear the Current playing device*/
+ for (j = 0; j < btif_max_av_clients; j++)
+ {
+ if (j != i)
+ btif_av_cb[j].current_playing = FALSE;
+ }
+ /*Clear the Play command in RC*/
+ btif_rc_clear_playing_state(FALSE);
+ return i;
+ }
+
+ /*No playing device, get the latest*/
+ for (i = 0; i < btif_max_av_clients; i++)
+ {
+ if (btif_av_cb[i].current_playing)
+ break;
+ }
+ if (i == btif_max_av_clients)
+ {
+ BTIF_TRACE_ERROR("Play on default");
+ i = 0; /*play on default*/
+ }
+ return i;
+}
+
+/*******************************************************************************
+**
+** Function btif_get_latest_playing_device_idx
+**
+** Description Get the index of AV where streaming is happening
+**
+** Returns int
+**
+*******************************************************************************/
+
+static int btif_get_latest_playing_device_idx()
+{
+ int i;
+ btif_sm_state_t state;
+ for (i = 0; i < btif_max_av_clients; i++)
+ {
+ state = btif_sm_get_state(btif_av_cb[i].sm_handle);
+ if (state == BTIF_AV_STATE_STARTED)
+ {
+ break;
+ }
+ }
+ return i;
+}
+
+/*******************************************************************************
+**
+** Function btif_av_is_playing
+**
+** Description Is AV in streaming state
+**
+** Returns BOOLEAN
+**
+*******************************************************************************/
+
+BOOLEAN btif_av_is_playing()
+{
+ int i;
+ for (i = 0; i < btif_max_av_clients; i++)
+ {
+ btif_av_cb[i].state = btif_sm_get_state(btif_av_cb[i].sm_handle);
+ if (btif_av_cb[i].state == BTIF_AV_STATE_STARTED)
+ {
+ BTIF_TRACE_EVENT("btif_av_is_playing on index= %d", i);
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/*******************************************************************************
+**
+** Function btif_get_conn_state_of_device
+**
+** Description Returns the state of AV scb
+**
+** Returns int
+**
+*******************************************************************************/
+
+static int btif_get_conn_state_of_device(BD_ADDR address)
+{
+ btif_sm_state_t state = BTIF_AV_STATE_IDLE;
+ int i;
+ for (i = 0; i < btif_max_av_clients; i++)
+ {
+ if ((bdcmp(address,
+ btif_av_cb[i].peer_bda.address) == 0))
+ {
+ state = btif_sm_get_state(btif_av_cb[i].sm_handle);
+ BTIF_TRACE_EVENT("BD Found: %02X %02X %02X %02X %02X %02X :state: %s",
+ address[5], address[4], address[3],
+ address[2], address[1], address[0],
+ dump_av_sm_state_name(state));
+ }
+ }
+ return state;
+}
+
+/*******************************************************************************
+**
+** Function btif_av_get_valid_idx_for_rc_events
+**
+** Description gets th valid index for the RC event address
+**
+** Returns int
+**
+*******************************************************************************/
+
+static int btif_av_get_valid_idx_for_rc_events(BD_ADDR bd_addr, int rc_handle)
+{
+ int index = 0;
+ /* First try to find if it is first event in AV IF
+ * both the handles would be in IDLE state, pick the first
+ * If we get second RC event while processing the priority
+ * for the first, reject the second connection. */
+
+ /*Get the index from connected SCBs*/
+ index = btif_av_idx_by_bdaddr(bd_addr);
+ if (index == btif_max_av_clients)
+ {
+ /* None of the SCBS matched
+ * Allocate free SCB, null address SCB*/
+ index = btif_av_idx_by_bdaddr(bd_null);
+ BTIF_TRACE_EVENT("btif_av_get_valid_idx_for_rc_events is %d", index);
+ if (index >= btif_max_av_clients)
+ {
+ BTIF_TRACE_EVENT("disconnect only AVRCP device rc_handle %d", rc_handle);
+ BTA_AvCloseRc(rc_handle);
+ }
+ }
+ return index;
+}
+
+/*******************************************************************************
+**
+** Function btif_av_check_rc_connection_priority
+**
+** Description Handles Priority callback for RC connections
+**
+** Returns void
+**
+*******************************************************************************/
+
+static void btif_av_check_rc_connection_priority(void *p_data)
+{
+ bt_bdaddr_t peer_bda;
+
+ /*Check if it is for same AV device*/
+ if (btif_av_is_device_connected(((tBTA_AV*)p_data)->rc_open.peer_addr))
+ {
+ /*AV is connected */
+ BTIF_TRACE_DEBUG("AV is connected, process RC connect event");
+ btif_rc_handler(BTA_AV_RC_OPEN_EVT, (tBTA_AV*)p_data);
+ return;
+ }
+ BTIF_TRACE_DEBUG("btif_av_check_rc_connection_priority");
+ bdcpy(peer_bda.address, ((tBTA_AV*)p_data)->rc_open.peer_addr);
+
+ if (idle_rc_event != 0)
+ {
+ BTIF_TRACE_DEBUG("Processing another RC Event ");
+ return;
+ }
+ idle_rc_event = BTA_AV_RC_OPEN_EVT;
+ memcpy(&idle_rc_data, ((tBTA_AV*)p_data), sizeof(tBTA_AV));
+ if (((tBTA_AV*)p_data)->rc_open.status == BTA_AV_SUCCESS)
+ {
+ BTIF_TRACE_DEBUG("RC conn is success ");
+ if (bt_av_src_callbacks != NULL)
+ {
+ BTIF_TRACE_DEBUG(" Check Device priority");
+ HAL_CBACK(bt_av_src_callbacks, connection_priority_cb,
+ &peer_bda);
+ }
+ }
+ else
+ {
+ idle_rc_event = 0;
+ memset(&idle_rc_data, 0, sizeof(tBTA_AV));
+ }
+ return;
+}
+
+
static void bte_av_callback(tBTA_AV_EVT event, tBTA_AV *p_data)
{
btif_transfer_context(btif_av_handle_event, event,
(char*)p_data, sizeof(tBTA_AV), btif_av_event_deep_copy);
}
+/*Called only in case of A2dp SInk, which runs on index 0*/
static void bte_av_media_callback(tBTA_AV_EVT event, tBTA_AV_MEDIA *p_data)
{
btif_sm_state_t state;
tA2D_STATUS a2d_status;
tA2D_SBC_CIE sbc_cie;
btif_av_sink_config_req_t config_req;
+ int index =0;
if (event == BTA_AV_MEDIA_DATA_EVT)/* Switch to BTIF_MEDIA context */
{
- state= btif_sm_get_state(btif_av_cb.sm_handle);
+ state= btif_sm_get_state(btif_av_cb[index].sm_handle);
if ( (state == BTIF_AV_STATE_STARTED) || /* send SBC packets only in Started State */
(state == BTIF_AV_STATE_OPENED) )
{
bt_status_t btif_av_init(int service_id)
{
- if (btif_av_cb.sm_handle == NULL)
+ int i;
+ if (btif_av_cb[0].sm_handle == NULL)
{
alarm_free(av_open_on_rc_timer);
av_open_on_rc_timer = alarm_new("btif_av.av_open_on_rc_timer");
- if (!btif_a2dp_start_media_task())
+ BTIF_TRACE_DEBUG("%s", __FUNCTION__);
+ if(!btif_a2dp_is_media_task_stopped())
return BT_STATUS_FAIL;
+ btif_av_cb[0].service = service_id;
/* Also initialize the AV state machine */
- btif_av_cb.sm_handle = btif_sm_init((const btif_sm_handler_t*)btif_av_state_handlers,
- BTIF_AV_STATE_IDLE);
+ for (i = 0; i < btif_max_av_clients; i++)
+ {
+ btif_av_cb[i].sm_handle = btif_sm_init((const btif_sm_handler_t*)btif_av_state_handlers,
+ BTIF_AV_STATE_IDLE, i);
+ }
+
+ btif_transfer_context(btif_av_handle_event, BTIF_AV_INIT_REQ_EVT,
+ (char*)&service_id, sizeof(int), NULL);
+
btif_enable_service(service_id);
- btif_a2dp_on_init();
}
return BT_STATUS_SUCCESS;
**
*******************************************************************************/
-static bt_status_t init_src(btav_callbacks_t* callbacks)
+static bt_status_t init_src(btav_callbacks_t* callbacks, int max_a2dp_connections,
+ int a2dp_multicast_state)
{
- BTIF_TRACE_EVENT("%s()", __func__);
+ bt_status_t status;
+
+ BTIF_TRACE_EVENT("%s with max conn = %d", __FUNCTION__, max_a2dp_connections);
+
+ if (bt_av_sink_callbacks != NULL) {
+ // already did btif_av_init()
+ status = BT_STATUS_SUCCESS;
+ }
+ else
+ {
+ if (a2dp_multicast_state)
+ {
+ is_multicast_supported = TRUE;
+ }
+ btif_max_av_clients = max_a2dp_connections;
+ status = btif_av_init(BTA_A2DP_SOURCE_SERVICE_ID);
+ }
- bt_status_t status = btif_av_init(BTA_A2DP_SOURCE_SERVICE_ID);
- if (status == BT_STATUS_SUCCESS)
+ if (status == BT_STATUS_SUCCESS) {
bt_av_src_callbacks = callbacks;
+ }
return status;
}
**
*******************************************************************************/
-static bt_status_t init_sink(btav_callbacks_t* callbacks)
+static bt_status_t init_sink(btav_callbacks_t* callbacks, int max,
+ int a2dp_multicast_state)
{
- BTIF_TRACE_EVENT("%s()", __func__);
+ bt_status_t status;
+
+ BTIF_TRACE_EVENT("%s", __FUNCTION__);
+
+ if (bt_av_src_callbacks != NULL) {
+ // already did btif_av_init()
+ status = BT_STATUS_SUCCESS;
+ }
+ else
+ {
+ enable_multicast = FALSE; // Clear multicast flag for sink
+ if (max > 1)
+ {
+ BTIF_TRACE_ERROR("Only one Sink can be initialized");
+ max = 1;
+ }
+ btif_max_av_clients = max; //Should be 1
+ status = btif_av_init(BTA_A2DP_SINK_SERVICE_ID);
+ }
- bt_status_t status = btif_av_init(BTA_A2DP_SINK_SERVICE_ID);
- if (status == BT_STATUS_SUCCESS)
+ if (status == BT_STATUS_SUCCESS) {
bt_av_sink_callbacks = callbacks;
+ //BTA_AvEnable_Sink(TRUE);
+ }
return status;
}
}
#endif
+
+void btif_get_latest_playing_device(BD_ADDR address)
+{
+ int index;
+ index = btif_get_latest_playing_device_idx();
+ if (index < btif_max_av_clients)
+ {
+ //copy bdaddrsss
+ bdcpy(address, btif_av_cb[index].peer_bda.address);
+ }
+ else
+ {
+ bdcpy(address, bd_null);
+ }
+}
+
+BOOLEAN btif_av_is_device_connected(BD_ADDR address)
+{
+ btif_sm_state_t state = btif_get_conn_state_of_device(address);
+
+ if ((state == BTIF_AV_STATE_OPENED) ||
+ (state == BTIF_AV_STATE_STARTED))
+ return TRUE;
+ else
+ return FALSE;
+}
+
+/*This function will trigger remote suspend for currently
+* playing device and then initiate START on Handoff device
+* whose address is passed as an argument. */
+/*******************************************************************************
+**
+** Function btif_av_trigger_dual_handoff
+**
+** Description Trigger the DUAL HANDOFF
+**
+** Returns void
+**
+*******************************************************************************/
+
+void btif_av_trigger_dual_handoff(BOOLEAN handoff, BD_ADDR address)
+{
+ int index;
+ /*Get the current playing device*/
+ BTIF_TRACE_DEBUG("%s", __FUNCTION__);
+ index = btif_get_latest_playing_device_idx();
+ if (index != btif_max_av_clients)
+ {
+ btif_av_cb[index].dual_handoff = handoff; /*Initiate Handoff*/
+ /*Initiate SUSPEND for this device*/
+ BTIF_TRACE_DEBUG("Initiate SUSPEND for this device on index = %d", index);
+ btif_sm_dispatch(btif_av_cb[index].sm_handle, BTIF_AV_SUSPEND_STREAM_REQ_EVT, NULL);
+ //btif_dispatch_sm_event(BTIF_AV_SUSPEND_STREAM_REQ_EVT, NULL, 0);
+ }
+ else
+ {
+ BTIF_TRACE_ERROR("Handoff on invalid index");
+ }
+}
+
+/*******************************************************************************
+**
+** Function btif_av_trigger_suspend
+**
+** Description Trigger suspend when multicast is ongoing for tuch tones
+** and new ACL is created.
+**
+** Returns void
+**
+*******************************************************************************/
+
+void btif_av_trigger_suspend()
+{
+ int index;
+ /*Get the current playing device*/
+ BTIF_TRACE_DEBUG("%s", __FUNCTION__);
+ index = btif_get_latest_playing_device_idx();
+ if (index <= btif_max_av_clients)
+ {
+ /*Initiate SUSPEND for this device*/
+ BTIF_TRACE_DEBUG("Initiate SUSPEND for this device on index = %d", index);
+ btif_sm_dispatch(btif_av_cb[index].sm_handle, BTIF_AV_SUSPEND_STREAM_REQ_EVT, NULL);
+ }
+ else
+ {
+ BTIF_TRACE_ERROR("suspend on invalid index");
+ }
+}
+
/*******************************************************************************
**
** Function connect
static bt_status_t connect_int(bt_bdaddr_t *bd_addr, uint16_t uuid)
{
btif_av_connect_req_t connect_req;
+ int i;
connect_req.target_bda = bd_addr;
connect_req.uuid = uuid;
BTIF_TRACE_EVENT("%s", __FUNCTION__);
- btif_sm_dispatch(btif_av_cb.sm_handle, BTIF_AV_CONNECT_REQ_EVT, (char*)&connect_req);
+ for (i = 0; i < btif_max_av_clients;)
+ {
+ if(btif_av_get_valid_idx(i))
+ {
+ if (bdcmp(bd_addr->address, btif_av_cb[i].peer_bda.address) == 0)
+ {
+ BTIF_TRACE_ERROR("Attempting connection for non idle device.. back off ");
+ btif_queue_advance();
+ return BT_STATUS_SUCCESS;
+ }
+ i++;
+ }
+ else
+ break;
+ }
+ if (i == btif_max_av_clients)
+ {
+ UINT8 rc_handle;
+
+ BTIF_TRACE_ERROR("%s: All indexes are full", __FUNCTION__);
+
+ /* Multicast: Check if AV slot is available for connection
+ * If not available, AV got connected to different devices.
+ * Disconnect this RC connection without AV connection.
+ */
+ rc_handle = btif_rc_get_connected_peer_handle(bd_addr->address);
+ if (rc_handle != BTIF_RC_HANDLE_NONE)
+ {
+ BTA_AvCloseRc(rc_handle);
+ }
+ btif_queue_advance();
+ return BT_STATUS_FAIL;
+ }
+
+ btif_sm_dispatch(btif_av_cb[i].sm_handle, BTIF_AV_CONNECT_REQ_EVT, (char*)&connect_req);
+
return BT_STATUS_SUCCESS;
}
*******************************************************************************/
static void cleanup(int service_uuid)
{
+ int i;
BTIF_TRACE_EVENT("%s", __FUNCTION__);
- btif_transfer_context(btif_av_handle_event, BTIF_AV_CLEANUP_REQ_EVT, NULL, 0, NULL);
+ btif_transfer_context(btif_av_handle_event, BTIF_AV_CLEANUP_REQ_EVT,
+ (char*)&service_uuid, sizeof(int), NULL);
btif_disable_service(service_uuid);
/* Also shut down the AV state machine */
- btif_sm_shutdown(btif_av_cb.sm_handle);
- btif_av_cb.sm_handle = NULL;
+ for (i = 0; i < btif_max_av_clients; i++ )
+ {
+ btif_sm_shutdown(btif_av_cb[i].sm_handle);
+ btif_av_cb[i].sm_handle = NULL;
+ }
}
static void cleanup_src(void) {
BTIF_TRACE_EVENT("%s", __FUNCTION__);
+ cleanup(BTA_A2DP_SOURCE_SERVICE_ID);
+}
- if (bt_av_src_callbacks)
- {
- bt_av_src_callbacks = NULL;
- if (bt_av_sink_callbacks == NULL)
- cleanup(BTA_A2DP_SOURCE_SERVICE_ID);
- }
+static void cleanup_sink(void) {
+ BTIF_TRACE_EVENT("%s", __FUNCTION__);
+ cleanup(BTA_A2DP_SINK_SERVICE_ID);
}
-static void cleanup_sink(void) {
- BTIF_TRACE_EVENT("%s", __FUNCTION__);
+static void allow_connection(int is_valid, bt_bdaddr_t *bd_addr)
+{
+ int index = 0;
+ BTIF_TRACE_DEBUG(" %s isValid is %d event %d", __FUNCTION__,is_valid,idle_rc_event);
+ switch (idle_rc_event)
+ {
+ case BTA_AV_RC_OPEN_EVT:
+ if (is_valid)
+ {
+ BTIF_TRACE_DEBUG("allowconn for RC connection");
+ alarm_set_on_queue(av_open_on_rc_timer,
+ BTIF_TIMEOUT_AV_OPEN_ON_RC_MS,
+ btif_initiate_av_open_timer_timeout, NULL,
+ btu_general_alarm_queue);
+ btif_rc_handler(idle_rc_event, &idle_rc_data);
+ }
+ else
+ {
+ UINT8 rc_handle = idle_rc_data.rc_open.rc_handle;
+ BTA_AvCloseRc(rc_handle);
+ }
+ break;
+
+ case BTA_AV_PENDING_EVT:
+ if (is_valid)
+ {
+ index = btif_av_idx_by_bdaddr(bd_addr->address);
+ if (index >= btif_max_av_clients)
+ {
+ BTIF_TRACE_DEBUG("Invalid index for device");
+ break;
+ }
+ BTIF_TRACE_DEBUG("The connection is allowed for the device at index = %d", index);
+ BTA_AvOpen(btif_av_cb[index].peer_bda.address, btif_av_cb[index].bta_handle,
+ TRUE, BTA_SEC_NONE, UUID_SERVCLASS_AUDIO_SOURCE);
+ }
+ else
+ {
+ BTA_AvDisconnect(idle_rc_data.pend.bd_addr);
+ }
+ break;
- if (bt_av_sink_callbacks)
- {
- bt_av_sink_callbacks = NULL;
- if (bt_av_src_callbacks == NULL)
- cleanup(BTA_A2DP_SINK_SERVICE_ID);
+ default:
+ BTIF_TRACE_DEBUG("%s : unhandled event:%s", __FUNCTION__,
+ dump_av_sm_event_name(idle_rc_event));
}
+ idle_rc_event = 0;
+ memset(&idle_rc_data, 0, sizeof(tBTA_AV));
}
static const btav_interface_t bt_av_src_interface = {
cleanup_src,
NULL,
NULL,
+ allow_connection,
};
static const btav_interface_t bt_av_sink_interface = {
NULL,
NULL,
#endif
+ NULL,
};
/*******************************************************************************
** Returns None
**
*******************************************************************************/
-
+/* Media task uses this info
+* But dont use it. */
btif_sm_handle_t btif_av_get_sm_handle(void)
{
- return btif_av_cb.sm_handle;
+ return btif_av_cb[0].sm_handle;
}
/*******************************************************************************
**
*******************************************************************************/
-bt_bdaddr_t btif_av_get_addr(void)
+bt_bdaddr_t btif_av_get_addr(BD_ADDR address)
{
- return btif_av_cb.peer_bda;
+ int i;
+ bt_bdaddr_t not_found ;
+ memset (¬_found, 0, sizeof(bt_bdaddr_t));
+ for (i = 0; i < btif_max_av_clients; i++)
+ {
+ if (bdcmp(btif_av_cb[i].peer_bda.address, address) == 0)
+ return btif_av_cb[i].peer_bda;
+ }
+ return not_found;
}
/*******************************************************************************
BOOLEAN btif_av_stream_ready(void)
{
- btif_sm_state_t state = btif_sm_get_state(btif_av_cb.sm_handle);
-
- BTIF_TRACE_DEBUG("btif_av_stream_ready : sm hdl %d, state %d, flags %x",
- btif_av_cb.sm_handle, state, btif_av_cb.flags);
-
+ int i;
+ BOOLEAN status = FALSE;
/* also make sure main adapter is enabled */
if (btif_is_enabled() == 0)
{
return FALSE;
}
- /* check if we are remotely suspended or stop is pending */
- if (btif_av_cb.flags & (BTIF_AV_FLAG_REMOTE_SUSPEND|BTIF_AV_FLAG_PENDING_STOP))
- return FALSE;
-
- return (state == BTIF_AV_STATE_OPENED);
+ for (i = 0; i < btif_max_av_clients; i++)
+ {
+ btif_av_cb[i].state = btif_sm_get_state(btif_av_cb[i].sm_handle);
+ /* Multicast:
+ * If any of the stream is in pending suspend state when
+ * we initiate start, it will result in inconsistent behavior
+ * Check the pending SUSPEND flag and return failure
+ * if suspend is in progress.
+ */
+ if (btif_av_cb[i].dual_handoff ||
+ (btif_av_cb[i].flags & BTIF_AV_FLAG_LOCAL_SUSPEND_PENDING))
+ {
+ status = FALSE;
+ break;
+ }
+ else if (btif_av_cb[i].flags &
+ (BTIF_AV_FLAG_REMOTE_SUSPEND|BTIF_AV_FLAG_PENDING_STOP))
+ {
+ status = FALSE;
+ break;
+ }
+ else if (btif_av_cb[i].state == BTIF_AV_STATE_OPENED)
+ {
+ status = TRUE;
+ }
+ }
+ BTIF_TRACE_DEBUG("btif_av_stream_ready: %d", status);
+ return status;
}
/*******************************************************************************
BOOLEAN btif_av_stream_started_ready(void)
{
- btif_sm_state_t state = btif_sm_get_state(btif_av_cb.sm_handle);
+ int i;
+ BOOLEAN status = FALSE;
- BTIF_TRACE_DEBUG("btif_av_stream_started : sm hdl %d, state %d, flags %x",
- btif_av_cb.sm_handle, state, btif_av_cb.flags);
-
- /* disallow media task to start if we have pending actions */
- if (btif_av_cb.flags & (BTIF_AV_FLAG_LOCAL_SUSPEND_PENDING | BTIF_AV_FLAG_REMOTE_SUSPEND
- | BTIF_AV_FLAG_PENDING_STOP))
- return FALSE;
-
- return (state == BTIF_AV_STATE_STARTED);
+ for (i = 0; i < btif_max_av_clients; i++)
+ {
+ btif_av_cb[i].state = btif_sm_get_state(btif_av_cb[i].sm_handle);
+ if (btif_av_cb[i].dual_handoff)
+ {
+ BTIF_TRACE_ERROR("%s: Under Dual handoff ",__FUNCTION__ );
+ status = FALSE;
+ break;
+ } else if (btif_av_cb[i].flags &
+ (BTIF_AV_FLAG_LOCAL_SUSPEND_PENDING |
+ BTIF_AV_FLAG_REMOTE_SUSPEND |
+ BTIF_AV_FLAG_PENDING_STOP))
+ {
+ status = FALSE;
+ break;
+ } else if (btif_av_cb[i].state == BTIF_AV_STATE_STARTED)
+ {
+ status = TRUE;
+ }
+ }
+ BTIF_TRACE_DEBUG("btif_av_stream_started_ready: %d", status);
+ return status;
}
/*******************************************************************************
*******************************************************************************/
bt_status_t btif_av_execute_service(BOOLEAN b_enable)
{
- if (b_enable)
- {
- /* TODO: Removed BTA_SEC_AUTHORIZE since the Java/App does not
- * handle this request in order to allow incoming connections to succeed.
- * We need to put this back once support for this is added */
+ int i;
+ if (b_enable)
+ {
+ /* TODO: Removed BTA_SEC_AUTHORIZE since the Java/App does not
+ * handle this request in order to allow incoming connections to succeed.
+ * We need to put this back once support for this is added */
- /* Added BTA_AV_FEAT_NO_SCO_SSPD - this ensures that the BTA does not
- * auto-suspend av streaming on AG events(SCO or Call). The suspend shall
- * be initiated by the app/audioflinger layers */
- /* Support for browsing for SDP record should work only if we enable BROWSE
- * while registering. */
+ /* Added BTA_AV_FEAT_NO_SCO_SSPD - this ensures that the BTA does not
+ * auto-suspend av streaming on AG events(SCO or Call). The suspend shall
+ * be initiated by the app/audioflinger layers */
#if (AVRC_METADATA_INCLUDED == TRUE)
- BTA_AvEnable(BTA_SEC_AUTHENTICATE,
- BTA_AV_FEAT_RCTG|BTA_AV_FEAT_METADATA|BTA_AV_FEAT_VENDOR|BTA_AV_FEAT_NO_SCO_SSPD
+ BTA_AvEnable(BTA_SEC_AUTHENTICATE,
+ BTA_AV_FEAT_RCTG|BTA_AV_FEAT_METADATA|BTA_AV_FEAT_VENDOR|BTA_AV_FEAT_NO_SCO_SSPD
+ |BTA_AV_FEAT_ACP_START
#if (AVRC_ADV_CTRL_INCLUDED == TRUE)
- |BTA_AV_FEAT_RCCT
- |BTA_AV_FEAT_ADV_CTRL
+ |BTA_AV_FEAT_RCCT
+ |BTA_AV_FEAT_ADV_CTRL
+ |BTA_AV_FEAT_BROWSE
#endif
- ,bte_av_callback);
+ ,bte_av_callback);
#else
- BTA_AvEnable(BTA_SEC_AUTHENTICATE, (BTA_AV_FEAT_RCTG | BTA_AV_FEAT_NO_SCO_SSPD),
- bte_av_callback);
+ BTA_AvEnable(BTA_SEC_AUTHENTICATE, (BTA_AV_FEAT_RCTG | BTA_AV_FEAT_NO_SCO_SSPD
+ |BTA_AV_FEAT_ACP_START), bte_av_callback);
#endif
- BTA_AvRegister(BTA_AV_CHNL_AUDIO, BTIF_AV_SERVICE_NAME, 0, bte_av_media_callback,
- UUID_SERVCLASS_AUDIO_SOURCE);
- }
- else {
- BTA_AvDeregister(btif_av_cb.bta_handle);
- BTA_AvDisable();
- }
- return BT_STATUS_SUCCESS;
+ for (i = 0; i < btif_max_av_clients; i++)
+ {
+ BTIF_TRACE_DEBUG("%s: BTA_AvRegister : %d", __FUNCTION__, i);
+ BTA_AvRegister(BTA_AV_CHNL_AUDIO, BTIF_AV_SERVICE_NAME, 0, bte_av_media_callback,
+ UUID_SERVCLASS_AUDIO_SOURCE);
+ }
+ }
+ else
+ {
+ for (i = 0; i < btif_max_av_clients; i++)
+ {
+ BTA_AvDeregister(btif_av_cb[i].bta_handle);
+ }
+ BTA_AvDisable();
+ }
+ return BT_STATUS_SUCCESS;
}
/*******************************************************************************
UUID_SERVCLASS_AUDIO_SINK);
}
else {
- BTA_AvDeregister(btif_av_cb.bta_handle);
+ BTA_AvDeregister(btif_av_cb[0].bta_handle);
BTA_AvDisable();
}
return BT_STATUS_SUCCESS;
*******************************************************************************/
BOOLEAN btif_av_is_connected(void)
{
- btif_sm_state_t state = btif_sm_get_state(btif_av_cb.sm_handle);
- return ((state == BTIF_AV_STATE_OPENED) || (state == BTIF_AV_STATE_STARTED));
+ int i;
+ BOOLEAN status = FALSE;
+ for (i = 0; i < btif_max_av_clients; i++)
+ {
+ btif_av_cb[i].state = btif_sm_get_state(btif_av_cb[i].sm_handle);
+ if ((btif_av_cb[i].state == BTIF_AV_STATE_OPENED) ||
+ (btif_av_cb[i].state == BTIF_AV_STATE_STARTED))
+ status = TRUE;
+ }
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function btif_av_is_connected_on_other_idx
+**
+** Description Checks if any other AV SCB is connected
+**
+** Returns BOOLEAN
+**
+*******************************************************************************/
+
+BOOLEAN btif_av_is_connected_on_other_idx(int current_index)
+{
+ //return true if other IDx is connected
+ btif_sm_state_t state = BTIF_AV_STATE_IDLE;
+ int i;
+ for (i = 0; i < btif_max_av_clients; i++)
+ {
+ if (i != current_index)
+ {
+ state = btif_sm_get_state(btif_av_cb[i].sm_handle);
+ if ((state == BTIF_AV_STATE_OPENED) ||
+ (state == BTIF_AV_STATE_STARTED))
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/*******************************************************************************
+**
+** Function btif_av_is_playing_on_other_idx
+**
+** Description Checks if any other AV SCB is connected
+**
+** Returns BOOLEAN
+**
+*******************************************************************************/
+
+BOOLEAN btif_av_is_playing_on_other_idx(int current_index)
+{
+ //return true if other IDx is playing
+ btif_sm_state_t state = BTIF_AV_STATE_IDLE;
+ int i;
+ for (i = 0; i < btif_max_av_clients; i++)
+ {
+ if (i != current_index)
+ {
+ state = btif_sm_get_state(btif_av_cb[i].sm_handle);
+ if (state == BTIF_AV_STATE_STARTED)
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/*******************************************************************************
+**
+** Function btif_av_update_current_playing_device
+**
+** Description Update the next connected device as playing
+**
+** Returns void
+**
+*******************************************************************************/
+
+static void btif_av_update_current_playing_device(int index)
+{
+ int i;
+ for (i = 0; i < btif_max_av_clients; i++)
+ {
+ if (i != index)
+ btif_av_cb[i].current_playing = TRUE;
+ }
}
/*******************************************************************************
*******************************************************************************/
BOOLEAN btif_av_is_peer_edr(void)
{
+ btif_sm_state_t state;
+ BOOLEAN peer_edr = FALSE;
+
ASSERTC(btif_av_is_connected(), "No active a2dp connection", 0);
- if (btif_av_cb.edr)
- return TRUE;
- else
- return FALSE;
+ /* If any of the remote in streaming state is BR
+ * return FALSE to ensure proper configuration
+ * is used. Ideally, since multicast is not supported
+ * if any of the connected device is BR device,
+ * we should not see both devices in START state.
+ */
+ for (int index = 0; index < btif_max_av_clients; index ++)
+ {
+ state = btif_sm_get_state(btif_av_cb[index].sm_handle);
+ if ((btif_av_cb[index].flags & BTIF_AV_FLAG_PENDING_START)
+ || (state == BTIF_AV_STATE_STARTED))
+ {
+ if (btif_av_cb[index].edr)
+ {
+ peer_edr = TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
+ }
+ }
+ return peer_edr;
}
-/******************************************************************************
+/*******************************************************************************
**
-** Function btif_av_clear_remote_suspend_flag
+** Function btif_av_any_br_peer
**
-** Description Clears btif_av_cd.flags if BTIF_AV_FLAG_REMOTE_SUSPEND is set
+** Description Check if the any of connected devices is BR device.
**
-** Returns void
-******************************************************************************/
-void btif_av_clear_remote_suspend_flag(void)
+** Returns TRUE if connected to any BR device, FALSE otherwise.
+**
+*******************************************************************************/
+BOOLEAN btif_av_any_br_peer(void)
{
- BTIF_TRACE_DEBUG("%s: flag :%x",__func__, btif_av_cb.flags);
- btif_av_cb.flags &= ~BTIF_AV_FLAG_REMOTE_SUSPEND;
+ btif_sm_state_t state;
+ for (int index = 0; index < btif_max_av_clients; index ++)
+ {
+ state = btif_sm_get_state(btif_av_cb[index].sm_handle);
+ if (state >= BTIF_AV_STATE_OPENED)
+ {
+ if (!btif_av_cb[index].edr)
+ {
+ BTIF_TRACE_WARNING("%s : Connected to BR device :", __FUNCTION__);
+ return TRUE;
+ }
+ }
+ }
+ return FALSE;
}
/*******************************************************************************
**
** Function btif_av_peer_supports_3mbps
**
-** Description Check if the connected A2DP device supports
-** 3 Mbps EDR. This function only works if connected.
-** If not connected it will always be false.
+** Description check if the connected a2dp device supports
+** 3mbps edr. Only when connected this function
+** will accurately provide a true capability of
+** remote peer. If not connected it will always be false.
**
-** Returns TRUE if remote device is EDR and supports 3 Mbps
+** Returns TRUE if remote device is EDR and supports 3mbps
**
*******************************************************************************/
BOOLEAN btif_av_peer_supports_3mbps(void)
{
- BOOLEAN is3mbps = ((btif_av_cb.edr & BTA_AV_EDR_3MBPS) != 0);
- BTIF_TRACE_DEBUG("%s: connected %d, edr_3mbps %d", __func__,
- btif_av_is_connected(), is3mbps);
- return (btif_av_is_connected() && is3mbps);
+ btif_sm_state_t state;
+ ASSERTC(btif_av_is_connected(), "No active a2dp connection", 0);
+
+ for (int index = 0; index < btif_max_av_clients; index ++)
+ {
+ state = btif_sm_get_state(btif_av_cb[index].sm_handle);
+ if ((btif_av_cb[index].flags & BTIF_AV_FLAG_PENDING_START)
+ || (state == BTIF_AV_STATE_STARTED))
+ {
+ if(btif_av_cb[index].edr_3mbps)
+ return TRUE;
+ }
+ }
+ return FALSE;
}
+/******************************************************************************
+**
+** Function btif_av_clear_remote_suspend_flag
+**
+** Description Clears btif_av_cd.flags if BTIF_AV_FLAG_REMOTE_SUSPEND is set
+**
+** Returns void
+******************************************************************************/
+void btif_av_clear_remote_suspend_flag(void)
+{
+ int i;
+ for (i = 0; i < btif_max_av_clients; i++)
+ {
+ BTIF_TRACE_DEBUG(" flag :%x",btif_av_cb[i].flags);
+ btif_av_cb[i].flags &= ~BTIF_AV_FLAG_REMOTE_SUSPEND;
+ }
+}
/*******************************************************************************
**
*******************************************************************************/
void btif_av_move_idle(bt_bdaddr_t bd_addr)
{
+ int index =0;
/* inform the application that ACL is disconnected and move to idle state */
- btif_sm_state_t state = btif_sm_get_state(btif_av_cb.sm_handle);
- BTIF_TRACE_DEBUG("%s: ACL Disconnected state %d is same device %d", __func__,
- state, memcmp (&bd_addr, &(btif_av_cb.peer_bda), sizeof(bd_addr)));
+ index = btif_av_idx_by_bdaddr(bd_addr.address);
+ if (index == btif_max_av_clients)
+ {
+ BTIF_TRACE_DEBUG("btif_av_move_idle: Already in IDLE");
+ return;
+ }
+ btif_sm_state_t state = btif_sm_get_state(btif_av_cb[index].sm_handle);
+ BTIF_TRACE_DEBUG("ACL Disconnected state %d is same device %d",state,
+ memcmp (&bd_addr, &(btif_av_cb[index].peer_bda), sizeof(bd_addr)));
if (state == BTIF_AV_STATE_OPENING &&
- (memcmp (&bd_addr, &(btif_av_cb.peer_bda), sizeof(bd_addr)) == 0))
+ (memcmp (&bd_addr, &(btif_av_cb[index].peer_bda), sizeof(bd_addr)) == 0))
+ {
+ BTIF_TRACE_DEBUG("Moving State from Opening to Idle due to ACL disconnect");
+ btif_report_connection_state(BTAV_CONNECTION_STATE_DISCONNECTED, &(btif_av_cb[index].peer_bda));
+
+ btif_sm_change_state(btif_av_cb[index].sm_handle, BTIF_AV_STATE_IDLE);
+ btif_queue_advance();
+ }
+}
+/******************************************************************************
+**
+** Function btif_av_get_num_playing_devices
+**
+** Description Return number of A2dp playing devices
+**
+** Returns int
+******************************************************************************/
+UINT16 btif_av_get_num_playing_devices(void)
+{
+ UINT16 i;
+ UINT16 playing_devices = 0;
+ for (i = 0; i < btif_max_av_clients; i++)
+ {
+ btif_av_cb[i].state = btif_sm_get_state(btif_av_cb[i].sm_handle);
+ if (btif_av_cb[i].state == BTIF_AV_STATE_STARTED)
+ {
+ playing_devices++;
+ }
+ }
+ BTIF_TRACE_DEBUG("AV devices playing: %d", playing_devices);
+
+ return playing_devices;
+}
+/*******************************************************************************
+**
+** Function btif_av_get_num_connected_devices
+**
+** Description Return number of A2dp connected devices
+**
+** Returns int
+******************************************************************************/
+UINT16 btif_av_get_num_connected_devices(void)
+{
+ UINT16 i;
+ UINT16 connected_devies = 0;
+ for (i = 0; i < btif_max_av_clients; i++)
+ {
+ btif_av_cb[i].state = btif_sm_get_state(btif_av_cb[i].sm_handle);
+ if ((btif_av_cb[i].state == BTIF_AV_STATE_OPENED) ||
+ (btif_av_cb[i].state == BTIF_AV_STATE_STARTED))
+ {
+ connected_devies++;
+ }
+ }
+ BTIF_TRACE_DEBUG("AV Connection count: %d", connected_devies);
+
+ return connected_devies;
+}
+
+/******************************************************************************
+**
+** Function btif_av_update_multicast_state
+**
+** Description Enable Multicast only if below conditions are satisfied
+** 1. Connected to only 2 EDR HS.
+** 2. Connected to both HS as master.
+** 3. Connected to 2 EDR HS and one BLE device
+** Multicast will fall back to soft handsoff in below conditions
+** 1. Number of ACL links is more than 2,like connected to HID
+** initiating connection for HS1 and HS2.
+** 2. Connected to BR and EDR HS.
+** 3. Connected to more then 1 BLE device
+**
+** Returns void
+******************************************************************************/
+void btif_av_update_multicast_state(int index)
+{
+ UINT16 num_connected_br_edr_devices = 0;
+ UINT16 num_connected_le_devices = 0;
+ UINT16 num_av_connected = 0;
+ UINT16 i = 0;
+ BOOLEAN is_slave = FALSE;
+ BOOLEAN is_br_hs_connected = FALSE;
+ BOOLEAN prev_multicast_state = enable_multicast;
+
+ if (!is_multicast_supported)
+ {
+ BTIF_TRACE_DEBUG("%s Multicast is Disabled", __FUNCTION__);
+ return;
+ }
+
+ if (multicast_disabled == TRUE)
+ {
+ multicast_disabled = FALSE;
+ enable_multicast = FALSE;
+ BTA_AvEnableMultiCast(FALSE, btif_av_cb[index].bta_handle);
+ return;
+ }
+
+ BTIF_TRACE_DEBUG("%s Multicast previous state : %s", __FUNCTION__,
+ enable_multicast ? "Enabled" : "Disabled" );
+
+ num_connected_br_edr_devices = btif_dm_get_br_edr_links();
+ num_connected_le_devices = btif_dm_get_le_links();
+ num_av_connected = btif_av_get_num_connected_devices();
+ is_br_hs_connected = btif_av_any_br_peer();
+
+ for (i = 0; i < btif_max_av_clients; i++)
+ {
+ if (btif_av_cb[i].is_slave == TRUE)
+ {
+ BTIF_TRACE_WARNING("Conected as slave");
+ is_slave = TRUE;
+ break;
+ }
+ }
+
+ if ((num_av_connected <= 2) && (is_br_hs_connected != TRUE) &&
+ (is_slave == FALSE) && ((num_connected_br_edr_devices <= 2) &&
+ (num_connected_le_devices <= 1)))
+ {
+ enable_multicast = TRUE;
+ }
+ else
{
- BTIF_TRACE_DEBUG("%s: Moving State from Opening to Idle due to ACL disconnect", __func__);
- btif_report_connection_state(BTAV_CONNECTION_STATE_DISCONNECTED,
- &(btif_av_cb.peer_bda));
- btif_sm_change_state(btif_av_cb.sm_handle, BTIF_AV_STATE_IDLE);
+ enable_multicast = FALSE;
+ }
+
+ BTIF_TRACE_DEBUG("%s Multicast current state : %s", __FUNCTION__,
+ enable_multicast ? "Enabled" : "Disabled" );
+
+ if (prev_multicast_state != enable_multicast)
+ {
+ BTA_AvEnableMultiCast(enable_multicast,
+ btif_av_cb[index].bta_handle);
+ HAL_CBACK(bt_av_src_callbacks, multicast_state_cb,
+ enable_multicast);
+ }
+}
+/******************************************************************************
+**
+** Function btif_av_get_multicast_state
+**
+** Description Returns TRUE if multicast is enabled else false
+**
+** Returns BOOLEAN
+******************************************************************************/
+BOOLEAN btif_av_get_multicast_state()
+{
+ return enable_multicast;
+}
+/******************************************************************************
+**
+** Function btif_av_get_ongoing_multicast
+**
+** Description Returns TRUE if multicast is ongoing
+**
+** Returns BOOLEAN
+******************************************************************************/
+BOOLEAN btif_av_get_ongoing_multicast()
+{
+ int i = 0, j = 0;
+ if (!is_multicast_supported)
+ {
+ BTIF_TRACE_DEBUG("Multicast is Disabled");
+ return FALSE;
+ }
+ for (i = 0; i < btif_max_av_clients; i++)
+ {
+ if (btif_av_cb[i].is_device_playing)
+ {
+ j++;
+ }
+ }
+ if (j == btif_max_av_clients)
+ {
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
}
}
******************************************************************************/
static btif_dm_pairing_cb_t pairing_cb;
static btif_dm_oob_cb_t oob_cb;
+static UINT16 num_active_br_edr_links;
+static UINT16 num_active_le_links;
static void btif_dm_generic_evt(UINT16 event, char* p_param);
static void btif_dm_cb_create_bond(bt_bdaddr_t *bd_addr, tBTA_TRANSPORT transport);
static void btif_dm_cb_hid_remote_name(tBTM_REMOTE_DEV_NAME *p_remote_name);
extern int btif_hh_connect(bt_bdaddr_t *bd_addr);
extern void bta_gatt_convert_uuid16_to_uuid128(UINT8 uuid_128[LEN_UUID_128], UINT16 uuid_16);
extern void btif_av_move_idle(bt_bdaddr_t bd_addr);
+extern void btif_av_trigger_suspend();
+extern BOOLEAN btif_av_get_ongoing_multicast();
/******************************************************************************
** Functions
bdcpy(bd_addr.address, p_data->link_up.bd_addr);
BTIF_TRACE_DEBUG("BTA_DM_LINK_UP_EVT. Sending BT_ACL_STATE_CONNECTED");
+ if(p_data->link_up.link_type == BT_TRANSPORT_LE)
+ {
+ num_active_le_links++;
+ BTIF_TRACE_DEBUG("num_active_le_links is %d ",
+ num_active_le_links);
+ }
+
+ if(p_data->link_up.link_type == BT_TRANSPORT_BR_EDR)
+ {
+ num_active_br_edr_links++;
+ BTIF_TRACE_DEBUG("num_active_br_edr_links is %d ",
+ num_active_br_edr_links);
+ }
+ /* When tuchtones are enabled and 2 EDR HS are connected, if new
+ * connection is initated, then tuch tones are send to both connected HS
+ * over A2dp.Stream will be suspended after 3 secs and if remote has
+ * initiated play in this duartion, multicast must not be enabled with
+ * 3 ACL's, hence trigger a2dp suspend.
+ * During active muisc streaming no new connection can happen, hence
+ * We will get this only when multistreaming is happening due to tuchtones
+ */
+ if (btif_av_get_ongoing_multicast())
+ {
+ // trigger a2dp suspend
+ btif_av_trigger_suspend();
+ }
+
btif_update_remote_version_property(&bd_addr);
HAL_CBACK(bt_hal_cbacks, acl_state_changed_cb, BT_STATUS_SUCCESS,
case BTA_DM_LINK_DOWN_EVT:
bdcpy(bd_addr.address, p_data->link_down.bd_addr);
+
btm_set_bond_type_dev(p_data->link_down.bd_addr, BOND_TYPE_UNKNOWN);
+
+ BTIF_TRACE_DEBUG("BTA_DM_LINK_DOWN_EVT. Sending BT_ACL_STATE_DISCONNECTED");
+ if (num_active_le_links > 0 &&
+ p_data->link_down.link_type == BT_TRANSPORT_LE)
+ {
+ num_active_le_links--;
+ BTIF_TRACE_DEBUG("num_active_le_links is %d ",num_active_le_links);
+ }
+
+ if (num_active_br_edr_links > 0 &&
+ p_data->link_down.link_type == BT_TRANSPORT_BR_EDR)
+ {
+ num_active_br_edr_links--;
+ BTIF_TRACE_DEBUG("num_active_br_edr_links is %d ",num_active_br_edr_links);
+ }
btif_av_move_idle(bd_addr);
BTIF_TRACE_DEBUG("BTA_DM_LINK_DOWN_EVT. Sending BT_ACL_STATE_DISCONNECTED");
HAL_CBACK(bt_hal_cbacks, acl_state_changed_cb, BT_STATUS_SUCCESS,
void btif_dm_on_disable()
{
+ /* Cleanup static variables.*/
+ num_active_br_edr_links = 0;
+ num_active_le_links = 0;
+
/* cancel any pending pairing requests */
if (pairing_cb.state == BT_BOND_STATE_BONDING)
{
}
pthread_mutex_unlock(&bond_event_lock);
}
+
+/*******************************************************************************
+**
+** Function btif_dm_get_br_edr_links.
+**
+** Description Returns number of active BR/EDR links.
+**
+** Returns UINT16
+**
+*******************************************************************************/
+UINT16 btif_dm_get_br_edr_links()
+{
+ BTIF_TRACE_DEBUG("BR/EDR Link count: %d", num_active_br_edr_links);
+ return num_active_br_edr_links;
+}
+
+/*******************************************************************************
+**
+** Function btif_dm_get_le_links.
+**
+** Description Returns number of active LE links.
+**
+** Returns UINT16
+**
+*******************************************************************************/
+UINT16 btif_dm_get_le_links()
+{
+ BTIF_TRACE_DEBUG("LE Link count: %d", num_active_le_links);
+ return num_active_le_links;
+}
+
}
break;
+ case A2DP_CTRL_CMD_CHECK_STREAM_STARTED:
+
+ if((btif_av_stream_started_ready() == TRUE))
+ a2dp_cmd_acknowledge(A2DP_CTRL_ACK_SUCCESS);
+ else
+ a2dp_cmd_acknowledge(A2DP_CTRL_ACK_FAILURE);
+ break;
+
case A2DP_CTRL_CMD_START:
/* Don't sent START request to stack while we are in call.
Some headsets like the Sony MW600, don't allow AVDTP START
break;
}
- if (btif_av_stream_ready() == TRUE)
+ /* In Dual A2dp, first check for started state of stream
+ * as we dont want to START again as while doing Handoff
+ * the stack state will be started, so it is not needed
+ * to send START again, just open the media socket
+ * and ACK the audio HAL.*/
+ if (btif_av_stream_started_ready())
+ {
+ /* already started, setup audio data channel listener
+ * and ack back immediately */
+ UIPC_Open(UIPC_CH_ID_AV_AUDIO, btif_a2dp_data_cb);
+
+ a2dp_cmd_acknowledge(A2DP_CTRL_ACK_SUCCESS);
+ }
+ else if (btif_av_stream_ready() == TRUE)
{
/* setup audio data channel listener */
UIPC_Open(UIPC_CH_ID_AV_AUDIO, btif_a2dp_data_cb);
a2dp_cmd_acknowledge(A2DP_CTRL_ACK_SUCCESS);
#endif
}
- else if (btif_av_stream_started_ready())
- {
- /* already started, setup audio data channel listener
- and ack back immediately */
- UIPC_Open(UIPC_CH_ID_AV_AUDIO, btif_a2dp_data_cb);
-
- a2dp_cmd_acknowledge(A2DP_CTRL_ACK_SUCCESS);
- }
else
{
APPL_TRACE_WARNING("%s: A2DP command %s while AV stream is not ready",
btif_media_task_enc_update_req(&msg);
}
+bool btif_a2dp_is_media_task_stopped(void)
+{
+ if (media_task_running != MEDIA_TASK_STATE_OFF)
+ {
+ APPL_TRACE_ERROR("btif_a2dp_is_media_task_stopped: %d",
+ media_task_running);
+ return false;
+ }
+ return true;
+}
+
bool btif_a2dp_start_media_task(void)
{
if (media_task_running != MEDIA_TASK_STATE_OFF)
APPL_TRACE_IMP("## A2DP START MEDIA THREAD ##");
btif_media_cmd_msg_queue = fixed_queue_new(SIZE_MAX);
+ if (btif_media_cmd_msg_queue == NULL)
+ goto error_exit;
/* start a2dp media task */
worker_thread = thread_new_sized("media_worker", MAX_MEDIA_WORKQUEUE_SEM_COUNT);
void btif_a2dp_stop_media_task(void)
{
- APPL_TRACE_IMP("## A2DP STOP MEDIA THREAD ##");
+ APPL_TRACE_DEBUG("## A2DP STOP MEDIA THREAD ##");
+ if (media_task_running != MEDIA_TASK_STATE_ON)
+ {
+ APPL_TRACE_ERROR("warning: media task cleanup state: %d",
+ media_task_running);
+ return;
+ }
+ /* make sure no channels are restarted while shutting down */
+ media_task_running = MEDIA_TASK_STATE_SHUTTING_DOWN;
// Stop timer
alarm_free(btif_media_cb.media_alarm);
// Exit thread
fixed_queue_free(btif_media_cmd_msg_queue, NULL);
- btif_media_cmd_msg_queue = NULL;
thread_post(worker_thread, btif_media_thread_cleanup, NULL);
thread_free(worker_thread);
+
worker_thread = NULL;
+ btif_media_cmd_msg_queue = NULL;
+ APPL_TRACE_DEBUG("## A2DP MEDIA THREAD STOPPED ##");
}
/*****************************************************************************
**
*******************************************************************************/
-void btif_a2dp_setup_codec(void)
+tBTIF_STATUS btif_a2dp_setup_codec(void)
{
tBTIF_AV_MEDIA_FEEDINGS media_feeding;
tBTIF_STATUS status;
/* Send message to Media task to configure transcoding */
btif_media_task_audio_feeding_init_req(&mfeed);
}
+ else
+ {
+ status = BTIF_ERROR_SRV_AV_FEEDING_NOT_SUPPORTED;
+ }
mutex_global_unlock();
+ return status;
}
p_buf->focus_state = state;
p_buf->hdr.event = BTIF_MEDIA_AUDIO_SINK_SET_FOCUS_STATE;
- fixed_queue_enqueue(btif_media_cmd_msg_queue, p_buf);
+ if (btif_media_cmd_msg_queue != NULL)
+ fixed_queue_enqueue(btif_media_cmd_msg_queue, p_buf);
}
void btif_a2dp_set_audio_track_gain(float gain)
raise_priority_a2dp(TASK_HIGH_MEDIA);
media_task_running = MEDIA_TASK_STATE_ON;
+ APPL_TRACE_DEBUG(" btif_media_thread_init complete");
}
static void btif_media_thread_cleanup(UNUSED_ATTR void *context) {
APPL_TRACE_IMP(" btif_media_thread_cleanup");
- /* make sure no channels are restarted while shutting down */
- media_task_running = MEDIA_TASK_STATE_SHUTTING_DOWN;
/* this calls blocks until uipc is fully closed */
UIPC_Close(UIPC_CH_ID_ALL);
/* Clear media task flag */
media_task_running = MEDIA_TASK_STATE_OFF;
+ APPL_TRACE_DEBUG(" btif_media_thread_cleanup complete");
}
/*******************************************************************************
BT_HDR *p_buf = osi_malloc(sizeof(BT_HDR));
p_buf->event = Evt;
- fixed_queue_enqueue(btif_media_cmd_msg_queue, p_buf);
+ if (btif_media_cmd_msg_queue != NULL)
+ fixed_queue_enqueue(btif_media_cmd_msg_queue, p_buf);
return TRUE;
}
memcpy(p_buf, p_msg, sizeof(tBTIF_MEDIA_INIT_AUDIO));
p_buf->hdr.event = BTIF_MEDIA_SBC_ENC_INIT;
- fixed_queue_enqueue(btif_media_cmd_msg_queue, p_buf);
+ if (btif_media_cmd_msg_queue != NULL)
+ fixed_queue_enqueue(btif_media_cmd_msg_queue, p_buf);
return TRUE;
}
memcpy(p_buf, p_msg, sizeof(tBTIF_MEDIA_UPDATE_AUDIO));
p_buf->hdr.event = BTIF_MEDIA_SBC_ENC_UPDATE;
- fixed_queue_enqueue(btif_media_cmd_msg_queue, p_buf);
+ if (btif_media_cmd_msg_queue != NULL)
+ fixed_queue_enqueue(btif_media_cmd_msg_queue, p_buf);
return TRUE;
}
memcpy(p_buf, p_msg, sizeof(tBTIF_MEDIA_INIT_AUDIO_FEEDING));
p_buf->hdr.event = BTIF_MEDIA_AUDIO_FEEDING_INIT;
- fixed_queue_enqueue(btif_media_cmd_msg_queue, p_buf);
+ if (btif_media_cmd_msg_queue != NULL)
+ fixed_queue_enqueue(btif_media_cmd_msg_queue, p_buf);
return TRUE;
}
BT_HDR *p_buf = osi_malloc(sizeof(BT_HDR));
p_buf->event = BTIF_MEDIA_START_AA_TX;
- fixed_queue_enqueue(btif_media_cmd_msg_queue, p_buf);
+ if (btif_media_cmd_msg_queue != NULL)
+ fixed_queue_enqueue(btif_media_cmd_msg_queue, p_buf);
return TRUE;
}
BT_HDR *p_buf = osi_malloc(sizeof(BT_HDR));
p_buf->event = BTIF_MEDIA_FLUSH_AA_RX;
- fixed_queue_enqueue(btif_media_cmd_msg_queue, p_buf);
+ if (btif_media_cmd_msg_queue != NULL)
+ fixed_queue_enqueue(btif_media_cmd_msg_queue, p_buf);
return TRUE;
}
** Constants & Macros
******************************************************************************/
+/* Support Two RC Handles simultaneously*/
+#define BTIF_RC_NUM_CB 2
+/* Default index*/
+#define BTIF_RC_DEFAULT_INDEX 0
/* cod value for Headsets */
#define COD_AV_HEADSETS 0x0404
/* for AVRC 1.4 need to change this */
#define CHECK_RC_CONNECTED \
BTIF_TRACE_DEBUG("## %s ##", __FUNCTION__); \
- if (btif_rc_cb.rc_connected == FALSE) \
- { \
+ int clients; \
+ int conn_status = BT_STATUS_NOT_READY; \
+ for (clients = 0; clients < btif_max_rc_clients; clients++) \
+ { \
+ if ((btif_rc_cb[clients].rc_connected == TRUE)) \
+ conn_status = BT_STATUS_SUCCESS; \
+ } \
+ if(conn_status == BT_STATUS_NOT_READY) \
+ { \
BTIF_TRACE_WARNING("Function %s() called when RC is not connected", __FUNCTION__); \
- return BT_STATUS_NOT_READY; \
+ return BT_STATUS_NOT_READY; \
}
-#define FILL_PDU_QUEUE(index, ctype, label, pending) \
+#define FILL_PDU_QUEUE(idx, ctype, label, pending, index) \
{ \
- btif_rc_cb.rc_pdu_info[index].ctype = ctype; \
- btif_rc_cb.rc_pdu_info[index].label = label; \
- btif_rc_cb.rc_pdu_info[index].is_rsp_pending = pending; \
+ btif_rc_cb[index].rc_pdu_info[idx].ctype = ctype; \
+ btif_rc_cb[index].rc_pdu_info[idx].label = label; \
+ btif_rc_cb[index].rc_pdu_info[idx].is_rsp_pending = pending; \
}
-#define SEND_METAMSG_RSP(index, avrc_rsp) \
+#define SEND_METAMSG_RSP(index, avrc_rsp, idx) \
{ \
- if (btif_rc_cb.rc_pdu_info[index].is_rsp_pending == FALSE) \
+ if(btif_rc_cb[idx].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_metamsg_rsp(btif_rc_cb.rc_handle, btif_rc_cb.rc_pdu_info[index].label, \
- btif_rc_cb.rc_pdu_info[index].ctype, avrc_rsp); \
- btif_rc_cb.rc_pdu_info[index].ctype = 0; \
- btif_rc_cb.rc_pdu_info[index].label = 0; \
- btif_rc_cb.rc_pdu_info[index].is_rsp_pending = FALSE; \
+ send_metamsg_rsp(btif_rc_cb[idx].rc_handle, btif_rc_cb[idx].rc_pdu_info[index].label, \
+ btif_rc_cb[idx].rc_pdu_info[index].ctype, avrc_rsp); \
+ btif_rc_cb[idx].rc_pdu_info[index].ctype = 0; \
+ btif_rc_cb[idx].rc_pdu_info[index].label = 0; \
+ btif_rc_cb[idx].rc_pdu_info[index].is_rsp_pending = FALSE; \
}
-
-#define SEND_BROWSEMSG_RSP(index , avrc_rsp) \
+#define SEND_BROWSEMSG_RSP(index , avrc_rsp, rc_index) \
{ \
- if(btif_rc_cb.rc_pdu_info[index].is_rsp_pending == FALSE) \
+ if(btif_rc_cb[rc_index].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; \
+ send_browsemsg_rsp(btif_rc_cb[rc_index].rc_handle, btif_rc_cb[rc_index].rc_pdu_info[index].label, \
+ btif_rc_cb[rc_index].rc_pdu_info[index].ctype, avrc_rsp); \
+ btif_rc_cb[rc_index].rc_pdu_info[index].ctype = 0; \
+ btif_rc_cb[rc_index].rc_pdu_info[index].label = 0; \
}
/*****************************************************************************
BOOLEAN rc_features_processed;
UINT64 rc_playing_uid;
BOOLEAN rc_procedure_complete;
+ BOOLEAN rc_play_processed;
} btif_rc_cb_t;
typedef struct {
rc_device_t device;
#define MAX_UINPUT_PATHS 3
+static int btif_max_rc_clients = 1;
static const char* uinput_dev_path[] =
{"/dev/uinput", "/dev/input/uinput", "/dev/misc/uinput" };
static int uinput_fd = -1;
static int init_uinput (void);
static void close_uinput (void);
static void sleep_ms(period_ms_t timeout_ms);
+#if (AVRC_CTLR_INCLUDED == TRUE)
+static BOOLEAN conn_status = FALSE;
+#endif
static const struct {
const char *name;
static void send_metamsg_rsp (UINT8 rc_handle, UINT8 label,
tBTA_AV_CODE code, tAVRC_RESPONSE *pmetamsg_resp);
#if (AVRC_ADV_CTRL_INCLUDED == TRUE)
-static void register_volumechange(UINT8 label);
+static void register_volumechange(UINT8 label, int index);
#endif
static void lbl_init();
static void lbl_destroy();
static bt_status_t list_player_app_setting_value_cmd(uint8_t attrib_id);
static bt_status_t get_player_app_setting_cmd(uint8_t num_attrib, uint8_t* attrib_ids);
#endif
-static void btif_rc_upstreams_evt(UINT16 event, tAVRC_COMMAND* p_param, UINT8 ctype, UINT8 label);
-#if (AVRC_ADV_CTRL_INCLUDED == TRUE)
-static void btif_rc_upstreams_rsp_evt(UINT16 event, tAVRC_RESPONSE *pavrc_resp, UINT8 ctype, UINT8 label);
-#endif
static void rc_start_play_status_timer(void);
static bool absolute_volume_disabled(void);
-static bt_status_t set_addrplayer_rsp(btrc_status_t status_code);
+static void btif_rc_upstreams_evt(UINT16 event, tAVRC_COMMAND* p_param, UINT8 ctype, UINT8 label,
+ int index);
+static void btif_rc_upstreams_rsp_evt(UINT16 event, tAVRC_RESPONSE *pavrc_resp, UINT8 ctype, UINT8 label,
+ int index);
+static bt_status_t set_addrplayer_rsp(btrc_status_t status_code, bt_bdaddr_t *bd_addr);
+static int btif_rc_get_idx_by_addr(BD_ADDR address);
/*Added for Browsing Message Response */
static void send_browsemsg_rsp (UINT8 rc_handle, UINT8 label,
/*****************************************************************************
** Static variables
******************************************************************************/
-static btif_rc_cb_t btif_rc_cb;
+/* Two RC CBs needed to handle two connections*/
+static btif_rc_cb_t btif_rc_cb[BTIF_RC_NUM_CB];
static btrc_callbacks_t *bt_rc_callbacks = NULL;
static btrc_ctrl_callbacks_t *bt_rc_ctrl_callbacks = NULL;
/*****************************************************************************
** Static functions
******************************************************************************/
+static UINT8 btif_rc_get_idx_by_rc_handle(UINT8 rc_handle);
/*****************************************************************************
** Externs
extern BOOLEAN btif_hf_call_terminated_recently();
extern BOOLEAN check_cod(const bt_bdaddr_t *remote_bdaddr, uint32_t cod);
-extern fixed_queue_t *btu_general_alarm_queue;
+extern void btif_get_latest_playing_device(BD_ADDR address); //get the Playing device address
+extern BOOLEAN btif_av_is_playing();
+extern BOOLEAN btif_av_is_device_connected(BD_ADDR address);
+extern void btif_av_trigger_dual_handoff(BOOLEAN handoff, BD_ADDR address);
extern BOOLEAN btif_hf_is_call_idle();
+extern BOOLEAN btif_av_get_multicast_state();
+extern BOOLEAN btif_av_is_current_device(BD_ADDR address);
+extern UINT16 btif_av_get_num_connected_devices(void);
+extern UINT16 btif_av_get_num_playing_devices(void);
+
+extern fixed_queue_t *btu_general_alarm_queue;
/*****************************************************************************
** Functions
char *name = "AVRCP";
BTIF_TRACE_DEBUG("%s", __FUNCTION__);
- uinput_fd = uinput_create(name);
- if (uinput_fd < 0) {
- BTIF_TRACE_ERROR("%s AVRCP: Failed to initialize uinput for %s (%d)",
- __FUNCTION__, name, uinput_fd);
- } else {
- BTIF_TRACE_DEBUG("%s AVRCP: Initialized uinput for %s (fd=%d)",
- __FUNCTION__, name, uinput_fd);
+ if (uinput_fd < 0)
+ {
+ BTIF_TRACE_DEBUG("Create Uinput device");
+ uinput_fd = uinput_create(name);
+ if (uinput_fd < 0) {
+ BTIF_TRACE_ERROR("%s AVRCP: Failed to initialize uinput for %s (%d)",
+ __FUNCTION__, name, uinput_fd);
+ }
+ else
+ {
+ BTIF_TRACE_DEBUG("%s AVRCP: Initialized uinput for %s (fd=%d)",
+ __FUNCTION__, name, uinput_fd);
+ }
}
return uinput_fd;
}
void close_uinput (void)
{
+ //Dont close uinput untill all connections are teared down
+ // Since we support Dual AVRCP conn now.
BTIF_TRACE_DEBUG("%s", __FUNCTION__);
if (uinput_fd > 0) {
ioctl(uinput_fd, UI_DEV_DESTROY);
}
}
+
#if (AVRC_CTLR_INCLUDED == TRUE)
void rc_cleanup_sent_cmd (void *p_data)
{
}
-void handle_rc_ctrl_features(BD_ADDR bd_addr)
+void handle_rc_ctrl_features(int index)
{
- BTIF_TRACE_DEBUG(" %s rc_feat_processed = %d", __FUNCTION__, btif_rc_cb.rc_features_processed);
- if (btif_rc_cb.rc_features_processed == TRUE)
- return;
- if ((btif_rc_cb.rc_features & BTA_AV_FEAT_RCTG)||
- ((btif_rc_cb.rc_features & BTA_AV_FEAT_RCCT)&&
- (btif_rc_cb.rc_features & BTA_AV_FEAT_ADV_CTRL)))
+ if ((btif_rc_cb[index].rc_features & BTA_AV_FEAT_RCTG)||
+ ((btif_rc_cb[index].rc_features & BTA_AV_FEAT_RCCT)&&
+ (btif_rc_cb[index].rc_features & BTA_AV_FEAT_ADV_CTRL)))
{
bt_bdaddr_t rc_addr;
int rc_features = 0;
- bdcpy(rc_addr.address,bd_addr);
+ bdcpy(rc_addr.address, btif_rc_cb[index].rc_addr);
- if ((btif_rc_cb.rc_features & BTA_AV_FEAT_ADV_CTRL)&&
- (btif_rc_cb.rc_features & BTA_AV_FEAT_RCCT))
+ if ((btif_rc_cb[index].rc_features & BTA_AV_FEAT_ADV_CTRL)&&
+ (btif_rc_cb[index].rc_features & BTA_AV_FEAT_RCCT))
{
rc_features |= BTRC_FEAT_ABSOLUTE_VOLUME;
}
- if ((btif_rc_cb.rc_features & BTA_AV_FEAT_METADATA)&&
- (btif_rc_cb.rc_features & BTA_AV_FEAT_VENDOR))
+ if ((btif_rc_cb[index].rc_features & BTA_AV_FEAT_METADATA)&&
+ (btif_rc_cb[index].rc_features & BTA_AV_FEAT_VENDOR)&&
+ (btif_rc_cb[index].rc_features_processed != TRUE))
{
rc_features |= BTRC_FEAT_METADATA;
/* Mark rc features processed to avoid repeating
* the AVRCP procedure every time on receiving this
* update.
*/
- if ((btif_rc_cb.rc_features_processed == FALSE) &&
+ if ((btif_rc_cb[index].rc_features_processed == FALSE) &&
btif_av_is_sink_enabled())
{
- btif_rc_cb.rc_features_processed = TRUE;
+ btif_rc_cb[index].rc_features_processed = TRUE;
getcapabilities_cmd (AVRC_CAP_COMPANY_ID);
}
}
}
#endif
-void handle_rc_features(BD_ADDR bd_addr)
+void handle_rc_features(int index)
{
if (bt_rc_callbacks != NULL)
{
- btrc_remote_features_t rc_features = BTRC_FEAT_NONE;
- bt_bdaddr_t rc_addr;
+ btrc_remote_features_t rc_features = BTRC_FEAT_NONE;
+ bt_bdaddr_t rc_addr;
+ bt_bdaddr_t avdtp_addr;
+ bdstr_t addr1, addr2;
- bdcpy(rc_addr.address, btif_rc_cb.rc_addr);
- bt_bdaddr_t avdtp_addr = btif_av_get_addr();
+ bdcpy(rc_addr.address, btif_rc_cb[index].rc_addr);
+ avdtp_addr = btif_av_get_addr(btif_rc_cb[index].rc_addr);
- bdstr_t addr1, addr2;
- BTIF_TRACE_DEBUG("%s: AVDTP Address: %s AVCTP address: %s", __func__,
- bdaddr_to_string(&avdtp_addr, addr1, sizeof(addr1)),
- bdaddr_to_string(&rc_addr, addr2, sizeof(addr2)));
+ BTIF_TRACE_DEBUG("AVDTP Address : %s AVCTP address: %s",
+ bdaddr_to_string(&avdtp_addr, addr1, sizeof(bdstr_t)),
+ bdaddr_to_string(&rc_addr, addr2, sizeof(bdstr_t)) );
- if (interop_match_addr(INTEROP_DISABLE_ABSOLUTE_VOLUME, &rc_addr)
- || absolute_volume_disabled()
- || bdcmp(avdtp_addr.address, rc_addr.address))
- btif_rc_cb.rc_features &= ~BTA_AV_FEAT_ADV_CTRL;
+ //if (interop_match(INTEROP_DISABLE_ABSOLUTE_VOLUME, &rc_addr)
+ if ( absolute_volume_disabled()
+ || bdcmp(avdtp_addr.address, rc_addr.address))
+ btif_rc_cb[index].rc_features &= ~BTA_AV_FEAT_ADV_CTRL;
- if (btif_rc_cb.rc_features & BTA_AV_FEAT_BROWSE)
+ if (btif_rc_cb[index].rc_features & BTA_AV_FEAT_BROWSE)
+ {
+ rc_features |= BTRC_FEAT_BROWSE;
+ }
+ if ( (btif_rc_cb[index].rc_features & BTA_AV_FEAT_ADV_CTRL) &&
+ (btif_rc_cb[index].rc_features & BTA_AV_FEAT_RCTG))
+ {
+ rc_features |= BTRC_FEAT_ABSOLUTE_VOLUME;
+ }
+ if (btif_rc_cb[index].rc_features & BTA_AV_FEAT_METADATA)
+ {
+ rc_features |= BTRC_FEAT_METADATA;
+ /* Mark rc features processed to avoid repeating
+ * the AVRCP procedure every time on receiving this
+ * update.
+ */
+ btif_rc_cb[index].rc_features_processed = TRUE;
+ getcapabilities_cmd (AVRC_CAP_COMPANY_ID);
+ }
+ BTIF_TRACE_DEBUG("%s: rc_features=0x%x", __FUNCTION__, rc_features);
+ if (btif_rc_cb[index].rc_connected)
+ {
+ BTIF_TRACE_DEBUG("%s: update App on supported features", __FUNCTION__);
+ HAL_CBACK(bt_rc_callbacks, remote_features_cb, &rc_addr, rc_features)
+ }
+ else
+ {
+ BTIF_TRACE_DEBUG("%s: skipping feature update to App", __FUNCTION__);
+ }
+#if (AVRC_ADV_CTRL_INCLUDED == TRUE)
+ BTIF_TRACE_DEBUG("Checking for feature flags in btif_rc_handler with label %d",
+ btif_rc_cb[index].rc_vol_label);
+ // Register for volume change on connect
+ if (btif_rc_cb[index].rc_features & BTA_AV_FEAT_ADV_CTRL &&
+ btif_rc_cb[index].rc_features & BTA_AV_FEAT_RCTG)
+ {
+ rc_transaction_t *p_transaction=NULL;
+ bt_status_t status = BT_STATUS_NOT_READY;
+ if (MAX_LABEL == btif_rc_cb[index].rc_vol_label)
+ {
+ status=get_transaction(&p_transaction);
+ }
+ else
+ {
+ p_transaction=get_transaction_by_lbl(btif_rc_cb[index].rc_vol_label);
+ if (NULL != p_transaction)
+ {
+ BTIF_TRACE_DEBUG("register_volumechange already in progress for label %d",
+ btif_rc_cb[index].rc_vol_label);
+ return;
+ }
+ else
+ status = get_transaction(&p_transaction);
+ }
+
+ if (BT_STATUS_SUCCESS == status && NULL!=p_transaction)
+ {
+ btif_rc_cb[index].rc_vol_label=p_transaction->lbl;
+ register_volumechange(btif_rc_cb[index].rc_vol_label, index);
+ }
+ }
+#endif
+ }
+ else
{
- rc_features |= BTRC_FEAT_BROWSE;
+ /*Disable all TG related bits if AVRCP TG feature is not enabled*/
+ BTIF_TRACE_WARNING("Avrcp TG role not enabled, disabling TG specific featuremask");
+ btif_rc_cb[index].rc_features &= ~BTA_AV_FEAT_ADV_CTRL;
+ btif_rc_cb[index].rc_features &= ~BTA_AV_FEAT_BROWSE;
+ btif_rc_cb[index].rc_features &= ~BTA_AV_FEAT_METADATA;
}
+}
-#if (AVRC_ADV_CTRL_INCLUDED == TRUE)
- if ( (btif_rc_cb.rc_features & BTA_AV_FEAT_ADV_CTRL) &&
- (btif_rc_cb.rc_features & BTA_AV_FEAT_RCTG))
+/***************************************************************************
+ * Function btif_rc_get_connection_state
+ *
+ * - Argument: none
+ *
+ * - Description: Return true if any RC is in connected state
+ *
+ ***************************************************************************/
+static BOOLEAN btif_rc_get_connection_state()
+{
+ int clients;
+
+ for (clients = 0; clients < btif_max_rc_clients; clients++)
{
- rc_features |= BTRC_FEAT_ABSOLUTE_VOLUME;
+ if (btif_rc_cb[clients].rc_connected == TRUE)
+ {
+ return TRUE;
+ }
}
-#endif
+ return FALSE;
+}
- if (btif_rc_cb.rc_features & BTA_AV_FEAT_METADATA)
+/***************************************************************************
+ * Function btif_rc_get_valid_idx
+ *
+ * - Argument: none
+ *
+ * - Description: Gets the index which is ready for new connection
+ *
+ ***************************************************************************/
+static int btif_rc_get_valid_idx()
+{
+ int i;
+ for (i = 0; i < btif_max_rc_clients; i++)
{
- rc_features |= BTRC_FEAT_METADATA;
+ if (!(btif_rc_cb[i].rc_connected))
+ break;
}
- if (btif_rc_cb.rc_features & BTA_AV_FEAT_AVRC_UI_UPDATE)
+ return i;
+}
+
+/***************************************************************************
+ * Function btif_rc_get_idx_by_rc_handle
+ *
+ * - Argument: rc handle
+ *
+ * - Description: Gets the RC handle index of matching handle
+ *
+ ***************************************************************************/
+static UINT8 btif_rc_get_idx_by_rc_handle(UINT8 rc_handle)
+{
+ UINT8 i;
+
+ for (i = 0; i < btif_max_rc_clients; i++)
{
- rc_features |= BTRC_FEAT_AVRC_UI_UPDATE;
+ if (btif_rc_cb[i].rc_handle == rc_handle)
+ break;
}
+ return i;
+}
- BTIF_TRACE_DEBUG("%s: rc_features=0x%x", __FUNCTION__, rc_features);
- HAL_CBACK(bt_rc_callbacks, remote_features_cb, &rc_addr, rc_features)
+/* Get the address of device on which PLAY command came
+* This address will be used in AV IF layer to determine
+* On which device to START playback. */
+/***************************************************************************
+ * Function btif_rc_get_playing_device
+ *
+ * - Argument: bd_addr
+ *
+ * - Description: Copies the BD address of current playing device
+ *
+ ***************************************************************************/
+void btif_rc_get_playing_device(BD_ADDR address)
+{
+ int i;
+ for (i = 0; i < btif_max_rc_clients; i++)
+ {
+ if (btif_rc_cb[i].rc_play_processed)
+ {
+ //copy bd address
+ bdcpy(address, btif_rc_cb[i].rc_addr);
+ }
+ }
+}
-#if (AVRC_ADV_CTRL_INCLUDED == TRUE)
- BTIF_TRACE_DEBUG("%s Checking for feature flags in btif_rc_handler with label %d",
- __FUNCTION__, btif_rc_cb.rc_vol_label);
- // Register for volume change on connect
- if (btif_rc_cb.rc_features & BTA_AV_FEAT_ADV_CTRL &&
- btif_rc_cb.rc_features & BTA_AV_FEAT_RCTG)
- {
- rc_transaction_t *p_transaction=NULL;
- bt_status_t status = BT_STATUS_NOT_READY;
- if (MAX_LABEL==btif_rc_cb.rc_vol_label)
- {
- status=get_transaction(&p_transaction);
- }
- else
- {
- p_transaction=get_transaction_by_lbl(btif_rc_cb.rc_vol_label);
- if (NULL!=p_transaction)
- {
- BTIF_TRACE_DEBUG("%s register_volumechange already in progress for label %d",
- __FUNCTION__, btif_rc_cb.rc_vol_label);
- return;
- } else {
- status=get_transaction(&p_transaction);
- }
- }
- if (BT_STATUS_SUCCESS == status && NULL!=p_transaction)
- {
- btif_rc_cb.rc_vol_label=p_transaction->lbl;
- register_volumechange(btif_rc_cb.rc_vol_label);
- }
- }
-#endif
+/* Reset the Play trigger, once the AVDTP START is
+* sent, called from AV IF layer. */
+/***************************************************************************
+ * Function btif_rc_clear_playing_state
+ *
+ * - Argument: BOOLEAN
+ *
+ * - Description: Clears the PLAY processed.rc_play_processed denotes
+ * play command has been processed for this device.
+ *
+ ***************************************************************************/
+void btif_rc_clear_playing_state(BOOLEAN state)
+{
+ int i;
+ for (i = 0; i < btif_max_rc_clients; i++)
+ {
+ if (btif_rc_cb[i].rc_play_processed)
+ {
+ btif_rc_cb[i].rc_play_processed = state;
+ }
+ }
+}
+
+/***************************************************************************
+ * Function btif_rc_clear_priority
+ *
+ * - Argument: Device address
+ *
+ * - Description: Clears the priority information for the device
+ * This can be used while AV disconnection for the device.
+ * Setting of rc_play_processed flag could have been avoided
+ * looking at the stream state, but it might still leave some
+ * corner case of audio suspending just before the play takes
+ * effect.
+ ***************************************************************************/
+void btif_rc_clear_priority(BD_ADDR address)
+{
+ int index;
+
+ index = btif_rc_get_idx_by_addr(address);
+ if(index < btif_max_rc_clients)
+ {
+ btif_rc_cb[index].rc_play_processed = FALSE;
}
}
{
BTIF_TRACE_IMP("%s: rc_handle: %d", __FUNCTION__, p_rc_open->rc_handle);
bt_status_t result = BT_STATUS_SUCCESS;
-#if (AVRC_CTLR_INCLUDED == TRUE)
bt_bdaddr_t rc_addr;
-#endif
-
- if (p_rc_open->status == BTA_AV_SUCCESS)
- {
- //check if already some RC is connected
- if (btif_rc_cb.rc_connected)
+ int index;
+ if(p_rc_open->status == BTA_AV_SUCCESS)
+ {
+ //Check if already some RC is connected
+ /*Now we can have two RC connections
+ * Check should be here about 3rd connection too.
+ * Get the free or MAX index. Max index should be rejected. */
+ index = btif_rc_get_valid_idx();
+ if (index == btif_max_rc_clients)
{
- BTIF_TRACE_ERROR("%s Got RC OPEN in connected state, Connected RC: %d \
- and Current RC: %d", __FUNCTION__, btif_rc_cb.rc_handle,p_rc_open->rc_handle );
- if ((btif_rc_cb.rc_handle != p_rc_open->rc_handle)
- && (bdcmp(btif_rc_cb.rc_addr, p_rc_open->peer_addr)))
- {
- BTIF_TRACE_DEBUG("%s Got RC connected for some other handle", __FUNCTION__);
- BTA_AvCloseRc(p_rc_open->rc_handle);
- return;
- }
+ /*Reached Max, this connection must be rejected*/
+ BTIF_TRACE_ERROR("RC OPEN in MAX connected state");
+ BTA_AvCloseRc(p_rc_open->rc_handle);
+ return;
}
- memcpy(btif_rc_cb.rc_addr, p_rc_open->peer_addr, sizeof(BD_ADDR));
- btif_rc_cb.rc_features = p_rc_open->peer_features;
- btif_rc_cb.rc_vol_label=MAX_LABEL;
- btif_rc_cb.rc_volume=MAX_VOLUME;
+ /*Use the index for this RC connection*/
+ BTIF_TRACE_DEBUG("Got RC OPEN on the index= %d", index);
+ memcpy(btif_rc_cb[index].rc_addr, p_rc_open->peer_addr, sizeof(BD_ADDR));
+ btif_rc_cb[index].rc_features = p_rc_open->peer_features;
+ btif_rc_cb[index].rc_vol_label = MAX_LABEL;
+ btif_rc_cb[index].rc_volume = MAX_VOLUME;
- btif_rc_cb.rc_connected = TRUE;
- btif_rc_cb.rc_handle = p_rc_open->rc_handle;
+ btif_rc_cb[index].rc_connected = TRUE;
+ btif_rc_cb[index].rc_handle = p_rc_open->rc_handle;
- /* on locally initiated connection we will get remote features as part of connect */
- if (btif_rc_cb.rc_features != 0)
- handle_rc_features(btif_rc_cb.rc_addr);
if (bt_rc_callbacks)
{
result = uinput_driver_check();
- if (result == BT_STATUS_SUCCESS)
+ if(result == BT_STATUS_SUCCESS)
{
init_uinput();
}
}
else
{
- BTIF_TRACE_WARNING("%s Avrcp TG role not enabled, not initializing UInput",
- __FUNCTION__);
+ BTIF_TRACE_WARNING("Avrcp TG role not enabled, not initializing UInput");
}
- BTIF_TRACE_DEBUG("%s handle_rc_connect features %d ",__FUNCTION__, btif_rc_cb.rc_features);
+ bdcpy(rc_addr.address, btif_rc_cb[index].rc_addr);
+ if (btif_rc_cb[index].rc_features & BTA_AV_FEAT_RCCT)
+ {
+ HAL_CBACK(bt_rc_callbacks, connection_state_cb, TRUE, &rc_addr);
+ }
+ /* on locally initiated connection we will get remote features as part of connect */
+ if (btif_rc_cb[index].rc_features != 0)
+ handle_rc_features(index);
+ BTIF_TRACE_DEBUG(" handle_rc_connect features %d ",btif_rc_cb[index].rc_features);
#if (AVRC_CTLR_INCLUDED == TRUE)
- btif_rc_cb.rc_playing_uid = RC_INVALID_TRACK_ID;
- bdcpy(rc_addr.address, btif_rc_cb.rc_addr);
- if (bt_rc_ctrl_callbacks != NULL)
+ /* report connection state if device is AVRCP target */
+ if (btif_rc_cb[index].rc_features & BTA_AV_FEAT_RCTG)
{
HAL_CBACK(bt_rc_ctrl_callbacks, connection_state_cb, TRUE, &rc_addr);
+ conn_status = TRUE;
}
- /* report connection state if remote device is AVRCP target */
- if ((btif_rc_cb.rc_features & BTA_AV_FEAT_RCTG)||
- ((btif_rc_cb.rc_features & BTA_AV_FEAT_RCCT)&&
- (btif_rc_cb.rc_features & BTA_AV_FEAT_ADV_CTRL)))
+ else
{
- handle_rc_ctrl_features(btif_rc_cb.rc_addr);
+ BTIF_TRACE_ERROR("RC connection state not updated to upper layer");
+ conn_status = FALSE;
}
#endif
+ /* on locally initiated connection we will get remote features as part of connect
+ Delay this update till connection update reaches Apps*/
}
else
{
BTIF_TRACE_ERROR("%s Connect failed with error code: %d",
__FUNCTION__, p_rc_open->status);
- btif_rc_cb.rc_connected = FALSE;
}
}
***************************************************************************/
void handle_rc_disconnect (tBTA_AV_RC_CLOSE *p_rc_close)
{
-#if (AVRC_CTLR_INCLUDED == TRUE)
bt_bdaddr_t rc_addr;
tBTA_AV_FEAT features;
-#endif
+ UINT8 index;
+ BOOLEAN is_connected = 0;
+
BTIF_TRACE_IMP("%s: rc_handle: %d", __FUNCTION__, p_rc_close->rc_handle);
- if ((p_rc_close->rc_handle != btif_rc_cb.rc_handle)
- && (bdcmp(btif_rc_cb.rc_addr, p_rc_close->peer_addr)))
+
+ index = btif_rc_get_idx_by_rc_handle(p_rc_close->rc_handle);
+ if (index == btif_max_rc_clients)
{
BTIF_TRACE_ERROR("Got disconnect of unknown device");
return;
}
-#if (AVRC_CTLR_INCLUDED == TRUE)
- bdcpy(rc_addr.address, btif_rc_cb.rc_addr);
- features = btif_rc_cb.rc_features;
- /* Clean up AVRCP procedure flags */
- memset(&btif_rc_cb.rc_app_settings, 0,
- sizeof(btif_rc_player_app_settings_t));
- btif_rc_cb.rc_features_processed = FALSE;
- btif_rc_cb.rc_procedure_complete = FALSE;
- rc_stop_play_status_timer();
- /* Check and clear the notification event list */
- if (btif_rc_cb.rc_supported_event_list != NULL)
- {
- list_clear(btif_rc_cb.rc_supported_event_list);
- btif_rc_cb.rc_supported_event_list = NULL;
+ if ((p_rc_close->rc_handle != btif_rc_cb[index].rc_handle)
+ && (bdcmp(btif_rc_cb[index].rc_addr, p_rc_close->peer_addr)))
+ {
+ BTIF_TRACE_ERROR("Got disconnect of unknown device");
+ return;
}
-#endif
- btif_rc_cb.rc_handle = 0;
- btif_rc_cb.rc_connected = FALSE;
- memset(btif_rc_cb.rc_addr, 0, sizeof(BD_ADDR));
- memset(btif_rc_cb.rc_notif, 0, sizeof(btif_rc_cb.rc_notif));
-
- btif_rc_cb.rc_features = 0;
- btif_rc_cb.rc_vol_label=MAX_LABEL;
- btif_rc_cb.rc_volume=MAX_VOLUME;
- if (device.lbllock_destroyed != TRUE)
+ btif_rc_cb[index].rc_handle = BTIF_RC_HANDLE_NONE;
+ btif_rc_cb[index].rc_connected = FALSE;
+ bdcpy(rc_addr.address, btif_rc_cb[index].rc_addr);
+ memset(btif_rc_cb[index].rc_addr, 0, sizeof(BD_ADDR));
+ memset(btif_rc_cb[index].rc_notif, 0, sizeof(btif_rc_cb[index].rc_notif));
+ features = btif_rc_cb[index].rc_features;
+ btif_rc_cb[index].rc_features = 0;
+ btif_rc_cb[index].rc_vol_label = MAX_LABEL;
+ btif_rc_cb[index].rc_volume = MAX_VOLUME;
+ btif_rc_cb[index].rc_play_processed = FALSE;
+ btif_rc_cb[index].rc_pending_play = FALSE;
+
+ //CLose Uinput only when all RCs are disconnected
+ is_connected = btif_rc_get_connection_state();
+ BTIF_TRACE_DEBUG("RC connected : %d", is_connected);
+ if (is_connected != TRUE && device.lbllock_destroyed != TRUE)
+ {
+ BTIF_TRACE_DEBUG("Clear UINPUT and transactions when zero RC left");
init_all_transactions();
-
- if (bt_rc_callbacks != NULL)
- {
close_uinput();
}
- else
- {
- BTIF_TRACE_WARNING("%s Avrcp TG role not enabled, not closing UInput", __FUNCTION__);
- }
-
if (!bdcmp(bd_null, rc_addr.address))
{
BTIF_TRACE_DEBUG("Cleanup already done");
HAL_CBACK(bt_rc_ctrl_callbacks, connection_state_cb, FALSE, &rc_addr);
}
#endif
+ if (features & BTA_AV_FEAT_RCCT)
+ {
+ HAL_CBACK(bt_rc_callbacks, connection_state_cb, FALSE, &rc_addr);
+ }
}
/***************************************************************************
* - Description: Remote control command handler
*
***************************************************************************/
+
+/* Rules: Only currenlty playing device's Passthrough commands
+* will be entertained.
+* While playing on Dev 1, if Dev2 sends Play, just respond it
+* without passing it to APP and in parallel start a protocol
+* suspend/pause the playback on DEV1 and Start on DEV2
+* Making sure that music is not paused and transfer happens seamless. */
void handle_rc_passthrough_cmd ( tBTA_AV_REMOTE_CMD *p_remote_cmd)
{
const char *status;
int pressed, i;
+ UINT8 index;
+ BD_ADDR address;
+ bt_bdaddr_t remote_address;
+ BOOLEAN ignore_play_processed = FALSE;
+
+ if (p_remote_cmd == NULL)
+ return;
+
+ index = btif_rc_get_idx_by_rc_handle(p_remote_cmd->rc_handle);
+ if (index == btif_max_rc_clients)
+ {
+ BTIF_TRACE_ERROR("Passthrough on invalid index");
+ return;
+ }
+ /* Multicast: Passthru command on AVRCP only device when connected
+ * to other A2DP devices, ignore it.
+ */
+ if (btif_av_is_connected() && !btif_av_is_device_connected(btif_rc_cb[index].rc_addr))
+ {
+ BTIF_TRACE_ERROR("Passthrough on AVRCP only device: Ignore..");
+ return;
+ }
+ /* Trigger DUAL Handoff when support single streaming */
+ if (btif_av_is_playing() &&
+ (btif_av_get_multicast_state() == FALSE))
+ {
+ /*compare the bd addr of current playing dev and this dev*/
+ btif_get_latest_playing_device(address);
+ if (bdcmp(btif_rc_cb[index].rc_addr, address) == 0)
+ {
+ APPL_TRACE_WARNING("Passthrough on the playing device");
+ if ((p_remote_cmd->rc_id == BTA_AV_RC_PLAY) &&
+ (p_remote_cmd->key_state == AVRC_STATE_PRESS))
+ {
+ APPL_TRACE_WARNING("Play again");
+ ignore_play_processed = TRUE;
+ }
+ }
+ else
+ {
+ BTIF_TRACE_DEBUG("Passthrough command on other device");
+ if (p_remote_cmd->rc_id == BTA_AV_RC_PLAY)
+ {
+ if (btif_av_is_device_connected(btif_rc_cb[index].rc_addr))
+ {
+ /* Trigger suspend on currently playing device
+ * Allow the Play to be sent to Music player to
+ * address Play during Pause(Local/DUT initiated)
+ * but SUSPEND not triggered by Audio module.
+ */
+ if (p_remote_cmd->key_state == AVRC_STATE_PRESS)
+ {
+ BTIF_TRACE_DEBUG("Trigger dual handoff for this play command");
+ btif_rc_cb[index].rc_play_processed = TRUE;
+ btif_av_trigger_dual_handoff(TRUE, btif_rc_cb[index].rc_addr);
+ }
+ }
+ else
+ {
+ APPL_TRACE_WARNING("%s: Command Invalid on %d", __FUNCTION__, index);
+ return;
+ }
+ }
+ else
+ {
+ APPL_TRACE_WARNING("%s:Ignore all Passthrough on %d", __FUNCTION__, index);
+ return;
+ }
+ }
+ }
BTIF_TRACE_DEBUG("%s: p_remote_cmd->rc_id=%d", __FUNCTION__, p_remote_cmd->rc_id);
/* If AVRC is open and peer sends PLAY but there is no AVDT, then we queue-up this PLAY */
if (p_remote_cmd->key_state == AVRC_STATE_PRESS)
{
APPL_TRACE_WARNING("%s: AVDT not open, queuing the PLAY command", __FUNCTION__);
- btif_rc_cb.rc_pending_play = TRUE;
+ btif_rc_cb[index].rc_pending_play = TRUE;
}
return;
}
- if ((p_remote_cmd->rc_id == BTA_AV_RC_PAUSE) && (btif_rc_cb.rc_pending_play))
+ if ((p_remote_cmd->rc_id == BTA_AV_RC_PAUSE) && (btif_rc_cb[index].rc_pending_play))
{
APPL_TRACE_WARNING("%s: Clear the pending PLAY on PAUSE received", __FUNCTION__);
- btif_rc_cb.rc_pending_play = FALSE;
+ btif_rc_cb[index].rc_pending_play = FALSE;
return;
}
if ((p_remote_cmd->rc_id == BTA_AV_RC_VOL_UP)||(p_remote_cmd->rc_id == BTA_AV_RC_VOL_DOWN))
APPL_TRACE_WARNING("%s: Stream suspended, ignore STOP cmd",__FUNCTION__);
return;
}
+ if(!btif_av_is_connected())
+ {
+ APPL_TRACE_WARNING("%s: AVDT not open, discarding pass-through command: %d",
+ __FUNCTION__, p_remote_cmd->rc_id);
+ return;
+ }
if (p_remote_cmd->key_state == AVRC_STATE_RELEASE) {
status = "released";
pressed = 0;
- } else {
+ }
+ else
+ {
status = "pressed";
pressed = 1;
}
if (p_remote_cmd->rc_id == BTA_AV_RC_FAST_FOR || p_remote_cmd->rc_id == BTA_AV_RC_REWIND) {
- HAL_CBACK(bt_rc_callbacks, passthrough_cmd_cb, p_remote_cmd->rc_id, pressed);
+ bdcpy(remote_address.address, btif_rc_cb[index].rc_addr);
+ HAL_CBACK(bt_rc_callbacks, passthrough_cmd_cb, p_remote_cmd->rc_id, pressed, &remote_address);
return;
}
-
+ /*Update the device on which PLAY is issued*/
+ if (p_remote_cmd->rc_id == BTA_AV_RC_PLAY)
+ {
+ BTIF_TRACE_DEBUG("PLAY command on the Index: = %d", index);
+ if (p_remote_cmd->key_state == AVRC_STATE_PRESS && !ignore_play_processed)
+ btif_rc_cb[index].rc_play_processed = TRUE;
+ }
for (i = 0; key_map[i].name != NULL; i++) {
if (p_remote_cmd->rc_id == key_map[i].avrcp) {
BTIF_TRACE_DEBUG("%s: %s %s", __FUNCTION__, key_map[i].name, status);
}
/***************************************************************************
+ * Function btif_rc_send_pause_command
+ *
+ * - Argument: None
+ *
+ * - Description: Sends PAUSE key event to Upper layer.
+ *
+ ***************************************************************************/
+void btif_rc_send_pause_command()
+{
+ int rc_id;
+
+ rc_id = BTA_AV_RC_PAUSE;
+ BTIF_TRACE_DEBUG("Send Pause to music if playing is remotely disconnected");
+
+ send_key(uinput_fd, KEY_PAUSECD, 1);
+ sleep_ms(30); // 30ms
+ send_key(uinput_fd, KEY_PAUSECD, 0);
+}
+
+/***************************************************************************
* Function handle_rc_passthrough_rsp
*
* - Argument: tBTA_AV_REMOTE_RSP passthrough command response
{
#if (AVRC_CTLR_INCLUDED == TRUE)
const char *status;
- if (btif_rc_cb.rc_features & BTA_AV_FEAT_RCTG)
+ int index = BTIF_RC_DEFAULT_INDEX; // 0th index is RC
+ if (btif_rc_cb[index].rc_features & BTA_AV_FEAT_RCTG)
{
int key_state;
if (p_remote_rsp->key_state == AVRC_STATE_RELEASE)
#if (AVRC_CTLR_INCLUDED == TRUE)
const char *status;
UINT8 vendor_id = 0;
- if (btif_rc_cb.rc_features & BTA_AV_FEAT_RCTG)
+ int index = BTIF_RC_DEFAULT_INDEX; // 0th index is RC
+ if (btif_rc_cb[index].rc_features & BTA_AV_FEAT_RCTG)
{
int key_state;
if (p_remote_rsp->key_state == AVRC_STATE_RELEASE)
UINT8 scratch_buf[512] = {0};
tAVRC_COMMAND avrc_command = {0};
tAVRC_STS status;
+ UINT8 index;
+
+ //Get the index of RC
+ index = btif_rc_get_idx_by_rc_handle(pmeta_msg->rc_handle);
+ if (index == btif_max_rc_clients)
+ {
+ BTIF_TRACE_ERROR("%s: Invalid RC index", __FUNCTION__);
+ return;
+ }
BTIF_TRACE_EVENT("+ %s", __FUNCTION__);
UINT8 event_id = avrc_command.reg_notif.event_id;
BTIF_TRACE_EVENT("%s:New register notification received.event_id:%s,label:0x%x,code:%x",
__FUNCTION__,dump_rc_notification_event_id(event_id), pmeta_msg->label,pmeta_msg->code);
- btif_rc_cb.rc_notif[event_id-1].bNotify = TRUE;
- btif_rc_cb.rc_notif[event_id-1].label = pmeta_msg->label;
+ btif_rc_cb[index].rc_notif[event_id-1].bNotify = TRUE;
+ btif_rc_cb[index].rc_notif[event_id-1].label = pmeta_msg->label;
if (event_id == AVRC_EVT_UIDS_CHANGE)
{
*btif context, no context switching is required. Invoke
* btif_rc_upstreams_evt directly from here. */
btif_rc_upstreams_evt((uint16_t)avrc_command.cmd.pdu, &avrc_command, pmeta_msg->code,
- pmeta_msg->label);
+ pmeta_msg->label, index);
}
}
//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
+ if (length < 10)
{
BTIF_TRACE_ERROR("GET_FOLDER_ITEMS: length error: =%d",length);
return TRUE;
UINT8 event;
UINT16 length;
tAVRC_COMMAND cmd;
- UINT8 *start_item, *p_length, *p_data;
- UINT8 *end_item;
+ UINT8 *p_length, *p_data;
tAVRC_RESPONSE avrc_rsp;
UINT8 dropmsg = TRUE;
+ UINT8 index = btif_rc_get_idx_by_rc_handle(pbrowse_msg->rc_handle);
+ if (index == btif_max_rc_clients)
+ {
+ BTIF_TRACE_ERROR("%s: Invalid RC index", __FUNCTION__);
+ return;
+ }
BTIF_TRACE_EVENT("+ %s", __FUNCTION__);
BTIF_TRACE_EVENT("pbrowse_msg PDU_ID :%x",pbrowse_msg->p_msg->browse.p_browse_data[0]);
}
if (dropmsg == FALSE)
{
- btif_rc_upstreams_evt(event,&cmd,0,pbrowse_msg->label);
+ btif_rc_upstreams_evt(event,&cmd,0,pbrowse_msg->label, index);
}
}
break;
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);
+ btif_rc_upstreams_evt(event, &cmd, 0, pbrowse_msg->label, index);
dropmsg = FALSE;
}
break;
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);
+ btif_rc_upstreams_evt(event, &cmd, 0, pbrowse_msg->label, index);
dropmsg = FALSE;
}
break;
case AVRC_PDU_GET_ITEM_ATTRIBUTES:
{
UINT16 packet_len;
- UINT8 num_attr, index;
+ UINT8 num_attr, idx;
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];
if (num_attr == 0)
{
/* remote requested all Attribute ID*/
- for (index = 0; index < BTRC_MAX_ELEM_ATTR_SIZE; index++)
+ for (idx = 0; idx < BTRC_MAX_ELEM_ATTR_SIZE; idx++)
{
- cmd.get_attrs.attrs[index] = index + 1;
+ cmd.get_attrs.attrs[idx] = idx + 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++)
+ for (idx = 0; idx < num_attr ; idx++)
{
- BE_STREAM_TO_UINT32(cmd.get_attrs.attrs[index], p_data);
- BTIF_TRACE_ERROR("GetItemAttr attrid: = %d", cmd.get_attrs.attrs[index]);
+ BE_STREAM_TO_UINT32(cmd.get_attrs.attrs[idx], p_data);
+ BTIF_TRACE_ERROR("GetItemAttr attrid: = %d", cmd.get_attrs.attrs[idx]);
}
}
- btif_rc_upstreams_evt(event, &cmd, 0, pbrowse_msg->label);
+ btif_rc_upstreams_evt(event, &cmd, 0, pbrowse_msg->label, index);
dropmsg = FALSE;
}
}
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);
+ send_browsemsg_rsp(btif_rc_cb[index].rc_handle, pbrowse_msg->label, 0, &avrc_rsp);
}
}
***************************************************************************/
void btif_rc_handler(tBTA_AV_EVT event, tBTA_AV *p_data)
{
+ UINT8 index;
+
BTIF_TRACE_IMP ("%s event:%s", __FUNCTION__, dump_rc_event(event));
switch (event)
{
case BTA_AV_REMOTE_CMD_EVT:
{
- if (bt_rc_callbacks != NULL)
- {
- BTIF_TRACE_DEBUG("%s rc_id:0x%x key_state:%d",
- __FUNCTION__, p_data->remote_cmd.rc_id,
+ BTIF_TRACE_DEBUG("rc_id:0x%x key_state:%d", p_data->remote_cmd.rc_id,
p_data->remote_cmd.key_state);
- /** In race conditions just after 2nd AVRCP is connected
- * remote might send pass through commands, so check for
- * Rc handle before processing pass through commands
- **/
- if (btif_rc_cb.rc_handle == p_data->remote_cmd.rc_handle)
- {
- handle_rc_passthrough_cmd( (&p_data->remote_cmd) );
- }
- else
- {
- BTIF_TRACE_DEBUG("%s Pass-through command for Invalid rc handle", __FUNCTION__);
- }
- }
- else
- {
- BTIF_TRACE_ERROR("AVRCP TG role not up, drop passthrough commands");
- }
+ /** In race conditions just after 2nd AVRCP is connected
+ * remote might send pass through commands, so check for
+ * Rc handle before processing pass through commands
+ **/
+ handle_rc_passthrough_cmd( (&p_data->remote_cmd) );
}
break;
#endif
case BTA_AV_RC_FEAT_EVT:
{
- BTIF_TRACE_DEBUG("%s Peer_features:%x", __FUNCTION__, p_data->rc_feat.peer_features);
- btif_rc_cb.rc_features = p_data->rc_feat.peer_features;
- handle_rc_features(p_data->rc_feat.peer_addr);
+ BTIF_TRACE_DEBUG("Peer_features:%x on RC handle: %d", p_data->rc_feat.peer_features,
+ p_data->rc_feat.rc_handle);
+ index = btif_rc_get_idx_by_rc_handle(p_data->rc_feat.rc_handle);
+ if (index == btif_max_rc_clients)
+ {
+ BTIF_TRACE_ERROR("%s: Invalid RC index for BTA_AV_RC_FEAT_EVT", __FUNCTION__);
+ return;
+ }
+ btif_rc_cb[index].rc_features = p_data->rc_feat.peer_features;
+ handle_rc_features(index);
#if (AVRC_CTLR_INCLUDED == TRUE)
- if ((btif_rc_cb.rc_connected) && (bt_rc_ctrl_callbacks != NULL))
+ bt_bdaddr_t rc_addr;
+ bdcpy(rc_addr.address, btif_rc_cb[index].rc_addr);
+ if (btif_rc_cb[index].rc_features & BTA_AV_FEAT_RCTG &&
+ btif_rc_cb[index].rc_connected == TRUE && conn_status == FALSE)
{
- handle_rc_ctrl_features(btif_rc_cb.rc_addr);
+ BTIF_TRACE_DEBUG("Update RC Connection State");
+ HAL_CBACK(bt_rc_ctrl_callbacks, connection_state_cb, TRUE, &rc_addr);
+ conn_status = TRUE;
}
#endif
}
***************************************************************************/
BOOLEAN btif_rc_get_connected_peer(BD_ADDR peer_addr)
{
- if (btif_rc_cb.rc_connected == TRUE) {
- bdcpy(peer_addr, btif_rc_cb.rc_addr);
- return TRUE;
+ /*Find the device for which AV is not connected but RC is.*/
+ int i;
+
+ for (i = 0; i < btif_max_rc_clients; i++)
+ {
+ if (btif_rc_cb[i].rc_connected == TRUE)
+ {
+ if (!btif_av_is_device_connected(btif_rc_cb[i].rc_addr))
+ {
+ bdcpy(peer_addr, btif_rc_cb[i].rc_addr);
+ return TRUE;
+ }
+ }
}
return FALSE;
}
+static int btif_rc_get_idx_by_addr(BD_ADDR address)
+{
+ int i;
+
+ for (i = 0; i < btif_max_rc_clients; i++)
+ {
+ if (bdcmp(btif_rc_cb[i].rc_addr, address) == 0)
+ {
+ break;
+ }
+ }
+ return i;
+}
+
/***************************************************************************
**
** Function btif_rc_get_connected_peer_handle
***************************************************************************/
UINT8 btif_rc_get_connected_peer_handle(BD_ADDR peer_addr)
{
- if (btif_rc_cb.rc_connected && !bdcmp(peer_addr, btif_rc_cb.rc_addr))
+ int i;
+ for (i = 0; i < btif_max_rc_clients; i++)
{
- return btif_rc_cb.rc_handle;
+ if ((btif_rc_cb[i].rc_connected == TRUE)
+ &&(!bdcmp(peer_addr,btif_rc_cb[i].rc_addr)))
+ {
+ return btif_rc_cb[i].rc_handle;
+ }
}
return BTIF_RC_HANDLE_NONE;
}
/* clear the queued PLAY command. if bSend is TRUE, forward to app */
void btif_rc_check_handle_pending_play (BD_ADDR peer_addr, BOOLEAN bSendToApp)
{
+ int index = btif_rc_get_idx_by_addr(peer_addr);
+
+ if (index == btif_max_rc_clients)
+ {
+ BTIF_TRACE_ERROR("%s: Invalid RC index", __FUNCTION__);
+ return;
+ }
UNUSED(peer_addr);
BTIF_TRACE_DEBUG("%s: bSendToApp=%d", __FUNCTION__, bSendToApp);
- if (btif_rc_cb.rc_pending_play)
+ if (btif_rc_cb[index].rc_pending_play)
{
if (bSendToApp)
{
APPL_TRACE_DEBUG("%s: Sending queued PLAYED event to app", __FUNCTION__);
memset (&remote_cmd, 0, sizeof(tBTA_AV_REMOTE_CMD));
- remote_cmd.rc_handle = btif_rc_cb.rc_handle;
+ remote_cmd.rc_handle = btif_rc_cb[index].rc_handle;
remote_cmd.rc_id = AVRC_ID_PLAY;
remote_cmd.hdr.ctype = AVRC_CMD_CTRL;
remote_cmd.hdr.opcode = AVRC_OP_PASS_THRU;
remote_cmd.key_state = AVRC_STATE_RELEASE;
handle_rc_passthrough_cmd( &remote_cmd );
}
- btif_rc_cb.rc_pending_play = FALSE;
+ btif_rc_cb[index].rc_pending_play = FALSE;
}
}
tAVRC_RESPONSE *pmetamsg_resp)
{
UINT8 ctype;
+ UINT8 index;
+ index = btif_rc_get_idx_by_rc_handle(rc_handle);
+ if (index == btif_max_rc_clients)
+ {
+ BTIF_TRACE_ERROR("%s: Invalid RC index", __FUNCTION__);
+ return;
+ }
if (!pmetamsg_resp)
{
BTIF_TRACE_WARNING("%s: Invalid response received from application", __FUNCTION__);
{
BOOLEAN bSent = FALSE;
UINT8 event_id = pmetamsg_resp->reg_notif.event_id;
- BOOLEAN bNotify = (btif_rc_cb.rc_connected) && (btif_rc_cb.rc_notif[event_id-1].bNotify);
+ BOOLEAN bNotify = (btif_rc_cb[index].rc_connected) && (btif_rc_cb[index].rc_notif[event_id-1].bNotify);
/* de-register this notification for a CHANGED response */
- btif_rc_cb.rc_notif[event_id-1].bNotify = FALSE;
+ btif_rc_cb[index].rc_notif[event_id-1].bNotify = FALSE;
BTIF_TRACE_DEBUG("%s rc_handle: %d. event_id: 0x%02d bNotify:%u", __FUNCTION__,
- btif_rc_cb.rc_handle, event_id, bNotify);
+ btif_rc_cb[index].rc_handle, event_id, bNotify);
if (bNotify)
{
BT_HDR *p_msg = NULL;
tAVRC_STS status;
- if (AVRC_STS_NO_ERROR == (status = AVRC_BldResponse(btif_rc_cb.rc_handle,
+ if (AVRC_STS_NO_ERROR == (status = AVRC_BldResponse(btif_rc_cb[index].rc_handle,
pmetamsg_resp, &p_msg)) )
{
BTIF_TRACE_DEBUG("%s Sending notification to rc_handle: %d. event_id: 0x%02d",
- __FUNCTION__, btif_rc_cb.rc_handle, event_id);
+ __FUNCTION__, btif_rc_cb[index].rc_handle, event_id);
bSent = TRUE;
- BTA_AvMetaRsp(btif_rc_cb.rc_handle, btif_rc_cb.rc_notif[event_id-1].label,
+ BTA_AvMetaRsp(btif_rc_cb[index].rc_handle, btif_rc_cb[index].rc_notif[event_id-1].label,
ctype, p_msg);
}
else
* Description - Send Browse message
*
*******************************************************************************/
-int app_sendbrowsemsg(UINT8 index ,tAVRC_RESPONSE *avrc_rsp)
+int app_sendbrowsemsg(UINT8 index ,tAVRC_RESPONSE *avrc_rsp, int rc_index)
{
- SEND_BROWSEMSG_RSP(index ,avrc_rsp);
+ SEND_BROWSEMSG_RSP(index ,avrc_rsp, rc_index);
return 0;
}
** Returns void
**
*******************************************************************************/
-static void btif_rc_upstreams_evt(UINT16 event, tAVRC_COMMAND *pavrc_cmd, UINT8 ctype, UINT8 label)
+static void btif_rc_upstreams_evt(UINT16 event, tAVRC_COMMAND *pavrc_cmd, UINT8 ctype, UINT8 label,
+ int index)
{
+ bt_bdaddr_t remote_addr;
+ BD_ADDR address;
+
+ bdcpy(remote_addr.address, btif_rc_cb[index].rc_addr);
BTIF_TRACE_IMP("%s pdu: %s handle: 0x%x ctype:%x label:%x", __FUNCTION__,
- dump_rc_pdu(pavrc_cmd->pdu), btif_rc_cb.rc_handle, ctype, label);
+ dump_rc_pdu(pavrc_cmd->pdu), btif_rc_cb[index].rc_handle, ctype, label);
switch (event)
{
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);
+ FILL_PDU_QUEUE(IDX_GET_PLAY_STATUS_RSP, ctype, label, TRUE, index)
+ HAL_CBACK(bt_rc_callbacks, get_play_status_cb, &remote_addr);
}
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);
+ FILL_PDU_QUEUE(IDX_LIST_APP_ATTR_RSP, ctype, label, TRUE, index)
+ HAL_CBACK(bt_rc_callbacks, list_player_app_attr_cb, &remote_addr);
}
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);
+ send_reject_response (btif_rc_cb[index].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);
+ FILL_PDU_QUEUE(IDX_LIST_APP_VALUE_RSP, ctype, label, TRUE, index)
+ HAL_CBACK(bt_rc_callbacks, list_player_app_values_cb,
+ pavrc_cmd->list_app_values.attr_id,
+ &remote_addr);
}
break;
case AVRC_PDU_GET_CUR_PLAYER_APP_VALUE:
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);
+ send_reject_response (btif_rc_cb[index].rc_handle, label, pavrc_cmd->pdu,
+ AVRC_STS_BAD_PARAM);
break;
}
memset( player_attr, 0, sizeof(player_attr));
{
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)
+ FILL_PDU_QUEUE(IDX_GET_CURR_APP_VAL_RSP, ctype, label, TRUE, index)
HAL_CBACK(bt_rc_callbacks, get_player_app_value_cb ,
- pavrc_cmd->get_cur_app_val.num_attr, player_attr );
+ pavrc_cmd->get_cur_app_val.num_attr, player_attr, &remote_addr);
}
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,
+ send_reject_response (btif_rc_cb[index].rc_handle, label,
pavrc_cmd->pdu, AVRC_STS_BAD_PARAM);
break;
}
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 );
+ FILL_PDU_QUEUE(IDX_SET_APP_VAL_RSP, ctype, label, TRUE, index)
+ HAL_CBACK(bt_rc_callbacks, set_player_app_value_cb, &attr, &remote_addr);
}
}
break;
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);
+ send_reject_response (btif_rc_cb[index].rc_handle, label, pavrc_cmd->pdu, AVRC_STS_BAD_PARAM);
}
else
{
{
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)
+ FILL_PDU_QUEUE(IDX_GET_APP_ATTR_TXT_RSP, ctype, label, TRUE, index)
HAL_CBACK(bt_rc_callbacks, get_player_app_attrs_text_cb,
- pavrc_cmd->get_app_attr_txt.num_attr, player_attr_txt );
+ pavrc_cmd->get_app_attr_txt.num_attr, player_attr_txt, &remote_addr);
}
}
break;
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);
+ send_reject_response (btif_rc_cb[index].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);
+ send_reject_response (btif_rc_cb[index].rc_handle, label, pavrc_cmd->pdu, AVRC_STS_BAD_PARAM);
}
else
{
- FILL_PDU_QUEUE(IDX_GET_APP_VAL_TXT_RSP, ctype, label, TRUE)
+ FILL_PDU_QUEUE(IDX_GET_APP_VAL_TXT_RSP, ctype, label, TRUE, index)
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);
+ pavrc_cmd->get_app_val_txt.vals, &remote_addr);
}
}
break;
else if (pavrc_cmd->get_elem_attrs.num_attr == 0xFF)
{
/* 0xff indicates, no attributes requested - reject */
- send_reject_response (btif_rc_cb.rc_handle, label, pavrc_cmd->pdu,
+ send_reject_response (btif_rc_cb[index].rc_handle, label, pavrc_cmd->pdu,
AVRC_STS_BAD_PARAM);
return;
}
}
}
}
- FILL_PDU_QUEUE(IDX_GET_ELEMENT_ATTR_RSP, ctype, label, TRUE);
- HAL_CBACK(bt_rc_callbacks, get_element_attr_cb, num_attr, element_attrs);
+ FILL_PDU_QUEUE(IDX_GET_ELEMENT_ATTR_RSP, ctype, label, TRUE, index);
+ HAL_CBACK(bt_rc_callbacks, get_element_attr_cb, num_attr, element_attrs, &remote_addr);
}
break;
case AVRC_PDU_REGISTER_NOTIFICATION:
{
BTIF_TRACE_WARNING("%s Device registering position changed with illegal param 0.",
__FUNCTION__);
- send_reject_response (btif_rc_cb.rc_handle, label, pavrc_cmd->pdu, AVRC_STS_BAD_PARAM);
+ send_reject_response (btif_rc_cb[index].rc_handle, label, pavrc_cmd->pdu, AVRC_STS_BAD_PARAM);
/* de-register this notification for a rejected response */
- btif_rc_cb.rc_notif[BTRC_EVT_PLAY_POS_CHANGED - 1].bNotify = FALSE;
+ btif_rc_cb[index].rc_notif[BTRC_EVT_PLAY_POS_CHANGED - 1].bNotify = FALSE;
return;
}
HAL_CBACK(bt_rc_callbacks, register_notification_cb, pavrc_cmd->reg_notif.event_id,
- pavrc_cmd->reg_notif.param);
+ pavrc_cmd->reg_notif.param, &remote_addr);
}
break;
case AVRC_PDU_INFORM_DISPLAY_CHARSET:
{
tAVRC_RESPONSE avrc_rsp;
BTIF_TRACE_EVENT("%s() AVRC_PDU_INFORM_DISPLAY_CHARSET", __FUNCTION__);
- if (btif_rc_cb.rc_connected == TRUE)
+ if(btif_rc_cb[index].rc_connected == TRUE)
{
memset(&(avrc_rsp.inform_charset), 0, sizeof(tAVRC_RSP));
avrc_rsp.inform_charset.opcode=opcode_from_pdu(AVRC_PDU_INFORM_DISPLAY_CHARSET);
avrc_rsp.inform_charset.pdu=AVRC_PDU_INFORM_DISPLAY_CHARSET;
avrc_rsp.inform_charset.status=AVRC_STS_NO_ERROR;
- send_metamsg_rsp(btif_rc_cb.rc_handle, label, ctype, &avrc_rsp);
+ send_metamsg_rsp(btif_rc_cb[index].rc_handle, label, ctype, &avrc_rsp);
}
}
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__);
FILL_PDU_QUEUE(IDX_SET_ADDRESS_PLAYER_RSP, ctype, label, TRUE, index);
if (!btif_hf_is_call_idle())
{
- set_addrplayer_rsp(ERR_PLAYER_NOT_ADDRESED); // send reject if call is in progress
+ set_addrplayer_rsp(ERR_PLAYER_NOT_ADDRESED, &remote_addr); // send reject if call is in progress
return;
}
- if (btif_rc_cb.rc_connected == TRUE)
+ if (btif_rc_cb[index].rc_connected == TRUE)
{
- HAL_CBACK(bt_rc_callbacks, set_addrplayer_cb, pavrc_cmd->addr_player.player_id);
+ FILL_PDU_QUEUE(IDX_SET_ADDRESS_PLAYER_RSP, ctype, label, TRUE, index);
+ HAL_CBACK(bt_rc_callbacks, set_addrplayer_cb, pavrc_cmd->addr_player.player_id, &remote_addr);
}
}
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;
+ UINT8 idx, 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)
+ FILL_PDU_QUEUE(IDX_GET_FOLDER_ITEMS_RSP,ctype, label, TRUE, index);
+ BTIF_TRACE_EVENT("rc_connected: %d",btif_rc_cb[index].rc_connected);
+ if (btif_rc_cb[index].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.size = AVCT_GetBrowseMtu(btif_rc_cb[index].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)
if (getfolder.attr_count == 0)
{
numAttr = 7;
- for (index = 0; index < BTRC_MAX_ELEM_ATTR_SIZE; index++)
+ for (idx = 0; idx < BTRC_MAX_ELEM_ATTR_SIZE; idx++)
{
- getfolder.attrs[index] = index + 1;
+ getfolder.attrs[idx] = idx + 1;
}
}
else
{
numAttr = getfolder.attr_count;
- for (index = 0; index < numAttr; index++)
+ for (idx = 0; idx < numAttr; idx++)
{
- getfolder.attrs[index] = pavrc_cmd->get_items.attrs[index];
- BTIF_TRACE_ERROR("getfolder[%d] = %d", index, getfolder.\
- attrs[index]);
+ getfolder.attrs[idx] = pavrc_cmd->get_items.attrs[idx];
+ BTIF_TRACE_ERROR("getfolder[%d] = %d", idx, getfolder.\
+ attrs[idx]);
BTIF_TRACE_ERROR("pavrc_cmd->get_items.attrs[%d] = %d",\
- index, pavrc_cmd->get_items.attrs[index]);
+ idx, pavrc_cmd->get_items.attrs[idx]);
}
}
}
- HAL_CBACK(bt_rc_callbacks, get_folderitems_cb, scope, &getfolder);
+ HAL_CBACK(bt_rc_callbacks, get_folderitems_cb, scope, &getfolder, &remote_addr);
}
}
break;
case AVRC_PDU_SET_BROWSED_PLAYER:
{
BTIF_TRACE_EVENT("%s() AVRC_PDU_SET_BROWSED_PLAYER", __FUNCTION__);
- if (btif_rc_cb.rc_connected == TRUE)
+ if (btif_rc_cb[index].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);
+ FILL_PDU_QUEUE(IDX_SET_BROWSE_PLAYER_RSP, ctype, label, TRUE, index);
+ HAL_CBACK(bt_rc_callbacks, set_browsed_player_cb, pavrc_cmd->br_player.player_id, &remote_addr);
}
}
break;
case AVRC_PDU_CHANGE_PATH:
{
BTIF_TRACE_EVENT("%s() AVRC_PDU_CHANGE_PATH", __FUNCTION__);
- if (btif_rc_cb.rc_connected == TRUE)
+ if (btif_rc_cb[index].rc_connected == TRUE)
{
- FILL_PDU_QUEUE(IDX_CHANGE_PATH_RSP, ctype, label, TRUE);
+ FILL_PDU_QUEUE(IDX_CHANGE_PATH_RSP, ctype, label, TRUE, index);
HAL_CBACK(bt_rc_callbacks, change_path_cb, pavrc_cmd->chg_path.direction, \
- pavrc_cmd->chg_path.folder_uid);
+ pavrc_cmd->chg_path.folder_uid, &remote_addr);
}
}
break;
case AVRC_PDU_GET_ITEM_ATTRIBUTES:
{
UINT8 num_attr = pavrc_cmd->get_attrs.attr_count;
- UINT8 index, num_attr_requested = 0;
+ UINT8 idx, 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++)
+ for (idx = 0; idx < BTRC_MAX_ELEM_ATTR_SIZE; idx++)
{
- element_attrs[index] = index + 1;
+ element_attrs[idx] = idx + 1;
}
- num_attr_requested = 7; /* get all seven */
+ num_attr_requested = BTRC_MAX_ELEM_ATTR_SIZE; /* get all */
}
else if (num_attr == 0xFF)
{
/* 0xff indicates, no attributes requested - reject */
- send_reject_response (btif_rc_cb.rc_handle, label, pavrc_cmd->pdu,
+ send_reject_response (btif_rc_cb[index].rc_handle, label, pavrc_cmd->pdu,
AVRC_STS_BAD_PARAM);
return;
}
* 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++)
+ for (idx = 0; (idx < num_attr) && (num_attr <= BTRC_MAX_ELEM_ATTR_SIZE); idx++)
{
- if ((pavrc_cmd->get_attrs.attrs[index] > 0) &&
- (pavrc_cmd->get_attrs.attrs[index] <= BTRC_MAX_ELEM_ATTR_SIZE))
+ if ((pavrc_cmd->get_attrs.attrs[idx] > 0) &&
+ (pavrc_cmd->get_attrs.attrs[idx] <= 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]);
+ element_attrs[idx] = pavrc_cmd->get_attrs.attrs[idx];
+ BTIF_TRACE_ERROR("element_attrs[%d]: %d", idx, element_attrs[idx]);
}
}
- num_attr_requested = index;
+ num_attr_requested = idx;
BTIF_TRACE_ERROR("num_attr_requested: %d", num_attr_requested);
}
- if (btif_rc_cb.rc_connected == TRUE)
+ if (btif_rc_cb[index].rc_connected == TRUE)
{
- FILL_PDU_QUEUE(IDX_GET_ITEM_ATTR_RSP, ctype, label, TRUE);
+ FILL_PDU_QUEUE(IDX_GET_ITEM_ATTR_RSP, ctype, label, TRUE, index);
HAL_CBACK(bt_rc_callbacks, get_item_attr_cb, pavrc_cmd->get_attrs.scope,
- pavrc_cmd->get_attrs.uid, num_attr_requested, element_attrs);
+ pavrc_cmd->get_attrs.uid, num_attr_requested, element_attrs, &remote_addr);
}
}
break;
case AVRC_PDU_PLAY_ITEM:
{
BTIF_TRACE_EVENT("%s() AVRC_PDU_PLAY_ITEM", __FUNCTION__);
- if (btif_rc_cb.rc_connected == TRUE)
+ if (btif_rc_cb[index].rc_connected == TRUE)
{
- FILL_PDU_QUEUE(IDX_PLAY_ITEM_RSP, ctype, label, TRUE);
+ FILL_PDU_QUEUE(IDX_PLAY_ITEM_RSP, ctype, label, TRUE, index);
HAL_CBACK(bt_rc_callbacks, play_item_cb, pavrc_cmd->play_item.scope,
- pavrc_cmd->play_item.uid);
+ pavrc_cmd->play_item.uid, &remote_addr);
+ /*This command will trigger playback or
+ * dual a2dp handoff.. Let it play on this device. */
+ btif_rc_cb[index].rc_play_processed = TRUE;
+ /* Trigger DUAL Handoff when support single streaming */
+ if (btif_av_is_playing() &&
+ (btif_av_get_multicast_state() == FALSE))
+ {
+ //compare the bd addr of current playing dev and this dev
+ btif_get_latest_playing_device(address);
+ if (bdcmp(btif_rc_cb[index].rc_addr, address) == 0)
+ {
+ APPL_TRACE_WARNING("Play item on the playing device");
+ } else
+ {
+ BTIF_TRACE_DEBUG("Play item on other device");
+ if (btif_av_is_device_connected(btif_rc_cb[index].rc_addr))
+ {
+ //Trigger suspend on currently playing device
+ BTIF_TRACE_DEBUG("Trigger dual handoff for this play Item command");
+ btif_rc_cb[index].rc_play_processed = TRUE;
+ btif_av_trigger_dual_handoff(TRUE, btif_rc_cb[index].rc_addr);
+ } else
+ {
+ APPL_TRACE_WARNING("%s:Play item Invalid on %d", __FUNCTION__, index);
+ }
+ }
+ }
}
}
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);
+ send_reject_response (btif_rc_cb[index].rc_handle, label, pavrc_cmd->pdu,
+ (pavrc_cmd->pdu == AVRC_PDU_SEARCH)?AVRC_STS_SEARCH_NOT_SUP:
+ AVRC_STS_BAD_CMD);
}
break;
}
UINT8 label)
{
BTIF_TRACE_DEBUG("%s pdu: %s handle: 0x%x", __FUNCTION__,
- dump_rc_pdu(pavrc_cmd->pdu), btif_rc_cb.rc_handle);
+ dump_rc_pdu(pavrc_cmd->pdu), btif_rc_cb[0].rc_handle);
bt_bdaddr_t rc_addr;
- bdcpy(rc_addr.address, btif_rc_cb.rc_addr);
+ bdcpy(rc_addr.address, btif_rc_cb[0].rc_addr);
#if (AVRC_CTLR_INCLUDED == TRUE)
switch (event)
{
** Returns void
**
*******************************************************************************/
-static void btif_rc_upstreams_rsp_evt(UINT16 event, tAVRC_RESPONSE *pavrc_resp, UINT8 ctype, UINT8 label)
+static void btif_rc_upstreams_rsp_evt(UINT16 event, tAVRC_RESPONSE *pavrc_resp, UINT8 ctype, UINT8 label, int index)
{
+ bt_bdaddr_t remote_addr;
+
+ bdcpy(remote_addr.address, btif_rc_cb[index].rc_addr);
BTIF_TRACE_IMP("%s pdu: %s handle: 0x%x ctype:%x label:%x", __FUNCTION__,
- dump_rc_pdu(pavrc_resp->pdu), btif_rc_cb.rc_handle, ctype, label);
+ dump_rc_pdu(pavrc_resp->pdu), btif_rc_cb[index].rc_handle, ctype, label);
switch (event)
{
case AVRC_PDU_REGISTER_NOTIFICATION:
{
- if (AVRC_RSP_CHANGED==ctype)
- btif_rc_cb.rc_volume=pavrc_resp->reg_notif.param.volume;
- HAL_CBACK(bt_rc_callbacks, volume_change_cb, pavrc_resp->reg_notif.param.volume,ctype)
+ if(AVRC_RSP_CHANGED==ctype)
+ btif_rc_cb[index].rc_volume=pavrc_resp->reg_notif.param.volume;
+ HAL_CBACK(bt_rc_callbacks, volume_change_cb, pavrc_resp->reg_notif.param.volume,ctype,
+ &remote_addr)
}
break;
case AVRC_PDU_SET_ABSOLUTE_VOLUME:
{
- BTIF_TRACE_DEBUG("%s Set absolute volume change event received: volume %d,ctype %d",
- __FUNCTION__, pavrc_resp->volume.volume,ctype);
- if (AVRC_RSP_ACCEPT==ctype)
- btif_rc_cb.rc_volume=pavrc_resp->volume.volume;
- HAL_CBACK(bt_rc_callbacks,volume_change_cb,pavrc_resp->volume.volume,ctype)
+ BTIF_TRACE_DEBUG("Set absolute volume change event received: volume %d,ctype %d",
+ pavrc_resp->volume.volume,ctype);
+ if(AVRC_RSP_ACCEPT==ctype)
+ btif_rc_cb[index].rc_volume=pavrc_resp->volume.volume;
+ HAL_CBACK(bt_rc_callbacks,volume_change_cb,pavrc_resp->volume.volume,ctype, &remote_addr)
}
break;
** Returns bt_status_t
**
*******************************************************************************/
-static bt_status_t init(btrc_callbacks_t* callbacks )
+//APP can pass the max conn value here too
+static bt_status_t init(btrc_callbacks_t* callbacks, int max_connections)
{
BTIF_TRACE_EVENT("## %s ##", __FUNCTION__);
bt_status_t result = BT_STATUS_SUCCESS;
+ int i;
if (bt_rc_callbacks)
return BT_STATUS_DONE;
bt_rc_callbacks = callbacks;
+ btif_max_rc_clients = max_connections;
memset (&btif_rc_cb, 0, sizeof(btif_rc_cb));
- btif_rc_cb.rc_vol_label=MAX_LABEL;
- btif_rc_cb.rc_volume=MAX_VOLUME;
+ for (i = 0; i < btif_max_rc_clients; i++)
+ {
+ btif_rc_cb[i].rc_vol_label=MAX_LABEL;
+ btif_rc_cb[i].rc_volume=MAX_VOLUME;
+ btif_rc_cb[i].rc_handle = BTIF_RC_HANDLE_NONE;
+ }
lbl_init();
return result;
if (bt_rc_ctrl_callbacks)
return BT_STATUS_DONE;
+ /* Controller is used only for Certification purposes.
+ * In normal case AVRCP controller will not be used, hence
+ * updating this is required.
+ */
bt_rc_ctrl_callbacks = callbacks;
memset (&btif_rc_cb, 0, sizeof(btif_rc_cb));
- btif_rc_cb.rc_vol_label=MAX_LABEL;
- btif_rc_cb.rc_volume=MAX_VOLUME;
+ btif_rc_cb[BTIF_RC_DEFAULT_INDEX].rc_vol_label=MAX_LABEL;
lbl_init();
return result;
static void rc_ctrl_procedure_complete ()
{
- if (btif_rc_cb.rc_procedure_complete == TRUE)
+ if (btif_rc_cb[0].rc_procedure_complete == TRUE)
{
return;
}
- btif_rc_cb.rc_procedure_complete = TRUE;
+ btif_rc_cb[0].rc_procedure_complete = TRUE;
UINT32 attr_list[] = {
AVRC_MEDIA_ATTR_ID_TITLE,
AVRC_MEDIA_ATTR_ID_ARTIST,
**
***************************************************************************/
static bt_status_t get_play_status_rsp(btrc_play_status_t play_status, uint32_t song_len,
- uint32_t song_pos)
+ uint32_t song_pos, bt_bdaddr_t *bd_addr)
{
tAVRC_RESPONSE avrc_rsp;
+ int rc_index;
CHECK_RC_CONNECTED
+
+ rc_index = btif_rc_get_idx_by_addr(bd_addr->address);
+ if (rc_index == btif_max_rc_clients)
+ {
+ BTIF_TRACE_ERROR("-%s on unknown index = %d", __FUNCTION__);
+ return BT_STATUS_FAIL;
+ }
+ BTIF_TRACE_DEBUG("-%s on index = %d", __FUNCTION__, rc_index);
+
memset(&(avrc_rsp.get_play_status), 0, sizeof(tAVRC_GET_PLAY_STATUS_RSP));
avrc_rsp.get_play_status.song_len = song_len;
avrc_rsp.get_play_status.song_pos = song_pos;
avrc_rsp.get_play_status.opcode = opcode_from_pdu(AVRC_PDU_GET_PLAY_STATUS);
avrc_rsp.get_play_status.status = AVRC_STS_NO_ERROR;
/* Send the response */
- SEND_METAMSG_RSP(IDX_GET_PLAY_STATUS_RSP, &avrc_rsp);
+ SEND_METAMSG_RSP(IDX_GET_PLAY_STATUS_RSP, &avrc_rsp, rc_index);
return BT_STATUS_SUCCESS;
}
** Returns bt_status_t
**
****************************************************************************/
-static bt_status_t list_player_app_attr_rsp( uint8_t num_attr, btrc_player_attr_t *p_attrs)
+static bt_status_t list_player_app_attr_rsp( uint8_t num_attr, btrc_player_attr_t *p_attrs, bt_bdaddr_t *bd_addr)
{
tAVRC_RESPONSE avrc_rsp;
UINT32 i;
-
+ int rc_index;
CHECK_RC_CONNECTED
+
+ rc_index = btif_rc_get_idx_by_addr(bd_addr->address);
+ if (rc_index == btif_max_rc_clients)
+ {
+ BTIF_TRACE_ERROR("-%s on unknown index = %d", __FUNCTION__);
+ return BT_STATUS_FAIL;
+ }
+ BTIF_TRACE_DEBUG("-%s on index = %d", __FUNCTION__, rc_index);
+
memset(&(avrc_rsp.list_app_attr), 0, sizeof(tAVRC_LIST_APP_ATTR_RSP));
if (num_attr == 0)
{
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);
+ SEND_METAMSG_RSP(IDX_LIST_APP_ATTR_RSP, &avrc_rsp, rc_index);
return BT_STATUS_SUCCESS;
}
** 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)
+static bt_status_t list_player_app_value_rsp( uint8_t num_val, uint8_t *value, bt_bdaddr_t *bd_addr)
{
tAVRC_RESPONSE avrc_rsp;
UINT32 i;
-
+ int rc_index;
CHECK_RC_CONNECTED
+
+ rc_index = btif_rc_get_idx_by_addr(bd_addr->address);
+ if (rc_index == btif_max_rc_clients)
+ {
+ BTIF_TRACE_ERROR("-%s on unknown index = %d", __FUNCTION__);
+ return BT_STATUS_FAIL;
+ }
+ BTIF_TRACE_DEBUG("-%s on index = %d", __FUNCTION__, rc_index);
+
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.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);
+ SEND_METAMSG_RSP(IDX_LIST_APP_VALUE_RSP, &avrc_rsp, rc_index);
return BT_STATUS_SUCCESS;
}
** 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)
+static bt_status_t get_player_app_value_rsp(btrc_player_settings_t *p_vals, bt_bdaddr_t *bd_addr)
{
tAVRC_RESPONSE avrc_rsp;
UINT32 i;
tAVRC_APP_SETTING app_sett[AVRC_MAX_APP_ATTR_SIZE];
-
+ int rc_index;
CHECK_RC_CONNECTED
+
+ rc_index = btif_rc_get_idx_by_addr(bd_addr->address);
+ if (rc_index == btif_max_rc_clients)
+ {
+ BTIF_TRACE_ERROR("-%s on unknown index = %d", __FUNCTION__);
+ return BT_STATUS_FAIL;
+ }
+ BTIF_TRACE_DEBUG("-%s on index = %d", __FUNCTION__, rc_index);
+
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
}
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);
+ SEND_METAMSG_RSP(IDX_GET_CURR_APP_VAL_RSP, &avrc_rsp, rc_index);
return BT_STATUS_SUCCESS;
}
** Return bt_staus_t
**
*******************************************************************/
-static bt_status_t set_player_app_value_rsp (btrc_status_t rsp_status )
+static bt_status_t set_player_app_value_rsp (btrc_status_t rsp_status, bt_bdaddr_t *bd_addr )
{
tAVRC_RESPONSE avrc_rsp;
- tAVRC_RSP set_app_val;
+ int rc_index;
+
+ rc_index = btif_rc_get_idx_by_addr(bd_addr->address);
+ if (rc_index == btif_max_rc_clients)
+ {
+ BTIF_TRACE_ERROR("-%s on unknown index = %d", __FUNCTION__);
+ return BT_STATUS_FAIL;
+ }
+ BTIF_TRACE_DEBUG("-%s on index = %d", __FUNCTION__, rc_index);
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);
+ SEND_METAMSG_RSP(IDX_SET_APP_VAL_RSP, &avrc_rsp, rc_index);
return BT_STATUS_SUCCESS;
}
**
**
*******************************************************************/
-static bt_status_t get_player_app_attr_text_rsp(int num_attr, btrc_player_setting_text_t *p_attrs)
+static bt_status_t get_player_app_attr_text_rsp(int num_attr, btrc_player_setting_text_t *p_attrs,
+ bt_bdaddr_t *bd_addr)
{
tAVRC_RESPONSE avrc_rsp;
tAVRC_APP_SETTING_TEXT attr_txt[AVRC_MAX_APP_ATTR_SIZE];
int i;
-
+ int rc_index;
CHECK_RC_CONNECTED
+
+ rc_index = btif_rc_get_idx_by_addr(bd_addr->address);
+ if (rc_index == btif_max_rc_clients)
+ {
+ BTIF_TRACE_ERROR("-%s on unknown index = %d", __FUNCTION__);
+ return BT_STATUS_FAIL;
+ }
+ BTIF_TRACE_DEBUG("-%s on index = %d", __FUNCTION__, rc_index);
+
if (num_attr == 0)
{
avrc_rsp.get_app_attr_txt.status = AVRC_STS_BAD_PARAM;
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);
+ SEND_METAMSG_RSP(IDX_GET_APP_ATTR_TXT_RSP, &avrc_rsp, rc_index);
return BT_STATUS_SUCCESS;
}
** Return bt_status_t
**
*******************************************************************/
-static bt_status_t get_player_app_value_text_rsp(int num_attr, btrc_player_setting_text_t *p_attrs)
+static bt_status_t get_player_app_value_text_rsp(int num_attr, btrc_player_setting_text_t *p_attrs, bt_bdaddr_t *bd_addr)
{
tAVRC_RESPONSE avrc_rsp;
tAVRC_APP_SETTING_TEXT attr_txt[AVRC_MAX_APP_ATTR_SIZE];
int i;
-
+ int rc_index;
CHECK_RC_CONNECTED
+
+ rc_index = btif_rc_get_idx_by_addr(bd_addr->address);
+ if (rc_index == btif_max_rc_clients)
+ {
+ BTIF_TRACE_ERROR("-%s on unknown index = %d", __FUNCTION__);
+ return BT_STATUS_FAIL;
+ }
+ BTIF_TRACE_DEBUG("- %s on index = %d", __FUNCTION__, rc_index);
+
if (num_attr == 0)
{
avrc_rsp.get_app_val_txt.status = AVRC_STS_BAD_PARAM;
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);
+ SEND_METAMSG_RSP(IDX_GET_APP_VAL_TXT_RSP, &avrc_rsp, rc_index);
return BT_STATUS_SUCCESS;
}
** Returns bt_status_t
**
***************************************************************************/
-static bt_status_t get_element_attr_rsp(uint8_t num_attr, btrc_element_attr_val_t *p_attrs)
+static bt_status_t get_element_attr_rsp(uint8_t num_attr, btrc_element_attr_val_t *p_attrs, bt_bdaddr_t *bd_addr)
{
tAVRC_RESPONSE avrc_rsp;
UINT32 i;
tAVRC_ATTR_ENTRY element_attrs[BTRC_MAX_ELEM_ATTR_SIZE];
+ int rc_index;
CHECK_RC_CONNECTED
+
+ rc_index = btif_rc_get_idx_by_addr(bd_addr->address);
+ if (rc_index == btif_max_rc_clients)
+ {
+ BTIF_TRACE_ERROR("-%s on unknown index = %d", __FUNCTION__);
+ return BT_STATUS_FAIL;
+ }
+ BTIF_TRACE_DEBUG("- %s on index = %d", __FUNCTION__, rc_index);
+
memset(element_attrs, 0, sizeof(tAVRC_ATTR_ENTRY) * num_attr);
if (num_attr == 0)
avrc_rsp.get_elem_attrs.pdu = AVRC_PDU_GET_ELEMENT_ATTR;
avrc_rsp.get_elem_attrs.opcode = opcode_from_pdu(AVRC_PDU_GET_ELEMENT_ATTR);
/* Send the response */
- SEND_METAMSG_RSP(IDX_GET_ELEMENT_ATTR_RSP, &avrc_rsp);
+ SEND_METAMSG_RSP(IDX_GET_ELEMENT_ATTR_RSP, &avrc_rsp, rc_index);
return BT_STATUS_SUCCESS;
}
**
***************************************************************************/
static bt_status_t register_notification_rsp(btrc_event_id_t event_id,
- btrc_notification_type_t type, btrc_register_notification_t *p_param)
+ btrc_notification_type_t type, btrc_register_notification_t *p_param, bt_bdaddr_t *bd_addr)
{
tAVRC_RESPONSE avrc_rsp;
+ int index = btif_rc_get_idx_by_addr(bd_addr->address);
CHECK_RC_CONNECTED
+
+ if (index == btif_max_rc_clients)
+ {
+ BTIF_TRACE_ERROR("%s: on unknown index", __FUNCTION__);
+ return BT_STATUS_FAIL;
+ }
+
+
BTIF_TRACE_IMP("## %s ## event_id:%s", __FUNCTION__, dump_rc_notification_event_id(event_id));
- if (btif_rc_cb.rc_notif[event_id-1].bNotify == FALSE)
+ if (btif_rc_cb[index].rc_notif[event_id-1].bNotify == FALSE)
{
BTIF_TRACE_ERROR("Avrcp Event id not registered: event_id = %x", event_id);
return BT_STATUS_NOT_READY;
{
case BTRC_EVT_PLAY_STATUS_CHANGED:
avrc_rsp.reg_notif.param.play_status = p_param->play_status;
+ /* Clear remote suspend flag, as remote device issues
+ * suspend within 3s after pause, and DUT within 3s
+ * initiates Play
+ */
if (avrc_rsp.reg_notif.param.play_status == PLAY_STATUS_PLAYING)
btif_av_clear_remote_suspend_flag();
break;
}
/* Send the response. */
- send_metamsg_rsp(btif_rc_cb.rc_handle, btif_rc_cb.rc_notif[event_id-1].label,
+ send_metamsg_rsp(btif_rc_cb[index].rc_handle, btif_rc_cb[index].rc_notif[event_id-1].label,
((type == BTRC_NOTIFICATION_TYPE_INTERIM)?AVRC_CMD_NOTIF:AVRC_RSP_CHANGED), &avrc_rsp);
return BT_STATUS_SUCCESS;
}
** Returns bt_status_t
**
***************************************************************************/
-static bt_status_t get_folderitem_rsp(btrc_folder_list_entries_t *rsp)
+static bt_status_t get_folderitem_rsp(btrc_folder_list_entries_t *rsp, bt_bdaddr_t *bd_addr)
{
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;
+ int rc_index;
+ CHECK_RC_CONNECTED
+
+ rc_index = btif_rc_get_idx_by_addr(bd_addr->address);
+ if (rc_index == btif_max_rc_clients)
+ {
+ BTIF_TRACE_ERROR("%s: on unknown index", __FUNCTION__);
+ return BT_STATUS_FAIL;
+ }
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;
if (media_attr_cnt > 0)
{
if ((item[i].u.media.p_attr_list = \
- (tAVRC_ATTR_ENTRY *)GKI_getbuf((UINT16)(media_attr_cnt * \
+ (tAVRC_ATTR_ENTRY *)osi_malloc((UINT16)(media_attr_cnt * \
sizeof(tAVRC_ATTR_ENTRY)))) != NULL)
{
for (xx = 0; xx < media_attr_cnt; xx++)
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);
+ app_sendbrowsemsg(IDX_GET_FOLDER_ITEMS_RSP ,&avrc_rsp, rc_index);
BTIF_TRACE_ERROR("free attr list");
for (i=0; (i < rsp->item_count && i < MAX_FOLDER_RSP_SUPPORT) ; ++i)
{
{
if (rsp->p_item_list[i].u.media.attr_count > 0)
{
- GKI_freebuf(item[i].u.media.p_attr_list);
+ osi_free_and_reset((void**)&item[i].u.media.p_attr_list);
}
}
}
**
*********************************************************************/
-static bt_status_t set_addrplayer_rsp(btrc_status_t status_code)
+static bt_status_t set_addrplayer_rsp(btrc_status_t status_code, bt_bdaddr_t *bd_addr)
{
tAVRC_RESPONSE avrc_rsp;
+ int rc_index;
CHECK_RC_CONNECTED
+ rc_index = btif_rc_get_idx_by_addr(bd_addr->address);
+
+ if (rc_index == btif_max_rc_clients)
+ {
+ BTIF_TRACE_ERROR("%s: on unknown index", __FUNCTION__);
+ return BT_STATUS_FAIL;
+ }
+ BTIF_TRACE_DEBUG("- %s on index = %d", __FUNCTION__, rc_index);
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);
+ SEND_METAMSG_RSP(IDX_SET_ADDRESS_PLAYER_RSP, &avrc_rsp, rc_index);
return BT_STATUS_SUCCESS;
}
**
*********************************************************************/
-static bt_status_t set_browseplayer_rsp(btrc_set_browsed_player_rsp_t *p_param)
+static bt_status_t set_browseplayer_rsp(btrc_set_browsed_player_rsp_t *p_param, bt_bdaddr_t *bd_addr)
{
tAVRC_RESPONSE avrc_rsp;
-
+ int rc_index = btif_rc_get_idx_by_addr(bd_addr->address);
CHECK_RC_CONNECTED
+
+ if (rc_index == btif_max_rc_clients)
+ {
+ BTIF_TRACE_ERROR("%s: on unknown index", __FUNCTION__);
+ return BT_STATUS_FAIL;
+ }
+ BTIF_TRACE_DEBUG("- %s on index = %d", __FUNCTION__, rc_index);
+
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.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);
+ SEND_BROWSEMSG_RSP(IDX_SET_BROWSE_PLAYER_RSP, &avrc_rsp, rc_index);
return BT_STATUS_SUCCESS;
}
**
*********************************************************************/
-static bt_status_t changepath_rsp(uint8_t status_code, uint32_t item_count)
+static bt_status_t changepath_rsp(uint8_t status_code, uint32_t item_count, bt_bdaddr_t *bd_addr)
{
tAVRC_RESPONSE avrc_rsp;
-
+ int rc_index;
CHECK_RC_CONNECTED
+
+ rc_index = btif_rc_get_idx_by_addr(bd_addr->address);
+
+ if (rc_index == btif_max_rc_clients)
+ {
+ BTIF_TRACE_ERROR("%s: on unknown index", __FUNCTION__);
+ return BT_STATUS_FAIL;
+ }
+ BTIF_TRACE_DEBUG("- %s on index = %d", __FUNCTION__, rc_index);
+
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);
+ SEND_BROWSEMSG_RSP(IDX_CHANGE_PATH_RSP, &avrc_rsp, rc_index);
return BT_STATUS_SUCCESS;
}
**
*********************************************************************/
-static bt_status_t playitem_rsp(uint8_t status_code)
+static bt_status_t playitem_rsp(uint8_t status_code, bt_bdaddr_t *bd_addr)
{
tAVRC_RESPONSE avrc_rsp;
-
+ int rc_index;
CHECK_RC_CONNECTED
+
+ rc_index = btif_rc_get_idx_by_addr(bd_addr->address);
+ if (rc_index == btif_max_rc_clients)
+ {
+ BTIF_TRACE_ERROR("%s: on unknown index", __FUNCTION__);
+ return BT_STATUS_FAIL;
+ }
+ BTIF_TRACE_DEBUG("- %s on index = %d", __FUNCTION__, rc_index);
+
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);
+ SEND_METAMSG_RSP(IDX_PLAY_ITEM_RSP, &avrc_rsp,rc_index);
+
return BT_STATUS_SUCCESS;
}
**
*********************************************************************/
-static bt_status_t get_itemattr_rsp(uint8_t num_attr, btrc_element_attr_val_t *p_attrs)
+static bt_status_t get_itemattr_rsp(uint8_t num_attr, btrc_element_attr_val_t *p_attrs, bt_bdaddr_t *bd_addr)
+
{
tAVRC_RESPONSE avrc_rsp;
UINT32 i;
- uint8_t j;
tAVRC_ATTR_ENTRY element_attrs[BTRC_MAX_ELEM_ATTR_SIZE];
+ int rc_index = btif_rc_get_idx_by_addr(bd_addr->address);
+ if (rc_index == btif_max_rc_clients)
+ {
+ BTIF_TRACE_ERROR("%s: on unknown index", __FUNCTION__);
+ return BT_STATUS_FAIL;
+ }
+ BTIF_TRACE_DEBUG("- %s on index = %d", __FUNCTION__, rc_index);
CHECK_RC_CONNECTED
memset(element_attrs, 0, sizeof(tAVRC_ATTR_ENTRY) * num_attr);
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);
+ SEND_BROWSEMSG_RSP(IDX_GET_ITEM_ATTR_RSP, &avrc_rsp, rc_index);
return BT_STATUS_SUCCESS;
}
+/**********************************************************************
+**
+** Function is_device_active_in_handoff
+**
+** Description Check if this is the active device during hand-off
+** If the multicast is disabled when connected to more
+** than one device and the active playing device is
+** different or device to start playback is different
+** then fail this condition.
+** Return BT_STATUS_SUCCESS if active BT_STATUS_FAIL otherwise
+**
+*********************************************************************/
+static bt_status_t is_device_active_in_handoff(bt_bdaddr_t *bd_addr)
+{
+ BD_ADDR playing_device;
+ int rc_index;
+ UINT16 connected_devices, playing_devices;
+
+ rc_index = btif_rc_get_idx_by_addr(bd_addr->address);
+ if(rc_index >= btif_max_rc_clients)
+ {
+ return BT_STATUS_FAIL;
+ }
+ connected_devices = btif_av_get_num_connected_devices();
+ playing_devices = btif_av_get_num_playing_devices();
+
+ if((connected_devices < btif_max_rc_clients) || (playing_devices > 1))
+ {
+ return BT_STATUS_SUCCESS;
+ }
+
+ if((connected_devices > 1) && (playing_devices == 1))
+ {
+ /* One playing device, check the active device */
+ btif_get_latest_playing_device(playing_device);
+ if (bdcmp(bd_addr->address, playing_device) == 0)
+ {
+ return BT_STATUS_SUCCESS;
+ }
+ else
+ {
+ return BT_STATUS_FAIL;
+ }
+ }
+ else if (playing_devices == 0)
+ {
+ /* No Playing device, find the next playing device
+ * Play initiated from remote
+ */
+ if (btif_rc_cb[rc_index].rc_play_processed == TRUE)
+ {
+ return BT_STATUS_SUCCESS;
+ }
+ else if (btif_av_is_current_device(bd_addr->address) == TRUE)
+ {
+ /* Play initiated locally. check the current device and
+ * make sure play is not initiated from other remote
+ */
+ BD_ADDR rc_play_device = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+ btif_rc_get_playing_device(rc_play_device);
+ if(bdcmp(bd_addr->address, bd_addr_null) != 0)
+ {
+ /* some other playing device */
+ return BT_STATUS_FAIL;
+ }
+ return BT_STATUS_SUCCESS;
+ }
+ else
+ {
+ BTIF_TRACE_ERROR("%s no playing or current device ", __FUNCTION__);
+ return BT_STATUS_FAIL;
+ }
+ }
+ else
+ {
+ BTIF_TRACE_ERROR("%s unchecked state: connected devices: %d playing devices: %d",
+ __FUNCTION__, connected_devices, playing_devices);
+ return BT_STATUS_SUCCESS;
+ }
+}
+
/***************************************************************************
**
** Function set_volume
** Returns bt_status_t
**
***************************************************************************/
-static bt_status_t set_volume(uint8_t volume)
+static bt_status_t set_volume(uint8_t volume, bt_bdaddr_t *bd_addr)
{
- BTIF_TRACE_DEBUG("%s", __FUNCTION__);
+ int index = btif_rc_get_idx_by_addr(bd_addr->address);
+
+ if (index == btif_max_rc_clients)
+ {
+ BTIF_TRACE_ERROR("%s: on unknown index", __FUNCTION__);
+ return BT_STATUS_FAIL;
+ }
+ BTIF_TRACE_DEBUG("- %s on index = %d", __FUNCTION__, index);
CHECK_RC_CONNECTED
tAVRC_STS status = BT_STATUS_UNSUPPORTED;
rc_transaction_t *p_transaction=NULL;
- if (btif_rc_cb.rc_volume==volume)
+ if(btif_rc_cb[index].rc_volume==volume)
{
status=BT_STATUS_DONE;
BTIF_TRACE_ERROR("%s: volume value already set earlier: 0x%02x",__FUNCTION__, volume);
return status;
}
- if ((btif_rc_cb.rc_features & BTA_AV_FEAT_RCTG) &&
- (btif_rc_cb.rc_features & BTA_AV_FEAT_ADV_CTRL))
+ if ((btif_rc_cb[index].rc_features & BTA_AV_FEAT_RCTG) &&
+ (btif_rc_cb[index].rc_features & BTA_AV_FEAT_ADV_CTRL))
{
tAVRC_COMMAND avrc_cmd = {0};
BT_HDR *p_msg = NULL;
{
BTIF_TRACE_DEBUG("%s msgreq being sent out with label %d",
__FUNCTION__,p_transaction->lbl);
- BTA_AvMetaCmd(btif_rc_cb.rc_handle,p_transaction->lbl, AVRC_CMD_CTRL, p_msg);
+ BTA_AvMetaCmd(btif_rc_cb[index].rc_handle,p_transaction->lbl, AVRC_CMD_CTRL, p_msg);
status = BT_STATUS_SUCCESS;
}
else
**
***************************************************************************/
-static void register_volumechange (UINT8 lbl)
+static void register_volumechange (UINT8 lbl, int index)
{
tAVRC_COMMAND avrc_cmd = {0};
BT_HDR *p_msg = NULL;
tAVRC_STS BldResp=AVRC_STS_BAD_CMD;
rc_transaction_t *p_transaction=NULL;
-
BTIF_TRACE_DEBUG("%s called with label:%d",__FUNCTION__,lbl);
avrc_cmd.cmd.opcode=0x00;
if (AVRC_STS_NO_ERROR == BldResp && p_msg) {
p_transaction = get_transaction_by_lbl(lbl);
if (p_transaction != NULL) {
- BTA_AvMetaCmd(btif_rc_cb.rc_handle, p_transaction->lbl,
+ BTA_AvMetaCmd(btif_rc_cb[index].rc_handle, p_transaction->lbl,
AVRC_CMD_NOTIF, p_msg);
BTIF_TRACE_DEBUG("%s:BTA_AvMetaCmd called", __func__);
} else {
***************************************************************************/
static void handle_rc_metamsg_rsp(tBTA_AV_META_MSG *pmeta_msg)
{
+ UINT8 index; /*For RC it is zero*/
tAVRC_RESPONSE avrc_response = {0};
UINT8 scratch_buf[512] = {0};
tAVRC_STS status = BT_STATUS_UNSUPPORTED;
- if (AVRC_OP_VENDOR==pmeta_msg->p_msg->hdr.opcode &&(AVRC_RSP_CHANGED==pmeta_msg->code
+ index = btif_rc_get_idx_by_rc_handle(pmeta_msg->rc_handle);
+ if (index == btif_max_rc_clients)
+ {
+ BTIF_TRACE_ERROR("%s: on unknown index", __FUNCTION__);
+ return;
+ }
+
+ if(AVRC_OP_VENDOR==pmeta_msg->p_msg->hdr.opcode &&(AVRC_RSP_CHANGED==pmeta_msg->code
|| AVRC_RSP_INTERIM==pmeta_msg->code || AVRC_RSP_ACCEPT==pmeta_msg->code
|| AVRC_RSP_REJ==pmeta_msg->code || AVRC_RSP_NOT_IMPL==pmeta_msg->code))
{
{
if (AVRC_PDU_REGISTER_NOTIFICATION==avrc_response.rsp.pdu
&& AVRC_EVT_VOLUME_CHANGE==avrc_response.reg_notif.event_id
- && btif_rc_cb.rc_vol_label==pmeta_msg->label)
+ && btif_rc_cb[index].rc_vol_label==pmeta_msg->label)
{
- btif_rc_cb.rc_vol_label=MAX_LABEL;
- release_transaction(btif_rc_cb.rc_vol_label);
+ btif_rc_cb[index].rc_vol_label=MAX_LABEL;
+ release_transaction(btif_rc_cb[index].rc_vol_label);
}
else if (AVRC_PDU_SET_ABSOLUTE_VOLUME==avrc_response.rsp.pdu)
{
}
else if (AVRC_PDU_REGISTER_NOTIFICATION==avrc_response.rsp.pdu
&& AVRC_EVT_VOLUME_CHANGE==avrc_response.reg_notif.event_id
- && btif_rc_cb.rc_vol_label!=pmeta_msg->label)
+ && btif_rc_cb[index].rc_vol_label!=pmeta_msg->label)
{
// Just discard the message, if the device sends back with an incorrect label
BTIF_TRACE_DEBUG("%s:Discarding register notfn in rsp.code: %d and label %d",
{
/* re-register for volume change notification */
// Do not re-register for rejected case, as it might get into endless loop
- register_volumechange(btif_rc_cb.rc_vol_label);
+ register_volumechange(btif_rc_cb[index].rc_vol_label, index);
}
else if (AVRC_PDU_SET_ABSOLUTE_VOLUME==avrc_response.rsp.pdu)
{
BTIF_TRACE_EVENT("%s: Passing received metamsg response to app. pdu: %s",
__FUNCTION__, dump_rc_pdu(avrc_response.pdu));
btif_rc_upstreams_rsp_evt((uint16_t)avrc_response.rsp.pdu, &avrc_response, pmeta_msg->code,
- pmeta_msg->label);
+ pmeta_msg->label, index);
}
#endif
if (p_event->label == label)
{
- list_remove(btif_rc_cb.rc_supported_event_list, p_event);
+ list_remove(btif_rc_cb[0].rc_supported_event_list, p_event);
return false;
}
return true;
static void rc_notification_interim_timout (UINT8 label)
{
list_node_t *node;
- if (btif_rc_cb.rc_supported_event_list == NULL)
+ if (btif_rc_cb[0].rc_supported_event_list == NULL)
return;
- list_foreach(btif_rc_cb.rc_supported_event_list,
+ list_foreach(btif_rc_cb[0].rc_supported_event_list,
iterate_supported_event_list_for_timeout, &label);
/* Timeout happened for interim response for the registered event,
* check if there are any pending for registration
*/
- node = list_begin(btif_rc_cb.rc_supported_event_list);
+ node = list_begin(btif_rc_cb[0].rc_supported_event_list);
while (node != NULL)
{
btif_rc_supported_event_t *p_event;
p_context = (btif_rc_timer_context_t *)data;
memset(&meta_msg, 0, sizeof(tBTA_AV_META_MSG));
- meta_msg.rc_handle = btif_rc_cb.rc_handle;
+ meta_msg.rc_handle = btif_rc_cb[0].rc_handle;
switch (p_context->rc_status_cmd.pdu_id) {
case AVRC_PDU_REGISTER_NOTIFICATION:
tBTA_AV_META_MSG meta_msg;
memset(&meta_msg, 0, sizeof(tBTA_AV_META_MSG));
- meta_msg.rc_handle = btif_rc_cb.rc_handle;
+ meta_msg.rc_handle = btif_rc_cb[0].rc_handle;
switch (p_context->rc_control_cmd.pdu_id) {
case AVRC_PDU_SET_PLAYER_APP_VALUE:
static void rc_start_play_status_timer(void)
{
/* Start the Play status timer only if it is not started */
- if (!alarm_is_scheduled(btif_rc_cb.rc_play_status_timer)) {
- if (btif_rc_cb.rc_play_status_timer == NULL) {
- btif_rc_cb.rc_play_status_timer =
+ if (!alarm_is_scheduled(btif_rc_cb[0].rc_play_status_timer)) {
+ if (btif_rc_cb[0].rc_play_status_timer == NULL) {
+ btif_rc_cb[0].rc_play_status_timer =
alarm_new("btif_rc.rc_play_status_timer");
}
- alarm_set_on_queue(btif_rc_cb.rc_play_status_timer,
+ alarm_set_on_queue(btif_rc_cb[0].rc_play_status_timer,
BTIF_TIMEOUT_RC_INTERIM_RSP_MS,
btif_rc_play_status_timer_timeout, NULL,
btu_general_alarm_queue);
***************************************************************************/
void rc_stop_play_status_timer()
{
- if (btif_rc_cb.rc_play_status_timer != NULL)
- alarm_cancel(btif_rc_cb.rc_play_status_timer);
+ if (btif_rc_cb[0].rc_play_status_timer != NULL)
+ alarm_cancel(btif_rc_cb[0].rc_play_status_timer);
}
/***************************************************************************
btif_rc_supported_event_t *p_event;
/* Todo: Check if list can be active when we hit here */
- btif_rc_cb.rc_supported_event_list = list_new(osi_free);
+ btif_rc_cb[0].rc_supported_event_list = list_new(osi_free);
for (xx = 0; xx < p_rsp->count; xx++)
{
/* Skip registering for Play position change notification */
p_event = (btif_rc_supported_event_t *)osi_malloc(sizeof(btif_rc_supported_event_t));
p_event->event_id = p_rsp->param.event_id[xx];
p_event->status = eNOT_REGISTERED;
- list_append(btif_rc_cb.rc_supported_event_list, p_event);
+ list_append(btif_rc_cb[0].rc_supported_event_list, p_event);
}
}
- if (list_is_empty(btif_rc_cb.rc_supported_event_list))
+ if (list_is_empty(btif_rc_cb[0].rc_supported_event_list))
{
BTIF_TRACE_EVENT(" Supported event list Empty, returning");
return;
}
- p_event = list_front(btif_rc_cb.rc_supported_event_list);
+ p_event = list_front(btif_rc_cb[0].rc_supported_event_list);
if (p_event != NULL)
{
register_for_event_notification(p_event);
};
- bdcpy(rc_addr.address, btif_rc_cb.rc_addr);
+ bdcpy(rc_addr.address, btif_rc_cb[0].rc_addr);
if (pmeta_msg->code == AVRC_RSP_INTERIM)
{
/* Update the UID for current track
* Attributes will be fetched after the AVRCP procedure
*/
- BE_STREAM_TO_UINT64(btif_rc_cb.rc_playing_uid, p_data);
+ BE_STREAM_TO_UINT64(btif_rc_cb[0].rc_playing_uid, p_data);
}
break;
p_rsp->event_id);
return;
}
- list_foreach(btif_rc_cb.rc_supported_event_list,
+ list_foreach(btif_rc_cb[0].rc_supported_event_list,
iterate_supported_event_list_for_interim_rsp,
&p_rsp->event_id);
- node = list_begin(btif_rc_cb.rc_supported_event_list);
+ node = list_begin(btif_rc_cb[0].rc_supported_event_list);
while (node != NULL)
{
p_event = (btif_rc_supported_event_t *)list_node(node);
p_event = NULL;
}
/* Registered for all events, we can request application settings */
- if ((p_event == NULL) && (btif_rc_cb.rc_app_settings.query_started == false))
+ if ((p_event == NULL) && (btif_rc_cb[0].rc_app_settings.query_started == false))
{
/* we need to do this only if remote TG supports
* player application settings
*/
- btif_rc_cb.rc_app_settings.query_started = TRUE;
- if (btif_rc_cb.rc_features & BTA_AV_FEAT_APP_SETTING)
+ btif_rc_cb[0].rc_app_settings.query_started = TRUE;
+ if (btif_rc_cb[0].rc_features & BTA_AV_FEAT_APP_SETTING)
{
list_player_app_setting_attrib_cmd();
}
BTIF_TRACE_DEBUG("%s Notification completed : 0x%2X ", __FUNCTION__,
p_rsp->event_id);
- node = list_begin(btif_rc_cb.rc_supported_event_list);
+ node = list_begin(btif_rc_cb[0].rc_supported_event_list);
while (node != NULL)
{
p_event = (btif_rc_supported_event_t *)list_node(node);
break;
}
UINT8 *p_data = p_rsp->param.track;
- BE_STREAM_TO_UINT64(btif_rc_cb.rc_playing_uid, p_data);
+ BE_STREAM_TO_UINT64(btif_rc_cb[0].rc_playing_uid, p_data);
get_element_attribute_cmd (AVRC_MAX_NUM_MEDIA_ATTR_ID, attr_list);
break;
if (p_rsp->attrs[xx] > AVRC_PLAYER_SETTING_LOW_MENU_EXT)
{
- st_index = btif_rc_cb.rc_app_settings.num_ext_attrs;
- btif_rc_cb.rc_app_settings.ext_attrs[st_index].attr_id = p_rsp->attrs[xx];
- btif_rc_cb.rc_app_settings.num_ext_attrs++;
+ st_index = btif_rc_cb[0].rc_app_settings.num_ext_attrs;
+ btif_rc_cb[0].rc_app_settings.ext_attrs[st_index].attr_id = p_rsp->attrs[xx];
+ btif_rc_cb[0].rc_app_settings.num_ext_attrs++;
}
else
{
- st_index = btif_rc_cb.rc_app_settings.num_attrs;
- btif_rc_cb.rc_app_settings.attrs[st_index].attr_id = p_rsp->attrs[xx];
- btif_rc_cb.rc_app_settings.num_attrs++;
+ st_index = btif_rc_cb[0].rc_app_settings.num_attrs;
+ btif_rc_cb[0].rc_app_settings.attrs[st_index].attr_id = p_rsp->attrs[xx];
+ btif_rc_cb[0].rc_app_settings.num_attrs++;
}
}
- btif_rc_cb.rc_app_settings.attr_index = 0;
- btif_rc_cb.rc_app_settings.ext_attr_index = 0;
- btif_rc_cb.rc_app_settings.ext_val_index = 0;
+ btif_rc_cb[0].rc_app_settings.attr_index = 0;
+ btif_rc_cb[0].rc_app_settings.ext_attr_index = 0;
+ btif_rc_cb[0].rc_app_settings.ext_val_index = 0;
if (p_rsp->num_attr)
{
- list_player_app_setting_value_cmd (btif_rc_cb.rc_app_settings.attrs[0].attr_id);
+ list_player_app_setting_value_cmd (btif_rc_cb[0].rc_app_settings.attrs[0].attr_id);
}
else
{
return;
}
- p_app_settings = &btif_rc_cb.rc_app_settings;
- bdcpy(rc_addr.address, btif_rc_cb.rc_addr);
+ p_app_settings = &btif_rc_cb[0].rc_app_settings;
+ bdcpy(rc_addr.address, btif_rc_cb[0].rc_addr);
if (p_app_settings->attr_index < p_app_settings->num_attrs)
{
return;
}
- bdcpy(rc_addr.address, btif_rc_cb.rc_addr);
+ bdcpy(rc_addr.address, btif_rc_cb[0].rc_addr);
app_settings.num_attr = p_rsp->num_val;
for (xx = 0; xx < app_settings.num_attr; xx++)
btif_rc_player_app_settings_t *p_app_settings;
bt_bdaddr_t rc_addr;
- p_app_settings = &btif_rc_cb.rc_app_settings;
- bdcpy(rc_addr.address, btif_rc_cb.rc_addr);
+ p_app_settings = &btif_rc_cb[0].rc_app_settings;
+ bdcpy(rc_addr.address, btif_rc_cb[0].rc_addr);
/* Todo: Do we need to retry on command timeout */
if (p_rsp->status != AVRC_STS_NO_ERROR)
btif_rc_player_app_settings_t *p_app_settings;
bt_bdaddr_t rc_addr;
- bdcpy(rc_addr.address, btif_rc_cb.rc_addr);
- p_app_settings = &btif_rc_cb.rc_app_settings;
+ bdcpy(rc_addr.address, btif_rc_cb[0].rc_addr);
+ p_app_settings = &btif_rc_cb[0].rc_app_settings;
/* Todo: Do we need to retry on command timeout */
if (p_rsp->status != AVRC_STS_NO_ERROR)
uint8_t accepted = 0;
bt_bdaddr_t rc_addr;
- bdcpy(rc_addr.address, btif_rc_cb.rc_addr);
+ bdcpy(rc_addr.address, btif_rc_cb[0].rc_addr);
/* For timeout pmeta_msg will be NULL, else we need to
* check if this is accepted by TG
btrc_element_attr_val_t *p_attr =
(btrc_element_attr_val_t *)osi_calloc(buf_size);
- bdcpy(rc_addr.address, btif_rc_cb.rc_addr);
+ bdcpy(rc_addr.address, btif_rc_cb[0].rc_addr);
for (int i = 0; i < p_rsp->num_attr; i++) {
p_attr[i].attr_id = p_rsp->p_attrs[i].attr_id;
{
bt_bdaddr_t rc_addr;
- bdcpy(rc_addr.address, btif_rc_cb.rc_addr);
+ bdcpy(rc_addr.address, btif_rc_cb[0].rc_addr);
if (p_rsp->status == AVRC_STS_NO_ERROR)
{
{
bt_rc_callbacks = NULL;
}
- alarm_free(btif_rc_cb.rc_play_status_timer);
+ alarm_free(btif_rc_cb[0].rc_play_status_timer);
lbl_destroy();
BTIF_TRACE_EVENT("## RC: %s ## completed", __FUNCTION__);
}
{
bt_rc_ctrl_callbacks = NULL;
}
- alarm_free(btif_rc_cb.rc_play_status_timer);
+ alarm_free(btif_rc_cb[0].rc_play_status_timer);
memset(&btif_rc_cb, 0, sizeof(btif_rc_cb_t));
lbl_destroy();
BTIF_TRACE_EVENT("## %s ## completed", __FUNCTION__);
UINT8* data_start = (UINT8*)(p_msg + 1) + p_msg->offset;
BTIF_TRACE_DEBUG("%s msgreq being sent out with label %d",
__FUNCTION__,p_transaction->lbl);
- BTA_AvVendorCmd(btif_rc_cb.rc_handle,p_transaction->lbl,AVRC_CMD_STATUS,
+ BTA_AvVendorCmd(btif_rc_cb[0].rc_handle,p_transaction->lbl,AVRC_CMD_STATUS,
data_start, p_msg->len);
status = BT_STATUS_SUCCESS;
start_status_command_timer (AVRC_PDU_GET_CAPABILITIES, p_transaction);
UINT8* data_start = (UINT8*)(p_msg + 1) + p_msg->offset;
BTIF_TRACE_DEBUG("%s msgreq being sent out with label %d",
__FUNCTION__,p_transaction->lbl);
- BTA_AvVendorCmd(btif_rc_cb.rc_handle,p_transaction->lbl,AVRC_CMD_STATUS,
+ BTA_AvVendorCmd(btif_rc_cb[0].rc_handle,p_transaction->lbl,AVRC_CMD_STATUS,
data_start, p_msg->len);
status = BT_STATUS_SUCCESS;
start_status_command_timer (AVRC_PDU_LIST_PLAYER_APP_ATTR, p_transaction);
UINT8* data_start = (UINT8*)(p_msg + 1) + p_msg->offset;
BTIF_TRACE_DEBUG("%s msgreq being sent out with label %d",
__FUNCTION__,p_transaction->lbl);
- BTA_AvVendorCmd(btif_rc_cb.rc_handle,p_transaction->lbl,AVRC_CMD_STATUS,
+ BTA_AvVendorCmd(btif_rc_cb[0].rc_handle,p_transaction->lbl,AVRC_CMD_STATUS,
data_start, p_msg->len);
status = BT_STATUS_SUCCESS;
start_status_command_timer (AVRC_PDU_LIST_PLAYER_APP_VALUES, p_transaction);
UINT8* data_start = (UINT8*)(p_msg + 1) + p_msg->offset;
BTIF_TRACE_DEBUG("%s msgreq being sent out with label %d",
__FUNCTION__,p_transaction->lbl);
- BTA_AvVendorCmd(btif_rc_cb.rc_handle,p_transaction->lbl,AVRC_CMD_STATUS,
+ BTA_AvVendorCmd(btif_rc_cb[0].rc_handle,p_transaction->lbl,AVRC_CMD_STATUS,
data_start, p_msg->len);
status = BT_STATUS_SUCCESS;
start_status_command_timer (AVRC_PDU_GET_CUR_PLAYER_APP_VALUE, p_transaction);
UINT8* data_start = (UINT8*)(p_msg + 1) + p_msg->offset;
BTIF_TRACE_DEBUG("%s msgreq being sent out with label %d",
__FUNCTION__,p_transaction->lbl);
- BTA_AvVendorCmd(btif_rc_cb.rc_handle,p_transaction->lbl,AVRC_CMD_CTRL,
+ BTA_AvVendorCmd(btif_rc_cb[0].rc_handle,p_transaction->lbl,AVRC_CMD_CTRL,
data_start, p_msg->len);
status = BT_STATUS_SUCCESS;
start_control_command_timer (AVRC_PDU_SET_PLAYER_APP_VALUE, p_transaction);
return status;
}
-
/***************************************************************************
**
** Function get_player_app_setting_val_text_cmd
__FUNCTION__, p_transaction->lbl);
if (p_msg != NULL)
{
- BTA_AvVendorCmd(btif_rc_cb.rc_handle, p_transaction->lbl,
+ BTA_AvVendorCmd(btif_rc_cb[0].rc_handle, p_transaction->lbl,
AVRC_CMD_STATUS, data_start, p_msg->len);
status = BT_STATUS_SUCCESS;
start_status_command_timer (AVRC_PDU_GET_PLAYER_APP_VALUE_TEXT, p_transaction);
__FUNCTION__, label);
if (p_msg != NULL)
{
- BTA_AvVendorCmd(btif_rc_cb.rc_handle, label, AVRC_CMD_NOTIF,
+ BTA_AvVendorCmd(btif_rc_cb[0].rc_handle, label, AVRC_CMD_NOTIF,
data_start, p_msg->len);
status = BT_STATUS_SUCCESS;
}
__FUNCTION__, p_transaction->lbl);
if (p_msg != NULL)
{
- BTA_AvVendorCmd(btif_rc_cb.rc_handle, p_transaction->lbl,
+ BTA_AvVendorCmd(btif_rc_cb[0].rc_handle, p_transaction->lbl,
AVRC_CMD_STATUS, data_start, p_msg->len);
status = BT_STATUS_SUCCESS;
start_status_command_timer (AVRC_PDU_GET_ELEMENT_ATTR,
__FUNCTION__, p_transaction->lbl);
if (p_msg != NULL)
{
- BTA_AvVendorCmd(btif_rc_cb.rc_handle,p_transaction->lbl,
+ BTA_AvVendorCmd(btif_rc_cb[0].rc_handle,p_transaction->lbl,
AVRC_CMD_STATUS, data_start, p_msg->len);
status = BT_STATUS_SUCCESS;
start_status_command_timer (AVRC_PDU_GET_PLAY_STATUS, p_transaction);
avrc_rsp.volume.pdu = AVRC_PDU_SET_ABSOLUTE_VOLUME;
avrc_rsp.volume.status = AVRC_STS_NO_ERROR;
avrc_rsp.volume.volume = abs_vol;
- status = AVRC_BldResponse(btif_rc_cb.rc_handle, &avrc_rsp, &p_msg);
+ status = AVRC_BldResponse(btif_rc_cb[0].rc_handle, &avrc_rsp, &p_msg);
if (status == AVRC_STS_NO_ERROR)
{
UINT8* data_start = (UINT8*)(p_msg + 1) + p_msg->offset;
BTIF_TRACE_DEBUG("%s msgreq being sent out with label %d",
- __FUNCTION__, btif_rc_cb.rc_vol_label);
+ __FUNCTION__, btif_rc_cb[0].rc_vol_label);
if (p_msg != NULL)
{
- BTA_AvVendorRsp(btif_rc_cb.rc_handle, label,
+ BTA_AvVendorRsp(btif_rc_cb[0].rc_handle, label,
BTA_AV_RSP_ACCEPT, data_start, p_msg->len, 0);
status = BT_STATUS_SUCCESS;
}
avrc_rsp.reg_notif.param.volume = abs_vol;
avrc_rsp.reg_notif.event_id = AVRC_EVT_VOLUME_CHANGE;
- status = AVRC_BldResponse(btif_rc_cb.rc_handle, &avrc_rsp, &p_msg);
+ status = AVRC_BldResponse(btif_rc_cb[0].rc_handle, &avrc_rsp, &p_msg);
if (status == AVRC_STS_NO_ERROR) {
BTIF_TRACE_DEBUG("%s msgreq being sent out with label %d",
__func__, label);
UINT8* data_start = (UINT8*)(p_msg + 1) + p_msg->offset;
- BTA_AvVendorRsp(btif_rc_cb.rc_handle, label,
+ BTA_AvVendorRsp(btif_rc_cb[0].rc_handle, label,
(rsp_type == BTRC_NOTIFICATION_TYPE_INTERIM) ?
AVRC_RSP_INTERIM : AVRC_RSP_CHANGED,
data_start, p_msg->len, 0);
BTIF_TRACE_DEBUG("%s: key-code: %d, key-state: %d", __FUNCTION__,
key_code, key_state);
CHECK_RC_CONNECTED
- if (btif_rc_cb.rc_features & BTA_AV_FEAT_RCTG)
+ if (btif_rc_cb[0].rc_features & BTA_AV_FEAT_RCTG)
{
bt_status_t tran_status = get_transaction(&p_transaction);
if ((BT_STATUS_SUCCESS == tran_status) && (NULL != p_transaction)) {
UINT24_TO_BE_STREAM(start, AVRC_CO_METADATA);
*(start)++ = 0;
UINT8_TO_BE_STREAM(start, key_code);
- BTA_AvRemoteVendorUniqueCmd(btif_rc_cb.rc_handle,
+ BTA_AvRemoteVendorUniqueCmd(btif_rc_cb[0].rc_handle,
p_transaction->lbl,
(tBTA_AV_STATE)key_state, buffer,
AVRC_PASS_THRU_GROUP_LEN);
static bt_status_t send_passthrough_cmd(bt_bdaddr_t *bd_addr, uint8_t key_code, uint8_t key_state)
{
tAVRC_STS status = BT_STATUS_UNSUPPORTED;
+ /* Controller is used only for Certification purposes.
+ * In normal case AVRCP controller will not be used, hence
+ * updating this is required.
+ */
+ int index = BTIF_RC_DEFAULT_INDEX; //For RC it should be 0
#if (AVRC_CTLR_INCLUDED == TRUE)
CHECK_RC_CONNECTED
rc_transaction_t *p_transaction=NULL;
BTIF_TRACE_DEBUG("%s: key-code: %d, key-state: %d", __FUNCTION__,
key_code, key_state);
- if (btif_rc_cb.rc_features & BTA_AV_FEAT_RCTG)
+ if (btif_rc_cb[index].rc_features & BTA_AV_FEAT_RCTG)
{
bt_status_t tran_status = get_transaction(&p_transaction);
if (BT_STATUS_SUCCESS == tran_status && NULL != p_transaction)
{
- BTA_AvRemoteCmd(btif_rc_cb.rc_handle, p_transaction->lbl,
+ BTA_AvRemoteCmd(btif_rc_cb[index].rc_handle, p_transaction->lbl,
(tBTA_AV_RC)key_code, (tBTA_AV_STATE)key_state);
status = BT_STATUS_SUCCESS;
BTIF_TRACE_DEBUG("%s: succesfully sent passthrough command to BTA", __FUNCTION__);
changepath_rsp,
playitem_rsp,
get_itemattr_rsp,
+ is_device_active_in_handoff,
cleanup,
};
******************************************************************************/
typedef struct {
btif_sm_state_t state;
+ int index;
btif_sm_handler_t *p_handlers;
} btif_sm_cb_t;
**
******************************************************************************/
-btif_sm_handle_t btif_sm_init(const btif_sm_handler_t *p_handlers, btif_sm_state_t initial_state)
+btif_sm_handle_t btif_sm_init(const btif_sm_handler_t *p_handlers, btif_sm_state_t initial_state,
+ int index)
{
if (p_handlers == NULL) {
BTIF_TRACE_ERROR("%s : p_handlers is NULL", __FUNCTION__);
btif_sm_cb_t *p_cb = (btif_sm_cb_t *)osi_malloc(sizeof(btif_sm_cb_t));
p_cb->state = initial_state;
p_cb->p_handlers = (btif_sm_handler_t*)p_handlers;
+ p_cb->index = index;
/* Send BTIF_SM_ENTER_EVT to the initial state */
- p_cb->p_handlers[initial_state](BTIF_SM_ENTER_EVT, NULL);
+ p_cb->p_handlers[initial_state](BTIF_SM_ENTER_EVT, NULL, index);
return (btif_sm_handle_t)p_cb;
}
btif_sm_state_t btif_sm_get_state(btif_sm_handle_t handle)
{
btif_sm_cb_t *p_cb = (btif_sm_cb_t*)handle;
-
if (p_cb == NULL)
{
BTIF_TRACE_ERROR("%s : Invalid handle", __FUNCTION__);
return BT_STATUS_FAIL;
}
- if (p_cb->p_handlers[p_cb->state](event, data) == FALSE)
+ if (p_cb->p_handlers[p_cb->state](event, data, p_cb->index) == FALSE)
return BT_STATUS_UNHANDLED;
return status;
}
/* Send exit event to the current state */
- if (p_cb->p_handlers[p_cb->state](BTIF_SM_EXIT_EVT, NULL) == FALSE)
+ if (p_cb->p_handlers[p_cb->state](BTIF_SM_EXIT_EVT, NULL, p_cb->index) == FALSE)
status = BT_STATUS_UNHANDLED;
/* Change to the new state */
p_cb->state = state;
/* Send enter event to the new state */
- if (p_cb->p_handlers[p_cb->state](BTIF_SM_ENTER_EVT, NULL) == FALSE)
+ if (p_cb->p_handlers[p_cb->state](BTIF_SM_ENTER_EVT, NULL, p_cb->index) == FALSE)
status = BT_STATUS_UNHANDLED;
return status;
#define AVDT_NUM_LINKS 2
#endif
-/* Number of simultaneous stream endpoints. */
+/* Number of simultaneous stream endpoints.
+ * Audio*2 + Video*2 + 1 Additional
+ */
#ifndef AVDT_NUM_SEPS
-#define AVDT_NUM_SEPS 3
+#define AVDT_NUM_SEPS 5
#endif
/* Number of transport channels setup by AVDT for all media streams */
#define AVCT_NUM_LINKS 2
#endif
-/* Number of simultaneous AVCTP connections. */
+/* Number of simultaneous AVCTP connections.
+ * Audio*2 + Video*2 + 1 Additional */
#ifndef AVCT_NUM_CONN
-#define AVCT_NUM_CONN 3
+#define AVCT_NUM_CONN 5
+#endif
+
+/* Buffer size to reassemble the SDU. */
+#ifndef AVCT_BR_USER_RX_BUF_SIZE
+#define AVCT_BR_USER_RX_BUF_SIZE BT_DEFAULT_BUFFER_SIZE
+#endif
+
+/* Buffer size to hold the SDU. */
+#ifndef AVCT_BR_USER_TX_BUF_SIZE
+#define AVCT_BR_USER_TX_BUF_SIZE BT_DEFAULT_BUFFER_SIZE
+#endif
+
+/*
+ * Buffer size used to hold MPS segments during SDU reassembly
+ */
+#ifndef AVCT_BR_FCR_RX_BUF_SIZE
+#define AVCT_BR_FCR_RX_BUF_SIZE BT_DEFAULT_BUFFER_SIZE
+#endif
+
+/*
+ * Default buffer size used to hold MPS segments used in (re)transmissions.
+ * The size of each buffer must be able to hold the maximum MPS segment size
+ * passed in tL2CAP_FCR_OPTIONS plus BT_HDR (8) + HCI preamble (4) +
+ * L2CAP_MIN_OFFSET (11 - as of BT 2.1 + EDR Spec).+1452 */
+#ifndef AVCT_BR_FCR_TX_BUF_SIZE
+#define AVCT_BR_FCR_TX_BUF_SIZE BT_DEFAULT_BUFFER_SIZE
#endif
/******************************************************************************
#define MCA_CTRL_MTU 60
#endif
+
/* The maximum number of registered MCAP instances. */
#ifndef MCA_NUM_REGS
#define MCA_NUM_REGS 12
#include "a2d_api.h"
#include "a2d_int.h"
#include "avdt_api.h"
+#include "osi/include/allocator.h"
/*****************************************************************************
** Global data
if (result == TRUE)
{
- /* store service_uuid */
+ /* store service_uuid and discovery db pointer */
a2d_cb.find.service_uuid = service_uuid;
a2d_cb.find.p_cback = p_cback;
a2d_cb.trace_level = BT_TRACE_LEVEL_NONE;
#endif
}
+/*******************************************************************************
+**
+** Function a2d_get_avdt_sdp_ver
+**
+** Description This function fetches current version of AVDT.
+**
+** Returns Current version of AVDT
+**
+*******************************************************************************/
+int a2d_get_avdt_sdp_ver ()
+{
+ return a2d_cb.avdt_sdp_ver;
+}
/* Used only for conformance testing */
extern void a2d_set_avdt_sdp_ver (UINT16 avdt_sdp_ver);
+/* Used to check local version of AVDTP */
+extern int a2d_get_avdt_sdp_ver ();
+
#ifdef __cplusplus
}
#endif
tAVCT_CB avct_cb;
#endif
+
+/*******************************************************************************
+**
+** Function AVCT_Init
+**
+** Description This function is called to initialize the control block
+** for this layer. It must be called before accessing any
+** other API functions for this layer. It is typically called
+** once during the start up of the stack.
+**
+** Returns void
+**
+*******************************************************************************/
+void AVCT_Init(void)
+{
+ /* initialize AVCTP data structures */
+ memset(&avct_cb, 0, sizeof(tAVCT_CB));
+
+#if defined(AVCT_INITIAL_TRACE_LEVEL)
+ avct_cb.trace_level = AVCT_INITIAL_TRACE_LEVEL;
+#else
+ avct_cb.trace_level = BT_TRACE_LEVEL_NONE;
+#endif
+}
+
/*******************************************************************************
**
** Function AVCT_Register
avct_cb.mtu_br = mtu_br;
#endif
-#if defined(AVCT_INITIAL_TRACE_LEVEL)
- avct_cb.trace_level = AVCT_INITIAL_TRACE_LEVEL;
-#else
- avct_cb.trace_level = BT_TRACE_LEVEL_NONE;
-#endif
-
if (mtu < AVCT_MIN_CONTROL_MTU)
mtu = AVCT_MIN_CONTROL_MTU;
/* store mtu */
else
{
p_ccb->p_bcb = avct_bcb_by_lcb(p_ccb->p_lcb);
- avct_bcb_event(p_ccb->p_bcb, AVCT_LCB_UL_MSG_EVT, (tAVCT_LCB_EVT *) &ul_msg);
+ if (p_ccb->p_bcb)
+ avct_bcb_event(p_ccb->p_bcb, AVCT_LCB_UL_MSG_EVT, (tAVCT_LCB_EVT *) &ul_msg);
+ else
+ {
+ result = AVCT_BAD_HANDLE;
+ osi_free(p_msg);
+ }
}
}
/* send msg event to lcb */
return result;
}
+/******************************************************************************
+**
+** Function AVCT_SetTraceLevel
+**
+** Description Sets the trace level for AVCT. If 0xff is passed, the
+** current trace level is returned.
+**
+** Input Parameters:
+** new_level: The level to set the AVCT tracing to:
+** 0xff-returns the current setting.
+** 0-turns off tracing.
+** >= 1-Errors.
+** >= 2-Warnings.
+** >= 3-APIs.
+** >= 4-Events.
+** >= 5-Debug.
+**
+** Returns The new trace level or current trace level if
+** the input parameter is 0xff.
+**
+******************************************************************************/
+UINT8 AVCT_SetTraceLevel (UINT8 new_level)
+{
+ if (new_level != 0xFF)
+ avct_cb.trace_level = new_level;
+
+ return (avct_cb.trace_level);
+}
+
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 */
+ fixed_queue_t *tx_q; /* Transmit data buffer queue */
BOOLEAN cong; /* TRUE, if congested */
} tAVCT_BCB;
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;
}
else
{
+ /* We will only support one browsing connection.
+ * Second incoming BR conn is rejected.*/
+ for (index = 0; index < AVCT_NUM_LINKS; index++)
+ {
+ p_bcb = &avct_cb.bcb[index];
+ if (p_bcb && p_bcb->allocated)
+ {
+ AVCT_TRACE_ERROR("Browsing already connected to other device");
+ AVCT_TRACE_ERROR("Reject Browsing connection:%d", p_bcb->allocated);
+ result = L2CAP_CONN_NO_RESOURCES;
+ L2CA_ErtmConnectRsp (bd_addr, id, lcid, result, L2CAP_CONN_OK, &ertm_info);
+ return;
+ }
+ }
index = (UINT8) (p_lcb - &avct_cb.lcb[0]); //calculate offset.
AVCT_TRACE_DEBUG("index value = %d",index);
p_bcb = &avct_cb.bcb[index];
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;
+ ertm_info.user_rx_buf_size = 4096;//AVCT_BR_USER_RX_BUF_SIZE;
+ ertm_info.user_tx_buf_size = 4096;//AVCT_BR_USER_TX_BUF_SIZE;
+ ertm_info.fcr_rx_buf_size = 4096;//AVCT_BR_FCR_RX_BUF_SIZE;
+ ertm_info.fcr_tx_buf_size = 4096;//AVCT_BR_FCR_TX_BUF_SIZE;
p_ertm_info = &ertm_info;
L2CA_ErtmConnectRsp (bd_addr, id, lcid, result, L2CAP_CONN_OK, p_ertm_info);
}
else /* prevent buffer leak */
{
AVCT_TRACE_WARNING("avct_l2c_br_data_ind_cback drop buffer");
- GKI_freebuf(p_buf);
+ osi_free_and_reset((void**)&p_buf);
}
}
/* execute action functions */
for (i = 0; i < AVCT_LCB_ACTIONS; i++)
{
- if ((action = state_table[event][i]) != AVCT_LCB_IGNORE)
+ if ((action = state_table[event][i]) < AVCT_LCB_IGNORE)
{
(*avct_lcb_action[action])(p_lcb, p_data);
}
/* execute action functions */
for (i = 0; i < AVCT_LCB_ACTIONS; i++)
{
- if ((action = state_table[event][i]) != AVCT_LCB_IGNORE)
+ if ((action = state_table[event][i]) < AVCT_LCB_IGNORE)
{
(*avct_bcb_action[action])(p_bcb, p_data);
}
{
if (p_ccb->allocated && (p_ccb->p_lcb == p_lcb) && (p_ccb->cc.pid == pid))
{
+ AVCT_TRACE_DEBUG("avct_lcb_has_pid, found");
return p_ccb;
}
}
+ AVCT_TRACE_WARNING("avct_lcb_has_pid, not found");
return NULL;
}
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, \
/* quick sanity check on length */
if (p_buf->len < avct_lcb_pkt_type_len[pkt_type])
{
- GKI_freebuf(p_buf);
+ osi_free_and_reset((void**)&p_buf);
AVCT_TRACE_WARNING("### Bad length during reassembly");
p_ret = NULL;
}
}
else
{
- GKI_freebuf(p_buf);
+ osi_free_and_reset((void**)&p_buf);
p_ret =NULL;
AVCT_TRACE_WARNING("### Got Fragmented packet");
}
******************************************************************************/
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");
if (p_ccb->allocated)
{
/* if bound to this lcb send connect confirm event */
+ AVCT_TRACE_DEBUG("avct_lcb_open_ind, %d", p_ccb->allocated);
if (p_ccb->p_lcb == p_lcb)
{
+ AVCT_TRACE_DEBUG("avct_lcb_open_ind, bind true");
bind = TRUE;
L2CA_SetTxPriority(p_lcb->ch_lcid, L2CAP_CHNL_PRIORITY_HIGH);
p_ccb->cc.p_ctrl_cback(avct_ccb_to_idx(p_ccb), AVCT_CONNECT_CFM_EVT,
(avct_lcb_has_pid(p_lcb, p_ccb->cc.pid) == NULL))
{
/* bind ccb to lcb and send connect ind event */
+ AVCT_TRACE_DEBUG("avct_lcb_open_ind, bind and update");
bind = TRUE;
p_ccb->p_lcb = p_lcb;
L2CA_SetTxPriority(p_lcb->ch_lcid, L2CAP_CHNL_PRIORITY_HIGH);
/* if no ccbs bound to this lcb, disconnect */
if (bind == FALSE)
{
+ AVCT_TRACE_DEBUG("avct_lcb_open_ind, send disconnect");
avct_lcb_event(p_lcb, AVCT_LCB_INT_CLOSE_EVT, p_data);
}
}
{
//set avct_cb.bcb to 0
memset(p_ccb->p_bcb, 0 ,sizeof(tAVCT_BCB));
- p_ccb->p_bcb == NULL;
+ p_ccb->p_bcb = NULL;
AVCT_TRACE_DEBUG("**close_ind");
}
}
*******************************************************************************/
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 */
+ AVCT_TRACE_DEBUG("avct_bcb_cong_ind = %d", p_data->cong);
+
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))
+ if (p_bcb->cong == FALSE && !fixed_queue_is_empty(p_bcb->tx_q))
{
- while (!p_bcb->cong && (p_buf = (BT_HDR *)GKI_dequeue(&p_bcb->tx_q)) != NULL)
+ while (!p_bcb->cong &&
+ (p_buf = (BT_HDR *)fixed_queue_try_dequeue(p_bcb->tx_q)) != NULL)
{
if (L2CA_DataWrite(p_bcb->ch_lcid, p_buf) == L2CAP_DW_CONGESTED)
{
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);
+ osi_free_and_reset((void**)&p_data->ul_msg.p_buf);
}
#endif
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);
if (p_bcb->cong == TRUE)
{
AVCT_TRACE_ERROR("L2CAP congestion");
- GKI_enqueue (&p_bcb->tx_q, p_buf);
+ fixed_queue_enqueue(p_bcb->tx_q, p_buf);
}
else
{
{
AVCT_TRACE_DEBUG("avct_bcb_free_msg_ind");
if (p_data)
- GKI_freebuf(p_data->p_buf);
+ osi_free_and_reset((void**)&p_data->p_buf);
}
#endif
if (cr_ipid == AVCT_CR_IPID_INVALID)
{
AVCT_TRACE_WARNING("### Invalid cr_ipid", cr_ipid);
- GKI_freebuf(p_data->p_buf);
+ osi_free_and_reset((void**)&p_data->p_buf);
return;
}
/* parse and lookup PID */
if (p_lcb == NULL)
{
AVCT_TRACE_ERROR("### Error lcb is NULL");
- GKI_freebuf(p_data->p_buf);
+ osi_free_and_reset((void**)&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);
+ osi_free_and_reset((void**)&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)
+ if ((p_buf = (BT_HDR *) osi_malloc(AVCT_CMD_BUF_SIZE)) != NULL)
{
p_buf->len = AVCT_HDR_LEN_SINGLE;
p_buf->offset = AVCT_MSG_OFFSET - AVCT_HDR_LEN_SINGLE;
tAVDT_CB avdt_cb;
#endif
+/*******************************************************************************
+**
+** Function AVDT_Init
+**
+** Description This function is called to initialize the control block
+** for this layer. It must be called before accessing any
+** other API functions for this layer. It is typically called
+** once during the start up of the stack.
+**
+** Returns void
+**
+*******************************************************************************/
+void AVDT_Init(void)
+{
+ memset(&avdt_cb, 0, sizeof(tAVDT_CB));
+
+#if defined(AVDT_INITIAL_TRACE_LEVEL)
+ avdt_cb.trace_level = AVDT_INITIAL_TRACE_LEVEL;
+#else
+ avdt_cb.trace_level = BT_TRACE_LEVEL_NONE;
+#endif
+}
+
void avdt_ccb_idle_ccb_timer_timeout(void *data)
{
tAVDT_CCB *p_ccb = (tAVDT_CCB *)data;
/*******************************************************************************
**
+** Function AVDT_UpdateServiceBusyState
+**
+** Description This function is used to set the service busy state
+** during outgoing connection to properly handle the
+** connections in upper layers.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void AVDT_UpdateServiceBusyState(BOOLEAN state)
+{
+ AVDT_TRACE_DEBUG("AVDT_UpdateServiceBusyState: %d", state);
+ avdt_cb.conn_in_progress = state;
+}
+
+/*******************************************************************************
+**
+** Function AVDT_GetServiceBusyState
+**
+** Description This function is used to get the service busy state
+**
+**
+** Returns outgoing connection in progress or not
+**
+*******************************************************************************/
+BOOLEAN AVDT_GetServiceBusyState(void)
+{
+ AVDT_TRACE_DEBUG("AVDT_GetServiceBusyState: %d", avdt_cb.conn_in_progress);
+ return avdt_cb.conn_in_progress;
+}
+
+/*******************************************************************************
+**
** Function AVDT_SINK_Activate
**
** Description Activate SEP of A2DP Sink. In Use parameter is adjusted.
/* Verify parameters; if invalid, return failure */
if (((p_cs->cfg.psc_mask & (~AVDT_PSC)) != 0) || (p_cs->p_ctrl_cback == NULL))
{
+ AVDT_TRACE_ERROR("%s: bad param", __FUNCTION__);
result = AVDT_BAD_PARAMS;
}
/* Allocate scb; if no scbs, return failure */
else if ((p_scb = avdt_scb_alloc(p_cs)) == NULL)
{
+ AVDT_TRACE_ERROR("%s: noresource", __FUNCTION__);
result = AVDT_NO_RESOURCES;
}
else
{
*p_handle = avdt_scb_to_hdl(p_scb);
+ AVDT_TRACE_DEBUG("%s: allocated SCB", __FUNCTION__);
}
return result;
}
tAVDT_SCB_ACTION *p_scb_act; /* pointer to SCB action functions */
tAVDT_CTRL_CBACK *p_conn_cback; /* connection callback function */
UINT8 trace_level; /* trace level */
+ BOOLEAN conn_in_progress; /* outgoing connection in progress */
} tAVDT_CB;
tBTM_STATUS rc;
UNUSED(psm);
+ /* Check if outgoing connection is in progress
+ * if yes, reject incoming connection at L2CAP
+ * level itself.
+ */
+ if(avdt_cb.conn_in_progress == TRUE)
+ {
+ AVDT_TRACE_WARNING("connect_ind: outgoing conn in progress: Reject incoming conn");
+ result = L2CAP_CONN_NO_RESOURCES;
+ }
/* do we already have a control channel for this peer? */
- if ((p_ccb = avdt_ccb_by_bd(bd_addr)) == NULL)
+ else if ((p_ccb = avdt_ccb_by_bd(bd_addr)) == NULL)
{
/* no, allocate ccb */
if ((p_ccb = avdt_ccb_alloc(bd_addr)) == NULL)
UINT8 opcode;
tAVRC_MSG msg;
UINT8 *p_data;
- UINT8 *browse_length;
UINT8 *p_begin;
BOOLEAN drop = FALSE;
BOOLEAN do_free = TRUE;
if (cr == AVCT_CMD)
{
/* send the response to the peer */
- p_rsp = avrc_copy_packet(p_pkt);
+ 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,
if (cr == AVCT_CMD)
{
/* send the response to the peer */
- p_rsp = avrc_copy_packet(p_pkt);
+ 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),
if (reject)
{
/* reject unsupported opcode */
- p_rsp = avrc_copy_packet(p_pkt);
+ 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)
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;
-}
/*******************************************************************************
**
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;
+ UINT16 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;
{
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);
{
UINT16 offset = AVCT_BROWSE_OFFSET;
UINT16 chnl = AVCT_DATA_BROWSE;
- UINT16 len = AVRC_BROWSE_POOL_SIZE;
+ UINT16 len = BT_DEFAULT_BUFFER_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);
+ p_pkt = (BT_HDR *)osi_malloc(len);
if (p_pkt != NULL)
{
}
if (alloc && (status != AVRC_STS_NO_ERROR) )
{
- GKI_freebuf(p_pkt);
+ osi_free_and_reset((void **)&p_pkt);
*pp_pkt = NULL;
AVRC_TRACE_ERROR("### error status:%d",status);
}
extern tA2D_STATUS A2D_FindService(UINT16 service_uuid, BD_ADDR bd_addr,
tA2D_SDP_DB_PARAMS *p_db, tA2D_FIND_CBACK *p_cback);
+/* Used to check local version of AVDTP */
+extern int a2d_get_avdt_sdp_ver ();
+
/******************************************************************************
**
** Function A2D_SetTraceLevel
/*******************************************************************************
**
+** Function AVCT_Init
+**
+** Description This function is called to initialize the control block
+** for this layer. It must be called before accessing any
+** other API functions for this layer. It is typically called
+** once during the start up of the stack.
+**
+** Returns void
+**
+*******************************************************************************/
+void AVCT_Init(void);
+
+/*******************************************************************************
+**
** Function AVCT_Register
**
** Description This is the system level registration function for the
extern UINT16 AVCT_MsgReq(UINT8 handle, UINT8 label, UINT8 cr, BT_HDR *p_msg);
+
+/******************************************************************************
+**
+** Function AVCT_SetTraceLevel
+**
+** Description Sets the trace level for AVCT. If 0xff is passed, the
+** current trace level is returned.
+**
+** Input Parameters:
+** new_level: The level to set the AVCT tracing to:
+** 0xff-returns the current setting.
+** 0-turns off tracing.
+** >= 1-Errors.
+** >= 2-Warnings.
+** >= 3-APIs.
+** >= 4-Events.
+** >= 5-Debug.
+**
+** Returns The new trace level or current trace level if
+** the input parameter is 0xff.
+**
+******************************************************************************/
+UINT8 AVCT_SetTraceLevel (UINT8 new_level);
+
+
/*******************************************************************************
**
** Function avct_get_peer_addr_by_ccb
/*******************************************************************************
**
+** Function AVDT_Init
+**
+** Description This function is called to initialize the control block
+** for this layer. It must be called before accessing any
+** other API functions for this layer. It is typically called
+** once during the start up of the stack.
+**
+** Returns void
+**
+*******************************************************************************/
+void AVDT_Init(void);
+
+/*******************************************************************************
+**
** Function AVDT_Register
**
** Description This is the system level registration function for the
/*******************************************************************************
**
+** Function AVDT_UpdateServiceBusyState
+**
+** Description This function is used to set the service busy state
+** during outgoing connection to properly handle the
+** connections in upper layers.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void AVDT_UpdateServiceBusyState(BOOLEAN state);
+
+/*******************************************************************************
+**
+** Function AVDT_GetServiceBusyState
+**
+** Description This function is used to get the service busy state
+**
+**
+** Returns outgoing connection in progress or not
+**
+*******************************************************************************/
+BOOLEAN AVDT_GetServiceBusyState(void);
+
+/*******************************************************************************
+**
** Function AVDT_SINK_Activate
**
** Description Activate SEP of A2DP Sink. In Use parameter is adjusted.
}
if (is_avrcp_fallback)
{
-#if (defined(SDP_AVRCP_1_6) && (SDP_AVRCP_1_6 == TRUE))
- /* Update AVRCP version back to 1.6 */
- p_attr->value_ptr[PROFILE_VERSION_POSITION] = 0x06;
-#else
#if (defined(SDP_AVRCP_1_5) && (SDP_AVRCP_1_5 == TRUE))
/* Update AVRCP version back to 1.5 */
p_attr->value_ptr[PROFILE_VERSION_POSITION] = 0x05;
#endif
-#endif
is_avrcp_fallback = FALSE;
}
if (is_avrcp_browse_bit_reset)
BOOLEAN maxxed_out = FALSE, is_cont = FALSE;
BOOLEAN is_avrcp_fallback = FALSE;
BOOLEAN is_avrcp_browse_bit_reset = FALSE;
- BOOLEAN is_avrcp_ca_bit_reset = FALSE;
BOOLEAN is_hfp_fallback = FALSE;
UINT8 *p_seq_start;
UINT16 seq_len, attr_len;
}
if (is_avrcp_fallback)
{
-#if (defined(SDP_AVRCP_1_6) && (SDP_AVRCP_1_6 == TRUE))
- /* Update AVRCP version back to 1.6 */
- p_attr->value_ptr[PROFILE_VERSION_POSITION] = 0x06;
-#else
#if (defined(SDP_AVRCP_1_5) && (SDP_AVRCP_1_5 == TRUE))
/* Update AVRCP version back to 1.5 */
p_attr->value_ptr[PROFILE_VERSION_POSITION] = 0x05;
#endif
-#endif
is_avrcp_fallback = FALSE;
}
if (is_avrcp_browse_bit_reset)
}
/* Get a buffer to use to build the response */
- BT_HDR *p_buf = (BT_HDR *)osi_malloc(SDP_DATA_BUF_SIZE);
+ p_buf = (BT_HDR *)osi_malloc(SDP_DATA_BUF_SIZE);
p_buf->offset = L2CAP_MIN_OFFSET;
p_rsp = p_rsp_start = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;