Merge branch 'idf/ble_audio_4.4.1_v6.1' into 'release/v6.1'

feat(ble_audio): Support Zephyr LE Audio v4.4.1 (v6.1)

See merge request espressif/esp-idf!50187
This commit is contained in:
Jiang Jiang Jian
2026-07-03 20:28:32 +08:00
29 changed files with 525 additions and 398 deletions

View File

@@ -175,7 +175,7 @@ if BT_BAP_BROADCAST_SINK
config BT_BAP_BROADCAST_SNK_COUNT
int "Basic Audio Broadcaster Sink count"
default 1
range 0 BT_ISO_MAX_BIG
range 1 BT_ISO_MAX_BIG
help
This option sets the number of broadcast sinks to support.
One broadcast sink can receive multiple streams

View File

@@ -249,4 +249,11 @@ if BT_TBS || BT_TBS_CLIENT
help
Sets the maximum length of the bearer provider name.
config BT_TBS_MAX_FRIENDLY_NAME_LENGTH
int "The maximum length of the friendly name supported"
default 30
range 1 512
help
Sets the maximum length of the friendly name in octets (without NULL terminator).
endif # BT_TBS || BT_TBS_CLIENT

View File

@@ -73,7 +73,7 @@ esp_err_t esp_ble_audio_ccp_call_control_server_set_bearer_provider_name(
}
esp_err_t esp_ble_audio_ccp_call_control_server_get_bearer_provider_name(
esp_ble_audio_ccp_call_control_server_bearer_t *bearer, const char **name)
esp_ble_audio_ccp_call_control_server_bearer_t *bearer, char *name, size_t name_size)
{
esp_err_t err;
@@ -81,7 +81,31 @@ esp_err_t esp_ble_audio_ccp_call_control_server_get_bearer_provider_name(
return ESP_ERR_INVALID_ARG;
}
err = bt_ccp_call_control_server_get_bearer_provider_name_safe(bearer, name);
err = bt_ccp_call_control_server_get_bearer_provider_name_safe(bearer, name, name_size);
if (err) {
switch (err) {
case -EFAULT:
return ESP_ERR_INVALID_STATE;
case -ENOMEM:
return ESP_ERR_NO_MEM;
default:
return ESP_FAIL;
}
}
return ESP_OK;
}
esp_err_t esp_ble_audio_ccp_call_control_server_get_bearer_uci(
esp_ble_audio_ccp_call_control_server_bearer_t *bearer, char *uci)
{
esp_err_t err;
if (bearer == NULL || uci == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_ccp_call_control_server_get_bearer_uci_safe(bearer, uci);
if (err) {
return ESP_FAIL;
}

View File

@@ -231,19 +231,16 @@ esp_err_t esp_ble_audio_tbs_set_status_flags(uint8_t bearer_index, uint16_t stat
return ESP_OK;
}
esp_err_t esp_ble_audio_tbs_set_uri_scheme_list(uint8_t bearer_index,
const char **uri_list,
uint8_t uri_count)
esp_err_t esp_ble_audio_tbs_set_uri_scheme_list(uint8_t bearer_index, const char *uri_scheme_list)
{
uint8_t count = CONFIG_BT_TBS_BEARER_COUNT;
int err;
if (count == 0 || bearer_index >= count ||
(uri_count && uri_list == NULL)) {
if (count == 0 || bearer_index >= count || uri_scheme_list == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_tbs_set_uri_scheme_list_safe(bearer_index, uri_list, uri_count);
err = bt_tbs_set_uri_scheme_list_safe(bearer_index, uri_scheme_list);
if (err) {
return ESP_FAIL;
}
@@ -994,4 +991,23 @@ unlock:
return ret;
}
#endif /* CONFIG_BT_TBS_CLIENT_CCID */
esp_ble_audio_tbs_instance_t *esp_ble_audio_tbs_client_get_by_index(uint16_t conn_handle, uint8_t index)
{
esp_ble_audio_tbs_instance_t *ret = NULL;
void *conn;
bt_le_host_lock();
conn = bt_le_acl_conn_find(conn_handle);
if (conn == NULL) {
goto unlock;
}
ret = lib_tbs_client_get_by_index(conn, index);
unlock:
bt_le_host_unlock();
return ret;
}
#endif /* CONFIG_BT_TBS_CLIENT */

View File

@@ -99,13 +99,25 @@ esp_err_t esp_ble_audio_ccp_call_control_server_set_bearer_provider_name(
/**
* @brief Get the bearer provider name.
*
* @param bearer The bearer to get the name for.
* @param name Pointer that will be updated to be the bearer provider name.
* @param bearer The bearer to get the name for.
* @param name Buffer that will be populated with the bearer provider name.
* @param name_size The size of the @p name buffer.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_ccp_call_control_server_get_bearer_provider_name(
esp_ble_audio_ccp_call_control_server_bearer_t *bearer, const char **name);
esp_ble_audio_ccp_call_control_server_bearer_t *bearer, char *name, size_t name_size);
/**
* @brief Get the bearer UCI.
*
* @param bearer The bearer to get the UCI for.
* @param uci Buffer of size BT_TBS_MAX_UCI_SIZE that the bearer UCI will be written to.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_ccp_call_control_server_get_bearer_uci(
esp_ble_audio_ccp_call_control_server_bearer_t *bearer, char *uci);
/**
* @brief Discovers the Telephone Bearer Service (TBS) support on a remote device.

View File

@@ -318,15 +318,12 @@ esp_err_t esp_ble_audio_tbs_set_status_flags(uint8_t bearer_index, uint16_t stat
/**
* @brief Sets the URI scheme list of a bearer.
*
* @param bearer_index The index of the Telephone Bearer.
* @param uri_list List of URI prefixes (e.g. {"skype", "tel"}).
* @param uri_count Number of URI prefixes in @p uri_list.
* @param bearer_index The index of the Telephone Bearer.
* @param uri_scheme_list Comma-separated list of URI prefixes (e.g. "skype,tel").
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_tbs_set_uri_scheme_list(uint8_t bearer_index,
const char **uri_list,
uint8_t uri_count);
esp_err_t esp_ble_audio_tbs_set_uri_scheme_list(uint8_t bearer_index, const char *uri_scheme_list);
/**
* @brief Register the callbacks for TBS.
@@ -628,6 +625,16 @@ esp_err_t esp_ble_audio_tbs_client_register_cb(esp_ble_audio_tbs_client_cb_t *cb
*/
esp_ble_audio_tbs_instance_t *esp_ble_audio_tbs_client_get_by_ccid(uint16_t conn_handle, uint8_t ccid);
/**
* @brief Look up Telephone Bearer Service instance by index.
*
* @param conn_handle Connection handle.
* @param index The index to lookup a service instance for.
*
* @return Pointer to TBS instance if found, NULL otherwise.
*/
esp_ble_audio_tbs_instance_t *esp_ble_audio_tbs_client_get_by_index(uint16_t conn_handle, uint8_t index);
#ifdef __cplusplus
}
#endif

View File

@@ -45,8 +45,13 @@ LOG_MODULE_REGISTER(LEA_CSIS, CONFIG_BT_ISO_LOG_LEVEL);
(BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_ENC)
#endif /* CONFIG_BT_CSIP_SET_MEMBER_SIRK_NOTIFIABLE */
#if CONFIG_BT_CSIP_SET_MEMBER_SIZE_NOTIFIABLE
#define CSIS_CHR_FLAGS_SET_SIZE \
(BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_READ_ENC)
#else /* CONFIG_BT_CSIP_SET_MEMBER_SIZE_NOTIFIABLE */
#define CSIS_CHR_FLAGS_SET_SIZE \
(BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_ENC)
#endif /* CONFIG_BT_CSIP_SET_MEMBER_SIZE_NOTIFIABLE */
#define CSIS_CHR_FLAGS_SET_LOCK \
(BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_WRITE | \
@@ -138,34 +143,60 @@ static int csis_svc_check(void)
int bt_le_nimble_csis_attr_handle_set(void)
{
struct bt_gatt_attr *attr;
uint16_t start_handle = 0;
uint16_t end_handle = 0;
LOG_DBG("[N]CsisAttrHdlSet[%u]", csis_svc_count);
for (size_t i = 0; i < csis_svc_count; i++) {
assert(csis_insts[i].svc_p);
struct bt_gatt_service *zsvc = csis_insts[i].svc_p;
assert(zsvc);
assert(csis_insts[i].sirk_handle >= 2);
/* SIRK is always the first characteristic, so its value handle anchors the range. */
start_handle = csis_insts[i].sirk_handle - 2; /* server attr handle & char def handle */
end_handle = csis_insts[i].rank_handle; /* no cccd for chr Set Member Rank */
LOG_DBG("[N]CsisInst[%u][%u][%u][%u]",
i, start_handle, end_handle, csis_insts[i].svc_p->attr_count);
LOG_DBG("[N]CsisInst[%u][%u][%u]", i, start_handle, zsvc->attr_count);
for (size_t j = 0; j < csis_insts[i].svc_p->attr_count; j++) {
(csis_insts[i].svc_p->attrs + j)->handle = start_handle + j;
for (size_t j = 0; j < zsvc->attr_count; j++) {
(zsvc->attrs + j)->handle = start_handle + j;
}
/* Last attribute in CSIS */
attr = csis_insts[i].svc_p->attrs + csis_insts[i].svc_p->attr_count - 1;
/* Cross-check the last characteristic value against the handle NimBLE assigned, to
* catch divergence between the lib's attribute layout and NimBLE's registration. The
* last characteristic is no longer necessarily Rank, as optional ones may be absent.
*/
for (size_t j = zsvc->attr_count; j-- > 0;) {
const struct bt_uuid_16 *uuid = (const struct bt_uuid_16 *)(zsvc->attrs + j)->uuid;
uint16_t chr_handle = 0;
if (attr->handle != end_handle) {
LOG_ERR("[N]CsisMismatchAttrHdl[%u][%u][%u][%u][%u]",
i, start_handle, end_handle, attr->handle,
csis_insts[i].svc_p->attr_count);
return -1;
if (uuid->uuid.type != BT_UUID_TYPE_16) {
continue;
}
switch (uuid->val) {
case BT_UUID_CSIS_SIRK_VAL:
chr_handle = csis_insts[i].sirk_handle;
break;
case BT_UUID_CSIS_SET_SIZE_VAL:
chr_handle = csis_insts[i].set_size_handle;
break;
case BT_UUID_CSIS_SET_LOCK_VAL:
chr_handle = csis_insts[i].set_lock_handle;
break;
case BT_UUID_CSIS_RANK_VAL:
chr_handle = csis_insts[i].rank_handle;
break;
default:
continue;
}
if ((zsvc->attrs + j)->handle != chr_handle) {
LOG_ERR("[N]CsisMismatchAttrHdl[%u][%u][%u]",
i, (zsvc->attrs + j)->handle, chr_handle);
return -1;
}
break;
}
}
@@ -189,8 +220,11 @@ static inline void csis_chr_init(struct ble_gatt_chr_def *chr,
}
static void csis_svc_init(struct csis_inst *inst,
struct ble_gatt_svc_def *svc)
struct ble_gatt_svc_def *svc,
const struct bt_gatt_service *zsvc)
{
size_t chr_cnt = 0U;
LOG_DBG("[N]CsisSvcInit");
svc->type = BLE_GATT_SVC_TYPE_PRIMARY;
@@ -200,29 +234,47 @@ static void csis_svc_init(struct csis_inst *inst,
svc->characteristics = calloc(CSIS_CHR_COUNT, sizeof(struct ble_gatt_chr_def));
assert(svc->characteristics);
/* Characteristic - Set Identity Resolving Key */
csis_chr_init((void *)&svc->characteristics[0],
&csis_uuid_sirk,
&inst->sirk_handle,
CSIS_CHR_FLAGS_SIRK);
/* Build the NimBLE characteristics from the ones actually present in the Zephyr
* service. Optional characteristics (set size, lock, rank) may be absent depending
* on the registration parameters, so the layout is data-driven rather than fixed.
*/
for (size_t i = 0; i < zsvc->attr_count; i++) {
const struct bt_uuid_16 *uuid = (const struct bt_uuid_16 *)zsvc->attrs[i].uuid;
/* Characteristic - Coordinated Set Size */
csis_chr_init((void *)&svc->characteristics[1],
&csis_uuid_set_size,
&inst->set_size_handle,
CSIS_CHR_FLAGS_SET_SIZE);
if (uuid->uuid.type != BT_UUID_TYPE_16) {
continue;
}
/* Characteristic - Set Member Lock */
csis_chr_init((void *)&svc->characteristics[2],
&csis_uuid_set_lock,
&inst->set_lock_handle,
CSIS_CHR_FLAGS_SET_LOCK);
switch (uuid->val) {
case BT_UUID_CSIS_SIRK_VAL:
csis_chr_init((void *)&svc->characteristics[chr_cnt++], &csis_uuid_sirk,
&inst->sirk_handle, CSIS_CHR_FLAGS_SIRK);
break;
case BT_UUID_CSIS_SET_SIZE_VAL:
csis_chr_init((void *)&svc->characteristics[chr_cnt++], &csis_uuid_set_size,
&inst->set_size_handle, CSIS_CHR_FLAGS_SET_SIZE);
break;
case BT_UUID_CSIS_SET_LOCK_VAL:
csis_chr_init((void *)&svc->characteristics[chr_cnt++], &csis_uuid_set_lock,
&inst->set_lock_handle, CSIS_CHR_FLAGS_SET_LOCK);
break;
case BT_UUID_CSIS_RANK_VAL:
csis_chr_init((void *)&svc->characteristics[chr_cnt++], &csis_uuid_rank,
&inst->rank_handle, CSIS_CHR_FLAGS_RANK);
break;
default:
break;
}
}
/* Characteristic - Set Member Rank */
csis_chr_init((void *)&svc->characteristics[3],
&csis_uuid_rank,
&inst->rank_handle,
CSIS_CHR_FLAGS_RANK);
/* svc->characteristics has CSIS_CHR_COUNT (= 4 + 1) slots: up to 4 real chars plus
* a trailing zeroed slot that NimBLE requires as the NULL-uuid array terminator.
* chr_cnt is the real-char count written via [chr_cnt++], so it must stay strictly
* below CSIS_CHR_COUNT — chr_cnt == CSIS_CHR_COUNT means a write already clobbered
* the terminator slot. Trips if the switch matches a 5th char: a new CSIS case added
* without bumping the (4 + 1), or a duplicate UUID in the Zephyr service table.
*/
assert(chr_cnt < CSIS_CHR_COUNT);
}
int bt_le_nimble_csis_init(void *svc, uint8_t count)
@@ -239,9 +291,9 @@ int bt_le_nimble_csis_init(void *svc, uint8_t count)
csis_svc_count = count;
for (size_t i = 0; i < csis_svc_count; i++) {
csis_svc_init(&csis_insts[i], &gatt_svc_csis[i]);
csis_insts[i].svc_p = ((struct bt_gatt_service **)svc)[i];
csis_svc_init(&csis_insts[i], &gatt_svc_csis[i], csis_insts[i].svc_p);
}
rc = ble_gatts_count_cfg(gatt_svc_csis);

View File

@@ -182,7 +182,7 @@ static const uint16_t ext_structs[] = {
sizeof(struct bt_bond_info),
};
#define LEA_VERSION (0x20260616)
#define LEA_VERSION (0x20260624)
struct lib_ext_cfgs {
/* BLE */
@@ -401,6 +401,7 @@ struct lib_ext_cfgs {
bool config_tbs_client_call_friendly_name;
uint8_t config_tbs_max_uri_length;
uint16_t config_tbs_max_provider_name_length;
uint16_t config_tbs_max_friendly_name_length;
/* TMAP (Telephony and Media Audio Profile) */
bool config_tmap_cg_supported;
@@ -893,6 +894,7 @@ static const struct lib_ext_cfgs ext_cfgs = {
#if CONFIG_BT_TBS || CONFIG_BT_TBS_CLIENT
.config_tbs_max_uri_length = CONFIG_BT_TBS_MAX_URI_LENGTH,
.config_tbs_max_provider_name_length = CONFIG_BT_TBS_MAX_PROVIDER_NAME_LENGTH,
.config_tbs_max_friendly_name_length = CONFIG_BT_TBS_MAX_FRIENDLY_NAME_LENGTH,
#endif /* CONFIG_BT_TBS || CONFIG_BT_TBS_CLIENT */
/* TMAP (Telephony and Media Audio Profile) */
@@ -1083,6 +1085,7 @@ struct lib_ext_funcs {
void *data);
int (*_conn_get_info)(const struct bt_conn *conn, struct bt_conn_info *info);
uint8_t (*_conn_index)(const struct bt_conn *conn);
struct bt_conn *(*_conn_lookup_index)(uint8_t index);
const bt_addr_le_t *(*_conn_get_dst)(const struct bt_conn *conn);
struct bt_conn *(*_conn_ref)(struct bt_conn *conn);
void (*_conn_unref)(struct bt_conn *conn);
@@ -1299,6 +1302,7 @@ static const struct lib_ext_funcs ext_funcs = {
._conn_foreach = (void *)bt_conn_foreach,
._conn_get_info = (void *)bt_conn_get_info,
._conn_index = (void *)bt_conn_index,
._conn_lookup_index = (void *)bt_conn_lookup_index,
._conn_get_dst = (void *)bt_conn_get_dst,
._conn_ref = (void *)bt_conn_ref,
._conn_unref = (void *)bt_conn_unref,
@@ -1363,6 +1367,7 @@ struct lib_funcs {
/* BAP Unicast Client */
bool (*_bap_unicast_client_has_ep)(const struct bt_bap_ep *ep);
struct bt_conn *(*_bap_unicast_client_ep_get_conn)(const struct bt_bap_ep *ep);
int (*_bap_unicast_client_register_cb)(struct bt_bap_unicast_client_cb *cb);
int (*_bap_unicast_client_config)(struct bt_bap_stream *stream,
const struct bt_audio_codec_cfg *codec_cfg);
@@ -1375,6 +1380,7 @@ struct lib_funcs {
/* BAP Unicast Server */
bool (*_bap_unicast_server_has_ep)(const struct bt_bap_ep *ep);
struct bt_conn *(*_bap_unicast_server_ep_get_conn)(const struct bt_bap_ep *ep);
int (*_bap_unicast_server_reconfig)(struct bt_bap_stream *stream,
const struct bt_audio_codec_cfg *codec_cfg);
int (*_bap_unicast_server_start)(struct bt_bap_stream *stream);
@@ -1407,11 +1413,11 @@ struct lib_funcs {
/* CAP Handover */
bool (*_cap_common_handover_is_active)(void);
bool (*_cap_handover_is_handover_broadcast_source)(const struct bt_cap_broadcast_source *cap_broadcast_source);
void (*_cap_handover_complete)(void);
void (*_cap_handover_unicast_proc_complete)(void);
void (*_cap_handover_complete)(struct bt_cap_common_proc *active_proc);
void (*_cap_handover_unicast_proc_complete)(struct bt_cap_common_proc *active_proc);
void (*_cap_handover_broadcast_source_stopped)(uint8_t reason);
void (*_cap_handover_unicast_to_broadcast_reception_start)(void);
int (*_cap_handover_broadcast_reception_stopped)(void);
int (*_cap_handover_broadcast_reception_stopped)(struct bt_cap_common_proc *active_proc);
void (*_cap_handover_receive_state_updated)(const struct bt_conn *conn,
const struct bt_bap_scan_delegator_recv_state *state);
@@ -1503,6 +1509,8 @@ struct lib_funcs {
int (*_tbs_client_primary_discover_gtbs)(struct bt_conn *conn);
struct bt_tbs_instance *(*_tbs_client_get_by_ccid)(const struct bt_conn *conn,
uint8_t ccid);
struct bt_tbs_instance *(*_tbs_client_get_by_index)(const struct bt_conn *conn,
uint8_t index);
/* VCP Volume Controller */
void (*_vcp_vol_ctlr_aics_init)(void);
@@ -1551,6 +1559,7 @@ static const struct lib_funcs lib_funcs = {
#if CONFIG_BT_BAP_UNICAST_CLIENT
._bap_unicast_client_has_ep = lib_bap_unicast_client_has_ep,
._bap_unicast_client_ep_get_conn = lib_bap_unicast_client_ep_get_conn,
._bap_unicast_client_register_cb = lib_bap_unicast_client_register_cb,
._bap_unicast_client_config = lib_bap_unicast_client_config,
._bap_unicast_client_metadata = lib_bap_unicast_client_metadata,
@@ -1562,6 +1571,7 @@ static const struct lib_funcs lib_funcs = {
#if CONFIG_BT_BAP_UNICAST_SERVER
._bap_unicast_server_has_ep = lib_bap_unicast_server_has_ep,
._bap_unicast_server_ep_get_conn = lib_bap_unicast_server_ep_get_conn,
._bap_unicast_server_reconfig = lib_bap_unicast_server_reconfig,
._bap_unicast_server_start = lib_bap_unicast_server_start,
._bap_unicast_server_metadata = lib_bap_unicast_server_metadata,
@@ -1697,6 +1707,10 @@ static const struct lib_funcs lib_funcs = {
._tbs_client_get_by_ccid = lib_tbs_client_get_by_ccid,
#endif /* CONFIG_BT_TBS_CLIENT_CCID */
#if CONFIG_BT_TBS_CLIENT
._tbs_client_get_by_index = lib_tbs_client_get_by_index,
#endif /* CONFIG_BT_TBS_CLIENT */
#if CONFIG_BT_VCP_VOL_CTLR_AICS
._vcp_vol_ctlr_aics_init = lib_vcp_vol_ctlr_aics_init,
#endif /* CONFIG_BT_VCP_VOL_CTLR_AICS */

View File

@@ -125,7 +125,10 @@ extern "C" {
#define BT_AICS_ERR_GAIN_MODE_NOT_ALLOWED 0x84
/** @} */
/** @brief Opaque Audio Input Control Service instance. */
/**
* @struct bt_aics
* @brief Opaque Audio Input Control Service instance.
*/
struct bt_aics;
/** @brief Structure for initializing a Audio Input Control Service instance. */

View File

@@ -619,16 +619,28 @@ struct bt_bap_ascs_rsp {
*/
#define BT_BAP_ASCS_RSP(c, r) (struct bt_bap_ascs_rsp) { .code = c, .reason = r }
/** @brief Abstract Audio Broadcast Source structure. */
/**
* @struct bt_bap_broadcast_source
* @brief Abstract Audio Broadcast Source structure.
*/
struct bt_bap_broadcast_source;
/** @brief Abstract Audio Broadcast Sink structure. */
/**
* @struct bt_bap_broadcast_sink
* @brief Abstract Audio Broadcast Sink structure.
*/
struct bt_bap_broadcast_sink;
/** @brief Abstract Audio Unicast Group structure. */
/**
* @struct bt_bap_unicast_group
* @brief Abstract Audio Unicast Group structure.
*/
struct bt_bap_unicast_group;
/** @brief Abstract Audio Endpoint structure. */
/**
* @struct bt_bap_ep
* @brief Abstract Audio Endpoint structure.
*/
struct bt_bap_ep;
/** Struct to hold subgroup specific information for the receive state */
@@ -871,6 +883,22 @@ struct bt_bap_ep_info {
*/
int bt_bap_ep_get_info_safe(const struct bt_bap_ep *ep, struct bt_bap_ep_info *info);
/**
* @brief Get the pointer to the ACL connection of an endpoint
*
* The caller gets a new reference to the connection object, if not NULL, which must be
* released with bt_conn_unref() once done using the object.
*
* @param ep The endpoint to get the ACL connection of
*
* @return The ACL connection pointer, or NULL if:
* - @p ep is NULL
* - @p ep is a broadcast endpoint
* - @p ep is a Unicast Server endpoint not yet configured by a remote client
* - @p ep is a Unicast Client endpoint not yet discovered on a remote server
*/
struct bt_conn *bt_bap_ep_get_conn(const struct bt_bap_ep *ep);
/**
* @brief Basic Audio Profile stream structure.
*
@@ -1189,7 +1217,7 @@ int bt_bap_stream_disable_safe(struct bt_bap_stream *stream);
* @retval 0 in case of success
* @retval -EINVAL if the stream, endpoint, ISO channel or connection is NULL
* @retval -EBADMSG if the stream or ISO channel is in an invalid state for connection
* @retval -EOPNOTSUPP if the role of the stream is not @ref BT_HCI_ROLE_CENTRAL
* @retval -EOPNOTSUPP if the role of the stream is not @ref BT_CONN_ROLE_CENTRAL
* @retval -EALREADY if the ISO channel is already connecting or connected
* @retval -EBUSY if another ISO channel is connecting
* @retval -ENOEXEC if otherwise rejected by the ISO layer
@@ -1233,7 +1261,7 @@ int bt_bap_stream_start_safe(struct bt_bap_stream *stream);
*
* @retval 0 Success
* @retval -EINVAL The @p stream does not have an endpoint or a connection, of the stream's
* connection's role is not @p BT_HCI_ROLE_CENTRAL
* connection's role is not @p BT_CONN_ROLE_CENTRAL
* @retval -EBADMSG The state of the @p stream endpoint is not @ref BT_BAP_EP_STATE_DISABLING
* @retval -EALREADY The CIS state of the @p is not in a connected state, and thus is already
* stopping
@@ -1530,8 +1558,11 @@ int bt_bap_unicast_server_unregister_cb_safe(const struct bt_bap_unicast_server_
*
* @param ep The structure object with endpoint info.
* @param user_data Data to pass to the function.
*
* @retval true Continue iterating.
* @retval false Stop iterating.
*/
typedef void (*bt_bap_ep_func_t)(struct bt_bap_ep *ep, void *user_data);
typedef bool (*bt_bap_ep_func_t)(struct bt_bap_ep *ep, void *user_data);
/**
* @brief Iterate through all endpoints of the given connection.
@@ -1539,8 +1570,12 @@ typedef void (*bt_bap_ep_func_t)(struct bt_bap_ep *ep, void *user_data);
* @param conn Connection object
* @param func Function to call for each endpoint.
* @param user_data Data to pass to the callback function.
*
* @retval 0 Success
* @retval -ECANCELED Iteration was stopped by the callback function before complete.
* @retval -EINVAL @p conn or @p func were NULL.
*/
void bt_bap_unicast_server_foreach_ep(struct bt_conn *conn, bt_bap_ep_func_t func, void *user_data);
int bt_bap_unicast_server_foreach_ep(struct bt_conn *conn, bt_bap_ep_func_t func, void *user_data);
/**
* @brief Initialize and configure a new ASE.
@@ -1711,8 +1746,8 @@ int bt_bap_unicast_group_delete_safe(struct bt_bap_unicast_group *unicast_group)
* @param stream The audio stream
* @param user_data User data
*
* @retval true Stop iterating.
* @retval false Continue iterating.
* @retval true Continue iterating.
* @retval false Stop iterating.
*/
typedef bool (*bt_bap_unicast_group_foreach_stream_func_t)(struct bt_bap_stream *stream,
void *user_data);
@@ -1770,11 +1805,22 @@ struct bt_bap_unicast_client_cb {
* @param conn Connection to the remote unicast server.
* @param dir Direction of the location.
* @param loc The location bitfield value.
*
* @return 0 in case of success or negative value in case of error.
*/
void (*location)(struct bt_conn *conn, enum bt_audio_dir dir, enum bt_audio_location loc);
/**
* @brief Remote Unicast Server Supported Contexts
*
* This callback is called whenever the supported contexts are read
* from the server or otherwise notified to the client.
*
* @param conn Connection to the remote unicast server.
* @param snk_ctx The sink context bitfield value.
* @param src_ctx The source context bitfield value.
*/
void (*supported_contexts)(struct bt_conn *conn, enum bt_audio_context snk_ctx,
enum bt_audio_context src_ctx);
/**
* @brief Remote Unicast Server Available Contexts
*
@@ -1784,8 +1830,6 @@ struct bt_bap_unicast_client_cb {
* @param conn Connection to the remote unicast server.
* @param snk_ctx The sink context bitfield value.
* @param src_ctx The source context bitfield value.
*
* @return 0 in case of success or negative value in case of error.
*/
void (*available_contexts)(struct bt_conn *conn, enum bt_audio_context snk_ctx,
enum bt_audio_context src_ctx);
@@ -2453,8 +2497,8 @@ int bt_bap_broadcast_source_get_base_safe(struct bt_bap_broadcast_source *source
* @param stream The audio stream
* @param user_data User data
*
* @retval true Stop iterating.
* @retval false Continue iterating.
* @retval true Continue iterating.
* @retval false Stop iterating.
*/
typedef bool (*bt_bap_broadcast_source_foreach_stream_func_t)(struct bt_bap_stream *stream,
void *user_data);
@@ -2467,7 +2511,7 @@ typedef bool (*bt_bap_broadcast_source_foreach_stream_func_t)(struct bt_bap_stre
* @param user_data User specified data that is sent to the callback function
*
* @retval 0 Success (even if no streams exists in the broadcast source).
* @retval -ECANCELED The @p func returned true.
* @retval -ECANCELED The @p func returned false and stopped the iteration.
* @retval -EINVAL @p source or @p func were NULL.
*/
int bt_bap_broadcast_source_foreach_stream_safe(struct bt_bap_broadcast_source *source,
@@ -2539,7 +2583,7 @@ struct bt_bap_broadcast_sink_cb {
* It is possible to register multiple struct of callbacks, but a single struct can only be
* registered once.
* Registering the same callback multiple times is undefined behavior and may break the stack.
*
* @param cb Broadcast sink callback structure.
*
* @retval 0 on success
@@ -2956,7 +3000,8 @@ int bt_bap_broadcast_assistant_discover_safe(struct bt_conn *conn);
* @retval -ENOMEM Could not allocated memory for the request
* @retval -ENOEXEC Unexpected scan or GATT error
*/
int bt_bap_broadcast_assistant_scan_start(struct bt_conn *conn, bool start_scan);
int bt_bap_broadcast_assistant_scan_start(struct bt_conn *conn,
bool start_scan);
int bt_bap_broadcast_assistant_scan_start_safe(struct bt_conn *conn,
bool start_scan);

View File

@@ -47,10 +47,16 @@
extern "C" {
#endif
/** @brief Abstract Audio Broadcast Source structure. */
/**
* @struct bt_cap_broadcast_source
* @brief Abstract Audio Broadcast Source structure.
*/
struct bt_cap_broadcast_source;
/** @brief Abstract CAP Unicast Group structure. */
/**
* @struct bt_cap_unicast_group
* @brief Abstract CAP Unicast Group structure.
*/
struct bt_cap_unicast_group;
/**
@@ -394,13 +400,13 @@ int bt_cap_unicast_group_add_streams_safe(struct bt_cap_unicast_group *unicast_g
*/
int bt_cap_unicast_group_delete_safe(struct bt_cap_unicast_group *unicast_group);
/** Callback function for bt_bap_unicast_group_foreach_stream()
/** Callback function for bt_cap_unicast_group_foreach_stream()
*
* @param stream The audio stream
* @param user_data User data
*
* @retval true Stop iterating.
* @retval false Continue iterating.
* @retval true Continue iterating.
* @retval false Stop iterating.
*/
typedef bool (*bt_cap_unicast_group_foreach_stream_func_t)(struct bt_cap_stream *stream,
void *user_data);
@@ -413,7 +419,7 @@ typedef bool (*bt_cap_unicast_group_foreach_stream_func_t)(struct bt_cap_stream
* @param user_data User specified data that is sent to the callback function
*
* @retval 0 Success (even if no streams exists in the group).
* @retval -ECANCELED The @p func returned true.
* @retval -ECANCELED The @p func returned false and stopped the iteration.
* @retval -EINVAL @p unicast_group or @p func were NULL.
*/
int bt_cap_unicast_group_foreach_stream_safe(struct bt_cap_unicast_group *unicast_group,
@@ -832,8 +838,8 @@ int bt_cap_initiator_broadcast_get_base_safe(struct bt_cap_broadcast_source *bro
* @param stream The audio stream
* @param user_data User data
*
* @retval true Stop iterating.
* @retval false Continue iterating.
* @retval true Continue iterating.
* @retval false Stop iterating.
*/
typedef bool (*bt_cap_initiator_broadcast_foreach_stream_func_t)(struct bt_cap_stream *stream,
void *user_data);
@@ -846,7 +852,7 @@ typedef bool (*bt_cap_initiator_broadcast_foreach_stream_func_t)(struct bt_cap_s
* @param user_data User specified data that is sent to the callback function.
*
* @retval 0 Success (even if no streams exists in the group).
* @retval -ECANCELED The @p func returned true.
* @retval -ECANCELED The @p func returned false and stopped the iteration.
* @retval -EINVAL @p broadcast_source or @p func were NULL.
*/
int bt_cap_initiator_broadcast_foreach_stream_safe(struct bt_cap_broadcast_source *broadcast_source,
@@ -887,6 +893,20 @@ struct bt_cap_handover_unicast_to_broadcast_param {
/** Callback structure for CAP procedures */
struct bt_cap_handover_cb {
/**
* @brief The broadcast source has been created for handover
*
* When this is called, the broadcast source has been created and the BASE can be
* generated by bt_cap_initiator_broadcast_get_base(). To continue with the broadcast
* reception part of the procedure, the application shall enable extended and periodic
* advertising and set the BASE in the periodic advertising data with
* bt_le_per_adv_set_data(). The procedure will finish once the CAP acceptors have synced
* to the newly created broadcast source.
*
* @param broadcast_source Pointer to newly created broadcast source.
*/
void (*unicast_to_broadcast_created)(struct bt_cap_broadcast_source *broadcast_source);
/**
* @brief The unicast to broadcast handover procedure has finished
*

View File

@@ -47,7 +47,10 @@ extern "C" {
* @ingroup bt_ccp
* @{
*/
/** @brief Abstract Call Control Server Telephone Bearer structure. */
/**
* @struct bt_ccp_call_control_server_bearer
* @brief Abstract Call Control Server Telephone Bearer structure.
*/
struct bt_ccp_call_control_server_bearer;
/**
@@ -101,8 +104,10 @@ int bt_ccp_call_control_server_unregister_bearer_safe(struct bt_ccp_call_control
*
* @retval 0 Success
* @retval -EINVAL @p bearer or @p name is NULL, or @p name is the empty string or @p name is larger
* than @kconfig{CONFIG_BT_TBS_MAX_PROVIDER_NAME_LENGTH}
* than @kconfig{CONFIG_BT_CCP_CALL_CONTROL_SERVER_PROVIDER_NAME_MAX_LEN}
* @retval -EFAULT @p bearer is not registered
* @retval -EBUSY The TBS instance of @p bearer is busy
* @retval -ENOEXEC The TBS instance of @p bearer returned unexpected error
*/
int bt_ccp_call_control_server_set_bearer_provider_name_safe(
struct bt_ccp_call_control_server_bearer *bearer, const char *name);
@@ -111,14 +116,32 @@ int bt_ccp_call_control_server_set_bearer_provider_name_safe(
* @brief Get the bearer provider name.
*
* @param[in] bearer The bearer to get the name for.
* @param[out] name Pointer that will be updated to be the bearer provider name.
* @param[out] name Pointer a buffer that will be populated with the bearer provider name.
* @param name_size The size of the @p name buffer. The suggested size is
* @kconfig{CONFIG_BT_CCP_CALL_CONTROL_SERVER_PROVIDER_NAME_MAX_LEN} + 1 to
* ensure that the name always fits.
*
* @retval 0 Success
* @retval -EINVAL @p bearer or @p name is NULL
* @retval -EFAULT @p bearer is not registered
* @retval -ENOMEM @p name_size is insufficient to hold the bearer name (including null terminator)
*/
int bt_ccp_call_control_server_get_bearer_provider_name_safe(
struct bt_ccp_call_control_server_bearer *bearer, const char **name);
struct bt_ccp_call_control_server_bearer *bearer, char *name, size_t name_size);
/**
* @brief Get the bearer UCI.
*
* @param[in] bearer The bearer to get the UCI for.
* @param[out] uci Pointer to a buffer of size @ref BT_TBS_MAX_UCI_SIZE that the bearer UCI will be
* written to.
*
* @retval 0 Success
* @retval -EINVAL @p bearer or @p uci is NULL
* @retval -EFAULT @p bearer is not registered
*/
int bt_ccp_call_control_server_get_bearer_uci_safe(struct bt_ccp_call_control_server_bearer *bearer,
char uci[BT_TBS_MAX_UCI_SIZE]);
/** @} */ /* End of group bt_ccp_call_control_server */
@@ -127,10 +150,17 @@ int bt_ccp_call_control_server_get_bearer_provider_name_safe(
* @ingroup bt_ccp
* @{
*/
/** Abstract Call Control Client structure. */
/**
* @struct bt_ccp_call_control_client
* @brief Abstract Call Control Client structure.
*/
struct bt_ccp_call_control_client;
/** Abstract Call Control Client bearer structure. */
/**
* @struct bt_ccp_call_control_client_bearer
* @brief Abstract Call Control Client bearer structure.
*/
struct bt_ccp_call_control_client_bearer;
/** Struct with information about bearers of a client */
@@ -159,23 +189,29 @@ struct bt_ccp_call_control_client_cb {
* @param client Call Control Client pointer.
* @param err Error value. 0 on success, GATT error on positive
* value or errno on negative value.
* @param bearers The bearers found.
* @param bearers The bearers found. Value must be copied if used after return.
* @param user_data User data stored in the callback struct.
*/
void (*discover)(struct bt_ccp_call_control_client *client, int err,
struct bt_ccp_call_control_client_bearers *bearers);
struct bt_ccp_call_control_client_bearers *bearers, void *user_data);
/**
* @brief Callback function for bt_ccp_call_control_client_read_bearer_provider_name().
*
* This callback is called once the read bearer provider name procedure is completed.
*
* @param client Call Control Client instance pointer.
* @param err Error value. 0 on success, GATT error on positive
* value or errno on negative value.
* @param name The bearer provider name. NULL if @p err is not 0.
* @param bearer Call Control Client bearer instance pointer.
* @param err Error value. 0 on success, GATT error on positive
* value or errno on negative value.
* @param name The bearer provider name. NULL if @p err is not 0.
* Value must be copied if used after return.
* @param user_data User data stored in the callback struct.
*/
void (*bearer_provider_name)(struct bt_ccp_call_control_client_bearer *bearer, int err,
const char *name);
const char *name, void *user_data);
/** User data that will be supplied to all callbacks */
void *user_data;
/** @cond INTERNAL_HIDDEN */
/** Internally used field for list handling */

View File

@@ -83,7 +83,10 @@ extern "C" {
*/
#define BT_CSIP_DATA_RSI(_rsi) BT_DATA(BT_DATA_CSIS_RSI, _rsi, BT_CSIP_RSI_SIZE)
/** @brief Opaque Coordinated Set Identification Service instance. */
/**
* @struct bt_csip_set_member_svc_inst
* @brief Opaque Coordinated Set Identification Service instance.
*/
struct bt_csip_set_member_svc_inst;
/** Callback structure for the Coordinated Set Identification Service */
@@ -224,6 +227,8 @@ int bt_csip_set_member_sirk_safe(struct bt_csip_set_member_svc_inst *svc_inst,
* It is important to note that a set cannot have multiple devices with the same rank in a set,
* and it is up to the caller of this function to ensure that.
* Similarly, it is important that the size is updated on all devices in the set at the same time.
* The rank of a device cannot be modified on its own, and a new rank can only be set if the @p size
* is different from the current set size.
*
* If @kconfig{CONFIG_BT_CSIP_SET_MEMBER_SIZE_NOTIFIABLE} is enabled, this will also send a
* notification to all connected or bonded clients.
@@ -234,7 +239,7 @@ int bt_csip_set_member_sirk_safe(struct bt_csip_set_member_svc_inst *svc_inst,
*
* @retval -EINVAL @p svc_inst is NULL, @p size is less than 1, @p rank is less than 1 or higher
* than @p size for a lockable @p svc_inst.
* @retval -EALREADY @p size and @p rank are already the provided values.
* @retval -EALREADY @p size is already set.
* @retval 0 Success.
*/
int bt_csip_set_member_set_size_and_rank_safe(struct bt_csip_set_member_svc_inst *svc_inst, uint8_t size,

View File

@@ -56,7 +56,10 @@ extern "C" {
/** Preset name maximum length */
#define BT_HAS_PRESET_NAME_MAX 40
/** @brief Opaque Hearing Access Service object. */
/**
* @struct bt_has
* @brief Opaque Hearing Access Service object.
*/
struct bt_has;
/** Hearing Aid device type */
@@ -424,14 +427,6 @@ int bt_has_preset_available_safe(uint8_t index);
*/
int bt_has_preset_unavailable_safe(uint8_t index);
/** Enum for return values for @ref bt_has_preset_func_t functions */
enum {
/** Stop iterating */
BT_HAS_PRESET_ITER_STOP = 0,
/** Continue iterating */
BT_HAS_PRESET_ITER_CONTINUE,
};
/**
* @typedef bt_has_preset_func_t
* @brief Preset iterator callback.
@@ -441,11 +436,11 @@ enum {
* @param name Preset name.
* @param user_data Data given.
*
* @return BT_HAS_PRESET_ITER_CONTINUE if should continue to the next preset.
* @return BT_HAS_PRESET_ITER_STOP to stop.
* @retval true Continue iterating.
* @retval false Stop iterating.
*/
typedef uint8_t (*bt_has_preset_func_t)(uint8_t index, enum bt_has_properties properties,
const char *name, void *user_data);
typedef bool (*bt_has_preset_func_t)(uint8_t index, enum bt_has_properties properties,
const char *name, void *user_data);
/**
* @brief Preset iterator.
@@ -455,8 +450,12 @@ typedef uint8_t (*bt_has_preset_func_t)(uint8_t index, enum bt_has_properties pr
* @param index Preset index, passing @ref BT_HAS_PRESET_INDEX_NONE skips index matching.
* @param func Callback function.
* @param user_data Data to pass to the callback.
*
* @retval 0 Success
* @retval -ECANCELED Iteration was stopped by the callback function before complete.
* @retval -EINVAL @p func was NULL.
*/
void bt_has_preset_foreach_safe(uint8_t index, bt_has_preset_func_t func, void *user_data);
int bt_has_preset_foreach_safe(uint8_t index, bt_has_preset_func_t func, void *user_data);
/**
* @brief Set active preset.

View File

@@ -54,7 +54,10 @@ extern "C" {
#define BT_MICP_MUTE_DISABLED 0x02
/** @} */
/** @brief Opaque Microphone Controller instance. */
/**
* @struct bt_micp_mic_ctlr
* @brief Opaque Microphone Controller instance.
*/
struct bt_micp_mic_ctlr;
/** @brief Register parameters structure for Microphone Control Service */

View File

@@ -201,7 +201,17 @@ extern "C" {
*/
#define BT_TBS_GTBS_INDEX 0xFF
/** @brief Opaque Telephone Bearer Service instance. */
/** Maximum size of bearer uniform caller identifier (UCI)
*
* Includes the NULL terminator.
* Allowed values are defined by Bluetooth Assigned Numbers.
*/
#define BT_TBS_MAX_UCI_SIZE 6
/**
* @struct bt_tbs_instance
* @brief Opaque Telephone Bearer Service instance.
*/
struct bt_tbs_instance;
/**
@@ -453,13 +463,11 @@ int bt_tbs_set_status_flags_safe(uint8_t bearer_index, uint16_t status_flags);
* @brief Sets the URI scheme list of a bearer.
*
* @param bearer_index The index of the Telephone Bearer.
* @param uri_list List of URI prefixes (e.g. {"skype", "tel"}).
* @param uri_count Number of URI prefixes in @p uri_list.
* @param uri_scheme_list Comma-separated list of URI prefixes (e.g. "skype,tel").
*
* @return BT_TBS_RESULT_CODE_* if positive or 0, errno value if negative.
*/
int bt_tbs_set_uri_scheme_list_safe(uint8_t bearer_index, const char **uri_list,
uint8_t uri_count);
int bt_tbs_set_uri_scheme_list_safe(uint8_t bearer_index, const char *uri_scheme_list);
/**
* @brief Register the callbacks for TBS.
*
@@ -1086,7 +1094,8 @@ int bt_tbs_client_read_friendly_name_safe(struct bt_conn *conn, uint8_t inst_ind
* @note @kconfig{CONFIG_BT_TBS_CLIENT_OPTIONAL_OPCODES} must be set
* for this function to be effective.
*/
int bt_tbs_client_read_optional_opcodes(struct bt_conn *conn, uint8_t inst_index);
int bt_tbs_client_read_optional_opcodes(struct bt_conn *conn,
uint8_t inst_index);
int bt_tbs_client_read_optional_opcodes_safe(struct bt_conn *conn,
uint8_t inst_index);
@@ -1115,6 +1124,16 @@ int bt_tbs_client_register_cb_safe(struct bt_tbs_client_cb *cbs);
struct bt_tbs_instance *bt_tbs_client_get_by_ccid_safe(const struct bt_conn *conn,
uint8_t ccid);
/**
* @brief Look up Telephone Bearer Service instance by index
*
* @param conn The connection to the TBS server.
* @param index The index to lookup a service instance for.
*
* @return Pointer to a Telephone Bearer Service instance if found else NULL.
*/
struct bt_tbs_instance *bt_tbs_client_get_by_index_safe(const struct bt_conn *conn, uint8_t index);
#ifdef __cplusplus
}
#endif

View File

@@ -61,7 +61,10 @@ extern "C" {
#define BT_VCP_STATE_MUTED 0x01
/** @} */
/** @brief Opaque Volume Control Service instance. */
/**
* @struct bt_vcp_vol_ctlr
* @brief Opaque Volume Control Service instance.
*/
struct bt_vcp_vol_ctlr;
/** Register structure for Volume Control Service */

View File

@@ -66,7 +66,10 @@ extern "C" {
#define BT_VOCS_MAX_OFFSET 255
/** @} */
/** @brief Opaque Volume Offset Control Service instance. */
/**
* @struct bt_vocs
* @brief Opaque Volume Offset Control Service instance.
*/
struct bt_vocs;
/** @brief Structure for registering a Volume Offset Control Service instance. */

View File

@@ -551,7 +551,10 @@ struct bt_ots_obj_metadata {
uint32_t props;
};
/** @brief Opaque OTS instance. */
/**
* @struct bt_ots
* @brief Opaque OTS instance.
*/
struct bt_ots;
/** @brief Descriptor for OTS object addition */

View File

@@ -134,6 +134,7 @@ enum bt_cap_common_subproc_type;
enum bt_cap_common_proc_type;
struct bt_cap_stream;
struct bt_cap_broadcast_source;
struct bt_cap_common_proc;
struct bt_ots;
struct bt_ots_client;
@@ -174,6 +175,7 @@ extern bool lib_bap_broadcast_source_has_ep(const struct bt_bap_ep *ep);
#if CONFIG_BT_BAP_UNICAST_CLIENT
extern bool lib_bap_unicast_client_has_ep(const struct bt_bap_ep *ep);
extern struct bt_conn *lib_bap_unicast_client_ep_get_conn(const struct bt_bap_ep *ep);
extern int lib_bap_unicast_client_register_cb(struct bt_bap_unicast_client_cb *cb);
extern int lib_bap_unicast_client_config(struct bt_bap_stream *stream,
const struct bt_audio_codec_cfg *codec_cfg);
@@ -187,6 +189,7 @@ extern int lib_bap_unicast_client_release(struct bt_bap_stream *stream);
#if CONFIG_BT_BAP_UNICAST_SERVER
extern bool lib_bap_unicast_server_has_ep(const struct bt_bap_ep *ep);
extern struct bt_conn *lib_bap_unicast_server_ep_get_conn(const struct bt_bap_ep *ep);
extern int lib_bap_unicast_server_reconfig(struct bt_bap_stream *stream,
const struct bt_audio_codec_cfg *codec_cfg);
extern int lib_bap_unicast_server_start(struct bt_bap_stream *stream);
@@ -222,11 +225,11 @@ extern void lib_cap_initiator_released(struct bt_cap_stream *cap_stream);
#if CONFIG_BT_CAP_HANDOVER
extern bool lib_cap_common_handover_is_active(void);
extern bool lib_cap_handover_is_handover_broadcast_source(const struct bt_cap_broadcast_source *cap_broadcast_source);
extern void lib_cap_handover_complete(void);
extern void lib_cap_handover_unicast_proc_complete(void);
extern void lib_cap_handover_complete(struct bt_cap_common_proc *active_proc);
extern void lib_cap_handover_unicast_proc_complete(struct bt_cap_common_proc *active_proc);
extern void lib_cap_handover_broadcast_source_stopped(uint8_t reason);
extern void lib_cap_handover_unicast_to_broadcast_reception_start(void);
extern int lib_cap_handover_broadcast_reception_stopped(void);
extern int lib_cap_handover_broadcast_reception_stopped(struct bt_cap_common_proc *active_proc);
extern void lib_cap_handover_receive_state_updated(const struct bt_conn *conn,
const struct bt_bap_scan_delegator_recv_state *state);
#endif /* CONFIG_BT_CAP_HANDOVER */
@@ -340,6 +343,11 @@ extern struct bt_tbs_instance *lib_tbs_client_get_by_ccid(const struct bt_conn *
uint8_t ccid);
#endif /* CONFIG_BT_TBS_CLIENT_CCID */
#if CONFIG_BT_TBS_CLIENT
extern struct bt_tbs_instance *lib_tbs_client_get_by_index(const struct bt_conn *conn,
uint8_t index);
#endif /* CONFIG_BT_TBS_CLIENT */
#if CONFIG_BT_VCP_VOL_CTLR_AICS
extern void lib_vcp_vol_ctlr_aics_init(void);
#endif /* CONFIG_BT_VCP_VOL_CTLR_AICS */

View File

@@ -1851,7 +1851,7 @@ static void handle_gatts_read_event(struct bt_le_gatts_read_event *event)
} else {
ret = attr->read(conn, attr, (void *)rsp, GATT_MAX_ATTR_LEN, 0);
if (ret < 0) {
LOG_ERR("[B]GattsRdEvtFail[%u][%d]", event->attr_handle, ret);
LOG_DBG("[B]GattsRdEvtErr[%u][%d]", event->attr_handle, ret);
status = BT_GATT_ERR(ret);
}
@@ -1942,7 +1942,7 @@ static void handle_gatts_write_event(struct bt_le_gatts_write_event *event)
} else {
ret = attr->write(conn, attr, event->value, event->len, 0, 0);
if (ret < 0) {
LOG_ERR("[B]GattsWrEvtFail[%u][%d]", event->attr_handle, ret);
LOG_DBG("[B]GattsWrEvtErr[%u][%d]", event->attr_handle, ret);
status = BT_GATT_ERR(ret);
}

View File

@@ -162,7 +162,7 @@ int bt_conn_get_info(const struct bt_conn *conn, struct bt_conn_info *info)
info->id = conn->id;
info->state = conn_internal_to_public_state(conn->state);
info->le.dst = &conn->le.dst;
info->le.interval = conn->le.interval;
info->le.interval_us = conn->le.interval_us;
if (conn->encrypt) {
/* Currently the flags is updated for lib usage.
@@ -330,6 +330,15 @@ struct bt_conn *bt_conn_lookup_handle(uint16_t handle, enum bt_conn_type type)
return conn;
}
struct bt_conn *bt_conn_lookup_index(uint8_t index)
{
if (index >= ARRAY_SIZE(acl_conns)) {
return NULL;
}
return bt_conn_ref(&acl_conns[index]);
}
_IDF_ONLY
struct bt_conn *bt_le_acl_conn_find(uint16_t conn_handle)
{

View File

@@ -2,7 +2,7 @@
/*
* SPDX-FileCopyrightText: 2020 Intel Corporation
* SPDX-FileCopyrightText: 2021-2025 Nordic Semiconductor ASA
* SPDX-FileCopyrightText: 2021-2026 Nordic Semiconductor ASA
* SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
@@ -22,6 +22,7 @@
#include <zephyr/bluetooth/conn.h>
#include <zephyr/bluetooth/hci_types.h>
#include <zephyr/bluetooth/iso.h>
#include <zephyr/bluetooth/common/bt_str.h>
#include <zephyr/kernel.h>
#include <zephyr/logging/log.h>
#include <zephyr/net_buf.h>
@@ -61,6 +62,8 @@ struct bt_conn iso_conns[CONFIG_BT_ISO_MAX_CHAN];
struct bt_iso_cig cigs[CONFIG_BT_ISO_MAX_CIG];
static struct bt_iso_cig *get_cig(const struct bt_iso_chan *iso_chan);
static int hci_le_create_cis(const struct bt_iso_connect_param *param, size_t count);
#endif /* CONFIG_BT_ISO_CENTRAL */
#if defined(CONFIG_BT_ISO_PERIPHERAL)
@@ -220,65 +223,65 @@ static int validate_iso_setup_data_path_parms(const struct bt_iso_chan *chan, ui
struct bt_conn *iso;
CHECKIF(chan == NULL) {
LOG_DBG("ChanNull");
LOG_ERR("ChanNull");
return -EINVAL;
}
CHECKIF(path == NULL) {
LOG_DBG("PathNull");
LOG_ERR("PathNull");
return -EINVAL;
}
CHECKIF(dir != BT_HCI_DATAPATH_DIR_HOST_TO_CTLR &&
dir != BT_HCI_DATAPATH_DIR_CTLR_TO_HOST) {
LOG_DBG("InvDir[%u]", dir);
LOG_ERR("InvDir[%u]", dir);
return -EINVAL;
}
iso = chan->iso;
if (iso == NULL) {
LOG_DBG("ChanNotAssociated[%p]", chan);
LOG_ERR("ChanNotAssociated[%p]", chan);
return -ENODEV;
}
if (!iso->iso.info.can_recv && dir == BT_HCI_DATAPATH_DIR_CTLR_TO_HOST) {
LOG_DBG("InvDirForChanCannotRecv[%u][%p]", dir, chan);
LOG_ERR("InvDirForChanCannotRecv[%u][%p]", dir, chan);
return -EINVAL;
}
if (!iso->iso.info.can_send && dir == BT_HCI_DATAPATH_DIR_HOST_TO_CTLR) {
LOG_DBG("InvDirForChanCannotSend[%u][%p]", dir, chan);
LOG_ERR("InvDirForChanCannotSend[%u][%p]", dir, chan);
return -EINVAL;
}
CHECKIF(path->pid != BT_ISO_DATA_PATH_HCI &&
!IN_RANGE(path->pid, BT_ISO_DATA_PATH_VS_ID_MIN, BT_ISO_DATA_PATH_VS_ID_MAX)) {
LOG_DBG("InvPid[%u]", path->pid);
LOG_ERR("InvPid[%u]", path->pid);
return -EINVAL;
}
CHECKIF(path->format > BT_HCI_CODING_FORMAT_G729A &&
path->format != BT_HCI_CODING_FORMAT_VS) {
LOG_DBG("InvFormat[%u]", path->format);
LOG_ERR("InvFormat[%u]", path->format);
return -EINVAL;
}
CHECKIF(path->delay > BT_ISO_CONTROLLER_DELAY_MAX) {
LOG_DBG("InvDelay[%u]", path->delay);
LOG_ERR("InvDelay[%u]", path->delay);
return -EINVAL;
}
CHECKIF(path->cc_len > 0U && path->cc == NULL) {
LOG_DBG("NoCcProvidedForCcLen[%u]", path->cc_len);
LOG_ERR("NoCcProvidedForCcLen[%u]", path->cc_len);
return -EINVAL;
}
@@ -300,14 +303,14 @@ int bt_iso_setup_data_path(const struct bt_iso_chan *chan, uint8_t dir,
err = hci_le_setup_iso_data_path(chan->iso, dir, path);
if (err != 0) {
LOG_DBG("SetDataPathFail[%d]", err);
LOG_ERR("SetDataPathFail[%d]", err);
/* Return known possible errors */
if (err == -ENOBUFS || err == -EIO || err == -EACCES) {
return err;
}
LOG_DBG("UnkErrFromSetupIsoDataPath[%d]", err);
LOG_ERR("UnkErrFromSetupIsoDataPath[%d]", err);
return -ENOEXEC;
}
@@ -360,21 +363,21 @@ static int validate_iso_remove_data_path(const struct bt_iso_chan *chan, uint8_t
struct bt_conn *iso;
CHECKIF(chan == NULL) {
LOG_DBG("ChanNull");
LOG_ERR("ChanNull");
return -EINVAL;
}
CHECKIF(dir != BT_HCI_DATAPATH_DIR_HOST_TO_CTLR &&
dir != BT_HCI_DATAPATH_DIR_CTLR_TO_HOST) {
LOG_DBG("InvDir[%u]", dir);
LOG_ERR("InvDir[%u]", dir);
return -EINVAL;
}
iso = chan->iso;
if (iso == NULL) {
LOG_DBG("ChanNotAssociated[%p]", chan);
LOG_ERR("ChanNotAssociated[%p]", chan);
return -ENODEV;
}
@@ -393,14 +396,14 @@ int bt_iso_remove_data_path(const struct bt_iso_chan *chan, uint8_t dir)
err = hci_le_remove_iso_data_path(chan->iso, dir);
if (err != 0) {
LOG_DBG("RemoveDataPathFail[%d]", err);
LOG_ERR("RemoveDataPathFail[%d]", err);
/* Return known possible errors */
if (err == -ENOBUFS || err == -EIO || err == -EACCES) {
return err;
}
LOG_DBG("UnkErrFromRemoveIsoDataPath[%d]", err);
LOG_ERR("UnkErrFromRemoveIsoDataPath[%d]", err);
return -ENOEXEC;
}
@@ -438,7 +441,7 @@ static void bt_iso_chan_disconnected(struct bt_iso_chan *chan, uint8_t reason)
const uint8_t conn_type = chan->iso->iso.info.type;
LOG_DBG("IsoChanDisconnected[%02x]", reason);
LOG_INF("IsoChanDisconnected[%02x]", reason);
bt_iso_chan_set_state(chan, BT_ISO_STATE_DISCONNECTED);
bt_conn_set_state(chan->iso, BT_CONN_DISCONNECT_COMPLETE);
@@ -492,6 +495,7 @@ static void bt_iso_chan_disconnected(struct bt_iso_chan *chan, uint8_t reason)
* complete in the same way as ACL and CIS do. Call bt_conn_tx_notify directly here
* to flush the chan->iso->tx_complete for each disconnected BIS
*/
/* TBD: do we need to clean the BIS tx list here? */
} else {
/* No special handling for BT_ISO_CHAN_TYPE_SYNC_RECEIVER */
}
@@ -525,8 +529,6 @@ const char *bt_iso_chan_state_str(uint8_t state)
return "disconnected";
case BT_ISO_STATE_CONNECTING:
return "connecting";
case BT_ISO_STATE_ENCRYPT_PENDING:
return "encryption pending";
case BT_ISO_STATE_CONNECTED:
return "connected";
case BT_ISO_STATE_DISCONNECTING:
@@ -547,8 +549,6 @@ void bt_iso_chan_set_state_debug(struct bt_iso_chan *chan, enum bt_iso_state sta
case BT_ISO_STATE_DISCONNECTED:
/* regardless of old state always allows this states */
break;
case BT_ISO_STATE_ENCRYPT_PENDING:
__fallthrough;
case BT_ISO_STATE_CONNECTING:
if (chan->state != BT_ISO_STATE_DISCONNECTED) {
LOG_WRN("InvTransition[%s][%d]", func, line);
@@ -691,8 +691,8 @@ static bool valid_chan_io_qos(const struct bt_iso_chan_io_qos *io_qos, bool is_t
LOG_DBG("ValidChanIoQos[%u][%u][%u]", is_tx, is_broadcast, advanced);
if (io_qos->phy != BT_GAP_LE_PHY_1M &&
io_qos->phy != BT_GAP_LE_PHY_2M &&
io_qos->phy != BT_GAP_LE_PHY_CODED) {
io_qos->phy != BT_GAP_LE_PHY_2M &&
io_qos->phy != BT_GAP_LE_PHY_CODED) {
LOG_ERR("InvPhy[%u]", io_qos->phy);
return false;
@@ -816,17 +816,6 @@ int bt_iso_chan_disconnect(struct bt_iso_chan *chan)
return -ENOTCONN;
}
if (chan->state == BT_ISO_STATE_ENCRYPT_PENDING) {
LOG_WRN("ChanAlreadyDisconnected");
bt_iso_chan_set_state(chan, BT_ISO_STATE_DISCONNECTED);
if (chan->ops->disconnected) {
chan->ops->disconnected(chan, BT_HCI_ERR_LOCALHOST_TERM_CONN);
}
return 0;
}
if (chan->state == BT_ISO_STATE_DISCONNECTING) {
LOG_WRN("AlreadyDisconnecting");
@@ -950,14 +939,14 @@ static void store_cis_info(const struct bt_hci_evt_le_cis_established *evt, stru
central->bn = evt->c_bn;
central->phy = bt_get_phy(evt->c_phy);
central->latency = sys_get_le16(evt->c_latency);
central->latency = sys_get_le24(evt->c_latency);
central->max_pdu = sys_le16_to_cpu(evt->c_max_pdu);
/* Transform to n * 1.25ms */
central->flush_timeout = info->iso_interval * evt->c_ft;
peripheral->bn = evt->p_bn;
peripheral->phy = bt_get_phy(evt->p_phy);
peripheral->latency = sys_get_le16(evt->p_latency);
peripheral->latency = sys_get_le24(evt->p_latency);
peripheral->max_pdu = sys_le16_to_cpu(evt->p_max_pdu);
/* Transform to n * 1.25ms */
peripheral->flush_timeout = info->iso_interval * evt->p_ft;
@@ -1155,17 +1144,6 @@ int bt_iso_server_register(struct bt_iso_server *server)
return -EINVAL;
}
#if defined(CONFIG_BT_SMP)
if (server->sec_level > BT_SECURITY_L3) {
LOG_ERR("InvSrvSecLevel[%u]", server->sec_level);
return -EINVAL;
} else if (server->sec_level < BT_SECURITY_L1) {
LOG_DBG("SrvSecLevelUpdatedToL1");
/* Level 0 is only applicable for BR/EDR */
server->sec_level = BT_SECURITY_L1;
}
#endif /* CONFIG_BT_SMP */
iso_server = server;
return 0;
@@ -1218,10 +1196,6 @@ static int iso_accept(struct bt_conn *acl, struct bt_conn *iso)
return -ENOMEM;
}
#if defined(CONFIG_BT_SMP)
chan->required_sec_level = iso_server->sec_level;
#endif /* CONFIG_BT_SMP */
bt_iso_chan_add(iso, chan);
bt_iso_chan_set_state(chan, BT_ISO_STATE_CONNECTING);
@@ -1277,32 +1251,12 @@ static int hci_le_accept_cis(uint16_t handle)
return 0;
}
static uint8_t iso_server_check_security(struct bt_conn *conn)
{
LOG_DBG("IsoSrvCheckSec[%u][%u]", conn->sec_level, iso_server->sec_level);
if (IS_ENABLED(CONFIG_BT_CONN_DISABLE_SECURITY)) {
return BT_HCI_ERR_SUCCESS;
}
#if defined(CONFIG_BT_SMP)
if (conn->sec_level >= iso_server->sec_level) {
return BT_HCI_ERR_SUCCESS;
}
return BT_HCI_ERR_INSUFFICIENT_SECURITY;
#else
return BT_HCI_ERR_SUCCESS;
#endif /* CONFIG_BT_SMP */
}
void hci_le_cis_req(struct net_buf *buf)
{
struct bt_hci_evt_le_cis_req *evt = (void *)buf->data;
uint16_t acl_handle = sys_le16_to_cpu(evt->acl_handle);
uint16_t cis_handle = sys_le16_to_cpu(evt->cis_handle);
struct bt_conn *acl, *iso;
uint8_t sec_err;
int err;
LOG_DBG("CisReqEvt[%u][%u][%u][%u]",
@@ -1331,18 +1285,6 @@ void hci_le_cis_req(struct net_buf *buf)
return;
}
sec_err = iso_server_check_security(acl);
if (sec_err != BT_HCI_ERR_SUCCESS) {
LOG_DBG("InsuffSec[%u]", sec_err);
err = hci_le_reject_cis(cis_handle, sec_err);
if (err != 0) {
LOG_ERR("RejectCisFail[%d]", err);
}
bt_conn_unref(acl);
return;
}
/* Add ISO connection */
iso = bt_conn_add_iso(acl);
@@ -1361,7 +1303,7 @@ void hci_le_cis_req(struct net_buf *buf)
/* Request application to accept */
err = iso_accept(acl, iso);
if (err) {
LOG_DBG("AppRejectedCis[%d]", err);
LOG_INF("AppRejectedCis[%d]", err);
bt_iso_cleanup_acl(iso);
bt_conn_unref(iso);
hci_le_reject_cis(cis_handle, BT_HCI_ERR_INSUFFICIENT_RESOURCES);
@@ -1412,17 +1354,17 @@ static bool valid_chan_qos(const struct bt_iso_chan_qos *qos, bool advanced)
#endif /* CONFIG_BT_ISO_TEST_PARAMS */
if (qos->rx == NULL && qos->tx == NULL) {
LOG_DBG("BothRxAndTxQosNull");
LOG_ERR("BothRxAndTxQosNull");
return false;
}
if (qos->rx != NULL && !valid_chan_io_qos(qos->rx, false, false, advanced)) {
LOG_DBG("InvRxQos");
LOG_ERR("InvRxQos");
return false;
}
if (qos->tx != NULL && !valid_chan_io_qos(qos->tx, true, false, advanced)) {
LOG_DBG("InvTxQos");
LOG_ERR("InvTxQos");
return false;
}
@@ -1459,7 +1401,7 @@ static struct net_buf *hci_le_set_cig_params(const struct bt_iso_cig *cig,
struct net_buf *rsp;
int i, err;
LOG_DBG("SetCigParams[%u]", cig->id);
LOG_INF("SetCigParams[%u]", cig->id);
buf = bt_hci_cmd_create(BT_HCI_OP_LE_SET_CIG_PARAMS,
sizeof(*req) + sizeof(*cis_param) * param->num_cis);
@@ -1482,7 +1424,7 @@ static struct net_buf *hci_le_set_cig_params(const struct bt_iso_cig *cig,
req->framing = param->framing;
req->num_cis = param->num_cis;
LOG_DBG("[%u][%u][%u][%u][%u][%u][%u][%u][%u]",
LOG_INF("[%u][%u][%u][%u][%u][%u][%u][%u][%u]",
cig->id, param->c_to_p_latency, param->p_to_c_latency,
param->c_to_p_interval, param->p_to_c_interval, param->sca,
param->packing, param->framing, param->num_cis);
@@ -1526,7 +1468,7 @@ static struct net_buf *hci_le_set_cig_params(const struct bt_iso_cig *cig,
cis_param->p_rtn = qos->rx->rtn;
}
LOG_DBG("[%d]:[%u][%u][%u][%u][%u][%u][%u]",
LOG_INF("[%d]:[%u][%u][%u][%u][%u][%u][%u]",
i, cis_param->cis_id, cis_param->c_phy, cis_param->c_sdu,
cis_param->c_rtn, cis_param->p_phy, cis_param->p_sdu,
cis_param->p_rtn);
@@ -1550,7 +1492,7 @@ static struct net_buf *hci_le_set_cig_test_params(const struct bt_iso_cig *cig,
struct net_buf *rsp;
int err;
LOG_DBG("SetCigTestParams");
LOG_INF("SetCigTestParams");
buf = bt_hci_cmd_create(BT_HCI_OP_LE_SET_CIG_PARAMS_TEST,
sizeof(*req) + sizeof(*cis_param) * param->num_cis);
@@ -1574,7 +1516,7 @@ static struct net_buf *hci_le_set_cig_test_params(const struct bt_iso_cig *cig,
req->framing = param->framing;
req->num_cis = param->num_cis;
LOG_DBG("[%u][%u][%u][%u][%u][%u][%u][%u][%u][%u]",
LOG_INF("[%u][%u][%u][%u][%u][%u][%u][%u][%u][%u]",
cig->id, param->c_to_p_interval, param->p_to_c_interval,
param->c_to_p_ft, param->p_to_c_ft, param->iso_interval,
param->sca, param->packing, param->framing, param->num_cis);
@@ -1621,7 +1563,7 @@ static struct net_buf *hci_le_set_cig_test_params(const struct bt_iso_cig *cig,
cis_param->p_bn = qos->rx->burst_number;
}
LOG_DBG("[%d]:[%u][%u][%u][%u][%u][%u][%u][%u][%u][%u]",
LOG_INF("[%d]:[%u][%u][%u][%u][%u][%u][%u][%u][%u][%u]",
i, cis_param->cis_id, cis_param->nse, cis_param->c_sdu,
cis_param->p_sdu, cis_param->c_pdu, cis_param->p_pdu,
cis_param->c_phy, cis_param->p_phy, cis_param->c_bn,
@@ -1638,7 +1580,7 @@ static struct net_buf *hci_le_set_cig_test_params(const struct bt_iso_cig *cig,
static bool is_advanced_cig_param(const struct bt_iso_cig_param *param)
{
LOG_DBG("IsAdvancedCigParam[%u][%u][%u]",
LOG_INF("IsAdvancedCigParam[%u][%u][%u]",
param->c_to_p_ft, param->p_to_c_ft, param->iso_interval);
if (param->c_to_p_ft != 0U || param->p_to_c_ft != 0U || param->iso_interval != 0U) {
@@ -1673,7 +1615,7 @@ static bool is_advanced_cig_param(const struct bt_iso_cig_param *param)
static struct bt_iso_cig *get_cig(const struct bt_iso_chan *iso_chan)
{
LOG_DBG("GetCig[%p]", iso_chan);
LOG_INF("GetCig[%p]", iso_chan);
if (iso_chan == NULL || iso_chan->iso == NULL) {
return NULL;
@@ -1688,19 +1630,19 @@ static struct bt_iso_cig *get_free_cig(void)
{
/* We can use the index in the `cigs` array as CIG ID */
LOG_DBG("GetFreeCig");
LOG_INF("GetFreeCig");
for (size_t i = 0; i < ARRAY_SIZE(cigs); i++) {
if (cigs[i].state == BT_ISO_CIG_STATE_IDLE) {
cigs[i].state = BT_ISO_CIG_STATE_CONFIGURED;
cigs[i].id = i;
sys_slist_init(&cigs[i].cis_channels);
LOG_DBG("CigNew[%zu]", i);
LOG_INF("CigNew[%zu]", i);
return &cigs[i];
}
}
LOG_ERR("NoFreeCig");
LOG_WRN("NoFreeCig");
return NULL;
}
@@ -1716,7 +1658,7 @@ static bool cis_is_in_cig(const struct bt_iso_cig *cig, const struct bt_iso_chan
static int cig_init_cis(struct bt_iso_cig *cig, const struct bt_iso_cig_param *param)
{
LOG_DBG("CigInitCis[%u]", cig->id);
LOG_INF("CigInitCis[%u]", cig->id);
for (uint8_t i = 0; i < param->num_cis; i++) {
struct bt_iso_chan *cis = param->cis_channels[i];
@@ -1726,7 +1668,7 @@ static int cig_init_cis(struct bt_iso_cig *cig, const struct bt_iso_cig_param *p
cis->iso = iso_new();
if (cis->iso == NULL) {
LOG_ERR("NoFreeCis");
LOG_WRN("NoFreeCis");
return -ENOMEM;
}
iso_conn = &cis->iso->iso;
@@ -1748,7 +1690,7 @@ static void cleanup_cig(struct bt_iso_cig *cig)
{
struct bt_iso_chan *cis, *tmp;
LOG_DBG("CleanupCig");
LOG_INF("CleanupCig");
SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&cig->cis_channels, cis, tmp, node) {
if (cis->iso != NULL) {
@@ -1818,6 +1760,15 @@ static bool valid_cig_param(const struct bt_iso_cig_param *param, bool advanced,
if (cis->qos->tx != NULL && cis->qos->tx->sdu != 0U) {
is_c_to_p = true;
}
/* Validate the current CIS, not the cumulative is_*_to_* flags: once an
* earlier CIS sets a direction the flags would mask a later CIS that has none.
*/
if ((cis->qos->rx == NULL || cis->qos->rx->sdu == 0U) &&
(cis->qos->tx == NULL || cis->qos->tx->sdu == 0U)) {
LOG_ERR("InvNoSduDir[%u]", i);
return false;
}
}
if (param->framing != BT_ISO_FRAMING_UNFRAMED && param->framing != BT_ISO_FRAMING_FRAMED) {
@@ -1941,7 +1892,7 @@ int bt_iso_cig_create(const struct bt_iso_cig_param *param, struct bt_iso_cig **
err = cig_init_cis(cig, param);
if (err) {
LOG_DBG("InitCisFail[%d]", err);
LOG_WRN("InitCisFail[%d]", err);
cleanup_cig(cig);
return err;
}
@@ -1984,7 +1935,7 @@ int bt_iso_cig_create(const struct bt_iso_cig_param *param, struct bt_iso_cig **
*out_cig = cig;
LOG_DBG("OutCig[%u]", cig->id);
LOG_INF("OutCig[%u]", cig->id);
return err;
}
@@ -1994,7 +1945,7 @@ static void restore_cig(struct bt_iso_cig *cig, uint8_t existing_num_cis)
struct bt_iso_chan *cis, *tmp;
sys_snode_t *prev = NULL;
LOG_DBG("RestoreCig[%u][%u]", cig->id, existing_num_cis);
LOG_INF("RestoreCig[%u][%u]", cig->id, existing_num_cis);
SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&cig->cis_channels, cis, tmp, node) {
/* Remove all newly added by comparing the cis_id to the number
@@ -2045,7 +1996,7 @@ int bt_iso_cig_reconfigure(struct bt_iso_cig *cig, const struct bt_iso_cig_param
#endif /* CONFIG_BT_ISO_TEST_PARAMS */
CHECKIF(!valid_cig_param(param, advanced, cig)) {
LOG_DBG("InvCigParams");
LOG_ERR("InvCigParams");
return -EINVAL;
}
@@ -2054,7 +2005,7 @@ int bt_iso_cig_reconfigure(struct bt_iso_cig *cig, const struct bt_iso_cig_param
err = cig_init_cis(cig, param);
if (err != 0) {
LOG_DBG("InitCisFail[%d]", err);
LOG_ERR("InitCisFail[%d]", err);
restore_cig(cig, existing_num_cis);
return err;
}
@@ -2111,7 +2062,7 @@ int bt_iso_cig_terminate(struct bt_iso_cig *cig)
{
int err;
LOG_DBG("IsoCigTerminate");
LOG_INF("IsoCigTerminate");
CHECKIF(cig == NULL) {
LOG_ERR("CigNull");
@@ -2140,7 +2091,7 @@ static int hci_le_create_cis(const struct bt_iso_connect_param *param, size_t co
struct bt_hci_cp_le_create_cis *req;
struct net_buf *buf;
LOG_DBG("CreateCis[%u]", count);
LOG_INF("CreateCis[%u]", count);
buf = bt_hci_cmd_create(BT_HCI_OP_LE_CREATE_CIS, sizeof(*req) + sizeof(*cis) * count);
if (!buf) {
@@ -2153,12 +2104,6 @@ static int hci_le_create_cis(const struct bt_iso_connect_param *param, size_t co
/* Program the cis parameters */
for (size_t i = 0; i < count; i++) {
struct bt_iso_chan *iso_chan = param[i].iso_chan;
if (iso_chan->state == BT_ISO_STATE_ENCRYPT_PENDING) {
continue;
}
cis = net_buf_add(buf, sizeof(*cis));
memset(cis, 0, sizeof(*cis));
@@ -2168,90 +2113,25 @@ static int hci_le_create_cis(const struct bt_iso_connect_param *param, size_t co
req->num_cis++;
}
/* If all CIS are pending for security, do nothing,
* but return a recognizable return value
*/
if (req->num_cis == 0) {
net_buf_unref(buf);
return -ECANCELED;
}
return bt_hci_cmd_send_sync(BT_HCI_OP_LE_CREATE_CIS, buf, NULL);
}
#if defined(CONFIG_BT_SMP)
static int iso_chan_connect_security(const struct bt_iso_connect_param *param, size_t count)
{
/* conn_idx_handled is an array of booleans for which conn indexes
* already have been used to call bt_conn_set_security.
* Using indexes avoids looping the array when checking if it has been
* handled.
*/
bool conn_idx_handled[CONFIG_BT_MAX_CONN];
LOG_DBG("IsoChanConnectSec[%u]", count);
memset(conn_idx_handled, false, sizeof(conn_idx_handled));
for (size_t i = 0; i < count; i++) {
struct bt_iso_chan *iso_chan = param[i].iso_chan;
struct bt_conn *acl = param[i].acl;
uint8_t conn_idx = bt_conn_index(acl);
LOG_DBG("SecLevel[%zu][%u][%u]",
i, acl->sec_level, iso_chan->required_sec_level);
if (acl->sec_level < iso_chan->required_sec_level) {
if (!conn_idx_handled[conn_idx]) {
int err;
err = bt_conn_set_security(acl, iso_chan->required_sec_level);
if (err != 0) {
LOG_ERR("SetSecFail[%zu][%d]", i, err);
/* Restore states */
for (size_t j = 0; j < i; j++) {
iso_chan = param[j].iso_chan;
if (iso_chan->state == BT_ISO_STATE_ENCRYPT_PENDING) {
bt_iso_cleanup_acl(iso_chan->iso);
bt_iso_chan_set_state(iso_chan,
BT_ISO_STATE_DISCONNECTED);
}
}
return err;
}
conn_idx_handled[conn_idx] = true;
}
iso_chan->iso->iso.acl = bt_conn_ref(acl);
bt_iso_chan_set_state(iso_chan, BT_ISO_STATE_ENCRYPT_PENDING);
}
}
return 0;
}
#endif /* CONFIG_BT_SMP */
static bool iso_chans_connecting(void)
{
LOG_DBG("IsoChansConnecting");
LOG_INF("IsoChansConnecting");
for (size_t i = 0U; i < ARRAY_SIZE(iso_conns); i++) {
const struct bt_conn *iso = &iso_conns[i];
const struct bt_iso_chan *iso_chan;
if (!(iso->iso.info.type == BT_ISO_CHAN_TYPE_CENTRAL ||
iso->iso.info.type == BT_ISO_CHAN_TYPE_PERIPHERAL)) {
iso->iso.info.type == BT_ISO_CHAN_TYPE_PERIPHERAL)) {
continue;
}
iso_chan = iso_chan(iso);
if (iso_chan != NULL &&
(iso_chan->state == BT_ISO_STATE_CONNECTING ||
iso_chan->state == BT_ISO_STATE_ENCRYPT_PENDING)) {
iso_chan->state == BT_ISO_STATE_CONNECTING) {
return true;
}
}
@@ -2263,7 +2143,7 @@ int bt_iso_chan_connect(const struct bt_iso_connect_param *param, size_t count)
{
int err;
LOG_DBG("IsoChanConnect[%u]", count);
LOG_INF("IsoChanConnect[%u]", count);
CHECKIF(param == NULL) {
LOG_ERR("ParamNull");
@@ -2313,23 +2193,8 @@ int bt_iso_chan_connect(const struct bt_iso_connect_param *param, size_t count)
return -EBUSY;
}
#if defined(CONFIG_BT_SMP)
/* Check for and initiate security for all channels that have
* requested encryption if the ACL link is not already secured
*/
err = iso_chan_connect_security(param, count);
if (err != 0) {
LOG_ERR("InitSecForCisFail[%d]", err);
return err;
}
#endif /* CONFIG_BT_SMP */
err = hci_le_create_cis(param, count);
if (err == -ECANCELED) {
LOG_DBG("CisPendingOnSec");
return 0;
} else if (err != 0) {
if (err != 0) {
LOG_ERR("ConnectCisFail[%d]", err);
return err;
@@ -2340,10 +2205,6 @@ int bt_iso_chan_connect(const struct bt_iso_connect_param *param, size_t count)
struct bt_iso_chan *iso_chan = param[i].iso_chan;
struct bt_iso_cig *cig;
if (iso_chan->state == BT_ISO_STATE_ENCRYPT_PENDING) {
continue;
}
iso_chan->iso->iso.acl = bt_conn_ref(param[i].acl);
bt_conn_set_state(iso_chan->iso, BT_CONN_INITIATING);
bt_iso_chan_set_state(iso_chan, BT_ISO_STATE_CONNECTING);
@@ -2379,12 +2240,12 @@ static struct bt_iso_big *get_free_big(void)
if (!atomic_test_and_set_bit(bigs[i].flags, BT_BIG_INITIALIZED)) {
bigs[i].handle = i;
sys_slist_init(&bigs[i].bis_channels);
LOG_DBG("BigNew[%u]", i);
LOG_INF("BigNew[%u]", i);
return &bigs[i];
}
}
LOG_ERR("NoFreeBig");
LOG_WRN("NoFreeBig");
return NULL;
}
@@ -2428,7 +2289,7 @@ static void big_disconnect(struct bt_iso_big *big, uint8_t reason)
{
struct bt_iso_chan *bis;
LOG_DBG("BigDisconnect[%02x]", reason);
LOG_INF("BigDisconnect[%02x]", reason);
atomic_set_bit(big->flags, BT_BIG_BUSY);
@@ -2457,13 +2318,13 @@ static void big_disconnect(struct bt_iso_big *big, uint8_t reason)
static int big_init_bis(struct bt_iso_big *big, struct bt_iso_chan *bis, uint8_t bis_number,
bool broadcaster)
{
LOG_DBG("BigInitBis[%u][%u][%u]", big->handle, bis_number, broadcaster);
LOG_INF("BigInitBis[%u][%u][%u]", big->handle, bis_number, broadcaster);
struct bt_conn_iso *iso_conn;
bis->iso = iso_new();
if (bis->iso == NULL) {
LOG_ERR("NoFreeBis");
LOG_WRN("NoFreeBis");
return -ENOMEM;
}
@@ -2494,13 +2355,13 @@ static int big_init_bis(struct bt_iso_big *big, struct bt_iso_chan *bis, uint8_t
int bt_iso_big_register_cb(struct bt_iso_big_cb *cb)
{
CHECKIF(cb == NULL) {
LOG_DBG("BigCbNull");
LOG_ERR("BigCbNull");
return -EINVAL;
}
if (sys_slist_find(&iso_big_cbs, &cb->_node, NULL)) {
LOG_DBG("BigCbAlreadyReg[%p]", cb);
LOG_WRN("BigCbAlreadyReg[%p]", cb);
return -EEXIST;
}
@@ -2520,7 +2381,7 @@ static int hci_le_create_big(struct bt_le_ext_adv *padv, struct bt_iso_big *big,
int err;
struct bt_iso_chan *bis;
LOG_DBG("CreateBig");
LOG_INF("CreateBig");
buf = bt_hci_cmd_create(BT_HCI_OP_LE_CREATE_BIG, sizeof(*req));
@@ -2552,12 +2413,12 @@ static int hci_le_create_big(struct bt_le_ext_adv *padv, struct bt_iso_big *big,
memset(req->bcode, 0, sizeof(req->bcode));
}
LOG_DBG("[%u][%u][%u][%u][%u][%u][%u][%u][%u][%u][%u]",
LOG_INF("[%u][%u][%u][%u][%u][%u][%u][%u][%u][%u][%u]",
req->big_handle, req->adv_handle, req->num_bis, param->interval,
req->max_sdu, req->max_latency, req->rtn, req->phy, req->packing,
req->framing, req->encryption);
if (req->encryption) {
LOG_DBG("[%s]", bt_hex(req->bcode, sizeof(req->bcode)));
LOG_INF("[%s]", bt_hex(req->bcode, sizeof(req->bcode)));
}
err = bt_hci_cmd_send_sync(BT_HCI_OP_LE_CREATE_BIG, buf, NULL);
@@ -2583,7 +2444,7 @@ static int hci_le_create_big_test(const struct bt_le_ext_adv *padv, struct bt_is
struct net_buf *buf;
int err;
LOG_DBG("CreateBigTest");
LOG_INF("CreateBigTest");
buf = bt_hci_cmd_create(BT_HCI_OP_LE_CREATE_BIG_TEST, sizeof(*req));
@@ -2619,13 +2480,13 @@ static int hci_le_create_big_test(const struct bt_le_ext_adv *padv, struct bt_is
memset(req->bcode, 0, sizeof(req->bcode));
}
LOG_DBG("[%u][%u][%u][%u][%u][%u][%u][%u][%u][%u][%u][%u][%u][%u][%u]",
LOG_INF("[%u][%u][%u][%u][%u][%u][%u][%u][%u][%u][%u][%u][%u][%u][%u]",
req->big_handle, req->adv_handle, req->num_bis, param->interval,
param->iso_interval, req->nse, req->max_sdu, req->max_pdu,
req->phy, req->packing, req->framing, req->bn, req->irc,
req->pto, req->encryption);
if (req->encryption) {
LOG_DBG("[%s]", bt_hex(req->bcode, sizeof(req->bcode)));
LOG_INF("[%s]", bt_hex(req->bcode, sizeof(req->bcode)));
}
err = bt_hci_cmd_send_sync(BT_HCI_OP_LE_CREATE_BIG_TEST, buf, NULL);
@@ -2642,7 +2503,7 @@ static int hci_le_create_big_test(const struct bt_le_ext_adv *padv, struct bt_is
static bool is_advanced_big_param(const struct bt_iso_big_create_param *param)
{
LOG_DBG("IsAdvancedBigParam[%u][%u]", param->irc, param->iso_interval);
LOG_INF("IsAdvancedBigParam[%u][%u]", param->irc, param->iso_interval);
if (param->irc != 0U || param->iso_interval != 0U) {
return true;
@@ -2823,7 +2684,7 @@ int bt_iso_big_create(struct bt_le_ext_adv *padv, struct bt_iso_big_create_param
err = big_init_bis(big, bis_channels[i], bis_number, true);
if (err != 0) {
LOG_DBG("InitBisFail[%u][%d]", i, err);
LOG_ERR("InitBisFail[%u][%d]", i, err);
cleanup_big(big);
return err;
@@ -2848,7 +2709,7 @@ int bt_iso_big_create(struct bt_le_ext_adv *padv, struct bt_iso_big_create_param
*out_big = big;
LOG_DBG("OutBig[%u]", big->handle);
LOG_INF("OutBig[%u]", big->handle);
return err;
}
@@ -2877,7 +2738,7 @@ static void store_bis_broadcaster_info(const struct bt_hci_evt_le_big_complete *
info->can_send = true;
info->can_recv = false;
LOG_DBG("StoreBisInfo[%u]", broadcaster_info->pto);
LOG_INF("StoreBisInfo[%u]", broadcaster_info->pto);
}
void hci_le_big_complete(struct net_buf *buf)
@@ -2887,8 +2748,8 @@ void hci_le_big_complete(struct net_buf *buf)
struct bt_iso_big *big;
int i;
LOG_DBG("BigComp");
LOG_DBG("Evt[%02x][%u][%u][%u][%u][%u][%u][%u][%u][%u][%u][%u]",
LOG_INF("BigComp");
LOG_INF("Evt[%02x][%u][%u][%u][%u][%u][%u][%u][%u][%u][%u][%u]",
evt->status, evt->big_handle, sys_get_le24(evt->sync_delay),
sys_get_le24(evt->latency), evt->phy, evt->nse, evt->bn,
evt->pto, evt->irc, evt->max_pdu, evt->iso_interval,
@@ -2925,7 +2786,7 @@ void hci_le_big_complete(struct net_buf *buf)
const uint16_t handle = evt->handle[i++];
struct bt_conn *iso_conn = bis->iso;
LOG_DBG("BisHdl[%04x]", handle);
LOG_INF("BisHdl[%04x]", handle);
iso_conn->handle = sys_le16_to_cpu(handle);
store_bis_broadcaster_info(evt, iso_conn);
@@ -2950,7 +2811,7 @@ void hci_le_big_terminate(struct net_buf *buf)
struct bt_hci_evt_le_big_terminate *evt = (void *)buf->data;
struct bt_iso_big *big;
LOG_DBG("BigTerminateEvt[%u][%02x]", evt->big_handle, evt->reason);
LOG_INF("BigTerminateEvt[%u][%02x]", evt->big_handle, evt->reason);
if (evt->big_handle >= ARRAY_SIZE(bigs)) {
LOG_ERR("InvBigHdl[%u][%u]", evt->big_handle, ARRAY_SIZE(bigs));
@@ -3041,7 +2902,7 @@ int bt_iso_big_terminate(struct bt_iso_big *big)
}
if (atomic_test_bit(big->flags, BT_BIG_BUSY)) {
LOG_DBG("BigBusy[%u]", big->handle);
LOG_WRN("BigBusy[%u]", big->handle);
return -EBUSY;
}
@@ -3111,8 +2972,8 @@ void hci_le_big_sync_established(struct net_buf *buf)
struct bt_iso_big *big;
int i;
LOG_DBG("BigSyncEstab");
LOG_DBG("Evt[%02x][%u][%u][%u][%u][%u][%u][%u][%u][%u]",
LOG_INF("BigSyncEstab");
LOG_INF("Evt[%02x][%u][%u][%u][%u][%u][%u][%u][%u][%u]",
evt->status, evt->big_handle, sys_get_le24(evt->latency),
evt->nse, evt->bn, evt->pto, evt->irc, evt->max_pdu,
evt->iso_interval, evt->num_bis);
@@ -3148,7 +3009,7 @@ void hci_le_big_sync_established(struct net_buf *buf)
const uint16_t handle = evt->handle[i++];
struct bt_conn *iso_conn = bis->iso;
LOG_DBG("BisHdl[%04x]", handle);
LOG_INF("BisHdl[%04x]", handle);
iso_conn->handle = sys_le16_to_cpu(handle);
store_bis_sync_receiver_info(evt, iso_conn);
@@ -3173,7 +3034,7 @@ void hci_le_big_sync_lost(struct net_buf *buf)
struct bt_hci_evt_le_big_sync_lost *evt = (void *)buf->data;
struct bt_iso_big *big;
LOG_DBG("BigSyncLostEvt[%u][%02x]", evt->big_handle, evt->reason);
LOG_INF("BigSyncLostEvt[%u][%02x]", evt->big_handle, evt->reason);
if (evt->big_handle >= ARRAY_SIZE(bigs)) {
LOG_ERR("InvBigHdl[%u][%u]", evt->big_handle, ARRAY_SIZE(bigs));
@@ -3195,7 +3056,7 @@ static int hci_le_big_create_sync(const struct bt_le_per_adv_sync *sync, struct
int err;
uint8_t bit_idx = 0;
LOG_DBG("BigCreateSync[%u][%u]", big->handle, big->num_bis);
LOG_INF("BigCreateSync[%u][%u]", big->handle, big->num_bis);
buf = bt_hci_cmd_create(BT_HCI_OP_LE_BIG_CREATE_SYNC, sizeof(*req) + big->num_bis);
if (!buf) {
@@ -3346,7 +3207,7 @@ int bt_iso_big_sync(struct bt_le_per_adv_sync *sync, struct bt_iso_big_sync_para
*/
err = big_init_bis(big, bis_channels[i], bis_number, false);
if (err != 0) {
LOG_DBG("InitBisFail[%u]: %d", i, err);
LOG_ERR("InitBisFail[%u]: %d", i, err);
cleanup_big(big);
return err;
@@ -3357,7 +3218,7 @@ int bt_iso_big_sync(struct bt_le_per_adv_sync *sync, struct bt_iso_big_sync_para
err = hci_le_big_create_sync(sync, big, param);
if (err) {
LOG_DBG("CreateBigSyncFail[%d]", err);
LOG_ERR("CreateBigSyncFail[%d]", err);
cleanup_big(big);
return err;
}
@@ -3368,7 +3229,7 @@ int bt_iso_big_sync(struct bt_le_per_adv_sync *sync, struct bt_iso_big_sync_para
*out_big = big;
LOG_DBG("OutBig[%u]", big->handle);
LOG_INF("OutBig[%u]", big->handle);
return 0;
}

View File

@@ -29,7 +29,7 @@ typedef enum __packed {
struct bt_conn_le {
bt_addr_le_t dst;
uint16_t interval;
uint32_t interval_us;
/** @brief Remote LE features
*
@@ -114,5 +114,7 @@ bool bt_conn_is_peer_addr_le(const struct bt_conn *conn, uint8_t id,
*/
#define BT_CONN_INDEX_INVALID 0xff
struct bt_conn *bt_conn_lookup_index(uint8_t index);
/* Set connection object in certain state and perform action related to state */
void bt_conn_set_state(struct bt_conn *conn, bt_conn_state_t state);

View File

@@ -112,7 +112,7 @@ struct bt_conn_le_info {
* Address (RPA) before identity has been resolved.
*/
const bt_addr_le_t *dst;
uint16_t interval; /**< Connection interval */
uint32_t interval_us; /**< Connection interval in microseconds */
};
/** @brief Convert connection interval to milliseconds

View File

@@ -182,8 +182,6 @@ extern "C" {
enum bt_iso_state {
/** Channel disconnected */
BT_ISO_STATE_DISCONNECTED,
/** Channel is pending ACL encryption before connecting */
BT_ISO_STATE_ENCRYPT_PENDING,
/** Channel in connecting state */
BT_ISO_STATE_CONNECTING,
/** Channel ready for upper layer traffic on it */
@@ -213,17 +211,6 @@ struct bt_iso_chan {
struct bt_iso_chan_qos *qos;
/** Channel state */
enum bt_iso_state state;
/**
* @brief The required security level of the channel
*
* This value can be set as the central before connecting a CIS
* with bt_iso_chan_connect().
* The value is overwritten to @ref bt_iso_server::sec_level for the
* peripheral once a channel has been accepted.
*
* Only available when @kconfig{CONFIG_BT_SMP} is enabled.
*/
bt_security_t required_sec_level;
/** @internal Node used internally by the stack */
sys_snode_t node;
};
@@ -783,13 +770,6 @@ struct bt_iso_accept_info {
/** @brief ISO Server structure. */
struct bt_iso_server {
/**
* @brief Required minimum security level.
*
* Only available when @kconfig{CONFIG_BT_SMP} is enabled.
*/
bt_security_t sec_level;
/**
* @brief Server accept callback
*

View File

@@ -120,7 +120,6 @@ static esp_ble_iso_chan_qos_t iso_qos = {
static esp_ble_iso_chan_t iso_chan = {
.ops = &iso_ops,
.qos = &iso_qos,
.required_sec_level = SECURITY_LEVEL,
};
static void create_cig_and_cis(uint16_t acl_handle)
@@ -253,8 +252,8 @@ static void acl_connect(esp_ble_iso_gap_app_event_t *event)
event->acl_connect.conn_handle, event->acl_connect.role,
EXAMPLE_BT_ADDR_PRINT_ARGS(event->acl_connect.dst.val));
if (iso_chan.required_sec_level == ESP_BLE_ISO_SECURITY_NO_MITM ||
iso_chan.required_sec_level == ESP_BLE_ISO_SECURITY_MITM) {
if (SECURITY_LEVEL == ESP_BLE_ISO_SECURITY_NO_MITM ||
SECURITY_LEVEL == ESP_BLE_ISO_SECURITY_MITM) {
err = pairing_start(event->acl_connect.conn_handle);
if (err) {
ESP_LOGE(TAG, "Failed to initiate security, err %d", err);

View File

@@ -19,8 +19,6 @@
#include "peripheral.h"
#define SECURITY_LEVEL ESP_BLE_ISO_SECURITY_NO_MITM
#define CIS_SDU_SIZE 120
static uint8_t ext_adv_data[3 + 2 + LOCAL_DEVICE_NAME_LEN];
@@ -95,7 +93,6 @@ static int iso_accept(const esp_ble_iso_accept_info_t *info,
}
static esp_ble_iso_server_t iso_server = {
.sec_level = SECURITY_LEVEL,
.accept = iso_accept,
};