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
--- /dev/null
+// 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 */
--- /dev/null
+// 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__ */
--- /dev/null
+// 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__ */
#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));
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)
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;
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:
{
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 );
}
/* 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) {
/* 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);
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
};
}
},
- /* 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)
}
},
- /* 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)
}
},
- /* AVK : 12 */
+ /* AVK : 3 */
{
(BTA_DM_PM_SNIFF), /* allow sniff */
#if (BTM_SSR_INCLUDED == TRUE)
}
#if BLE_INCLUDED == TRUE
- /* GATTC : 13 */
+ /* GATTC : 4 */
, {
(BTA_DM_PM_SNIFF | BTA_DM_PM_PARK), /* allow park & sniff */
#if (BTM_SSR_INCLUDED == TRUE)
{{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)
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,
}
}
#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
// 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)
/*******************************************************************************
**
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 */
#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);
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) */
/*******************************************************************************
**
}
}
-/*******************************************************************************
-**
-** 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
{
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
** 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 )
{
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 &&
}
}
#endif
+
/*******************************************************************************
**
** Function bta_dm_pm_active
/* 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
}
}
+
/*******************************************************************************
**
** Function bta_dm_pm_btm_status
default:
break;
}
-
-
-
}
+
/*******************************************************************************
**
** Function bta_dm_pm_timer
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
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)
/*******************************************************************************
APPL_TRACE_DEBUG("bta_dm_pm_obtain_controller_state: %d", cur_state);
return cur_state;
}
+
#endif
APPL_TRACE_DEBUG("bta_pcm_resample : outsamples %d", out_sample);
#endif
- return (out_sample * bta_dm_pcm_cb.sample_size);
+ return (out_sample);
}
#endif
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,
#endif
} tBTA_DM_ACL_CHANGE;
+#if (BTA_DM_PM_INCLUDED == TRUE)
/* data type for BTA_DM_PM_BTM_STATUS_EVT */
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 {
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;
} 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
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 {
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 */
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;
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
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);
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);
--- /dev/null
+/******************************************************************************
+ *
+ * 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) */
--- /dev/null
+/******************************************************************************
+ *
+ * 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) */
--- /dev/null
+/******************************************************************************
+ *
+ * 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) */
--- /dev/null
+/******************************************************************************
+ *
+ * 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) */
--- /dev/null
+/******************************************************************************
+ *
+ * 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) */
--- /dev/null
+/******************************************************************************
+ *
+ * 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) */
--- /dev/null
+/******************************************************************************
+ *
+ * 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, ¶ms);
+ /* 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, ¶ms);
+ }
+
+ /* 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) */
--- /dev/null
+/******************************************************************************
+ *
+ * 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) */
--- /dev/null
+/******************************************************************************
+ *
+ * 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) */
--- /dev/null
+/******************************************************************************
+ *
+ * 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) */
*******************************************************************************/
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
#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
*****************************************************************************/
*******************************************************************************/
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);
-
-
/*******************************************************************************
**
--- /dev/null
+/******************************************************************************
+ *
+ * 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 */
--- /dev/null
+// 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 */
--- /dev/null
+// 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__ */
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
******************************************************************************/
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;
#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 */
#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 */
};
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
--- /dev/null
+// 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) */
--- /dev/null
+// 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(¶m, 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, ¶m);
+ } 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(¶m, 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, ¶m);
+ 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, ¶m);
+ 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, ¶m);
+ 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, ¶m);
+ 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, ¶m);
+ 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, ¶m);
+ 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, ¶m);
+ 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(¶m, 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, ¶m);
+ } 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(¶m, 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, ¶m);
+ } while (0);
+
+ /* Inform the application about in-band ringtone */
+ if (btc_hf_client_cb.peer_feat & BTA_HF_CLIENT_PEER_INBAND)
+ {
+ do {
+ memset(¶m, 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, ¶m);
+ } 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(¶m, 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, ¶m);
+ } 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(¶m, 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, ¶m);
+ } while (0);
+ break;
+ case BTA_HF_CLIENT_SPK_EVT:
+ do {
+ memset(¶m, 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, ¶m);
+ } while (0);
+ break;
+ case BTA_HF_CLIENT_VOICE_REC_EVT:
+ do {
+ memset(¶m, 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, ¶m);
+ } while (0);
+ break;
+ case BTA_HF_CLIENT_OPERATOR_NAME_EVT:
+ do {
+ memset(¶m, 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, ¶m);
+ } while (0);
+ break;
+ case BTA_HF_CLIENT_CLIP_EVT:
+ do {
+ memset(¶m, 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, ¶m);
+ } while (0);
+ break;
+ case BTA_HF_CLIENT_BINP_EVT:
+ do {
+ memset(¶m, 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, ¶m);
+ } while (0);
+ break;
+ case BTA_HF_CLIENT_CCWA_EVT:
+ do {
+ memset(¶m, 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, ¶m);
+ } while (0);
+ break;
+ case BTA_HF_CLIENT_AT_RESULT_EVT:
+ do {
+ memset(¶m, 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, ¶m);
+ } while (0);
+ break;
+ case BTA_HF_CLIENT_CLCC_EVT:
+ do {
+ memset(¶m, 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, ¶m);
+ } while (0);
+ break;
+ case BTA_HF_CLIENT_CNUM_EVT:
+ do {
+ memset(¶m, 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, ¶m);
+ break;
+ } while (0);
+ break;
+ case BTA_HF_CLIENT_BTRH_EVT:
+ if (p_data->val.value <= ESP_HF_BTRH_STATUS_REJECTED) {
+ do {
+ memset(¶m, 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, ¶m);
+ } while (0);
+ }
+ break;
+ case BTA_HF_CLIENT_BSIR_EVT:
+ memset(¶m, 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, ¶m);
+ break;
+ case BTA_HF_CLIENT_AUDIO_OPEN_EVT:
+ do {
+ memset(¶m, 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, ¶m);
+ } while (0);
+ break;
+ case BTA_HF_CLIENT_AUDIO_MSBC_OPEN_EVT:
+ do {
+ memset(¶m, 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, ¶m);
+ } while (0);
+ break;
+ case BTA_HF_CLIENT_AUDIO_CLOSE_EVT:
+ do {
+ memset(¶m, 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, ¶m);
+ } 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) */
--- /dev/null
+// 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__ */
#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
*
******************************************************************************/
#include <stdbool.h>
+#include "common/bt_target.h"
#include "common/bt_trace.h"
#include "device/bdaddr.h"
#include "stack/bt_types.h"
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];
// 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?
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;
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,
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()
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();
--- /dev/null
+#include "hci/hci_audio.h"
+
+void set_audio_state(uint16_t handle, sco_codec_t codec, sco_state_t state)
+{
+ //todo
+ return;
+}
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)
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()
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);
}
--- /dev/null
+/******************************************************************************
+ *
+ * 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_ */
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();
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)(
#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"
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;
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);
#if (defined(A2D_INCLUDED) && A2D_INCLUDED == TRUE)
A2D_Deinit();
#endif
-}
\ No newline at end of file
+}
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)
#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"
{
#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;
#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
/* 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 */
/*******************************************************************************
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 )
} 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
** 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;
/* 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 */
}
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
#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) ||
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;
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 */
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 */
#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;
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 */
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
}
/*******************************************************************************
/*******************
** 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;
//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) {
}
-#endif ///(defined RFCOMM_INCLUDED && RFCOMM_INCLUDED == TRUE)
\ No newline at end of file
+#endif ///(defined RFCOMM_INCLUDED && RFCOMM_INCLUDED == TRUE)
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;
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 */
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 \
bluedroid/bta/ar \
bluedroid/bta/sys \
bluedroid/bta/jv \
+ bluedroid/bta/hf_client \
bluedroid/bta \
bluedroid/btcore \
bluedroid/btif \
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 \
bluedroid/utils \
bluedroid/api \
bluedroid
-
endif
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.
*/
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.
-Subproject commit 700d2bc914b755b840a0adeaa9d1ff45b398b6fa
+Subproject commit 16516d7009f1c31c21939047447a95238194de40
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 );
../../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
##
BT A2DP <esp_a2dp>
BT AVRC <esp_avrc>
BT SPP <esp_spp>
+ BT HFP Define <esp_hf_defs>
+ BT HFP Client <esp_hf_client>
--- /dev/null
+HFP CLIENT API
+==============
+
+Overview
+--------
+
+`Instructions`_
+
+.. _Instructions: ../template.html
+
+API Reference
+-------------
+
+.. include:: /_build/inc/esp_hf_client_api.inc
--- /dev/null
+HFP DEFINES
+===========
+
+Overview
+--------
+
+`Instructions`_
+
+.. _Instructions: ../template.html
+
+API Reference
+-------------
+
+.. include:: /_build/inc/esp_hf_defs.inc
+
+
--- /dev/null
+.. include:: ../../../en/api-reference/bluetooth/esp_hf_client.rst
--- /dev/null
+.. include:: ../../../en/api-reference/bluetooth/esp_hf_defs.rst