]> granicus.if.org Git - esp-idf/commitdiff
component/bt: implement HFP Hands Free Unit Role
authorwangmengyang <wangmengyang@espressif.com>
Mon, 21 May 2018 03:33:30 +0000 (11:33 +0800)
committerwangmengyang <wangmengyang@espressif.com>
Mon, 21 May 2018 03:33:30 +0000 (11:33 +0800)
60 files changed:
components/bt/Kconfig
components/bt/bluedroid/api/esp_hf_client_api.c [new file with mode: 0644]
components/bt/bluedroid/api/include/api/esp_hf_client_api.h [new file with mode: 0644]
components/bt/bluedroid/api/include/api/esp_hf_defs.h [new file with mode: 0644]
components/bt/bluedroid/bta/dm/bta_dm_act.c
components/bt/bluedroid/bta/dm/bta_dm_cfg.c
components/bt/bluedroid/bta/dm/bta_dm_ci.c
components/bt/bluedroid/bta/dm/bta_dm_co.c
components/bt/bluedroid/bta/dm/bta_dm_main.c
components/bt/bluedroid/bta/dm/bta_dm_pm.c
components/bt/bluedroid/bta/dm/bta_dm_sco.c
components/bt/bluedroid/bta/dm/include/bta_dm_int.h
components/bt/bluedroid/bta/hf_client/bta_hf_client_act.c [new file with mode: 0644]
components/bt/bluedroid/bta/hf_client/bta_hf_client_api.c [new file with mode: 0644]
components/bt/bluedroid/bta/hf_client/bta_hf_client_at.c [new file with mode: 0644]
components/bt/bluedroid/bta/hf_client/bta_hf_client_cmd.c [new file with mode: 0644]
components/bt/bluedroid/bta/hf_client/bta_hf_client_main.c [new file with mode: 0644]
components/bt/bluedroid/bta/hf_client/bta_hf_client_rfc.c [new file with mode: 0644]
components/bt/bluedroid/bta/hf_client/bta_hf_client_sco.c [new file with mode: 0644]
components/bt/bluedroid/bta/hf_client/bta_hf_client_sdp.c [new file with mode: 0644]
components/bt/bluedroid/bta/hf_client/include/bta_hf_client_at.h [new file with mode: 0644]
components/bt/bluedroid/bta/hf_client/include/bta_hf_client_int.h [new file with mode: 0644]
components/bt/bluedroid/bta/include/bta/bta_dm_ci.h
components/bt/bluedroid/bta/include/bta/bta_dm_co.h
components/bt/bluedroid/bta/include/bta/bta_hf_client_api.h [new file with mode: 0644]
components/bt/bluedroid/bta/include/bta/bta_hf_client_co.h [new file with mode: 0644]
components/bt/bluedroid/bta/include/bta/bta_hfp_defs.h [new file with mode: 0644]
components/bt/bluedroid/btc/core/btc_dm.c
components/bt/bluedroid/btc/core/btc_task.c
components/bt/bluedroid/btc/include/btc/btc_task.h
components/bt/bluedroid/btc/profile/std/hf_client/bta_hf_client_co.c [new file with mode: 0644]
components/bt/bluedroid/btc/profile/std/hf_client/btc_hf_client.c [new file with mode: 0644]
components/bt/bluedroid/btc/profile/std/include/btc_hf_client.h [new file with mode: 0644]
components/bt/bluedroid/common/include/common/bt_target.h
components/bt/bluedroid/device/controller.c
components/bt/bluedroid/device/include/device/controller.h
components/bt/bluedroid/hci/hci_audio.c [new file with mode: 0644]
components/bt/bluedroid/hci/hci_packet_factory.c
components/bt/bluedroid/hci/hci_packet_parser.c
components/bt/bluedroid/hci/include/hci/hci_audio.h [new file with mode: 0644]
components/bt/bluedroid/hci/include/hci/hci_packet_factory.h
components/bt/bluedroid/hci/include/hci/hci_packet_parser.h
components/bt/bluedroid/main/bte_init.c
components/bt/bluedroid/stack/btm/btm_devctl.c
components/bt/bluedroid/stack/btm/btm_sco.c
components/bt/bluedroid/stack/btm/include/btm_int.h
components/bt/bluedroid/stack/btu/btu_hcif.c
components/bt/bluedroid/stack/include/stack/btm_api.h
components/bt/bluedroid/stack/rfcomm/port_rfc.c
components/bt/bt.c
components/bt/component.mk
components/bt/include/esp_bt.h
components/bt/lib
components/esp32/ld/esp32.rom.ld
docs/Doxyfile
docs/en/api-reference/bluetooth/classic_bt.rst
docs/en/api-reference/bluetooth/esp_hf_client.rst [new file with mode: 0644]
docs/en/api-reference/bluetooth/esp_hf_defs.rst [new file with mode: 0644]
docs/zh_CN/api-reference/bluetooth/esp_hf_client.rst [new file with mode: 0644]
docs/zh_CN/api-reference/bluetooth/esp_hf_defs.rst [new file with mode: 0644]

index 853265d653b460b3a0bb83b51633bee0ced86bcd..aca5029e73669579514d87c776e11f2768618513 100644 (file)
@@ -189,6 +189,33 @@ config BT_SPP_ENABLED
     help
         This enables the Serial Port Profile
 
+config HFP_ENABLE
+    bool "Hands Free/Handset Profile"
+    depends on CLASSIC_BT_ENABLED
+    default n
+
+choice HFP_ROLE
+    prompt "Hands-free Profile Role configuration"
+    depends on HFP_ENABLE
+
+config HFP_CLIENT_ENABLE
+    bool "Hands Free Unit"
+endchoice
+
+choice HFP_AUDIO_DATA_PATH
+    prompt "audio(SCO) data path"
+    depends on HFP_ENABLE
+
+config HFP_AUDIO_DATA_PATH_PCM
+    bool "PCM"
+    help
+        This enables the Serial Port Profile
+config HFP_AUDIO_DATA_PATH_HCI
+    bool "HCI"
+    help
+        This enables the Serial Port Profile
+endchoice
+
 config GATTS_ENABLE
     bool "Include GATT server module(GATTS)"
     depends on BLUEDROID_ENABLED
diff --git a/components/bt/bluedroid/api/esp_hf_client_api.c b/components/bt/bluedroid/api/esp_hf_client_api.c
new file mode 100644 (file)
index 0000000..fbc5d47
--- /dev/null
@@ -0,0 +1,476 @@
+// Copyright 2018 Espressif Systems (Shanghai) PTE LTD
+//
+// 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.
+
+#include "common/bt_target.h"
+#include <string.h>
+#include "esp_err.h"
+#include "esp_hf_client_api.h"
+#include "esp_bt_main.h"
+#include "btc/btc_manage.h"
+#include "btc_hf_client.h"
+#include "bta/bta_api.h"
+#include "bta/bta_hf_client_api.h"
+
+#if BTC_HF_CLIENT_INCLUDED
+esp_err_t esp_hf_client_register_callback(esp_hf_client_cb_t callback)
+{
+    if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
+        return ESP_ERR_INVALID_STATE;
+    }
+
+    if (callback == NULL) {
+        return ESP_FAIL;
+    }
+
+    btc_profile_cb_set(BTC_PID_HF_CLIENT, callback);
+    return ESP_OK;
+}
+
+esp_err_t esp_hf_client_init(void)
+{
+    if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
+        return ESP_ERR_INVALID_STATE;
+    }
+
+    btc_msg_t msg;
+
+    msg.sig = BTC_SIG_API_CALL;
+    msg.pid = BTC_PID_HF_CLIENT;
+    msg.act = BTC_HF_CLIENT_INIT_EVT;
+
+    /* Switch to BTC context */
+    bt_status_t stat = btc_transfer_context(&msg, NULL, 0, NULL);
+    return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
+}
+
+esp_err_t esp_hf_client_deinit(void)
+{
+    if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
+        return ESP_ERR_INVALID_STATE;
+    }
+
+    btc_msg_t msg;
+
+    msg.sig = BTC_SIG_API_CALL;
+    msg.pid = BTC_PID_HF_CLIENT;
+    msg.act = BTC_HF_CLIENT_DEINIT_EVT;
+
+    /* Switch to BTC context */
+    bt_status_t stat = btc_transfer_context(&msg, NULL, 0, NULL);
+    return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
+}
+
+esp_err_t esp_hf_client_connect(esp_bd_addr_t remote_bda)
+{
+    if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
+        return ESP_ERR_INVALID_STATE;
+    }
+
+    bt_status_t stat;
+    btc_hf_client_args_t arg;
+    btc_msg_t msg;
+
+    msg.sig = BTC_SIG_API_CALL;
+    msg.pid = BTC_PID_HF_CLIENT;
+    msg.act = BTC_HF_CLIENT_CONNECT_EVT;
+
+    memset(&arg, 0, sizeof(btc_hf_client_args_t));
+
+    /* Switch to BTC context */
+    memcpy(&(arg.connect), remote_bda, sizeof(bt_bdaddr_t));
+    stat = btc_transfer_context(&msg, &arg, sizeof(btc_hf_client_args_t), NULL);
+    return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
+}
+
+esp_err_t esp_hf_client_disconnect(esp_bd_addr_t remote_bda)
+{
+    if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
+        return ESP_ERR_INVALID_STATE;
+    }
+
+    bt_status_t stat;
+    btc_hf_client_args_t arg;
+    btc_msg_t msg;
+
+    msg.sig = BTC_SIG_API_CALL;
+    msg.pid = BTC_PID_HF_CLIENT;
+    msg.act = BTC_HF_CLIENT_DISCONNECT_EVT;
+
+    memset(&arg, 0, sizeof(btc_hf_client_args_t));
+
+    /* Switch to BTC context */
+    memcpy(&(arg.disconnect), remote_bda, sizeof(bt_bdaddr_t));
+    stat = btc_transfer_context(&msg, &arg, sizeof(btc_hf_client_args_t), NULL);
+    return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
+}
+
+esp_err_t esp_hf_client_connect_audio(esp_bd_addr_t remote_bda)
+{
+    if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
+        return ESP_ERR_INVALID_STATE;
+    }
+
+    bt_status_t stat;
+    btc_hf_client_args_t arg;
+    btc_msg_t msg;
+
+    msg.sig = BTC_SIG_API_CALL;
+    msg.pid = BTC_PID_HF_CLIENT;
+    msg.act = BTC_HF_CLIENT_CONNECT_AUDIO_EVT;
+
+    memset(&arg, 0, sizeof(btc_hf_client_args_t));
+
+    /* Switch to BTC context */
+    memcpy(&(arg.connect_audio), remote_bda, sizeof(bt_bdaddr_t));
+    stat = btc_transfer_context(&msg, &arg, sizeof(btc_hf_client_args_t), NULL);
+    return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
+}
+
+esp_err_t esp_hf_client_disconnect_audio(esp_bd_addr_t remote_bda)
+{
+    if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
+        return ESP_ERR_INVALID_STATE;
+    }
+
+    bt_status_t stat;
+    btc_hf_client_args_t arg;
+    btc_msg_t msg;
+
+    msg.sig = BTC_SIG_API_CALL;
+    msg.pid = BTC_PID_HF_CLIENT;
+    msg.act = BTC_HF_CLIENT_DISCONNECT_AUDIO_EVT;
+
+    memset(&arg, 0, sizeof(btc_hf_client_args_t));
+
+    /* Switch to BTC context */
+    memcpy(&(arg.disconnect_audio), remote_bda, sizeof(bt_bdaddr_t));
+    stat = btc_transfer_context(&msg, &arg, sizeof(btc_hf_client_args_t), NULL);
+    return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
+}
+
+
+esp_err_t esp_hf_client_start_voice_recognition(void)
+{
+    if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
+        return ESP_ERR_INVALID_STATE;
+    }
+
+    btc_msg_t msg;
+
+    msg.sig = BTC_SIG_API_CALL;
+    msg.pid = BTC_PID_HF_CLIENT;
+    msg.act = BTC_HF_CLIENT_START_VOICE_RECOGNITION_EVT;
+
+    /* Switch to BTC context */
+    bt_status_t stat = btc_transfer_context(&msg, NULL, 0, NULL);
+    return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
+}
+
+esp_err_t esp_hf_client_stop_voice_recognition(void)
+{
+    if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
+        return ESP_ERR_INVALID_STATE;
+    }
+
+    btc_msg_t msg;
+
+    msg.sig = BTC_SIG_API_CALL;
+    msg.pid = BTC_PID_HF_CLIENT;
+    msg.act = BTC_HF_CLIENT_STOP_VOICE_RECOGNITION_EVT;
+
+    /* Switch to BTC context */
+    bt_status_t stat = btc_transfer_context(&msg, NULL, 0, NULL);
+    return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
+}
+
+esp_err_t esp_hf_client_volume_update(esp_hf_volume_control_target_t type, int volume)
+{
+    if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
+        return ESP_ERR_INVALID_STATE;
+    }
+
+    btc_msg_t msg;
+    btc_hf_client_args_t arg;
+
+    msg.sig = BTC_SIG_API_CALL;
+    msg.pid = BTC_PID_HF_CLIENT;
+    msg.act = BTC_HF_CLIENT_VOLUME_UPDATE_EVT;
+
+    memset(&arg, 0, sizeof(btc_hf_client_args_t));
+    arg.volume_update.type = type;
+    arg.volume_update.volume = volume;
+
+    /* Switch to BTC context */
+    bt_status_t stat = btc_transfer_context(&msg, &arg, sizeof(btc_hf_client_args_t), NULL);
+    return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
+}
+
+esp_err_t esp_hf_client_dial(const char *number)
+{
+    if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
+        return ESP_ERR_INVALID_STATE;
+    }
+
+    btc_msg_t msg;
+    btc_hf_client_args_t arg;
+
+    if (number != NULL && strlen(number) > ESP_BT_HF_CLIENT_NUMBER_LEN) {
+        return ESP_ERR_INVALID_ARG;
+    }
+
+    msg.sig = BTC_SIG_API_CALL;
+    msg.pid = BTC_PID_HF_CLIENT;
+    msg.act = BTC_HF_CLIENT_DIAL_EVT;
+
+    memset(&arg, 0, sizeof(btc_hf_client_args_t));
+    if (number != NULL) {
+        strcpy(arg.dial.number, number);
+    } else {
+        arg.dial.number[0] = '\0';
+    }
+
+    /* Switch to BTC context */
+    bt_status_t stat = btc_transfer_context(&msg, &arg, sizeof(btc_hf_client_args_t), NULL);
+    return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
+}
+
+esp_err_t esp_hf_client_dial_memory(int location)
+{
+    if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
+        return ESP_ERR_INVALID_STATE;
+    }
+
+    btc_msg_t msg;
+    btc_hf_client_args_t arg;
+
+    msg.sig = BTC_SIG_API_CALL;
+    msg.pid = BTC_PID_HF_CLIENT;
+    msg.act = BTC_HF_CLIENT_DIAL_MEMORY_EVT;
+
+    memset(&arg, 0, sizeof(btc_hf_client_args_t));
+    arg.dial_memory.location = location;
+
+    /* Switch to BTC context */
+    bt_status_t stat = btc_transfer_context(&msg, &arg, sizeof(btc_hf_client_args_t), NULL);
+    return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
+}
+
+esp_err_t esp_hf_client_send_chld_cmd(esp_hf_chld_type_t chld, int idx)
+{
+    if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
+        return ESP_ERR_INVALID_STATE;
+    }
+
+    btc_msg_t msg;
+    btc_hf_client_args_t arg;
+
+    msg.sig = BTC_SIG_API_CALL;
+    msg.pid = BTC_PID_HF_CLIENT;
+    msg.act = BTC_HF_CLIENT_SEND_CHLD_CMD_EVT;
+
+    memset(&arg, 0, sizeof(btc_hf_client_args_t));
+    arg.chld.type = chld;
+    arg.chld.idx = idx;
+
+    /* Switch to BTC context */
+    bt_status_t stat = btc_transfer_context(&msg, &arg, sizeof(btc_hf_client_args_t), NULL);
+    return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
+}
+
+esp_err_t esp_hf_client_send_btrh_cmd(esp_hf_btrh_cmd_t btrh)
+{
+    if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
+        return ESP_ERR_INVALID_STATE;
+    }
+
+    btc_msg_t msg;
+    btc_hf_client_args_t arg;
+
+    msg.sig = BTC_SIG_API_CALL;
+    msg.pid = BTC_PID_HF_CLIENT;
+    msg.act = BTC_HF_CLIENT_SEND_BTRH_CMD_EVT;
+
+    memset(&arg, 0, sizeof(btc_hf_client_args_t));
+    arg.btrh.cmd = btrh;
+
+    /* Switch to BTC context */
+    bt_status_t stat = btc_transfer_context(&msg, &arg, sizeof(btc_hf_client_args_t), NULL);
+    return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
+}
+
+esp_err_t esp_hf_client_answer_call(void)
+{
+    if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
+        return ESP_ERR_INVALID_STATE;
+    }
+
+    btc_msg_t msg;
+
+    msg.sig = BTC_SIG_API_CALL;
+    msg.pid = BTC_PID_HF_CLIENT;
+    msg.act = BTC_HF_CLIENT_ANSWER_CALL_EVT;
+
+    /* Switch to BTC context */
+    bt_status_t stat = btc_transfer_context(&msg, NULL, 0, NULL);
+    return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
+}
+
+esp_err_t esp_hf_client_reject_call(void)
+{
+    if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
+        return ESP_ERR_INVALID_STATE;
+    }
+
+    btc_msg_t msg;
+
+    msg.sig = BTC_SIG_API_CALL;
+    msg.pid = BTC_PID_HF_CLIENT;
+    msg.act = BTC_HF_CLIENT_REJECT_CALL_EVT;
+
+    /* Switch to BTC context */
+    bt_status_t stat = btc_transfer_context(&msg, NULL, 0, NULL);
+    return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
+}
+
+esp_err_t esp_hf_client_query_current_calls(void)
+{
+    if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
+        return ESP_ERR_INVALID_STATE;
+    }
+
+    btc_msg_t msg;
+
+    msg.sig = BTC_SIG_API_CALL;
+    msg.pid = BTC_PID_HF_CLIENT;
+    msg.act = BTC_HF_CLIENT_QUERY_CURRENT_CALLS_EVT;
+
+    /* Switch to BTC context */
+    bt_status_t stat = btc_transfer_context(&msg, NULL, 0, NULL);
+    return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
+}
+
+esp_err_t esp_hf_client_query_current_operator_name(void)
+{
+    if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
+        return ESP_ERR_INVALID_STATE;
+    }
+
+    btc_msg_t msg;
+
+    msg.sig = BTC_SIG_API_CALL;
+    msg.pid = BTC_PID_HF_CLIENT;
+    msg.act = BTC_HF_CLIENT_QUERY_CURRENT_OPERATOR_NAME_EVT;
+
+    /* Switch to BTC context */
+    bt_status_t stat = btc_transfer_context(&msg, NULL, 0, NULL);
+    return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
+}
+
+esp_err_t esp_hf_client_retrieve_subscriber_info(void)
+{
+    if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
+        return ESP_ERR_INVALID_STATE;
+    }
+
+    btc_msg_t msg;
+
+    msg.sig = BTC_SIG_API_CALL;
+    msg.pid = BTC_PID_HF_CLIENT;
+    msg.act = BTC_HF_CLIENT_RETRIEVE_SUBSCRIBER_INFO_EVT;
+
+    /* Switch to BTC context */
+    bt_status_t stat = btc_transfer_context(&msg, NULL, 0, NULL);
+    return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
+}
+
+esp_err_t esp_hf_client_send_dtmf(char code)
+{
+    if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
+        return ESP_ERR_INVALID_STATE;
+    }
+
+    btc_msg_t msg;
+    btc_hf_client_args_t arg;
+
+    msg.sig = BTC_SIG_API_CALL;
+    msg.pid = BTC_PID_HF_CLIENT;
+    msg.act = BTC_HF_CLIENT_SEND_DTMF_EVT;
+
+    memset(&arg, 0, sizeof(btc_hf_client_args_t));
+    arg.send_dtmf.code = code;
+
+    /* Switch to BTC context */
+    bt_status_t stat = btc_transfer_context(&msg, &arg, sizeof(btc_hf_client_args_t), NULL);
+    return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
+}
+
+esp_err_t esp_hf_client_request_last_voice_tag_number(void)
+{
+    if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
+        return ESP_ERR_INVALID_STATE;
+    }
+
+    btc_msg_t msg;
+
+    msg.sig = BTC_SIG_API_CALL;
+    msg.pid = BTC_PID_HF_CLIENT;
+    msg.act = BTC_HF_CLIENT_REQUEST_LAST_VOICE_TAG_NUMBER_EVT;
+
+    /* Switch to BTC context */
+    bt_status_t stat = btc_transfer_context(&msg, NULL, 0, NULL);
+    return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
+}
+
+esp_err_t esp_hf_client_register_data_callback(esp_hf_client_incoming_data_cb_t recv,
+                                               esp_hf_client_outgoing_data_cb_t send)
+{
+    if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
+        return ESP_ERR_INVALID_STATE;
+    }
+
+    btc_msg_t msg;
+    msg.sig = BTC_SIG_API_CALL;
+    msg.pid = BTC_PID_HF_CLIENT;
+    msg.act = BTC_HF_CLIENT_REGISTER_DATA_CALLBACK_EVT;
+
+    btc_hf_client_args_t arg;
+    memset(&arg, 0, sizeof(btc_hf_client_args_t));
+    arg.reg_data_cb.recv = recv;
+    arg.reg_data_cb.send = send;
+
+    /* Switch to BTC context */
+    bt_status_t stat = btc_transfer_context(&msg, &arg, sizeof(btc_hf_client_args_t), NULL);
+    return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
+}
+
+
+#if (BTM_SCO_HCI_INCLUDED == TRUE )
+void esp_hf_client_outgoing_data_ready(void)
+{
+    BTA_HfClientCiData();
+}
+
+void esp_hf_client_pcm_resample_init(uint32_t src_sps, uint32_t bits, uint32_t channels)
+{
+    BTA_DmPcmInitSamples(src_sps, bits, channels);
+}
+
+int32_t esp_hf_client_pcm_resample(void *src, uint32_t in_bytes, void *dst)
+{
+    return BTA_DmPcmResample(src, in_bytes, dst);
+}
+
+#endif /* #if (BTM_SCO_HCI_INCLUDED == TRUE ) */
+
+#endif /* BTC_HF_CLIENT_INCLUDED */
diff --git a/components/bt/bluedroid/api/include/api/esp_hf_client_api.h b/components/bt/bluedroid/api/include/api/esp_hf_client_api.h
new file mode 100644 (file)
index 0000000..65598e0
--- /dev/null
@@ -0,0 +1,635 @@
+// Copyright 2018 Espressif Systems (Shanghai) PTE LTD
+//
+// 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.
+
+#ifndef __ESP_HF_CLIENT_API_H__
+#define __ESP_HF_CLIENT_API_H__
+
+#include "esp_err.h"
+#include "esp_bt_defs.h"
+#include "esp_hf_defs.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ESP_BT_HF_CLIENT_NUMBER_LEN           (32)
+#define ESP_BT_HF_CLIENT_OPERATOR_NAME_LEN    (16)
+
+/// Bluetooth HFP RFCOMM connection and service level connection status
+typedef enum {
+    ESP_HF_CLIENT_CONNECTION_STATE_DISCONNECTED = 0,     /*!< RFCOMM data link channel released */
+    ESP_HF_CLIENT_CONNECTION_STATE_CONNECTING,           /*!< connecting remote device on the RFCOMM data link*/
+    ESP_HF_CLIENT_CONNECTION_STATE_CONNECTED,            /*!< RFCOMM connection established */
+    ESP_HF_CLIENT_CONNECTION_STATE_SLC_CONNECTED,        /*!< service level connection established */
+    ESP_HF_CLIENT_CONNECTION_STATE_DISCONNECTING,        /*!< disconnecting with remote device on the RFCOMM dat link*/
+} esp_hf_client_connection_state_t;
+
+/// Bluetooth HFP audio connection status
+typedef enum {
+    ESP_HF_CLIENT_AUDIO_STATE_DISCONNECTED = 0,          /*!< audio connection released */
+    ESP_HF_CLIENT_AUDIO_STATE_CONNECTING,                /*!< audio connection has been initiated */
+    ESP_HF_CLIENT_AUDIO_STATE_CONNECTED,                 /*!< audio connection is established */
+    ESP_HF_CLIENT_AUDIO_STATE_CONNECTED_MSBC,            /*!< mSBC audio connection is estalibshed */
+} esp_hf_client_audio_state_t;
+
+/// in-band ring tone state
+typedef enum {
+    ESP_HF_CLIENT_IN_BAND_RINGTONE_NOT_PROVIDED = 0,
+    ESP_HF_CLIENT_IN_BAND_RINGTONE_PROVIDED,
+} esp_hf_client_in_band_ring_state_t;
+
+/* features masks of AG */
+#define ESP_HF_CLIENT_PEER_FEAT_3WAY       0x01        /* Three-way calling */
+#define ESP_HF_CLIENT_PEER_FEAT_ECNR       0x02        /* Echo cancellation and/or noise reduction */
+#define ESP_HF_CLIENT_PEER_FEAT_VREC       0x04        /* Voice recognition */
+#define ESP_HF_CLIENT_PEER_FEAT_INBAND     0x08        /* In-band ring tone */
+#define ESP_HF_CLIENT_PEER_FEAT_VTAG       0x10        /* Attach a phone number to a voice tag */
+#define ESP_HF_CLIENT_PEER_FEAT_REJECT     0x20        /* Ability to reject incoming call */
+#define ESP_HF_CLIENT_PEER_FEAT_ECS        0x40        /* Enhanced Call Status */
+#define ESP_HF_CLIENT_PEER_FEAT_ECC        0x80        /* Enhanced Call Control */
+#define ESP_HF_CLIENT_PEER_FEAT_EXTERR    0x100        /* Extended error codes */
+#define ESP_HF_CLIENT_PEER_FEAT_CODEC     0x200        /* Codec Negotiation */
+
+/* CHLD feature masks of AG */
+#define ESP_HF_CLIENT_CHLD_FEAT_REL           0x01       /* 0  Release waiting call or held calls */
+#define ESP_HF_CLIENT_CHLD_FEAT_REL_ACC       0x02       /* 1  Release active calls and accept other waiting or held call */
+#define ESP_HF_CLIENT_CHLD_FEAT_REL_X         0x04       /* 1x Release specified active call only */
+#define ESP_HF_CLIENT_CHLD_FEAT_HOLD_ACC      0x08       /* 2  Active calls on hold and accept other waiting or held call */
+#define ESP_HF_CLIENT_CHLD_FEAT_PRIV_X        0x10       /* 2x Request private mode with specified call(put the rest on hold */
+#define ESP_HF_CLIENT_CHLD_FEAT_MERGE         0x20       /* 3  Add held call to multiparty */
+#define ESP_HF_CLIENT_CHLD_FEAT_MERGE_DETACH  0x40       /* 4  Connect two calls and leave(disconnct from multiparty */
+
+/// HF CLIENT callback events
+typedef enum {
+    ESP_HF_CLIENT_CONNECTION_STATE_EVT = 0,          /*!< connection state changed event */
+    ESP_HF_CLIENT_AUDIO_STATE_EVT,                   /*!< audio connection state change event */
+    ESP_HF_CLIENT_BVRA_EVT,                          /*!< voice recognition state change event */
+    ESP_HF_CLIENT_CIND_CALL_EVT,                     /*!< call indication */
+    ESP_HF_CLIENT_CIND_CALL_SETUP_EVT,               /*!< call setup indication */
+    ESP_HF_CLIENT_CIND_CALL_HELD_EVT,                /*!< call held indication */
+    ESP_HF_CLIENT_CIND_SERVICE_AVAILABILITY_EVT,     /*!< network service availability indication */
+    ESP_HF_CLIENT_CIND_SIGNAL_STRENGTH_EVT,          /*!< signal strength indication */
+    ESP_HF_CLIENT_CIND_ROAMING_STATUS_EVT,           /*!< roaming status indication */
+    ESP_HF_CLIENT_CIND_BATTERY_LEVEL_EVT,            /*!< battery level indication */
+    ESP_HF_CLIENT_COPS_CURRENT_OPERATOR_EVT,         /*!< current operator information */
+    ESP_HF_CLIENT_BTRH_EVT,                          /*!< call response and hold event */
+    ESP_HF_CLIENT_CLIP_EVT,                          /*!< Calling Line Identification notification */
+    ESP_HF_CLIENT_CCWA_EVT,                          /*!< call waiting notification */
+    ESP_HF_CLIENT_CLCC_EVT,                          /*!< list of current calls notification */
+    ESP_HF_CLIENT_VOLUME_CONTROL_EVT,                /*!< audio volume control command from AG, provided by +VGM or +VGS message */
+    ESP_HF_CLIENT_AT_RESPONSE_EVT,                   /*!< AT command response event */
+    ESP_HF_CLIENT_CNUM_EVT,                          /*!< subscriber information response from AG */
+    ESP_HF_CLIENT_BSIR_EVT,                          /*!< setting of in-band ring tone */
+    ESP_HF_CLIENT_BINP_EVT,                          /*!< requested number of last voice tag from AG */
+    ESP_HF_CLIENT_RING_IND_EVT,                      /*!< ring indication event */
+} esp_hf_client_cb_event_t;
+
+/// HFP client callback parameters
+typedef union {
+    /**
+     * @brief  ESP_HF_CLIENT_CONNECTION_STATE_EVT
+     */
+    struct hf_client_conn_stat_param {
+        esp_hf_client_connection_state_t state;   /*!< HF connection state */
+        uint32_t peer_feat;                       /*!< AG supported features */
+        uint32_t chld_feat;                       /*!< AG supported features on call hold and multiparty services */
+        esp_bd_addr_t remote_bda;                 /*!< remote bluetooth device address */
+    } conn_stat;                                  /*!< HF callback param of ESP_HF_CLIENT_CONNECTION_STATE_EVT */
+
+    /**
+     * @brief ESP_HF_CLIENT_AUDIO_STATE_EVT
+     */
+    struct hf_client_audio_stat_param {
+        esp_hf_client_audio_state_t state;        /*!< audio connection state */
+        esp_bd_addr_t remote_bda;                 /*!< remote bluetooth device address */
+    } audio_stat;                                 /*!< HF callback param of ESP_HF_CLIENT_AUDIO_STATE_EVT */
+
+    /**
+     * @brief ESP_HF_CLIENT_BVRA_EVT
+     */
+    struct hf_client_bvra_param {
+        esp_hf_vr_state_t value;                  /*!< voice recognition state */
+    } bvra;                                       /*!< HF callback param of ESP_HF_CLIENT_BVRA_EVT */
+
+    /**
+     * @brief ESP_HF_CLIENT_CIND_SERVICE_AVAILABILITY_EVT
+     */
+    struct hf_client_service_availability_param {
+        esp_hf_service_availability_status_t status;     /*!< service availability status */
+    } service_availability;                              /*!< HF callback param of ESP_HF_CLIENT_CIND_SERVICE_AVAILABILITY_EVT */
+
+    /**
+     * @brief ESP_HF_CLIENT_CIND_ROAMING_STATUS_EVT
+     */
+    struct hf_client_network_roaming_param {
+        esp_hf_roaming_status_t status;          /*!< roaming status */
+    } roaming;                                   /*!< HF callback param of ESP_HF_CLIENT_CIND_ROAMING_STATUS_EVT */
+
+    /**
+     * @brief ESP_HF_CLIENT_CIND_SIGNAL_STRENGTH_EVT
+     */
+    struct hf_client_signal_strength_ind_param {
+        int value;                               /*!< singal strength value, ranges from 0 to 5 */
+    } signal_strength;                           /*!< HF callback param of ESP_HF_CLIENT_CIND_SIGNAL_STRENGTH_EVT */
+
+    /**
+     * @brief ESP_HF_CLIENT_CIND_BATTERY_LEVEL_EVT
+     */
+    struct hf_client_battery_level_ind_param {
+        int value;                               /*!< battery charge value, ranges from 0 to 5 */
+    } battery_level;                             /*!< HF callback param of ESP_HF_CLIENT_CIND_BATTERY_LEVEL_EVT */
+
+    /**
+     * @brief ESP_HF_CLIENT_COPS_CURRENT_OPERATOR_EVT
+     */
+    struct hf_client_current_operator_param {
+        const char *name;                        /*!< name of the network operator */
+    } cops;                                      /*!< HF callback param of ESP_HF_CLIENT_COPS_CURRENT_OPERATOR_EVT */
+
+    /**
+     * @brief ESP_HF_CLIENT_CIND_CALL_EVT
+     */
+    struct hf_client_call_ind_param {
+        esp_hf_call_status_t status;             /*!< call status indicator */
+    } call;                                      /*!< HF callback param of ESP_HF_CLIENT_CIND_CALL_EVT */
+
+    /**
+     * @brief ESP_HF_CLIENT_CIND_CALL_SETUP_EVT
+     */
+    struct hf_client_call_setup_ind_param {
+        esp_hf_call_setup_status_t status;       /*!< call setup status indicator */
+    } call_setup;                                /*!< HF callback param of ESP_HF_CLIENT_BVRA_EVT */
+
+    /**
+     * @brief ESP_HF_CLIENT_CIND_CALL_HELD_EVT
+     */
+    struct hf_client_call_held_ind_param {
+        esp_hf_call_held_status_t status;        /*!< bluetooth proprietary call hold status indocator */
+    } call_held;                                 /*!< HF callback param of ESP_HF_CLIENT_CIND_CALL_HELD_EVT */
+
+    /**
+     * @brief ESP_HF_CLIENT_BTRH_EVT
+     */
+    struct hf_client_btrh_param {
+        esp_hf_btrh_status_t status;             /*!< call hold and response status result code */
+    } btrh;                                      /*!< HF callback param of ESP_HF_CLIENT_BRTH_EVT */
+
+    /**
+     * @brief ESP_HF_CLIENT_CLIP_EVT
+     */
+    struct hf_client_clip_param {
+        const char *number;                      /*!< phone number string of call */
+    } clip;                                      /*!< HF callback param of ESP_HF_CLIENT_CLIP_EVT */
+
+    /**
+     * @brief ESP_HF_CLIENT_CCWA_EVT
+     */
+    struct hf_client_ccwa_param {
+        const char *number;                      /*!< phone number string of waiting call */
+    } ccwa;                                      /*!< HF callback param of ESP_HF_CLIENT_BVRA_EVT */
+
+    /**
+     * @brief ESP_HF_CLIENT_CLCC_EVT
+     */
+    struct hf_client_clcc_param {
+        int idx;                                 /*!< numbering(starting with 1) of the call */
+        esp_hf_current_call_direction_t dir;     /*!< direction of the call */
+        esp_hf_current_call_status_t status;     /*!< status of the call */
+        esp_hf_current_call_mpty_type_t mpty;    /*!< multi-party flag */
+        char *number;                            /*!< phone number(optional) */
+    } clcc;                                      /*!< HF callback param of ESP_HF_CLIENT_CLCC_EVT */
+
+    /**
+     * @brief ESP_HF_CLIENT_VOLUME_CONTROL_EVT
+     */
+    struct hf_client_volume_control_param {
+        esp_hf_volume_control_target_t type;     /*!< volume control target, speaker or microphone */
+        int volume;                              /*!< gain, ranges from 0 to 15 */
+    } volume_control;                            /*!< HF callback param of ESP_HF_CLIENT_VOLUME_CONTROL_EVT */
+
+    /**
+     * @brief ESP_HF_CLIENT_AT_RESPONSE_EVT
+     */
+    struct hf_client_at_response_param {
+        esp_hf_at_response_code_t code;          /*!< AT response code */
+        esp_hf_cme_err_t cme;                    /*!< Extended Audio Gateway Error Result Code */
+    } at_response;                               /*!< HF callback param of ESP_HF_CLIENT_AT_RESPONSE_EVT */
+
+    /**
+     * @brief ESP_HF_CLIENT_CNUM_EVT
+     */
+    struct hf_client_cnum_param {
+        const char *number;                      /*!< phone number string */
+        esp_hf_subscriber_service_type_t type;   /*!< service type that the phone number relates to */
+    } cnum;                                      /*!< HF callback param of ESP_HF_CLIENT_CNUM_EVT */
+
+    /**
+     * @brief ESP_HF_CLIENT_BSIR_EVT
+     */
+    struct hf_client_bsirparam {
+        esp_hf_client_in_band_ring_state_t state;  /*!< setting state of in-band ring tone */
+    } bsir;                                        /*!< HF callback param of ESP_HF_CLIENT_BSIR_EVT */
+
+    /**
+     * @brief ESP_HF_CLIENT_BINP_EVT
+     */
+    struct hf_client_binp_param {
+        const char *number;                      /*!< phone number corresponding to the last voice tag in the HF */
+    } binp;                                      /*!< HF callback param of ESP_HF_CLIENT_BINP_EVT */
+
+} esp_hf_client_cb_param_t;
+
+/**
+ * @brief           HFP client incoming data callback function, the callback is useful in case of 
+ *                  Voice Over HCI.
+ * @param[in]       buf : pointer to incoming data(payload of HCI synchronous data packet), the 
+ *                  buffer is allocated inside bluetooth protocol stack and will be released after
+ *                  invoke of the callback is finished.
+ * @param[in]       len : size(in bytes) in buf
+ */
+typedef void (* esp_hf_client_incoming_data_cb_t)(const uint8_t *buf, uint32_t len);
+
+/**
+ * @brief           HFP client outgoing data callback function, the callback is useful in case of 
+ *                  Voice Over HCI. Once audio connection is set up and the application layer has 
+ *                  prepared data to send, the lower layer will call this function to read data 
+ *                  and then send. This callback is supposed to be implemented as non-blocking,
+ *                  and if data is not enough, return value 0 is supposed.
+ *                  
+ * @param[in]       buf : pointer to incoming data(payload of HCI synchronous data packet), the 
+ *                  buffer is allocated inside bluetooth protocol stack and will be released after
+ *                  invoke of the callback is finished.
+ * @param[in]       len : size(in bytes) in buf
+ * @param[out]      length of data successfully read
+ */
+typedef uint32_t (* esp_hf_client_outgoing_data_cb_t)(uint8_t *buf, uint32_t len);
+
+/**
+ * @brief           HFP client callback function type
+ *
+ * @param           event : Event type
+ *
+ * @param           param : Pointer to callback parameter
+ */
+typedef void (* esp_hf_client_cb_t)(esp_hf_client_cb_event_t event, esp_hf_client_cb_param_t *param);
+
+/**
+ * @brief           Register application callback function to HFP client module. This function should be called
+ *                  only after esp_bluedroid_enable() completes successfully, used by HFP client
+ *
+ * @param[in]       callback: HFP client event callback function
+ *
+ * @return
+ *                  - ESP_OK: success
+ *                  - ESP_INVALID_STATE: if bluetooth stack is not yet enabled
+ *                  - ESP_FAIL: if callback is a NULL function pointer
+ *
+ */
+esp_err_t esp_hf_client_register_callback(esp_hf_client_cb_t callback);
+
+/**
+ *
+ * @brief           Initialize the bluetooth HFP client module. This function should be called
+ *                  after esp_bluedroid_enable() completes successfully
+ *
+ * @return
+ *                  - ESP_OK: if the initialization request is sent successfully
+ *                  - ESP_INVALID_STATE: if bluetooth stack is not yet enabled
+ *                  - ESP_FAIL: others
+ *
+ */
+esp_err_t esp_hf_client_init(void);
+
+/**
+ *
+ * @brief           De-initialize for HFP client module. This function
+ *                  should be called only after esp_bluedroid_enable() completes successfully
+ *
+ * @return
+ *                  - ESP_OK: success
+ *                  - ESP_INVALID_STATE: if bluetooth stack is not yet enabled
+ *                  - ESP_FAIL: others
+ *
+ */
+esp_err_t esp_hf_client_deinit(void);
+
+/**
+ *
+ * @brief           Connect to remote bluetooth HFP audio gateway(AG) device, must after esp_a2d_hf_client_init()
+ *
+ * @param[in]       remote_bda: remote bluetooth device address
+ *
+ * @return
+ *                  - ESP_OK: connect request is sent to lower layer
+ *                  - ESP_INVALID_STATE: if bluetooth stack is not yet enabled
+ *                  - ESP_FAIL: others
+ *
+ */
+esp_err_t esp_hf_client_connect(esp_bd_addr_t remote_bda);
+
+/**
+ *
+ * @brief           Disconnect from the remote HFP audio gateway
+ *
+ * @param[in]       remote_bda: remote bluetooth device address
+ * @return
+ *                  - ESP_OK: disconnect request is sent to lower layer
+ *                  - ESP_INVALID_STATE: if bluetooth stack is not yet enabled
+ *                  - ESP_FAIL: others
+ *
+ */
+esp_err_t esp_hf_client_disconnect(esp_bd_addr_t remote_bda);
+
+/**
+ *
+ * @brief           Create audio connection with remote HFP AG. As a precondition to use this API,
+ *                  Service Level Connection shall exist with AG
+ *
+ * @param[in]       remote_bda: remote bluetooth device address
+ * @return
+ *                  - ESP_OK: disconnect request is sent to lower layer
+ *                  - ESP_INVALID_STATE: if bluetooth stack is not yet enabled
+ *                  - ESP_FAIL: others
+ *
+ */
+esp_err_t esp_hf_client_connect_audio(esp_bd_addr_t remote_bda);
+
+/**
+ *
+ * @brief           Release the established audio connection with remote HFP AG.
+ *
+ * @param[in]       remote_bda: remote bluetooth device address
+ * @return
+ *                  - ESP_OK: disconnect request is sent to lower layer
+ *                  - ESP_INVALID_STATE: if bluetooth stack is not yet enabled
+ *                  - ESP_FAIL: others
+ *
+ */
+esp_err_t esp_hf_client_disconnect_audio(esp_bd_addr_t remote_bda);
+
+/**
+ *
+ * @brief           Enable voice recognition in the AG. As a precondition to use this API,
+ *                  Service Level Connection shall exist with AG
+ *
+ * @return
+ *                  - ESP_OK: disconnect request is sent to lower layer
+ *                  - ESP_INVALID_STATE: if bluetooth stack is not yet enabled
+ *                  - ESP_FAIL: others
+ *
+ */
+esp_err_t esp_hf_client_start_voice_recognition(void);
+
+/**
+ *
+ * @brief           Disable voice recognition in the AG. As a precondition to use this API,
+ *                  Service Level Connection shall exist with AG
+ *
+ * @return
+ *                  - ESP_OK: disconnect request is sent to lower layer
+ *                  - ESP_INVALID_STATE: if bluetooth stack is not yet enabled
+ *                  - ESP_FAIL: others
+ *
+ */
+esp_err_t esp_hf_client_stop_voice_recognition(void);
+
+/**
+ *
+ * @brief           Volume synchronization with AG. As a precondition to use this API,
+ *                  Service Level Connection shall exist with AG
+ *
+ * @param[in]       type: volume control target, speaker or microphone
+ * @param[in]       volume: gain of the speaker of microphone, ranges 0 to 15
+ *
+ * @return
+ *                  - ESP_OK: disconnect request is sent to lower layer
+ *                  - ESP_INVALID_STATE: if bluetooth stack is not yet enabled
+ *                  - ESP_FAIL: others
+ *
+ */
+esp_err_t esp_hf_client_volume_update(esp_hf_volume_control_target_t type, int volume);
+
+/**
+ *
+ * @brief           Place a call with a specified number, if number is NULL, last called number is
+ *                  called.  As a precondition to use this API, Service Level Connection shall
+ *                  exist with AG
+ *
+ * @param[in]       number: number string of the call. If NULL, the last number is called(aka re-dial)
+ *
+ * @return
+ *                  - ESP_OK: disconnect request is sent to lower layer
+ *                  - ESP_INVALID_STATE: if bluetooth stack is not yet enabled
+ *                  - ESP_FAIL: others
+ *
+ */
+esp_err_t esp_hf_client_dial(const char *number);
+
+/**
+ *
+ * @brief           Place a call with number specified by location(speed dial). As a precondition,
+ *                  to use this API, Service Level Connection shall exist with AG
+ *
+ * @param[in]       location: location of the number in the memory
+ *
+ * @return
+ *                  - ESP_OK: disconnect request is sent to lower layer
+ *                  - ESP_INVALID_STATE: if bluetooth stack is not yet enabled
+ *                  - ESP_FAIL: others
+ *
+ */
+
+esp_err_t esp_hf_client_dial_memory(int location);
+
+/**
+ *
+ * @brief           Send call hold and multiparty commands, or enhanced call control commands(Use AT+CHLD).
+ *                  As a precondition to use this API, Service Level Connection shall exist with AG
+ *
+ * @param[in]       chld: AT+CHLD call hold and multiparty handling AT command.
+ * @param[in]       idx: used in Enhanced Call Control Mechanisms, used if chld is
+ *                       ESP_HF_CHLD_TYPE_REL_X or ESP_HF_CHLD_TYPE_PRIV_X
+ *
+ * @return
+ *                  - ESP_OK: disconnect request is sent to lower layer
+ *                  - ESP_INVALID_STATE: if bluetooth stack is not yet enabled
+ *                  - ESP_FAIL: others
+ *
+ */
+esp_err_t esp_hf_client_send_chld_cmd(esp_hf_chld_type_t chld, int idx);
+
+/**
+ *
+ * @brief           Send response and hold action command(Send AT+BTRH command)
+ *                  As a precondition to use this API, Service Level Connection shall exist with AG
+ *
+ * @param[in]       btrh: response and hold action to send
+ *
+ * @return
+ *                  - ESP_OK: disconnect request is sent to lower layer
+ *                  - ESP_INVALID_STATE: if bluetooth stack is not yet enabled
+ *                  - ESP_FAIL: others
+ *
+ */
+esp_err_t esp_hf_client_send_btrh_cmd(esp_hf_btrh_cmd_t btrh);
+
+/**
+ *
+ * @brief           Answer an incoming call(send ATA command). As a precondition to use this API,
+ *                  Service Level Connection shall exist with AG
+ *
+ * @return
+ *                  - ESP_OK: disconnect request is sent to lower layer
+ *                  - ESP_INVALID_STATE: if bluetooth stack is not yet enabled
+ *                  - ESP_FAIL: others
+ *
+ */
+esp_err_t esp_hf_client_answer_call(void);
+
+/**
+ *
+ * @brief           Reject an incoming call(send AT+CHUP command), As a precondition to use this API,
+ *                  Service Level Connection shall exist with AG
+ *
+ * @return
+ *                  - ESP_OK: disconnect request is sent to lower layer
+ *                  - ESP_INVALID_STATE: if bluetooth stack is not yet enabled
+ *                  - ESP_FAIL: others
+ *
+ */
+esp_err_t esp_hf_client_reject_call(void);
+
+/**
+ *
+ * @brief           Query list of current calls in AG(send AT+CLCC command), As a precondition to use this API,
+ *                  Service Level Connection shall exist with AG
+ *
+ * @return
+ *                  - ESP_OK: disconnect request is sent to lower layer
+ *                  - ESP_INVALID_STATE: if bluetooth stack is not yet enabled
+ *                  - ESP_FAIL: others
+ *
+ */
+esp_err_t esp_hf_client_query_current_calls(void);
+
+/**
+ *
+ * @brief           Query the name of currently selected network operator in AG(use AT+COPS commands)
+ *                  As a precondition to use this API, Service Level Connection shall exist with AG
+ *
+ * @return
+ *                  - ESP_OK: disconnect request is sent to lower layer
+ *                  - ESP_INVALID_STATE: if bluetooth stack is not yet enabled
+ *                  - ESP_FAIL: others
+ *
+ */
+esp_err_t esp_hf_client_query_current_operator_name(void);
+
+/**
+ *
+ * @brief           Get subscriber information number from AG(send AT+CNUM command)
+ *                  As a precondition to use this API, Service Level Connection shall exist with AG
+ *
+ * @return
+ *                  - ESP_OK: disconnect request is sent to lower layer
+ *                  - ESP_INVALID_STATE: if bluetooth stack is not yet enabled
+ *                  - ESP_FAIL: others
+ *
+ */
+esp_err_t esp_hf_client_retrieve_subscriber_info(void);
+
+/**
+ *
+ * @brief           Transmit DTMF codes during an ongoing call(use AT+VTS commands)
+ *                  As a precondition to use this API, Service Level Connection shall exist with AG
+ *
+ * @param[in]       code: dtmf code, single ascii character in the set 0-9, #, *, A-D
+ *
+ * @return
+ *                  - ESP_OK: disconnect request is sent to lower layer
+ *                  - ESP_INVALID_STATE: if bluetooth stack is not yet enabled
+ *                  - ESP_FAIL: others
+ *
+ */
+esp_err_t esp_hf_client_send_dtmf(char code);
+
+/**
+ *
+ * @brief           Request a phone number from AG corresponding to last voice tag recorded
+ *                  (send AT+BINP command). As a precondition to use this API, Service Level
+ *                  Connection shall exist with AG
+ *
+ * @return
+ *                  - ESP_OK: disconnect request is sent to lower layer
+ *                  - ESP_INVALID_STATE: if bluetooth stack is not yet enabled
+ *                  - ESP_FAIL: others
+ *
+ */
+esp_err_t esp_hf_client_request_last_voice_tag_number(void);
+
+/**
+ * @brief           Register HFP client data output function; the callback is only used in
+ *                  the case that Voice Over HCI is enabled.
+ *
+ * @param[in]       recv: HFP client incoming data callback function
+ * @param[in]       send: HFP client outgoing data callback function
+ *
+ * @return
+ *                  - ESP_OK: success
+ *                  - ESP_INVALID_STATE: if bluetooth stack is not yet enabled
+ *                  - ESP_FAIL: if callback is a NULL function pointer
+ *
+ */
+esp_err_t esp_hf_client_register_data_callback(esp_hf_client_incoming_data_cb_t recv,
+                                               esp_hf_client_outgoing_data_cb_t send);
+
+/**
+ * @brief           Trigger the lower-layer to fetch and send audio data. This function is only
+ *                  only used in the case that Voice Over HCI is enabled. Precondition is that
+ *                  the HFP audio connection is connected. After this function is called, lower
+ *                  layer will invoke esp_hf_client_outgoing_data_cb_t to fetch data
+ *
+ */
+void esp_hf_client_outgoing_data_ready(void);
+
+
+/**
+ * @brief           Initialize the down sampling converter. This is a utility function that can
+ *                  only be used in the case that Voice Over HCI is enabled. 
+ *
+ * @param[in]       src_sps: original samples per second(source audio data, i.e. 48000, 32000,
+ *                  16000, 44100, 22050, 11025)
+ * @param[in]       bits: number of bits per pcm sample (16)
+ * @param[in]       channels: number of channels (i.e. mono(1), stereo(2)...)
+ */
+void esp_hf_client_pcm_resample_init(uint32_t src_sps, uint32_t bits, uint32_t channels);
+
+/**
+ * @brief           Down sampling utility to convert high sampling rate into 8K/16bits 1-channel mode PCM
+ *                  samples. This can only be used in the case that Voice Over HCI is enabled.
+ *
+ * @param[in]       src: pointer to the buffer where the original smapling PCM are stored
+ * @param[in]       in_bytes: length of the input PCM sample buffer in byte
+ * @param[in]       dst: pointer to the buffer which is to be used to store the converted PCM samples
+ *
+ * @return          number of samples converted
+ */
+int32_t esp_hf_client_pcm_resample(void *src, uint32_t in_bytes, void *dst);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* __ESP_HF_CLIENT_API_H__ */
diff --git a/components/bt/bluedroid/api/include/api/esp_hf_defs.h b/components/bt/bluedroid/api/include/api/esp_hf_defs.h
new file mode 100644 (file)
index 0000000..b712779
--- /dev/null
@@ -0,0 +1,181 @@
+// Copyright 2018 Espressif Systems (Shanghai) PTE LTD
+//
+// 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.
+
+#ifndef __ESP_HF_DEFS_H__
+#define __ESP_HF_DEFS_H__
+
+#include "esp_bt_defs.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/// Bluetooth HFP audio volume control target
+typedef enum {
+    ESP_HF_VOLUME_CONTROL_TARGET_SPK = 0,             /*!< speaker */
+    ESP_HF_VOLUME_CONTROL_TARGET_MIC,                 /*!< microphone */
+} esp_hf_volume_control_target_t;
+
+/// +CIND roaming status indicator values
+typedef enum {
+    ESP_HF_ROAMING_STATUS_INACTIVE = 0,               /*!< roaming is not active */
+    ESP_HF_ROAMING_STATUS_ACTIVE,                     /*!< a roaming is active */
+} esp_hf_roaming_status_t;
+
+/// +CIND call status indicator values
+typedef enum {
+    ESP_HF_CALL_STATUS_NO_CALLS = 0,                  /*!< no call in progress  */
+    ESP_HF_CALL_STATUS_CALL_IN_PROGRESS = 1,          /*!< call is present(active or held) */
+} esp_hf_call_status_t;
+
+/// +CIND call setup status indicator values
+typedef enum {
+    ESP_HF_CALL_SETUP_STATUS_NONE = 0,                /*!< no call setup in progress */
+    ESP_HF_CALL_SETUP_STATUS_INCOMING = 1,            /*!< incoming call setup in progress */
+    ESP_HF_CALL_SETUP_STATUS_OUTGOING_DIALING = 2,    /*!< outgoing call setup in dialing state */
+    ESP_HF_CALL_SETUP_STATUS_OUTGOING_ALERTING = 3,   /*!< outgoing call setup in alerting state */
+} esp_hf_call_setup_status_t;
+
+/// +CIND call held indicator values
+typedef enum {
+    ESP_HF_CALL_HELD_STATUS_NONE = 0,                 /*!< no calls held */
+    ESP_HF_CALL_HELD_STATUS_HELD_AND_ACTIVE = 1,      /*!< both active and held call */
+    ESP_HF_CALL_HELD_STATUS_HELD = 2,                 /*!< call on hold, no active call*/
+} esp_hf_call_held_status_t;
+
+/// +CIND network service availability status
+typedef enum {
+    ESP_HF_SERVICE_AVAILABILITY_STATUS_UNAVAILABLE = 0, /*!< service not available */
+    ESP_HF_SERVICE_AVAILABILITY_STATUS_AVAILABLE,       /*!< service available */
+} esp_hf_service_availability_status_t;
+
+/// +CLCC status of the call
+typedef enum {
+    ESP_HF_CURRENT_CALL_STATUS_ACTIVE = 0,            /*!< active */
+    ESP_HF_CURRENT_CALL_STATUS_HELD = 1,              /*!< held */
+    ESP_HF_CURRENT_CALL_STATUS_DIALING = 2,           /*!< dialing (outgoing calls only) */
+    ESP_HF_CURRENT_CALL_STATUS_ALERTING = 3,          /*!< alerting (outgoing calls only) */
+    ESP_HF_CURRENT_CALL_STATUS_INCOMING = 4,          /*!< incoming (incoming calls only) */
+    ESP_HF_CURRENT_CALL_STATUS_WAITING = 5,           /*!< waiting (incoming calls only) */
+    ESP_HF_CURRENT_CALL_STATUS_HELD_BY_RESP_HOLD = 6, /*!< call held by response and hold */
+} esp_hf_current_call_status_t;
+
+/// +CLCC direction of the call
+typedef enum {
+    ESP_HF_CURRENT_CALL_DIRECTION_OUTGOING = 0,       /*!< outgoing */
+    ESP_HF_CURRENT_CALL_DIRECTION_INCOMING = 1,       /*!< incoming */
+} esp_hf_current_call_direction_t;
+
+/// +CLCC multi-party call flag
+typedef enum {
+    ESP_HF_CURRENT_CALL_MPTY_TYPE_SINGLE = 0,         /*!< not a member of a multi-party call */
+    ESP_HF_CURRENT_CALL_MPTY_TYPE_MULTI = 1,          /*!< member of a multi-party call */
+} esp_hf_current_call_mpty_type_t;
+
+/// +CLCC call mode
+typedef enum {
+    ESP_HF_CURRENT_CALL_MODE_VOICE = 0,
+    ESP_HF_CURRENT_CALL_MODE_DATA = 1,
+    ESP_HF_CURRENT_CALL_MODE_FAX = 2,
+} esp_hf_current_call_mode_t;
+
+/// +CLCC address type
+typedef enum {
+    ESP_HF_CALL_ADDR_TYPE_UNKNOWN = 0x81,            /*!< unkown address type */
+    ESP_HF_CALL_ADDR_TYPE_INTERNATIONAL = 0x91,      /*!< international address */
+} esp_hf_call_addr_type_t;
+
+/// +CNUM service type of the phone number
+typedef enum {
+    ESP_HF_SUBSCRIBER_SERVICE_TYPE_UNKNOWN = 0,      /*!< unknown */
+    ESP_HF_SUBSCRIBER_SERVICE_TYPE_VOICE,            /*!< voice service */
+    ESP_HF_SUBSCRIBER_SERVICE_TYPE_FAX,              /*!< fax service */
+} esp_hf_subscriber_service_type_t;
+
+/// +BTRH response and hold result code
+typedef enum {
+    ESP_HF_BTRH_STATUS_HELD = 0,       /*!< incoming call is put on held in AG */
+    ESP_HF_BTRH_STATUS_ACCEPTED,       /*!< held incoming call is accepted in AG */
+    ESP_HF_BTRH_STATUS_REJECTED,       /*!< held incoming call is rejected in AG */
+} esp_hf_btrh_status_t;
+
+/// AT+BTRH response and hold action code
+typedef enum {
+    ESP_HF_BTRH_CMD_HOLD = 0,          /*!< put the incoming call on hold */
+    ESP_HF_BTRH_CMD_ACCEPT = 1,        /*!< accept a held incoming call */
+    ESP_HF_BTRH_CMD_REJECT = 2,        /*!< reject a held incoming call */
+} esp_hf_btrh_cmd_t;
+
+/// response indication codes for AT commands
+typedef enum {
+    ESP_HF_AT_RESPONSE_CODE_OK = 0,         /*!< acknoweledges execution of a command line */
+    ESP_HF_AT_RESPONSE_CODE_ERR,            /*!< command not accepted */
+    ESP_HF_AT_RESPONSE_CODE_NO_CARRIER,     /*!< connection terminated */
+    ESP_HF_AT_RESPONSE_CODE_BUSY,           /*!< busy signal detected */
+    ESP_HF_AT_RESPONSE_CODE_NO_ANSWER,      /*!< connection completion timeout */
+    ESP_HF_AT_RESPONSE_CODE_DELAYED,        /*!< delayed */
+    ESP_HF_AT_RESPONSE_CODE_BLACKLISTED,    /*!< blacklisted */
+    ESP_HF_AT_RESPONSE_CODE_CME,            /*!< CME error */
+} esp_hf_at_response_code_t;
+
+/// voice recognition state
+typedef enum {
+    ESP_HF_VR_STATE_DISABLED = 0,           /*!< voice recognition disabled */
+    ESP_HF_VR_STATE_ENABLED,                /*!< voice recognition enabled */
+} esp_hf_vr_state_t;
+
+/// AT+CHLD command values
+typedef enum {
+    ESP_HF_CHLD_TYPE_REL = 0,               /*!< <0>, Terminate all held or set UDUB("busy") to a waiting call */
+    ESP_HF_CHLD_TYPE_REL_ACC,               /*!< <1>, Terminate all active calls and accepts a waiting/held call */
+    ESP_HF_CHLD_TYPE_HOLD_ACC,              /*!< <2>, Hold all active calls and accepts a waiting/held call */
+    ESP_HF_CHLD_TYPE_MERGE,                 /*!< <3>, Add all held calls to a conference */
+    ESP_HF_CHLD_TYPE_MERGE_DETACH,          /*!< <4>, connect the two calls and disconnects the subscriber from both calls */
+    ESP_HF_CHLD_TYPE_REL_X,                 /*!< <1x>, releases specified calls only */
+    ESP_HF_CHLD_TYPE_PRIV_X,                /*!< <2x>, request private consultation mode with specified call */
+} esp_hf_chld_type_t;
+
+/// Extended Audio Gateway Error Result Code Response
+typedef enum {
+    ESP_HF_CME_AG_FAILURE = 0,                    /*!< ag failure */
+    ESP_HF_CME_NO_CONNECTION_TO_PHONE = 1,        /*!< no connection to phone */
+    ESP_HF_CME_OPERATION_NOT_ALLOWED = 3,         /*!< operation not allowed */
+    ESP_HF_CME_OPERATION_NOT_SUPPORTED = 4,       /*!< operation not supported */
+    ESP_HF_CME_PH_SIM_PIN_REQUIRED = 5,           /*!< PH-SIM PIN Required */
+    ESP_HF_CME_SIM_NOT_INSERTED = 10,             /*!< SIM not inserted */
+    ESP_HF_CME_SIM_PIN_REQUIRED = 11,             /*!< SIM PIN required */
+    ESP_HF_CME_SIM_PUK_REQUIRED = 12,             /*!< SIM PUK required */
+    ESP_HF_CME_SIM_FAILURE = 13,                  /*!< SIM failure */
+    ESP_HF_CME_SIM_BUSY = 14,                     /*!< SIM busy */
+    ESP_HF_CME_INCORRECT_PASSWORD = 16,           /*!< incorrect password */
+    ESP_HF_CME_SIM_PIN2_REQUIRED = 17,            /*!< SIM PIN2 required */
+    ESP_HF_CME_SIM_PUK2_REQUIRED = 18,            /*!< SIM PUK2 required */
+    ESP_HF_CME_MEMEORY_FULL = 20,                 /*!< memory full */
+    ESP_HF_CME_INVALID_INDEX = 21,                /*!< invalid index */
+    ESP_HF_CME_MEMEORY_FAILURE = 23,              /*!< memory failure */
+    ESP_HF_CME_TEXT_STRING_TOO_LONG = 24,         /*!< test string too long */
+    ESP_HF_CME_INVALID_CHARACTERS_IN_TEXT_STRING = 25,  /*!< invalid characters in text string */
+    ESP_HF_CME_DIAL_STRING_TOO_LONG = 26,         /*!< dial string too long*/
+    ESP_HF_CME_INVALID_CHARACTERS_IN_DIAL_STRING = 27,  /*!< invalid characters in dial string */
+    ESP_HF_CME_NO_NETWORK_SERVICE = 30,           /*!< no network service */
+    ESP_HF_CME_NETWORK_TIMEOUT = 31,              /*!< network timeout */
+    ESP_HF_CME_NETWORK_NOT_ALLOWED = 32,          /*!< network not allowed --emergency calls only */
+} esp_hf_cme_err_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __ESP_HF_DEFS_H__ */
index 3985dc839df22034f685870186679763f25cd1fa..c2eff109a783327ac82fe3a8e33d008769bc130f 100644 (file)
@@ -396,9 +396,7 @@ static void bta_dm_sys_hw_cback( tBTA_SYS_HW_EVT status )
 #endif
         /* hw is ready, go on with BTA DM initialization */
         memset(&bta_dm_search_cb, 0x00, sizeof(bta_dm_search_cb));
-#if (BTM_SSR_INCLUDED == TRUE)
         memset(&bta_dm_conn_srvcs, 0x00, sizeof(bta_dm_conn_srvcs));
-#endif  ///BTM_SSR_INCLUDED == TRUE
         memset(&bta_dm_di_cb, 0, sizeof(tBTA_DM_DI_CB));
 
         memcpy(dev_class, p_bta_dm_cfg->dev_class, sizeof(dev_class));
@@ -443,10 +441,12 @@ static void bta_dm_sys_hw_cback( tBTA_SYS_HW_EVT status )
         BTM_ReadLocalDeviceNameFromController((tBTM_CMPL_CB *)bta_dm_local_name_cback);
 
         bta_sys_rm_register((tBTA_SYS_CONN_CBACK *)bta_dm_rm_cback);
-#if (BTM_SSR_INCLUDED == TRUE)
+
+#if (BTA_DM_PM_INCLUDED == TRUE)
         /* initialize bluetooth low power manager */
         bta_dm_init_pm();
-#endif  ///BTM_SSR_INCLUDED == TRUE
+#endif /* #if (BTA_DM_PM_INCLUDED == TRUE) */
+
         bta_sys_policy_register((tBTA_SYS_CONN_CBACK *)bta_dm_policy_cback);
 
 #if (BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE && SDP_INCLUDED == TRUE) && (GATTC_INCLUDED == TRUE)
@@ -483,9 +483,11 @@ void bta_dm_disable (tBTA_DM_MSG *p_data)
 
     BTM_SetDiscoverability(BTM_NON_DISCOVERABLE, 0, 0);
     BTM_SetConnectability(BTM_NON_CONNECTABLE, 0, 0);
-#if (BTM_SSR_INCLUDED == TRUE)
+
+#if (BTA_DM_PM_INCLUDED == TRUE)
     bta_dm_disable_pm();
-#endif  ///BTM_SSR_INCLUDED == TRUE
+#endif /* #if (BTA_DM_PM_INCLUDED == TRUE) */
+
     bta_dm_disable_search_and_disc();
     bta_dm_cb.disabling = TRUE;
 
@@ -1070,12 +1072,12 @@ static void bta_dm_policy_cback(tBTA_SYS_CONN_STATUS status, UINT8 id, UINT8 app
         p_dev->link_policy &= (~policy);
         BTM_SetLinkPolicy(p_dev->peer_bdaddr, &(p_dev->link_policy));
 
+#if (BTA_DM_PM_INCLUDED == TRUE)
         if (policy & (HCI_ENABLE_SNIFF_MODE | HCI_ENABLE_PARK_MODE)) {
             /* if clearing sniff/park, wake the link */
-#if (BTM_SSR_INCLUDED == TRUE)
             bta_dm_pm_active(p_dev->peer_bdaddr);
-#endif  ///BTM_SSR_INCLUDED == TRUE
         }
+#endif /* #if (BTA_DM_PM_INCLUDED == TRUE) */
         break;
 
     case BTA_SYS_PLCY_DEF_SET:
@@ -3365,10 +3367,12 @@ static void bta_dm_disable_conn_down_timer_cback (TIMER_LIST_ENT *p_tle)
 {
     UNUSED(p_tle);
     tBTA_SYS_HW_MSG *sys_enable_event;
-#if (BTM_SSR_INCLUDED == TRUE)
+
+#if (BTA_DM_PM_INCLUDED == TRUE)
     /* disable the power managment module */
     bta_dm_disable_pm();
-#endif  ///BTM_SSR_INCLUDED == TRUE
+#endif /* #if (BTA_DM_PM_INCLUDED == TRUE) */
+
     /* register our callback to SYS HW manager */
     bta_sys_hw_register( BTA_SYS_HW_BLUETOOTH, bta_dm_sys_hw_cback );
 
@@ -3431,9 +3435,7 @@ static void bta_dm_rm_cback(tBTA_SYS_CONN_STATUS status, UINT8 id, UINT8 app_id,
             }
             /* AV calls bta_sys_conn_open with the A2DP stream count as app_id */
             if (BTA_ID_AV == id) {
-#if (BTM_SSR_INCLUDED == TRUE)
                 bta_dm_cb.cur_av_count = bta_dm_get_av_count();
-#endif  ///BTM_SSR_INCLUDED == TRUE
             }
         } else if ( status == BTA_SYS_CONN_IDLE) {
             if (p_dev) {
@@ -3442,9 +3444,7 @@ static void bta_dm_rm_cback(tBTA_SYS_CONN_STATUS status, UINT8 id, UINT8 app_id,
 
             /* get cur_av_count from connected services */
             if (BTA_ID_AV == id) {
-#if (BTM_SSR_INCLUDED == TRUE)
                 bta_dm_cb.cur_av_count = bta_dm_get_av_count();
-#endif  ///BTM_SSR_INCLUDED == TRUE
             }
         }
         APPL_TRACE_EVENT("bta_dm_rm_cback:%d, status:%d", bta_dm_cb.cur_av_count, status);
index 2e22aa77c5c280f28b92726720e768a88d202370..c29960ab68df65d94e5c4181f6bd9eb2a40a55e6 100644 (file)
@@ -116,39 +116,24 @@ tBTA_DM_CFG *p_bta_dm_cfg = (tBTA_DM_CFG *) &bta_dm_cfg;
 tBTA_DM_RM *p_bta_dm_rm_cfg = (tBTA_DM_RM *) &bta_dm_rm_cfg;
 
 #if BLE_INCLUDED == TRUE
-#  define BTA_DM_NUM_PM_ENTRY         21  /* number of entries in bta_dm_pm_cfg except the first */
-#  define BTA_DM_NUM_PM_SPEC          15  /* number of entries in bta_dm_pm_spec */
+#  define BTA_DM_NUM_PM_ENTRY         6  /* number of entries in bta_dm_pm_cfg except the first */
+#  define BTA_DM_NUM_PM_SPEC          6  /* number of entries in bta_dm_pm_spec */
 #else
-#  define BTA_DM_NUM_PM_ENTRY         19  /* number of entries in bta_dm_pm_cfg except the first */
-#  define BTA_DM_NUM_PM_SPEC          13  /* number of entries in bta_dm_pm_spec */
+#  define BTA_DM_NUM_PM_ENTRY         4  /* number of entries in bta_dm_pm_cfg except the first */
+#  define BTA_DM_NUM_PM_SPEC          4  /* number of entries in bta_dm_pm_spec */
 #endif
 
+#if (BTA_DM_PM_INCLUDED == TRUE)
+
 tBTA_DM_PM_TYPE_QUALIFIER tBTA_DM_PM_CFG bta_dm_pm_cfg[BTA_DM_NUM_PM_ENTRY + 1] = {
     {BTA_ID_SYS, BTA_DM_NUM_PM_ENTRY, 0},  /* reserved: specifies length of this table. */
     {BTA_ID_AG,  BTA_ALL_APP_ID,      0},  /* ag uses first spec table for app id 0 */
-    {BTA_ID_CT,  1,                   1},  /* ct (BTA_ID_CT,APP ID=1) spec table */
-    {BTA_ID_CG,  BTA_ALL_APP_ID,      1},  /* cg resue ct spec table */
-    {BTA_ID_DG,  BTA_ALL_APP_ID,      2},  /* dg spec table */
-    {BTA_ID_AV,  BTA_ALL_APP_ID,      4},  /* av spec table */
-    {BTA_ID_AVK, BTA_ALL_APP_ID,     12},  /* avk spec table */
-    {BTA_ID_FTC, BTA_ALL_APP_ID,      6},  /* ftc spec table */
-    {BTA_ID_FTS, BTA_ALL_APP_ID,      7},  /* fts spec table */
-    {BTA_ID_HD,  BTA_ALL_APP_ID,      3},  /* hd spec table */
-    {BTA_ID_HH,  BTA_ALL_APP_ID,      5},  /* hh spec table */
-    {BTA_ID_PBC, BTA_ALL_APP_ID,      2},  /* reuse dg spec table */
-    {BTA_ID_PBS, BTA_ALL_APP_ID,      7},  /* reuse fts spec table */
-    {BTA_ID_OPC, BTA_ALL_APP_ID,      6},  /* reuse ftc spec table */
-    {BTA_ID_OPS, BTA_ALL_APP_ID,      7},  /* reuse fts spec table */
-    {BTA_ID_MSE, BTA_ALL_APP_ID,      7},  /* reuse fts spec table */
-    // {BTA_ID_JV,  BTA_JV_PM_ID_1,      6},  /* app BTA_JV_PM_ID_1, reuse ftc spec table */
-    // {BTA_ID_JV,  BTA_ALL_APP_ID,      7},  /* reuse fts spec table */
-    {BTA_ID_HL,  BTA_ALL_APP_ID,      8},  /* reuse fts spec table */
-    {BTA_ID_PAN, BTUI_PAN_ID_PANU,    9},  /* PANU spec table */
-    {BTA_ID_PAN, BTUI_PAN_ID_NAP,    10},  /* NAP spec table */
-    {BTA_ID_HS,  BTA_ALL_APP_ID,     11}   /* HS spec table */
+    {BTA_ID_AV,  BTA_ALL_APP_ID,      1},  /* av spec table */
+    {BTA_ID_HS,  BTA_ALL_APP_ID,      2},  /* HS spec table */
+    {BTA_ID_AVK, BTA_ALL_APP_ID,      3}   /* avk spec table */
 #if BLE_INCLUDED == TRUE
-    , {BTA_ID_GATTC,  BTA_ALL_APP_ID,  13} /* gattc spec table */
-    , {BTA_ID_GATTS,  BTA_ALL_APP_ID,  14} /* gatts spec table */
+    , {BTA_ID_GATTC,  BTA_ALL_APP_ID,   4} /* gattc spec table */
+    , {BTA_ID_GATTS,  BTA_ALL_APP_ID,   5} /* gatts spec table */
 #endif
 };
 
@@ -173,64 +158,7 @@ tBTA_DM_PM_TYPE_QUALIFIER tBTA_DM_PM_SPEC bta_dm_pm_spec[BTA_DM_NUM_PM_SPEC] = {
         }
     },
 
-    /* CT, CG : 1 */
-    {
-        (BTA_DM_PM_SNIFF | BTA_DM_PM_PARK),                           /* allow park & sniff */
-#if (BTM_SSR_INCLUDED == TRUE)
-        (BTA_DM_PM_SSR2),                                              /* the SSR entry */
-#endif
-        {
-            {{BTA_DM_PM_PARK,   5000 + BTA_DM_PM_SPEC_TO_OFFSET},  {BTA_DM_PM_NO_ACTION, 0}},    /* conn open  park */
-            {{BTA_DM_PM_NO_PREF,   0},  {BTA_DM_PM_NO_ACTION, 0}},    /* conn close  */
-            {{BTA_DM_PM_NO_ACTION, 0},  {BTA_DM_PM_NO_ACTION, 0}},    /* app open */
-            {{BTA_DM_PM_NO_ACTION, 0},  {BTA_DM_PM_NO_ACTION, 0}},    /* app close */
-            {{BTA_DM_PM_SNIFF_A2DP_IDX, 5000 + BTA_DM_PM_SPEC_TO_OFFSET}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco open sniff */
-            {{BTA_DM_PM_PARK,   5000 + BTA_DM_PM_SPEC_TO_OFFSET},  {BTA_DM_PM_NO_ACTION, 0}},    /* sco close  park */
-            {{BTA_DM_PM_NO_ACTION, 0},  {BTA_DM_PM_NO_ACTION, 0}},    /* idle */
-            {{BTA_DM_PM_NO_ACTION, 0},  {BTA_DM_PM_NO_ACTION, 0}},    /* busy */
-            {{BTA_DM_PM_RETRY,  5000 + BTA_DM_PM_SPEC_TO_OFFSET},  {BTA_DM_PM_NO_ACTION, 0}}     /* mode change retry */
-        }
-    },
-
-    /* DG, PBC : 2 */
-    {
-        (BTA_DM_PM_ACTIVE),                                             /* no power saving mode allowed */
-#if (BTM_SSR_INCLUDED == TRUE)
-        (BTA_DM_PM_SSR2),                                              /* the SSR entry */
-#endif
-        {
-            {{BTA_DM_PM_SNIFF,  5000 + BTA_DM_PM_SPEC_TO_OFFSET},   {BTA_DM_PM_NO_ACTION, 0}},    /* conn open active */
-            {{BTA_DM_PM_NO_PREF,   0},   {BTA_DM_PM_NO_ACTION, 0}},    /* conn close  */
-            {{BTA_DM_PM_ACTIVE,    0},   {BTA_DM_PM_NO_ACTION, 0}},    /* app open */
-            {{BTA_DM_PM_NO_ACTION, 0},   {BTA_DM_PM_NO_ACTION, 0}},    /* app close */
-            {{BTA_DM_PM_NO_ACTION, 0},   {BTA_DM_PM_NO_ACTION, 0}},    /* sco open  */
-            {{BTA_DM_PM_NO_ACTION, 0},   {BTA_DM_PM_NO_ACTION, 0}},    /* sco close   */
-            {{BTA_DM_PM_SNIFF,  1000 + BTA_DM_PM_SPEC_TO_OFFSET},   {BTA_DM_PM_NO_ACTION, 0}},    /* idle */
-            {{BTA_DM_PM_ACTIVE,    0},   {BTA_DM_PM_NO_ACTION, 0}},    /* busy */
-            {{BTA_DM_PM_NO_ACTION, 0},   {BTA_DM_PM_NO_ACTION, 0}}     /* mode change retry */
-        }
-    },
-
-    /* HD : 3 */
-    {
-        (BTA_DM_PM_SNIFF | BTA_DM_PM_PARK),                            /* allow park & sniff */
-#if (BTM_SSR_INCLUDED == TRUE)
-        (BTA_DM_PM_SSR3),                                              /* the SSR entry */
-#endif
-        {
-            {{BTA_DM_PM_SNIFF_HD_ACTIVE_IDX, 5000 + BTA_DM_PM_SPEC_TO_OFFSET}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn open sniff */
-            {{BTA_DM_PM_NO_PREF,   0},   {BTA_DM_PM_NO_ACTION, 0}},    /* conn close */
-            {{BTA_DM_PM_NO_ACTION, 0},   {BTA_DM_PM_NO_ACTION, 0}},    /* app open */
-            {{BTA_DM_PM_NO_ACTION, 0},   {BTA_DM_PM_NO_ACTION, 0}},    /* app close */
-            {{BTA_DM_PM_NO_ACTION, 0},   {BTA_DM_PM_NO_ACTION, 0}},    /* sco open  */
-            {{BTA_DM_PM_NO_ACTION, 0},   {BTA_DM_PM_NO_ACTION, 0}},    /* sco close */
-            {{BTA_DM_PM_SNIFF_HD_IDLE_IDX, 5000 + BTA_DM_PM_SPEC_TO_OFFSET}, {BTA_DM_PM_NO_ACTION, 0}},   /* idle */
-            {{BTA_DM_PM_SNIFF_HD_ACTIVE_IDX, 0}, {BTA_DM_PM_NO_ACTION, 0}},    /* busy */
-            {{BTA_DM_PM_NO_ACTION, 0},   {BTA_DM_PM_NO_ACTION, 0}}     /* mode change retry */
-        }
-    },
-
-    /* AV : 4 */
+    /* AV : 1 */
     {
         (BTA_DM_PM_SNIFF),                                             /* allow sniff */
 #if (BTM_SSR_INCLUDED == TRUE)
@@ -249,122 +177,7 @@ tBTA_DM_PM_TYPE_QUALIFIER tBTA_DM_PM_SPEC bta_dm_pm_spec[BTA_DM_NUM_PM_SPEC] = {
         }
     },
 
-    /* HH : 5 */
-    {
-        (BTA_DM_PM_SNIFF | BTA_DM_PM_PARK),                            /* allow park & sniff */
-#if (BTM_SSR_INCLUDED == TRUE)
-        (BTA_DM_PM_SSR1),                                              /* the SSR entry */
-#endif
-        {
-            {{BTA_DM_PM_SNIFF_HH_OPEN_IDX, BTA_DM_PM_HH_OPEN_DELAY + BTA_DM_PM_SPEC_TO_OFFSET}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn open  sniff */
-            {{BTA_DM_PM_NO_PREF,   0},   {BTA_DM_PM_NO_ACTION, 0}},    /* conn close  */
-            {{BTA_DM_PM_NO_ACTION, 0},   {BTA_DM_PM_NO_ACTION, 0}},    /* app open */
-            {{BTA_DM_PM_NO_ACTION, 0},   {BTA_DM_PM_NO_ACTION, 0}},    /* app close */
-            {{BTA_DM_PM_NO_ACTION, 0},   {BTA_DM_PM_NO_ACTION, 0}},    /* sco open  */
-            {{BTA_DM_PM_NO_ACTION, 0},   {BTA_DM_PM_NO_ACTION, 0}},    /* sco close, used for HH suspend   */
-            {{BTA_DM_PM_SNIFF_HH_IDLE_IDX, BTA_DM_PM_HH_IDLE_DELAY + BTA_DM_PM_SPEC_TO_OFFSET},   {BTA_DM_PM_NO_ACTION, 0}},    /* idle */
-            {{BTA_DM_PM_SNIFF_HH_ACTIVE_IDX, BTA_DM_PM_HH_ACTIVE_DELAY + BTA_DM_PM_SPEC_TO_OFFSET},   {BTA_DM_PM_NO_ACTION, 0}},    /* busy */
-            {{BTA_DM_PM_NO_ACTION, 0},   {BTA_DM_PM_NO_ACTION, 0}}     /* mode change retry */
-        }
-    },
-
-    /* FTC, OPC, JV : 6 */
-    {
-        (BTA_DM_PM_SNIFF),                                             /* allow sniff */
-#if (BTM_SSR_INCLUDED == TRUE)
-        (BTA_DM_PM_SSR2),                                              /* the SSR entry */
-#endif
-        {
-            {{BTA_DM_PM_ACTIVE,    0},   {BTA_DM_PM_NO_ACTION, 0}},    /* conn open  active */
-            {{BTA_DM_PM_NO_PREF,   0},   {BTA_DM_PM_NO_ACTION, 0}},    /* conn close  */
-            {{BTA_DM_PM_ACTIVE,    0},   {BTA_DM_PM_NO_ACTION, 0}},    /* app open */
-            {{BTA_DM_PM_NO_ACTION, 0},   {BTA_DM_PM_NO_ACTION, 0}},    /* app close */
-            {{BTA_DM_PM_NO_ACTION, 0},   {BTA_DM_PM_NO_ACTION, 0}},    /* sco open  */
-            {{BTA_DM_PM_NO_ACTION, 0},   {BTA_DM_PM_NO_ACTION, 0}},    /* sco close   */
-            {{BTA_DM_PM_SNIFF_A2DP_IDX, 5000 + BTA_DM_PM_SPEC_TO_OFFSET},   {BTA_DM_PM_NO_ACTION, 0}},    /* idle */
-            {{BTA_DM_PM_ACTIVE,    0},   {BTA_DM_PM_NO_ACTION, 0}},    /* busy */
-            {{BTA_DM_PM_NO_ACTION, 0},   {BTA_DM_PM_NO_ACTION, 0}}     /* mode change retry */
-        }
-    },
-
-    /* FTS, PBS, OPS, MSE, BTA_JV_PM_ID_1 : 7 */
-    {
-        (BTA_DM_PM_SNIFF),                                             /* allow sniff */
-#if (BTM_SSR_INCLUDED == TRUE)
-        (BTA_DM_PM_SSR2),                                              /* the SSR entry */
-#endif
-        {
-            {{BTA_DM_PM_ACTIVE,    0},   {BTA_DM_PM_NO_ACTION, 0}},    /* conn open  active */
-            {{BTA_DM_PM_NO_PREF,   0},   {BTA_DM_PM_NO_ACTION, 0}},    /* conn close  */
-            {{BTA_DM_PM_ACTIVE,    0},   {BTA_DM_PM_NO_ACTION, 0}},    /* app open */
-            {{BTA_DM_PM_NO_ACTION, 0},   {BTA_DM_PM_NO_ACTION, 0}},    /* app close */
-            {{BTA_DM_PM_NO_ACTION, 0},   {BTA_DM_PM_NO_ACTION, 0}},    /* sco open  */
-            {{BTA_DM_PM_NO_ACTION, 0},   {BTA_DM_PM_NO_ACTION, 0}},    /* sco close   */
-            {{BTA_DM_PM_SNIFF_A2DP_IDX, BTA_FTS_OPS_IDLE_TO_SNIFF_DELAY_MS + BTA_DM_PM_SPEC_TO_OFFSET}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */
-            {{BTA_DM_PM_ACTIVE,    0},   {BTA_DM_PM_NO_ACTION, 0}},    /* busy */
-            {{BTA_DM_PM_NO_ACTION, 0},   {BTA_DM_PM_NO_ACTION, 0}}     /* mode change retry */
-        }
-    },
-
-    /* HL : 8 */
-    {
-        (BTA_DM_PM_SNIFF),                                             /* allow sniff */
-#if (BTM_SSR_INCLUDED == TRUE)
-        (BTA_DM_PM_SSR2),                                              /* the SSR entry */
-#endif
-        {
-            {{BTA_DM_PM_SNIFF_A2DP_IDX, 5000 + BTA_DM_PM_SPEC_TO_OFFSET}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn open sniff  */
-            {{BTA_DM_PM_NO_PREF,   0},   {BTA_DM_PM_NO_ACTION, 0}},   /* conn close  */
-            {{BTA_DM_PM_NO_ACTION, 0},   {BTA_DM_PM_NO_ACTION, 0}},   /* app open */
-            {{BTA_DM_PM_NO_ACTION, 0},   {BTA_DM_PM_NO_ACTION, 0}},   /* app close */
-            {{BTA_DM_PM_NO_ACTION, 0},   {BTA_DM_PM_NO_ACTION, 0}},   /* sco open, active */
-            {{BTA_DM_PM_NO_ACTION, 0},   {BTA_DM_PM_NO_ACTION, 0}},   /* sco close sniff  */
-            {{BTA_DM_PM_NO_ACTION, 0},   {BTA_DM_PM_NO_ACTION, 0}},   /* idle */
-            {{BTA_DM_PM_ACTIVE,    0},   {BTA_DM_PM_NO_ACTION, 0}},   /* busy */
-            {{BTA_DM_PM_NO_ACTION, 0},   {BTA_DM_PM_NO_ACTION, 0}}    /* mode change retry */
-        }
-    },
-
-    /* PANU : 9 */
-    {
-        (BTA_DM_PM_SNIFF),                                             /* allow sniff */
-#if (BTM_SSR_INCLUDED == TRUE)
-        (BTA_DM_PM_SSR2),                                              /* the SSR entry */
-#endif
-        {
-            {{BTA_DM_PM_ACTIVE,    0},   {BTA_DM_PM_NO_ACTION, 0}},    /* conn open  active */
-            {{BTA_DM_PM_NO_PREF,   0},   {BTA_DM_PM_NO_ACTION, 0}},    /* conn close  */
-            {{BTA_DM_PM_ACTIVE,    0},   {BTA_DM_PM_NO_ACTION, 0}},    /* app open */
-            {{BTA_DM_PM_NO_ACTION, 0},   {BTA_DM_PM_NO_ACTION, 0}},    /* app close */
-            {{BTA_DM_PM_NO_ACTION, 0},   {BTA_DM_PM_NO_ACTION, 0}},    /* sco open  */
-            {{BTA_DM_PM_NO_ACTION, 0},   {BTA_DM_PM_NO_ACTION, 0}},    /* sco close   */
-            {{BTA_DM_PM_SNIFF_A2DP_IDX, 5000 + BTA_DM_PM_SPEC_TO_OFFSET},   {BTA_DM_PM_NO_ACTION, 0}},    /* idle */
-            {{BTA_DM_PM_ACTIVE,    0},   {BTA_DM_PM_NO_ACTION, 0}},    /* busy */
-            {{BTA_DM_PM_NO_ACTION, 0},   {BTA_DM_PM_NO_ACTION, 0}}     /* mode change retry */
-        }
-    },
-
-    /* NAP : 10 */
-    {
-        (BTA_DM_PM_SNIFF),                                             /* allow sniff */
-#if (BTM_SSR_INCLUDED == TRUE)
-        (BTA_DM_PM_SSR2),                                              /* the SSR entry */
-#endif
-        {
-            {{BTA_DM_PM_ACTIVE,    0},   {BTA_DM_PM_NO_ACTION, 0}},    /* conn open  active */
-            {{BTA_DM_PM_NO_PREF,   0},   {BTA_DM_PM_NO_ACTION, 0}},    /* conn close  */
-            {{BTA_DM_PM_ACTIVE,    0},   {BTA_DM_PM_NO_ACTION, 0}},    /* app open */
-            {{BTA_DM_PM_NO_ACTION, 0},   {BTA_DM_PM_NO_ACTION, 0}},    /* app close */
-            {{BTA_DM_PM_NO_ACTION, 0},   {BTA_DM_PM_NO_ACTION, 0}},    /* sco open  */
-            {{BTA_DM_PM_NO_ACTION, 0},   {BTA_DM_PM_NO_ACTION, 0}},    /* sco close   */
-            {{BTA_DM_PM_SNIFF_A2DP_IDX, 5000 + BTA_DM_PM_SPEC_TO_OFFSET},   {BTA_DM_PM_NO_ACTION, 0}},    /* idle */
-            {{BTA_DM_PM_ACTIVE,    0},   {BTA_DM_PM_NO_ACTION, 0}},   /* busy */
-
-            {{BTA_DM_PM_NO_ACTION, 0},   {BTA_DM_PM_NO_ACTION, 0}}     /* mode change retry */
-        }
-    },
-
-    /* HS : 11 */
+    /* HS : 2 */
     {
         (BTA_DM_PM_SNIFF | BTA_DM_PM_PARK),                           /* allow park & sniff */
 #if (BTM_SSR_INCLUDED == TRUE)
@@ -383,7 +196,7 @@ tBTA_DM_PM_TYPE_QUALIFIER tBTA_DM_PM_SPEC bta_dm_pm_spec[BTA_DM_NUM_PM_SPEC] = {
         }
     },
 
-    /* AVK : 12 */
+    /* AVK : 3 */
     {
         (BTA_DM_PM_SNIFF),                                             /* allow sniff */
 #if (BTM_SSR_INCLUDED == TRUE)
@@ -403,7 +216,7 @@ tBTA_DM_PM_TYPE_QUALIFIER tBTA_DM_PM_SPEC bta_dm_pm_spec[BTA_DM_NUM_PM_SPEC] = {
     }
 
 #if BLE_INCLUDED == TRUE
-    /* GATTC : 13 */
+    /* GATTC : 4 */
     , {
         (BTA_DM_PM_SNIFF | BTA_DM_PM_PARK),                           /* allow park & sniff */
 #if (BTM_SSR_INCLUDED == TRUE)
@@ -424,7 +237,7 @@ tBTA_DM_PM_TYPE_QUALIFIER tBTA_DM_PM_SPEC bta_dm_pm_spec[BTA_DM_NUM_PM_SPEC] = {
             {{BTA_DM_PM_RETRY,   5000 + BTA_DM_PM_SPEC_TO_OFFSET},   {BTA_DM_PM_NO_ACTION, 0}}    /* mode change retry */
         }
     }
-    /* GATTS : 14 */
+    /* GATTS : 5 */
     , {
         (BTA_DM_PM_SNIFF | BTA_DM_PM_PARK),                           /* allow park & sniff */
 #if (BTM_SSR_INCLUDED == TRUE)
@@ -528,6 +341,8 @@ tBTA_DM_PM_CFG *p_bta_dm_pm_cfg = (tBTA_DM_PM_CFG *) &bta_dm_pm_cfg;
 tBTA_DM_PM_SPEC *p_bta_dm_pm_spec = (tBTA_DM_PM_SPEC *) &bta_dm_pm_spec;
 tBTM_PM_PWR_MD *p_bta_dm_pm_md = (tBTM_PM_PWR_MD *) &bta_dm_pm_md;
 
+#endif /* #if (BTA_DM_PM_INCLUDED == TRUE) */
+
 /* The performance impact of EIR packet size
 **
 ** When BTM_EIR_DEFAULT_FEC_REQUIRED is TRUE,
index e7385013c5112fc877b17aab934c60bf428bf89b..f10787ad0362f1bfd1374e93bf32219eb656d95d 100644 (file)
@@ -83,32 +83,3 @@ void bta_dm_ci_rmt_oob(BOOLEAN accept, BD_ADDR bd_addr, BT_OCTET16 c, BT_OCTET16
     }
 }
 #endif /* BTM_OOB_INCLUDED */
-
-#if (BTM_SCO_HCI_INCLUDED == TRUE)
-/*******************************************************************************
-**
-** Function         bta_dm_sco_ci_data_ready
-**
-** Description      This function sends an event to indicating that the phone
-**                  has SCO data ready.
-**
-** Parameters       event: is obtained from bta_dm_sco_co_open() function, which
-**                          is the BTA event we want to send back to BTA module
-**                          when there is encoded data ready.
-**                  sco_handle: is the BTA sco handle which indicate a specific
-**                           SCO connection.
-** Returns          void
-**
-*******************************************************************************/
-void bta_dm_sco_ci_data_ready(UINT16 event, UINT16 sco_handle)
-{
-    BT_HDR  *p_buf;
-
-    if ((p_buf = (BT_HDR *) osi_malloc(sizeof(BT_HDR))) != NULL) {
-        p_buf->event = event;
-        p_buf->layer_specific = sco_handle;
-
-        bta_sys_sendmsg(p_buf);
-    }
-}
-#endif
index 9b0b89b3a45792afa29d6d1f8bc3d53be05a63b5..dbfabc3b7a74f256ae8d8f835cfe378464b15809 100644 (file)
@@ -205,149 +205,6 @@ void bta_dm_co_rmt_oob(BD_ADDR bd_addr)
 
 // REMOVE FOR BLUEDROID ?
 
-#if (BTM_SCO_HCI_INCLUDED == TRUE ) && (BTM_SCO_INCLUDED == TRUE)
-#if (defined(BTIF_INCLUDED) && BTIF_INCLUDED == TRUE)
-/*******************************************************************************
-**
-** Function         btui_sco_codec_callback
-**
-** Description      Callback for btui codec.
-**
-**
-** Returns          void
-**
-*******************************************************************************/
-static void btui_sco_codec_callback(UINT16 event, UINT16 sco_handle)
-{
-    bta_dm_sco_ci_data_ready(event, sco_handle);
-}
-/*******************************************************************************
-**
-** Function         bta_dm_sco_co_init
-**
-** Description      This function can be used by the phone to initialize audio
-**                  codec or for other initialization purposes before SCO connection
-**                  is opened.
-**
-**
-** Returns          tBTA_DM_SCO_ROUTE_TYPE: SCO routing configuration type.
-**
-*******************************************************************************/
-tBTA_DM_SCO_ROUTE_TYPE bta_dm_sco_co_init(UINT32 rx_bw, UINT32 tx_bw,
-        tBTA_CODEC_INFO *p_codec_type, UINT8 app_id)
-{
-    tBTM_SCO_ROUTE_TYPE route = BTA_DM_SCO_ROUTE_PCM;
-
-    BTIF_TRACE_DEBUG("bta_dm_sco_co_init");
-
-    /* set up SCO routing configuration if SCO over HCI app ID is used and run time
-        configuration is set to SCO over HCI */
-    /* HS invoke this call-out */
-    if (
-#if (BTA_HS_INCLUDED == TRUE ) && (BTA_HS_INCLUDED == TRUE)
-        (app_id == BTUI_DM_SCO_4_HS_APP_ID && btui_cfg.hs_sco_over_hci) ||
-#endif
-        /* AG invoke this call-out */
-        (app_id != BTUI_DM_SCO_4_HS_APP_ID && btui_cfg.ag_sco_over_hci )) {
-        route = btui_cb.sco_hci = BTA_DM_SCO_ROUTE_HCI;
-    }
-    /* no codec is is used for the SCO data */
-    if (p_codec_type->codec_type == BTA_SCO_CODEC_PCM && route == BTA_DM_SCO_ROUTE_HCI) {
-        /* initialize SCO codec */
-        if (!btui_sco_codec_init(rx_bw, tx_bw)) {
-            BTIF_TRACE_ERROR("codec initialization exception!");
-        }
-    }
-
-    return route;
-}
-
-
-
-/*******************************************************************************
-**
-** Function         bta_dm_sco_co_open
-**
-** Description      This function is executed when a SCO connection is open.
-**
-**
-** Returns          void
-**
-*******************************************************************************/
-void bta_dm_sco_co_open(UINT16 handle, UINT8 pkt_size, UINT16 event)
-{
-    tBTUI_SCO_CODEC_CFG cfg;
-
-    if (btui_cb.sco_hci) {
-        BTIF_TRACE_DEBUG("bta_dm_sco_co_open handle:%d pkt_size:%d", handle, pkt_size);
-        /* use dedicated SCO buffer pool for SCO TX data */
-        cfg.pool_id = HCI_SCO_POOL_ID;
-        cfg.p_cback = btui_sco_codec_callback;
-        cfg.pkt_size = pkt_size;
-        cfg.cb_event = event;
-        /* open and start the codec */
-        btui_sco_codec_open(&cfg);
-        btui_sco_codec_start(handle);
-    }
-}
-
-/*******************************************************************************
-**
-** Function         bta_dm_sco_co_close
-**
-** Description      This function is called when a SCO connection is closed
-**
-**
-** Returns          void
-**
-*******************************************************************************/
-void bta_dm_sco_co_close(void)
-{
-    if (btui_cb.sco_hci) {
-        BTIF_TRACE_DEBUG("bta_dm_sco_co_close close codec");
-        /* close sco codec */
-        btui_sco_codec_close();
-
-        btui_cb.sco_hci = FALSE;
-    }
-}
-
-/*******************************************************************************
-**
-** Function         bta_dm_sco_co_in_data
-**
-** Description      This function is called to send incoming SCO data to application.
-**
-** Returns          void
-**
-*******************************************************************************/
-void bta_dm_sco_co_in_data(BT_HDR  *p_buf)
-{
-    if (btui_cfg.sco_use_mic) {
-        btui_sco_codec_inqdata (p_buf);
-    } else {
-        osi_free(p_buf);
-    }
-}
-
-/*******************************************************************************
-**
-** Function         bta_dm_sco_co_out_data
-**
-** Description      This function is called to send SCO data over HCI.
-**
-** Returns          void
-**
-*******************************************************************************/
-void bta_dm_sco_co_out_data(BT_HDR  **p_buf)
-{
-    btui_sco_codec_readbuf(p_buf);
-}
-
-#endif /* #if (defined(BTIF_INCLUDED) && BTIF_INCLUDED == TRUE) */
-#endif /* #if (BTM_SCO_HCI_INCLUDED == TRUE ) && (BTM_SCO_INCLUDED == TRUE)*/
-
-
 #if (defined BLE_INCLUDED && BLE_INCLUDED == TRUE)
 /*******************************************************************************
 **
index 75d5ad44c68b543414f176312b2d232b5b91fbfa..25977e7a4911d1becafd6128ab09f61e6c94c4f4 100644 (file)
@@ -66,11 +66,11 @@ const tBTA_DM_ACTION bta_dm_action[BTA_DM_MAX_EVT] = {
     bta_dm_bond_cancel,                     /* 12  BTA_DM_API_BOND_CANCEL_EVT */
     bta_dm_pin_reply,                       /* 13 BTA_DM_API_PIN_REPLY_EVT */
 #endif  ///SMP_INCLUDED == TRUE
-#if (BTM_SSR_INCLUDED == TRUE)
+#if (BTA_DM_PM_INCLUDED == TRUE)
     /* power manger events */
     bta_dm_pm_btm_status,                   /* 16 BTA_DM_PM_BTM_STATUS_EVT */
     bta_dm_pm_timer,                        /* 17 BTA_DM_PM_TIMER_EVT*/
-#endif  ///BTM_SSR_INCLUDED == TRUE
+#endif /* #if (BTA_DM_PM_INCLUDED == TRUE) */
     /* simple pairing events */
 #if (SMP_INCLUDED == TRUE)
     bta_dm_confirm,                         /* 18 BTA_DM_API_CONFIRM_EVT */
index a876ec36a9c73f2dcda9b21a730ef0b45035ee38..e0f967ba5063a6910a46b707c8ee680ad44c5455 100644 (file)
 #include "bta/bta_api.h"
 #include "bta_dm_int.h"
 #include "stack/btm_api.h"
+#include "osi/allocator.h"
 
-#if (BTM_SSR_INCLUDED == TRUE)
+tBTA_DM_CONNECTED_SRVCS bta_dm_conn_srvcs;
 
+#if (BTA_DM_PM_INCLUDED == TRUE)
 static void bta_dm_pm_cback(tBTA_SYS_CONN_STATUS status, UINT8 id, UINT8 app_id, BD_ADDR peer_addr);
 static void bta_dm_pm_set_mode(BD_ADDR peer_addr, tBTA_DM_PM_ACTION pm_mode,
                                tBTA_DM_PM_REQ pm_req);
@@ -45,18 +47,15 @@ static void bta_dm_pm_hid_check(BOOLEAN bScoActive);
 static void bta_dm_pm_set_sniff_policy(tBTA_DM_PEER_DEVICE *p_dev, BOOLEAN bDisable);
 static void bta_dm_pm_stop_timer_by_index(tBTA_PM_TIMER *p_timer,
         UINT8 timer_idx);
-#endif///BTM_SSR_INCLUDED == TRUE
 
 #if (BTM_SSR_INCLUDED == TRUE)
 #if (defined BTA_HH_INCLUDED && BTA_HH_INCLUDED == TRUE)
 #include "../hh/bta_hh_int.h"
 /* BTA_DM_PM_SSR1 will be dedicated for HH SSR setting entry, no other profile can use it */
 #define BTA_DM_PM_SSR_HH      BTA_DM_PM_SSR1
-#endif
+#endif /* (defined BTA_HH_INCLUDED && BTA_HH_INCLUDED == TRUE) */
 static void bta_dm_pm_ssr(BD_ADDR peer_addr);
-
-tBTA_DM_CONNECTED_SRVCS bta_dm_conn_srvcs;
-
+#endif /* (BTM_SSR_INCLUDED == TRUE) */
 
 /*******************************************************************************
 **
@@ -118,27 +117,6 @@ void bta_dm_disable_pm(void)
     }
 }
 
-/*******************************************************************************
-**
-** Function         bta_dm_get_av_count
-**
-** Description      Get the number of connected AV
-**
-**
-** Returns          number of av connections
-**
-*******************************************************************************/
-UINT8 bta_dm_get_av_count(void)
-{
-    UINT8 count = 0;
-    for (int i = 0; i < bta_dm_conn_srvcs.count; i++) {
-        if (bta_dm_conn_srvcs.conn_srvc[i].id == BTA_ID_AV) {
-            ++count;
-        }
-    }
-    return count;
-}
-
 /*******************************************************************************
 **
 ** Function         bta_dm_pm_stop_timer
@@ -337,10 +315,10 @@ static void bta_dm_pm_cback(tBTA_SYS_CONN_STATUS status, UINT8 id, UINT8 app_id,
 {
 
     UINT8 i, j;
-    UINT8 *p = NULL;
     tBTA_DM_PEER_DEVICE *p_dev;
 
 #if (BTM_SSR_INCLUDED == TRUE)
+    UINT8 *p = NULL;
     int               index = BTA_DM_PM_SSR0;
 #endif
 
@@ -492,7 +470,6 @@ static void bta_dm_pm_cback(tBTA_SYS_CONN_STATUS status, UINT8 id, UINT8 app_id,
 ** Returns          void
 **
 *******************************************************************************/
-
 static void bta_dm_pm_set_mode(BD_ADDR peer_addr, tBTA_DM_PM_ACTION pm_request,
                                tBTA_DM_PM_REQ pm_req )
 {
@@ -702,8 +679,6 @@ static BOOLEAN bta_dm_pm_sniff(tBTA_DM_PEER_DEVICE *p_peer_dev, UINT8 index)
     BTM_ReadPowerMode(p_peer_dev->peer_bdaddr, &mode);
 #if (BTM_SSR_INCLUDED == TRUE)
     p_rem_feat = BTM_ReadRemoteFeatures (p_peer_dev->peer_bdaddr);
-#endif  ///BTM_SSR_INCLUDED == TRUE
-#if (BTM_SSR_INCLUDED == TRUE)
     APPL_TRACE_DEBUG("bta_dm_pm_sniff cur:%d, idx:%d, info:x%x", mode, index, p_peer_dev->info);
     if (mode != BTM_PM_MD_SNIFF ||
             (HCI_SNIFF_SUB_RATE_SUPPORTED(BTM_ReadLocalFeatures ()) && p_rem_feat &&
@@ -805,6 +780,7 @@ static void bta_dm_pm_ssr(BD_ADDR peer_addr)
     }
 }
 #endif
+
 /*******************************************************************************
 **
 ** Function         bta_dm_pm_active
@@ -824,11 +800,8 @@ void bta_dm_pm_active(BD_ADDR peer_addr)
     /* switch to active mode */
     pm.mode = BTM_PM_MD_ACTIVE;
     BTM_SetPowerMode (bta_dm_cb.pm_id, peer_addr, &pm);
-
-
 }
 
-
 /*******************************************************************************
 **
 ** Function         bta_dm_pm_btm_cback
@@ -901,6 +874,7 @@ static void bta_dm_pm_timer_cback(void *p_tle)
     }
 }
 
+
 /*******************************************************************************
 **
 ** Function         bta_dm_pm_btm_status
@@ -995,11 +969,9 @@ void bta_dm_pm_btm_status(tBTA_DM_MSG *p_data)
     default:
         break;
     }
-
-
-
 }
 
+
 /*******************************************************************************
 **
 ** Function         bta_dm_pm_timer
@@ -1015,33 +987,7 @@ void bta_dm_pm_timer(tBTA_DM_MSG *p_data)
     APPL_TRACE_EVENT("%s", __func__);
     bta_dm_pm_set_mode(p_data->pm_timer.bd_addr, p_data->pm_timer.pm_request, BTA_DM_PM_EXECUTE);
 }
-#endif  ///BTM_SSR_INCLUDED == TRUE
-
 
-/*******************************************************************************
-**
-** Function         bta_dm_find_peer_device
-**
-** Description      Given an address, find the associated control block.
-**
-** Returns          tBTA_DM_PEER_DEVICE
-**
-*******************************************************************************/
-tBTA_DM_PEER_DEVICE *bta_dm_find_peer_device(BD_ADDR peer_addr)
-{
-    tBTA_DM_PEER_DEVICE *p_dev = NULL;
-
-    for (int i = 0; i < bta_dm_cb.device_list.count; i++) {
-        if (!bdcmp( bta_dm_cb.device_list.peer_device[i].peer_bdaddr, peer_addr)) {
-            p_dev = &bta_dm_cb.device_list.peer_device[i];
-            break;
-        }
-
-    }
-    return p_dev;
-}
-
-#if (BTM_SSR_INCLUDED == TRUE)
 /*******************************************************************************
 **
 ** Function         bta_dm_is_sco_active
@@ -1138,7 +1084,52 @@ static void bta_dm_pm_set_sniff_policy(tBTA_DM_PEER_DEVICE *p_dev, BOOLEAN bDisa
     BTM_SetLinkPolicy(p_dev->peer_bdaddr, &policy_setting);
 
 }
-#endif  ///BTM_SSR_INCLUDED == TRUE
+#endif /* #if (BTA_DM_PM_INCLUDED == TRUE) */
+
+/*******************************************************************************
+**
+** Function         bta_dm_get_av_count
+**
+** Description      Get the number of connected AV
+**
+**
+** Returns          number of av connections
+**
+*******************************************************************************/
+UINT8 bta_dm_get_av_count(void)
+{
+    UINT8 count = 0;
+    for (int i = 0; i < bta_dm_conn_srvcs.count; i++) {
+        if (bta_dm_conn_srvcs.conn_srvc[i].id == BTA_ID_AV) {
+            ++count;
+        }
+    }
+    return count;
+}
+
+/*******************************************************************************
+**
+** Function         bta_dm_find_peer_device
+**
+** Description      Given an address, find the associated control block.
+**
+** Returns          tBTA_DM_PEER_DEVICE
+**
+*******************************************************************************/
+tBTA_DM_PEER_DEVICE *bta_dm_find_peer_device(BD_ADDR peer_addr)
+{
+    tBTA_DM_PEER_DEVICE *p_dev = NULL;
+
+    for (int i = 0; i < bta_dm_cb.device_list.count; i++) {
+        if (!bdcmp( bta_dm_cb.device_list.peer_device[i].peer_bdaddr, peer_addr)) {
+            p_dev = &bta_dm_cb.device_list.peer_device[i];
+            break;
+        }
+
+    }
+    return p_dev;
+}
+
 
 #if ((defined BLE_INCLUDED) && (BLE_INCLUDED == TRUE) && SDP_INCLUDED == TRUE)
 /*******************************************************************************
@@ -1161,5 +1152,6 @@ tBTA_DM_CONTRL_STATE bta_dm_pm_obtain_controller_state(void)
     APPL_TRACE_DEBUG("bta_dm_pm_obtain_controller_state: %d", cur_state);
     return cur_state;
 }
+
 #endif
 
index 45d098f44227150b920b670339886d4fb83e55ba..9acfa9544a0bef8b6530f66fd813d2035262c92b 100644 (file)
@@ -650,6 +650,6 @@ INT32 BTA_DmPcmResample (void *p_src, UINT32 in_bytes, void *p_dst)
     APPL_TRACE_DEBUG("bta_pcm_resample : outsamples  %d",  out_sample);
 #endif
 
-    return (out_sample * bta_dm_pcm_cb.sample_size);
+    return (out_sample);
 }
 #endif
index 6461bd4986b728d4fe2650040f3a5601903aa52b..d07e951f12248ea761067b2e7231e6415248a2ea 100644 (file)
@@ -63,11 +63,11 @@ enum {
     BTA_DM_API_BOND_CANCEL_EVT,
     BTA_DM_API_PIN_REPLY_EVT,
 #endif  ///SMP_INCLUDED == TRUE
-#if (BTM_SSR_INCLUDED == TRUE)
+#if (BTA_DM_PM_INCLUDED == TRUE)
     /* power manger events */
     BTA_DM_PM_BTM_STATUS_EVT,
     BTA_DM_PM_TIMER_EVT,
-#endif  ///BTM_SSR_INCLUDED == TRUE
+#endif /* #if (BTA_DM_PM_INCLUDED == TRUE) */
 #if (SMP_INCLUDED == TRUE)
     /* simple pairing events */
     BTA_DM_API_CONFIRM_EVT,
@@ -350,6 +350,7 @@ typedef struct {
 #endif
 } tBTA_DM_ACL_CHANGE;
 
+#if (BTA_DM_PM_INCLUDED == TRUE)
 /* data type for BTA_DM_PM_BTM_STATUS_EVT */
 typedef struct {
 
@@ -367,7 +368,7 @@ typedef struct {
     BD_ADDR         bd_addr;
     tBTA_DM_PM_ACTION  pm_request;
 } tBTA_DM_PM_TIMER;
-
+#endif /* #if (BTA_DM_PM_INCLUDED == TRUE) */
 
 /* data type for BTA_DM_API_ADD_DEVICE_EVT */
 typedef struct {
@@ -757,9 +758,11 @@ typedef union {
 
     tBTA_DM_ACL_CHANGE  acl_change;
 
+#if (BTA_DM_PM_INCLUDED == TRUE)
     tBTA_DM_PM_BTM_STATUS pm_status;
 
     tBTA_DM_PM_TIMER pm_timer;
+#endif /* #if (BTA_DM_PM_INCLUDED == TRUE) */
 
     tBTA_DM_API_DI_DISC     di_disc;
 
@@ -889,6 +892,10 @@ typedef struct {
 
 }  tBTA_DM_CONNECTED_SRVCS;
 
+extern tBTA_DM_CONNECTED_SRVCS bta_dm_conn_srvcs;
+
+#if (BTA_DM_PM_INCLUDED == TRUE)
+
 typedef struct {
 #define BTA_DM_PM_SNIFF_TIMER_IDX   0
 #define BTA_DM_PM_PARK_TIMER_IDX    1
@@ -908,9 +915,8 @@ typedef struct {
     BOOLEAN                 in_use;
 } tBTA_PM_TIMER;
 
-extern tBTA_DM_CONNECTED_SRVCS bta_dm_conn_srvcs;
-
 #define BTA_DM_NUM_PM_TIMER 7
+#endif /* #if (BTA_DM_PM_INCLUDED == TRUE) */
 
 /* DM control block */
 typedef struct {
@@ -931,10 +937,10 @@ typedef struct {
     UINT32                      wbt_sdp_handle;          /* WIDCOMM Extensions SDP record handle */
     UINT8                       wbt_scn;                 /* WIDCOMM Extensions SCN */
     UINT8                       num_master_only;
-#if BTM_SSR_INCLUDED == TRUE
+#if (BTA_DM_PM_INCLUDED == TRUE)
     UINT8                       pm_id;
     tBTA_PM_TIMER               pm_timer[BTA_DM_NUM_PM_TIMER];
-#endif  ///BTM_SSR_INCLUDED == TRUE
+#endif /* #if (BTA_DM_PM_INCLUDED == TRUE) */
     UINT32                      role_policy_mask;   /* the bits set indicates the modules that wants to remove role switch from the default link policy */
     UINT16                      cur_policy;         /* current default link policy */
     UINT16                      rs_event;           /* the event waiting for role switch */
@@ -1101,12 +1107,14 @@ typedef struct {
     UINT8 lmp_version;
 } tBTA_DM_LMP_VER_INFO;
 
+#if (BTA_DM_PM_INCLUDED == TRUE)
 extern tBTA_DM_PM_CFG *p_bta_dm_pm_cfg;
 extern tBTA_DM_PM_SPEC *p_bta_dm_pm_spec;
 extern tBTM_PM_PWR_MD *p_bta_dm_pm_md;
 #if (BTM_SSR_INCLUDED == TRUE)
 extern tBTA_DM_SSR_SPEC *p_bta_dm_ssr_spec;
 #endif
+#endif /* #if (BTA_DM_PM_INCLUDED == TRUE) */
 
 /* update dynamic BRCM Aware EIR data */
 extern const tBTA_DM_EIR_CONF bta_dm_eir_cfg;
@@ -1161,9 +1169,6 @@ extern void bta_dm_add_device (tBTA_DM_MSG *p_data);
 extern void bta_dm_remove_device (tBTA_DM_MSG *p_data);
 extern void bta_dm_close_acl(tBTA_DM_MSG *p_data);
 
-
-extern void bta_dm_pm_btm_status(tBTA_DM_MSG *p_data);
-extern void bta_dm_pm_timer(tBTA_DM_MSG *p_data);
 extern void bta_dm_add_ampkey (tBTA_DM_MSG *p_data);
 
 #if BLE_INCLUDED == TRUE
@@ -1223,8 +1228,13 @@ extern void bta_dm_ci_io_req_act(tBTA_DM_MSG *p_data);
 extern void bta_dm_ci_rmt_oob_act(tBTA_DM_MSG *p_data);
 #endif /* BTM_OOB_INCLUDED */
 
+#if (BTA_DM_PM_INCLUDED == TRUE)
 extern void bta_dm_init_pm(void);
 extern void bta_dm_disable_pm(void);
+extern void bta_dm_pm_active(BD_ADDR peer_addr);
+extern void bta_dm_pm_btm_status(tBTA_DM_MSG *p_data);
+extern void bta_dm_pm_timer(tBTA_DM_MSG *p_data);
+#endif /* #if (BTA_DM_PM_INCLUDED == TRUE) */
 
 extern UINT8 bta_dm_get_av_count(void);
 extern void bta_dm_search_start (tBTA_DM_MSG *p_data);
@@ -1251,9 +1261,6 @@ extern void bta_dm_search_cancel_notify (tBTA_DM_MSG *p_data);
 extern void bta_dm_search_cancel_transac_cmpl(tBTA_DM_MSG *p_data);
 extern void bta_dm_disc_rmt_name (tBTA_DM_MSG *p_data);
 extern tBTA_DM_PEER_DEVICE *bta_dm_find_peer_device(BD_ADDR peer_addr);
-
-extern void bta_dm_pm_active(BD_ADDR peer_addr);
-
 void bta_dm_eir_update_uuid(UINT16 uuid16, BOOLEAN adding);
 
 extern void bta_dm_enable_test_mode(tBTA_DM_MSG *p_data);
diff --git a/components/bt/bluedroid/bta/hf_client/bta_hf_client_act.c b/components/bt/bluedroid/bta/hf_client/bta_hf_client_act.c
new file mode 100644 (file)
index 0000000..c42b5bd
--- /dev/null
@@ -0,0 +1,772 @@
+/******************************************************************************
+ *
+ *  Copyright (c) 2014 The Android Open Source Project
+ *  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 handsfree client.
+ *
+ ******************************************************************************/
+
+#include "bta/bta_api.h"
+#include "bta/bta_hf_client_api.h"
+#include "bta_hf_client_int.h"
+#include "bta_dm_int.h"
+#include "stack/l2c_api.h"
+#include "stack/port_api.h"
+#include "bta/bta_sys.h"
+#include "bta/utl.h"
+#include "common/bt_defs.h"
+#include <string.h>
+#include "osi/allocator.h"
+
+#if (BTA_HF_INCLUDED == TRUE)
+/*****************************************************************************
+**  Constants
+*****************************************************************************/
+
+/* maximum length of data to read from RFCOMM */
+#define BTA_HF_CLIENT_RFC_READ_MAX     512
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_register
+**
+** Description      This function initializes values of the scb and sets up
+**                  the SDP record for the services.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hf_client_register(tBTA_HF_CLIENT_DATA *p_data)
+{
+    tBTA_HF_CLIENT_REGISTER evt;
+    tBTA_UTL_COD   cod;
+
+    memset(&evt, 0, sizeof(evt));
+
+    /* initialize control block */
+    bta_hf_client_scb_init();
+
+    bta_hf_client_cb.scb.serv_sec_mask = p_data->api_register.sec_mask;
+    bta_hf_client_cb.scb.features = p_data->api_register.features;
+
+    /* initialize AT control block */
+    bta_hf_client_at_init();
+
+    /* create SDP records */
+    bta_hf_client_create_record(p_data);
+
+    /* Set the Audio service class bit */
+    cod.service = BTM_COD_SERVICE_AUDIO;
+    utl_set_device_class(&cod, BTA_UTL_SET_COD_SERVICE_CLASS);
+
+    /* start RFCOMM server */
+    bta_hf_client_start_server();
+
+    /* call app callback with register event */
+    evt.status = BTA_HF_CLIENT_SUCCESS;
+    (*bta_hf_client_cb.p_cback)(BTA_HF_CLIENT_REGISTER_EVT, &evt);
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_deregister
+**
+** Description      This function removes the sdp records, closes the RFCOMM
+**                  servers, and deallocates the service control block.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hf_client_deregister(tBTA_HF_CLIENT_DATA *p_data)
+{
+    bta_hf_client_cb.scb.deregister = TRUE;
+
+    /* remove sdp record */
+    bta_hf_client_del_record(p_data);
+
+    /* remove rfcomm server */
+    bta_hf_client_close_server();
+
+    /* disable */
+    bta_hf_client_scb_disable();
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_start_dereg
+**
+** Description      Start a deregister event.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hf_client_start_dereg(tBTA_HF_CLIENT_DATA *p_data)
+{
+    bta_hf_client_cb.scb.deregister = TRUE;
+
+    /* remove sdp record */
+    bta_hf_client_del_record(p_data);
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_start_close
+**
+** Description      Start the process of closing SCO and RFCOMM connection.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hf_client_start_close(tBTA_HF_CLIENT_DATA *p_data)
+{
+    /* Take the link out of sniff and set L2C idle time to 0 */
+#if (BTA_DM_PM_INCLUDED == TRUE)
+    bta_dm_pm_active(bta_hf_client_cb.scb.peer_addr);
+#endif /* (BTA_DM_PM_INCLUDED == TRUE) */
+    L2CA_SetIdleTimeoutByBdAddr(bta_hf_client_cb.scb.peer_addr, 0, BT_TRANSPORT_BR_EDR);
+
+    /* if SCO is open close SCO and wait on RFCOMM close */
+    if (bta_hf_client_cb.scb.sco_state == BTA_HF_CLIENT_SCO_OPEN_ST) {
+        bta_hf_client_cb.scb.sco_close_rfc = TRUE;
+    } else {
+        bta_hf_client_rfc_do_close(p_data);
+    }
+
+    /* always do SCO shutdown to handle all SCO corner cases */
+    bta_hf_client_sco_shutdown(NULL);
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_start_open
+**
+** Description      This starts an HF Client open.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hf_client_start_open(tBTA_HF_CLIENT_DATA *p_data)
+{
+    BD_ADDR pending_bd_addr;
+
+    /* store parameters */
+    if (p_data) {
+        bdcpy(bta_hf_client_cb.scb.peer_addr, p_data->api_open.bd_addr);
+        bta_hf_client_cb.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 now.                                         */
+        /* We will decide what to do when we find incoming connection later.*/
+        bta_hf_client_collision_cback (0, BTA_ID_HS, 0, bta_hf_client_cb.scb.peer_addr);
+        return;
+    }
+
+    /* close server */
+    bta_hf_client_close_server();
+
+    /* set role */
+    bta_hf_client_cb.scb.role = BTA_HF_CLIENT_INT;
+
+    /* do service search */
+    bta_hf_client_do_disc();
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_cback_open
+**
+** Description      Send open callback event to application.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+static void bta_hf_client_cback_open(tBTA_HF_CLIENT_DATA *p_data, tBTA_HF_CLIENT_STATUS status)
+{
+    tBTA_HF_CLIENT_OPEN evt;
+
+    memset(&evt, 0, sizeof(evt));
+
+    /* call app callback with open event */
+    evt.status = status;
+    if (p_data) {
+        /* if p_data is provided then we need to pick the bd address from the open api structure */
+        bdcpy(evt.bd_addr, p_data->api_open.bd_addr);
+    } else {
+        bdcpy(evt.bd_addr, bta_hf_client_cb.scb.peer_addr);
+    }
+
+    (*bta_hf_client_cb.p_cback)(BTA_HF_CLIENT_OPEN_EVT, &evt);
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_rfc_open
+**
+** Description      Handle RFCOMM channel open.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hf_client_rfc_open(tBTA_HF_CLIENT_DATA *p_data)
+{
+    UNUSED(p_data);
+
+    bta_sys_conn_open(BTA_ID_HS, 1, bta_hf_client_cb.scb.peer_addr);
+
+    bta_hf_client_cback_open(NULL, BTA_HF_CLIENT_SUCCESS);
+
+    /* start SLC procedure */
+    bta_hf_client_slc_seq(FALSE);
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_rfc_acp_open
+**
+** Description      Handle RFCOMM channel open when accepting connection.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hf_client_rfc_acp_open(tBTA_HF_CLIENT_DATA *p_data)
+{
+    UINT16          lcid;
+    BD_ADDR         dev_addr;
+    int             status;
+
+    /* set role */
+    bta_hf_client_cb.scb.role = BTA_HF_CLIENT_ACP;
+
+    APPL_TRACE_DEBUG ("bta_hf_client_rfc_acp_open: serv_handle = %d rfc.port_handle = %d",
+                      bta_hf_client_cb.scb.serv_handle, p_data->rfc.port_handle);
+
+    /* get bd addr of peer */
+    if (PORT_SUCCESS != (status = PORT_CheckConnection(p_data->rfc.port_handle, dev_addr, &lcid))) {
+        APPL_TRACE_DEBUG ("bta_hf_client_rfc_acp_open error PORT_CheckConnection returned status %d", status);
+    }
+
+    /* Collision Handling */
+    if (bta_hf_client_cb.scb.colli_tmr_on) {
+        /* stop collision timer */
+        bta_hf_client_cb.scb.colli_tmr_on = FALSE;
+        bta_sys_free_timer (&bta_hf_client_cb.scb.colli_timer);
+
+        if (bdcmp (dev_addr, bta_hf_client_cb.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. */
+            bta_hf_client_resume_open ();
+        }
+    }
+
+    bdcpy (bta_hf_client_cb.scb.peer_addr, dev_addr);
+    bta_hf_client_cb.scb.conn_handle = p_data->rfc.port_handle;
+
+    /* do service discovery to get features */
+    bta_hf_client_do_disc();
+
+    /* continue with open processing */
+    bta_hf_client_rfc_open(p_data);
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_rfc_fail
+**
+** Description      RFCOMM connection failed.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hf_client_rfc_fail(tBTA_HF_CLIENT_DATA *p_data)
+{
+    UNUSED(p_data);
+
+    /* reinitialize stuff */
+    bta_hf_client_cb.scb.conn_handle = 0;
+    bta_hf_client_cb.scb.peer_features = 0;
+    bta_hf_client_cb.scb.chld_features = 0;
+    bta_hf_client_cb.scb.role = BTA_HF_CLIENT_ACP;
+    bta_hf_client_cb.scb.svc_conn = FALSE;
+    bta_hf_client_cb.scb.send_at_reply = FALSE;
+    bta_hf_client_cb.scb.negotiated_codec = BTM_SCO_CODEC_CVSD;
+
+    bta_hf_client_at_reset();
+
+    /* reopen server */
+    bta_hf_client_start_server();
+
+    /* call open cback w. failure */
+    bta_hf_client_cback_open(NULL, BTA_HF_CLIENT_FAIL_RFCOMM);
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_disc_fail
+**
+** Description      This function handles a discovery failure.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hf_client_disc_fail(tBTA_HF_CLIENT_DATA *p_data)
+{
+    UNUSED(p_data);
+
+    /* reopen server */
+    bta_hf_client_start_server();
+
+    /* reinitialize stuff */
+
+    /* call open cback w. failure */
+    bta_hf_client_cback_open(NULL, BTA_HF_CLIENT_FAIL_SDP);
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_open_fail
+**
+** Description      open connection failed.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hf_client_open_fail(tBTA_HF_CLIENT_DATA *p_data)
+{
+    /* call open cback w. failure */
+    bta_hf_client_cback_open(p_data, BTA_HF_CLIENT_FAIL_RESOURCES);
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_rfc_close
+**
+** Description      RFCOMM connection closed.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hf_client_rfc_close(tBTA_HF_CLIENT_DATA *p_data)
+{
+    UNUSED(p_data);
+
+    /* reinitialize stuff */
+    bta_hf_client_cb.scb.peer_features = 0;
+    bta_hf_client_cb.scb.chld_features = 0;
+    bta_hf_client_cb.scb.role = BTA_HF_CLIENT_ACP;
+    bta_hf_client_cb.scb.svc_conn = FALSE;
+    bta_hf_client_cb.scb.send_at_reply = FALSE;
+    bta_hf_client_cb.scb.negotiated_codec = BTM_SCO_CODEC_CVSD;
+
+    bta_hf_client_at_reset();
+
+    bta_sys_conn_close(BTA_ID_HS, 1, bta_hf_client_cb.scb.peer_addr);
+
+    /* call close cback */
+    (*bta_hf_client_cb.p_cback)(BTA_HF_CLIENT_CLOSE_EVT, NULL);
+
+    /* if not deregistering reopen server */
+    if (bta_hf_client_cb.scb.deregister == FALSE) {
+        /* Clear peer bd_addr so instance can be reused */
+        bdcpy(bta_hf_client_cb.scb.peer_addr, bd_addr_null);
+
+        /* start server as it might got closed on open*/
+        bta_hf_client_start_server();
+
+        bta_hf_client_cb.scb.conn_handle = 0;
+
+        /* Make sure SCO is shutdown */
+        bta_hf_client_sco_shutdown(NULL);
+
+        bta_sys_sco_unuse(BTA_ID_HS, 1, bta_hf_client_cb.scb.peer_addr);
+    }
+    /* else close port and deallocate scb */
+    else {
+        bta_hf_client_close_server();
+        bta_hf_client_scb_disable();
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_disc_int_res
+**
+** Description      This function handles a discovery result when initiator.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hf_client_disc_int_res(tBTA_HF_CLIENT_DATA *p_data)
+{
+    UINT16 event = BTA_HF_CLIENT_DISC_FAIL_EVT;
+
+    APPL_TRACE_DEBUG ("bta_hf_client_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_hf_client_sdp_find_attr()) {
+            event = BTA_HF_CLIENT_DISC_OK_EVT;
+        }
+    }
+
+    /* free discovery db */
+    bta_hf_client_free_db(p_data);
+
+    /* send ourselves sdp ok/fail event */
+    bta_hf_client_sm_execute(event, p_data);
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_disc_acp_res
+**
+** Description      This function handles a discovery result when acceptor.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hf_client_disc_acp_res(tBTA_HF_CLIENT_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_hf_client_sdp_find_attr();
+    }
+
+    /* free discovery db */
+    bta_hf_client_free_db(p_data);
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_rfc_data
+**
+** Description      Read and process data from RFCOMM.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hf_client_rfc_data(tBTA_HF_CLIENT_DATA *p_data)
+{
+    UINT16  len;
+    char    *buf = osi_calloc(BTA_HF_CLIENT_RFC_READ_MAX);
+    if (buf == NULL) {
+        APPL_TRACE_ERROR("No mem %s", __FUNCTION__);
+        return;
+    }
+
+    UNUSED(p_data);
+
+    /* read data from rfcomm; if bad status, we're done */
+    while (PORT_ReadData(bta_hf_client_cb.scb.conn_handle, buf, BTA_HF_CLIENT_RFC_READ_MAX, &len) == PORT_SUCCESS) {
+        /* if no data, we're done */
+        if (len == 0) {
+            break;
+        }
+
+        bta_hf_client_at_parse(buf, len);
+
+        /* no more data to read, we're done */
+        if (len < BTA_HF_CLIENT_RFC_READ_MAX) {
+            break;
+        }
+    }
+    osi_free(buf);
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_svc_conn_open
+**
+** Description      Service level connection opened
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hf_client_svc_conn_open(tBTA_HF_CLIENT_DATA *p_data)
+{
+    tBTA_HF_CLIENT_CONN evt;
+    UNUSED(p_data);
+
+    memset(&evt, 0, sizeof(evt));
+
+    if (!bta_hf_client_cb.scb.svc_conn) {
+        /* set state variable */
+        bta_hf_client_cb.scb.svc_conn = TRUE;
+
+        /* call callback */
+        evt.peer_feat = bta_hf_client_cb.scb.peer_features;
+        evt.chld_feat = bta_hf_client_cb.scb.chld_features;
+
+        (*bta_hf_client_cb.p_cback)(BTA_HF_CLIENT_CONN_EVT, &evt);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_cback_ind
+**
+** Description      Send indicator callback event to application.
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hf_client_ind(tBTA_HF_CLIENT_IND_TYPE type, UINT16 value)
+{
+    tBTA_HF_CLIENT_IND evt;
+
+    memset(&evt, 0, sizeof(evt));
+
+    evt.type = type;
+    evt.value = value;
+
+    (*bta_hf_client_cb.p_cback)(BTA_HF_CLIENT_IND_EVT, &evt);
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_evt_val
+**
+** Description      Send event to application.
+**                  This is a generic helper for events with common data.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hf_client_evt_val(tBTA_HF_CLIENT_EVT type, UINT16 value)
+{
+    tBTA_HF_CLIENT_VAL evt;
+
+    memset(&evt, 0, sizeof(evt));
+
+    evt.value = value;
+
+    (*bta_hf_client_cb.p_cback)(type, &evt);
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_operator_name
+**
+** Description      Send operator name event to application.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hf_client_operator_name(char *name)
+{
+    tBTA_HF_CLIENT_OPERATOR_NAME *evt;
+
+    if ((evt = osi_calloc(sizeof(tBTA_HF_CLIENT_OPERATOR_NAME))) != NULL) {
+        strlcpy(evt->name, name, BTA_HF_CLIENT_OPERATOR_NAME_LEN + 1);
+        evt->name[BTA_HF_CLIENT_OPERATOR_NAME_LEN] = '\0';
+
+        (*bta_hf_client_cb.p_cback)(BTA_HF_CLIENT_OPERATOR_NAME_EVT, evt);
+        osi_free(evt);
+    } else {
+        APPL_TRACE_ERROR("No mem: %s", __func__);
+    }
+}
+
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_clip
+**
+** Description      Send CLIP event to application.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hf_client_clip(char *number)
+{
+    tBTA_HF_CLIENT_NUMBER *evt;
+
+    if ((evt = osi_calloc(sizeof(tBTA_HF_CLIENT_NUMBER))) != NULL) {
+        strlcpy(evt->number, number, BTA_HF_CLIENT_NUMBER_LEN + 1);
+        evt->number[BTA_HF_CLIENT_NUMBER_LEN] = '\0';
+
+        (*bta_hf_client_cb.p_cback)(BTA_HF_CLIENT_CLIP_EVT, evt);
+        osi_free(evt);
+    } else {
+        APPL_TRACE_ERROR("No mem: %s", __func__);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_ccwa
+**
+** Description      Send CLIP event to application.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hf_client_ccwa(char *number)
+{
+    tBTA_HF_CLIENT_NUMBER *evt;
+
+    if ((evt = osi_calloc(sizeof(tBTA_HF_CLIENT_NUMBER))) != NULL) {
+        strlcpy(evt->number, number, BTA_HF_CLIENT_NUMBER_LEN + 1);
+        evt->number[BTA_HF_CLIENT_NUMBER_LEN] = '\0';
+        
+
+        (*bta_hf_client_cb.p_cback)(BTA_HF_CLIENT_CCWA_EVT, evt);
+        osi_free(evt);
+    } else {
+        APPL_TRACE_ERROR("No mem: %s", __func__);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_at_result
+**
+** Description      Send AT result event to application.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hf_client_at_result(tBTA_HF_CLIENT_AT_RESULT_TYPE type, UINT16 cme)
+{
+    tBTA_HF_CLIENT_AT_RESULT evt;
+
+    memset(&evt, 0, sizeof(evt));
+
+    evt.type = type;
+    evt.cme = cme;
+
+    (*bta_hf_client_cb.p_cback)(BTA_HF_CLIENT_AT_RESULT_EVT, &evt);
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_clcc
+**
+** Description      Send clcc event to application.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hf_client_clcc(UINT32 idx, BOOLEAN incoming, UINT8 status, BOOLEAN mpty, char *number)
+{
+    tBTA_HF_CLIENT_CLCC *evt;
+
+    if ((evt = osi_calloc(sizeof(tBTA_HF_CLIENT_CLCC))) != NULL) {
+        evt->idx = idx;
+        evt->inc = incoming;
+        evt->status = status;
+        evt->mpty = mpty;
+
+        if (number) {
+            evt->number_present = TRUE;
+            strlcpy(evt->number, number, BTA_HF_CLIENT_NUMBER_LEN + 1);
+            evt->number[BTA_HF_CLIENT_NUMBER_LEN] = '\0';
+        }
+        
+        (*bta_hf_client_cb.p_cback)(BTA_HF_CLIENT_CLCC_EVT, evt);
+        osi_free(evt);
+    } else {
+        APPL_TRACE_ERROR("No mem, %s\n", __func__);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_cnum
+**
+** Description      Send cnum event to application.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hf_client_cnum(char *number, UINT16 service)
+{
+    tBTA_HF_CLIENT_CNUM *evt;
+
+    if ((evt = osi_calloc(sizeof(tBTA_HF_CLIENT_CNUM))) != NULL) {
+
+        evt->service = service;
+        strlcpy(evt->number, number, BTA_HF_CLIENT_NUMBER_LEN + 1);
+        evt->number[BTA_HF_CLIENT_NUMBER_LEN] = '\0';
+
+        (*bta_hf_client_cb.p_cback)(BTA_HF_CLIENT_CNUM_EVT, evt);
+        osi_free(evt);
+    } else {
+        APPL_TRACE_ERROR("No mem, %s", __func__);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_binp
+**
+** Description      Send BINP event to application.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hf_client_binp(char *number)
+{
+    tBTA_HF_CLIENT_NUMBER *evt;
+
+    if ((evt = osi_calloc(sizeof(tBTA_HF_CLIENT_NUMBER))) != NULL) {
+        strlcpy(evt->number, number, BTA_HF_CLIENT_NUMBER_LEN + 1);
+        evt->number[BTA_HF_CLIENT_NUMBER_LEN] = '\0';
+
+        (*bta_hf_client_cb.p_cback)(BTA_HF_CLIENT_BINP_EVT, evt);
+        osi_free(evt);
+    } else {
+        APPL_TRACE_ERROR("No mem: %s", __func__);
+    }
+}
+
+#endif /* #if (BTA_HF_INCLUDED == TRUE) */
diff --git a/components/bt/bluedroid/bta/hf_client/bta_hf_client_api.c b/components/bt/bluedroid/bta/hf_client/bta_hf_client_api.c
new file mode 100644 (file)
index 0000000..434b2b5
--- /dev/null
@@ -0,0 +1,312 @@
+/******************************************************************************
+ *
+ *  Copyright (c) 2014 The Android Open Source Project
+ *  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 handsfree (HF role)
+ *  subsystem of BTA
+ *
+ ******************************************************************************/
+
+#include <string.h>
+#include "bta/bta_hf_client_api.h"
+#include "bta_hf_client_int.h"
+#include "osi/allocator.h"
+
+#if (BTA_HF_INCLUDED == TRUE)
+/*****************************************************************************
+**  Constants and data types
+*****************************************************************************/
+static const tBTA_SYS_REG bta_hf_client_reg = {
+    bta_hf_client_hdl_event,
+    BTA_HfClientDisable
+};
+
+static const uint8_t bta_hf_client_cb_data_size[] = {
+    0,                                  // #define BTA_HF_CLIENT_ENABLE_EVT            0
+    sizeof(tBTA_HF_CLIENT_REGISTER),    // #define BTA_HF_CLIENT_REGISTER_EVT          1
+    sizeof(tBTA_HF_CLIENT_OPEN),        // #define BTA_HF_CLIENT_OPEN_EVT              2
+    0,                                  // #define BTA_HF_CLIENT_CLOSE_EVT             3
+    sizeof(tBTA_HF_CLIENT_CONN),        // #define BTA_HF_CLIENT_CONN_EVT              4
+    sizeof(tBTA_HF_CLIENT_HDR),         // #define BTA_HF_CLIENT_AUDIO_OPEN_EVT        5
+    sizeof(tBTA_HF_CLIENT_HDR),         //#define BTA_HF_CLIENT_AUDIO_MSBC_OPEN_EVT   6 
+    sizeof(tBTA_HF_CLIENT_HDR),         // #define BTA_HF_CLIENT_AUDIO_CLOSE_EVT       7
+    sizeof(tBTA_HF_CLIENT_VAL),         // #define BTA_HF_CLIENT_SPK_EVT               8
+    sizeof(tBTA_HF_CLIENT_VAL),         // #define BTA_HF_CLIENT_MIC_EVT               9
+    sizeof(tBTA_HF_CLIENT_IND),         //#define BTA_HF_CLIENT_IND_EVT               10
+    sizeof(tBTA_HF_CLIENT_VAL),         // #define BTA_HF_CLIENT_VOICE_REC_EVT         11
+    sizeof(tBTA_HF_CLIENT_OPERATOR_NAME),    // #define BTA_HF_CLIENT_OPERATOR_NAME_EVT     12
+    sizeof(tBTA_HF_CLIENT_NUMBER),           // #define BTA_HF_CLIENT_CLIP_EVT              13
+    sizeof(tBTA_HF_CLIENT_NUMBER),      // #define BTA_HF_CLIENT_CCWA_EVT              14
+    sizeof(tBTA_HF_CLIENT_AT_RESULT),   // #define BTA_HF_CLIENT_AT_RESULT_EVT         15
+    sizeof(tBTA_HF_CLIENT_CLCC),        // #define BTA_HF_CLIENT_CLCC_EVT              16
+    sizeof(tBTA_HF_CLIENT_CNUM),        //#define BTA_HF_CLIENT_CNUM_EVT              17
+    sizeof(tBTA_HF_CLIENT_VAL),         // #define BTA_HF_CLIENT_BTRH_EVT              18
+    sizeof(tBTA_HF_CLIENT_VAL),         // #define BTA_HF_CLIENT_BSIR_EVT              19
+    sizeof(tBTA_HF_CLIENT_NUMBER),      // #define BTA_HF_CLIENT_BINP_EVT              20
+    sizeof(tBTA_HF_CLIENT_VAL),         // #define BTA_HF_CLIENT_RING_INDICATION       21
+    0,                                  // #define BTA_HF_CLIENT_DISABLE_EVT           30
+};
+/*****************************************************************************
+**  External Function Declarations
+*****************************************************************************/
+
+/*******************************************************************************
+**
+** Function         BTA_HfClientEnable
+**
+** Description      Enable the HF CLient service. When the enable
+**                  operation is complete the callback function will be
+**                  called with a BTA_HF_CLIENT_ENABLE_EVT. This function must
+**                  be called before other function in the HF CLient API are
+**                  called.
+**
+** Returns          BTA_SUCCESS if OK, BTA_FAILURE otherwise.
+**
+*******************************************************************************/
+tBTA_STATUS BTA_HfClientEnable(tBTA_HF_CLIENT_CBACK *p_cback)
+{
+    tBTA_HF_CLIENT_API_ENABLE  *p_buf;
+
+    if (bta_sys_is_register (BTA_ID_HS)) {
+        APPL_TRACE_ERROR("BTA HF Client is already enabled, ignoring ...");
+        return BTA_FAILURE;
+    }
+
+    /* register with BTA system manager */
+    bta_sys_register(BTA_ID_HS, &bta_hf_client_reg);
+
+    if ((p_buf = (tBTA_HF_CLIENT_API_ENABLE *) osi_malloc(sizeof(tBTA_HF_CLIENT_API_ENABLE))) != NULL) {
+        p_buf->hdr.event = BTA_HF_CLIENT_API_ENABLE_EVT;
+        p_buf->p_cback = p_cback;
+        bta_sys_sendmsg(p_buf);
+    }
+
+    return BTA_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function         BTA_HfClientDisable
+**
+** Description      Disable the HF Client service
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void BTA_HfClientDisable(void)
+{
+    BT_HDR  *p_buf;
+
+    if ((p_buf = (BT_HDR *) osi_malloc(sizeof(BT_HDR))) != NULL) {
+        p_buf->event = BTA_HF_CLIENT_API_DISABLE_EVT;
+        bta_sys_sendmsg(p_buf);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         BTA_HfClientRegister
+**
+** Description      Register an HF Client service.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void BTA_HfClientRegister(tBTA_SEC sec_mask, tBTA_HF_CLIENT_FEAT features,
+                          char *p_service_name)
+{
+    tBTA_HF_CLIENT_API_REGISTER    *p_buf;
+
+    if ((p_buf = (tBTA_HF_CLIENT_API_REGISTER *) osi_malloc(sizeof(tBTA_HF_CLIENT_API_REGISTER))) != NULL) {
+        p_buf->hdr.event = BTA_HF_CLIENT_API_REGISTER_EVT;
+        p_buf->features = features;
+        p_buf->sec_mask = sec_mask;
+        if (p_service_name) {
+            BCM_STRNCPY_S(p_buf->name, BTA_SERVICE_NAME_LEN + 1, p_service_name, BTA_SERVICE_NAME_LEN);
+            p_buf->name[BTA_SERVICE_NAME_LEN] = 0;
+        } else {
+            p_buf->name[0] = '\0';
+        }
+        bta_sys_sendmsg(p_buf);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         BTA_HfClientDeregister
+**
+** Description      Deregister an HF Client service.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void BTA_HfClientDeregister(UINT16 handle)
+{
+    BT_HDR  *p_buf;
+
+    if ((p_buf = (BT_HDR *) osi_malloc(sizeof(BT_HDR))) != NULL) {
+        p_buf->event = BTA_HF_CLIENT_API_DEREGISTER_EVT;
+        p_buf->layer_specific = handle;
+        bta_sys_sendmsg(p_buf);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         BTA_HfClientOpen
+**
+** Description      Opens a connection to an audio gateway.
+**                  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_HfClientOpen(UINT16 handle, BD_ADDR bd_addr, tBTA_SEC sec_mask)
+{
+    tBTA_HF_CLIENT_API_OPEN  *p_buf;
+
+    if ((p_buf = (tBTA_HF_CLIENT_API_OPEN *) osi_malloc(sizeof(tBTA_HF_CLIENT_API_OPEN))) != NULL) {
+        p_buf->hdr.event = BTA_HF_CLIENT_API_OPEN_EVT;
+        p_buf->hdr.layer_specific = handle;
+        bdcpy(p_buf->bd_addr, bd_addr);
+        p_buf->sec_mask = sec_mask;
+        bta_sys_sendmsg(p_buf);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         BTA_HfClientClose
+**
+** Description      Close the current connection to an audio gateway.
+**                  Any current audio connection will also be closed
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void BTA_HfClientClose(UINT16 handle)
+{
+    BT_HDR  *p_buf;
+
+    if ((p_buf = (BT_HDR *) osi_malloc(sizeof(BT_HDR))) != NULL) {
+        p_buf->event = BTA_HF_CLIENT_API_CLOSE_EVT;
+        p_buf->layer_specific = handle;
+        bta_sys_sendmsg(p_buf);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         BTA_HfCllientAudioOpen
+**
+** Description      Opens an audio connection to the currently connected
+**                 audio gateway
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void BTA_HfClientAudioOpen(UINT16 handle)
+{
+    BT_HDR  *p_buf;
+
+    if ((p_buf = (BT_HDR *) osi_malloc(sizeof(BT_HDR))) != NULL) {
+        p_buf->event = BTA_HF_CLIENT_API_AUDIO_OPEN_EVT;
+        p_buf->layer_specific = handle;
+        bta_sys_sendmsg(p_buf);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         BTA_HfClientAudioClose
+**
+** Description      Close the currently active audio connection to an audio
+**                  gateway. The data connection remains open
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void BTA_HfClientAudioClose(UINT16 handle)
+{
+    BT_HDR  *p_buf;
+
+    if ((p_buf = (BT_HDR *) osi_malloc(sizeof(BT_HDR))) != NULL) {
+        p_buf->event = BTA_HF_CLIENT_API_AUDIO_CLOSE_EVT;
+        p_buf->layer_specific = handle;
+        bta_sys_sendmsg(p_buf);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         BTA_HfClientSendAT
+**
+** Description      send AT command
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void BTA_HfClientSendAT(UINT16 handle, tBTA_HF_CLIENT_AT_CMD_TYPE at, UINT32 val1, UINT32 val2, const char *str)
+{
+    tBTA_HF_CLIENT_DATA_VAL  *p_buf;
+
+    if ((p_buf = (tBTA_HF_CLIENT_DATA_VAL *) osi_malloc(sizeof(tBTA_HF_CLIENT_DATA_VAL))) != NULL) {
+        p_buf->hdr.event = BTA_HF_CLIENT_SEND_AT_CMD_EVT;
+        p_buf->uint8_val = at;
+        p_buf->uint32_val1 = val1;
+        p_buf->uint32_val2 = val2;
+
+        if (str) {
+            strlcpy(p_buf->str, str, BTA_HF_CLIENT_NUMBER_LEN + 1);
+            p_buf->str[BTA_HF_CLIENT_NUMBER_LEN] = '\0';
+        } else {
+            p_buf->str[0] = '\0';
+        }
+
+        p_buf->hdr.layer_specific = handle;
+        bta_sys_sendmsg(p_buf);
+    }
+}
+#if (BTM_SCO_HCI_INCLUDED == TRUE )
+void BTA_HfClientCiData(void)
+{
+    BT_HDR *p_buf;
+    if ((p_buf = (BT_HDR *) osi_malloc(sizeof(BT_HDR))) != NULL) {
+        p_buf->event = BTA_HF_CLIENT_CI_SCO_DATA_EVT;
+        bta_sys_sendmsg(p_buf);
+    }
+}
+#endif /* #if (BTM_SCO_HCI_INCLUDED == TRUE ) */
+
+int BTA_HfClientGetCbDataSize(tBTA_HF_CLIENT_EVT event)
+{
+    return bta_hf_client_cb_data_size[event];
+}
+#endif /* #if (BTA_HF_INCLUDED == TRUE) */
diff --git a/components/bt/bluedroid/bta/hf_client/bta_hf_client_at.c b/components/bt/bluedroid/bta/hf_client/bta_hf_client_at.c
new file mode 100644 (file)
index 0000000..51a10d9
--- /dev/null
@@ -0,0 +1,1795 @@
+/******************************************************************************
+ *
+ *  Copyright (c) 2014 The Android Open Source Project
+ *  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.
+ *
+ ******************************************************************************/
+// #include <errno.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "bta/bta_hf_client_api.h"
+#include "bta_hf_client_int.h"
+#include "stack/port_api.h"
+#include "osi/allocator.h"
+
+#if (BTA_HF_INCLUDED == TRUE)
+/* Uncomment to enable AT traffic dumping */
+/* #define BTA_HF_CLIENT_AT_DUMP 1 */
+
+/* minimum length of AT event */
+#define BTA_HF_CLIENT_AT_EVENT_MIN_LEN 3
+
+/* timeout for AT response */
+#define BTA_HF_CLIENT_AT_TIMEOUT 29989
+
+/* timeout for AT hold timer */
+#define BTA_HF_CLIENT_AT_HOLD_TIMEOUT 41
+
+/******************************************************************************
+**
+**          DATA TYPES AND CONTAINERS
+**
+*******************************************************************************/
+/* BRSF: store received values here */
+extern tBTA_HF_CLIENT_CB  bta_hf_client_cb;
+
+/******************************************************************************
+**       SUPPORTED EVENT MESSAGES
+*******************************************************************************/
+
+/* CIND: supported indicator names */
+#define BTA_HF_CLIENT_INDICATOR_BATTERYCHG  "battchg"
+#define BTA_HF_CLIENT_INDICATOR_SIGNAL      "signal"
+#define BTA_HF_CLIENT_INDICATOR_SERVICE     "service"
+#define BTA_HF_CLIENT_INDICATOR_CALL        "call"
+#define BTA_HF_CLIENT_INDICATOR_ROAM        "roam"
+#define BTA_HF_CLIENT_INDICATOR_CALLSETUP   "callsetup"
+#define BTA_HF_CLIENT_INDICATOR_CALLHELD    "callheld"
+
+#define MIN(a, b) \
+    ({ __typeof__(a) _a = (a); __typeof__(b) _b = (b); (_a < _b) ? _a : _b; })
+
+/* CIND: represents each indicators boundaries */
+typedef struct {
+    char *name;
+    UINT8 min;
+    UINT8 max;
+    UINT8 namelen;
+} tBTA_HF_CLIENT_INDICATOR;
+
+#define BTA_HF_CLIENT_AT_SUPPORTED_INDICATOR_COUNT 7
+
+/* CIND: storage room for indicators value range and their statuses */
+static const tBTA_HF_CLIENT_INDICATOR bta_hf_client_indicators[BTA_HF_CLIENT_AT_SUPPORTED_INDICATOR_COUNT] = {
+    /* name                                | min | max | name length - used by parser */
+    {BTA_HF_CLIENT_INDICATOR_BATTERYCHG,     0,   5,    sizeof(BTA_HF_CLIENT_INDICATOR_BATTERYCHG)},
+    {BTA_HF_CLIENT_INDICATOR_SIGNAL,         0,   5,    sizeof(BTA_HF_CLIENT_INDICATOR_SIGNAL)},
+    {BTA_HF_CLIENT_INDICATOR_SERVICE,        0,   1,    sizeof(BTA_HF_CLIENT_INDICATOR_SERVICE)},
+    {BTA_HF_CLIENT_INDICATOR_CALL,           0,   1,    sizeof(BTA_HF_CLIENT_INDICATOR_CALL)},
+    {BTA_HF_CLIENT_INDICATOR_ROAM,           0,   1,    sizeof(BTA_HF_CLIENT_INDICATOR_ROAM)},
+    {BTA_HF_CLIENT_INDICATOR_CALLSETUP,      0,   3,    sizeof(BTA_HF_CLIENT_INDICATOR_CALLSETUP)},
+    {BTA_HF_CLIENT_INDICATOR_CALLHELD,       0,   2,    sizeof(BTA_HF_CLIENT_INDICATOR_CALLHELD)}
+};
+
+/* +VGM/+VGS - gain min/max values  */
+#define BTA_HF_CLIENT_VGS_MIN   0
+#define BTA_HF_CLIENT_VGS_MAX  15
+#define BTA_HF_CLIENT_VGM_MIN   0
+#define BTA_HF_CLIENT_VGM_MAX  15
+
+UINT32 service_index = 0;
+BOOLEAN service_availability = TRUE;
+/* helper functions for handling AT commands queueing */
+
+static void bta_hf_client_handle_ok();
+
+static void bta_hf_client_clear_queued_at(void)
+{
+    tBTA_HF_CLIENT_AT_QCMD *cur = bta_hf_client_cb.scb.at_cb.queued_cmd;
+    tBTA_HF_CLIENT_AT_QCMD *next;
+
+    while (cur != NULL) {
+        next = cur->next;
+        osi_free(cur);
+        cur = next;
+    }
+
+    bta_hf_client_cb.scb.at_cb.queued_cmd = NULL;
+}
+
+static void bta_hf_client_queue_at(tBTA_HF_CLIENT_AT_CMD cmd, const char *buf, UINT16 buf_len)
+{
+    tBTA_HF_CLIENT_AT_QCMD *new_cmd;
+
+    APPL_TRACE_DEBUG("%s", __FUNCTION__);
+
+    if ((new_cmd = (tBTA_HF_CLIENT_AT_QCMD *) osi_malloc(sizeof(tBTA_HF_CLIENT_AT_QCMD))) != NULL) {
+        new_cmd->cmd = cmd;
+        new_cmd->buf_len = buf_len;
+        new_cmd->next = NULL;
+        memcpy(new_cmd->buf, buf, buf_len);
+
+        if (bta_hf_client_cb.scb.at_cb.queued_cmd != NULL) {
+            tBTA_HF_CLIENT_AT_QCMD *qcmd = bta_hf_client_cb.scb.at_cb.queued_cmd;
+
+            while (qcmd->next != NULL) {
+                qcmd = qcmd->next;
+            }
+
+            qcmd->next = new_cmd;
+        } else {
+            bta_hf_client_cb.scb.at_cb.queued_cmd = new_cmd;
+        }
+    }
+}
+
+static void bta_hf_client_at_resp_timer_cback (TIMER_LIST_ENT *p_tle)
+{
+    if (p_tle) {
+        bta_hf_client_cb.scb.at_cb.resp_timer_on = FALSE;
+
+        APPL_TRACE_ERROR("HFPClient: AT response timeout, disconnecting");
+
+        bta_hf_client_sm_execute(BTA_HF_CLIENT_API_CLOSE_EVT, NULL);
+    }
+}
+
+static void bta_hf_client_stop_at_resp_timer(void)
+{
+    if (bta_hf_client_cb.scb.at_cb.resp_timer_on) {
+        bta_hf_client_cb.scb.at_cb.resp_timer_on = FALSE;
+        bta_sys_stop_timer (&bta_hf_client_cb.scb.at_cb.resp_timer);
+    }
+}
+
+static void bta_hf_client_free_at_resp_timer(void)
+{
+    bta_hf_client_cb.scb.at_cb.resp_timer_on = FALSE;
+    bta_sys_free_timer (&bta_hf_client_cb.scb.at_cb.resp_timer);
+}
+
+static void bta_hf_client_start_at_resp_timer(void)
+{
+    if (bta_hf_client_cb.scb.at_cb.resp_timer_on) {
+        bta_sys_stop_timer (&bta_hf_client_cb.scb.at_cb.resp_timer);
+    }
+
+    bta_hf_client_cb.scb.at_cb.resp_timer.p_cback = (TIMER_CBACK *)&bta_hf_client_at_resp_timer_cback;
+    bta_sys_start_timer(&bta_hf_client_cb.scb.at_cb.resp_timer, 0, BTA_HF_CLIENT_AT_TIMEOUT);
+    bta_hf_client_cb.scb.at_cb.resp_timer_on = TRUE;
+}
+
+static void bta_hf_client_send_at(tBTA_HF_CLIENT_AT_CMD cmd, char *buf, UINT16 buf_len)
+{
+    if ((bta_hf_client_cb.scb.at_cb.current_cmd == BTA_HF_CLIENT_AT_NONE ||
+            bta_hf_client_cb.scb.svc_conn == FALSE) &&
+            bta_hf_client_cb.scb.at_cb.hold_timer_on == FALSE) {
+        UINT16  len;
+
+#ifdef BTA_HF_CLIENT_AT_DUMP
+        APPL_TRACE_DEBUG("%s %.*s", __FUNCTION__, buf_len - 1, buf);
+#endif
+
+        bta_hf_client_cb.scb.at_cb.current_cmd = cmd;
+        /* Generate fake responses for these because they won't reliably work */
+        if (!service_availability &&
+                (cmd == BTA_HF_CLIENT_AT_CNUM || cmd == BTA_HF_CLIENT_AT_COPS)) {
+            APPL_TRACE_WARNING("%s: No service, skipping %d command", __FUNCTION__, cmd);
+            bta_hf_client_handle_ok();
+            return;
+        }
+
+        PORT_WriteData(bta_hf_client_cb.scb.conn_handle, buf, buf_len, &len);
+
+        bta_hf_client_start_at_resp_timer();
+
+        return;
+    }
+
+    bta_hf_client_queue_at(cmd, buf, buf_len);
+}
+
+static void bta_hf_client_send_queued_at(void)
+{
+    tBTA_HF_CLIENT_AT_QCMD *cur = bta_hf_client_cb.scb.at_cb.queued_cmd;
+
+    APPL_TRACE_DEBUG("%s", __FUNCTION__);
+
+    if (cur != NULL) {
+        bta_hf_client_cb.scb.at_cb.queued_cmd = cur->next;
+
+        bta_hf_client_send_at(cur->cmd, cur->buf, cur->buf_len);
+
+        osi_free(cur);
+    }
+}
+
+static void bta_hf_client_at_hold_timer_cback(TIMER_LIST_ENT *p_tle)
+{
+    APPL_TRACE_DEBUG("%s", __FUNCTION__);
+
+    if (p_tle) {
+        bta_hf_client_cb.scb.at_cb.hold_timer_on = FALSE;
+        bta_hf_client_send_queued_at();
+    }
+}
+
+static void bta_hf_client_stop_at_hold_timer(void)
+{
+    APPL_TRACE_DEBUG("%s", __FUNCTION__);
+
+    if (bta_hf_client_cb.scb.at_cb.hold_timer_on) {
+        bta_hf_client_cb.scb.at_cb.hold_timer_on = FALSE;
+        bta_sys_stop_timer (&bta_hf_client_cb.scb.at_cb.hold_timer);
+    }
+}
+
+static void bta_hf_client_free_at_hold_timer(void)
+{
+    APPL_TRACE_DEBUG("%s", __FUNCTION__);
+
+    bta_hf_client_cb.scb.at_cb.hold_timer_on = FALSE;
+    bta_sys_free_timer(&bta_hf_client_cb.scb.at_cb.hold_timer);
+}
+
+static void bta_hf_client_start_at_hold_timer(void)
+{
+    TIMER_LIST_ENT *timer = &bta_hf_client_cb.scb.at_cb.hold_timer;
+
+    APPL_TRACE_DEBUG("%s", __FUNCTION__);
+
+    if (bta_hf_client_cb.scb.at_cb.hold_timer_on) {
+        bta_sys_stop_timer (timer);
+    }
+
+    timer->p_cback = (TIMER_CBACK *)&bta_hf_client_at_hold_timer_cback;
+    bta_sys_start_timer(timer, 0, BTA_HF_CLIENT_AT_HOLD_TIMEOUT);
+    bta_hf_client_cb.scb.at_cb.hold_timer_on = TRUE;
+}
+
+/******************************************************************************
+**
+**          COMMON AT EVENT HANDLING FUNCTIONS
+**
+**   Receives data (strings, ints, etc.) from the parser and processes this data.
+**   No buffer parsing is being done here.
+*******************************************************************************/
+
+static void bta_hf_client_handle_ok()
+{
+    APPL_TRACE_DEBUG("%s", __FUNCTION__);
+
+    bta_hf_client_stop_at_resp_timer();
+
+    if (!bta_hf_client_cb.scb.svc_conn) {
+        bta_hf_client_slc_seq(FALSE);
+        return;
+    }
+
+    switch (bta_hf_client_cb.scb.at_cb.current_cmd) {
+    case BTA_HF_CLIENT_AT_BIA:
+    case BTA_HF_CLIENT_AT_BCC:
+        break;
+    case BTA_HF_CLIENT_AT_BCS:
+        bta_hf_client_start_at_hold_timer();
+        bta_hf_client_cb.scb.at_cb.current_cmd = BTA_HF_CLIENT_AT_NONE;
+        return;
+    case BTA_HF_CLIENT_AT_CLIP: //last cmd is post slc seq
+        if (bta_hf_client_cb.scb.send_at_reply == FALSE) {
+            bta_hf_client_cb.scb.send_at_reply = TRUE;
+        }
+        break;
+    case BTA_HF_CLIENT_AT_NONE:
+        bta_hf_client_stop_at_hold_timer();
+        break;
+    default:
+        if (bta_hf_client_cb.scb.send_at_reply) {
+            bta_hf_client_at_result(BTA_HF_CLIENT_AT_RESULT_OK, 0);
+        }
+        break;
+    }
+
+    bta_hf_client_cb.scb.at_cb.current_cmd = BTA_HF_CLIENT_AT_NONE;
+
+    bta_hf_client_send_queued_at();
+}
+
+static void bta_hf_client_handle_error(tBTA_HF_CLIENT_AT_RESULT_TYPE type, UINT16 cme)
+{
+    APPL_TRACE_DEBUG("%s %u %u", __FUNCTION__, type, cme);
+
+    bta_hf_client_stop_at_resp_timer();
+
+    if (!bta_hf_client_cb.scb.svc_conn) {
+        bta_hf_client_slc_seq(TRUE);
+        return;
+    }
+
+    switch (bta_hf_client_cb.scb.at_cb.current_cmd) {
+    case BTA_HF_CLIENT_AT_BIA:
+        break;
+    case BTA_HF_CLIENT_AT_BCC:
+    case BTA_HF_CLIENT_AT_BCS:
+        bta_hf_client_cback_sco(BTA_HF_CLIENT_AUDIO_CLOSE_EVT);
+        break;
+    case BTA_HF_CLIENT_AT_CLIP: //last cmd is post slc seq
+        if (bta_hf_client_cb.scb.send_at_reply == FALSE) {
+            bta_hf_client_cb.scb.send_at_reply = TRUE;
+        }
+        break;
+    default:
+        if (bta_hf_client_cb.scb.send_at_reply) {
+            bta_hf_client_at_result(type, cme);
+        }
+        break;
+    }
+
+    bta_hf_client_cb.scb.at_cb.current_cmd = BTA_HF_CLIENT_AT_NONE;
+
+    bta_hf_client_send_queued_at();
+}
+
+static void bta_hf_client_handle_ring()
+{
+    APPL_TRACE_DEBUG("%s", __FUNCTION__);
+    bta_hf_client_evt_val(BTA_HF_CLIENT_RING_INDICATION, 0);
+}
+
+static void bta_hf_client_handle_brsf(UINT32 value)
+{
+    APPL_TRACE_DEBUG("%s 0x%x", __FUNCTION__, value);
+    bta_hf_client_cb.scb.peer_features = value;
+}
+
+/* handles a single indicator descriptor - registers it for value changing events */
+static void bta_hf_client_handle_cind_list_item(char *name, UINT32 min, UINT32 max, UINT32 index)
+{
+
+    UINT8 i = 0;
+
+    APPL_TRACE_DEBUG("%s %u.%s <%u:%u>", __FUNCTION__, index, name, min, max);
+
+    /* look for a matching indicator on list of supported ones */
+    for (i = 0; i < BTA_HF_CLIENT_AT_SUPPORTED_INDICATOR_COUNT; i++) {
+        if (strcmp(name, BTA_HF_CLIENT_INDICATOR_SERVICE) == 0) {
+            service_index = index;
+        }
+        /* look for a match - search one sign further than indicators name to check for string end */
+        /* It will distinguish 'callheld' which could be matched by strncmp as 'call'.               */
+        if (strncmp(name, bta_hf_client_indicators[i].name, bta_hf_client_indicators[i].namelen) != 0) {
+            continue;
+        }
+
+        /* index - enumerates value position in the incoming sequence                      */
+        /* if name matches one of the known indicators, add its incoming position          */
+        /* to lookup table for easy value->indicator matching later, when only values come  */
+        bta_hf_client_cb.scb.at_cb.indicator_lookup[index] = i;
+
+        return;
+    }
+}
+
+static void bta_hf_client_handle_cind_value(UINT32 index, UINT32 value)
+{
+    APPL_TRACE_DEBUG("%s index: %u value: %u", __FUNCTION__, index, value);
+
+    if (index >= BTA_HF_CLIENT_AT_INDICATOR_COUNT) {
+        return;
+    }
+
+    if (service_index == index) {
+        if (value == 0) {
+            service_availability = FALSE;
+        } else {
+            service_availability = TRUE;
+        }
+    }
+    if (bta_hf_client_cb.scb.at_cb.indicator_lookup[index] == -1) {
+        return;
+    }
+
+    /* get the real array index from lookup table */
+    index = bta_hf_client_cb.scb.at_cb.indicator_lookup[index];
+
+    /* Ignore out of range values */
+    if (value > bta_hf_client_indicators[index].max ||
+            value < bta_hf_client_indicators[index].min) {
+        return;
+    }
+
+    /* tBTA_HF_CLIENT_IND_TYPE match index in bta_hf_client_indicators */
+    bta_hf_client_ind(index, value);
+}
+
+static void bta_hf_client_handle_chld(UINT32 mask)
+{
+    APPL_TRACE_DEBUG("%s 0x%x", __FUNCTION__, mask);
+
+    bta_hf_client_cb.scb.chld_features |= mask;
+}
+
+static void bta_hf_client_handle_ciev(UINT32 index, UINT32 value)
+{
+    INT8 realind = -1;
+
+    APPL_TRACE_DEBUG("%s index: %u value: %u", __FUNCTION__, index, value);
+
+    if (index == 0 || index > BTA_HF_CLIENT_AT_INDICATOR_COUNT) {
+        return;
+    }
+
+    if (service_index == index - 1) {
+        service_availability = value == 0 ? FALSE : TRUE;
+    }
+
+    realind = bta_hf_client_cb.scb.at_cb.indicator_lookup[index - 1];
+
+    if (realind >= 0 && realind < BTA_HF_CLIENT_AT_SUPPORTED_INDICATOR_COUNT) {
+        /* get the real in-array index from lookup table by index it comes at */
+        /* if there is no bug it should automatically be correctly calculated    */
+        if (value > bta_hf_client_indicators[realind].max || value < bta_hf_client_indicators[realind].min) {
+            return;
+        }
+
+        /* update service availability on +ciev from AG. */
+        if (service_index == (index - 1)) {
+            if (value == 1) {
+                service_availability = TRUE;
+            } else {
+                service_availability = FALSE;
+            }
+        }
+
+        /* tBTA_HF_CLIENT_IND_TYPE match index in bta_hf_client_indicators */
+        bta_hf_client_ind(realind, value);
+    }
+}
+
+static void bta_hf_client_handle_bcs(UINT32 codec)
+{
+    APPL_TRACE_DEBUG("%s %u", __FUNCTION__, codec);
+
+    if (codec == BTM_SCO_CODEC_CVSD ||
+            (codec == BTM_SCO_CODEC_MSBC && bta_hf_client_cb.msbc_enabled == TRUE)) {
+        bta_hf_client_cb.scb.negotiated_codec = codec;
+        bta_hf_client_send_at_bcs(codec);
+    } else {
+        bta_hf_client_cb.scb.negotiated_codec = BTM_SCO_CODEC_CVSD;
+        bta_hf_client_send_at_bac();
+    }
+}
+
+static void bta_hf_client_handle_bsir(UINT32 provided)
+{
+    APPL_TRACE_DEBUG("%s %u", __FUNCTION__, provided);
+
+    bta_hf_client_evt_val(BTA_HF_CLIENT_BSIR_EVT, provided);
+}
+
+static void bta_hf_client_handle_cmeerror(UINT32 code)
+{
+    bta_hf_client_handle_error(BTA_HF_CLIENT_AT_RESULT_CME, code);
+}
+
+static void bta_hf_client_handle_vgm(UINT32 value)
+{
+    APPL_TRACE_DEBUG("%s %u", __FUNCTION__, value);
+
+    if (value <= BTA_HF_CLIENT_VGM_MAX) {
+        bta_hf_client_evt_val(BTA_HF_CLIENT_MIC_EVT, value);
+    }
+}
+
+static void bta_hf_client_handle_vgs(UINT32 value)
+{
+    APPL_TRACE_DEBUG("%s %u", __FUNCTION__, value);
+
+    if (value <= BTA_HF_CLIENT_VGS_MAX) {
+        bta_hf_client_evt_val(BTA_HF_CLIENT_SPK_EVT, value);
+    }
+}
+
+static void bta_hf_client_handle_bvra(UINT32 value)
+{
+    APPL_TRACE_DEBUG("%s %u", __FUNCTION__, value);
+
+    if (value > 1) {
+        return;
+    }
+
+    bta_hf_client_evt_val(BTA_HF_CLIENT_VOICE_REC_EVT, value);
+}
+
+static void bta_hf_client_handle_clip(char *numstr, UINT32 type)
+{
+    APPL_TRACE_DEBUG("%s %u %s", __FUNCTION__, type, numstr);
+
+    bta_hf_client_clip(numstr);
+}
+
+static void bta_hf_client_handle_ccwa(char *numstr, UINT32 type)
+{
+    APPL_TRACE_DEBUG("%s %u %s", __FUNCTION__, type, numstr);
+
+    bta_hf_client_ccwa(numstr);
+}
+
+static void bta_hf_client_handle_cops(char *opstr, UINT32 mode)
+{
+    APPL_TRACE_DEBUG("%s %u %s", __FUNCTION__, mode, opstr);
+
+    bta_hf_client_operator_name(opstr);
+}
+
+static void bta_hf_client_handle_binp(char *numstr)
+{
+    APPL_TRACE_DEBUG("%s %s", __FUNCTION__, numstr);
+
+    bta_hf_client_binp(numstr);
+}
+
+static void bta_hf_client_handle_clcc(UINT16 idx, UINT16 dir, UINT16 status, UINT16 mode, UINT16 mpty, char *numstr, UINT16 type)
+{
+    APPL_TRACE_DEBUG("%s idx: %u dir: %u status: %u mode: %u mpty: %u",
+                     __FUNCTION__, idx, dir, status, mode, mpty);
+
+    if (numstr) {
+        APPL_TRACE_DEBUG("%s number: %s  type: %u", __FUNCTION__, numstr, type);
+    }
+
+    bta_hf_client_clcc(idx, dir, status, mpty, numstr);
+}
+
+static void bta_hf_client_handle_cnum( char *numstr, UINT16 type, UINT16 service)
+{
+    APPL_TRACE_DEBUG("%s number: %s type: %u service: %u", __FUNCTION__, numstr, type, service);
+
+    /* TODO: should number be modified according to type? */
+    bta_hf_client_cnum(numstr, service);
+}
+
+static void bta_hf_client_handle_btrh( UINT16 code)
+{
+    APPL_TRACE_DEBUG("%s %u", __FUNCTION__, code);
+
+    bta_hf_client_evt_val(BTA_HF_CLIENT_BTRH_EVT, code);
+}
+
+/******************************************************************************
+**
+**          COMMON AT EVENTS PARSING FUNCTIONS
+**
+*******************************************************************************/
+
+/* Check if prefix match and skip spaces if any */
+#define AT_CHECK_EVENT(buf, event) \
+    if (strncmp("\r\n"event, buf,sizeof("\r\n"event) - 1) != 0) return buf; \
+    buf += sizeof("\r\n"event) - 1; \
+    while (*buf == ' ') buf++;
+
+/* check for <cr><lf> and forward buffer if match */
+#define AT_CHECK_RN(buf) \
+    if (strncmp("\r\n", buf, sizeof("\r\n") - 1) != 0) { \
+        APPL_TRACE_DEBUG("%s missing end <cr><lf>", __FUNCTION__); \
+        return NULL;} \
+    buf += sizeof("\r\n") - 1;
+
+/* skip rest of AT string up to <cr> */
+#define AT_SKIP_REST(buf) while(*buf != '\r') buf++;
+
+static char *bta_hf_client_parse_ok(char *buffer)
+{
+    AT_CHECK_EVENT(buffer, "OK");
+    AT_CHECK_RN(buffer);
+
+    bta_hf_client_handle_ok();
+
+    return buffer;
+}
+
+static char *bta_hf_client_parse_error(char *buffer)
+{
+    AT_CHECK_EVENT(buffer, "ERROR");
+    AT_CHECK_RN(buffer);
+
+    bta_hf_client_handle_error(BTA_HF_CLIENT_AT_RESULT_ERROR, 0);
+
+    return buffer;
+}
+
+static char *bta_hf_client_parse_ring(char *buffer)
+{
+    AT_CHECK_EVENT(buffer, "RING");
+    AT_CHECK_RN(buffer);
+
+    bta_hf_client_handle_ring();
+
+    return buffer;
+}
+
+/* generic uint32 parser */
+static char *bta_hf_client_parse_uint32(char *buffer, void (*handler_callback)(UINT32))
+{
+    UINT32 value;
+    int res;
+    int offset;
+
+    res = sscanf(buffer, "%u%n", &value, &offset);
+    if (res < 1) {
+        return NULL;
+    }
+
+    buffer += offset;
+
+    AT_CHECK_RN(buffer);
+
+    handler_callback(value);
+    return buffer;
+}
+
+static char *bta_hf_client_parse_brsf(char *buffer)
+{
+    AT_CHECK_EVENT(buffer, "+BRSF:");
+
+    return bta_hf_client_parse_uint32(buffer, bta_hf_client_handle_brsf);
+}
+
+static char *bta_hf_client_parse_cind_values(char *buffer)
+{
+    /* value and its position */
+    UINT16 index = 0;
+    UINT32 value = 0;
+
+    int offset;
+    int res;
+
+    while ((res = sscanf(buffer, "%u%n", &value, &offset)) > 0) {
+        /* decides if its valid index and value, if yes stores it */
+        bta_hf_client_handle_cind_value(index, value);
+
+        buffer += offset;
+
+        /* check if more values are present */
+        if (*buffer != ',') {
+            break;
+        }
+
+        index++;
+        buffer++;
+    }
+
+    if (res > 0) {
+        AT_CHECK_RN(buffer);
+        return buffer;
+    }
+
+    return NULL;
+}
+
+static char *bta_hf_client_parse_cind_list(char *buffer)
+{
+    int offset;
+    char *name = osi_malloc(129);
+    UINT32 min, max;
+    UINT32 index = 0;
+    int res;
+
+    if (name == NULL) {
+        APPL_TRACE_ERROR("No mem %s", __FUNCTION__);
+        return NULL;
+    }
+
+    while ((res = sscanf(buffer, "(\"%128[^\"]\",(%u%*[-,]%u))%n", name, &min, &max, &offset)) > 2) {
+        bta_hf_client_handle_cind_list_item(name, min, max, index);
+        buffer += offset;
+        index++;
+
+        if (*buffer != ',') {
+            break;
+        }
+
+        buffer++;
+    }
+
+    osi_free(name);
+
+    if (res > 2) {
+        AT_CHECK_RN(buffer);
+        return buffer;
+    }
+
+    return NULL;
+}
+
+static char *bta_hf_client_parse_cind(char *buffer)
+{
+    AT_CHECK_EVENT(buffer, "+CIND:");
+
+    if (*buffer == '(') {
+        return bta_hf_client_parse_cind_list(buffer);
+    }
+
+    return bta_hf_client_parse_cind_values(buffer);
+}
+
+static char *bta_hf_client_parse_chld(char *buffer)
+{
+    AT_CHECK_EVENT(buffer, "+CHLD:");
+
+    if (*buffer != '(') {
+        return NULL;
+    }
+
+    buffer++;
+
+    while (*buffer != '\0') {
+        if (strncmp("0", buffer, 1) == 0) {
+            bta_hf_client_handle_chld(BTA_HF_CLIENT_CHLD_REL);
+            buffer++;
+        } else if (strncmp("1x", buffer, 2) == 0) {
+            bta_hf_client_handle_chld(BTA_HF_CLIENT_CHLD_REL_X);
+            buffer += 2;
+        } else if (strncmp("1", buffer, 1) == 0) {
+            bta_hf_client_handle_chld(BTA_HF_CLIENT_CHLD_REL_ACC);
+            buffer++;
+        } else if (strncmp("2x", buffer, 2) == 0) {
+            bta_hf_client_handle_chld(BTA_HF_CLIENT_CHLD_PRIV_X);
+            buffer += 2;
+        } else if (strncmp("2", buffer, 1) == 0) {
+            bta_hf_client_handle_chld(BTA_HF_CLIENT_CHLD_HOLD_ACC);
+            buffer++;
+        } else if (strncmp("3", buffer, 1) == 0) {
+            bta_hf_client_handle_chld(BTA_HF_CLIENT_CHLD_MERGE);
+            buffer++;
+        } else if (strncmp("4", buffer, 1) == 0) {
+            bta_hf_client_handle_chld(BTA_HF_CLIENT_CHLD_MERGE_DETACH);
+            buffer++;
+        } else {
+            return NULL;
+        }
+
+        if (*buffer == ',') {
+            buffer++;
+            continue;
+        }
+
+        if (*buffer == ')') {
+            buffer++;
+            break;
+        }
+
+        return NULL;
+    }
+
+    AT_CHECK_RN(buffer);
+
+    return buffer;
+}
+
+static char *bta_hf_client_parse_ciev(char *buffer)
+{
+    UINT32 index, value;
+    int res;
+    int offset;
+
+    AT_CHECK_EVENT(buffer, "+CIEV:");
+
+    res = sscanf(buffer, "%u,%u%n", &index, &value, &offset);
+    if (res < 2) {
+        return NULL;
+    }
+
+    buffer += offset;
+
+    AT_CHECK_RN(buffer);
+
+    bta_hf_client_handle_ciev(index, value);
+    return buffer;
+}
+
+static char *bta_hf_client_parse_bcs(char *buffer)
+{
+    AT_CHECK_EVENT(buffer, "+BCS:");
+
+    return bta_hf_client_parse_uint32(buffer, bta_hf_client_handle_bcs);
+}
+
+static char *bta_hf_client_parse_bsir(char *buffer)
+{
+    AT_CHECK_EVENT(buffer, "+BSIR:");
+
+    return bta_hf_client_parse_uint32(buffer, bta_hf_client_handle_bsir);
+}
+
+static char *bta_hf_client_parse_cmeerror(char *buffer)
+{
+    AT_CHECK_EVENT(buffer, "+CME ERROR:");
+
+    return bta_hf_client_parse_uint32(buffer, bta_hf_client_handle_cmeerror);
+}
+
+static char *bta_hf_client_parse_vgm(char *buffer)
+{
+    AT_CHECK_EVENT(buffer, "+VGM:");
+
+    return bta_hf_client_parse_uint32(buffer, bta_hf_client_handle_vgm);
+}
+
+static char *bta_hf_client_parse_vgme(char *buffer)
+{
+    AT_CHECK_EVENT(buffer, "+VGM=");
+
+    return bta_hf_client_parse_uint32(buffer, bta_hf_client_handle_vgm);
+}
+
+static char *bta_hf_client_parse_vgs(char *buffer)
+{
+    AT_CHECK_EVENT(buffer, "+VGS:");
+
+    return bta_hf_client_parse_uint32(buffer, bta_hf_client_handle_vgs);
+}
+
+static char *bta_hf_client_parse_vgse(char *buffer)
+{
+    AT_CHECK_EVENT(buffer, "+VGS=");
+
+    return bta_hf_client_parse_uint32(buffer, bta_hf_client_handle_vgs);
+}
+
+static char *bta_hf_client_parse_bvra(char *buffer)
+{
+    AT_CHECK_EVENT(buffer, "+BVRA:");
+
+    return bta_hf_client_parse_uint32(buffer, bta_hf_client_handle_bvra);
+}
+
+static char *bta_hf_client_parse_clip(char *buffer)
+{
+    /* spec forces 32 chars, plus \0 here */
+    char number[33];
+    UINT32 type = 0;
+    int res;
+    int offset;
+
+    AT_CHECK_EVENT(buffer, "+CLIP:");
+
+    /* there might be something more after %lu but HFP doesn't care */
+    res = sscanf(buffer, "\"%32[^\"]\",%u%n", number, &type, &offset);
+    if (res < 2) {
+        return NULL;
+    }
+
+    buffer += offset;
+
+    AT_SKIP_REST(buffer);
+
+    AT_CHECK_RN(buffer);
+
+    bta_hf_client_handle_clip(number, type);
+    return buffer;
+}
+
+/* in HFP context there is no difference between ccwa and clip */
+static char *bta_hf_client_parse_ccwa(char *buffer)
+{
+    /* ac to spec 32 chars max, plus \0 here */
+    char number[33];
+    UINT32 type = 0;
+    int res ;
+    int offset;
+
+    AT_CHECK_EVENT(buffer, "+CCWA:");
+
+    /* there might be something more after %lu but HFP doesn't care */
+    res = sscanf(buffer, "\"%32[^\"]\",%u%n", number, &type, &offset);
+    if (res < 2) {
+        return NULL;
+    }
+
+    buffer += offset;
+
+    AT_SKIP_REST(buffer);
+
+    AT_CHECK_RN(buffer);
+
+    bta_hf_client_handle_ccwa(number, type);
+    return buffer;
+}
+
+static char *bta_hf_client_parse_cops(char *buffer)
+{
+    UINT8 mode;
+    /* spec forces 16 chars max, plus \0 here */
+    char opstr[17];
+    int res;
+    int offset;
+
+    AT_CHECK_EVENT(buffer, "+COPS:");
+
+    /* TODO: Not sure if operator string actually can contain escaped " char inside */
+    res = sscanf(buffer, "%hhi,0,\"%16[^\"]\"%n", &mode, opstr, &offset);
+    if (res < 2) {
+        return NULL;
+    }
+
+    buffer += offset;
+
+    AT_SKIP_REST(buffer);
+
+    AT_CHECK_RN(buffer);
+
+    bta_hf_client_handle_cops(opstr, mode);
+    return buffer;
+}
+
+static char *bta_hf_client_parse_binp(char *buffer)
+{
+    /* HFP only supports phone number as BINP data */
+    /* phone number is 32 chars plus one for \0*/
+    char numstr[33];
+    int res;
+    int offset;
+
+    AT_CHECK_EVENT(buffer, "+BINP:");
+
+    res = sscanf(buffer, "\"%32[^\"]\"\r\n%n", numstr, &offset);
+    if (res < 1) {
+        return NULL;
+    }
+
+    buffer += offset;
+
+    /* some phones might sent type as well, just skip it */
+    AT_SKIP_REST(buffer);
+
+    AT_CHECK_RN(buffer);
+
+    bta_hf_client_handle_binp(numstr);
+    return buffer;
+}
+
+static char *bta_hf_client_parse_clcc(char *buffer)
+{
+    UINT16 idx, dir, status, mode, mpty;
+    char numstr[33];     /* spec forces 32 chars, plus one for \0*/
+    UINT16 type;
+    int res;
+    int offset;
+    AT_CHECK_EVENT(buffer, "+CLCC:");
+
+    res = sscanf(buffer, "%hu,%hu,%hu,%hu,%hu%n",
+                 &idx, &dir, &status, &mode, &mpty, &offset);
+    if (res < 5) {
+        return NULL;
+    }
+
+    buffer += offset;
+
+    /* check optional part */
+    if (*buffer == ',') {
+        int res2;
+
+        res2 = sscanf(buffer, ",\"%32[^\"]\",%hu%n", numstr, &type, &offset);
+        if (res2 < 0) {
+            return NULL;
+        }
+
+        if (res2 == 0) {
+            res2 = sscanf(buffer, ",\"\",%hu%n", &type, &offset);
+            if (res < 0) {
+                return NULL;
+            }
+
+            /* numstr is not matched in second attempt, correct this */
+            res2++;
+            numstr[0] = '\0';
+        }
+
+        if (res2 < 2) {
+            return NULL;
+        }
+
+        res += res2;
+        buffer += offset;
+    }
+
+    AT_CHECK_RN(buffer);
+
+    if (res > 6) {
+        /* we also have last two optional parameters */
+        bta_hf_client_handle_clcc(idx, dir, status, mode, mpty, numstr, type);
+    } else {
+        /* we didn't get the last two parameters */
+        bta_hf_client_handle_clcc(idx, dir, status, mode, mpty, NULL, 0);
+    }
+
+    return buffer;
+}
+
+static char *bta_hf_client_parse_cnum(char *buffer)
+{
+    char numstr[33];     /* spec forces 32 chars, plus one for \0*/
+    UINT16 type;
+    UINT16 service = 0; /* 0 in case this optional parameter is not being sent */
+    int res;
+    int offset;
+
+    AT_CHECK_EVENT(buffer, "+CNUM:");
+
+    res = sscanf(buffer, ",\"%32[^\"]\",%hu,,%hu%n", numstr, &type, &service, &offset);
+    if (res < 0) {
+        return NULL;
+    }
+
+    if (res == 0) {
+        res = sscanf(buffer, ",\"\",%hu,,%hu%n", &type, &service, &offset);
+        if (res < 0) {
+            return NULL;
+        }
+
+        /* numstr is not matched in second attempt, correct this */
+        res++;
+        numstr[0] = '\0';
+    }
+
+    if (res < 3) {
+        return NULL;
+    }
+
+    buffer += offset;
+
+    AT_CHECK_RN(buffer);
+
+    /* service is optional */
+    if (res == 2) {
+        bta_hf_client_handle_cnum(numstr, type, service);
+        return buffer;
+    }
+
+    if (service != 4 && service != 5) {
+        return NULL;
+    }
+
+    bta_hf_client_handle_cnum(numstr, type, service);
+    return buffer;
+}
+
+static char *bta_hf_client_parse_btrh(char *buffer)
+{
+    UINT16 code = 0;
+    int res;
+    int offset;
+
+    AT_CHECK_EVENT(buffer, "+BTRH:");
+
+    res = sscanf(buffer, "%hu%n", &code, &offset);
+    if (res < 1) {
+        return NULL;
+    }
+
+    buffer += offset;
+
+    AT_CHECK_RN(buffer);
+
+    bta_hf_client_handle_btrh(code);
+    return buffer;
+}
+
+static char *bta_hf_client_parse_busy(char *buffer)
+{
+    AT_CHECK_EVENT(buffer, "BUSY");
+    AT_CHECK_RN(buffer);
+
+    bta_hf_client_handle_error(BTA_HF_CLIENT_AT_RESULT_BUSY, 0);
+
+    return buffer;
+}
+
+static char *bta_hf_client_parse_delayed(char *buffer)
+{
+    AT_CHECK_EVENT(buffer, "DELAYED");
+    AT_CHECK_RN(buffer);
+
+    bta_hf_client_handle_error(BTA_HF_CLIENT_AT_RESULT_DELAY, 0);
+
+    return buffer;
+}
+
+static char *bta_hf_client_parse_no_carrier(char *buffer)
+{
+    AT_CHECK_EVENT(buffer, "NO CARRIER");
+    AT_CHECK_RN(buffer);
+
+    bta_hf_client_handle_error(BTA_HF_CLIENT_AT_RESULT_NO_CARRIER, 0);
+
+    return buffer;
+}
+
+static char *bta_hf_client_parse_no_answer(char *buffer)
+{
+    AT_CHECK_EVENT(buffer, "NO ANSWER");
+    AT_CHECK_RN(buffer);
+
+    bta_hf_client_handle_error(BTA_HF_CLIENT_AT_RESULT_NO_ANSWER, 0);
+
+    return buffer;
+}
+
+static char *bta_hf_client_parse_blacklisted(char *buffer)
+{
+    AT_CHECK_EVENT(buffer, "BLACKLISTED");
+    AT_CHECK_RN(buffer);
+
+    bta_hf_client_handle_error(BTA_HF_CLIENT_AT_RESULT_BLACKLISTED, 0);
+
+    return buffer;
+}
+
+static char *bta_hf_client_skip_unknown(char *buffer)
+{
+    char *start;
+    char *tmp;
+
+    tmp = strstr(buffer, "\r\n");
+    if (tmp == NULL) {
+        return NULL;
+    }
+
+    buffer += 2;
+    start = buffer;
+
+    tmp = strstr(buffer, "\r\n");
+    if (tmp == NULL) {
+        return NULL;
+    }
+
+    buffer = tmp + 2;
+
+    APPL_TRACE_DEBUG("%s %.*s", __FUNCTION__, buffer - start - 2, start);
+
+    return buffer;
+}
+
+
+/******************************************************************************
+**       SUPPORTED EVENT MESSAGES
+*******************************************************************************/
+
+/* returned values are as follow:
+ * != NULL && != buf  : match and parsed ok
+ * == NULL            : match but parse failed
+ * != NULL && == buf  : no match
+ */
+typedef char *(*tBTA_HF_CLIENT_PARSER_CALLBACK)(char *);
+
+static const tBTA_HF_CLIENT_PARSER_CALLBACK bta_hf_client_parser_cb[] = {
+    bta_hf_client_parse_ok,
+    bta_hf_client_parse_error,
+    bta_hf_client_parse_ring,
+    bta_hf_client_parse_brsf,
+    bta_hf_client_parse_cind,
+    bta_hf_client_parse_ciev,
+    bta_hf_client_parse_chld,
+    bta_hf_client_parse_bcs,
+    bta_hf_client_parse_bsir,
+    bta_hf_client_parse_cmeerror,
+    bta_hf_client_parse_vgm,
+    bta_hf_client_parse_vgme,
+    bta_hf_client_parse_vgs,
+    bta_hf_client_parse_vgse,
+    bta_hf_client_parse_bvra,
+    bta_hf_client_parse_clip,
+    bta_hf_client_parse_ccwa,
+    bta_hf_client_parse_cops,
+    bta_hf_client_parse_binp,
+    bta_hf_client_parse_clcc,
+    bta_hf_client_parse_cnum,
+    bta_hf_client_parse_btrh,
+    bta_hf_client_parse_busy,
+    bta_hf_client_parse_delayed,
+    bta_hf_client_parse_no_carrier,
+    bta_hf_client_parse_no_answer,
+    bta_hf_client_parse_blacklisted,
+    bta_hf_client_skip_unknown
+};
+
+/* calculate supported event list length */
+static const UINT16 bta_hf_client_psraser_cb_count =
+    sizeof(bta_hf_client_parser_cb) / sizeof(bta_hf_client_parser_cb[0]);
+
+#ifdef BTA_HF_CLIENT_AT_DUMP
+static void bta_hf_client_dump_at(void)
+{
+    char dump[(4 * BTA_HF_CLIENT_AT_PARSER_MAX_LEN) + 1];
+    char *p1, *p2;
+
+    p1 = bta_hf_client_cb.scb.at_cb.buf;
+    p2 = dump;
+
+    while (*p1 != '\0') {
+        if (*p1 == '\r') {
+            strlcpy(p2, "<cr>", 4);
+            p2 += 4;
+        } else if (*p1 == '\n') {
+            strlcpy(p2, "<lf>", 4);
+            p2 += 4;
+        } else {
+            *p2 = *p1;
+            p2++;
+        }
+        p1++;
+    }
+
+    *p2 = '\0';
+
+    APPL_TRACE_DEBUG("%s %s", __FUNCTION__, dump);
+}
+#endif
+
+static void bta_hf_client_at_parse_start(void)
+{
+    char *buf = bta_hf_client_cb.scb.at_cb.buf;
+
+    APPL_TRACE_DEBUG("%s", __FUNCTION__);
+
+#ifdef BTA_HF_CLIENT_AT_DUMP
+    bta_hf_client_dump_at();
+#endif
+
+    while (*buf != '\0') {
+        int i;
+        char *tmp = NULL;
+
+        for (i = 0; i < bta_hf_client_psraser_cb_count; i++) {
+            tmp = bta_hf_client_parser_cb[i](buf);
+            if (tmp == NULL) {
+                APPL_TRACE_ERROR("HFPCient: AT event/reply parsing failed, skipping");
+                tmp = bta_hf_client_skip_unknown(buf);
+                break;
+            }
+
+            /* matched or unknown skipped, if unknown failed tmp is NULL so
+               this is also handled */
+            if (tmp != buf) {
+                buf = tmp;
+                break;
+            }
+        }
+
+        /* could not skip unknown (received garbage?)... disconnect */
+        if (tmp == NULL) {
+            APPL_TRACE_ERROR("HFPCient: could not skip unknown AT event, disconnecting");
+            bta_hf_client_at_reset();
+            bta_hf_client_sm_execute(BTA_HF_CLIENT_API_CLOSE_EVT, NULL);
+            return;
+        }
+
+        buf = tmp;
+    }
+}
+
+static BOOLEAN bta_hf_client_check_at_complete(void)
+{
+    BOOLEAN ret = FALSE;
+    tBTA_HF_CLIENT_AT_CB *at_cb = &bta_hf_client_cb.scb.at_cb;
+
+    if (at_cb->offset >= BTA_HF_CLIENT_AT_EVENT_MIN_LEN) {
+        if (at_cb->buf[at_cb->offset - 2] == '\r' && at_cb->buf[at_cb->offset - 1] == '\n') {
+            ret = TRUE;
+        }
+    }
+
+    APPL_TRACE_DEBUG("%s %d", __FUNCTION__, ret);
+
+    return ret;
+}
+
+static void bta_hf_client_at_clear_buf(void)
+{
+    memset(bta_hf_client_cb.scb.at_cb.buf, 0, sizeof(bta_hf_client_cb.scb.at_cb.buf));
+    bta_hf_client_cb.scb.at_cb.offset = 0;
+}
+
+/******************************************************************************
+**
+**          MAIN PARSING FUNCTION
+**
+**
+*******************************************************************************/
+void bta_hf_client_at_parse(char *buf, unsigned int len)
+{
+    APPL_TRACE_DEBUG("%s offset: %u len: %u", __FUNCTION__, bta_hf_client_cb.scb.at_cb.offset, len);
+
+    if (len + bta_hf_client_cb.scb.at_cb.offset > BTA_HF_CLIENT_AT_PARSER_MAX_LEN) {
+        unsigned int tmp = bta_hf_client_cb.scb.at_cb.offset;
+        unsigned int space_left = BTA_HF_CLIENT_AT_PARSER_MAX_LEN - bta_hf_client_cb.scb.at_cb.offset;
+        char *tmp_buff = osi_malloc(BTA_HF_CLIENT_AT_PARSER_MAX_LEN);
+        if (tmp_buff == NULL) {
+            APPL_TRACE_ERROR("No mem %s", __FUNCTION__);
+            return;
+        }
+        APPL_TRACE_DEBUG("%s overrun, trying to recover", __FUNCTION__);
+
+        /* fill up parser buffer */
+        memcpy(bta_hf_client_cb.scb.at_cb.buf + bta_hf_client_cb.scb.at_cb.offset, buf, space_left);
+        len -= space_left;
+        buf += space_left;
+        bta_hf_client_cb.scb.at_cb.offset += space_left;
+
+        /* find end of last complete command before proceeding */
+        while (bta_hf_client_check_at_complete() == FALSE) {
+            if (bta_hf_client_cb.scb.at_cb.offset == 0) {
+                APPL_TRACE_ERROR("HFPClient: AT parser buffer overrun, disconnecting");
+
+                bta_hf_client_at_reset();
+                bta_hf_client_sm_execute(BTA_HF_CLIENT_API_CLOSE_EVT, NULL);
+                osi_free(tmp_buff);
+                return;
+            }
+
+            bta_hf_client_cb.scb.at_cb.offset--;
+        }
+
+        /* cut buffer to complete AT event and keep cut data */
+        tmp += space_left - bta_hf_client_cb.scb.at_cb.offset;
+        memcpy(tmp_buff, bta_hf_client_cb.scb.at_cb.buf + bta_hf_client_cb.scb.at_cb.offset, tmp);
+        bta_hf_client_cb.scb.at_cb.buf[bta_hf_client_cb.scb.at_cb.offset] = '\0';
+
+        /* parse */
+        bta_hf_client_at_parse_start();
+        bta_hf_client_at_clear_buf();
+
+        /* recover cut data */
+        memcpy(bta_hf_client_cb.scb.at_cb.buf, tmp_buff, tmp);
+        bta_hf_client_cb.scb.at_cb.offset += tmp;
+
+        osi_free(tmp_buff);
+    }
+
+    memcpy(bta_hf_client_cb.scb.at_cb.buf + bta_hf_client_cb.scb.at_cb.offset, buf, len);
+    bta_hf_client_cb.scb.at_cb.offset += len;
+
+    /* If last event is complete, parsing can be started */
+    if (bta_hf_client_check_at_complete() == TRUE) {
+        bta_hf_client_at_parse_start();
+        bta_hf_client_at_clear_buf();
+    }
+}
+
+void bta_hf_client_send_at_brsf(void)
+{
+    char *buf = osi_malloc(BTA_HF_CLIENT_AT_MAX_LEN);
+    int at_len;
+
+    if (buf == NULL) {
+        APPL_TRACE_ERROR("No mem %s", __FUNCTION__);
+        return;
+    }
+
+    APPL_TRACE_DEBUG("%s", __FUNCTION__);
+
+    at_len = snprintf(buf, BTA_HF_CLIENT_AT_MAX_LEN, "AT+BRSF=%u\r", bta_hf_client_cb.scb.features);
+
+    bta_hf_client_send_at(BTA_HF_CLIENT_AT_BRSF , buf, at_len);
+    osi_free(buf);
+}
+
+void bta_hf_client_send_at_bac(void)
+{
+    char *buf;
+
+    APPL_TRACE_DEBUG("%s", __FUNCTION__);
+
+    if (bta_hf_client_cb.msbc_enabled) {
+        buf = "AT+BAC=1,2\r";
+    } else {
+        buf = "AT+BAC=1\r";
+    }
+
+    bta_hf_client_send_at(BTA_HF_CLIENT_AT_BAC, buf, strlen(buf));
+}
+
+void bta_hf_client_send_at_bcs(UINT32 codec)
+{
+    char * buf = osi_malloc(BTA_HF_CLIENT_AT_MAX_LEN);
+    int at_len;
+
+    if (buf == NULL) {
+        APPL_TRACE_ERROR("No mem %s", __FUNCTION__);
+        return;
+    }
+
+    at_len = snprintf(buf, BTA_HF_CLIENT_AT_MAX_LEN, "AT+BCS=%u\r", codec);
+
+    bta_hf_client_send_at(BTA_HF_CLIENT_AT_BCS, buf, at_len);
+    osi_free(buf);
+}
+
+void bta_hf_client_send_at_cind(BOOLEAN status)
+{
+    char *buf;
+    tBTA_HF_CLIENT_AT_CMD cmd;
+
+    APPL_TRACE_DEBUG("%s", __FUNCTION__);
+
+    if (status) {
+        buf = "AT+CIND?\r";
+        cmd = BTA_HF_CLIENT_AT_CIND_STATUS;
+    } else {
+        buf = "AT+CIND=?\r";
+        cmd = BTA_HF_CLIENT_AT_CIND;
+    }
+
+    bta_hf_client_send_at(cmd, buf, strlen(buf));
+}
+
+void bta_hf_client_send_at_cmer(BOOLEAN activate)
+{
+    char *buf;
+
+    APPL_TRACE_DEBUG("%s", __FUNCTION__);
+
+    if (activate) {
+        buf = "AT+CMER=3,0,0,1\r";
+    } else {
+        buf = "AT+CMER=3,0,0,0\r";
+    }
+
+    bta_hf_client_send_at(BTA_HF_CLIENT_AT_CMER, buf, strlen(buf));
+}
+
+void bta_hf_client_send_at_chld(char cmd, UINT32 idx)
+{
+    char *buf = osi_malloc(BTA_HF_CLIENT_AT_MAX_LEN);
+    int at_len;
+
+    if (buf == NULL) {
+        APPL_TRACE_ERROR("No mem %s", __FUNCTION__);
+        return;
+    }
+
+    if (idx > 0) {
+        at_len = snprintf(buf, BTA_HF_CLIENT_AT_MAX_LEN, "AT+CHLD=%c%u\r", cmd, idx);
+    } else {
+        at_len = snprintf(buf, BTA_HF_CLIENT_AT_MAX_LEN, "AT+CHLD=%c\r", cmd);
+    }
+
+    bta_hf_client_send_at(BTA_HF_CLIENT_AT_CHLD, buf, at_len);
+    osi_free(buf);
+}
+
+void bta_hf_client_send_at_clip(BOOLEAN activate)
+{
+    char *buf;
+
+    APPL_TRACE_DEBUG("%s", __FUNCTION__);
+
+    if (activate) {
+        buf = "AT+CLIP=1\r";
+    } else {
+        buf = "AT+CLIP=0\r";
+    }
+
+    bta_hf_client_send_at(BTA_HF_CLIENT_AT_CLIP, buf, strlen(buf));
+}
+
+void bta_hf_client_send_at_ccwa(BOOLEAN activate)
+{
+    char *buf;
+
+    APPL_TRACE_DEBUG("%s", __FUNCTION__);
+
+    if (activate) {
+        buf = "AT+CCWA=1\r";
+    } else {
+        buf = "AT+CCWA=0\r";
+    }
+
+    bta_hf_client_send_at(BTA_HF_CLIENT_AT_CCWA, buf, strlen(buf));
+}
+
+
+void bta_hf_client_send_at_cmee(BOOLEAN activate)
+{
+    char *buf;
+
+    APPL_TRACE_DEBUG("%s", __FUNCTION__);
+
+    if (activate) {
+        buf = "AT+CMEE=1\r";
+    } else {
+        buf = "AT+CMEE=0\r";
+    }
+
+    bta_hf_client_send_at(BTA_HF_CLIENT_AT_CMEE, buf, strlen(buf));
+}
+
+void bta_hf_client_send_at_cops(BOOLEAN query)
+{
+    char *buf;
+
+    APPL_TRACE_DEBUG("%s", __FUNCTION__);
+
+    if (query) {
+        buf = "AT+COPS?\r";
+    } else {
+        buf = "AT+COPS=3,0\r";
+    }
+
+    bta_hf_client_send_at(BTA_HF_CLIENT_AT_COPS, buf, strlen(buf));
+}
+
+void bta_hf_client_send_at_clcc(void)
+{
+    char *buf;
+
+    APPL_TRACE_DEBUG("%s", __FUNCTION__);
+
+    buf = "AT+CLCC\r";
+
+    bta_hf_client_send_at(BTA_HF_CLIENT_AT_CLCC, buf, strlen(buf));
+}
+
+void bta_hf_client_send_at_bvra(BOOLEAN enable)
+{
+    char *buf;
+
+    APPL_TRACE_DEBUG("%s", __FUNCTION__);
+
+    if (enable) {
+        buf = "AT+BVRA=1\r";
+    } else {
+        buf = "AT+BVRA=0\r";
+    }
+
+    bta_hf_client_send_at(BTA_HF_CLIENT_AT_BVRA, buf, strlen(buf));
+}
+
+void bta_hf_client_send_at_vgs(UINT32 volume)
+{
+    char *buf = osi_malloc(BTA_HF_CLIENT_AT_MAX_LEN);
+    int at_len;
+    if (buf == NULL) {
+        APPL_TRACE_ERROR("No mem %s", __FUNCTION__);
+        return;
+    }
+    APPL_TRACE_DEBUG("%s", __FUNCTION__);
+
+    at_len = snprintf(buf, BTA_HF_CLIENT_AT_MAX_LEN, "AT+VGS=%u\r", volume);
+
+    bta_hf_client_send_at(BTA_HF_CLIENT_AT_VGS, buf, at_len);
+    osi_free(buf);
+}
+
+void bta_hf_client_send_at_vgm(UINT32 volume)
+{
+    char *buf = osi_malloc(BTA_HF_CLIENT_AT_MAX_LEN);
+    int at_len;
+
+    if (buf == NULL) {
+        APPL_TRACE_ERROR("No mem %s", __FUNCTION__);
+        return;
+    }
+    APPL_TRACE_DEBUG("%s", __FUNCTION__);
+
+    at_len = snprintf(buf, BTA_HF_CLIENT_AT_MAX_LEN, "AT+VGM=%u\r", volume);
+
+    bta_hf_client_send_at(BTA_HF_CLIENT_AT_VGM, buf, at_len);
+    osi_free(buf);
+}
+
+void bta_hf_client_send_at_atd(char *number, UINT32 memory)
+{
+    char *buf = osi_malloc(BTA_HF_CLIENT_AT_MAX_LEN);
+    int at_len;
+
+    if (buf == NULL) {
+        APPL_TRACE_ERROR("No mem %s", __FUNCTION__);
+        return;
+    }
+    APPL_TRACE_DEBUG("%s", __FUNCTION__);
+
+    if (number[0] != '\0') {
+        at_len = snprintf(buf, BTA_HF_CLIENT_AT_MAX_LEN, "ATD%s;\r", number);
+    } else {
+        at_len = snprintf(buf, BTA_HF_CLIENT_AT_MAX_LEN, "ATD>%u;\r", memory);
+    }
+
+    at_len = MIN(at_len, BTA_HF_CLIENT_AT_MAX_LEN);
+
+    bta_hf_client_send_at(BTA_HF_CLIENT_AT_ATD, buf, at_len);
+    osi_free(buf);
+}
+
+void bta_hf_client_send_at_bldn(void)
+{
+    char *buf;
+
+    APPL_TRACE_DEBUG("%s", __FUNCTION__);
+
+    buf = "AT+BLDN\r";
+
+    bta_hf_client_send_at(BTA_HF_CLIENT_AT_BLDN, buf, strlen(buf));
+}
+
+void bta_hf_client_send_at_ata(void)
+{
+    char *buf;
+
+    APPL_TRACE_DEBUG("%s", __FUNCTION__);
+
+    buf = "ATA\r";
+
+    bta_hf_client_send_at(BTA_HF_CLIENT_AT_ATA, buf, strlen(buf));
+}
+
+void bta_hf_client_send_at_chup(void)
+{
+    char *buf;
+
+    APPL_TRACE_DEBUG("%s", __FUNCTION__);
+
+    buf = "AT+CHUP\r";
+
+    bta_hf_client_send_at(BTA_HF_CLIENT_AT_CHUP, buf, strlen(buf));
+}
+
+void bta_hf_client_send_at_btrh(BOOLEAN query, UINT32 val)
+{
+    char *buf = osi_malloc(BTA_HF_CLIENT_AT_MAX_LEN);
+    int at_len;
+
+    if (buf == NULL) {
+        APPL_TRACE_ERROR("No mem %s", __FUNCTION__);
+        return;
+    }
+    APPL_TRACE_DEBUG("%s", __FUNCTION__);
+
+    if (query == TRUE) {
+        at_len = snprintf(buf, BTA_HF_CLIENT_AT_MAX_LEN, "AT+BTRH?\r");
+    } else {
+        at_len = snprintf(buf, BTA_HF_CLIENT_AT_MAX_LEN, "AT+BTRH=%u\r", val);
+    }
+
+    bta_hf_client_send_at(BTA_HF_CLIENT_AT_BTRH, buf, at_len);
+    osi_free(buf);
+}
+
+void bta_hf_client_send_at_vts(char code)
+{
+    char *buf = osi_malloc(BTA_HF_CLIENT_AT_MAX_LEN);
+    int at_len;
+    if (buf == NULL) {
+        APPL_TRACE_ERROR("No mem %s", __FUNCTION__);
+        return;
+    }
+    APPL_TRACE_DEBUG("%s", __FUNCTION__);
+
+    at_len = snprintf(buf, BTA_HF_CLIENT_AT_MAX_LEN, "AT+VTS=%c\r", code);
+
+    bta_hf_client_send_at(BTA_HF_CLIENT_AT_VTS, buf, at_len);
+    osi_free(buf);
+}
+
+void bta_hf_client_send_at_bcc(void)
+{
+    char *buf;
+
+    APPL_TRACE_DEBUG("%s", __FUNCTION__);
+
+    buf = "AT+BCC\r";
+
+    bta_hf_client_send_at(BTA_HF_CLIENT_AT_BCC, buf, strlen(buf));
+}
+
+void bta_hf_client_send_at_cnum(void)
+{
+    char *buf;
+
+    APPL_TRACE_DEBUG("%s", __FUNCTION__);
+
+    buf = "AT+CNUM\r";
+
+    bta_hf_client_send_at(BTA_HF_CLIENT_AT_CNUM, buf, strlen(buf));
+}
+
+void bta_hf_client_send_at_nrec(void)
+{
+    char *buf;
+
+    APPL_TRACE_DEBUG("%s", __FUNCTION__);
+
+    if (!(bta_hf_client_cb.scb.peer_features & BTA_HF_CLIENT_PEER_FEAT_ECNR)) {
+        APPL_TRACE_ERROR("%s: Remote does not support NREC.", __FUNCTION__);
+        return;
+    }
+
+    buf = "AT+NREC=0\r";
+
+    bta_hf_client_send_at(BTA_HF_CLIENT_AT_NREC, buf, strlen(buf));
+}
+
+void bta_hf_client_send_at_binp(UINT32 action)
+{
+    char *buf = osi_malloc(BTA_HF_CLIENT_AT_MAX_LEN);
+    int at_len;
+
+    if (buf == NULL) {
+        APPL_TRACE_ERROR("No mem %s", __FUNCTION__);
+        return;
+    }
+
+    at_len = snprintf(buf, BTA_HF_CLIENT_AT_MAX_LEN, "AT+BINP=%u\r", action);
+
+    bta_hf_client_send_at(BTA_HF_CLIENT_AT_BINP, buf, at_len);
+    osi_free(buf);
+}
+
+void bta_hf_client_send_at_bia(void)
+{
+    char *buf;
+    int at_len;
+    int i;
+
+    APPL_TRACE_DEBUG("%s", __FUNCTION__);
+    if (bta_hf_client_cb.scb.peer_version < HFP_VERSION_1_6) {
+        APPL_TRACE_DEBUG("Remote does not Support AT+BIA");
+        return;
+    }
+
+    buf = osi_malloc(BTA_HF_CLIENT_AT_MAX_LEN);
+    if (buf == NULL) {
+        APPL_TRACE_ERROR("No mem %s", __FUNCTION__);
+        return;
+    }
+    at_len = snprintf(buf, BTA_HF_CLIENT_AT_MAX_LEN, "AT+BIA=");
+
+    for (i = 0; i < BTA_HF_CLIENT_AT_INDICATOR_COUNT; i++) {
+        int sup = bta_hf_client_cb.scb.at_cb.indicator_lookup[i] == -1 ? 0 : 1;
+
+        at_len += snprintf(buf + at_len, BTA_HF_CLIENT_AT_MAX_LEN - at_len, "%u,", sup);
+    }
+
+    buf[at_len - 1] = '\r';
+
+    bta_hf_client_send_at(BTA_HF_CLIENT_AT_BIA, buf, at_len);
+    osi_free(buf);
+}
+
+void bta_hf_client_at_init(void)
+{
+    memset(&bta_hf_client_cb.scb.at_cb, 0, sizeof(tBTA_HF_CLIENT_AT_CB));
+    bta_hf_client_at_reset();
+}
+
+void bta_hf_client_at_reset(void)
+{
+    int i;
+
+    bta_hf_client_free_at_resp_timer();
+    bta_hf_client_free_at_hold_timer();
+
+    bta_hf_client_clear_queued_at();
+
+    bta_hf_client_at_clear_buf();
+
+    for (i = 0; i < BTA_HF_CLIENT_AT_INDICATOR_COUNT; i++) {
+        bta_hf_client_cb.scb.at_cb.indicator_lookup[i] = -1;
+    }
+
+    bta_hf_client_cb.scb.at_cb.current_cmd = BTA_HF_CLIENT_AT_NONE;
+}
+#endif /* #if (BTA_HF_INCLUDED == TRUE) */
diff --git a/components/bt/bluedroid/bta/hf_client/bta_hf_client_cmd.c b/components/bt/bluedroid/bta/hf_client/bta_hf_client_cmd.c
new file mode 100644 (file)
index 0000000..df761e4
--- /dev/null
@@ -0,0 +1,85 @@
+/******************************************************************************
+ *
+ *  Copyright (c) 2014 The Android Open Source Project
+ *  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.
+ *
+ ******************************************************************************/
+
+#include "bta_hf_client_int.h"
+#include "stdio.h"
+#include "common/bt_target.h"
+
+#if (BTA_HF_INCLUDED == TRUE)
+
+void bta_hf_client_send_at_cmd(tBTA_HF_CLIENT_DATA *p_data)
+{
+    tBTA_HF_CLIENT_DATA_VAL *p_val = (tBTA_HF_CLIENT_DATA_VAL *)p_data;
+
+    switch (p_val->uint8_val) {
+    case BTA_HF_CLIENT_AT_CMD_VTS:
+        bta_hf_client_send_at_vts((char)p_val->uint32_val1);
+        break;
+    case BTA_HF_CLIENT_AT_CMD_BTRH:
+        bta_hf_client_send_at_btrh(FALSE, p_val->uint32_val1);
+        break;
+    case BTA_HF_CLIENT_AT_CMD_CHUP:
+        bta_hf_client_send_at_chup();
+        break;
+    case BTA_HF_CLIENT_AT_CMD_CHLD:
+        /* expects ascii code for command */
+        bta_hf_client_send_at_chld('0' + p_val->uint32_val1, p_val->uint32_val2);
+        break;
+    case BTA_HF_CLIENT_AT_CMD_BCC:
+        bta_hf_client_send_at_bcc();
+        break;
+    case BTA_HF_CLIENT_AT_CMD_CNUM:
+        bta_hf_client_send_at_cnum();
+        break;
+    case BTA_HF_CLIENT_AT_CMD_ATA:
+        bta_hf_client_send_at_ata();
+        break;
+    case BTA_HF_CLIENT_AT_CMD_COPS:
+        bta_hf_client_send_at_cops(TRUE);
+        break;
+    case BTA_HF_CLIENT_AT_CMD_ATD:
+        bta_hf_client_send_at_atd(p_val->str, p_val->uint32_val1);
+        break;
+    case BTA_HF_CLIENT_AT_CMD_VGM:
+        bta_hf_client_send_at_vgm(p_val->uint32_val1);
+        break;
+    case BTA_HF_CLIENT_AT_CMD_VGS:
+        bta_hf_client_send_at_vgs(p_val->uint32_val1);
+        break;
+    case BTA_HF_CLIENT_AT_CMD_BVRA:
+        bta_hf_client_send_at_bvra(p_val->uint32_val1 == 0 ? FALSE : TRUE);
+        break;
+    case BTA_HF_CLIENT_AT_CMD_CLCC:
+        bta_hf_client_send_at_clcc();
+        break;
+    case BTA_HF_CLIENT_AT_CMD_BINP:
+        bta_hf_client_send_at_binp(p_val->uint32_val1);
+        break;
+    case BTA_HF_CLIENT_AT_CMD_BLDN:
+        bta_hf_client_send_at_bldn();
+        break;
+    case BTA_HF_CLIENT_AT_CMD_NREC:
+        bta_hf_client_send_at_nrec();
+        break;
+    default:
+        APPL_TRACE_ERROR("Default case, %s", __FUNCTION__);
+        break;
+    }
+}
+#endif /* #if (BTA_HF_INCLUDED == TRUE) */
diff --git a/components/bt/bluedroid/bta/hf_client/bta_hf_client_main.c b/components/bt/bluedroid/bta/hf_client/bta_hf_client_main.c
new file mode 100644 (file)
index 0000000..16e67cf
--- /dev/null
@@ -0,0 +1,662 @@
+/******************************************************************************
+ *
+ *  Copyright (c) 2014 The Android Open Source Project
+ *  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.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+#include <stdlib.h>
+#include "common/bt_defs.h"
+#include "bta/bta_api.h"
+#include "bta/bta_sys.h"
+#include "bta/bta_hf_client_api.h"
+#include "bta_hf_client_int.h"
+
+#if (BTA_HF_INCLUDED == TRUE)
+/* uncomment to enable extra debug */
+/* #define BTA_HF_CLIENT_DEBUG TRUE */
+
+#ifndef BTA_HF_CLIENT_DEBUG
+#define BTA_HF_CLIENT_DEBUG FALSE
+#endif
+
+#if BTA_HF_CLIENT_DEBUG == TRUE
+static char *bta_hf_client_evt_str(UINT16 event);
+static char *bta_hf_client_state_str(UINT8 state);
+#endif
+
+/* state machine states */
+enum {
+    BTA_HF_CLIENT_INIT_ST,
+    BTA_HF_CLIENT_OPENING_ST,
+    BTA_HF_CLIENT_OPEN_ST,
+    BTA_HF_CLIENT_CLOSING_ST
+};
+
+/* state machine action enumeration list */
+enum {
+    BTA_HF_CLIENT_REGISTER,
+    BTA_HF_CLIENT_DEREGISTER,
+    BTA_HF_CLIENT_START_DEREG,
+    BTA_HF_CLIENT_RFC_DO_CLOSE,
+    BTA_HF_CLIENT_START_CLOSE,
+    BTA_HF_CLIENT_START_OPEN,
+    BTA_HF_CLIENT_RFC_ACP_OPEN,
+    BTA_HF_CLIENT_SCO_LISTEN,
+    BTA_HF_CLIENT_SCO_CONN_OPEN,
+    BTA_HF_CLIENT_SCO_CONN_CLOSE,
+    BTA_HF_CLIENT_SCO_OPEN,
+    BTA_HF_CLIENT_SCO_CLOSE,
+    BTA_HF_CLIENT_SCO_SHUTDOWN,
+    BTA_HF_CLIENT_FREE_DB,
+    BTA_HF_CLIENT_OPEN_FAIL,
+    BTA_HF_CLIENT_RFC_OPEN,
+    BTA_HF_CLIENT_RFC_FAIL,
+    BTA_HF_CLIENT_DISC_INT_RES,
+    BTA_HF_CLIENT_RFC_DO_OPEN,
+    BTA_HF_CLIENT_DISC_FAIL,
+    BTA_HF_CLIENT_RFC_CLOSE,
+    BTA_HF_CLIENT_RFC_DATA,
+    BTA_HF_CLIENT_DISC_ACP_RES,
+    BTA_HF_CLIENT_SVC_CONN_OPEN,
+    BTA_HF_CLIENT_SEND_AT_CMD,
+#if (BTM_SCO_HCI_INCLUDED == TRUE)
+    BTA_HF_CLIENT_CI_SCO_DATA,
+#endif
+    BTA_HF_CLIENT_NUM_ACTIONS,
+};
+
+#define BTA_HF_CLIENT_IGNORE BTA_HF_CLIENT_NUM_ACTIONS
+
+/* type for action functions */
+typedef void (*tBTA_HF_CLIENT_ACTION)(tBTA_HF_CLIENT_DATA *p_data);
+
+/* action functions table, indexed with action enum */
+const tBTA_HF_CLIENT_ACTION bta_hf_client_action[] = {
+    /* BTA_HF_CLIENT_REGISTER */      bta_hf_client_register,
+    /* BTA_HF_CLIENT_DEREGISTER */    bta_hf_client_deregister,
+    /* BTA_HF_CLIENT_START_DEREG */   bta_hf_client_start_dereg,
+    /* BTA_HF_CLIENT_RFC_DO_CLOSE */  bta_hf_client_rfc_do_close,
+    /* BTA_HF_CLIENT_START_CLOSE */   bta_hf_client_start_close,
+    /* BTA_HF_CLIENT_START_OPEN */    bta_hf_client_start_open,
+    /* BTA_HF_CLIENT_RFC_ACP_OPEN */  bta_hf_client_rfc_acp_open,
+    /* BTA_HF_CLIENT_SCO_LISTEN */    bta_hf_client_sco_listen,
+    /* BTA_HF_CLIENT_SCO_CONN_OPEN */ bta_hf_client_sco_conn_open,
+    /* BTA_HF_CLIENT_SCO_CONN_CLOSE*/ bta_hf_client_sco_conn_close,
+    /* BTA_HF_CLIENT_SCO_OPEN */      bta_hf_client_sco_open,
+    /* BTA_HF_CLIENT_SCO_CLOSE */     bta_hf_client_sco_close,
+    /* BTA_HF_CLIENT_SCO_SHUTDOWN */  bta_hf_client_sco_shutdown,
+    /* BTA_HF_CLIENT_FREE_DB */       bta_hf_client_free_db,
+    /* BTA_HF_CLIENT_OPEN_FAIL */     bta_hf_client_open_fail,
+    /* BTA_HF_CLIENT_RFC_OPEN */      bta_hf_client_rfc_open,
+    /* BTA_HF_CLIENT_RFC_FAIL */      bta_hf_client_rfc_fail,
+    /* BTA_HF_CLIENT_DISC_INT_RES */  bta_hf_client_disc_int_res,
+    /* BTA_HF_CLIENT_RFC_DO_OPEN */   bta_hf_client_rfc_do_open,
+    /* BTA_HF_CLIENT_DISC_FAIL */     bta_hf_client_disc_fail,
+    /* BTA_HF_CLIENT_RFC_CLOSE */     bta_hf_client_rfc_close,
+    /* BTA_HF_CLIENT_RFC_DATA */      bta_hf_client_rfc_data,
+    /* BTA_HF_CLIENT_DISC_ACP_RES */  bta_hf_client_disc_acp_res,
+    /* BTA_HF_CLIENT_SVC_CONN_OPEN */ bta_hf_client_svc_conn_open,
+    /* BTA_HF_CLIENT_SEND_AT_CMD */   bta_hf_client_send_at_cmd,
+#if (BTM_SCO_HCI_INCLUDED == TRUE )
+    /* BTA_HF_CLIENT_CI_SCO_DATA */   bta_hf_client_ci_sco_data,
+#endif /* (BTM_SCO_HCI_INCLUDED == TRUE ) */
+};
+
+/* state table information */
+#define BTA_HF_CLIENT_ACTIONS              2       /* number of actions */
+#define BTA_HF_CLIENT_NEXT_STATE           2       /* position of next state */
+#define BTA_HF_CLIENT_NUM_COLS             3       /* number of columns in state tables */
+
+/* state table for init state */
+const UINT8 bta_hf_client_st_init[][BTA_HF_CLIENT_NUM_COLS] = {
+    /* Event                    Action 1                       Action 2                       Next state */
+    /* API_REGISTER_EVT */      {BTA_HF_CLIENT_REGISTER,       BTA_HF_CLIENT_IGNORE,          BTA_HF_CLIENT_INIT_ST},
+    /* API_DEREGISTER_EVT */    {BTA_HF_CLIENT_DEREGISTER,     BTA_HF_CLIENT_IGNORE,          BTA_HF_CLIENT_INIT_ST},
+    /* API_OPEN_EVT */          {BTA_HF_CLIENT_START_OPEN,     BTA_HF_CLIENT_IGNORE,          BTA_HF_CLIENT_OPENING_ST},
+    /* API_CLOSE_EVT */         {BTA_HF_CLIENT_IGNORE,         BTA_HF_CLIENT_IGNORE,          BTA_HF_CLIENT_INIT_ST},
+    /* API_AUDIO_OPEN_EVT */    {BTA_HF_CLIENT_IGNORE,         BTA_HF_CLIENT_IGNORE,          BTA_HF_CLIENT_INIT_ST},
+    /* API_AUDIO_CLOSE_EVT */   {BTA_HF_CLIENT_IGNORE,         BTA_HF_CLIENT_IGNORE,          BTA_HF_CLIENT_INIT_ST},
+    /* RFC_OPEN_EVT */          {BTA_HF_CLIENT_RFC_ACP_OPEN,   BTA_HF_CLIENT_SCO_LISTEN,      BTA_HF_CLIENT_OPEN_ST},
+    /* RFC_CLOSE_EVT */         {BTA_HF_CLIENT_IGNORE,         BTA_HF_CLIENT_IGNORE,          BTA_HF_CLIENT_INIT_ST},
+    /* RFC_SRV_CLOSE_EVT */     {BTA_HF_CLIENT_IGNORE,         BTA_HF_CLIENT_IGNORE,          BTA_HF_CLIENT_INIT_ST},
+    /* RFC_DATA_EVT */          {BTA_HF_CLIENT_IGNORE,         BTA_HF_CLIENT_IGNORE,          BTA_HF_CLIENT_INIT_ST},
+    /* DISC_ACP_RES_EVT */      {BTA_HF_CLIENT_FREE_DB,        BTA_HF_CLIENT_IGNORE,          BTA_HF_CLIENT_INIT_ST},
+    /* DISC_INT_RES_EVT */      {BTA_HF_CLIENT_IGNORE,         BTA_HF_CLIENT_IGNORE,          BTA_HF_CLIENT_INIT_ST},
+    /* DISC_OK_EVT */           {BTA_HF_CLIENT_IGNORE,         BTA_HF_CLIENT_IGNORE,          BTA_HF_CLIENT_INIT_ST},
+    /* DISC_FAIL_EVT */         {BTA_HF_CLIENT_IGNORE,         BTA_HF_CLIENT_IGNORE,          BTA_HF_CLIENT_INIT_ST},
+    /* SCO_OPEN_EVT */          {BTA_HF_CLIENT_IGNORE,         BTA_HF_CLIENT_IGNORE,          BTA_HF_CLIENT_INIT_ST},
+    /* SCO_CLOSE_EVT */         {BTA_HF_CLIENT_IGNORE,         BTA_HF_CLIENT_IGNORE,          BTA_HF_CLIENT_INIT_ST},
+    /* SEND_AT_CMD_EVT */       {BTA_HF_CLIENT_IGNORE,         BTA_HF_CLIENT_IGNORE,          BTA_HF_CLIENT_INIT_ST},
+#if (BTM_SCO_HCI_INCLUDED == TRUE )
+    /* CI_SCO_DATA_EVT */       {BTA_HF_CLIENT_IGNORE,         BTA_HF_CLIENT_IGNORE,          BTA_HF_CLIENT_INIT_ST},
+#endif /* (BTM_SCO_HCI_INCLUDED == TRUE ) */
+};
+
+/* state table for opening state */
+const UINT8 bta_hf_client_st_opening[][BTA_HF_CLIENT_NUM_COLS] = {
+    /* Event                    Action 1                       Action 2                       Next state */
+    /* API_REGISTER_EVT */      {BTA_HF_CLIENT_IGNORE,         BTA_HF_CLIENT_IGNORE,          BTA_HF_CLIENT_OPENING_ST},
+    /* API_DEREGISTER_EVT */    {BTA_HF_CLIENT_RFC_DO_CLOSE,   BTA_HF_CLIENT_START_DEREG,     BTA_HF_CLIENT_CLOSING_ST},
+    /* API_OPEN_EVT */          {BTA_HF_CLIENT_OPEN_FAIL,      BTA_HF_CLIENT_IGNORE,          BTA_HF_CLIENT_OPENING_ST},
+    /* API_CLOSE_EVT */         {BTA_HF_CLIENT_RFC_DO_CLOSE,   BTA_HF_CLIENT_IGNORE,          BTA_HF_CLIENT_CLOSING_ST},
+    /* API_AUDIO_OPEN_EVT */    {BTA_HF_CLIENT_IGNORE,         BTA_HF_CLIENT_IGNORE,          BTA_HF_CLIENT_OPENING_ST},
+    /* API_AUDIO_CLOSE_EVT */   {BTA_HF_CLIENT_IGNORE,         BTA_HF_CLIENT_IGNORE,          BTA_HF_CLIENT_OPENING_ST},
+    /* RFC_OPEN_EVT */          {BTA_HF_CLIENT_RFC_OPEN,       BTA_HF_CLIENT_SCO_LISTEN,      BTA_HF_CLIENT_OPEN_ST},
+    /* RFC_CLOSE_EVT */         {BTA_HF_CLIENT_RFC_FAIL,       BTA_HF_CLIENT_IGNORE,          BTA_HF_CLIENT_INIT_ST},
+    /* RFC_SRV_CLOSE_EVT */     {BTA_HF_CLIENT_IGNORE,         BTA_HF_CLIENT_IGNORE,          BTA_HF_CLIENT_OPENING_ST},
+    /* RFC_DATA_EVT */          {BTA_HF_CLIENT_IGNORE,         BTA_HF_CLIENT_IGNORE,          BTA_HF_CLIENT_OPENING_ST},
+    /* DISC_ACP_RES_EVT */      {BTA_HF_CLIENT_IGNORE,         BTA_HF_CLIENT_IGNORE,          BTA_HF_CLIENT_OPENING_ST},
+    /* DISC_INT_RES_EVT */      {BTA_HF_CLIENT_DISC_INT_RES,   BTA_HF_CLIENT_IGNORE,          BTA_HF_CLIENT_OPENING_ST},
+    /* DISC_OK_EVT */           {BTA_HF_CLIENT_RFC_DO_OPEN,    BTA_HF_CLIENT_IGNORE,          BTA_HF_CLIENT_OPENING_ST},
+    /* DISC_FAIL_EVT */         {BTA_HF_CLIENT_DISC_FAIL,      BTA_HF_CLIENT_IGNORE,          BTA_HF_CLIENT_INIT_ST},
+    /* SCO_OPEN_EVT */          {BTA_HF_CLIENT_IGNORE,         BTA_HF_CLIENT_IGNORE,          BTA_HF_CLIENT_OPENING_ST},
+    /* SCO_CLOSE_EVT */         {BTA_HF_CLIENT_IGNORE,         BTA_HF_CLIENT_IGNORE,          BTA_HF_CLIENT_OPENING_ST},
+    /* SEND_AT_CMD_EVT */       {BTA_HF_CLIENT_IGNORE,         BTA_HF_CLIENT_IGNORE,          BTA_HF_CLIENT_OPENING_ST},
+#if (BTM_SCO_HCI_INCLUDED == TRUE )
+    /* CI_SCO_DATA_EVT */       {BTA_HF_CLIENT_IGNORE,         BTA_HF_CLIENT_IGNORE,          BTA_HF_CLIENT_OPENING_ST},
+#endif /* (BTM_SCO_HCI_INCLUDED == TRUE ) */
+};
+
+/* state table for open state */
+const UINT8 bta_hf_client_st_open[][BTA_HF_CLIENT_NUM_COLS] = {
+    /* Event                    Action 1                       Action 2                       Next state */
+    /* API_REGISTER_EVT */      {BTA_HF_CLIENT_IGNORE,         BTA_HF_CLIENT_IGNORE,          BTA_HF_CLIENT_OPEN_ST},
+    /* API_DEREGISTER_EVT */    {BTA_HF_CLIENT_START_CLOSE,    BTA_HF_CLIENT_START_DEREG,     BTA_HF_CLIENT_CLOSING_ST},
+    /* API_OPEN_EVT */          {BTA_HF_CLIENT_OPEN_FAIL,      BTA_HF_CLIENT_IGNORE,          BTA_HF_CLIENT_OPEN_ST},
+    /* API_CLOSE_EVT */         {BTA_HF_CLIENT_START_CLOSE,    BTA_HF_CLIENT_IGNORE,          BTA_HF_CLIENT_CLOSING_ST},
+    /* API_AUDIO_OPEN_EVT */    {BTA_HF_CLIENT_SCO_OPEN,       BTA_HF_CLIENT_IGNORE,          BTA_HF_CLIENT_OPEN_ST},
+    /* API_AUDIO_CLOSE_EVT */   {BTA_HF_CLIENT_SCO_CLOSE,      BTA_HF_CLIENT_IGNORE,          BTA_HF_CLIENT_OPEN_ST},
+    /* RFC_OPEN_EVT */          {BTA_HF_CLIENT_IGNORE,         BTA_HF_CLIENT_IGNORE,          BTA_HF_CLIENT_OPEN_ST},
+    /* RFC_CLOSE_EVT */         {BTA_HF_CLIENT_RFC_CLOSE,      BTA_HF_CLIENT_IGNORE,          BTA_HF_CLIENT_INIT_ST},
+    /* RFC_SRV_CLOSE_EVT */     {BTA_HF_CLIENT_IGNORE,         BTA_HF_CLIENT_IGNORE,          BTA_HF_CLIENT_OPEN_ST},
+    /* RFC_DATA_EVT */          {BTA_HF_CLIENT_RFC_DATA,       BTA_HF_CLIENT_IGNORE,          BTA_HF_CLIENT_OPEN_ST},
+    /* DISC_ACP_RES_EVT */      {BTA_HF_CLIENT_DISC_ACP_RES,   BTA_HF_CLIENT_IGNORE,          BTA_HF_CLIENT_OPEN_ST},
+    /* DISC_INT_RES_EVT */      {BTA_HF_CLIENT_IGNORE,         BTA_HF_CLIENT_IGNORE,          BTA_HF_CLIENT_OPEN_ST},
+    /* DISC_OK_EVT */           {BTA_HF_CLIENT_IGNORE,         BTA_HF_CLIENT_IGNORE,          BTA_HF_CLIENT_OPEN_ST},
+    /* DISC_FAIL_EVT */         {BTA_HF_CLIENT_IGNORE,         BTA_HF_CLIENT_IGNORE,          BTA_HF_CLIENT_OPEN_ST},
+    /* SCO_OPEN_EVT */          {BTA_HF_CLIENT_SCO_CONN_OPEN,  BTA_HF_CLIENT_IGNORE,          BTA_HF_CLIENT_OPEN_ST},
+    /* SCO_CLOSE_EVT */         {BTA_HF_CLIENT_SCO_CONN_CLOSE, BTA_HF_CLIENT_IGNORE,          BTA_HF_CLIENT_OPEN_ST},
+    /* SEND_AT_CMD_EVT */       {BTA_HF_CLIENT_SEND_AT_CMD,    BTA_HF_CLIENT_IGNORE,          BTA_HF_CLIENT_OPEN_ST},
+#if (BTM_SCO_HCI_INCLUDED == TRUE )
+    /* CI_SCO_DATA_EVT */       {BTA_HF_CLIENT_CI_SCO_DATA,    BTA_HF_CLIENT_IGNORE,          BTA_HF_CLIENT_OPEN_ST},
+#endif /* (BTM_SCO_HCI_INCLUDED == TRUE ) */
+};
+
+/* state table for closing state */
+const UINT8 bta_hf_client_st_closing[][BTA_HF_CLIENT_NUM_COLS] = {
+    /* Event                    Action 1                       Action 2                       Next state */
+    /* API_REGISTER_EVT */      {BTA_HF_CLIENT_IGNORE,         BTA_HF_CLIENT_IGNORE,          BTA_HF_CLIENT_CLOSING_ST},
+    /* API_DEREGISTER_EVT */    {BTA_HF_CLIENT_START_DEREG,    BTA_HF_CLIENT_IGNORE,          BTA_HF_CLIENT_CLOSING_ST},
+    /* API_OPEN_EVT */          {BTA_HF_CLIENT_OPEN_FAIL,      BTA_HF_CLIENT_IGNORE,          BTA_HF_CLIENT_CLOSING_ST},
+    /* API_CLOSE_EVT */         {BTA_HF_CLIENT_IGNORE,         BTA_HF_CLIENT_IGNORE,          BTA_HF_CLIENT_CLOSING_ST},
+    /* API_AUDIO_OPEN_EVT */    {BTA_HF_CLIENT_IGNORE,         BTA_HF_CLIENT_IGNORE,          BTA_HF_CLIENT_CLOSING_ST},
+    /* API_AUDIO_CLOSE_EVT */   {BTA_HF_CLIENT_IGNORE,         BTA_HF_CLIENT_IGNORE,          BTA_HF_CLIENT_CLOSING_ST},
+    /* RFC_OPEN_EVT */          {BTA_HF_CLIENT_IGNORE,         BTA_HF_CLIENT_IGNORE,          BTA_HF_CLIENT_CLOSING_ST},
+    /* RFC_CLOSE_EVT */         {BTA_HF_CLIENT_RFC_CLOSE,      BTA_HF_CLIENT_IGNORE,          BTA_HF_CLIENT_INIT_ST},
+    /* RFC_SRV_CLOSE_EVT */     {BTA_HF_CLIENT_IGNORE,         BTA_HF_CLIENT_IGNORE,          BTA_HF_CLIENT_CLOSING_ST},
+    /* RFC_DATA_EVT */          {BTA_HF_CLIENT_IGNORE,         BTA_HF_CLIENT_IGNORE,          BTA_HF_CLIENT_CLOSING_ST},
+    /* DISC_ACP_RES_EVT */      {BTA_HF_CLIENT_FREE_DB,        BTA_HF_CLIENT_IGNORE,          BTA_HF_CLIENT_CLOSING_ST},
+    /* DISC_INT_RES_EVT */      {BTA_HF_CLIENT_FREE_DB,        BTA_HF_CLIENT_IGNORE,          BTA_HF_CLIENT_INIT_ST},
+    /* DISC_OK_EVT */           {BTA_HF_CLIENT_IGNORE,         BTA_HF_CLIENT_IGNORE,          BTA_HF_CLIENT_CLOSING_ST},
+    /* DISC_FAIL_EVT */         {BTA_HF_CLIENT_IGNORE,         BTA_HF_CLIENT_IGNORE,          BTA_HF_CLIENT_CLOSING_ST},
+    /* SCO_OPEN_EVT */          {BTA_HF_CLIENT_IGNORE,         BTA_HF_CLIENT_IGNORE,          BTA_HF_CLIENT_CLOSING_ST},
+    /* SCO_CLOSE_EVT */         {BTA_HF_CLIENT_IGNORE,         BTA_HF_CLIENT_IGNORE,          BTA_HF_CLIENT_CLOSING_ST},
+    /* SEND_AT_CMD_EVT */       {BTA_HF_CLIENT_IGNORE,         BTA_HF_CLIENT_IGNORE,          BTA_HF_CLIENT_CLOSING_ST},
+#if (BTM_SCO_HCI_INCLUDED == TRUE )
+    /* CI_SCO_DATA_EVT */       {BTA_HF_CLIENT_IGNORE,         BTA_HF_CLIENT_IGNORE,          BTA_HF_CLIENT_CLOSING_ST},
+#endif /* (BTM_SCO_HCI_INCLUDED == TRUE ) */
+};
+
+/* type for state table */
+typedef const UINT8 (*tBTA_HF_CLIENT_ST_TBL)[BTA_HF_CLIENT_NUM_COLS];
+
+/* state table */
+const tBTA_HF_CLIENT_ST_TBL bta_hf_client_st_tbl[] = {
+    bta_hf_client_st_init,
+    bta_hf_client_st_opening,
+    bta_hf_client_st_open,
+    bta_hf_client_st_closing
+};
+
+/* HF Client control block */
+#if BTA_DYNAMIC_MEMORY == FALSE
+tBTA_HF_CLIENT_CB  bta_hf_client_cb;
+#else
+tBTA_HF_CLIENT_CB  *bta_hf_client_cb_ptr;
+#endif
+
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_scb_init
+**
+** Description      Initialize an HF_Client service control block.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hf_client_scb_init(void)
+{
+    APPL_TRACE_DEBUG("%s", __FUNCTION__);
+
+    memset(&bta_hf_client_cb.scb, 0, sizeof(tBTA_HF_CLIENT_SCB));
+    bta_hf_client_cb.scb.sco_idx = BTM_INVALID_SCO_INDEX;
+    bta_hf_client_cb.scb.negotiated_codec = BTM_SCO_CODEC_CVSD;
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_scb_disable
+**
+** Description      Disable a service control block.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hf_client_scb_disable(void)
+{
+    APPL_TRACE_DEBUG("%s", __FUNCTION__);
+
+    bta_hf_client_scb_init();
+
+    (*bta_hf_client_cb.p_cback)(BTA_HF_CLIENT_DISABLE_EVT, NULL);
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_resume_open
+**
+** Description      Resume opening process.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hf_client_resume_open (void)
+{
+    APPL_TRACE_DEBUG ("%s", __FUNCTION__);
+
+    /* resume opening process.  */
+    if (bta_hf_client_cb.scb.state == BTA_HF_CLIENT_INIT_ST) {
+        bta_hf_client_cb.scb.state = BTA_HF_CLIENT_OPENING_ST;
+        bta_hf_client_start_open (NULL);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_colli_timer_cback
+**
+** Description      HF Client connection collision timer callback
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+static void bta_hf_client_colli_timer_cback (TIMER_LIST_ENT *p_tle)
+{
+    APPL_TRACE_DEBUG("%s", __FUNCTION__);
+
+    if (p_tle) {
+        bta_hf_client_cb.scb.colli_tmr_on = FALSE;
+
+        /* If the peer haven't opened connection, restart opening process */
+        bta_hf_client_resume_open ();
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_collision_cback
+**
+** Description      Get notified about collision.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hf_client_collision_cback (tBTA_SYS_CONN_STATUS status, UINT8 id,
+                                    UINT8 app_id, BD_ADDR peer_addr)
+{
+    UNUSED(status);
+    UNUSED(app_id);
+    UNUSED(peer_addr);
+
+    if (bta_hf_client_cb.scb.state == BTA_HF_CLIENT_OPENING_ST) {
+        if (id == BTA_ID_SYS) { /* ACL collision */
+            APPL_TRACE_WARNING ("HF Client found collision (ACL) ...");
+        } else if (id == BTA_ID_HS) { /* RFCOMM collision */
+            APPL_TRACE_WARNING ("HF Client found collision (RFCOMM) ...");
+        } else {
+            APPL_TRACE_WARNING ("HF Client found collision (\?\?\?) ...");
+        }
+
+        bta_hf_client_cb.scb.state = BTA_HF_CLIENT_INIT_ST;
+
+        /* Cancel SDP if it had been started. */
+        if (bta_hf_client_cb.scb.p_disc_db) {
+            (void)SDP_CancelServiceSearch (bta_hf_client_cb.scb.p_disc_db);
+            bta_hf_client_free_db(NULL);
+        }
+
+        /* reopen registered server */
+        /* Collision may be detected before or after we close servers. */
+        bta_hf_client_start_server();
+
+        /* Start timer to handle connection opening restart */
+        bta_hf_client_cb.scb.colli_timer.p_cback = (TIMER_CBACK *)&bta_hf_client_colli_timer_cback;
+        bta_sys_start_timer(&bta_hf_client_cb.scb.colli_timer, 0, BTA_HF_CLIENT_COLLISION_TIMER);
+        bta_hf_client_cb.scb.colli_tmr_on = TRUE;
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_api_enable
+**
+** Description      Handle an API enable event.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+static void bta_hf_client_api_enable(tBTA_HF_CLIENT_DATA *p_data)
+{
+    /* initialize control block */
+    memset(&bta_hf_client_cb, 0, sizeof(tBTA_HF_CLIENT_CB));
+
+    /* store callback function */
+    bta_hf_client_cb.p_cback = p_data->api_enable.p_cback;
+
+    /* check if mSBC support enabled */
+#if 0 // todo
+    char value[PROPERTY_VALUE_MAX];
+    property_get("ro.bluetooth.hfp.ver", value, "0");
+    if (strcmp(value, "1.6") == 0) {
+        bta_hf_client_cb.msbc_enabled = TRUE;
+    }
+#else
+    bta_hf_client_cb.msbc_enabled = FALSE;
+#endif
+
+    bta_hf_client_cb.scb.negotiated_codec = BTM_SCO_CODEC_CVSD;
+
+    /* set same setting as AG does */
+    BTM_WriteVoiceSettings(AG_VOICE_SETTINGS);
+
+    bta_sys_collision_register (BTA_ID_HS, bta_hf_client_collision_cback);
+
+    /* call callback with enable event */
+    (*bta_hf_client_cb.p_cback)(BTA_HF_CLIENT_ENABLE_EVT, NULL);
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_api_disable
+**
+** Description      Handle an API disable event.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+static void bta_hf_client_api_disable(tBTA_HF_CLIENT_DATA *p_data)
+{
+    if (!bta_sys_is_register (BTA_ID_HS)) {
+        APPL_TRACE_ERROR("BTA HF Client is already disabled, ignoring ...");
+        return;
+    }
+
+    /* De-register with BTA system manager */
+    bta_sys_deregister(BTA_ID_HS);
+
+    bta_hf_client_sm_execute(BTA_HF_CLIENT_API_DEREGISTER_EVT, p_data);
+
+    bta_sys_collision_register (BTA_ID_HS, NULL);
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_hdl_event
+**
+** Description      Data HF Client main event handling function.
+**
+**
+** Returns          BOOLEAN
+**
+*******************************************************************************/
+BOOLEAN bta_hf_client_hdl_event(BT_HDR *p_msg)
+{
+#if BTA_HF_CLIENT_DEBUG == TRUE
+    APPL_TRACE_DEBUG("bta_hf_client_hdl_event %s (0x%x)", bta_hf_client_evt_str(p_msg->event), p_msg->event);
+#endif
+
+    switch (p_msg->event) {
+    /* handle enable event */
+    case BTA_HF_CLIENT_API_ENABLE_EVT:
+        bta_hf_client_api_enable((tBTA_HF_CLIENT_DATA *) p_msg);
+        break;
+
+    /* handle disable event */
+    case BTA_HF_CLIENT_API_DISABLE_EVT:
+        bta_hf_client_api_disable((tBTA_HF_CLIENT_DATA *) p_msg);
+        break;
+
+    default:
+        bta_hf_client_sm_execute(p_msg->event, (tBTA_HF_CLIENT_DATA *) p_msg);
+        break;
+    }
+    return TRUE;
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_sm_execute
+**
+** Description      State machine event handling function for HF Client
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hf_client_sm_execute(UINT16 event, tBTA_HF_CLIENT_DATA *p_data)
+{
+    tBTA_HF_CLIENT_ST_TBL      state_table;
+    UINT8               action;
+    int                 i;
+
+#if BTA_HF_CLIENT_DEBUG == TRUE
+    UINT16  in_event = event;
+    UINT8 in_state =  bta_hf_client_cb.scb.state;
+
+    /* Ignore displaying of AT results when not connected (Ignored in state machine) */
+    if (bta_hf_client_cb.scb.state == BTA_HF_CLIENT_OPEN_ST) {
+        APPL_TRACE_EVENT("HF Client evt : State %d (%s), Event 0x%04x (%s)",
+                         bta_hf_client_cb.scb.state,
+                         bta_hf_client_state_str(bta_hf_client_cb.scb.state),
+                         event, bta_hf_client_evt_str(event));
+    }
+#endif
+
+    event &= 0x00FF;
+    if (event >= (BTA_HF_CLIENT_MAX_EVT & 0x00FF)) {
+        APPL_TRACE_ERROR("HF Client evt out of range, ignoring...");
+        return;
+    }
+
+    /* look up the state table for the current state */
+    state_table = bta_hf_client_st_tbl[bta_hf_client_cb.scb.state];
+
+    /* set next state */
+    bta_hf_client_cb.scb.state = state_table[event][BTA_HF_CLIENT_NEXT_STATE];
+
+    /* execute action functions */
+    for (i = 0; i < BTA_HF_CLIENT_ACTIONS; i++) {
+        if ((action = state_table[event][i]) != BTA_HF_CLIENT_IGNORE) {
+            (*bta_hf_client_action[action])(p_data);
+        } else {
+            break;
+        }
+    }
+
+#if BTA_HF_CLIENT_DEBUG == TRUE
+    if (bta_hf_client_cb.scb.state != in_state) {
+        APPL_TRACE_EVENT("BTA HF Client State Change: [%s] -> [%s] after Event [%s]",
+                         bta_hf_client_state_str(in_state),
+                         bta_hf_client_state_str(bta_hf_client_cb.scb.state),
+                         bta_hf_client_evt_str(in_event));
+    }
+#endif
+}
+
+static void send_post_slc_cmd(void)
+{
+    bta_hf_client_cb.scb.at_cb.current_cmd = BTA_HF_CLIENT_AT_NONE;
+
+    bta_hf_client_send_at_bia();
+    bta_hf_client_send_at_ccwa(TRUE);
+    bta_hf_client_send_at_cmee(TRUE);
+    bta_hf_client_send_at_cops(FALSE);
+    bta_hf_client_send_at_btrh(TRUE, 0);
+    bta_hf_client_send_at_clip(TRUE);
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_slc_seq
+**
+** Description      Handles AT commands sequence required for SLC creation
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hf_client_slc_seq(BOOLEAN error)
+{
+    APPL_TRACE_DEBUG("bta_hf_client_slc_seq cmd: %u", bta_hf_client_cb.scb.at_cb.current_cmd);
+
+    if (error) {
+        /* SLC establishment error, sent close rfcomm event */
+        APPL_TRACE_ERROR("HFPClient: Failed to create SLC due to AT error, disconnecting (%u)",
+                         bta_hf_client_cb.scb.at_cb.current_cmd);
+
+        bta_hf_client_sm_execute(BTA_HF_CLIENT_API_CLOSE_EVT, NULL);
+        return;
+    }
+
+    if (bta_hf_client_cb.scb.svc_conn) {
+        return;
+    }
+
+    switch (bta_hf_client_cb.scb.at_cb.current_cmd) {
+    case BTA_HF_CLIENT_AT_NONE:
+        bta_hf_client_send_at_brsf();
+        break;
+
+    case BTA_HF_CLIENT_AT_BRSF:
+        if (bta_hf_client_cb.scb.peer_features & BTA_HF_CLIENT_PEER_CODEC) {
+            bta_hf_client_send_at_bac();
+            break;
+        }
+
+        bta_hf_client_send_at_cind(FALSE);
+        break;
+
+    case BTA_HF_CLIENT_AT_BAC:
+        bta_hf_client_send_at_cind(FALSE);
+        break;
+
+    case BTA_HF_CLIENT_AT_CIND:
+        bta_hf_client_send_at_cind(TRUE);
+        break;
+
+    case BTA_HF_CLIENT_AT_CIND_STATUS:
+        bta_hf_client_send_at_cmer(TRUE);
+        break;
+
+    case BTA_HF_CLIENT_AT_CMER:
+        if (bta_hf_client_cb.scb.peer_features & BTA_HF_CLIENT_PEER_FEAT_3WAY) {
+            bta_hf_client_send_at_chld('?', 0);
+        } else {
+            bta_hf_client_svc_conn_open(NULL);
+            send_post_slc_cmd();
+        }
+        break;
+
+    case BTA_HF_CLIENT_AT_CHLD:
+        bta_hf_client_svc_conn_open(NULL);
+        send_post_slc_cmd();
+        break;
+
+    default:
+        /* If happen there is a bug in SLC creation procedure... */
+        APPL_TRACE_ERROR("HFPClient: Failed to create SLCdue to unexpected AT command, disconnecting (%u)",
+                         bta_hf_client_cb.scb.at_cb.current_cmd);
+
+        bta_hf_client_sm_execute(BTA_HF_CLIENT_API_CLOSE_EVT, NULL);
+        break;
+    }
+}
+
+#if BTA_HF_CLIENT_DEBUG == TRUE
+
+#ifndef CASE_RETURN_STR
+#define CASE_RETURN_STR(const) case const: return #const;
+#endif
+
+static char *bta_hf_client_evt_str(UINT16 event)
+{
+    switch (event) {
+        CASE_RETURN_STR(BTA_HF_CLIENT_API_REGISTER_EVT)
+        CASE_RETURN_STR(BTA_HF_CLIENT_API_DEREGISTER_EVT)
+        CASE_RETURN_STR(BTA_HF_CLIENT_API_OPEN_EVT)
+        CASE_RETURN_STR(BTA_HF_CLIENT_API_CLOSE_EVT)
+        CASE_RETURN_STR(BTA_HF_CLIENT_API_AUDIO_OPEN_EVT)
+        CASE_RETURN_STR(BTA_HF_CLIENT_API_AUDIO_CLOSE_EVT)
+        CASE_RETURN_STR(BTA_HF_CLIENT_RFC_OPEN_EVT)
+        CASE_RETURN_STR(BTA_HF_CLIENT_RFC_CLOSE_EVT)
+        CASE_RETURN_STR(BTA_HF_CLIENT_RFC_SRV_CLOSE_EVT)
+        CASE_RETURN_STR(BTA_HF_CLIENT_RFC_DATA_EVT)
+        CASE_RETURN_STR(BTA_HF_CLIENT_DISC_ACP_RES_EVT)
+        CASE_RETURN_STR(BTA_HF_CLIENT_DISC_INT_RES_EVT)
+        CASE_RETURN_STR(BTA_HF_CLIENT_DISC_OK_EVT)
+        CASE_RETURN_STR(BTA_HF_CLIENT_DISC_FAIL_EVT)
+        CASE_RETURN_STR(BTA_HF_CLIENT_API_ENABLE_EVT)
+        CASE_RETURN_STR(BTA_HF_CLIENT_API_DISABLE_EVT)
+        CASE_RETURN_STR(BTA_HF_CLIENT_SCO_OPEN_EVT)
+        CASE_RETURN_STR(BTA_HF_CLIENT_SCO_CLOSE_EVT)
+        CASE_RETURN_STR(BTA_HF_CLIENT_SEND_AT_CMD_EVT)
+    default:
+        return "Unknown HF Client Event";
+    }
+}
+
+static char *bta_hf_client_state_str(UINT8 state)
+{
+    switch (state) {
+        CASE_RETURN_STR(BTA_HF_CLIENT_INIT_ST)
+        CASE_RETURN_STR(BTA_HF_CLIENT_OPENING_ST)
+        CASE_RETURN_STR(BTA_HF_CLIENT_OPEN_ST)
+        CASE_RETURN_STR(BTA_HF_CLIENT_CLOSING_ST)
+    default:
+        return "Unknown HF Client State";
+    }
+}
+#endif
+#endif /* #if (BTA_HF_INCLUDED == TRUE) */
diff --git a/components/bt/bluedroid/bta/hf_client/bta_hf_client_rfc.c b/components/bt/bluedroid/bta/hf_client/bta_hf_client_rfc.c
new file mode 100644 (file)
index 0000000..1b140db
--- /dev/null
@@ -0,0 +1,246 @@
+/******************************************************************************
+ *
+ *  Copyright (c) 2014 The Android Open Source Project
+ *  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 "common/bt_defs.h"
+#include "bta/bta_api.h"
+#include "bta_hf_client_int.h"
+#include "stack/port_api.h"
+#include "osi/allocator.h"
+
+#if (BTA_HF_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function         bta_hf_client_port_cback
+**
+** Description      RFCOMM Port callback
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+static void bta_hf_client_port_cback(UINT32 code, UINT16 port_handle)
+{
+    BT_HDR      *p_buf;
+    UNUSED(code);
+
+    /* ignore port events for port handles other than connected handle */
+    if (port_handle != bta_hf_client_cb.scb.conn_handle) {
+        APPL_TRACE_DEBUG("bta_hf_client_port_cback ignoring handle:%d conn_handle = %d",
+                         port_handle, bta_hf_client_cb.scb.conn_handle);
+        return;
+    }
+
+    if ((p_buf = (BT_HDR *) osi_malloc(sizeof(BT_HDR))) != NULL) {
+        p_buf->event = BTA_HF_CLIENT_RFC_DATA_EVT;
+        bta_sys_sendmsg(p_buf);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_mgmt_cback
+**
+** Description      RFCOMM management callback
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+static void bta_hf_client_mgmt_cback(UINT32 code, UINT16 port_handle)
+{
+    tBTA_HF_CLIENT_RFC     *p_buf;
+    UINT16                  event;
+
+    APPL_TRACE_DEBUG("bta_hf_client_mgmt_cback : code = %d, port_handle = %d, conn_handle = %d, serv_handle = %d",
+                     code, port_handle, bta_hf_client_cb.scb.conn_handle, bta_hf_client_cb.scb.serv_handle);
+
+    /* ignore close event for port handles other than connected handle */
+    if ((code != PORT_SUCCESS) && (port_handle != bta_hf_client_cb.scb.conn_handle)) {
+        APPL_TRACE_DEBUG("bta_hf_client_mgmt_cback ignoring handle:%d", port_handle);
+        return;
+    }
+
+    if (code == PORT_SUCCESS) {
+        if ((bta_hf_client_cb.scb.conn_handle && (port_handle == bta_hf_client_cb.scb.conn_handle)) || /* outgoing connection */
+                (port_handle == bta_hf_client_cb.scb.serv_handle)) {                     /* incoming connection */
+            event = BTA_HF_CLIENT_RFC_OPEN_EVT;
+        } else {
+            APPL_TRACE_ERROR ("bta_hf_client_mgmt_cback: PORT_SUCCESS, ignoring handle = %d", port_handle);
+            return;
+        }
+    }
+    /* distinguish server close events */
+    else if (port_handle == bta_hf_client_cb.scb.conn_handle) {
+        event = BTA_HF_CLIENT_RFC_CLOSE_EVT;
+    } else {
+        event = BTA_HF_CLIENT_RFC_SRV_CLOSE_EVT;
+    }
+
+    if ((p_buf = (tBTA_HF_CLIENT_RFC *) osi_malloc(sizeof(tBTA_HF_CLIENT_RFC))) != NULL) {
+        p_buf->hdr.event = event;
+        p_buf->port_handle = port_handle;
+        bta_sys_sendmsg(p_buf);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_setup_port
+**
+** Description      Setup RFCOMM port for use by HF Client.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hf_client_setup_port(UINT16 handle)
+{
+    PORT_SetEventMask(handle, PORT_EV_RXCHAR);
+    PORT_SetEventCallback(handle, bta_hf_client_port_cback);
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_start_server
+**
+** Description      Setup RFCOMM server for use by HF Client.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hf_client_start_server(void)
+{
+    int port_status;
+
+    if (bta_hf_client_cb.scb.serv_handle > 0) {
+        APPL_TRACE_DEBUG("%s already started, handle: %d", __FUNCTION__, bta_hf_client_cb.scb.serv_handle);
+        return;
+    }
+
+    BTM_SetSecurityLevel(FALSE, "", BTM_SEC_SERVICE_HF_HANDSFREE, bta_hf_client_cb.scb.serv_sec_mask,
+                         BT_PSM_RFCOMM, BTM_SEC_PROTO_RFCOMM, bta_hf_client_cb.scn);
+
+    port_status =  RFCOMM_CreateConnection(UUID_SERVCLASS_HF_HANDSFREE, bta_hf_client_cb.scn,
+                                           TRUE, BTA_HF_CLIENT_MTU, (UINT8 *) bd_addr_any, &(bta_hf_client_cb.scb.serv_handle),
+                                           bta_hf_client_mgmt_cback);
+
+    if (port_status  == PORT_SUCCESS) {
+        bta_hf_client_setup_port(bta_hf_client_cb.scb.serv_handle);
+    } else {
+        /* TODO: can we handle this better? */
+        APPL_TRACE_DEBUG("bta_hf_client_start_server: RFCOMM_CreateConnection returned error:%d", port_status);
+    }
+
+    APPL_TRACE_DEBUG("bta_hf_client_start_server handle: %d", bta_hf_client_cb.scb.serv_handle);
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_close_server
+**
+** Description      Close RFCOMM server port for use by HF Client.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hf_client_close_server(void)
+{
+    APPL_TRACE_DEBUG("%s %d", __FUNCTION__, bta_hf_client_cb.scb.serv_handle);
+
+    if (bta_hf_client_cb.scb.serv_handle == 0) {
+        APPL_TRACE_DEBUG("%s already stopped", __FUNCTION__);
+        return;
+    }
+
+    RFCOMM_RemoveServer(bta_hf_client_cb.scb.serv_handle);
+    bta_hf_client_cb.scb.serv_handle = 0;
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_rfc_do_open
+**
+** Description      Open an RFCOMM connection to the peer device.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hf_client_rfc_do_open(tBTA_HF_CLIENT_DATA *p_data)
+{
+    BTM_SetSecurityLevel(TRUE, "", BTM_SEC_SERVICE_HF_HANDSFREE,
+                         bta_hf_client_cb.scb.cli_sec_mask, BT_PSM_RFCOMM,
+                         BTM_SEC_PROTO_RFCOMM, bta_hf_client_cb.scb.peer_scn);
+
+    if (RFCOMM_CreateConnection(UUID_SERVCLASS_HF_HANDSFREE, bta_hf_client_cb.scb.peer_scn,
+                                FALSE, BTA_HF_CLIENT_MTU, bta_hf_client_cb.scb.peer_addr, &(bta_hf_client_cb.scb.conn_handle),
+                                bta_hf_client_mgmt_cback) == PORT_SUCCESS) {
+        bta_hf_client_setup_port(bta_hf_client_cb.scb.conn_handle);
+        APPL_TRACE_DEBUG("bta_hf_client_rfc_do_open : conn_handle = %d", bta_hf_client_cb.scb.conn_handle);
+    }
+    /* RFCOMM create connection failed; send ourselves RFCOMM close event */
+    else {
+        bta_hf_client_sm_execute(BTA_HF_CLIENT_RFC_CLOSE_EVT, p_data);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_rfc_do_close
+**
+** Description      Close RFCOMM connection.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hf_client_rfc_do_close(tBTA_HF_CLIENT_DATA *p_data)
+{
+    tBTA_HF_CLIENT_RFC     *p_buf;
+    UNUSED(p_data);
+
+    if (bta_hf_client_cb.scb.conn_handle) {
+        RFCOMM_RemoveConnection(bta_hf_client_cb.scb.conn_handle);
+    } else {
+        /* Close API was called while HF Client 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_HF_CLIENT_RFC *) osi_malloc(sizeof(tBTA_HF_CLIENT_RFC))) != NULL) {
+            p_buf->hdr.event = BTA_HF_CLIENT_RFC_CLOSE_EVT;
+            bta_sys_sendmsg(p_buf);
+        }
+
+        /* Cancel SDP if it had been started. */
+        if (bta_hf_client_cb.scb.p_disc_db) {
+            (void)SDP_CancelServiceSearch (bta_hf_client_cb.scb.p_disc_db);
+            bta_hf_client_free_db(NULL);
+        }
+    }
+}
+#endif /* #if (BTA_HF_INCLUDED == TRUE) */
diff --git a/components/bt/bluedroid/bta/hf_client/bta_hf_client_sco.c b/components/bt/bluedroid/bta/hf_client/bta_hf_client_sco.c
new file mode 100644 (file)
index 0000000..744edc9
--- /dev/null
@@ -0,0 +1,825 @@
+/******************************************************************************
+ *
+ *  Copyright (c) 2014 The Android Open Source Project
+ *  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.
+ *
+ ******************************************************************************/
+
+#include "bta_hf_client_int.h"
+#include "common/bt_trace.h"
+#include <string.h>
+#include "common/bt_defs.h"
+#include "common/bt_target.h"
+#include "osi/allocator.h"
+#if (BTM_SCO_HCI_INCLUDED == TRUE )
+#include "bta/bta_hf_client_co.h"
+#include "hci/hci_audio.h"
+#endif
+
+#if (BTA_HF_INCLUDED == TRUE)
+#define BTA_HF_CLIENT_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)
+
+static const tBTM_ESCO_PARAMS bta_hf_client_esco_params[] = {
+    /* SCO CVSD */
+    {
+        .rx_bw = BTM_64KBITS_RATE,
+        .tx_bw = BTM_64KBITS_RATE,
+        .max_latency = 10,
+        .voice_contfmt = BTM_VOICE_SETTING_CVSD,
+        .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),
+        .retrans_effort = BTM_ESCO_RETRANS_POWER,
+    },
+    /* ESCO CVSD */
+    {
+        .rx_bw = BTM_64KBITS_RATE,
+        .tx_bw = BTM_64KBITS_RATE,
+        .max_latency = 10,
+        .voice_contfmt = BTM_VOICE_SETTING_CVSD,
+        /* Allow controller to use all types available except 5-slot EDR */
+        .packet_types = (BTM_SCO_LINK_ALL_PKT_MASK |
+        BTM_SCO_PKT_TYPES_MASK_NO_2_EV5 |
+        BTM_SCO_PKT_TYPES_MASK_NO_3_EV5),
+        .retrans_effort = BTM_ESCO_RETRANS_POWER,
+    },
+    /* ESCO mSBC */
+    {
+        .rx_bw = BTM_64KBITS_RATE,
+        .tx_bw = BTM_64KBITS_RATE,
+        .max_latency = 13,
+        .voice_contfmt = BTM_VOICE_SETTING_TRANS,
+        /* Packet Types : EV3 + 2-EV3               */
+        .packet_types = (BTM_SCO_PKT_TYPES_MASK_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),
+        .retrans_effort = BTM_ESCO_RETRANS_QUALITY,
+    }
+};
+
+enum {
+    BTA_HF_CLIENT_SCO_LISTEN_E,
+    BTA_HF_CLIENT_SCO_OPEN_E,          /* open request */
+    BTA_HF_CLIENT_SCO_CLOSE_E,         /* close request */
+    BTA_HF_CLIENT_SCO_SHUTDOWN_E,      /* shutdown request */
+    BTA_HF_CLIENT_SCO_CONN_OPEN_E,     /* sco opened */
+    BTA_HF_CLIENT_SCO_CONN_CLOSE_E,    /* sco closed */
+#if (BTM_SCO_HCI_INCLUDED == TRUE )
+    BTA_HF_CLIENT_SCO_CI_DATA_E,       /* sco data ready */
+#endif /* #if (BTM_SCO_HCI_INCLUDED == TRUE ) */
+};
+
+static void bta_hf_client_sco_event(UINT8 event);
+/*******************************************************************************
+**
+** Function         bta_hf_client_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_hf_client_sco_remove(BOOLEAN only_active)
+{
+    BOOLEAN     removed_started = FALSE;
+    tBTM_STATUS status;
+
+    APPL_TRACE_DEBUG("%s %d", __FUNCTION__, only_active);
+
+    if (bta_hf_client_cb.scb.sco_idx != BTM_INVALID_SCO_INDEX) {
+        status = BTM_RemoveSco(bta_hf_client_cb.scb.sco_idx);
+
+        APPL_TRACE_DEBUG("%s idx 0x%04x, status:0x%x", __FUNCTION__, bta_hf_client_cb.scb.sco_idx, status);
+
+        if (status == BTM_CMD_STARTED) {
+            removed_started = TRUE;
+        }
+        /* If no connection reset the sco handle */
+        else if ( (status == BTM_SUCCESS) || (status == BTM_UNKNOWN_ADDR) ) {
+            bta_hf_client_cb.scb.sco_idx = BTM_INVALID_SCO_INDEX;
+        }
+    }
+    return removed_started;
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_cback_sco
+**
+** Description      Call application callback function with SCO event.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hf_client_cback_sco(UINT8 event)
+{
+    tBTA_HF_CLIENT_HDR    evt;
+
+    memset(&evt, 0, sizeof(evt));
+
+    /* call app cback */
+    (*bta_hf_client_cb.p_cback)(event, (tBTA_HF_CLIENT_HDR *) &evt);
+}
+
+#if (BTM_SCO_HCI_INCLUDED == TRUE )
+/*******************************************************************************
+**
+** Function         bta_hf_client_sco_read_cback
+**
+** Description      Callback function is the callback function for incoming
+**                  SCO data over HCI.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void bta_hf_client_sco_read_cback (UINT16 sco_idx, BT_HDR *p_data, tBTM_SCO_DATA_FLAG status)
+{
+    if (status != BTM_SCO_DATA_CORRECT)
+    {
+        APPL_TRACE_DEBUG("%s: status(%d)", __FUNCTION__, status);
+    }
+
+    bta_hf_client_sco_co_in_data (p_data, status);
+    osi_free(p_data);
+}
+#endif /* BTM_SCO_HCI_INCLUDED */
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_sco_conn_rsp
+**
+** Description      Process the SCO connection request
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+static void bta_hf_client_sco_conn_rsp(tBTM_ESCO_CONN_REQ_EVT_DATA *p_data)
+{
+    tBTM_ESCO_PARAMS    resp;
+    UINT8               hci_status = HCI_SUCCESS;
+#if (BTM_SCO_HCI_INCLUDED == TRUE )
+    tBTA_HFP_CODEC_INFO     codec_info = {BTA_HFP_SCO_CODEC_PCM};
+    UINT32              pcm_sample_rate;
+#endif
+    APPL_TRACE_DEBUG("%s", __FUNCTION__);
+
+    if (bta_hf_client_cb.scb.sco_state == BTA_HF_CLIENT_SCO_LISTEN_ST) {
+        if (p_data->link_type == BTM_LINK_TYPE_SCO) {
+            resp = bta_hf_client_esco_params[0];
+        } else {
+            resp = bta_hf_client_esco_params[bta_hf_client_cb.scb.negotiated_codec];
+        }
+
+        /* tell sys to stop av if any */
+        bta_sys_sco_use(BTA_ID_HS, 1, bta_hf_client_cb.scb.peer_addr);
+
+#if (BTM_SCO_HCI_INCLUDED == TRUE )
+        bta_hf_client_co_audio_state(bta_hf_client_cb.scb.sco_idx, SCO_STATE_SETUP, 0);
+        pcm_sample_rate = BTA_HFP_SCO_SAMP_RATE_8K;
+
+        /* initialize SCO setup, no voice setting for AG, data rate <==> sample rate */
+        BTM_ConfigScoPath(bta_hf_client_sco_co_init(pcm_sample_rate, pcm_sample_rate, &codec_info, 0),
+            bta_hf_client_sco_read_cback, NULL, TRUE);
+#endif
+    } else {
+        hci_status = HCI_ERR_HOST_REJECT_DEVICE;
+    }
+
+    BTM_EScoConnRsp(p_data->sco_inx, hci_status, &resp);
+}
+
+#if (BTM_SCO_HCI_INCLUDED == TRUE )
+/*******************************************************************************
+**
+** Function         bta_ag_ci_sco_data
+**
+** Description      Process the SCO data ready callin event
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hf_client_ci_sco_data(tBTA_HF_CLIENT_DATA *p_data)
+{
+    UNUSED(p_data);
+    bta_hf_client_sco_event(BTA_HF_CLIENT_SCO_CI_DATA_E);
+}
+#endif
+/*******************************************************************************
+**
+** Function         bta_hf_client_sco_connreq_cback
+**
+** Description      BTM eSCO connection requests and eSCO change requests
+**                  Only the connection requests are processed by BTA.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void bta_hf_client_esco_connreq_cback(tBTM_ESCO_EVT event, tBTM_ESCO_EVT_DATA *p_data)
+{
+    APPL_TRACE_DEBUG("%s %d", __FUNCTION__, event);
+
+    if (event != BTM_ESCO_CONN_REQ_EVT) {
+        return;
+    }
+
+    /* TODO check remote bdaddr, should allow connect only from device with
+     * active SLC  */
+
+    bta_hf_client_cb.scb.sco_idx = p_data->conn_evt.sco_inx;
+
+    bta_hf_client_sco_conn_rsp(&p_data->conn_evt);
+
+    bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_OPENING_ST;
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_sco_conn_cback
+**
+** Description      BTM SCO connection callback.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+static void bta_hf_client_sco_conn_cback(UINT16 sco_idx)
+{
+    BT_HDR  *p_buf;
+    UINT8 *rem_bd;
+
+    APPL_TRACE_DEBUG("%s %d", __FUNCTION__, sco_idx);
+
+    rem_bd = BTM_ReadScoBdAddr(sco_idx);
+
+    if (rem_bd && bdcmp(bta_hf_client_cb.scb.peer_addr, rem_bd) == 0 &&
+            bta_hf_client_cb.scb.svc_conn && bta_hf_client_cb.scb.sco_idx == sco_idx) {
+        if ((p_buf = (BT_HDR *) osi_malloc(sizeof(BT_HDR))) != NULL) {
+            p_buf->event = BTA_HF_CLIENT_SCO_OPEN_EVT;
+            p_buf->layer_specific = bta_hf_client_cb.scb.conn_handle;
+            bta_sys_sendmsg(p_buf);
+        }
+    }
+    /* no match found; disconnect sco, init sco variables */
+    else {
+        bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_SHUTDOWN_ST;
+        BTM_RemoveSco(sco_idx);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_sco_disc_cback
+**
+** Description      BTM SCO disconnection callback.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+static void bta_hf_client_sco_disc_cback(UINT16 sco_idx)
+{
+    BT_HDR  *p_buf;
+
+    APPL_TRACE_DEBUG("%s %d", __FUNCTION__, sco_idx);
+
+    if (bta_hf_client_cb.scb.sco_idx == sco_idx) {
+#if (BTM_SCO_HCI_INCLUDED == TRUE )
+        tBTM_STATUS status = BTM_ConfigScoPath(BTM_SCO_ROUTE_PCM, NULL, NULL, TRUE);
+        APPL_TRACE_DEBUG("%s close config status = %d", __FUNCTION__, status);
+        /* SCO clean up here */
+        bta_hf_client_sco_co_close();
+#endif
+        if ((p_buf = (BT_HDR *) osi_malloc(sizeof(BT_HDR))) != NULL) {
+            p_buf->event = BTA_HF_CLIENT_SCO_CLOSE_EVT;
+            p_buf->layer_specific = bta_hf_client_cb.scb.conn_handle;;
+            bta_sys_sendmsg(p_buf);
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_create_sco
+**
+** Description
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+static void bta_hf_client_sco_create(BOOLEAN is_orig)
+{
+    tBTM_STATUS       status;
+    UINT8            *p_bd_addr = NULL;
+    tBTM_ESCO_PARAMS params;
+#if (BTM_SCO_HCI_INCLUDED == TRUE )
+    tBTM_SCO_ROUTE_TYPE sco_route;
+    tBTA_HFP_CODEC_INFO codec_info = {BTA_HFP_SCO_CODEC_PCM};
+    UINT32              pcm_sample_rate;
+#endif
+    APPL_TRACE_DEBUG("%s %d", __FUNCTION__, is_orig);
+
+    /* Make sure this sco handle is not already in use */
+    if (bta_hf_client_cb.scb.sco_idx != BTM_INVALID_SCO_INDEX) {
+        APPL_TRACE_WARNING("%s: Index 0x%04x already in use", __FUNCTION__,
+                           bta_hf_client_cb.scb.sco_idx);
+        return;
+    }
+
+    params = bta_hf_client_esco_params[1];
+
+    /* if initiating set current scb and peer bd addr */
+    if (is_orig) {
+        /* Attempt to use eSCO if remote host supports HFP >= 1.5 */
+        if (bta_hf_client_cb.scb.peer_version >= HFP_VERSION_1_5 && !bta_hf_client_cb.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_HF_CLIENT_NO_EDR_ESCO)) {
+                bta_hf_client_cb.scb.retry_with_sco_only = TRUE;
+                APPL_TRACE_API("Setting retry_with_sco_only to TRUE");
+            }
+        } else {
+            if (bta_hf_client_cb.scb.retry_with_sco_only) {
+                APPL_TRACE_API("retrying with SCO only");
+            }
+            bta_hf_client_cb.scb.retry_with_sco_only = FALSE;
+
+            BTM_SetEScoMode(BTM_LINK_TYPE_SCO, &params);
+        }
+
+        /* tell sys to stop av if any */
+        bta_sys_sco_use(BTA_ID_HS, 1, bta_hf_client_cb.scb.peer_addr);
+
+#if (BTM_SCO_HCI_INCLUDED == TRUE )
+        /* Allow any platform specific pre-SCO set up to take place */
+        bta_hf_client_co_audio_state(bta_hf_client_cb.scb.sco_idx, SCO_STATE_SETUP, 0);
+
+        pcm_sample_rate = BTA_HFP_SCO_SAMP_RATE_8K;
+        sco_route = bta_hf_client_sco_co_init(pcm_sample_rate, pcm_sample_rate, &codec_info, 0);
+
+        /* initialize SCO setup, no voice setting for AG, data rate <==> sample rate */
+        BTM_ConfigScoPath(sco_route, bta_hf_client_sco_read_cback, NULL, TRUE);
+#endif
+
+    } else {
+        bta_hf_client_cb.scb.retry_with_sco_only = FALSE;
+    }
+
+    p_bd_addr = bta_hf_client_cb.scb.peer_addr;
+
+    status = BTM_CreateSco(p_bd_addr, is_orig, params.packet_types,
+                           &bta_hf_client_cb.scb.sco_idx, bta_hf_client_sco_conn_cback,
+                           bta_hf_client_sco_disc_cback);
+    if (status == BTM_CMD_STARTED && !is_orig) {
+        if (!BTM_RegForEScoEvts(bta_hf_client_cb.scb.sco_idx, bta_hf_client_esco_connreq_cback)) {
+            APPL_TRACE_DEBUG("%s SCO registration success", __FUNCTION__);
+        }
+    }
+
+    APPL_TRACE_API("%s: orig %d, inx 0x%04x, status 0x%x, pkt types 0x%04x",
+                   __FUNCTION__, is_orig, bta_hf_client_cb.scb.sco_idx,
+                   status, params.packet_types);
+}
+
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_sco_event
+**
+** Description      Handle SCO events
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+static void bta_hf_client_sco_event(UINT8 event)
+{
+    APPL_TRACE_DEBUG("%s state: %d event: %d", __FUNCTION__,
+                     bta_hf_client_cb.scb.sco_state, event);
+
+#if (BTM_SCO_HCI_INCLUDED == TRUE )
+    tBTA_HF_CLIENT_SCB *p_scb = &bta_hf_client_cb.scb;
+    BT_HDR  *p_buf;
+#endif
+
+#if (BTM_SCO_HCI_INCLUDED == TRUE )
+    if (event == BTA_HF_CLIENT_SCO_CI_DATA_E) {
+        uint16_t pkt_offset = 1 + HCI_SCO_PREAMBLE_SIZE;
+        uint16_t len_to_send = 0;
+        uint8_t *p;
+        while (true)
+        {
+            p_buf = osi_malloc(sizeof(BT_HDR) + pkt_offset + BTM_SCO_DATA_SIZE_MAX);
+            if (!p_buf) {
+                APPL_TRACE_WARNING("%s, no mem", __FUNCTION__);
+                break;
+            }
+
+            p_buf->offset = pkt_offset;
+            len_to_send = bta_hf_client_sco_co_out_data(p_buf->data + pkt_offset, BTM_SCO_DATA_SIZE_MAX);
+            if (len_to_send) {
+                if (bta_hf_client_cb.scb.sco_state == BTA_HF_CLIENT_SCO_OPEN_ST) {
+                    p = (UINT8 *)(p_buf->data + pkt_offset -1);
+                    *p = len_to_send; // set SCO packet length;
+                    tBTM_STATUS write_stat = BTM_WriteScoData(p_scb->sco_idx, p_buf);
+                    if (write_stat != BTM_SUCCESS && write_stat != BTM_SCO_BAD_LENGTH) {
+                        break;
+                    }
+                } else {
+                    osi_free(p_buf);
+                }
+            } else {
+                osi_free(p_buf);
+                break;
+            }
+        }
+
+        return;
+    }
+#endif
+
+    switch (bta_hf_client_cb.scb.sco_state) {
+    case BTA_HF_CLIENT_SCO_SHUTDOWN_ST:
+        switch (event) {
+        case BTA_HF_CLIENT_SCO_LISTEN_E:
+            /* create sco listen connection */
+            bta_hf_client_sco_create(FALSE);
+            bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_LISTEN_ST;
+            break;
+
+        default:
+            APPL_TRACE_WARNING("BTA_HF_CLIENT_SCO_SHUTDOWN_ST: Ignoring event %d", event);
+            break;
+        }
+        break;
+
+    case BTA_HF_CLIENT_SCO_LISTEN_ST:
+        switch (event) {
+        case BTA_HF_CLIENT_SCO_LISTEN_E:
+            /* create sco listen connection (Additional channel) */
+            bta_hf_client_sco_create(FALSE);
+            break;
+
+        case BTA_HF_CLIENT_SCO_OPEN_E:
+            /* remove listening connection */
+            bta_hf_client_sco_remove(FALSE);
+
+            /* create sco connection to peer */
+            bta_hf_client_sco_create(TRUE);
+            bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_OPENING_ST;
+            break;
+
+        case BTA_HF_CLIENT_SCO_SHUTDOWN_E:
+            /* remove listening connection */
+            bta_hf_client_sco_remove(FALSE);
+
+            bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_SHUTDOWN_ST;
+            break;
+
+        case BTA_HF_CLIENT_SCO_CLOSE_E:
+            /* remove listening connection */
+            /* Ignore the event. We need to keep listening SCO for the active SLC */
+            APPL_TRACE_WARNING("BTA_HF_CLIENT_SCO_LISTEN_ST: Ignoring event %d", event);
+            break;
+
+        case BTA_HF_CLIENT_SCO_CONN_CLOSE_E:
+            /* sco failed; create sco listen connection */
+            bta_hf_client_sco_create(FALSE);
+            bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_LISTEN_ST;
+            break;
+
+        default:
+            APPL_TRACE_WARNING("BTA_HF_CLIENT_SCO_LISTEN_ST: Ignoring event %d", event);
+            break;
+        }
+        break;
+
+    case BTA_HF_CLIENT_SCO_OPENING_ST:
+        switch (event) {
+        case BTA_HF_CLIENT_SCO_CLOSE_E:
+            bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_OPEN_CL_ST;
+            break;
+
+        case BTA_HF_CLIENT_SCO_SHUTDOWN_E:
+            bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_SHUTTING_ST;
+            break;
+
+        case BTA_HF_CLIENT_SCO_CONN_OPEN_E:
+            bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_OPEN_ST;
+            break;
+
+        case BTA_HF_CLIENT_SCO_CONN_CLOSE_E:
+            /* sco failed; create sco listen connection */
+            bta_hf_client_sco_create(FALSE);
+            bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_LISTEN_ST;
+            break;
+
+        default:
+            APPL_TRACE_WARNING("BTA_HF_CLIENT_SCO_OPENING_ST: Ignoring event %d", event);
+            break;
+        }
+        break;
+
+    case BTA_HF_CLIENT_SCO_OPEN_CL_ST:
+        switch (event) {
+        case BTA_HF_CLIENT_SCO_OPEN_E:
+            bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_OPENING_ST;
+            break;
+
+        case BTA_HF_CLIENT_SCO_SHUTDOWN_E:
+            bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_SHUTTING_ST;
+            break;
+
+        case BTA_HF_CLIENT_SCO_CONN_OPEN_E:
+            /* close sco connection */
+            bta_hf_client_sco_remove(TRUE);
+
+            bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_CLOSING_ST;
+            break;
+
+        case BTA_HF_CLIENT_SCO_CONN_CLOSE_E:
+            /* sco failed; create sco listen connection */
+
+            bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_LISTEN_ST;
+            break;
+
+        default:
+            APPL_TRACE_WARNING("BTA_HF_CLIENT_SCO_OPEN_CL_ST: Ignoring event %d", event);
+            break;
+        }
+        break;
+
+    case BTA_HF_CLIENT_SCO_OPEN_ST:
+        switch (event) {
+        case BTA_HF_CLIENT_SCO_CLOSE_E:
+            /* close sco connection if active */
+            if (bta_hf_client_sco_remove(TRUE)) {
+                bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_CLOSING_ST;
+            }
+            break;
+
+        case BTA_HF_CLIENT_SCO_SHUTDOWN_E:
+            /* remove all listening connections */
+            bta_hf_client_sco_remove(FALSE);
+
+            bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_SHUTTING_ST;
+            break;
+
+        case BTA_HF_CLIENT_SCO_CONN_CLOSE_E:
+            /* peer closed sco; create sco listen connection */
+            bta_hf_client_sco_create(FALSE);
+            bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_LISTEN_ST;
+            break;
+
+        default:
+            APPL_TRACE_WARNING("BTA_HF_CLIENT_SCO_OPEN_ST: Ignoring event %d", event);
+            break;
+        }
+        break;
+
+    case BTA_HF_CLIENT_SCO_CLOSING_ST:
+        switch (event) {
+        case BTA_HF_CLIENT_SCO_OPEN_E:
+            bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_CLOSE_OP_ST;
+            break;
+
+        case BTA_HF_CLIENT_SCO_SHUTDOWN_E:
+            bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_SHUTTING_ST;
+            break;
+
+        case BTA_HF_CLIENT_SCO_CONN_CLOSE_E:
+            /* peer closed sco; create sco listen connection */
+            bta_hf_client_sco_create(FALSE);
+
+            bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_LISTEN_ST;
+            break;
+
+        default:
+            APPL_TRACE_WARNING("BTA_HF_CLIENT_SCO_CLOSING_ST: Ignoring event %d", event);
+            break;
+        }
+        break;
+
+    case BTA_HF_CLIENT_SCO_CLOSE_OP_ST:
+        switch (event) {
+        case BTA_HF_CLIENT_SCO_CLOSE_E:
+            bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_CLOSING_ST;
+            break;
+
+        case BTA_HF_CLIENT_SCO_SHUTDOWN_E:
+            bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_SHUTTING_ST;
+            break;
+
+        case BTA_HF_CLIENT_SCO_CONN_CLOSE_E:
+            /* open sco connection */
+            bta_hf_client_sco_create(TRUE);
+            bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_OPENING_ST;
+            break;
+
+        default:
+            APPL_TRACE_WARNING("BTA_HF_CLIENT_SCO_CLOSE_OP_ST: Ignoring event %d", event);
+            break;
+        }
+        break;
+
+    case BTA_HF_CLIENT_SCO_SHUTTING_ST:
+        switch (event) {
+        case BTA_HF_CLIENT_SCO_CONN_OPEN_E:
+            /* close sco connection; wait for conn close event */
+            bta_hf_client_sco_remove(TRUE);
+            break;
+
+        case BTA_HF_CLIENT_SCO_CONN_CLOSE_E:
+            bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_SHUTDOWN_ST;
+            break;
+
+        case BTA_HF_CLIENT_SCO_SHUTDOWN_E:
+            bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_SHUTDOWN_ST;
+            break;
+
+        default:
+            APPL_TRACE_WARNING("BTA_HF_CLIENT_SCO_SHUTTING_ST: Ignoring event %d", event);
+            break;
+        }
+        break;
+
+    default:
+        break;
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_sco_listen
+**
+** Description      Initialize SCO listener
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hf_client_sco_listen(tBTA_HF_CLIENT_DATA *p_data)
+{
+    UNUSED(p_data);
+
+    APPL_TRACE_DEBUG("%s", __FUNCTION__);
+
+    bta_hf_client_sco_event(BTA_HF_CLIENT_SCO_LISTEN_E);
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_sco_shutdown
+**
+** Description
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hf_client_sco_shutdown(tBTA_HF_CLIENT_DATA *p_data)
+{
+    UNUSED(p_data);
+
+    APPL_TRACE_DEBUG("%s", __FUNCTION__);
+
+    bta_hf_client_sco_event(BTA_HF_CLIENT_SCO_SHUTDOWN_E);
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_sco_conn_open
+**
+** Description
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hf_client_sco_conn_open(tBTA_HF_CLIENT_DATA *p_data)
+{
+    UNUSED(p_data);
+
+    APPL_TRACE_DEBUG("%s", __FUNCTION__);
+
+    bta_hf_client_sco_event(BTA_HF_CLIENT_SCO_CONN_OPEN_E);
+
+    bta_sys_sco_open(BTA_ID_HS, 1, bta_hf_client_cb.scb.peer_addr);
+#if (BTM_SCO_HCI_INCLUDED == TRUE)
+    bta_hf_client_co_audio_state(bta_hf_client_cb.scb.sco_idx, SCO_STATE_ON, 0);
+    /* open SCO codec if SCO is routed through transport */
+    bta_hf_client_sco_co_open(bta_hf_client_cb.scb.sco_idx, BTA_HFP_SCO_OUT_PKT_SIZE, BTA_HF_CLIENT_CI_SCO_DATA_EVT);
+#endif
+
+    if (bta_hf_client_cb.scb.negotiated_codec == BTM_SCO_CODEC_MSBC) {
+        bta_hf_client_cback_sco(BTA_HF_CLIENT_AUDIO_MSBC_OPEN_EVT);
+    } else {
+        bta_hf_client_cback_sco(BTA_HF_CLIENT_AUDIO_OPEN_EVT);
+    }
+
+    bta_hf_client_cb.scb.retry_with_sco_only = FALSE;
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_sco_conn_close
+**
+** Description
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hf_client_sco_conn_close(tBTA_HF_CLIENT_DATA *p_data)
+{
+    APPL_TRACE_DEBUG("%s", __FUNCTION__);
+
+    /* clear current scb */
+    bta_hf_client_cb.scb.sco_idx = BTM_INVALID_SCO_INDEX;
+
+    /* retry_with_sco_only, will be set only when initiator
+    ** and HFClient is first trying to establish an eSCO connection */
+    if (bta_hf_client_cb.scb.retry_with_sco_only && bta_hf_client_cb.scb.svc_conn) {
+        bta_hf_client_sco_create(TRUE);
+    } else {
+        bta_hf_client_sco_event(BTA_HF_CLIENT_SCO_CONN_CLOSE_E);
+
+        bta_sys_sco_close(BTA_ID_HS, 1, bta_hf_client_cb.scb.peer_addr);
+
+        bta_sys_sco_unuse(BTA_ID_HS, 1, bta_hf_client_cb.scb.peer_addr);
+
+        /* call app callback */
+        bta_hf_client_cback_sco(BTA_HF_CLIENT_AUDIO_CLOSE_EVT);
+
+        if (bta_hf_client_cb.scb.sco_close_rfc == TRUE) {
+            bta_hf_client_cb.scb.sco_close_rfc = FALSE;
+            bta_hf_client_rfc_do_close(p_data);
+        }
+    }
+    bta_hf_client_cb.scb.retry_with_sco_only = FALSE;
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_sco_open
+**
+** Description
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hf_client_sco_open(tBTA_HF_CLIENT_DATA *p_data)
+{
+    UNUSED(p_data);
+
+    APPL_TRACE_DEBUG("%s", __FUNCTION__);
+
+    bta_hf_client_sco_event(BTA_HF_CLIENT_SCO_OPEN_E);
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_sco_close
+**
+** Description
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hf_client_sco_close(tBTA_HF_CLIENT_DATA *p_data)
+{
+    UNUSED(p_data);
+
+    APPL_TRACE_DEBUG("%s  0x%x", __FUNCTION__, bta_hf_client_cb.scb.sco_idx);
+
+    if (bta_hf_client_cb.scb.sco_idx != BTM_INVALID_SCO_INDEX) {
+        bta_hf_client_sco_event(BTA_HF_CLIENT_SCO_CLOSE_E);
+    }
+}
+
+#endif /* #if (BTA_HF_INCLUDED == TRUE) */
diff --git a/components/bt/bluedroid/bta/hf_client/bta_hf_client_sdp.c b/components/bt/bluedroid/bta/hf_client/bta_hf_client_sdp.c
new file mode 100644 (file)
index 0000000..920fcc9
--- /dev/null
@@ -0,0 +1,367 @@
+/******************************************************************************
+ *
+ *  Copyright (c) 2014 The Android Open Source Project
+ *  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/bta_api.h"
+#include "bta/bta_sys.h"
+#include "common/bt_defs.h"
+#include "bta/bta_hf_client_api.h"
+#include "bta_hf_client_int.h"
+#include "osi/allocator.h"
+
+#if (BTA_HF_INCLUDED == TRUE)
+/* Number of protocol elements in protocol element list. */
+#define BTA_HF_CLIENT_NUM_PROTO_ELEMS      2
+
+/* Number of elements in service class id list. */
+#define BTA_HF_CLIENT_NUM_SVC_ELEMS        2
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_sdp_cback
+**
+** Description      SDP callback function.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+static void bta_hf_client_sdp_cback(UINT16 status)
+{
+    tBTA_HF_CLIENT_DISC_RESULT *p_buf;
+    UINT16                     event;
+
+    APPL_TRACE_DEBUG("bta_hf_client_sdp_cback status:0x%x", status);
+
+    /* set event according to int/acp */
+    if (bta_hf_client_cb.scb.role == BTA_HF_CLIENT_ACP) {
+        event = BTA_HF_CLIENT_DISC_ACP_RES_EVT;
+    } else {
+        event = BTA_HF_CLIENT_DISC_INT_RES_EVT;
+    }
+
+    if ((p_buf = (tBTA_HF_CLIENT_DISC_RESULT *) osi_malloc(sizeof(tBTA_HF_CLIENT_DISC_RESULT))) != NULL) {
+        p_buf->hdr.event = event;
+        p_buf->status = status;
+        bta_sys_sendmsg(p_buf);
+    }
+}
+
+/******************************************************************************
+**
+** Function         bta_hf_client_add_record
+**
+** Description      This function is called by a server application to add
+**                  HFP Client 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_hf_client_add_record(char *p_service_name, UINT8 scn,
+                                 tBTA_HF_CLIENT_FEAT features, UINT32 sdp_handle)
+{
+    tSDP_PROTOCOL_ELEM  proto_elem_list[BTA_HF_CLIENT_NUM_PROTO_ELEMS];
+    UINT16              svc_class_id_list[BTA_HF_CLIENT_NUM_SVC_ELEMS];
+    UINT16              browse_list[] = {UUID_SERVCLASS_PUBLIC_BROWSE_GROUP};
+    UINT16              version;
+    UINT16              profile_uuid;
+    BOOLEAN             result = TRUE;
+    UINT8               buf[2];
+    UINT16              sdp_features = 0;
+
+    APPL_TRACE_DEBUG("bta_hf_client_add_record");
+
+    memset( proto_elem_list, 0 , BTA_HF_CLIENT_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_HF_CLIENT_NUM_PROTO_ELEMS, proto_elem_list);
+
+    /* add service class id list */
+    svc_class_id_list[0] = UUID_SERVCLASS_HF_HANDSFREE;
+    svc_class_id_list[1] = UUID_SERVCLASS_GENERIC_AUDIO;
+    result &= SDP_AddServiceClassIdList(sdp_handle, BTA_HF_CLIENT_NUM_SVC_ELEMS, svc_class_id_list);
+
+    /* add profile descriptor list */
+    profile_uuid = UUID_SERVCLASS_HF_HANDSFREE;
+    version = HFP_VERSION_1_6;
+
+    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 */
+    if (features & BTA_HF_CLIENT_FEAT_ECNR) {
+        sdp_features |= BTA_HF_CLIENT_FEAT_ECNR;
+    }
+
+    if (features & BTA_HF_CLIENT_FEAT_3WAY) {
+        sdp_features |= BTA_HF_CLIENT_FEAT_3WAY;
+    }
+
+    if (features & BTA_HF_CLIENT_FEAT_CLI) {
+        sdp_features |= BTA_HF_CLIENT_FEAT_CLI;
+    }
+
+    if (features & BTA_HF_CLIENT_FEAT_VREC) {
+        sdp_features |= BTA_HF_CLIENT_FEAT_VREC;
+    }
+
+    if (features & BTA_HF_CLIENT_FEAT_VOL) {
+        sdp_features |= BTA_HF_CLIENT_FEAT_VOL;
+    }
+
+    /* Codec bit position is different in SDP (bit 5) and in BRSF (bit 7) */
+    if (features & BTA_HF_CLIENT_FEAT_CODEC) {
+        sdp_features |= 0x0020;
+    }
+
+    UINT16_TO_BE_FIELD(buf, sdp_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_hf_client_create_record
+**
+** Description      Create SDP record for registered service.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hf_client_create_record(tBTA_HF_CLIENT_DATA *p_data)
+{
+    /* add sdp record if not already registered */
+    if (bta_hf_client_cb.sdp_handle == 0) {
+        bta_hf_client_cb.sdp_handle = SDP_CreateRecord();
+        bta_hf_client_cb.scn = BTM_AllocateSCN();
+        bta_hf_client_add_record(p_data->api_register.name,
+                                 bta_hf_client_cb.scn,
+                                 p_data->api_register.features,
+                                 bta_hf_client_cb.sdp_handle);
+
+        bta_sys_add_uuid(UUID_SERVCLASS_HF_HANDSFREE);
+    }
+
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_del_record
+**
+** Description      Delete SDP record for registered service.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hf_client_del_record(tBTA_HF_CLIENT_DATA *p_data)
+{
+    UNUSED(p_data);
+
+    APPL_TRACE_DEBUG("bta_hf_client_del_record");
+
+    if (bta_hf_client_cb.sdp_handle != 0) {
+        SDP_DeleteRecord(bta_hf_client_cb.sdp_handle);
+        bta_hf_client_cb.sdp_handle = 0;
+        BTM_FreeSCN(bta_hf_client_cb.scn);
+        BTM_SecClrService(BTM_SEC_SERVICE_HF_HANDSFREE);
+        bta_sys_remove_uuid(UUID_SERVCLASS_HF_HANDSFREE);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_sdp_find_attr
+**
+** Description      Process SDP discovery results to find requested attribute
+**
+**
+** Returns          TRUE if results found, FALSE otherwise.
+**
+*******************************************************************************/
+BOOLEAN bta_hf_client_sdp_find_attr(void)
+{
+    tSDP_DISC_REC       *p_rec = NULL;
+    tSDP_DISC_ATTR      *p_attr;
+    tSDP_PROTOCOL_ELEM  pe;
+    BOOLEAN             result = FALSE;
+
+    bta_hf_client_cb.scb.peer_version = HFP_VERSION_1_1;   /* Default version */
+
+    /* loop through all records we found */
+    while (TRUE) {
+        /* get next record; if none found, we're done */
+        if ((p_rec = SDP_FindServiceInDb(bta_hf_client_cb.scb.p_disc_db, UUID_SERVCLASS_AG_HANDSFREE, p_rec)) == NULL) {
+            break;
+        }
+
+        /* get scn from proto desc list if initiator */
+        if (bta_hf_client_cb.scb.role == BTA_HF_CLIENT_INT) {
+            if (SDP_FindProtocolListElemInRec(p_rec, UUID_PROTOCOL_RFCOMM, &pe)) {
+                bta_hf_client_cb.scb.peer_scn = (UINT8) pe.params[0];
+            } else {
+                continue;
+            }
+        }
+
+        /* get profile version (if failure, version parameter is not updated) */
+        SDP_FindProfileVersionInRec(p_rec, UUID_SERVCLASS_HF_HANDSFREE, &bta_hf_client_cb.scb.peer_version);
+
+        /* get features */
+        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 (bta_hf_client_cb.scb.peer_features == 0) {
+                bta_hf_client_cb.scb.peer_features = p_attr->attr_value.v.u16;
+
+                /* SDP and BRSF WBS bit are different, correct it if set */
+                if (bta_hf_client_cb.scb.peer_features & 0x0020) {
+                    bta_hf_client_cb.scb.peer_features &= ~0x0020;
+                    bta_hf_client_cb.scb.peer_features |= BTA_HF_CLIENT_PEER_CODEC;
+                }
+
+                /* get network for ability to reject calls */
+                if ((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_NETWORK)) != NULL) {
+                    if (p_attr->attr_value.v.u16 == 0x01) {
+                        bta_hf_client_cb.scb.peer_features |= BTA_HF_CLIENT_PEER_REJECT;
+                    }
+                }
+            }
+        }
+
+        /* found what we needed */
+        result = TRUE;
+        break;
+    }
+
+    APPL_TRACE_DEBUG("%s peer_version=0x%x peer_features=0x%x",
+                     __FUNCTION__, bta_hf_client_cb.scb.peer_version,
+                     bta_hf_client_cb.scb.peer_features);
+
+    return result;
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_do_disc
+**
+** Description      Do service discovery.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hf_client_do_disc(void)
+{
+    tSDP_UUID       uuid_list[2];
+    UINT16          num_uuid = 1;
+    UINT16          attr_list[4];
+    UINT8           num_attr;
+    BOOLEAN         db_inited = FALSE;
+
+    /* initiator; get proto list and features */
+    if (bta_hf_client_cb.scb.role == BTA_HF_CLIENT_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_AG_HANDSFREE;
+    }
+    /* acceptor; get features */
+    else {
+        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_AG_HANDSFREE;
+    }
+
+    /* allocate buffer for sdp database */
+    bta_hf_client_cb.scb.p_disc_db = (tSDP_DISCOVERY_DB *) osi_malloc(BT_DEFAULT_BUFFER_SIZE);
+
+    if (bta_hf_client_cb.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(bta_hf_client_cb.scb.p_disc_db, BT_DEFAULT_BUFFER_SIZE, num_uuid,
+                                        uuid_list, num_attr, attr_list);
+    }
+
+    if (db_inited) {
+        /*Service discovery not initiated */
+        db_inited = SDP_ServiceSearchAttributeRequest(bta_hf_client_cb.scb.peer_addr,
+                    bta_hf_client_cb.scb.p_disc_db, bta_hf_client_sdp_cback);
+    }
+
+    if (!db_inited) {
+        /*free discover db */
+        bta_hf_client_free_db(NULL);
+        /* sent failed event */
+        bta_hf_client_sm_execute(BTA_HF_CLIENT_DISC_FAIL_EVT, NULL);
+    }
+
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_free_db
+**
+** Description      Free discovery database.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hf_client_free_db(tBTA_HF_CLIENT_DATA *p_data)
+{
+    UNUSED(p_data);
+
+    if (bta_hf_client_cb.scb.p_disc_db != NULL) {
+        osi_free(bta_hf_client_cb.scb.p_disc_db);
+        bta_hf_client_cb.scb.p_disc_db = NULL;
+    }
+}
+#endif /* #if (BTA_HF_INCLUDED == TRUE) */
diff --git a/components/bt/bluedroid/bta/hf_client/include/bta_hf_client_at.h b/components/bt/bluedroid/bta/hf_client/include/bta_hf_client_at.h
new file mode 100644 (file)
index 0000000..922e5e4
--- /dev/null
@@ -0,0 +1,117 @@
+/******************************************************************************
+ *
+ *  Copyright (c) 2014 The Android Open Source Project
+ *  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.
+ *
+ ******************************************************************************/
+
+/*****************************************************************************
+**  Data types
+*****************************************************************************/
+#include "common/bt_target.h"
+#if (BTA_HF_INCLUDED == TRUE)
+
+/* ASCII character string of arguments to the AT command */
+#define BTA_HF_CLIENT_AT_MAX_LEN        512
+
+/* 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);
+
+enum {
+    BTA_HF_CLIENT_AT_NONE,
+    BTA_HF_CLIENT_AT_BRSF,
+    BTA_HF_CLIENT_AT_BAC,
+    BTA_HF_CLIENT_AT_CIND,
+    BTA_HF_CLIENT_AT_CIND_STATUS,
+    BTA_HF_CLIENT_AT_CMER,
+    BTA_HF_CLIENT_AT_CHLD,
+    BTA_HF_CLIENT_AT_CMEE,
+    BTA_HF_CLIENT_AT_BIA,
+    BTA_HF_CLIENT_AT_CLIP,
+    BTA_HF_CLIENT_AT_CCWA,
+    BTA_HF_CLIENT_AT_COPS,
+    BTA_HF_CLIENT_AT_CLCC,
+    BTA_HF_CLIENT_AT_BVRA,
+    BTA_HF_CLIENT_AT_VGS,
+    BTA_HF_CLIENT_AT_VGM,
+    BTA_HF_CLIENT_AT_ATD,
+    BTA_HF_CLIENT_AT_BLDN,
+    BTA_HF_CLIENT_AT_ATA,
+    BTA_HF_CLIENT_AT_CHUP,
+    BTA_HF_CLIENT_AT_BTRH,
+    BTA_HF_CLIENT_AT_VTS,
+    BTA_HF_CLIENT_AT_BCC,
+    BTA_HF_CLIENT_AT_BCS,
+    BTA_HF_CLIENT_AT_CNUM,
+    BTA_HF_CLIENT_AT_NREC,
+    BTA_HF_CLIENT_AT_BINP,
+};
+
+typedef UINT8 tBTA_HF_CLIENT_AT_CMD;
+
+/* Maximum combined buffer for received AT events string */
+#define BTA_HF_CLIENT_AT_PARSER_MAX_LEN        4096
+
+/* This structure holds prepared AT command queued for sending */
+struct queued_at_cmd {
+    tBTA_HF_CLIENT_AT_CMD cmd;
+    char buf[BTA_HF_CLIENT_AT_MAX_LEN];
+    UINT16 buf_len;
+    struct queued_at_cmd *next;
+};
+typedef struct queued_at_cmd tBTA_HF_CLIENT_AT_QCMD;
+
+/* Maximum number of indicators */
+#define BTA_HF_CLIENT_AT_INDICATOR_COUNT 20
+
+/* AT command parsing control block */
+typedef struct {
+    char                    buf[BTA_HF_CLIENT_AT_PARSER_MAX_LEN + 1]; /* extra byte to always have \0 at the end */
+    unsigned int            offset;
+    tBTA_HF_CLIENT_AT_CMD   current_cmd;
+    tBTA_HF_CLIENT_AT_QCMD  *queued_cmd;
+
+    TIMER_LIST_ENT          resp_timer;    /* AT response timer */
+    BOOLEAN                 resp_timer_on; /* TRUE if AT response timer is active */
+
+    TIMER_LIST_ENT          hold_timer;    /* AT hold timer */
+    BOOLEAN                 hold_timer_on; /* TRUE if AT hold timer is active */
+
+    /* CIND: lookup table to store the sequence of incoming indicators and their values
+       so when their values come later, we know which value in sequence match certain indicator */
+    int                     indicator_lookup[BTA_HF_CLIENT_AT_INDICATOR_COUNT];
+
+} tBTA_HF_CLIENT_AT_CB;
+
+/*****************************************************************************
+**  Functions
+*****************************************************************************/
+
+void bta_hf_client_at_init(void);
+void bta_hf_client_at_reset(void);
+#endif /* #if (BTA_HF_INCLUDED == TRUE) */
diff --git a/components/bt/bluedroid/bta/hf_client/include/bta_hf_client_int.h b/components/bt/bluedroid/bta/hf_client/include/bta_hf_client_int.h
new file mode 100644 (file)
index 0000000..2e3fab9
--- /dev/null
@@ -0,0 +1,296 @@
+/******************************************************************************
+ *
+ *  Copyright (c) 2014 The Android Open Source Project
+ *  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.
+ *
+ ******************************************************************************/
+
+#include "bta/bta_sys.h"
+#include "bta/bta_api.h"
+#include "bta/bta_hf_client_api.h"
+#include "bta_hf_client_at.h"
+
+#if (BTA_HF_INCLUDED == TRUE)
+/*****************************************************************************
+**  Constants
+*****************************************************************************/
+#define HFP_VERSION_1_1         0x0101
+#define HFP_VERSION_1_5         0x0105
+#define HFP_VERSION_1_6         0x0106
+
+/* RFCOMM MTU SIZE */
+#define BTA_HF_CLIENT_MTU       256
+
+/* profile role for connection */
+#define BTA_HF_CLIENT_ACP       0       /* accepted connection */
+#define BTA_HF_CLIENT_INT       1       /* initiating connection */
+
+/* Timer to wait for retry in case of collision */
+#ifndef BTA_HF_CLIENT_COLLISION_TIMER
+#define BTA_HF_CLIENT_COLLISION_TIMER  2411
+#endif
+
+enum {
+    /* these events are handled by the state machine */
+    BTA_HF_CLIENT_API_REGISTER_EVT = BTA_SYS_EVT_START(BTA_ID_HS),
+    BTA_HF_CLIENT_API_DEREGISTER_EVT,
+    BTA_HF_CLIENT_API_OPEN_EVT,
+    BTA_HF_CLIENT_API_CLOSE_EVT,
+    BTA_HF_CLIENT_API_AUDIO_OPEN_EVT,
+    BTA_HF_CLIENT_API_AUDIO_CLOSE_EVT,
+    BTA_HF_CLIENT_RFC_OPEN_EVT,
+    BTA_HF_CLIENT_RFC_CLOSE_EVT,
+    BTA_HF_CLIENT_RFC_SRV_CLOSE_EVT,
+    BTA_HF_CLIENT_RFC_DATA_EVT,
+    BTA_HF_CLIENT_DISC_ACP_RES_EVT,
+    BTA_HF_CLIENT_DISC_INT_RES_EVT,
+    BTA_HF_CLIENT_DISC_OK_EVT,
+    BTA_HF_CLIENT_DISC_FAIL_EVT,
+    BTA_HF_CLIENT_SCO_OPEN_EVT,
+    BTA_HF_CLIENT_SCO_CLOSE_EVT,
+    BTA_HF_CLIENT_SEND_AT_CMD_EVT,
+#if (BTM_SCO_HCI_INCLUDED == TRUE )
+    BTA_HF_CLIENT_CI_SCO_DATA_EVT,
+#endif /* (BTM_SCO_HCI_INCLUDED == TRUE ) */
+    BTA_HF_CLIENT_MAX_EVT,
+
+    /* these events are handled outside of the state machine */
+    BTA_HF_CLIENT_API_ENABLE_EVT,
+    BTA_HF_CLIENT_API_DISABLE_EVT
+};
+
+/*****************************************************************************
+**  Data types
+*****************************************************************************/
+
+/* data type for BTA_HF_CLIENT_API_ENABLE_EVT */
+typedef struct {
+    BT_HDR                     hdr;
+    tBTA_HF_CLIENT_CBACK      *p_cback;
+} tBTA_HF_CLIENT_API_ENABLE;
+
+/* data type for BTA_HF_CLIENT_API_REGISTER_EVT */
+typedef struct {
+    BT_HDR                     hdr;
+    tBTA_HF_CLIENT_CBACK      *p_cback;
+    tBTA_SEC                   sec_mask;
+    tBTA_HF_CLIENT_FEAT        features;
+    char                       name[BTA_SERVICE_NAME_LEN + 1];
+} tBTA_HF_CLIENT_API_REGISTER;
+
+/* data type for BTA_HF_CLIENT_API_OPEN_EVT */
+typedef struct {
+    BT_HDR              hdr;
+    BD_ADDR             bd_addr;
+    tBTA_SEC            sec_mask;
+} tBTA_HF_CLIENT_API_OPEN;
+
+/* data type for BTA_HF_CLIENT_DISC_RESULT_EVT */
+typedef struct {
+    BT_HDR          hdr;
+    UINT16          status;
+} tBTA_HF_CLIENT_DISC_RESULT;
+
+/* data type for RFCOMM events */
+typedef struct {
+    BT_HDR          hdr;
+    UINT16          port_handle;
+} tBTA_HF_CLIENT_RFC;
+
+/* generic purpose data type for other events */
+typedef struct {
+    BT_HDR          hdr;
+    BOOLEAN         bool_val;
+    UINT8           uint8_val;
+    UINT32          uint32_val1;
+    UINT32          uint32_val2;
+    char            str[BTA_HF_CLIENT_NUMBER_LEN + 1];
+} tBTA_HF_CLIENT_DATA_VAL;
+
+/* union of all event datatypes */
+typedef union {
+    BT_HDR                         hdr;
+    tBTA_HF_CLIENT_API_ENABLE      api_enable;
+    tBTA_HF_CLIENT_API_REGISTER    api_register;
+    tBTA_HF_CLIENT_API_OPEN        api_open;
+    tBTA_HF_CLIENT_DISC_RESULT     disc_result;
+    tBTA_HF_CLIENT_RFC             rfc;
+    tBTA_HF_CLIENT_DATA_VAL        val;
+
+} tBTA_HF_CLIENT_DATA;
+
+/* type for each service control block */
+typedef struct {
+    UINT16              serv_handle;    /* RFCOMM server handle */
+    BD_ADDR             peer_addr;      /* peer bd address */
+    tSDP_DISCOVERY_DB   *p_disc_db;     /* pointer to discovery database */
+    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_HF_CLIENT_FEAT        features;       /* features registered by application */
+    tBTA_HF_CLIENT_PEER_FEAT   peer_features;  /* peer device features */
+    tBTA_HF_CLIENT_CHLD_FEAT   chld_features;  /* call handling features */
+    UINT16              peer_version;   /* profile version of peer device */
+    UINT8               peer_scn;       /* peer scn */
+    UINT8               role;           /* initiator/acceptor role */
+    UINT16              sco_idx;        /* SCO handle */
+    UINT8               sco_state;      /* SCO state variable */
+    BOOLEAN             sco_close_rfc;   /* TRUE if also close RFCOMM after SCO */
+    BOOLEAN             retry_with_sco_only;
+    BOOLEAN             deregister;     /* TRUE if service shutting down */
+    BOOLEAN             svc_conn;       /* set to TRUE when service level connection is up */
+    BOOLEAN             send_at_reply;  /* set to TRUE to notify framework about AT results */
+    tBTA_HF_CLIENT_AT_CB at_cb;         /* AT Parser control block */
+    UINT8               state;          /* state machine state */
+    tBTM_SCO_CODEC_TYPE negotiated_codec; /* negotiated codec */
+    TIMER_LIST_ENT      colli_timer;    /* Collision timer */
+    BOOLEAN             colli_tmr_on;   /* TRUE if collision timer is active */
+} tBTA_HF_CLIENT_SCB;
+
+/* sco states */
+enum {
+    BTA_HF_CLIENT_SCO_SHUTDOWN_ST,  /* no listening, no connection */
+    BTA_HF_CLIENT_SCO_LISTEN_ST,    /* listening */
+    BTA_HF_CLIENT_SCO_OPENING_ST,   /* connection opening */
+    BTA_HF_CLIENT_SCO_OPEN_CL_ST,   /* opening connection being closed */
+    BTA_HF_CLIENT_SCO_OPEN_ST,      /* open */
+    BTA_HF_CLIENT_SCO_CLOSING_ST,   /* closing */
+    BTA_HF_CLIENT_SCO_CLOSE_OP_ST,  /* closing sco being opened */
+    BTA_HF_CLIENT_SCO_SHUTTING_ST   /* sco shutting down */
+};
+
+/* type for AG control block */
+typedef struct {
+    tBTA_HF_CLIENT_SCB         scb;             /* service control block */
+    UINT32                     sdp_handle;
+    UINT8                      scn;
+    tBTA_HF_CLIENT_CBACK       *p_cback;        /* application callback */
+    BOOLEAN                    msbc_enabled;
+} tBTA_HF_CLIENT_CB;
+
+/*****************************************************************************
+**  Global data
+*****************************************************************************/
+
+/* control block declaration */
+#if BTA_DYNAMIC_MEMORY == FALSE
+extern tBTA_HF_CLIENT_CB bta_hf_client_cb;
+#else
+extern tBTA_HF_CLIENT_CB *bta_hf_client_cb_ptr;
+#define bta_hf_client_cb (*bta_hf_client_cb_ptr)
+#endif
+
+/*****************************************************************************
+**  Function prototypes
+*****************************************************************************/
+
+/* main functions */
+extern void bta_hf_client_scb_init(void);
+extern void bta_hf_client_scb_disable(void);
+extern BOOLEAN bta_hf_client_hdl_event(BT_HDR *p_msg);
+extern void bta_hf_client_sm_execute(UINT16 event,
+                                     tBTA_HF_CLIENT_DATA *p_data);
+extern void bta_hf_client_slc_seq(BOOLEAN error);
+extern void bta_hf_client_collision_cback (tBTA_SYS_CONN_STATUS status, UINT8 id,
+        UINT8 app_id, BD_ADDR peer_addr);
+extern void bta_hf_client_resume_open ();
+
+/* SDP functions */
+extern BOOLEAN bta_hf_client_add_record(char *p_service_name,
+                                        UINT8 scn, tBTA_HF_CLIENT_FEAT features,
+                                        UINT32 sdp_handle);
+extern void bta_hf_client_create_record(tBTA_HF_CLIENT_DATA *p_data);
+extern void bta_hf_client_del_record(tBTA_HF_CLIENT_DATA *p_data);
+extern BOOLEAN bta_hf_client_sdp_find_attr(void);
+extern void bta_hf_client_do_disc(void);
+extern void bta_hf_client_free_db(tBTA_HF_CLIENT_DATA *p_data);
+
+/* RFCOMM functions */
+extern void bta_hf_client_setup_port(UINT16 handle);
+extern void bta_hf_client_start_server(void);
+extern void bta_hf_client_close_server(void);
+extern void bta_hf_client_rfc_do_open(tBTA_HF_CLIENT_DATA *p_data);
+extern void bta_hf_client_rfc_do_close(tBTA_HF_CLIENT_DATA *p_data);
+
+/* SCO functions */
+extern void bta_hf_client_sco_listen(tBTA_HF_CLIENT_DATA *p_data);
+extern void bta_hf_client_sco_shutdown(tBTA_HF_CLIENT_DATA *p_data);
+extern void bta_hf_client_sco_conn_open(tBTA_HF_CLIENT_DATA *p_data);
+extern void bta_hf_client_sco_conn_close(tBTA_HF_CLIENT_DATA *p_data);
+extern void bta_hf_client_sco_open(tBTA_HF_CLIENT_DATA *p_data);
+extern void bta_hf_client_sco_close(tBTA_HF_CLIENT_DATA *p_data);
+extern void bta_hf_client_cback_sco(UINT8 event);
+
+/* AT command functions */
+extern void bta_hf_client_at_parse(char *buf, unsigned int len);
+extern void bta_hf_client_send_at_brsf(void);
+extern void bta_hf_client_send_at_bac(void);
+extern void bta_hf_client_send_at_cind(BOOLEAN status);
+extern void bta_hf_client_send_at_cmer(BOOLEAN activate);
+extern void bta_hf_client_send_at_chld(char cmd, UINT32 idx);
+extern void bta_hf_client_send_at_clip(BOOLEAN activate);
+extern void bta_hf_client_send_at_ccwa(BOOLEAN activate);
+extern void bta_hf_client_send_at_cmee(BOOLEAN activate);
+extern void bta_hf_client_send_at_cops(BOOLEAN query);
+extern void bta_hf_client_send_at_clcc(void);
+extern void bta_hf_client_send_at_bvra(BOOLEAN enable);
+extern void bta_hf_client_send_at_vgs(UINT32 volume);
+extern void bta_hf_client_send_at_vgm(UINT32 volume);
+extern void bta_hf_client_send_at_atd(char *number, UINT32 memory);
+extern void bta_hf_client_send_at_bldn(void);
+extern void bta_hf_client_send_at_ata(void);
+extern void bta_hf_client_send_at_chup(void);
+extern void bta_hf_client_send_at_btrh(BOOLEAN query, UINT32 val);
+extern void bta_hf_client_send_at_vts(char code);
+extern void bta_hf_client_send_at_bcc(void);
+extern void bta_hf_client_send_at_bcs(UINT32 codec);
+extern void bta_hf_client_send_at_cnum(void);
+extern void bta_hf_client_send_at_nrec(void);
+extern void bta_hf_client_send_at_binp(UINT32 action);
+extern void bta_hf_client_send_at_bia(void);
+
+/* Action functions */
+extern void bta_hf_client_register(tBTA_HF_CLIENT_DATA *p_data);
+extern void bta_hf_client_deregister(tBTA_HF_CLIENT_DATA *p_data);
+extern void bta_hf_client_start_dereg(tBTA_HF_CLIENT_DATA *p_data);
+extern void bta_hf_client_start_close(tBTA_HF_CLIENT_DATA *p_data);
+extern void bta_hf_client_start_open(tBTA_HF_CLIENT_DATA *p_data);
+extern void bta_hf_client_rfc_acp_open(tBTA_HF_CLIENT_DATA *p_data);
+extern void bta_hf_client_rfc_open(tBTA_HF_CLIENT_DATA *p_data);
+extern void bta_hf_client_rfc_fail(tBTA_HF_CLIENT_DATA *p_data);
+extern void bta_hf_client_disc_fail(tBTA_HF_CLIENT_DATA *p_data);
+extern void bta_hf_client_open_fail(tBTA_HF_CLIENT_DATA *p_data);
+extern void bta_hf_client_rfc_close(tBTA_HF_CLIENT_DATA *p_data);
+extern void bta_hf_client_disc_acp_res(tBTA_HF_CLIENT_DATA *p_data);
+extern void bta_hf_client_rfc_data(tBTA_HF_CLIENT_DATA *p_data);
+extern void bta_hf_client_disc_int_res(tBTA_HF_CLIENT_DATA *p_data);
+extern void bta_hf_client_svc_conn_open(tBTA_HF_CLIENT_DATA *p_data);
+extern void bta_hf_client_ind(tBTA_HF_CLIENT_IND_TYPE type, UINT16 value);
+extern void bta_hf_client_evt_val(tBTA_HF_CLIENT_EVT type, UINT16 value);
+extern void bta_hf_client_operator_name(char *name);
+extern void bta_hf_client_clip(char *number);
+extern void bta_hf_client_ccwa(char *number);
+extern void bta_hf_client_at_result(tBTA_HF_CLIENT_AT_RESULT_TYPE type, UINT16 cme);
+extern void bta_hf_client_clcc(UINT32 idx, BOOLEAN incoming, UINT8 status, BOOLEAN mpty, char *number);
+extern void bta_hf_client_cnum(char *number, UINT16 service);
+extern void bta_hf_client_binp(char *number);
+
+/* Commands handling functions */
+extern void bta_hf_client_dial(tBTA_HF_CLIENT_DATA *p_data);
+extern void bta_hf_client_send_at_cmd(tBTA_HF_CLIENT_DATA *p_data);
+#if (BTM_SCO_HCI_INCLUDED == TRUE )
+extern void bta_hf_client_ci_sco_data(tBTA_HF_CLIENT_DATA *p_data);
+#endif /* (BTM_SCO_HCI_INCLUDED == TRUE ) */
+#endif /* #if (BTA_HF_INCLUDED == TRUE) */
index 90565aac8513cdae0b339f61b8df66f5f0fdf730..cd15c86c31f740cdb997ad5e6ff76529c96ba1d2 100644 (file)
@@ -61,18 +61,6 @@ extern void bta_dm_ci_io_req(BD_ADDR bd_addr, tBTA_IO_CAP io_cap,
 *******************************************************************************/
 extern void bta_dm_ci_rmt_oob(BOOLEAN accept, BD_ADDR bd_addr,
                               BT_OCTET16 c, BT_OCTET16 r);
-/*******************************************************************************
-**
-** Function         bta_dm_sco_ci_data_ready
-**
-** Description      This function sends an event to indicating that the phone
-**                  has SCO data ready..
-**
-** Returns          void
-**
-*******************************************************************************/
-extern void bta_dm_sco_ci_data_ready(UINT16 event, UINT16 sco_handle);
-
 #ifdef __cplusplus
 }
 #endif
index 7d62857191fe0064e6c1fcb18cd164d41984165e..1f1f648a9fe0bf496f420bc88caa89916e3ae41b 100644 (file)
 
 #include "bta/bta_sys.h"
 
-
-#ifndef BTA_SCO_OUT_PKT_SIZE
-#define BTA_SCO_OUT_PKT_SIZE    BTM_SCO_DATA_SIZE_MAX
-#endif
-
-#define BTA_SCO_CODEC_PCM       0       /* used for regular SCO */
-#define BTA_SCO_CODEC_SBC       1       /* used for WBS */
-typedef UINT8   tBTA_SCO_CODEC_TYPE;
-
-#define BTA_DM_SCO_SAMP_RATE_8K     8000
-#define BTA_DM_SCO_SAMP_RATE_16K    16000
-
-/* SCO codec information */
-typedef struct {
-    tBTA_SCO_CODEC_TYPE   codec_type;
-} tBTA_CODEC_INFO;
-
-#define BTA_DM_SCO_ROUTE_PCM    BTM_SCO_ROUTE_PCM
-#define BTA_DM_SCO_ROUTE_HCI    BTM_SCO_ROUTE_HCI
-
-typedef tBTM_SCO_ROUTE_TYPE tBTA_DM_SCO_ROUTE_TYPE;
-
-
 /*****************************************************************************
 **  Function Declarations
 *****************************************************************************/
@@ -135,72 +112,6 @@ extern void bta_dm_co_loc_oob(BOOLEAN valid, BT_OCTET16 c, BT_OCTET16 r);
 *******************************************************************************/
 extern void bta_dm_co_rmt_oob(BD_ADDR bd_addr);
 
-/*****************************************************************************
-**  SCO over HCI Function Declarations
-*****************************************************************************/
-/*******************************************************************************
-**
-** Function         bta_dm_sco_co_init
-**
-** Description      This function can be used by the phone to initialize audio
-**                  codec or for other initialization purposes before SCO connection
-**                  is opened.
-**
-**
-** Returns          Void.
-**
-*******************************************************************************/
-extern tBTA_DM_SCO_ROUTE_TYPE bta_dm_sco_co_init(UINT32 rx_bw, UINT32 tx_bw,
-        tBTA_CODEC_INFO *p_codec_info, UINT8 app_id);
-
-
-/*******************************************************************************
-**
-** Function         bta_dm_sco_co_open
-**
-** Description      This function is executed when a SCO connection is open.
-**
-**
-** Returns          void
-**
-*******************************************************************************/
-extern void bta_dm_sco_co_open(UINT16 handle, UINT8 pkt_size, UINT16 event);
-
-/*******************************************************************************
-**
-** Function         bta_dm_sco_co_close
-**
-** Description      This function is called when a SCO connection is closed
-**
-**
-** Returns          void
-**
-*******************************************************************************/
-extern void bta_dm_sco_co_close(void);
-
-/*******************************************************************************
-**
-** Function         bta_dm_sco_co_out_data
-**
-** Description      This function is called to send SCO data over HCI.
-**
-** Returns          void
-**
-*******************************************************************************/
-extern void bta_dm_sco_co_out_data(BT_HDR  **p_buf);
-
-/*******************************************************************************
-**
-** Function         bta_dm_sco_co_in_data
-**
-** Description      This function is called to send incoming SCO data to application.
-**
-** Returns          void
-**
-*******************************************************************************/
-extern void bta_dm_sco_co_in_data(BT_HDR  *p_buf, tBTM_SCO_DATA_FLAG status);
-
-
 
 /*******************************************************************************
 **
diff --git a/components/bt/bluedroid/bta/include/bta/bta_hf_client_api.h b/components/bt/bluedroid/bta/include/bta/bta_hf_client_api.h
new file mode 100644 (file)
index 0000000..ade9f63
--- /dev/null
@@ -0,0 +1,378 @@
+/******************************************************************************
+ *
+ *  Copyright (c) 2014 The Android Open Source Project
+ *  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 handsfree (HF role) subsystem
+ *
+ ******************************************************************************/
+#ifndef BTA_HF_CLIENT_API_H
+#define BTA_HF_CLIENT_API_H
+
+#include "bta_api.h"
+#include "bta_hfp_defs.h"
+
+#if (BTA_HF_INCLUDED == TRUE)
+/*****************************************************************************
+**  Constants and data types
+*****************************************************************************/
+
+/* HFP peer (AG) features*/
+#define BTA_HF_CLIENT_PEER_FEAT_3WAY   0x00000001  /* Three-way calling */
+#define BTA_HF_CLIENT_PEER_FEAT_ECNR   0x00000002  /* Echo cancellation and/or noise reduction */
+#define BTA_HF_CLIENT_PEER_FEAT_VREC   0x00000004  /* Voice recognition */
+#define BTA_HF_CLIENT_PEER_INBAND      0x00000008  /* In-band ring tone */
+#define BTA_HF_CLIENT_PEER_VTAG        0x00000010  /* Attach a phone number to a voice tag */
+#define BTA_HF_CLIENT_PEER_REJECT      0x00000020  /* Ability to reject incoming call */
+#define BTA_HF_CLIENT_PEER_ECS         0x00000040  /* Enhanced Call Status */
+#define BTA_HF_CLIENT_PEER_ECC         0x00000080  /* Enhanced Call Control */
+#define BTA_HF_CLIENT_PEER_EXTERR      0x00000100  /* Extended error codes */
+#define BTA_HF_CLIENT_PEER_CODEC       0x00000200  /* Codec Negotiation */
+
+typedef UINT16 tBTA_HF_CLIENT_PEER_FEAT;
+
+/* HFP HF features */
+#define BTA_HF_CLIENT_FEAT_ECNR        0x00000001  /* Echo cancellation and/or noise reduction */
+#define BTA_HF_CLIENT_FEAT_3WAY        0x00000002  /* Call waiting and three-way calling */
+#define BTA_HF_CLIENT_FEAT_CLI         0x00000004  /* Caller ID presentation capability */
+#define BTA_HF_CLIENT_FEAT_VREC        0x00000008  /* Voice recognition activation */
+#define BTA_HF_CLIENT_FEAT_VOL         0x00000010  /* Remote volume control */
+#define BTA_HF_CLIENT_FEAT_ECS         0x00000020  /* Enhanced Call Status */
+#define BTA_HF_CLIENT_FEAT_ECC         0x00000040  /* Enhanced Call Control */
+#define BTA_HF_CLIENT_FEAT_CODEC       0x00000080  /* Codec Negotiation */
+
+/* HFP HF extended call handling - masks not related to any spec */
+#define BTA_HF_CLIENT_CHLD_REL          0x00000001  /* 0  Release waiting call or held calls */
+#define BTA_HF_CLIENT_CHLD_REL_ACC      0x00000002  /* 1  Release active calls and accept other (waiting or held) cal */
+#define BTA_HF_CLIENT_CHLD_REL_X        0x00000004  /* 1x Release x call*/
+#define BTA_HF_CLIENT_CHLD_HOLD_ACC     0x00000008  /* 2  Active calls on hold and accept other call */
+#define BTA_HF_CLIENT_CHLD_PRIV_X       0x00000010  /* 2x Active multiparty call on hold except call x */
+#define BTA_HF_CLIENT_CHLD_MERGE        0x00000020  /* 3  Add held call to multiparty */
+#define BTA_HF_CLIENT_CHLD_MERGE_DETACH 0x00000040  /* 4  Add held call to multiparty */
+
+typedef UINT16 tBTA_HF_CLIENT_CHLD_FEAT;
+
+/* HFP AG errors ot OK sent to HF Unit */
+#define BTA_HF_CLIENT_AT_RESULT_OK            0
+#define BTA_HF_CLIENT_AT_RESULT_ERROR         1
+#define BTA_HF_CLIENT_AT_RESULT_NO_CARRIER    2
+#define BTA_HF_CLIENT_AT_RESULT_BUSY          3
+#define BTA_HF_CLIENT_AT_RESULT_NO_ANSWER     4
+#define BTA_HF_CLIENT_AT_RESULT_DELAY         5
+#define BTA_HF_CLIENT_AT_RESULT_BLACKLISTED   6
+#define BTA_HF_CLIENT_AT_RESULT_CME           7
+
+typedef UINT8 tBTA_HF_CLIENT_AT_RESULT_TYPE;
+
+/* HF Client callback events */
+#define BTA_HF_CLIENT_ENABLE_EVT            0  /* HF Client enabled */
+#define BTA_HF_CLIENT_REGISTER_EVT          1  /* HF Client registered */
+#define BTA_HF_CLIENT_OPEN_EVT              2  /* HF Client connection open */
+#define BTA_HF_CLIENT_CLOSE_EVT             3  /* HF Client connection closed */
+#define BTA_HF_CLIENT_CONN_EVT              4  /* Service level connection opened */
+#define BTA_HF_CLIENT_AUDIO_OPEN_EVT        5  /* Audio connection open */
+#define BTA_HF_CLIENT_AUDIO_MSBC_OPEN_EVT   6  /* Audio connection with mSBC codec open */
+#define BTA_HF_CLIENT_AUDIO_CLOSE_EVT       7  /* Audio connection closed */
+#define BTA_HF_CLIENT_SPK_EVT               8  /* Speaker volume changed */
+#define BTA_HF_CLIENT_MIC_EVT               9  /* Microphone volume changed */
+#define BTA_HF_CLIENT_IND_EVT               10 /* Indicator */
+#define BTA_HF_CLIENT_VOICE_REC_EVT         11 /* AG changed voice recognition setting */
+#define BTA_HF_CLIENT_OPERATOR_NAME_EVT     12 /* Operator name acquired */
+#define BTA_HF_CLIENT_CLIP_EVT              13 /* Calling line identification event */
+#define BTA_HF_CLIENT_CCWA_EVT              14 /* Call waiting notification */
+#define BTA_HF_CLIENT_AT_RESULT_EVT         15 /* Call waiting notification */
+#define BTA_HF_CLIENT_CLCC_EVT              16 /* current call event */
+#define BTA_HF_CLIENT_CNUM_EVT              17 /* subscriber information event */
+#define BTA_HF_CLIENT_BTRH_EVT              18 /* bluetooth response and hold event */
+#define BTA_HF_CLIENT_BSIR_EVT              19 /* in-band ring tone setting changed event */
+#define BTA_HF_CLIENT_BINP_EVT              20 /* binp number event */
+#define BTA_HF_CLIENT_RING_INDICATION       21 /* HF Client ring indication */
+#define BTA_HF_CLIENT_DISABLE_EVT           30 /* HF Client disabled */
+
+typedef UINT8 tBTA_HF_CLIENT_EVT;
+
+/* HF Client open status */
+#define BTA_HF_CLIENT_SUCCESS          0 /* Connection successfully opened */
+#define BTA_HF_CLIENT_FAIL_SDP         1 /* Open failed due to SDP */
+#define BTA_HF_CLIENT_FAIL_RFCOMM      2 /* Open failed due to RFCOMM */
+#define BTA_HF_CLIENT_FAIL_RESOURCES   3 /* out of resources failure  */
+
+typedef UINT8 tBTA_HF_CLIENT_STATUS;
+
+/* indicator type */
+#define BTA_HF_CLIENT_IND_BATTCH    0  /* Battery charge indicator */
+#define BTA_HF_CLIENT_IND_SIGNAL    1  /* Signal Strength indicator */
+#define BTA_HF_CLIENT_IND_SERVICE   2  /* Service availability indicator */
+#define BTA_HF_CLIENT_IND_CALL      3  /* Standard call status indicator*/
+#define BTA_HF_CLIENT_IND_ROAM      4  /* Roaming status indicator */
+#define BTA_HF_CLIENT_IND_CALLSETUP 5  /* Call setup status indicator */
+#define BTA_HF_CLIENT_IND_CALLHELD  6  /* Call hold status indicator */
+
+typedef UINT8 tBTA_HF_CLIENT_IND_TYPE;
+
+/* AT commands */
+#define BTA_HF_CLIENT_AT_CMD_VTS    0
+#define BTA_HF_CLIENT_AT_CMD_BTRH   1
+#define BTA_HF_CLIENT_AT_CMD_CHUP   2
+#define BTA_HF_CLIENT_AT_CMD_CHLD   3
+#define BTA_HF_CLIENT_AT_CMD_BCC    4
+#define BTA_HF_CLIENT_AT_CMD_CNUM   5
+#define BTA_HF_CLIENT_AT_CMD_ATA    6
+#define BTA_HF_CLIENT_AT_CMD_COPS   7
+#define BTA_HF_CLIENT_AT_CMD_ATD    8
+#define BTA_HF_CLIENT_AT_CMD_VGM    9
+#define BTA_HF_CLIENT_AT_CMD_VGS    10
+#define BTA_HF_CLIENT_AT_CMD_BVRA   11
+#define BTA_HF_CLIENT_AT_CMD_CLCC   12
+#define BTA_HF_CLIENT_AT_CMD_BINP   13
+#define BTA_HF_CLIENT_AT_CMD_BLDN   14
+#define BTA_HF_CLIENT_AT_CMD_NREC   15
+
+typedef UINT8 tBTA_HF_CLIENT_AT_CMD_TYPE;
+
+/* data associated with most non-AT events */
+/* placeholder, if not needed should be removed*/
+typedef struct {
+} tBTA_HF_CLIENT_HDR;
+
+/* data associated with BTA_HF_CLIENT_REGISTER_EVT */
+typedef struct {
+    tBTA_HF_CLIENT_HDR      hdr;
+    UINT16                  handle;
+    tBTA_HF_CLIENT_STATUS   status;
+} tBTA_HF_CLIENT_REGISTER;
+
+/* data associated with BTA_HF_CLIENT_OPEN_EVT */
+typedef struct {
+    tBTA_HF_CLIENT_HDR      hdr;
+    BD_ADDR                 bd_addr;
+    tBTA_HF_CLIENT_STATUS   status;
+} tBTA_HF_CLIENT_OPEN;
+
+/* data associated with BTA_HF_CLIENT_CONN_EVT */
+typedef struct {
+    tBTA_HF_CLIENT_HDR         hdr;
+    tBTA_HF_CLIENT_PEER_FEAT   peer_feat;
+    tBTA_HF_CLIENT_CHLD_FEAT   chld_feat;
+} tBTA_HF_CLIENT_CONN;
+
+/* data associated with BTA_HF_CLIENT_IND_EVT event */
+typedef struct {
+    tBTA_HF_CLIENT_HDR         hdr;
+    tBTA_HF_CLIENT_IND_TYPE    type;
+    UINT16                     value;
+} tBTA_HF_CLIENT_IND;
+
+/* data associated with BTA_HF_CLIENT_OPERATOR_NAME_EVT */
+#define BTA_HF_CLIENT_OPERATOR_NAME_LEN 16
+typedef struct {
+    char                       name[BTA_HF_CLIENT_OPERATOR_NAME_LEN + 1];
+} tBTA_HF_CLIENT_OPERATOR_NAME;
+
+/* data associated with BTA_HF_CLIENT_CLIP_EVT  and BTA_HF_CLIENT_CCWA_EVT*/
+#define BTA_HF_CLIENT_NUMBER_LEN 32
+typedef struct {
+    char                       number[BTA_HF_CLIENT_NUMBER_LEN + 1];
+} tBTA_HF_CLIENT_NUMBER;
+
+/* data associated with BTA_HF_CLIENT_AT_RESULT_EVT event */
+typedef struct {
+    tBTA_HF_CLIENT_AT_RESULT_TYPE    type;
+    UINT16                           cme;
+} tBTA_HF_CLIENT_AT_RESULT;
+
+/* data associated with BTA_HF_CLIENT_CLCC_EVT event */
+typedef struct {
+    UINT32                     idx;
+    BOOLEAN                    inc;
+    UINT8                      status;
+    BOOLEAN                    mpty;
+    BOOLEAN                    number_present;
+    char                       number[BTA_HF_CLIENT_NUMBER_LEN + 1];
+} tBTA_HF_CLIENT_CLCC;
+
+/* data associated with BTA_HF_CLIENT_CNUM_EVT event */
+typedef struct {
+    UINT16                     service;
+    char                       number[BTA_HF_CLIENT_NUMBER_LEN + 1];
+} tBTA_HF_CLIENT_CNUM;
+
+/* data associated with other events */
+typedef struct {
+    UINT16                     value;
+} tBTA_HF_CLIENT_VAL;
+
+/* union of data associated with AG callback */
+typedef union {
+    tBTA_HF_CLIENT_HDR              hdr;
+    tBTA_HF_CLIENT_REGISTER         reg;
+    tBTA_HF_CLIENT_OPEN             open;
+    tBTA_HF_CLIENT_CONN             conn;
+    tBTA_HF_CLIENT_IND              ind;
+    tBTA_HF_CLIENT_VAL              val;
+    tBTA_HF_CLIENT_OPERATOR_NAME    operator;
+    tBTA_HF_CLIENT_NUMBER           number;
+    tBTA_HF_CLIENT_AT_RESULT        result;
+    tBTA_HF_CLIENT_CLCC             clcc;
+    tBTA_HF_CLIENT_CNUM             cnum;
+} tBTA_HF_CLIENT;
+
+typedef UINT32 tBTA_HF_CLIENT_FEAT;
+
+/* HF Client callback */
+typedef void (tBTA_HF_CLIENT_CBACK)(tBTA_HF_CLIENT_EVT event, void *p_data);
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*****************************************************************************
+**  External Function Declarations
+*****************************************************************************/
+
+/*******************************************************************************
+**
+** Function         BTA_HfClientEnable
+**
+** Description      Enable the HF CLient service. When the enable
+**                  operation is complete the callback function will be
+**                  called with a BTA_HF_CLIENT_ENABLE_EVT. This function must
+**                  be called before other function in the HF CLient API are
+**                  called.
+**
+** Returns          BTA_SUCCESS if OK, BTA_FAILURE otherwise.
+**
+*******************************************************************************/
+tBTA_STATUS BTA_HfClientEnable(tBTA_HF_CLIENT_CBACK *p_cback);
+
+/*******************************************************************************
+**
+** Function         BTA_HfClientDisable
+**
+** Description      Disable the HF Client service
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void BTA_HfClientDisable(void);
+
+/*******************************************************************************
+**
+** Function         BTA_HfClientRegister
+**
+** Description      Register an HF Client service.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void BTA_HfClientRegister(tBTA_SEC sec_mask, tBTA_HF_CLIENT_FEAT features,
+                          char *p_service_name);
+
+/*******************************************************************************
+**
+** Function         BTA_HfClientDeregister
+**
+** Description      Deregister an HF Client service.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void BTA_HfClientDeregister(UINT16 handle);
+
+/*******************************************************************************
+**
+** Function         BTA_HfClientOpen
+**
+** Description      Opens a connection to an audio gateway.
+**                  When connection is open callback function is called
+**                  with a BTA_HF_CLIENT_OPEN_EVT. Only the data connection is
+**                  opened. The audio connection is not opened.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void BTA_HfClientOpen(UINT16 handle, BD_ADDR bd_addr, tBTA_SEC sec_mask);
+
+/*******************************************************************************
+**
+** Function         BTA_HfClientClose
+**
+** Description      Close the current connection to an audio gateway.
+**                  Any current audio connection will also be closed
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void BTA_HfClientClose(UINT16 handle);
+
+/*******************************************************************************
+**
+** Function         BTA_HfCllientAudioOpen
+**
+** Description      Opens an audio connection to the currently connected
+**                 audio gateway
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void BTA_HfClientAudioOpen(UINT16 handle);
+
+/*******************************************************************************
+**
+** Function         BTA_HfClientAudioClose
+**
+** Description      Close the currently active audio connection to an audio
+**                  gateway. The data connection remains open
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void BTA_HfClientAudioClose(UINT16 handle);
+
+/*******************************************************************************
+**
+** Function         BTA_HfClientSendAT
+**
+** Description      send AT command
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void BTA_HfClientSendAT(UINT16 handle, tBTA_HF_CLIENT_AT_CMD_TYPE at, UINT32 val1, UINT32 val2, const char *str);
+
+#if (BTM_SCO_HCI_INCLUDED == TRUE )
+void BTA_HfClientCiData(void);
+#endif /*#if (BTM_SCO_HCI_INCLUDED == TRUE ) */
+
+int BTA_HfClientGetCbDataSize(tBTA_HF_CLIENT_EVT event);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* #if (BTA_HF_INCLUDED == TRUE) */
+#endif /* BTA_HF_CLIENT_API_H */
diff --git a/components/bt/bluedroid/bta/include/bta/bta_hf_client_co.h b/components/bt/bluedroid/bta/include/bta/bta_hf_client_co.h
new file mode 100644 (file)
index 0000000..af53e6e
--- /dev/null
@@ -0,0 +1,115 @@
+// Copyright 2018 Espressif Systems (Shanghai) PTE LTD
+//
+// 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 interface file for hf client call-out functions.
+ *
+ ******************************************************************************/
+#ifndef BTA_HF_CLIENT_CO_H
+#define BTA_HF_CLIENT_CO_H
+
+#include "common/bt_target.h"
+#include "bta/bta_hf_client_api.h"
+
+#if (BTA_HF_INCLUDED == TRUE)
+
+#if (BTM_SCO_HCI_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function         bta_hf_client_co_audio_state
+**
+** Description      This function is called by the HF CLIENT before the audio connection
+**                  is brought up, after it comes up, and after it goes down.
+**
+** Parameters       handle - handle of the AG instance
+**                  state - Audio state
+**                  codec - if WBS support is compiled in, codec to going to be used is provided
+**                      and when in SCO_STATE_SETUP, BTM_I2SPCMConfig() must be called with
+**                      the correct platform parameters.
+**                      in the other states codec type should not be ignored
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hf_client_co_audio_state(UINT16 handle, UINT8 state, tBTA_HFP_PEER_CODEC codec);
+
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_sco_co_init
+**
+** Description      This function can be used by the phone to initialize audio
+**                  codec or for other initialization purposes before SCO connection
+**                  is opened.
+**
+**
+** Returns          Void.
+**
+*******************************************************************************/
+tBTA_HFP_SCO_ROUTE_TYPE bta_hf_client_sco_co_init(UINT32 rx_bw, UINT32 tx_bw,
+        tBTA_HFP_CODEC_INFO *p_codec_info, UINT8 app_id);
+
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_sco_co_open
+**
+** Description      This function is executed when a SCO connection is open.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hf_client_sco_co_open(UINT16 handle, UINT8 pkt_size, UINT16 event);
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_sco_co_close
+**
+** Description      This function is called when a SCO connection is closed
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hf_client_sco_co_close(void);
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_sco_co_out_data
+**
+** Description      This function is called to send SCO data over HCI.
+**
+** Returns          number of bytes got from application
+**
+*******************************************************************************/
+uint32_t bta_hf_client_sco_co_out_data(uint8_t *p_buf, uint32_t sz);
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_sco_co_in_data
+**
+** Description      This function is called to send incoming SCO data to application.
+**
+** Returns          void
+**
+*******************************************************************************/
+extern void bta_hf_client_sco_co_in_data(BT_HDR  *p_buf, tBTM_SCO_DATA_FLAG status);
+
+#endif /* #if (BTM_SCO_HCI_INCLUDED == TRUE) */
+
+#endif /* #if (BTA_HF_INCLUDED == TRUE) */
+#endif /* BTA_HF_CLIENT_CO_H */
diff --git a/components/bt/bluedroid/bta/include/bta/bta_hfp_defs.h b/components/bt/bluedroid/bta/include/bta/bta_hfp_defs.h
new file mode 100644 (file)
index 0000000..4644819
--- /dev/null
@@ -0,0 +1,47 @@
+// Copyright 2018 Espressif Systems (Shanghai) PTE LTD
+//
+// 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.
+
+#ifndef __BTA_HFP_DEFS_H__
+#define __BTA_HFP_DEFS_H__
+
+#include "stack/btm_api.h"
+
+#define BTA_HFP_CODEC_NONE           BTM_SCO_CODEC_NONE
+#define BTA_HFP_CODEC_CVSD           BTM_SCO_CODEC_CVSD      /* CVSD */
+#define BTA_HFP_CODEC_MSBC           BTM_SCO_CODEC_MSBC      /* mSBC */
+
+typedef UINT16 tBTA_HFP_PEER_CODEC;
+
+#ifndef BTA_HFP_SCO_OUT_PKT_SIZE
+#define BTA_HFP_SCO_OUT_PKT_SIZE    BTM_SCO_DATA_SIZE_MAX
+#endif
+
+#define BTA_HFP_SCO_CODEC_PCM       0       /* used for regular SCO */
+#define BTA_HFP_SCO_CODEC_SBC       1       /* used for WBS */
+typedef UINT8   tBTA_HFP_SCO_CODEC_TYPE;
+
+#define BTA_HFP_SCO_SAMP_RATE_8K     8000
+#define BTA_HFP_SCO_SAMP_RATE_16K    16000
+
+/* SCO codec information */
+typedef struct {
+    tBTA_HFP_SCO_CODEC_TYPE   codec_type;
+} tBTA_HFP_CODEC_INFO;
+
+#define BTA_HFP_SCO_ROUTE_PCM    BTM_SCO_ROUTE_PCM
+#define BTA_HFP_SCO_ROUTE_HCI    BTM_SCO_ROUTE_HCI
+
+typedef tBTM_SCO_ROUTE_TYPE tBTA_HFP_SCO_ROUTE_TYPE;
+
+#endif /* __BTA_HFP_DEFS_H__ */
index 1ed93a725e235b4abe1af82d03f727aac7682155..9f6c91105807fca0136c914aed9bd7287f6c2fe8 100644 (file)
@@ -57,6 +57,9 @@ static btc_dm_local_key_cb_t ble_local_key_cb;
 extern bt_status_t btc_av_execute_service(BOOLEAN b_enable);
 extern bt_status_t btc_av_sink_execute_service(BOOLEAN b_enable);
 #endif
+#if BTC_HF_CLIENT_INCLUDED
+extern bt_status_t btc_hf_client_execute_service(BOOLEAN b_enable);
+#endif
 /******************************************************************************
 **  Functions
 ******************************************************************************/
@@ -396,6 +399,11 @@ static bt_status_t btc_in_execute_service_request(tBTA_SERVICE_ID service_id,
         btc_av_sink_execute_service(b_enable);
         break;
 #endif
+#if BTC_HF_CLIENT_INCLUDED
+    case BTA_HFP_HS_SERVICE_ID:
+        btc_hf_client_execute_service(b_enable);
+        break;
+#endif /* #if BTC_HF_CLIENT_INCLUDED */
     default:
         BTC_TRACE_ERROR("%s: Unknown service being enabled\n", __FUNCTION__);
         return BT_STATUS_FAIL;
index 1d14d7ecf086e8141961ccc19c038826f72f4b49..b8afbb5814346f698bc5f4b30bbef5f805056ed8 100644 (file)
@@ -42,6 +42,9 @@
 #if CONFIG_BT_SPP_ENABLED
 #include "btc_spp.h"
 #endif /* #if CONFIG_BT_SPP_ENABLED */
+#if BTC_HF_CLIENT_INCLUDED
+#include "btc_hf_client.h"
+#endif  /* #if BTC_HF_CLIENT_INCLUDED */
 #endif /* #if CONFIG_CLASSIC_BT_ENABLED */
 
 
@@ -80,6 +83,9 @@ static btc_func_t profile_tab[BTC_PID_NUM] = {
 #if CONFIG_BT_SPP_ENABLED
     [BTC_PID_SPP]         = {btc_spp_call_handler,        btc_spp_cb_handler      },
 #endif /* #if CONFIG_BT_SPP_ENABLED */
+#if BTC_HF_CLIENT_INCLUDED
+    [BTC_PID_HF_CLIENT]   = {btc_hf_client_call_handler,  btc_hf_client_cb_handler},
+#endif  /* #if BTC_HF_CLIENT_INCLUDED */
 #endif /* #if CONFIG_CLASSIC_BT_ENABLED */
 };
 
index 401f8ee7bb73134030176539b27b672a6951aa18..f644e865a6b4658f467d34f74842830563c352d1 100644 (file)
@@ -54,6 +54,9 @@ typedef enum {
     BTC_PID_A2DP,
     BTC_PID_AVRC,
     BTC_PID_SPP,
+#if BTC_HF_CLIENT_INCLUDED
+    BTC_PID_HF_CLIENT,
+#endif /* BTC_HF_CLIENT_INCLUDED */
 #endif  /* CONFIG_CLASSIC_BT_ENABLED */
     BTC_PID_NUM,
 } btc_pid_t; //btc profile id
diff --git a/components/bt/bluedroid/btc/profile/std/hf_client/bta_hf_client_co.c b/components/bt/bluedroid/btc/profile/std/hf_client/bta_hf_client_co.c
new file mode 100644 (file)
index 0000000..27eda74
--- /dev/null
@@ -0,0 +1,137 @@
+// Copyright 2018 Espressif Systems (Shanghai) PTE LTD
+//
+// 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.
+
+#include "bta/bta_hf_client_co.h"
+#include "hci/hci_audio.h"
+#include "btc_hf_client.h"
+#if (BTA_HF_INCLUDED == TRUE)
+
+#if (BTM_SCO_HCI_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function         bta_hf_client_co_audio_state
+**
+** Description      This function is called by the HF CLIENT before the audio connection
+**                  is brought up, after it comes up, and after it goes down.
+**
+** Parameters       handle - handle of the AG instance
+**                  state - Audio state
+**                  codec - if WBS support is compiled in, codec to going to be used is provided
+**                      and when in SCO_STATE_SETUP, BTM_I2SPCMConfig() must be called with
+**                      the correct platform parameters.
+**                      in the other states codec type should not be ignored
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hf_client_co_audio_state(UINT16 handle, UINT8 state, tBTA_HFP_PEER_CODEC codec)
+{
+    switch (state)
+    {
+    case SCO_STATE_ON:
+    case SCO_STATE_OFF:
+    case SCO_STATE_OFF_TRANSFER:
+    case SCO_STATE_SETUP:
+    default:
+        break;
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_sco_co_init
+**
+** Description      This function can be used by the phone to initialize audio
+**                  codec or for other initialization purposes before SCO connection
+**                  is opened.
+**
+**
+** Returns          Void.
+**
+*******************************************************************************/
+tBTA_HFP_SCO_ROUTE_TYPE bta_hf_client_sco_co_init(UINT32 rx_bw, UINT32 tx_bw,
+        tBTA_HFP_CODEC_INFO *p_codec_info, UINT8 app_id)
+{
+    APPL_TRACE_EVENT("%s rx_bw %d, tx_bw %d, codec %d", __FUNCTION__, rx_bw, tx_bw,
+                     p_codec_info->codec_type);
+    return BTA_HFP_SCO_ROUTE_HCI;
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_sco_co_open
+**
+** Description      This function is executed when a SCO connection is open.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hf_client_sco_co_open(UINT16 handle, UINT8 pkt_size, UINT16 event)
+{
+    APPL_TRACE_EVENT("%s hdl %x, pkt_sz %u, event %u", __FUNCTION__, handle,
+                     pkt_size, event);
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_sco_co_close
+**
+** Description      This function is called when a SCO connection is closed
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hf_client_sco_co_close(void)
+{
+    APPL_TRACE_EVENT("%s", __FUNCTION__);
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_sco_co_out_data
+**
+** Description      This function is called to send SCO data over HCI.
+**
+** Returns          number of bytes got from application
+**
+*******************************************************************************/
+uint32_t bta_hf_client_sco_co_out_data(uint8_t *p_buf, uint32_t sz)
+{
+    return btc_hf_client_outgoing_data_cb_to_app(p_buf, sz);
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_sco_co_in_data
+**
+** Description      This function is called to send incoming SCO data to application.
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hf_client_sco_co_in_data(BT_HDR  *p_buf, tBTM_SCO_DATA_FLAG status)
+{
+    UINT8       *p = (UINT8 *)(p_buf + 1) + p_buf->offset;
+    UINT8       pkt_size = 0;
+
+    STREAM_SKIP_UINT16(p);
+    STREAM_TO_UINT8 (pkt_size, p);
+    btc_hf_client_incoming_data_cb_to_app(p, pkt_size);
+}
+
+#endif /* #if (BTM_SCO_HCI_INCLUDED == TRUE) */
+
+#endif /* #if (BTA_HF_INCLUDED == TRUE) */
diff --git a/components/bt/bluedroid/btc/profile/std/hf_client/btc_hf_client.c b/components/bt/bluedroid/btc/profile/std/hf_client/btc_hf_client.c
new file mode 100644 (file)
index 0000000..1d927fe
--- /dev/null
@@ -0,0 +1,1089 @@
+// Copyright 2018 Espressif Systems (Shanghai) PTE LTD
+//
+// 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.
+
+/******************************************************************************
+ **
+ **  Name:          btc_hf_client.c
+ **
+ ******************************************************************************/
+#include "common/bt_target.h"
+#include "common/bt_trace.h"
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdlib.h>
+#include "common/bt_defs.h"
+#include "device/bdaddr.h"
+#include "btc/btc_dm.h"
+#include "btc_hf_client.h"
+#include "btc/btc_profile_queue.h"
+#include "osi/allocator.h"
+#include "btc/btc_manage.h"
+#include "btc/btc_util.h"
+#include "esp_hf_client_api.h"
+#include "bta/bta_hf_client_api.h"
+#include "esp_bt.h"
+#include <assert.h>
+
+#if (BTC_HF_CLIENT_INCLUDED == TRUE)
+
+/************************************************************************************
+**  Constants & Macros
+************************************************************************************/
+
+#ifndef BTC_HF_CLIENT_SERVICE_NAME
+#define BTC_HF_CLIENT_SERVICE_NAME ("Handsfree")
+#endif
+
+#ifndef BTC_HF_CLIENT_SECURITY
+#define BTC_HF_CLIENT_SECURITY    (BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT)
+#endif
+
+#ifndef BTC_HF_CLIENT_FEATURES
+#define BTC_HF_CLIENT_FEATURES   ( BTA_HF_CLIENT_FEAT_ECNR  | \
+                                    BTA_HF_CLIENT_FEAT_3WAY  | \
+                                    BTA_HF_CLIENT_FEAT_CLI   | \
+                                    BTA_HF_CLIENT_FEAT_VREC  | \
+                                    BTA_HF_CLIENT_FEAT_VOL   | \
+                                    BTA_HF_CLIENT_FEAT_ECS   | \
+                                    BTA_HF_CLIENT_FEAT_ECC   | \
+                                    BTA_HF_CLIENT_FEAT_CODEC)
+#endif
+
+/************************************************************************************
+**  Local type definitions
+************************************************************************************/
+/* BTC-HF control block to map bdaddr to BTA handle */
+typedef struct
+{
+    bool                               initialized;
+    UINT16                             handle;
+    bt_bdaddr_t                        connected_bda;
+    esp_hf_client_connection_state_t   state;
+    esp_hf_vr_state_t                  vr_state;
+    tBTA_HF_CLIENT_PEER_FEAT           peer_feat;
+    tBTA_HF_CLIENT_CHLD_FEAT           chld_feat;
+} btc_hf_client_cb_t;
+
+/************************************************************************************
+**  Static variables
+************************************************************************************/
+const char *btc_hf_client_version = "1.6";
+static UINT32 btc_hf_client_features = 0;
+static btc_hf_client_cb_t btc_hf_client_cb;
+static esp_hf_client_incoming_data_cb_t btc_hf_client_incoming_data_cb = NULL;
+static esp_hf_client_outgoing_data_cb_t btc_hf_client_outgoing_data_cb = NULL;
+
+/************************************************************************************
+**  Static functions
+************************************************************************************/
+#define CHECK_HF_CLIENT_INIT() do { \
+if (! btc_hf_client_cb.initialized) { \
+    return BT_STATUS_NOT_READY; \
+} \
+} while (0)
+
+#define CHECK_HF_CLIENT_SLC_CONNECTED() do { \
+if (! btc_hf_client_cb.initialized || \
+    btc_hf_client_cb.state != ESP_HF_CLIENT_CONNECTION_STATE_SLC_CONNECTED) { \
+    return BT_STATUS_NOT_READY; \
+} \
+} while (0)
+
+static inline void btc_hf_client_cb_to_app(esp_hf_client_cb_event_t event, esp_hf_client_cb_param_t *param)
+{
+    esp_hf_client_cb_t btc_hf_client_callback = (esp_hf_client_cb_t)btc_profile_cb_get(BTC_PID_HF_CLIENT);
+    if (btc_hf_client_callback) {
+        btc_hf_client_callback(event, param);
+    }
+}
+
+static void clear_state(void)
+{
+    memset(&btc_hf_client_cb, 0, sizeof(btc_hf_client_cb_t));
+}
+
+static BOOLEAN is_connected(bt_bdaddr_t *bd_addr)
+{
+    if (((btc_hf_client_cb.state == ESP_HF_CLIENT_CONNECTION_STATE_CONNECTED) ||
+            (btc_hf_client_cb.state == ESP_HF_CLIENT_CONNECTION_STATE_SLC_CONNECTED))&&
+        ((bd_addr == NULL) || (bdcmp(bd_addr->address, btc_hf_client_cb.connected_bda.address) == 0)))
+        return TRUE;
+    return FALSE;
+}
+
+void btc_hf_client_reg_data_cb(esp_hf_client_incoming_data_cb_t recv,
+                               esp_hf_client_outgoing_data_cb_t send)
+{
+    btc_hf_client_incoming_data_cb = recv;
+    btc_hf_client_outgoing_data_cb = send;
+}
+
+void btc_hf_client_incoming_data_cb_to_app(const uint8_t *data, uint32_t len)
+{
+    // todo: critical section protection
+    if (btc_hf_client_incoming_data_cb) {
+        btc_hf_client_incoming_data_cb(data, len);
+    }
+}
+
+uint32_t btc_hf_client_outgoing_data_cb_to_app(uint8_t *data, uint32_t len)
+{
+    // todo: critical section protection
+    if (btc_hf_client_outgoing_data_cb) {
+        return btc_hf_client_outgoing_data_cb(data, len);
+    } else {
+        return 0;
+    }
+}
+
+/*****************************************************************************
+**
+**   btc hf api functions
+**
+*****************************************************************************/
+
+/*******************************************************************************
+**
+** Function        btc_hf_client_init
+**
+** Description     initializes the hf interface
+**
+** Returns         bt_status_t
+**
+*******************************************************************************/
+bt_status_t btc_hf_client_init(void)
+{
+    BTC_TRACE_EVENT("%s", __FUNCTION__);
+
+    uint8_t data_path;
+    btc_dm_enable_service(BTA_HFP_HS_SERVICE_ID);
+
+    clear_state();
+
+    btc_hf_client_cb.initialized = true;
+
+#if CONFIG_HFP_AUDIO_DATA_PATH_HCI
+    data_path = ESP_SCO_DATA_PATH_HCI;
+#else
+    data_path = ESP_SCO_DATA_PATH_PCM;
+#endif
+    esp_bredr_sco_datapath_set(data_path);
+    return BT_STATUS_SUCCESS;
+}
+
+
+/*******************************************************************************
+**
+** Function        btc_hf_client_connect
+**
+** Description     connect to audio gateway
+**
+** Returns         bt_status_t
+**
+*******************************************************************************/
+static bt_status_t connect_int( bt_bdaddr_t *bd_addr, uint16_t uuid )
+{
+    if (is_connected(bd_addr))
+        return BT_STATUS_BUSY;
+
+    btc_hf_client_cb.state = ESP_HF_CLIENT_CONNECTION_STATE_CONNECTING;
+    bdcpy(btc_hf_client_cb.connected_bda.address, bd_addr->address);
+
+    BTA_HfClientOpen(btc_hf_client_cb.handle, btc_hf_client_cb.connected_bda.address,
+               BTC_HF_CLIENT_SECURITY);
+
+    return BT_STATUS_SUCCESS;
+}
+
+
+bt_status_t btc_hf_client_connect( bt_bdaddr_t *bd_addr )
+{
+    BTC_TRACE_EVENT("HFP Client version is  %s", btc_hf_client_version);
+    CHECK_HF_CLIENT_INIT();
+    return btc_queue_connect(UUID_SERVCLASS_HF_HANDSFREE, bd_addr, connect_int);
+
+}
+
+/*******************************************************************************
+**
+** Function         btc_hf_client_deinit
+**
+** Description      Closes the HF interface
+**
+** Returns          bt_status_t
+**
+*******************************************************************************/
+void  btc_hf_client_deinit( void )
+{
+    BTC_TRACE_EVENT("%s", __FUNCTION__);
+
+    btc_dm_disable_service(BTA_HFP_HS_SERVICE_ID);
+
+    btc_hf_client_cb.initialized = false;
+}
+
+/*******************************************************************************
+**
+** Function         btc_hf_client_disconnect
+**
+** Description      disconnect from audio gateway
+**
+** Returns         bt_status_t
+**
+*******************************************************************************/
+bt_status_t btc_hf_client_disconnect( bt_bdaddr_t *bd_addr )
+{
+    CHECK_HF_CLIENT_INIT();
+
+    if (is_connected(bd_addr))
+    {
+        BTA_HfClientClose(btc_hf_client_cb.handle);
+        return BT_STATUS_SUCCESS;
+    }
+
+    return BT_STATUS_FAIL;
+}
+
+/*******************************************************************************
+**
+** Function        btc_hf_client_connect_audio
+**
+** Description     create an audio connection
+**
+** Returns         bt_status_t
+**
+*******************************************************************************/
+bt_status_t btc_hf_client_connect_audio( bt_bdaddr_t *bd_addr )
+{
+    CHECK_HF_CLIENT_SLC_CONNECTED();
+
+    if (is_connected(bd_addr))
+    {
+        if (btc_hf_client_cb.peer_feat & BTA_HF_CLIENT_PEER_CODEC)
+        {
+            BTA_HfClientSendAT(btc_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_BCC, 0, 0, NULL);
+        }
+        else
+        {
+            BTA_HfClientAudioOpen(btc_hf_client_cb.handle);
+        }
+
+        /* Inform the application that the audio connection has been initiated successfully */
+        do {
+            esp_hf_client_cb_param_t param;
+            memset(&param, 0, sizeof(esp_hf_client_cb_param_t));
+            param.audio_stat.state = ESP_HF_CLIENT_AUDIO_STATE_CONNECTING;
+            memcpy(param.audio_stat.remote_bda, &btc_hf_client_cb.connected_bda, sizeof(esp_bd_addr_t));
+            btc_hf_client_cb_to_app(ESP_HF_CLIENT_AUDIO_STATE_EVT, &param);
+        } while (0);
+
+        return BT_STATUS_SUCCESS;
+    }
+
+    return BT_STATUS_FAIL;
+}
+
+/*******************************************************************************
+**
+** Function         btc_hf_client_disconnect_audio
+**
+** Description      close the audio connection
+**
+** Returns         bt_status_t
+**
+*******************************************************************************/
+bt_status_t btc_hf_client_disconnect_audio( bt_bdaddr_t *bd_addr )
+{
+    CHECK_HF_CLIENT_SLC_CONNECTED();
+
+    if (is_connected(bd_addr))
+    {
+        BTA_HfClientAudioClose(btc_hf_client_cb.handle);
+        return BT_STATUS_SUCCESS;
+    }
+
+    return BT_STATUS_FAIL;
+}
+
+/*******************************************************************************
+**
+** Function         btc_hf_client_start_voice_recognition
+**
+** Description      start voice recognition
+**
+** Returns          bt_status_t
+**
+*******************************************************************************/
+static bt_status_t btc_hf_client_start_voice_recognition(void)
+{
+    CHECK_HF_CLIENT_SLC_CONNECTED();
+
+    if (btc_hf_client_cb.peer_feat & BTA_HF_CLIENT_PEER_FEAT_VREC)
+    {
+        BTA_HfClientSendAT(btc_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_BVRA, 1, 0, NULL);
+
+        return BT_STATUS_SUCCESS;
+    }
+
+    return BT_STATUS_UNSUPPORTED;
+}
+
+
+/*******************************************************************************
+**
+** Function         btc_hf_client_stop_voice_recognition
+**
+** Description      stop voice recognition
+**
+** Returns          bt_status_t
+**
+*******************************************************************************/
+static bt_status_t btc_hf_client_stop_voice_recognition(void)
+{
+    CHECK_HF_CLIENT_SLC_CONNECTED();
+
+    if (btc_hf_client_cb.peer_feat & BTA_HF_CLIENT_PEER_FEAT_VREC)
+    {
+        BTA_HfClientSendAT(btc_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_BVRA, 0, 0, NULL);
+
+        return BT_STATUS_SUCCESS;
+    }
+
+    return BT_STATUS_UNSUPPORTED;
+}
+
+/*******************************************************************************
+**
+** Function         btc_hf_client_volume_update
+**
+** Description      volume update
+**
+** Returns          bt_status_t
+**
+*******************************************************************************/
+static bt_status_t btc_hf_client_volume_update(esp_hf_volume_control_target_t type, int volume)
+{
+    CHECK_HF_CLIENT_SLC_CONNECTED();
+
+    switch (type)
+    {
+        case ESP_HF_VOLUME_CONTROL_TARGET_SPK:
+            BTA_HfClientSendAT(btc_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_VGS, volume, 0, NULL);
+            break;
+        case ESP_HF_VOLUME_CONTROL_TARGET_MIC:
+            BTA_HfClientSendAT(btc_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_VGM, volume, 0, NULL);
+            break;
+        default:
+            return BT_STATUS_UNSUPPORTED;
+    }
+
+    return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function         btc_hf_client_dial
+**
+** Description      place a call
+**
+** Returns          bt_status_t
+**
+*******************************************************************************/
+static bt_status_t btc_hf_client_dial(const char *number)
+{
+    CHECK_HF_CLIENT_SLC_CONNECTED();
+
+    if (strlen(number) != 0)
+    {
+        BTA_HfClientSendAT(btc_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_ATD, 0, 0, number);
+    }
+    else
+    {
+        BTA_HfClientSendAT(btc_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_BLDN, 0, 0, NULL);
+    }
+
+    return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function         dial_memory
+**
+** Description      place a call with number specified by location (speed dial)
+**
+** Returns          bt_status_t
+**
+*******************************************************************************/
+static bt_status_t btc_hf_client_dial_memory(int location)
+{
+    CHECK_HF_CLIENT_SLC_CONNECTED();
+
+    BTA_HfClientSendAT(btc_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_ATD, location, 0, NULL);
+
+    return BT_STATUS_SUCCESS;
+}
+
+static bt_status_t btc_hf_client_send_chld_cmd(esp_hf_chld_type_t type, int idx)
+{
+    CHECK_HF_CLIENT_SLC_CONNECTED();
+
+    switch (type)
+    {
+    case ESP_HF_CHLD_TYPE_REL:
+        if (btc_hf_client_cb.chld_feat & BTA_HF_CLIENT_CHLD_REL)
+        {
+            BTA_HfClientSendAT(btc_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_CHLD, 0, 0, NULL);
+            break;
+        }
+        return BT_STATUS_UNSUPPORTED;
+    case ESP_HF_CHLD_TYPE_REL_ACC:
+        // CHLD 1 is mandatory for 3 way calling
+        if (btc_hf_client_cb.peer_feat & BTA_HF_CLIENT_PEER_FEAT_3WAY)
+        {
+            BTA_HfClientSendAT(btc_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_CHLD, 1, 0, NULL);
+            break;
+        }
+        return BT_STATUS_UNSUPPORTED;
+    case ESP_HF_CHLD_TYPE_HOLD_ACC:
+        // CHLD 2 is mandatory for 3 way calling
+        if (btc_hf_client_cb.peer_feat & BTA_HF_CLIENT_PEER_FEAT_3WAY)
+        {
+            BTA_HfClientSendAT(btc_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_CHLD, 2, 0, NULL);
+            break;
+        }
+        return BT_STATUS_UNSUPPORTED;
+    case ESP_HF_CHLD_TYPE_MERGE:
+        if (btc_hf_client_cb.chld_feat & BTA_HF_CLIENT_CHLD_MERGE)
+        {
+            BTA_HfClientSendAT(btc_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_CHLD, 3, 0, NULL);
+            break;
+        }
+        return BT_STATUS_UNSUPPORTED;
+    case ESP_HF_CHLD_TYPE_MERGE_DETACH:
+        if (btc_hf_client_cb.chld_feat & BTA_HF_CLIENT_CHLD_MERGE_DETACH)
+        {
+            BTA_HfClientSendAT(btc_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_CHLD, 4, 0, NULL);
+            break;
+        }
+        return BT_STATUS_UNSUPPORTED;
+    case ESP_HF_CHLD_TYPE_REL_X:
+        if (btc_hf_client_cb.peer_feat & BTA_HF_CLIENT_PEER_ECC)
+        {
+            if (idx < 1)
+            {
+                return BT_STATUS_FAIL;
+            }
+            BTA_HfClientSendAT(btc_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_CHLD, 1, idx, NULL);
+            break;
+        }
+        return BT_STATUS_UNSUPPORTED;
+    case ESP_HF_CHLD_TYPE_PRIV_X:
+        if (btc_hf_client_cb.peer_feat & BTA_HF_CLIENT_PEER_ECC)
+        {
+            if (idx < 1)
+            {
+                return BT_STATUS_FAIL;
+            }
+            BTA_HfClientSendAT(btc_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_CHLD, 2, idx, NULL);
+            break;
+        }
+        return BT_STATUS_UNSUPPORTED;
+
+    }
+    return BT_STATUS_SUCCESS;
+}
+
+static bt_status_t btc_hf_client_send_btrh_cmd(esp_hf_btrh_cmd_t btrh)
+{
+    CHECK_HF_CLIENT_SLC_CONNECTED();
+
+    switch (btrh) {
+    case ESP_HF_BTRH_CMD_HOLD:
+        BTA_HfClientSendAT(btc_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_BTRH, 0, 0, NULL);
+        break;
+    case ESP_HF_BTRH_CMD_ACCEPT:
+        BTA_HfClientSendAT(btc_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_BTRH, 1, 0, NULL);
+        break;
+    case ESP_HF_BTRH_CMD_REJECT:
+        BTA_HfClientSendAT(btc_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_BTRH, 2, 0, NULL);
+        break;
+    default:
+        return BT_STATUS_FAIL;
+    }
+
+    return BT_STATUS_SUCCESS;
+}
+
+static bt_status_t btc_hf_client_answer_call(void)
+{
+    CHECK_HF_CLIENT_SLC_CONNECTED();
+    BTA_HfClientSendAT(btc_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_ATA, 0, 0, NULL);
+    return BT_STATUS_SUCCESS;
+}
+
+static bt_status_t btc_hf_client_reject_call(void)
+{
+    CHECK_HF_CLIENT_SLC_CONNECTED();
+    BTA_HfClientSendAT(btc_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_CHUP, 0, 0, NULL);
+    return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function         btc_hf_client_query_current_calls
+**
+** Description      query list of current calls
+**
+** Returns          bt_status_t
+**
+*******************************************************************************/
+static bt_status_t btc_hf_client_query_current_calls(void)
+{
+    CHECK_HF_CLIENT_SLC_CONNECTED();
+
+    if (btc_hf_client_cb.peer_feat & BTA_HF_CLIENT_PEER_ECS)
+    {
+        BTA_HfClientSendAT(btc_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_CLCC, 0, 0, NULL);
+
+        return BT_STATUS_SUCCESS;
+    }
+
+    return BT_STATUS_UNSUPPORTED;
+}
+
+/*******************************************************************************
+**
+** Function         btc_hf_client_query_current_operator_name
+**
+** Description      query current selected operator name
+**
+** Returns          bt_status_t
+**
+*******************************************************************************/
+static bt_status_t btc_hf_client_query_current_operator_name(void)
+{
+    CHECK_HF_CLIENT_SLC_CONNECTED();
+
+    BTA_HfClientSendAT(btc_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_COPS, 0, 0, NULL);
+
+    return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function         btc_hf_client_retieve_subscriber_info
+**
+** Description      retrieve subscriber number information
+**
+** Returns          bt_status_t
+**
+*******************************************************************************/
+static bt_status_t btc_hf_client_retrieve_subscriber_info(void)
+{
+    CHECK_HF_CLIENT_SLC_CONNECTED();
+
+    BTA_HfClientSendAT(btc_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_CNUM, 0, 0, NULL);
+
+    return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function         btc_hf_client_send_dtmf
+**
+** Description      send dtmf
+**
+** Returns          bt_status_t
+**
+*******************************************************************************/
+static bt_status_t btc_hf_client_send_dtmf(char code)
+{
+    CHECK_HF_CLIENT_SLC_CONNECTED();
+
+    BTA_HfClientSendAT(btc_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_VTS, code, 0, NULL);
+
+    return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function         btc_hf_client_request_last_voice_tag_number
+**
+** Description      Request number from AG for VR purposes
+**
+** Returns          bt_status_t
+**
+*******************************************************************************/
+static bt_status_t btc_hf_client_request_last_voice_tag_number(void)
+{
+    CHECK_HF_CLIENT_SLC_CONNECTED();
+
+    if (btc_hf_client_cb.peer_feat & BTA_HF_CLIENT_PEER_VTAG)
+    {
+        BTA_HfClientSendAT(btc_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_BINP, 1, 0, NULL);
+
+        return BT_STATUS_SUCCESS;
+    }
+
+    return BT_STATUS_UNSUPPORTED;
+}
+
+/*******************************************************************************
+**
+** Function         bte_hf_client_evt
+**
+** Description      Switches context from BTE to BTIF for all HF Client events
+**
+** Returns          void
+**
+*******************************************************************************/
+static void bte_hf_client_evt(tBTA_HF_CLIENT_EVT event, void *p_data)
+{
+    bt_status_t stat;
+    btc_msg_t msg;
+    int arg_len = BTA_HfClientGetCbDataSize(event);
+    void *arg = (p_data != NULL && arg_len > 0) ? p_data : NULL;
+
+    msg.sig = BTC_SIG_API_CB;
+    msg.pid = BTC_PID_HF_CLIENT;
+    msg.act = (uint8_t) event;
+
+    stat = btc_transfer_context(&msg, arg, arg_len, NULL);
+
+    if (stat) {
+        BTC_TRACE_ERROR("%s transfer failed\n", __func__);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         btc_hf_client_execute_service
+**
+** Description      Initializes/Shuts down the service
+**
+** Returns          BT_STATUS_SUCCESS on success, BT_STATUS_FAIL otherwise
+**
+*******************************************************************************/
+bt_status_t btc_hf_client_execute_service(BOOLEAN b_enable)
+{
+    BTC_TRACE_EVENT("%s enable:%d", __FUNCTION__, b_enable);
+
+     if (b_enable)
+     {
+          /* Enable and register with BTA-HFClient */
+          BTA_HfClientEnable(bte_hf_client_evt);
+          if (strcmp(btc_hf_client_version, "1.6") == 0)
+          {
+              BTC_TRACE_EVENT("Support Codec Nego. %d ", BTC_HF_CLIENT_FEATURES);
+              BTA_HfClientRegister(BTC_HF_CLIENT_SECURITY, BTC_HF_CLIENT_FEATURES,
+                      BTC_HF_CLIENT_SERVICE_NAME);
+          }
+          else
+          {
+              BTC_TRACE_EVENT("No Codec Nego Supported");
+              btc_hf_client_features = BTC_HF_CLIENT_FEATURES;
+              btc_hf_client_features = btc_hf_client_features & (~BTA_HF_CLIENT_FEAT_CODEC);
+              BTC_TRACE_EVENT("btc_hf_client_features is   %d", btc_hf_client_features);
+              BTA_HfClientRegister(BTC_HF_CLIENT_SECURITY, btc_hf_client_features,
+                      BTC_HF_CLIENT_SERVICE_NAME);
+          }
+
+     }
+     else
+     {
+         BTA_HfClientDeregister(btc_hf_client_cb.handle);
+         BTA_HfClientDisable();
+     }
+     return BT_STATUS_SUCCESS;
+}
+
+static void process_ind_evt(tBTA_HF_CLIENT_IND *ind)
+{
+    esp_hf_client_cb_param_t param;
+    memset(&param, 0, sizeof(esp_hf_client_cb_param_t));
+    
+    switch (ind->type)
+    {
+        case BTA_HF_CLIENT_IND_CALL:
+            param.call.status = ind->value;
+            btc_hf_client_cb_to_app(ESP_HF_CLIENT_CIND_CALL_EVT, &param);
+            break;
+    
+        case BTA_HF_CLIENT_IND_CALLSETUP:
+            param.call_setup.status = ind->value;
+            btc_hf_client_cb_to_app(ESP_HF_CLIENT_CIND_CALL_SETUP_EVT, &param);
+            break;
+        case BTA_HF_CLIENT_IND_CALLHELD:
+            param.call_held.status = ind->value;
+            btc_hf_client_cb_to_app(ESP_HF_CLIENT_CIND_CALL_HELD_EVT, &param);
+            break;
+
+        case BTA_HF_CLIENT_IND_SERVICE:
+            param.service_availability.status = ind->value;
+            btc_hf_client_cb_to_app(ESP_HF_CLIENT_CIND_SERVICE_AVAILABILITY_EVT, &param);
+            break;
+
+        case BTA_HF_CLIENT_IND_SIGNAL:
+            param.signal_strength.value = ind->value;
+            btc_hf_client_cb_to_app(ESP_HF_CLIENT_CIND_SIGNAL_STRENGTH_EVT, &param);
+            break;
+
+        case BTA_HF_CLIENT_IND_ROAM:
+            param.roaming.status = ind->value;
+            btc_hf_client_cb_to_app(ESP_HF_CLIENT_CIND_ROAMING_STATUS_EVT, &param);
+            break;
+
+        case BTA_HF_CLIENT_IND_BATTCH:
+            param.battery_level.value = ind->value;
+            btc_hf_client_cb_to_app(ESP_HF_CLIENT_CIND_BATTERY_LEVEL_EVT, &param);
+            break;
+
+        default:
+            break;
+    }
+}
+
+void btc_hf_client_cb_handler(btc_msg_t *msg)
+{
+    uint16_t event = msg->act;
+    tBTA_HF_CLIENT *p_data = (tBTA_HF_CLIENT *)msg->arg;
+    esp_hf_client_cb_param_t param;
+    bdstr_t bdstr;
+
+    switch (event)
+    {
+        case BTA_HF_CLIENT_ENABLE_EVT:
+        case BTA_HF_CLIENT_DISABLE_EVT:
+            break;
+        case BTA_HF_CLIENT_REGISTER_EVT:
+            btc_hf_client_cb.handle = p_data->reg.handle;
+            break;
+        case BTA_HF_CLIENT_OPEN_EVT:
+            if (p_data->open.status == BTA_HF_CLIENT_SUCCESS)
+            {
+                bdcpy(btc_hf_client_cb.connected_bda.address, p_data->open.bd_addr);
+                btc_hf_client_cb.state = ESP_HF_CLIENT_CONNECTION_STATE_CONNECTED;
+                btc_hf_client_cb.peer_feat = 0;
+                btc_hf_client_cb.chld_feat = 0;
+                //clear_phone_state();
+            }
+            else if (btc_hf_client_cb.state == ESP_HF_CLIENT_CONNECTION_STATE_CONNECTING)
+            {
+                btc_hf_client_cb.state = ESP_HF_CLIENT_CONNECTION_STATE_DISCONNECTED;
+            }
+            else
+            {
+                BTC_TRACE_WARNING("%s: HF CLient open failed, but another device connected. status=%d state=%d connected device=%s",
+                        __FUNCTION__, p_data->open.status, btc_hf_client_cb.state, bdaddr_to_string(&btc_hf_client_cb.connected_bda, bdstr, sizeof(bdstr)));
+                break;
+            }
+
+            do {
+                memset(&param, 0, sizeof(esp_hf_client_cb_param_t));
+                param.conn_stat.state = btc_hf_client_cb.state;
+                param.conn_stat.peer_feat = 0;
+                param.conn_stat.chld_feat = 0;
+            
+                memcpy(param.conn_stat.remote_bda, &btc_hf_client_cb.connected_bda,
+                       sizeof(esp_bd_addr_t));
+
+                btc_hf_client_cb_to_app(ESP_HF_CLIENT_CONNECTION_STATE_EVT, &param);
+            } while (0);
+            
+            if (btc_hf_client_cb.state == ESP_HF_CLIENT_CONNECTION_STATE_DISCONNECTED)
+                bdsetany(btc_hf_client_cb.connected_bda.address);
+
+            if (p_data->open.status != BTA_HF_CLIENT_SUCCESS)
+                btc_queue_advance();
+
+            break;
+
+        case BTA_HF_CLIENT_CONN_EVT:
+            btc_hf_client_cb.peer_feat = p_data->conn.peer_feat;
+            btc_hf_client_cb.chld_feat = p_data->conn.chld_feat;
+            btc_hf_client_cb.state = ESP_HF_CLIENT_CONNECTION_STATE_SLC_CONNECTED;
+
+            do {
+                memset(&param, 0, sizeof(esp_hf_client_cb_param_t));
+                param.conn_stat.state = btc_hf_client_cb.state;
+                param.conn_stat.peer_feat = btc_hf_client_cb.peer_feat;
+                param.conn_stat.chld_feat = btc_hf_client_cb.chld_feat;
+            
+                memcpy(param.conn_stat.remote_bda, &btc_hf_client_cb.connected_bda,
+                       sizeof(esp_bd_addr_t));
+
+                btc_hf_client_cb_to_app(ESP_HF_CLIENT_CONNECTION_STATE_EVT, &param);
+            } while (0);
+            
+            /* Inform the application about in-band ringtone */
+            if (btc_hf_client_cb.peer_feat & BTA_HF_CLIENT_PEER_INBAND)
+            {
+                do {
+                    memset(&param, 0, sizeof(esp_hf_client_cb_param_t));
+                    param.bsir.state =  ESP_HF_CLIENT_IN_BAND_RINGTONE_PROVIDED;
+                    btc_hf_client_cb_to_app(ESP_HF_CLIENT_BSIR_EVT, &param);
+                } while (0);
+            }
+
+            btc_queue_advance();
+            break;
+            
+        case BTA_HF_CLIENT_CLOSE_EVT:
+            btc_hf_client_cb.state = ESP_HF_CLIENT_CONNECTION_STATE_DISCONNECTED;
+            do {
+                memset(&param, 0, sizeof(esp_hf_client_cb_param_t));
+                param.conn_stat.state = ESP_HF_CLIENT_CONNECTION_STATE_DISCONNECTED;
+                param.conn_stat.peer_feat = 0;
+                param.conn_stat.chld_feat = 0;
+            
+                memcpy(param.conn_stat.remote_bda, &btc_hf_client_cb.connected_bda,
+                       sizeof(esp_bd_addr_t));
+
+                btc_hf_client_cb_to_app(ESP_HF_CLIENT_CONNECTION_STATE_EVT, &param);
+            } while (0);
+
+            bdsetany(btc_hf_client_cb.connected_bda.address);
+            btc_hf_client_cb.peer_feat = 0;
+            btc_hf_client_cb.chld_feat = 0;
+            btc_queue_advance();
+            break;
+        case BTA_HF_CLIENT_IND_EVT:
+            process_ind_evt(&p_data->ind);
+            break;
+        case BTA_HF_CLIENT_MIC_EVT:
+            do {
+                memset(&param, 0, sizeof(esp_hf_client_cb_param_t));
+                param.volume_control.type = ESP_HF_VOLUME_CONTROL_TARGET_MIC;
+                param.volume_control.volume = p_data->val.value;
+
+                btc_hf_client_cb_to_app(ESP_HF_CLIENT_VOLUME_CONTROL_EVT, &param);
+            } while (0);
+            break;
+        case BTA_HF_CLIENT_SPK_EVT:
+            do {
+                memset(&param, 0, sizeof(esp_hf_client_cb_param_t));
+                param.volume_control.type = ESP_HF_VOLUME_CONTROL_TARGET_SPK;
+                param.volume_control.volume = p_data->val.value;
+
+                btc_hf_client_cb_to_app(ESP_HF_CLIENT_VOLUME_CONTROL_EVT, &param);
+            } while (0);
+            break;
+        case BTA_HF_CLIENT_VOICE_REC_EVT:
+            do {
+                memset(&param, 0, sizeof(esp_hf_client_cb_param_t));
+                param.bvra.value = p_data->val.value;
+
+                btc_hf_client_cb_to_app(ESP_HF_CLIENT_BVRA_EVT, &param);
+            } while (0);
+            break;
+        case BTA_HF_CLIENT_OPERATOR_NAME_EVT:
+            do {
+                memset(&param, 0, sizeof(esp_hf_client_cb_param_t));
+                param.cops.name = p_data->operator.name;
+                btc_hf_client_cb_to_app(ESP_HF_CLIENT_COPS_CURRENT_OPERATOR_EVT, &param);
+            } while (0);
+            break;
+        case BTA_HF_CLIENT_CLIP_EVT:
+            do {
+                memset(&param, 0, sizeof(esp_hf_client_cb_param_t));
+                param.clip.number = p_data->number.number;
+                btc_hf_client_cb_to_app(ESP_HF_CLIENT_CLIP_EVT, &param);
+            } while (0);
+            break;
+        case BTA_HF_CLIENT_BINP_EVT:
+            do {
+                memset(&param, 0, sizeof(esp_hf_client_cb_param_t));
+                param.binp.number = p_data->number.number;
+                btc_hf_client_cb_to_app(ESP_HF_CLIENT_BINP_EVT, &param);
+            } while (0);
+            break;
+        case BTA_HF_CLIENT_CCWA_EVT:
+            do {
+                memset(&param, 0, sizeof(esp_hf_client_cb_param_t));
+                param.ccwa.number = p_data->number.number;
+                btc_hf_client_cb_to_app(ESP_HF_CLIENT_CCWA_EVT, &param);
+            } while (0);
+            break;
+        case BTA_HF_CLIENT_AT_RESULT_EVT:
+            do {
+                memset(&param, 0, sizeof(esp_hf_client_cb_param_t));
+                param.at_response.code = p_data->result.type;
+                param.at_response.cme = p_data->result.cme;
+
+                btc_hf_client_cb_to_app(ESP_HF_CLIENT_AT_RESPONSE_EVT, &param);
+            } while (0);
+            break;
+        case BTA_HF_CLIENT_CLCC_EVT:
+            do {
+                memset(&param, 0, sizeof(esp_hf_client_cb_param_t));
+                param.clcc.idx = p_data->clcc.idx;
+                param.clcc.dir = p_data->clcc.inc ? ESP_HF_CURRENT_CALL_DIRECTION_INCOMING :
+                    ESP_HF_CURRENT_CALL_DIRECTION_OUTGOING;
+                param.clcc.status = p_data->clcc.status;
+                param.clcc.mpty = p_data->clcc.mpty ? ESP_HF_CURRENT_CALL_MPTY_TYPE_MULTI :
+                    ESP_HF_CURRENT_CALL_MPTY_TYPE_SINGLE;
+                param.clcc.number = p_data->clcc.number_present ? p_data->clcc.number : NULL;
+                btc_hf_client_cb_to_app(ESP_HF_CLIENT_CLCC_EVT, &param);
+            } while (0);
+            break;
+        case BTA_HF_CLIENT_CNUM_EVT:
+            do {
+                memset(&param, 0, sizeof(esp_hf_client_cb_param_t));
+                param.cnum.number = p_data->cnum.number;
+                if (p_data->cnum.service == 4) {
+                    param.cnum.type = ESP_HF_SUBSCRIBER_SERVICE_TYPE_VOICE;
+                } else if (p_data->cnum.service == 5) {
+                    param.cnum.type = ESP_HF_SUBSCRIBER_SERVICE_TYPE_FAX;
+                } else {
+                    param.cnum.type = ESP_HF_SUBSCRIBER_SERVICE_TYPE_UNKNOWN;
+                }
+                btc_hf_client_cb_to_app(ESP_HF_CLIENT_CNUM_EVT, &param);
+                break;
+            } while (0);
+            break;
+        case BTA_HF_CLIENT_BTRH_EVT:
+            if (p_data->val.value <= ESP_HF_BTRH_STATUS_REJECTED) {
+                do {
+                    memset(&param, 0, sizeof(esp_hf_client_cb_param_t));
+                    param.btrh.status = p_data->val.value;
+
+                    btc_hf_client_cb_to_app(ESP_HF_CLIENT_BTRH_EVT, &param);
+                } while (0);
+            }
+            break;
+        case BTA_HF_CLIENT_BSIR_EVT:
+            memset(&param, 0, sizeof(esp_hf_client_cb_param_t));
+            if (p_data->val.value != 0)
+            {
+                param.bsir.state = ESP_HF_CLIENT_IN_BAND_RINGTONE_PROVIDED;
+            }
+            else
+            {
+                param.bsir.state = ESP_HF_CLIENT_IN_BAND_RINGTONE_NOT_PROVIDED;
+            }
+            btc_hf_client_cb_to_app(ESP_HF_CLIENT_BSIR_EVT, &param);
+            break;
+        case BTA_HF_CLIENT_AUDIO_OPEN_EVT:
+            do {
+                memset(&param, 0, sizeof(esp_hf_client_cb_param_t));
+                param.audio_stat.state = ESP_HF_CLIENT_AUDIO_STATE_CONNECTED;
+                memcpy(param.audio_stat.remote_bda, &btc_hf_client_cb.connected_bda,
+                       sizeof(esp_bd_addr_t));                
+                btc_hf_client_cb_to_app(ESP_HF_CLIENT_AUDIO_STATE_EVT, &param);
+            } while (0);
+            break;
+        case BTA_HF_CLIENT_AUDIO_MSBC_OPEN_EVT:
+            do {
+                memset(&param, 0, sizeof(esp_hf_client_cb_param_t));
+                param.audio_stat.state = ESP_HF_CLIENT_AUDIO_STATE_CONNECTED_MSBC;
+                memcpy(param.audio_stat.remote_bda, &btc_hf_client_cb.connected_bda,
+                       sizeof(esp_bd_addr_t));                
+                btc_hf_client_cb_to_app(ESP_HF_CLIENT_AUDIO_STATE_EVT, &param);
+            } while (0);
+            break;
+        case BTA_HF_CLIENT_AUDIO_CLOSE_EVT:
+            do {
+                memset(&param, 0, sizeof(esp_hf_client_cb_param_t));
+                param.audio_stat.state = ESP_HF_CLIENT_AUDIO_STATE_DISCONNECTED;
+                memcpy(param.audio_stat.remote_bda, &btc_hf_client_cb.connected_bda,
+                       sizeof(esp_bd_addr_t));
+                btc_hf_client_cb_to_app(ESP_HF_CLIENT_AUDIO_STATE_EVT, &param);
+            } while (0);
+            break;
+        case BTA_HF_CLIENT_RING_INDICATION:
+            do {
+                btc_hf_client_cb_to_app(ESP_HF_CLIENT_RING_IND_EVT, NULL);
+            } while (0);
+            break;
+        default:
+            BTC_TRACE_WARNING("%s: Unhandled event: %d", __FUNCTION__, event);
+            break;
+    }
+}
+
+void btc_hf_client_call_handler(btc_msg_t *msg)
+{
+    btc_hf_client_args_t *arg = (btc_hf_client_args_t *)(msg->arg);
+    switch (msg->act) {
+
+    case BTC_HF_CLIENT_INIT_EVT:
+        btc_hf_client_init();
+        break;
+    case BTC_HF_CLIENT_DEINIT_EVT:
+        btc_hf_client_deinit();
+        break;
+    case BTC_HF_CLIENT_CONNECT_EVT:
+        btc_hf_client_connect(&arg->connect);
+        break;
+    case BTC_HF_CLIENT_DISCONNECT_EVT:
+        btc_hf_client_disconnect(&arg->disconnect);
+        break;
+    case BTC_HF_CLIENT_CONNECT_AUDIO_EVT:
+        btc_hf_client_connect_audio(&arg->connect_audio);
+        break;
+    case BTC_HF_CLIENT_DISCONNECT_AUDIO_EVT:
+        btc_hf_client_disconnect_audio(&arg->disconnect_audio);
+        break;
+    case BTC_HF_CLIENT_START_VOICE_RECOGNITION_EVT:
+        btc_hf_client_start_voice_recognition();
+        break;
+    case BTC_HF_CLIENT_STOP_VOICE_RECOGNITION_EVT:
+        btc_hf_client_stop_voice_recognition();
+        break;
+    case BTC_HF_CLIENT_VOLUME_UPDATE_EVT:
+        btc_hf_client_volume_update(arg->volume_update.type, arg->volume_update.volume);
+        break;
+    case BTC_HF_CLIENT_DIAL_EVT:
+        btc_hf_client_dial(arg->dial.number);
+        break;
+    case BTC_HF_CLIENT_DIAL_MEMORY_EVT:
+        btc_hf_client_dial_memory(arg->dial_memory.location);
+        break;
+    case BTC_HF_CLIENT_SEND_CHLD_CMD_EVT:
+        btc_hf_client_send_chld_cmd(arg->chld.type, arg->chld.idx);
+        break;
+    case BTC_HF_CLIENT_SEND_BTRH_CMD_EVT:
+        btc_hf_client_send_btrh_cmd(arg->btrh.cmd);
+        break;
+    case BTC_HF_CLIENT_ANSWER_CALL_EVT:
+        btc_hf_client_answer_call();
+        break;
+    case BTC_HF_CLIENT_REJECT_CALL_EVT:
+        btc_hf_client_reject_call();
+        break;
+    case BTC_HF_CLIENT_QUERY_CURRENT_CALLS_EVT:
+        btc_hf_client_query_current_calls();
+        break;
+    case BTC_HF_CLIENT_QUERY_CURRENT_OPERATOR_NAME_EVT:
+        btc_hf_client_query_current_operator_name();
+        break;
+    case BTC_HF_CLIENT_RETRIEVE_SUBSCRIBER_INFO_EVT:
+        btc_hf_client_retrieve_subscriber_info();
+        break;
+    case BTC_HF_CLIENT_SEND_DTMF_EVT:
+        btc_hf_client_send_dtmf(arg->send_dtmf.code);
+        break;
+    case BTC_HF_CLIENT_REQUEST_LAST_VOICE_TAG_NUMBER_EVT:
+        btc_hf_client_request_last_voice_tag_number();
+        break;
+    case BTC_HF_CLIENT_REGISTER_DATA_CALLBACK_EVT:
+        btc_hf_client_reg_data_cb(arg->reg_data_cb.recv, arg->reg_data_cb.send);
+        break;
+    default:
+        BTC_TRACE_WARNING("%s : unhandled event: %d\n", __FUNCTION__, msg->act);
+    }
+}
+
+#endif /* #if (BTC_HF_CLIENT_INCLUDED == TRUE) */
diff --git a/components/bt/bluedroid/btc/profile/std/include/btc_hf_client.h b/components/bt/bluedroid/btc/profile/std/include/btc_hf_client.h
new file mode 100644 (file)
index 0000000..6500b9d
--- /dev/null
@@ -0,0 +1,128 @@
+// Copyright 2018 Espressif Systems (Shanghai) PTE LTD
+//
+// 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:      btc_hf_client.h
+ *
+ *  Description:   Main API header file for all BTC HF client functions accessed
+ *                 from internal stack.
+ *
+ *******************************************************************************/
+
+#ifndef __BTC_HF_CLIENT_H__
+#define __BTC_HF_CLIENT_H__
+
+#include "common/bt_target.h"
+#include "esp_hf_client_api.h"
+#include "btc/btc_task.h"
+#include "btc/btc_common.h"
+#include "bta/bta_hf_client_api.h"
+
+#if (BTC_HF_CLIENT_INCLUDED == TRUE)
+/*******************************************************************************
+**  Type definitions for callback functions
+********************************************************************************/
+typedef enum {
+    BTC_HF_CLIENT_INIT_EVT,
+    BTC_HF_CLIENT_DEINIT_EVT,
+    BTC_HF_CLIENT_CONNECT_EVT,
+    BTC_HF_CLIENT_DISCONNECT_EVT,
+    BTC_HF_CLIENT_CONNECT_AUDIO_EVT,
+    BTC_HF_CLIENT_DISCONNECT_AUDIO_EVT,
+    BTC_HF_CLIENT_START_VOICE_RECOGNITION_EVT,
+    BTC_HF_CLIENT_STOP_VOICE_RECOGNITION_EVT,
+    BTC_HF_CLIENT_VOLUME_UPDATE_EVT,
+    BTC_HF_CLIENT_DIAL_EVT,
+    BTC_HF_CLIENT_DIAL_MEMORY_EVT,
+    BTC_HF_CLIENT_SEND_CHLD_CMD_EVT,
+    BTC_HF_CLIENT_SEND_BTRH_CMD_EVT,
+    BTC_HF_CLIENT_ANSWER_CALL_EVT,
+    BTC_HF_CLIENT_REJECT_CALL_EVT,
+    BTC_HF_CLIENT_QUERY_CURRENT_CALLS_EVT,
+    BTC_HF_CLIENT_QUERY_CURRENT_OPERATOR_NAME_EVT,
+    BTC_HF_CLIENT_RETRIEVE_SUBSCRIBER_INFO_EVT,
+    BTC_HF_CLIENT_SEND_DTMF_EVT,
+    BTC_HF_CLIENT_REQUEST_LAST_VOICE_TAG_NUMBER_EVT,
+    BTC_HF_CLIENT_REGISTER_DATA_CALLBACK_EVT,
+} btc_hf_client_act_t;
+
+/* btc_hf_client_args_t */
+typedef union {
+    // BTC_HF_CLIENT_CONNECT_EVT
+    bt_bdaddr_t connect;
+
+    // BTC_HF_CLIENT_DISCONNECT_EVT
+    bt_bdaddr_t disconnect;
+
+    // BTC_HF_CLIENT_CONNECT_AUDIO_EVT
+    bt_bdaddr_t connect_audio;
+
+    // BTC_HF_CLIENT_DISCONNECT_AUDIO_EVT
+    bt_bdaddr_t disconnect_audio;
+
+    // BTC_HF_CLIENT_VOLUME_UPDATE_EVT,
+    struct volume_update_args {
+        esp_hf_volume_control_target_t type;
+        int volume;
+    } volume_update;
+
+    // BTC_HF_CLIENT_DIAL_EVT
+    struct dial_args {
+        char number[ESP_BT_HF_CLIENT_NUMBER_LEN + 1];
+    } dial;
+
+    // BTC_HF_CLIENT_DIAL_MEMORY_EVT
+    struct dial_memory_args {
+        int location;
+    } dial_memory;
+
+    // BTC_HF_CLIENT_SEND_CHLD_CMD_EVT
+    struct send_chld_cmd_args {
+        esp_hf_chld_type_t type;
+        int idx;
+    } chld;
+
+    // BTC_HF_CLIENT_SEND_BTRH_CMD_EVT
+    struct send_btrh_cmd_args {
+        esp_hf_btrh_cmd_t cmd;
+    } btrh;
+
+    // BTC_HF_CLIENT_SEND_DTMF_EVT
+    struct send_dtmf {
+        char code;
+    } send_dtmf;
+
+    // BTC_HF_CLIENT_REGISTER_DATA_CALLBACK_EVT
+    struct reg_data_callback {
+        esp_hf_client_incoming_data_cb_t recv;
+        esp_hf_client_outgoing_data_cb_t send;
+    } reg_data_cb;
+} btc_hf_client_args_t;
+
+/*******************************************************************************
+**  BTC HF AG API
+********************************************************************************/
+
+void btc_hf_client_call_handler(btc_msg_t *msg);
+
+void btc_hf_client_cb_handler(btc_msg_t *msg);
+
+void btc_hf_client_incoming_data_cb_to_app(const uint8_t *data, uint32_t len);
+
+uint32_t btc_hf_client_outgoing_data_cb_to_app(uint8_t *data, uint32_t len);
+#endif  ///BTC_HF_CLIENT_INCLUDED == TRUE
+
+#endif /* __BTC_HF_CLIENT_H__ */
index 55b84b808f564cc6f2b7c4f38a9de11a02357f0b..8f3205f9be4e84b384d300d42243d98cac05bd74 100644 (file)
@@ -50,6 +50,7 @@
 #define BTC_PRF_QUEUE_INCLUDED      TRUE
 #define BTC_GAP_BT_INCLUDED         TRUE
 #define BTA_SDP_INCLUDED            TRUE
+#define BTA_DM_PM_INCLUDED          TRUE
 #define SDP_INCLUDED                TRUE
 
 #if CONFIG_A2DP_ENABLE
 #define BTC_SPP_INCLUDED            TRUE
 #endif /* CONFIG_BT_SPP_ENABLED */
 
+#if CONFIG_HFP_CLIENT_ENABLE
+#define BTC_HF_CLIENT_INCLUDED      TRUE
+#define BTA_HF_INCLUDED             TRUE
+#ifndef RFCOMM_INCLUDED
+#define RFCOMM_INCLUDED             TRUE
+#endif
+#ifndef BTM_SCO_INCLUDED
+#define BTM_SCO_INCLUDED            TRUE
+#endif
+#ifndef BTM_MAX_SCO_LINKS
+#define BTM_MAX_SCO_LINKS           (1)
+#endif
+#endif  /* CONFIG_HFP_HF_ENABLE */
+
 #endif /* #if CONFIG_CLASSIC_BT_ENABLED */
 
 #ifndef CLASSIC_BT_INCLUDED
 #define BTA_INCLUDED TRUE
 #endif
 
+#ifndef BTA_DM_PM_INCLUDED
+#define BTA_DM_PM_INCLUDED FALSE
+#endif
+
 #ifndef BTA_PAN_INCLUDED
 #define BTA_PAN_INCLUDED FALSE
 #endif
 
 /* Includes SCO if TRUE */
 #ifndef BTM_SCO_INCLUDED
-#define BTM_SCO_INCLUDED            FALSE      //TRUE       /* TRUE includes SCO code */
+#define BTM_SCO_INCLUDED                FALSE       /* TRUE includes SCO code */
 #endif
 
 /* Includes SCO if TRUE */
 #ifndef BTM_SCO_HCI_INCLUDED
-#define BTM_SCO_HCI_INCLUDED            FALSE       /* TRUE includes SCO over HCI code */
+#if CONFIG_HFP_AUDIO_DATA_PATH_HCI
+#define BTM_SCO_HCI_INCLUDED            TRUE       /* TRUE includes SCO over HCI code */
+#else
+#define BTM_SCO_HCI_INCLUDED            FALSE
+#endif /* CONFIG_HFP_AUDIO_DATA_PATH_HCI */
 #endif
 
 /* Includes WBS if TRUE */
 *************************/
 /* max TX SCO data packet size */
 #ifndef BTM_SCO_DATA_SIZE_MAX
-#define BTM_SCO_DATA_SIZE_MAX       240
+#define BTM_SCO_DATA_SIZE_MAX       120 //240
 #endif
 
 /* The size in bytes of the BTM inquiry database. 5 As Default */
 
 /* The number of SCO links. */
 #ifndef BTM_MAX_SCO_LINKS
-#if (CLASSIC_BT_INCLUDED == TRUE)
-#define BTM_MAX_SCO_LINKS           1  //3
-#else   ///CLASSIC_BT_INCLUDED == TRUE
-#define BTM_MAX_SCO_LINKS           0
-#endif  ///CLASSIC_BT_INCLUDED == TRUE
+#define BTM_MAX_SCO_LINKS           0  //3
 #endif
 
 /* The preferred type of SCO links (2-eSCO, 0-SCO). */
 
 /* This is set to TRUE if link is to be unparked due to BTM_CreateSCO API. */
 #ifndef BTM_SCO_WAKE_PARKED_LINK
-#define BTM_SCO_WAKE_PARKED_LINK    TRUE
+#define BTM_SCO_WAKE_PARKED_LINK    FALSE
 #endif
 
 /* If the user does not respond to security process requests within this many seconds,
 #endif
 
 /* TRUE to include Sniff Subrating */
+#if (BTA_DM_PM_INCLUDED == TRUE)
 #ifndef BTM_SSR_INCLUDED
 #define BTM_SSR_INCLUDED                FALSE
 #endif
+#endif /* BTA_DM_PM_INCLUDED */
 
 /*************************
 ** End of Lisbon Features
index 93ef5384e89b2ec34523931daac9e7ee7a6a3d8c..06b8a52c7c6a8a68da00eadf91f72729fbcd7cde 100644 (file)
@@ -16,6 +16,7 @@
  *
  ******************************************************************************/
 #include <stdbool.h>
+#include "common/bt_target.h"
 #include "common/bt_trace.h"
 #include "device/bdaddr.h"
 #include "stack/bt_types.h"
@@ -61,6 +62,9 @@ static uint16_t acl_data_size_ble;
 static uint16_t acl_buffer_count_classic;
 static uint8_t acl_buffer_count_ble;
 
+static uint8_t sco_data_size;
+static uint16_t sco_buffer_count;
+
 static uint8_t ble_white_list_size;
 static uint8_t ble_resolving_list_max_size;
 static uint8_t ble_supported_states[BLE_SUPPORTED_STATES_SIZE];
@@ -88,7 +92,8 @@ static void start_up(void)
     // Request the classic buffer size next
     response = AWAIT_COMMAND(packet_factory->make_read_buffer_size());
     packet_parser->parse_read_buffer_size_response(
-        response, &acl_data_size_classic, &acl_buffer_count_classic);
+        response, &acl_data_size_classic, &acl_buffer_count_classic,
+        &sco_data_size, &sco_buffer_count);
 
     // Tell the controller about our buffer sizes and buffer counts next
     // TODO(zachoverflow): factor this out. eww l2cap contamination. And why just a hardcoded 10?
@@ -244,6 +249,10 @@ static void start_up(void)
         packet_parser->parse_generic_command_complete(response);
     }
 
+#if (BTM_SCO_HCI_INCLUDED == TRUE)
+    response = AWAIT_COMMAND(packet_factory->make_write_sync_flow_control_enable(1));
+    packet_parser->parse_generic_command_complete(response);
+#endif
     readable = true;
     // return future_new_immediate(FUTURE_SUCCESS);
     return;
@@ -447,6 +456,20 @@ static void set_ble_resolving_list_max_size(int resolving_list_max_size)
     ble_resolving_list_max_size = resolving_list_max_size;
 }
 
+#if (BTM_SCO_HCI_INCLUDED == TRUE)
+static uint8_t get_sco_data_size(void)
+{
+    assert(readable);
+    return sco_data_size;
+}
+
+static uint8_t get_sco_buffer_count(void)
+{
+    assert(readable);
+    return sco_buffer_count;
+}
+#endif /* (BTM_SCO_HCI_INCLUDED == TRUE) */
+
 static const controller_t interface = {
     start_up,
     shut_down,
@@ -489,7 +512,11 @@ static const controller_t interface = {
     get_ble_white_list_size,
 
     get_ble_resolving_list_max_size,
-    set_ble_resolving_list_max_size
+    set_ble_resolving_list_max_size,
+#if (BTM_SCO_HCI_INCLUDED == TRUE)
+    get_sco_data_size,
+    get_sco_buffer_count,
+#endif /* (BTM_SCO_HCI_INCLUDED == TRUE) */
 };
 
 const controller_t *controller_get_interface()
index b2806d69b80a47d3fce74d656a6d0904391f4dd0..704b456d7f4b45c468fc1cc4a366e347013b9abe 100644 (file)
@@ -79,6 +79,11 @@ typedef struct controller_t {
 
     uint8_t (*get_ble_resolving_list_max_size)(void);
     void (*set_ble_resolving_list_max_size)(int resolving_list_max_size);
+#if (BTM_SCO_HCI_INCLUDED == TRUE)
+    // Get the number of sco packets the controller can buffer
+    uint8_t (*get_sco_data_size)(void);
+    uint8_t (*get_sco_buffer_count)(void);
+#endif /* #if (BTM_SCO_HCI_INCLUDED == TRUE) */
 } controller_t;
 
 const controller_t *controller_get_interface();
diff --git a/components/bt/bluedroid/hci/hci_audio.c b/components/bt/bluedroid/hci/hci_audio.c
new file mode 100644 (file)
index 0000000..1983e7a
--- /dev/null
@@ -0,0 +1,7 @@
+#include "hci/hci_audio.h"
+
+void set_audio_state(uint16_t handle, sco_codec_t codec, sco_state_t state)
+{
+    //todo
+    return;
+}
index 549323be6167d1204c9a1d812036732266c01835..2c88570e3de36554ea1a94dcf07db876e9ca511a 100644 (file)
@@ -175,6 +175,15 @@ static BT_HDR *make_ble_set_event_mask(const bt_event_mask_t *event_mask)
     return packet;
 }
 
+static BT_HDR *make_write_sync_flow_control_enable(uint8_t enable)
+{
+    uint8_t *stream;
+    const uint8_t parameter_size = 1;
+    BT_HDR *packet = make_command(HCI_WRITE_SCO_FLOW_CTRL_ENABLE, parameter_size, &stream);
+
+    UINT8_TO_STREAM(stream, enable);
+    return packet;
+}
 // Internal functions
 
 static BT_HDR *make_command_no_params(uint16_t opcode)
@@ -227,7 +236,8 @@ static const hci_packet_factory_t interface = {
     make_ble_read_resolving_list_size,
     make_ble_read_suggested_default_data_length,
     make_ble_write_suggested_default_data_length,
-    make_ble_set_event_mask
+    make_ble_set_event_mask,
+    make_write_sync_flow_control_enable
 };
 
 const hci_packet_factory_t *hci_packet_factory_get_interface()
index 627d1ccb824953a5b63f7abb26879105bc135214..c2adee5e66f6eaa8fbbf2c3e60827b68bffe0a51 100644 (file)
@@ -42,16 +42,18 @@ static void parse_generic_command_complete(BT_HDR *response)
 
 static void parse_read_buffer_size_response(
     BT_HDR *response,
-    uint16_t *data_size_ptr,
-    uint16_t *acl_buffer_count_ptr)
+    uint16_t *acl_data_size_ptr,
+    uint16_t *acl_buffer_count_ptr,
+    uint8_t *sco_data_size_ptr,
+    uint16_t *sco_buffer_count_ptr)
 {
 
-    uint8_t *stream = read_command_complete_header(response, HCI_READ_BUFFER_SIZE, 5 /* bytes after */);
+    uint8_t *stream = read_command_complete_header(response, HCI_READ_BUFFER_SIZE, 7 /* bytes after */);
     assert(stream != NULL);
-    STREAM_TO_UINT16(*data_size_ptr, stream);
-    STREAM_SKIP_UINT8(stream); // skip the sco packet length
+    STREAM_TO_UINT16(*acl_data_size_ptr, stream);
+    STREAM_TO_UINT8(*sco_data_size_ptr, stream);
     STREAM_TO_UINT16(*acl_buffer_count_ptr, stream);
-
+    STREAM_TO_UINT16(*sco_buffer_count_ptr, stream);
     buffer_allocator->free(response);
 }
 
diff --git a/components/bt/bluedroid/hci/include/hci/hci_audio.h b/components/bt/bluedroid/hci/include/hci/hci_audio.h
new file mode 100644 (file)
index 0000000..a9234c3
--- /dev/null
@@ -0,0 +1,42 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2015 Google, Inc.
+ *
+ *  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.
+ *
+ ******************************************************************************/
+
+#ifndef _HCI_AUDIO_H_
+#define _HCI_AUDIO_H_
+#include <stdint.h>
+
+// Audio state definitions.
+typedef enum {
+    SCO_STATE_OFF = 0,      // Audio is off.
+    SCO_STATE_OFF_TRANSFER, // Closed pending final transfer of audio.
+    SCO_STATE_ON,           // Audio is on.
+    SCO_STATE_SETUP,        // Open pending completion of audio setup.
+} sco_state_t;
+
+// Codec type definitions.
+typedef enum {
+    SCO_CODEC_NONE = 0x0000,
+    SCO_CODEC_CVSD = 0x0001,
+    SCO_CODEC_MSBC = 0x0002,
+} sco_codec_t;
+
+// Set the audio state on the controller for SCO (PCM, WBS, ...) using the
+// vendor library.
+void set_audio_state(uint16_t handle, sco_codec_t codec, sco_state_t state);
+
+#endif /* _HCI_AUDIO_H_ */
index b98b80d5d7087ca32379011bb52ee1b5a28b859c..0cc4dc6849e87b221574ef059b6bdf2a29c4553e 100644 (file)
@@ -42,6 +42,7 @@ typedef struct {
     BT_HDR *(*make_ble_read_suggested_default_data_length)(void);
     BT_HDR *(*make_ble_write_suggested_default_data_length)(uint16_t SuggestedMaxTxOctets, uint16_t SuggestedMaxTxTime);
     BT_HDR *(*make_ble_set_event_mask)(const bt_event_mask_t *event_mask);
+    BT_HDR *(*make_write_sync_flow_control_enable)(uint8_t enable);
 } hci_packet_factory_t;
 
 const hci_packet_factory_t *hci_packet_factory_get_interface();
index 2e5b5ef986896d6722cf780840810179179a9f3e..b0cc4b3b49c86bceef31145fb7c94e6309535040 100644 (file)
@@ -33,8 +33,10 @@ typedef struct {
 
     void (*parse_read_buffer_size_response)(
         BT_HDR *response,
-        uint16_t *data_size_ptr,
-        uint16_t *acl_buffer_count_ptr
+        uint16_t *acl_data_size_ptr,
+        uint16_t *acl_buffer_count_ptr,
+        uint8_t *sco_data_size_ptr,
+        uint16_t *sco_buffer_count_ptr
     );
 
     void (*parse_read_local_version_info_response)(
index 1b1395f4b4d14e73cadf4402cf15b7911446a3fc..38cfc812fbc1610c4f5abba331b71b4bd5e02b4f 100644 (file)
@@ -89,7 +89,9 @@
 #include "bta/bta_sys.h"
 #include "osi/allocator.h"
 
-//#include "bta_ag_int.h"
+#if BTA_HF_INCLUDED == TRUE
+#include "bta_hf_client_int.h"
+#endif
 
 #if BTA_SDP_INCLUDED == TRUE
 #include "bta_sdp_int.h"
@@ -227,7 +229,13 @@ void BTE_InitStack(void)
     memset((void *)bta_dm_search_cb_ptr, 0, sizeof(tBTA_DM_SEARCH_CB));
     memset((void *)bta_dm_di_cb_ptr, 0, sizeof(tBTA_DM_DI_CB));
     //memset((void *)bta_prm_cb_ptr, 0, sizeof(tBTA_PRM_CB));
-    //memset((void *)bta_ag_cb_ptr, 0, sizeof(tBTA_AG_CB));
+
+#if (defined BTA_HF_INCLUDED && BTA_HF_INCLUDED == TRUE)
+    if ((bta_hf_client_cb_ptr = (tBTA_HF_CLIENT_CB *)osi_malloc(sizeof(tBTA_HF_CLIENT_CB))) == NULL) {
+        return;
+    }
+    memset((void *)bta_hf_client_cb_ptr, 0, sizeof(tBTA_HF_CLIENT_CB));
+#endif
 #if (defined BTA_JV_INCLUDED && BTA_JV_INCLUDED == TRUE)
     if ((bta_jv_cb_ptr = (tBTA_JV_CB *)osi_malloc(sizeof(tBTA_JV_CB))) == NULL) {
         return;
@@ -327,6 +335,10 @@ void BTE_DeinitStack(void)
     osi_free(bta_jv_cb_ptr);
     bta_jv_cb_ptr = NULL;
 #endif //JV
+#if (defined BTA_HF_INCLUDED && BTA_HF_INCLUDED == TRUE)
+    osi_free(bta_hf_client_cb_ptr);
+    bta_hf_client_cb_ptr = NULL;
+#endif
     osi_free(bta_dm_di_cb_ptr);
     bta_dm_di_cb_ptr = NULL;
     osi_free(bta_dm_search_cb_ptr);
@@ -354,4 +366,4 @@ void BTE_DeinitStack(void)
 #if (defined(A2D_INCLUDED) && A2D_INCLUDED == TRUE)
     A2D_Deinit();
 #endif
-}
\ No newline at end of file
+}
index 085cda925410d655d45261b97ceb8247f083d857..41bfb92f080576a0f0810e2fe778214222e4844e 100644 (file)
@@ -170,6 +170,9 @@ static void reset_complete(void)
     btm_pm_reset();
 
     l2c_link_processs_num_bufs(controller->get_acl_buffer_count_classic());
+#if BTM_SCO_HCI_INCLUDED == TRUE
+    btm_sco_process_num_bufs(controller->get_sco_buffer_count());
+#endif
 #if (BLE_INCLUDED == TRUE)
 
 #if (defined BLE_PRIVACY_SPT && BLE_PRIVACY_SPT == TRUE)
index d9b257d171265e530ce165b8bc82fef46094aa9e..e04209aab5f869f17f87287fef45979ed51e4dcb 100644 (file)
@@ -30,6 +30,7 @@
 #include "stack/hcimsgs.h"
 #include "stack/btu.h"
 #include "stack/btm_api.h"
+#include "osi/allocator.h"
 #include "btm_int.h"
 #include "stack/hcidefs.h"
 //#include "bt_utils.h"
@@ -109,6 +110,11 @@ void btm_sco_init (void)
 {
 #if 0  /* cleared in btm_init; put back in if called from anywhere else! */
     memset (&btm_cb.sco_cb, 0, sizeof(tSCO_CB));
+#endif
+#if (BTM_SCO_HCI_INCLUDED == TRUE)
+    for (int i = 0; i < BTM_MAX_SCO_LINKS; i++) {
+        btm_cb.sco_cb.sco_db[i].xmit_data_q = fixed_queue_new(SIZE_MAX);
+    }
 #endif
     /* Initialize nonzero defaults */
     btm_cb.sco_cb.sco_disc_reason  = BTM_INVALID_SCO_DISC_REASON;
@@ -207,6 +213,66 @@ static void btm_esco_conn_rsp (UINT16 sco_inx, UINT8 hci_status, BD_ADDR bda,
 
 
 #if BTM_SCO_HCI_INCLUDED == TRUE
+void btm_sco_process_num_bufs (UINT16 num_lm_sco_bufs)
+{
+    BTM_TRACE_ERROR("%s, %d", __FUNCTION__, num_lm_sco_bufs);
+    btm_cb.sco_cb.num_lm_sco_bufs = btm_cb.sco_cb.xmit_window_size = num_lm_sco_bufs;
+}
+
+/*******************************************************************************
+**
+** Function         BTM_ConfigScoPath
+**
+** Description      This function enable/disable SCO over HCI and registers SCO
+**                  data callback if SCO over HCI is enabled.
+**
+** Parameter        path: SCO or HCI
+**                  p_sco_data_cb: callback function or SCO data if path is set
+**                                 to transport.
+**                  p_pcm_param: pointer to the PCM interface parameter. If a NULL
+**                               pointer is used, PCM parameter maintained in
+**                               the control block will be used; otherwise update
+**                               control block value.
+**                  err_data_rpt: Lisbon feature to enable the erronous data report
+**                                or not.
+**
+** Returns          BTM_SUCCESS if the successful.
+**                  BTM_NO_RESOURCES: no rsource to start the command.
+**                  BTM_ILLEGAL_VALUE: invalid callback function pointer.
+**                  BTM_CMD_STARTED :Command sent. Waiting for command cmpl event.
+**
+**
+*******************************************************************************/
+//extern
+tBTM_STATUS BTM_ConfigScoPath (tBTM_SCO_ROUTE_TYPE path,
+                               tBTM_SCO_DATA_CB *p_sco_data_cb,
+                               tBTM_SCO_PCM_PARAM *p_pcm_param,
+                               BOOLEAN err_data_rpt)
+{
+    UNUSED(err_data_rpt);
+    UNUSED(p_pcm_param);
+    btm_cb.sco_cb.sco_path = path;
+    if (path == BTM_SCO_ROUTE_PCM) {
+        return BTM_SUCCESS;
+    } else if (path == BTM_SCO_ROUTE_HCI) {
+        if (p_sco_data_cb) {
+            btm_cb.sco_cb.p_data_cb = p_sco_data_cb;
+        }
+    }
+
+    return BTM_SUCCESS;
+}
+
+static void hci_sco_data_to_lower(BT_HDR *p_buf)
+{
+    p_buf->event = BT_EVT_TO_LM_HCI_SCO;
+    if (p_buf->offset == 0) {
+        BTM_TRACE_ERROR("offset cannot be 0");
+        osi_free(p_buf);
+    }
+
+    bte_main_hci_send(p_buf, (UINT16)(BT_EVT_TO_LM_HCI_SCO | LOCAL_BLE_CONTROLLER_ID));
+}
 /*******************************************************************************
 **
 ** Function         btm_sco_check_send_pkts
@@ -224,16 +290,58 @@ void btm_sco_check_send_pkts (UINT16 sco_inx)
 
     /* If there is data to send, send it now */
     BT_HDR  *p_buf;
-    while ((p_buf = (BT_HDR *)fixed_queue_try_dequeue(p_ccb->xmit_data_q)) != NULL)
+    while (p_cb->xmit_window_size != 0)
     {
+        if ((p_buf = (BT_HDR *)fixed_queue_try_dequeue(p_ccb->xmit_data_q)) == NULL) {
+            break;
+        }
 #if BTM_SCO_HCI_DEBUG
         BTM_TRACE_DEBUG("btm: [%d] buf in xmit_data_q",
                         fixed_queue_length(p_ccb->xmit_data_q) + 1);
 #endif
+        /* Don't go negative */
+        p_cb->xmit_window_size -= 1;
+        p_ccb->sent_not_acked += 1;
 
-        HCI_SCO_DATA_TO_LOWER(p_buf);
+        // HCI_SCO_DATA_TO_LOWER(p_buf);
+        hci_sco_data_to_lower(p_buf);
     }
 }
+
+void btm_sco_process_num_completed_pkts (UINT8 *p)
+{
+    UINT8       num_handles, xx;
+    UINT16      handle;
+    UINT16      num_sent;
+    UINT16      sco_inx;
+    tSCO_CB  *p_cb = &btm_cb.sco_cb;
+    tSCO_CONN * p_ccb;
+    STREAM_TO_UINT8 (num_handles, p);
+    for (xx = 0; xx < num_handles; xx++) {
+        STREAM_TO_UINT16 (handle, p);
+        handle &= 0x7ff; // walk around for bad handle bit mask from controller
+        STREAM_TO_UINT16 (num_sent, p);
+        if ((sco_inx = btm_find_scb_by_handle(handle & 0x7ff)) == BTM_MAX_SCO_LINKS) {
+            continue;
+        }
+        BTM_TRACE_DEBUG("%s, %d, %u", __FUNCTION__, handle, p_cb->xmit_window_size); //debug
+        p_ccb = &p_cb->sco_db[sco_inx];
+        p_ccb->sent_not_acked -= num_sent;
+        // don't go negative
+        if (p_ccb->sent_not_acked < 0) {
+            BTM_TRACE_WARNING("SCO: un-acked underf: %u", p_ccb->sent_not_acked);
+            p_ccb->sent_not_acked = 0;
+        }
+        p_cb->xmit_window_size += num_sent;
+        if (p_cb->xmit_window_size > p_cb->num_lm_sco_bufs) {
+            BTM_TRACE_WARNING("SCO xwind: %d, max %d", p_cb->xmit_window_size, p_cb->num_lm_sco_bufs);
+            p_cb->xmit_window_size = p_cb->num_lm_sco_bufs;
+        }
+        btm_sco_check_send_pkts (sco_inx);
+    }
+
+    return;
+}
 #endif /* BTM_SCO_HCI_INCLUDED == TRUE */
 
 /*******************************************************************************
@@ -259,7 +367,7 @@ void  btm_route_sco_data(BT_HDR *p_msg)
     handle   = HCID_GET_HANDLE (handle);
 
     STREAM_TO_UINT8 (pkt_size, p);
-
+    UNUSED(pkt_size);
     if ((sco_inx = btm_find_scb_by_handle(handle)) != BTM_MAX_SCO_LINKS ) {
         /* send data callback */
         if (!btm_cb.sco_cb.p_data_cb )
@@ -272,6 +380,7 @@ void  btm_route_sco_data(BT_HDR *p_msg)
     } else { /* no mapping handle SCO connection is active, free the buffer */
         osi_free (p_msg);
     }
+    BTM_TRACE_DEBUG ("SCO: hdl %x, len %d, pkt_sz %d\n", handle, p_msg->len, pkt_size);
 #else
     osi_free(p_msg);
 #endif
@@ -295,11 +404,13 @@ void  btm_route_sco_data(BT_HDR *p_msg)
 **                  BTM_NO_RESOURCES: no resources.
 **                  BTM_UNKNOWN_ADDR: unknown SCO connection handle, or SCO is not
 **                                    routed via HCI.
+**                  BTM_ERR_PROCESSING: transmit queue overflow
 **
 **
 *******************************************************************************/
 tBTM_STATUS BTM_WriteScoData (UINT16 sco_inx, BT_HDR *p_buf)
 {
+    APPL_TRACE_DEBUG("%s", __FUNCTION__);
 #if (BTM_SCO_HCI_INCLUDED == TRUE) && (BTM_MAX_SCO_LINKS>0)
     tSCO_CONN   *p_ccb = &btm_cb.sco_cb.sco_db[sco_inx];
     UINT8   *p;
@@ -310,7 +421,6 @@ tBTM_STATUS BTM_WriteScoData (UINT16 sco_inx, BT_HDR *p_buf)
         /* Ensure we have enough space in the buffer for the SCO and HCI headers */
         if (p_buf->offset < HCI_SCO_PREAMBLE_SIZE) {
             BTM_TRACE_ERROR ("BTM SCO - cannot send buffer, offset: %d", p_buf->offset);
-            osi_free (p_buf);
             status = BTM_ILLEGAL_VALUE;
         } else { /* write HCI header */
             /* Step back 3 bytes to add the headers */
@@ -327,20 +437,27 @@ tBTM_STATUS BTM_WriteScoData (UINT16 sco_inx, BT_HDR *p_buf)
             }
 
             UINT8_TO_STREAM (p, (UINT8)p_buf->len);
+            BTM_TRACE_DEBUG ("BTM SCO hdl %x, len %u", p_ccb->hci_handle, p_buf->len);
             p_buf->len += HCI_SCO_PREAMBLE_SIZE;
 
-            fixed_queue_enqueue(p_ccb->xmit_data_q, p_buf);
-
-            btm_sco_check_send_pkts (sco_inx);
+            if (fixed_queue_length(p_ccb->xmit_data_q) < BTM_SCO_XMIT_QUEUE_THRS) {
+                fixed_queue_enqueue(p_ccb->xmit_data_q, p_buf);
+                btm_sco_check_send_pkts (sco_inx);
+            } else {
+                BTM_TRACE_WARNING ("SCO xmit Q overflow, pkt dropped");
+                status = BTM_ERR_PROCESSING;
+            }
         }
     } else {
-        osi_free(p_buf);
-
         BTM_TRACE_WARNING ("BTM_WriteScoData, invalid sco index: %d at state [%d]",
                            sco_inx, btm_cb.sco_cb.sco_db[sco_inx].state);
         status = BTM_UNKNOWN_ADDR;
     }
 
+    if (status != BTM_SUCCESS && status != BTM_SCO_BAD_LENGTH) {
+        BTM_TRACE_WARNING ("stat %d", status);
+        osi_free(p_buf);
+    }
     return (status);
 
 #else
@@ -839,7 +956,7 @@ void btm_sco_connected (UINT8 hci_status, BD_ADDR bda, UINT16 hci_handle,
 #endif
 
     btm_cb.sco_cb.sco_disc_reason = hci_status;
-
+    BTM_TRACE_ERROR("%s, handle %x", __FUNCTION__, hci_handle);
 #if (BTM_MAX_SCO_LINKS>0)
     for (xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++) {
         if (((p->state == SCO_ST_CONNECTING) ||
@@ -876,7 +993,9 @@ void btm_sco_connected (UINT8 hci_status, BD_ADDR bda, UINT16 hci_handle,
             if (p->state == SCO_ST_LISTENING) {
                 spt = TRUE;
             }
-
+#if BTM_SCO_HCI_INCLUDED == TRUE
+            p->sent_not_acked = 0;
+#endif
             p->state = SCO_ST_CONNECTED;
             p->hci_handle = hci_handle;
 
@@ -1022,6 +1141,14 @@ void btm_sco_removed (UINT16 hci_handle, UINT8 reason)
             btm_sco_flush_sco_data(xx);
 
             p->state = SCO_ST_UNUSED;
+#if BTM_SCO_HCI_INCLUDED == TRUE
+            btm_cb.sco_cb.xmit_window_size += p->sent_not_acked;
+            /* avoid overflow */
+            if (btm_cb.sco_cb.xmit_window_size > btm_cb.sco_cb.num_lm_sco_bufs) {
+                btm_cb.sco_cb.xmit_window_size = btm_cb.sco_cb.num_lm_sco_bufs;
+            }
+            p->sent_not_acked = 0;
+#endif
             p->hci_handle = BTM_INVALID_HCI_HANDLE;
             p->rem_bd_known = FALSE;
             p->esco.p_esco_cback = NULL;    /* Deregister eSCO callback */
index 5922a5814556caf67a64c9f8c194d0fe53dac3cd..bde7af9a2e12d9af7b89d63756ad16e59fd72130 100644 (file)
@@ -365,7 +365,9 @@ typedef struct {
 typedef struct {
     tBTM_ESCO_INFO   esco;              /* Current settings             */
 #if BTM_SCO_HCI_INCLUDED == TRUE
+#define BTM_SCO_XMIT_QUEUE_THRS         20
     fixed_queue_t   *xmit_data_q;       /* SCO data transmitting queue  */
+    INT16           sent_not_acked;
 #endif
     tBTM_SCO_CB     *p_conn_cb;         /* Callback for when connected  */
     tBTM_SCO_CB     *p_disc_cb;         /* Callback for when disconnect */
@@ -382,6 +384,7 @@ typedef struct {
 #if BTM_SCO_HCI_INCLUDED == TRUE
     tBTM_SCO_DATA_CB     *p_data_cb;        /* Callback for SCO data over HCI */
     UINT32               xmit_window_size; /* Total SCO window in bytes  */
+    UINT16               num_lm_sco_bufs;
 #endif
     tSCO_CONN            sco_db[BTM_MAX_SCO_LINKS];
     tBTM_ESCO_PARAMS     def_esco_parms;
@@ -996,6 +999,10 @@ void btm_pm_proc_mode_change (UINT8 hci_status, UINT16 hci_handle, UINT8 mode,
 void btm_pm_proc_ssr_evt (UINT8 *p, UINT16 evt_len);
 #if BTM_SCO_INCLUDED == TRUE
 void btm_sco_chk_pend_unpark (UINT8 hci_status, UINT16 hci_handle);
+#if (BTM_SCO_HCI_INCLUDED == TRUE )
+void btm_sco_process_num_bufs (UINT16 num_lm_sco_bufs);
+void btm_sco_process_num_completed_pkts (UINT8 *p);
+#endif /* (BTM_SCO_HCI_INCLUDED == TRUE ) */
 #else
 #define btm_sco_chk_pend_unpark(hci_status, hci_handle)
 #endif /* BTM_SCO_INCLUDED */
index f0d50ed42b90927df0ff42183d2d2d8743d686c9..09f5af491433f64cb56ef27ae40c956982990f24 100644 (file)
@@ -1292,7 +1292,9 @@ static void btu_hcif_num_compl_data_pkts_evt (UINT8 *p)
     l2c_link_process_num_completed_pkts (p);
 
     /* Send on to SCO */
-    /*?? No SCO for now */
+#if (BTM_SCO_HCI_INCLUDED == TRUE) && (BTM_SCO_INCLUDED == TRUE)
+    btm_sco_process_num_completed_pkts (p);
+#endif
 }
 
 /*******************************************************************************
index 294cf84cee71c0bcaba73ef4e12a9876de07bbfe..79ecba8c8fbbafd772e24ec5ec0e539fd7094b11 100644 (file)
@@ -955,8 +955,8 @@ typedef UINT8 tBTM_SCO_TYPE;
 /*******************
 ** SCO Routing Path
 ********************/
-#define BTM_SCO_ROUTE_PCM           HCI_BRCM_SCO_ROUTE_PCM
-#define BTM_SCO_ROUTE_HCI           HCI_BRCM_SCO_ROUTE_HCI
+#define BTM_SCO_ROUTE_PCM           (0) // HCI_BRCM_SCO_ROUTE_PCM
+#define BTM_SCO_ROUTE_HCI           (1) // HCI_BRCM_SCO_ROUTE_HCI
 typedef UINT8 tBTM_SCO_ROUTE_TYPE;
 
 
index b227ea5cf9c1cbd1b4f13218f09e8ce8f932ec62..46b3e07116ac1faa91dcf4fcbda699668f0d584f 100644 (file)
@@ -833,7 +833,7 @@ void PORT_DataInd (tRFC_MCB *p_mcb, UINT8 dlci, BT_HDR *p_buf)
         //osi_free (p_buf);
         return;
     } else {
-        RFCOMM_TRACE_ERROR("PORT_DataInd, p_port:%p, p_data_co_callback is null", p_port);
+        RFCOMM_TRACE_DEBUG("PORT_DataInd, p_port:%p, p_data_co_callback is null", p_port);
     }
     /* If client registered callback we can just deliver receive data */
     if (p_port->p_data_callback) {
@@ -1094,4 +1094,4 @@ void port_get_credits (tPORT *p_port, UINT8 k)
 }
 
 
-#endif ///(defined RFCOMM_INCLUDED && RFCOMM_INCLUDED == TRUE)
\ No newline at end of file
+#endif ///(defined RFCOMM_INCLUDED && RFCOMM_INCLUDED == TRUE)
index 68f5dee7fda4fd6570c889b4281188a31b98d730..eeb374f1f2b8a7bd9a7ba8e623ecca16950b45ea 100644 (file)
@@ -97,6 +97,7 @@ extern int ble_txpwr_set(int power_type, int power_level);
 extern int ble_txpwr_get(int power_type);
 extern int bredr_txpwr_set(int min_power_level, int max_power_level);
 extern int bredr_txpwr_get(int *min_power_level, int *max_power_level);
+extern void bredr_sco_datapath_set(uint8_t data_path);
 
 extern char _bss_start_btdm;
 extern char _bss_end_btdm;
@@ -1103,4 +1104,13 @@ void esp_bt_controller_wakeup_request(void)
     btdm_wakeup_request();
 }
 
+esp_err_t esp_bredr_sco_datapath_set(esp_sco_data_path_t data_path)
+{
+    if (btdm_controller_status != ESP_BT_CONTROLLER_STATUS_ENABLED) {
+        return ESP_ERR_INVALID_STATE;
+    }
+    bredr_sco_datapath_set(data_path);
+    return ESP_OK;
+}
+
 #endif /*  CONFIG_BT_ENABLED */
index 8de4d6889cc7f43128aeeb2cc5af6de0cf1fe338..f0c1f1202747c776f71eb6951bb499f8773caad1 100644 (file)
@@ -25,6 +25,7 @@ ifdef CONFIG_BLUEDROID_ENABLED
 COMPONENT_PRIV_INCLUDEDIRS +=   bluedroid/bta/include                   \
                                 bluedroid/bta/ar/include                \
                                 bluedroid/bta/av/include                \
+                                bluedroid/bta/hf_client/include         \
                                 bluedroid/bta/dm/include                \
                                 bluedroid/bta/gatt/include              \
                                 bluedroid/bta/hh/include                \
@@ -75,6 +76,7 @@ COMPONENT_SRCDIRS +=    bluedroid/bta/dm                      \
                         bluedroid/bta/ar                      \
                         bluedroid/bta/sys                     \
                         bluedroid/bta/jv                      \
+                        bluedroid/bta/hf_client               \
                         bluedroid/bta                         \
                         bluedroid/btcore                      \
                         bluedroid/btif                        \
@@ -92,6 +94,7 @@ COMPONENT_SRCDIRS +=    bluedroid/bta/dm                      \
                         bluedroid/btc/profile/std/a2dp        \
                         bluedroid/btc/profile/std/avrc        \
                         bluedroid/btc/profile/std/spp         \
+                        bluedroid/btc/profile/std/hf_client   \
                         bluedroid/btc/profile                 \
                         bluedroid/stack/btm                   \
                         bluedroid/stack/btu                   \
@@ -111,5 +114,4 @@ COMPONENT_SRCDIRS +=    bluedroid/bta/dm                      \
                         bluedroid/utils                       \
                         bluedroid/api                         \
                         bluedroid
-
 endif
index 9924420f6f0318d5c7f963cce8fe98a0827fe77c..2b06c09d115c44313f99316f112154a8b9c0924c 100644 (file)
@@ -122,6 +122,14 @@ typedef enum {
     ESP_PWR_LVL_P7  = 7,            /*!< Corresponding to   7dbm */
 } esp_power_level_t;
 
+/**
+ * @brief Bluetooth audio data transport path
+ */
+typedef enum {
+    ESP_SCO_DATA_PATH_HCI = 0,            /*!< data over HCI transport */
+    ESP_SCO_DATA_PATH_PCM = 1,            /*!< data over PCM interface */
+} esp_sco_data_path_t;
+
 /**
  * @brief  Set BLE TX power
  *         Connection Tx power should only be set after connection created.
@@ -164,6 +172,13 @@ esp_err_t esp_bredr_tx_power_set(esp_power_level_t min_power_level, esp_power_le
  */
 esp_err_t esp_bredr_tx_power_get(esp_power_level_t *min_power_level, esp_power_level_t *max_power_level);
 
+/**
+ * @brief  set default SCO data path
+ *         Should be called after controller is enabled, and before (e)SCO link is established
+ * @param  data_path: SCO data path
+ * @return              ESP_OK - success, other - failed
+ */
+esp_err_t esp_bredr_sco_datapath_set(esp_sco_data_path_t data_path);
 
 /**
  * @brief  Initialize BT controller to allocate task and other resource.
index 700d2bc914b755b840a0adeaa9d1ff45b398b6fa..16516d7009f1c31c21939047447a95238194de40 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 700d2bc914b755b840a0adeaa9d1ff45b398b6fa
+Subproject commit 16516d7009f1c31c21939047447a95238194de40
index 6529aacb9752161f7eedb255e0911bddce42a7c4..8c458ff14612523cca85423cfade9ced5193817c 100644 (file)
@@ -1704,6 +1704,7 @@ PROVIDE ( ets_update_cpu_frequency_rom = 0x40008550 );  /* Updates g_ticks_per_u
 PROVIDE ( hci_tl_env = 0x3ffb8154 );
 PROVIDE ( ld_acl_env = 0x3ffb8258 );
 PROVIDE ( ea_env = 0x3ffb80ec );
+PROVIDE ( lc_sco_data_path_config = 0x3ffb81f8 );
 PROVIDE ( ld_active_ch_map = 0x3ffb8334 );
 PROVIDE ( ld_bcst_acl_env = 0x3ffb8274 );
 PROVIDE ( ld_csb_rx_env = 0x3ffb8278 );
index 7c1ac334d31552ecad61efce5e0568401883e4fa..481eaa3fe5b7e0d25acf95a0619ad097fc474b98 100644 (file)
@@ -51,6 +51,8 @@ INPUT = \
     ../../components/bt/bluedroid/api/include/api/esp_a2dp_api.h \
     ../../components/bt/bluedroid/api/include/api/esp_avrc_api.h \
     ../../components/bt/bluedroid/api/include/api/esp_spp_api.h \
+    ../../components/bt/bluedroid/api/include/api/esp_hf_defs.h \
+    ../../components/bt/bluedroid/api/include/api/esp_hf_client_api.h \
     ##
     ## Ethernet - API Reference
     ##
index 2fd161e711cab14a5a083d745aecb9de0209551a..3a9a30430bfa335c1405a5ef94213799c181ae48 100644 (file)
@@ -8,3 +8,5 @@ CLASSIC BT
    BT A2DP <esp_a2dp>
    BT AVRC <esp_avrc>
    BT SPP <esp_spp>
+   BT HFP Define <esp_hf_defs>
+   BT HFP Client <esp_hf_client>
diff --git a/docs/en/api-reference/bluetooth/esp_hf_client.rst b/docs/en/api-reference/bluetooth/esp_hf_client.rst
new file mode 100644 (file)
index 0000000..7c8a2d8
--- /dev/null
@@ -0,0 +1,14 @@
+HFP CLIENT API
+==============
+
+Overview
+--------
+
+`Instructions`_
+
+.. _Instructions: ../template.html
+
+API Reference
+-------------
+
+.. include:: /_build/inc/esp_hf_client_api.inc
diff --git a/docs/en/api-reference/bluetooth/esp_hf_defs.rst b/docs/en/api-reference/bluetooth/esp_hf_defs.rst
new file mode 100644 (file)
index 0000000..615b623
--- /dev/null
@@ -0,0 +1,16 @@
+HFP DEFINES
+===========
+
+Overview
+--------
+
+`Instructions`_
+
+.. _Instructions: ../template.html
+
+API Reference
+-------------
+
+.. include:: /_build/inc/esp_hf_defs.inc
+
+
diff --git a/docs/zh_CN/api-reference/bluetooth/esp_hf_client.rst b/docs/zh_CN/api-reference/bluetooth/esp_hf_client.rst
new file mode 100644 (file)
index 0000000..160f0b2
--- /dev/null
@@ -0,0 +1 @@
+.. include:: ../../../en/api-reference/bluetooth/esp_hf_client.rst
diff --git a/docs/zh_CN/api-reference/bluetooth/esp_hf_defs.rst b/docs/zh_CN/api-reference/bluetooth/esp_hf_defs.rst
new file mode 100644 (file)
index 0000000..f863457
--- /dev/null
@@ -0,0 +1 @@
+.. include:: ../../../en/api-reference/bluetooth/esp_hf_defs.rst