feat(ble_audio): Support ISO & LE Audio functionalities (Preview)

This commit is contained in:
Linyan Liu
2026-02-25 17:52:10 +08:00
committed by BOT
parent 15a0d3fdea
commit 3ef5da096a
383 changed files with 155035 additions and 5 deletions
+1
View File
@@ -168,6 +168,7 @@
- "components/bt/controller/lib_esp32c5/esp32c5-bt-lib"
- "components/bt/controller/lib_esp32h4/esp32h4-bt-lib"
- "components/bt/esp_ble_mesh/lib/lib"
- "components/bt/esp_ble_audio/lib/lib"
- ".gitmodules"
##############
+5
View File
@@ -149,3 +149,8 @@
path = components/bt/esp_ble_mesh/lib/lib
url = ../../espressif/esp-ble-mesh-lib.git
shallow = true
[submodule "components/bt/esp_ble_audio/lib/lib"]
path = components/bt/esp_ble_audio/lib/lib
url = ../../espressif/esp-ble-audio-lib.git
shallow = true
+171
View File
@@ -57,6 +57,14 @@ if(CONFIG_IDF_DOC_BUILD)
${ble_mesh_v11_include_dirs})
endif()
set(ble_iso_include_dirs
"esp_ble_audio/api/iso/include"
)
set(ble_audio_include_dirs
"esp_ble_audio/api/audio/include"
)
set(bluedroid_include_dirs host/bluedroid/api/include/api)
if(CONFIG_BT_CONTROLLER_ENABLED OR CONFIG_IDF_DOC_BUILD)
@@ -68,6 +76,8 @@ if(CONFIG_IDF_DOC_BUILD)
${target_specific_include_dirs}
${common_include_dirs}
${ble_mesh_include_dirs}
${ble_iso_include_dirs}
${ble_audio_include_dirs}
${bluedroid_include_dirs}
${nimble_hci_include_dirs})
endif()
@@ -680,6 +690,160 @@ if(CONFIG_BT_ENABLED)
endif()
endif()
if(CONFIG_BT_ISO)
list(APPEND include_dirs
${ble_iso_include_dirs}
"esp_ble_audio/host"
"esp_ble_audio/host/adapter"
"esp_ble_audio/include/subsys/bluetooth"
"esp_ble_audio/include/subsys/bluetooth/host"
"esp_ble_audio/include")
list(APPEND srcs
"esp_ble_audio/host/adapter/nimble/gatt/gatt.c"
"esp_ble_audio/host/adapter/nimble/gatt/gatt.db.c"
"esp_ble_audio/host/adapter/nimble/gatt/gatt.nrp.c"
"esp_ble_audio/host/adapter/nimble/gap.c"
"esp_ble_audio/host/adapter/nimble/iso.c"
"esp_ble_audio/host/common/adv.c"
"esp_ble_audio/host/common/conn.c"
"esp_ble_audio/host/common/gatt.c"
"esp_ble_audio/host/common/hci.c"
"esp_ble_audio/host/common/host.c"
"esp_ble_audio/host/common/iso.c"
"esp_ble_audio/host/common/scan.c"
"esp_ble_audio/host/common/task.c"
"esp_ble_audio/host/common/app/gap.c"
"esp_ble_audio/host/common/app/gatt.c"
"esp_ble_audio/host/utils/crc/crc32_sw.c"
"esp_ble_audio/host/utils/addr.c"
"esp_ble_audio/host/utils/bt_str.c"
"esp_ble_audio/host/utils/buf.c"
"esp_ble_audio/host/utils/crypto.c"
"esp_ble_audio/host/utils/timer.c"
"esp_ble_audio/host/utils/utf8.c"
"esp_ble_audio/host/utils/utils.c"
"esp_ble_audio/host/utils/uuid.c"
"esp_ble_audio/host/iso/iso.c"
"esp_ble_audio/api/iso/esp_ble_iso_common_api.c")
if(CONFIG_BT_OTS OR CONFIG_BT_OTS_CLIENT)
list(APPEND srcs
"esp_ble_audio/host/common/l2cap.c"
"esp_ble_audio/host/adapter/nimble/l2cap.c")
endif()
endif()
if(CONFIG_BT_AUDIO)
list(APPEND include_dirs
${ble_audio_include_dirs}
"esp_ble_audio/include/subsys/bluetooth/host")
list(APPEND srcs
"esp_ble_audio/host/adapter/nimble/profiles/server.c"
"esp_ble_audio/host/adapter/nimble/init.c"
"esp_ble_audio/host/common/init.c"
"esp_ble_audio/api/audio/esp_ble_audio_aics_api.c"
"esp_ble_audio/api/audio/esp_ble_audio_bap_api.c"
"esp_ble_audio/api/audio/esp_ble_audio_cap_api.c"
"esp_ble_audio/api/audio/esp_ble_audio_ccp_api.c"
"esp_ble_audio/api/audio/esp_ble_audio_codec_api.c"
"esp_ble_audio/api/audio/esp_ble_audio_common_api.c"
"esp_ble_audio/api/audio/esp_ble_audio_csip_api.c"
"esp_ble_audio/api/audio/esp_ble_audio_gmap_api.c"
"esp_ble_audio/api/audio/esp_ble_audio_has_api.c"
"esp_ble_audio/api/audio/esp_ble_audio_mcc_api.c"
"esp_ble_audio/api/audio/esp_ble_audio_media_proxy_api.c"
"esp_ble_audio/api/audio/esp_ble_audio_micp_api.c"
"esp_ble_audio/api/audio/esp_ble_audio_pacs_api.c"
"esp_ble_audio/api/audio/esp_ble_audio_pbp_api.c"
"esp_ble_audio/api/audio/esp_ble_audio_tbs_api.c"
"esp_ble_audio/api/audio/esp_ble_audio_tmap_api.c"
"esp_ble_audio/api/audio/esp_ble_audio_vcp_api.c"
"esp_ble_audio/api/audio/esp_ble_audio_vocs_api.c")
if(CONFIG_BT_ASCS)
list(APPEND srcs
"esp_ble_audio/host/adapter/nimble/profiles/ascs.c")
endif()
if(CONFIG_BT_PACS)
list(APPEND srcs
"esp_ble_audio/host/adapter/nimble/profiles/pacs.c")
endif()
if(CONFIG_BT_BAP_SCAN_DELEGATOR)
list(APPEND srcs
"esp_ble_audio/host/adapter/nimble/profiles/bass.c")
endif()
if(CONFIG_BT_CAP_ACCEPTOR)
list(APPEND srcs
"esp_ble_audio/host/adapter/nimble/profiles/cas.c")
endif()
if(CONFIG_BT_CSIP_SET_MEMBER)
list(APPEND srcs
"esp_ble_audio/host/adapter/nimble/profiles/csis.c")
endif()
if(CONFIG_BT_TBS)
list(APPEND srcs
"esp_ble_audio/host/adapter/nimble/profiles/tbs.c")
endif()
if(CONFIG_BT_TMAP)
list(APPEND srcs
"esp_ble_audio/host/adapter/nimble/profiles/tmas.c")
endif()
if(CONFIG_BT_VCP_VOL_REND)
list(APPEND srcs
"esp_ble_audio/host/adapter/nimble/profiles/vcs.c")
endif()
if(CONFIG_BT_MICP_MIC_DEV)
list(APPEND srcs
"esp_ble_audio/host/adapter/nimble/profiles/mics.c")
endif()
if(CONFIG_BT_MCS)
list(APPEND srcs
"esp_ble_audio/host/adapter/nimble/profiles/mcs.c")
endif()
if(CONFIG_BT_HAS)
list(APPEND srcs
"esp_ble_audio/host/adapter/nimble/profiles/has.c")
endif()
if(CONFIG_BT_OTS OR CONFIG_BT_OTS_CLIENT)
list(APPEND include_dirs
"esp_ble_audio/host/services/ots")
list(APPEND srcs
"esp_ble_audio/host/services/ots/ots_l2cap.c")
if(CONFIG_BT_OTS)
list(APPEND srcs
"esp_ble_audio/host/services/ots/ots_oacp.c"
"esp_ble_audio/host/services/ots/ots_obj_manager.c"
"esp_ble_audio/host/services/ots/ots_olcp.c"
"esp_ble_audio/host/services/ots/ots.c")
if(CONFIG_BT_OTS_DIR_LIST_OBJ)
list(APPEND srcs
"esp_ble_audio/host/services/ots/ots_dir_list.c")
endif()
endif()
if(CONFIG_BT_OTS_CLIENT)
list(APPEND srcs
"esp_ble_audio/host/services/ots/ots_client.c")
endif()
endif()
endif()
if(CONFIG_BT_DUAL_MODE_ARCH)
add_subdirectory(porting_btdm)
list(APPEND srcs
@@ -1171,6 +1335,13 @@ if(CONFIG_BT_NIMBLE_MESH)
PROPERTIES COMPILE_FLAGS -Wno-type-limits)
endif()
if(CONFIG_BT_AUDIO)
if(CONFIG_IDF_TARGET_ESP32H4)
add_prebuilt_library(ble_audio "esp_ble_audio/lib/lib/esp32h4/libble_audio.a")
target_link_libraries(${COMPONENT_LIB} PRIVATE ble_audio)
endif()
endif()
if(CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_DISABLE AND CONFIG_BT_NIMBLE_ENABLED)
# some variables in NimBLE are only used by asserts
target_compile_options(${COMPONENT_LIB} PRIVATE -Wno-unused-but-set-variable -Wno-unused-variable)
+10
View File
@@ -109,6 +109,16 @@ menu "Bluetooth"
This option is to configure the buffer size of the hci adv report cache in hci debug mode.
This is a ring buffer, the new data will overwrite the oldest data if the buffer is full.
menu "BLE ISO Options"
depends on BT_ENABLED && SOC_BLE_ISO_SUPPORTED
source "$IDF_PATH/components/bt/esp_ble_audio/host/iso/Kconfig.iso.in"
endmenu
menu "BLE Audio Options"
depends on BT_ENABLED && SOC_BLE_AUDIO_SUPPORTED
source "$IDF_PATH/components/bt/esp_ble_audio/Kconfig.in"
endmenu
endmenu
menuconfig BLE_MESH
+142
View File
@@ -0,0 +1,142 @@
# Bluetooth Audio configuration options
# SPDX-FileCopyrightText: 2020 Intel Corporation
# SPDX-FileCopyrightText: 2022 Nordic Semiconductor ASA
# SPDX-License-Identifier: Apache-2.0
config BT_AUDIO
bool # hidden
help
This option enables Bluetooth Audio support. The specific
features that are available may depend on other features
that have been enabled in the stack, such as Periodic
Advertisement for Broadcast and L2CAP Dynamic Channel
for Unicast.
config BT_AUDIO_RX
bool # hidden
default y if BT_ASCS_ASE_SNK || BT_BAP_UNICAST_CLIENT_ASE_SRC || BT_BAP_BROADCAST_SINK
select BT_AUDIO
config BT_AUDIO_TX
bool # hidden
default y if BT_ASCS_ASE_SRC || BT_BAP_UNICAST_CLIENT_ASE_SNK || BT_BAP_BROADCAST_SOURCE
select BT_AUDIO
menu "AICS Options"
rsource "Kconfig/Kconfig.aics.in"
endmenu
menu "ASCS Options"
rsource "Kconfig/Kconfig.ascs.in"
endmenu
menu "BAP Options"
rsource "Kconfig/Kconfig.bap.in"
endmenu
menu "CAP Options"
rsource "Kconfig/Kconfig.cap.in"
endmenu
menu "CCP Options"
rsource "Kconfig/Kconfig.ccp.in"
endmenu
menu "CSIP Options"
rsource "Kconfig/Kconfig.csip.in"
endmenu
menu "GMAP Options"
rsource "Kconfig/Kconfig.gmap.in"
endmenu
menu "MCS Options"
rsource "Kconfig/Kconfig.mcs.in"
endmenu
menu "MCTL Options"
rsource "Kconfig/Kconfig.mctl.in"
endmenu
menu "MICP Options"
rsource "Kconfig/Kconfig.micp.in"
endmenu
menu "MPL Options"
rsource "Kconfig/Kconfig.mpl.in"
endmenu
menu "PACS Options"
rsource "Kconfig/Kconfig.pacs.in"
endmenu
menu "TBS Options"
rsource "Kconfig/Kconfig.tbs.in"
endmenu
menu "VCP Options"
rsource "Kconfig/Kconfig.vcp.in"
endmenu
menu "VOCS Options"
rsource "Kconfig/Kconfig.vocs.in"
endmenu
menu "TMAP Options"
rsource "Kconfig/Kconfig.tmap.in"
endmenu
menu "HAS Options"
rsource "Kconfig/Kconfig.has.in"
endmenu
menu "PBP Options"
rsource "Kconfig/Kconfig.pbp.in"
endmenu
menu "OTS Options"
rsource "host/services/ots/Kconfig.ots.in"
endmenu
config BT_AUDIO_NO_LOG
bool "Disable BLE Audio Debug Log"
default n
help
Select this to save the BLE Audio related rodata code size. Enabling
this option will disable the output of BLE Audio debug log.
menu "BLE Audio Debug Log Level"
depends on !BT_AUDIO_NO_LOG
choice BT_AUDIO_LOG_LEVEL
prompt "LE_AUDIO_LOG_LEVEL"
default BT_AUDIO_LOG_LEVEL_WARNING
depends on !BT_AUDIO_NO_LOG
help
Define BLE Audio trace level.
config BT_AUDIO_LOG_LEVEL_NONE
bool "NONE"
config BT_AUDIO_LOG_LEVEL_ERROR
bool "ERROR"
config BT_AUDIO_LOG_LEVEL_WARNING
bool "WARNING"
config BT_AUDIO_LOG_LEVEL_INFO
bool "INFO"
config BT_AUDIO_LOG_LEVEL_DEBUG
bool "DEBUG"
config BT_AUDIO_LOG_LEVEL_VERBOSE
bool "VERBOSE"
endchoice
config BT_AUDIO_LOG_LEVEL
int
default 0 if BT_AUDIO_LOG_LEVEL_NONE
default 1 if BT_AUDIO_LOG_LEVEL_ERROR
default 2 if BT_AUDIO_LOG_LEVEL_WARNING
default 3 if BT_AUDIO_LOG_LEVEL_INFO
default 4 if BT_AUDIO_LOG_LEVEL_DEBUG
default 5 if BT_AUDIO_LOG_LEVEL_VERBOSE
default 2
endmenu
@@ -0,0 +1,50 @@
# Bluetooth Audio - Audio Input Control Service options
#
# SPDX-FileCopyrightText: 2020 Bose Corporation
# SPDX-FileCopyrightText: 2020 Nordic Semiconductor ASA
#
# SPDX-License-Identifier: Apache-2.0
#
##################### Audio Input Control Service #####################
config BT_AICS_MAX_INSTANCE_COUNT
int "Audio Input Control Service max instance count"
default 0
range 0 15
help
This option sets the maximum number of instances of Audio Input
Control Services.
config BT_AICS
bool # hidden
default y if BT_AICS_MAX_INSTANCE_COUNT > 0
help
This hidden option enables support for Audio Input Control Service.
if BT_AICS
config BT_AICS_MAX_INPUT_DESCRIPTION_SIZE
int "Audio Input Control Service max input description size"
default 32
range 0 512
help
This option sets the maximum input description size in octets.
endif # BT_AICS
##################### Audio Input Control Service Client #####################
config BT_AICS_CLIENT_MAX_INSTANCE_COUNT
int "Audio Input Control Service client max instance count"
default 0
range 0 15
help
This option sets the maximum number of instances of Audio Input
Control Services.
config BT_AICS_CLIENT
bool # hidden
default y if BT_AICS_CLIENT_MAX_INSTANCE_COUNT > 0
help
This hidden option enables support for Audio Input Control Service.
@@ -0,0 +1,73 @@
# Bluetooth Audio - Audio Stream Control configuration options
#
# SPDX-FileCopyrightText: 2020 Intel Corporation
# SPDX-FileCopyrightText: 2022 Nordic Semiconductor ASA
# SPDX-License-Identifier: Apache-2.0
#
config BT_ASCS
bool "Audio Stream Control Service Support"
help
This option enables support for Audio Stream Control Service.
if BT_ASCS
config BT_ASCS_MAX_ASE_SNK_COUNT
int "Maximum number of Audio Stream Endpoint Sink Characteristics"
default 2
range 0 255
help
An ASE Sink characteristic represents the state of an ASE, which is
coupled to a single direction of a unicast Audio Stream.
config BT_ASCS_MAX_ASE_SRC_COUNT
int "Maximum number of Audio Stream Endpoint Source Characteristics"
default 2
range 0 255
help
An ASE Source characteristic represents the state of an ASE, which is
coupled to a single direction of a unicast Audio Stream.
config BT_ASCS_ASE_SNK
bool # hidden
default y if BT_ASCS_MAX_ASE_SNK_COUNT > 0
select BT_PAC_SNK
select BT_AUDIO_RX
config BT_ASCS_ASE_SRC
bool # hidden
default y if BT_ASCS_MAX_ASE_SRC_COUNT > 0
select BT_PAC_SRC
select BT_AUDIO_TX
config BT_ASCS_MAX_ACTIVE_ASES
int "Number of simultaneously supported ASE sessions"
default BT_ISO_MAX_CHAN
range 1 65535
help
The number of simultaneously supported active ASEs, in particular
meaning the number of ASEs that are allowed to be in a non-idle state at
a single time.
config BT_ASCS_ISO_DISCONNECT_DELAY
int "Milliseconds of delay before ASCS disconnects ISO after stream stop"
range 0 5000
default 500
help
The number of milliseconds ASCS will wait before disconnecting the ISO
of a stopped stream. The delay is added as it is the Unicast Client's
responsibility, but this is a failsafe to ensure that ISO channel is
being properly disconnected.
config BT_ASCS_ASE_BUF_TIMEOUT
int "Milliseconds of timeout when handle concurrent access to the long read ASE buffer"
range 0 1000
default 50
help
The number of milliseconds that the ASCS implementation will maximum wait before rejecting
an ASE read or dropping a notification if the ASE state is being accessed by another
thread.
endif # BT_ASCS
@@ -0,0 +1,268 @@
# Bluetooth Audio - Basic Audio Profile configuration options
#
# SPDX-FileCopyrightText: 2020 Intel Corporation
# SPDX-FileCopyrightText: 2022-2025 Nordic Semiconductor ASA
# SPDX-License-Identifier: Apache-2.0
#
config BT_BAP_UNICAST
bool
default y if BT_BAP_UNICAST_SERVER || BT_BAP_UNICAST_CLIENT
config BT_BAP_UNICAST_SERVER
bool "Bluetooth Unicast Audio Server Support"
select BT_ISO_PERIPHERAL
select BT_ASCS
select BT_PAC_SNK if BT_ASCS_ASE_SNK
select BT_PAC_SRC if BT_ASCS_ASE_SRC
help
This option enables support for Bluetooth Unicast Audio Server
using Isochronous channels.
config BT_BAP_UNICAST_CLIENT
bool "Bluetooth Unicast Audio Client Support"
select BT_ISO_CENTRAL
help
This option enables support for Bluetooth Unicast Audio Client
using Isochronous channels.
config BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE
int "Codec Specific Configuration Data Size"
default 19
range 0 255
help
Number of octets to support for Codec Specific Configuration data.
The default value 19 matches the required fields for the LC3 codec.
config BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE
int "Codec Specific Configuration Metadata Size"
default 20
range 0 255
help
Number of octets to support for Codec Specific Configuration metadata.
config BT_BAP_BASS_MAX_SUBGROUPS
int "Maximum number of subgroups supported for the BASS receive states"
default 1
range 1 24
help
This option sets the maximum number of subgroups supported.
Due to limitations in advertising data, the maximum size of all subgroups are 249.
The minimum size of a subgroup is 10 octets.
So effectively there can be a maximum of 24 subgroups in a BASE.
config BT_AUDIO_CODEC_CAP_MAX_DATA_SIZE
int "Codec Capabilities Data Size"
default 19
range 0 255
help
Number of octets to support for Codec Specific Capabilities data.
The default value 19 matches the required fields for the LC3 codec.
config BT_AUDIO_CODEC_CAP_MAX_METADATA_SIZE
int "Codec Capabilities Metadata Size"
default 4
range 0 255
help
Number of octets to support for Codec Specific Capabilities metadata.
if BT_BAP_UNICAST_CLIENT
config BT_BAP_UNICAST_CLIENT_GROUP_COUNT
int "Basic Audio Unicast Group count"
default 1
range 1 BT_ISO_MAX_CIG
help
This option sets the number of connected audio groups to support as
the unicast client.
config BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT
int "Basic Audio Profile Unicast Group Connected Isochronous Stream (CIS) count"
depends on BT_BAP_UNICAST_CLIENT_GROUP_COUNT > 0
default 1
range 1 BT_ISO_MAX_CHAN if BT_ISO_MAX_CHAN < 31
range 1 31
help
This option sets the maximum number of CIS per unicast group to support.
Since BAP streams are unidirectional, two BAP streams may use a single CIS, the number of
BAP audio streams per group may be up to twice of this value.
config BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT
int "Basic Audio Profile ASE Sink count"
default 2
range 0 255
help
This option enables caching a number of Audio Stream Endpoint Sink
instances for Basic Audio Profile on a per connection basis.
config BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT
int "Basic Audio Profile ASE Source count"
default 2
range 0 255
help
This option enables caching a number of Audio Stream Endpoint Source
instances for Basic Audio Profile on a per connection basis.
config BT_BAP_UNICAST_CLIENT_ASE_SNK
bool # hidden
default y if BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 0
config BT_BAP_UNICAST_CLIENT_ASE_SRC
bool # hidden
default y if BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 0
endif # BT_BAP_UNICAST_CLIENT
config BT_BAP_BROADCAST_SOURCE
bool "Bluetooth Broadcast Source Audio Support"
select BT_ISO_BROADCASTER
help
This option enables support for Bluetooth Broadcast Source Audio using
Isochronous channels.
if BT_BAP_BROADCAST_SOURCE
config BT_BAP_BROADCAST_SRC_SUBGROUP_COUNT
int "Basic Audio Broadcast Source subgroup count"
default 1
range 1 BT_ISO_MAX_CHAN if BT_ISO_MAX_CHAN < 31
range 1 31
help
This option sets the maximum number of subgroups per broadcast source
to support.
config BT_BAP_BROADCAST_SRC_COUNT
int "Basic Audio Broadcaster source count"
default 1
range 1 BT_ISO_MAX_BIG
help
This option sets the number of broadcast sources to support.
One broadcast source can send multiple streams
(up to BT_BAP_BROADCAST_SRC_STREAM_COUNT per broadcast source).
config BT_BAP_BROADCAST_SRC_STREAM_COUNT
int "Basic Audio Broadcast Source Stream count"
default 1
range 1 BT_ISO_MAX_CHAN if BT_ISO_MAX_CHAN < 31
range 1 31
help
This option sets the maximum number of streams per broadcast source
to support.
endif # BT_BAP_BROADCAST_SOURCE
config BT_BAP_BROADCAST_SINK
bool "Bluetooth Broadcast Sink Audio Support"
select BT_ISO_SYNC_RECEIVER
select BT_PAC_SNK
depends on BT_BAP_SCAN_DELEGATOR
help
This option enables support for Bluetooth Broadcast Sink Audio using
Isochronous channels.
if BT_BAP_BROADCAST_SINK
config BT_BAP_BROADCAST_SNK_SUBGROUP_COUNT
int "Basic Audio Profile Broadcast Sink subgroup count"
default 1
range 1 BT_BAP_BASS_MAX_SUBGROUPS
help
This option sets the maximum number of subgroups per broadcast sink
to support.
config BT_BAP_BROADCAST_SNK_COUNT
int "Basic Audio Broadcaster Sink count"
default 1
range 0 BT_ISO_MAX_BIG
help
This option sets the number of broadcast sinks to support.
One broadcast sink can receive multiple streams
(up to BT_BAP_BROADCAST_SNK_STREAM_COUNT per broadcast sink).
config BT_BAP_BROADCAST_SNK_STREAM_COUNT
int "Basic Audio Broadcast Sink Stream count"
depends on BT_BAP_BROADCAST_SNK_COUNT > 0
default 1
range 1 BT_ISO_MAX_CHAN if BT_ISO_MAX_CHAN < 31
range 1 31
help
This option sets the maximum number of streams per broadcast sink
to support.
endif # BT_BAP_BROADCAST_SINK
config BT_BAP_SCAN_DELEGATOR
bool "Basic Audio Profile Scan Delegator role support"
select BT_ISO_SYNC_RECEIVER
help
This option enables support for the Scan Delegator role and the
Broadcast Audio Scan Service (BASS).
if BT_BAP_SCAN_DELEGATOR
config BT_BAP_SCAN_DELEGATOR_RECV_STATE_COUNT
int "Scan Delegator Receive State Count"
default 1
range 1 3
help
Sets the number of receive state characteristics present on the
server. Each characteristic may hold information to sync to a
periodic advertise or a broadcast isochronous stream.
config BT_BAP_SCAN_DELEGATOR_BUF_TIMEOUT
int "Milliseconds of timeout when handle concurrent access to the long read ASE buffer"
range 0 1000
default 50
help
The maximum number of milliseconds that the scan delegator implementation will wait
before rejecting a read or dropping a notification if the scan delegator state is
being accessed by another thread.
endif # BT_BAP_SCAN_DELEGATOR
config BT_BAP_BROADCAST_ASSISTANT
bool "Basic Audio Profile Broadcast Assistant role support"
select BT_ISO_SYNC_RECEIVER
select BT_AUDIO
help
This option enables support for the Broadcast Assistant role.
if BT_BAP_BROADCAST_ASSISTANT
config BT_BAP_BROADCAST_ASSISTANT_RECV_STATE_COUNT
int "Broadcast Assistant Max Receive State Count"
default 1
range 1 255
help
Sets the number of maximum receive stat characteristics that will be
discovered and ready to use. Each characteristic may hold information
to sync to a periodic advertise or a broadcast isochronous stream.
endif # BT_BAP_BROADCAST_ASSISTANT
config BT_BAP_DEBUG_STREAM_DATA
bool "Bluetooth Audio Stream data debug"
help
Use this option to enable Bluetooth Audio Stream data debug logs for
the Bluetooth Audio functionality. This will enable debug logs for all
audio data received and sent.
config BT_BAP_STREAM
# Virtual/hidden option
bool
default y if BT_ASCS || BT_BAP_UNICAST_CLIENT || \
BT_BAP_BROADCAST_SOURCE || BT_BAP_BROADCAST_SINK
config BT_BAP_DEBUG_STREAM_SEQ_NUM
bool "Bluetooth Audio Stream sequence number debug"
default y
help
Use this option to enable Bluetooth Audio Stream sequence number debugging logs for
the Bluetooth Audio functionality. This will provide a warning if the application
provides unexpected sequence numbers.
config BT_BAP_BASE
bool
default y if BT_BAP_BROADCAST_SINK || BT_BAP_BROADCAST_ASSISTANT || BT_BAP_SCAN_DELEGATOR
@@ -0,0 +1,58 @@
# Bluetooth Audio - Common Audio Profile (CAP) options
#
# SPDX-FileCopyrightText: 2022 Nordic Semiconductor ASA
#
# SPDX-License-Identifier: Apache-2.0
#
config BT_CAP
bool # hidden
default y if BT_CAP_ACCEPTOR || BT_CAP_INITIATOR
config BT_CAP_ACCEPTOR
bool "Common Audio Profile Acceptor Role Support"
depends on BT_BAP_UNICAST_SERVER || (BT_BAP_BROADCAST_SINK && BT_BAP_SCAN_DELEGATOR)
depends on BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE >= 4
help
Enabling this will enable the CAP Acceptor role. This instantiates the
common audio service (CAS).
config BT_CAP_ACCEPTOR_SET_MEMBER
bool "Common Audio Profile Acceptor Role Set Member support"
depends on BT_CAP_ACCEPTOR
depends on BT_CSIP_SET_MEMBER
help
Enabling this will allow a CAP acceptor to be a set member.
Enabling this will require a manual register of the CAS service.
Enabling will take one of the allocated CSIS instances
(BT_CSIP_SET_MEMBER_MAX_INSTANCE_COUNT).
config BT_CAP_INITIATOR_UNICAST
bool # hidden
default y if BT_CAP_INITIATOR && BT_BAP_UNICAST_CLIENT
config BT_CAP_INITIATOR
bool "Common Audio Profile Initiator Role Support"
depends on (BT_BAP_UNICAST_CLIENT && BT_CSIP_SET_COORDINATOR) || BT_BAP_BROADCAST_SOURCE
depends on BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE >= 4
help
Enabling this will enable the CAP Initiator role.
config BT_CAP_COMMANDER
bool "Common Audio Profile Initiator Role Support"
depends on (BT_BAP_BROADCAST_ASSISTANT && BT_BAP_SCAN_DELEGATOR && BT_CSIP_SET_COORDINATOR) || \
(BT_BAP_SCAN_DELEGATOR && BT_CSIP_SET_COORDINATOR) || \
(BT_VCP_VOL_CTLR && BT_CSIP_SET_COORDINATOR) || \
(BT_MICP_MIC_CTLR && BT_CSIP_SET_COORDINATOR) || \
BT_TBS_CLIENT || \
BT_MCC
help
Enabling this will enable the CAP Initiator role.
config BT_CAP_HANDOVER
bool "Common Audio Profile Handover Procedures"
depends on BT_CAP_COMMANDER && BT_CAP_INITIATOR && BT_BAP_BROADCAST_ASSISTANT && \
BT_BAP_BROADCAST_SOURCE && BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 0
help
Enable support for the CAP Handover procedures, allowing a device to switch between
broadcast and unicast for a usecase.
@@ -0,0 +1,52 @@
# Bluetooth Audio - Call Control Profile (CCP) configuration options
#
# SPDX-FileCopyrightText: 2024 Nordic Semiconductor ASA
#
# SPDX-License-Identifier: Apache-2.0
#
config BT_CCP_CALL_CONTROL_CLIENT
bool "Call Control Profile Client Support"
depends on BT_TBS_CLIENT
help
This option enables support for the Call Control Profile Client which uses the Telephone
Bearer Service (TBS) client to control calls on a remote device.
if BT_CCP_CALL_CONTROL_CLIENT
config BT_CCP_CALL_CONTROL_CLIENT_BEARER_COUNT
int "Telephone bearer count"
default 1
range 1 255 if BT_TBS_CLIENT_TBS
range 1 1
help
The number of supported telephone bearers on the CCP Call Control Client
endif # BT_CCP_CALL_CONTROL_CLIENT
config BT_CCP_CALL_CONTROL_SERVER
bool "Call Control Profile Call Control Server Support"
depends on BT_TBS
help
This option enables support for the Call Control Profile Call Control Server which uses
the Telephone Bearer Service (TBS) to hold and control calls on a device.
if BT_CCP_CALL_CONTROL_SERVER
config BT_CCP_CALL_CONTROL_SERVER_BEARER_COUNT
int "Telephone bearer count"
default 1
range 1 255
help
The number of supported telephone bearers on the CCP Call Control Server
config BT_CCP_CALL_CONTROL_SERVER_PROVIDER_NAME_MAX_LEN
# The original BT_CCP_CALL_CONTROL_SERVER_PROVIDER_NAME_MAX_LENGTH is reported
# as too long while running pre-commit check.
int "The maximum length of the bearer provider name excluding null terminator"
default BT_TBS_MAX_PROVIDER_NAME_LENGTH
range 1 BT_TBS_MAX_PROVIDER_NAME_LENGTH
help
Sets the maximum length of the bearer provider name.
endif # BT_CCP_CALL_CONTROL_SERVER
@@ -0,0 +1,95 @@
# Bluetooth Audio - Broadcast Assistant configuration options
#
# SPDX-FileCopyrightText: 2020 Bose Corporation
# SPDX-FileCopyrightText: 2021 Nordic Semiconductor ASA
#
# SPDX-License-Identifier: Apache-2.0
#
#################### Coordinated Set Identification Service ####################
config BT_CSIP_SET_MEMBER
bool "Coordinated Set Identification Profile Set Member support"
help
This option enables support for Coordinated Set Identification
Profile Set Member role and the Coordinated Set Identification
Service.
if BT_CSIP_SET_MEMBER
config BT_CSIP_SET_MEMBER_TEST_SAMPLE_DATA
bool "Coordinated Set Identification Service Test Sample Data"
help
Enable the use of the sample data defined by the CSIS spec SIRK.
This will use the sample SIRK, prand and LTK.
WARNING: This option enables anyone to track and decrypt the SIRK
(if encrypted) using public sample data.
Should not be used for production builds.
config BT_CSIP_SET_MEMBER_ENC_SIRK_SUPPORT
bool "Support for encrypted SIRK"
default y
help
Enables support encrypting the SIRK.
config BT_CSIP_SET_MEMBER_MAX_INSTANCE_COUNT
int "Coordinated Set Identification Profile max service instance count"
default 1
range 1 255
help
This option sets the maximum number of instances of Coordinated Set
Identification Services. If the service is declared as primary service
then only a single instance is possible.
Enabling BT_CAP_ACCEPTOR_SET_MEMBER will take one of the allocated
instances.
config BT_CSIP_SET_MEMBER_SIRK_NOTIFIABLE
bool "SIRK notifiable Support"
help
This option enables support for clients to be notified on SIRK changes.
config BT_CSIP_SET_MEMBER_SIZE_NOTIFIABLE
bool "Set Size notifiable support"
help
This option enables support for clients to be notified on Set Size changes.
endif # BT_CSIP_SET_MEMBER
#################### Coordinated Set Identification Client ####################
config BT_CSIP_SET_COORDINATOR
bool "Coordinated Set Identification Profile Set Coordinator Support"
help
This option enables support for Coordinated Set Identification
Profile Set Coordinator.
if BT_CSIP_SET_COORDINATOR
config BT_CSIP_SET_COORDINATOR_TEST_SAMPLE_DATA
bool "Coordinated Set Identification Service Test Sample Data"
help
Enable the use of the sample data defined by the CSIS spec.
This will use the sample SIRK, prand and LTK.
WARNING: This option enables the client to use the sample data
to locate members and decrypt the SIRK, and thus won't work
with set members that are not using the sample data.
Should not be used for production builds.
config BT_CSIP_SET_COORDINATOR_MAX_CSIS_INSTANCES
int "Coordinated Set Identification Service Count"
default 1
range 1 3
help
Sets the number of service instances, which corresponds to the number
of different sets the peer device may be in.
config BT_CSIP_SET_COORDINATOR_ENC_SIRK_SUPPORT
bool "Support for encrypted SIRK"
default y
help
Enables support encrypting the SIRK.
endif # BT_CSIP_SET_COORDINATOR
@@ -0,0 +1,28 @@
# Bluetooth Audio - Gaming Audio Profile (GMAP) options
#
# SPDX-FileCopyrightText: 2023 Nordic Semiconductor ASA
#
# SPDX-License-Identifier: Apache-2.0
#
config BT_GMAP_UGG_SUPPORTED
bool # hidden
default y if BT_CAP_INITIATOR && BT_BAP_UNICAST_CLIENT && BT_VCP_VOL_CTLR
config BT_GMAP_UGT_SUPPORTED
bool # hidden
default y if BT_CAP_ACCEPTOR && BT_BAP_UNICAST_SERVER
config BT_GMAP_BGS_SUPPORTED
bool # hidden
default y if BT_CAP_INITIATOR && BT_BAP_BROADCAST_SOURCE && BT_BAP_BROADCAST_ASSISTANT
config BT_GMAP_BGR_SUPPORTED
bool # hidden
default y if BT_CAP_ACCEPTOR && BT_BAP_BROADCAST_SINK && BT_VCP_VOL_REND
config BT_GMAP
bool "Gaming Audio Profile"
depends on BT_CAP_ACCEPTOR || BT_CAP_INITIATOR
help
Enabling this will enable GMAP.
@@ -0,0 +1,59 @@
# Bluetooth Audio - Hearing Access Service options
#
# SPDX-FileCopyrightText: 2022 Codecoup
#
# SPDX-License-Identifier: Apache-2.0
menuconfig BT_HAS
bool "Hearing Access Service support"
depends on BT_BAP_UNICAST_SERVER
help
This option enables support for Hearing Access Service.
if BT_HAS
config BT_HAS_FEATURES_NOTIFIABLE
bool "Hearing Aid Features Notifiable Support"
help
This option enables support for clients to subscribe for notifications
on the Hearing Aid Features characteristic.
config BT_HAS_PRESET_COUNT
int "Preset record list size"
default 2
range 0 255
help
This option sets the number of Hearing Access Service Presets
that can be registered. Setting this value to 0 disables Presets support.
config BT_HAS_PRESET_SUPPORT
bool # hidden
default y if BT_HAS_PRESET_COUNT > 0
if BT_HAS_PRESET_SUPPORT
config BT_HAS_PRESET_NAME_DYNAMIC
bool "Allow to set preset name on runtime"
help
Enabling this option allows for runtime configuration of preset name.
config BT_HAS_PRESET_CONTROL_POINT_NOTIFIABLE
bool "Preset Control Point Notifiable support (depends on EATT)"
help
This option enables support for clients to subscribe for notifications
on the Hearing Aid Preset Control Point characteristic.
config BT_HAS_ACTIVE_PRESET_INDEX
bool # hidden
default y if BT_HAS_PRESET_SUPPORT
help
This option enables the Hearing Aid Active Preset Index characteristic.
endif # BT_HAS_PRESET_SUPPORT
endif # BT_HAS
config BT_HAS_CLIENT
bool "Hearing Access Service Client support"
help
This option enables support for Hearing Access Service Client.
@@ -0,0 +1,218 @@
# Bluetooth Audio - Media control configuration options
#
# SPDX-FileCopyrightText: 2020-2022 Nordic Semiconductor
#
# SPDX-License-Identifier: Apache-2.0
#
#### Media Control Service ################################
config BT_MCS
bool "Media Control Service Support"
depends on BT_MCTL_LOCAL_PLAYER_REMOTE_CONTROL
help
This option enables support for the Media Control Service.
#### Media Control Client ################################
config BT_MCC
bool "Media Control Client Support"
help
This option enables support for the Media Control Client.
if BT_MCC
config BT_MCC_MEDIA_PLAYER_NAME_MAX
int "Max length of media player name"
default 20
range 1 255
help
Sets the maximum number of bytes (including the null termination) of
the name of the media player. If the name is longer, the media
control client will truncate the name when reading it.
config BT_MCC_ICON_URL_MAX
int "Max length of media player icon URL"
default 40
range 1 255
help
Sets the maximum number of bytes (including the null termination) of
the media player icon URL. If the URL is longer, the media control
client will truncate the name when reading it.
config BT_MCC_TRACK_TITLE_MAX
int "Max length of the title of a track"
default 40
range 1 255
help
Sets the maximum number of bytes (including the null termination) of
the title of any track in the media player. If the title is longer,
the media control client will truncate the title when reading it.
config BT_MCC_SEGMENT_NAME_MAX
int "Max length of the name of a track segment"
default 25
range 1 255
help
Sets the maximum number of bytes (including the null termination)
of the name of any track segment in the media player. If the name is
longer, the media control client will truncate the name when reading
it.
config BT_MCC_OTS
bool "Media Control Client support for Object Transfer Service (depends on OTS Client)"
depends on BT_OTS_CLIENT
help
Use this option to configure support in the Media Control Client for
an included Object Transfer Service in the Media Control Service.
if BT_MCC_OTS
config BT_MCC_OTC_OBJ_BUF_SIZE
int "The size of the buffer used for OTC object in MCC"
default 512
range 1 65536
help
Sets the size (in octets) of the buffer used for receiving the content
of objects.
Should be set large enough to fit any expected object.
config BT_MCC_TOTAL_OBJ_CONTENT_MEM
int "Total memory size to use for storing the content of objects"
default 1
range 0 65536
help
Sets the total memory size (in octets) to use for storing the content
of objects.
This is used for the total memory pool buffer size from which memory
is allocated when reading object content.
config BT_MCC_TRACK_SEGS_MAX_CNT
int "Maximum number of tracks segments in a track segment object"
default 25
range 0 500
help
Sets the maximum number of tracks segments in a track segment object.
If the received object is bigger, the remaining data in the object
will be ignored.
config BT_MCC_GROUP_RECORDS_MAX
int "Maximum number of records in a group object"
default 25
range 0 500
help
Sets the maximum number of records in a group object. If the received
group object has more records than this, the remaining records in the
object will be ignored.
endif # BT_MCC_OTS
config BT_MCC_SHELL
bool "Media Control Client Shell Support"
help
This option enables shell support for the Media Control Client.
config BT_MCC_MINIMAL
bool "Minimal Media Control Client without optional procedures"
help
This option disables all optional procedures in the Media Control Client.
config BT_MCC_READ_MEDIA_PLAYER_ICON_URL
bool "Support reading Media Player Icon URL"
default y if !BT_MCC_MINIMAL
help
This option enables support for Read Media Information procedure
optionally read the Media Player Icon URL.
config BT_MCC_READ_TRACK_TITLE
bool "Support reading Track Title"
default y if !BT_MCC_MINIMAL
help
This option enables support for reading Track Title.
config BT_MCC_READ_TRACK_TITLE_ENABLE_SUBSCRIPTION
bool "Support to enable or disable the subscription of Track Title"
default y if !BT_MCC_MINIMAL
help
This option enables support for the subscription of Track Title.
config BT_MCC_READ_TRACK_DURATION
bool "Support reading Track Duration"
default y if !BT_MCC_MINIMAL
help
This option enables support for reading Track Duration.
config BT_MCC_READ_TRACK_POSITION
bool "Support reading Track Position"
default y if !BT_MCC_MINIMAL
help
This option enables support for reading Track Position.
config BT_MCC_SET_TRACK_POSITION
bool "Support setting Track Position"
default y if !BT_MCC_MINIMAL
help
This option enables support for setting Track Position.
config BT_MCC_READ_PLAYBACK_SPEED
bool "Support reading Playback Speed"
default y if !BT_MCC_MINIMAL
help
This option enables support for reading Playback Speed.
config BT_MCC_SET_PLAYBACK_SPEED
bool "Support setting Playback Speed"
default y if !BT_MCC_MINIMAL
help
This option enables support for setting Playback Speed.
config BT_MCC_READ_SEEKING_SPEED
bool "Support reading Seeking Speed"
default y if !BT_MCC_MINIMAL
help
This option enables support for reading Seeking Speed.
config BT_MCC_READ_PLAYING_ORDER
bool "Support reading Playing Order"
default y if !BT_MCC_MINIMAL
help
This option enables support for reading Playing Order.
config BT_MCC_SET_PLAYING_ORDER
bool "Support setting Playing Order"
default y if !BT_MCC_MINIMAL
help
This option enables support for setting Playing Order.
config BT_MCC_READ_PLAYING_ORDER_SUPPORTED
bool "Support reading Playing Order Supported"
default y if !BT_MCC_MINIMAL
help
This option enables support for reading Playing Order Supported.
config BT_MCC_READ_MEDIA_STATE
bool "Support reading Media State"
default y if !BT_MCC_MINIMAL
help
This option enables support for reading Media State.
config BT_MCC_SET_MEDIA_CONTROL_POINT
bool "Support setting Media Control Point"
default y if !BT_MCC_MINIMAL
help
This option enables support for setting Media Control Point.
config BT_MCC_READ_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED
bool "Support reading Media Control Point Opcodes Supported"
default y if !BT_MCC_MINIMAL
help
This option enables support for reading Media Control Point Opcodes Supported.
config BT_MCC_READ_CONTENT_CONTROL_ID
bool "Support reading Content Control ID"
default y if !BT_MCC_MINIMAL
help
This option enables support for reading Content Control ID.
endif # BT_MCC
@@ -0,0 +1,59 @@
# Bluetooth Audio - Media control configuration options
#
# SPDX-FileCopyrightText: 2022 Nordic Semiconductor
#
# SPDX-License-Identifier: Apache-2.0
#
# TODO: Decide, and add, top-level namespace prefix (currently none) to symbols.
# Dependent upon where the module will be placed.
config BT_MCTL
bool "Support for media player control"
help
Enables support for control of local and remote media players
To enable support for control of a local media player, support for
local media player must be enabled
if BT_MCTL
config BT_MCTL_LOCAL_PLAYER_CONTROL
bool "Support for control of local media player"
help
This option enables support for control of a local media player
config BT_MCTL_LOCAL_PLAYER_LOCAL_CONTROL
bool "Support for local control of local media player"
default y
depends on BT_MCTL_LOCAL_PLAYER_CONTROL
help
This option enables support for local application control of local
media players
config BT_MCTL_LOCAL_PLAYER_REMOTE_CONTROL
bool "Support for remote control of local media players"
depends on BT_MCTL_LOCAL_PLAYER_CONTROL
help
This option enables support for remote control of local media
players.
config BT_MCTL_REMOTE_PLAYER_CONTROL
bool "Support for control of remote media player"
default y
# TODO: Remove dependency on BT_MCC once MCC has been reworked
depends on BT_MCC
help
This options enables support for control of a remote media player.
config BT_MCTL_REMOTE_PLAYER_CONTROL_OBJECTS
bool "Support for accessing objects on remote player"
depends on BT_MCTL_REMOTE_PLAYER_CONTROL
default y
# TODO: Remove dependency on BT_MCC_OTS once MCC has been reworked
depends on BT_MCC_OTS
help
This options enables support for accessing objects (tracks, groups,
search results, ...) on a remote media player
endif # BT_MCTL
@@ -0,0 +1,62 @@
# Bluetooth Audio - Microphone Control Service options
#
# SPDX-FileCopyrightText: 2020 Bose Corporation
# SPDX-FileCopyrightText: 2020-2022 Nordic Semiconductor ASA
#
# SPDX-License-Identifier: Apache-2.0
#
########### Microphone Control Profile Microphone Device ###########
config BT_MICP_MIC_DEV
bool "Microphone Control Profile Microphone Device Support"
help
This option enables support for Microphone Control Profile
Microphone Device.
if BT_MICP_MIC_DEV
config BT_MICP_MIC_DEV_AICS_INSTANCE_COUNT
int "Audio Input Control Service instance count for \
Microphone Control Service Microphone Device"
default 0
range 0 BT_AICS_MAX_INSTANCE_COUNT
help
This option sets the number of instances of Audio Input Control
Services for Microphone Control Profile Microphone Device.
config BT_MICP_MIC_DEV_AICS
bool # Hidden
default y if BT_MICP_MIC_DEV_AICS_INSTANCE_COUNT > 0
help
This hidden option makes it possible to easily check if AICS is
enabled for Microphone Control Profile Microphone Device.
endif # BT_MICP_MIC_DEV
########### Microphone Control Profile Microphone Controller ###########
config BT_MICP_MIC_CTLR
bool "Microphone Control Profile Microphone Controller Support"
help
This option enables support for the Microphone Control Profile
Microphone Controller role
if BT_MICP_MIC_CTLR
config BT_MICP_MIC_CTLR_MAX_AICS_INST
int "Maximum number of Audio Input Control Service instances to setup"
default 0
range 0 BT_AICS_CLIENT_MAX_INSTANCE_COUNT
help
Sets the maximum number of Audio Input Control Service (AICS)
instances to setup and use.
config BT_MICP_MIC_CTLR_AICS
bool # Hidden
default y if BT_MICP_MIC_CTLR_MAX_AICS_INST > 0
help
This hidden option makes it possible to easily check if AICS is
enabled for MICP client.
endif # BT_MICP_MIC_CTLR
@@ -0,0 +1,110 @@
# Bluetooth Audio - Media player configuration options
#
# SPDX-FileCopyrightText: 2022 Nordic Semiconductor
#
# SPDX-License-Identifier: Apache-2.0
#
config BT_MPL
bool "Support for media player"
help
Enables support for media player
Note that the provided media player is a sample that only provides a
mock-up with no actual media being played.
For real media playback, the sample must be extended, hooked up to a
real media player or replaced with a real media player.
if BT_MPL
config BT_MPL_MEDIA_PLAYER_NAME
string "Media Player Name"
default "Player0"
help
Use this option to set the name of the media player.
config BT_MPL_MEDIA_PLAYER_NAME_MAX
int "Max length of media player name"
default 20
range 1 255
help
Sets the maximum number of bytes (including the null termination) of
the name of the media player.
config BT_MPL_ICON_URL
string "Media player Icon URL"
default "http://server.some.where/path/icon.png"
help
Use this option to set the URL of the Media Player Icon.
config BT_MPL_ICON_URL_MAX
int "Max length of media player icon URL"
default 40
range 1 255
help
Sets the maximum number of bytes (including the null termination) of
the media player icon URL.
config BT_MPL_TRACK_TITLE_MAX
int "Max length of the title of a track"
default 40
range 1 255
help
Sets the maximum number of bytes (including the null termination) of
the title of any track in the media player.
config BT_MPL_SEGMENT_NAME_MAX
int "Max length of the name of a track segment"
default 25
range 1 255
help
Sets the maximum number of bytes (including the null termination)
of the name of any track segment in the media player.
config BT_MPL_GROUP_TITLE_MAX
int "Max length of the title of a group of tracks"
default BT_MPL_TRACK_TITLE_MAX
range 1 255
help
Sets the maximum number of bytes (including the null termination) of
the title of any group in the media player.
config BT_MPL_OBJECTS
bool "Support for media player objects"
depends on BT_OTS
# TODO: Temporarily depends also on BT_MCS, to avoid issues with the
# bt_mcs_get_ots() call
depends on BT_MCS
# OTS shall be instantiated as a Secondary Service and shall be
# included in MCS or GMCS.
help
Enables support for objects in the media player
Objects are used to give/get more information about e.g. media tracks.
Requires the Object Transfer Service
if BT_MPL_OBJECTS
config BT_MPL_MAX_OBJ_SIZE
int "Total memory size to use for storing the content of objects"
default 127
range 0 65536
help
Sets the total memory size (in octets) to use for storing the content of objects.
This is used for the total memory pool buffer size from which memory
is allocated when sending object content.
config BT_MPL_ICON_BITMAP_SIZE
int "Media player Icon bitmap object size"
default 127
help
This option sets the maximum size (in octets) of the icon object.
config BT_MPL_TRACK_MAX_SIZE
int "Maximum size for a track object"
default 127
help
This option sets the maximum size (in octets) of a track object.
endif # BT_MPL_OBJECTS
endif # BT_MPL
@@ -0,0 +1,87 @@
# Bluetooth Audio - Published Audio Capabilities configuration options
#
# SPDX-FileCopyrightText: 2022 Nordic Semiconductor ASA
# SPDX-License-Identifier: Apache-2.0
#
config BT_PAC_SNK
bool "Sink PAC Characteristic Support"
help
This option enables support for Sink Published Audio Capabilities.
if BT_PAC_SNK
config BT_PAC_SNK_NOTIFIABLE
bool "Sink PAC Notifiable Support"
help
This option enables support for clients to be notified on the Sink
PAC Characteristic changes.
config BT_PAC_SNK_LOC
bool "Sink PAC Location Support"
default y
help
This option enables support for Sink PAC Location Characteristic.
config BT_PAC_SNK_LOC_WRITEABLE
bool "Sink PAC Location Writable Support"
depends on BT_PAC_SNK_LOC
help
This option enables support for clients to write to the Sink PAC
Location Characteristic.
config BT_PAC_SNK_LOC_NOTIFIABLE
bool "Sink Audio Location Notifiable Support"
depends on BT_PAC_SNK_LOC
help
This option enables support for clients to be notified on the Sink
Audio Location Characteristic changes.
endif # BT_PACS_SNK
config BT_PAC_SRC
bool "Source PAC Characteristic Support"
help
This option enables support for Source Published Audio Capabilities.
if BT_PAC_SRC
config BT_PAC_SRC_NOTIFIABLE
bool "Source PAC Notifiable Support"
help
This option enables support for clients to be notified on the Source
PAC Characteristic changes.
config BT_PAC_SRC_LOC
bool "Source PAC Location Support"
default y
help
This option enables support for Source PAC Location Characteristic.
config BT_PAC_SRC_LOC_WRITEABLE
bool "Source PAC Location Writable Support"
depends on BT_PAC_SRC_LOC
help
This option enables support for clients to write to the Source PAC
Location Characteristic.
config BT_PAC_SRC_LOC_NOTIFIABLE
bool "Source Audio Location Notifiable Support"
depends on BT_PAC_SRC_LOC
help
This option enables support for clients to be notified on the Source
Audio Location Characteristic changes.
endif # BT_PAC_SRC
config BT_PACS
bool # hidden
default y if BT_PAC_SNK || BT_PAC_SRC
config BT_PACS_SUPPORTED_CONTEXT_NOTIFIABLE
bool "Supported Audio Context Notifiable Support"
depends on BT_PACS
help
This option enables support for clients to be notified on the
Supported Audio Contexts Characteristic changes.
@@ -0,0 +1,11 @@
# Bluetooth Audio - Public Broadcast Profile (PBP) options
#
# SPDX-FileCopyrightText: 2023 NXP
#
# SPDX-License-Identifier: Apache-2.0
#
config BT_PBP
bool "Public Broadcast Profile"
help
Enabling this will enable PBP.
@@ -0,0 +1,252 @@
# Bluetooth Audio - Call control configuration options
#
# SPDX-FileCopyrightText: 2020 Bose Corporation
# SPDX-FileCopyrightText: 2024 Nordic Semiconductor ASA
#
# SPDX-License-Identifier: Apache-2.0
#
##################### Telephone Bearer Service #####################
config BT_TBS
bool "Telephone Bearer Service Support"
select BT_AUDIO
help
This option enables support for Telephone Bearer Service. By default this only
initializes the GTBS service. If specific TBS services are wanted, they need to be
enabled by setting BT_TBS_BEARER_COUNT to a non-zero value.
if BT_TBS
config BT_TBS_SUPPORTED_FEATURES
int "Telephone Bearer Service Supported Features"
default 1
range 0 3
help
Bitfield to set supported features of the bearer.
Bit 0: Local Hold and Retrieve
Bit 1: Join calls within Telephone Bearer Service
config BT_TBS_MAX_CALLS
int "Telephone Bearer Service Maximum Number Of Calls Supported"
default 3
range 1 16
help
Sets the maximum number of calls the service supports per bearer.
config BT_TBS_BEARER_COUNT
int "How many bearer instances the device instantiates"
default 0
range 0 255
help
Sets the number of TBS instances that are instantiated
config BT_TBS_MAX_SCHEME_LIST_LENGTH
int "The maximum length of the URI scheme list"
default 30
range 0 512
help
Sets the maximum length of the URI scheme list.
endif # BT_TBS
##################### Call Control Client #####################
config BT_TBS_CLIENT_GTBS
bool "Generic Telephone Bearer Service client support"
help
This option enables support for the GTBS-oriented Call Control client.
config BT_TBS_CLIENT_TBS
bool "Telephone Bearer Service client support"
help
This option enables support for the TBS-oriented Call Control client.
config BT_TBS_CLIENT
bool # hidden
default y if BT_TBS_CLIENT_GTBS || BT_TBS_CLIENT_TBS
select BT_AUDIO
if BT_TBS_CLIENT
config BT_TBS_CLIENT_MAX_CALLS
int "Maximum Number Of Calls Supported"
default 1
help
Sets the maximum number of calls the client supports per TBS instance.
config BT_TBS_CLIENT_MAX_TBS_INSTANCES
int "Maximum number of TBS instances to setup"
depends on BT_TBS_CLIENT_TBS
default 1
range 1 3
help
Sets the maximum number of Telephone Bearer Service (TBS)
instances to setup and use.
config BT_TBS_CLIENT_MINIMAL
bool "Minimal TBS Client without optional procedures"
default n
help
This option disables all optional procedures in the TBS Client.
config BT_TBS_CLIENT_BEARER_PROVIDER_NAME
bool "Support reading Bearer Provider Name"
default y if !BT_TBS_CLIENT_MINIMAL
help
This option enables support for reading Bearer Provider Name.
config BT_TBS_CLIENT_BEARER_UCI
bool "Support reading Bearer UCI"
default y if !BT_TBS_CLIENT_MINIMAL
help
This option enables support for reading Bearer UCI.
config BT_TBS_CLIENT_BEARER_TECHNOLOGY
bool "Support reading Bearer Technology"
default y if !BT_TBS_CLIENT_MINIMAL
help
This option enables support for reading Bearer Technology.
config BT_TBS_CLIENT_BEARER_URI_SCHEMES_SUPPORTED_LIST
bool "Support reading Bearer URI Schemes Supported List"
default y if !BT_TBS_CLIENT_MINIMAL
help
This option enables support for reading Bearer URI Schemes Supported
List.
config BT_TBS_CLIENT_BEARER_SIGNAL_STRENGTH
bool "Support reading Bearer Signal Strength"
default y if !BT_TBS_CLIENT_MINIMAL
help
This option enables support for reading Bearer Signal Strength.
config BT_TBS_CLIENT_READ_BEARER_SIGNAL_INTERVAL
bool "Support reading Bearer Signal Strength Reporting Interval"
default y if !BT_TBS_CLIENT_MINIMAL
help
This option enables support for reading Bearer Signal Strength
Reporting Interval.
config BT_TBS_CLIENT_SET_BEARER_SIGNAL_INTERVAL
bool "Support setting Bearer Signal Strength Reporting Interval"
default y if !BT_TBS_CLIENT_MINIMAL
help
This option enables support for setting Bearer Signal Strength
Reporting Interval.
config BT_TBS_CLIENT_BEARER_LIST_CURRENT_CALLS
bool "Support reading Bearer List Current Calls"
default y if !BT_TBS_CLIENT_MINIMAL
help
This option enables support for reading Bearer List Current Calls.
config BT_TBS_CLIENT_CCID
bool "Support reading Content Control ID"
default y if !BT_TBS_CLIENT_MINIMAL
help
This option enables support for reading Content Control ID.
config BT_TBS_CLIENT_INCOMING_URI
bool "Support reading Incoming Call Target Bearer URI"
default y if !BT_TBS_CLIENT_MINIMAL
help
This option enables support for reading Incoming Call Target Bearer
URI.
config BT_TBS_CLIENT_STATUS_FLAGS
bool "Support reading Status Flags"
default y if !BT_TBS_CLIENT_MINIMAL
help
This option enables support for reading Status Flags.
config BT_TBS_CLIENT_CP_PROCEDURES
bool # hidden
default y
depends on (BT_TBS_CLIENT_ACCEPT_CALL || \
BT_TBS_CLIENT_TERMINATE_CALL || \
BT_TBS_CLIENT_HOLD_CALL || \
BT_TBS_CLIENT_RETRIEVE_CALL || \
BT_TBS_CLIENT_ORIGINATE_CALL || \
BT_TBS_CLIENT_JOIN_CALLS)
help
This hidden option indicates that there are at least one control
point procedure available.
When this option is disabled it indicates that the control point can
be optimized away.
config BT_TBS_CLIENT_ACCEPT_CALL
bool "Support Accept Call"
default y if !BT_TBS_CLIENT_MINIMAL
help
This option enables support for answering an incoming call.
config BT_TBS_CLIENT_TERMINATE_CALL
bool "Support Terminate Call"
default y if !BT_TBS_CLIENT_MINIMAL
help
This option enables support for terminating a call.
config BT_TBS_CLIENT_HOLD_CALL
bool "Support Hold Call"
default y if !BT_TBS_CLIENT_MINIMAL
help
This option enables support for putting a call on hold.
config BT_TBS_CLIENT_RETRIEVE_CALL
bool "Support Retrieve Call"
default y if !BT_TBS_CLIENT_MINIMAL
help
This option enables support for retrieving a call on hold.
config BT_TBS_CLIENT_ORIGINATE_CALL
bool "Support Originate Call"
default y if !BT_TBS_CLIENT_MINIMAL
help
This option enables support for originating a call.
config BT_TBS_CLIENT_JOIN_CALLS
bool "Support Join Calls"
depends on BT_TBS_CLIENT_MAX_CALLS > 1
default y if !BT_TBS_CLIENT_MINIMAL
help
This option enables support for joining calls.
config BT_TBS_CLIENT_OPTIONAL_OPCODES
bool "Support reading Optional Opcodes"
default y if !BT_TBS_CLIENT_MINIMAL
help
This option enables support for reading Optional Opcodes.
config BT_TBS_CLIENT_INCOMING_CALL
bool "Support reading Incoming Call"
default y if !BT_TBS_CLIENT_MINIMAL
help
This option enables support for reading Incoming Call.
config BT_TBS_CLIENT_CALL_FRIENDLY_NAME
bool "Support reading Call Friendly Name"
default y if !BT_TBS_CLIENT_MINIMAL
help
This option enables support for reading Call Friendly Name.
endif # BT_TBS_CLIENT
if BT_TBS || BT_TBS_CLIENT
config BT_TBS_MAX_URI_LENGTH
int "The maximum length of the call URI supported"
default 30
range 4 253
help
Sets the maximum length of the call URI supported. Note that if this
value is lower than a call URI, the call request will be rejected.
config BT_TBS_MAX_PROVIDER_NAME_LENGTH
int "The maximum length of the bearer provider name"
default 30
range 1 512
help
Sets the maximum length of the bearer provider name.
endif # BT_TBS || BT_TBS_CLIENT
@@ -0,0 +1,38 @@
# Bluetooth Audio - Telephony and Media Audio Profile (TMAP) options
#
# SPDX-FileCopyrightText: 2023 NXP
#
# SPDX-License-Identifier: Apache-2.0
#
config BT_TMAP_CG_SUPPORTED
bool # hidden
default y if (BT_CAP_INITIATOR && BT_CAP_COMMANDER && BT_BAP_UNICAST_CLIENT && \
BT_BAP_UNICAST_CLIENT_ASE_SRC > 0 && BT_BAP_UNICAST_CLIENT_ASE_SNK > 0 && \
BT_VCP_VOL_CTLR && BT_TBS)
config BT_TMAP_CT_SUPPORTED
bool # hidden
default y if BT_CAP_ACCEPTOR && (BT_ASCS_ASE_SNK > 0 || BT_ASCS_ASE_SRC > 0)
config BT_TMAP_UMS_SUPPORTED
bool # hidden
default y if (BT_CAP_INITIATOR && BT_CAP_COMMANDER && BT_BAP_UNICAST_CLIENT && \
BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 0 && BT_VCP_VOL_CTLR && BT_MCS)
config BT_TMAP_UMR_SUPPORTED
bool # hidden
default y if BT_CAP_ACCEPTOR && BT_ASCS_ASE_SNK > 0 && BT_VCP_VOL_REND
config BT_TMAP_BMS_SUPPORTED
bool # hidden
default y if BT_CAP_INITIATOR && BT_BAP_BROADCAST_SOURCE
config BT_TMAP_BMR_SUPPORTED
bool # hidden
default y if BT_CAP_ACCEPTOR && BT_BAP_BROADCAST_SINK && BT_VCP_VOL_REND
config BT_TMAP
bool "Telephony and Media Audio Profile"
depends on BT_CAP_ACCEPTOR || BT_CAP_INITIATOR
help
Enabling this will enable TMAP.
@@ -0,0 +1,97 @@
# Bluetooth Audio - Volume Control Profile configuration options
#
# SPDX-FileCopyrightText: 2020 Bose Corporation
# SPDX-FileCopyrightText: 2020-2022 Nordic Semiconductor ASA
#
# SPDX-License-Identifier: Apache-2.0
#
################### Volume Control Profile Volume Renderer ###################
config BT_VCP_VOL_REND
bool "Volume Control Profile Volume Renderer Support"
help
This option enables support for Volume Control Profile Volume Renderer
role and the Volume Control Service.
if BT_VCP_VOL_REND
config BT_VCP_VOL_REND_VOCS_INSTANCE_COUNT
int "Volume Offset Control Service instance count"
default 0
range 0 BT_VOCS_MAX_INSTANCE_COUNT
help
This option sets the number of instances of Volume Offset Control
Services.
config BT_VCP_VOL_REND_VOCS
bool # Hidden
default y if BT_VCP_VOL_REND_VOCS_INSTANCE_COUNT > 0
help
This hidden option makes it possible to easily check if VOCS is
enabled for VCS.
config BT_VCP_VOL_REND_AICS_INSTANCE_COUNT
int "Audio Input Control Service instance count for VCS"
default 0
range 0 BT_AICS_MAX_INSTANCE_COUNT
help
This option sets the number of instances of Audio Input Control
Services for VCS.
config BT_VCP_VOL_REND_AICS
bool # Hidden
default y if BT_VCP_VOL_REND_AICS_INSTANCE_COUNT > 0
help
This hidden option makes it possible to easily check if AICS is
enabled for VCS.
config BT_VCP_VOL_REND_VOL_FLAGS_NOTIFIABLE
bool "Volume Flags notifiable support"
help
This option enables support for clients to subscribe for notifications
on the Volume Flags characteristic.
endif # BT_VCP_VOL_REND
################### Volume Control Profile Volume Controller ###################
config BT_VCP_VOL_CTLR
bool "Volume Control Profile Volume Controller Support"
help
This option enables support for Volume Control Profile Volume
Controller.
if BT_VCP_VOL_CTLR
config BT_VCP_VOL_CTLR_MAX_VOCS_INST
int "Maximum number of VOCS instances to setup"
default 0
range 0 BT_VOCS_CLIENT_MAX_INSTANCE_COUNT
help
Sets the maximum number of Volume Offset Control Service (VOCS)
instances to setup and use.
config BT_VCP_VOL_CTLR_VOCS
bool # Hidden
default y if BT_VCP_VOL_CTLR_MAX_VOCS_INST > 0
help
This hidden option makes it possible to easily check if VOCS is
enabled for VCS client.
config BT_VCP_VOL_CTLR_MAX_AICS_INST
int "Maximum number of AICS instances to setup"
default 0
range 0 3
help
Sets the maximum number of Audio Input Control Service (AICS)
instances to setup and use.
config BT_VCP_VOL_CTLR_AICS
bool # Hidden
default y if BT_VCP_VOL_CTLR_MAX_AICS_INST > 0
help
This hidden option makes it possible to easily check if AICS is
enabled for VCS client.
endif # BT_VCP_VOL_CTLR
@@ -0,0 +1,49 @@
# Bluetooth Audio - Volume Offset Control Service options
#
# SPDX-FileCopyrightText: 2020 Bose Corporation
#
# SPDX-License-Identifier: Apache-2.0
#
##################### Volume Offset Control Service #####################
config BT_VOCS_MAX_INSTANCE_COUNT
int "Volume Offset Control Service max instance count"
default 0
range 0 15
help
This option sets the maximum number of instances of Volume Offset
Control Services.
config BT_VOCS
bool # hidden
default y if BT_VOCS_MAX_INSTANCE_COUNT > 0
help
This hidden option enables support for Volume Control Service.
if BT_VOCS
config BT_VOCS_MAX_OUTPUT_DESCRIPTION_SIZE
int "Volume Offset Control Service max output description size"
default 32
range 0 512
help
This option sets the maximum output description size in octets.
endif # BT_VOCS
##################### Volume Offset Control Service Client #####################
config BT_VOCS_CLIENT_MAX_INSTANCE_COUNT
int "Volume Offset Control Service client max instance count"
default 0
range 0 15
help
This option sets the maximum number of instances of Volume Offset
Control Service clients.
config BT_VOCS_CLIENT
bool # hidden
default y if BT_VOCS_CLIENT_MAX_INSTANCE_COUNT > 0
help
This hidden option enables support for Volume Offset Control Service.
@@ -0,0 +1,359 @@
/*
* SPDX-FileCopyrightText: 2020-2024 Nordic Semiconductor ASA
* SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "esp_ble_audio_aics_api.h"
#if CONFIG_BT_AICS
esp_ble_audio_aics_t *esp_ble_audio_aics_free_instance_get(void)
{
return bt_aics_free_instance_get_safe();
}
void *esp_ble_audio_aics_svc_decl_get(esp_ble_audio_aics_t *aics)
{
if (aics == NULL) {
return NULL;
}
return bt_aics_svc_decl_get_safe(aics);
}
esp_err_t esp_ble_audio_aics_register(esp_ble_audio_aics_t *aics,
esp_ble_audio_aics_register_param_t *param)
{
int err;
if (aics == NULL || param == NULL) {
return ESP_ERR_INVALID_ARG;
}
if (param->mute > ESP_BLE_AUDIO_AICS_STATE_MUTE_DISABLED ||
param->gain_mode > ESP_BLE_AUDIO_AICS_MODE_AUTO ||
param->type > ESP_BLE_AUDIO_AICS_INPUT_TYPE_AMBIENT ||
param->units == 0 ||
param->min_gain > param->max_gain ||
param->gain < param->min_gain ||
param->gain > param->max_gain) {
return ESP_ERR_INVALID_ARG;
}
err = bt_aics_register_safe(aics, param);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_aics_activate(esp_ble_audio_aics_t *inst)
{
int err;
if (inst == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_aics_activate_safe(inst);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_aics_deactivate(esp_ble_audio_aics_t *inst)
{
int err;
if (inst == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_aics_deactivate_safe(inst);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
#endif /* CONFIG_BT_AICS */
#if CONFIG_BT_AICS || CONFIG_BT_AICS_CLIENT
esp_err_t esp_ble_audio_aics_state_get(esp_ble_audio_aics_t *inst)
{
int err;
if (inst == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_aics_state_get_safe(inst);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_aics_gain_setting_get(esp_ble_audio_aics_t *inst)
{
int err;
if (inst == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_aics_gain_setting_get_safe(inst);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_aics_type_get(esp_ble_audio_aics_t *inst)
{
int err;
if (inst == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_aics_type_get_safe(inst);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_aics_status_get(esp_ble_audio_aics_t *inst)
{
int err;
if (inst == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_aics_status_get_safe(inst);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_aics_disable_mute(esp_ble_audio_aics_t *inst)
{
int err;
if (inst == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_aics_disable_mute_safe(inst);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_aics_unmute(esp_ble_audio_aics_t *inst)
{
int err;
if (inst == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_aics_unmute_safe(inst);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_aics_mute(esp_ble_audio_aics_t *inst)
{
int err;
if (inst == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_aics_mute_safe(inst);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_aics_gain_set_manual_only(esp_ble_audio_aics_t *inst)
{
int err;
if (inst == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_aics_gain_set_manual_only_safe(inst);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_aics_gain_set_auto_only(esp_ble_audio_aics_t *inst)
{
int err;
if (inst == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_aics_gain_set_auto_only_safe(inst);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_aics_manual_gain_set(esp_ble_audio_aics_t *inst)
{
int err;
if (inst == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_aics_manual_gain_set_safe(inst);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_aics_automatic_gain_set(esp_ble_audio_aics_t *inst)
{
int err;
if (inst == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_aics_automatic_gain_set_safe(inst);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_aics_gain_set(esp_ble_audio_aics_t *inst, int8_t gain)
{
int err;
if (inst == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_aics_gain_set_safe(inst, gain);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_aics_description_get(esp_ble_audio_aics_t *inst)
{
int err;
if (inst == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_aics_description_get_safe(inst);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_aics_description_set(esp_ble_audio_aics_t *inst,
const char *description)
{
int err;
if (inst == NULL || description == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_aics_description_set_safe(inst, description);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
#endif /* CONFIG_BT_AICS || CONFIG_BT_AICS_CLIENT */
#if CONFIG_BT_AICS_CLIENT
esp_err_t esp_ble_audio_aics_discover(uint16_t conn_handle, esp_ble_audio_aics_t *inst,
const esp_ble_audio_aics_discover_param_t *param)
{
esp_err_t ret = ESP_OK;
void *conn;
int err;
if (inst == NULL || param == NULL ||
param->end_handle <= param->start_handle) {
return ESP_ERR_INVALID_ARG;
}
bt_le_host_lock();
conn = bt_le_acl_conn_find(conn_handle);
if (conn == NULL) {
ret = ESP_ERR_NOT_FOUND;
goto unlock;
}
err = bt_aics_discover(conn, inst, param);
if (err) {
ret = ESP_FAIL;
}
unlock:
bt_le_host_unlock();
return ret;
}
esp_ble_audio_aics_t *esp_ble_audio_aics_client_free_instance_get(void)
{
return bt_aics_client_free_instance_get_safe();
}
esp_err_t esp_ble_audio_aics_client_cb_register(esp_ble_audio_aics_t *inst,
esp_ble_audio_aics_cb_t *cb)
{
if (inst == NULL) {
return ESP_ERR_INVALID_ARG;
}
bt_aics_client_cb_register_safe(inst, cb);
return ESP_OK;
}
#endif /* CONFIG_BT_AICS_CLIENT */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,722 @@
/*
* SPDX-FileCopyrightText: 2022-2024 Nordic Semiconductor ASA
* SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "esp_ble_audio_cap_api.h"
#if CONFIG_BT_CAP_ACCEPTOR_SET_MEMBER
esp_err_t esp_ble_audio_cap_acceptor_register(const esp_ble_audio_csip_set_member_register_param_t *param,
esp_ble_audio_csip_set_member_svc_inst_t **svc_inst)
{
int err;
if (param == NULL || svc_inst == NULL) {
return ESP_ERR_INVALID_ARG;
}
if (param->lockable && param->rank == 0) {
/* Rank cannot be 0 if service is lockable */
return ESP_ERR_INVALID_ARG;
}
if (param->rank > param->set_size) {
/* Invalid rank (shall be less than or equal to set_size */
return ESP_ERR_INVALID_ARG;
}
#if CONFIG_BT_CSIP_SET_MEMBER_MAX_INSTANCE_COUNT > 1
if (param->parent == NULL) {
/* Parent service not provided */
return ESP_ERR_INVALID_ARG;
}
#endif /* CONFIG_BT_CSIP_SET_MEMBER_MAX_INSTANCE_COUNT > 1 */
err = bt_cap_acceptor_register_safe(param, svc_inst);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
#endif /* CONFIG_BT_CAP_ACCEPTOR_SET_MEMBER */
#if CONFIG_BT_CAP
esp_err_t esp_ble_audio_cap_stream_ops_register(esp_ble_audio_cap_stream_t *stream,
esp_ble_audio_bap_stream_ops_t *ops)
{
if (stream == NULL || ops == NULL) {
return ESP_ERR_INVALID_ARG;
}
bt_cap_stream_ops_register_safe(stream, ops);
return ESP_OK;
}
#if CONFIG_BT_AUDIO_TX
esp_err_t esp_ble_audio_cap_stream_send(esp_ble_audio_cap_stream_t *stream,
const uint8_t *sdu, uint16_t sdu_len,
uint16_t seq_num)
{
struct net_buf buf = {
/* Note: only data and len are used */
.data = (void *)sdu,
.len = sdu_len,
};
int err;
if (stream == NULL || (!sdu ^ !sdu_len)) {
return ESP_ERR_INVALID_ARG;
}
err = bt_cap_stream_send_safe(stream, &buf, seq_num);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_cap_stream_send_ts(esp_ble_audio_cap_stream_t *stream,
const uint8_t *sdu, uint16_t sdu_len,
uint16_t seq_num, uint32_t ts)
{
struct net_buf buf = {
/* Note: only data and len are used */
.data = (void *)sdu,
.len = sdu_len,
};
int err;
if (stream == NULL || (!sdu ^ !sdu_len)) {
return ESP_ERR_INVALID_ARG;
}
err = bt_cap_stream_send_ts_safe(stream, &buf, seq_num, ts);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_cap_stream_get_tx_sync(esp_ble_audio_cap_stream_t *stream,
esp_ble_iso_tx_info_t *info)
{
int err;
if (stream == NULL || info == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_cap_stream_get_tx_sync_safe(stream, info);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
#endif /* CONFIG_BT_AUDIO_TX */
#endif /* CONFIG_BT_CAP */
#if CONFIG_BT_BAP_UNICAST_CLIENT
esp_err_t esp_ble_audio_cap_unicast_group_create(const esp_ble_audio_cap_unicast_group_param_t *param,
esp_ble_audio_cap_unicast_group_t **unicast_group)
{
int err;
if (param == NULL || unicast_group == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_cap_unicast_group_create_safe(param, unicast_group);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_cap_unicast_group_reconfig(esp_ble_audio_cap_unicast_group_t *unicast_group,
const esp_ble_audio_cap_unicast_group_param_t *param)
{
int err;
if (unicast_group == NULL || param == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_cap_unicast_group_reconfig_safe(unicast_group, param);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_cap_unicast_group_add_streams(esp_ble_audio_cap_unicast_group_t *unicast_group,
const esp_ble_audio_cap_unicast_group_stream_pair_param_t params[],
size_t num_param)
{
int err;
if (unicast_group == NULL || params == NULL || num_param == 0) {
return ESP_ERR_INVALID_ARG;
}
err = bt_cap_unicast_group_add_streams_safe(unicast_group, params, num_param);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_cap_unicast_group_delete(esp_ble_audio_cap_unicast_group_t *unicast_group)
{
int err;
if (unicast_group == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_cap_unicast_group_delete_safe(unicast_group);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
#endif /* CONFIG_BT_BAP_UNICAST_CLIENT */
#if CONFIG_BT_CAP_INITIATOR
esp_err_t esp_ble_audio_cap_initiator_register_cb(const esp_ble_audio_cap_initiator_cb_t *cb)
{
int err;
if (cb == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_cap_initiator_register_cb_safe(cb);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_cap_initiator_unregister_cb(const esp_ble_audio_cap_initiator_cb_t *cb)
{
int err;
if (cb == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_cap_initiator_unregister_cb_safe(cb);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
#if CONFIG_BT_BAP_UNICAST_CLIENT
esp_err_t esp_ble_audio_cap_initiator_unicast_discover(uint16_t conn_handle)
{
esp_err_t ret = ESP_OK;
void *conn;
int err;
bt_le_host_lock();
conn = bt_le_acl_conn_find(conn_handle);
if (conn == NULL) {
ret = ESP_ERR_NOT_FOUND;
goto unlock;
}
err = bt_cap_initiator_unicast_discover(conn);
if (err) {
ret = ESP_FAIL;
}
unlock:
bt_le_host_unlock();
return ret;
}
esp_err_t esp_ble_audio_cap_initiator_unicast_audio_start(const esp_ble_audio_cap_unicast_audio_start_param_t *param)
{
int err;
if (param == NULL || param->count == 0 || param->stream_params == NULL ||
param->count > CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT) {
return ESP_ERR_INVALID_ARG;
}
err = bt_cap_initiator_unicast_audio_start_safe(param);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_cap_initiator_unicast_audio_update(const esp_ble_audio_cap_unicast_audio_update_param_t *param)
{
int err;
if (param == NULL || param->count == 0 || param->stream_params == NULL ||
param->count > CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT) {
return ESP_ERR_INVALID_ARG;
}
err = bt_cap_initiator_unicast_audio_update_safe(param);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_cap_initiator_unicast_audio_stop(const esp_ble_audio_cap_unicast_audio_stop_param_t *param)
{
int err;
if (param == NULL || param->count == 0 || param->streams == NULL ||
param->count > CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT) {
return ESP_ERR_INVALID_ARG;
}
err = bt_cap_initiator_unicast_audio_stop_safe(param);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_cap_initiator_unicast_audio_cancel(void)
{
int err;
err = bt_cap_initiator_unicast_audio_cancel_safe();
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
#endif /* CONFIG_BT_BAP_UNICAST_CLIENT */
#if CONFIG_BT_BAP_BROADCAST_SOURCE
esp_err_t esp_ble_audio_cap_initiator_broadcast_audio_create(const esp_ble_audio_cap_initiator_broadcast_create_param_t *param,
esp_ble_audio_cap_broadcast_source_t **broadcast_source)
{
int err;
if (param == NULL || broadcast_source == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_cap_initiator_broadcast_audio_create_safe(param, broadcast_source);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_cap_initiator_broadcast_audio_start(esp_ble_audio_cap_broadcast_source_t *broadcast_source,
uint8_t adv_handle)
{
esp_err_t ret = ESP_OK;
void *adv;
int err;
if (broadcast_source == NULL) {
return ESP_ERR_INVALID_ARG;
}
bt_le_host_lock();
adv = bt_le_ext_adv_find(adv_handle);
if (adv == NULL) {
ret = ESP_ERR_NOT_FOUND;
goto unlock;
}
err = bt_cap_initiator_broadcast_audio_start(broadcast_source, adv);
if (err) {
ret = ESP_FAIL;
}
unlock:
bt_le_host_unlock();
return ret;
}
esp_err_t esp_ble_audio_cap_initiator_broadcast_audio_update(esp_ble_audio_cap_broadcast_source_t *broadcast_source,
const uint8_t meta[], size_t meta_len)
{
int err;
if (broadcast_source == NULL || meta == NULL || meta_len == 0) {
return ESP_ERR_INVALID_ARG;
}
err = bt_cap_initiator_broadcast_audio_update_safe(broadcast_source, meta, meta_len);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_cap_initiator_broadcast_audio_stop(esp_ble_audio_cap_broadcast_source_t *broadcast_source)
{
int err;
if (broadcast_source == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_cap_initiator_broadcast_audio_stop_safe(broadcast_source);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_cap_initiator_broadcast_audio_delete(esp_ble_audio_cap_broadcast_source_t *broadcast_source)
{
int err;
if (broadcast_source == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_cap_initiator_broadcast_audio_delete_safe(broadcast_source);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_cap_initiator_broadcast_get_base(esp_ble_audio_cap_broadcast_source_t *broadcast_source,
struct net_buf_simple *base_buf)
{
int err;
if (broadcast_source == NULL || base_buf == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_cap_initiator_broadcast_get_base_safe(broadcast_source, base_buf);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
#endif /* CONFIG_BT_BAP_BROADCAST_SOURCE */
#endif /* CONFIG_BT_CAP_INITIATOR */
#if CONFIG_BT_CAP_HANDOVER
esp_err_t esp_ble_audio_cap_handover_register_cb(const esp_ble_audio_cap_handover_cb_t *cb)
{
int err;
if (cb == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_cap_handover_register_cb_safe(cb);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_cap_handover_unregister_cb(const esp_ble_audio_cap_handover_cb_t *cb)
{
int err;
if (cb == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_cap_handover_unregister_cb_safe(cb);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_cap_handover_unicast_to_broadcast(
const esp_ble_audio_cap_handover_unicast_to_broadcast_param_t *param)
{
int err;
if (param == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_cap_handover_unicast_to_broadcast_safe(param);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_cap_handover_broadcast_to_unicast(
const esp_ble_audio_cap_handover_broadcast_to_unicast_param_t *param)
{
int err;
if (param == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_cap_handover_broadcast_to_unicast_safe(param);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
#endif /* CONFIG_BT_CAP_HANDOVER */
#if CONFIG_BT_CAP_COMMANDER
esp_err_t esp_ble_audio_cap_commander_register_cb(const esp_ble_audio_cap_commander_cb_t *cb)
{
int err;
if (cb == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_cap_commander_register_cb_safe(cb);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_cap_commander_unregister_cb(const esp_ble_audio_cap_commander_cb_t *cb)
{
int err;
if (cb == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_cap_commander_unregister_cb_safe(cb);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_cap_commander_discover(uint16_t conn_handle)
{
esp_err_t ret = ESP_OK;
void *conn;
int err;
bt_le_host_lock();
conn = bt_le_acl_conn_find(conn_handle);
if (conn == NULL) {
ret = ESP_ERR_NOT_FOUND;
goto unlock;
}
err = bt_cap_commander_discover(conn);
if (err) {
ret = ESP_FAIL;
}
unlock:
bt_le_host_unlock();
return ret;
}
esp_err_t esp_ble_audio_cap_commander_cancel(void)
{
int err;
err = bt_cap_commander_cancel_safe();
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
#if CONFIG_BT_BAP_BROADCAST_ASSISTANT
esp_err_t esp_ble_audio_cap_commander_broadcast_reception_start(
const esp_ble_audio_cap_commander_broadcast_reception_start_param_t *param)
{
int err;
if (param == NULL || param->count == 0 ||
param->count > CONFIG_BT_MAX_CONN || param->param == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_cap_commander_broadcast_reception_start_safe(param);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_cap_commander_broadcast_reception_stop(
const esp_ble_audio_cap_commander_broadcast_reception_stop_param_t *param)
{
int err;
if (param == NULL || param->count == 0 ||
param->count > CONFIG_BT_MAX_CONN || param->param == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_cap_commander_broadcast_reception_stop_safe(param);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_cap_commander_distribute_broadcast_code(
const esp_ble_audio_cap_commander_distribute_broadcast_code_param_t *param)
{
int err;
if (param == NULL || param->count == 0 ||
param->count > CONFIG_BT_MAX_CONN || param->param == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_cap_commander_distribute_broadcast_code_safe(param);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
#endif /* CONFIG_BT_BAP_BROADCAST_ASSISTANT */
#if CONFIG_BT_VCP_VOL_CTLR
esp_err_t esp_ble_audio_cap_commander_change_volume(
const esp_ble_audio_cap_commander_change_volume_param_t *param)
{
int err;
if (param == NULL || param->count == 0 ||
param->count > CONFIG_BT_MAX_CONN || param->members == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_cap_commander_change_volume_safe(param);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
#if CONFIG_BT_VCP_VOL_CTLR_VOCS
esp_err_t esp_ble_audio_cap_commander_change_volume_offset(
const esp_ble_audio_cap_commander_change_volume_offset_param_t *param)
{
int err;
if (param == NULL || param->count == 0 ||
param->count > CONFIG_BT_MAX_CONN || param->param == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_cap_commander_change_volume_offset_safe(param);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
#endif /* CONFIG_BT_VCP_VOL_CTLR_VOCS */
esp_err_t esp_ble_audio_cap_commander_change_volume_mute_state(
const esp_ble_audio_cap_commander_change_volume_mute_state_param_t *param)
{
int err;
if (param == NULL || param->count == 0 ||
param->count > CONFIG_BT_MAX_CONN || param->members == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_cap_commander_change_volume_mute_state_safe(param);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
#endif /* CONFIG_BT_VCP_VOL_CTLR */
#if CONFIG_BT_MICP_MIC_CTLR
esp_err_t esp_ble_audio_cap_commander_change_microphone_mute_state(
const esp_ble_audio_cap_commander_change_microphone_mute_state_param_t *param)
{
int err;
if (param == NULL || param->count == 0 ||
param->count > CONFIG_BT_MAX_CONN || param->members == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_cap_commander_change_microphone_mute_state_safe(param);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
#if CONFIG_BT_MICP_MIC_CTLR_AICS
esp_err_t esp_ble_audio_cap_commander_change_microphone_gain_setting(
const esp_ble_audio_cap_commander_change_microphone_gain_setting_param_t *param)
{
int err;
if (param == NULL || param->count == 0 ||
param->count > CONFIG_BT_MAX_CONN || param->param == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_cap_commander_change_microphone_gain_setting_safe(param);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
#endif /* CONFIG_BT_MICP_MIC_CTLR_AICS */
#endif /* CONFIG_BT_MICP_MIC_CTLR */
#endif /* CONFIG_BT_CAP_COMMANDER */
@@ -0,0 +1,181 @@
/*
* SPDX-FileCopyrightText: 2024 Nordic Semiconductor ASA
* SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "esp_ble_audio_ccp_api.h"
#if CONFIG_BT_CCP_CALL_CONTROL_SERVER
esp_err_t esp_ble_audio_ccp_call_control_server_register_bearer(
const esp_ble_audio_tbs_register_param_t *param,
esp_ble_audio_ccp_call_control_server_bearer_t **bearer)
{
esp_err_t err;
if (param == NULL || bearer == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_ccp_call_control_server_register_bearer_safe(param, bearer);
if (err) {
/* Map Zephyr error codes to ESP-IDF error codes */
switch (err) {
case -EINVAL:
return ESP_ERR_INVALID_ARG;
case -ENOMEM:
return ESP_ERR_NO_MEM;
case -EALREADY:
return ESP_ERR_INVALID_STATE;
case -EAGAIN:
return ESP_ERR_INVALID_STATE;
default:
return ESP_FAIL;
}
}
return ESP_OK;
}
esp_err_t esp_ble_audio_ccp_call_control_server_unregister_bearer(
esp_ble_audio_ccp_call_control_server_bearer_t *bearer)
{
esp_err_t err;
if (bearer == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_ccp_call_control_server_unregister_bearer_safe(bearer);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_ccp_call_control_server_set_bearer_provider_name(
esp_ble_audio_ccp_call_control_server_bearer_t *bearer, const char *name)
{
esp_err_t err;
if (bearer == NULL || name == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_ccp_call_control_server_set_bearer_provider_name_safe(bearer, name);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
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_err_t err;
if (bearer == NULL || name == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_ccp_call_control_server_get_bearer_provider_name_safe(bearer, name);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
#endif /* CONFIG_BT_CCP_CALL_CONTROL_SERVER */
#if CONFIG_BT_CCP_CALL_CONTROL_CLIENT
esp_err_t esp_ble_audio_ccp_call_control_client_discover(
esp_ble_conn_t *conn, esp_ble_audio_ccp_call_control_client_t **out_client)
{
esp_err_t err;
if (conn == NULL || out_client == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_ccp_call_control_client_discover_safe(conn, out_client);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_ccp_call_control_client_register_cb(
esp_ble_audio_ccp_call_control_client_cb_t *cb)
{
esp_err_t err;
if (cb == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_ccp_call_control_client_register_cb_safe(cb);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_ccp_call_control_client_unregister_cb(
esp_ble_audio_ccp_call_control_client_cb_t *cb)
{
esp_err_t err;
if (cb == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_ccp_call_control_client_unregister_cb_safe(cb);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_ccp_call_control_client_get_bearers(
esp_ble_audio_ccp_call_control_client_t *client,
esp_ble_audio_ccp_call_control_client_bearers_t *bearers)
{
esp_err_t err;
if (client == NULL || bearers == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_ccp_call_control_client_get_bearers_safe(client, bearers);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
#endif /* CONFIG_BT_CCP_CALL_CONTROL_CLIENT */
#if CONFIG_BT_TBS_CLIENT_BEARER_PROVIDER_NAME
esp_err_t esp_ble_audio_ccp_call_control_client_read_bearer_provider_name(
esp_ble_audio_ccp_call_control_client_bearer_t *bearer)
{
esp_err_t err;
if (bearer == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_ccp_call_control_client_read_bearer_provider_name_safe(bearer);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
#endif /* CONFIG_BT_TBS_CLIENT_BEARER_PROVIDER_NAME */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,153 @@
/*
* SPDX-FileCopyrightText: 2020 Intel Corporation
* SPDX-FileCopyrightText: 2020-2024 Nordic Semiconductor ASA
* SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#include "esp_ble_audio_common_api.h"
esp_err_t esp_ble_audio_data_parse(const uint8_t ltv[], size_t size,
bool (*func)(uint8_t type,
const uint8_t *data,
uint8_t data_len,
void *user_data),
void *user_data)
{
return esp_ble_iso_data_parse(ltv, size, func, user_data);
}
esp_err_t esp_ble_audio_data_get_val(const uint8_t ltv_data[],
size_t size, uint8_t type,
const uint8_t **data,
uint8_t *data_len)
{
int ret;
if (ltv_data == NULL || data == NULL || data_len == NULL) {
return ESP_ERR_INVALID_ARG;
}
ret = bt_audio_data_get_val(ltv_data, size, type, data);
if (ret < 0) {
return ESP_FAIL;
}
*data_len = ret;
return ESP_OK;
}
uint8_t esp_ble_audio_get_chan_count(esp_ble_audio_location_t chan_allocation)
{
return bt_audio_get_chan_count(chan_allocation);
}
esp_err_t esp_ble_audio_gattc_disc_start(uint16_t conn_handle)
{
int err;
err = bt_gattc_disc_start_safe(conn_handle);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
void esp_ble_audio_gap_app_post_event(uint8_t type, void *param)
{
bt_le_gap_app_post_event(type, param);
}
void esp_ble_audio_gatt_app_post_event(uint8_t type, void *param)
{
bt_le_gatt_app_post_event(type, param);
}
esp_err_t esp_ble_audio_common_init(esp_ble_audio_init_info_t *info)
{
bool gap_cb_registered = false;
bool gatt_cb_registered = false;
int err;
if (info) {
if (info->gap_cb) {
err = bt_le_gap_app_cb_register(info->gap_cb);
if (err) {
return ESP_FAIL;
}
gap_cb_registered = true;
}
if (info->gatt_cb) {
err = bt_le_gatt_app_cb_register(info->gatt_cb);
if (err) {
goto unregister_gap;
}
gatt_cb_registered = true;
}
}
err = bt_le_host_init();
if (err) {
goto unregister_gatt;
}
err = bt_le_audio_init();
if (err) {
bt_le_host_deinit();
goto unregister_gatt;
}
return ESP_OK;
unregister_gatt:
if (gatt_cb_registered) {
bt_le_gatt_app_cb_unregister();
}
unregister_gap:
if (gap_cb_registered) {
bt_le_gap_app_cb_unregister();
}
return ESP_FAIL;
}
esp_err_t esp_ble_audio_common_start(esp_ble_audio_start_info_t *info)
{
int err;
if (info) {
#if CONFIG_BT_CSIP_SET_MEMBER
uint8_t cas_included = 0;
for (size_t i = 0; i < ARRAY_SIZE(info->csis_insts); i++) {
if (info->csis_insts[i].svc_inst &&
info->csis_insts[i].included_by_cas) {
cas_included++;
}
}
/* From CAS Spec:
* The CAS shall include no more than one instance of CSIS.
*/
if (cas_included > 1) {
return ESP_ERR_INVALID_ARG;
}
#endif /* CONFIG_BT_CSIP_SET_MEMBER */
}
err = bt_le_audio_start(info);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
@@ -0,0 +1,290 @@
/*
* SPDX-FileCopyrightText: 2021-2024 Nordic Semiconductor ASA
* SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "esp_ble_audio_csip_api.h"
#if CONFIG_BT_CSIP_SET_MEMBER
void *esp_ble_audio_csip_set_member_svc_decl_get(const esp_ble_audio_csip_set_member_svc_inst_t *svc_inst)
{
if (svc_inst == NULL) {
return NULL;
}
return bt_csip_set_member_svc_decl_get_safe(svc_inst);
}
esp_err_t esp_ble_audio_csip_set_member_register(const esp_ble_audio_csip_set_member_register_param_t *param,
esp_ble_audio_csip_set_member_svc_inst_t **svc_inst)
{
int err;
if (param == NULL || svc_inst == NULL) {
return ESP_ERR_INVALID_ARG;
}
if (param->lockable && param->rank == 0) {
/* Rank cannot be 0 if service is lockable */
return ESP_ERR_INVALID_ARG;
}
if (param->rank > param->set_size) {
/* Invalid rank (shall be less than or equal to set_size */
return ESP_ERR_INVALID_ARG;
}
#if CONFIG_BT_CSIP_SET_MEMBER_MAX_INSTANCE_COUNT > 1
if (param->parent == NULL) {
/* Parent service not provided */
return ESP_ERR_INVALID_ARG;
}
#endif /* CONFIG_BT_CSIP_SET_MEMBER_MAX_INSTANCE_COUNT > 1 */
err = bt_csip_set_member_register_safe(param, svc_inst);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_csip_set_member_unregister(esp_ble_audio_csip_set_member_svc_inst_t *svc_inst)
{
int err;
if (svc_inst == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_csip_set_member_unregister_safe(svc_inst);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_csip_set_member_sirk(esp_ble_audio_csip_set_member_svc_inst_t *svc_inst,
const uint8_t sirk[ESP_BLE_AUDIO_CSIP_SIRK_SIZE])
{
int err;
if (svc_inst == NULL || sirk == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_csip_set_member_sirk_safe(svc_inst, sirk);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_csip_set_member_set_size_and_rank(esp_ble_audio_csip_set_member_svc_inst_t *svc_inst,
uint8_t size, uint8_t rank)
{
int err;
if (svc_inst == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_csip_set_member_set_size_and_rank_safe(svc_inst, size, rank);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_csip_set_member_get_info(const esp_ble_audio_csip_set_member_svc_inst_t *svc_inst,
esp_ble_audio_csip_set_member_set_info_t *info)
{
int err;
if (svc_inst == NULL || info == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_csip_set_member_get_info_safe(svc_inst, info);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_csip_set_member_generate_rsi(const esp_ble_audio_csip_set_member_svc_inst_t *svc_inst,
uint8_t rsi[ESP_BLE_AUDIO_CSIP_RSI_SIZE])
{
int err;
if (svc_inst == NULL || rsi == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_csip_set_member_generate_rsi_safe(svc_inst, rsi);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_csip_set_member_lock(esp_ble_audio_csip_set_member_svc_inst_t *svc_inst,
bool lock, bool force)
{
int err;
if (svc_inst == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_csip_set_member_lock_safe(svc_inst, lock, force);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
#endif /* CONFIG_BT_CSIP_SET_MEMBER */
#if CONFIG_BT_CSIP_SET_COORDINATOR
esp_err_t esp_ble_audio_csip_set_coordinator_discover(uint16_t conn_handle)
{
esp_err_t ret = ESP_OK;
void *conn;
int err;
bt_le_host_lock();
conn = bt_le_acl_conn_find(conn_handle);
if (conn == NULL) {
ret = ESP_ERR_NOT_FOUND;
goto unlock;
}
err = bt_csip_set_coordinator_discover(conn);
if (err) {
ret = ESP_FAIL;
}
unlock:
bt_le_host_unlock();
return ret;
}
esp_ble_audio_csip_set_coordinator_set_member_t *
esp_ble_audio_csip_set_coordinator_set_member_by_conn(uint16_t conn_handle)
{
esp_ble_audio_csip_set_coordinator_set_member_t *ret = NULL;
void *conn;
bt_le_host_lock();
conn = bt_le_acl_conn_find(conn_handle);
if (conn == NULL) {
goto unlock;
}
ret = bt_csip_set_coordinator_set_member_by_conn(conn);
unlock:
bt_le_host_unlock();
return ret;
}
bool esp_ble_audio_csip_set_coordinator_is_set_member(const uint8_t sirk[ESP_BLE_AUDIO_CSIP_SIRK_SIZE],
uint8_t data_type, const uint8_t *data, uint8_t data_len)
{
struct bt_data ad = {
.type = data_type,
.data = data,
.data_len = data_len,
};
if (sirk == NULL || data_type != BT_DATA_CSIS_RSI ||
data == NULL || data_len != ESP_BLE_AUDIO_CSIP_RSI_SIZE) {
return false;
}
return bt_csip_set_coordinator_is_set_member_safe(sirk, &ad);
}
esp_err_t esp_ble_audio_csip_set_coordinator_register_cb(esp_ble_audio_csip_set_coordinator_cb_t *cb)
{
int err;
if (cb == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_csip_set_coordinator_register_cb_safe(cb);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_csip_set_coordinator_ordered_access(const esp_ble_audio_csip_set_coordinator_set_member_t *members[],
uint8_t count,
const esp_ble_audio_csip_set_coordinator_set_info_t *set_info,
bt_csip_set_coordinator_ordered_access_t cb)
{
int err;
if (members == NULL ||
count == 0 || count > CONFIG_BT_MAX_CONN ||
set_info == NULL || cb == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_csip_set_coordinator_ordered_access_safe(members, count, set_info, cb);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_csip_set_coordinator_lock(const esp_ble_audio_csip_set_coordinator_set_member_t **members,
uint8_t count,
const esp_ble_audio_csip_set_coordinator_set_info_t *set_info)
{
int err;
if (members == NULL || count > CONFIG_BT_MAX_CONN || set_info == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_csip_set_coordinator_lock_safe(members, count, set_info);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_csip_set_coordinator_release(const esp_ble_audio_csip_set_coordinator_set_member_t **members,
uint8_t count,
const esp_ble_audio_csip_set_coordinator_set_info_t *set_info)
{
int err;
if (members == NULL || count > CONFIG_BT_MAX_CONN || set_info == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_csip_set_coordinator_release_safe(members, count, set_info);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
#endif /* CONFIG_BT_CSIP_SET_COORDINATOR */
@@ -0,0 +1,268 @@
/*
* SPDX-FileCopyrightText: 2023-2024 Nordic Semiconductor ASA
* SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "esp_ble_audio_gmap_api.h"
#if CONFIG_BT_GMAP
esp_err_t esp_ble_audio_gmap_cb_register(const esp_ble_audio_gmap_cb_t *cb)
{
int err;
if (cb == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_gmap_cb_register_safe(cb);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_gmap_discover(uint16_t conn_handle)
{
esp_err_t ret = ESP_OK;
void *conn;
int err;
bt_le_host_lock();
conn = bt_le_acl_conn_find(conn_handle);
if (conn == NULL) {
ret = ESP_ERR_NOT_FOUND;
goto unlock;
}
err = bt_gmap_discover(conn);
if (err) {
ret = ESP_FAIL;
}
unlock:
bt_le_host_unlock();
return ret;
}
#define GMAP_ROLE_MASK (ESP_BLE_AUDIO_GMAP_ROLE_UGG | \
ESP_BLE_AUDIO_GMAP_ROLE_UGT | \
ESP_BLE_AUDIO_GMAP_ROLE_BGS | \
ESP_BLE_AUDIO_GMAP_ROLE_BGR)
static bool valid_gmap_role(esp_ble_audio_gmap_role_t role)
{
if (role == 0 || (role & GMAP_ROLE_MASK) != role) {
/* Invalid role */
return false;
}
if ((role & ESP_BLE_AUDIO_GMAP_ROLE_UGG) != 0 &&
!IS_ENABLED(CONFIG_BT_GMAP_UGG_SUPPORTED)) {
/* Device does not support the UGG role */
return false;
}
if ((role & ESP_BLE_AUDIO_GMAP_ROLE_UGT) != 0 &&
!IS_ENABLED(CONFIG_BT_GMAP_UGT_SUPPORTED)) {
/* Device does not support the UGT role */
return false;
}
if ((role & ESP_BLE_AUDIO_GMAP_ROLE_BGS) != 0 &&
!IS_ENABLED(CONFIG_BT_GMAP_BGS_SUPPORTED)) {
/* Device does not support the BGS role */
return false;
}
if ((role & ESP_BLE_AUDIO_GMAP_ROLE_BGR) != 0 &&
!IS_ENABLED(CONFIG_BT_GMAP_BGR_SUPPORTED)) {
/* Device does not support the BGR role */
return false;
}
return true;
}
static bool valid_gmap_features(esp_ble_audio_gmap_role_t role,
esp_ble_audio_gmap_feat_t features)
{
#if CONFIG_BT_GMAP_UGG_SUPPORTED
if ((role & ESP_BLE_AUDIO_GMAP_ROLE_UGG) != 0) {
esp_ble_audio_gmap_ugg_feat_t ugg_feat = features.ugg_feat;
if ((ugg_feat & ESP_BLE_AUDIO_GMAP_UGG_FEAT_MULTIPLEX) != 0 &&
CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT == 0) {
/* Cannot support ESP_BLE_AUDIO_GMAP_UGG_FEAT_MULTIPLEX with
* CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT == 0.
*/
return false;
}
if ((ugg_feat & ESP_BLE_AUDIO_GMAP_UGG_FEAT_96KBPS_SOURCE) != 0 &&
CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT == 0) {
/* Cannot support ESP_BLE_AUDIO_GMAP_UGG_FEAT_96KBPS_SOURCE with
* CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT == 0.
*/
return false;
}
if ((ugg_feat & ESP_BLE_AUDIO_GMAP_UGG_FEAT_MULTISINK) != 0 &&
(CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT < 2 ||
CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT < 2)) {
/* Cannot support ESP_BLE_AUDIO_GMAP_UGG_FEAT_MULTISINK with
* CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT or
* CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT < 2.
*/
return false;
}
}
#endif /* CONFIG_BT_GMAP_UGG_SUPPORTED */
#if CONFIG_BT_GMAP_UGT_SUPPORTED
if ((role & ESP_BLE_AUDIO_GMAP_ROLE_UGT) != 0) {
esp_ble_audio_gmap_ugt_feat_t ugt_feat = features.ugt_feat;
esp_ble_audio_gmap_bgr_feat_t bgr_feat = features.bgr_feat;
if ((ugt_feat & ESP_BLE_AUDIO_GMAP_UGT_FEAT_SOURCE) == 0 &&
(ugt_feat & ESP_BLE_AUDIO_GMAP_UGT_FEAT_SINK) == 0) {
/* Device shall support either ESP_BLE_AUDIO_GMAP_UGT_FEAT_SOURCE or
* ESP_BLE_AUDIO_GMAP_UGT_FEAT_SINK.
*/
return false;
}
if ((ugt_feat & ESP_BLE_AUDIO_GMAP_UGT_FEAT_SOURCE) == 0 &&
((ugt_feat & ESP_BLE_AUDIO_GMAP_UGT_FEAT_80KBPS_SOURCE) != 0 ||
(ugt_feat & ESP_BLE_AUDIO_GMAP_UGT_FEAT_MULTISOURCE) != 0)) {
/* Device shall support ESP_BLE_AUDIO_GMAP_UGT_FEAT_SOURCE if
* ESP_BLE_AUDIO_GMAP_UGT_FEAT_80KBPS_SOURCE or
* ESP_BLE_AUDIO_GMAP_UGT_FEAT_MULTISOURCE is supported.
*/
return false;
}
if ((ugt_feat & ESP_BLE_AUDIO_GMAP_UGT_FEAT_SOURCE) != 0 &&
CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT == 0) {
/* Cannot support ESP_BLE_AUDIO_GMAP_UGT_FEAT_SOURCE with
* CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT == 0.
*/
return false;
}
if ((ugt_feat & ESP_BLE_AUDIO_GMAP_UGT_FEAT_MULTISOURCE) != 0 &&
(CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT < 2 ||
CONFIG_BT_ASCS_MAX_ACTIVE_ASES < 2)) {
/* Cannot support ESP_BLE_AUDIO_GMAP_UGT_FEAT_MULTISOURCE with
* CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT or
* CONFIG_BT_ASCS_MAX_ACTIVE_ASES < 2.
*/
return false;
}
if ((ugt_feat & ESP_BLE_AUDIO_GMAP_UGT_FEAT_SINK) != 0 &&
CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT == 0) {
/* Cannot support ESP_BLE_AUDIO_GMAP_UGT_FEAT_SINK with
* CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT == 0.
*/
return false;
}
if ((ugt_feat & ESP_BLE_AUDIO_GMAP_UGT_FEAT_SINK) == 0 &&
((ugt_feat & ESP_BLE_AUDIO_GMAP_UGT_FEAT_64KBPS_SINK) != 0 ||
(ugt_feat & ESP_BLE_AUDIO_GMAP_UGT_FEAT_MULTISINK) != 0 ||
(ugt_feat & ESP_BLE_AUDIO_GMAP_UGT_FEAT_MULTIPLEX) != 0)) {
/* Device shall support ESP_BLE_AUDIO_GMAP_UGT_FEAT_SINK if
* ESP_BLE_AUDIO_GMAP_UGT_FEAT_64KBPS_SINK,
* ESP_BLE_AUDIO_GMAP_UGT_FEAT_MULTISINK or
* ESP_BLE_AUDIO_GMAP_UGT_FEAT_MULTIPLEX is supported.
*/
return false;
}
if ((ugt_feat & ESP_BLE_AUDIO_GMAP_UGT_FEAT_MULTISINK) != 0 &&
(CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT < 2 ||
CONFIG_BT_ASCS_MAX_ACTIVE_ASES < 2)) {
/* Cannot support ESP_BLE_AUDIO_GMAP_UGT_FEAT_MULTISINK with
* CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT or
* CONFIG_BT_ASCS_MAX_ACTIVE_ASES < 2.
*/
return false;
}
/* If the device supports both the UGT and BGT roles, then it needs
* have the same support for multiplexing for both roles.
*/
if ((role & ESP_BLE_AUDIO_GMAP_ROLE_BGR) != 0 &&
IS_ENABLED(CONFIG_BT_GMAP_BGR_SUPPORTED) &&
!!(ugt_feat & ESP_BLE_AUDIO_GMAP_UGT_FEAT_MULTIPLEX) !=
!!(bgr_feat & ESP_BLE_AUDIO_GMAP_BGR_FEAT_MULTIPLEX)) {
/* Device shall support ESP_BLE_AUDIO_GMAP_UGT_FEAT_MULTIPLEX if
* ESP_BLE_AUDIO_GMAP_BGR_FEAT_MULTIPLEX is supported, and vice versa.
*/
return false;
}
}
#endif /* CONFIG_BT_GMAP_UGT_SUPPORTED */
#if CONFIG_BT_GMAP_BGR_SUPPORTED
if ((role & ESP_BLE_AUDIO_GMAP_ROLE_BGR) != 0) {
esp_ble_audio_gmap_bgr_feat_t bgr_feat = features.bgr_feat;
if ((bgr_feat & ESP_BLE_AUDIO_GMAP_BGR_FEAT_MULTISINK) != 0 &&
CONFIG_BT_BAP_BROADCAST_SNK_STREAM_COUNT < 2) {
/* Cannot support ESP_BLE_AUDIO_GMAP_BGR_FEAT_MULTISINK with
* CONFIG_BT_BAP_BROADCAST_SNK_STREAM_COUNT < 2.
*/
return false;
}
}
#endif /* CONFIG_BT_GMAP_BGR_SUPPORTED */
/* If the roles are not supported, then the feature characteristics
* are not instantiated and the feature values do not need to be
* checked, as they will never be read (thus ignore by the stack).
*/
return true;
}
esp_err_t esp_ble_audio_gmap_register(esp_ble_audio_gmap_role_t role,
esp_ble_audio_gmap_feat_t features)
{
int err;
if (valid_gmap_role(role) == false ||
valid_gmap_features(role, features) == false) {
return ESP_ERR_INVALID_ARG;
}
err = bt_gmap_register_safe(role, features);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_gmap_set_role(esp_ble_audio_gmap_role_t role,
esp_ble_audio_gmap_feat_t features)
{
int err;
if (valid_gmap_role(role) == false ||
valid_gmap_features(role, features) == false) {
return ESP_ERR_INVALID_ARG;
}
err = bt_gmap_set_role_safe(role, features);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
#endif /* CONFIG_BT_GMAP */
@@ -0,0 +1,281 @@
/*
* SPDX-FileCopyrightText: 2022 Codecoup
* SPDX-FileCopyrightText: 2024 Nordic Semiconductor ASA
* SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "esp_ble_audio_has_api.h"
#if CONFIG_BT_HAS_CLIENT
esp_err_t esp_ble_audio_has_client_cb_register(const esp_ble_audio_has_client_cb_t *cb)
{
int err;
if (cb == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_has_client_cb_register_safe(cb);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_has_client_discover(uint16_t conn_handle)
{
esp_err_t ret = ESP_OK;
void *conn;
int err;
bt_le_host_lock();
conn = bt_le_acl_conn_find(conn_handle);
if (conn == NULL) {
ret = ESP_ERR_NOT_FOUND;
goto unlock;
}
err = bt_has_client_discover(conn);
if (err) {
ret = ESP_FAIL;
}
unlock:
bt_le_host_unlock();
return ret;
}
esp_err_t esp_ble_audio_has_client_presets_read(esp_ble_audio_has_t *has,
uint8_t index,
uint8_t max_count)
{
int err;
if (has == NULL ||
index == ESP_BLE_AUDIO_HAS_PRESET_INDEX_NONE ||
max_count == 0) {
return ESP_ERR_INVALID_ARG;
}
err = bt_has_client_presets_read_safe(has, index, max_count);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_has_client_preset_set(esp_ble_audio_has_t *has,
uint8_t index, bool sync)
{
int err;
if (has == NULL || index == ESP_BLE_AUDIO_HAS_PRESET_INDEX_NONE) {
return ESP_ERR_INVALID_ARG;
}
err = bt_has_client_preset_set_safe(has, index, sync);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_has_client_preset_next(esp_ble_audio_has_t *has, bool sync)
{
int err;
if (has == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_has_client_preset_next_safe(has, sync);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_has_client_preset_prev(esp_ble_audio_has_t *has, bool sync)
{
int err;
if (has == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_has_client_preset_prev_safe(has, sync);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
#endif /* CONFIG_BT_HAS_CLIENT */
#if CONFIG_BT_HAS
esp_err_t esp_ble_audio_has_register(const esp_ble_audio_has_features_param_t *features)
{
int err;
if (features == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_has_register_safe(features);
if (err) {
return ESP_FAIL;
}
#if BLE_AUDIO_SVC_SEP_ADD
err = bt_le_has_init();
if (err) {
return ESP_FAIL;
}
#endif /* BLE_AUDIO_SVC_SEP_ADD */
return ESP_OK;
}
esp_err_t esp_ble_audio_has_preset_register(const esp_ble_audio_has_preset_register_param_t *param)
{
int err;
if (param == NULL ||
param->index == ESP_BLE_AUDIO_HAS_PRESET_INDEX_NONE ||
param->name == NULL ||
param->ops == NULL || param->ops->select == NULL) {
return ESP_ERR_INVALID_ARG;
}
if (strlen(param->name) < ESP_BLE_AUDIO_HAS_PRESET_NAME_MIN ||
strlen(param->name) > ESP_BLE_AUDIO_HAS_PRESET_NAME_MAX) {
return ESP_ERR_INVALID_ARG;
}
if (!IS_ENABLED(CONFIG_BT_HAS_PRESET_NAME_DYNAMIC) &&
(param->properties & ESP_BLE_AUDIO_HAS_PROP_WRITABLE) > 0) {
/* Writable presets is not supported */
return ESP_ERR_INVALID_ARG;
}
err = bt_has_preset_register_safe(param);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_has_preset_unregister(uint8_t index)
{
int err;
if (index == ESP_BLE_AUDIO_HAS_PRESET_INDEX_NONE) {
return ESP_ERR_INVALID_ARG;
}
err = bt_has_preset_unregister_safe(index);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_has_preset_available(uint8_t index)
{
int err;
if (index == ESP_BLE_AUDIO_HAS_PRESET_INDEX_NONE) {
return ESP_ERR_INVALID_ARG;
}
err = bt_has_preset_available_safe(index);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_has_preset_unavailable(uint8_t index)
{
int err;
if (index == ESP_BLE_AUDIO_HAS_PRESET_INDEX_NONE) {
return ESP_ERR_INVALID_ARG;
}
err = bt_has_preset_unavailable_safe(index);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_has_preset_active_set(uint8_t index)
{
int err;
if (index == ESP_BLE_AUDIO_HAS_PRESET_INDEX_NONE) {
return ESP_ERR_INVALID_ARG;
}
err = bt_has_preset_active_set_safe(index);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
uint8_t esp_ble_audio_has_preset_active_get(void)
{
return bt_has_preset_active_get_safe();
}
esp_err_t esp_ble_audio_has_preset_name_change(uint8_t index, const char *name)
{
int err;
if (index == ESP_BLE_AUDIO_HAS_PRESET_INDEX_NONE || name == NULL) {
return ESP_ERR_INVALID_ARG;
}
if (strlen(name) < ESP_BLE_AUDIO_HAS_PRESET_NAME_MIN ||
strlen(name) > ESP_BLE_AUDIO_HAS_PRESET_NAME_MAX) {
return ESP_ERR_INVALID_ARG;
}
err = bt_has_preset_name_change_safe(index, name);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_has_features_set(const esp_ble_audio_has_features_param_t *features)
{
int err;
if (features == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_has_features_set_safe(features);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
#endif /* CONFIG_BT_HAS */
@@ -0,0 +1,947 @@
/*
* SPDX-FileCopyrightText: 2019-2024 Nordic Semiconductor ASA
* SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "esp_ble_audio_mcs_defs.h"
#include "esp_ble_audio_mcc_api.h"
#if CONFIG_BT_MCC
esp_err_t esp_ble_audio_mcc_init(esp_ble_audio_mcc_cb_t *cb)
{
int err;
err = bt_mcc_init_safe(cb);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_mcc_discover_mcs(uint16_t conn_handle, bool subscribe)
{
esp_err_t ret = ESP_OK;
void *conn;
int err;
bt_le_host_lock();
conn = bt_le_acl_conn_find(conn_handle);
if (conn == NULL) {
ret = ESP_ERR_NOT_FOUND;
goto unlock;
}
err = bt_mcc_discover_mcs(conn, subscribe);
if (err) {
ret = ESP_FAIL;
}
unlock:
bt_le_host_unlock();
return ret;
}
esp_err_t esp_ble_audio_mcc_read_player_name(uint16_t conn_handle)
{
esp_err_t ret = ESP_OK;
void *conn;
int err;
bt_le_host_lock();
conn = bt_le_acl_conn_find(conn_handle);
if (conn == NULL) {
ret = ESP_ERR_NOT_FOUND;
goto unlock;
}
err = bt_mcc_read_player_name(conn);
if (err) {
ret = ESP_FAIL;
}
unlock:
bt_le_host_unlock();
return ret;
}
#if CONFIG_BT_MCC_READ_MEDIA_PLAYER_ICON_URL
esp_err_t esp_ble_audio_mcc_read_icon_url(uint16_t conn_handle)
{
esp_err_t ret = ESP_OK;
void *conn;
int err;
bt_le_host_lock();
conn = bt_le_acl_conn_find(conn_handle);
if (conn == NULL) {
ret = ESP_ERR_NOT_FOUND;
goto unlock;
}
err = bt_mcc_read_icon_url(conn);
if (err) {
ret = ESP_FAIL;
}
unlock:
bt_le_host_unlock();
return ret;
}
#endif /* CONFIG_BT_MCC_READ_MEDIA_PLAYER_ICON_URL */
#if CONFIG_BT_MCC_READ_TRACK_TITLE
esp_err_t esp_ble_audio_mcc_read_track_title(uint16_t conn_handle)
{
esp_err_t ret = ESP_OK;
void *conn;
int err;
bt_le_host_lock();
conn = bt_le_acl_conn_find(conn_handle);
if (conn == NULL) {
ret = ESP_ERR_NOT_FOUND;
goto unlock;
}
err = bt_mcc_read_track_title(conn);
if (err) {
ret = ESP_FAIL;
}
unlock:
bt_le_host_unlock();
return ret;
}
#endif /* CONFIG_BT_MCC_READ_TRACK_TITLE */
#if CONFIG_BT_MCC_READ_TRACK_DURATION
esp_err_t esp_ble_audio_mcc_read_track_duration(uint16_t conn_handle)
{
esp_err_t ret = ESP_OK;
void *conn;
int err;
bt_le_host_lock();
conn = bt_le_acl_conn_find(conn_handle);
if (conn == NULL) {
ret = ESP_ERR_NOT_FOUND;
goto unlock;
}
err = bt_mcc_read_track_duration(conn);
if (err) {
ret = ESP_FAIL;
}
unlock:
bt_le_host_unlock();
return ret;
}
#endif /* CONFIG_BT_MCC_READ_TRACK_DURATION */
#if CONFIG_BT_MCC_READ_TRACK_POSITION
esp_err_t esp_ble_audio_mcc_read_track_position(uint16_t conn_handle)
{
esp_err_t ret = ESP_OK;
void *conn;
int err;
bt_le_host_lock();
conn = bt_le_acl_conn_find(conn_handle);
if (conn == NULL) {
ret = ESP_ERR_NOT_FOUND;
goto unlock;
}
err = bt_mcc_read_track_position(conn);
if (err) {
ret = ESP_FAIL;
}
unlock:
bt_le_host_unlock();
return ret;
}
#endif /* CONFIG_BT_MCC_READ_TRACK_POSITION */
#if CONFIG_BT_MCC_SET_TRACK_POSITION
esp_err_t esp_ble_audio_mcc_set_track_position(uint16_t conn_handle, int32_t pos)
{
esp_err_t ret = ESP_OK;
void *conn;
int err;
bt_le_host_lock();
conn = bt_le_acl_conn_find(conn_handle);
if (conn == NULL) {
ret = ESP_ERR_NOT_FOUND;
goto unlock;
}
err = bt_mcc_set_track_position(conn, pos);
if (err) {
ret = ESP_FAIL;
}
unlock:
bt_le_host_unlock();
return ret;
}
#endif /* CONFIG_BT_MCC_SET_TRACK_POSITION */
#if CONFIG_BT_MCC_READ_PLAYBACK_SPEED
esp_err_t esp_ble_audio_mcc_read_playback_speed(uint16_t conn_handle)
{
esp_err_t ret = ESP_OK;
void *conn;
int err;
bt_le_host_lock();
conn = bt_le_acl_conn_find(conn_handle);
if (conn == NULL) {
ret = ESP_ERR_NOT_FOUND;
goto unlock;
}
err = bt_mcc_read_playback_speed(conn);
if (err) {
ret = ESP_FAIL;
}
unlock:
bt_le_host_unlock();
return ret;
}
#endif /* CONFIG_BT_MCC_READ_PLAYBACK_SPEED */
#if CONFIG_BT_MCC_SET_PLAYBACK_SPEED
esp_err_t esp_ble_audio_mcc_set_playback_speed(uint16_t conn_handle, int8_t speed)
{
esp_err_t ret = ESP_OK;
void *conn;
int err;
bt_le_host_lock();
conn = bt_le_acl_conn_find(conn_handle);
if (conn == NULL) {
ret = ESP_ERR_NOT_FOUND;
goto unlock;
}
err = bt_mcc_set_playback_speed(conn, speed);
if (err) {
ret = ESP_FAIL;
}
unlock:
bt_le_host_unlock();
return ret;
}
#endif /* CONFIG_BT_MCC_SET_PLAYBACK_SPEED */
#if CONFIG_BT_MCC_READ_SEEKING_SPEED
esp_err_t esp_ble_audio_mcc_read_seeking_speed(uint16_t conn_handle)
{
esp_err_t ret = ESP_OK;
void *conn;
int err;
bt_le_host_lock();
conn = bt_le_acl_conn_find(conn_handle);
if (conn == NULL) {
ret = ESP_ERR_NOT_FOUND;
goto unlock;
}
err = bt_mcc_read_seeking_speed(conn);
if (err) {
ret = ESP_FAIL;
}
unlock:
bt_le_host_unlock();
return ret;
}
#endif /* CONFIG_BT_MCC_READ_SEEKING_SPEED */
#if CONFIG_BT_MCC_READ_PLAYING_ORDER
esp_err_t esp_ble_audio_mcc_read_playing_order(uint16_t conn_handle)
{
esp_err_t ret = ESP_OK;
void *conn;
int err;
bt_le_host_lock();
conn = bt_le_acl_conn_find(conn_handle);
if (conn == NULL) {
ret = ESP_ERR_NOT_FOUND;
goto unlock;
}
err = bt_mcc_read_playing_order(conn);
if (err) {
ret = ESP_FAIL;
}
unlock:
bt_le_host_unlock();
return ret;
}
#endif /* CONFIG_BT_MCC_READ_PLAYING_ORDER */
#if CONFIG_BT_MCC_SET_PLAYING_ORDER
esp_err_t esp_ble_audio_mcc_set_playing_order(uint16_t conn_handle, uint8_t order)
{
esp_err_t ret = ESP_OK;
void *conn;
int err;
bt_le_host_lock();
conn = bt_le_acl_conn_find(conn_handle);
if (conn == NULL) {
ret = ESP_ERR_NOT_FOUND;
goto unlock;
}
err = bt_mcc_set_playing_order(conn, order);
if (err) {
ret = ESP_FAIL;
}
unlock:
bt_le_host_unlock();
return ret;
}
#endif /* CONFIG_BT_MCC_SET_PLAYING_ORDER */
#if CONFIG_BT_MCC_READ_PLAYING_ORDER_SUPPORTED
esp_err_t esp_ble_audio_mcc_read_playing_orders_supported(uint16_t conn_handle)
{
esp_err_t ret = ESP_OK;
void *conn;
int err;
bt_le_host_lock();
conn = bt_le_acl_conn_find(conn_handle);
if (conn == NULL) {
ret = ESP_ERR_NOT_FOUND;
goto unlock;
}
err = bt_mcc_read_playing_orders_supported(conn);
if (err) {
ret = ESP_FAIL;
}
unlock:
bt_le_host_unlock();
return ret;
}
#endif /* CONFIG_BT_MCC_READ_PLAYING_ORDER_SUPPORTED */
#if CONFIG_BT_MCC_READ_MEDIA_STATE
esp_err_t esp_ble_audio_mcc_read_media_state(uint16_t conn_handle)
{
esp_err_t ret = ESP_OK;
void *conn;
int err;
bt_le_host_lock();
conn = bt_le_acl_conn_find(conn_handle);
if (conn == NULL) {
ret = ESP_ERR_NOT_FOUND;
goto unlock;
}
err = bt_mcc_read_media_state(conn);
if (err) {
ret = ESP_FAIL;
}
unlock:
bt_le_host_unlock();
return ret;
}
#endif /* CONFIG_BT_MCC_READ_MEDIA_STATE */
#if CONFIG_BT_MCC_SET_MEDIA_CONTROL_POINT
#define MCS_VALID_OP(opcode) \
(IN_RANGE((opcode), ESP_BLE_AUDIO_MCS_OPC_PLAY, ESP_BLE_AUDIO_MCS_OPC_STOP) || \
(opcode == ESP_BLE_AUDIO_MCS_OPC_MOVE_RELATIVE) || \
IN_RANGE((opcode), ESP_BLE_AUDIO_MCS_OPC_PREV_SEGMENT, ESP_BLE_AUDIO_MCS_OPC_GOTO_SEGMENT) || \
IN_RANGE((opcode), ESP_BLE_AUDIO_MCS_OPC_PREV_TRACK, ESP_BLE_AUDIO_MCS_OPC_GOTO_TRACK) || \
IN_RANGE((opcode), ESP_BLE_AUDIO_MCS_OPC_PREV_GROUP, ESP_BLE_AUDIO_MCS_OPC_GOTO_GROUP))
esp_err_t esp_ble_audio_mcc_send_cmd(uint16_t conn_handle,
const esp_ble_audio_mpl_cmd_t *cmd)
{
esp_err_t ret = ESP_OK;
void *conn;
int err;
if (cmd == NULL || MCS_VALID_OP(cmd->opcode) == false) {
return ESP_ERR_INVALID_ARG;
}
bt_le_host_lock();
conn = bt_le_acl_conn_find(conn_handle);
if (conn == NULL) {
ret = ESP_ERR_NOT_FOUND;
goto unlock;
}
err = bt_mcc_send_cmd(conn, cmd);
if (err) {
ret = ESP_FAIL;
}
unlock:
bt_le_host_unlock();
return ret;
}
#endif /* CONFIG_BT_MCC_SET_MEDIA_CONTROL_POINT */
#if CONFIG_BT_MCC_READ_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED
esp_err_t esp_ble_audio_mcc_read_opcodes_supported(uint16_t conn_handle)
{
esp_err_t ret = ESP_OK;
void *conn;
int err;
bt_le_host_lock();
conn = bt_le_acl_conn_find(conn_handle);
if (conn == NULL) {
ret = ESP_ERR_NOT_FOUND;
goto unlock;
}
err = bt_mcc_read_opcodes_supported(conn);
if (err) {
ret = ESP_FAIL;
}
unlock:
bt_le_host_unlock();
return ret;
}
#endif /* CONFIG_BT_MCC_READ_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED */
#if CONFIG_BT_MCC_READ_CONTENT_CONTROL_ID
esp_err_t esp_ble_audio_mcc_read_content_control_id(uint16_t conn_handle)
{
esp_err_t ret = ESP_OK;
void *conn;
int err;
bt_le_host_lock();
conn = bt_le_acl_conn_find(conn_handle);
if (conn == NULL) {
ret = ESP_ERR_NOT_FOUND;
goto unlock;
}
err = bt_mcc_read_content_control_id(conn);
if (err) {
ret = ESP_FAIL;
}
unlock:
bt_le_host_unlock();
return ret;
}
#endif /* CONFIG_BT_MCC_READ_CONTENT_CONTROL_ID */
#if CONFIG_BT_MCC_OTS
esp_err_t esp_ble_audio_mcc_read_icon_obj_id(uint16_t conn_handle)
{
esp_err_t ret = ESP_OK;
void *conn;
int err;
bt_le_host_lock();
conn = bt_le_acl_conn_find(conn_handle);
if (conn == NULL) {
ret = ESP_ERR_NOT_FOUND;
goto unlock;
}
err = bt_mcc_read_icon_obj_id(conn);
if (err) {
ret = ESP_FAIL;
}
unlock:
bt_le_host_unlock();
return ret;
}
esp_err_t esp_ble_audio_mcc_read_segments_obj_id(uint16_t conn_handle)
{
esp_err_t ret = ESP_OK;
void *conn;
int err;
bt_le_host_lock();
conn = bt_le_acl_conn_find(conn_handle);
if (conn == NULL) {
ret = ESP_ERR_NOT_FOUND;
goto unlock;
}
err = bt_mcc_read_segments_obj_id(conn);
if (err) {
ret = ESP_FAIL;
}
unlock:
bt_le_host_unlock();
return ret;
}
esp_err_t esp_ble_audio_mcc_read_current_track_obj_id(uint16_t conn_handle)
{
esp_err_t ret = ESP_OK;
void *conn;
int err;
bt_le_host_lock();
conn = bt_le_acl_conn_find(conn_handle);
if (conn == NULL) {
ret = ESP_ERR_NOT_FOUND;
goto unlock;
}
err = bt_mcc_read_current_track_obj_id(conn);
if (err) {
ret = ESP_FAIL;
}
unlock:
bt_le_host_unlock();
return ret;
}
esp_err_t esp_ble_audio_mcc_set_current_track_obj_id(uint16_t conn_handle, uint64_t id)
{
esp_err_t ret = ESP_OK;
void *conn;
int err;
if (ESP_BLE_AUDIO_MCS_VALID_OBJ_ID(id) == false) {
return ESP_ERR_INVALID_ARG;
}
bt_le_host_lock();
conn = bt_le_acl_conn_find(conn_handle);
if (conn == NULL) {
ret = ESP_ERR_NOT_FOUND;
goto unlock;
}
err = bt_mcc_set_current_track_obj_id(conn, id);
if (err) {
ret = ESP_FAIL;
}
unlock:
bt_le_host_unlock();
return ret;
}
esp_err_t esp_ble_audio_mcc_read_next_track_obj_id(uint16_t conn_handle)
{
esp_err_t ret = ESP_OK;
void *conn;
int err;
bt_le_host_lock();
conn = bt_le_acl_conn_find(conn_handle);
if (conn == NULL) {
ret = ESP_ERR_NOT_FOUND;
goto unlock;
}
err = bt_mcc_read_next_track_obj_id(conn);
if (err) {
ret = ESP_FAIL;
}
unlock:
bt_le_host_unlock();
return ret;
}
esp_err_t esp_ble_audio_mcc_set_next_track_obj_id(uint16_t conn_handle, uint64_t id)
{
esp_err_t ret = ESP_OK;
void *conn;
int err;
if (ESP_BLE_AUDIO_MCS_VALID_OBJ_ID(id) == false) {
return ESP_ERR_INVALID_ARG;
}
bt_le_host_lock();
conn = bt_le_acl_conn_find(conn_handle);
if (conn == NULL) {
ret = ESP_ERR_NOT_FOUND;
goto unlock;
}
err = bt_mcc_set_next_track_obj_id(conn, id);
if (err) {
ret = ESP_FAIL;
}
unlock:
bt_le_host_unlock();
return ret;
}
esp_err_t esp_ble_audio_mcc_read_current_group_obj_id(uint16_t conn_handle)
{
esp_err_t ret = ESP_OK;
void *conn;
int err;
bt_le_host_lock();
conn = bt_le_acl_conn_find(conn_handle);
if (conn == NULL) {
ret = ESP_ERR_NOT_FOUND;
goto unlock;
}
err = bt_mcc_read_current_group_obj_id(conn);
if (err) {
ret = ESP_FAIL;
}
unlock:
bt_le_host_unlock();
return ret;
}
esp_err_t esp_ble_audio_mcc_set_current_group_obj_id(uint16_t conn_handle, uint64_t id)
{
esp_err_t ret = ESP_OK;
void *conn;
int err;
if (ESP_BLE_AUDIO_MCS_VALID_OBJ_ID(id) == false) {
return ESP_ERR_INVALID_ARG;
}
bt_le_host_lock();
conn = bt_le_acl_conn_find(conn_handle);
if (conn == NULL) {
ret = ESP_ERR_NOT_FOUND;
goto unlock;
}
err = bt_mcc_set_current_group_obj_id(conn, id);
if (err) {
ret = ESP_FAIL;
}
unlock:
bt_le_host_unlock();
return ret;
}
esp_err_t esp_ble_audio_mcc_read_parent_group_obj_id(uint16_t conn_handle)
{
esp_err_t ret = ESP_OK;
void *conn;
int err;
bt_le_host_lock();
conn = bt_le_acl_conn_find(conn_handle);
if (conn == NULL) {
ret = ESP_ERR_NOT_FOUND;
goto unlock;
}
err = bt_mcc_read_parent_group_obj_id(conn);
if (err) {
ret = ESP_FAIL;
}
unlock:
bt_le_host_unlock();
return ret;
}
esp_err_t esp_ble_audio_mcc_send_search(uint16_t conn_handle,
const esp_ble_audio_mpl_search_t *search)
{
esp_err_t ret = ESP_OK;
void *conn;
int err;
if (search == NULL || IN_RANGE(search->len,
ESP_BLE_AUDIO_SEARCH_LEN_MIN,
ESP_BLE_AUDIO_SEARCH_LEN_MAX) == false) {
return ESP_ERR_INVALID_ARG;
}
bt_le_host_lock();
conn = bt_le_acl_conn_find(conn_handle);
if (conn == NULL) {
ret = ESP_ERR_NOT_FOUND;
goto unlock;
}
err = bt_mcc_send_search(conn, search);
if (err) {
ret = ESP_FAIL;
}
unlock:
bt_le_host_unlock();
return ret;
}
esp_err_t esp_ble_audio_mcc_read_search_results_obj_id(uint16_t conn_handle)
{
esp_err_t ret = ESP_OK;
void *conn;
int err;
bt_le_host_lock();
conn = bt_le_acl_conn_find(conn_handle);
if (conn == NULL) {
ret = ESP_ERR_NOT_FOUND;
goto unlock;
}
err = bt_mcc_read_search_results_obj_id(conn);
if (err) {
ret = ESP_FAIL;
}
unlock:
bt_le_host_unlock();
return ret;
}
esp_err_t esp_ble_audio_mcc_otc_read_object_metadata(uint16_t conn_handle)
{
esp_err_t ret = ESP_OK;
void *conn;
int err;
bt_le_host_lock();
conn = bt_le_acl_conn_find(conn_handle);
if (conn == NULL) {
ret = ESP_ERR_NOT_FOUND;
goto unlock;
}
err = bt_mcc_otc_read_object_metadata(conn);
if (err) {
ret = ESP_FAIL;
}
unlock:
bt_le_host_unlock();
return ret;
}
esp_err_t esp_ble_audio_mcc_otc_read_icon_object(uint16_t conn_handle)
{
esp_err_t ret = ESP_OK;
void *conn;
int err;
bt_le_host_lock();
conn = bt_le_acl_conn_find(conn_handle);
if (conn == NULL) {
ret = ESP_ERR_NOT_FOUND;
goto unlock;
}
err = bt_mcc_otc_read_icon_object(conn);
if (err) {
ret = ESP_FAIL;
}
unlock:
bt_le_host_unlock();
return ret;
}
esp_err_t esp_ble_audio_mcc_otc_read_track_segments_object(uint16_t conn_handle)
{
esp_err_t ret = ESP_OK;
void *conn;
int err;
bt_le_host_lock();
conn = bt_le_acl_conn_find(conn_handle);
if (conn == NULL) {
ret = ESP_ERR_NOT_FOUND;
goto unlock;
}
err = bt_mcc_otc_read_track_segments_object(conn);
if (err) {
ret = ESP_FAIL;
}
unlock:
bt_le_host_unlock();
return ret;
}
esp_err_t esp_ble_audio_mcc_otc_read_current_track_object(uint16_t conn_handle)
{
esp_err_t ret = ESP_OK;
void *conn;
int err;
bt_le_host_lock();
conn = bt_le_acl_conn_find(conn_handle);
if (conn == NULL) {
ret = ESP_ERR_NOT_FOUND;
goto unlock;
}
err = bt_mcc_otc_read_current_track_object(conn);
if (err) {
ret = ESP_FAIL;
}
unlock:
bt_le_host_unlock();
return ret;
}
esp_err_t esp_ble_audio_mcc_otc_read_next_track_object(uint16_t conn_handle)
{
esp_err_t ret = ESP_OK;
void *conn;
int err;
bt_le_host_lock();
conn = bt_le_acl_conn_find(conn_handle);
if (conn == NULL) {
ret = ESP_ERR_NOT_FOUND;
goto unlock;
}
err = bt_mcc_otc_read_next_track_object(conn);
if (err) {
ret = ESP_FAIL;
}
unlock:
bt_le_host_unlock();
return ret;
}
esp_err_t esp_ble_audio_mcc_otc_read_current_group_object(uint16_t conn_handle)
{
esp_err_t ret = ESP_OK;
void *conn;
int err;
bt_le_host_lock();
conn = bt_le_acl_conn_find(conn_handle);
if (conn == NULL) {
ret = ESP_ERR_NOT_FOUND;
goto unlock;
}
err = bt_mcc_otc_read_current_group_object(conn);
if (err) {
ret = ESP_FAIL;
}
unlock:
bt_le_host_unlock();
return ret;
}
esp_err_t esp_ble_audio_mcc_otc_read_parent_group_object(uint16_t conn_handle)
{
esp_err_t ret = ESP_OK;
void *conn;
int err;
bt_le_host_lock();
conn = bt_le_acl_conn_find(conn_handle);
if (conn == NULL) {
ret = ESP_ERR_NOT_FOUND;
goto unlock;
}
err = bt_mcc_otc_read_parent_group_object(conn);
if (err) {
ret = ESP_FAIL;
}
unlock:
bt_le_host_unlock();
return ret;
}
#if CONFIG_BT_MCC_SHELL
struct bt_ots_client *esp_ble_audio_mcc_otc_inst(uint16_t conn_handle)
{
struct bt_ots_client *ret = NULL;
void *conn;
bt_le_host_lock();
conn = bt_le_acl_conn_find(conn_handle);
if (conn == NULL) {
goto unlock;
}
ret = bt_mcc_otc_inst(conn);
unlock:
bt_le_host_unlock();
return ret;
}
#endif /* CONFIG_BT_MCC_SHELL */
#endif /* CONFIG_BT_MCC_OTS */
#endif /* CONFIG_BT_MCC */
@@ -0,0 +1,585 @@
/*
* SPDX-FileCopyrightText: 2019-2024 Nordic Semiconductor ASA
* SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "esp_ble_audio_mcs_defs.h"
#include "esp_ble_audio_media_proxy_api.h"
#if CONFIG_BT_MCTL_LOCAL_PLAYER_LOCAL_CONTROL
esp_err_t esp_ble_audio_media_proxy_ctrl_register(esp_ble_audio_media_proxy_ctrl_cbs_t *ctrl_cbs)
{
int err;
if (ctrl_cbs == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_media_proxy_ctrl_register_safe(ctrl_cbs);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
#endif /* CONFIG_BT_MCTL_LOCAL_PLAYER_LOCAL_CONTROL */
#if CONFIG_BT_MCTL_REMOTE_PLAYER_CONTROL
esp_err_t esp_ble_audio_media_proxy_ctrl_discover_player(uint16_t conn_handle)
{
esp_err_t ret = ESP_OK;
void *conn;
int err;
bt_le_host_lock();
conn = bt_le_acl_conn_find(conn_handle);
if (conn == NULL) {
ret = ESP_ERR_NOT_FOUND;
goto unlock;
}
err = bt_media_proxy_ctrl_discover_player(conn);
if (err) {
ret = ESP_FAIL;
}
unlock:
bt_le_host_unlock();
return ret;
}
#endif /* CONFIG_BT_MCTL_REMOTE_PLAYER_CONTROL */
#if CONFIG_BT_MCTL_LOCAL_PLAYER_LOCAL_CONTROL || CONFIG_BT_MCTL_REMOTE_PLAYER_CONTROL
esp_err_t esp_ble_audio_media_proxy_ctrl_get_player_name(esp_ble_audio_media_player_t *player)
{
int err;
if (player == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_media_proxy_ctrl_get_player_name_safe(player);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_media_proxy_ctrl_get_icon_id(esp_ble_audio_media_player_t *player)
{
int err;
if (player == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_media_proxy_ctrl_get_icon_id_safe(player);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_media_proxy_ctrl_get_icon_url(esp_ble_audio_media_player_t *player)
{
int err;
if (player == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_media_proxy_ctrl_get_icon_url_safe(player);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_media_proxy_ctrl_get_track_title(esp_ble_audio_media_player_t *player)
{
int err;
if (player == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_media_proxy_ctrl_get_track_title_safe(player);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_media_proxy_ctrl_get_track_duration(esp_ble_audio_media_player_t *player)
{
int err;
if (player == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_media_proxy_ctrl_get_track_duration_safe(player);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_media_proxy_ctrl_get_track_position(esp_ble_audio_media_player_t *player)
{
int err;
if (player == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_media_proxy_ctrl_get_track_position_safe(player);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_media_proxy_ctrl_set_track_position(esp_ble_audio_media_player_t *player,
int32_t position)
{
int err;
if (player == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_media_proxy_ctrl_set_track_position_safe(player, position);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_media_proxy_ctrl_get_playback_speed(esp_ble_audio_media_player_t *player)
{
int err;
if (player == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_media_proxy_ctrl_get_playback_speed_safe(player);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_media_proxy_ctrl_set_playback_speed(esp_ble_audio_media_player_t *player,
int8_t speed)
{
int err;
if (player == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_media_proxy_ctrl_set_playback_speed_safe(player, speed);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_media_proxy_ctrl_get_seeking_speed(esp_ble_audio_media_player_t *player)
{
int err;
if (player == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_media_proxy_ctrl_get_seeking_speed_safe(player);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_media_proxy_ctrl_get_track_segments_id(esp_ble_audio_media_player_t *player)
{
int err;
if (player == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_media_proxy_ctrl_get_track_segments_id_safe(player);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_media_proxy_ctrl_get_current_track_id(esp_ble_audio_media_player_t *player)
{
int err;
if (player == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_media_proxy_ctrl_get_current_track_id_safe(player);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_media_proxy_ctrl_set_current_track_id(esp_ble_audio_media_player_t *player,
uint64_t id)
{
int err;
if (player == NULL || (IS_ENABLED(CONFIG_BT_MCTL_LOCAL_PLAYER_LOCAL_CONTROL) &&
ESP_BLE_AUDIO_MCS_VALID_OBJ_ID(id) == false)) {
return ESP_ERR_INVALID_ARG;
}
err = bt_media_proxy_ctrl_set_current_track_id_safe(player, id);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_media_proxy_ctrl_get_next_track_id(esp_ble_audio_media_player_t *player)
{
int err;
if (player == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_media_proxy_ctrl_get_next_track_id_safe(player);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_media_proxy_ctrl_set_next_track_id(esp_ble_audio_media_player_t *player,
uint64_t id)
{
int err;
if (player == NULL || ESP_BLE_AUDIO_MCS_VALID_OBJ_ID(id) == false) {
return ESP_ERR_INVALID_ARG;
}
err = bt_media_proxy_ctrl_set_next_track_id_safe(player, id);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_media_proxy_ctrl_get_parent_group_id(esp_ble_audio_media_player_t *player)
{
int err;
if (player == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_media_proxy_ctrl_get_parent_group_id_safe(player);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_media_proxy_ctrl_get_current_group_id(esp_ble_audio_media_player_t *player)
{
int err;
if (player == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_media_proxy_ctrl_get_current_group_id_safe(player);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_media_proxy_ctrl_set_current_group_id(esp_ble_audio_media_player_t *player,
uint64_t id)
{
int err;
if (player == NULL || (IS_ENABLED(CONFIG_BT_MCTL_LOCAL_PLAYER_LOCAL_CONTROL) &&
ESP_BLE_AUDIO_MCS_VALID_OBJ_ID(id) == false)) {
return ESP_ERR_INVALID_ARG;
}
err = bt_media_proxy_ctrl_set_current_group_id_safe(player, id);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_media_proxy_ctrl_get_playing_order(esp_ble_audio_media_player_t *player)
{
int err;
if (player == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_media_proxy_ctrl_get_playing_order_safe(player);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_media_proxy_ctrl_set_playing_order(esp_ble_audio_media_player_t *player,
uint8_t order)
{
int err;
if (player == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_media_proxy_ctrl_set_playing_order_safe(player, order);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_media_proxy_ctrl_get_playing_orders_supported(esp_ble_audio_media_player_t *player)
{
int err;
if (player == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_media_proxy_ctrl_get_playing_orders_supported_safe(player);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_media_proxy_ctrl_get_media_state(esp_ble_audio_media_player_t *player)
{
int err;
if (player == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_media_proxy_ctrl_get_media_state_safe(player);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_media_proxy_ctrl_send_command(esp_ble_audio_media_player_t *player,
const esp_ble_audio_mpl_cmd_t *command)
{
int err;
if (player == NULL || command == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_media_proxy_ctrl_send_command_safe(player, command);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_media_proxy_ctrl_get_commands_supported(esp_ble_audio_media_player_t *player)
{
int err;
if (player == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_media_proxy_ctrl_get_commands_supported_safe(player);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_media_proxy_ctrl_send_search(esp_ble_audio_media_player_t *player,
const esp_ble_audio_mpl_search_t *search)
{
int err;
if (player == NULL || search == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_media_proxy_ctrl_send_search_safe(player, search);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_media_proxy_ctrl_get_search_results_id(esp_ble_audio_media_player_t *player)
{
int err;
if (player == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_media_proxy_ctrl_get_search_results_id_safe(player);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_media_proxy_ctrl_get_content_ctrl_id(esp_ble_audio_media_player_t *player)
{
int err;
if (player == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_media_proxy_ctrl_get_content_ctrl_id_safe(player);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
#endif /* CONFIG_BT_MCTL_LOCAL_PLAYER_LOCAL_CONTROL || CONFIG_BT_MCTL_REMOTE_PLAYER_CONTROL */
#if CONFIG_BT_MCTL_LOCAL_PLAYER_CONTROL
static bool pl_calls_is_valid(const esp_ble_audio_media_proxy_pl_calls_t *pl_calls)
{
if (pl_calls == NULL) {
return false;
}
if (pl_calls->get_player_name == NULL ||
pl_calls->get_icon_url == NULL ||
pl_calls->get_track_title == NULL ||
pl_calls->get_track_duration == NULL ||
pl_calls->get_track_position == NULL ||
pl_calls->set_track_position == NULL ||
pl_calls->get_playback_speed == NULL ||
pl_calls->set_playback_speed == NULL ||
pl_calls->get_seeking_speed == NULL ||
pl_calls->get_playing_order == NULL ||
pl_calls->set_playing_order == NULL ||
pl_calls->get_playing_orders_supported == NULL ||
pl_calls->get_media_state == NULL ||
pl_calls->send_command == NULL ||
pl_calls->get_commands_supported == NULL ||
pl_calls->get_content_ctrl_id == NULL) {
return false;
}
#if CONFIG_BT_MPL_OBJECTS
if (pl_calls->get_icon_id == NULL ||
pl_calls->get_track_segments_id == NULL ||
pl_calls->get_current_track_id == NULL ||
pl_calls->set_current_track_id == NULL ||
pl_calls->get_next_track_id == NULL ||
pl_calls->set_next_track_id == NULL ||
pl_calls->get_parent_group_id == NULL ||
pl_calls->get_current_group_id == NULL ||
pl_calls->set_current_group_id == NULL ||
pl_calls->send_search == NULL ||
pl_calls->get_search_results_id == NULL) {
return false;
}
#endif /* CONFIG_BT_MPL_OBJECTS */
return true;
}
esp_err_t esp_ble_audio_media_proxy_pl_register(esp_ble_audio_media_proxy_pl_calls_t *pl_calls)
{
int err;
if (pl_calls_is_valid(pl_calls) == false) {
return ESP_ERR_INVALID_ARG;
}
err = bt_media_proxy_pl_register_safe(pl_calls);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_media_proxy_pl_init(void)
{
int err;
err = bt_media_proxy_pl_init_safe();
if (err) {
return ESP_FAIL;
}
#if CONFIG_BT_MCS && BLE_AUDIO_SVC_SEP_ADD
err = bt_le_media_proxy_pl_init();
if (err) {
return ESP_FAIL;
}
#endif /* CONFIG_BT_MCS && BLE_AUDIO_SVC_SEP_ADD */
return ESP_OK;
}
#endif /* CONFIG_BT_MCTL_LOCAL_PLAYER_CONTROL */
#if CONFIG_BT_MCS && CONFIG_BT_OTS
struct bt_ots *esp_ble_audio_mcs_get_ots(void)
{
return bt_mcs_get_ots_safe();
}
#endif /* CONFIG_BT_MCS && CONFIG_BT_OTS */
@@ -0,0 +1,231 @@
/*
* SPDX-FileCopyrightText: 2020-2024 Nordic Semiconductor ASA
* SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "esp_ble_audio_micp_api.h"
#if CONFIG_BT_MICP_MIC_DEV
esp_err_t esp_ble_audio_micp_mic_dev_register(esp_ble_audio_micp_mic_dev_register_param_t *param)
{
int err;
if (param == NULL ||
(CONFIG_BT_MICP_MIC_DEV_AICS_INSTANCE_COUNT && param->aics_param == NULL)) {
return ESP_ERR_INVALID_ARG;
}
err = bt_micp_mic_dev_register_safe(param);
if (err) {
return ESP_FAIL;
}
#if BLE_AUDIO_SVC_SEP_ADD
err = bt_le_micp_mic_dev_init();
if (err) {
return ESP_FAIL;
}
#endif /* BLE_AUDIO_SVC_SEP_ADD */
return ESP_OK;
}
esp_err_t esp_ble_audio_micp_mic_dev_included_get(esp_ble_audio_micp_included_t *included)
{
int err;
if (included == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_micp_mic_dev_included_get_safe(included);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_micp_mic_dev_unmute(void)
{
int err;
err = bt_micp_mic_dev_unmute_safe();
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_micp_mic_dev_mute(void)
{
int err;
err = bt_micp_mic_dev_mute_safe();
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_micp_mic_dev_mute_disable(void)
{
int err;
err = bt_micp_mic_dev_mute_disable_safe();
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_micp_mic_dev_mute_get(void)
{
int err;
err = bt_micp_mic_dev_mute_get_safe();
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
#endif /* CONFIG_BT_MICP_MIC_DEV */
#if CONFIG_BT_MICP_MIC_CTLR
#if CONFIG_BT_MICP_MIC_CTLR_AICS
esp_err_t esp_ble_audio_micp_mic_ctlr_included_get(esp_ble_audio_micp_mic_ctlr_t *mic_ctlr,
esp_ble_audio_micp_included_t *included)
{
int err;
if (mic_ctlr == NULL || included == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_micp_mic_ctlr_included_get_safe(mic_ctlr, included);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
#endif /* CONFIG_BT_MICP_MIC_CTLR_AICS */
esp_ble_audio_micp_mic_ctlr_t *esp_ble_audio_micp_mic_ctlr_get_by_conn(uint16_t conn_handle)
{
esp_ble_audio_micp_mic_ctlr_t *ret = NULL;
void *conn;
bt_le_host_lock();
conn = bt_le_acl_conn_find(conn_handle);
if (conn == NULL) {
goto unlock;
}
ret = bt_micp_mic_ctlr_get_by_conn(conn);
unlock:
bt_le_host_unlock();
return ret;
}
esp_err_t esp_ble_audio_micp_mic_ctlr_discover(uint16_t conn_handle,
esp_ble_audio_micp_mic_ctlr_t **mic_ctlr)
{
esp_err_t ret = ESP_OK;
void *conn;
int err;
if (mic_ctlr == NULL) {
return ESP_ERR_INVALID_ARG;
}
bt_le_host_lock();
conn = bt_le_acl_conn_find(conn_handle);
if (conn == NULL) {
ret = ESP_ERR_NOT_FOUND;
goto unlock;
}
err = bt_micp_mic_ctlr_discover(conn, mic_ctlr);
if (err) {
ret = ESP_FAIL;
}
unlock:
bt_le_host_unlock();
return ret;
}
esp_err_t esp_ble_audio_micp_mic_ctlr_unmute(esp_ble_audio_micp_mic_ctlr_t *mic_ctlr)
{
int err;
if (mic_ctlr == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_micp_mic_ctlr_unmute_safe(mic_ctlr);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_micp_mic_ctlr_mute(esp_ble_audio_micp_mic_ctlr_t *mic_ctlr)
{
int err;
if (mic_ctlr == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_micp_mic_ctlr_mute_safe(mic_ctlr);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_micp_mic_ctlr_mute_get(esp_ble_audio_micp_mic_ctlr_t *mic_ctlr)
{
int err;
if (mic_ctlr == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_micp_mic_ctlr_mute_get_safe(mic_ctlr);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_micp_mic_ctlr_cb_register(esp_ble_audio_micp_mic_ctlr_cb_t *cb)
{
int err;
if (cb == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_micp_mic_ctlr_cb_register_safe(cb);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
#endif /* CONFIG_BT_MICP_MIC_CTLR */
@@ -0,0 +1,200 @@
/*
* SPDX-FileCopyrightText: 2021 Intel Corporation
* SPDX-FileCopyrightText: 2021-2024 Nordic Semiconductor ASA
* SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "esp_ble_audio_pacs_api.h"
#if CONFIG_BT_PACS
esp_err_t esp_ble_audio_pacs_register(const esp_ble_audio_pacs_register_param_t *param)
{
int err;
if (param == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_pacs_register_safe(param);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_pacs_unregister(void)
{
int err;
err = bt_pacs_unregister_safe();
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
static bool dir_is_valid(esp_ble_audio_dir_t dir)
{
if (dir != ESP_BLE_AUDIO_DIR_SINK &&
dir != ESP_BLE_AUDIO_DIR_SOURCE) {
return false;
}
return true;
}
esp_err_t esp_ble_audio_pacs_cap_register(esp_ble_audio_dir_t dir,
esp_ble_audio_pacs_cap_t *cap)
{
int err;
if (dir_is_valid(dir) == false ||
cap == NULL || cap->codec_cap == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_pacs_cap_register_safe(dir, cap);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_pacs_cap_unregister(esp_ble_audio_dir_t dir,
esp_ble_audio_pacs_cap_t *cap)
{
int err;
if (dir_is_valid(dir) == false || cap == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_pacs_cap_unregister_safe(dir, cap);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_pacs_set_location(esp_ble_audio_dir_t dir,
esp_ble_audio_location_t location)
{
int err;
if (dir_is_valid(dir) == false) {
return ESP_ERR_INVALID_ARG;
}
err = bt_pacs_set_location_safe(dir, location);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_pacs_set_available_contexts(esp_ble_audio_dir_t dir,
esp_ble_audio_context_t contexts)
{
int err;
if (dir_is_valid(dir) == false) {
return ESP_ERR_INVALID_ARG;
}
err = bt_pacs_set_available_contexts_safe(dir, contexts);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_ble_audio_context_t esp_ble_audio_pacs_get_available_contexts(esp_ble_audio_dir_t dir)
{
if (dir_is_valid(dir) == false) {
return ESP_BLE_AUDIO_CONTEXT_TYPE_NONE;
}
return bt_pacs_get_available_contexts_safe(dir);
}
esp_err_t esp_ble_audio_pacs_conn_set_available_contexts_for_conn(uint16_t conn_handle,
esp_ble_audio_dir_t dir,
esp_ble_audio_context_t *contexts)
{
esp_err_t ret = ESP_OK;
void *conn;
int err;
/* Note: contexts could be NULL */
if (dir_is_valid(dir) == false) {
return ESP_ERR_INVALID_ARG;
}
bt_le_host_lock();
conn = bt_le_acl_conn_find(conn_handle);
if (conn == NULL) {
ret = ESP_ERR_NOT_FOUND;
goto unlock;
}
err = bt_pacs_conn_set_available_contexts_for_conn(conn, dir, contexts);
if (err) {
ret = ESP_FAIL;
}
unlock:
bt_le_host_unlock();
return ret;
}
esp_ble_audio_context_t esp_ble_audio_pacs_get_available_contexts_for_conn(uint16_t conn_handle,
esp_ble_audio_dir_t dir)
{
esp_ble_audio_context_t ret = ESP_BLE_AUDIO_CONTEXT_TYPE_NONE;
void *conn;
if (dir_is_valid(dir) == false) {
return ESP_BLE_AUDIO_CONTEXT_TYPE_NONE;
}
bt_le_host_lock();
conn = bt_le_acl_conn_find(conn_handle);
if (conn == NULL) {
goto unlock;
}
ret = bt_pacs_get_available_contexts_for_conn(conn, dir);
unlock:
bt_le_host_unlock();
return ret;
}
esp_err_t esp_ble_audio_pacs_set_supported_contexts(esp_ble_audio_dir_t dir,
esp_ble_audio_context_t contexts)
{
int err;
if (dir_is_valid(dir) == false) {
return ESP_ERR_INVALID_ARG;
}
err = bt_pacs_set_supported_contexts_safe(dir, contexts);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
#endif /* CONFIG_BT_PACS */
@@ -0,0 +1,65 @@
/*
* SPDX-FileCopyrightText: 2023 NXP
* SPDX-FileCopyrightText: 2024 Nordic Semiconductor ASA
* SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "esp_ble_audio_pbp_api.h"
#if CONFIG_BT_PBP
esp_err_t esp_ble_audio_pbp_get_announcement(const uint8_t meta[], size_t meta_len,
esp_ble_audio_pbp_announcement_feature_t features,
struct net_buf_simple *pba_data_buf)
{
int err;
if (pba_data_buf == NULL ||
pba_data_buf->size < (meta_len + ESP_BLE_AUDIO_PBP_MIN_PBA_SIZE)) {
return ESP_ERR_INVALID_ARG;
}
if ((meta == NULL && meta_len != 0) || (meta != NULL && meta_len == 0)) {
return ESP_ERR_INVALID_ARG;
}
err = bt_pbp_get_announcement(meta, meta_len, features, pba_data_buf);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_pbp_parse_announcement(uint8_t data_type, const uint8_t *data, uint8_t data_len,
esp_ble_audio_pbp_announcement_feature_t *features,
uint8_t **meta, uint8_t *meta_len)
{
struct bt_data ad = {
.type = data_type,
.data = data,
.data_len = data_len,
};
int ret;
if (data == NULL || data_len == 0 || features == NULL ||
meta == NULL || meta_len == NULL) {
return ESP_ERR_INVALID_ARG;
}
if (data_type != BT_DATA_SVC_DATA16 ||
data_len < ESP_BLE_AUDIO_PBP_MIN_PBA_SIZE) {
return ESP_ERR_INVALID_ARG;
}
ret = bt_pbp_parse_announcement(&ad, features, meta);
if (ret < 0) {
return ESP_FAIL;
}
*meta_len = ret;
return ESP_OK;
}
#endif /* CONFIG_BT_PBP */
@@ -0,0 +1,997 @@
/*
* SPDX-FileCopyrightText: 2020 Bose Corporation
* SPDX-FileCopyrightText: 2021 Nordic Semiconductor ASA
* SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "esp_ble_audio_tbs_api.h"
#if CONFIG_BT_TBS
esp_err_t esp_ble_audio_tbs_accept(uint8_t call_index)
{
int err;
err = bt_tbs_accept_safe(call_index);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_tbs_hold(uint8_t call_index)
{
int err;
err = bt_tbs_hold_safe(call_index);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_tbs_retrieve(uint8_t call_index)
{
int err;
err = bt_tbs_retrieve_safe(call_index);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_tbs_terminate(uint8_t call_index)
{
int err;
err = bt_tbs_terminate_safe(call_index);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_tbs_originate(uint8_t bearer_index,
char *uri,
uint8_t *call_index)
{
int err;
if (uri == NULL || call_index == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_tbs_originate_safe(bearer_index, uri, call_index);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_tbs_join(uint8_t call_index_cnt, uint8_t *call_indexes)
{
int err;
if (call_index_cnt == 0 || call_indexes == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_tbs_join_safe(call_index_cnt, call_indexes);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_tbs_remote_answer(uint8_t call_index)
{
int err;
err = bt_tbs_remote_answer_safe(call_index);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_tbs_remote_hold(uint8_t call_index)
{
int err;
err = bt_tbs_remote_hold_safe(call_index);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_tbs_remote_retrieve(uint8_t call_index)
{
int err;
err = bt_tbs_remote_retrieve_safe(call_index);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_tbs_remote_terminate(uint8_t call_index)
{
int err;
err = bt_tbs_remote_terminate_safe(call_index);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_tbs_remote_incoming(uint8_t bearer_index,
const char *to,
const char *from,
const char *friendly_name,
uint8_t *call_index)
{
int ret;
if (to == NULL || from == NULL ||
friendly_name == NULL || call_index == NULL) {
return ESP_ERR_INVALID_ARG;
}
ret = bt_tbs_remote_incoming_safe(bearer_index, to, from, friendly_name);
if (ret < 0) {
return ESP_FAIL;
}
*call_index = ret;
return ESP_OK;
}
esp_err_t esp_ble_audio_tbs_set_bearer_provider_name(uint8_t bearer_index, const char *name)
{
int err;
if (name == NULL || strlen(name) == 0 ||
strlen(name) >= CONFIG_BT_TBS_MAX_PROVIDER_NAME_LENGTH) {
return ESP_ERR_INVALID_ARG;
}
err = bt_tbs_set_bearer_provider_name_safe(bearer_index, name);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_tbs_set_bearer_technology(uint8_t bearer_index, uint8_t new_technology)
{
int err;
if (new_technology < ESP_BLE_AUDIO_TBS_TECHNOLOGY_3G ||
new_technology > ESP_BLE_AUDIO_TBS_TECHNOLOGY_WCDMA) {
return ESP_ERR_INVALID_ARG;
}
err = bt_tbs_set_bearer_technology_safe(bearer_index, new_technology);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_tbs_set_signal_strength(uint8_t bearer_index, uint8_t new_signal_strength)
{
int err;
if (new_signal_strength > ESP_BLE_AUDIO_TBS_SIGNAL_STRENGTH_MAX &&
new_signal_strength != ESP_BLE_AUDIO_TBS_SIGNAL_STRENGTH_UNKNOWN) {
return ESP_ERR_INVALID_ARG;
}
err = bt_tbs_set_signal_strength_safe(bearer_index, new_signal_strength);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
#define TBS_VALID_STATUS_FLAGS(val) ((val) <= (BIT(0) | BIT(1)))
esp_err_t esp_ble_audio_tbs_set_status_flags(uint8_t bearer_index, uint16_t status_flags)
{
int err;
if (TBS_VALID_STATUS_FLAGS(status_flags) == false) {
return ESP_ERR_INVALID_ARG;
}
err = bt_tbs_set_status_flags_safe(bearer_index, status_flags);
if (err) {
return ESP_FAIL;
}
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)
{
uint8_t count = CONFIG_BT_TBS_BEARER_COUNT;
int err;
if (count == 0 || bearer_index >= count ||
(uri_count && uri_list == NULL)) {
return ESP_ERR_INVALID_ARG;
}
err = bt_tbs_set_uri_scheme_list_safe(bearer_index, uri_list, uri_count);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
void esp_ble_audio_tbs_register_cb(esp_ble_audio_tbs_cb_t *cbs)
{
bt_tbs_register_cb_safe(cbs);
}
static bool valid_register_param(const esp_ble_audio_tbs_register_param_t *param)
{
if (param == NULL) {
return false;
}
if (param->provider_name == NULL) {
return false;
}
if (strlen(param->provider_name) == 0 ||
strlen(param->provider_name) >= CONFIG_BT_TBS_MAX_PROVIDER_NAME_LENGTH) {
/* Provider name empty or length not less than CONFIG_BT_TBS_MAX_PROVIDER_NAME_LENGTH */
return false;
}
if (param->uci == NULL) {
return false;
}
if (param->uri_schemes_supported == NULL) {
return false;
}
if (IN_RANGE(param->technology,
ESP_BLE_AUDIO_TBS_TECHNOLOGY_3G,
ESP_BLE_AUDIO_TBS_TECHNOLOGY_WCDMA) == false) {
return false;
}
if (param->supported_features > ESP_BLE_AUDIO_TBS_FEATURE_ALL) {
return false;
}
if (CONFIG_BT_TBS_BEARER_COUNT == 0 && param->gtbs == false) {
return false;
}
return true;
}
esp_err_t esp_ble_audio_tbs_register_bearer(const esp_ble_audio_tbs_register_param_t *param,
uint8_t *bearer_index)
{
int ret;
if (param == NULL || valid_register_param(param) == false || bearer_index == NULL) {
return ESP_ERR_INVALID_ARG;
}
/* Note: currently only GTBS is supported */
if (param->gtbs == false) {
return ESP_ERR_INVALID_ARG;
}
ret = bt_tbs_register_bearer_safe(param);
if (ret < 0) {
return ESP_FAIL;
}
*bearer_index = ret;
#if BLE_AUDIO_SVC_SEP_ADD
if (bt_le_gtbs_init()) {
bt_tbs_unregister_bearer_safe(*bearer_index);
return ESP_FAIL;
}
#endif /* BLE_AUDIO_SVC_SEP_ADD */
return ESP_OK;
}
esp_err_t esp_ble_audio_tbs_unregister_bearer(uint8_t bearer_index)
{
int err;
err = bt_tbs_unregister_bearer_safe(bearer_index);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
#endif /* CONFIG_BT_TBS */
#if CONFIG_BT_TBS_CLIENT
esp_err_t esp_ble_audio_tbs_client_discover(uint16_t conn_handle)
{
esp_err_t ret = ESP_OK;
void *conn;
int err;
bt_le_host_lock();
conn = bt_le_acl_conn_find(conn_handle);
if (conn == NULL) {
ret = ESP_ERR_NOT_FOUND;
goto unlock;
}
err = bt_tbs_client_discover(conn);
if (err) {
ret = ESP_FAIL;
}
unlock:
bt_le_host_unlock();
return ret;
}
#if CONFIG_BT_TBS_CLIENT_SET_BEARER_SIGNAL_INTERVAL
esp_err_t esp_ble_audio_tbs_client_set_signal_strength_interval(uint16_t conn_handle,
uint8_t inst_index,
uint8_t interval)
{
esp_err_t ret = ESP_OK;
void *conn;
int err;
bt_le_host_lock();
conn = bt_le_acl_conn_find(conn_handle);
if (conn == NULL) {
ret = ESP_ERR_NOT_FOUND;
goto unlock;
}
err = bt_tbs_client_set_signal_strength_interval(conn, inst_index, interval);
if (err) {
ret = ESP_FAIL;
}
unlock:
bt_le_host_unlock();
return ret;
}
#endif /* CONFIG_BT_TBS_CLIENT_SET_BEARER_SIGNAL_INTERVAL */
#if CONFIG_BT_TBS_CLIENT_ORIGINATE_CALL
#define TBS_MIN_URI_LEN 3 /* a:b */
#define FIRST_PRINTABLE_ASCII_CHAR ' ' /* space */
static inline bool tbs_valid_uri(const uint8_t *uri, size_t uri_len)
{
if (uri_len > CONFIG_BT_TBS_MAX_URI_LENGTH || uri_len < TBS_MIN_URI_LEN) {
return false;
}
if (uri[0] < FIRST_PRINTABLE_ASCII_CHAR) {
/* Invalid first char */
return false;
}
for (size_t i = 1; i < uri_len; i++) {
if (uri[i] == ':' && uri[i + 1] >= FIRST_PRINTABLE_ASCII_CHAR) {
return true;
}
}
return false;
}
esp_err_t esp_ble_audio_tbs_client_originate_call(uint16_t conn_handle,
uint8_t inst_index,
const char *uri)
{
esp_err_t ret = ESP_OK;
void *conn;
int err;
if (uri == NULL ||
tbs_valid_uri((const uint8_t *)uri, strlen(uri)) == false) {
return ESP_ERR_INVALID_ARG;
}
bt_le_host_lock();
conn = bt_le_acl_conn_find(conn_handle);
if (conn == NULL) {
ret = ESP_ERR_NOT_FOUND;
goto unlock;
}
err = bt_tbs_client_originate_call(conn, inst_index, uri);
if (err) {
ret = ESP_FAIL;
}
unlock:
bt_le_host_unlock();
return ret;
}
#endif /* CONFIG_BT_TBS_CLIENT_ORIGINATE_CALL */
#if CONFIG_BT_TBS_CLIENT_TERMINATE_CALL
esp_err_t esp_ble_audio_tbs_client_terminate_call(uint16_t conn_handle,
uint8_t inst_index,
uint8_t call_index)
{
esp_err_t ret = ESP_OK;
void *conn;
int err;
bt_le_host_lock();
conn = bt_le_acl_conn_find(conn_handle);
if (conn == NULL) {
ret = ESP_ERR_NOT_FOUND;
goto unlock;
}
err = bt_tbs_client_terminate_call(conn, inst_index, call_index);
if (err) {
ret = ESP_FAIL;
}
unlock:
bt_le_host_unlock();
return ret;
}
#endif /* CONFIG_BT_TBS_CLIENT_TERMINATE_CALL */
#if CONFIG_BT_TBS_CLIENT_HOLD_CALL
esp_err_t esp_ble_audio_tbs_client_hold_call(uint16_t conn_handle,
uint8_t inst_index,
uint8_t call_index)
{
esp_err_t ret = ESP_OK;
void *conn;
int err;
bt_le_host_lock();
conn = bt_le_acl_conn_find(conn_handle);
if (conn == NULL) {
ret = ESP_ERR_NOT_FOUND;
goto unlock;
}
err = bt_tbs_client_hold_call(conn, inst_index, call_index);
if (err) {
ret = ESP_FAIL;
}
unlock:
bt_le_host_unlock();
return ret;
}
#endif /* CONFIG_BT_TBS_CLIENT_HOLD_CALL */
#if CONFIG_BT_TBS_CLIENT_ACCEPT_CALL
esp_err_t esp_ble_audio_tbs_client_accept_call(uint16_t conn_handle,
uint8_t inst_index,
uint8_t call_index)
{
esp_err_t ret = ESP_OK;
void *conn;
int err;
bt_le_host_lock();
conn = bt_le_acl_conn_find(conn_handle);
if (conn == NULL) {
ret = ESP_ERR_NOT_FOUND;
goto unlock;
}
err = bt_tbs_client_accept_call(conn, inst_index, call_index);
if (err) {
ret = ESP_FAIL;
}
unlock:
bt_le_host_unlock();
return ret;
}
#endif /* CONFIG_BT_TBS_CLIENT_ACCEPT_CALL */
#if CONFIG_BT_TBS_CLIENT_RETRIEVE_CALL
esp_err_t esp_ble_audio_tbs_client_retrieve_call(uint16_t conn_handle,
uint8_t inst_index,
uint8_t call_index)
{
esp_err_t ret = ESP_OK;
void *conn;
int err;
bt_le_host_lock();
conn = bt_le_acl_conn_find(conn_handle);
if (conn == NULL) {
ret = ESP_ERR_NOT_FOUND;
goto unlock;
}
err = bt_tbs_client_retrieve_call(conn, inst_index, call_index);
if (err) {
ret = ESP_FAIL;
}
unlock:
bt_le_host_unlock();
return ret;
}
#endif /* CONFIG_BT_TBS_CLIENT_RETRIEVE_CALL */
#if CONFIG_BT_TBS_CLIENT_JOIN_CALLS
esp_err_t esp_ble_audio_tbs_client_join_calls(uint16_t conn_handle,
uint8_t inst_index,
const uint8_t *call_indexes,
uint8_t count)
{
esp_err_t ret = ESP_OK;
void *conn;
int err;
if (call_indexes == NULL ||
count < 2 || count > CONFIG_BT_TBS_CLIENT_MAX_CALLS) {
return ESP_ERR_INVALID_ARG;
}
bt_le_host_lock();
conn = bt_le_acl_conn_find(conn_handle);
if (conn == NULL) {
ret = ESP_ERR_NOT_FOUND;
goto unlock;
}
err = bt_tbs_client_join_calls(conn, inst_index, call_indexes, count);
if (err) {
ret = ESP_FAIL;
}
unlock:
bt_le_host_unlock();
return ret;
}
#endif /* CONFIG_BT_TBS_CLIENT_JOIN_CALLS */
#if CONFIG_BT_TBS_CLIENT_BEARER_PROVIDER_NAME
esp_err_t esp_ble_audio_tbs_client_read_bearer_provider_name(uint16_t conn_handle, uint8_t inst_index)
{
esp_err_t ret = ESP_OK;
void *conn;
int err;
bt_le_host_lock();
conn = bt_le_acl_conn_find(conn_handle);
if (conn == NULL) {
ret = ESP_ERR_NOT_FOUND;
goto unlock;
}
err = bt_tbs_client_read_bearer_provider_name(conn, inst_index);
if (err) {
ret = ESP_FAIL;
}
unlock:
bt_le_host_unlock();
return ret;
}
#endif /* CONFIG_BT_TBS_CLIENT_BEARER_PROVIDER_NAME */
#if CONFIG_BT_TBS_CLIENT_BEARER_UCI
esp_err_t esp_ble_audio_tbs_client_read_bearer_uci(uint16_t conn_handle, uint8_t inst_index)
{
esp_err_t ret = ESP_OK;
void *conn;
int err;
bt_le_host_lock();
conn = bt_le_acl_conn_find(conn_handle);
if (conn == NULL) {
ret = ESP_ERR_NOT_FOUND;
goto unlock;
}
err = bt_tbs_client_read_bearer_uci(conn, inst_index);
if (err) {
ret = ESP_FAIL;
}
unlock:
bt_le_host_unlock();
return ret;
}
#endif /* CONFIG_BT_TBS_CLIENT_BEARER_UCI */
#if CONFIG_BT_TBS_CLIENT_BEARER_TECHNOLOGY
esp_err_t esp_ble_audio_tbs_client_read_technology(uint16_t conn_handle, uint8_t inst_index)
{
esp_err_t ret = ESP_OK;
void *conn;
int err;
bt_le_host_lock();
conn = bt_le_acl_conn_find(conn_handle);
if (conn == NULL) {
ret = ESP_ERR_NOT_FOUND;
goto unlock;
}
err = bt_tbs_client_read_technology(conn, inst_index);
if (err) {
ret = ESP_FAIL;
}
unlock:
bt_le_host_unlock();
return ret;
}
#endif /* CONFIG_BT_TBS_CLIENT_BEARER_TECHNOLOGY */
#if CONFIG_BT_TBS_CLIENT_BEARER_URI_SCHEMES_SUPPORTED_LIST
esp_err_t esp_ble_audio_tbs_client_read_uri_list(uint16_t conn_handle, uint8_t inst_index)
{
esp_err_t ret = ESP_OK;
void *conn;
int err;
bt_le_host_lock();
conn = bt_le_acl_conn_find(conn_handle);
if (conn == NULL) {
ret = ESP_ERR_NOT_FOUND;
goto unlock;
}
err = bt_tbs_client_read_uri_list(conn, inst_index);
if (err) {
ret = ESP_FAIL;
}
unlock:
bt_le_host_unlock();
return ret;
}
#endif /* CONFIG_BT_TBS_CLIENT_BEARER_URI_SCHEMES_SUPPORTED_LIST */
#if CONFIG_BT_TBS_CLIENT_BEARER_SIGNAL_STRENGTH
esp_err_t esp_ble_audio_tbs_client_read_signal_strength(uint16_t conn_handle, uint8_t inst_index)
{
esp_err_t ret = ESP_OK;
void *conn;
int err;
bt_le_host_lock();
conn = bt_le_acl_conn_find(conn_handle);
if (conn == NULL) {
ret = ESP_ERR_NOT_FOUND;
goto unlock;
}
err = bt_tbs_client_read_signal_strength(conn, inst_index);
if (err) {
ret = ESP_FAIL;
}
unlock:
bt_le_host_unlock();
return ret;
}
#endif /* CONFIG_BT_TBS_CLIENT_BEARER_SIGNAL_STRENGTH */
#if CONFIG_BT_TBS_CLIENT_READ_BEARER_SIGNAL_INTERVAL
esp_err_t esp_ble_audio_tbs_client_read_signal_interval(uint16_t conn_handle, uint8_t inst_index)
{
esp_err_t ret = ESP_OK;
void *conn;
int err;
bt_le_host_lock();
conn = bt_le_acl_conn_find(conn_handle);
if (conn == NULL) {
ret = ESP_ERR_NOT_FOUND;
goto unlock;
}
err = bt_tbs_client_read_signal_interval(conn, inst_index);
if (err) {
ret = ESP_FAIL;
}
unlock:
bt_le_host_unlock();
return ret;
}
#endif /* CONFIG_BT_TBS_CLIENT_READ_BEARER_SIGNAL_INTERVAL */
#if CONFIG_BT_TBS_CLIENT_BEARER_LIST_CURRENT_CALLS
esp_err_t esp_ble_audio_tbs_client_read_current_calls(uint16_t conn_handle, uint8_t inst_index)
{
esp_err_t ret = ESP_OK;
void *conn;
int err;
bt_le_host_lock();
conn = bt_le_acl_conn_find(conn_handle);
if (conn == NULL) {
ret = ESP_ERR_NOT_FOUND;
goto unlock;
}
err = bt_tbs_client_read_current_calls(conn, inst_index);
if (err) {
ret = ESP_FAIL;
}
unlock:
bt_le_host_unlock();
return ret;
}
#endif /* CONFIG_BT_TBS_CLIENT_BEARER_LIST_CURRENT_CALLS */
#if CONFIG_BT_TBS_CLIENT_CCID
esp_err_t esp_ble_audio_tbs_client_read_ccid(uint16_t conn_handle, uint8_t inst_index)
{
esp_err_t ret = ESP_OK;
void *conn;
int err;
bt_le_host_lock();
conn = bt_le_acl_conn_find(conn_handle);
if (conn == NULL) {
ret = ESP_ERR_NOT_FOUND;
goto unlock;
}
err = bt_tbs_client_read_ccid(conn, inst_index);
if (err) {
ret = ESP_FAIL;
}
unlock:
bt_le_host_unlock();
return ret;
}
#endif /* CONFIG_BT_TBS_CLIENT_CCID */
#if CONFIG_BT_TBS_CLIENT_INCOMING_URI
esp_err_t esp_ble_audio_tbs_client_read_call_uri(uint16_t conn_handle, uint8_t inst_index)
{
esp_err_t ret = ESP_OK;
void *conn;
int err;
bt_le_host_lock();
conn = bt_le_acl_conn_find(conn_handle);
if (conn == NULL) {
ret = ESP_ERR_NOT_FOUND;
goto unlock;
}
err = bt_tbs_client_read_call_uri(conn, inst_index);
if (err) {
ret = ESP_FAIL;
}
unlock:
bt_le_host_unlock();
return ret;
}
#endif /* CONFIG_BT_TBS_CLIENT_INCOMING_URI */
#if CONFIG_BT_TBS_CLIENT_STATUS_FLAGS
esp_err_t esp_ble_audio_tbs_client_read_status_flags(uint16_t conn_handle, uint8_t inst_index)
{
esp_err_t ret = ESP_OK;
void *conn;
int err;
bt_le_host_lock();
conn = bt_le_acl_conn_find(conn_handle);
if (conn == NULL) {
ret = ESP_ERR_NOT_FOUND;
goto unlock;
}
err = bt_tbs_client_read_status_flags(conn, inst_index);
if (err) {
ret = ESP_FAIL;
}
unlock:
bt_le_host_unlock();
return ret;
}
#endif /* CONFIG_BT_TBS_CLIENT_STATUS_FLAGS */
esp_err_t esp_ble_audio_tbs_client_read_call_state(uint16_t conn_handle, uint8_t inst_index)
{
esp_err_t ret = ESP_OK;
void *conn;
int err;
bt_le_host_lock();
conn = bt_le_acl_conn_find(conn_handle);
if (conn == NULL) {
ret = ESP_ERR_NOT_FOUND;
goto unlock;
}
err = bt_tbs_client_read_call_state(conn, inst_index);
if (err) {
ret = ESP_FAIL;
}
unlock:
bt_le_host_unlock();
return ret;
}
#if CONFIG_BT_TBS_CLIENT_INCOMING_CALL
esp_err_t esp_ble_audio_tbs_client_read_remote_uri(uint16_t conn_handle, uint8_t inst_index)
{
esp_err_t ret = ESP_OK;
void *conn;
int err;
bt_le_host_lock();
conn = bt_le_acl_conn_find(conn_handle);
if (conn == NULL) {
ret = ESP_ERR_NOT_FOUND;
goto unlock;
}
err = bt_tbs_client_read_remote_uri(conn, inst_index);
if (err) {
ret = ESP_FAIL;
}
unlock:
bt_le_host_unlock();
return ret;
}
#endif /* CONFIG_BT_TBS_CLIENT_INCOMING_CALL */
#if CONFIG_BT_TBS_CLIENT_CALL_FRIENDLY_NAME
esp_err_t esp_ble_audio_tbs_client_read_friendly_name(uint16_t conn_handle, uint8_t inst_index)
{
esp_err_t ret = ESP_OK;
void *conn;
int err;
bt_le_host_lock();
conn = bt_le_acl_conn_find(conn_handle);
if (conn == NULL) {
ret = ESP_ERR_NOT_FOUND;
goto unlock;
}
err = bt_tbs_client_read_friendly_name(conn, inst_index);
if (err) {
ret = ESP_FAIL;
}
unlock:
bt_le_host_unlock();
return ret;
}
#endif /* CONFIG_BT_TBS_CLIENT_CALL_FRIENDLY_NAME */
#if CONFIG_BT_TBS_CLIENT_OPTIONAL_OPCODES
esp_err_t esp_ble_audio_tbs_client_read_optional_opcodes(uint16_t conn_handle, uint8_t inst_index)
{
esp_err_t ret = ESP_OK;
void *conn;
int err;
bt_le_host_lock();
conn = bt_le_acl_conn_find(conn_handle);
if (conn == NULL) {
ret = ESP_ERR_NOT_FOUND;
goto unlock;
}
err = bt_tbs_client_read_optional_opcodes(conn, inst_index);
if (err) {
ret = ESP_FAIL;
}
unlock:
bt_le_host_unlock();
return ret;
}
#endif /* CONFIG_BT_TBS_CLIENT_OPTIONAL_OPCODES */
esp_err_t esp_ble_audio_tbs_client_register_cb(esp_ble_audio_tbs_client_cb_t *cbs)
{
int err;
if (cbs == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_tbs_client_register_cb_safe(cbs);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
#if CONFIG_BT_TBS_CLIENT_CCID
esp_ble_audio_tbs_instance_t *esp_ble_audio_tbs_client_get_by_ccid(uint16_t conn_handle, uint8_t ccid)
{
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_ccid(conn, ccid);
unlock:
bt_le_host_unlock();
return ret;
}
#endif /* CONFIG_BT_TBS_CLIENT_CCID */
#endif /* CONFIG_BT_TBS_CLIENT */
@@ -0,0 +1,60 @@
/*
* SPDX-FileCopyrightText: 2023 NXP
* SPDX-FileCopyrightText: 2024 Nordic Semiconductor ASA
* SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "esp_ble_audio_tmap_api.h"
#if CONFIG_BT_TMAP
esp_err_t esp_ble_audio_tmap_register(esp_ble_audio_tmap_role_t role)
{
int err;
err = bt_tmap_register_safe(role);
if (err) {
return ESP_FAIL;
}
#if BLE_AUDIO_SVC_SEP_ADD
err = bt_le_tmas_init();
if (err) {
return ESP_FAIL;
}
#endif /* BLE_AUDIO_SVC_SEP_ADD */
return ESP_OK;
}
esp_err_t esp_ble_audio_tmap_discover(uint16_t conn_handle,
const esp_ble_audio_tmap_cb_t *tmap_cb)
{
esp_err_t ret = ESP_OK;
void *conn;
int err;
bt_le_host_lock();
conn = bt_le_acl_conn_find(conn_handle);
if (conn == NULL) {
ret = ESP_ERR_NOT_FOUND;
goto unlock;
}
err = bt_tmap_discover(conn, tmap_cb);
if (err) {
ret = ESP_FAIL;
}
unlock:
bt_le_host_unlock();
return ret;
}
void esp_ble_audio_tmap_set_role(esp_ble_audio_tmap_role_t role)
{
bt_tmap_set_role_safe(role);
}
#endif /* CONFIG_BT_TMAP */
@@ -0,0 +1,430 @@
/*
* SPDX-FileCopyrightText: 2020-2024 Nordic Semiconductor ASA
* SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "esp_ble_audio_vcp_api.h"
#if CONFIG_BT_VCP_VOL_REND
esp_err_t esp_ble_audio_vcp_vol_rend_included_get(esp_ble_audio_vcp_included_t *included)
{
int err;
if (included == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_vcp_vol_rend_included_get_safe(included);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_vcp_vol_rend_register(esp_ble_audio_vcp_vol_rend_register_param_t *param)
{
int err;
if (param == NULL) {
return ESP_ERR_INVALID_ARG;
}
if (CONFIG_BT_VCP_VOL_REND_VOCS_INSTANCE_COUNT && param->vocs_param == NULL) {
return ESP_ERR_INVALID_ARG;
}
if (CONFIG_BT_VCP_VOL_REND_AICS_INSTANCE_COUNT && param->aics_param == NULL) {
return ESP_ERR_INVALID_ARG;
}
if (param->mute > ESP_BLE_AUDIO_VCP_STATE_MUTED || param->step == 0) {
return ESP_ERR_INVALID_ARG;
}
err = bt_vcp_vol_rend_register_safe(param);
if (err) {
return ESP_FAIL;
}
#if BLE_AUDIO_SVC_SEP_ADD
err = bt_le_vcp_vol_rend_init();
if (err) {
return ESP_FAIL;
}
#endif /* BLE_AUDIO_SVC_SEP_ADD */
return ESP_OK;
}
esp_err_t esp_ble_audio_vcp_vol_rend_set_step(uint8_t volume_step)
{
int err;
if (volume_step == 0) {
return ESP_ERR_INVALID_ARG;
}
err = bt_vcp_vol_rend_set_step_safe(volume_step);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_vcp_vol_rend_get_state(void)
{
int err;
err = bt_vcp_vol_rend_get_state_safe();
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_vcp_vol_rend_get_flags(void)
{
int err;
err = bt_vcp_vol_rend_get_flags_safe();
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_vcp_vol_rend_vol_down(void)
{
int err;
err = bt_vcp_vol_rend_vol_down_safe();
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_vcp_vol_rend_vol_up(void)
{
int err;
err = bt_vcp_vol_rend_vol_up_safe();
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_vcp_vol_rend_unmute_vol_down(void)
{
int err;
err = bt_vcp_vol_rend_unmute_vol_down_safe();
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_vcp_vol_rend_unmute_vol_up(void)
{
int err;
err = bt_vcp_vol_rend_unmute_vol_up_safe();
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_vcp_vol_rend_set_vol(uint8_t volume)
{
int err;
err = bt_vcp_vol_rend_set_vol_safe(volume);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_vcp_vol_rend_unmute(void)
{
int err;
err = bt_vcp_vol_rend_unmute_safe();
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_vcp_vol_rend_mute(void)
{
int err;
err = bt_vcp_vol_rend_mute_safe();
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
#endif /* CONFIG_BT_VCP_VOL_REND */
#if CONFIG_BT_VCP_VOL_CTLR
esp_err_t esp_ble_audio_vcp_vol_ctlr_cb_register(esp_ble_audio_vcp_vol_ctlr_cb_t *cb)
{
int err;
if (cb == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_vcp_vol_ctlr_cb_register_safe(cb);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_vcp_vol_ctlr_cb_unregister(esp_ble_audio_vcp_vol_ctlr_cb_t *cb)
{
int err;
if (cb == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_vcp_vol_ctlr_cb_unregister_safe(cb);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_vcp_vol_ctlr_discover(uint16_t conn_handle,
esp_ble_audio_vcp_vol_ctlr_t **vol_ctlr)
{
esp_err_t ret = ESP_OK;
void *conn;
int err;
if (vol_ctlr == NULL) {
return ESP_ERR_INVALID_ARG;
}
bt_le_host_lock();
conn = bt_le_acl_conn_find(conn_handle);
if (conn == NULL) {
ret = ESP_ERR_NOT_FOUND;
goto unlock;
}
err = bt_vcp_vol_ctlr_discover(conn, vol_ctlr);
if (err) {
ret = ESP_FAIL;
}
unlock:
bt_le_host_unlock();
return ret;
}
esp_ble_audio_vcp_vol_ctlr_t *esp_ble_audio_vcp_vol_ctlr_get_by_conn(uint16_t conn_handle)
{
esp_ble_audio_vcp_vol_ctlr_t *ret = NULL;
void *conn;
bt_le_host_lock();
conn = bt_le_acl_conn_find(conn_handle);
if (conn == NULL) {
goto unlock;
}
ret = bt_vcp_vol_ctlr_get_by_conn(conn);
unlock:
bt_le_host_unlock();
return ret;
}
#if CONFIG_BT_VCP_VOL_CTLR_VOCS || CONFIG_BT_VCP_VOL_CTLR_AICS
esp_err_t esp_ble_audio_vcp_vol_ctlr_included_get(esp_ble_audio_vcp_vol_ctlr_t *vol_ctlr,
esp_ble_audio_vcp_included_t *included)
{
int err;
if (vol_ctlr == NULL || included == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_vcp_vol_ctlr_included_get_safe(vol_ctlr, included);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
#endif /* CONFIG_BT_VCP_VOL_CTLR_VOCS || CONFIG_BT_VCP_VOL_CTLR_AICS */
esp_err_t esp_ble_audio_vcp_vol_ctlr_read_state(esp_ble_audio_vcp_vol_ctlr_t *vol_ctlr)
{
int err;
if (vol_ctlr == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_vcp_vol_ctlr_read_state_safe(vol_ctlr);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_vcp_vol_ctlr_read_flags(esp_ble_audio_vcp_vol_ctlr_t *vol_ctlr)
{
int err;
if (vol_ctlr == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_vcp_vol_ctlr_read_flags_safe(vol_ctlr);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_vcp_vol_ctlr_vol_down(esp_ble_audio_vcp_vol_ctlr_t *vol_ctlr)
{
int err;
if (vol_ctlr == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_vcp_vol_ctlr_vol_down_safe(vol_ctlr);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_vcp_vol_ctlr_vol_up(esp_ble_audio_vcp_vol_ctlr_t *vol_ctlr)
{
int err;
if (vol_ctlr == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_vcp_vol_ctlr_vol_up_safe(vol_ctlr);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_vcp_vol_ctlr_unmute_vol_down(esp_ble_audio_vcp_vol_ctlr_t *vol_ctlr)
{
int err;
if (vol_ctlr == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_vcp_vol_ctlr_unmute_vol_down_safe(vol_ctlr);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_vcp_vol_ctlr_unmute_vol_up(esp_ble_audio_vcp_vol_ctlr_t *vol_ctlr)
{
int err;
if (vol_ctlr == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_vcp_vol_ctlr_unmute_vol_up_safe(vol_ctlr);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_vcp_vol_ctlr_set_vol(esp_ble_audio_vcp_vol_ctlr_t *vol_ctlr, uint8_t volume)
{
int err;
if (vol_ctlr == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_vcp_vol_ctlr_set_vol_safe(vol_ctlr, volume);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_vcp_vol_ctlr_unmute(esp_ble_audio_vcp_vol_ctlr_t *vol_ctlr)
{
int err;
if (vol_ctlr == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_vcp_vol_ctlr_unmute_safe(vol_ctlr);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_vcp_vol_ctlr_mute(esp_ble_audio_vcp_vol_ctlr_t *vol_ctlr)
{
int err;
if (vol_ctlr == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_vcp_vol_ctlr_mute_safe(vol_ctlr);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
#endif /* CONFIG_BT_VCP_VOL_CTLR */
@@ -0,0 +1,198 @@
/*
* SPDX-FileCopyrightText: 2020-2024 Nordic Semiconductor ASA
* SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "esp_ble_audio_vocs_api.h"
#if CONFIG_BT_VOCS
esp_ble_audio_vocs_t *esp_ble_audio_vocs_free_instance_get(void)
{
return bt_vocs_free_instance_get_safe();
}
void *esp_ble_audio_vocs_svc_decl_get(esp_ble_audio_vocs_t *vocs)
{
if (vocs == NULL) {
return NULL;
}
return bt_vocs_svc_decl_get_safe(vocs);
}
esp_err_t esp_ble_audio_vocs_register(esp_ble_audio_vocs_t *vocs,
const esp_ble_audio_vocs_register_param_t *param)
{
int err;
if (vocs == NULL || param == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_vocs_register_safe(vocs, param);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
#endif /* CONFIG_BT_VOCS */
#if CONFIG_BT_VOCS || CONFIG_BT_VOCS_CLIENT
esp_err_t esp_ble_audio_vocs_state_get(esp_ble_audio_vocs_t *inst)
{
int err;
if (inst == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_vocs_state_get_safe(inst);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_vocs_state_set(esp_ble_audio_vocs_t *inst, int16_t offset)
{
int err;
if (inst == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_vocs_state_set_safe(inst, offset);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_vocs_location_get(esp_ble_audio_vocs_t *inst)
{
int err;
if (inst == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_vocs_location_get_safe(inst);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_vocs_location_set(esp_ble_audio_vocs_t *inst, uint32_t location)
{
int err;
if (inst == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_vocs_location_set_safe(inst, location);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_vocs_description_get(esp_ble_audio_vocs_t *inst)
{
int err;
if (inst == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_vocs_description_get_safe(inst);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_audio_vocs_description_set(esp_ble_audio_vocs_t *inst,
const char *description)
{
int err;
if (inst == NULL || description == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_vocs_description_set_safe(inst, description);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
#endif /* CONFIG_BT_VOCS || CONFIG_BT_VOCS_CLIENT */
#if CONFIG_BT_VOCS_CLIENT
esp_err_t esp_ble_audio_vocs_client_cb_register(esp_ble_audio_vocs_t *inst,
esp_ble_audio_vocs_cb_t *cb)
{
if (inst == NULL) {
return ESP_ERR_INVALID_ARG;
}
bt_vocs_client_cb_register_safe(inst, cb);
return ESP_OK;
}
esp_ble_audio_vocs_t *esp_ble_audio_vocs_client_free_instance_get(void)
{
return bt_vocs_client_free_instance_get_safe();
}
esp_err_t esp_ble_audio_vocs_discover(uint16_t conn_handle,
esp_ble_audio_vocs_t *inst,
const esp_ble_audio_vocs_discover_param_t *param)
{
esp_err_t ret = ESP_OK;
void *conn;
int err;
if (inst == NULL || param == NULL) {
return ESP_ERR_INVALID_ARG;
}
if (param->start_handle == 0 ||
param->end_handle == 0 ||
param->end_handle < param->start_handle) {
/* Start handle and end handle shall be non-zero and
* start handle shall be less than end handle.
*/
return ESP_ERR_INVALID_ARG;
}
bt_le_host_lock();
conn = bt_le_acl_conn_find(conn_handle);
if (conn == NULL) {
ret = ESP_ERR_NOT_FOUND;
goto unlock;
}
err = bt_vocs_discover(conn, inst, param);
if (err) {
ret = ESP_FAIL;
}
unlock:
bt_le_host_unlock();
return ret;
}
#endif /* CONFIG_BT_VOCS_CLIENT */
@@ -0,0 +1,293 @@
/*
* SPDX-FileCopyrightText: 2020-2024 Nordic Semiconductor ASA
* SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ESP_BLE_AUDIO_AICS_API_H_
#define ESP_BLE_AUDIO_AICS_API_H_
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include "sdkconfig.h"
#include "esp_err.h"
#include <zephyr/bluetooth/audio/audio.h>
#include <zephyr/bluetooth/audio/aics.h>
#include "common/init.h"
#include "common/host.h"
#ifdef __cplusplus
extern "C" {
#endif
/*!< The mute state is unmuted */
#define ESP_BLE_AUDIO_AICS_STATE_UNMUTED BT_AICS_STATE_UNMUTED
/*!< The mute state is muted */
#define ESP_BLE_AUDIO_AICS_STATE_MUTED BT_AICS_STATE_MUTED
/*!< The mute state is disabled */
#define ESP_BLE_AUDIO_AICS_STATE_MUTE_DISABLED BT_AICS_STATE_MUTE_DISABLED
/*!< The gain mode is manual only and cannot be changed to automatic */
#define ESP_BLE_AUDIO_AICS_MODE_MANUAL_ONLY BT_AICS_MODE_MANUAL_ONLY
/*!< The gain mode is automatic only and cannot be changed to manual */
#define ESP_BLE_AUDIO_AICS_MODE_AUTO_ONLY BT_AICS_MODE_AUTO_ONLY
/*!< The gain mode is manual */
#define ESP_BLE_AUDIO_AICS_MODE_MANUAL BT_AICS_MODE_MANUAL
/*!< The gain mode is automatic */
#define ESP_BLE_AUDIO_AICS_MODE_AUTO BT_AICS_MODE_AUTO
/*!< The input is unspecified */
#define ESP_BLE_AUDIO_AICS_INPUT_TYPE_UNSPECIFIED BT_AICS_INPUT_TYPE_UNSPECIFIED
/*!< The input is a Bluetooth Audio Stream */
#define ESP_BLE_AUDIO_AICS_INPUT_TYPE_BLUETOOTH BT_AICS_INPUT_TYPE_BLUETOOTH
/*!< The input is a microphone */
#define ESP_BLE_AUDIO_AICS_INPUT_TYPE_MICROPHONE BT_AICS_INPUT_TYPE_MICROPHONE
/*!< The input is analog */
#define ESP_BLE_AUDIO_AICS_INPUT_TYPE_ANALOG BT_AICS_INPUT_TYPE_ANALOG
/*!< The input is digital */
#define ESP_BLE_AUDIO_AICS_INPUT_TYPE_DIGITAL BT_AICS_INPUT_TYPE_DIGITAL
/*!< The input is a radio (AM/FM/XM/etc.) */
#define ESP_BLE_AUDIO_AICS_INPUT_TYPE_RADIO BT_AICS_INPUT_TYPE_RADIO
/*!< The input is a Streaming Audio Source */
#define ESP_BLE_AUDIO_AICS_INPUT_TYPE_STREAMING BT_AICS_INPUT_TYPE_STREAMING
/*!< The input is transparent / pass-through */
#define ESP_BLE_AUDIO_AICS_INPUT_TYPE_AMBIENT BT_AICS_INPUT_TYPE_AMBIENT
/** Audio Input Control Service instance. */
typedef struct bt_aics esp_ble_audio_aics_t;
/** Structure to hold callbacks for Audio Input Control Service. */
typedef struct bt_aics_cb esp_ble_audio_aics_cb_t;
/** Structure for initializing an Audio Input Control Service instance. */
typedef struct bt_aics_register_param esp_ble_audio_aics_register_param_t;
/** Structure for discovering an Audio Input Control Service instance. */
typedef struct bt_aics_discover_param esp_ble_audio_aics_discover_param_t;
/**
* @brief Get a free instance of Audio Input Control Service from the pool.
*
* @return Audio Input Control Service instance in case of success or NULL in case of error.
*/
esp_ble_audio_aics_t *esp_ble_audio_aics_free_instance_get(void);
/**
* @brief Get the service declaration attribute.
*
* The first service attribute returned can be included in any other GATT service.
*
* @param aics Audio Input Control Service instance.
*
* @return Pointer to the attributes of the service.
*/
void *esp_ble_audio_aics_svc_decl_get(esp_ble_audio_aics_t *aics);
/**
* @brief Initialize the Audio Input Control Service instance.
*
* @param aics Audio Input Control Service instance.
* @param param Audio Input Control Service register parameters.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_aics_register(esp_ble_audio_aics_t *aics,
esp_ble_audio_aics_register_param_t *param);
/**
* @brief Activates an Audio Input Control Service instance.
*
* Audio Input Control Services are activated by default, but this will allow
* the server reactivate an Audio Input Control Service instance after it has
* been deactivated.
*
* @param inst The instance pointer.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_aics_activate(esp_ble_audio_aics_t *inst);
/**
* @brief Deactivates an Audio Input Control Service instance.
*
* Audio Input Control Services are activated by default, but this will allow
* the server to deactivate an Audio Input Control Service.
*
* @param inst The instance pointer.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_aics_deactivate(esp_ble_audio_aics_t *inst);
/**
* @brief Read the Audio Input Control Service input state.
*
* @param inst The instance pointer.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_aics_state_get(esp_ble_audio_aics_t *inst);
/**
* @brief Read the Audio Input Control Service gain settings.
*
* @param inst The instance pointer.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_aics_gain_setting_get(esp_ble_audio_aics_t *inst);
/**
* @brief Read the Audio Input Control Service input type.
*
* @param inst The instance pointer.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_aics_type_get(esp_ble_audio_aics_t *inst);
/**
* @brief Read the Audio Input Control Service input status.
*
* @param inst The instance pointer.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_aics_status_get(esp_ble_audio_aics_t *inst);
/**
* @brief Disable mute in the Audio Input Control Service.
*
* @param inst The instance pointer.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_aics_disable_mute(esp_ble_audio_aics_t *inst);
/**
* @brief Unmute the Audio Input Control Service input.
*
* @param inst The instance pointer.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_aics_unmute(esp_ble_audio_aics_t *inst);
/**
* @brief Mute the Audio Input Control Service input.
*
* @param inst The instance pointer.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_aics_mute(esp_ble_audio_aics_t *inst);
/**
* @brief Set manual only gain mode in Audio Input Control Service.
*
* @param inst The instance pointer.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_aics_gain_set_manual_only(esp_ble_audio_aics_t *inst);
/**
* @brief Set automatic only gain mode in Audio Input Control Service.
*
* @param inst The instance pointer.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_aics_gain_set_auto_only(esp_ble_audio_aics_t *inst);
/**
* @brief Set input gain to manual.
*
* @param inst The instance pointer.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_aics_manual_gain_set(esp_ble_audio_aics_t *inst);
/**
* @brief Set the input gain to automatic.
*
* @param inst The instance pointer.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_aics_automatic_gain_set(esp_ble_audio_aics_t *inst);
/**
* @brief Set the input gain.
*
* @param inst The instance pointer.
* @param gain The gain to set (-128 to 127) in gain setting units.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_aics_gain_set(esp_ble_audio_aics_t *inst, int8_t gain);
/**
* @brief Read the Audio Input Control Service description.
*
* @param inst The instance pointer.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_aics_description_get(esp_ble_audio_aics_t *inst);
/**
* @brief Set the Audio Input Control Service description.
*
* @param inst The instance pointer.
* @param description The description as an UTF-8 encoded string.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_aics_description_set(esp_ble_audio_aics_t *inst,
const char *description);
/**
* @brief Discover an Audio Input Control Service.
*
* Attempts to discover an Audio Input Control Service on a server given the
* @p param.
*
* @param conn_handle Connection handle.
* @param inst The instance pointer.
* @param param Pointer to the parameters.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_aics_discover(uint16_t conn_handle, esp_ble_audio_aics_t *inst,
const esp_ble_audio_aics_discover_param_t *param);
/**
* @brief Get a new Audio Input Control Service client instance.
*
* @return Pointer to the instance, or NULL if no free instances are left.
*/
esp_ble_audio_aics_t *esp_ble_audio_aics_client_free_instance_get(void);
/**
* @brief Registers the callbacks for the Audio Input Control Service client.
*
* @param inst The instance pointer.
* @param cb Pointer to the callback structure.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_aics_client_cb_register(esp_ble_audio_aics_t *inst,
esp_ble_audio_aics_cb_t *cb);
#ifdef __cplusplus
}
#endif
#endif /* ESP_BLE_AUDIO_AICS_API_H_ */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,967 @@
/*
* SPDX-FileCopyrightText: 2023-2024 Nordic Semiconductor ASA
* SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFS_H_
#define ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFS_H_
#include "sdkconfig.h"
#include <zephyr/bluetooth/audio/bap_lc3_preset.h>
#include "esp_ble_audio_lc3_defs.h"
#ifdef __cplusplus
extern "C" {
#endif
/** Struct to hold a BAP defined LC3 preset */
typedef struct bt_bap_lc3_preset esp_ble_audio_bap_lc3_preset_t;
/*!< Helper to declare an LC3 preset structure */
#define ESP_BLE_AUDIO_BAP_LC3_PRESET(_codec, _qos) \
BT_BAP_LC3_PRESET(_codec, _qos)
/**
* @brief Define an LC3 preset configuration.
*
* @param _name Preset configuration name.
* @param _freq Sample frequency (in Hz).
* @param _duration Frame duration (in microseconds).
* @param _loc Audio channel location.
* @param _len Frame length in octets.
* @param _frames_per_sdu Number of frames per SDU.
* @param _stream_context Stream context (e.g., Media, Conversational, etc.).
* @param _interval Audio frame interval (in microseconds).
* @param _sdu SDU size in octets.
* @param _rtn Number of retransmissions.
* @param _latency Maximum transport latency (in milliseconds).
* @param _pd Presentation delay (in microseconds).
*/
#define ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, _freq, _duration, _loc, _len, \
_frames_per_sdu, _stream_context, \
_interval, _sdu, _rtn, _latency, _pd) \
static uint8_t codec_cfg_data_##_name[] = \
ESP_BLE_AUDIO_CODEC_CFG_LC3_DATA(_freq, _duration, _loc, _len, _frames_per_sdu); \
static uint8_t codec_cfg_meta_##_name[] = \
ESP_BLE_AUDIO_CODEC_CFG_LC3_META(_stream_context); \
static esp_ble_audio_bap_lc3_preset_t _name = \
ESP_BLE_AUDIO_BAP_LC3_PRESET(ESP_BLE_AUDIO_CODEC_CFG_LC3(codec_cfg_data_##_name, \
codec_cfg_meta_##_name), \
ESP_BLE_AUDIO_BAP_QOS_CFG_UNFRAMED(_interval, _sdu, _rtn, \
_latency, _pd));
/**
* @brief Helper to declare LC3 Unicast 8_1_1 codec configuration.
*
* @param _loc Audio channel location bitfield.
* @param _stream_context Stream context.
*/
#define ESP_BLE_AUDIO_BAP_LC3_UNICAST_PRESET_8_1_1_DEFINE(_name, _loc, _stream_context) \
ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \
BT_AUDIO_CODEC_CFG_FREQ_8KHZ, \
BT_AUDIO_CODEC_CFG_DURATION_7_5, \
_loc, 26u, 1, \
_stream_context, \
7500u, 26u, 2u, 8u, 40000u)
/**
* @brief Helper to declare LC3 Unicast 8_2_1 codec configuration.
*
* @param _loc Audio channel location bitfield.
* @param _stream_context Stream context.
*/
#define ESP_BLE_AUDIO_BAP_LC3_UNICAST_PRESET_8_2_1_DEFINE(_name, _loc, _stream_context) \
ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \
BT_AUDIO_CODEC_CFG_FREQ_8KHZ, \
BT_AUDIO_CODEC_CFG_DURATION_10, \
_loc, 30U, 1, \
_stream_context, \
10000u, 30u, 2u, 10u, 40000u)
/**
* @brief Helper to declare LC3 Unicast 16_1_1 codec configuration.
*
* @param _loc Audio channel location bitfield.
* @param _stream_context Stream context.
*/
#define ESP_BLE_AUDIO_BAP_LC3_UNICAST_PRESET_16_1_1_DEFINE(_name, _loc, _stream_context) \
ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \
BT_AUDIO_CODEC_CFG_FREQ_16KHZ, \
BT_AUDIO_CODEC_CFG_DURATION_7_5, \
_loc, 30U, 1, \
_stream_context, \
7500u, 30u, 2u, 8u, 40000u)
/**
* @brief Helper to declare LC3 Unicast 16_2_1 codec configuration.
*
* @param _loc Audio channel location bitfield.
* @param _stream_context Stream context.
*/
#define ESP_BLE_AUDIO_BAP_LC3_UNICAST_PRESET_16_2_1_DEFINE(_name, _loc, _stream_context) \
ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \
BT_AUDIO_CODEC_CFG_FREQ_16KHZ, \
BT_AUDIO_CODEC_CFG_DURATION_10, \
_loc, 40U, 1, \
_stream_context, \
10000u, 40u, 2u, 10u, 40000u)
/**
* @brief Helper to declare LC3 Unicast 24_1_1 codec configuration.
*
* @param _loc Audio channel location bitfield.
* @param _stream_context Stream context.
*/
#define ESP_BLE_AUDIO_BAP_LC3_UNICAST_PRESET_24_1_1_DEFINE(_name, _loc, _stream_context) \
ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \
BT_AUDIO_CODEC_CFG_FREQ_24KHZ, \
BT_AUDIO_CODEC_CFG_DURATION_7_5, \
_loc, 45U, 1, \
_stream_context, \
7500u, 45u, 2u, 8u, 40000u)
/**
* @brief Helper to declare LC3 Unicast 24_2_1 codec configuration.
*
* Mandatory to support as unicast server.
*
* @param _loc Audio channel location bitfield.
* @param _stream_context Stream context.
*/
#define ESP_BLE_AUDIO_BAP_LC3_UNICAST_PRESET_24_2_1_DEFINE(_name, _loc, _stream_context) \
ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \
BT_AUDIO_CODEC_CFG_FREQ_24KHZ, \
BT_AUDIO_CODEC_CFG_DURATION_10, \
_loc, 60U, 1, \
_stream_context, \
10000u, 60u, 2u, 10u, 40000u)
/**
* @brief Helper to declare LC3 Unicast 32_1_1 codec configuration.
*
* @param _loc Audio channel location bitfield.
* @param _stream_context Stream context.
*/
#define ESP_BLE_AUDIO_BAP_LC3_UNICAST_PRESET_32_1_1_DEFINE(_name, _loc, _stream_context) \
ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \
BT_AUDIO_CODEC_CFG_FREQ_32KHZ, \
BT_AUDIO_CODEC_CFG_DURATION_7_5, \
_loc, 60U, 1, \
_stream_context, \
7500u, 60u, 2u, 8u, 40000u)
/**
* @brief Helper to declare LC3 Unicast 32_2_1 codec configuration.
*
* @param _loc Audio channel location bitfield.
* @param _stream_context Stream context.
*/
#define ESP_BLE_AUDIO_BAP_LC3_UNICAST_PRESET_32_2_1_DEFINE(_name, _loc, _stream_context) \
ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \
BT_AUDIO_CODEC_CFG_FREQ_32KHZ, \
BT_AUDIO_CODEC_CFG_DURATION_10, \
_loc, 80U, 1, \
_stream_context, \
10000u, 80u, 2u, 10u, 40000u)
/**
* @brief Helper to declare LC3 Unicast 441_1_1 codec configuration.
*
* @param _loc Audio channel location bitfield.
* @param _stream_context Stream context.
*/
#define ESP_BLE_AUDIO_BAP_LC3_UNICAST_PRESET_441_1_1_DEFINE(_name, _loc, _stream_context) \
ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \
BT_AUDIO_CODEC_CFG_FREQ_44KHZ, \
BT_AUDIO_CODEC_CFG_DURATION_7_5, \
_loc, 97U, 1, \
_stream_context, \
8163u, 97u, 5u, 24u, 40000u)
/**
* @brief Helper to declare LC3 Unicast 441_2_1 codec configuration.
*
* @param _loc Audio channel location bitfield.
* @param _stream_context Stream context.
*/
#define ESP_BLE_AUDIO_BAP_LC3_UNICAST_PRESET_441_2_1_DEFINE(_name, _loc, _stream_context) \
ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \
BT_AUDIO_CODEC_CFG_FREQ_44KHZ, \
BT_AUDIO_CODEC_CFG_DURATION_10, \
_loc, 130U, 1, \
_stream_context, \
10884u, 130u, 5u, 31u, 40000u)
/**
* @brief Helper to declare LC3 Unicast 48_1_1 codec configuration.
*
* @param _loc Audio channel location bitfield.
* @param _stream_context Stream context.
*/
#define ESP_BLE_AUDIO_BAP_LC3_UNICAST_PRESET_48_1_1_DEFINE(_name, _loc, _stream_context) \
ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \
BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \
BT_AUDIO_CODEC_CFG_DURATION_7_5, \
_loc, 75U, 1, \
_stream_context, \
7500u, 75u, 5u, 15u, 40000u)
/**
* @brief Helper to declare LC3 Unicast 48_2_1 codec configuration.
*
* @param _loc Audio channel location bitfield.
* @param _stream_context Stream context.
*/
#define ESP_BLE_AUDIO_BAP_LC3_UNICAST_PRESET_48_2_1_DEFINE(_name, _loc, _stream_context) \
ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \
BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \
BT_AUDIO_CODEC_CFG_DURATION_10, \
_loc, 100U, 1, \
_stream_context, \
10000u, 100u, 5u, 20u, 40000u)
/**
* @brief Helper to declare LC3 Unicast 48_3_1 codec configuration.
*
* @param _loc Audio channel location bitfield.
* @param _stream_context Stream context.
*/
#define ESP_BLE_AUDIO_BAP_LC3_UNICAST_PRESET_48_3_1_DEFINE(_name, _loc, _stream_context) \
ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \
BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \
BT_AUDIO_CODEC_CFG_DURATION_7_5, \
_loc, 90U, 1, \
_stream_context, \
7500u, 90u, 5u, 15u, 40000u)
/**
* @brief Helper to declare LC3 Unicast 48_4_1 codec configuration.
*
* @param _loc Audio channel location bitfield.
* @param _stream_context Stream context.
*/
#define ESP_BLE_AUDIO_BAP_LC3_UNICAST_PRESET_48_4_1_DEFINE(_name, _loc, _stream_context) \
ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \
BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \
BT_AUDIO_CODEC_CFG_DURATION_10, \
_loc, 120u, 1, \
_stream_context, \
10000u, 120u, 5u, 20u, 40000u)
/**
* @brief Helper to declare LC3 Unicast 48_5_1 codec configuration.
*
* @param _loc Audio channel location bitfield.
* @param _stream_context Stream context.
*/
#define ESP_BLE_AUDIO_BAP_LC3_UNICAST_PRESET_48_5_1_DEFINE(_name, _loc, _stream_context) \
ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \
BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \
BT_AUDIO_CODEC_CFG_DURATION_7_5, \
_loc, 117u, 1, \
_stream_context, \
7500u, 117u, 5u, 15u, 40000u)
/**
* @brief Helper to declare LC3 Unicast 48_6_1 codec configuration.
*
* @param _loc Audio channel location bitfield.
* @param _stream_context Stream context.
*/
#define ESP_BLE_AUDIO_BAP_LC3_UNICAST_PRESET_48_6_1_DEFINE(_name, _loc, _stream_context) \
ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \
BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \
BT_AUDIO_CODEC_CFG_DURATION_10, \
_loc, 155u, 1, \
_stream_context, \
10000u, 155u, 5u, 20u, 40000u)
/**
* @brief Helper to declare LC3 Unicast 8_1_2 codec configuration.
*
* @param _loc Audio channel location bitfield.
* @param _stream_context Stream context.
*/
#define ESP_BLE_AUDIO_BAP_LC3_UNICAST_PRESET_8_1_2_DEFINE(_name, _loc, _stream_context) \
ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \
BT_AUDIO_CODEC_CFG_FREQ_8KHZ, \
BT_AUDIO_CODEC_CFG_DURATION_7_5, \
_loc, 26u, 1, \
_stream_context, \
7500u, 26u, 13u, 75u, 40000u)
/**
* @brief Helper to declare LC3 Unicast 8_2_2 codec configuration.
*
* @param _loc Audio channel location bitfield.
* @param _stream_context Stream context.
*/
#define ESP_BLE_AUDIO_BAP_LC3_UNICAST_PRESET_8_2_2_DEFINE(_name, _loc, _stream_context) \
ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \
BT_AUDIO_CODEC_CFG_FREQ_8KHZ, \
BT_AUDIO_CODEC_CFG_DURATION_10, \
_loc, 30U, 1, \
_stream_context, \
10000u, 30u, 13u, 95u, 40000u)
/**
* @brief Helper to declare LC3 Unicast 16_1_2 codec configuration.
*
* @param _loc Audio channel location bitfield.
* @param _stream_context Stream context.
*/
#define ESP_BLE_AUDIO_BAP_LC3_UNICAST_PRESET_16_1_2_DEFINE(_name, _loc, _stream_context) \
ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \
BT_AUDIO_CODEC_CFG_FREQ_16KHZ, \
BT_AUDIO_CODEC_CFG_DURATION_7_5, \
_loc, 30U, 1, \
_stream_context, \
7500u, 30u, 13u, 75u, 40000u)
/**
* @brief Helper to declare LC3 Unicast 16_2_2 codec configuration.
*
* @param _loc Audio channel location bitfield.
* @param _stream_context Stream context.
*/
#define ESP_BLE_AUDIO_BAP_LC3_UNICAST_PRESET_16_2_2_DEFINE(_name, _loc, _stream_context) \
ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \
BT_AUDIO_CODEC_CFG_FREQ_16KHZ, \
BT_AUDIO_CODEC_CFG_DURATION_10, \
_loc, 40U, 1, \
_stream_context, \
10000u, 40u, 13u, 95u, 40000u)
/**
* @brief Helper to declare LC3 Unicast 24_1_2 codec configuration.
*
* @param _loc Audio channel location bitfield.
* @param _stream_context Stream context.
*/
#define ESP_BLE_AUDIO_BAP_LC3_UNICAST_PRESET_24_1_2_DEFINE(_name, _loc, _stream_context) \
ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \
BT_AUDIO_CODEC_CFG_FREQ_24KHZ, \
BT_AUDIO_CODEC_CFG_DURATION_7_5, \
_loc, 45U, 1, \
_stream_context, \
7500u, 45u, 13u, 75u, 40000u)
/**
* @brief Helper to declare LC3 Unicast 24_2_2 codec configuration.
*
* @param _loc Audio channel location bitfield.
* @param _stream_context Stream context.
*/
#define ESP_BLE_AUDIO_BAP_LC3_UNICAST_PRESET_24_2_2_DEFINE(_name, _loc, _stream_context) \
ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \
BT_AUDIO_CODEC_CFG_FREQ_24KHZ, \
BT_AUDIO_CODEC_CFG_DURATION_10, \
_loc, 60U, 1, \
_stream_context, \
10000u, 60u, 13u, 95u, 40000u)
/**
* @brief Helper to declare LC3 Unicast 32_1_2 codec configuration.
*
* @param _loc Audio channel location bitfield.
* @param _stream_context Stream context.
*/
#define ESP_BLE_AUDIO_BAP_LC3_UNICAST_PRESET_32_1_2_DEFINE(_name, _loc, _stream_context) \
ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \
BT_AUDIO_CODEC_CFG_FREQ_32KHZ, \
BT_AUDIO_CODEC_CFG_DURATION_7_5, \
_loc, 60U, 1, \
_stream_context, \
7500u, 60u, 13u, 75u, 40000u)
/**
* @brief Helper to declare LC3 Unicast 32_2_2 codec configuration.
*
* @param _loc Audio channel location bitfield.
* @param _stream_context Stream context.
*/
#define ESP_BLE_AUDIO_BAP_LC3_UNICAST_PRESET_32_2_2_DEFINE(_name, _loc, _stream_context) \
ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \
BT_AUDIO_CODEC_CFG_FREQ_32KHZ, \
BT_AUDIO_CODEC_CFG_DURATION_10, \
_loc, 80U, 1, \
_stream_context, \
10000u, 80u, 13u, 95u, 40000u)
/**
* @brief Helper to declare LC3 Unicast 441_1_2 codec configuration.
*
* @param _loc Audio channel location bitfield.
* @param _stream_context Stream context.
*/
#define ESP_BLE_AUDIO_BAP_LC3_UNICAST_PRESET_441_1_2_DEFINE(_name, _loc, _stream_context) \
ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \
BT_AUDIO_CODEC_CFG_FREQ_44KHZ, \
BT_AUDIO_CODEC_CFG_DURATION_7_5, \
_loc, 97U, 1, \
_stream_context, \
8163u, 97u, 13u, 80u, 40000u)
/**
* @brief Helper to declare LC3 Unicast 441_2_2 codec configuration.
*
* @param _loc Audio channel location bitfield.
* @param _stream_context Stream context.
*/
#define ESP_BLE_AUDIO_BAP_LC3_UNICAST_PRESET_441_2_2_DEFINE(_name, _loc, _stream_context) \
ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \
BT_AUDIO_CODEC_CFG_FREQ_44KHZ, \
BT_AUDIO_CODEC_CFG_DURATION_10, \
_loc, 130U, 1, \
_stream_context, \
10884u, 130u, 13u, 85u, 40000u)
/**
* @brief Helper to declare LC3 Unicast 48_1_2 codec configuration.
*
* @param _loc Audio channel location bitfield.
* @param _stream_context Stream context.
*/
#define ESP_BLE_AUDIO_BAP_LC3_UNICAST_PRESET_48_1_2_DEFINE(_name, _loc, _stream_context) \
ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \
BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \
BT_AUDIO_CODEC_CFG_DURATION_7_5, \
_loc, 75U, 1, \
_stream_context, \
7500u, 75u, 13u, 75u, 40000u)
/**
* @brief Helper to declare LC3 Unicast 48_2_2 codec configuration.
*
* @param _loc Audio channel location bitfield.
* @param _stream_context Stream context.
*/
#define ESP_BLE_AUDIO_BAP_LC3_UNICAST_PRESET_48_2_2_DEFINE(_name, _loc, _stream_context) \
ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \
BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \
BT_AUDIO_CODEC_CFG_DURATION_10, \
_loc, 100U, 1, \
_stream_context, \
10000u, 100u, 13u, 95u, 40000u)
/**
* @brief Helper to declare LC3 Unicast 48_3_2 codec configuration.
*
* @param _loc Audio channel location bitfield.
* @param _stream_context Stream context.
*/
#define ESP_BLE_AUDIO_BAP_LC3_UNICAST_PRESET_48_3_2_DEFINE(_name, _loc, _stream_context) \
ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \
BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \
BT_AUDIO_CODEC_CFG_DURATION_7_5, \
_loc, 90U, 1, \
_stream_context, \
7500u, 90u, 13u, 75u, 40000u)
/**
* @brief Helper to declare LC3 Unicast 48_4_2 codec configuration.
*
* @param _loc Audio channel location bitfield.
* @param _stream_context Stream context.
*/
#define ESP_BLE_AUDIO_BAP_LC3_UNICAST_PRESET_48_4_2_DEFINE(_name, _loc, _stream_context) \
ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \
BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \
BT_AUDIO_CODEC_CFG_DURATION_10, \
_loc, 120u, 1, \
_stream_context, \
10000u, 120u, 13u, 100u, 40000u)
/**
* @brief Helper to declare LC3 Unicast 48_5_2 codec configuration.
*
* @param _loc Audio channel location bitfield.
* @param _stream_context Stream context.
*/
#define ESP_BLE_AUDIO_BAP_LC3_UNICAST_PRESET_48_5_2_DEFINE(_name, _loc, _stream_context) \
ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \
BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \
BT_AUDIO_CODEC_CFG_DURATION_7_5, \
_loc, 117u, 1, \
_stream_context, \
7500u, 117u, 13u, 75u, 40000u)
/**
* @brief Helper to declare LC3 Unicast 48_6_2 codec configuration.
*
* @param _loc Audio channel location bitfield.
* @param _stream_context Stream context.
*/
#define ESP_BLE_AUDIO_BAP_LC3_UNICAST_PRESET_48_6_2_DEFINE(_name, _loc, _stream_context) \
ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \
BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \
BT_AUDIO_CODEC_CFG_DURATION_10, \
_loc, 155u, 1, \
_stream_context, \
10000u, 155u, 13u, 100u, 40000u)
/**
* @brief Helper to declare LC3 Broadcast 8_1_1 codec configuration.
*
* @param _loc Audio channel location bitfield.
* @param _stream_context Stream context.
*/
#define ESP_BLE_AUDIO_BAP_LC3_BROADCAST_PRESET_8_1_1_DEFINE(_name, _loc, _stream_context) \
ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \
BT_AUDIO_CODEC_CFG_FREQ_8KHZ, \
BT_AUDIO_CODEC_CFG_DURATION_7_5, \
_loc, 26u, 1, \
_stream_context, \
7500u, 26u, 2u, 8u, 40000u)
/**
* @brief Helper to declare LC3 Broadcast 8_2_1 codec configuration.
*
* @param _loc Audio channel location bitfield.
* @param _stream_context Stream context.
*/
#define ESP_BLE_AUDIO_BAP_LC3_BROADCAST_PRESET_8_2_1_DEFINE(_name, _loc, _stream_context) \
ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \
BT_AUDIO_CODEC_CFG_FREQ_8KHZ, \
BT_AUDIO_CODEC_CFG_DURATION_10, \
_loc, 30U, 1, \
_stream_context, \
10000u, 30u, 2u, 10u, 40000u)
/**
* @brief Helper to declare LC3 Broadcast 16_1_1 codec configuration.
*
* @param _loc Audio channel location bitfield.
* @param _stream_context Stream context.
*/
#define ESP_BLE_AUDIO_BAP_LC3_BROADCAST_PRESET_16_1_1_DEFINE(_name, _loc, _stream_context) \
ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \
BT_AUDIO_CODEC_CFG_FREQ_16KHZ, \
BT_AUDIO_CODEC_CFG_DURATION_7_5, \
_loc, 30U, 1, \
_stream_context, \
7500u, 30u, 2u, 8u, 40000u)
/**
* @brief Helper to declare LC3 Broadcast 16_2_1 codec configuration.
*
* Mandatory to support as both broadcast source and sink.
*
* @param _loc Audio channel location bitfield.
* @param _stream_context Stream context.
*/
#define ESP_BLE_AUDIO_BAP_LC3_BROADCAST_PRESET_16_2_1_DEFINE(_name, _loc, _stream_context) \
ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \
BT_AUDIO_CODEC_CFG_FREQ_16KHZ, \
BT_AUDIO_CODEC_CFG_DURATION_10, \
_loc, 40U, 1, \
_stream_context, \
10000u, 40u, 2u, 10u, 40000u)
/**
* @brief Helper to declare LC3 Broadcast 24_1_1 codec configuration.
*
* @param _loc Audio channel location bitfield.
* @param _stream_context Stream context.
*/
#define ESP_BLE_AUDIO_BAP_LC3_BROADCAST_PRESET_24_1_1_DEFINE(_name, _loc, _stream_context) \
ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \
BT_AUDIO_CODEC_CFG_FREQ_24KHZ, \
BT_AUDIO_CODEC_CFG_DURATION_7_5, \
_loc, 45U, 1, \
_stream_context, \
7500u, 45u, 2u, 8u, 40000u)
/**
* @brief Helper to declare LC3 Broadcast 24_2_1 codec configuration.
*
* Mandatory to support as broadcast sink.
*
* @param _loc Audio channel location bitfield.
* @param _stream_context Stream context.
*/
#define ESP_BLE_AUDIO_BAP_LC3_BROADCAST_PRESET_24_2_1_DEFINE(_name, _loc, _stream_context) \
ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \
BT_AUDIO_CODEC_CFG_FREQ_24KHZ, \
BT_AUDIO_CODEC_CFG_DURATION_10, \
_loc, 60U, 1, \
_stream_context, \
10000u, 60u, 2u, 10u, 40000u)
/**
* @brief Helper to declare LC3 Broadcast 32_1_1 codec configuration.
*
* @param _loc Audio channel location bitfield.
* @param _stream_context Stream context.
*/
#define ESP_BLE_AUDIO_BAP_LC3_BROADCAST_PRESET_32_1_1_DEFINE(_name, _loc, _stream_context) \
ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \
BT_AUDIO_CODEC_CFG_FREQ_32KHZ, \
BT_AUDIO_CODEC_CFG_DURATION_7_5, \
_loc, 60U, 1, \
_stream_context, \
7500u, 60u, 2u, 8u, 40000u)
/**
* @brief Helper to declare LC3 Broadcast 32_2_1 codec configuration.
*
* @param _loc Audio channel location bitfield.
* @param _stream_context Stream context.
*/
#define ESP_BLE_AUDIO_BAP_LC3_BROADCAST_PRESET_32_2_1_DEFINE(_name, _loc, _stream_context) \
ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \
BT_AUDIO_CODEC_CFG_FREQ_32KHZ, \
BT_AUDIO_CODEC_CFG_DURATION_10, \
_loc, 80U, 1, \
_stream_context, \
10000u, 80u, 2u, 10u, 40000u)
/**
* @brief Helper to declare LC3 Broadcast 441_1_1 codec configuration.
*
* @param _loc Audio channel location bitfield.
* @param _stream_context Stream context.
*/
#define ESP_BLE_AUDIO_BAP_LC3_BROADCAST_PRESET_441_1_1_DEFINE(_name, _loc, _stream_context) \
ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \
BT_AUDIO_CODEC_CFG_FREQ_44KHZ, \
BT_AUDIO_CODEC_CFG_DURATION_7_5, \
_loc, 97U, 1, \
_stream_context, \
8163u, 97u, 4u, 24u, 40000u)
/**
* @brief Helper to declare LC3 Broadcast 441_2_1 codec configuration.
*
* @param _loc Audio channel location bitfield.
* @param _stream_context Stream context.
*/
#define ESP_BLE_AUDIO_BAP_LC3_BROADCAST_PRESET_441_2_1_DEFINE(_name, _loc, _stream_context) \
ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \
BT_AUDIO_CODEC_CFG_FREQ_44KHZ, \
BT_AUDIO_CODEC_CFG_DURATION_10, \
_loc, 130U, 1, \
_stream_context, \
10884u, 130u, 4u, 31u, 40000u)
/**
* @brief Helper to declare LC3 Broadcast 48_1_1 codec configuration.
*
* @param _loc Audio channel location bitfield.
* @param _stream_context Stream context.
*/
#define ESP_BLE_AUDIO_BAP_LC3_BROADCAST_PRESET_48_1_1_DEFINE(_name, _loc, _stream_context) \
ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \
BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \
BT_AUDIO_CODEC_CFG_DURATION_7_5, \
_loc, 75U, 1, \
_stream_context, \
7500u, 75u, 4u, 15u, 40000u)
/**
* @brief Helper to declare LC3 Broadcast 48_2_1 codec configuration.
*
* @param _loc Audio channel location bitfield.
* @param _stream_context Stream context.
*/
#define ESP_BLE_AUDIO_BAP_LC3_BROADCAST_PRESET_48_2_1_DEFINE(_name, _loc, _stream_context) \
ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \
BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \
BT_AUDIO_CODEC_CFG_DURATION_10, \
_loc, 100U, 1, \
_stream_context, \
10000u, 100u, 4u, 20u, 40000u)
/**
* @brief Helper to declare LC3 Broadcast 48_3_1 codec configuration.
*
* @param _loc Audio channel location bitfield.
* @param _stream_context Stream context.
*/
#define ESP_BLE_AUDIO_BAP_LC3_BROADCAST_PRESET_48_3_1_DEFINE(_name, _loc, _stream_context) \
ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \
BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \
BT_AUDIO_CODEC_CFG_DURATION_7_5, \
_loc, 90U, 1, \
_stream_context, \
7500u, 90u, 4u, 15u, 40000u)
/**
* @brief Helper to declare LC3 Broadcast 48_4_1 codec configuration.
*
* @param _loc Audio channel location bitfield.
* @param _stream_context Stream context.
*/
#define ESP_BLE_AUDIO_BAP_LC3_BROADCAST_PRESET_48_4_1_DEFINE(_name, _loc, _stream_context) \
ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \
BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \
BT_AUDIO_CODEC_CFG_DURATION_10, \
_loc, 120u, 1, \
_stream_context, \
10000u, 120u, 4u, 20u, 40000u)
/**
* @brief Helper to declare LC3 Broadcast 48_5_1 codec configuration.
*
* @param _loc Audio channel location bitfield.
* @param _stream_context Stream context.
*/
#define ESP_BLE_AUDIO_BAP_LC3_BROADCAST_PRESET_48_5_1_DEFINE(_name, _loc, _stream_context) \
ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \
BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \
BT_AUDIO_CODEC_CFG_DURATION_7_5, \
_loc, 117u, 1, \
_stream_context, \
7500u, 117u, 4u, 15u, 40000u)
/**
* @brief Helper to declare LC3 Broadcast 48_6_1 codec configuration.
*
* @param _loc Audio channel location bitfield.
* @param _stream_context Stream context.
*/
#define ESP_BLE_AUDIO_BAP_LC3_BROADCAST_PRESET_48_6_1_DEFINE(_name, _loc, _stream_context) \
ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \
BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \
BT_AUDIO_CODEC_CFG_DURATION_10, \
_loc, 155u, 1, \
_stream_context, \
10000u, 155u, 4u, 20u, 40000u)
/**
* @brief Helper to declare LC3 Broadcast 8_1_2 codec configuration.
*
* @param _loc Audio channel location bitfield.
* @param _stream_context Stream context.
*/
#define ESP_BLE_AUDIO_BAP_LC3_BROADCAST_PRESET_8_1_2_DEFINE(_name, _loc, _stream_context) \
ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \
BT_AUDIO_CODEC_CFG_FREQ_8KHZ, \
BT_AUDIO_CODEC_CFG_DURATION_7_5, \
_loc, 26u, 1, \
_stream_context, \
7500u, 26u, 4u, 45u, 40000u)
/**
* @brief Helper to declare LC3 Broadcast 8_2_2 codec configuration.
*
* @param _loc Audio channel location bitfield.
* @param _stream_context Stream context.
*/
#define ESP_BLE_AUDIO_BAP_LC3_BROADCAST_PRESET_8_2_2_DEFINE(_name, _loc, _stream_context) \
ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \
BT_AUDIO_CODEC_CFG_FREQ_8KHZ, \
BT_AUDIO_CODEC_CFG_DURATION_10, \
_loc, 30U, 1, \
_stream_context, \
10000u, 30u, 4u, 60u, 40000u)
/**
* @brief Helper to declare LC3 Broadcast 16_1_2 codec configuration.
*
* @param _loc Audio channel location bitfield.
* @param _stream_context Stream context.
*/
#define ESP_BLE_AUDIO_BAP_LC3_BROADCAST_PRESET_16_1_2_DEFINE(_name, _loc, _stream_context) \
ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \
BT_AUDIO_CODEC_CFG_FREQ_16KHZ, \
BT_AUDIO_CODEC_CFG_DURATION_7_5, \
_loc, 30U, 1, \
_stream_context, \
7500u, 30u, 4u, 45u, 40000u)
/**
* @brief Helper to declare LC3 Broadcast 16_2_2 codec configuration.
*
* Mandatory to support as both broadcast source and sink.
*
* @param _loc Audio channel location bitfield.
* @param _stream_context Stream context.
*/
#define ESP_BLE_AUDIO_BAP_LC3_BROADCAST_PRESET_16_2_2_DEFINE(_name, _loc, _stream_context) \
ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \
BT_AUDIO_CODEC_CFG_FREQ_16KHZ, \
BT_AUDIO_CODEC_CFG_DURATION_10, \
_loc, 40U, 1, \
_stream_context, \
10000u, 40u, 4u, 60u, 40000u)
/**
* @brief Helper to declare LC3 Broadcast 24_1_2 codec configuration.
*
* @param _loc Audio channel location bitfield.
* @param _stream_context Stream context.
*/
#define ESP_BLE_AUDIO_BAP_LC3_BROADCAST_PRESET_24_1_2_DEFINE(_name, _loc, _stream_context) \
ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \
BT_AUDIO_CODEC_CFG_FREQ_24KHZ, \
BT_AUDIO_CODEC_CFG_DURATION_7_5, \
_loc, 45U, 1, \
_stream_context, \
7500u, 45u, 4u, 45u, 40000u)
/**
* @brief Helper to declare LC3 Broadcast 24_2_2 codec configuration.
*
* Mandatory to support as broadcast sink.
*
* @param _loc Audio channel location bitfield.
* @param _stream_context Stream context.
*/
#define ESP_BLE_AUDIO_BAP_LC3_BROADCAST_PRESET_24_2_2_DEFINE(_name, _loc, _stream_context) \
ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \
BT_AUDIO_CODEC_CFG_FREQ_24KHZ, \
BT_AUDIO_CODEC_CFG_DURATION_10, \
_loc, 60U, 1, \
_stream_context, \
10000u, 60u, 4u, 60u, 40000u)
/**
* @brief Helper to declare LC3 Broadcast 32_1_2 codec configuration.
*
* @param _loc Audio channel location bitfield.
* @param _stream_context Stream context.
*/
#define ESP_BLE_AUDIO_BAP_LC3_BROADCAST_PRESET_32_1_2_DEFINE(_name, _loc, _stream_context) \
ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \
BT_AUDIO_CODEC_CFG_FREQ_32KHZ, \
BT_AUDIO_CODEC_CFG_DURATION_7_5, \
_loc, 60U, 1, \
_stream_context, \
7500u, 60u, 4u, 45u, 40000u)
/**
* @brief Helper to declare LC3 Broadcast 32_2_2 codec configuration.
*
* @param _loc Audio channel location bitfield.
* @param _stream_context Stream context.
*/
#define ESP_BLE_AUDIO_BAP_LC3_BROADCAST_PRESET_32_2_2_DEFINE(_name, _loc, _stream_context) \
ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \
BT_AUDIO_CODEC_CFG_FREQ_32KHZ, \
BT_AUDIO_CODEC_CFG_DURATION_10, \
_loc, 80U, 1, \
_stream_context, \
10000u, 80u, 4u, 60u, 40000u)
/**
* @brief Helper to declare LC3 Broadcast 441_1_2 codec configuration.
*
* @param _loc Audio channel location bitfield.
* @param _stream_context Stream context.
*/
#define ESP_BLE_AUDIO_BAP_LC3_BROADCAST_PRESET_441_1_2_DEFINE(_name, _loc, _stream_context) \
ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \
BT_AUDIO_CODEC_CFG_FREQ_44KHZ, \
BT_AUDIO_CODEC_CFG_DURATION_7_5, \
_loc, 97U, 1, \
_stream_context, \
8163u, 97u, 4u, 54u, 40000u)
/**
* @brief Helper to declare LC3 Broadcast 441_2_2 codec configuration.
*
* @param _loc Audio channel location bitfield.
* @param _stream_context Stream context.
*/
#define ESP_BLE_AUDIO_BAP_LC3_BROADCAST_PRESET_441_2_2_DEFINE(_name, _loc, _stream_context) \
ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \
BT_AUDIO_CODEC_CFG_FREQ_44KHZ, \
BT_AUDIO_CODEC_CFG_DURATION_10, \
_loc, 130U, 1, \
_stream_context, \
10884u, 130u, 4u, 60u, 40000u)
/**
* @brief Helper to declare LC3 Broadcast 48_1_2 codec configuration.
*
* @param _loc Audio channel location bitfield.
* @param _stream_context Stream context.
*/
#define ESP_BLE_AUDIO_BAP_LC3_BROADCAST_PRESET_48_1_2_DEFINE(_name, _loc, _stream_context) \
ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \
BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \
BT_AUDIO_CODEC_CFG_DURATION_7_5, \
_loc, 75U, 1, \
_stream_context, \
7500u, 75u, 4u, 50u, 40000u)
/**
* @brief Helper to declare LC3 Broadcast 48_2_2 codec configuration.
*
* @param _loc Audio channel location bitfield.
* @param _stream_context Stream context.
*/
#define ESP_BLE_AUDIO_BAP_LC3_BROADCAST_PRESET_48_2_2_DEFINE(_name, _loc, _stream_context) \
ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \
BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \
BT_AUDIO_CODEC_CFG_DURATION_10, \
_loc, 100U, 1, \
_stream_context, \
10000u, 100u, 4u, 65u, 40000u)
/**
* @brief Helper to declare LC3 Broadcast 48_3_2 codec configuration.
*
* @param _loc Audio channel location bitfield.
* @param _stream_context Stream context.
*/
#define ESP_BLE_AUDIO_BAP_LC3_BROADCAST_PRESET_48_3_2_DEFINE(_name, _loc, _stream_context) \
ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \
BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \
BT_AUDIO_CODEC_CFG_DURATION_7_5, \
_loc, 90U, 1, \
_stream_context, \
7500u, 90u, 4u, 50u, 40000u)
/**
* @brief Helper to declare LC3 Broadcast 48_4_2 codec configuration.
*
* @param _loc Audio channel location bitfield.
* @param _stream_context Stream context.
*/
#define ESP_BLE_AUDIO_BAP_LC3_BROADCAST_PRESET_48_4_2_DEFINE(_name, _loc, _stream_context) \
ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \
BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \
BT_AUDIO_CODEC_CFG_DURATION_10, \
_loc, 120u, 1, \
_stream_context, \
10000u, 120u, 4u, 65u, 40000u)
/**
* @brief Helper to declare LC3 Broadcast 48_5_2 codec configuration.
*
* @param _loc Audio channel location bitfield.
* @param _stream_context Stream context.
*/
#define ESP_BLE_AUDIO_BAP_LC3_BROADCAST_PRESET_48_5_2_DEFINE(_name, _loc, _stream_context) \
ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \
BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \
BT_AUDIO_CODEC_CFG_DURATION_7_5, \
_loc, 117u, 1, \
_stream_context, \
7500u, 117u, 4u, 50u, 40000u)
/**
* @brief Helper to declare LC3 Broadcast 48_6_2 codec configuration.
*
* @param _loc Audio channel location bitfield.
* @param _stream_context Stream context.
*/
#define ESP_BLE_AUDIO_BAP_LC3_BROADCAST_PRESET_48_6_2_DEFINE(_name, _loc, _stream_context) \
ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \
BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \
BT_AUDIO_CODEC_CFG_DURATION_10, \
_loc, 155u, 1, \
_stream_context, \
10000u, 155u, 4u, 65u, 40000u)
#ifdef __cplusplus
}
#endif
#endif /* ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFS_H_ */
@@ -0,0 +1,659 @@
/*
* SPDX-FileCopyrightText: 2022-2024 Nordic Semiconductor ASA
* SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ESP_BLE_AUDIO_CAP_API_H_
#define ESP_BLE_AUDIO_CAP_API_H_
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include "sdkconfig.h"
#include "esp_err.h"
#include <zephyr/bluetooth/audio/audio.h>
#include <zephyr/bluetooth/audio/cap.h>
#include "common/init.h"
#include "common/host.h"
#include "esp_ble_audio_bap_api.h"
#include "esp_ble_audio_csip_api.h"
#ifdef __cplusplus
extern "C" {
#endif
/*!< The set is an ad-hoc set */
#define ESP_BLE_AUDIO_CAP_SET_TYPE_AD_HOC BT_CAP_SET_TYPE_AD_HOC
/*!< The set is a CSIP Coordinated Set */
#define ESP_BLE_AUDIO_CAP_SET_TYPE_CSIP BT_CAP_SET_TYPE_CSIP
/** Type of CAP set */
typedef enum bt_cap_set_type esp_ble_audio_cap_set_type_t;
/** Common Audio Profile stream structure */
typedef struct bt_cap_stream esp_ble_audio_cap_stream_t;
/** Common Audio Broadcast Source structure */
typedef struct bt_cap_broadcast_source esp_ble_audio_cap_broadcast_source_t;
/** Common Audio Unicast Group structure */
typedef struct bt_cap_unicast_group esp_ble_audio_cap_unicast_group_t;
/** Callback structure for CAP procedures */
typedef struct bt_cap_initiator_cb esp_ble_audio_cap_initiator_cb_t;
/** Union represents a Common Audio Set member that are either in a Coordinated or ad-hoc set */
typedef union bt_cap_set_member esp_ble_audio_cap_set_member_t;
/** Parameter structure for each stream in the unicast group */
typedef struct bt_cap_unicast_group_stream_param \
esp_ble_audio_cap_unicast_group_stream_param_t;
/* Parameter structure for the unicast group functions */
typedef struct bt_cap_unicast_group_stream_pair_param \
esp_ble_audio_cap_unicast_group_stream_pair_param_t;
/** Parameters for the creating unicast groups */
typedef struct bt_cap_unicast_group_param \
esp_ble_audio_cap_unicast_group_param_t;
/** CAP unicast audio stream specific parameters for starting audio */
typedef struct bt_cap_unicast_audio_start_stream_param \
esp_ble_audio_cap_unicast_audio_start_stream_param_t;
/** CAP unicast audio specific parameters for starting audio */
typedef struct bt_cap_unicast_audio_start_param \
esp_ble_audio_cap_unicast_audio_start_param_t;
/** CAP unicast audio stream specific parameters for updating audio */
typedef struct bt_cap_unicast_audio_update_stream_param \
esp_ble_audio_cap_unicast_audio_update_stream_param_t;
/** CAP unicast audio specific parameters for updating audio */
typedef struct bt_cap_unicast_audio_update_param \
esp_ble_audio_cap_unicast_audio_update_param_t;
/** CAP unicast audio specific parameters for stopping audio */
typedef struct bt_cap_unicast_audio_stop_param \
esp_ble_audio_cap_unicast_audio_stop_param_t;
/** CAP Initiator broadcast audio stream specific parameters */
typedef struct bt_cap_initiator_broadcast_stream_param \
esp_ble_audio_cap_initiator_broadcast_stream_param_t;
/** CAP Initiator broadcast audio subgroup specific parameters */
typedef struct bt_cap_initiator_broadcast_subgroup_param \
esp_ble_audio_cap_initiator_broadcast_subgroup_param_t;
/** CAP Initiator broadcast audio specific parameters for creating audio */
typedef struct bt_cap_initiator_broadcast_create_param \
esp_ble_audio_cap_initiator_broadcast_create_param_t;
/** Callback structure for CAP Handover procedures */
typedef struct bt_cap_handover_cb esp_ble_audio_cap_handover_cb_t;
/** CAP Handover unicast audio to broadcast audio specific parameters */
typedef struct bt_cap_handover_unicast_to_broadcast_param \
esp_ble_audio_cap_handover_unicast_to_broadcast_param_t;
/** CAP Handover broadcast audio to unicast audio specific parameters */
typedef struct bt_cap_handover_broadcast_to_unicast_param \
esp_ble_audio_cap_handover_broadcast_to_unicast_param_t;
/** Callback structure for CAP Commander procedures */
typedef struct bt_cap_commander_cb esp_ble_audio_cap_commander_cb_t;
/** CAP Commander broadcast audio member specific parameters for starting audio reception */
typedef struct bt_cap_commander_broadcast_reception_start_member_param \
esp_ble_audio_cap_commander_broadcast_reception_start_member_param_t;
/** CAP Commander broadcast audio specific parameters for starting audio reception */
typedef struct bt_cap_commander_broadcast_reception_start_param \
esp_ble_audio_cap_commander_broadcast_reception_start_param_t;
/** CAP Commander broadcast audio member specific parameters for stopping audio reception */
typedef struct bt_cap_commander_broadcast_reception_stop_member_param \
esp_ble_audio_cap_commander_broadcast_reception_stop_member_param_t;
/** CAP Commander broadcast audio specific parameters for stopping audio reception */
typedef struct bt_cap_commander_broadcast_reception_stop_param \
esp_ble_audio_cap_commander_broadcast_reception_stop_param_t;
/** CAP Commander member parameters for distributing broadcast code */
typedef struct bt_cap_commander_distribute_broadcast_code_member_param \
esp_ble_audio_cap_commander_distribute_broadcast_code_member_param_t;
/** Parameters for distributing broadcast code */
typedef struct bt_cap_commander_distribute_broadcast_code_param \
esp_ble_audio_cap_commander_distribute_broadcast_code_param_t;
/** Parameters for changing absolute volume */
typedef struct bt_cap_commander_change_volume_param \
esp_ble_audio_cap_commander_change_volume_param_t;
/** Parameters for changing volume offset for a member */
typedef struct bt_cap_commander_change_volume_offset_member_param \
esp_ble_audio_cap_commander_change_volume_offset_member_param_t;
/** Parameters for changing volume offset */
typedef struct bt_cap_commander_change_volume_offset_param \
esp_ble_audio_cap_commander_change_volume_offset_param_t;
/** Parameters for changing volume mute state */
typedef struct bt_cap_commander_change_volume_mute_state_param \
esp_ble_audio_cap_commander_change_volume_mute_state_param_t;
/** Parameters for changing microphone mute state */
typedef struct bt_cap_commander_change_microphone_mute_state_param \
esp_ble_audio_cap_commander_change_microphone_mute_state_param_t;
/** Parameters for changing microphone gain setting for a member */
typedef struct bt_cap_commander_change_microphone_gain_setting_member_param \
esp_ble_audio_cap_commander_change_microphone_gain_setting_member_param_t;
/** Parameters for changing microphone gain setting */
typedef struct bt_cap_commander_change_microphone_gain_setting_param \
esp_ble_audio_cap_commander_change_microphone_gain_setting_param_t;
/**
* @brief Register the Common Audio Service.
*
* This will register and enable the service and make it discoverable by
* clients. This will also register a Coordinated Set Identification
* Service instance.
*
* @param param Coordinated Set Identification Service register parameters.
* @param svc_inst Pointer to the registered Coordinated Set Identification Service.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_cap_acceptor_register(const esp_ble_audio_csip_set_member_register_param_t *param,
esp_ble_audio_csip_set_member_svc_inst_t **svc_inst);
/**
* @brief Discovers audio support on a remote device.
*
* This will discover the Common Audio Service (CAS) on the remote device, to
* verify if the remote device supports the Common Audio Profile.
*
* @param conn_handle Connection handle.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_cap_initiator_unicast_discover(uint16_t conn_handle);
/**
* @brief Register Audio operations for a Common Audio Profile stream.
*
* Register Audio operations for a stream.
*
* @param stream Stream object.
* @param ops Stream operations structure.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_cap_stream_ops_register(esp_ble_audio_cap_stream_t *stream,
esp_ble_audio_bap_stream_ops_t *ops);
/**
* @brief Send data to Common Audio Profile stream without timestamp.
*
* Sends data over the specified CAP audio stream with a sequence number.
*
* @param stream Stream object.
* @param sdu Buffer containing data to be sent.
* @param sdu_len Length of data to be sent.
* @param seq_num Packet Sequence number. This value shall be incremented
* for each call to this function and at least once per SDU
* interval for a specific channel.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_cap_stream_send(esp_ble_audio_cap_stream_t *stream,
const uint8_t *sdu, uint16_t sdu_len,
uint16_t seq_num);
/**
* @brief Send data to Common Audio Profile stream with timestamp.
*
* Sends data over the specified CAP audio stream with a sequence number.
*
* @param stream Stream object.
* @param sdu Buffer containing data to be sent.
* @param sdu_len Length of data to be sent.
* @param seq_num Packet Sequence number. This value shall be incremented
* for each call to this function and at least once per SDU
* interval for a specific channel.
* @param ts Timestamp of the SDU in microseconds (us). This value can
* be used to transmit multiple SDUs in the same SDU interval
* in a CIG or BIG.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_cap_stream_send_ts(esp_ble_audio_cap_stream_t *stream,
const uint8_t *sdu, uint16_t sdu_len,
uint16_t seq_num, uint32_t ts);
/**
* @brief Get ISO transmission timing info for a Common Audio Profile stream.
*
* @param stream Stream object.
* @param info Transmit info object.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_cap_stream_get_tx_sync(esp_ble_audio_cap_stream_t *stream,
esp_ble_iso_tx_info_t *info);
/**
* @brief Create unicast group.
*
* Create a new audio unicast group with one or more audio streams as a unicast client.
* All streams shall share the same framing.
* All streams in the same direction shall share the same interval and latency (see
* esp_ble_audio_bap_qos_cfg_t).
*
* @param param The unicast group create parameters.
* @param unicast_group Pointer to the unicast group created.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_cap_unicast_group_create(const esp_ble_audio_cap_unicast_group_param_t *param,
esp_ble_audio_cap_unicast_group_t **unicast_group);
/**
* @brief Reconfigure unicast group.
*
* Reconfigure a unicast group with one or more audio streams as a unicast client.
* All streams shall share the same framing.
* All streams in the same direction shall share the same interval and latency (see
* esp_ble_audio_bap_qos_cfg_t).
* All streams in @p param shall already belong to @p unicast_group.
* Use esp_ble_audio_cap_unicast_group_add_streams() to add additional streams.
*
* @param unicast_group Pointer to the unicast group created.
* @param param The unicast group reconfigure parameters.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_cap_unicast_group_reconfig(esp_ble_audio_cap_unicast_group_t *unicast_group,
const esp_ble_audio_cap_unicast_group_param_t *param);
/**
* @brief Add streams to a unicast group as a unicast client.
*
* This function can be used to add additional streams to a esp_ble_audio_cap_unicast_group_t.
*
* This can be called at any time before any of the streams in the group has been started
* (see esp_ble_audio_bap_stream_ops_t.started()).
* This can also be called after the streams have been stopped (see
* esp_ble_audio_bap_stream_ops_t.stopped()).
*
* Once a stream has been added to a unicast group, it cannot be removed. To remove a stream
* from a group, the group must be deleted with esp_ble_audio_cap_unicast_group_delete(), but
* this will require all streams in the group to be released first.
*
* @param unicast_group Pointer to the unicast group
* @param params Array of stream parameters with streams being added to the group.
* @param num_param Number of parameters in @p params.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_cap_unicast_group_add_streams(esp_ble_audio_cap_unicast_group_t *unicast_group,
const esp_ble_audio_cap_unicast_group_stream_pair_param_t params[],
size_t num_param);
/**
* @brief Delete audio unicast group.
*
* Delete a audio unicast group as a client. All streams in the group shall
* be in the idle or configured state.
*
* @param unicast_group Pointer to the unicast group to delete.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_cap_unicast_group_delete(esp_ble_audio_cap_unicast_group_t *unicast_group);
/**
* @brief Register Common Audio Profile Initiator callbacks.
*
* @param cb The callback structure. Shall remain static.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_cap_initiator_register_cb(const esp_ble_audio_cap_initiator_cb_t *cb);
/**
* @brief Unregister Common Audio Profile Initiator callbacks.
*
* @param cb The callback structure that was previously registered.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_cap_initiator_unregister_cb(const esp_ble_audio_cap_initiator_cb_t *cb);
/**
* @brief Setup and start unicast audio streams for a set of devices.
*
* @param param Parameters to start the audio streams.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_cap_initiator_unicast_audio_start(const esp_ble_audio_cap_unicast_audio_start_param_t *param);
/**
* @brief Update unicast audio streams.
*
* This will update the metadata of one or more streams.
*
* @param param Update parameters.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_cap_initiator_unicast_audio_update(const esp_ble_audio_cap_unicast_audio_update_param_t *param);
/**
* @brief Stop unicast audio streams.
*
* This will stop one or more streams.
*
* @param param Stop parameters.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_cap_initiator_unicast_audio_stop(const esp_ble_audio_cap_unicast_audio_stop_param_t *param);
/**
* @brief Cancel any current Common Audio Profile procedure.
*
* This will stop the current procedure from continuing and making it possible to run a new
* Common Audio Profile procedure.
*
* It is recommended to do this if any existing procedure takes longer time than expected, which
* could indicate a missing response from the Common Audio Profile Acceptor.
*
* This does not send any requests to any Common Audio Profile Acceptors involved with the current
* procedure, and thus notifications from the Common Audio Profile Acceptors may arrive after this
* has been called. It is thus recommended to either only use this if a procedure has stalled, or
* wait a short while before starting any new Common Audio Profile procedure after this has been
* called to avoid getting notifications from the cancelled procedure. The wait time depends on
* the connection interval, the number of devices in the previous procedure and the behavior of the
* Common Audio Profile Acceptors.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_cap_initiator_unicast_audio_cancel(void);
/**
* @brief Create a Common Audio Profile broadcast source.
*
* Create a new audio broadcast source with one or more audio streams.
*
* @param param Parameters to start the audio streams.
* @param broadcast_source Pointer to the broadcast source created.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_cap_initiator_broadcast_audio_create(const esp_ble_audio_cap_initiator_broadcast_create_param_t *param,
esp_ble_audio_cap_broadcast_source_t **broadcast_source);
/**
* @brief Start Common Audio Profile broadcast source.
*
* The broadcast source will be visible for scanners once this has been called,
* and the device will advertise audio announcements.
*
* @param broadcast_source Pointer to the broadcast source.
* @param adv_handle Handle of an extended advertising set with
* periodic advertising configured.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_cap_initiator_broadcast_audio_start(
esp_ble_audio_cap_broadcast_source_t *broadcast_source,
uint8_t adv_handle);
/**
* @brief Update broadcast audio streams for a Common Audio Profile broadcast source.
*
* @param broadcast_source The broadcast source to update.
* @param meta The new metadata. The metadata shall contain a list
* of CCIDs as well as a non-0 context bitfield.
* @param meta_len The length of @p meta.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_cap_initiator_broadcast_audio_update(esp_ble_audio_cap_broadcast_source_t *broadcast_source,
const uint8_t meta[], size_t meta_len);
/**
* @brief Stop broadcast audio streams for a Common Audio Profile broadcast source.
*
* @param broadcast_source The broadcast source to stop. The audio streams
* in this will be stopped and reset.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_cap_initiator_broadcast_audio_stop(esp_ble_audio_cap_broadcast_source_t *broadcast_source);
/**
* @brief Delete Common Audio Profile broadcast source.
*
* @param broadcast_source The broadcast source to delete.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_cap_initiator_broadcast_audio_delete(esp_ble_audio_cap_broadcast_source_t *broadcast_source);
/**
* @brief Get the Broadcast Audio Stream Endpoint of a Common Audio Profile
* broadcast source.
*
* This will encode the BASE of a broadcast source into a buffer, that can be
* used for advertisement. The encoded BASE will thus be encoded as
* little-endian. The BASE shall be put into the periodic advertising data.
*
* See table 3.15 in the Basic Audio Profile v1.0.1 for the structure.
*
* @param broadcast_source Pointer to the broadcast source.
* @param base_buf Pointer to a buffer where the BASE will be inserted.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_cap_initiator_broadcast_get_base(esp_ble_audio_cap_broadcast_source_t *broadcast_source,
struct net_buf_simple *base_buf);
/**
* @brief Register Common Audio Profile Handover callbacks.
*
* @param cb The callback structure. Shall remain static.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_cap_handover_register_cb(const esp_ble_audio_cap_handover_cb_t *cb);
/**
* @brief Unregister Common Audio Profile Handover callbacks.
*
* @param cb The callback structure that was previously registered.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_cap_handover_unregister_cb(const esp_ble_audio_cap_handover_cb_t *cb);
/**
* @brief Hands over the sink streams in a unicast group to a broadcast source.
*
* All streams in the provided unicast group will be stopped and released. The sink streams
* will be transferred to a broadcast source, and the broadcast source information will be
* shared with all accepters that are currently receiving audio. Any stream that is not in
* the streaming state will only be released.
*
* esp_ble_audio_bap_broadcast_assistant_discover() must have been successfully perform for
* all members in @p param before starting this procedure.
*
* @param param The parameters for the handover.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_cap_handover_unicast_to_broadcast(
const esp_ble_audio_cap_handover_unicast_to_broadcast_param_t *param);
/**
* @brief Hands over the data streams in a broadcast source to a unicast group.
*
* The streams in the broadcast source will be stopped and the broadcast source
* will be deleted.
*
* @param param The parameters for the handover.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_cap_handover_broadcast_to_unicast(
const esp_ble_audio_cap_handover_broadcast_to_unicast_param_t *param);
/**
* @brief Register Common Audio Profile Commander callbacks.
*
* @param cb The callback structure. Shall remain static.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_cap_commander_register_cb(const esp_ble_audio_cap_commander_cb_t *cb);
/**
* @brief Unregister Common Audio Profile Commander callbacks.
*
* @param cb The callback structure that was previously registered.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_cap_commander_unregister_cb(const esp_ble_audio_cap_commander_cb_t *cb);
/**
* @brief Discovers audio support on a remote device.
*
* This will discover the Common Audio Service (CAS) on the remote device,
* to verify if the remote device supports the Common Audio Profile.
*
* @param conn_handle Connection handle.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_cap_commander_discover(uint16_t conn_handle);
/**
* @brief Cancel any current Common Audio Profile commander procedure.
*
* This will stop the current procedure from continuing and making it possible to run a new
* Common Audio Profile procedure.
*
* It is recommended to do this if any existing procedure takes longer time than expected, which
* could indicate a missing response from the Common Audio Profile Acceptor.
*
* This does not send any requests to any Common Audio Profile Acceptors involved with the
* current procedure, and thus notifications from the Common Audio Profile Acceptors may
* arrive after this has been called. It is thus recommended to either only use this if a
* procedure has stalled, or wait a short while before starting any new Common Audio Profile
* procedure after this has been called to avoid getting notifications from the cancelled
* procedure. The wait time depends on the connection interval, the number of devices in the
* previous procedure and the behavior of the Common Audio Profile Acceptors.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_cap_commander_cancel(void);
/**
* @brief Starts the reception of broadcast audio on one or more remote
* Common Audio Profile Acceptors.
*
* @param param The parameters to start the broadcast audio
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_cap_commander_broadcast_reception_start(
const esp_ble_audio_cap_commander_broadcast_reception_start_param_t *param);
/**
* @brief Stops the reception of broadcast audio on one or more remote
* Common Audio Profile Acceptors.
*
* @param param The parameters to stop the broadcast audio
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_cap_commander_broadcast_reception_stop(
const esp_ble_audio_cap_commander_broadcast_reception_stop_param_t *param);
/**
* @brief Distributes the broadcast code on one or more remote Common
* Audio Profile Acceptors.
*
* @param param The parameters for distributing the broadcast code.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_cap_commander_distribute_broadcast_code(
const esp_ble_audio_cap_commander_distribute_broadcast_code_param_t *param);
/**
* @brief Change the volume on one or more Common Audio Profile Acceptors.
*
* @param param The parameters for the volume change.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_cap_commander_change_volume(
const esp_ble_audio_cap_commander_change_volume_param_t *param);
/**
* @brief Change the volume offset on one or more Common Audio Profile Acceptors.
*
* @param param The parameters for the volume offset change.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_cap_commander_change_volume_offset(
const esp_ble_audio_cap_commander_change_volume_offset_param_t *param);
/**
* @brief Change the volume mute state on one or more Common Audio Profile Acceptors.
*
* @param param The parameters for the volume mute state change.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_cap_commander_change_volume_mute_state(
const esp_ble_audio_cap_commander_change_volume_mute_state_param_t *param);
/**
* @brief Change the microphone mute state on one or more Common Audio Profile Acceptors.
*
* @param param The parameters for the microphone mute state change.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_cap_commander_change_microphone_mute_state(
const esp_ble_audio_cap_commander_change_microphone_mute_state_param_t *param);
/**
* @brief Change the microphone gain setting on one or more Common Audio Profile Acceptors.
*
* @param param The parameters for the microphone gain setting change.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_cap_commander_change_microphone_gain_setting(
const esp_ble_audio_cap_commander_change_microphone_gain_setting_param_t *param);
#ifdef __cplusplus
}
#endif
#endif /* ESP_BLE_AUDIO_CAP_API_H_ */
@@ -0,0 +1,171 @@
/*
* SPDX-FileCopyrightText: 2024 Nordic Semiconductor ASA
* SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ESP_BLE_AUDIO_CCP_API_H_
#define ESP_BLE_AUDIO_CCP_API_H_
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include "sdkconfig.h"
#include "esp_err.h"
#include <zephyr/bluetooth/audio/audio.h>
#include <zephyr/bluetooth/audio/ccp.h>
#include "common/init.h"
#include "common/host.h"
#include "esp_ble_audio_tbs_api.h"
#include "esp_ble_audio_common_api.h"
#ifdef __cplusplus
extern "C" {
#endif
/** Abstract Call Control Server Telephone Bearer structure */
typedef struct bt_ccp_call_control_server_bearer \
esp_ble_audio_ccp_call_control_server_bearer_t;
/** Abstract Call Control Client structure. */
typedef struct bt_ccp_call_control_client \
esp_ble_audio_ccp_call_control_client_t;
/** Abstract Call Control Client bearer structure. */
typedef struct bt_ccp_call_control_client_bearer \
esp_ble_audio_ccp_call_control_client_bearer_t;
/** Struct with information about bearers of a client */
typedef struct bt_ccp_call_control_client_bearers \
esp_ble_audio_ccp_call_control_client_bearers_t;
/** Struct to hold the Telephone Bearer Service client callbacks */
typedef struct bt_ccp_call_control_client_cb \
esp_ble_audio_ccp_call_control_client_cb_t;
/**
* @brief Register a Telephone Bearer.
*
* This will register a Telephone Bearer Service (TBS) (or a Generic Telephone
* Bearer service (GTBS)) with the provided parameters.
*
* As per the TBS specification, the GTBS shall be instantiated for the feature,
* and as such a GTBS shall always be registered before any TBS can be registered.
* Similarly, all TBS shall be unregistered before the GTBS can be unregistered
* with esp_ble_audio_ccp_call_control_server_unregister_bearer().
*
* @param param The parameters to initialize the bearer.
* @param bearer Pointer to the initialized bearer.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_ccp_call_control_server_register_bearer(
const esp_ble_audio_tbs_register_param_t *param,
esp_ble_audio_ccp_call_control_server_bearer_t **bearer);
/**
* @brief Unregister a Telephone Bearer.
*
* This will unregister a Telephone Bearer Service (TBS) (or a Generic Telephone
* Bearer service (GTBS)) with the provided parameters. The bearer shall be
* registered first by esp_ble_audio_ccp_call_control_server_register_bearer()
* before it can be unregistered.
*
* All TBS shall be unregistered before the GTBS can be unregistered with.
*
* @param bearer The bearer to unregister.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_ccp_call_control_server_unregister_bearer(
esp_ble_audio_ccp_call_control_server_bearer_t *bearer);
/**
* @brief Set a new bearer provider name.
*
* @param bearer The bearer to set the name for.
* @param name The new bearer provider name.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_ccp_call_control_server_set_bearer_provider_name(
esp_ble_audio_ccp_call_control_server_bearer_t *bearer, const char *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.
*
* @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);
/**
* @brief Discovers the Telephone Bearer Service (TBS) support on a remote device.
*
* This will discover the Telephone Bearer Service (TBS) and Generic Telephone Bearer
* Service (GTBS) on the remote device.
*
* @param conn Connection to a remote server.
* @param out_client Pointer to client instance on success.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_ccp_call_control_client_discover(
esp_ble_conn_t *conn, esp_ble_audio_ccp_call_control_client_t **out_client);
/**
* @brief Register callbacks for the Call Control Client.
*
* @param cb The callback struct.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_ccp_call_control_client_register_cb(
esp_ble_audio_ccp_call_control_client_cb_t *cb);
/**
* @brief Unregister callbacks for the Call Control Client.
*
* @param cb The callback struct.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_ccp_call_control_client_unregister_cb(
esp_ble_audio_ccp_call_control_client_cb_t *cb);
/**
* @brief Get the bearers of a client instance.
*
* @param client The client to get the bearers of.
* @param bearers The bearers struct that will be populated
* with the bearers of @p client.
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_ccp_call_control_client_get_bearers(
esp_ble_audio_ccp_call_control_client_t *client,
esp_ble_audio_ccp_call_control_client_bearers_t *bearers);
/**
* @brief Read the bearer provider name of a remote TBS bearer.
*
* @param bearer The bearer to read the name from.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_ccp_call_control_client_read_bearer_provider_name(
esp_ble_audio_ccp_call_control_client_bearer_t *bearer);
#ifdef __cplusplus
}
#endif
#endif /* ESP_BLE_AUDIO_CCP_API_H_ */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,172 @@
/*
* SPDX-FileCopyrightText: 2020 Intel Corporation
* SPDX-FileCopyrightText: 2020-2024 Nordic Semiconductor ASA
* SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ESP_BLE_AUDIO_COMMON_API_H_
#define ESP_BLE_AUDIO_COMMON_API_H_
#include <stdint.h>
#include <string.h>
#include <stddef.h>
#include <stdbool.h>
#include "sdkconfig.h"
#include "esp_err.h"
#include "common/init.h"
#include "common/host.h"
#include "common/app/gatt.h"
#include "esp_ble_iso_common_api.h"
#include "esp_ble_audio_defs.h"
#include "esp_ble_audio_csip_api.h"
#include "esp_ble_audio_vcp_api.h"
#include "esp_ble_audio_micp_api.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Helper for parsing length-type-value data.
*
* @param ltv Length-type-value (LTV) encoded data.
* @param size Size of the @p ltv data.
* @param func Callback function which will be called for each element
* that's found in the data. The callback should return
* true to continue parsing, or false to stop parsing.
* @param user_data User data to be passed to the callback.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_data_parse(const uint8_t ltv[], size_t size,
bool (*func)(uint8_t type,
const uint8_t *data,
uint8_t data_len,
void *user_data),
void *user_data);
/**
* @brief Get the value of a specific data type in an length-type-value data array.
*
* @param ltv_data The array containing the length-type-value tuples.
* @param size The size of @p ltv_data.
* @param type The type to get the value for.
* @param data Pointer to the data-pointer to update when item is found.
* Any found data will be little endian.
* @param data_len Length The length of found @p data (may be 0).
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_data_get_val(const uint8_t ltv_data[],
size_t size, uint8_t type,
const uint8_t **data,
uint8_t *data_len);
/**
* @brief Function to get the number of channels from the channel allocation.
*
* @param chan_allocation The channel allocation.
*
* @return The number of channels.
*/
uint8_t esp_ble_audio_get_chan_count(esp_ble_audio_location_t chan_allocation);
/**
* @brief Start GATT service discovery.
*
* @note This function is only needed while using NimBLE Host.
*
* @param conn_handle Connection Handle.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_gattc_disc_start(uint16_t conn_handle);
/*!< Audio GAP Extended Scan Recv event */
#define ESP_BLE_AUDIO_GAP_EVENT_EXT_SCAN_RECV BT_LE_GAP_APP_EVENT_EXT_SCAN_RECV
/*!< Audio GAP Periodic Sync Established event */
#define ESP_BLE_AUDIO_GAP_EVENT_PA_SYNC BT_LE_GAP_APP_EVENT_PA_SYNC
/*!< Audio GAP Periodic Sync Lost event */
#define ESP_BLE_AUDIO_GAP_EVENT_PA_SYNC_LOST BT_LE_GAP_APP_EVENT_PA_SYNC_LOST
/*!< Audio GAP Connection Complete event */
#define ESP_BLE_AUDIO_GAP_EVENT_ACL_CONNECT BT_LE_GAP_APP_EVENT_ACL_CONNECT
/*!< Audio GAP Disconnection Complete event */
#define ESP_BLE_AUDIO_GAP_EVENT_ACL_DISCONNECT BT_LE_GAP_APP_EVENT_ACL_DISCONNECT
/*!< Audio GAP Security Change event */
#define ESP_BLE_AUDIO_GAP_EVENT_SECURITY_CHANGE BT_LE_GAP_APP_EVENT_SECURITY_CHANGE
/** Audio GAP application event structure */
typedef struct bt_le_gap_app_event esp_ble_audio_gap_app_event_t;
/*!< Audio GATT MTU exchange complete event */
#define ESP_BLE_AUDIO_GATT_EVENT_GATT_MTU_CHANGE BT_LE_GATT_APP_EVENT_GATT_MTU_CHANGE
/*!< Audio GATT client discovery complete event */
#define ESP_BLE_AUDIO_GATT_EVENT_GATTC_DISC_CMPL BT_LE_GATT_APP_EVENT_GATTC_DISC_CMPL
/** Audio GATT application event structure */
typedef struct bt_le_gatt_app_event esp_ble_audio_gatt_app_event_t;
/** Contains callback functions for GAP and GATT events */
typedef struct {
bt_le_gap_app_cb gap_cb; /*!< GAP event callbacks */
bt_le_gatt_app_cb gatt_cb; /*!< GATT event callbacks */
} esp_ble_audio_init_info_t;
/**
* @brief Post an application-layer GAP event for audio internal usage.
*
* @note This function is only needed while using NimBLE Host.
*
* @param type Event type.
* @param param Event parameters.
*/
void esp_ble_audio_gap_app_post_event(uint8_t type, void *param);
/**
* @brief Post an application-layer GATT event for audio internal usage.
*
* @note This function is only needed while using NimBLE Host.
*
* @param type Event type.
* @param param Event parameters.
*/
void esp_ble_audio_gatt_app_post_event(uint8_t type, void *param);
/**
* @brief Initialize BLE Audio common functionality.
*
* @param info Initialization parameters.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_common_init(esp_ble_audio_init_info_t *info);
/** Contains service instances for audio profiles */
typedef struct {
#if CONFIG_BT_CSIP_SET_MEMBER
struct {
esp_ble_audio_csip_set_member_svc_inst_t *svc_inst; /*!< Pointer of CSIS Service instance */
bool included_by_cas; /*!< Indicate if the CSIS Service is included by CAS */
} csis_insts[CONFIG_BT_CSIP_SET_MEMBER_MAX_INSTANCE_COUNT]; /*!< Structures of CSIS Service instances */
#endif /* CONFIG_BT_CSIP_SET_MEMBER */
uint8_t dummy; /*!< Dummy field to avoid empty struct */
} esp_ble_audio_start_info_t;
/**
* @brief Start BLE Audio services.
*
* @param info Service instances to start.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_common_start(esp_ble_audio_start_info_t *info);
#ifdef __cplusplus
}
#endif
#endif /* ESP_BLE_AUDIO_COMMON_API_H_ */
@@ -0,0 +1,294 @@
/*
* SPDX-FileCopyrightText: 2021-2024 Nordic Semiconductor ASA
* SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ESP_BLE_AUDIO_CSIP_API_H_
#define ESP_BLE_AUDIO_CSIP_API_H_
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include "sdkconfig.h"
#include "esp_err.h"
#include <zephyr/bluetooth/audio/audio.h>
#include <zephyr/bluetooth/audio/csip.h>
#include "common/init.h"
#include "common/host.h"
#ifdef __cplusplus
extern "C" {
#endif
/*!< Size of the Set Identification Resolving Key (SIRK) */
#define ESP_BLE_AUDIO_CSIP_SIRK_SIZE BT_CSIP_SIRK_SIZE
/*!< Size of the Resolvable Set Identifier (RSI) */
#define ESP_BLE_AUDIO_CSIP_RSI_SIZE BT_CSIP_RSI_SIZE
/*!< Accept the request to read the SIRK as plaintext */
#define ESP_BLE_AUDIO_CSIP_READ_SIRK_REQ_RSP_ACCEPT BT_CSIP_READ_SIRK_REQ_RSP_ACCEPT
/*!< Accept the request to read the SIRK, but return encrypted SIRK */
#define ESP_BLE_AUDIO_CSIP_READ_SIRK_REQ_RSP_ACCEPT_ENC BT_CSIP_READ_SIRK_REQ_RSP_ACCEPT_ENC
/*!< Reject the request to read the SIRK */
#define ESP_BLE_AUDIO_CSIP_READ_SIRK_REQ_RSP_REJECT BT_CSIP_READ_SIRK_REQ_RSP_REJECT
/*!< SIRK is available only via an OOB procedure */
#define ESP_BLE_AUDIO_CSIP_READ_SIRK_REQ_RSP_OOB_ONLY BT_CSIP_READ_SIRK_REQ_RSP_OOB_ONLY
/**
* @brief Helper to declare bt_data array including RSI.
*
* This macro is mainly for creating an array of struct bt_data elements.
*
* @param _rsi Pointer to the RSI value.
*/
#define ESP_BLE_AUDIO_CSIP_DATA_RSI(_rsi) BT_CSIP_DATA_RSI(_rsi)
/** Callback structure for the Coordinated Set Identification Service */
typedef struct bt_csip_set_member_cb esp_ble_audio_csip_set_member_cb_t;
/** Coordinated Set Identification Service instance */
typedef struct bt_csip_set_member_svc_inst esp_ble_audio_csip_set_member_svc_inst_t;
/** Register structure for Coordinated Set Identification Service */
typedef struct bt_csip_set_member_register_param esp_ble_audio_csip_set_member_register_param_t;
/** Struct to hold information about a service instance */
typedef struct bt_csip_set_member_set_info esp_ble_audio_csip_set_member_set_info_t;
/** Struct to hold the Coordinated Set Identification Profile Set Coordinator callbacks */
typedef struct bt_csip_set_coordinator_cb esp_ble_audio_csip_set_coordinator_cb_t;
/** Information about a specific set */
typedef struct bt_csip_set_coordinator_set_info esp_ble_audio_csip_set_coordinator_set_info_t;
/** Struct representing a coordinated set instance on a remote device */
typedef struct bt_csip_set_coordinator_csis_inst esp_ble_audio_csip_set_coordinator_csis_inst_t;
/** Struct representing a remote device as a set member */
typedef struct bt_csip_set_coordinator_set_member esp_ble_audio_csip_set_coordinator_set_member_t;
/**
* @brief Get the service declaration attribute.
*
* The first service attribute can be included in any other GATT service.
*
* @param svc_inst Pointer to the Coordinated Set Identification Service.
*
* @return The first CSIS attribute instance.
*/
void *esp_ble_audio_csip_set_member_svc_decl_get(const esp_ble_audio_csip_set_member_svc_inst_t *svc_inst);
/**
* @brief Register a Coordinated Set Identification Service instance.
*
* This will register and enable the service and make it discoverable by clients.
*
* This shall only be done as a server.
*
* @param param Coordinated Set Identification Service register parameters.
* @param svc_inst Pointer to the registered Coordinated Set Identification Service.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_csip_set_member_register(const esp_ble_audio_csip_set_member_register_param_t *param,
esp_ble_audio_csip_set_member_svc_inst_t **svc_inst);
/**
* @brief Unregister a Coordinated Set Identification Service instance.
*
* This will unregister and disable the service instance.
*
* @param svc_inst Pointer to the registered Coordinated Set Identification Service.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_csip_set_member_unregister(esp_ble_audio_csip_set_member_svc_inst_t *svc_inst);
/**
* @brief Set the SIRK of a service instance.
*
* @param svc_inst Pointer to the registered Coordinated Set Identification Service.
* @param sirk The new SIRK.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_csip_set_member_sirk(esp_ble_audio_csip_set_member_svc_inst_t *svc_inst,
const uint8_t sirk[ESP_BLE_AUDIO_CSIP_SIRK_SIZE]);
/**
* @brief Set a new size and rank for a service instance.
*
* This function can be used to dynamically change the size and rank of a service instance.
* 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.
*
* If CONFIG_BT_CSIP_SET_MEMBER_SIZE_NOTIFIABLE is enabled, this will also send a notification
* to all connected or bonded clients.
*
* @param svc_inst The service instance.
* @param size The new set size.
* @param rank The new rank. Ignored if the @p svc_inst is not lockable.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_csip_set_member_set_size_and_rank(esp_ble_audio_csip_set_member_svc_inst_t *svc_inst,
uint8_t size, uint8_t rank);
/**
* @brief Get information about a service instances.
*
* @param svc_inst The service instance.
* @param info Pointer to a struct to store the information in.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_csip_set_member_get_info(const esp_ble_audio_csip_set_member_svc_inst_t *svc_inst,
esp_ble_audio_csip_set_member_set_info_t *info);
/**
* @brief Generate the Resolvable Set Identifier (RSI) value.
*
* This will generate RSI for given @p svc_inst instance.
*
* @param svc_inst Pointer to the Coordinated Set Identification Service.
* @param rsi Pointer to the 6-octet newly generated RSI data in little-endian.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_csip_set_member_generate_rsi(const esp_ble_audio_csip_set_member_svc_inst_t *svc_inst,
uint8_t rsi[ESP_BLE_AUDIO_CSIP_RSI_SIZE]);
/**
* @brief Locks a specific Coordinated Set Identification Service instance on the server.
*
* @param svc_inst Pointer to the Coordinated Set Identification Service.
* @param lock If true lock the set, if false release the set.
* @param force This argument only have meaning when @p lock is false
* (release) and will force release the lock, regardless of who
* took the lock.
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_csip_set_member_lock(esp_ble_audio_csip_set_member_svc_inst_t *svc_inst,
bool lock, bool force);
/**
* @brief Initialise the csip_set_coordinator instance for a connection.
* This will do a discovery on the device and prepare the instance
* for following commands.
*
* @param conn_handle Connection handle.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_csip_set_coordinator_discover(uint16_t conn_handle);
/**
* @brief Get the set member from a connection pointer.
*
* Get the Coordinated Set Identification Profile Set Coordinator pointer
* from connection handle.
* Only Set Coordinators that have been initiated can be retrieved.
*
* @param conn_handle Connection handle.
*
* @return Pointer to a Coordinated Set Identification Profile Set Coordinator instance.
* NULL if the connection has not been found or has not done discovery yet.
*/
esp_ble_audio_csip_set_coordinator_set_member_t *
esp_ble_audio_csip_set_coordinator_set_member_by_conn(uint16_t conn_handle);
/**
* @brief Check if advertising data indicates a set member.
*
* @param sirk The SIRK of the set to check against.
* @param data_type Type of the advertising data.
* @param data Pointer of the advertising data.
* @param data_len Length of the advertising data.
*
* @return True if the advertising data indicates a set member, false otherwise.
*/
bool esp_ble_audio_csip_set_coordinator_is_set_member(const uint8_t sirk[ESP_BLE_AUDIO_CSIP_SIRK_SIZE],
uint8_t data_type, const uint8_t *data, uint8_t data_len);
/**
* @brief Registers callbacks for csip_set_coordinator.
*
* @param cb Pointer to the callback structure.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_csip_set_coordinator_register_cb(esp_ble_audio_csip_set_coordinator_cb_t *cb);
/**
* @brief Access Coordinated Set devices in an ordered manner as a client.
*
* This function will read the lock state of all devices and if all devices are
* in the unlocked state, then @p cb will be called with the same members as
* provided by @p members, but where the members are ordered by rank (if present).
*
* This procedure only works if all the members have the lock characteristic,
* and all either has rank = 0 or unique ranks.
*
* If any of the members are in the locked state, the procedure will be cancelled.
*
* This can only be done on members that are bonded.
*
* @param members Array of set members to access.
* @param count Number of set members in @p members.
* @param set_info Pointer to the a specific set_info struct, as a member may
* be part of multiple sets.
* @param cb The callback function to be called for each member.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_csip_set_coordinator_ordered_access(const esp_ble_audio_csip_set_coordinator_set_member_t *members[],
uint8_t count,
const esp_ble_audio_csip_set_coordinator_set_info_t *set_info,
bt_csip_set_coordinator_ordered_access_t cb);
/**
* @brief Lock an array of set members.
*
* The members will be locked starting from lowest rank going up.
*
* @param members Array of set members to lock.
* @param count Number of set members in @p members.
* @param set_info Pointer to the a specific set_info struct, as a member
* may be part of multiple sets.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_csip_set_coordinator_lock(const esp_ble_audio_csip_set_coordinator_set_member_t **members,
uint8_t count,
const esp_ble_audio_csip_set_coordinator_set_info_t *set_info);
/**
* @brief Release an array of set members.
*
* The members will be released starting from highest rank going down.
*
* @param members Array of set members to lock.
* @param count Number of set members in @p members.
* @param set_info Pointer to the a specific set_info struct, as a member
* may be part of multiple sets.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_csip_set_coordinator_release(const esp_ble_audio_csip_set_coordinator_set_member_t **members,
uint8_t count,
const esp_ble_audio_csip_set_coordinator_set_info_t *set_info);
#ifdef __cplusplus
}
#endif
#endif /* ESP_BLE_AUDIO_CSIP_API_H_ */
@@ -0,0 +1,567 @@
/*
* SPDX-FileCopyrightText: 2020 Intel Corporation
* SPDX-FileCopyrightText: 2020-2024 Nordic Semiconductor ASA
* SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ESP_BLE_AUDIO_DEFS_H_
#define ESP_BLE_AUDIO_DEFS_H_
#include <stdint.h>
#include <stdbool.h>
#include "sdkconfig.h"
#include <zephyr/bluetooth/audio/audio.h>
#ifdef __cplusplus
extern "C" {
#endif
/*!< Minimum ATT MTU size required by Basic Audio Profile (BAP) */
#define ESP_BLE_AUDIO_ATT_MTU_MIN 64
/**
* Audio direction sink.
*
* For a BAP Unicast Client or Broadcast Source this is considered outgoing audio (TX).
* For a BAP Unicast Server or Broadcast Sink this is considered incoming audio (RX).
*/
#define ESP_BLE_AUDIO_DIR_SINK BT_AUDIO_DIR_SINK
/**
* Audio direction source.
*
* For a BAP Unicast Client or Broadcast Source this is considered incoming audio (RX).
* For a BAP Unicast Server or Broadcast Sink this is considered outgoing audio (TX).
*/
#define ESP_BLE_AUDIO_DIR_SOURCE BT_AUDIO_DIR_SOURCE
/** Audio direction from the perspective of the BAP Unicast Server / BAP Broadcast Sink */
typedef enum bt_audio_dir esp_ble_audio_dir_t;
/*!< Size of the stream language value, e.g. "eng" */
#define ESP_BLE_AUDIO_LANG_SIZE BT_AUDIO_LANG_SIZE
/*!< Size of the broadcast ID in octets */
#define ESP_BLE_AUDIO_BROADCAST_ID_SIZE BT_AUDIO_BROADCAST_ID_SIZE
/*!< Maximum broadcast ID value */
#define ESP_BLE_AUDIO_BROADCAST_ID_MAX BT_AUDIO_BROADCAST_ID_MAX
/*!< Indicates that the server have no preference for the presentation delay */
#define ESP_BLE_AUDIO_PD_PREF_NONE BT_AUDIO_PD_PREF_NONE
/*!< Maximum presentation delay in microseconds */
#define ESP_BLE_AUDIO_PD_MAX BT_AUDIO_PD_MAX
/*!< Indicates that the unicast server does not have a preference for any retransmission number */
#define ESP_BLE_AUDIO_RTN_PREF_NONE BT_AUDIO_RTN_PREF_NONE
/*!< The minimum size of a Broadcast Name as defined by Bluetooth Assigned Numbers */
#define ESP_BLE_AUDIO_BROADCAST_NAME_LEN_MIN BT_AUDIO_BROADCAST_NAME_LEN_MIN
/*!< The maximum size of a Broadcast Name as defined by Bluetooth Assigned Numbers */
#define ESP_BLE_AUDIO_BROADCAST_NAME_LEN_MAX BT_AUDIO_BROADCAST_NAME_LEN_MAX
/*!< Unicast Server is connectable and is requesting a connection. */
#define ESP_BLE_AUDIO_UNICAST_ANNOUNCEMENT_GENERAL BT_AUDIO_UNICAST_ANNOUNCEMENT_GENERAL
/*!< Unicast Server is connectable but is not requesting a connection. */
#define ESP_BLE_AUDIO_UNICAST_ANNOUNCEMENT_TARGETED BT_AUDIO_UNICAST_ANNOUNCEMENT_TARGETED
/*!< No context type */
#define ESP_BLE_AUDIO_CONTEXT_TYPE_NONE BT_AUDIO_CONTEXT_TYPE_NONE
/**
* Identifies audio where the use case context does not match any other defined value,
* or where the context is unknown or cannot be determined.
*/
#define ESP_BLE_AUDIO_CONTEXT_TYPE_UNSPECIFIED BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED
/**
* Conversation between humans, for example, in telephony or video calls, including
* traditional cellular as well as VoIP and Push-to-Talk
*/
#define ESP_BLE_AUDIO_CONTEXT_TYPE_CONVERSATIONAL BT_AUDIO_CONTEXT_TYPE_CONVERSATIONAL
/*!< Media, for example, music playback, radio, podcast or movie soundtrack, or tv audio */
#define ESP_BLE_AUDIO_CONTEXT_TYPE_MEDIA BT_AUDIO_CONTEXT_TYPE_MEDIA
/**
* Audio associated with video gaming, for example gaming media; gaming effects; music
* and in-game voice chat between participants; or a mix of all the above
*/
#define ESP_BLE_AUDIO_CONTEXT_TYPE_GAME BT_AUDIO_CONTEXT_TYPE_GAME
/*!< Instructional audio, for example, in navigation, announcements, or user guidance */
#define ESP_BLE_AUDIO_CONTEXT_TYPE_INSTRUCTIONAL BT_AUDIO_CONTEXT_TYPE_INSTRUCTIONAL
/*!< Man-machine communication, for example, with voice recognition or virtual assistants */
#define ESP_BLE_AUDIO_CONTEXT_TYPE_VOICE_ASSISTANTS BT_AUDIO_CONTEXT_TYPE_VOICE_ASSISTANTS
/**
* Live audio, for example, from a microphone where audio is perceived both through a
* direct acoustic path and through an LE Audio Stream
*/
#define ESP_BLE_AUDIO_CONTEXT_TYPE_LIVE BT_AUDIO_CONTEXT_TYPE_LIVE
/**
* Sound effects including keyboard and touch feedback; menu and user interface sounds;
* and other system sounds
*/
#define ESP_BLE_AUDIO_CONTEXT_TYPE_SOUND_EFFECTS BT_AUDIO_CONTEXT_TYPE_SOUND_EFFECTS
/**
* Notification and reminder sounds; attention-seeking audio, for example,
* in beeps signaling the arrival of a message
*/
#define ESP_BLE_AUDIO_CONTEXT_TYPE_NOTIFICATIONS BT_AUDIO_CONTEXT_TYPE_NOTIFICATIONS
/**
* Alerts the user to an incoming call, for example, an incoming telephony or video call,
* including traditional cellular as well as VoIP and Push-to-Talk
*/
#define ESP_BLE_AUDIO_CONTEXT_TYPE_RINGTONE BT_AUDIO_CONTEXT_TYPE_RINGTONE
/**
* Alarms and timers; immediate alerts, for example, in a critical battery alarm,
* timer expiry or alarm clock, toaster, cooker, kettle, microwave, etc.
*/
#define ESP_BLE_AUDIO_CONTEXT_TYPE_ALERTS BT_AUDIO_CONTEXT_TYPE_ALERTS
/*!< Emergency alarm Emergency sounds, for example, fire alarms or other urgent alerts */
#define ESP_BLE_AUDIO_CONTEXT_TYPE_EMERGENCY_ALARM BT_AUDIO_CONTEXT_TYPE_EMERGENCY_ALARM
/*!< Any known context */
#define ESP_BLE_AUDIO_CONTEXT_TYPE_ANY BT_AUDIO_CONTEXT_TYPE_ANY
/** Audio Context Type for Generic Audio */
typedef enum bt_audio_context esp_ble_audio_context_t;
/*!< No rating */
#define ESP_BLE_AUDIO_PARENTAL_RATING_NO_RATING BT_AUDIO_PARENTAL_RATING_NO_RATING
/*!< For all ages */
#define ESP_BLE_AUDIO_PARENTAL_RATING_AGE_ANY BT_AUDIO_PARENTAL_RATING_AGE_ANY
/*!< Recommended for listeners of age 5 and above */
#define ESP_BLE_AUDIO_PARENTAL_RATING_AGE_5_OR_ABOVE BT_AUDIO_PARENTAL_RATING_AGE_5_OR_ABOVE
/*!< Recommended for listeners of age 6 and above */
#define ESP_BLE_AUDIO_PARENTAL_RATING_AGE_6_OR_ABOVE BT_AUDIO_PARENTAL_RATING_AGE_6_OR_ABOVE
/*!< Recommended for listeners of age 7 and above */
#define ESP_BLE_AUDIO_PARENTAL_RATING_AGE_7_OR_ABOVE BT_AUDIO_PARENTAL_RATING_AGE_7_OR_ABOVE
/*!< Recommended for listeners of age 8 and above */
#define ESP_BLE_AUDIO_PARENTAL_RATING_AGE_8_OR_ABOVE BT_AUDIO_PARENTAL_RATING_AGE_8_OR_ABOVE
/*!< Recommended for listeners of age 9 and above */
#define ESP_BLE_AUDIO_PARENTAL_RATING_AGE_9_OR_ABOVE BT_AUDIO_PARENTAL_RATING_AGE_9_OR_ABOVE
/*!< Recommended for listeners of age 10 and above */
#define ESP_BLE_AUDIO_PARENTAL_RATING_AGE_10_OR_ABOVE BT_AUDIO_PARENTAL_RATING_AGE_10_OR_ABOVE
/*!< Recommended for listeners of age 11 and above */
#define ESP_BLE_AUDIO_PARENTAL_RATING_AGE_11_OR_ABOVE BT_AUDIO_PARENTAL_RATING_AGE_11_OR_ABOVE
/*!< Recommended for listeners of age 12 and above */
#define ESP_BLE_AUDIO_PARENTAL_RATING_AGE_12_OR_ABOVE BT_AUDIO_PARENTAL_RATING_AGE_12_OR_ABOVE
/*!< Recommended for listeners of age 13 and above */
#define ESP_BLE_AUDIO_PARENTAL_RATING_AGE_13_OR_ABOVE BT_AUDIO_PARENTAL_RATING_AGE_13_OR_ABOVE
/*!< Recommended for listeners of age 14 and above */
#define ESP_BLE_AUDIO_PARENTAL_RATING_AGE_14_OR_ABOVE BT_AUDIO_PARENTAL_RATING_AGE_14_OR_ABOVE
/*!< Recommended for listeners of age 15 and above */
#define ESP_BLE_AUDIO_PARENTAL_RATING_AGE_15_OR_ABOVE BT_AUDIO_PARENTAL_RATING_AGE_15_OR_ABOVE
/*!< Recommended for listeners of age 16 and above */
#define ESP_BLE_AUDIO_PARENTAL_RATING_AGE_16_OR_ABOVE BT_AUDIO_PARENTAL_RATING_AGE_16_OR_ABOVE
/*!< Recommended for listeners of age 17 and above */
#define ESP_BLE_AUDIO_PARENTAL_RATING_AGE_17_OR_ABOVE BT_AUDIO_PARENTAL_RATING_AGE_17_OR_ABOVE
/*!< Recommended for listeners of age 18 and above */
#define ESP_BLE_AUDIO_PARENTAL_RATING_AGE_18_OR_ABOVE BT_AUDIO_PARENTAL_RATING_AGE_18_OR_ABOVE
/** Parental rating defined by the Generic Audio assigned numbers */
typedef enum bt_audio_parental_rating esp_ble_audio_parental_rating_t;
/*!< No audio data is being transmitted */
#define ESP_BLE_AUDIO_ACTIVE_STATE_DISABLED BT_AUDIO_ACTIVE_STATE_DISABLED
/*!< Audio data is being transmitted */
#define ESP_BLE_AUDIO_ACTIVE_STATE_ENABLED BT_AUDIO_ACTIVE_STATE_ENABLED
/** Audio Active State defined by the Generic Audio assigned numbers */
typedef enum bt_audio_active_state esp_ble_audio_active_state_t;
/*!< Preferred audio context */
#define ESP_BLE_AUDIO_METADATA_TYPE_PREF_CONTEXT BT_AUDIO_METADATA_TYPE_PREF_CONTEXT
/*!< Streaming audio context */
#define ESP_BLE_AUDIO_METADATA_TYPE_STREAM_CONTEXT BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT
/*!< UTF-8 encoded title or summary of stream content */
#define ESP_BLE_AUDIO_METADATA_TYPE_PROGRAM_INFO BT_AUDIO_METADATA_TYPE_PROGRAM_INFO
/*!< Language */
#define ESP_BLE_AUDIO_METADATA_TYPE_LANG BT_AUDIO_METADATA_TYPE_LANG
/*!< Array of 8-bit CCID values */
#define ESP_BLE_AUDIO_METADATA_TYPE_CCID_LIST BT_AUDIO_METADATA_TYPE_CCID_LIST
/*!< Parental rating */
#define ESP_BLE_AUDIO_METADATA_TYPE_PARENTAL_RATING BT_AUDIO_METADATA_TYPE_PARENTAL_RATING
/*!< UTF-8 encoded URI for additional Program information */
#define ESP_BLE_AUDIO_METADATA_TYPE_PROGRAM_INFO_URI BT_AUDIO_METADATA_TYPE_PROGRAM_INFO_URI
/*!< Audio active state */
#define ESP_BLE_AUDIO_METADATA_TYPE_AUDIO_STATE BT_AUDIO_METADATA_TYPE_AUDIO_STATE
/*!< Broadcast Audio Immediate Rendering flag */
#define ESP_BLE_AUDIO_METADATA_TYPE_BROADCAST_IMMEDIATE BT_AUDIO_METADATA_TYPE_BROADCAST_IMMEDIATE
/*!< Assisted listening stream */
#define ESP_BLE_AUDIO_METADATA_TYPE_ASSISTED_LISTENING_STREAM BT_AUDIO_METADATA_TYPE_ASSISTED_LISTENING_STREAM
/*!< UTF-8 encoded Broadcast name */
#define ESP_BLE_AUDIO_METADATA_TYPE_BROADCAST_NAME BT_AUDIO_METADATA_TYPE_BROADCAST_NAME
/*!< Extended metadata */
#define ESP_BLE_AUDIO_METADATA_TYPE_EXTENDED BT_AUDIO_METADATA_TYPE_EXTENDED
/*!< Vendor specific metadata */
#define ESP_BLE_AUDIO_METADATA_TYPE_VENDOR BT_AUDIO_METADATA_TYPE_VENDOR
/**
* @brief Helper to check whether metadata type is known by the stack.
*
* @param _type Metadata type.
*/
#define ESP_BLE_AUDIO_METADATA_TYPE_IS_KNOWN(_type) \
BT_AUDIO_METADATA_TYPE_IS_KNOWN(_type)
/** Metadata types defined by the Generic Audio assigned numbers */
typedef enum bt_audio_metadata_type esp_ble_audio_metadata_type_t;
/*!< Mono Audio (no specified Audio Location) */
#define ESP_BLE_AUDIO_LOCATION_MONO_AUDIO BT_AUDIO_LOCATION_MONO_AUDIO
/*!< Front Left */
#define ESP_BLE_AUDIO_LOCATION_FRONT_LEFT BT_AUDIO_LOCATION_FRONT_LEFT
/*!< Front Right */
#define ESP_BLE_AUDIO_LOCATION_FRONT_RIGHT BT_AUDIO_LOCATION_FRONT_RIGHT
/*!< Front Center */
#define ESP_BLE_AUDIO_LOCATION_FRONT_CENTER BT_AUDIO_LOCATION_FRONT_CENTER
/*!< Low Frequency Effects 1 */
#define ESP_BLE_AUDIO_LOCATION_LOW_FREQ_EFFECTS_1 BT_AUDIO_LOCATION_LOW_FREQ_EFFECTS_1
/*!< Back Left */
#define ESP_BLE_AUDIO_LOCATION_BACK_LEFT BT_AUDIO_LOCATION_BACK_LEFT
/*!< Back Right */
#define ESP_BLE_AUDIO_LOCATION_BACK_RIGHT BT_AUDIO_LOCATION_BACK_RIGHT
/*!< Front Left of Center */
#define ESP_BLE_AUDIO_LOCATION_FRONT_LEFT_OF_CENTER BT_AUDIO_LOCATION_FRONT_LEFT_OF_CENTER
/*!< Front Right of Center */
#define ESP_BLE_AUDIO_LOCATION_FRONT_RIGHT_OF_CENTER BT_AUDIO_LOCATION_FRONT_RIGHT_OF_CENTER
/*!< Back Center */
#define ESP_BLE_AUDIO_LOCATION_BACK_CENTER BT_AUDIO_LOCATION_BACK_CENTER
/*!< Low Frequency Effects 2 */
#define ESP_BLE_AUDIO_LOCATION_LOW_FREQ_EFFECTS_2 BT_AUDIO_LOCATION_LOW_FREQ_EFFECTS_2
/*!< Side Left */
#define ESP_BLE_AUDIO_LOCATION_SIDE_LEFT BT_AUDIO_LOCATION_SIDE_LEFT
/*!< Side Right */
#define ESP_BLE_AUDIO_LOCATION_SIDE_RIGHT BT_AUDIO_LOCATION_SIDE_RIGHT
/*!< Top Front Left */
#define ESP_BLE_AUDIO_LOCATION_TOP_FRONT_LEFT BT_AUDIO_LOCATION_TOP_FRONT_LEFT
/*!< Top Front Right */
#define ESP_BLE_AUDIO_LOCATION_TOP_FRONT_RIGHT BT_AUDIO_LOCATION_TOP_FRONT_RIGHT
/*!< Top Front Center */
#define ESP_BLE_AUDIO_LOCATION_TOP_FRONT_CENTER BT_AUDIO_LOCATION_TOP_FRONT_CENTER
/*!< Top Center */
#define ESP_BLE_AUDIO_LOCATION_TOP_CENTER BT_AUDIO_LOCATION_TOP_CENTER
/*!< Top Back Left */
#define ESP_BLE_AUDIO_LOCATION_TOP_BACK_LEFT BT_AUDIO_LOCATION_TOP_BACK_LEFT
/*!< Top Back Right */
#define ESP_BLE_AUDIO_LOCATION_TOP_BACK_RIGHT BT_AUDIO_LOCATION_TOP_BACK_RIGHT
/*!< Top Side Left */
#define ESP_BLE_AUDIO_LOCATION_TOP_SIDE_LEFT BT_AUDIO_LOCATION_TOP_SIDE_LEFT
/*!< Top Side Right */
#define ESP_BLE_AUDIO_LOCATION_TOP_SIDE_RIGHT BT_AUDIO_LOCATION_TOP_SIDE_RIGHT
/*!< Top Back Center */
#define ESP_BLE_AUDIO_LOCATION_TOP_BACK_CENTER BT_AUDIO_LOCATION_TOP_BACK_CENTER
/*!< Bottom Front Center */
#define ESP_BLE_AUDIO_LOCATION_BOTTOM_FRONT_CENTER BT_AUDIO_LOCATION_BOTTOM_FRONT_CENTER
/*!< Bottom Front Left */
#define ESP_BLE_AUDIO_LOCATION_BOTTOM_FRONT_LEFT BT_AUDIO_LOCATION_BOTTOM_FRONT_LEFT
/*!< Bottom Front Right */
#define ESP_BLE_AUDIO_LOCATION_BOTTOM_FRONT_RIGHT BT_AUDIO_LOCATION_BOTTOM_FRONT_RIGHT
/*!< Front Left Wide */
#define ESP_BLE_AUDIO_LOCATION_FRONT_LEFT_WIDE BT_AUDIO_LOCATION_FRONT_LEFT_WIDE
/*!< Front Right Wide */
#define ESP_BLE_AUDIO_LOCATION_FRONT_RIGHT_WIDE BT_AUDIO_LOCATION_FRONT_RIGHT_WIDE
/*!< Left Surround */
#define ESP_BLE_AUDIO_LOCATION_LEFT_SURROUND BT_AUDIO_LOCATION_LEFT_SURROUND
/*!< Right Surround */
#define ESP_BLE_AUDIO_LOCATION_RIGHT_SURROUND BT_AUDIO_LOCATION_RIGHT_SURROUND
/*!< Any known location */
#define ESP_BLE_AUDIO_LOCATION_ANY BT_AUDIO_LOCATION_ANY
/** Location values defined by the Generic Audio assigned numbers */
typedef enum bt_audio_location esp_ble_audio_location_t;
/*!< Unspecified audio enhancement */
#define ESP_BLE_AUDIO_ASSISTED_LISTENING_STREAM_UNSPECIFIED BT_AUDIO_ASSISTED_LISTENING_STREAM_UNSPECIFIED
/** Assisted Listening Stream defined by the Generic Audio assigned numbers */
typedef enum bt_audio_assisted_listening_stream esp_ble_audio_assisted_listening_stream_t;
/*!< Size in octets of a 16-bit UUID */
#define ESP_BLE_AUDIO_UUID_SIZE_16 BT_UUID_SIZE_16
/*!< Audio Input Control Service UUID value */
#define ESP_BLE_AUDIO_UUID_AICS_VAL BT_UUID_AICS_VAL
/*!< Audio Stream Control Service UUID value */
#define ESP_BLE_AUDIO_UUID_ASCS_VAL BT_UUID_ASCS_VAL
/*!< Broadcast Audio Scan Service UUID value */
#define ESP_BLE_AUDIO_UUID_BASS_VAL BT_UUID_BASS_VAL
/*!< Basic Audio Announcement Service UUID value */
#define ESP_BLE_AUDIO_UUID_BASIC_AUDIO_VAL BT_UUID_BASIC_AUDIO_VAL
/*!< Broadcast Audio Announcement Service UUID value */
#define ESP_BLE_AUDIO_UUID_BROADCAST_AUDIO_VAL BT_UUID_BROADCAST_AUDIO_VAL
/*!< Common Audio Service UUID value */
#define ESP_BLE_AUDIO_UUID_CAS_VAL BT_UUID_CAS_VAL
/*!< Coordinated Set Identification Service UUID value */
#define ESP_BLE_AUDIO_UUID_CSIS_VAL BT_UUID_CSIS_VAL
/*!< Gaming Service UUID value */
#define ESP_BLE_AUDIO_UUID_GMAS_VAL BT_UUID_GMAS_VAL
/*!< Generic Media Control Service UUID value */
#define ESP_BLE_AUDIO_UUID_GMCS_VAL BT_UUID_GMCS_VAL
/*!< Generic Telephone Bearer Service UUID value */
#define ESP_BLE_AUDIO_UUID_GTBS_VAL BT_UUID_GTBS_VAL
/*!< Hearing Access Service UUID value */
#define ESP_BLE_AUDIO_UUID_HAS_VAL BT_UUID_HAS_VAL
/*!< Media Control Service UUID value */
#define ESP_BLE_AUDIO_UUID_MCS_VAL BT_UUID_MCS_VAL
/*!< Microphone Control Service UUID value */
#define ESP_BLE_AUDIO_UUID_MICS_VAL BT_UUID_MICS_VAL
/*!< Published Audio Capabilities Service UUID value */
#define ESP_BLE_AUDIO_UUID_PACS_VAL BT_UUID_PACS_VAL
/*!< Public Broadcast Announcement Service UUID value */
#define ESP_BLE_AUDIO_UUID_PBA_VAL BT_UUID_PBA_VAL
/*!< Telephone Bearer Service UUID value */
#define ESP_BLE_AUDIO_UUID_TBS_VAL BT_UUID_TBS_VAL
/*!< Telephony and Media Audio Service UUID value */
#define ESP_BLE_AUDIO_UUID_TMAS_VAL BT_UUID_TMAS_VAL
/*!< Volume Control Service UUID value */
#define ESP_BLE_AUDIO_UUID_VCS_VAL BT_UUID_VCS_VAL
/*!< Volume Offset Control Service UUID value */
#define ESP_BLE_AUDIO_UUID_VOCS_VAL BT_UUID_VOCS_VAL
/*!< Object Transfer Service UUID value */
#define ESP_BLE_AUDIO_UUID_OTS_VAL BT_UUID_OTS_VAL
/*!< Audio Input Control Service State value */
#define ESP_BLE_AUDIO_UUID_AICS_STATE_VAL BT_UUID_AICS_STATE_VAL
/*!< Audio Input Control Service Gain Settings Properties value */
#define ESP_BLE_AUDIO_UUID_AICS_GAIN_SETTINGS_VAL BT_UUID_AICS_GAIN_SETTINGS_VAL
/*!< Audio Input Control Service Input Type value */
#define ESP_BLE_AUDIO_UUID_AICS_INPUT_TYPE_VAL BT_UUID_AICS_INPUT_TYPE_VAL
/*!< Audio Input Control Service Input Status value */
#define ESP_BLE_AUDIO_UUID_AICS_INPUT_STATUS_VAL BT_UUID_AICS_INPUT_STATUS_VAL
/*!< Audio Input Control Service Control Point value */
#define ESP_BLE_AUDIO_UUID_AICS_CONTROL_VAL BT_UUID_AICS_CONTROL_VAL
/*!< Audio Input Control Service Input Description value */
#define ESP_BLE_AUDIO_UUID_AICS_DESCRIPTION_VAL BT_UUID_AICS_DESCRIPTION_VAL
/*!< Audio Stream Endpoint Sink Characteristic value */
#define ESP_BLE_AUDIO_UUID_ASCS_ASE_SNK_VAL BT_UUID_ASCS_ASE_SNK_VAL
/*!< Audio Stream Endpoint Source Characteristic value */
#define ESP_BLE_AUDIO_UUID_ASCS_ASE_SRC_VAL BT_UUID_ASCS_ASE_SRC_VAL
/*!< Audio Stream Endpoint Control Point Characteristic value */
#define ESP_BLE_AUDIO_UUID_ASCS_ASE_CP_VAL BT_UUID_ASCS_ASE_CP_VAL
/*!< Broadcast Audio Scan Service Scan State value */
#define ESP_BLE_AUDIO_UUID_BASS_CONTROL_POINT_VAL BT_UUID_BASS_CONTROL_POINT_VAL
/*!< Broadcast Audio Scan Service Receive State value */
#define ESP_BLE_AUDIO_UUID_BASS_RECV_STATE_VAL BT_UUID_BASS_RECV_STATE_VAL
/*!< Set Identity Resolving Key value */
#define ESP_BLE_AUDIO_UUID_CSIS_SIRK_VAL BT_UUID_CSIS_SIRK_VAL
/*!< Set size value */
#define ESP_BLE_AUDIO_UUID_CSIS_SET_SIZE_VAL BT_UUID_CSIS_SET_SIZE_VAL
/*!< Set lock value */
#define ESP_BLE_AUDIO_UUID_CSIS_SET_LOCK_VAL BT_UUID_CSIS_SET_LOCK_VAL
/*!< Rank value */
#define ESP_BLE_AUDIO_UUID_CSIS_RANK_VAL BT_UUID_CSIS_RANK_VAL
/*!< Gaming Audio Profile Role UUID value */
#define ESP_BLE_AUDIO_UUID_GMAP_ROLE_VAL BT_UUID_GMAP_ROLE_VAL
/*!< Gaming Audio Profile Unicast Game Gateway Features UUID value */
#define ESP_BLE_AUDIO_UUID_GMAP_UGG_FEAT_VAL BT_UUID_GMAP_UGG_FEAT_VAL
/*!< Gaming Audio Profile Unicast Game Terminal Features UUID value */
#define ESP_BLE_AUDIO_UUID_GMAP_UGT_FEAT_VAL BT_UUID_GMAP_UGT_FEAT_VAL
/*!< Gaming Audio Profile Broadcast Game Sender Features UUID value */
#define ESP_BLE_AUDIO_UUID_GMAP_BGS_FEAT_VAL BT_UUID_GMAP_BGS_FEAT_VAL
/*!< Gaming Audio Profile Broadcast Game Receiver Features UUID value */
#define ESP_BLE_AUDIO_UUID_GMAP_BGR_FEAT_VAL BT_UUID_GMAP_BGR_FEAT_VAL
/*!< Hearing Aid Features Characteristic value */
#define ESP_BLE_AUDIO_UUID_HAS_HEARING_AID_FEATURES_VAL BT_UUID_HAS_HEARING_AID_FEATURES_VAL
/*!< Hearing Aid Preset Control Point Characteristic value */
#define ESP_BLE_AUDIO_UUID_HAS_PRESET_CONTROL_POINT_VAL BT_UUID_HAS_PRESET_CONTROL_POINT_VAL
/*!< Hearing Aid Active Preset Index Characteristic value */
#define ESP_BLE_AUDIO_UUID_HAS_ACTIVE_PRESET_INDEX_VAL BT_UUID_HAS_ACTIVE_PRESET_INDEX_VAL
/*!< Media player name value */
#define ESP_BLE_AUDIO_UUID_MCS_PLAYER_NAME_VAL BT_UUID_MCS_PLAYER_NAME_VAL
/*!< Media Icon Object ID value */
#define ESP_BLE_AUDIO_UUID_MCS_ICON_OBJ_ID_VAL BT_UUID_MCS_ICON_OBJ_ID_VAL
/*!< Media Icon URL value */
#define ESP_BLE_AUDIO_UUID_MCS_ICON_URL_VAL BT_UUID_MCS_ICON_URL_VAL
/*!< Track Changed value */
#define ESP_BLE_AUDIO_UUID_MCS_TRACK_CHANGED_VAL BT_UUID_MCS_TRACK_CHANGED_VAL
/*!< Track Title value */
#define ESP_BLE_AUDIO_UUID_MCS_TRACK_TITLE_VAL BT_UUID_MCS_TRACK_TITLE_VAL
/*!< Track Duration value */
#define ESP_BLE_AUDIO_UUID_MCS_TRACK_DURATION_VAL BT_UUID_MCS_TRACK_DURATION_VAL
/*!< Track Position value */
#define ESP_BLE_AUDIO_UUID_MCS_TRACK_POSITION_VAL BT_UUID_MCS_TRACK_POSITION_VAL
/*!< Playback Speed value */
#define ESP_BLE_AUDIO_UUID_MCS_PLAYBACK_SPEED_VAL BT_UUID_MCS_PLAYBACK_SPEED_VAL
/*!< Seeking Speed value */
#define ESP_BLE_AUDIO_UUID_MCS_SEEKING_SPEED_VAL BT_UUID_MCS_SEEKING_SPEED_VAL
/*!< Track Segments Object ID value */
#define ESP_BLE_AUDIO_UUID_MCS_TRACK_SEGMENTS_OBJ_ID_VAL BT_UUID_MCS_TRACK_SEGMENTS_OBJ_ID_VAL
/*!< Current Track Object ID value */
#define ESP_BLE_AUDIO_UUID_MCS_CURRENT_TRACK_OBJ_ID_VAL BT_UUID_MCS_CURRENT_TRACK_OBJ_ID_VAL
/*!< Next Track Object ID value */
#define ESP_BLE_AUDIO_UUID_MCS_NEXT_TRACK_OBJ_ID_VAL BT_UUID_MCS_NEXT_TRACK_OBJ_ID_VAL
/*!< Parent Group Object ID value */
#define ESP_BLE_AUDIO_UUID_MCS_PARENT_GROUP_OBJ_ID_VAL BT_UUID_MCS_PARENT_GROUP_OBJ_ID_VAL
/*!< Group Object ID value */
#define ESP_BLE_AUDIO_UUID_MCS_CURRENT_GROUP_OBJ_ID_VAL BT_UUID_MCS_CURRENT_GROUP_OBJ_ID_VAL
/*!< Playing Order value */
#define ESP_BLE_AUDIO_UUID_MCS_PLAYING_ORDER_VAL BT_UUID_MCS_PLAYING_ORDER_VAL
/*!< Playing Orders supported value */
#define ESP_BLE_AUDIO_UUID_MCS_PLAYING_ORDERS_VAL BT_UUID_MCS_PLAYING_ORDERS_VAL
/*!< Media State value */
#define ESP_BLE_AUDIO_UUID_MCS_MEDIA_STATE_VAL BT_UUID_MCS_MEDIA_STATE_VAL
/*!< Media Control Point value */
#define ESP_BLE_AUDIO_UUID_MCS_MEDIA_CONTROL_POINT_VAL BT_UUID_MCS_MEDIA_CONTROL_POINT_VAL
/*!< Media control opcodes supported value */
#define ESP_BLE_AUDIO_UUID_MCS_MEDIA_CONTROL_OPCODES_VAL BT_UUID_MCS_MEDIA_CONTROL_OPCODES_VAL
/*!< Search result object ID value */
#define ESP_BLE_AUDIO_UUID_MCS_SEARCH_RESULTS_OBJ_ID_VAL BT_UUID_MCS_SEARCH_RESULTS_OBJ_ID_VAL
/*!< Search control point value */
#define ESP_BLE_AUDIO_UUID_MCS_SEARCH_CONTROL_POINT_VAL BT_UUID_MCS_SEARCH_CONTROL_POINT_VAL
/*!< Microphone Control Service Mute value */
#define ESP_BLE_AUDIO_UUID_MICS_MUTE_VAL BT_UUID_MICS_MUTE_VAL
/*!< Sink PAC Characteristic value */
#define ESP_BLE_AUDIO_UUID_PACS_SNK_VAL BT_UUID_PACS_SNK_VAL
/*!< Sink PAC Locations Characteristic value */
#define ESP_BLE_AUDIO_UUID_PACS_SNK_LOC_VAL BT_UUID_PACS_SNK_LOC_VAL
/*!< Source PAC Characteristic value */
#define ESP_BLE_AUDIO_UUID_PACS_SRC_VAL BT_UUID_PACS_SRC_VAL
/*!< Source PAC Locations Characteristic value */
#define ESP_BLE_AUDIO_UUID_PACS_SRC_LOC_VAL BT_UUID_PACS_SRC_LOC_VAL
/*!< Available Audio Contexts Characteristic value */
#define ESP_BLE_AUDIO_UUID_PACS_AVAILABLE_CONTEXT_VAL BT_UUID_PACS_AVAILABLE_CONTEXT_VAL
/*!< Supported Audio Context Characteristic value */
#define ESP_BLE_AUDIO_UUID_PACS_SUPPORTED_CONTEXT_VAL BT_UUID_PACS_SUPPORTED_CONTEXT_VAL
/*!< Bearer Provider Name value */
#define ESP_BLE_AUDIO_UUID_TBS_PROVIDER_NAME_VAL BT_UUID_TBS_PROVIDER_NAME_VAL
/*!< Bearer UCI value */
#define ESP_BLE_AUDIO_UUID_TBS_UCI_VAL BT_UUID_TBS_UCI_VAL
/*!< Bearer Technology value */
#define ESP_BLE_AUDIO_UUID_TBS_TECHNOLOGY_VAL BT_UUID_TBS_TECHNOLOGY_VAL
/*!< Bearer URI Prefixes Supported List value */
#define ESP_BLE_AUDIO_UUID_TBS_URI_LIST_VAL BT_UUID_TBS_URI_LIST_VAL
/*!< Bearer Signal Strength value */
#define ESP_BLE_AUDIO_UUID_TBS_SIGNAL_STRENGTH_VAL BT_UUID_TBS_SIGNAL_STRENGTH_VAL
/*!< Bearer Signal Strength Reporting Interval value */
#define ESP_BLE_AUDIO_UUID_TBS_SIGNAL_INTERVAL_VAL BT_UUID_TBS_SIGNAL_INTERVAL_VAL
/*!< Bearer List Current Calls value */
#define ESP_BLE_AUDIO_UUID_TBS_LIST_CURRENT_CALLS_VAL BT_UUID_TBS_LIST_CURRENT_CALLS_VAL
/*!< Status flags value */
#define ESP_BLE_AUDIO_UUID_TBS_STATUS_FLAGS_VAL BT_UUID_TBS_STATUS_FLAGS_VAL
/*!< Incoming Call Target Caller ID value */
#define ESP_BLE_AUDIO_UUID_TBS_INCOMING_URI_VAL BT_UUID_TBS_INCOMING_URI_VAL
/*!< Call State value */
#define ESP_BLE_AUDIO_UUID_TBS_CALL_STATE_VAL BT_UUID_TBS_CALL_STATE_VAL
/*!< Call Control Point value */
#define ESP_BLE_AUDIO_UUID_TBS_CALL_CONTROL_POINT_VAL BT_UUID_TBS_CALL_CONTROL_POINT_VAL
/*!< Optional Opcodes value */
#define ESP_BLE_AUDIO_UUID_TBS_OPTIONAL_OPCODES_VAL BT_UUID_TBS_OPTIONAL_OPCODES_VAL
/*!< Terminate reason value */
#define ESP_BLE_AUDIO_UUID_TBS_TERMINATE_REASON_VAL BT_UUID_TBS_TERMINATE_REASON_VAL
/*!< Incoming Call value */
#define ESP_BLE_AUDIO_UUID_TBS_INCOMING_CALL_VAL BT_UUID_TBS_INCOMING_CALL_VAL
/*!< Incoming Call Friendly name value */
#define ESP_BLE_AUDIO_UUID_TBS_FRIENDLY_NAME_VAL BT_UUID_TBS_FRIENDLY_NAME_VAL
/*!< Volume Control Setting value */
#define ESP_BLE_AUDIO_UUID_VCS_STATE_VAL BT_UUID_VCS_STATE_VAL
/*!< Volume Control Control point value */
#define ESP_BLE_AUDIO_UUID_VCS_CONTROL_VAL BT_UUID_VCS_CONTROL_VAL
/*!< Volume Control Flags value */
#define ESP_BLE_AUDIO_UUID_VCS_FLAGS_VAL BT_UUID_VCS_FLAGS_VAL
/*!< Volume Offset State value */
#define ESP_BLE_AUDIO_UUID_VOCS_STATE_VAL BT_UUID_VOCS_STATE_VAL
/*!< Audio Location value */
#define ESP_BLE_AUDIO_UUID_VOCS_LOCATION_VAL BT_UUID_VOCS_LOCATION_VAL
/*!< Volume Offset Control Point value */
#define ESP_BLE_AUDIO_UUID_VOCS_CONTROL_VAL BT_UUID_VOCS_CONTROL_VAL
/*!< Volume Offset Audio Output Description value */
#define ESP_BLE_AUDIO_UUID_VOCS_DESCRIPTION_VAL BT_UUID_VOCS_DESCRIPTION_VAL
/*!< Content Control ID value */
#define ESP_BLE_AUDIO_UUID_CCID_VAL BT_UUID_CCID_VAL
/*!< OTS Feature Characteristic UUID value */
#define ESP_BLE_AUDIO_UUID_OTS_FEATURE_VAL BT_UUID_OTS_FEATURE_VAL
/*!< OTS Object Name Characteristic UUID value */
#define ESP_BLE_AUDIO_UUID_OTS_NAME_VAL BT_UUID_OTS_NAME_VAL
/*!< OTS Object Type Characteristic UUID value */
#define ESP_BLE_AUDIO_UUID_OTS_TYPE_VAL BT_UUID_OTS_TYPE_VAL
/*!< OTS Object Size Characteristic UUID value */
#define ESP_BLE_AUDIO_UUID_OTS_SIZE_VAL BT_UUID_OTS_SIZE_VAL
/*!< OTS Object First-Created Characteristic UUID value */
#define ESP_BLE_AUDIO_UUID_OTS_FIRST_CREATED_VAL BT_UUID_OTS_FIRST_CREATED_VAL
/*!< OTS Object Last-Modified Characteristic UUI value */
#define ESP_BLE_AUDIO_UUID_OTS_LAST_MODIFIED_VAL BT_UUID_OTS_LAST_MODIFIED_VAL
/*!< OTS Object ID Characteristic UUID value */
#define ESP_BLE_AUDIO_UUID_OTS_ID_VAL BT_UUID_OTS_ID_VAL
/*!< OTS Object Properties Characteristic UUID value */
#define ESP_BLE_AUDIO_UUID_OTS_PROPERTIES_VAL BT_UUID_OTS_PROPERTIES_VAL
/*!< OTS Object Action Control Point Characteristic UUID value */
#define ESP_BLE_AUDIO_UUID_OTS_ACTION_CP_VAL BT_UUID_OTS_ACTION_CP_VAL
/*!< OTS Object List Control Point Characteristic UUID value */
#define ESP_BLE_AUDIO_UUID_OTS_LIST_CP_VAL BT_UUID_OTS_LIST_CP_VAL
/*!< OTS Object List Filter Characteristic UUID value */
#define ESP_BLE_AUDIO_UUID_OTS_LIST_FILTER_VAL BT_UUID_OTS_LIST_FILTER_VAL
/*!< OTS Object Changed Characteristic UUID value */
#define ESP_BLE_AUDIO_UUID_OTS_CHANGED_VAL BT_UUID_OTS_CHANGED_VAL
/*!< OTS Unspecified Object Type UUID value */
#define ESP_BLE_AUDIO_UUID_OTS_TYPE_UNSPECIFIED_VAL BT_UUID_OTS_TYPE_UNSPECIFIED_VAL
/*!< OTS Directory Listing UUID value */
#define ESP_BLE_AUDIO_UUID_OTS_DIRECTORY_LISTING_VAL BT_UUID_OTS_DIRECTORY_LISTING_VAL
/*!< OTS Media Player Icon Object Type value */
#define ESP_BLE_AUDIO_UUID_OTS_TYPE_MPL_ICON_VAL BT_UUID_OTS_TYPE_MPL_ICON_VAL
/*!< OTS Track Segments Object Type value */
#define ESP_BLE_AUDIO_UUID_OTS_TYPE_TRACK_SEGMENT_VAL BT_UUID_OTS_TYPE_TRACK_SEGMENT_VAL
/*!< OTS Track Object Type value */
#define ESP_BLE_AUDIO_UUID_OTS_TYPE_TRACK_VAL BT_UUID_OTS_TYPE_TRACK_VAL
/*!< OTS Group Object Type value */
#define ESP_BLE_AUDIO_UUID_OTS_TYPE_GROUP_VAL BT_UUID_OTS_TYPE_GROUP_VAL
/*!< Generic Audio Sink */
#define ESP_BLE_AUDIO_APPEARANCE_GENERIC_AUDIO_SINK BT_APPEARANCE_GENERIC_AUDIO_SINK
/*!< Standalone Speaker */
#define ESP_BLE_AUDIO_APPEARANCE_AUDIO_SINK_STANDALONE_SPEAKER BT_APPEARANCE_AUDIO_SINK_STANDALONE_SPEAKER
/*!< Soundbar */
#define ESP_BLE_AUDIO_APPEARANCE_AUDIO_SINK_SOUNDBAR BT_APPEARANCE_AUDIO_SINK_SOUNDBAR
/*!< Bookshelf Speaker */
#define ESP_BLE_AUDIO_APPEARANCE_AUDIO_SINK_BOOKSHELF_SPEAKER BT_APPEARANCE_AUDIO_SINK_BOOKSHELF_SPEAKER
/*!< Standmounted Speaker */
#define ESP_BLE_AUDIO_APPEARANCE_AUDIO_SINK_STANDMOUNTED_SPEAKER BT_APPEARANCE_AUDIO_SINK_STANDMOUNTED_SPEAKER
/*!< Speakerphone */
#define ESP_BLE_AUDIO_APPEARANCE_AUDIO_SINK_SPEAKERPHONE BT_APPEARANCE_AUDIO_SINK_SPEAKERPHONE
/*!< Generic Audio Source */
#define ESP_BLE_AUDIO_APPEARANCE_GENERIC_AUDIO_SOURCE BT_APPEARANCE_GENERIC_AUDIO_SOURCE
/*!< Microphone */
#define ESP_BLE_AUDIO_APPEARANCE_AUDIO_SOURCE_MICROPHONE BT_APPEARANCE_AUDIO_SOURCE_MICROPHONE
/*!< Alarm */
#define ESP_BLE_AUDIO_APPEARANCE_AUDIO_SOURCE_ALARM BT_APPEARANCE_AUDIO_SOURCE_ALARM
/*!< Bell */
#define ESP_BLE_AUDIO_APPEARANCE_AUDIO_SOURCE_BELL BT_APPEARANCE_AUDIO_SOURCE_BELL
/*!< Horn */
#define ESP_BLE_AUDIO_APPEARANCE_AUDIO_SOURCE_HORN BT_APPEARANCE_AUDIO_SOURCE_HORN
/*!< Broadcasting Device */
#define ESP_BLE_AUDIO_APPEARANCE_AUDIO_SOURCE_BROADCASTING_DEVICE BT_APPEARANCE_AUDIO_SOURCE_BROADCASTING_DEVICE
/*!< Service Desk */
#define ESP_BLE_AUDIO_APPEARANCE_AUDIO_SOURCE_SERVICE_DESK BT_APPEARANCE_AUDIO_SOURCE_SERVICE_DESK
/*!< Kiosk */
#define ESP_BLE_AUDIO_APPEARANCE_AUDIO_SOURCE_KIOSK BT_APPEARANCE_AUDIO_SOURCE_KIOSK
/*!< Broadcasting Room */
#define ESP_BLE_AUDIO_APPEARANCE_AUDIO_SOURCE_BROADCASTING_ROOM BT_APPEARANCE_AUDIO_SOURCE_BROADCASTING_ROOM
/*!< Auditorium */
#define ESP_BLE_AUDIO_APPEARANCE_AUDIO_SOURCE_AUDITORIUM BT_APPEARANCE_AUDIO_SOURCE_AUDITORIUM
/*!< Generic Wearable Audio Device */
#define ESP_BLE_AUDIO_APPEARANCE_GENERIC_WEARABLE_AUDIO_DEVICE BT_APPEARANCE_GENERIC_WEARABLE_AUDIO_DEVICE
/*!< Earbud */
#define ESP_BLE_AUDIO_APPEARANCE_WEARABLE_AUDIO_DEVICE_EARBUD BT_APPEARANCE_WEARABLE_AUDIO_DEVICE_EARBUD
/*!< Headset */
#define ESP_BLE_AUDIO_APPEARANCE_WEARABLE_AUDIO_DEVICE_HEADSET BT_APPEARANCE_WEARABLE_AUDIO_DEVICE_HEADSET
/*!< Headphones */
#define ESP_BLE_AUDIO_APPEARANCE_WEARABLE_AUDIO_DEVICE_HEADPHONES BT_APPEARANCE_WEARABLE_AUDIO_DEVICE_HEADPHONES
/*!< Neck Band */
#define ESP_BLE_AUDIO_APPEARANCE_WEARABLE_AUDIO_DEVICE_NECK_BAND BT_APPEARANCE_WEARABLE_AUDIO_DEVICE_NECK_BAND
/*!< Generic Hearing aid */
#define ESP_BLE_AUDIO_APPEARANCE_GENERIC_HEARING_AID BT_APPEARANCE_GENERIC_HEARING_AID
/*!< In-ear hearing aid */
#define ESP_BLE_AUDIO_APPEARANCE_HEARING_AID_IN_EAR BT_APPEARANCE_HEARING_AID_IN_EAR
/*!< Behind-ear hearing aid */
#define ESP_BLE_AUDIO_APPEARANCE_HEARING_AID_BEHIND_EAR BT_APPEARANCE_HEARING_AID_BEHIND_EAR
/*!< Cochlear Implant */
#define ESP_BLE_AUDIO_APPEARANCE_HEARING_AID_COCHLEAR_IMPLANT BT_APPEARANCE_HEARING_AID_COCHLEAR_IMPLANT
#ifdef __cplusplus
}
#endif
#endif /* ESP_BLE_AUDIO_DEFS_H_ */
@@ -0,0 +1,134 @@
/*
* SPDX-FileCopyrightText: 2023-2024 Nordic Semiconductor ASA
* SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ESP_BLE_AUDIO_GMAP_API_H_
#define ESP_BLE_AUDIO_GMAP_API_H_
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include "sdkconfig.h"
#include "esp_err.h"
#include <zephyr/bluetooth/audio/gmap.h>
#include "common/init.h"
#include "common/host.h"
#ifdef __cplusplus
extern "C" {
#endif
/*!< Gaming Role Unicast Game Gateway */
#define ESP_BLE_AUDIO_GMAP_ROLE_UGG BT_GMAP_ROLE_UGG
/*!< Gaming Role Unicast Game Terminal */
#define ESP_BLE_AUDIO_GMAP_ROLE_UGT BT_GMAP_ROLE_UGT
/*!< Gaming Role Broadcast Game Sender */
#define ESP_BLE_AUDIO_GMAP_ROLE_BGS BT_GMAP_ROLE_BGS
/*!< Gaming Role Broadcast Game Receiver */
#define ESP_BLE_AUDIO_GMAP_ROLE_BGR BT_GMAP_ROLE_BGR
/** Gaming Role bitfield */
typedef enum bt_gmap_role esp_ble_audio_gmap_role_t;
/*!< Support transmitting multiple LC3 codec frames per block in an SDU */
#define ESP_BLE_AUDIO_GMAP_UGG_FEAT_MULTIPLEX BT_GMAP_UGG_FEAT_MULTIPLEX
/*!< 96 kbps source support */
#define ESP_BLE_AUDIO_GMAP_UGG_FEAT_96KBPS_SOURCE BT_GMAP_UGG_FEAT_96KBPS_SOURCE
/*!< Support for receiving at least two channels of audio, each in a separate CIS */
#define ESP_BLE_AUDIO_GMAP_UGG_FEAT_MULTISINK BT_GMAP_UGG_FEAT_MULTISINK
/** Unicast Game Gateway Feature bitfield */
typedef enum bt_gmap_ugg_feat esp_ble_audio_gmap_ugg_feat_t;
/*!< Source support */
#define ESP_BLE_AUDIO_GMAP_UGT_FEAT_SOURCE BT_GMAP_UGT_FEAT_SOURCE
/*!< 80 kbps source support */
#define ESP_BLE_AUDIO_GMAP_UGT_FEAT_80KBPS_SOURCE BT_GMAP_UGT_FEAT_80KBPS_SOURCE
/*!< Sink support */
#define ESP_BLE_AUDIO_GMAP_UGT_FEAT_SINK BT_GMAP_UGT_FEAT_SINK
/*!< 64 kbps sink support */
#define ESP_BLE_AUDIO_GMAP_UGT_FEAT_64KBPS_SINK BT_GMAP_UGT_FEAT_64KBPS_SINK
/*!< Support for receiving multiple LC3 codec frames per block in an SDU */
#define ESP_BLE_AUDIO_GMAP_UGT_FEAT_MULTIPLEX BT_GMAP_UGT_FEAT_MULTIPLEX
/*!< Support for receiving at least two audio channels, each in a separate CIS */
#define ESP_BLE_AUDIO_GMAP_UGT_FEAT_MULTISINK BT_GMAP_UGT_FEAT_MULTISINK
/*!< Support for sending at least two audio channels, each in a separate CIS */
#define ESP_BLE_AUDIO_GMAP_UGT_FEAT_MULTISOURCE BT_GMAP_UGT_FEAT_MULTISOURCE
/** Unicast Game Terminal Feature bitfield */
typedef enum bt_gmap_ugt_feat esp_ble_audio_gmap_ugt_feat_t;
/*!< 96 kbps support */
#define ESP_BLE_AUDIO_GMAP_BGS_FEAT_96KBPS BT_GMAP_BGS_FEAT_96KBPS
/** Broadcast Game Receiver Feature bitfield */
typedef enum bt_gmap_bgs_feat esp_ble_audio_gmap_bgs_feat_t;
/*!< Support for receiving at least two audio channels, each in a separate BIS */
#define ESP_BLE_AUDIO_GMAP_BGR_FEAT_MULTISINK BT_GMAP_BGR_FEAT_MULTISINK
/*!< Support for receiving multiple LC3 codec frames per block in an SDU */
#define ESP_BLE_AUDIO_GMAP_BGR_FEAT_MULTIPLEX BT_GMAP_BGR_FEAT_MULTIPLEX
/** Broadcast Game Receiver Feature bitfield */
typedef enum bt_gmap_bgr_feat esp_ble_audio_gmap_bgr_feat_t;
/** Hearing Access Service Client callback structure */
typedef struct bt_gmap_cb esp_ble_audio_gmap_cb_t;
/** Broadcast Game Receiver Feature bitfield */
typedef struct bt_gmap_feat esp_ble_audio_gmap_feat_t;
/**
* @brief Registers the callbacks used by the Gaming Audio Profile.
*
* @param cb The callback structure.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_gmap_cb_register(const esp_ble_audio_gmap_cb_t *cb);
/**
* @brief Discover Gaming Service on a remote device.
*
* Procedure to find a Gaming Service on a server identified by @p conn_handle.
*
* @param conn_handle Connection handle.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_gmap_discover(uint16_t conn_handle);
/**
* @brief Adds GMAS instance to database and sets the received Gaming Audio Profile role(s).
*
* @param role Gaming Audio Profile role(s) of the device (one or multiple).
* @param features Features of the roles. If a role is not in the @p role parameter, then
* the feature value for that role is simply ignored.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_gmap_register(esp_ble_audio_gmap_role_t role,
esp_ble_audio_gmap_feat_t features);
/**
* @brief Set one or multiple Gaming Audio Profile roles and features dynamically.
*
* Previously registered value will be overwritten. If there is a role change, this will trigger
* a Gaming Audio Service (GMAS) service change. If there is only a feature change, no service
* change will happen.
*
* @param role Gaming Audio Profile role(s).
* @param features Features of the roles. If a role is not in the @p role parameter, then
* the feature value for that role is simply ignored.
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_gmap_set_role(esp_ble_audio_gmap_role_t role,
esp_ble_audio_gmap_feat_t features);
#ifdef __cplusplus
}
#endif
#endif /* ESP_BLE_AUDIO_GMAP_API_H_ */
@@ -0,0 +1,324 @@
/*
* SPDX-FileCopyrightText: 2023-2024 Nordic Semiconductor ASA
* SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ESP_BLE_AUDIO_GMAP_LC3_PRESET_DEFS_H_
#define ESP_BLE_AUDIO_GMAP_LC3_PRESET_DEFS_H_
#include <zephyr/bluetooth/audio/gmap_lc3_preset.h>
#include "esp_ble_audio_bap_lc3_preset_defs.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Base macro for defining GMAP LC3 presets.
*
* @param _name Preset name.
* @param _freq Sampling frequency (16, 32, or 48 kHz).
* @param _duration Frame duration (7.5 or 10 ms).
* @param _loc Audio channel location.
* @param _len Frame length in bytes.
* @param _frames_per_sdu Number of frames per SDU.
* @param _stream_context Stream context type.
* @param _interval Interval between packets in microseconds.
* @param _sdu SDU size in bytes.
* @param _rtn Maximum number of retransmissions.
* @param _latency Maximum latency in milliseconds.
* @param _pd Presentation delay in microseconds.
*/
#define ESP_BLE_AUDIO_GMAP_LC3_PRESET_DEFINE(_name, _freq, _duration, _loc, _len, \
_frames_per_sdu, _stream_context, \
_interval, _sdu, _rtn, _latency, _pd) \
static uint8_t codec_cfg_data_##_name[] = \
ESP_BLE_AUDIO_CODEC_CFG_LC3_DATA(_freq, _duration, _loc, _len, _frames_per_sdu); \
static uint8_t codec_cfg_meta_##_name[] = \
ESP_BLE_AUDIO_CODEC_CFG_LC3_META(_stream_context); \
static esp_ble_audio_bap_lc3_preset_t _name = \
ESP_BLE_AUDIO_BAP_LC3_PRESET(ESP_BLE_AUDIO_CODEC_CFG_LC3(codec_cfg_data_##_name, \
codec_cfg_meta_##_name), \
ESP_BLE_AUDIO_BAP_QOS_CFG_UNFRAMED(_interval, _sdu, _rtn, \
_latency, _pd));
/**
* @brief Gaming Reliable (GR) preset at 32kHz, 7.5ms frame duration.
*
* Optimized for reliable gaming audio with low latency (15ms) and standard presentation delay (10ms).
*
* @param _name Preset name.
* @param _loc Audio channel location.
* @param _stream_context Stream context type.
*/
#define ESP_BLE_AUDIO_GMAP_LC3_PRESET_32_1_GR_DEFINE(_name, _loc, _stream_context) \
ESP_BLE_AUDIO_GMAP_LC3_PRESET_DEFINE(_name, \
BT_AUDIO_CODEC_CFG_FREQ_32KHZ, \
BT_AUDIO_CODEC_CFG_DURATION_7_5, \
_loc, 60U, 1, \
_stream_context, \
7500u, 60U, 1U, 15U, 10000U)
/**
* @brief Gaming Reliable (GR) preset at 32kHz, 10ms frame duration.
*
* Higher quality variant with increased frame duration for better audio quality.
*
* @param _name Preset name.
* @param _loc Audio channel location.
* @param _stream_context Stream context type.
*/
#define ESP_BLE_AUDIO_GMAP_LC3_PRESET_32_2_GR_DEFINE(_name, _loc, _stream_context) \
ESP_BLE_AUDIO_GMAP_LC3_PRESET_DEFINE(_name, \
BT_AUDIO_CODEC_CFG_FREQ_32KHZ, \
BT_AUDIO_CODEC_CFG_DURATION_10, \
_loc, 80U, 1, \
_stream_context, \
10000u, 80U, 1U, 20U, 10000U)
/**
* @brief Gaming Reliable (GR) preset at 48kHz, 7.5ms frame duration.
*
* High-quality gaming audio with minimal latency.
*
* @param _name Preset name.
* @param _loc Audio channel location.
* @param _stream_context Stream context type.
*/
#define ESP_BLE_AUDIO_GMAP_LC3_PRESET_48_1_GR_DEFINE(_name, _loc, _stream_context) \
ESP_BLE_AUDIO_GMAP_LC3_PRESET_DEFINE(_name, \
BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \
BT_AUDIO_CODEC_CFG_DURATION_7_5, \
_loc, 75U, 1, \
_stream_context, \
7500u, 75U, 1U, 15U, 10000U)
/**
* @brief Gaming Reliable (GR) preset at 48kHz, 10ms frame duration.
*
* High-quality gaming audio with balanced latency and quality.
*
* @param _name Preset name.
* @param _loc Audio channel location.
* @param _stream_context Stream context type.
*/
#define ESP_BLE_AUDIO_GMAP_LC3_PRESET_48_2_GR_DEFINE(_name, _loc, _stream_context) \
ESP_BLE_AUDIO_GMAP_LC3_PRESET_DEFINE(_name, \
BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \
BT_AUDIO_CODEC_CFG_DURATION_10, \
_loc, 100U, 1, \
_stream_context, \
10000u, 100U, 1U, 20U, 10000U)
/**
* @brief Gaming Reliable (GR) preset at 48kHz, 7.5ms frame duration, higher bitrate.
*
* Enhanced quality gaming audio with minimal latency.
*
* @param _name Preset name.
* @param _loc Audio channel location.
* @param _stream_context Stream context type.
*/
#define ESP_BLE_AUDIO_GMAP_LC3_PRESET_48_3_GR_DEFINE(_name, _loc, _stream_context) \
ESP_BLE_AUDIO_GMAP_LC3_PRESET_DEFINE(_name, \
BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \
BT_AUDIO_CODEC_CFG_DURATION_7_5, \
_loc, 90U, 1, \
_stream_context, \
7500u, 90U, 1U, 15U, 10000U)
/**
* @brief Gaming Reliable (GR) preset at 48kHz, 10ms frame duration, higher bitrate.
*
* Premium quality gaming audio with balanced latency.
*
* @param _name Preset name.
* @param _loc Audio channel location.
* @param _stream_context Stream context type.
*/
#define ESP_BLE_AUDIO_GMAP_LC3_PRESET_48_4_GR_DEFINE(_name, _loc, _stream_context) \
ESP_BLE_AUDIO_GMAP_LC3_PRESET_DEFINE(_name, \
BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \
BT_AUDIO_CODEC_CFG_DURATION_10, \
_loc, 120u, 1, \
_stream_context, \
10000u, 120U, 1U, 20U, 10000U)
/**
* @brief Gaming Standard (GS) preset at 16kHz, 7.5ms frame duration.
*
* Basic gaming audio with longer presentation delay (60ms).
*
* @param _name Preset name.
* @param _loc Audio channel location.
* @param _stream_context Stream context type.
*/
#define ESP_BLE_AUDIO_GMAP_LC3_PRESET_16_1_GS_DEFINE(_name, _loc, _stream_context) \
ESP_BLE_AUDIO_GMAP_LC3_PRESET_DEFINE(_name, \
BT_AUDIO_CODEC_CFG_FREQ_16KHZ, \
BT_AUDIO_CODEC_CFG_DURATION_7_5, \
_loc, 30U, 1, \
_stream_context, \
7500u, 30U, 1U, 15U, 60000U)
/**
* @brief Gaming Standard (GS) preset at 16kHz, 10ms frame duration.
*
* Basic gaming audio with better quality and longer presentation delay.
*
* @param _name Preset name.
* @param _loc Audio channel location.
* @param _stream_context Stream context type.
*/
#define ESP_BLE_AUDIO_GMAP_LC3_PRESET_16_2_GS_DEFINE(_name, _loc, _stream_context) \
ESP_BLE_AUDIO_GMAP_LC3_PRESET_DEFINE(_name, \
BT_AUDIO_CODEC_CFG_FREQ_16KHZ, \
BT_AUDIO_CODEC_CFG_DURATION_10, \
_loc, 40U, 1, \
_stream_context, \
10000u, 40U, 1U, 20U, 60000U)
/**
* @brief Gaming Standard (GS) preset at 32kHz, 7.5ms frame duration.
*
* Medium quality gaming audio with standard latency.
*
* @param _name Preset name.
* @param _loc Audio channel location.
* @param _stream_context Stream context type.
*/
#define ESP_BLE_AUDIO_GMAP_LC3_PRESET_32_1_GS_DEFINE(_name, _loc, _stream_context) \
ESP_BLE_AUDIO_GMAP_LC3_PRESET_DEFINE(_name, \
BT_AUDIO_CODEC_CFG_FREQ_32KHZ, \
BT_AUDIO_CODEC_CFG_DURATION_7_5, \
_loc, 60U, 1, \
_stream_context, \
7500u, 60U, 1U, 15U, 60000U)
/**
* @brief Gaming Standard (GS) preset at 32kHz, 10ms frame duration.
*
* Enhanced medium quality gaming audio.
*
* @param _name Preset name.
* @param _loc Audio channel location.
* @param _stream_context Stream context type.
*/
#define ESP_BLE_AUDIO_GMAP_LC3_PRESET_32_2_GS_DEFINE(_name, _loc, _stream_context) \
ESP_BLE_AUDIO_GMAP_LC3_PRESET_DEFINE(_name, \
BT_AUDIO_CODEC_CFG_FREQ_32KHZ, \
BT_AUDIO_CODEC_CFG_DURATION_10, \
_loc, 80U, 1, \
_stream_context, \
10000u, 80U, 1U, 20U, 60000U)
/**
* @brief Gaming Standard (GS) preset at 48kHz, 7.5ms frame duration.
*
* High quality gaming audio with standard latency.
*
* @param _name Preset name.
* @param _loc Audio channel location.
* @param _stream_context Stream context type.
*/
#define ESP_BLE_AUDIO_GMAP_LC3_PRESET_48_1_GS_DEFINE(_name, _loc, _stream_context) \
ESP_BLE_AUDIO_GMAP_LC3_PRESET_DEFINE(_name, \
BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \
BT_AUDIO_CODEC_CFG_DURATION_7_5, \
_loc, 75U, 1, \
_stream_context, \
7500u, 75U, 1U, 15U, 60000U)
/**
* @brief Gaming Standard (GS) preset at 48kHz, 10ms frame duration.
*
* Premium quality gaming audio with standard latency.
*
* @param _name Preset name.
* @param _loc Audio channel location.
* @param _stream_context Stream context type.
*/
#define ESP_BLE_AUDIO_GMAP_LC3_PRESET_48_2_GS_DEFINE(_name, _loc, _stream_context) \
ESP_BLE_AUDIO_GMAP_LC3_PRESET_DEFINE(_name, \
BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \
BT_AUDIO_CODEC_CFG_DURATION_10, \
_loc, 100U, 1, \
_stream_context, \
10000u, 100U, 1U, 20U, 60000U)
/**
* @brief Generic Gaming (G) preset at 48kHz, 7.5ms frame duration.
*
* High quality gaming audio with ultra-low latency (8ms).
*
* @param _name Preset name.
* @param _loc Audio channel location.
* @param _stream_context Stream context type.
*/
#define ESP_BLE_AUDIO_GMAP_LC3_PRESET_48_1_G_DEFINE(_name, _loc, _stream_context) \
ESP_BLE_AUDIO_GMAP_LC3_PRESET_DEFINE(_name, \
BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \
BT_AUDIO_CODEC_CFG_DURATION_7_5, \
_loc, 75U, 1, \
_stream_context, \
7500u, 75U, 1U, 8U, 10000U)
/**
* @brief Generic Gaming (G) preset at 48kHz, 10ms frame duration.
*
* High quality gaming audio with very low latency (10ms).
*
* @param _name Preset name.
* @param _loc Audio channel location.
* @param _stream_context Stream context type.
*/
#define ESP_BLE_AUDIO_GMAP_LC3_PRESET_48_2_G_DEFINE(_name, _loc, _stream_context) \
ESP_BLE_AUDIO_GMAP_LC3_PRESET_DEFINE(_name, \
BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \
BT_AUDIO_CODEC_CFG_DURATION_10, \
_loc, 100U, 1, \
_stream_context, \
10000u, 100U, 1U, 10U, 10000U)
/**
* @brief Generic Gaming (G) preset at 48kHz, 7.5ms frame duration, higher bitrate.
*
* Premium quality gaming audio with ultra-low latency.
*
* @param _name Preset name.
* @param _loc Audio channel location.
* @param _stream_context Stream context type.
*/
#define ESP_BLE_AUDIO_GMAP_LC3_PRESET_48_3_G_DEFINE(_name, _loc, _stream_context) \
ESP_BLE_AUDIO_GMAP_LC3_PRESET_DEFINE(_name, \
BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \
BT_AUDIO_CODEC_CFG_DURATION_7_5, \
_loc, 90U, 1, \
_stream_context, \
7500u, 90U, 1U, 8U, 10000U)
/**
* @brief Generic Gaming (G) preset at 48kHz, 10ms frame duration, higher bitrate.
*
* Highest quality gaming audio with very low latency.
*
* @param _name Preset name.
* @param _loc Audio channel location.
* @param _stream_context Stream context type.
*/
#define ESP_BLE_AUDIO_GMAP_LC3_PRESET_48_4_G_DEFINE(_name, _loc, _stream_context) \
ESP_BLE_AUDIO_GMAP_LC3_PRESET_DEFINE(_name, \
BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \
BT_AUDIO_CODEC_CFG_DURATION_10, \
_loc, 120u, 1, \
_stream_context, \
10000u, 120U, 1U, 10U, 10000U)
#ifdef __cplusplus
}
#endif
#endif /* ESP_BLE_AUDIO_GMAP_LC3_PRESET_DEFS_H_ */
@@ -0,0 +1,267 @@
/*
* SPDX-FileCopyrightText: 2022 Codecoup
* SPDX-FileCopyrightText: 2024 Nordic Semiconductor ASA
* SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ESP_BLE_AUDIO_HAS_API_H_
#define ESP_BLE_AUDIO_HAS_API_H_
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include "sdkconfig.h"
#include "esp_err.h"
#include <zephyr/bluetooth/conn.h>
#include <zephyr/bluetooth/audio/has.h>
#include "common/init.h"
#include "common/host.h"
#ifdef __cplusplus
extern "C" {
#endif
/*!< No index */
#define ESP_BLE_AUDIO_HAS_PRESET_INDEX_NONE BT_HAS_PRESET_INDEX_NONE
/*!< First preset index */
#define ESP_BLE_AUDIO_HAS_PRESET_INDEX_FIRST BT_HAS_PRESET_INDEX_FIRST
/*!< Last preset index */
#define ESP_BLE_AUDIO_HAS_PRESET_INDEX_LAST BT_HAS_PRESET_INDEX_LAST
/*!< Preset name minimum length */
#define ESP_BLE_AUDIO_HAS_PRESET_NAME_MIN BT_HAS_PRESET_NAME_MIN
/*!< Preset name maximum length */
#define ESP_BLE_AUDIO_HAS_PRESET_NAME_MAX BT_HAS_PRESET_NAME_MAX
/*!< No properties set */
#define ESP_BLE_AUDIO_HAS_PROP_NONE BT_HAS_PROP_NONE
/*!< Preset name can be written by the client */
#define ESP_BLE_AUDIO_HAS_PROP_WRITABLE BT_HAS_PROP_WRITABLE
/*!< Preset availability */
#define ESP_BLE_AUDIO_HAS_PROP_AVAILABLE BT_HAS_PROP_AVAILABLE
/** Preset Properties values */
typedef enum bt_has_properties esp_ble_audio_has_properties_t;
/*!< Indicate support for presets */
#define ESP_BLE_AUDIO_HAS_PRESET_SUPPORT BT_HAS_PRESET_SUPPORT
/** Hearing Aid device capabilities */
typedef enum bt_has_capabilities esp_ble_audio_has_capabilities_t;
/**
* Two hearing aids that form a Coordinated Set, one for the right ear and one for the left
* ear of the user. Typically used by a user with bilateral hearing loss.
*/
#define ESP_BLE_AUDIO_HAS_HEARING_AID_TYPE_BINAURAL BT_HAS_HEARING_AID_TYPE_BINAURAL
/**
* A single hearing aid for the left or the right ear. Typically used by a user with
* unilateral hearing loss.
*/
#define ESP_BLE_AUDIO_HAS_HEARING_AID_TYPE_MONAURAL BT_HAS_HEARING_AID_TYPE_MONAURAL
/**
* Two hearing aids with a connection to one another that expose a single Bluetooth radio
* interface.
*/
#define ESP_BLE_AUDIO_HAS_HEARING_AID_TYPE_BANDED BT_HAS_HEARING_AID_TYPE_BANDED
/** Hearing Aid device type */
typedef enum bt_has_hearing_aid_type esp_ble_audio_has_hearing_aid_type_t;
/** Hearing Access Service object */
typedef struct bt_has esp_ble_audio_has_t;
/** Hearing Access Service Client callback structure */
typedef struct bt_has_client_cb esp_ble_audio_has_client_cb_t;
/** Structure for registering features of a Hearing Access Service instance */
typedef struct bt_has_features_param esp_ble_audio_has_features_param_t;
/** Preset operations structure */
typedef struct bt_has_preset_ops esp_ble_audio_has_preset_ops_t;
/** Preset record definition */
typedef struct bt_has_preset_record esp_ble_audio_has_preset_record_t;
/** Register structure for preset */
typedef struct bt_has_preset_register_param esp_ble_audio_has_preset_register_param_t;
/**
* @brief Registers the callbacks used by the Hearing Access Service client.
*
* @param cb The callback structure.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_has_client_cb_register(const esp_ble_audio_has_client_cb_t *cb);
/**
* @brief Discover Hearing Access Service on a remote device.
*
* Client method to find a Hearing Access Service on a server identified by @p conn_handle.
*
* @param conn_handle Connection handle.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_has_client_discover(uint16_t conn_handle);
/**
* @brief Read Preset Records.
*
* Client method to read up to @p max_count presets starting from given @p index.
*
* @param has Pointer to the Hearing Access Service object.
* @param index The index to start with.
* @param max_count Maximum number of presets to read.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_has_client_presets_read(esp_ble_audio_has_t *has,
uint8_t index,
uint8_t max_count);
/**
* @brief Set Active Preset.
*
* Client procedure to set preset identified by @p index as active.
*
* @param has Pointer to the Hearing Access Service object.
* @param index Preset index to activate.
* @param sync Request active preset synchronization in set.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_has_client_preset_set(esp_ble_audio_has_t *has,
uint8_t index, bool sync);
/**
* @brief Activate Next Preset.
*
* Client procedure to set next available preset as active.
*
* @param has Pointer to the Hearing Access Service object.
* @param sync Request active preset synchronization in set.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_has_client_preset_next(esp_ble_audio_has_t *has, bool sync);
/**
* @brief Activate Previous Preset.
*
* Client procedure to set previous available preset as active.
*
* @param has Pointer to the Hearing Access Service object.
* @param sync Request active preset synchronization in set.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_has_client_preset_prev(esp_ble_audio_has_t *has, bool sync);
/**
* @brief Register the Hearing Access Service instance.
*
* @param features Hearing Access Service register parameters.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_has_register(const esp_ble_audio_has_features_param_t *features);
/**
* @brief Register preset.
*
* Register preset. The preset will be added to the list of exposed preset records.
*
* @param param Preset registration parameter.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_has_preset_register(const esp_ble_audio_has_preset_register_param_t *param);
/**
* @brief Unregister Preset.
*
* Unregister preset. The preset will be removed from the list of preset records.
*
* @param index The index of preset that's being requested to unregister.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_has_preset_unregister(uint8_t index);
/**
* @brief Set the preset as available.
*
* This will notify preset availability to peer devices. Only available preset can
* be selected as active preset.
*
* @param index The index of preset that's became available.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_has_preset_available(uint8_t index);
/**
* @brief Set the preset as unavailable.
*
* This will notify preset availability to peer devices. Unavailable preset cannot
* be selected as active preset.
*
* @param index The index of preset that's became unavailable.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_has_preset_unavailable(uint8_t index);
/**
* @brief Set active preset.
*
* Function used to set the preset identified by the @p index as the active preset.
* The preset index will be notified to peer devices.
*
* @param index Preset index.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_has_preset_active_set(uint8_t index);
/**
* @brief Get active preset.
*
* Function used to get the currently active preset index.
*
* @return Active preset index.
*/
uint8_t esp_ble_audio_has_preset_active_get(void);
/**
* @brief Change the Preset Name.
*
* Change the name of the preset identified by @p index.
*
* @param index The index of the preset to change the name of.
* @param name Name to write.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_has_preset_name_change(uint8_t index, const char *name);
/**
* @brief Change the Hearing Aid Features.
*
* Change the hearing aid features.
*
* @param features The features to be set.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_has_features_set(const esp_ble_audio_has_features_param_t *features);
#ifdef __cplusplus
}
#endif
#endif /* ESP_BLE_AUDIO_HAS_API_H_ */
@@ -0,0 +1,89 @@
/*
* SPDX-FileCopyrightText: 2020 Intel Corporation
* SPDX-FileCopyrightText: 2022-2024 Nordic Semiconductor ASA
* SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ESP_BLE_AUDIO_LC3_DEFS_H_
#define ESP_BLE_AUDIO_LC3_DEFS_H_
#include <zephyr/bluetooth/audio/lc3.h>
#include "esp_ble_audio_codec_api.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Helper to declare LC3 codec capability.
*
* @param _freq Supported Sampling Frequencies bitfield.
* @param _duration Supported Frame Durations bitfield.
* @param _chan_count Supported channels.
* @param _len_min Minimum number of octets supported per codec frame.
* @param _len_max Maximum number of octets supported per codec frame.
* @param _max_frames_per_sdu Supported maximum codec frames per SDU.
* Optional and will be included only if != 1.
*/
#define ESP_BLE_AUDIO_CODEC_CAP_LC3_DATA(_freq, _duration, _chan_count, \
_len_min, _len_max, \
_max_frames_per_sdu) \
BT_AUDIO_CODEC_CAP_LC3_DATA(_freq, _duration, _chan_count, \
_len_min, _len_max, \
_max_frames_per_sdu)
/**
* @brief Helper to declare LC3 codec metadata.
*
* @param _prefer_context Preferred contexts.
*/
#define ESP_BLE_AUDIO_CODEC_CAP_LC3_META(_prefer_context) \
BT_AUDIO_CODEC_CAP_LC3_META(_prefer_context)
/**
* @brief Helper to declare LC3 codec capability.
*
* @param _data LC3 codec capability data.
* @param _meta LC3 codec capability metadata.
*/
#define ESP_BLE_AUDIO_CODEC_CAP_LC3(_data, _meta) \
ESP_BLE_AUDIO_CODEC_CAP(ESP_BLE_ISO_CODING_FORMAT_LC3, 0x0000, 0x0000, _data, _meta)
/**
* @brief Helper to declare LC3 codec data configuration.
*
* @param _freq Sampling frequency.
* @param _duration Frame duration.
* @param _loc Audio channel location bitfield.
* @param _len Octets per frame (16-bit integer).
* @param _frames_per_sdu Frames per SDU (8-bit integer). This value is
* optional and will be included only if != 1.
*/
#define ESP_BLE_AUDIO_CODEC_CFG_LC3_DATA(_freq, _duration, _loc, _len, _frames_per_sdu) \
BT_AUDIO_CODEC_CFG_LC3_DATA(_freq, _duration, _loc, _len, _frames_per_sdu)
/**
* @brief Helper to declare LC3 codec metadata configuration.
*
* @param _stream_context Stream context.
*/
#define ESP_BLE_AUDIO_CODEC_CFG_LC3_META(_stream_context) \
BT_AUDIO_CODEC_CFG_LC3_META(_stream_context)
/**
* @brief Helper to declare LC3 codec configuration.
*
* @param _data LC3 codec configuration data.
* @param _meta LC3 codec configuration metadata.
*/
#define ESP_BLE_AUDIO_CODEC_CFG_LC3(_data, _meta) \
ESP_BLE_AUDIO_CODEC_CFG(ESP_BLE_ISO_CODING_FORMAT_LC3, 0x0000, 0x0000, _data, _meta)
#ifdef __cplusplus
}
#endif
#endif /* ESP_BLE_AUDIO_LC3_DEFS_H_ */
@@ -0,0 +1,393 @@
/*
* SPDX-FileCopyrightText: 2019-2024 Nordic Semiconductor ASA
* SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ESP_BLE_AUDIO_MCC_API_H_
#define ESP_BLE_AUDIO_MCC_API_H_
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include "sdkconfig.h"
#include "esp_err.h"
#include <zephyr/bluetooth/services/ots.h>
#include <zephyr/bluetooth/audio/mcc.h>
#include "common/init.h"
#include "common/host.h"
#include "esp_ble_audio_media_proxy_api.h"
#ifdef __cplusplus
extern "C" {
#endif
/** Media control client callbacks */
typedef struct bt_mcc_cb esp_ble_audio_mcc_cb_t;
/**
* @brief Initialize Media Control Client.
*
* @param cb Callbacks to be used.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_mcc_init(esp_ble_audio_mcc_cb_t *cb);
/**
* @brief Discover Media Control Service.
*
* Discover Media Control Service (MCS) on the server given by the connection
* Optionally subscribe to notifications.
*
* Shall be called once, after media control client initialization and before
* using other media control client functionality.
*
* @param conn_handle Connection handle.
* @param subscribe Whether to subscribe to notifications.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_mcc_discover_mcs(uint16_t conn_handle, bool subscribe);
/**
* @brief Read Media Player Name.
*
* @param conn_handle Connection handle.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_mcc_read_player_name(uint16_t conn_handle);
/**
* @brief Read Icon Object ID.
*
* @param conn_handle Connection handle.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_mcc_read_icon_obj_id(uint16_t conn_handle);
/**
* @brief Read Icon Object URL.
*
* @param conn_handle Connection handle.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_mcc_read_icon_url(uint16_t conn_handle);
/**
* @brief Read Track Title.
*
* @param conn_handle Connection handle.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_mcc_read_track_title(uint16_t conn_handle);
/**
* @brief Read Track Duration.
*
* @param conn_handle Connection handle.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_mcc_read_track_duration(uint16_t conn_handle);
/**
* @brief Read Track Position.
*
* @param conn_handle Connection handle.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_mcc_read_track_position(uint16_t conn_handle);
/**
* @brief Set Track position.
*
* @param conn_handle Connection handle.
* @param pos Track position.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_mcc_set_track_position(uint16_t conn_handle, int32_t pos);
/**
* @brief Read Playback speed.
*
* @param conn_handle Connection handle.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_mcc_read_playback_speed(uint16_t conn_handle);
/**
* @brief Set Playback Speed.
*
* @param conn_handle Connection handle.
* @param speed Playback speed.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_mcc_set_playback_speed(uint16_t conn_handle, int8_t speed);
/**
* @brief Read Seeking speed.
*
* @param conn_handle Connection handle.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_mcc_read_seeking_speed(uint16_t conn_handle);
/**
* @brief Read Track Segments Object ID.
*
* @param conn_handle Connection handle.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_mcc_read_segments_obj_id(uint16_t conn_handle);
/**
* @brief Read Current Track Object ID.
*
* @param conn_handle Connection handle.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_mcc_read_current_track_obj_id(uint16_t conn_handle);
/**
* @brief Set Current Track Object ID.
*
* Set the Current Track to the track given by the @p id parameter.
*
* @param conn_handle Connection handle.
* @param id Object Transfer Service ID (UINT48) of the track to set as the current track.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_mcc_set_current_track_obj_id(uint16_t conn_handle, uint64_t id);
/**
* @brief Read Next Track Object ID.
*
* @param conn_handle Connection handle.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_mcc_read_next_track_obj_id(uint16_t conn_handle);
/**
* @brief Set Next Track Object ID.
*
* @param conn_handle Connection handle.
* @param id Object Transfer Service ID (UINT48) of the track to set as the next track.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_mcc_set_next_track_obj_id(uint16_t conn_handle, uint64_t id);
/**
* @brief Read Current Group Object ID.
*
* @param conn_handle Connection handle.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_mcc_read_current_group_obj_id(uint16_t conn_handle);
/**
* @brief Set Current Group Object ID.
*
* @param conn_handle Connection handle.
* @param id Object Transfer Service ID (UINT48) of the group to set as the current group.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_mcc_set_current_group_obj_id(uint16_t conn_handle, uint64_t id);
/**
* @brief Read Parent Group Object ID.
*
* @param conn_handle Connection handle.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_mcc_read_parent_group_obj_id(uint16_t conn_handle);
/**
* @brief Read Playing Order.
*
* @param conn_handle Connection handle.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_mcc_read_playing_order(uint16_t conn_handle);
/**
* @brief Set Playing Order.
*
* @param conn_handle Connection handle.
* @param order Playing order.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_mcc_set_playing_order(uint16_t conn_handle, uint8_t order);
/**
* @brief Read Playing Orders Supported.
*
* @param conn_handle Connection handle.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_mcc_read_playing_orders_supported(uint16_t conn_handle);
/**
* @brief Read Media State.
*
* @param conn_handle Connection handle.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_mcc_read_media_state(uint16_t conn_handle);
/**
* @brief Send a command.
*
* Write a command (e.g. "play", "pause") to the server's media control point.
*
* @param conn_handle Connection handle.
* @param cmd The command to send.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_mcc_send_cmd(uint16_t conn_handle,
const esp_ble_audio_mpl_cmd_t *cmd);
/**
* @brief Read Opcodes Supported.
*
* @param conn_handle Connection handle.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_mcc_read_opcodes_supported(uint16_t conn_handle);
/**
* @brief Send a Search command.
*
* Write a search to the server's search control point.
*
* @param conn_handle Connection handle.
* @param search The search.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_mcc_send_search(uint16_t conn_handle,
const esp_ble_audio_mpl_search_t *search);
/**
* @brief Search Results Group Object ID.
*
* @param conn_handle Connection handle.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_mcc_read_search_results_obj_id(uint16_t conn_handle);
/**
* @brief Read Content Control ID.
*
* @param conn_handle Connection handle.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_mcc_read_content_control_id(uint16_t conn_handle);
/**
* @brief Read the current object metadata.
*
* @param conn_handle Connection handle.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_mcc_otc_read_object_metadata(uint16_t conn_handle);
/**
* @brief Read the Icon Object.
*
* @param conn_handle Connection handle.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_mcc_otc_read_icon_object(uint16_t conn_handle);
/**
* @brief Read the Track Segments Object.
*
* @param conn_handle Connection handle.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_mcc_otc_read_track_segments_object(uint16_t conn_handle);
/**
* @brief Read the Current Track Object.
*
* @param conn_handle Connection handle.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_mcc_otc_read_current_track_object(uint16_t conn_handle);
/**
* @brief Read the Next Track Object.
*
* @param conn_handle Connection handle.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_mcc_otc_read_next_track_object(uint16_t conn_handle);
/**
* @brief Read the Current Group Object.
*
* @param conn_handle Connection handle.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_mcc_otc_read_current_group_object(uint16_t conn_handle);
/**
* @brief Read the Parent Group Object.
*
* @param conn_handle Connection handle.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_mcc_otc_read_parent_group_object(uint16_t conn_handle);
/**
* @brief Look up MCC OTC instance.
*
* @param conn_handle Connection handle.
*
* @return Pointer to a MCC OTC instance if found else NULL.
*/
struct bt_ots_client *esp_ble_audio_mcc_otc_inst(uint16_t conn_handle);
#ifdef __cplusplus
}
#endif
#endif /* ESP_BLE_AUDIO_MCC_API_H_ */
@@ -0,0 +1,268 @@
/*
* SPDX-FileCopyrightText: 2019-2024 Nordic Semiconductor ASA
* SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ESP_BLE_AUDIO_MCS_DEFS_H_
#define ESP_BLE_AUDIO_MCS_DEFS_H_
#include <zephyr/bluetooth/audio/mcs.h>
#ifdef __cplusplus
extern "C" {
#endif
/*!< Minimum playback speed, resulting in 25% speed */
#define ESP_BLE_AUDIO_MCS_PLAYBACK_SPEED_MIN BT_MCS_PLAYBACK_SPEED_MIN
/*!< Quarter playback speed, resulting in 25% speed */
#define ESP_BLE_AUDIO_MCS_PLAYBACK_SPEED_QUARTER BT_MCS_PLAYBACK_SPEED_QUARTER
/*!< Half playback speed, resulting in 50% speed */
#define ESP_BLE_AUDIO_MCS_PLAYBACK_SPEED_HALF BT_MCS_PLAYBACK_SPEED_HALF
/*!< Unity playback speed, resulting in 100% speed */
#define ESP_BLE_AUDIO_MCS_PLAYBACK_SPEED_UNITY BT_MCS_PLAYBACK_SPEED_UNITY
/*!< Double playback speed, resulting in 200% speed */
#define ESP_BLE_AUDIO_MCS_PLAYBACK_SPEED_DOUBLE BT_MCS_PLAYBACK_SPEED_DOUBLE
/*!< Max playback speed, resulting in 395.7% speed (nearly 400%) */
#define ESP_BLE_AUDIO_MCS_PLAYBACK_SPEED_MAX BT_MCS_PLAYBACK_SPEED_MAX
/*!< Maximum seeking speed - Can be negated */
#define ESP_BLE_AUDIO_MCS_SEEKING_SPEED_FACTOR_MAX BT_MCS_SEEKING_SPEED_FACTOR_MAX
/*!< Minimum seeking speed - Can be negated */
#define ESP_BLE_AUDIO_MCS_SEEKING_SPEED_FACTOR_MIN BT_MCS_SEEKING_SPEED_FACTOR_MIN
/*!< No seeking */
#define ESP_BLE_AUDIO_MCS_SEEKING_SPEED_FACTOR_ZERO BT_MCS_SEEKING_SPEED_FACTOR_ZERO
/*!< A single track is played once; there is no next track. */
#define ESP_BLE_AUDIO_MCS_PLAYING_ORDER_SINGLE_ONCE BT_MCS_PLAYING_ORDER_SINGLE_ONCE
/*!< A single track is played repeatedly; the next track is the current track. */
#define ESP_BLE_AUDIO_MCS_PLAYING_ORDER_SINGLE_REPEAT BT_MCS_PLAYING_ORDER_SINGLE_REPEAT
/*!< The tracks within a group are played once in track order. */
#define ESP_BLE_AUDIO_MCS_PLAYING_ORDER_INORDER_ONCE BT_MCS_PLAYING_ORDER_INORDER_ONCE
/*!< The tracks within a group are played in track order repeatedly. */
#define ESP_BLE_AUDIO_MCS_PLAYING_ORDER_INORDER_REPEAT BT_MCS_PLAYING_ORDER_INORDER_REPEAT
/*!< The tracks within a group are played once only from the oldest first. */
#define ESP_BLE_AUDIO_MCS_PLAYING_ORDER_OLDEST_ONCE BT_MCS_PLAYING_ORDER_OLDEST_ONCE
/*!< The tracks within a group are played from the oldest first repeatedly. */
#define ESP_BLE_AUDIO_MCS_PLAYING_ORDER_OLDEST_REPEAT BT_MCS_PLAYING_ORDER_OLDEST_REPEAT
/*!< The tracks within a group are played once only from the newest first. */
#define ESP_BLE_AUDIO_MCS_PLAYING_ORDER_NEWEST_ONCE BT_MCS_PLAYING_ORDER_NEWEST_ONCE
/*!< The tracks within a group are played from the newest first repeatedly. */
#define ESP_BLE_AUDIO_MCS_PLAYING_ORDER_NEWEST_REPEAT BT_MCS_PLAYING_ORDER_NEWEST_REPEAT
/*!< The tracks within a group are played in random order once. */
#define ESP_BLE_AUDIO_MCS_PLAYING_ORDER_SHUFFLE_ONCE BT_MCS_PLAYING_ORDER_SHUFFLE_ONCE
/*!< The tracks within a group are played in random order repeatedly. */
#define ESP_BLE_AUDIO_MCS_PLAYING_ORDER_SHUFFLE_REPEAT BT_MCS_PLAYING_ORDER_SHUFFLE_REPEAT
/*!< The current track is invalid, and no track has been selected. */
#define ESP_BLE_AUDIO_MCS_MEDIA_STATE_INACTIVE BT_MCS_MEDIA_STATE_INACTIVE
/*!< The media player is playing the current track. */
#define ESP_BLE_AUDIO_MCS_MEDIA_STATE_PLAYING BT_MCS_MEDIA_STATE_PLAYING
/*!< The current track is paused. The media player has a current track, but it is not being played */
#define ESP_BLE_AUDIO_MCS_MEDIA_STATE_PAUSED BT_MCS_MEDIA_STATE_PAUSED
/*!< The current track is fast forwarding or fast rewinding. */
#define ESP_BLE_AUDIO_MCS_MEDIA_STATE_SEEKING BT_MCS_MEDIA_STATE_SEEKING
/*!< Start playing the current track. */
#define ESP_BLE_AUDIO_MCS_OPC_PLAY BT_MCS_OPC_PLAY
/*!< Pause playing the current track. */
#define ESP_BLE_AUDIO_MCS_OPC_PAUSE BT_MCS_OPC_PAUSE
/*!< Fast rewind the current track. */
#define ESP_BLE_AUDIO_MCS_OPC_FAST_REWIND BT_MCS_OPC_FAST_REWIND
/*!< Fast forward the current track. */
#define ESP_BLE_AUDIO_MCS_OPC_FAST_FORWARD BT_MCS_OPC_FAST_FORWARD
/**
* Stop current activity and return to the paused state and set
* the current track position to the start of the current track.
*/
#define ESP_BLE_AUDIO_MCS_OPC_STOP BT_MCS_OPC_STOP
/*!< Set a new current track position relative to the current track position. */
#define ESP_BLE_AUDIO_MCS_OPC_MOVE_RELATIVE BT_MCS_OPC_MOVE_RELATIVE
/**
* Set the current track position to the starting position of
* the previous segment of the current track.
*/
#define ESP_BLE_AUDIO_MCS_OPC_PREV_SEGMENT BT_MCS_OPC_PREV_SEGMENT
/**
* Set the current track position to the starting position of
* the next segment of the current track.
*/
#define ESP_BLE_AUDIO_MCS_OPC_NEXT_SEGMENT BT_MCS_OPC_NEXT_SEGMENT
/**
* Set the current track position to the starting position of
* the first segment of the current track.
*/
#define ESP_BLE_AUDIO_MCS_OPC_FIRST_SEGMENT BT_MCS_OPC_FIRST_SEGMENT
/**
* Set the current track position to the starting position of
* the last segment of the current track.
*/
#define ESP_BLE_AUDIO_MCS_OPC_LAST_SEGMENT BT_MCS_OPC_LAST_SEGMENT
/**
* Set the current track position to the starting position of
* the nth segment of the current track.
*/
#define ESP_BLE_AUDIO_MCS_OPC_GOTO_SEGMENT BT_MCS_OPC_GOTO_SEGMENT
/*!< Set the current track to the previous track based on the playing order. */
#define ESP_BLE_AUDIO_MCS_OPC_PREV_TRACK BT_MCS_OPC_PREV_TRACK
/*!< Set the current track to the next track based on the playing order. */
#define ESP_BLE_AUDIO_MCS_OPC_NEXT_TRACK BT_MCS_OPC_NEXT_TRACK
/*!< Set the current track to the first track based on the playing order. */
#define ESP_BLE_AUDIO_MCS_OPC_FIRST_TRACK BT_MCS_OPC_FIRST_TRACK
/*!< Set the current track to the last track based on the playing order. */
#define ESP_BLE_AUDIO_MCS_OPC_LAST_TRACK BT_MCS_OPC_LAST_TRACK
/*!< Set the current track to the nth track based on the playing order. */
#define ESP_BLE_AUDIO_MCS_OPC_GOTO_TRACK BT_MCS_OPC_GOTO_TRACK
/*!< Set the current group to the previous group in the sequence of groups. */
#define ESP_BLE_AUDIO_MCS_OPC_PREV_GROUP BT_MCS_OPC_PREV_GROUP
/*!< Set the current group to the next group in the sequence of groups. */
#define ESP_BLE_AUDIO_MCS_OPC_NEXT_GROUP BT_MCS_OPC_NEXT_GROUP
/*!< Set the current group to the first group in the sequence of groups. */
#define ESP_BLE_AUDIO_MCS_OPC_FIRST_GROUP BT_MCS_OPC_FIRST_GROUP
/*!< Set the current group to the last group in the sequence of groups. */
#define ESP_BLE_AUDIO_MCS_OPC_LAST_GROUP BT_MCS_OPC_LAST_GROUP
/*!< Set the current group to the nth group in the sequence of groups. */
#define ESP_BLE_AUDIO_MCS_OPC_GOTO_GROUP BT_MCS_OPC_GOTO_GROUP
/*!< Media control point supported opcodes length */
#define ESP_BLE_AUDIO_MCS_OPCODES_SUPPORTED_LEN BT_MCS_OPCODES_SUPPORTED_LEN
/*!< Support the Play opcode */
#define ESP_BLE_AUDIO_MCS_OPC_SUP_PLAY BT_MCS_OPC_SUP_PLAY
/*!< Support the Pause opcode */
#define ESP_BLE_AUDIO_MCS_OPC_SUP_PAUSE BT_MCS_OPC_SUP_PAUSE
/*!< Support the Fast Rewind opcode */
#define ESP_BLE_AUDIO_MCS_OPC_SUP_FAST_REWIND BT_MCS_OPC_SUP_FAST_REWIND
/*!< Support the Fast Forward opcode */
#define ESP_BLE_AUDIO_MCS_OPC_SUP_FAST_FORWARD BT_MCS_OPC_SUP_FAST_FORWARD
/*!< Support the Stop opcode */
#define ESP_BLE_AUDIO_MCS_OPC_SUP_STOP BT_MCS_OPC_SUP_STOP
/*!< Support the Move Relative opcode */
#define ESP_BLE_AUDIO_MCS_OPC_SUP_MOVE_RELATIVE BT_MCS_OPC_SUP_MOVE_RELATIVE
/*!< Support the Previous Segment opcode */
#define ESP_BLE_AUDIO_MCS_OPC_SUP_PREV_SEGMENT BT_MCS_OPC_SUP_PREV_SEGMENT
/*!< Support the Next Segment opcode */
#define ESP_BLE_AUDIO_MCS_OPC_SUP_NEXT_SEGMENT BT_MCS_OPC_SUP_NEXT_SEGMENT
/*!< Support the First Segment opcode */
#define ESP_BLE_AUDIO_MCS_OPC_SUP_FIRST_SEGMENT BT_MCS_OPC_SUP_FIRST_SEGMENT
/*!< Support the Last Segment opcode */
#define ESP_BLE_AUDIO_MCS_OPC_SUP_LAST_SEGMENT BT_MCS_OPC_SUP_LAST_SEGMENT
/*!< Support the Goto Segment opcode */
#define ESP_BLE_AUDIO_MCS_OPC_SUP_GOTO_SEGMENT BT_MCS_OPC_SUP_GOTO_SEGMENT
/*!< Support the Previous Track opcode */
#define ESP_BLE_AUDIO_MCS_OPC_SUP_PREV_TRACK BT_MCS_OPC_SUP_PREV_TRACK
/*!< Support the Next Track opcode */
#define ESP_BLE_AUDIO_MCS_OPC_SUP_NEXT_TRACK BT_MCS_OPC_SUP_NEXT_TRACK
/*!< Support the First Track opcode */
#define ESP_BLE_AUDIO_MCS_OPC_SUP_FIRST_TRACK BT_MCS_OPC_SUP_FIRST_TRACK
/*!< Support the Last Track opcode */
#define ESP_BLE_AUDIO_MCS_OPC_SUP_LAST_TRACK BT_MCS_OPC_SUP_LAST_TRACK
/*!< Support the Goto Track opcode */
#define ESP_BLE_AUDIO_MCS_OPC_SUP_GOTO_TRACK BT_MCS_OPC_SUP_GOTO_TRACK
/*!< Support the Previous Group opcode */
#define ESP_BLE_AUDIO_MCS_OPC_SUP_PREV_GROUP BT_MCS_OPC_SUP_PREV_GROUP
/*!< Support the Next Group opcode */
#define ESP_BLE_AUDIO_MCS_OPC_SUP_NEXT_GROUP BT_MCS_OPC_SUP_NEXT_GROUP
/*!< Support the First Group opcode */
#define ESP_BLE_AUDIO_MCS_OPC_SUP_FIRST_GROUP BT_MCS_OPC_SUP_FIRST_GROUP
/*!< Support the Last Group opcode */
#define ESP_BLE_AUDIO_MCS_OPC_SUP_LAST_GROUP BT_MCS_OPC_SUP_LAST_GROUP
/*!< Support the Goto Group opcode */
#define ESP_BLE_AUDIO_MCS_OPC_SUP_GOTO_GROUP BT_MCS_OPC_SUP_GOTO_GROUP
/** Action requested by the opcode write was completed successfully. */
#define ESP_BLE_AUDIO_MCS_OPC_NTF_SUCCESS BT_MCS_OPC_NTF_SUCCESS
/** An invalid or unsupported opcode was used for the Media Control Point write. */
#define ESP_BLE_AUDIO_MCS_OPC_NTF_NOT_SUPPORTED BT_MCS_OPC_NTF_NOT_SUPPORTED
/**
* The Media Player State characteristic value is Inactive when the opcode is
* received or the result of the requested action of the opcode results in the
* Media Player State characteristic being set to Inactive.
*/
#define ESP_BLE_AUDIO_MCS_OPC_NTF_PLAYER_INACTIVE BT_MCS_OPC_NTF_PLAYER_INACTIVE
/**
* The requested action of any Media Control Point write cannot be completed
* successfully because of a condition within the player.
*/
#define ESP_BLE_AUDIO_MCS_OPC_NTF_CANNOT_BE_COMPLETED BT_MCS_OPC_NTF_CANNOT_BE_COMPLETED
/*!< Search for Track Name */
#define ESP_BLE_AUDIO_MCS_SEARCH_TYPE_TRACK_NAME BT_MCS_SEARCH_TYPE_TRACK_NAME
/*!< Search for Artist Name */
#define ESP_BLE_AUDIO_MCS_SEARCH_TYPE_ARTIST_NAME BT_MCS_SEARCH_TYPE_ARTIST_NAME
/*!< Search for Album Name */
#define ESP_BLE_AUDIO_MCS_SEARCH_TYPE_ALBUM_NAME BT_MCS_SEARCH_TYPE_ALBUM_NAME
/*!< Search for Group Name */
#define ESP_BLE_AUDIO_MCS_SEARCH_TYPE_GROUP_NAME BT_MCS_SEARCH_TYPE_GROUP_NAME
/*!< Search for Earliest Year */
#define ESP_BLE_AUDIO_MCS_SEARCH_TYPE_EARLIEST_YEAR BT_MCS_SEARCH_TYPE_EARLIEST_YEAR
/*!< Search for Latest Year */
#define ESP_BLE_AUDIO_MCS_SEARCH_TYPE_LATEST_YEAR BT_MCS_SEARCH_TYPE_LATEST_YEAR
/*!< Search for Genre */
#define ESP_BLE_AUDIO_MCS_SEARCH_TYPE_GENRE BT_MCS_SEARCH_TYPE_GENRE
/*!< Search for Tracks only */
#define ESP_BLE_AUDIO_MCS_SEARCH_TYPE_ONLY_TRACKS BT_MCS_SEARCH_TYPE_ONLY_TRACKS
/*!< Search for Groups only */
#define ESP_BLE_AUDIO_MCS_SEARCH_TYPE_ONLY_GROUPS BT_MCS_SEARCH_TYPE_ONLY_GROUPS
/*!< Search control point minimum length */
#define ESP_BLE_AUDIO_SEARCH_LEN_MIN SEARCH_LEN_MIN
/*!< Search control point maximum length */
#define ESP_BLE_AUDIO_SEARCH_LEN_MAX SEARCH_LEN_MAX
/*!< Search control point item (SCI) minimum length */
#define ESP_BLE_AUDIO_SEARCH_SCI_LEN_MIN SEARCH_SCI_LEN_MIN
/*!< Search parameters maximum length */
#define ESP_BLE_AUDIO_SEARCH_PARAM_MAX SEARCH_PARAM_MAX
/*!< Search request was accepted; search has started. */
#define ESP_BLE_AUDIO_MCS_SCP_NTF_SUCCESS BT_MCS_SCP_NTF_SUCCESS
/*!< Search request was invalid; no search started. */
#define ESP_BLE_AUDIO_MCS_SCP_NTF_FAILURE BT_MCS_SCP_NTF_FAILURE
/*!< Group object type is track */
#define ESP_BLE_AUDIO_MCS_GROUP_OBJECT_TRACK_TYPE BT_MCS_GROUP_OBJECT_TRACK_TYPE
/*!< Group object type is group */
#define ESP_BLE_AUDIO_MCS_GROUP_OBJECT_GROUP_TYPE BT_MCS_GROUP_OBJECT_GROUP_TYPE
/*!< A single track is played once; there is no next track. */
#define ESP_BLE_AUDIO_MCS_PLAYING_ORDERS_SUPPORTED_SINGLE_ONCE BT_MCS_PLAYING_ORDERS_SUPPORTED_SINGLE_ONCE
/*!< A single track is played repeatedly; the next track is the current track. */
#define ESP_BLE_AUDIO_MCS_PLAYING_ORDERS_SUPPORTED_SINGLE_REPEAT BT_MCS_PLAYING_ORDERS_SUPPORTED_SINGLE_REPEAT
/*!< The tracks within a group are played once in track order. */
#define ESP_BLE_AUDIO_MCS_PLAYING_ORDERS_SUPPORTED_INORDER_ONCE BT_MCS_PLAYING_ORDERS_SUPPORTED_INORDER_ONCE
/*!< The tracks within a group are played in track order repeatedly. */
#define ESP_BLE_AUDIO_MCS_PLAYING_ORDERS_SUPPORTED_INORDER_REPEAT BT_MCS_PLAYING_ORDERS_SUPPORTED_INORDER_REPEAT
/*!< The tracks within a group are played once only from the oldest first. */
#define ESP_BLE_AUDIO_MCS_PLAYING_ORDERS_SUPPORTED_OLDEST_ONCE BT_MCS_PLAYING_ORDERS_SUPPORTED_OLDEST_ONCE
/*!< The tracks within a group are played from the oldest first repeatedly. */
#define ESP_BLE_AUDIO_MCS_PLAYING_ORDERS_SUPPORTED_OLDEST_REPEAT BT_MCS_PLAYING_ORDERS_SUPPORTED_OLDEST_REPEAT
/*!< The tracks within a group are played once only from the newest first. */
#define ESP_BLE_AUDIO_MCS_PLAYING_ORDERS_SUPPORTED_NEWEST_ONCE BT_MCS_PLAYING_ORDERS_SUPPORTED_NEWEST_ONCE
/*!< The tracks within a group are played from the newest first repeatedly. */
#define ESP_BLE_AUDIO_MCS_PLAYING_ORDERS_SUPPORTED_NEWEST_REPEAT BT_MCS_PLAYING_ORDERS_SUPPORTED_NEWEST_REPEAT
/*!< The tracks within a group are played in random order once. */
#define ESP_BLE_AUDIO_MCS_PLAYING_ORDERS_SUPPORTED_SHUFFLE_ONCE BT_MCS_PLAYING_ORDERS_SUPPORTED_SHUFFLE_ONCE
/*!< The tracks within a group are played in random order repeatedly. */
#define ESP_BLE_AUDIO_MCS_PLAYING_ORDERS_SUPPORTED_SHUFFLE_REPEAT BT_MCS_PLAYING_ORDERS_SUPPORTED_SHUFFLE_REPEAT
/**
* Check if an Object ID is valid for MCS.
* This differs from BT_OTS_VALID_OBJ_ID as MCS does not use the directory list object.
*/
#define ESP_BLE_AUDIO_MCS_VALID_OBJ_ID(id) \
(IN_RANGE((id), BT_OTS_OBJ_ID_MIN, BT_OTS_OBJ_ID_MAX))
#ifdef __cplusplus
}
#endif
#endif /* ESP_BLE_AUDIO_MCS_DEFS_H_ */
@@ -0,0 +1,743 @@
/*
* SPDX-FileCopyrightText: 2019-2024 Nordic Semiconductor ASA
* SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ESP_BLE_AUDIO_MEDIA_PROXY_API_H_
#define ESP_BLE_AUDIO_MEDIA_PROXY_API_H_
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include "sdkconfig.h"
#include "esp_err.h"
#include <zephyr/bluetooth/services/ots.h>
#include <zephyr/bluetooth/audio/media_proxy.h>
#include "common/init.h"
#include "common/host.h"
#ifdef __cplusplus
extern "C" {
#endif
/*!< Minimum playback speed, resulting in 25% speed */
#define ESP_BLE_AUDIO_MEDIA_PROXY_PLAYBACK_SPEED_MIN MEDIA_PROXY_PLAYBACK_SPEED_MIN
/*!< Quarter playback speed, resulting in 25% speed */
#define ESP_BLE_AUDIO_MEDIA_PROXY_PLAYBACK_SPEED_QUARTER MEDIA_PROXY_PLAYBACK_SPEED_QUARTER
/*!< Half playback speed, resulting in 50% speed */
#define ESP_BLE_AUDIO_MEDIA_PROXY_PLAYBACK_SPEED_HALF MEDIA_PROXY_PLAYBACK_SPEED_HALF
/*!< Unity playback speed, resulting in 100% speed */
#define ESP_BLE_AUDIO_MEDIA_PROXY_PLAYBACK_SPEED_UNITY MEDIA_PROXY_PLAYBACK_SPEED_UNITY
/*!< Double playback speed, resulting in 200% speed */
#define ESP_BLE_AUDIO_MEDIA_PROXY_PLAYBACK_SPEED_DOUBLE MEDIA_PROXY_PLAYBACK_SPEED_DOUBLE
/*!< Max playback speed, resulting in 395.7% speed (nearly 400%) */
#define ESP_BLE_AUDIO_MEDIA_PROXY_PLAYBACK_SPEED_MAX MEDIA_PROXY_PLAYBACK_SPEED_MAX
/*!< The current track is invalid, and no track has been selected. */
#define ESP_BLE_AUDIO_MEDIA_PROXY_STATE_INACTIVE MEDIA_PROXY_STATE_INACTIVE
/*!< The media player is playing the current track. */
#define ESP_BLE_AUDIO_MEDIA_PROXY_STATE_PLAYING MEDIA_PROXY_STATE_PLAYING
/*!< The current track is paused. The media player has a current track, but it is not being played */
#define ESP_BLE_AUDIO_MEDIA_PROXY_STATE_PAUSED MEDIA_PROXY_STATE_PAUSED
/*!< The current track is fast forwarding or fast rewinding. */
#define ESP_BLE_AUDIO_MEDIA_PROXY_STATE_SEEKING MEDIA_PROXY_STATE_SEEKING
/*!< Used internally as the last state value */
#define ESP_BLE_AUDIO_MEDIA_PROXY_STATE_LAST MEDIA_PROXY_STATE_LAST
/*!< Start playing the current track. */
#define ESP_BLE_AUDIO_MEDIA_PROXY_OP_PLAY MEDIA_PROXY_OP_PLAY
/*!< Pause playing the current track. */
#define ESP_BLE_AUDIO_MEDIA_PROXY_OP_PAUSE MEDIA_PROXY_OP_PAUSE
/*!< Fast rewind the current track. */
#define ESP_BLE_AUDIO_MEDIA_PROXY_OP_FAST_REWIND MEDIA_PROXY_OP_FAST_REWIND
/*!< Fast forward the current track. */
#define ESP_BLE_AUDIO_MEDIA_PROXY_OP_FAST_FORWARD MEDIA_PROXY_OP_FAST_FORWARD
/**
* Stop current activity and return to the paused state and set
* the current track position to the start of the current track.
*/
#define ESP_BLE_AUDIO_MEDIA_PROXY_OP_STOP MEDIA_PROXY_OP_STOP
/*!< Set a new current track position relative to the current track position. */
#define ESP_BLE_AUDIO_MEDIA_PROXY_OP_MOVE_RELATIVE MEDIA_PROXY_OP_MOVE_RELATIVE
/**
* Set the current track position to the starting position of
* the previous segment of the current track.
*/
#define ESP_BLE_AUDIO_MEDIA_PROXY_OP_PREV_SEGMENT MEDIA_PROXY_OP_PREV_SEGMENT
/**
* Set the current track position to the starting position of
* the next segment of the current track.
*/
#define ESP_BLE_AUDIO_MEDIA_PROXY_OP_NEXT_SEGMENT MEDIA_PROXY_OP_NEXT_SEGMENT
/**
* Set the current track position to the starting position of
* the first segment of the current track.
*/
#define ESP_BLE_AUDIO_MEDIA_PROXY_OP_FIRST_SEGMENT MEDIA_PROXY_OP_FIRST_SEGMENT
/**
* Set the current track position to the starting position of
* the last segment of the current track.
*/
#define ESP_BLE_AUDIO_MEDIA_PROXY_OP_LAST_SEGMENT MEDIA_PROXY_OP_LAST_SEGMENT
/**
* Set the current track position to the starting position of
* the nth segment of the current track.
*/
#define ESP_BLE_AUDIO_MEDIA_PROXY_OP_GOTO_SEGMENT MEDIA_PROXY_OP_GOTO_SEGMENT
/*!< Set the current track to the previous track based on the playing order. */
#define ESP_BLE_AUDIO_MEDIA_PROXY_OP_PREV_TRACK MEDIA_PROXY_OP_PREV_TRACK
/*!< Set the current track to the next track based on the playing order. */
#define ESP_BLE_AUDIO_MEDIA_PROXY_OP_NEXT_TRACK MEDIA_PROXY_OP_NEXT_TRACK
/*!< Set the current track to the first track based on the playing order. */
#define ESP_BLE_AUDIO_MEDIA_PROXY_OP_FIRST_TRACK MEDIA_PROXY_OP_FIRST_TRACK
/*!< Set the current track to the last track based on the playing order. */
#define ESP_BLE_AUDIO_MEDIA_PROXY_OP_LAST_TRACK MEDIA_PROXY_OP_LAST_TRACK
/*!< Set the current track to the nth track based on the playing order. */
#define ESP_BLE_AUDIO_MEDIA_PROXY_OP_GOTO_TRACK MEDIA_PROXY_OP_GOTO_TRACK
/*!< Set the current group to the previous group in the sequence of groups. */
#define ESP_BLE_AUDIO_MEDIA_PROXY_OP_PREV_GROUP MEDIA_PROXY_OP_PREV_GROUP
/*!< Set the current group to the next group in the sequence of groups. */
#define ESP_BLE_AUDIO_MEDIA_PROXY_OP_NEXT_GROUP MEDIA_PROXY_OP_NEXT_GROUP
/*!< Set the current group to the first group in the sequence of groups. */
#define ESP_BLE_AUDIO_MEDIA_PROXY_OP_FIRST_GROUP MEDIA_PROXY_OP_FIRST_GROUP
/*!< Set the current group to the last group in the sequence of groups. */
#define ESP_BLE_AUDIO_MEDIA_PROXY_OP_LAST_GROUP MEDIA_PROXY_OP_LAST_GROUP
/*!< Set the current group to the nth group in the sequence of groups. */
#define ESP_BLE_AUDIO_MEDIA_PROXY_OP_GOTO_GROUP MEDIA_PROXY_OP_GOTO_GROUP
/*!< Media player supported opcodes length */
#define ESP_BLE_AUDIO_MEDIA_PROXY_OPCODES_SUPPORTED_LEN MEDIA_PROXY_OPCODES_SUPPORTED_LEN
/*!< Support the Play opcode */
#define ESP_BLE_AUDIO_MEDIA_PROXY_OP_SUP_PLAY MEDIA_PROXY_OP_SUP_PLAY
/*!< Support the Pause opcode */
#define ESP_BLE_AUDIO_MEDIA_PROXY_OP_SUP_PAUSE MEDIA_PROXY_OP_SUP_PAUSE
/*!< Support the Fast Rewind opcode */
#define ESP_BLE_AUDIO_MEDIA_PROXY_OP_SUP_FAST_REWIND MEDIA_PROXY_OP_SUP_FAST_REWIND
/*!< Support the Fast Forward opcode */
#define ESP_BLE_AUDIO_MEDIA_PROXY_OP_SUP_FAST_FORWARD MEDIA_PROXY_OP_SUP_FAST_FORWARD
/*!< Support the Stop opcode */
#define ESP_BLE_AUDIO_MEDIA_PROXY_OP_SUP_STOP MEDIA_PROXY_OP_SUP_STOP
/*!< Support the Move Relative opcode */
#define ESP_BLE_AUDIO_MEDIA_PROXY_OP_SUP_MOVE_RELATIVE MEDIA_PROXY_OP_SUP_MOVE_RELATIVE
/*!< Support the Previous Segment opcode */
#define ESP_BLE_AUDIO_MEDIA_PROXY_OP_SUP_PREV_SEGMENT MEDIA_PROXY_OP_SUP_PREV_SEGMENT
/*!< Support the Next Segment opcode */
#define ESP_BLE_AUDIO_MEDIA_PROXY_OP_SUP_NEXT_SEGMENT MEDIA_PROXY_OP_SUP_NEXT_SEGMENT
/*!< Support the First Segment opcode */
#define ESP_BLE_AUDIO_MEDIA_PROXY_OP_SUP_FIRST_SEGMENT MEDIA_PROXY_OP_SUP_FIRST_SEGMENT
/*!< Support the Last Segment opcode */
#define ESP_BLE_AUDIO_MEDIA_PROXY_OP_SUP_LAST_SEGMENT MEDIA_PROXY_OP_SUP_LAST_SEGMENT
/*!< Support the Goto Segment opcode */
#define ESP_BLE_AUDIO_MEDIA_PROXY_OP_SUP_GOTO_SEGMENT MEDIA_PROXY_OP_SUP_GOTO_SEGMENT
/*!< Support the Previous Track opcode */
#define ESP_BLE_AUDIO_MEDIA_PROXY_OP_SUP_PREV_TRACK MEDIA_PROXY_OP_SUP_PREV_TRACK
/*!< Support the Next Track opcode */
#define ESP_BLE_AUDIO_MEDIA_PROXY_OP_SUP_NEXT_TRACK MEDIA_PROXY_OP_SUP_NEXT_TRACK
/*!< Support the First Track opcode */
#define ESP_BLE_AUDIO_MEDIA_PROXY_OP_SUP_FIRST_TRACK MEDIA_PROXY_OP_SUP_FIRST_TRACK
/*!< Support the Last Track opcode */
#define ESP_BLE_AUDIO_MEDIA_PROXY_OP_SUP_LAST_TRACK MEDIA_PROXY_OP_SUP_LAST_TRACK
/*!< Support the Goto Track opcode */
#define ESP_BLE_AUDIO_MEDIA_PROXY_OP_SUP_GOTO_TRACK MEDIA_PROXY_OP_SUP_GOTO_TRACK
/*!< Support the Previous Group opcode */
#define ESP_BLE_AUDIO_MEDIA_PROXY_OP_SUP_PREV_GROUP MEDIA_PROXY_OP_SUP_PREV_GROUP
/*!< Support the Next Group opcode */
#define ESP_BLE_AUDIO_MEDIA_PROXY_OP_SUP_NEXT_GROUP MEDIA_PROXY_OP_SUP_NEXT_GROUP
/*!< Support the First Group opcode */
#define ESP_BLE_AUDIO_MEDIA_PROXY_OP_SUP_FIRST_GROUP MEDIA_PROXY_OP_SUP_FIRST_GROUP
/*!< Support the Last Group opcode */
#define ESP_BLE_AUDIO_MEDIA_PROXY_OP_SUP_LAST_GROUP MEDIA_PROXY_OP_SUP_LAST_GROUP
/*!< Support the Goto Group opcode */
#define ESP_BLE_AUDIO_MEDIA_PROXY_OP_SUP_GOTO_GROUP MEDIA_PROXY_OP_SUP_GOTO_GROUP
/*!< Action requested by the opcode write was completed successfully. */
#define ESP_BLE_AUDIO_MEDIA_PROXY_CMD_SUCCESS MEDIA_PROXY_CMD_SUCCESS
/*!< An invalid or unsupported opcode was used for the Media Control Point write. */
#define ESP_BLE_AUDIO_MEDIA_PROXY_CMD_NOT_SUPPORTED MEDIA_PROXY_CMD_NOT_SUPPORTED
/**
* The Media Player State characteristic value is Inactive when the opcode
* is received or the result of the requested action of the opcode results
* in the Media Player State characteristic being set to Inactive.
*/
#define ESP_BLE_AUDIO_MEDIA_PROXY_CMD_PLAYER_INACTIVE MEDIA_PROXY_CMD_PLAYER_INACTIVE
/**
* The requested action of any Media Control Point write cannot be completed
* successfully because of a condition within the player.
*/
#define ESP_BLE_AUDIO_MEDIA_PROXY_CMD_CANNOT_BE_COMPLETED MEDIA_PROXY_CMD_CANNOT_BE_COMPLETED
/*!< Search for Track Name */
#define ESP_BLE_AUDIO_MEDIA_PROXY_SEARCH_TYPE_TRACK_NAME MEDIA_PROXY_SEARCH_TYPE_TRACK_NAME
/*!< Search for Artist Name */
#define ESP_BLE_AUDIO_MEDIA_PROXY_SEARCH_TYPE_ARTIST_NAME MEDIA_PROXY_SEARCH_TYPE_ARTIST_NAME
/*!< Search for Album Name */
#define ESP_BLE_AUDIO_MEDIA_PROXY_SEARCH_TYPE_ALBUM_NAME MEDIA_PROXY_SEARCH_TYPE_ALBUM_NAME
/*!< Search for Group Name */
#define ESP_BLE_AUDIO_MEDIA_PROXY_SEARCH_TYPE_GROUP_NAME MEDIA_PROXY_SEARCH_TYPE_GROUP_NAME
/*!< Search for Earliest Year */
#define ESP_BLE_AUDIO_MEDIA_PROXY_SEARCH_TYPE_EARLIEST_YEAR MEDIA_PROXY_SEARCH_TYPE_EARLIEST_YEAR
/*!< Search for Latest Year */
#define ESP_BLE_AUDIO_MEDIA_PROXY_SEARCH_TYPE_LATEST_YEAR MEDIA_PROXY_SEARCH_TYPE_LATEST_YEAR
/*!< Search for Genre */
#define ESP_BLE_AUDIO_MEDIA_PROXY_SEARCH_TYPE_GENRE MEDIA_PROXY_SEARCH_TYPE_GENRE
/*!< Search for Tracks only */
#define ESP_BLE_AUDIO_MEDIA_PROXY_SEARCH_TYPE_ONLY_TRACKS MEDIA_PROXY_SEARCH_TYPE_ONLY_TRACKS
/*!< Search for Groups only */
#define ESP_BLE_AUDIO_MEDIA_PROXY_SEARCH_TYPE_ONLY_GROUPS MEDIA_PROXY_SEARCH_TYPE_ONLY_GROUPS
/*!< Search request was accepted; search has started. */
#define ESP_BLE_AUDIO_MEDIA_PROXY_SEARCH_SUCCESS MEDIA_PROXY_SEARCH_SUCCESS
/*!< Search request was invalid; no search started. */
#define ESP_BLE_AUDIO_MEDIA_PROXY_SEARCH_FAILURE MEDIA_PROXY_SEARCH_FAILURE
/*!< Group object type is track */
#define ESP_BLE_AUDIO_MEDIA_PROXY_GROUP_OBJECT_TRACK_TYPE MEDIA_PROXY_GROUP_OBJECT_TRACK_TYPE
/*!< Group object type is group */
#define ESP_BLE_AUDIO_MEDIA_PROXY_GROUP_OBJECT_GROUP_TYPE MEDIA_PROXY_GROUP_OBJECT_GROUP_TYPE
/*!< Maximum seeking speed - Can be negated */
#define ESP_BLE_AUDIO_MEDIA_PROXY_SEEKING_SPEED_FACTOR_MAX MEDIA_PROXY_SEEKING_SPEED_FACTOR_MAX
/*!< Minimum seeking speed - Can be negated */
#define ESP_BLE_AUDIO_MEDIA_PROXY_SEEKING_SPEED_FACTOR_MIN MEDIA_PROXY_SEEKING_SPEED_FACTOR_MIN
/*!< No seeking */
#define ESP_BLE_AUDIO_MEDIA_PROXY_SEEKING_SPEED_FACTOR_ZERO MEDIA_PROXY_SEEKING_SPEED_FACTOR_ZERO
/*!< A single track is played once; there is no next track. */
#define ESP_BLE_AUDIO_MEDIA_PROXY_PLAYING_ORDER_SINGLE_ONCE MEDIA_PROXY_PLAYING_ORDER_SINGLE_ONCE
/*!< A single track is played repeatedly; the next track is the current track. */
#define ESP_BLE_AUDIO_MEDIA_PROXY_PLAYING_ORDER_SINGLE_REPEAT MEDIA_PROXY_PLAYING_ORDER_SINGLE_REPEAT
/*!< The tracks within a group are played once in track order. */
#define ESP_BLE_AUDIO_MEDIA_PROXY_PLAYING_ORDER_INORDER_ONCE MEDIA_PROXY_PLAYING_ORDER_INORDER_ONCE
/*!< The tracks within a group are played in track order repeatedly. */
#define ESP_BLE_AUDIO_MEDIA_PROXY_PLAYING_ORDER_INORDER_REPEAT MEDIA_PROXY_PLAYING_ORDER_INORDER_REPEAT
/*!< The tracks within a group are played once only from the oldest first. */
#define ESP_BLE_AUDIO_MEDIA_PROXY_PLAYING_ORDER_OLDEST_ONCE MEDIA_PROXY_PLAYING_ORDER_OLDEST_ONCE
/*!< The tracks within a group are played from the oldest first repeatedly. */
#define ESP_BLE_AUDIO_MEDIA_PROXY_PLAYING_ORDER_OLDEST_REPEAT MEDIA_PROXY_PLAYING_ORDER_OLDEST_REPEAT
/*!< The tracks within a group are played once only from the newest first. */
#define ESP_BLE_AUDIO_MEDIA_PROXY_PLAYING_ORDER_NEWEST_ONCE MEDIA_PROXY_PLAYING_ORDER_NEWEST_ONCE
/*!< The tracks within a group are played from the newest first repeatedly. */
#define ESP_BLE_AUDIO_MEDIA_PROXY_PLAYING_ORDER_NEWEST_REPEAT MEDIA_PROXY_PLAYING_ORDER_NEWEST_REPEAT
/*!< The tracks within a group are played in random order once. */
#define ESP_BLE_AUDIO_MEDIA_PROXY_PLAYING_ORDER_SHUFFLE_ONCE MEDIA_PROXY_PLAYING_ORDER_SHUFFLE_ONCE
/*!< The tracks within a group are played in random order repeatedly. */
#define ESP_BLE_AUDIO_MEDIA_PROXY_PLAYING_ORDER_SHUFFLE_REPEAT MEDIA_PROXY_PLAYING_ORDER_SHUFFLE_REPEAT
/*!< A single track is played once; there is no next track. */
#define ESP_BLE_AUDIO_MEDIA_PROXY_PLAYING_ORDERS_SUPPORTED_SINGLE_ONCE MEDIA_PROXY_PLAYING_ORDERS_SUPPORTED_SINGLE_ONCE
/*!< A single track is played repeatedly; the next track is the current track. */
#define ESP_BLE_AUDIO_MEDIA_PROXY_PLAYING_ORDERS_SUPPORTED_SINGLE_REPEAT MEDIA_PROXY_PLAYING_ORDERS_SUPPORTED_SINGLE_REPEAT
/*!< The tracks within a group are played once in track order. */
#define ESP_BLE_AUDIO_MEDIA_PROXY_PLAYING_ORDERS_SUPPORTED_INORDER_ONCE MEDIA_PROXY_PLAYING_ORDERS_SUPPORTED_INORDER_ONCE
/*!< The tracks within a group are played in track order repeatedly. */
#define ESP_BLE_AUDIO_MEDIA_PROXY_PLAYING_ORDERS_SUPPORTED_INORDER_REPEAT MEDIA_PROXY_PLAYING_ORDERS_SUPPORTED_INORDER_REPEAT
/*!< The tracks within a group are played once only from the oldest first. */
#define ESP_BLE_AUDIO_MEDIA_PROXY_PLAYING_ORDERS_SUPPORTED_OLDEST_ONCE MEDIA_PROXY_PLAYING_ORDERS_SUPPORTED_OLDEST_ONCE
/*!< The tracks within a group are played from the oldest first repeatedly. */
#define ESP_BLE_AUDIO_MEDIA_PROXY_PLAYING_ORDERS_SUPPORTED_OLDEST_REPEAT MEDIA_PROXY_PLAYING_ORDERS_SUPPORTED_OLDEST_REPEAT
/*!< The tracks within a group are played once only from the newest first. */
#define ESP_BLE_AUDIO_MEDIA_PROXY_PLAYING_ORDERS_SUPPORTED_NEWEST_ONCE MEDIA_PROXY_PLAYING_ORDERS_SUPPORTED_NEWEST_ONCE
/*!< The tracks within a group are played from the newest first repeatedly. */
#define ESP_BLE_AUDIO_MEDIA_PROXY_PLAYING_ORDERS_SUPPORTED_NEWEST_REPEAT MEDIA_PROXY_PLAYING_ORDERS_SUPPORTED_NEWEST_REPEAT
/*!< The tracks within a group are played in random order once. */
#define ESP_BLE_AUDIO_MEDIA_PROXY_PLAYING_ORDERS_SUPPORTED_SHUFFLE_ONCE MEDIA_PROXY_PLAYING_ORDERS_SUPPORTED_SHUFFLE_ONCE
/*!< The tracks within a group are played in random order repeatedly. */
#define ESP_BLE_AUDIO_MEDIA_PROXY_PLAYING_ORDERS_SUPPORTED_SHUFFLE_REPEAT MEDIA_PROXY_PLAYING_ORDERS_SUPPORTED_SHUFFLE_REPEAT
/** Media player command */
typedef struct mpl_cmd esp_ble_audio_mpl_cmd_t;
/** Media command notification */
typedef struct mpl_cmd_ntf esp_ble_audio_mpl_cmd_ntf_t;
/** Search control item */
typedef struct mpl_sci esp_ble_audio_mpl_sci_t;
/** Search */
typedef struct mpl_search esp_ble_audio_mpl_search_t;
/** Media player instance */
typedef struct media_player esp_ble_audio_media_player_t;
/** Callbacks to a controller, from the media proxy */
typedef struct media_proxy_ctrl_cbs esp_ble_audio_media_proxy_ctrl_cbs_t;
/** Available calls in a player, that the media proxy can call */
typedef struct media_proxy_pl_calls esp_ble_audio_media_proxy_pl_calls_t;
/**
* @brief Register a controller with the media_proxy.
*
* @param ctrl_cbs Callbacks to the controller.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_media_proxy_ctrl_register(esp_ble_audio_media_proxy_ctrl_cbs_t *ctrl_cbs);
/**
* @brief Discover a remote media player.
*
* Discover a remote media player instance.
* The remote player instance will be discovered, and accessed, using Bluetooth,
* via the media control client and a remote media control service.
* This call will start a GATT discovery of the Media Control Service on the peer,
* and setup handles and subscriptions.
*
* This shall be called once before any other actions can be executed for the
* remote player. The remote player instance will be returned in the
* discover_player() callback.
*
* @param conn_handle Connection handle.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_media_proxy_ctrl_discover_player(uint16_t conn_handle);
/**
* @brief Read Media Player Name.
*
* @param player Media player instance pointer.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_media_proxy_ctrl_get_player_name(esp_ble_audio_media_player_t *player);
/**
* @brief Read Icon Object ID.
*
* Get an ID (48 bit) that can be used to retrieve the Icon
* Object from an Object Transfer Service.
*
* See the Media Control Service spec v1.0 sections 3.2 and
* 4.1 for a description of the Icon Object.
*
* Requires Object Transfer Service
*
* @param player Media player instance pointer.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_media_proxy_ctrl_get_icon_id(esp_ble_audio_media_player_t *player);
/**
* @brief Read Icon URL.
*
* Get a URL to the media player's icon.
*
* @param player Media player instance pointer.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_media_proxy_ctrl_get_icon_url(esp_ble_audio_media_player_t *player);
/**
* @brief Read Track Title.
*
* @param player Media player instance pointer.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_media_proxy_ctrl_get_track_title(esp_ble_audio_media_player_t *player);
/**
* @brief Read Track Duration.
*
* The duration of a track is measured in hundredths of a second.
*
* @param player Media player instance pointer.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_media_proxy_ctrl_get_track_duration(esp_ble_audio_media_player_t *player);
/**
* @brief Read Track Position.
*
* The position of the player (the playing position) is measured
* in hundredths of a second from the beginning of the track.
*
* @param player Media player instance pointer.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_media_proxy_ctrl_get_track_position(esp_ble_audio_media_player_t *player);
/**
* @brief Set Track Position.
*
* Set the playing position of the media player in the current
* track. The position is given in hundredths of a second,
* from the beginning of the track of the track for positive
* values, and (backwards) from the end of the track for
* negative values.
*
* @param player Media player instance pointer.
* @param position The track position to set.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_media_proxy_ctrl_set_track_position(esp_ble_audio_media_player_t *player,
int32_t position);
/**
* @brief Get Playback Speed.
*
* The playback speed parameter is related to the actual
* playback speed as follows:
* actual playback speed = 2^(speed_parameter/64)
*
* A speed parameter of 0 corresponds to unity speed playback
* (i.e. playback at "normal" speed). A speed parameter of
* -128 corresponds to playback at one fourth of normal speed,
* 127 corresponds to playback at almost four times the normal
* speed.
*
* @param player Media player instance pointer.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_media_proxy_ctrl_get_playback_speed(esp_ble_audio_media_player_t *player);
/**
* @brief Set Playback Speed.
*
* See the get_playback_speed() function for an explanation of
* the playback speed parameter.
*
* Note that the media player may not support all possible
* values of the playback speed parameter. If the value given
* is not supported, and is higher than the current value, the
* player should set the playback speed to the next higher
* supported value. (And correspondingly to the next lower
* supported value for given values lower than the current
* value.)
*
* @param player Media player instance pointer.
* @param speed The playback speed parameter to set.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_media_proxy_ctrl_set_playback_speed(esp_ble_audio_media_player_t *player,
int8_t speed);
/**
* @brief Get Seeking Speed.
*
* The seeking speed gives the speed with which the player is
* seeking. It is a factor, relative to real-time playback
* speed - a factor four means seeking happens at four times
* the real-time playback speed. Positive values are for
* forward seeking, negative values for backwards seeking.
*
* The seeking speed is not settable - a non-zero seeking speed
* is the result of "fast rewind" of "fast forward" commands.
*
* @param player Media player instance pointer.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_media_proxy_ctrl_get_seeking_speed(esp_ble_audio_media_player_t *player);
/**
* @brief Read Current Track Segments Object ID.
*
* Get an ID (48 bit) that can be used to retrieve the Current
* Track Segments Object from an Object Transfer Service.
*
* See the Media Control Service spec v1.0 sections 3.10 and
* 4.2 for a description of the Track Segments Object.
*
* Requires Object Transfer Service.
*
* @param player Media player instance pointer.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_media_proxy_ctrl_get_track_segments_id(esp_ble_audio_media_player_t *player);
/**
* @brief Read Current Track Object ID.
*
* Get an ID (48 bit) that can be used to retrieve the Current
* Track Object from an Object Transfer Service.
*
* See the Media Control Service spec v1.0 sections 3.11 and
* 4.3 for a description of the Current Track Object.
*
* Requires Object Transfer Service.
*
* @param player Media player instance pointer.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_media_proxy_ctrl_get_current_track_id(esp_ble_audio_media_player_t *player);
/**
* @brief Set Current Track Object ID.
*
* Change the player's current track to the track given by the ID.
* (Behaves similarly to the goto track command.)
*
* Requires Object Transfer Service.
*
* @param player Media player instance pointer.
* @param id The ID of a track object.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_media_proxy_ctrl_set_current_track_id(esp_ble_audio_media_player_t *player,
uint64_t id);
/**
* @brief Read Next Track Object ID.
*
* Get an ID (48 bit) that can be used to retrieve the Next
* Track Object from an Object Transfer Service.
*
* Requires Object Transfer Service.
*
* @param player Media player instance pointer.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_media_proxy_ctrl_get_next_track_id(esp_ble_audio_media_player_t *player);
/**
* @brief Set Next Track Object ID.
*
* Change the player's next track to the track given by the ID.
*
* Requires Object Transfer Service.
*
* @param player Media player instance pointer.
* @param id The ID of a track object.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_media_proxy_ctrl_set_next_track_id(esp_ble_audio_media_player_t *player,
uint64_t id);
/**
* @brief Read Parent Group Object ID.
*
* Get an ID (48 bit) that can be used to retrieve the Parent
* Track Object from an Object Transfer Service.
*
* The parent group is the parent of the current group.
*
* See the Media Control Service spec v1.0 sections 3.14 and
* 4.4 for a description of the Current Track Object.
*
* Requires Object Transfer Service.
*
* @param player Media player instance pointer.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_media_proxy_ctrl_get_parent_group_id(esp_ble_audio_media_player_t *player);
/**
* @brief Read Current Group Object ID.
*
* Get an ID (48 bit) that can be used to retrieve the Current
* Track Object from an Object Transfer Service
*
* See the Media Control Service spec v1.0 sections 3.14 and
* 4.4 for a description of the Current Group Object.
*
* Requires Object Transfer Service.
*
* @param player Media player instance pointer.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_media_proxy_ctrl_get_current_group_id(esp_ble_audio_media_player_t *player);
/**
* @brief Set Current Group Object ID.
*
* Change the player's current group to the group given by the
* ID, and the current track to the first track in that group.
*
* Requires Object Transfer Service.
*
* @param player Media player instance pointer.
* @param id The ID of a group object.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_media_proxy_ctrl_set_current_group_id(esp_ble_audio_media_player_t *player,
uint64_t id);
/**
* @brief Read Playing Order.
*
* @param player Media player instance pointer.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_media_proxy_ctrl_get_playing_order(esp_ble_audio_media_player_t *player);
/**
* @brief Set Playing Order.
*
* Set the media player's playing order.
*
* @param player Media player instance pointer.
* @param order The playing order to set.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_media_proxy_ctrl_set_playing_order(esp_ble_audio_media_player_t *player,
uint8_t order);
/**
* @brief Read Playing Orders Supported.
*
* Read a bitmap containing the media player's supported playing orders.
*
* @param player Media player instance pointer.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_media_proxy_ctrl_get_playing_orders_supported(esp_ble_audio_media_player_t *player);
/**
* @brief Read Media State.
*
* Read the media player's state.
*
* @param player Media player instance pointer.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_media_proxy_ctrl_get_media_state(esp_ble_audio_media_player_t *player);
/**
* @brief Send Command.
*
* Send a command to the media player.
* Commands may cause the media player to change its state.
* May result in two callbacks - one for the actual sending of the command
* to the player, one for the result of the command from the player.
*
* @param player Media player instance pointer.
* @param command The command to send.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_media_proxy_ctrl_send_command(esp_ble_audio_media_player_t *player,
const esp_ble_audio_mpl_cmd_t *command);
/**
* @brief Read Commands Supported.
*
* Read a bitmap containing the media player's supported command opcodes.
*
* @param player Media player instance pointer.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_media_proxy_ctrl_get_commands_supported(esp_ble_audio_media_player_t *player);
/**
* @brief Set Search.
*
* Write a search to the media player.
* If the search is successful, the search results will be available as
* a group object in the Object Transfer Service (OTS).
*
* May result in up to three callbacks:
* - one for the actual sending of the search to the player;
* - one for the result code for the search from the player;
* - if the search is successful, one for the search results object ID
* in the OTs.
*
* Requires Object Transfer Service.
*
* @param player Media player instance pointer.
* @param search The search to write.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_media_proxy_ctrl_send_search(esp_ble_audio_media_player_t *player,
const esp_ble_audio_mpl_search_t *search);
/**
* @brief Read Search Results Object ID.
*
* Get an ID (48 bit) that can be used to retrieve the Search
* Results Object from an Object Transfer Service.
*
* The search results object is a group object.
* The search results object only exists if a successful
* search operation has been done.
*
* Requires Object Transfer Service.
*
* @param player Media player instance pointer.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_media_proxy_ctrl_get_search_results_id(esp_ble_audio_media_player_t *player);
/**
* @brief Read Content Control ID.
*
* The content control ID identifies a content control service
* on a device, and links it to the corresponding audio stream.
*
* @param player Media player instance pointer.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_media_proxy_ctrl_get_content_ctrl_id(esp_ble_audio_media_player_t *player);
/**
* @brief Register a player with the media proxy.
*
* Register a player with the media proxy module, for use by media
* controllers.
*
* The media proxy may call any non-NULL function pointers in the
* supplied media_proxy_pl_calls structure.
*
* @param pl_calls Function pointers to the media player's calls.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_media_proxy_pl_register(esp_ble_audio_media_proxy_pl_calls_t *pl_calls);
/**
* @brief Initialize player.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_media_proxy_pl_init(void);
/**
* @brief Get the pointer of the Object Transfer Service used by the Media Control Service.
*
* @return Pointer to an OTS instance if found else NULL.
*/
struct bt_ots *esp_ble_audio_mcs_get_ots(void);
#ifdef __cplusplus
}
#endif
#endif /* ESP_BLE_AUDIO_MEDIA_PROXY_API_H_ */
@@ -0,0 +1,184 @@
/*
* SPDX-FileCopyrightText: 2020-2024 Nordic Semiconductor ASA
* SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ESP_BLE_AUDIO_MICP_API_H_
#define ESP_BLE_AUDIO_MICP_API_H_
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include "sdkconfig.h"
#include "esp_err.h"
#include <zephyr/bluetooth/audio/micp.h>
#include "common/init.h"
#include "common/host.h"
#ifdef __cplusplus
extern "C" {
#endif
/*!< The microphone state is unmuted */
#define ESP_BLE_AUDIO_MICP_MUTE_UNMUTED BT_MICP_MUTE_UNMUTED
/*!< The microphone state is muted */
#define ESP_BLE_AUDIO_MICP_MUTE_MUTED BT_MICP_MUTE_MUTED
/*!< The microphone state is disabled and cannot be muted or unmuted */
#define ESP_BLE_AUDIO_MICP_MUTE_DISABLED BT_MICP_MUTE_DISABLED
/** Microphone Controller instance */
typedef struct bt_micp_mic_ctlr esp_ble_audio_micp_mic_ctlr_t;
/** Struct to hold the Microphone Controller callbacks */
typedef struct bt_micp_mic_ctlr_cb esp_ble_audio_micp_mic_ctlr_cb_t;
/** Struct to hold the Microphone Device callbacks */
typedef struct bt_micp_mic_dev_cb esp_ble_audio_micp_mic_dev_cb_t;
/** Register parameters structure for Microphone Control Service */
typedef struct bt_micp_mic_dev_register_param esp_ble_audio_micp_mic_dev_register_param_t;
/** Microphone Control Profile included services */
typedef struct bt_micp_included esp_ble_audio_micp_included_t;
/**
* @brief Initialize the Microphone Control Profile Microphone Device.
*
* This will enable the Microphone Control Service instance and make it
* discoverable by Microphone Controllers.
*
* @param param Pointer to an initialization structure.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_micp_mic_dev_register(esp_ble_audio_micp_mic_dev_register_param_t *param);
/**
* @brief Get Microphone Device included services.
*
* Returns a pointer to a struct that contains information about the
* Microphone Device included Audio Input Control Service instances.
*
* @param included Pointer to store the result in.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_micp_mic_dev_included_get(esp_ble_audio_micp_included_t *included);
/**
* @brief Unmute the Microphone Device.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_micp_mic_dev_unmute(void);
/**
* @brief Mute the Microphone Device.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_micp_mic_dev_mute(void);
/**
* @brief Disable the mute functionality on the Microphone Device.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_micp_mic_dev_mute_disable(void);
/**
* @brief Read the mute state on the Microphone Device.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_micp_mic_dev_mute_get(void);
/**
* @brief Get Microphone Control Profile included services.
*
* Returns a pointer to a struct that contains information about the
* Microphone Control Profile included services instances, such as
* pointers to the Audio Input Control Service instances.
*
* @param mic_ctlr Microphone Controller instance pointer.
* @param included Pointer to store the result in.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_micp_mic_ctlr_included_get(esp_ble_audio_micp_mic_ctlr_t *mic_ctlr,
esp_ble_audio_micp_included_t *included);
/**
* @brief Get the Microphone controller from a connection pointer.
*
* Only Microphone controllers that have been initiated can be retrieved.
*
* @param conn_handle Connection handle.
*
* @return Pointer to a Microphone controller instance or NULL if not found.
*/
esp_ble_audio_micp_mic_ctlr_t *esp_ble_audio_micp_mic_ctlr_get_by_conn(uint16_t conn_handle);
/**
* @brief Discover Microphone Control Service.
*
* This will start a GATT discovery and setup handles and subscriptions.
* This shall be called once before any other actions can be executed
* for the peer device.
*
* @param conn_handle Connection handle.
* @param mic_ctlr Valid remote instance object on success.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_micp_mic_ctlr_discover(uint16_t conn_handle,
esp_ble_audio_micp_mic_ctlr_t **mic_ctlr);
/**
* @brief Unmute a remote Microphone Device.
*
* @param mic_ctlr Microphone Controller instance pointer.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_micp_mic_ctlr_unmute(esp_ble_audio_micp_mic_ctlr_t *mic_ctlr);
/**
* @brief Mute a remote Microphone Device.
*
* @param mic_ctlr Microphone Controller instance pointer.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_micp_mic_ctlr_mute(esp_ble_audio_micp_mic_ctlr_t *mic_ctlr);
/**
* @brief Read the mute state of a remote Microphone Device.
*
* @param mic_ctlr Microphone Controller instance pointer.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_micp_mic_ctlr_mute_get(esp_ble_audio_micp_mic_ctlr_t *mic_ctlr);
/**
* @brief Registers the callbacks used by Microphone Controller.
*
* This can only be done as the client.
*
* @param cb The callback structure.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_micp_mic_ctlr_cb_register(esp_ble_audio_micp_mic_ctlr_cb_t *cb);
#ifdef __cplusplus
}
#endif
#endif /* ESP_BLE_AUDIO_MICP_API_H_ */
@@ -0,0 +1,153 @@
/*
* SPDX-FileCopyrightText: 2021 Intel Corporation
* SPDX-FileCopyrightText: 2021-2024 Nordic Semiconductor ASA
* SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ESP_BLE_AUDIO_PACS_API_H_
#define ESP_BLE_AUDIO_PACS_API_H_
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include "sdkconfig.h"
#include "esp_err.h"
#include <zephyr/bluetooth/audio/pacs.h>
#include "common/init.h"
#include "common/host.h"
#include "esp_ble_audio_defs.h"
#ifdef __cplusplus
extern "C" {
#endif
/** Structure for registering PACS */
typedef struct bt_pacs_register_param esp_ble_audio_pacs_register_param_t;
/** Published Audio Capability structure. */
typedef struct bt_pacs_cap esp_ble_audio_pacs_cap_t;
/**
* @brief Register the Published Audio Capability Service instance.
*
* @param param PACS register parameters.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_pacs_register(const esp_ble_audio_pacs_register_param_t *param);
/**
* @brief Unregister the Published Audio Capability Service instance.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_pacs_unregister(void);
/**
* @brief Register Published Audio Capability.
*
* Register Audio Local Capability.
*
* @param dir Direction of the endpoint to register capability for.
* @param cap Capability structure.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_pacs_cap_register(esp_ble_audio_dir_t dir,
esp_ble_audio_pacs_cap_t *cap);
/**
* @brief Unregister Published Audio Capability.
*
* Unregister Audio Local Capability.
*
* @param dir Direction of the endpoint to unregister capability for.
* @param cap Capability structure.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_pacs_cap_unregister(esp_ble_audio_dir_t dir,
esp_ble_audio_pacs_cap_t *cap);
/**
* @brief Set the location for an endpoint type.
*
* @param dir Direction of the endpoints to change location for.
* @param location The location to be set.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_pacs_set_location(esp_ble_audio_dir_t dir,
esp_ble_audio_location_t location);
/**
* @brief Set the available contexts for an endpoint type.
*
* @param dir Direction of the endpoints to change available contexts for.
* @param contexts The contexts to be set.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_pacs_set_available_contexts(esp_ble_audio_dir_t dir,
esp_ble_audio_context_t contexts);
/**
* @brief Get the available contexts for an endpoint type.
*
* @param dir Direction of the endpoints to get contexts for.
*
* @return Bitmask of available contexts.
*/
esp_ble_audio_context_t esp_ble_audio_pacs_get_available_contexts(esp_ble_audio_dir_t dir);
/**
* @brief Set the available contexts for a given connection.
*
* This function sets the available contexts value for a given connection.
* The Available Context Value is reset to default on ACL disconnection.
*
* @param conn_handle Connection handle.
* @param dir Direction of the endpoints to change available contexts for.
* @param contexts The contexts to be set or NULL to reset to default.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_pacs_conn_set_available_contexts_for_conn(uint16_t conn_handle,
esp_ble_audio_dir_t dir,
esp_ble_audio_context_t *contexts);
/**
* @brief Get the available contexts for a given connection.
*
* This server function returns the available contexts value for a given connection.
*
* @param conn_handle Connection handle.
* @param dir Direction of the endpoints to get contexts for.
*
* @return Bitmask of available contexts.
*/
esp_ble_audio_context_t esp_ble_audio_pacs_get_available_contexts_for_conn(uint16_t conn_handle,
esp_ble_audio_dir_t dir);
/**
* @brief Set the supported contexts for an endpoint type.
*
* @param dir Direction of the endpoints to change available contexts for.
* @param contexts The contexts to be set.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_pacs_set_supported_contexts(esp_ble_audio_dir_t dir,
esp_ble_audio_context_t contexts);
#ifdef __cplusplus
}
#endif
#endif /* ESP_BLE_AUDIO_PACS_API_H_ */
@@ -0,0 +1,78 @@
/*
* SPDX-FileCopyrightText: 2023 NXP
* SPDX-FileCopyrightText: 2024 Nordic Semiconductor ASA
* SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ESP_BLE_AUDIO_PBP_API_H_
#define ESP_BLE_AUDIO_PBP_API_H_
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include "sdkconfig.h"
#include "esp_err.h"
#include <zephyr/bluetooth/audio/pbp.h>
#include "common/init.h"
#include "common/host.h"
#ifdef __cplusplus
extern "C" {
#endif
/** Minimum size of the Public Broadcast Announcement */
#define ESP_BLE_AUDIO_PBP_MIN_PBA_SIZE BT_PBP_MIN_PBA_SIZE
/*!< Broadcast Streams encryption status */
#define ESP_BLE_AUDIO_PBP_ANNOUNCEMENT_FEATURE_ENCRYPTION BT_PBP_ANNOUNCEMENT_FEATURE_ENCRYPTION
/*!< Standard Quality Public Broadcast Audio configuration */
#define ESP_BLE_AUDIO_PBP_ANNOUNCEMENT_FEATURE_STANDARD_QUALITY BT_PBP_ANNOUNCEMENT_FEATURE_STANDARD_QUALITY
/*!< High Quality Public Broadcast Audio configuration */
#define ESP_BLE_AUDIO_PBP_ANNOUNCEMENT_FEATURE_HIGH_QUALITY BT_PBP_ANNOUNCEMENT_FEATURE_HIGH_QUALITY
/** Public Broadcast Announcement features */
typedef enum bt_pbp_announcement_feature esp_ble_audio_pbp_announcement_feature_t;
/**
* @brief Creates a Public Broadcast Announcement based on the information received
* in the features parameter.
*
* @param meta Metadata to be included in the advertising data.
* @param meta_len Size of the metadata fields to be included in the advertising data.
* @param features Public Broadcast Announcement features.
* @param pba_data_buf Pointer to store the PBA advertising data. Buffer size needs to be
* meta_len + ESP_BLE_AUDIO_PBP_MIN_PBA_SIZE.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_pbp_get_announcement(const uint8_t meta[], size_t meta_len,
esp_ble_audio_pbp_announcement_feature_t features,
struct net_buf_simple *pba_data_buf);
/**
* @brief Parses the received advertising data corresponding to a Public Broadcast
* Announcement.
* Returns the advertised Public Broadcast Announcement features and metadata.
*
* @param data_type Type of advertising data to be checked.
* @param data Pointer of advertising data to be checked.
* @param data_len Length of advertising data to be checked.
* @param features Pointer to public broadcast source features to store the parsed features in.
* @param meta Pointer to the metadata present in the advertising data.
* @param meta_len Size of the metadata fields to be included in the advertising data.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_pbp_parse_announcement(uint8_t data_type, const uint8_t *data, uint8_t data_len,
esp_ble_audio_pbp_announcement_feature_t *features,
uint8_t **meta, uint8_t *meta_len);
#ifdef __cplusplus
}
#endif
#endif /* ESP_BLE_AUDIO_PBP_API_H_ */
@@ -0,0 +1,635 @@
/*
* SPDX-FileCopyrightText: 2020 Bose Corporation
* SPDX-FileCopyrightText: 2021 Nordic Semiconductor ASA
* SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ESP_BLE_AUDIO_TBS_API_H_
#define ESP_BLE_AUDIO_TBS_API_H_
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include "sdkconfig.h"
#include "esp_err.h"
#include <zephyr/bluetooth/audio/tbs.h>
#include "common/init.h"
#include "common/host.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* The GTBS index denotes whenever a callback is from a Generic Telephone
* Bearer Service (GTBS) instance, or whenever the client should perform
* on action on the GTBS instance of the server, rather than any of the
* specific Telephone Bearer Service instances.
*/
#define ESP_BLE_AUDIO_TBS_GTBS_INDEX BT_TBS_GTBS_INDEX
/*!< A remote party is calling (incoming call). */
#define ESP_BLE_AUDIO_TBS_CALL_STATE_INCOMING BT_TBS_CALL_STATE_INCOMING
/**
* The process to call the remote party has started on the server, but the
* remote party is not being alerted (outgoing call).
*/
#define ESP_BLE_AUDIO_TBS_CALL_STATE_DIALING BT_TBS_CALL_STATE_DIALING
/*!< A remote party is being alerted (outgoing call). */
#define ESP_BLE_AUDIO_TBS_CALL_STATE_ALERTING BT_TBS_CALL_STATE_ALERTING
/*!< The call is in an active conversation. */
#define ESP_BLE_AUDIO_TBS_CALL_STATE_ACTIVE BT_TBS_CALL_STATE_ACTIVE
/**
* The call is connected but held locally. Locally Held implies that either
* the server or the client can affect the state.
*/
#define ESP_BLE_AUDIO_TBS_CALL_STATE_LOCALLY_HELD BT_TBS_CALL_STATE_LOCALLY_HELD
/**
* The call is connected but held remotely. Remotely Held means that the state
* is controlled by the remote party of a call.
*/
#define ESP_BLE_AUDIO_TBS_CALL_STATE_REMOTELY_HELD BT_TBS_CALL_STATE_REMOTELY_HELD
/*!< The call is connected but held both locally and remotely. */
#define ESP_BLE_AUDIO_TBS_CALL_STATE_LOCALLY_AND_REMOTELY_HELD BT_TBS_CALL_STATE_LOCALLY_AND_REMOTELY_HELD
/*!< The URI value used to originate a call was formed improperly. */
#define ESP_BLE_AUDIO_TBS_REASON_BAD_REMOTE_URI BT_TBS_REASON_BAD_REMOTE_URI
/*!< The call failed. */
#define ESP_BLE_AUDIO_TBS_REASON_CALL_FAILED BT_TBS_REASON_CALL_FAILED
/*!< The remote party ended the call. */
#define ESP_BLE_AUDIO_TBS_REASON_REMOTE_ENDED_CALL BT_TBS_REASON_REMOTE_ENDED_CALL
/*!< The call ended from the server. */
#define ESP_BLE_AUDIO_TBS_REASON_SERVER_ENDED_CALL BT_TBS_REASON_SERVER_ENDED_CALL
/*!< The line was busy. */
#define ESP_BLE_AUDIO_TBS_REASON_LINE_BUSY BT_TBS_REASON_LINE_BUSY
/*!< Network congestion. */
#define ESP_BLE_AUDIO_TBS_REASON_NETWORK_CONGESTED BT_TBS_REASON_NETWORK_CONGESTED
/*!< The client terminated the call. */
#define ESP_BLE_AUDIO_TBS_REASON_CLIENT_TERMINATED BT_TBS_REASON_CLIENT_TERMINATED
/*!< No service. */
#define ESP_BLE_AUDIO_TBS_REASON_NO_SERVICE BT_TBS_REASON_NO_SERVICE
/*!< No answer. */
#define ESP_BLE_AUDIO_TBS_REASON_NO_ANSWER BT_TBS_REASON_NO_ANSWER
/*!< Unspecified. */
#define ESP_BLE_AUDIO_TBS_REASON_UNSPECIFIED BT_TBS_REASON_UNSPECIFIED
/*!< The opcode write was successful. */
#define ESP_BLE_AUDIO_TBS_RESULT_CODE_SUCCESS BT_TBS_RESULT_CODE_SUCCESS
/*!< An invalid opcode was used for the Call Control Point write. */
#define ESP_BLE_AUDIO_TBS_RESULT_CODE_OPCODE_NOT_SUPPORTED BT_TBS_RESULT_CODE_OPCODE_NOT_SUPPORTED
/*!< The requested operation cannot be completed. */
#define ESP_BLE_AUDIO_TBS_RESULT_CODE_OPERATION_NOT_POSSIBLE BT_TBS_RESULT_CODE_OPERATION_NOT_POSSIBLE
/*!< The Call Index used for the Call Control Point write is invalid. */
#define ESP_BLE_AUDIO_TBS_RESULT_CODE_INVALID_CALL_INDEX BT_TBS_RESULT_CODE_INVALID_CALL_INDEX
/**
* The opcode written to the Call Control Point was received when the current
* Call State for the Call Index was not in the expected state.
*/
#define ESP_BLE_AUDIO_TBS_RESULT_CODE_STATE_MISMATCH BT_TBS_RESULT_CODE_STATE_MISMATCH
/*!< Lack of internal resources to complete the requested action. */
#define ESP_BLE_AUDIO_TBS_RESULT_CODE_OUT_OF_RESOURCES BT_TBS_RESULT_CODE_OUT_OF_RESOURCES
/*!< The Outgoing URI is incorrect or invalid when an Originate opcode is sent. */
#define ESP_BLE_AUDIO_TBS_RESULT_CODE_INVALID_URI BT_TBS_RESULT_CODE_INVALID_URI
/*!< Local Hold and Local Retrieve Call Control Point Opcodes supported */
#define ESP_BLE_AUDIO_TBS_FEATURE_HOLD BT_TBS_FEATURE_HOLD
/*!< Join Call Control Point Opcode supported */
#define ESP_BLE_AUDIO_TBS_FEATURE_JOIN BT_TBS_FEATURE_JOIN
/*!< All Control Point Opcodes supported */
#define ESP_BLE_AUDIO_TBS_FEATURE_ALL BT_TBS_FEATURE_ALL
/*!< No service */
#define ESP_BLE_AUDIO_TBS_SIGNAL_STRENGTH_NO_SERVICE BT_TBS_SIGNAL_STRENGTH_NO_SERVICE
/*!< Maximum signal strength */
#define ESP_BLE_AUDIO_TBS_SIGNAL_STRENGTH_MAX BT_TBS_SIGNAL_STRENGTH_MAX
/*!< Signal strength is unknown */
#define ESP_BLE_AUDIO_TBS_SIGNAL_STRENGTH_UNKNOWN BT_TBS_SIGNAL_STRENGTH_UNKNOWN
/*!< 3G */
#define ESP_BLE_AUDIO_TBS_TECHNOLOGY_3G BT_TBS_TECHNOLOGY_3G
/*!< 4G */
#define ESP_BLE_AUDIO_TBS_TECHNOLOGY_4G BT_TBS_TECHNOLOGY_4G
/*!< Long-term evolution (LTE) */
#define ESP_BLE_AUDIO_TBS_TECHNOLOGY_LTE BT_TBS_TECHNOLOGY_LTE
/*!< Wifi */
#define ESP_BLE_AUDIO_TBS_TECHNOLOGY_WIFI BT_TBS_TECHNOLOGY_WIFI
/*!< 5G */
#define ESP_BLE_AUDIO_TBS_TECHNOLOGY_5G BT_TBS_TECHNOLOGY_5G
/*!< Global System for Mobile Communications (GSM) */
#define ESP_BLE_AUDIO_TBS_TECHNOLOGY_GSM BT_TBS_TECHNOLOGY_GSM
/*!< Code-Division Multiple Access (CDMA) */
#define ESP_BLE_AUDIO_TBS_TECHNOLOGY_CDMA BT_TBS_TECHNOLOGY_CDMA
/*!< 2G */
#define ESP_BLE_AUDIO_TBS_TECHNOLOGY_2G BT_TBS_TECHNOLOGY_2G
/*!< Wideband Code-Division Multiple Access (WCDMA) */
#define ESP_BLE_AUDIO_TBS_TECHNOLOGY_WCDMA BT_TBS_TECHNOLOGY_WCDMA
/*!< Inband ringtone enabled */
#define ESP_BLE_AUDIO_TBS_STATUS_FLAG_INBAND_RINGTONE BT_TBS_STATUS_FLAG_INBAND_RINGTONE
/*!< Server is in silent mod */
#define ESP_BLE_AUDIO_TBS_STATUS_FLAG_SILENT_MOD BT_TBS_STATUS_FLAG_SILENT_MOD
/*!< If set, call is outgoing else incoming */
#define ESP_BLE_AUDIO_TBS_CALL_FLAG_OUTGOING BT_TBS_CALL_FLAG_OUTGOING
/*!< If set call is withheld, else not withheld */
#define ESP_BLE_AUDIO_TBS_CALL_FLAG_WITHHELD BT_TBS_CALL_FLAG_WITHHELD
/*!< If set call is withheld by network, else provided by network */
#define ESP_BLE_AUDIO_TBS_CALL_FLAG_WITHHELD_BY_NETWORK BT_TBS_CALL_FLAG_WITHHELD_BY_NETWORK
/** Struct to hold the Telephone Bearer Service callbacks */
typedef struct bt_tbs_cb esp_ble_audio_tbs_cb_t;
/** Telephone Bearer Service instance */
typedef struct bt_tbs_instance esp_ble_audio_tbs_instance_t;
/** Struct to hold the parameters to initialize the bearer */
typedef struct bt_tbs_register_param esp_ble_audio_tbs_register_param_t;
/** Struct to hold the Telephone Bearer Service client callbacks */
typedef struct bt_tbs_client_cb esp_ble_audio_tbs_client_cb_t;
/** Struct to hold a call as the Telephone Bearer Service client */
typedef struct bt_tbs_client_call esp_ble_audio_tbs_client_call_t;
/** Struct to hold a call state */
typedef struct bt_tbs_client_call_state esp_ble_audio_tbs_client_call_state_t;
/**
* @brief Accept an alerting call.
*
* @param call_index The index of the call that will be accepted.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_tbs_accept(uint8_t call_index);
/**
* @brief Hold a call.
*
* @param call_index The index of the call that will be held.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_tbs_hold(uint8_t call_index);
/**
* @brief Retrieve a call.
*
* @param call_index The index of the call that will be retrieved.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_tbs_retrieve(uint8_t call_index);
/**
* @brief Terminate a call.
*
* @param call_index The index of the call that will be terminated.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_tbs_terminate(uint8_t call_index);
/**
* @brief Originate a call.
*
* @param bearer_index The index of the Telephone Bearer.
* @param uri The remote URI.
* @param call_index Pointer to a value where the new call_index will be stored.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_tbs_originate(uint8_t bearer_index,
char *uri,
uint8_t *call_index);
/**
* @brief Join calls.
*
* @param call_index_cnt The number of call indexes to join.
* @param call_indexes Array of call indexes to join.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_tbs_join(uint8_t call_index_cnt, uint8_t *call_indexes);
/**
* @brief Notify the server that the remote party answered the call.
*
* @param call_index The index of the call that was answered.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_tbs_remote_answer(uint8_t call_index);
/**
* @brief Notify the server that the remote party held the call.
*
* @param call_index The index of the call that was held.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_tbs_remote_hold(uint8_t call_index);
/**
* @brief Notify the server that the remote party retrieved the call.
*
* @param call_index The index of the call that was retrieved.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_tbs_remote_retrieve(uint8_t call_index);
/**
* @brief Notify the server that the remote party terminated the call.
*
* @param call_index The index of the call that was terminated.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_tbs_remote_terminate(uint8_t call_index);
/**
* @brief Notify the server of an incoming call.
*
* @param bearer_index The index of the Telephone Bearer.
* @param to The URI that is receiving the call.
* @param from The URI of the remote caller.
* @param friendly_name The friendly name of the remote caller.
* @param call_index The call index on success.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_tbs_remote_incoming(uint8_t bearer_index,
const char *to,
const char *from,
const char *friendly_name,
uint8_t *call_index);
/**
* @brief Set a new bearer provider.
*
* @param bearer_index The index of the Telephone Bearer or
* ESP_BLE_AUDIO_TBS_GTBS_INDEX for GTBS.
* @param name The new bearer provider name.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_tbs_set_bearer_provider_name(uint8_t bearer_index, const char *name);
/**
* @brief Set a new bearer technology.
*
* @param bearer_index The index of the Telephone Bearer or
* ESP_BLE_AUDIO_TBS_GTBS_INDEX for GTBS.
* @param new_technology The new bearer technology.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_tbs_set_bearer_technology(uint8_t bearer_index, uint8_t new_technology);
/**
* @brief Update the signal strength reported by the server.
*
* @param bearer_index The index of the Telephone Bearer or
* ESP_BLE_AUDIO_TBS_GTBS_INDEX for GTBS.
* @param new_signal_strength The new signal strength.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_tbs_set_signal_strength(uint8_t bearer_index, uint8_t new_signal_strength);
/**
* @brief Sets the feature and status value.
*
* @param bearer_index The index of the Telephone Bearer or
* ESP_BLE_AUDIO_TBS_GTBS_INDEX for GTBS.
* @param status_flags The new feature and status value.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_tbs_set_status_flags(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.
*
* @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);
/**
* @brief Register the callbacks for TBS.
*
* @param cbs Pointer to the callback structure.
*/
void esp_ble_audio_tbs_register_cb(esp_ble_audio_tbs_cb_t *cbs);
/**
* @brief Register a Telephone Bearer.
*
* This will register a Telephone Bearer Service (TBS) (or a Generic Telephone
* Bearer service (GTBS)) with the provided parameters.
*
* As per the TBS specification, the GTBS shall be instantiated for the feature,
* and as such a GTBS shall always be registered before any TBS can be registered.
*
* @param param The parameters to initialize the bearer.
* @param bearer_index The registered bearer index on success.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_tbs_register_bearer(const esp_ble_audio_tbs_register_param_t *param,
uint8_t *bearer_index);
/**
* @brief Unregister a Telephone Bearer.
*
* This will unregister a Telephone Bearer Service (TBS) (or a Generic Telephone
* Bearer service (GTBS)) with the provided parameters.
*
* Similarly, all TBS shall be unregistered before the GTBS can be unregistered with.
*
* @param bearer_index The index of the bearer to unregister.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_tbs_unregister_bearer(uint8_t bearer_index);
/**
* @brief Discover TBS for a connection. This will start a GATT
* discover and setup handles and subscriptions.
*
* @param conn_handle Connection handle.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_tbs_client_discover(uint16_t conn_handle);
/**
* @brief Set the signal strength reporting interval for a TBS instance.
*
* @param conn_handle Connection handle.
* @param inst_index The index of the TBS instance.
* @param interval The interval to write (0-255 seconds).
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_tbs_client_set_signal_strength_interval(uint16_t conn_handle,
uint8_t inst_index,
uint8_t interval);
/**
* @brief Request to originate a call.
*
* @param conn_handle Connection handle.
* @param inst_index The index of the TBS instance.
* @param uri The URI of the callee.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_tbs_client_originate_call(uint16_t conn_handle,
uint8_t inst_index,
const char *uri);
/**
* @brief Request to terminate a call.
*
* @param conn_handle Connection handle.
* @param inst_index The index of the TBS instance.
* @param call_index The call index to terminate.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_tbs_client_terminate_call(uint16_t conn_handle,
uint8_t inst_index,
uint8_t call_index);
/**
* @brief Request to hold a call.
*
* @param conn_handle Connection handle.
* @param inst_index The index of the TBS instance.
* @param call_index The call index to place on hold.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_tbs_client_hold_call(uint16_t conn_handle,
uint8_t inst_index,
uint8_t call_index);
/**
* @brief Accept an incoming call.
*
* @param conn_handle Connection handle.
* @param inst_index The index of the TBS instance.
* @param call_index The call index to accept.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_tbs_client_accept_call(uint16_t conn_handle,
uint8_t inst_index,
uint8_t call_index);
/**
* @brief Retrieve call from (local) hold.
*
* @param conn_handle Connection handle.
* @param inst_index The index of the TBS instance.
* @param call_index The call index to retrieve.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_tbs_client_retrieve_call(uint16_t conn_handle,
uint8_t inst_index,
uint8_t call_index);
/**
* @brief Join multiple calls.
*
* @param conn_handle Connection handle.
* @param inst_index The index of the TBS instance.
* @param call_indexes Array of call indexes.
* @param count Number of call indexes in the call_indexes array.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_tbs_client_join_calls(uint16_t conn_handle,
uint8_t inst_index,
const uint8_t *call_indexes,
uint8_t count);
/**
* @brief Read the bearer provider name of a TBS instance.
*
* @param conn_handle Connection handle.
* @param inst_index The index of the TBS instance.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_tbs_client_read_bearer_provider_name(uint16_t conn_handle, uint8_t inst_index);
/**
* @brief Read the UCI of a TBS instance.
*
* @param conn_handle Connection handle.
* @param inst_index The index of the TBS instance.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_tbs_client_read_bearer_uci(uint16_t conn_handle, uint8_t inst_index);
/**
* @brief Read the technology of a TBS instance.
*
* @param conn_handle Connection handle.
* @param inst_index The index of the TBS instance.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_tbs_client_read_technology(uint16_t conn_handle, uint8_t inst_index);
/**
* @brief Read the URI schemes list of a TBS instance.
*
* @param conn_handle Connection handle.
* @param inst_index The index of the TBS instance.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_tbs_client_read_uri_list(uint16_t conn_handle, uint8_t inst_index);
/**
* @brief Read the current signal strength of a TBS instance.
*
* @param conn_handle Connection handle.
* @param inst_index The index of the TBS instance.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_tbs_client_read_signal_strength(uint16_t conn_handle, uint8_t inst_index);
/**
* @brief Read the signal strength reporting interval of a TBS instance.
*
* @param conn_handle Connection handle.
* @param inst_index The index of the TBS instance.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_tbs_client_read_signal_interval(uint16_t conn_handle, uint8_t inst_index);
/**
* @brief Read the list of current calls of a TBS instance.
*
* @param conn_handle Connection handle.
* @param inst_index The index of the TBS instance.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_tbs_client_read_current_calls(uint16_t conn_handle, uint8_t inst_index);
/**
* @brief Read the content ID of a TBS instance.
*
* @param conn_handle Connection handle.
* @param inst_index The index of the TBS instance.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_tbs_client_read_ccid(uint16_t conn_handle, uint8_t inst_index);
/**
* @brief Read the call target URI of a TBS instance.
*
* @param conn_handle Connection handle.
* @param inst_index The index of the TBS instance.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_tbs_client_read_call_uri(uint16_t conn_handle, uint8_t inst_index);
/**
* @brief Read the feature and status value of a TBS instance.
*
* @param conn_handle Connection handle.
* @param inst_index The index of the TBS instance.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_tbs_client_read_status_flags(uint16_t conn_handle, uint8_t inst_index);
/**
* @brief Read the states of the current calls of a TBS instance.
*
* @param conn_handle Connection handle.
* @param inst_index The index of the TBS instance.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_tbs_client_read_call_state(uint16_t conn_handle, uint8_t inst_index);
/**
* @brief Read the remote URI of a TBS instance.
*
* @param conn_handle Connection handle.
* @param inst_index The index of the TBS instance.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_tbs_client_read_remote_uri(uint16_t conn_handle, uint8_t inst_index);
/**
* @brief Read the friendly name of a call for a TBS instance.
*
* @param conn_handle Connection handle.
* @param inst_index The index of the TBS instance.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_tbs_client_read_friendly_name(uint16_t conn_handle, uint8_t inst_index);
/**
* @brief Read the supported opcode of a TBS instance.
*
* @param conn_handle Connection handle.
* @param inst_index The index of the TBS instance.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_tbs_client_read_optional_opcodes(uint16_t conn_handle, uint8_t inst_index);
/**
* @brief Register the callbacks for CCP.
*
* @param cbs Pointer to the callback structure.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_tbs_client_register_cb(esp_ble_audio_tbs_client_cb_t *cbs);
/**
* @brief Look up Telephone Bearer Service instance by CCID.
*
* @param conn_handle Connection handle.
* @param ccid The CCID 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_ccid(uint16_t conn_handle, uint8_t ccid);
#ifdef __cplusplus
}
#endif
#endif /* ESP_BLE_AUDIO_TBS_API_H_ */
@@ -0,0 +1,79 @@
/*
* SPDX-FileCopyrightText: 2023 NXP
* SPDX-FileCopyrightText: 2024 Nordic Semiconductor ASA
* SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ESP_BLE_AUDIO_TMAP_API_H_
#define ESP_BLE_AUDIO_TMAP_API_H_
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include "sdkconfig.h"
#include "esp_err.h"
#include <zephyr/bluetooth/audio/tmap.h>
#include "common/init.h"
#include "common/host.h"
#ifdef __cplusplus
extern "C" {
#endif
/*!< TMAP Call Gateway role */
#define ESP_BLE_AUDIO_TMAP_ROLE_CG BT_TMAP_ROLE_CG
/*!< TMAP Call Terminal role */
#define ESP_BLE_AUDIO_TMAP_ROLE_CT BT_TMAP_ROLE_CT
/*!< TMAP Unicast Media Sender role */
#define ESP_BLE_AUDIO_TMAP_ROLE_UMS BT_TMAP_ROLE_UMS
/*!< TMAP Unicast Media Receiver role */
#define ESP_BLE_AUDIO_TMAP_ROLE_UMR BT_TMAP_ROLE_UMR
/*!< TMAP Broadcast Media Sender role */
#define ESP_BLE_AUDIO_TMAP_ROLE_BMS BT_TMAP_ROLE_BMS
/*!< TMAP Broadcast Media Receiver role */
#define ESP_BLE_AUDIO_TMAP_ROLE_BMR BT_TMAP_ROLE_BMR
/** TMAP Role characteristic */
typedef enum bt_tmap_role esp_ble_audio_tmap_role_t;
/** TMAP callback structure */
typedef struct bt_tmap_cb esp_ble_audio_tmap_cb_t;
/**
* @brief Adds TMAS instance to database and sets the received TMAP role(s).
*
* @param role TMAP role(s) of the device (one or multiple).
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_tmap_register(esp_ble_audio_tmap_role_t role);
/**
* @brief Perform service discovery as TMAP Client.
*
* @param conn_handle Connection handle.
* @param tmap_cb Pointer to struct of TMAP callbacks.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_tmap_discover(uint16_t conn_handle,
const esp_ble_audio_tmap_cb_t *tmap_cb);
/**
* @brief Set one or multiple TMAP roles dynamically.
* Previously registered value will be overwritten.
*
* @param role TMAP role(s).
*/
void esp_ble_audio_tmap_set_role(esp_ble_audio_tmap_role_t role);
#ifdef __cplusplus
}
#endif
#endif /* ESP_BLE_AUDIO_TMAP_API_H_ */
@@ -0,0 +1,299 @@
/*
* SPDX-FileCopyrightText: 2020-2024 Nordic Semiconductor ASA
* SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ESP_BLE_AUDIO_VCP_API_H_
#define ESP_BLE_AUDIO_VCP_API_H_
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include "sdkconfig.h"
#include "esp_err.h"
#include <zephyr/bluetooth/audio/vcp.h>
#include "common/init.h"
#include "common/host.h"
#ifdef __cplusplus
extern "C" {
#endif
/*!< The volume state is unmuted */
#define ESP_BLE_AUDIO_VCP_STATE_UNMUTED BT_VCP_STATE_UNMUTED
/*!< The volume state is muted */
#define ESP_BLE_AUDIO_VCP_STATE_MUTED BT_VCP_STATE_MUTED
/** Volume Control Service included services */
typedef struct bt_vcp_included esp_ble_audio_vcp_included_t;
/** Volume Control Service instance */
typedef struct bt_vcp_vol_ctlr esp_ble_audio_vcp_vol_ctlr_t;
/** Struct to hold the Volume Controller callbacks */
typedef struct bt_vcp_vol_ctlr_cb esp_ble_audio_vcp_vol_ctlr_cb_t;
/** Struct to hold the Volume Renderer callbacks */
typedef struct bt_vcp_vol_rend_cb esp_ble_audio_vcp_vol_rend_cb_t;
/** Register structure for Volume Control Service */
typedef struct bt_vcp_vol_rend_register_param esp_ble_audio_vcp_vol_rend_register_param_t;
/**
* @brief Get Volume Control Service included services.
*
* Returns a pointer to a struct that contains information about the
* Volume Control Service included service instances, such as pointers
* to the Volume Offset Control Service (Volume Offset Control Service)
* or Audio Input Control Service (AICS) instances.
*
* @param included Pointer to store the result in.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_vcp_vol_rend_included_get(esp_ble_audio_vcp_included_t *included);
/**
* @brief Register the Volume Control Service.
*
* This will register and enable the service and make it discoverable by
* clients.
*
* @param param Volume Control Service register parameters.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_vcp_vol_rend_register(esp_ble_audio_vcp_vol_rend_register_param_t *param);
/**
* @brief Set the Volume Control Service volume step size.
*
* This can only be done as the server.
*
* @param volume_step The volume step size (1-255).
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_vcp_vol_rend_set_step(uint8_t volume_step);
/**
* @brief Get the Volume Control Service volume state.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_vcp_vol_rend_get_state(void);
/**
* @brief Get the Volume Control Service flags.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_vcp_vol_rend_get_flags(void);
/**
* @brief Turn the volume down by one step on the server.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_vcp_vol_rend_vol_down(void);
/**
* @brief Turn the volume up by one step on the server.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_vcp_vol_rend_vol_up(void);
/**
* @brief Turn the volume down and unmute the server.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_vcp_vol_rend_unmute_vol_down(void);
/**
* @brief Turn the volume up and unmute the server.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_vcp_vol_rend_unmute_vol_up(void);
/**
* @brief Set the volume on the server.
*
* @param volume The absolute volume to set.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_vcp_vol_rend_set_vol(uint8_t volume);
/**
* @brief Unmute the server.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_vcp_vol_rend_unmute(void);
/**
* @brief Mute the server.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_vcp_vol_rend_mute(void);
/**
* @brief Registers the callbacks used by the Volume Controller.
*
* @param cb The callback structure.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_vcp_vol_ctlr_cb_register(esp_ble_audio_vcp_vol_ctlr_cb_t *cb);
/**
* @brief Unregisters the callbacks used by the Volume Controller.
*
* @param cb The callback structure.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_vcp_vol_ctlr_cb_unregister(esp_ble_audio_vcp_vol_ctlr_cb_t *cb);
/**
* @brief Discover Volume Control Service and included services.
*
* This will start a GATT discovery and setup handles and subscriptions.
* This shall be called once before any other actions can be executed
* for the peer device.
*
* This shall only be done as the client,
*
* @param conn_handle Connection handle.
* @param vol_ctlr Valid remote instance object on success.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_vcp_vol_ctlr_discover(uint16_t conn_handle,
esp_ble_audio_vcp_vol_ctlr_t **vol_ctlr);
/**
* @brief Get the volume controller from a connection pointer
*
* Get the Volume Control Profile Volume Controller pointer from a connection.
* Only volume controllers that have been initiated can be retrieved.
*
* @param conn_handle Connection handle.
*
* @return Pointer to a Volume Control Profile Volume Controller instance.
* NULL if the connection has not been found has not done discovery yet.
*/
esp_ble_audio_vcp_vol_ctlr_t *esp_ble_audio_vcp_vol_ctlr_get_by_conn(uint16_t conn_handle);
/**
* @brief Get Volume Control Service included services.
*
* Returns a pointer to a struct that contains information about the
* Volume Control Service included service instances, such as pointers
* to the Volume Offset Control Service (Volume Offset Control Service)
* or Audio Input Control Service (AICS) instances.
*
* @param vol_ctlr Volume Controller instance pointer.
* @param included Pointer to store the result in.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_vcp_vol_ctlr_included_get(esp_ble_audio_vcp_vol_ctlr_t *vol_ctlr,
esp_ble_audio_vcp_included_t *included);
/**
* @brief Read the volume state of a remote Volume Renderer.
*
* @param vol_ctlr Volume Controller instance pointer.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_vcp_vol_ctlr_read_state(esp_ble_audio_vcp_vol_ctlr_t *vol_ctlr);
/**
* @brief Read the volume flags of a remote Volume Renderer.
*
* @param vol_ctlr Volume Controller instance pointer.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_vcp_vol_ctlr_read_flags(esp_ble_audio_vcp_vol_ctlr_t *vol_ctlr);
/**
* @brief Turn the volume down one step on a remote Volume Renderer.
*
* @param vol_ctlr Volume Controller instance pointer.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_vcp_vol_ctlr_vol_down(esp_ble_audio_vcp_vol_ctlr_t *vol_ctlr);
/**
* @brief Turn the volume up one step on a remote Volume Renderer.
*
* @param vol_ctlr Volume Controller instance pointer.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_vcp_vol_ctlr_vol_up(esp_ble_audio_vcp_vol_ctlr_t *vol_ctlr);
/**
* @brief Turn the volume down one step and unmute on a remote Volume Renderer.
*
* @param vol_ctlr Volume Controller instance pointer.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_vcp_vol_ctlr_unmute_vol_down(esp_ble_audio_vcp_vol_ctlr_t *vol_ctlr);
/**
* @brief Turn the volume up one step and unmute on a remote Volume Renderer.
*
* @param vol_ctlr Volume Controller instance pointer.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_vcp_vol_ctlr_unmute_vol_up(esp_ble_audio_vcp_vol_ctlr_t *vol_ctlr);
/**
* @brief Set the absolute volume on a remote Volume Renderer.
*
* @param vol_ctlr Volume Controller instance pointer.
* @param volume The absolute volume to set.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_vcp_vol_ctlr_set_vol(esp_ble_audio_vcp_vol_ctlr_t *vol_ctlr, uint8_t volume);
/**
* @brief Unmute a remote Volume Renderer.
*
* @param vol_ctlr Volume Controller instance pointer.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_vcp_vol_ctlr_unmute(esp_ble_audio_vcp_vol_ctlr_t *vol_ctlr);
/**
* @brief Mute a remote Volume Renderer.
*
* @param vol_ctlr Volume Controller instance pointer.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_vcp_vol_ctlr_mute(esp_ble_audio_vcp_vol_ctlr_t *vol_ctlr);
#ifdef __cplusplus
}
#endif
#endif /* ESP_BLE_AUDIO_VCP_API_H_ */
@@ -0,0 +1,168 @@
/*
* SPDX-FileCopyrightText: 2020-2024 Nordic Semiconductor ASA
* SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ESP_BLE_AUDIO_VOCS_API_H_
#define ESP_BLE_AUDIO_VOCS_API_H_
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include "sdkconfig.h"
#include "esp_err.h"
#include <zephyr/bluetooth/audio/vocs.h>
#include "common/init.h"
#include "common/host.h"
#ifdef __cplusplus
extern "C" {
#endif
/*!< Minimum offset value */
#define ESP_BLE_AUDIO_VOCS_MIN_OFFSET BT_VOCS_MIN_OFFSET
/*!< Maximum offset value */
#define ESP_BLE_AUDIO_VOCS_MAX_OFFSET BT_VOCS_MAX_OFFSET
/** Volume Offset Control Service instance */
typedef struct bt_vocs esp_ble_audio_vocs_t;
/** Struct to hold the Volume Offset Control Service callbacks */
typedef struct bt_vocs_cb esp_ble_audio_vocs_cb_t;
/** Structure for registering a Volume Offset Control Service instance */
typedef struct bt_vocs_register_param esp_ble_audio_vocs_register_param_t;
/** Structure for discovering a Volume Offset Control Service instance */
typedef struct bt_vocs_discover_param esp_ble_audio_vocs_discover_param_t;
/**
* @brief Get a free service instance of Volume Offset Control Service from the pool.
*
* @return Volume Offset Control Service instance in case of success or NULL in case of error.
*/
esp_ble_audio_vocs_t *esp_ble_audio_vocs_free_instance_get(void);
/**
* @brief Get the service declaration attribute.
*
* The first service attribute returned can be included in any other GATT service.
*
* @param vocs Volume Offset Control Service instance.
*
* @return Pointer to the attributes of the service.
*/
void *esp_ble_audio_vocs_svc_decl_get(esp_ble_audio_vocs_t *vocs);
/**
* @brief Register the Volume Offset Control Service instance.
*
* @param vocs Volume Offset Control Service instance.
* @param param Volume Offset Control Service register parameters.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_vocs_register(esp_ble_audio_vocs_t *vocs,
const esp_ble_audio_vocs_register_param_t *param);
/**
* @brief Read the Volume Offset Control Service offset state.
*
* @param inst Pointer to the Volume Offset Control Service instance.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_vocs_state_get(esp_ble_audio_vocs_t *inst);
/**
* @brief Set the Volume Offset Control Service offset state.
*
* @param inst Pointer to the Volume Offset Control Service instance.
* @param offset The offset to set (-255 to 255).
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_vocs_state_set(esp_ble_audio_vocs_t *inst, int16_t offset);
/**
* @brief Read the Volume Offset Control Service location.
*
* @param inst Pointer to the Volume Offset Control Service instance.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_vocs_location_get(esp_ble_audio_vocs_t *inst);
/**
* @brief Set the Volume Offset Control Service location.
*
* @param inst Pointer to the Volume Offset Control Service instance.
* @param location The location to set.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_vocs_location_set(esp_ble_audio_vocs_t *inst, uint32_t location);
/**
* @brief Read the Volume Offset Control Service output description.
*
* @param inst Pointer to the Volume Offset Control Service instance.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_vocs_description_get(esp_ble_audio_vocs_t *inst);
/**
* @brief Set the Volume Offset Control Service description.
*
* @param inst Pointer to the Volume Offset Control Service instance.
* @param description The UTF-8 encoded string description to set.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_vocs_description_set(esp_ble_audio_vocs_t *inst,
const char *description);
/**
* @brief Registers the callbacks for the Volume Offset Control Service client.
*
* @param inst Pointer to the Volume Offset Control Service client instance.
* @param cb Pointer to the callback structure.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_vocs_client_cb_register(esp_ble_audio_vocs_t *inst,
esp_ble_audio_vocs_cb_t *cb);
/**
* @brief Returns a pointer to a Volume Offset Control Service client instance.
*
* @return Pointer to the instance, or NULL if no free instances are left.
*/
esp_ble_audio_vocs_t *esp_ble_audio_vocs_client_free_instance_get(void);
/**
* @brief Discover a Volume Offset Control Service.
*
* Attempts to discover a Volume Offset Control Service on a server given the @p param.
*
* @param conn_handle Connection handle.
* @param inst Pointer to the Volume Offset Control Service client instance.
* @param param Pointer to the parameters.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_audio_vocs_discover(uint16_t conn_handle,
esp_ble_audio_vocs_t *inst,
const esp_ble_audio_vocs_discover_param_t *param);
#ifdef __cplusplus
}
#endif
#endif /* ESP_BLE_AUDIO_VOCS_API_H_ */
@@ -0,0 +1,432 @@
/*
* SPDX-FileCopyrightText: 2020 Intel Corporation
* SPDX-FileCopyrightText: 2021-2024 Nordic Semiconductor ASA
* SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "esp_ble_iso_common_api.h"
esp_err_t esp_ble_iso_data_parse(const uint8_t ltv[], size_t size,
bool (*func)(uint8_t type,
const uint8_t *data,
uint8_t data_len,
void *user_data),
void *user_data)
{
if (ltv == NULL || func == NULL) {
return ESP_ERR_INVALID_ARG;
}
for (size_t i = 0; i < size;) {
const size_t remaining = size - i;
const uint8_t len = ltv[i];
uint8_t data_len;
uint8_t type;
/* LTV item format: [len][type][value...], total item size is len + 1.
* len includes type and value, but excludes itself.
*/
if (len < sizeof(uint8_t) || len > (remaining - 1)) {
return ESP_ERR_INVALID_SIZE;
}
type = ltv[i + 1];
data_len = len - sizeof(uint8_t);
/* Skip empty value entries in strict parsing mode. */
if (data_len == 0) {
i += (size_t)len + 1;
continue;
}
if (func(type, &ltv[i + 2], data_len, user_data) == false) {
return ESP_OK;
}
i += (size_t)len + 1;
}
return ESP_OK;
}
#if CONFIG_BT_ISO_UNICAST
#if CONFIG_BT_ISO_PERIPHERAL
esp_err_t esp_ble_iso_server_register(esp_ble_iso_server_t *server)
{
int err;
err = bt_iso_server_register_safe(server);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_iso_server_unregister(esp_ble_iso_server_t *server)
{
int err;
err = bt_iso_server_unregister_safe(server);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
#endif /* CONFIG_BT_ISO_PERIPHERAL */
#if CONFIG_BT_ISO_CENTRAL
esp_err_t esp_ble_iso_cig_create(esp_ble_iso_cig_param_t *param,
esp_ble_iso_cig_t **out_cig)
{
int err;
err = bt_iso_cig_create_safe(param, out_cig);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_iso_cig_reconfigure(esp_ble_iso_cig_t *cig,
esp_ble_iso_cig_param_t *param)
{
int err;
err = bt_iso_cig_reconfigure_safe(cig, param);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_iso_cig_terminate(esp_ble_iso_cig_t *cig)
{
int err;
err = bt_iso_cig_terminate_safe(cig);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_iso_chan_connect(esp_ble_iso_connect_param_t *param,
uint16_t conn_handle, size_t count)
{
esp_err_t ret = ESP_OK;
void *conn;
int err;
if (param == NULL || count == 0) {
return ESP_ERR_INVALID_ARG;
}
bt_le_host_lock();
conn = bt_le_acl_conn_find(conn_handle);
if (conn == NULL) {
ret = ESP_ERR_NOT_FOUND;
goto unlock;
}
for (size_t i = 0; i < count; i++) {
param[i].acl = conn;
}
err = bt_iso_chan_connect(param, count);
if (err) {
ret = ESP_FAIL;
}
unlock:
bt_le_host_unlock();
return ret;
}
#endif /* CONFIG_BT_ISO_CENTRAL */
esp_err_t esp_ble_iso_chan_disconnect(esp_ble_iso_chan_t *chan)
{
int err;
err = bt_iso_chan_disconnect_safe(chan);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
#endif /* CONFIG_BT_ISO_UNICAST */
static inline bool valid_dir(uint8_t dir)
{
if (dir != ESP_BLE_ISO_DATA_PATH_DIR_INPUT &&
dir != ESP_BLE_ISO_DATA_PATH_DIR_OUTPUT) {
return false;
}
return true;
}
esp_err_t esp_ble_iso_setup_data_path(const esp_ble_iso_chan_t *chan, uint8_t dir,
const esp_ble_iso_chan_path_t *path)
{
int err;
if (chan == NULL || path == NULL || valid_dir(dir) == false) {
return ESP_ERR_INVALID_ARG;
}
err = bt_iso_setup_data_path_safe(chan, dir, path);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_iso_remove_data_path(const esp_ble_iso_chan_t *chan, uint8_t dir)
{
int err;
if (chan == NULL || valid_dir(dir) == false) {
return ESP_ERR_INVALID_ARG;
}
err = bt_iso_remove_data_path_safe(chan, dir);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
#if CONFIG_BT_ISO_BROADCAST
esp_err_t esp_ble_iso_big_register_cb(esp_ble_iso_big_cb_t *cb)
{
int err;
if (cb == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_iso_big_register_cb_safe(cb);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
#if CONFIG_BT_ISO_BROADCASTER
esp_err_t esp_ble_iso_big_ext_adv_add(esp_ble_iso_ext_adv_info_t *info)
{
int err;
if (info == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_le_ext_adv_new_safe(info->adv_handle);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_iso_big_ext_adv_delete(esp_ble_iso_ext_adv_info_t *info)
{
int err;
if (info == NULL) {
return ESP_ERR_INVALID_ARG;
}
err = bt_le_ext_adv_delete_safe(info->adv_handle);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_iso_big_create(uint8_t adv_handle,
esp_ble_iso_big_create_param_t *param,
esp_ble_iso_big_t **out_big)
{
esp_err_t ret = ESP_OK;
void *adv;
int err;
bt_le_host_lock();
adv = bt_le_ext_adv_find(adv_handle);
if (adv == NULL) {
ret = ESP_ERR_NOT_FOUND;
goto unlock;
}
err = bt_iso_big_create(adv, param, out_big);
if (err) {
ret = ESP_FAIL;
}
unlock:
bt_le_host_unlock();
return ret;
}
#endif /* CONFIG_BT_ISO_BROADCASTER */
#if CONFIG_BT_ISO_SYNC_RECEIVER
esp_err_t esp_ble_iso_big_sync(uint16_t sync_handle,
esp_ble_iso_big_sync_param_t *param,
esp_ble_iso_big_t **out_big)
{
void *per_adv_sync;
int err;
per_adv_sync = bt_le_per_adv_sync_find_safe(sync_handle);
if (per_adv_sync == NULL) {
return ESP_ERR_NOT_FOUND;
}
err = bt_iso_big_sync_safe(per_adv_sync, param, out_big);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
#endif /* CONFIG_BT_ISO_SYNC_RECEIVER */
esp_err_t esp_ble_iso_big_terminate(esp_ble_iso_big_t *big)
{
int err;
err = bt_iso_big_terminate_safe(big);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
#endif /* CONFIG_BT_ISO_BROADCAST */
esp_err_t esp_ble_iso_chan_get_info(esp_ble_iso_chan_t *chan,
esp_ble_iso_info_t *info)
{
int err;
err = bt_iso_chan_get_info_safe(chan, info);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
#if CONFIG_BT_ISO_TX
esp_err_t esp_ble_iso_chan_get_tx_sync(esp_ble_iso_chan_t *chan,
esp_ble_iso_tx_info_t *info)
{
int err;
err = bt_iso_chan_get_tx_sync_safe(chan, info);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_iso_chan_send(esp_ble_iso_chan_t *chan,
const uint8_t *sdu,
uint16_t sdu_len,
uint16_t seq_num)
{
struct net_buf buf = {
/* Note: only data and len are used */
.data = (void *)sdu,
.len = sdu_len,
};
int err;
if (chan == NULL || (!sdu ^ !sdu_len)) {
return ESP_ERR_INVALID_ARG;
}
err = bt_iso_chan_send_safe(chan, &buf, seq_num);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_ble_iso_chan_send_ts(esp_ble_iso_chan_t *chan,
const uint8_t *sdu,
uint16_t sdu_len,
uint16_t seq_num,
uint32_t ts)
{
struct net_buf buf = {
/* Note: only data and len are used */
.data = (void *)sdu,
.len = sdu_len,
};
int err;
if (chan == NULL || (!sdu ^ !sdu_len)) {
return ESP_ERR_INVALID_ARG;
}
err = bt_iso_chan_send_ts_safe(chan, &buf, seq_num, ts);
if (err) {
return ESP_FAIL;
}
return ESP_OK;
}
#endif /* CONFIG_BT_ISO_TX */
void esp_ble_iso_gap_app_post_event(uint8_t type, void *param)
{
bt_le_gap_app_post_event(type, param);
}
esp_err_t esp_ble_iso_common_init(esp_ble_iso_init_info_t *info)
{
bool gap_cb_registered = false;
int err;
if (info) {
if (info->gap_cb) {
err = bt_le_gap_app_cb_register(info->gap_cb);
if (err) {
return ESP_FAIL;
}
gap_cb_registered = true;
}
}
err = bt_le_host_init();
if (err) {
goto unregister_gap;
}
return ESP_OK;
unregister_gap:
if (gap_cb_registered) {
bt_le_gap_app_cb_unregister();
}
return ESP_FAIL;
}
@@ -0,0 +1,594 @@
/*
* SPDX-FileCopyrightText: 2020 Intel Corporation
* SPDX-FileCopyrightText: 2021-2024 Nordic Semiconductor ASA
* SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ESP_BLE_ISO_COMMON_API_H_
#define ESP_BLE_ISO_COMMON_API_H_
#include <stdint.h>
#include <string.h>
#include <stddef.h>
#include <stdbool.h>
#include "sdkconfig.h"
#include "esp_err.h"
#include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/bluetooth/iso.h>
#include <../host/conn_internal.h>
#include "common/host.h"
#include "common/app/gap.h"
#include "common/app/gatt.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* Convert BIS index to bit
*
* The BIS indexes start from 0x01, so the lowest allowed bit is
* BIT(0) that represents index 0x01. To synchronize to e.g. BIS
* indexes 0x01 and 0x02, the bitfield value should be BIT(0) | BIT(1).
* As a general notation, to sync to BIS index N use BIT(N - 1).
*/
#define ESP_BLE_ISO_BIS_INDEX_BIT(x) BT_ISO_BIS_INDEX_BIT(x)
/*!< The minimum value for vendor specific data path ID */
#define ESP_BLE_ISO_DATA_PATH_VS_ID_MIN BT_ISO_DATA_PATH_VS_ID_MIN
/*!< The maximum value for vendor specific data path ID */
#define ESP_BLE_ISO_DATA_PATH_VS_ID_MAX BT_ISO_DATA_PATH_VS_ID_MAX
/*!< Minimum controller delay in microseconds */
#define ESP_BLE_ISO_CONTROLLER_DELAY_MIN BT_ISO_CONTROLLER_DELAY_MIN
/*!< Maximum controller delay in microseconds */
#define ESP_BLE_ISO_CONTROLLER_DELAY_MAX BT_ISO_CONTROLLER_DELAY_MAX
/*!< Unknown SDU interval */
#define ESP_BLE_ISO_SDU_INTERVAL_UNKNOWN BT_ISO_SDU_INTERVAL_UNKNOWN
/*!< Minimum interval value in microseconds */
#define ESP_BLE_ISO_SDU_INTERVAL_MIN BT_ISO_SDU_INTERVAL_MIN
/*!< Maximum interval value in microseconds */
#define ESP_BLE_ISO_SDU_INTERVAL_MAX BT_ISO_SDU_INTERVAL_MAX
/*!< Minimum ISO interval (N * 1.25 ms) */
#define ESP_BLE_ISO_ISO_INTERVAL_MIN BT_ISO_ISO_INTERVAL_MIN
/*!< Maximum ISO interval (N * 1.25 ms) */
#define ESP_BLE_ISO_ISO_INTERVAL_MAX BT_ISO_ISO_INTERVAL_MAX
/*!< Minimum latency value in milliseconds */
#define ESP_BLE_ISO_LATENCY_MIN BT_ISO_LATENCY_MIN
/*!< Maximum latency value in milliseconds */
#define ESP_BLE_ISO_LATENCY_MAX BT_ISO_LATENCY_MAX
/*!< Packets will be sent sequentially between the channels in the group */
#define ESP_BLE_ISO_PACKING_SEQUENTIAL BT_ISO_PACKING_SEQUENTIAL
/*!< Packets will be sent interleaved between the channels in the group */
#define ESP_BLE_ISO_PACKING_INTERLEAVED BT_ISO_PACKING_INTERLEAVED
/*!< Packets may be framed or unframed */
#define ESP_BLE_ISO_FRAMING_UNFRAMED BT_ISO_FRAMING_UNFRAMED
/*!< Packets are always framed */
#define ESP_BLE_ISO_FRAMING_FRAMED BT_ISO_FRAMING_FRAMED
/*!< Maximum number of isochronous channels in a single group */
#define ESP_BLE_ISO_MAX_GROUP_ISO_COUNT BT_ISO_MAX_GROUP_ISO_COUNT
/*!< Minimum SDU size */
#define ESP_BLE_ISO_MIN_SDU BT_ISO_MIN_SDU
/*!< Maximum SDU size */
#define ESP_BLE_ISO_MAX_SDU BT_ISO_MAX_SDU
/*!< Minimum PDU size */
#define ESP_BLE_ISO_CONNECTED_PDU_MIN BT_ISO_CONNECTED_PDU_MIN
/*!< Minimum PDU size */
#define ESP_BLE_ISO_BROADCAST_PDU_MIN BT_ISO_BROADCAST_PDU_MIN
/*!< Maximum PDU size */
#define ESP_BLE_ISO_PDU_MAX BT_ISO_PDU_MAX
/*!< Minimum burst number */
#define ESP_BLE_ISO_BN_MIN BT_ISO_BN_MIN
/*!< Maximum burst number */
#define ESP_BLE_ISO_BN_MAX BT_ISO_BN_MAX
/*!< Minimum flush timeout */
#define ESP_BLE_ISO_FT_MIN BT_ISO_FT_MIN
/*!< Maximum flush timeout */
#define ESP_BLE_ISO_FT_MAX BT_ISO_FT_MAX
/*!< Minimum number of subevents */
#define ESP_BLE_ISO_NSE_MIN BT_ISO_NSE_MIN
/*!< Maximum number of subevents */
#define ESP_BLE_ISO_NSE_MAX BT_ISO_NSE_MAX
/*!< Minimum BIG sync timeout value (N * 10 ms) */
#define ESP_BLE_ISO_SYNC_TIMEOUT_MIN BT_ISO_SYNC_TIMEOUT_MIN
/*!< Maximum BIG sync timeout value (N * 10 ms) */
#define ESP_BLE_ISO_SYNC_TIMEOUT_MAX BT_ISO_SYNC_TIMEOUT_MAX
/*!< Controller controlled maximum subevent count value */
#define ESP_BLE_ISO_SYNC_MSE_ANY BT_ISO_SYNC_MSE_ANY
/*!< Minimum BIG sync maximum subevent count value */
#define ESP_BLE_ISO_SYNC_MSE_MIN BT_ISO_SYNC_MSE_MIN
/*!< Maximum BIG sync maximum subevent count value */
#define ESP_BLE_ISO_SYNC_MSE_MAX BT_ISO_SYNC_MSE_MAX
/*!< Minimum connected ISO retransmission value */
#define ESP_BLE_ISO_CONNECTED_RTN_MIN BT_ISO_CONNECTED_RTN_MIN
/*!< Maximum connected ISO retransmission value */
#define ESP_BLE_ISO_CONNECTED_RTN_MAX BT_ISO_CONNECTED_RTN_MAX
/*!< Minimum broadcast ISO retransmission value */
#define ESP_BLE_ISO_BROADCAST_RTN_MIN BT_ISO_BROADCAST_RTN_MIN
/*!< Maximum broadcast ISO retransmission value */
#define ESP_BLE_ISO_BROADCAST_RTN_MAX BT_ISO_BROADCAST_RTN_MAX
/*!< Broadcast code size */
#define ESP_BLE_ISO_BROADCAST_CODE_SIZE BT_ISO_BROADCAST_CODE_SIZE
/*!< Lowest BIS index */
#define ESP_BLE_ISO_BIS_INDEX_MIN BT_ISO_BIS_INDEX_MIN
/*!< Highest BIS index */
#define ESP_BLE_ISO_BIS_INDEX_MAX BT_ISO_BIS_INDEX_MAX
/*!< Minimum Immediate Repetition Count */
#define ESP_BLE_ISO_IRC_MIN BT_ISO_IRC_MIN
/*!< Maximum Immediate Repetition Count */
#define ESP_BLE_ISO_IRC_MAX BT_ISO_IRC_MAX
/*!< Minimum pre-transmission offset */
#define ESP_BLE_ISO_PTO_MIN BT_ISO_PTO_MIN
/*!< Maximum pre-transmission offset */
#define ESP_BLE_ISO_PTO_MAX BT_ISO_PTO_MAX
/*!< No subinterval */
#define ESP_BLE_ISO_SUBINTERVAL_NONE BT_ISO_SUBINTERVAL_NONE
/*!< Unknown subinterval */
#define ESP_BLE_ISO_SUBINTERVAL_UNKNOWN BT_ISO_SUBINTERVAL_UNKNOWN
/*!< Minimum subinterval in microseconds */
#define ESP_BLE_ISO_SUBINTERVAL_MIN BT_ISO_SUBINTERVAL_MIN
/*!< Maximum subinterval in microseconds */
#define ESP_BLE_ISO_SUBINTERVAL_MAX BT_ISO_SUBINTERVAL_MAX
/*!< Audio Input (Host to Controller) Data Path Direction */
#define ESP_BLE_ISO_DATA_PATH_DIR_INPUT BT_HCI_DATAPATH_DIR_HOST_TO_CTLR
/*!< Audio Output (Controller to Host) Data Path Direction */
#define ESP_BLE_ISO_DATA_PATH_DIR_OUTPUT BT_HCI_DATAPATH_DIR_CTLR_TO_HOST
/*!< Value to set the ISO data path over HCI */
#define ESP_BLE_ISO_DATA_PATH_HCI BT_ISO_DATA_PATH_HCI
/*!< Transparent Coding Format */
#define ESP_BLE_ISO_CODING_FORMAT_TRANSPARENT BT_HCI_CODING_FORMAT_TRANSPARENT
/*!< LC3 Coding Format */
#define ESP_BLE_ISO_CODING_FORMAT_LC3 BT_HCI_CODING_FORMAT_LC3
/*!< The ISO packet is valid */
#define ESP_BLE_ISO_FLAGS_VALID BT_ISO_FLAGS_VALID
/*!< The ISO packet may possibly contain errors */
#define ESP_BLE_ISO_FLAGS_ERROR BT_ISO_FLAGS_ERROR
/*!< The ISO packet was lost */
#define ESP_BLE_ISO_FLAGS_LOST BT_ISO_FLAGS_LOST
/*!< Timestamp is valid */
#define ESP_BLE_ISO_FLAGS_TS BT_ISO_FLAGS_TS
/*!< LE 1M PHY */
#define ESP_BLE_ISO_PHY_1M BT_GAP_LE_PHY_1M
/*!< LE 2M PHY */
#define ESP_BLE_ISO_PHY_2M BT_GAP_LE_PHY_2M
/*!< LE Coded PHY, coding scheme not specified */
#define ESP_BLE_ISO_PHY_CODED BT_GAP_LE_PHY_CODED
/*!< Unknown */
#define ESP_BLE_ISO_SCA_UNKNOWN BT_GAP_SCA_UNKNOWN
/*!< 251 ppm to 500 ppm */
#define ESP_BLE_ISO_SCA_251_500 BT_GAP_SCA_251_500
/*!< 151 ppm to 250 ppm */
#define ESP_BLE_ISO_SCA_151_250 BT_GAP_SCA_151_250
/*!< 101 ppm to 150 ppm */
#define ESP_BLE_ISO_SCA_101_150 BT_GAP_SCA_101_150
/*!< 76 ppm to 100 ppm */
#define ESP_BLE_ISO_SCA_76_100 BT_GAP_SCA_76_100
/*!< 51 ppm to 75 ppm */
#define ESP_BLE_ISO_SCA_51_75 BT_GAP_SCA_51_75
/*!< 31 ppm to 50 ppm */
#define ESP_BLE_ISO_SCA_31_50 BT_GAP_SCA_31_50
/*!< 21 ppm to 30 ppm */
#define ESP_BLE_ISO_SCA_21_30 BT_GAP_SCA_21_30
/*!< 0 ppm to 20 ppm */
#define ESP_BLE_ISO_SCA_0_20 BT_GAP_SCA_0_20
/*!< Security Level 1: No encryption and no authentication */
#define ESP_BLE_ISO_SECURITY_NONE BT_SECURITY_L1
/*!< Security Level 2: Encryption and no authentication (no MITM) */
#define ESP_BLE_ISO_SECURITY_NO_MITM BT_SECURITY_L2
/*!< Security Level 3: Encryption and authentication (MITM) */
#define ESP_BLE_ISO_SECURITY_MITM BT_SECURITY_L3
/** Connection structure. */
typedef struct bt_conn esp_ble_conn_t;
/** ISO Channel structure. */
typedef struct bt_iso_chan esp_ble_iso_chan_t;
/** ISO Channel operations structure. */
typedef struct bt_iso_chan_ops esp_ble_iso_chan_ops_t;
/** ISO Channel QoS structure. */
typedef struct bt_iso_chan_qos esp_ble_iso_chan_qos_t;
/** ISO Channel IO QoS structure. */
typedef struct bt_iso_chan_io_qos esp_ble_iso_chan_io_qos_t;
/** ISO Channel Data Path structure. */
typedef struct bt_iso_chan_path esp_ble_iso_chan_path_t;
/** Connected Isochronous Group (CIG). */
typedef struct bt_iso_cig esp_ble_iso_cig_t;
/** Connected Isochronous Group (CIG) parameters. */
typedef struct bt_iso_cig_param esp_ble_iso_cig_param_t;
/** ISO connection parameters structure. */
typedef struct bt_iso_connect_param esp_ble_iso_connect_param_t;
/** ISO Accept Info Structure. */
typedef struct bt_iso_accept_info esp_ble_iso_accept_info_t;
/** ISO Server structure. */
typedef struct bt_iso_server esp_ble_iso_server_t;
/** ISO Unicast Info Structure. */
typedef struct bt_iso_unicast_info esp_ble_iso_unicast_info_t;
/** ISO Unicast TX Info Structure. */
typedef struct bt_iso_unicast_tx_info esp_ble_iso_unicast_tx_info_t;
/** ISO Broadcast callbacks */
typedef struct bt_iso_big_cb esp_ble_iso_big_cb_t;
/** Broadcast Isochronous Group (BIG). */
typedef struct bt_iso_big esp_ble_iso_big_t;
/** Broadcast Isochronous Group (BIG) creation parameters. */
typedef struct bt_iso_big_create_param esp_ble_iso_big_create_param_t;
/** Broadcast Isochronous Group (BIG) Sync Parameters. */
typedef struct bt_iso_big_sync_param esp_ble_iso_big_sync_param_t;
/** Broadcast Isochronous Group (BIG) information. */
typedef struct bt_iso_biginfo esp_ble_iso_biginfo_t;
/** ISO Broadcaster Info Structure. */
typedef struct bt_iso_broadcaster_info esp_ble_iso_broadcaster_info_t;
/** ISO Synchronized Receiver Info Structure. */
typedef struct bt_iso_sync_receiver_info esp_ble_iso_sync_receiver_info_t;
/** ISO channel Info Structure. */
typedef struct bt_iso_info esp_ble_iso_info_t;
/** ISO Meta Data structure for received ISO packets. */
typedef struct bt_iso_recv_info esp_ble_iso_recv_info_t;
/** ISO Meta Data structure for transmitted ISO packets. */
typedef struct bt_iso_tx_info esp_ble_iso_tx_info_t;
/** ISO Unicast & Broadcast TX Callback Info Structure. */
typedef struct bt_iso_tx_cb_info esp_ble_iso_tx_cb_info_t;
/** Extended advertising information structure */
typedef struct {
uint8_t adv_handle; /*!< Handle for the advertising set */
} esp_ble_iso_ext_adv_info_t;
/**
* @brief Helper for parsing length-type-value data.
*
* @param ltv Length-type-value (LTV) encoded data.
* @param size Size of the @p ltv data.
* @param func Callback function which will be called for each element
* that's found in the data. The callback should return
* true to continue parsing, or false to stop parsing.
* @param user_data User data to be passed to the callback.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_iso_data_parse(const uint8_t ltv[], size_t size,
bool (*func)(uint8_t type,
const uint8_t *data,
uint8_t data_len,
void *user_data),
void *user_data);
/**
* @brief Register an ISO server.
*
* @param server Pointer to the ISO server structure.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_iso_server_register(esp_ble_iso_server_t *server);
/**
* @brief Unregister an ISO server.
*
* @param server Pointer to the ISO server structure.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_iso_server_unregister(esp_ble_iso_server_t *server);
/**
* @brief Create a Connected ISO Group (CIG).
*
* @param param Parameters for CIG creation.
* @param out_cig Pointer to store created CIG.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_iso_cig_create(esp_ble_iso_cig_param_t *param,
esp_ble_iso_cig_t **out_cig);
/**
* @brief Reconfigure a Connected ISO Group.
*
* @param cig Pointer to the CIG to reconfigure.
* @param param New parameters for the CIG.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_iso_cig_reconfigure(esp_ble_iso_cig_t *cig,
esp_ble_iso_cig_param_t *param);
/**
* @brief Terminate a Connected ISO Group.
*
* @param cig Pointer to the CIG to terminate.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_iso_cig_terminate(esp_ble_iso_cig_t *cig);
/**
* @brief Connect ISO channels.
*
* @param param Connection parameters.
* @param conn_handle Connection handle.
* @param count Number of channels to connect.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_iso_chan_connect(esp_ble_iso_connect_param_t *param,
uint16_t conn_handle, size_t count);
/**
* @brief Disconnect an ISO channel.
*
* @param chan Pointer to the ISO channel.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_iso_chan_disconnect(esp_ble_iso_chan_t *chan);
/**
* @brief Set up the ISO data path for an ISO channel.
*
* The channel must be associated with a BIS or CIS handle first which it is when the
* esp_ble_iso_chan_ops_t.connected() callback is called.
*
* @param chan The channel to setup the ISO data path for.
* @param dir The direction to setup, either ESP_BLE_ISO_DATA_PATH_DIR_INPUT
* or ESP_BLE_ISO_DATA_PATH_DIR_OUTPUT.
* For ISO broadcast channels this can only be
* ESP_BLE_ISO_DATA_PATH_DIR_INPUT, and for ISO sync receiver
* channels this can only be ESP_BLE_ISO_DATA_PATH_DIR_OUTPUT.
* @param path The data path.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_iso_setup_data_path(const esp_ble_iso_chan_t *chan, uint8_t dir,
const esp_ble_iso_chan_path_t *path);
/**
* @brief Removes the ISO data path for an ISO channel.
*
* Removes the ISO data path configured by esp_ble_iso_setup_data_path() for the provided
* @p dir.
*
* The data paths of CIS for Peripherals are deleted by the controller, and thus it is not
* necessary (or possible) to remove data paths of CIS after they have disconnected for a
* Peripheral, as per Bluetooth Core specification 6.0, Vol 4, Part E, Section 7.7.5.
* The data paths for CIS for a Central remain valid, even after a disconnection, and thus
* a Central device should call bt_iso_remove_data_path() on disconnect if it no longer
* wants to use that CIS.
* All data paths created by a Central are removed when the CIG is removed with
* esp_ble_iso_cig_terminate().
*
* Any data paths associated with an ISO Sync Receiver BIG are removed by the controller
* when the BIG sync is lost or terminated, and thus it is not necessary (or possible) to
* remove data paths of ISO channels associated with a BIG for a Sync Receiver, as per
* Bluetooth Core specification 6.0, Vol 4, Part E, Section 7.7.65.30.
*
* All data paths associated with an ISO Broadcaster BIG are removed when the BIG is
* terminated by esp_ble_iso_big_terminate(), and thus it is not necessary (or possible)
* to remove data paths of ISO channels associated with a BIG for a Broadcaster,
* as per Bluetooth Core specification 6.0, Vol 4, Part E, Section 7.8.105.
*
* @param chan The channel to setup the ISO data path for.
* @param dir The direction to setup, either ESP_BLE_ISO_DATA_PATH_DIR_INPUT or
* ESP_BLE_ISO_DATA_PATH_DIR_OUTPUT. For ISO broadcast channels this
* can only be ESP_BLE_ISO_DATA_PATH_DIR_INPUT, and for ISO sync
* receiver channels this can only be ESP_BLE_ISO_DATA_PATH_DIR_OUTPUT.
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_iso_remove_data_path(const esp_ble_iso_chan_t *chan, uint8_t dir);
/**
* @brief Registers callbacks for Broadcast Sources.
*
* @param cb Pointer to the callback structure.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_iso_big_register_cb(esp_ble_iso_big_cb_t *cb);
/**
* @brief Add extended advertising for BIG.
*
* @param info Extended advertising information.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_iso_big_ext_adv_add(esp_ble_iso_ext_adv_info_t *info);
/**
* @brief Delete extended advertising for BIG.
*
* @param info Extended advertising information.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_iso_big_ext_adv_delete(esp_ble_iso_ext_adv_info_t *info);
/**
* @brief Create a Broadcast ISO Group (BIG).
*
* @param adv_handle Advertising handle.
* @param param Parameters for BIG creation.
* @param out_big Pointer to store created BIG.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_iso_big_create(uint8_t adv_handle,
esp_ble_iso_big_create_param_t *param,
esp_ble_iso_big_t **out_big);
/**
* @brief Synchronize with a Broadcast ISO Group.
*
* @param sync_handle Sync handle.
* @param param Sync parameters.
* @param out_big Pointer to store synchronized BIG.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_iso_big_sync(uint16_t sync_handle,
esp_ble_iso_big_sync_param_t *param,
esp_ble_iso_big_t **out_big);
/**
* @brief Terminate a Broadcast ISO Group.
*
* @param big Pointer to the BIG to terminate.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_iso_big_terminate(esp_ble_iso_big_t *big);
/**
* @brief Get ISO channel information.
*
* @param chan Pointer to the ISO channel.
* @param info Pointer to store channel information.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_iso_chan_get_info(esp_ble_iso_chan_t *chan,
esp_ble_iso_info_t *info);
/**
* @brief Get TX sync information for an ISO channel.
*
* @param chan Pointer to the ISO channel.
* @param info Pointer to store TX sync information.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_iso_chan_get_tx_sync(esp_ble_iso_chan_t *chan,
esp_ble_iso_tx_info_t *info);
/**
* @brief Send data over an ISO channel.
*
* @param chan Pointer to the ISO channel.
* @param sdu Pointer to the SDU data.
* @param sdu_len Length of the SDU.
* @param seq_num Sequence number.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_iso_chan_send(esp_ble_iso_chan_t *chan,
const uint8_t *sdu,
uint16_t sdu_len,
uint16_t seq_num);
/**
* @brief Send timestamped data over an ISO channel.
*
* @param chan Pointer to the ISO channel.
* @param sdu Pointer to the SDU data.
* @param sdu_len Length of the SDU.
* @param seq_num Sequence number.
* @param ts Timestamp.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_iso_chan_send_ts(esp_ble_iso_chan_t *chan,
const uint8_t *sdu,
uint16_t sdu_len,
uint16_t seq_num,
uint32_t ts);
/*!< ISO GAP Extended Scan Recv event */
#define ESP_BLE_ISO_GAP_EVENT_EXT_SCAN_RECV BT_LE_GAP_APP_EVENT_EXT_SCAN_RECV
/*!< ISO GAP Periodic Sync Established event */
#define ESP_BLE_ISO_GAP_EVENT_PA_SYNC BT_LE_GAP_APP_EVENT_PA_SYNC
/*!< ISO GAP Periodic Sync Lost event */
#define ESP_BLE_ISO_GAP_EVENT_PA_SYNC_LOST BT_LE_GAP_APP_EVENT_PA_SYNC_LOST
/*!< ISO GAP Connection Complete event */
#define ESP_BLE_ISO_GAP_EVENT_ACL_CONNECT BT_LE_GAP_APP_EVENT_ACL_CONNECT
/*!< ISO GAP Disconnection Complete event */
#define ESP_BLE_ISO_GAP_EVENT_ACL_DISCONNECT BT_LE_GAP_APP_EVENT_ACL_DISCONNECT
/*!< ISO GAP Security Changed event */
#define ESP_BLE_ISO_GAP_EVENT_SECURITY_CHANGE BT_LE_GAP_APP_EVENT_SECURITY_CHANGE
/*!< ISO GAP BIGInfo Adv Report event */
#define ESP_BLE_ISO_GAP_EVENT_BIGINFO_RECV BT_LE_GAP_APP_EVENT_BIGINFO_RECV
/** ISO GAP application event structure */
typedef struct bt_le_gap_app_event esp_ble_iso_gap_app_event_t;
/** ISO initialization information structure */
typedef struct {
bt_le_gap_app_cb gap_cb; /*!< GAP event callbacks */
} esp_ble_iso_init_info_t;
/**
* @brief Post an application-layer GAP event for ISO internal usage.
*
* @note This function is only needed while using NimBLE Host.
*
* @param type Event type.
* @param param Event parameters.
*/
void esp_ble_iso_gap_app_post_event(uint8_t type, void *param);
/**
* @brief Initialize ISO common functionality.
*
* @param info Initialization information.
*
* @return ESP_OK on success, or an error code on failure.
*/
esp_err_t esp_ble_iso_common_init(esp_ble_iso_init_info_t *info);
#ifdef __cplusplus
}
#endif
#endif /* ESP_BLE_ISO_COMMON_API_H_ */
@@ -0,0 +1,205 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <errno.h>
#include <zephyr/logging/log.h>
#include <zephyr/bluetooth/buf.h>
#include <zephyr/bluetooth/hci.h>
#include <../host/hci_core.h>
#include <../host/iso_internal.h>
#include "host/ble_gap.h"
#include "services/gap/ble_svc_gap.h"
#include "common/host.h"
#include "common/app/gap.h"
void bt_le_nimble_gap_post_event(void *param)
{
struct bt_le_gap_app_param *qev;
struct ble_gap_conn_desc desc;
struct ble_gap_event *ev;
int err;
qev = calloc(1, sizeof(*qev));
assert(qev);
memset(&desc, 0, sizeof(desc));
ev = param;
if (ev->type != BLE_GAP_EVENT_EXT_DISC &&
ev->type != BLE_GAP_EVENT_PERIODIC_REPORT) {
LOG_DBG("[N]PostGapEvt[%u]", ev->type);
}
/* TODO:
* - Limit the adv report posted to ISO task;
* - Limit the extended adv report posted to ISO task;
* - Limit the periodic adv report posted to ISO task;
* - E.g. If the adv report contains any information interested by LE Audio.
*/
switch (ev->type) {
case BLE_GAP_EVENT_EXT_DISC:
qev->type = BT_LE_GAP_APP_PARAM_EXT_SCAN_RECV;
qev->ext_scan_recv.event_type = (ev->ext_disc.data_status << 5) | ev->ext_disc.props;
qev->ext_scan_recv.addr.type = ev->ext_disc.addr.type;
memcpy(qev->ext_scan_recv.addr.val, ev->ext_disc.addr.val, BT_ADDR_SIZE);
qev->ext_scan_recv.rssi = ev->ext_disc.rssi;
qev->ext_scan_recv.tx_power = ev->ext_disc.tx_power;
qev->ext_scan_recv.sid = ev->ext_disc.sid;
qev->ext_scan_recv.pri_phy = ev->ext_disc.prim_phy;
qev->ext_scan_recv.sec_phy = ev->ext_disc.sec_phy;
qev->ext_scan_recv.per_adv_itvl = ev->ext_disc.periodic_adv_itvl;
qev->ext_scan_recv.data_len = ev->ext_disc.length_data;
if (qev->ext_scan_recv.data_len) {
qev->ext_scan_recv.data = calloc(1, qev->ext_scan_recv.data_len);
assert(qev->ext_scan_recv.data);
memcpy(qev->ext_scan_recv.data, ev->ext_disc.data, qev->ext_scan_recv.data_len);
}
break;
case BLE_GAP_EVENT_PERIODIC_SYNC:
qev->type = BT_LE_GAP_APP_PARAM_PA_SYNC;
qev->pa_sync.status = ev->periodic_sync.status;
qev->pa_sync.sync_handle = ev->periodic_sync.sync_handle;
qev->pa_sync.addr.type = ev->periodic_sync.adv_addr.type;
memcpy(qev->pa_sync.addr.val, ev->periodic_sync.adv_addr.val, BT_ADDR_SIZE);
qev->pa_sync.sid = ev->periodic_sync.sid;
qev->pa_sync.adv_phy = ev->periodic_sync.adv_phy;
qev->pa_sync.per_adv_itvl = ev->periodic_sync.per_adv_ival;
qev->pa_sync.adv_ca = ev->periodic_sync.adv_clk_accuracy;
break;
case BLE_GAP_EVENT_PERIODIC_SYNC_LOST:
qev->type = BT_LE_GAP_APP_PARAM_PA_SYNC_LOST;
qev->pa_sync_lost.sync_handle = ev->periodic_sync_lost.sync_handle;
qev->pa_sync_lost.reason = ev->periodic_sync_lost.reason;
break;
case BLE_GAP_EVENT_PERIODIC_REPORT:
qev->type = BT_LE_GAP_APP_PARAM_PA_SYNC_RECV;
qev->pa_sync_recv.sync_handle = ev->periodic_report.sync_handle;
qev->pa_sync_recv.tx_power = ev->periodic_report.tx_power;
qev->pa_sync_recv.rssi = ev->periodic_report.rssi;
qev->pa_sync_recv.data_status = ev->periodic_report.data_status;
qev->pa_sync_recv.data_len = ev->periodic_report.data_length;
if (qev->pa_sync_recv.data_len) {
qev->pa_sync_recv.data = calloc(1, qev->pa_sync_recv.data_len);
assert(qev->pa_sync_recv.data);
memcpy(qev->pa_sync_recv.data, ev->periodic_report.data, qev->pa_sync_recv.data_len);
}
break;
case BLE_GAP_EVENT_CONNECT:
qev->type = BT_LE_GAP_APP_PARAM_ACL_CONNECT;
qev->acl_connect.status = ev->connect.status;
if (qev->acl_connect.status == 0) {
err = ble_gap_conn_find(ev->connect.conn_handle, &desc);
assert(err == 0);
qev->acl_connect.conn_handle = desc.conn_handle;
qev->acl_connect.role = desc.role;
qev->acl_connect.dst.type = desc.peer_id_addr.type;
memcpy(qev->acl_connect.dst.val, desc.peer_id_addr.val, BT_ADDR_SIZE);
}
break;
case BLE_GAP_EVENT_DISCONNECT:
qev->type = BT_LE_GAP_APP_PARAM_ACL_DISCONNECT;
qev->acl_disconnect.conn_handle = ev->disconnect.conn.conn_handle;
qev->acl_disconnect.reason = ev->disconnect.reason;
break;
case BLE_GAP_EVENT_ENC_CHANGE:
qev->type = BT_LE_GAP_APP_PARAM_SECURITY_CHANGE;
qev->security_change.status = ev->enc_change.status;
if (qev->security_change.status == 0) {
err = ble_gap_conn_find(ev->enc_change.conn_handle, &desc);
assert(err == 0);
qev->security_change.conn_handle = ev->enc_change.conn_handle;
qev->security_change.role = desc.role;
qev->security_change.sec_level = BT_SECURITY_L3;
qev->security_change.dst.type = desc.peer_id_addr.type;
memcpy(qev->security_change.dst.val, desc.peer_id_addr.val, BT_ADDR_SIZE);
}
break;
default:
free(qev);
assert(0);
break;
}
err = bt_le_iso_task_post(ISO_QUEUE_ITEM_TYPE_GAP_EVENT, qev, sizeof(*qev));
if (err) {
LOG_ERR("[N]GapPostEvtFail[%d][%u]", err, qev->type);
goto free;
}
return;
free:
switch (qev->type) {
case BT_LE_GAP_APP_PARAM_EXT_SCAN_RECV:
if (qev->ext_scan_recv.data) {
free(qev->ext_scan_recv.data);
qev->ext_scan_recv.data = NULL;
}
break;
case BT_LE_GAP_APP_PARAM_PA_SYNC_RECV:
if (qev->pa_sync_recv.data) {
free(qev->pa_sync_recv.data);
qev->pa_sync_recv.data = NULL;
}
break;
default:
break;
}
free(qev);
}
int bt_le_nimble_scan_start(const struct bt_le_scan_param *param, ble_gap_event_fn *cb)
{
struct ble_gap_disc_params scan_param = {0};
scan_param.itvl = param->interval;
scan_param.window = param->window;
scan_param.filter_policy = 0;
scan_param.limited = 0;
scan_param.passive = !param->type;
scan_param.filter_duplicates = 0;
return ble_gap_disc(BLE_OWN_ADDR_PUBLIC, BLE_HS_FOREVER, &scan_param, cb, NULL);
}
int bt_le_nimble_scan_stop(void)
{
return ble_gap_disc_cancel();
}
int bt_le_nimble_iso_disconnect(uint16_t conn_handle, uint8_t reason)
{
return ble_gap_iso_disconnect(conn_handle, reason);
}
@@ -0,0 +1,30 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef HOST_NIMBLE_APP_GAP_H_
#define HOST_NIMBLE_APP_GAP_H_
#include <stdint.h>
#include "host/ble_gap.h"
#ifdef __cplusplus
extern "C" {
#endif
void bt_le_nimble_gap_post_event(void *param);
int bt_le_nimble_scan_start(const struct bt_le_scan_param *param, ble_gap_event_fn *cb);
int bt_le_nimble_scan_stop(void);
int bt_le_nimble_iso_disconnect(uint16_t conn_handle, uint8_t reason);
#ifdef __cplusplus
}
#endif
#endif /* HOST_NIMBLE_APP_GAP_H_ */
@@ -0,0 +1,525 @@
/*
* 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/bluetooth.h>
#include <zephyr/bluetooth/conn.h>
#include <zephyr/bluetooth/gatt.h>
#include <zephyr/bluetooth/common/bt_str.h>
#include <../host/conn_internal.h>
#include "host/ble_hs.h"
#include "host/ble_att.h"
#include "host/ble_gatt.h"
#include "host/ble_hs_mbuf.h"
#include "common/host.h"
#include "common/app/gatt.h"
void bt_le_nimble_gatt_post_event(void *param)
{
struct bt_le_gatt_event_param *qev;
struct ble_gap_event *ev;
int err;
ev = param;
/* LOG_DBG("[N]PostGattEvt[%u]", ev->type); */
/* Currently we only handle this event for indication */
if (ev->type == BLE_GAP_EVENT_NOTIFY_TX && ev->notify_tx.indication == 0) {
return;
}
qev = calloc(1, sizeof(*qev));
assert(qev);
switch (ev->type) {
case BLE_GAP_EVENT_MTU:
qev->type = BT_LE_GATT_MTU_CHANGE_EVENT;
qev->gatt_mtu_change.conn_handle = ev->mtu.conn_handle;
qev->gatt_mtu_change.mtu = ev->mtu.value;
break;
case BLE_GAP_EVENT_SUBSCRIBE:
qev->type = BT_LE_GATTS_SUBSCRIBE_EVENT;
qev->gatts_subscribe.conn_handle = ev->subscribe.conn_handle;
qev->gatts_subscribe.attr_handle = ev->subscribe.attr_handle;
qev->gatts_subscribe.prev_notify = ev->subscribe.prev_notify;
qev->gatts_subscribe.cur_notify = ev->subscribe.cur_notify;
qev->gatts_subscribe.prev_indicate = ev->subscribe.prev_indicate;
qev->gatts_subscribe.cur_indicate = ev->subscribe.cur_indicate;
qev->gatts_subscribe.reason = ev->subscribe.reason;
break;
case BLE_GAP_EVENT_NOTIFY_RX:
qev->type = BT_LE_GATTC_NOTIFY_RX_EVENT;
qev->gattc_notify_rx.conn_handle = ev->notify_rx.conn_handle;
qev->gattc_notify_rx.attr_handle = ev->notify_rx.attr_handle;
qev->gattc_notify_rx.is_notify = (ev->notify_rx.indication == 0);
if (ev->notify_rx.om && OS_MBUF_PKTLEN(ev->notify_rx.om)) {
uint16_t total_len = OS_MBUF_PKTLEN(ev->notify_rx.om);
qev->gattc_notify_rx.len = total_len;
qev->gattc_notify_rx.value = calloc(1, total_len);
assert(qev->gattc_notify_rx.value);
os_mbuf_copydata(ev->notify_rx.om, 0, total_len, qev->gattc_notify_rx.value);
}
break;
case BLE_GAP_EVENT_NOTIFY_TX:
qev->type = BT_LE_GATTS_NOTIFY_TX_EVENT;
qev->gatts_notify_tx.is_notify = (ev->notify_tx.indication == 0);
qev->gatts_notify_tx.conn_handle = ev->notify_tx.conn_handle;
qev->gatts_notify_tx.attr_handle = ev->notify_tx.attr_handle;
qev->gatts_notify_tx.status = ev->notify_tx.status;
break;
default:
free(qev);
assert(0);
break;
}
err = bt_le_iso_task_post(ISO_QUEUE_ITEM_TYPE_GATT_EVENT, qev, sizeof(*qev));
if (err) {
LOG_ERR("[N]GattPostEvtFail[%d][%u]", err, qev->type);
if (qev->type == BT_LE_GATTC_NOTIFY_RX_EVENT &&
qev->gattc_notify_rx.value) {
free(qev->gattc_notify_rx.value);
qev->gattc_notify_rx.value = NULL;
}
free(qev);
}
}
int bt_le_nimble_gatt_post_disc_event(uint16_t conn_handle, ble_uuid16_t *uuid,
struct bt_gatt_discover_params *params,
uint8_t type)
{
struct bt_le_gatt_event_param *qev;
int err;
LOG_DBG("[N]GattcDiscHdlr[%u][%u]", conn_handle, type);
if (type == GATTC_DISC_TYPE_DUMMY || type >= GATTC_DISC_TYPE_MAX) {
LOG_ERR("[N]InvDiscType[%u]", type);
return -EINVAL;
}
qev = calloc(1, sizeof(*qev));
assert(qev);
qev->type = BT_LE_GATTC_DISCOVER_EVENT;
qev->gattc_discover.type = type;
qev->gattc_discover.conn_handle = conn_handle;
qev->gattc_discover.uuid = (uuid ? uuid->value : 0x0000);
qev->gattc_discover.params = params;
err = bt_le_iso_task_post(ISO_QUEUE_ITEM_TYPE_GATT_EVENT, qev, sizeof(*qev));
if (err) {
LOG_ERR("[N]GattPostDiscEvtFail[%d][%u]", err, type);
free(qev);
return err;
}
return 0;
}
int bt_le_nimble_gatt_post_disc_cmpl_event(uint16_t conn_handle, uint8_t status)
{
struct bt_le_gatt_event_param *qev;
int err;
LOG_DBG("[N]GattcDiscCmplEvtHdlr[%u][%02x]", conn_handle, status);
qev = calloc(1, sizeof(*qev));
assert(qev);
qev->type = BT_LE_GATTC_DISC_CMPL_EVENT;
qev->gattc_disc_cmpl.status = status;
qev->gattc_disc_cmpl.conn_handle = conn_handle;
err = bt_le_iso_task_post(ISO_QUEUE_ITEM_TYPE_GATT_EVENT, qev, sizeof(*qev));
if (err) {
LOG_ERR("[N]GattPostDiscCmplEvtFail[%d][%u][%02x]", err, conn_handle, status);
free(qev);
return err;
}
return 0;
}
static void handle_gatts_subscribe_event_safe(struct bt_le_gatts_subscribe_event *event)
{
/* LOG_DBG("[N]HdlGattsSubEvt[%u][%u][%u][%u][%02x]", */
/* event->conn_handle, event->attr_handle, event->cur_notify, */
/* event->cur_indicate, event->reason); */
/* Note:
* For NimBLE Host, the attr_handle is the handle of characteristic value
* declaration. For CCCD, its attr_handle shall be incremented with 1.
*/
bt_le_host_lock();
bt_gatts_sub_changed(event->conn_handle,
event->attr_handle + 1,
event->cur_notify,
event->cur_indicate,
event->reason);
bt_le_host_unlock();
bt_le_gatts_app_subscribe_event(event);
}
static void handle_gattc_notify_rx_event_safe(struct bt_le_gattc_notify_rx_event *event)
{
struct bt_gatt_subscribe_params *params;
struct gattc_sub *sub;
struct bt_conn *conn;
LOG_DBG("[N]HdlGattcNtfRxEvt[%u][%u][%u]",
event->conn_handle, event->attr_handle, event->len);
bt_le_host_lock();
conn = bt_le_acl_conn_find(event->conn_handle);
if (conn == NULL || conn->state != BT_CONN_CONNECTED) {
LOG_ERR("[N]NotConn[%d]", __LINE__);
goto end;
}
sub = bt_gattc_sub_find(conn);
if (sub == NULL) {
goto end;
}
SYS_SLIST_FOR_EACH_CONTAINER(&sub->list, params, node) {
if (params->ccc_handle != BT_GATT_AUTO_DISCOVER_CCC_HANDLE &&
params->value_handle == event->attr_handle) {
if (params->notify) {
params->notify(conn, params, event->value, event->len);
}
}
}
end:
if (event->value) {
free(event->value);
}
bt_le_host_unlock();
}
static void handle_gatts_notify_tx_event_safe(struct bt_le_gatts_notify_tx_event *event)
{
LOG_DBG("[N]HdlGattsNtfTxEvt[%u][%u][%u][%02x]",
event->conn_handle, event->attr_handle, event->is_notify, event->status);
/* Currently we only handle this event for indication */
if (event->is_notify) {
return;
}
/* The event->status could be:
* - 0: Indication is sent successfully;
* - BLE_HS_EDONE: Confirm is received;
* - BLE_HS_ENOTCONN: Not connected;
* - BLE_HS_ETIMEOUT: ATT procedure times out.
*/
bt_le_host_lock();
bt_le_nimble_gatts_nrp_indicate_cb(event->conn_handle, event->attr_handle, event->status);
bt_le_host_unlock();
}
void bt_le_nimble_gatt_handle_event(uint8_t *data, size_t data_len)
{
struct bt_le_gatt_event_param *param;
param = (struct bt_le_gatt_event_param *)data;
/* LOG_DBG("[N]HdlGattEvt[%u]", param->type); */
switch (param->type) {
case BT_LE_GATT_MTU_CHANGE_EVENT:
bt_le_gatt_app_mtu_change_event(param->gatt_mtu_change.conn_handle,
param->gatt_mtu_change.mtu);
break;
case BT_LE_GATTC_DISCOVER_EVENT:
handle_gattc_db_disc_event_safe(&param->gattc_discover);
break;
case BT_LE_GATTC_DISC_CMPL_EVENT:
bt_le_gattc_app_disc_cmpl_event(&param->gattc_disc_cmpl);
break;
case BT_LE_GATTS_SUBSCRIBE_EVENT:
handle_gatts_subscribe_event_safe(&param->gatts_subscribe);
break;
case BT_LE_GATTC_NOTIFY_RX_EVENT:
handle_gattc_notify_rx_event_safe(&param->gattc_notify_rx);
break;
case BT_LE_GATTS_NOTIFY_TX_EVENT:
handle_gatts_notify_tx_event_safe(&param->gatts_notify_tx);
break;
default:
assert(0);
break;
}
free(data);
}
uint16_t bt_le_nimble_gatt_get_mtu(struct bt_conn *conn)
{
LOG_DBG("[N]GattGetMtu[%u]", conn->handle);
return ble_att_mtu(conn->handle);
}
ssize_t bt_le_nimble_gatts_attr_read(struct bt_conn *conn, const struct bt_gatt_attr *attr,
void *buf, uint16_t buf_len, uint16_t offset,
const void *value, uint16_t value_len)
{
uint16_t len;
if (buf_len == UINT16_MAX) {
/* TODO: A better solution for using a variable for the cb pointer */
struct bt_le_nimble_gatt_read_cb *cb = buf;
assert(cb->read_cb);
len = cb->read_cb(cb->read_arg, offset, value, value_len);
} else {
assert(attr);
LOG_DBG("[N]Hdl[%u]", attr->handle);
if (offset >= value_len) {
LOG_WRN("[N]OffsetTooLarge[%u][%u]", offset, value_len);
return 0;
}
len = MIN(buf_len, value_len - offset);
memcpy(buf, (uint8_t *)value + offset, len);
}
LOG_DBG("[N]GattsAttrRd[%u]", len);
return len;
}
static int gatts_notify(struct bt_conn *conn, struct bt_gatt_notify_params *params)
{
struct notify_data data;
struct bt_conn *conns;
uint8_t conns_count;
struct os_mbuf *om;
int rc = 0;
memset(&data, 0, sizeof(data));
data.attr = params->attr;
data.handle = bt_gatt_attr_get_handle(data.attr);
/* Lookup UUID if it was given */
if (params->uuid) {
if (bt_gatts_find_attr_by_uuid(&data, params->uuid) == false) {
return -ENOENT;
}
params->attr = data.attr;
} else {
if (data.handle == 0) {
LOG_WRN("[N]DataHdlZero");
return -ENOENT;
}
}
/* Check if attribute is a characteristic then adjust the handle */
if (bt_uuid_cmp(data.attr->uuid, BT_UUID_GATT_CHRC) == 0) {
struct bt_gatt_chrc *chrc;
assert(data.attr->user_data);
chrc = data.attr->user_data;
if ((chrc->properties & BT_GATT_CHRC_NOTIFY) == 0) {
LOG_WRN("[N]NtfNotSupp[%u][%02x]", data.handle, chrc->properties);
return -EINVAL;
}
data.handle = bt_gatt_attr_value_handle(data.attr);
LOG_INF("[N]DataHdl[%u][%u]", data.attr->handle, data.handle);
}
if (conn) {
om = ble_hs_mbuf_from_flat(params->data, params->len);
if (om == NULL) {
LOG_ERR("[N]NoMemForNtf[%u]", params->len);
return -ENOMEM;
}
rc = ble_gatts_notify_custom(conn->handle, data.handle, om);
if (rc && rc != BLE_HS_ENOTCONN) {
LOG_ERR("[N]GattsNtfCustomFail[%d]", rc);
}
} else {
bt_conn_get_acl_conns(&conns, &conns_count);
for (size_t i = 0; i < conns_count; i++) {
if (conns[i].state == BT_CONN_CONNECTED) {
om = ble_hs_mbuf_from_flat(params->data, params->len);
if (om == NULL) {
LOG_ERR("[N]NoMemForNtf[%u]", params->len);
return -ENOMEM;
}
rc = ble_gatts_notify_custom(conns[i].handle, data.handle, om);
if (rc && rc != BLE_HS_ENOTCONN) {
LOG_ERR("[N]GattsNtfCustomFail[%d]", rc);
}
}
}
/* For sending notifications to all connected peers, always return success */
rc = 0;
}
return rc;
}
int bt_le_nimble_gatts_notify(struct bt_conn *conn, struct bt_gatt_notify_params *params)
{
LOG_DBG("[N]GattsNtf[%u]", conn ? conn->handle : UINT16_MAX);
return gatts_notify(conn, params);
}
int bt_le_nimble_gatts_indicate(struct bt_conn *conn, struct bt_gatt_indicate_params *params)
{
LOG_DBG("[N]GattsInd[%u]", conn ? conn->handle : UINT16_MAX);
return bt_le_nimble_gatt_nrp_insert(conn, GATTS_NRP_INDICATE, params);
}
int bt_le_nimble_gattc_disc_start(uint16_t conn_handle)
{
LOG_DBG("[N]GattcDiscStart[%u]", conn_handle);
return bt_le_nimble_gattc_db_auto_disc(conn_handle);
}
int bt_le_nimble_gattc_discover(struct bt_conn *conn, struct bt_gatt_discover_params *params)
{
ble_uuid16_t uuid = {0};
LOG_DBG("[N]GattcDisc[%u]", conn->handle);
if (params->uuid) {
uuid.u.type = BLE_UUID_TYPE_16;
uuid.value = BT_UUID_16(params->uuid)->val;
}
switch (params->type) {
case BT_GATT_DISCOVER_PRIMARY:
if (params->uuid) {
return bt_le_nimble_gattc_db_disc_svc_by_uuid(conn, &uuid, params);
}
LOG_ERR("[N]NotSuppDiscAllPrimarySvcs");
return -ENOTSUP;
case BT_GATT_DISCOVER_INCLUDE:
return bt_le_nimble_gattc_db_find_inc_svcs(conn, params);
case BT_GATT_DISCOVER_CHARACTERISTIC:
if (params->uuid) {
return bt_le_nimble_gattc_db_disc_chrs_by_uuid(conn, &uuid, params);
}
return bt_le_nimble_gattc_db_disc_all_chrs(conn, params);
case BT_GATT_DISCOVER_DESCRIPTOR:
assert(params->uuid);
/* Only descriptors can be filtered */
if (bt_uuid_cmp(params->uuid, BT_UUID_GATT_PRIMARY) == 0 ||
bt_uuid_cmp(params->uuid, BT_UUID_GATT_SECONDARY) == 0 ||
bt_uuid_cmp(params->uuid, BT_UUID_GATT_INCLUDE) == 0 ||
bt_uuid_cmp(params->uuid, BT_UUID_GATT_CHRC) == 0) {
LOG_ERR("[N]InvDscToDisc[%02x]", params->uuid->type);
return -EINVAL;
}
return bt_le_nimble_gattc_db_disc_all_dscs(conn, params);
default:
LOG_ERR("[N]DiscNotSupp[%u]", params->type);
return -ENOTSUP;
}
}
int bt_le_nimble_gattc_read(struct bt_conn *conn, struct bt_gatt_read_params *params)
{
uint8_t type;
if (params->handle_count == 0) {
type = GATTC_NRP_READ_BY_UUID;
} else if (params->single.offset) {
type = GATTC_NRP_READ_LONG;
} else {
type = GATTC_NRP_READ_SINGLE;
}
LOG_DBG("[N]GattcRd[%u][%u]", conn->handle, type);
return bt_le_nimble_gatt_nrp_insert(conn, type, params);
}
int bt_le_nimble_gattc_write(struct bt_conn *conn, struct bt_gatt_write_params *params)
{
LOG_DBG("[N]GattcWr[%u]", conn->handle);
return bt_le_nimble_gatt_nrp_insert(conn, GATTC_NRP_WRITE_REQ, params);
}
int bt_le_nimble_gattc_write_without_rsp(struct bt_conn *conn, uint16_t handle,
const void *data, uint16_t length)
{
LOG_DBG("[N]GattcWrCmd[%u][%u][%u]", conn->handle, handle, length);
return ble_gattc_write_no_rsp_flat(conn->handle, handle, data, length);
}
int bt_le_nimble_gattc_write_ccc(struct bt_conn *conn, struct bt_gatt_subscribe_params *params)
{
/* LOG_DBG("[N]GattcWrCcc[%u]", conn->handle); */
return bt_le_nimble_gatt_nrp_insert(conn, GATTC_NRP_SUBSCRIBE, params);
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,124 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef HOST_NIMBLE_GATT_H_
#define HOST_NIMBLE_GATT_H_
#include <stdint.h>
#include <assert.h>
#include <zephyr/bluetooth/uuid.h>
#include "host/ble_uuid.h"
#include "host/ble_gatt.h"
#ifdef __cplusplus
extern "C" {
#endif
struct bt_le_nimble_gatt_read_cb {
int (*read_cb)(void *arg, uint16_t offset, const void *data, uint16_t len);
void *read_arg;
};
static inline uint8_t BT_LE_NIMBLE_GATT_UUID_TO_Z(uint8_t type)
{
/* Used to convert NimBLE UUID to Zephyr UUID */
if (type == BLE_UUID_TYPE_16) {
return BT_UUID_TYPE_16;
} else if (type == BLE_UUID_TYPE_32) {
return BT_UUID_TYPE_32;
} else if (type == BLE_UUID_TYPE_128) {
return BT_UUID_TYPE_128;
} else {
assert(0);
return BT_UUID_TYPE_16;
}
}
void bt_le_nimble_gatt_post_event(void *event);
int bt_le_nimble_gatt_post_disc_event(uint16_t conn_handle, ble_uuid16_t *uuid,
struct bt_gatt_discover_params *params,
uint8_t type);
int bt_le_nimble_gatt_post_disc_cmpl_event(uint16_t conn_handle, uint8_t status);
void bt_le_nimble_gatt_handle_event(uint8_t *data, size_t data_len);
uint16_t bt_le_nimble_gatt_get_mtu(struct bt_conn *conn);
ssize_t bt_le_nimble_gatts_attr_read(struct bt_conn *conn, const struct bt_gatt_attr *attr,
void *buf, uint16_t buf_len, uint16_t offset,
const void *value, uint16_t value_len);
int bt_le_nimble_gatts_notify(struct bt_conn *conn, struct bt_gatt_notify_params *params);
int bt_le_nimble_gatts_indicate(struct bt_conn *conn, struct bt_gatt_indicate_params *params);
int bt_le_nimble_gattc_disc_start(uint16_t conn_handle);
int bt_le_nimble_gattc_discover(struct bt_conn *conn, struct bt_gatt_discover_params *params);
int bt_le_nimble_gattc_read(struct bt_conn *conn, struct bt_gatt_read_params *params);
int bt_le_nimble_gattc_write(struct bt_conn *conn, struct bt_gatt_write_params *params);
int bt_le_nimble_gattc_write_without_rsp(struct bt_conn *conn, uint16_t handle,
const void *data, uint16_t length);
int bt_le_nimble_gattc_write_ccc(struct bt_conn *conn, struct bt_gatt_subscribe_params *params);
struct bt_le_gattc_discover_event;
void handle_gattc_db_disc_event_safe(struct bt_le_gattc_discover_event *event);
int bt_le_nimble_gattc_db_disc_svc_by_uuid(struct bt_conn *conn, ble_uuid16_t *uuid,
struct bt_gatt_discover_params *params);
int bt_le_nimble_gattc_db_find_inc_svcs(struct bt_conn *conn,
struct bt_gatt_discover_params *params);
int bt_le_nimble_gattc_db_disc_chrs_by_uuid(struct bt_conn *conn, ble_uuid16_t *uuid,
struct bt_gatt_discover_params *params);
int bt_le_nimble_gattc_db_disc_all_chrs(struct bt_conn *conn,
struct bt_gatt_discover_params *params);
int bt_le_nimble_gattc_db_disc_all_dscs(struct bt_conn *conn,
struct bt_gatt_discover_params *params);
int bt_le_nimble_gattc_db_auto_disc(uint16_t conn_handle);
void bt_le_nimble_gattc_db_remove(uint16_t conn_handle);
enum {
GATTC_NRP_READ_BY_UUID,
GATTC_NRP_READ_LONG,
GATTC_NRP_READ_SINGLE,
GATTC_NRP_WRITE_REQ,
GATTC_NRP_SUBSCRIBE,
GATTS_NRP_INDICATE,
GATT_NRP_MAX_NUM,
};
void bt_le_nimble_gatts_nrp_indicate_cb(uint16_t conn_handle,
int16_t attr_handle,
uint8_t status);
int bt_le_nimble_gatt_nrp_insert(struct bt_conn *conn, uint8_t type, void *params);
int bt_le_nimble_gatt_nrp_remove(struct bt_conn *conn, uint8_t type, void *params);
void bt_le_nimble_gatt_nrp_clear(uint16_t conn_handle);
#ifdef __cplusplus
}
#endif
#endif /* HOST_NIMBLE_GATT_H_ */
@@ -0,0 +1,901 @@
/*
* 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/bluetooth.h>
#include <zephyr/bluetooth/conn.h>
#include <zephyr/bluetooth/gatt.h>
#include <zephyr/bluetooth/common/bt_str.h>
#include <../host/conn_internal.h>
#include "host/ble_hs.h"
#include "host/ble_att.h"
#include "host/ble_gatt.h"
#include "host/ble_hs_mbuf.h"
#include "common/host.h"
struct gatt_nrp_node {
uint8_t type;
union {
struct {
struct bt_gatt_read_params *params;
} read_by_uuid;
struct {
struct bt_gatt_read_params *params;
} read_long;
struct {
struct bt_gatt_read_params *params;
} read_single;
struct {
struct bt_gatt_write_params *params;
} write_req;
struct {
struct bt_gatt_subscribe_params *params;
} subscribe;
struct {
struct bt_gatt_indicate_params *params;
} indicate;
};
sys_snode_t node;
};
static struct gatt_nrp {
uint16_t conn_handle;
sys_slist_t list; /* List of GATT need response pdu (e.g., read req, write req, indication, etc.) */
} gatt_nrp[CONFIG_BT_MAX_CONN] = {
[0 ...(CONFIG_BT_MAX_CONN - 1)] = {
.conn_handle = UINT16_MAX,
},
};
static int gattc_nrp_read_by_uuid_cb_safe(uint16_t conn_handle,
const struct ble_gatt_error *error,
struct ble_gatt_attr *attr,
void *arg)
{
struct bt_gatt_read_params *read_params;
struct bt_conn *conn;
int rc = 0;
read_params = arg;
assert(read_params);
assert(read_params->func);
assert(read_params->handle_count == 0);
assert(read_params->by_uuid.uuid);
assert(read_params->by_uuid.uuid->type == BT_UUID_TYPE_16);
LOG_DBG("[N]GattcNrpRdByUuidCb[%u][%04x][%s]",
conn_handle, error->status, bt_uuid_str(read_params->by_uuid.uuid));
bt_le_host_lock();
conn = bt_le_acl_conn_find(conn_handle);
if (conn == NULL || conn->state != BT_CONN_CONNECTED) {
LOG_ERR("[N]GattcNrpNotConn[%d]", __LINE__);
rc = -ENOTCONN;
/* Note:
* Cannot remove NRP node or invoke callback without valid conn.
* Consider if bt_le_nimble_gatt_nrp_clear() should be invoked.
*/
goto end;
}
/* Shall be invoked before the read_params->func is invoked */
bt_le_nimble_gatt_nrp_remove(conn, GATTC_NRP_READ_BY_UUID, read_params);
switch (error->status) {
case 0:
assert(attr);
assert(attr->om);
LOG_DBG("[N]GattcNrpHdl[%u][%u][%u]Len[%u]",
attr->handle, read_params->by_uuid.start_handle,
read_params->by_uuid.end_handle, attr->om->om_len);
if (read_params->by_uuid.start_handle == BT_ATT_FIRST_ATTRIBUTE_HANDLE) {
read_params->by_uuid.start_handle = attr->handle;
}
read_params->func(conn, 0, read_params, attr->om->om_data, attr->om->om_len);
break;
case BLE_HS_EDONE:
read_params->func(conn, 0, read_params, NULL, 0);
break;
default:
LOG_WRN("[N]GattcNrpStatus[%04x]", error->status);
if (error->status & BLE_HS_ERR_ATT_BASE) {
read_params->func(conn, (uint8_t)error->status, read_params, NULL, 0);
} else {
/* Note: for other errors, currently we just ignore it. */
}
rc = error->status;
break;
}
end:
bt_le_host_unlock();
return rc;
}
static int gattc_nrp_read_long_cb_safe(uint16_t conn_handle,
const struct ble_gatt_error *error,
struct ble_gatt_attr *attr,
void *arg)
{
struct bt_gatt_read_params *read_params;
struct bt_conn *conn;
int rc = 0;
read_params = arg;
assert(read_params);
assert(read_params->func);
assert(read_params->handle_count == 1);
assert(read_params->single.offset != 0);
LOG_DBG("[N]GattcNrpRdLongCb[%u][%04x]", conn_handle, error->status);
bt_le_host_lock();
conn = bt_le_acl_conn_find(conn_handle);
if (conn == NULL || conn->state != BT_CONN_CONNECTED) {
LOG_ERR("[N]GattcNrpNotConn[%d]", __LINE__);
rc = -ENOTCONN;
goto end;
}
/* Shall be invoked before the read_params->func is invoked */
bt_le_nimble_gatt_nrp_remove(conn, GATTC_NRP_READ_LONG, read_params);
switch (error->status) {
case 0:
assert(attr);
assert(attr->om);
LOG_DBG("[N]GattcNrpHdl[%u][%u]Offset[%u]Len[%u]",
attr->handle, read_params->single.handle, attr->offset, attr->om->om_len);
read_params->func(conn, 0, read_params, attr->om->om_data, attr->om->om_len);
break;
case BLE_HS_EDONE:
read_params->func(conn, 0, read_params, NULL, 0);
break;
default:
LOG_WRN("[N]GattcNrpStatus[%04x]", error->status);
if (error->status & BLE_HS_ERR_ATT_BASE) {
read_params->func(conn, (uint8_t)error->status, read_params, NULL, 0);
} else {
/* Note: for other errors, currently we just ignore it. */
}
rc = error->status;
break;
}
end:
bt_le_host_unlock();
return rc;
}
static int gattc_nrp_read_single_cb_safe(uint16_t conn_handle,
const struct ble_gatt_error *error,
struct ble_gatt_attr *attr,
void *arg)
{
struct bt_gatt_read_params *read_params;
struct bt_conn *conn;
int rc = 0;
read_params = arg;
assert(read_params);
assert(read_params->func);
assert(read_params->handle_count == 1);
assert(read_params->single.offset == 0);
LOG_DBG("[N]GattcNrpRdSingleCb[%u][%04x]", conn_handle, error->status);
bt_le_host_lock();
conn = bt_le_acl_conn_find(conn_handle);
if (conn == NULL || conn->state != BT_CONN_CONNECTED) {
LOG_ERR("[N]GattcNrpNotConn[%d]", __LINE__);
rc = -ENOTCONN;
goto end;
}
/* Shall be invoked before the read_params->func is invoked */
bt_le_nimble_gatt_nrp_remove(conn, GATTC_NRP_READ_SINGLE, read_params);
switch (error->status) {
case 0:
assert(attr);
assert(attr->om);
LOG_DBG("[N]GattcNrpHdl[%u][%u]Len[%u]",
attr->handle, read_params->single.handle, attr->om->om_len);
if (read_params->func(conn, 0, read_params,
attr->om->om_data,
attr->om->om_len) == BT_GATT_ITER_CONTINUE) {
/* Workaround for completing the handling of ATT Read Response
* by BAP Unicast Client.
*/
read_params->func(conn, 0, read_params, NULL, 0);
}
break;
case BLE_HS_EDONE:
read_params->func(conn, 0, read_params, NULL, 0);
break;
default:
LOG_WRN("[N]GattcNrpStatus[%04x]", error->status);
if (error->status & BLE_HS_ERR_ATT_BASE) {
read_params->func(conn, (uint8_t)error->status, read_params, NULL, 0);
} else {
/* Note: for other errors, currently we just ignore it. */
}
rc = error->status;
break;
}
end:
bt_le_host_unlock();
return rc;
}
static int gattc_nrp_read(struct bt_conn *conn, struct bt_gatt_read_params *params)
{
int rc;
LOG_DBG("[N]GattcNrpRd[%u][%u]", conn->handle, params->handle_count);
if (params->handle_count == 0) {
LOG_DBG("[N]GattcNrpByUuid[%u][%u][%s]",
params->by_uuid.start_handle, params->by_uuid.end_handle,
bt_uuid_str(params->by_uuid.uuid));
ble_uuid16_t uuid = {
.u.type = BLE_UUID_TYPE_16,
.value = BT_UUID_16(params->by_uuid.uuid)->val,
};
rc = ble_gattc_read_by_uuid(conn->handle,
params->by_uuid.start_handle,
params->by_uuid.end_handle,
&uuid.u,
gattc_nrp_read_by_uuid_cb_safe,
params);
if (rc) {
LOG_ERR("[N]GattcNrpRdByUuidFail[%d]", rc);
}
} else if (params->single.offset) {
LOG_DBG("[N]GattcNrpLong[%u][%u]", params->single.handle, params->single.offset);
rc = ble_gattc_read_long(conn->handle,
params->single.handle,
params->single.offset,
gattc_nrp_read_long_cb_safe,
params);
if (rc) {
LOG_ERR("[N]GattcNrpRdLongFail[%d]", rc);
}
} else {
LOG_DBG("[N]GattcNrpSingle[%u]", params->single.handle);
rc = ble_gattc_read(conn->handle,
params->single.handle,
gattc_nrp_read_single_cb_safe,
params);
if (rc) {
LOG_ERR("[N]GattcNrpRdFail[%d]", rc);
}
}
return rc;
}
static int gattc_nrp_write_cb_safe(uint16_t conn_handle,
const struct ble_gatt_error *error,
struct ble_gatt_attr *attr,
void *arg)
{
struct bt_gatt_write_params *write_params;
struct bt_conn *conn;
int rc = 0;
write_params = arg;
assert(write_params);
assert(write_params->func);
LOG_DBG("[N]GattcNrpWrCb[%u][%04x]", conn_handle, error->status);
bt_le_host_lock();
conn = bt_le_acl_conn_find(conn_handle);
if (conn == NULL || conn->state != BT_CONN_CONNECTED) {
LOG_ERR("[N]GattcNrpNotConn[%d]", __LINE__);
rc = -ENOTCONN;
goto end;
}
/* Shall be invoked before the write_params->func is invoked */
bt_le_nimble_gatt_nrp_remove(conn, GATTC_NRP_WRITE_REQ, write_params);
switch (error->status) {
case 0:
assert(attr);
LOG_DBG("[N]GattcNrpHdl[%u][%u]", attr->handle, write_params->handle);
write_params->func(conn, 0, write_params);
break;
case BLE_HS_EDONE:
/* Note: for sending write request, the EDONE status will not be reported. */
break;
default:
LOG_WRN("[N]GattcNrpStatus[%04x]", error->status);
if (error->status & BLE_HS_ERR_ATT_BASE) {
write_params->func(conn, (uint8_t)error->status, write_params);
} else {
/* Note: for other errors, currently we just ignore it. */
}
rc = error->status;
break;
}
end:
bt_le_host_unlock();
return rc;
}
static int gattc_nrp_write(struct bt_conn *conn, struct bt_gatt_write_params *params)
{
int rc;
LOG_DBG("[N]GattcNrpWr[%u][%u][%u]",
conn->handle, params->handle, params->length);
rc = ble_gattc_write_flat(conn->handle,
params->handle,
params->data,
params->length,
gattc_nrp_write_cb_safe,
params);
if (rc) {
LOG_ERR("[N]GattcNrpWrFlatFail[%d]", rc);
}
return rc;
}
static int gattc_nrp_subscribe_cb_safe(uint16_t conn_handle,
const struct ble_gatt_error *error,
struct ble_gatt_attr *attr,
void *arg)
{
struct bt_gatt_subscribe_params *sub_params;
struct bt_conn *conn;
int rc = 0;
sub_params = arg;
assert(sub_params);
LOG_DBG("[N]GattcNrpSubCb[%u][%04x]", conn_handle, error->status);
bt_le_host_lock();
conn = bt_le_acl_conn_find(conn_handle);
if (conn == NULL || conn->state != BT_CONN_CONNECTED) {
LOG_ERR("[N]GattcNrpNotConn[%d]", __LINE__);
rc = -ENOTCONN;
goto end;
}
/* Should be invoked here */
bt_le_nimble_gatt_nrp_remove(conn, GATTC_NRP_SUBSCRIBE, sub_params);
switch (error->status) {
case 0:
assert(attr);
LOG_DBG("[N]GattcNrpHdl[%u]", attr->handle);
#if 0
/* Mask the callback invocation for now.
* Check the bt_gatt_subscribe function for details.
*/
if (sub_params->subscribe) {
sub_params->subscribe(conn, 0, sub_params);
}
#endif
break;
case BLE_HS_EDONE:
break;
default:
LOG_WRN("[N]GattcNrpStatus[%04x]", error->status);
#if 0
/* Mask the callback invocation for now.
* Check the bt_gatt_subscribe function for details.
*/
if (sub_params->subscribe && (error->status & BLE_HS_ERR_ATT_BASE)) {
sub_params->subscribe(conn, (uint8_t)error->status, sub_params);
}
#endif
rc = error->status;
break;
}
end:
bt_le_host_unlock();
return rc;
}
static int gattc_nrp_subscribe(struct bt_conn *conn, struct bt_gatt_subscribe_params *params)
{
int rc;
LOG_DBG("[N]GattcNrpSub[%u][%u][%04x]",
conn->handle, params->ccc_handle, params->value);
rc = ble_gattc_write_flat(conn->handle,
params->ccc_handle,
&params->value,
sizeof(params->value),
gattc_nrp_subscribe_cb_safe,
params);
if (rc && rc != BLE_HS_ENOTCONN) {
LOG_ERR("[N]GattcNrpSubFail[%d]", rc);
}
return rc;
}
void bt_le_nimble_gatts_nrp_indicate_cb(uint16_t conn_handle,
int16_t attr_handle,
uint8_t status)
{
struct bt_gatt_indicate_params params = {0};
struct bt_gatt_attr attr = {0};
struct bt_conn *conn;
LOG_DBG("[N]GattsNrpIndCb[%u][%u][%u]", conn_handle, attr_handle, status);
conn = bt_le_acl_conn_find(conn_handle);
if (conn == NULL || conn->state != BT_CONN_CONNECTED) {
LOG_ERR("[N]GattsNrpNotConn[%d]", __LINE__);
return;
}
switch (status) {
case 0:
break;
case BLE_HS_EDONE:
break;
default:
LOG_WRN("[N]GattsNrpIndCbStatus[%u]", status);
break;
}
if (status) {
attr.handle = attr_handle;
params.attr = &attr;
bt_le_nimble_gatt_nrp_remove(conn, GATTS_NRP_INDICATE, &params);
}
}
static int gatts_nrp_indicate(struct bt_conn *conn, struct bt_gatt_indicate_params *params)
{
struct notify_data data = {0};
struct os_mbuf *om = NULL;
int rc;
assert(conn && params);
assert(params->attr);
assert(params->data);
assert(params->len);
data.attr = params->attr;
data.handle = bt_gatt_attr_get_handle(data.attr);
LOG_DBG("[N]GattsNrpInd[%u][%u]", conn->handle, data.handle);
/* Lookup UUID if it was given */
if (params->uuid) {
if (bt_gatts_find_attr_by_uuid(&data, params->uuid) == false) {
return -ENOENT;
}
params->attr = data.attr;
} else {
if (data.handle == 0) {
LOG_WRN("[N]GattsNrpDataHdlZero");
return -ENOENT;
}
}
/* Check if attribute is a characteristic then adjust the handle */
if (bt_uuid_cmp(data.attr->uuid, BT_UUID_GATT_CHRC) == 0) {
struct bt_gatt_chrc *chrc;
assert(data.attr->user_data);
chrc = data.attr->user_data;
if ((chrc->properties & BT_GATT_CHRC_INDICATE) == 0) {
LOG_WRN("[N]GattsNrpIndNotSupp[%u][%02x]", data.handle, chrc->properties);
return -EINVAL;
}
data.handle = bt_gatt_attr_value_handle(data.attr);
LOG_INF("[N]GattsNrpDataHdl[%u][%u]", data.attr->handle, data.handle);
}
om = ble_hs_mbuf_from_flat(params->data, params->len);
if (om == NULL) {
LOG_ERR("[N]GattsNrpNoMemForInd[%u]", params->len);
return -ENOMEM;
}
rc = ble_gatts_indicate_custom(conn->handle, data.handle, om);
if (rc) {
LOG_ERR("[N]GattsNrpIndCustomFail[%d]", rc);
}
return rc;
}
static struct gatt_nrp *gatt_nrp_add(uint16_t conn_handle)
{
for (size_t i = 0; i < ARRAY_SIZE(gatt_nrp); i++) {
if (gatt_nrp[i].conn_handle == UINT16_MAX) {
gatt_nrp[i].conn_handle = conn_handle;
sys_slist_init(&gatt_nrp[i].list);
return &gatt_nrp[i];
}
}
LOG_ERR("[N]GattNrpNoFreeGattNrp[%u]", conn_handle);
return NULL;
}
static struct gatt_nrp *gatt_nrp_find(uint16_t conn_handle)
{
for (size_t i = 0; i < ARRAY_SIZE(gatt_nrp); i++) {
if (gatt_nrp[i].conn_handle == conn_handle) {
LOG_DBG("[N]GattNrpFound[%u]", conn_handle);
return &gatt_nrp[i];
}
}
return NULL;
}
static void gatt_nrp_del(struct gatt_nrp *nrp)
{
struct gatt_nrp_node *nrp_head;
sys_snode_t *node;
assert(nrp);
while (1) {
node = sys_slist_get(&nrp->list);
if (node == NULL) {
break;
}
nrp_head = CONTAINER_OF(node, struct gatt_nrp_node, node);
LOG_DBG("[N]GattNrpFree[%p]", nrp_head);
free(nrp_head);
}
nrp->conn_handle = UINT16_MAX;
}
static int gatt_nrp_insert(struct bt_conn *conn, uint8_t type, void *params)
{
struct gatt_nrp_node *nrp_node;
struct gatt_nrp *nrp;
int rc = 0;
LOG_DBG("[N]GattNrpInsert[%u][%u]", conn->handle, type);
nrp = gatt_nrp_find(conn->handle);
if (nrp == NULL) {
nrp = gatt_nrp_add(conn->handle);
}
if (nrp == NULL) {
return -ENOMEM;
}
nrp_node = calloc(1, sizeof(*nrp_node));
assert(nrp_node);
nrp_node->type = type;
switch (type) {
case GATTC_NRP_READ_BY_UUID:
nrp_node->read_by_uuid.params = params;
break;
case GATTC_NRP_READ_LONG:
nrp_node->read_long.params = params;
break;
case GATTC_NRP_READ_SINGLE:
nrp_node->read_single.params = params;
break;
case GATTC_NRP_WRITE_REQ:
nrp_node->write_req.params = params;
break;
case GATTC_NRP_SUBSCRIBE:
nrp_node->subscribe.params = params;
break;
case GATTS_NRP_INDICATE:
nrp_node->indicate.params = params;
break;
default:
assert(0);
}
if (sys_slist_is_empty(&nrp->list)) {
LOG_DBG("[N]GattNrpListEmpty");
if (type == GATTC_NRP_READ_BY_UUID ||
type == GATTC_NRP_READ_LONG ||
type == GATTC_NRP_READ_SINGLE) {
rc = gattc_nrp_read(conn, params);
} else if (type == GATTC_NRP_WRITE_REQ) {
rc = gattc_nrp_write(conn, params);
} else if (type == GATTC_NRP_SUBSCRIBE) {
rc = gattc_nrp_subscribe(conn, params);
} else if (type == GATTS_NRP_INDICATE) {
rc = gatts_nrp_indicate(conn, params);
}
} else {
LOG_DBG("[N]GattNrpListNotEmpty");
rc = 0;
}
if (rc == 0) {
LOG_DBG("[N]GattNrpAppend[%p]", nrp_node);
sys_slist_append(&nrp->list, &nrp_node->node);
} else {
LOG_ERR("[N]GattNrpInsertFail[%d]", rc);
free(nrp_node);
}
return rc;
}
static int gatts_nrp_indicate_insert(struct bt_conn *conn, struct bt_gatt_indicate_params *params)
{
struct bt_conn *conns;
uint8_t conns_count;
int rc = 0;
LOG_DBG("[N]GattsNrpIndInsert[%p]", conn);
if (conn) {
return gatt_nrp_insert(conn, GATTS_NRP_INDICATE, params);
}
bt_conn_get_acl_conns(&conns, &conns_count);
for (size_t i = 0; i < conns_count; i++) {
LOG_DBG("[N]GattsNrpConn[%u][%u][%u]", i, conns[i].handle, conns[i].state);
if (conns[i].state == BT_CONN_CONNECTED) {
rc = gatt_nrp_insert(&conns[i], GATTS_NRP_INDICATE, params);
if (rc) {
return rc;
}
}
}
return 0;
}
int bt_le_nimble_gatt_nrp_insert(struct bt_conn *conn, uint8_t type, void *params)
{
int rc;
if (type == GATTS_NRP_INDICATE) {
rc = gatts_nrp_indicate_insert(conn, params);
} else {
rc = gatt_nrp_insert(conn, type, params);
}
return rc;
}
int bt_le_nimble_gatt_nrp_remove(struct bt_conn *conn, uint8_t type, void *params)
{
struct gatt_nrp_node *nrp_head;
struct gatt_nrp *nrp;
sys_snode_t *node;
int rc = 0;
LOG_DBG("[N]GattNrpRemove[%u][%u]", conn->handle, type);
nrp = gatt_nrp_find(conn->handle);
if (nrp == NULL) {
LOG_ERR("[N]GattNrpNotFound[%u]", conn->handle);
return -ENODEV;
}
/* Fetch and remove the first node from list */
node = sys_slist_get(&nrp->list);
assert(node);
nrp_head = CONTAINER_OF(node, struct gatt_nrp_node, node);
assert(nrp_head->type == type);
switch (type) {
case GATTC_NRP_READ_BY_UUID:
assert(nrp_head->read_by_uuid.params == params);
break;
case GATTC_NRP_READ_LONG:
assert(nrp_head->read_long.params == params);
break;
case GATTC_NRP_READ_SINGLE:
assert(nrp_head->read_single.params == params);
break;
case GATTC_NRP_WRITE_REQ:
assert(nrp_head->write_req.params == params);
break;
case GATTC_NRP_SUBSCRIBE:
assert(nrp_head->subscribe.params == params);
break;
case GATTS_NRP_INDICATE:
assert(nrp_head->indicate.params);
if (nrp_head->indicate.params->attr->handle !=
((struct bt_gatt_indicate_params *)params)->attr->handle) {
LOG_ERR("[N]GattNrpMismatchIndHdl[%u][%u]",
((struct bt_gatt_indicate_params *)params)->attr->handle,
nrp_head->indicate.params->attr->handle);
assert(0); /* Should not happen */
}
/* Note:
* The params may be shared by multiple connections. And currently
* in this case, the params will not be updated in the func callback.
*/
nrp_head->indicate.params->func(conn, nrp_head->indicate.params, 0);
break;
default:
assert(0);
}
LOG_DBG("[N]GattNrpFree[%p]", nrp_head);
free(nrp_head);
while (1) {
if (sys_slist_is_empty(&nrp->list)) {
break;
}
/* Fetch the first node from list */
node = sys_slist_peek_head(&nrp->list);
nrp_head = CONTAINER_OF(node, struct gatt_nrp_node, node);
if (nrp_head->type == GATTC_NRP_READ_BY_UUID) {
rc = gattc_nrp_read(conn, nrp_head->read_by_uuid.params);
if (rc) {
LOG_ERR("[N]GattcNrpRdByUuidFail[%d]", rc);
assert(nrp_head->read_by_uuid.params->func);
nrp_head->read_by_uuid.params->func(conn, rc, nrp_head->read_by_uuid.params, NULL, 0);
}
} else if (nrp_head->type == GATTC_NRP_READ_LONG) {
rc = gattc_nrp_read(conn, nrp_head->read_long.params);
if (rc) {
LOG_ERR("[N]GattcNrpRdLongFail[%d]", rc);
assert(nrp_head->read_long.params->func);
nrp_head->read_long.params->func(conn, rc, nrp_head->read_long.params, NULL, 0);
}
} else if (nrp_head->type == GATTC_NRP_READ_SINGLE) {
rc = gattc_nrp_read(conn, nrp_head->read_single.params);
if (rc) {
LOG_ERR("[N]GattcNrpRdSingleFail[%d]", rc);
assert(nrp_head->read_single.params->func);
nrp_head->read_single.params->func(conn, rc, nrp_head->read_single.params, NULL, 0);
}
} else if (nrp_head->type == GATTC_NRP_WRITE_REQ) {
rc = gattc_nrp_write(conn, nrp_head->write_req.params);
if (rc) {
LOG_ERR("[N]GattcNrpWrFail[%d]", rc);
assert(nrp_head->write_req.params->func);
nrp_head->write_req.params->func(conn, rc, nrp_head->write_req.params);
}
} else if (nrp_head->type == GATTC_NRP_SUBSCRIBE) {
rc = gattc_nrp_subscribe(conn, nrp_head->subscribe.params);
if (rc) {
LOG_ERR("[N]GattcNrpSubFail[%d]", rc);
}
} else if (nrp_head->type == GATTS_NRP_INDICATE) {
rc = gatts_nrp_indicate(conn, nrp_head->indicate.params);
if (rc) {
LOG_ERR("[N]GattsNrpIndFail[%d]", rc);
assert(nrp_head->indicate.params->func);
nrp_head->indicate.params->func(conn, nrp_head->indicate.params, rc);
}
}
if (rc == 0) {
LOG_DBG("[N]GattNrpOnGoing[%p]", nrp_head);
break;
}
LOG_DBG("[N]GattNrpRemoveAndFree[%p]", nrp_head);
/* If this nrp operation failed, then remove it from list,
* peek the next node and start.
*/
sys_slist_remove(&nrp->list, NULL, node);
free(nrp_head);
}
return 0;
}
void bt_le_nimble_gatt_nrp_clear(uint16_t conn_handle)
{
struct gatt_nrp *nrp;
LOG_DBG("[N]GattNrpClear[%u]", conn_handle);
nrp = gatt_nrp_find(conn_handle);
if (nrp == NULL) {
return;
}
gatt_nrp_del(nrp);
}
@@ -0,0 +1,455 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdint.h>
#include <string.h>
#include <errno.h>
#include "sdkconfig.h"
#include <zephyr/sys/util.h>
#include <zephyr/logging/log.h>
#include <zephyr/bluetooth/audio/vcp.h>
#include "host/ble_gatt.h"
#include "services/gap/ble_svc_gap.h"
#include "services/gatt/ble_svc_gatt.h"
#include "nimble/init.h"
#include "common/init.h"
#include "../../../lib/include/audio.h"
#if CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT
#define ASCS_ASE_SNK_CCCD_COUNT CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT
#else /* CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT */
#define ASCS_ASE_SNK_CCCD_COUNT 0
#endif /* CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT */
#if CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT
#define ASCS_ASE_SRC_CCCD_COUNT CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT
#else /* CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT */
#define ASCS_ASE_SRC_CCCD_COUNT 0
#endif /* CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT */
#if CONFIG_BT_PAC_SNK_NOTIFIABLE
#define PAC_SNK_CCCD_COUNT 1
#else /* CONFIG_BT_PAC_SNK_NOTIFIABLE */
#define PAC_SNK_CCCD_COUNT 0
#endif /* CONFIG_BT_PAC_SNK_NOTIFIABLE */
#if CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE
#define PAC_SNK_LOC_CCCD_COUNT 1
#else /* CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE */
#define PAC_SNK_LOC_CCCD_COUNT 0
#endif /* CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE */
#if CONFIG_BT_PAC_SRC_NOTIFIABLE
#define PAC_SRC_CCCD_COUNT 1
#else /* CONFIG_BT_PAC_SRC_NOTIFIABLE */
#define PAC_SRC_CCCD_COUNT 0
#endif /* CONFIG_BT_PAC_SRC_NOTIFIABLE */
#if CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE
#define PAC_SRC_LOC_CCCD_COUNT 1
#else /* CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE */
#define PAC_SRC_LOC_CCCD_COUNT 0
#endif /* CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE */
#if CONFIG_BT_PACS_SUPPORTED_CONTEXT_NOTIFIABLE
#define PACS_SUPPORTED_CONTEXT_CCCD_COUNT 1
#else /* CONFIG_BT_PACS_SUPPORTED_CONTEXT_NOTIFIABLE */
#define PACS_SUPPORTED_CONTEXT_CCCD_COUNT 0
#endif /* CONFIG_BT_PACS_SUPPORTED_CONTEXT_NOTIFIABLE */
#if CONFIG_BT_BAP_SCAN_DELEGATOR_RECV_STATE_COUNT
#define SCAN_DELEGATOR_RECV_STATE_CCCD_COUNT CONFIG_BT_BAP_SCAN_DELEGATOR_RECV_STATE_COUNT
#else /* CONFIG_BT_BAP_SCAN_DELEGATOR_RECV_STATE_COUNT */
#define SCAN_DELEGATOR_RECV_STATE_CCCD_COUNT 0
#endif /* CONFIG_BT_BAP_SCAN_DELEGATOR_RECV_STATE_COUNT */
#if CONFIG_BT_CSIP_SET_MEMBER_SIRK_NOTIFIABLE
#define CSIP_SET_MEMBER_CCCD_COUNT 1
#else /* CONFIG_BT_CSIP_SET_MEMBER_SIRK_NOTIFIABLE */
#define CSIP_SET_MEMBER_CCCD_COUNT 0
#endif /* CONFIG_BT_CSIP_SET_MEMBER_SIRK_NOTIFIABLE */
#if CONFIG_BT_VCP_VOL_REND_VOL_FLAGS_NOTIFIABLE
#define VCP_VOL_REND_VOL_FLAGS_CCCD_COUNT 1
#else /* CONFIG_BT_VCP_VOL_REND_VOL_FLAGS_NOTIFIABLE */
#define VCP_VOL_REND_VOL_FLAGS_CCCD_COUNT 0
#endif /* CONFIG_BT_VCP_VOL_REND_VOL_FLAGS_NOTIFIABLE */
#if CONFIG_BT_VOCS_MAX_INSTANCE_COUNT
#define VOCS_CCCD_COUNT (CONFIG_BT_VOCS_MAX_INSTANCE_COUNT * 3)
#else /* CONFIG_BT_VOCS_MAX_INSTANCE_COUNT */
#define VOCS_CCCD_COUNT 0
#endif /* CONFIG_BT_VOCS_MAX_INSTANCE_COUNT */
#if CONFIG_BT_AICS_MAX_INSTANCE_COUNT
#define AICS_CCCD_COUNT (CONFIG_BT_AICS_MAX_INSTANCE_COUNT * 3)
#else /* CONFIG_BT_AICS_MAX_INSTANCE_COUNT */
#define AICS_CCCD_COUNT 0
#endif /* CONFIG_BT_AICS_MAX_INSTANCE_COUNT */
#if CONFIG_BT_HAS_FEATURES_NOTIFIABLE
#define HAS_FEATURES_CCCD_COUNT 1
#else /* CONFIG_BT_HAS_FEATURES_NOTIFIABLE */
#define HAS_FEATURES_CCCD_COUNT 0
#endif /* CONFIG_BT_HAS_FEATURES_NOTIFIABLE */
#if CONFIG_BT_HAS_PRESET_CONTROL_POINT_NOTIFIABLE
#define HAS_PRESET_CONTROL_POINT_CCCD_COUNT 1
#else /* CONFIG_BT_HAS_PRESET_CONTROL_POINT_NOTIFIABLE */
#define HAS_PRESET_CONTROL_POINT_CCCD_COUNT 0
#endif /* CONFIG_BT_HAS_PRESET_CONTROL_POINT_NOTIFIABLE */
#if CONFIG_BT_HAS_ACTIVE_PRESET_INDEX
#define HAS_ACTIVE_PRESET_INDEX_CCCD_COUNT 1
#else /* CONFIG_BT_HAS_ACTIVE_PRESET_INDEX */
#define HAS_ACTIVE_PRESET_INDEX_CCCD_COUNT 0
#endif /* CONFIG_BT_HAS_ACTIVE_PRESET_INDEX */
#if CONFIG_BT_OTS
#define OTS_CCCD_COUNT (CONFIG_BT_OTS_MAX_INST_CNT * 2)
#else /* CONFIG_BT_OTS */
#define OTS_CCCD_COUNT 0
#endif /* CONFIG_BT_OTS */
/* 6 is reserved for other GATT services.
* TODO:
* - OTS
* - MCS (GMCS is used for now)
* - TBS (GTBS is used for now)
*/
#define TOTAL_CCCDS_COUNT (6 + \
(IS_ENABLED(CONFIG_BT_ASCS) ? (1 + ASCS_ASE_SNK_CCCD_COUNT + \
ASCS_ASE_SRC_CCCD_COUNT) : 0) + \
(IS_ENABLED(CONFIG_BT_PACS) ? (PAC_SNK_CCCD_COUNT + PAC_SNK_LOC_CCCD_COUNT + \
PAC_SRC_CCCD_COUNT + PAC_SRC_LOC_CCCD_COUNT + \
1 + PACS_SUPPORTED_CONTEXT_CCCD_COUNT) : 0) + \
(IS_ENABLED(CONFIG_BT_BAP_SCAN_DELEGATOR) ? SCAN_DELEGATOR_RECV_STATE_CCCD_COUNT : 0) + \
(IS_ENABLED(CONFIG_BT_MCS) ? 11 : 0) + \
(IS_ENABLED(CONFIG_BT_CSIP_SET_MEMBER) ? (CSIP_SET_MEMBER_CCCD_COUNT + 2) : 0) + \
(IS_ENABLED(CONFIG_BT_VCP_VOL_REND) ? (1 + VCP_VOL_REND_VOL_FLAGS_CCCD_COUNT) : 0) + \
VOCS_CCCD_COUNT + \
AICS_CCCD_COUNT + \
(IS_ENABLED(CONFIG_BT_TBS) ? 12 : 0) + \
(IS_ENABLED(CONFIG_BT_HAS) ? (HAS_FEATURES_CCCD_COUNT + \
HAS_PRESET_CONTROL_POINT_CCCD_COUNT + \
HAS_ACTIVE_PRESET_INDEX_CCCD_COUNT) : 0) + \
(IS_ENABLED(CONFIG_BT_OTS) ? OTS_CCCD_COUNT : 0))
_Static_assert(TOTAL_CCCDS_COUNT <= CONFIG_BT_NIMBLE_MAX_CCCDS, "Too small BT_NIMBLE_MAX_CCCDS");
int bt_le_nimble_audio_init(void)
{
int err = 0;
err = ble_att_set_preferred_mtu(BLE_AUDIO_ATT_MTU_MIN);
if (err) {
LOG_ERR("[N]SetPrefMtuFail[%d]", err);
return err;
}
ble_svc_gap_init();
ble_svc_gatt_init();
#if CONFIG_BT_PACS
err = bt_le_nimble_pacs_init();
if (err) {
return err;
}
#endif /* CONFIG_BT_PACS */
#if (BLE_AUDIO_SVC_SEP_ADD == 0)
#if CONFIG_BT_ASCS
err = bt_le_nimble_ascs_init();
if (err) {
return err;
}
#endif /* CONFIG_BT_ASCS */
#if CONFIG_BT_BAP_SCAN_DELEGATOR
err = bt_le_nimble_bass_init();
if (err) {
return err;
}
#endif /* CONFIG_BT_BAP_SCAN_DELEGATOR */
#if CONFIG_BT_TMAP
err = bt_le_nimble_tmas_init();
if (err) {
return err;
}
#endif /* CONFIG_BT_TMAP */
#if CONFIG_BT_TBS
err = bt_le_nimble_gtbs_init();
if (err) {
return err;
}
#endif /* CONFIG_BT_TBS */
#if CONFIG_BT_HAS
err = bt_le_nimble_has_init();
if (err) {
return err;
}
#endif /* CONFIG_BT_HAS */
#endif /* (BLE_AUDIO_SVC_SEP_ADD == 0) */
return err;
}
static int nimble_gatt_attr_handle_set(void)
{
int err = 0;
#if CONFIG_BT_ASCS
err = bt_le_nimble_ascs_attr_handle_set();
if (err) {
return err;
}
#endif /* CONFIG_BT_ASCS */
#if CONFIG_BT_PACS
err = bt_le_nimble_pacs_attr_handle_set();
if (err) {
return err;
}
#endif /* CONFIG_BT_PACS */
#if CONFIG_BT_BAP_SCAN_DELEGATOR
err = bt_le_nimble_bass_attr_handle_set();
if (err) {
return err;
}
#endif /* CONFIG_BT_BAP_SCAN_DELEGATOR */
#if CONFIG_BT_CAP_ACCEPTOR
err = bt_le_nimble_cas_attr_handle_set();
if (err) {
return err;
}
#endif /* CONFIG_BT_CAP_ACCEPTOR */
#if CONFIG_BT_TMAP
err = bt_le_nimble_tmas_attr_handle_set();
if (err) {
return err;
}
#endif /* CONFIG_BT_TMAP */
#if CONFIG_BT_CSIP_SET_MEMBER
err = bt_le_nimble_csis_attr_handle_set();
if (err) {
return err;
}
#endif /* CONFIG_BT_CSIP_SET_MEMBER */
#if CONFIG_BT_VCP_VOL_REND
err = bt_le_nimble_vcs_attr_handle_set();
if (err) {
return err;
}
#endif /* CONFIG_BT_VCP_VOL_REND */
#if CONFIG_BT_MICP_MIC_DEV
err = bt_le_nimble_mics_attr_handle_set();
if (err) {
return err;
}
#endif /* CONFIG_BT_MICP_MIC_DEV */
#if CONFIG_BT_MCS
err = bt_le_nimble_gmcs_attr_handle_set();
if (err) {
return err;
}
#endif /* CONFIG_BT_MCS */
#if CONFIG_BT_TBS
err = bt_le_nimble_gtbs_attr_handle_set();
if (err) {
return err;
}
#endif /* CONFIG_BT_TBS */
#if CONFIG_BT_HAS
err = bt_le_nimble_has_attr_handle_set();
if (err) {
return err;
}
#endif /* CONFIG_BT_HAS */
return err;
}
#if CONFIG_BT_CSIP_SET_MEMBER
static int nimble_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);
assert(csis_svc[count]);
if (info->csis_insts[i].included_by_cas) {
if (*inc_csis_svc == NULL) {
*inc_csis_svc = csis_svc[count];
} else {
assert(0);
}
}
count++;
}
err = bt_le_nimble_csis_init(csis_svc, count);
if (err) {
return err;
}
return 0;
}
#endif /* CONFIG_BT_CSIP_SET_MEMBER */
#if CONFIG_BT_MCS
int bt_le_nimble_media_proxy_pl_init(void)
{
/* Note:
* Currently the existence of some characteristics within GMCS
* are determined by the enabling of OTS.
*/
#if CONFIG_BT_OTS
return bt_le_nimble_gmcs_init(true);
#else /* CONFIG_BT_OTS */
return bt_le_nimble_gmcs_init(false);
#endif /* CONFIG_BT_OTS */
}
#endif /* CONFIG_BT_MCS */
#if CONFIG_BT_VCP_VOL_REND
int bt_le_nimble_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_nimble_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_nimble_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_nimble_mics_init(&micp_included);
if (err) {
return err;
}
return 0;
}
#endif /* CONFIG_BT_MICP_MIC_DEV */
int bt_le_nimble_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 = nimble_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_nimble_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_SEP_ADD == 0)
#if CONFIG_BT_MCS
err = bt_le_nimble_media_proxy_pl_init();
if (err) {
return err;
}
#endif /* CONFIG_BT_MCS */
#if CONFIG_BT_VCP_VOL_REND
err = bt_le_nimble_vcp_vol_rend_init();
if (err) {
return err;
}
#endif /* CONFIG_BT_VCP_VOL_REND */
#if CONFIG_BT_MICP_MIC_DEV
err = bt_le_nimble_micp_mic_dev_init();
if (err) {
return err;
}
#endif /* CONFIG_BT_MICP_MIC_DEV */
#endif /* (BLE_AUDIO_SVC_SEP_ADD == 0) */
err = ble_gatts_start();
if (err) {
LOG_ERR("[N]GattsStartFail[%d]", err);
return err;
}
err = nimble_gatt_attr_handle_set();
if (err) {
return err;
}
return err;
}
@@ -0,0 +1,42 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef HOST_NIMBLE_INIT_H_
#define HOST_NIMBLE_INIT_H_
#include <stdint.h>
#include "nimble/profiles/ascs.h"
#include "nimble/profiles/bass.h"
#include "nimble/profiles/cas.h"
#include "nimble/profiles/csis.h"
#include "nimble/profiles/mcs.h"
#include "nimble/profiles/mics.h"
#include "nimble/profiles/pacs.h"
#include "nimble/profiles/tbs.h"
#include "nimble/profiles/tmas.h"
#include "nimble/profiles/vcs.h"
#include "nimble/profiles/has.h"
#ifdef __cplusplus
extern "C" {
#endif
int bt_le_nimble_audio_init(void);
int bt_le_nimble_media_proxy_pl_init(void);
int bt_le_nimble_vcp_vol_rend_init(void);
int bt_le_nimble_micp_mic_dev_init(void);
int bt_le_nimble_audio_start(void *info);
#ifdef __cplusplus
}
#endif
#endif /* HOST_NIMBLE_INIT_H_ */
@@ -0,0 +1,861 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdint.h>
#include <string.h>
#include <errno.h>
#include <zephyr/logging/log.h>
#include <../host/conn_internal.h>
#include <../host/iso_internal.h>
#include "../src/ble_hs_priv.h"
#include "host/ble_hs_iso.h"
#include "host/ble_hs_iso_hci.h"
#include "common/host.h"
extern int ble_hs_iso_evt_rx_cb_set(void *cb);
#if CONFIG_BT_ISO_RX
extern int ble_hs_iso_pkt_rx_cb_set(ble_hs_iso_pkt_rx_fn cb);
#endif /* CONFIG_BT_ISO_RX */
static int hci_cmd_read_iso_tx_sync(struct net_buf *buf, struct net_buf **rsp)
{
uint16_t packet_seq_num = 0;
uint32_t tx_time_stamp = 0;
uint32_t time_offset = 0;
uint16_t conn_handle;
int status;
assert(rsp);
assert(buf->len >= 5);
conn_handle = sys_get_le16(buf->data + 3);
ble_hs_lock();
status = ble_hs_hci_read_iso_tx_sync(conn_handle,
&packet_seq_num,
&tx_time_stamp,
&time_offset);
if (status) {
LOG_ERR("[N]RdIsoTxSyncFail[%u][%02x]", conn_handle, status);
}
ble_hs_unlock();
if (status) {
net_buf_unref(buf);
*rsp = NULL;
} else {
net_buf_reset(buf);
net_buf_add_u8(buf, status);
net_buf_add_le16(buf, conn_handle);
net_buf_add_le16(buf, packet_seq_num);
net_buf_add_le32(buf, tx_time_stamp);
net_buf_add_le24(buf, time_offset);
*rsp = buf;
}
return status;
}
static int hci_cmd_set_cig_params(struct net_buf *buf, struct net_buf **rsp)
{
struct ble_hci_le_cis_params *cis_params = NULL;
uint32_t sdu_interval_c_to_p;
uint32_t sdu_interval_p_to_c;
uint8_t worst_case_sca;
uint16_t mtl_c_to_p;
uint16_t mtl_p_to_c;
uint8_t cis_count;
uint8_t packing;
uint8_t framing;
uint8_t cig_id;
uint8_t rp_len;
uint8_t *rp;
int status;
assert(rsp);
assert(buf->len >= 18);
cig_id = buf->data[3];
sdu_interval_c_to_p = sys_get_le24(buf->data + 4);
sdu_interval_p_to_c = sys_get_le24(buf->data + 7);
worst_case_sca = buf->data[10];
packing = buf->data[11];
framing = buf->data[12];
mtl_c_to_p = sys_get_le16(buf->data + 13);
mtl_p_to_c = sys_get_le16(buf->data + 15);
cis_count = buf->data[17];
assert(buf->len >= 18 + cis_count * sizeof(struct ble_hci_le_cis_params));
/* The cis_count can be 0 */
if (cis_count) {
cis_params = calloc(1, cis_count * sizeof(struct ble_hci_le_cis_params));
assert(cis_params);
}
rp_len = sizeof(struct ble_hci_le_set_cig_params_rp) + cis_count * 2;
rp = calloc(1, rp_len);
assert(rp);
for (size_t i = 0; i < cis_count; i++) {
cis_params[i].cis_id = buf->data[18 + i * sizeof(struct ble_hci_le_cis_params)];
cis_params[i].max_sdu_c_to_p = sys_get_le16(buf->data + 19 + i * sizeof(struct ble_hci_le_cis_params));
cis_params[i].max_sdu_p_to_c = sys_get_le16(buf->data + 21 + i * sizeof(struct ble_hci_le_cis_params));
cis_params[i].phy_c_to_p = buf->data[23 + i * sizeof(struct ble_hci_le_cis_params)];
cis_params[i].phy_p_to_c = buf->data[24 + i * sizeof(struct ble_hci_le_cis_params)];
cis_params[i].rtn_c_to_p = buf->data[25 + i * sizeof(struct ble_hci_le_cis_params)];
cis_params[i].rtn_p_to_c = buf->data[26 + i * sizeof(struct ble_hci_le_cis_params)];
}
ble_hs_lock();
status = ble_hs_hci_set_cig_params(cig_id,
sdu_interval_c_to_p,
sdu_interval_p_to_c,
worst_case_sca,
packing,
framing,
mtl_c_to_p,
mtl_p_to_c,
cis_count,
cis_params,
rp,
rp_len);
if (status) {
LOG_ERR("[N]SetCigParamsFail[%u][%02x]", cig_id, status);
}
ble_hs_unlock();
if (status) {
net_buf_unref(buf);
*rsp = NULL;
} else {
net_buf_reset(buf);
net_buf_add_u8(buf, status);
net_buf_add_u8(buf, rp[0]);
net_buf_add_u8(buf, rp[1]);
for (size_t i = 0; i < cis_count; i++) {
net_buf_add_le16(buf, sys_get_le16(rp + sizeof(struct ble_hci_le_set_cig_params_rp) + i * 2));
}
*rsp = buf;
}
free(cis_params);
free(rp);
return status;
}
static int hci_cmd_set_cig_params_test(struct net_buf *buf, struct net_buf **rsp)
{
struct ble_hci_le_cis_params_test *cis_params = NULL;
uint32_t sdu_interval_c_to_p;
uint32_t sdu_interval_p_to_c;
uint8_t worst_case_sca;
uint16_t iso_interval;
uint8_t ft_c_to_p;
uint8_t ft_p_to_c;
uint8_t cis_count;
uint8_t packing;
uint8_t framing;
uint8_t cig_id;
uint8_t rp_len;
uint8_t *rp;
int status;
assert(rsp);
assert(buf->len >= 18);
cig_id = buf->data[3];
sdu_interval_c_to_p = sys_get_le24(buf->data + 4);
sdu_interval_p_to_c = sys_get_le24(buf->data + 7);
ft_c_to_p = buf->data[10];
ft_p_to_c = buf->data[11];
iso_interval = sys_get_le16(buf->data + 12);
worst_case_sca = buf->data[14];
packing = buf->data[15];
framing = buf->data[16];
cis_count = buf->data[17];
assert(buf->len >= 18 + cis_count * sizeof(struct ble_hci_le_cis_params_test));
/* The cis_count can be 0 */
if (cis_count) {
cis_params = calloc(1, cis_count * sizeof(struct ble_hci_le_cis_params_test));
assert(cis_params);
}
rp_len = sizeof(struct ble_hci_le_set_cig_params_test_rp) + cis_count * 2;
rp = calloc(1, rp_len);
assert(rp);
for (size_t i = 0; i < cis_count; i++) {
cis_params[i].cis_id = buf->data[18 + i * sizeof(struct ble_hci_le_cis_params_test)];
cis_params[i].nse = buf->data[19 + i * sizeof(struct ble_hci_le_cis_params_test)];
cis_params[i].max_sdu_c_to_p = sys_get_le16(buf->data + 20 + i * sizeof(struct ble_hci_le_cis_params_test));
cis_params[i].max_sdu_p_to_c = sys_get_le16(buf->data + 22 + i * sizeof(struct ble_hci_le_cis_params_test));
cis_params[i].max_pdu_c_to_p = sys_get_le16(buf->data + 24 + i * sizeof(struct ble_hci_le_cis_params_test));
cis_params[i].max_pdu_p_to_c = sys_get_le16(buf->data + 26 + i * sizeof(struct ble_hci_le_cis_params_test));
cis_params[i].phy_c_to_p = buf->data[28 + i * sizeof(struct ble_hci_le_cis_params_test)];
cis_params[i].phy_p_to_c = buf->data[29 + i * sizeof(struct ble_hci_le_cis_params_test)];
cis_params[i].bn_c_to_p = buf->data[30 + i * sizeof(struct ble_hci_le_cis_params_test)];
cis_params[i].bn_p_to_c = buf->data[31 + i * sizeof(struct ble_hci_le_cis_params_test)];
}
ble_hs_lock();
status = ble_hs_hci_set_cig_params_test(cig_id,
sdu_interval_c_to_p,
sdu_interval_p_to_c,
ft_c_to_p,
ft_p_to_c,
iso_interval,
worst_case_sca,
packing,
framing,
cis_count,
cis_params,
rp,
rp_len);
if (status) {
LOG_ERR("[N]SetCigParamsTestFail[%u][%02x]", cig_id, status);
}
ble_hs_unlock();
if (status) {
net_buf_unref(buf);
*rsp = NULL;
} else {
net_buf_reset(buf);
net_buf_add_u8(buf, status);
net_buf_add_u8(buf, rp[0]);
net_buf_add_u8(buf, rp[1]);
for (size_t i = 0; i < cis_count; i++) {
net_buf_add_le16(buf, sys_get_le16(rp + sizeof(struct ble_hci_le_set_cig_params_test_rp) + i * 2));
}
*rsp = buf;
}
free(cis_params);
free(rp);
return status;
}
static int hci_cmd_create_cis(struct net_buf *buf, struct net_buf **rsp)
{
struct ble_hci_le_create_cis_params *cis_params;
uint8_t cis_count;
int status;
ARG_UNUSED(rsp);
assert(buf->len >= 4);
/* The cis_count shall be at least 1 */
cis_count = buf->data[3];
assert(buf->len >= 4 + cis_count * sizeof(struct ble_hci_le_create_cis_params));
cis_params = calloc(1, cis_count * sizeof(struct ble_hci_le_create_cis_params));
assert(cis_params);
for (size_t i = 0; i < cis_count; i++) {
cis_params[i].cis_handle = sys_get_le16(buf->data + 4 + i * sizeof(struct ble_hci_le_create_cis_params));
cis_params[i].conn_handle = sys_get_le16(buf->data + 6 + i * sizeof(struct ble_hci_le_create_cis_params));
}
ble_hs_lock();
status = ble_hs_hci_create_cis(cis_count, cis_params);
if (status) {
LOG_ERR("[N]CreateCisFail[%u][%02x]", cis_count, status);
}
ble_hs_unlock();
net_buf_unref(buf);
free(cis_params);
return status;
}
static int hci_cmd_remove_cig(struct net_buf *buf, struct net_buf **rsp)
{
uint8_t cig_id;
int status;
ARG_UNUSED(rsp);
assert(buf->len >= 4);
cig_id = buf->data[3];
ble_hs_lock();
status = ble_hs_hci_remove_cig(cig_id);
if (status) {
LOG_ERR("[N]RemoveCigFail[%u][%02x]", cig_id, status);
}
ble_hs_unlock();
net_buf_unref(buf);
return status;
}
static int hci_cmd_accept_cis_req(struct net_buf *buf, struct net_buf **rsp)
{
uint16_t cis_handle;
int status;
ARG_UNUSED(rsp);
assert(buf->len >= 5);
cis_handle = sys_get_le16(buf->data + 3);
ble_hs_lock();
status = ble_hs_hci_accept_cis_request(cis_handle);
if (status) {
LOG_ERR("[N]AcceptCisReqFail[%u][%02x]", cis_handle, status);
}
ble_hs_unlock();
net_buf_unref(buf);
return status;
}
static int hci_cmd_reject_cis_req(struct net_buf *buf, struct net_buf **rsp)
{
uint16_t cis_handle;
uint8_t reason;
int status;
ARG_UNUSED(rsp);
assert(buf->len >= 6);
cis_handle = sys_get_le16(buf->data + 3);
reason = buf->data[5];
ble_hs_lock();
status = ble_hs_hci_reject_cis_request(cis_handle, reason);
if (status) {
LOG_ERR("[N]RejectCisReqFail[%u][%02x]", cis_handle, status);
}
ble_hs_unlock();
net_buf_unref(buf);
return status;
}
static int hci_cmd_create_big(struct net_buf *buf, struct net_buf **rsp)
{
uint8_t big_handle;
uint8_t adv_handle;
uint8_t num_bis;
uint32_t sdu_interval;
uint16_t max_sdu;
uint16_t mtl;
uint8_t rtn;
uint8_t phy;
uint8_t packing;
uint8_t framing;
uint8_t encryption;
uint8_t *bst_code;
int status;
ARG_UNUSED(rsp);
assert(buf->len >= 34);
big_handle = buf->data[3];
adv_handle = buf->data[4];
num_bis = buf->data[5];
sdu_interval = sys_get_le24(buf->data + 6);
max_sdu = sys_get_le16(buf->data + 9);
mtl = sys_get_le16(buf->data + 11);
rtn = buf->data[13];
phy = buf->data[14];
packing = buf->data[15];
framing = buf->data[16];
encryption = buf->data[17];
bst_code = buf->data + 18;
ble_hs_lock();
status = ble_hs_hci_create_big(big_handle,
adv_handle,
num_bis,
sdu_interval,
max_sdu,
mtl,
rtn,
phy,
packing,
framing,
encryption,
bst_code);
if (status) {
LOG_ERR("[N]CreateBigFail[%u][%02x]", big_handle, status);
}
ble_hs_unlock();
net_buf_unref(buf);
return status;
}
static int hci_cmd_create_big_test(struct net_buf *buf, struct net_buf **rsp)
{
uint8_t big_handle;
uint8_t adv_handle;
uint8_t num_bis;
uint32_t sdu_interval;
uint16_t iso_interval;
uint16_t max_sdu;
uint16_t max_pdu;
uint8_t nse;
uint8_t phy;
uint8_t packing;
uint8_t framing;
uint8_t bn;
uint8_t irc;
uint8_t pto;
uint8_t encryption;
uint8_t *bst_code;
int status;
ARG_UNUSED(rsp);
assert(buf->len >= 39);
big_handle = buf->data[3];
adv_handle = buf->data[4];
num_bis = buf->data[5];
sdu_interval = sys_get_le24(buf->data + 6);
iso_interval = sys_get_le16(buf->data + 9);
nse = buf->data[11];
max_sdu = sys_get_le16(buf->data + 12);
max_pdu = sys_get_le16(buf->data + 14);
phy = buf->data[16];
packing = buf->data[17];
framing = buf->data[18];
bn = buf->data[19];
irc = buf->data[20];
pto = buf->data[21];
encryption = buf->data[22];
bst_code = buf->data + 23;
ble_hs_lock();
status = ble_hs_hci_create_big_test(big_handle,
adv_handle,
num_bis,
sdu_interval,
iso_interval,
nse,
max_sdu,
max_pdu,
phy,
packing,
framing,
bn,
irc,
pto,
encryption,
bst_code);
if (status) {
LOG_ERR("[N]CreateBigTestFail[%u][%02x]", big_handle, status);
}
ble_hs_unlock();
net_buf_unref(buf);
return status;
}
static int hci_cmd_terminate_big(struct net_buf *buf, struct net_buf **rsp)
{
uint8_t big_handle;
uint8_t reason;
int status;
ARG_UNUSED(rsp);
assert(buf->len >= 5);
big_handle = buf->data[3];
reason = buf->data[4];
ble_hs_lock();
status = ble_hs_hci_terminate_big(big_handle, reason);
if (status) {
LOG_ERR("[N]TerminateBigFail[%u][%02x]", big_handle, status);
}
ble_hs_unlock();
net_buf_unref(buf);
return status;
}
static int hci_cmd_big_create_sync(struct net_buf *buf, struct net_buf **rsp)
{
uint16_t sync_timeout;
uint16_t sync_handle;
uint8_t big_handle;
uint8_t encryption;
uint8_t *bst_code;
uint8_t num_bis;
uint8_t *bis;
uint8_t mse;
int status;
ARG_UNUSED(rsp);
assert(buf->len >= 27);
big_handle = buf->data[3];
sync_handle = sys_get_le16(buf->data + 4);
encryption = buf->data[6];
bst_code = buf->data + 7;
mse = buf->data[23];
sync_timeout = sys_get_le16(buf->data + 24);
num_bis = buf->data[26];
bis = buf->data + 27;
assert(buf->len >= 27 + num_bis);
ble_hs_lock();
status = ble_hs_hci_big_create_sync(big_handle,
sync_handle,
encryption,
bst_code,
mse,
sync_timeout,
num_bis,
bis);
if (status) {
LOG_ERR("[N]BigCreateSyncFail[%u][%02x]", big_handle, status);
}
ble_hs_unlock();
net_buf_unref(buf);
return status;
}
static int hci_cmd_big_terminate_sync(struct net_buf *buf, struct net_buf **rsp)
{
uint8_t big_handle;
int status;
assert(rsp);
assert(buf->len >= 4);
big_handle = buf->data[3];
ble_hs_lock();
status = ble_hs_hci_big_terminate_sync(big_handle);
if (status) {
LOG_ERR("[N]BigTerminateSyncFail[%u][%02x]", big_handle, status);
}
ble_hs_unlock();
if (status) {
net_buf_unref(buf);
*rsp = NULL;
} else {
net_buf_reset(buf);
net_buf_add_u8(buf, status);
net_buf_add_u8(buf, big_handle);
*rsp = buf;
}
return status;
}
static int hci_cmd_setup_iso_data_path(struct net_buf *buf, struct net_buf **rsp)
{
uint8_t data_path_direction;
uint32_t controller_delay;
uint16_t conn_handle;
uint8_t data_path_id;
uint8_t coding_format;
uint16_t company_id;
uint16_t vs_codec_id;
uint8_t codec_cfg_len;
uint8_t *codec_cfg;
int status;
assert(rsp);
assert(buf->len >= 16);
conn_handle = sys_get_le16(buf->data + 3);
data_path_direction = buf->data[5];
data_path_id = buf->data[6];
coding_format = buf->data[7];
company_id = sys_get_le16(buf->data + 8);
vs_codec_id = sys_get_le16(buf->data + 10);
controller_delay = sys_get_le24(buf->data + 12);
codec_cfg_len = buf->data[15];
codec_cfg = buf->data + 16;
assert(buf->len >= 16 + codec_cfg_len);
ble_hs_lock();
status = ble_hs_hci_setup_iso_data_path(conn_handle,
data_path_direction,
data_path_id,
coding_format,
company_id,
vs_codec_id,
controller_delay,
codec_cfg_len,
codec_cfg);
if (status) {
LOG_ERR("[N]SetupIsoDataPathFail[%u][%02x]", conn_handle, status);
}
ble_hs_unlock();
if (status) {
net_buf_unref(buf);
*rsp = NULL;
} else {
net_buf_reset(buf);
net_buf_add_u8(buf, status);
net_buf_add_le16(buf, conn_handle);
*rsp = buf;
}
return status;
}
static int hci_cmd_remove_iso_data_path(struct net_buf *buf, struct net_buf **rsp)
{
uint8_t data_path_direction;
uint16_t conn_handle;
int status;
assert(rsp);
assert(buf->len >= 6);
conn_handle = sys_get_le16(buf->data + 3);
data_path_direction = buf->data[5];
ble_hs_lock();
status = ble_hs_hci_remove_iso_data_path(conn_handle, data_path_direction);
if (status) {
LOG_ERR("[N]RemoveIsoDataPathFail[%u][%02x]", conn_handle, status);
}
ble_hs_unlock();
if (status) {
net_buf_unref(buf);
*rsp = NULL;
} else {
net_buf_reset(buf);
net_buf_add_u8(buf, status);
net_buf_add_le16(buf, conn_handle);
*rsp = buf;
}
return status;
}
int bt_le_nimble_iso_cmd_send_sync(uint16_t opcode,
struct net_buf *buf,
struct net_buf **rsp)
{
switch (opcode) {
case BT_HCI_OP_LE_READ_ISO_TX_SYNC:
return hci_cmd_read_iso_tx_sync(buf, rsp);
case BT_HCI_OP_LE_SET_CIG_PARAMS:
return hci_cmd_set_cig_params(buf, rsp);
case BT_HCI_OP_LE_SET_CIG_PARAMS_TEST:
return hci_cmd_set_cig_params_test(buf, rsp);
case BT_HCI_OP_LE_CREATE_CIS:
return hci_cmd_create_cis(buf, rsp);
case BT_HCI_OP_LE_REMOVE_CIG:
return hci_cmd_remove_cig(buf, rsp);
case BT_HCI_OP_LE_ACCEPT_CIS:
return hci_cmd_accept_cis_req(buf, rsp);
case BT_HCI_OP_LE_REJECT_CIS:
return hci_cmd_reject_cis_req(buf, rsp);
case BT_HCI_OP_LE_CREATE_BIG:
return hci_cmd_create_big(buf, rsp);
case BT_HCI_OP_LE_CREATE_BIG_TEST:
return hci_cmd_create_big_test(buf, rsp);
case BT_HCI_OP_LE_TERMINATE_BIG:
return hci_cmd_terminate_big(buf, rsp);
case BT_HCI_OP_LE_BIG_CREATE_SYNC:
return hci_cmd_big_create_sync(buf, rsp);
case BT_HCI_OP_LE_BIG_TERMINATE_SYNC:
return hci_cmd_big_terminate_sync(buf, rsp);
case BT_HCI_OP_LE_SETUP_ISO_PATH:
return hci_cmd_setup_iso_data_path(buf, rsp);
case BT_HCI_OP_LE_REMOVE_ISO_PATH:
return hci_cmd_remove_iso_data_path(buf, rsp);
default:
LOG_ERR("[N]IsoCmdNotSupp[%04x]", opcode);
net_buf_unref(buf);
return -ENOTSUP;
}
}
static void iso_evt_rx(uint8_t event, const void *data,
unsigned int len, bool le_meta)
{
size_t qdata_len;
uint8_t *qdata;
int err;
if (event != BT_HCI_EVT_LE_BIGINFO_ADV_REPORT) {
LOG_DBG("[N]ISOEvtRx[%02x][%u][%u]", event, len, le_meta);
}
qdata_len = len + 2;
qdata = calloc(1, qdata_len);
assert(qdata);
qdata[0] = le_meta;
qdata[1] = event;
memcpy(qdata + 2, data, len);
err = bt_le_iso_task_post(ISO_QUEUE_ITEM_TYPE_ISO_HCI_EVENT, qdata, qdata_len);
if (err) {
LOG_ERR("[N]IsoPostEvtFail[%d][%02x]", err, event);
free(qdata);
}
}
#if CONFIG_BT_ISO_UNICAST
static int iso_enable_cis(void)
{
int err;
ble_hs_lock();
err = ble_hs_hci_set_host_feature(32, 1);
if (err) {
LOG_ERR("[N]IsoEnableCisFail[%d]", err);
}
ble_hs_unlock();
return err;
}
static int iso_disable_cis(void)
{
int err;
ble_hs_lock();
err = ble_hs_hci_set_host_feature(32, 0);
if (err) {
LOG_ERR("[N]IsoDisableCisFail[%d]", err);
}
ble_hs_unlock();
return err;
}
#endif /* CONFIG_BT_ISO_UNICAST */
int bt_le_nimble_iso_init(void)
{
int err;
err = ble_hs_iso_evt_rx_cb_set(iso_evt_rx);
if (err) {
LOG_ERR("[N]IsoEvtRxCbSetFail[%d]", err);
return err;
}
#if CONFIG_BT_ISO_RX
err = ble_hs_iso_pkt_rx_cb_set(bt_le_iso_rx);
if (err) {
LOG_ERR("[N]IsoPktRxCbSetFail[%d]", err);
return err;
}
#endif /* CONFIG_BT_ISO_RX */
#if CONFIG_BT_ISO_UNICAST
/* Set Connected Isochronous Streams - Host support */
err = iso_enable_cis();
if (err) {
return err;
}
#endif /* CONFIG_BT_ISO_UNICAST */
return 0;
}
void bt_le_nimble_iso_deinit(void)
{
LOG_DBG("IsoDeinit");
ble_hs_iso_evt_rx_cb_set(NULL);
#if CONFIG_BT_ISO_RX
ble_hs_iso_pkt_rx_cb_set(NULL);
#endif /* CONFIG_BT_ISO_RX */
#if CONFIG_BT_ISO_UNICAST
iso_disable_cis();
#endif /* CONFIG_BT_ISO_UNICAST */
}
@@ -0,0 +1,28 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef HOST_NIMBLE_ISO_H_
#define HOST_NIMBLE_ISO_H_
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
int bt_le_nimble_iso_cmd_send_sync(uint16_t opcode,
struct net_buf *buf,
struct net_buf **rsp);
int bt_le_nimble_iso_init(void);
void bt_le_nimble_iso_deinit(void);
#ifdef __cplusplus
}
#endif
#endif /* HOST_NIMBLE_ISO_H_ */
@@ -0,0 +1,322 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#include <errno.h>
#include <assert.h>
#include <zephyr/kernel.h>
#include <zephyr/logging/log.h>
#include <zephyr/bluetooth/l2cap.h>
#include <../host/conn_internal.h>
#include "host/ble_hs.h"
#include "host/ble_l2cap.h"
#include "host/ble_hs_mbuf.h"
#include "../../../nimble/host/src/ble_l2cap_priv.h"
#include "common/host.h"
_Static_assert(CONFIG_BT_NIMBLE_L2CAP_COC_MAX_NUM && "At least one L2CAP coc shall be supported");
#define OTS_L2CAP_BUF_COUNT (3 * CONFIG_BT_NIMBLE_L2CAP_COC_MAX_NUM)
#define OTS_L2CAP_MEM_SIZE OS_MEMPOOL_SIZE(OTS_L2CAP_BUF_COUNT, L2CAP_LE_OTS_MTU * 2)
static os_membuf_t ots_mem[OTS_L2CAP_MEM_SIZE];
static struct os_mempool ots_mbuf_mempool;
static struct os_mbuf_pool ots_mbuf_pool;
static struct ble_l2cap_chan *ots_chan;
static int ots_l2cap_recv_ready(struct ble_l2cap_chan *chan)
{
struct os_mbuf *sdu_rx;
int rc;
LOG_DBG("[N]OtsRecvReady");
sdu_rx = os_mbuf_get_pkthdr(&ots_mbuf_pool, 0);
if (sdu_rx == NULL) {
LOG_ERR("[N]NoBufForL2capRecv");
return -ENOMEM;
}
rc = ble_l2cap_recv_ready(chan, sdu_rx);
if (rc) {
LOG_ERR("[N]L2capRecvFail[%d]", rc);
os_mbuf_free_chain(sdu_rx);
return rc;
}
return 0;
}
static int ots_l2cap_event_cb(struct ble_l2cap_event *event, void *arg)
{
struct ble_l2cap_chan_info chan_info;
uint16_t result = 0;
size_t sdu_len;
uint8_t *sdu;
int err;
LOG_DBG("[N]OtsEvtCb[%u]", event->type);
switch (event->type) {
case BLE_L2CAP_EVENT_COC_CONNECTED:
if (event->connect.status) {
LOG_ERR("[N]CocConnectFail[%d]", event->connect.status);
return 0;
}
if (ots_chan) {
LOG_ERR("[N]CocChanExist");
return 0;
}
ots_chan = event->connect.chan;
if (ble_l2cap_get_chan_info(event->connect.chan, &chan_info)) {
assert(0);
}
LOG_DBG("[N]CocConnect[%u][%04x][%04x][%04x][%u][%u][%u][%u]",
event->connect.conn_handle, chan_info.scid, chan_info.dcid,
chan_info.psm, chan_info.our_l2cap_mtu, chan_info.peer_l2cap_mtu,
chan_info.our_coc_mtu, chan_info.peer_coc_mtu);
bt_le_l2cap_connected(event->connect.conn_handle, chan_info.psm,
chan_info.dcid, chan_info.peer_coc_mtu,
chan_info.scid, chan_info.our_coc_mtu);
return 0;
case BLE_L2CAP_EVENT_COC_DISCONNECTED:
if (ots_chan != event->disconnect.chan) {
LOG_ERR("[N]DisconnectInvCocChan");
return 0;
}
LOG_DBG("[N]CocDisconnect[%u][%04x]",
event->disconnect.conn_handle, event->disconnect.chan->psm);
bt_le_l2cap_disconnected(event->disconnect.conn_handle, event->disconnect.chan->psm);
ots_chan = NULL;
return 0;
case BLE_L2CAP_EVENT_COC_ACCEPT:
if (event->accept.peer_sdu_size > L2CAP_LE_OTS_MTU) {
LOG_ERR("[N]InvAcceptMtu[%u][%u]",
event->accept.peer_sdu_size, L2CAP_LE_OTS_MTU);
return -EINVAL;
}
LOG_DBG("[N]CocAccept[%u][%04x][%04x][%u][%u][%u][%u]",
event->accept.conn_handle, event->accept.chan->psm,
event->accept.chan->dcid, event->accept.chan->coc_tx.mtu,
event->accept.chan->peer_coc_mps, event->accept.peer_sdu_size,
event->accept.chan->coc_tx.credits);
err = bt_le_l2cap_accept(event->accept.conn_handle,
event->accept.chan->psm,
event->accept.chan->dcid,
event->accept.chan->coc_tx.mtu,
event->accept.chan->peer_coc_mps,
event->accept.chan->coc_tx.credits,
&result);
if (err) {
return err;
}
ARG_UNUSED(result);
return ots_l2cap_recv_ready(event->accept.chan);
case BLE_L2CAP_EVENT_COC_DATA_RECEIVED:
if (ots_chan != event->receive.chan) {
LOG_ERR("[N]RecvOnInvCocChan");
return 0;
}
assert(event->receive.sdu_rx);
LOG_DBG("[N]CocReceive[%u][%04x][%u]",
event->receive.conn_handle, event->receive.chan->psm,
event->receive.sdu_rx->om_len);
sdu_len = OS_MBUF_PKTLEN(event->receive.sdu_rx);
sdu = calloc(1, sdu_len);
assert(sdu);
err = os_mbuf_copydata(event->receive.sdu_rx, 0, sdu_len, sdu);
assert(err == 0);
bt_le_l2cap_received(event->receive.conn_handle,
event->receive.chan->psm,
sdu, sdu_len);
os_mbuf_free_chain(event->receive.sdu_rx);
free(sdu);
return ots_l2cap_recv_ready(event->receive.chan);
case BLE_L2CAP_EVENT_COC_TX_UNSTALLED:
if (ots_chan != event->tx_unstalled.chan) {
LOG_ERR("[N]TxUnstalledOnInvCocChan");
return 0;
}
LOG_DBG("[N]CocTxUnstalled[%u][%d]",
event->tx_unstalled.conn_handle, event->tx_unstalled.status);
/* TODO: transmit the remaining data */
return 0;
default:
return 0;
}
}
int bt_le_nimble_l2cap_chan_connect(uint16_t conn_handle)
{
struct os_mbuf *sdu_rx;
int rc;
if (ots_chan) {
LOG_WRN("[N]OtsChanExist");
return -EALREADY;
}
sdu_rx = os_mbuf_get_pkthdr(&ots_mbuf_pool, 0);
if (sdu_rx == NULL) {
LOG_ERR("[N]NoBufForL2capConnect");
return -ENOMEM;
}
rc = ble_l2cap_connect(conn_handle, L2CAP_LE_OTS_PSM, L2CAP_LE_OTS_MTU,
sdu_rx, ots_l2cap_event_cb, NULL);
if (rc) {
LOG_ERR("[N]L2capConnectFail[%d]", rc);
os_mbuf_free_chain(sdu_rx);
return rc;
}
return 0;
}
int bt_le_nimble_l2cap_chan_disconnect(struct bt_l2cap_chan *chan)
{
int rc;
if (ots_chan == NULL) {
LOG_WRN("[N]NoOtsChan");
return -ENOTCONN;
}
if (ble_l2cap_get_conn_handle(ots_chan) != chan->conn->handle) {
LOG_ERR("[N]UnexpOtsChan[%u][%u]",
ble_l2cap_get_conn_handle(ots_chan), chan->conn->handle);
return -EINVAL;
}
rc = ble_l2cap_disconnect(ots_chan);
if (rc) {
LOG_ERR("[N]L2capDisconnectFail[%d]", rc);
return rc;
}
return 0;
}
int bt_le_nimble_l2cap_chan_send(struct bt_l2cap_chan *chan, struct net_buf *buf)
{
struct os_mbuf *sdu_tx;
int rc;
if (ots_chan == NULL) {
LOG_WRN("[N]NoOtsChan");
return -ENOTCONN;
}
if (ble_l2cap_get_conn_handle(ots_chan) != chan->conn->handle) {
LOG_ERR("[N]UnexpOtsChan[%u][%u]",
ble_l2cap_get_conn_handle(ots_chan), chan->conn->handle);
return -EINVAL;
}
sdu_tx = os_mbuf_get_pkthdr(&ots_mbuf_pool, 0);
if (sdu_tx == NULL) {
LOG_ERR("[N]NoBufForL2capSend");
return -ENOMEM;
}
rc = os_mbuf_append(sdu_tx, buf->data, buf->len);
if (rc) {
LOG_ERR("[N]AppendBufFail[%d]", rc);
os_mbuf_free_chain(sdu_tx);
return -EIO;
}
rc = ble_l2cap_send(ots_chan, sdu_tx);
if (rc) {
if (rc == BLE_HS_ESTALLED) {
/* TODO:
* Wait for the BLE_L2CAP_EVENT_COC_TX_UNSTALLED event and continue.
*/
LOG_WRN("[N]MoreCreditsForL2capSend");
} else {
LOG_ERR("[N]L2capSendFail[%d]", rc);
}
os_mbuf_free_chain(sdu_tx);
return rc;
}
return 0;
}
int bt_le_nimble_l2cap_init(void)
{
int rc;
rc = os_mempool_init(&ots_mbuf_mempool, OTS_L2CAP_BUF_COUNT, L2CAP_LE_OTS_MTU * 2, ots_mem, "ots_pool");
if (rc) {
LOG_ERR("[N]InitOtsMempoolFail[%d]", rc);
return rc;
}
rc = os_mbuf_pool_init(&ots_mbuf_pool, &ots_mbuf_mempool, L2CAP_LE_OTS_MTU, OTS_L2CAP_BUF_COUNT);
if (rc) {
LOG_ERR("[N]InitOtsMbufPoolFail[%d]", rc);
return rc;
}
#if CONFIG_BT_OTS
rc = ble_l2cap_create_server(L2CAP_LE_OTS_PSM, L2CAP_LE_OTS_MTU, ots_l2cap_event_cb, NULL);
if (rc) {
LOG_ERR("[N]CreateL2capSrvFail[%d]", rc);
return rc;
}
#endif /* CONFIG_BT_OTS */
return 0;
}
void bt_le_nimble_l2cap_deinit(void)
{
LOG_DBG("NimbleL2capDeinit");
/* TODO: free the ots_mbuf_pool and ots_mbuf_mempool */
#if CONFIG_BT_OTS
/* TODO: destroy the server */
#endif /* CONFIG_BT_OTS */
}
@@ -0,0 +1,32 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef HOST_NIMBLE_L2CAP_H_
#define HOST_NIMBLE_L2CAP_H_
#include <stdint.h>
#include <zephyr/bluetooth/l2cap.h>
#ifdef __cplusplus
extern "C" {
#endif
int bt_le_nimble_l2cap_chan_connect(uint16_t conn_handle);
int bt_le_nimble_l2cap_chan_disconnect(struct bt_l2cap_chan *chan);
int bt_le_nimble_l2cap_chan_send(struct bt_l2cap_chan *chan, struct net_buf *buf);
int bt_le_nimble_l2cap_init(void);
void bt_le_nimble_l2cap_deinit(void);
#ifdef __cplusplus
}
#endif
#endif /* HOST_NIMBLE_L2CAP_H_ */
@@ -0,0 +1,230 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <assert.h>
#include <stdint.h>
#include <stdbool.h>
#include <errno.h>
#include <stdlib.h>
#include <zephyr/autoconf.h>
#include <zephyr/logging/log.h>
#include <zephyr/bluetooth/uuid.h>
#include <zephyr/bluetooth/gatt.h>
#include <../host/conn_internal.h>
#include "os/os_mbuf.h"
#include "os/os_mempool.h"
#include "host/ble_att.h"
#include "host/ble_gatt.h"
#include "host/ble_hs_mbuf.h"
#include "nimble/profiles/server.h"
#include "common/host.h"
#include "../../../lib/include/audio.h"
static const ble_uuid16_t ascs_uuid_ase_cp = BLE_UUID16_INIT(BT_UUID_ASCS_ASE_CP_VAL);
static const ble_uuid16_t ascs_uuid_ase_snk = BLE_UUID16_INIT(BT_UUID_ASCS_ASE_SNK_VAL);
static const ble_uuid16_t ascs_uuid_ase_src = BLE_UUID16_INIT(BT_UUID_ASCS_ASE_SRC_VAL);
static uint16_t ase_control_point_handle;
static uint16_t ase_snk_handle[CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT];
static uint16_t ase_src_handle[CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT];
static struct ble_gatt_svc_def gatt_svc_ascs[] = {
{
/* Audio Stream Control Service */
.type = BLE_GATT_SVC_TYPE_PRIMARY,
.uuid = BLE_UUID16_DECLARE(BT_UUID_ASCS_VAL),
.includes = NULL,
.characteristics = NULL,
},
{
0, /* No more services. */
},
};
static void ascs_svc_add_ase_cp_chr(struct ble_gatt_chr_def *chr)
{
LOG_DBG("[N]AscsSvcAddAseCpChr");
chr->uuid = &ascs_uuid_ase_cp.u;
chr->access_cb = bt_le_nimble_gatts_access_cb_safe;
chr->arg = NULL;
chr->descriptors = NULL; /* NULL if no descriptors. Do not include CCCD */
chr->flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_WRITE_NO_RSP | \
BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_WRITE_ENC;
chr->min_key_size = 16;
chr->val_handle = &ase_control_point_handle;
}
#if CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT > 0
static void ascs_svc_add_ase_snk_chr(struct ble_gatt_chr_def *chrs)
{
for (size_t i = 0 ; i < CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT; i++) {
struct ble_gatt_chr_def *chr = chrs + i;
LOG_DBG("[N]AscsSvcAddAseSnkChr[%u]", i);
chr->uuid = &ascs_uuid_ase_snk.u;
chr->access_cb = bt_le_nimble_gatts_access_cb_safe;
chr->arg = UINT_TO_POINTER(i);
chr->descriptors = NULL; /* NULL if no descriptors. Do not include CCCD */
chr->flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_READ_ENC;
chr->min_key_size = 16;
chr->val_handle = &ase_snk_handle[i];
}
}
#endif /* CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT > 0 */
#if CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT > 0
static void ascs_svc_add_ase_src_chr(struct ble_gatt_chr_def *chrs)
{
for (size_t i = 0 ; i < CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT; i++) {
struct ble_gatt_chr_def *chr = chrs + i;
LOG_DBG("[N]AscsSvcAddAseSrcChr[%u]", i);
chr->uuid = &ascs_uuid_ase_src.u;
chr->access_cb = bt_le_nimble_gatts_access_cb_safe;
chr->arg = UINT_TO_POINTER(i);
chr->descriptors = NULL; /* NULL if no descriptors. Do not include CCCD */
chr->flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_READ_ENC;
chr->min_key_size = 16;
chr->val_handle = &ase_src_handle[i];
}
}
#endif /* CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT > 0 */
int bt_le_nimble_ascs_attr_handle_set(void)
{
struct bt_gatt_service *ascs_svc;
struct bt_gatt_attr *attr;
uint16_t start_handle;
uint16_t end_handle;
ascs_svc = lib_ascs_svc_get();
assert(ascs_svc);
assert(ase_control_point_handle >= 2);
start_handle = ase_control_point_handle - 2; /* server attr handle & char def handle */
#if CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT > 0
end_handle = ase_src_handle[CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT - 1] + 1; /* cccd attr handle */
#elif CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT > 0
end_handle = ase_snk_handle[CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT - 1] + 1; /* cccd attr handle */
#else
end_handle = ase_control_point_handle + 1; /* cccd attr handle */
#endif
LOG_DBG("[N]AscsAttrHdlSet[%u][%u][%u]",
start_handle, end_handle, ascs_svc->attr_count);
for (size_t i = 0; i < ascs_svc->attr_count; i++) {
(ascs_svc->attrs + i)->handle = start_handle + i;
}
/* Last attribute in ASCS */
attr = ascs_svc->attrs + ascs_svc->attr_count - 1;
if (attr->handle != end_handle) {
LOG_ERR("[N]AscsMismatchAttrHhl[%u][%u][%u][%u]",
start_handle, end_handle, attr->handle, ascs_svc->attr_count);
return -1;
}
return 0;
}
static int ascs_svc_check(void)
{
struct bt_gatt_service *ascs_svc;
const struct bt_uuid_16 *uuid;
bool chr_found;
/* This function is used to make sure the characteristics within
* the service exist in the service defined by Zephyr.
*/
ascs_svc = lib_ascs_svc_get();
assert(ascs_svc);
LOG_DBG("[N]AscsSvcCheck");
for (const struct ble_gatt_chr_def *chr = gatt_svc_ascs[0].characteristics;
chr && chr->uuid; chr++) {
const ble_uuid16_t *check = (const ble_uuid16_t *)chr->uuid;
chr_found = false;
for (size_t i = 0; i < ascs_svc->attr_count; i++) {
uuid = (const struct bt_uuid_16 *)(ascs_svc->attrs + i)->uuid;
if (uuid && uuid->uuid.type == BT_LE_NIMBLE_GATT_UUID_TO_Z(check->u.type) &&
uuid->val == check->value) {
chr_found = true;
break;
}
}
if (chr_found == false) {
LOG_ERR("[N]AscsChrNotFound[%04x]", check->value);
return -1;
}
}
return 0;
}
int bt_le_nimble_ascs_init(void)
{
uint16_t chr_count;
int rc;
/* An additional characteristic consist of all 0s indicating end of characteristics */
chr_count = 1 + CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT + CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT + 1;
LOG_DBG("[N]AscsInit[%u]", chr_count);
gatt_svc_ascs[0].characteristics = calloc(chr_count, sizeof(struct ble_gatt_chr_def));
assert(gatt_svc_ascs[0].characteristics);
ascs_svc_add_ase_cp_chr((void *)(gatt_svc_ascs[0].characteristics + 0));
#if CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT > 0
ascs_svc_add_ase_snk_chr((void *)(gatt_svc_ascs[0].characteristics + 1));
#endif /* CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT > 0 */
#if CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT > 0
ascs_svc_add_ase_src_chr((void *)(gatt_svc_ascs[0].characteristics + 1 + CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT));
#endif /* CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT > 0 */
rc = ble_gatts_count_cfg(gatt_svc_ascs);
if (rc) {
LOG_ERR("[N]AscsCountCfgFail[%d]", rc);
goto free;
}
rc = ble_gatts_add_svcs(gatt_svc_ascs);
if (rc) {
LOG_ERR("[N]AscsAddSvcsFail[%d]", rc);
goto free;
}
rc = ascs_svc_check();
if (rc) {
goto free;
}
return 0;
free:
free((void *)gatt_svc_ascs[0].characteristics);
gatt_svc_ascs[0].characteristics = NULL;
return rc;
}
@@ -0,0 +1,25 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef HOST_NIMBLE_PROFILE_ASCS_H_
#define HOST_NIMBLE_PROFILE_ASCS_H_
#include <stdint.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
int bt_le_nimble_ascs_attr_handle_set(void);
int bt_le_nimble_ascs_init(void);
#ifdef __cplusplus
}
#endif
#endif /* HOST_NIMBLE_PROFILE_ASCS_H_ */
@@ -0,0 +1,194 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <assert.h>
#include <stdint.h>
#include <stdbool.h>
#include <errno.h>
#include <stdlib.h>
#include <zephyr/autoconf.h>
#include <zephyr/logging/log.h>
#include <zephyr/bluetooth/uuid.h>
#include <zephyr/bluetooth/gatt.h>
#include <../host/conn_internal.h>
#include "os/os_mbuf.h"
#include "os/os_mempool.h"
#include "host/ble_att.h"
#include "host/ble_gatt.h"
#include "host/ble_hs_mbuf.h"
#include "nimble/profiles/server.h"
#include "common/host.h"
#include "../../../lib/include/audio.h"
static const ble_uuid16_t bass_uuid_control_point = BLE_UUID16_INIT(BT_UUID_BASS_CONTROL_POINT_VAL);
static const ble_uuid16_t bass_uuid_recv_state = BLE_UUID16_INIT(BT_UUID_BASS_RECV_STATE_VAL);
static uint16_t bass_control_point_handle;
static uint16_t bass_recv_state_handle[CONFIG_BT_BAP_SCAN_DELEGATOR_RECV_STATE_COUNT];
static struct ble_gatt_svc_def gatt_svc_bass[] = {
{
/* Broadcast Audio Scan Service */
.type = BLE_GATT_SVC_TYPE_PRIMARY,
.uuid = BLE_UUID16_DECLARE(BT_UUID_BASS_VAL),
.includes = NULL,
.characteristics = NULL,
},
{
0, /* No more services. */
},
};
static void bass_svc_add_control_point_chr(struct ble_gatt_chr_def *chr)
{
LOG_DBG("[N]BassSvcAddControlPointChr");
chr->uuid = &bass_uuid_control_point.u;
chr->access_cb = bt_le_nimble_gatts_access_cb_safe;
chr->arg = NULL;
chr->descriptors = NULL; /* NULL if no descriptors. Do not include CCCD */
chr->flags = BLE_GATT_CHR_F_WRITE_NO_RSP | BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_WRITE_ENC;
chr->min_key_size = 16;
chr->val_handle = &bass_control_point_handle;
}
static void bass_svc_add_recv_state_chr(struct ble_gatt_chr_def *chrs)
{
for (size_t i = 0 ; i < CONFIG_BT_BAP_SCAN_DELEGATOR_RECV_STATE_COUNT; i++) {
struct ble_gatt_chr_def *chr = chrs + i;
LOG_DBG("[N]BassSvcAddRecvStateChr[%u]", i);
chr->uuid = &bass_uuid_recv_state.u;
chr->access_cb = bt_le_nimble_gatts_access_cb_safe;
chr->arg = UINT_TO_POINTER(i);
chr->descriptors = NULL; /* NULL if no descriptors. Do not include CCCD */
chr->flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_READ_ENC;
chr->min_key_size = 16;
chr->val_handle = &bass_recv_state_handle[i];
}
}
int bt_le_nimble_bass_attr_handle_set(void)
{
struct bt_gatt_service *bass_svc;
struct bt_gatt_attr *attr;
uint16_t start_handle;
uint16_t end_handle;
bass_svc = lib_bap_bass_svc_get();
assert(bass_svc);
assert(bass_control_point_handle >= 2);
start_handle = bass_control_point_handle - 2; /* server attr handle & char def handle */
end_handle = bass_recv_state_handle[CONFIG_BT_BAP_SCAN_DELEGATOR_RECV_STATE_COUNT - 1] + 1; /* cccd attr handle */
LOG_DBG("[N]BassAttrHdlSet[%u][%u][%u]",
start_handle, end_handle, bass_svc->attr_count);
for (size_t i = 0; i < bass_svc->attr_count; i++) {
(bass_svc->attrs + i)->handle = start_handle + i;
}
/* Last attribute in BASS */
attr = bass_svc->attrs + bass_svc->attr_count - 1;
if (attr->handle != end_handle) {
LOG_ERR("[N]BassMismatchAttrHdl[%u][%u][%u][%u]",
start_handle, end_handle, attr->handle, bass_svc->attr_count);
return -1;
}
return 0;
}
static int bass_svc_check(void)
{
struct bt_gatt_service *bass_svc;
const struct bt_uuid_16 *uuid;
bool chr_found;
/* This function is used to make sure the characteristics within
* the service exist in the service defined by Zephyr.
*/
bass_svc = lib_bap_bass_svc_get();
assert(bass_svc);
LOG_DBG("[N]BassSvcCheck");
for (const struct ble_gatt_chr_def *chr = gatt_svc_bass->characteristics;
chr && chr->uuid; chr++) {
const ble_uuid16_t *check = (const ble_uuid16_t *)chr->uuid;
chr_found = false;
for (size_t i = 0; i < bass_svc->attr_count; i++) {
uuid = (const struct bt_uuid_16 *)(bass_svc->attrs + i)->uuid;
if (uuid->uuid.type == BT_LE_NIMBLE_GATT_UUID_TO_Z(check->u.type) &&
uuid->val == check->value) {
chr_found = true;
break;
}
}
if (chr_found == false) {
LOG_ERR("[N]BassChrNotFound[%04x]", check->value);
return -1;
}
}
return 0;
}
int bt_le_nimble_bass_init(void)
{
uint16_t chr_count;
int rc;
/* An additional characteristic consist of all 0s indicating end of characteristics */
chr_count = 1 + CONFIG_BT_BAP_SCAN_DELEGATOR_RECV_STATE_COUNT + 1;
LOG_DBG("[N]BassInit[%u]", chr_count);
gatt_svc_bass->characteristics = calloc(chr_count, sizeof(struct ble_gatt_chr_def));
assert(gatt_svc_bass->characteristics);
bass_svc_add_control_point_chr((void *)(gatt_svc_bass->characteristics + 0));
bass_svc_add_recv_state_chr((void *)(gatt_svc_bass->characteristics + 1));
rc = ble_gatts_count_cfg(gatt_svc_bass);
if (rc) {
LOG_ERR("[N]BassCountCfgFail[%d]", rc);
goto free;
}
rc = ble_gatts_add_svcs(gatt_svc_bass);
if (rc) {
LOG_ERR("[N]BassAddSvcsFail[%d]", rc);
goto free;
}
rc = bass_svc_check();
if (rc) {
goto free;
}
return 0;
free:
free((void *)gatt_svc_bass->characteristics);
gatt_svc_bass->characteristics = NULL;
return rc;
}
@@ -0,0 +1,25 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef HOST_NIMBLE_PROFILE_BASS_H_
#define HOST_NIMBLE_PROFILE_BASS_H_
#include <stdint.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
int bt_le_nimble_bass_attr_handle_set(void);
int bt_le_nimble_bass_init(void);
#ifdef __cplusplus
}
#endif
#endif /* HOST_NIMBLE_PROFILE_BASS_H_ */
@@ -0,0 +1,126 @@
/*
* 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 <../host/conn_internal.h>
#include "host/ble_gatt.h"
#include "common/host.h"
#include "../../../lib/include/audio.h"
#if CONFIG_BT_CAP_ACCEPTOR_SET_MEMBER
extern struct ble_gatt_svc_def *cas_get_included_csis(void *csis_svc_p);
static struct bt_gatt_service *inc_csis_svc;
static struct ble_gatt_svc_def *cas_inc_svcs[] = {
NULL,
NULL,
};
#endif /* CONFIG_BT_CAP_ACCEPTOR_SET_MEMBER */
static struct ble_gatt_svc_def gatt_svc_cas[] = {
{
/* Published Audio Capabilities Service */
.type = BLE_GATT_SVC_TYPE_PRIMARY,
.uuid = BLE_UUID16_DECLARE(BT_UUID_CAS_VAL),
.includes = NULL,
.characteristics = NULL,
},
{
0, /* No more services. */
},
};
int bt_le_nimble_cas_attr_handle_set(void)
{
struct bt_gatt_service *cas_svc;
uint16_t handle;
int rc;
cas_svc = lib_cas_svc_get();
assert(cas_svc);
LOG_DBG("[N]CasAttrHdlSet[%u]", cas_svc->attr_count);
rc = ble_gatts_find_svc(BLE_UUID16_DECLARE(BT_UUID_CAS_VAL), &handle);
if (rc) {
LOG_ERR("[N]CasNotFound[%d]", rc);
return rc;
}
LOG_DBG("[N]Hdl[%u]", handle);
for (size_t i = 0; i < cas_svc->attr_count; i++) {
(cas_svc->attrs + i)->handle = handle + i;
}
return 0;
}
int bt_le_nimble_cas_init(void *csis_svc_p)
{
int rc;
LOG_DBG("[N]CasInit[%p]", csis_svc_p);
#if CONFIG_BT_CAP_ACCEPTOR_SET_MEMBER
/* The instance of CSIS is included by CAS */
if (csis_svc_p) {
cas_inc_svcs[0] = cas_get_included_csis(csis_svc_p);
if (cas_inc_svcs[0] == NULL) {
LOG_ERR("[N]CasIncCsisNotFound");
return -1;
}
/* Terminate the included service array with NULL */
cas_inc_svcs[1] = NULL;
gatt_svc_cas[0].includes = (const struct ble_gatt_svc_def **)cas_inc_svcs;
inc_csis_svc = csis_svc_p;
}
#else /* CONFIG_BT_CAP_ACCEPTOR_SET_MEMBER */
ARG_UNUSED(csis_svc_p);
#endif /* CONFIG_BT_CAP_ACCEPTOR_SET_MEMBER */
rc = ble_gatts_count_cfg(gatt_svc_cas);
if (rc) {
LOG_ERR("[N]CasCountCfgFail[%d]", rc);
return rc;
}
rc = ble_gatts_add_svcs(gatt_svc_cas);
if (rc) {
LOG_ERR("[N]CasAddSvcsFail[%d]", rc);
return rc;
}
#if !CONFIG_BT_CAP_ACCEPTOR_SET_MEMBER
struct bt_gatt_service *cas_svc;
cas_svc = lib_cas_svc_get();
assert(cas_svc);
/* Insert CAS to the GATT db list */
rc = bt_gatt_service_register_safe(cas_svc);
if (rc) {
LOG_ERR("[N]CasSvcRegFail[%d]", rc);
}
#endif /* !CONFIG_BT_CAP_ACCEPTOR_SET_MEMBER */
return rc;
}
@@ -0,0 +1,25 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef HOST_NIMBLE_PROFILE_CAS_H_
#define HOST_NIMBLE_PROFILE_CAS_H_
#include <stdint.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
int bt_le_nimble_cas_attr_handle_set(void);
int bt_le_nimble_cas_init(void *csis_svc);
#ifdef __cplusplus
}
#endif
#endif /* HOST_NIMBLE_PROFILE_CAS_H_ */
@@ -0,0 +1,271 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <assert.h>
#include <stdint.h>
#include <stdbool.h>
#include <errno.h>
#include <stdlib.h>
#include <zephyr/autoconf.h>
#include <zephyr/logging/log.h>
#include <zephyr/bluetooth/uuid.h>
#include <zephyr/bluetooth/gatt.h>
#include <zephyr/bluetooth/audio/csip.h>
#include <../host/conn_internal.h>
#include "os/os_mbuf.h"
#include "os/os_mempool.h"
#include "host/ble_att.h"
#include "host/ble_gatt.h"
#include "host/ble_hs_mbuf.h"
#include "nimble/profiles/server.h"
#include "common/host.h"
#include "../../../lib/include/audio.h"
#define CSIS_SVC_COUNT CONFIG_BT_CSIP_SET_MEMBER_MAX_INSTANCE_COUNT
#define CSIS_CHR_COUNT (4 + 1)
#if CONFIG_BT_CSIP_SET_MEMBER_SIRK_NOTIFIABLE
#define CSIS_CHR_FLAGS_SIRK \
(BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_READ_ENC)
#else /* CONFIG_BT_CSIP_SET_MEMBER_SIRK_NOTIFIABLE */
#define CSIS_CHR_FLAGS_SIRK \
(BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_ENC)
#endif /* CONFIG_BT_CSIP_SET_MEMBER_SIRK_NOTIFIABLE */
#define CSIS_CHR_FLAGS_SET_SIZE \
(BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_READ_ENC)
#define CSIS_CHR_FLAGS_SET_LOCK \
(BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_WRITE | \
BLE_GATT_CHR_F_READ_ENC | BLE_GATT_CHR_F_WRITE_ENC)
#define CSIS_CHR_FLAGS_RANK \
(BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_ENC)
static const ble_uuid16_t csis_uuid_svc = BLE_UUID16_INIT(BT_UUID_CSIS_VAL);
static const ble_uuid16_t csis_uuid_sirk = BLE_UUID16_INIT(BT_UUID_CSIS_SIRK_VAL);
static const ble_uuid16_t csis_uuid_set_size = BLE_UUID16_INIT(BT_UUID_CSIS_SET_SIZE_VAL);
static const ble_uuid16_t csis_uuid_set_lock = BLE_UUID16_INIT(BT_UUID_CSIS_SET_LOCK_VAL);
static const ble_uuid16_t csis_uuid_rank = BLE_UUID16_INIT(BT_UUID_CSIS_RANK_VAL);
static struct csis_inst {
struct bt_gatt_service *svc_p;
uint16_t sirk_handle;
uint16_t set_size_handle;
uint16_t set_lock_handle;
uint16_t rank_handle;
} csis_insts[CSIS_SVC_COUNT];
static uint8_t csis_svc_count;
/* Extra one for terminating the CSIS service array */
static struct ble_gatt_svc_def gatt_svc_csis[CSIS_SVC_COUNT + 1];
struct ble_gatt_svc_def *cas_get_included_csis(void *csis_svc_p)
{
size_t i;
LOG_DBG("[N]CasGetIncCsis[%u]", csis_svc_count);
for (i = 0; i < csis_svc_count; i++) {
if (csis_insts[i].svc_p == csis_svc_p) {
break;
}
}
if (i == csis_svc_count) {
return NULL;
}
return &gatt_svc_csis[i];
}
static int csis_svc_check(void)
{
const struct bt_uuid_16 *uuid;
bool chr_found;
/* This function is used to make sure the characteristics within
* the service exist in the service defined by Zephyr.
*/
LOG_DBG("[N]CsisSvcCheck[%u]", csis_svc_count);
for (size_t i = 0; i < csis_svc_count; i++) {
struct ble_gatt_svc_def *csis = &gatt_svc_csis[i];
struct bt_gatt_service *svc = csis_insts[i].svc_p;
assert(svc);
for (const struct ble_gatt_chr_def *chr = csis->characteristics;
chr && chr->uuid; chr++) {
const ble_uuid16_t *check = (const ble_uuid16_t *)chr->uuid;
chr_found = false;
for (size_t j = 0; j < svc->attr_count; j++) {
uuid = (const struct bt_uuid_16 *)(svc->attrs + j)->uuid;
if (uuid->uuid.type == BT_LE_NIMBLE_GATT_UUID_TO_Z(check->u.type) &&
uuid->val == check->value) {
chr_found = true;
break;
}
}
if (chr_found == false) {
LOG_ERR("[N]CsisChrNotFound[%u][%04x]", i, check->value);
return -1;
}
}
}
return 0;
}
int bt_le_nimble_csis_attr_handle_set(void)
{
struct bt_gatt_attr *attr;
uint16_t start_handle;
uint16_t end_handle;
LOG_DBG("[N]CsisAttrHdlSet[%u]", csis_svc_count);
for (size_t i = 0; i < csis_svc_count; i++) {
assert(csis_insts[i].svc_p);
assert(csis_insts[i].sirk_handle >= 2);
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);
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;
}
/* Last attribute in CSIS */
attr = csis_insts[i].svc_p->attrs + csis_insts[i].svc_p->attr_count - 1;
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;
}
}
return 0;
}
static inline void csis_chr_init(struct ble_gatt_chr_def *chr,
const ble_uuid16_t *uuid,
uint16_t *val_handle,
ble_gatt_chr_flags flags)
{
LOG_DBG("[N]CsisChrInit[%04x]", uuid->value);
chr->uuid = &uuid->u;
chr->access_cb = bt_le_nimble_gatts_access_cb_safe;
chr->arg = NULL;
chr->descriptors = NULL; /* NULL if no descriptors. Do not include CCCD */
chr->flags = flags;
chr->min_key_size = 16;
chr->val_handle = val_handle;
}
static void csis_svc_init(struct csis_inst *inst,
struct ble_gatt_svc_def *svc)
{
LOG_DBG("[N]CsisSvcInit");
svc->type = BLE_GATT_SVC_TYPE_PRIMARY;
svc->uuid = &csis_uuid_svc.u;
svc->includes = NULL;
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);
/* Characteristic - Coordinated Set Size */
csis_chr_init((void *)&svc->characteristics[1],
&csis_uuid_set_size,
&inst->set_size_handle,
CSIS_CHR_FLAGS_SET_SIZE);
/* Characteristic - Set Member Lock */
csis_chr_init((void *)&svc->characteristics[2],
&csis_uuid_set_lock,
&inst->set_lock_handle,
CSIS_CHR_FLAGS_SET_LOCK);
/* Characteristic - Set Member Rank */
csis_chr_init((void *)&svc->characteristics[3],
&csis_uuid_rank,
&inst->rank_handle,
CSIS_CHR_FLAGS_RANK);
}
int bt_le_nimble_csis_init(void *svc, uint8_t count)
{
int rc;
LOG_DBG("[N]CsisInit[%u]", count);
if (count > CSIS_SVC_COUNT) {
LOG_ERR("[N]InvCsisCount[%u][%u]", count, CSIS_SVC_COUNT);
return -1;
}
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];
}
rc = ble_gatts_count_cfg(gatt_svc_csis);
if (rc) {
LOG_ERR("[N]CsisCountCfgFail[%d]", rc);
goto free;
}
rc = ble_gatts_add_svcs(gatt_svc_csis);
if (rc) {
LOG_ERR("[N]CsisAddSvcsFail[%d]", rc);
goto free;
}
rc = csis_svc_check();
if (rc) {
goto free;
}
return 0;
free:
for (size_t i = 0; i < csis_svc_count; i++) {
free((void *)gatt_svc_csis[i].characteristics);
gatt_svc_csis[i].characteristics = NULL;
}
csis_svc_count = 0;
return rc;
}
@@ -0,0 +1,28 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef HOST_NIMBLE_PROFILE_CSIS_H_
#define HOST_NIMBLE_PROFILE_CSIS_H_
#include <stdint.h>
#include <stdbool.h>
#include <zephyr/bluetooth/audio/audio.h>
#include <zephyr/bluetooth/audio/csip.h>
#ifdef __cplusplus
extern "C" {
#endif
int bt_le_nimble_csis_attr_handle_set(void);
int bt_le_nimble_csis_init(void *csis_svc, uint8_t count);
#ifdef __cplusplus
}
#endif
#endif /* HOST_NIMBLE_PROFILE_CSIS_H_ */
@@ -0,0 +1,231 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <assert.h>
#include <stdint.h>
#include <stdbool.h>
#include <errno.h>
#include <stdlib.h>
#include <zephyr/autoconf.h>
#include <zephyr/logging/log.h>
#include <zephyr/bluetooth/uuid.h>
#include <zephyr/bluetooth/gatt.h>
#include <../host/conn_internal.h>
#include "os/os_mbuf.h"
#include "os/os_mempool.h"
#include "host/ble_att.h"
#include "host/ble_gatt.h"
#include "host/ble_hs_mbuf.h"
#include "nimble/profiles/server.h"
#include "common/host.h"
#include "../../../lib/include/audio.h"
static const ble_uuid16_t has_uuid_features = BLE_UUID16_INIT(BT_UUID_HAS_HEARING_AID_FEATURES_VAL);
static const ble_uuid16_t has_uuid_control_point = BLE_UUID16_INIT(BT_UUID_HAS_PRESET_CONTROL_POINT_VAL);
static const ble_uuid16_t has_uuid_preset_index = BLE_UUID16_INIT(BT_UUID_HAS_ACTIVE_PRESET_INDEX_VAL);
static uint16_t has_features_handle;
static uint16_t has_control_point_handle;
static uint16_t has_preset_index_handle;
static struct ble_gatt_svc_def gatt_svc_has[] = {
{
/* Hearing Access Service */
.type = BLE_GATT_SVC_TYPE_PRIMARY,
.uuid = BLE_UUID16_DECLARE(BT_UUID_HAS_VAL),
.includes = NULL,
.characteristics = NULL,
},
{
0, /* No more services. */
},
};
static void has_svc_add_features_chr(struct ble_gatt_chr_def *chr)
{
chr->uuid = &has_uuid_features.u;
chr->access_cb = bt_le_nimble_gatts_access_cb_safe;
chr->arg = NULL;
chr->descriptors = NULL; /* NULL if no descriptors. Do not include CCCD */
#if CONFIG_BT_HAS_FEATURES_NOTIFIABLE
chr->flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_READ_ENC;
#else /* CONFIG_BT_HAS_FEATURES_NOTIFIABLE */
chr->flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_ENC;
#endif /* CONFIG_BT_HAS_FEATURES_NOTIFIABLE */
chr->min_key_size = 16;
chr->val_handle = &has_features_handle;
LOG_DBG("[N]HasSvcAddFeatChr[%04x]", chr->flags);
}
static void has_svc_add_control_point_chr(struct ble_gatt_chr_def *chr)
{
chr->uuid = &has_uuid_control_point.u;
chr->access_cb = bt_le_nimble_gatts_access_cb_safe;
chr->arg = NULL;
chr->descriptors = NULL; /* NULL if no descriptors. Do not include CCCD */
#if CONFIG_BT_HAS_PRESET_CONTROL_POINT_NOTIFIABLE
chr->flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_INDICATE |
BLE_GATT_CHR_F_WRITE_ENC | BLE_GATT_CHR_F_NOTIFY;
#else /* CONFIG_BT_HAS_PRESET_CONTROL_POINT_NOTIFIABLE */
chr->flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_INDICATE | BLE_GATT_CHR_F_WRITE_ENC;
#endif /* CONFIG_BT_HAS_PRESET_CONTROL_POINT_NOTIFIABLE */
chr->min_key_size = 16;
chr->val_handle = &has_control_point_handle;
LOG_DBG("[N]HasSvcAddControlPointChr[%04x]", chr->flags);
}
#if CONFIG_BT_HAS_ACTIVE_PRESET_INDEX
static void has_svc_add_preset_index_chr(struct ble_gatt_chr_def *chr)
{
LOG_DBG("[N]HasSvcAddPresetIndexChr");
chr->uuid = &has_uuid_preset_index.u;
chr->access_cb = bt_le_nimble_gatts_access_cb_safe;
chr->arg = NULL;
chr->descriptors = NULL; /* NULL if no descriptors. Do not include CCCD */
chr->flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_READ_ENC;
chr->min_key_size = 16;
chr->val_handle = &has_preset_index_handle;
}
#endif /* CONFIG_BT_HAS_ACTIVE_PRESET_INDEX */
int bt_le_nimble_has_attr_handle_set(void)
{
struct bt_gatt_service *has_svc;
struct bt_gatt_attr *attr;
uint16_t start_handle = 0;
uint16_t end_handle = 0;
int rc;
has_svc = lib_has_svc_get();
assert(has_svc);
LOG_DBG("[N]HasAttrHdlSet[%u]", has_svc->attr_count);
assert(has_svc->attr_count > 0);
rc = ble_gatts_find_svc(BLE_UUID16_DECLARE(BT_UUID_HAS_VAL), &start_handle);
if (rc) {
LOG_ERR("[N]HasNotFound[%d]", rc);
return rc;
}
end_handle = start_handle + has_svc->attr_count - 1;
LOG_DBG("[N]Hdl[%u][%u]", start_handle, end_handle);
for (size_t i = 0; i < has_svc->attr_count; i++) {
(has_svc->attrs + i)->handle = start_handle + i;
}
/* Last attribute in HAS */
attr = has_svc->attrs + has_svc->attr_count - 1;
if (attr->handle != end_handle) {
LOG_ERR("[N]HasMismatchAttrHdl (%u %u %u %u)",
start_handle, end_handle, attr->handle, has_svc->attr_count);
return -1;
}
return 0;
}
static int has_svc_check(void)
{
struct bt_gatt_service *has_svc;
const struct bt_uuid_16 *uuid;
bool chr_found;
/* This function is used to make sure the characteristics within
* the service exist in the service defined by Zephyr.
*/
has_svc = lib_has_svc_get();
assert(has_svc);
LOG_DBG("[N]HasSvcCheck");
for (const struct ble_gatt_chr_def *chr = gatt_svc_has[0].characteristics;
chr && chr->uuid; chr++) {
const ble_uuid16_t *check = (const ble_uuid16_t *)chr->uuid;
chr_found = false;
for (size_t i = 0; i < has_svc->attr_count; i++) {
uuid = (const struct bt_uuid_16 *)(has_svc->attrs + i)->uuid;
if (uuid->uuid.type == BT_LE_NIMBLE_GATT_UUID_TO_Z(check->u.type) &&
uuid->val == check->value) {
chr_found = true;
break;
}
}
if (chr_found == false) {
LOG_ERR("[N]HasChrNotFound[%04x]", check->value);
return -1;
}
}
return 0;
}
int bt_le_nimble_has_init(void)
{
uint8_t chr_count;
int rc;
/* An additional characteristic consist of all 0s indicating end of characteristics */
#if CONFIG_BT_HAS_ACTIVE_PRESET_INDEX
chr_count = 1 + 1 + 1 + 1;
#else /* CONFIG_BT_HAS_ACTIVE_PRESET_INDEX */
chr_count = 1 + 1 + 1;
#endif /* CONFIG_BT_HAS_ACTIVE_PRESET_INDEX */
LOG_DBG("[N]HasInit[%u]", chr_count);
gatt_svc_has->characteristics = calloc(chr_count, sizeof(struct ble_gatt_chr_def));
assert(gatt_svc_has->characteristics);
has_svc_add_features_chr((void *)(gatt_svc_has->characteristics + 0));
has_svc_add_control_point_chr((void *)(gatt_svc_has->characteristics + 1));
#if CONFIG_BT_HAS_ACTIVE_PRESET_INDEX
has_svc_add_preset_index_chr((void *)(gatt_svc_has->characteristics + 2));
#endif /* CONFIG_BT_HAS_ACTIVE_PRESET_INDEX */
rc = ble_gatts_count_cfg(gatt_svc_has);
if (rc) {
LOG_ERR("[N]HasCountCfgFail[%d]", rc);
goto free;
}
rc = ble_gatts_add_svcs(gatt_svc_has);
if (rc) {
LOG_ERR("[N]HasAddSvcsFail[%d]", rc);
goto free;
}
rc = has_svc_check();
if (rc) {
goto free;
}
return 0;
free:
free((void *)gatt_svc_has->characteristics);
gatt_svc_has->characteristics = NULL;
return rc;
}
@@ -0,0 +1,27 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef HOST_NIMBLE_PROFILE_HAS_H_
#define HOST_NIMBLE_PROFILE_HAS_H_
#include <stdint.h>
#include <stdbool.h>
#include <zephyr/bluetooth/audio/audio.h>
#ifdef __cplusplus
extern "C" {
#endif
int bt_le_nimble_has_attr_handle_set(void);
int bt_le_nimble_has_init(void);
#ifdef __cplusplus
}
#endif
#endif /* HOST_NIMBLE_PROFILE_HAS_H_ */
@@ -0,0 +1,705 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdint.h>
#include <stdbool.h>
#include <errno.h>
#include <stdlib.h>
#include <zephyr/autoconf.h>
#include <zephyr/logging/log.h>
#include <zephyr/bluetooth/uuid.h>
#include <zephyr/bluetooth/gatt.h>
#include <zephyr/bluetooth/services/ots.h>
#include <zephyr/bluetooth/audio/media_proxy.h>
#if CONFIG_BT_OTS
#include "ots_internal.h"
#endif /* CONFIG_BT_OTS */
#include <../host/conn_internal.h>
#include "os/os_mbuf.h"
#include "os/os_mempool.h"
#include "host/ble_att.h"
#include "host/ble_gatt.h"
#include "host/ble_hs_mbuf.h"
#include "nimble/profiles/server.h"
#include "common/host.h"
#include "../../../lib/include/audio.h"
#if CONFIG_BT_OTS
#define INC_OTS_CHR_COUNT 8 /* - OTS Feature (M)
* - Object Name (M)
* - Object Type (M)
* - Object Size (M)
* - Object ID (C.1)
* - Object Properties (M)
* - Object Action Control Point (M)
* - Object List Control Point (C.1)
*/
#define INC_OTS_CHR_FLAGS_FEATURE \
(BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_ENC)
#if CONFIG_BT_OTS_OBJ_NAME_WRITE_SUPPORT
#define INC_OTS_CHR_FLAGS_NAME \
(BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_ENC | BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_WRITE_ENC)
#else /* CONFIG_BT_OTS_OBJ_NAME_WRITE_SUPPORT */
#define INC_OTS_CHR_FLAGS_NAME \
(BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_ENC)
#endif /* CONFIG_BT_OTS_OBJ_NAME_WRITE_SUPPORT */
#define INC_OTS_CHR_FLAGS_TYPE \
(BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_ENC)
#define INC_OTS_CHR_FLAGS_SIZE \
(BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_ENC)
#define INC_OTS_CHR_FLAGS_ID \
(BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_ENC)
#define INC_OTS_CHR_FLAGS_PROPS \
(BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_ENC)
#define INC_OTS_CHR_FLAGS_ACTION_CP \
(BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_INDICATE | BLE_GATT_CHR_F_WRITE_ENC)
#define INC_OTS_CHR_FLAGS_LIST_CP \
(BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_INDICATE | BLE_GATT_CHR_F_WRITE_ENC)
static uint8_t inc_ots_svc_count;
static struct bt_ots *ots;
static uint16_t inc_ots_chr_feature_handle;
static uint16_t inc_ots_chr_name_handle;
static uint16_t inc_ots_chr_type_handle;
static uint16_t inc_ots_chr_size_handle;
static uint16_t inc_ots_chr_id_handle;
static uint16_t inc_ots_chr_props_handle;
static uint16_t inc_ots_chr_action_cp_handle;
static uint16_t inc_ots_chr_list_cp_handle;
static struct ble_gatt_svc_def *gatt_svc_inc_ots;
static struct ble_gatt_svc_def **gmcs_inc_svcs;
static const ble_uuid16_t inc_ots_uuid_svc = BLE_UUID16_INIT(BT_UUID_OTS_VAL);
static const ble_uuid16_t inc_ots_uuid_feature = BLE_UUID16_INIT(BT_UUID_OTS_FEATURE_VAL);
static const ble_uuid16_t inc_ots_uuid_name = BLE_UUID16_INIT(BT_UUID_OTS_NAME_VAL);
static const ble_uuid16_t inc_ots_uuid_type = BLE_UUID16_INIT(BT_UUID_OTS_TYPE_VAL);
static const ble_uuid16_t inc_ots_uuid_size = BLE_UUID16_INIT(BT_UUID_OTS_SIZE_VAL);
static const ble_uuid16_t inc_ots_uuid_id = BLE_UUID16_INIT(BT_UUID_OTS_ID_VAL);
static const ble_uuid16_t inc_ots_uuid_props = BLE_UUID16_INIT(BT_UUID_OTS_PROPERTIES_VAL);
static const ble_uuid16_t inc_ots_uuid_action_cp = BLE_UUID16_INIT(BT_UUID_OTS_ACTION_CP_VAL);
static const ble_uuid16_t inc_ots_uuid_list_cp = BLE_UUID16_INIT(BT_UUID_OTS_LIST_CP_VAL);
#endif /* CONFIG_BT_OTS */
static uint16_t mcs_player_name_handle;
#if CONFIG_BT_OTS
static uint16_t mcs_icon_obj_id_handle;
#endif /* CONFIG_BT_OTS */
static uint16_t mcs_icon_url_handle;
static uint16_t mcs_track_changed_handle;
static uint16_t mcs_track_title_handle;
static uint16_t mcs_track_duration_handle;
static uint16_t mcs_track_position_handle;
static uint16_t mcs_playback_speed_handle;
static uint16_t mcs_seeking_speed_handle;
#if CONFIG_BT_OTS
static uint16_t mcs_track_segments_obj_id_handle;
static uint16_t mcs_current_track_obj_id_handle;
static uint16_t mcs_next_track_obj_id_handle;
static uint16_t mcs_parent_group_obj_id_handle;
static uint16_t mcs_current_group_obj_id_handle;
#endif /* CONFIG_BT_OTS */
static uint16_t mcs_playing_order_handle;
static uint16_t mcs_playing_orders_handle;
static uint16_t mcs_media_state_handle;
static uint16_t mcs_media_control_point_handle;
static uint16_t mcs_media_control_opcodes_handle;
#if CONFIG_BT_OTS
static uint16_t mcs_search_control_point_handle;
static uint16_t mcs_search_results_obj_id_handle;
#endif /* CONFIG_BT_OTS */
static uint16_t ccid_handle;
static struct ble_gatt_svc_def gatt_svc_gmcs[] = {
{
/* Published Audio Capabilities Service */
.type = BLE_GATT_SVC_TYPE_PRIMARY,
.uuid = BLE_UUID16_DECLARE(BT_UUID_GMCS_VAL),
.includes = NULL,
.characteristics = (struct ble_gatt_chr_def[])
{
{
.uuid = BLE_UUID16_DECLARE(BT_UUID_MCS_PLAYER_NAME_VAL),
.access_cb = bt_le_nimble_gatts_access_cb_safe,
.arg = NULL,
.descriptors = NULL, /* NULL if no descriptors. Do not include CCCD */
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_READ_ENC,
.min_key_size = 16,
.val_handle = &mcs_player_name_handle,
},
#if CONFIG_BT_OTS
{
.uuid = BLE_UUID16_DECLARE(BT_UUID_MCS_ICON_OBJ_ID_VAL),
.access_cb = bt_le_nimble_gatts_access_cb_safe,
.arg = NULL,
.descriptors = NULL, /* NULL if no descriptors. Do not include CCCD */
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_ENC,
.min_key_size = 16,
.val_handle = &mcs_icon_obj_id_handle,
},
#endif /* CONFIG_BT_OTS */
{
.uuid = BLE_UUID16_DECLARE(BT_UUID_MCS_ICON_URL_VAL),
.access_cb = bt_le_nimble_gatts_access_cb_safe,
.arg = NULL,
.descriptors = NULL, /* NULL if no descriptors. Do not include CCCD */
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_ENC,
.min_key_size = 16,
.val_handle = &mcs_icon_url_handle,
}, {
.uuid = BLE_UUID16_DECLARE(BT_UUID_MCS_TRACK_CHANGED_VAL),
.access_cb = bt_le_nimble_gatts_access_cb_safe,
.arg = NULL,
.descriptors = NULL, /* NULL if no descriptors. Do not include CCCD */
.flags = BLE_GATT_CHR_F_NOTIFY,
.min_key_size = 16,
.val_handle = &mcs_track_changed_handle,
}, {
.uuid = BLE_UUID16_DECLARE(BT_UUID_MCS_TRACK_TITLE_VAL),
.access_cb = bt_le_nimble_gatts_access_cb_safe,
.arg = NULL,
.descriptors = NULL, /* NULL if no descriptors. Do not include CCCD */
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_READ_ENC,
.min_key_size = 16,
.val_handle = &mcs_track_title_handle,
}, {
.uuid = BLE_UUID16_DECLARE(BT_UUID_MCS_TRACK_DURATION_VAL),
.access_cb = bt_le_nimble_gatts_access_cb_safe,
.arg = NULL,
.descriptors = NULL, /* NULL if no descriptors. Do not include CCCD */
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_READ_ENC,
.min_key_size = 16,
.val_handle = &mcs_track_duration_handle,
}, {
.uuid = BLE_UUID16_DECLARE(BT_UUID_MCS_TRACK_POSITION_VAL),
.access_cb = bt_le_nimble_gatts_access_cb_safe,
.arg = NULL,
.descriptors = NULL, /* NULL if no descriptors. Do not include CCCD */
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_WRITE | \
BLE_GATT_CHR_F_WRITE_NO_RSP | BLE_GATT_CHR_F_NOTIFY | \
BLE_GATT_CHR_F_READ_ENC | BLE_GATT_CHR_F_WRITE_ENC,
.min_key_size = 16,
.val_handle = &mcs_track_position_handle,
}, {
.uuid = BLE_UUID16_DECLARE(BT_UUID_MCS_PLAYBACK_SPEED_VAL),
.access_cb = bt_le_nimble_gatts_access_cb_safe,
.arg = NULL,
.descriptors = NULL, /* NULL if no descriptors. Do not include CCCD */
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_WRITE | \
BLE_GATT_CHR_F_WRITE_NO_RSP | BLE_GATT_CHR_F_NOTIFY | \
BLE_GATT_CHR_F_READ_ENC | BLE_GATT_CHR_F_WRITE_ENC,
.min_key_size = 16,
.val_handle = &mcs_playback_speed_handle,
}, {
.uuid = BLE_UUID16_DECLARE(BT_UUID_MCS_SEEKING_SPEED_VAL),
.access_cb = bt_le_nimble_gatts_access_cb_safe,
.arg = NULL,
.descriptors = NULL, /* NULL if no descriptors. Do not include CCCD */
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_READ_ENC,
.min_key_size = 16,
.val_handle = &mcs_seeking_speed_handle,
},
#if CONFIG_BT_OTS
{
.uuid = BLE_UUID16_DECLARE(BT_UUID_MCS_TRACK_SEGMENTS_OBJ_ID_VAL),
.access_cb = bt_le_nimble_gatts_access_cb_safe,
.arg = NULL,
.descriptors = NULL, /* NULL if no descriptors. Do not include CCCD */
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_ENC,
.min_key_size = 16,
.val_handle = &mcs_track_segments_obj_id_handle,
}, {
.uuid = BLE_UUID16_DECLARE(BT_UUID_MCS_CURRENT_TRACK_OBJ_ID_VAL),
.access_cb = bt_le_nimble_gatts_access_cb_safe,
.arg = NULL,
.descriptors = NULL, /* NULL if no descriptors. Do not include CCCD */
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_WRITE | \
BLE_GATT_CHR_F_WRITE_NO_RSP | BLE_GATT_CHR_F_NOTIFY | \
BLE_GATT_CHR_F_READ_ENC | BLE_GATT_CHR_F_WRITE_ENC,
.min_key_size = 16,
.val_handle = &mcs_current_track_obj_id_handle,
}, {
.uuid = BLE_UUID16_DECLARE(BT_UUID_MCS_NEXT_TRACK_OBJ_ID_VAL),
.access_cb = bt_le_nimble_gatts_access_cb_safe,
.arg = NULL,
.descriptors = NULL, /* NULL if no descriptors. Do not include CCCD */
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_WRITE | \
BLE_GATT_CHR_F_WRITE_NO_RSP | BLE_GATT_CHR_F_NOTIFY | \
BLE_GATT_CHR_F_READ_ENC | BLE_GATT_CHR_F_WRITE_ENC,
.min_key_size = 16,
.val_handle = &mcs_next_track_obj_id_handle,
}, {
.uuid = BLE_UUID16_DECLARE(BT_UUID_MCS_PARENT_GROUP_OBJ_ID_VAL),
.access_cb = bt_le_nimble_gatts_access_cb_safe,
.arg = NULL,
.descriptors = NULL, /* NULL if no descriptors. Do not include CCCD */
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_READ_ENC,
.min_key_size = 16,
.val_handle = &mcs_parent_group_obj_id_handle,
}, {
.uuid = BLE_UUID16_DECLARE(BT_UUID_MCS_CURRENT_GROUP_OBJ_ID_VAL),
.access_cb = bt_le_nimble_gatts_access_cb_safe,
.arg = NULL,
.descriptors = NULL, /* NULL if no descriptors. Do not include CCCD */
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_WRITE | \
BLE_GATT_CHR_F_WRITE_NO_RSP | BLE_GATT_CHR_F_NOTIFY | \
BLE_GATT_CHR_F_READ_ENC | BLE_GATT_CHR_F_WRITE_ENC,
.min_key_size = 16,
.val_handle = &mcs_current_group_obj_id_handle,
},
#endif /* CONFIG_BT_OTS */
{
.uuid = BLE_UUID16_DECLARE(BT_UUID_MCS_PLAYING_ORDER_VAL),
.access_cb = bt_le_nimble_gatts_access_cb_safe,
.arg = NULL,
.descriptors = NULL, /* NULL if no descriptors. Do not include CCCD */
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_WRITE | \
BLE_GATT_CHR_F_WRITE_NO_RSP | BLE_GATT_CHR_F_NOTIFY | \
BLE_GATT_CHR_F_READ_ENC | BLE_GATT_CHR_F_WRITE_ENC,
.min_key_size = 16,
.val_handle = &mcs_playing_order_handle,
}, {
.uuid = BLE_UUID16_DECLARE(BT_UUID_MCS_PLAYING_ORDERS_VAL),
.access_cb = bt_le_nimble_gatts_access_cb_safe,
.arg = NULL,
.descriptors = NULL, /* NULL if no descriptors. Do not include CCCD */
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_ENC,
.min_key_size = 16,
.val_handle = &mcs_playing_orders_handle,
}, {
.uuid = BLE_UUID16_DECLARE(BT_UUID_MCS_MEDIA_STATE_VAL),
.access_cb = bt_le_nimble_gatts_access_cb_safe,
.arg = NULL,
.descriptors = NULL, /* NULL if no descriptors. Do not include CCCD */
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_READ_ENC,
.min_key_size = 16,
.val_handle = &mcs_media_state_handle,
}, {
.uuid = BLE_UUID16_DECLARE(BT_UUID_MCS_MEDIA_CONTROL_POINT_VAL),
.access_cb = bt_le_nimble_gatts_access_cb_safe,
.arg = NULL,
.descriptors = NULL, /* NULL if no descriptors. Do not include CCCD */
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_WRITE_NO_RSP | \
BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_WRITE_ENC,
.min_key_size = 16,
.val_handle = &mcs_media_control_point_handle,
}, {
.uuid = BLE_UUID16_DECLARE(BT_UUID_MCS_MEDIA_CONTROL_OPCODES_VAL),
.access_cb = bt_le_nimble_gatts_access_cb_safe,
.arg = NULL,
.descriptors = NULL, /* NULL if no descriptors. Do not include CCCD */
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_READ_ENC,
.min_key_size = 16,
.val_handle = &mcs_media_control_opcodes_handle,
},
#if CONFIG_BT_OTS
{
.uuid = BLE_UUID16_DECLARE(BT_UUID_MCS_SEARCH_CONTROL_POINT_VAL),
.access_cb = bt_le_nimble_gatts_access_cb_safe,
.arg = NULL,
.descriptors = NULL, /* NULL if no descriptors. Do not include CCCD */
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_WRITE_NO_RSP | \
BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_WRITE_ENC,
.min_key_size = 16,
.val_handle = &mcs_search_control_point_handle,
}, {
.uuid = BLE_UUID16_DECLARE(BT_UUID_MCS_SEARCH_RESULTS_OBJ_ID_VAL),
.access_cb = bt_le_nimble_gatts_access_cb_safe,
.arg = NULL,
.descriptors = NULL, /* NULL if no descriptors. Do not include CCCD */
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_READ_ENC,
.min_key_size = 16,
.val_handle = &mcs_search_results_obj_id_handle,
},
#endif /* CONFIG_BT_OTS */
{
.uuid = BLE_UUID16_DECLARE(BT_UUID_CCID_VAL),
.access_cb = bt_le_nimble_gatts_access_cb_safe,
.arg = NULL,
.descriptors = NULL, /* NULL if no descriptors. Do not include CCCD */
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_ENC,
.min_key_size = 16,
.val_handle = &ccid_handle,
}, {
0, /* No more characteristics in this service. */
}
}
},
{
0, /* No more services. */
},
};
#if CONFIG_BT_OTS
static int inc_ots_attr_handle_set(void)
{
struct bt_gatt_attr *attr;
uint16_t start_handle;
uint16_t end_handle;
assert(ots && ots->service);
assert(inc_ots_chr_feature_handle >= 2);
start_handle = inc_ots_chr_feature_handle - 2; /* server attr handle & char def handle */
end_handle = inc_ots_chr_list_cp_handle + 1; /* cccd for chr Object List Control Point */
LOG_DBG("[N]IncOtsAttrHdlSet[%u][%u][%u]",
start_handle, end_handle, ots->service->attr_count);
for (size_t i = 0; i < ots->service->attr_count; i++) {
(ots->service->attrs + i)->handle = start_handle + i;
}
/* Last attribute in included OTS */
attr = ots->service->attrs + ots->service->attr_count - 1;
if (attr->handle != end_handle) {
LOG_ERR("[N]IncOtsMismatchAttrHdl[%u][%u][%u][%u]",
start_handle, end_handle, attr->handle, ots->service->attr_count);
return -1;
}
return 0;
}
#endif /* CONFIG_BT_OTS */
int bt_le_nimble_gmcs_attr_handle_set(void)
{
struct bt_gatt_service *gmcs_svc;
struct bt_gatt_attr *attr;
uint16_t start_handle = 0;
uint16_t end_handle = 0;
int rc;
gmcs_svc = lib_mcs_svc_get();
assert(gmcs_svc);
LOG_DBG("[N]GmcsAttrHdlSet[%u]", gmcs_svc->attr_count);
rc = ble_gatts_find_svc(BLE_UUID16_DECLARE(BT_UUID_GMCS_VAL), &start_handle);
if (rc) {
LOG_ERR("[N]GmcsNotFound[%d]", rc);
return rc;
}
end_handle = start_handle + gmcs_svc->attr_count - 1;
LOG_DBG("[N]Hdl[%u][%u]", start_handle, end_handle);
for (size_t i = 0; i < gmcs_svc->attr_count; i++) {
(gmcs_svc->attrs + i)->handle = start_handle + i;
}
/* Last attribute in MCS */
attr = gmcs_svc->attrs + gmcs_svc->attr_count - 1;
if (attr->handle != end_handle) {
LOG_ERR("[N]GmcsMismatchAttrHdl[%u][%u][%u][%u]",
start_handle, end_handle, attr->handle, gmcs_svc->attr_count);
return -1;
}
#if CONFIG_BT_OTS
if (inc_ots_svc_count) {
rc = inc_ots_attr_handle_set();
if (rc) {
return rc;
}
}
#endif /* CONFIG_BT_OTS */
return 0;
}
static int gmcs_svc_check(void)
{
struct bt_gatt_service *gmcs_svc;
const struct bt_uuid_16 *uuid;
bool chr_found;
/* This function is used to make sure the characteristics within
* the service exist in the service defined by Zephyr.
*/
gmcs_svc = lib_mcs_svc_get();
assert(gmcs_svc);
LOG_DBG("[N]GmcsSvcCheck");
for (const struct ble_gatt_chr_def *chr = gatt_svc_gmcs[0].characteristics;
chr && chr->uuid; chr++) {
const ble_uuid16_t *check = (const ble_uuid16_t *)chr->uuid;
chr_found = false;
for (size_t i = 0; i < gmcs_svc->attr_count; i++) {
uuid = (const struct bt_uuid_16 *)(gmcs_svc->attrs + i)->uuid;
if (uuid->uuid.type == BT_LE_NIMBLE_GATT_UUID_TO_Z(check->u.type) &&
uuid->val == check->value) {
chr_found = true;
break;
}
}
if (chr_found == false) {
LOG_ERR("[N]GmcsChrNotFound[%04x]", check->value);
return -1;
}
}
return 0;
}
#if CONFIG_BT_OTS
static int inc_ots_svc_check(void)
{
const struct bt_uuid_16 *uuid;
bool chr_found;
/* This function is used to make sure the characteristics within
* the service exist in the service defined by Zephyr.
*/
assert(gatt_svc_inc_ots);
assert(ots && ots->service);
LOG_DBG("[N]IncOtsSvcCheck");
for (const struct ble_gatt_chr_def *chr = gatt_svc_inc_ots[0].characteristics;
chr && chr->uuid; chr++) {
const ble_uuid16_t *check = (const ble_uuid16_t *)chr->uuid;
chr_found = false;
for (size_t i = 0; i < ots->service->attr_count; i++) {
uuid = (const struct bt_uuid_16 *)(ots->service->attrs + i)->uuid;
if (uuid->uuid.type == BT_LE_NIMBLE_GATT_UUID_TO_Z(check->u.type) &&
uuid->val == check->value) {
chr_found = true;
break;
}
}
if (chr_found == false) {
LOG_ERR("[N]IncOtsChrNotFound[%04x]", check->value);
return -1;
}
}
return 0;
}
static inline void inc_ots_chr_init(struct ble_gatt_chr_def *chr,
const ble_uuid16_t *uuid,
uint16_t *val_handle,
ble_gatt_chr_flags flags)
{
LOG_DBG("[N]IncOtsChrInit[%04x]", uuid->value);
chr->uuid = &uuid->u;
chr->access_cb = bt_le_nimble_gatts_access_cb_safe;
chr->arg = NULL;
chr->descriptors = NULL; /* NULL if no descriptors. Do not include CCCD */
chr->flags = flags;
chr->min_key_size = 16;
chr->val_handle = val_handle;
}
static int inc_ots_svc_init(void)
{
struct ble_gatt_svc_def *svc;
struct bt_gatt_attr *attrs;
uint8_t chr_count;
attrs = bt_ots_svc_decl_get(ots);
assert(attrs);
chr_count = 0;
for (size_t i = 0; i < ots->service->attr_count; i++) {
if (bt_uuid_cmp(attrs[i].uuid, BT_UUID_GATT_CHRC) == 0) {
chr_count++;
}
}
LOG_DBG("[N]IncOtsSvcInit[%u]", chr_count);
if (chr_count != INC_OTS_CHR_COUNT) {
LOG_ERR("[N]InvOtsChrCount[%u][%u]", chr_count, INC_OTS_CHR_COUNT);
return -EINVAL;
}
svc = &gatt_svc_inc_ots[0];
svc->type = BLE_GATT_SVC_TYPE_SECONDARY;
svc->uuid = &inc_ots_uuid_svc.u;
svc->includes = NULL;
/* An additional characteristic consist of all 0s indicating end of characteristics */
svc->characteristics = calloc(INC_OTS_CHR_COUNT + 1, sizeof(struct ble_gatt_chr_def));
assert(svc->characteristics);
/* Characteristic - OTS Feature */
inc_ots_chr_init((void *)&svc->characteristics[0],
&inc_ots_uuid_feature,
&inc_ots_chr_feature_handle,
INC_OTS_CHR_FLAGS_FEATURE);
/* Characteristic - Object Name */
inc_ots_chr_init((void *)&svc->characteristics[1],
&inc_ots_uuid_name,
&inc_ots_chr_name_handle,
INC_OTS_CHR_FLAGS_NAME);
/* Characteristic - Object Type */
inc_ots_chr_init((void *)&svc->characteristics[2],
&inc_ots_uuid_type,
&inc_ots_chr_type_handle,
INC_OTS_CHR_FLAGS_TYPE);
/* Characteristic - Object Size */
inc_ots_chr_init((void *)&svc->characteristics[3],
&inc_ots_uuid_size,
&inc_ots_chr_size_handle,
INC_OTS_CHR_FLAGS_SIZE);
/* Characteristic - Object ID */
inc_ots_chr_init((void *)&svc->characteristics[4],
&inc_ots_uuid_id,
&inc_ots_chr_id_handle,
INC_OTS_CHR_FLAGS_ID);
/* Characteristic - Object Properties */
inc_ots_chr_init((void *)&svc->characteristics[5],
&inc_ots_uuid_props,
&inc_ots_chr_props_handle,
INC_OTS_CHR_FLAGS_PROPS);
/* Characteristic - Object Action Control Point */
inc_ots_chr_init((void *)&svc->characteristics[6],
&inc_ots_uuid_action_cp,
&inc_ots_chr_action_cp_handle,
INC_OTS_CHR_FLAGS_ACTION_CP);
/* Characteristic - Object List Control Point */
inc_ots_chr_init((void *)&svc->characteristics[7],
&inc_ots_uuid_list_cp,
&inc_ots_chr_list_cp_handle,
INC_OTS_CHR_FLAGS_LIST_CP);
return 0;
}
#endif /* CONFIG_BT_OTS */
int bt_le_nimble_gmcs_init(bool ots_included)
{
int rc;
LOG_DBG("[N]GmcsInit[%u]", ots_included);
#if CONFIG_BT_OTS
if (ots_included) {
inc_ots_svc_count = 1;
/* Extra one for terminating the included service array with NULL */
gmcs_inc_svcs = calloc(2, sizeof(struct ble_gatt_svc_def *));
assert(gmcs_inc_svcs);
/* Extra one for terminating the OTS service array */
gatt_svc_inc_ots = calloc(2, sizeof(struct ble_gatt_svc_def));
assert(gatt_svc_inc_ots);
ots = lib_mcs_get_ots();
assert(ots && ots->service);
rc = inc_ots_svc_init();
if (rc) {
goto free;
}
gmcs_inc_svcs[0] = &gatt_svc_inc_ots[0];
rc = ble_gatts_count_cfg(gatt_svc_inc_ots);
if (rc) {
LOG_ERR("[N]IncOtsCountCfgFail[%d]", rc);
goto free;
}
rc = ble_gatts_add_svcs(gatt_svc_inc_ots);
if (rc) {
LOG_ERR("[N]IncOtsAddSvcsFail[%d]", rc);
goto free;
}
rc = inc_ots_svc_check();
if (rc) {
goto free;
}
/* Terminate the included service array with NULL */
gmcs_inc_svcs[1] = NULL;
}
gatt_svc_gmcs[0].includes = (const struct ble_gatt_svc_def **)gmcs_inc_svcs;
#endif /* CONFIG_BT_OTS */
rc = ble_gatts_count_cfg(gatt_svc_gmcs);
if (rc) {
LOG_ERR("[N]GmcsCountCfgFail[%d]", rc);
goto free;
}
rc = ble_gatts_add_svcs(gatt_svc_gmcs);
if (rc) {
LOG_ERR("[N]GmcsAddSvcsFail[%d]", rc);
goto free;
}
rc = gmcs_svc_check();
if (rc) {
goto free;
}
return 0;
free:
#if CONFIG_BT_OTS
if (ots_included) {
inc_ots_svc_count = 0;
free(gmcs_inc_svcs);
gmcs_inc_svcs = NULL;
if (gatt_svc_inc_ots[0].characteristics) {
free((void *)gatt_svc_inc_ots[0].characteristics);
gatt_svc_inc_ots[0].characteristics = NULL;
}
free(gatt_svc_inc_ots);
gatt_svc_inc_ots = NULL;
}
gatt_svc_gmcs[0].includes = NULL;
#endif /* CONFIG_BT_OTS */
return rc;
}
@@ -0,0 +1,28 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef HOST_NIMBLE_PROFILE_MCS_H_
#define HOST_NIMBLE_PROFILE_MCS_H_
#include <stdint.h>
#include <stdbool.h>
#include <zephyr/bluetooth/audio/audio.h>
#include <zephyr/bluetooth/audio/mcs.h>
#ifdef __cplusplus
extern "C" {
#endif
int bt_le_nimble_gmcs_attr_handle_set(void);
int bt_le_nimble_gmcs_init(bool ots_included);
#ifdef __cplusplus
}
#endif
#endif /* HOST_NIMBLE_PROFILE_MCS_H_ */
@@ -0,0 +1,447 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdint.h>
#include <stdbool.h>
#include <errno.h>
#include <stdlib.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 <../host/conn_internal.h>
#include "os/os_mbuf.h"
#include "os/os_mempool.h"
#include "host/ble_att.h"
#include "host/ble_gatt.h"
#include "host/ble_hs_mbuf.h"
#include "nimble/profiles/server.h"
#include "common/host.h"
#include "../../../lib/include/audio.h"
#define INC_AICS_CHR_COUNT (6 + 1)
#define INC_AICS_CHR_FLAGS_STATE \
(BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_READ_ENC)
#define INC_AICS_CHR_FLAGS_GAIN \
(BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_ENC)
#define INC_AICS_CHR_FLAGS_TYPE \
(BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_ENC)
#define INC_AICS_CHR_FLAGS_STATUS \
(BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_READ_ENC)
#define INC_AICS_CHR_FLAGS_CONTROL \
(BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_WRITE_ENC)
#define INC_AICS_CHR_FLAGS_DESCRIPTION \
(BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_WRITE_NO_RSP | \
BLE_GATT_CHR_F_READ_ENC | BLE_GATT_CHR_F_WRITE_ENC)
static uint8_t inc_aics_svc_count;
static struct inc_aics_inst {
struct bt_gatt_service *svc_p;
uint16_t state_handle;
uint16_t gain_handle;
uint16_t type_handle;
uint16_t status_handle;
uint16_t control_handle;
uint16_t description_handle;
} *inc_aics_insts;
static struct ble_gatt_svc_def *gatt_svc_inc_aics;
static const ble_uuid16_t inc_aics_uuid_svc = BLE_UUID16_INIT(BT_UUID_AICS_VAL);
static const ble_uuid16_t inc_aics_uuid_state = BLE_UUID16_INIT(BT_UUID_AICS_STATE_VAL);
static const ble_uuid16_t inc_aics_uuid_gain = BLE_UUID16_INIT(BT_UUID_AICS_GAIN_SETTINGS_VAL);
static const ble_uuid16_t inc_aics_uuid_type = BLE_UUID16_INIT(BT_UUID_AICS_INPUT_TYPE_VAL);
static const ble_uuid16_t inc_aics_uuid_status = BLE_UUID16_INIT(BT_UUID_AICS_INPUT_STATUS_VAL);
static const ble_uuid16_t inc_aics_uuid_control = BLE_UUID16_INIT(BT_UUID_AICS_CONTROL_VAL);
static const ble_uuid16_t inc_aics_uuid_description = BLE_UUID16_INIT(BT_UUID_AICS_DESCRIPTION_VAL);
static struct ble_gatt_svc_def **mics_inc_svcs;
static uint16_t mics_mute_handle;
static struct ble_gatt_svc_def gatt_svc_mics[] = {
{
/* Microphone Control Service */
.type = BLE_GATT_SVC_TYPE_PRIMARY,
.uuid = BLE_UUID16_DECLARE(BT_UUID_MICS_VAL),
.includes = NULL,
.characteristics = (struct ble_gatt_chr_def[])
{
{
.uuid = BLE_UUID16_DECLARE(BT_UUID_MICS_MUTE_VAL),
.access_cb = bt_le_nimble_gatts_access_cb_safe,
.arg = NULL,
.descriptors = NULL, /* NULL if no descriptors. Do not include CCCD */
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY | \
BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ_ENC | \
BLE_GATT_CHR_F_WRITE_ENC,
.min_key_size = 16,
.val_handle = &mics_mute_handle,
}, {
0, /* No more characteristics in this service. */
}
}
},
{
0, /* No more services. */
}
};
static int inc_aics_svc_check(void)
{
const struct bt_uuid_16 *uuid;
bool chr_found;
/* This function is used to make sure the characteristics within
* the service exist in the service defined by Zephyr.
*/
assert(gatt_svc_inc_aics);
assert(inc_aics_insts);
LOG_DBG("[N]IncAicsSvcCheck[%u]", inc_aics_svc_count);
for (size_t i = 0; i < inc_aics_svc_count; i++) {
struct ble_gatt_svc_def *aics = &gatt_svc_inc_aics[i];
struct bt_gatt_service *svc = inc_aics_insts[i].svc_p;
assert(svc);
for (const struct ble_gatt_chr_def *chr = aics->characteristics;
chr && chr->uuid; chr++) {
const ble_uuid16_t *check = (const ble_uuid16_t *)chr->uuid;
chr_found = false;
for (size_t j = 0; j < svc->attr_count; j++) {
uuid = (const struct bt_uuid_16 *)(svc->attrs + j)->uuid;
if (uuid->uuid.type == BT_LE_NIMBLE_GATT_UUID_TO_Z(check->u.type) &&
uuid->val == check->value) {
chr_found = true;
break;
}
}
if (chr_found == false) {
LOG_ERR("[N]IncAicsChrNotFound[%u][%04x]", i, check->value);
return -1;
}
}
}
return 0;
}
static int mics_svc_check(void)
{
struct bt_gatt_service *mics_svc;
const struct bt_uuid_16 *uuid;
bool chr_found;
mics_svc = lib_mics_svc_get();
assert(mics_svc);
LOG_DBG("[N]MicsSvcCheck");
for (const struct ble_gatt_chr_def *chr = gatt_svc_mics->characteristics;
chr && chr->uuid; chr++) {
const ble_uuid16_t *check = (const ble_uuid16_t *)chr->uuid;
chr_found = false;
for (size_t i = 0; i < mics_svc->attr_count; i++) {
uuid = (const struct bt_uuid_16 *)(mics_svc->attrs + i)->uuid;
if (uuid->uuid.type == BT_LE_NIMBLE_GATT_UUID_TO_Z(check->u.type) &&
uuid->val == check->value) {
chr_found = true;
break;
}
}
if (chr_found == false) {
LOG_ERR("[N]MicsChrNotFound[%04x]", check->value);
return -1;
}
}
return 0;
}
static int inc_aics_attr_handle_set(void)
{
struct bt_gatt_attr *attr;
uint16_t start_handle;
uint16_t end_handle;
assert(inc_aics_insts);
LOG_DBG("[N]IncAicsAttrHdlSet[%u]", inc_aics_svc_count);
for (size_t i = 0; i < inc_aics_svc_count; i++) {
assert(inc_aics_insts[i].svc_p);
assert(inc_aics_insts[i].state_handle >= 2);
start_handle = inc_aics_insts[i].state_handle - 2; /* server attr handle & char def handle */
end_handle = inc_aics_insts[i].description_handle + 1; /* cccd for chr Audio Input Description */
LOG_DBG("[N]IncAicsInst[%u][%u][%u][%u]",
i, start_handle, end_handle, inc_aics_insts[i].svc_p->attr_count);
for (size_t j = 0; j < inc_aics_insts[i].svc_p->attr_count; j++) {
(inc_aics_insts[i].svc_p->attrs + j)->handle = start_handle + j;
}
/* Last attribute in included AICS */
attr = inc_aics_insts[i].svc_p->attrs + inc_aics_insts[i].svc_p->attr_count - 1;
if (attr->handle != end_handle) {
LOG_ERR("[N]IncAicsMismatchAttrHdl[%u][%u][%u][%u]",
start_handle, end_handle, attr->handle,
inc_aics_insts[i].svc_p->attr_count);
return -1;
}
}
return 0;
}
int bt_le_nimble_mics_attr_handle_set(void)
{
struct bt_gatt_service *mics_svc;
struct bt_gatt_attr *attr;
uint16_t start_handle = 0;
uint16_t end_handle = 0;
int rc;
mics_svc = lib_mics_svc_get();
assert(mics_svc);
LOG_DBG("[N]MicsAttrHdlSet[%u]", mics_svc->attr_count);
rc = ble_gatts_find_svc(BLE_UUID16_DECLARE(BT_UUID_MICS_VAL), &start_handle);
if (rc) {
LOG_ERR("[N]MicsNotFound[%d]", rc);
return rc;
}
end_handle = start_handle + mics_svc->attr_count - 1;
LOG_DBG("[N]Hdl[%u][%u]", start_handle, end_handle);
for (size_t i = 0; i < mics_svc->attr_count; i++) {
(mics_svc->attrs + i)->handle = start_handle + i;
}
/* Last attribute in MICS */
attr = mics_svc->attrs + mics_svc->attr_count - 1;
if (attr->handle != end_handle) {
LOG_ERR("[N]MicsMismatchAttrHdl[%u][%u][%u][%u]",
start_handle, end_handle, attr->handle, mics_svc->attr_count);
return -1;
}
if (inc_aics_svc_count) {
rc = inc_aics_attr_handle_set();
if (rc) {
return rc;
}
}
return 0;
}
static inline void inc_aics_chr_init(struct ble_gatt_chr_def *chr,
const ble_uuid16_t *uuid,
uint16_t *val_handle,
ble_gatt_chr_flags flags)
{
LOG_DBG("[N]IncAicsChrInit[%04x]", uuid->value);
chr->uuid = &uuid->u;
chr->access_cb = bt_le_nimble_gatts_access_cb_safe;
chr->arg = NULL;
chr->descriptors = NULL; /* NULL if no descriptors. Do not include CCCD */
chr->flags = flags;
chr->min_key_size = 16;
chr->val_handle = val_handle;
}
static void inc_aics_svc_init(struct inc_aics_inst *inst,
struct ble_gatt_svc_def *svc)
{
LOG_DBG("[N]IncAicsSvcInit");
svc->type = BLE_GATT_SVC_TYPE_SECONDARY;
svc->uuid = &inc_aics_uuid_svc.u;
svc->includes = NULL;
svc->characteristics = calloc(INC_AICS_CHR_COUNT, sizeof(struct ble_gatt_chr_def));
assert(svc->characteristics);
/* Characteristic - Audio Input State */
inc_aics_chr_init((void *)&svc->characteristics[0],
&inc_aics_uuid_state,
&inst->state_handle,
INC_AICS_CHR_FLAGS_STATE);
/* Characteristic - Gain Setting Properties */
inc_aics_chr_init((void *)&svc->characteristics[1],
&inc_aics_uuid_gain,
&inst->gain_handle,
INC_AICS_CHR_FLAGS_GAIN);
/* Characteristic - Audio Input Type */
inc_aics_chr_init((void *)&svc->characteristics[2],
&inc_aics_uuid_type,
&inst->type_handle,
INC_AICS_CHR_FLAGS_TYPE);
/* Characteristic - Audio Input Status */
inc_aics_chr_init((void *)&svc->characteristics[3],
&inc_aics_uuid_status,
&inst->status_handle,
INC_AICS_CHR_FLAGS_STATUS);
/* Characteristic - Audio Input Control Point */
inc_aics_chr_init((void *)&svc->characteristics[4],
&inc_aics_uuid_control,
&inst->control_handle,
INC_AICS_CHR_FLAGS_CONTROL);
/* Characteristic - Audio Input Description */
inc_aics_chr_init((void *)&svc->characteristics[5],
&inc_aics_uuid_description,
&inst->description_handle,
INC_AICS_CHR_FLAGS_DESCRIPTION);
}
int bt_le_nimble_mics_init(void *micp_inc)
{
struct bt_micp_included *micp_included;
uint8_t inc_count;
int rc;
LOG_DBG("[N]MicsInit[%p]", micp_inc);
micp_included = micp_inc;
if (micp_included) {
LOG_DBG("[N]MicpIncCount[%u]", micp_included->aics_cnt);
if (micp_included->aics_cnt > CONFIG_BT_MICP_MIC_DEV_AICS_INSTANCE_COUNT) {
LOG_ERR("[N]InvMicpIncCount[%u][%u]",
micp_included->aics_cnt, CONFIG_BT_MICP_MIC_DEV_AICS_INSTANCE_COUNT);
return -1;
}
inc_aics_svc_count = micp_included->aics_cnt;
/* Extra one for terminating the included service array with NULL */
inc_count = inc_aics_svc_count + 1;
mics_inc_svcs = calloc(inc_count, sizeof(struct ble_gatt_svc_def *));
assert(mics_inc_svcs);
/* MICS may include zero or more instances of AICS */
if (inc_aics_svc_count) {
inc_aics_insts = calloc(inc_aics_svc_count, sizeof(struct inc_aics_inst));
assert(inc_aics_insts);
/* Extra one for terminating the AICS service array */
gatt_svc_inc_aics = calloc(inc_aics_svc_count + 1, sizeof(struct ble_gatt_svc_def));
assert(gatt_svc_inc_aics);
for (size_t i = 0; i < inc_aics_svc_count; i++) {
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]);
mics_inc_svcs[i] = &gatt_svc_inc_aics[i];
}
rc = ble_gatts_count_cfg(gatt_svc_inc_aics);
if (rc) {
LOG_ERR("[N]IncAicsCountCfgFail[%d]", rc);
goto free;
}
rc = ble_gatts_add_svcs(gatt_svc_inc_aics);
if (rc) {
LOG_ERR("[N]IncAicsAddSvcsFail[%d]", rc);
goto free;
}
rc = inc_aics_svc_check();
if (rc) {
goto free;
}
}
/* Terminate the included service array with NULL */
mics_inc_svcs[inc_count - 1] = NULL;
}
gatt_svc_mics[0].includes = (const struct ble_gatt_svc_def **)mics_inc_svcs;
rc = ble_gatts_count_cfg(gatt_svc_mics);
if (rc) {
LOG_ERR("[N]MicsCountCfgFail[%d]", rc);
goto free;
}
rc = ble_gatts_add_svcs(gatt_svc_mics);
if (rc) {
LOG_ERR("[N]MicsAddSvcsFail[%d]", rc);
goto free;
}
rc = mics_svc_check();
if (rc) {
goto free;
}
return 0;
free:
if (micp_included) {
free(mics_inc_svcs);
mics_inc_svcs = NULL;
if (inc_aics_svc_count) {
free(inc_aics_insts);
inc_aics_insts = NULL;
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;
inc_aics_svc_count = 0;
}
}
gatt_svc_mics[0].includes = NULL;
return rc;
}
@@ -0,0 +1,28 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef HOST_NIMBLE_PROFILE_MICS_H_
#define HOST_NIMBLE_PROFILE_MICS_H_
#include <stdint.h>
#include <stdbool.h>
#include <zephyr/bluetooth/audio/audio.h>
#include <zephyr/bluetooth/audio/micp.h>
#ifdef __cplusplus
extern "C" {
#endif
int bt_le_nimble_mics_attr_handle_set(void);
int bt_le_nimble_mics_init(void *micp_inc);
#ifdef __cplusplus
}
#endif
#endif /* HOST_NIMBLE_PROFILE_MICS_H_ */
@@ -0,0 +1,268 @@
/*
* 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 <../host/conn_internal.h>
#include "os/os_mbuf.h"
#include "os/os_mempool.h"
#include "host/ble_att.h"
#include "host/ble_gatt.h"
#include "host/ble_hs_mbuf.h"
#include "nimble/profiles/server.h"
#include "common/host.h"
#include "../../../lib/include/audio.h"
#if CONFIG_BT_PAC_SNK
static uint16_t pacs_snk_handle;
#if CONFIG_BT_PAC_SNK_LOC
static uint16_t pacs_snk_loc_handle;
#endif /* CONFIG_BT_PAC_SNK_LOC */
#endif /* CONFIG_BT_PAC_SNK */
#if CONFIG_BT_PAC_SRC
static uint16_t pacs_src_handle;
#if CONFIG_BT_PAC_SRC_LOC
static uint16_t pacs_src_loc_handle;
#endif /* CONFIG_BT_PAC_SRC_LOC */
#endif /* CONFIG_BT_PAC_SRC */
static uint16_t pacs_ava_ctx_handle;
static uint16_t pacs_sup_ctx_handle;
static const struct ble_gatt_svc_def gatt_svc_pacs[] = {
{
/* Published Audio Capabilities Service */
.type = BLE_GATT_SVC_TYPE_PRIMARY,
.uuid = BLE_UUID16_DECLARE(BT_UUID_PACS_VAL),
.includes = NULL,
.characteristics = (struct ble_gatt_chr_def[])
{
#if CONFIG_BT_PAC_SNK
{
.uuid = BLE_UUID16_DECLARE(BT_UUID_PACS_SNK_VAL),
.access_cb = bt_le_nimble_gatts_access_cb_safe,
.arg = NULL,
.descriptors = NULL, /* NULL if no descriptors. Do not include CCCD */
#if CONFIG_BT_PAC_SNK_NOTIFIABLE
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_READ_ENC,
#else /* CONFIG_BT_PAC_SNK_NOTIFIABLE */
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_ENC,
#endif /* CONFIG_BT_PAC_SNK_NOTIFIABLE */
.min_key_size = 16,
.val_handle = &pacs_snk_handle,
},
#if CONFIG_BT_PAC_SNK_LOC
{
.uuid = BLE_UUID16_DECLARE(BT_UUID_PACS_SNK_LOC_VAL),
.access_cb = bt_le_nimble_gatts_access_cb_safe,
.arg = NULL,
.descriptors = NULL, /* NULL if no descriptors. Do not include CCCD */
#if CONFIG_BT_PAC_SNK_LOC_WRITEABLE && CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_WRITE | \
BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_READ_ENC | \
BLE_GATT_CHR_F_WRITE_ENC,
#elif CONFIG_BT_PAC_SNK_LOC_WRITEABLE && !CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_WRITE | \
BLE_GATT_CHR_F_READ_ENC | BLE_GATT_CHR_F_WRITE_ENC,
#elif !CONFIG_BT_PAC_SNK_LOC_WRITEABLE && CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_READ_ENC,
#else /* !CONFIG_BT_PAC_SNK_LOC_WRITEABLE && !CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE */
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_ENC,
#endif /* CONFIG_BT_PAC_SNK_LOC_WRITEABLE && CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE */
.min_key_size = 16,
.val_handle = &pacs_snk_loc_handle,
},
#endif /* CONFIG_BT_PAC_SNK_LOC */
#endif /* CONFIG_BT_PAC_SNK */
#if CONFIG_BT_PAC_SRC
{
.uuid = BLE_UUID16_DECLARE(BT_UUID_PACS_SRC_VAL),
.access_cb = bt_le_nimble_gatts_access_cb_safe,
.arg = NULL,
.descriptors = NULL, /* NULL if no descriptors. Do not include CCCD */
#if CONFIG_BT_PAC_SRC_NOTIFIABLE
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_READ_ENC,
#else /* CONFIG_BT_PAC_SRC_NOTIFIABLE */
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_ENC,
#endif /* CONFIG_BT_PAC_SRC_NOTIFIABLE */
.min_key_size = 16,
.val_handle = &pacs_src_handle,
},
#if CONFIG_BT_PAC_SRC_LOC
{
.uuid = BLE_UUID16_DECLARE(BT_UUID_PACS_SRC_LOC_VAL),
.access_cb = bt_le_nimble_gatts_access_cb_safe,
.arg = NULL,
.descriptors = NULL, /* NULL if no descriptors. Do not include CCCD */
#if CONFIG_BT_PAC_SRC_LOC_WRITEABLE && CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_WRITE | \
BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_READ_ENC | \
BLE_GATT_CHR_F_WRITE_ENC,
#elif CONFIG_BT_PAC_SRC_LOC_WRITEABLE && !CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_WRITE | \
BLE_GATT_CHR_F_READ_ENC | BLE_GATT_CHR_F_WRITE_ENC,
#elif !CONFIG_BT_PAC_SRC_LOC_WRITEABLE && CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_READ_ENC,
#else /* !CONFIG_BT_PAC_SRC_LOC_WRITEABLE && !CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE */
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_ENC,
#endif /* CONFIG_BT_PAC_SRC_LOC_WRITEABLE && CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE */
.min_key_size = 16,
.val_handle = &pacs_src_loc_handle,
},
#endif /* CONFIG_BT_PAC_SRC_LOC */
#endif /* CONFIG_BT_PAC_SRC */
{
.uuid = BLE_UUID16_DECLARE(BT_UUID_PACS_AVAILABLE_CONTEXT_VAL),
.access_cb = bt_le_nimble_gatts_access_cb_safe,
.arg = NULL,
.descriptors = NULL, /* NULL if no descriptors. Do not include CCCD */
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_READ_ENC,
.min_key_size = 16,
.val_handle = &pacs_ava_ctx_handle,
}, {
.uuid = BLE_UUID16_DECLARE(BT_UUID_PACS_SUPPORTED_CONTEXT_VAL),
.access_cb = bt_le_nimble_gatts_access_cb_safe,
.arg = NULL,
.descriptors = NULL, /* NULL if no descriptors. Do not include CCCD */
#if CONFIG_BT_PACS_SUPPORTED_CONTEXT_NOTIFIABLE
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_READ_ENC,
#else /* CONFIG_BT_PACS_SUPPORTED_CONTEXT_NOTIFIABLE */
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_ENC,
#endif /* CONFIG_BT_PACS_SUPPORTED_CONTEXT_NOTIFIABLE */
.min_key_size = 16,
.val_handle = &pacs_sup_ctx_handle,
}, {
0, /* No more characteristics in this service. */
}
}
},
{
0, /* No more services. */
},
};
int bt_le_nimble_pacs_attr_handle_set(void)
{
struct bt_gatt_service *pacs_svc;
struct bt_gatt_attr *attr;
uint16_t start_handle;
uint16_t end_handle;
pacs_svc = lib_pacs_svc_get();
assert(pacs_svc);
#if CONFIG_BT_PAC_SNK
assert(pacs_snk_handle >= 2);
start_handle = pacs_snk_handle - 2; /* server attr handle & char def handle */
#elif CONFIG_BT_PAC_SRC
assert(pacs_src_handle >= 2);
start_handle = pacs_src_handle - 2; /* server attr handle & char def handle */
#else
assert(pacs_ava_ctx_handle >= 2);
start_handle = pacs_ava_ctx_handle - 2; /* server attr handle & char def handle */
#endif
#if CONFIG_BT_PACS_SUPPORTED_CONTEXT_NOTIFIABLE
end_handle = pacs_sup_ctx_handle + 1; /* cccd attr handle */
#else /* CONFIG_BT_PACS_SUPPORTED_CONTEXT_NOTIFIABLE */
end_handle = pacs_sup_ctx_handle; /* char value attr handle */
#endif /* CONFIG_BT_PACS_SUPPORTED_CONTEXT_NOTIFIABLE */
LOG_DBG("[N]PacsAttrHdlSet[%u][%u][%u][%u]",
start_handle, end_handle, pacs_sup_ctx_handle, pacs_svc->attr_count);
for (size_t i = 0; i < pacs_svc->attr_count; i++) {
(pacs_svc->attrs + i)->handle = start_handle + i;
}
/* Last attribute in PACS */
attr = pacs_svc->attrs + pacs_svc->attr_count - 1;
if (attr->handle != end_handle) {
LOG_ERR("[N]PacsMismatchAttrHdl[%u][%u][%u][%u]",
start_handle, end_handle, attr->handle, pacs_svc->attr_count);
return -1;
}
return 0;
}
static int pacs_svc_check(void)
{
struct bt_gatt_service *pacs_svc;
const struct bt_uuid_16 *uuid;
bool chr_found;
/* This function is used to make sure the characteristics within
* the service exist in the service defined by Zephyr.
*/
pacs_svc = lib_pacs_svc_get();
assert(pacs_svc);
LOG_DBG("[N]PacsSvcCheck");
for (const struct ble_gatt_chr_def *chr = gatt_svc_pacs[0].characteristics;
chr && chr->uuid; chr++) {
const ble_uuid16_t *check = (const ble_uuid16_t *)chr->uuid;
chr_found = false;
for (size_t i = 0; i < pacs_svc->attr_count; i++) {
uuid = (const struct bt_uuid_16 *)(pacs_svc->attrs + i)->uuid;
if (uuid->uuid.type == BT_LE_NIMBLE_GATT_UUID_TO_Z(check->u.type) &&
uuid->val == check->value) {
chr_found = true;
break;
}
}
if (chr_found == false) {
LOG_ERR("[N]PacsChrNotFound[%04x]", check->value);
return -1;
}
}
return 0;
}
int bt_le_nimble_pacs_init(void)
{
int rc;
LOG_DBG("[N]PacsInit");
rc = ble_gatts_count_cfg(gatt_svc_pacs);
if (rc) {
LOG_ERR("[N]PacsCountCfgFail[%d]", rc);
return rc;
}
rc = ble_gatts_add_svcs(gatt_svc_pacs);
if (rc) {
LOG_ERR("[N]PacsAddSvcsFail[%d]", rc);
return rc;
}
rc = pacs_svc_check();
if (rc) {
return rc;
}
return 0;
}
@@ -0,0 +1,28 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef HOST_NIMBLE_PROFILE_PACS_H_
#define HOST_NIMBLE_PROFILE_PACS_H_
#include <stdint.h>
#include <stdbool.h>
#include <zephyr/bluetooth/audio/audio.h>
#include <zephyr/bluetooth/audio/pacs.h>
#ifdef __cplusplus
extern "C" {
#endif
int bt_le_nimble_pacs_attr_handle_set(void);
int bt_le_nimble_pacs_init(void);
#ifdef __cplusplus
}
#endif
#endif /* HOST_NIMBLE_PROFILE_PACS_H_ */
@@ -0,0 +1,174 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stddef.h>
#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 <../host/conn_internal.h>
#include "os/os_mbuf.h"
#include "os/os_mempool.h"
#include "host/ble_hs.h"
#include "host/ble_att.h"
#include "host/ble_gatt.h"
#include "host/ble_hs_mbuf.h"
#include "common/host.h"
static ssize_t gatts_read_cb(void *arg, uint16_t offset, const void *data, uint16_t len)
{
struct os_mbuf *om;
int rc;
ARG_UNUSED(offset);
om = (struct os_mbuf *)arg;
assert(om);
LOG_DBG("[N]GattsRdCb[%u][%u]", offset, len);
if (data == NULL || len == 0) {
rc = 0;
} else {
rc = os_mbuf_append(om, data, len);
if (rc) {
LOG_ERR("[N]MbufAppendFail[%d]", rc);
}
}
return (rc == 0 ? len : 0);
}
static int gatts_access_cb(uint16_t conn_handle, uint16_t attr_handle,
struct ble_gatt_access_ctxt *ctx, void *arg)
{
struct bt_le_nimble_gatt_read_cb cb;
const struct bt_gatt_attr *attr;
struct bt_conn *conn;
uint8_t *data;
ssize_t rc;
assert(ctx);
LOG_DBG("[N]GattsAccessCb[%u][%u][%02x]", conn_handle, attr_handle, ctx->op);
conn = bt_le_acl_conn_find(conn_handle);
if (conn == NULL || conn->state != BT_CONN_CONNECTED) {
LOG_ERR("[N]NotConn[%d]", __LINE__);
return -ENOTCONN;
}
switch (ctx->op) {
case BLE_GATT_ACCESS_OP_READ_CHR:
attr = bt_gatts_find_attr_by_handle(attr_handle);
if (attr == NULL) {
LOG_WRN("[N]RdInvHdl[%u]", attr_handle);
return BT_GATT_ERR(BT_ATT_ERR_INVALID_HANDLE);
}
if (attr->read == NULL) {
LOG_WRN("[N]RdNotPermit");
return BT_GATT_ERR(BT_ATT_ERR_READ_NOT_PERMITTED);
}
cb.read_cb = gatts_read_cb;
cb.read_arg = ctx->om;
rc = attr->read(conn, attr, (void *)&cb, UINT16_MAX, 0);
if (rc < 0) {
LOG_ERR("[N]RdFail[%u][%d]", attr_handle, rc);
return BT_GATT_ERR(rc);
}
return 0;
case BLE_GATT_ACCESS_OP_WRITE_CHR:
attr = bt_gatts_find_attr_by_handle(attr_handle);
if (attr == NULL) {
LOG_WRN("[N]WrInvHdl[%u]", attr_handle);
return BT_GATT_ERR(BT_ATT_ERR_INVALID_HANDLE);
}
if (attr->write == NULL) {
LOG_WRN("[N]WrNotPermit");
return BT_GATT_ERR(BT_ATT_ERR_WRITE_NOT_PERMITTED);
}
if (BT_UUID_16(attr->uuid)->val == BT_UUID_BASS_CONTROL_POINT_VAL) {
/* Receive Write Long Characteristic for assistant adding source.
* TODO:
* Check if the following operation could be directly used?
* "write(conn, attr, ctx->om->om_data, OS_MBUF_PKTLEN(ctx->om), 0, 0)"
*/
uint16_t alloc_len = 16 + CONFIG_BT_BAP_BASS_MAX_SUBGROUPS *
(5 + CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE);
LOG_DBG("[N]WrBassControlPoint[%u]", alloc_len);
if (OS_MBUF_PKTLEN(ctx->om) > alloc_len) {
LOG_ERR("[N]WrBassCtrlPtTooLong[%u > %u]",
OS_MBUF_PKTLEN(ctx->om), alloc_len);
return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN);
}
data = calloc(1, alloc_len);
assert(data);
rc = os_mbuf_copydata(ctx->om, 0, OS_MBUF_PKTLEN(ctx->om), data);
assert(rc == 0);
rc = attr->write(conn, attr, data, OS_MBUF_PKTLEN(ctx->om), 0, 0);
free(data);
data = NULL;
} else {
LOG_DBG("[N]Wr[%u]", OS_MBUF_PKTLEN(ctx->om));
data = calloc(1, OS_MBUF_PKTLEN(ctx->om));
assert(data);
rc = os_mbuf_copydata(ctx->om, 0, OS_MBUF_PKTLEN(ctx->om), data);
assert(rc == 0);
rc = attr->write(conn, attr, data, OS_MBUF_PKTLEN(ctx->om), 0, 0);
free(data);
data = NULL;
}
if (rc < 0) {
LOG_ERR("[N]WrFail[%u][%d]", attr_handle, rc);
return BT_GATT_ERR(rc);
}
return 0;
case BLE_GATT_ACCESS_OP_READ_DSC:
return 0;
case BLE_GATT_ACCESS_OP_WRITE_DSC:
return 0;
default:
return BLE_ATT_ERR_UNLIKELY;
}
}
int bt_le_nimble_gatts_access_cb_safe(uint16_t conn_handle, uint16_t attr_handle,
struct ble_gatt_access_ctxt *ctx, void *arg)
{
int err;
bt_le_host_lock();
err = gatts_access_cb(conn_handle, attr_handle, ctx, arg);
bt_le_host_unlock();
return err;
}
@@ -0,0 +1,26 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef HOST_NIMBLE_SERVER_H_
#define HOST_NIMBLE_SERVER_H_
#include <stdint.h>
#include <stdbool.h>
#include "host/ble_gatt.h"
#ifdef __cplusplus
extern "C" {
#endif
int bt_le_nimble_gatts_access_cb_safe(uint16_t conn_handle, uint16_t attr_handle,
struct ble_gatt_access_ctxt *ctx, void *arg);
#ifdef __cplusplus
}
#endif
#endif /* HOST_NIMBLE_SERVER_H_ */
@@ -0,0 +1,253 @@
/*
* 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 <../host/conn_internal.h>
#include "os/os_mbuf.h"
#include "os/os_mempool.h"
#include "host/ble_att.h"
#include "host/ble_gatt.h"
#include "host/ble_hs_mbuf.h"
#include "nimble/profiles/server.h"
#include "common/host.h"
#include "../../../lib/include/audio.h"
static const struct ble_gatt_svc_def gatt_svc_gtbs[] = {
{
/* Generic Telephone Bearer Service */
.type = BLE_GATT_SVC_TYPE_PRIMARY,
.uuid = BLE_UUID16_DECLARE(BT_UUID_GTBS_VAL),
.includes = NULL,
.characteristics = (struct ble_gatt_chr_def[])
{
{
.uuid = BLE_UUID16_DECLARE(BT_UUID_TBS_PROVIDER_NAME_VAL),
.access_cb = bt_le_nimble_gatts_access_cb_safe,
.arg = NULL,
.descriptors = NULL, /* NULL if no descriptors. Do not include CCCD */
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_READ_ENC,
.min_key_size = 16,
}, {
.uuid = BLE_UUID16_DECLARE(BT_UUID_TBS_UCI_VAL),
.access_cb = bt_le_nimble_gatts_access_cb_safe,
.arg = NULL,
.descriptors = NULL, /* NULL if no descriptors. Do not include CCCD */
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_ENC,
.min_key_size = 16,
}, {
.uuid = BLE_UUID16_DECLARE(BT_UUID_TBS_TECHNOLOGY_VAL),
.access_cb = bt_le_nimble_gatts_access_cb_safe,
.arg = NULL,
.descriptors = NULL, /* NULL if no descriptors. Do not include CCCD */
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_READ_ENC,
.min_key_size = 16,
}, {
.uuid = BLE_UUID16_DECLARE(BT_UUID_TBS_URI_LIST_VAL),
.access_cb = bt_le_nimble_gatts_access_cb_safe,
.arg = NULL,
.descriptors = NULL, /* NULL if no descriptors. Do not include CCCD */
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_READ_ENC,
.min_key_size = 16,
}, {
.uuid = BLE_UUID16_DECLARE(BT_UUID_TBS_SIGNAL_STRENGTH_VAL),
.access_cb = bt_le_nimble_gatts_access_cb_safe,
.arg = NULL,
.descriptors = NULL, /* NULL if no descriptors. Do not include CCCD */
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_READ_ENC,
.min_key_size = 16,
}, {
.uuid = BLE_UUID16_DECLARE(BT_UUID_TBS_SIGNAL_INTERVAL_VAL),
.access_cb = bt_le_nimble_gatts_access_cb_safe,
.arg = NULL,
.descriptors = NULL, /* NULL if no descriptors. Do not include CCCD */
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_WRITE | \
BLE_GATT_CHR_F_WRITE_NO_RSP | BLE_GATT_CHR_F_READ_ENC | \
BLE_GATT_CHR_F_WRITE_ENC,
.min_key_size = 16,
}, {
.uuid = BLE_UUID16_DECLARE(BT_UUID_TBS_LIST_CURRENT_CALLS_VAL),
.access_cb = bt_le_nimble_gatts_access_cb_safe,
.arg = NULL,
.descriptors = NULL, /* NULL if no descriptors. Do not include CCCD */
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_READ_ENC,
.min_key_size = 16,
}, {
.uuid = BLE_UUID16_DECLARE(BT_UUID_CCID_VAL),
.access_cb = bt_le_nimble_gatts_access_cb_safe,
.arg = NULL,
.descriptors = NULL, /* NULL if no descriptors. Do not include CCCD */
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_ENC,
.min_key_size = 16,
}, {
.uuid = BLE_UUID16_DECLARE(BT_UUID_TBS_STATUS_FLAGS_VAL),
.access_cb = bt_le_nimble_gatts_access_cb_safe,
.arg = NULL,
.descriptors = NULL, /* NULL if no descriptors. Do not include CCCD */
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_READ_ENC,
.min_key_size = 16,
}, {
.uuid = BLE_UUID16_DECLARE(BT_UUID_TBS_INCOMING_URI_VAL),
.access_cb = bt_le_nimble_gatts_access_cb_safe,
.arg = NULL,
.descriptors = NULL, /* NULL if no descriptors. Do not include CCCD */
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_READ_ENC,
.min_key_size = 16,
}, {
.uuid = BLE_UUID16_DECLARE(BT_UUID_TBS_CALL_STATE_VAL),
.access_cb = bt_le_nimble_gatts_access_cb_safe,
.arg = NULL,
.descriptors = NULL, /* NULL if no descriptors. Do not include CCCD */
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_READ_ENC,
.min_key_size = 16,
}, {
.uuid = BLE_UUID16_DECLARE(BT_UUID_TBS_CALL_CONTROL_POINT_VAL),
.access_cb = bt_le_nimble_gatts_access_cb_safe,
.arg = NULL,
.descriptors = NULL, /* NULL if no descriptors. Do not include CCCD */
.flags = BLE_GATT_CHR_F_WRITE_NO_RSP | BLE_GATT_CHR_F_WRITE | \
BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_WRITE_ENC,
.min_key_size = 16,
}, {
.uuid = BLE_UUID16_DECLARE(BT_UUID_TBS_OPTIONAL_OPCODES_VAL),
.access_cb = bt_le_nimble_gatts_access_cb_safe,
.arg = NULL,
.descriptors = NULL, /* NULL if no descriptors. Do not include CCCD */
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_ENC,
.min_key_size = 16,
}, {
.uuid = BLE_UUID16_DECLARE(BT_UUID_TBS_TERMINATE_REASON_VAL),
.access_cb = bt_le_nimble_gatts_access_cb_safe,
.arg = NULL,
.descriptors = NULL, /* NULL if no descriptors. Do not include CCCD */
.flags = BLE_GATT_CHR_F_NOTIFY,
.min_key_size = 16,
}, {
.uuid = BLE_UUID16_DECLARE(BT_UUID_TBS_INCOMING_CALL_VAL),
.access_cb = bt_le_nimble_gatts_access_cb_safe,
.arg = NULL,
.descriptors = NULL, /* NULL if no descriptors. Do not include CCCD */
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_READ_ENC,
.min_key_size = 16,
}, {
.uuid = BLE_UUID16_DECLARE(BT_UUID_TBS_FRIENDLY_NAME_VAL),
.access_cb = bt_le_nimble_gatts_access_cb_safe,
.arg = NULL,
.descriptors = NULL, /* NULL if no descriptors. Do not include CCCD */
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_READ_ENC,
.min_key_size = 16,
}, {
0, /* No more characteristics in this service. */
}
}
},
{
0, /* No more services. */
},
};
int bt_le_nimble_gtbs_attr_handle_set(void)
{
struct bt_gatt_service *gtbs_svc;
uint16_t handle;
int rc;
gtbs_svc = lib_gtbs_svc_get();
assert(gtbs_svc);
LOG_DBG("[N]GtbsAttrHdlSet[%u]", gtbs_svc->attr_count);
rc = ble_gatts_find_svc(BLE_UUID16_DECLARE(BT_UUID_GTBS_VAL), &handle);
if (rc) {
LOG_ERR("[N]GtbsNotFound[%d]", rc);
return rc;
}
LOG_DBG("[N]Hdl[%u]", handle);
for (size_t i = 0; i < gtbs_svc->attr_count; i++) {
(gtbs_svc->attrs + i)->handle = handle + i;
}
return 0;
}
static int gtbs_svc_check(void)
{
struct bt_gatt_service *gtbs_svc;
const struct bt_uuid_16 *uuid;
bool chr_found;
/* This function is used to make sure the characteristics within
* the service exist in the service defined by Zephyr.
*/
gtbs_svc = lib_gtbs_svc_get();
assert(gtbs_svc);
LOG_DBG("[N]GtbsSvcCheck");
for (const struct ble_gatt_chr_def *chr = gatt_svc_gtbs[0].characteristics;
chr && chr->uuid; chr++) {
const ble_uuid16_t *check = (const ble_uuid16_t *)chr->uuid;
chr_found = false;
for (size_t i = 0; i < gtbs_svc->attr_count; i++) {
uuid = (const struct bt_uuid_16 *)(gtbs_svc->attrs + i)->uuid;
if (uuid->uuid.type == BT_LE_NIMBLE_GATT_UUID_TO_Z(check->u.type) &&
uuid->val == check->value) {
chr_found = true;
break;
}
}
if (chr_found == false) {
LOG_ERR("[N]GtbsChrNotFound[%04x]", check->value);
return -1;
}
}
return 0;
}
int bt_le_nimble_gtbs_init(void)
{
int rc;
LOG_DBG("[N]GtbsInit");
rc = ble_gatts_count_cfg(gatt_svc_gtbs);
if (rc) {
LOG_ERR("[N]GtbsCountCfgFail[%d]", rc);
return rc;
}
rc = ble_gatts_add_svcs(gatt_svc_gtbs);
if (rc) {
LOG_ERR("[N]GtbsAddSvcsFail[%d]", rc);
return rc;
}
rc = gtbs_svc_check();
if (rc) {
return rc;
}
return 0;
}
@@ -0,0 +1,25 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef HOST_NIMBLE_PROFILE_TBS_H_
#define HOST_NIMBLE_PROFILE_TBS_H_
#include <stdint.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
int bt_le_nimble_gtbs_attr_handle_set(void);
int bt_le_nimble_gtbs_init(void);
#ifdef __cplusplus
}
#endif
#endif /* HOST_NIMBLE_PROFILE_TBS_H_ */
@@ -0,0 +1,146 @@
/*
* 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 <../host/conn_internal.h>
#include "os/os_mbuf.h"
#include "os/os_mempool.h"
#include "host/ble_att.h"
#include "host/ble_gatt.h"
#include "host/ble_hs_mbuf.h"
#include "nimble/profiles/server.h"
#include "common/host.h"
#include "../../../lib/include/audio.h"
static const struct ble_gatt_svc_def gatt_svc_tmas[] = {
{
/* Telephony and Media Audio Service */
.type = BLE_GATT_SVC_TYPE_PRIMARY,
.uuid = BLE_UUID16_DECLARE(BT_UUID_TMAS_VAL),
.includes = NULL,
.characteristics = (struct ble_gatt_chr_def[])
{
{
.uuid = BLE_UUID16_DECLARE(BT_UUID_GATT_TMAPR_VAL),
.access_cb = bt_le_nimble_gatts_access_cb_safe,
.arg = NULL,
.descriptors = NULL, /* NULL if no descriptors. Do not include CCCD */
.flags = BLE_GATT_CHR_F_READ,
.min_key_size = 0,
.val_handle = NULL,
}, {
0, /* No more characteristics in this service. */
}
}
},
{
0, /* No more services. */
},
};
int bt_le_nimble_tmas_attr_handle_set(void)
{
struct bt_gatt_service *tmas_svc;
uint16_t handle;
int rc;
tmas_svc = lib_tmas_svc_get();
assert(tmas_svc);
LOG_DBG("[N]TmasAttrHdlSet[%u]", tmas_svc->attr_count);
rc = ble_gatts_find_svc(BLE_UUID16_DECLARE(BT_UUID_TMAS_VAL), &handle);
if (rc) {
LOG_ERR("[N]TmasNotFound[%d]", rc);
return rc;
}
LOG_DBG("[N]Hdl[%u]", handle);
for (size_t i = 0; i < tmas_svc->attr_count; i++) {
(tmas_svc->attrs + i)->handle = handle + i;
}
return 0;
}
static int tmas_svc_check(void)
{
struct bt_gatt_service *tmas_svc;
const struct bt_uuid_16 *uuid;
bool chr_found;
/* This function is used to make sure the characteristics within
* the service exist in the service defined by Zephyr.
*/
tmas_svc = lib_tmas_svc_get();
assert(tmas_svc);
LOG_DBG("[N]TmasSvcCheck");
for (const struct ble_gatt_chr_def *chr = gatt_svc_tmas[0].characteristics;
chr && chr->uuid; chr++) {
const ble_uuid16_t *check = (const ble_uuid16_t *)chr->uuid;
chr_found = false;
for (size_t i = 0; i < tmas_svc->attr_count; i++) {
uuid = (const struct bt_uuid_16 *)(tmas_svc->attrs + i)->uuid;
if (uuid->uuid.type == BT_LE_NIMBLE_GATT_UUID_TO_Z(check->u.type) &&
uuid->val == check->value) {
chr_found = true;
break;
}
}
if (chr_found == false) {
LOG_ERR("[N]TmasChrNotFound[%04x]", check->value);
return -1;
}
}
return 0;
}
int bt_le_nimble_tmas_init(void)
{
int rc;
LOG_DBG("[N]TmasInit");
rc = ble_gatts_count_cfg(gatt_svc_tmas);
if (rc) {
LOG_ERR("[N]TmasCountCfgFail[%d]", rc);
return rc;
}
rc = ble_gatts_add_svcs(gatt_svc_tmas);
if (rc) {
LOG_ERR("[N]TmasAddSvcsFail[%d]", rc);
return rc;
}
rc = tmas_svc_check();
if (rc) {
return rc;
}
return 0;
}
@@ -0,0 +1,25 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef HOST_NIMBLE_PROFILE_TMAS_H_
#define HOST_NIMBLE_PROFILE_TMAS_H_
#include <stdint.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
int bt_le_nimble_tmas_attr_handle_set(void);
int bt_le_nimble_tmas_init(void);
#ifdef __cplusplus
}
#endif
#endif /* HOST_NIMBLE_PROFILE_TMAS_H_ */

Some files were not shown because too many files have changed in this diff Show More