feat(ble_audio): Support running ISO & LE Audio with Bluedroid Host

This commit is contained in:
Liu Linyan
2026-05-29 17:24:54 +08:00
parent 6cd0e56ae2
commit 8dbef3bad4
223 changed files with 14714 additions and 2347 deletions
@@ -0,0 +1,43 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef HOST_BLUEDROID_INIT_H_
#define HOST_BLUEDROID_INIT_H_
#include <stdint.h>
#include "bluedroid/server.h"
#include "bluedroid/profiles/ascs.h"
#include "bluedroid/profiles/bass.h"
#include "bluedroid/profiles/cas.h"
#include "bluedroid/profiles/csis.h"
#include "bluedroid/profiles/mcs.h"
#include "bluedroid/profiles/mics.h"
#include "bluedroid/profiles/pacs.h"
#include "bluedroid/profiles/tbs.h"
#include "bluedroid/profiles/tmas.h"
#include "bluedroid/profiles/vcs.h"
#include "bluedroid/profiles/has.h"
#ifdef __cplusplus
extern "C" {
#endif
int bt_le_bluedroid_audio_init(void);
int bt_le_bluedroid_media_proxy_pl_init(void);
int bt_le_bluedroid_vcp_vol_rend_init(void);
int bt_le_bluedroid_micp_mic_dev_init(void);
int bt_le_bluedroid_audio_start(void *info);
#ifdef __cplusplus
}
#endif
#endif /* HOST_BLUEDROID_INIT_H_ */
@@ -0,0 +1,25 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef HOST_BLUEDROID_PROFILE_ASCS_H_
#define HOST_BLUEDROID_PROFILE_ASCS_H_
#include <stdint.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
int bt_le_bluedroid_ascs_init(void);
int bt_le_bluedroid_ascs_start(void);
#ifdef __cplusplus
}
#endif
#endif /* HOST_BLUEDROID_PROFILE_ASCS_H_ */
@@ -0,0 +1,25 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef HOST_BLUEDROID_PROFILE_BASS_H_
#define HOST_BLUEDROID_PROFILE_BASS_H_
#include <stdint.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
int bt_le_bluedroid_bass_init(void);
int bt_le_bluedroid_bass_start(void);
#ifdef __cplusplus
}
#endif
#endif /* HOST_BLUEDROID_PROFILE_BASS_H_ */
@@ -0,0 +1,25 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef HOST_BLUEDROID_PROFILE_CAS_H_
#define HOST_BLUEDROID_PROFILE_CAS_H_
#include <stdint.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
int bt_le_bluedroid_cas_init(void *csis_svc_p);
int bt_le_bluedroid_cas_start(void);
#ifdef __cplusplus
}
#endif
#endif /* HOST_BLUEDROID_PROFILE_CAS_H_ */
@@ -0,0 +1,25 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef HOST_BLUEDROID_PROFILE_CSIS_H_
#define HOST_BLUEDROID_PROFILE_CSIS_H_
#include <stdint.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
int bt_le_bluedroid_csis_init(void *csis_svc, uint8_t count);
int bt_le_bluedroid_csis_start(void);
#ifdef __cplusplus
}
#endif
#endif /* HOST_BLUEDROID_PROFILE_CSIS_H_ */
@@ -0,0 +1,25 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef HOST_BLUEDROID_PROFILE_HAS_H_
#define HOST_BLUEDROID_PROFILE_HAS_H_
#include <stdint.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
int bt_le_bluedroid_has_init(void);
int bt_le_bluedroid_has_start(void);
#ifdef __cplusplus
}
#endif
#endif /* HOST_BLUEDROID_PROFILE_HAS_H_ */
@@ -0,0 +1,25 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef HOST_BLUEDROID_PROFILE_MCS_H_
#define HOST_BLUEDROID_PROFILE_MCS_H_
#include <stdint.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
int bt_le_bluedroid_gmcs_init(void);
int bt_le_bluedroid_gmcs_start(void);
#ifdef __cplusplus
}
#endif
#endif /* HOST_BLUEDROID_PROFILE_MCS_H_ */
@@ -0,0 +1,25 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef HOST_BLUEDROID_PROFILE_MICS_H_
#define HOST_BLUEDROID_PROFILE_MICS_H_
#include <stdint.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
int bt_le_bluedroid_mics_init(void *micp_inc);
int bt_le_bluedroid_mics_start(void);
#ifdef __cplusplus
}
#endif
#endif /* HOST_BLUEDROID_PROFILE_MICS_H_ */
@@ -0,0 +1,25 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef HOST_BLUEDROID_PROFILE_PACS_H_
#define HOST_BLUEDROID_PROFILE_PACS_H_
#include <stdint.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
int bt_le_bluedroid_pacs_init(void);
int bt_le_bluedroid_pacs_start(void);
#ifdef __cplusplus
}
#endif
#endif /* HOST_BLUEDROID_PROFILE_PACS_H_ */
@@ -0,0 +1,25 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef HOST_BLUEDROID_PROFILE_TBS_H_
#define HOST_BLUEDROID_PROFILE_TBS_H_
#include <stdint.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
int bt_le_bluedroid_gtbs_init(void);
int bt_le_bluedroid_gtbs_start(void);
#ifdef __cplusplus
}
#endif
#endif /* HOST_BLUEDROID_PROFILE_TBS_H_ */
@@ -0,0 +1,25 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef HOST_BLUEDROID_PROFILE_TMAS_H_
#define HOST_BLUEDROID_PROFILE_TMAS_H_
#include <stdint.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
int bt_le_bluedroid_tmas_init(void);
int bt_le_bluedroid_tmas_start(void);
#ifdef __cplusplus
}
#endif
#endif /* HOST_BLUEDROID_PROFILE_TMAS_H_ */
@@ -0,0 +1,25 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef HOST_BLUEDROID_PROFILE_VCS_H_
#define HOST_BLUEDROID_PROFILE_VCS_H_
#include <stdint.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
int bt_le_bluedroid_vcs_init(void *vcp_inc);
int bt_le_bluedroid_vcs_start(void);
#ifdef __cplusplus
}
#endif
#endif /* HOST_BLUEDROID_PROFILE_VCS_H_ */
@@ -0,0 +1,172 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef HOST_BLUEDROID_SERVER_H_
#define HOST_BLUEDROID_SERVER_H_
#include <stdint.h>
#include <stdbool.h>
#include <zephyr/bluetooth/gatt.h>
#include <zephyr/bluetooth/uuid.h>
#ifdef __cplusplus
extern "C" {
#endif
static inline char *audio_svc_uuid_to_str(uint16_t uuid)
{
switch (uuid) {
case BT_UUID_AICS_VAL: return "AICS";
case BT_UUID_CAS_VAL: return "CAS";
case BT_UUID_VCS_VAL: return "VCS";
case BT_UUID_VOCS_VAL: return "VOCS";
case BT_UUID_CSIS_VAL: return "CSIS";
case BT_UUID_MCS_VAL: return "MCS";
case BT_UUID_GMCS_VAL: return "GMCS";
case BT_UUID_TBS_VAL: return "TBS";
case BT_UUID_GTBS_VAL: return "GTBS";
case BT_UUID_MICS_VAL: return "MICS";
case BT_UUID_ASCS_VAL: return "ASCS";
case BT_UUID_BASS_VAL: return "BASS";
case BT_UUID_PACS_VAL: return "PACS";
case BT_UUID_BASIC_AUDIO_VAL: return "BASIC_AUDIO";
case BT_UUID_HAS_VAL: return "HAS";
case BT_UUID_TMAS_VAL: return "TMAS";
case BT_UUID_PBA_VAL: return "PBA";
case BT_UUID_GMAS_VAL: return "GMAS";
case BT_UUID_OTS_VAL: return "OTS";
default: return "UnknownSvc";
}
}
static inline char *audio_chrc_uuid_to_str(uint16_t uuid)
{
switch (uuid) {
case BT_UUID_OTS_FEATURE_VAL: return "OTS_FEATURE";
case BT_UUID_OTS_NAME_VAL: return "OTS_NAME";
case BT_UUID_OTS_TYPE_VAL: return "OTS_TYPE";
case BT_UUID_OTS_SIZE_VAL: return "OTS_SIZE";
case BT_UUID_OTS_FIRST_CREATED_VAL: return "OTS_FIRST_CREATED";
case BT_UUID_OTS_LAST_MODIFIED_VAL: return "OTS_LAST_MODIFIED";
case BT_UUID_OTS_ID_VAL: return "OTS_ID";
case BT_UUID_OTS_PROPERTIES_VAL: return "OTS_PROPERTIES";
case BT_UUID_OTS_ACTION_CP_VAL: return "OTS_ACTION_CP";
case BT_UUID_OTS_LIST_CP_VAL: return "OTS_LIST_CP";
case BT_UUID_OTS_LIST_FILTER_VAL: return "OTS_LIST_FILTER";
case BT_UUID_OTS_CHANGED_VAL: return "OTS_CHANGED";
case BT_UUID_GATT_TMAPR_VAL: return "TMAP_ROLE";
case BT_UUID_AICS_STATE_VAL: return "AICS_STATE";
case BT_UUID_AICS_GAIN_SETTINGS_VAL: return "AICS_GAIN_SETTINGS";
case BT_UUID_AICS_INPUT_TYPE_VAL: return "AICS_INPUT_TYPE";
case BT_UUID_AICS_INPUT_STATUS_VAL: return "AICS_INPUT_STATUS";
case BT_UUID_AICS_CONTROL_VAL: return "AICS_CONTROL";
case BT_UUID_AICS_DESCRIPTION_VAL: return "AICS_DESCRIPTION";
case BT_UUID_VCS_STATE_VAL: return "VCS_STATE";
case BT_UUID_VCS_CONTROL_VAL: return "VCS_CONTROL";
case BT_UUID_VCS_FLAGS_VAL: return "VCS_FLAGS";
case BT_UUID_VOCS_STATE_VAL: return "VOCS_STATE";
case BT_UUID_VOCS_LOCATION_VAL: return "VOCS_LOCATION";
case BT_UUID_VOCS_CONTROL_VAL: return "VOCS_CONTROL";
case BT_UUID_VOCS_DESCRIPTION_VAL: return "VOCS_DESCRIPTION";
case BT_UUID_CSIS_SIRK_VAL: return "CSIS_SIRK";
case BT_UUID_CSIS_SET_SIZE_VAL: return "CSIS_SET_SIZE";
case BT_UUID_CSIS_SET_LOCK_VAL: return "CSIS_SET_LOCK";
case BT_UUID_CSIS_RANK_VAL: return "CSIS_RANK";
case BT_UUID_MCS_PLAYER_NAME_VAL: return "MCS_PLAYER_NAME";
case BT_UUID_MCS_ICON_OBJ_ID_VAL: return "MCS_ICON_OBJ_ID";
case BT_UUID_MCS_ICON_URL_VAL: return "MCS_ICON_URL";
case BT_UUID_MCS_TRACK_CHANGED_VAL: return "MCS_TRACK_CHANGED";
case BT_UUID_MCS_TRACK_TITLE_VAL: return "MCS_TRACK_TITLE";
case BT_UUID_MCS_TRACK_DURATION_VAL: return "MCS_TRACK_DURATION";
case BT_UUID_MCS_TRACK_POSITION_VAL: return "MCS_TRACK_POSITION";
case BT_UUID_MCS_PLAYBACK_SPEED_VAL: return "MCS_PLAYBACK_SPEED";
case BT_UUID_MCS_SEEKING_SPEED_VAL: return "MCS_SEEKING_SPEED";
case BT_UUID_MCS_TRACK_SEGMENTS_OBJ_ID_VAL: return "MCS_TRACK_SEGMENTS_OBJ_ID";
case BT_UUID_MCS_CURRENT_TRACK_OBJ_ID_VAL: return "MCS_CURRENT_TRACK_OBJ_ID";
case BT_UUID_MCS_NEXT_TRACK_OBJ_ID_VAL: return "MCS_NEXT_TRACK_OBJ_ID";
case BT_UUID_MCS_PARENT_GROUP_OBJ_ID_VAL: return "MCS_PARENT_GROUP_OBJ_ID";
case BT_UUID_MCS_CURRENT_GROUP_OBJ_ID_VAL: return "MCS_CURRENT_GROUP_OBJ_ID";
case BT_UUID_MCS_PLAYING_ORDER_VAL: return "MCS_PLAYING_ORDER";
case BT_UUID_MCS_PLAYING_ORDERS_VAL: return "MCS_PLAYING_ORDERS";
case BT_UUID_MCS_MEDIA_STATE_VAL: return "MCS_MEDIA_STATE";
case BT_UUID_MCS_MEDIA_CONTROL_POINT_VAL: return "MCS_MEDIA_CONTROL_POINT";
case BT_UUID_MCS_MEDIA_CONTROL_OPCODES_VAL: return "MCS_MEDIA_CONTROL_OPCODES";
case BT_UUID_MCS_SEARCH_RESULTS_OBJ_ID_VAL: return "MCS_SEARCH_RESULTS_OBJ_ID";
case BT_UUID_MCS_SEARCH_CONTROL_POINT_VAL: return "MCS_SEARCH_CONTROL_POINT";
case BT_UUID_TBS_PROVIDER_NAME_VAL: return "TBS_PROVIDER_NAME";
case BT_UUID_TBS_UCI_VAL: return "TBS_UCI";
case BT_UUID_TBS_TECHNOLOGY_VAL: return "TBS_TECHNOLOGY";
case BT_UUID_TBS_URI_LIST_VAL: return "TBS_URI_LIST";
case BT_UUID_TBS_SIGNAL_STRENGTH_VAL: return "TBS_SIGNAL_STRENGTH";
case BT_UUID_TBS_SIGNAL_INTERVAL_VAL: return "TBS_SIGNAL_INTERVAL";
case BT_UUID_TBS_LIST_CURRENT_CALLS_VAL: return "TBS_LIST_CURRENT_CALLS";
case BT_UUID_CCID_VAL: return "CCID";
case BT_UUID_TBS_STATUS_FLAGS_VAL: return "TBS_STATUS_FLAGS";
case BT_UUID_TBS_INCOMING_URI_VAL: return "TBS_INCOMING_URI";
case BT_UUID_TBS_CALL_STATE_VAL: return "TBS_CALL_STATE";
case BT_UUID_TBS_CALL_CONTROL_POINT_VAL: return "TBS_CALL_CONTROL_POINT";
case BT_UUID_TBS_OPTIONAL_OPCODES_VAL: return "TBS_OPTIONAL_OPCODES";
case BT_UUID_TBS_TERMINATE_REASON_VAL: return "TBS_TERMINATE_REASON";
case BT_UUID_TBS_INCOMING_CALL_VAL: return "TBS_INCOMING_CALL";
case BT_UUID_TBS_FRIENDLY_NAME_VAL: return "TBS_FRIENDLY_NAME";
case BT_UUID_MICS_MUTE_VAL: return "MICS_MUTE";
case BT_UUID_ASCS_ASE_SNK_VAL: return "ASCS_ASE_SNK";
case BT_UUID_ASCS_ASE_SRC_VAL: return "ASCS_ASE_SRC";
case BT_UUID_ASCS_ASE_CP_VAL: return "ASCS_ASE_CP";
case BT_UUID_BASS_CONTROL_POINT_VAL: return "BASS_CP";
case BT_UUID_BASS_RECV_STATE_VAL: return "BASS_RECV_STATE";
case BT_UUID_PACS_SNK_VAL: return "PACS_SNK";
case BT_UUID_PACS_SNK_LOC_VAL: return "PACS_SNK_LOC";
case BT_UUID_PACS_SRC_VAL: return "PACS_SRC";
case BT_UUID_PACS_SRC_LOC_VAL: return "PACS_SRC_LOC";
case BT_UUID_PACS_AVAILABLE_CONTEXT_VAL: return "PACS_AVAILABLE_CONTEXT";
case BT_UUID_PACS_SUPPORTED_CONTEXT_VAL: return "PACS_SUPPORTED_CONTEXT";
case BT_UUID_HAS_HEARING_AID_FEATURES_VAL: return "HAS_HEARING_AID_FEATURES";
case BT_UUID_HAS_PRESET_CONTROL_POINT_VAL: return "HAS_PRESET_CONTROL_POINT";
case BT_UUID_HAS_ACTIVE_PRESET_INDEX_VAL: return "HAS_ACTIVE_PRESET_INDEX";
case BT_UUID_GMAP_ROLE_VAL: return "GMAP_ROLE";
case BT_UUID_GMAP_UGG_FEAT_VAL: return "GMAP_UGG_FEAT";
case BT_UUID_GMAP_UGT_FEAT_VAL: return "GMAP_UGT_FEAT";
case BT_UUID_GMAP_BGS_FEAT_VAL: return "GMAP_BGS_FEAT";
case BT_UUID_GMAP_BGR_FEAT_VAL: return "GMAP_BGR_FEAT";
default: return "UnknownChrc";
}
}
enum {
AICS_IN_PROGRESS,
ASCS_IN_PROGRESS,
BASS_IN_PROGRESS,
CAS_IN_PROGRESS,
CSIS_IN_PROGRESS,
HAS_IN_PROGRESS,
GMCS_IN_PROGRESS,
MCS_IN_PROGRESS,
MICS_IN_PROGRESS,
PACS_IN_PROGRESS,
GTBS_IN_PROGRESS,
TBS_IN_PROGRESS,
TMAS_IN_PROGRESS,
VCS_IN_PROGRESS,
VOCS_IN_PROGRESS,
MAX_IN_PROGRESS,
};
void bt_le_bluedroid_audio_gatts_init(void);
int bt_le_bluedroid_set_svc_in_progress(uint8_t value);
int bt_le_bluedroid_svc_init(struct bt_gatt_service *svc);
int bt_le_bluedroid_svc_start(struct bt_gatt_service *svc);
#ifdef __cplusplus
}
#endif
#endif /* HOST_BLUEDROID_SERVER_H_ */
@@ -0,0 +1,342 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdint.h>
#include <errno.h>
#include <assert.h>
#include "sdkconfig.h"
#include "bta/bta_gatt_common.h"
#include <zephyr/sys/util.h>
#include <zephyr/logging/log.h>
#include <zephyr/bluetooth/audio/micp.h>
#include <zephyr/bluetooth/audio/vcp.h>
#include "bluedroid/init.h"
#include "common/init.h"
#include "../../../lib/include/audio.h"
LOG_MODULE_REGISTER(LEA_BINIT, CONFIG_BT_ISO_LOG_LEVEL);
#if CONFIG_BT_CSIP_SET_MEMBER
#define CSIS_SVC_COUNT CONFIG_BT_CSIP_SET_MEMBER_MAX_INSTANCE_COUNT
#else /* CONFIG_BT_CSIP_SET_MEMBER */
#define CSIS_SVC_COUNT 0
#endif /* CONFIG_BT_CSIP_SET_MEMBER */
/* 3 is reserved for other GATT services */
#define TOTAL_SERVICE_COUNT (3 + \
(IS_ENABLED(CONFIG_BT_ASCS) ? 1 : 0) + \
(IS_ENABLED(CONFIG_BT_PACS) ? 1 : 0) + \
(IS_ENABLED(CONFIG_BT_BAP_SCAN_DELEGATOR) ? 1 : 0) + \
(IS_ENABLED(CONFIG_BT_TMAP) ? 1 : 0) + \
(IS_ENABLED(CONFIG_BT_MCS) ? 1 : 0) + \
(IS_ENABLED(CONFIG_BT_CSIP_SET_MEMBER) ? CSIS_SVC_COUNT : 0) + \
(IS_ENABLED(CONFIG_BT_CAP_ACCEPTOR) ? 1 : 0) + \
(IS_ENABLED(CONFIG_BT_VCP_VOL_REND) ? 1 : 0) + \
(IS_ENABLED(CONFIG_BT_MICP_MIC_DEV) ? 1 : 0) + \
CONFIG_BT_VOCS_MAX_INSTANCE_COUNT + \
CONFIG_BT_AICS_MAX_INSTANCE_COUNT + \
(IS_ENABLED(CONFIG_BT_TBS) ? 1 : 0) + \
(IS_ENABLED(CONFIG_BT_HAS) ? 1 : 0))
_Static_assert(TOTAL_SERVICE_COUNT <= CONFIG_BT_GATT_MAX_SR_PROFILES, "Too small BT_GATT_MAX_SR_PROFILES");
int bt_le_bluedroid_audio_init(void)
{
int err = 0;
BTA_GATT_SetLocalMTU(BLE_AUDIO_ATT_MTU_MIN);
bt_le_bluedroid_audio_gatts_init();
#if CONFIG_BT_PACS
err = bt_le_bluedroid_pacs_init();
if (err) {
return err;
}
#endif /* CONFIG_BT_PACS */
#if (BLE_AUDIO_SVC_DEFERRED_ADD == 0)
#if CONFIG_BT_ASCS
err = bt_le_bluedroid_ascs_init();
if (err) {
return err;
}
#endif /* CONFIG_BT_ASCS */
#if CONFIG_BT_BAP_SCAN_DELEGATOR
err = bt_le_bluedroid_bass_init();
if (err) {
return err;
}
#endif /* CONFIG_BT_BAP_SCAN_DELEGATOR */
#if CONFIG_BT_TMAP
err = bt_le_bluedroid_tmas_init();
if (err) {
return err;
}
#endif /* CONFIG_BT_TMAP */
#if CONFIG_BT_TBS
err = bt_le_bluedroid_gtbs_init();
if (err) {
return err;
}
#endif /* CONFIG_BT_TBS */
#if CONFIG_BT_HAS
err = bt_le_bluedroid_has_init();
if (err) {
return err;
}
#endif /* CONFIG_BT_HAS */
#endif /* (BLE_AUDIO_SVC_DEFERRED_ADD == 0) */
return err;
}
#if CONFIG_BT_CSIP_SET_MEMBER
static int bluedroid_gatt_csis_init(struct bt_le_audio_start_info *info,
struct bt_gatt_service **inc_csis_svc)
{
struct bt_gatt_service *csis_svc[CONFIG_BT_CSIP_SET_MEMBER_MAX_INSTANCE_COUNT];
uint8_t count;
int err;
if (info == NULL) {
return 0;
}
*inc_csis_svc = NULL;
count = 0;
for (size_t i = 0; i < ARRAY_SIZE(info->csis_insts); i++) {
if (info->csis_insts[i].svc_inst == NULL) {
continue;
}
csis_svc[count] = lib_csip_set_member_svc_get(info->csis_insts[i].svc_inst);
if (!csis_svc[count]) {
LOG_ERR("[B]CsisSvcGetFail[%u]", i);
return -ENODEV;
}
if (info->csis_insts[i].included_by_cas) {
if (*inc_csis_svc == NULL) {
*inc_csis_svc = csis_svc[count];
} else {
/* CAS may include at most one CSIS — caller misconfigured. */
LOG_ERR("[B]CsisMultiIncByCas");
return -EINVAL;
}
}
count++;
}
err = bt_le_bluedroid_csis_init(csis_svc, count);
if (err) {
return err;
}
return 0;
}
#endif /* CONFIG_BT_CSIP_SET_MEMBER */
#if CONFIG_BT_MCS
int bt_le_bluedroid_media_proxy_pl_init(void)
{
int err;
#if CONFIG_BT_MPL_OBJECTS
#endif /* CONFIG_BT_MPL_OBJECTS */
err = bt_le_bluedroid_gmcs_init();
if (err) {
return err;
}
return 0;
}
#endif /* CONFIG_BT_MCS */
#if CONFIG_BT_VCP_VOL_REND
int bt_le_bluedroid_vcp_vol_rend_init(void)
{
struct bt_vcp_included vcp_included;
int err;
memset(&vcp_included, 0, sizeof(vcp_included));
err = bt_vcp_vol_rend_included_get_safe(&vcp_included);
if (err) {
return err;
}
err = bt_le_bluedroid_vcs_init(&vcp_included);
if (err) {
return err;
}
return 0;
}
#endif /* CONFIG_BT_VCP_VOL_REND */
#if CONFIG_BT_MICP_MIC_DEV
int bt_le_bluedroid_micp_mic_dev_init(void)
{
struct bt_micp_included micp_included;
int err;
memset(&micp_included, 0, sizeof(micp_included));
err = bt_micp_mic_dev_included_get_safe(&micp_included);
if (err) {
return err;
}
err = bt_le_bluedroid_mics_init(&micp_included);
if (err) {
return err;
}
return 0;
}
#endif /* CONFIG_BT_MICP_MIC_DEV */
int bt_le_bluedroid_audio_start(void *info)
{
struct bt_gatt_service *inc_csis_svc = NULL;
int err = 0;
#if CONFIG_BT_CSIP_SET_MEMBER
/* Note:
* Should add CSIS before CAS in case one CSIS instance
* is included by CAS.
*/
err = bluedroid_gatt_csis_init(info, &inc_csis_svc);
if (err) {
return err;
}
#endif /* CONFIG_BT_CSIP_SET_MEMBER */
#if CONFIG_BT_CAP_ACCEPTOR
err = bt_le_bluedroid_cas_init(inc_csis_svc);
if (err) {
return err;
}
#else /* CONFIG_BT_CAP_ACCEPTOR */
ARG_UNUSED(inc_csis_svc);
#endif /* CONFIG_BT_CAP_ACCEPTOR */
#if (BLE_AUDIO_SVC_DEFERRED_ADD == 0)
#if CONFIG_BT_MCS
err = bt_le_bluedroid_media_proxy_pl_init();
if (err) {
return err;
}
#endif /* CONFIG_BT_MCS */
#if CONFIG_BT_VCP_VOL_REND
err = bt_le_bluedroid_vcp_vol_rend_init();
if (err) {
return err;
}
#endif /* CONFIG_BT_VCP_VOL_REND */
#if CONFIG_BT_MICP_MIC_DEV
err = bt_le_bluedroid_micp_mic_dev_init();
if (err) {
return err;
}
#endif /* CONFIG_BT_MICP_MIC_DEV */
#endif /* (BLE_AUDIO_SVC_DEFERRED_ADD == 0) */
#if CONFIG_BT_ASCS
err = bt_le_bluedroid_ascs_start();
if (err) {
return err;
}
#endif /* CONFIG_BT_ASCS */
#if CONFIG_BT_PACS
err = bt_le_bluedroid_pacs_start();
if (err) {
return err;
}
#endif /* CONFIG_BT_PACS */
#if CONFIG_BT_BAP_SCAN_DELEGATOR
err = bt_le_bluedroid_bass_start();
if (err) {
return err;
}
#endif /* CONFIG_BT_BAP_SCAN_DELEGATOR */
#if CONFIG_BT_TMAP
err = bt_le_bluedroid_tmas_start();
if (err) {
return err;
}
#endif /* CONFIG_BT_TMAP */
#if CONFIG_BT_CSIP_SET_MEMBER
err = bt_le_bluedroid_csis_start();
if (err) {
return err;
}
#endif /* CONFIG_BT_CSIP_SET_MEMBER */
#if CONFIG_BT_CAP_ACCEPTOR
err = bt_le_bluedroid_cas_start();
if (err) {
return err;
}
#endif /* CONFIG_BT_CAP_ACCEPTOR */
#if CONFIG_BT_VCP_VOL_REND
err = bt_le_bluedroid_vcs_start();
if (err) {
return err;
}
#endif /* CONFIG_BT_VCP_VOL_REND */
#if CONFIG_BT_MICP_MIC_DEV
err = bt_le_bluedroid_mics_start();
if (err) {
return err;
}
#endif /* CONFIG_BT_MICP_MIC_DEV */
#if CONFIG_BT_MCS
err = bt_le_bluedroid_gmcs_start();
if (err) {
return err;
}
#endif /* CONFIG_BT_MCS */
#if CONFIG_BT_TBS
err = bt_le_bluedroid_gtbs_start();
if (err) {
return err;
}
#endif /* CONFIG_BT_TBS */
#if CONFIG_BT_HAS
err = bt_le_bluedroid_has_start();
if (err) {
return err;
}
#endif /* CONFIG_BT_HAS */
return err;
}
@@ -0,0 +1,56 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdint.h>
#include <stdbool.h>
#include <errno.h>
#include <zephyr/autoconf.h>
#include <zephyr/logging/log.h>
#include <zephyr/bluetooth/uuid.h>
#include <zephyr/bluetooth/gatt.h>
#include "bluedroid/server.h"
#include "common/host.h"
#include "../../../lib/include/audio.h"
LOG_MODULE_REGISTER(LEA_ASCS, CONFIG_BT_ISO_LOG_LEVEL);
int bt_le_bluedroid_ascs_init(void)
{
struct bt_gatt_service *ascs_svc;
LOG_DBG("[B]AscsInit");
ascs_svc = lib_ascs_svc_get();
if (!ascs_svc) {
LOG_ERR("[B]AscsSvcGetFail");
return -ENODEV;
}
bt_le_bluedroid_set_svc_in_progress(ASCS_IN_PROGRESS);
return bt_le_bluedroid_svc_init(ascs_svc);
}
int bt_le_bluedroid_ascs_start(void)
{
struct bt_gatt_service *ascs_svc;
LOG_DBG("[B]AscsStart");
ascs_svc = lib_ascs_svc_get();
if (!ascs_svc) {
LOG_ERR("[B]AscsSvcGetFail");
return -ENODEV;
}
bt_le_bluedroid_set_svc_in_progress(ASCS_IN_PROGRESS);
return bt_le_bluedroid_svc_start(ascs_svc);
}
@@ -0,0 +1,56 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdint.h>
#include <stdbool.h>
#include <errno.h>
#include <zephyr/autoconf.h>
#include <zephyr/logging/log.h>
#include <zephyr/bluetooth/uuid.h>
#include <zephyr/bluetooth/gatt.h>
#include "bluedroid/server.h"
#include "common/host.h"
#include "../../../lib/include/audio.h"
LOG_MODULE_REGISTER(LEA_BASS, CONFIG_BT_ISO_LOG_LEVEL);
int bt_le_bluedroid_bass_init(void)
{
struct bt_gatt_service *bass_svc;
LOG_DBG("[B]BassInit");
bass_svc = lib_bap_bass_svc_get();
if (!bass_svc) {
LOG_ERR("[B]BassSvcGetFail");
return -ENODEV;
}
bt_le_bluedroid_set_svc_in_progress(BASS_IN_PROGRESS);
return bt_le_bluedroid_svc_init(bass_svc);
}
int bt_le_bluedroid_bass_start(void)
{
struct bt_gatt_service *bass_svc;
LOG_DBG("[B]BassStart");
bass_svc = lib_bap_bass_svc_get();
if (!bass_svc) {
LOG_ERR("[B]BassSvcGetFail");
return -ENODEV;
}
bt_le_bluedroid_set_svc_in_progress(BASS_IN_PROGRESS);
return bt_le_bluedroid_svc_start(bass_svc);
}
@@ -0,0 +1,105 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdint.h>
#include <stdbool.h>
#include <errno.h>
#include <zephyr/autoconf.h>
#include <zephyr/logging/log.h>
#include <zephyr/bluetooth/uuid.h>
#include <zephyr/bluetooth/gatt.h>
#include "bluedroid/server.h"
#include "common/host.h"
#include "../../../lib/include/audio.h"
LOG_MODULE_REGISTER(LEA_CAS, CONFIG_BT_ISO_LOG_LEVEL);
#if CONFIG_BT_CAP_ACCEPTOR_SET_MEMBER
static struct inc_svc_inst inc_csis_inst;
struct inc_svc_inst *cas_not_included_inst(void)
{
if (inc_csis_inst.included == false) {
return &inc_csis_inst;
}
return NULL;
}
#endif /* CONFIG_BT_CAP_ACCEPTOR_SET_MEMBER */
int bt_le_bluedroid_cas_init(void *csis_svc_p)
{
struct bt_gatt_service *cas_svc;
int err = 0;
LOG_DBG("[B]CasInit");
#if CONFIG_BT_CAP_ACCEPTOR_SET_MEMBER
/* csis_svc_p is non-NULL in practice (SET_MEMBER depends on CSIP_SET_MEMBER,
* which populates it), but guard for parity with the nimble adapter. With
* no CSIS, mark included=true so cas_not_included_inst() skips it and
* svc_init never feeds a NULL svc_p into BTA_GATTS_AddIncludeService. */
if (csis_svc_p) {
/* The instance of CSIS is included by CAS */
inc_csis_inst.svc_p = csis_svc_p;
/* Reset included before svc_init; see mics.c for rationale. */
inc_csis_inst.included = false;
} else {
inc_csis_inst.included = true;
}
#else /* CONFIG_BT_CAP_ACCEPTOR_SET_MEMBER */
ARG_UNUSED(csis_svc_p);
#endif /* CONFIG_BT_CAP_ACCEPTOR_SET_MEMBER */
cas_svc = lib_cas_svc_get();
if (!cas_svc) {
LOG_ERR("[B]CasSvcGetFail");
return -ENODEV;
}
bt_le_bluedroid_set_svc_in_progress(CAS_IN_PROGRESS);
err = bt_le_bluedroid_svc_init(cas_svc);
if (err) {
return err;
}
#if CONFIG_BT_CAP_ACCEPTOR_SET_MEMBER
if (cas_not_included_inst()) {
LOG_ERR("[B]CasCsisNotInc");
return -EIO;
}
#else /* CONFIG_BT_CAP_ACCEPTOR_SET_MEMBER */
/* Insert CAS to the GATT db list */
err = bt_gatt_service_register_safe(cas_svc);
if (err) {
LOG_ERR("[B]CasSvcRegFail[%d]", err);
}
#endif /* CONFIG_BT_CAP_ACCEPTOR_SET_MEMBER */
return err;
}
int bt_le_bluedroid_cas_start(void)
{
struct bt_gatt_service *cas_svc;
LOG_DBG("[B]CasStart");
cas_svc = lib_cas_svc_get();
if (!cas_svc) {
LOG_ERR("[B]CasSvcGetFail");
return -ENODEV;
}
bt_le_bluedroid_set_svc_in_progress(CAS_IN_PROGRESS);
return bt_le_bluedroid_svc_start(cas_svc);
}
@@ -0,0 +1,76 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdint.h>
#include <stdbool.h>
#include <errno.h>
#include <zephyr/autoconf.h>
#include <zephyr/logging/log.h>
#include <zephyr/bluetooth/uuid.h>
#include <zephyr/bluetooth/gatt.h>
#include "bluedroid/server.h"
#include "common/host.h"
#include "../../../lib/include/audio.h"
LOG_MODULE_REGISTER(LEA_CSIS, CONFIG_BT_ISO_LOG_LEVEL);
#define CSIS_SVC_COUNT CONFIG_BT_CSIP_SET_MEMBER_MAX_INSTANCE_COUNT
static struct csis_inst {
struct bt_gatt_service *svc_p;
} csis_insts[CSIS_SVC_COUNT];
static uint8_t csis_svc_count;
int bt_le_bluedroid_csis_init(void *svc, uint8_t count)
{
int err;
LOG_DBG("[B]CsisInit");
if (count > CSIS_SVC_COUNT) {
return -1;
}
bt_le_bluedroid_set_svc_in_progress(CSIS_IN_PROGRESS);
for (size_t i = 0; i < count; i++) {
csis_insts[i].svc_p = ((struct bt_gatt_service **)svc)[i];
err = bt_le_bluedroid_svc_init(csis_insts[i].svc_p);
if (err) {
return err;
}
}
/* Commit the count only after the loop succeeds, so a mid-loop failure
* doesn't leave csis_start() iterating uninitialized entries. */
csis_svc_count = count;
return 0;
}
int bt_le_bluedroid_csis_start(void)
{
int err;
LOG_DBG("[B]CsisStart");
bt_le_bluedroid_set_svc_in_progress(CSIS_IN_PROGRESS);
for (size_t i = 0; i < csis_svc_count; i++) {
err = bt_le_bluedroid_svc_start(csis_insts[i].svc_p);
if (err) {
return err;
}
}
return 0;
}
@@ -0,0 +1,56 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdint.h>
#include <stdbool.h>
#include <errno.h>
#include <zephyr/autoconf.h>
#include <zephyr/logging/log.h>
#include <zephyr/bluetooth/uuid.h>
#include <zephyr/bluetooth/gatt.h>
#include "bluedroid/server.h"
#include "common/host.h"
#include "../../../lib/include/audio.h"
LOG_MODULE_REGISTER(LEA_HAS, CONFIG_BT_ISO_LOG_LEVEL);
int bt_le_bluedroid_has_init(void)
{
struct bt_gatt_service *has_svc;
LOG_DBG("[B]HasInit");
has_svc = lib_has_svc_get();
if (!has_svc) {
LOG_ERR("[B]HasSvcGetFail");
return -ENODEV;
}
bt_le_bluedroid_set_svc_in_progress(HAS_IN_PROGRESS);
return bt_le_bluedroid_svc_init(has_svc);
}
int bt_le_bluedroid_has_start(void)
{
struct bt_gatt_service *has_svc;
LOG_DBG("[B]HasStart");
has_svc = lib_has_svc_get();
if (!has_svc) {
LOG_ERR("[B]HasSvcGetFail");
return -ENODEV;
}
bt_le_bluedroid_set_svc_in_progress(HAS_IN_PROGRESS);
return bt_le_bluedroid_svc_start(has_svc);
}
@@ -0,0 +1,52 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdint.h>
#include <stdbool.h>
#include <errno.h>
#include <zephyr/autoconf.h>
#include <zephyr/logging/log.h>
#include <zephyr/bluetooth/uuid.h>
#include <zephyr/bluetooth/gatt.h>
#include "bluedroid/server.h"
#include "common/host.h"
#include "../../../lib/include/audio.h"
LOG_MODULE_REGISTER(LEA_MCS, CONFIG_BT_ISO_LOG_LEVEL);
int bt_le_bluedroid_gmcs_init(void)
{
struct bt_gatt_service *gmcs_svc;
gmcs_svc = lib_mcs_svc_get();
if (!gmcs_svc) {
LOG_ERR("[B]GmcsSvcGetFail");
return -ENODEV;
}
bt_le_bluedroid_set_svc_in_progress(GMCS_IN_PROGRESS);
return bt_le_bluedroid_svc_init(gmcs_svc);
}
int bt_le_bluedroid_gmcs_start(void)
{
struct bt_gatt_service *gmcs_svc;
gmcs_svc = lib_mcs_svc_get();
if (!gmcs_svc) {
LOG_ERR("[B]GmcsSvcGetFail");
return -ENODEV;
}
bt_le_bluedroid_set_svc_in_progress(GMCS_IN_PROGRESS);
return bt_le_bluedroid_svc_start(gmcs_svc);
}
@@ -0,0 +1,136 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdint.h>
#include <stdbool.h>
#include <errno.h>
#include <zephyr/autoconf.h>
#include <zephyr/logging/log.h>
#include <zephyr/bluetooth/uuid.h>
#include <zephyr/bluetooth/gatt.h>
#include <zephyr/bluetooth/audio/micp.h>
#include "bluedroid/server.h"
#include "common/host.h"
#include "../../../lib/include/audio.h"
LOG_MODULE_REGISTER(LEA_MICS, CONFIG_BT_ISO_LOG_LEVEL);
#define AICS_INST_COUNT CONFIG_BT_MICP_MIC_DEV_AICS_INSTANCE_COUNT
static uint8_t inc_aics_svc_count;
static struct inc_svc_inst inc_aics_insts[AICS_INST_COUNT];
struct inc_svc_inst *mics_not_included_inst(void)
{
for (size_t i = 0; i < inc_aics_svc_count; i++) {
if (inc_aics_insts[i].included == false) {
return &inc_aics_insts[i];
}
}
return NULL;
}
int bt_le_bluedroid_mics_init(void *micp_inc)
{
struct bt_micp_included *micp_included;
struct bt_gatt_service *mics_svc;
int err;
LOG_DBG("[B]MicsInit");
mics_svc = lib_mics_svc_get();
if (!mics_svc) {
LOG_ERR("[B]MicsSvcGetFail");
return -ENODEV;
}
/* Reset before the NULL check so a re-init with micp_included == NULL
* doesn't iterate over stale entries from a previous non-NULL call. */
inc_aics_svc_count = 0;
micp_included = micp_inc;
if (micp_included) {
if (micp_included->aics_cnt > AICS_INST_COUNT) {
return -EINVAL;
}
bt_le_bluedroid_set_svc_in_progress(AICS_IN_PROGRESS);
/* MICS may include zero or more instances of AICS */
for (size_t i = 0; i < micp_included->aics_cnt; i++) {
inc_aics_insts[i].svc_p = lib_aics_svc_get(micp_included->aics[i]);
if (!inc_aics_insts[i].svc_p) {
LOG_ERR("[B]AicsSvcGetFail[%u]", i);
return -ENODEV;
}
/* Reset included before svc_init: server.c sets it to true when
* the include attribute is processed. Without this reset, a
* re-init where the include attribute is missing would leave
* the stale true from a previous init and mics_not_included_inst()
* would falsely report all instances as included. */
inc_aics_insts[i].included = false;
err = bt_le_bluedroid_svc_init(inc_aics_insts[i].svc_p);
if (err) {
return err;
}
}
/* Commit the count only after every instance initialized — a mid-loop
* failure above leaves it at 0 (reset on entry) so mics_start() never
* iterates partially-initialized entries. */
inc_aics_svc_count = micp_included->aics_cnt;
}
bt_le_bluedroid_set_svc_in_progress(MICS_IN_PROGRESS);
err = bt_le_bluedroid_svc_init(mics_svc);
if (err) {
return err;
}
if (mics_not_included_inst()) {
LOG_ERR("[B]MicsAicsNotAllInc");
return -EIO;
}
return 0;
}
int bt_le_bluedroid_mics_start(void)
{
struct bt_gatt_service *mics_svc;
int err;
LOG_DBG("[B]MicsStart");
mics_svc = lib_mics_svc_get();
if (!mics_svc) {
LOG_ERR("[B]MicsSvcGetFail");
return -ENODEV;
}
bt_le_bluedroid_set_svc_in_progress(AICS_IN_PROGRESS);
for (size_t i = 0; i < inc_aics_svc_count; i++) {
err = bt_le_bluedroid_svc_start(inc_aics_insts[i].svc_p);
if (err) {
return err;
}
}
bt_le_bluedroid_set_svc_in_progress(MICS_IN_PROGRESS);
return bt_le_bluedroid_svc_start(mics_svc);
}
@@ -0,0 +1,56 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdint.h>
#include <stdbool.h>
#include <errno.h>
#include <zephyr/autoconf.h>
#include <zephyr/logging/log.h>
#include <zephyr/bluetooth/uuid.h>
#include <zephyr/bluetooth/gatt.h>
#include "bluedroid/server.h"
#include "common/host.h"
#include "../../../lib/include/audio.h"
LOG_MODULE_REGISTER(LEA_PACS, CONFIG_BT_ISO_LOG_LEVEL);
int bt_le_bluedroid_pacs_init(void)
{
struct bt_gatt_service *pacs_svc;
LOG_DBG("[B]PacsInit");
pacs_svc = lib_pacs_svc_get();
if (!pacs_svc) {
LOG_ERR("[B]PacsSvcGetFail");
return -ENODEV;
}
bt_le_bluedroid_set_svc_in_progress(PACS_IN_PROGRESS);
return bt_le_bluedroid_svc_init(pacs_svc);
}
int bt_le_bluedroid_pacs_start(void)
{
struct bt_gatt_service *pacs_svc;
LOG_DBG("[B]PacsStart");
pacs_svc = lib_pacs_svc_get();
if (!pacs_svc) {
LOG_ERR("[B]PacsSvcGetFail");
return -ENODEV;
}
bt_le_bluedroid_set_svc_in_progress(PACS_IN_PROGRESS);
return bt_le_bluedroid_svc_start(pacs_svc);
}
@@ -0,0 +1,52 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdint.h>
#include <stdbool.h>
#include <errno.h>
#include <zephyr/autoconf.h>
#include <zephyr/logging/log.h>
#include <zephyr/bluetooth/uuid.h>
#include <zephyr/bluetooth/gatt.h>
#include "bluedroid/server.h"
#include "common/host.h"
#include "../../../lib/include/audio.h"
LOG_MODULE_REGISTER(LEA_TBS, CONFIG_BT_ISO_LOG_LEVEL);
int bt_le_bluedroid_gtbs_init(void)
{
struct bt_gatt_service *gtbs_svc;
gtbs_svc = lib_gtbs_svc_get();
if (!gtbs_svc) {
LOG_ERR("[B]GtbsSvcGetFail");
return -ENODEV;
}
bt_le_bluedroid_set_svc_in_progress(GTBS_IN_PROGRESS);
return bt_le_bluedroid_svc_init(gtbs_svc);
}
int bt_le_bluedroid_gtbs_start(void)
{
struct bt_gatt_service *gtbs_svc;
gtbs_svc = lib_gtbs_svc_get();
if (!gtbs_svc) {
LOG_ERR("[B]GtbsSvcGetFail");
return -ENODEV;
}
bt_le_bluedroid_set_svc_in_progress(GTBS_IN_PROGRESS);
return bt_le_bluedroid_svc_start(gtbs_svc);
}
@@ -0,0 +1,56 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdint.h>
#include <stdbool.h>
#include <errno.h>
#include <zephyr/autoconf.h>
#include <zephyr/logging/log.h>
#include <zephyr/bluetooth/uuid.h>
#include <zephyr/bluetooth/gatt.h>
#include "bluedroid/server.h"
#include "common/host.h"
#include "../../../lib/include/audio.h"
LOG_MODULE_REGISTER(LEA_TMAS, CONFIG_BT_ISO_LOG_LEVEL);
int bt_le_bluedroid_tmas_init(void)
{
struct bt_gatt_service *tmas_svc;
LOG_DBG("[B]TmasInit");
tmas_svc = lib_tmas_svc_get();
if (!tmas_svc) {
LOG_ERR("[B]TmasSvcGetFail");
return -ENODEV;
}
bt_le_bluedroid_set_svc_in_progress(TMAS_IN_PROGRESS);
return bt_le_bluedroid_svc_init(tmas_svc);
}
int bt_le_bluedroid_tmas_start(void)
{
struct bt_gatt_service *tmas_svc;
LOG_DBG("[B]TmasStart");
tmas_svc = lib_tmas_svc_get();
if (!tmas_svc) {
LOG_ERR("[B]TmasSvcGetFail");
return -ENODEV;
}
bt_le_bluedroid_set_svc_in_progress(TMAS_IN_PROGRESS);
return bt_le_bluedroid_svc_start(tmas_svc);
}
@@ -0,0 +1,169 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdint.h>
#include <stdbool.h>
#include <errno.h>
#include <zephyr/autoconf.h>
#include <zephyr/logging/log.h>
#include <zephyr/bluetooth/uuid.h>
#include <zephyr/bluetooth/gatt.h>
#include <zephyr/bluetooth/audio/vcp.h>
#include "bluedroid/server.h"
#include "common/host.h"
#include "../../../lib/include/audio.h"
LOG_MODULE_REGISTER(LEA_VCS, CONFIG_BT_ISO_LOG_LEVEL);
#define VOCS_INST_COUNT CONFIG_BT_VCP_VOL_REND_VOCS_INSTANCE_COUNT
#define AICS_INST_COUNT CONFIG_BT_VCP_VOL_REND_AICS_INSTANCE_COUNT
static uint8_t inc_vocs_svc_count;
static uint8_t inc_aics_svc_count;
static struct inc_svc_inst inc_vocs_insts[VOCS_INST_COUNT];
static struct inc_svc_inst inc_aics_insts[AICS_INST_COUNT];
struct inc_svc_inst *vcs_not_included_inst(void)
{
for (size_t i = 0; i < inc_vocs_svc_count; i++) {
if (inc_vocs_insts[i].included == false) {
return &inc_vocs_insts[i];
}
}
for (size_t i = 0; i < inc_aics_svc_count; i++) {
if (inc_aics_insts[i].included == false) {
return &inc_aics_insts[i];
}
}
return NULL;
}
int bt_le_bluedroid_vcs_init(void *vcp_inc)
{
struct bt_vcp_included *vcp_included;
struct bt_gatt_service *vcs_svc;
int err;
LOG_DBG("[B]VcsInit");
vcs_svc = lib_vcs_svc_get();
if (!vcs_svc) {
LOG_ERR("[B]VcsSvcGetFail");
return -ENODEV;
}
/* Reset before the NULL check so a re-init with vcp_included == NULL
* doesn't iterate over stale entries from a previous non-NULL call. */
inc_vocs_svc_count = 0;
inc_aics_svc_count = 0;
vcp_included = vcp_inc;
if (vcp_included) {
if (vcp_included->vocs_cnt > VOCS_INST_COUNT ||
vcp_included->aics_cnt > AICS_INST_COUNT) {
return -EINVAL;
}
inc_vocs_svc_count = vcp_included->vocs_cnt;
inc_aics_svc_count = vcp_included->aics_cnt;
bt_le_bluedroid_set_svc_in_progress(VOCS_IN_PROGRESS);
/* VCS may include zero or more instances of VOCS */
for (size_t i = 0; i < inc_vocs_svc_count; i++) {
inc_vocs_insts[i].svc_p = lib_vocs_svc_get(vcp_included->vocs[i]);
if (!inc_vocs_insts[i].svc_p) {
LOG_ERR("[B]VocsSvcGetFail[%u]", i);
return -ENODEV;
}
/* Reset included before svc_init; see mics.c for rationale. */
inc_vocs_insts[i].included = false;
err = bt_le_bluedroid_svc_init(inc_vocs_insts[i].svc_p);
if (err) {
return err;
}
}
bt_le_bluedroid_set_svc_in_progress(AICS_IN_PROGRESS);
/* VCS may include zero or more instances of AICS */
for (size_t i = 0; i < inc_aics_svc_count; i++) {
inc_aics_insts[i].svc_p = lib_aics_svc_get(vcp_included->aics[i]);
if (!inc_aics_insts[i].svc_p) {
LOG_ERR("[B]AicsSvcGetFail[%u]", i);
return -ENODEV;
}
/* Reset included before svc_init; see mics.c for rationale. */
inc_aics_insts[i].included = false;
err = bt_le_bluedroid_svc_init(inc_aics_insts[i].svc_p);
if (err) {
return err;
}
}
}
bt_le_bluedroid_set_svc_in_progress(VCS_IN_PROGRESS);
err = bt_le_bluedroid_svc_init(vcs_svc);
if (err) {
return err;
}
if (vcs_not_included_inst()) {
LOG_ERR("[B]VcsVocsAicsNotAllInc");
return -EIO;
}
return 0;
}
int bt_le_bluedroid_vcs_start(void)
{
struct bt_gatt_service *vcs_svc;
int err;
LOG_DBG("[B]VcsStart");
vcs_svc = lib_vcs_svc_get();
if (!vcs_svc) {
LOG_ERR("[B]VcsSvcGetFail");
return -ENODEV;
}
bt_le_bluedroid_set_svc_in_progress(VOCS_IN_PROGRESS);
for (size_t i = 0; i < inc_vocs_svc_count; i++) {
err = bt_le_bluedroid_svc_start(inc_vocs_insts[i].svc_p);
if (err) {
return err;
}
}
bt_le_bluedroid_set_svc_in_progress(AICS_IN_PROGRESS);
for (size_t i = 0; i < inc_aics_svc_count; i++) {
err = bt_le_bluedroid_svc_start(inc_aics_insts[i].svc_p);
if (err) {
return err;
}
}
bt_le_bluedroid_set_svc_in_progress(VCS_IN_PROGRESS);
return bt_le_bluedroid_svc_start(vcs_svc);
}
@@ -0,0 +1,596 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdint.h>
#include <stdbool.h>
#include <errno.h>
#include <zephyr/autoconf.h>
#include <zephyr/logging/log.h>
#include <zephyr/bluetooth/uuid.h>
#include <zephyr/bluetooth/gatt.h>
#include <zephyr/bluetooth/audio/micp.h>
#include <zephyr/bluetooth/audio/vcp.h>
#include <../host/conn_internal.h>
#include "bta/bta_gatt_api.h"
#include "bluedroid/gatt.h"
#include "bluedroid/server.h"
#include "common/host.h"
LOG_MODULE_REGISTER(LEA_GSRV, CONFIG_BT_ISO_LOG_LEVEL);
static uint8_t svc_in_progress;
static uint16_t inc_svc_handle;
static uint16_t svc_handle;
static uint16_t chrc_handle;
static bool is_primary_svc(void)
{
if (svc_in_progress == ASCS_IN_PROGRESS ||
svc_in_progress == BASS_IN_PROGRESS ||
svc_in_progress == CAS_IN_PROGRESS ||
svc_in_progress == CSIS_IN_PROGRESS ||
svc_in_progress == HAS_IN_PROGRESS ||
svc_in_progress == GMCS_IN_PROGRESS ||
svc_in_progress == MCS_IN_PROGRESS ||
svc_in_progress == MICS_IN_PROGRESS ||
svc_in_progress == PACS_IN_PROGRESS ||
svc_in_progress == GTBS_IN_PROGRESS ||
svc_in_progress == TBS_IN_PROGRESS ||
svc_in_progress == TMAS_IN_PROGRESS ||
svc_in_progress == VCS_IN_PROGRESS) {
return true;
}
return false;
}
static bool is_secondary_svc(void)
{
if (svc_in_progress == AICS_IN_PROGRESS ||
svc_in_progress == VOCS_IN_PROGRESS) {
return true;
}
return false;
}
static bool any_included_svc(void)
{
if (svc_in_progress == CAS_IN_PROGRESS ||
svc_in_progress == MICS_IN_PROGRESS ||
svc_in_progress == VCS_IN_PROGRESS) {
return true;
}
return false;
}
static bool is_svc_uuid_valid(uint16_t uuid)
{
switch (svc_in_progress) {
case AICS_IN_PROGRESS:
return (uuid == BT_UUID_AICS_VAL);
case ASCS_IN_PROGRESS:
return (uuid == BT_UUID_ASCS_VAL);
case BASS_IN_PROGRESS:
return (uuid == BT_UUID_BASS_VAL);
case CAS_IN_PROGRESS:
return (uuid == BT_UUID_CAS_VAL);
case CSIS_IN_PROGRESS:
return (uuid == BT_UUID_CSIS_VAL);
case HAS_IN_PROGRESS:
return (uuid == BT_UUID_HAS_VAL);
case GMCS_IN_PROGRESS:
return (uuid == BT_UUID_GMCS_VAL);
case MCS_IN_PROGRESS:
return (uuid == BT_UUID_MCS_VAL);
case MICS_IN_PROGRESS:
return (uuid == BT_UUID_MICS_VAL);
case PACS_IN_PROGRESS:
return (uuid == BT_UUID_PACS_VAL);
case GTBS_IN_PROGRESS:
return (uuid == BT_UUID_GTBS_VAL);
case TBS_IN_PROGRESS:
return (uuid == BT_UUID_TBS_VAL);
case TMAS_IN_PROGRESS:
return (uuid == BT_UUID_TMAS_VAL);
case VCS_IN_PROGRESS:
return (uuid == BT_UUID_VCS_VAL);
case VOCS_IN_PROGRESS:
return (uuid == BT_UUID_VOCS_VAL);
default:
return false;
}
}
static void svc_create_cb(uint16_t service_id, uint16_t svc_instance,
bool is_primary, uint8_t status, void *uuid)
{
int result = status;
if ((is_primary_svc() && is_primary == false) ||
(is_secondary_svc() && is_primary == true) ||
((tBT_UUID *)uuid)->len != 2 ||
is_svc_uuid_valid(((tBT_UUID *)uuid)->uu.uuid16) == false) {
/* uuid16 is only meaningful when len == 2; for 32/128-bit UUIDs the
* union access would log the first 2 bytes of a wider value. */
if (((tBT_UUID *)uuid)->len == 2) {
LOG_ERR("[B]SvcCreateMismatch[%u][%u][2][0x%04x]",
svc_in_progress, is_primary,
((tBT_UUID *)uuid)->uu.uuid16);
} else {
LOG_ERR("[B]SvcCreateMismatch[%u][%u][%u][nonU16]",
svc_in_progress, is_primary,
((tBT_UUID *)uuid)->len);
}
result = -1;
goto end;
}
svc_handle = service_id;
end:
bt_le_bluedroid_gatts_sem_give(result);
}
static void inc_svc_add_cb(uint16_t service_id, uint16_t attr_id, uint8_t status)
{
int result = status;
if (service_id != svc_handle) {
LOG_ERR("[B]IncSvcAddMismatch[%u][%u][%u]",
svc_in_progress, service_id, svc_handle);
result = -1;
goto end;
}
inc_svc_handle = attr_id;
end:
bt_le_bluedroid_gatts_sem_give(result);
}
static void chrc_add_cb(uint16_t service_id, uint16_t attr_id,
uint8_t status, void *uuid)
{
int result = status;
if (service_id != svc_handle || ((tBT_UUID *)uuid)->len != 2) {
/* uuid16 is only meaningful when len == 2; for 32/128-bit UUIDs the
* union access would log the first 2 bytes of a wider value. */
if (((tBT_UUID *)uuid)->len == 2) {
LOG_ERR("[B]ChrcAddMismatch[%u][%u][%u][2][0x%04x]",
svc_in_progress, service_id, svc_handle,
((tBT_UUID *)uuid)->uu.uuid16);
} else {
LOG_ERR("[B]ChrcAddMismatch[%u][%u][%u][%u][nonU16]",
svc_in_progress, service_id, svc_handle,
((tBT_UUID *)uuid)->len);
}
result = -1;
goto end;
}
chrc_handle = attr_id;
end:
bt_le_bluedroid_gatts_sem_give(result);
}
static void svc_start_cb(uint16_t service_id, uint8_t status)
{
int result = status;
if (service_id != svc_handle) {
LOG_ERR("[B]SvcStartMismatch[%u][%u]", service_id, svc_handle);
result = -1;
}
bt_le_bluedroid_gatts_sem_give(result);
}
static struct gatts_svc_cb svc_cb = {
.svc_create_cb = svc_create_cb,
.inc_svc_add_cb = inc_svc_add_cb,
.chrc_add_cb = chrc_add_cb,
.svc_start_cb = svc_start_cb,
};
void bt_le_bluedroid_audio_gatts_init(void)
{
bt_le_bluedroid_gatts_svc_cb_register(&svc_cb);
}
int bt_le_bluedroid_set_svc_in_progress(uint8_t value)
{
if (value >= MAX_IN_PROGRESS) {
LOG_ERR("[B]SvcInProgressInv[%u]", value);
return -1;
}
svc_in_progress = value;
return 0;
}
static bool is_svc_attr_uuid_valid(uint16_t attr_uuid)
{
switch (svc_in_progress) {
case AICS_IN_PROGRESS:
return (attr_uuid == BT_UUID_AICS_STATE_VAL ||
attr_uuid == BT_UUID_AICS_GAIN_SETTINGS_VAL ||
attr_uuid == BT_UUID_AICS_INPUT_TYPE_VAL ||
attr_uuid == BT_UUID_AICS_INPUT_STATUS_VAL ||
attr_uuid == BT_UUID_AICS_CONTROL_VAL ||
attr_uuid == BT_UUID_AICS_DESCRIPTION_VAL);
case ASCS_IN_PROGRESS:
return (attr_uuid == BT_UUID_ASCS_ASE_SNK_VAL ||
attr_uuid == BT_UUID_ASCS_ASE_SRC_VAL ||
attr_uuid == BT_UUID_ASCS_ASE_CP_VAL);
case BASS_IN_PROGRESS:
return (attr_uuid == BT_UUID_BASS_CONTROL_POINT_VAL ||
attr_uuid == BT_UUID_BASS_RECV_STATE_VAL);
case CAS_IN_PROGRESS:
/* No characteristic in CAS */
return false;
case CSIS_IN_PROGRESS:
return (attr_uuid == BT_UUID_CSIS_SIRK_VAL ||
attr_uuid == BT_UUID_CSIS_SET_SIZE_VAL ||
attr_uuid == BT_UUID_CSIS_SET_LOCK_VAL ||
attr_uuid == BT_UUID_CSIS_RANK_VAL);
case HAS_IN_PROGRESS:
return (attr_uuid == BT_UUID_HAS_HEARING_AID_FEATURES_VAL ||
attr_uuid == BT_UUID_HAS_PRESET_CONTROL_POINT_VAL ||
attr_uuid == BT_UUID_HAS_ACTIVE_PRESET_INDEX_VAL);
case GMCS_IN_PROGRESS:
case MCS_IN_PROGRESS:
return (attr_uuid == BT_UUID_MCS_PLAYER_NAME_VAL ||
attr_uuid == BT_UUID_MCS_ICON_OBJ_ID_VAL ||
attr_uuid == BT_UUID_MCS_ICON_URL_VAL ||
attr_uuid == BT_UUID_MCS_TRACK_CHANGED_VAL ||
attr_uuid == BT_UUID_MCS_TRACK_TITLE_VAL ||
attr_uuid == BT_UUID_MCS_TRACK_DURATION_VAL ||
attr_uuid == BT_UUID_MCS_TRACK_POSITION_VAL ||
attr_uuid == BT_UUID_MCS_PLAYBACK_SPEED_VAL ||
attr_uuid == BT_UUID_MCS_SEEKING_SPEED_VAL ||
attr_uuid == BT_UUID_MCS_TRACK_SEGMENTS_OBJ_ID_VAL ||
attr_uuid == BT_UUID_MCS_CURRENT_TRACK_OBJ_ID_VAL ||
attr_uuid == BT_UUID_MCS_NEXT_TRACK_OBJ_ID_VAL ||
attr_uuid == BT_UUID_MCS_PARENT_GROUP_OBJ_ID_VAL ||
attr_uuid == BT_UUID_MCS_CURRENT_GROUP_OBJ_ID_VAL ||
attr_uuid == BT_UUID_MCS_PLAYING_ORDER_VAL ||
attr_uuid == BT_UUID_MCS_PLAYING_ORDERS_VAL ||
attr_uuid == BT_UUID_MCS_MEDIA_STATE_VAL ||
attr_uuid == BT_UUID_MCS_MEDIA_CONTROL_POINT_VAL ||
attr_uuid == BT_UUID_MCS_MEDIA_CONTROL_OPCODES_VAL ||
attr_uuid == BT_UUID_MCS_SEARCH_RESULTS_OBJ_ID_VAL ||
attr_uuid == BT_UUID_MCS_SEARCH_CONTROL_POINT_VAL ||
attr_uuid == BT_UUID_CCID_VAL);
case MICS_IN_PROGRESS:
return (attr_uuid == BT_UUID_MICS_MUTE_VAL);
case PACS_IN_PROGRESS:
return (attr_uuid == BT_UUID_PACS_SNK_VAL ||
attr_uuid == BT_UUID_PACS_SNK_LOC_VAL ||
attr_uuid == BT_UUID_PACS_SRC_VAL ||
attr_uuid == BT_UUID_PACS_SRC_LOC_VAL ||
attr_uuid == BT_UUID_PACS_AVAILABLE_CONTEXT_VAL ||
attr_uuid == BT_UUID_PACS_SUPPORTED_CONTEXT_VAL);
case GTBS_IN_PROGRESS:
case TBS_IN_PROGRESS:
return (attr_uuid == BT_UUID_TBS_PROVIDER_NAME_VAL ||
attr_uuid == BT_UUID_TBS_UCI_VAL ||
attr_uuid == BT_UUID_TBS_TECHNOLOGY_VAL ||
attr_uuid == BT_UUID_TBS_URI_LIST_VAL ||
attr_uuid == BT_UUID_TBS_SIGNAL_STRENGTH_VAL ||
attr_uuid == BT_UUID_TBS_SIGNAL_INTERVAL_VAL ||
attr_uuid == BT_UUID_TBS_LIST_CURRENT_CALLS_VAL ||
attr_uuid == BT_UUID_CCID_VAL ||
attr_uuid == BT_UUID_TBS_STATUS_FLAGS_VAL ||
attr_uuid == BT_UUID_TBS_INCOMING_URI_VAL ||
attr_uuid == BT_UUID_TBS_CALL_STATE_VAL ||
attr_uuid == BT_UUID_TBS_CALL_CONTROL_POINT_VAL ||
attr_uuid == BT_UUID_TBS_OPTIONAL_OPCODES_VAL ||
attr_uuid == BT_UUID_TBS_TERMINATE_REASON_VAL ||
attr_uuid == BT_UUID_TBS_INCOMING_CALL_VAL ||
attr_uuid == BT_UUID_TBS_FRIENDLY_NAME_VAL);
case TMAS_IN_PROGRESS:
return (attr_uuid == BT_UUID_GATT_TMAPR_VAL);
case VCS_IN_PROGRESS:
return (attr_uuid == BT_UUID_VCS_STATE_VAL ||
attr_uuid == BT_UUID_VCS_CONTROL_VAL ||
attr_uuid == BT_UUID_VCS_FLAGS_VAL);
case VOCS_IN_PROGRESS:
return (attr_uuid == BT_UUID_VOCS_STATE_VAL ||
attr_uuid == BT_UUID_VOCS_LOCATION_VAL ||
attr_uuid == BT_UUID_VOCS_CONTROL_VAL ||
attr_uuid == BT_UUID_VOCS_DESCRIPTION_VAL);
default:
return false;
}
}
static struct inc_svc_inst *get_not_included_inst(void)
{
switch (svc_in_progress) {
#if CONFIG_BT_CAP_ACCEPTOR_SET_MEMBER
case CAS_IN_PROGRESS:
extern struct inc_svc_inst *cas_not_included_inst(void);
return cas_not_included_inst();
#endif /* CONFIG_BT_CAP_ACCEPTOR_SET_MEMBER */
#if CONFIG_BT_MICP_MIC_DEV
case MICS_IN_PROGRESS:
extern struct inc_svc_inst *mics_not_included_inst(void);
return mics_not_included_inst();
#endif /* CONFIG_BT_MICP_MIC_DEV */
#if CONFIG_BT_VCP_VOL_REND
case VCS_IN_PROGRESS:
extern struct inc_svc_inst *vcs_not_included_inst(void);
return vcs_not_included_inst();
#endif /* CONFIG_BT_VCP_VOL_REND */
default:
return NULL;
}
}
static uint8_t get_svc_inst_id(uint16_t svc_uuid)
{
/* Note:
* For LE Audio, some service could have multiple instances.
*/
static uint8_t aics_count;
static uint8_t csis_count;
static uint8_t vocs_count;
static uint8_t mcs_count;
static uint8_t ots_count;
static uint8_t tbs_count;
switch (svc_uuid) {
case BT_UUID_AICS_VAL:
return aics_count++;
case BT_UUID_CSIS_VAL:
return csis_count++;
case BT_UUID_VOCS_VAL:
return vocs_count++;
case BT_UUID_MCS_VAL:
return mcs_count++;
case BT_UUID_OTS_VAL:
return ots_count++;
case BT_UUID_TBS_VAL:
return tbs_count++;
default:
return 0;
}
}
int bt_le_bluedroid_svc_init(struct bt_gatt_service *svc)
{
struct bt_gatt_attr *curr_attr;
struct bt_gatt_attr *next_attr;
struct inc_svc_inst *inc_inst;
struct bt_gatt_chrc *chrc;
tBTA_GATT_PERM perm;
uint16_t attr_uuid;
uint8_t inst_id;
tBT_UUID uuid;
assert(svc);
for (size_t i = 0; i < svc->attr_count; i++) {
curr_attr = &svc->attrs[i];
attr_uuid = BT_UUID_16(curr_attr->uuid)->val;
switch (attr_uuid) {
case BT_UUID_GATT_PRIMARY_VAL:
if (is_primary_svc() == false) {
LOG_ERR("[B]NotCreatingPrimary");
return -1;
}
assert(curr_attr->user_data);
bt_le_bluedroid_gatt_uuid_convert(curr_attr->user_data, &uuid);
inst_id = get_svc_inst_id(uuid.uu.uuid16);
bt_le_bluedroid_gatts_sem_reset();
BTA_GATTS_CreateService(bt_le_bluedroid_gatts_get_if(), &uuid, inst_id, svc->attr_count, true);
if (bt_le_bluedroid_gatts_sem_take()) {
LOG_ERR("[B]PrimaryCreateFail");
return -1;
}
curr_attr->handle = svc_handle;
LOG_INF("[B]PrimarySvc[%s][0x%04x][%u][0x%04x][%d]",
audio_svc_uuid_to_str(uuid.uu.uuid16), uuid.uu.uuid16,
inst_id, curr_attr->perm, svc_handle);
break;
case BT_UUID_GATT_SECONDARY_VAL:
if (is_secondary_svc() == false) {
LOG_ERR("[B]NotCreatingSecondary");
return -1;
}
assert(curr_attr->user_data);
bt_le_bluedroid_gatt_uuid_convert(curr_attr->user_data, &uuid);
inst_id = get_svc_inst_id(uuid.uu.uuid16);
bt_le_bluedroid_gatts_sem_reset();
BTA_GATTS_CreateService(bt_le_bluedroid_gatts_get_if(), &uuid, inst_id, svc->attr_count, false);
if (bt_le_bluedroid_gatts_sem_take()) {
LOG_ERR("[B]SecondaryCreateFail");
return -1;
}
curr_attr->handle = svc_handle;
LOG_INF("[B]SecondarySvc[%s][0x%04x][%u][0x%04x][%d]",
audio_svc_uuid_to_str(uuid.uu.uuid16), uuid.uu.uuid16,
inst_id, curr_attr->perm, svc_handle);
break;
case BT_UUID_GATT_INCLUDE_VAL:
if (any_included_svc() == false) {
LOG_ERR("[B]NoSvcToInc[%u]", svc_in_progress);
return -1;
}
inc_inst = get_not_included_inst();
if (inc_inst == NULL) {
LOG_ERR("[B]IncSvcNotFound[%u]", svc_in_progress);
return -1;
}
bt_le_bluedroid_gatts_sem_reset();
BTA_GATTS_AddIncludeService(svc_handle, inc_inst->svc_p->attrs[0].handle);
if (bt_le_bluedroid_gatts_sem_take()) {
LOG_ERR("[B]IncSvcAddFail");
return -1;
}
curr_attr->handle = inc_svc_handle;
inc_inst->included = true; /* Mark the svc as included */
LOG_INF("[B]IncSvc[%s][0x%04x][0x%04x][%d]",
audio_svc_uuid_to_str(BT_UUID_16(inc_inst->svc_p->attrs[0].user_data)->val),
BT_UUID_16(inc_inst->svc_p->attrs[0].user_data)->val,
curr_attr->perm, inc_svc_handle);
break;
case BT_UUID_GATT_CHRC_VAL:
/* Chrc declaration must be followed by its value attribute.
* Standard BT_GATT_CHARACTERISTIC pairs them, but guard against
* a malformed table where it is the last entry. */
if (i + 1 >= svc->attr_count) {
LOG_ERR("[B]ChrcDeclLastAttr[%u]", svc_in_progress);
return -1;
}
next_attr = &svc->attrs[i + 1];
perm = bt_le_bluedroid_gatt_perm_convert(next_attr->perm);
assert(curr_attr->user_data);
chrc = curr_attr->user_data;
bt_le_bluedroid_gatt_uuid_convert(chrc->uuid, &uuid);
bt_le_bluedroid_gatts_sem_reset();
BTA_GATTS_AddCharacteristic(svc_handle, &uuid, perm, chrc->properties, NULL, NULL);
if (bt_le_bluedroid_gatts_sem_take()) {
LOG_ERR("[B]ChrcAddFail");
return -1;
}
/* Characteristic declaration handle and Characteristic value handle */
curr_attr->handle = chrc_handle - 1;
next_attr->handle = chrc_handle;
LOG_INF("[B]Chrc[%s][0x%04x][%u][%u][0x%04x][0x%02x]",
audio_chrc_uuid_to_str(uuid.uu.uuid16), uuid.uu.uuid16,
chrc_handle - 1, chrc_handle, next_attr->perm, chrc->properties);
break;
case BT_UUID_GATT_CCC_VAL:
perm = bt_le_bluedroid_gatt_perm_convert(curr_attr->perm);
bt_le_bluedroid_gatt_uuid_convert(curr_attr->uuid, &uuid);
bt_le_bluedroid_gatts_sem_reset();
BTA_GATTS_AddCharDescriptor(svc_handle, perm, &uuid, NULL, NULL);
if (bt_le_bluedroid_gatts_sem_take()) {
LOG_ERR("[B]ChrcCccdAddFail");
return -1;
}
curr_attr->handle = chrc_handle;
LOG_INF("[B]ChrcCccd[%u][0x%04x]", chrc_handle, curr_attr->perm);
break;
default:
if (is_svc_attr_uuid_valid(attr_uuid) == false) {
LOG_ERR("[B]InvSvcAttrUuid[0x%04x][%u]", attr_uuid, svc_in_progress);
return -1;
}
break;
}
}
return 0;
}
int bt_le_bluedroid_svc_start(struct bt_gatt_service *svc)
{
assert(svc);
svc_handle = svc->attrs[0].handle;
/* App may not register this svc (e.g. CAP Acceptor single mode keeps
* unused capability built). Skip rather than fail audio_start.
*/
if (svc_handle == 0) {
LOG_DBG("[B]SvcNotInit[%u]", svc_in_progress);
return 0;
}
bt_le_bluedroid_gatts_sem_reset();
BTA_GATTS_StartService(svc_handle, BTA_GATT_TRANSPORT_LE);
if (bt_le_bluedroid_gatts_sem_take()) {
LOG_ERR("[B]SvcStartFail");
return -1;
}
return 0;
}
@@ -313,13 +313,18 @@ static int nimble_gatt_csis_init(struct bt_le_audio_start_info *info,
}
csis_svc[count] = lib_csip_set_member_svc_get(info->csis_insts[i].svc_inst);
assert(csis_svc[count]);
if (!csis_svc[count]) {
LOG_ERR("[N]CsisSvcGetFail[%u]", i);
return -ENODEV;
}
if (info->csis_insts[i].included_by_cas) {
if (*inc_csis_svc == NULL) {
*inc_csis_svc = csis_svc[count];
} else {
assert(0);
/* CAS may include at most one CSIS — caller misconfigured. */
LOG_ERR("[N]CsisMultiIncByCas");
return -EINVAL;
}
}
@@ -23,7 +23,7 @@
#include "host/ble_gatt.h"
#include "host/ble_hs_mbuf.h"
#include "nimble/profiles/server.h"
#include "nimble/server.h"
#include "common/host.h"
@@ -122,7 +122,10 @@ int bt_le_nimble_ascs_attr_handle_set(void)
}
ascs_svc = lib_ascs_svc_get();
assert(ascs_svc);
if (!ascs_svc) {
LOG_ERR("[N]AscsSvcGetFail");
return -ENODEV;
}
assert(ase_control_point_handle >= 2);
start_handle = ase_control_point_handle - 2; /* server attr handle & char def handle */
@@ -164,7 +167,10 @@ static int ascs_svc_check(void)
*/
ascs_svc = lib_ascs_svc_get();
assert(ascs_svc);
if (!ascs_svc) {
LOG_ERR("[N]AscsSvcGetFail");
return -ENODEV;
}
LOG_DBG("[N]AscsSvcCheck");
@@ -23,7 +23,7 @@
#include "host/ble_gatt.h"
#include "host/ble_hs_mbuf.h"
#include "nimble/profiles/server.h"
#include "nimble/server.h"
#include "common/host.h"
@@ -98,7 +98,10 @@ int bt_le_nimble_bass_attr_handle_set(void)
}
bass_svc = lib_bap_bass_svc_get();
assert(bass_svc);
if (!bass_svc) {
LOG_ERR("[N]BassSvcGetFail");
return -ENODEV;
}
assert(bass_control_point_handle >= 2);
start_handle = bass_control_point_handle - 2; /* server attr handle & char def handle */
@@ -134,7 +137,10 @@ static int bass_svc_check(void)
*/
bass_svc = lib_bap_bass_svc_get();
assert(bass_svc);
if (!bass_svc) {
LOG_ERR("[N]BassSvcGetFail");
return -ENODEV;
}
LOG_DBG("[N]BassSvcCheck");
@@ -60,7 +60,10 @@ int bt_le_nimble_cas_attr_handle_set(void)
}
cas_svc = lib_cas_svc_get();
assert(cas_svc);
if (!cas_svc) {
LOG_ERR("[N]CasSvcGetFail");
return -ENODEV;
}
LOG_DBG("[N]CasAttrHdlSet[%u][%u]", handle, cas_svc->attr_count);
@@ -113,7 +116,10 @@ int bt_le_nimble_cas_init(void *csis_svc_p)
struct bt_gatt_service *cas_svc;
cas_svc = lib_cas_svc_get();
assert(cas_svc);
if (!cas_svc) {
LOG_ERR("[N]CasSvcGetFail");
return -ENODEV;
}
/* Insert CAS to the GATT db list */
rc = bt_gatt_service_register_safe(cas_svc);
@@ -25,7 +25,7 @@
#include "host/ble_gatt.h"
#include "host/ble_hs_mbuf.h"
#include "nimble/profiles/server.h"
#include "nimble/server.h"
#include "common/host.h"
@@ -23,7 +23,7 @@
#include "host/ble_gatt.h"
#include "host/ble_hs_mbuf.h"
#include "nimble/profiles/server.h"
#include "nimble/server.h"
#include "common/host.h"
@@ -120,7 +120,10 @@ int bt_le_nimble_has_attr_handle_set(void)
}
has_svc = lib_has_svc_get();
assert(has_svc);
if (!has_svc) {
LOG_ERR("[N]HasSvcGetFail");
return -ENODEV;
}
assert(has_svc->attr_count > 0);
end_handle = start_handle + has_svc->attr_count - 1;
@@ -136,7 +139,7 @@ int bt_le_nimble_has_attr_handle_set(void)
attr = has_svc->attrs + has_svc->attr_count - 1;
if (attr->handle != end_handle) {
LOG_ERR("[N]HasMismatchAttrHdl (%u %u %u %u)",
LOG_ERR("[N]HasMismatchAttrHdl[%u][%u][%u][%u]",
start_handle, end_handle, attr->handle, has_svc->attr_count);
return -1;
}
@@ -155,7 +158,10 @@ static int has_svc_check(void)
*/
has_svc = lib_has_svc_get();
assert(has_svc);
if (!has_svc) {
LOG_ERR("[N]HasSvcGetFail");
return -ENODEV;
}
LOG_DBG("[N]HasSvcCheck");
@@ -28,7 +28,7 @@
#include "host/ble_gatt.h"
#include "host/ble_hs_mbuf.h"
#include "nimble/profiles/server.h"
#include "nimble/server.h"
#include "common/host.h"
@@ -403,7 +403,10 @@ int bt_le_nimble_gmcs_attr_handle_set(void)
}
gmcs_svc = lib_mcs_svc_get();
assert(gmcs_svc);
if (!gmcs_svc) {
LOG_ERR("[N]GmcsSvcGetFail");
return -ENODEV;
}
end_handle = start_handle + gmcs_svc->attr_count - 1;
@@ -446,7 +449,10 @@ static int gmcs_svc_check(void)
*/
gmcs_svc = lib_mcs_svc_get();
assert(gmcs_svc);
if (!gmcs_svc) {
LOG_ERR("[N]GmcsSvcGetFail");
return -ENODEV;
}
LOG_DBG("[N]GmcsSvcCheck");
@@ -23,7 +23,7 @@
#include "host/ble_gatt.h"
#include "host/ble_hs_mbuf.h"
#include "nimble/profiles/server.h"
#include "nimble/server.h"
#include "common/host.h"
@@ -159,7 +159,10 @@ static int mics_svc_check(void)
bool chr_found;
mics_svc = lib_mics_svc_get();
assert(mics_svc);
if (!mics_svc) {
LOG_ERR("[N]MicsSvcGetFail");
return -ENODEV;
}
LOG_DBG("[N]MicsSvcCheck");
@@ -244,7 +247,10 @@ int bt_le_nimble_mics_attr_handle_set(void)
}
mics_svc = lib_mics_svc_get();
assert(mics_svc);
if (!mics_svc) {
LOG_ERR("[N]MicsSvcGetFail");
return -ENODEV;
}
end_handle = start_handle + mics_svc->attr_count - 1;
@@ -379,6 +385,11 @@ int bt_le_nimble_mics_init(void *micp_inc)
inc_aics_svc_init(&inc_aics_insts[i], &gatt_svc_inc_aics[i]);
inc_aics_insts[i].svc_p = lib_aics_svc_get(micp_included->aics[i]);
if (!inc_aics_insts[i].svc_p) {
LOG_ERR("[N]AicsSvcGetFail[%u]", i);
rc = -ENODEV;
goto free;
}
mics_inc_svcs[i] = &gatt_svc_inc_aics[i];
}
@@ -21,7 +21,7 @@
#include "host/ble_gatt.h"
#include "host/ble_hs_mbuf.h"
#include "nimble/profiles/server.h"
#include "nimble/server.h"
#include "common/host.h"
@@ -166,7 +166,10 @@ int bt_le_nimble_pacs_attr_handle_set(void)
uint16_t end_handle = 0;
pacs_svc = lib_pacs_svc_get();
assert(pacs_svc);
if (!pacs_svc) {
LOG_ERR("[N]PacsSvcGetFail");
return -ENODEV;
}
#if CONFIG_BT_PAC_SNK
assert(pacs_snk_handle >= 2);
@@ -214,7 +217,10 @@ static int pacs_svc_check(void)
*/
pacs_svc = lib_pacs_svc_get();
assert(pacs_svc);
if (!pacs_svc) {
LOG_ERR("[N]PacsSvcGetFail");
return -ENODEV;
}
LOG_DBG("[N]PacsSvcCheck");
@@ -21,7 +21,7 @@
#include "host/ble_gatt.h"
#include "host/ble_hs_mbuf.h"
#include "nimble/profiles/server.h"
#include "nimble/server.h"
#include "common/host.h"
@@ -178,7 +178,10 @@ int bt_le_nimble_gtbs_attr_handle_set(void)
}
gtbs_svc = lib_gtbs_svc_get();
assert(gtbs_svc);
if (!gtbs_svc) {
LOG_ERR("[N]GtbsSvcGetFail");
return -ENODEV;
}
LOG_DBG("[N]GtbsAttrHdlSet[%u][%u]", handle, gtbs_svc->attr_count);
@@ -200,7 +203,10 @@ static int gtbs_svc_check(void)
*/
gtbs_svc = lib_gtbs_svc_get();
assert(gtbs_svc);
if (!gtbs_svc) {
LOG_ERR("[N]GtbsSvcGetFail");
return -ENODEV;
}
LOG_DBG("[N]GtbsSvcCheck");
@@ -21,7 +21,7 @@
#include "host/ble_gatt.h"
#include "host/ble_hs_mbuf.h"
#include "nimble/profiles/server.h"
#include "nimble/server.h"
#include "common/host.h"
@@ -71,7 +71,10 @@ int bt_le_nimble_tmas_attr_handle_set(void)
}
tmas_svc = lib_tmas_svc_get();
assert(tmas_svc);
if (!tmas_svc) {
LOG_ERR("[N]TmasSvcGetFail");
return -ENODEV;
}
LOG_DBG("[N]TmasAttrHdlSet[%u][%u]", handle, tmas_svc->attr_count);
@@ -93,7 +96,10 @@ static int tmas_svc_check(void)
*/
tmas_svc = lib_tmas_svc_get();
assert(tmas_svc);
if (!tmas_svc) {
LOG_ERR("[N]TmasSvcGetFail");
return -ENODEV;
}
LOG_DBG("[N]TmasSvcCheck");
@@ -23,7 +23,7 @@
#include "host/ble_gatt.h"
#include "host/ble_hs_mbuf.h"
#include "nimble/profiles/server.h"
#include "nimble/server.h"
#include "common/host.h"
@@ -261,7 +261,10 @@ static int vcs_svc_check(void)
*/
vcs_svc = lib_vcs_svc_get();
assert(vcs_svc);
if (!vcs_svc) {
LOG_ERR("[N]VcsSvcGetFail");
return -ENODEV;
}
LOG_DBG("[N]VCSSvcCheck");
@@ -380,7 +383,10 @@ int bt_le_nimble_vcs_attr_handle_set(void)
}
vcs_svc = lib_vcs_svc_get();
assert(vcs_svc);
if (!vcs_svc) {
LOG_ERR("[N]VcsSvcGetFail");
return -ENODEV;
}
end_handle = start_handle + vcs_svc->attr_count - 1;
@@ -576,6 +582,11 @@ int bt_le_nimble_vcs_init(void *vcp_inc)
inc_vocs_svc_init(&inc_vocs_insts[i], &gatt_svc_inc_vocs[i]);
inc_vocs_insts[i].svc_p = lib_vocs_svc_get(vcp_included->vocs[i]);
if (!inc_vocs_insts[i].svc_p) {
LOG_ERR("[N]VocsSvcGetFail[%u]", i);
rc = -ENODEV;
goto free;
}
vcs_inc_svcs[i] = &gatt_svc_inc_vocs[i];
}
@@ -608,6 +619,11 @@ int bt_le_nimble_vcs_init(void *vcp_inc)
inc_aics_svc_init(&inc_aics_insts[i], &gatt_svc_inc_aics[i]);
inc_aics_insts[i].svc_p = lib_aics_svc_get(vcp_included->aics[i]);
if (!inc_aics_insts[i].svc_p) {
LOG_ERR("[N]AicsSvcGetFail[%u]", i);
rc = -ENODEV;
goto free;
}
vcs_inc_svcs[inc_vocs_svc_count + i] = &gatt_svc_inc_aics[i];
}
@@ -670,13 +686,17 @@ free:
}
if (inc_aics_svc_count) {
for (size_t i = 0; i < inc_aics_svc_count; i++) {
free((void *)gatt_svc_inc_aics[i].characteristics);
gatt_svc_inc_aics[i].characteristics = NULL;
}
/* A VOCS-phase failure reaches here with the count already set
* but gatt_svc_inc_aics not yet allocated (still NULL). */
if (gatt_svc_inc_aics) {
for (size_t i = 0; i < inc_aics_svc_count; i++) {
free((void *)gatt_svc_inc_aics[i].characteristics);
gatt_svc_inc_aics[i].characteristics = NULL;
}
free(gatt_svc_inc_aics);
gatt_svc_inc_aics = NULL;
free(gatt_svc_inc_aics);
gatt_svc_inc_aics = NULL;
}
inc_aics_svc_count = 0;
}
@@ -44,7 +44,11 @@
#include <../host/conn_internal.h>
#include <../host/hci_core.h>
#if CONFIG_BT_BLUEDROID_ENABLED
#include "bluedroid/init.h"
#else
#include "nimble/init.h"
#endif
#include "../../../lib/include/audio.h"
@@ -2091,7 +2095,11 @@ int bt_le_audio_init(void)
return err;
}
#if CONFIG_BT_BLUEDROID_ENABLED
return bt_le_bluedroid_audio_init();
#else
return bt_le_nimble_audio_init();
#endif
}
#if BLE_AUDIO_SVC_DEFERRED_ADD
@@ -2100,7 +2108,11 @@ int bt_le_ascs_init(void)
{
LOG_DBG("AscsInit");
#if CONFIG_BT_BLUEDROID_ENABLED
return bt_le_bluedroid_ascs_init();
#else
return bt_le_nimble_ascs_init();
#endif
}
#endif /* CONFIG_BT_ASCS */
@@ -2109,7 +2121,11 @@ int bt_le_bass_init(void)
{
LOG_DBG("BassInit");
#if CONFIG_BT_BLUEDROID_ENABLED
return bt_le_bluedroid_bass_init();
#else
return bt_le_nimble_bass_init();
#endif
}
#endif /* CONFIG_BT_BAP_SCAN_DELEGATOR */
@@ -2118,7 +2134,11 @@ int bt_le_tmas_init(void)
{
LOG_DBG("TmasInit");
#if CONFIG_BT_BLUEDROID_ENABLED
return bt_le_bluedroid_tmas_init();
#else
return bt_le_nimble_tmas_init();
#endif
}
#endif /* CONFIG_BT_TMAP */
@@ -2127,7 +2147,11 @@ int bt_le_gtbs_init(void)
{
LOG_DBG("GtbsInit");
#if CONFIG_BT_BLUEDROID_ENABLED
return bt_le_bluedroid_gtbs_init();
#else
return bt_le_nimble_gtbs_init();
#endif
}
#endif /* CONFIG_BT_TBS */
@@ -2136,7 +2160,11 @@ int bt_le_has_init(void)
{
LOG_DBG("HasInit");
#if CONFIG_BT_BLUEDROID_ENABLED
return bt_le_bluedroid_has_init();
#else
return bt_le_nimble_has_init();
#endif
}
#endif /* CONFIG_BT_HAS */
@@ -2145,7 +2173,11 @@ int bt_le_media_proxy_pl_init(void)
{
LOG_DBG("MprxPlInit");
#if CONFIG_BT_BLUEDROID_ENABLED
return bt_le_bluedroid_media_proxy_pl_init();
#else
return bt_le_nimble_media_proxy_pl_init();
#endif
}
#endif /* CONFIG_BT_MCS */
@@ -2154,7 +2186,11 @@ int bt_le_vcp_vol_rend_init(void)
{
LOG_DBG("VcpVolRendInit");
#if CONFIG_BT_BLUEDROID_ENABLED
return bt_le_bluedroid_vcp_vol_rend_init();
#else
return bt_le_nimble_vcp_vol_rend_init();
#endif
}
#endif /* CONFIG_BT_VCP_VOL_REND */
@@ -2163,7 +2199,11 @@ int bt_le_micp_mic_dev_init(void)
{
LOG_DBG("MicpMicDevInit");
#if CONFIG_BT_BLUEDROID_ENABLED
return bt_le_bluedroid_micp_mic_dev_init();
#else
return bt_le_nimble_micp_mic_dev_init();
#endif
}
#endif /* CONFIG_BT_MICP_MIC_DEV */
#endif /* BLE_AUDIO_SVC_DEFERRED_ADD */
@@ -2172,7 +2212,11 @@ int bt_le_audio_start(void *info)
{
LOG_DBG("AudioStart");
#if CONFIG_BT_BLUEDROID_ENABLED
return bt_le_bluedroid_audio_start(info);
#else
return bt_le_nimble_audio_start(info);
#endif
}
void ble_audio_lib_compressed_out(uint8_t log_level, uint32_t log_index, size_t arg_cnt, ...)