forked from espressif/esp-idf
Merge branch 'feature/bt_support_external_codec' into 'master'
feat(bt/bluedroid): Support external codec in Bluedroid HFP and A2DP Closes BT-3937 See merge request espressif/esp-idf!36607
This commit is contained in:
@@ -288,7 +288,9 @@ if(CONFIG_BT_ENABLED)
|
||||
"host/bluedroid/btc/profile/std/a2dp/btc_a2dp.c"
|
||||
"host/bluedroid/btc/profile/std/a2dp/btc_a2dp_control.c"
|
||||
"host/bluedroid/btc/profile/std/a2dp/btc_a2dp_sink.c"
|
||||
"host/bluedroid/btc/profile/std/a2dp/btc_a2dp_sink_ext_coedc.c"
|
||||
"host/bluedroid/btc/profile/std/a2dp/btc_a2dp_source.c"
|
||||
"host/bluedroid/btc/profile/std/a2dp/btc_a2dp_source_ext_codec.c"
|
||||
"host/bluedroid/btc/profile/std/a2dp/btc_av.c"
|
||||
"host/bluedroid/btc/profile/std/avrc/btc_avrc.c"
|
||||
"host/bluedroid/btc/profile/std/avrc/bta_avrc_co.c"
|
||||
|
@@ -89,6 +89,15 @@ config BT_A2DP_ENABLE
|
||||
help
|
||||
Advanced Audio Distribution Profile
|
||||
|
||||
config BT_A2DP_USE_EXTERNAL_CODEC
|
||||
bool "Use External Codec for A2DP"
|
||||
depends on BT_A2DP_ENABLE
|
||||
default n
|
||||
help
|
||||
If enable, user shall register audio codec capability to A2DP and encode/decode
|
||||
audio data in application layer. The internal codec in A2DP will be remove in
|
||||
the future, it is recommend to use external codec for new design.
|
||||
|
||||
config BT_AVRCP_ENABLED
|
||||
bool
|
||||
depends on BT_A2DP_ENABLE
|
||||
@@ -184,6 +193,15 @@ choice BT_HFP_AUDIO_DATA_PATH
|
||||
bool "HCI"
|
||||
endchoice
|
||||
|
||||
config BT_HFP_USE_EXTERNAL_CODEC
|
||||
bool "Use External Codec for HFP"
|
||||
depends on BT_HFP_ENABLE && BT_HFP_AUDIO_DATA_PATH_HCI
|
||||
default n
|
||||
help
|
||||
If enable, user shall encode/decode audio data in application layer. The internal
|
||||
codec in HFP will be remove in the future, it is recommend to use external codec
|
||||
for new design.
|
||||
|
||||
config BT_HFP_WBS_ENABLE
|
||||
bool "Wide Band Speech"
|
||||
depends on BT_HFP_ENABLE && BT_HFP_AUDIO_DATA_PATH_HCI
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -14,6 +14,37 @@
|
||||
|
||||
#if BTC_AV_INCLUDED
|
||||
|
||||
esp_a2d_audio_buff_t *esp_a2d_audio_buff_alloc(uint16_t size)
|
||||
{
|
||||
if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (size == 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uint8_t *p_buf = NULL, *p_data;
|
||||
btc_av_audio_buff_alloc(size, &p_buf, &p_data);
|
||||
if (p_buf == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
esp_a2d_audio_buff_t *audio_buf = (esp_a2d_audio_buff_t *)p_buf;
|
||||
audio_buf->buff_size = size;
|
||||
audio_buf->data_len = 0;
|
||||
audio_buf->data = p_data;
|
||||
return audio_buf;
|
||||
}
|
||||
|
||||
void esp_a2d_audio_buff_free(esp_a2d_audio_buff_t *audio_buf)
|
||||
{
|
||||
if (audio_buf == NULL) {
|
||||
return;
|
||||
}
|
||||
btc_av_audio_buff_free((uint8_t *)audio_buf);
|
||||
}
|
||||
|
||||
#if BTC_AV_SINK_INCLUDED
|
||||
esp_err_t esp_a2d_sink_init(void)
|
||||
{
|
||||
@@ -36,6 +67,35 @@ esp_err_t esp_a2d_sink_init(void)
|
||||
return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
|
||||
}
|
||||
|
||||
esp_err_t esp_a2d_sink_register_stream_endpoint(uint8_t seid, const esp_a2d_mcc_t *mcc)
|
||||
{
|
||||
if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
if (g_a2dp_on_deinit || g_a2dp_sink_ongoing_deinit) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
if (seid >= ESP_A2D_MAX_SEPS) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
btc_msg_t msg;
|
||||
msg.sig = BTC_SIG_API_CALL;
|
||||
msg.pid = BTC_PID_A2DP;
|
||||
msg.act = BTC_AV_SINK_API_REG_SEP_EVT;
|
||||
|
||||
btc_av_args_t arg;
|
||||
memset(&arg, 0, sizeof(btc_av_args_t));
|
||||
arg.reg_sep.seid = seid;
|
||||
memcpy(&arg.reg_sep.mcc, mcc, sizeof(esp_a2d_mcc_t));
|
||||
|
||||
/* Switch to BTC context */
|
||||
bt_status_t stat = btc_transfer_context(&msg, &arg, sizeof(btc_av_args_t), NULL, NULL);
|
||||
return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
|
||||
}
|
||||
|
||||
esp_err_t esp_a2d_sink_deinit(void)
|
||||
{
|
||||
if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
|
||||
@@ -81,6 +141,30 @@ esp_err_t esp_a2d_sink_register_data_callback(esp_a2d_sink_data_cb_t callback)
|
||||
return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
|
||||
}
|
||||
|
||||
esp_err_t esp_a2d_sink_register_audio_data_callback(esp_a2d_sink_audio_data_cb_t callback)
|
||||
{
|
||||
if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
if (g_a2dp_sink_ongoing_deinit) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
btc_msg_t msg;
|
||||
msg.sig = BTC_SIG_API_CALL;
|
||||
msg.pid = BTC_PID_A2DP;
|
||||
msg.act = BTC_AV_SINK_API_REG_AUDIO_DATA_CB_EVT;
|
||||
|
||||
btc_av_args_t arg;
|
||||
memset(&arg, 0, sizeof(btc_av_args_t));
|
||||
arg.audio_data_cb = callback;
|
||||
|
||||
/* Switch to BTC context */
|
||||
bt_status_t stat = btc_transfer_context(&msg, &arg, sizeof(btc_av_args_t), NULL, NULL);
|
||||
return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
|
||||
}
|
||||
|
||||
esp_err_t esp_a2d_sink_connect(esp_bd_addr_t remote_bda)
|
||||
{
|
||||
if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
|
||||
@@ -251,6 +335,35 @@ esp_err_t esp_a2d_source_init(void)
|
||||
return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
|
||||
}
|
||||
|
||||
esp_err_t esp_a2d_source_register_stream_endpoint(uint8_t seid, const esp_a2d_mcc_t *mcc)
|
||||
{
|
||||
if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
if (g_a2dp_on_deinit || g_a2dp_sink_ongoing_deinit) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
if (seid >= ESP_A2D_MAX_SEPS) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
btc_msg_t msg;
|
||||
msg.sig = BTC_SIG_API_CALL;
|
||||
msg.pid = BTC_PID_A2DP;
|
||||
msg.act = BTC_AV_SRC_API_REG_SEP_EVT;
|
||||
|
||||
btc_av_args_t arg;
|
||||
memset(&arg, 0, sizeof(btc_av_args_t));
|
||||
arg.reg_sep.seid = seid;
|
||||
memcpy(&arg.reg_sep.mcc, mcc, sizeof(esp_a2d_mcc_t));
|
||||
|
||||
/* Switch to BTC context */
|
||||
bt_status_t stat = btc_transfer_context(&msg, &arg, sizeof(btc_av_args_t), NULL, NULL);
|
||||
return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
|
||||
}
|
||||
|
||||
esp_err_t esp_a2d_source_deinit(void)
|
||||
{
|
||||
if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
|
||||
@@ -348,6 +461,26 @@ esp_err_t esp_a2d_source_register_data_callback(esp_a2d_source_data_cb_t callbac
|
||||
return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
|
||||
}
|
||||
|
||||
esp_err_t esp_a2d_source_audio_data_send(esp_a2d_conn_hdl_t conn_hdl, esp_a2d_audio_buff_t *audio_buf)
|
||||
{
|
||||
if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED || !btc_av_is_started()) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
if (audio_buf == NULL || audio_buf->data_len == 0 || conn_hdl == 0) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (!btc_a2d_src_audio_mtu_check(audio_buf->data_len)) {
|
||||
return ESP_ERR_INVALID_SIZE;
|
||||
}
|
||||
|
||||
if (btc_a2d_src_audio_data_send(conn_hdl, audio_buf) != BT_STATUS_SUCCESS) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
#endif /* BTC_AV_SRC_INCLUDED */
|
||||
|
||||
#endif /* #if BTC_AV_INCLUDED */
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -528,6 +528,8 @@ esp_err_t esp_hf_ag_out_call(esp_bd_addr_t remote_addr, int num_active, int num_
|
||||
return (status == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
|
||||
}
|
||||
|
||||
#if (BTM_SCO_HCI_INCLUDED == TRUE)
|
||||
|
||||
esp_err_t esp_hf_ag_register_data_callback(esp_hf_incoming_data_cb_t recv, esp_hf_outgoing_data_cb_t send)
|
||||
{
|
||||
if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
|
||||
@@ -548,7 +550,73 @@ esp_err_t esp_hf_ag_register_data_callback(esp_hf_incoming_data_cb_t recv, esp_h
|
||||
return (status == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
|
||||
}
|
||||
|
||||
#if (BTM_SCO_HCI_INCLUDED == TRUE)
|
||||
esp_err_t esp_hf_ag_register_audio_data_callback(esp_hf_ag_audio_data_cb_t callback)
|
||||
{
|
||||
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;
|
||||
msg.act = BTC_HF_REGISTER_AUDIO_DATA_CALLBACK_EVT;
|
||||
|
||||
btc_hf_args_t arg;
|
||||
memset(&arg, 0, sizeof(btc_hf_args_t));
|
||||
arg.reg_audio_data_cb.callback = callback;
|
||||
|
||||
/* Switch to BTC context */
|
||||
bt_status_t status = btc_transfer_context(&msg, &arg, sizeof(btc_hf_args_t), NULL, NULL);
|
||||
return (status == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
|
||||
}
|
||||
|
||||
esp_hf_audio_buff_t *esp_hf_ag_audio_buff_alloc(uint16_t size)
|
||||
{
|
||||
if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (size == 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uint8_t *p_buf = NULL, *p_data;
|
||||
BTA_AgAudioBuffAlloc(size, &p_buf, &p_data);
|
||||
if (p_buf == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
esp_hf_audio_buff_t *audio_buf = (esp_hf_audio_buff_t *)p_buf;
|
||||
audio_buf->buff_size = size;
|
||||
audio_buf->data_len = 0;
|
||||
audio_buf->data = p_data;
|
||||
return audio_buf;
|
||||
}
|
||||
|
||||
void esp_hf_ag_audio_buff_free(esp_hf_audio_buff_t *audio_buf)
|
||||
{
|
||||
if (audio_buf == NULL) {
|
||||
return;
|
||||
}
|
||||
BTA_AgAudioBuffFree((UINT8 *)audio_buf);
|
||||
}
|
||||
|
||||
esp_err_t esp_hf_ag_audio_data_send(esp_hf_sync_conn_hdl_t sync_conn_hdl, esp_hf_audio_buff_t *audio_buf)
|
||||
{
|
||||
if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
if (audio_buf == NULL || audio_buf->data_len == 0) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (btc_hf_ag_audio_data_send(sync_conn_hdl, (uint8_t *)audio_buf, audio_buf->data, audio_buf->data_len)) {
|
||||
return ESP_OK;
|
||||
}
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
esp_err_t esp_hf_ag_pkt_stat_nums_get(uint16_t sync_conn_handle)
|
||||
{
|
||||
if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -541,6 +541,71 @@ void esp_hf_client_outgoing_data_ready(void)
|
||||
BTA_HfClientCiData();
|
||||
}
|
||||
|
||||
esp_err_t esp_hf_client_register_audio_data_callback(esp_hf_client_audio_data_cb_t callback)
|
||||
{
|
||||
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_AUDIO_DATA_CALLBACK_EVT;
|
||||
|
||||
btc_hf_client_args_t arg;
|
||||
memset(&arg, 0, sizeof(btc_hf_client_args_t));
|
||||
arg.reg_audio_data_cb.callback = callback;
|
||||
|
||||
/* Switch to BTC context */
|
||||
bt_status_t stat = btc_transfer_context(&msg, &arg, sizeof(btc_hf_client_args_t), NULL, NULL);
|
||||
return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
|
||||
}
|
||||
|
||||
esp_hf_audio_buff_t *esp_hf_client_audio_buff_alloc(uint16_t size)
|
||||
{
|
||||
if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (size == 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uint8_t *p_buf = NULL, *p_data;
|
||||
BTA_HfClientAudioBuffAlloc(size, &p_buf, &p_data);
|
||||
if (p_buf == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
esp_hf_audio_buff_t *audio_buf = (esp_hf_audio_buff_t *)p_buf;
|
||||
audio_buf->buff_size = size;
|
||||
audio_buf->data_len = 0;
|
||||
audio_buf->data = p_data;
|
||||
return audio_buf;
|
||||
}
|
||||
|
||||
void esp_hf_client_audio_buff_free(esp_hf_audio_buff_t *audio_buf)
|
||||
{
|
||||
if (audio_buf == NULL) {
|
||||
return;
|
||||
}
|
||||
BTA_HfClientAudioBuffFree((UINT8 *)audio_buf);
|
||||
}
|
||||
|
||||
esp_err_t esp_hf_client_audio_data_send(esp_hf_sync_conn_hdl_t sync_conn_hdl, esp_hf_audio_buff_t *audio_buf)
|
||||
{
|
||||
if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
if (audio_buf == NULL || audio_buf->data_len == 0) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
BTA_HfClientAudioDataSend(sync_conn_hdl, (uint8_t *)audio_buf, audio_buf->data, audio_buf->data_len);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void esp_hf_client_pcm_resample_init(uint32_t src_sps, uint32_t bits, uint32_t channels)
|
||||
{
|
||||
BTA_DmPcmInitSamples(src_sps, bits, channels);
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -9,11 +9,16 @@
|
||||
|
||||
#include "esp_err.h"
|
||||
#include "esp_bt_defs.h"
|
||||
#include "esp_a2dp_legacy_api.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define ESP_A2D_MAX_SEPS 1 /*!< Maximum number of Stream Endpoint that supported */
|
||||
|
||||
typedef uint16_t esp_a2d_conn_hdl_t; /*!< Connection handle, associate with specific device that connected */
|
||||
|
||||
/**
|
||||
* @brief Media codec types supported by A2DP.
|
||||
*/
|
||||
@@ -30,6 +35,102 @@ typedef uint8_t esp_a2d_mct_t;
|
||||
#define ESP_A2D_PSC_DELAY_RPT (1<<0) /*!< Delay Report */
|
||||
typedef uint16_t esp_a2d_psc_t;
|
||||
|
||||
/**
|
||||
* @brief A2DP SBC sampling frequency bit mask in CIE
|
||||
*/
|
||||
#define ESP_A2D_SBC_CIE_SF_16K (0x8) /*!< SBC sampling frequency 16kHz */
|
||||
#define ESP_A2D_SBC_CIE_SF_32K (0x4) /*!< SBC sampling frequency 32kHz */
|
||||
#define ESP_A2D_SBC_CIE_SF_44K (0x2) /*!< SBC sampling frequency 44.1kHz */
|
||||
#define ESP_A2D_SBC_CIE_SF_48K (0x1) /*!< SBC sampling frequency 48kHz */
|
||||
|
||||
/**
|
||||
* @brief A2DP SBC channel mode bit mask in CIE
|
||||
*/
|
||||
#define ESP_A2D_SBC_CIE_CH_MODE_MONO (0x8) /*!< SBC channel mode Mono */
|
||||
#define ESP_A2D_SBC_CIE_CH_MODE_DUAL_CHANNEL (0x4) /*!< SBC channel mode Dual Channel */
|
||||
#define ESP_A2D_SBC_CIE_CH_MODE_STEREO (0x2) /*!< SBC channel mode Stereo */
|
||||
#define ESP_A2D_SBC_CIE_CH_MODE_JOINT_STEREO (0x1) /*!< SBC channel mode Stereo */
|
||||
|
||||
/**
|
||||
* @brief A2DP SBC block length bit mask in CIE
|
||||
*/
|
||||
#define ESP_A2D_SBC_CIE_BLOCK_LEN_4 (0x8) /*!< SBC block length 4 */
|
||||
#define ESP_A2D_SBC_CIE_BLOCK_LEN_8 (0x4) /*!< SBC block length 8 */
|
||||
#define ESP_A2D_SBC_CIE_BLOCK_LEN_12 (0x2) /*!< SBC block length 12 */
|
||||
#define ESP_A2D_SBC_CIE_BLOCK_LEN_16 (0x1) /*!< SBC block length 16 */
|
||||
|
||||
/**
|
||||
* @brief A2DP SBC number of subbands bit mask in CIE
|
||||
*/
|
||||
#define ESP_A2D_SBC_CIE_NUM_SUBBANDS_4 (0x2) /*!< SBC number of subbands 4 */
|
||||
#define ESP_A2D_SBC_CIE_NUM_SUBBANDS_8 (0x1) /*!< SBC number of subbands 8 */
|
||||
|
||||
/**
|
||||
* @brief A2DP SBC allocation method bit mask in CIE
|
||||
*/
|
||||
#define ESP_A2D_SBC_CIE_ALLOC_MTHD_SRN (0x2) /*!< SBC allocation method SNR */
|
||||
#define ESP_A2D_SBC_CIE_ALLOC_MTHD_LOUDNESS (0x1) /*!< SBC allocation method Loudness */
|
||||
|
||||
/**
|
||||
* @brief A2DP SBC media codec capabilities information struct
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t ch_mode : 4; /*!< Channel mode */
|
||||
uint8_t samp_freq : 4; /*!< Sampling frequency */
|
||||
uint8_t alloc_mthd : 2; /*!< Allocation method */
|
||||
uint8_t num_subbands : 2; /*!< Number of subbands */
|
||||
uint8_t block_len : 4; /*!< Block length */
|
||||
uint8_t min_bitpool; /*!< Minimum bitpool */
|
||||
uint8_t max_bitpool; /*!< Maximum bitpool */
|
||||
} __attribute__((packed)) esp_a2d_cie_sbc_t;
|
||||
|
||||
/**
|
||||
* @brief A2DP MPEG-1, 2 media codec capabilities information struct (Not supported yet)
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t ch_mode : 4; /*!< Channel mode */
|
||||
uint8_t crc : 1; /*!< CRC protection */
|
||||
uint8_t layer : 3; /*!< Layers of MPEG-1,2 Audio */
|
||||
uint8_t samp_freq : 6; /*!< Sampling frequency */
|
||||
uint8_t mpf : 1; /*!< Media payload format */
|
||||
uint8_t rfu : 1; /*!< Reserved */
|
||||
uint8_t bri1 : 7; /*!< Bit rate index part 1 */
|
||||
uint8_t vbr : 1; /*!< Support of VBR */
|
||||
uint8_t bri2; /*!< Bit rate index part 2 */
|
||||
} __attribute__((packed)) esp_a2d_cie_m12_t;
|
||||
|
||||
/**
|
||||
* @brief A2DP MPEG-2, 4 media codec capabilities information struct (Not supported yet)
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t drc : 1; /*!< Support of MPEG-D DRC */
|
||||
uint8_t obj_type : 7; /*!< Object type */
|
||||
uint8_t samp_freq1 : 8; /*!< Sampling frequency part 1 */
|
||||
uint8_t ch : 4; /*!< Channels */
|
||||
uint8_t samp_freq2 : 4; /*!< Sampling frequency part 2 */
|
||||
uint8_t br1 : 7; /*!< Bit rate part 1 */
|
||||
uint8_t vbr : 1; /*!< Support of VBR */
|
||||
uint8_t br2; /*!< Bit rate part 2 */
|
||||
uint8_t br3; /*!< Bit rate part 3 */
|
||||
} __attribute__((packed)) esp_a2d_cie_m24_t;
|
||||
|
||||
/**
|
||||
* @brief A2DP ATRAC media codec capabilities information struct (Not supported yet)
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t rfu1 : 2; /*!< Reserved */
|
||||
uint8_t ch_mode : 3; /*!< Channel mode */
|
||||
uint8_t version : 3; /*!< Version */
|
||||
uint8_t bri1 : 3; /*!< Bit rate index part 1 */
|
||||
uint8_t vbr : 1; /*!< Support of VBR */
|
||||
uint8_t samp_freq : 2; /*!< Sampling frequency */
|
||||
uint8_t rfu2 : 2; /*!< Reserved */
|
||||
uint8_t bri2; /*!< Bit rate index part 2 */
|
||||
uint8_t bri3; /*!< Bit rate index part 3 */
|
||||
uint16_t max_sul; /*!< Maximum SUL */
|
||||
uint8_t rfu3; /*!< Reserved */
|
||||
} __attribute__((packed)) esp_a2d_cie_atrac_t;
|
||||
|
||||
/**
|
||||
* @brief A2DP media codec capabilities union
|
||||
*/
|
||||
@@ -40,10 +141,15 @@ typedef struct {
|
||||
#define ESP_A2D_CIE_LEN_M24 (6)
|
||||
#define ESP_A2D_CIE_LEN_ATRAC (7)
|
||||
union {
|
||||
uint8_t sbc[ESP_A2D_CIE_LEN_SBC]; /*!< SBC codec capabilities */
|
||||
uint8_t m12[ESP_A2D_CIE_LEN_M12]; /*!< MPEG-1,2 audio codec capabilities */
|
||||
uint8_t m24[ESP_A2D_CIE_LEN_M24]; /*!< MPEG-2, 4 AAC audio codec capabilities */
|
||||
uint8_t atrac[ESP_A2D_CIE_LEN_ATRAC]; /*!< ATRAC family codec capabilities */
|
||||
uint8_t sbc[ESP_A2D_CIE_LEN_SBC] __attribute__((deprecated)); /*!< SBC codec capabilities, deprecated, use sbc_info instead */
|
||||
uint8_t m12[ESP_A2D_CIE_LEN_M12] __attribute__((deprecated)); /*!< MPEG-1,2 audio codec capabilities, deprecated, use m12_info instead */
|
||||
uint8_t m24[ESP_A2D_CIE_LEN_M24] __attribute__((deprecated)); /*!< MPEG-2, 4 AAC audio codec capabilities, deprecated, use m24_info instead */
|
||||
uint8_t atrac[ESP_A2D_CIE_LEN_ATRAC] __attribute__((deprecated)); /*!< ATRAC family codec capabilities, deprecated, use atrac_info instead */
|
||||
|
||||
esp_a2d_cie_sbc_t sbc_info; /*!< SBC codec capabilities */
|
||||
esp_a2d_cie_m12_t m12_info; /*!< MPEG-1,2 audio codec capabilities */
|
||||
esp_a2d_cie_m24_t m24_info; /*!< MPEG-2, 4 AAC audio codec capabilities */
|
||||
esp_a2d_cie_atrac_t atrac_info; /*!< ATRAC family codec capabilities */
|
||||
} cie; /*!< A2DP codec information element */
|
||||
} __attribute__((packed)) esp_a2d_mcc_t;
|
||||
|
||||
@@ -103,6 +209,16 @@ typedef enum {
|
||||
ESP_A2D_INIT_SUCCESS /*!< A2DP profile deinit successful event */
|
||||
} esp_a2d_init_state_t;
|
||||
|
||||
/**
|
||||
* @brief Bluetooth A2DP SEP register states
|
||||
*/
|
||||
typedef enum {
|
||||
ESP_A2D_SEP_REG_SUCCESS = 0, /*!< A2DP stream endpoint register success */
|
||||
ESP_A2D_SEP_REG_FAIL, /*!< A2DP stream endpoint register generic fail */
|
||||
ESP_A2D_SEP_REG_UNSUPPORTED, /*!< A2DP stream endpoint register fail, unsupported codec type or param */
|
||||
ESP_A2D_SEP_REG_INVALID_STATE, /*!< A2DP stream endpoint register fail, invalid state */
|
||||
} esp_a2d_sep_reg_state_t;
|
||||
|
||||
/**
|
||||
* @brief Bluetooth A2DP set delay report value states
|
||||
*/
|
||||
@@ -117,15 +233,27 @@ typedef enum {
|
||||
typedef enum {
|
||||
ESP_A2D_CONNECTION_STATE_EVT = 0, /*!< connection state changed event */
|
||||
ESP_A2D_AUDIO_STATE_EVT, /*!< audio stream transmission state changed event */
|
||||
ESP_A2D_AUDIO_CFG_EVT, /*!< audio codec is configured, only used for A2DP SINK */
|
||||
ESP_A2D_AUDIO_CFG_EVT, /*!< audio codec is configured */
|
||||
ESP_A2D_MEDIA_CTRL_ACK_EVT, /*!< acknowledge event in response to media control commands */
|
||||
ESP_A2D_PROF_STATE_EVT, /*!< indicate a2dp init&deinit complete */
|
||||
ESP_A2D_SEP_REG_STATE_EVT, /*!< indicate a2dp steam endpoint register status */
|
||||
ESP_A2D_SNK_PSC_CFG_EVT, /*!< protocol service capabilities configured,only used for A2DP SINK */
|
||||
ESP_A2D_SNK_SET_DELAY_VALUE_EVT, /*!< indicate a2dp sink set delay report value complete, only used for A2DP SINK */
|
||||
ESP_A2D_SNK_GET_DELAY_VALUE_EVT, /*!< indicate a2dp sink get delay report value complete, only used for A2DP SINK */
|
||||
ESP_A2D_REPORT_SNK_DELAY_VALUE_EVT, /*!< report delay value, only used for A2DP SRC */
|
||||
} esp_a2d_cb_event_t;
|
||||
|
||||
/**
|
||||
* @brief A2DP audio buffer
|
||||
*/
|
||||
typedef struct {
|
||||
uint16_t buff_size; /*!< audio buff size */
|
||||
uint16_t number_frame; /*!< number of encoded frame in this buff */
|
||||
uint32_t timestamp; /*!< timestamp of the first frame */
|
||||
uint16_t data_len; /*!< audio data len */
|
||||
uint8_t *data; /*!< pointer to audio data start */
|
||||
} esp_a2d_audio_buff_t; /*!< struct to store audio data */
|
||||
|
||||
/**
|
||||
* @brief A2DP state callback parameters
|
||||
*/
|
||||
@@ -136,6 +264,8 @@ typedef union {
|
||||
struct a2d_conn_stat_param {
|
||||
esp_a2d_connection_state_t state; /*!< one of values from esp_a2d_connection_state_t */
|
||||
esp_bd_addr_t remote_bda; /*!< remote bluetooth device address */
|
||||
esp_a2d_conn_hdl_t conn_hdl; /*!< connection handle */
|
||||
uint16_t audio_mtu; /*!< MTU of audio connection */
|
||||
esp_a2d_disc_rsn_t disc_rsn; /*!< reason of disconnection for "DISCONNECTED" */
|
||||
} conn_stat; /*!< A2DP connection status */
|
||||
|
||||
@@ -144,7 +274,8 @@ typedef union {
|
||||
*/
|
||||
struct a2d_audio_stat_param {
|
||||
esp_a2d_audio_state_t state; /*!< one of the values from esp_a2d_audio_state_t */
|
||||
esp_bd_addr_t remote_bda; /*!< remote bluetooth device address */
|
||||
esp_bd_addr_t remote_bda; /*!< remote bluetooth device address*/
|
||||
esp_a2d_conn_hdl_t conn_hdl; /*!< connection handle */
|
||||
} audio_stat; /*!< audio stream playing state */
|
||||
|
||||
/**
|
||||
@@ -152,6 +283,7 @@ typedef union {
|
||||
*/
|
||||
struct a2d_audio_cfg_param {
|
||||
esp_bd_addr_t remote_bda; /*!< remote bluetooth device address */
|
||||
esp_a2d_conn_hdl_t conn_hdl; /*!< connection handle */
|
||||
esp_a2d_mcc_t mcc; /*!< A2DP media codec capability information */
|
||||
} audio_cfg; /*!< media codec configuration information */
|
||||
|
||||
@@ -170,6 +302,14 @@ typedef union {
|
||||
esp_a2d_init_state_t init_state; /*!< a2dp profile state param */
|
||||
} a2d_prof_stat; /*!< status to indicate a2d prof init or deinit */
|
||||
|
||||
/**
|
||||
* @brief ESP_A2D_SEP_REG_STATE_EVT
|
||||
*/
|
||||
struct a2d_sep_reg_stat_param {
|
||||
uint8_t seid; /*!< the stream endpoint to register */
|
||||
esp_a2d_sep_reg_state_t reg_state; /*!< stream endpoint register state */
|
||||
} a2d_sep_reg_stat; /*!< status to indicate a2d sep register success or not */
|
||||
|
||||
/**
|
||||
* @brief ESP_A2D_SNK_PSC_CFG_EVT
|
||||
*/
|
||||
@@ -213,25 +353,31 @@ typedef void (* esp_a2d_cb_t)(esp_a2d_cb_event_t event, esp_a2d_cb_param_t *para
|
||||
/**
|
||||
* @brief A2DP sink data callback function
|
||||
*
|
||||
* @param[in] buf : pointer to the data received from A2DP source device and is PCM format decoded from SBC decoder;
|
||||
* buf references to a static memory block and can be overwritten by upcoming data
|
||||
* @param[in] conn_hdl: connection handle
|
||||
*
|
||||
* @param[in] len : size(in bytes) in buf
|
||||
* @param[in] audio_buf: pointer to the data received from A2DP source device, should be freed by
|
||||
* calling esp_a2d_audio_buff_free
|
||||
*/
|
||||
typedef void (* esp_a2d_sink_data_cb_t)(const uint8_t *buf, uint32_t len);
|
||||
typedef void (* esp_a2d_sink_audio_data_cb_t)(esp_a2d_conn_hdl_t conn_hdl, esp_a2d_audio_buff_t *audio_buf);
|
||||
|
||||
/**
|
||||
* @brief A2DP source data read callback function
|
||||
* @brief Allocate a audio buffer to store and send audio data, can be used in both sink and source.
|
||||
*
|
||||
* @param[in] buf : buffer to be filled with PCM data stream from higher layer
|
||||
* @param[in] size: buffer size to allocate
|
||||
*
|
||||
* @param[in] len : size(in bytes) of data block to be copied to buf. -1 is an indication to user
|
||||
* that data buffer shall be flushed
|
||||
*
|
||||
* @return size of bytes read successfully, if the argument len is -1, this value is ignored.
|
||||
* @return allocated audio buffer, if Bluedroid is not enabled, no memory, or size is
|
||||
* zeros, will return NULL
|
||||
*
|
||||
*/
|
||||
typedef int32_t (* esp_a2d_source_data_cb_t)(uint8_t *buf, int32_t len);
|
||||
esp_a2d_audio_buff_t *esp_a2d_audio_buff_alloc(uint16_t size);
|
||||
|
||||
/**
|
||||
* @brief Free a audio buffer allocated by esp_a2d_audio_buff_alloc.
|
||||
*
|
||||
* @param[in] audio_buf: audio buffer to free
|
||||
*
|
||||
*/
|
||||
void esp_a2d_audio_buff_free(esp_a2d_audio_buff_t *audio_buf);
|
||||
|
||||
/**
|
||||
* @brief Register application callback function to A2DP module. This function should be called
|
||||
@@ -248,23 +394,20 @@ typedef int32_t (* esp_a2d_source_data_cb_t)(uint8_t *buf, int32_t len);
|
||||
*/
|
||||
esp_err_t esp_a2d_register_callback(esp_a2d_cb_t callback);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Register A2DP sink data output function; For now the output is PCM data stream decoded
|
||||
* from SBC format. This function should be called only after esp_bluedroid_enable()
|
||||
* completes successfully, used only by A2DP sink. The callback is invoked in the context
|
||||
* of A2DP sink task whose stack size is configurable through menuconfig.
|
||||
* @brief Register A2DP sink audio data output function, the output format is undecoded audio data
|
||||
* frame in esp_a2d_audio_buff_t, user shall call esp_a2d_audio_buff_free to free the buff
|
||||
* when the data is consumed.
|
||||
*
|
||||
* @param[in] callback: A2DP sink data callback function
|
||||
* @param[in] callback: A2DP sink audio data callback function
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: success
|
||||
* - ESP_ERR_INVALID_STATE: if bluetooth stack is not yet enabled
|
||||
* - ESP_FAIL: if callback is a NULL function pointer
|
||||
* - ESP_FAIL: others
|
||||
*
|
||||
*/
|
||||
esp_err_t esp_a2d_sink_register_data_callback(esp_a2d_sink_data_cb_t callback);
|
||||
|
||||
esp_err_t esp_a2d_sink_register_audio_data_callback(esp_a2d_sink_audio_data_cb_t callback);
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -282,6 +425,23 @@ esp_err_t esp_a2d_sink_register_data_callback(esp_a2d_sink_data_cb_t callback);
|
||||
*/
|
||||
esp_err_t esp_a2d_sink_init(void);
|
||||
|
||||
/**
|
||||
* @brief Register a a2dp sink Stream Endpoint (SEP) with specific codec capability, shall register
|
||||
* SEP after a2dp sink initializing and before a2dp connection establishing. Register the same
|
||||
* SEP index repeatedly will overwrite the old one.
|
||||
*
|
||||
* @param[in] seid: local SEP identifier, start from 0, less than ESP_A2D_MAX_SEPS
|
||||
*
|
||||
* @param[in] mcc: codec capability, currently only supports SBC
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: success
|
||||
* - ESP_ERR_INVALID_STATE: if bluetooth stack is not yet enabled
|
||||
* - ESP_ERR_INVALID_ARG: invalid parameter
|
||||
* - ESP_FAIL: others
|
||||
*
|
||||
*/
|
||||
esp_err_t esp_a2d_sink_register_stream_endpoint(uint8_t seid, const esp_a2d_mcc_t *mcc);
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -297,7 +457,6 @@ esp_err_t esp_a2d_sink_init(void);
|
||||
*/
|
||||
esp_err_t esp_a2d_sink_deinit(void);
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief Connect to remote bluetooth A2DP source device. This API must be called after
|
||||
@@ -313,7 +472,6 @@ esp_err_t esp_a2d_sink_deinit(void);
|
||||
*/
|
||||
esp_err_t esp_a2d_sink_connect(esp_bd_addr_t remote_bda);
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief Disconnect from the remote A2DP source device. This API must be called after
|
||||
@@ -359,7 +517,6 @@ esp_err_t esp_a2d_sink_set_delay_value(uint16_t delay_value);
|
||||
*/
|
||||
esp_err_t esp_a2d_sink_get_delay_value(void);
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief Media control commands. This API can be used for both A2DP sink and source
|
||||
@@ -375,7 +532,6 @@ esp_err_t esp_a2d_sink_get_delay_value(void);
|
||||
*/
|
||||
esp_err_t esp_a2d_media_ctrl(esp_a2d_media_ctrl_t ctrl);
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief Initialize the bluetooth A2DP source module. A2DP can work independently.
|
||||
@@ -392,6 +548,23 @@ esp_err_t esp_a2d_media_ctrl(esp_a2d_media_ctrl_t ctrl);
|
||||
*/
|
||||
esp_err_t esp_a2d_source_init(void);
|
||||
|
||||
/**
|
||||
* @brief Register a a2dp source Stream Endpoint (SEP) with specific codec capability, shall register
|
||||
* SEP after a2dp source initializing and before a2dp connection establishing. Register the same
|
||||
* SEP index repeatedly will overwrite the old one.
|
||||
*
|
||||
* @param[in] seid: local SEP identifier, start from 0, less than ESP_A2D_MAX_SEPS
|
||||
*
|
||||
* @param[in] mcc: codec capability, currently, only SBC supported
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: success
|
||||
* - ESP_ERR_INVALID_STATE: if bluetooth stack is not yet enabled
|
||||
* - ESP_ERR_INVALID_ARG: invalid parameter
|
||||
* - ESP_FAIL: others
|
||||
*
|
||||
*/
|
||||
esp_err_t esp_a2d_source_register_stream_endpoint(uint8_t seid, const esp_a2d_mcc_t *mcc);
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -407,23 +580,24 @@ esp_err_t esp_a2d_source_init(void);
|
||||
*/
|
||||
esp_err_t esp_a2d_source_deinit(void);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Register A2DP source data input function. For now, the input shoule be PCM data stream.
|
||||
* This function should be called only after esp_bluedroid_enable() completes
|
||||
* successfully. The callback is invoked in the context of A2DP source task whose
|
||||
* stack size is configurable through menuconfig.
|
||||
* @brief Send a audio buff with encoded audio data to sink, the audio data len shall not bigger than
|
||||
* audio connection mtu (retrieved from ESP_A2D_CONNECTION_STATE_EVT). if the return value is
|
||||
* ESP_OK, then the audio buff is consumed, otherwise, audio buff can be reused by user.
|
||||
*
|
||||
* @param[in] callback: A2DP source data callback function
|
||||
* @param[in] conn_hdl: connection handle
|
||||
*
|
||||
* @param[in] audio_buf: encoded audio data
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: success
|
||||
* - ESP_ERR_INVALID_STATE: if bluetooth stack is not yet enabled
|
||||
* - ESP_FAIL: if callback is a NULL function pointer
|
||||
* - ESP_ERR_INVALID_ARG: invalid parameter
|
||||
* - ESP_ERR_INVALID_SIZE: data len bigger than mtu
|
||||
* - ESP_FAIL: buffer queue is full, try again later
|
||||
*
|
||||
*/
|
||||
esp_err_t esp_a2d_source_register_data_callback(esp_a2d_source_data_cb_t callback);
|
||||
|
||||
esp_err_t esp_a2d_source_audio_data_send(esp_a2d_conn_hdl_t conn_hdl, esp_a2d_audio_buff_t *audio_buf);
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -440,7 +614,6 @@ esp_err_t esp_a2d_source_register_data_callback(esp_a2d_source_data_cb_t callbac
|
||||
*/
|
||||
esp_err_t esp_a2d_source_connect(esp_bd_addr_t remote_bda);
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief Disconnect from the remote A2DP sink device. This API must be called
|
||||
|
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/*
|
||||
* Some legacy APIs of A2DP, will be removed in the future
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "esp_err.h"
|
||||
#include "esp_bt_defs.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief [Deprecated] A2DP sink data callback function
|
||||
*
|
||||
* @param[in] buf : pointer to the data received from A2DP source device and is PCM format decoded from SBC decoder;
|
||||
* buf references to a static memory block and can be overwritten by upcoming data
|
||||
*
|
||||
* @param[in] len : size(in bytes) in buf
|
||||
*/
|
||||
typedef void (* esp_a2d_sink_data_cb_t)(const uint8_t *buf, uint32_t len);
|
||||
|
||||
/**
|
||||
* @brief [Deprecated] A2DP source data read callback function
|
||||
*
|
||||
* @param[in] buf : buffer to be filled with PCM data stream from higher layer
|
||||
*
|
||||
* @param[in] len : size(in bytes) of data block to be copied to buf. -1 is an indication to user
|
||||
* that data buffer shall be flushed
|
||||
*
|
||||
* @return size of bytes read successfully, if the argument len is -1, this value is ignored.
|
||||
*
|
||||
*/
|
||||
typedef int32_t (* esp_a2d_source_data_cb_t)(uint8_t *buf, int32_t len);
|
||||
|
||||
/**
|
||||
* @brief [Deprecated] Register A2DP sink data output function; For now the output is PCM data stream decoded
|
||||
* from SBC format. This function should be called only after esp_bluedroid_enable()
|
||||
* completes successfully, used only by A2DP sink. The callback is invoked in the context
|
||||
* of A2DP sink task whose stack size is configurable through menuconfig.
|
||||
*
|
||||
* @param[in] callback: A2DP sink data callback function
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: success
|
||||
* - ESP_ERR_INVALID_STATE: if bluetooth stack is not yet enabled
|
||||
* - ESP_FAIL: if callback is a NULL function pointer
|
||||
*
|
||||
*/
|
||||
esp_err_t esp_a2d_sink_register_data_callback(esp_a2d_sink_data_cb_t callback);
|
||||
|
||||
/**
|
||||
* @brief [Deprecated] Register A2DP source data input function. For now, the input should be PCM data stream.
|
||||
* This function should be called only after esp_bluedroid_enable() completes
|
||||
* successfully. The callback is invoked in the context of A2DP source task whose
|
||||
* stack size is configurable through menuconfig.
|
||||
*
|
||||
* @param[in] callback: A2DP source data callback function
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: success
|
||||
* - ESP_ERR_INVALID_STATE: if bluetooth stack is not yet enabled
|
||||
* - ESP_FAIL: if callback is a NULL function pointer
|
||||
*
|
||||
*/
|
||||
esp_err_t esp_a2d_source_register_data_callback(esp_a2d_source_data_cb_t callback);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "esp_err.h"
|
||||
#include "esp_bt_defs.h"
|
||||
#include "esp_hf_defs.h"
|
||||
#include "esp_hf_ag_legacy_api.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -93,7 +94,8 @@ typedef union
|
||||
struct hf_audio_stat_param {
|
||||
esp_bd_addr_t remote_addr; /*!< Remote bluetooth device address */
|
||||
esp_hf_audio_state_t state; /*!< Audio connection state */
|
||||
uint16_t sync_conn_handle; /*!< (e)SCO connection handle */
|
||||
esp_hf_sync_conn_hdl_t sync_conn_handle; /*!< (e)SCO connection handle */
|
||||
uint16_t preferred_frame_size; /*!< Valid only when Voice Over HCI is enabled, recommended frame size to send */
|
||||
} audio_stat; /*!< AG callback param of ESP_HF_AUDIO_STATE_EVT */
|
||||
|
||||
/**
|
||||
@@ -233,35 +235,6 @@ typedef union
|
||||
|
||||
} esp_hf_cb_param_t; /*!< HFP AG callback param compound*/
|
||||
|
||||
/**
|
||||
* @brief AG 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_incoming_data_cb_t)(const uint8_t *buf, uint32_t len);
|
||||
|
||||
/**
|
||||
* @brief AG 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
|
||||
*
|
||||
* @return length of data successfully read
|
||||
*/
|
||||
typedef uint32_t (* esp_hf_outgoing_data_cb_t) (uint8_t *buf, uint32_t len);
|
||||
|
||||
/**
|
||||
* @brief HF AG callback function type
|
||||
*
|
||||
@@ -271,6 +244,20 @@ typedef uint32_t (* esp_hf_outgoing_data_cb_t) (uint8_t *buf, uint32_t len);
|
||||
*/
|
||||
typedef void (* esp_hf_cb_t) (esp_hf_cb_event_t event, esp_hf_cb_param_t *param);
|
||||
|
||||
/**
|
||||
* @brief HFP AG incoming audio data callback function, user should copy audio_buf struct
|
||||
* to other place before return. This callback is used in case of Voice Over HCI.
|
||||
*
|
||||
* @param[in] sync_conn_hdl: (e)SCO connection handle
|
||||
*
|
||||
* @param[in] audio_buf: pointer to incoming data(payload of HCI synchronous data packet), user
|
||||
* should free audio buffer by calling esp_hf_ag_audio_buff_free
|
||||
*
|
||||
* @param[in] is_bad_frame: whether this packet is marked as bad frame by baseband
|
||||
*
|
||||
*/
|
||||
typedef void (* esp_hf_ag_audio_data_cb_t)(esp_hf_sync_conn_hdl_t sync_conn_hdl, esp_hf_audio_buff_t *audio_buf, bool is_bad_frame);
|
||||
|
||||
/************************************************************************************
|
||||
** ESP HF API
|
||||
************************************************************************************/
|
||||
@@ -678,19 +665,58 @@ esp_err_t esp_hf_ag_end_call(esp_bd_addr_t remote_addr, int num_active, int num_
|
||||
char *number, esp_hf_call_addr_type_t call_addr_type);
|
||||
|
||||
/**
|
||||
* @brief Register AG data output function.
|
||||
* The callback is only used in the case that Voice Over HCI is enabled.
|
||||
* @brief Register HFP AG audio 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
|
||||
* @param[in] callback: HFP AG incoming audio data callback function
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: success
|
||||
* - ESP_ERR_INVALID_STATE: if bluetooth stack is not yet enabled
|
||||
* - ESP_FAIL: if callback is a NULL function pointer
|
||||
* - ESP_FAIL: others
|
||||
*
|
||||
*/
|
||||
esp_err_t esp_hf_ag_register_data_callback(esp_hf_incoming_data_cb_t recv, esp_hf_outgoing_data_cb_t send);
|
||||
esp_err_t esp_hf_ag_register_audio_data_callback(esp_hf_ag_audio_data_cb_t callback);
|
||||
|
||||
/**
|
||||
* @brief Allocate a audio buffer to store and send audio data. This function is only
|
||||
* used in the case that Voice Over HCI is enabled.
|
||||
*
|
||||
* @param[in] size: buffer size to allocate
|
||||
*
|
||||
* @return allocated audio buffer, if Bluedroid is not enabled, no memory, or size is
|
||||
* zeros, will return NULL
|
||||
*
|
||||
*/
|
||||
esp_hf_audio_buff_t *esp_hf_ag_audio_buff_alloc(uint16_t size);
|
||||
|
||||
/**
|
||||
* @brief Free a audio buffer allocated by esp_hf_ag_audio_buff_alloc. This function
|
||||
* is only used in the case that Voice Over HCI is enabled.
|
||||
*
|
||||
* @param[in] audio_buf: audio buffer to free
|
||||
*
|
||||
*/
|
||||
void esp_hf_ag_audio_buff_free(esp_hf_audio_buff_t *audio_buf);
|
||||
|
||||
/**
|
||||
* @brief Send audio data, the audio buffer should by allocated by esp_hf_ag_audio_buff_alloc.
|
||||
* If the length of the audio data is equal to preferred_frame_size indicated by
|
||||
* ESP_HF_AUDIO_STATE_EVT, then we can reduce one memory copy inside the Bluedroid stack.
|
||||
* This function is only used in the case that Voice Over HCI is enabled.
|
||||
*
|
||||
* @param[in] sync_conn_hdl: (e)SCO connection handle
|
||||
*
|
||||
* @param[in] audio_buf: audio buffer that audio data stored
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: success
|
||||
* - ESP_ERR_INVALID_STATE: if bluetooth stack is not yet enabled
|
||||
* - ESP_ERR_INVALID_ARG: invalid parameter
|
||||
* - ESP_FAIL: others
|
||||
*
|
||||
*/
|
||||
esp_err_t esp_hf_ag_audio_data_send(esp_hf_sync_conn_hdl_t sync_conn_hdl, esp_hf_audio_buff_t *audio_buf);
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -709,16 +735,6 @@ esp_err_t esp_hf_ag_register_data_callback(esp_hf_incoming_data_cb_t recv, esp_h
|
||||
*/
|
||||
esp_err_t esp_hf_ag_pkt_stat_nums_get(uint16_t sync_conn_handle);
|
||||
|
||||
/**
|
||||
* @brief Trigger the lower-layer to fetch and send audio data.
|
||||
*
|
||||
* This function is only used in the case that Voice Over HCI is enabled.
|
||||
* As a precondition to use this API, Service Level Connection shall exist with HFP client.
|
||||
* After this function is called, lower layer will invoke esp_hf_client_outgoing_data_cb_t to fetch data
|
||||
*
|
||||
*/
|
||||
void esp_hf_ag_outgoing_data_ready(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/*
|
||||
* Some legacy APIs of HFP AG, will be removed in the future
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "esp_err.h"
|
||||
#include "esp_bt_defs.h"
|
||||
#include "esp_hf_defs.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief AG 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_incoming_data_cb_t)(const uint8_t *buf, uint32_t len);
|
||||
|
||||
/**
|
||||
* @brief AG 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
|
||||
*
|
||||
* @return length of data successfully read
|
||||
*/
|
||||
typedef uint32_t (* esp_hf_outgoing_data_cb_t) (uint8_t *buf, uint32_t len);
|
||||
|
||||
/**
|
||||
* @brief Register AG 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_ERR_INVALID_STATE: if bluetooth stack is not yet enabled
|
||||
* - ESP_FAIL: if callback is a NULL function pointer
|
||||
*
|
||||
*/
|
||||
esp_err_t esp_hf_ag_register_data_callback(esp_hf_incoming_data_cb_t recv, esp_hf_outgoing_data_cb_t send);
|
||||
|
||||
/**
|
||||
* @brief Trigger the lower-layer to fetch and send audio data.
|
||||
*
|
||||
* This function is only used in the case that Voice Over HCI is enabled.
|
||||
* As a precondition to use this API, Service Level Connection shall exist with HFP client.
|
||||
* After this function is called, lower layer will invoke esp_hf_ag_outgoing_data_cb_t to fetch data
|
||||
*
|
||||
*/
|
||||
void esp_hf_ag_outgoing_data_ready(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "esp_err.h"
|
||||
#include "esp_bt_defs.h"
|
||||
#include "esp_hf_defs.h"
|
||||
#include "esp_hf_client_legacy_api.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -118,7 +119,8 @@ typedef union {
|
||||
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 */
|
||||
uint16_t sync_conn_handle; /*!< (e)SCO connection handle */
|
||||
esp_hf_sync_conn_hdl_t sync_conn_handle; /*!< (e)SCO connection handle */
|
||||
uint16_t preferred_frame_size; /*!< valid only when Voice Over HCI is enabled, recommended frame size to send */
|
||||
} audio_stat; /*!< HF callback param of ESP_HF_CLIENT_AUDIO_STATE_EVT */
|
||||
|
||||
/**
|
||||
@@ -277,32 +279,18 @@ typedef union {
|
||||
} esp_hf_client_cb_param_t; /*!< HFP client callback parameters */
|
||||
|
||||
/**
|
||||
* @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.
|
||||
* @brief HFP client incoming audio data callback function, user should copy audio_buf struct
|
||||
* to other place before return. This callback is used 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] sync_conn_hdl: (e)SCO connection handle
|
||||
*
|
||||
* @param[in] len : size(in bytes) in buf
|
||||
* @param[in] audio_buf: pointer to incoming data(payload of HCI synchronous data packet), user
|
||||
* should free audio buffer by calling esp_hf_client_audio_buff_free
|
||||
*
|
||||
* @return length of data successfully read
|
||||
* @param[in] is_bad_frame: whether this packet is marked as bad frame by baseband
|
||||
*
|
||||
*/
|
||||
typedef uint32_t (* esp_hf_client_outgoing_data_cb_t)(uint8_t *buf, uint32_t len);
|
||||
typedef void (* esp_hf_client_audio_data_cb_t)(esp_hf_sync_conn_hdl_t sync_conn_hdl, esp_hf_audio_buff_t *audio_buf, bool is_bad_frame);
|
||||
|
||||
/**
|
||||
* @brief HFP client callback function type
|
||||
@@ -662,24 +650,6 @@ esp_err_t esp_hf_client_request_last_voice_tag_number(void);
|
||||
*/
|
||||
esp_err_t esp_hf_client_send_nrec(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_ERR_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 Get the number of packets received and sent
|
||||
@@ -697,15 +667,57 @@ esp_err_t esp_hf_client_register_data_callback(esp_hf_client_incoming_data_cb_t
|
||||
esp_err_t esp_hf_client_pkt_stat_nums_get(uint16_t sync_conn_handle);
|
||||
|
||||
/**
|
||||
* @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. After this
|
||||
* function is called, lower layer will invoke esp_hf_client_outgoing_data_cb_t to fetch data.
|
||||
* @brief Register HFP client audio data output function; the callback is only used in
|
||||
* the case that Voice Over HCI is enabled.
|
||||
*
|
||||
* As a precondition to use this API, Service Level Connection shall exist with AG.
|
||||
* @param[in] callback: HFP client incoming audio data callback function
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: success
|
||||
* - ESP_ERR_INVALID_STATE: if bluetooth stack is not yet enabled
|
||||
* - ESP_FAIL: others
|
||||
*
|
||||
*/
|
||||
void esp_hf_client_outgoing_data_ready(void);
|
||||
esp_err_t esp_hf_client_register_audio_data_callback(esp_hf_client_audio_data_cb_t callback);
|
||||
|
||||
/**
|
||||
* @brief Allocate a audio buffer to store and send audio data. This function is only
|
||||
* used in the case that Voice Over HCI is enabled.
|
||||
*
|
||||
* @param[in] size: buffer size to allocate
|
||||
*
|
||||
* @return allocated audio buffer, if Bluedroid is not enabled, no memory, or size is
|
||||
* zeros, will return NULL
|
||||
*
|
||||
*/
|
||||
esp_hf_audio_buff_t *esp_hf_client_audio_buff_alloc(uint16_t size);
|
||||
|
||||
/**
|
||||
* @brief Free a audio buffer allocated by esp_hf_client_audio_buff_alloc. This function
|
||||
* is only used in the case that Voice Over HCI is enabled.
|
||||
*
|
||||
* @param[in] audio_buf: audio buffer to free
|
||||
*
|
||||
*/
|
||||
void esp_hf_client_audio_buff_free(esp_hf_audio_buff_t *audio_buf);
|
||||
|
||||
/**
|
||||
* @brief Send audio data, the audio buffer should by allocated by esp_hf_client_audio_buff_alloc.
|
||||
* If the length of the audio data is equal to preferred_frame_size indicated by
|
||||
* ESP_HF_CLIENT_AUDIO_STATE_EVT, then we can reduce one memory copy inside the Bluedroid stack.
|
||||
* This function is only used in the case that Voice Over HCI is enabled.
|
||||
*
|
||||
* @param[in] sync_conn_hdl: (e)SCO connection handle
|
||||
*
|
||||
* @param[in] audio_buf: audio buffer that audio data stored
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: success
|
||||
* - ESP_ERR_INVALID_STATE: if bluetooth stack is not yet enabled
|
||||
* - ESP_ERR_INVALID_ARG: invalid parameter
|
||||
*
|
||||
*/
|
||||
esp_err_t esp_hf_client_audio_data_send(esp_hf_sync_conn_hdl_t sync_conn_hdl, esp_hf_audio_buff_t *audio_buf);
|
||||
|
||||
/**
|
||||
* @brief Initialize the down sampling converter. This is a utility function that can
|
||||
|
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/*
|
||||
* Some legacy APIs of HFP HF, will be removed in the future
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "esp_err.h"
|
||||
#include "esp_bt_defs.h"
|
||||
#include "esp_hf_defs.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @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
|
||||
*
|
||||
* @return length of data successfully read
|
||||
*
|
||||
*/
|
||||
typedef uint32_t (* esp_hf_client_outgoing_data_cb_t)(uint8_t *buf, uint32_t len);
|
||||
|
||||
/**
|
||||
* @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_ERR_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. After this
|
||||
* function is called, lower layer will invoke esp_hf_client_outgoing_data_cb_t to fetch data.
|
||||
*
|
||||
* As a precondition to use this API, Service Level Connection shall exist with AG.
|
||||
*
|
||||
*/
|
||||
void esp_hf_client_outgoing_data_ready(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -13,6 +13,8 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef uint16_t esp_hf_sync_conn_hdl_t;
|
||||
|
||||
/// profile states
|
||||
typedef enum {
|
||||
ESP_HF_INIT_SUCCESS = 0, /*!< Indicate init successful */
|
||||
@@ -249,6 +251,25 @@ typedef enum {
|
||||
ESP_HF_CME_NETWORK_NOT_ALLOWED = 32, /*!< network not allowed --emergency calls only */
|
||||
} esp_hf_cme_err_t;
|
||||
|
||||
/* Since HFP uses a fixed set of mSBC codec parameters, define it here */
|
||||
#define ESP_HF_MSBC_CHANNEL_MODE "Mono" /*!< mSBC channel mode */
|
||||
#define ESP_HF_MSBC_SAMPLING_RATE "16 kHz" /*!< mSBC sampling rate */
|
||||
#define ESP_HF_MSBC_ALLOCATION_METHOD "Loudness" /*!< mSBC allocation method */
|
||||
#define ESP_HF_MSBC_SUBBANDS 8 /*!< mSBC subbands */
|
||||
#define ESP_HF_MSBC_BLOCK_LENGTH 15 /*!< mSBC block length */
|
||||
#define ESP_HF_MSBC_BITPOOL 26 /*!< mSBC bitpool */
|
||||
/* frame size after mSBC encoded */
|
||||
#define ESP_HF_MSBC_ENCODED_FRAME_SIZE 57 /*!< mSBC frame size */
|
||||
|
||||
/**
|
||||
* @brief HFP audio buffer
|
||||
*/
|
||||
typedef struct {
|
||||
uint16_t buff_size; /*!< buffer size */
|
||||
uint16_t data_len; /*!< audio data length, data length should not greater than buffer size */
|
||||
uint8_t *data; /*!< pointer to audio data start */
|
||||
} esp_hf_audio_buff_t; /*!< struct to store audio data */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@@ -57,7 +57,7 @@
|
||||
#define BTA_AV_CLOSE_REQ_TIME_VAL 4000
|
||||
#endif
|
||||
|
||||
/* number to retry on reconfigure failure - some headsets requirs this number to be more than 1 */
|
||||
/* number to retry on reconfigure failure - some headsets requires this number to be more than 1 */
|
||||
#ifndef BTA_AV_RECONFIG_RETRY
|
||||
#define BTA_AV_RECONFIG_RETRY 6
|
||||
#endif
|
||||
@@ -239,7 +239,7 @@ static UINT8 bta_av_get_scb_handle(tBTA_AV_SCB *p_scb, UINT8 local_sep)
|
||||
return (p_scb->seps[xx].av_handle);
|
||||
}
|
||||
}
|
||||
APPL_TRACE_DEBUG(" bta_av_get_scb_handle appropiate sep_type not found")
|
||||
APPL_TRACE_DEBUG(" bta_av_get_scb_handle appropriate sep_type not found")
|
||||
return 0; /* return invalid handle */
|
||||
}
|
||||
|
||||
@@ -260,7 +260,7 @@ static UINT8 bta_av_get_scb_sep_type(tBTA_AV_SCB *p_scb, UINT8 tavdt_handle)
|
||||
return (p_scb->seps[xx].tsep);
|
||||
}
|
||||
}
|
||||
APPL_TRACE_DEBUG(" bta_av_get_scb_sep_type appropiate handle not found")
|
||||
APPL_TRACE_DEBUG(" bta_av_get_scb_sep_type appropriate handle not found")
|
||||
return 3; /* return invalid sep type */
|
||||
}
|
||||
|
||||
@@ -586,9 +586,18 @@ void bta_av_stream_data_cback(UINT8 handle, BT_HDR *p_pkt, UINT32 time_stamp, UI
|
||||
osi_free(p_pkt);
|
||||
return;
|
||||
}
|
||||
|
||||
if (p_pkt->offset >= 4) {
|
||||
/* The offset of avdt packet will always greater than 4, it is safe to add timestamp here */
|
||||
*((UINT32 *) (p_pkt + 1)) = time_stamp;
|
||||
}
|
||||
else {
|
||||
APPL_TRACE_WARNING("bta_av_stream_data_cback avdt packet offset small than 4");
|
||||
}
|
||||
|
||||
p_pkt->event = BTA_AV_MEDIA_DATA_EVT;
|
||||
p_scb->seps[p_scb->sep_idx].p_app_data_cback(BTA_AV_MEDIA_DATA_EVT, (tBTA_AV_MEDIA *)p_pkt);
|
||||
osi_free(p_pkt); /* a copy of packet had been delivered, we free this buffer */
|
||||
/* packet will be free by upper */
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
@@ -843,7 +852,7 @@ void bta_av_role_res (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
|
||||
bdcpy(av_open.bd_addr, p_scb->peer_addr);
|
||||
av_open.chnl = p_scb->chnl;
|
||||
av_open.hndl = p_scb->hndl;
|
||||
start.status = BTA_AV_FAIL_ROLE;
|
||||
av_open.status = BTA_AV_FAIL_ROLE;
|
||||
if (p_scb->seps[p_scb->sep_idx].tsep == AVDT_TSEP_SRC ) {
|
||||
av_open.sep = AVDT_TSEP_SNK;
|
||||
} else if (p_scb->seps[p_scb->sep_idx].tsep == AVDT_TSEP_SNK ) {
|
||||
@@ -1271,7 +1280,7 @@ void bta_av_setconfig_rsp (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
|
||||
if (AVDT_TSEP_SNK == local_sep) {
|
||||
if ((p_data->ci_setconfig.err_code == AVDT_SUCCESS) &&
|
||||
(p_scb->seps[p_scb->sep_idx].p_app_data_cback != NULL)) {
|
||||
p_scb->seps[p_scb->sep_idx].p_app_data_cback(BTA_AV_MEDIA_SINK_CFG_EVT,
|
||||
p_scb->seps[p_scb->sep_idx].p_app_data_cback(BTA_AV_MEDIA_CFG_EVT,
|
||||
(tBTA_AV_MEDIA *)p_scb->cfg.codec_info);
|
||||
}
|
||||
if (p_scb->cur_psc_mask & AVDT_PSC_DELAY_RPT) {
|
||||
@@ -1384,7 +1393,7 @@ void bta_av_str_opened (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
|
||||
{
|
||||
/* TODO check if other audio channel is open.
|
||||
* If yes, check if reconfig is needed
|
||||
* Rigt now we do not do this kind of checking.
|
||||
* Right now we do not do this kind of checking.
|
||||
* BTA-AV is INT for 2nd audio connection.
|
||||
* The application needs to make sure the current codec_info is proper.
|
||||
* If one audio connection is open and another SNK attempts to connect to AV,
|
||||
@@ -1397,6 +1406,7 @@ void bta_av_str_opened (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
|
||||
open.status = BTA_AV_SUCCESS;
|
||||
open.starting = bta_av_chk_start(p_scb);
|
||||
open.edr = 0;
|
||||
open.mtu = mtu;
|
||||
if ( NULL != (p = BTM_ReadRemoteFeatures(p_scb->peer_addr))) {
|
||||
if (HCI_EDR_ACL_2MPS_SUPPORTED(p)) {
|
||||
open.edr |= BTA_AV_EDR_2MBPS;
|
||||
@@ -1533,7 +1543,7 @@ void bta_av_do_close (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
|
||||
L2CA_FlushChannel (p_scb->l2c_cid, L2CAP_FLUSH_CHANS_ALL);
|
||||
|
||||
AVDT_CloseReq(p_scb->avdt_handle);
|
||||
/* just in case that the link is congested, link is flow controled by peer or
|
||||
/* just in case that the link is congested, link is flow controlled by peer or
|
||||
* for whatever reason the the close request can not be sent in time.
|
||||
* when this timer expires, AVDT_DisconnectReq will be called to disconnect the link
|
||||
*/
|
||||
@@ -1814,7 +1824,7 @@ void bta_av_open_failed (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
|
||||
|
||||
}
|
||||
|
||||
/* if there is already an active AV connnection with the same bd_addr,
|
||||
/* if there is already an active AV connection with the same bd_addr,
|
||||
don't send disconnect req, just report the open event with BTA_AV_FAIL_GET_CAP status */
|
||||
if (is_av_opened == TRUE) {
|
||||
bdcpy(open.bd_addr, p_scb->peer_addr);
|
||||
@@ -1856,7 +1866,7 @@ void bta_av_getcap_results (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
|
||||
tAVDT_CFG cfg;
|
||||
UINT8 media_type;
|
||||
tAVDT_SEP_INFO *p_info = &p_scb->sep_info[p_scb->sep_info_idx];
|
||||
UINT16 uuid_int; /* UUID for which connection was initiatied */
|
||||
UINT16 uuid_int; /* UUID for which connection was initiated */
|
||||
tBTA_AV_SNK_PSC_CFG psc_cfg = {0};
|
||||
|
||||
memcpy(&cfg, &p_scb->cfg, sizeof(tAVDT_CFG));
|
||||
@@ -1899,9 +1909,9 @@ void bta_av_getcap_results (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
|
||||
p_scb->cur_psc_mask = cfg.psc_mask;
|
||||
|
||||
if (uuid_int == UUID_SERVCLASS_AUDIO_SINK) {
|
||||
if (p_scb->seps[p_scb->sep_idx].p_app_data_cback != NULL) {
|
||||
if (p_scb->seps[p_scb->sep_idx].p_app_data_cback != NULL) {
|
||||
APPL_TRACE_DEBUG(" Configure Deoder for Sink Connection ");
|
||||
p_scb->seps[p_scb->sep_idx].p_app_data_cback(BTA_AV_MEDIA_SINK_CFG_EVT,
|
||||
p_scb->seps[p_scb->sep_idx].p_app_data_cback(BTA_AV_MEDIA_CFG_EVT,
|
||||
(tBTA_AV_MEDIA *)p_scb->cfg.codec_info);
|
||||
}
|
||||
if (p_scb->cur_psc_mask & AVDT_PSC_DELAY_RPT) {
|
||||
@@ -1909,6 +1919,13 @@ void bta_av_getcap_results (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
|
||||
}
|
||||
(*bta_av_cb.p_cback)(BTA_AV_SNK_PSC_CFG_EVT, (tBTA_AV *)&psc_cfg);
|
||||
}
|
||||
else {
|
||||
/* UUID_SERVCLASS_AUDIO_SOURCE */
|
||||
if (p_scb->seps[p_scb->sep_idx].p_app_data_cback != NULL) {
|
||||
p_scb->seps[p_scb->sep_idx].p_app_data_cback(BTA_AV_MEDIA_CFG_EVT,
|
||||
(tBTA_AV_MEDIA *)p_scb->cfg.codec_info);
|
||||
}
|
||||
}
|
||||
|
||||
/* open the stream */
|
||||
AVDT_OpenReq(p_scb->seps[p_scb->sep_idx].av_handle, p_scb->peer_addr,
|
||||
@@ -2387,7 +2404,7 @@ void bta_av_start_ok (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
|
||||
{
|
||||
/* If sink starts stream, disable sniff mode here */
|
||||
if (!initiator) {
|
||||
/* If souce is the master role, disable role switch during streaming.
|
||||
/* If source is the master role, disable role switch during streaming.
|
||||
* Otherwise allow role switch, if source is slave.
|
||||
* Because it would not hurt source, if the peer device wants source to be master */
|
||||
if ((BTM_GetRole (p_scb->peer_addr, &cur_role) == BTM_SUCCESS) &&
|
||||
@@ -2502,7 +2519,7 @@ void bta_av_str_closed (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
|
||||
bta_av_str_stopped(p_scb, NULL);
|
||||
}
|
||||
|
||||
/* Update common mtu shared by remaining connectons */
|
||||
/* Update common mtu shared by remaining connections */
|
||||
mtu = bta_av_chk_mtu(p_scb, BTA_AV_MAX_A2DP_MTU);
|
||||
|
||||
{
|
||||
|
@@ -129,6 +129,23 @@ void BTA_AvRegister(tBTA_AV_CHNL chnl, const char *p_service_name, UINT8 app_id,
|
||||
}
|
||||
}
|
||||
|
||||
void BTA_AvRegSEP(tBTA_AV_CHNL chnl, UINT8 seid, UINT8 tsep, tBTA_AV_CODEC codec_type, UINT8 *p_codec_info, tBTA_AV_DATA_CBACK *p_data_cback)
|
||||
{
|
||||
tBTA_AV_API_REG_SEP *p_buf;
|
||||
|
||||
if ((p_buf = (tBTA_AV_API_REG_SEP *) osi_malloc(sizeof(tBTA_AV_API_REG_SEP))) != NULL) {
|
||||
p_buf->hdr.layer_specific = chnl;
|
||||
p_buf->hdr.event = BTA_AV_API_REG_SEP_EVT;
|
||||
|
||||
p_buf->seid = seid;
|
||||
p_buf->tsep = tsep;
|
||||
p_buf->codec_type = codec_type;
|
||||
memcpy(p_buf->codec_info, p_codec_info, AVDT_CODEC_SIZE);
|
||||
p_buf->p_data_cback = p_data_cback;
|
||||
bta_sys_sendmsg(p_buf);
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function BTA_AvDeregister
|
||||
|
@@ -151,6 +151,7 @@ static const tBTA_AV_ST_TBL bta_av_st_tbl[] = {
|
||||
typedef void (*tBTA_AV_NSM_ACT)(tBTA_AV_DATA *p_data);
|
||||
static void bta_av_api_enable(tBTA_AV_DATA *p_data);
|
||||
static void bta_av_api_register(tBTA_AV_DATA *p_data);
|
||||
static void bta_av_api_reg_sep(tBTA_AV_DATA *p_data);
|
||||
#if (BTA_AV_SINK_INCLUDED == TRUE)
|
||||
static void bta_av_api_sink_enable(tBTA_AV_DATA *p_data);
|
||||
static void bta_av_api_get_delay_value(tBTA_AV_DATA *p_data);
|
||||
@@ -170,6 +171,7 @@ static void bta_av_sys_rs_cback (tBTA_SYS_CONN_STATUS status, UINT8 id, UINT8 ap
|
||||
const tBTA_AV_NSM_ACT bta_av_nsm_act[] = {
|
||||
bta_av_api_enable, /* BTA_AV_API_ENABLE_EVT */
|
||||
bta_av_api_register, /* BTA_AV_API_REGISTER_EVT */
|
||||
bta_av_api_reg_sep, /* BTA_AV_API_REG_SEP_EVT */
|
||||
bta_av_api_deregister, /* BTA_AV_API_DEREGISTER_EVT */
|
||||
bta_av_api_disconnect, /* BTA_AV_API_DISCONNECT_EVT */
|
||||
bta_av_ci_data, /* BTA_AV_CI_SRC_DATA_READY_EVT */
|
||||
@@ -533,9 +535,11 @@ static void bta_av_api_register(tBTA_AV_DATA *p_data)
|
||||
tAVDT_REG reg;
|
||||
tAVDT_CS cs;
|
||||
char *p_service_name;
|
||||
tBTA_AV_CODEC codec_type;
|
||||
tBTA_UTL_COD cod;
|
||||
#if (BTA_AV_EXT_CODEC == FALSE)
|
||||
tBTA_AV_CODEC codec_type;
|
||||
UINT8 index = 0;
|
||||
#endif
|
||||
char p_avk_service_name[BTA_SERVICE_NAME_LEN + 1];
|
||||
BCM_STRNCPY_S(p_avk_service_name, BTIF_AVK_SERVICE_NAME, BTA_SERVICE_NAME_LEN);
|
||||
p_avk_service_name[BTA_SERVICE_NAME_LEN] = '\0';
|
||||
@@ -658,6 +662,7 @@ static void bta_av_api_register(tBTA_AV_DATA *p_data)
|
||||
|
||||
/* keep the configuration in the stream control block */
|
||||
memcpy(&p_scb->cfg, &cs.cfg, sizeof(tAVDT_CFG));
|
||||
#if (BTA_AV_EXT_CODEC == FALSE)
|
||||
while (index < BTA_AV_MAX_SEPS &&
|
||||
(p_scb->p_cos->init)(&codec_type, cs.cfg.codec_info,
|
||||
&cs.cfg.num_protect, cs.cfg.protect_info, p_data->api_reg.tsep) == TRUE) {
|
||||
@@ -673,12 +678,13 @@ static void bta_av_api_register(tBTA_AV_DATA *p_data)
|
||||
|
||||
#if (BTA_AV_SINK_INCLUDED == TRUE)
|
||||
p_scb->seps[index].tsep = cs.tsep;
|
||||
if (cs.tsep == AVDT_TSEP_SNK) {
|
||||
p_scb->seps[index].p_app_data_cback = p_data->api_reg.p_app_data_cback;
|
||||
} else {
|
||||
p_scb->seps[index].p_app_data_cback = NULL; /* In case of A2DP SOURCE we don't need a callback to handle media packets */
|
||||
}
|
||||
// if (cs.tsep == AVDT_TSEP_SNK) {
|
||||
// p_scb->seps[index].p_app_data_cback = p_data->api_reg.p_app_data_cback;
|
||||
// } else {
|
||||
// p_scb->seps[index].p_app_data_cback = NULL; /* In case of A2DP SOURCE we don't need a callback to handle media packets */
|
||||
// }
|
||||
#endif
|
||||
p_scb->seps[index].p_app_data_cback = p_data->api_reg.p_app_data_cback;
|
||||
|
||||
APPL_TRACE_DEBUG("audio[%d] av_handle: %d codec_type: %d\n",
|
||||
index, p_scb->seps[index].av_handle, p_scb->seps[index].codec_type);
|
||||
@@ -687,6 +693,7 @@ static void bta_av_api_register(tBTA_AV_DATA *p_data)
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!bta_av_cb.reg_audio) {
|
||||
if (p_data->api_reg.tsep == AVDT_TSEP_SRC) {
|
||||
@@ -744,6 +751,86 @@ static void bta_av_api_register(tBTA_AV_DATA *p_data)
|
||||
(*bta_av_cb.p_cback)(BTA_AV_REGISTER_EVT, (tBTA_AV *)®istr);
|
||||
}
|
||||
|
||||
static void bta_av_api_reg_sep(tBTA_AV_DATA *p_data)
|
||||
{
|
||||
UNUSED(p_data);
|
||||
#if (BTA_AV_EXT_CODEC == TRUE)
|
||||
tAVDT_CS cs;
|
||||
tBTA_AV_CODEC codec_type;
|
||||
UINT8 index = p_data->api_reg_sep.seid;
|
||||
tBTA_AV_SEP_REG sep_reg;
|
||||
|
||||
sep_reg.seid = p_data->api_reg_sep.seid;
|
||||
sep_reg.reg_state = BTA_AV_FAIL;
|
||||
|
||||
if (index > BTA_AV_MAX_SEPS || p_data->hdr.layer_specific != BTA_AV_CHNL_AUDIO) {
|
||||
(*bta_av_cb.p_cback)(BTA_AV_SEP_REG_EVT, (tBTA_AV *)&sep_reg);
|
||||
APPL_TRACE_WARNING("%s invalid parameter: seid %d, ch %d", __FUNCTION__, index, p_data->hdr.layer_specific);
|
||||
return;
|
||||
}
|
||||
|
||||
memset(&cs, 0, sizeof(tAVDT_CS));
|
||||
cs.cfg.num_codec = 1;
|
||||
cs.tsep = p_data->api_reg_sep.tsep;
|
||||
cs.nsc_mask = AVDT_NSC_RECONFIG | ((bta_av_cb.features & BTA_AV_FEAT_PROTECT) ? 0 : AVDT_NSC_SECURITY);
|
||||
|
||||
for (int xx = 0; xx < BTA_AV_NUM_STRS; xx++) {
|
||||
if (bta_av_cb.p_scb[xx] != NULL && bta_av_cb.p_scb[xx]->chnl == BTA_AV_CHNL_AUDIO) {
|
||||
tBTA_AV_SCB *p_scb = bta_av_cb.p_scb[xx];
|
||||
cs.p_ctrl_cback = bta_av_dt_cback[p_scb->hdi];
|
||||
cs.cfg.psc_mask = AVDT_PSC_TRANS;
|
||||
cs.media_type = AVDT_MEDIA_AUDIO;
|
||||
cs.mtu = p_bta_av_cfg->audio_mtu;
|
||||
cs.flush_to = L2CAP_DEFAULT_FLUSH_TO;
|
||||
|
||||
#if AVDT_REPORTING == TRUE
|
||||
if (bta_av_cb.features & BTA_AV_FEAT_REPORT) {
|
||||
cs.cfg.psc_mask |= AVDT_PSC_REPORT;
|
||||
cs.p_report_cback = bta_av_a2dp_report_cback;
|
||||
#if AVDT_MULTIPLEXING == TRUE
|
||||
cs.cfg.mux_tsid_report = 2;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
if (bta_av_cb.features & BTA_AV_FEAT_DELAY_RPT) {
|
||||
cs.cfg.psc_mask |= AVDT_PSC_DELAY_RPT;
|
||||
}
|
||||
/* todo: check whether this memcpy is necessary */
|
||||
memcpy(&p_scb->cfg, &cs.cfg, sizeof(tAVDT_CFG));
|
||||
|
||||
codec_type = p_data->api_reg_sep.codec_type;
|
||||
memcpy(cs.cfg.codec_info, p_data->api_reg_sep.codec_info, AVDT_CODEC_SIZE);
|
||||
if ((p_scb->p_cos->init)(&codec_type, cs.cfg.codec_info,
|
||||
&cs.cfg.num_protect, cs.cfg.protect_info, p_data->api_reg_sep.tsep) == TRUE) {
|
||||
|
||||
#if (BTA_AV_SINK_INCLUDED == TRUE)
|
||||
if (p_data->api_reg_sep.tsep == AVDT_TSEP_SNK) {
|
||||
cs.p_data_cback = bta_av_stream_data_cback;
|
||||
}
|
||||
#endif
|
||||
if ((p_scb->seps[index].av_handle != 0) && (AVDT_RemoveStream(p_scb->seps[index].av_handle) != AVDT_SUCCESS)) {
|
||||
APPL_TRACE_WARNING("%s fail to remove exist sep", __FUNCTION__);
|
||||
}
|
||||
if (AVDT_CreateStream(&p_scb->seps[index].av_handle, &cs) == AVDT_SUCCESS) {
|
||||
p_scb->seps[index].codec_type = codec_type;
|
||||
p_scb->seps[index].tsep = cs.tsep;
|
||||
p_scb->seps[index].p_app_data_cback = p_data->api_reg_sep.p_data_cback;
|
||||
} else {
|
||||
APPL_TRACE_WARNING("%s fail to create sep", __FUNCTION__);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
APPL_TRACE_WARNING("%s invalid codec capability", __FUNCTION__);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sep_reg.reg_state = BTA_AV_SUCCESS;
|
||||
(*bta_av_cb.p_cback)(BTA_AV_SEP_REG_EVT, (tBTA_AV *)&sep_reg);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function bta_av_api_deregister
|
||||
@@ -1415,7 +1502,8 @@ char *bta_av_action_code(UINT16 action_code)
|
||||
case 46: return "BTA_AV_DELAY_CO";
|
||||
case 47: return "BTA_AV_OPEN_AT_INC";
|
||||
case 48: return "BTA_AV_OPEN_FAIL_SDP";
|
||||
case 49: return "NULL";
|
||||
case 49: return "BTA_AV_SET_DELAY_VALUE";
|
||||
case 50: return "NULL";
|
||||
default: return "unknown";
|
||||
}
|
||||
}
|
||||
|
@@ -581,6 +581,64 @@ UINT8 bta_av_sbc_cfg_in_cap(UINT8 *p_cfg, tA2D_SBC_CIE *p_cap)
|
||||
return status;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function bta_av_sbc_cfg_in_external_codec_cap
|
||||
**
|
||||
** Description This function checks whether an SBC codec configuration
|
||||
** is allowable for the given external codec capabilities.
|
||||
**
|
||||
** Returns 0 if ok, nonzero if error.
|
||||
**
|
||||
*******************************************************************************/
|
||||
UINT8 bta_av_sbc_cfg_in_external_codec_cap(UINT8 *p_cfg, UINT8 *p_cap)
|
||||
{
|
||||
UINT8 status = 0;
|
||||
tA2D_SBC_CIE cfg_cie;
|
||||
tA2D_SBC_CIE cap_cie;
|
||||
|
||||
/* parse configuration */
|
||||
if ((status = A2D_ParsSbcInfo(&cfg_cie, p_cfg, FALSE)) != 0) {
|
||||
return status;
|
||||
}
|
||||
/* parse capability */
|
||||
if ((status = A2D_ParsSbcInfo(&cap_cie, p_cap, TRUE)) != 0) {
|
||||
return status;
|
||||
}
|
||||
|
||||
/* verify that each parameter is in range */
|
||||
|
||||
/* sampling frequency */
|
||||
if ((cfg_cie.samp_freq & cap_cie.samp_freq) == 0) {
|
||||
status = A2D_NS_SAMP_FREQ;
|
||||
}
|
||||
/* channel mode */
|
||||
else if ((cfg_cie.ch_mode & cap_cie.ch_mode) == 0) {
|
||||
status = A2D_NS_CH_MODE;
|
||||
}
|
||||
/* block length */
|
||||
else if ((cfg_cie.block_len & cap_cie.block_len) == 0) {
|
||||
status = A2D_BAD_BLOCK_LEN;
|
||||
}
|
||||
/* subbands */
|
||||
else if ((cfg_cie.num_subbands & cap_cie.num_subbands) == 0) {
|
||||
status = A2D_NS_SUBBANDS;
|
||||
}
|
||||
/* allocation method */
|
||||
else if ((cfg_cie.alloc_mthd & cap_cie.alloc_mthd) == 0) {
|
||||
status = A2D_NS_ALLOC_MTHD;
|
||||
}
|
||||
/* max bitpool */
|
||||
else if (cfg_cie.max_bitpool > cap_cie.max_bitpool) {
|
||||
status = A2D_NS_MAX_BITPOOL;
|
||||
}
|
||||
/* min bitpool */
|
||||
else if (cfg_cie.min_bitpool < cap_cie.min_bitpool) {
|
||||
status = A2D_NS_MIN_BITPOOL;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function bta_av_sbc_bld_hdr
|
||||
|
@@ -98,6 +98,7 @@ enum {
|
||||
/* these events are handled outside of the state machine */
|
||||
BTA_AV_API_ENABLE_EVT,
|
||||
BTA_AV_API_REGISTER_EVT,
|
||||
BTA_AV_API_REG_SEP_EVT,
|
||||
BTA_AV_API_DEREGISTER_EVT,
|
||||
BTA_AV_API_DISCONNECT_EVT,
|
||||
BTA_AV_CI_SRC_DATA_READY_EVT,
|
||||
@@ -195,6 +196,15 @@ typedef struct {
|
||||
tBTA_AVRC_CO_FUNCTS *bta_avrc_cos;
|
||||
} tBTA_AV_API_REG;
|
||||
|
||||
/* data type for BTA_AV_API_REG_SEP_EVT */
|
||||
typedef struct {
|
||||
BT_HDR hdr;
|
||||
UINT8 seid;
|
||||
UINT8 tsep;
|
||||
tBTA_AV_CODEC codec_type;
|
||||
UINT8 codec_info[AVDT_CODEC_SIZE];
|
||||
tBTA_AV_DATA_CBACK *p_data_cback;
|
||||
} tBTA_AV_API_REG_SEP;
|
||||
|
||||
enum {
|
||||
BTA_AV_RS_NONE, /* straight API call */
|
||||
@@ -425,6 +435,7 @@ typedef union {
|
||||
BT_HDR hdr;
|
||||
tBTA_AV_API_ENABLE api_enable;
|
||||
tBTA_AV_API_REG api_reg;
|
||||
tBTA_AV_API_REG_SEP api_reg_sep;
|
||||
tBTA_AV_API_OPEN api_open;
|
||||
tBTA_AV_API_STOP api_stop;
|
||||
tBTA_AV_API_DISCNT api_discnt;
|
||||
|
@@ -339,6 +339,73 @@ void BTA_AgCiData(UINT16 handle)
|
||||
bta_sys_sendmsg(p_buf);
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function BTA_AgAudioBuffAlloc
|
||||
**
|
||||
** Description Allocate an audio buffer with specific size, reserve enough
|
||||
** space and offset for lower layer to send the buffer directly.
|
||||
**
|
||||
**
|
||||
** Returns void
|
||||
**
|
||||
*******************************************************************************/
|
||||
void BTA_AgAudioBuffAlloc(UINT16 size, UINT8 **pp_buff, UINT8 **pp_data)
|
||||
{
|
||||
/* reserve 1 byte at last, when the size is mSBC frame size (57), then we got a buffer that can hold 60 bytes data */
|
||||
BT_HDR *p_buf= (BT_HDR *)osi_calloc(sizeof(BT_HDR) + BTA_AG_BUFF_OFFSET_MIN + BTA_AG_H2_HEADER_LEN + size + 1);
|
||||
if (p_buf != NULL) {
|
||||
/* mSBC offset is large than CVSD, so this is also work in CVSD air mode */
|
||||
p_buf->offset = BTA_AG_BUFF_OFFSET_MIN + BTA_AG_H2_HEADER_LEN;
|
||||
*pp_buff = (UINT8 *)p_buf;
|
||||
*pp_data = (UINT8 *)(p_buf + 1) + p_buf->offset;
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function BTA_AgAudioBuffFree
|
||||
**
|
||||
** Description Free an audio buffer.
|
||||
**
|
||||
**
|
||||
** Returns void
|
||||
**
|
||||
*******************************************************************************/
|
||||
void BTA_AgAudioBuffFree(UINT8 *p_buf)
|
||||
{
|
||||
osi_free(p_buf);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function BTA_AgAudioDataSend
|
||||
**
|
||||
** Description Send audio data to lower level, whether success or not, buffer
|
||||
** is consumed.
|
||||
**
|
||||
**
|
||||
** Returns void
|
||||
**
|
||||
*******************************************************************************/
|
||||
void BTA_AgAudioDataSend(UINT16 handle, UINT8 *p_buff_start, UINT8 *p_data, UINT16 data_len)
|
||||
{
|
||||
BT_HDR *p_buf = (BT_HDR *)p_buff_start;
|
||||
tBTA_AG_SCB *p_scb;
|
||||
assert(p_data - (UINT8 *)(p_buf + 1) >= 0);
|
||||
if ((p_scb = bta_ag_scb_by_idx(handle)) != NULL) {
|
||||
p_buf->event = BTA_AG_API_SCO_DATA_SEND_EVT;
|
||||
p_buf->layer_specific = handle;
|
||||
p_buf->offset = p_data - (UINT8 *)(p_buf + 1);
|
||||
p_buf->len = data_len;
|
||||
bta_sys_sendmsg(p_buf);
|
||||
}
|
||||
else {
|
||||
osi_free(p_buf);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* #if (BTM_SCO_HCI_INCLUDED == TRUE) */
|
||||
|
||||
#endif /* #if (BTA_AG_INCLUDED == TRUE)*/
|
||||
|
@@ -89,6 +89,8 @@ enum
|
||||
BTA_AG_SETCODEC,
|
||||
BTA_AG_SEND_RING,
|
||||
BTA_AG_CI_SCO_DATA,
|
||||
BTA_AG_SCO_DATA_SEND,
|
||||
BTA_AG_SCO_DATA_FREE,
|
||||
BTA_AG_CI_RX_DATA,
|
||||
BTA_AG_RCVD_SLC_READY,
|
||||
BTA_AG_PKT_STAT_NUMS,
|
||||
@@ -133,6 +135,8 @@ const tBTA_AG_ACTION bta_ag_action[] =
|
||||
bta_ag_setcodec,
|
||||
bta_ag_send_ring,
|
||||
bta_ag_ci_sco_data,
|
||||
bta_ag_sco_data_send,
|
||||
bta_ag_sco_data_free,
|
||||
bta_ag_ci_rx_data,
|
||||
bta_ag_rcvd_slc_ready,
|
||||
bta_ag_pkt_stat_nums
|
||||
@@ -155,6 +159,7 @@ const UINT8 bta_ag_st_init[][BTA_AG_NUM_COLS] =
|
||||
/* API_AUDIO_CLOSE_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST},
|
||||
/* API_RESULT_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST},
|
||||
/* API_SETCODEC_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST},
|
||||
/* API_SCO_DATA_SEND_EVT */ {BTA_AG_SCO_DATA_FREE, BTA_AG_IGNORE, BTA_AG_INIT_ST},
|
||||
/* RFC_OPEN_EVT */ {BTA_AG_RFC_ACP_OPEN, BTA_AG_SCO_LISTEN, BTA_AG_OPEN_ST},
|
||||
/* RFC_CLOSE_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST},
|
||||
/* RFC_SRV_CLOSE_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST},
|
||||
@@ -185,6 +190,7 @@ const UINT8 bta_ag_st_opening[][BTA_AG_NUM_COLS] =
|
||||
/* API_AUDIO_CLOSE_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPENING_ST},
|
||||
/* API_RESULT_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPENING_ST},
|
||||
/* API_SETCODEC_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPENING_ST},
|
||||
/* API_SCO_DATA_SEND_EVT */ {BTA_AG_SCO_DATA_FREE, BTA_AG_IGNORE, BTA_AG_OPENING_ST},
|
||||
/* RFC_OPEN_EVT */ {BTA_AG_RFC_OPEN, BTA_AG_SCO_LISTEN, BTA_AG_OPEN_ST},
|
||||
/* RFC_CLOSE_EVT */ {BTA_AG_RFC_FAIL, BTA_AG_IGNORE, BTA_AG_INIT_ST},
|
||||
/* RFC_SRV_CLOSE_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPENING_ST},
|
||||
@@ -215,6 +221,7 @@ const UINT8 bta_ag_st_open[][BTA_AG_NUM_COLS] =
|
||||
/* API_AUDIO_CLOSE_EVT */ {BTA_AG_SCO_CLOSE, BTA_AG_IGNORE, BTA_AG_OPEN_ST},
|
||||
/* API_RESULT_EVT */ {BTA_AG_RESULT, BTA_AG_IGNORE, BTA_AG_OPEN_ST},
|
||||
/* API_SETCODEC_EVT */ {BTA_AG_SETCODEC, BTA_AG_IGNORE, BTA_AG_OPEN_ST},
|
||||
/* API_SCO_DATA_SEND_EVT */ {BTA_AG_SCO_DATA_SEND, BTA_AG_IGNORE, BTA_AG_OPEN_ST},
|
||||
/* RFC_OPEN_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPEN_ST},
|
||||
/* RFC_CLOSE_EVT */ {BTA_AG_RFC_CLOSE, BTA_AG_IGNORE, BTA_AG_INIT_ST},
|
||||
/* RFC_SRV_CLOSE_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPEN_ST},
|
||||
@@ -245,6 +252,7 @@ const UINT8 bta_ag_st_closing[][BTA_AG_NUM_COLS] =
|
||||
/* API_AUDIO_CLOSE_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
|
||||
/* API_RESULT_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
|
||||
/* API_SETCODEC_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
|
||||
/* API_SCO_DATA_SEND_EVT */ {BTA_AG_SCO_DATA_FREE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
|
||||
/* RFC_OPEN_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
|
||||
/* RFC_CLOSE_EVT */ {BTA_AG_RFC_CLOSE, BTA_AG_IGNORE, BTA_AG_INIT_ST},
|
||||
/* RFC_SRV_CLOSE_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
|
||||
@@ -360,9 +368,9 @@ static char *bta_ag_evt_str(UINT16 event, tBTA_AG_RES result)
|
||||
case BTA_AG_API_DISABLE_EVT:
|
||||
return "Disable AG";
|
||||
case BTA_AG_CI_SCO_DATA_EVT:
|
||||
return "SCO data Callin";
|
||||
return "SCO data Call In";
|
||||
case BTA_AG_CI_SLC_READY_EVT:
|
||||
return "SLC Ready Callin";
|
||||
return "SLC Ready Call In";
|
||||
case BTA_AG_PKT_STAT_NUMS_GET_EVT:
|
||||
return "Get Packet Nums";
|
||||
default:
|
||||
@@ -433,6 +441,7 @@ static tBTA_AG_SCB *bta_ag_scb_alloc(void)
|
||||
#if (BTM_WBS_INCLUDED == TRUE)
|
||||
p_scb->codec_updated = FALSE;
|
||||
#endif
|
||||
p_scb->p_sco_data = NULL;
|
||||
/* set up timers */
|
||||
p_scb->act_timer.param = (UINT32) p_scb;
|
||||
p_scb->act_timer.p_cback = bta_ag_timer_cback;
|
||||
@@ -473,6 +482,10 @@ void bta_ag_scb_dealloc(tBTA_AG_SCB *p_scb)
|
||||
#if (BTM_WBS_INCLUDED == TRUE)
|
||||
bta_sys_free_timer(&p_scb->cn_timer);
|
||||
#endif
|
||||
if (p_scb->p_sco_data != NULL) {
|
||||
osi_free(p_scb->p_sco_data);
|
||||
p_scb->p_sco_data = NULL;
|
||||
}
|
||||
bta_sys_free_timer(&p_scb->colli_timer);
|
||||
|
||||
/* initialize control block */
|
||||
@@ -774,7 +787,7 @@ static void bta_ag_api_enable(tBTA_AG_DATA *p_data)
|
||||
bta_ag_cb.scb->negotiated_codec = BTM_SCO_CODEC_CVSD;
|
||||
}
|
||||
|
||||
/* set deault setting for eSCO/SCO */
|
||||
/* set default setting for eSCO/SCO */
|
||||
BTM_WriteVoiceSettings(AG_VOICE_SETTINGS);
|
||||
bta_sys_collision_register (BTA_ID_AG, bta_ag_collision_cback);
|
||||
/* call callback with enable event */
|
||||
@@ -943,6 +956,7 @@ void bta_ag_sm_execute(tBTA_AG_SCB *p_scb, UINT16 event, tBTA_AG_DATA *p_data)
|
||||
BOOLEAN bta_ag_hdl_event(BT_HDR *p_msg)
|
||||
{
|
||||
tBTA_AG_SCB *p_scb;
|
||||
BOOLEAN free_msg = TRUE;
|
||||
APPL_TRACE_DEBUG("bta_ag_hdl_event: Event 0x%04x ", p_msg->event);
|
||||
|
||||
switch (p_msg->event) {
|
||||
@@ -966,15 +980,22 @@ BOOLEAN bta_ag_hdl_event(BT_HDR *p_msg)
|
||||
bta_ag_api_result((tBTA_AG_DATA *) p_msg);
|
||||
break;
|
||||
|
||||
/* all others reference scb by handle */
|
||||
case BTA_AG_API_SCO_DATA_SEND_EVT:
|
||||
free_msg = FALSE;
|
||||
/* fall through */
|
||||
default:
|
||||
/* all others reference scb by handle */
|
||||
if ((p_scb = bta_ag_scb_by_idx(p_msg->layer_specific)) != NULL) {
|
||||
APPL_TRACE_DEBUG("bta_ag_hdl_event: p_scb 0x%08x ", (unsigned int)p_scb);
|
||||
bta_ag_sm_execute(p_scb, p_msg->event, (tBTA_AG_DATA *) p_msg);
|
||||
}
|
||||
else {
|
||||
/* free message if p_scb not found */
|
||||
free_msg = TRUE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return TRUE;
|
||||
return free_msg;
|
||||
}
|
||||
|
||||
#endif /* #if (BTA_AG_INCLUDED == TRUE) */
|
||||
|
@@ -345,9 +345,10 @@ static void bta_ag_sco_read_cback(UINT16 sco_inx, BT_HDR *p_data, tBTM_SCO_DATA_
|
||||
APPL_TRACE_DEBUG("bta_ag_sco_read_cback: status(%d)", status);
|
||||
}
|
||||
|
||||
#if (BTA_HFP_EXT_CODEC == FALSE)
|
||||
/* Callout function must free the data. */
|
||||
bta_ag_sco_co_in_data(p_data, status);
|
||||
osi_free(p_data);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
/*******************************************************************************
|
||||
@@ -459,6 +460,37 @@ static void bta_ag_esco_connreq_cback(tBTM_ESCO_EVT event, tBTM_ESCO_EVT_DATA *p
|
||||
}
|
||||
}
|
||||
|
||||
#if (BTM_SCO_HCI_INCLUDED == TRUE) && (BTA_HFP_EXT_CODEC == TRUE)
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function bta_ag_sco_get_frame_size
|
||||
**
|
||||
** Description Get SCO frame size.
|
||||
**
|
||||
**
|
||||
** Returns SCO frame size
|
||||
**
|
||||
*******************************************************************************/
|
||||
static UINT16 bta_ag_sco_get_frame_size(tBTA_AG_SCB *p_scb)
|
||||
{
|
||||
UINT16 frame_size = 0;
|
||||
switch (p_scb->air_mode)
|
||||
{
|
||||
case BTM_SCO_AIR_MODE_CVSD:
|
||||
frame_size = p_scb->out_pkt_len;
|
||||
break;
|
||||
case BTM_SCO_AIR_MODE_TRANSPNT:
|
||||
frame_size = BTA_AG_MSBC_FRAME_SIZE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return frame_size;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function bta_ag_cback_sco
|
||||
@@ -471,14 +503,19 @@ static void bta_ag_esco_connreq_cback(tBTM_ESCO_EVT event, tBTM_ESCO_EVT_DATA *p
|
||||
*******************************************************************************/
|
||||
static void bta_ag_cback_sco(tBTA_AG_SCB *p_scb, UINT8 event)
|
||||
{
|
||||
tBTA_AG_HDR sco;
|
||||
tBTA_AG_AUDIO_STAT audio_stat = {0};
|
||||
|
||||
sco.handle = bta_ag_scb_to_idx(p_scb);
|
||||
sco.app_id = p_scb->app_id;
|
||||
sco.sync_conn_handle = BTM_ReadScoHandle(p_scb->sco_idx);
|
||||
audio_stat.hdr.handle = bta_ag_scb_to_idx(p_scb);
|
||||
audio_stat.hdr.app_id = p_scb->app_id;
|
||||
audio_stat.hdr.sync_conn_handle = BTM_ReadScoHandle(p_scb->sco_idx);
|
||||
#if (BTM_SCO_HCI_INCLUDED == TRUE) && (BTA_HFP_EXT_CODEC == TRUE)
|
||||
if (event != BTA_AG_AUDIO_CLOSE_EVT) {
|
||||
audio_stat.preferred_frame_size = bta_ag_sco_get_frame_size(p_scb);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* call close cback */
|
||||
(*bta_ag_cb.p_cback)(event, (tBTA_AG *) &sco);
|
||||
(*bta_ag_cb.p_cback)(event, (tBTA_AG *) &audio_stat);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
@@ -784,7 +821,7 @@ static void bta_ag_sco_event(tBTA_AG_SCB *p_scb, UINT8 event)
|
||||
p_scb->sco_idx, p_sco->state,
|
||||
bta_ag_sco_state_str(p_sco->state), event, bta_ag_sco_evt_str(event));
|
||||
|
||||
#if (BTM_SCO_HCI_INCLUDED == TRUE)
|
||||
#if (BTM_SCO_HCI_INCLUDED == TRUE) && (BTA_HFP_EXT_CODEC == FALSE)
|
||||
BT_HDR *p_buf;
|
||||
if (event == BTA_AG_SCO_CI_DATA_E)
|
||||
{
|
||||
@@ -1633,6 +1670,11 @@ void bta_ag_sco_conn_close(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
|
||||
bta_sys_sco_unuse(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
|
||||
}
|
||||
|
||||
if (p_scb->p_sco_data != NULL) {
|
||||
osi_free(p_scb->p_sco_data);
|
||||
p_scb->p_sco_data = NULL;
|
||||
}
|
||||
|
||||
/* call app callback */
|
||||
bta_ag_cback_sco(p_scb, BTA_AG_AUDIO_CLOSE_EVT);
|
||||
#if (BTM_WBS_INCLUDED == TRUE)
|
||||
@@ -1665,7 +1707,7 @@ void bta_ag_sco_conn_rsp(tBTA_AG_SCB *p_scb, tBTM_ESCO_CONN_REQ_EVT_DATA *p_data
|
||||
bta_ag_cb.sco.state == BTA_AG_SCO_CLOSE_XFER_ST ||
|
||||
bta_ag_cb.sco.state == BTA_AG_SCO_OPEN_XFER_ST)
|
||||
{
|
||||
/* If script overrided sco parameter by BTA_CMD_SET_ESCO_PARAM */
|
||||
/* If script override sco parameter by BTA_CMD_SET_ESCO_PARAM */
|
||||
if (bta_ag_cb.sco.param_updated)
|
||||
{
|
||||
resp = bta_ag_cb.sco.params;
|
||||
@@ -1736,7 +1778,7 @@ void bta_ag_sco_conn_rsp(tBTA_AG_SCB *p_scb, tBTM_ESCO_CONN_REQ_EVT_DATA *p_data
|
||||
**
|
||||
** Function bta_ag_ci_sco_data
|
||||
**
|
||||
** Description Process the SCO data ready callin event
|
||||
** Description Process the SCO data ready call in event
|
||||
**
|
||||
**
|
||||
** Returns void
|
||||
@@ -1752,6 +1794,288 @@ void bta_ag_ci_sco_data(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
|
||||
#endif
|
||||
}
|
||||
|
||||
#if (BTM_SCO_HCI_INCLUDED == TRUE) && (BTA_HFP_EXT_CODEC == TRUE)
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function bta_ag_write_sco_data
|
||||
**
|
||||
** Description Write two SCO data buffers to specified instance
|
||||
**
|
||||
**
|
||||
** Returns void
|
||||
**
|
||||
*******************************************************************************/
|
||||
static void bta_ag_write_sco_data(tBTA_AG_SCB *p_scb, BT_HDR *p_buf1, BT_HDR *p_buf2)
|
||||
{
|
||||
BTM_WriteScoData(p_scb->sco_idx, p_buf1);
|
||||
if (p_buf2 != NULL) {
|
||||
BTM_WriteScoData(p_scb->sco_idx, p_buf2);
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function bta_ag_sco_data_send_cvsd
|
||||
**
|
||||
** Description Process SCO data of CVSD air mode
|
||||
**
|
||||
**
|
||||
** Returns void
|
||||
**
|
||||
*******************************************************************************/
|
||||
static void bta_ag_sco_data_send_cvsd(tBTA_AG_SCB *p_scb, BT_HDR *p_buf)
|
||||
{
|
||||
UINT16 out_pkt_len = p_scb->out_pkt_len;
|
||||
|
||||
if (p_scb->p_sco_data != NULL) {
|
||||
/* the remaining data of last sending operation */
|
||||
BT_HDR *p_buf_last = p_scb->p_sco_data;
|
||||
/* remaining data len should small than out_pkt_len */
|
||||
assert(p_buf_last->len < out_pkt_len);
|
||||
BT_HDR *p_buf2 = osi_calloc(sizeof(BT_HDR) + BTA_AG_BUFF_OFFSET_MIN + out_pkt_len);
|
||||
if (p_buf2 == NULL) {
|
||||
osi_free(p_buf);
|
||||
osi_free(p_buf_last);
|
||||
p_scb->p_sco_data = NULL;
|
||||
APPL_TRACE_WARNING("%s, no memory", __FUNCTION__);
|
||||
return;
|
||||
}
|
||||
p_buf2->offset = BTA_AG_BUFF_OFFSET_MIN;
|
||||
UINT8 *p_data = (UINT8 *)(p_buf2 + 1) + p_buf2->offset;
|
||||
memcpy(p_data, (UINT8 *)(p_buf_last + 1) + p_buf_last->offset, p_buf_last->len);
|
||||
|
||||
if (p_buf->len + p_buf_last->len < out_pkt_len) {
|
||||
memcpy(p_data + p_buf_last->len, (UINT8 *)(p_buf + 1) + p_buf->offset, p_buf->len);
|
||||
p_buf2->len = p_buf->len + p_buf_last->len;
|
||||
osi_free(p_buf);
|
||||
osi_free(p_buf_last);
|
||||
p_scb->p_sco_data = p_buf2;
|
||||
}
|
||||
else {
|
||||
UINT16 copy_len = out_pkt_len - p_buf_last->len;
|
||||
memcpy(p_data + p_buf_last->len, (UINT8 *)(p_buf + 1) + p_buf->offset, copy_len);
|
||||
p_buf2->len = out_pkt_len;
|
||||
p_buf->offset += copy_len;
|
||||
p_buf->len -= copy_len;
|
||||
osi_free(p_buf_last);
|
||||
p_scb->p_sco_data = NULL;
|
||||
bta_ag_write_sco_data(p_scb, p_buf2, NULL);
|
||||
|
||||
if (p_buf->len == 0) {
|
||||
osi_free(p_buf);
|
||||
}
|
||||
else {
|
||||
/* recursive call, this will only called once */
|
||||
bta_ag_sco_data_send_cvsd(p_scb, p_buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (p_buf->len < out_pkt_len) {
|
||||
p_scb->p_sco_data = p_buf;
|
||||
}
|
||||
else {
|
||||
/* p_scb->p_sco_data != NULL && p_buf->len >= out_pkt_len */
|
||||
while (1) {
|
||||
if (p_buf->len == out_pkt_len) {
|
||||
bta_ag_write_sco_data(p_scb, p_buf, NULL);
|
||||
break;
|
||||
}
|
||||
else {
|
||||
BT_HDR *p_buf2 = osi_calloc(sizeof(BT_HDR) + BTA_AG_BUFF_OFFSET_MIN + out_pkt_len);
|
||||
if (p_buf2 == NULL) {
|
||||
osi_free(p_buf);
|
||||
APPL_TRACE_WARNING("%s, no memory", __FUNCTION__);
|
||||
return;
|
||||
}
|
||||
p_buf2->offset = BTA_AG_BUFF_OFFSET_MIN;
|
||||
UINT8 *p_data = (UINT8 *)(p_buf2 + 1) + p_buf2->offset;
|
||||
memcpy(p_data, (UINT8 *)(p_buf + 1) + p_buf->offset, out_pkt_len);
|
||||
p_buf2->len = out_pkt_len;
|
||||
p_buf->offset += out_pkt_len;
|
||||
p_buf->len -= out_pkt_len;
|
||||
bta_ag_write_sco_data(p_scb, p_buf2, NULL);
|
||||
}
|
||||
if (p_buf->len < out_pkt_len) {
|
||||
p_scb->p_sco_data = p_buf;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function bta_ag_sco_data_send_msbc
|
||||
**
|
||||
** Description Process SCO data of mSBC air mode
|
||||
**
|
||||
**
|
||||
** Returns void
|
||||
**
|
||||
*******************************************************************************/
|
||||
static void bta_ag_sco_data_send_msbc(tBTA_AG_SCB *p_scb, BT_HDR *p_buf)
|
||||
{
|
||||
UINT16 out_pkt_len = p_scb->out_pkt_len;
|
||||
if (p_buf->len == BTA_AG_MSBC_FRAME_SIZE && p_buf->offset >= BTA_AG_BUFF_OFFSET_MIN + BTA_AG_H2_HEADER_LEN) {
|
||||
/* add H2 header */
|
||||
p_buf->offset -= BTA_AG_H2_HEADER_LEN;
|
||||
UINT8 *p_data = (UINT8 *)(p_buf + 1) + p_buf->offset;
|
||||
bta_ag_h2_header((UINT16 *)p_data);
|
||||
/* add header len, add addition one bytes, the len is BTA_AG_SCO_OUT_PKT_LEN_2EV3 now */
|
||||
p_buf->len += BTA_AG_H2_HEADER_LEN + 1;
|
||||
|
||||
if (out_pkt_len == BTA_AG_SCO_OUT_PKT_LEN_2EV3) {
|
||||
/* mSBC frame can be send directly */
|
||||
bta_ag_write_sco_data(p_scb, p_buf, NULL);
|
||||
}
|
||||
else if (out_pkt_len == BTA_AG_SCO_OUT_PKT_LEN_EV3) {
|
||||
/* need to split into 2 sco packages for sending */
|
||||
BT_HDR *p_buf2 = osi_calloc(sizeof(BT_HDR) + BTA_AG_BUFF_OFFSET_MIN + BTA_AG_SCO_OUT_PKT_LEN_EV3);
|
||||
if (p_buf2 == NULL) {
|
||||
/* free the first buff too */
|
||||
osi_free(p_buf);
|
||||
APPL_TRACE_WARNING("%s, no memory", __FUNCTION__);
|
||||
return;
|
||||
}
|
||||
p_buf2->offset = BTA_AG_BUFF_OFFSET_MIN;
|
||||
p_buf2->len = BTA_AG_SCO_OUT_PKT_LEN_EV3;
|
||||
UINT8 *p_data2 = (UINT8 *)(p_buf2 + 1) + p_buf2->offset;
|
||||
memcpy(p_data2, p_data + BTA_AG_SCO_OUT_PKT_LEN_EV3, BTA_AG_SCO_OUT_PKT_LEN_EV3);
|
||||
/* update the first packet len */
|
||||
p_buf->len = BTA_AG_SCO_OUT_PKT_LEN_EV3;
|
||||
bta_ag_write_sco_data(p_scb, p_buf, p_buf2);
|
||||
}
|
||||
else {
|
||||
osi_free(p_buf);
|
||||
APPL_TRACE_WARNING("%s, invalid out pkt len: %d", __FUNCTION__, out_pkt_len);
|
||||
}
|
||||
}
|
||||
else if (p_buf->len != 0 && p_buf->len % BTA_AG_MSBC_FRAME_SIZE == 0) {
|
||||
/* multiple mSBC frame in the buffer, or just one but offset is too small */
|
||||
UINT8 *p_data = (UINT8 *)(p_buf + 1) + p_buf->offset;
|
||||
UINT16 total_len = p_buf->len;
|
||||
if (out_pkt_len == BTA_AG_SCO_OUT_PKT_LEN_2EV3) {
|
||||
while (total_len != 0) {
|
||||
BT_HDR *p_buf2 = osi_calloc(sizeof(BT_HDR) + BTA_AG_BUFF_OFFSET_MIN + BTA_AG_SCO_OUT_PKT_LEN_2EV3);
|
||||
if (p_buf2 == NULL) {
|
||||
APPL_TRACE_WARNING("%s, no memory", __FUNCTION__);
|
||||
break;
|
||||
}
|
||||
p_buf2->offset = BTA_AG_BUFF_OFFSET_MIN;
|
||||
p_buf2->len = BTA_AG_SCO_OUT_PKT_LEN_2EV3;
|
||||
UINT8 *p_data2 = (UINT8 *)(p_buf2 + 1) + p_buf2->offset;
|
||||
bta_ag_h2_header((UINT16 *)p_data2);
|
||||
p_data2 += BTA_AG_H2_HEADER_LEN;
|
||||
memcpy(p_data2, p_data, BTA_AG_MSBC_FRAME_SIZE);
|
||||
p_data += BTA_AG_MSBC_FRAME_SIZE;
|
||||
total_len -= BTA_AG_MSBC_FRAME_SIZE;
|
||||
bta_ag_write_sco_data(p_scb, p_buf2, NULL);
|
||||
}
|
||||
}
|
||||
else if (out_pkt_len == BTA_AG_SCO_OUT_PKT_LEN_EV3) {
|
||||
while (total_len != 0) {
|
||||
BT_HDR *p_buf2 = osi_calloc(sizeof(BT_HDR) + BTA_AG_BUFF_OFFSET_MIN + BTA_AG_SCO_OUT_PKT_LEN_EV3);
|
||||
if (p_buf2 == NULL) {
|
||||
APPL_TRACE_WARNING("%s, no memory", __FUNCTION__);
|
||||
break;
|
||||
}
|
||||
BT_HDR *p_buf3 = osi_calloc(sizeof(BT_HDR) + BTA_AG_BUFF_OFFSET_MIN + BTA_AG_SCO_OUT_PKT_LEN_EV3);
|
||||
if (p_buf3 == NULL) {
|
||||
/* free the first buff too */
|
||||
osi_free(p_buf2);
|
||||
APPL_TRACE_WARNING("%s, no memory", __FUNCTION__);
|
||||
break;
|
||||
}
|
||||
|
||||
/* build first packet, include H2 header */
|
||||
p_buf2->offset = BTA_AG_BUFF_OFFSET_MIN;
|
||||
p_buf2->len = BTA_AG_SCO_OUT_PKT_LEN_EV3;
|
||||
UINT8 *p_data2 = (UINT8 *)(p_buf2 + 1) + p_buf2->offset;
|
||||
bta_ag_h2_header((UINT16 *)p_data2);
|
||||
p_data2 += BTA_AG_H2_HEADER_LEN;
|
||||
memcpy(p_data2, p_data, BTA_AG_SCO_OUT_PKT_LEN_EV3 - BTA_AG_H2_HEADER_LEN);
|
||||
p_data += BTA_AG_SCO_OUT_PKT_LEN_EV3 - BTA_AG_H2_HEADER_LEN;
|
||||
total_len -= BTA_AG_SCO_OUT_PKT_LEN_EV3 - BTA_AG_H2_HEADER_LEN;
|
||||
|
||||
/* build second packet, not include header */
|
||||
p_buf3->offset = BTA_AG_BUFF_OFFSET_MIN;
|
||||
p_buf3->len = BTA_AG_SCO_OUT_PKT_LEN_EV3;
|
||||
UINT8 *p_data3 = (UINT8 *)(p_buf3 + 1) + p_buf3->offset;
|
||||
memcpy(p_data3, p_data, BTA_AG_MSBC_FRAME_SIZE - BTA_AG_H2_HEADER_LEN - BTA_AG_SCO_OUT_PKT_LEN_EV3);
|
||||
p_data += BTA_AG_MSBC_FRAME_SIZE - BTA_AG_H2_HEADER_LEN - BTA_AG_SCO_OUT_PKT_LEN_EV3;
|
||||
total_len -= BTA_AG_MSBC_FRAME_SIZE - BTA_AG_H2_HEADER_LEN - BTA_AG_SCO_OUT_PKT_LEN_EV3;
|
||||
bta_ag_write_sco_data(p_scb, p_buf2, p_buf3);
|
||||
}
|
||||
}
|
||||
else {
|
||||
APPL_TRACE_WARNING("%s, invalid out pkt len: %d", __FUNCTION__, out_pkt_len);
|
||||
}
|
||||
osi_free(p_buf);
|
||||
}
|
||||
else {
|
||||
APPL_TRACE_WARNING("%s, unaccepted data len: %d", __FUNCTION__, p_buf->len);
|
||||
osi_free(p_buf);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function bta_ag_sco_data_send
|
||||
**
|
||||
** Description Route SCO data to specific processing function based on air mode
|
||||
**
|
||||
**
|
||||
** Returns void
|
||||
**
|
||||
*******************************************************************************/
|
||||
void bta_ag_sco_data_send(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
|
||||
{
|
||||
BT_HDR *p_buf = (BT_HDR *) p_data;
|
||||
|
||||
#if (BTM_SCO_HCI_INCLUDED == TRUE) && (BTA_HFP_EXT_CODEC == TRUE)
|
||||
if (bta_ag_cb.sco.state != BTA_AG_SCO_OPEN_ST || bta_ag_cb.sco.cur_idx != p_scb->sco_idx) {
|
||||
osi_free(p_data);
|
||||
APPL_TRACE_WARNING("%s: SCO invalid state", __FUNCTION__);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (p_scb->air_mode)
|
||||
{
|
||||
case BTM_SCO_AIR_MODE_CVSD:
|
||||
bta_ag_sco_data_send_cvsd(p_scb, p_buf);
|
||||
break;
|
||||
case BTM_SCO_AIR_MODE_TRANSPNT:
|
||||
bta_ag_sco_data_send_msbc(p_scb, p_buf);
|
||||
break;
|
||||
default:
|
||||
osi_free(p_buf);
|
||||
APPL_TRACE_WARNING("%s: unsupported air mode: %d", __FUNCTION__, p_scb->air_mode);
|
||||
break;
|
||||
}
|
||||
#else
|
||||
osi_free(p_buf);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function bta_ag_sco_data_free
|
||||
**
|
||||
** Description Free SCO data
|
||||
**
|
||||
**
|
||||
** Returns void
|
||||
**
|
||||
*******************************************************************************/
|
||||
void bta_ag_sco_data_free(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
|
||||
{
|
||||
UNUSED(p_scb);
|
||||
osi_free(p_data);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function bta_ag_set_esco_param
|
||||
|
@@ -96,6 +96,19 @@
|
||||
BTA_AG_FEAT_VREC | BTA_AG_FEAT_INBAND | \
|
||||
BTA_AG_FEAT_VTAG)
|
||||
|
||||
#if (BTM_SCO_HCI_INCLUDED == TRUE)
|
||||
/* 1 (offset can not be 0) + HCI_SCO_PREAMBLE */
|
||||
#define BTA_AG_BUFF_OFFSET_MIN (1 + HCI_SCO_PREAMBLE_SIZE)
|
||||
/* mSBC H2 header length */
|
||||
#define BTA_AG_H2_HEADER_LEN 2
|
||||
/* mSBC frame size not include H1/H2 header */
|
||||
#define BTA_AG_MSBC_FRAME_SIZE 57
|
||||
/* max user data len of sco packet type EV3 */
|
||||
#define BTA_AG_SCO_OUT_PKT_LEN_EV3 30
|
||||
/* max user data len of sco packet type 2-EV3 */
|
||||
#define BTA_AG_SCO_OUT_PKT_LEN_2EV3 60
|
||||
#endif
|
||||
|
||||
enum
|
||||
{
|
||||
/* these events are handled by the state machine */
|
||||
@@ -107,6 +120,7 @@ enum
|
||||
BTA_AG_API_AUDIO_CLOSE_EVT,
|
||||
BTA_AG_API_RESULT_EVT,
|
||||
BTA_AG_API_SETCODEC_EVT,
|
||||
BTA_AG_API_SCO_DATA_SEND_EVT,
|
||||
BTA_AG_RFC_OPEN_EVT,
|
||||
BTA_AG_RFC_CLOSE_EVT,
|
||||
BTA_AG_RFC_SRV_CLOSE_EVT,
|
||||
@@ -295,6 +309,7 @@ typedef struct
|
||||
TIMER_LIST_ENT cn_timer; /* codec negotiation timer */
|
||||
#endif
|
||||
UINT16 sco_idx; /* SCO connection index */
|
||||
BT_HDR *p_sco_data; /* remaining SCO data of last sending operation */
|
||||
BOOLEAN in_use; /* scb in use */
|
||||
BOOLEAN dealloc; /* TRUE if service shutting down */
|
||||
BOOLEAN clip_enabled; /* set to TRUE if HF enables CLIP reporting */
|
||||
@@ -452,10 +467,13 @@ extern void bta_ag_result(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
|
||||
extern void bta_ag_setcodec(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
|
||||
extern void bta_ag_send_ring(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
|
||||
extern void bta_ag_ci_sco_data(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
|
||||
extern void bta_ag_sco_data_send(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
|
||||
extern void bta_ag_sco_data_free(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
|
||||
extern void bta_ag_set_esco_param(BOOLEAN set_reset, tBTM_ESCO_PARAMS *param);
|
||||
extern void bta_ag_ci_rx_data(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
|
||||
extern void bta_ag_rcvd_slc_ready(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
|
||||
extern void bta_ag_pkt_stat_nums(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
|
||||
extern void bta_ag_h2_header(UINT16 *p_buf);
|
||||
|
||||
#endif /* #if (BTA_AG_INCLUDED == TRUE) */
|
||||
|
||||
|
@@ -44,9 +44,9 @@ static const uint8_t bta_hf_client_cb_data_size[] = {
|
||||
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_AUDIO_STAT), // #define BTA_HF_CLIENT_AUDIO_OPEN_EVT 5
|
||||
sizeof(tBTA_HF_CLIENT_AUDIO_STAT), // #define BTA_HF_CLIENT_AUDIO_MSBC_OPEN_EVT 6
|
||||
sizeof(tBTA_HF_CLIENT_AUDIO_STAT), // #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
|
||||
@@ -322,6 +322,16 @@ void BTA_HfClientPktStatsNumsGet(UINT16 sync_conn_handle)
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function BTA_HfClientCiData
|
||||
**
|
||||
** Description Send SCO outgoing data ready event
|
||||
**
|
||||
**
|
||||
** Returns void
|
||||
**
|
||||
*******************************************************************************/
|
||||
void BTA_HfClientCiData(void)
|
||||
{
|
||||
BT_HDR *p_buf;
|
||||
@@ -330,8 +340,79 @@ void BTA_HfClientCiData(void)
|
||||
bta_sys_sendmsg(p_buf);
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function BTA_HfClientAudioBuffAlloc
|
||||
**
|
||||
** Description Allocate an audio buffer with specific size, reserve enough
|
||||
** space and offset for lower layer to send the buffer directly.
|
||||
**
|
||||
**
|
||||
** Returns void
|
||||
**
|
||||
*******************************************************************************/
|
||||
void BTA_HfClientAudioBuffAlloc(UINT16 size, UINT8 **pp_buff, UINT8 **pp_data)
|
||||
{
|
||||
/* reserve 1 byte at last, when the size is mSBC frame size (57), then we got a buffer that can hold 60 bytes data */
|
||||
BT_HDR *p_buf= (BT_HDR *)osi_calloc(sizeof(BT_HDR) + BTA_HF_CLIENT_BUFF_OFFSET_MIN + BTA_HF_CLIENT_H2_HEADER_LEN + size + 1);
|
||||
if (p_buf != NULL) {
|
||||
/* mSBC offset is large than CVSD, so this is work in CVSD air mode */
|
||||
p_buf->offset = BTA_HF_CLIENT_BUFF_OFFSET_MIN + BTA_HF_CLIENT_H2_HEADER_LEN;
|
||||
*pp_buff = (UINT8 *)p_buf;
|
||||
*pp_data = (UINT8 *)(p_buf + 1) + p_buf->offset;
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function BTA_HfClientAudioBuffFree
|
||||
**
|
||||
** Description Free an audio buffer.
|
||||
**
|
||||
**
|
||||
** Returns void
|
||||
**
|
||||
*******************************************************************************/
|
||||
void BTA_HfClientAudioBuffFree(UINT8 *p_buf)
|
||||
{
|
||||
osi_free(p_buf);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function BTA_HfClientAudioDataSend
|
||||
**
|
||||
** Description Send audio data to lower layer, whether success or not, buffer
|
||||
** is consumed.
|
||||
**
|
||||
**
|
||||
** Returns void
|
||||
**
|
||||
*******************************************************************************/
|
||||
void BTA_HfClientAudioDataSend(UINT16 sync_conn_hdl, UINT8 *p_buff_start, UINT8 *p_data, UINT16 data_len)
|
||||
{
|
||||
/* currently, sync_conn_hdl is not used */
|
||||
BT_HDR *p_buf = (BT_HDR *)p_buff_start;
|
||||
assert(p_data - (UINT8 *)(p_buf + 1) >= 0);
|
||||
p_buf->event = BTA_HF_CLIENT_SCO_DATA_SEND_EVT;
|
||||
p_buf->offset = p_data - (UINT8 *)(p_buf + 1);
|
||||
p_buf->len = data_len;
|
||||
bta_sys_sendmsg(p_buf);
|
||||
}
|
||||
|
||||
#endif /* #if (BTM_SCO_HCI_INCLUDED == TRUE ) */
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function BTA_HfClientGetCbDataSize
|
||||
**
|
||||
** Description Get callback data size of specific event
|
||||
**
|
||||
**
|
||||
** Returns void
|
||||
**
|
||||
*******************************************************************************/
|
||||
int BTA_HfClientGetCbDataSize(tBTA_HF_CLIENT_EVT event)
|
||||
{
|
||||
return bta_hf_client_cb_data_size[event];
|
||||
|
@@ -24,6 +24,7 @@
|
||||
#include "bta/bta_sys.h"
|
||||
#include "bta/bta_hf_client_api.h"
|
||||
#include "bta_hf_client_int.h"
|
||||
#include "osi/allocator.h"
|
||||
|
||||
#if BT_HF_CLIENT_BQB_INCLUDED
|
||||
static BOOLEAN s_bta_hf_client_bqb_clip_flag = TRUE;
|
||||
@@ -79,6 +80,8 @@ enum {
|
||||
BTA_HF_CLIENT_SEND_AT_CMD,
|
||||
#if (BTM_SCO_HCI_INCLUDED == TRUE)
|
||||
BTA_HF_CLIENT_CI_SCO_DATA,
|
||||
BTA_HF_CLIENT_SCO_DATA_SEND,
|
||||
BTA_HF_CLIENT_SCO_DATA_FREE,
|
||||
BTA_HF_CLIENT_PKT_STAT_NUMS,
|
||||
#endif
|
||||
BTA_HF_CLIENT_NUM_ACTIONS,
|
||||
@@ -118,6 +121,8 @@ const tBTA_HF_CLIENT_ACTION bta_hf_client_action[] = {
|
||||
/* 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,
|
||||
/* BTA_HF_CLIENT_SCO_DATA_SEND */ bta_hf_client_sco_data_send,
|
||||
/* BTA_HF_CLIENT_SCO_DATA_FREE */ bta_hf_client_sco_data_free,
|
||||
/* BTA_HF_CLIENT_PKT_STAT_NUMS */ bta_hf_client_pkt_stat_nums,
|
||||
#endif /* (BTM_SCO_HCI_INCLUDED == TRUE ) */
|
||||
};
|
||||
@@ -149,6 +154,7 @@ const UINT8 bta_hf_client_st_init[][BTA_HF_CLIENT_NUM_COLS] = {
|
||||
/* 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},
|
||||
/* SCO_DATA_SEND_EVT */ {BTA_HF_CLIENT_SCO_DATA_FREE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_INIT_ST},
|
||||
/* PKT_STAT_NUMS_GET_EVT */ {BTA_HF_CLIENT_PKT_STAT_NUMS, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_INIT_ST},
|
||||
#endif /* (BTM_SCO_HCI_INCLUDED == TRUE ) */
|
||||
};
|
||||
@@ -175,6 +181,7 @@ const UINT8 bta_hf_client_st_opening[][BTA_HF_CLIENT_NUM_COLS] = {
|
||||
/* 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},
|
||||
/* SCO_DATA_SEND_EVT */ {BTA_HF_CLIENT_SCO_DATA_FREE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_OPENING_ST},
|
||||
/* PKT_STAT_NUMS_GET_EVT */ {BTA_HF_CLIENT_PKT_STAT_NUMS, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_OPENING_ST},
|
||||
#endif /* (BTM_SCO_HCI_INCLUDED == TRUE ) */
|
||||
};
|
||||
@@ -201,6 +208,7 @@ const UINT8 bta_hf_client_st_open[][BTA_HF_CLIENT_NUM_COLS] = {
|
||||
/* 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},
|
||||
/* SCO_DATA_SEND_EVT */ {BTA_HF_CLIENT_SCO_DATA_SEND, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_OPEN_ST},
|
||||
/* PKT_STAT_NUMS_GET_EVT */ {BTA_HF_CLIENT_PKT_STAT_NUMS, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_OPEN_ST},
|
||||
#endif /* (BTM_SCO_HCI_INCLUDED == TRUE ) */
|
||||
};
|
||||
@@ -227,6 +235,7 @@ const UINT8 bta_hf_client_st_closing[][BTA_HF_CLIENT_NUM_COLS] = {
|
||||
/* 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},
|
||||
/* SCO_DATA_SEND_EVT */ {BTA_HF_CLIENT_SCO_DATA_FREE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_CLOSING_ST},
|
||||
/* PKT_STAT_NUMS_GET_EVT */ {BTA_HF_CLIENT_PKT_STAT_NUMS, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_CLOSING_ST},
|
||||
#endif /* (BTM_SCO_HCI_INCLUDED == TRUE ) */
|
||||
};
|
||||
@@ -284,6 +293,7 @@ void bta_hf_client_scb_init(void)
|
||||
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;
|
||||
bta_hf_client_cb.scb.p_sco_data = NULL;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
@@ -299,6 +309,10 @@ void bta_hf_client_scb_init(void)
|
||||
void bta_hf_client_scb_disable(void)
|
||||
{
|
||||
APPL_TRACE_DEBUG("%s", __FUNCTION__);
|
||||
if (bta_hf_client_cb.scb.p_sco_data != NULL) {
|
||||
osi_free(bta_hf_client_cb.scb.p_sco_data);
|
||||
bta_hf_client_cb.scb.p_sco_data = NULL;
|
||||
}
|
||||
|
||||
bta_hf_client_scb_init();
|
||||
|
||||
@@ -470,6 +484,7 @@ static void bta_hf_client_api_disable(tBTA_HF_CLIENT_DATA *p_data)
|
||||
*******************************************************************************/
|
||||
BOOLEAN bta_hf_client_hdl_event(BT_HDR *p_msg)
|
||||
{
|
||||
BOOLEAN free_msg = TRUE;
|
||||
#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
|
||||
@@ -484,12 +499,16 @@ BOOLEAN bta_hf_client_hdl_event(BT_HDR *p_msg)
|
||||
case BTA_HF_CLIENT_API_DISABLE_EVT:
|
||||
bta_hf_client_api_disable((tBTA_HF_CLIENT_DATA *) p_msg);
|
||||
break;
|
||||
|
||||
#if (BTM_SCO_HCI_INCLUDED == TRUE) && (BTA_HFP_EXT_CODEC == TRUE)
|
||||
case BTA_HF_CLIENT_SCO_DATA_SEND_EVT:
|
||||
free_msg = false;
|
||||
/* fall through */
|
||||
#endif
|
||||
default:
|
||||
bta_hf_client_sm_execute(p_msg->event, (tBTA_HF_CLIENT_DATA *) p_msg);
|
||||
break;
|
||||
}
|
||||
return TRUE;
|
||||
return free_msg;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
|
@@ -177,6 +177,36 @@ static BOOLEAN bta_hf_client_sco_remove(BOOLEAN only_active)
|
||||
return removed_started;
|
||||
}
|
||||
|
||||
#if (BTM_SCO_HCI_INCLUDED == TRUE) && (BTA_HFP_EXT_CODEC == TRUE)
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function bta_hf_client_sco_get_frame_size
|
||||
**
|
||||
** Description Get SCO frame size
|
||||
**
|
||||
** Returns frame size
|
||||
**
|
||||
*******************************************************************************/
|
||||
static UINT16 bta_hf_client_sco_get_frame_size(void)
|
||||
{
|
||||
UINT16 frame_size = 0;
|
||||
switch (bta_hf_client_cb.scb.air_mode)
|
||||
{
|
||||
case BTM_SCO_AIR_MODE_CVSD:
|
||||
frame_size = bta_hf_client_cb.scb.out_pkt_len;
|
||||
break;
|
||||
case BTM_SCO_AIR_MODE_TRANSPNT:
|
||||
frame_size = BTA_HF_CLIENT_MSBC_FRAME_SIZE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return frame_size;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function bta_hf_client_cback_sco
|
||||
@@ -189,13 +219,17 @@ static BOOLEAN bta_hf_client_sco_remove(BOOLEAN only_active)
|
||||
*******************************************************************************/
|
||||
void bta_hf_client_cback_sco(UINT8 event)
|
||||
{
|
||||
tBTA_HF_CLIENT_HDR evt;
|
||||
|
||||
memset(&evt, 0, sizeof(evt));
|
||||
evt.sync_conn_handle = BTM_ReadScoHandle(bta_hf_client_cb.scb.sco_idx);
|
||||
tBTA_HF_CLIENT_AUDIO_STAT audio_stat;
|
||||
|
||||
memset(&audio_stat, 0, sizeof(audio_stat));
|
||||
audio_stat.hdr.sync_conn_handle = BTM_ReadScoHandle(bta_hf_client_cb.scb.sco_idx);
|
||||
#if (BTM_SCO_HCI_INCLUDED == TRUE) && (BTA_HFP_EXT_CODEC == TRUE)
|
||||
if (event != BTA_HF_CLIENT_AUDIO_CLOSE_EVT) {
|
||||
audio_stat.preferred_frame_size = bta_hf_client_sco_get_frame_size();
|
||||
}
|
||||
#endif
|
||||
/* call app cback */
|
||||
(*bta_hf_client_cb.p_cback)(event, (tBTA_HF_CLIENT_HDR *) &evt);
|
||||
(*bta_hf_client_cb.p_cback)(event, &audio_stat);
|
||||
}
|
||||
|
||||
#if (BTM_SCO_HCI_INCLUDED == TRUE )
|
||||
@@ -217,7 +251,6 @@ static void bta_hf_client_sco_read_cback (UINT16 sco_idx, BT_HDR *p_data, tBTM_S
|
||||
}
|
||||
|
||||
bta_hf_client_sco_co_in_data (p_data, status);
|
||||
osi_free(p_data);
|
||||
}
|
||||
#endif /* BTM_SCO_HCI_INCLUDED */
|
||||
|
||||
@@ -307,7 +340,7 @@ void bta_hf_client_pkt_stat_nums(tBTA_HF_CLIENT_DATA *p_data)
|
||||
**
|
||||
** Function bta_hf_client_ci_sco_data
|
||||
**
|
||||
** Description Process the SCO data ready callin event
|
||||
** Description Process the SCO data ready call in event
|
||||
**
|
||||
**
|
||||
** Returns void
|
||||
@@ -318,6 +351,281 @@ 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);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function bta_hf_client_write_sco_data
|
||||
**
|
||||
** Description Write two SCO data buffers to specified instance
|
||||
**
|
||||
**
|
||||
** Returns void
|
||||
**
|
||||
*******************************************************************************/
|
||||
static void bta_hf_client_write_sco_data(BT_HDR *p_buf1, BT_HDR *p_buf2)
|
||||
{
|
||||
BTM_WriteScoData(bta_hf_client_cb.scb.sco_idx, p_buf1);
|
||||
if (p_buf2 != NULL) {
|
||||
BTM_WriteScoData(bta_hf_client_cb.scb.sco_idx, p_buf2);
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function bta_hf_client_sco_data_send_cvsd
|
||||
**
|
||||
** Description Process SCO data of CVSD air mode
|
||||
**
|
||||
**
|
||||
** Returns void
|
||||
**
|
||||
*******************************************************************************/
|
||||
static void bta_hf_client_sco_data_send_cvsd(BT_HDR *p_buf, UINT8 out_pkt_len)
|
||||
{
|
||||
if (bta_hf_client_cb.scb.p_sco_data != NULL) {
|
||||
/* the remaining data of last sending operation */
|
||||
BT_HDR *p_buf_last = bta_hf_client_cb.scb.p_sco_data;
|
||||
/* remaining data len should small than out_pkt_len */
|
||||
assert(p_buf_last->len < out_pkt_len);
|
||||
BT_HDR *p_buf2 = osi_calloc(sizeof(BT_HDR) + BTA_HF_CLIENT_BUFF_OFFSET_MIN + out_pkt_len);
|
||||
if (p_buf2 == NULL) {
|
||||
osi_free(p_buf);
|
||||
osi_free(p_buf_last);
|
||||
bta_hf_client_cb.scb.p_sco_data = NULL;
|
||||
APPL_TRACE_WARNING("%s, no memory", __FUNCTION__);
|
||||
return;
|
||||
}
|
||||
p_buf2->offset = BTA_HF_CLIENT_BUFF_OFFSET_MIN;
|
||||
|
||||
UINT8 *p_data = (UINT8 *)(p_buf2 + 1) + p_buf2->offset;
|
||||
memcpy(p_data, (UINT8 *)(p_buf_last + 1) + p_buf_last->offset, p_buf_last->len);
|
||||
|
||||
if (p_buf->len + p_buf_last->len < out_pkt_len) {
|
||||
memcpy(p_data + p_buf_last->len, (UINT8 *)(p_buf + 1) + p_buf->offset, p_buf->len);
|
||||
p_buf2->len = p_buf->len + p_buf_last->len;
|
||||
osi_free(p_buf);
|
||||
osi_free(p_buf_last);
|
||||
bta_hf_client_cb.scb.p_sco_data = p_buf2;
|
||||
}
|
||||
else {
|
||||
UINT16 copy_len = out_pkt_len - p_buf_last->len;
|
||||
memcpy(p_data + p_buf_last->len, (UINT8 *)(p_buf + 1) + p_buf->offset, copy_len);
|
||||
p_buf2->len = out_pkt_len;
|
||||
p_buf->offset += copy_len;
|
||||
p_buf->len -= copy_len;
|
||||
osi_free(p_buf_last);
|
||||
bta_hf_client_cb.scb.p_sco_data = NULL;
|
||||
bta_hf_client_write_sco_data(p_buf2, NULL);
|
||||
if (p_buf->len == 0) {
|
||||
osi_free(p_buf);
|
||||
}
|
||||
else {
|
||||
/* Recursive call, this will only called once */
|
||||
bta_hf_client_sco_data_send_cvsd(p_buf, out_pkt_len);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (p_buf->len < out_pkt_len) {
|
||||
bta_hf_client_cb.scb.p_sco_data = p_buf;
|
||||
}
|
||||
else {
|
||||
/* bta_hf_client_cb.scb.p_sco_data == NULL && p_buf->len >= out_pkt_len */
|
||||
while (1) {
|
||||
if (p_buf->len == out_pkt_len) {
|
||||
bta_hf_client_write_sco_data(p_buf, NULL);
|
||||
break;
|
||||
}
|
||||
else {
|
||||
BT_HDR *p_buf2 = osi_calloc(sizeof(BT_HDR) + BTA_HF_CLIENT_BUFF_OFFSET_MIN + out_pkt_len);
|
||||
if (p_buf2 == NULL) {
|
||||
osi_free(p_buf);
|
||||
APPL_TRACE_WARNING("%s, no memory", __FUNCTION__);
|
||||
return;
|
||||
}
|
||||
p_buf2->offset = BTA_HF_CLIENT_BUFF_OFFSET_MIN;
|
||||
UINT8 *p_data = (UINT8 *)(p_buf2 + 1) + p_buf2->offset;
|
||||
memcpy(p_data, (UINT8 *)(p_buf + 1) + p_buf->offset, out_pkt_len);
|
||||
p_buf2->len = out_pkt_len;
|
||||
p_buf->offset += out_pkt_len;
|
||||
p_buf->len -= out_pkt_len;
|
||||
bta_hf_client_write_sco_data(p_buf2, NULL);
|
||||
}
|
||||
if (p_buf->len < out_pkt_len) {
|
||||
bta_hf_client_cb.scb.p_sco_data = p_buf;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function bta_hf_client_sco_data_send_msbc
|
||||
**
|
||||
** Description Process SCO data of mSBC air mode
|
||||
**
|
||||
**
|
||||
** Returns void
|
||||
**
|
||||
*******************************************************************************/
|
||||
static void bta_hf_client_sco_data_send_msbc(BT_HDR *p_buf, UINT8 out_pkt_len)
|
||||
{
|
||||
if (p_buf->len == BTA_HF_CLIENT_MSBC_FRAME_SIZE && p_buf->offset >= BTA_HF_CLIENT_BUFF_OFFSET_MIN + BTA_HF_CLIENT_H2_HEADER_LEN) {
|
||||
/* add H2 header */
|
||||
p_buf->offset -= BTA_HF_CLIENT_H2_HEADER_LEN;
|
||||
UINT8 *p_data = (UINT8 *)(p_buf + 1) + p_buf->offset;
|
||||
bta_hf_client_h2_header((UINT16 *)p_data);
|
||||
/* add header len, add addition one bytes, the len is BTA_HF_CLIENT_SCO_OUT_PKT_LEN_2EV3 now */
|
||||
p_buf->len += BTA_HF_CLIENT_H2_HEADER_LEN + 1;
|
||||
|
||||
if (out_pkt_len == BTA_HF_CLIENT_SCO_OUT_PKT_LEN_2EV3) {
|
||||
/* mSBC frame can be send directly */
|
||||
bta_hf_client_write_sco_data(p_buf, NULL);
|
||||
}
|
||||
else if (out_pkt_len == BTA_HF_CLIENT_SCO_OUT_PKT_LEN_EV3) {
|
||||
/* need to split into 2 sco packages for sending */
|
||||
BT_HDR *p_buf2 = osi_calloc(sizeof(BT_HDR) + BTA_HF_CLIENT_BUFF_OFFSET_MIN + BTA_HF_CLIENT_SCO_OUT_PKT_LEN_EV3);
|
||||
if (p_buf2 == NULL) {
|
||||
/* free the first buff too */
|
||||
osi_free(p_buf);
|
||||
APPL_TRACE_WARNING("%s, no memory", __FUNCTION__);
|
||||
return;
|
||||
}
|
||||
p_buf2->offset = BTA_HF_CLIENT_BUFF_OFFSET_MIN;
|
||||
p_buf2->len = BTA_HF_CLIENT_SCO_OUT_PKT_LEN_EV3;
|
||||
UINT8 *p_data2 = (UINT8 *)(p_buf2 + 1) + p_buf2->offset;
|
||||
memcpy(p_data2, p_data + BTA_HF_CLIENT_SCO_OUT_PKT_LEN_EV3, BTA_HF_CLIENT_SCO_OUT_PKT_LEN_EV3);
|
||||
/* update the first packet len */
|
||||
p_buf->len = BTA_HF_CLIENT_SCO_OUT_PKT_LEN_EV3;
|
||||
bta_hf_client_write_sco_data(p_buf, p_buf2);
|
||||
}
|
||||
else {
|
||||
osi_free(p_buf);
|
||||
APPL_TRACE_WARNING("%s, invalid out pkt len: %d", __FUNCTION__, out_pkt_len);
|
||||
}
|
||||
}
|
||||
else if (p_buf->len != 0 && p_buf->len % BTA_HF_CLIENT_MSBC_FRAME_SIZE == 0) {
|
||||
/* multiple mSBC frame in the buffer, or just one but offset is too small */
|
||||
UINT8 *p_data = (UINT8 *)(p_buf + 1) + p_buf->offset;
|
||||
UINT16 total_len = p_buf->len;
|
||||
if (out_pkt_len == BTA_HF_CLIENT_SCO_OUT_PKT_LEN_2EV3) {
|
||||
while (total_len != 0) {
|
||||
BT_HDR *p_buf2 = osi_calloc(sizeof(BT_HDR) + BTA_HF_CLIENT_BUFF_OFFSET_MIN + BTA_HF_CLIENT_SCO_OUT_PKT_LEN_2EV3);
|
||||
if (p_buf2 == NULL) {
|
||||
APPL_TRACE_WARNING("%s, no memory", __FUNCTION__);
|
||||
break;
|
||||
}
|
||||
p_buf2->offset = BTA_HF_CLIENT_BUFF_OFFSET_MIN;
|
||||
p_buf2->len = BTA_HF_CLIENT_SCO_OUT_PKT_LEN_2EV3;
|
||||
UINT8 *p_data2 = (UINT8 *)(p_buf2 + 1) + p_buf2->offset;
|
||||
bta_hf_client_h2_header((UINT16 *)p_data2);
|
||||
p_data2 += BTA_HF_CLIENT_H2_HEADER_LEN;
|
||||
memcpy(p_data2, p_data, BTA_HF_CLIENT_MSBC_FRAME_SIZE);
|
||||
p_data += BTA_HF_CLIENT_MSBC_FRAME_SIZE;
|
||||
total_len -= BTA_HF_CLIENT_MSBC_FRAME_SIZE;
|
||||
bta_hf_client_write_sco_data(p_buf2, NULL);
|
||||
}
|
||||
}
|
||||
else if (out_pkt_len == BTA_HF_CLIENT_SCO_OUT_PKT_LEN_EV3) {
|
||||
while (total_len != 0) {
|
||||
BT_HDR *p_buf2 = osi_calloc(sizeof(BT_HDR) + BTA_HF_CLIENT_BUFF_OFFSET_MIN + BTA_HF_CLIENT_SCO_OUT_PKT_LEN_EV3);
|
||||
if (p_buf2 == NULL) {
|
||||
APPL_TRACE_WARNING("%s, no memory", __FUNCTION__);
|
||||
break;
|
||||
}
|
||||
BT_HDR *p_buf3 = osi_calloc(sizeof(BT_HDR) + BTA_HF_CLIENT_BUFF_OFFSET_MIN + BTA_HF_CLIENT_SCO_OUT_PKT_LEN_EV3);
|
||||
if (p_buf3 == NULL) {
|
||||
/* free the first buff too */
|
||||
osi_free(p_buf2);
|
||||
APPL_TRACE_WARNING("%s, no memory", __FUNCTION__);
|
||||
break;
|
||||
}
|
||||
|
||||
/* build first packet, include H2 header */
|
||||
p_buf2->offset = BTA_HF_CLIENT_BUFF_OFFSET_MIN;
|
||||
p_buf2->len = BTA_HF_CLIENT_SCO_OUT_PKT_LEN_EV3;
|
||||
UINT8 *p_data2 = (UINT8 *)(p_buf2 + 1) + p_buf2->offset;
|
||||
bta_hf_client_h2_header((UINT16 *)p_data2);
|
||||
p_data2 += BTA_HF_CLIENT_H2_HEADER_LEN;
|
||||
memcpy(p_data2, p_data, BTA_HF_CLIENT_SCO_OUT_PKT_LEN_EV3 - BTA_HF_CLIENT_H2_HEADER_LEN);
|
||||
p_data += BTA_HF_CLIENT_SCO_OUT_PKT_LEN_EV3 - BTA_HF_CLIENT_H2_HEADER_LEN;
|
||||
total_len -= BTA_HF_CLIENT_SCO_OUT_PKT_LEN_EV3 - BTA_HF_CLIENT_H2_HEADER_LEN;
|
||||
|
||||
/* build second packet, not include header */
|
||||
p_buf3->offset = BTA_HF_CLIENT_BUFF_OFFSET_MIN;
|
||||
p_buf3->len = BTA_HF_CLIENT_SCO_OUT_PKT_LEN_EV3;
|
||||
UINT8 *p_data3 = (UINT8 *)(p_buf3 + 1) + p_buf3->offset;
|
||||
memcpy(p_data3, p_data, BTA_HF_CLIENT_MSBC_FRAME_SIZE - BTA_HF_CLIENT_H2_HEADER_LEN - BTA_HF_CLIENT_SCO_OUT_PKT_LEN_EV3);
|
||||
p_data += BTA_HF_CLIENT_MSBC_FRAME_SIZE - BTA_HF_CLIENT_H2_HEADER_LEN - BTA_HF_CLIENT_SCO_OUT_PKT_LEN_EV3;
|
||||
total_len -= BTA_HF_CLIENT_MSBC_FRAME_SIZE - BTA_HF_CLIENT_H2_HEADER_LEN - BTA_HF_CLIENT_SCO_OUT_PKT_LEN_EV3;
|
||||
bta_hf_client_write_sco_data(p_buf2, p_buf3);
|
||||
}
|
||||
}
|
||||
else {
|
||||
APPL_TRACE_WARNING("%s, invalid out pkt len: %d", __FUNCTION__, out_pkt_len);
|
||||
}
|
||||
osi_free(p_buf);
|
||||
}
|
||||
else {
|
||||
APPL_TRACE_WARNING("%s, unaccepted data len: %d", __FUNCTION__, p_buf->len);
|
||||
osi_free(p_buf);
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function bta_hf_client_sco_data_send
|
||||
**
|
||||
** Description Route SCO data to specific processing function based on air mode
|
||||
**
|
||||
**
|
||||
** Returns void
|
||||
**
|
||||
*******************************************************************************/
|
||||
void bta_hf_client_sco_data_send(tBTA_HF_CLIENT_DATA *p_data)
|
||||
{
|
||||
BT_HDR *p_buf = (BT_HDR *) p_data;
|
||||
|
||||
if (bta_hf_client_cb.scb.sco_state != BTA_HF_CLIENT_SCO_OPEN_ST) {
|
||||
osi_free(p_data);
|
||||
APPL_TRACE_WARNING("%s: SCO not open", __FUNCTION__);
|
||||
return;
|
||||
}
|
||||
|
||||
UINT8 out_pkt_len = bta_hf_client_cb.scb.out_pkt_len;
|
||||
UINT8 air_mode = bta_hf_client_cb.scb.air_mode;
|
||||
|
||||
switch (air_mode)
|
||||
{
|
||||
case BTM_SCO_AIR_MODE_CVSD:
|
||||
bta_hf_client_sco_data_send_cvsd(p_buf, out_pkt_len);
|
||||
break;
|
||||
case BTM_SCO_AIR_MODE_TRANSPNT:
|
||||
bta_hf_client_sco_data_send_msbc(p_buf, out_pkt_len);
|
||||
break;
|
||||
default:
|
||||
osi_free(p_buf);
|
||||
APPL_TRACE_WARNING("%s: unsupported air mode: %d", __FUNCTION__, air_mode);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function bta_hf_client_sco_data_free
|
||||
**
|
||||
** Description Free SCO data buffer
|
||||
**
|
||||
**
|
||||
** Returns void
|
||||
**
|
||||
*******************************************************************************/
|
||||
void bta_hf_client_sco_data_free(tBTA_HF_CLIENT_DATA *p_data)
|
||||
{
|
||||
/* just free the sco data buffer */
|
||||
osi_free(p_data);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*******************************************************************************
|
||||
@@ -539,12 +847,9 @@ 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;
|
||||
#if (BTM_SCO_HCI_INCLUDED == TRUE ) && (BTA_HFP_EXT_CODEC == FALSE)
|
||||
BT_HDR *p_buf;
|
||||
#endif
|
||||
|
||||
#if (BTM_SCO_HCI_INCLUDED == TRUE )
|
||||
tBTA_HF_CLIENT_SCB *p_scb = &bta_hf_client_cb.scb;
|
||||
if (event == BTA_HF_CLIENT_SCO_CI_DATA_E) {
|
||||
UINT16 pkt_offset = 1 + HCI_SCO_PREAMBLE_SIZE;
|
||||
UINT16 len_to_send = 0;
|
||||
@@ -890,6 +1195,11 @@ void bta_hf_client_sco_conn_close(tBTA_HF_CLIENT_DATA *p_data)
|
||||
|
||||
bta_sys_sco_unuse(BTA_ID_HS, 1, bta_hf_client_cb.scb.peer_addr);
|
||||
|
||||
if (bta_hf_client_cb.scb.p_sco_data != NULL) {
|
||||
osi_free(bta_hf_client_cb.scb.p_sco_data);
|
||||
bta_hf_client_cb.scb.p_sco_data = NULL;
|
||||
}
|
||||
|
||||
/* call app callback */
|
||||
bta_hf_client_cback_sco(BTA_HF_CLIENT_AUDIO_CLOSE_EVT);
|
||||
|
||||
|
@@ -44,6 +44,19 @@
|
||||
#define BTA_HF_CLIENT_COLLISION_TIMER 2411
|
||||
#endif
|
||||
|
||||
#if (BTM_SCO_HCI_INCLUDED == TRUE )
|
||||
/* 1 (offset can not be 0) + HCI_SCO_PREAMBLE */
|
||||
#define BTA_HF_CLIENT_BUFF_OFFSET_MIN (1 + HCI_SCO_PREAMBLE_SIZE)
|
||||
/* mSBC H2 header length */
|
||||
#define BTA_HF_CLIENT_H2_HEADER_LEN 2
|
||||
/* mSBC frame size not include H1/H2 header */
|
||||
#define BTA_HF_CLIENT_MSBC_FRAME_SIZE 57
|
||||
/* max user data len of sco packet type EV3 */
|
||||
#define BTA_HF_CLIENT_SCO_OUT_PKT_LEN_EV3 30
|
||||
/* max user data len of sco packet type 2-EV3 */
|
||||
#define BTA_HF_CLIENT_SCO_OUT_PKT_LEN_2EV3 60
|
||||
#endif
|
||||
|
||||
enum {
|
||||
/* these events are handled by the state machine */
|
||||
BTA_HF_CLIENT_API_REGISTER_EVT = BTA_SYS_EVT_START(BTA_ID_HS),
|
||||
@@ -65,6 +78,7 @@ enum {
|
||||
BTA_HF_CLIENT_SEND_AT_CMD_EVT,
|
||||
#if (BTM_SCO_HCI_INCLUDED == TRUE )
|
||||
BTA_HF_CLIENT_CI_SCO_DATA_EVT,
|
||||
BTA_HF_CLIENT_SCO_DATA_SEND_EVT,
|
||||
BTA_HF_CLIENT_PKT_NUMS_GET_EVT,
|
||||
#endif /* (BTM_SCO_HCI_INCLUDED == TRUE ) */
|
||||
BTA_HF_CLIENT_MAX_EVT,
|
||||
@@ -138,7 +152,6 @@ typedef union {
|
||||
tBTA_HF_CLIENT_RFC rfc;
|
||||
tBTA_HF_CLIENT_DATA_VAL val;
|
||||
tBTA_HF_CLIENT_PKT_STAT_GET pkt_stat;
|
||||
|
||||
} tBTA_HF_CLIENT_DATA;
|
||||
|
||||
/* type for each service control block */
|
||||
@@ -158,6 +171,7 @@ typedef struct {
|
||||
UINT16 sco_idx; /* SCO handle */
|
||||
UINT8 sco_state; /* SCO state variable */
|
||||
BOOLEAN sco_close_rfc; /* TRUE if also close RFCOMM after SCO */
|
||||
BT_HDR *p_sco_data; /* remaining SCO data of last sending operation */
|
||||
BOOLEAN retry_with_sco_only;
|
||||
BOOLEAN deregister; /* TRUE if service shutting down */
|
||||
BOOLEAN svc_conn; /* set to TRUE when service level connection is up */
|
||||
@@ -312,5 +326,8 @@ 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_pkt_stat_nums(tBTA_HF_CLIENT_DATA *p_data);
|
||||
extern void bta_hf_client_ci_sco_data(tBTA_HF_CLIENT_DATA *p_data);
|
||||
extern void bta_hf_client_h2_header(UINT16 *p_buf);
|
||||
extern void bta_hf_client_sco_data_send(tBTA_HF_CLIENT_DATA *p_data);
|
||||
extern void bta_hf_client_sco_data_free(tBTA_HF_CLIENT_DATA *p_data);
|
||||
#endif /* (BTM_SCO_HCI_INCLUDED == TRUE ) */
|
||||
#endif /* #if (BTA_HF_INCLUDED == TRUE) */
|
||||
|
@@ -112,7 +112,7 @@ typedef UINT8 tBTA_AG_STATUS;
|
||||
/* It is safe to use the same value as BTA_AG_HANDLE_ALL
|
||||
* HANDLE_ALL is used for delivering indication
|
||||
* SCO_NO_CHANGE is used for changing sco behavior
|
||||
* They donot interfere with each other
|
||||
* They do not interfere with each other
|
||||
*/
|
||||
#define BTA_AG_HANDLE_SCO_NO_CHANGE 0xFFFF
|
||||
|
||||
@@ -363,6 +363,13 @@ typedef struct
|
||||
tBTA_AG_CHLD_FEAT chld_feat;
|
||||
} tBTA_AG_CONN;
|
||||
|
||||
/* data associated with BTA_AG_AUDIO_OPEN_EVT, BTA_AG_AUDIO_CLOSE_EVT or BTA_AG_AUDIO_MSBC_OPEN_EVT */
|
||||
typedef struct
|
||||
{
|
||||
tBTA_AG_HDR hdr;
|
||||
UINT16 preferred_frame_size;
|
||||
} tBTA_AG_AUDIO_STAT;
|
||||
|
||||
/* data associated with AT command event */
|
||||
typedef struct
|
||||
{
|
||||
@@ -427,6 +434,7 @@ typedef union
|
||||
tBTA_AG_OPEN open;
|
||||
tBTA_AG_CLOSE close;
|
||||
tBTA_AG_CONN conn;
|
||||
tBTA_AG_AUDIO_STAT audio_stat;
|
||||
tBTA_AG_IND ind;
|
||||
tBTA_AG_VAL val;
|
||||
//add
|
||||
@@ -619,6 +627,45 @@ void BTA_AgPktStatsNumsGet(UINT16 handle, UINT16 sync_conn_handle);
|
||||
**
|
||||
*******************************************************************************/
|
||||
void BTA_AgCiData(UINT16 handle);
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function BTA_AgAudioBuffAlloc
|
||||
**
|
||||
** Description Allocate an audio buffer with specific size, reserve enough
|
||||
** space and offset for lower layer to send the buffer directly.
|
||||
**
|
||||
**
|
||||
** Returns void
|
||||
**
|
||||
*******************************************************************************/
|
||||
void BTA_AgAudioBuffAlloc(UINT16 size, UINT8 **pp_buff, UINT8 **pp_data);
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function BTA_AgAudioBuffFree
|
||||
**
|
||||
** Description Free an audio buffer.
|
||||
**
|
||||
**
|
||||
** Returns void
|
||||
**
|
||||
*******************************************************************************/
|
||||
void BTA_AgAudioBuffFree(UINT8 *p_buf);
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function BTA_AgAudioDataSend
|
||||
**
|
||||
** Description Send audio data to lower layer, whether success or not, buffer
|
||||
** is consumed.
|
||||
**
|
||||
**
|
||||
** Returns void
|
||||
**
|
||||
*******************************************************************************/
|
||||
void BTA_AgAudioDataSend(UINT16 handle, UINT8 *p_buff_start, UINT8 *p_data, UINT16 data_len);
|
||||
|
||||
#endif /*#if (BTM_SCO_HCI_INCLUDED == TRUE ) */
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@@ -256,18 +256,19 @@ typedef UINT8 tBTA_AV_GET_TYPE;
|
||||
#define BTA_AV_META_MSG_EVT 17 /* metadata messages */
|
||||
#define BTA_AV_REJECT_EVT 18 /* incoming connection rejected */
|
||||
#define BTA_AV_RC_FEAT_EVT 19 /* remote control channel peer supported features update */
|
||||
#define BTA_AV_MEDIA_SINK_CFG_EVT 20 /* command to configure codec */
|
||||
#define BTA_AV_MEDIA_CFG_EVT 20 /* command to configure codec */
|
||||
#define BTA_AV_MEDIA_DATA_EVT 21 /* sending data to Media Task */
|
||||
#define BTA_AV_SET_DELAY_VALUE_EVT 22 /* set delay reporting value */
|
||||
#define BTA_AV_GET_DELAY_VALUE_EVT 23 /* get delay reporting value */
|
||||
#define BTA_AV_SNK_PSC_CFG_EVT 24 /* Protocol service capabilities. */
|
||||
#define BTA_AV_SEP_REG_EVT 25 /* stream endpoint registered */
|
||||
|
||||
/* still keep Cover Art event here if Cover Art feature not enabled */
|
||||
#define BTA_AV_CA_STATUS_EVT 25 /* Cover Art Client status event */
|
||||
#define BTA_AV_CA_DATA_EVT 26 /* Cover Art response body data */
|
||||
#define BTA_AV_CA_STATUS_EVT 26 /* Cover Art Client status event */
|
||||
#define BTA_AV_CA_DATA_EVT 27 /* Cover Art response body data */
|
||||
|
||||
/* Max BTA event */
|
||||
#define BTA_AV_MAX_EVT 27
|
||||
#define BTA_AV_MAX_EVT 28
|
||||
|
||||
|
||||
/* function types for call-out functions */
|
||||
@@ -341,6 +342,12 @@ typedef struct {
|
||||
tBTA_AVRC_CO_FUNCTS *p_bta_avrc_cos;
|
||||
} tBTA_AV_REGISTER;
|
||||
|
||||
/* Event associated with BTA_AV_SEP_REG_EVT */
|
||||
typedef struct {
|
||||
UINT8 seid;
|
||||
tBTA_AV_STATUS reg_state;
|
||||
} tBTA_AV_SEP_REG;
|
||||
|
||||
/* data associated with BTA_AV_OPEN_EVT */
|
||||
#define BTA_AV_EDR_2MBPS 0x01
|
||||
#define BTA_AV_EDR_3MBPS 0x02
|
||||
@@ -354,6 +361,7 @@ typedef struct {
|
||||
BOOLEAN starting;
|
||||
tBTA_AV_EDR edr; /* 0, if peer device does not support EDR */
|
||||
UINT8 sep; /* sep type of peer device */
|
||||
UINT16 mtu;
|
||||
} tBTA_AV_OPEN;
|
||||
|
||||
/* data associated with BTA_AV_CLOSE_EVT */
|
||||
@@ -519,6 +527,7 @@ typedef union {
|
||||
tBTA_AV_CHNL chnl;
|
||||
tBTA_AV_ENABLE enable;
|
||||
tBTA_AV_REGISTER registr;
|
||||
tBTA_AV_SEP_REG sep_reg;
|
||||
tBTA_AV_OPEN open;
|
||||
tBTA_AV_CLOSE close;
|
||||
tBTA_AV_START start;
|
||||
@@ -657,6 +666,8 @@ void BTA_AvRegister(tBTA_AV_CHNL chnl, const char *p_service_name,
|
||||
tBTA_AV_CO_FUNCTS *bta_av_cos, tBTA_AVRC_CO_FUNCTS *bta_avrc_cos,
|
||||
UINT8 tsep);
|
||||
|
||||
void BTA_AvRegSEP(tBTA_AV_CHNL chnl, UINT8 idx, UINT8 tsep, tBTA_AV_CODEC codec_type, UINT8 *p_codec_info, tBTA_AV_DATA_CBACK *p_data_cback);
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function BTA_AvDeregister
|
||||
|
@@ -194,6 +194,18 @@ extern UINT8 bta_av_sbc_cfg_for_cap(UINT8 *p_peer, tA2D_SBC_CIE *p_cap, tA2D_SBC
|
||||
*******************************************************************************/
|
||||
extern UINT8 bta_av_sbc_cfg_in_cap(UINT8 *p_cfg, tA2D_SBC_CIE *p_cap);
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function bta_av_sbc_cfg_in_external_codec_cap
|
||||
**
|
||||
** Description This function checks whether an SBC codec configuration
|
||||
** is allowable for the given external codec capabilities.
|
||||
**
|
||||
** Returns 0 if ok, nonzero if error.
|
||||
**
|
||||
*******************************************************************************/
|
||||
extern UINT8 bta_av_sbc_cfg_in_external_codec_cap(UINT8 *p_cfg, UINT8 *p_cap);
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function bta_av_sbc_cfg_matches_cap
|
||||
|
@@ -188,6 +188,12 @@ typedef struct {
|
||||
tBTA_HF_CLIENT_CHLD_FEAT chld_feat;
|
||||
} tBTA_HF_CLIENT_CONN;
|
||||
|
||||
/* data associated with BTA_HF_CLIENT_AUDIO_XXX_EVT */
|
||||
typedef struct {
|
||||
tBTA_HF_CLIENT_HDR hdr;
|
||||
UINT16 preferred_frame_size;
|
||||
} tBTA_HF_CLIENT_AUDIO_STAT;
|
||||
|
||||
/* data associated with BTA_HF_CLIENT_IND_EVT event */
|
||||
typedef struct {
|
||||
tBTA_HF_CLIENT_HDR hdr;
|
||||
@@ -251,6 +257,7 @@ typedef union {
|
||||
tBTA_HF_CLIENT_REGISTER reg;
|
||||
tBTA_HF_CLIENT_OPEN open;
|
||||
tBTA_HF_CLIENT_CONN conn;
|
||||
tBTA_HF_CLIENT_AUDIO_STAT audio_stat;
|
||||
tBTA_HF_CLIENT_IND ind;
|
||||
tBTA_HF_CLIENT_VAL val;
|
||||
tBTA_HF_CLIENT_OPERATOR_NAME operator;
|
||||
@@ -406,9 +413,68 @@ void BTA_HfClientSendAT(UINT16 handle, tBTA_HF_CLIENT_AT_CMD_TYPE at, UINT32 val
|
||||
*******************************************************************************/
|
||||
void BTA_HfClientPktStatsNumsGet(UINT16 sync_conn_handle);
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function BTA_HfClientCiData
|
||||
**
|
||||
** Description Send SCO outgoing data ready event
|
||||
**
|
||||
**
|
||||
** Returns void
|
||||
**
|
||||
*******************************************************************************/
|
||||
void BTA_HfClientCiData(void);
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function BTA_HfClientAudioBuffAlloc
|
||||
**
|
||||
** Description Allocate an audio buffer with specific size, reserve enough
|
||||
** space and offset for lower layer to send the buffer directly.
|
||||
**
|
||||
**
|
||||
** Returns void
|
||||
**
|
||||
*******************************************************************************/
|
||||
void BTA_HfClientAudioBuffAlloc(UINT16 size, UINT8 **pp_buff, UINT8 **pp_data);
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function BTA_HfClientAudioBuffFree
|
||||
**
|
||||
** Description Free an audio buffer.
|
||||
**
|
||||
**
|
||||
** Returns void
|
||||
**
|
||||
*******************************************************************************/
|
||||
void BTA_HfClientAudioBuffFree(UINT8 *p_buf);
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function BTA_HfClientAudioDataSend
|
||||
**
|
||||
** Description Send audio data to lower layer, whether success or not, buffer
|
||||
** is consumed.
|
||||
**
|
||||
**
|
||||
** Returns void
|
||||
**
|
||||
*******************************************************************************/
|
||||
void BTA_HfClientAudioDataSend(UINT16 sync_conn_hdl, UINT8 *p_buff_start, UINT8 *p_data, UINT16 data_len);
|
||||
|
||||
#endif /*#if (BTM_SCO_HCI_INCLUDED == TRUE ) */
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function BTA_HfClientGetCbDataSize
|
||||
**
|
||||
** Description Get callback data size of specific event
|
||||
**
|
||||
**
|
||||
** Returns void
|
||||
**
|
||||
*******************************************************************************/
|
||||
int BTA_HfClientGetCbDataSize(tBTA_HF_CLIENT_EVT event);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@@ -122,7 +122,6 @@ static UINT8 bta_av_co_audio_sink_supports_config(UINT8 codec_type, const UINT8
|
||||
static BOOLEAN bta_av_co_audio_peer_src_supports_codec(tBTA_AV_CO_PEER *p_peer, UINT8 *p_src_index);
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function bta_av_co_cp_is_active
|
||||
@@ -245,18 +244,29 @@ BOOLEAN bta_av_co_audio_init(UINT8 *p_codec_type, UINT8 *p_codec_info, UINT8 *p_
|
||||
UINT16_TO_STREAM(p, BTA_AV_CP_SCMS_T_ID);
|
||||
} while (0);
|
||||
#endif
|
||||
#if (BTC_AV_EXT_CODEC == TRUE)
|
||||
/* for external codec, we get codec capability from BTA_AV */
|
||||
bta_av_co_cb.codec_caps.id = *p_codec_type;
|
||||
memcpy(bta_av_co_cb.codec_caps.info, p_codec_info, AVDT_CODEC_SIZE);
|
||||
bta_av_co_audio_codec_reset();
|
||||
#else
|
||||
/* Set up for SBC codec for SRC*/
|
||||
*p_codec_type = BTA_AV_CODEC_SBC;
|
||||
|
||||
/* This should not fail because we are using constants for parameters */
|
||||
A2D_BldSbcInfo(AVDT_MEDIA_AUDIO, (tA2D_SBC_CIE *) &bta_av_co_sbc_caps, p_codec_info);
|
||||
#endif
|
||||
return TRUE;
|
||||
} else if (tsep == AVDT_TSEP_SNK) {
|
||||
#if (BTC_AV_EXT_CODEC == TRUE)
|
||||
/* for external codec, we get codec capability from BTA_AV */
|
||||
bta_av_co_cb.codec_caps.id = *p_codec_type;
|
||||
memcpy(bta_av_co_cb.codec_caps.info, p_codec_info, AVDT_CODEC_SIZE);
|
||||
bta_av_co_audio_codec_reset();
|
||||
#else
|
||||
*p_codec_type = BTA_AV_CODEC_SBC;
|
||||
|
||||
/* This should not fail because we are using constants for parameters */
|
||||
A2D_BldSbcInfo(AVDT_MEDIA_AUDIO, (tA2D_SBC_CIE *) &bta_av_co_sbc_sink_caps, p_codec_info);
|
||||
|
||||
#endif
|
||||
/* Codec is valid */
|
||||
return TRUE;
|
||||
} else {
|
||||
@@ -387,7 +397,7 @@ void bta_av_build_src_cfg (UINT8 *p_pref_cfg, UINT8 *p_src_cap)
|
||||
/* now try to build a preferred one */
|
||||
/* parse configuration */
|
||||
if ((status = A2D_ParsSbcInfo(&src_cap, p_src_cap, TRUE)) != 0) {
|
||||
APPL_TRACE_DEBUG(" Cant parse src cap ret = %d", status);
|
||||
APPL_TRACE_DEBUG(" Can't parse src cap ret = %d", status);
|
||||
return ;
|
||||
}
|
||||
|
||||
@@ -1062,12 +1072,12 @@ static BOOLEAN bta_av_co_audio_codec_build_config(const UINT8 *p_codec_caps, UIN
|
||||
memcpy(p_codec_cfg, bta_av_co_cb.codec_cfg.info, BTA_AV_CO_SBC_MAX_BITPOOL_OFF + 1);
|
||||
|
||||
/* Update the bit pool boundaries with the codec capabilities */
|
||||
p_codec_cfg[BTA_AV_CO_SBC_MIN_BITPOOL_OFF] = p_codec_caps[BTA_AV_CO_SBC_MIN_BITPOOL_OFF];
|
||||
p_codec_cfg[BTA_AV_CO_SBC_MAX_BITPOOL_OFF] = p_codec_caps[BTA_AV_CO_SBC_MAX_BITPOOL_OFF];
|
||||
p_codec_cfg[BTA_AV_CO_SBC_MIN_BITPOOL_OFF] = BTA_AV_CO_MAX(p_codec_caps[BTA_AV_CO_SBC_MIN_BITPOOL_OFF], p_codec_cfg[BTA_AV_CO_SBC_MIN_BITPOOL_OFF]);
|
||||
p_codec_cfg[BTA_AV_CO_SBC_MAX_BITPOOL_OFF] = BTA_AV_CO_MIN(p_codec_caps[BTA_AV_CO_SBC_MAX_BITPOOL_OFF], p_codec_cfg[BTA_AV_CO_SBC_MAX_BITPOOL_OFF]);
|
||||
|
||||
APPL_TRACE_EVENT("bta_av_co_audio_codec_build_config : bitpool min %d, max %d",
|
||||
p_codec_cfg[BTA_AV_CO_SBC_MIN_BITPOOL_OFF],
|
||||
p_codec_caps[BTA_AV_CO_SBC_MAX_BITPOOL_OFF]);
|
||||
p_codec_cfg[BTA_AV_CO_SBC_MAX_BITPOOL_OFF]);
|
||||
break;
|
||||
default:
|
||||
APPL_TRACE_ERROR("bta_av_co_audio_codec_build_config: unsupported codec id %d", bta_av_co_cb.codec_cfg.id);
|
||||
@@ -1301,10 +1311,20 @@ static BOOLEAN bta_av_co_audio_peer_src_supports_codec(tBTA_AV_CO_PEER *p_peer,
|
||||
if (p_src_index) {
|
||||
*p_src_index = index;
|
||||
}
|
||||
if (0 == bta_av_sbc_cfg_matches_cap((UINT8 *)p_peer->srcs[index].codec_caps,
|
||||
(tA2D_SBC_CIE *)&bta_av_co_sbc_sink_caps)) {
|
||||
#if (BTC_AV_EXT_CODEC == TRUE)
|
||||
tA2D_SBC_CIE cap_cie;
|
||||
if (A2D_ParsSbcInfo(&cap_cie, bta_av_co_cb.codec_caps.info, TRUE) != A2D_SUCCESS) {
|
||||
return FALSE;
|
||||
}
|
||||
if (0 == bta_av_sbc_cfg_matches_cap((UINT8 *)p_peer->srcs[index].codec_caps, &cap_cie)) {
|
||||
return TRUE;
|
||||
}
|
||||
#else
|
||||
if (0 == bta_av_sbc_cfg_matches_cap((UINT8 *)p_peer->srcs[index].codec_caps,
|
||||
(tA2D_SBC_CIE *)&bta_av_co_sbc_sink_caps)) {
|
||||
return TRUE;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -1334,7 +1354,11 @@ static UINT8 bta_av_co_audio_sink_supports_config(UINT8 codec_type, const UINT8
|
||||
|
||||
switch (codec_type) {
|
||||
case BTA_AV_CODEC_SBC:
|
||||
#if (BTC_AV_EXT_CODEC == TRUE)
|
||||
status = bta_av_sbc_cfg_in_external_codec_cap((UINT8 *)p_codec_cfg, (UINT8 *)bta_av_co_cb.codec_caps.info);
|
||||
#else
|
||||
status = bta_av_sbc_cfg_in_cap((UINT8 *)p_codec_cfg, (tA2D_SBC_CIE *)&bta_av_co_sbc_sink_caps);
|
||||
#endif
|
||||
break;
|
||||
case BTA_AV_CODEC_M12:
|
||||
case BTA_AV_CODEC_M24:
|
||||
@@ -1365,7 +1389,11 @@ static UINT8 bta_av_co_audio_media_supports_config(UINT8 codec_type, const UINT8
|
||||
|
||||
switch (codec_type) {
|
||||
case BTA_AV_CODEC_SBC:
|
||||
#if (BTC_AV_EXT_CODEC == TRUE)
|
||||
status = bta_av_sbc_cfg_in_external_codec_cap((UINT8 *)p_codec_cfg, (UINT8 *)bta_av_co_cb.codec_caps.info);
|
||||
#else
|
||||
status = bta_av_sbc_cfg_in_cap((UINT8 *)p_codec_cfg, (tA2D_SBC_CIE *)&bta_av_co_sbc_caps);
|
||||
#endif
|
||||
break;
|
||||
case BTA_AV_CODEC_M12:
|
||||
case BTA_AV_CODEC_M24:
|
||||
@@ -1478,12 +1506,16 @@ void bta_av_co_audio_codec_reset(void)
|
||||
osi_mutex_global_lock();
|
||||
FUNC_TRACE();
|
||||
|
||||
#if (BTC_AV_EXT_CODEC == TRUE)
|
||||
bta_av_co_cb.codec_cfg.id = bta_av_co_cb.codec_caps.id;
|
||||
bta_av_build_src_cfg(bta_av_co_cb.codec_cfg.info, bta_av_co_cb.codec_caps.info);
|
||||
#else
|
||||
/* Reset the current configuration to SBC */
|
||||
bta_av_co_cb.codec_cfg.id = BTC_AV_CODEC_SBC;
|
||||
|
||||
if (A2D_BldSbcInfo(A2D_MEDIA_TYPE_AUDIO, (tA2D_SBC_CIE *)&btc_av_sbc_default_config, bta_av_co_cb.codec_cfg.info) != A2D_SUCCESS) {
|
||||
APPL_TRACE_ERROR("bta_av_co_audio_codec_reset A2D_BldSbcInfo failed");
|
||||
}
|
||||
#endif
|
||||
|
||||
osi_mutex_global_unlock();
|
||||
}
|
||||
@@ -1564,7 +1596,6 @@ BOOLEAN bta_av_co_audio_set_codec(const tBTC_AV_MEDIA_FEEDINGS *p_feeding, tBTC_
|
||||
/* The new config was correctly built */
|
||||
bta_av_co_cb.codec_cfg = new_cfg;
|
||||
|
||||
|
||||
/* Check all devices support it */
|
||||
*p_status = BTC_AV_SUCCESS;
|
||||
return bta_av_co_audio_codec_supported(p_status);
|
||||
@@ -1666,13 +1697,16 @@ void bta_av_co_audio_discard_config(tBTA_AV_HNDL hndl)
|
||||
** Returns Nothing
|
||||
**
|
||||
*******************************************************************************/
|
||||
void bta_av_co_init(void)
|
||||
void bta_av_co_init(tBTC_AV_CODEC_INFO *codec_caps)
|
||||
{
|
||||
FUNC_TRACE();
|
||||
|
||||
/* Reset the control block */
|
||||
memset(&bta_av_co_cb, 0, sizeof(bta_av_co_cb));
|
||||
|
||||
if (codec_caps) {
|
||||
memcpy(&bta_av_co_cb.codec_caps, codec_caps, sizeof(tBTC_AV_CODEC_INFO));
|
||||
}
|
||||
bta_av_co_cb.codec_cfg_setconfig.id = BTC_AV_CODEC_NONE;
|
||||
|
||||
#if defined(BTA_AV_CO_CP_SCMS_T) && (BTA_AV_CO_CP_SCMS_T == TRUE)
|
||||
@@ -1685,7 +1719,6 @@ void bta_av_co_init(void)
|
||||
bta_av_co_audio_codec_reset();
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function bta_av_co_peer_cp_supported
|
||||
@@ -1729,7 +1762,7 @@ BOOLEAN bta_av_co_peer_cp_supported(tBTA_AV_HNDL hndl)
|
||||
** of our exported bitpool range. If set we will set the
|
||||
** remote preference.
|
||||
**
|
||||
** Returns TRUE if config set, FALSE otherwize
|
||||
** Returns TRUE if config set, FALSE otherwise
|
||||
**
|
||||
*******************************************************************************/
|
||||
|
||||
|
@@ -49,7 +49,12 @@ void btc_a2dp_on_idle(void)
|
||||
}
|
||||
#endif // BTC_AV_SRC_INCLUDED
|
||||
|
||||
bta_av_co_init();
|
||||
#if (BTC_AV_EXT_CODEC == TRUE)
|
||||
tBTC_AV_CODEC_INFO *codec_caps = btc_av_codec_cap_get();
|
||||
#else
|
||||
tBTC_AV_CODEC_INFO *codec_caps = NULL;
|
||||
#endif
|
||||
bta_av_co_init(codec_caps);
|
||||
|
||||
#if BTC_AV_SINK_INCLUDED
|
||||
if (btc_av_get_peer_sep() == AVDT_TSEP_SRC && btc_av_get_service_id() == BTA_A2DP_SINK_SERVICE_ID) {
|
||||
@@ -88,9 +93,11 @@ BOOLEAN btc_a2dp_on_started(tBTA_AV_START *p_av, BOOLEAN pending_start)
|
||||
ack = TRUE;
|
||||
}
|
||||
} else {
|
||||
#if (BTC_AV_EXT_CODEC == FALSE)
|
||||
/* we were remotely started, make sure codec
|
||||
is setup before datapath is started */
|
||||
btc_a2dp_source_setup_codec();
|
||||
#endif
|
||||
}
|
||||
|
||||
/* media task is autostarted upon a2dp audiopath connection */
|
||||
|
@@ -71,8 +71,10 @@ static void btc_a2dp_datapath_open(void)
|
||||
/* Start the media task to encode SBC */
|
||||
btc_a2dp_source_start_audio_req();
|
||||
|
||||
#if (BTC_AV_EXT_CODEC == FALSE)
|
||||
/* make sure we update any changed sbc encoder params */
|
||||
btc_a2dp_source_encoder_update();
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
#if (BTC_AV_SINK_INCLUDED == TRUE)
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -30,12 +30,13 @@
|
||||
#include "btc_av.h"
|
||||
#include "btc/btc_util.h"
|
||||
#include "esp_a2dp_api.h"
|
||||
#include "oi_codec_sbc.h"
|
||||
#include "oi_status.h"
|
||||
#include "osi/future.h"
|
||||
#include <assert.h>
|
||||
|
||||
#if (BTC_AV_SINK_INCLUDED == TRUE)
|
||||
#if (BTC_AV_SINK_INCLUDED == TRUE) && (BTC_AV_EXT_CODEC == FALSE)
|
||||
|
||||
#include "oi_codec_sbc.h"
|
||||
#include "oi_status.h"
|
||||
|
||||
/*****************************************************************************
|
||||
** Constants
|
||||
@@ -85,13 +86,6 @@ typedef struct {
|
||||
void *param;
|
||||
} a2dp_sink_task_evt_t;
|
||||
|
||||
typedef struct {
|
||||
UINT16 num_frames_to_be_processed;
|
||||
UINT16 len;
|
||||
UINT16 offset;
|
||||
UINT16 layer_specific;
|
||||
} tBT_SBC_HDR;
|
||||
|
||||
typedef struct {
|
||||
BOOLEAN rx_flush; /* discards any incoming data when true */
|
||||
UINT8 channel_count;
|
||||
@@ -121,7 +115,7 @@ static void btc_a2dp_sink_rx_flush(void);
|
||||
static int btc_a2dp_sink_get_track_frequency(UINT8 frequency);
|
||||
static int btc_a2dp_sink_get_track_channel_count(UINT8 channeltype);
|
||||
/* Handle incoming media packets A2DP SINK streaming*/
|
||||
static void btc_a2dp_sink_handle_inc_media(tBT_SBC_HDR *p_msg);
|
||||
static void btc_a2dp_sink_handle_inc_media(BT_HDR *p_msg);
|
||||
static void btc_a2dp_sink_handle_decoder_reset(tBTC_MEDIA_SINK_CFG_UPDATE *p_msg);
|
||||
static void btc_a2dp_sink_handle_clear_track(void);
|
||||
static BOOLEAN btc_a2dp_sink_clear_track(void);
|
||||
@@ -346,7 +340,7 @@ void btc_a2dp_sink_reset_decoder(UINT8 *p_av)
|
||||
|
||||
static void btc_a2dp_sink_data_ready(UNUSED_ATTR void *context)
|
||||
{
|
||||
tBT_SBC_HDR *p_msg;
|
||||
BT_HDR *p_msg;
|
||||
int nb_of_msgs_to_process = 0;
|
||||
|
||||
if (fixed_queue_is_empty(a2dp_sink_local_param.btc_aa_snk_cb.RxSbcQ)) {
|
||||
@@ -362,13 +356,12 @@ static void btc_a2dp_sink_data_ready(UNUSED_ATTR void *context)
|
||||
if (btc_a2dp_sink_state != BTC_A2DP_SINK_STATE_ON){
|
||||
return;
|
||||
}
|
||||
p_msg = (tBT_SBC_HDR *)fixed_queue_dequeue(a2dp_sink_local_param.btc_aa_snk_cb.RxSbcQ, 0);
|
||||
p_msg = (BT_HDR *)fixed_queue_dequeue(a2dp_sink_local_param.btc_aa_snk_cb.RxSbcQ, 0);
|
||||
if ( p_msg == NULL ) {
|
||||
APPL_TRACE_ERROR("Insufficient data in que ");
|
||||
break;
|
||||
}
|
||||
btc_a2dp_sink_handle_inc_media(p_msg);
|
||||
osi_free(p_msg);
|
||||
nb_of_msgs_to_process--;
|
||||
}
|
||||
APPL_TRACE_DEBUG(" Process Frames - ");
|
||||
@@ -526,25 +519,27 @@ static void btc_a2dp_sink_handle_decoder_reset(tBTC_MEDIA_SINK_CFG_UPDATE *p_msg
|
||||
** Returns void
|
||||
**
|
||||
*******************************************************************************/
|
||||
static void btc_a2dp_sink_handle_inc_media(tBT_SBC_HDR *p_msg)
|
||||
static void btc_a2dp_sink_handle_inc_media(BT_HDR *p_msg)
|
||||
{
|
||||
UINT8 *sbc_start_frame = ((UINT8 *)(p_msg + 1) + p_msg->offset + 1);
|
||||
int count;
|
||||
UINT32 pcmBytes, availPcmBytes;
|
||||
OI_INT16 *pcmDataPointer = a2dp_sink_local_param.pcmData; /*Will be overwritten on next packet receipt*/
|
||||
OI_STATUS status;
|
||||
int num_sbc_frames = p_msg->num_frames_to_be_processed;
|
||||
int num_sbc_frames = (*((UINT8 *)(p_msg + 1) + p_msg->offset)) & 0x0f;
|
||||
UINT32 sbc_frame_len = p_msg->len - 1;
|
||||
availPcmBytes = sizeof(a2dp_sink_local_param.pcmData);
|
||||
|
||||
/* XXX: Check if the below check is correct, we are checking for peer to be sink when we are sink */
|
||||
if (btc_av_get_peer_sep() == AVDT_TSEP_SNK || (a2dp_sink_local_param.btc_aa_snk_cb.rx_flush)) {
|
||||
APPL_TRACE_DEBUG(" State Changed happened in this tick ");
|
||||
osi_free(p_msg);
|
||||
return;
|
||||
}
|
||||
|
||||
// ignore data if no one is listening
|
||||
if (!btc_a2dp_control_get_datachnl_stat()) {
|
||||
osi_free(p_msg);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -565,9 +560,9 @@ static void btc_a2dp_sink_handle_inc_media(tBT_SBC_HDR *p_msg)
|
||||
for (count = 0; count < num_sbc_frames && sbc_frame_len != 0; count ++) {
|
||||
pcmBytes = availPcmBytes;
|
||||
status = OI_CODEC_SBC_DecodeFrame(&a2dp_sink_local_param.context, (const OI_BYTE **)&sbc_start_frame,
|
||||
(OI_UINT32 *)&sbc_frame_len,
|
||||
(OI_INT16 *)pcmDataPointer,
|
||||
(OI_UINT32 *)&pcmBytes);
|
||||
(OI_UINT32 *)&sbc_frame_len,
|
||||
(OI_INT16 *)pcmDataPointer,
|
||||
(OI_UINT32 *)&pcmBytes);
|
||||
if (!OI_SUCCESS(status)) {
|
||||
APPL_TRACE_ERROR("Decoding failure: %d\n", status);
|
||||
break;
|
||||
@@ -577,6 +572,7 @@ static void btc_a2dp_sink_handle_inc_media(tBT_SBC_HDR *p_msg)
|
||||
p_msg->offset += (p_msg->len - 1) - sbc_frame_len;
|
||||
p_msg->len = sbc_frame_len + 1;
|
||||
}
|
||||
osi_free(p_msg);
|
||||
|
||||
btc_a2d_data_cb_to_app((uint8_t *)a2dp_sink_local_param.pcmData, (sizeof(a2dp_sink_local_param.pcmData) - availPcmBytes));
|
||||
}
|
||||
@@ -663,35 +659,28 @@ static int btc_a2dp_sink_get_track_channel_count(UINT8 channeltype)
|
||||
*******************************************************************************/
|
||||
UINT8 btc_a2dp_sink_enque_buf(BT_HDR *p_pkt)
|
||||
{
|
||||
tBT_SBC_HDR *p_msg;
|
||||
|
||||
if (btc_a2dp_sink_state != BTC_A2DP_SINK_STATE_ON){
|
||||
osi_free(p_pkt);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (a2dp_sink_local_param.btc_aa_snk_cb.rx_flush == TRUE) { /* Flush enabled, do not enque*/
|
||||
if (a2dp_sink_local_param.btc_aa_snk_cb.rx_flush == TRUE) { /* Flush enabled, do not enqueue */
|
||||
osi_free(p_pkt);
|
||||
return fixed_queue_length(a2dp_sink_local_param.btc_aa_snk_cb.RxSbcQ);
|
||||
}
|
||||
|
||||
if (fixed_queue_length(a2dp_sink_local_param.btc_aa_snk_cb.RxSbcQ) >= MAX_OUTPUT_A2DP_SNK_FRAME_QUEUE_SZ) {
|
||||
osi_free(p_pkt);
|
||||
APPL_TRACE_WARNING("Pkt dropped\n");
|
||||
return fixed_queue_length(a2dp_sink_local_param.btc_aa_snk_cb.RxSbcQ);
|
||||
}
|
||||
|
||||
APPL_TRACE_DEBUG("btc_a2dp_sink_enque_buf + ");
|
||||
|
||||
/* allocate and Queue this buffer */
|
||||
if ((p_msg = (tBT_SBC_HDR *) osi_malloc(sizeof(tBT_SBC_HDR) +
|
||||
p_pkt->offset + p_pkt->len)) != NULL) {
|
||||
memcpy(p_msg, p_pkt, (sizeof(BT_HDR) + p_pkt->offset + p_pkt->len));
|
||||
p_msg->num_frames_to_be_processed = (*((UINT8 *)(p_msg + 1) + p_msg->offset)) & 0x0f;
|
||||
APPL_TRACE_VERBOSE("btc_a2dp_sink_enque_buf %d + \n", p_msg->num_frames_to_be_processed);
|
||||
fixed_queue_enqueue(a2dp_sink_local_param.btc_aa_snk_cb.RxSbcQ, p_msg, FIXED_QUEUE_MAX_TIMEOUT);
|
||||
osi_thread_post_event(a2dp_sink_local_param.btc_aa_snk_cb.data_ready_event, OSI_THREAD_MAX_TIMEOUT);
|
||||
} else {
|
||||
/* let caller deal with a failed allocation */
|
||||
APPL_TRACE_WARNING("btc_a2dp_sink_enque_buf No Buffer left - ");
|
||||
}
|
||||
// p_msg->num_frames_to_be_processed = (*((UINT8 *)(p_msg + 1) + p_msg->offset)) & 0x0f;
|
||||
fixed_queue_enqueue(a2dp_sink_local_param.btc_aa_snk_cb.RxSbcQ, p_pkt, FIXED_QUEUE_MAX_TIMEOUT);
|
||||
osi_thread_post_event(a2dp_sink_local_param.btc_aa_snk_cb.data_ready_event, OSI_THREAD_MAX_TIMEOUT);
|
||||
|
||||
return fixed_queue_length(a2dp_sink_local_param.btc_aa_snk_cb.RxSbcQ);
|
||||
}
|
||||
|
||||
@@ -749,4 +738,4 @@ static void btc_a2dp_sink_thread_cleanup(UNUSED_ATTR void *context)
|
||||
a2dp_sink_local_param.btc_aa_snk_cb.data_ready_event = NULL;
|
||||
}
|
||||
|
||||
#endif /* BTC_AV_SINK_INCLUDED */
|
||||
#endif /* (BTC_AV_SINK_INCLUDED == TRUE) && (BTC_AV_EXT_CODEC == FALSE) */
|
||||
|
@@ -0,0 +1,286 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "common/bt_target.h"
|
||||
#include "common/bt_trace.h"
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include "common/bt_defs.h"
|
||||
#include "osi/allocator.h"
|
||||
#include "osi/mutex.h"
|
||||
#include "osi/thread.h"
|
||||
#include "osi/fixed_queue.h"
|
||||
#include "stack/a2d_api.h"
|
||||
#include "bta/bta_av_api.h"
|
||||
#include "bta/bta_av_ci.h"
|
||||
#include "btc_av_co.h"
|
||||
#include "btc_a2dp.h"
|
||||
#include "btc_a2dp_control.h"
|
||||
#include "btc_a2dp_sink.h"
|
||||
#include "btc/btc_manage.h"
|
||||
#include "btc_av.h"
|
||||
#include "btc/btc_util.h"
|
||||
#include "esp_a2dp_api.h"
|
||||
#include "osi/future.h"
|
||||
#include <assert.h>
|
||||
|
||||
#if (BTC_AV_SINK_INCLUDED == TRUE) && (BTC_AV_EXT_CODEC == TRUE)
|
||||
|
||||
#define MAX_OUTPUT_A2DP_SNK_FRAME_QUEUE_SZ (25)
|
||||
#define BTC_A2DP_SNK_DATA_QUEUE_IDX (1)
|
||||
|
||||
enum {
|
||||
BTC_A2DP_SINK_STATE_OFF = 0,
|
||||
BTC_A2DP_SINK_STATE_ON = 1,
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
BOOLEAN rx_flush; /* discards any incoming data when true */
|
||||
struct osi_event *data_ready_event;
|
||||
fixed_queue_t *audio_rx_q;
|
||||
} tBTC_A2DP_SINK_CB;
|
||||
|
||||
typedef struct {
|
||||
uint16_t expected_seq_num;
|
||||
bool seq_num_recount;
|
||||
} a2dp_sink_media_pkt_seq_num_t;
|
||||
|
||||
typedef struct {
|
||||
tBTC_A2DP_SINK_CB btc_aa_snk_cb;
|
||||
osi_thread_t *btc_aa_snk_task_hdl;
|
||||
a2dp_sink_media_pkt_seq_num_t media_pkt_seq_num;
|
||||
} a2dp_sink_local_param_t;
|
||||
|
||||
static int btc_a2dp_sink_state = BTC_A2DP_SINK_STATE_OFF;
|
||||
static esp_a2d_sink_audio_data_cb_t bt_aa_snk_audio_data_cb = NULL;
|
||||
|
||||
#if A2D_DYNAMIC_MEMORY == FALSE
|
||||
static a2dp_sink_local_param_t a2dp_sink_local_param;
|
||||
#else
|
||||
static a2dp_sink_local_param_t *a2dp_sink_local_param_ptr;
|
||||
#define a2dp_sink_local_param (*a2dp_sink_local_param_ptr)
|
||||
#endif ///A2D_DYNAMIC_MEMORY == FALSE
|
||||
|
||||
static void btc_a2dp_sink_data_ready(UNUSED_ATTR void *context);
|
||||
static void btc_a2dp_sink_handle_inc_media(BT_HDR *p_msg);
|
||||
|
||||
void btc_a2dp_sink_reg_audio_data_cb(esp_a2d_sink_audio_data_cb_t callback)
|
||||
{
|
||||
bt_aa_snk_audio_data_cb = callback;
|
||||
}
|
||||
|
||||
static inline void btc_a2d_audio_data_cb_to_app(uint16_t conn_hdl, uint8_t *buf, uint8_t *data, uint16_t len, uint16_t number_frame, uint32_t timestamp)
|
||||
{
|
||||
if (bt_aa_snk_audio_data_cb) {
|
||||
/* AVDT media packet offset is larger than sizeof(esp_a2d_audio_buff_t), it safe to do this */
|
||||
esp_a2d_audio_buff_t *audio_buff = (esp_a2d_audio_buff_t *)buf;
|
||||
audio_buff->buff_size = len;
|
||||
audio_buff->number_frame = number_frame;
|
||||
audio_buff->data_len = len;
|
||||
audio_buff->data = data;
|
||||
audio_buff->timestamp = timestamp;
|
||||
bt_aa_snk_audio_data_cb(conn_hdl, audio_buff);
|
||||
}
|
||||
else {
|
||||
osi_free(buf);
|
||||
}
|
||||
}
|
||||
|
||||
static void btc_a2dp_sink_rx_flush(void)
|
||||
{
|
||||
while (!fixed_queue_is_empty(a2dp_sink_local_param.btc_aa_snk_cb.audio_rx_q)) {
|
||||
osi_free(fixed_queue_dequeue(a2dp_sink_local_param.btc_aa_snk_cb.audio_rx_q, 0));
|
||||
}
|
||||
}
|
||||
|
||||
bool btc_a2dp_sink_startup(void)
|
||||
{
|
||||
if (btc_a2dp_sink_state != BTC_A2DP_SINK_STATE_OFF) {
|
||||
APPL_TRACE_ERROR("a2dp sink already start up");
|
||||
return false;
|
||||
}
|
||||
|
||||
#if A2D_DYNAMIC_MEMORY == TRUE
|
||||
if ((a2dp_sink_local_param_ptr = (a2dp_sink_local_param_t *)osi_malloc(sizeof(a2dp_sink_local_param_t))) == NULL) {
|
||||
APPL_TRACE_ERROR("%s malloc failed!", __func__);
|
||||
return false;
|
||||
}
|
||||
memset((void *)a2dp_sink_local_param_ptr, 0, sizeof(a2dp_sink_local_param_t));
|
||||
#endif
|
||||
|
||||
a2dp_sink_local_param.btc_aa_snk_task_hdl = btc_get_current_thread();
|
||||
|
||||
struct osi_event *data_event = osi_event_create(btc_a2dp_sink_data_ready, NULL);
|
||||
assert (data_event != NULL);
|
||||
osi_event_bind(data_event, a2dp_sink_local_param.btc_aa_snk_task_hdl, BTC_A2DP_SNK_DATA_QUEUE_IDX);
|
||||
a2dp_sink_local_param.btc_aa_snk_cb.data_ready_event = data_event;
|
||||
a2dp_sink_local_param.btc_aa_snk_cb.audio_rx_q = fixed_queue_new(QUEUE_SIZE_MAX);
|
||||
btc_a2dp_sink_state = BTC_A2DP_SINK_STATE_ON;
|
||||
|
||||
btc_a2dp_control_init();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void btc_a2dp_sink_shutdown(void)
|
||||
{
|
||||
if (btc_a2dp_sink_state != BTC_A2DP_SINK_STATE_ON) {
|
||||
APPL_TRACE_ERROR("a2dp sink already shutdown");
|
||||
return;
|
||||
}
|
||||
|
||||
btc_a2dp_control_set_datachnl_stat(FALSE);
|
||||
|
||||
btc_a2dp_sink_state = BTC_A2DP_SINK_STATE_OFF;
|
||||
|
||||
btc_a2dp_control_cleanup();
|
||||
|
||||
fixed_queue_free(a2dp_sink_local_param.btc_aa_snk_cb.audio_rx_q, osi_free_func);
|
||||
|
||||
a2dp_sink_local_param.btc_aa_snk_cb.audio_rx_q = NULL;
|
||||
|
||||
osi_event_delete(a2dp_sink_local_param.btc_aa_snk_cb.data_ready_event);
|
||||
a2dp_sink_local_param.btc_aa_snk_cb.data_ready_event = NULL;
|
||||
|
||||
a2dp_sink_local_param.btc_aa_snk_task_hdl = NULL;
|
||||
|
||||
#if A2D_DYNAMIC_MEMORY == TRUE
|
||||
osi_free(a2dp_sink_local_param_ptr);
|
||||
a2dp_sink_local_param_ptr = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
void btc_a2dp_sink_on_idle(void)
|
||||
{
|
||||
a2dp_sink_local_param.btc_aa_snk_cb.rx_flush = TRUE;
|
||||
btc_a2dp_sink_rx_flush();
|
||||
}
|
||||
|
||||
void btc_a2dp_sink_on_stopped(tBTA_AV_SUSPEND *p_av)
|
||||
{
|
||||
UNUSED(p_av);
|
||||
|
||||
a2dp_sink_local_param.btc_aa_snk_cb.rx_flush = TRUE;
|
||||
btc_a2dp_control_set_datachnl_stat(FALSE);
|
||||
btc_a2dp_sink_rx_flush();
|
||||
}
|
||||
|
||||
void btc_a2dp_sink_on_suspended(tBTA_AV_SUSPEND *p_av)
|
||||
{
|
||||
UNUSED(p_av);
|
||||
|
||||
a2dp_sink_local_param.btc_aa_snk_cb.rx_flush = TRUE;
|
||||
btc_a2dp_sink_rx_flush();
|
||||
}
|
||||
|
||||
void btc_a2dp_sink_set_rx_flush(BOOLEAN enable)
|
||||
{
|
||||
if (enable == FALSE) {
|
||||
a2dp_sink_local_param.media_pkt_seq_num.expected_seq_num = 0x1;
|
||||
a2dp_sink_local_param.media_pkt_seq_num.seq_num_recount = true;
|
||||
}
|
||||
a2dp_sink_local_param.btc_aa_snk_cb.rx_flush = enable;
|
||||
btc_a2dp_sink_rx_flush();
|
||||
}
|
||||
|
||||
static void btc_a2dp_sink_data_ready(UNUSED_ATTR void *context)
|
||||
{
|
||||
BT_HDR *p_msg;
|
||||
int nb_of_msgs_to_process = 0;
|
||||
|
||||
if (btc_a2dp_sink_state != BTC_A2DP_SINK_STATE_ON){
|
||||
return;
|
||||
}
|
||||
|
||||
if (!fixed_queue_is_empty(a2dp_sink_local_param.btc_aa_snk_cb.audio_rx_q)) {
|
||||
if (a2dp_sink_local_param.btc_aa_snk_cb.rx_flush == TRUE) {
|
||||
btc_a2dp_sink_rx_flush();
|
||||
return;
|
||||
}
|
||||
nb_of_msgs_to_process = fixed_queue_length(a2dp_sink_local_param.btc_aa_snk_cb.audio_rx_q);
|
||||
APPL_TRACE_DEBUG("%s nb msgs:%d", __func__, nb_of_msgs_to_process);
|
||||
while (nb_of_msgs_to_process > 0) {
|
||||
p_msg = (BT_HDR *)fixed_queue_dequeue(a2dp_sink_local_param.btc_aa_snk_cb.audio_rx_q, 0);
|
||||
if ( p_msg == NULL ) {
|
||||
APPL_TRACE_ERROR("%s insufficient data in queue", __func__);
|
||||
break;
|
||||
}
|
||||
btc_a2dp_sink_handle_inc_media(p_msg);
|
||||
nb_of_msgs_to_process--;
|
||||
}
|
||||
|
||||
if (!fixed_queue_is_empty(a2dp_sink_local_param.btc_aa_snk_cb.audio_rx_q)) {
|
||||
osi_thread_post_event(a2dp_sink_local_param.btc_aa_snk_cb.data_ready_event, OSI_THREAD_MAX_TIMEOUT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void btc_a2dp_sink_handle_inc_media(BT_HDR *p_msg)
|
||||
{
|
||||
UINT8 *sbc_start_frame = ((UINT8 *)(p_msg + 1) + p_msg->offset + 1);
|
||||
int num_sbc_frames = (*((UINT8 *)(p_msg + 1) + p_msg->offset)) & 0x0f;
|
||||
UINT32 sbc_frame_len = p_msg->len - 1;
|
||||
|
||||
if (a2dp_sink_local_param.btc_aa_snk_cb.rx_flush) {
|
||||
osi_free(p_msg);
|
||||
return;
|
||||
}
|
||||
|
||||
/* ignore data if no one is listening */
|
||||
if (!btc_a2dp_control_get_datachnl_stat()) {
|
||||
osi_free(p_msg);
|
||||
return;
|
||||
}
|
||||
|
||||
if (p_msg->layer_specific != a2dp_sink_local_param.media_pkt_seq_num.expected_seq_num) {
|
||||
/* Because the sequence number of some devices is not recounted */
|
||||
if (!a2dp_sink_local_param.media_pkt_seq_num.seq_num_recount ||
|
||||
a2dp_sink_local_param.media_pkt_seq_num.expected_seq_num != 0x1) {
|
||||
APPL_TRACE_WARNING("Sequence numbers error, recv:0x%x, expect:0x%x, recount:0x%x",
|
||||
p_msg->layer_specific, a2dp_sink_local_param.media_pkt_seq_num.expected_seq_num,
|
||||
a2dp_sink_local_param.media_pkt_seq_num.seq_num_recount);
|
||||
}
|
||||
}
|
||||
a2dp_sink_local_param.media_pkt_seq_num.expected_seq_num = p_msg->layer_specific + 1;
|
||||
a2dp_sink_local_param.media_pkt_seq_num.seq_num_recount = false;
|
||||
|
||||
APPL_TRACE_DEBUG("Number of sbc frames %d, frame_len %d\n", num_sbc_frames, sbc_frame_len);
|
||||
|
||||
UINT32 timestamp = *((UINT32 *) (p_msg + 1));
|
||||
UINT16 conn_hdl = btc_a2d_conn_handle_get();
|
||||
btc_a2d_audio_data_cb_to_app(conn_hdl, (uint8_t *)p_msg, sbc_start_frame, sbc_frame_len, num_sbc_frames, timestamp);
|
||||
/* dont free p_msg here */
|
||||
}
|
||||
|
||||
UINT8 btc_a2dp_sink_enque_buf(BT_HDR *p_pkt)
|
||||
{
|
||||
if (btc_a2dp_sink_state != BTC_A2DP_SINK_STATE_ON){
|
||||
osi_free(p_pkt);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (a2dp_sink_local_param.btc_aa_snk_cb.rx_flush == TRUE) {
|
||||
/* Flush enabled, do not enqueue */
|
||||
osi_free(p_pkt);
|
||||
return fixed_queue_length(a2dp_sink_local_param.btc_aa_snk_cb.audio_rx_q);
|
||||
}
|
||||
|
||||
if (fixed_queue_length(a2dp_sink_local_param.btc_aa_snk_cb.audio_rx_q) >= MAX_OUTPUT_A2DP_SNK_FRAME_QUEUE_SZ) {
|
||||
osi_free(p_pkt);
|
||||
APPL_TRACE_WARNING("Pkt dropped\n");
|
||||
return fixed_queue_length(a2dp_sink_local_param.btc_aa_snk_cb.audio_rx_q);
|
||||
}
|
||||
|
||||
APPL_TRACE_DEBUG("btc_a2dp_sink_enque_buf + ");
|
||||
|
||||
// p_msg->num_frames_to_be_processed = (*((UINT8 *)(p_msg + 1) + p_msg->offset)) & 0x0f;
|
||||
fixed_queue_enqueue(a2dp_sink_local_param.btc_aa_snk_cb.audio_rx_q, p_pkt, FIXED_QUEUE_MAX_TIMEOUT);
|
||||
osi_thread_post_event(a2dp_sink_local_param.btc_aa_snk_cb.data_ready_event, OSI_THREAD_MAX_TIMEOUT);
|
||||
|
||||
return fixed_queue_length(a2dp_sink_local_param.btc_aa_snk_cb.audio_rx_q);
|
||||
}
|
||||
|
||||
#endif
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -36,11 +36,12 @@
|
||||
#include "btc_av.h"
|
||||
#include "btc/btc_util.h"
|
||||
#include "esp_a2dp_api.h"
|
||||
#include "sbc_encoder.h"
|
||||
#include "osi/future.h"
|
||||
#include <assert.h>
|
||||
|
||||
#if BTC_AV_SRC_INCLUDED
|
||||
#if (BTC_AV_SRC_INCLUDED == TRUE) && (BTC_AV_EXT_CODEC == FALSE)
|
||||
|
||||
#include "sbc_encoder.h"
|
||||
|
||||
/*****************************************************************************
|
||||
** BQB global variables
|
||||
@@ -83,12 +84,6 @@ enum {
|
||||
|
||||
#define BTC_MEDIA_AA_BUF_SIZE (4096+16)
|
||||
|
||||
#if (BTA_AV_CO_CP_SCMS_T == TRUE)
|
||||
#define BTC_MEDIA_AA_SBC_OFFSET (AVDT_MEDIA_OFFSET + BTA_AV_SBC_HDR_SIZE + 1)
|
||||
#else
|
||||
#define BTC_MEDIA_AA_SBC_OFFSET (AVDT_MEDIA_OFFSET + BTA_AV_SBC_HDR_SIZE)
|
||||
#endif
|
||||
|
||||
#ifndef BTC_MEDIA_BITRATE_STEP
|
||||
#define BTC_MEDIA_BITRATE_STEP 5
|
||||
#endif
|
||||
@@ -170,6 +165,10 @@ typedef struct {
|
||||
UINT64 last_frame_us;
|
||||
} a2dp_source_local_param_t;
|
||||
|
||||
static BOOLEAN btc_a2dp_source_stop_audio_req(void);
|
||||
static BOOLEAN btc_a2dp_source_tx_flush_req(void);
|
||||
static BOOLEAN btc_a2dp_source_audio_feeding_init_req(tBTC_MEDIA_INIT_AUDIO_FEEDING *p_msg);
|
||||
|
||||
static void btc_a2dp_source_thread_init(UNUSED_ATTR void *context);
|
||||
static void btc_a2dp_source_thread_cleanup(UNUSED_ATTR void *context);
|
||||
static void btc_a2dp_source_flush_q(fixed_queue_t *p_q);
|
||||
@@ -226,11 +225,6 @@ static inline void btc_aa_cb_to_app(esp_a2d_cb_event_t event, esp_a2d_cb_param_t
|
||||
** BTC ADAPTATION
|
||||
*****************************************************************************/
|
||||
|
||||
bool btc_a2dp_source_is_streaming(void)
|
||||
{
|
||||
return a2dp_source_local_param.btc_aa_src_cb.is_tx_timer == TRUE;
|
||||
}
|
||||
|
||||
bool btc_a2dp_source_is_task_shutting_down(void)
|
||||
{
|
||||
return btc_a2dp_source_state == BTC_A2DP_SOURCE_STATE_SHUTTING_DOWN;
|
||||
@@ -505,7 +499,7 @@ BOOLEAN btc_a2dp_source_start_audio_req(void)
|
||||
** Returns TRUE is success
|
||||
**
|
||||
*******************************************************************************/
|
||||
BOOLEAN btc_a2dp_source_stop_audio_req(void)
|
||||
static BOOLEAN btc_a2dp_source_stop_audio_req(void)
|
||||
{
|
||||
/*
|
||||
* Explicitly check whether the btc_aa_src_ctrl_queue is not NULL to
|
||||
@@ -536,7 +530,7 @@ BOOLEAN btc_a2dp_source_stop_audio_req(void)
|
||||
** Returns TRUE is success
|
||||
**
|
||||
*******************************************************************************/
|
||||
BOOLEAN btc_a2dp_source_enc_init_req(tBTC_MEDIA_INIT_AUDIO *p_msg)
|
||||
static BOOLEAN btc_a2dp_source_enc_init_req(tBTC_MEDIA_INIT_AUDIO *p_msg)
|
||||
{
|
||||
tBTC_MEDIA_INIT_AUDIO *p_buf;
|
||||
if (NULL == (p_buf = osi_malloc(sizeof(tBTC_MEDIA_INIT_AUDIO)))) {
|
||||
@@ -559,7 +553,7 @@ BOOLEAN btc_a2dp_source_enc_init_req(tBTC_MEDIA_INIT_AUDIO *p_msg)
|
||||
** Returns TRUE is success
|
||||
**
|
||||
*******************************************************************************/
|
||||
BOOLEAN btc_a2dp_source_enc_update_req(tBTC_MEDIA_UPDATE_AUDIO *p_msg)
|
||||
static BOOLEAN btc_a2dp_source_enc_update_req(tBTC_MEDIA_UPDATE_AUDIO *p_msg)
|
||||
{
|
||||
tBTC_MEDIA_UPDATE_AUDIO *p_buf;
|
||||
if (NULL == (p_buf = osi_malloc(sizeof(tBTC_MEDIA_UPDATE_AUDIO)))) {
|
||||
@@ -1451,6 +1445,7 @@ static void btc_a2dp_source_prep_2_send(UINT8 nb_frame)
|
||||
*******************************************************************************/
|
||||
static void btc_a2dp_source_send_aa_frame(void)
|
||||
{
|
||||
/* if external codec is used, skip generate audio frame */
|
||||
UINT8 nb_frame_2_send;
|
||||
|
||||
/* get the number of frame to send */
|
||||
@@ -1461,8 +1456,8 @@ static void btc_a2dp_source_send_aa_frame(void)
|
||||
btc_a2dp_source_prep_2_send(nb_frame_2_send);
|
||||
}
|
||||
|
||||
/* send it */
|
||||
BTC_TRACE_VERBOSE("%s: send %d frames", __FUNCTION__, nb_frame_2_send);
|
||||
BTC_TRACE_VERBOSE("%s: send %d new frames", __FUNCTION__, nb_frame_2_send);
|
||||
|
||||
bta_av_ci_src_data_ready(BTA_AV_CHNL_AUDIO);
|
||||
}
|
||||
|
||||
@@ -1539,8 +1534,8 @@ static void btc_a2dp_source_aa_stop_tx(void)
|
||||
when the DUT and the remote device issue SUSPEND simultaneously
|
||||
and due to the processing of the SUSPEND request from the remote,
|
||||
the media path is torn down. If the A2DP HAL happens to wait
|
||||
for ACK for the initiated SUSPEND, it would never receive it casuing
|
||||
a block/wait. Due to this acknowledgement, the A2DP HAL is guranteed
|
||||
for ACK for the initiated SUSPEND, it would never receive it causing
|
||||
a block/wait. Due to this acknowledgement, the A2DP HAL is guaranteed
|
||||
to get the ACK for any pending command in such cases. */
|
||||
|
||||
if (send_ack) {
|
||||
@@ -1647,4 +1642,4 @@ static void btc_a2dp_source_thread_cleanup(UNUSED_ATTR void *context)
|
||||
a2dp_source_local_param.btc_aa_src_cb.poll_data = NULL;
|
||||
}
|
||||
|
||||
#endif /* BTC_AV_INCLUDED */
|
||||
#endif /* (BTC_AV_SRC_INCLUDED == TRUE) && (BTC_AV_EXT_CODEC == FALSE) */
|
||||
|
@@ -0,0 +1,235 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "common/bt_target.h"
|
||||
#include "common/bt_trace.h"
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include "osi/allocator.h"
|
||||
#include "osi/fixed_queue.h"
|
||||
#include "stack/a2d_api.h"
|
||||
#include "bta/bta_av_api.h"
|
||||
#include "bta/bta_av_ci.h"
|
||||
#include "btc/btc_manage.h"
|
||||
#include "btc/btc_common.h"
|
||||
#include "btc_av_co.h"
|
||||
#include "btc_a2dp.h"
|
||||
#include "btc_a2dp_control.h"
|
||||
#include "btc_a2dp_source.h"
|
||||
#include "btc_av.h"
|
||||
#include "esp_a2dp_api.h"
|
||||
#include <assert.h>
|
||||
|
||||
#if (BTC_AV_SRC_INCLUDED == TRUE) && (BTC_AV_EXT_CODEC == TRUE)
|
||||
|
||||
#define MAX_OUTPUT_A2DP_SRC_FRAME_QUEUE_SZ (27)
|
||||
|
||||
enum {
|
||||
BTC_A2DP_SOURCE_STATE_OFF = 0,
|
||||
BTC_A2DP_SOURCE_STATE_ON = 1,
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
BOOLEAN stream_started;
|
||||
BOOLEAN tx_flush;
|
||||
fixed_queue_t *audio_tx_q;
|
||||
} a2dp_source_local_param_t;
|
||||
|
||||
static int btc_a2dp_source_state = BTC_A2DP_SOURCE_STATE_OFF;
|
||||
#if A2D_DYNAMIC_MEMORY == FALSE
|
||||
static a2dp_source_local_param_t a2dp_source_local_param;
|
||||
#else
|
||||
static a2dp_source_local_param_t *a2dp_source_local_param_ptr;
|
||||
#define a2dp_source_local_param (*a2dp_source_local_param_ptr)
|
||||
#endif ///A2D_DYNAMIC_MEMORY == FALSE
|
||||
|
||||
static inline void btc_aa_cb_to_app(esp_a2d_cb_event_t event, esp_a2d_cb_param_t *param)
|
||||
{
|
||||
esp_a2d_cb_t btc_aa_cb = (esp_a2d_cb_t)btc_profile_cb_get(BTC_PID_A2DP);
|
||||
if (btc_aa_cb) {
|
||||
btc_aa_cb(event, param);
|
||||
}
|
||||
}
|
||||
|
||||
static void btc_a2dp_source_tx_flush(void)
|
||||
{
|
||||
while (!fixed_queue_is_empty(a2dp_source_local_param.audio_tx_q)) {
|
||||
osi_free(fixed_queue_dequeue(a2dp_source_local_param.audio_tx_q, 0));
|
||||
}
|
||||
}
|
||||
|
||||
static void btc_a2dp_source_tx_stop(void)
|
||||
{
|
||||
if (a2dp_source_local_param.stream_started == TRUE) {
|
||||
a2dp_source_local_param.stream_started = FALSE;
|
||||
/* ack to command */
|
||||
btc_a2dp_control_command_ack(ESP_A2D_MEDIA_CTRL_ACK_SUCCESS);
|
||||
}
|
||||
|
||||
/* flush tx queue */
|
||||
btc_a2dp_source_tx_flush();
|
||||
a2dp_source_local_param.tx_flush = FALSE;
|
||||
}
|
||||
|
||||
BOOLEAN btc_a2dp_source_enqueue_audio_frame(BT_HDR *p_buf)
|
||||
{
|
||||
if (btc_a2dp_source_state != BTC_A2DP_SOURCE_STATE_ON) {
|
||||
APPL_TRACE_WARNING("%s source not start up", __func__);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (a2dp_source_local_param.tx_flush) {
|
||||
APPL_TRACE_WARNING("%s try to send data when tx flush enable", __func__);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (fixed_queue_length(a2dp_source_local_param.audio_tx_q) > MAX_OUTPUT_A2DP_SRC_FRAME_QUEUE_SZ) {
|
||||
APPL_TRACE_WARNING("%s audio tx queue overflow: %d", __func__, fixed_queue_length(a2dp_source_local_param.audio_tx_q));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
fixed_queue_enqueue(a2dp_source_local_param.audio_tx_q, p_buf, FIXED_QUEUE_MAX_TIMEOUT);
|
||||
bta_av_ci_src_data_ready(BTA_AV_CHNL_AUDIO);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void btc_source_report_delay_value(UINT16 delay_value)
|
||||
{
|
||||
esp_a2d_cb_param_t param;
|
||||
|
||||
if (btc_a2dp_source_state != BTC_A2DP_SOURCE_STATE_ON){
|
||||
return;
|
||||
}
|
||||
|
||||
param.a2d_report_delay_value_stat.delay_value = delay_value;
|
||||
|
||||
btc_aa_cb_to_app(ESP_A2D_REPORT_SNK_DELAY_VALUE_EVT, ¶m);
|
||||
}
|
||||
|
||||
BOOLEAN btc_a2dp_source_start_audio_req(void)
|
||||
{
|
||||
a2dp_source_local_param.stream_started = TRUE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BT_HDR *btc_a2dp_source_audio_readbuf(void)
|
||||
{
|
||||
if (btc_a2dp_source_state != BTC_A2DP_SOURCE_STATE_ON || a2dp_source_local_param.tx_flush){
|
||||
return NULL;
|
||||
}
|
||||
return fixed_queue_dequeue(a2dp_source_local_param.audio_tx_q, 0);
|
||||
}
|
||||
|
||||
void btc_a2dp_source_set_tx_flush(BOOLEAN enable)
|
||||
{
|
||||
a2dp_source_local_param.tx_flush = enable;
|
||||
if (enable) {
|
||||
btc_a2dp_source_tx_flush();
|
||||
}
|
||||
}
|
||||
|
||||
void btc_a2dp_source_on_suspended(tBTA_AV_SUSPEND *p_av)
|
||||
{
|
||||
/* check for status failures */
|
||||
if (p_av->status != BTA_AV_SUCCESS) {
|
||||
if (p_av->initiator == TRUE) {
|
||||
btc_a2dp_control_command_ack(ESP_A2D_MEDIA_CTRL_ACK_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
/* stop tx, ack to cmd, flush tx queue */
|
||||
btc_a2dp_source_tx_stop();
|
||||
}
|
||||
|
||||
void btc_a2dp_source_on_stopped(tBTA_AV_SUSPEND *p_av)
|
||||
{
|
||||
/* allow using this api for other than suspend */
|
||||
if (p_av != NULL) {
|
||||
if (p_av->status != BTA_AV_SUCCESS) {
|
||||
if (p_av->initiator) {
|
||||
btc_a2dp_control_command_ack(ESP_A2D_MEDIA_CTRL_ACK_FAILURE);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* stop tx, ack to cmd, flush tx queue */
|
||||
btc_a2dp_source_tx_stop();
|
||||
}
|
||||
|
||||
void btc_a2dp_source_on_idle(void)
|
||||
{
|
||||
/* stop tx, ack to cmd, flush tx queue */
|
||||
btc_a2dp_source_tx_stop();
|
||||
}
|
||||
|
||||
bool btc_a2dp_source_is_task_shutting_down(void)
|
||||
{
|
||||
/* always return false, remove this api when internal codec is remove */
|
||||
return false;
|
||||
}
|
||||
|
||||
bool btc_a2dp_source_startup(void)
|
||||
{
|
||||
if (btc_a2dp_source_state != BTC_A2DP_SOURCE_STATE_OFF) {
|
||||
APPL_TRACE_ERROR("%s A2DP source already start up", __func__);
|
||||
return false;
|
||||
}
|
||||
|
||||
#if A2D_DYNAMIC_MEMORY == TRUE
|
||||
if ((a2dp_source_local_param_ptr = (a2dp_source_local_param_t *)osi_malloc(sizeof(a2dp_source_local_param_t))) == NULL) {
|
||||
APPL_TRACE_ERROR("%s malloc failed!", __func__);
|
||||
return false;
|
||||
}
|
||||
memset((void *)a2dp_source_local_param_ptr, 0, sizeof(a2dp_source_local_param_t));
|
||||
#endif
|
||||
|
||||
btc_a2dp_source_state = BTC_A2DP_SOURCE_STATE_ON;
|
||||
|
||||
a2dp_source_local_param.audio_tx_q = fixed_queue_new(QUEUE_SIZE_MAX);
|
||||
if(a2dp_source_local_param.audio_tx_q == NULL) {
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
btc_a2dp_control_init();
|
||||
|
||||
return true;
|
||||
|
||||
error_exit:;
|
||||
APPL_TRACE_ERROR("%s A2DP source start up failed", __func__);
|
||||
|
||||
#if A2D_DYNAMIC_MEMORY == TRUE
|
||||
osi_free(a2dp_source_local_param_ptr);
|
||||
a2dp_source_local_param_ptr = NULL;
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void btc_a2dp_source_shutdown(void)
|
||||
{
|
||||
if (btc_a2dp_source_state != BTC_A2DP_SOURCE_STATE_ON) {
|
||||
APPL_TRACE_ERROR("%s A2DP source already shutdown", __func__);
|
||||
return;
|
||||
}
|
||||
btc_a2dp_source_state = BTC_A2DP_SOURCE_STATE_OFF;
|
||||
|
||||
btc_a2dp_control_cleanup();
|
||||
|
||||
fixed_queue_free(a2dp_source_local_param.audio_tx_q, osi_free_func);
|
||||
|
||||
a2dp_source_local_param.audio_tx_q = NULL;
|
||||
a2dp_source_local_param.tx_flush = FALSE;
|
||||
a2dp_source_local_param.stream_started = FALSE;
|
||||
|
||||
#if A2D_DYNAMIC_MEMORY == TRUE
|
||||
osi_free(a2dp_source_local_param_ptr);
|
||||
a2dp_source_local_param_ptr = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* (BTC_AV_SRC_INCLUDED == TRUE) && (BTC_AV_EXT_CODEC == TRUE) */
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "btc/btc_common.h"
|
||||
#include "btc/btc_manage.h"
|
||||
#include "btc_av.h"
|
||||
#include "btc_av_co.h"
|
||||
#include "btc_avrc.h"
|
||||
#include "btc/btc_util.h"
|
||||
#include "btc/btc_profile_queue.h"
|
||||
@@ -46,6 +47,9 @@ bool g_a2dp_source_ongoing_deinit;
|
||||
bool g_a2dp_sink_ongoing_deinit;
|
||||
|
||||
|
||||
/* reserve some bytes for media payload header (currently, only SBC, 1 byte) */
|
||||
#define BTC_AV_AUDIO_MTU_RESERVE 1
|
||||
|
||||
/*****************************************************************************
|
||||
** Constants & Macros
|
||||
******************************************************************************/
|
||||
@@ -74,6 +78,9 @@ typedef enum {
|
||||
#define BTC_AV_FLAG_PENDING_START 0x4
|
||||
#define BTC_AV_FLAG_PENDING_STOP 0x8
|
||||
|
||||
#define BTC_AV_SBC_CIE_OFFSET 3
|
||||
#define BTC_AV_SBC_CIE_LEN 4
|
||||
|
||||
/*****************************************************************************
|
||||
** Local type definitions
|
||||
******************************************************************************/
|
||||
@@ -81,11 +88,13 @@ typedef enum {
|
||||
typedef struct {
|
||||
int service_id;
|
||||
tBTA_AV_HNDL bta_handle;
|
||||
UINT16 mtu;
|
||||
bt_bdaddr_t peer_bda;
|
||||
btc_sm_handle_t sm_handle;
|
||||
UINT8 flags;
|
||||
tBTA_AV_EDR edr;
|
||||
UINT8 peer_sep; /* sep type of peer device */
|
||||
tBTC_AV_CODEC_INFO codec_caps;
|
||||
#if BTC_AV_SRC_INCLUDED
|
||||
osi_alarm_t *tle_av_open_on_rc;
|
||||
#endif /* BTC_AV_SRC_INCLUDED */
|
||||
@@ -170,6 +179,7 @@ static void btc_av_event_free_data(btc_msg_t *msg);
|
||||
|
||||
extern tBTA_AV_CO_FUNCTS bta_av_a2d_cos;
|
||||
extern tBTA_AVRC_CO_FUNCTS bta_avrc_cos;
|
||||
extern tA2D_SBC_CIE btc_av_sbc_default_config;
|
||||
/*****************************************************************************
|
||||
** Local helper functions
|
||||
******************************************************************************/
|
||||
@@ -222,7 +232,7 @@ UNUSED_ATTR static const char *dump_av_sm_event_name(btc_av_sm_event_t event)
|
||||
CASE_RETURN_STR(BTC_AV_DISCONNECT_REQ_EVT)
|
||||
CASE_RETURN_STR(BTC_AV_START_STREAM_REQ_EVT)
|
||||
CASE_RETURN_STR(BTC_AV_SUSPEND_STREAM_REQ_EVT)
|
||||
CASE_RETURN_STR(BTC_AV_SINK_CONFIG_REQ_EVT)
|
||||
CASE_RETURN_STR(BTC_AV_CONFIG_EVT)
|
||||
default: return "UNKNOWN_EVENT";
|
||||
}
|
||||
}
|
||||
@@ -263,7 +273,7 @@ static void btc_initiate_av_open_tmr_hdlr(void *arg)
|
||||
/*****************************************************************************
|
||||
** Static functions
|
||||
******************************************************************************/
|
||||
static void btc_report_connection_state(esp_a2d_connection_state_t state, bt_bdaddr_t *bd_addr, int disc_rsn)
|
||||
static void btc_report_connection_state(esp_a2d_connection_state_t state, bt_bdaddr_t *bd_addr, uint16_t mtu, int disc_rsn)
|
||||
{
|
||||
// todo: add callback for SRC
|
||||
esp_a2d_cb_param_t param;
|
||||
@@ -272,8 +282,15 @@ static void btc_report_connection_state(esp_a2d_connection_state_t state, bt_bda
|
||||
param.conn_stat.state = state;
|
||||
if (bd_addr) {
|
||||
memcpy(param.conn_stat.remote_bda, bd_addr, sizeof(esp_bd_addr_t));
|
||||
if (memcmp(bd_addr, &(btc_av_cb.peer_bda), sizeof(bt_bdaddr_t)) == 0) {
|
||||
param.conn_stat.conn_hdl = btc_av_cb.bta_handle;
|
||||
}
|
||||
}
|
||||
if (state == ESP_A2D_CONNECTION_STATE_DISCONNECTED) {
|
||||
if (state == ESP_A2D_CONNECTION_STATE_CONNECTED) {
|
||||
param.conn_stat.audio_mtu = mtu;
|
||||
btc_av_cb.mtu = mtu;
|
||||
}
|
||||
else if (state == ESP_A2D_CONNECTION_STATE_DISCONNECTED) {
|
||||
param.conn_stat.disc_rsn = (disc_rsn == 0) ? ESP_A2D_DISC_RSN_NORMAL :
|
||||
ESP_A2D_DISC_RSN_ABNORMAL;
|
||||
}
|
||||
@@ -289,6 +306,9 @@ static void btc_report_audio_state(esp_a2d_audio_state_t state, bt_bdaddr_t *bd_
|
||||
param.audio_stat.state = state;
|
||||
if (bd_addr) {
|
||||
memcpy(param.audio_stat.remote_bda, bd_addr, sizeof(esp_bd_addr_t));
|
||||
if (memcmp(bd_addr, &(btc_av_cb.peer_bda), sizeof(bt_bdaddr_t)) == 0) {
|
||||
param.audio_stat.conn_hdl = btc_av_cb.bta_handle;
|
||||
}
|
||||
}
|
||||
btc_a2d_cb_to_app(ESP_A2D_AUDIO_STATE_EVT, ¶m);
|
||||
}
|
||||
@@ -328,6 +348,12 @@ static BOOLEAN btc_av_state_idle_handler(btc_sm_event_t event, void *p_data)
|
||||
case BTA_AV_REGISTER_EVT:
|
||||
btc_av_cb.bta_handle = ((tBTA_AV *)p_data)->registr.hndl;
|
||||
break;
|
||||
case BTA_AV_SEP_REG_EVT:
|
||||
param.a2d_sep_reg_stat.seid = ((tBTA_AV *)p_data)->sep_reg.seid;
|
||||
param.a2d_sep_reg_stat.reg_state = (((tBTA_AV *)p_data)->sep_reg.reg_state == BTA_AV_SUCCESS) ? ESP_A2D_SEP_REG_SUCCESS :
|
||||
ESP_A2D_SEP_REG_FAIL;
|
||||
btc_a2d_cb_to_app(ESP_A2D_SEP_REG_STATE_EVT, ¶m);
|
||||
break;
|
||||
|
||||
case BTA_AV_PENDING_EVT:
|
||||
case BTC_AV_CONNECT_REQ_EVT: {
|
||||
@@ -358,7 +384,7 @@ static BOOLEAN btc_av_state_idle_handler(btc_sm_event_t event, void *p_data)
|
||||
|
||||
case BTC_AV_DISCONNECT_REQ_EVT:
|
||||
BTC_TRACE_WARNING("No Link At All.");
|
||||
btc_report_connection_state(ESP_A2D_CONNECTION_STATE_DISCONNECTED, &((btc_av_disconn_req_t *)p_data)->target_bda, 0);
|
||||
btc_report_connection_state(ESP_A2D_CONNECTION_STATE_DISCONNECTED, &((btc_av_disconn_req_t *)p_data)->target_bda, 0, 0);
|
||||
break;
|
||||
|
||||
case BTA_AV_RC_OPEN_EVT:
|
||||
@@ -448,7 +474,7 @@ static BOOLEAN btc_av_state_opening_handler(btc_sm_event_t event, void *p_data)
|
||||
switch (event) {
|
||||
case BTC_SM_ENTER_EVT:
|
||||
/* inform the application that we are entering connecting state */
|
||||
btc_report_connection_state(ESP_A2D_CONNECTION_STATE_CONNECTING, &(btc_av_cb.peer_bda), 0);
|
||||
btc_report_connection_state(ESP_A2D_CONNECTION_STATE_CONNECTING, &(btc_av_cb.peer_bda), 0, 0);
|
||||
break;
|
||||
|
||||
case BTC_SM_EXIT_EVT:
|
||||
@@ -456,7 +482,7 @@ static BOOLEAN btc_av_state_opening_handler(btc_sm_event_t event, void *p_data)
|
||||
|
||||
case BTA_AV_REJECT_EVT:
|
||||
BTC_TRACE_WARNING(" Received BTA_AV_REJECT_EVT \n");
|
||||
btc_report_connection_state(ESP_A2D_CONNECTION_STATE_DISCONNECTED, &(btc_av_cb.peer_bda), 0);
|
||||
btc_report_connection_state(ESP_A2D_CONNECTION_STATE_DISCONNECTED, &(btc_av_cb.peer_bda), 0, 0);
|
||||
btc_sm_change_state(btc_av_cb.sm_handle, BTC_AV_STATE_IDLE);
|
||||
break;
|
||||
|
||||
@@ -464,13 +490,14 @@ static BOOLEAN btc_av_state_opening_handler(btc_sm_event_t event, void *p_data)
|
||||
tBTA_AV *p_bta_data = (tBTA_AV *)p_data;
|
||||
esp_a2d_connection_state_t conn_stat;
|
||||
btc_sm_state_t av_state;
|
||||
uint16_t mtu = 0;
|
||||
BTC_TRACE_DEBUG("status:%d, edr 0x%x, peer sep %d\n", p_bta_data->open.status,
|
||||
p_bta_data->open.edr, p_bta_data->open.sep);
|
||||
|
||||
if (p_bta_data->open.status == BTA_AV_SUCCESS) {
|
||||
btc_av_cb.edr = p_bta_data->open.edr;
|
||||
btc_av_cb.peer_sep = p_bta_data->open.sep;
|
||||
|
||||
mtu = p_bta_data->open.mtu - BTC_AV_AUDIO_MTU_RESERVE;
|
||||
conn_stat = ESP_A2D_CONNECTION_STATE_CONNECTED;
|
||||
av_state = BTC_AV_STATE_OPENED;
|
||||
} else {
|
||||
@@ -480,7 +507,7 @@ static BOOLEAN btc_av_state_opening_handler(btc_sm_event_t event, void *p_data)
|
||||
av_state = BTC_AV_STATE_IDLE;
|
||||
}
|
||||
/* inform the application of the event */
|
||||
btc_report_connection_state(conn_stat, &(btc_av_cb.peer_bda), 0);
|
||||
btc_report_connection_state(conn_stat, &(btc_av_cb.peer_bda), mtu, 0);
|
||||
/* change state to open/idle based on the status */
|
||||
btc_sm_change_state(btc_av_cb.sm_handle, av_state);
|
||||
|
||||
@@ -502,13 +529,12 @@ static BOOLEAN btc_av_state_opening_handler(btc_sm_event_t event, void *p_data)
|
||||
btc_queue_advance();
|
||||
} break;
|
||||
|
||||
case BTC_AV_SINK_CONFIG_REQ_EVT: {
|
||||
if (btc_av_cb.peer_sep == AVDT_TSEP_SRC) {
|
||||
esp_a2d_cb_param_t param;
|
||||
memcpy(param.audio_cfg.remote_bda, &btc_av_cb.peer_bda, sizeof(esp_bd_addr_t));
|
||||
memcpy(¶m.audio_cfg.mcc, p_data, sizeof(esp_a2d_mcc_t));
|
||||
btc_a2d_cb_to_app(ESP_A2D_AUDIO_CFG_EVT, ¶m);
|
||||
}
|
||||
case BTC_AV_CONFIG_EVT: {
|
||||
esp_a2d_cb_param_t param;
|
||||
param.audio_cfg.conn_hdl = btc_av_cb.bta_handle;
|
||||
memcpy(param.audio_cfg.remote_bda, &btc_av_cb.peer_bda, sizeof(esp_bd_addr_t));
|
||||
memcpy(¶m.audio_cfg.mcc, p_data, sizeof(esp_a2d_mcc_t));
|
||||
btc_a2d_cb_to_app(ESP_A2D_AUDIO_CFG_EVT, ¶m);
|
||||
} break;
|
||||
|
||||
case BTC_AV_CONNECT_REQ_EVT:
|
||||
@@ -520,7 +546,7 @@ static BOOLEAN btc_av_state_opening_handler(btc_sm_event_t event, void *p_data)
|
||||
break;
|
||||
} else {
|
||||
BTC_TRACE_DEBUG("%s: Moved from idle by Incoming Connection request\n", __func__);
|
||||
btc_report_connection_state(ESP_A2D_CONNECTION_STATE_DISCONNECTED, (bt_bdaddr_t *)p_data, 0);
|
||||
btc_report_connection_state(ESP_A2D_CONNECTION_STATE_DISCONNECTED, (bt_bdaddr_t *)p_data, 0, 0);
|
||||
btc_queue_advance();
|
||||
break;
|
||||
}
|
||||
@@ -623,7 +649,7 @@ static BOOLEAN btc_av_state_closing_handler(btc_sm_event_t event, void *p_data)
|
||||
case BTA_AV_CLOSE_EVT: {
|
||||
tBTA_AV_CLOSE *close = (tBTA_AV_CLOSE *)p_data;
|
||||
/* inform the application that we are disconnecting */
|
||||
btc_report_connection_state(ESP_A2D_CONNECTION_STATE_DISCONNECTED, &(btc_av_cb.peer_bda), close->disc_rsn);
|
||||
btc_report_connection_state(ESP_A2D_CONNECTION_STATE_DISCONNECTED, &(btc_av_cb.peer_bda), 0, close->disc_rsn);
|
||||
btc_sm_change_state(btc_av_cb.sm_handle, BTC_AV_STATE_IDLE);
|
||||
break;
|
||||
}
|
||||
@@ -693,7 +719,9 @@ static BOOLEAN btc_av_state_opened_handler(btc_sm_event_t event, void *p_data)
|
||||
case BTC_AV_START_STREAM_REQ_EVT:
|
||||
#if BTC_AV_SRC_INCLUDED
|
||||
if (btc_av_cb.peer_sep != AVDT_TSEP_SRC) {
|
||||
#if (BTC_AV_EXT_CODEC == FALSE)
|
||||
btc_a2dp_source_setup_codec();
|
||||
#endif
|
||||
}
|
||||
#endif /* BTC_AV_SRC_INCLUDED */
|
||||
BTA_AvStart();
|
||||
@@ -759,7 +787,7 @@ static BOOLEAN btc_av_state_opened_handler(btc_sm_event_t event, void *p_data)
|
||||
}
|
||||
|
||||
/* inform the application that we are disconnecting */
|
||||
btc_report_connection_state(ESP_A2D_CONNECTION_STATE_DISCONNECTING, &(btc_av_cb.peer_bda), 0);
|
||||
btc_report_connection_state(ESP_A2D_CONNECTION_STATE_DISCONNECTING, &(btc_av_cb.peer_bda), 0, 0);
|
||||
break;
|
||||
|
||||
case BTA_AV_CLOSE_EVT: {
|
||||
@@ -767,7 +795,7 @@ static BOOLEAN btc_av_state_opened_handler(btc_sm_event_t event, void *p_data)
|
||||
btc_a2dp_on_stopped(NULL);
|
||||
tBTA_AV_CLOSE *close = (tBTA_AV_CLOSE *)p_data;
|
||||
/* inform the application that we are disconnected */
|
||||
btc_report_connection_state(ESP_A2D_CONNECTION_STATE_DISCONNECTED, &(btc_av_cb.peer_bda),
|
||||
btc_report_connection_state(ESP_A2D_CONNECTION_STATE_DISCONNECTED, &(btc_av_cb.peer_bda), 0,
|
||||
close->disc_rsn);
|
||||
|
||||
if (btc_av_cb.flags & BTC_AV_FLAG_PENDING_START) {
|
||||
@@ -804,7 +832,7 @@ static BOOLEAN btc_av_state_opened_handler(btc_sm_event_t event, void *p_data)
|
||||
} else {
|
||||
BTC_TRACE_DEBUG("%s: Moved to opened by Other Incoming Conn req\n", __func__);
|
||||
btc_report_connection_state(ESP_A2D_CONNECTION_STATE_DISCONNECTED,
|
||||
(bt_bdaddr_t *)p_data, ESP_A2D_DISC_RSN_NORMAL);
|
||||
(bt_bdaddr_t *)p_data, 0, ESP_A2D_DISC_RSN_NORMAL);
|
||||
}
|
||||
btc_queue_advance();
|
||||
break;
|
||||
@@ -917,7 +945,7 @@ static BOOLEAN btc_av_state_started_handler(btc_sm_event_t event, void *p_data)
|
||||
}
|
||||
|
||||
/* inform the application that we are disconnecting */
|
||||
btc_report_connection_state(ESP_A2D_CONNECTION_STATE_DISCONNECTING, &(btc_av_cb.peer_bda), 0);
|
||||
btc_report_connection_state(ESP_A2D_CONNECTION_STATE_DISCONNECTING, &(btc_av_cb.peer_bda), 0, 0);
|
||||
|
||||
/* wait in closing state until fully closed */
|
||||
btc_sm_change_state(btc_av_cb.sm_handle, BTC_AV_STATE_CLOSING);
|
||||
@@ -982,7 +1010,7 @@ static BOOLEAN btc_av_state_started_handler(btc_sm_event_t event, void *p_data)
|
||||
btc_a2dp_on_stopped(NULL);
|
||||
tBTA_AV_CLOSE *close = (tBTA_AV_CLOSE *)p_data;
|
||||
/* inform the application that we are disconnected */
|
||||
btc_report_connection_state(ESP_A2D_CONNECTION_STATE_DISCONNECTED, &(btc_av_cb.peer_bda),
|
||||
btc_report_connection_state(ESP_A2D_CONNECTION_STATE_DISCONNECTED, &(btc_av_cb.peer_bda), 0,
|
||||
close->disc_rsn);
|
||||
btc_sm_change_state(btc_av_cb.sm_handle, BTC_AV_STATE_IDLE);
|
||||
|
||||
@@ -1337,7 +1365,7 @@ static void bte_av_callback(tBTA_AV_EVT event, tBTA_AV *p_data)
|
||||
}
|
||||
|
||||
#if BTC_AV_SINK_INCLUDED
|
||||
static void bte_av_media_callback(tBTA_AV_EVT event, tBTA_AV_MEDIA *p_data)
|
||||
static void bte_av_media_sink_callback(tBTA_AV_EVT event, tBTA_AV_MEDIA *p_data)
|
||||
{
|
||||
btc_sm_state_t state;
|
||||
UINT8 que_len;
|
||||
@@ -1351,13 +1379,16 @@ static void bte_av_media_callback(tBTA_AV_EVT event, tBTA_AV_MEDIA *p_data)
|
||||
que_len = btc_a2dp_sink_enque_buf((BT_HDR *)p_data);
|
||||
BTC_TRACE_DEBUG(" Packets in Que %d\n", que_len);
|
||||
} else {
|
||||
osi_free(p_data);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (event == BTA_AV_MEDIA_SINK_CFG_EVT) {
|
||||
if (event == BTA_AV_MEDIA_CFG_EVT) {
|
||||
#if (BTC_AV_EXT_CODEC == FALSE)
|
||||
/* send a command to BT Media Task */
|
||||
btc_a2dp_sink_reset_decoder((UINT8 *)p_data);
|
||||
#endif
|
||||
|
||||
/* currently only supports SBC */
|
||||
a2d_status = A2D_ParsSbcInfo(&sbc_cie, (UINT8 *)p_data, FALSE);
|
||||
@@ -1367,11 +1398,11 @@ static void bte_av_media_callback(tBTA_AV_EVT event, tBTA_AV_MEDIA *p_data)
|
||||
|
||||
msg.sig = BTC_SIG_API_CB;
|
||||
msg.pid = BTC_PID_A2DP;
|
||||
msg.act = BTC_AV_SINK_CONFIG_REQ_EVT;
|
||||
msg.act = BTC_AV_CONFIG_EVT;
|
||||
|
||||
memset(&arg, 0, sizeof(btc_av_args_t));
|
||||
arg.mcc.type = ESP_A2D_MCT_SBC;
|
||||
memcpy(arg.mcc.cie.sbc, (uint8_t *)p_data + 3, ESP_A2D_CIE_LEN_SBC);
|
||||
memcpy(&arg.mcc.cie.sbc_info, (uint8_t *)p_data + BTC_AV_SBC_CIE_OFFSET, BTC_AV_SBC_CIE_LEN);
|
||||
btc_transfer_context(&msg, &arg, sizeof(btc_av_args_t), NULL, NULL);
|
||||
} else {
|
||||
BTC_TRACE_ERROR("ERROR dump_codec_info A2D_ParsSbcInfo fail:%d\n", a2d_status);
|
||||
@@ -1380,7 +1411,7 @@ static void bte_av_media_callback(tBTA_AV_EVT event, tBTA_AV_MEDIA *p_data)
|
||||
UNUSED(que_len);
|
||||
}
|
||||
#else
|
||||
static void bte_av_media_callback(tBTA_AV_EVT event, tBTA_AV_MEDIA *p_data)
|
||||
static void bte_av_media_sink_callback(tBTA_AV_EVT event, tBTA_AV_MEDIA *p_data)
|
||||
{
|
||||
UNUSED(event);
|
||||
UNUSED(p_data);
|
||||
@@ -1388,6 +1419,82 @@ static void bte_av_media_callback(tBTA_AV_EVT event, tBTA_AV_MEDIA *p_data)
|
||||
}
|
||||
#endif
|
||||
|
||||
#if BTC_AV_SRC_INCLUDED
|
||||
static void bte_av_media_source_callback(tBTA_AV_EVT event, tBTA_AV_MEDIA *p_data)
|
||||
{
|
||||
tA2D_STATUS a2d_status;
|
||||
tA2D_SBC_CIE sbc_cie;
|
||||
|
||||
if (event == BTA_AV_MEDIA_CFG_EVT) {
|
||||
/* currently only supports SBC */
|
||||
a2d_status = A2D_ParsSbcInfo(&sbc_cie, (UINT8 *)p_data, FALSE);
|
||||
if (a2d_status == A2D_SUCCESS) {
|
||||
btc_msg_t msg;
|
||||
btc_av_args_t arg;
|
||||
|
||||
msg.sig = BTC_SIG_API_CB;
|
||||
msg.pid = BTC_PID_A2DP;
|
||||
msg.act = BTC_AV_CONFIG_EVT;
|
||||
|
||||
memset(&arg, 0, sizeof(btc_av_args_t));
|
||||
arg.mcc.type = ESP_A2D_MCT_SBC;
|
||||
memcpy(&arg.mcc.cie.sbc_info, (uint8_t *)p_data + BTC_AV_SBC_CIE_OFFSET, BTC_AV_SBC_CIE_LEN);
|
||||
btc_transfer_context(&msg, &arg, sizeof(btc_av_args_t), NULL, NULL);
|
||||
} else {
|
||||
BTC_TRACE_ERROR("A2D_ParsSbcInfo fail:%d\n", a2d_status);
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
static void bte_av_media_source_callback(tBTA_AV_EVT event, tBTA_AV_MEDIA *p_data)
|
||||
{
|
||||
UNUSED(event);
|
||||
UNUSED(p_data);
|
||||
BTC_TRACE_WARNING("%s : event %u\n", __func__, event);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if (BTC_AV_EXT_CODEC == TRUE)
|
||||
|
||||
tBTC_AV_CODEC_INFO *btc_av_codec_cap_get(void)
|
||||
{
|
||||
return &btc_av_cb.codec_caps;
|
||||
}
|
||||
|
||||
static void btc_av_reg_sep(uint8_t tsep, uint8_t seid, esp_a2d_mcc_t *mcc)
|
||||
{
|
||||
tBTA_AV_DATA_CBACK *p_data_cback = NULL;
|
||||
esp_a2d_cb_param_t param;
|
||||
|
||||
param.a2d_sep_reg_stat.seid = seid;
|
||||
if (btc_av_cb.sm_handle == NULL || btc_sm_get_state(btc_av_cb.sm_handle) != BTC_AV_STATE_IDLE) {
|
||||
param.a2d_sep_reg_stat.reg_state = ESP_A2D_SEP_REG_INVALID_STATE;
|
||||
btc_a2d_cb_to_app(ESP_A2D_SEP_REG_STATE_EVT, ¶m);
|
||||
BTC_TRACE_WARNING("%s: try to reg sep when a2dp not init or connected", __func__);
|
||||
}
|
||||
|
||||
if (mcc->type == ESP_A2D_MCT_SBC) {
|
||||
A2D_BldSbcInfo(A2D_MEDIA_TYPE_AUDIO, (tA2D_SBC_CIE *)&btc_av_sbc_default_config, btc_av_cb.codec_caps.info);
|
||||
/* overwrite sbc cie */
|
||||
memcpy(btc_av_cb.codec_caps.info + A2D_SBC_CIE_OFF, &mcc->cie, A2D_SBC_CIE_LEN);
|
||||
|
||||
if (tsep == AVDT_TSEP_SNK) {
|
||||
p_data_cback = bte_av_media_sink_callback;
|
||||
}
|
||||
else {
|
||||
p_data_cback = bte_av_media_source_callback;
|
||||
}
|
||||
BTA_AvRegSEP(BTA_AV_CHNL_AUDIO, seid, tsep, BTA_AV_CODEC_SBC, btc_av_cb.codec_caps.info, p_data_cback);
|
||||
}
|
||||
else {
|
||||
param.a2d_sep_reg_stat.reg_state = ESP_A2D_SEP_REG_UNSUPPORTED;
|
||||
btc_a2d_cb_to_app(ESP_A2D_SEP_REG_STATE_EVT, ¶m);
|
||||
BTC_TRACE_WARNING("%s: unsupported codec type %d", __func__, mcc->type);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function btc_av_execute_service
|
||||
@@ -1399,7 +1506,15 @@ static void bte_av_media_callback(tBTA_AV_EVT event, tBTA_AV_MEDIA *p_data)
|
||||
*******************************************************************************/
|
||||
bt_status_t btc_av_execute_service(BOOLEAN b_enable, UINT8 tsep)
|
||||
{
|
||||
tBTA_AV_DATA_CBACK *p_data_cback = NULL;
|
||||
|
||||
if (b_enable) {
|
||||
if (tsep == AVDT_TSEP_SNK) {
|
||||
p_data_cback = bte_av_media_sink_callback;
|
||||
}
|
||||
else {
|
||||
p_data_cback = bte_av_media_source_callback;
|
||||
}
|
||||
/* TODO: Removed BTA_SEC_AUTHORIZE since the Java/App does not
|
||||
* handle this request in order to allow incoming connections to succeed.
|
||||
* We need to put this back once support for this is added */
|
||||
@@ -1413,11 +1528,11 @@ bt_status_t btc_av_execute_service(BOOLEAN b_enable, UINT8 tsep)
|
||||
BTA_AV_FEAT_RCTG | BTA_AV_FEAT_METADATA | BTA_AV_FEAT_VENDOR |
|
||||
BTA_AV_FEAT_RCCT | BTA_AV_FEAT_ADV_CTRL | BTA_AV_FEAT_DELAY_RPT,
|
||||
bte_av_callback);
|
||||
BTA_AvRegister(BTA_AV_CHNL_AUDIO, BTC_AV_SERVICE_NAME, 0, bte_av_media_callback, &bta_av_a2d_cos, &bta_avrc_cos, tsep);
|
||||
BTA_AvRegister(BTA_AV_CHNL_AUDIO, BTC_AV_SERVICE_NAME, 0, p_data_cback, &bta_av_a2d_cos, &bta_avrc_cos, tsep);
|
||||
} else {
|
||||
BTC_TRACE_WARNING("A2DP Enable without AVRC")
|
||||
BTA_AvEnable(BTA_SEC_AUTHENTICATE, BTA_AV_FEAT_NO_SCO_SSPD | BTA_AV_FEAT_DELAY_RPT, bte_av_callback);
|
||||
BTA_AvRegister(BTA_AV_CHNL_AUDIO, BTC_AV_SERVICE_NAME, 0, bte_av_media_callback, &bta_av_a2d_cos, NULL, tsep);
|
||||
BTA_AvRegister(BTA_AV_CHNL_AUDIO, BTC_AV_SERVICE_NAME, 0, p_data_cback, &bta_av_a2d_cos, NULL, tsep);
|
||||
}
|
||||
} else {
|
||||
BTA_AvDeregister(btc_av_cb.bta_handle);
|
||||
@@ -1476,6 +1591,11 @@ BOOLEAN btc_av_is_connected(void)
|
||||
return ((state == BTC_AV_STATE_OPENED) || (state == BTC_AV_STATE_STARTED));
|
||||
}
|
||||
|
||||
BOOLEAN btc_av_is_started(void)
|
||||
{
|
||||
return ((btc_sm_get_state(btc_av_cb.sm_handle) == BTC_AV_STATE_STARTED));
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* Function btc_av_get_service_id
|
||||
@@ -1548,15 +1668,17 @@ void btc_a2dp_call_handler(btc_msg_t *msg)
|
||||
btc_av_args_t *arg = (btc_av_args_t *)(msg->arg);
|
||||
switch (msg->act) {
|
||||
#if BTC_AV_SINK_INCLUDED
|
||||
case BTC_AV_SINK_CONFIG_REQ_EVT: {
|
||||
btc_sm_dispatch(btc_av_cb.sm_handle, msg->act, (void *)(msg->arg));
|
||||
break;
|
||||
}
|
||||
case BTC_AV_SINK_API_INIT_EVT: {
|
||||
btc_a2d_sink_init();
|
||||
// todo: callback to application
|
||||
break;
|
||||
}
|
||||
#if (BTC_AV_EXT_CODEC == TRUE)
|
||||
case BTC_AV_SINK_API_REG_SEP_EVT: {
|
||||
btc_av_reg_sep(AVDT_TSEP_SNK, arg->reg_sep.seid, &arg->reg_sep.mcc);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
case BTC_AV_SINK_API_DEINIT_EVT: {
|
||||
btc_a2d_sink_deinit();
|
||||
// todo: callback to application
|
||||
@@ -1574,10 +1696,17 @@ void btc_a2dp_call_handler(btc_msg_t *msg)
|
||||
btc_sm_dispatch(btc_av_cb.sm_handle, BTC_AV_DISCONNECT_REQ_EVT, &disconn_req);
|
||||
break;
|
||||
}
|
||||
#if (BTC_AV_EXT_CODEC == TRUE)
|
||||
case BTC_AV_SINK_API_REG_AUDIO_DATA_CB_EVT: {
|
||||
btc_a2dp_sink_reg_audio_data_cb(arg->audio_data_cb);
|
||||
break;
|
||||
}
|
||||
#else
|
||||
case BTC_AV_SINK_API_REG_DATA_CB_EVT: {
|
||||
btc_a2dp_sink_reg_data_cb(arg->data_cb);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
case BTC_AV_SINK_API_SET_DELAY_VALUE_EVT: {
|
||||
btc_a2d_sink_set_delay_value(arg->delay_value);
|
||||
break;
|
||||
@@ -1592,6 +1721,12 @@ void btc_a2dp_call_handler(btc_msg_t *msg)
|
||||
btc_a2d_src_init();
|
||||
break;
|
||||
}
|
||||
#if (BTC_AV_EXT_CODEC == TRUE)
|
||||
case BTC_AV_SRC_API_REG_SEP_EVT: {
|
||||
btc_av_reg_sep(AVDT_TSEP_SRC, arg->reg_sep.seid, &arg->reg_sep.mcc);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
case BTC_AV_SRC_API_DEINIT_EVT: {
|
||||
btc_a2d_src_deinit();
|
||||
break;
|
||||
@@ -1607,10 +1742,12 @@ void btc_a2dp_call_handler(btc_msg_t *msg)
|
||||
btc_sm_dispatch(btc_av_cb.sm_handle, BTC_AV_DISCONNECT_REQ_EVT, &disconn_req);
|
||||
break;
|
||||
}
|
||||
#if (BTC_AV_EXT_CODEC == FALSE)
|
||||
case BTC_AV_SRC_API_REG_DATA_CB_EVT: {
|
||||
btc_a2dp_src_reg_data_cb(arg->src_data_cb);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
#endif /* BTC_AV_SRC_INCLUDED */
|
||||
case BTC_AV_API_MEDIA_CTRL_EVT: {
|
||||
btc_a2dp_control_media_ctrl(arg->ctrl);
|
||||
@@ -1734,6 +1871,56 @@ static bt_status_t btc_a2d_src_connect(bt_bdaddr_t *remote_bda)
|
||||
return btc_queue_connect(UUID_SERVCLASS_AUDIO_SOURCE, remote_bda, connect_int);
|
||||
}
|
||||
|
||||
BOOLEAN btc_a2d_src_audio_mtu_check(uint16_t data_len)
|
||||
{
|
||||
|
||||
return (data_len <= btc_av_cb.mtu);
|
||||
}
|
||||
|
||||
bt_status_t btc_a2d_src_audio_data_send(esp_a2d_conn_hdl_t conn_hdl, esp_a2d_audio_buff_t *audio_buf)
|
||||
{
|
||||
#if (BTC_AV_EXT_CODEC == TRUE)
|
||||
if (conn_hdl != btc_av_cb.bta_handle) {
|
||||
return BT_STATUS_FAIL;
|
||||
}
|
||||
BT_HDR *p_buf = (BT_HDR *)audio_buf;
|
||||
assert(audio_buf->data - (UINT8 *)(p_buf + 1) >= BTC_AUDIO_BUFF_OFFSET);
|
||||
/* since p_buf and audio_buf point to the same memory, backup those value before modify p_buf */
|
||||
uint16_t number_frame = audio_buf->number_frame;
|
||||
uint16_t data_len = audio_buf->data_len;
|
||||
uint32_t timestamp = audio_buf->timestamp;
|
||||
p_buf->offset = audio_buf->data - (UINT8 *)(p_buf + 1);
|
||||
p_buf->layer_specific = number_frame;
|
||||
p_buf->len = data_len;
|
||||
*((UINT32 *) (p_buf + 1)) = timestamp;
|
||||
|
||||
if (btc_a2dp_source_enqueue_audio_frame(p_buf)) {
|
||||
return BT_STATUS_SUCCESS;
|
||||
}
|
||||
#endif
|
||||
return BT_STATUS_FAIL;
|
||||
}
|
||||
|
||||
#endif /* BTC_AV_SRC_INCLUDED */
|
||||
|
||||
uint16_t btc_a2d_conn_handle_get(void)
|
||||
{
|
||||
return btc_av_cb.bta_handle;
|
||||
}
|
||||
|
||||
void btc_av_audio_buff_alloc(uint16_t size, uint8_t **pp_buff, uint8_t **pp_data)
|
||||
{
|
||||
/* todo */
|
||||
BT_HDR *p_buf= (BT_HDR *)osi_calloc(sizeof(BT_HDR) + BTC_AUDIO_BUFF_OFFSET + size);
|
||||
if (p_buf != NULL) {
|
||||
*pp_buff = (uint8_t *)p_buf;
|
||||
*pp_data = (uint8_t *)(p_buf + 1) + BTC_AUDIO_BUFF_OFFSET;
|
||||
}
|
||||
}
|
||||
|
||||
void btc_av_audio_buff_free(uint8_t *p_buf)
|
||||
{
|
||||
osi_free(p_buf);
|
||||
}
|
||||
|
||||
#endif /* #if BTC_AV_INCLUDED */
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -64,6 +64,7 @@ typedef struct {
|
||||
typedef struct {
|
||||
/* Connected peer information */
|
||||
tBTA_AV_CO_PEER peers[BTA_AV_NUM_STRS];
|
||||
tBTC_AV_CODEC_INFO codec_caps;
|
||||
/* Current codec configuration - access to this variable must be protected */
|
||||
tBTC_AV_CODEC_INFO codec_cfg;
|
||||
tBTC_AV_CODEC_INFO codec_cfg_setconfig; /* remote peer setconfig preference */
|
||||
@@ -189,8 +190,7 @@ void bta_av_co_audio_discard_config(tBTA_AV_HNDL hndl);
|
||||
** Returns Nothing
|
||||
**
|
||||
*******************************************************************************/
|
||||
void bta_av_co_init(void);
|
||||
|
||||
void bta_av_co_init(tBTC_AV_CODEC_INFO *codec_caps);
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
@@ -211,7 +211,7 @@ BOOLEAN bta_av_co_peer_cp_supported(tBTA_AV_HNDL hndl);
|
||||
** of our exported bitpool range. If set we will set the
|
||||
** remote preference.
|
||||
**
|
||||
** Returns TRUE if config set, FALSE otherwize
|
||||
** Returns TRUE if config set, FALSE otherwise
|
||||
**
|
||||
*******************************************************************************/
|
||||
BOOLEAN bta_av_co_get_remote_bitpool_pref(UINT8 *min, UINT8 *max);
|
||||
|
@@ -35,9 +35,11 @@
|
||||
* CONST
|
||||
********************************************************************************/
|
||||
#if (BTM_SCO_HCI_INCLUDED == TRUE)
|
||||
#if (BTC_HFP_EXT_CODEC == FALSE)
|
||||
#include "oi_codec_sbc.h"
|
||||
#include "oi_status.h"
|
||||
#include "sbc_encoder.h"
|
||||
#endif
|
||||
|
||||
#if (PLC_INCLUDED == TRUE)
|
||||
#include "sbc_plc.h"
|
||||
@@ -58,21 +60,39 @@ static bta_hf_ct_plc_t *bta_hf_ct_plc_ptr;
|
||||
#define HF_SBC_DEC_RAW_DATA_SIZE 240
|
||||
#define HF_SBC_ENC_RAW_DATA_SIZE 240
|
||||
|
||||
// H2: Header with synchronization word and sequence number
|
||||
#define BTA_HF_H2_HEADER_SYNC_WORD 0x0801
|
||||
#define BTA_HF_H2_HEADER_SYNC_WORD_MASK 0x0FFF
|
||||
#define BTA_HF_H2_HEADER_BIT0_MASK (1 << 0)
|
||||
#define BTA_HF_H2_HEADER_BIT1_MASK (1 << 1)
|
||||
#define BTA_HF_H2_HEADER_SN0_BIT_OFFSET1 12
|
||||
#define BTA_HF_H2_HEADER_SN0_BIT_OFFSET2 13
|
||||
#define BTA_HF_H2_HEADER_SN1_BIT_OFFSET1 14
|
||||
#define BTA_HF_H2_HEADER_SN1_BIT_OFFSET2 15
|
||||
|
||||
#define BTA_HF_H2_HEADER_SYNC_WORD_CHECK(p) ((*((uint16_t *)p) & BTA_HF_H2_HEADER_SYNC_WORD_MASK) == BTA_HF_H2_HEADER_SYNC_WORD)
|
||||
|
||||
/* BTA-AG-CO control block to map bdaddr to BTA handle */
|
||||
typedef struct
|
||||
{
|
||||
#if (BTC_HFP_EXT_CODEC == FALSE)
|
||||
OI_CODEC_SBC_DECODER_CONTEXT decoder_context;
|
||||
OI_UINT32 decoder_context_data[HF_SBC_DEC_CONTEXT_DATA_LEN];
|
||||
OI_INT16 decode_raw_data[HF_SBC_DEC_RAW_DATA_SIZE];
|
||||
|
||||
SBC_ENC_PARAMS encoder;
|
||||
|
||||
UINT8 sequence_number;
|
||||
bool is_bad_frame;
|
||||
bool decode_first_pkt;
|
||||
OI_BYTE decode_msbc_data[BTM_MSBC_FRAME_SIZE];
|
||||
bool encode_first_pkt;
|
||||
OI_BYTE decode_msbc_data[BTM_MSBC_FRAME_SIZE];
|
||||
OI_BYTE encode_msbc_data[BTM_MSBC_FRAME_SIZE];
|
||||
#else
|
||||
UINT8 sequence_number;
|
||||
BOOLEAN rx_first_pkt;
|
||||
BOOLEAN is_bad_frame;
|
||||
UINT8 rx_half_msbc_data[BTM_MSBC_FRAME_SIZE/2];
|
||||
#endif
|
||||
} bta_ag_co_cb_t;
|
||||
|
||||
#if HFP_DYNAMIC_MEMORY == FALSE
|
||||
@@ -151,7 +171,7 @@ void bta_ag_ci_rx_write(UINT16 handle, char *p_data, UINT16 len)
|
||||
** Function bta_ag_ci_slc_ready
|
||||
**
|
||||
** Description This function is called to notify AG that SLC is up at
|
||||
** the application. This funcion is only used when the app
|
||||
** the application. This function is only used when the app
|
||||
** is running in pass-through mode.
|
||||
**
|
||||
** Returns void
|
||||
@@ -179,18 +199,9 @@ void bta_ag_ci_slc_ready(UINT16 handle)
|
||||
** Returns void
|
||||
**
|
||||
*******************************************************************************/
|
||||
static void bta_ag_h2_header(UINT16 *p_buf)
|
||||
void bta_ag_h2_header(UINT16 *p_buf)
|
||||
{
|
||||
// H2: Header with synchronization word and sequence number
|
||||
#define BTA_HF_H2_HEADER 0x0801
|
||||
#define BTA_HF_H2_HEADER_BIT0_MASK (1 << 0)
|
||||
#define BTA_HF_H2_HEADER_BIT1_MASK (1 << 1)
|
||||
#define BTA_HF_H2_HEADER_SN0_BIT_OFFSET1 12
|
||||
#define BTA_HF_H2_HEADER_SN0_BIT_OFFSET2 13
|
||||
#define BTA_HF_H2_HEADER_SN1_BIT_OFFSET1 14
|
||||
#define BTA_HF_H2_HEADER_SN1_BIT_OFFSET2 15
|
||||
|
||||
UINT16 h2_header = BTA_HF_H2_HEADER;
|
||||
UINT16 h2_header = BTA_HF_H2_HEADER_SYNC_WORD;
|
||||
UINT8 h2_header_sn0 = bta_ag_co_cb.sequence_number & BTA_HF_H2_HEADER_BIT0_MASK;
|
||||
UINT8 h2_header_sn1 = bta_ag_co_cb.sequence_number & BTA_HF_H2_HEADER_BIT1_MASK;
|
||||
h2_header |= (h2_header_sn0 << BTA_HF_H2_HEADER_SN0_BIT_OFFSET1
|
||||
@@ -202,6 +213,19 @@ static void bta_ag_h2_header(UINT16 *p_buf)
|
||||
*p_buf = h2_header;
|
||||
}
|
||||
|
||||
#if (BTC_HFP_EXT_CODEC == TRUE)
|
||||
|
||||
static void bta_ag_pkt_state_reset(void)
|
||||
{
|
||||
bta_ag_co_cb.sequence_number = 0;
|
||||
bta_ag_co_cb.rx_first_pkt = TRUE;
|
||||
bta_ag_co_cb.is_bad_frame = FALSE;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if (BTC_HFP_EXT_CODEC == FALSE)
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function bta_hf_dec_init
|
||||
@@ -217,6 +241,7 @@ static void bta_hf_dec_init(void)
|
||||
sbc_plc_init(&(bta_hf_ct_plc.plc_state));
|
||||
#endif ///(PLC_INCLUDED == TRUE)
|
||||
|
||||
|
||||
OI_STATUS status = OI_CODEC_SBC_DecoderReset(&bta_ag_co_cb.decoder_context, bta_ag_co_cb.decoder_context_data,
|
||||
HF_SBC_DEC_CONTEXT_DATA_LEN * sizeof(OI_UINT32), 1, 1, FALSE, TRUE);
|
||||
if (!OI_SUCCESS(status)) {
|
||||
@@ -326,15 +351,21 @@ static void bta_ag_decode_msbc_frame(UINT8 **data, UINT8 *length, BOOLEAN is_bad
|
||||
APPL_TRACE_ERROR("Frame decode error: %d", status);
|
||||
break;
|
||||
}
|
||||
#endif ///(PLC_INCLUDED == TRUE)
|
||||
|
||||
if (OI_SUCCESS(status)) {
|
||||
btc_hf_incoming_data_cb_to_app((const uint8_t *)(bta_hf_ct_plc.sbc_plc_out), sbc_raw_data_size);
|
||||
}
|
||||
#else
|
||||
if (OI_SUCCESS(status)) {
|
||||
btc_hf_incoming_data_cb_to_app((const uint8_t *)(bta_ag_co_cb.decode_raw_data), sbc_raw_data_size);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*******************************************************************************
|
||||
* BTA AG SCO CO FUNCITONS
|
||||
* BTA AG SCO CO FUNCTIONS
|
||||
********************************************************************************/
|
||||
/*******************************************************************************
|
||||
**
|
||||
@@ -418,8 +449,12 @@ void bta_ag_sco_co_open(UINT16 handle, tBTM_SCO_AIR_MODE_TYPE air_mode, UINT8 in
|
||||
}
|
||||
#endif ///(PLC_INCLUDED == TRUE)
|
||||
#endif /// (HFP_DYNAMIC_MEMORY == TRUE)
|
||||
#if (BTC_HFP_EXT_CODEC == TRUE)
|
||||
bta_ag_pkt_state_reset();
|
||||
#else
|
||||
bta_hf_dec_init();
|
||||
bta_hf_enc_init();
|
||||
#endif
|
||||
return;
|
||||
} else {
|
||||
return; // Nothing to do
|
||||
@@ -476,6 +511,8 @@ void bta_ag_sco_co_close(void)
|
||||
hf_inout_pkt_size = 0;
|
||||
}
|
||||
|
||||
#if (BTC_HFP_EXT_CODEC == FALSE)
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function bta_ag_sco_co_out_data
|
||||
@@ -525,7 +562,7 @@ uint32_t bta_ag_sco_co_out_data(UINT8 *p_buf)
|
||||
//Never run to here.
|
||||
}
|
||||
} else {
|
||||
APPL_TRACE_ERROR("%s invaild air mode: %d", __FUNCTION__, hf_air_mode);
|
||||
APPL_TRACE_ERROR("%s invalid air mode: %d", __FUNCTION__, hf_air_mode);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -546,6 +583,65 @@ void bta_ag_sco_co_in_data(BT_HDR *p_buf, tBTM_SCO_DATA_FLAG status)
|
||||
STREAM_SKIP_UINT16(p);
|
||||
STREAM_TO_UINT8(pkt_size, p);
|
||||
|
||||
#if (BTC_HFP_EXT_CODEC == TRUE)
|
||||
if (hf_air_mode == BTM_SCO_AIR_MODE_CVSD) {
|
||||
btc_hf_audio_data_cb_to_app((uint8_t *)p_buf, (uint8_t *)p, pkt_size, status != BTM_SCO_DATA_CORRECT);
|
||||
}
|
||||
else if (hf_air_mode == BTM_SCO_AIR_MODE_TRANSPNT) {
|
||||
if (pkt_size != hf_inout_pkt_size) {
|
||||
bta_ag_co_cb.is_bad_frame = true;
|
||||
}
|
||||
if (status != BTM_SCO_DATA_CORRECT) {
|
||||
bta_ag_co_cb.is_bad_frame = true;
|
||||
}
|
||||
if (hf_inout_pkt_size == BTM_MSBC_FRAME_SIZE / 2) {
|
||||
if (pkt_size > BTM_MSBC_FRAME_SIZE / 2) {
|
||||
pkt_size = BTM_MSBC_FRAME_SIZE / 2;
|
||||
}
|
||||
if (bta_ag_co_cb.rx_first_pkt){
|
||||
memcpy(bta_ag_co_cb.rx_half_msbc_data, p, pkt_size);
|
||||
osi_free(p_buf);
|
||||
} else {
|
||||
BT_HDR *p_new_buf = osi_calloc(sizeof(BT_HDR) + BTM_MSBC_FRAME_SIZE);
|
||||
p_new_buf->offset = 0;
|
||||
UINT8 *p_data = (UINT8 *)(p_new_buf + 1) + p_new_buf->offset;
|
||||
memcpy(p_data, bta_ag_co_cb.rx_half_msbc_data, BTM_MSBC_FRAME_SIZE / 2);
|
||||
memcpy(p_data + BTM_MSBC_FRAME_SIZE / 2, p, pkt_size);
|
||||
osi_free(p_buf);
|
||||
if (BTA_HF_H2_HEADER_SYNC_WORD_CHECK(p_data)) {
|
||||
/* H2 header sync word found, skip */
|
||||
p_data += 2;
|
||||
}
|
||||
else if (!bta_ag_co_cb.is_bad_frame){
|
||||
/* not a bad frame, assume as H1 header */
|
||||
p_data += 1;
|
||||
}
|
||||
btc_hf_audio_data_cb_to_app((uint8_t *)p_new_buf, (uint8_t *)p_data, BTM_MSBC_FRAME_SIZE, bta_ag_co_cb.is_bad_frame);
|
||||
bta_ag_co_cb.is_bad_frame = false;
|
||||
memset(bta_ag_co_cb.decode_msbc_data, 0, BTM_MSBC_FRAME_SIZE);
|
||||
}
|
||||
bta_ag_co_cb.rx_first_pkt = !bta_ag_co_cb.rx_first_pkt;
|
||||
}
|
||||
else if (hf_inout_pkt_size == BTM_MSBC_FRAME_SIZE) {
|
||||
if (pkt_size > BTM_MSBC_FRAME_SIZE) {
|
||||
pkt_size = BTM_MSBC_FRAME_SIZE;
|
||||
}
|
||||
if (BTA_HF_H2_HEADER_SYNC_WORD_CHECK(p)) {
|
||||
/* H2 header sync word found, skip */
|
||||
p += 2;
|
||||
}
|
||||
else if (!bta_ag_co_cb.is_bad_frame){
|
||||
/* not a bad frame, assume as H1 header */
|
||||
p += 1;
|
||||
}
|
||||
btc_hf_audio_data_cb_to_app((uint8_t *)p_buf, (uint8_t *)p, pkt_size, bta_ag_co_cb.is_bad_frame);
|
||||
bta_ag_co_cb.is_bad_frame = false;
|
||||
}
|
||||
else {
|
||||
osi_free(p_buf);
|
||||
}
|
||||
}
|
||||
#else
|
||||
if (hf_air_mode == BTM_SCO_AIR_MODE_CVSD) {
|
||||
// CVSD
|
||||
if(status != BTM_SCO_DATA_CORRECT) {
|
||||
@@ -583,8 +679,12 @@ void bta_ag_sco_co_in_data(BT_HDR *p_buf, tBTM_SCO_DATA_FLAG status)
|
||||
//Never run to here.
|
||||
}
|
||||
} else {
|
||||
APPL_TRACE_ERROR("%s invaild air mode: %d", __FUNCTION__, hf_air_mode);
|
||||
APPL_TRACE_ERROR("%s invalid air mode: %d", __FUNCTION__, hf_air_mode);
|
||||
}
|
||||
osi_free(p_buf);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* #if (BTM_SCO_HCI_INCLUDED == TRUE) */
|
||||
#endif /* #if (BTA_AG_INCLUDED == TRUE) */
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -236,12 +236,15 @@ static void bte_hf_evt(tBTA_AG_EVT event, tBTA_AG *param)
|
||||
else if (BTA_AG_OPEN_EVT == event) {
|
||||
param_len = sizeof(tBTA_AG_OPEN);
|
||||
}
|
||||
else if ((BTA_AG_CLOSE_EVT == event) || (BTA_AG_AUDIO_OPEN_EVT == event) || (BTA_AG_AUDIO_CLOSE_EVT == event)) {
|
||||
else if ((BTA_AG_CLOSE_EVT == event)) {
|
||||
param_len = sizeof(tBTA_AG_HDR);
|
||||
}
|
||||
else if (BTA_AG_CONN_EVT == event) {
|
||||
param_len = sizeof(tBTA_AG_CONN);
|
||||
}
|
||||
else if ((BTA_AG_AUDIO_OPEN_EVT == event) || (BTA_AG_AUDIO_CLOSE_EVT == event) || (BTA_AG_AUDIO_MSBC_OPEN_EVT == event)) {
|
||||
param_len = sizeof(tBTA_AG_AUDIO_STAT);
|
||||
}
|
||||
else if (param) {
|
||||
param_len = sizeof(tBTA_AG_VAL);
|
||||
}
|
||||
@@ -265,6 +268,26 @@ void btc_hf_reg_data_cb(esp_hf_incoming_data_cb_t recv, esp_hf_outgoing_data_cb_
|
||||
hf_local_param[0].btc_hf_outgoing_data_cb = send;
|
||||
}
|
||||
|
||||
void btc_hf_reg_audio_data_cb(esp_hf_ag_audio_data_cb_t callback)
|
||||
{
|
||||
hf_local_param[0].btc_hf_audio_data_cb = callback;
|
||||
}
|
||||
|
||||
void btc_hf_audio_data_cb_to_app(uint8_t *buf, uint8_t *data, uint16_t len, bool is_bad_frame)
|
||||
{
|
||||
if (hf_local_param[0].btc_hf_audio_data_cb) {
|
||||
/* we always have sizeof(BT_HDR) bytes free space before data, it is enough for esp_hf_audio_buff_t */
|
||||
esp_hf_audio_buff_t *audio_buff = (esp_hf_audio_buff_t *)buf;
|
||||
audio_buff->buff_size = len;
|
||||
audio_buff->data_len = len;
|
||||
audio_buff->data = data;
|
||||
hf_local_param[0].btc_hf_audio_data_cb(hf_local_param[0].btc_hf_cb.sync_conn_hdl, audio_buff, is_bad_frame);
|
||||
}
|
||||
else {
|
||||
osi_free(buf);
|
||||
}
|
||||
}
|
||||
|
||||
void btc_hf_incoming_data_cb_to_app(const uint8_t *data, uint32_t len)
|
||||
{
|
||||
int idx = 0;
|
||||
@@ -949,6 +972,20 @@ bt_status_t btc_hf_ci_sco_data(void)
|
||||
return status;
|
||||
}
|
||||
|
||||
bool btc_hf_ag_audio_data_send(uint16_t sync_conn_hdl, uint8_t *p_buff_start, uint8_t *p_data, uint8_t data_len)
|
||||
{
|
||||
#if (BTM_SCO_HCI_INCLUDED == TRUE) && (BTA_HFP_EXT_CODEC == TRUE)
|
||||
/* currently, sync_conn_hdl is not used */
|
||||
int idx = btc_hf_latest_connected_idx();
|
||||
CHECK_HF_SLC_CONNECTED(idx);
|
||||
if (idx != BTC_HF_INVALID_IDX) {
|
||||
BTA_AgAudioDataSend(hf_local_param[idx].btc_hf_cb.handle, p_buff_start, p_data, data_len);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
** Memory malloc and release
|
||||
************************************************************************************/
|
||||
@@ -1266,6 +1303,13 @@ void btc_hf_call_handler(btc_msg_t *msg)
|
||||
btc_hf_reg_data_cb(arg->reg_data_cb.recv, arg->reg_data_cb.send);
|
||||
break;
|
||||
}
|
||||
|
||||
case BTC_HF_REGISTER_AUDIO_DATA_CALLBACK_EVT:
|
||||
{
|
||||
btc_hf_reg_audio_data_cb(arg->reg_audio_data_cb.callback);
|
||||
break;
|
||||
}
|
||||
|
||||
case BTC_HF_REQUEST_PKT_STAT_EVT:
|
||||
{
|
||||
btc_hf_pkt_stat_nums_get(arg->pkt_sync_hd.sync_conn_handle);
|
||||
@@ -1411,7 +1455,9 @@ void btc_hf_cb_handler(btc_msg_t *msg)
|
||||
do {
|
||||
param.audio_stat.state = ESP_HF_AUDIO_STATE_CONNECTED;
|
||||
memcpy(param.audio_stat.remote_addr, &hf_local_param[idx].btc_hf_cb.connected_bda,sizeof(esp_bd_addr_t));
|
||||
hf_local_param[idx].btc_hf_cb.sync_conn_hdl = p_data->hdr.sync_conn_handle;
|
||||
param.audio_stat.sync_conn_handle = p_data->hdr.sync_conn_handle;
|
||||
param.audio_stat.preferred_frame_size = p_data->audio_stat.preferred_frame_size;
|
||||
btc_hf_cb_to_app(ESP_HF_AUDIO_STATE_EVT, ¶m);
|
||||
} while(0);
|
||||
break;
|
||||
@@ -1424,7 +1470,9 @@ void btc_hf_cb_handler(btc_msg_t *msg)
|
||||
do {
|
||||
param.audio_stat.state = ESP_HF_AUDIO_STATE_CONNECTED_MSBC;
|
||||
memcpy(param.audio_stat.remote_addr, &hf_local_param[idx].btc_hf_cb.connected_bda,sizeof(esp_bd_addr_t));
|
||||
hf_local_param[idx].btc_hf_cb.sync_conn_hdl = p_data->hdr.sync_conn_handle;
|
||||
param.audio_stat.sync_conn_handle = p_data->hdr.sync_conn_handle;
|
||||
param.audio_stat.preferred_frame_size = p_data->audio_stat.preferred_frame_size;
|
||||
btc_hf_cb_to_app(ESP_HF_AUDIO_STATE_EVT, ¶m);
|
||||
} while (0);
|
||||
break;
|
||||
@@ -1435,6 +1483,7 @@ void btc_hf_cb_handler(btc_msg_t *msg)
|
||||
CHECK_HF_IDX(idx);
|
||||
do {
|
||||
param.audio_stat.state = ESP_HF_AUDIO_STATE_DISCONNECTED;
|
||||
hf_local_param[idx].btc_hf_cb.sync_conn_hdl = 0;
|
||||
memcpy(param.audio_stat.remote_addr, &hf_local_param[idx].btc_hf_cb.connected_bda, sizeof(esp_bd_addr_t));
|
||||
param.audio_stat.sync_conn_handle = p_data->hdr.sync_conn_handle;
|
||||
btc_hf_cb_to_app(ESP_HF_AUDIO_STATE_EVT, ¶m);
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -14,9 +14,23 @@
|
||||
|
||||
#if (BTM_SCO_HCI_INCLUDED == TRUE)
|
||||
|
||||
#if (BTC_HFP_EXT_CODEC == FALSE)
|
||||
#include "oi_codec_sbc.h"
|
||||
#include "oi_status.h"
|
||||
#include "sbc_encoder.h"
|
||||
#endif
|
||||
|
||||
// H2: Header with synchronization word and sequence number
|
||||
#define BTA_HF_H2_HEADER_SYNC_WORD 0x0801
|
||||
#define BTA_HF_H2_HEADER_SYNC_WORD_MASK 0x0FFF
|
||||
#define BTA_HF_H2_HEADER_BIT0_MASK (1 << 0)
|
||||
#define BTA_HF_H2_HEADER_BIT1_MASK (1 << 1)
|
||||
#define BTA_HF_H2_HEADER_SN0_BIT_OFFSET1 12
|
||||
#define BTA_HF_H2_HEADER_SN0_BIT_OFFSET2 13
|
||||
#define BTA_HF_H2_HEADER_SN1_BIT_OFFSET1 14
|
||||
#define BTA_HF_H2_HEADER_SN1_BIT_OFFSET2 15
|
||||
|
||||
#define BTA_HF_H2_HEADER_SYNC_WORD_CHECK(p) ((*((uint16_t *)p) & BTA_HF_H2_HEADER_SYNC_WORD_MASK) == BTA_HF_H2_HEADER_SYNC_WORD)
|
||||
|
||||
#if (PLC_INCLUDED == TRUE)
|
||||
#include "sbc_plc.h"
|
||||
@@ -44,18 +58,23 @@ static bta_hf_ct_plc_t *bta_hf_ct_plc_ptr;
|
||||
/* BTA-HF-CO control block to map bdaddr to BTA handle */
|
||||
typedef struct
|
||||
{
|
||||
#if (BTC_HFP_EXT_CODEC == FALSE)
|
||||
OI_CODEC_SBC_DECODER_CONTEXT decoder_context;
|
||||
OI_UINT32 decoder_context_data[HF_SBC_DEC_CONTEXT_DATA_LEN];
|
||||
OI_INT16 decode_raw_data[HF_SBC_DEC_RAW_DATA_SIZE];
|
||||
|
||||
SBC_ENC_PARAMS encoder;
|
||||
|
||||
UINT8 sequence_number;
|
||||
bool is_bad_frame;
|
||||
bool decode_first_pkt;
|
||||
OI_BYTE decode_msbc_data[BTM_MSBC_FRAME_SIZE];
|
||||
bool encode_first_pkt;
|
||||
OI_BYTE decode_msbc_data[BTM_MSBC_FRAME_SIZE];
|
||||
OI_BYTE encode_msbc_data[BTM_MSBC_FRAME_SIZE];
|
||||
#else
|
||||
UINT8 sequence_number;
|
||||
BOOLEAN rx_first_pkt;
|
||||
BOOLEAN is_bad_frame;
|
||||
UINT8 rx_half_msbc_data[BTM_MSBC_FRAME_SIZE/2];
|
||||
#endif
|
||||
} bta_hf_client_co_cb_t;
|
||||
|
||||
#if HFP_DYNAMIC_MEMORY == FALSE
|
||||
@@ -118,6 +137,8 @@ tBTA_HFP_SCO_ROUTE_TYPE bta_hf_client_sco_co_init(UINT32 rx_bw, UINT32 tx_bw,
|
||||
return BTA_HFP_SCO_ROUTE_HCI;
|
||||
}
|
||||
|
||||
#if (BTC_HFP_EXT_CODEC == FALSE)
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function bta_hf_dec_init
|
||||
@@ -168,6 +189,19 @@ static void bta_hf_enc_init(void) {
|
||||
SBC_Encoder_Init(&(bta_hf_client_co_cb.encoder));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if (BTC_HFP_EXT_CODEC == TRUE)
|
||||
|
||||
void bta_hf_pkt_state_reset(void)
|
||||
{
|
||||
bta_hf_client_co_cb.sequence_number = 0;
|
||||
bta_hf_client_co_cb.rx_first_pkt = TRUE;
|
||||
bta_hf_client_co_cb.is_bad_frame = FALSE;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function bta_hf_client_sco_co_open
|
||||
@@ -204,8 +238,12 @@ void bta_hf_client_sco_co_open(UINT16 handle, UINT8 air_mode, UINT8 inout_pkt_si
|
||||
|
||||
#endif /// (HFP_DYNAMIC_MEMORY == TRUE)
|
||||
|
||||
#if (BTC_HFP_EXT_CODEC == TRUE)
|
||||
bta_hf_pkt_state_reset();
|
||||
#else
|
||||
bta_hf_dec_init();
|
||||
bta_hf_enc_init();
|
||||
#endif
|
||||
|
||||
return;
|
||||
} else {
|
||||
@@ -280,18 +318,9 @@ void bta_hf_client_sco_co_close(void)
|
||||
** Returns void
|
||||
**
|
||||
*******************************************************************************/
|
||||
static void bta_hf_client_h2_header(UINT16 *p_buf)
|
||||
void bta_hf_client_h2_header(UINT16 *p_buf)
|
||||
{
|
||||
// H2: Header with synchronization word and sequence number
|
||||
#define BTA_HF_H2_HEADER 0x0801
|
||||
#define BTA_HF_H2_HEADER_BIT0_MASK (1 << 0)
|
||||
#define BTA_HF_H2_HEADER_BIT1_MASK (1 << 1)
|
||||
#define BTA_HF_H2_HEADER_SN0_BIT_OFFSET1 12
|
||||
#define BTA_HF_H2_HEADER_SN0_BIT_OFFSET2 13
|
||||
#define BTA_HF_H2_HEADER_SN1_BIT_OFFSET1 14
|
||||
#define BTA_HF_H2_HEADER_SN1_BIT_OFFSET2 15
|
||||
|
||||
UINT16 h2_header = BTA_HF_H2_HEADER;
|
||||
UINT16 h2_header = BTA_HF_H2_HEADER_SYNC_WORD;
|
||||
UINT8 h2_header_sn0 = bta_hf_client_co_cb.sequence_number & BTA_HF_H2_HEADER_BIT0_MASK;
|
||||
UINT8 h2_header_sn1 = bta_hf_client_co_cb.sequence_number & BTA_HF_H2_HEADER_BIT1_MASK;
|
||||
h2_header |= (h2_header_sn0 << BTA_HF_H2_HEADER_SN0_BIT_OFFSET1
|
||||
@@ -304,6 +333,8 @@ static void bta_hf_client_h2_header(UINT16 *p_buf)
|
||||
*p_buf = h2_header;
|
||||
}
|
||||
|
||||
#if (BTC_HFP_EXT_CODEC == FALSE)
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function bta_hf_client_sco_co_out_data
|
||||
@@ -364,7 +395,7 @@ uint32_t bta_hf_client_sco_co_out_data(UINT8 *p_buf)
|
||||
|
||||
|
||||
} else {
|
||||
APPL_TRACE_ERROR("%s invaild air mode: %d", __FUNCTION__, hf_air_mode);
|
||||
APPL_TRACE_ERROR("%s invalid air mode: %d", __FUNCTION__, hf_air_mode);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -439,6 +470,8 @@ static void bta_hf_client_decode_msbc_frame(UINT8 **data, UINT8 *length, BOOLEAN
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function bta_hf_client_sco_co_in_data
|
||||
@@ -450,12 +483,77 @@ static void bta_hf_client_decode_msbc_frame(UINT8 **data, UINT8 *length, BOOLEAN
|
||||
*******************************************************************************/
|
||||
void bta_hf_client_sco_co_in_data(BT_HDR *p_buf, tBTM_SCO_DATA_FLAG status)
|
||||
{
|
||||
if (hf_air_mode != BTM_SCO_AIR_MODE_CVSD && hf_air_mode != BTM_SCO_AIR_MODE_TRANSPNT) {
|
||||
APPL_TRACE_ERROR("%s invalid air mode: %d", __FUNCTION__, hf_air_mode);
|
||||
osi_free(p_buf);
|
||||
return;
|
||||
}
|
||||
|
||||
UINT8 *p = (UINT8 *)(p_buf + 1) + p_buf->offset;
|
||||
UINT8 pkt_size = 0;
|
||||
|
||||
STREAM_SKIP_UINT16(p);
|
||||
STREAM_TO_UINT8 (pkt_size, p);
|
||||
|
||||
#if (BTC_HFP_EXT_CODEC == TRUE)
|
||||
if (hf_air_mode == BTM_SCO_AIR_MODE_CVSD) {
|
||||
btc_hf_client_audio_data_cb_to_app((uint8_t *)p_buf, (uint8_t *)p, pkt_size, status != BTM_SCO_DATA_CORRECT);
|
||||
}
|
||||
else if (hf_air_mode == BTM_SCO_AIR_MODE_TRANSPNT) {
|
||||
if (pkt_size != hf_inout_pkt_size) {
|
||||
bta_hf_client_co_cb.is_bad_frame = true;
|
||||
}
|
||||
if (status != BTM_SCO_DATA_CORRECT) {
|
||||
bta_hf_client_co_cb.is_bad_frame = true;
|
||||
}
|
||||
if (hf_inout_pkt_size == BTM_MSBC_FRAME_SIZE / 2) {
|
||||
if (pkt_size > BTM_MSBC_FRAME_SIZE / 2) {
|
||||
pkt_size = BTM_MSBC_FRAME_SIZE / 2;
|
||||
}
|
||||
if (bta_hf_client_co_cb.rx_first_pkt){
|
||||
memcpy(bta_hf_client_co_cb.rx_half_msbc_data, p, pkt_size);
|
||||
osi_free(p_buf);
|
||||
} else {
|
||||
BT_HDR *p_new_buf = osi_calloc(sizeof(BT_HDR) + BTM_MSBC_FRAME_SIZE);
|
||||
p_new_buf->offset = 0;
|
||||
UINT8 *p_data = (UINT8 *)(p_new_buf + 1) + p_new_buf->offset;
|
||||
memcpy(p_data, bta_hf_client_co_cb.rx_half_msbc_data, BTM_MSBC_FRAME_SIZE / 2);
|
||||
memcpy(p_data + BTM_MSBC_FRAME_SIZE / 2, p, pkt_size);
|
||||
osi_free(p_buf);
|
||||
if (BTA_HF_H2_HEADER_SYNC_WORD_CHECK(p_data)) {
|
||||
/* H2 header sync word found, skip */
|
||||
p_data += 2;
|
||||
}
|
||||
else if (!bta_hf_client_co_cb.is_bad_frame){
|
||||
/* not a bad frame, assume as H1 header */
|
||||
p_data += 1;
|
||||
}
|
||||
btc_hf_client_audio_data_cb_to_app((uint8_t *)p_new_buf, (uint8_t *)p_data, BTM_MSBC_FRAME_SIZE, bta_hf_client_co_cb.is_bad_frame);
|
||||
bta_hf_client_co_cb.is_bad_frame = false;
|
||||
memset(bta_hf_client_co_cb.rx_half_msbc_data, 0, BTM_MSBC_FRAME_SIZE);
|
||||
}
|
||||
bta_hf_client_co_cb.rx_first_pkt = !bta_hf_client_co_cb.rx_first_pkt;
|
||||
}
|
||||
else if (hf_inout_pkt_size == BTM_MSBC_FRAME_SIZE) {
|
||||
if (pkt_size > BTM_MSBC_FRAME_SIZE) {
|
||||
pkt_size = BTM_MSBC_FRAME_SIZE;
|
||||
}
|
||||
if (BTA_HF_H2_HEADER_SYNC_WORD_CHECK(p)) {
|
||||
/* H2 header sync word found, skip */
|
||||
p += 2;
|
||||
}
|
||||
else if (!bta_hf_client_co_cb.is_bad_frame){
|
||||
/* not a bad frame, assume as H1 header */
|
||||
p += 1;
|
||||
}
|
||||
btc_hf_client_audio_data_cb_to_app((uint8_t *)p_buf, (uint8_t *)p, pkt_size, bta_hf_client_co_cb.is_bad_frame);
|
||||
bta_hf_client_co_cb.is_bad_frame = false;
|
||||
}
|
||||
else {
|
||||
osi_free(p_buf);
|
||||
}
|
||||
}
|
||||
#else
|
||||
if (hf_air_mode == BTM_SCO_AIR_MODE_CVSD) {
|
||||
// CVSD
|
||||
if(status != BTM_SCO_DATA_CORRECT){
|
||||
@@ -496,8 +594,10 @@ void bta_hf_client_sco_co_in_data(BT_HDR *p_buf, tBTM_SCO_DATA_FLAG status)
|
||||
//Never run to here.
|
||||
}
|
||||
} else {
|
||||
APPL_TRACE_ERROR("%s invaild air mode: %d", __FUNCTION__, hf_air_mode);
|
||||
APPL_TRACE_ERROR("%s invalid air mode: %d", __FUNCTION__, hf_air_mode);
|
||||
}
|
||||
osi_free(p_buf);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* #if (BTM_SCO_HCI_INCLUDED == TRUE) */
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -132,6 +132,26 @@ void btc_hf_client_reg_data_cb(esp_hf_client_incoming_data_cb_t recv,
|
||||
hf_client_local_param.btc_hf_client_outgoing_data_cb = send;
|
||||
}
|
||||
|
||||
static void btc_hf_client_reg_audio_data_cb(esp_hf_client_audio_data_cb_t callback)
|
||||
{
|
||||
hf_client_local_param.btc_hf_client_audio_data_cb = callback;
|
||||
}
|
||||
|
||||
void btc_hf_client_audio_data_cb_to_app(uint8_t *buf, uint8_t *data, uint16_t len, bool is_bad_frame)
|
||||
{
|
||||
if (hf_client_local_param.btc_hf_client_audio_data_cb) {
|
||||
/* we always have sizeof(BT_HDR) bytes free space before data, it is enough for esp_hf_audio_buff_t */
|
||||
esp_hf_audio_buff_t *audio_buff = (esp_hf_audio_buff_t *)buf;
|
||||
audio_buff->buff_size = len;
|
||||
audio_buff->data_len = len;
|
||||
audio_buff->data = data;
|
||||
hf_client_local_param.btc_hf_client_audio_data_cb(hf_client_local_param.btc_hf_client_cb.sync_conn_hdl, audio_buff, is_bad_frame);
|
||||
}
|
||||
else {
|
||||
osi_free(buf);
|
||||
}
|
||||
}
|
||||
|
||||
void btc_hf_client_incoming_data_cb_to_app(const uint8_t *data, uint32_t len)
|
||||
{
|
||||
// todo: critical section protection
|
||||
@@ -1076,7 +1096,9 @@ void btc_hf_client_cb_handler(btc_msg_t *msg)
|
||||
param.audio_stat.state = ESP_HF_CLIENT_AUDIO_STATE_CONNECTED;
|
||||
memcpy(param.audio_stat.remote_bda, &hf_client_local_param.btc_hf_client_cb.connected_bda,
|
||||
sizeof(esp_bd_addr_t));
|
||||
hf_client_local_param.btc_hf_client_cb.sync_conn_hdl = p_data->hdr.sync_conn_handle;
|
||||
param.audio_stat.sync_conn_handle = p_data->hdr.sync_conn_handle;
|
||||
param.audio_stat.preferred_frame_size = p_data->audio_stat.preferred_frame_size;
|
||||
btc_hf_client_cb_to_app(ESP_HF_CLIENT_AUDIO_STATE_EVT, ¶m);
|
||||
} while (0);
|
||||
break;
|
||||
@@ -1085,7 +1107,9 @@ void btc_hf_client_cb_handler(btc_msg_t *msg)
|
||||
param.audio_stat.state = ESP_HF_CLIENT_AUDIO_STATE_CONNECTED_MSBC;
|
||||
memcpy(param.audio_stat.remote_bda, &hf_client_local_param.btc_hf_client_cb.connected_bda,
|
||||
sizeof(esp_bd_addr_t));
|
||||
hf_client_local_param.btc_hf_client_cb.sync_conn_hdl = p_data->hdr.sync_conn_handle;
|
||||
param.audio_stat.sync_conn_handle = p_data->hdr.sync_conn_handle;
|
||||
param.audio_stat.preferred_frame_size = p_data->audio_stat.preferred_frame_size;
|
||||
btc_hf_client_cb_to_app(ESP_HF_CLIENT_AUDIO_STATE_EVT, ¶m);
|
||||
} while (0);
|
||||
break;
|
||||
@@ -1094,7 +1118,9 @@ void btc_hf_client_cb_handler(btc_msg_t *msg)
|
||||
param.audio_stat.state = ESP_HF_CLIENT_AUDIO_STATE_DISCONNECTED;
|
||||
memcpy(param.audio_stat.remote_bda, &hf_client_local_param.btc_hf_client_cb.connected_bda,
|
||||
sizeof(esp_bd_addr_t));
|
||||
hf_client_local_param.btc_hf_client_cb.sync_conn_hdl = 0;
|
||||
param.audio_stat.sync_conn_handle = p_data->hdr.sync_conn_handle;
|
||||
param.audio_stat.preferred_frame_size = 0;
|
||||
btc_hf_client_cb_to_app(ESP_HF_CLIENT_AUDIO_STATE_EVT, ¶m);
|
||||
} while (0);
|
||||
break;
|
||||
@@ -1183,6 +1209,9 @@ void btc_hf_client_call_handler(btc_msg_t *msg)
|
||||
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;
|
||||
case BTC_HF_CLIENT_REGISTER_AUDIO_DATA_CALLBACK_EVT:
|
||||
btc_hf_client_reg_audio_data_cb(arg->reg_audio_data_cb.callback);
|
||||
break;
|
||||
case BTC_HF_CLIENT_SEND_NREC_EVT:
|
||||
btc_hf_client_send_nrec();
|
||||
break;
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -23,6 +23,7 @@
|
||||
/*******************************************************************************
|
||||
** Data types
|
||||
*******************************************************************************/
|
||||
#if (BTC_AV_EXT_CODEC == FALSE)
|
||||
|
||||
/* tBTC_MEDIA_INIT_AUDIO msg structure */
|
||||
typedef struct {
|
||||
@@ -50,6 +51,8 @@ typedef struct {
|
||||
tBTC_AV_MEDIA_FEEDINGS feeding;
|
||||
} tBTC_MEDIA_INIT_AUDIO_FEEDING;
|
||||
|
||||
#endif
|
||||
|
||||
/*******************************************************************************
|
||||
** Public functions
|
||||
*******************************************************************************/
|
||||
@@ -76,29 +79,6 @@ bool btc_a2dp_source_startup(void);
|
||||
*******************************************************************************/
|
||||
void btc_a2dp_source_shutdown(void);
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function btc_a2dp_source_enc_init_req
|
||||
**
|
||||
** Description Request to initialize the media task encoder
|
||||
**
|
||||
** Returns TRUE is success
|
||||
**
|
||||
*******************************************************************************/
|
||||
BOOLEAN btc_a2dp_source_enc_init_req(tBTC_MEDIA_INIT_AUDIO *p_msg);
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function btc_a2dp_source_enc_udpate_req
|
||||
**
|
||||
** Description Request to update the media task encoder
|
||||
**
|
||||
** Returns TRUE is success
|
||||
**
|
||||
*******************************************************************************/
|
||||
BOOLEAN btc_a2dp_source_enc_update_req(tBTC_MEDIA_UPDATE_AUDIO *p_msg);
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function btc_a2dp_source_start_audio_req
|
||||
@@ -110,28 +90,6 @@ BOOLEAN btc_a2dp_source_enc_update_req(tBTC_MEDIA_UPDATE_AUDIO *p_msg);
|
||||
*******************************************************************************/
|
||||
BOOLEAN btc_a2dp_source_start_audio_req(void);
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function btc_a2dp_source_stop_audio_req
|
||||
**
|
||||
** Description Request to stop audio encoding task
|
||||
**
|
||||
** Returns TRUE is success
|
||||
**
|
||||
*******************************************************************************/
|
||||
BOOLEAN btc_a2dp_source_stop_audio_req(void);
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function btc_a2dp_source_tx_flush_req
|
||||
**
|
||||
** Description Request to flush audio encoding pipe
|
||||
**
|
||||
** Returns TRUE is success
|
||||
**
|
||||
*******************************************************************************/
|
||||
BOOLEAN btc_a2dp_source_tx_flush_req(void);
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function btc_a2dp_source_audio_readbuf
|
||||
@@ -143,27 +101,6 @@ BOOLEAN btc_a2dp_source_tx_flush_req(void);
|
||||
*******************************************************************************/
|
||||
BT_HDR *btc_a2dp_source_audio_readbuf(void);
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function btc_a2dp_source_audio_feeding_init_req
|
||||
**
|
||||
** Description Request to initialize audio feeding
|
||||
**
|
||||
** Returns TRUE if success
|
||||
**
|
||||
*******************************************************************************/
|
||||
|
||||
BOOLEAN btc_a2dp_source_audio_feeding_init_req(tBTC_MEDIA_INIT_AUDIO_FEEDING *p_msg);
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function btc_a2dp_source_is_streaming
|
||||
**
|
||||
** Description Check whether A2DP source is in streaming state
|
||||
**
|
||||
*******************************************************************************/
|
||||
bool btc_a2dp_source_is_streaming(void);
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function btc_a2dp_source_is_task_shutting_down
|
||||
@@ -204,15 +141,6 @@ void btc_a2dp_source_on_stopped(tBTA_AV_SUSPEND *p_av);
|
||||
*******************************************************************************/
|
||||
void btc_a2dp_source_on_suspended(tBTA_AV_SUSPEND *p_av);
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function btc_a2dp_source_setup_codec
|
||||
**
|
||||
** Description initialize the encoder parameters
|
||||
**
|
||||
*******************************************************************************/
|
||||
void btc_a2dp_source_setup_codec(void);
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function btc_a2dp_source_set_tx_flush
|
||||
@@ -222,6 +150,17 @@ void btc_a2dp_source_setup_codec(void);
|
||||
*******************************************************************************/
|
||||
void btc_a2dp_source_set_tx_flush(BOOLEAN enable);
|
||||
|
||||
#if (BTC_AV_EXT_CODEC == FALSE)
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function btc_a2dp_source_setup_codec
|
||||
**
|
||||
** Description initialize the encoder parameters
|
||||
**
|
||||
*******************************************************************************/
|
||||
void btc_a2dp_source_setup_codec(void);
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function btc_a2dp_source_encoder_update
|
||||
@@ -231,6 +170,8 @@ void btc_a2dp_source_set_tx_flush(BOOLEAN enable);
|
||||
*******************************************************************************/
|
||||
void btc_a2dp_source_encoder_update(void);
|
||||
|
||||
#endif
|
||||
|
||||
/*****************************************************************************
|
||||
**
|
||||
** Function btc_source_report_delay_value
|
||||
@@ -240,6 +181,19 @@ void btc_a2dp_source_encoder_update(void);
|
||||
*******************************************************************************/
|
||||
void btc_source_report_delay_value(UINT16 delay_value);
|
||||
|
||||
#if (BTC_AV_EXT_CODEC == TRUE)
|
||||
|
||||
/*****************************************************************************
|
||||
**
|
||||
** Function btc_a2dp_source_enqueue_audio_frame
|
||||
**
|
||||
** Description Enqueue source audio frame to tx queue
|
||||
**
|
||||
*******************************************************************************/
|
||||
BOOLEAN btc_a2dp_source_enqueue_audio_frame(BT_HDR *p_buf);
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* #if BTC_AV_SRC_INCLUDED */
|
||||
|
||||
#endif /* __BTC_A2DP_SOURCE_H__ */
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -22,11 +22,21 @@
|
||||
#include "btc/btc_task.h"
|
||||
#include "btc/btc_common.h"
|
||||
#include "btc/btc_sm.h"
|
||||
#include "btc_av_api.h"
|
||||
#include "bta/bta_av_api.h"
|
||||
#include "bta/bta_av_sbc.h"
|
||||
|
||||
#if (BTC_AV_INCLUDED == TRUE)
|
||||
|
||||
// global variable to inidcate avrc is initialized with a2dp
|
||||
#if (BTA_AV_CO_CP_SCMS_T == TRUE)
|
||||
#define BTC_MEDIA_AA_SBC_OFFSET (AVDT_MEDIA_OFFSET + BTA_AV_SBC_HDR_SIZE + 1)
|
||||
#else
|
||||
#define BTC_MEDIA_AA_SBC_OFFSET (AVDT_MEDIA_OFFSET + BTA_AV_SBC_HDR_SIZE)
|
||||
#endif
|
||||
|
||||
#define BTC_AUDIO_BUFF_OFFSET BTC_MEDIA_AA_SBC_OFFSET
|
||||
|
||||
// global variable to indicate avrc is initialized with a2dp
|
||||
extern bool g_av_with_rc;
|
||||
// global variable to indicate a2dp is initialized
|
||||
extern bool g_a2dp_on_init;
|
||||
@@ -51,21 +61,24 @@ typedef enum {
|
||||
BTC_AV_DISCONNECT_REQ_EVT,
|
||||
BTC_AV_START_STREAM_REQ_EVT,
|
||||
BTC_AV_SUSPEND_STREAM_REQ_EVT,
|
||||
BTC_AV_SINK_CONFIG_REQ_EVT,
|
||||
BTC_AV_CONFIG_EVT,
|
||||
} btc_av_sm_event_t;
|
||||
|
||||
typedef enum {
|
||||
#if BTC_AV_SINK_INCLUDED
|
||||
BTC_AV_SINK_API_INIT_EVT = 0,
|
||||
BTC_AV_SINK_API_REG_SEP_EVT,
|
||||
BTC_AV_SINK_API_DEINIT_EVT,
|
||||
BTC_AV_SINK_API_CONNECT_EVT,
|
||||
BTC_AV_SINK_API_DISCONNECT_EVT,
|
||||
BTC_AV_SINK_API_REG_DATA_CB_EVT,
|
||||
BTC_AV_SINK_API_REG_AUDIO_DATA_CB_EVT,
|
||||
BTC_AV_SINK_API_SET_DELAY_VALUE_EVT,
|
||||
BTC_AV_SINK_API_GET_DELAY_VALUE_EVT,
|
||||
#endif /* BTC_AV_SINK_INCLUDED */
|
||||
#if BTC_AV_SRC_INCLUDED
|
||||
BTC_AV_SRC_API_INIT_EVT,
|
||||
BTC_AV_SRC_API_REG_SEP_EVT,
|
||||
BTC_AV_SRC_API_DEINIT_EVT,
|
||||
BTC_AV_SRC_API_CONNECT_EVT,
|
||||
BTC_AV_SRC_API_DISCONNECT_EVT,
|
||||
@@ -77,14 +90,14 @@ typedef enum {
|
||||
/* btc_av_args_t */
|
||||
typedef union {
|
||||
#if BTC_AV_SINK_INCLUDED
|
||||
// BTC_AV_SINK_CONFIG_REQ_EVT -- internal event
|
||||
esp_a2d_mcc_t mcc;
|
||||
// BTC_AV_SINK_API_CONNECT_EVT
|
||||
bt_bdaddr_t connect;
|
||||
// BTC_AV_SINK_API_DISCONNECT_EVT
|
||||
bt_bdaddr_t disconn;
|
||||
// BTC_AV_SINK_API_REG_DATA_CB_EVT
|
||||
esp_a2d_sink_data_cb_t data_cb;
|
||||
// BTC_AV_SINK_API_REG_AUDIO_DATA_CB_EVT
|
||||
esp_a2d_sink_audio_data_cb_t audio_data_cb;
|
||||
// BTC_AV_SINK_API_SET_DELAY_VALUE_EVT
|
||||
uint16_t delay_value;
|
||||
#endif /* BTC_AV_SINK_INCLUDED */
|
||||
@@ -96,6 +109,13 @@ typedef union {
|
||||
// BTC_AV_SRC_API_DISCONNECT_EVT
|
||||
bt_bdaddr_t src_disconn;
|
||||
#endif /* BTC_AV_SRC_INCLUDED */
|
||||
// BTC_AV_CONFIG_EVT
|
||||
esp_a2d_mcc_t mcc;
|
||||
// BTC_AV_SINK_API_REG_SEP_EVT or BTC_AV_SRC_API_REG_SEP_EVT
|
||||
struct {
|
||||
uint8_t seid;
|
||||
esp_a2d_mcc_t mcc;
|
||||
} reg_sep;
|
||||
// BTC_AV_API_MEDIA_CTRL_EVT
|
||||
esp_a2d_media_ctrl_t ctrl;
|
||||
} btc_av_args_t;
|
||||
@@ -110,6 +130,32 @@ void btc_a2dp_cb_handler(btc_msg_t *msg);
|
||||
|
||||
void btc_a2dp_sink_reg_data_cb(esp_a2d_sink_data_cb_t callback);
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function btc_a2dp_sink_reg_audio_data_cb
|
||||
**
|
||||
** Description Register a2dp sink audio data callback
|
||||
**
|
||||
** Returns None
|
||||
**
|
||||
*******************************************************************************/
|
||||
void btc_a2dp_sink_reg_audio_data_cb(esp_a2d_sink_audio_data_cb_t callback);
|
||||
|
||||
#if (BTC_AV_EXT_CODEC == TRUE)
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function btc_av_codec_cap_get
|
||||
**
|
||||
** Description Get external codec capability
|
||||
**
|
||||
** Returns Pointer to codec capability
|
||||
**
|
||||
*******************************************************************************/
|
||||
tBTC_AV_CODEC_INFO *btc_av_codec_cap_get(void);
|
||||
|
||||
#endif
|
||||
|
||||
void btc_a2dp_src_reg_data_cb(esp_a2d_source_data_cb_t callback);
|
||||
/*******************************************************************************
|
||||
**
|
||||
@@ -172,6 +218,16 @@ void btc_dispatch_sm_event(btc_av_sm_event_t event, void *p_data, int len);
|
||||
|
||||
BOOLEAN btc_av_is_connected(void);
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function btc_av_is_started
|
||||
**
|
||||
** Description Checks if av is started
|
||||
**
|
||||
** Returns BOOLEAN
|
||||
**
|
||||
*******************************************************************************/
|
||||
BOOLEAN btc_av_is_started(void);
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
@@ -225,4 +281,60 @@ uint8_t btc_av_get_service_id(void);
|
||||
|
||||
#endif ///BTC_AV_INCLUDED == TRUE
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function btc_a2d_conn_handle_get
|
||||
**
|
||||
** Description Get connection handle from btc_av_cb
|
||||
**
|
||||
** Returns Void
|
||||
**
|
||||
*******************************************************************************/
|
||||
uint16_t btc_a2d_conn_handle_get(void);
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function btc_av_audio_buff_alloc
|
||||
**
|
||||
** Description Allocate audio buffer with specific size
|
||||
**
|
||||
** Returns Void
|
||||
**
|
||||
*******************************************************************************/
|
||||
void btc_av_audio_buff_alloc(uint16_t size, uint8_t **pp_buff, uint8_t **pp_data);
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function btc_av_audio_buff_free
|
||||
**
|
||||
** Description Free audio buffer
|
||||
**
|
||||
** Returns Void
|
||||
**
|
||||
*******************************************************************************/
|
||||
void btc_av_audio_buff_free(uint8_t *p_buf);
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function btc_a2d_src_audio_mtu_check
|
||||
**
|
||||
** Description Checks if data length is valid, not bigger than mtu
|
||||
**
|
||||
** Returns BOOLEAN
|
||||
**
|
||||
*******************************************************************************/
|
||||
BOOLEAN btc_a2d_src_audio_mtu_check(uint16_t data_len);
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function btc_a2d_src_audio_data_send
|
||||
**
|
||||
** Description Send audio data to lower layer, audio buffer is consumed
|
||||
** only when operation is success
|
||||
**
|
||||
** Returns BT_STATUS_SUCCESS if success, otherwise, BT_STATUS_FAIL
|
||||
**
|
||||
*******************************************************************************/
|
||||
bt_status_t btc_a2d_src_audio_data_send(esp_a2d_conn_hdl_t conn_hdl, esp_a2d_audio_buff_t *audio_buf);
|
||||
|
||||
#endif /* __BTC_AV_H__ */
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -57,6 +57,7 @@ typedef enum
|
||||
BTC_HF_END_CALL_EVT,
|
||||
//REG
|
||||
BTC_HF_REGISTER_DATA_CALLBACK_EVT,
|
||||
BTC_HF_REGISTER_AUDIO_DATA_CALLBACK_EVT,
|
||||
BTC_HF_REQUEST_PKT_STAT_EVT
|
||||
} btc_hf_act_t;
|
||||
|
||||
@@ -189,6 +190,11 @@ typedef union
|
||||
esp_hf_outgoing_data_cb_t send;
|
||||
} reg_data_cb;
|
||||
|
||||
// BTC_HF_REGISTER_AUDIO_DATA_CALLBACK_EVT
|
||||
struct ag_reg_audio_data_callback {
|
||||
esp_hf_ag_audio_data_cb_t callback;
|
||||
} reg_audio_data_cb;
|
||||
|
||||
// BTC_HF_REQUEST_PKT_STAT_EVT
|
||||
struct ag_req_pkt_stat_sync_handle {
|
||||
UINT16 sync_conn_handle;
|
||||
@@ -211,6 +217,7 @@ typedef struct
|
||||
{
|
||||
bool initialized;
|
||||
UINT16 handle;
|
||||
UINT16 sync_conn_hdl;
|
||||
bt_bdaddr_t connected_bda;
|
||||
tBTA_AG_PEER_FEAT peer_feat;
|
||||
tBTA_AG_CHLD_FEAT chld_feat;
|
||||
@@ -231,6 +238,7 @@ typedef struct
|
||||
btc_hf_cb_t btc_hf_cb;
|
||||
esp_hf_incoming_data_cb_t btc_hf_incoming_data_cb;
|
||||
esp_hf_outgoing_data_cb_t btc_hf_outgoing_data_cb;
|
||||
esp_hf_ag_audio_data_cb_t btc_hf_audio_data_cb;
|
||||
} hf_local_param_t;
|
||||
|
||||
#if HFP_DYNAMIC_MEMORY == TRUE
|
||||
@@ -247,6 +255,8 @@ void btc_hf_cb_handler(btc_msg_t *msg); //handle the event from bta
|
||||
|
||||
void btc_hf_incoming_data_cb_to_app(const uint8_t *data, uint32_t len);
|
||||
|
||||
void btc_hf_audio_data_cb_to_app(uint8_t *buf, uint8_t *data, uint16_t len, bool is_bad_frame);
|
||||
|
||||
uint32_t btc_hf_outgoing_data_cb_to_app(uint8_t *data, uint32_t len);
|
||||
|
||||
void btc_hf_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src);
|
||||
@@ -255,6 +265,8 @@ void btc_hf_arg_deep_free(btc_msg_t *msg);
|
||||
|
||||
bt_status_t btc_hf_ci_sco_data(void);
|
||||
|
||||
bool btc_hf_ag_audio_data_send(uint16_t sync_conn_hdl, uint8_t *p_buff_start, uint8_t *p_data, uint8_t data_len);
|
||||
|
||||
#endif // BTC_HF_INCLUDED == TRUE
|
||||
|
||||
#endif /* __BTC_HF_AG_H__ */
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -49,6 +49,7 @@ typedef enum {
|
||||
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_REGISTER_AUDIO_DATA_CALLBACK_EVT,
|
||||
BTC_HF_CLIENT_SEND_NREC_EVT,
|
||||
BTC_HF_CLIENT_SEND_XAPL_EVT,
|
||||
BTC_HF_CLIENT_SEND_IPHONEACCEV_EVT,
|
||||
@@ -107,6 +108,11 @@ typedef union {
|
||||
esp_hf_client_outgoing_data_cb_t send;
|
||||
} reg_data_cb;
|
||||
|
||||
// BTC_HF_CLIENT_REGISTER_AUDIO_DATA_CALLBACK_EVT
|
||||
struct hf_client_reg_audio_data_callback {
|
||||
esp_hf_client_audio_data_cb_t callback;
|
||||
} reg_audio_data_cb;
|
||||
|
||||
//BTC_HF_CLIENT_SEND_XAPL_EVT
|
||||
struct send_xapl_args {
|
||||
char information[ESP_BT_HF_AT_SEND_XAPL_LEN + 1];
|
||||
@@ -134,6 +140,7 @@ typedef struct
|
||||
{
|
||||
bool initialized;
|
||||
UINT16 handle;
|
||||
UINT16 sync_conn_hdl;
|
||||
bt_bdaddr_t connected_bda;
|
||||
esp_hf_client_connection_state_t state;
|
||||
esp_hf_vr_state_t vr_state;
|
||||
@@ -147,6 +154,7 @@ typedef struct
|
||||
btc_hf_client_cb_t btc_hf_client_cb;
|
||||
esp_hf_client_incoming_data_cb_t btc_hf_client_incoming_data_cb;
|
||||
esp_hf_client_outgoing_data_cb_t btc_hf_client_outgoing_data_cb;
|
||||
esp_hf_client_audio_data_cb_t btc_hf_client_audio_data_cb;
|
||||
}hf_client_local_param_t;
|
||||
|
||||
#if HFP_DYNAMIC_MEMORY == TRUE
|
||||
@@ -162,6 +170,8 @@ void btc_hf_client_call_handler(btc_msg_t *msg);
|
||||
|
||||
void btc_hf_client_cb_handler(btc_msg_t *msg);
|
||||
|
||||
void btc_hf_client_audio_data_cb_to_app(uint8_t *buf, uint8_t *data, uint16_t len, bool is_bad_frame);
|
||||
|
||||
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);
|
||||
|
@@ -39,6 +39,12 @@
|
||||
#define UC_BT_A2DP_ENABLED FALSE
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BT_A2DP_USE_EXTERNAL_CODEC
|
||||
#define UC_BT_A2DP_USE_EXTERNAL_CODEC CONFIG_BT_A2DP_USE_EXTERNAL_CODEC
|
||||
#else
|
||||
#define UC_BT_A2DP_USE_EXTERNAL_CODEC FALSE
|
||||
#endif
|
||||
|
||||
//AVRCP
|
||||
#ifdef CONFIG_BT_AVRCP_ENABLED
|
||||
#define UC_BT_AVRCP_ENABLED TRUE
|
||||
@@ -101,6 +107,12 @@
|
||||
#define UC_BT_HFP_CLIENT_ENABLED FALSE
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BT_HFP_USE_EXTERNAL_CODEC
|
||||
#define UC_BT_HFP_USE_EXTERNAL_CODEC CONFIG_BT_HFP_USE_EXTERNAL_CODEC
|
||||
#else
|
||||
#define UC_BT_HFP_USE_EXTERNAL_CODEC FALSE
|
||||
#endif
|
||||
|
||||
//HID
|
||||
#ifdef CONFIG_BT_HID_ENABLED
|
||||
#define UC_BT_HID_ENABLED CONFIG_BT_HID_ENABLED
|
||||
|
@@ -88,9 +88,14 @@
|
||||
#define BTC_AV_INCLUDED TRUE
|
||||
#define BTA_AV_SINK_INCLUDED TRUE
|
||||
#define BTC_AV_SINK_INCLUDED TRUE
|
||||
#define SBC_DEC_INCLUDED TRUE
|
||||
#define BTC_AV_SRC_INCLUDED TRUE
|
||||
#if (UC_BT_A2DP_USE_EXTERNAL_CODEC == TRUE)
|
||||
#define BTC_AV_EXT_CODEC TRUE
|
||||
#define BTA_AV_EXT_CODEC TRUE
|
||||
#else
|
||||
#define SBC_DEC_INCLUDED TRUE
|
||||
#define SBC_ENC_INCLUDED TRUE
|
||||
#endif
|
||||
#if UC_BT_AVRCP_CT_COVER_ART_ENABLED
|
||||
#define BTA_AV_CA_INCLUDED TRUE
|
||||
#define BTC_AV_CA_INCLUDED TRUE
|
||||
@@ -122,14 +127,22 @@
|
||||
#ifndef BTM_SCO_INCLUDED
|
||||
#define BTM_SCO_INCLUDED TRUE
|
||||
#endif
|
||||
#if (UC_BT_HFP_AUDIO_DATA_PATH_HCI == TRUE)
|
||||
#if (UC_BT_HFP_USE_EXTERNAL_CODEC == TRUE)
|
||||
#define BTC_HFP_EXT_CODEC TRUE
|
||||
#define BTA_HFP_EXT_CODEC TRUE
|
||||
#define PLC_INCLUDED FALSE
|
||||
#else
|
||||
#ifndef SBC_DEC_INCLUDED
|
||||
#define SBC_DEC_INCLUDED TRUE
|
||||
#endif
|
||||
#ifndef SBC_ENC_INCLUDED
|
||||
#define SBC_ENC_INCLUDED TRUE
|
||||
#endif
|
||||
#ifndef PLC_INCLUDED
|
||||
#define PLC_INCLUDED TRUE
|
||||
#endif /* (UC_BT_HFP_USE_EXTERNAL_CODEC == TRUE) */
|
||||
#else
|
||||
#define PLC_INCLUDED FALSE
|
||||
#endif
|
||||
|
||||
#if (UC_BT_HFP_AG_ENABLED == TRUE)
|
||||
@@ -569,6 +582,10 @@
|
||||
#define BTC_AV_SRC_INCLUDED FALSE
|
||||
#endif
|
||||
|
||||
#ifndef BTC_AV_EXT_CODEC
|
||||
#define BTC_AV_EXT_CODEC FALSE
|
||||
#endif
|
||||
|
||||
#ifndef BTC_SPP_INCLUDED
|
||||
#define BTC_SPP_INCLUDED FALSE
|
||||
#endif
|
||||
@@ -593,6 +610,10 @@
|
||||
#define SBC_ENC_INCLUDED FALSE
|
||||
#endif
|
||||
|
||||
#ifndef BTC_HFP_EXT_CODEC
|
||||
#define BTC_HFP_EXT_CODEC FALSE
|
||||
#endif
|
||||
|
||||
/******************************************************************************
|
||||
**
|
||||
** BTA-layer components
|
||||
@@ -642,6 +663,10 @@
|
||||
#define BTA_AV_CA_INCLUDED FALSE
|
||||
#endif
|
||||
|
||||
#ifndef BTA_AV_EXT_CODEC
|
||||
#define BTA_AV_EXT_CODEC FALSE
|
||||
#endif
|
||||
|
||||
#ifndef BTA_AV_SINK_INCLUDED
|
||||
#define BTA_AV_SINK_INCLUDED FALSE
|
||||
#endif
|
||||
@@ -654,6 +679,10 @@
|
||||
#define BTA_SDP_INCLUDED FALSE
|
||||
#endif
|
||||
|
||||
#ifndef BTA_HFP_EXT_CODEC
|
||||
#define BTA_HFP_EXT_CODEC FALSE
|
||||
#endif
|
||||
|
||||
/* This is set to enable use of GAP L2CAP connections. */
|
||||
#ifndef VND_BT_JV_BTA_L2CAP
|
||||
#define VND_BT_JV_BTA_L2CAP FALSE
|
||||
|
@@ -264,6 +264,37 @@ UINT16 AVDT_CreateStream(UINT8 *p_handle, tAVDT_CS *p_cs)
|
||||
return result;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function AVDT_UpdateCodecInfo
|
||||
**
|
||||
** Description Update codec capability for a stream endpoint.
|
||||
**
|
||||
**
|
||||
** Returns AVDT_SUCCESS if successful, otherwise error.
|
||||
**
|
||||
*******************************************************************************/
|
||||
UINT16 AVDT_UpdateCodecInfo(UINT8 handle, UINT8 num_codec, UINT8 *codec_info, UINT16 codec_info_len)
|
||||
{
|
||||
UINT16 result = AVDT_SUCCESS;
|
||||
tAVDT_SCB *p_scb;
|
||||
|
||||
/* look up scb */
|
||||
if ((p_scb = avdt_scb_by_hdl(handle)) == NULL) {
|
||||
result = AVDT_BAD_HANDLE;
|
||||
}
|
||||
else if (num_codec != 1 || codec_info == NULL || codec_info_len != AVDT_CODEC_SIZE) {
|
||||
/* currently, only allow one codec info */
|
||||
result = AVDT_BAD_PARAMS;
|
||||
}
|
||||
else {
|
||||
/* update codec info */
|
||||
p_scb->cs.cfg.num_codec = num_codec;
|
||||
memcpy(p_scb->cs.cfg.codec_info, codec_info, codec_info_len);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function AVDT_RemoveStream
|
||||
|
@@ -30,7 +30,12 @@
|
||||
/* the length of the SBC Media Payload header. */
|
||||
#define A2D_SBC_MPL_HDR_LEN 1
|
||||
|
||||
/* the LOSC of SBC media codec capabilitiy */
|
||||
/* CIE offset in the info byte sequence */
|
||||
#define A2D_SBC_CIE_OFF 3
|
||||
/* CIE length in the info byte sequence */
|
||||
#define A2D_SBC_CIE_LEN 4
|
||||
|
||||
/* the LOSC of SBC media codec capability */
|
||||
#define A2D_SBC_INFO_LEN 6
|
||||
|
||||
/* for Codec Specific Information Element */
|
||||
|
@@ -517,6 +517,18 @@ extern void AVDT_AbortReq(UINT8 handle);
|
||||
*******************************************************************************/
|
||||
extern UINT16 AVDT_CreateStream(UINT8 *p_handle, tAVDT_CS *p_cs);
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function AVDT_UpdateCodecInfo
|
||||
**
|
||||
** Description Update codec capability for a stream endpoint.
|
||||
**
|
||||
**
|
||||
** Returns AVDT_SUCCESS if successful, otherwise error.
|
||||
**
|
||||
*******************************************************************************/
|
||||
extern UINT16 AVDT_UpdateCodecInfo(UINT8 handle, UINT8 num_codec, UINT8 *codec_info, UINT16 codec_info_len);
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function AVDT_RemoveStream
|
||||
|
@@ -61,4 +61,11 @@ menu "A2DP Example Configuration"
|
||||
help
|
||||
This enables the AVRCP Cover Art feature in example and try to get cover art image from peer device.
|
||||
|
||||
config EXAMPLE_A2DP_SINK_USE_EXTERNAL_CODEC
|
||||
bool "Use External Codec Instead of Internal"
|
||||
default n
|
||||
select BT_A2DP_USE_EXTERNAL_CODEC
|
||||
help
|
||||
If enable, Bluedroid stack will not decode A2DP audio data, user need to decode it in application layer.
|
||||
|
||||
endmenu
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
@@ -321,21 +321,21 @@ static void bt_av_hdl_a2d_evt(uint16_t event, void *p_param)
|
||||
/* when audio codec is configured, this event comes */
|
||||
case ESP_A2D_AUDIO_CFG_EVT: {
|
||||
a2d = (esp_a2d_cb_param_t *)(p_param);
|
||||
ESP_LOGI(BT_AV_TAG, "A2DP audio stream configuration, codec type: %d", a2d->audio_cfg.mcc.type);
|
||||
esp_a2d_mcc_t *p_mcc = &a2d->audio_cfg.mcc;
|
||||
ESP_LOGI(BT_AV_TAG, "A2DP audio stream configuration, codec type: %d", p_mcc->type);
|
||||
/* for now only SBC stream is supported */
|
||||
if (a2d->audio_cfg.mcc.type == ESP_A2D_MCT_SBC) {
|
||||
if (p_mcc->type == ESP_A2D_MCT_SBC) {
|
||||
int sample_rate = 16000;
|
||||
int ch_count = 2;
|
||||
char oct0 = a2d->audio_cfg.mcc.cie.sbc[0];
|
||||
if (oct0 & (0x01 << 6)) {
|
||||
if (p_mcc->cie.sbc_info.samp_freq & ESP_A2D_SBC_CIE_SF_32K) {
|
||||
sample_rate = 32000;
|
||||
} else if (oct0 & (0x01 << 5)) {
|
||||
} else if (p_mcc->cie.sbc_info.samp_freq & ESP_A2D_SBC_CIE_SF_44K) {
|
||||
sample_rate = 44100;
|
||||
} else if (oct0 & (0x01 << 4)) {
|
||||
} else if (p_mcc->cie.sbc_info.samp_freq & ESP_A2D_SBC_CIE_SF_48K) {
|
||||
sample_rate = 48000;
|
||||
}
|
||||
|
||||
if (oct0 & (0x01 << 3)) {
|
||||
if (p_mcc->cie.sbc_info.ch_mode & ESP_A2D_SBC_CIE_CH_MODE_MONO) {
|
||||
ch_count = 1;
|
||||
}
|
||||
#ifdef CONFIG_EXAMPLE_A2DP_SINK_OUTPUT_INTERNAL_DAC
|
||||
@@ -362,11 +362,14 @@ static void bt_av_hdl_a2d_evt(uint16_t event, void *p_param)
|
||||
i2s_channel_reconfig_std_slot(tx_chan, &slot_cfg);
|
||||
i2s_channel_enable(tx_chan);
|
||||
#endif
|
||||
ESP_LOGI(BT_AV_TAG, "Configure audio player: %x-%x-%x-%x",
|
||||
a2d->audio_cfg.mcc.cie.sbc[0],
|
||||
a2d->audio_cfg.mcc.cie.sbc[1],
|
||||
a2d->audio_cfg.mcc.cie.sbc[2],
|
||||
a2d->audio_cfg.mcc.cie.sbc[3]);
|
||||
ESP_LOGI(BT_AV_TAG, "Configure audio player: 0x%x-0x%x-0x%x-0x%x-0x%x-%d-%d",
|
||||
p_mcc->cie.sbc_info.samp_freq,
|
||||
p_mcc->cie.sbc_info.ch_mode,
|
||||
p_mcc->cie.sbc_info.block_len,
|
||||
p_mcc->cie.sbc_info.num_subbands,
|
||||
p_mcc->cie.sbc_info.alloc_mthd,
|
||||
p_mcc->cie.sbc_info.min_bitpool,
|
||||
p_mcc->cie.sbc_info.max_bitpool);
|
||||
ESP_LOGI(BT_AV_TAG, "Audio player configured, sample rate: %d", sample_rate);
|
||||
}
|
||||
break;
|
||||
@@ -381,6 +384,17 @@ static void bt_av_hdl_a2d_evt(uint16_t event, void *p_param)
|
||||
}
|
||||
break;
|
||||
}
|
||||
/* when using external codec, after sep registration done, this event comes */
|
||||
case ESP_A2D_SEP_REG_STATE_EVT: {
|
||||
a2d = (esp_a2d_cb_param_t *)(p_param);
|
||||
if (a2d->a2d_sep_reg_stat.reg_state == ESP_A2D_SEP_REG_SUCCESS) {
|
||||
ESP_LOGI(BT_AV_TAG, "A2DP register SEP success, seid: %d", a2d->a2d_sep_reg_stat.seid);
|
||||
}
|
||||
else {
|
||||
ESP_LOGI(BT_AV_TAG, "A2DP register SEP fail, seid: %d, state: %d", a2d->a2d_sep_reg_stat.seid, a2d->a2d_sep_reg_stat.reg_state);
|
||||
}
|
||||
break;
|
||||
}
|
||||
/* When protocol service capabilities configured, this event comes */
|
||||
case ESP_A2D_SNK_PSC_CFG_EVT: {
|
||||
a2d = (esp_a2d_cb_param_t *)(p_param);
|
||||
@@ -591,6 +605,7 @@ void bt_app_a2d_cb(esp_a2d_cb_event_t event, esp_a2d_cb_param_t *param)
|
||||
case ESP_A2D_AUDIO_STATE_EVT:
|
||||
case ESP_A2D_AUDIO_CFG_EVT:
|
||||
case ESP_A2D_PROF_STATE_EVT:
|
||||
case ESP_A2D_SEP_REG_STATE_EVT:
|
||||
case ESP_A2D_SNK_PSC_CFG_EVT:
|
||||
case ESP_A2D_SNK_SET_DELAY_VALUE_EVT:
|
||||
case ESP_A2D_SNK_GET_DELAY_VALUE_EVT: {
|
||||
@@ -603,6 +618,8 @@ void bt_app_a2d_cb(esp_a2d_cb_event_t event, esp_a2d_cb_param_t *param)
|
||||
}
|
||||
}
|
||||
|
||||
#if CONFIG_EXAMPLE_A2DP_SINK_USE_EXTERNAL_CODEC == FALSE
|
||||
|
||||
void bt_app_a2d_data_cb(const uint8_t *data, uint32_t len)
|
||||
{
|
||||
write_ringbuf(data, len);
|
||||
@@ -613,6 +630,21 @@ void bt_app_a2d_data_cb(const uint8_t *data, uint32_t len)
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void bt_app_a2d_audio_data_cb(esp_a2d_conn_hdl_t conn_hdl, esp_a2d_audio_buff_t *audio_buf)
|
||||
{
|
||||
ESP_LOGI(BT_AV_TAG, "data_len: %d, number_frame: %d, ts: %lu", audio_buf->data_len, audio_buf->number_frame, audio_buf->timestamp);
|
||||
|
||||
/*
|
||||
* Normally, user should send the audio_buf to other task, decode and free audio buff,
|
||||
* But the codec component is not merge into IDF now, so we just free audio data here
|
||||
*/
|
||||
esp_a2d_audio_buff_free(audio_buf);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void bt_app_rc_ct_cb(esp_avrc_ct_cb_event_t event, esp_avrc_ct_cb_param_t *param)
|
||||
{
|
||||
#if CONFIG_EXAMPLE_AVRCP_CT_COVER_ART_ENABLE
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
@@ -32,6 +32,14 @@ void bt_app_a2d_cb(esp_a2d_cb_event_t event, esp_a2d_cb_param_t *param);
|
||||
*/
|
||||
void bt_app_a2d_data_cb(const uint8_t *data, uint32_t len);
|
||||
|
||||
/**
|
||||
* @brief callback function for A2DP sink undecoded audio data
|
||||
*
|
||||
* @param [in] conn_hdl connection handle
|
||||
* @param [in] audio_buf pointer to audio buff
|
||||
*/
|
||||
void bt_app_a2d_audio_data_cb(esp_a2d_conn_hdl_t conn_hdl, esp_a2d_audio_buff_t *audio_buf);
|
||||
|
||||
/**
|
||||
* @brief callback function for AVRCP controller
|
||||
*
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
@@ -164,8 +164,23 @@ static void bt_av_hdl_stack_evt(uint16_t event, void *p_param)
|
||||
|
||||
assert(esp_a2d_sink_init() == ESP_OK);
|
||||
esp_a2d_register_callback(&bt_app_a2d_cb);
|
||||
esp_a2d_sink_register_data_callback(bt_app_a2d_data_cb);
|
||||
|
||||
#if CONFIG_EXAMPLE_A2DP_SINK_USE_EXTERNAL_CODEC == FALSE
|
||||
esp_a2d_sink_register_data_callback(bt_app_a2d_data_cb);
|
||||
#else
|
||||
esp_a2d_mcc_t mcc = {0};
|
||||
mcc.type = ESP_A2D_MCT_SBC;
|
||||
mcc.cie.sbc_info.samp_freq = 0xf;
|
||||
mcc.cie.sbc_info.ch_mode = 0xf;
|
||||
mcc.cie.sbc_info.block_len = 0xf;
|
||||
mcc.cie.sbc_info.num_subbands = 0x3;
|
||||
mcc.cie.sbc_info.alloc_mthd = 0x3;
|
||||
mcc.cie.sbc_info.max_bitpool = 250;
|
||||
mcc.cie.sbc_info.min_bitpool = 2;
|
||||
/* register stream end point, only support mSBC currently */
|
||||
esp_a2d_sink_register_stream_endpoint(0, &mcc);
|
||||
esp_a2d_sink_register_audio_data_callback(bt_app_a2d_audio_data_cb);
|
||||
#endif
|
||||
/* Get the default value of the delay value */
|
||||
esp_a2d_sink_get_delay_value();
|
||||
/* Get local device name */
|
||||
|
@@ -92,7 +92,7 @@ static void bt_app_task_handler(void *arg)
|
||||
void bt_app_task_start_up(void)
|
||||
{
|
||||
bt_app_task_queue = xQueueCreate(10, sizeof(bt_app_msg_t));
|
||||
xTaskCreate(bt_app_task_handler, "BtAppT", 2048, NULL, configMAX_PRIORITIES - 3, &bt_app_task_handle);
|
||||
xTaskCreate(bt_app_task_handler, "BtAppT", 4096, NULL, configMAX_PRIORITIES - 3, &bt_app_task_handle);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
@@ -174,59 +174,55 @@ extern esp_bd_addr_t peer_addr;
|
||||
// If you want to connect a specific device, add it's address here
|
||||
// esp_bd_addr_t peer_addr = {0xac, 0x67, 0xb2, 0x53, 0x77, 0xbe};
|
||||
|
||||
#if CONFIG_BT_HFP_AUDIO_DATA_PATH_HCI
|
||||
#if CONFIG_BT_HFP_AUDIO_DATA_PATH_HCI && CONFIG_BT_HFP_USE_EXTERNAL_CODEC
|
||||
|
||||
#define ESP_HFP_RINGBUF_SIZE 3600
|
||||
static RingbufHandle_t m_rb = NULL;
|
||||
static esp_hf_sync_conn_hdl_t s_sync_conn_hdl;
|
||||
static bool s_msbc_air_mode = false;
|
||||
QueueHandle_t s_audio_buff_queue = NULL;
|
||||
static int s_audio_buff_cnt = 0;
|
||||
|
||||
static void bt_app_hf_client_audio_open(void)
|
||||
static void bt_app_hf_client_audio_data_cb(esp_hf_sync_conn_hdl_t sync_conn_hdl, esp_hf_audio_buff_t *audio_buf, bool is_bad_frame)
|
||||
{
|
||||
m_rb = xRingbufferCreate(ESP_HFP_RINGBUF_SIZE, RINGBUF_TYPE_BYTEBUF);
|
||||
}
|
||||
|
||||
static void bt_app_hf_client_audio_close(void)
|
||||
{
|
||||
if (!m_rb) {
|
||||
return ;
|
||||
}
|
||||
|
||||
vRingbufferDelete(m_rb);
|
||||
}
|
||||
|
||||
static uint32_t bt_app_hf_client_outgoing_cb(uint8_t *p_buf, uint32_t sz)
|
||||
{
|
||||
if (!m_rb) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t item_size = 0;
|
||||
uint8_t *data = xRingbufferReceiveUpTo(m_rb, &item_size, 0, sz);
|
||||
if (item_size == sz) {
|
||||
memcpy(p_buf, data, item_size);
|
||||
vRingbufferReturnItem(m_rb, data);
|
||||
return sz;
|
||||
} else if (0 < item_size) {
|
||||
vRingbufferReturnItem(m_rb, data);
|
||||
return 0;
|
||||
} else {
|
||||
// data not enough, do not read
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void bt_app_hf_client_incoming_cb(const uint8_t *buf, uint32_t sz)
|
||||
{
|
||||
if (! m_rb) {
|
||||
if (is_bad_frame) {
|
||||
esp_hf_client_audio_buff_free(audio_buf);
|
||||
return;
|
||||
}
|
||||
BaseType_t done = xRingbufferSend(m_rb, (uint8_t *)buf, sz, 0);
|
||||
if (! done) {
|
||||
ESP_LOGE(BT_HF_TAG, "rb send fail");
|
||||
|
||||
if (s_audio_buff_queue && xQueueSend(s_audio_buff_queue, &audio_buf, 0)) {
|
||||
s_audio_buff_cnt++;
|
||||
}
|
||||
else {
|
||||
esp_hf_client_audio_buff_free(audio_buf);
|
||||
}
|
||||
|
||||
esp_hf_client_outgoing_data_ready();
|
||||
/* cache some data to add latency */
|
||||
if (s_audio_buff_cnt < 20) {
|
||||
return;
|
||||
}
|
||||
|
||||
esp_hf_audio_buff_t *audio_data_to_send;
|
||||
if (!xQueueReceive(s_audio_buff_queue, &audio_data_to_send, 0)) {
|
||||
return;
|
||||
}
|
||||
|
||||
s_audio_buff_cnt--;
|
||||
if (s_msbc_air_mode && audio_data_to_send->data_len > ESP_HF_MSBC_ENCODED_FRAME_SIZE) {
|
||||
/*
|
||||
* in mSBC air mode, we may receive a mSBC frame with some padding bytes at the end,
|
||||
* but esp_hf_client_audio_data_send API do not allow adding padding bytes at the end,
|
||||
* so we need to remove those padding bytes before send back to peer device.
|
||||
*/
|
||||
audio_data_to_send->data_len = ESP_HF_MSBC_ENCODED_FRAME_SIZE;
|
||||
}
|
||||
|
||||
/* send audio data back to AG */
|
||||
if (esp_hf_client_audio_data_send(s_sync_conn_hdl, audio_data_to_send) != ESP_OK) {
|
||||
esp_hf_client_audio_buff_free(audio_data_to_send);
|
||||
ESP_LOGW(BT_HF_TAG, "fail to send audio data");
|
||||
}
|
||||
}
|
||||
#endif /* #if CONFIG_BT_HFP_AUDIO_DATA_PATH_HCI */
|
||||
|
||||
#endif /* #if CONFIG_BT_HFP_AUDIO_DATA_PATH_HCI && CONFIG_BT_HFP_USE_EXTERNAL_CODEC */
|
||||
|
||||
/* callback for HF_CLIENT */
|
||||
void bt_app_hf_client_cb(esp_hf_client_cb_event_t event, esp_hf_client_cb_param_t *param)
|
||||
@@ -255,16 +251,32 @@ void bt_app_hf_client_cb(esp_hf_client_cb_event_t event, esp_hf_client_cb_param_
|
||||
{
|
||||
ESP_LOGI(BT_HF_TAG, "--audio state %s",
|
||||
c_audio_state_str[param->audio_stat.state]);
|
||||
#if CONFIG_BT_HFP_AUDIO_DATA_PATH_HCI
|
||||
#if CONFIG_BT_HFP_AUDIO_DATA_PATH_HCI && CONFIG_BT_HFP_USE_EXTERNAL_CODEC
|
||||
if (param->audio_stat.state == ESP_HF_CLIENT_AUDIO_STATE_CONNECTED_MSBC) {
|
||||
s_msbc_air_mode = true;
|
||||
ESP_LOGI(BT_HF_TAG, "--audio air mode: mSBC , preferred_frame_size: %d", param->audio_stat.preferred_frame_size);
|
||||
}
|
||||
else if (param->audio_stat.state == ESP_HF_CLIENT_AUDIO_STATE_CONNECTED) {
|
||||
s_msbc_air_mode = false;
|
||||
ESP_LOGI(BT_HF_TAG, "--audio air mode: CVSD , preferred_frame_size: %d", param->audio_stat.preferred_frame_size);
|
||||
}
|
||||
|
||||
if (param->audio_stat.state == ESP_HF_CLIENT_AUDIO_STATE_CONNECTED ||
|
||||
param->audio_stat.state == ESP_HF_CLIENT_AUDIO_STATE_CONNECTED_MSBC) {
|
||||
esp_hf_client_register_data_callback(bt_app_hf_client_incoming_cb,
|
||||
bt_app_hf_client_outgoing_cb);
|
||||
bt_app_hf_client_audio_open();
|
||||
s_sync_conn_hdl = param->audio_stat.sync_conn_handle;
|
||||
s_audio_buff_queue = xQueueCreate(50, sizeof(esp_hf_audio_buff_t*));
|
||||
esp_hf_client_register_audio_data_callback(bt_app_hf_client_audio_data_cb);
|
||||
} else if (param->audio_stat.state == ESP_HF_CLIENT_AUDIO_STATE_DISCONNECTED) {
|
||||
bt_app_hf_client_audio_close();
|
||||
s_sync_conn_hdl = 0;
|
||||
s_msbc_air_mode = false;
|
||||
esp_hf_audio_buff_t *buff_to_free = NULL;
|
||||
while (xQueueReceive(s_audio_buff_queue, &buff_to_free, 0)) {
|
||||
esp_hf_client_audio_buff_free(buff_to_free);
|
||||
}
|
||||
vQueueDelete(s_audio_buff_queue);
|
||||
s_audio_buff_cnt = 0;
|
||||
}
|
||||
#endif /* #if CONFIG_BT_HFP_AUDIO_DATA_PATH_HCI */
|
||||
#endif /* #if CONFIG_BT_HFP_AUDIO_DATA_PATH_HCI && CONFIG_BT_HFP_USE_EXTERNAL_CODEC */
|
||||
break;
|
||||
}
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
@@ -297,21 +297,21 @@ static void bt_av_hdl_a2d_evt(uint16_t event, void *p_param)
|
||||
/* when audio codec is configured, this event comes */
|
||||
case ESP_A2D_AUDIO_CFG_EVT: {
|
||||
a2d = (esp_a2d_cb_param_t *)(p_param);
|
||||
ESP_LOGI(BT_AV_TAG, "A2DP audio stream configuration, codec type: %d", a2d->audio_cfg.mcc.type);
|
||||
esp_a2d_mcc_t *p_mcc = &a2d->audio_cfg.mcc;
|
||||
ESP_LOGI(BT_AV_TAG, "A2DP audio stream configuration, codec type: %d", p_mcc->type);
|
||||
/* for now only SBC stream is supported */
|
||||
if (a2d->audio_cfg.mcc.type == ESP_A2D_MCT_SBC) {
|
||||
if (p_mcc->type == ESP_A2D_MCT_SBC) {
|
||||
int sample_rate = 16000;
|
||||
int ch_count = 2;
|
||||
char oct0 = a2d->audio_cfg.mcc.cie.sbc[0];
|
||||
if (oct0 & (0x01 << 6)) {
|
||||
if (p_mcc->cie.sbc_info.samp_freq & ESP_A2D_SBC_CIE_SF_32K) {
|
||||
sample_rate = 32000;
|
||||
} else if (oct0 & (0x01 << 5)) {
|
||||
} else if (p_mcc->cie.sbc_info.samp_freq & ESP_A2D_SBC_CIE_SF_44K) {
|
||||
sample_rate = 44100;
|
||||
} else if (oct0 & (0x01 << 4)) {
|
||||
} else if (p_mcc->cie.sbc_info.samp_freq & ESP_A2D_SBC_CIE_SF_48K) {
|
||||
sample_rate = 48000;
|
||||
}
|
||||
|
||||
if (oct0 & (0x01 << 3)) {
|
||||
if (p_mcc->cie.sbc_info.ch_mode & ESP_A2D_SBC_CIE_CH_MODE_MONO) {
|
||||
ch_count = 1;
|
||||
}
|
||||
#ifdef CONFIG_EXAMPLE_A2DP_SINK_OUTPUT_INTERNAL_DAC
|
||||
@@ -338,11 +338,14 @@ static void bt_av_hdl_a2d_evt(uint16_t event, void *p_param)
|
||||
i2s_channel_reconfig_std_slot(tx_chan, &slot_cfg);
|
||||
i2s_channel_enable(tx_chan);
|
||||
#endif
|
||||
ESP_LOGI(BT_AV_TAG, "Configure audio player: %x-%x-%x-%x",
|
||||
a2d->audio_cfg.mcc.cie.sbc[0],
|
||||
a2d->audio_cfg.mcc.cie.sbc[1],
|
||||
a2d->audio_cfg.mcc.cie.sbc[2],
|
||||
a2d->audio_cfg.mcc.cie.sbc[3]);
|
||||
ESP_LOGI(BT_AV_TAG, "Configure audio player: 0x%x-0x%x-0x%x-0x%x-0x%x-%d-%d",
|
||||
p_mcc->cie.sbc_info.samp_freq,
|
||||
p_mcc->cie.sbc_info.ch_mode,
|
||||
p_mcc->cie.sbc_info.block_len,
|
||||
p_mcc->cie.sbc_info.num_subbands,
|
||||
p_mcc->cie.sbc_info.alloc_mthd,
|
||||
p_mcc->cie.sbc_info.min_bitpool,
|
||||
p_mcc->cie.sbc_info.max_bitpool);
|
||||
ESP_LOGI(BT_AV_TAG, "Audio player configured, sample rate: %d", sample_rate);
|
||||
}
|
||||
break;
|
||||
@@ -364,7 +367,7 @@ static void bt_av_hdl_a2d_evt(uint16_t event, void *p_param)
|
||||
if (a2d->a2d_psc_cfg_stat.psc_mask & ESP_A2D_PSC_DELAY_RPT) {
|
||||
ESP_LOGI(BT_AV_TAG, "Peer device support delay reporting");
|
||||
} else {
|
||||
ESP_LOGI(BT_AV_TAG, "Peer device unsupport delay reporting");
|
||||
ESP_LOGI(BT_AV_TAG, "Peer device unsupported delay reporting");
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -415,13 +418,13 @@ static void bt_av_hdl_avrc_ct_evt(uint16_t event, void *p_param)
|
||||
}
|
||||
break;
|
||||
}
|
||||
/* when passthrough responsed, this event comes */
|
||||
/* when passthrough responded, this event comes */
|
||||
case ESP_AVRC_CT_PASSTHROUGH_RSP_EVT: {
|
||||
ESP_LOGI(BT_RC_CT_TAG, "AVRC passthrough rsp: key_code 0x%x, key_state %d, rsp_code %d", rc->psth_rsp.key_code,
|
||||
rc->psth_rsp.key_state, rc->psth_rsp.rsp_code);
|
||||
break;
|
||||
}
|
||||
/* when metadata responsed, this event comes */
|
||||
/* when metadata responded, this event comes */
|
||||
case ESP_AVRC_CT_METADATA_RSP_EVT: {
|
||||
ESP_LOGI(BT_RC_CT_TAG, "AVRC metadata rsp: attribute id 0x%x, %s", rc->meta_rsp.attr_id, rc->meta_rsp.attr_text);
|
||||
free(rc->meta_rsp.attr_text);
|
||||
|
Reference in New Issue
Block a user