OSDN Git Service

Add support for Multi-HFP devices
authorNitin Srivastava <nitinsr@codeaurora.org>
Fri, 14 Mar 2014 23:19:58 +0000 (16:19 -0700)
committerMatthew Xie <mattx@google.com>
Tue, 6 May 2014 08:14:24 +0000 (01:14 -0700)
1. Add multi headset support in stack.
2. Each HS will be associated with unique CB in BTIF
and also corresponding SCB in BTA.
3. Upstream event callbacks will be sent to
specific HS based on BD_ADDR.
4. Similiarly all commands to BTIF will be for
specific HS.

Change-Id: I0dc6b1b54f16244b802d818ae60944877a41d020

bta/ag/bta_ag_act.c
bta/ag/bta_ag_cmd.c
bta/ag/bta_ag_main.c
bta/include/bta_ag_api.h
btif/src/btif_hf.c
include/bt_target.h

index 11fc85c..cedbb3d 100644 (file)
@@ -406,7 +406,7 @@ void bta_ag_rfc_fail(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
 *******************************************************************************/
 void bta_ag_rfc_close(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
 {
-    tBTA_AG_HDR    close;
+    tBTA_AG_CLOSE    close;
     tBTA_SERVICE_MASK services;
     int i, num_active_conn = 0;
     UNUSED(p_data);
@@ -436,13 +436,14 @@ void bta_ag_rfc_close(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
     bta_sys_stop_timer(&p_scb->cn_timer);
 #endif
 
-    close.handle = bta_ag_scb_to_idx(p_scb);
-    close.app_id = p_scb->app_id;
+    close.hdr.handle = bta_ag_scb_to_idx(p_scb);
+    close.hdr.app_id = p_scb->app_id;
+    bdcpy(close.bd_addr, p_scb->peer_addr);
 
     bta_sys_conn_close(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
 
     /* call close call-out */
-    bta_ag_co_data_close(close.handle);
+    bta_ag_co_data_close(close.hdr.handle);
 
     /* call close cback */
     (*bta_ag_cb.p_cback)(BTA_AG_CLOSE_EVT, (tBTA_AG *) &close);
@@ -819,6 +820,7 @@ void bta_ag_svc_conn_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
         evt.hdr.handle = bta_ag_scb_to_idx(p_scb);
         evt.hdr.app_id = p_scb->app_id;
         evt.peer_feat = p_scb->peer_features;
+        bdcpy(evt.bd_addr, p_scb->peer_addr);
 #if (BTM_WBS_INCLUDED == TRUE )
         evt.peer_codec  = p_scb->peer_codecs;
 #endif
index 54cd4d3..073deeb 100644 (file)
@@ -867,6 +867,7 @@ void bta_ag_at_hfp_cback(tBTA_AG_SCB *p_scb, UINT16 cmd, UINT8 arg_type,
     val.hdr.handle = bta_ag_scb_to_idx(p_scb);
     val.hdr.app_id = p_scb->app_id;
     val.num = int_arg;
+    bdcpy(val.bd_addr, p_scb->peer_addr);
     BCM_STRNCPY_S(val.str, sizeof(val.str), p_arg, BTA_AG_AT_MAX_LEN);
     val.str[BTA_AG_AT_MAX_LEN] = 0;
 
index bae992b..712e50e 100644 (file)
@@ -753,6 +753,7 @@ static void bta_ag_api_register(tBTA_AG_DATA *p_data)
     /* allocate an scb */
     if ((p_scb = bta_ag_scb_alloc()) != NULL)
     {
+        APPL_TRACE_DEBUG1("bta_ag_api_register: p_scb 0x%08x ", p_scb);
         bta_ag_sm_execute(p_scb, p_data->hdr.event, p_data);
     }
     else
@@ -781,6 +782,7 @@ static void bta_ag_api_result(tBTA_AG_DATA *p_data)
     {
         if ((p_scb = bta_ag_scb_by_idx(p_data->hdr.layer_specific)) != NULL)
         {
+            APPL_TRACE_DEBUG1("bta_ag_api_result: p_scb 0x%08x ", p_scb);
             bta_ag_sm_execute(p_scb, BTA_AG_API_RESULT_EVT, p_data);
         }
     }
@@ -788,8 +790,9 @@ static void bta_ag_api_result(tBTA_AG_DATA *p_data)
     {
         for (i = 0, p_scb = &bta_ag_cb.scb[0]; i < BTA_AG_NUM_SCB; i++, p_scb++)
         {
-            if (p_scb->in_use)
+            if (p_scb->in_use && p_scb->svc_conn)
             {
+                APPL_TRACE_DEBUG1("bta_ag_api_result p_scb 0x%08x ", p_scb);
                 bta_ag_sm_execute(p_scb, BTA_AG_API_RESULT_EVT, p_data);
             }
         }
@@ -879,6 +882,7 @@ BOOLEAN bta_ag_hdl_event(BT_HDR *p_msg)
 {
     tBTA_AG_SCB *p_scb;
 
+    APPL_TRACE_DEBUG1("bta_ag_hdl_event: Event 0x%04x ", p_msg->event);
     switch (p_msg->event)
     {
         /* handle enable event */
@@ -905,6 +909,7 @@ BOOLEAN bta_ag_hdl_event(BT_HDR *p_msg)
         default:
             if ((p_scb = bta_ag_scb_by_idx(p_msg->layer_specific)) != NULL)
             {
+                APPL_TRACE_DEBUG1("bta_ag_hdl_event: p_scb 0x%08x ", p_scb);
                 bta_ag_sm_execute(p_scb, p_msg->event, (tBTA_AG_DATA *) p_msg);
             }
             break;
index f16687c..85f82a0 100644 (file)
@@ -275,11 +275,19 @@ typedef struct
     tBTA_AG_STATUS      status;
 } tBTA_AG_OPEN;
 
+/* data associated with BTA_AG_CLOSE_EVT */
+typedef struct
+{
+    tBTA_AG_HDR         hdr;
+    BD_ADDR             bd_addr;
+} tBTA_AG_CLOSE;
+
 /* data associated with BTA_AG_CONN_EVT */
 typedef struct
 {
     tBTA_AG_HDR         hdr;
     tBTA_AG_PEER_FEAT   peer_feat;
+    BD_ADDR             bd_addr;
     tBTA_AG_PEER_CODEC  peer_codec;
 } tBTA_AG_CONN;
 
@@ -287,6 +295,7 @@ typedef struct
 typedef struct
 {
     tBTA_AG_HDR         hdr;
+    BD_ADDR             bd_addr;
     char                str[BTA_AG_AT_MAX_LEN+1];
     UINT16              num;
     UINT8               idx;    /* call number used by CLCC and CHLD */
@@ -298,6 +307,7 @@ typedef union
     tBTA_AG_HDR         hdr;
     tBTA_AG_REGISTER    reg;
     tBTA_AG_OPEN        open;
+    tBTA_AG_CLOSE       close;
     tBTA_AG_CONN        conn;
     tBTA_AG_VAL         val;
 } tBTA_AG;
index b4ade0d..418156d 100644 (file)
                              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)\
     {\
@@ -120,10 +142,11 @@ typedef struct _btif_hf_cb
     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];
 
 
 /************************************************************************************
@@ -149,15 +172,41 @@ static btif_hf_cb_t btif_hf_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
@@ -187,7 +236,7 @@ static UINT8 callstate_to_callsetup(bthf_call_state_t call_state)
 ** 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));
@@ -198,7 +247,7 @@ static void send_at_result(UINT8 ok_flag, UINT16 errcode)
         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);
 }
 
 /*******************************************************************************
@@ -221,12 +270,77 @@ static void send_indicator_update (UINT16 indicator, UINT16 value)
     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)
@@ -252,6 +366,8 @@ static void btif_hf_upstreams_evt(UINT16 event, char* p_param)
 {
     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));
 
@@ -262,43 +378,54 @@ static void btif_hf_upstreams_evt(UINT16 event, char* p_param)
             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
             */
@@ -306,60 +433,79 @@ static void btif_hf_upstreams_evt(UINT16 event, char* p_param)
             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 */
@@ -367,35 +513,40 @@ static void btif_hf_upstreams_evt(UINT16 event, char* p_param)
             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;
 
 
@@ -452,14 +603,14 @@ static void bte_hf_evt(tBTA_AG_EVT event, tBTA_AG *p_data)
 *******************************************************************************/
 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:
         {
@@ -479,9 +630,10 @@ static void btif_in_hf_generic_evt(UINT16 event, char *p_param)
 ** 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;
 
@@ -495,8 +647,13 @@ static bt_status_t init( bthf_callbacks_t* 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;
 }
@@ -512,12 +669,26 @@ static bt_status_t init( bthf_callbacks_t* callbacks )
 *******************************************************************************/
 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;
     }
@@ -544,9 +715,11 @@ static bt_status_t disconnect( bt_bdaddr_t *bd_addr )
 {
     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;
     }
 
@@ -566,9 +739,11 @@ static bt_status_t connect_audio( bt_bdaddr_t *bd_addr )
 {
     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,
@@ -592,9 +767,11 @@ static bt_status_t disconnect_audio( bt_bdaddr_t *bd_addr )
 {
     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;
     }
 
@@ -610,17 +787,20 @@ static bt_status_t disconnect_audio( bt_bdaddr_t *bd_addr )
 ** 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;
         }
@@ -642,18 +822,20 @@ static bt_status_t start_voice_recognition()
 ** 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;
         }
@@ -675,16 +857,19 @@ static bt_status_t stop_voice_recognition()
 ** 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;
@@ -733,11 +918,13 @@ static bt_status_t device_status_notification(bthf_network_state_t ntk_state,
 ** 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;
 
@@ -745,7 +932,7 @@ static bt_status_t cops_response(const char *cops)
         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;
@@ -762,11 +949,14 @@ static bt_status_t cops_response(const char *cops)
 *******************************************************************************/
 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;
 
@@ -783,7 +973,7 @@ static bt_status_t cind_response(int svc, int num_active, int num_held,
                 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;
     }
@@ -800,17 +990,18 @@ static bt_status_t cind_response(int svc, int num_active, int num_held,
 ** 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;
     }
@@ -827,14 +1018,17 @@ static bt_status_t formatted_at_response(const char *rsp)
 ** 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;
     }
 
@@ -854,13 +1048,15 @@ static bt_status_t at_response(bthf_at_response_t response_code, int error_code)
 **
 *******************************************************************************/
 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;
@@ -887,7 +1083,7 @@ static bt_status_t clcc_response(int index, bthf_call_direction_t dir,
                     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;
     }
@@ -913,29 +1109,40 @@ static bt_status_t phone_state_change(int num_active, int num_held, bthf_call_st
     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;
@@ -952,24 +1159,24 @@ static bt_status_t phone_state_change(int num_active, int num_held, bthf_call_st
     ** 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));
 
@@ -977,22 +1184,22 @@ static bt_status_t phone_state_change(int num_active, int num_held, bthf_call_st
         {
             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;
@@ -1026,13 +1233,13 @@ static bt_status_t phone_state_change(int num_active, int num_held, bthf_call_st
                 }
                 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:
@@ -1061,34 +1268,38 @@ static bt_status_t phone_state_change(int num_active, int num_held, bthf_call_st
     ** 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;
 }
 
@@ -1107,13 +1318,14 @@ BOOLEAN btif_hf_call_terminated_recently()
       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;
       }
 }
@@ -1170,16 +1382,23 @@ static const bthf_interface_t bthfInterface = {
 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();
      }
index 5ac668c..c81cbe5 100644 (file)
@@ -1026,7 +1026,7 @@ and USER_HW_DISABLE_API macros */
 
 /* The number of SCO links. */
 #ifndef BTM_MAX_SCO_LINKS
-#define BTM_MAX_SCO_LINKS           2
+#define BTM_MAX_SCO_LINKS           3
 #endif
 
 /* The preferred type of SCO links (2-eSCO, 0-SCO). */