BTA_AG_FEAT_UNAT)
#endif
-#define BTIF_HF_ID_1 0
-
#define BTIF_HF_CALL_END_TIMEOUT 6
+#define BTIF_HF_INVALID_IDX -1
+
+/* Number of BTIF-HF control blocks */
+#define BTIF_HF_NUM_CB 2
+
+/* Max HF clients supported from App */
+UINT16 btif_max_hf_clients = -1;
+
+/* HF app ids for service registration */
+typedef enum {
+ BTIF_HF_ID_1 = 0,
+ BTIF_HF_ID_2,
+#if (BTIF_HF_NUM_CB == 3)
+ BTIF_HF_ID_3
+#endif
+} bthf_hf_id_t;
+
+UINT16 bthf_hf_id[BTIF_HF_NUM_CB] = {BTIF_HF_ID_1, BTIF_HF_ID_2,
+ #if (BTIF_HF_NUM_CB == 3)
+ BTIF_HF_ID_3
+ #endif
+ };
+
/************************************************************************************
** Local type definitions
************************************************************************************/
** Static variables
************************************************************************************/
static bthf_callbacks_t *bt_hf_callbacks = NULL;
+static int hf_idx = BTIF_HF_INVALID_IDX;
#define CHECK_BTHF_INIT() if (bt_hf_callbacks == NULL)\
{\
int num_active;
int num_held;
struct timespec call_end_timestamp;
+ struct timespec connected_timestamp;
bthf_call_state_t call_setup_state;
} btif_hf_cb_t;
-static btif_hf_cb_t btif_hf_cb;
+static btif_hf_cb_t btif_hf_cb[BTIF_HF_NUM_CB];
/************************************************************************************
*******************************************************************************/
static BOOLEAN is_connected(bt_bdaddr_t *bd_addr)
{
- if (((btif_hf_cb.state == BTHF_CONNECTION_STATE_CONNECTED) || (btif_hf_cb.state == BTHF_CONNECTION_STATE_SLC_CONNECTED))&&
- ((bd_addr == NULL) || (bdcmp(bd_addr->address, btif_hf_cb.connected_bda.address) == 0)))
- return TRUE;
- else
+ int i;
+ for (i = 0; i < btif_max_hf_clients; ++i)
+ {
+ if (((btif_hf_cb[i].state == BTHF_CONNECTION_STATE_CONNECTED) ||
+ (btif_hf_cb[i].state == BTHF_CONNECTION_STATE_SLC_CONNECTED)) &&
+ ((bd_addr == NULL) || (bdcmp(bd_addr->address,
+ btif_hf_cb[i].connected_bda.address) == 0)))
+ return TRUE;
+ }
return FALSE;
}
/*******************************************************************************
**
+** Function btif_hf_idx_by_bdaddr
+**
+** Description Internal function to get idx by bdaddr
+**
+** Returns idx
+**
+*******************************************************************************/
+static int btif_hf_idx_by_bdaddr(bt_bdaddr_t *bd_addr)
+{
+ int i;
+ for (i = 0; i < btif_max_hf_clients; ++i)
+ {
+ if ((bdcmp(bd_addr->address,
+ btif_hf_cb[i].connected_bda.address) == 0))
+ return i;
+ }
+ return BTIF_HF_INVALID_IDX;
+}
+
+/*******************************************************************************
+**
** Function callstate_to_callsetup
**
** Description Converts HAL call state to BTA call setup indicator value
** Returns void
**
*******************************************************************************/
-static void send_at_result(UINT8 ok_flag, UINT16 errcode)
+static void send_at_result(UINT8 ok_flag, UINT16 errcode, int idx)
{
tBTA_AG_RES_DATA ag_res;
memset (&ag_res, 0, sizeof (ag_res));
ag_res.errcode = errcode;
}
- BTA_AgResult (btif_hf_cb.handle, BTA_AG_UNAT_RES, &ag_res);
+ BTA_AgResult (btif_hf_cb[idx].handle, BTA_AG_UNAT_RES, &ag_res);
}
/*******************************************************************************
BTA_AgResult(BTA_AG_HANDLE_ALL, BTA_AG_IND_RES, &ag_res);
}
-void clear_phone_state()
+void clear_phone_state_multihf(int idx)
{
- btif_hf_cb.call_setup_state = BTHF_CALL_STATE_IDLE;
- btif_hf_cb.num_active = btif_hf_cb.num_held = 0;
+ btif_hf_cb[idx].call_setup_state = BTHF_CALL_STATE_IDLE;
+ btif_hf_cb[idx].num_active = btif_hf_cb[idx].num_held = 0;
}
+/*******************************************************************************
+**
+** Function btif_hf_latest_connected_idx
+**
+** Description Returns idx for latest connected HF
+**
+** Returns int
+**
+*******************************************************************************/
+static int btif_hf_latest_connected_idx()
+{
+ struct timespec now, conn_time_delta;
+ int latest_conn_idx = BTIF_HF_INVALID_IDX, i;
+
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ conn_time_delta.tv_sec = now.tv_sec;
+
+ for (i = 0; i < btif_max_hf_clients; i++)
+ {
+ if (btif_hf_cb[i].state == BTHF_CONNECTION_STATE_SLC_CONNECTED)
+ {
+ if ((now.tv_sec - btif_hf_cb[i].connected_timestamp.tv_sec)
+ < conn_time_delta.tv_sec)
+ {
+ conn_time_delta.tv_sec =
+ now.tv_sec - btif_hf_cb[i].connected_timestamp.tv_sec;
+ latest_conn_idx = i;
+ }
+ }
+ }
+ return latest_conn_idx;
+}
+
+/*******************************************************************************
+**
+** Function btif_hf_check_if_slc_connected
+**
+** Description Returns BT_STATUS_SUCCESS if SLC is up for any HF
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+static bt_status_t btif_hf_check_if_slc_connected()
+{
+ if (bt_hf_callbacks == NULL)
+ {
+ BTIF_TRACE_WARNING1("BTHF: %s: BTHF not initialized", __FUNCTION__);
+ return BT_STATUS_NOT_READY;
+ }
+ else
+ {
+ int i;
+ for (i = 0; i < btif_max_hf_clients; i++)
+ {
+ if ((btif_hf_cb[i].state == BTHF_CONNECTION_STATE_SLC_CONNECTED))
+ {
+ BTIF_TRACE_EVENT2("BTHF: %s: slc connected for idx = %d",
+ __FUNCTION__, i);
+ return BT_STATUS_SUCCESS;
+ }
+ }
+ BTIF_TRACE_WARNING1("BTHF: %s: No SLC connection up", __FUNCTION__);
+ return BT_STATUS_NOT_READY;
+ }
+}
/*****************************************************************************
** Section name (Group of functions)
{
tBTA_AG *p_data = (tBTA_AG *)p_param;
bdstr_t bdstr;
+ bt_bdaddr_t addr;
+ int idx = p_data->hdr.handle - 1;
BTIF_TRACE_DEBUG2("%s: event=%s", __FUNCTION__, dump_hf_event(event));
break;
case BTA_AG_REGISTER_EVT:
- btif_hf_cb.handle = p_data->reg.hdr.handle;
+ btif_hf_cb[idx].handle = p_data->reg.hdr.handle;
+ BTIF_TRACE_DEBUG2("%s: BTA_AG_REGISTER_EVT,"
+ "btif_hf_cb.handle = %d", __FUNCTION__, btif_hf_cb[idx].handle);
break;
case BTA_AG_OPEN_EVT:
if (p_data->open.status == BTA_AG_SUCCESS)
{
- bdcpy(btif_hf_cb.connected_bda.address, p_data->open.bd_addr);
- btif_hf_cb.state = BTHF_CONNECTION_STATE_CONNECTED;
- btif_hf_cb.peer_feat = 0;
- clear_phone_state();
+ bdcpy(btif_hf_cb[idx].connected_bda.address,
+ p_data->open.bd_addr);
+ btif_hf_cb[idx].state = BTHF_CONNECTION_STATE_CONNECTED;
+ btif_hf_cb[idx].peer_feat = 0;
+ clear_phone_state_multihf(idx);
}
- else if (btif_hf_cb.state == BTHF_CONNECTION_STATE_CONNECTING)
+ else if (btif_hf_cb[idx].state == BTHF_CONNECTION_STATE_CONNECTING)
{
- btif_hf_cb.state = BTHF_CONNECTION_STATE_DISCONNECTED;
+ btif_hf_cb[idx].state = BTHF_CONNECTION_STATE_DISCONNECTED;
}
else
{
BTIF_TRACE_WARNING4("%s: AG open failed, but another device connected. status=%d state=%d connected device=%s",
- __FUNCTION__, p_data->open.status, btif_hf_cb.state, bd2str(&btif_hf_cb.connected_bda, &bdstr));
+ __FUNCTION__, p_data->open.status, btif_hf_cb[idx].state,
+ bd2str(&btif_hf_cb[idx].connected_bda, &bdstr));
break;
}
- HAL_CBACK(bt_hf_callbacks, connection_state_cb, btif_hf_cb.state, &btif_hf_cb.connected_bda);
+ HAL_CBACK(bt_hf_callbacks, connection_state_cb, btif_hf_cb[idx].state,
+ &btif_hf_cb[idx].connected_bda);
- if (btif_hf_cb.state == BTHF_CONNECTION_STATE_DISCONNECTED)
- bdsetany(btif_hf_cb.connected_bda.address);
+ if (btif_hf_cb[idx].state == BTHF_CONNECTION_STATE_DISCONNECTED)
+ bdsetany(btif_hf_cb[idx].connected_bda.address);
if (p_data->open.status != BTA_AG_SUCCESS)
btif_queue_advance();
break;
case BTA_AG_CLOSE_EVT:
- btif_hf_cb.state = BTHF_CONNECTION_STATE_DISCONNECTED;
- HAL_CBACK(bt_hf_callbacks, connection_state_cb, btif_hf_cb.state, &btif_hf_cb.connected_bda);
- bdsetany(btif_hf_cb.connected_bda.address);
- btif_hf_cb.peer_feat = 0;
- clear_phone_state();
+ btif_hf_cb[idx].connected_timestamp.tv_sec = 0;
+ btif_hf_cb[idx].state = BTHF_CONNECTION_STATE_DISCONNECTED;
+ BTIF_TRACE_DEBUG3("%s: BTA_AG_CLOSE_EVT,"
+ "idx = %d, btif_hf_cb.handle = %d", __FUNCTION__, idx,
+ btif_hf_cb[idx].handle);
+ HAL_CBACK(bt_hf_callbacks, connection_state_cb, btif_hf_cb[idx].state,
+ &btif_hf_cb[idx].connected_bda);
+ bdsetany(btif_hf_cb[idx].connected_bda.address);
+ btif_hf_cb[idx].peer_feat = 0;
+ clear_phone_state_multihf(idx);
+ hf_idx = btif_hf_latest_connected_idx();
/* If AG_OPEN was received but SLC was not setup in a specified time (10 seconds),
** then AG_CLOSE may be received. We need to advance the queue here
*/
break;
case BTA_AG_CONN_EVT:
- btif_hf_cb.peer_feat = p_data->conn.peer_feat;
- btif_hf_cb.state = BTHF_CONNECTION_STATE_SLC_CONNECTED;
-
- HAL_CBACK(bt_hf_callbacks, connection_state_cb, btif_hf_cb.state,
- &btif_hf_cb.connected_bda);
+ clock_gettime(CLOCK_MONOTONIC,
+ &btif_hf_cb[idx].connected_timestamp);
+ BTIF_TRACE_DEBUG2("%s: BTA_AG_CONN_EVT, idx = %d ",
+ __FUNCTION__, idx);
+ btif_hf_cb[idx].peer_feat = p_data->conn.peer_feat;
+ btif_hf_cb[idx].state = BTHF_CONNECTION_STATE_SLC_CONNECTED;
+ hf_idx = btif_hf_latest_connected_idx();
+
+ HAL_CBACK(bt_hf_callbacks, connection_state_cb, btif_hf_cb[idx].state,
+ &btif_hf_cb[idx].connected_bda);
btif_queue_advance();
break;
case BTA_AG_AUDIO_OPEN_EVT:
- HAL_CBACK(bt_hf_callbacks, audio_state_cb, BTHF_AUDIO_STATE_CONNECTED, &btif_hf_cb.connected_bda);
+ hf_idx = idx;
+ HAL_CBACK(bt_hf_callbacks, audio_state_cb, BTHF_AUDIO_STATE_CONNECTED,
+ &btif_hf_cb[idx].connected_bda);
break;
case BTA_AG_AUDIO_CLOSE_EVT:
- HAL_CBACK(bt_hf_callbacks, audio_state_cb, BTHF_AUDIO_STATE_DISCONNECTED, &btif_hf_cb.connected_bda);
+ HAL_CBACK(bt_hf_callbacks, audio_state_cb, BTHF_AUDIO_STATE_DISCONNECTED,
+ &btif_hf_cb[idx].connected_bda);
break;
/* BTA auto-responds, silently discard */
case BTA_AG_SPK_EVT:
case BTA_AG_MIC_EVT:
HAL_CBACK(bt_hf_callbacks, volume_cmd_cb,
- (event == BTA_AG_SPK_EVT) ? BTHF_VOLUME_TYPE_SPK : BTHF_VOLUME_TYPE_MIC, p_data->val.num);
+ (event == BTA_AG_SPK_EVT) ? BTHF_VOLUME_TYPE_SPK :
+ BTHF_VOLUME_TYPE_MIC, p_data->val.num,
+ &btif_hf_cb[idx].connected_bda);
break;
case BTA_AG_AT_A_EVT:
- HAL_CBACK(bt_hf_callbacks, answer_call_cmd_cb);
+ hf_idx = idx;
+ HAL_CBACK(bt_hf_callbacks, answer_call_cmd_cb,
+ &btif_hf_cb[idx].connected_bda);
break;
/* Java needs to send OK/ERROR for these commands */
case BTA_AG_AT_BLDN_EVT:
case BTA_AG_AT_D_EVT:
+ hf_idx = idx;
HAL_CBACK(bt_hf_callbacks, dial_call_cmd_cb,
- (event == BTA_AG_AT_D_EVT) ? p_data->val.str : NULL);
+ (event == BTA_AG_AT_D_EVT) ? p_data->val.str : NULL,
+ &btif_hf_cb[idx].connected_bda);
break;
case BTA_AG_AT_CHUP_EVT:
- HAL_CBACK(bt_hf_callbacks, hangup_call_cmd_cb);
+ HAL_CBACK(bt_hf_callbacks, hangup_call_cmd_cb,
+ &btif_hf_cb[idx].connected_bda);
break;
case BTA_AG_AT_CIND_EVT:
- HAL_CBACK(bt_hf_callbacks, cind_cmd_cb);
+ HAL_CBACK(bt_hf_callbacks, cind_cmd_cb,
+ &btif_hf_cb[idx].connected_bda);
break;
case BTA_AG_AT_VTS_EVT:
- HAL_CBACK(bt_hf_callbacks, dtmf_cmd_cb, p_data->val.str[0]);
+ HAL_CBACK(bt_hf_callbacks, dtmf_cmd_cb, p_data->val.str[0],
+ &btif_hf_cb[idx].connected_bda);
break;
case BTA_AG_AT_BVRA_EVT:
HAL_CBACK(bt_hf_callbacks, vr_cmd_cb,
- (p_data->val.num == 1) ? BTHF_VR_STATE_STARTED : BTHF_VR_STATE_STOPPED);
+ (p_data->val.num == 1) ? BTHF_VR_STATE_STARTED :
+ BTHF_VR_STATE_STOPPED, &btif_hf_cb[idx].connected_bda);
break;
case BTA_AG_AT_NREC_EVT:
HAL_CBACK(bt_hf_callbacks, nrec_cmd_cb,
- (p_data->val.num == 1) ? BTHF_NREC_START : BTHF_NREC_STOP);
+ (p_data->val.num == 1) ? BTHF_NREC_START : BTHF_NREC_STOP,
+ &btif_hf_cb[idx].connected_bda);
break;
/* TODO: Add a callback for CBC */
break;
case BTA_AG_AT_CKPD_EVT:
- HAL_CBACK(bt_hf_callbacks, key_pressed_cmd_cb);
+ HAL_CBACK(bt_hf_callbacks, key_pressed_cmd_cb,
+ &btif_hf_cb[idx].connected_bda);
break;
/* Java needs to send OK/ERROR for these commands */
case BTA_AG_AT_CHLD_EVT:
- HAL_CBACK(bt_hf_callbacks, chld_cmd_cb, atoi(p_data->val.str));
+ HAL_CBACK(bt_hf_callbacks, chld_cmd_cb, atoi(p_data->val.str),
+ &btif_hf_cb[idx].connected_bda);
break;
case BTA_AG_AT_CLCC_EVT:
- HAL_CBACK(bt_hf_callbacks, clcc_cmd_cb, p_data->val.num);
+ HAL_CBACK(bt_hf_callbacks, clcc_cmd_cb,
+ &btif_hf_cb[idx].connected_bda);
break;
case BTA_AG_AT_COPS_EVT:
- HAL_CBACK(bt_hf_callbacks, cops_cmd_cb);
+ HAL_CBACK(bt_hf_callbacks, cops_cmd_cb,
+ &btif_hf_cb[idx].connected_bda);
break;
case BTA_AG_AT_UNAT_EVT:
- HAL_CBACK(bt_hf_callbacks, unknown_at_cmd_cb,
- p_data->val.str);
+ HAL_CBACK(bt_hf_callbacks, unknown_at_cmd_cb, p_data->val.str,
+ &btif_hf_cb[idx].connected_bda);
break;
case BTA_AG_AT_CNUM_EVT:
- HAL_CBACK(bt_hf_callbacks, cnum_cmd_cb);
+ HAL_CBACK(bt_hf_callbacks, cnum_cmd_cb,
+ &btif_hf_cb[idx].connected_bda);
break;
/* TODO: Some of these commands may need to be sent to app. For now respond with error */
case BTA_AG_AT_BINP_EVT:
case BTA_AG_AT_BTRH_EVT:
- send_at_result(BTA_AG_OK_ERROR, BTA_AG_ERR_OP_NOT_SUPPORTED);
+ send_at_result(BTA_AG_OK_ERROR, BTA_AG_ERR_OP_NOT_SUPPORTED, idx);
break;
*******************************************************************************/
static void btif_in_hf_generic_evt(UINT16 event, char *p_param)
{
- UNUSED(p_param);
+ int idx = btif_hf_idx_by_bdaddr((bt_bdaddr_t *)p_param);
BTIF_TRACE_EVENT2("%s: event=%d", __FUNCTION__, event);
switch (event) {
case BTIF_HFP_CB_AUDIO_CONNECTING:
{
HAL_CBACK(bt_hf_callbacks, audio_state_cb, BTHF_AUDIO_STATE_CONNECTING,
- &btif_hf_cb.connected_bda);
+ &btif_hf_cb[idx].connected_bda);
} break;
default:
{
** Returns bt_status_t
**
*******************************************************************************/
-static bt_status_t init( bthf_callbacks_t* callbacks )
+static bt_status_t init( bthf_callbacks_t* callbacks, int max_hf_clients)
{
BTIF_TRACE_EVENT1("%s", __FUNCTION__);
+ int i;
bt_hf_callbacks = callbacks;
btif_enable_service(BTA_HSP_SERVICE_ID);
#endif
- memset(&btif_hf_cb, 0, sizeof(btif_hf_cb_t));
- clear_phone_state();
+ memset(&btif_hf_cb, 0, sizeof(btif_hf_cb));
+ btif_max_hf_clients = max_hf_clients;
+ BTIF_TRACE_DEBUG1("btif_max_hf_clients = %d", btif_max_hf_clients);
+ for (i = 0; i < btif_max_hf_clients; i++)
+ {
+ clear_phone_state_multihf(i);
+ }
return BT_STATUS_SUCCESS;
}
*******************************************************************************/
static bt_status_t connect_int( bt_bdaddr_t *bd_addr )
{
+ CHECK_BTHF_INIT();
+ int i;
+ for (i = 0; i < btif_max_hf_clients;)
+ {
+ if (((btif_hf_cb[i].state == BTHF_CONNECTION_STATE_CONNECTED) ||
+ (btif_hf_cb[i].state == BTHF_CONNECTION_STATE_SLC_CONNECTED)))
+ i++;
+ else
+ break;
+ }
+
+ if (i == btif_max_hf_clients)
+ return BT_STATUS_BUSY;
+
if (!is_connected(bd_addr))
{
- btif_hf_cb.state = BTHF_CONNECTION_STATE_CONNECTING;
- bdcpy(btif_hf_cb.connected_bda.address, bd_addr->address);
+ btif_hf_cb[i].state = BTHF_CONNECTION_STATE_CONNECTING;
+ bdcpy(btif_hf_cb[i].connected_bda.address, bd_addr->address);
- BTA_AgOpen(btif_hf_cb.handle, btif_hf_cb.connected_bda.address,
+ BTA_AgOpen(btif_hf_cb[i].handle, btif_hf_cb[i].connected_bda.address,
BTIF_HF_SECURITY, BTIF_HF_SERVICES);
return BT_STATUS_SUCCESS;
}
{
CHECK_BTHF_INIT();
- if (is_connected(bd_addr))
+ int idx = btif_hf_idx_by_bdaddr(bd_addr);
+
+ if (is_connected(bd_addr) && (idx != BTIF_HF_INVALID_IDX))
{
- BTA_AgClose(btif_hf_cb.handle);
+ BTA_AgClose(btif_hf_cb[idx].handle);
return BT_STATUS_SUCCESS;
}
{
CHECK_BTHF_INIT();
- if (is_connected(bd_addr))
+ int idx = btif_hf_idx_by_bdaddr(bd_addr);
+
+ if (is_connected(bd_addr) && (idx != BTIF_HF_INVALID_IDX))
{
- BTA_AgAudioOpen(btif_hf_cb.handle);
+ BTA_AgAudioOpen(btif_hf_cb[idx].handle);
/* Inform the application that the audio connection has been initiated successfully */
btif_transfer_context(btif_in_hf_generic_evt, BTIF_HFP_CB_AUDIO_CONNECTING,
{
CHECK_BTHF_INIT();
- if (is_connected(bd_addr))
+ int idx = btif_hf_idx_by_bdaddr(bd_addr);
+
+ if (is_connected(bd_addr) && (idx != BTIF_HF_INVALID_IDX))
{
- BTA_AgAudioClose(btif_hf_cb.handle);
+ BTA_AgAudioClose(btif_hf_cb[idx].handle);
return BT_STATUS_SUCCESS;
}
** Returns bt_status_t
**
*******************************************************************************/
-static bt_status_t start_voice_recognition()
+static bt_status_t start_voice_recognition(bt_bdaddr_t *bd_addr)
{
CHECK_BTHF_INIT();
- if (is_connected(NULL))
+
+ int idx = btif_hf_idx_by_bdaddr(bd_addr);
+
+ if (is_connected(bd_addr) && (idx != BTIF_HF_INVALID_IDX))
{
- if (btif_hf_cb.peer_feat & BTA_AG_PEER_FEAT_VREC)
+ if (btif_hf_cb[idx].peer_feat & BTA_AG_PEER_FEAT_VREC)
{
tBTA_AG_RES_DATA ag_res;
memset(&ag_res, 0, sizeof(ag_res));
ag_res.state = 1;
- BTA_AgResult (btif_hf_cb.handle, BTA_AG_BVRA_RES, &ag_res);
+ BTA_AgResult (btif_hf_cb[idx].handle, BTA_AG_BVRA_RES, &ag_res);
return BT_STATUS_SUCCESS;
}
** Returns bt_status_t
**
*******************************************************************************/
-static bt_status_t stop_voice_recognition()
+static bt_status_t stop_voice_recognition(bt_bdaddr_t *bd_addr)
{
CHECK_BTHF_INIT();
- if (is_connected(NULL))
+ int idx = btif_hf_idx_by_bdaddr(bd_addr);
+
+ if (is_connected(bd_addr) && (idx != BTIF_HF_INVALID_IDX))
{
- if (btif_hf_cb.peer_feat & BTA_AG_PEER_FEAT_VREC)
+ if (btif_hf_cb[idx].peer_feat & BTA_AG_PEER_FEAT_VREC)
{
tBTA_AG_RES_DATA ag_res;
memset(&ag_res, 0, sizeof(ag_res));
ag_res.state = 0;
- BTA_AgResult (btif_hf_cb.handle, BTA_AG_BVRA_RES, &ag_res);
+ BTA_AgResult (btif_hf_cb[idx].handle, BTA_AG_BVRA_RES, &ag_res);
return BT_STATUS_SUCCESS;
}
** Returns bt_status_t
**
*******************************************************************************/
-static bt_status_t volume_control(bthf_volume_type_t type, int volume)
+static bt_status_t volume_control(bthf_volume_type_t type, int volume,
+ bt_bdaddr_t *bd_addr)
{
CHECK_BTHF_INIT();
+ int idx = btif_hf_idx_by_bdaddr(bd_addr);
+
tBTA_AG_RES_DATA ag_res;
memset(&ag_res, 0, sizeof(tBTA_AG_RES_DATA));
- if (is_connected(NULL))
+ if (is_connected(bd_addr) && (idx != BTIF_HF_INVALID_IDX))
{
ag_res.num = volume;
- BTA_AgResult(btif_hf_cb.handle,
+ BTA_AgResult(btif_hf_cb[idx].handle,
(type == BTHF_VOLUME_TYPE_SPK) ? BTA_AG_SPK_RES : BTA_AG_MIC_RES,
&ag_res);
return BT_STATUS_SUCCESS;
** Returns bt_status_t
**
*******************************************************************************/
-static bt_status_t cops_response(const char *cops)
+static bt_status_t cops_response(const char *cops, bt_bdaddr_t *bd_addr)
{
CHECK_BTHF_INIT();
- if (is_connected(NULL))
+ int idx = btif_hf_idx_by_bdaddr(bd_addr);
+
+ if (is_connected(bd_addr) && (idx != BTIF_HF_INVALID_IDX))
{
tBTA_AG_RES_DATA ag_res;
sprintf (ag_res.str, "0,0,\"%s\"", cops);
ag_res.ok_flag = BTA_AG_OK_DONE;
- BTA_AgResult (btif_hf_cb.handle, BTA_AG_COPS_RES, &ag_res);
+ BTA_AgResult (btif_hf_cb[idx].handle, BTA_AG_COPS_RES, &ag_res);
return BT_STATUS_SUCCESS;
}
return BT_STATUS_FAIL;
*******************************************************************************/
static bt_status_t cind_response(int svc, int num_active, int num_held,
bthf_call_state_t call_setup_state,
- int signal, int roam, int batt_chg)
+ int signal, int roam, int batt_chg,
+ bt_bdaddr_t *bd_addr)
{
CHECK_BTHF_INIT();
- if (is_connected(NULL))
+ int idx = btif_hf_idx_by_bdaddr(bd_addr);
+
+ if (is_connected(bd_addr) && (idx != BTIF_HF_INVALID_IDX))
{
tBTA_AG_RES_DATA ag_res;
batt_chg, /* Battery level */
((num_held == 0) ? 0 : ((num_active == 0) ? 2 : 1))); /* Call held */
- BTA_AgResult (btif_hf_cb.handle, BTA_AG_CIND_RES, &ag_res);
+ BTA_AgResult (btif_hf_cb[idx].handle, BTA_AG_CIND_RES, &ag_res);
return BT_STATUS_SUCCESS;
}
** Returns bt_status_t
**
*******************************************************************************/
-static bt_status_t formatted_at_response(const char *rsp)
+static bt_status_t formatted_at_response(const char *rsp, bt_bdaddr_t *bd_addr)
{
CHECK_BTHF_INIT();
tBTA_AG_RES_DATA ag_res;
+ int idx = btif_hf_idx_by_bdaddr(bd_addr);
- if (is_connected(NULL))
+ if (is_connected(bd_addr) && (idx != BTIF_HF_INVALID_IDX))
{
/* Format the response and send */
memset (&ag_res, 0, sizeof (ag_res));
strncpy(ag_res.str, rsp, BTA_AG_AT_MAX_LEN);
- BTA_AgResult (btif_hf_cb.handle, BTA_AG_UNAT_RES, &ag_res);
+ BTA_AgResult (btif_hf_cb[idx].handle, BTA_AG_UNAT_RES, &ag_res);
return BT_STATUS_SUCCESS;
}
** Returns bt_status_t
**
*******************************************************************************/
-static bt_status_t at_response(bthf_at_response_t response_code, int error_code)
+static bt_status_t at_response(bthf_at_response_t response_code,
+ int error_code, bt_bdaddr_t *bd_addr)
{
CHECK_BTHF_INIT();
- if (is_connected(NULL))
+ int idx = btif_hf_idx_by_bdaddr(bd_addr);
+
+ if (is_connected(bd_addr) && (idx != BTIF_HF_INVALID_IDX))
{
send_at_result((response_code == BTHF_AT_RESPONSE_OK) ? BTA_AG_OK_DONE
- : BTA_AG_OK_ERROR, error_code);
+ : BTA_AG_OK_ERROR, error_code, idx);
return BT_STATUS_SUCCESS;
}
**
*******************************************************************************/
static bt_status_t clcc_response(int index, bthf_call_direction_t dir,
- bthf_call_state_t state, bthf_call_mode_t mode,
- bthf_call_mpty_type_t mpty, const char *number,
- bthf_call_addrtype_t type)
+ bthf_call_state_t state, bthf_call_mode_t mode,
+ bthf_call_mpty_type_t mpty, const char *number,
+ bthf_call_addrtype_t type, bt_bdaddr_t *bd_addr)
{
CHECK_BTHF_INIT();
- if (is_connected(NULL))
+ int idx = btif_hf_idx_by_bdaddr(bd_addr);
+
+ if (is_connected(bd_addr) && (idx != BTIF_HF_INVALID_IDX))
{
tBTA_AG_RES_DATA ag_res;
int xx;
sprintf (&ag_res.str[xx], ",\"%s\",%d", number, type);
}
}
- BTA_AgResult (btif_hf_cb.handle, BTA_AG_CLCC_RES, &ag_res);
+ BTA_AgResult (btif_hf_cb[idx].handle, BTA_AG_CLCC_RES, &ag_res);
return BT_STATUS_SUCCESS;
}
tBTA_AG_RES_DATA ag_res;
bt_status_t status = BT_STATUS_SUCCESS;
BOOLEAN activeCallUpdated = FALSE;
+ int idx, i;
+
+ /* Set idx to index of HF which sent ATA/BLDN else latest connected HF */
+ idx = (hf_idx == BTIF_HF_INVALID_IDX) ?
+ btif_hf_latest_connected_idx(): hf_idx;
+ BTIF_TRACE_DEBUG1("phone_state_change: idx = %d", idx);
- CHECK_BTHF_SLC_CONNECTED();
+ /* Check if SLC is connected */
+ if (btif_hf_check_if_slc_connected() != BT_STATUS_SUCCESS)
+ return BT_STATUS_NOT_READY;
- BTIF_TRACE_DEBUG6("phone_state_change: num_active=%d [prev: %d] num_held=%d[prev: %d]"\
- " call_setup=%s [prev: %s]", num_active, btif_hf_cb.num_active,
- num_held, btif_hf_cb.num_held,
- dump_hf_call_state(call_setup_state), dump_hf_call_state(btif_hf_cb.call_setup_state));
+ BTIF_TRACE_DEBUG6("phone_state_change: num_active=%d [prev: %d] num_held=%d[prev: %d]"
+ " call_setup=%s [prev: %s]", num_active, btif_hf_cb[idx].num_active,
+ num_held, btif_hf_cb[idx].num_held, dump_hf_call_state(call_setup_state),
+ dump_hf_call_state(btif_hf_cb[idx].call_setup_state));
/* if all indicators are 0, send end call and return */
if (num_active == 0 && num_held == 0 && call_setup_state == BTHF_CALL_STATE_IDLE)
{
BTIF_TRACE_DEBUG1("%s: Phone on hook", __FUNCTION__);
- /* record call termination timestamp if there was an active/held call or callsetup state > BTHF_CALL_STATE_IDLE */
- if ((btif_hf_cb.call_setup_state != BTHF_CALL_STATE_IDLE ) || (btif_hf_cb.num_active) ||(btif_hf_cb.num_held))
+ /* record call termination timestamp if there was an active/held call or
+ callsetup state > BTHF_CALL_STATE_IDLE */
+ if ((btif_hf_cb[idx].call_setup_state != BTHF_CALL_STATE_IDLE ) ||
+ (btif_hf_cb[idx].num_active) ||(btif_hf_cb[idx].num_held))
{
BTIF_TRACE_DEBUG1("%s: Record call termination timestamp", __FUNCTION__);
- clock_gettime(CLOCK_MONOTONIC, &btif_hf_cb.call_end_timestamp);
+ clock_gettime(CLOCK_MONOTONIC, &btif_hf_cb[0].call_end_timestamp);
}
BTA_AgResult (BTA_AG_HANDLE_ALL, BTA_AG_END_CALL_RES, NULL);
+ hf_idx = BTIF_HF_INVALID_IDX;
/* if held call was present, reset that as well */
- if (btif_hf_cb.num_held)
+ if (btif_hf_cb[idx].num_held)
send_indicator_update(BTA_AG_IND_CALLHELD, 0);
goto update_call_states;
** force the SCO to be setup. Handle this special case here prior to
** call setup handling
*/
- if ( (num_active == 1) && (btif_hf_cb.num_active == 0) && (btif_hf_cb.num_held == 0) &&
- (btif_hf_cb.call_setup_state == BTHF_CALL_STATE_IDLE) )
+ if ( (num_active == 1) && (btif_hf_cb[idx].num_active == 0) && (btif_hf_cb[idx].num_held == 0)
+ && (btif_hf_cb[idx].call_setup_state == BTHF_CALL_STATE_IDLE) )
{
BTIF_TRACE_DEBUG1("%s: Active call notification received without call setup update",
__FUNCTION__);
memset(&ag_res, 0, sizeof(tBTA_AG_RES_DATA));
- ag_res.audio_handle = btif_hf_cb.handle;
+ ag_res.audio_handle = btif_hf_cb[idx].handle;
res = BTA_AG_OUT_CALL_CONN_RES;
BTA_AgResult(BTA_AG_HANDLE_ALL, res, &ag_res);
activeCallUpdated = TRUE;
}
/* Ringing call changed? */
- if (call_setup_state != btif_hf_cb.call_setup_state)
+ if (call_setup_state != btif_hf_cb[idx].call_setup_state)
{
BTIF_TRACE_DEBUG3("%s: Call setup states changed. old: %s new: %s",
- __FUNCTION__, dump_hf_call_state(btif_hf_cb.call_setup_state),
+ __FUNCTION__, dump_hf_call_state(btif_hf_cb[idx].call_setup_state),
dump_hf_call_state(call_setup_state));
memset(&ag_res, 0, sizeof(tBTA_AG_RES_DATA));
{
case BTHF_CALL_STATE_IDLE:
{
- switch (btif_hf_cb.call_setup_state)
+ switch (btif_hf_cb[idx].call_setup_state)
{
case BTHF_CALL_STATE_INCOMING:
- if (num_active > btif_hf_cb.num_active)
+ if (num_active > btif_hf_cb[idx].num_active)
{
res = BTA_AG_IN_CALL_CONN_RES;
- ag_res.audio_handle = btif_hf_cb.handle;
+ ag_res.audio_handle = btif_hf_cb[idx].handle;
}
- else if (num_held > btif_hf_cb.num_held)
+ else if (num_held > btif_hf_cb[idx].num_held)
res = BTA_AG_IN_CALL_HELD_RES;
else
res = BTA_AG_CALL_CANCEL_RES;
break;
case BTHF_CALL_STATE_DIALING:
case BTHF_CALL_STATE_ALERTING:
- if (num_active > btif_hf_cb.num_active)
+ if (num_active > btif_hf_cb[idx].num_active)
{
ag_res.audio_handle = BTA_AG_HANDLE_SCO_NO_CHANGE;
res = BTA_AG_OUT_CALL_CONN_RES;
}
break;
case BTHF_CALL_STATE_DIALING:
- ag_res.audio_handle = btif_hf_cb.handle;
+ ag_res.audio_handle = btif_hf_cb[idx].handle;
res = BTA_AG_OUT_CALL_ORIG_RES;
break;
case BTHF_CALL_STATE_ALERTING:
/* if we went from idle->alert, force SCO setup here. dialing usually triggers it */
- if (btif_hf_cb.call_setup_state == BTHF_CALL_STATE_IDLE)
- ag_res.audio_handle = btif_hf_cb.handle;
+ if (btif_hf_cb[idx].call_setup_state == BTHF_CALL_STATE_IDLE)
+ ag_res.audio_handle = btif_hf_cb[idx].handle;
res = BTA_AG_OUT_CALL_ALERT_RES;
break;
default:
** https://www.bluetooth.org/errata/errata_view.cfm?errata_id=2043
** Handle call indicator change
**/
- if (!activeCallUpdated && ((num_active + num_held) != (btif_hf_cb.num_active + btif_hf_cb.num_held)) )
+ if (!activeCallUpdated && ((num_active + num_held) !=
+ (btif_hf_cb[idx].num_active + btif_hf_cb[idx].num_held)) )
{
- BTIF_TRACE_DEBUG3("%s: Active call states changed. old: %d new: %d", __FUNCTION__, btif_hf_cb.num_active, num_active);
+ BTIF_TRACE_DEBUG3("%s: Active call states changed. old: %d new: %d", __FUNCTION__, btif_hf_cb[idx].num_active, num_active);
send_indicator_update(BTA_AG_IND_CALL, ((num_active + num_held) > 0) ? 1 : 0);
}
/* Held Changed? */
- if (num_held != btif_hf_cb.num_held)
+ if (num_held != btif_hf_cb[idx].num_held)
{
- BTIF_TRACE_DEBUG3("%s: Held call states changed. old: %d new: %d", __FUNCTION__, btif_hf_cb.num_held, num_held);
+ BTIF_TRACE_DEBUG3("%s: Held call states changed. old: %d new: %d",
+ __FUNCTION__, btif_hf_cb[idx].num_held, num_held);
send_indicator_update(BTA_AG_IND_CALLHELD, ((num_held == 0) ? 0 : ((num_active == 0) ? 2 : 1)));
}
/* Calls Swapped? */
- if ( (call_setup_state == btif_hf_cb.call_setup_state) &&
+ if ( (call_setup_state == btif_hf_cb[idx].call_setup_state) &&
(num_active && num_held) &&
- (num_active == btif_hf_cb.num_active) &&
- (num_held == btif_hf_cb.num_held) )
+ (num_active == btif_hf_cb[idx].num_active) &&
+ (num_held == btif_hf_cb[idx].num_held) )
{
BTIF_TRACE_DEBUG1("%s: Calls swapped", __FUNCTION__);
send_indicator_update(BTA_AG_IND_CALLHELD, 1);
}
update_call_states:
- btif_hf_cb.num_active = num_active;
- btif_hf_cb.num_held = num_held;
- btif_hf_cb.call_setup_state = call_setup_state;
-
+ for (i = 0; i < btif_max_hf_clients; i++)
+ {
+ btif_hf_cb[i].num_active = num_active;
+ btif_hf_cb[i].num_held = num_held;
+ btif_hf_cb[i].call_setup_state = call_setup_state;
+ }
return status;
}
struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
- if (now.tv_sec < btif_hf_cb.call_end_timestamp.tv_sec + BTIF_HF_CALL_END_TIMEOUT)
+ if (now.tv_sec < btif_hf_cb[0].call_end_timestamp.tv_sec +
+ BTIF_HF_CALL_END_TIMEOUT)
{
return TRUE;
}
else
{
- btif_hf_cb.call_end_timestamp.tv_sec = 0;
+ btif_hf_cb[0].call_end_timestamp.tv_sec = 0;
return FALSE;
}
}
bt_status_t btif_hf_execute_service(BOOLEAN b_enable)
{
char * p_service_names[] = BTIF_HF_SERVICE_NAMES;
+ int i;
if (b_enable)
{
/* Enable and register with BTA-AG */
BTA_AgEnable (BTA_AG_PARSE, bte_hf_evt);
- BTA_AgRegister(BTIF_HF_SERVICES, BTIF_HF_SECURITY, BTIF_HF_FEATURES,
- p_service_names, BTIF_HF_ID_1);
+ for (i = 0; i < btif_max_hf_clients; i++)
+ {
+ BTA_AgRegister(BTIF_HF_SERVICES, BTIF_HF_SECURITY,
+ BTIF_HF_FEATURES, p_service_names, bthf_hf_id[i]);
+ }
}
else {
/* De-register AG */
- BTA_AgDeregister(btif_hf_cb.handle);
+ for (i = 0; i < btif_max_hf_clients; i++)
+ {
+ BTA_AgDeregister(btif_hf_cb[i].handle);
+ }
/* Disable AG */
BTA_AgDisable();
}