Submitted on behalf of 3rd party copied from external/bluetooth/bluedroid

Initial commit for HFP Client

Change-Id: I26b7d49b76ab28b019314ddb514e8f46b3bc4772
diff --git a/bta/hf_client/bta_hf_client_act.c b/bta/hf_client/bta_hf_client_act.c
new file mode 100644
index 0000000..11fc85c
--- /dev/null
+++ b/bta/hf_client/bta_hf_client_act.c
@@ -0,0 +1,876 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2003-2012 Broadcom Corporation
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *  This file contains action functions for the audio gateway.
+ *
+ ******************************************************************************/
+
+#include "bta_api.h"
+#include "bd.h"
+#include "bta_sys.h"
+#include "bta_ag_api.h"
+#include "bta_ag_co.h"
+#include "bta_ag_int.h"
+#include "port_api.h"
+#include "utl.h"
+#include <string.h>
+#include "bta_dm_int.h"
+#include "l2c_api.h"
+
+/*****************************************************************************
+**  Constants
+*****************************************************************************/
+
+/* maximum length of data to read from RFCOMM */
+#define BTA_AG_RFC_READ_MAX     512
+
+/* maximum AT command length */
+#define BTA_AG_CMD_MAX          512
+
+const UINT16 bta_ag_uuid[BTA_AG_NUM_IDX] =
+{
+    UUID_SERVCLASS_HEADSET_AUDIO_GATEWAY,
+    UUID_SERVCLASS_AG_HANDSFREE
+};
+
+const UINT8 bta_ag_sec_id[BTA_AG_NUM_IDX] =
+{
+    BTM_SEC_SERVICE_HEADSET_AG,
+    BTM_SEC_SERVICE_AG_HANDSFREE
+};
+
+const tBTA_SERVICE_ID bta_ag_svc_id[BTA_AG_NUM_IDX] =
+{
+    BTA_HSP_SERVICE_ID,
+    BTA_HFP_SERVICE_ID
+};
+
+const tBTA_SERVICE_MASK bta_ag_svc_mask[BTA_AG_NUM_IDX] =
+{
+    BTA_HSP_SERVICE_MASK,
+    BTA_HFP_SERVICE_MASK
+};
+
+typedef void (*tBTA_AG_ATCMD_CBACK)(tBTA_AG_SCB *p_scb, UINT16 cmd, UINT8 arg_type,
+                                    char *p_arg, INT16 int_arg);
+
+const tBTA_AG_ATCMD_CBACK bta_ag_at_cback_tbl[BTA_AG_NUM_IDX] =
+{
+    bta_ag_at_hsp_cback,
+    bta_ag_at_hfp_cback
+};
+
+/*******************************************************************************
+**
+** Function         bta_ag_cback_open
+**
+** Description      Send open callback event to application.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+static void bta_ag_cback_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data, tBTA_AG_STATUS status)
+{
+    tBTA_AG_OPEN    open;
+
+    /* call app callback with open event */
+    open.hdr.handle = bta_ag_scb_to_idx(p_scb);
+    open.hdr.app_id = p_scb->app_id;
+    open.status = status;
+    open.service_id = bta_ag_svc_id[p_scb->conn_service];
+    if(p_data)
+    {
+        /* if p_data is provided then we need to pick the bd address from the open api structure */
+        bdcpy(open.bd_addr, p_data->api_open.bd_addr);
+    }
+    else
+    {
+        bdcpy(open.bd_addr, p_scb->peer_addr);
+    }
+
+    (*bta_ag_cb.p_cback)(BTA_AG_OPEN_EVT, (tBTA_AG *) &open);
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_register
+**
+** Description      This function initializes values of the AG cb and sets up
+**                  the SDP record for the services.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_register(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+    tBTA_AG_REGISTER reg;
+
+    /* initialize control block */
+    p_scb->reg_services = p_data->api_register.services;
+    p_scb->serv_sec_mask = p_data->api_register.sec_mask;
+    p_scb->features = p_data->api_register.features;
+    p_scb->app_id = p_data->api_register.app_id;
+
+    /* create SDP records */
+    bta_ag_create_records(p_scb, p_data);
+
+    /* start RFCOMM servers */
+    bta_ag_start_servers(p_scb, p_scb->reg_services);
+
+    /* call app callback with register event */
+    reg.hdr.handle = bta_ag_scb_to_idx(p_scb);
+    reg.hdr.app_id = p_scb->app_id;
+    reg.status = BTA_AG_SUCCESS;
+    (*bta_ag_cb.p_cback)(BTA_AG_REGISTER_EVT, (tBTA_AG *) &reg);
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_deregister
+**
+** Description      This function removes the sdp records, closes the RFCOMM
+**                  servers, and deallocates the service control block.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_deregister(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+    /* set dealloc */
+    p_scb->dealloc = TRUE;
+
+    /* remove sdp records */
+    bta_ag_del_records(p_scb, p_data);
+
+    /* remove rfcomm servers */
+    bta_ag_close_servers(p_scb, p_scb->reg_services);
+
+    /* dealloc */
+    bta_ag_scb_dealloc(p_scb);
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_start_dereg
+**
+** Description      Start a deregister event.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_start_dereg(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+    /* set dealloc */
+    p_scb->dealloc = TRUE;
+
+    /* remove sdp records */
+    bta_ag_del_records(p_scb, p_data);
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_start_open
+**
+** Description      This starts an AG open.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_start_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+    BD_ADDR pending_bd_addr;
+
+    /* store parameters */
+    if (p_data)
+    {
+        bdcpy(p_scb->peer_addr, p_data->api_open.bd_addr);
+        p_scb->open_services = p_data->api_open.services;
+        p_scb->cli_sec_mask = p_data->api_open.sec_mask;
+    }
+
+    /* Check if RFCOMM has any incoming connection to avoid collision. */
+    if (PORT_IsOpening (pending_bd_addr))
+    {
+        /* Let the incoming connection goes through.                        */
+        /* Issue collision for this scb for now.                            */
+        /* We will decide what to do when we find incoming connetion later. */
+        bta_ag_collision_cback (0, BTA_ID_AG, 0, p_scb->peer_addr);
+        return;
+    }
+
+    /* close servers */
+    bta_ag_close_servers(p_scb, p_scb->reg_services);
+
+    /* set role */
+    p_scb->role = BTA_AG_INT;
+
+    /* do service search */
+    bta_ag_do_disc(p_scb, p_scb->open_services);
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_disc_int_res
+**
+** Description      This function handles a discovery result when initiator.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_disc_int_res(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+    UINT16 event = BTA_AG_DISC_FAIL_EVT;
+
+    APPL_TRACE_DEBUG1 ("bta_ag_disc_int_res: Status: %d", p_data->disc_result.status);
+
+    /* if found service */
+    if (p_data->disc_result.status == SDP_SUCCESS ||
+        p_data->disc_result.status == SDP_DB_FULL)
+    {
+        /* get attributes */
+        if (bta_ag_sdp_find_attr(p_scb, p_scb->open_services))
+        {
+            /* set connected service */
+            p_scb->conn_service = bta_ag_service_to_idx(p_scb->open_services);
+
+            /* send ourselves sdp ok event */
+            event = BTA_AG_DISC_OK_EVT;
+        }
+    }
+
+    /* free discovery db */
+    bta_ag_free_db(p_scb, p_data);
+
+    /* if service not found check if we should search for other service */
+    if ((event == BTA_AG_DISC_FAIL_EVT) &&
+        (p_data->disc_result.status == SDP_SUCCESS ||
+         p_data->disc_result.status == SDP_DB_FULL ||
+         p_data->disc_result.status == SDP_NO_RECS_MATCH))
+    {
+        if ((p_scb->open_services & BTA_HFP_SERVICE_MASK) &&
+            (p_scb->open_services & BTA_HSP_SERVICE_MASK))
+        {
+            /* search for HSP */
+            p_scb->open_services &= ~BTA_HFP_SERVICE_MASK;
+            bta_ag_do_disc(p_scb, p_scb->open_services);
+        }
+        else if ((p_scb->open_services & BTA_HSP_SERVICE_MASK) &&
+                 (p_scb->hsp_version == HSP_VERSION_1_2))
+        {
+            /* search for UUID_SERVCLASS_HEADSET for HSP 1.0 device */
+            p_scb->hsp_version = HSP_VERSION_1_0;
+            bta_ag_do_disc(p_scb, p_scb->open_services);
+        }
+        else
+        {
+            /* send ourselves sdp ok/fail event */
+            bta_ag_sm_execute(p_scb, event, p_data);
+        }
+    }
+    else
+    {
+        /* send ourselves sdp ok/fail event */
+        bta_ag_sm_execute(p_scb, event, p_data);
+    }
+
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_disc_acp_res
+**
+** Description      This function handles a discovery result when acceptor.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_disc_acp_res(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+    /* if found service */
+    if (p_data->disc_result.status == SDP_SUCCESS ||
+        p_data->disc_result.status == SDP_DB_FULL)
+    {
+        /* get attributes */
+        bta_ag_sdp_find_attr(p_scb, bta_ag_svc_mask[p_scb->conn_service]);
+    }
+
+    /* free discovery db */
+    bta_ag_free_db(p_scb, p_data);
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_disc_fail
+**
+** Description      This function handles a discovery failure.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_disc_fail(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+    UNUSED(p_data);
+
+    /* reopen registered servers */
+    bta_ag_start_servers(p_scb, p_scb->reg_services);
+
+    /* reinitialize stuff */
+
+    /* call open cback w. failure */
+    bta_ag_cback_open(p_scb, NULL, BTA_AG_FAIL_SDP);
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_open_fail
+**
+** Description      open connection failed.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_open_fail(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+    /* call open cback w. failure */
+    bta_ag_cback_open(p_scb, p_data, BTA_AG_FAIL_RESOURCES);
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_rfc_fail
+**
+** Description      RFCOMM connection failed.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_rfc_fail(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+    UNUSED(p_data);
+
+    /* reinitialize stuff */
+    p_scb->conn_handle = 0;
+    p_scb->conn_service = 0;
+    p_scb->peer_features = 0;
+#if (BTM_WBS_INCLUDED == TRUE )
+    p_scb->peer_codecs = BTA_AG_CODEC_NONE;
+    p_scb->sco_codec = BTA_AG_CODEC_NONE;
+#endif
+    p_scb->role = 0;
+    p_scb->svc_conn = FALSE;
+    p_scb->hsp_version = HSP_VERSION_1_2;
+
+    /* reopen registered servers */
+    bta_ag_start_servers(p_scb, p_scb->reg_services);
+
+    /* call open cback w. failure */
+    bta_ag_cback_open(p_scb, NULL, BTA_AG_FAIL_RFCOMM);
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_rfc_close
+**
+** Description      RFCOMM connection closed.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_rfc_close(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+    tBTA_AG_HDR    close;
+    tBTA_SERVICE_MASK services;
+    int i, num_active_conn = 0;
+    UNUSED(p_data);
+
+#ifdef  _WIN32_WCE
+    /* The BTE RFCOMM automatically removes the connection when closed, but BTW does not */
+    if (p_scb->conn_handle != 0)
+        RFCOMM_RemoveConnection (p_scb->conn_handle);
+#endif
+
+    /* reinitialize stuff */
+    p_scb->conn_service = 0;
+    p_scb->peer_features = 0;
+#if (BTM_WBS_INCLUDED == TRUE )
+    p_scb->peer_codecs = BTA_AG_CODEC_NONE;
+    p_scb->sco_codec = BTA_AG_CODEC_NONE;
+#endif
+    p_scb->role = 0;
+    p_scb->post_sco = BTA_AG_POST_SCO_NONE;
+    p_scb->svc_conn = FALSE;
+    p_scb->hsp_version = HSP_VERSION_1_2;
+    bta_ag_at_reinit(&p_scb->at_cb);
+
+    /* stop timers */
+    bta_sys_stop_timer(&p_scb->act_timer);
+#if (BTM_WBS_INCLUDED == TRUE)
+    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;
+
+    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);
+
+    /* call close cback */
+    (*bta_ag_cb.p_cback)(BTA_AG_CLOSE_EVT, (tBTA_AG *) &close);
+
+    /* if not deregistering (deallocating) reopen registered servers */
+    if (p_scb->dealloc == FALSE)
+    {
+        /* Clear peer bd_addr so instance can be reused */
+        bdcpy(p_scb->peer_addr, bd_addr_null);
+
+        /* start only unopened server */
+        services = p_scb->reg_services;
+        for (i = 0; i < BTA_AG_NUM_IDX && services != 0; i++)
+        {
+            if(p_scb->serv_handle[i])
+                services &= ~((tBTA_SERVICE_MASK)1 << (BTA_HSP_SERVICE_ID + i));
+        }
+        bta_ag_start_servers(p_scb, services);
+
+        p_scb->conn_handle = 0;
+
+        /* Make sure SCO state is BTA_AG_SCO_SHUTDOWN_ST */
+        bta_ag_sco_shutdown(p_scb, NULL);
+
+        /* Check if all the SLCs are down */
+        for (i = 0; i < BTA_AG_NUM_SCB; i++)
+        {
+            if (bta_ag_cb.scb[i].in_use && bta_ag_cb.scb[i].svc_conn)
+                num_active_conn++;
+        }
+
+        if(!num_active_conn)
+        {
+            bta_sys_sco_unuse(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+        }
+
+    }
+    /* else close port and deallocate scb */
+    else
+    {
+        RFCOMM_RemoveServer(p_scb->conn_handle);
+        bta_ag_scb_dealloc(p_scb);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_rfc_open
+**
+** Description      Handle RFCOMM channel open.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_rfc_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+    /* initialize AT feature variables */
+    p_scb->clip_enabled = FALSE;
+    p_scb->ccwa_enabled = FALSE;
+    p_scb->cmer_enabled = FALSE;
+    p_scb->cmee_enabled = FALSE;
+    p_scb->inband_enabled = ((p_scb->features & BTA_AG_FEAT_INBAND) == BTA_AG_FEAT_INBAND);
+
+    /* set up AT command interpreter */
+    p_scb->at_cb.p_at_tbl = (tBTA_AG_AT_CMD *) bta_ag_at_tbl[p_scb->conn_service];
+    p_scb->at_cb.p_cmd_cback = (tBTA_AG_AT_CMD_CBACK *) bta_ag_at_cback_tbl[p_scb->conn_service];
+    p_scb->at_cb.p_err_cback = (tBTA_AG_AT_ERR_CBACK *) bta_ag_at_err_cback;
+    p_scb->at_cb.p_user = p_scb;
+    p_scb->at_cb.cmd_max_len = BTA_AG_CMD_MAX;
+    bta_ag_at_init(&p_scb->at_cb);
+
+    /* call app open call-out */
+    bta_ag_co_data_open(bta_ag_scb_to_idx(p_scb), bta_ag_svc_id[p_scb->conn_service]);
+
+    bta_sys_conn_open(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+
+    bta_ag_cback_open(p_scb, NULL, BTA_AG_SUCCESS);
+
+    if (p_scb->conn_service == BTA_AG_HFP)
+    {
+        /* if hfp start timer for service level conn */
+        bta_sys_start_timer(&p_scb->act_timer, BTA_AG_SVC_TOUT_EVT, p_bta_ag_cfg->conn_tout);
+    }
+    else
+    {
+        /* else service level conn is open */
+        bta_ag_svc_conn_open(p_scb, p_data);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_rfc_acp_open
+**
+** Description      Handle RFCOMM channel open when accepting connection.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_rfc_acp_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+    UINT16          lcid;
+    int             i;
+    tBTA_AG_SCB     *ag_scb, *other_scb;
+    BD_ADDR         dev_addr;
+    int             status;
+
+    /* set role */
+    p_scb->role = BTA_AG_ACP;
+
+    APPL_TRACE_DEBUG2 ("bta_ag_rfc_acp_open: serv_handle0 = %d serv_handle1 = %d",
+                       p_scb->serv_handle[0], p_scb->serv_handle[1]);
+
+    /* get bd addr of peer */
+    if (PORT_SUCCESS != (status=PORT_CheckConnection(p_data->rfc.port_handle, dev_addr, &lcid)))
+    {
+        APPL_TRACE_DEBUG1 ("bta_ag_rfc_acp_open error PORT_CheckConnection returned status %d", status);
+    }
+
+    /* Collision Handling */
+    for (i = 0, ag_scb = &bta_ag_cb.scb[0]; i < BTA_AG_NUM_SCB; i++, ag_scb++)
+    {
+        if ((ag_scb->in_use) && (ag_scb->colli_tmr_on))
+        {
+            /* stop collision timer */
+            ag_scb->colli_tmr_on = FALSE;
+            bta_sys_stop_timer (&ag_scb->colli_timer);
+
+            if (bdcmp (dev_addr, ag_scb->peer_addr) == 0)
+            {
+                /* If incoming and outgoing device are same, nothing more to do.            */
+                /* Outgoing conn will be aborted because we have successful incoming conn.  */
+            }
+            else
+            {
+                /* Resume outgoing connection. */
+                other_scb = bta_ag_get_other_idle_scb (p_scb);
+                if (other_scb)
+                {
+                    bdcpy(other_scb->peer_addr, ag_scb->peer_addr);
+                    other_scb->open_services = ag_scb->open_services;
+                    other_scb->cli_sec_mask = ag_scb->cli_sec_mask;
+
+                    bta_ag_resume_open (other_scb);
+                }
+            }
+
+            break;
+        }
+    }
+
+    bdcpy (p_scb->peer_addr, dev_addr);
+
+    /* determine connected service from port handle */
+    for (i = 0; i < BTA_AG_NUM_IDX; i++)
+    {
+        APPL_TRACE_DEBUG3 ("bta_ag_rfc_acp_open: i = %d serv_handle = %d port_handle = %d",
+                           i, p_scb->serv_handle[i], p_data->rfc.port_handle);
+
+        if (p_scb->serv_handle[i] == p_data->rfc.port_handle)
+        {
+            p_scb->conn_service = i;
+            p_scb->conn_handle = p_data->rfc.port_handle;
+            break;
+        }
+    }
+
+    APPL_TRACE_DEBUG2 ("bta_ag_rfc_acp_open: conn_service = %d conn_handle = %d",
+                       p_scb->conn_service, p_scb->conn_handle);
+
+    /* close any unopened server */
+    bta_ag_close_servers(p_scb, (p_scb->reg_services & ~bta_ag_svc_mask[p_scb->conn_service]));
+
+    /* do service discovery to get features */
+    bta_ag_do_disc(p_scb, bta_ag_svc_mask[p_scb->conn_service]);
+
+    /* continue with common open processing */
+    bta_ag_rfc_open(p_scb, p_data);
+
+
+
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_rfc_data
+**
+** Description      Read and process data from RFCOMM.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_rfc_data(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+    UINT16  len;
+    char    buf[BTA_AG_RFC_READ_MAX];
+    UNUSED(p_data);
+
+    memset(buf, 0, BTA_AG_RFC_READ_MAX);
+
+    /* do the following */
+    for(;;)
+    {
+        /* read data from rfcomm; if bad status, we're done */
+        if (PORT_ReadData(p_scb->conn_handle, buf, BTA_AG_RFC_READ_MAX, &len) != PORT_SUCCESS)
+        {
+            break;
+        }
+
+        /* if no data, we're done */
+        if (len == 0)
+        {
+            break;
+        }
+
+        /* run AT command interpreter on data */
+        bta_ag_at_parse(&p_scb->at_cb, buf, len);
+
+        /* no more data to read, we're done */
+        if (len < BTA_AG_RFC_READ_MAX)
+        {
+            break;
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_start_close
+**
+** Description      Start the process of closing SCO and RFCOMM connection.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_start_close(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+    /* Take the link out of sniff and set L2C idle time to 0 */
+    bta_dm_pm_active(p_scb->peer_addr);
+    L2CA_SetIdleTimeoutByBdAddr(p_scb->peer_addr, 0);
+
+    /* if SCO is open close SCO and wait on RFCOMM close */
+    if (bta_ag_sco_is_open(p_scb))
+    {
+        p_scb->post_sco = BTA_AG_POST_SCO_CLOSE_RFC;
+    }
+    else
+    {
+        p_scb->post_sco = BTA_AG_POST_SCO_NONE;
+        bta_ag_rfc_do_close(p_scb, p_data);
+    }
+
+    /* always do SCO shutdown to handle all SCO corner cases */
+    bta_ag_sco_shutdown(p_scb, p_data);
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_post_sco_open
+**
+** Description      Perform post-SCO open action, if any
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_post_sco_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+    switch (p_scb->post_sco)
+    {
+        case BTA_AG_POST_SCO_RING:
+            bta_ag_send_ring(p_scb, p_data);
+            p_scb->post_sco = BTA_AG_POST_SCO_NONE;
+            break;
+
+        case BTA_AG_POST_SCO_CALL_CONN:
+            bta_ag_send_call_inds(p_scb, BTA_AG_IN_CALL_CONN_RES);
+            p_scb->post_sco = BTA_AG_POST_SCO_NONE;
+            break;
+
+        default:
+            break;
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_post_sco_close
+**
+** Description      Perform post-SCO close action, if any
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_post_sco_close(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+    switch (p_scb->post_sco)
+    {
+        case BTA_AG_POST_SCO_CLOSE_RFC:
+            bta_ag_rfc_do_close(p_scb, p_data);
+            p_scb->post_sco = BTA_AG_POST_SCO_NONE;
+            break;
+
+        case BTA_AG_POST_SCO_CALL_CONN:
+            bta_ag_send_call_inds(p_scb, BTA_AG_IN_CALL_CONN_RES);
+            p_scb->post_sco = BTA_AG_POST_SCO_NONE;
+            break;
+
+        case BTA_AG_POST_SCO_CALL_ORIG:
+            bta_ag_send_call_inds(p_scb, BTA_AG_OUT_CALL_ORIG_RES);
+            p_scb->post_sco = BTA_AG_POST_SCO_NONE;
+            break;
+
+        case BTA_AG_POST_SCO_CALL_END:
+            bta_ag_send_call_inds(p_scb, BTA_AG_END_CALL_RES);
+            p_scb->post_sco = BTA_AG_POST_SCO_NONE;
+            break;
+
+        case BTA_AG_POST_SCO_CALL_END_INCALL:
+            bta_ag_send_call_inds(p_scb, BTA_AG_END_CALL_RES);
+
+            /* Sending callsetup IND and Ring were defered to after SCO close. */
+            bta_ag_send_call_inds(p_scb, BTA_AG_IN_CALL_RES);
+
+            if (bta_ag_inband_enabled(p_scb) && !(p_scb->features & BTA_AG_FEAT_NOSCO))
+            {
+                p_scb->post_sco = BTA_AG_POST_SCO_RING;
+                bta_ag_sco_open(p_scb, p_data);
+            }
+            else
+            {
+                p_scb->post_sco = BTA_AG_POST_SCO_NONE;
+                bta_ag_send_ring(p_scb, p_data);
+            }
+            break;
+
+        default:
+            break;
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_svc_conn_open
+**
+** Description      Service level connection opened
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_svc_conn_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+    tBTA_AG_CONN evt;
+    UNUSED(p_data);
+
+    if (!p_scb->svc_conn)
+    {
+        /* set state variable */
+        p_scb->svc_conn = TRUE;
+
+        /* Clear AT+BIA mask from previous SLC if any. */
+        p_scb->bia_masked_out = 0;
+
+        /* stop timer */
+        bta_sys_stop_timer(&p_scb->act_timer);
+
+        /* call callback */
+        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;
+#if (BTM_WBS_INCLUDED == TRUE )
+        evt.peer_codec  = p_scb->peer_codecs;
+#endif
+
+        if ((p_scb->call_ind != BTA_AG_CALL_INACTIVE) ||
+            (p_scb->callsetup_ind != BTA_AG_CALLSETUP_NONE))
+        {
+            bta_sys_sco_use(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+        }
+
+        (*bta_ag_cb.p_cback)(BTA_AG_CONN_EVT, (tBTA_AG *) &evt);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_ci_rx_data
+**
+** Description      Send result code
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_ci_rx_data(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+    UINT16 len;
+    tBTA_AG_CI_RX_WRITE *p_rx_write_msg = (tBTA_AG_CI_RX_WRITE *)p_data;
+    char *p_data_area = (char *)(p_rx_write_msg+1);     /* Point to data area after header */
+
+    /* send to RFCOMM */
+    PORT_WriteData(p_scb->conn_handle, p_data_area, strlen(p_data_area), &len);
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_rcvd_slc_ready
+**
+** Description      Handles SLC ready call-in in case of pass-through mode.
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_rcvd_slc_ready(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+    UNUSED(p_data);
+
+    APPL_TRACE_DEBUG1("bta_ag_rcvd_slc_ready: handle = %d", bta_ag_scb_to_idx(p_scb));
+
+    if (bta_ag_cb.parse_mode == BTA_AG_PASS_THROUGH)
+    {
+        /* In pass-through mode, BTA knows that SLC is ready only through call-in. */
+        bta_ag_svc_conn_open(p_scb, NULL);
+    }
+}
+
diff --git a/bta/hf_client/bta_hf_client_api.c b/bta/hf_client/bta_hf_client_api.c
new file mode 100644
index 0000000..07dceb9
--- /dev/null
+++ b/bta/hf_client/bta_hf_client_api.c
@@ -0,0 +1,323 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2003-2012 Broadcom Corporation
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *  This is the implementation of the API for the audio gateway (AG)
+ *  subsystem of BTA, Broadcom's Bluetooth application layer for mobile
+ *  phones.
+ *
+ ******************************************************************************/
+
+#include "bta_api.h"
+#include "bd.h"
+#include "bta_sys.h"
+#include "bta_ag_api.h"
+#include "bta_ag_int.h"
+#include "gki.h"
+#include <string.h>
+
+/*****************************************************************************
+**  Constants
+*****************************************************************************/
+
+static const tBTA_SYS_REG bta_ag_reg =
+{
+    bta_ag_hdl_event,
+    BTA_AgDisable
+};
+
+/*******************************************************************************
+**
+** Function         BTA_AgEnable
+**
+** Description      Enable the audio gateway service. When the enable
+**                  operation is complete the callback function will be
+**                  called with a BTA_AG_ENABLE_EVT. This function must
+**                  be called before other function in the AG API are
+**                  called.
+**
+** Returns          BTA_SUCCESS if OK, BTA_FAILURE otherwise.
+**
+*******************************************************************************/
+tBTA_STATUS BTA_AgEnable(tBTA_AG_PARSE_MODE parse_mode, tBTA_AG_CBACK *p_cback)
+{
+    tBTA_AG_API_ENABLE  *p_buf;
+    UINT8       idx;
+
+    /* Error if AG is already enabled, or AG is in the middle of disabling. */
+    for (idx = 0; idx < BTA_AG_NUM_SCB; idx++)
+    {
+        if (bta_ag_cb.scb[idx].in_use)
+        {
+            APPL_TRACE_ERROR0 ("BTA_AgEnable: FAILED, AG already enabled.");
+            return BTA_FAILURE;
+        }
+    }
+
+    /* register with BTA system manager */
+    GKI_sched_lock();
+    bta_sys_register(BTA_ID_AG, &bta_ag_reg);
+    GKI_sched_unlock();
+
+    if ((p_buf = (tBTA_AG_API_ENABLE *) GKI_getbuf(sizeof(tBTA_AG_API_ENABLE))) != NULL)
+    {
+        p_buf->hdr.event = BTA_AG_API_ENABLE_EVT;
+        p_buf->parse_mode = parse_mode;
+        p_buf->p_cback = p_cback;
+        bta_sys_sendmsg(p_buf);
+    }
+
+    return BTA_SUCCESS;
+
+}
+
+/*******************************************************************************
+**
+** Function         BTA_AgDisable
+**
+** Description      Disable the audio gateway service
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void BTA_AgDisable(void)
+{
+    BT_HDR  *p_buf;
+
+    if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL)
+    {
+        p_buf->event = BTA_AG_API_DISABLE_EVT;
+        bta_sys_sendmsg(p_buf);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         BTA_AgRegister
+**
+** Description      Register an Audio Gateway service.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void BTA_AgRegister(tBTA_SERVICE_MASK services, tBTA_SEC sec_mask,tBTA_AG_FEAT features,
+                  char * p_service_names[], UINT8 app_id)
+{
+    tBTA_AG_API_REGISTER    *p_buf;
+    int                     i;
+
+    if ((p_buf = (tBTA_AG_API_REGISTER *) GKI_getbuf(sizeof(tBTA_AG_API_REGISTER))) != NULL)
+    {
+        p_buf->hdr.event = BTA_AG_API_REGISTER_EVT;
+        p_buf->features = features;
+        p_buf->sec_mask = sec_mask;
+        p_buf->services = services;
+        p_buf->app_id = app_id;
+        for (i = 0; i < BTA_AG_NUM_IDX; i++)
+        {
+            if(p_service_names[i])
+            {
+                BCM_STRNCPY_S(p_buf->p_name[i], BTA_SERVICE_NAME_LEN+1, p_service_names[i], BTA_SERVICE_NAME_LEN);
+                p_buf->p_name[i][BTA_SERVICE_NAME_LEN] = 0;
+            }
+            else
+            {
+                p_buf->p_name[i][0] = 0;
+            }
+        }
+        bta_sys_sendmsg(p_buf);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         BTA_AgDeregister
+**
+** Description      Deregister an audio gateway service.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void BTA_AgDeregister(UINT16 handle)
+{
+    BT_HDR  *p_buf;
+
+    if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL)
+    {
+        p_buf->event = BTA_AG_API_DEREGISTER_EVT;
+        p_buf->layer_specific = handle;
+        bta_sys_sendmsg(p_buf);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         BTA_AgOpen
+**
+** Description      Opens a connection to a headset or hands-free device.
+**                  When connection is open callback function is called
+**                  with a BTA_AG_OPEN_EVT. Only the data connection is
+**                  opened. The audio connection is not opened.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void BTA_AgOpen(UINT16 handle, BD_ADDR bd_addr, tBTA_SEC sec_mask, tBTA_SERVICE_MASK services)
+{
+    tBTA_AG_API_OPEN  *p_buf;
+
+    if ((p_buf = (tBTA_AG_API_OPEN *) GKI_getbuf(sizeof(tBTA_AG_API_OPEN))) != NULL)
+    {
+        p_buf->hdr.event = BTA_AG_API_OPEN_EVT;
+        p_buf->hdr.layer_specific = handle;
+        bdcpy(p_buf->bd_addr, bd_addr);
+        p_buf->services = services;
+        p_buf->sec_mask = sec_mask;
+        bta_sys_sendmsg(p_buf);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         BTA_AgClose
+**
+** Description      Close the current connection to a headset or a handsfree
+**                  Any current audio connection will also be closed.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void BTA_AgClose(UINT16 handle)
+{
+    BT_HDR  *p_buf;
+
+    if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL)
+    {
+        p_buf->event = BTA_AG_API_CLOSE_EVT;
+        p_buf->layer_specific = handle;
+        bta_sys_sendmsg(p_buf);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         BTA_AgAudioOpen
+**
+** Description      Opens an audio connection to the currently connected
+**                  headset or hnadsfree.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void BTA_AgAudioOpen(UINT16 handle)
+{
+    BT_HDR  *p_buf;
+
+    if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL)
+    {
+        p_buf->event = BTA_AG_API_AUDIO_OPEN_EVT;
+        p_buf->layer_specific = handle;
+        bta_sys_sendmsg(p_buf);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         BTA_AgAudioClose
+**
+** Description      Close the currently active audio connection to a headset
+**                  or hnadsfree. The data connection remains open
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void BTA_AgAudioClose(UINT16 handle)
+{
+    BT_HDR  *p_buf;
+
+    if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL)
+    {
+        p_buf->event = BTA_AG_API_AUDIO_CLOSE_EVT;
+        p_buf->layer_specific = handle;
+        bta_sys_sendmsg(p_buf);
+    }
+}
+
+
+/*******************************************************************************
+**
+** Function         BTA_AgResult
+**
+** Description      Send an AT result code to a headset or hands-free device.
+**                  This function is only used when the AG parse mode is set
+**                  to BTA_AG_PARSE.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void BTA_AgResult(UINT16 handle, tBTA_AG_RES result, tBTA_AG_RES_DATA *p_data)
+{
+    tBTA_AG_API_RESULT  *p_buf;
+
+    if ((p_buf = (tBTA_AG_API_RESULT *) GKI_getbuf(sizeof(tBTA_AG_API_RESULT))) != NULL)
+    {
+        p_buf->hdr.event = BTA_AG_API_RESULT_EVT;
+        p_buf->hdr.layer_specific = handle;
+        p_buf->result = result;
+        if(p_data)
+        {
+            memcpy(&p_buf->data, p_data, sizeof(p_buf->data));
+        }
+        bta_sys_sendmsg(p_buf);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         BTA_AgSetCodec
+**
+** Description      Specify the codec type to be used for the subsequent
+**                  audio connection.
+**
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void BTA_AgSetCodec(UINT16 handle, tBTA_AG_PEER_CODEC codec)
+{
+    tBTA_AG_API_SETCODEC    *p_buf;
+
+    if ((p_buf = (tBTA_AG_API_SETCODEC *) GKI_getbuf(sizeof(tBTA_AG_API_SETCODEC))) != NULL)
+    {
+        p_buf->hdr.event = BTA_AG_API_SETCODEC_EVT;
+        p_buf->hdr.layer_specific = handle;
+        p_buf->codec = codec;
+        bta_sys_sendmsg(p_buf);
+    }
+}
+
diff --git a/bta/hf_client/bta_hf_client_at.c b/bta/hf_client/bta_hf_client_at.c
new file mode 100644
index 0000000..74d3948
--- /dev/null
+++ b/bta/hf_client/bta_hf_client_at.c
@@ -0,0 +1,243 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2004-2012 Broadcom Corporation
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *  BTA AG AT command interpreter.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+#include "gki.h"
+#include "bta_ag_at.h"
+#include "utl.h"
+
+/*****************************************************************************
+**  Constants
+*****************************************************************************/
+
+/******************************************************************************
+**
+** Function         bta_ag_at_init
+**
+** Description      Initialize the AT command parser control block.
+**
+**
+** Returns          void
+**
+******************************************************************************/
+void bta_ag_at_init(tBTA_AG_AT_CB *p_cb)
+{
+    p_cb->p_cmd_buf = NULL;
+    p_cb->cmd_pos = 0;
+}
+
+/******************************************************************************
+**
+** Function         bta_ag_at_reinit
+**
+** Description      Re-initialize the AT command parser control block.  This
+**                  function resets the AT command parser state and frees
+**                  any GKI buffer.
+**
+**
+** Returns          void
+**
+******************************************************************************/
+void bta_ag_at_reinit(tBTA_AG_AT_CB *p_cb)
+{
+    if (p_cb->p_cmd_buf != NULL)
+    {
+        GKI_freebuf(p_cb->p_cmd_buf);
+        p_cb->p_cmd_buf = NULL;
+    }
+    p_cb->cmd_pos = 0;
+}
+/******************************************************************************
+**
+** Function         bta_ag_process_at
+**
+** Description      Parse AT commands.  This function will take the input
+**                  character string and parse it for AT commands according to
+**                  the AT command table passed in the control block.
+**
+**
+** Returns          void
+**
+******************************************************************************/
+void bta_ag_process_at(tBTA_AG_AT_CB *p_cb)
+{
+    UINT16      idx;
+    UINT8       arg_type;
+    char        *p_arg;
+    INT16       int_arg = 0;
+    /* loop through at command table looking for match */
+    for (idx = 0; p_cb->p_at_tbl[idx].p_cmd[0] != 0; idx++)
+    {
+        if (!utl_strucmp(p_cb->p_at_tbl[idx].p_cmd, p_cb->p_cmd_buf))
+        {
+            break;
+        }
+    }
+
+    /* if there is a match; verify argument type */
+    if (p_cb->p_at_tbl[idx].p_cmd[0] != 0)
+    {
+        /* start of argument is p + strlen matching command */
+        p_arg = p_cb->p_cmd_buf + strlen(p_cb->p_at_tbl[idx].p_cmd);
+
+        /* if no argument */
+        if (p_arg[0] == 0)
+        {
+            arg_type = BTA_AG_AT_NONE;
+        }
+        /* else if arg is '?' and it is last character */
+        else if (p_arg[0] == '?' && p_arg[1] == 0)
+        {
+            /* we have a read */
+            arg_type = BTA_AG_AT_READ;
+        }
+        /* else if arg is '=' */
+        else if (p_arg[0] == '=' && p_arg[1] != 0)
+        {
+            if (p_arg[1] == '?' && p_arg[2] == 0)
+            {
+                /* we have a test */
+                arg_type = BTA_AG_AT_TEST;
+            }
+            else
+            {
+                /* we have a set */
+                arg_type = BTA_AG_AT_SET;
+
+                /* skip past '=' */
+                p_arg++;
+            }
+        }
+        else
+        /* else it is freeform argument */
+        {
+            arg_type = BTA_AG_AT_FREE;
+        }
+
+        /* if arguments match command capabilities */
+        if ((arg_type & p_cb->p_at_tbl[idx].arg_type) != 0)
+        {
+            /* if it's a set integer check max, min range */
+            if (arg_type == BTA_AG_AT_SET &&
+                p_cb->p_at_tbl[idx].fmt == BTA_AG_AT_INT)
+            {
+                int_arg = utl_str2int(p_arg);
+                if (int_arg < (INT16) p_cb->p_at_tbl[idx].min ||
+                    int_arg > (INT16) p_cb->p_at_tbl[idx].max)
+                {
+                    /* arg out of range; error */
+                    (*p_cb->p_err_cback)(p_cb->p_user, FALSE, NULL);
+                }
+                else
+                {
+
+                    (*p_cb->p_cmd_cback)(p_cb->p_user, idx, arg_type, p_arg, int_arg);
+                }
+            }
+            else
+            {
+                (*p_cb->p_cmd_cback)(p_cb->p_user, idx, arg_type, p_arg, int_arg);
+            }
+        }
+        /* else error */
+        else
+        {
+            (*p_cb->p_err_cback)(p_cb->p_user, FALSE, NULL);
+        }
+    }
+    /* else no match call error callback */
+    else
+    {
+        (*p_cb->p_err_cback)(p_cb->p_user, TRUE, p_cb->p_cmd_buf);
+    }
+}
+
+/******************************************************************************
+**
+** Function         bta_ag_at_parse
+**
+** Description      Parse AT commands.  This function will take the input
+**                  character string and parse it for AT commands according to
+**                  the AT command table passed in the control block.
+**
+**
+** Returns          void
+**
+******************************************************************************/
+void bta_ag_at_parse(tBTA_AG_AT_CB *p_cb, char *p_buf, UINT16 len)
+{
+    int i = 0;
+    char* p_save;
+
+    if (p_cb->p_cmd_buf == NULL)
+    {
+        p_cb->p_cmd_buf = (char *) GKI_getbuf(p_cb->cmd_max_len);
+        p_cb->cmd_pos = 0;
+    }
+
+    for (i = 0; i < len;)
+    {
+        while (p_cb->cmd_pos < p_cb->cmd_max_len-1 && i < len)
+        {
+            /* Skip null characters between AT commands. */
+            if ((p_cb->cmd_pos == 0) && (p_buf[i] == 0))
+            {
+                i++;
+                continue;
+            }
+
+            p_cb->p_cmd_buf[p_cb->cmd_pos] = p_buf[i++];
+            if ( p_cb->p_cmd_buf[p_cb->cmd_pos] == '\r' || p_cb->p_cmd_buf[p_cb->cmd_pos] == '\n')
+            {
+                p_cb->p_cmd_buf[p_cb->cmd_pos] = 0;
+                if ((p_cb->cmd_pos > 2)                                      &&
+                    (p_cb->p_cmd_buf[0] == 'A' || p_cb->p_cmd_buf[0] == 'a') &&
+                    (p_cb->p_cmd_buf[1] == 'T' || p_cb->p_cmd_buf[1] == 't'))
+                {
+                    p_save = p_cb->p_cmd_buf;
+                    p_cb->p_cmd_buf += 2;
+                    bta_ag_process_at(p_cb);
+                    p_cb->p_cmd_buf = p_save;
+                }
+
+                p_cb->cmd_pos = 0;
+
+            }
+            else if( p_cb->p_cmd_buf[p_cb->cmd_pos] == 0x1A || p_cb->p_cmd_buf[p_cb->cmd_pos] == 0x1B )
+            {
+                p_cb->p_cmd_buf[++p_cb->cmd_pos] = 0;
+                (*p_cb->p_err_cback)(p_cb->p_user, TRUE, p_cb->p_cmd_buf);
+                p_cb->cmd_pos = 0;
+            }
+            else
+            {
+                ++p_cb->cmd_pos;
+            }
+        }
+
+        if (i < len)
+            p_cb->cmd_pos = 0;
+    }
+}
+
diff --git a/bta/hf_client/bta_hf_client_at.h b/bta/hf_client/bta_hf_client_at.h
new file mode 100644
index 0000000..90d7b0f
--- /dev/null
+++ b/bta/hf_client/bta_hf_client_at.h
@@ -0,0 +1,121 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2004-2012 Broadcom Corporation
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *  Interface file for BTA AG AT command interpreter.
+ *
+ ******************************************************************************/
+#ifndef BTA_AG_AT_H
+#define BTA_AG_AT_H
+
+/*****************************************************************************
+**  Constants
+*****************************************************************************/
+
+/* AT command argument capabilities */
+#define BTA_AG_AT_NONE          0x01        /* no argument */
+#define BTA_AG_AT_SET           0x02        /* set value */
+#define BTA_AG_AT_READ          0x04        /* read value */
+#define BTA_AG_AT_TEST          0x08        /* test value range */
+#define BTA_AG_AT_FREE          0x10        /* freeform argument */
+
+/* AT command argument format */
+#define BTA_AG_AT_STR           0           /* string */
+#define BTA_AG_AT_INT           1           /* integer */
+
+/*****************************************************************************
+**  Data types
+*****************************************************************************/
+
+/* AT command table element */
+typedef struct
+{
+    const char  *p_cmd;         /* AT command string */
+    UINT8       arg_type;       /* allowable argument type syntax */
+    UINT8       fmt;            /* whether arg is int or string */
+    UINT8       min;            /* minimum value for int arg */
+    INT16       max;            /* maximum value for int arg */
+} tBTA_AG_AT_CMD;
+
+/* callback function executed when command is parsed */
+typedef void (tBTA_AG_AT_CMD_CBACK)(void *p_user, UINT16 cmd, UINT8 arg_type,
+                                    char *p_arg, INT16 int_arg);
+
+/* callback function executed to send "ERROR" result code */
+typedef void (tBTA_AG_AT_ERR_CBACK)(void *p_user, BOOLEAN unknown, char *p_arg);
+
+/* AT command parsing control block */
+typedef struct
+{
+    tBTA_AG_AT_CMD          *p_at_tbl;      /* AT command table */
+    tBTA_AG_AT_CMD_CBACK    *p_cmd_cback;   /* command callback */
+    tBTA_AG_AT_ERR_CBACK    *p_err_cback;   /* error callback */
+    void                    *p_user;        /* user-defined data */
+    char                    *p_cmd_buf;     /* temp parsing buffer */
+    UINT16                  cmd_pos;        /* position in temp buffer */
+    UINT16                  cmd_max_len;    /* length of temp buffer to allocate */
+    UINT8                   state;          /* parsing state */
+} tBTA_AG_AT_CB;
+
+/*****************************************************************************
+**  Function prototypes
+*****************************************************************************/
+
+/*****************************************************************************
+**
+** Function         bta_ag_at_init
+**
+** Description      Initialize the AT command parser control block.
+**
+**
+** Returns          void
+**
+*****************************************************************************/
+extern void bta_ag_at_init(tBTA_AG_AT_CB *p_cb);
+
+/*****************************************************************************
+**
+** Function         bta_ag_at_reinit
+**
+** Description      Re-initialize the AT command parser control block.  This
+**                  function resets the AT command parser state and frees
+**                  any GKI buffer.
+**
+**
+** Returns          void
+**
+*****************************************************************************/
+extern void bta_ag_at_reinit(tBTA_AG_AT_CB *p_cb);
+
+/*****************************************************************************
+**
+** Function         bta_ag_at_parse
+**
+** Description      Parse AT commands.  This function will take the input
+**                  character string and parse it for AT commands according to
+**                  the AT command table passed in the control block.
+**
+**
+** Returns          void
+**
+*****************************************************************************/
+extern void bta_ag_at_parse(tBTA_AG_AT_CB *p_cb, char *p_buf, UINT16 len);
+
+#endif /* BTA_AG_AT_H */
+
diff --git a/bta/hf_client/bta_hf_client_cmd.c b/bta/hf_client/bta_hf_client_cmd.c
new file mode 100644
index 0000000..54cd4d3
--- /dev/null
+++ b/bta/hf_client/bta_hf_client_cmd.c
@@ -0,0 +1,1843 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2004-2012 Broadcom Corporation
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *  This file contains functions for processing AT commands and results.
+ *
+ ******************************************************************************/
+
+#include "bta_api.h"
+#include "bta_sys.h"
+#include "bta_ag_api.h"
+#include "bta_ag_int.h"
+#include "bta_ag_at.h"
+#include "port_api.h"
+#include "utl.h"
+#include <stdio.h>
+#include <string.h>
+
+/*****************************************************************************
+**  Constants
+*****************************************************************************/
+
+/* ring timeout */
+#define BTA_AG_RING_TOUT        5000
+
+#define BTA_AG_CMD_MAX_VAL      32767  /* Maximum value is signed 16-bit value */
+
+
+
+/* clip type constants */
+#define BTA_AG_CLIP_TYPE_MIN        128
+#define BTA_AG_CLIP_TYPE_MAX        175
+#define BTA_AG_CLIP_TYPE_DEFAULT    129
+#define BTA_AG_CLIP_TYPE_VOIP       255
+
+#if defined(BTA_AG_MULTI_RESULT_INCLUDED) && (BTA_AG_MULTI_RESULT_INCLUDED == TRUE)
+#define BTA_AG_AT_MULTI_LEN            2
+#define AT_SET_RES_CB(res_cb, c, p, i) {res_cb.code = c; res_cb.p_arg = p; res_cb.int_arg = i;}
+
+/* type for AT result code block */
+typedef struct
+{
+    UINT8 code;
+    char *p_arg;
+    INT16 int_arg;
+} tBTA_AG_RESULT_CB;
+
+/* type for multiple AT result codes block */
+typedef struct
+{
+    UINT8 num_result;
+    tBTA_AG_RESULT_CB res_cb[BTA_AG_AT_MULTI_LEN];
+} tBTA_AG_MULTI_RESULT_CB;
+#endif
+
+/* enumeration of HSP AT commands matches HSP command interpreter table */
+enum
+{
+    BTA_AG_HS_CMD_CKPD,
+    BTA_AG_HS_CMD_VGS,
+    BTA_AG_HS_CMD_VGM
+};
+
+/* enumeration of HFP AT commands matches HFP command interpreter table */
+enum
+{
+    BTA_AG_HF_CMD_A,
+    BTA_AG_HF_CMD_D,
+    BTA_AG_HF_CMD_VGS,
+    BTA_AG_HF_CMD_VGM,
+    BTA_AG_HF_CMD_CCWA,
+    BTA_AG_HF_CMD_CHLD,
+    BTA_AG_HF_CMD_CHUP,
+    BTA_AG_HF_CMD_CIND,
+    BTA_AG_HF_CMD_CLIP,
+    BTA_AG_HF_CMD_CMER,
+    BTA_AG_HF_CMD_VTS,
+    BTA_AG_HF_CMD_BINP,
+    BTA_AG_HF_CMD_BLDN,
+    BTA_AG_HF_CMD_BVRA,
+    BTA_AG_HF_CMD_BRSF,
+    BTA_AG_HF_CMD_NREC,
+    BTA_AG_HF_CMD_CNUM,
+    BTA_AG_HF_CMD_BTRH,
+    BTA_AG_HF_CMD_CLCC,
+    BTA_AG_HF_CMD_COPS,
+    BTA_AG_HF_CMD_CMEE,
+    BTA_AG_HF_CMD_BIA,
+    BTA_AG_HF_CMD_CBC,
+    BTA_AG_HF_CMD_BCC,
+    BTA_AG_HF_CMD_BCS,
+    BTA_AG_HF_CMD_BAC
+};
+
+/* AT command interpreter table for HSP */
+const tBTA_AG_AT_CMD bta_ag_hsp_cmd[] =
+{
+    {"+CKPD",   BTA_AG_AT_SET,                      BTA_AG_AT_INT, 200, 200},
+    {"+VGS",    BTA_AG_AT_SET,                      BTA_AG_AT_INT,   0,  15},
+    {"+VGM",    BTA_AG_AT_SET,                      BTA_AG_AT_INT,   0,  15},
+    {"",        BTA_AG_AT_NONE,                     BTA_AG_AT_STR,   0,   0}
+};
+
+/* AT command interpreter table for HFP */
+const tBTA_AG_AT_CMD bta_ag_hfp_cmd[] =
+{
+    {"A",       BTA_AG_AT_NONE,                     BTA_AG_AT_STR,   0,   0},
+    {"D",       (BTA_AG_AT_NONE | BTA_AG_AT_FREE),  BTA_AG_AT_STR,   0,   0},
+    {"+VGS",    BTA_AG_AT_SET,                      BTA_AG_AT_INT,   0,  15},
+    {"+VGM",    BTA_AG_AT_SET,                      BTA_AG_AT_INT,   0,  15},
+    {"+CCWA",   BTA_AG_AT_SET,                      BTA_AG_AT_INT,   0,   1},
+    /* Consider CHLD as str to take care of indexes for ECC */
+    {"+CHLD",   (BTA_AG_AT_SET | BTA_AG_AT_TEST),   BTA_AG_AT_STR,   0,   4},
+    {"+CHUP",   BTA_AG_AT_NONE,                     BTA_AG_AT_STR,   0,   0},
+    {"+CIND",   (BTA_AG_AT_READ | BTA_AG_AT_TEST),  BTA_AG_AT_STR,   0,   0},
+    {"+CLIP",   BTA_AG_AT_SET,                      BTA_AG_AT_INT,   0,   1},
+    {"+CMER",   BTA_AG_AT_SET,                      BTA_AG_AT_STR,   0,   0},
+    {"+VTS",    BTA_AG_AT_SET,                      BTA_AG_AT_STR,   0,   0},
+    {"+BINP",   BTA_AG_AT_SET,                      BTA_AG_AT_INT,   1,   1},
+    {"+BLDN",   BTA_AG_AT_NONE,                     BTA_AG_AT_STR,   0,   0},
+    {"+BVRA",   BTA_AG_AT_SET,                      BTA_AG_AT_INT,   0,   1},
+    {"+BRSF",   BTA_AG_AT_SET,                      BTA_AG_AT_INT,   0,   BTA_AG_CMD_MAX_VAL},
+    {"+NREC",   BTA_AG_AT_SET,                      BTA_AG_AT_INT,   0,   0},
+    {"+CNUM",   BTA_AG_AT_NONE,                     BTA_AG_AT_STR,   0,   0},
+    {"+BTRH",   (BTA_AG_AT_READ | BTA_AG_AT_SET),   BTA_AG_AT_INT,   0,   2},
+    {"+CLCC",   BTA_AG_AT_NONE,                     BTA_AG_AT_STR,   0,   0},
+    {"+COPS",   (BTA_AG_AT_READ | BTA_AG_AT_SET),   BTA_AG_AT_STR,   0,   0},
+    {"+CMEE",   BTA_AG_AT_SET,                      BTA_AG_AT_INT,   0,   1},
+    {"+BIA",    BTA_AG_AT_SET,                      BTA_AG_AT_STR,   0,   20},
+    {"+CBC",    BTA_AG_AT_SET,                      BTA_AG_AT_INT,   0,   100},
+    {"+BCC",    BTA_AG_AT_NONE,                     BTA_AG_AT_STR,   0,   0},
+    {"+BCS",    BTA_AG_AT_SET,                      BTA_AG_AT_INT,   0,   BTA_AG_CMD_MAX_VAL},
+    {"+BAC",    BTA_AG_AT_SET,                      BTA_AG_AT_STR,   0,   0},
+    {"",        BTA_AG_AT_NONE,                     BTA_AG_AT_STR,   0,   0}
+};
+
+/* AT result code table element */
+typedef struct
+{
+    const char  *p_res;         /* AT result string */
+    UINT8       fmt;            /* whether argument is int or string */
+} tBTA_AG_RESULT;
+
+/* AT result code argument types */
+enum
+{
+    BTA_AG_RES_FMT_NONE,       /* no argument */
+    BTA_AG_RES_FMT_INT,        /* integer argument */
+    BTA_AG_RES_FMT_STR         /* string argument */
+};
+
+/* enumeration of AT result codes, matches constant table */
+enum
+{
+    BTA_AG_RES_OK,
+    BTA_AG_RES_ERROR,
+    BTA_AG_RES_RING,
+    BTA_AG_RES_VGS,
+    BTA_AG_RES_VGM,
+    BTA_AG_RES_CCWA,
+    BTA_AG_RES_CHLD,
+    BTA_AG_RES_CIND,
+    BTA_AG_RES_CLIP,
+    BTA_AG_RES_CIEV,
+    BTA_AG_RES_BINP,
+    BTA_AG_RES_BVRA,
+    BTA_AG_RES_BRSF,
+    BTA_AG_RES_BSIR,
+    BTA_AG_RES_CNUM,
+    BTA_AG_RES_BTRH,
+    BTA_AG_RES_CLCC,
+    BTA_AG_RES_COPS,
+    BTA_AG_RES_CMEE,
+    BTA_AG_RES_BCS,
+    BTA_AG_RES_UNAT
+};
+
+#if defined(BTA_HSP_RESULT_REPLACE_COLON) && (BTA_HSP_RESULT_REPLACE_COLON == TRUE)
+#define COLON_IDX_4_VGSVGM    4
+#endif
+/* AT result code constant table  (Indexed by result code) */
+const tBTA_AG_RESULT bta_ag_result_tbl[] =
+{
+    {"OK",      BTA_AG_RES_FMT_NONE},
+    {"ERROR",   BTA_AG_RES_FMT_NONE},
+    {"RING",    BTA_AG_RES_FMT_NONE},
+    {"+VGS: ",  BTA_AG_RES_FMT_INT},
+    {"+VGM: ",  BTA_AG_RES_FMT_INT},
+    {"+CCWA: ", BTA_AG_RES_FMT_STR},
+    {"+CHLD: ", BTA_AG_RES_FMT_STR},
+    {"+CIND: ", BTA_AG_RES_FMT_STR},
+    {"+CLIP: ", BTA_AG_RES_FMT_STR},
+    {"+CIEV: ", BTA_AG_RES_FMT_STR},
+    {"+BINP: ", BTA_AG_RES_FMT_STR},
+    {"+BVRA: ", BTA_AG_RES_FMT_INT},
+    {"+BRSF: ", BTA_AG_RES_FMT_INT},
+    {"+BSIR: ", BTA_AG_RES_FMT_INT},
+    {"+CNUM: ", BTA_AG_RES_FMT_STR},
+    {"+BTRH: ", BTA_AG_RES_FMT_INT},
+    {"+CLCC: ", BTA_AG_RES_FMT_STR},
+    {"+COPS: ", BTA_AG_RES_FMT_STR},
+    {"+CME ERROR: ", BTA_AG_RES_FMT_INT},
+    {"+BCS: ",  BTA_AG_RES_FMT_INT},
+    {"",        BTA_AG_RES_FMT_STR}
+};
+
+const tBTA_AG_AT_CMD *bta_ag_at_tbl[BTA_AG_NUM_IDX] =
+{
+    bta_ag_hsp_cmd,
+    bta_ag_hfp_cmd
+};
+
+/* callback event lookup table for HSP */
+const tBTA_AG_EVT bta_ag_hsp_cb_evt[] =
+{
+    BTA_AG_AT_CKPD_EVT,     /* BTA_AG_HS_CMD_CKPD */
+    BTA_AG_SPK_EVT,         /* BTA_AG_HS_CMD_VGS */
+    BTA_AG_MIC_EVT          /* BTA_AG_HS_CMD_VGM */
+};
+
+/* callback event lookup table for HFP  (Indexed by command) */
+const tBTA_AG_EVT bta_ag_hfp_cb_evt[] =
+{
+    BTA_AG_AT_A_EVT,        /* BTA_AG_HF_CMD_A */
+    BTA_AG_AT_D_EVT,        /* BTA_AG_HF_CMD_D */
+    BTA_AG_SPK_EVT,         /* BTA_AG_HF_CMD_VGS */
+    BTA_AG_MIC_EVT,         /* BTA_AG_HF_CMD_VGM */
+    0,                      /* BTA_AG_HF_CMD_CCWA */
+    BTA_AG_AT_CHLD_EVT,     /* BTA_AG_HF_CMD_CHLD */
+    BTA_AG_AT_CHUP_EVT,     /* BTA_AG_HF_CMD_CHUP */
+    BTA_AG_AT_CIND_EVT,     /* BTA_AG_HF_CMD_CIND */
+    0,                      /* BTA_AG_HF_CMD_CLIP */
+    0,                      /* BTA_AG_HF_CMD_CMER */
+    BTA_AG_AT_VTS_EVT,      /* BTA_AG_HF_CMD_VTS */
+    BTA_AG_AT_BINP_EVT,     /* BTA_AG_HF_CMD_BINP */
+    BTA_AG_AT_BLDN_EVT,     /* BTA_AG_HF_CMD_BLDN */
+    BTA_AG_AT_BVRA_EVT,     /* BTA_AG_HF_CMD_BVRA */
+    0,                      /* BTA_AG_HF_CMD_BRSF */
+    BTA_AG_AT_NREC_EVT,     /* BTA_AG_HF_CMD_NREC */
+    BTA_AG_AT_CNUM_EVT,     /* BTA_AG_HF_CMD_CNUM */
+    BTA_AG_AT_BTRH_EVT,     /* BTA_AG_HF_CMD_BTRH */
+    BTA_AG_AT_CLCC_EVT,     /* BTA_AG_HF_CMD_CLCC */
+    BTA_AG_AT_COPS_EVT,     /* BTA_AG_HF_CMD_COPS */
+    0,                      /* BTA_AG_HF_CMD_CMEE */
+    0,                      /* BTA_AG_HF_CMD_BIA */
+    BTA_AG_AT_CBC_EVT,      /* BTA_AG_HF_CMD_CBC */
+    0,                      /* BTA_AG_HF_CMD_BCC */
+    BTA_AG_AT_BCS_EVT,      /* BTA_AG_HF_CMD_BCS */
+    BTA_AG_AT_BAC_EVT       /* BTA_AG_HF_CMD_BAC */
+};
+
+/* translation of API result code values to internal values */
+const UINT8 bta_ag_trans_result[] =
+{
+    BTA_AG_RES_VGS,     /* BTA_AG_SPK_RES */
+    BTA_AG_RES_VGM,     /* BTA_AG_MIC_RES */
+    BTA_AG_RES_BSIR,    /* BTA_AG_INBAND_RING_RES */
+    BTA_AG_RES_CIND,    /* BTA_AG_CIND_RES */
+    BTA_AG_RES_BINP,    /* BTA_AG_BINP_RES */
+    BTA_AG_RES_CIEV,    /* BTA_AG_IND_RES */
+    BTA_AG_RES_BVRA,    /* BTA_AG_BVRA_RES */
+    BTA_AG_RES_CNUM,    /* BTA_AG_CNUM_RES */
+    BTA_AG_RES_BTRH,    /* BTA_AG_BTRH_RES */
+    BTA_AG_RES_CLCC,    /* BTA_AG_CLCC_RES */
+    BTA_AG_RES_COPS,    /* BTA_AG_COPS_RES */
+    0,                  /* BTA_AG_IN_CALL_RES */
+    0,                  /* BTA_AG_IN_CALL_CONN_RES */
+    BTA_AG_RES_CCWA,    /* BTA_AG_CALL_WAIT_RES */
+    0,                  /* BTA_AG_OUT_CALL_ORIG_RES */
+    0,                  /* BTA_AG_OUT_CALL_ALERT_RES */
+    0,                  /* BTA_AG_OUT_CALL_CONN_RES */
+    0,                  /* BTA_AG_CALL_CANCEL_RES */
+    0,                  /* BTA_AG_END_CALL_RES */
+    0,                  /* BTA_AG_IN_CALL_HELD_RES */
+    BTA_AG_RES_UNAT     /* BTA_AG_UNAT_RES */
+};
+
+/* callsetup indicator value lookup table */
+const UINT8 bta_ag_callsetup_ind_tbl[] =
+{
+    0,                          /* BTA_AG_SPK_RES */
+    0,                          /* BTA_AG_MIC_RES */
+    0,                          /* BTA_AG_INBAND_RING_RES */
+    0,                          /* BTA_AG_CIND_RES */
+    0,                          /* BTA_AG_BINP_RES */
+    0,                          /* BTA_AG_IND_RES */
+    0,                          /* BTA_AG_BVRA_RES */
+    0,                          /* BTA_AG_CNUM_RES */
+    0,                          /* BTA_AG_BTRH_RES */
+    0,                          /* BTA_AG_CLCC_RES */
+    0,                          /* BTA_AG_COPS_RES */
+    BTA_AG_CALLSETUP_INCOMING,  /* BTA_AG_IN_CALL_RES */
+    BTA_AG_CALLSETUP_NONE,      /* BTA_AG_IN_CALL_CONN_RES */
+    BTA_AG_CALLSETUP_INCOMING,  /* BTA_AG_CALL_WAIT_RES */
+    BTA_AG_CALLSETUP_OUTGOING,  /* BTA_AG_OUT_CALL_ORIG_RES */
+    BTA_AG_CALLSETUP_ALERTING,  /* BTA_AG_OUT_CALL_ALERT_RES */
+    BTA_AG_CALLSETUP_NONE,      /* BTA_AG_OUT_CALL_CONN_RES */
+    BTA_AG_CALLSETUP_NONE,      /* BTA_AG_CALL_CANCEL_RES */
+    BTA_AG_CALLSETUP_NONE,      /* BTA_AG_END_CALL_RES */
+    BTA_AG_CALLSETUP_NONE       /* BTA_AG_IN_CALL_HELD_RES */
+};
+
+/*******************************************************************************
+**
+** Function         bta_ag_send_result
+**
+** Description      Send an AT result code.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+static void bta_ag_send_result(tBTA_AG_SCB *p_scb, UINT8 code, char *p_arg,
+                               INT16 int_arg)
+{
+    char    buf[BTA_AG_AT_MAX_LEN + 16];
+    char    *p = buf;
+    UINT16  len;
+
+#if defined(BTA_AG_RESULT_DEBUG) && (BTA_AG_RESULT_DEBUG == TRUE)
+    memset(buf, NULL, sizeof(buf));
+#endif
+    /* init with \r\n */
+    *p++ = '\r';
+    *p++ = '\n';
+
+    /* copy result code string */
+    BCM_STRCPY_S(p, sizeof(buf), bta_ag_result_tbl[code].p_res);
+#if defined(BTA_HSP_RESULT_REPLACE_COLON) && (BTA_HSP_RESULT_REPLACE_COLON == TRUE)
+    if(p_scb->conn_service == BTA_AG_HSP)
+    {
+        /* If HSP then ":"symbol should be changed as "=" for HSP compatibility */
+        switch(code)
+        {
+        case BTA_AG_RES_VGS:
+        case BTA_AG_RES_VGM:
+            if(*(p+COLON_IDX_4_VGSVGM) == ':')
+            {
+                #if defined(BTA_AG_RESULT_DEBUG) && (BTA_AG_RESULT_DEBUG == TRUE)
+                APPL_TRACE_DEBUG0("[HSP] ':'symbol is changed as '=' for HSP compatibility");
+                #endif
+                *(p+COLON_IDX_4_VGSVGM) = '=';
+            }
+            break;
+        }
+    }
+#endif
+    p += strlen(bta_ag_result_tbl[code].p_res);
+
+    /* copy argument if any */
+    if (bta_ag_result_tbl[code].fmt == BTA_AG_RES_FMT_INT)
+    {
+        p += utl_itoa((UINT16) int_arg, p);
+    }
+    else if (bta_ag_result_tbl[code].fmt == BTA_AG_RES_FMT_STR)
+    {
+        BCM_STRCPY_S(p, sizeof(buf), p_arg);
+        p += strlen(p_arg);
+    }
+
+    /* finish with \r\n */
+    *p++ = '\r';
+    *p++ = '\n';
+
+#if defined(BTA_AG_RESULT_DEBUG) && (BTA_AG_RESULT_DEBUG == TRUE)
+    APPL_TRACE_DEBUG1("bta_ag_send_result: %s", buf);
+#endif
+
+    /* send to RFCOMM */
+    PORT_WriteData(p_scb->conn_handle, buf, (UINT16) (p - buf), &len);
+}
+
+#if defined(BTA_AG_MULTI_RESULT_INCLUDED) && (BTA_AG_MULTI_RESULT_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function         bta_ag_send_multi_result
+**
+** Description      Send multiple AT result codes.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+static void bta_ag_send_multi_result(tBTA_AG_SCB *p_scb, tBTA_AG_MULTI_RESULT_CB *m_res_cb)
+{
+    char    buf[BTA_AG_AT_MAX_LEN * BTA_AG_AT_MULTI_LEN + 16];
+    char    *p = buf;
+    UINT16  len;
+    UINT8   res_idx = 0;
+
+    if((!m_res_cb) || (m_res_cb->num_result == 0) || (m_res_cb->num_result > BTA_AG_AT_MULTI_LEN))
+    {
+        APPL_TRACE_DEBUG0("m_res_cb is NULL or num_result is out of range.");
+        return;
+    }
+
+#if defined(BTA_AG_RESULT_DEBUG) && (BTA_AG_RESULT_DEBUG == TRUE)
+    memset(buf, NULL, sizeof(buf));
+#endif
+
+    while(res_idx < m_res_cb->num_result)
+    {
+        /* init with \r\n */
+        *p++ = '\r';
+        *p++ = '\n';
+
+        /* copy result code string */
+        BCM_STRCPY_S(p, sizeof(buf), bta_ag_result_tbl[m_res_cb->res_cb[res_idx].code].p_res);
+        p += strlen(bta_ag_result_tbl[m_res_cb->res_cb[res_idx].code].p_res);
+
+        /* copy argument if any */
+        if (bta_ag_result_tbl[m_res_cb->res_cb[res_idx].code].fmt == BTA_AG_RES_FMT_INT)
+        {
+            p += utl_itoa((UINT16) m_res_cb->res_cb[res_idx].int_arg, p);
+        }
+        else if (bta_ag_result_tbl[m_res_cb->res_cb[res_idx].code].fmt == BTA_AG_RES_FMT_STR)
+        {
+            BCM_STRCPY_S(p, sizeof(buf), m_res_cb->res_cb[res_idx].p_arg);
+            p += strlen(m_res_cb->res_cb[res_idx].p_arg);
+        }
+
+        /* finish with \r\n */
+        *p++ = '\r';
+        *p++ = '\n';
+
+        res_idx++;
+    }
+
+#if defined(BTA_AG_RESULT_DEBUG) && (BTA_AG_RESULT_DEBUG == TRUE)
+    APPL_TRACE_DEBUG1("send_result: %s", buf);
+#endif
+
+    /* send to RFCOMM */
+    PORT_WriteData(p_scb->conn_handle, buf, (UINT16) (p - buf), &len);
+}
+#endif
+
+/*******************************************************************************
+**
+** Function         bta_ag_send_ok
+**
+** Description      Send an OK result code.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+static void bta_ag_send_ok(tBTA_AG_SCB *p_scb)
+{
+    bta_ag_send_result(p_scb, BTA_AG_RES_OK, NULL, 0);
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_send_error
+**
+** Description      Send an ERROR result code.
+**                      errcode - used to send verbose errocode
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+static void bta_ag_send_error(tBTA_AG_SCB *p_scb, INT16 errcode)
+{
+    /* If HFP and extended audio gateway error codes are enabled */
+    if (p_scb->conn_service == BTA_AG_HFP && p_scb->cmee_enabled)
+        bta_ag_send_result(p_scb, BTA_AG_RES_CMEE, NULL, errcode);
+    else
+        bta_ag_send_result(p_scb, BTA_AG_RES_ERROR, NULL, 0);
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_send_ind
+**
+** Description      Send an indicator CIEV result code.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+static void bta_ag_send_ind(tBTA_AG_SCB *p_scb, UINT16 id, UINT16 value, BOOLEAN on_demand)
+{
+    char    str[12];
+    char    *p = str;
+
+    /* If the indicator is masked out, just return */
+    /* Mandatory indicators can not be masked out. */
+    if ((p_scb->bia_masked_out & ((UINT32)1 << id)) &&
+        ((id != BTA_AG_IND_CALL) && (id != BTA_AG_IND_CALLSETUP) && (id != BTA_AG_IND_CALLHELD)))
+        return;
+
+    /* Ensure we do not send duplicate indicators if not requested by app */
+    /* If it was requested by app, transmit CIEV even if it is duplicate. */
+    if (id == BTA_AG_IND_CALL)
+    {
+        if ((value == p_scb->call_ind) && (on_demand == FALSE))
+            return;
+
+        p_scb->call_ind = (UINT8)value;
+    }
+
+    if ((id == BTA_AG_IND_CALLSETUP) && (on_demand == FALSE))
+    {
+        if (value == p_scb->callsetup_ind)
+            return;
+
+        p_scb->callsetup_ind = (UINT8)value;
+    }
+
+    if ((id == BTA_AG_IND_SERVICE) && (on_demand == FALSE))
+    {
+        if (value == p_scb->service_ind)
+            return;
+
+        p_scb->service_ind = (UINT8)value;
+    }
+    if ((id == BTA_AG_IND_SIGNAL) && (on_demand == FALSE))
+    {
+        if (value == p_scb->signal_ind)
+            return;
+
+        p_scb->signal_ind = (UINT8)value;
+    }
+    if ((id == BTA_AG_IND_ROAM) && (on_demand == FALSE))
+    {
+        if (value == p_scb->roam_ind)
+            return;
+
+        p_scb->roam_ind = (UINT8)value;
+    }
+    if ((id == BTA_AG_IND_BATTCHG) && (on_demand == FALSE))
+    {
+        if (value == p_scb->battchg_ind)
+            return;
+
+        p_scb->battchg_ind = (UINT8)value;
+    }
+
+    if ((id == BTA_AG_IND_CALLHELD) && (on_demand == FALSE))
+    {
+        /* call swap could result in sending callheld=1 multiple times */
+        if ((value != 1) && (value == p_scb->callheld_ind))
+            return;
+
+        p_scb->callheld_ind = (UINT8)value;
+    }
+
+    if (p_scb->cmer_enabled)
+    {
+        p += utl_itoa(id, p);
+        *p++ = ',';
+        utl_itoa(value, p);
+        bta_ag_send_result(p_scb, BTA_AG_RES_CIEV, str, 0);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_parse_cmer
+**
+** Description      Parse AT+CMER parameter string.
+**
+**
+** Returns          TRUE if parsed ok, FALSE otherwise.
+**
+*******************************************************************************/
+static BOOLEAN bta_ag_parse_cmer(char *p_s, BOOLEAN *p_enabled)
+{
+    INT16   n[4] = {-1, -1, -1, -1};
+    int     i;
+    char    *p;
+
+    for (i = 0; i < 4; i++)
+    {
+        /* skip to comma delimiter */
+        for (p = p_s; *p != ',' && *p != 0; p++);
+
+        /* get integer value */
+        *p = 0;
+        n[i] = utl_str2int(p_s);
+        p_s = p + 1;
+        if (p_s == 0)
+        {
+            break;
+        }
+    }
+
+    /* process values */
+    if (n[0] < 0 || n[3] < 0)
+    {
+        return FALSE;
+    }
+
+    if ((n[0] == 3) && ((n[3] == 1) || (n[3] == 0)))
+    {
+        *p_enabled = (BOOLEAN) n[3];
+    }
+
+    return TRUE;
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_parse_chld
+**
+** Description      Parse AT+CHLD parameter string.
+**
+**
+** Returns          Returns idx (1-7), or 0 if ECC not enabled or idx doesn't exist
+**
+*******************************************************************************/
+static UINT8 bta_ag_parse_chld(tBTA_AG_SCB *p_scb, char *p_s)
+{
+    UINT8   retval = 0;
+    INT16   idx = -1;
+    UNUSED(p_scb);
+
+    if (p_s[1] != 0)
+    {
+        /* p_idxstr++;  point to beginning of call number */
+        idx = utl_str2int(&p_s[1]);
+        if (idx != -1 && idx < 255)
+            retval = (UINT8)idx;
+    }
+
+    return (retval);
+}
+
+#if (BTM_WBS_INCLUDED == TRUE )
+/*******************************************************************************
+**
+** Function         bta_ag_parse_bac
+**
+** Description      Parse AT+BAC parameter string.
+**
+** Returns          Returns bitmap of supported codecs.
+**
+*******************************************************************************/
+static tBTA_AG_PEER_CODEC bta_ag_parse_bac(tBTA_AG_SCB *p_scb, char *p_s)
+{
+    tBTA_AG_PEER_CODEC  retval = BTA_AG_CODEC_NONE;
+    UINT16  uuid_codec;
+    BOOLEAN cont = FALSE;       /* Continue processing */
+    char *p;
+
+    while(p_s)
+    {
+        /* skip to comma delimiter */
+        for(p = p_s; *p != ',' && *p != 0; p++);
+
+        /* get integre value */
+        if (*p != 0)
+        {
+            *p = 0;
+            cont = TRUE;
+        }
+        else
+            cont = FALSE;
+
+        uuid_codec = utl_str2int(p_s);
+        switch(uuid_codec)
+        {
+            case UUID_CODEC_CVSD:   retval |= BTA_AG_CODEC_CVSD;     break;
+            case UUID_CODEC_MSBC:   retval |= BTA_AG_CODEC_MSBC;     break;
+            default:
+                APPL_TRACE_ERROR1("Unknown Codec UUID(%d) received", uuid_codec);
+                return BTA_AG_CODEC_NONE;
+        }
+
+        if (cont)
+            p_s = p + 1;
+        else
+            break;
+    }
+
+    return (retval);
+}
+#endif
+
+/*******************************************************************************
+**
+** Function         bta_ag_process_unat_res
+**
+** Description      Process the unat response data and remove extra carriage return
+**                  and line feed
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+
+static void bta_ag_process_unat_res(char *unat_result)
+{
+    UINT8   str_leng;
+    UINT8   i = 0;
+    UINT8   j = 0;
+    UINT8   pairs_of_nl_cr;
+    char    trim_data[BTA_AG_AT_MAX_LEN];
+
+
+
+    str_leng = strlen(unat_result);
+
+    /* If no extra CR and LF, just return */
+    if(str_leng < 4)
+        return;
+
+    /* Remove the carriage return and left feed */
+    while(unat_result[0] =='\r' && unat_result[1] =='\n'
+        && unat_result[str_leng-2] =='\r' && unat_result[str_leng-1] =='\n')
+    {
+        pairs_of_nl_cr = 1;
+        for (i=0;i<(str_leng-4*pairs_of_nl_cr);i++)
+        {
+            trim_data[j++] = unat_result[i+pairs_of_nl_cr*2];
+        }
+        /* Add EOF */
+        trim_data[j] = '\0';
+        str_leng = str_leng - 4;
+        BCM_STRNCPY_S(unat_result, BTA_AG_AT_MAX_LEN+1, trim_data,str_leng+1);
+        i=0;
+        j=0;
+
+        if(str_leng <4)
+            return;
+
+
+    }
+    return;
+}
+
+
+/*******************************************************************************
+**
+** Function         bta_ag_inband_enabled
+**
+** Description      Determine whether in-band ring can be used.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+BOOLEAN bta_ag_inband_enabled(tBTA_AG_SCB *p_scb)
+{
+    /* if feature is enabled and no other scbs connected */
+    if (p_scb->inband_enabled && !bta_ag_other_scb_open(p_scb))
+    {
+        return TRUE;
+    }
+    else
+    {
+        return FALSE;
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_send_call_inds
+**
+** Description      Send call and callsetup indicators.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_send_call_inds(tBTA_AG_SCB *p_scb, tBTA_AG_RES result)
+{
+    UINT8 call = p_scb->call_ind;
+    UINT8 callsetup;
+
+    /* set new call and callsetup values based on BTA_AgResult */
+    callsetup = bta_ag_callsetup_ind_tbl[result];
+
+    if (result == BTA_AG_END_CALL_RES)
+    {
+        call = BTA_AG_CALL_INACTIVE;
+    }
+    else if (result == BTA_AG_IN_CALL_CONN_RES || result == BTA_AG_OUT_CALL_CONN_RES
+             || result == BTA_AG_IN_CALL_HELD_RES)
+    {
+        call = BTA_AG_CALL_ACTIVE;
+    }
+    else
+    {
+        call = p_scb->call_ind;
+    }
+
+    /* Send indicator function tracks if the values have actually changed */
+    bta_ag_send_ind(p_scb, BTA_AG_IND_CALL, call, FALSE);
+    bta_ag_send_ind(p_scb, BTA_AG_IND_CALLSETUP, callsetup, FALSE);
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_at_hsp_cback
+**
+** Description      AT command processing callback for HSP.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_at_hsp_cback(tBTA_AG_SCB *p_scb, UINT16 cmd, UINT8 arg_type,
+                                char *p_arg, INT16 int_arg)
+{
+    tBTA_AG_VAL val;
+
+    APPL_TRACE_DEBUG4("AT cmd:%d arg_type:%d arg:%d arg:%s", cmd, arg_type,
+                      int_arg, p_arg);
+
+    /* send OK */
+    bta_ag_send_ok(p_scb);
+
+    val.hdr.handle = bta_ag_scb_to_idx(p_scb);
+    val.hdr.app_id = p_scb->app_id;
+    val.num = (UINT16) int_arg;
+    BCM_STRNCPY_S(val.str, sizeof(val.str), p_arg, BTA_AG_AT_MAX_LEN);
+    val.str[BTA_AG_AT_MAX_LEN] = 0;
+
+    /* call callback with event */
+    (*bta_ag_cb.p_cback)(bta_ag_hsp_cb_evt[cmd], (tBTA_AG *) &val);
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_at_hfp_cback
+**
+** Description      AT command processing callback for HFP.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_at_hfp_cback(tBTA_AG_SCB *p_scb, UINT16 cmd, UINT8 arg_type,
+                                char *p_arg, INT16 int_arg)
+{
+    tBTA_AG_VAL     val;
+    tBTA_AG_EVT   event;
+    tBTA_AG_SCB     *ag_scb;
+    UINT32          i, ind_id;
+    UINT32          bia_masked_out;
+#if (BTM_WBS_INCLUDED == TRUE )
+    tBTA_AG_PEER_CODEC  codec_type, codec_sent;
+#endif
+
+    APPL_TRACE_DEBUG4("HFP AT cmd:%d arg_type:%d arg:%d arg:%s", cmd, arg_type,
+                      int_arg, p_arg);
+
+    val.hdr.handle = bta_ag_scb_to_idx(p_scb);
+    val.hdr.app_id = p_scb->app_id;
+    val.num = int_arg;
+    BCM_STRNCPY_S(val.str, sizeof(val.str), p_arg, BTA_AG_AT_MAX_LEN);
+    val.str[BTA_AG_AT_MAX_LEN] = 0;
+
+    event = bta_ag_hfp_cb_evt[cmd];
+
+    switch (cmd)
+    {
+        case BTA_AG_HF_CMD_A:
+        case BTA_AG_HF_CMD_VGS:
+        case BTA_AG_HF_CMD_VGM:
+        case BTA_AG_HF_CMD_CHUP:
+        case BTA_AG_HF_CMD_CBC:
+            /* send OK */
+            bta_ag_send_ok(p_scb);
+            break;
+
+        case BTA_AG_HF_CMD_BLDN:
+            /* Do not send OK, App will send error or OK depending on
+            ** last dial number enabled or not */
+            break;
+
+        case BTA_AG_HF_CMD_D:
+            /* Do not send OK for Dial cmds
+            ** Let application decide whether to send OK or ERROR*/
+
+            /* if mem dial cmd, make sure string contains only digits */
+            if(p_arg[0] == '>')
+            {
+                if(!utl_isintstr(p_arg+1))
+                {
+                    event = 0;
+                    bta_ag_send_error(p_scb, BTA_AG_ERR_INV_CHAR_IN_DSTR);
+                }
+            }
+            else if (p_arg[0] == 'V')   /* ATDV : Dial VoIP Call */
+            {
+                /* We do not check string. Code will be added later if needed. */
+                if(!((p_scb->peer_features & BTA_AG_PEER_FEAT_VOIP) && (p_scb->features & BTA_AG_FEAT_VOIP)))
+                {
+                    event = 0;
+                    bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED);
+                }
+            }
+            /* If dial cmd, make sure string contains only dial digits
+            ** Dial digits are 0-9, A-C, *, #, + */
+            else
+            {
+                if(!utl_isdialstr(p_arg))
+                {
+                    event = 0;
+                    bta_ag_send_error(p_scb, BTA_AG_ERR_INV_CHAR_IN_DSTR);
+                }
+            }
+            break;
+
+        case BTA_AG_HF_CMD_CCWA:
+            /* store setting */
+            p_scb->ccwa_enabled = (BOOLEAN) int_arg;
+
+            /* send OK */
+            bta_ag_send_ok(p_scb);
+            break;
+
+        case BTA_AG_HF_CMD_CHLD:
+            if (arg_type == BTA_AG_AT_TEST)
+            {
+                /* don't call callback */
+                event = 0;
+
+                /* send CHLD string */
+                /* Form string based on supported 1.5 feature */
+                if ((p_scb->peer_version >= HFP_VERSION_1_5) &&
+                    (p_scb->features & BTA_AG_FEAT_ECC) &&
+                    (p_scb->peer_features & BTA_AG_PEER_FEAT_ECC))
+                    bta_ag_send_result(p_scb, BTA_AG_RES_CHLD, p_bta_ag_cfg->chld_val_ecc, 0);
+                else
+                    bta_ag_send_result(p_scb, BTA_AG_RES_CHLD, p_bta_ag_cfg->chld_val, 0);
+
+                /* send OK */
+                bta_ag_send_ok(p_scb);
+
+                /* if service level conn. not already open, now it's open */
+                bta_ag_svc_conn_open(p_scb, NULL);
+
+            }
+            else
+            {
+                val.idx = bta_ag_parse_chld(p_scb, val.str);
+
+                if(val.idx && !((p_scb->features & BTA_AG_FEAT_ECC) && (p_scb->peer_features & BTA_AG_PEER_FEAT_ECC)))
+                {
+                    /* we do not support ECC, but HF is sending us a CHLD with call index*/
+                    event = 0;
+                    bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED);
+
+                }
+                else
+                {
+
+                /* If it is swap between calls, set call held indicator to 3(out of valid 0-2)
+                ** Application will set it back to 1
+                ** callheld indicator will be sent across to the peer. */
+                if(val.str[0] == '2')
+                {
+                    for (i = 0, ag_scb = &bta_ag_cb.scb[0]; i < BTA_AG_NUM_SCB; i++, ag_scb++)
+                    {
+                        if (ag_scb->in_use)
+                        {
+                            if((ag_scb->call_ind == BTA_AG_CALL_ACTIVE)
+                                && (ag_scb->callsetup_ind == BTA_AG_CALLSETUP_NONE))
+                                ag_scb->callheld_ind = BTA_AG_CALLHELD_NOACTIVE + 1;
+                        }
+                    }
+                }
+                }
+
+                /* Do not send OK. Let app decide after parsing the val str */
+                /* bta_ag_send_ok(p_scb); */
+            }
+            break;
+
+        case BTA_AG_HF_CMD_CIND:
+            if (arg_type == BTA_AG_AT_TEST)
+            {
+                /* don't call callback */
+                event = 0;
+
+                /* send CIND string, send OK */
+                bta_ag_send_result(p_scb, BTA_AG_RES_CIND, p_bta_ag_cfg->cind_info, 0);
+                bta_ag_send_ok(p_scb);
+            }
+            break;
+
+        case BTA_AG_HF_CMD_CLIP:
+            /* store setting, send OK */
+            p_scb->clip_enabled = (BOOLEAN) int_arg;
+            bta_ag_send_ok(p_scb);
+            break;
+
+        case BTA_AG_HF_CMD_CMER:
+            /* if parsed ok store setting, send OK */
+            if (bta_ag_parse_cmer(p_arg, &p_scb->cmer_enabled))
+            {
+                bta_ag_send_ok(p_scb);
+
+                /* if service level conn. not already open and our features and
+                ** peer features do not have 3-way, service level conn. now open
+                */
+                if (!p_scb->svc_conn &&
+                    !((p_scb->features & BTA_AG_FEAT_3WAY) && (p_scb->peer_features & BTA_AG_PEER_FEAT_3WAY)))
+                {
+                    bta_ag_svc_conn_open(p_scb, NULL);
+                }
+            }
+            else
+            {
+                bta_ag_send_error(p_scb, BTA_AG_ERR_INV_CHAR_IN_TSTR);
+            }
+            break;
+
+        case BTA_AG_HF_CMD_VTS:
+            /* check argument */
+            if (strlen(p_arg) == 1)
+            {
+                bta_ag_send_ok(p_scb);
+            }
+            else
+            {
+                event = 0;
+                bta_ag_send_error(p_scb, BTA_AG_ERR_INV_CHAR_IN_TSTR);
+            }
+            break;
+
+        case BTA_AG_HF_CMD_BINP:
+            /* if feature not set don't call callback, send ERROR */
+            if (!(p_scb->features & BTA_AG_FEAT_VTAG))
+            {
+                event = 0;
+                bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED);
+            }
+            break;
+
+        case BTA_AG_HF_CMD_BVRA:
+            /* if feature not supported don't call callback, send ERROR. App will send OK */
+            if (!(p_scb->features & BTA_AG_FEAT_VREC))
+            {
+                event = 0;
+                bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED);
+            }
+            break;
+
+        case BTA_AG_HF_CMD_BRSF:
+            /* store peer features */
+            p_scb->peer_features = (UINT16) int_arg;
+
+            /* send BRSF, send OK */
+            bta_ag_send_result(p_scb, BTA_AG_RES_BRSF, NULL,
+                               (INT16) (p_scb->features & BTA_AG_BSRF_FEAT_SPEC));
+            bta_ag_send_ok(p_scb);
+            break;
+
+        case BTA_AG_HF_CMD_NREC:
+            /* if feature send OK, else don't call callback, send ERROR */
+            if (p_scb->features & BTA_AG_FEAT_ECNR)
+            {
+                bta_ag_send_ok(p_scb);
+            }
+            else
+            {
+                event = 0;
+                bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED);
+            }
+            break;
+
+        case BTA_AG_HF_CMD_BTRH:
+            /* if feature send BTRH, send OK:, else don't call callback, send ERROR */
+            if (p_scb->features & BTA_AG_FEAT_BTRH)
+            {
+                /* If set command; send response and notify app */
+                if (arg_type == BTA_AG_AT_SET)
+                {
+                    for (i = 0, ag_scb = &bta_ag_cb.scb[0]; i < BTA_AG_NUM_SCB; i++, ag_scb++)
+                    {
+                        if (ag_scb->in_use)
+                        {
+                            bta_ag_send_result(ag_scb, BTA_AG_RES_BTRH, NULL, int_arg);
+                        }
+                    }
+                    bta_ag_send_ok(p_scb);
+                }
+                else /* Read Command */
+                {
+                    val.num = BTA_AG_BTRH_READ;
+                }
+            }
+            else
+            {
+                event = 0;
+                bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED);
+            }
+            break;
+
+        case BTA_AG_HF_CMD_COPS:
+            if (arg_type == BTA_AG_AT_SET)
+            {
+                /* don't call callback */
+                event = 0;
+
+                /* send OK */
+                bta_ag_send_ok(p_scb);
+            }
+            break;
+
+        case BTA_AG_HF_CMD_CMEE:
+            if (p_scb->features & BTA_AG_FEAT_EXTERR)
+            {
+                /* store setting */
+                p_scb->cmee_enabled = (BOOLEAN) int_arg;
+
+                /* send OK */
+                bta_ag_send_ok(p_scb);
+            }
+            else
+            {
+                bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED);
+            }
+            /* don't call callback */
+            event = 0;
+            break;
+
+        case BTA_AG_HF_CMD_BIA:
+            /* don't call callback */
+            event = 0;
+
+            bia_masked_out = p_scb->bia_masked_out;
+
+            /* Parse the indicator mask */
+            for (i = 0, ind_id = 1; (val.str[i] != 0) && (ind_id <= 20); i++, ind_id++)
+            {
+                if (val.str[i] == ',')
+                    continue;
+
+                if (val.str[i] == '0')
+                    bia_masked_out |= ((UINT32)1 << ind_id);
+                else if (val.str[i] == '1')
+                    bia_masked_out &= ~((UINT32)1 << ind_id);
+                else
+                    break;
+
+                i++;
+                if ( (val.str[i] != 0) && (val.str[i] != ',') )
+                    break;
+            }
+            if (val.str[i] == 0)
+            {
+                p_scb->bia_masked_out = bia_masked_out;
+                bta_ag_send_ok (p_scb);
+            }
+            else
+                bta_ag_send_error (p_scb, BTA_AG_ERR_INVALID_INDEX);
+            break;
+
+        case BTA_AG_HF_CMD_CNUM:
+            break;
+        case BTA_AG_HF_CMD_CLCC:
+            if(!(p_scb->features & BTA_AG_FEAT_ECS))
+            {
+                event = 0;
+                bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED);
+            }
+            break;
+
+#if (BTM_WBS_INCLUDED == TRUE )
+        case BTA_AG_HF_CMD_BAC:
+            bta_ag_send_ok(p_scb);
+
+            /* store available codecs from the peer */
+            if((p_scb->peer_features & BTA_AG_PEER_FEAT_CODEC) && (p_scb->features & BTA_AG_FEAT_CODEC))
+            {
+                p_scb->peer_codecs = bta_ag_parse_bac(p_scb, p_arg);
+                p_scb->codec_updated = TRUE;
+
+                if (p_scb->peer_codecs & BTA_AG_CODEC_MSBC)
+                {
+                    p_scb->sco_codec = UUID_CODEC_MSBC;
+                    APPL_TRACE_DEBUG0("Received AT+BAC, updating sco codec to MSBC");
+                }
+                else
+                {
+                    p_scb->sco_codec = UUID_CODEC_CVSD;
+                    APPL_TRACE_DEBUG0("Received AT+BAC, updating sco codec to CVSD");
+                }
+
+                /* Received BAC while in codec negotiation. */
+                if ((bta_ag_cb.sco.state == BTA_AG_SCO_CODEC_ST) && (bta_ag_cb.sco.p_curr_scb == p_scb))
+                {
+                    bta_ag_codec_negotiate (p_scb);
+                }
+            }
+            else
+            {
+                p_scb->peer_codecs = BTA_AG_CODEC_NONE;
+                APPL_TRACE_ERROR0("Unexpected CMD:AT+BAC, Codec Negotiation is not supported");
+            }
+            break;
+
+        case BTA_AG_HF_CMD_BCS:
+            /* stop cn timer */
+            bta_sys_stop_timer(&p_scb->cn_timer);
+
+            switch(int_arg)
+            {
+                case UUID_CODEC_CVSD:   codec_type = BTA_AG_CODEC_CVSD;     break;
+                case UUID_CODEC_MSBC:   codec_type = BTA_AG_CODEC_MSBC;     break;
+                default:
+                    APPL_TRACE_ERROR1("Unknown codec_uuid %d", int_arg);
+                    codec_type = 0xFFFF;
+                    break;
+            }
+
+            if (p_scb->codec_fallback)
+                codec_sent = BTA_AG_CODEC_CVSD;
+            else
+                codec_sent = p_scb->sco_codec;
+
+            if(codec_type == codec_sent)
+                bta_ag_sco_codec_nego(p_scb, TRUE);
+            else
+                bta_ag_sco_codec_nego(p_scb, FALSE);
+
+            bta_ag_send_ok(p_scb);
+            break;
+
+        case BTA_AG_HF_CMD_BCC:
+            bta_ag_send_ok(p_scb);
+            bta_ag_sco_open(p_scb, NULL);
+            break;
+#endif
+
+        default:
+            bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED);
+            break;
+    }
+
+    /* call callback */
+    if (event != 0)
+    {
+        (*bta_ag_cb.p_cback)(event, (tBTA_AG *) &val);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_at_err_cback
+**
+** Description      AT command parser error callback.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_at_err_cback(tBTA_AG_SCB *p_scb, BOOLEAN unknown, char *p_arg)
+{
+    tBTA_AG_VAL     val;
+
+    if(unknown && (!strlen(p_arg)))
+    {
+        APPL_TRACE_DEBUG0("Empty AT cmd string received");
+        bta_ag_send_ok(p_scb);
+        return;
+    }
+
+    /* if unknown AT command and configured to pass these to app */
+    if (unknown && (p_scb->features & BTA_AG_FEAT_UNAT))
+    {
+        val.hdr.handle = bta_ag_scb_to_idx(p_scb);
+        val.hdr.app_id = p_scb->app_id;
+        val.num = 0;
+        BCM_STRNCPY_S(val.str, sizeof(val.str), p_arg, BTA_AG_AT_MAX_LEN);
+        val.str[BTA_AG_AT_MAX_LEN] = 0;
+        (*bta_ag_cb.p_cback)(BTA_AG_AT_UNAT_EVT, (tBTA_AG *) &val);
+    }
+    else
+    {
+        bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_hsp_result
+**
+** Description      Handle API result for HSP connections.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_hsp_result(tBTA_AG_SCB *p_scb, tBTA_AG_API_RESULT *p_result)
+{
+    UINT8 code = bta_ag_trans_result[p_result->result];
+
+    APPL_TRACE_DEBUG1("bta_ag_hsp_result : res = %d", p_result->result);
+
+    switch(p_result->result)
+    {
+        case BTA_AG_SPK_RES:
+        case BTA_AG_MIC_RES:
+            bta_ag_send_result(p_scb, code, NULL, p_result->data.num);
+            break;
+
+        case BTA_AG_IN_CALL_RES:
+            /* tell sys to stop av if any */
+            bta_sys_sco_use(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+
+            /* if sco already opened or no inband ring send ring now */
+            if (bta_ag_sco_is_open(p_scb) || !bta_ag_inband_enabled(p_scb) ||
+                (p_scb->features & BTA_AG_FEAT_NOSCO))
+            {
+                bta_ag_send_ring(p_scb, (tBTA_AG_DATA *) p_result);
+            }
+            /* else open sco, send ring after sco opened */
+            else
+            {
+                /* HSPv1.2: AG shall not send RING if using in-band ring tone. */
+                if (p_scb->hsp_version >= HSP_VERSION_1_2)
+                    p_scb->post_sco = BTA_AG_POST_SCO_NONE;
+                else
+                    p_scb->post_sco = BTA_AG_POST_SCO_RING;
+
+                bta_ag_sco_open(p_scb, (tBTA_AG_DATA *) p_result);
+            }
+            break;
+
+        case BTA_AG_IN_CALL_CONN_RES:
+        case BTA_AG_OUT_CALL_ORIG_RES:
+            /* if incoming call connected stop ring timer */
+            if (p_result->result == BTA_AG_IN_CALL_CONN_RES)
+            {
+                bta_sys_stop_timer(&p_scb->act_timer);
+            }
+
+            if (!(p_scb->features & BTA_AG_FEAT_NOSCO))
+            {
+                /* if audio connected to this scb open sco */
+                if (p_result->data.audio_handle == bta_ag_scb_to_idx(p_scb))
+                {
+                    bta_ag_sco_open(p_scb, (tBTA_AG_DATA *) p_result);
+                }
+                /* else if no audio at call close sco */
+                else if (p_result->data.audio_handle == BTA_AG_HANDLE_NONE)
+                {
+                    bta_ag_sco_close(p_scb, (tBTA_AG_DATA *) p_result);
+                }
+            }
+            break;
+
+        case BTA_AG_END_CALL_RES:
+            /* stop ring timer */
+            bta_sys_stop_timer(&p_scb->act_timer);
+
+            /* close sco */
+            if ((bta_ag_sco_is_open(p_scb) || bta_ag_sco_is_opening(p_scb)) && !(p_scb->features & BTA_AG_FEAT_NOSCO))
+            {
+                bta_ag_sco_close(p_scb, (tBTA_AG_DATA *) p_result);
+            }
+            else
+            {
+                /* if av got suspended by this call, let it resume. */
+                bta_sys_sco_unuse(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+            }
+            break;
+
+        case BTA_AG_INBAND_RING_RES:
+            p_scb->inband_enabled = p_result->data.state;
+            APPL_TRACE_DEBUG1("inband_enabled set to %d", p_scb->inband_enabled);
+            break;
+
+        case BTA_AG_UNAT_RES:
+            if (p_result->data.ok_flag != BTA_AG_OK_ERROR)
+            {
+                if (p_result->data.str[0] != 0)
+                {
+                    bta_ag_send_result(p_scb, code, p_result->data.str, 0);
+                }
+
+                if (p_result->data.ok_flag == BTA_AG_OK_DONE)
+                    bta_ag_send_ok(p_scb);
+            }
+            else
+            {
+                bta_ag_send_error(p_scb, BTA_AG_ERR_INV_CHAR_IN_TSTR);
+            }
+            break;
+
+        default:
+            /* ignore all others */
+            break;
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_hfp_result
+**
+** Description      Handle API result for HFP connections.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_hfp_result(tBTA_AG_SCB *p_scb, tBTA_AG_API_RESULT *p_result)
+{
+    UINT8 code = bta_ag_trans_result[p_result->result];
+
+    APPL_TRACE_DEBUG1("bta_ag_hfp_result : res = %d", p_result->result);
+
+    switch(p_result->result)
+    {
+        case BTA_AG_SPK_RES:
+        case BTA_AG_MIC_RES:
+            bta_ag_send_result(p_scb, code, NULL, p_result->data.num);
+            break;
+
+        case BTA_AG_IN_CALL_RES:
+            /* tell sys to stop av if any */
+            bta_sys_sco_use(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+
+            /* store caller id string.
+             * append type info at the end.
+             * make sure a valid type info is passed.
+             * otherwise add 129 as default type */
+            if ((p_result->data.num < BTA_AG_CLIP_TYPE_MIN) || (p_result->data.num > BTA_AG_CLIP_TYPE_MAX))
+            {
+                if (p_result->data.num != BTA_AG_CLIP_TYPE_VOIP)
+                    p_result->data.num = BTA_AG_CLIP_TYPE_DEFAULT;
+            }
+
+            APPL_TRACE_DEBUG1("CLIP type :%d", p_result->data.num);
+            p_scb->clip[0] = 0;
+            if (p_result->data.str[0] != 0)
+                sprintf(p_scb->clip,"%s,%d", p_result->data.str, p_result->data.num);
+
+            /* send callsetup indicator */
+            if (p_scb->post_sco == BTA_AG_POST_SCO_CALL_END)
+            {
+                /* Need to sent 2 callsetup IND's(Call End and Incoming call) after SCO close. */
+                p_scb->post_sco = BTA_AG_POST_SCO_CALL_END_INCALL;
+            }
+            else
+            {
+                bta_ag_send_call_inds(p_scb, p_result->result);
+
+                /* if sco already opened or no inband ring send ring now */
+                if (bta_ag_sco_is_open(p_scb) || !bta_ag_inband_enabled(p_scb) ||
+                    (p_scb->features & BTA_AG_FEAT_NOSCO))
+                {
+                    bta_ag_send_ring(p_scb, (tBTA_AG_DATA *) p_result);
+                }
+                /* else open sco, send ring after sco opened */
+                else
+                {
+                    p_scb->post_sco = BTA_AG_POST_SCO_RING;
+                    bta_ag_sco_open(p_scb, (tBTA_AG_DATA *) p_result);
+                }
+            }
+            break;
+
+        case BTA_AG_IN_CALL_CONN_RES:
+            /* stop ring timer */
+            bta_sys_stop_timer(&p_scb->act_timer);
+
+            /* if sco not opened and we need to open it, open sco first
+            ** then send indicators
+            */
+            if (p_result->data.audio_handle == bta_ag_scb_to_idx(p_scb) &&
+                !bta_ag_sco_is_open(p_scb) && !(p_scb->features & BTA_AG_FEAT_NOSCO))
+            {
+                p_scb->post_sco = BTA_AG_POST_SCO_CALL_CONN;
+                bta_ag_sco_open(p_scb, (tBTA_AG_DATA *) p_result);
+            }
+            /* else if sco open and we need to close it, close sco first
+            ** then send indicators
+            */
+            else if (p_result->data.audio_handle == BTA_AG_HANDLE_NONE &&
+                     bta_ag_sco_is_open(p_scb) && !(p_scb->features & BTA_AG_FEAT_NOSCO))
+            {
+                p_scb->post_sco = BTA_AG_POST_SCO_CALL_CONN;
+                bta_ag_sco_close(p_scb, (tBTA_AG_DATA *) p_result);
+            }
+            /* else send indicators now */
+            else
+            {
+                bta_ag_send_call_inds(p_scb, p_result->result);
+            }
+            break;
+
+        case BTA_AG_IN_CALL_HELD_RES:
+            /* stop ring timer */
+            bta_sys_stop_timer(&p_scb->act_timer);
+
+            bta_ag_send_call_inds(p_scb, p_result->result);
+
+            break;
+
+        case BTA_AG_OUT_CALL_ORIG_RES:
+            /* if sco open and we need to close it, close sco first
+            ** then send indicators; else send indicators now
+            */
+            if (p_result->data.audio_handle == BTA_AG_HANDLE_NONE &&
+                bta_ag_sco_is_open(p_scb) && !(p_scb->features & BTA_AG_FEAT_NOSCO))
+            {
+                p_scb->post_sco = BTA_AG_POST_SCO_CALL_ORIG;
+                bta_ag_sco_close(p_scb, (tBTA_AG_DATA *) p_result);
+            }
+            else
+            {
+                bta_ag_send_call_inds(p_scb, p_result->result);
+                if (p_result->data.audio_handle == bta_ag_scb_to_idx(p_scb) &&
+                    !(p_scb->features & BTA_AG_FEAT_NOSCO))
+                {
+                    bta_ag_sco_open(p_scb, (tBTA_AG_DATA *) p_result);
+                }
+            }
+            break;
+
+        case BTA_AG_OUT_CALL_ALERT_RES:
+            /* send indicators */
+            bta_ag_send_call_inds(p_scb, p_result->result);
+            if (p_result->data.audio_handle == bta_ag_scb_to_idx(p_scb) &&
+                !(p_scb->features & BTA_AG_FEAT_NOSCO))
+            {
+                bta_ag_sco_open(p_scb, (tBTA_AG_DATA *) p_result);
+            }
+            break;
+
+        case BTA_AG_OUT_CALL_CONN_RES:
+            /* send indicators */
+            bta_ag_send_call_inds(p_scb, p_result->result);
+
+            /* open or close sco */
+            if (!(p_scb->features & BTA_AG_FEAT_NOSCO))
+            {
+                if (p_result->data.audio_handle == bta_ag_scb_to_idx(p_scb))
+                {
+                    bta_ag_sco_open(p_scb, (tBTA_AG_DATA *) p_result);
+                }
+                else if (p_result->data.audio_handle == BTA_AG_HANDLE_NONE)
+                {
+                    bta_ag_sco_close(p_scb, (tBTA_AG_DATA *) p_result);
+                }
+            }
+            break;
+
+        case BTA_AG_CALL_CANCEL_RES:
+            /* send indicators */
+            bta_ag_send_call_inds(p_scb, p_result->result);
+            break;
+
+        case BTA_AG_END_CALL_RES:
+            /* stop ring timer */
+            bta_sys_stop_timer(&p_scb->act_timer);
+
+            /* if sco open, close sco then send indicator values */
+            if ((bta_ag_sco_is_open(p_scb) || bta_ag_sco_is_opening(p_scb)) && !(p_scb->features & BTA_AG_FEAT_NOSCO))
+            {
+                p_scb->post_sco = BTA_AG_POST_SCO_CALL_END;
+                bta_ag_sco_close(p_scb, (tBTA_AG_DATA *) p_result);
+            }
+            else if (p_scb->post_sco == BTA_AG_POST_SCO_CALL_END_INCALL)
+            {
+                /* sco closing for outgoing call because of incoming call */
+                /* Send only callsetup end indicator after sco close */
+                p_scb->post_sco = BTA_AG_POST_SCO_CALL_END;
+            }
+            else
+            {
+                bta_ag_send_call_inds(p_scb, p_result->result);
+
+                /* if av got suspended by this call, let it resume. */
+                bta_sys_sco_unuse(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+            }
+            break;
+
+        case BTA_AG_INBAND_RING_RES:
+            p_scb->inband_enabled = p_result->data.state;
+            APPL_TRACE_DEBUG1("inband_enabled set to %d", p_scb->inband_enabled);
+            bta_ag_send_result(p_scb, code, NULL, p_result->data.state);
+            break;
+
+        case BTA_AG_CIND_RES:
+            /* store local values */
+            p_scb->call_ind = p_result->data.str[0] - '0';
+            p_scb->callsetup_ind = p_result->data.str[2] - '0';
+            p_scb->service_ind = p_result->data.str[4] - '0';
+            p_scb->signal_ind = p_result->data.str[6] - '0';
+            p_scb->roam_ind = p_result->data.str[8] - '0';
+            p_scb->battchg_ind = p_result->data.str[10] - '0';
+            APPL_TRACE_DEBUG2("cind call:%d callsetup:%d", p_scb->call_ind, p_scb->callsetup_ind);
+
+            bta_ag_send_result(p_scb, code, p_result->data.str, 0);
+            bta_ag_send_ok(p_scb);
+            break;
+
+        case BTA_AG_BINP_RES:
+        case BTA_AG_CNUM_RES:
+        case BTA_AG_CLCC_RES:
+        case BTA_AG_COPS_RES:
+            if (p_result->data.ok_flag != BTA_AG_OK_ERROR)
+            {
+                if (p_result->data.str[0] != 0)
+                {
+                   bta_ag_send_result(p_scb, code, p_result->data.str, 0);
+                }
+
+                if (p_result->data.ok_flag == BTA_AG_OK_DONE)
+                    bta_ag_send_ok(p_scb);
+            }
+            else
+            {
+                bta_ag_send_error(p_scb, p_result->data.errcode);
+            }
+            break;
+
+
+        case BTA_AG_UNAT_RES:
+            if (p_result->data.ok_flag != BTA_AG_OK_ERROR)
+            {
+                if (p_result->data.str[0] != 0)
+                {
+                    bta_ag_process_unat_res(p_result->data.str);
+                    APPL_TRACE_DEBUG1("BTA_AG_RES :%s",p_result->data.str);
+                    bta_ag_send_result(p_scb, code, p_result->data.str, 0);
+                }
+
+                if (p_result->data.ok_flag == BTA_AG_OK_DONE)
+                    bta_ag_send_ok(p_scb);
+            }
+            else
+            {
+                bta_ag_send_error(p_scb, p_result->data.errcode);
+            }
+            break;
+
+        case BTA_AG_CALL_WAIT_RES:
+            if (p_scb->ccwa_enabled)
+            {
+                bta_ag_send_result(p_scb, code, p_result->data.str, 0);
+            }
+            bta_ag_send_call_inds(p_scb, p_result->result);
+            break;
+
+        case BTA_AG_IND_RES:
+            bta_ag_send_ind(p_scb, p_result->data.ind.id, p_result->data.ind.value, FALSE);
+            break;
+
+        case BTA_AG_BVRA_RES:
+            bta_ag_send_result(p_scb, code, NULL, p_result->data.state);
+            break;
+
+        case BTA_AG_BTRH_RES:
+            if (p_result->data.ok_flag != BTA_AG_OK_ERROR)
+            {
+                /* Don't respond to read if not in response & hold state */
+                if (p_result->data.num != BTA_AG_BTRH_NO_RESP)
+                {
+                    bta_ag_send_result(p_scb, code, NULL, p_result->data.num);
+                }
+
+                /* In case of a response to a read request we need to send OK */
+                if (p_result->data.ok_flag == BTA_AG_OK_DONE)
+                    bta_ag_send_ok(p_scb);
+            }
+            else
+            {
+                bta_ag_send_error(p_scb, p_result->data.errcode);
+            }
+            break;
+
+       default:
+            break;
+    }
+}
+
+
+/*******************************************************************************
+**
+** Function         bta_ag_result
+**
+** Description      Handle API result.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_result(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+    if (p_scb->conn_service == BTA_AG_HSP)
+    {
+        bta_ag_hsp_result(p_scb, &p_data->api_result);
+    }
+    else
+    {
+        bta_ag_hfp_result(p_scb, &p_data->api_result);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_setcodec
+**
+** Description      Handle API SetCodec
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_setcodec(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+#if (BTM_WBS_INCLUDED == TRUE )
+    tBTA_AG_PEER_CODEC codec_type = p_data->api_setcodec.codec;
+
+    /* Check if the requested codec type is valid */
+    if((codec_type != BTA_AG_CODEC_NONE) &&
+       (codec_type != BTA_AG_CODEC_CVSD) &&
+       (codec_type != BTA_AG_CODEC_MSBC))
+    {
+        APPL_TRACE_ERROR1("bta_ag_setcodec error: unsupported codec type %d", codec_type);
+        return;
+    }
+
+    if((p_scb->peer_codecs & codec_type) || (codec_type == BTA_AG_CODEC_NONE) || (codec_type == BTA_AG_CODEC_CVSD))
+    {
+        p_scb->sco_codec = codec_type;
+        p_scb->codec_updated = TRUE;
+        APPL_TRACE_DEBUG1("bta_ag_setcodec: Updated codec type %d", codec_type);
+    }
+    else
+    {
+        APPL_TRACE_ERROR1("bta_ag_setcodec error: unsupported codec type %d", codec_type);
+    }
+#else
+    UNUSED(p_scb);
+    UNUSED(p_data);
+#endif
+}
+
+
+#if (BTM_WBS_INCLUDED == TRUE )
+/*******************************************************************************
+**
+** Function         bta_ag_send_bcs
+**
+** Description      Send +BCS AT command to peer.
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_send_bcs(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+    UINT16 codec_uuid;
+
+    if (p_scb->codec_fallback)
+    {
+        codec_uuid = UUID_CODEC_CVSD;
+    }
+    else
+    {
+        switch(p_scb->sco_codec)
+        {
+            case BTA_AG_CODEC_NONE:     codec_uuid = UUID_CODEC_CVSD;   break;
+            case BTA_AG_CODEC_CVSD:     codec_uuid = UUID_CODEC_CVSD;   break;
+            case BTA_AG_CODEC_MSBC:     codec_uuid = UUID_CODEC_MSBC;   break;
+            default:
+                APPL_TRACE_ERROR1("bta_ag_send_bcs: unknown codec %d, use CVSD", p_scb->sco_codec);
+                codec_uuid = UUID_CODEC_CVSD;
+                break;
+        }
+    }
+
+    /* send +BCS */
+    bta_ag_send_result(p_scb, BTA_AG_RES_BCS, NULL, codec_uuid);
+
+}
+#endif
+
+/*******************************************************************************
+**
+** Function         bta_ag_send_ring
+**
+** Description      Send RING result code to peer.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_send_ring(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+    UNUSED(p_data);
+
+#if defined(BTA_AG_MULTI_RESULT_INCLUDED) && (BTA_AG_MULTI_RESULT_INCLUDED == TRUE)
+    tBTA_AG_MULTI_RESULT_CB m_res_cb;
+
+    if (p_scb->conn_service == BTA_AG_HFP && p_scb->clip_enabled && p_scb->clip[0] != 0)
+    {
+        memset(&m_res_cb, NULL, sizeof(tBTA_AG_MULTI_RESULT_CB));
+
+        m_res_cb.num_result = 2;
+        AT_SET_RES_CB(m_res_cb.res_cb[0], BTA_AG_RES_RING, NULL, 0)
+        AT_SET_RES_CB(m_res_cb.res_cb[1], BTA_AG_RES_CLIP, p_scb->clip, 0)
+
+        bta_ag_send_multi_result(p_scb, &m_res_cb);
+    }
+    else
+    {
+        /* send RING ONLY */
+        bta_ag_send_result(p_scb, BTA_AG_RES_RING, NULL, 0);
+    }
+#else
+    /* send RING */
+    bta_ag_send_result(p_scb, BTA_AG_RES_RING, NULL, 0);
+
+    /* if HFP and clip enabled and clip data send CLIP */
+    if (p_scb->conn_service == BTA_AG_HFP && p_scb->clip_enabled && p_scb->clip[0] != 0)
+    {
+        bta_ag_send_result(p_scb, BTA_AG_RES_CLIP, p_scb->clip, 0);
+    }
+#endif
+
+    /* restart ring timer */
+    bta_sys_start_timer(&p_scb->act_timer, BTA_AG_RING_TOUT_EVT, BTA_AG_RING_TOUT);
+}
+
+
diff --git a/bta/hf_client/bta_hf_client_int.h b/bta/hf_client/bta_hf_client_int.h
new file mode 100644
index 0000000..b0d1b1d
--- /dev/null
+++ b/bta/hf_client/bta_hf_client_int.h
@@ -0,0 +1,423 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2003-2012 Broadcom Corporation
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *  This is the private interface file for the BTA audio gateway.
+ *
+ ******************************************************************************/
+#ifndef BTA_AG_INT_H
+#define BTA_AG_INT_H
+
+#include "bta_sys.h"
+#include "bta_api.h"
+#include "bta_ag_api.h"
+#include "bta_ag_at.h"
+
+/* Send RING & CLIP in one AT cmd */
+#ifndef BTA_AG_MULTI_RESULT_INCLUDED
+#define BTA_AG_MULTI_RESULT_INCLUDED      FALSE
+#endif
+
+/* Replace : in VGS and VGM for HSP */
+#ifndef BTA_HSP_RESULT_REPLACE_COLON
+#define BTA_HSP_RESULT_REPLACE_COLON      TRUE
+#endif
+
+/*****************************************************************************
+**  Constants
+*****************************************************************************/
+#define HFP_VERSION_1_1         0x0101
+#define HFP_VERSION_1_5         0x0105
+#define HFP_VERSION_1_6         0x0106
+
+#define HSP_VERSION_1_0         0x0100
+#define HSP_VERSION_1_2         0x0102
+
+/* Number of SCBs (AG service instances that can be registered) */
+#ifndef BTA_AG_NUM_SCB
+#define BTA_AG_NUM_SCB          2
+#endif
+
+/* Timer to wait for retry in case of collision */
+#ifndef BTA_AG_COLLISION_TIMER
+#define BTA_AG_COLLISION_TIMER  2000
+#endif
+
+/* RFCOMM MTU SIZE */
+#define BTA_AG_MTU              256
+
+/* Internal profile indexes */
+#define BTA_AG_HSP              0       /* index for HSP */
+#define BTA_AG_HFP              1       /* index for HFP */
+#define BTA_AG_NUM_IDX          2       /* number of profile indexes */
+
+/* profile role for connection */
+#define BTA_AG_ACP              0       /* accepted connection */
+#define BTA_AG_INT              1       /* initiating connection */
+
+/* feature mask that matches spec */
+#define BTA_AG_BSRF_FEAT_SPEC        (BTA_AG_FEAT_3WAY | BTA_AG_FEAT_ECNR    | \
+                                      BTA_AG_FEAT_VREC | BTA_AG_FEAT_INBAND  | \
+                                      BTA_AG_FEAT_VTAG | BTA_AG_FEAT_REJECT  | \
+                                      BTA_AG_FEAT_ECS  | BTA_AG_FEAT_ECC     | \
+                                      BTA_AG_FEAT_EXTERR | BTA_AG_FEAT_CODEC | \
+                                      BTA_AG_FEAT_VOIP)
+
+#define BTA_AG_SDP_FEAT_SPEC         (BTA_AG_FEAT_3WAY | BTA_AG_FEAT_ECNR    | \
+                                      BTA_AG_FEAT_VREC | BTA_AG_FEAT_INBAND  | \
+                                      BTA_AG_FEAT_VTAG)
+
+enum
+{
+    /* these events are handled by the state machine */
+    BTA_AG_API_REGISTER_EVT = BTA_SYS_EVT_START(BTA_ID_AG),
+    BTA_AG_API_DEREGISTER_EVT,
+    BTA_AG_API_OPEN_EVT,
+    BTA_AG_API_CLOSE_EVT,
+    BTA_AG_API_AUDIO_OPEN_EVT,
+    BTA_AG_API_AUDIO_CLOSE_EVT,
+    BTA_AG_API_RESULT_EVT,
+    BTA_AG_API_SETCODEC_EVT,
+    BTA_AG_RFC_OPEN_EVT,
+    BTA_AG_RFC_CLOSE_EVT,
+    BTA_AG_RFC_SRV_CLOSE_EVT,
+    BTA_AG_RFC_DATA_EVT,
+    BTA_AG_SCO_OPEN_EVT,
+    BTA_AG_SCO_CLOSE_EVT,
+    BTA_AG_DISC_ACP_RES_EVT,
+    BTA_AG_DISC_INT_RES_EVT,
+    BTA_AG_DISC_OK_EVT,
+    BTA_AG_DISC_FAIL_EVT,
+    BTA_AG_CI_RX_WRITE_EVT,
+    BTA_AG_RING_TOUT_EVT,
+    BTA_AG_SVC_TOUT_EVT,
+    BTA_AG_CI_SCO_DATA_EVT,
+    BTA_AG_CI_SLC_READY_EVT,
+    BTA_AG_MAX_EVT,
+
+    /* these events are handled outside of the state machine */
+    BTA_AG_API_ENABLE_EVT,
+    BTA_AG_API_DISABLE_EVT
+};
+
+/* Actions to perform after a SCO event */
+enum
+{
+    BTA_AG_POST_SCO_NONE,       /* no action */
+    BTA_AG_POST_SCO_CLOSE_RFC,  /* close RFCOMM channel after SCO closes */
+    BTA_AG_POST_SCO_RING,       /* send RING result code after SCO opens */
+    BTA_AG_POST_SCO_CALL_CONN,  /* send call indicators after SCO opens/closes */
+    BTA_AG_POST_SCO_CALL_ORIG,  /* send call indicators after SCO closes */
+    BTA_AG_POST_SCO_CALL_END,   /* send call indicators after SCO closes */
+    BTA_AG_POST_SCO_CALL_END_INCALL   /* send call indicators for end call & incoming call after SCO closes */
+};
+
+/* sco states */
+enum
+{
+    BTA_AG_SCO_SHUTDOWN_ST,     /* no sco listening, all sco connections closed */
+    BTA_AG_SCO_LISTEN_ST,       /* sco listening */
+#if (BTM_WBS_INCLUDED == TRUE )
+    BTA_AG_SCO_CODEC_ST,        /* sco codec negotiation */
+#endif
+    BTA_AG_SCO_OPENING_ST,      /* sco connection opening */
+    BTA_AG_SCO_OPEN_CL_ST,      /* opening sco connection being closed */
+    BTA_AG_SCO_OPEN_XFER_ST,    /* opening sco connection being transferred */
+    BTA_AG_SCO_OPEN_ST,         /* sco open */
+    BTA_AG_SCO_CLOSING_ST,      /* sco closing */
+    BTA_AG_SCO_CLOSE_OP_ST,     /* closing sco being opened */
+    BTA_AG_SCO_CLOSE_XFER_ST,   /* closing sco being transferred */
+    BTA_AG_SCO_SHUTTING_ST      /* sco shutting down */
+};
+
+/*****************************************************************************
+**  Data types
+*****************************************************************************/
+
+/* data type for BTA_AG_API_ENABLE_EVT */
+typedef struct
+{
+    BT_HDR              hdr;
+    tBTA_AG_PARSE_MODE  parse_mode;
+    tBTA_AG_CBACK      *p_cback;
+} tBTA_AG_API_ENABLE;
+
+/* data type for BTA_AG_API_REGISTER_EVT */
+typedef struct
+{
+    BT_HDR              hdr;
+    char                p_name[2][BTA_SERVICE_NAME_LEN+1];
+    tBTA_SERVICE_MASK   services;
+    tBTA_SEC            sec_mask;
+    tBTA_AG_FEAT        features;
+    UINT8               app_id;
+} tBTA_AG_API_REGISTER;
+
+/* data type for BTA_AG_API_OPEN_EVT */
+typedef struct
+{
+    BT_HDR              hdr;
+    BD_ADDR             bd_addr;
+    tBTA_SERVICE_MASK   services;
+    tBTA_SEC            sec_mask;
+} tBTA_AG_API_OPEN;
+
+/* data type for BTA_AG_API_RESULT_EVT */
+typedef struct
+{
+    BT_HDR            hdr;
+    tBTA_AG_RES       result;
+    tBTA_AG_RES_DATA  data;
+} tBTA_AG_API_RESULT;
+
+/* data type for BTA_AG_API_SETCODEC_EVT */
+typedef struct
+{
+    BT_HDR              hdr;
+    tBTA_AG_PEER_CODEC  codec;
+} tBTA_AG_API_SETCODEC;
+
+/* data type for BTA_AG_DISC_RESULT_EVT */
+typedef struct
+{
+    BT_HDR          hdr;
+    UINT16          status;
+} tBTA_AG_DISC_RESULT;
+
+/* data type for RFCOMM events */
+typedef struct
+{
+    BT_HDR          hdr;
+    UINT16          port_handle;
+} tBTA_AG_RFC;
+
+/* data type for BTA_AG_CI_RX_WRITE_EVT */
+typedef struct
+{
+    BT_HDR          hdr;
+//    char            p_data[BTA_AG_MTU+1];
+} tBTA_AG_CI_RX_WRITE;
+
+/* union of all event datatypes */
+typedef union
+{
+    BT_HDR                  hdr;
+    tBTA_AG_API_ENABLE      api_enable;
+    tBTA_AG_API_REGISTER    api_register;
+    tBTA_AG_API_OPEN        api_open;
+    tBTA_AG_API_RESULT      api_result;
+#if (BTM_WBS_INCLUDED == TRUE )
+    tBTA_AG_API_SETCODEC    api_setcodec;
+#endif
+    tBTA_AG_DISC_RESULT     disc_result;
+    tBTA_AG_RFC             rfc;
+    tBTA_AG_CI_RX_WRITE     ci_rx_write;
+} tBTA_AG_DATA;
+
+/* type for each profile */
+typedef struct
+{
+    UINT32          sdp_handle;
+    UINT8           scn;
+} tBTA_AG_PROFILE;
+
+/* type for each service control block */
+typedef struct
+{
+    char                clip[BTA_AG_AT_MAX_LEN+1]; /* number string used for CLIP */
+    UINT16              serv_handle[BTA_AG_NUM_IDX]; /* RFCOMM server handles */
+    tBTA_AG_AT_CB       at_cb;          /* AT command interpreter */
+    TIMER_LIST_ENT      act_timer;     /* ring timer */
+    BD_ADDR             peer_addr;      /* peer bd address */
+    tSDP_DISCOVERY_DB   *p_disc_db;     /* pointer to discovery database */
+    tBTA_SERVICE_MASK   reg_services;   /* services specified in register API */
+    tBTA_SERVICE_MASK   open_services;  /* services specified in open API */
+    UINT16              conn_handle;    /* RFCOMM handle of connected service */
+    tBTA_SEC            serv_sec_mask;  /* server security mask */
+    tBTA_SEC            cli_sec_mask;   /* client security mask */
+    tBTA_AG_FEAT        features;       /* features registered by application */
+    tBTA_AG_PEER_FEAT   peer_features;  /* peer device features */
+    UINT16              peer_version;   /* profile version of peer device */
+    UINT16              hsp_version;    /* HSP profile version */
+#if (BTM_WBS_INCLUDED == TRUE )
+    tBTA_AG_PEER_CODEC  peer_codecs;    /* codecs for eSCO supported by the peer */
+    tBTA_AG_PEER_CODEC  sco_codec;      /* codec to be used for eSCO connection */
+    tBTA_AG_PEER_CODEC  inuse_codec;    /* codec being used for the current SCO connection */
+    BOOLEAN             codec_updated;  /* set to TRUE whenever the app updates codec type */
+    BOOLEAN             codec_fallback; /* If sco nego fails for mSBC, fallback to CVSD */
+    TIMER_LIST_ENT      cn_timer;       /* codec negotiation timer */
+#endif
+    UINT16              sco_idx;        /* SCO handle */
+    BOOLEAN             in_use;         /* scb in use */
+    BOOLEAN             dealloc;        /* TRUE if service shutting down */
+    BOOLEAN             clip_enabled;   /* set to TRUE if HF enables CLIP reporting */
+    BOOLEAN             ccwa_enabled;   /* set to TRUE if HF enables CCWA reporting */
+    BOOLEAN             cmer_enabled;   /* set to TRUE if HF enables CMER reporting */
+    BOOLEAN             cmee_enabled;   /* set to TRUE if HF enables CME ERROR reporting */
+    BOOLEAN             inband_enabled; /* set to TRUE if inband ring enabled */
+    BOOLEAN             svc_conn;       /* set to TRUE when service level connection up */
+    TIMER_LIST_ENT      colli_timer;    /* Collision timer */
+    BOOLEAN             colli_tmr_on;   /* TRUE if collision timer is active */
+    UINT8               state;          /* state machine state */
+    UINT8               conn_service;   /* connected service */
+    UINT8               peer_scn;       /* peer scn */
+    UINT8               app_id;         /* application id */
+    UINT8               role;           /* initiator/acceptor role */
+    UINT8               post_sco;       /* action to perform after sco event */
+    UINT8               call_ind;       /* CIEV call indicator value */
+    UINT8               callsetup_ind;  /* CIEV callsetup indicator value */
+    UINT8               service_ind;    /* CIEV service indicator value */
+    UINT8               signal_ind;     /* CIEV signal indicator value */
+    UINT8               roam_ind;       /* CIEV roam indicator value */
+    UINT8               battchg_ind;    /* CIEV battery charge indicator value */
+    UINT8               callheld_ind;   /* CIEV call held indicator value */
+    BOOLEAN             retry_with_sco_only; /* indicator to try with SCO only when eSCO fails */
+    UINT32              bia_masked_out; /* indicators HF does not want us to send */
+} tBTA_AG_SCB;
+
+/* type for sco data */
+typedef struct
+{
+    tBTM_ESCO_CONN_REQ_EVT_DATA  conn_data;     /* SCO data for pending conn request */
+    tBTA_AG_SCB                 *p_curr_scb;    /* SCB associated with SCO connection */
+    tBTA_AG_SCB                 *p_xfer_scb;    /* SCB associated with SCO transfer */
+    UINT16                      cur_idx;        /* SCO handle */
+    UINT8                       state;          /* SCO state variable */
+    BOOLEAN                     param_updated;  /* if params were updated to non-default */
+    tBTM_ESCO_PARAMS            params;         /* ESCO parameters */
+} tBTA_AG_SCO_CB;
+
+
+/* type for AG control block */
+typedef struct
+{
+    tBTA_AG_SCB         scb[BTA_AG_NUM_SCB];        /* service control blocks */
+    tBTA_AG_PROFILE     profile[BTA_AG_NUM_IDX];    /* profile-specific data */
+    tBTA_AG_SCO_CB      sco;                        /* SCO data */
+    tBTA_AG_CBACK       *p_cback;                   /* application callback */
+    tBTA_AG_PARSE_MODE  parse_mode;                 /* parse/pass-through mode */
+} tBTA_AG_CB;
+
+/*****************************************************************************
+**  Global data
+*****************************************************************************/
+
+/* constant lookup tables */
+extern const UINT16 bta_ag_uuid[BTA_AG_NUM_IDX];
+extern const UINT8 bta_ag_sec_id[BTA_AG_NUM_IDX];
+extern const tBTA_AG_AT_CMD *bta_ag_at_tbl[BTA_AG_NUM_IDX];
+
+/* control block declaration */
+#if BTA_DYNAMIC_MEMORY == FALSE
+extern tBTA_AG_CB bta_ag_cb;
+#else
+extern tBTA_AG_CB *bta_ag_cb_ptr;
+#define bta_ag_cb (*bta_ag_cb_ptr)
+#endif
+
+/* config struct */
+extern tBTA_AG_CFG *p_bta_ag_cfg;
+
+/*****************************************************************************
+**  Function prototypes
+*****************************************************************************/
+
+/* main functions */
+extern void bta_ag_scb_dealloc(tBTA_AG_SCB *p_scb);
+extern UINT16 bta_ag_scb_to_idx(tBTA_AG_SCB *p_scb);
+extern tBTA_AG_SCB *bta_ag_scb_by_idx(UINT16 idx);
+extern UINT8 bta_ag_service_to_idx(tBTA_SERVICE_MASK services);
+extern UINT16 bta_ag_idx_by_bdaddr(BD_ADDR peer_addr);
+extern BOOLEAN bta_ag_other_scb_open(tBTA_AG_SCB *p_curr_scb);
+extern tBTA_AG_SCB *bta_ag_get_other_idle_scb (tBTA_AG_SCB *p_curr_scb);
+extern void bta_ag_sm_execute(tBTA_AG_SCB *p_scb, UINT16 event, tBTA_AG_DATA *p_data);
+extern BOOLEAN bta_ag_hdl_event(BT_HDR *p_msg);
+extern void bta_ag_collision_cback (tBTA_SYS_CONN_STATUS status, UINT8 id,
+                                    UINT8 app_id, BD_ADDR peer_addr);
+extern void bta_ag_resume_open (tBTA_AG_SCB *p_scb);
+
+/* SDP functions */
+extern BOOLEAN bta_ag_add_record(UINT16 service_uuid, char *p_service_name, UINT8 scn,
+                                 tBTA_AG_FEAT features, UINT32 sdp_handle);
+extern void bta_ag_create_records(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_del_records(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern BOOLEAN bta_ag_sdp_find_attr(tBTA_AG_SCB *p_scb, tBTA_SERVICE_MASK service);
+extern void bta_ag_do_disc(tBTA_AG_SCB *p_scb, tBTA_SERVICE_MASK service);
+extern void bta_ag_free_db(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+
+/* RFCOMM functions */
+extern void bta_ag_start_servers(tBTA_AG_SCB *p_scb, tBTA_SERVICE_MASK services);
+extern void bta_ag_close_servers(tBTA_AG_SCB *p_scb, tBTA_SERVICE_MASK services);
+extern BOOLEAN bta_ag_is_server_closed (tBTA_AG_SCB *p_scb);
+extern void bta_ag_rfc_do_close(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_rfc_do_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+
+/* SCO functions */
+extern BOOLEAN bta_ag_sco_is_open(tBTA_AG_SCB *p_scb);
+extern BOOLEAN bta_ag_sco_is_opening(tBTA_AG_SCB *p_scb);
+extern void bta_ag_sco_conn_rsp(tBTA_AG_SCB *p_scb, tBTM_ESCO_CONN_REQ_EVT_DATA *p_data);
+
+/* AT command functions */
+extern void bta_ag_at_hsp_cback(tBTA_AG_SCB *p_scb, UINT16 cmd, UINT8 arg_type,
+                                char *p_arg, INT16 int_arg);
+extern void bta_ag_at_hfp_cback(tBTA_AG_SCB *p_scb, UINT16 cmd, UINT8 arg_type,
+                                char *p_arg, INT16 int_arg);
+extern void bta_ag_at_err_cback(tBTA_AG_SCB *p_scb, BOOLEAN unknown, char *p_arg);
+extern BOOLEAN bta_ag_inband_enabled(tBTA_AG_SCB *p_scb);
+extern void bta_ag_send_call_inds(tBTA_AG_SCB *p_scb, tBTA_AG_RES result);
+
+/* Action functions */
+extern void bta_ag_register(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_deregister(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_start_dereg(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_start_close(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_start_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_disc_int_res(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_disc_acp_res(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_disc_fail(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_open_fail(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_rfc_fail(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_rfc_close(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_rfc_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_rfc_acp_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_rfc_data(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_sco_listen(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_sco_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_sco_close(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+#if (BTM_WBS_INCLUDED == TRUE )
+extern void bta_ag_sco_codec_nego(tBTA_AG_SCB *p_scb, BOOLEAN result);
+extern void bta_ag_codec_negotiate (tBTA_AG_SCB *p_scb);
+#endif
+extern void bta_ag_sco_shutdown(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_sco_conn_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_sco_conn_close(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_post_sco_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_post_sco_close(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_svc_conn_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_result(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_setcodec(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+#if (BTM_WBS_INCLUDED == TRUE )
+extern void bta_ag_send_bcs(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+#endif
+extern void bta_ag_send_ring(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_ci_sco_data(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_set_esco_param(BOOLEAN set_reset, tBTM_ESCO_PARAMS *param);
+extern void bta_ag_ci_rx_data(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_rcvd_slc_ready(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+#endif /* BTA_AG_INT_H */
diff --git a/bta/hf_client/bta_hf_client_main.c b/bta/hf_client/bta_hf_client_main.c
new file mode 100644
index 0000000..bae992b
--- /dev/null
+++ b/bta/hf_client/bta_hf_client_main.c
@@ -0,0 +1,1015 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2003-2012 Broadcom Corporation
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *  This is the main implementation file for the BTA audio gateway.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+#include "bta_api.h"
+#include "bta_sys.h"
+#include "bta_ag_co.h"
+#include "bta_ag_int.h"
+#include "bd.h"
+#include "utl.h"
+
+/*****************************************************************************
+** Constants and types
+*****************************************************************************/
+#ifndef BTA_AG_DEBUG
+#define BTA_AG_DEBUG FALSE
+#endif
+
+#if BTA_AG_DEBUG == TRUE
+static char *bta_ag_evt_str(UINT16 event, tBTA_AG_RES result);
+static char *bta_ag_state_str(UINT8 state);
+#endif
+
+/* state machine states */
+enum
+{
+    BTA_AG_INIT_ST,
+    BTA_AG_OPENING_ST,
+    BTA_AG_OPEN_ST,
+    BTA_AG_CLOSING_ST
+};
+
+/* state machine action enumeration list */
+enum
+{
+    BTA_AG_REGISTER,
+    BTA_AG_DEREGISTER,
+    BTA_AG_START_OPEN,
+    BTA_AG_RFC_DO_OPEN,
+    BTA_AG_RFC_DO_CLOSE,
+    BTA_AG_START_DEREG,
+    BTA_AG_START_CLOSE,
+    BTA_AG_RFC_OPEN,
+    BTA_AG_OPEN_FAIL,
+    BTA_AG_RFC_ACP_OPEN,
+    BTA_AG_RFC_CLOSE,
+    BTA_AG_RFC_FAIL,
+    BTA_AG_RFC_DATA,
+    BTA_AG_DISC_INT_RES,
+    BTA_AG_DISC_FAIL,
+    BTA_AG_DISC_ACP_RES,
+    BTA_AG_FREE_DB,
+    BTA_AG_SCO_CONN_OPEN,
+    BTA_AG_SCO_CONN_CLOSE,
+    BTA_AG_SCO_LISTEN,
+    BTA_AG_SCO_OPEN,
+    BTA_AG_SCO_CLOSE,
+    BTA_AG_SCO_SHUTDOWN,
+    BTA_AG_POST_SCO_OPEN,
+    BTA_AG_POST_SCO_CLOSE,
+    BTA_AG_SVC_CONN_OPEN,
+    BTA_AG_RESULT,
+    BTA_AG_SETCODEC,
+    BTA_AG_SEND_RING,
+    BTA_AG_CI_SCO_DATA,
+    BTA_AG_CI_RX_DATA,
+    BTA_AG_RCVD_SLC_READY,
+    BTA_AG_NUM_ACTIONS
+};
+
+#define BTA_AG_IGNORE       BTA_AG_NUM_ACTIONS
+
+/* type for action functions */
+typedef void (*tBTA_AG_ACTION)(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+
+/* action functions */
+const tBTA_AG_ACTION bta_ag_action[] =
+{
+    bta_ag_register,
+    bta_ag_deregister,
+    bta_ag_start_open,
+    bta_ag_rfc_do_open,
+    bta_ag_rfc_do_close,
+    bta_ag_start_dereg,
+    bta_ag_start_close,
+    bta_ag_rfc_open,
+    bta_ag_open_fail,
+    bta_ag_rfc_acp_open,
+    bta_ag_rfc_close,
+    bta_ag_rfc_fail,
+    bta_ag_rfc_data,
+    bta_ag_disc_int_res,
+    bta_ag_disc_fail,
+    bta_ag_disc_acp_res,
+    bta_ag_free_db,
+    bta_ag_sco_conn_open,
+    bta_ag_sco_conn_close,
+    bta_ag_sco_listen,
+    bta_ag_sco_open,
+    bta_ag_sco_close,
+    bta_ag_sco_shutdown,
+    bta_ag_post_sco_open,
+    bta_ag_post_sco_close,
+    bta_ag_svc_conn_open,
+    bta_ag_result,
+    bta_ag_setcodec,
+    bta_ag_send_ring,
+    bta_ag_ci_sco_data,
+    bta_ag_ci_rx_data,
+    bta_ag_rcvd_slc_ready
+};
+
+/* state table information */
+#define BTA_AG_ACTIONS              2       /* number of actions */
+#define BTA_AG_NEXT_STATE           2       /* position of next state */
+#define BTA_AG_NUM_COLS             3       /* number of columns in state tables */
+
+/* state table for init state */
+const UINT8 bta_ag_st_init[][BTA_AG_NUM_COLS] =
+{
+/* Event                    Action 1                Action 2                Next state */
+/* API_REGISTER_EVT */      {BTA_AG_REGISTER,       BTA_AG_IGNORE,          BTA_AG_INIT_ST},
+/* API_DEREGISTER_EVT */    {BTA_AG_DEREGISTER,     BTA_AG_IGNORE,          BTA_AG_INIT_ST},
+/* API_OPEN_EVT */          {BTA_AG_START_OPEN,     BTA_AG_IGNORE,          BTA_AG_OPENING_ST},
+/* API_CLOSE_EVT */         {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_INIT_ST},
+/* API_AUDIO_OPEN_EVT */    {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_INIT_ST},
+/* API_AUDIO_CLOSE_EVT */   {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_INIT_ST},
+/* API_RESULT_EVT */        {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_INIT_ST},
+/* API_SETCODEC_EVT */      {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_INIT_ST},
+/* RFC_OPEN_EVT */          {BTA_AG_RFC_ACP_OPEN,   BTA_AG_SCO_LISTEN,      BTA_AG_OPEN_ST},
+/* RFC_CLOSE_EVT */         {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_INIT_ST},
+/* RFC_SRV_CLOSE_EVT */     {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_INIT_ST},
+/* RFC_DATA_EVT */          {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_INIT_ST},
+/* SCO_OPEN_EVT */          {BTA_AG_SCO_CONN_OPEN,  BTA_AG_IGNORE,          BTA_AG_INIT_ST},
+/* SCO_CLOSE_EVT */         {BTA_AG_SCO_CONN_CLOSE, BTA_AG_IGNORE,          BTA_AG_INIT_ST},
+/* DISC_ACP_RES_EVT */      {BTA_AG_FREE_DB,        BTA_AG_IGNORE,          BTA_AG_INIT_ST},
+/* DISC_INT_RES_EVT */      {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_INIT_ST},
+/* DISC_OK_EVT */           {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_INIT_ST},
+/* DISC_FAIL_EVT */         {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_INIT_ST},
+/* CI_RX_WRITE_EVT */       {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_INIT_ST},
+/* RING_TOUT_EVT */         {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_INIT_ST},
+/* SVC_TOUT_EVT */          {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_INIT_ST},
+/* CI_SCO_DATA_EVT */       {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_INIT_ST},
+/* CI_SLC_READY_EVT */      {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_INIT_ST}
+};
+
+/* state table for opening state */
+const UINT8 bta_ag_st_opening[][BTA_AG_NUM_COLS] =
+{
+/* Event                    Action 1                Action 2                Next state */
+/* API_REGISTER_EVT */      {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_OPENING_ST},
+/* API_DEREGISTER_EVT */    {BTA_AG_RFC_DO_CLOSE,   BTA_AG_START_DEREG,     BTA_AG_CLOSING_ST},
+/* API_OPEN_EVT */          {BTA_AG_OPEN_FAIL,      BTA_AG_IGNORE,          BTA_AG_OPENING_ST},
+/* API_CLOSE_EVT */         {BTA_AG_RFC_DO_CLOSE,   BTA_AG_IGNORE,          BTA_AG_CLOSING_ST},
+/* API_AUDIO_OPEN_EVT */    {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_OPENING_ST},
+/* API_AUDIO_CLOSE_EVT */   {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_OPENING_ST},
+/* API_RESULT_EVT */        {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_OPENING_ST},
+/* API_SETCODEC_EVT */      {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_OPENING_ST},
+/* RFC_OPEN_EVT */          {BTA_AG_RFC_OPEN,       BTA_AG_SCO_LISTEN,      BTA_AG_OPEN_ST},
+/* RFC_CLOSE_EVT */         {BTA_AG_RFC_FAIL,       BTA_AG_IGNORE,          BTA_AG_INIT_ST},
+/* RFC_SRV_CLOSE_EVT */     {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_OPENING_ST},
+/* RFC_DATA_EVT */          {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_OPENING_ST},
+/* SCO_OPEN_EVT */          {BTA_AG_SCO_CONN_OPEN,  BTA_AG_IGNORE,          BTA_AG_OPENING_ST},
+/* SCO_CLOSE_EVT */         {BTA_AG_SCO_CONN_CLOSE, BTA_AG_IGNORE,          BTA_AG_OPENING_ST},
+/* DISC_ACP_RES_EVT */      {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_OPENING_ST},
+/* DISC_INT_RES_EVT */      {BTA_AG_DISC_INT_RES,   BTA_AG_IGNORE,          BTA_AG_OPENING_ST},
+/* DISC_OK_EVT */           {BTA_AG_RFC_DO_OPEN,    BTA_AG_IGNORE,          BTA_AG_OPENING_ST},
+/* DISC_FAIL_EVT */         {BTA_AG_DISC_FAIL,      BTA_AG_IGNORE,          BTA_AG_INIT_ST},
+/* CI_RX_WRITE_EVT */       {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_OPENING_ST},
+/* RING_TOUT_EVT */         {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_OPENING_ST},
+/* SVC_TOUT_EVT */          {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_OPENING_ST},
+/* CI_SCO_DATA_EVT */       {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_OPENING_ST},
+/* CI_SLC_READY_EVT */      {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_OPENING_ST}
+};
+
+/* state table for open state */
+const UINT8 bta_ag_st_open[][BTA_AG_NUM_COLS] =
+{
+/* Event                    Action 1                Action 2                Next state */
+/* API_REGISTER_EVT */      {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_OPEN_ST},
+/* API_DEREGISTER_EVT */    {BTA_AG_START_CLOSE,    BTA_AG_START_DEREG,     BTA_AG_CLOSING_ST},
+/* API_OPEN_EVT */          {BTA_AG_OPEN_FAIL,      BTA_AG_IGNORE,          BTA_AG_OPEN_ST},
+/* API_CLOSE_EVT */         {BTA_AG_START_CLOSE,    BTA_AG_IGNORE,          BTA_AG_CLOSING_ST},
+/* API_AUDIO_OPEN_EVT */    {BTA_AG_SCO_OPEN,       BTA_AG_IGNORE,          BTA_AG_OPEN_ST},
+/* API_AUDIO_CLOSE_EVT */   {BTA_AG_SCO_CLOSE,      BTA_AG_IGNORE,          BTA_AG_OPEN_ST},
+/* API_RESULT_EVT */        {BTA_AG_RESULT,         BTA_AG_IGNORE,          BTA_AG_OPEN_ST},
+/* API_SETCODEC_EVT */      {BTA_AG_SETCODEC,       BTA_AG_IGNORE,          BTA_AG_OPEN_ST},
+/* RFC_OPEN_EVT */          {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_OPEN_ST},
+/* RFC_CLOSE_EVT */         {BTA_AG_RFC_CLOSE,      BTA_AG_IGNORE,          BTA_AG_INIT_ST},
+/* RFC_SRV_CLOSE_EVT */     {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_OPEN_ST},
+/* RFC_DATA_EVT */          {BTA_AG_RFC_DATA,       BTA_AG_IGNORE,          BTA_AG_OPEN_ST},
+/* SCO_OPEN_EVT */          {BTA_AG_SCO_CONN_OPEN,  BTA_AG_POST_SCO_OPEN,   BTA_AG_OPEN_ST},
+/* SCO_CLOSE_EVT */         {BTA_AG_SCO_CONN_CLOSE, BTA_AG_POST_SCO_CLOSE,  BTA_AG_OPEN_ST},
+/* DISC_ACP_RES_EVT */      {BTA_AG_DISC_ACP_RES,   BTA_AG_IGNORE,          BTA_AG_OPEN_ST},
+/* DISC_INT_RES_EVT */      {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_OPEN_ST},
+/* DISC_OK_EVT */           {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_OPEN_ST},
+/* DISC_FAIL_EVT */         {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_OPEN_ST},
+/* CI_RX_WRITE_EVT */       {BTA_AG_CI_RX_DATA,     BTA_AG_IGNORE,          BTA_AG_OPEN_ST},
+/* RING_TOUT_EVT */         {BTA_AG_SEND_RING,      BTA_AG_IGNORE,          BTA_AG_OPEN_ST},
+/* SVC_TOUT_EVT */          {BTA_AG_START_CLOSE,    BTA_AG_IGNORE,          BTA_AG_CLOSING_ST},
+/* CI_SCO_DATA_EVT */       {BTA_AG_CI_SCO_DATA,    BTA_AG_IGNORE,          BTA_AG_OPEN_ST},
+/* CI_SLC_READY_EVT */      {BTA_AG_RCVD_SLC_READY, BTA_AG_IGNORE,          BTA_AG_OPEN_ST}
+};
+
+/* state table for closing state */
+const UINT8 bta_ag_st_closing[][BTA_AG_NUM_COLS] =
+{
+/* Event                    Action 1                Action 2                Next state */
+/* API_REGISTER_EVT */      {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_CLOSING_ST},
+/* API_DEREGISTER_EVT */    {BTA_AG_START_DEREG,    BTA_AG_IGNORE,          BTA_AG_CLOSING_ST},
+/* API_OPEN_EVT */          {BTA_AG_OPEN_FAIL,      BTA_AG_IGNORE,          BTA_AG_CLOSING_ST},
+/* API_CLOSE_EVT */         {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_CLOSING_ST},
+/* API_AUDIO_OPEN_EVT */    {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_CLOSING_ST},
+/* API_AUDIO_CLOSE_EVT */   {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_CLOSING_ST},
+/* API_RESULT_EVT */        {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_CLOSING_ST},
+/* API_SETCODEC_EVT */      {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_CLOSING_ST},
+/* RFC_OPEN_EVT */          {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_CLOSING_ST},
+/* RFC_CLOSE_EVT */         {BTA_AG_RFC_CLOSE,      BTA_AG_IGNORE,          BTA_AG_INIT_ST},
+/* RFC_SRV_CLOSE_EVT */     {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_CLOSING_ST},
+/* RFC_DATA_EVT */          {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_CLOSING_ST},
+/* SCO_OPEN_EVT */          {BTA_AG_SCO_CONN_OPEN,  BTA_AG_IGNORE,          BTA_AG_CLOSING_ST},
+/* SCO_CLOSE_EVT */         {BTA_AG_SCO_CONN_CLOSE, BTA_AG_POST_SCO_CLOSE,  BTA_AG_CLOSING_ST},
+/* DISC_ACP_RES_EVT */      {BTA_AG_FREE_DB,        BTA_AG_IGNORE,          BTA_AG_CLOSING_ST},
+/* DISC_INT_RES_EVT */      {BTA_AG_FREE_DB,        BTA_AG_IGNORE,          BTA_AG_INIT_ST},
+/* DISC_OK_EVT */           {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_CLOSING_ST},
+/* DISC_FAIL_EVT */         {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_CLOSING_ST},
+/* CI_RX_WRITE_EVT */       {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_CLOSING_ST},
+/* RING_TOUT_EVT */         {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_CLOSING_ST},
+/* SVC_TOUT_EVT */          {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_CLOSING_ST},
+/* CI_SCO_DATA_EVT */       {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_CLOSING_ST},
+/* CI_SLC_READY_EVT */      {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_CLOSING_ST}
+};
+
+/* type for state table */
+typedef const UINT8 (*tBTA_AG_ST_TBL)[BTA_AG_NUM_COLS];
+
+/* state table */
+const tBTA_AG_ST_TBL bta_ag_st_tbl[] =
+{
+    bta_ag_st_init,
+    bta_ag_st_opening,
+    bta_ag_st_open,
+    bta_ag_st_closing
+};
+
+/*****************************************************************************
+** Global data
+*****************************************************************************/
+
+/* AG control block */
+#if BTA_DYNAMIC_MEMORY == FALSE
+tBTA_AG_CB  bta_ag_cb;
+#endif
+
+/*******************************************************************************
+**
+** Function         bta_ag_timer_cback
+**
+** Description      AG timer callback.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+static void bta_ag_timer_cback(void *p)
+{
+    BT_HDR          *p_buf;
+    TIMER_LIST_ENT  *p_tle = (TIMER_LIST_ENT *) p;
+
+    if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL)
+    {
+        p_buf->event = p_tle->event;
+        p_buf->layer_specific = bta_ag_scb_to_idx((tBTA_AG_SCB *) p_tle->param);
+        bta_sys_sendmsg(p_buf);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_scb_alloc
+**
+** Description      Allocate an AG service control block.
+**
+**
+** Returns          pointer to the scb, or NULL if none could be allocated.
+**
+*******************************************************************************/
+static tBTA_AG_SCB *bta_ag_scb_alloc(void)
+{
+    tBTA_AG_SCB     *p_scb = &bta_ag_cb.scb[0];
+    int             i;
+
+    for (i = 0; i < BTA_AG_NUM_SCB; i++, p_scb++)
+    {
+        if (!p_scb->in_use)
+        {
+            /* initialize variables */
+            p_scb->in_use = TRUE;
+            p_scb->sco_idx = BTM_INVALID_SCO_INDEX;
+
+            /* set up timers */
+            p_scb->act_timer.param = (UINT32) p_scb;
+            p_scb->act_timer.p_cback = bta_ag_timer_cback;
+
+            APPL_TRACE_DEBUG1("bta_ag_scb_alloc %d", bta_ag_scb_to_idx(p_scb));
+            break;
+        }
+    }
+
+    if (i == BTA_AG_NUM_SCB)
+    {
+        /* out of scbs */
+        p_scb = NULL;
+        APPL_TRACE_WARNING0("Out of ag scbs");
+    }
+    return p_scb;
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_scb_dealloc
+**
+** Description      Deallocate a service control block.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_scb_dealloc(tBTA_AG_SCB *p_scb)
+{
+    UINT8   idx;
+    BOOLEAN allocated = FALSE;
+
+    APPL_TRACE_DEBUG1("bta_ag_scb_dealloc %d", bta_ag_scb_to_idx(p_scb));
+
+    /* stop timers */
+    bta_sys_stop_timer(&p_scb->act_timer);
+#if (BTM_WBS_INCLUDED == TRUE)
+    bta_sys_stop_timer(&p_scb->cn_timer);
+#endif
+
+    /* initialize control block */
+    memset(p_scb, 0, sizeof(tBTA_AG_SCB));
+    p_scb->sco_idx = BTM_INVALID_SCO_INDEX;
+
+    /* If all scbs are deallocated, callback with disable event */
+    if (!bta_sys_is_register (BTA_ID_AG))
+    {
+        for (idx = 0; idx < BTA_AG_NUM_SCB; idx++)
+        {
+            if (bta_ag_cb.scb[idx].in_use)
+            {
+                allocated = TRUE;
+                break;
+            }
+        }
+
+        if (!allocated)
+        {
+            (*bta_ag_cb.p_cback)(BTA_AG_DISABLE_EVT, NULL);
+        }
+    }
+
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_scb_to_idx
+**
+** Description      Given a pointer to an scb, return its index.
+**
+**
+** Returns          Index of scb.
+**
+*******************************************************************************/
+UINT16 bta_ag_scb_to_idx(tBTA_AG_SCB *p_scb)
+{
+    /* use array arithmetic to determine index */
+    return ((UINT16) (p_scb - bta_ag_cb.scb)) + 1;
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_scb_by_idx
+**
+** Description      Given an scb index return pointer to scb.
+**
+**
+** Returns          Pointer to scb or NULL if not allocated.
+**
+*******************************************************************************/
+tBTA_AG_SCB *bta_ag_scb_by_idx(UINT16 idx)
+{
+    tBTA_AG_SCB     *p_scb;
+
+    /* verify index */
+    if (idx > 0 && idx <= BTA_AG_NUM_SCB)
+    {
+        p_scb = &bta_ag_cb.scb[idx - 1];
+        if (!p_scb->in_use)
+        {
+            p_scb = NULL;
+            APPL_TRACE_WARNING1("ag scb idx %d not allocated", idx);
+        }
+    }
+    else
+    {
+        p_scb = NULL;
+        APPL_TRACE_DEBUG1("ag scb idx %d out of range", idx);
+    }
+    return p_scb;
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_service_to_idx
+**
+** Description      Given a BTA service mask convert to profile index.
+**
+**
+** Returns          Profile ndex of scb.
+**
+*******************************************************************************/
+UINT8 bta_ag_service_to_idx(tBTA_SERVICE_MASK services)
+{
+    if (services & BTA_HFP_SERVICE_MASK)
+    {
+        return BTA_AG_HFP;
+    }
+    else
+    {
+        return BTA_AG_HSP;
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_idx_by_bdaddr
+**
+** Description      Find SCB associated with peer BD address.
+**
+**
+** Returns          Index of SCB or zero if none found.
+**
+*******************************************************************************/
+UINT16 bta_ag_idx_by_bdaddr(BD_ADDR peer_addr)
+{
+    tBTA_AG_SCB     *p_scb = &bta_ag_cb.scb[0];
+    UINT16          i;
+
+    if (peer_addr != NULL)
+    {
+        for (i = 0; i < BTA_AG_NUM_SCB; i++, p_scb++)
+        {
+            if (p_scb->in_use && !bdcmp(peer_addr, p_scb->peer_addr))
+            {
+                return (i + 1);
+            }
+        }
+    }
+
+    /* no scb found */
+    APPL_TRACE_WARNING0("No ag scb for peer addr");
+    return 0;
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_other_scb_open
+**
+** Description      Check whether any other scb is in open state.
+**
+**
+** Returns          TRUE if another scb is in open state, FALSE otherwise.
+**
+*******************************************************************************/
+BOOLEAN bta_ag_other_scb_open(tBTA_AG_SCB *p_curr_scb)
+{
+    tBTA_AG_SCB     *p_scb = &bta_ag_cb.scb[0];
+    int             i;
+
+    for (i = 0; i < BTA_AG_NUM_SCB; i++, p_scb++)
+    {
+        if (p_scb->in_use && p_scb != p_curr_scb && p_scb->state == BTA_AG_OPEN_ST)
+        {
+            return TRUE;
+        }
+    }
+
+    /* no other scb found */
+    APPL_TRACE_DEBUG0("No other ag scb open");
+    return FALSE;
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_get_other_idle_scb
+**
+** Description      Return other scb if it is in INIT st.
+**
+**
+** Returns          Pointer to other scb if INIT st, NULL otherwise.
+**
+*******************************************************************************/
+tBTA_AG_SCB *bta_ag_get_other_idle_scb (tBTA_AG_SCB *p_curr_scb)
+{
+    tBTA_AG_SCB     *p_scb = &bta_ag_cb.scb[0];
+    UINT8   xx;
+
+    for (xx = 0; xx < BTA_AG_NUM_SCB; xx++, p_scb++)
+    {
+        if (p_scb->in_use && (p_scb != p_curr_scb) && (p_scb->state == BTA_AG_INIT_ST))
+        {
+            return p_scb;
+        }
+    }
+
+    /* no other scb found */
+    APPL_TRACE_DEBUG0("bta_ag_get_other_idle_scb: No idle AG scb");
+    return NULL;
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_colli_timer_cback
+**
+** Description      AG connection collision timer callback
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+static void bta_ag_colli_timer_cback (TIMER_LIST_ENT *p_tle)
+{
+    tBTA_AG_SCB *p_scb;
+
+    APPL_TRACE_DEBUG0 ("bta_ag_colli_timer_cback");
+
+    if (p_tle)
+    {
+        p_scb = (tBTA_AG_SCB *)p_tle->param;
+
+        if (p_scb)
+        {
+            p_scb->colli_tmr_on = FALSE;
+
+            /* If the peer haven't opened AG connection     */
+            /* we will restart opening process.             */
+            bta_ag_resume_open (p_scb);
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_collision_cback
+**
+** Description      Get notified about collision.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_collision_cback (tBTA_SYS_CONN_STATUS status, UINT8 id,
+                                    UINT8 app_id, BD_ADDR peer_addr)
+{
+    UINT16  handle;
+    tBTA_AG_SCB *p_scb;
+    UNUSED(status);
+    UNUSED(app_id);
+
+    /* Check if we have opening scb for the peer device. */
+    handle = bta_ag_idx_by_bdaddr (peer_addr);
+    p_scb = bta_ag_scb_by_idx (handle);
+
+    if (p_scb && (p_scb->state == BTA_AG_OPENING_ST))
+    {
+        if (id == BTA_ID_SYS)   /* ACL collision */
+        {
+            APPL_TRACE_WARNING0 ("AG found collision (ACL) ...");
+        }
+        else if (id == BTA_ID_AG)   /* RFCOMM collision */
+        {
+            APPL_TRACE_WARNING0 ("AG found collision (RFCOMM) ...");
+        }
+        else
+        {
+            APPL_TRACE_WARNING0 ("AG found collision (\?\?\?) ...");
+        }
+
+        p_scb->state = BTA_AG_INIT_ST;
+
+        /* Cancel SDP if it had been started. */
+        if(p_scb->p_disc_db)
+        {
+            (void)SDP_CancelServiceSearch (p_scb->p_disc_db);
+            bta_ag_free_db(p_scb, NULL);
+        }
+
+        /* reopen registered servers */
+        /* Collision may be detected before or after we close servers. */
+        if (bta_ag_is_server_closed (p_scb))
+            bta_ag_start_servers(p_scb, p_scb->reg_services);
+
+        /* Start timer to han */
+        p_scb->colli_timer.p_cback = (TIMER_CBACK*)&bta_ag_colli_timer_cback;
+        p_scb->colli_timer.param = (INT32)p_scb;
+        bta_sys_start_timer(&p_scb->colli_timer, 0, BTA_AG_COLLISION_TIMER);
+        p_scb->colli_tmr_on = TRUE;
+    }
+
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_resume_open
+**
+** Description      Resume opening process.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_resume_open (tBTA_AG_SCB *p_scb)
+{
+    if (p_scb)
+    {
+        APPL_TRACE_DEBUG1 ("bta_ag_resume_open, Handle(%d)", bta_ag_scb_to_idx(p_scb));
+
+        /* resume opening process.  */
+        if (p_scb->state == BTA_AG_INIT_ST)
+        {
+            p_scb->state = BTA_AG_OPENING_ST;
+            bta_ag_start_open (p_scb, NULL);
+        }
+    }
+    else
+    {
+        APPL_TRACE_ERROR0 ("bta_ag_resume_open, Null p_scb");
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_api_enable
+**
+** Description      Handle an API enable event.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+static void bta_ag_api_enable(tBTA_AG_DATA *p_data)
+{
+    /* initialize control block */
+    memset(&bta_ag_cb, 0, sizeof(tBTA_AG_CB));
+
+    /* store callback function */
+    bta_ag_cb.p_cback = p_data->api_enable.p_cback;
+    bta_ag_cb.parse_mode = p_data->api_enable.parse_mode;
+
+    /* call init call-out */
+    bta_ag_co_init();
+
+    bta_sys_collision_register (BTA_ID_AG, bta_ag_collision_cback);
+
+    /* call callback with enable event */
+    (*bta_ag_cb.p_cback)(BTA_AG_ENABLE_EVT, NULL);
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_api_disable
+**
+** Description      Handle an API disable event.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+static void bta_ag_api_disable(tBTA_AG_DATA *p_data)
+{
+    /* deregister all scbs in use */
+    tBTA_AG_SCB     *p_scb = &bta_ag_cb.scb[0];
+    BOOLEAN         do_dereg = FALSE;
+    int             i;
+
+    if (!bta_sys_is_register (BTA_ID_AG))
+    {
+        APPL_TRACE_ERROR0("BTA AG is already disabled, ignoring ...");
+        return;
+    }
+
+    /* De-register with BTA system manager */
+    GKI_sched_lock();
+    bta_sys_deregister(BTA_ID_AG);
+    GKI_sched_unlock();
+
+    for (i = 0; i < BTA_AG_NUM_SCB; i++, p_scb++)
+    {
+        if (p_scb->in_use)
+        {
+            bta_ag_sm_execute(p_scb, BTA_AG_API_DEREGISTER_EVT, p_data);
+            do_dereg = TRUE;
+        }
+    }
+
+    if (!do_dereg)
+    {
+        /* Done, send callback evt to app */
+        (*bta_ag_cb.p_cback)(BTA_AG_DISABLE_EVT, NULL);
+    }
+
+    bta_sys_collision_register (BTA_ID_AG, NULL);
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_api_register
+**
+** Description      Handle an API event registers a new service.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+static void bta_ag_api_register(tBTA_AG_DATA *p_data)
+{
+    tBTA_AG_SCB     *p_scb;
+    tBTA_AG_REGISTER reg;
+
+    /* allocate an scb */
+    if ((p_scb = bta_ag_scb_alloc()) != NULL)
+    {
+        bta_ag_sm_execute(p_scb, p_data->hdr.event, p_data);
+    }
+    else
+    {
+        reg.status = BTA_AG_FAIL_RESOURCES;
+        (*bta_ag_cb.p_cback)(BTA_AG_REGISTER_EVT, (tBTA_AG *) &reg);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_api_result
+**
+** Description      Handle an API result event.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+static void bta_ag_api_result(tBTA_AG_DATA *p_data)
+{
+    tBTA_AG_SCB     *p_scb;
+    int             i;
+
+    if (p_data->hdr.layer_specific != BTA_AG_HANDLE_ALL)
+    {
+        if ((p_scb = bta_ag_scb_by_idx(p_data->hdr.layer_specific)) != NULL)
+        {
+            bta_ag_sm_execute(p_scb, BTA_AG_API_RESULT_EVT, p_data);
+        }
+    }
+    else
+    {
+        for (i = 0, p_scb = &bta_ag_cb.scb[0]; i < BTA_AG_NUM_SCB; i++, p_scb++)
+        {
+            if (p_scb->in_use)
+            {
+                bta_ag_sm_execute(p_scb, BTA_AG_API_RESULT_EVT, p_data);
+            }
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_sm_execute
+**
+** Description      State machine event handling function for AG
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_sm_execute(tBTA_AG_SCB *p_scb, UINT16 event, tBTA_AG_DATA *p_data)
+{
+    tBTA_AG_ST_TBL      state_table;
+    UINT8               action;
+    int                 i;
+
+#if BTA_AG_DEBUG == TRUE
+    UINT16  in_event = event;
+    UINT8   in_state = p_scb->state;
+
+    /* Ignore displaying of AT results when not connected (Ignored in state machine) */
+    if (in_event != BTA_AG_API_RESULT_EVT || p_scb->state == BTA_AG_OPEN_ST)
+    {
+        APPL_TRACE_EVENT5("AG evt (hdl 0x%04x): State %d (%s), Event 0x%04x (%s)",
+                           bta_ag_scb_to_idx(p_scb),
+                           p_scb->state, bta_ag_state_str(p_scb->state),
+                           event, bta_ag_evt_str(event, p_data->api_result.result));
+    }
+#else
+    APPL_TRACE_EVENT3("AG evt (hdl 0x%04x): State %d, Event 0x%04x",
+                      bta_ag_scb_to_idx(p_scb), p_scb->state, event);
+#endif
+
+    event &= 0x00FF;
+    if (event >= (BTA_AG_MAX_EVT & 0x00FF))
+    {
+        APPL_TRACE_ERROR0("AG evt out of range, ignoring...");
+        return;
+    }
+
+    /* look up the state table for the current state */
+    state_table = bta_ag_st_tbl[p_scb->state];
+
+    /* set next state */
+    p_scb->state = state_table[event][BTA_AG_NEXT_STATE];
+
+    /* execute action functions */
+    for (i = 0; i < BTA_AG_ACTIONS; i++)
+    {
+        if ((action = state_table[event][i]) != BTA_AG_IGNORE)
+        {
+            (*bta_ag_action[action])(p_scb, p_data);
+        }
+        else
+        {
+            break;
+        }
+    }
+#if BTA_AG_DEBUG == TRUE
+    if (p_scb->state != in_state)
+    {
+        APPL_TRACE_EVENT3("BTA AG State Change: [%s] -> [%s] after Event [%s]",
+                      bta_ag_state_str(in_state),
+                      bta_ag_state_str(p_scb->state),
+                      bta_ag_evt_str(in_event, p_data->api_result.result));
+    }
+#endif
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_hdl_event
+**
+** Description      Data gateway main event handling function.
+**
+**
+** Returns          BOOLEAN
+**
+*******************************************************************************/
+BOOLEAN bta_ag_hdl_event(BT_HDR *p_msg)
+{
+    tBTA_AG_SCB *p_scb;
+
+    switch (p_msg->event)
+    {
+        /* handle enable event */
+        case BTA_AG_API_ENABLE_EVT:
+            bta_ag_api_enable((tBTA_AG_DATA *) p_msg);
+            break;
+
+        /* handle disable event */
+        case BTA_AG_API_DISABLE_EVT:
+            bta_ag_api_disable((tBTA_AG_DATA *) p_msg);
+            break;
+
+        /* handle register event */
+        case BTA_AG_API_REGISTER_EVT:
+            bta_ag_api_register((tBTA_AG_DATA *) p_msg);
+            break;
+
+        /* handle result event */
+        case BTA_AG_API_RESULT_EVT:
+            bta_ag_api_result((tBTA_AG_DATA *) p_msg);
+            break;
+
+        /* all others reference scb by handle */
+        default:
+            if ((p_scb = bta_ag_scb_by_idx(p_msg->layer_specific)) != NULL)
+            {
+                bta_ag_sm_execute(p_scb, p_msg->event, (tBTA_AG_DATA *) p_msg);
+            }
+            break;
+    }
+    return TRUE;
+}
+
+#if BTA_AG_DEBUG == TRUE
+static char *bta_ag_evt_str(UINT16 event, tBTA_AG_RES result)
+{
+    switch (event)
+    {
+    case BTA_AG_API_REGISTER_EVT:
+        return "Register Request";
+    case BTA_AG_API_DEREGISTER_EVT:
+        return "Deregister Request";
+    case BTA_AG_API_OPEN_EVT:
+        return "Open SLC Request";
+    case BTA_AG_API_CLOSE_EVT:
+        return "Close SLC Request";
+    case BTA_AG_API_AUDIO_OPEN_EVT:
+        return "Open Audio Request";
+    case BTA_AG_API_AUDIO_CLOSE_EVT:
+        return "Close Audio Request";
+    case BTA_AG_API_RESULT_EVT:
+        switch (result)
+        {
+        case BTA_AG_SPK_RES:            return ("AT Result  BTA_AG_SPK_RES");
+        case BTA_AG_MIC_RES:            return ("AT Result  BTA_AG_MIC_RES");
+        case BTA_AG_INBAND_RING_RES:    return ("AT Result  BTA_AG_INBAND_RING_RES");
+        case BTA_AG_CIND_RES:           return ("AT Result  BTA_AG_CIND_RES");
+        case BTA_AG_BINP_RES:           return ("AT Result  BTA_AG_BINP_RES");
+        case BTA_AG_IND_RES:            return ("AT Result  BTA_AG_IND_RES");
+        case BTA_AG_BVRA_RES:           return ("AT Result  BTA_AG_BVRA_RES");
+        case BTA_AG_CNUM_RES:           return ("AT Result  BTA_AG_CNUM_RES");
+        case BTA_AG_BTRH_RES:           return ("AT Result  BTA_AG_BTRH_RES");
+        case BTA_AG_CLCC_RES:           return ("AT Result  BTA_AG_CLCC_RES");
+        case BTA_AG_COPS_RES:           return ("AT Result  BTA_AG_COPS_RES");
+        case BTA_AG_IN_CALL_RES:        return ("AT Result  BTA_AG_IN_CALL_RES");
+        case BTA_AG_IN_CALL_CONN_RES:   return ("AT Result  BTA_AG_IN_CALL_CONN_RES");
+        case BTA_AG_CALL_WAIT_RES:      return ("AT Result  BTA_AG_CALL_WAIT_RES");
+        case BTA_AG_OUT_CALL_ORIG_RES:  return ("AT Result  BTA_AG_OUT_CALL_ORIG_RES");
+        case BTA_AG_OUT_CALL_ALERT_RES: return ("AT Result  BTA_AG_OUT_CALL_ALERT_RES");
+        case BTA_AG_OUT_CALL_CONN_RES:  return ("AT Result  BTA_AG_OUT_CALL_CONN_RES");
+        case BTA_AG_CALL_CANCEL_RES:    return ("AT Result  BTA_AG_CALL_CANCEL_RES");
+        case BTA_AG_END_CALL_RES:       return ("AT Result  BTA_AG_END_CALL_RES");
+        case BTA_AG_UNAT_RES:           return ("AT Result  BTA_AG_UNAT_RES");
+        default:                        return ("Unknown AG Result");
+        }
+    case BTA_AG_API_SETCODEC_EVT:
+        return "Set Codec Request";
+    case BTA_AG_RFC_OPEN_EVT:
+        return "RFC Opened";
+    case BTA_AG_RFC_CLOSE_EVT:
+        return "RFC Closed";
+    case BTA_AG_RFC_SRV_CLOSE_EVT:
+        return "RFC SRV Closed";
+    case BTA_AG_RFC_DATA_EVT:
+        return "RFC Data";
+    case BTA_AG_SCO_OPEN_EVT:
+        return "Audio Opened";
+    case BTA_AG_SCO_CLOSE_EVT:
+        return "Audio Closed";
+    case BTA_AG_DISC_ACP_RES_EVT:
+        return "Discovery ACP Result";
+    case BTA_AG_DISC_INT_RES_EVT:
+        return "Discovery INT Result";
+    case BTA_AG_DISC_OK_EVT:
+        return "Discovery OK";
+    case BTA_AG_DISC_FAIL_EVT:
+        return "Discovery Failed";
+    case BTA_AG_CI_RX_WRITE_EVT:
+        return "CI RX Write";
+    case BTA_AG_RING_TOUT_EVT:
+        return "Ring Timeout";
+    case BTA_AG_SVC_TOUT_EVT:
+        return "Service Timeout";
+    case BTA_AG_API_ENABLE_EVT:
+        return "Enable AG";
+    case BTA_AG_API_DISABLE_EVT:
+        return "Disable AG";
+    case BTA_AG_CI_SCO_DATA_EVT:
+        return "SCO data Callin";
+    case BTA_AG_CI_SLC_READY_EVT:
+        return "SLC Ready Callin";
+    default:
+        return "Unknown AG Event";
+    }
+}
+
+static char *bta_ag_state_str(UINT8 state)
+{
+    switch (state)
+    {
+    case BTA_AG_INIT_ST:
+        return "Initial";
+    case BTA_AG_OPENING_ST:
+        return "Opening";
+    case BTA_AG_OPEN_ST:
+        return "Open";
+    case BTA_AG_CLOSING_ST:
+        return "Closing";
+    default:
+        return "Unknown AG State";
+    }
+}
+
+#endif
diff --git a/bta/hf_client/bta_hf_client_rfc.c b/bta/hf_client/bta_hf_client_rfc.c
new file mode 100644
index 0000000..d6b5329
--- /dev/null
+++ b/bta/hf_client/bta_hf_client_rfc.c
@@ -0,0 +1,446 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2004-2012 Broadcom Corporation
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *  This file contains the audio gateway functions controlling the RFCOMM
+ *  connections.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+#include "bta_api.h"
+#include "bta_sys.h"
+#include "bta_ag_api.h"
+#include "bta_ag_int.h"
+#include "bta_ag_co.h"
+#include "btm_api.h"
+#include "port_api.h"
+#include "rfcdefs.h"
+#include "gki.h"
+#include "bd.h"
+#include "utl.h"
+
+/* Event mask for RfCOMM port callback */
+#define BTA_AG_PORT_EV_MASK         PORT_EV_RXCHAR
+
+/* each scb has its own rfcomm callbacks */
+void bta_ag_port_cback_1(UINT32 code, UINT16 port_handle);
+void bta_ag_port_cback_2(UINT32 code, UINT16 port_handle);
+void bta_ag_port_cback_3(UINT32 code, UINT16 port_handle);
+
+void bta_ag_mgmt_cback_1(UINT32 code, UINT16 port_handle);
+void bta_ag_mgmt_cback_2(UINT32 code, UINT16 port_handle);
+void bta_ag_mgmt_cback_3(UINT32 code, UINT16 port_handle);
+
+int bta_ag_data_cback_1(UINT16 port_handle, void *p_data, UINT16 len);
+int bta_ag_data_cback_2(UINT16 port_handle, void *p_data, UINT16 len);
+int bta_ag_data_cback_3(UINT16 port_handle, void *p_data, UINT16 len);
+
+/* rfcomm callback function tables */
+typedef tPORT_CALLBACK *tBTA_AG_PORT_CBACK;
+const tBTA_AG_PORT_CBACK bta_ag_port_cback_tbl[] =
+{
+    bta_ag_port_cback_1,
+    bta_ag_port_cback_2,
+    bta_ag_port_cback_3
+};
+
+const tBTA_AG_PORT_CBACK bta_ag_mgmt_cback_tbl[] =
+{
+    bta_ag_mgmt_cback_1,
+    bta_ag_mgmt_cback_2,
+    bta_ag_mgmt_cback_3
+};
+
+typedef tPORT_DATA_CALLBACK *tBTA_AG_DATA_CBACK;
+const tBTA_AG_DATA_CBACK bta_ag_data_cback_tbl[] =
+{
+    bta_ag_data_cback_1,
+    bta_ag_data_cback_2,
+    bta_ag_data_cback_3
+};
+
+/*******************************************************************************
+**
+** Function         bta_ag_port_cback
+**
+** Description      RFCOMM Port callback
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+static void bta_ag_port_cback(UINT32 code, UINT16 port_handle, UINT16 handle)
+{
+    BT_HDR      *p_buf;
+    tBTA_AG_SCB *p_scb;
+    UNUSED(code);
+
+    if ((p_scb = bta_ag_scb_by_idx(handle)) != NULL)
+    {
+        /* ignore port events for port handles other than connected handle */
+        if (port_handle != p_scb->conn_handle)
+        {
+            APPL_TRACE_DEBUG3("ag_port_cback ignoring handle:%d conn_handle = %d other handle = %d",
+                              port_handle, p_scb->conn_handle, handle);
+            return;
+        }
+
+        if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL)
+        {
+            p_buf->event = BTA_AG_RFC_DATA_EVT;
+            p_buf->layer_specific = handle;
+            bta_sys_sendmsg(p_buf);
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_mgmt_cback
+**
+** Description      RFCOMM management callback
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+static void bta_ag_mgmt_cback(UINT32 code, UINT16 port_handle, UINT16 handle)
+{
+    tBTA_AG_RFC     *p_buf;
+    tBTA_AG_SCB     *p_scb;
+    UINT16          event;
+    UINT8           i;
+    BOOLEAN         found_handle = FALSE;
+
+    APPL_TRACE_DEBUG3("ag_mgmt_cback : code = %d, port_handle = %d, handle = %d",
+                        code, port_handle, handle);
+
+    if ((p_scb = bta_ag_scb_by_idx(handle)) != NULL)
+    {
+        /* ignore close event for port handles other than connected handle */
+        if ((code != PORT_SUCCESS) && (port_handle != p_scb->conn_handle))
+        {
+            APPL_TRACE_DEBUG1("ag_mgmt_cback ignoring handle:%d", port_handle);
+            return;
+        }
+
+        if (code == PORT_SUCCESS)
+        {
+            if (p_scb->conn_handle)     /* Outgoing connection */
+            {
+                if (port_handle == p_scb->conn_handle)
+                    found_handle = TRUE;
+            }
+            else                        /* Incoming connection */
+            {
+                for (i = 0; i < BTA_AG_NUM_IDX; i++)
+                {
+                    if (port_handle == p_scb->serv_handle[i])
+                        found_handle = TRUE;
+                }
+            }
+
+            if (!found_handle)
+            {
+                APPL_TRACE_ERROR1 ("bta_ag_mgmt_cback: PORT_SUCCESS, ignoring handle = %d", port_handle);
+                return;
+            }
+
+            event = BTA_AG_RFC_OPEN_EVT;
+        }
+        /* distinguish server close events */
+        else if (port_handle == p_scb->conn_handle)
+        {
+            event = BTA_AG_RFC_CLOSE_EVT;
+        }
+        else
+        {
+            event = BTA_AG_RFC_SRV_CLOSE_EVT;
+        }
+
+        if ((p_buf = (tBTA_AG_RFC *) GKI_getbuf(sizeof(tBTA_AG_RFC))) != NULL)
+        {
+            p_buf->hdr.event = event;
+            p_buf->hdr.layer_specific = handle;
+            p_buf->port_handle = port_handle;
+            bta_sys_sendmsg(p_buf);
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_data_cback
+**
+** Description      RFCOMM data callback
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+static int bta_ag_data_cback(UINT16 port_handle, void *p_data, UINT16 len, UINT16 handle)
+{
+    UNUSED(port_handle);
+
+    /* call data call-out directly */
+    bta_ag_co_tx_write(handle, (UINT8 *) p_data, len);
+    return 0;
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_port_cback_1 to 3
+**                  bta_ag_mgmt_cback_1 to 3
+**
+** Description      RFCOMM callback functions.  This is an easy way to
+**                  distinguish scb from the callback.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_mgmt_cback_1(UINT32 code, UINT16 handle) {bta_ag_mgmt_cback(code, handle, 1);}
+void bta_ag_mgmt_cback_2(UINT32 code, UINT16 handle) {bta_ag_mgmt_cback(code, handle, 2);}
+void bta_ag_mgmt_cback_3(UINT32 code, UINT16 handle) {bta_ag_mgmt_cback(code, handle, 3);}
+void bta_ag_port_cback_1(UINT32 code, UINT16 handle) {bta_ag_port_cback(code, handle, 1);}
+void bta_ag_port_cback_2(UINT32 code, UINT16 handle) {bta_ag_port_cback(code, handle, 2);}
+void bta_ag_port_cback_3(UINT32 code, UINT16 handle) {bta_ag_port_cback(code, handle, 3);}
+
+/*******************************************************************************
+**
+** Function         bta_ag_data_cback_1 to 3
+**
+** Description      RFCOMM data callback functions.  This is an easy way to
+**                  distinguish scb from the callback.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+int bta_ag_data_cback_1(UINT16 port_handle, void *p_data, UINT16 len)
+{
+    return bta_ag_data_cback(port_handle, p_data, len, 1);
+}
+int bta_ag_data_cback_2(UINT16 port_handle, void *p_data, UINT16 len)
+{
+    return bta_ag_data_cback(port_handle, p_data, len, 2);
+}
+int bta_ag_data_cback_3(UINT16 port_handle, void *p_data, UINT16 len)
+{
+    return bta_ag_data_cback(port_handle, p_data, len, 3);
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_setup_port
+**
+** Description      Setup RFCOMM port for use by AG.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_setup_port(tBTA_AG_SCB *p_scb, UINT16 handle)
+{
+    UINT16 i = bta_ag_scb_to_idx(p_scb) - 1;
+
+    /* set up data callback if using pass through mode */
+    if (bta_ag_cb.parse_mode == BTA_AG_PASS_THROUGH)
+    {
+        PORT_SetDataCallback(handle, bta_ag_data_cback_tbl[i]);
+    }
+
+    PORT_SetEventMask(handle, BTA_AG_PORT_EV_MASK);
+    PORT_SetEventCallback(handle, bta_ag_port_cback_tbl[i]);
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_start_servers
+**
+** Description      Setup RFCOMM servers for use by AG.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_start_servers(tBTA_AG_SCB *p_scb, tBTA_SERVICE_MASK services)
+{
+    int i;
+    int bta_ag_port_status;
+
+    services >>= BTA_HSP_SERVICE_ID;
+    for (i = 0; i < BTA_AG_NUM_IDX && services != 0; i++, services >>= 1)
+    {
+        /* if service is set in mask */
+        if (services & 1)
+        {
+            BTM_SetSecurityLevel(FALSE, "", bta_ag_sec_id[i], p_scb->serv_sec_mask,
+                BT_PSM_RFCOMM, BTM_SEC_PROTO_RFCOMM, bta_ag_cb.profile[i].scn);
+
+            bta_ag_port_status =  RFCOMM_CreateConnection(bta_ag_uuid[i], bta_ag_cb.profile[i].scn,
+                TRUE, BTA_AG_MTU, (UINT8 *) bd_addr_any, &(p_scb->serv_handle[i]),
+                bta_ag_mgmt_cback_tbl[bta_ag_scb_to_idx(p_scb) - 1]);
+
+            if( bta_ag_port_status  == PORT_SUCCESS )
+            {
+                bta_ag_setup_port(p_scb, p_scb->serv_handle[i]);
+            }
+            else
+            {
+                /* TODO: CR#137125 to handle to error properly */
+                APPL_TRACE_DEBUG1("bta_ag_start_servers: RFCOMM_CreateConnection returned error:%d", bta_ag_port_status);
+            }
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_close_servers
+**
+** Description      Close RFCOMM servers port for use by AG.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_close_servers(tBTA_AG_SCB *p_scb, tBTA_SERVICE_MASK services)
+{
+    int i;
+
+    services >>= BTA_HSP_SERVICE_ID;
+    for (i = 0; i < BTA_AG_NUM_IDX && services != 0; i++, services >>= 1)
+    {
+        /* if service is set in mask */
+        if (services & 1)
+        {
+            RFCOMM_RemoveServer(p_scb->serv_handle[i]);
+            p_scb->serv_handle[i] = 0;
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_is_server_closed
+**
+** Description      Returns TRUE if all servers are closed.
+**
+**
+** Returns          TRUE if all servers are closed, FALSE otherwise
+**
+*******************************************************************************/
+BOOLEAN bta_ag_is_server_closed (tBTA_AG_SCB *p_scb)
+{
+    UINT8 xx;
+    BOOLEAN is_closed = TRUE;
+
+    for (xx = 0; xx < BTA_AG_NUM_IDX; xx++)
+    {
+        if (p_scb->serv_handle[xx] != 0)
+            is_closed = FALSE;
+    }
+
+    return is_closed;
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_rfc_do_open
+**
+** Description      Open an RFCOMM connection to the peer device.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_rfc_do_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+    BTM_SetSecurityLevel(TRUE, "", bta_ag_sec_id[p_scb->conn_service],
+        p_scb->cli_sec_mask, BT_PSM_RFCOMM, BTM_SEC_PROTO_RFCOMM, p_scb->peer_scn);
+
+    if (RFCOMM_CreateConnection(bta_ag_uuid[p_scb->conn_service], p_scb->peer_scn,
+            FALSE, BTA_AG_MTU, p_scb->peer_addr, &(p_scb->conn_handle),
+            bta_ag_mgmt_cback_tbl[bta_ag_scb_to_idx(p_scb) - 1]) == PORT_SUCCESS)
+    {
+        bta_ag_setup_port(p_scb, p_scb->conn_handle);
+        APPL_TRACE_DEBUG1("bta_ag_rfc_do_open : conn_handle = %d", p_scb->conn_handle);
+    }
+    /* RFCOMM create connection failed; send ourselves RFCOMM close event */
+    else
+    {
+        bta_ag_sm_execute(p_scb, BTA_AG_RFC_CLOSE_EVT, p_data);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_rfc_do_close
+**
+** Description      Close RFCOMM connection.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_rfc_do_close(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+    tBTA_AG_RFC     *p_buf;
+    UNUSED(p_data);
+
+    if (p_scb->conn_handle)
+    {
+        RFCOMM_RemoveConnection(p_scb->conn_handle);
+    }
+    else
+    {
+        /* Close API was called while AG is in Opening state.               */
+        /* Need to trigger the state machine to send callback to the app    */
+        /* and move back to INIT state.                                     */
+        if ((p_buf = (tBTA_AG_RFC *) GKI_getbuf(sizeof(tBTA_AG_RFC))) != NULL)
+        {
+            p_buf->hdr.event = BTA_AG_RFC_CLOSE_EVT;
+            p_buf->hdr.layer_specific = bta_ag_scb_to_idx(p_scb);
+            bta_sys_sendmsg(p_buf);
+        }
+
+        /* Cancel SDP if it had been started. */
+        /*
+        if(p_scb->p_disc_db)
+        {
+            (void)SDP_CancelServiceSearch (p_scb->p_disc_db);
+        }
+        */
+    }
+
+#ifdef _WIN32_WCE
+    {
+        /* Windows versions of RFCOMM does NOT generate a closed callback when we close */
+        tPORT_CALLBACK *rfc_mgmt_cback = bta_ag_mgmt_cback_tbl[bta_ag_scb_to_idx(p_scb) - 1];
+
+        if (rfc_mgmt_cback)
+        {
+            (rfc_mgmt_cback)(PORT_CLOSED, p_scb->conn_handle);
+        }
+    }
+#endif
+}
+
diff --git a/bta/hf_client/bta_hf_client_sco.c b/bta/hf_client/bta_hf_client_sco.c
new file mode 100644
index 0000000..87d9188
--- /dev/null
+++ b/bta/hf_client/bta_hf_client_sco.c
@@ -0,0 +1,1675 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2004-2012 Broadcom Corporation
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *  This file contains functions for managing the SCO connection used in AG.
+ *
+ ******************************************************************************/
+
+#include "bta_api.h"
+#include "bta_ag_api.h"
+#include "bta_ag_co.h"
+#if (BTM_SCO_HCI_INCLUDED == TRUE )
+#include "bta_dm_co.h"
+#endif
+#include "bta_ag_int.h"
+#include "btm_api.h"
+#include "gki.h"
+#include "utl.h"
+
+#ifndef BTA_AG_SCO_DEBUG
+#define BTA_AG_SCO_DEBUG FALSE
+#endif
+
+#ifndef BTA_AG_CODEC_NEGO_TIMEOUT
+#define BTA_AG_CODEC_NEGO_TIMEOUT   3000
+#endif
+
+#if BTA_AG_SCO_DEBUG == TRUE
+static char *bta_ag_sco_evt_str(UINT8 event);
+static char *bta_ag_sco_state_str(UINT8 state);
+#endif
+
+#define BTA_AG_NO_EDR_ESCO  (BTM_SCO_PKT_TYPES_MASK_NO_2_EV3 | \
+                             BTM_SCO_PKT_TYPES_MASK_NO_3_EV3 | \
+                             BTM_SCO_PKT_TYPES_MASK_NO_2_EV5 | \
+                             BTM_SCO_PKT_TYPES_MASK_NO_3_EV5)
+
+/* sco events */
+enum
+{
+    BTA_AG_SCO_LISTEN_E,        /* listen request */
+    BTA_AG_SCO_OPEN_E,          /* open request */
+    BTA_AG_SCO_XFER_E,          /* transfer request */
+#if (BTM_WBS_INCLUDED == TRUE )
+    BTA_AG_SCO_CN_DONE_E,       /* codec negotiation done */
+    BTA_AG_SCO_REOPEN_E,        /* Retry with other codec when failed */
+#endif
+    BTA_AG_SCO_CLOSE_E,         /* close request */
+    BTA_AG_SCO_SHUTDOWN_E,      /* shutdown request */
+    BTA_AG_SCO_CONN_OPEN_E,     /* sco open */
+    BTA_AG_SCO_CONN_CLOSE_E,    /* sco closed */
+    BTA_AG_SCO_CI_DATA_E        /* SCO data ready */
+};
+
+#if (BTM_WBS_INCLUDED == TRUE )
+#define BTA_AG_NUM_CODECS   2
+static const tBTM_ESCO_PARAMS bta_ag_esco_params[BTA_AG_NUM_CODECS] =
+{
+    /* CVSD */
+    {
+        BTM_64KBITS_RATE,                   /* TX Bandwidth (64 kbits/sec)              */
+        BTM_64KBITS_RATE,                   /* RX Bandwidth (64 kbits/sec)              */
+        0x000a,                             /* 10 ms (HS/HF can use EV3, 2-EV3, 3-EV3)  */
+        BTM_VOICE_SETTING_CVSD,             /* Inp Linear, Air CVSD, 2s Comp, 16bit     */
+       (BTM_SCO_PKT_TYPES_MASK_HV1      +  /* Packet Types                             */
+        BTM_SCO_PKT_TYPES_MASK_HV2      +
+        BTM_SCO_PKT_TYPES_MASK_HV3      +
+        BTM_SCO_PKT_TYPES_MASK_EV3      +
+        BTM_SCO_PKT_TYPES_MASK_EV4      +
+        BTM_SCO_PKT_TYPES_MASK_EV5      +
+        BTM_SCO_PKT_TYPES_MASK_NO_2_EV5 +
+        BTM_SCO_PKT_TYPES_MASK_NO_3_EV5),
+        BTM_ESCO_RETRANS_POWER       /* Retransmission effort                      */
+    },
+    /* mSBC */
+    {
+        BTM_64KBITS_RATE,                   /* TX Bandwidth (64 kbits/sec), 8000        */
+        BTM_64KBITS_RATE,                   /* RX Bandwidth (64 kbits/sec), 8000        */
+        13,                                 /* 13 ms                                    */
+        BTM_VOICE_SETTING_TRANS,            /* Inp Linear, Transparent, 2s Comp, 16bit  */
+       (BTM_SCO_PKT_TYPES_MASK_EV3      |   /* Packet Types : EV3 + 2-EV3               */
+        BTM_SCO_PKT_TYPES_MASK_NO_3_EV3 |
+        BTM_SCO_PKT_TYPES_MASK_NO_2_EV5 |
+        BTM_SCO_PKT_TYPES_MASK_NO_3_EV5),
+        BTM_ESCO_RETRANS_QUALITY       /* Retransmission effort                      */
+    }
+};
+#else
+static const tBTM_ESCO_PARAMS bta_ag_esco_params =
+{
+    BTM_64KBITS_RATE,                   /* TX Bandwidth (64 kbits/sec)              */
+    BTM_64KBITS_RATE,                   /* RX Bandwidth (64 kbits/sec)              */
+    0x000a,                             /* 10 ms (HS/HF can use EV3, 2-EV3, 3-EV3)  */
+    0x0060,                             /* Inp Linear, Air CVSD, 2s Comp, 16bit     */
+    (BTM_SCO_PKT_TYPES_MASK_HV1      +  /* Packet Types                             */
+     BTM_SCO_PKT_TYPES_MASK_HV2      +
+     BTM_SCO_PKT_TYPES_MASK_HV3      +
+     BTM_SCO_PKT_TYPES_MASK_EV3      +
+     BTM_SCO_PKT_TYPES_MASK_EV4      +
+     BTM_SCO_PKT_TYPES_MASK_EV5      +
+     BTM_SCO_PKT_TYPES_MASK_NO_2_EV5 +
+     BTM_SCO_PKT_TYPES_MASK_NO_3_EV5),
+     BTM_ESCO_RETRANS_POWER       /* Retransmission effort                      */
+};
+#endif
+
+/*******************************************************************************
+**
+** Function         bta_ag_sco_conn_cback
+**
+** Description      BTM SCO connection callback.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+static void bta_ag_sco_conn_cback(UINT16 sco_idx)
+{
+    UINT16  handle;
+    BT_HDR  *p_buf;
+    tBTA_AG_SCB *p_scb;
+
+    /* match callback to scb; first check current sco scb */
+    if (bta_ag_cb.sco.p_curr_scb != NULL && bta_ag_cb.sco.p_curr_scb->in_use)
+    {
+        handle = bta_ag_scb_to_idx(bta_ag_cb.sco.p_curr_scb);
+    }
+    /* then check for scb connected to this peer */
+    else
+    {
+        /* Check if SLC is up */
+        handle = bta_ag_idx_by_bdaddr(BTM_ReadScoBdAddr(sco_idx));
+        p_scb = bta_ag_scb_by_idx(handle);
+        if(p_scb && !p_scb->svc_conn)
+            handle = 0;
+    }
+
+    if (handle != 0)
+    {
+        if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL)
+        {
+            p_buf->event = BTA_AG_SCO_OPEN_EVT;
+            p_buf->layer_specific = handle;
+            bta_sys_sendmsg(p_buf);
+        }
+    }
+    /* no match found; disconnect sco, init sco variables */
+    else
+    {
+        bta_ag_cb.sco.p_curr_scb = NULL;
+        bta_ag_cb.sco.state = BTA_AG_SCO_SHUTDOWN_ST;
+        BTM_RemoveSco(sco_idx);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_sco_disc_cback
+**
+** Description      BTM SCO disconnection callback.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+static void bta_ag_sco_disc_cback(UINT16 sco_idx)
+{
+    BT_HDR  *p_buf;
+    UINT16  handle = 0;
+
+    APPL_TRACE_DEBUG3 ("bta_ag_sco_disc_cback(): sco_idx: 0x%x  p_cur_scb: 0x%08x  sco.state: %d", sco_idx, bta_ag_cb.sco.p_curr_scb, bta_ag_cb.sco.state);
+
+    APPL_TRACE_DEBUG4 ("bta_ag_sco_disc_cback(): scb[0] addr: 0x%08x  in_use: %u  sco_idx: 0x%x  sco state: %u",
+                       &bta_ag_cb.scb[0], bta_ag_cb.scb[0].in_use, bta_ag_cb.scb[0].sco_idx, bta_ag_cb.scb[0].state);
+    APPL_TRACE_DEBUG4 ("bta_ag_sco_disc_cback(): scb[1] addr: 0x%08x  in_use: %u  sco_idx: 0x%x  sco state: %u",
+                       &bta_ag_cb.scb[1], bta_ag_cb.scb[1].in_use, bta_ag_cb.scb[1].sco_idx, bta_ag_cb.scb[1].state);
+
+    /* match callback to scb */
+    if (bta_ag_cb.sco.p_curr_scb != NULL && bta_ag_cb.sco.p_curr_scb->in_use)
+    {
+        /* We only care about callbacks for the active SCO */
+        if (bta_ag_cb.sco.p_curr_scb->sco_idx != sco_idx)
+        {
+            if (bta_ag_cb.sco.p_curr_scb->sco_idx != 0xFFFF)
+                return;
+        }
+        handle  = bta_ag_scb_to_idx(bta_ag_cb.sco.p_curr_scb);
+    }
+
+    if (handle != 0)
+    {
+#if (BTM_SCO_HCI_INCLUDED == TRUE )
+        tBTM_STATUS status = BTM_ConfigScoPath(BTM_SCO_ROUTE_PCM, NULL, NULL, TRUE);
+        APPL_TRACE_DEBUG1("bta_ag_sco_disc_cback sco close config status = %d", status);
+	    /* SCO clean up here */
+        bta_dm_sco_co_close();
+#endif
+
+#if (BTM_WBS_INCLUDED == TRUE )
+        /* Restore settings */
+        if(bta_ag_cb.sco.p_curr_scb->inuse_codec == BTA_AG_CODEC_MSBC)
+        {
+            BTM_SetWBSCodec (BTM_SCO_CODEC_NONE);
+            BTM_WriteVoiceSettings (BTM_VOICE_SETTING_CVSD);
+
+            /* If SCO open was initiated by AG and failed for mSBC, try CVSD again. */
+            if (bta_ag_sco_is_opening (bta_ag_cb.sco.p_curr_scb))
+            {
+                bta_ag_cb.sco.p_curr_scb->codec_fallback = TRUE;
+                APPL_TRACE_DEBUG0("Fallback to CVSD");
+            }
+        }
+
+        bta_ag_cb.sco.p_curr_scb->inuse_codec = BTA_AG_CODEC_NONE;
+#endif
+
+        if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL)
+        {
+            p_buf->event = BTA_AG_SCO_CLOSE_EVT;
+            p_buf->layer_specific = handle;
+            bta_sys_sendmsg(p_buf);
+        }
+    }
+    /* no match found */
+    else
+    {
+        APPL_TRACE_DEBUG0("no scb for ag_sco_disc_cback");
+
+        /* sco could be closed after scb dealloc'ed */
+        if (bta_ag_cb.sco.p_curr_scb != NULL)
+        {
+            bta_ag_cb.sco.p_curr_scb->sco_idx = BTM_INVALID_SCO_INDEX;
+            bta_ag_cb.sco.p_curr_scb = NULL;
+            bta_ag_cb.sco.state = BTA_AG_SCO_SHUTDOWN_ST;
+        }
+    }
+}
+#if (BTM_SCO_HCI_INCLUDED == TRUE )
+/*******************************************************************************
+**
+** Function         bta_ag_sco_read_cback
+**
+** Description      Callback function is the callback function for incoming
+**                  SCO data over HCI.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void bta_ag_sco_read_cback (UINT16 sco_inx, BT_HDR *p_data, tBTM_SCO_DATA_FLAG status)
+{
+    if (status != BTM_SCO_DATA_CORRECT)
+    {
+        APPL_TRACE_DEBUG1("bta_ag_sco_read_cback: status(%d)", status);
+    }
+
+    /* Callout function must free the data. */
+    bta_dm_sco_co_in_data (p_data, status);
+}
+#endif
+/*******************************************************************************
+**
+** Function         bta_ag_remove_sco
+**
+** Description      Removes the specified SCO from the system.
+**                  If only_active is TRUE, then SCO is only removed if connected
+**
+** Returns          BOOLEAN   - TRUE if Sco removal was started
+**
+*******************************************************************************/
+static BOOLEAN bta_ag_remove_sco(tBTA_AG_SCB *p_scb, BOOLEAN only_active)
+{
+    BOOLEAN     removed_started = FALSE;
+    tBTM_STATUS	status;
+
+    if (p_scb->sco_idx != BTM_INVALID_SCO_INDEX)
+    {
+        if (!only_active || p_scb->sco_idx == bta_ag_cb.sco.cur_idx)
+        {
+            status = BTM_RemoveSco(p_scb->sco_idx);
+
+            APPL_TRACE_DEBUG2("ag remove sco: inx 0x%04x, status:0x%x", p_scb->sco_idx, status);
+
+            if (status == BTM_CMD_STARTED)
+            {
+                /* Sco is connected; set current control block */
+                bta_ag_cb.sco.p_curr_scb = p_scb;
+
+                removed_started = TRUE;
+            }
+            /* If no connection reset the sco handle */
+            else if ( (status == BTM_SUCCESS) || (status == BTM_UNKNOWN_ADDR) )
+            {
+                p_scb->sco_idx = BTM_INVALID_SCO_INDEX;
+            }
+        }
+    }
+    return removed_started;
+}
+
+
+/*******************************************************************************
+**
+** Function         bta_ag_esco_connreq_cback
+**
+** Description      BTM eSCO connection requests and eSCO change requests
+**                  Only the connection requests are processed by BTA.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void bta_ag_esco_connreq_cback(tBTM_ESCO_EVT event, tBTM_ESCO_EVT_DATA *p_data)
+{
+    tBTA_AG_SCB         *p_scb;
+    UINT16               handle;
+    UINT16               sco_inx = p_data->conn_evt.sco_inx;
+
+    /* Only process connection requests */
+    if (event == BTM_ESCO_CONN_REQ_EVT)
+    {
+        if ((handle = bta_ag_idx_by_bdaddr(BTM_ReadScoBdAddr(sco_inx))) != 0 &&
+            ((p_scb = bta_ag_scb_by_idx(handle)) != NULL) && p_scb->svc_conn)
+        {
+            p_scb->sco_idx = sco_inx;
+
+            /* If no other SCO active, allow this one */
+            if (!bta_ag_cb.sco.p_curr_scb)
+            {
+                APPL_TRACE_EVENT1("bta_ag_esco_connreq_cback: Accept Conn Request (sco_inx 0x%04x)", sco_inx);
+                bta_ag_sco_conn_rsp(p_scb, &p_data->conn_evt);
+
+                bta_ag_cb.sco.state = BTA_AG_SCO_OPENING_ST;
+                bta_ag_cb.sco.p_curr_scb = p_scb;
+                bta_ag_cb.sco.cur_idx = p_scb->sco_idx;
+            }
+            else    /* Begin a transfer: Close current SCO before responding */
+            {
+                APPL_TRACE_DEBUG0("bta_ag_esco_connreq_cback: Begin XFER");
+                bta_ag_cb.sco.p_xfer_scb = p_scb;
+                bta_ag_cb.sco.conn_data = p_data->conn_evt;
+                bta_ag_cb.sco.state = BTA_AG_SCO_OPEN_XFER_ST;
+
+                if (!bta_ag_remove_sco(bta_ag_cb.sco.p_curr_scb, TRUE))
+                {
+                    APPL_TRACE_ERROR1("bta_ag_esco_connreq_cback: Nothing to remove so accept Conn Request (sco_inx 0x%04x)", sco_inx);
+                    bta_ag_cb.sco.p_xfer_scb = NULL;
+                    bta_ag_cb.sco.state = BTA_AG_SCO_LISTEN_ST;
+
+                    bta_ag_sco_conn_rsp(p_scb, &p_data->conn_evt);
+                }
+            }
+        }
+        /* If error occurred send reject response immediately */
+        else
+        {
+            APPL_TRACE_WARNING0("no scb for bta_ag_esco_connreq_cback or no resources");
+            BTM_EScoConnRsp(p_data->conn_evt.sco_inx, HCI_ERR_HOST_REJECT_RESOURCES, NULL);
+        }
+    }
+    /* Received a change in the esco link */
+    else if (event == BTM_ESCO_CHG_EVT)
+    {
+        APPL_TRACE_EVENT5("eSCO change event (inx %d): rtrans %d, rxlen %d, txlen %d, txint %d",
+            p_data->chg_evt.sco_inx,
+            p_data->chg_evt.retrans_window, p_data->chg_evt.rx_pkt_len,
+            p_data->chg_evt.tx_pkt_len, p_data->chg_evt.tx_interval);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_cback_sco
+**
+** Description      Call application callback function with SCO event.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+static void bta_ag_cback_sco(tBTA_AG_SCB *p_scb, UINT8 event)
+{
+    tBTA_AG_HDR    sco;
+
+    sco.handle = bta_ag_scb_to_idx(p_scb);
+    sco.app_id = p_scb->app_id;
+
+    /* call close cback */
+    (*bta_ag_cb.p_cback)(event, (tBTA_AG *) &sco);
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_create_sco
+**
+** Description
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+static void bta_ag_create_sco(tBTA_AG_SCB *p_scb, BOOLEAN is_orig)
+{
+    tBTM_STATUS       status;
+    UINT8            *p_bd_addr = NULL;
+    tBTM_ESCO_PARAMS params;
+#if (BTM_WBS_INCLUDED == TRUE )
+    tBTA_AG_PEER_CODEC  esco_codec = BTM_SCO_CODEC_CVSD;
+    int codec_index = 0;
+#endif
+#if (BTM_SCO_HCI_INCLUDED == TRUE )
+    tBTM_SCO_ROUTE_TYPE sco_route;
+    tBTA_CODEC_INFO     codec_info = {BTA_SCO_CODEC_PCM};
+    UINT32              pcm_sample_rate;
+#endif
+
+    /* Make sure this sco handle is not already in use */
+    if (p_scb->sco_idx != BTM_INVALID_SCO_INDEX)
+    {
+        APPL_TRACE_WARNING1("bta_ag_create_sco: Index 0x%04x Already In Use!",
+                             p_scb->sco_idx);
+        return;
+    }
+
+#if (BTM_WBS_INCLUDED == TRUE )
+    if ((p_scb->sco_codec == BTM_SCO_CODEC_MSBC) &&
+        !p_scb->codec_fallback &&
+        !p_scb->retry_with_sco_only)
+        esco_codec = BTM_SCO_CODEC_MSBC;
+
+    if (p_scb->codec_fallback)
+    {
+        p_scb->codec_fallback = FALSE;
+
+        /* Force AG to send +BCS for the next audio connection. */
+        p_scb->codec_updated = TRUE;
+    }
+
+    if (esco_codec == BTM_SCO_CODEC_MSBC)
+        codec_index = esco_codec - 1;
+
+    params = bta_ag_esco_params[codec_index];
+#else
+    params = bta_ag_esco_params;
+#endif
+
+    if(bta_ag_cb.sco.param_updated) /* If we do not use the default parameters */
+        params = bta_ag_cb.sco.params;
+
+    if(!bta_ag_cb.sco.param_updated)
+    {
+#if (BTM_WBS_INCLUDED == TRUE)
+        if (!codec_index)   /* For non-WBS */
+#endif
+        {
+            /* Use the application packet types (5 slot EV packets not allowed) */
+            params.packet_types = p_bta_ag_cfg->sco_pkt_types     |
+                                  BTM_SCO_PKT_TYPES_MASK_NO_2_EV5 |
+                                  BTM_SCO_PKT_TYPES_MASK_NO_3_EV5;
+        }
+    }
+
+    /* if initiating set current scb and peer bd addr */
+    if (is_orig)
+    {
+        /* Attempt to use eSCO if remote host supports HFP >= 1.5 */
+        /* Need to find out from SIG if HSP can use eSCO; for now use SCO */
+        if (p_scb->conn_service == BTA_AG_HFP && p_scb->peer_version >= HFP_VERSION_1_5 && !p_scb->retry_with_sco_only)
+        {
+
+            BTM_SetEScoMode(BTM_LINK_TYPE_ESCO, &params);
+            /* If ESCO or EDR ESCO, retry with SCO only in case of failure */
+            if((params.packet_types & BTM_ESCO_LINK_ONLY_MASK)
+               ||!((params.packet_types & ~(BTM_ESCO_LINK_ONLY_MASK | BTM_SCO_LINK_ONLY_MASK)) ^ BTA_AG_NO_EDR_ESCO))
+            {
+#if (BTM_WBS_INCLUDED == TRUE )
+                if (esco_codec != BTA_AG_CODEC_MSBC)
+                {
+                    p_scb->retry_with_sco_only = TRUE;
+                    APPL_TRACE_API0("Setting retry_with_sco_only to TRUE");
+                }
+                else    /* Do not use SCO when using mSBC */
+                {
+                    p_scb->retry_with_sco_only = FALSE;
+                    APPL_TRACE_API0("Setting retry_with_sco_only to FALSE");
+                }
+#else
+                p_scb->retry_with_sco_only = TRUE;
+                APPL_TRACE_API0("Setting retry_with_sco_only to TRUE");
+#endif
+            }
+        }
+        else
+        {
+            if(p_scb->retry_with_sco_only)
+                APPL_TRACE_API0("retrying with SCO only");
+            p_scb->retry_with_sco_only = FALSE;
+
+            BTM_SetEScoMode(BTM_LINK_TYPE_SCO, &params);
+        }
+
+        bta_ag_cb.sco.p_curr_scb = p_scb;
+
+        /* tell sys to stop av if any */
+        bta_sys_sco_use(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+
+        /* Allow any platform specific pre-SCO set up to take place */
+        bta_ag_co_audio_state(bta_ag_scb_to_idx(p_scb), p_scb->app_id, BTA_AG_CO_AUD_STATE_SETUP);
+
+#if (BTM_SCO_HCI_INCLUDED == TRUE )
+#if (BTM_WBS_INCLUDED == TRUE)
+        if (esco_codec == BTA_AG_CODEC_MSBC)
+            pcm_sample_rate = BTA_DM_SCO_SAMP_RATE_16K;
+        else
+#endif
+            pcm_sample_rate = BTA_DM_SCO_SAMP_RATE_8K;
+
+        sco_route = bta_dm_sco_co_init(pcm_sample_rate, pcm_sample_rate, &codec_info, p_scb->app_id);
+#endif
+
+#if (BTM_WBS_INCLUDED == TRUE )
+        if (esco_codec == BTA_AG_CODEC_MSBC)
+        {
+            /* Enable mSBC codec in fw */
+            BTM_SetWBSCodec (esco_codec);
+        }
+
+        /* Specify PCM input for SBC codec in fw */
+        BTM_ConfigI2SPCM (esco_codec, (UINT8)HCI_BRCM_I2SPCM_IS_DEFAULT_ROLE, (UINT8)HCI_BRCM_I2SPCM_SAMPLE_DEFAULT, (UINT8)HCI_BRCM_I2SPCM_CLOCK_DEFAULT);
+
+        /* This setting may not be necessary */
+        /* To be verified with stable 2049 boards */
+        if (esco_codec == BTA_AG_CODEC_MSBC)
+            BTM_WriteVoiceSettings (BTM_VOICE_SETTING_TRANS);
+        else
+            BTM_WriteVoiceSettings (BTM_VOICE_SETTING_CVSD);
+
+        /* save the current codec because sco_codec can be updated while SCO is open. */
+        p_scb->inuse_codec = esco_codec;
+#endif
+
+#if (BTM_SCO_HCI_INCLUDED == TRUE )
+        /* initialize SCO setup, no voice setting for AG, data rate <==> sample rate */
+        BTM_ConfigScoPath(sco_route, bta_ag_sco_read_cback, NULL, TRUE);
+#endif
+        bta_ag_cb.sco.cur_idx = p_scb->sco_idx;
+    }
+    else
+        p_scb->retry_with_sco_only = FALSE;
+
+    p_bd_addr = p_scb->peer_addr;
+
+    status = BTM_CreateSco(p_bd_addr, is_orig, params.packet_types,
+                           &p_scb->sco_idx, bta_ag_sco_conn_cback,
+                           bta_ag_sco_disc_cback);
+    if (status == BTM_CMD_STARTED)
+    {
+        if (!is_orig)
+        {
+            BTM_RegForEScoEvts(p_scb->sco_idx, bta_ag_esco_connreq_cback);
+        }
+        else    /* Initiating the connection, set the current sco handle */
+        {
+            bta_ag_cb.sco.cur_idx = p_scb->sco_idx;
+        }
+    }
+
+    APPL_TRACE_API4("ag create sco: orig %d, inx 0x%04x, status 0x%x, pkt types 0x%04x",
+                      is_orig, p_scb->sco_idx, status, params.packet_types);
+}
+
+#if (BTM_WBS_INCLUDED == TRUE )
+/*******************************************************************************
+**
+** Function         bta_ag_cn_timer_cback
+**
+** Description
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+static void bta_ag_cn_timer_cback (TIMER_LIST_ENT *p_tle)
+{
+    tBTA_AG_SCB *p_scb;
+
+    if (p_tle)
+    {
+        p_scb = (tBTA_AG_SCB *)p_tle->param;
+
+        if (p_scb)
+        {
+            /* Announce that codec negotiation failed. */
+            bta_ag_sco_codec_nego(p_scb, FALSE);
+
+            /* call app callback */
+            bta_ag_cback_sco(p_scb, BTA_AG_AUDIO_CLOSE_EVT);
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_codec_negotiate
+**
+** Description      Initiate codec negotiation by sending AT command.
+**                  If not necessary, skip negotiation.
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_codec_negotiate(tBTA_AG_SCB *p_scb)
+{
+    bta_ag_cb.sco.p_curr_scb = p_scb;
+
+    if (p_scb->codec_updated || p_scb->codec_fallback)
+    {
+        /* Change the power mode to Active until sco open is completed. */
+        bta_sys_busy(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+
+        /* Send +BCS to the peer */
+        bta_ag_send_bcs(p_scb, NULL);
+
+        /* Start timer to handle timeout */
+        p_scb->cn_timer.p_cback = (TIMER_CBACK*)&bta_ag_cn_timer_cback;
+        p_scb->cn_timer.param = (INT32)p_scb;
+        bta_sys_start_timer(&p_scb->cn_timer, 0, BTA_AG_CODEC_NEGO_TIMEOUT);
+    }
+    else
+    {
+        /* use same codec type as previous SCO connection, skip codec negotiation */
+        bta_ag_sco_codec_nego(p_scb, TRUE);
+    }
+}
+#endif
+
+/*******************************************************************************
+**
+** Function         bta_ag_sco_event
+**
+** Description
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+static void bta_ag_sco_event(tBTA_AG_SCB *p_scb, UINT8 event)
+{
+    tBTA_AG_SCO_CB *p_sco = &bta_ag_cb.sco;
+#if (BTM_WBS_INCLUDED == TRUE )
+    tBTA_AG_SCB *p_cn_scb = NULL;   /* For codec negotiation */
+#endif
+#if (BTM_SCO_HCI_INCLUDED == TRUE )
+    BT_HDR  *p_buf;
+#endif
+#if BTA_AG_SCO_DEBUG == TRUE
+    UINT8   in_state = p_sco->state;
+
+    APPL_TRACE_EVENT5("BTA ag sco evt (hdl 0x%04x): State %d (%s), Event %d (%s)",
+                        p_scb->sco_idx,
+                        p_sco->state, bta_ag_sco_state_str(p_sco->state),
+                        event, bta_ag_sco_evt_str(event));
+#else
+    APPL_TRACE_EVENT3("BTA ag sco evt (hdl 0x%04x): State %d, Event %d",
+                      p_scb->sco_idx, p_sco->state, event);
+#endif
+
+#if (BTM_SCO_HCI_INCLUDED == TRUE )
+    if (event == BTA_AG_SCO_CI_DATA_E)
+    {
+        while (TRUE)
+        {
+            bta_dm_sco_co_out_data(&p_buf);
+            if (p_buf)
+            {
+                if (p_sco->state == BTA_AG_SCO_OPEN_ST)
+                    BTM_WriteScoData(p_sco->p_curr_scb->sco_idx, p_buf);
+                else
+                    GKI_freebuf(p_buf);
+            }
+            else
+                break;
+        }
+
+        return;
+    }
+#endif
+
+    switch (p_sco->state)
+    {
+        case BTA_AG_SCO_SHUTDOWN_ST:
+            switch (event)
+            {
+                case BTA_AG_SCO_LISTEN_E:
+                    /* create sco listen connection */
+                    bta_ag_create_sco(p_scb, FALSE);
+                    p_sco->state = BTA_AG_SCO_LISTEN_ST;
+                    break;
+
+                default:
+                    APPL_TRACE_WARNING1("BTA_AG_SCO_SHUTDOWN_ST: Ignoring event %d", event);
+                    break;
+            }
+            break;
+
+        case BTA_AG_SCO_LISTEN_ST:
+            switch (event)
+            {
+                case BTA_AG_SCO_LISTEN_E:
+                    /* create sco listen connection (Additional channel) */
+                    bta_ag_create_sco(p_scb, FALSE);
+                    break;
+
+                case BTA_AG_SCO_OPEN_E:
+                    /* remove listening connection */
+                    bta_ag_remove_sco(p_scb, FALSE);
+
+#if (BTM_WBS_INCLUDED == TRUE )
+                    /* start codec negotiation */
+                    p_sco->state = BTA_AG_SCO_CODEC_ST;
+                    p_cn_scb = p_scb;
+#else
+                    /* create sco connection to peer */
+                    bta_ag_create_sco(p_scb, TRUE);
+                    p_sco->state = BTA_AG_SCO_OPENING_ST;
+#endif
+                    break;
+
+                case BTA_AG_SCO_SHUTDOWN_E:
+                    /* remove listening connection */
+                    bta_ag_remove_sco(p_scb, FALSE);
+
+                    if (p_scb == p_sco->p_curr_scb)
+                        p_sco->p_curr_scb = NULL;
+
+                    /* If last SCO instance then finish shutting down */
+                    if (!bta_ag_other_scb_open(p_scb))
+                    {
+                        p_sco->state = BTA_AG_SCO_SHUTDOWN_ST;
+                    }
+                    break;
+
+                case BTA_AG_SCO_CLOSE_E:
+                    /* remove listening connection */
+                    /* Ignore the event. We need to keep listening SCO for the active SLC */
+                    APPL_TRACE_WARNING1("BTA_AG_SCO_LISTEN_ST: Ignoring event %d", event);
+                    break;
+
+                case BTA_AG_SCO_CONN_CLOSE_E:
+                    /* sco failed; create sco listen connection */
+                    bta_ag_create_sco(p_scb, FALSE);
+                    p_sco->state = BTA_AG_SCO_LISTEN_ST;
+                    break;
+
+                default:
+                    APPL_TRACE_WARNING1("BTA_AG_SCO_LISTEN_ST: Ignoring event %d", event);
+                    break;
+            }
+            break;
+
+#if (BTM_WBS_INCLUDED == TRUE )
+        case BTA_AG_SCO_CODEC_ST:
+            switch (event)
+            {
+                case BTA_AG_SCO_LISTEN_E:
+                    /* create sco listen connection (Additional channel) */
+                    bta_ag_create_sco(p_scb, FALSE);
+                    break;
+
+                case BTA_AG_SCO_CN_DONE_E:
+                    /* create sco connection to peer */
+                    bta_ag_create_sco(p_scb, TRUE);
+                    p_sco->state = BTA_AG_SCO_OPENING_ST;
+                    break;
+
+                case BTA_AG_SCO_XFER_E:
+                    /* save xfer scb */
+                    p_sco->p_xfer_scb = p_scb;
+                    p_sco->state = BTA_AG_SCO_CLOSE_XFER_ST;
+                    break;
+
+                case BTA_AG_SCO_SHUTDOWN_E:
+                    /* remove listening connection */
+                    bta_ag_remove_sco(p_scb, FALSE);
+
+                    if (p_scb == p_sco->p_curr_scb)
+                        p_sco->p_curr_scb = NULL;
+
+                    /* If last SCO instance then finish shutting down */
+                    if (!bta_ag_other_scb_open(p_scb))
+                    {
+                        p_sco->state = BTA_AG_SCO_SHUTDOWN_ST;
+                    }
+                    break;
+
+                case BTA_AG_SCO_CLOSE_E:
+                    /* sco open is not started yet. just go back to listening */
+                    p_sco->state = BTA_AG_SCO_LISTEN_ST;
+                    break;
+
+                case BTA_AG_SCO_CONN_CLOSE_E:
+                    /* sco failed; create sco listen connection */
+                    bta_ag_create_sco(p_scb, FALSE);
+                    p_sco->state = BTA_AG_SCO_LISTEN_ST;
+                    break;
+
+                default:
+                    APPL_TRACE_WARNING1("BTA_AG_SCO_CODEC_ST: Ignoring event %d", event);
+                    break;
+            }
+            break;
+#endif
+
+        case BTA_AG_SCO_OPENING_ST:
+            switch (event)
+            {
+                case BTA_AG_SCO_LISTEN_E:
+                    /* second headset has now joined */
+                    /* create sco listen connection (Additional channel) */
+                    if (p_scb != p_sco->p_curr_scb)
+                    {
+                        bta_ag_create_sco(p_scb, FALSE);
+                    }
+                    break;
+
+#if (BTM_WBS_INCLUDED == TRUE)
+                case BTA_AG_SCO_REOPEN_E:
+                    /* start codec negotiation */
+                    p_sco->state = BTA_AG_SCO_CODEC_ST;
+                    p_cn_scb = p_scb;
+                    break;
+#endif
+
+                case BTA_AG_SCO_XFER_E:
+                    /* save xfer scb */
+                    p_sco->p_xfer_scb = p_scb;
+                    p_sco->state = BTA_AG_SCO_CLOSE_XFER_ST;
+                    break;
+
+                case BTA_AG_SCO_CLOSE_E:
+                    p_sco->state = BTA_AG_SCO_OPEN_CL_ST;
+                    break;
+
+                case BTA_AG_SCO_SHUTDOWN_E:
+                    /* If not opening scb, just close it */
+                    if (p_scb != p_sco->p_curr_scb)
+                    {
+                        /* remove listening connection */
+                        bta_ag_remove_sco(p_scb, FALSE);
+                    }
+                    else
+                        p_sco->state = BTA_AG_SCO_SHUTTING_ST;
+
+                    break;
+
+                case BTA_AG_SCO_CONN_OPEN_E:
+                    p_sco->state = BTA_AG_SCO_OPEN_ST;
+                    break;
+
+                case BTA_AG_SCO_CONN_CLOSE_E:
+                    /* sco failed; create sco listen connection */
+                    bta_ag_create_sco(p_scb, FALSE);
+                    p_sco->state = BTA_AG_SCO_LISTEN_ST;
+                    break;
+
+                default:
+                    APPL_TRACE_WARNING1("BTA_AG_SCO_OPENING_ST: Ignoring event %d", event);
+                    break;
+            }
+            break;
+
+        case BTA_AG_SCO_OPEN_CL_ST:
+            switch (event)
+            {
+                case BTA_AG_SCO_XFER_E:
+                    /* save xfer scb */
+                    p_sco->p_xfer_scb = p_scb;
+
+                    p_sco->state = BTA_AG_SCO_CLOSE_XFER_ST;
+                    break;
+
+                case BTA_AG_SCO_OPEN_E:
+                    p_sco->state = BTA_AG_SCO_OPENING_ST;
+                    break;
+
+                case BTA_AG_SCO_SHUTDOWN_E:
+                    /* If not opening scb, just close it */
+                    if (p_scb != p_sco->p_curr_scb)
+                    {
+                        /* remove listening connection */
+                        bta_ag_remove_sco(p_scb, FALSE);
+                    }
+                    else
+                        p_sco->state = BTA_AG_SCO_SHUTTING_ST;
+
+                    break;
+
+                case BTA_AG_SCO_CONN_OPEN_E:
+                    /* close sco connection */
+                    bta_ag_remove_sco(p_scb, TRUE);
+
+                    p_sco->state = BTA_AG_SCO_CLOSING_ST;
+                    break;
+
+                case BTA_AG_SCO_CONN_CLOSE_E:
+                    /* sco failed; create sco listen connection */
+
+                    p_sco->state = BTA_AG_SCO_LISTEN_ST;
+                    break;
+
+                default:
+                    APPL_TRACE_WARNING1("BTA_AG_SCO_OPEN_CL_ST: Ignoring event %d", event);
+                    break;
+            }
+            break;
+
+        case BTA_AG_SCO_OPEN_XFER_ST:
+            switch (event)
+            {
+                case BTA_AG_SCO_CLOSE_E:
+                    /* close sco connection */
+                    bta_ag_remove_sco(p_scb, TRUE);
+
+                    p_sco->state = BTA_AG_SCO_CLOSING_ST;
+                    break;
+
+                case BTA_AG_SCO_SHUTDOWN_E:
+                    /* remove all connection */
+                    bta_ag_remove_sco(p_scb, FALSE);
+                    p_sco->state = BTA_AG_SCO_SHUTTING_ST;
+
+                    break;
+
+                case BTA_AG_SCO_CONN_CLOSE_E:
+                    /* closed sco; place in listen mode and
+                       accept the transferred connection */
+                    bta_ag_create_sco(p_scb, FALSE);    /* Back into listen mode */
+
+                    /* Accept sco connection with xfer scb */
+                    bta_ag_sco_conn_rsp(p_sco->p_xfer_scb, &p_sco->conn_data);
+                    p_sco->state = BTA_AG_SCO_OPENING_ST;
+                    p_sco->p_curr_scb = p_sco->p_xfer_scb;
+                    p_sco->cur_idx = p_sco->p_xfer_scb->sco_idx;
+                    p_sco->p_xfer_scb = NULL;
+                     break;
+
+                default:
+                    APPL_TRACE_WARNING1("BTA_AG_SCO_OPEN_XFER_ST: Ignoring event %d", event);
+                    break;
+            }
+            break;
+
+        case BTA_AG_SCO_OPEN_ST:
+            switch (event)
+            {
+                case BTA_AG_SCO_LISTEN_E:
+                    /* second headset has now joined */
+                    /* create sco listen connection (Additional channel) */
+                    if (p_scb != p_sco->p_curr_scb)
+                    {
+                        bta_ag_create_sco(p_scb, FALSE);
+                    }
+                    break;
+
+                case BTA_AG_SCO_XFER_E:
+                    /* close current sco connection */
+                    bta_ag_remove_sco(p_sco->p_curr_scb, TRUE);
+
+                    /* save xfer scb */
+                    p_sco->p_xfer_scb = p_scb;
+
+                    p_sco->state = BTA_AG_SCO_CLOSE_XFER_ST;
+                    break;
+
+                case BTA_AG_SCO_CLOSE_E:
+                    /* close sco connection if active */
+                    if (bta_ag_remove_sco(p_scb, TRUE))
+                    {
+                        p_sco->state = BTA_AG_SCO_CLOSING_ST;
+                    }
+                    break;
+
+                case BTA_AG_SCO_SHUTDOWN_E:
+                    /* remove all listening connections */
+                    bta_ag_remove_sco(p_scb, FALSE);
+
+                    /* If SCO was active on this scb, close it */
+                    if (p_scb == p_sco->p_curr_scb)
+                    {
+                        p_sco->state = BTA_AG_SCO_SHUTTING_ST;
+                    }
+                    break;
+
+                case BTA_AG_SCO_CONN_CLOSE_E:
+                    /* peer closed sco; create sco listen connection */
+                    bta_ag_create_sco(p_scb, FALSE);
+                    p_sco->state = BTA_AG_SCO_LISTEN_ST;
+                    break;
+
+                default:
+                    APPL_TRACE_WARNING1("BTA_AG_SCO_OPEN_ST: Ignoring event %d", event);
+                    break;
+            }
+            break;
+
+        case BTA_AG_SCO_CLOSING_ST:
+            switch (event)
+            {
+                case BTA_AG_SCO_LISTEN_E:
+                    /* create sco listen connection (Additional channel) */
+                    if (p_scb != p_sco->p_curr_scb)
+                    {
+                        bta_ag_create_sco(p_scb, FALSE);
+                    }
+                    break;
+
+                case BTA_AG_SCO_OPEN_E:
+                    p_sco->state = BTA_AG_SCO_CLOSE_OP_ST;
+                    break;
+
+                case BTA_AG_SCO_XFER_E:
+                    /* save xfer scb */
+                    p_sco->p_xfer_scb = p_scb;
+
+                    p_sco->state = BTA_AG_SCO_CLOSE_XFER_ST;
+                    break;
+
+                case BTA_AG_SCO_SHUTDOWN_E:
+                    /* If not closing scb, just close it */
+                    if (p_scb != p_sco->p_curr_scb)
+                    {
+                        /* remove listening connection */
+                        bta_ag_remove_sco(p_scb, FALSE);
+                    }
+                    else
+                        p_sco->state = BTA_AG_SCO_SHUTTING_ST;
+
+                    break;
+
+                case BTA_AG_SCO_CONN_CLOSE_E:
+                    /* peer closed sco; create sco listen connection */
+                    bta_ag_create_sco(p_scb, FALSE);
+
+                    p_sco->state = BTA_AG_SCO_LISTEN_ST;
+                    break;
+
+                default:
+                    APPL_TRACE_WARNING1("BTA_AG_SCO_CLOSING_ST: Ignoring event %d", event);
+                    break;
+            }
+            break;
+
+        case BTA_AG_SCO_CLOSE_OP_ST:
+            switch (event)
+            {
+                case BTA_AG_SCO_CLOSE_E:
+                    p_sco->state = BTA_AG_SCO_CLOSING_ST;
+                    break;
+
+                case BTA_AG_SCO_SHUTDOWN_E:
+                    p_sco->state = BTA_AG_SCO_SHUTTING_ST;
+                    break;
+
+                case BTA_AG_SCO_CONN_CLOSE_E:
+#if (BTM_WBS_INCLUDED == TRUE )
+                    /* start codec negotiation */
+                    p_sco->state = BTA_AG_SCO_CODEC_ST;
+                    p_cn_scb = p_scb;
+#else
+                    /* open sco connection */
+                    bta_ag_create_sco(p_scb, TRUE);
+                    p_sco->state = BTA_AG_SCO_OPENING_ST;
+#endif
+                    break;
+
+                case BTA_AG_SCO_LISTEN_E:
+                    /* create sco listen connection (Additional channel) */
+                    if (p_scb != p_sco->p_curr_scb)
+                    {
+                        bta_ag_create_sco(p_scb, FALSE);
+                    }
+                    break;
+
+                default:
+                    APPL_TRACE_WARNING1("BTA_AG_SCO_CLOSE_OP_ST: Ignoring event %d", event);
+                    break;
+            }
+            break;
+
+        case BTA_AG_SCO_CLOSE_XFER_ST:
+            switch (event)
+            {
+                case BTA_AG_SCO_CONN_OPEN_E:
+                    /* close sco connection so headset can be transferred
+                       Probably entered this state from "opening state" */
+                    bta_ag_remove_sco(p_scb, TRUE);
+                    break;
+
+                case BTA_AG_SCO_CLOSE_E:
+                    /* clear xfer scb */
+                    p_sco->p_xfer_scb = NULL;
+
+                    p_sco->state = BTA_AG_SCO_CLOSING_ST;
+                    break;
+
+                case BTA_AG_SCO_SHUTDOWN_E:
+                    /* clear xfer scb */
+                    p_sco->p_xfer_scb = NULL;
+
+                    p_sco->state = BTA_AG_SCO_SHUTTING_ST;
+                    break;
+
+                case BTA_AG_SCO_CONN_CLOSE_E:
+                    /* closed sco; place old sco in listen mode,
+                       take current sco out of listen, and
+                       create originating sco for current */
+                    bta_ag_create_sco(p_scb, FALSE);
+                    bta_ag_remove_sco(p_sco->p_xfer_scb, FALSE);
+
+#if (BTM_WBS_INCLUDED == TRUE )
+                    /* start codec negotiation */
+                    p_sco->state = BTA_AG_SCO_CODEC_ST;
+                    p_cn_scb = p_sco->p_xfer_scb;
+                    p_sco->p_xfer_scb = NULL;
+#else
+                    /* create sco connection to peer */
+                    bta_ag_create_sco(p_sco->p_xfer_scb, TRUE);
+                    p_sco->p_xfer_scb = NULL;
+                    p_sco->state = BTA_AG_SCO_OPENING_ST;
+#endif
+                    break;
+
+                default:
+                    APPL_TRACE_WARNING1("BTA_AG_SCO_CLOSE_XFER_ST: Ignoring event %d", event);
+                    break;
+            }
+            break;
+
+        case BTA_AG_SCO_SHUTTING_ST:
+            switch (event)
+            {
+                case BTA_AG_SCO_CONN_OPEN_E:
+                    /* close sco connection; wait for conn close event */
+                    bta_ag_remove_sco(p_scb, TRUE);
+                    break;
+
+                case BTA_AG_SCO_CONN_CLOSE_E:
+                    /* If last SCO instance then finish shutting down */
+                    if (!bta_ag_other_scb_open(p_scb))
+                    {
+                        p_sco->state = BTA_AG_SCO_SHUTDOWN_ST;
+                    }
+                    else    /* Other instance is still listening */
+                    {
+                        p_sco->state = BTA_AG_SCO_LISTEN_ST;
+                    }
+
+                    if (p_scb == p_sco->p_curr_scb)
+                    {
+                        p_sco->p_curr_scb->sco_idx = BTM_INVALID_SCO_INDEX;
+                        p_sco->p_curr_scb = NULL;
+                    }
+                    break;
+
+                case BTA_AG_SCO_LISTEN_E:
+                    /* create sco listen connection (Additional channel) */
+                    if (p_scb != p_sco->p_curr_scb)
+                    {
+                        bta_ag_create_sco(p_scb, FALSE);
+                    }
+                    break;
+
+                case BTA_AG_SCO_SHUTDOWN_E:
+                    if (!bta_ag_other_scb_open(p_scb))
+                    {
+                        p_sco->state = BTA_AG_SCO_SHUTDOWN_ST;
+                    }
+                    else    /* Other instance is still listening */
+                    {
+                        p_sco->state = BTA_AG_SCO_LISTEN_ST;
+                    }
+
+                    if (p_scb == p_sco->p_curr_scb)
+                    {
+                        p_sco->p_curr_scb->sco_idx = BTM_INVALID_SCO_INDEX;
+                        p_sco->p_curr_scb = NULL;
+                    }
+                    break;
+
+                default:
+                    APPL_TRACE_WARNING1("BTA_AG_SCO_SHUTTING_ST: Ignoring event %d", event);
+                    break;
+            }
+            break;
+
+        default:
+            break;
+    }
+#if BTA_AG_SCO_DEBUG == TRUE
+    if (p_sco->state != in_state)
+    {
+        APPL_TRACE_EVENT3("BTA AG SCO State Change: [%s] -> [%s] after Event [%s]",
+                      bta_ag_sco_state_str(in_state),
+                      bta_ag_sco_state_str(p_sco->state),
+                      bta_ag_sco_evt_str(event));
+    }
+#endif
+
+#if (BTM_WBS_INCLUDED == TRUE )
+    if (p_cn_scb)
+    {
+        bta_ag_codec_negotiate(p_cn_scb);
+    }
+#endif
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_sco_is_open
+**
+** Description      Check if sco is open for this scb.
+**
+**
+** Returns          TRUE if sco open for this scb, FALSE otherwise.
+**
+*******************************************************************************/
+BOOLEAN bta_ag_sco_is_open(tBTA_AG_SCB *p_scb)
+{
+    return ((bta_ag_cb.sco.state == BTA_AG_SCO_OPEN_ST) &&
+            (bta_ag_cb.sco.p_curr_scb == p_scb));
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_sco_is_opening
+**
+** Description      Check if sco is in Opening state.
+**
+**
+** Returns          TRUE if sco is in Opening state for this scb, FALSE otherwise.
+**
+*******************************************************************************/
+BOOLEAN bta_ag_sco_is_opening(tBTA_AG_SCB *p_scb)
+{
+#if (BTM_WBS_INCLUDED == TRUE )
+    return (((bta_ag_cb.sco.state == BTA_AG_SCO_OPENING_ST) ||
+            (bta_ag_cb.sco.state == BTA_AG_SCO_OPENING_ST)) &&
+            (bta_ag_cb.sco.p_curr_scb == p_scb));
+#else
+    return ((bta_ag_cb.sco.state == BTA_AG_SCO_OPENING_ST) &&
+            (bta_ag_cb.sco.p_curr_scb == p_scb));
+#endif
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_sco_listen
+**
+** Description
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_sco_listen(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+    UNUSED(p_data);
+    bta_ag_sco_event(p_scb, BTA_AG_SCO_LISTEN_E);
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_sco_open
+**
+** Description
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_sco_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+    UINT8 event;
+    UNUSED(p_data);
+
+    /* if another scb using sco, this is a transfer */
+    if (bta_ag_cb.sco.p_curr_scb != NULL && bta_ag_cb.sco.p_curr_scb != p_scb)
+    {
+        event = BTA_AG_SCO_XFER_E;
+    }
+    /* else it is an open */
+    else
+    {
+        event = BTA_AG_SCO_OPEN_E;
+    }
+
+    bta_ag_sco_event(p_scb, event);
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_sco_close
+**
+** Description
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_sco_close(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+    UNUSED(p_data);
+
+    /* if scb is in use */
+#if (BTM_WBS_INCLUDED == TRUE )
+    /* sco_idx is not allocated in SCO_CODEC_ST, we still need to move to listening state. */
+    if ((p_scb->sco_idx != BTM_INVALID_SCO_INDEX) || (bta_ag_cb.sco.state == BTA_AG_SCO_CODEC_ST))
+#else
+    if (p_scb->sco_idx != BTM_INVALID_SCO_INDEX)
+#endif
+    {
+        APPL_TRACE_DEBUG1("bta_ag_sco_close: sco_inx = %d", p_scb->sco_idx);
+        bta_ag_sco_event(p_scb, BTA_AG_SCO_CLOSE_E);
+    }
+}
+
+#if (BTM_WBS_INCLUDED == TRUE )
+
+/*******************************************************************************
+**
+** Function         bta_ag_sco_codec_nego
+**
+** Description
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_sco_codec_nego(tBTA_AG_SCB *p_scb, BOOLEAN result)
+{
+    if(result == TRUE)
+    {
+        /* Subsequent sco connection will skip codec negotiation */
+        p_scb->codec_updated = FALSE;
+
+        bta_ag_sco_event(p_scb, BTA_AG_SCO_CN_DONE_E);
+    }
+    else    /* codec negotiation failed */
+        bta_ag_sco_event(p_scb, BTA_AG_SCO_CLOSE_E);
+}
+#endif
+
+/*******************************************************************************
+**
+** Function         bta_ag_sco_shutdown
+**
+** Description
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_sco_shutdown(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+    UNUSED(p_data);
+
+    bta_ag_sco_event(p_scb, BTA_AG_SCO_SHUTDOWN_E);
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_sco_conn_open
+**
+** Description
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_sco_conn_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+    UNUSED(p_data);
+
+    bta_ag_sco_event(p_scb, BTA_AG_SCO_CONN_OPEN_E);
+
+    bta_sys_sco_open(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+
+    bta_ag_co_audio_state(bta_ag_scb_to_idx(p_scb), p_scb->app_id, BTA_AG_CO_AUD_STATE_ON);
+
+#if (BTM_SCO_HCI_INCLUDED == TRUE )
+    /* open SCO codec if SCO is routed through transport */
+    bta_dm_sco_co_open(bta_ag_scb_to_idx(p_scb), BTA_SCO_OUT_PKT_SIZE, BTA_AG_CI_SCO_DATA_EVT);
+#endif
+
+    /* call app callback */
+    bta_ag_cback_sco(p_scb, BTA_AG_AUDIO_OPEN_EVT);
+
+    p_scb->retry_with_sco_only = FALSE;
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_sco_conn_close
+**
+** Description
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_sco_conn_close(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+    UINT16 handle = bta_ag_scb_to_idx(p_scb);
+    UNUSED(p_data);
+
+    /* clear current scb */
+    bta_ag_cb.sco.p_curr_scb = NULL;
+    p_scb->sco_idx = BTM_INVALID_SCO_INDEX;
+
+#if (BTM_WBS_INCLUDED == TRUE)
+    /* codec_fallback is set when AG is initiator and connection failed for mSBC. */
+    if (p_scb->codec_fallback && p_scb->svc_conn)
+    {
+        bta_ag_sco_event(p_scb, BTA_AG_SCO_REOPEN_E);
+    }
+    else if (p_scb->retry_with_sco_only && p_scb->svc_conn)
+    {
+        /* retry_with_sco_only is set when AG is initiator and connection failed for eSCO */
+        bta_ag_create_sco(p_scb, TRUE);
+    }
+#else
+    /* retry_with_sco_only, will be set only when AG is initiator
+    ** and AG is first trying to establish an eSCO connection */
+    if (p_scb->retry_with_sco_only && p_scb->svc_conn)
+    {
+        bta_ag_create_sco(p_scb, TRUE);
+    }
+#endif
+    else
+    {
+        /* Indicate if the closing of audio is because of transfer */
+        if (bta_ag_cb.sco.p_xfer_scb)
+            bta_ag_co_audio_state(handle, p_scb->app_id, BTA_AG_CO_AUD_STATE_OFF_XFER);
+        else
+            bta_ag_co_audio_state(handle, p_scb->app_id, BTA_AG_CO_AUD_STATE_OFF);
+
+        bta_ag_sco_event(p_scb, BTA_AG_SCO_CONN_CLOSE_E);
+
+        bta_sys_sco_close(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+
+        /* if av got suspended by this call, let it resume. */
+        /* In case call stays alive regardless of sco, av should not be affected. */
+        if(((p_scb->call_ind == BTA_AG_CALL_INACTIVE) && (p_scb->callsetup_ind == BTA_AG_CALLSETUP_NONE))
+            || (p_scb->post_sco == BTA_AG_POST_SCO_CALL_END))
+        {
+            bta_sys_sco_unuse(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+        }
+
+        /* call app callback */
+        bta_ag_cback_sco(p_scb, BTA_AG_AUDIO_CLOSE_EVT);
+    }
+    p_scb->retry_with_sco_only = FALSE;
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_sco_conn_rsp
+**
+** Description      Process the SCO connection request
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_sco_conn_rsp(tBTA_AG_SCB *p_scb, tBTM_ESCO_CONN_REQ_EVT_DATA *p_data)
+{
+    tBTM_ESCO_PARAMS    resp;
+    UINT8               hci_status = HCI_SUCCESS;
+#if (BTM_SCO_HCI_INCLUDED == TRUE )
+    tBTA_CODEC_INFO     codec_info = {BTA_SCO_CODEC_PCM};
+    UINT32              pcm_sample_rate;
+#endif
+
+    if (bta_ag_cb.sco.state == BTA_AG_SCO_LISTEN_ST     ||
+        bta_ag_cb.sco.state == BTA_AG_SCO_CLOSE_XFER_ST ||
+        bta_ag_cb.sco.state == BTA_AG_SCO_OPEN_XFER_ST)
+    {
+        /* If script overrided sco parameter by BTA_CMD_SET_ESCO_PARAM */
+        if (bta_ag_cb.sco.param_updated)
+        {
+            resp = bta_ag_cb.sco.params;
+        }
+        else
+        {
+            resp.rx_bw = BTM_64KBITS_RATE;
+            resp.tx_bw = BTM_64KBITS_RATE;
+            resp.max_latency = 10;
+            resp.voice_contfmt = 0x60;
+            resp.retrans_effort = BTM_ESCO_RETRANS_POWER;
+
+            if (p_data->link_type == BTM_LINK_TYPE_SCO)
+            {
+                resp.packet_types = (BTM_SCO_LINK_ONLY_MASK          |
+                                     BTM_SCO_PKT_TYPES_MASK_NO_2_EV3 |
+                                     BTM_SCO_PKT_TYPES_MASK_NO_3_EV3 |
+                                     BTM_SCO_PKT_TYPES_MASK_NO_2_EV5 |
+                                     BTM_SCO_PKT_TYPES_MASK_NO_3_EV5);
+            }
+            else    /* Allow controller to use all types available except 5-slot EDR */
+            {
+                resp.packet_types = (BTM_SCO_LINK_ALL_PKT_MASK |
+                                     BTM_SCO_PKT_TYPES_MASK_NO_2_EV5 |
+                                     BTM_SCO_PKT_TYPES_MASK_NO_3_EV5);
+            }
+        }
+
+        /* tell sys to stop av if any */
+        bta_sys_sco_use(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+
+        /* Allow any platform specific pre-SCO set up to take place */
+        bta_ag_co_audio_state(bta_ag_scb_to_idx(p_scb), p_scb->app_id, BTA_AG_CO_AUD_STATE_SETUP);
+
+#if (BTM_WBS_INCLUDED == TRUE )
+        /* When HS initiated SCO, it cannot be WBS. */
+        BTM_ConfigI2SPCM (BTM_SCO_CODEC_CVSD, (UINT8)HCI_BRCM_I2SPCM_IS_DEFAULT_ROLE, (UINT8)HCI_BRCM_I2SPCM_SAMPLE_DEFAULT, (UINT8)HCI_BRCM_I2SPCM_CLOCK_DEFAULT);
+#endif
+
+#if (BTM_SCO_HCI_INCLUDED == TRUE )
+        pcm_sample_rate = BTA_DM_SCO_SAMP_RATE_8K;
+
+        /* initialize SCO setup, no voice setting for AG, data rate <==> sample rate */
+        BTM_ConfigScoPath(bta_dm_sco_co_init(pcm_sample_rate, pcm_sample_rate, &codec_info, p_scb->app_id),
+            bta_ag_sco_read_cback, NULL, TRUE);
+#endif
+    }
+    else
+        hci_status = HCI_ERR_HOST_REJECT_DEVICE;
+
+#if (BTM_WBS_INCLUDED == TRUE )
+    /* If SCO open was initiated from HS, it must be CVSD */
+    p_scb->inuse_codec = BTA_AG_CODEC_NONE;
+#endif
+
+    BTM_EScoConnRsp(p_data->sco_inx, hci_status, &resp);
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_ci_sco_data
+**
+** Description      Process the SCO data ready callin event
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_ci_sco_data(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+    UNUSED(p_scb);
+    UNUSED(p_data);
+
+#if (BTM_SCO_HCI_INCLUDED == TRUE )
+    bta_ag_sco_event(p_scb, BTA_AG_SCO_CI_DATA_E);
+#endif
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_set_esco_param
+**
+** Description      Update esco parameters from script wrapper.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_set_esco_param(BOOLEAN set_reset, tBTM_ESCO_PARAMS *param)
+{
+    if(set_reset == FALSE)    /* reset the parameters to default */
+    {
+        bta_ag_cb.sco.param_updated = FALSE;
+        APPL_TRACE_DEBUG0("bta_ag_set_esco_param : Resetting ESCO parameters to default");
+    }
+    else
+    {
+        bta_ag_cb.sco.param_updated = TRUE;
+        bta_ag_cb.sco.params = *param;
+        APPL_TRACE_DEBUG0("bta_ag_set_esco_param : Setting ESCO parameters");
+    }
+}
+
+/*******************************************************************************
+**  Debugging functions
+*******************************************************************************/
+
+#if BTA_AG_SCO_DEBUG == TRUE
+static char *bta_ag_sco_evt_str(UINT8 event)
+{
+    switch (event)
+    {
+    case BTA_AG_SCO_LISTEN_E:
+        return "Listen Request";
+    case BTA_AG_SCO_OPEN_E:
+        return "Open Request";
+    case BTA_AG_SCO_XFER_E:
+        return "Transfer Request";
+#if (BTM_WBS_INCLUDED == TRUE )
+    case BTA_AG_SCO_CN_DONE_E:
+        return "Codec Negotiation Done";
+    case BTA_AG_SCO_REOPEN_E:
+        return "Reopen Request";
+#endif
+    case BTA_AG_SCO_CLOSE_E:
+        return "Close Request";
+    case BTA_AG_SCO_SHUTDOWN_E:
+        return "Shutdown Request";
+    case BTA_AG_SCO_CONN_OPEN_E:
+        return "Opened";
+    case BTA_AG_SCO_CONN_CLOSE_E:
+        return "Closed";
+    case BTA_AG_SCO_CI_DATA_E  :
+        return "Sco Data";
+    default:
+        return "Unknown SCO Event";
+    }
+}
+
+static char *bta_ag_sco_state_str(UINT8 state)
+{
+    switch (state)
+    {
+    case BTA_AG_SCO_SHUTDOWN_ST:
+        return "Shutdown";
+    case BTA_AG_SCO_LISTEN_ST:
+        return "Listening";
+#if (BTM_WBS_INCLUDED == TRUE )
+    case BTA_AG_SCO_CODEC_ST:
+        return "Codec Negotiation";
+#endif
+    case BTA_AG_SCO_OPENING_ST:
+        return "Opening";
+    case BTA_AG_SCO_OPEN_CL_ST:
+        return "Open while closing";
+    case BTA_AG_SCO_OPEN_XFER_ST:
+        return "Opening while Transferring";
+    case BTA_AG_SCO_OPEN_ST:
+        return "Open";
+    case BTA_AG_SCO_CLOSING_ST:
+        return "Closing";
+    case BTA_AG_SCO_CLOSE_OP_ST:
+        return "Close while Opening";
+    case BTA_AG_SCO_CLOSE_XFER_ST:
+        return "Close while Transferring";
+    case BTA_AG_SCO_SHUTTING_ST:
+        return "Shutting Down";
+    default:
+        return "Unknown SCO State";
+    }
+}
+
+#endif
diff --git a/bta/hf_client/bta_hf_client_sdp.c b/bta/hf_client/bta_hf_client_sdp.c
new file mode 100644
index 0000000..333cb1b
--- /dev/null
+++ b/bta/hf_client/bta_hf_client_sdp.c
@@ -0,0 +1,504 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2003-2012 Broadcom Corporation
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *  This file contains the audio gateway functions performing SDP
+ *  operations.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+#include "bta_api.h"
+#include "bta_sys.h"
+#include "bta_ag_api.h"
+#include "bta_ag_int.h"
+#include "sdp_api.h"
+#include "btm_api.h"
+#include "gki.h"
+#include "utl.h"
+
+/* Number of protocol elements in protocol element list. */
+#define BTA_AG_NUM_PROTO_ELEMS      2
+
+/* Number of elements in service class id list. */
+#define BTA_AG_NUM_SVC_ELEMS        2
+
+/* size of database for service discovery */
+#ifndef BTA_AG_DISC_BUF_SIZE
+#define BTA_AG_DISC_BUF_SIZE        GKI_MAX_BUF_SIZE
+#endif
+
+/* declare sdp callback functions */
+void bta_ag_sdp_cback_1(UINT16 status);
+void bta_ag_sdp_cback_2(UINT16 status);
+void bta_ag_sdp_cback_3(UINT16 status);
+
+/* SDP callback function table */
+typedef tSDP_DISC_CMPL_CB *tBTA_AG_SDP_CBACK;
+const tBTA_AG_SDP_CBACK bta_ag_sdp_cback_tbl[] =
+{
+    bta_ag_sdp_cback_1,
+    bta_ag_sdp_cback_2,
+    bta_ag_sdp_cback_3
+};
+
+/*******************************************************************************
+**
+** Function         bta_ag_sdp_cback
+**
+** Description      SDP callback function.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+static void bta_ag_sdp_cback(UINT16 status, UINT8 idx)
+{
+    tBTA_AG_DISC_RESULT *p_buf;
+    UINT16              event;
+    tBTA_AG_SCB         *p_scb;
+
+    APPL_TRACE_DEBUG1("bta_ag_sdp_cback status:0x%x", status);
+
+    if ((p_scb = bta_ag_scb_by_idx(idx)) != NULL)
+    {
+        /* set event according to int/acp */
+        if (p_scb->role == BTA_AG_ACP)
+        {
+            event = BTA_AG_DISC_ACP_RES_EVT;
+        }
+        else
+        {
+            event = BTA_AG_DISC_INT_RES_EVT;
+        }
+
+        if ((p_buf = (tBTA_AG_DISC_RESULT *) GKI_getbuf(sizeof(tBTA_AG_DISC_RESULT))) != NULL)
+        {
+            p_buf->hdr.event = event;
+            p_buf->hdr.layer_specific = idx;
+            p_buf->status = status;
+            bta_sys_sendmsg(p_buf);
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_sdp_cback_1 to 3
+**
+** Description      SDP callback functions.  Since there is no way to
+**                  distinguish scb from the callback we need separate
+**                  callbacks for each scb.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_sdp_cback_1(UINT16 status) {bta_ag_sdp_cback(status, 1);}
+void bta_ag_sdp_cback_2(UINT16 status) {bta_ag_sdp_cback(status, 2);}
+void bta_ag_sdp_cback_3(UINT16 status) {bta_ag_sdp_cback(status, 3);}
+
+/******************************************************************************
+**
+** Function         bta_ag_add_record
+**
+** Description      This function is called by a server application to add
+**                  HSP or HFP information to an SDP record.  Prior to
+**                  calling this function the application must call
+**                  SDP_CreateRecord() to create an SDP record.
+**
+** Returns          TRUE if function execution succeeded,
+**                  FALSE if function execution failed.
+**
+******************************************************************************/
+BOOLEAN bta_ag_add_record(UINT16 service_uuid, char *p_service_name, UINT8 scn,
+                          tBTA_AG_FEAT features, UINT32 sdp_handle)
+{
+    tSDP_PROTOCOL_ELEM  proto_elem_list[BTA_AG_NUM_PROTO_ELEMS];
+    UINT16              svc_class_id_list[BTA_AG_NUM_SVC_ELEMS];
+    UINT16              browse_list[] = {UUID_SERVCLASS_PUBLIC_BROWSE_GROUP};
+    UINT16              version;
+    UINT16              profile_uuid;
+    UINT8               network;
+    BOOLEAN             result = TRUE;
+    BOOLEAN             codec_supported = FALSE;
+    UINT8               buf[2];
+
+    APPL_TRACE_DEBUG1("bta_ag_add_record uuid: %x", service_uuid);
+
+    memset( proto_elem_list, 0 , BTA_AG_NUM_PROTO_ELEMS*sizeof(tSDP_PROTOCOL_ELEM));
+
+    /* add the protocol element sequence */
+    proto_elem_list[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
+    proto_elem_list[0].num_params = 0;
+    proto_elem_list[1].protocol_uuid = UUID_PROTOCOL_RFCOMM;
+    proto_elem_list[1].num_params = 1;
+    proto_elem_list[1].params[0] = scn;
+    result &= SDP_AddProtocolList(sdp_handle, BTA_AG_NUM_PROTO_ELEMS, proto_elem_list);
+
+    /* add service class id list */
+    svc_class_id_list[0] = service_uuid;
+    svc_class_id_list[1] = UUID_SERVCLASS_GENERIC_AUDIO;
+    result &= SDP_AddServiceClassIdList(sdp_handle, BTA_AG_NUM_SVC_ELEMS, svc_class_id_list);
+
+    /* add profile descriptor list */
+    if (service_uuid == UUID_SERVCLASS_AG_HANDSFREE)
+    {
+        profile_uuid = UUID_SERVCLASS_HF_HANDSFREE;
+        version = HFP_VERSION_1_6;
+    }
+    else
+    {
+        profile_uuid = UUID_SERVCLASS_HEADSET;
+        version = HSP_VERSION_1_2;
+    }
+    result &= SDP_AddProfileDescriptorList(sdp_handle, profile_uuid, version);
+
+    /* add service name */
+    if (p_service_name != NULL && p_service_name[0] != 0)
+    {
+        result &= SDP_AddAttribute(sdp_handle, ATTR_ID_SERVICE_NAME, TEXT_STR_DESC_TYPE,
+                    (UINT32)(strlen(p_service_name)+1), (UINT8 *) p_service_name);
+    }
+
+    /* add features and network */
+    if (service_uuid == UUID_SERVCLASS_AG_HANDSFREE)
+    {
+        network = (features & BTA_AG_FEAT_REJECT) ? 1 : 0;
+        result &= SDP_AddAttribute(sdp_handle, ATTR_ID_DATA_STORES_OR_NETWORK,
+                    UINT_DESC_TYPE, 1, &network);
+
+        if (features & BTA_AG_FEAT_CODEC)
+            codec_supported = TRUE;
+
+        features &= BTA_AG_SDP_FEAT_SPEC;
+
+        /* Codec bit position is different in SDP and in BRSF */
+        if (codec_supported)
+            features |= 0x0020;
+
+        UINT16_TO_BE_FIELD(buf, features);
+        result &= SDP_AddAttribute(sdp_handle, ATTR_ID_SUPPORTED_FEATURES, UINT_DESC_TYPE, 2, buf);
+    }
+
+    /* add browse group list */
+    result &= SDP_AddUuidSequence(sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, browse_list);
+
+    return result;
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_create_records
+**
+** Description      Create SDP records for registered services.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_create_records(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+    int                 i;
+    tBTA_SERVICE_MASK   services;
+
+    services = p_scb->reg_services >> BTA_HSP_SERVICE_ID;
+    for (i = 0; i < BTA_AG_NUM_IDX && services != 0; i++, services >>= 1)
+    {
+        /* if service is set in mask */
+        if (services & 1)
+        {
+            /* add sdp record if not already registered */
+            if (bta_ag_cb.profile[i].sdp_handle == 0)
+            {
+                bta_ag_cb.profile[i].sdp_handle = SDP_CreateRecord();
+                bta_ag_cb.profile[i].scn = BTM_AllocateSCN();
+                bta_ag_add_record(bta_ag_uuid[i], p_data->api_register.p_name[i],
+                    bta_ag_cb.profile[i].scn, p_data->api_register.features,
+                    bta_ag_cb.profile[i].sdp_handle);
+                bta_sys_add_uuid(bta_ag_uuid[i]);
+            }
+        }
+    }
+
+    p_scb->hsp_version = HSP_VERSION_1_2;
+
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_del_records
+**
+** Description      Delete SDP records for any registered services.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_del_records(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+    tBTA_AG_SCB         *p = &bta_ag_cb.scb[0];
+    tBTA_SERVICE_MASK   services;
+    tBTA_SERVICE_MASK   others = 0;
+    int                 i;
+    UNUSED(p_data);
+
+    /* get services of all other registered servers */
+    for (i = 0; i < BTA_AG_NUM_IDX; i++, p++)
+    {
+        if (p_scb == p)
+        {
+            continue;
+        }
+
+        if (p->in_use && p->dealloc == FALSE)
+        {
+            others |= p->reg_services;
+        }
+    }
+
+    others >>= BTA_HSP_SERVICE_ID;
+    services = p_scb->reg_services >> BTA_HSP_SERVICE_ID;
+    for (i = 0; i < BTA_AG_NUM_IDX && services != 0; i++, services >>= 1, others >>= 1)
+    {
+        /* if service registered for this scb and not registered for any other scb */
+        if (((services & 1) == 1) && ((others & 1) == 0))
+        {
+            APPL_TRACE_DEBUG1("bta_ag_del_records %d", i);
+            if (bta_ag_cb.profile[i].sdp_handle != 0)
+            {
+                SDP_DeleteRecord(bta_ag_cb.profile[i].sdp_handle);
+                bta_ag_cb.profile[i].sdp_handle = 0;
+            }
+            BTM_FreeSCN(bta_ag_cb.profile[i].scn);
+            BTM_SecClrService(bta_ag_sec_id[i]);
+            bta_sys_remove_uuid(bta_ag_uuid[i]);
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_sdp_find_attr
+**
+** Description      Process SDP discovery results to find requested attributes
+**                  for requested service.
+**
+**
+** Returns          TRUE if results found, FALSE otherwise.
+**
+*******************************************************************************/
+BOOLEAN bta_ag_sdp_find_attr(tBTA_AG_SCB *p_scb, tBTA_SERVICE_MASK service)
+{
+    tSDP_DISC_REC       *p_rec = NULL;
+    tSDP_DISC_ATTR      *p_attr;
+    tSDP_PROTOCOL_ELEM  pe;
+    UINT16              uuid;
+    BOOLEAN             result = FALSE;
+
+    if (service & BTA_HFP_SERVICE_MASK)
+    {
+        uuid = UUID_SERVCLASS_HF_HANDSFREE;
+        p_scb->peer_version = HFP_VERSION_1_1;   /* Default version */
+    }
+    else if (service & BTA_HSP_SERVICE_MASK && p_scb->role == BTA_AG_INT)
+    {
+        uuid = UUID_SERVCLASS_HEADSET_HS;
+        p_scb->peer_version = 0x0100;   /* Default version */
+    }
+    else
+    {
+        return result;
+    }
+
+    /* loop through all records we found */
+    while (TRUE)
+    {
+        /* get next record; if none found, we're done */
+        if ((p_rec = SDP_FindServiceInDb(p_scb->p_disc_db, uuid, p_rec)) == NULL)
+        {
+            if (uuid == UUID_SERVCLASS_HEADSET_HS)
+            {
+                /* Search again in case the peer device is HSP v1.0 */
+                uuid = UUID_SERVCLASS_HEADSET;
+                if ((p_rec = SDP_FindServiceInDb(p_scb->p_disc_db, uuid, p_rec)) == NULL)
+                {
+                    break;
+                }
+            }
+            else
+                break;
+        }
+
+        /* get scn from proto desc list if initiator */
+        if (p_scb->role == BTA_AG_INT)
+        {
+            if (SDP_FindProtocolListElemInRec(p_rec, UUID_PROTOCOL_RFCOMM, &pe))
+            {
+                p_scb->peer_scn = (UINT8) pe.params[0];
+            }
+            else
+            {
+                continue;
+            }
+        }
+
+        /* get profile version (if failure, version parameter is not updated) */
+        SDP_FindProfileVersionInRec(p_rec, uuid, &p_scb->peer_version);
+
+        /* get features if HFP */
+        if (service & BTA_HFP_SERVICE_MASK)
+        {
+            if ((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_SUPPORTED_FEATURES)) != NULL)
+            {
+                /* Found attribute. Get value. */
+                /* There might be race condition between SDP and BRSF.  */
+                /* Do not update if we already received BRSF.           */
+                if (p_scb->peer_features == 0)
+                    p_scb->peer_features = p_attr->attr_value.v.u16;
+            }
+        }
+        else    /* HSP */
+        {
+            if ((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_REMOTE_AUDIO_VOLUME_CONTROL)) != NULL)
+            {
+                /* Remote volume control of HSP */
+                if (p_attr->attr_value.v.u8)
+                    p_scb->peer_features |= BTA_AG_PEER_FEAT_VOL;
+                else
+                    p_scb->peer_features &= ~BTA_AG_PEER_FEAT_VOL;
+            }
+
+        }
+
+        /* found what we needed */
+        result = TRUE;
+        break;
+    }
+    return result;
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_do_disc
+**
+** Description      Do service discovery.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_do_disc(tBTA_AG_SCB *p_scb, tBTA_SERVICE_MASK service)
+{
+    tSDP_UUID       uuid_list[2];
+    UINT16          num_uuid = 1;
+    UINT16          attr_list[4];
+    UINT8           num_attr;
+    BOOLEAN         db_inited = FALSE;
+
+    /* HFP initiator; get proto list and features */
+    if (service & BTA_HFP_SERVICE_MASK && p_scb->role == BTA_AG_INT)
+    {
+        attr_list[0] = ATTR_ID_SERVICE_CLASS_ID_LIST;
+        attr_list[1] = ATTR_ID_PROTOCOL_DESC_LIST;
+        attr_list[2] = ATTR_ID_BT_PROFILE_DESC_LIST;
+        attr_list[3] = ATTR_ID_SUPPORTED_FEATURES;
+        num_attr = 4;
+        uuid_list[0].uu.uuid16 = UUID_SERVCLASS_HF_HANDSFREE;
+    }
+    /* HFP acceptor; get features */
+    else if (service & BTA_HFP_SERVICE_MASK && p_scb->role == BTA_AG_ACP)
+    {
+        attr_list[0] = ATTR_ID_SERVICE_CLASS_ID_LIST;
+        attr_list[1] = ATTR_ID_BT_PROFILE_DESC_LIST;
+        attr_list[2] = ATTR_ID_SUPPORTED_FEATURES;
+        num_attr = 3;
+        uuid_list[0].uu.uuid16 = UUID_SERVCLASS_HF_HANDSFREE;
+    }
+    /* HSP initiator; get proto list */
+    else if (service & BTA_HSP_SERVICE_MASK && p_scb->role == BTA_AG_INT)
+    {
+        attr_list[0] = ATTR_ID_SERVICE_CLASS_ID_LIST;
+        attr_list[1] = ATTR_ID_PROTOCOL_DESC_LIST;
+        attr_list[2] = ATTR_ID_BT_PROFILE_DESC_LIST;
+        attr_list[3] = ATTR_ID_REMOTE_AUDIO_VOLUME_CONTROL;
+        num_attr = 4;
+
+        uuid_list[0].uu.uuid16 = UUID_SERVCLASS_HEADSET;        /* Legacy from HSP v1.0 */
+        if (p_scb->hsp_version >= HSP_VERSION_1_2)
+        {
+            uuid_list[1].uu.uuid16 = UUID_SERVCLASS_HEADSET_HS;
+            num_uuid = 2;
+        }
+    }
+    /* HSP acceptor; no discovery */
+    else
+    {
+        return;
+    }
+
+    /* allocate buffer for sdp database */
+    p_scb->p_disc_db = (tSDP_DISCOVERY_DB *) GKI_getbuf(BTA_AG_DISC_BUF_SIZE);
+
+    if(p_scb->p_disc_db)
+    {
+        /* set up service discovery database; attr happens to be attr_list len */
+        uuid_list[0].len = LEN_UUID_16;
+        uuid_list[1].len = LEN_UUID_16;
+        db_inited = SDP_InitDiscoveryDb(p_scb->p_disc_db, BTA_AG_DISC_BUF_SIZE, num_uuid,
+                            uuid_list, num_attr, attr_list);
+    }
+
+    if(db_inited)
+    {
+        /*Service discovery not initiated */
+        db_inited = SDP_ServiceSearchAttributeRequest(p_scb->peer_addr, p_scb->p_disc_db,
+                                      bta_ag_sdp_cback_tbl[bta_ag_scb_to_idx(p_scb) - 1]);
+    }
+
+    if(!db_inited)
+    {
+        /*free discover db */
+        bta_ag_free_db(p_scb, NULL);
+        /* sent failed event */
+        bta_ag_sm_execute(p_scb, BTA_AG_DISC_FAIL_EVT, NULL);
+    }
+
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_free_db
+**
+** Description      Free discovery database.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_free_db(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+    UNUSED(p_data);
+
+    if (p_scb->p_disc_db != NULL)
+    {
+        GKI_freebuf(p_scb->p_disc_db);
+        p_scb->p_disc_db = NULL;
+    }
+}
diff --git a/bta/include/bta_hf_client_api.h b/bta/include/bta_hf_client_api.h
new file mode 100644
index 0000000..f16687c
--- /dev/null
+++ b/bta/include/bta_hf_client_api.h
@@ -0,0 +1,514 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2003-2012 Broadcom Corporation
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *  This is the public interface file for the audio gateway (AG) subsystem
+ *  of BTA, Broadcom's Bluetooth application layer for mobile phones.
+ *
+ ******************************************************************************/
+#ifndef BTA_AG_API_H
+#define BTA_AG_API_H
+
+#include "bta_api.h"
+
+/*****************************************************************************
+**  Constants and data types
+*****************************************************************************/
+
+/* AG feature masks */
+#define BTA_AG_FEAT_3WAY    0x00000001   /* Three-way calling */
+#define BTA_AG_FEAT_ECNR    0x00000002   /* Echo cancellation and/or noise reduction */
+#define BTA_AG_FEAT_VREC    0x00000004   /* Voice recognition */
+#define BTA_AG_FEAT_INBAND  0x00000008   /* In-band ring tone */
+#define BTA_AG_FEAT_VTAG    0x00000010   /* Attach a phone number to a voice tag */
+#define BTA_AG_FEAT_REJECT  0x00000020   /* Ability to reject incoming call */
+#define BTA_AG_FEAT_ECS     0x00000040   /* Enhanced Call Status */
+#define BTA_AG_FEAT_ECC     0x00000080   /* Enhanced Call Control */
+#define BTA_AG_FEAT_EXTERR  0x00000100   /* Extended error codes */
+#define BTA_AG_FEAT_CODEC   0x00000200   /* Codec Negotiation */
+#define BTA_AG_FEAT_VOIP    0x00000400   /* VoIP call */
+/* Proprietary features: using 31 ~ 16 bits */
+#define BTA_AG_FEAT_BTRH    0x00010000   /* CCAP incoming call hold */
+#define BTA_AG_FEAT_UNAT    0x00020000   /* Pass unknown AT commands to application */
+#define BTA_AG_FEAT_NOSCO   0x00040000   /* No SCO control performed by BTA AG */
+#define BTA_AG_FEAT_NO_ESCO 0x00080000   /* Do not allow or use eSCO */
+
+typedef UINT32 tBTA_AG_FEAT;
+
+/* AG parse mode */
+#define BTA_AG_PARSE            0 /* Perform AT command parsing in AG */
+#define BTA_AG_PASS_THROUGH     1 /* Pass data directly to phoneÂ’s AT command interpreter */
+
+typedef UINT8 tBTA_AG_PARSE_MODE;
+
+/* AG open status */
+#define BTA_AG_SUCCESS          0 /* Connection successfully opened */
+#define BTA_AG_FAIL_SDP         1 /* Open failed due to SDP */
+#define BTA_AG_FAIL_RFCOMM      2 /* Open failed due to RFCOMM */
+#define BTA_AG_FAIL_RESOURCES   3 /* out of resources failure  */
+
+typedef UINT8 tBTA_AG_STATUS;
+
+/* handle values used with BTA_AgResult */
+#define BTA_AG_HANDLE_NONE      0
+#define BTA_AG_HANDLE_ALL       0xFFFF
+/* It is safe to use the same value as BTA_AG_HANDLE_ALL
+ * HANDLE_ALL is used for delivering indication
+ * SCO_NO_CHANGE is used for changing sco behavior
+ * They donot interfere with each other
+ */
+#define BTA_AG_HANDLE_SCO_NO_CHANGE 0xFFFF
+
+/* AG result codes used with BTA_AgResult */
+#define BTA_AG_SPK_RES              0   /* Update speaker volume */
+#define BTA_AG_MIC_RES              1   /* Update microphone volume */
+#define BTA_AG_INBAND_RING_RES      2   /* Update inband ring state */
+#define BTA_AG_CIND_RES             3   /* Send indicator response for AT+CIND */
+#define BTA_AG_BINP_RES             4   /* Send phone number for voice tag for AT+BINP */
+#define BTA_AG_IND_RES              5   /* Update an indicator value */
+#define BTA_AG_BVRA_RES             6   /* Update voice recognition state */
+#define BTA_AG_CNUM_RES             7   /* Send subscriber number response for AT+CNUM */
+#define BTA_AG_BTRH_RES             8   /* Send CCAP incoming call hold */
+#define BTA_AG_CLCC_RES             9   /* Query list of calls */
+#define BTA_AG_COPS_RES             10  /* Read network operator */
+#define BTA_AG_IN_CALL_RES          11  /* Indicate incoming phone call */
+#define BTA_AG_IN_CALL_CONN_RES     12  /* Incoming phone call connected */
+#define BTA_AG_CALL_WAIT_RES        13  /* Call waiting notification */
+#define BTA_AG_OUT_CALL_ORIG_RES    14  /* Outgoing phone call origination */
+#define BTA_AG_OUT_CALL_ALERT_RES   15  /* Outgoing phone call alerting remote party */
+#define BTA_AG_OUT_CALL_CONN_RES    16  /* Outgoing phone call connected */
+#define BTA_AG_CALL_CANCEL_RES      17  /* Incoming/outgoing 3-way canceled before connected */
+#define BTA_AG_END_CALL_RES         18  /* End call */
+#define BTA_AG_IN_CALL_HELD_RES     19  /* Incoming call held */
+#define BTA_AG_UNAT_RES             20  /* Response to unknown AT command event */
+
+typedef UINT8 tBTA_AG_RES;
+
+/* HFP peer features */
+#define BTA_AG_PEER_FEAT_ECNR       0x0001  /* Echo cancellation and/or noise reduction */
+#define BTA_AG_PEER_FEAT_3WAY       0x0002  /* Call waiting and three-way calling */
+#define BTA_AG_PEER_FEAT_CLI        0x0004  /* Caller ID presentation capability */
+#define BTA_AG_PEER_FEAT_VREC       0x0008  /* Voice recognition activation */
+#define BTA_AG_PEER_FEAT_VOL        0x0010  /* Remote volume control */
+#define BTA_AG_PEER_FEAT_ECS        0x0020  /* Enhanced Call Status */
+#define BTA_AG_PEER_FEAT_ECC        0x0040  /* Enhanced Call Control */
+#define BTA_AG_PEER_FEAT_CODEC      0x0080  /* Codec Negotiation */
+#define BTA_AG_PEER_FEAT_VOIP       0x0100  /* VoIP call */
+
+typedef UINT16 tBTA_AG_PEER_FEAT;
+
+/* HFP peer supported codec masks */
+#define BTA_AG_CODEC_NONE           BTM_SCO_CODEC_NONE
+#define BTA_AG_CODEC_CVSD           BTM_SCO_CODEC_CVSD      /* CVSD */
+#define BTA_AG_CODEC_MSBC           BTM_SCO_CODEC_MSBC      /* mSBC */
+typedef UINT16 tBTA_AG_PEER_CODEC;
+
+/* HFP errcode - Set when BTA_AG_OK_ERROR is returned in 'ok_flag' */
+#define BTA_AG_ERR_PHONE_FAILURE    0       /* Phone Failure */
+#define BTA_AG_ERR_NO_CONN_PHONE    1       /* No connection to phone */
+#define BTA_AG_ERR_OP_NOT_ALLOWED   3       /* Operation not allowed */
+#define BTA_AG_ERR_OP_NOT_SUPPORTED 4       /* Operation not supported */
+#define BTA_AG_ERR_PHSIM_PIN_REQ    5       /* PH-SIM PIN required */
+#define BTA_AG_ERR_SIM_NOT_INSERTED 10      /* SIM not inserted */
+#define BTA_AG_ERR_SIM_PIN_REQ      11      /* SIM PIN required */
+#define BTA_AG_ERR_SIM_PUK_REQ      12      /* SIM PUK required */
+#define BTA_AG_ERR_SIM_FAILURE      13      /* SIM failure */
+#define BTA_AG_ERR_SIM_BUSY         14      /* SIM busy */
+#define BTA_AG_ERR_INCORRECT_PWD    16      /* Incorrect password */
+#define BTA_AG_ERR_SIM_PIN2_REQ     17      /* SIM PIN2 required */
+#define BTA_AG_ERR_SIM_PUK2_REQ     18      /* SIM PUK2 required */
+#define BTA_AG_ERR_MEMORY_FULL      20      /* Memory full */
+#define BTA_AG_ERR_INVALID_INDEX    21      /* Invalid index */
+#define BTA_AG_ERR_MEMORY_FAILURE   23      /* Memory failure */
+#define BTA_AG_ERR_TEXT_TOO_LONG    24      /* Text string too long */
+#define BTA_AG_ERR_INV_CHAR_IN_TSTR 25      /* Invalid characters in text string */
+#define BTA_AG_ERR_DSTR_TOO_LONG    26      /* Dial string too long */
+#define BTA_AG_ERR_INV_CHAR_IN_DSTR 27      /* Invalid characters in dial string */
+#define BTA_AG_ERR_NO_NETWORK_SERV  30      /* No network service */
+#define BTA_AG_ERR_NETWORK_TIME_OUT 31      /* Network timeout */
+#define BTA_AG_ERR_NO_NET_EMG_ONLY  32      /* Network not allowed - emergency service only */
+#define BTA_AG_ERR_VOIP_CS_CALLS    33      /* AG cannot create simultaneous VoIP and CS calls */
+#define BTA_AG_ERR_NOT_FOR_VOIP     34      /* Not supported on this call type(VoIP) */
+#define BTA_AG_ERR_SIP_RESP_CODE    35      /* SIP 3 digit response code */
+
+#if 0   /* Not Used in Bluetooth HFP 1.5 Specification */
+#define BTA_AG_ERR_PHADAP_LNK_RES   2       /* Phone-adapter link reserved */
+#define BTA_AG_ERR_PHFSIM_PIN_REQ   6       /* PH-FSIM PIN required */
+#define BTA_AG_ERR_PHFSIM_PUK_REQ   7       /* PH-FSIM PUK required */
+#define BTA_AG_ERR_SIM_WRONG        15      /* SIM wrong */
+#define BTA_AG_ERR_NOT_FOUND        22      /* Not found */
+#define BTA_AG_ERR_NETWORK_TIMEOUT  31      /* Network timeout */
+#define BTA_AG_ERR_NET_PIN_REQ      40      /* Network personalization PIN required */
+#define BTA_AG_ERR_NET_PUK_REQ      41      /* Network personalization PUK required */
+#define BTA_AG_ERR_SUBSET_PIN_REQ   42      /* Network subset personalization PIN required */
+#define BTA_AG_ERR_SUBSET_PUK_REQ   43      /* Network subset personalization PUK required */
+#define BTA_AG_ERR_SERVPRO_PIN_REQ  44      /* Service provider personalization PIN required */
+#define BTA_AG_ERR_SERVPRO_PUK_REQ  45      /* Service provider personalization PUK required */
+#define BTA_AG_ERR_CORP_PIN_REQ     46      /* Corporate personalization PIN required */
+#define BTA_AG_ERR_CORP_PUK_REQ     47      /* Corporate personalization PUK required */
+#define BTA_AG_ERR_UNKNOWN          100    /* Unknown error */
+/* GPRS-related errors */
+#define BTA_AG_ERR_ILL_MS           103    /* Illegal MS (#3) */
+#define BTA_AG_ERR_ILL_ME           106    /* Illegal ME (#6) */
+#define BTA_AG_ERR_GPRS_NOT_ALLOWED 107    /* GPRS services not allowed (#7) */
+#define BTA_AG_ERR_PLMN_NOT_ALLOWED 111    /* PLMN services not allowed (#11) */
+#define BTA_AG_ERR_LOC_NOT_ALLOWED  112    /* Location area not allowed (#12) */
+#define BTA_AG_ERR_ROAM_NOT_ALLOWED 113    /* Roaming not allowed in this location area (#13) */
+/* Errors related to a failure to Activate a Context */
+#define BTA_AG_ERR_OPT_NOT_SUPP     132    /* Service option not supported (#32) */
+#define BTA_AG_ERR_OPT_NOT_SUBSCR   133    /* Requested service option not subscribed (#33) */
+#define BTA_AG_ERR_OPT_OUT_OF_ORDER 134    /* Service option temporarily out of order (#34) */
+#define BTA_AG_ERR_PDP_AUTH_FAILURE 149    /* PDP authentication failure */
+/* Other GPRS errors */
+#define BTA_AG_ERR_INV_MOBILE_CLASS 150    /* Invalid mobile class */
+#define BTA_AG_ERR_UNSPEC_GPRS_ERR  148    /* Unspecified GPRS error */
+#endif  /* Unused error codes */
+
+
+/* HFP result data 'ok_flag' */
+#define BTA_AG_OK_CONTINUE          0       /* Send out response (more responses coming) */
+#define BTA_AG_OK_DONE              1       /* Send out response followed by OK (finished) */
+#define BTA_AG_OK_ERROR             2       /* Error response */
+
+/* BTRH values */
+#define BTA_AG_BTRH_SET_HOLD        0       /* Put incoming call on hold */
+#define BTA_AG_BTRH_SET_ACC         1       /* Accept incoming call on hold */
+#define BTA_AG_BTRH_SET_REJ         2       /* Reject incoming call on hold */
+#define BTA_AG_BTRH_READ            3       /* Read the current value */
+#define BTA_AG_BTRH_NO_RESP         4       /* Not in RH States (reply to read) */
+
+/* ASCII character string of arguments to the AT command or result */
+#ifndef BTA_AG_AT_MAX_LEN
+#define BTA_AG_AT_MAX_LEN           256
+#endif
+
+/* data associated with BTA_AG_IND_RES */
+typedef struct
+{
+    UINT16          id;
+    UINT16          value;
+} tBTA_AG_IND;
+
+/* data type for BTA_AgResult() */
+typedef struct
+{
+    char            str[BTA_AG_AT_MAX_LEN+1];
+    tBTA_AG_IND     ind;
+    UINT16          num;
+    UINT16          audio_handle;
+    UINT16          errcode;        /* Valid only if 'ok_flag' is set to BTA_AG_OK_ERROR */
+    UINT8           ok_flag;        /* Indicates if response is finished, and if error occurred */
+    BOOLEAN         state;
+} tBTA_AG_RES_DATA;
+
+/* AG callback events */
+#define BTA_AG_ENABLE_EVT       0  /* AG enabled */
+#define BTA_AG_REGISTER_EVT     1  /* AG registered */
+#define BTA_AG_OPEN_EVT         2  /* AG connection open */
+#define BTA_AG_CLOSE_EVT        3  /* AG connection closed */
+#define BTA_AG_CONN_EVT         4  /* Service level connection opened */
+#define BTA_AG_AUDIO_OPEN_EVT   5  /* Audio connection open */
+#define BTA_AG_AUDIO_CLOSE_EVT  6  /* Audio connection closed */
+#define BTA_AG_SPK_EVT          7  /* Speaker volume changed */
+#define BTA_AG_MIC_EVT          8  /* Microphone volume changed */
+#define BTA_AG_AT_CKPD_EVT      9  /* CKPD from the HS */
+#define BTA_AG_DISABLE_EVT      30 /* AG disabled       */
+
+/* Values below are for HFP only */
+#define BTA_AG_AT_A_EVT         10 /* Answer a call */
+#define BTA_AG_AT_D_EVT         11 /* Place a call using number or memory dial */
+#define BTA_AG_AT_CHLD_EVT      12 /* Call hold */
+#define BTA_AG_AT_CHUP_EVT      13 /* Hang up a call */
+#define BTA_AG_AT_CIND_EVT      14 /* Read indicator settings */
+#define BTA_AG_AT_VTS_EVT       15 /* Transmit DTMF tone */
+#define BTA_AG_AT_BINP_EVT      16 /* Retrieve number from voice tag */
+#define BTA_AG_AT_BLDN_EVT      17 /* Place call to last dialed number */
+#define BTA_AG_AT_BVRA_EVT      18 /* Enable/disable voice recognition */
+#define BTA_AG_AT_NREC_EVT      19 /* Disable echo canceling */
+#define BTA_AG_AT_CNUM_EVT      20 /* Retrieve subscriber number */
+#define BTA_AG_AT_BTRH_EVT      21 /* CCAP-style incoming call hold */
+#define BTA_AG_AT_CLCC_EVT      22 /* Query list of current calls */
+#define BTA_AG_AT_COPS_EVT      23 /* Query list of current calls */
+#define BTA_AG_AT_UNAT_EVT      24 /* Unknown AT command */
+#define BTA_AG_AT_CBC_EVT       25 /* Battery Level report from HF */
+#define BTA_AG_AT_BAC_EVT       26 /* Codec select */
+#define BTA_AG_AT_BCS_EVT       27 /* Codec select */
+
+typedef UINT8 tBTA_AG_EVT;
+
+/* data associated with most non-AT events */
+typedef struct
+{
+    UINT16              handle;
+    UINT8               app_id;
+} tBTA_AG_HDR;
+
+/* data associated with BTA_AG_REGISTER_EVT */
+typedef struct
+{
+    tBTA_AG_HDR         hdr;
+    tBTA_AG_STATUS      status;
+} tBTA_AG_REGISTER;
+
+/* data associated with BTA_AG_OPEN_EVT */
+typedef struct
+{
+    tBTA_AG_HDR         hdr;
+    BD_ADDR             bd_addr;
+    tBTA_SERVICE_ID     service_id;
+    tBTA_AG_STATUS      status;
+} tBTA_AG_OPEN;
+
+/* data associated with BTA_AG_CONN_EVT */
+typedef struct
+{
+    tBTA_AG_HDR         hdr;
+    tBTA_AG_PEER_FEAT   peer_feat;
+    tBTA_AG_PEER_CODEC  peer_codec;
+} tBTA_AG_CONN;
+
+/* data associated with AT command event */
+typedef struct
+{
+    tBTA_AG_HDR         hdr;
+    char                str[BTA_AG_AT_MAX_LEN+1];
+    UINT16              num;
+    UINT8               idx;    /* call number used by CLCC and CHLD */
+} tBTA_AG_VAL;
+
+/* union of data associated with AG callback */
+typedef union
+{
+    tBTA_AG_HDR         hdr;
+    tBTA_AG_REGISTER    reg;
+    tBTA_AG_OPEN        open;
+    tBTA_AG_CONN        conn;
+    tBTA_AG_VAL         val;
+} tBTA_AG;
+
+/* AG callback */
+typedef void (tBTA_AG_CBACK)(tBTA_AG_EVT event, tBTA_AG *p_data);
+
+/* indicator constants HFP 1.1 and later */
+#define BTA_AG_IND_CALL             1   /* position of call indicator */
+#define BTA_AG_IND_CALLSETUP        2   /* position of callsetup indicator */
+#define BTA_AG_IND_SERVICE          3   /* position of service indicator */
+
+/* indicator constants HFP 1.5 and later */
+#define BTA_AG_IND_SIGNAL           4   /* position of signal strength indicator */
+#define BTA_AG_IND_ROAM             5   /* position of roaming indicator */
+#define BTA_AG_IND_BATTCHG          6   /* position of battery charge indicator */
+#define BTA_AG_IND_CALLHELD         7   /* position of callheld indicator */
+#define BTA_AG_IND_BEARER           8   /* position of bearer indicator */
+
+/* call indicator values */
+#define BTA_AG_CALL_INACTIVE        0   /* Phone call inactive */
+#define BTA_AG_CALL_ACTIVE          1   /* Phone call active */
+
+/* callsetup indicator values */
+#define BTA_AG_CALLSETUP_NONE       0   /* Not currently in call set up */
+#define BTA_AG_CALLSETUP_INCOMING   1   /* Incoming call process ongoing */
+#define BTA_AG_CALLSETUP_OUTGOING   2   /* Outgoing call set up is ongoing */
+#define BTA_AG_CALLSETUP_ALERTING   3   /* Remote party being alerted in an outgoing call */
+
+/* service indicator values */
+#define BTA_AG_SERVICE_NONE         0   /* Neither CS nor VoIP service is available     */
+#define BTA_AG_SERVICE_CS           1   /* Only CS service is available                 */
+#define BTA_AG_SERVICE_VOIP         2   /* Only VoIP service is available               */
+#define BTA_AG_SERVICE_CS_VOIP      3   /* Both CS and VoIP services available          */
+
+/* callheld indicator values */
+#define BTA_AG_CALLHELD_INACTIVE    0   /* No held calls */
+#define BTA_AG_CALLHELD_ACTIVE      1   /* Call held and call active */
+#define BTA_AG_CALLHELD_NOACTIVE    2   /* Call held and no call active */
+
+/* signal strength indicator values */
+#define BTA_AG_ROAMING_INACTIVE     0   /* Phone call inactive */
+#define BTA_AG_ROAMING_ACTIVE       1   /* Phone call active */
+
+/* bearer indicator values */
+#define BTA_AG_BEARER_WLAN          0   /* WLAN         */
+#define BTA_AG_BEARER_BLUETOOTH     1   /* Bluetooth    */
+#define BTA_AG_BEARER_WIRED         2   /* Wired        */
+#define BTA_AG_BEARER_2G3G          3   /* 2G 3G        */
+#define BTA_AG_BEARER_WIMAX         4   /* WIMAX        */
+#define BTA_AG_BEARER_RES1          5   /* Reserved     */
+#define BTA_AG_BEARER_RES2          6   /* Reserved     */
+#define BTA_AG_BEARER_RES3          7   /* Reserved     */
+
+/* AG configuration structure */
+typedef struct
+{
+    char         *cind_info;
+    INT32        conn_tout;
+    UINT16       sco_pkt_types;
+    char         *chld_val_ecc;
+    char         *chld_val;
+} tBTA_AG_CFG;
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*****************************************************************************
+**  External Function Declarations
+*****************************************************************************/
+
+/*******************************************************************************
+**
+** Function         BTA_AgEnable
+**
+** Description      Enable the audio gateway service. When the enable
+**                  operation is complete the callback function will be
+**                  called with a BTA_AG_ENABLE_EVT. This function must
+**                  be called before other function in the AG API are
+**                  called.
+**
+** Returns          BTA_SUCCESS if OK, BTA_FAILURE otherwise.
+**
+*******************************************************************************/
+BTA_API tBTA_STATUS BTA_AgEnable(tBTA_AG_PARSE_MODE parse_mode, tBTA_AG_CBACK *p_cback);
+
+/*******************************************************************************
+**
+** Function         BTA_AgDisable
+**
+** Description      Disable the audio gateway service
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+BTA_API void BTA_AgDisable(void);
+
+/*******************************************************************************
+**
+** Function         BTA_AgRegister
+**
+** Description      Register an Audio Gateway service.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+BTA_API void BTA_AgRegister(tBTA_SERVICE_MASK services, tBTA_SEC sec_mask,
+                tBTA_AG_FEAT features, char *p_service_names[], UINT8 app_id);
+
+/*******************************************************************************
+**
+** Function         BTA_AgDeregister
+**
+** Description      Deregister an audio gateway service.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+BTA_API void BTA_AgDeregister(UINT16 handle);
+
+/*******************************************************************************
+**
+** Function         BTA_AgOpen
+**
+** Description      Opens a connection to a headset or hands-free device.
+**                  When connection is open callback function is called
+**                  with a BTA_AG_OPEN_EVT. Only the data connection is
+**                  opened. The audio connection is not opened.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+BTA_API void BTA_AgOpen(UINT16 handle, BD_ADDR bd_addr, tBTA_SEC sec_mask, tBTA_SERVICE_MASK services);
+
+/*******************************************************************************
+**
+** Function         BTA_AgClose
+**
+** Description      Close the current connection to a headset or a handsfree
+**                  Any current audio connection will also be closed
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+BTA_API void BTA_AgClose(UINT16 handle);
+
+/*******************************************************************************
+**
+** Function         BTA_AgAudioOpen
+**
+** Description      Opens an audio connection to the currently connected
+**                  headset or hnadsfree
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+BTA_API void BTA_AgAudioOpen(UINT16 handle);
+
+/*******************************************************************************
+**
+** Function         BTA_AgAudioClose
+**
+** Description      Close the currently active audio connection to a headset
+**                  or hnadsfree. The data connection remains open
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+BTA_API void BTA_AgAudioClose(UINT16 handle);
+
+/*******************************************************************************
+**
+** Function         BTA_AgResult
+**
+** Description      Send an AT result code to a headset or hands-free device.
+**                  This function is only used when the AG parse mode is set
+**                  to BTA_AG_PARSE.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+BTA_API void BTA_AgResult(UINT16 handle, tBTA_AG_RES result, tBTA_AG_RES_DATA *p_data);
+
+/*******************************************************************************
+**
+** Function         BTA_AgSetCodec
+**
+** Description      Specify the codec type to be used for the subsequent
+**                  audio connection.
+**
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+BTA_API void BTA_AgSetCodec(UINT16 handle, tBTA_AG_PEER_CODEC codec);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BTA_AG_API_H */
+
+
diff --git a/btif/src/btif_hf_client.c b/btif/src/btif_hf_client.c
new file mode 100644
index 0000000..b4ade0d
--- /dev/null
+++ b/btif/src/btif_hf_client.c
@@ -0,0 +1,1202 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
+/************************************************************************************
+ *
+ *  Filename:      btif_hf.c
+ *
+ *  Description:   Handsfree Profile Bluetooth Interface
+ *
+ *
+ ***********************************************************************************/
+
+#include <hardware/bluetooth.h>
+#include <hardware/bt_hf.h>
+#include <stdlib.h>
+
+#define LOG_TAG "BTIF_HF"
+#include "btif_common.h"
+#include "btif_util.h"
+#include "btif_profile_queue.h"
+
+#include "bd.h"
+#include "bta_ag_api.h"
+
+/************************************************************************************
+**  Constants & Macros
+************************************************************************************/
+#ifndef BTIF_HSAG_SERVICE_NAME
+#define BTIF_HSAG_SERVICE_NAME ("Headset Gateway")
+#endif
+
+#ifndef BTIF_HFAG_SERVICE_NAME
+#define BTIF_HFAG_SERVICE_NAME ("Handsfree Gateway")
+#endif
+
+#ifndef BTIF_HF_SERVICES
+#define BTIF_HF_SERVICES    (BTA_HSP_SERVICE_MASK | BTA_HFP_SERVICE_MASK )
+#endif
+
+#ifndef BTIF_HF_SERVICE_NAMES
+#define BTIF_HF_SERVICE_NAMES {BTIF_HSAG_SERVICE_NAME , BTIF_HFAG_SERVICE_NAME}
+#endif
+
+#ifndef BTIF_HF_SECURITY
+#define BTIF_HF_SECURITY    (BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT)
+#endif
+
+#ifndef BTIF_HF_FEATURES
+#define BTIF_HF_FEATURES   ( BTA_AG_FEAT_3WAY | \
+                             BTA_AG_FEAT_ECNR   | \
+                             BTA_AG_FEAT_REJECT | \
+                             BTA_AG_FEAT_ECS    | \
+                             BTA_AG_FEAT_EXTERR | \
+                             BTA_AG_FEAT_BTRH   | \
+                             BTA_AG_FEAT_VREC   | \
+                             BTA_AG_FEAT_UNAT)
+#endif
+
+#define BTIF_HF_ID_1        0
+
+#define BTIF_HF_CALL_END_TIMEOUT       6
+
+/************************************************************************************
+**  Local type definitions
+************************************************************************************/
+
+/************************************************************************************
+**  Static variables
+************************************************************************************/
+static bthf_callbacks_t *bt_hf_callbacks = NULL;
+
+#define CHECK_BTHF_INIT() if (bt_hf_callbacks == NULL)\
+    {\
+        BTIF_TRACE_WARNING1("BTHF: %s: BTHF not initialized", __FUNCTION__);\
+        return BT_STATUS_NOT_READY;\
+    }\
+    else\
+    {\
+        BTIF_TRACE_EVENT1("BTHF: %s", __FUNCTION__);\
+    }
+
+#define CHECK_BTHF_SLC_CONNECTED() if (bt_hf_callbacks == NULL)\
+    {\
+        BTIF_TRACE_WARNING1("BTHF: %s: BTHF not initialized", __FUNCTION__);\
+        return BT_STATUS_NOT_READY;\
+    }\
+    else if (btif_hf_cb.state != BTHF_CONNECTION_STATE_SLC_CONNECTED)\
+    {\
+        BTIF_TRACE_WARNING2("BTHF: %s: SLC connection not up. state=%s", __FUNCTION__, dump_hf_conn_state(btif_hf_cb.state));\
+        return BT_STATUS_NOT_READY;\
+    }\
+    else\
+    {\
+        BTIF_TRACE_EVENT1("BTHF: %s", __FUNCTION__);\
+    }
+
+/* BTIF-HF control block to map bdaddr to BTA handle */
+typedef struct _btif_hf_cb
+{
+    UINT16                  handle;
+    bt_bdaddr_t             connected_bda;
+    bthf_connection_state_t state;
+    bthf_vr_state_t         vr_state;
+    tBTA_AG_PEER_FEAT       peer_feat;
+    int                     num_active;
+    int                     num_held;
+    struct timespec         call_end_timestamp;
+    bthf_call_state_t       call_setup_state;
+} btif_hf_cb_t;
+
+static btif_hf_cb_t btif_hf_cb;
+
+
+/************************************************************************************
+**  Static functions
+************************************************************************************/
+
+/************************************************************************************
+**  Externs
+************************************************************************************/
+
+/************************************************************************************
+**  Functions
+************************************************************************************/
+
+/*******************************************************************************
+**
+** Function         is_connected
+**
+** Description      Internal function to check if HF is connected
+**
+** Returns          TRUE if connected
+**
+*******************************************************************************/
+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
+        return FALSE;
+}
+
+/*******************************************************************************
+**
+** Function         callstate_to_callsetup
+**
+** Description      Converts HAL call state to BTA call setup indicator value
+**
+** Returns          BTA call indicator value
+**
+*******************************************************************************/
+static UINT8 callstate_to_callsetup(bthf_call_state_t call_state)
+{
+    UINT8 call_setup = 0;
+    if (call_state == BTHF_CALL_STATE_INCOMING)
+        call_setup = 1;
+    if (call_state == BTHF_CALL_STATE_DIALING)
+        call_setup = 2;
+    if (call_state == BTHF_CALL_STATE_ALERTING)
+        call_setup = 3;
+
+    return call_setup;
+}
+
+/*******************************************************************************
+**
+** Function         send_at_result
+**
+** Description      Send AT result code (OK/ERROR)
+**
+** Returns          void
+**
+*******************************************************************************/
+static void send_at_result(UINT8 ok_flag, UINT16 errcode)
+{
+    tBTA_AG_RES_DATA    ag_res;
+    memset (&ag_res, 0, sizeof (ag_res));
+
+    ag_res.ok_flag = ok_flag;
+    if (ok_flag == BTA_AG_OK_ERROR)
+    {
+        ag_res.errcode = errcode;
+    }
+
+    BTA_AgResult (btif_hf_cb.handle, BTA_AG_UNAT_RES, &ag_res);
+}
+
+/*******************************************************************************
+**
+** Function         send_indicator_update
+**
+** Description      Send indicator update (CIEV)
+**
+** Returns          void
+**
+*******************************************************************************/
+static void send_indicator_update (UINT16 indicator, UINT16 value)
+{
+    tBTA_AG_RES_DATA ag_res;
+
+    memset(&ag_res, 0, sizeof(tBTA_AG_RES_DATA));
+    ag_res.ind.id = indicator;
+    ag_res.ind.value = value;
+
+    BTA_AgResult(BTA_AG_HANDLE_ALL, BTA_AG_IND_RES, &ag_res);
+}
+
+void clear_phone_state()
+{
+    btif_hf_cb.call_setup_state = BTHF_CALL_STATE_IDLE;
+    btif_hf_cb.num_active = btif_hf_cb.num_held = 0;
+}
+
+
+/*****************************************************************************
+**   Section name (Group of functions)
+*****************************************************************************/
+
+/*****************************************************************************
+**
+**   btif hf api functions (no context switch)
+**
+*****************************************************************************/
+
+
+/*******************************************************************************
+**
+** Function         btif_hf_upstreams_evt
+**
+** Description      Executes HF UPSTREAMS events in btif context
+**
+** Returns          void
+**
+*******************************************************************************/
+static void btif_hf_upstreams_evt(UINT16 event, char* p_param)
+{
+    tBTA_AG *p_data = (tBTA_AG *)p_param;
+    bdstr_t bdstr;
+
+    BTIF_TRACE_DEBUG2("%s: event=%s", __FUNCTION__, dump_hf_event(event));
+
+    switch (event)
+    {
+        case BTA_AG_ENABLE_EVT:
+        case BTA_AG_DISABLE_EVT:
+            break;
+
+        case BTA_AG_REGISTER_EVT:
+            btif_hf_cb.handle = p_data->reg.hdr.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();
+            }
+            else if (btif_hf_cb.state == BTHF_CONNECTION_STATE_CONNECTING)
+            {
+                btif_hf_cb.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));
+                break;
+            }
+
+            HAL_CBACK(bt_hf_callbacks, connection_state_cb, btif_hf_cb.state, &btif_hf_cb.connected_bda);
+
+            if (btif_hf_cb.state == BTHF_CONNECTION_STATE_DISCONNECTED)
+                bdsetany(btif_hf_cb.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();
+            /* 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
+            */
+            btif_queue_advance();
+            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);
+            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);
+            break;
+
+        case BTA_AG_AUDIO_CLOSE_EVT:
+            HAL_CBACK(bt_hf_callbacks, audio_state_cb, BTHF_AUDIO_STATE_DISCONNECTED, &btif_hf_cb.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);
+            break;
+
+        case BTA_AG_AT_A_EVT:
+            HAL_CBACK(bt_hf_callbacks, answer_call_cmd_cb);
+            break;
+
+        /* Java needs to send OK/ERROR for these commands */
+        case BTA_AG_AT_BLDN_EVT:
+        case BTA_AG_AT_D_EVT:
+            HAL_CBACK(bt_hf_callbacks, dial_call_cmd_cb,
+                (event == BTA_AG_AT_D_EVT) ? p_data->val.str : NULL);
+            break;
+
+        case BTA_AG_AT_CHUP_EVT:
+            HAL_CBACK(bt_hf_callbacks, hangup_call_cmd_cb);
+            break;
+
+        case BTA_AG_AT_CIND_EVT:
+            HAL_CBACK(bt_hf_callbacks, cind_cmd_cb);
+            break;
+
+        case BTA_AG_AT_VTS_EVT:
+            HAL_CBACK(bt_hf_callbacks, dtmf_cmd_cb, p_data->val.str[0]);
+            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);
+            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);
+            break;
+
+        /* TODO: Add a callback for CBC */
+        case BTA_AG_AT_CBC_EVT:
+            break;
+
+        case BTA_AG_AT_CKPD_EVT:
+            HAL_CBACK(bt_hf_callbacks, key_pressed_cmd_cb);
+            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));
+            break;
+
+        case BTA_AG_AT_CLCC_EVT:
+            HAL_CBACK(bt_hf_callbacks, clcc_cmd_cb, p_data->val.num);
+            break;
+
+        case BTA_AG_AT_COPS_EVT:
+            HAL_CBACK(bt_hf_callbacks, cops_cmd_cb);
+            break;
+
+        case BTA_AG_AT_UNAT_EVT:
+            HAL_CBACK(bt_hf_callbacks, unknown_at_cmd_cb,
+                             p_data->val.str);
+            break;
+
+        case BTA_AG_AT_CNUM_EVT:
+            HAL_CBACK(bt_hf_callbacks, cnum_cmd_cb);
+            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);
+            break;
+
+
+        default:
+            BTIF_TRACE_WARNING2("%s: Unhandled event: %d", __FUNCTION__, event);
+            break;
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bte_hf_evt
+**
+** Description      Switches context from BTE to BTIF for all HF events
+**
+** Returns          void
+**
+*******************************************************************************/
+
+static void bte_hf_evt(tBTA_AG_EVT event, tBTA_AG *p_data)
+{
+    bt_status_t status;
+    int param_len = 0;
+
+    /* TODO: BTA sends the union members and not tBTA_AG. If using param_len=sizeof(tBTA_AG), we get a crash on memcpy */
+    if (BTA_AG_REGISTER_EVT == event)
+        param_len = sizeof(tBTA_AG_REGISTER);
+    else if (BTA_AG_OPEN_EVT == event)
+        param_len = sizeof(tBTA_AG_OPEN);
+    else if (BTA_AG_CONN_EVT == event)
+        param_len = sizeof(tBTA_AG_CONN);
+    else if ( (BTA_AG_CLOSE_EVT == event) || (BTA_AG_AUDIO_OPEN_EVT == event) || (BTA_AG_AUDIO_CLOSE_EVT == event))
+        param_len = sizeof(tBTA_AG_HDR);
+    else if (p_data)
+        param_len = sizeof(tBTA_AG_VAL);
+
+    /* switch context to btif task context (copy full union size for convenience) */
+    status = btif_transfer_context(btif_hf_upstreams_evt, (uint16_t)event, (void*)p_data, param_len, NULL);
+
+    /* catch any failed context transfers */
+    ASSERTC(status == BT_STATUS_SUCCESS, "context transfer failed", status);
+}
+
+
+/*******************************************************************************
+**
+** Function         btif_in_hf_generic_evt
+**
+** Description     Processes generic events to be sent to JNI that are not triggered from the BTA.
+**                      Always runs in BTIF context
+**
+** Returns          void
+**
+*******************************************************************************/
+static void btif_in_hf_generic_evt(UINT16 event, char *p_param)
+{
+    UNUSED(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);
+        } break;
+        default:
+        {
+            BTIF_TRACE_WARNING2("%s : Unknown event 0x%x", __FUNCTION__, event);
+        }
+        break;
+    }
+}
+
+
+/*******************************************************************************
+**
+** Function         btif_hf_init
+**
+** Description     initializes the hf interface
+**
+** Returns         bt_status_t
+**
+*******************************************************************************/
+static bt_status_t init( bthf_callbacks_t* callbacks )
+{
+    BTIF_TRACE_EVENT1("%s", __FUNCTION__);
+
+    bt_hf_callbacks = callbacks;
+
+    /* Invoke the enable service API to the core to set the appropriate service_id
+     * Internally, the HSP_SERVICE_ID shall also be enabled if HFP is enabled (phone)
+     * othwerwise only HSP is enabled (tablet)
+    */
+#if (defined(BTIF_HF_SERVICES) && (BTIF_HF_SERVICES & BTA_HFP_SERVICE_MASK))
+    btif_enable_service(BTA_HFP_SERVICE_ID);
+#else
+    btif_enable_service(BTA_HSP_SERVICE_ID);
+#endif
+
+    memset(&btif_hf_cb, 0, sizeof(btif_hf_cb_t));
+    clear_phone_state();
+
+    return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function         connect
+**
+** Description     connect to headset
+**
+** Returns         bt_status_t
+**
+*******************************************************************************/
+static bt_status_t connect_int( bt_bdaddr_t *bd_addr )
+{
+    if (!is_connected(bd_addr))
+    {
+        btif_hf_cb.state = BTHF_CONNECTION_STATE_CONNECTING;
+        bdcpy(btif_hf_cb.connected_bda.address, bd_addr->address);
+
+        BTA_AgOpen(btif_hf_cb.handle, btif_hf_cb.connected_bda.address,
+                   BTIF_HF_SECURITY, BTIF_HF_SERVICES);
+        return BT_STATUS_SUCCESS;
+    }
+
+    return BT_STATUS_BUSY;
+}
+
+static bt_status_t connect( bt_bdaddr_t *bd_addr )
+{
+    CHECK_BTHF_INIT();
+    return btif_queue_connect(UUID_SERVCLASS_AG_HANDSFREE, bd_addr, connect_int);
+}
+
+/*******************************************************************************
+**
+** Function         disconnect
+**
+** Description      disconnect from headset
+**
+** Returns         bt_status_t
+**
+*******************************************************************************/
+static bt_status_t disconnect( bt_bdaddr_t *bd_addr )
+{
+    CHECK_BTHF_INIT();
+
+    if (is_connected(bd_addr))
+    {
+        BTA_AgClose(btif_hf_cb.handle);
+        return BT_STATUS_SUCCESS;
+    }
+
+    return BT_STATUS_FAIL;
+}
+
+/*******************************************************************************
+**
+** Function         connect_audio
+**
+** Description     create an audio connection
+**
+** Returns         bt_status_t
+**
+*******************************************************************************/
+static bt_status_t connect_audio( bt_bdaddr_t *bd_addr )
+{
+    CHECK_BTHF_INIT();
+
+    if (is_connected(bd_addr))
+    {
+        BTA_AgAudioOpen(btif_hf_cb.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,
+                              (char *)bd_addr, sizeof(bt_bdaddr_t), NULL);
+        return BT_STATUS_SUCCESS;
+    }
+
+    return BT_STATUS_FAIL;
+}
+
+/*******************************************************************************
+**
+** Function         disconnect_audio
+**
+** Description      close the audio connection
+**
+** Returns         bt_status_t
+**
+*******************************************************************************/
+static bt_status_t disconnect_audio( bt_bdaddr_t *bd_addr )
+{
+    CHECK_BTHF_INIT();
+
+    if (is_connected(bd_addr))
+    {
+        BTA_AgAudioClose(btif_hf_cb.handle);
+        return BT_STATUS_SUCCESS;
+    }
+
+    return BT_STATUS_FAIL;
+}
+
+/*******************************************************************************
+**
+** Function         start_voice_recognition
+**
+** Description      start voice recognition
+**
+** Returns          bt_status_t
+**
+*******************************************************************************/
+static bt_status_t start_voice_recognition()
+{
+    CHECK_BTHF_INIT();
+    if (is_connected(NULL))
+    {
+        if (btif_hf_cb.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);
+
+            return BT_STATUS_SUCCESS;
+        }
+        else
+        {
+            return BT_STATUS_UNSUPPORTED;
+        }
+    }
+
+    return BT_STATUS_NOT_READY;
+}
+
+/*******************************************************************************
+**
+** Function         stop_voice_recognition
+**
+** Description      stop voice recognition
+**
+** Returns          bt_status_t
+**
+*******************************************************************************/
+static bt_status_t stop_voice_recognition()
+{
+    CHECK_BTHF_INIT();
+
+    if (is_connected(NULL))
+    {
+        if (btif_hf_cb.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);
+
+            return BT_STATUS_SUCCESS;
+        }
+        else
+        {
+            return BT_STATUS_UNSUPPORTED;
+        }
+    }
+
+    return BT_STATUS_NOT_READY;
+}
+
+/*******************************************************************************
+**
+** Function         volume_control
+**
+** Description      volume control
+**
+** Returns          bt_status_t
+**
+*******************************************************************************/
+static bt_status_t volume_control(bthf_volume_type_t type, int volume)
+{
+    CHECK_BTHF_INIT();
+
+    tBTA_AG_RES_DATA ag_res;
+    memset(&ag_res, 0, sizeof(tBTA_AG_RES_DATA));
+    if (is_connected(NULL))
+    {
+        ag_res.num = volume;
+        BTA_AgResult(btif_hf_cb.handle,
+                     (type == BTHF_VOLUME_TYPE_SPK) ? BTA_AG_SPK_RES : BTA_AG_MIC_RES,
+                     &ag_res);
+        return BT_STATUS_SUCCESS;
+    }
+
+    return BT_STATUS_FAIL;
+}
+
+/*******************************************************************************
+**
+** Function         device_status_notification
+**
+** Description      Combined device status change notification
+**
+** Returns          bt_status_t
+**
+*******************************************************************************/
+static bt_status_t device_status_notification(bthf_network_state_t ntk_state,
+                          bthf_service_type_t svc_type, int signal, int batt_chg)
+{
+    CHECK_BTHF_INIT();
+
+    if (is_connected(NULL))
+    {
+        /* send all indicators to BTA.
+        ** BTA will make sure no duplicates are sent out
+        */
+        send_indicator_update(BTA_AG_IND_SERVICE,
+                              (ntk_state == BTHF_NETWORK_STATE_AVAILABLE) ? 1 : 0);
+        send_indicator_update(BTA_AG_IND_ROAM,
+                             (svc_type == BTHF_SERVICE_TYPE_HOME) ? 0 : 1);
+        send_indicator_update(BTA_AG_IND_SIGNAL, signal);
+        send_indicator_update(BTA_AG_IND_BATTCHG, batt_chg);
+        return BT_STATUS_SUCCESS;
+    }
+
+    return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function         cops_response
+**
+** Description      Response for COPS command
+**
+** Returns          bt_status_t
+**
+*******************************************************************************/
+static bt_status_t cops_response(const char *cops)
+{
+    CHECK_BTHF_INIT();
+
+    if (is_connected(NULL))
+    {
+        tBTA_AG_RES_DATA    ag_res;
+
+        /* Format the response */
+        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);
+        return BT_STATUS_SUCCESS;
+    }
+    return BT_STATUS_FAIL;
+}
+
+/*******************************************************************************
+**
+** Function         cind_response
+**
+** Description      Response for CIND command
+**
+** Returns          bt_status_t
+**
+*******************************************************************************/
+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)
+{
+    CHECK_BTHF_INIT();
+
+    if (is_connected(NULL))
+    {
+        tBTA_AG_RES_DATA    ag_res;
+
+        memset (&ag_res, 0, sizeof (ag_res));
+        /* per the errata 2043, call=1 implies atleast one call is in progress (active/held)
+        ** https://www.bluetooth.org/errata/errata_view.cfm?errata_id=2043
+        **/
+        sprintf (ag_res.str, "%d,%d,%d,%d,%d,%d,%d",
+                (num_active + num_held) ? 1 : 0,                       /* Call state */
+                callstate_to_callsetup(call_setup_state),              /* Callsetup state */
+                svc,                                                   /* network service */
+                signal,                                                /* Signal strength */
+                roam,                                                  /* Roaming indicator */
+                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);
+
+        return BT_STATUS_SUCCESS;
+    }
+
+    return BT_STATUS_FAIL;
+}
+
+/*******************************************************************************
+**
+** Function         formatted_at_response
+**
+** Description      Pre-formatted AT response, typically in response to unknown AT cmd
+**
+** Returns          bt_status_t
+**
+*******************************************************************************/
+static bt_status_t formatted_at_response(const char *rsp)
+{
+    CHECK_BTHF_INIT();
+    tBTA_AG_RES_DATA    ag_res;
+
+    if (is_connected(NULL))
+    {
+        /* 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);
+
+        return BT_STATUS_SUCCESS;
+    }
+
+    return BT_STATUS_FAIL;
+}
+
+/*******************************************************************************
+**
+** Function         at_response
+**
+** Description      ok/error response
+**
+** Returns          bt_status_t
+**
+*******************************************************************************/
+static bt_status_t at_response(bthf_at_response_t response_code, int error_code)
+{
+    CHECK_BTHF_INIT();
+
+    if (is_connected(NULL))
+    {
+        send_at_result((response_code == BTHF_AT_RESPONSE_OK) ? BTA_AG_OK_DONE
+                        : BTA_AG_OK_ERROR, error_code);
+        return BT_STATUS_SUCCESS;
+    }
+
+
+    return BT_STATUS_FAIL;
+}
+
+/*******************************************************************************
+**
+** Function         clcc_response
+**
+** Description      response for CLCC command
+**                  Can be iteratively called for each call index. Call index
+**                  of 0 will be treated as NULL termination (Completes response)
+**
+** Returns          bt_status_t
+**
+*******************************************************************************/
+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)
+{
+    CHECK_BTHF_INIT();
+
+    if (is_connected(NULL))
+    {
+        tBTA_AG_RES_DATA    ag_res;
+        int                 xx;
+
+        memset (&ag_res, 0, sizeof (ag_res));
+
+        /* Format the response */
+        if (index == 0)
+        {
+            ag_res.ok_flag = BTA_AG_OK_DONE;
+        }
+        else
+        {
+            BTIF_TRACE_EVENT6("clcc_response: [%d] dir %d state %d mode %d number = %s type = %d",
+                          index, dir, state, mode, number, type);
+            xx = sprintf (ag_res.str, "%d,%d,%d,%d,%d",
+                         index, dir, state, mode, mpty);
+
+            if (number)
+            {
+                if ((type == BTHF_CALL_ADDRTYPE_INTERNATIONAL) && (*number != '+'))
+                    sprintf (&ag_res.str[xx], ",\"+%s\",%d", number, type);
+                else
+                    sprintf (&ag_res.str[xx], ",\"%s\",%d", number, type);
+            }
+        }
+        BTA_AgResult (btif_hf_cb.handle, BTA_AG_CLCC_RES, &ag_res);
+
+        return BT_STATUS_SUCCESS;
+    }
+
+    return BT_STATUS_FAIL;
+}
+
+/*******************************************************************************
+**
+** Function         phone_state_change
+**
+** Description      notify of a call state change
+**                  number & type: valid only for incoming & waiting call
+**
+** Returns          bt_status_t
+**
+*******************************************************************************/
+
+static bt_status_t phone_state_change(int num_active, int num_held, bthf_call_state_t call_setup_state,
+                                            const char *number, bthf_call_addrtype_t type)
+{
+    tBTA_AG_RES res = 0xff;
+    tBTA_AG_RES_DATA ag_res;
+    bt_status_t status = BT_STATUS_SUCCESS;
+    BOOLEAN activeCallUpdated = FALSE;
+
+    CHECK_BTHF_SLC_CONNECTED();
+
+    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));
+
+    /* 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))
+        {
+            BTIF_TRACE_DEBUG1("%s: Record call termination timestamp", __FUNCTION__);
+            clock_gettime(CLOCK_MONOTONIC, &btif_hf_cb.call_end_timestamp);
+        }
+        BTA_AgResult (BTA_AG_HANDLE_ALL, BTA_AG_END_CALL_RES, NULL);
+
+        /* if held call was present, reset that as well */
+        if (btif_hf_cb.num_held)
+            send_indicator_update(BTA_AG_IND_CALLHELD, 0);
+
+        goto update_call_states;
+    }
+
+    /* active state can change when:
+    ** 1. an outgoing/incoming call was answered
+    ** 2. an held was resumed
+    ** 3. without callsetup notifications, call became active
+    ** (3) can happen if call is active and a headset connects to us
+    **
+    ** In the case of (3), we will have to notify the stack of an active
+    ** call, instead of sending an indicator update. This will also
+    ** 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) )
+    {
+        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;
+        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)
+    {
+        BTIF_TRACE_DEBUG3("%s: Call setup states changed. old: %s new: %s",
+            __FUNCTION__, dump_hf_call_state(btif_hf_cb.call_setup_state),
+            dump_hf_call_state(call_setup_state));
+        memset(&ag_res, 0, sizeof(tBTA_AG_RES_DATA));
+
+        switch (call_setup_state)
+        {
+            case BTHF_CALL_STATE_IDLE:
+            {
+                switch (btif_hf_cb.call_setup_state)
+                {
+                    case BTHF_CALL_STATE_INCOMING:
+                        if (num_active > btif_hf_cb.num_active)
+                        {
+                            res = BTA_AG_IN_CALL_CONN_RES;
+                            ag_res.audio_handle = btif_hf_cb.handle;
+                        }
+                        else if (num_held > btif_hf_cb.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)
+                        {
+                            ag_res.audio_handle = BTA_AG_HANDLE_SCO_NO_CHANGE;
+                            res = BTA_AG_OUT_CALL_CONN_RES;
+                        }
+                        else
+                            res = BTA_AG_CALL_CANCEL_RES;
+                        break;
+                    default:
+                        BTIF_TRACE_ERROR1("%s: Incorrect Call setup state transition", __FUNCTION__);
+                        status = BT_STATUS_PARM_INVALID;
+                        break;
+                }
+            } break;
+
+            case BTHF_CALL_STATE_INCOMING:
+                if (num_active || num_held)
+                    res = BTA_AG_CALL_WAIT_RES;
+                else
+                    res = BTA_AG_IN_CALL_RES;
+                if (number)
+                {
+                    int xx = 0;
+                    if ((type == BTHF_CALL_ADDRTYPE_INTERNATIONAL) && (*number != '+'))
+                        xx = sprintf (ag_res.str, "\"+%s\"", number);
+                    else
+                        xx = sprintf (ag_res.str, "\"%s\"", number);
+                    ag_res.num = type;
+
+                    if (res == BTA_AG_CALL_WAIT_RES)
+                        sprintf(&ag_res.str[xx], ",%d", type);
+                }
+                break;
+            case BTHF_CALL_STATE_DIALING:
+                ag_res.audio_handle = btif_hf_cb.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;
+                res = BTA_AG_OUT_CALL_ALERT_RES;
+                break;
+            default:
+                BTIF_TRACE_ERROR1("%s: Incorrect new ringing call state", __FUNCTION__);
+                status = BT_STATUS_PARM_INVALID;
+                break;
+        }
+        BTIF_TRACE_DEBUG3("%s: Call setup state changed. res=%d, audio_handle=%d", __FUNCTION__, res, ag_res.audio_handle);
+
+        if (res)
+            BTA_AgResult(BTA_AG_HANDLE_ALL, res, &ag_res);
+
+        /* if call setup is idle, we have already updated call indicator, jump out */
+        if (call_setup_state == BTHF_CALL_STATE_IDLE)
+        {
+            /* check & update callheld */
+            if ((num_held > 0) && (num_active > 0))
+                send_indicator_update(BTA_AG_IND_CALLHELD, 1);
+            goto update_call_states;
+        }
+    }
+
+    memset(&ag_res, 0, sizeof(tBTA_AG_RES_DATA));
+
+    /* per the errata 2043, call=1 implies atleast one call is in progress (active/held)
+    ** 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)) )
+    {
+        BTIF_TRACE_DEBUG3("%s: Active call states changed. old: %d new: %d", __FUNCTION__, btif_hf_cb.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)
+    {
+        BTIF_TRACE_DEBUG3("%s: Held call states changed. old: %d new: %d", __FUNCTION__, btif_hf_cb.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) &&
+         (num_active && num_held) &&
+         (num_active == btif_hf_cb.num_active) &&
+         (num_held == btif_hf_cb.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;
+
+    return status;
+}
+
+
+/*******************************************************************************
+**
+** Function         btif_hf_call_terminated_recently
+**
+** Description      Checks if a call has been terminated
+**
+** Returns          bt_status_t
+**
+*******************************************************************************/
+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)
+      {
+          return TRUE;
+      }
+      else
+      {
+          btif_hf_cb.call_end_timestamp.tv_sec = 0;
+          return FALSE;
+      }
+}
+
+/*******************************************************************************
+**
+** Function         cleanup
+**
+** Description      Closes the HF interface
+**
+** Returns          bt_status_t
+**
+*******************************************************************************/
+static void  cleanup( void )
+{
+    BTIF_TRACE_EVENT1("%s", __FUNCTION__);
+
+    if (bt_hf_callbacks)
+    {
+        btif_disable_service(BTA_HFP_SERVICE_ID);
+        bt_hf_callbacks = NULL;
+    }
+}
+
+static const bthf_interface_t bthfInterface = {
+    sizeof(bthfInterface),
+    init,
+    connect,
+    disconnect,
+    connect_audio,
+    disconnect_audio,
+    start_voice_recognition,
+    stop_voice_recognition,
+    volume_control,
+    device_status_notification,
+    cops_response,
+    cind_response,
+    formatted_at_response,
+    at_response,
+    clcc_response,
+    phone_state_change,
+    cleanup,
+};
+
+/*******************************************************************************
+**
+** Function         btif_hf_execute_service
+**
+** Description      Initializes/Shuts down the service
+**
+** Returns          BT_STATUS_SUCCESS on success, BT_STATUS_FAIL otherwise
+**
+*******************************************************************************/
+bt_status_t btif_hf_execute_service(BOOLEAN b_enable)
+{
+     char * p_service_names[] = BTIF_HF_SERVICE_NAMES;
+     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);
+     }
+     else {
+         /* De-register AG */
+         BTA_AgDeregister(btif_hf_cb.handle);
+         /* Disable AG */
+         BTA_AgDisable();
+     }
+     return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function         btif_hf_get_interface
+**
+** Description      Get the hf callback interface
+**
+** Returns          bthf_interface_t
+**
+*******************************************************************************/
+const bthf_interface_t *btif_hf_get_interface()
+{
+    BTIF_TRACE_EVENT1("%s", __FUNCTION__);
+    return &bthfInterface;
+}