From 4c4e143a2f82215694e14f3c21828aba23c62db9 Mon Sep 17 00:00:00 2001 From: wangmengyang Date: Mon, 21 May 2018 11:33:30 +0800 Subject: [PATCH] component/bt: implement HFP Hands Free Unit Role --- components/bt/Kconfig | 27 + .../bt/bluedroid/api/esp_hf_client_api.c | 476 +++++ .../api/include/api/esp_hf_client_api.h | 635 ++++++ .../bluedroid/api/include/api/esp_hf_defs.h | 181 ++ components/bt/bluedroid/bta/dm/bta_dm_act.c | 28 +- components/bt/bluedroid/bta/dm/bta_dm_cfg.c | 221 +- components/bt/bluedroid/bta/dm/bta_dm_ci.c | 29 - components/bt/bluedroid/bta/dm/bta_dm_co.c | 143 -- components/bt/bluedroid/bta/dm/bta_dm_main.c | 4 +- components/bt/bluedroid/bta/dm/bta_dm_pm.c | 120 +- components/bt/bluedroid/bta/dm/bta_dm_sco.c | 2 +- .../bt/bluedroid/bta/dm/include/bta_dm_int.h | 33 +- .../bta/hf_client/bta_hf_client_act.c | 772 +++++++ .../bta/hf_client/bta_hf_client_api.c | 312 +++ .../bta/hf_client/bta_hf_client_at.c | 1795 +++++++++++++++++ .../bta/hf_client/bta_hf_client_cmd.c | 85 + .../bta/hf_client/bta_hf_client_main.c | 662 ++++++ .../bta/hf_client/bta_hf_client_rfc.c | 246 +++ .../bta/hf_client/bta_hf_client_sco.c | 825 ++++++++ .../bta/hf_client/bta_hf_client_sdp.c | 367 ++++ .../bta/hf_client/include/bta_hf_client_at.h | 117 ++ .../bta/hf_client/include/bta_hf_client_int.h | 296 +++ .../bt/bluedroid/bta/include/bta/bta_dm_ci.h | 12 - .../bt/bluedroid/bta/include/bta/bta_dm_co.h | 89 - .../bta/include/bta/bta_hf_client_api.h | 378 ++++ .../bta/include/bta/bta_hf_client_co.h | 115 ++ .../bluedroid/bta/include/bta/bta_hfp_defs.h | 47 + components/bt/bluedroid/btc/core/btc_dm.c | 8 + components/bt/bluedroid/btc/core/btc_task.c | 6 + .../bt/bluedroid/btc/include/btc/btc_task.h | 3 + .../profile/std/hf_client/bta_hf_client_co.c | 137 ++ .../btc/profile/std/hf_client/btc_hf_client.c | 1089 ++++++++++ .../btc/profile/std/include/btc_hf_client.h | 128 ++ .../common/include/common/bt_target.h | 39 +- components/bt/bluedroid/device/controller.c | 31 +- .../device/include/device/controller.h | 5 + components/bt/bluedroid/hci/hci_audio.c | 7 + .../bt/bluedroid/hci/hci_packet_factory.c | 12 +- .../bt/bluedroid/hci/hci_packet_parser.c | 14 +- .../bt/bluedroid/hci/include/hci/hci_audio.h | 42 + .../hci/include/hci/hci_packet_factory.h | 1 + .../hci/include/hci/hci_packet_parser.h | 6 +- components/bt/bluedroid/main/bte_init.c | 18 +- .../bt/bluedroid/stack/btm/btm_devctl.c | 3 + components/bt/bluedroid/stack/btm/btm_sco.c | 149 +- .../bt/bluedroid/stack/btm/include/btm_int.h | 7 + components/bt/bluedroid/stack/btu/btu_hcif.c | 4 +- .../bluedroid/stack/include/stack/btm_api.h | 4 +- .../bt/bluedroid/stack/rfcomm/port_rfc.c | 4 +- components/bt/bt.c | 10 + components/bt/component.mk | 4 +- components/bt/include/esp_bt.h | 15 + components/bt/lib | 2 +- components/esp32/ld/esp32.rom.ld | 1 + docs/Doxyfile | 2 + .../en/api-reference/bluetooth/classic_bt.rst | 2 + .../api-reference/bluetooth/esp_hf_client.rst | 14 + .../api-reference/bluetooth/esp_hf_defs.rst | 16 + .../api-reference/bluetooth/esp_hf_client.rst | 1 + .../api-reference/bluetooth/esp_hf_defs.rst | 1 + 60 files changed, 9191 insertions(+), 611 deletions(-) create mode 100644 components/bt/bluedroid/api/esp_hf_client_api.c create mode 100644 components/bt/bluedroid/api/include/api/esp_hf_client_api.h create mode 100644 components/bt/bluedroid/api/include/api/esp_hf_defs.h create mode 100644 components/bt/bluedroid/bta/hf_client/bta_hf_client_act.c create mode 100644 components/bt/bluedroid/bta/hf_client/bta_hf_client_api.c create mode 100644 components/bt/bluedroid/bta/hf_client/bta_hf_client_at.c create mode 100644 components/bt/bluedroid/bta/hf_client/bta_hf_client_cmd.c create mode 100644 components/bt/bluedroid/bta/hf_client/bta_hf_client_main.c create mode 100644 components/bt/bluedroid/bta/hf_client/bta_hf_client_rfc.c create mode 100644 components/bt/bluedroid/bta/hf_client/bta_hf_client_sco.c create mode 100644 components/bt/bluedroid/bta/hf_client/bta_hf_client_sdp.c create mode 100644 components/bt/bluedroid/bta/hf_client/include/bta_hf_client_at.h create mode 100644 components/bt/bluedroid/bta/hf_client/include/bta_hf_client_int.h create mode 100644 components/bt/bluedroid/bta/include/bta/bta_hf_client_api.h create mode 100644 components/bt/bluedroid/bta/include/bta/bta_hf_client_co.h create mode 100644 components/bt/bluedroid/bta/include/bta/bta_hfp_defs.h create mode 100644 components/bt/bluedroid/btc/profile/std/hf_client/bta_hf_client_co.c create mode 100644 components/bt/bluedroid/btc/profile/std/hf_client/btc_hf_client.c create mode 100644 components/bt/bluedroid/btc/profile/std/include/btc_hf_client.h create mode 100644 components/bt/bluedroid/hci/hci_audio.c create mode 100644 components/bt/bluedroid/hci/include/hci/hci_audio.h create mode 100644 docs/en/api-reference/bluetooth/esp_hf_client.rst create mode 100644 docs/en/api-reference/bluetooth/esp_hf_defs.rst create mode 100644 docs/zh_CN/api-reference/bluetooth/esp_hf_client.rst create mode 100644 docs/zh_CN/api-reference/bluetooth/esp_hf_defs.rst diff --git a/components/bt/Kconfig b/components/bt/Kconfig index 853265d65..aca5029e7 100644 --- a/components/bt/Kconfig +++ b/components/bt/Kconfig @@ -189,6 +189,33 @@ config BT_SPP_ENABLED help This enables the Serial Port Profile +config HFP_ENABLE + bool "Hands Free/Handset Profile" + depends on CLASSIC_BT_ENABLED + default n + +choice HFP_ROLE + prompt "Hands-free Profile Role configuration" + depends on HFP_ENABLE + +config HFP_CLIENT_ENABLE + bool "Hands Free Unit" +endchoice + +choice HFP_AUDIO_DATA_PATH + prompt "audio(SCO) data path" + depends on HFP_ENABLE + +config HFP_AUDIO_DATA_PATH_PCM + bool "PCM" + help + This enables the Serial Port Profile +config HFP_AUDIO_DATA_PATH_HCI + bool "HCI" + help + This enables the Serial Port Profile +endchoice + config GATTS_ENABLE bool "Include GATT server module(GATTS)" depends on BLUEDROID_ENABLED diff --git a/components/bt/bluedroid/api/esp_hf_client_api.c b/components/bt/bluedroid/api/esp_hf_client_api.c new file mode 100644 index 000000000..fbc5d475c --- /dev/null +++ b/components/bt/bluedroid/api/esp_hf_client_api.c @@ -0,0 +1,476 @@ +// Copyright 2018 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "common/bt_target.h" +#include +#include "esp_err.h" +#include "esp_hf_client_api.h" +#include "esp_bt_main.h" +#include "btc/btc_manage.h" +#include "btc_hf_client.h" +#include "bta/bta_api.h" +#include "bta/bta_hf_client_api.h" + +#if BTC_HF_CLIENT_INCLUDED +esp_err_t esp_hf_client_register_callback(esp_hf_client_cb_t callback) +{ + if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) { + return ESP_ERR_INVALID_STATE; + } + + if (callback == NULL) { + return ESP_FAIL; + } + + btc_profile_cb_set(BTC_PID_HF_CLIENT, callback); + return ESP_OK; +} + +esp_err_t esp_hf_client_init(void) +{ + if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) { + return ESP_ERR_INVALID_STATE; + } + + btc_msg_t msg; + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_HF_CLIENT; + msg.act = BTC_HF_CLIENT_INIT_EVT; + + /* Switch to BTC context */ + bt_status_t stat = btc_transfer_context(&msg, NULL, 0, NULL); + return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL; +} + +esp_err_t esp_hf_client_deinit(void) +{ + if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) { + return ESP_ERR_INVALID_STATE; + } + + btc_msg_t msg; + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_HF_CLIENT; + msg.act = BTC_HF_CLIENT_DEINIT_EVT; + + /* Switch to BTC context */ + bt_status_t stat = btc_transfer_context(&msg, NULL, 0, NULL); + return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL; +} + +esp_err_t esp_hf_client_connect(esp_bd_addr_t remote_bda) +{ + if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) { + return ESP_ERR_INVALID_STATE; + } + + bt_status_t stat; + btc_hf_client_args_t arg; + btc_msg_t msg; + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_HF_CLIENT; + msg.act = BTC_HF_CLIENT_CONNECT_EVT; + + memset(&arg, 0, sizeof(btc_hf_client_args_t)); + + /* Switch to BTC context */ + memcpy(&(arg.connect), remote_bda, sizeof(bt_bdaddr_t)); + stat = btc_transfer_context(&msg, &arg, sizeof(btc_hf_client_args_t), NULL); + return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL; +} + +esp_err_t esp_hf_client_disconnect(esp_bd_addr_t remote_bda) +{ + if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) { + return ESP_ERR_INVALID_STATE; + } + + bt_status_t stat; + btc_hf_client_args_t arg; + btc_msg_t msg; + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_HF_CLIENT; + msg.act = BTC_HF_CLIENT_DISCONNECT_EVT; + + memset(&arg, 0, sizeof(btc_hf_client_args_t)); + + /* Switch to BTC context */ + memcpy(&(arg.disconnect), remote_bda, sizeof(bt_bdaddr_t)); + stat = btc_transfer_context(&msg, &arg, sizeof(btc_hf_client_args_t), NULL); + return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL; +} + +esp_err_t esp_hf_client_connect_audio(esp_bd_addr_t remote_bda) +{ + if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) { + return ESP_ERR_INVALID_STATE; + } + + bt_status_t stat; + btc_hf_client_args_t arg; + btc_msg_t msg; + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_HF_CLIENT; + msg.act = BTC_HF_CLIENT_CONNECT_AUDIO_EVT; + + memset(&arg, 0, sizeof(btc_hf_client_args_t)); + + /* Switch to BTC context */ + memcpy(&(arg.connect_audio), remote_bda, sizeof(bt_bdaddr_t)); + stat = btc_transfer_context(&msg, &arg, sizeof(btc_hf_client_args_t), NULL); + return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL; +} + +esp_err_t esp_hf_client_disconnect_audio(esp_bd_addr_t remote_bda) +{ + if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) { + return ESP_ERR_INVALID_STATE; + } + + bt_status_t stat; + btc_hf_client_args_t arg; + btc_msg_t msg; + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_HF_CLIENT; + msg.act = BTC_HF_CLIENT_DISCONNECT_AUDIO_EVT; + + memset(&arg, 0, sizeof(btc_hf_client_args_t)); + + /* Switch to BTC context */ + memcpy(&(arg.disconnect_audio), remote_bda, sizeof(bt_bdaddr_t)); + stat = btc_transfer_context(&msg, &arg, sizeof(btc_hf_client_args_t), NULL); + return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL; +} + + +esp_err_t esp_hf_client_start_voice_recognition(void) +{ + if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) { + return ESP_ERR_INVALID_STATE; + } + + btc_msg_t msg; + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_HF_CLIENT; + msg.act = BTC_HF_CLIENT_START_VOICE_RECOGNITION_EVT; + + /* Switch to BTC context */ + bt_status_t stat = btc_transfer_context(&msg, NULL, 0, NULL); + return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL; +} + +esp_err_t esp_hf_client_stop_voice_recognition(void) +{ + if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) { + return ESP_ERR_INVALID_STATE; + } + + btc_msg_t msg; + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_HF_CLIENT; + msg.act = BTC_HF_CLIENT_STOP_VOICE_RECOGNITION_EVT; + + /* Switch to BTC context */ + bt_status_t stat = btc_transfer_context(&msg, NULL, 0, NULL); + return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL; +} + +esp_err_t esp_hf_client_volume_update(esp_hf_volume_control_target_t type, int volume) +{ + if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) { + return ESP_ERR_INVALID_STATE; + } + + btc_msg_t msg; + btc_hf_client_args_t arg; + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_HF_CLIENT; + msg.act = BTC_HF_CLIENT_VOLUME_UPDATE_EVT; + + memset(&arg, 0, sizeof(btc_hf_client_args_t)); + arg.volume_update.type = type; + arg.volume_update.volume = volume; + + /* Switch to BTC context */ + bt_status_t stat = btc_transfer_context(&msg, &arg, sizeof(btc_hf_client_args_t), NULL); + return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL; +} + +esp_err_t esp_hf_client_dial(const char *number) +{ + if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) { + return ESP_ERR_INVALID_STATE; + } + + btc_msg_t msg; + btc_hf_client_args_t arg; + + if (number != NULL && strlen(number) > ESP_BT_HF_CLIENT_NUMBER_LEN) { + return ESP_ERR_INVALID_ARG; + } + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_HF_CLIENT; + msg.act = BTC_HF_CLIENT_DIAL_EVT; + + memset(&arg, 0, sizeof(btc_hf_client_args_t)); + if (number != NULL) { + strcpy(arg.dial.number, number); + } else { + arg.dial.number[0] = '\0'; + } + + /* Switch to BTC context */ + bt_status_t stat = btc_transfer_context(&msg, &arg, sizeof(btc_hf_client_args_t), NULL); + return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL; +} + +esp_err_t esp_hf_client_dial_memory(int location) +{ + if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) { + return ESP_ERR_INVALID_STATE; + } + + btc_msg_t msg; + btc_hf_client_args_t arg; + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_HF_CLIENT; + msg.act = BTC_HF_CLIENT_DIAL_MEMORY_EVT; + + memset(&arg, 0, sizeof(btc_hf_client_args_t)); + arg.dial_memory.location = location; + + /* Switch to BTC context */ + bt_status_t stat = btc_transfer_context(&msg, &arg, sizeof(btc_hf_client_args_t), NULL); + return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL; +} + +esp_err_t esp_hf_client_send_chld_cmd(esp_hf_chld_type_t chld, int idx) +{ + if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) { + return ESP_ERR_INVALID_STATE; + } + + btc_msg_t msg; + btc_hf_client_args_t arg; + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_HF_CLIENT; + msg.act = BTC_HF_CLIENT_SEND_CHLD_CMD_EVT; + + memset(&arg, 0, sizeof(btc_hf_client_args_t)); + arg.chld.type = chld; + arg.chld.idx = idx; + + /* Switch to BTC context */ + bt_status_t stat = btc_transfer_context(&msg, &arg, sizeof(btc_hf_client_args_t), NULL); + return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL; +} + +esp_err_t esp_hf_client_send_btrh_cmd(esp_hf_btrh_cmd_t btrh) +{ + if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) { + return ESP_ERR_INVALID_STATE; + } + + btc_msg_t msg; + btc_hf_client_args_t arg; + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_HF_CLIENT; + msg.act = BTC_HF_CLIENT_SEND_BTRH_CMD_EVT; + + memset(&arg, 0, sizeof(btc_hf_client_args_t)); + arg.btrh.cmd = btrh; + + /* Switch to BTC context */ + bt_status_t stat = btc_transfer_context(&msg, &arg, sizeof(btc_hf_client_args_t), NULL); + return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL; +} + +esp_err_t esp_hf_client_answer_call(void) +{ + if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) { + return ESP_ERR_INVALID_STATE; + } + + btc_msg_t msg; + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_HF_CLIENT; + msg.act = BTC_HF_CLIENT_ANSWER_CALL_EVT; + + /* Switch to BTC context */ + bt_status_t stat = btc_transfer_context(&msg, NULL, 0, NULL); + return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL; +} + +esp_err_t esp_hf_client_reject_call(void) +{ + if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) { + return ESP_ERR_INVALID_STATE; + } + + btc_msg_t msg; + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_HF_CLIENT; + msg.act = BTC_HF_CLIENT_REJECT_CALL_EVT; + + /* Switch to BTC context */ + bt_status_t stat = btc_transfer_context(&msg, NULL, 0, NULL); + return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL; +} + +esp_err_t esp_hf_client_query_current_calls(void) +{ + if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) { + return ESP_ERR_INVALID_STATE; + } + + btc_msg_t msg; + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_HF_CLIENT; + msg.act = BTC_HF_CLIENT_QUERY_CURRENT_CALLS_EVT; + + /* Switch to BTC context */ + bt_status_t stat = btc_transfer_context(&msg, NULL, 0, NULL); + return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL; +} + +esp_err_t esp_hf_client_query_current_operator_name(void) +{ + if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) { + return ESP_ERR_INVALID_STATE; + } + + btc_msg_t msg; + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_HF_CLIENT; + msg.act = BTC_HF_CLIENT_QUERY_CURRENT_OPERATOR_NAME_EVT; + + /* Switch to BTC context */ + bt_status_t stat = btc_transfer_context(&msg, NULL, 0, NULL); + return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL; +} + +esp_err_t esp_hf_client_retrieve_subscriber_info(void) +{ + if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) { + return ESP_ERR_INVALID_STATE; + } + + btc_msg_t msg; + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_HF_CLIENT; + msg.act = BTC_HF_CLIENT_RETRIEVE_SUBSCRIBER_INFO_EVT; + + /* Switch to BTC context */ + bt_status_t stat = btc_transfer_context(&msg, NULL, 0, NULL); + return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL; +} + +esp_err_t esp_hf_client_send_dtmf(char code) +{ + if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) { + return ESP_ERR_INVALID_STATE; + } + + btc_msg_t msg; + btc_hf_client_args_t arg; + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_HF_CLIENT; + msg.act = BTC_HF_CLIENT_SEND_DTMF_EVT; + + memset(&arg, 0, sizeof(btc_hf_client_args_t)); + arg.send_dtmf.code = code; + + /* Switch to BTC context */ + bt_status_t stat = btc_transfer_context(&msg, &arg, sizeof(btc_hf_client_args_t), NULL); + return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL; +} + +esp_err_t esp_hf_client_request_last_voice_tag_number(void) +{ + if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) { + return ESP_ERR_INVALID_STATE; + } + + btc_msg_t msg; + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_HF_CLIENT; + msg.act = BTC_HF_CLIENT_REQUEST_LAST_VOICE_TAG_NUMBER_EVT; + + /* Switch to BTC context */ + bt_status_t stat = btc_transfer_context(&msg, NULL, 0, NULL); + return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL; +} + +esp_err_t esp_hf_client_register_data_callback(esp_hf_client_incoming_data_cb_t recv, + esp_hf_client_outgoing_data_cb_t send) +{ + if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) { + return ESP_ERR_INVALID_STATE; + } + + btc_msg_t msg; + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_HF_CLIENT; + msg.act = BTC_HF_CLIENT_REGISTER_DATA_CALLBACK_EVT; + + btc_hf_client_args_t arg; + memset(&arg, 0, sizeof(btc_hf_client_args_t)); + arg.reg_data_cb.recv = recv; + arg.reg_data_cb.send = send; + + /* Switch to BTC context */ + bt_status_t stat = btc_transfer_context(&msg, &arg, sizeof(btc_hf_client_args_t), NULL); + return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL; +} + + +#if (BTM_SCO_HCI_INCLUDED == TRUE ) +void esp_hf_client_outgoing_data_ready(void) +{ + BTA_HfClientCiData(); +} + +void esp_hf_client_pcm_resample_init(uint32_t src_sps, uint32_t bits, uint32_t channels) +{ + BTA_DmPcmInitSamples(src_sps, bits, channels); +} + +int32_t esp_hf_client_pcm_resample(void *src, uint32_t in_bytes, void *dst) +{ + return BTA_DmPcmResample(src, in_bytes, dst); +} + +#endif /* #if (BTM_SCO_HCI_INCLUDED == TRUE ) */ + +#endif /* BTC_HF_CLIENT_INCLUDED */ diff --git a/components/bt/bluedroid/api/include/api/esp_hf_client_api.h b/components/bt/bluedroid/api/include/api/esp_hf_client_api.h new file mode 100644 index 000000000..65598e087 --- /dev/null +++ b/components/bt/bluedroid/api/include/api/esp_hf_client_api.h @@ -0,0 +1,635 @@ +// Copyright 2018 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef __ESP_HF_CLIENT_API_H__ +#define __ESP_HF_CLIENT_API_H__ + +#include "esp_err.h" +#include "esp_bt_defs.h" +#include "esp_hf_defs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ESP_BT_HF_CLIENT_NUMBER_LEN (32) +#define ESP_BT_HF_CLIENT_OPERATOR_NAME_LEN (16) + +/// Bluetooth HFP RFCOMM connection and service level connection status +typedef enum { + ESP_HF_CLIENT_CONNECTION_STATE_DISCONNECTED = 0, /*!< RFCOMM data link channel released */ + ESP_HF_CLIENT_CONNECTION_STATE_CONNECTING, /*!< connecting remote device on the RFCOMM data link*/ + ESP_HF_CLIENT_CONNECTION_STATE_CONNECTED, /*!< RFCOMM connection established */ + ESP_HF_CLIENT_CONNECTION_STATE_SLC_CONNECTED, /*!< service level connection established */ + ESP_HF_CLIENT_CONNECTION_STATE_DISCONNECTING, /*!< disconnecting with remote device on the RFCOMM dat link*/ +} esp_hf_client_connection_state_t; + +/// Bluetooth HFP audio connection status +typedef enum { + ESP_HF_CLIENT_AUDIO_STATE_DISCONNECTED = 0, /*!< audio connection released */ + ESP_HF_CLIENT_AUDIO_STATE_CONNECTING, /*!< audio connection has been initiated */ + ESP_HF_CLIENT_AUDIO_STATE_CONNECTED, /*!< audio connection is established */ + ESP_HF_CLIENT_AUDIO_STATE_CONNECTED_MSBC, /*!< mSBC audio connection is estalibshed */ +} esp_hf_client_audio_state_t; + +/// in-band ring tone state +typedef enum { + ESP_HF_CLIENT_IN_BAND_RINGTONE_NOT_PROVIDED = 0, + ESP_HF_CLIENT_IN_BAND_RINGTONE_PROVIDED, +} esp_hf_client_in_band_ring_state_t; + +/* features masks of AG */ +#define ESP_HF_CLIENT_PEER_FEAT_3WAY 0x01 /* Three-way calling */ +#define ESP_HF_CLIENT_PEER_FEAT_ECNR 0x02 /* Echo cancellation and/or noise reduction */ +#define ESP_HF_CLIENT_PEER_FEAT_VREC 0x04 /* Voice recognition */ +#define ESP_HF_CLIENT_PEER_FEAT_INBAND 0x08 /* In-band ring tone */ +#define ESP_HF_CLIENT_PEER_FEAT_VTAG 0x10 /* Attach a phone number to a voice tag */ +#define ESP_HF_CLIENT_PEER_FEAT_REJECT 0x20 /* Ability to reject incoming call */ +#define ESP_HF_CLIENT_PEER_FEAT_ECS 0x40 /* Enhanced Call Status */ +#define ESP_HF_CLIENT_PEER_FEAT_ECC 0x80 /* Enhanced Call Control */ +#define ESP_HF_CLIENT_PEER_FEAT_EXTERR 0x100 /* Extended error codes */ +#define ESP_HF_CLIENT_PEER_FEAT_CODEC 0x200 /* Codec Negotiation */ + +/* CHLD feature masks of AG */ +#define ESP_HF_CLIENT_CHLD_FEAT_REL 0x01 /* 0 Release waiting call or held calls */ +#define ESP_HF_CLIENT_CHLD_FEAT_REL_ACC 0x02 /* 1 Release active calls and accept other waiting or held call */ +#define ESP_HF_CLIENT_CHLD_FEAT_REL_X 0x04 /* 1x Release specified active call only */ +#define ESP_HF_CLIENT_CHLD_FEAT_HOLD_ACC 0x08 /* 2 Active calls on hold and accept other waiting or held call */ +#define ESP_HF_CLIENT_CHLD_FEAT_PRIV_X 0x10 /* 2x Request private mode with specified call(put the rest on hold */ +#define ESP_HF_CLIENT_CHLD_FEAT_MERGE 0x20 /* 3 Add held call to multiparty */ +#define ESP_HF_CLIENT_CHLD_FEAT_MERGE_DETACH 0x40 /* 4 Connect two calls and leave(disconnct from multiparty */ + +/// HF CLIENT callback events +typedef enum { + ESP_HF_CLIENT_CONNECTION_STATE_EVT = 0, /*!< connection state changed event */ + ESP_HF_CLIENT_AUDIO_STATE_EVT, /*!< audio connection state change event */ + ESP_HF_CLIENT_BVRA_EVT, /*!< voice recognition state change event */ + ESP_HF_CLIENT_CIND_CALL_EVT, /*!< call indication */ + ESP_HF_CLIENT_CIND_CALL_SETUP_EVT, /*!< call setup indication */ + ESP_HF_CLIENT_CIND_CALL_HELD_EVT, /*!< call held indication */ + ESP_HF_CLIENT_CIND_SERVICE_AVAILABILITY_EVT, /*!< network service availability indication */ + ESP_HF_CLIENT_CIND_SIGNAL_STRENGTH_EVT, /*!< signal strength indication */ + ESP_HF_CLIENT_CIND_ROAMING_STATUS_EVT, /*!< roaming status indication */ + ESP_HF_CLIENT_CIND_BATTERY_LEVEL_EVT, /*!< battery level indication */ + ESP_HF_CLIENT_COPS_CURRENT_OPERATOR_EVT, /*!< current operator information */ + ESP_HF_CLIENT_BTRH_EVT, /*!< call response and hold event */ + ESP_HF_CLIENT_CLIP_EVT, /*!< Calling Line Identification notification */ + ESP_HF_CLIENT_CCWA_EVT, /*!< call waiting notification */ + ESP_HF_CLIENT_CLCC_EVT, /*!< list of current calls notification */ + ESP_HF_CLIENT_VOLUME_CONTROL_EVT, /*!< audio volume control command from AG, provided by +VGM or +VGS message */ + ESP_HF_CLIENT_AT_RESPONSE_EVT, /*!< AT command response event */ + ESP_HF_CLIENT_CNUM_EVT, /*!< subscriber information response from AG */ + ESP_HF_CLIENT_BSIR_EVT, /*!< setting of in-band ring tone */ + ESP_HF_CLIENT_BINP_EVT, /*!< requested number of last voice tag from AG */ + ESP_HF_CLIENT_RING_IND_EVT, /*!< ring indication event */ +} esp_hf_client_cb_event_t; + +/// HFP client callback parameters +typedef union { + /** + * @brief ESP_HF_CLIENT_CONNECTION_STATE_EVT + */ + struct hf_client_conn_stat_param { + esp_hf_client_connection_state_t state; /*!< HF connection state */ + uint32_t peer_feat; /*!< AG supported features */ + uint32_t chld_feat; /*!< AG supported features on call hold and multiparty services */ + esp_bd_addr_t remote_bda; /*!< remote bluetooth device address */ + } conn_stat; /*!< HF callback param of ESP_HF_CLIENT_CONNECTION_STATE_EVT */ + + /** + * @brief ESP_HF_CLIENT_AUDIO_STATE_EVT + */ + struct hf_client_audio_stat_param { + esp_hf_client_audio_state_t state; /*!< audio connection state */ + esp_bd_addr_t remote_bda; /*!< remote bluetooth device address */ + } audio_stat; /*!< HF callback param of ESP_HF_CLIENT_AUDIO_STATE_EVT */ + + /** + * @brief ESP_HF_CLIENT_BVRA_EVT + */ + struct hf_client_bvra_param { + esp_hf_vr_state_t value; /*!< voice recognition state */ + } bvra; /*!< HF callback param of ESP_HF_CLIENT_BVRA_EVT */ + + /** + * @brief ESP_HF_CLIENT_CIND_SERVICE_AVAILABILITY_EVT + */ + struct hf_client_service_availability_param { + esp_hf_service_availability_status_t status; /*!< service availability status */ + } service_availability; /*!< HF callback param of ESP_HF_CLIENT_CIND_SERVICE_AVAILABILITY_EVT */ + + /** + * @brief ESP_HF_CLIENT_CIND_ROAMING_STATUS_EVT + */ + struct hf_client_network_roaming_param { + esp_hf_roaming_status_t status; /*!< roaming status */ + } roaming; /*!< HF callback param of ESP_HF_CLIENT_CIND_ROAMING_STATUS_EVT */ + + /** + * @brief ESP_HF_CLIENT_CIND_SIGNAL_STRENGTH_EVT + */ + struct hf_client_signal_strength_ind_param { + int value; /*!< singal strength value, ranges from 0 to 5 */ + } signal_strength; /*!< HF callback param of ESP_HF_CLIENT_CIND_SIGNAL_STRENGTH_EVT */ + + /** + * @brief ESP_HF_CLIENT_CIND_BATTERY_LEVEL_EVT + */ + struct hf_client_battery_level_ind_param { + int value; /*!< battery charge value, ranges from 0 to 5 */ + } battery_level; /*!< HF callback param of ESP_HF_CLIENT_CIND_BATTERY_LEVEL_EVT */ + + /** + * @brief ESP_HF_CLIENT_COPS_CURRENT_OPERATOR_EVT + */ + struct hf_client_current_operator_param { + const char *name; /*!< name of the network operator */ + } cops; /*!< HF callback param of ESP_HF_CLIENT_COPS_CURRENT_OPERATOR_EVT */ + + /** + * @brief ESP_HF_CLIENT_CIND_CALL_EVT + */ + struct hf_client_call_ind_param { + esp_hf_call_status_t status; /*!< call status indicator */ + } call; /*!< HF callback param of ESP_HF_CLIENT_CIND_CALL_EVT */ + + /** + * @brief ESP_HF_CLIENT_CIND_CALL_SETUP_EVT + */ + struct hf_client_call_setup_ind_param { + esp_hf_call_setup_status_t status; /*!< call setup status indicator */ + } call_setup; /*!< HF callback param of ESP_HF_CLIENT_BVRA_EVT */ + + /** + * @brief ESP_HF_CLIENT_CIND_CALL_HELD_EVT + */ + struct hf_client_call_held_ind_param { + esp_hf_call_held_status_t status; /*!< bluetooth proprietary call hold status indocator */ + } call_held; /*!< HF callback param of ESP_HF_CLIENT_CIND_CALL_HELD_EVT */ + + /** + * @brief ESP_HF_CLIENT_BTRH_EVT + */ + struct hf_client_btrh_param { + esp_hf_btrh_status_t status; /*!< call hold and response status result code */ + } btrh; /*!< HF callback param of ESP_HF_CLIENT_BRTH_EVT */ + + /** + * @brief ESP_HF_CLIENT_CLIP_EVT + */ + struct hf_client_clip_param { + const char *number; /*!< phone number string of call */ + } clip; /*!< HF callback param of ESP_HF_CLIENT_CLIP_EVT */ + + /** + * @brief ESP_HF_CLIENT_CCWA_EVT + */ + struct hf_client_ccwa_param { + const char *number; /*!< phone number string of waiting call */ + } ccwa; /*!< HF callback param of ESP_HF_CLIENT_BVRA_EVT */ + + /** + * @brief ESP_HF_CLIENT_CLCC_EVT + */ + struct hf_client_clcc_param { + int idx; /*!< numbering(starting with 1) of the call */ + esp_hf_current_call_direction_t dir; /*!< direction of the call */ + esp_hf_current_call_status_t status; /*!< status of the call */ + esp_hf_current_call_mpty_type_t mpty; /*!< multi-party flag */ + char *number; /*!< phone number(optional) */ + } clcc; /*!< HF callback param of ESP_HF_CLIENT_CLCC_EVT */ + + /** + * @brief ESP_HF_CLIENT_VOLUME_CONTROL_EVT + */ + struct hf_client_volume_control_param { + esp_hf_volume_control_target_t type; /*!< volume control target, speaker or microphone */ + int volume; /*!< gain, ranges from 0 to 15 */ + } volume_control; /*!< HF callback param of ESP_HF_CLIENT_VOLUME_CONTROL_EVT */ + + /** + * @brief ESP_HF_CLIENT_AT_RESPONSE_EVT + */ + struct hf_client_at_response_param { + esp_hf_at_response_code_t code; /*!< AT response code */ + esp_hf_cme_err_t cme; /*!< Extended Audio Gateway Error Result Code */ + } at_response; /*!< HF callback param of ESP_HF_CLIENT_AT_RESPONSE_EVT */ + + /** + * @brief ESP_HF_CLIENT_CNUM_EVT + */ + struct hf_client_cnum_param { + const char *number; /*!< phone number string */ + esp_hf_subscriber_service_type_t type; /*!< service type that the phone number relates to */ + } cnum; /*!< HF callback param of ESP_HF_CLIENT_CNUM_EVT */ + + /** + * @brief ESP_HF_CLIENT_BSIR_EVT + */ + struct hf_client_bsirparam { + esp_hf_client_in_band_ring_state_t state; /*!< setting state of in-band ring tone */ + } bsir; /*!< HF callback param of ESP_HF_CLIENT_BSIR_EVT */ + + /** + * @brief ESP_HF_CLIENT_BINP_EVT + */ + struct hf_client_binp_param { + const char *number; /*!< phone number corresponding to the last voice tag in the HF */ + } binp; /*!< HF callback param of ESP_HF_CLIENT_BINP_EVT */ + +} esp_hf_client_cb_param_t; + +/** + * @brief HFP client incoming data callback function, the callback is useful in case of + * Voice Over HCI. + * @param[in] buf : pointer to incoming data(payload of HCI synchronous data packet), the + * buffer is allocated inside bluetooth protocol stack and will be released after + * invoke of the callback is finished. + * @param[in] len : size(in bytes) in buf + */ +typedef void (* esp_hf_client_incoming_data_cb_t)(const uint8_t *buf, uint32_t len); + +/** + * @brief HFP client outgoing data callback function, the callback is useful in case of + * Voice Over HCI. Once audio connection is set up and the application layer has + * prepared data to send, the lower layer will call this function to read data + * and then send. This callback is supposed to be implemented as non-blocking, + * and if data is not enough, return value 0 is supposed. + * + * @param[in] buf : pointer to incoming data(payload of HCI synchronous data packet), the + * buffer is allocated inside bluetooth protocol stack and will be released after + * invoke of the callback is finished. + * @param[in] len : size(in bytes) in buf + * @param[out] length of data successfully read + */ +typedef uint32_t (* esp_hf_client_outgoing_data_cb_t)(uint8_t *buf, uint32_t len); + +/** + * @brief HFP client callback function type + * + * @param event : Event type + * + * @param param : Pointer to callback parameter + */ +typedef void (* esp_hf_client_cb_t)(esp_hf_client_cb_event_t event, esp_hf_client_cb_param_t *param); + +/** + * @brief Register application callback function to HFP client module. This function should be called + * only after esp_bluedroid_enable() completes successfully, used by HFP client + * + * @param[in] callback: HFP client event callback function + * + * @return + * - ESP_OK: success + * - ESP_INVALID_STATE: if bluetooth stack is not yet enabled + * - ESP_FAIL: if callback is a NULL function pointer + * + */ +esp_err_t esp_hf_client_register_callback(esp_hf_client_cb_t callback); + +/** + * + * @brief Initialize the bluetooth HFP client module. This function should be called + * after esp_bluedroid_enable() completes successfully + * + * @return + * - ESP_OK: if the initialization request is sent successfully + * - ESP_INVALID_STATE: if bluetooth stack is not yet enabled + * - ESP_FAIL: others + * + */ +esp_err_t esp_hf_client_init(void); + +/** + * + * @brief De-initialize for HFP client module. This function + * should be called only after esp_bluedroid_enable() completes successfully + * + * @return + * - ESP_OK: success + * - ESP_INVALID_STATE: if bluetooth stack is not yet enabled + * - ESP_FAIL: others + * + */ +esp_err_t esp_hf_client_deinit(void); + +/** + * + * @brief Connect to remote bluetooth HFP audio gateway(AG) device, must after esp_a2d_hf_client_init() + * + * @param[in] remote_bda: remote bluetooth device address + * + * @return + * - ESP_OK: connect request is sent to lower layer + * - ESP_INVALID_STATE: if bluetooth stack is not yet enabled + * - ESP_FAIL: others + * + */ +esp_err_t esp_hf_client_connect(esp_bd_addr_t remote_bda); + +/** + * + * @brief Disconnect from the remote HFP audio gateway + * + * @param[in] remote_bda: remote bluetooth device address + * @return + * - ESP_OK: disconnect request is sent to lower layer + * - ESP_INVALID_STATE: if bluetooth stack is not yet enabled + * - ESP_FAIL: others + * + */ +esp_err_t esp_hf_client_disconnect(esp_bd_addr_t remote_bda); + +/** + * + * @brief Create audio connection with remote HFP AG. As a precondition to use this API, + * Service Level Connection shall exist with AG + * + * @param[in] remote_bda: remote bluetooth device address + * @return + * - ESP_OK: disconnect request is sent to lower layer + * - ESP_INVALID_STATE: if bluetooth stack is not yet enabled + * - ESP_FAIL: others + * + */ +esp_err_t esp_hf_client_connect_audio(esp_bd_addr_t remote_bda); + +/** + * + * @brief Release the established audio connection with remote HFP AG. + * + * @param[in] remote_bda: remote bluetooth device address + * @return + * - ESP_OK: disconnect request is sent to lower layer + * - ESP_INVALID_STATE: if bluetooth stack is not yet enabled + * - ESP_FAIL: others + * + */ +esp_err_t esp_hf_client_disconnect_audio(esp_bd_addr_t remote_bda); + +/** + * + * @brief Enable voice recognition in the AG. As a precondition to use this API, + * Service Level Connection shall exist with AG + * + * @return + * - ESP_OK: disconnect request is sent to lower layer + * - ESP_INVALID_STATE: if bluetooth stack is not yet enabled + * - ESP_FAIL: others + * + */ +esp_err_t esp_hf_client_start_voice_recognition(void); + +/** + * + * @brief Disable voice recognition in the AG. As a precondition to use this API, + * Service Level Connection shall exist with AG + * + * @return + * - ESP_OK: disconnect request is sent to lower layer + * - ESP_INVALID_STATE: if bluetooth stack is not yet enabled + * - ESP_FAIL: others + * + */ +esp_err_t esp_hf_client_stop_voice_recognition(void); + +/** + * + * @brief Volume synchronization with AG. As a precondition to use this API, + * Service Level Connection shall exist with AG + * + * @param[in] type: volume control target, speaker or microphone + * @param[in] volume: gain of the speaker of microphone, ranges 0 to 15 + * + * @return + * - ESP_OK: disconnect request is sent to lower layer + * - ESP_INVALID_STATE: if bluetooth stack is not yet enabled + * - ESP_FAIL: others + * + */ +esp_err_t esp_hf_client_volume_update(esp_hf_volume_control_target_t type, int volume); + +/** + * + * @brief Place a call with a specified number, if number is NULL, last called number is + * called. As a precondition to use this API, Service Level Connection shall + * exist with AG + * + * @param[in] number: number string of the call. If NULL, the last number is called(aka re-dial) + * + * @return + * - ESP_OK: disconnect request is sent to lower layer + * - ESP_INVALID_STATE: if bluetooth stack is not yet enabled + * - ESP_FAIL: others + * + */ +esp_err_t esp_hf_client_dial(const char *number); + +/** + * + * @brief Place a call with number specified by location(speed dial). As a precondition, + * to use this API, Service Level Connection shall exist with AG + * + * @param[in] location: location of the number in the memory + * + * @return + * - ESP_OK: disconnect request is sent to lower layer + * - ESP_INVALID_STATE: if bluetooth stack is not yet enabled + * - ESP_FAIL: others + * + */ + +esp_err_t esp_hf_client_dial_memory(int location); + +/** + * + * @brief Send call hold and multiparty commands, or enhanced call control commands(Use AT+CHLD). + * As a precondition to use this API, Service Level Connection shall exist with AG + * + * @param[in] chld: AT+CHLD call hold and multiparty handling AT command. + * @param[in] idx: used in Enhanced Call Control Mechanisms, used if chld is + * ESP_HF_CHLD_TYPE_REL_X or ESP_HF_CHLD_TYPE_PRIV_X + * + * @return + * - ESP_OK: disconnect request is sent to lower layer + * - ESP_INVALID_STATE: if bluetooth stack is not yet enabled + * - ESP_FAIL: others + * + */ +esp_err_t esp_hf_client_send_chld_cmd(esp_hf_chld_type_t chld, int idx); + +/** + * + * @brief Send response and hold action command(Send AT+BTRH command) + * As a precondition to use this API, Service Level Connection shall exist with AG + * + * @param[in] btrh: response and hold action to send + * + * @return + * - ESP_OK: disconnect request is sent to lower layer + * - ESP_INVALID_STATE: if bluetooth stack is not yet enabled + * - ESP_FAIL: others + * + */ +esp_err_t esp_hf_client_send_btrh_cmd(esp_hf_btrh_cmd_t btrh); + +/** + * + * @brief Answer an incoming call(send ATA command). As a precondition to use this API, + * Service Level Connection shall exist with AG + * + * @return + * - ESP_OK: disconnect request is sent to lower layer + * - ESP_INVALID_STATE: if bluetooth stack is not yet enabled + * - ESP_FAIL: others + * + */ +esp_err_t esp_hf_client_answer_call(void); + +/** + * + * @brief Reject an incoming call(send AT+CHUP command), As a precondition to use this API, + * Service Level Connection shall exist with AG + * + * @return + * - ESP_OK: disconnect request is sent to lower layer + * - ESP_INVALID_STATE: if bluetooth stack is not yet enabled + * - ESP_FAIL: others + * + */ +esp_err_t esp_hf_client_reject_call(void); + +/** + * + * @brief Query list of current calls in AG(send AT+CLCC command), As a precondition to use this API, + * Service Level Connection shall exist with AG + * + * @return + * - ESP_OK: disconnect request is sent to lower layer + * - ESP_INVALID_STATE: if bluetooth stack is not yet enabled + * - ESP_FAIL: others + * + */ +esp_err_t esp_hf_client_query_current_calls(void); + +/** + * + * @brief Query the name of currently selected network operator in AG(use AT+COPS commands) + * As a precondition to use this API, Service Level Connection shall exist with AG + * + * @return + * - ESP_OK: disconnect request is sent to lower layer + * - ESP_INVALID_STATE: if bluetooth stack is not yet enabled + * - ESP_FAIL: others + * + */ +esp_err_t esp_hf_client_query_current_operator_name(void); + +/** + * + * @brief Get subscriber information number from AG(send AT+CNUM command) + * As a precondition to use this API, Service Level Connection shall exist with AG + * + * @return + * - ESP_OK: disconnect request is sent to lower layer + * - ESP_INVALID_STATE: if bluetooth stack is not yet enabled + * - ESP_FAIL: others + * + */ +esp_err_t esp_hf_client_retrieve_subscriber_info(void); + +/** + * + * @brief Transmit DTMF codes during an ongoing call(use AT+VTS commands) + * As a precondition to use this API, Service Level Connection shall exist with AG + * + * @param[in] code: dtmf code, single ascii character in the set 0-9, #, *, A-D + * + * @return + * - ESP_OK: disconnect request is sent to lower layer + * - ESP_INVALID_STATE: if bluetooth stack is not yet enabled + * - ESP_FAIL: others + * + */ +esp_err_t esp_hf_client_send_dtmf(char code); + +/** + * + * @brief Request a phone number from AG corresponding to last voice tag recorded + * (send AT+BINP command). As a precondition to use this API, Service Level + * Connection shall exist with AG + * + * @return + * - ESP_OK: disconnect request is sent to lower layer + * - ESP_INVALID_STATE: if bluetooth stack is not yet enabled + * - ESP_FAIL: others + * + */ +esp_err_t esp_hf_client_request_last_voice_tag_number(void); + +/** + * @brief Register HFP client data output function; the callback is only used in + * the case that Voice Over HCI is enabled. + * + * @param[in] recv: HFP client incoming data callback function + * @param[in] send: HFP client outgoing data callback function + * + * @return + * - ESP_OK: success + * - ESP_INVALID_STATE: if bluetooth stack is not yet enabled + * - ESP_FAIL: if callback is a NULL function pointer + * + */ +esp_err_t esp_hf_client_register_data_callback(esp_hf_client_incoming_data_cb_t recv, + esp_hf_client_outgoing_data_cb_t send); + +/** + * @brief Trigger the lower-layer to fetch and send audio data. This function is only + * only used in the case that Voice Over HCI is enabled. Precondition is that + * the HFP audio connection is connected. After this function is called, lower + * layer will invoke esp_hf_client_outgoing_data_cb_t to fetch data + * + */ +void esp_hf_client_outgoing_data_ready(void); + + +/** + * @brief Initialize the down sampling converter. This is a utility function that can + * only be used in the case that Voice Over HCI is enabled. + * + * @param[in] src_sps: original samples per second(source audio data, i.e. 48000, 32000, + * 16000, 44100, 22050, 11025) + * @param[in] bits: number of bits per pcm sample (16) + * @param[in] channels: number of channels (i.e. mono(1), stereo(2)...) + */ +void esp_hf_client_pcm_resample_init(uint32_t src_sps, uint32_t bits, uint32_t channels); + +/** + * @brief Down sampling utility to convert high sampling rate into 8K/16bits 1-channel mode PCM + * samples. This can only be used in the case that Voice Over HCI is enabled. + * + * @param[in] src: pointer to the buffer where the original smapling PCM are stored + * @param[in] in_bytes: length of the input PCM sample buffer in byte + * @param[in] dst: pointer to the buffer which is to be used to store the converted PCM samples + * + * @return number of samples converted + */ +int32_t esp_hf_client_pcm_resample(void *src, uint32_t in_bytes, void *dst); + +#ifdef __cplusplus +} +#endif + + +#endif /* __ESP_HF_CLIENT_API_H__ */ diff --git a/components/bt/bluedroid/api/include/api/esp_hf_defs.h b/components/bt/bluedroid/api/include/api/esp_hf_defs.h new file mode 100644 index 000000000..b71277932 --- /dev/null +++ b/components/bt/bluedroid/api/include/api/esp_hf_defs.h @@ -0,0 +1,181 @@ +// Copyright 2018 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef __ESP_HF_DEFS_H__ +#define __ESP_HF_DEFS_H__ + +#include "esp_bt_defs.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +/// Bluetooth HFP audio volume control target +typedef enum { + ESP_HF_VOLUME_CONTROL_TARGET_SPK = 0, /*!< speaker */ + ESP_HF_VOLUME_CONTROL_TARGET_MIC, /*!< microphone */ +} esp_hf_volume_control_target_t; + +/// +CIND roaming status indicator values +typedef enum { + ESP_HF_ROAMING_STATUS_INACTIVE = 0, /*!< roaming is not active */ + ESP_HF_ROAMING_STATUS_ACTIVE, /*!< a roaming is active */ +} esp_hf_roaming_status_t; + +/// +CIND call status indicator values +typedef enum { + ESP_HF_CALL_STATUS_NO_CALLS = 0, /*!< no call in progress */ + ESP_HF_CALL_STATUS_CALL_IN_PROGRESS = 1, /*!< call is present(active or held) */ +} esp_hf_call_status_t; + +/// +CIND call setup status indicator values +typedef enum { + ESP_HF_CALL_SETUP_STATUS_NONE = 0, /*!< no call setup in progress */ + ESP_HF_CALL_SETUP_STATUS_INCOMING = 1, /*!< incoming call setup in progress */ + ESP_HF_CALL_SETUP_STATUS_OUTGOING_DIALING = 2, /*!< outgoing call setup in dialing state */ + ESP_HF_CALL_SETUP_STATUS_OUTGOING_ALERTING = 3, /*!< outgoing call setup in alerting state */ +} esp_hf_call_setup_status_t; + +/// +CIND call held indicator values +typedef enum { + ESP_HF_CALL_HELD_STATUS_NONE = 0, /*!< no calls held */ + ESP_HF_CALL_HELD_STATUS_HELD_AND_ACTIVE = 1, /*!< both active and held call */ + ESP_HF_CALL_HELD_STATUS_HELD = 2, /*!< call on hold, no active call*/ +} esp_hf_call_held_status_t; + +/// +CIND network service availability status +typedef enum { + ESP_HF_SERVICE_AVAILABILITY_STATUS_UNAVAILABLE = 0, /*!< service not available */ + ESP_HF_SERVICE_AVAILABILITY_STATUS_AVAILABLE, /*!< service available */ +} esp_hf_service_availability_status_t; + +/// +CLCC status of the call +typedef enum { + ESP_HF_CURRENT_CALL_STATUS_ACTIVE = 0, /*!< active */ + ESP_HF_CURRENT_CALL_STATUS_HELD = 1, /*!< held */ + ESP_HF_CURRENT_CALL_STATUS_DIALING = 2, /*!< dialing (outgoing calls only) */ + ESP_HF_CURRENT_CALL_STATUS_ALERTING = 3, /*!< alerting (outgoing calls only) */ + ESP_HF_CURRENT_CALL_STATUS_INCOMING = 4, /*!< incoming (incoming calls only) */ + ESP_HF_CURRENT_CALL_STATUS_WAITING = 5, /*!< waiting (incoming calls only) */ + ESP_HF_CURRENT_CALL_STATUS_HELD_BY_RESP_HOLD = 6, /*!< call held by response and hold */ +} esp_hf_current_call_status_t; + +/// +CLCC direction of the call +typedef enum { + ESP_HF_CURRENT_CALL_DIRECTION_OUTGOING = 0, /*!< outgoing */ + ESP_HF_CURRENT_CALL_DIRECTION_INCOMING = 1, /*!< incoming */ +} esp_hf_current_call_direction_t; + +/// +CLCC multi-party call flag +typedef enum { + ESP_HF_CURRENT_CALL_MPTY_TYPE_SINGLE = 0, /*!< not a member of a multi-party call */ + ESP_HF_CURRENT_CALL_MPTY_TYPE_MULTI = 1, /*!< member of a multi-party call */ +} esp_hf_current_call_mpty_type_t; + +/// +CLCC call mode +typedef enum { + ESP_HF_CURRENT_CALL_MODE_VOICE = 0, + ESP_HF_CURRENT_CALL_MODE_DATA = 1, + ESP_HF_CURRENT_CALL_MODE_FAX = 2, +} esp_hf_current_call_mode_t; + +/// +CLCC address type +typedef enum { + ESP_HF_CALL_ADDR_TYPE_UNKNOWN = 0x81, /*!< unkown address type */ + ESP_HF_CALL_ADDR_TYPE_INTERNATIONAL = 0x91, /*!< international address */ +} esp_hf_call_addr_type_t; + +/// +CNUM service type of the phone number +typedef enum { + ESP_HF_SUBSCRIBER_SERVICE_TYPE_UNKNOWN = 0, /*!< unknown */ + ESP_HF_SUBSCRIBER_SERVICE_TYPE_VOICE, /*!< voice service */ + ESP_HF_SUBSCRIBER_SERVICE_TYPE_FAX, /*!< fax service */ +} esp_hf_subscriber_service_type_t; + +/// +BTRH response and hold result code +typedef enum { + ESP_HF_BTRH_STATUS_HELD = 0, /*!< incoming call is put on held in AG */ + ESP_HF_BTRH_STATUS_ACCEPTED, /*!< held incoming call is accepted in AG */ + ESP_HF_BTRH_STATUS_REJECTED, /*!< held incoming call is rejected in AG */ +} esp_hf_btrh_status_t; + +/// AT+BTRH response and hold action code +typedef enum { + ESP_HF_BTRH_CMD_HOLD = 0, /*!< put the incoming call on hold */ + ESP_HF_BTRH_CMD_ACCEPT = 1, /*!< accept a held incoming call */ + ESP_HF_BTRH_CMD_REJECT = 2, /*!< reject a held incoming call */ +} esp_hf_btrh_cmd_t; + +/// response indication codes for AT commands +typedef enum { + ESP_HF_AT_RESPONSE_CODE_OK = 0, /*!< acknoweledges execution of a command line */ + ESP_HF_AT_RESPONSE_CODE_ERR, /*!< command not accepted */ + ESP_HF_AT_RESPONSE_CODE_NO_CARRIER, /*!< connection terminated */ + ESP_HF_AT_RESPONSE_CODE_BUSY, /*!< busy signal detected */ + ESP_HF_AT_RESPONSE_CODE_NO_ANSWER, /*!< connection completion timeout */ + ESP_HF_AT_RESPONSE_CODE_DELAYED, /*!< delayed */ + ESP_HF_AT_RESPONSE_CODE_BLACKLISTED, /*!< blacklisted */ + ESP_HF_AT_RESPONSE_CODE_CME, /*!< CME error */ +} esp_hf_at_response_code_t; + +/// voice recognition state +typedef enum { + ESP_HF_VR_STATE_DISABLED = 0, /*!< voice recognition disabled */ + ESP_HF_VR_STATE_ENABLED, /*!< voice recognition enabled */ +} esp_hf_vr_state_t; + +/// AT+CHLD command values +typedef enum { + ESP_HF_CHLD_TYPE_REL = 0, /*!< <0>, Terminate all held or set UDUB("busy") to a waiting call */ + ESP_HF_CHLD_TYPE_REL_ACC, /*!< <1>, Terminate all active calls and accepts a waiting/held call */ + ESP_HF_CHLD_TYPE_HOLD_ACC, /*!< <2>, Hold all active calls and accepts a waiting/held call */ + ESP_HF_CHLD_TYPE_MERGE, /*!< <3>, Add all held calls to a conference */ + ESP_HF_CHLD_TYPE_MERGE_DETACH, /*!< <4>, connect the two calls and disconnects the subscriber from both calls */ + ESP_HF_CHLD_TYPE_REL_X, /*!< <1x>, releases specified calls only */ + ESP_HF_CHLD_TYPE_PRIV_X, /*!< <2x>, request private consultation mode with specified call */ +} esp_hf_chld_type_t; + +/// Extended Audio Gateway Error Result Code Response +typedef enum { + ESP_HF_CME_AG_FAILURE = 0, /*!< ag failure */ + ESP_HF_CME_NO_CONNECTION_TO_PHONE = 1, /*!< no connection to phone */ + ESP_HF_CME_OPERATION_NOT_ALLOWED = 3, /*!< operation not allowed */ + ESP_HF_CME_OPERATION_NOT_SUPPORTED = 4, /*!< operation not supported */ + ESP_HF_CME_PH_SIM_PIN_REQUIRED = 5, /*!< PH-SIM PIN Required */ + ESP_HF_CME_SIM_NOT_INSERTED = 10, /*!< SIM not inserted */ + ESP_HF_CME_SIM_PIN_REQUIRED = 11, /*!< SIM PIN required */ + ESP_HF_CME_SIM_PUK_REQUIRED = 12, /*!< SIM PUK required */ + ESP_HF_CME_SIM_FAILURE = 13, /*!< SIM failure */ + ESP_HF_CME_SIM_BUSY = 14, /*!< SIM busy */ + ESP_HF_CME_INCORRECT_PASSWORD = 16, /*!< incorrect password */ + ESP_HF_CME_SIM_PIN2_REQUIRED = 17, /*!< SIM PIN2 required */ + ESP_HF_CME_SIM_PUK2_REQUIRED = 18, /*!< SIM PUK2 required */ + ESP_HF_CME_MEMEORY_FULL = 20, /*!< memory full */ + ESP_HF_CME_INVALID_INDEX = 21, /*!< invalid index */ + ESP_HF_CME_MEMEORY_FAILURE = 23, /*!< memory failure */ + ESP_HF_CME_TEXT_STRING_TOO_LONG = 24, /*!< test string too long */ + ESP_HF_CME_INVALID_CHARACTERS_IN_TEXT_STRING = 25, /*!< invalid characters in text string */ + ESP_HF_CME_DIAL_STRING_TOO_LONG = 26, /*!< dial string too long*/ + ESP_HF_CME_INVALID_CHARACTERS_IN_DIAL_STRING = 27, /*!< invalid characters in dial string */ + ESP_HF_CME_NO_NETWORK_SERVICE = 30, /*!< no network service */ + ESP_HF_CME_NETWORK_TIMEOUT = 31, /*!< network timeout */ + ESP_HF_CME_NETWORK_NOT_ALLOWED = 32, /*!< network not allowed --emergency calls only */ +} esp_hf_cme_err_t; + +#ifdef __cplusplus +} +#endif + +#endif /* __ESP_HF_DEFS_H__ */ diff --git a/components/bt/bluedroid/bta/dm/bta_dm_act.c b/components/bt/bluedroid/bta/dm/bta_dm_act.c index 3985dc839..c2eff109a 100644 --- a/components/bt/bluedroid/bta/dm/bta_dm_act.c +++ b/components/bt/bluedroid/bta/dm/bta_dm_act.c @@ -396,9 +396,7 @@ static void bta_dm_sys_hw_cback( tBTA_SYS_HW_EVT status ) #endif /* hw is ready, go on with BTA DM initialization */ memset(&bta_dm_search_cb, 0x00, sizeof(bta_dm_search_cb)); -#if (BTM_SSR_INCLUDED == TRUE) memset(&bta_dm_conn_srvcs, 0x00, sizeof(bta_dm_conn_srvcs)); -#endif ///BTM_SSR_INCLUDED == TRUE memset(&bta_dm_di_cb, 0, sizeof(tBTA_DM_DI_CB)); memcpy(dev_class, p_bta_dm_cfg->dev_class, sizeof(dev_class)); @@ -443,10 +441,12 @@ static void bta_dm_sys_hw_cback( tBTA_SYS_HW_EVT status ) BTM_ReadLocalDeviceNameFromController((tBTM_CMPL_CB *)bta_dm_local_name_cback); bta_sys_rm_register((tBTA_SYS_CONN_CBACK *)bta_dm_rm_cback); -#if (BTM_SSR_INCLUDED == TRUE) + +#if (BTA_DM_PM_INCLUDED == TRUE) /* initialize bluetooth low power manager */ bta_dm_init_pm(); -#endif ///BTM_SSR_INCLUDED == TRUE +#endif /* #if (BTA_DM_PM_INCLUDED == TRUE) */ + bta_sys_policy_register((tBTA_SYS_CONN_CBACK *)bta_dm_policy_cback); #if (BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE && SDP_INCLUDED == TRUE) && (GATTC_INCLUDED == TRUE) @@ -483,9 +483,11 @@ void bta_dm_disable (tBTA_DM_MSG *p_data) BTM_SetDiscoverability(BTM_NON_DISCOVERABLE, 0, 0); BTM_SetConnectability(BTM_NON_CONNECTABLE, 0, 0); -#if (BTM_SSR_INCLUDED == TRUE) + +#if (BTA_DM_PM_INCLUDED == TRUE) bta_dm_disable_pm(); -#endif ///BTM_SSR_INCLUDED == TRUE +#endif /* #if (BTA_DM_PM_INCLUDED == TRUE) */ + bta_dm_disable_search_and_disc(); bta_dm_cb.disabling = TRUE; @@ -1070,12 +1072,12 @@ static void bta_dm_policy_cback(tBTA_SYS_CONN_STATUS status, UINT8 id, UINT8 app p_dev->link_policy &= (~policy); BTM_SetLinkPolicy(p_dev->peer_bdaddr, &(p_dev->link_policy)); +#if (BTA_DM_PM_INCLUDED == TRUE) if (policy & (HCI_ENABLE_SNIFF_MODE | HCI_ENABLE_PARK_MODE)) { /* if clearing sniff/park, wake the link */ -#if (BTM_SSR_INCLUDED == TRUE) bta_dm_pm_active(p_dev->peer_bdaddr); -#endif ///BTM_SSR_INCLUDED == TRUE } +#endif /* #if (BTA_DM_PM_INCLUDED == TRUE) */ break; case BTA_SYS_PLCY_DEF_SET: @@ -3365,10 +3367,12 @@ static void bta_dm_disable_conn_down_timer_cback (TIMER_LIST_ENT *p_tle) { UNUSED(p_tle); tBTA_SYS_HW_MSG *sys_enable_event; -#if (BTM_SSR_INCLUDED == TRUE) + +#if (BTA_DM_PM_INCLUDED == TRUE) /* disable the power managment module */ bta_dm_disable_pm(); -#endif ///BTM_SSR_INCLUDED == TRUE +#endif /* #if (BTA_DM_PM_INCLUDED == TRUE) */ + /* register our callback to SYS HW manager */ bta_sys_hw_register( BTA_SYS_HW_BLUETOOTH, bta_dm_sys_hw_cback ); @@ -3431,9 +3435,7 @@ static void bta_dm_rm_cback(tBTA_SYS_CONN_STATUS status, UINT8 id, UINT8 app_id, } /* AV calls bta_sys_conn_open with the A2DP stream count as app_id */ if (BTA_ID_AV == id) { -#if (BTM_SSR_INCLUDED == TRUE) bta_dm_cb.cur_av_count = bta_dm_get_av_count(); -#endif ///BTM_SSR_INCLUDED == TRUE } } else if ( status == BTA_SYS_CONN_IDLE) { if (p_dev) { @@ -3442,9 +3444,7 @@ static void bta_dm_rm_cback(tBTA_SYS_CONN_STATUS status, UINT8 id, UINT8 app_id, /* get cur_av_count from connected services */ if (BTA_ID_AV == id) { -#if (BTM_SSR_INCLUDED == TRUE) bta_dm_cb.cur_av_count = bta_dm_get_av_count(); -#endif ///BTM_SSR_INCLUDED == TRUE } } APPL_TRACE_EVENT("bta_dm_rm_cback:%d, status:%d", bta_dm_cb.cur_av_count, status); diff --git a/components/bt/bluedroid/bta/dm/bta_dm_cfg.c b/components/bt/bluedroid/bta/dm/bta_dm_cfg.c index 2e22aa77c..c29960ab6 100644 --- a/components/bt/bluedroid/bta/dm/bta_dm_cfg.c +++ b/components/bt/bluedroid/bta/dm/bta_dm_cfg.c @@ -116,39 +116,24 @@ tBTA_DM_CFG *p_bta_dm_cfg = (tBTA_DM_CFG *) &bta_dm_cfg; tBTA_DM_RM *p_bta_dm_rm_cfg = (tBTA_DM_RM *) &bta_dm_rm_cfg; #if BLE_INCLUDED == TRUE -# define BTA_DM_NUM_PM_ENTRY 21 /* number of entries in bta_dm_pm_cfg except the first */ -# define BTA_DM_NUM_PM_SPEC 15 /* number of entries in bta_dm_pm_spec */ +# define BTA_DM_NUM_PM_ENTRY 6 /* number of entries in bta_dm_pm_cfg except the first */ +# define BTA_DM_NUM_PM_SPEC 6 /* number of entries in bta_dm_pm_spec */ #else -# define BTA_DM_NUM_PM_ENTRY 19 /* number of entries in bta_dm_pm_cfg except the first */ -# define BTA_DM_NUM_PM_SPEC 13 /* number of entries in bta_dm_pm_spec */ +# define BTA_DM_NUM_PM_ENTRY 4 /* number of entries in bta_dm_pm_cfg except the first */ +# define BTA_DM_NUM_PM_SPEC 4 /* number of entries in bta_dm_pm_spec */ #endif +#if (BTA_DM_PM_INCLUDED == TRUE) + tBTA_DM_PM_TYPE_QUALIFIER tBTA_DM_PM_CFG bta_dm_pm_cfg[BTA_DM_NUM_PM_ENTRY + 1] = { {BTA_ID_SYS, BTA_DM_NUM_PM_ENTRY, 0}, /* reserved: specifies length of this table. */ {BTA_ID_AG, BTA_ALL_APP_ID, 0}, /* ag uses first spec table for app id 0 */ - {BTA_ID_CT, 1, 1}, /* ct (BTA_ID_CT,APP ID=1) spec table */ - {BTA_ID_CG, BTA_ALL_APP_ID, 1}, /* cg resue ct spec table */ - {BTA_ID_DG, BTA_ALL_APP_ID, 2}, /* dg spec table */ - {BTA_ID_AV, BTA_ALL_APP_ID, 4}, /* av spec table */ - {BTA_ID_AVK, BTA_ALL_APP_ID, 12}, /* avk spec table */ - {BTA_ID_FTC, BTA_ALL_APP_ID, 6}, /* ftc spec table */ - {BTA_ID_FTS, BTA_ALL_APP_ID, 7}, /* fts spec table */ - {BTA_ID_HD, BTA_ALL_APP_ID, 3}, /* hd spec table */ - {BTA_ID_HH, BTA_ALL_APP_ID, 5}, /* hh spec table */ - {BTA_ID_PBC, BTA_ALL_APP_ID, 2}, /* reuse dg spec table */ - {BTA_ID_PBS, BTA_ALL_APP_ID, 7}, /* reuse fts spec table */ - {BTA_ID_OPC, BTA_ALL_APP_ID, 6}, /* reuse ftc spec table */ - {BTA_ID_OPS, BTA_ALL_APP_ID, 7}, /* reuse fts spec table */ - {BTA_ID_MSE, BTA_ALL_APP_ID, 7}, /* reuse fts spec table */ - // {BTA_ID_JV, BTA_JV_PM_ID_1, 6}, /* app BTA_JV_PM_ID_1, reuse ftc spec table */ - // {BTA_ID_JV, BTA_ALL_APP_ID, 7}, /* reuse fts spec table */ - {BTA_ID_HL, BTA_ALL_APP_ID, 8}, /* reuse fts spec table */ - {BTA_ID_PAN, BTUI_PAN_ID_PANU, 9}, /* PANU spec table */ - {BTA_ID_PAN, BTUI_PAN_ID_NAP, 10}, /* NAP spec table */ - {BTA_ID_HS, BTA_ALL_APP_ID, 11} /* HS spec table */ + {BTA_ID_AV, BTA_ALL_APP_ID, 1}, /* av spec table */ + {BTA_ID_HS, BTA_ALL_APP_ID, 2}, /* HS spec table */ + {BTA_ID_AVK, BTA_ALL_APP_ID, 3} /* avk spec table */ #if BLE_INCLUDED == TRUE - , {BTA_ID_GATTC, BTA_ALL_APP_ID, 13} /* gattc spec table */ - , {BTA_ID_GATTS, BTA_ALL_APP_ID, 14} /* gatts spec table */ + , {BTA_ID_GATTC, BTA_ALL_APP_ID, 4} /* gattc spec table */ + , {BTA_ID_GATTS, BTA_ALL_APP_ID, 5} /* gatts spec table */ #endif }; @@ -173,64 +158,7 @@ tBTA_DM_PM_TYPE_QUALIFIER tBTA_DM_PM_SPEC bta_dm_pm_spec[BTA_DM_NUM_PM_SPEC] = { } }, - /* CT, CG : 1 */ - { - (BTA_DM_PM_SNIFF | BTA_DM_PM_PARK), /* allow park & sniff */ -#if (BTM_SSR_INCLUDED == TRUE) - (BTA_DM_PM_SSR2), /* the SSR entry */ -#endif - { - {{BTA_DM_PM_PARK, 5000 + BTA_DM_PM_SPEC_TO_OFFSET}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn open park */ - {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn close */ - {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app open */ - {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */ - {{BTA_DM_PM_SNIFF_A2DP_IDX, 5000 + BTA_DM_PM_SPEC_TO_OFFSET}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco open sniff */ - {{BTA_DM_PM_PARK, 5000 + BTA_DM_PM_SPEC_TO_OFFSET}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco close park */ - {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */ - {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */ - {{BTA_DM_PM_RETRY, 5000 + BTA_DM_PM_SPEC_TO_OFFSET}, {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */ - } - }, - - /* DG, PBC : 2 */ - { - (BTA_DM_PM_ACTIVE), /* no power saving mode allowed */ -#if (BTM_SSR_INCLUDED == TRUE) - (BTA_DM_PM_SSR2), /* the SSR entry */ -#endif - { - {{BTA_DM_PM_SNIFF, 5000 + BTA_DM_PM_SPEC_TO_OFFSET}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn open active */ - {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn close */ - {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app open */ - {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */ - {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco open */ - {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco close */ - {{BTA_DM_PM_SNIFF, 1000 + BTA_DM_PM_SPEC_TO_OFFSET}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */ - {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */ - {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */ - } - }, - - /* HD : 3 */ - { - (BTA_DM_PM_SNIFF | BTA_DM_PM_PARK), /* allow park & sniff */ -#if (BTM_SSR_INCLUDED == TRUE) - (BTA_DM_PM_SSR3), /* the SSR entry */ -#endif - { - {{BTA_DM_PM_SNIFF_HD_ACTIVE_IDX, 5000 + BTA_DM_PM_SPEC_TO_OFFSET}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn open sniff */ - {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn close */ - {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app open */ - {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */ - {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco open */ - {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco close */ - {{BTA_DM_PM_SNIFF_HD_IDLE_IDX, 5000 + BTA_DM_PM_SPEC_TO_OFFSET}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */ - {{BTA_DM_PM_SNIFF_HD_ACTIVE_IDX, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */ - {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */ - } - }, - - /* AV : 4 */ + /* AV : 1 */ { (BTA_DM_PM_SNIFF), /* allow sniff */ #if (BTM_SSR_INCLUDED == TRUE) @@ -249,122 +177,7 @@ tBTA_DM_PM_TYPE_QUALIFIER tBTA_DM_PM_SPEC bta_dm_pm_spec[BTA_DM_NUM_PM_SPEC] = { } }, - /* HH : 5 */ - { - (BTA_DM_PM_SNIFF | BTA_DM_PM_PARK), /* allow park & sniff */ -#if (BTM_SSR_INCLUDED == TRUE) - (BTA_DM_PM_SSR1), /* the SSR entry */ -#endif - { - {{BTA_DM_PM_SNIFF_HH_OPEN_IDX, BTA_DM_PM_HH_OPEN_DELAY + BTA_DM_PM_SPEC_TO_OFFSET}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn open sniff */ - {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn close */ - {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app open */ - {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */ - {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco open */ - {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco close, used for HH suspend */ - {{BTA_DM_PM_SNIFF_HH_IDLE_IDX, BTA_DM_PM_HH_IDLE_DELAY + BTA_DM_PM_SPEC_TO_OFFSET}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */ - {{BTA_DM_PM_SNIFF_HH_ACTIVE_IDX, BTA_DM_PM_HH_ACTIVE_DELAY + BTA_DM_PM_SPEC_TO_OFFSET}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */ - {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */ - } - }, - - /* FTC, OPC, JV : 6 */ - { - (BTA_DM_PM_SNIFF), /* allow sniff */ -#if (BTM_SSR_INCLUDED == TRUE) - (BTA_DM_PM_SSR2), /* the SSR entry */ -#endif - { - {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn open active */ - {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn close */ - {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app open */ - {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */ - {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco open */ - {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco close */ - {{BTA_DM_PM_SNIFF_A2DP_IDX, 5000 + BTA_DM_PM_SPEC_TO_OFFSET}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */ - {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */ - {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */ - } - }, - - /* FTS, PBS, OPS, MSE, BTA_JV_PM_ID_1 : 7 */ - { - (BTA_DM_PM_SNIFF), /* allow sniff */ -#if (BTM_SSR_INCLUDED == TRUE) - (BTA_DM_PM_SSR2), /* the SSR entry */ -#endif - { - {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn open active */ - {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn close */ - {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app open */ - {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */ - {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco open */ - {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco close */ - {{BTA_DM_PM_SNIFF_A2DP_IDX, BTA_FTS_OPS_IDLE_TO_SNIFF_DELAY_MS + BTA_DM_PM_SPEC_TO_OFFSET}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */ - {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */ - {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */ - } - }, - - /* HL : 8 */ - { - (BTA_DM_PM_SNIFF), /* allow sniff */ -#if (BTM_SSR_INCLUDED == TRUE) - (BTA_DM_PM_SSR2), /* the SSR entry */ -#endif - { - {{BTA_DM_PM_SNIFF_A2DP_IDX, 5000 + BTA_DM_PM_SPEC_TO_OFFSET}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn open sniff */ - {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn close */ - {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app open */ - {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */ - {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco open, active */ - {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco close sniff */ - {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */ - {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */ - {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */ - } - }, - - /* PANU : 9 */ - { - (BTA_DM_PM_SNIFF), /* allow sniff */ -#if (BTM_SSR_INCLUDED == TRUE) - (BTA_DM_PM_SSR2), /* the SSR entry */ -#endif - { - {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn open active */ - {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn close */ - {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app open */ - {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */ - {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco open */ - {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco close */ - {{BTA_DM_PM_SNIFF_A2DP_IDX, 5000 + BTA_DM_PM_SPEC_TO_OFFSET}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */ - {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */ - {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */ - } - }, - - /* NAP : 10 */ - { - (BTA_DM_PM_SNIFF), /* allow sniff */ -#if (BTM_SSR_INCLUDED == TRUE) - (BTA_DM_PM_SSR2), /* the SSR entry */ -#endif - { - {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn open active */ - {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn close */ - {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app open */ - {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */ - {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco open */ - {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco close */ - {{BTA_DM_PM_SNIFF_A2DP_IDX, 5000 + BTA_DM_PM_SPEC_TO_OFFSET}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */ - {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */ - - {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */ - } - }, - - /* HS : 11 */ + /* HS : 2 */ { (BTA_DM_PM_SNIFF | BTA_DM_PM_PARK), /* allow park & sniff */ #if (BTM_SSR_INCLUDED == TRUE) @@ -383,7 +196,7 @@ tBTA_DM_PM_TYPE_QUALIFIER tBTA_DM_PM_SPEC bta_dm_pm_spec[BTA_DM_NUM_PM_SPEC] = { } }, - /* AVK : 12 */ + /* AVK : 3 */ { (BTA_DM_PM_SNIFF), /* allow sniff */ #if (BTM_SSR_INCLUDED == TRUE) @@ -403,7 +216,7 @@ tBTA_DM_PM_TYPE_QUALIFIER tBTA_DM_PM_SPEC bta_dm_pm_spec[BTA_DM_NUM_PM_SPEC] = { } #if BLE_INCLUDED == TRUE - /* GATTC : 13 */ + /* GATTC : 4 */ , { (BTA_DM_PM_SNIFF | BTA_DM_PM_PARK), /* allow park & sniff */ #if (BTM_SSR_INCLUDED == TRUE) @@ -424,7 +237,7 @@ tBTA_DM_PM_TYPE_QUALIFIER tBTA_DM_PM_SPEC bta_dm_pm_spec[BTA_DM_NUM_PM_SPEC] = { {{BTA_DM_PM_RETRY, 5000 + BTA_DM_PM_SPEC_TO_OFFSET}, {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */ } } - /* GATTS : 14 */ + /* GATTS : 5 */ , { (BTA_DM_PM_SNIFF | BTA_DM_PM_PARK), /* allow park & sniff */ #if (BTM_SSR_INCLUDED == TRUE) @@ -528,6 +341,8 @@ tBTA_DM_PM_CFG *p_bta_dm_pm_cfg = (tBTA_DM_PM_CFG *) &bta_dm_pm_cfg; tBTA_DM_PM_SPEC *p_bta_dm_pm_spec = (tBTA_DM_PM_SPEC *) &bta_dm_pm_spec; tBTM_PM_PWR_MD *p_bta_dm_pm_md = (tBTM_PM_PWR_MD *) &bta_dm_pm_md; +#endif /* #if (BTA_DM_PM_INCLUDED == TRUE) */ + /* The performance impact of EIR packet size ** ** When BTM_EIR_DEFAULT_FEC_REQUIRED is TRUE, diff --git a/components/bt/bluedroid/bta/dm/bta_dm_ci.c b/components/bt/bluedroid/bta/dm/bta_dm_ci.c index e7385013c..f10787ad0 100644 --- a/components/bt/bluedroid/bta/dm/bta_dm_ci.c +++ b/components/bt/bluedroid/bta/dm/bta_dm_ci.c @@ -83,32 +83,3 @@ void bta_dm_ci_rmt_oob(BOOLEAN accept, BD_ADDR bd_addr, BT_OCTET16 c, BT_OCTET16 } } #endif /* BTM_OOB_INCLUDED */ - -#if (BTM_SCO_HCI_INCLUDED == TRUE) -/******************************************************************************* -** -** Function bta_dm_sco_ci_data_ready -** -** Description This function sends an event to indicating that the phone -** has SCO data ready. -** -** Parameters event: is obtained from bta_dm_sco_co_open() function, which -** is the BTA event we want to send back to BTA module -** when there is encoded data ready. -** sco_handle: is the BTA sco handle which indicate a specific -** SCO connection. -** Returns void -** -*******************************************************************************/ -void bta_dm_sco_ci_data_ready(UINT16 event, UINT16 sco_handle) -{ - BT_HDR *p_buf; - - if ((p_buf = (BT_HDR *) osi_malloc(sizeof(BT_HDR))) != NULL) { - p_buf->event = event; - p_buf->layer_specific = sco_handle; - - bta_sys_sendmsg(p_buf); - } -} -#endif diff --git a/components/bt/bluedroid/bta/dm/bta_dm_co.c b/components/bt/bluedroid/bta/dm/bta_dm_co.c index 9b0b89b3a..dbfabc3b7 100644 --- a/components/bt/bluedroid/bta/dm/bta_dm_co.c +++ b/components/bt/bluedroid/bta/dm/bta_dm_co.c @@ -205,149 +205,6 @@ void bta_dm_co_rmt_oob(BD_ADDR bd_addr) // REMOVE FOR BLUEDROID ? -#if (BTM_SCO_HCI_INCLUDED == TRUE ) && (BTM_SCO_INCLUDED == TRUE) -#if (defined(BTIF_INCLUDED) && BTIF_INCLUDED == TRUE) -/******************************************************************************* -** -** Function btui_sco_codec_callback -** -** Description Callback for btui codec. -** -** -** Returns void -** -*******************************************************************************/ -static void btui_sco_codec_callback(UINT16 event, UINT16 sco_handle) -{ - bta_dm_sco_ci_data_ready(event, sco_handle); -} -/******************************************************************************* -** -** Function bta_dm_sco_co_init -** -** Description This function can be used by the phone to initialize audio -** codec or for other initialization purposes before SCO connection -** is opened. -** -** -** Returns tBTA_DM_SCO_ROUTE_TYPE: SCO routing configuration type. -** -*******************************************************************************/ -tBTA_DM_SCO_ROUTE_TYPE bta_dm_sco_co_init(UINT32 rx_bw, UINT32 tx_bw, - tBTA_CODEC_INFO *p_codec_type, UINT8 app_id) -{ - tBTM_SCO_ROUTE_TYPE route = BTA_DM_SCO_ROUTE_PCM; - - BTIF_TRACE_DEBUG("bta_dm_sco_co_init"); - - /* set up SCO routing configuration if SCO over HCI app ID is used and run time - configuration is set to SCO over HCI */ - /* HS invoke this call-out */ - if ( -#if (BTA_HS_INCLUDED == TRUE ) && (BTA_HS_INCLUDED == TRUE) - (app_id == BTUI_DM_SCO_4_HS_APP_ID && btui_cfg.hs_sco_over_hci) || -#endif - /* AG invoke this call-out */ - (app_id != BTUI_DM_SCO_4_HS_APP_ID && btui_cfg.ag_sco_over_hci )) { - route = btui_cb.sco_hci = BTA_DM_SCO_ROUTE_HCI; - } - /* no codec is is used for the SCO data */ - if (p_codec_type->codec_type == BTA_SCO_CODEC_PCM && route == BTA_DM_SCO_ROUTE_HCI) { - /* initialize SCO codec */ - if (!btui_sco_codec_init(rx_bw, tx_bw)) { - BTIF_TRACE_ERROR("codec initialization exception!"); - } - } - - return route; -} - - - -/******************************************************************************* -** -** Function bta_dm_sco_co_open -** -** Description This function is executed when a SCO connection is open. -** -** -** Returns void -** -*******************************************************************************/ -void bta_dm_sco_co_open(UINT16 handle, UINT8 pkt_size, UINT16 event) -{ - tBTUI_SCO_CODEC_CFG cfg; - - if (btui_cb.sco_hci) { - BTIF_TRACE_DEBUG("bta_dm_sco_co_open handle:%d pkt_size:%d", handle, pkt_size); - /* use dedicated SCO buffer pool for SCO TX data */ - cfg.pool_id = HCI_SCO_POOL_ID; - cfg.p_cback = btui_sco_codec_callback; - cfg.pkt_size = pkt_size; - cfg.cb_event = event; - /* open and start the codec */ - btui_sco_codec_open(&cfg); - btui_sco_codec_start(handle); - } -} - -/******************************************************************************* -** -** Function bta_dm_sco_co_close -** -** Description This function is called when a SCO connection is closed -** -** -** Returns void -** -*******************************************************************************/ -void bta_dm_sco_co_close(void) -{ - if (btui_cb.sco_hci) { - BTIF_TRACE_DEBUG("bta_dm_sco_co_close close codec"); - /* close sco codec */ - btui_sco_codec_close(); - - btui_cb.sco_hci = FALSE; - } -} - -/******************************************************************************* -** -** Function bta_dm_sco_co_in_data -** -** Description This function is called to send incoming SCO data to application. -** -** Returns void -** -*******************************************************************************/ -void bta_dm_sco_co_in_data(BT_HDR *p_buf) -{ - if (btui_cfg.sco_use_mic) { - btui_sco_codec_inqdata (p_buf); - } else { - osi_free(p_buf); - } -} - -/******************************************************************************* -** -** Function bta_dm_sco_co_out_data -** -** Description This function is called to send SCO data over HCI. -** -** Returns void -** -*******************************************************************************/ -void bta_dm_sco_co_out_data(BT_HDR **p_buf) -{ - btui_sco_codec_readbuf(p_buf); -} - -#endif /* #if (defined(BTIF_INCLUDED) && BTIF_INCLUDED == TRUE) */ -#endif /* #if (BTM_SCO_HCI_INCLUDED == TRUE ) && (BTM_SCO_INCLUDED == TRUE)*/ - - #if (defined BLE_INCLUDED && BLE_INCLUDED == TRUE) /******************************************************************************* ** diff --git a/components/bt/bluedroid/bta/dm/bta_dm_main.c b/components/bt/bluedroid/bta/dm/bta_dm_main.c index 75d5ad44c..25977e7a4 100644 --- a/components/bt/bluedroid/bta/dm/bta_dm_main.c +++ b/components/bt/bluedroid/bta/dm/bta_dm_main.c @@ -66,11 +66,11 @@ const tBTA_DM_ACTION bta_dm_action[BTA_DM_MAX_EVT] = { bta_dm_bond_cancel, /* 12 BTA_DM_API_BOND_CANCEL_EVT */ bta_dm_pin_reply, /* 13 BTA_DM_API_PIN_REPLY_EVT */ #endif ///SMP_INCLUDED == TRUE -#if (BTM_SSR_INCLUDED == TRUE) +#if (BTA_DM_PM_INCLUDED == TRUE) /* power manger events */ bta_dm_pm_btm_status, /* 16 BTA_DM_PM_BTM_STATUS_EVT */ bta_dm_pm_timer, /* 17 BTA_DM_PM_TIMER_EVT*/ -#endif ///BTM_SSR_INCLUDED == TRUE +#endif /* #if (BTA_DM_PM_INCLUDED == TRUE) */ /* simple pairing events */ #if (SMP_INCLUDED == TRUE) bta_dm_confirm, /* 18 BTA_DM_API_CONFIRM_EVT */ diff --git a/components/bt/bluedroid/bta/dm/bta_dm_pm.c b/components/bt/bluedroid/bta/dm/bta_dm_pm.c index a876ec36a..e0f967ba5 100644 --- a/components/bt/bluedroid/bta/dm/bta_dm_pm.c +++ b/components/bt/bluedroid/bta/dm/bta_dm_pm.c @@ -30,9 +30,11 @@ #include "bta/bta_api.h" #include "bta_dm_int.h" #include "stack/btm_api.h" +#include "osi/allocator.h" -#if (BTM_SSR_INCLUDED == TRUE) +tBTA_DM_CONNECTED_SRVCS bta_dm_conn_srvcs; +#if (BTA_DM_PM_INCLUDED == TRUE) static void bta_dm_pm_cback(tBTA_SYS_CONN_STATUS status, UINT8 id, UINT8 app_id, BD_ADDR peer_addr); static void bta_dm_pm_set_mode(BD_ADDR peer_addr, tBTA_DM_PM_ACTION pm_mode, tBTA_DM_PM_REQ pm_req); @@ -45,18 +47,15 @@ static void bta_dm_pm_hid_check(BOOLEAN bScoActive); static void bta_dm_pm_set_sniff_policy(tBTA_DM_PEER_DEVICE *p_dev, BOOLEAN bDisable); static void bta_dm_pm_stop_timer_by_index(tBTA_PM_TIMER *p_timer, UINT8 timer_idx); -#endif///BTM_SSR_INCLUDED == TRUE #if (BTM_SSR_INCLUDED == TRUE) #if (defined BTA_HH_INCLUDED && BTA_HH_INCLUDED == TRUE) #include "../hh/bta_hh_int.h" /* BTA_DM_PM_SSR1 will be dedicated for HH SSR setting entry, no other profile can use it */ #define BTA_DM_PM_SSR_HH BTA_DM_PM_SSR1 -#endif +#endif /* (defined BTA_HH_INCLUDED && BTA_HH_INCLUDED == TRUE) */ static void bta_dm_pm_ssr(BD_ADDR peer_addr); - -tBTA_DM_CONNECTED_SRVCS bta_dm_conn_srvcs; - +#endif /* (BTM_SSR_INCLUDED == TRUE) */ /******************************************************************************* ** @@ -118,27 +117,6 @@ void bta_dm_disable_pm(void) } } -/******************************************************************************* -** -** Function bta_dm_get_av_count -** -** Description Get the number of connected AV -** -** -** Returns number of av connections -** -*******************************************************************************/ -UINT8 bta_dm_get_av_count(void) -{ - UINT8 count = 0; - for (int i = 0; i < bta_dm_conn_srvcs.count; i++) { - if (bta_dm_conn_srvcs.conn_srvc[i].id == BTA_ID_AV) { - ++count; - } - } - return count; -} - /******************************************************************************* ** ** Function bta_dm_pm_stop_timer @@ -337,10 +315,10 @@ static void bta_dm_pm_cback(tBTA_SYS_CONN_STATUS status, UINT8 id, UINT8 app_id, { UINT8 i, j; - UINT8 *p = NULL; tBTA_DM_PEER_DEVICE *p_dev; #if (BTM_SSR_INCLUDED == TRUE) + UINT8 *p = NULL; int index = BTA_DM_PM_SSR0; #endif @@ -492,7 +470,6 @@ static void bta_dm_pm_cback(tBTA_SYS_CONN_STATUS status, UINT8 id, UINT8 app_id, ** Returns void ** *******************************************************************************/ - static void bta_dm_pm_set_mode(BD_ADDR peer_addr, tBTA_DM_PM_ACTION pm_request, tBTA_DM_PM_REQ pm_req ) { @@ -702,8 +679,6 @@ static BOOLEAN bta_dm_pm_sniff(tBTA_DM_PEER_DEVICE *p_peer_dev, UINT8 index) BTM_ReadPowerMode(p_peer_dev->peer_bdaddr, &mode); #if (BTM_SSR_INCLUDED == TRUE) p_rem_feat = BTM_ReadRemoteFeatures (p_peer_dev->peer_bdaddr); -#endif ///BTM_SSR_INCLUDED == TRUE -#if (BTM_SSR_INCLUDED == TRUE) APPL_TRACE_DEBUG("bta_dm_pm_sniff cur:%d, idx:%d, info:x%x", mode, index, p_peer_dev->info); if (mode != BTM_PM_MD_SNIFF || (HCI_SNIFF_SUB_RATE_SUPPORTED(BTM_ReadLocalFeatures ()) && p_rem_feat && @@ -805,6 +780,7 @@ static void bta_dm_pm_ssr(BD_ADDR peer_addr) } } #endif + /******************************************************************************* ** ** Function bta_dm_pm_active @@ -824,11 +800,8 @@ void bta_dm_pm_active(BD_ADDR peer_addr) /* switch to active mode */ pm.mode = BTM_PM_MD_ACTIVE; BTM_SetPowerMode (bta_dm_cb.pm_id, peer_addr, &pm); - - } - /******************************************************************************* ** ** Function bta_dm_pm_btm_cback @@ -901,6 +874,7 @@ static void bta_dm_pm_timer_cback(void *p_tle) } } + /******************************************************************************* ** ** Function bta_dm_pm_btm_status @@ -995,11 +969,9 @@ void bta_dm_pm_btm_status(tBTA_DM_MSG *p_data) default: break; } - - - } + /******************************************************************************* ** ** Function bta_dm_pm_timer @@ -1015,33 +987,7 @@ void bta_dm_pm_timer(tBTA_DM_MSG *p_data) APPL_TRACE_EVENT("%s", __func__); bta_dm_pm_set_mode(p_data->pm_timer.bd_addr, p_data->pm_timer.pm_request, BTA_DM_PM_EXECUTE); } -#endif ///BTM_SSR_INCLUDED == TRUE - -/******************************************************************************* -** -** Function bta_dm_find_peer_device -** -** Description Given an address, find the associated control block. -** -** Returns tBTA_DM_PEER_DEVICE -** -*******************************************************************************/ -tBTA_DM_PEER_DEVICE *bta_dm_find_peer_device(BD_ADDR peer_addr) -{ - tBTA_DM_PEER_DEVICE *p_dev = NULL; - - for (int i = 0; i < bta_dm_cb.device_list.count; i++) { - if (!bdcmp( bta_dm_cb.device_list.peer_device[i].peer_bdaddr, peer_addr)) { - p_dev = &bta_dm_cb.device_list.peer_device[i]; - break; - } - - } - return p_dev; -} - -#if (BTM_SSR_INCLUDED == TRUE) /******************************************************************************* ** ** Function bta_dm_is_sco_active @@ -1138,7 +1084,52 @@ static void bta_dm_pm_set_sniff_policy(tBTA_DM_PEER_DEVICE *p_dev, BOOLEAN bDisa BTM_SetLinkPolicy(p_dev->peer_bdaddr, &policy_setting); } -#endif ///BTM_SSR_INCLUDED == TRUE +#endif /* #if (BTA_DM_PM_INCLUDED == TRUE) */ + +/******************************************************************************* +** +** Function bta_dm_get_av_count +** +** Description Get the number of connected AV +** +** +** Returns number of av connections +** +*******************************************************************************/ +UINT8 bta_dm_get_av_count(void) +{ + UINT8 count = 0; + for (int i = 0; i < bta_dm_conn_srvcs.count; i++) { + if (bta_dm_conn_srvcs.conn_srvc[i].id == BTA_ID_AV) { + ++count; + } + } + return count; +} + +/******************************************************************************* +** +** Function bta_dm_find_peer_device +** +** Description Given an address, find the associated control block. +** +** Returns tBTA_DM_PEER_DEVICE +** +*******************************************************************************/ +tBTA_DM_PEER_DEVICE *bta_dm_find_peer_device(BD_ADDR peer_addr) +{ + tBTA_DM_PEER_DEVICE *p_dev = NULL; + + for (int i = 0; i < bta_dm_cb.device_list.count; i++) { + if (!bdcmp( bta_dm_cb.device_list.peer_device[i].peer_bdaddr, peer_addr)) { + p_dev = &bta_dm_cb.device_list.peer_device[i]; + break; + } + + } + return p_dev; +} + #if ((defined BLE_INCLUDED) && (BLE_INCLUDED == TRUE) && SDP_INCLUDED == TRUE) /******************************************************************************* @@ -1161,5 +1152,6 @@ tBTA_DM_CONTRL_STATE bta_dm_pm_obtain_controller_state(void) APPL_TRACE_DEBUG("bta_dm_pm_obtain_controller_state: %d", cur_state); return cur_state; } + #endif diff --git a/components/bt/bluedroid/bta/dm/bta_dm_sco.c b/components/bt/bluedroid/bta/dm/bta_dm_sco.c index 45d098f44..9acfa9544 100644 --- a/components/bt/bluedroid/bta/dm/bta_dm_sco.c +++ b/components/bt/bluedroid/bta/dm/bta_dm_sco.c @@ -650,6 +650,6 @@ INT32 BTA_DmPcmResample (void *p_src, UINT32 in_bytes, void *p_dst) APPL_TRACE_DEBUG("bta_pcm_resample : outsamples %d", out_sample); #endif - return (out_sample * bta_dm_pcm_cb.sample_size); + return (out_sample); } #endif diff --git a/components/bt/bluedroid/bta/dm/include/bta_dm_int.h b/components/bt/bluedroid/bta/dm/include/bta_dm_int.h index 6461bd498..d07e951f1 100644 --- a/components/bt/bluedroid/bta/dm/include/bta_dm_int.h +++ b/components/bt/bluedroid/bta/dm/include/bta_dm_int.h @@ -63,11 +63,11 @@ enum { BTA_DM_API_BOND_CANCEL_EVT, BTA_DM_API_PIN_REPLY_EVT, #endif ///SMP_INCLUDED == TRUE -#if (BTM_SSR_INCLUDED == TRUE) +#if (BTA_DM_PM_INCLUDED == TRUE) /* power manger events */ BTA_DM_PM_BTM_STATUS_EVT, BTA_DM_PM_TIMER_EVT, -#endif ///BTM_SSR_INCLUDED == TRUE +#endif /* #if (BTA_DM_PM_INCLUDED == TRUE) */ #if (SMP_INCLUDED == TRUE) /* simple pairing events */ BTA_DM_API_CONFIRM_EVT, @@ -350,6 +350,7 @@ typedef struct { #endif } tBTA_DM_ACL_CHANGE; +#if (BTA_DM_PM_INCLUDED == TRUE) /* data type for BTA_DM_PM_BTM_STATUS_EVT */ typedef struct { @@ -367,7 +368,7 @@ typedef struct { BD_ADDR bd_addr; tBTA_DM_PM_ACTION pm_request; } tBTA_DM_PM_TIMER; - +#endif /* #if (BTA_DM_PM_INCLUDED == TRUE) */ /* data type for BTA_DM_API_ADD_DEVICE_EVT */ typedef struct { @@ -757,9 +758,11 @@ typedef union { tBTA_DM_ACL_CHANGE acl_change; +#if (BTA_DM_PM_INCLUDED == TRUE) tBTA_DM_PM_BTM_STATUS pm_status; tBTA_DM_PM_TIMER pm_timer; +#endif /* #if (BTA_DM_PM_INCLUDED == TRUE) */ tBTA_DM_API_DI_DISC di_disc; @@ -889,6 +892,10 @@ typedef struct { } tBTA_DM_CONNECTED_SRVCS; +extern tBTA_DM_CONNECTED_SRVCS bta_dm_conn_srvcs; + +#if (BTA_DM_PM_INCLUDED == TRUE) + typedef struct { #define BTA_DM_PM_SNIFF_TIMER_IDX 0 #define BTA_DM_PM_PARK_TIMER_IDX 1 @@ -908,9 +915,8 @@ typedef struct { BOOLEAN in_use; } tBTA_PM_TIMER; -extern tBTA_DM_CONNECTED_SRVCS bta_dm_conn_srvcs; - #define BTA_DM_NUM_PM_TIMER 7 +#endif /* #if (BTA_DM_PM_INCLUDED == TRUE) */ /* DM control block */ typedef struct { @@ -931,10 +937,10 @@ typedef struct { UINT32 wbt_sdp_handle; /* WIDCOMM Extensions SDP record handle */ UINT8 wbt_scn; /* WIDCOMM Extensions SCN */ UINT8 num_master_only; -#if BTM_SSR_INCLUDED == TRUE +#if (BTA_DM_PM_INCLUDED == TRUE) UINT8 pm_id; tBTA_PM_TIMER pm_timer[BTA_DM_NUM_PM_TIMER]; -#endif ///BTM_SSR_INCLUDED == TRUE +#endif /* #if (BTA_DM_PM_INCLUDED == TRUE) */ UINT32 role_policy_mask; /* the bits set indicates the modules that wants to remove role switch from the default link policy */ UINT16 cur_policy; /* current default link policy */ UINT16 rs_event; /* the event waiting for role switch */ @@ -1101,12 +1107,14 @@ typedef struct { UINT8 lmp_version; } tBTA_DM_LMP_VER_INFO; +#if (BTA_DM_PM_INCLUDED == TRUE) extern tBTA_DM_PM_CFG *p_bta_dm_pm_cfg; extern tBTA_DM_PM_SPEC *p_bta_dm_pm_spec; extern tBTM_PM_PWR_MD *p_bta_dm_pm_md; #if (BTM_SSR_INCLUDED == TRUE) extern tBTA_DM_SSR_SPEC *p_bta_dm_ssr_spec; #endif +#endif /* #if (BTA_DM_PM_INCLUDED == TRUE) */ /* update dynamic BRCM Aware EIR data */ extern const tBTA_DM_EIR_CONF bta_dm_eir_cfg; @@ -1161,9 +1169,6 @@ extern void bta_dm_add_device (tBTA_DM_MSG *p_data); extern void bta_dm_remove_device (tBTA_DM_MSG *p_data); extern void bta_dm_close_acl(tBTA_DM_MSG *p_data); - -extern void bta_dm_pm_btm_status(tBTA_DM_MSG *p_data); -extern void bta_dm_pm_timer(tBTA_DM_MSG *p_data); extern void bta_dm_add_ampkey (tBTA_DM_MSG *p_data); #if BLE_INCLUDED == TRUE @@ -1223,8 +1228,13 @@ extern void bta_dm_ci_io_req_act(tBTA_DM_MSG *p_data); extern void bta_dm_ci_rmt_oob_act(tBTA_DM_MSG *p_data); #endif /* BTM_OOB_INCLUDED */ +#if (BTA_DM_PM_INCLUDED == TRUE) extern void bta_dm_init_pm(void); extern void bta_dm_disable_pm(void); +extern void bta_dm_pm_active(BD_ADDR peer_addr); +extern void bta_dm_pm_btm_status(tBTA_DM_MSG *p_data); +extern void bta_dm_pm_timer(tBTA_DM_MSG *p_data); +#endif /* #if (BTA_DM_PM_INCLUDED == TRUE) */ extern UINT8 bta_dm_get_av_count(void); extern void bta_dm_search_start (tBTA_DM_MSG *p_data); @@ -1251,9 +1261,6 @@ extern void bta_dm_search_cancel_notify (tBTA_DM_MSG *p_data); extern void bta_dm_search_cancel_transac_cmpl(tBTA_DM_MSG *p_data); extern void bta_dm_disc_rmt_name (tBTA_DM_MSG *p_data); extern tBTA_DM_PEER_DEVICE *bta_dm_find_peer_device(BD_ADDR peer_addr); - -extern void bta_dm_pm_active(BD_ADDR peer_addr); - void bta_dm_eir_update_uuid(UINT16 uuid16, BOOLEAN adding); extern void bta_dm_enable_test_mode(tBTA_DM_MSG *p_data); diff --git a/components/bt/bluedroid/bta/hf_client/bta_hf_client_act.c b/components/bt/bluedroid/bta/hf_client/bta_hf_client_act.c new file mode 100644 index 000000000..c42b5bd14 --- /dev/null +++ b/components/bt/bluedroid/bta/hf_client/bta_hf_client_act.c @@ -0,0 +1,772 @@ +/****************************************************************************** + * + * Copyright (c) 2014 The Android Open Source Project + * Copyright (C) 2003-2012 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + +/****************************************************************************** + * + * This file contains action functions for the handsfree client. + * + ******************************************************************************/ + +#include "bta/bta_api.h" +#include "bta/bta_hf_client_api.h" +#include "bta_hf_client_int.h" +#include "bta_dm_int.h" +#include "stack/l2c_api.h" +#include "stack/port_api.h" +#include "bta/bta_sys.h" +#include "bta/utl.h" +#include "common/bt_defs.h" +#include +#include "osi/allocator.h" + +#if (BTA_HF_INCLUDED == TRUE) +/***************************************************************************** +** Constants +*****************************************************************************/ + +/* maximum length of data to read from RFCOMM */ +#define BTA_HF_CLIENT_RFC_READ_MAX 512 + +/******************************************************************************* +** +** Function bta_hf_client_register +** +** Description This function initializes values of the scb and sets up +** the SDP record for the services. +** +** +** Returns void +** +*******************************************************************************/ +void bta_hf_client_register(tBTA_HF_CLIENT_DATA *p_data) +{ + tBTA_HF_CLIENT_REGISTER evt; + tBTA_UTL_COD cod; + + memset(&evt, 0, sizeof(evt)); + + /* initialize control block */ + bta_hf_client_scb_init(); + + bta_hf_client_cb.scb.serv_sec_mask = p_data->api_register.sec_mask; + bta_hf_client_cb.scb.features = p_data->api_register.features; + + /* initialize AT control block */ + bta_hf_client_at_init(); + + /* create SDP records */ + bta_hf_client_create_record(p_data); + + /* Set the Audio service class bit */ + cod.service = BTM_COD_SERVICE_AUDIO; + utl_set_device_class(&cod, BTA_UTL_SET_COD_SERVICE_CLASS); + + /* start RFCOMM server */ + bta_hf_client_start_server(); + + /* call app callback with register event */ + evt.status = BTA_HF_CLIENT_SUCCESS; + (*bta_hf_client_cb.p_cback)(BTA_HF_CLIENT_REGISTER_EVT, &evt); +} + +/******************************************************************************* +** +** Function bta_hf_client_deregister +** +** Description This function removes the sdp records, closes the RFCOMM +** servers, and deallocates the service control block. +** +** +** Returns void +** +*******************************************************************************/ +void bta_hf_client_deregister(tBTA_HF_CLIENT_DATA *p_data) +{ + bta_hf_client_cb.scb.deregister = TRUE; + + /* remove sdp record */ + bta_hf_client_del_record(p_data); + + /* remove rfcomm server */ + bta_hf_client_close_server(); + + /* disable */ + bta_hf_client_scb_disable(); +} + +/******************************************************************************* +** +** Function bta_hf_client_start_dereg +** +** Description Start a deregister event. +** +** +** Returns void +** +*******************************************************************************/ +void bta_hf_client_start_dereg(tBTA_HF_CLIENT_DATA *p_data) +{ + bta_hf_client_cb.scb.deregister = TRUE; + + /* remove sdp record */ + bta_hf_client_del_record(p_data); +} + +/******************************************************************************* +** +** Function bta_hf_client_start_close +** +** Description Start the process of closing SCO and RFCOMM connection. +** +** +** Returns void +** +*******************************************************************************/ +void bta_hf_client_start_close(tBTA_HF_CLIENT_DATA *p_data) +{ + /* Take the link out of sniff and set L2C idle time to 0 */ +#if (BTA_DM_PM_INCLUDED == TRUE) + bta_dm_pm_active(bta_hf_client_cb.scb.peer_addr); +#endif /* (BTA_DM_PM_INCLUDED == TRUE) */ + L2CA_SetIdleTimeoutByBdAddr(bta_hf_client_cb.scb.peer_addr, 0, BT_TRANSPORT_BR_EDR); + + /* if SCO is open close SCO and wait on RFCOMM close */ + if (bta_hf_client_cb.scb.sco_state == BTA_HF_CLIENT_SCO_OPEN_ST) { + bta_hf_client_cb.scb.sco_close_rfc = TRUE; + } else { + bta_hf_client_rfc_do_close(p_data); + } + + /* always do SCO shutdown to handle all SCO corner cases */ + bta_hf_client_sco_shutdown(NULL); +} + +/******************************************************************************* +** +** Function bta_hf_client_start_open +** +** Description This starts an HF Client open. +** +** +** Returns void +** +*******************************************************************************/ +void bta_hf_client_start_open(tBTA_HF_CLIENT_DATA *p_data) +{ + BD_ADDR pending_bd_addr; + + /* store parameters */ + if (p_data) { + bdcpy(bta_hf_client_cb.scb.peer_addr, p_data->api_open.bd_addr); + bta_hf_client_cb.scb.cli_sec_mask = p_data->api_open.sec_mask; + } + + /* Check if RFCOMM has any incoming connection to avoid collision. */ + if (PORT_IsOpening (pending_bd_addr)) { + /* Let the incoming connection goes through. */ + /* Issue collision for now. */ + /* We will decide what to do when we find incoming connection later.*/ + bta_hf_client_collision_cback (0, BTA_ID_HS, 0, bta_hf_client_cb.scb.peer_addr); + return; + } + + /* close server */ + bta_hf_client_close_server(); + + /* set role */ + bta_hf_client_cb.scb.role = BTA_HF_CLIENT_INT; + + /* do service search */ + bta_hf_client_do_disc(); +} + +/******************************************************************************* +** +** Function bta_hf_client_cback_open +** +** Description Send open callback event to application. +** +** +** Returns void +** +*******************************************************************************/ +static void bta_hf_client_cback_open(tBTA_HF_CLIENT_DATA *p_data, tBTA_HF_CLIENT_STATUS status) +{ + tBTA_HF_CLIENT_OPEN evt; + + memset(&evt, 0, sizeof(evt)); + + /* call app callback with open event */ + evt.status = status; + if (p_data) { + /* if p_data is provided then we need to pick the bd address from the open api structure */ + bdcpy(evt.bd_addr, p_data->api_open.bd_addr); + } else { + bdcpy(evt.bd_addr, bta_hf_client_cb.scb.peer_addr); + } + + (*bta_hf_client_cb.p_cback)(BTA_HF_CLIENT_OPEN_EVT, &evt); +} + +/******************************************************************************* +** +** Function bta_hf_client_rfc_open +** +** Description Handle RFCOMM channel open. +** +** +** Returns void +** +*******************************************************************************/ +void bta_hf_client_rfc_open(tBTA_HF_CLIENT_DATA *p_data) +{ + UNUSED(p_data); + + bta_sys_conn_open(BTA_ID_HS, 1, bta_hf_client_cb.scb.peer_addr); + + bta_hf_client_cback_open(NULL, BTA_HF_CLIENT_SUCCESS); + + /* start SLC procedure */ + bta_hf_client_slc_seq(FALSE); +} + +/******************************************************************************* +** +** Function bta_hf_client_rfc_acp_open +** +** Description Handle RFCOMM channel open when accepting connection. +** +** +** Returns void +** +*******************************************************************************/ +void bta_hf_client_rfc_acp_open(tBTA_HF_CLIENT_DATA *p_data) +{ + UINT16 lcid; + BD_ADDR dev_addr; + int status; + + /* set role */ + bta_hf_client_cb.scb.role = BTA_HF_CLIENT_ACP; + + APPL_TRACE_DEBUG ("bta_hf_client_rfc_acp_open: serv_handle = %d rfc.port_handle = %d", + bta_hf_client_cb.scb.serv_handle, p_data->rfc.port_handle); + + /* get bd addr of peer */ + if (PORT_SUCCESS != (status = PORT_CheckConnection(p_data->rfc.port_handle, dev_addr, &lcid))) { + APPL_TRACE_DEBUG ("bta_hf_client_rfc_acp_open error PORT_CheckConnection returned status %d", status); + } + + /* Collision Handling */ + if (bta_hf_client_cb.scb.colli_tmr_on) { + /* stop collision timer */ + bta_hf_client_cb.scb.colli_tmr_on = FALSE; + bta_sys_free_timer (&bta_hf_client_cb.scb.colli_timer); + + if (bdcmp (dev_addr, bta_hf_client_cb.scb.peer_addr) == 0) { + /* If incoming and outgoing device are same, nothing more to do. */ + /* Outgoing conn will be aborted because we have successful incoming conn. */ + } else { + /* Resume outgoing connection. */ + bta_hf_client_resume_open (); + } + } + + bdcpy (bta_hf_client_cb.scb.peer_addr, dev_addr); + bta_hf_client_cb.scb.conn_handle = p_data->rfc.port_handle; + + /* do service discovery to get features */ + bta_hf_client_do_disc(); + + /* continue with open processing */ + bta_hf_client_rfc_open(p_data); +} + +/******************************************************************************* +** +** Function bta_hf_client_rfc_fail +** +** Description RFCOMM connection failed. +** +** +** Returns void +** +*******************************************************************************/ +void bta_hf_client_rfc_fail(tBTA_HF_CLIENT_DATA *p_data) +{ + UNUSED(p_data); + + /* reinitialize stuff */ + bta_hf_client_cb.scb.conn_handle = 0; + bta_hf_client_cb.scb.peer_features = 0; + bta_hf_client_cb.scb.chld_features = 0; + bta_hf_client_cb.scb.role = BTA_HF_CLIENT_ACP; + bta_hf_client_cb.scb.svc_conn = FALSE; + bta_hf_client_cb.scb.send_at_reply = FALSE; + bta_hf_client_cb.scb.negotiated_codec = BTM_SCO_CODEC_CVSD; + + bta_hf_client_at_reset(); + + /* reopen server */ + bta_hf_client_start_server(); + + /* call open cback w. failure */ + bta_hf_client_cback_open(NULL, BTA_HF_CLIENT_FAIL_RFCOMM); +} + +/******************************************************************************* +** +** Function bta_hf_client_disc_fail +** +** Description This function handles a discovery failure. +** +** +** Returns void +** +*******************************************************************************/ +void bta_hf_client_disc_fail(tBTA_HF_CLIENT_DATA *p_data) +{ + UNUSED(p_data); + + /* reopen server */ + bta_hf_client_start_server(); + + /* reinitialize stuff */ + + /* call open cback w. failure */ + bta_hf_client_cback_open(NULL, BTA_HF_CLIENT_FAIL_SDP); +} + +/******************************************************************************* +** +** Function bta_hf_client_open_fail +** +** Description open connection failed. +** +** +** Returns void +** +*******************************************************************************/ +void bta_hf_client_open_fail(tBTA_HF_CLIENT_DATA *p_data) +{ + /* call open cback w. failure */ + bta_hf_client_cback_open(p_data, BTA_HF_CLIENT_FAIL_RESOURCES); +} + +/******************************************************************************* +** +** Function bta_hf_client_rfc_close +** +** Description RFCOMM connection closed. +** +** +** Returns void +** +*******************************************************************************/ +void bta_hf_client_rfc_close(tBTA_HF_CLIENT_DATA *p_data) +{ + UNUSED(p_data); + + /* reinitialize stuff */ + bta_hf_client_cb.scb.peer_features = 0; + bta_hf_client_cb.scb.chld_features = 0; + bta_hf_client_cb.scb.role = BTA_HF_CLIENT_ACP; + bta_hf_client_cb.scb.svc_conn = FALSE; + bta_hf_client_cb.scb.send_at_reply = FALSE; + bta_hf_client_cb.scb.negotiated_codec = BTM_SCO_CODEC_CVSD; + + bta_hf_client_at_reset(); + + bta_sys_conn_close(BTA_ID_HS, 1, bta_hf_client_cb.scb.peer_addr); + + /* call close cback */ + (*bta_hf_client_cb.p_cback)(BTA_HF_CLIENT_CLOSE_EVT, NULL); + + /* if not deregistering reopen server */ + if (bta_hf_client_cb.scb.deregister == FALSE) { + /* Clear peer bd_addr so instance can be reused */ + bdcpy(bta_hf_client_cb.scb.peer_addr, bd_addr_null); + + /* start server as it might got closed on open*/ + bta_hf_client_start_server(); + + bta_hf_client_cb.scb.conn_handle = 0; + + /* Make sure SCO is shutdown */ + bta_hf_client_sco_shutdown(NULL); + + bta_sys_sco_unuse(BTA_ID_HS, 1, bta_hf_client_cb.scb.peer_addr); + } + /* else close port and deallocate scb */ + else { + bta_hf_client_close_server(); + bta_hf_client_scb_disable(); + } +} + +/******************************************************************************* +** +** Function bta_hf_client_disc_int_res +** +** Description This function handles a discovery result when initiator. +** +** +** Returns void +** +*******************************************************************************/ +void bta_hf_client_disc_int_res(tBTA_HF_CLIENT_DATA *p_data) +{ + UINT16 event = BTA_HF_CLIENT_DISC_FAIL_EVT; + + APPL_TRACE_DEBUG ("bta_hf_client_disc_int_res: Status: %d", p_data->disc_result.status); + + /* if found service */ + if (p_data->disc_result.status == SDP_SUCCESS || + p_data->disc_result.status == SDP_DB_FULL) { + /* get attributes */ + if (bta_hf_client_sdp_find_attr()) { + event = BTA_HF_CLIENT_DISC_OK_EVT; + } + } + + /* free discovery db */ + bta_hf_client_free_db(p_data); + + /* send ourselves sdp ok/fail event */ + bta_hf_client_sm_execute(event, p_data); +} + +/******************************************************************************* +** +** Function bta_hf_client_disc_acp_res +** +** Description This function handles a discovery result when acceptor. +** +** +** Returns void +** +*******************************************************************************/ +void bta_hf_client_disc_acp_res(tBTA_HF_CLIENT_DATA *p_data) +{ + /* if found service */ + if (p_data->disc_result.status == SDP_SUCCESS || + p_data->disc_result.status == SDP_DB_FULL) { + /* get attributes */ + bta_hf_client_sdp_find_attr(); + } + + /* free discovery db */ + bta_hf_client_free_db(p_data); +} + +/******************************************************************************* +** +** Function bta_hf_client_rfc_data +** +** Description Read and process data from RFCOMM. +** +** +** Returns void +** +*******************************************************************************/ +void bta_hf_client_rfc_data(tBTA_HF_CLIENT_DATA *p_data) +{ + UINT16 len; + char *buf = osi_calloc(BTA_HF_CLIENT_RFC_READ_MAX); + if (buf == NULL) { + APPL_TRACE_ERROR("No mem %s", __FUNCTION__); + return; + } + + UNUSED(p_data); + + /* read data from rfcomm; if bad status, we're done */ + while (PORT_ReadData(bta_hf_client_cb.scb.conn_handle, buf, BTA_HF_CLIENT_RFC_READ_MAX, &len) == PORT_SUCCESS) { + /* if no data, we're done */ + if (len == 0) { + break; + } + + bta_hf_client_at_parse(buf, len); + + /* no more data to read, we're done */ + if (len < BTA_HF_CLIENT_RFC_READ_MAX) { + break; + } + } + osi_free(buf); +} + +/******************************************************************************* +** +** Function bta_hf_client_svc_conn_open +** +** Description Service level connection opened +** +** +** Returns void +** +*******************************************************************************/ +void bta_hf_client_svc_conn_open(tBTA_HF_CLIENT_DATA *p_data) +{ + tBTA_HF_CLIENT_CONN evt; + UNUSED(p_data); + + memset(&evt, 0, sizeof(evt)); + + if (!bta_hf_client_cb.scb.svc_conn) { + /* set state variable */ + bta_hf_client_cb.scb.svc_conn = TRUE; + + /* call callback */ + evt.peer_feat = bta_hf_client_cb.scb.peer_features; + evt.chld_feat = bta_hf_client_cb.scb.chld_features; + + (*bta_hf_client_cb.p_cback)(BTA_HF_CLIENT_CONN_EVT, &evt); + } +} + +/******************************************************************************* +** +** Function bta_hf_client_cback_ind +** +** Description Send indicator callback event to application. +** +** Returns void +** +*******************************************************************************/ +void bta_hf_client_ind(tBTA_HF_CLIENT_IND_TYPE type, UINT16 value) +{ + tBTA_HF_CLIENT_IND evt; + + memset(&evt, 0, sizeof(evt)); + + evt.type = type; + evt.value = value; + + (*bta_hf_client_cb.p_cback)(BTA_HF_CLIENT_IND_EVT, &evt); +} + +/******************************************************************************* +** +** Function bta_hf_client_evt_val +** +** Description Send event to application. +** This is a generic helper for events with common data. +** +** +** Returns void +** +*******************************************************************************/ +void bta_hf_client_evt_val(tBTA_HF_CLIENT_EVT type, UINT16 value) +{ + tBTA_HF_CLIENT_VAL evt; + + memset(&evt, 0, sizeof(evt)); + + evt.value = value; + + (*bta_hf_client_cb.p_cback)(type, &evt); +} + +/******************************************************************************* +** +** Function bta_hf_client_operator_name +** +** Description Send operator name event to application. +** +** +** Returns void +** +*******************************************************************************/ +void bta_hf_client_operator_name(char *name) +{ + tBTA_HF_CLIENT_OPERATOR_NAME *evt; + + if ((evt = osi_calloc(sizeof(tBTA_HF_CLIENT_OPERATOR_NAME))) != NULL) { + strlcpy(evt->name, name, BTA_HF_CLIENT_OPERATOR_NAME_LEN + 1); + evt->name[BTA_HF_CLIENT_OPERATOR_NAME_LEN] = '\0'; + + (*bta_hf_client_cb.p_cback)(BTA_HF_CLIENT_OPERATOR_NAME_EVT, evt); + osi_free(evt); + } else { + APPL_TRACE_ERROR("No mem: %s", __func__); + } +} + + +/******************************************************************************* +** +** Function bta_hf_client_clip +** +** Description Send CLIP event to application. +** +** +** Returns void +** +*******************************************************************************/ +void bta_hf_client_clip(char *number) +{ + tBTA_HF_CLIENT_NUMBER *evt; + + if ((evt = osi_calloc(sizeof(tBTA_HF_CLIENT_NUMBER))) != NULL) { + strlcpy(evt->number, number, BTA_HF_CLIENT_NUMBER_LEN + 1); + evt->number[BTA_HF_CLIENT_NUMBER_LEN] = '\0'; + + (*bta_hf_client_cb.p_cback)(BTA_HF_CLIENT_CLIP_EVT, evt); + osi_free(evt); + } else { + APPL_TRACE_ERROR("No mem: %s", __func__); + } +} + +/******************************************************************************* +** +** Function bta_hf_client_ccwa +** +** Description Send CLIP event to application. +** +** +** Returns void +** +*******************************************************************************/ +void bta_hf_client_ccwa(char *number) +{ + tBTA_HF_CLIENT_NUMBER *evt; + + if ((evt = osi_calloc(sizeof(tBTA_HF_CLIENT_NUMBER))) != NULL) { + strlcpy(evt->number, number, BTA_HF_CLIENT_NUMBER_LEN + 1); + evt->number[BTA_HF_CLIENT_NUMBER_LEN] = '\0'; + + + (*bta_hf_client_cb.p_cback)(BTA_HF_CLIENT_CCWA_EVT, evt); + osi_free(evt); + } else { + APPL_TRACE_ERROR("No mem: %s", __func__); + } +} + +/******************************************************************************* +** +** Function bta_hf_client_at_result +** +** Description Send AT result event to application. +** +** +** Returns void +** +*******************************************************************************/ +void bta_hf_client_at_result(tBTA_HF_CLIENT_AT_RESULT_TYPE type, UINT16 cme) +{ + tBTA_HF_CLIENT_AT_RESULT evt; + + memset(&evt, 0, sizeof(evt)); + + evt.type = type; + evt.cme = cme; + + (*bta_hf_client_cb.p_cback)(BTA_HF_CLIENT_AT_RESULT_EVT, &evt); +} + +/******************************************************************************* +** +** Function bta_hf_client_clcc +** +** Description Send clcc event to application. +** +** +** Returns void +** +*******************************************************************************/ +void bta_hf_client_clcc(UINT32 idx, BOOLEAN incoming, UINT8 status, BOOLEAN mpty, char *number) +{ + tBTA_HF_CLIENT_CLCC *evt; + + if ((evt = osi_calloc(sizeof(tBTA_HF_CLIENT_CLCC))) != NULL) { + evt->idx = idx; + evt->inc = incoming; + evt->status = status; + evt->mpty = mpty; + + if (number) { + evt->number_present = TRUE; + strlcpy(evt->number, number, BTA_HF_CLIENT_NUMBER_LEN + 1); + evt->number[BTA_HF_CLIENT_NUMBER_LEN] = '\0'; + } + + (*bta_hf_client_cb.p_cback)(BTA_HF_CLIENT_CLCC_EVT, evt); + osi_free(evt); + } else { + APPL_TRACE_ERROR("No mem, %s\n", __func__); + } +} + +/******************************************************************************* +** +** Function bta_hf_client_cnum +** +** Description Send cnum event to application. +** +** +** Returns void +** +*******************************************************************************/ +void bta_hf_client_cnum(char *number, UINT16 service) +{ + tBTA_HF_CLIENT_CNUM *evt; + + if ((evt = osi_calloc(sizeof(tBTA_HF_CLIENT_CNUM))) != NULL) { + + evt->service = service; + strlcpy(evt->number, number, BTA_HF_CLIENT_NUMBER_LEN + 1); + evt->number[BTA_HF_CLIENT_NUMBER_LEN] = '\0'; + + (*bta_hf_client_cb.p_cback)(BTA_HF_CLIENT_CNUM_EVT, evt); + osi_free(evt); + } else { + APPL_TRACE_ERROR("No mem, %s", __func__); + } +} + +/******************************************************************************* +** +** Function bta_hf_client_binp +** +** Description Send BINP event to application. +** +** +** Returns void +** +*******************************************************************************/ +void bta_hf_client_binp(char *number) +{ + tBTA_HF_CLIENT_NUMBER *evt; + + if ((evt = osi_calloc(sizeof(tBTA_HF_CLIENT_NUMBER))) != NULL) { + strlcpy(evt->number, number, BTA_HF_CLIENT_NUMBER_LEN + 1); + evt->number[BTA_HF_CLIENT_NUMBER_LEN] = '\0'; + + (*bta_hf_client_cb.p_cback)(BTA_HF_CLIENT_BINP_EVT, evt); + osi_free(evt); + } else { + APPL_TRACE_ERROR("No mem: %s", __func__); + } +} + +#endif /* #if (BTA_HF_INCLUDED == TRUE) */ diff --git a/components/bt/bluedroid/bta/hf_client/bta_hf_client_api.c b/components/bt/bluedroid/bta/hf_client/bta_hf_client_api.c new file mode 100644 index 000000000..434b2b520 --- /dev/null +++ b/components/bt/bluedroid/bta/hf_client/bta_hf_client_api.c @@ -0,0 +1,312 @@ +/****************************************************************************** + * + * Copyright (c) 2014 The Android Open Source Project + * Copyright (C) 2003-2012 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + +/****************************************************************************** + * + * This is the implementation of the API for the handsfree (HF role) + * subsystem of BTA + * + ******************************************************************************/ + +#include +#include "bta/bta_hf_client_api.h" +#include "bta_hf_client_int.h" +#include "osi/allocator.h" + +#if (BTA_HF_INCLUDED == TRUE) +/***************************************************************************** +** Constants and data types +*****************************************************************************/ +static const tBTA_SYS_REG bta_hf_client_reg = { + bta_hf_client_hdl_event, + BTA_HfClientDisable +}; + +static const uint8_t bta_hf_client_cb_data_size[] = { + 0, // #define BTA_HF_CLIENT_ENABLE_EVT 0 + sizeof(tBTA_HF_CLIENT_REGISTER), // #define BTA_HF_CLIENT_REGISTER_EVT 1 + sizeof(tBTA_HF_CLIENT_OPEN), // #define BTA_HF_CLIENT_OPEN_EVT 2 + 0, // #define BTA_HF_CLIENT_CLOSE_EVT 3 + sizeof(tBTA_HF_CLIENT_CONN), // #define BTA_HF_CLIENT_CONN_EVT 4 + sizeof(tBTA_HF_CLIENT_HDR), // #define BTA_HF_CLIENT_AUDIO_OPEN_EVT 5 + sizeof(tBTA_HF_CLIENT_HDR), //#define BTA_HF_CLIENT_AUDIO_MSBC_OPEN_EVT 6 + sizeof(tBTA_HF_CLIENT_HDR), // #define BTA_HF_CLIENT_AUDIO_CLOSE_EVT 7 + sizeof(tBTA_HF_CLIENT_VAL), // #define BTA_HF_CLIENT_SPK_EVT 8 + sizeof(tBTA_HF_CLIENT_VAL), // #define BTA_HF_CLIENT_MIC_EVT 9 + sizeof(tBTA_HF_CLIENT_IND), //#define BTA_HF_CLIENT_IND_EVT 10 + sizeof(tBTA_HF_CLIENT_VAL), // #define BTA_HF_CLIENT_VOICE_REC_EVT 11 + sizeof(tBTA_HF_CLIENT_OPERATOR_NAME), // #define BTA_HF_CLIENT_OPERATOR_NAME_EVT 12 + sizeof(tBTA_HF_CLIENT_NUMBER), // #define BTA_HF_CLIENT_CLIP_EVT 13 + sizeof(tBTA_HF_CLIENT_NUMBER), // #define BTA_HF_CLIENT_CCWA_EVT 14 + sizeof(tBTA_HF_CLIENT_AT_RESULT), // #define BTA_HF_CLIENT_AT_RESULT_EVT 15 + sizeof(tBTA_HF_CLIENT_CLCC), // #define BTA_HF_CLIENT_CLCC_EVT 16 + sizeof(tBTA_HF_CLIENT_CNUM), //#define BTA_HF_CLIENT_CNUM_EVT 17 + sizeof(tBTA_HF_CLIENT_VAL), // #define BTA_HF_CLIENT_BTRH_EVT 18 + sizeof(tBTA_HF_CLIENT_VAL), // #define BTA_HF_CLIENT_BSIR_EVT 19 + sizeof(tBTA_HF_CLIENT_NUMBER), // #define BTA_HF_CLIENT_BINP_EVT 20 + sizeof(tBTA_HF_CLIENT_VAL), // #define BTA_HF_CLIENT_RING_INDICATION 21 + 0, // #define BTA_HF_CLIENT_DISABLE_EVT 30 +}; +/***************************************************************************** +** External Function Declarations +*****************************************************************************/ + +/******************************************************************************* +** +** Function BTA_HfClientEnable +** +** Description Enable the HF CLient service. When the enable +** operation is complete the callback function will be +** called with a BTA_HF_CLIENT_ENABLE_EVT. This function must +** be called before other function in the HF CLient API are +** called. +** +** Returns BTA_SUCCESS if OK, BTA_FAILURE otherwise. +** +*******************************************************************************/ +tBTA_STATUS BTA_HfClientEnable(tBTA_HF_CLIENT_CBACK *p_cback) +{ + tBTA_HF_CLIENT_API_ENABLE *p_buf; + + if (bta_sys_is_register (BTA_ID_HS)) { + APPL_TRACE_ERROR("BTA HF Client is already enabled, ignoring ..."); + return BTA_FAILURE; + } + + /* register with BTA system manager */ + bta_sys_register(BTA_ID_HS, &bta_hf_client_reg); + + if ((p_buf = (tBTA_HF_CLIENT_API_ENABLE *) osi_malloc(sizeof(tBTA_HF_CLIENT_API_ENABLE))) != NULL) { + p_buf->hdr.event = BTA_HF_CLIENT_API_ENABLE_EVT; + p_buf->p_cback = p_cback; + bta_sys_sendmsg(p_buf); + } + + return BTA_SUCCESS; +} + +/******************************************************************************* +** +** Function BTA_HfClientDisable +** +** Description Disable the HF Client service +** +** +** Returns void +** +*******************************************************************************/ +void BTA_HfClientDisable(void) +{ + BT_HDR *p_buf; + + if ((p_buf = (BT_HDR *) osi_malloc(sizeof(BT_HDR))) != NULL) { + p_buf->event = BTA_HF_CLIENT_API_DISABLE_EVT; + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function BTA_HfClientRegister +** +** Description Register an HF Client service. +** +** +** Returns void +** +*******************************************************************************/ +void BTA_HfClientRegister(tBTA_SEC sec_mask, tBTA_HF_CLIENT_FEAT features, + char *p_service_name) +{ + tBTA_HF_CLIENT_API_REGISTER *p_buf; + + if ((p_buf = (tBTA_HF_CLIENT_API_REGISTER *) osi_malloc(sizeof(tBTA_HF_CLIENT_API_REGISTER))) != NULL) { + p_buf->hdr.event = BTA_HF_CLIENT_API_REGISTER_EVT; + p_buf->features = features; + p_buf->sec_mask = sec_mask; + if (p_service_name) { + BCM_STRNCPY_S(p_buf->name, BTA_SERVICE_NAME_LEN + 1, p_service_name, BTA_SERVICE_NAME_LEN); + p_buf->name[BTA_SERVICE_NAME_LEN] = 0; + } else { + p_buf->name[0] = '\0'; + } + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function BTA_HfClientDeregister +** +** Description Deregister an HF Client service. +** +** +** Returns void +** +*******************************************************************************/ +void BTA_HfClientDeregister(UINT16 handle) +{ + BT_HDR *p_buf; + + if ((p_buf = (BT_HDR *) osi_malloc(sizeof(BT_HDR))) != NULL) { + p_buf->event = BTA_HF_CLIENT_API_DEREGISTER_EVT; + p_buf->layer_specific = handle; + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function BTA_HfClientOpen +** +** Description Opens a connection to an audio gateway. +** When connection is open callback function is called +** with a BTA_AG_OPEN_EVT. Only the data connection is +** opened. The audio connection is not opened. +** +** +** Returns void +** +*******************************************************************************/ +void BTA_HfClientOpen(UINT16 handle, BD_ADDR bd_addr, tBTA_SEC sec_mask) +{ + tBTA_HF_CLIENT_API_OPEN *p_buf; + + if ((p_buf = (tBTA_HF_CLIENT_API_OPEN *) osi_malloc(sizeof(tBTA_HF_CLIENT_API_OPEN))) != NULL) { + p_buf->hdr.event = BTA_HF_CLIENT_API_OPEN_EVT; + p_buf->hdr.layer_specific = handle; + bdcpy(p_buf->bd_addr, bd_addr); + p_buf->sec_mask = sec_mask; + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function BTA_HfClientClose +** +** Description Close the current connection to an audio gateway. +** Any current audio connection will also be closed +** +** +** Returns void +** +*******************************************************************************/ +void BTA_HfClientClose(UINT16 handle) +{ + BT_HDR *p_buf; + + if ((p_buf = (BT_HDR *) osi_malloc(sizeof(BT_HDR))) != NULL) { + p_buf->event = BTA_HF_CLIENT_API_CLOSE_EVT; + p_buf->layer_specific = handle; + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function BTA_HfCllientAudioOpen +** +** Description Opens an audio connection to the currently connected +** audio gateway +** +** +** Returns void +** +*******************************************************************************/ +void BTA_HfClientAudioOpen(UINT16 handle) +{ + BT_HDR *p_buf; + + if ((p_buf = (BT_HDR *) osi_malloc(sizeof(BT_HDR))) != NULL) { + p_buf->event = BTA_HF_CLIENT_API_AUDIO_OPEN_EVT; + p_buf->layer_specific = handle; + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function BTA_HfClientAudioClose +** +** Description Close the currently active audio connection to an audio +** gateway. The data connection remains open +** +** +** Returns void +** +*******************************************************************************/ +void BTA_HfClientAudioClose(UINT16 handle) +{ + BT_HDR *p_buf; + + if ((p_buf = (BT_HDR *) osi_malloc(sizeof(BT_HDR))) != NULL) { + p_buf->event = BTA_HF_CLIENT_API_AUDIO_CLOSE_EVT; + p_buf->layer_specific = handle; + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function BTA_HfClientSendAT +** +** Description send AT command +** +** +** Returns void +** +*******************************************************************************/ +void BTA_HfClientSendAT(UINT16 handle, tBTA_HF_CLIENT_AT_CMD_TYPE at, UINT32 val1, UINT32 val2, const char *str) +{ + tBTA_HF_CLIENT_DATA_VAL *p_buf; + + if ((p_buf = (tBTA_HF_CLIENT_DATA_VAL *) osi_malloc(sizeof(tBTA_HF_CLIENT_DATA_VAL))) != NULL) { + p_buf->hdr.event = BTA_HF_CLIENT_SEND_AT_CMD_EVT; + p_buf->uint8_val = at; + p_buf->uint32_val1 = val1; + p_buf->uint32_val2 = val2; + + if (str) { + strlcpy(p_buf->str, str, BTA_HF_CLIENT_NUMBER_LEN + 1); + p_buf->str[BTA_HF_CLIENT_NUMBER_LEN] = '\0'; + } else { + p_buf->str[0] = '\0'; + } + + p_buf->hdr.layer_specific = handle; + bta_sys_sendmsg(p_buf); + } +} +#if (BTM_SCO_HCI_INCLUDED == TRUE ) +void BTA_HfClientCiData(void) +{ + BT_HDR *p_buf; + if ((p_buf = (BT_HDR *) osi_malloc(sizeof(BT_HDR))) != NULL) { + p_buf->event = BTA_HF_CLIENT_CI_SCO_DATA_EVT; + bta_sys_sendmsg(p_buf); + } +} +#endif /* #if (BTM_SCO_HCI_INCLUDED == TRUE ) */ + +int BTA_HfClientGetCbDataSize(tBTA_HF_CLIENT_EVT event) +{ + return bta_hf_client_cb_data_size[event]; +} +#endif /* #if (BTA_HF_INCLUDED == TRUE) */ diff --git a/components/bt/bluedroid/bta/hf_client/bta_hf_client_at.c b/components/bt/bluedroid/bta/hf_client/bta_hf_client_at.c new file mode 100644 index 000000000..51a10d9bf --- /dev/null +++ b/components/bt/bluedroid/bta/hf_client/bta_hf_client_at.c @@ -0,0 +1,1795 @@ +/****************************************************************************** + * + * Copyright (c) 2014 The Android Open Source Project + * Copyright (C) 2003-2012 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ +// #include +#include +#include + +#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 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 ", __FUNCTION__); \ + return NULL;} \ + buf += sizeof("\r\n") - 1; + +/* skip rest of AT string up to */ +#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, "", 4); + p2 += 4; + } else if (*p1 == '\n') { + strlcpy(p2, "", 4); + p2 += 4; + } else { + *p2 = *p1; + p2++; + } + p1++; + } + + *p2 = '\0'; + + APPL_TRACE_DEBUG("%s %s", __FUNCTION__, dump); +} +#endif + +static void bta_hf_client_at_parse_start(void) +{ + char *buf = bta_hf_client_cb.scb.at_cb.buf; + + APPL_TRACE_DEBUG("%s", __FUNCTION__); + +#ifdef BTA_HF_CLIENT_AT_DUMP + bta_hf_client_dump_at(); +#endif + + while (*buf != '\0') { + int i; + char *tmp = NULL; + + for (i = 0; i < bta_hf_client_psraser_cb_count; i++) { + tmp = bta_hf_client_parser_cb[i](buf); + if (tmp == NULL) { + APPL_TRACE_ERROR("HFPCient: AT event/reply parsing failed, skipping"); + tmp = bta_hf_client_skip_unknown(buf); + break; + } + + /* matched or unknown skipped, if unknown failed tmp is NULL so + this is also handled */ + if (tmp != buf) { + buf = tmp; + break; + } + } + + /* could not skip unknown (received garbage?)... disconnect */ + if (tmp == NULL) { + APPL_TRACE_ERROR("HFPCient: could not skip unknown AT event, disconnecting"); + bta_hf_client_at_reset(); + bta_hf_client_sm_execute(BTA_HF_CLIENT_API_CLOSE_EVT, NULL); + return; + } + + buf = tmp; + } +} + +static BOOLEAN bta_hf_client_check_at_complete(void) +{ + BOOLEAN ret = FALSE; + tBTA_HF_CLIENT_AT_CB *at_cb = &bta_hf_client_cb.scb.at_cb; + + if (at_cb->offset >= BTA_HF_CLIENT_AT_EVENT_MIN_LEN) { + if (at_cb->buf[at_cb->offset - 2] == '\r' && at_cb->buf[at_cb->offset - 1] == '\n') { + ret = TRUE; + } + } + + APPL_TRACE_DEBUG("%s %d", __FUNCTION__, ret); + + return ret; +} + +static void bta_hf_client_at_clear_buf(void) +{ + memset(bta_hf_client_cb.scb.at_cb.buf, 0, sizeof(bta_hf_client_cb.scb.at_cb.buf)); + bta_hf_client_cb.scb.at_cb.offset = 0; +} + +/****************************************************************************** +** +** MAIN PARSING FUNCTION +** +** +*******************************************************************************/ +void bta_hf_client_at_parse(char *buf, unsigned int len) +{ + APPL_TRACE_DEBUG("%s offset: %u len: %u", __FUNCTION__, bta_hf_client_cb.scb.at_cb.offset, len); + + if (len + bta_hf_client_cb.scb.at_cb.offset > BTA_HF_CLIENT_AT_PARSER_MAX_LEN) { + unsigned int tmp = bta_hf_client_cb.scb.at_cb.offset; + unsigned int space_left = BTA_HF_CLIENT_AT_PARSER_MAX_LEN - bta_hf_client_cb.scb.at_cb.offset; + char *tmp_buff = osi_malloc(BTA_HF_CLIENT_AT_PARSER_MAX_LEN); + if (tmp_buff == NULL) { + APPL_TRACE_ERROR("No mem %s", __FUNCTION__); + return; + } + APPL_TRACE_DEBUG("%s overrun, trying to recover", __FUNCTION__); + + /* fill up parser buffer */ + memcpy(bta_hf_client_cb.scb.at_cb.buf + bta_hf_client_cb.scb.at_cb.offset, buf, space_left); + len -= space_left; + buf += space_left; + bta_hf_client_cb.scb.at_cb.offset += space_left; + + /* find end of last complete command before proceeding */ + while (bta_hf_client_check_at_complete() == FALSE) { + if (bta_hf_client_cb.scb.at_cb.offset == 0) { + APPL_TRACE_ERROR("HFPClient: AT parser buffer overrun, disconnecting"); + + bta_hf_client_at_reset(); + bta_hf_client_sm_execute(BTA_HF_CLIENT_API_CLOSE_EVT, NULL); + osi_free(tmp_buff); + return; + } + + bta_hf_client_cb.scb.at_cb.offset--; + } + + /* cut buffer to complete AT event and keep cut data */ + tmp += space_left - bta_hf_client_cb.scb.at_cb.offset; + memcpy(tmp_buff, bta_hf_client_cb.scb.at_cb.buf + bta_hf_client_cb.scb.at_cb.offset, tmp); + bta_hf_client_cb.scb.at_cb.buf[bta_hf_client_cb.scb.at_cb.offset] = '\0'; + + /* parse */ + bta_hf_client_at_parse_start(); + bta_hf_client_at_clear_buf(); + + /* recover cut data */ + memcpy(bta_hf_client_cb.scb.at_cb.buf, tmp_buff, tmp); + bta_hf_client_cb.scb.at_cb.offset += tmp; + + osi_free(tmp_buff); + } + + memcpy(bta_hf_client_cb.scb.at_cb.buf + bta_hf_client_cb.scb.at_cb.offset, buf, len); + bta_hf_client_cb.scb.at_cb.offset += len; + + /* If last event is complete, parsing can be started */ + if (bta_hf_client_check_at_complete() == TRUE) { + bta_hf_client_at_parse_start(); + bta_hf_client_at_clear_buf(); + } +} + +void bta_hf_client_send_at_brsf(void) +{ + char *buf = osi_malloc(BTA_HF_CLIENT_AT_MAX_LEN); + int at_len; + + if (buf == NULL) { + APPL_TRACE_ERROR("No mem %s", __FUNCTION__); + return; + } + + APPL_TRACE_DEBUG("%s", __FUNCTION__); + + at_len = snprintf(buf, BTA_HF_CLIENT_AT_MAX_LEN, "AT+BRSF=%u\r", bta_hf_client_cb.scb.features); + + bta_hf_client_send_at(BTA_HF_CLIENT_AT_BRSF , buf, at_len); + osi_free(buf); +} + +void bta_hf_client_send_at_bac(void) +{ + char *buf; + + APPL_TRACE_DEBUG("%s", __FUNCTION__); + + if (bta_hf_client_cb.msbc_enabled) { + buf = "AT+BAC=1,2\r"; + } else { + buf = "AT+BAC=1\r"; + } + + bta_hf_client_send_at(BTA_HF_CLIENT_AT_BAC, buf, strlen(buf)); +} + +void bta_hf_client_send_at_bcs(UINT32 codec) +{ + char * buf = osi_malloc(BTA_HF_CLIENT_AT_MAX_LEN); + int at_len; + + if (buf == NULL) { + APPL_TRACE_ERROR("No mem %s", __FUNCTION__); + return; + } + + at_len = snprintf(buf, BTA_HF_CLIENT_AT_MAX_LEN, "AT+BCS=%u\r", codec); + + bta_hf_client_send_at(BTA_HF_CLIENT_AT_BCS, buf, at_len); + osi_free(buf); +} + +void bta_hf_client_send_at_cind(BOOLEAN status) +{ + char *buf; + tBTA_HF_CLIENT_AT_CMD cmd; + + APPL_TRACE_DEBUG("%s", __FUNCTION__); + + if (status) { + buf = "AT+CIND?\r"; + cmd = BTA_HF_CLIENT_AT_CIND_STATUS; + } else { + buf = "AT+CIND=?\r"; + cmd = BTA_HF_CLIENT_AT_CIND; + } + + bta_hf_client_send_at(cmd, buf, strlen(buf)); +} + +void bta_hf_client_send_at_cmer(BOOLEAN activate) +{ + char *buf; + + APPL_TRACE_DEBUG("%s", __FUNCTION__); + + if (activate) { + buf = "AT+CMER=3,0,0,1\r"; + } else { + buf = "AT+CMER=3,0,0,0\r"; + } + + bta_hf_client_send_at(BTA_HF_CLIENT_AT_CMER, buf, strlen(buf)); +} + +void bta_hf_client_send_at_chld(char cmd, UINT32 idx) +{ + char *buf = osi_malloc(BTA_HF_CLIENT_AT_MAX_LEN); + int at_len; + + if (buf == NULL) { + APPL_TRACE_ERROR("No mem %s", __FUNCTION__); + return; + } + + if (idx > 0) { + at_len = snprintf(buf, BTA_HF_CLIENT_AT_MAX_LEN, "AT+CHLD=%c%u\r", cmd, idx); + } else { + at_len = snprintf(buf, BTA_HF_CLIENT_AT_MAX_LEN, "AT+CHLD=%c\r", cmd); + } + + bta_hf_client_send_at(BTA_HF_CLIENT_AT_CHLD, buf, at_len); + osi_free(buf); +} + +void bta_hf_client_send_at_clip(BOOLEAN activate) +{ + char *buf; + + APPL_TRACE_DEBUG("%s", __FUNCTION__); + + if (activate) { + buf = "AT+CLIP=1\r"; + } else { + buf = "AT+CLIP=0\r"; + } + + bta_hf_client_send_at(BTA_HF_CLIENT_AT_CLIP, buf, strlen(buf)); +} + +void bta_hf_client_send_at_ccwa(BOOLEAN activate) +{ + char *buf; + + APPL_TRACE_DEBUG("%s", __FUNCTION__); + + if (activate) { + buf = "AT+CCWA=1\r"; + } else { + buf = "AT+CCWA=0\r"; + } + + bta_hf_client_send_at(BTA_HF_CLIENT_AT_CCWA, buf, strlen(buf)); +} + + +void bta_hf_client_send_at_cmee(BOOLEAN activate) +{ + char *buf; + + APPL_TRACE_DEBUG("%s", __FUNCTION__); + + if (activate) { + buf = "AT+CMEE=1\r"; + } else { + buf = "AT+CMEE=0\r"; + } + + bta_hf_client_send_at(BTA_HF_CLIENT_AT_CMEE, buf, strlen(buf)); +} + +void bta_hf_client_send_at_cops(BOOLEAN query) +{ + char *buf; + + APPL_TRACE_DEBUG("%s", __FUNCTION__); + + if (query) { + buf = "AT+COPS?\r"; + } else { + buf = "AT+COPS=3,0\r"; + } + + bta_hf_client_send_at(BTA_HF_CLIENT_AT_COPS, buf, strlen(buf)); +} + +void bta_hf_client_send_at_clcc(void) +{ + char *buf; + + APPL_TRACE_DEBUG("%s", __FUNCTION__); + + buf = "AT+CLCC\r"; + + bta_hf_client_send_at(BTA_HF_CLIENT_AT_CLCC, buf, strlen(buf)); +} + +void bta_hf_client_send_at_bvra(BOOLEAN enable) +{ + char *buf; + + APPL_TRACE_DEBUG("%s", __FUNCTION__); + + if (enable) { + buf = "AT+BVRA=1\r"; + } else { + buf = "AT+BVRA=0\r"; + } + + bta_hf_client_send_at(BTA_HF_CLIENT_AT_BVRA, buf, strlen(buf)); +} + +void bta_hf_client_send_at_vgs(UINT32 volume) +{ + char *buf = osi_malloc(BTA_HF_CLIENT_AT_MAX_LEN); + int at_len; + if (buf == NULL) { + APPL_TRACE_ERROR("No mem %s", __FUNCTION__); + return; + } + APPL_TRACE_DEBUG("%s", __FUNCTION__); + + at_len = snprintf(buf, BTA_HF_CLIENT_AT_MAX_LEN, "AT+VGS=%u\r", volume); + + bta_hf_client_send_at(BTA_HF_CLIENT_AT_VGS, buf, at_len); + osi_free(buf); +} + +void bta_hf_client_send_at_vgm(UINT32 volume) +{ + char *buf = osi_malloc(BTA_HF_CLIENT_AT_MAX_LEN); + int at_len; + + if (buf == NULL) { + APPL_TRACE_ERROR("No mem %s", __FUNCTION__); + return; + } + APPL_TRACE_DEBUG("%s", __FUNCTION__); + + at_len = snprintf(buf, BTA_HF_CLIENT_AT_MAX_LEN, "AT+VGM=%u\r", volume); + + bta_hf_client_send_at(BTA_HF_CLIENT_AT_VGM, buf, at_len); + osi_free(buf); +} + +void bta_hf_client_send_at_atd(char *number, UINT32 memory) +{ + char *buf = osi_malloc(BTA_HF_CLIENT_AT_MAX_LEN); + int at_len; + + if (buf == NULL) { + APPL_TRACE_ERROR("No mem %s", __FUNCTION__); + return; + } + APPL_TRACE_DEBUG("%s", __FUNCTION__); + + if (number[0] != '\0') { + at_len = snprintf(buf, BTA_HF_CLIENT_AT_MAX_LEN, "ATD%s;\r", number); + } else { + at_len = snprintf(buf, BTA_HF_CLIENT_AT_MAX_LEN, "ATD>%u;\r", memory); + } + + at_len = MIN(at_len, BTA_HF_CLIENT_AT_MAX_LEN); + + bta_hf_client_send_at(BTA_HF_CLIENT_AT_ATD, buf, at_len); + osi_free(buf); +} + +void bta_hf_client_send_at_bldn(void) +{ + char *buf; + + APPL_TRACE_DEBUG("%s", __FUNCTION__); + + buf = "AT+BLDN\r"; + + bta_hf_client_send_at(BTA_HF_CLIENT_AT_BLDN, buf, strlen(buf)); +} + +void bta_hf_client_send_at_ata(void) +{ + char *buf; + + APPL_TRACE_DEBUG("%s", __FUNCTION__); + + buf = "ATA\r"; + + bta_hf_client_send_at(BTA_HF_CLIENT_AT_ATA, buf, strlen(buf)); +} + +void bta_hf_client_send_at_chup(void) +{ + char *buf; + + APPL_TRACE_DEBUG("%s", __FUNCTION__); + + buf = "AT+CHUP\r"; + + bta_hf_client_send_at(BTA_HF_CLIENT_AT_CHUP, buf, strlen(buf)); +} + +void bta_hf_client_send_at_btrh(BOOLEAN query, UINT32 val) +{ + char *buf = osi_malloc(BTA_HF_CLIENT_AT_MAX_LEN); + int at_len; + + if (buf == NULL) { + APPL_TRACE_ERROR("No mem %s", __FUNCTION__); + return; + } + APPL_TRACE_DEBUG("%s", __FUNCTION__); + + if (query == TRUE) { + at_len = snprintf(buf, BTA_HF_CLIENT_AT_MAX_LEN, "AT+BTRH?\r"); + } else { + at_len = snprintf(buf, BTA_HF_CLIENT_AT_MAX_LEN, "AT+BTRH=%u\r", val); + } + + bta_hf_client_send_at(BTA_HF_CLIENT_AT_BTRH, buf, at_len); + osi_free(buf); +} + +void bta_hf_client_send_at_vts(char code) +{ + char *buf = osi_malloc(BTA_HF_CLIENT_AT_MAX_LEN); + int at_len; + if (buf == NULL) { + APPL_TRACE_ERROR("No mem %s", __FUNCTION__); + return; + } + APPL_TRACE_DEBUG("%s", __FUNCTION__); + + at_len = snprintf(buf, BTA_HF_CLIENT_AT_MAX_LEN, "AT+VTS=%c\r", code); + + bta_hf_client_send_at(BTA_HF_CLIENT_AT_VTS, buf, at_len); + osi_free(buf); +} + +void bta_hf_client_send_at_bcc(void) +{ + char *buf; + + APPL_TRACE_DEBUG("%s", __FUNCTION__); + + buf = "AT+BCC\r"; + + bta_hf_client_send_at(BTA_HF_CLIENT_AT_BCC, buf, strlen(buf)); +} + +void bta_hf_client_send_at_cnum(void) +{ + char *buf; + + APPL_TRACE_DEBUG("%s", __FUNCTION__); + + buf = "AT+CNUM\r"; + + bta_hf_client_send_at(BTA_HF_CLIENT_AT_CNUM, buf, strlen(buf)); +} + +void bta_hf_client_send_at_nrec(void) +{ + char *buf; + + APPL_TRACE_DEBUG("%s", __FUNCTION__); + + if (!(bta_hf_client_cb.scb.peer_features & BTA_HF_CLIENT_PEER_FEAT_ECNR)) { + APPL_TRACE_ERROR("%s: Remote does not support NREC.", __FUNCTION__); + return; + } + + buf = "AT+NREC=0\r"; + + bta_hf_client_send_at(BTA_HF_CLIENT_AT_NREC, buf, strlen(buf)); +} + +void bta_hf_client_send_at_binp(UINT32 action) +{ + char *buf = osi_malloc(BTA_HF_CLIENT_AT_MAX_LEN); + int at_len; + + if (buf == NULL) { + APPL_TRACE_ERROR("No mem %s", __FUNCTION__); + return; + } + + at_len = snprintf(buf, BTA_HF_CLIENT_AT_MAX_LEN, "AT+BINP=%u\r", action); + + bta_hf_client_send_at(BTA_HF_CLIENT_AT_BINP, buf, at_len); + osi_free(buf); +} + +void bta_hf_client_send_at_bia(void) +{ + char *buf; + int at_len; + int i; + + APPL_TRACE_DEBUG("%s", __FUNCTION__); + if (bta_hf_client_cb.scb.peer_version < HFP_VERSION_1_6) { + APPL_TRACE_DEBUG("Remote does not Support AT+BIA"); + return; + } + + buf = osi_malloc(BTA_HF_CLIENT_AT_MAX_LEN); + if (buf == NULL) { + APPL_TRACE_ERROR("No mem %s", __FUNCTION__); + return; + } + at_len = snprintf(buf, BTA_HF_CLIENT_AT_MAX_LEN, "AT+BIA="); + + for (i = 0; i < BTA_HF_CLIENT_AT_INDICATOR_COUNT; i++) { + int sup = bta_hf_client_cb.scb.at_cb.indicator_lookup[i] == -1 ? 0 : 1; + + at_len += snprintf(buf + at_len, BTA_HF_CLIENT_AT_MAX_LEN - at_len, "%u,", sup); + } + + buf[at_len - 1] = '\r'; + + bta_hf_client_send_at(BTA_HF_CLIENT_AT_BIA, buf, at_len); + osi_free(buf); +} + +void bta_hf_client_at_init(void) +{ + memset(&bta_hf_client_cb.scb.at_cb, 0, sizeof(tBTA_HF_CLIENT_AT_CB)); + bta_hf_client_at_reset(); +} + +void bta_hf_client_at_reset(void) +{ + int i; + + bta_hf_client_free_at_resp_timer(); + bta_hf_client_free_at_hold_timer(); + + bta_hf_client_clear_queued_at(); + + bta_hf_client_at_clear_buf(); + + for (i = 0; i < BTA_HF_CLIENT_AT_INDICATOR_COUNT; i++) { + bta_hf_client_cb.scb.at_cb.indicator_lookup[i] = -1; + } + + bta_hf_client_cb.scb.at_cb.current_cmd = BTA_HF_CLIENT_AT_NONE; +} +#endif /* #if (BTA_HF_INCLUDED == TRUE) */ diff --git a/components/bt/bluedroid/bta/hf_client/bta_hf_client_cmd.c b/components/bt/bluedroid/bta/hf_client/bta_hf_client_cmd.c new file mode 100644 index 000000000..df761e4e9 --- /dev/null +++ b/components/bt/bluedroid/bta/hf_client/bta_hf_client_cmd.c @@ -0,0 +1,85 @@ +/****************************************************************************** + * + * Copyright (c) 2014 The Android Open Source Project + * Copyright (C) 2003-2012 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + +#include "bta_hf_client_int.h" +#include "stdio.h" +#include "common/bt_target.h" + +#if (BTA_HF_INCLUDED == TRUE) + +void bta_hf_client_send_at_cmd(tBTA_HF_CLIENT_DATA *p_data) +{ + tBTA_HF_CLIENT_DATA_VAL *p_val = (tBTA_HF_CLIENT_DATA_VAL *)p_data; + + switch (p_val->uint8_val) { + case BTA_HF_CLIENT_AT_CMD_VTS: + bta_hf_client_send_at_vts((char)p_val->uint32_val1); + break; + case BTA_HF_CLIENT_AT_CMD_BTRH: + bta_hf_client_send_at_btrh(FALSE, p_val->uint32_val1); + break; + case BTA_HF_CLIENT_AT_CMD_CHUP: + bta_hf_client_send_at_chup(); + break; + case BTA_HF_CLIENT_AT_CMD_CHLD: + /* expects ascii code for command */ + bta_hf_client_send_at_chld('0' + p_val->uint32_val1, p_val->uint32_val2); + break; + case BTA_HF_CLIENT_AT_CMD_BCC: + bta_hf_client_send_at_bcc(); + break; + case BTA_HF_CLIENT_AT_CMD_CNUM: + bta_hf_client_send_at_cnum(); + break; + case BTA_HF_CLIENT_AT_CMD_ATA: + bta_hf_client_send_at_ata(); + break; + case BTA_HF_CLIENT_AT_CMD_COPS: + bta_hf_client_send_at_cops(TRUE); + break; + case BTA_HF_CLIENT_AT_CMD_ATD: + bta_hf_client_send_at_atd(p_val->str, p_val->uint32_val1); + break; + case BTA_HF_CLIENT_AT_CMD_VGM: + bta_hf_client_send_at_vgm(p_val->uint32_val1); + break; + case BTA_HF_CLIENT_AT_CMD_VGS: + bta_hf_client_send_at_vgs(p_val->uint32_val1); + break; + case BTA_HF_CLIENT_AT_CMD_BVRA: + bta_hf_client_send_at_bvra(p_val->uint32_val1 == 0 ? FALSE : TRUE); + break; + case BTA_HF_CLIENT_AT_CMD_CLCC: + bta_hf_client_send_at_clcc(); + break; + case BTA_HF_CLIENT_AT_CMD_BINP: + bta_hf_client_send_at_binp(p_val->uint32_val1); + break; + case BTA_HF_CLIENT_AT_CMD_BLDN: + bta_hf_client_send_at_bldn(); + break; + case BTA_HF_CLIENT_AT_CMD_NREC: + bta_hf_client_send_at_nrec(); + break; + default: + APPL_TRACE_ERROR("Default case, %s", __FUNCTION__); + break; + } +} +#endif /* #if (BTA_HF_INCLUDED == TRUE) */ diff --git a/components/bt/bluedroid/bta/hf_client/bta_hf_client_main.c b/components/bt/bluedroid/bta/hf_client/bta_hf_client_main.c new file mode 100644 index 000000000..16e67cf73 --- /dev/null +++ b/components/bt/bluedroid/bta/hf_client/bta_hf_client_main.c @@ -0,0 +1,662 @@ +/****************************************************************************** + * + * Copyright (c) 2014 The Android Open Source Project + * Copyright (C) 2003-2012 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + +#include +#include +#include "common/bt_defs.h" +#include "bta/bta_api.h" +#include "bta/bta_sys.h" +#include "bta/bta_hf_client_api.h" +#include "bta_hf_client_int.h" + +#if (BTA_HF_INCLUDED == TRUE) +/* uncomment to enable extra debug */ +/* #define BTA_HF_CLIENT_DEBUG TRUE */ + +#ifndef BTA_HF_CLIENT_DEBUG +#define BTA_HF_CLIENT_DEBUG FALSE +#endif + +#if BTA_HF_CLIENT_DEBUG == TRUE +static char *bta_hf_client_evt_str(UINT16 event); +static char *bta_hf_client_state_str(UINT8 state); +#endif + +/* state machine states */ +enum { + BTA_HF_CLIENT_INIT_ST, + BTA_HF_CLIENT_OPENING_ST, + BTA_HF_CLIENT_OPEN_ST, + BTA_HF_CLIENT_CLOSING_ST +}; + +/* state machine action enumeration list */ +enum { + BTA_HF_CLIENT_REGISTER, + BTA_HF_CLIENT_DEREGISTER, + BTA_HF_CLIENT_START_DEREG, + BTA_HF_CLIENT_RFC_DO_CLOSE, + BTA_HF_CLIENT_START_CLOSE, + BTA_HF_CLIENT_START_OPEN, + BTA_HF_CLIENT_RFC_ACP_OPEN, + BTA_HF_CLIENT_SCO_LISTEN, + BTA_HF_CLIENT_SCO_CONN_OPEN, + BTA_HF_CLIENT_SCO_CONN_CLOSE, + BTA_HF_CLIENT_SCO_OPEN, + BTA_HF_CLIENT_SCO_CLOSE, + BTA_HF_CLIENT_SCO_SHUTDOWN, + BTA_HF_CLIENT_FREE_DB, + BTA_HF_CLIENT_OPEN_FAIL, + BTA_HF_CLIENT_RFC_OPEN, + BTA_HF_CLIENT_RFC_FAIL, + BTA_HF_CLIENT_DISC_INT_RES, + BTA_HF_CLIENT_RFC_DO_OPEN, + BTA_HF_CLIENT_DISC_FAIL, + BTA_HF_CLIENT_RFC_CLOSE, + BTA_HF_CLIENT_RFC_DATA, + BTA_HF_CLIENT_DISC_ACP_RES, + BTA_HF_CLIENT_SVC_CONN_OPEN, + BTA_HF_CLIENT_SEND_AT_CMD, +#if (BTM_SCO_HCI_INCLUDED == TRUE) + BTA_HF_CLIENT_CI_SCO_DATA, +#endif + BTA_HF_CLIENT_NUM_ACTIONS, +}; + +#define BTA_HF_CLIENT_IGNORE BTA_HF_CLIENT_NUM_ACTIONS + +/* type for action functions */ +typedef void (*tBTA_HF_CLIENT_ACTION)(tBTA_HF_CLIENT_DATA *p_data); + +/* action functions table, indexed with action enum */ +const tBTA_HF_CLIENT_ACTION bta_hf_client_action[] = { + /* BTA_HF_CLIENT_REGISTER */ bta_hf_client_register, + /* BTA_HF_CLIENT_DEREGISTER */ bta_hf_client_deregister, + /* BTA_HF_CLIENT_START_DEREG */ bta_hf_client_start_dereg, + /* BTA_HF_CLIENT_RFC_DO_CLOSE */ bta_hf_client_rfc_do_close, + /* BTA_HF_CLIENT_START_CLOSE */ bta_hf_client_start_close, + /* BTA_HF_CLIENT_START_OPEN */ bta_hf_client_start_open, + /* BTA_HF_CLIENT_RFC_ACP_OPEN */ bta_hf_client_rfc_acp_open, + /* BTA_HF_CLIENT_SCO_LISTEN */ bta_hf_client_sco_listen, + /* BTA_HF_CLIENT_SCO_CONN_OPEN */ bta_hf_client_sco_conn_open, + /* BTA_HF_CLIENT_SCO_CONN_CLOSE*/ bta_hf_client_sco_conn_close, + /* BTA_HF_CLIENT_SCO_OPEN */ bta_hf_client_sco_open, + /* BTA_HF_CLIENT_SCO_CLOSE */ bta_hf_client_sco_close, + /* BTA_HF_CLIENT_SCO_SHUTDOWN */ bta_hf_client_sco_shutdown, + /* BTA_HF_CLIENT_FREE_DB */ bta_hf_client_free_db, + /* BTA_HF_CLIENT_OPEN_FAIL */ bta_hf_client_open_fail, + /* BTA_HF_CLIENT_RFC_OPEN */ bta_hf_client_rfc_open, + /* BTA_HF_CLIENT_RFC_FAIL */ bta_hf_client_rfc_fail, + /* BTA_HF_CLIENT_DISC_INT_RES */ bta_hf_client_disc_int_res, + /* BTA_HF_CLIENT_RFC_DO_OPEN */ bta_hf_client_rfc_do_open, + /* BTA_HF_CLIENT_DISC_FAIL */ bta_hf_client_disc_fail, + /* BTA_HF_CLIENT_RFC_CLOSE */ bta_hf_client_rfc_close, + /* BTA_HF_CLIENT_RFC_DATA */ bta_hf_client_rfc_data, + /* BTA_HF_CLIENT_DISC_ACP_RES */ bta_hf_client_disc_acp_res, + /* BTA_HF_CLIENT_SVC_CONN_OPEN */ bta_hf_client_svc_conn_open, + /* BTA_HF_CLIENT_SEND_AT_CMD */ bta_hf_client_send_at_cmd, +#if (BTM_SCO_HCI_INCLUDED == TRUE ) + /* BTA_HF_CLIENT_CI_SCO_DATA */ bta_hf_client_ci_sco_data, +#endif /* (BTM_SCO_HCI_INCLUDED == TRUE ) */ +}; + +/* state table information */ +#define BTA_HF_CLIENT_ACTIONS 2 /* number of actions */ +#define BTA_HF_CLIENT_NEXT_STATE 2 /* position of next state */ +#define BTA_HF_CLIENT_NUM_COLS 3 /* number of columns in state tables */ + +/* state table for init state */ +const UINT8 bta_hf_client_st_init[][BTA_HF_CLIENT_NUM_COLS] = { + /* Event Action 1 Action 2 Next state */ + /* API_REGISTER_EVT */ {BTA_HF_CLIENT_REGISTER, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_INIT_ST}, + /* API_DEREGISTER_EVT */ {BTA_HF_CLIENT_DEREGISTER, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_INIT_ST}, + /* API_OPEN_EVT */ {BTA_HF_CLIENT_START_OPEN, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_OPENING_ST}, + /* API_CLOSE_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_INIT_ST}, + /* API_AUDIO_OPEN_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_INIT_ST}, + /* API_AUDIO_CLOSE_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_INIT_ST}, + /* RFC_OPEN_EVT */ {BTA_HF_CLIENT_RFC_ACP_OPEN, BTA_HF_CLIENT_SCO_LISTEN, BTA_HF_CLIENT_OPEN_ST}, + /* RFC_CLOSE_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_INIT_ST}, + /* RFC_SRV_CLOSE_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_INIT_ST}, + /* RFC_DATA_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_INIT_ST}, + /* DISC_ACP_RES_EVT */ {BTA_HF_CLIENT_FREE_DB, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_INIT_ST}, + /* DISC_INT_RES_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_INIT_ST}, + /* DISC_OK_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_INIT_ST}, + /* DISC_FAIL_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_INIT_ST}, + /* SCO_OPEN_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_INIT_ST}, + /* SCO_CLOSE_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_INIT_ST}, + /* SEND_AT_CMD_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_INIT_ST}, +#if (BTM_SCO_HCI_INCLUDED == TRUE ) + /* CI_SCO_DATA_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_INIT_ST}, +#endif /* (BTM_SCO_HCI_INCLUDED == TRUE ) */ +}; + +/* state table for opening state */ +const UINT8 bta_hf_client_st_opening[][BTA_HF_CLIENT_NUM_COLS] = { + /* Event Action 1 Action 2 Next state */ + /* API_REGISTER_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_OPENING_ST}, + /* API_DEREGISTER_EVT */ {BTA_HF_CLIENT_RFC_DO_CLOSE, BTA_HF_CLIENT_START_DEREG, BTA_HF_CLIENT_CLOSING_ST}, + /* API_OPEN_EVT */ {BTA_HF_CLIENT_OPEN_FAIL, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_OPENING_ST}, + /* API_CLOSE_EVT */ {BTA_HF_CLIENT_RFC_DO_CLOSE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_CLOSING_ST}, + /* API_AUDIO_OPEN_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_OPENING_ST}, + /* API_AUDIO_CLOSE_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_OPENING_ST}, + /* RFC_OPEN_EVT */ {BTA_HF_CLIENT_RFC_OPEN, BTA_HF_CLIENT_SCO_LISTEN, BTA_HF_CLIENT_OPEN_ST}, + /* RFC_CLOSE_EVT */ {BTA_HF_CLIENT_RFC_FAIL, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_INIT_ST}, + /* RFC_SRV_CLOSE_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_OPENING_ST}, + /* RFC_DATA_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_OPENING_ST}, + /* DISC_ACP_RES_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_OPENING_ST}, + /* DISC_INT_RES_EVT */ {BTA_HF_CLIENT_DISC_INT_RES, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_OPENING_ST}, + /* DISC_OK_EVT */ {BTA_HF_CLIENT_RFC_DO_OPEN, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_OPENING_ST}, + /* DISC_FAIL_EVT */ {BTA_HF_CLIENT_DISC_FAIL, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_INIT_ST}, + /* SCO_OPEN_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_OPENING_ST}, + /* SCO_CLOSE_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_OPENING_ST}, + /* SEND_AT_CMD_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_OPENING_ST}, +#if (BTM_SCO_HCI_INCLUDED == TRUE ) + /* CI_SCO_DATA_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_OPENING_ST}, +#endif /* (BTM_SCO_HCI_INCLUDED == TRUE ) */ +}; + +/* state table for open state */ +const UINT8 bta_hf_client_st_open[][BTA_HF_CLIENT_NUM_COLS] = { + /* Event Action 1 Action 2 Next state */ + /* API_REGISTER_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_OPEN_ST}, + /* API_DEREGISTER_EVT */ {BTA_HF_CLIENT_START_CLOSE, BTA_HF_CLIENT_START_DEREG, BTA_HF_CLIENT_CLOSING_ST}, + /* API_OPEN_EVT */ {BTA_HF_CLIENT_OPEN_FAIL, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_OPEN_ST}, + /* API_CLOSE_EVT */ {BTA_HF_CLIENT_START_CLOSE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_CLOSING_ST}, + /* API_AUDIO_OPEN_EVT */ {BTA_HF_CLIENT_SCO_OPEN, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_OPEN_ST}, + /* API_AUDIO_CLOSE_EVT */ {BTA_HF_CLIENT_SCO_CLOSE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_OPEN_ST}, + /* RFC_OPEN_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_OPEN_ST}, + /* RFC_CLOSE_EVT */ {BTA_HF_CLIENT_RFC_CLOSE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_INIT_ST}, + /* RFC_SRV_CLOSE_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_OPEN_ST}, + /* RFC_DATA_EVT */ {BTA_HF_CLIENT_RFC_DATA, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_OPEN_ST}, + /* DISC_ACP_RES_EVT */ {BTA_HF_CLIENT_DISC_ACP_RES, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_OPEN_ST}, + /* DISC_INT_RES_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_OPEN_ST}, + /* DISC_OK_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_OPEN_ST}, + /* DISC_FAIL_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_OPEN_ST}, + /* SCO_OPEN_EVT */ {BTA_HF_CLIENT_SCO_CONN_OPEN, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_OPEN_ST}, + /* SCO_CLOSE_EVT */ {BTA_HF_CLIENT_SCO_CONN_CLOSE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_OPEN_ST}, + /* SEND_AT_CMD_EVT */ {BTA_HF_CLIENT_SEND_AT_CMD, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_OPEN_ST}, +#if (BTM_SCO_HCI_INCLUDED == TRUE ) + /* CI_SCO_DATA_EVT */ {BTA_HF_CLIENT_CI_SCO_DATA, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_OPEN_ST}, +#endif /* (BTM_SCO_HCI_INCLUDED == TRUE ) */ +}; + +/* state table for closing state */ +const UINT8 bta_hf_client_st_closing[][BTA_HF_CLIENT_NUM_COLS] = { + /* Event Action 1 Action 2 Next state */ + /* API_REGISTER_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_CLOSING_ST}, + /* API_DEREGISTER_EVT */ {BTA_HF_CLIENT_START_DEREG, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_CLOSING_ST}, + /* API_OPEN_EVT */ {BTA_HF_CLIENT_OPEN_FAIL, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_CLOSING_ST}, + /* API_CLOSE_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_CLOSING_ST}, + /* API_AUDIO_OPEN_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_CLOSING_ST}, + /* API_AUDIO_CLOSE_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_CLOSING_ST}, + /* RFC_OPEN_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_CLOSING_ST}, + /* RFC_CLOSE_EVT */ {BTA_HF_CLIENT_RFC_CLOSE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_INIT_ST}, + /* RFC_SRV_CLOSE_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_CLOSING_ST}, + /* RFC_DATA_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_CLOSING_ST}, + /* DISC_ACP_RES_EVT */ {BTA_HF_CLIENT_FREE_DB, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_CLOSING_ST}, + /* DISC_INT_RES_EVT */ {BTA_HF_CLIENT_FREE_DB, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_INIT_ST}, + /* DISC_OK_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_CLOSING_ST}, + /* DISC_FAIL_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_CLOSING_ST}, + /* SCO_OPEN_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_CLOSING_ST}, + /* SCO_CLOSE_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_CLOSING_ST}, + /* SEND_AT_CMD_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_CLOSING_ST}, +#if (BTM_SCO_HCI_INCLUDED == TRUE ) + /* CI_SCO_DATA_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_CLOSING_ST}, +#endif /* (BTM_SCO_HCI_INCLUDED == TRUE ) */ +}; + +/* type for state table */ +typedef const UINT8 (*tBTA_HF_CLIENT_ST_TBL)[BTA_HF_CLIENT_NUM_COLS]; + +/* state table */ +const tBTA_HF_CLIENT_ST_TBL bta_hf_client_st_tbl[] = { + bta_hf_client_st_init, + bta_hf_client_st_opening, + bta_hf_client_st_open, + bta_hf_client_st_closing +}; + +/* HF Client control block */ +#if BTA_DYNAMIC_MEMORY == FALSE +tBTA_HF_CLIENT_CB bta_hf_client_cb; +#else +tBTA_HF_CLIENT_CB *bta_hf_client_cb_ptr; +#endif + + +/******************************************************************************* +** +** Function bta_hf_client_scb_init +** +** Description Initialize an HF_Client service control block. +** +** +** Returns void +** +*******************************************************************************/ +void bta_hf_client_scb_init(void) +{ + APPL_TRACE_DEBUG("%s", __FUNCTION__); + + memset(&bta_hf_client_cb.scb, 0, sizeof(tBTA_HF_CLIENT_SCB)); + bta_hf_client_cb.scb.sco_idx = BTM_INVALID_SCO_INDEX; + bta_hf_client_cb.scb.negotiated_codec = BTM_SCO_CODEC_CVSD; +} + +/******************************************************************************* +** +** Function bta_hf_client_scb_disable +** +** Description Disable a service control block. +** +** +** Returns void +** +*******************************************************************************/ +void bta_hf_client_scb_disable(void) +{ + APPL_TRACE_DEBUG("%s", __FUNCTION__); + + bta_hf_client_scb_init(); + + (*bta_hf_client_cb.p_cback)(BTA_HF_CLIENT_DISABLE_EVT, NULL); +} + +/******************************************************************************* +** +** Function bta_hf_client_resume_open +** +** Description Resume opening process. +** +** +** Returns void +** +*******************************************************************************/ +void bta_hf_client_resume_open (void) +{ + APPL_TRACE_DEBUG ("%s", __FUNCTION__); + + /* resume opening process. */ + if (bta_hf_client_cb.scb.state == BTA_HF_CLIENT_INIT_ST) { + bta_hf_client_cb.scb.state = BTA_HF_CLIENT_OPENING_ST; + bta_hf_client_start_open (NULL); + } +} + +/******************************************************************************* +** +** Function bta_hf_client_colli_timer_cback +** +** Description HF Client connection collision timer callback +** +** +** Returns void +** +*******************************************************************************/ +static void bta_hf_client_colli_timer_cback (TIMER_LIST_ENT *p_tle) +{ + APPL_TRACE_DEBUG("%s", __FUNCTION__); + + if (p_tle) { + bta_hf_client_cb.scb.colli_tmr_on = FALSE; + + /* If the peer haven't opened connection, restart opening process */ + bta_hf_client_resume_open (); + } +} + +/******************************************************************************* +** +** Function bta_hf_client_collision_cback +** +** Description Get notified about collision. +** +** +** Returns void +** +*******************************************************************************/ +void bta_hf_client_collision_cback (tBTA_SYS_CONN_STATUS status, UINT8 id, + UINT8 app_id, BD_ADDR peer_addr) +{ + UNUSED(status); + UNUSED(app_id); + UNUSED(peer_addr); + + if (bta_hf_client_cb.scb.state == BTA_HF_CLIENT_OPENING_ST) { + if (id == BTA_ID_SYS) { /* ACL collision */ + APPL_TRACE_WARNING ("HF Client found collision (ACL) ..."); + } else if (id == BTA_ID_HS) { /* RFCOMM collision */ + APPL_TRACE_WARNING ("HF Client found collision (RFCOMM) ..."); + } else { + APPL_TRACE_WARNING ("HF Client found collision (\?\?\?) ..."); + } + + bta_hf_client_cb.scb.state = BTA_HF_CLIENT_INIT_ST; + + /* Cancel SDP if it had been started. */ + if (bta_hf_client_cb.scb.p_disc_db) { + (void)SDP_CancelServiceSearch (bta_hf_client_cb.scb.p_disc_db); + bta_hf_client_free_db(NULL); + } + + /* reopen registered server */ + /* Collision may be detected before or after we close servers. */ + bta_hf_client_start_server(); + + /* Start timer to handle connection opening restart */ + bta_hf_client_cb.scb.colli_timer.p_cback = (TIMER_CBACK *)&bta_hf_client_colli_timer_cback; + bta_sys_start_timer(&bta_hf_client_cb.scb.colli_timer, 0, BTA_HF_CLIENT_COLLISION_TIMER); + bta_hf_client_cb.scb.colli_tmr_on = TRUE; + } +} + +/******************************************************************************* +** +** Function bta_hf_client_api_enable +** +** Description Handle an API enable event. +** +** +** Returns void +** +*******************************************************************************/ +static void bta_hf_client_api_enable(tBTA_HF_CLIENT_DATA *p_data) +{ + /* initialize control block */ + memset(&bta_hf_client_cb, 0, sizeof(tBTA_HF_CLIENT_CB)); + + /* store callback function */ + bta_hf_client_cb.p_cback = p_data->api_enable.p_cback; + + /* check if mSBC support enabled */ +#if 0 // todo + char value[PROPERTY_VALUE_MAX]; + property_get("ro.bluetooth.hfp.ver", value, "0"); + if (strcmp(value, "1.6") == 0) { + bta_hf_client_cb.msbc_enabled = TRUE; + } +#else + bta_hf_client_cb.msbc_enabled = FALSE; +#endif + + bta_hf_client_cb.scb.negotiated_codec = BTM_SCO_CODEC_CVSD; + + /* set same setting as AG does */ + BTM_WriteVoiceSettings(AG_VOICE_SETTINGS); + + bta_sys_collision_register (BTA_ID_HS, bta_hf_client_collision_cback); + + /* call callback with enable event */ + (*bta_hf_client_cb.p_cback)(BTA_HF_CLIENT_ENABLE_EVT, NULL); +} + +/******************************************************************************* +** +** Function bta_hf_client_api_disable +** +** Description Handle an API disable event. +** +** +** Returns void +** +*******************************************************************************/ +static void bta_hf_client_api_disable(tBTA_HF_CLIENT_DATA *p_data) +{ + if (!bta_sys_is_register (BTA_ID_HS)) { + APPL_TRACE_ERROR("BTA HF Client is already disabled, ignoring ..."); + return; + } + + /* De-register with BTA system manager */ + bta_sys_deregister(BTA_ID_HS); + + bta_hf_client_sm_execute(BTA_HF_CLIENT_API_DEREGISTER_EVT, p_data); + + bta_sys_collision_register (BTA_ID_HS, NULL); +} + +/******************************************************************************* +** +** Function bta_hf_client_hdl_event +** +** Description Data HF Client main event handling function. +** +** +** Returns BOOLEAN +** +*******************************************************************************/ +BOOLEAN bta_hf_client_hdl_event(BT_HDR *p_msg) +{ +#if BTA_HF_CLIENT_DEBUG == TRUE + APPL_TRACE_DEBUG("bta_hf_client_hdl_event %s (0x%x)", bta_hf_client_evt_str(p_msg->event), p_msg->event); +#endif + + switch (p_msg->event) { + /* handle enable event */ + case BTA_HF_CLIENT_API_ENABLE_EVT: + bta_hf_client_api_enable((tBTA_HF_CLIENT_DATA *) p_msg); + break; + + /* handle disable event */ + case BTA_HF_CLIENT_API_DISABLE_EVT: + bta_hf_client_api_disable((tBTA_HF_CLIENT_DATA *) p_msg); + break; + + default: + bta_hf_client_sm_execute(p_msg->event, (tBTA_HF_CLIENT_DATA *) p_msg); + break; + } + return TRUE; +} + +/******************************************************************************* +** +** Function bta_hf_client_sm_execute +** +** Description State machine event handling function for HF Client +** +** +** Returns void +** +*******************************************************************************/ +void bta_hf_client_sm_execute(UINT16 event, tBTA_HF_CLIENT_DATA *p_data) +{ + tBTA_HF_CLIENT_ST_TBL state_table; + UINT8 action; + int i; + +#if BTA_HF_CLIENT_DEBUG == TRUE + UINT16 in_event = event; + UINT8 in_state = bta_hf_client_cb.scb.state; + + /* Ignore displaying of AT results when not connected (Ignored in state machine) */ + if (bta_hf_client_cb.scb.state == BTA_HF_CLIENT_OPEN_ST) { + APPL_TRACE_EVENT("HF Client evt : State %d (%s), Event 0x%04x (%s)", + bta_hf_client_cb.scb.state, + bta_hf_client_state_str(bta_hf_client_cb.scb.state), + event, bta_hf_client_evt_str(event)); + } +#endif + + event &= 0x00FF; + if (event >= (BTA_HF_CLIENT_MAX_EVT & 0x00FF)) { + APPL_TRACE_ERROR("HF Client evt out of range, ignoring..."); + return; + } + + /* look up the state table for the current state */ + state_table = bta_hf_client_st_tbl[bta_hf_client_cb.scb.state]; + + /* set next state */ + bta_hf_client_cb.scb.state = state_table[event][BTA_HF_CLIENT_NEXT_STATE]; + + /* execute action functions */ + for (i = 0; i < BTA_HF_CLIENT_ACTIONS; i++) { + if ((action = state_table[event][i]) != BTA_HF_CLIENT_IGNORE) { + (*bta_hf_client_action[action])(p_data); + } else { + break; + } + } + +#if BTA_HF_CLIENT_DEBUG == TRUE + if (bta_hf_client_cb.scb.state != in_state) { + APPL_TRACE_EVENT("BTA HF Client State Change: [%s] -> [%s] after Event [%s]", + bta_hf_client_state_str(in_state), + bta_hf_client_state_str(bta_hf_client_cb.scb.state), + bta_hf_client_evt_str(in_event)); + } +#endif +} + +static void send_post_slc_cmd(void) +{ + bta_hf_client_cb.scb.at_cb.current_cmd = BTA_HF_CLIENT_AT_NONE; + + bta_hf_client_send_at_bia(); + bta_hf_client_send_at_ccwa(TRUE); + bta_hf_client_send_at_cmee(TRUE); + bta_hf_client_send_at_cops(FALSE); + bta_hf_client_send_at_btrh(TRUE, 0); + bta_hf_client_send_at_clip(TRUE); +} + +/******************************************************************************* +** +** Function bta_hf_client_slc_seq +** +** Description Handles AT commands sequence required for SLC creation +** +** +** Returns void +** +*******************************************************************************/ +void bta_hf_client_slc_seq(BOOLEAN error) +{ + APPL_TRACE_DEBUG("bta_hf_client_slc_seq cmd: %u", bta_hf_client_cb.scb.at_cb.current_cmd); + + if (error) { + /* SLC establishment error, sent close rfcomm event */ + APPL_TRACE_ERROR("HFPClient: Failed to create SLC due to AT error, disconnecting (%u)", + bta_hf_client_cb.scb.at_cb.current_cmd); + + bta_hf_client_sm_execute(BTA_HF_CLIENT_API_CLOSE_EVT, NULL); + return; + } + + if (bta_hf_client_cb.scb.svc_conn) { + return; + } + + switch (bta_hf_client_cb.scb.at_cb.current_cmd) { + case BTA_HF_CLIENT_AT_NONE: + bta_hf_client_send_at_brsf(); + break; + + case BTA_HF_CLIENT_AT_BRSF: + if (bta_hf_client_cb.scb.peer_features & BTA_HF_CLIENT_PEER_CODEC) { + bta_hf_client_send_at_bac(); + break; + } + + bta_hf_client_send_at_cind(FALSE); + break; + + case BTA_HF_CLIENT_AT_BAC: + bta_hf_client_send_at_cind(FALSE); + break; + + case BTA_HF_CLIENT_AT_CIND: + bta_hf_client_send_at_cind(TRUE); + break; + + case BTA_HF_CLIENT_AT_CIND_STATUS: + bta_hf_client_send_at_cmer(TRUE); + break; + + case BTA_HF_CLIENT_AT_CMER: + if (bta_hf_client_cb.scb.peer_features & BTA_HF_CLIENT_PEER_FEAT_3WAY) { + bta_hf_client_send_at_chld('?', 0); + } else { + bta_hf_client_svc_conn_open(NULL); + send_post_slc_cmd(); + } + break; + + case BTA_HF_CLIENT_AT_CHLD: + bta_hf_client_svc_conn_open(NULL); + send_post_slc_cmd(); + break; + + default: + /* If happen there is a bug in SLC creation procedure... */ + APPL_TRACE_ERROR("HFPClient: Failed to create SLCdue to unexpected AT command, disconnecting (%u)", + bta_hf_client_cb.scb.at_cb.current_cmd); + + bta_hf_client_sm_execute(BTA_HF_CLIENT_API_CLOSE_EVT, NULL); + break; + } +} + +#if BTA_HF_CLIENT_DEBUG == TRUE + +#ifndef CASE_RETURN_STR +#define CASE_RETURN_STR(const) case const: return #const; +#endif + +static char *bta_hf_client_evt_str(UINT16 event) +{ + switch (event) { + CASE_RETURN_STR(BTA_HF_CLIENT_API_REGISTER_EVT) + CASE_RETURN_STR(BTA_HF_CLIENT_API_DEREGISTER_EVT) + CASE_RETURN_STR(BTA_HF_CLIENT_API_OPEN_EVT) + CASE_RETURN_STR(BTA_HF_CLIENT_API_CLOSE_EVT) + CASE_RETURN_STR(BTA_HF_CLIENT_API_AUDIO_OPEN_EVT) + CASE_RETURN_STR(BTA_HF_CLIENT_API_AUDIO_CLOSE_EVT) + CASE_RETURN_STR(BTA_HF_CLIENT_RFC_OPEN_EVT) + CASE_RETURN_STR(BTA_HF_CLIENT_RFC_CLOSE_EVT) + CASE_RETURN_STR(BTA_HF_CLIENT_RFC_SRV_CLOSE_EVT) + CASE_RETURN_STR(BTA_HF_CLIENT_RFC_DATA_EVT) + CASE_RETURN_STR(BTA_HF_CLIENT_DISC_ACP_RES_EVT) + CASE_RETURN_STR(BTA_HF_CLIENT_DISC_INT_RES_EVT) + CASE_RETURN_STR(BTA_HF_CLIENT_DISC_OK_EVT) + CASE_RETURN_STR(BTA_HF_CLIENT_DISC_FAIL_EVT) + CASE_RETURN_STR(BTA_HF_CLIENT_API_ENABLE_EVT) + CASE_RETURN_STR(BTA_HF_CLIENT_API_DISABLE_EVT) + CASE_RETURN_STR(BTA_HF_CLIENT_SCO_OPEN_EVT) + CASE_RETURN_STR(BTA_HF_CLIENT_SCO_CLOSE_EVT) + CASE_RETURN_STR(BTA_HF_CLIENT_SEND_AT_CMD_EVT) + default: + return "Unknown HF Client Event"; + } +} + +static char *bta_hf_client_state_str(UINT8 state) +{ + switch (state) { + CASE_RETURN_STR(BTA_HF_CLIENT_INIT_ST) + CASE_RETURN_STR(BTA_HF_CLIENT_OPENING_ST) + CASE_RETURN_STR(BTA_HF_CLIENT_OPEN_ST) + CASE_RETURN_STR(BTA_HF_CLIENT_CLOSING_ST) + default: + return "Unknown HF Client State"; + } +} +#endif +#endif /* #if (BTA_HF_INCLUDED == TRUE) */ diff --git a/components/bt/bluedroid/bta/hf_client/bta_hf_client_rfc.c b/components/bt/bluedroid/bta/hf_client/bta_hf_client_rfc.c new file mode 100644 index 000000000..1b140dbd9 --- /dev/null +++ b/components/bt/bluedroid/bta/hf_client/bta_hf_client_rfc.c @@ -0,0 +1,246 @@ +/****************************************************************************** + * + * Copyright (c) 2014 The Android Open Source Project + * Copyright (C) 2004-2012 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + +/****************************************************************************** + * + * This file contains the audio gateway functions controlling the RFCOMM + * connections. + * + ******************************************************************************/ + +#include +#include "common/bt_defs.h" +#include "bta/bta_api.h" +#include "bta_hf_client_int.h" +#include "stack/port_api.h" +#include "osi/allocator.h" + +#if (BTA_HF_INCLUDED == TRUE) +/******************************************************************************* +** +** Function bta_hf_client_port_cback +** +** Description RFCOMM Port callback +** +** +** Returns void +** +*******************************************************************************/ +static void bta_hf_client_port_cback(UINT32 code, UINT16 port_handle) +{ + BT_HDR *p_buf; + UNUSED(code); + + /* ignore port events for port handles other than connected handle */ + if (port_handle != bta_hf_client_cb.scb.conn_handle) { + APPL_TRACE_DEBUG("bta_hf_client_port_cback ignoring handle:%d conn_handle = %d", + port_handle, bta_hf_client_cb.scb.conn_handle); + return; + } + + if ((p_buf = (BT_HDR *) osi_malloc(sizeof(BT_HDR))) != NULL) { + p_buf->event = BTA_HF_CLIENT_RFC_DATA_EVT; + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function bta_hf_client_mgmt_cback +** +** Description RFCOMM management callback +** +** +** Returns void +** +*******************************************************************************/ +static void bta_hf_client_mgmt_cback(UINT32 code, UINT16 port_handle) +{ + tBTA_HF_CLIENT_RFC *p_buf; + UINT16 event; + + APPL_TRACE_DEBUG("bta_hf_client_mgmt_cback : code = %d, port_handle = %d, conn_handle = %d, serv_handle = %d", + code, port_handle, bta_hf_client_cb.scb.conn_handle, bta_hf_client_cb.scb.serv_handle); + + /* ignore close event for port handles other than connected handle */ + if ((code != PORT_SUCCESS) && (port_handle != bta_hf_client_cb.scb.conn_handle)) { + APPL_TRACE_DEBUG("bta_hf_client_mgmt_cback ignoring handle:%d", port_handle); + return; + } + + if (code == PORT_SUCCESS) { + if ((bta_hf_client_cb.scb.conn_handle && (port_handle == bta_hf_client_cb.scb.conn_handle)) || /* outgoing connection */ + (port_handle == bta_hf_client_cb.scb.serv_handle)) { /* incoming connection */ + event = BTA_HF_CLIENT_RFC_OPEN_EVT; + } else { + APPL_TRACE_ERROR ("bta_hf_client_mgmt_cback: PORT_SUCCESS, ignoring handle = %d", port_handle); + return; + } + } + /* distinguish server close events */ + else if (port_handle == bta_hf_client_cb.scb.conn_handle) { + event = BTA_HF_CLIENT_RFC_CLOSE_EVT; + } else { + event = BTA_HF_CLIENT_RFC_SRV_CLOSE_EVT; + } + + if ((p_buf = (tBTA_HF_CLIENT_RFC *) osi_malloc(sizeof(tBTA_HF_CLIENT_RFC))) != NULL) { + p_buf->hdr.event = event; + p_buf->port_handle = port_handle; + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function bta_hf_client_setup_port +** +** Description Setup RFCOMM port for use by HF Client. +** +** +** Returns void +** +*******************************************************************************/ +void bta_hf_client_setup_port(UINT16 handle) +{ + PORT_SetEventMask(handle, PORT_EV_RXCHAR); + PORT_SetEventCallback(handle, bta_hf_client_port_cback); +} + +/******************************************************************************* +** +** Function bta_hf_client_start_server +** +** Description Setup RFCOMM server for use by HF Client. +** +** +** Returns void +** +*******************************************************************************/ +void bta_hf_client_start_server(void) +{ + int port_status; + + if (bta_hf_client_cb.scb.serv_handle > 0) { + APPL_TRACE_DEBUG("%s already started, handle: %d", __FUNCTION__, bta_hf_client_cb.scb.serv_handle); + return; + } + + BTM_SetSecurityLevel(FALSE, "", BTM_SEC_SERVICE_HF_HANDSFREE, bta_hf_client_cb.scb.serv_sec_mask, + BT_PSM_RFCOMM, BTM_SEC_PROTO_RFCOMM, bta_hf_client_cb.scn); + + port_status = RFCOMM_CreateConnection(UUID_SERVCLASS_HF_HANDSFREE, bta_hf_client_cb.scn, + TRUE, BTA_HF_CLIENT_MTU, (UINT8 *) bd_addr_any, &(bta_hf_client_cb.scb.serv_handle), + bta_hf_client_mgmt_cback); + + if (port_status == PORT_SUCCESS) { + bta_hf_client_setup_port(bta_hf_client_cb.scb.serv_handle); + } else { + /* TODO: can we handle this better? */ + APPL_TRACE_DEBUG("bta_hf_client_start_server: RFCOMM_CreateConnection returned error:%d", port_status); + } + + APPL_TRACE_DEBUG("bta_hf_client_start_server handle: %d", bta_hf_client_cb.scb.serv_handle); +} + +/******************************************************************************* +** +** Function bta_hf_client_close_server +** +** Description Close RFCOMM server port for use by HF Client. +** +** +** Returns void +** +*******************************************************************************/ +void bta_hf_client_close_server(void) +{ + APPL_TRACE_DEBUG("%s %d", __FUNCTION__, bta_hf_client_cb.scb.serv_handle); + + if (bta_hf_client_cb.scb.serv_handle == 0) { + APPL_TRACE_DEBUG("%s already stopped", __FUNCTION__); + return; + } + + RFCOMM_RemoveServer(bta_hf_client_cb.scb.serv_handle); + bta_hf_client_cb.scb.serv_handle = 0; +} + +/******************************************************************************* +** +** Function bta_hf_client_rfc_do_open +** +** Description Open an RFCOMM connection to the peer device. +** +** +** Returns void +** +*******************************************************************************/ +void bta_hf_client_rfc_do_open(tBTA_HF_CLIENT_DATA *p_data) +{ + BTM_SetSecurityLevel(TRUE, "", BTM_SEC_SERVICE_HF_HANDSFREE, + bta_hf_client_cb.scb.cli_sec_mask, BT_PSM_RFCOMM, + BTM_SEC_PROTO_RFCOMM, bta_hf_client_cb.scb.peer_scn); + + if (RFCOMM_CreateConnection(UUID_SERVCLASS_HF_HANDSFREE, bta_hf_client_cb.scb.peer_scn, + FALSE, BTA_HF_CLIENT_MTU, bta_hf_client_cb.scb.peer_addr, &(bta_hf_client_cb.scb.conn_handle), + bta_hf_client_mgmt_cback) == PORT_SUCCESS) { + bta_hf_client_setup_port(bta_hf_client_cb.scb.conn_handle); + APPL_TRACE_DEBUG("bta_hf_client_rfc_do_open : conn_handle = %d", bta_hf_client_cb.scb.conn_handle); + } + /* RFCOMM create connection failed; send ourselves RFCOMM close event */ + else { + bta_hf_client_sm_execute(BTA_HF_CLIENT_RFC_CLOSE_EVT, p_data); + } +} + +/******************************************************************************* +** +** Function bta_hf_client_rfc_do_close +** +** Description Close RFCOMM connection. +** +** +** Returns void +** +*******************************************************************************/ +void bta_hf_client_rfc_do_close(tBTA_HF_CLIENT_DATA *p_data) +{ + tBTA_HF_CLIENT_RFC *p_buf; + UNUSED(p_data); + + if (bta_hf_client_cb.scb.conn_handle) { + RFCOMM_RemoveConnection(bta_hf_client_cb.scb.conn_handle); + } else { + /* Close API was called while HF Client is in Opening state. */ + /* Need to trigger the state machine to send callback to the app */ + /* and move back to INIT state. */ + if ((p_buf = (tBTA_HF_CLIENT_RFC *) osi_malloc(sizeof(tBTA_HF_CLIENT_RFC))) != NULL) { + p_buf->hdr.event = BTA_HF_CLIENT_RFC_CLOSE_EVT; + bta_sys_sendmsg(p_buf); + } + + /* Cancel SDP if it had been started. */ + if (bta_hf_client_cb.scb.p_disc_db) { + (void)SDP_CancelServiceSearch (bta_hf_client_cb.scb.p_disc_db); + bta_hf_client_free_db(NULL); + } + } +} +#endif /* #if (BTA_HF_INCLUDED == TRUE) */ diff --git a/components/bt/bluedroid/bta/hf_client/bta_hf_client_sco.c b/components/bt/bluedroid/bta/hf_client/bta_hf_client_sco.c new file mode 100644 index 000000000..744edc917 --- /dev/null +++ b/components/bt/bluedroid/bta/hf_client/bta_hf_client_sco.c @@ -0,0 +1,825 @@ +/****************************************************************************** + * + * Copyright (c) 2014 The Android Open Source Project + * Copyright (C) 2004-2012 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + +#include "bta_hf_client_int.h" +#include "common/bt_trace.h" +#include +#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) */ diff --git a/components/bt/bluedroid/bta/hf_client/bta_hf_client_sdp.c b/components/bt/bluedroid/bta/hf_client/bta_hf_client_sdp.c new file mode 100644 index 000000000..920fcc952 --- /dev/null +++ b/components/bt/bluedroid/bta/hf_client/bta_hf_client_sdp.c @@ -0,0 +1,367 @@ +/****************************************************************************** + * + * Copyright (c) 2014 The Android Open Source Project + * Copyright (C) 2003-2012 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + +/****************************************************************************** + * + * This file contains the audio gateway functions performing SDP + * operations. + * + ******************************************************************************/ + +#include +#include "bta/bta_api.h" +#include "bta/bta_sys.h" +#include "common/bt_defs.h" +#include "bta/bta_hf_client_api.h" +#include "bta_hf_client_int.h" +#include "osi/allocator.h" + +#if (BTA_HF_INCLUDED == TRUE) +/* Number of protocol elements in protocol element list. */ +#define BTA_HF_CLIENT_NUM_PROTO_ELEMS 2 + +/* Number of elements in service class id list. */ +#define BTA_HF_CLIENT_NUM_SVC_ELEMS 2 + +/******************************************************************************* +** +** Function bta_hf_client_sdp_cback +** +** Description SDP callback function. +** +** +** Returns void +** +*******************************************************************************/ +static void bta_hf_client_sdp_cback(UINT16 status) +{ + tBTA_HF_CLIENT_DISC_RESULT *p_buf; + UINT16 event; + + APPL_TRACE_DEBUG("bta_hf_client_sdp_cback status:0x%x", status); + + /* set event according to int/acp */ + if (bta_hf_client_cb.scb.role == BTA_HF_CLIENT_ACP) { + event = BTA_HF_CLIENT_DISC_ACP_RES_EVT; + } else { + event = BTA_HF_CLIENT_DISC_INT_RES_EVT; + } + + if ((p_buf = (tBTA_HF_CLIENT_DISC_RESULT *) osi_malloc(sizeof(tBTA_HF_CLIENT_DISC_RESULT))) != NULL) { + p_buf->hdr.event = event; + p_buf->status = status; + bta_sys_sendmsg(p_buf); + } +} + +/****************************************************************************** +** +** Function bta_hf_client_add_record +** +** Description This function is called by a server application to add +** HFP Client information to an SDP record. Prior to +** calling this function the application must call +** SDP_CreateRecord() to create an SDP record. +** +** Returns TRUE if function execution succeeded, +** FALSE if function execution failed. +** +******************************************************************************/ +BOOLEAN bta_hf_client_add_record(char *p_service_name, UINT8 scn, + tBTA_HF_CLIENT_FEAT features, UINT32 sdp_handle) +{ + tSDP_PROTOCOL_ELEM proto_elem_list[BTA_HF_CLIENT_NUM_PROTO_ELEMS]; + UINT16 svc_class_id_list[BTA_HF_CLIENT_NUM_SVC_ELEMS]; + UINT16 browse_list[] = {UUID_SERVCLASS_PUBLIC_BROWSE_GROUP}; + UINT16 version; + UINT16 profile_uuid; + BOOLEAN result = TRUE; + UINT8 buf[2]; + UINT16 sdp_features = 0; + + APPL_TRACE_DEBUG("bta_hf_client_add_record"); + + memset( proto_elem_list, 0 , BTA_HF_CLIENT_NUM_PROTO_ELEMS * sizeof(tSDP_PROTOCOL_ELEM)); + + /* add the protocol element sequence */ + proto_elem_list[0].protocol_uuid = UUID_PROTOCOL_L2CAP; + proto_elem_list[0].num_params = 0; + proto_elem_list[1].protocol_uuid = UUID_PROTOCOL_RFCOMM; + proto_elem_list[1].num_params = 1; + proto_elem_list[1].params[0] = scn; + result &= SDP_AddProtocolList(sdp_handle, BTA_HF_CLIENT_NUM_PROTO_ELEMS, proto_elem_list); + + /* add service class id list */ + svc_class_id_list[0] = UUID_SERVCLASS_HF_HANDSFREE; + svc_class_id_list[1] = UUID_SERVCLASS_GENERIC_AUDIO; + result &= SDP_AddServiceClassIdList(sdp_handle, BTA_HF_CLIENT_NUM_SVC_ELEMS, svc_class_id_list); + + /* add profile descriptor list */ + profile_uuid = UUID_SERVCLASS_HF_HANDSFREE; + version = HFP_VERSION_1_6; + + result &= SDP_AddProfileDescriptorList(sdp_handle, profile_uuid, version); + + /* add service name */ + if (p_service_name != NULL && p_service_name[0] != 0) { + result &= SDP_AddAttribute(sdp_handle, ATTR_ID_SERVICE_NAME, TEXT_STR_DESC_TYPE, + (UINT32)(strlen(p_service_name) + 1), (UINT8 *) p_service_name); + } + + /* add features */ + if (features & BTA_HF_CLIENT_FEAT_ECNR) { + sdp_features |= BTA_HF_CLIENT_FEAT_ECNR; + } + + if (features & BTA_HF_CLIENT_FEAT_3WAY) { + sdp_features |= BTA_HF_CLIENT_FEAT_3WAY; + } + + if (features & BTA_HF_CLIENT_FEAT_CLI) { + sdp_features |= BTA_HF_CLIENT_FEAT_CLI; + } + + if (features & BTA_HF_CLIENT_FEAT_VREC) { + sdp_features |= BTA_HF_CLIENT_FEAT_VREC; + } + + if (features & BTA_HF_CLIENT_FEAT_VOL) { + sdp_features |= BTA_HF_CLIENT_FEAT_VOL; + } + + /* Codec bit position is different in SDP (bit 5) and in BRSF (bit 7) */ + if (features & BTA_HF_CLIENT_FEAT_CODEC) { + sdp_features |= 0x0020; + } + + UINT16_TO_BE_FIELD(buf, sdp_features); + result &= SDP_AddAttribute(sdp_handle, ATTR_ID_SUPPORTED_FEATURES, UINT_DESC_TYPE, 2, buf); + + /* add browse group list */ + result &= SDP_AddUuidSequence(sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, browse_list); + + return result; +} + +/******************************************************************************* +** +** Function bta_hf_client_create_record +** +** Description Create SDP record for registered service. +** +** +** Returns void +** +*******************************************************************************/ +void bta_hf_client_create_record(tBTA_HF_CLIENT_DATA *p_data) +{ + /* add sdp record if not already registered */ + if (bta_hf_client_cb.sdp_handle == 0) { + bta_hf_client_cb.sdp_handle = SDP_CreateRecord(); + bta_hf_client_cb.scn = BTM_AllocateSCN(); + bta_hf_client_add_record(p_data->api_register.name, + bta_hf_client_cb.scn, + p_data->api_register.features, + bta_hf_client_cb.sdp_handle); + + bta_sys_add_uuid(UUID_SERVCLASS_HF_HANDSFREE); + } + +} + +/******************************************************************************* +** +** Function bta_hf_client_del_record +** +** Description Delete SDP record for registered service. +** +** +** Returns void +** +*******************************************************************************/ +void bta_hf_client_del_record(tBTA_HF_CLIENT_DATA *p_data) +{ + UNUSED(p_data); + + APPL_TRACE_DEBUG("bta_hf_client_del_record"); + + if (bta_hf_client_cb.sdp_handle != 0) { + SDP_DeleteRecord(bta_hf_client_cb.sdp_handle); + bta_hf_client_cb.sdp_handle = 0; + BTM_FreeSCN(bta_hf_client_cb.scn); + BTM_SecClrService(BTM_SEC_SERVICE_HF_HANDSFREE); + bta_sys_remove_uuid(UUID_SERVCLASS_HF_HANDSFREE); + } +} + +/******************************************************************************* +** +** Function bta_hf_client_sdp_find_attr +** +** Description Process SDP discovery results to find requested attribute +** +** +** Returns TRUE if results found, FALSE otherwise. +** +*******************************************************************************/ +BOOLEAN bta_hf_client_sdp_find_attr(void) +{ + tSDP_DISC_REC *p_rec = NULL; + tSDP_DISC_ATTR *p_attr; + tSDP_PROTOCOL_ELEM pe; + BOOLEAN result = FALSE; + + bta_hf_client_cb.scb.peer_version = HFP_VERSION_1_1; /* Default version */ + + /* loop through all records we found */ + while (TRUE) { + /* get next record; if none found, we're done */ + if ((p_rec = SDP_FindServiceInDb(bta_hf_client_cb.scb.p_disc_db, UUID_SERVCLASS_AG_HANDSFREE, p_rec)) == NULL) { + break; + } + + /* get scn from proto desc list if initiator */ + if (bta_hf_client_cb.scb.role == BTA_HF_CLIENT_INT) { + if (SDP_FindProtocolListElemInRec(p_rec, UUID_PROTOCOL_RFCOMM, &pe)) { + bta_hf_client_cb.scb.peer_scn = (UINT8) pe.params[0]; + } else { + continue; + } + } + + /* get profile version (if failure, version parameter is not updated) */ + SDP_FindProfileVersionInRec(p_rec, UUID_SERVCLASS_HF_HANDSFREE, &bta_hf_client_cb.scb.peer_version); + + /* get features */ + if ((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_SUPPORTED_FEATURES)) != NULL) { + /* Found attribute. Get value. */ + /* There might be race condition between SDP and BRSF. */ + /* Do not update if we already received BRSF. */ + if (bta_hf_client_cb.scb.peer_features == 0) { + bta_hf_client_cb.scb.peer_features = p_attr->attr_value.v.u16; + + /* SDP and BRSF WBS bit are different, correct it if set */ + if (bta_hf_client_cb.scb.peer_features & 0x0020) { + bta_hf_client_cb.scb.peer_features &= ~0x0020; + bta_hf_client_cb.scb.peer_features |= BTA_HF_CLIENT_PEER_CODEC; + } + + /* get network for ability to reject calls */ + if ((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_NETWORK)) != NULL) { + if (p_attr->attr_value.v.u16 == 0x01) { + bta_hf_client_cb.scb.peer_features |= BTA_HF_CLIENT_PEER_REJECT; + } + } + } + } + + /* found what we needed */ + result = TRUE; + break; + } + + APPL_TRACE_DEBUG("%s peer_version=0x%x peer_features=0x%x", + __FUNCTION__, bta_hf_client_cb.scb.peer_version, + bta_hf_client_cb.scb.peer_features); + + return result; +} + +/******************************************************************************* +** +** Function bta_hf_client_do_disc +** +** Description Do service discovery. +** +** +** Returns void +** +*******************************************************************************/ +void bta_hf_client_do_disc(void) +{ + tSDP_UUID uuid_list[2]; + UINT16 num_uuid = 1; + UINT16 attr_list[4]; + UINT8 num_attr; + BOOLEAN db_inited = FALSE; + + /* initiator; get proto list and features */ + if (bta_hf_client_cb.scb.role == BTA_HF_CLIENT_INT) { + attr_list[0] = ATTR_ID_SERVICE_CLASS_ID_LIST; + attr_list[1] = ATTR_ID_PROTOCOL_DESC_LIST; + attr_list[2] = ATTR_ID_BT_PROFILE_DESC_LIST; + attr_list[3] = ATTR_ID_SUPPORTED_FEATURES; + num_attr = 4; + uuid_list[0].uu.uuid16 = UUID_SERVCLASS_AG_HANDSFREE; + } + /* acceptor; get features */ + else { + attr_list[0] = ATTR_ID_SERVICE_CLASS_ID_LIST; + attr_list[1] = ATTR_ID_BT_PROFILE_DESC_LIST; + attr_list[2] = ATTR_ID_SUPPORTED_FEATURES; + num_attr = 3; + uuid_list[0].uu.uuid16 = UUID_SERVCLASS_AG_HANDSFREE; + } + + /* allocate buffer for sdp database */ + bta_hf_client_cb.scb.p_disc_db = (tSDP_DISCOVERY_DB *) osi_malloc(BT_DEFAULT_BUFFER_SIZE); + + if (bta_hf_client_cb.scb.p_disc_db) { + /* set up service discovery database; attr happens to be attr_list len */ + uuid_list[0].len = LEN_UUID_16; + uuid_list[1].len = LEN_UUID_16; + db_inited = SDP_InitDiscoveryDb(bta_hf_client_cb.scb.p_disc_db, BT_DEFAULT_BUFFER_SIZE, num_uuid, + uuid_list, num_attr, attr_list); + } + + if (db_inited) { + /*Service discovery not initiated */ + db_inited = SDP_ServiceSearchAttributeRequest(bta_hf_client_cb.scb.peer_addr, + bta_hf_client_cb.scb.p_disc_db, bta_hf_client_sdp_cback); + } + + if (!db_inited) { + /*free discover db */ + bta_hf_client_free_db(NULL); + /* sent failed event */ + bta_hf_client_sm_execute(BTA_HF_CLIENT_DISC_FAIL_EVT, NULL); + } + +} + +/******************************************************************************* +** +** Function bta_hf_client_free_db +** +** Description Free discovery database. +** +** +** Returns void +** +*******************************************************************************/ +void bta_hf_client_free_db(tBTA_HF_CLIENT_DATA *p_data) +{ + UNUSED(p_data); + + if (bta_hf_client_cb.scb.p_disc_db != NULL) { + osi_free(bta_hf_client_cb.scb.p_disc_db); + bta_hf_client_cb.scb.p_disc_db = NULL; + } +} +#endif /* #if (BTA_HF_INCLUDED == TRUE) */ diff --git a/components/bt/bluedroid/bta/hf_client/include/bta_hf_client_at.h b/components/bt/bluedroid/bta/hf_client/include/bta_hf_client_at.h new file mode 100644 index 000000000..922e5e454 --- /dev/null +++ b/components/bt/bluedroid/bta/hf_client/include/bta_hf_client_at.h @@ -0,0 +1,117 @@ +/****************************************************************************** + * + * Copyright (c) 2014 The Android Open Source Project + * Copyright (C) 2003-2012 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + +/***************************************************************************** +** Data types +*****************************************************************************/ +#include "common/bt_target.h" +#if (BTA_HF_INCLUDED == TRUE) + +/* ASCII character string of arguments to the AT command */ +#define BTA_HF_CLIENT_AT_MAX_LEN 512 + +/* AT command table element */ +typedef struct { + const char *p_cmd; /* AT command string */ + UINT8 arg_type; /* allowable argument type syntax */ + UINT8 fmt; /* whether arg is int or string */ + UINT8 min; /* minimum value for int arg */ + INT16 max; /* maximum value for int arg */ +} tBTA_AG_AT_CMD; + +/* callback function executed when command is parsed */ +typedef void (tBTA_AG_AT_CMD_CBACK)(void *p_user, UINT16 cmd, UINT8 arg_type, + char *p_arg, INT16 int_arg); + +/* callback function executed to send "ERROR" result code */ +typedef void (tBTA_AG_AT_ERR_CBACK)(void *p_user, BOOLEAN unknown, char *p_arg); + +enum { + BTA_HF_CLIENT_AT_NONE, + BTA_HF_CLIENT_AT_BRSF, + BTA_HF_CLIENT_AT_BAC, + BTA_HF_CLIENT_AT_CIND, + BTA_HF_CLIENT_AT_CIND_STATUS, + BTA_HF_CLIENT_AT_CMER, + BTA_HF_CLIENT_AT_CHLD, + BTA_HF_CLIENT_AT_CMEE, + BTA_HF_CLIENT_AT_BIA, + BTA_HF_CLIENT_AT_CLIP, + BTA_HF_CLIENT_AT_CCWA, + BTA_HF_CLIENT_AT_COPS, + BTA_HF_CLIENT_AT_CLCC, + BTA_HF_CLIENT_AT_BVRA, + BTA_HF_CLIENT_AT_VGS, + BTA_HF_CLIENT_AT_VGM, + BTA_HF_CLIENT_AT_ATD, + BTA_HF_CLIENT_AT_BLDN, + BTA_HF_CLIENT_AT_ATA, + BTA_HF_CLIENT_AT_CHUP, + BTA_HF_CLIENT_AT_BTRH, + BTA_HF_CLIENT_AT_VTS, + BTA_HF_CLIENT_AT_BCC, + BTA_HF_CLIENT_AT_BCS, + BTA_HF_CLIENT_AT_CNUM, + BTA_HF_CLIENT_AT_NREC, + BTA_HF_CLIENT_AT_BINP, +}; + +typedef UINT8 tBTA_HF_CLIENT_AT_CMD; + +/* Maximum combined buffer for received AT events string */ +#define BTA_HF_CLIENT_AT_PARSER_MAX_LEN 4096 + +/* This structure holds prepared AT command queued for sending */ +struct queued_at_cmd { + tBTA_HF_CLIENT_AT_CMD cmd; + char buf[BTA_HF_CLIENT_AT_MAX_LEN]; + UINT16 buf_len; + struct queued_at_cmd *next; +}; +typedef struct queued_at_cmd tBTA_HF_CLIENT_AT_QCMD; + +/* Maximum number of indicators */ +#define BTA_HF_CLIENT_AT_INDICATOR_COUNT 20 + +/* AT command parsing control block */ +typedef struct { + char buf[BTA_HF_CLIENT_AT_PARSER_MAX_LEN + 1]; /* extra byte to always have \0 at the end */ + unsigned int offset; + tBTA_HF_CLIENT_AT_CMD current_cmd; + tBTA_HF_CLIENT_AT_QCMD *queued_cmd; + + TIMER_LIST_ENT resp_timer; /* AT response timer */ + BOOLEAN resp_timer_on; /* TRUE if AT response timer is active */ + + TIMER_LIST_ENT hold_timer; /* AT hold timer */ + BOOLEAN hold_timer_on; /* TRUE if AT hold timer is active */ + + /* CIND: lookup table to store the sequence of incoming indicators and their values + so when their values come later, we know which value in sequence match certain indicator */ + int indicator_lookup[BTA_HF_CLIENT_AT_INDICATOR_COUNT]; + +} tBTA_HF_CLIENT_AT_CB; + +/***************************************************************************** +** Functions +*****************************************************************************/ + +void bta_hf_client_at_init(void); +void bta_hf_client_at_reset(void); +#endif /* #if (BTA_HF_INCLUDED == TRUE) */ diff --git a/components/bt/bluedroid/bta/hf_client/include/bta_hf_client_int.h b/components/bt/bluedroid/bta/hf_client/include/bta_hf_client_int.h new file mode 100644 index 000000000..2e3fab9c1 --- /dev/null +++ b/components/bt/bluedroid/bta/hf_client/include/bta_hf_client_int.h @@ -0,0 +1,296 @@ +/****************************************************************************** + * + * Copyright (c) 2014 The Android Open Source Project + * Copyright (C) 2003-2012 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + +#include "bta/bta_sys.h" +#include "bta/bta_api.h" +#include "bta/bta_hf_client_api.h" +#include "bta_hf_client_at.h" + +#if (BTA_HF_INCLUDED == TRUE) +/***************************************************************************** +** Constants +*****************************************************************************/ +#define HFP_VERSION_1_1 0x0101 +#define HFP_VERSION_1_5 0x0105 +#define HFP_VERSION_1_6 0x0106 + +/* RFCOMM MTU SIZE */ +#define BTA_HF_CLIENT_MTU 256 + +/* profile role for connection */ +#define BTA_HF_CLIENT_ACP 0 /* accepted connection */ +#define BTA_HF_CLIENT_INT 1 /* initiating connection */ + +/* Timer to wait for retry in case of collision */ +#ifndef BTA_HF_CLIENT_COLLISION_TIMER +#define BTA_HF_CLIENT_COLLISION_TIMER 2411 +#endif + +enum { + /* these events are handled by the state machine */ + BTA_HF_CLIENT_API_REGISTER_EVT = BTA_SYS_EVT_START(BTA_ID_HS), + BTA_HF_CLIENT_API_DEREGISTER_EVT, + BTA_HF_CLIENT_API_OPEN_EVT, + BTA_HF_CLIENT_API_CLOSE_EVT, + BTA_HF_CLIENT_API_AUDIO_OPEN_EVT, + BTA_HF_CLIENT_API_AUDIO_CLOSE_EVT, + BTA_HF_CLIENT_RFC_OPEN_EVT, + BTA_HF_CLIENT_RFC_CLOSE_EVT, + BTA_HF_CLIENT_RFC_SRV_CLOSE_EVT, + BTA_HF_CLIENT_RFC_DATA_EVT, + BTA_HF_CLIENT_DISC_ACP_RES_EVT, + BTA_HF_CLIENT_DISC_INT_RES_EVT, + BTA_HF_CLIENT_DISC_OK_EVT, + BTA_HF_CLIENT_DISC_FAIL_EVT, + BTA_HF_CLIENT_SCO_OPEN_EVT, + BTA_HF_CLIENT_SCO_CLOSE_EVT, + BTA_HF_CLIENT_SEND_AT_CMD_EVT, +#if (BTM_SCO_HCI_INCLUDED == TRUE ) + BTA_HF_CLIENT_CI_SCO_DATA_EVT, +#endif /* (BTM_SCO_HCI_INCLUDED == TRUE ) */ + BTA_HF_CLIENT_MAX_EVT, + + /* these events are handled outside of the state machine */ + BTA_HF_CLIENT_API_ENABLE_EVT, + BTA_HF_CLIENT_API_DISABLE_EVT +}; + +/***************************************************************************** +** Data types +*****************************************************************************/ + +/* data type for BTA_HF_CLIENT_API_ENABLE_EVT */ +typedef struct { + BT_HDR hdr; + tBTA_HF_CLIENT_CBACK *p_cback; +} tBTA_HF_CLIENT_API_ENABLE; + +/* data type for BTA_HF_CLIENT_API_REGISTER_EVT */ +typedef struct { + BT_HDR hdr; + tBTA_HF_CLIENT_CBACK *p_cback; + tBTA_SEC sec_mask; + tBTA_HF_CLIENT_FEAT features; + char name[BTA_SERVICE_NAME_LEN + 1]; +} tBTA_HF_CLIENT_API_REGISTER; + +/* data type for BTA_HF_CLIENT_API_OPEN_EVT */ +typedef struct { + BT_HDR hdr; + BD_ADDR bd_addr; + tBTA_SEC sec_mask; +} tBTA_HF_CLIENT_API_OPEN; + +/* data type for BTA_HF_CLIENT_DISC_RESULT_EVT */ +typedef struct { + BT_HDR hdr; + UINT16 status; +} tBTA_HF_CLIENT_DISC_RESULT; + +/* data type for RFCOMM events */ +typedef struct { + BT_HDR hdr; + UINT16 port_handle; +} tBTA_HF_CLIENT_RFC; + +/* generic purpose data type for other events */ +typedef struct { + BT_HDR hdr; + BOOLEAN bool_val; + UINT8 uint8_val; + UINT32 uint32_val1; + UINT32 uint32_val2; + char str[BTA_HF_CLIENT_NUMBER_LEN + 1]; +} tBTA_HF_CLIENT_DATA_VAL; + +/* union of all event datatypes */ +typedef union { + BT_HDR hdr; + tBTA_HF_CLIENT_API_ENABLE api_enable; + tBTA_HF_CLIENT_API_REGISTER api_register; + tBTA_HF_CLIENT_API_OPEN api_open; + tBTA_HF_CLIENT_DISC_RESULT disc_result; + tBTA_HF_CLIENT_RFC rfc; + tBTA_HF_CLIENT_DATA_VAL val; + +} tBTA_HF_CLIENT_DATA; + +/* type for each service control block */ +typedef struct { + UINT16 serv_handle; /* RFCOMM server handle */ + BD_ADDR peer_addr; /* peer bd address */ + tSDP_DISCOVERY_DB *p_disc_db; /* pointer to discovery database */ + UINT16 conn_handle; /* RFCOMM handle of connected service */ + tBTA_SEC serv_sec_mask; /* server security mask */ + tBTA_SEC cli_sec_mask; /* client security mask */ + tBTA_HF_CLIENT_FEAT features; /* features registered by application */ + tBTA_HF_CLIENT_PEER_FEAT peer_features; /* peer device features */ + tBTA_HF_CLIENT_CHLD_FEAT chld_features; /* call handling features */ + UINT16 peer_version; /* profile version of peer device */ + UINT8 peer_scn; /* peer scn */ + UINT8 role; /* initiator/acceptor role */ + UINT16 sco_idx; /* SCO handle */ + UINT8 sco_state; /* SCO state variable */ + BOOLEAN sco_close_rfc; /* TRUE if also close RFCOMM after SCO */ + BOOLEAN retry_with_sco_only; + BOOLEAN deregister; /* TRUE if service shutting down */ + BOOLEAN svc_conn; /* set to TRUE when service level connection is up */ + BOOLEAN send_at_reply; /* set to TRUE to notify framework about AT results */ + tBTA_HF_CLIENT_AT_CB at_cb; /* AT Parser control block */ + UINT8 state; /* state machine state */ + tBTM_SCO_CODEC_TYPE negotiated_codec; /* negotiated codec */ + TIMER_LIST_ENT colli_timer; /* Collision timer */ + BOOLEAN colli_tmr_on; /* TRUE if collision timer is active */ +} tBTA_HF_CLIENT_SCB; + +/* sco states */ +enum { + BTA_HF_CLIENT_SCO_SHUTDOWN_ST, /* no listening, no connection */ + BTA_HF_CLIENT_SCO_LISTEN_ST, /* listening */ + BTA_HF_CLIENT_SCO_OPENING_ST, /* connection opening */ + BTA_HF_CLIENT_SCO_OPEN_CL_ST, /* opening connection being closed */ + BTA_HF_CLIENT_SCO_OPEN_ST, /* open */ + BTA_HF_CLIENT_SCO_CLOSING_ST, /* closing */ + BTA_HF_CLIENT_SCO_CLOSE_OP_ST, /* closing sco being opened */ + BTA_HF_CLIENT_SCO_SHUTTING_ST /* sco shutting down */ +}; + +/* type for AG control block */ +typedef struct { + tBTA_HF_CLIENT_SCB scb; /* service control block */ + UINT32 sdp_handle; + UINT8 scn; + tBTA_HF_CLIENT_CBACK *p_cback; /* application callback */ + BOOLEAN msbc_enabled; +} tBTA_HF_CLIENT_CB; + +/***************************************************************************** +** Global data +*****************************************************************************/ + +/* control block declaration */ +#if BTA_DYNAMIC_MEMORY == FALSE +extern tBTA_HF_CLIENT_CB bta_hf_client_cb; +#else +extern tBTA_HF_CLIENT_CB *bta_hf_client_cb_ptr; +#define bta_hf_client_cb (*bta_hf_client_cb_ptr) +#endif + +/***************************************************************************** +** Function prototypes +*****************************************************************************/ + +/* main functions */ +extern void bta_hf_client_scb_init(void); +extern void bta_hf_client_scb_disable(void); +extern BOOLEAN bta_hf_client_hdl_event(BT_HDR *p_msg); +extern void bta_hf_client_sm_execute(UINT16 event, + tBTA_HF_CLIENT_DATA *p_data); +extern void bta_hf_client_slc_seq(BOOLEAN error); +extern void bta_hf_client_collision_cback (tBTA_SYS_CONN_STATUS status, UINT8 id, + UINT8 app_id, BD_ADDR peer_addr); +extern void bta_hf_client_resume_open (); + +/* SDP functions */ +extern BOOLEAN bta_hf_client_add_record(char *p_service_name, + UINT8 scn, tBTA_HF_CLIENT_FEAT features, + UINT32 sdp_handle); +extern void bta_hf_client_create_record(tBTA_HF_CLIENT_DATA *p_data); +extern void bta_hf_client_del_record(tBTA_HF_CLIENT_DATA *p_data); +extern BOOLEAN bta_hf_client_sdp_find_attr(void); +extern void bta_hf_client_do_disc(void); +extern void bta_hf_client_free_db(tBTA_HF_CLIENT_DATA *p_data); + +/* RFCOMM functions */ +extern void bta_hf_client_setup_port(UINT16 handle); +extern void bta_hf_client_start_server(void); +extern void bta_hf_client_close_server(void); +extern void bta_hf_client_rfc_do_open(tBTA_HF_CLIENT_DATA *p_data); +extern void bta_hf_client_rfc_do_close(tBTA_HF_CLIENT_DATA *p_data); + +/* SCO functions */ +extern void bta_hf_client_sco_listen(tBTA_HF_CLIENT_DATA *p_data); +extern void bta_hf_client_sco_shutdown(tBTA_HF_CLIENT_DATA *p_data); +extern void bta_hf_client_sco_conn_open(tBTA_HF_CLIENT_DATA *p_data); +extern void bta_hf_client_sco_conn_close(tBTA_HF_CLIENT_DATA *p_data); +extern void bta_hf_client_sco_open(tBTA_HF_CLIENT_DATA *p_data); +extern void bta_hf_client_sco_close(tBTA_HF_CLIENT_DATA *p_data); +extern void bta_hf_client_cback_sco(UINT8 event); + +/* AT command functions */ +extern void bta_hf_client_at_parse(char *buf, unsigned int len); +extern void bta_hf_client_send_at_brsf(void); +extern void bta_hf_client_send_at_bac(void); +extern void bta_hf_client_send_at_cind(BOOLEAN status); +extern void bta_hf_client_send_at_cmer(BOOLEAN activate); +extern void bta_hf_client_send_at_chld(char cmd, UINT32 idx); +extern void bta_hf_client_send_at_clip(BOOLEAN activate); +extern void bta_hf_client_send_at_ccwa(BOOLEAN activate); +extern void bta_hf_client_send_at_cmee(BOOLEAN activate); +extern void bta_hf_client_send_at_cops(BOOLEAN query); +extern void bta_hf_client_send_at_clcc(void); +extern void bta_hf_client_send_at_bvra(BOOLEAN enable); +extern void bta_hf_client_send_at_vgs(UINT32 volume); +extern void bta_hf_client_send_at_vgm(UINT32 volume); +extern void bta_hf_client_send_at_atd(char *number, UINT32 memory); +extern void bta_hf_client_send_at_bldn(void); +extern void bta_hf_client_send_at_ata(void); +extern void bta_hf_client_send_at_chup(void); +extern void bta_hf_client_send_at_btrh(BOOLEAN query, UINT32 val); +extern void bta_hf_client_send_at_vts(char code); +extern void bta_hf_client_send_at_bcc(void); +extern void bta_hf_client_send_at_bcs(UINT32 codec); +extern void bta_hf_client_send_at_cnum(void); +extern void bta_hf_client_send_at_nrec(void); +extern void bta_hf_client_send_at_binp(UINT32 action); +extern void bta_hf_client_send_at_bia(void); + +/* Action functions */ +extern void bta_hf_client_register(tBTA_HF_CLIENT_DATA *p_data); +extern void bta_hf_client_deregister(tBTA_HF_CLIENT_DATA *p_data); +extern void bta_hf_client_start_dereg(tBTA_HF_CLIENT_DATA *p_data); +extern void bta_hf_client_start_close(tBTA_HF_CLIENT_DATA *p_data); +extern void bta_hf_client_start_open(tBTA_HF_CLIENT_DATA *p_data); +extern void bta_hf_client_rfc_acp_open(tBTA_HF_CLIENT_DATA *p_data); +extern void bta_hf_client_rfc_open(tBTA_HF_CLIENT_DATA *p_data); +extern void bta_hf_client_rfc_fail(tBTA_HF_CLIENT_DATA *p_data); +extern void bta_hf_client_disc_fail(tBTA_HF_CLIENT_DATA *p_data); +extern void bta_hf_client_open_fail(tBTA_HF_CLIENT_DATA *p_data); +extern void bta_hf_client_rfc_close(tBTA_HF_CLIENT_DATA *p_data); +extern void bta_hf_client_disc_acp_res(tBTA_HF_CLIENT_DATA *p_data); +extern void bta_hf_client_rfc_data(tBTA_HF_CLIENT_DATA *p_data); +extern void bta_hf_client_disc_int_res(tBTA_HF_CLIENT_DATA *p_data); +extern void bta_hf_client_svc_conn_open(tBTA_HF_CLIENT_DATA *p_data); +extern void bta_hf_client_ind(tBTA_HF_CLIENT_IND_TYPE type, UINT16 value); +extern void bta_hf_client_evt_val(tBTA_HF_CLIENT_EVT type, UINT16 value); +extern void bta_hf_client_operator_name(char *name); +extern void bta_hf_client_clip(char *number); +extern void bta_hf_client_ccwa(char *number); +extern void bta_hf_client_at_result(tBTA_HF_CLIENT_AT_RESULT_TYPE type, UINT16 cme); +extern void bta_hf_client_clcc(UINT32 idx, BOOLEAN incoming, UINT8 status, BOOLEAN mpty, char *number); +extern void bta_hf_client_cnum(char *number, UINT16 service); +extern void bta_hf_client_binp(char *number); + +/* Commands handling functions */ +extern void bta_hf_client_dial(tBTA_HF_CLIENT_DATA *p_data); +extern void bta_hf_client_send_at_cmd(tBTA_HF_CLIENT_DATA *p_data); +#if (BTM_SCO_HCI_INCLUDED == TRUE ) +extern void bta_hf_client_ci_sco_data(tBTA_HF_CLIENT_DATA *p_data); +#endif /* (BTM_SCO_HCI_INCLUDED == TRUE ) */ +#endif /* #if (BTA_HF_INCLUDED == TRUE) */ diff --git a/components/bt/bluedroid/bta/include/bta/bta_dm_ci.h b/components/bt/bluedroid/bta/include/bta/bta_dm_ci.h index 90565aac8..cd15c86c3 100644 --- a/components/bt/bluedroid/bta/include/bta/bta_dm_ci.h +++ b/components/bt/bluedroid/bta/include/bta/bta_dm_ci.h @@ -61,18 +61,6 @@ extern void bta_dm_ci_io_req(BD_ADDR bd_addr, tBTA_IO_CAP io_cap, *******************************************************************************/ extern void bta_dm_ci_rmt_oob(BOOLEAN accept, BD_ADDR bd_addr, BT_OCTET16 c, BT_OCTET16 r); -/******************************************************************************* -** -** Function bta_dm_sco_ci_data_ready -** -** Description This function sends an event to indicating that the phone -** has SCO data ready.. -** -** Returns void -** -*******************************************************************************/ -extern void bta_dm_sco_ci_data_ready(UINT16 event, UINT16 sco_handle); - #ifdef __cplusplus } #endif diff --git a/components/bt/bluedroid/bta/include/bta/bta_dm_co.h b/components/bt/bluedroid/bta/include/bta/bta_dm_co.h index 7d6285719..1f1f648a9 100644 --- a/components/bt/bluedroid/bta/include/bta/bta_dm_co.h +++ b/components/bt/bluedroid/bta/include/bta/bta_dm_co.h @@ -26,29 +26,6 @@ #include "bta/bta_sys.h" - -#ifndef BTA_SCO_OUT_PKT_SIZE -#define BTA_SCO_OUT_PKT_SIZE BTM_SCO_DATA_SIZE_MAX -#endif - -#define BTA_SCO_CODEC_PCM 0 /* used for regular SCO */ -#define BTA_SCO_CODEC_SBC 1 /* used for WBS */ -typedef UINT8 tBTA_SCO_CODEC_TYPE; - -#define BTA_DM_SCO_SAMP_RATE_8K 8000 -#define BTA_DM_SCO_SAMP_RATE_16K 16000 - -/* SCO codec information */ -typedef struct { - tBTA_SCO_CODEC_TYPE codec_type; -} tBTA_CODEC_INFO; - -#define BTA_DM_SCO_ROUTE_PCM BTM_SCO_ROUTE_PCM -#define BTA_DM_SCO_ROUTE_HCI BTM_SCO_ROUTE_HCI - -typedef tBTM_SCO_ROUTE_TYPE tBTA_DM_SCO_ROUTE_TYPE; - - /***************************************************************************** ** Function Declarations *****************************************************************************/ @@ -135,72 +112,6 @@ extern void bta_dm_co_loc_oob(BOOLEAN valid, BT_OCTET16 c, BT_OCTET16 r); *******************************************************************************/ extern void bta_dm_co_rmt_oob(BD_ADDR bd_addr); -/***************************************************************************** -** SCO over HCI Function Declarations -*****************************************************************************/ -/******************************************************************************* -** -** Function bta_dm_sco_co_init -** -** Description This function can be used by the phone to initialize audio -** codec or for other initialization purposes before SCO connection -** is opened. -** -** -** Returns Void. -** -*******************************************************************************/ -extern tBTA_DM_SCO_ROUTE_TYPE bta_dm_sco_co_init(UINT32 rx_bw, UINT32 tx_bw, - tBTA_CODEC_INFO *p_codec_info, UINT8 app_id); - - -/******************************************************************************* -** -** Function bta_dm_sco_co_open -** -** Description This function is executed when a SCO connection is open. -** -** -** Returns void -** -*******************************************************************************/ -extern void bta_dm_sco_co_open(UINT16 handle, UINT8 pkt_size, UINT16 event); - -/******************************************************************************* -** -** Function bta_dm_sco_co_close -** -** Description This function is called when a SCO connection is closed -** -** -** Returns void -** -*******************************************************************************/ -extern void bta_dm_sco_co_close(void); - -/******************************************************************************* -** -** Function bta_dm_sco_co_out_data -** -** Description This function is called to send SCO data over HCI. -** -** Returns void -** -*******************************************************************************/ -extern void bta_dm_sco_co_out_data(BT_HDR **p_buf); - -/******************************************************************************* -** -** Function bta_dm_sco_co_in_data -** -** Description This function is called to send incoming SCO data to application. -** -** Returns void -** -*******************************************************************************/ -extern void bta_dm_sco_co_in_data(BT_HDR *p_buf, tBTM_SCO_DATA_FLAG status); - - /******************************************************************************* ** diff --git a/components/bt/bluedroid/bta/include/bta/bta_hf_client_api.h b/components/bt/bluedroid/bta/include/bta/bta_hf_client_api.h new file mode 100644 index 000000000..ade9f63f2 --- /dev/null +++ b/components/bt/bluedroid/bta/include/bta/bta_hf_client_api.h @@ -0,0 +1,378 @@ +/****************************************************************************** + * + * Copyright (c) 2014 The Android Open Source Project + * Copyright (C) 2003-2012 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + +/****************************************************************************** + * + * This is the public interface file for the handsfree (HF role) subsystem + * + ******************************************************************************/ +#ifndef BTA_HF_CLIENT_API_H +#define BTA_HF_CLIENT_API_H + +#include "bta_api.h" +#include "bta_hfp_defs.h" + +#if (BTA_HF_INCLUDED == TRUE) +/***************************************************************************** +** Constants and data types +*****************************************************************************/ + +/* HFP peer (AG) features*/ +#define BTA_HF_CLIENT_PEER_FEAT_3WAY 0x00000001 /* Three-way calling */ +#define BTA_HF_CLIENT_PEER_FEAT_ECNR 0x00000002 /* Echo cancellation and/or noise reduction */ +#define BTA_HF_CLIENT_PEER_FEAT_VREC 0x00000004 /* Voice recognition */ +#define BTA_HF_CLIENT_PEER_INBAND 0x00000008 /* In-band ring tone */ +#define BTA_HF_CLIENT_PEER_VTAG 0x00000010 /* Attach a phone number to a voice tag */ +#define BTA_HF_CLIENT_PEER_REJECT 0x00000020 /* Ability to reject incoming call */ +#define BTA_HF_CLIENT_PEER_ECS 0x00000040 /* Enhanced Call Status */ +#define BTA_HF_CLIENT_PEER_ECC 0x00000080 /* Enhanced Call Control */ +#define BTA_HF_CLIENT_PEER_EXTERR 0x00000100 /* Extended error codes */ +#define BTA_HF_CLIENT_PEER_CODEC 0x00000200 /* Codec Negotiation */ + +typedef UINT16 tBTA_HF_CLIENT_PEER_FEAT; + +/* HFP HF features */ +#define BTA_HF_CLIENT_FEAT_ECNR 0x00000001 /* Echo cancellation and/or noise reduction */ +#define BTA_HF_CLIENT_FEAT_3WAY 0x00000002 /* Call waiting and three-way calling */ +#define BTA_HF_CLIENT_FEAT_CLI 0x00000004 /* Caller ID presentation capability */ +#define BTA_HF_CLIENT_FEAT_VREC 0x00000008 /* Voice recognition activation */ +#define BTA_HF_CLIENT_FEAT_VOL 0x00000010 /* Remote volume control */ +#define BTA_HF_CLIENT_FEAT_ECS 0x00000020 /* Enhanced Call Status */ +#define BTA_HF_CLIENT_FEAT_ECC 0x00000040 /* Enhanced Call Control */ +#define BTA_HF_CLIENT_FEAT_CODEC 0x00000080 /* Codec Negotiation */ + +/* HFP HF extended call handling - masks not related to any spec */ +#define BTA_HF_CLIENT_CHLD_REL 0x00000001 /* 0 Release waiting call or held calls */ +#define BTA_HF_CLIENT_CHLD_REL_ACC 0x00000002 /* 1 Release active calls and accept other (waiting or held) cal */ +#define BTA_HF_CLIENT_CHLD_REL_X 0x00000004 /* 1x Release x call*/ +#define BTA_HF_CLIENT_CHLD_HOLD_ACC 0x00000008 /* 2 Active calls on hold and accept other call */ +#define BTA_HF_CLIENT_CHLD_PRIV_X 0x00000010 /* 2x Active multiparty call on hold except call x */ +#define BTA_HF_CLIENT_CHLD_MERGE 0x00000020 /* 3 Add held call to multiparty */ +#define BTA_HF_CLIENT_CHLD_MERGE_DETACH 0x00000040 /* 4 Add held call to multiparty */ + +typedef UINT16 tBTA_HF_CLIENT_CHLD_FEAT; + +/* HFP AG errors ot OK sent to HF Unit */ +#define BTA_HF_CLIENT_AT_RESULT_OK 0 +#define BTA_HF_CLIENT_AT_RESULT_ERROR 1 +#define BTA_HF_CLIENT_AT_RESULT_NO_CARRIER 2 +#define BTA_HF_CLIENT_AT_RESULT_BUSY 3 +#define BTA_HF_CLIENT_AT_RESULT_NO_ANSWER 4 +#define BTA_HF_CLIENT_AT_RESULT_DELAY 5 +#define BTA_HF_CLIENT_AT_RESULT_BLACKLISTED 6 +#define BTA_HF_CLIENT_AT_RESULT_CME 7 + +typedef UINT8 tBTA_HF_CLIENT_AT_RESULT_TYPE; + +/* HF Client callback events */ +#define BTA_HF_CLIENT_ENABLE_EVT 0 /* HF Client enabled */ +#define BTA_HF_CLIENT_REGISTER_EVT 1 /* HF Client registered */ +#define BTA_HF_CLIENT_OPEN_EVT 2 /* HF Client connection open */ +#define BTA_HF_CLIENT_CLOSE_EVT 3 /* HF Client connection closed */ +#define BTA_HF_CLIENT_CONN_EVT 4 /* Service level connection opened */ +#define BTA_HF_CLIENT_AUDIO_OPEN_EVT 5 /* Audio connection open */ +#define BTA_HF_CLIENT_AUDIO_MSBC_OPEN_EVT 6 /* Audio connection with mSBC codec open */ +#define BTA_HF_CLIENT_AUDIO_CLOSE_EVT 7 /* Audio connection closed */ +#define BTA_HF_CLIENT_SPK_EVT 8 /* Speaker volume changed */ +#define BTA_HF_CLIENT_MIC_EVT 9 /* Microphone volume changed */ +#define BTA_HF_CLIENT_IND_EVT 10 /* Indicator */ +#define BTA_HF_CLIENT_VOICE_REC_EVT 11 /* AG changed voice recognition setting */ +#define BTA_HF_CLIENT_OPERATOR_NAME_EVT 12 /* Operator name acquired */ +#define BTA_HF_CLIENT_CLIP_EVT 13 /* Calling line identification event */ +#define BTA_HF_CLIENT_CCWA_EVT 14 /* Call waiting notification */ +#define BTA_HF_CLIENT_AT_RESULT_EVT 15 /* Call waiting notification */ +#define BTA_HF_CLIENT_CLCC_EVT 16 /* current call event */ +#define BTA_HF_CLIENT_CNUM_EVT 17 /* subscriber information event */ +#define BTA_HF_CLIENT_BTRH_EVT 18 /* bluetooth response and hold event */ +#define BTA_HF_CLIENT_BSIR_EVT 19 /* in-band ring tone setting changed event */ +#define BTA_HF_CLIENT_BINP_EVT 20 /* binp number event */ +#define BTA_HF_CLIENT_RING_INDICATION 21 /* HF Client ring indication */ +#define BTA_HF_CLIENT_DISABLE_EVT 30 /* HF Client disabled */ + +typedef UINT8 tBTA_HF_CLIENT_EVT; + +/* HF Client open status */ +#define BTA_HF_CLIENT_SUCCESS 0 /* Connection successfully opened */ +#define BTA_HF_CLIENT_FAIL_SDP 1 /* Open failed due to SDP */ +#define BTA_HF_CLIENT_FAIL_RFCOMM 2 /* Open failed due to RFCOMM */ +#define BTA_HF_CLIENT_FAIL_RESOURCES 3 /* out of resources failure */ + +typedef UINT8 tBTA_HF_CLIENT_STATUS; + +/* indicator type */ +#define BTA_HF_CLIENT_IND_BATTCH 0 /* Battery charge indicator */ +#define BTA_HF_CLIENT_IND_SIGNAL 1 /* Signal Strength indicator */ +#define BTA_HF_CLIENT_IND_SERVICE 2 /* Service availability indicator */ +#define BTA_HF_CLIENT_IND_CALL 3 /* Standard call status indicator*/ +#define BTA_HF_CLIENT_IND_ROAM 4 /* Roaming status indicator */ +#define BTA_HF_CLIENT_IND_CALLSETUP 5 /* Call setup status indicator */ +#define BTA_HF_CLIENT_IND_CALLHELD 6 /* Call hold status indicator */ + +typedef UINT8 tBTA_HF_CLIENT_IND_TYPE; + +/* AT commands */ +#define BTA_HF_CLIENT_AT_CMD_VTS 0 +#define BTA_HF_CLIENT_AT_CMD_BTRH 1 +#define BTA_HF_CLIENT_AT_CMD_CHUP 2 +#define BTA_HF_CLIENT_AT_CMD_CHLD 3 +#define BTA_HF_CLIENT_AT_CMD_BCC 4 +#define BTA_HF_CLIENT_AT_CMD_CNUM 5 +#define BTA_HF_CLIENT_AT_CMD_ATA 6 +#define BTA_HF_CLIENT_AT_CMD_COPS 7 +#define BTA_HF_CLIENT_AT_CMD_ATD 8 +#define BTA_HF_CLIENT_AT_CMD_VGM 9 +#define BTA_HF_CLIENT_AT_CMD_VGS 10 +#define BTA_HF_CLIENT_AT_CMD_BVRA 11 +#define BTA_HF_CLIENT_AT_CMD_CLCC 12 +#define BTA_HF_CLIENT_AT_CMD_BINP 13 +#define BTA_HF_CLIENT_AT_CMD_BLDN 14 +#define BTA_HF_CLIENT_AT_CMD_NREC 15 + +typedef UINT8 tBTA_HF_CLIENT_AT_CMD_TYPE; + +/* data associated with most non-AT events */ +/* placeholder, if not needed should be removed*/ +typedef struct { +} tBTA_HF_CLIENT_HDR; + +/* data associated with BTA_HF_CLIENT_REGISTER_EVT */ +typedef struct { + tBTA_HF_CLIENT_HDR hdr; + UINT16 handle; + tBTA_HF_CLIENT_STATUS status; +} tBTA_HF_CLIENT_REGISTER; + +/* data associated with BTA_HF_CLIENT_OPEN_EVT */ +typedef struct { + tBTA_HF_CLIENT_HDR hdr; + BD_ADDR bd_addr; + tBTA_HF_CLIENT_STATUS status; +} tBTA_HF_CLIENT_OPEN; + +/* data associated with BTA_HF_CLIENT_CONN_EVT */ +typedef struct { + tBTA_HF_CLIENT_HDR hdr; + tBTA_HF_CLIENT_PEER_FEAT peer_feat; + tBTA_HF_CLIENT_CHLD_FEAT chld_feat; +} tBTA_HF_CLIENT_CONN; + +/* data associated with BTA_HF_CLIENT_IND_EVT event */ +typedef struct { + tBTA_HF_CLIENT_HDR hdr; + tBTA_HF_CLIENT_IND_TYPE type; + UINT16 value; +} tBTA_HF_CLIENT_IND; + +/* data associated with BTA_HF_CLIENT_OPERATOR_NAME_EVT */ +#define BTA_HF_CLIENT_OPERATOR_NAME_LEN 16 +typedef struct { + char name[BTA_HF_CLIENT_OPERATOR_NAME_LEN + 1]; +} tBTA_HF_CLIENT_OPERATOR_NAME; + +/* data associated with BTA_HF_CLIENT_CLIP_EVT and BTA_HF_CLIENT_CCWA_EVT*/ +#define BTA_HF_CLIENT_NUMBER_LEN 32 +typedef struct { + char number[BTA_HF_CLIENT_NUMBER_LEN + 1]; +} tBTA_HF_CLIENT_NUMBER; + +/* data associated with BTA_HF_CLIENT_AT_RESULT_EVT event */ +typedef struct { + tBTA_HF_CLIENT_AT_RESULT_TYPE type; + UINT16 cme; +} tBTA_HF_CLIENT_AT_RESULT; + +/* data associated with BTA_HF_CLIENT_CLCC_EVT event */ +typedef struct { + UINT32 idx; + BOOLEAN inc; + UINT8 status; + BOOLEAN mpty; + BOOLEAN number_present; + char number[BTA_HF_CLIENT_NUMBER_LEN + 1]; +} tBTA_HF_CLIENT_CLCC; + +/* data associated with BTA_HF_CLIENT_CNUM_EVT event */ +typedef struct { + UINT16 service; + char number[BTA_HF_CLIENT_NUMBER_LEN + 1]; +} tBTA_HF_CLIENT_CNUM; + +/* data associated with other events */ +typedef struct { + UINT16 value; +} tBTA_HF_CLIENT_VAL; + +/* union of data associated with AG callback */ +typedef union { + tBTA_HF_CLIENT_HDR hdr; + tBTA_HF_CLIENT_REGISTER reg; + tBTA_HF_CLIENT_OPEN open; + tBTA_HF_CLIENT_CONN conn; + tBTA_HF_CLIENT_IND ind; + tBTA_HF_CLIENT_VAL val; + tBTA_HF_CLIENT_OPERATOR_NAME operator; + tBTA_HF_CLIENT_NUMBER number; + tBTA_HF_CLIENT_AT_RESULT result; + tBTA_HF_CLIENT_CLCC clcc; + tBTA_HF_CLIENT_CNUM cnum; +} tBTA_HF_CLIENT; + +typedef UINT32 tBTA_HF_CLIENT_FEAT; + +/* HF Client callback */ +typedef void (tBTA_HF_CLIENT_CBACK)(tBTA_HF_CLIENT_EVT event, void *p_data); + +#ifdef __cplusplus +extern "C" +{ +#endif + +/***************************************************************************** +** External Function Declarations +*****************************************************************************/ + +/******************************************************************************* +** +** Function BTA_HfClientEnable +** +** Description Enable the HF CLient service. When the enable +** operation is complete the callback function will be +** called with a BTA_HF_CLIENT_ENABLE_EVT. This function must +** be called before other function in the HF CLient API are +** called. +** +** Returns BTA_SUCCESS if OK, BTA_FAILURE otherwise. +** +*******************************************************************************/ +tBTA_STATUS BTA_HfClientEnable(tBTA_HF_CLIENT_CBACK *p_cback); + +/******************************************************************************* +** +** Function BTA_HfClientDisable +** +** Description Disable the HF Client service +** +** +** Returns void +** +*******************************************************************************/ +void BTA_HfClientDisable(void); + +/******************************************************************************* +** +** Function BTA_HfClientRegister +** +** Description Register an HF Client service. +** +** +** Returns void +** +*******************************************************************************/ +void BTA_HfClientRegister(tBTA_SEC sec_mask, tBTA_HF_CLIENT_FEAT features, + char *p_service_name); + +/******************************************************************************* +** +** Function BTA_HfClientDeregister +** +** Description Deregister an HF Client service. +** +** +** Returns void +** +*******************************************************************************/ +void BTA_HfClientDeregister(UINT16 handle); + +/******************************************************************************* +** +** Function BTA_HfClientOpen +** +** Description Opens a connection to an audio gateway. +** When connection is open callback function is called +** with a BTA_HF_CLIENT_OPEN_EVT. Only the data connection is +** opened. The audio connection is not opened. +** +** +** Returns void +** +*******************************************************************************/ +void BTA_HfClientOpen(UINT16 handle, BD_ADDR bd_addr, tBTA_SEC sec_mask); + +/******************************************************************************* +** +** Function BTA_HfClientClose +** +** Description Close the current connection to an audio gateway. +** Any current audio connection will also be closed +** +** +** Returns void +** +*******************************************************************************/ +void BTA_HfClientClose(UINT16 handle); + +/******************************************************************************* +** +** Function BTA_HfCllientAudioOpen +** +** Description Opens an audio connection to the currently connected +** audio gateway +** +** +** Returns void +** +*******************************************************************************/ +void BTA_HfClientAudioOpen(UINT16 handle); + +/******************************************************************************* +** +** Function BTA_HfClientAudioClose +** +** Description Close the currently active audio connection to an audio +** gateway. The data connection remains open +** +** +** Returns void +** +*******************************************************************************/ +void BTA_HfClientAudioClose(UINT16 handle); + +/******************************************************************************* +** +** Function BTA_HfClientSendAT +** +** Description send AT command +** +** +** Returns void +** +*******************************************************************************/ +void BTA_HfClientSendAT(UINT16 handle, tBTA_HF_CLIENT_AT_CMD_TYPE at, UINT32 val1, UINT32 val2, const char *str); + +#if (BTM_SCO_HCI_INCLUDED == TRUE ) +void BTA_HfClientCiData(void); +#endif /*#if (BTM_SCO_HCI_INCLUDED == TRUE ) */ + +int BTA_HfClientGetCbDataSize(tBTA_HF_CLIENT_EVT event); + +#ifdef __cplusplus +} +#endif +#endif /* #if (BTA_HF_INCLUDED == TRUE) */ +#endif /* BTA_HF_CLIENT_API_H */ diff --git a/components/bt/bluedroid/bta/include/bta/bta_hf_client_co.h b/components/bt/bluedroid/bta/include/bta/bta_hf_client_co.h new file mode 100644 index 000000000..af53e6e31 --- /dev/null +++ b/components/bt/bluedroid/bta/include/bta/bta_hf_client_co.h @@ -0,0 +1,115 @@ +// Copyright 2018 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + + +/****************************************************************************** + * + * This is the interface file for hf client call-out functions. + * + ******************************************************************************/ +#ifndef BTA_HF_CLIENT_CO_H +#define BTA_HF_CLIENT_CO_H + +#include "common/bt_target.h" +#include "bta/bta_hf_client_api.h" + +#if (BTA_HF_INCLUDED == TRUE) + +#if (BTM_SCO_HCI_INCLUDED == TRUE) +/******************************************************************************* +** +** Function bta_hf_client_co_audio_state +** +** Description This function is called by the HF CLIENT before the audio connection +** is brought up, after it comes up, and after it goes down. +** +** Parameters handle - handle of the AG instance +** state - Audio state +** codec - if WBS support is compiled in, codec to going to be used is provided +** and when in SCO_STATE_SETUP, BTM_I2SPCMConfig() must be called with +** the correct platform parameters. +** in the other states codec type should not be ignored +** +** Returns void +** +*******************************************************************************/ +void bta_hf_client_co_audio_state(UINT16 handle, UINT8 state, tBTA_HFP_PEER_CODEC codec); + + +/******************************************************************************* +** +** Function bta_hf_client_sco_co_init +** +** Description This function can be used by the phone to initialize audio +** codec or for other initialization purposes before SCO connection +** is opened. +** +** +** Returns Void. +** +*******************************************************************************/ +tBTA_HFP_SCO_ROUTE_TYPE bta_hf_client_sco_co_init(UINT32 rx_bw, UINT32 tx_bw, + tBTA_HFP_CODEC_INFO *p_codec_info, UINT8 app_id); + + +/******************************************************************************* +** +** Function bta_hf_client_sco_co_open +** +** Description This function is executed when a SCO connection is open. +** +** +** Returns void +** +*******************************************************************************/ +void bta_hf_client_sco_co_open(UINT16 handle, UINT8 pkt_size, UINT16 event); + +/******************************************************************************* +** +** Function bta_hf_client_sco_co_close +** +** Description This function is called when a SCO connection is closed +** +** +** Returns void +** +*******************************************************************************/ +void bta_hf_client_sco_co_close(void); + +/******************************************************************************* +** +** Function bta_hf_client_sco_co_out_data +** +** Description This function is called to send SCO data over HCI. +** +** Returns number of bytes got from application +** +*******************************************************************************/ +uint32_t bta_hf_client_sco_co_out_data(uint8_t *p_buf, uint32_t sz); + +/******************************************************************************* +** +** Function bta_hf_client_sco_co_in_data +** +** Description This function is called to send incoming SCO data to application. +** +** Returns void +** +*******************************************************************************/ +extern void bta_hf_client_sco_co_in_data(BT_HDR *p_buf, tBTM_SCO_DATA_FLAG status); + +#endif /* #if (BTM_SCO_HCI_INCLUDED == TRUE) */ + +#endif /* #if (BTA_HF_INCLUDED == TRUE) */ +#endif /* BTA_HF_CLIENT_CO_H */ diff --git a/components/bt/bluedroid/bta/include/bta/bta_hfp_defs.h b/components/bt/bluedroid/bta/include/bta/bta_hfp_defs.h new file mode 100644 index 000000000..464481979 --- /dev/null +++ b/components/bt/bluedroid/bta/include/bta/bta_hfp_defs.h @@ -0,0 +1,47 @@ +// Copyright 2018 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef __BTA_HFP_DEFS_H__ +#define __BTA_HFP_DEFS_H__ + +#include "stack/btm_api.h" + +#define BTA_HFP_CODEC_NONE BTM_SCO_CODEC_NONE +#define BTA_HFP_CODEC_CVSD BTM_SCO_CODEC_CVSD /* CVSD */ +#define BTA_HFP_CODEC_MSBC BTM_SCO_CODEC_MSBC /* mSBC */ + +typedef UINT16 tBTA_HFP_PEER_CODEC; + +#ifndef BTA_HFP_SCO_OUT_PKT_SIZE +#define BTA_HFP_SCO_OUT_PKT_SIZE BTM_SCO_DATA_SIZE_MAX +#endif + +#define BTA_HFP_SCO_CODEC_PCM 0 /* used for regular SCO */ +#define BTA_HFP_SCO_CODEC_SBC 1 /* used for WBS */ +typedef UINT8 tBTA_HFP_SCO_CODEC_TYPE; + +#define BTA_HFP_SCO_SAMP_RATE_8K 8000 +#define BTA_HFP_SCO_SAMP_RATE_16K 16000 + +/* SCO codec information */ +typedef struct { + tBTA_HFP_SCO_CODEC_TYPE codec_type; +} tBTA_HFP_CODEC_INFO; + +#define BTA_HFP_SCO_ROUTE_PCM BTM_SCO_ROUTE_PCM +#define BTA_HFP_SCO_ROUTE_HCI BTM_SCO_ROUTE_HCI + +typedef tBTM_SCO_ROUTE_TYPE tBTA_HFP_SCO_ROUTE_TYPE; + +#endif /* __BTA_HFP_DEFS_H__ */ diff --git a/components/bt/bluedroid/btc/core/btc_dm.c b/components/bt/bluedroid/btc/core/btc_dm.c index 1ed93a725..9f6c91105 100644 --- a/components/bt/bluedroid/btc/core/btc_dm.c +++ b/components/bt/bluedroid/btc/core/btc_dm.c @@ -57,6 +57,9 @@ static btc_dm_local_key_cb_t ble_local_key_cb; extern bt_status_t btc_av_execute_service(BOOLEAN b_enable); extern bt_status_t btc_av_sink_execute_service(BOOLEAN b_enable); #endif +#if BTC_HF_CLIENT_INCLUDED +extern bt_status_t btc_hf_client_execute_service(BOOLEAN b_enable); +#endif /****************************************************************************** ** Functions ******************************************************************************/ @@ -396,6 +399,11 @@ static bt_status_t btc_in_execute_service_request(tBTA_SERVICE_ID service_id, btc_av_sink_execute_service(b_enable); break; #endif +#if BTC_HF_CLIENT_INCLUDED + case BTA_HFP_HS_SERVICE_ID: + btc_hf_client_execute_service(b_enable); + break; +#endif /* #if BTC_HF_CLIENT_INCLUDED */ default: BTC_TRACE_ERROR("%s: Unknown service being enabled\n", __FUNCTION__); return BT_STATUS_FAIL; diff --git a/components/bt/bluedroid/btc/core/btc_task.c b/components/bt/bluedroid/btc/core/btc_task.c index 1d14d7ecf..b8afbb581 100644 --- a/components/bt/bluedroid/btc/core/btc_task.c +++ b/components/bt/bluedroid/btc/core/btc_task.c @@ -42,6 +42,9 @@ #if CONFIG_BT_SPP_ENABLED #include "btc_spp.h" #endif /* #if CONFIG_BT_SPP_ENABLED */ +#if BTC_HF_CLIENT_INCLUDED +#include "btc_hf_client.h" +#endif /* #if BTC_HF_CLIENT_INCLUDED */ #endif /* #if CONFIG_CLASSIC_BT_ENABLED */ @@ -80,6 +83,9 @@ static btc_func_t profile_tab[BTC_PID_NUM] = { #if CONFIG_BT_SPP_ENABLED [BTC_PID_SPP] = {btc_spp_call_handler, btc_spp_cb_handler }, #endif /* #if CONFIG_BT_SPP_ENABLED */ +#if BTC_HF_CLIENT_INCLUDED + [BTC_PID_HF_CLIENT] = {btc_hf_client_call_handler, btc_hf_client_cb_handler}, +#endif /* #if BTC_HF_CLIENT_INCLUDED */ #endif /* #if CONFIG_CLASSIC_BT_ENABLED */ }; diff --git a/components/bt/bluedroid/btc/include/btc/btc_task.h b/components/bt/bluedroid/btc/include/btc/btc_task.h index 401f8ee7b..f644e865a 100644 --- a/components/bt/bluedroid/btc/include/btc/btc_task.h +++ b/components/bt/bluedroid/btc/include/btc/btc_task.h @@ -54,6 +54,9 @@ typedef enum { BTC_PID_A2DP, BTC_PID_AVRC, BTC_PID_SPP, +#if BTC_HF_CLIENT_INCLUDED + BTC_PID_HF_CLIENT, +#endif /* BTC_HF_CLIENT_INCLUDED */ #endif /* CONFIG_CLASSIC_BT_ENABLED */ BTC_PID_NUM, } btc_pid_t; //btc profile id diff --git a/components/bt/bluedroid/btc/profile/std/hf_client/bta_hf_client_co.c b/components/bt/bluedroid/btc/profile/std/hf_client/bta_hf_client_co.c new file mode 100644 index 000000000..27eda746d --- /dev/null +++ b/components/bt/bluedroid/btc/profile/std/hf_client/bta_hf_client_co.c @@ -0,0 +1,137 @@ +// Copyright 2018 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "bta/bta_hf_client_co.h" +#include "hci/hci_audio.h" +#include "btc_hf_client.h" +#if (BTA_HF_INCLUDED == TRUE) + +#if (BTM_SCO_HCI_INCLUDED == TRUE) +/******************************************************************************* +** +** Function bta_hf_client_co_audio_state +** +** Description This function is called by the HF CLIENT before the audio connection +** is brought up, after it comes up, and after it goes down. +** +** Parameters handle - handle of the AG instance +** state - Audio state +** codec - if WBS support is compiled in, codec to going to be used is provided +** and when in SCO_STATE_SETUP, BTM_I2SPCMConfig() must be called with +** the correct platform parameters. +** in the other states codec type should not be ignored +** +** Returns void +** +*******************************************************************************/ +void bta_hf_client_co_audio_state(UINT16 handle, UINT8 state, tBTA_HFP_PEER_CODEC codec) +{ + switch (state) + { + case SCO_STATE_ON: + case SCO_STATE_OFF: + case SCO_STATE_OFF_TRANSFER: + case SCO_STATE_SETUP: + default: + break; + } +} + +/******************************************************************************* +** +** Function bta_hf_client_sco_co_init +** +** Description This function can be used by the phone to initialize audio +** codec or for other initialization purposes before SCO connection +** is opened. +** +** +** Returns Void. +** +*******************************************************************************/ +tBTA_HFP_SCO_ROUTE_TYPE bta_hf_client_sco_co_init(UINT32 rx_bw, UINT32 tx_bw, + tBTA_HFP_CODEC_INFO *p_codec_info, UINT8 app_id) +{ + APPL_TRACE_EVENT("%s rx_bw %d, tx_bw %d, codec %d", __FUNCTION__, rx_bw, tx_bw, + p_codec_info->codec_type); + return BTA_HFP_SCO_ROUTE_HCI; +} + +/******************************************************************************* +** +** Function bta_hf_client_sco_co_open +** +** Description This function is executed when a SCO connection is open. +** +** +** Returns void +** +*******************************************************************************/ +void bta_hf_client_sco_co_open(UINT16 handle, UINT8 pkt_size, UINT16 event) +{ + APPL_TRACE_EVENT("%s hdl %x, pkt_sz %u, event %u", __FUNCTION__, handle, + pkt_size, event); +} + +/******************************************************************************* +** +** Function bta_hf_client_sco_co_close +** +** Description This function is called when a SCO connection is closed +** +** +** Returns void +** +*******************************************************************************/ +void bta_hf_client_sco_co_close(void) +{ + APPL_TRACE_EVENT("%s", __FUNCTION__); +} + +/******************************************************************************* +** +** Function bta_hf_client_sco_co_out_data +** +** Description This function is called to send SCO data over HCI. +** +** Returns number of bytes got from application +** +*******************************************************************************/ +uint32_t bta_hf_client_sco_co_out_data(uint8_t *p_buf, uint32_t sz) +{ + return btc_hf_client_outgoing_data_cb_to_app(p_buf, sz); +} + +/******************************************************************************* +** +** Function bta_hf_client_sco_co_in_data +** +** Description This function is called to send incoming SCO data to application. +** +** Returns void +** +*******************************************************************************/ +void bta_hf_client_sco_co_in_data(BT_HDR *p_buf, tBTM_SCO_DATA_FLAG status) +{ + UINT8 *p = (UINT8 *)(p_buf + 1) + p_buf->offset; + UINT8 pkt_size = 0; + + STREAM_SKIP_UINT16(p); + STREAM_TO_UINT8 (pkt_size, p); + btc_hf_client_incoming_data_cb_to_app(p, pkt_size); +} + +#endif /* #if (BTM_SCO_HCI_INCLUDED == TRUE) */ + +#endif /* #if (BTA_HF_INCLUDED == TRUE) */ diff --git a/components/bt/bluedroid/btc/profile/std/hf_client/btc_hf_client.c b/components/bt/bluedroid/btc/profile/std/hf_client/btc_hf_client.c new file mode 100644 index 000000000..1d927fe1d --- /dev/null +++ b/components/bt/bluedroid/btc/profile/std/hf_client/btc_hf_client.c @@ -0,0 +1,1089 @@ +// Copyright 2018 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/****************************************************************************** + ** + ** Name: btc_hf_client.c + ** + ******************************************************************************/ +#include "common/bt_target.h" +#include "common/bt_trace.h" +#include +#include +#include +#include +#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 + +#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) */ diff --git a/components/bt/bluedroid/btc/profile/std/include/btc_hf_client.h b/components/bt/bluedroid/btc/profile/std/include/btc_hf_client.h new file mode 100644 index 000000000..6500b9d87 --- /dev/null +++ b/components/bt/bluedroid/btc/profile/std/include/btc_hf_client.h @@ -0,0 +1,128 @@ +// Copyright 2018 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + + +/******************************************************************************* + * + * Filename: btc_hf_client.h + * + * Description: Main API header file for all BTC HF client functions accessed + * from internal stack. + * + *******************************************************************************/ + +#ifndef __BTC_HF_CLIENT_H__ +#define __BTC_HF_CLIENT_H__ + +#include "common/bt_target.h" +#include "esp_hf_client_api.h" +#include "btc/btc_task.h" +#include "btc/btc_common.h" +#include "bta/bta_hf_client_api.h" + +#if (BTC_HF_CLIENT_INCLUDED == TRUE) +/******************************************************************************* +** Type definitions for callback functions +********************************************************************************/ +typedef enum { + BTC_HF_CLIENT_INIT_EVT, + BTC_HF_CLIENT_DEINIT_EVT, + BTC_HF_CLIENT_CONNECT_EVT, + BTC_HF_CLIENT_DISCONNECT_EVT, + BTC_HF_CLIENT_CONNECT_AUDIO_EVT, + BTC_HF_CLIENT_DISCONNECT_AUDIO_EVT, + BTC_HF_CLIENT_START_VOICE_RECOGNITION_EVT, + BTC_HF_CLIENT_STOP_VOICE_RECOGNITION_EVT, + BTC_HF_CLIENT_VOLUME_UPDATE_EVT, + BTC_HF_CLIENT_DIAL_EVT, + BTC_HF_CLIENT_DIAL_MEMORY_EVT, + BTC_HF_CLIENT_SEND_CHLD_CMD_EVT, + BTC_HF_CLIENT_SEND_BTRH_CMD_EVT, + BTC_HF_CLIENT_ANSWER_CALL_EVT, + BTC_HF_CLIENT_REJECT_CALL_EVT, + BTC_HF_CLIENT_QUERY_CURRENT_CALLS_EVT, + BTC_HF_CLIENT_QUERY_CURRENT_OPERATOR_NAME_EVT, + BTC_HF_CLIENT_RETRIEVE_SUBSCRIBER_INFO_EVT, + BTC_HF_CLIENT_SEND_DTMF_EVT, + BTC_HF_CLIENT_REQUEST_LAST_VOICE_TAG_NUMBER_EVT, + BTC_HF_CLIENT_REGISTER_DATA_CALLBACK_EVT, +} btc_hf_client_act_t; + +/* btc_hf_client_args_t */ +typedef union { + // BTC_HF_CLIENT_CONNECT_EVT + bt_bdaddr_t connect; + + // BTC_HF_CLIENT_DISCONNECT_EVT + bt_bdaddr_t disconnect; + + // BTC_HF_CLIENT_CONNECT_AUDIO_EVT + bt_bdaddr_t connect_audio; + + // BTC_HF_CLIENT_DISCONNECT_AUDIO_EVT + bt_bdaddr_t disconnect_audio; + + // BTC_HF_CLIENT_VOLUME_UPDATE_EVT, + struct volume_update_args { + esp_hf_volume_control_target_t type; + int volume; + } volume_update; + + // BTC_HF_CLIENT_DIAL_EVT + struct dial_args { + char number[ESP_BT_HF_CLIENT_NUMBER_LEN + 1]; + } dial; + + // BTC_HF_CLIENT_DIAL_MEMORY_EVT + struct dial_memory_args { + int location; + } dial_memory; + + // BTC_HF_CLIENT_SEND_CHLD_CMD_EVT + struct send_chld_cmd_args { + esp_hf_chld_type_t type; + int idx; + } chld; + + // BTC_HF_CLIENT_SEND_BTRH_CMD_EVT + struct send_btrh_cmd_args { + esp_hf_btrh_cmd_t cmd; + } btrh; + + // BTC_HF_CLIENT_SEND_DTMF_EVT + struct send_dtmf { + char code; + } send_dtmf; + + // BTC_HF_CLIENT_REGISTER_DATA_CALLBACK_EVT + struct reg_data_callback { + esp_hf_client_incoming_data_cb_t recv; + esp_hf_client_outgoing_data_cb_t send; + } reg_data_cb; +} btc_hf_client_args_t; + +/******************************************************************************* +** BTC HF AG API +********************************************************************************/ + +void btc_hf_client_call_handler(btc_msg_t *msg); + +void btc_hf_client_cb_handler(btc_msg_t *msg); + +void btc_hf_client_incoming_data_cb_to_app(const uint8_t *data, uint32_t len); + +uint32_t btc_hf_client_outgoing_data_cb_to_app(uint8_t *data, uint32_t len); +#endif ///BTC_HF_CLIENT_INCLUDED == TRUE + +#endif /* __BTC_HF_CLIENT_H__ */ diff --git a/components/bt/bluedroid/common/include/common/bt_target.h b/components/bt/bluedroid/common/include/common/bt_target.h index 55b84b808..8f3205f9b 100644 --- a/components/bt/bluedroid/common/include/common/bt_target.h +++ b/components/bt/bluedroid/common/include/common/bt_target.h @@ -50,6 +50,7 @@ #define BTC_PRF_QUEUE_INCLUDED TRUE #define BTC_GAP_BT_INCLUDED TRUE #define BTA_SDP_INCLUDED TRUE +#define BTA_DM_PM_INCLUDED TRUE #define SDP_INCLUDED TRUE #if CONFIG_A2DP_ENABLE @@ -79,6 +80,20 @@ #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 @@ -190,6 +205,10 @@ #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 @@ -491,12 +510,16 @@ /* 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 */ @@ -516,7 +539,7 @@ *************************/ /* 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 */ @@ -580,11 +603,7 @@ /* 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). */ @@ -656,7 +675,7 @@ /* 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, @@ -710,9 +729,11 @@ #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 diff --git a/components/bt/bluedroid/device/controller.c b/components/bt/bluedroid/device/controller.c index 93ef5384e..06b8a52c7 100644 --- a/components/bt/bluedroid/device/controller.c +++ b/components/bt/bluedroid/device/controller.c @@ -16,6 +16,7 @@ * ******************************************************************************/ #include +#include "common/bt_target.h" #include "common/bt_trace.h" #include "device/bdaddr.h" #include "stack/bt_types.h" @@ -61,6 +62,9 @@ static uint16_t acl_data_size_ble; static uint16_t acl_buffer_count_classic; static uint8_t acl_buffer_count_ble; +static uint8_t sco_data_size; +static uint16_t sco_buffer_count; + static uint8_t ble_white_list_size; static uint8_t ble_resolving_list_max_size; static uint8_t ble_supported_states[BLE_SUPPORTED_STATES_SIZE]; @@ -88,7 +92,8 @@ static void start_up(void) // Request the classic buffer size next response = AWAIT_COMMAND(packet_factory->make_read_buffer_size()); packet_parser->parse_read_buffer_size_response( - response, &acl_data_size_classic, &acl_buffer_count_classic); + response, &acl_data_size_classic, &acl_buffer_count_classic, + &sco_data_size, &sco_buffer_count); // Tell the controller about our buffer sizes and buffer counts next // TODO(zachoverflow): factor this out. eww l2cap contamination. And why just a hardcoded 10? @@ -244,6 +249,10 @@ static void start_up(void) packet_parser->parse_generic_command_complete(response); } +#if (BTM_SCO_HCI_INCLUDED == TRUE) + response = AWAIT_COMMAND(packet_factory->make_write_sync_flow_control_enable(1)); + packet_parser->parse_generic_command_complete(response); +#endif readable = true; // return future_new_immediate(FUTURE_SUCCESS); return; @@ -447,6 +456,20 @@ static void set_ble_resolving_list_max_size(int resolving_list_max_size) ble_resolving_list_max_size = resolving_list_max_size; } +#if (BTM_SCO_HCI_INCLUDED == TRUE) +static uint8_t get_sco_data_size(void) +{ + assert(readable); + return sco_data_size; +} + +static uint8_t get_sco_buffer_count(void) +{ + assert(readable); + return sco_buffer_count; +} +#endif /* (BTM_SCO_HCI_INCLUDED == TRUE) */ + static const controller_t interface = { start_up, shut_down, @@ -489,7 +512,11 @@ static const controller_t interface = { get_ble_white_list_size, get_ble_resolving_list_max_size, - set_ble_resolving_list_max_size + set_ble_resolving_list_max_size, +#if (BTM_SCO_HCI_INCLUDED == TRUE) + get_sco_data_size, + get_sco_buffer_count, +#endif /* (BTM_SCO_HCI_INCLUDED == TRUE) */ }; const controller_t *controller_get_interface() diff --git a/components/bt/bluedroid/device/include/device/controller.h b/components/bt/bluedroid/device/include/device/controller.h index b2806d69b..704b456d7 100644 --- a/components/bt/bluedroid/device/include/device/controller.h +++ b/components/bt/bluedroid/device/include/device/controller.h @@ -79,6 +79,11 @@ typedef struct controller_t { uint8_t (*get_ble_resolving_list_max_size)(void); void (*set_ble_resolving_list_max_size)(int resolving_list_max_size); +#if (BTM_SCO_HCI_INCLUDED == TRUE) + // Get the number of sco packets the controller can buffer + uint8_t (*get_sco_data_size)(void); + uint8_t (*get_sco_buffer_count)(void); +#endif /* #if (BTM_SCO_HCI_INCLUDED == TRUE) */ } controller_t; const controller_t *controller_get_interface(); diff --git a/components/bt/bluedroid/hci/hci_audio.c b/components/bt/bluedroid/hci/hci_audio.c new file mode 100644 index 000000000..1983e7afd --- /dev/null +++ b/components/bt/bluedroid/hci/hci_audio.c @@ -0,0 +1,7 @@ +#include "hci/hci_audio.h" + +void set_audio_state(uint16_t handle, sco_codec_t codec, sco_state_t state) +{ + //todo + return; +} diff --git a/components/bt/bluedroid/hci/hci_packet_factory.c b/components/bt/bluedroid/hci/hci_packet_factory.c index 549323be6..2c88570e3 100644 --- a/components/bt/bluedroid/hci/hci_packet_factory.c +++ b/components/bt/bluedroid/hci/hci_packet_factory.c @@ -175,6 +175,15 @@ static BT_HDR *make_ble_set_event_mask(const bt_event_mask_t *event_mask) return packet; } +static BT_HDR *make_write_sync_flow_control_enable(uint8_t enable) +{ + uint8_t *stream; + const uint8_t parameter_size = 1; + BT_HDR *packet = make_command(HCI_WRITE_SCO_FLOW_CTRL_ENABLE, parameter_size, &stream); + + UINT8_TO_STREAM(stream, enable); + return packet; +} // Internal functions static BT_HDR *make_command_no_params(uint16_t opcode) @@ -227,7 +236,8 @@ static const hci_packet_factory_t interface = { make_ble_read_resolving_list_size, make_ble_read_suggested_default_data_length, make_ble_write_suggested_default_data_length, - make_ble_set_event_mask + make_ble_set_event_mask, + make_write_sync_flow_control_enable }; const hci_packet_factory_t *hci_packet_factory_get_interface() diff --git a/components/bt/bluedroid/hci/hci_packet_parser.c b/components/bt/bluedroid/hci/hci_packet_parser.c index 627d1ccb8..c2adee5e6 100644 --- a/components/bt/bluedroid/hci/hci_packet_parser.c +++ b/components/bt/bluedroid/hci/hci_packet_parser.c @@ -42,16 +42,18 @@ static void parse_generic_command_complete(BT_HDR *response) static void parse_read_buffer_size_response( BT_HDR *response, - uint16_t *data_size_ptr, - uint16_t *acl_buffer_count_ptr) + uint16_t *acl_data_size_ptr, + uint16_t *acl_buffer_count_ptr, + uint8_t *sco_data_size_ptr, + uint16_t *sco_buffer_count_ptr) { - uint8_t *stream = read_command_complete_header(response, HCI_READ_BUFFER_SIZE, 5 /* bytes after */); + uint8_t *stream = read_command_complete_header(response, HCI_READ_BUFFER_SIZE, 7 /* bytes after */); assert(stream != NULL); - STREAM_TO_UINT16(*data_size_ptr, stream); - STREAM_SKIP_UINT8(stream); // skip the sco packet length + STREAM_TO_UINT16(*acl_data_size_ptr, stream); + STREAM_TO_UINT8(*sco_data_size_ptr, stream); STREAM_TO_UINT16(*acl_buffer_count_ptr, stream); - + STREAM_TO_UINT16(*sco_buffer_count_ptr, stream); buffer_allocator->free(response); } diff --git a/components/bt/bluedroid/hci/include/hci/hci_audio.h b/components/bt/bluedroid/hci/include/hci/hci_audio.h new file mode 100644 index 000000000..a9234c3a0 --- /dev/null +++ b/components/bt/bluedroid/hci/include/hci/hci_audio.h @@ -0,0 +1,42 @@ +/****************************************************************************** + * + * Copyright (C) 2015 Google, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + +#ifndef _HCI_AUDIO_H_ +#define _HCI_AUDIO_H_ +#include + +// 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_ */ diff --git a/components/bt/bluedroid/hci/include/hci/hci_packet_factory.h b/components/bt/bluedroid/hci/include/hci/hci_packet_factory.h index b98b80d5d..0cc4dc684 100644 --- a/components/bt/bluedroid/hci/include/hci/hci_packet_factory.h +++ b/components/bt/bluedroid/hci/include/hci/hci_packet_factory.h @@ -42,6 +42,7 @@ typedef struct { BT_HDR *(*make_ble_read_suggested_default_data_length)(void); BT_HDR *(*make_ble_write_suggested_default_data_length)(uint16_t SuggestedMaxTxOctets, uint16_t SuggestedMaxTxTime); BT_HDR *(*make_ble_set_event_mask)(const bt_event_mask_t *event_mask); + BT_HDR *(*make_write_sync_flow_control_enable)(uint8_t enable); } hci_packet_factory_t; const hci_packet_factory_t *hci_packet_factory_get_interface(); diff --git a/components/bt/bluedroid/hci/include/hci/hci_packet_parser.h b/components/bt/bluedroid/hci/include/hci/hci_packet_parser.h index 2e5b5ef98..b0cc4b3b4 100644 --- a/components/bt/bluedroid/hci/include/hci/hci_packet_parser.h +++ b/components/bt/bluedroid/hci/include/hci/hci_packet_parser.h @@ -33,8 +33,10 @@ typedef struct { void (*parse_read_buffer_size_response)( BT_HDR *response, - uint16_t *data_size_ptr, - uint16_t *acl_buffer_count_ptr + uint16_t *acl_data_size_ptr, + uint16_t *acl_buffer_count_ptr, + uint8_t *sco_data_size_ptr, + uint16_t *sco_buffer_count_ptr ); void (*parse_read_local_version_info_response)( diff --git a/components/bt/bluedroid/main/bte_init.c b/components/bt/bluedroid/main/bte_init.c index 1b1395f4b..38cfc812f 100644 --- a/components/bt/bluedroid/main/bte_init.c +++ b/components/bt/bluedroid/main/bte_init.c @@ -89,7 +89,9 @@ #include "bta/bta_sys.h" #include "osi/allocator.h" -//#include "bta_ag_int.h" +#if BTA_HF_INCLUDED == TRUE +#include "bta_hf_client_int.h" +#endif #if BTA_SDP_INCLUDED == TRUE #include "bta_sdp_int.h" @@ -227,7 +229,13 @@ void BTE_InitStack(void) memset((void *)bta_dm_search_cb_ptr, 0, sizeof(tBTA_DM_SEARCH_CB)); memset((void *)bta_dm_di_cb_ptr, 0, sizeof(tBTA_DM_DI_CB)); //memset((void *)bta_prm_cb_ptr, 0, sizeof(tBTA_PRM_CB)); - //memset((void *)bta_ag_cb_ptr, 0, sizeof(tBTA_AG_CB)); + +#if (defined BTA_HF_INCLUDED && BTA_HF_INCLUDED == TRUE) + if ((bta_hf_client_cb_ptr = (tBTA_HF_CLIENT_CB *)osi_malloc(sizeof(tBTA_HF_CLIENT_CB))) == NULL) { + return; + } + memset((void *)bta_hf_client_cb_ptr, 0, sizeof(tBTA_HF_CLIENT_CB)); +#endif #if (defined BTA_JV_INCLUDED && BTA_JV_INCLUDED == TRUE) if ((bta_jv_cb_ptr = (tBTA_JV_CB *)osi_malloc(sizeof(tBTA_JV_CB))) == NULL) { return; @@ -327,6 +335,10 @@ void BTE_DeinitStack(void) osi_free(bta_jv_cb_ptr); bta_jv_cb_ptr = NULL; #endif //JV +#if (defined BTA_HF_INCLUDED && BTA_HF_INCLUDED == TRUE) + osi_free(bta_hf_client_cb_ptr); + bta_hf_client_cb_ptr = NULL; +#endif osi_free(bta_dm_di_cb_ptr); bta_dm_di_cb_ptr = NULL; osi_free(bta_dm_search_cb_ptr); @@ -354,4 +366,4 @@ void BTE_DeinitStack(void) #if (defined(A2D_INCLUDED) && A2D_INCLUDED == TRUE) A2D_Deinit(); #endif -} \ No newline at end of file +} diff --git a/components/bt/bluedroid/stack/btm/btm_devctl.c b/components/bt/bluedroid/stack/btm/btm_devctl.c index 085cda925..41bfb92f0 100644 --- a/components/bt/bluedroid/stack/btm/btm_devctl.c +++ b/components/bt/bluedroid/stack/btm/btm_devctl.c @@ -170,6 +170,9 @@ static void reset_complete(void) btm_pm_reset(); l2c_link_processs_num_bufs(controller->get_acl_buffer_count_classic()); +#if BTM_SCO_HCI_INCLUDED == TRUE + btm_sco_process_num_bufs(controller->get_sco_buffer_count()); +#endif #if (BLE_INCLUDED == TRUE) #if (defined BLE_PRIVACY_SPT && BLE_PRIVACY_SPT == TRUE) diff --git a/components/bt/bluedroid/stack/btm/btm_sco.c b/components/bt/bluedroid/stack/btm/btm_sco.c index d9b257d17..e04209aab 100644 --- a/components/bt/bluedroid/stack/btm/btm_sco.c +++ b/components/bt/bluedroid/stack/btm/btm_sco.c @@ -30,6 +30,7 @@ #include "stack/hcimsgs.h" #include "stack/btu.h" #include "stack/btm_api.h" +#include "osi/allocator.h" #include "btm_int.h" #include "stack/hcidefs.h" //#include "bt_utils.h" @@ -109,6 +110,11 @@ void btm_sco_init (void) { #if 0 /* cleared in btm_init; put back in if called from anywhere else! */ memset (&btm_cb.sco_cb, 0, sizeof(tSCO_CB)); +#endif +#if (BTM_SCO_HCI_INCLUDED == TRUE) + for (int i = 0; i < BTM_MAX_SCO_LINKS; i++) { + btm_cb.sco_cb.sco_db[i].xmit_data_q = fixed_queue_new(SIZE_MAX); + } #endif /* Initialize nonzero defaults */ btm_cb.sco_cb.sco_disc_reason = BTM_INVALID_SCO_DISC_REASON; @@ -207,6 +213,66 @@ static void btm_esco_conn_rsp (UINT16 sco_inx, UINT8 hci_status, BD_ADDR bda, #if BTM_SCO_HCI_INCLUDED == TRUE +void btm_sco_process_num_bufs (UINT16 num_lm_sco_bufs) +{ + BTM_TRACE_ERROR("%s, %d", __FUNCTION__, num_lm_sco_bufs); + btm_cb.sco_cb.num_lm_sco_bufs = btm_cb.sco_cb.xmit_window_size = num_lm_sco_bufs; +} + +/******************************************************************************* +** +** Function BTM_ConfigScoPath +** +** Description This function enable/disable SCO over HCI and registers SCO +** data callback if SCO over HCI is enabled. +** +** Parameter path: SCO or HCI +** p_sco_data_cb: callback function or SCO data if path is set +** to transport. +** p_pcm_param: pointer to the PCM interface parameter. If a NULL +** pointer is used, PCM parameter maintained in +** the control block will be used; otherwise update +** control block value. +** err_data_rpt: Lisbon feature to enable the erronous data report +** or not. +** +** Returns BTM_SUCCESS if the successful. +** BTM_NO_RESOURCES: no rsource to start the command. +** BTM_ILLEGAL_VALUE: invalid callback function pointer. +** BTM_CMD_STARTED :Command sent. Waiting for command cmpl event. +** +** +*******************************************************************************/ +//extern +tBTM_STATUS BTM_ConfigScoPath (tBTM_SCO_ROUTE_TYPE path, + tBTM_SCO_DATA_CB *p_sco_data_cb, + tBTM_SCO_PCM_PARAM *p_pcm_param, + BOOLEAN err_data_rpt) +{ + UNUSED(err_data_rpt); + UNUSED(p_pcm_param); + btm_cb.sco_cb.sco_path = path; + if (path == BTM_SCO_ROUTE_PCM) { + return BTM_SUCCESS; + } else if (path == BTM_SCO_ROUTE_HCI) { + if (p_sco_data_cb) { + btm_cb.sco_cb.p_data_cb = p_sco_data_cb; + } + } + + return BTM_SUCCESS; +} + +static void hci_sco_data_to_lower(BT_HDR *p_buf) +{ + p_buf->event = BT_EVT_TO_LM_HCI_SCO; + if (p_buf->offset == 0) { + BTM_TRACE_ERROR("offset cannot be 0"); + osi_free(p_buf); + } + + bte_main_hci_send(p_buf, (UINT16)(BT_EVT_TO_LM_HCI_SCO | LOCAL_BLE_CONTROLLER_ID)); +} /******************************************************************************* ** ** Function btm_sco_check_send_pkts @@ -224,16 +290,58 @@ void btm_sco_check_send_pkts (UINT16 sco_inx) /* If there is data to send, send it now */ BT_HDR *p_buf; - while ((p_buf = (BT_HDR *)fixed_queue_try_dequeue(p_ccb->xmit_data_q)) != NULL) + while (p_cb->xmit_window_size != 0) { + if ((p_buf = (BT_HDR *)fixed_queue_try_dequeue(p_ccb->xmit_data_q)) == NULL) { + break; + } #if BTM_SCO_HCI_DEBUG BTM_TRACE_DEBUG("btm: [%d] buf in xmit_data_q", fixed_queue_length(p_ccb->xmit_data_q) + 1); #endif + /* Don't go negative */ + p_cb->xmit_window_size -= 1; + p_ccb->sent_not_acked += 1; - HCI_SCO_DATA_TO_LOWER(p_buf); + // HCI_SCO_DATA_TO_LOWER(p_buf); + hci_sco_data_to_lower(p_buf); } } + +void btm_sco_process_num_completed_pkts (UINT8 *p) +{ + UINT8 num_handles, xx; + UINT16 handle; + UINT16 num_sent; + UINT16 sco_inx; + tSCO_CB *p_cb = &btm_cb.sco_cb; + tSCO_CONN * p_ccb; + STREAM_TO_UINT8 (num_handles, p); + for (xx = 0; xx < num_handles; xx++) { + STREAM_TO_UINT16 (handle, p); + handle &= 0x7ff; // walk around for bad handle bit mask from controller + STREAM_TO_UINT16 (num_sent, p); + if ((sco_inx = btm_find_scb_by_handle(handle & 0x7ff)) == BTM_MAX_SCO_LINKS) { + continue; + } + BTM_TRACE_DEBUG("%s, %d, %u", __FUNCTION__, handle, p_cb->xmit_window_size); //debug + p_ccb = &p_cb->sco_db[sco_inx]; + p_ccb->sent_not_acked -= num_sent; + // don't go negative + if (p_ccb->sent_not_acked < 0) { + BTM_TRACE_WARNING("SCO: un-acked underf: %u", p_ccb->sent_not_acked); + p_ccb->sent_not_acked = 0; + } + p_cb->xmit_window_size += num_sent; + if (p_cb->xmit_window_size > p_cb->num_lm_sco_bufs) { + BTM_TRACE_WARNING("SCO xwind: %d, max %d", p_cb->xmit_window_size, p_cb->num_lm_sco_bufs); + p_cb->xmit_window_size = p_cb->num_lm_sco_bufs; + } + btm_sco_check_send_pkts (sco_inx); + } + + return; +} #endif /* BTM_SCO_HCI_INCLUDED == TRUE */ /******************************************************************************* @@ -259,7 +367,7 @@ void btm_route_sco_data(BT_HDR *p_msg) handle = HCID_GET_HANDLE (handle); STREAM_TO_UINT8 (pkt_size, p); - + UNUSED(pkt_size); if ((sco_inx = btm_find_scb_by_handle(handle)) != BTM_MAX_SCO_LINKS ) { /* send data callback */ if (!btm_cb.sco_cb.p_data_cb ) @@ -272,6 +380,7 @@ void btm_route_sco_data(BT_HDR *p_msg) } else { /* no mapping handle SCO connection is active, free the buffer */ osi_free (p_msg); } + BTM_TRACE_DEBUG ("SCO: hdl %x, len %d, pkt_sz %d\n", handle, p_msg->len, pkt_size); #else osi_free(p_msg); #endif @@ -295,11 +404,13 @@ void btm_route_sco_data(BT_HDR *p_msg) ** BTM_NO_RESOURCES: no resources. ** BTM_UNKNOWN_ADDR: unknown SCO connection handle, or SCO is not ** routed via HCI. +** BTM_ERR_PROCESSING: transmit queue overflow ** ** *******************************************************************************/ tBTM_STATUS BTM_WriteScoData (UINT16 sco_inx, BT_HDR *p_buf) { + APPL_TRACE_DEBUG("%s", __FUNCTION__); #if (BTM_SCO_HCI_INCLUDED == TRUE) && (BTM_MAX_SCO_LINKS>0) tSCO_CONN *p_ccb = &btm_cb.sco_cb.sco_db[sco_inx]; UINT8 *p; @@ -310,7 +421,6 @@ tBTM_STATUS BTM_WriteScoData (UINT16 sco_inx, BT_HDR *p_buf) /* Ensure we have enough space in the buffer for the SCO and HCI headers */ if (p_buf->offset < HCI_SCO_PREAMBLE_SIZE) { BTM_TRACE_ERROR ("BTM SCO - cannot send buffer, offset: %d", p_buf->offset); - osi_free (p_buf); status = BTM_ILLEGAL_VALUE; } else { /* write HCI header */ /* Step back 3 bytes to add the headers */ @@ -327,20 +437,27 @@ tBTM_STATUS BTM_WriteScoData (UINT16 sco_inx, BT_HDR *p_buf) } UINT8_TO_STREAM (p, (UINT8)p_buf->len); + BTM_TRACE_DEBUG ("BTM SCO hdl %x, len %u", p_ccb->hci_handle, p_buf->len); p_buf->len += HCI_SCO_PREAMBLE_SIZE; - fixed_queue_enqueue(p_ccb->xmit_data_q, p_buf); - - btm_sco_check_send_pkts (sco_inx); + if (fixed_queue_length(p_ccb->xmit_data_q) < BTM_SCO_XMIT_QUEUE_THRS) { + fixed_queue_enqueue(p_ccb->xmit_data_q, p_buf); + btm_sco_check_send_pkts (sco_inx); + } else { + BTM_TRACE_WARNING ("SCO xmit Q overflow, pkt dropped"); + status = BTM_ERR_PROCESSING; + } } } else { - osi_free(p_buf); - BTM_TRACE_WARNING ("BTM_WriteScoData, invalid sco index: %d at state [%d]", sco_inx, btm_cb.sco_cb.sco_db[sco_inx].state); status = BTM_UNKNOWN_ADDR; } + if (status != BTM_SUCCESS && status != BTM_SCO_BAD_LENGTH) { + BTM_TRACE_WARNING ("stat %d", status); + osi_free(p_buf); + } return (status); #else @@ -839,7 +956,7 @@ void btm_sco_connected (UINT8 hci_status, BD_ADDR bda, UINT16 hci_handle, #endif btm_cb.sco_cb.sco_disc_reason = hci_status; - + BTM_TRACE_ERROR("%s, handle %x", __FUNCTION__, hci_handle); #if (BTM_MAX_SCO_LINKS>0) for (xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++) { if (((p->state == SCO_ST_CONNECTING) || @@ -876,7 +993,9 @@ void btm_sco_connected (UINT8 hci_status, BD_ADDR bda, UINT16 hci_handle, if (p->state == SCO_ST_LISTENING) { spt = TRUE; } - +#if BTM_SCO_HCI_INCLUDED == TRUE + p->sent_not_acked = 0; +#endif p->state = SCO_ST_CONNECTED; p->hci_handle = hci_handle; @@ -1022,6 +1141,14 @@ void btm_sco_removed (UINT16 hci_handle, UINT8 reason) btm_sco_flush_sco_data(xx); p->state = SCO_ST_UNUSED; +#if BTM_SCO_HCI_INCLUDED == TRUE + btm_cb.sco_cb.xmit_window_size += p->sent_not_acked; + /* avoid overflow */ + if (btm_cb.sco_cb.xmit_window_size > btm_cb.sco_cb.num_lm_sco_bufs) { + btm_cb.sco_cb.xmit_window_size = btm_cb.sco_cb.num_lm_sco_bufs; + } + p->sent_not_acked = 0; +#endif p->hci_handle = BTM_INVALID_HCI_HANDLE; p->rem_bd_known = FALSE; p->esco.p_esco_cback = NULL; /* Deregister eSCO callback */ diff --git a/components/bt/bluedroid/stack/btm/include/btm_int.h b/components/bt/bluedroid/stack/btm/include/btm_int.h index 5922a5814..bde7af9a2 100644 --- a/components/bt/bluedroid/stack/btm/include/btm_int.h +++ b/components/bt/bluedroid/stack/btm/include/btm_int.h @@ -365,7 +365,9 @@ typedef struct { typedef struct { tBTM_ESCO_INFO esco; /* Current settings */ #if BTM_SCO_HCI_INCLUDED == TRUE +#define BTM_SCO_XMIT_QUEUE_THRS 20 fixed_queue_t *xmit_data_q; /* SCO data transmitting queue */ + INT16 sent_not_acked; #endif tBTM_SCO_CB *p_conn_cb; /* Callback for when connected */ tBTM_SCO_CB *p_disc_cb; /* Callback for when disconnect */ @@ -382,6 +384,7 @@ typedef struct { #if BTM_SCO_HCI_INCLUDED == TRUE tBTM_SCO_DATA_CB *p_data_cb; /* Callback for SCO data over HCI */ UINT32 xmit_window_size; /* Total SCO window in bytes */ + UINT16 num_lm_sco_bufs; #endif tSCO_CONN sco_db[BTM_MAX_SCO_LINKS]; tBTM_ESCO_PARAMS def_esco_parms; @@ -996,6 +999,10 @@ void btm_pm_proc_mode_change (UINT8 hci_status, UINT16 hci_handle, UINT8 mode, void btm_pm_proc_ssr_evt (UINT8 *p, UINT16 evt_len); #if BTM_SCO_INCLUDED == TRUE void btm_sco_chk_pend_unpark (UINT8 hci_status, UINT16 hci_handle); +#if (BTM_SCO_HCI_INCLUDED == TRUE ) +void btm_sco_process_num_bufs (UINT16 num_lm_sco_bufs); +void btm_sco_process_num_completed_pkts (UINT8 *p); +#endif /* (BTM_SCO_HCI_INCLUDED == TRUE ) */ #else #define btm_sco_chk_pend_unpark(hci_status, hci_handle) #endif /* BTM_SCO_INCLUDED */ diff --git a/components/bt/bluedroid/stack/btu/btu_hcif.c b/components/bt/bluedroid/stack/btu/btu_hcif.c index f0d50ed42..09f5af491 100644 --- a/components/bt/bluedroid/stack/btu/btu_hcif.c +++ b/components/bt/bluedroid/stack/btu/btu_hcif.c @@ -1292,7 +1292,9 @@ static void btu_hcif_num_compl_data_pkts_evt (UINT8 *p) l2c_link_process_num_completed_pkts (p); /* Send on to SCO */ - /*?? No SCO for now */ +#if (BTM_SCO_HCI_INCLUDED == TRUE) && (BTM_SCO_INCLUDED == TRUE) + btm_sco_process_num_completed_pkts (p); +#endif } /******************************************************************************* diff --git a/components/bt/bluedroid/stack/include/stack/btm_api.h b/components/bt/bluedroid/stack/include/stack/btm_api.h index 294cf84ce..79ecba8c8 100644 --- a/components/bt/bluedroid/stack/include/stack/btm_api.h +++ b/components/bt/bluedroid/stack/include/stack/btm_api.h @@ -955,8 +955,8 @@ typedef UINT8 tBTM_SCO_TYPE; /******************* ** SCO Routing Path ********************/ -#define BTM_SCO_ROUTE_PCM HCI_BRCM_SCO_ROUTE_PCM -#define BTM_SCO_ROUTE_HCI HCI_BRCM_SCO_ROUTE_HCI +#define BTM_SCO_ROUTE_PCM (0) // HCI_BRCM_SCO_ROUTE_PCM +#define BTM_SCO_ROUTE_HCI (1) // HCI_BRCM_SCO_ROUTE_HCI typedef UINT8 tBTM_SCO_ROUTE_TYPE; diff --git a/components/bt/bluedroid/stack/rfcomm/port_rfc.c b/components/bt/bluedroid/stack/rfcomm/port_rfc.c index b227ea5cf..46b3e0711 100644 --- a/components/bt/bluedroid/stack/rfcomm/port_rfc.c +++ b/components/bt/bluedroid/stack/rfcomm/port_rfc.c @@ -833,7 +833,7 @@ void PORT_DataInd (tRFC_MCB *p_mcb, UINT8 dlci, BT_HDR *p_buf) //osi_free (p_buf); return; } else { - RFCOMM_TRACE_ERROR("PORT_DataInd, p_port:%p, p_data_co_callback is null", p_port); + RFCOMM_TRACE_DEBUG("PORT_DataInd, p_port:%p, p_data_co_callback is null", p_port); } /* If client registered callback we can just deliver receive data */ if (p_port->p_data_callback) { @@ -1094,4 +1094,4 @@ void port_get_credits (tPORT *p_port, UINT8 k) } -#endif ///(defined RFCOMM_INCLUDED && RFCOMM_INCLUDED == TRUE) \ No newline at end of file +#endif ///(defined RFCOMM_INCLUDED && RFCOMM_INCLUDED == TRUE) diff --git a/components/bt/bt.c b/components/bt/bt.c index 68f5dee7f..eeb374f1f 100644 --- a/components/bt/bt.c +++ b/components/bt/bt.c @@ -97,6 +97,7 @@ extern int ble_txpwr_set(int power_type, int power_level); extern int ble_txpwr_get(int power_type); extern int bredr_txpwr_set(int min_power_level, int max_power_level); extern int bredr_txpwr_get(int *min_power_level, int *max_power_level); +extern void bredr_sco_datapath_set(uint8_t data_path); extern char _bss_start_btdm; extern char _bss_end_btdm; @@ -1103,4 +1104,13 @@ void esp_bt_controller_wakeup_request(void) btdm_wakeup_request(); } +esp_err_t esp_bredr_sco_datapath_set(esp_sco_data_path_t data_path) +{ + if (btdm_controller_status != ESP_BT_CONTROLLER_STATUS_ENABLED) { + return ESP_ERR_INVALID_STATE; + } + bredr_sco_datapath_set(data_path); + return ESP_OK; +} + #endif /* CONFIG_BT_ENABLED */ diff --git a/components/bt/component.mk b/components/bt/component.mk index 8de4d6889..f0c1f1202 100644 --- a/components/bt/component.mk +++ b/components/bt/component.mk @@ -25,6 +25,7 @@ ifdef CONFIG_BLUEDROID_ENABLED COMPONENT_PRIV_INCLUDEDIRS += bluedroid/bta/include \ bluedroid/bta/ar/include \ bluedroid/bta/av/include \ + bluedroid/bta/hf_client/include \ bluedroid/bta/dm/include \ bluedroid/bta/gatt/include \ bluedroid/bta/hh/include \ @@ -75,6 +76,7 @@ COMPONENT_SRCDIRS += bluedroid/bta/dm \ bluedroid/bta/ar \ bluedroid/bta/sys \ bluedroid/bta/jv \ + bluedroid/bta/hf_client \ bluedroid/bta \ bluedroid/btcore \ bluedroid/btif \ @@ -92,6 +94,7 @@ COMPONENT_SRCDIRS += bluedroid/bta/dm \ bluedroid/btc/profile/std/a2dp \ bluedroid/btc/profile/std/avrc \ bluedroid/btc/profile/std/spp \ + bluedroid/btc/profile/std/hf_client \ bluedroid/btc/profile \ bluedroid/stack/btm \ bluedroid/stack/btu \ @@ -111,5 +114,4 @@ COMPONENT_SRCDIRS += bluedroid/bta/dm \ bluedroid/utils \ bluedroid/api \ bluedroid - endif diff --git a/components/bt/include/esp_bt.h b/components/bt/include/esp_bt.h index 9924420f6..2b06c09d1 100644 --- a/components/bt/include/esp_bt.h +++ b/components/bt/include/esp_bt.h @@ -122,6 +122,14 @@ typedef enum { ESP_PWR_LVL_P7 = 7, /*!< Corresponding to 7dbm */ } esp_power_level_t; +/** + * @brief Bluetooth audio data transport path + */ +typedef enum { + ESP_SCO_DATA_PATH_HCI = 0, /*!< data over HCI transport */ + ESP_SCO_DATA_PATH_PCM = 1, /*!< data over PCM interface */ +} esp_sco_data_path_t; + /** * @brief Set BLE TX power * Connection Tx power should only be set after connection created. @@ -164,6 +172,13 @@ esp_err_t esp_bredr_tx_power_set(esp_power_level_t min_power_level, esp_power_le */ esp_err_t esp_bredr_tx_power_get(esp_power_level_t *min_power_level, esp_power_level_t *max_power_level); +/** + * @brief set default SCO data path + * Should be called after controller is enabled, and before (e)SCO link is established + * @param data_path: SCO data path + * @return ESP_OK - success, other - failed + */ +esp_err_t esp_bredr_sco_datapath_set(esp_sco_data_path_t data_path); /** * @brief Initialize BT controller to allocate task and other resource. diff --git a/components/bt/lib b/components/bt/lib index 700d2bc91..16516d700 160000 --- a/components/bt/lib +++ b/components/bt/lib @@ -1 +1 @@ -Subproject commit 700d2bc914b755b840a0adeaa9d1ff45b398b6fa +Subproject commit 16516d7009f1c31c21939047447a95238194de40 diff --git a/components/esp32/ld/esp32.rom.ld b/components/esp32/ld/esp32.rom.ld index 6529aacb9..8c458ff14 100644 --- a/components/esp32/ld/esp32.rom.ld +++ b/components/esp32/ld/esp32.rom.ld @@ -1704,6 +1704,7 @@ PROVIDE ( ets_update_cpu_frequency_rom = 0x40008550 ); /* Updates g_ticks_per_u PROVIDE ( hci_tl_env = 0x3ffb8154 ); PROVIDE ( ld_acl_env = 0x3ffb8258 ); PROVIDE ( ea_env = 0x3ffb80ec ); +PROVIDE ( lc_sco_data_path_config = 0x3ffb81f8 ); PROVIDE ( ld_active_ch_map = 0x3ffb8334 ); PROVIDE ( ld_bcst_acl_env = 0x3ffb8274 ); PROVIDE ( ld_csb_rx_env = 0x3ffb8278 ); diff --git a/docs/Doxyfile b/docs/Doxyfile index 7c1ac334d..481eaa3fe 100644 --- a/docs/Doxyfile +++ b/docs/Doxyfile @@ -51,6 +51,8 @@ INPUT = \ ../../components/bt/bluedroid/api/include/api/esp_a2dp_api.h \ ../../components/bt/bluedroid/api/include/api/esp_avrc_api.h \ ../../components/bt/bluedroid/api/include/api/esp_spp_api.h \ + ../../components/bt/bluedroid/api/include/api/esp_hf_defs.h \ + ../../components/bt/bluedroid/api/include/api/esp_hf_client_api.h \ ## ## Ethernet - API Reference ## diff --git a/docs/en/api-reference/bluetooth/classic_bt.rst b/docs/en/api-reference/bluetooth/classic_bt.rst index 2fd161e71..3a9a30430 100644 --- a/docs/en/api-reference/bluetooth/classic_bt.rst +++ b/docs/en/api-reference/bluetooth/classic_bt.rst @@ -8,3 +8,5 @@ CLASSIC BT BT A2DP BT AVRC BT SPP + BT HFP Define + BT HFP Client diff --git a/docs/en/api-reference/bluetooth/esp_hf_client.rst b/docs/en/api-reference/bluetooth/esp_hf_client.rst new file mode 100644 index 000000000..7c8a2d88c --- /dev/null +++ b/docs/en/api-reference/bluetooth/esp_hf_client.rst @@ -0,0 +1,14 @@ +HFP CLIENT API +============== + +Overview +-------- + +`Instructions`_ + +.. _Instructions: ../template.html + +API Reference +------------- + +.. include:: /_build/inc/esp_hf_client_api.inc diff --git a/docs/en/api-reference/bluetooth/esp_hf_defs.rst b/docs/en/api-reference/bluetooth/esp_hf_defs.rst new file mode 100644 index 000000000..615b62386 --- /dev/null +++ b/docs/en/api-reference/bluetooth/esp_hf_defs.rst @@ -0,0 +1,16 @@ +HFP DEFINES +=========== + +Overview +-------- + +`Instructions`_ + +.. _Instructions: ../template.html + +API Reference +------------- + +.. include:: /_build/inc/esp_hf_defs.inc + + diff --git a/docs/zh_CN/api-reference/bluetooth/esp_hf_client.rst b/docs/zh_CN/api-reference/bluetooth/esp_hf_client.rst new file mode 100644 index 000000000..160f0b2df --- /dev/null +++ b/docs/zh_CN/api-reference/bluetooth/esp_hf_client.rst @@ -0,0 +1 @@ +.. include:: ../../../en/api-reference/bluetooth/esp_hf_client.rst diff --git a/docs/zh_CN/api-reference/bluetooth/esp_hf_defs.rst b/docs/zh_CN/api-reference/bluetooth/esp_hf_defs.rst new file mode 100644 index 000000000..f863457f2 --- /dev/null +++ b/docs/zh_CN/api-reference/bluetooth/esp_hf_defs.rst @@ -0,0 +1 @@ +.. include:: ../../../en/api-reference/bluetooth/esp_hf_defs.rst