diff --git a/doc/connectivity/bluetooth/api/audio/shell/bap.rst b/doc/connectivity/bluetooth/api/audio/shell/bap.rst index 873c4091f60e88..2efbb4e61d14de 100644 --- a/doc/connectivity/bluetooth/api/audio/shell/bap.rst +++ b/doc/connectivity/bluetooth/api/audio/shell/bap.rst @@ -16,7 +16,7 @@ Commands bap --help Subcommands: - init + init : [ase_sink_count, ase_source_count] select_broadcast : create_broadcast : [preset ] [enc ] start_broadcast : diff --git a/doc/releases/migration-guide-4.0.rst b/doc/releases/migration-guide-4.0.rst index bb2c4bf1223ab6..2a45691dbf5c8e 100644 --- a/doc/releases/migration-guide-4.0.rst +++ b/doc/releases/migration-guide-4.0.rst @@ -208,6 +208,19 @@ Bluetooth Audio This needs to be added to all instances of VCP Volume Renderer callback functions defined. (:github:`76992`) +* The Unicast Server has a new registration function :c:func:`bt_bap_unicast_server_register` which + takes a :c:struct:`bt_bap_unicast_server_register_param` as argument. This allows the Unicast + Server to dynamically register Source and Sink ASE count at runtime. The old + :kconfig:option:`CONFIG_BT_ASCS_ASE_SRC_COUNT` and :kconfig:option:`CONFIG_BT_ASCS_ASE_SNK_COUNT` + has been renamed to :kconfig:option:`CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT` and + :kconfig:option:`CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT` to reflect that they now serve as a + compile-time maximum configuration of ASEs to be used. + :c:func:`bt_bap_unicast_server_register` needs to be called once before using the Unicast Server, + and more specfically prior to calling :c:func:`bt_bap_unicast_server_register_cb` for the first + time. It does not need to be called again until the new function + :c:func:`bt_bap_unicast_server_unregister` has been called. + (:github:`76632`) + Bluetooth Classic ================= diff --git a/include/zephyr/bluetooth/audio/bap.h b/include/zephyr/bluetooth/audio/bap.h index 3de92a88ae9626..0c9c5fa0fc95d9 100644 --- a/include/zephyr/bluetooth/audio/bap.h +++ b/include/zephyr/bluetooth/audio/bap.h @@ -635,6 +635,22 @@ struct bt_bap_stream_ops { void (*disconnected)(struct bt_bap_stream *stream, uint8_t reason); }; +/** Structure for registering Unicast Server */ +struct bt_bap_unicast_server_register_param { + /** + * @brief Sink Count to register. + * + * Should be in range [0, @kconfig{CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT}] + */ + uint8_t snk_cnt; + + /** @brief Source Count to register. + * + * Should be in range [0, @kconfig{CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT}] + */ + uint8_t src_cnt; +}; + /** * @brief Register Audio callbacks for a stream. * @@ -1019,11 +1035,41 @@ struct bt_bap_unicast_server_cb { int (*release)(struct bt_bap_stream *stream, struct bt_bap_ascs_rsp *rsp); }; +/** + * @brief Register the Unicast Server. + * + * Register the Unicast Server. Only a single Unicast Server can be registered at any one time. + * This will register ASCS in the GATT database. + * + * @param param Registration parameters for ascs. + * + * @return 0 in case of success, negative error code otherwise. + */ +int bt_bap_unicast_server_register(const struct bt_bap_unicast_server_register_param *param); + +/** + * @brief Unregister the Unicast Server. + * + * Unregister the Unicast Server. + * This will unregister ASCS in the GATT database. + * Before calling this function, any callbacks registered through + * bt_bap_unicast_server_register_cb() needs to be unregistered with + * bt_bap_unicast_server_unregister_cb(). + * + * Calling this function will issue an release operation on any ASE + * in a non-idle state. + * + * @return 0 in case of success, negative error code otherwise. + */ +int bt_bap_unicast_server_unregister(void); + /** * @brief Register unicast server callbacks. * * Only one callback structure can be registered, and attempting to * registering more than one will result in an error. + * Prior to calling this function the Unicast Server needs to be + * registered with bt_bap_unicast_server_register(). * * @param cb Unicast server callback structure. * @@ -1037,6 +1083,9 @@ int bt_bap_unicast_server_register_cb(const struct bt_bap_unicast_server_cb *cb) * May only unregister a callback structure that has previously been * registered by bt_bap_unicast_server_register_cb(). * + * Calling this function will issue an release operation on any ASE + * in a non-idle state. + * * @param cb Unicast server callback structure. * * @return 0 in case of success or negative value in case of error. diff --git a/include/zephyr/bluetooth/audio/gmap.h b/include/zephyr/bluetooth/audio/gmap.h index 0fb5c3b064e2db..edb38d042dad6c 100644 --- a/include/zephyr/bluetooth/audio/gmap.h +++ b/include/zephyr/bluetooth/audio/gmap.h @@ -89,7 +89,7 @@ enum bt_gmap_ugt_feat { /** * @brief Source support * - * Requires @kconfig{CONFIG_BT_ASCS_ASE_SRC_COUNT} > 0 + * Requires @kconfig{CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT} > 0 */ BT_GMAP_UGT_FEAT_SOURCE = BIT(0), /** @@ -101,7 +101,7 @@ enum bt_gmap_ugt_feat { /** * @brief Sink support * - * Requires @kconfig{CONFIG_BT_ASCS_ASE_SNK_COUNT} > 0 + * Requires @kconfig{CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT} > 0 */ BT_GMAP_UGT_FEAT_SINK = BIT(2), /** @@ -119,14 +119,14 @@ enum bt_gmap_ugt_feat { /** * @brief Support for receiving at least two audio channels, each in a separate CIS * - * Requires @kconfig{CONFIG_BT_ASCS_ASE_SNK_COUNT} > 1 and + * Requires @kconfig{CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT} > 1 and * @kconfig{CONFIG_BT_ASCS_MAX_ACTIVE_ASES} > 1, and BT_GMAP_UGT_FEAT_SINK to be set as well */ BT_GMAP_UGT_FEAT_MULTISINK = BIT(5), /** * @brief Support for sending at least two audio channels, each in a separate CIS * - * Requires @kconfig{CONFIG_BT_ASCS_ASE_SRC_COUNT} > 1 and + * Requires @kconfig{CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT} > 1 and * @kconfig{CONFIG_BT_ASCS_MAX_ACTIVE_ASES} > 1, and BT_GMAP_UGT_FEAT_SOURCE to be set * as well */ diff --git a/samples/bluetooth/bap_unicast_server/prj.conf b/samples/bluetooth/bap_unicast_server/prj.conf index 4e72b59df4c914..60230d0d0d1219 100644 --- a/samples/bluetooth/bap_unicast_server/prj.conf +++ b/samples/bluetooth/bap_unicast_server/prj.conf @@ -5,8 +5,8 @@ CONFIG_BT_ISO_PERIPHERAL=y CONFIG_BT_AUDIO=y CONFIG_BT_BAP_UNICAST_SERVER=y CONFIG_BT_ASCS=y -CONFIG_BT_ASCS_ASE_SNK_COUNT=2 -CONFIG_BT_ASCS_ASE_SRC_COUNT=1 +CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT=2 +CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT=1 CONFIG_BT_ISO_TX_BUF_COUNT=2 # Support an ISO channel per ASE CONFIG_BT_ISO_MAX_CHAN=4 diff --git a/samples/bluetooth/bap_unicast_server/src/main.c b/samples/bluetooth/bap_unicast_server/src/main.c index dd57b46597714b..4ea4119ae7fdad 100644 --- a/samples/bluetooth/bap_unicast_server/src/main.c +++ b/samples/bluetooth/bap_unicast_server/src/main.c @@ -29,7 +29,7 @@ BT_AUDIO_CONTEXT_TYPE_MEDIA | \ BT_AUDIO_CONTEXT_TYPE_GAME) -NET_BUF_POOL_FIXED_DEFINE(tx_pool, CONFIG_BT_ASCS_ASE_SRC_COUNT, +NET_BUF_POOL_FIXED_DEFINE(tx_pool, CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT, BT_ISO_SDU_BUF_SIZE(CONFIG_BT_ISO_TX_MTU), CONFIG_BT_CONN_TX_USER_DATA_SIZE, NULL); @@ -40,13 +40,13 @@ static const struct bt_audio_codec_cap lc3_codec_cap = BT_AUDIO_CODEC_CAP_LC3( static struct bt_conn *default_conn; static struct k_work_delayable audio_send_work; -static struct bt_bap_stream sink_streams[CONFIG_BT_ASCS_ASE_SNK_COUNT]; +static struct bt_bap_stream sink_streams[CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT]; static struct audio_source { struct bt_bap_stream stream; uint16_t seq_num; uint16_t max_sdu; size_t len_to_send; -} source_streams[CONFIG_BT_ASCS_ASE_SRC_COUNT]; +} source_streams[CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT]; static size_t configured_source_stream_count; static const struct bt_audio_codec_qos_pref qos_pref = @@ -466,6 +466,11 @@ static int lc3_release(struct bt_bap_stream *stream, struct bt_bap_ascs_rsp *rsp return 0; } +static struct bt_bap_unicast_server_register_param param = { + CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT, + CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT +}; + static const struct bt_bap_unicast_server_cb unicast_server_cb = { .config = lc3_config, .reconfig = lc3_reconfig, @@ -727,6 +732,7 @@ int main(void) printk("Bluetooth initialized\n"); + bt_bap_unicast_server_register(¶m); bt_bap_unicast_server_register_cb(&unicast_server_cb); bt_pacs_cap_register(BT_AUDIO_DIR_SINK, &cap_sink); @@ -780,7 +786,7 @@ int main(void) printk("Advertising successfully started\n"); - if (CONFIG_BT_ASCS_ASE_SRC_COUNT > 0) { + if (CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT > 0) { /* Start send timer */ k_work_init_delayable(&audio_send_work, audio_timer_timeout); } diff --git a/samples/bluetooth/cap_acceptor/prj.conf b/samples/bluetooth/cap_acceptor/prj.conf index 4a67de1e58226d..36da8d2bb04f6d 100644 --- a/samples/bluetooth/cap_acceptor/prj.conf +++ b/samples/bluetooth/cap_acceptor/prj.conf @@ -23,8 +23,8 @@ CONFIG_BT_ATT_PREPARE_COUNT=1 # Support an ISO channel per ASE CONFIG_BT_ASCS=y -CONFIG_BT_ASCS_ASE_SNK_COUNT=1 -CONFIG_BT_ASCS_ASE_SRC_COUNT=1 +CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT=1 +CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT=1 # Support an ISO channel per ASE CONFIG_BT_ISO_MAX_CHAN=2 diff --git a/samples/bluetooth/cap_acceptor/src/cap_acceptor_unicast.c b/samples/bluetooth/cap_acceptor/src/cap_acceptor_unicast.c index a9ae04039d9ed0..cbdb859eb8f1be 100644 --- a/samples/bluetooth/cap_acceptor/src/cap_acceptor_unicast.c +++ b/samples/bluetooth/cap_acceptor/src/cap_acceptor_unicast.c @@ -402,6 +402,17 @@ int init_cap_acceptor_unicast(struct peer_config *peer) if (!cbs_registered) { int err; + struct bt_bap_unicast_server_register_param param = { + CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT, + CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT + }; + + err = bt_bap_unicast_server_register(¶m); + if (err != 0) { + LOG_ERR("Failed to register BAP unicast server: %d", err); + + return -ENOEXEC; + } err = bt_bap_unicast_server_register_cb(&unicast_server_cb); if (err != 0) { diff --git a/samples/bluetooth/hap_ha/prj.conf b/samples/bluetooth/hap_ha/prj.conf index 83d6f70db37621..222da719c760fd 100644 --- a/samples/bluetooth/hap_ha/prj.conf +++ b/samples/bluetooth/hap_ha/prj.conf @@ -18,8 +18,8 @@ CONFIG_BT_ATT_PREPARE_COUNT=1 CONFIG_BT_AUDIO=y CONFIG_BT_BAP_UNICAST_SERVER=y CONFIG_BT_ASCS=y -CONFIG_BT_ASCS_ASE_SNK_COUNT=1 -CONFIG_BT_ASCS_ASE_SRC_COUNT=1 +CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT=1 +CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT=1 # Support an ISO channel per ASE CONFIG_BT_ISO_MAX_CHAN=2 diff --git a/samples/bluetooth/hap_ha/src/bap_unicast_sr.c b/samples/bluetooth/hap_ha/src/bap_unicast_sr.c index 6244bb76bf1101..c671ad0ccd7662 100644 --- a/samples/bluetooth/hap_ha/src/bap_unicast_sr.c +++ b/samples/bluetooth/hap_ha/src/bap_unicast_sr.c @@ -18,7 +18,7 @@ #include #include -NET_BUF_POOL_FIXED_DEFINE(tx_pool, CONFIG_BT_ASCS_ASE_SRC_COUNT, +NET_BUF_POOL_FIXED_DEFINE(tx_pool, CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT, BT_ISO_SDU_BUF_SIZE(CONFIG_BT_ISO_TX_MTU), CONFIG_BT_CONN_TX_USER_DATA_SIZE, NULL); @@ -29,11 +29,12 @@ static const struct bt_audio_codec_cap lc3_codec_cap = BT_AUDIO_CODEC_CAP_LC3( static struct bt_conn *default_conn; static struct k_work_delayable audio_send_work; -static struct bt_bap_stream streams[CONFIG_BT_ASCS_ASE_SNK_COUNT + CONFIG_BT_ASCS_ASE_SRC_COUNT]; +static struct bt_bap_stream streams[CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT + + CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT]; static struct audio_source { struct bt_bap_stream *stream; uint16_t seq_num; -} source_streams[CONFIG_BT_ASCS_ASE_SRC_COUNT]; +} source_streams[CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT]; static size_t configured_source_stream_count; static const struct bt_audio_codec_qos_pref qos_pref = @@ -316,6 +317,11 @@ static int lc3_release(struct bt_bap_stream *stream, struct bt_bap_ascs_rsp *rsp return 0; } +static struct bt_bap_unicast_server_register_param param = { + CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT, + CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT +}; + static const struct bt_bap_unicast_server_cb unicast_server_cb = { .config = lc3_config, .reconfig = lc3_reconfig, @@ -394,6 +400,7 @@ static struct bt_pacs_cap cap_source = { int bap_unicast_sr_init(void) { + bt_bap_unicast_server_register(¶m); bt_bap_unicast_server_register_cb(&unicast_server_cb); bt_pacs_cap_register(BT_AUDIO_DIR_SINK, &cap_sink); diff --git a/samples/bluetooth/tmap_peripheral/prj.conf b/samples/bluetooth/tmap_peripheral/prj.conf index 35f5d15502c2e0..69e721a3c9c77d 100644 --- a/samples/bluetooth/tmap_peripheral/prj.conf +++ b/samples/bluetooth/tmap_peripheral/prj.conf @@ -29,8 +29,8 @@ CONFIG_BT_MCC=y # Support an ISO channel per ASE CONFIG_BT_ASCS=y -CONFIG_BT_ASCS_ASE_SNK_COUNT=1 -CONFIG_BT_ASCS_ASE_SRC_COUNT=1 +CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT=1 +CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT=1 # Support an ISO channel per ASE CONFIG_BT_ISO_MAX_CHAN=2 diff --git a/samples/bluetooth/tmap_peripheral/src/bap_unicast_sr.c b/samples/bluetooth/tmap_peripheral/src/bap_unicast_sr.c index 8e325855e655a1..a4e81dd0838ba3 100644 --- a/samples/bluetooth/tmap_peripheral/src/bap_unicast_sr.c +++ b/samples/bluetooth/tmap_peripheral/src/bap_unicast_sr.c @@ -30,11 +30,12 @@ static const struct bt_audio_codec_cap lc3_codec_cap = (AVAILABLE_SINK_CONTEXT | AVAILABLE_SOURCE_CONTEXT)); static struct bt_conn *default_conn; -static struct bt_bap_stream streams[CONFIG_BT_ASCS_ASE_SNK_COUNT + CONFIG_BT_ASCS_ASE_SRC_COUNT]; +static struct bt_bap_stream streams[CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT + + CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT]; static struct audio_source { struct bt_bap_stream *stream; uint16_t seq_num; -} source_streams[CONFIG_BT_ASCS_ASE_SRC_COUNT]; +} source_streams[CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT]; static size_t configured_source_stream_count; static const struct bt_audio_codec_qos_pref qos_pref = @@ -271,6 +272,11 @@ static int lc3_release(struct bt_bap_stream *stream, struct bt_bap_ascs_rsp *rsp return 0; } +static struct bt_bap_unicast_server_register_param param = { + CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT, + CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT +}; + static const struct bt_bap_unicast_server_cb unicast_server_cb = { .config = lc3_config, .reconfig = lc3_reconfig, @@ -351,6 +357,7 @@ static struct bt_pacs_cap cap = { int bap_unicast_sr_init(void) { + bt_bap_unicast_server_register(¶m); bt_bap_unicast_server_register_cb(&unicast_server_cb); if (IS_ENABLED(CONFIG_BT_PAC_SNK)) { diff --git a/subsys/bluetooth/audio/Kconfig.ascs b/subsys/bluetooth/audio/Kconfig.ascs index acf539f3ac8c6e..61d92c2b4846ef 100644 --- a/subsys/bluetooth/audio/Kconfig.ascs +++ b/subsys/bluetooth/audio/Kconfig.ascs @@ -12,16 +12,16 @@ config BT_ASCS This option enables support for Audio Stream Control Service. if BT_ASCS -config BT_ASCS_ASE_SNK_COUNT - int "Number of Audio Stream Endpoint Sink Characteristics" +config BT_ASCS_MAX_ASE_SNK_COUNT + int "Maximum number of Audio Stream Endpoint Sink Characteristics" default 2 range 0 $(UINT8_MAX) 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_ASE_SRC_COUNT - int "Number of Audio Stream Endpoint Source Characteristics" +config BT_ASCS_MAX_ASE_SRC_COUNT + int "Maximum number of Audio Stream Endpoint Source Characteristics" default 2 range 0 $(UINT8_MAX) help @@ -29,12 +29,12 @@ config BT_ASCS_ASE_SRC_COUNT coupled to a single direction of a unicast Audio Stream. config BT_ASCS_ASE_SNK - def_bool BT_ASCS_ASE_SNK_COUNT > 0 + def_bool BT_ASCS_MAX_ASE_SNK_COUNT > 0 select BT_PAC_SNK select BT_AUDIO_RX config BT_ASCS_ASE_SRC - def_bool BT_ASCS_ASE_SRC_COUNT > 0 + def_bool BT_ASCS_MAX_ASE_SRC_COUNT > 0 select BT_PAC_SRC select BT_AUDIO_TX diff --git a/subsys/bluetooth/audio/ascs.c b/subsys/bluetooth/audio/ascs.c index 113425728ff683..c2256512179f96 100644 --- a/subsys/bluetooth/audio/ascs.c +++ b/subsys/bluetooth/audio/ascs.c @@ -4,6 +4,7 @@ /* * Copyright (c) 2020 Intel Corporation * Copyright (c) 2022-2023 Nordic Semiconductor ASA + * Copyright (c) 2024 Demant A/S * * SPDX-License-Identifier: Apache-2.0 */ @@ -54,8 +55,8 @@ LOG_MODULE_REGISTER(bt_ascs, CONFIG_BT_ASCS_LOG_LEVEL); #define ASE_BUF_SEM_TIMEOUT K_MSEC(CONFIG_BT_ASCS_ASE_BUF_TIMEOUT) #define MAX_ASES_SESSIONS CONFIG_BT_MAX_CONN * \ - (CONFIG_BT_ASCS_ASE_SNK_COUNT + \ - CONFIG_BT_ASCS_ASE_SRC_COUNT) + (CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT + \ + CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT) #define NTF_HEADER_SIZE (3) /* opcode (1) + handle (2) */ @@ -67,13 +68,13 @@ BUILD_ASSERT(CONFIG_BT_ASCS_MAX_ACTIVE_ASES <= MAX(MAX_ASES_SESSIONS, #define ASE_ID(_ase) ase->ep.status.id #define ASE_DIR(_id) \ - (_id > CONFIG_BT_ASCS_ASE_SNK_COUNT ? BT_AUDIO_DIR_SOURCE : BT_AUDIO_DIR_SINK) + (_id > CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT ? BT_AUDIO_DIR_SOURCE : BT_AUDIO_DIR_SINK) #define ASE_UUID(_id) \ - (_id > CONFIG_BT_ASCS_ASE_SNK_COUNT ? BT_UUID_ASCS_ASE_SRC : BT_UUID_ASCS_ASE_SNK) -#define ASE_COUNT (CONFIG_BT_ASCS_ASE_SNK_COUNT + CONFIG_BT_ASCS_ASE_SRC_COUNT) + (_id > CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT ? BT_UUID_ASCS_ASE_SRC : BT_UUID_ASCS_ASE_SNK) +#define ASE_COUNT (CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT + CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT) #define BT_BAP_ASCS_RSP_NULL ((struct bt_bap_ascs_rsp[]) { BT_BAP_ASCS_RSP(0, 0) }) -static struct bt_ascs_ase { +struct bt_ascs_ase { struct bt_conn *conn; struct bt_bap_ep ep; const struct bt_gatt_attr *attr; @@ -81,7 +82,14 @@ static struct bt_ascs_ase { struct k_work_delayable state_transition_work; enum bt_bap_ep_state state_pending; bool unexpected_iso_link_loss; -} ase_pool[CONFIG_BT_ASCS_MAX_ACTIVE_ASES]; +}; + +struct bt_ascs { + /* Whether the service has been registered or not */ + bool registered; + + struct bt_ascs_ase ase_pool[CONFIG_BT_ASCS_MAX_ACTIVE_ASES]; +} ascs; /* Minimum state size when in the codec configured state */ #define MIN_CONFIG_STATE_SIZE (1 + 1 + 1 + 1 + 1 + 2 + 3 + 3 + 3 + 3 + 5 + 1) @@ -825,8 +833,8 @@ static int ascs_iso_accept(const struct bt_iso_accept_info *info, struct bt_iso_ { LOG_DBG("conn %p", (void *)info->acl); - for (size_t i = 0; i < ARRAY_SIZE(ase_pool); i++) { - struct bt_ascs_ase *ase = &ase_pool[i]; + for (size_t i = 0; i < ARRAY_SIZE(ascs.ase_pool); i++) { + struct bt_ascs_ase *ase = &ascs.ase_pool[i]; enum bt_bap_ep_state state; struct bt_iso_chan *chan; @@ -1282,8 +1290,8 @@ int bt_ascs_disable_ase(struct bt_bap_ep *ep) static void disconnected(struct bt_conn *conn, uint8_t reason) { - for (size_t i = 0; i < ARRAY_SIZE(ase_pool); i++) { - struct bt_ascs_ase *ase = &ase_pool[i]; + for (size_t i = 0; i < ARRAY_SIZE(ascs.ase_pool); i++) { + struct bt_ascs_ase *ase = &ascs.ase_pool[i]; if (ase->conn != conn) { continue; @@ -1407,9 +1415,9 @@ static struct bt_ascs_ase *ase_new(struct bt_conn *conn, uint8_t id) __ASSERT(id > 0 && id <= ASE_COUNT, "invalid ASE_ID 0x%02x", id); - for (size_t i = 0; i < ARRAY_SIZE(ase_pool); i++) { - if (ase_pool[i].conn == NULL) { - ase = &ase_pool[i]; + for (size_t i = 0; i < ARRAY_SIZE(ascs.ase_pool); i++) { + if (ascs.ase_pool[i].conn == NULL) { + ase = &ascs.ase_pool[i]; break; } } @@ -1427,8 +1435,8 @@ static struct bt_ascs_ase *ase_new(struct bt_conn *conn, uint8_t id) static struct bt_ascs_ase *ase_find(struct bt_conn *conn, uint8_t id) { - for (size_t i = 0; i < ARRAY_SIZE(ase_pool); i++) { - struct bt_ascs_ase *ase = &ase_pool[i]; + for (size_t i = 0; i < ARRAY_SIZE(ascs.ase_pool); i++) { + struct bt_ascs_ase *ase = &ascs.ase_pool[i]; if (ase->conn == conn && ase->ep.status.id == id) { return ase; @@ -1685,8 +1693,8 @@ static int ase_config(struct bt_ascs_ase *ase, const struct bt_ascs_config *cfg) static struct bt_bap_ep *ep_lookup_stream(struct bt_conn *conn, struct bt_bap_stream *stream) { - for (size_t i = 0; i < ARRAY_SIZE(ase_pool); i++) { - struct bt_ascs_ase *ase = &ase_pool[i]; + for (size_t i = 0; i < ARRAY_SIZE(ascs.ase_pool); i++) { + struct bt_ascs_ase *ase = &ascs.ase_pool[i]; if (ase->conn == conn && ase->ep.stream == stream) { return &ase->ep; @@ -1896,8 +1904,8 @@ static ssize_t ascs_config(struct bt_conn *conn, struct net_buf_simple *buf) void bt_ascs_foreach_ep(struct bt_conn *conn, bt_bap_ep_func_t func, void *user_data) { - for (size_t i = 0; i < ARRAY_SIZE(ase_pool); i++) { - struct bt_ascs_ase *ase = &ase_pool[i]; + for (size_t i = 0; i < ARRAY_SIZE(ascs.ase_pool); i++) { + struct bt_ascs_ase *ase = &ascs.ase_pool[i]; if (ase->conn == conn) { func(&ase->ep, user_data); @@ -3080,22 +3088,120 @@ static ssize_t ascs_cp_write(struct bt_conn *conn, BT_AUDIO_CCC(ascs_ase_cfg_changed) #define BT_ASCS_ASE_SNK_DEFINE(_n, ...) BT_ASCS_ASE_DEFINE(BT_UUID_ASCS_ASE_SNK, (_n) + 1) #define BT_ASCS_ASE_SRC_DEFINE(_n, ...) BT_ASCS_ASE_DEFINE(BT_UUID_ASCS_ASE_SRC, (_n) + 1 + \ - CONFIG_BT_ASCS_ASE_SNK_COUNT) - -BT_GATT_SERVICE_DEFINE(ascs_svc, - BT_GATT_PRIMARY_SERVICE(BT_UUID_ASCS), - BT_AUDIO_CHRC(BT_UUID_ASCS_ASE_CP, - BT_GATT_CHRC_WRITE | BT_GATT_CHRC_WRITE_WITHOUT_RESP | BT_GATT_CHRC_NOTIFY, - BT_GATT_PERM_WRITE_ENCRYPT | BT_GATT_PERM_PREPARE_WRITE, - NULL, ascs_cp_write, NULL), - BT_AUDIO_CCC(ascs_cp_cfg_changed), -#if CONFIG_BT_ASCS_ASE_SNK_COUNT > 0 - LISTIFY(CONFIG_BT_ASCS_ASE_SNK_COUNT, BT_ASCS_ASE_SNK_DEFINE, (,)), -#endif /* CONFIG_BT_ASCS_ASE_SNK_COUNT > 0 */ -#if CONFIG_BT_ASCS_ASE_SRC_COUNT > 0 - LISTIFY(CONFIG_BT_ASCS_ASE_SRC_COUNT, BT_ASCS_ASE_SRC_DEFINE, (,)), -#endif /* CONFIG_BT_ASCS_ASE_SRC_COUNT > 0 */ -); + CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT) + +#define BT_ASCS_CHR_ASE_CONTROL_POINT \ + BT_AUDIO_CHRC(BT_UUID_ASCS_ASE_CP, \ + BT_GATT_CHRC_WRITE | BT_GATT_CHRC_WRITE_WITHOUT_RESP | BT_GATT_CHRC_NOTIFY, \ + BT_GATT_PERM_WRITE_ENCRYPT | BT_GATT_PERM_PREPARE_WRITE, \ + NULL, ascs_cp_write, NULL), \ + BT_AUDIO_CCC(ascs_cp_cfg_changed) + +#if CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT > 0 +#define BT_ASCS_ASE_SINKS \ + LISTIFY(CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT, BT_ASCS_ASE_SNK_DEFINE, (,)), +#else +#define BT_ASCS_ASE_SINKS +#endif /* CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT > 0 */ + +#if CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT > 0 +#define BT_ASCS_ASE_SOURCES \ + LISTIFY(CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT, BT_ASCS_ASE_SRC_DEFINE, (,)), +#else +#define BT_ASCS_ASE_SOURCES +#endif /* CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT > 0 */ + +#define BT_ASCS_SERVICE_DEFINITION() { \ + BT_GATT_PRIMARY_SERVICE(BT_UUID_ASCS), \ + BT_AUDIO_CHRC(BT_UUID_ASCS_ASE_CP, \ + BT_GATT_CHRC_WRITE | BT_GATT_CHRC_WRITE_WITHOUT_RESP | BT_GATT_CHRC_NOTIFY, \ + BT_GATT_PERM_WRITE_ENCRYPT | BT_GATT_PERM_PREPARE_WRITE, \ + NULL, ascs_cp_write, NULL), \ + BT_AUDIO_CCC(ascs_cp_cfg_changed), \ + BT_ASCS_ASE_SINKS \ + BT_ASCS_ASE_SOURCES \ + } + +#define ASCS_ASE_CHAR_ATTR_COUNT 3 /* declaration + value + cccd */ + +static struct bt_gatt_attr ascs_attrs[] = BT_ASCS_SERVICE_DEFINITION(); +static struct bt_gatt_service ascs_svc = (struct bt_gatt_service)BT_GATT_SERVICE(ascs_attrs); + +static void configure_ase_char(uint8_t snk_cnt, uint8_t src_cnt) +{ + uint8_t snk_ases_to_rem = CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT - snk_cnt; + uint8_t src_ases_to_rem = CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT - src_cnt; + size_t attrs_to_rem; + + /* Remove the Source ASEs. The ones to remove will always be at the very tail of the + * attributes, so we just decrease the count withe the amount of sources we want to remove. + */ + attrs_to_rem = src_ases_to_rem * ASCS_ASE_CHAR_ATTR_COUNT; + ascs_svc.attr_count -= attrs_to_rem; + + /* Remove the Sink ASEs. + */ + attrs_to_rem = snk_ases_to_rem * ASCS_ASE_CHAR_ATTR_COUNT; + if (CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT == 0 || CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT + == src_ases_to_rem) { + /* If there are no Source ASEs present, then we can just decrease the + * attribute count + */ + ascs_svc.attr_count -= attrs_to_rem; + } else { + /* As Source ASEs are present, we need to iterate backwards (as this will likely be + * the shortest distance). Find the first Sink to save, and move all Sources + * backwards to it. + */ + size_t src_start_idx = ascs_svc.attr_count - (src_cnt * ASCS_ASE_CHAR_ATTR_COUNT); + size_t new_src_start_idx = src_start_idx - (snk_ases_to_rem * + ASCS_ASE_CHAR_ATTR_COUNT); + + for (size_t i = 0; i < src_cnt * ASCS_ASE_CHAR_ATTR_COUNT; i++) { + ascs_svc.attrs[new_src_start_idx + i] = ascs_svc.attrs[src_start_idx + i]; + } + + ascs_svc.attr_count -= attrs_to_rem; + } +} + +int bt_ascs_register(uint8_t snk_cnt, uint8_t src_cnt) +{ + int err = 0; + + if (ascs.registered) { + LOG_DBG("ASCS already registered"); + + return -EALREADY; + } + + if (snk_cnt > CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT || + src_cnt > CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT) { + LOG_DBG("Provided ASE count above maximum"); + + return -EINVAL; + } + + /* At least one ASE has been registered */ + if (snk_cnt == 0 && src_cnt == 0) { + LOG_DBG("Can't register ASCS with zero ASEs"); + + return -EINVAL; + } + + configure_ase_char(snk_cnt, src_cnt); + + err = bt_gatt_service_register(&ascs_svc); + if (err != 0) { + LOG_DBG("Failed to register ASCS in gatt DB"); + + return err; + } + + ascs.registered = true; + + return err; +} static int control_point_notify(struct bt_conn *conn, const void *data, uint16_t len) { @@ -3111,6 +3217,10 @@ int bt_ascs_init(const struct bt_bap_unicast_server_cb *cb) { int err; + if (!ascs.registered) { + return -ENOTSUP; + } + if (unicast_server_cb != NULL) { return -EALREADY; } @@ -3128,17 +3238,47 @@ int bt_ascs_init(const struct bt_bap_unicast_server_cb *cb) void bt_ascs_cleanup(void) { - for (size_t i = 0; i < ARRAY_SIZE(ase_pool); i++) { - struct bt_ascs_ase *ase = &ase_pool[i]; + for (size_t i = 0; i < ARRAY_SIZE(ascs.ase_pool); i++) { + struct bt_ascs_ase *ase = &ascs.ase_pool[i]; if (ase->conn != NULL) { bt_ascs_release_ase(&ase->ep); } } - if (unicast_server_cb != NULL) { bt_iso_server_unregister(&iso_server); unicast_server_cb = NULL; } } + +int bt_ascs_unregister(void) +{ + int err; + struct bt_gatt_attr _ascs_attrs[] = BT_ASCS_SERVICE_DEFINITION(); + + if (!ascs.registered) { + LOG_DBG("No ascs instance registered"); + return -EALREADY; + } + + for (size_t i = 0; i < ARRAY_SIZE(ascs.ase_pool); i++) { + if (ascs.ase_pool[i].ep.status.state != BT_BAP_EP_STATE_IDLE) { + return -EBUSY; + } + } + + err = bt_gatt_service_unregister(&ascs_svc); + /* If unregistration was succesfull, make sure to reset ascs_attrs so it can be used for + * new registrations + */ + if (err != 0) { + LOG_DBG("Failed to unregister ASCS"); + return err; + } + + memcpy(&ascs_attrs, &_ascs_attrs, sizeof(struct bt_gatt_attr)); + ascs.registered = false; + + return err; +} #endif /* BT_BAP_UNICAST_SERVER */ diff --git a/subsys/bluetooth/audio/ascs_internal.h b/subsys/bluetooth/audio/ascs_internal.h index f96a1905ec5252..67ba2aefe1d060 100644 --- a/subsys/bluetooth/audio/ascs_internal.h +++ b/subsys/bluetooth/audio/ascs_internal.h @@ -3,6 +3,7 @@ * Copyright (c) 2020 Intel Corporation * Copyright (c) 2022-2023 Nordic Semiconductor ASA + * Copyright (c) 2024 Demant A/S * * SPDX-License-Identifier: Apache-2.0 */ @@ -357,4 +358,7 @@ int bt_ascs_release_ase(struct bt_bap_ep *ep); void bt_ascs_foreach_ep(struct bt_conn *conn, bt_bap_ep_func_t func, void *user_data); +int bt_ascs_register(uint8_t snk_cnt, uint8_t src_cnt); +int bt_ascs_unregister(void); + #endif /* BT_ASCS_INTERNAL_H */ diff --git a/subsys/bluetooth/audio/bap_unicast_server.c b/subsys/bluetooth/audio/bap_unicast_server.c index 0c631186c03a49..ee5160e186a30b 100644 --- a/subsys/bluetooth/audio/bap_unicast_server.c +++ b/subsys/bluetooth/audio/bap_unicast_server.c @@ -2,6 +2,7 @@ /* * Copyright (c) 2021-2023 Nordic Semiconductor ASA + * Copyright (c) 2024 Demant A/S * * SPDX-License-Identifier: Apache-2.0 */ @@ -28,6 +29,26 @@ LOG_MODULE_REGISTER(bt_bap_unicast_server, CONFIG_BT_BAP_UNICAST_SERVER_LOG_LEVE static const struct bt_bap_unicast_server_cb *unicast_server_cb; +int bt_bap_unicast_server_register(const struct bt_bap_unicast_server_register_param *param) +{ + if (param == NULL) { + LOG_DBG("param is NULL"); + return -EINVAL; + } + + return bt_ascs_register(param->snk_cnt, param->src_cnt); +} + +int bt_bap_unicast_server_unregister(void) +{ + if (unicast_server_cb != NULL) { + LOG_DBG("Callbacks are still registered"); + return -EAGAIN; + } + + return bt_ascs_unregister(); +} + int bt_bap_unicast_server_register_cb(const struct bt_bap_unicast_server_cb *cb) { int err; @@ -54,7 +75,12 @@ int bt_bap_unicast_server_register_cb(const struct bt_bap_unicast_server_cb *cb) int bt_bap_unicast_server_unregister_cb(const struct bt_bap_unicast_server_cb *cb) { - CHECKIF(cb == NULL) { + if (unicast_server_cb == NULL) { + LOG_DBG("no callback is registered"); + return -EALREADY; + } + + if (cb == NULL) { LOG_DBG("cb is NULL"); return -EINVAL; } diff --git a/subsys/bluetooth/audio/gmap_server.c b/subsys/bluetooth/audio/gmap_server.c index d80003bf210a79..b5c96fe3dade85 100644 --- a/subsys/bluetooth/audio/gmap_server.c +++ b/subsys/bluetooth/audio/gmap_server.c @@ -226,26 +226,27 @@ static bool valid_gmap_features(enum bt_gmap_role role, struct bt_gmap_feat feat } if ((ugt_feat & BT_GMAP_UGT_FEAT_SOURCE) != 0 && - CONFIG_BT_ASCS_ASE_SRC_COUNT == 0) { + CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT == 0) { LOG_DBG("Cannot support BT_GMAP_UGT_FEAT_SOURCE with " - "CONFIG_BT_ASCS_ASE_SRC_COUNT == 0"); + "CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT == 0"); return false; } if ((ugt_feat & BT_GMAP_UGT_FEAT_MULTISOURCE) != 0 && - (CONFIG_BT_ASCS_ASE_SRC_COUNT < 2 || CONFIG_BT_ASCS_MAX_ACTIVE_ASES < 2)) { + (CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT < 2 || CONFIG_BT_ASCS_MAX_ACTIVE_ASES < 2)) { LOG_DBG("Cannot support BT_GMAP_UGT_FEAT_MULTISOURCE with " - "CONFIG_BT_ASCS_ASE_SRC_COUNT (%d) or " + "CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT (%d) or " "CONFIG_BT_ASCS_MAX_ACTIVE_ASES (%d) < 2", - CONFIG_BT_ASCS_ASE_SRC_COUNT, CONFIG_BT_ASCS_MAX_ACTIVE_ASES); + CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT, CONFIG_BT_ASCS_MAX_ACTIVE_ASES); return false; } - if ((ugt_feat & BT_GMAP_UGT_FEAT_SINK) != 0 && CONFIG_BT_ASCS_ASE_SNK_COUNT == 0) { + if ((ugt_feat & BT_GMAP_UGT_FEAT_SINK) != 0 + && CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT == 0) { LOG_DBG("Cannot support BT_GMAP_UGT_FEAT_SINK with " - "CONFIG_BT_ASCS_ASE_SNK_COUNT == 0"); + "CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT == 0"); return false; } @@ -262,11 +263,11 @@ static bool valid_gmap_features(enum bt_gmap_role role, struct bt_gmap_feat feat } if ((ugt_feat & BT_GMAP_UGT_FEAT_MULTISINK) != 0 && - (CONFIG_BT_ASCS_ASE_SNK_COUNT < 2 || CONFIG_BT_ASCS_MAX_ACTIVE_ASES < 2)) { + (CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT < 2 || CONFIG_BT_ASCS_MAX_ACTIVE_ASES < 2)) { LOG_DBG("Cannot support BT_GMAP_UGT_FEAT_MULTISINK with " - "CONFIG_BT_ASCS_ASE_SNK_COUNT (%d) or " + "CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT (%d) or " "CONFIG_BT_ASCS_MAX_ACTIVE_ASES (%d) < 2", - CONFIG_BT_ASCS_ASE_SNK_COUNT, CONFIG_BT_ASCS_MAX_ACTIVE_ASES); + CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT, CONFIG_BT_ASCS_MAX_ACTIVE_ASES); return false; } diff --git a/subsys/bluetooth/audio/shell/audio.h b/subsys/bluetooth/audio/shell/audio.h index 811a0e3aca3f5a..4c8b66f33c0690 100644 --- a/subsys/bluetooth/audio/shell/audio.h +++ b/subsys/bluetooth/audio/shell/audio.h @@ -199,7 +199,8 @@ struct broadcast_sink { #if defined(CONFIG_BT_BAP_UNICAST) #define UNICAST_SERVER_STREAM_COUNT \ - COND_CODE_1(CONFIG_BT_ASCS, (CONFIG_BT_ASCS_ASE_SNK_COUNT + CONFIG_BT_ASCS_ASE_SRC_COUNT), \ + COND_CODE_1(CONFIG_BT_ASCS, \ + (CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT + CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT), \ (0)) #define UNICAST_CLIENT_STREAM_COUNT \ COND_CODE_1(CONFIG_BT_BAP_UNICAST_CLIENT, \ diff --git a/subsys/bluetooth/audio/shell/bap.c b/subsys/bluetooth/audio/shell/bap.c index 089dfcb4960f6c..0cb175ec2eed83 100644 --- a/subsys/bluetooth/audio/shell/bap.c +++ b/subsys/bluetooth/audio/shell/bap.c @@ -3683,7 +3683,47 @@ static int cmd_init(const struct shell *sh, size_t argc, char *argv[]) return -ENOEXEC; } + if (argc != 1 && (IS_ENABLED(CONFIG_BT_BAP_UNICAST_SERVER) && argc != 3)) { + shell_error(sh, "Invalid argument count"); + shell_help(sh); + + return SHELL_CMD_HELP_PRINTED; + } + #if defined(CONFIG_BT_BAP_UNICAST_SERVER) + unsigned long snk_cnt, src_cnt; + struct bt_bap_unicast_server_register_param unicast_server_param = { + CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT, + CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT + }; + + + if (argc == 3) { + snk_cnt = shell_strtoul(argv[1], 0, &err); + if (snk_cnt > CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT) { + shell_error(sh, "Invalid Sink ASE count: %lu. Valid interval: [0, %u]", + snk_cnt, CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT); + + return -ENOEXEC; + } + + unicast_server_param.snk_cnt = snk_cnt; + + src_cnt = shell_strtoul(argv[2], 0, &err); + if (src_cnt > CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT) { + shell_error(sh, "Invalid Source ASE count: %lu. Valid interval: [0, %u]", + src_cnt, CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT); + + return -ENOEXEC; + } + + unicast_server_param.src_cnt = src_cnt; + } else { + snk_cnt = CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT; + src_cnt = CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT; + } + + bt_bap_unicast_server_register(&unicast_server_param); bt_bap_unicast_server_register_cb(&unicast_server_cb); #endif /* CONFIG_BT_BAP_UNICAST_SERVER */ @@ -4004,7 +4044,8 @@ static int cmd_print_ase_info(const struct shell *sh, size_t argc, char *argv[]) "[bcast_flag]" HELP_SEP "[extended ]" HELP_SEP "[vendor ]]" SHELL_STATIC_SUBCMD_SET_CREATE( - bap_cmds, SHELL_CMD_ARG(init, NULL, NULL, cmd_init, 1, 0), + bap_cmds, SHELL_CMD_ARG(init, NULL, NULL, cmd_init, 1, + IS_ENABLED(CONFIG_BT_BAP_UNICAST_SERVER) ? 2 : 0), #if defined(CONFIG_BT_BAP_BROADCAST_SOURCE) SHELL_CMD_ARG(select_broadcast, NULL, "", cmd_select_broadcast_source, 2, 0), SHELL_CMD_ARG(create_broadcast, NULL, "[preset ] [enc ]", diff --git a/subsys/bluetooth/audio/shell/gmap.c b/subsys/bluetooth/audio/shell/gmap.c index 2ec5d86e2d60dd..964fbfbadc7a52 100644 --- a/subsys/bluetooth/audio/shell/gmap.c +++ b/subsys/bluetooth/audio/shell/gmap.c @@ -96,18 +96,18 @@ static void set_gmap_features(struct bt_gmap_feat *features) } if (IS_ENABLED(CONFIG_BT_GMAP_UGT_SUPPORTED)) { -#if CONFIG_BT_ASCS_ASE_SRC_COUNT > 0 +#if CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT > 0 features->ugt_feat |= (BT_GMAP_UGT_FEAT_SOURCE | BT_GMAP_UGT_FEAT_80KBPS_SOURCE); -#if CONFIG_BT_ASCS_ASE_SRC_COUNT > 1 +#if CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT > 1 features->ugt_feat |= BT_GMAP_UGT_FEAT_MULTISOURCE; -#endif /* CONFIG_BT_ASCS_ASE_SRC_COUNT > 1 */ -#endif /* CONFIG_BT_ASCS_ASE_SRC_COUNT > 0 */ -#if CONFIG_BT_ASCS_ASE_SNK_COUNT > 0 +#endif /* CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT > 1 */ +#endif /* CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT > 0 */ +#if CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT > 0 features->ugt_feat |= (BT_GMAP_UGT_FEAT_SINK | BT_GMAP_UGT_FEAT_64KBPS_SINK); -#if CONFIG_BT_ASCS_ASE_SNK_COUNT > 1 +#if CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT > 1 features->ugt_feat |= BT_GMAP_UGT_FEAT_MULTISINK; -#endif /* CONFIG_BT_ASCS_ASE_SNK_COUNT > 1 */ -#endif /* CONFIG_BT_ASCS_ASE_SNK_COUNT > 0 */ +#endif /* CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT > 1 */ +#endif /* CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT > 0 */ } if (IS_ENABLED(CONFIG_BT_GMAP_BGS_SUPPORTED)) { diff --git a/tests/bluetooth/audio/ascs/prj.conf b/tests/bluetooth/audio/ascs/prj.conf index 2ed3485e335841..4b1098ceac6a2a 100644 --- a/tests/bluetooth/audio/ascs/prj.conf +++ b/tests/bluetooth/audio/ascs/prj.conf @@ -7,8 +7,8 @@ CONFIG_BT_ISO_PERIPHERAL=y CONFIG_BT_ISO_MAX_CHAN=1 CONFIG_BT_AUDIO=y CONFIG_BT_ASCS=y -CONFIG_BT_ASCS_ASE_SNK_COUNT=1 -CONFIG_BT_ASCS_ASE_SRC_COUNT=1 +CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT=2 +CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT=2 CONFIG_BT_ASCS_MAX_ACTIVE_ASES=1 CONFIG_BT_BAP_UNICAST_SERVER=y diff --git a/tests/bluetooth/audio/ascs/src/main.c b/tests/bluetooth/audio/ascs/src/main.c index 69e738dceb8251..e91368e230566c 100644 --- a/tests/bluetooth/audio/ascs/src/main.c +++ b/tests/bluetooth/audio/ascs/src/main.c @@ -2,6 +2,7 @@ /* * Copyright (c) 2023 Codecoup + * Copyright (c) 2024 Demant A/S * * SPDX-License-Identifier: Apache-2.0 */ @@ -60,18 +61,26 @@ struct ascs_test_suite_fixture { static void ascs_test_suite_fixture_init(struct ascs_test_suite_fixture *fixture) { + struct bt_bap_unicast_server_register_param param = { + CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT, + CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT + }; + int err; + memset(fixture, 0, sizeof(*fixture)); + err = bt_bap_unicast_server_register(¶m); + fixture->ase_cp = test_ase_control_point_get(); test_conn_init(&fixture->conn); - test_ase_snk_get(1, &fixture->ase_snk.attr); + test_ase_snk_get(CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT, &fixture->ase_snk.attr); if (fixture->ase_snk.attr != NULL) { fixture->ase_snk.id = test_ase_id_get(fixture->ase_snk.attr); } - test_ase_src_get(1, &fixture->ase_src.attr); + test_ase_src_get(CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT, &fixture->ase_src.attr); if (fixture->ase_src.attr != NULL) { fixture->ase_src.id = test_ase_id_get(fixture->ase_src.attr); } @@ -84,11 +93,15 @@ static void *ascs_test_suite_setup(void) fixture = malloc(sizeof(*fixture)); zassert_not_null(fixture); - ascs_test_suite_fixture_init(fixture); - return fixture; } +static void ascs_test_suite_before(void *f) +{ + memset(f, 0, sizeof(struct ascs_test_suite_fixture)); + ascs_test_suite_fixture_init(f); +} + static void ascs_test_suite_teardown(void *f) { free(f); @@ -96,11 +109,15 @@ static void ascs_test_suite_teardown(void *f) static void ascs_test_suite_after(void *f) { - bt_ascs_cleanup(); + /* We skip error-checking this, as somehow this breaks the tests, due to seemingly + * memory corruption, causing incorrect lookup of attributes in following 'before' calls + */ + bt_bap_unicast_server_unregister_cb(&mock_bap_unicast_server_cb); + bt_bap_unicast_server_unregister(); } -ZTEST_SUITE(ascs_test_suite, NULL, ascs_test_suite_setup, NULL, ascs_test_suite_after, - ascs_test_suite_teardown); +ZTEST_SUITE(ascs_test_suite, NULL, ascs_test_suite_setup, ascs_test_suite_before, + ascs_test_suite_after, ascs_test_suite_teardown); ZTEST_F(ascs_test_suite, test_has_sink_ase_chrc) { @@ -136,6 +153,158 @@ ZTEST_F(ascs_test_suite, test_sink_ase_read_state_idle) zassert_equal(0x00, hdr.ase_state, "unexpected ASE_State 0x%02x", hdr.ase_state); } +ZTEST_F(ascs_test_suite, test_cb_register_without_ascs_registered) +{ + int err; + + /* Unregister ASCS, as its registered through setup */ + err = bt_bap_unicast_server_unregister(); + zassert_equal(err, 0, "unexpected err response %d", err); + + err = bt_bap_unicast_server_register_cb(&mock_bap_unicast_server_cb); + zassert_equal(err, -ENOTSUP, "unexpected err response %d", err); +} + +ZTEST_F(ascs_test_suite, test_ascs_register_with_null_param) +{ + int err; + + /* Unregister ASCS, as its registered through setup */ + err = bt_bap_unicast_server_unregister(); + zassert_equal(err, 0, "unexpected err response %d", err); + + err = bt_bap_unicast_server_register(NULL); + zassert_equal(err, -EINVAL, "unexpected err response %d", err); +} + +ZTEST_F(ascs_test_suite, test_ascs_register_twice) +{ + int err; + struct bt_bap_unicast_server_register_param param = { + CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT, + CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT + }; + + /* Setup already registered once, so calling once here should be sufficient */ + err = bt_bap_unicast_server_register(¶m); + zassert_equal(err, -EALREADY, "unexpected err response %d", err); +} + +ZTEST_F(ascs_test_suite, test_ascs_register_too_many_sinks) +{ + int err; + struct bt_bap_unicast_server_register_param param = { + CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT + 1, + CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT + }; + + /* Unregister ASCS, as its registered through setup */ + err = bt_bap_unicast_server_unregister(); + zassert_equal(err, 0, "unexpected err response %d", err); + + err = bt_bap_unicast_server_register(¶m); + zassert_equal(err, -EINVAL, "unexpected err response %d", err); +} + +ZTEST_F(ascs_test_suite, test_ascs_register_too_many_sources) +{ + int err; + struct bt_bap_unicast_server_register_param param = { + CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT, + CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT + 1 + }; + + /* Unregister ASCS, as its registered through setup */ + err = bt_bap_unicast_server_unregister(); + zassert_equal(err, 0, "unexpected err response %d", err); + + err = bt_bap_unicast_server_register(¶m); + zassert_equal(err, -EINVAL, "unexpected err response %d", err); +} + +ZTEST_F(ascs_test_suite, test_ascs_register_zero_ases) +{ + int err; + struct bt_bap_unicast_server_register_param param = { + 0, + 0 + }; + + /* Unregister ASCS, as its registered through setup */ + err = bt_bap_unicast_server_unregister(); + zassert_equal(err, 0, "unexpected err response %d", err); + + err = bt_bap_unicast_server_register(¶m); + zassert_equal(err, -EINVAL, "unexpected err response %d", err); +} + +ZTEST_F(ascs_test_suite, test_ascs_register_fewer_than_max_ases) +{ + int err; + struct bt_bap_unicast_server_register_param param = { + CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT > 0 ? CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT - 1 : 0, + CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT > 0 ? CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT - 1 : 0 + }; + + /* Unregister ASCS, as its registered through setup */ + err = bt_bap_unicast_server_unregister(); + zassert_equal(err, 0, "unexpected err response %d", err); + + err = bt_bap_unicast_server_register(¶m); + zassert_equal(err, 0, "unexpected err response %d", err); +} + +ZTEST_F(ascs_test_suite, test_ascs_unregister_without_register) +{ + int err; + + /* Unregister ASCS, as its registered through setup */ + err = bt_bap_unicast_server_unregister(); + zassert_equal(err, 0, "unexpected err response %d", err); + + err = bt_bap_unicast_server_unregister(); + zassert_equal(err, -EALREADY, "unexpected err response %d", err); +} + +ZTEST_F(ascs_test_suite, test_ascs_unregister_with_ases_in_config_state) +{ + const struct test_ase_chrc_value_hdr *hdr; + const struct bt_gatt_attr *ase; + struct bt_bap_stream *stream = &fixture->stream; + struct bt_conn *conn = &fixture->conn; + struct bt_gatt_notify_params *notify_params; + uint8_t ase_id; + int err; + + if (IS_ENABLED(CONFIG_BT_ASCS_ASE_SNK)) { + ase = fixture->ase_snk.attr; + ase_id = fixture->ase_snk.id; + } else { + ase = fixture->ase_src.attr; + ase_id = fixture->ase_src.id; + } + + zexpect_not_null(ase); + zexpect_true(ase_id != 0x00); + + err = bt_bap_unicast_server_register_cb(&mock_bap_unicast_server_cb); + zassert_equal(err, 0, "unexpected err response %d", err); + + /* Set ASE to non-idle state */ + test_ase_control_client_config_codec(conn, ase_id, stream); + + err = bt_bap_unicast_server_unregister_cb(&mock_bap_unicast_server_cb); + zassert_equal(err, 0, "unexpected err response %d", err); + + err = bt_bap_unicast_server_unregister(); + + /* Expected to notify the upper layers */ + expect_bt_bap_unicast_server_cb_release_called_once(stream); + expect_bt_bap_stream_ops_released_called_once(stream); + + zassert_equal(err, 0, "unexpected err response %d", err); +} + ZTEST_F(ascs_test_suite, test_release_ase_on_callback_unregister) { const struct test_ase_chrc_value_hdr *hdr; @@ -144,6 +313,7 @@ ZTEST_F(ascs_test_suite, test_release_ase_on_callback_unregister) struct bt_conn *conn = &fixture->conn; struct bt_gatt_notify_params *notify_params; uint8_t ase_id; + int err; if (IS_ENABLED(CONFIG_BT_ASCS_ASE_SNK)) { ase = fixture->ase_snk.attr; @@ -156,7 +326,8 @@ ZTEST_F(ascs_test_suite, test_release_ase_on_callback_unregister) zexpect_not_null(ase); zexpect_true(ase_id != 0x00); - bt_bap_unicast_server_register_cb(&mock_bap_unicast_server_cb); + err = bt_bap_unicast_server_register_cb(&mock_bap_unicast_server_cb); + zassert_equal(err, 0, "unexpected err response %d", err); /* Set ASE to non-idle state */ test_ase_control_client_config_codec(conn, ase_id, stream); @@ -225,6 +396,7 @@ ZTEST_F(ascs_test_suite, test_release_ase_on_acl_disconnection) const struct bt_gatt_attr *ase; struct bt_iso_chan *chan; uint8_t ase_id; + int err; if (IS_ENABLED(CONFIG_BT_ASCS_ASE_SNK)) { ase = fixture->ase_snk.attr; @@ -237,7 +409,8 @@ ZTEST_F(ascs_test_suite, test_release_ase_on_acl_disconnection) zexpect_not_null(ase); zexpect_true(ase_id != 0x00); - bt_bap_unicast_server_register_cb(&mock_bap_unicast_server_cb); + err = bt_bap_unicast_server_register_cb(&mock_bap_unicast_server_cb); + zassert_equal(err, 0, "unexpected err response %d", err); /* Set ASE to non-idle state */ test_preamble_state_streaming(conn, ase_id, stream, &chan, @@ -282,7 +455,8 @@ ZTEST_F(ascs_test_suite, test_release_ase_pair_on_acl_disconnection) ase_src_id = fixture->ase_src.id; zexpect_true(ase_src_id != 0x00); - bt_bap_unicast_server_register_cb(&mock_bap_unicast_server_cb); + err = bt_bap_unicast_server_register_cb(&mock_bap_unicast_server_cb); + zassert_equal(err, 0, "unexpected err response %d", err); test_ase_control_client_config_codec(conn, ase_snk_id, &snk_stream); test_ase_control_client_config_qos(conn, ase_snk_id); @@ -327,10 +501,12 @@ ZTEST_F(ascs_test_suite, test_recv_in_streaming_state) }; struct bt_iso_chan *chan; struct net_buf buf; + int err; Z_TEST_SKIP_IFNDEF(CONFIG_BT_ASCS_ASE_SNK); - bt_bap_unicast_server_register_cb(&mock_bap_unicast_server_cb); + err = bt_bap_unicast_server_register_cb(&mock_bap_unicast_server_cb); + zassert_equal(err, 0, "unexpected err response %d", err); test_preamble_state_streaming(conn, ase_id, stream, &chan, false); @@ -357,7 +533,8 @@ ZTEST_F(ascs_test_suite, test_recv_in_enabling_state) Z_TEST_SKIP_IFNDEF(CONFIG_BT_ASCS_ASE_SNK); - bt_bap_unicast_server_register_cb(&mock_bap_unicast_server_cb); + err = bt_bap_unicast_server_register_cb(&mock_bap_unicast_server_cb); + zassert_equal(err, 0, "unexpected err response %d", err); test_preamble_state_enabling(conn, ase_id, stream); @@ -381,6 +558,7 @@ ZTEST_F(ascs_test_suite, test_cis_link_loss_in_streaming_state) const struct bt_gatt_attr *ase; struct bt_iso_chan *chan; uint8_t ase_id; + int err; if (IS_ENABLED(CONFIG_BT_ASCS_ASE_SNK)) { ase = fixture->ase_snk.attr; @@ -392,7 +570,8 @@ ZTEST_F(ascs_test_suite, test_cis_link_loss_in_streaming_state) zexpect_not_null(ase); zexpect_true(ase_id != 0x00); - bt_bap_unicast_server_register_cb(&mock_bap_unicast_server_cb); + err = bt_bap_unicast_server_register_cb(&mock_bap_unicast_server_cb); + zassert_equal(err, 0, "unexpected err response %d", err); test_preamble_state_streaming(conn, ase_id, stream, &chan, !IS_ENABLED(CONFIG_BT_ASCS_ASE_SNK)); @@ -426,7 +605,8 @@ static void test_cis_link_loss_in_disabling_state(struct ascs_test_suite_fixture zexpect_not_null(ase); zexpect_true(ase_id != 0x00); - bt_bap_unicast_server_register_cb(&mock_bap_unicast_server_cb); + err = bt_bap_unicast_server_register_cb(&mock_bap_unicast_server_cb); + zassert_equal(err, 0, "unexpected err response %d", err); test_preamble_state_enabling(conn, ase_id, stream); err = mock_bt_iso_accept(conn, 0x01, 0x01, &chan); @@ -485,7 +665,8 @@ ZTEST_F(ascs_test_suite, test_cis_link_loss_in_enabling_state) zexpect_not_null(ase); zexpect_true(ase_id != 0x00); - bt_bap_unicast_server_register_cb(&mock_bap_unicast_server_cb); + err = bt_bap_unicast_server_register_cb(&mock_bap_unicast_server_cb); + zassert_equal(err, 0, "unexpected err response %d", err); test_preamble_state_enabling(conn, ase_id, stream); err = mock_bt_iso_accept(conn, 0x01, 0x01, &chan); @@ -532,7 +713,8 @@ ZTEST_F(ascs_test_suite, test_cis_link_loss_in_enabling_state_client_retries) zexpect_not_null(ase); zexpect_true(ase_id != 0x00); - bt_bap_unicast_server_register_cb(&mock_bap_unicast_server_cb); + err = bt_bap_unicast_server_register_cb(&mock_bap_unicast_server_cb); + zassert_equal(err, 0, "unexpected err response %d", err); test_preamble_state_enabling(conn, ase_id, stream); err = mock_bt_iso_accept(conn, 0x01, 0x01, &chan); @@ -606,7 +788,8 @@ ZTEST_F(ascs_test_suite, test_ase_state_notification_retry) cp = test_ase_control_point_get(); zexpect_not_null(cp); - bt_bap_unicast_server_register_cb(&mock_bap_unicast_server_cb); + err = bt_bap_unicast_server_register_cb(&mock_bap_unicast_server_cb); + zassert_equal(err, 0, "unexpected err response %d", err); stream_allocated = stream; mock_bap_unicast_server_cb_config_fake.custom_fake = unicast_server_cb_config_custom_fake; diff --git a/tests/bluetooth/audio/ascs/src/test_ase_control_params.c b/tests/bluetooth/audio/ascs/src/test_ase_control_params.c index a89af5bf170d97..45605a538f7e6d 100644 --- a/tests/bluetooth/audio/ascs/src/test_ase_control_params.c +++ b/tests/bluetooth/audio/ascs/src/test_ase_control_params.c @@ -2,6 +2,7 @@ /* * Copyright (c) 2023 Codecoup + * Copyright (c) 2024 Demant A/S * * SPDX-License-Identifier: Apache-2.0 */ @@ -41,30 +42,50 @@ static void *test_ase_control_params_setup(void) fixture = malloc(sizeof(*fixture)); zassert_not_null(fixture); - test_conn_init(&fixture->conn); - fixture->ase_cp = test_ase_control_point_get(); - - if (IS_ENABLED(CONFIG_BT_ASCS_ASE_SNK)) { - test_ase_snk_get(1, &fixture->ase); - } else { - test_ase_src_get(1, &fixture->ase); - } - return fixture; } static void test_ase_control_params_before(void *f) { struct test_ase_control_params_fixture *fixture = f; + struct bt_bap_unicast_server_register_param param = { + CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT, + CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT + }; + int err; ARG_UNUSED(fixture); - bt_bap_unicast_server_register_cb(&mock_bap_unicast_server_cb); + err = bt_bap_unicast_server_register(¶m); + zassert_equal(err, 0, "unexpected err response %d", err); + + err = bt_bap_unicast_server_register_cb(&mock_bap_unicast_server_cb); + zassert_equal(err, 0, "unexpected err response %d", err); + + test_conn_init(&fixture->conn); + fixture->ase_cp = test_ase_control_point_get(); + + if (IS_ENABLED(CONFIG_BT_ASCS_ASE_SNK)) { + test_ase_snk_get(CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT, &fixture->ase); + } else { + test_ase_src_get(CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT, &fixture->ase); + } + } static void test_ase_control_params_after(void *f) { - bt_bap_unicast_server_unregister_cb(&mock_bap_unicast_server_cb); + int err; + + err = bt_bap_unicast_server_unregister_cb(&mock_bap_unicast_server_cb); + zassert_equal(err, 0, "unexpected err response %d", err); + + err = bt_bap_unicast_server_unregister(); + while (err != 0) { + zassert_equal(err, -EBUSY, "unexpected err response %d", err); + k_sleep(K_MSEC(10)); + err = bt_bap_unicast_server_unregister(); + } } static void test_ase_control_params_teardown(void *f) @@ -171,7 +192,8 @@ ZTEST_F(test_ase_control_params, test_codec_configure_number_of_ases_0x00) ZTEST_F(test_ase_control_params, test_codec_configure_number_of_ases_above_max) { - const uint16_t ase_cnt = CONFIG_BT_ASCS_ASE_SNK_COUNT + CONFIG_BT_ASCS_ASE_SRC_COUNT + 1; + const uint16_t ase_cnt = CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT + + CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT + 1; /* Skip if number of ASEs configured is high enough to support any value in the write req */ if (ase_cnt > UINT8_MAX) { @@ -367,13 +389,13 @@ static int unicast_server_cb_config_custom_fake(struct bt_conn *conn, const stru ZTEST_F(test_ase_control_params, test_codec_configure_invalid_ase_id_unavailable) { /* Test requires support for at least 2 ASEs */ - if (CONFIG_BT_ASCS_ASE_SNK_COUNT + CONFIG_BT_ASCS_ASE_SRC_COUNT < 2) { + if (CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT + CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT < 2) { ztest_test_skip(); } const uint8_t ase_id_valid = 0x01; - const uint8_t ase_id_invalid = CONFIG_BT_ASCS_ASE_SNK_COUNT + - CONFIG_BT_ASCS_ASE_SRC_COUNT + 1; + const uint8_t ase_id_invalid = CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT + + CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT + 1; const uint8_t buf[] = { 0x01, /* Opcode = Config Codec */ 0x02, /* Number_of_ASEs */ @@ -546,7 +568,8 @@ ZTEST_F(test_ase_control_params, test_config_qos_number_of_ases_0x00) ZTEST_F(test_ase_control_params, test_config_qos_number_of_ases_above_max) { - const uint16_t ase_cnt = CONFIG_BT_ASCS_ASE_SNK_COUNT + CONFIG_BT_ASCS_ASE_SRC_COUNT + 1; + const uint16_t ase_cnt = CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT + + CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT + 1; /* Skip if number of ASEs configured is high enough to support any value in the write req */ if (ase_cnt > UINT8_MAX) { @@ -655,7 +678,8 @@ ZTEST_F(test_ase_control_params, test_enable_number_of_ases_0x00) ZTEST_F(test_ase_control_params, test_enable_number_of_ases_above_max) { - const uint16_t ase_cnt = CONFIG_BT_ASCS_ASE_SNK_COUNT + CONFIG_BT_ASCS_ASE_SRC_COUNT + 1; + const uint16_t ase_cnt = CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT + + CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT + 1; /* Skip if number of ASEs configured is high enough to support any value in the write req */ if (ase_cnt > UINT8_MAX) { @@ -720,13 +744,13 @@ ZTEST_F(test_ase_control_params, test_enable_metadata_too_short) ZTEST_F(test_ase_control_params, test_enable_invalid_ase_id) { /* Test requires support for at least 2 ASEs */ - if (CONFIG_BT_ASCS_ASE_SNK_COUNT + CONFIG_BT_ASCS_ASE_SRC_COUNT < 2) { + if (CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT + CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT < 2) { ztest_test_skip(); } const uint8_t ase_id_valid = 0x01; - const uint8_t ase_id_invalid = CONFIG_BT_ASCS_ASE_SNK_COUNT + - CONFIG_BT_ASCS_ASE_SRC_COUNT + 1; + const uint8_t ase_id_invalid = CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT + + CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT + 1; const uint8_t buf[] = { 0x03, /* Opcode = Enable */ 0x02, /* Number_of_ASEs */ @@ -831,7 +855,7 @@ ZTEST_F(test_ase_control_params, test_receiver_start_ready_number_of_ases_0x00) ZTEST_F(test_ase_control_params, test_receiver_start_ready_number_of_ases_above_max) { - const uint16_t ase_cnt = CONFIG_BT_ASCS_ASE_SRC_COUNT + 1; + const uint16_t ase_cnt = CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT + 1; const struct bt_gatt_attr *ase; Z_TEST_SKIP_IFNDEF(CONFIG_BT_ASCS_ASE_SRC); @@ -932,7 +956,8 @@ ZTEST_F(test_ase_control_params, test_disable_number_of_ases_0x00) ZTEST_F(test_ase_control_params, test_disable_number_of_ases_above_max) { - const uint16_t ase_cnt = CONFIG_BT_ASCS_ASE_SNK_COUNT + CONFIG_BT_ASCS_ASE_SRC_COUNT + 1; + const uint16_t ase_cnt = CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT + + CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT + 1; /* Skip if number of ASEs configured is high enough to support any value in the write req */ if (ase_cnt > UINT8_MAX) { @@ -1021,7 +1046,7 @@ ZTEST_F(test_ase_control_params, test_receiver_stop_ready_number_of_ases_0x00) ZTEST_F(test_ase_control_params, test_receiver_stop_ready_number_of_ases_above_max) { - const uint16_t ase_cnt = CONFIG_BT_ASCS_ASE_SRC_COUNT + 1; + const uint16_t ase_cnt = CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT + 1; const struct bt_gatt_attr *ase; Z_TEST_SKIP_IFNDEF(CONFIG_BT_ASCS_ASE_SRC); @@ -1123,7 +1148,8 @@ ZTEST_F(test_ase_control_params, test_update_metadata_number_of_ases_0x00) ZTEST_F(test_ase_control_params, test_update_metadata_number_of_ases_above_max) { - const uint16_t ase_cnt = CONFIG_BT_ASCS_ASE_SNK_COUNT + CONFIG_BT_ASCS_ASE_SRC_COUNT + 1; + const uint16_t ase_cnt = CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT + + CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT + 1; /* Skip if number of ASEs configured is high enough to support any value in the write req */ if (ase_cnt > UINT8_MAX) { @@ -1188,13 +1214,13 @@ ZTEST_F(test_ase_control_params, test_update_metadata_metadata_too_short) ZTEST_F(test_ase_control_params, test_update_metadata_invalid_ase_id) { /* Test requires support for at least 2 ASEs */ - if (CONFIG_BT_ASCS_ASE_SNK_COUNT + CONFIG_BT_ASCS_ASE_SRC_COUNT < 2) { + if (CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT + CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT < 2) { ztest_test_skip(); } const uint8_t ase_id_valid = 0x01; - const uint8_t ase_id_invalid = CONFIG_BT_ASCS_ASE_SNK_COUNT + - CONFIG_BT_ASCS_ASE_SRC_COUNT + 1; + const uint8_t ase_id_invalid = CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT + + CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT + 1; const uint8_t buf[] = { 0x07, /* Opcode = Update Metadata */ 0x02, /* Number_of_ASEs */ @@ -1260,7 +1286,8 @@ ZTEST_F(test_ase_control_params, test_release_number_of_ases_0x00) ZTEST_F(test_ase_control_params, test_release_number_of_ases_above_max) { - const uint16_t ase_cnt = CONFIG_BT_ASCS_ASE_SNK_COUNT + CONFIG_BT_ASCS_ASE_SRC_COUNT + 1; + const uint16_t ase_cnt = CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT + + CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT + 1; /* Skip if number of ASEs configured is high enough to support any value in the write req */ if (ase_cnt > UINT8_MAX) { diff --git a/tests/bluetooth/audio/ascs/src/test_ase_state_transition.c b/tests/bluetooth/audio/ascs/src/test_ase_state_transition.c index 0d4e6928d5f8d2..f93e5276f391ad 100644 --- a/tests/bluetooth/audio/ascs/src/test_ase_state_transition.c +++ b/tests/bluetooth/audio/ascs/src/test_ase_state_transition.c @@ -2,6 +2,7 @@ /* * Copyright (c) 2023 Codecoup + * Copyright (c) 2024 Demant A/S * * SPDX-License-Identifier: Apache-2.0 */ @@ -47,24 +48,74 @@ static void *test_sink_ase_state_transition_setup(void) fixture = malloc(sizeof(*fixture)); zassert_not_null(fixture); - memset(fixture, 0, sizeof(*fixture)); + return fixture; +} + +static void test_ase_snk_state_transition_before(void *f) +{ + struct test_ase_state_transition_fixture *fixture = + (struct test_ase_state_transition_fixture *) f; + struct bt_bap_unicast_server_register_param param = { + CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT, + CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT + }; + int err; + + err = bt_bap_unicast_server_register(¶m); + zassert_equal(err, 0, "unexpected err response %d", err); + + err = bt_bap_unicast_server_register_cb(&mock_bap_unicast_server_cb); + zassert_equal(err, 0, "unexpected err response %d", err); + + memset(fixture, 0, sizeof(struct test_ase_state_transition_fixture)); test_conn_init(&fixture->conn); test_ase_snk_get(1, &fixture->ase.attr); if (fixture->ase.attr != NULL) { fixture->ase.id = test_ase_id_get(fixture->ase.attr); } - return fixture; + bt_bap_stream_cb_register(&fixture->stream, &mock_bap_stream_ops); } -static void test_ase_state_transition_before(void *f) +static void test_ase_src_state_transition_before(void *f) { - bt_bap_unicast_server_register_cb(&mock_bap_unicast_server_cb); + struct test_ase_state_transition_fixture *fixture = + (struct test_ase_state_transition_fixture *) f; + struct bt_bap_unicast_server_register_param param = { + CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT, + CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT + }; + int err; + + err = bt_bap_unicast_server_register(¶m); + zassert_equal(err, 0, "unexpected err response %d", err); + + err = bt_bap_unicast_server_register_cb(&mock_bap_unicast_server_cb); + zassert_equal(err, 0, "unexpected err response %d", err); + + memset(fixture, 0, sizeof(struct test_ase_state_transition_fixture)); + test_conn_init(&fixture->conn); + test_ase_src_get(CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT, &fixture->ase.attr); + if (fixture->ase.attr != NULL) { + fixture->ase.id = test_ase_id_get(fixture->ase.attr); + } + + bt_bap_stream_cb_register(&fixture->stream, &mock_bap_stream_ops); } static void test_ase_state_transition_after(void *f) { - bt_bap_unicast_server_unregister_cb(&mock_bap_unicast_server_cb); + int err; + + err = bt_bap_unicast_server_unregister_cb(&mock_bap_unicast_server_cb); + zassert_equal(err, 0, "unexpected err response %d", err); + + err = bt_bap_unicast_server_unregister(); + while (err != 0) { + zassert_equal(err, -EBUSY, "unexpected err response %d", err); + k_sleep(K_MSEC(10)); + err = bt_bap_unicast_server_unregister(); + } } static void test_ase_state_transition_teardown(void *f) @@ -73,7 +124,7 @@ static void test_ase_state_transition_teardown(void *f) } ZTEST_SUITE(test_sink_ase_state_transition, NULL, test_sink_ase_state_transition_setup, - test_ase_state_transition_before, test_ase_state_transition_after, + test_ase_snk_state_transition_before, test_ase_state_transition_after, test_ase_state_transition_teardown); ZTEST_F(test_sink_ase_state_transition, test_client_idle_to_codec_configured) @@ -90,7 +141,6 @@ ZTEST_F(test_sink_ase_state_transition, test_client_idle_to_codec_configured) expect_bt_bap_unicast_server_cb_config_called_once(conn, EMPTY, BT_AUDIO_DIR_SINK, EMPTY); expect_bt_bap_stream_ops_configured_called_once(stream, EMPTY); } - ZTEST_F(test_sink_ase_state_transition, test_client_codec_configured_to_qos_configured) { struct bt_bap_stream *stream = &fixture->stream; @@ -602,7 +652,7 @@ static void *test_source_ase_state_transition_setup(void) memset(fixture, 0, sizeof(*fixture)); test_conn_init(&fixture->conn); - test_ase_src_get(1, &fixture->ase.attr); + test_ase_src_get(CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT, &fixture->ase.attr); if (fixture->ase.attr != NULL) { fixture->ase.id = test_ase_id_get(fixture->ase.attr); } @@ -611,7 +661,7 @@ static void *test_source_ase_state_transition_setup(void) } ZTEST_SUITE(test_source_ase_state_transition, NULL, test_source_ase_state_transition_setup, - test_ase_state_transition_before, test_ase_state_transition_after, + test_ase_src_state_transition_before, test_ase_state_transition_after, test_ase_state_transition_teardown); ZTEST_F(test_source_ase_state_transition, test_client_idle_to_codec_configured) diff --git a/tests/bluetooth/audio/ascs/src/test_ase_state_transition_invalid.c b/tests/bluetooth/audio/ascs/src/test_ase_state_transition_invalid.c index c36943c0956acf..454a3d85ac402b 100644 --- a/tests/bluetooth/audio/ascs/src/test_ase_state_transition_invalid.c +++ b/tests/bluetooth/audio/ascs/src/test_ase_state_transition_invalid.c @@ -2,6 +2,7 @@ /* * Copyright (c) 2023 Codecoup + * Copyright (c) 2024 Demant A/S * * SPDX-License-Identifier: Apache-2.0 */ @@ -40,23 +41,46 @@ static void *test_ase_state_transition_invalid_setup(void) fixture = malloc(sizeof(*fixture)); zassert_not_null(fixture); - memset(fixture, 0, sizeof(*fixture)); - fixture->ase_cp = test_ase_control_point_get(); - test_conn_init(&fixture->conn); - test_ase_snk_get(1, &fixture->ase_snk); - test_ase_src_get(1, &fixture->ase_src); return fixture; } static void test_ase_state_transition_invalid_before(void *f) { - bt_bap_unicast_server_register_cb(&mock_bap_unicast_server_cb); + struct test_ase_state_transition_invalid_fixture *fixture = + (struct test_ase_state_transition_invalid_fixture *)f; + struct bt_bap_unicast_server_register_param param = { + CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT, + CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT + }; + int err; + + err = bt_bap_unicast_server_register(¶m); + zassert_equal(err, 0, "unexpected err response %d", err); + + err = bt_bap_unicast_server_register_cb(&mock_bap_unicast_server_cb); + zassert_equal(err, 0, "unexpected err response %d", err); + + memset(fixture, 0, sizeof(struct test_ase_state_transition_invalid_fixture)); + fixture->ase_cp = test_ase_control_point_get(); + test_conn_init(&fixture->conn); + test_ase_snk_get(CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT, &fixture->ase_snk); + test_ase_src_get(CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT, &fixture->ase_src); } static void test_ase_state_transition_invalid_after(void *f) { - bt_bap_unicast_server_unregister_cb(&mock_bap_unicast_server_cb); + int err; + + err = bt_bap_unicast_server_unregister_cb(&mock_bap_unicast_server_cb); + zassert_equal(err, 0, "unexpected err response %d", err); + + err = bt_bap_unicast_server_unregister(); + while (err != 0) { + zassert_equal(err, -EBUSY, "unexpected err response %d", err); + k_sleep(K_MSEC(10)); + err = bt_bap_unicast_server_unregister(); + } } static void test_ase_state_transition_invalid_teardown(void *f) diff --git a/tests/bluetooth/audio/ascs/testcase.yaml b/tests/bluetooth/audio/ascs/testcase.yaml index e646ea28bbf118..ba6e549c306b70 100644 --- a/tests/bluetooth/audio/ascs/testcase.yaml +++ b/tests/bluetooth/audio/ascs/testcase.yaml @@ -8,11 +8,11 @@ tests: bluetooth.audio.ascs.test_snk_only: type: unit extra_configs: - - CONFIG_BT_ASCS_ASE_SRC_COUNT=0 + - CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT=0 bluetooth.audio.ascs.test_src_only: type: unit extra_configs: - - CONFIG_BT_ASCS_ASE_SNK_COUNT=0 + - CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT=0 bluetooth.audio.ascs.test_unicast_client_enabled: type: unit extra_configs: diff --git a/tests/bluetooth/audio/mocks/CMakeLists.txt b/tests/bluetooth/audio/mocks/CMakeLists.txt index ead819b901abc0..4f12849fc2e827 100644 --- a/tests/bluetooth/audio/mocks/CMakeLists.txt +++ b/tests/bluetooth/audio/mocks/CMakeLists.txt @@ -1,5 +1,6 @@ # # Copyright (c) 2023 Codecoup +# Coperight (c) 2024 Demant A/S # # SPDX-License-Identifier: Apache-2.0 # @@ -24,6 +25,14 @@ target_include_directories(mocks PUBLIC ${ZEPHYR_BASE}/tests/bluetooth/audio ${ZEPHYR_BASE}/subsys/bluetooth ${ZEPHYR_BASE}/subsys/bluetooth/audio + ${ZEPHYR_BASE}/subsys/bluetooth/common + ${ZEPHYR_BASE}/include/zephyr +) + +target_sources(testbinary PRIVATE + ${ZEPHYR_BASE}/subsys/bluetooth/common/bt_str.c + ${ZEPHYR_BASE}/subsys/bluetooth/host/uuid.c + ${ZEPHYR_BASE}/include/zephyr/kernel.h ) add_subdirectory(${ZEPHYR_BASE}/tests/bluetooth/host host_mocks) diff --git a/tests/bluetooth/audio/mocks/include/gatt.h b/tests/bluetooth/audio/mocks/include/gatt.h index 43b56dac29e451..619d35f13e9c68 100644 --- a/tests/bluetooth/audio/mocks/include/gatt.h +++ b/tests/bluetooth/audio/mocks/include/gatt.h @@ -20,5 +20,7 @@ DECLARE_FAKE_VALUE_FUNC(bool, mock_bt_gatt_is_subscribed, struct bt_conn *, void bt_gatt_notify_cb_reset(void); uint16_t bt_gatt_get_mtu(struct bt_conn *conn); +int bt_gatt_service_register(struct bt_gatt_service *svc); +int bt_gatt_service_unregister(struct bt_gatt_service *svc); #endif /* MOCKS_GATT_H_ */ diff --git a/tests/bluetooth/audio/mocks/src/gatt.c b/tests/bluetooth/audio/mocks/src/gatt.c index 3a9db441cb517c..a158b13d176d2c 100644 --- a/tests/bluetooth/audio/mocks/src/gatt.c +++ b/tests/bluetooth/audio/mocks/src/gatt.c @@ -1,18 +1,30 @@ /* * Copyright (c) 2023 Codecoup + * Copyright (c) 2024 Demant A/S * * SPDX-License-Identifier: Apache-2.0 */ +#include +#include #include +#include + +#include +#include +#include #include #include #include #include +#include #include +#include +#include #include "gatt.h" #include "conn.h" +#include "common/bt_str.h" #define LOG_LEVEL CONFIG_BT_GATT_LOG_LEVEL #include @@ -28,6 +40,9 @@ DEFINE_FAKE_VALUE_FUNC(int, mock_bt_gatt_notify_cb, struct bt_conn *, DEFINE_FAKE_VALUE_FUNC(bool, mock_bt_gatt_is_subscribed, struct bt_conn *, const struct bt_gatt_attr *, uint16_t); +static uint16_t last_static_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE; +static sys_slist_t db; + ssize_t bt_gatt_attr_read_service(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, uint16_t len, uint16_t offset) { @@ -182,9 +197,6 @@ void bt_gatt_notify_cb_reset(void) RESET_FAKE(mock_bt_gatt_notify_cb); } -#define foreach_attr_type_dyndb(...) -#define last_static_handle BT_ATT_LAST_ATTRIBUTE_HANDLE - /* Exact copy of subsys/bluetooth/host/gatt.c:gatt_foreach_iter() */ static uint8_t gatt_foreach_iter(const struct bt_gatt_attr *attr, uint16_t handle, uint16_t start_handle, @@ -226,6 +238,39 @@ static uint8_t gatt_foreach_iter(const struct bt_gatt_attr *attr, return result; } +/* Exact copy of subsys/bluetooth/host/gatt.c:foreach_attr_type_dyndb() */ +static void foreach_attr_type_dyndb(uint16_t start_handle, uint16_t end_handle, + const struct bt_uuid *uuid, const void *attr_data, + uint16_t num_matches, bt_gatt_attr_func_t func, void *user_data) +{ + size_t i; + struct bt_gatt_service *svc; + + LOG_DBG("foreach_attr_type_dyndb"); + + SYS_SLIST_FOR_EACH_CONTAINER(&db, svc, node) { + struct bt_gatt_service *next; + + next = SYS_SLIST_PEEK_NEXT_CONTAINER(svc, node); + if (next) { + /* Skip ahead if start is not within service handles */ + if (next->attrs[0].handle <= start_handle) { + continue; + } + } + + for (i = 0; i < svc->attr_count; i++) { + struct bt_gatt_attr *attr = &svc->attrs[i]; + + if (gatt_foreach_iter(attr, attr->handle, start_handle, end_handle, uuid, + attr_data, &num_matches, func, + user_data) == BT_GATT_ITER_STOP) { + return; + } + } + } +} + /* Exact copy of subsys/bluetooth/host/gatt.c:bt_gatt_foreach_attr_type() */ void bt_gatt_foreach_attr_type(uint16_t start_handle, uint16_t end_handle, const struct bt_uuid *uuid, @@ -234,6 +279,8 @@ void bt_gatt_foreach_attr_type(uint16_t start_handle, uint16_t end_handle, { size_t i; + LOG_DBG("bt_gatt_foreach_attr_type"); + if (!num_matches) { num_matches = UINT16_MAX; } @@ -255,17 +302,163 @@ void bt_gatt_foreach_attr_type(uint16_t start_handle, uint16_t end_handle, attr_data, &num_matches, func, user_data) == BT_GATT_ITER_STOP) { + LOG_DBG("Returning after searching static DB"); return; } } } } + LOG_DBG("foreach_attr_type_dyndb"); /* Iterate over dynamic db */ foreach_attr_type_dyndb(start_handle, end_handle, uuid, attr_data, num_matches, func, user_data); } +static void bt_gatt_service_init(void) +{ + last_static_handle = 0U; + + STRUCT_SECTION_FOREACH(bt_gatt_service_static, svc) { + last_static_handle += svc->attr_count; + } +} + +/* Exact copy of subsys/bluetooth/host/gatt.c:found_attr() */ +static uint8_t found_attr(const struct bt_gatt_attr *attr, uint16_t handle, void *user_data) +{ + const struct bt_gatt_attr **found = user_data; + + *found = attr; + + return BT_GATT_ITER_STOP; +} + +/* Exact copy of subsys/bluetooth/host/gatt.c:find_attr() */ +static const struct bt_gatt_attr *find_attr(uint16_t handle) +{ + const struct bt_gatt_attr *attr = NULL; + + bt_gatt_foreach_attr(handle, handle, found_attr, &attr); + + return attr; +} + +/* Exact copy of subsys/bluetooth/host/gatt.c:gatt_insert() */ +static void gatt_insert(struct bt_gatt_service *svc, uint16_t last_handle) +{ + struct bt_gatt_service *tmp, *prev = NULL; + + if (last_handle == 0 || svc->attrs[0].handle > last_handle) { + sys_slist_append(&db, &svc->node); + return; + } + + /* DB shall always have its service in ascending order */ + SYS_SLIST_FOR_EACH_CONTAINER(&db, tmp, node) { + if (tmp->attrs[0].handle > svc->attrs[0].handle) { + if (prev) { + sys_slist_insert(&db, &prev->node, &svc->node); + } else { + sys_slist_prepend(&db, &svc->node); + } + return; + } + + prev = tmp; + } +} + +/* Exact copy of subsys/bluetooth/host/gatt.c:gatt_register() */ +static int gatt_register(struct bt_gatt_service *svc) +{ + struct bt_gatt_service *last; + uint16_t handle, last_handle; + struct bt_gatt_attr *attrs = svc->attrs; + uint16_t count = svc->attr_count; + + if (sys_slist_is_empty(&db)) { + handle = last_static_handle; + last_handle = 0; + goto populate; + } + + last = SYS_SLIST_PEEK_TAIL_CONTAINER(&db, last, node); + handle = last->attrs[last->attr_count - 1].handle; + last_handle = handle; + +populate: + /* Populate the handles and append them to the list */ + for (; attrs && count; attrs++, count--) { + if (!attrs->handle) { + /* Allocate handle if not set already */ + attrs->handle = ++handle; + } else if (attrs->handle > handle) { + /* Use existing handle if valid */ + handle = attrs->handle; + } else if (find_attr(attrs->handle)) { + /* Service has conflicting handles */ + LOG_ERR("Mock: Unable to register handle 0x%04x", attrs->handle); + return -EINVAL; + } + + LOG_DBG("attr %p handle 0x%04x uuid %s perm 0x%02x", attrs, attrs->handle, + bt_uuid_str(attrs->uuid), attrs->perm); + } + + gatt_insert(svc, last_handle); + + return 0; +} + +static int gatt_unregister(struct bt_gatt_service *svc) +{ + if (!sys_slist_find_and_remove(&db, &svc->node)) { + return -ENOENT; + } + + return 0; +} + +int bt_gatt_service_register(struct bt_gatt_service *svc) +{ + int err; + + __ASSERT(svc, "invalid parameters\n"); + __ASSERT(svc->attrs, "invalid parameters\n"); + __ASSERT(svc->attr_count, "invalid parameters\n"); + + /* Init GATT core services */ + bt_gatt_service_init(); + + /* Do no allow to register mandatory services twice */ + if (!bt_uuid_cmp(svc->attrs[0].uuid, BT_UUID_GAP) || + !bt_uuid_cmp(svc->attrs[0].uuid, BT_UUID_GATT)) { + return -EALREADY; + } + + err = gatt_register(svc); + if (err < 0) { + return err; + } + + return 0; +} + +int bt_gatt_service_unregister(struct bt_gatt_service *svc) +{ + int err; + + __ASSERT(svc, "invalid parameters\n"); + + err = gatt_unregister(svc); + if (err) { + return err; + } + + return 0; +} + /* Exact copy of subsys/bluetooth/host/gatt.c:bt_gatt_attr_read() */ ssize_t bt_gatt_attr_read(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, uint16_t buf_len, uint16_t offset, diff --git a/tests/bluetooth/shell/audio.conf b/tests/bluetooth/shell/audio.conf index e783677ad0fc50..404a04c885279b 100644 --- a/tests/bluetooth/shell/audio.conf +++ b/tests/bluetooth/shell/audio.conf @@ -58,8 +58,8 @@ CONFIG_BT_ISO_RX_MTU=310 CONFIG_BT_AUDIO=y CONFIG_BT_BAP_UNICAST_SERVER=y -CONFIG_BT_ASCS_ASE_SNK_COUNT=2 -CONFIG_BT_ASCS_ASE_SRC_COUNT=2 +CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT=2 +CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT=2 CONFIG_BT_BAP_UNICAST_CLIENT=y CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT=4 @@ -70,8 +70,8 @@ CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE=255 CONFIG_BT_AUDIO_CODEC_CAP_MAX_METADATA_SIZE=255 CONFIG_BT_ASCS=y -CONFIG_BT_ASCS_ASE_SNK_COUNT=2 -CONFIG_BT_ASCS_ASE_SRC_COUNT=2 +CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT=2 +CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT=2 CONFIG_BT_BAP_UNICAST_CLIENT=y CONFIG_BT_BAP_BROADCAST_SOURCE=y CONFIG_BT_BAP_BROADCAST_SRC_SUBGROUP_COUNT=4 diff --git a/tests/bluetooth/shell/testcase.yaml b/tests/bluetooth/shell/testcase.yaml index 4a3bca95fb11bb..269d9319b7cbff 100644 --- a/tests/bluetooth/shell/testcase.yaml +++ b/tests/bluetooth/shell/testcase.yaml @@ -262,12 +262,12 @@ tests: extra_args: CONF_FILE="audio.conf" build_only: true extra_configs: - - CONFIG_BT_ASCS_ASE_SNK_COUNT=0 + - CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT=0 bluetooth.audio_shell.no_server_ase_src: extra_args: CONF_FILE="audio.conf" build_only: true extra_configs: - - CONFIG_BT_ASCS_ASE_SRC_COUNT=0 + - CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT=0 bluetooth.audio_shell.no_client_ase_snk: extra_args: CONF_FILE="audio.conf" build_only: true @@ -294,14 +294,14 @@ tests: extra_configs: - CONFIG_BT_BAP_BROADCAST_SOURCE=n - CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT=0 - - CONFIG_BT_ASCS_ASE_SRC_COUNT=0 + - CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT=0 bluetooth.audio_shell.no_audio_rx: extra_args: CONF_FILE="audio.conf" build_only: true extra_configs: - CONFIG_BT_BAP_BROADCAST_SINK=n - CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT=0 - - CONFIG_BT_ASCS_ASE_SNK_COUNT=0 + - CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT=0 bluetooth.audio_shell.no_has: extra_args: CONF_FILE="audio.conf" build_only: true diff --git a/tests/bluetooth/tester/overlay-le-audio.conf b/tests/bluetooth/tester/overlay-le-audio.conf index 6b0186e55d8595..d0c40206f0a8c0 100644 --- a/tests/bluetooth/tester/overlay-le-audio.conf +++ b/tests/bluetooth/tester/overlay-le-audio.conf @@ -57,8 +57,8 @@ CONFIG_BT_BUF_ACL_RX_SIZE=255 # ASCS CONFIG_BT_ASCS=y -CONFIG_BT_ASCS_ASE_SNK_COUNT=2 -CONFIG_BT_ASCS_ASE_SRC_COUNT=2 +CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT=2 +CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT=2 # Support an ISO channel per ASE CONFIG_BT_ISO_MAX_CHAN=4 diff --git a/tests/bluetooth/tester/src/audio/btp_bap_audio_stream.c b/tests/bluetooth/tester/src/audio/btp_bap_audio_stream.c index e294cacbaea18f..6cd9bad48a5e08 100644 --- a/tests/bluetooth/tester/src/audio/btp_bap_audio_stream.c +++ b/tests/bluetooth/tester/src/audio/btp_bap_audio_stream.c @@ -21,7 +21,7 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME, CONFIG_BTTESTER_LOG_LEVEL); #include "btp/btp.h" #include "btp_bap_audio_stream.h" -NET_BUF_POOL_FIXED_DEFINE(tx_pool, MAX(CONFIG_BT_ASCS_ASE_SRC_COUNT, +NET_BUF_POOL_FIXED_DEFINE(tx_pool, MAX(CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT, CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT), BT_ISO_SDU_BUF_SIZE(CONFIG_BT_ISO_TX_MTU), CONFIG_BT_CONN_TX_USER_DATA_SIZE, NULL); diff --git a/tests/bluetooth/tester/src/audio/btp_bap_unicast.c b/tests/bluetooth/tester/src/audio/btp_bap_unicast.c index 531605689fcf9b..0a78441f0132cf 100644 --- a/tests/bluetooth/tester/src/audio/btp_bap_unicast.c +++ b/tests/bluetooth/tester/src/audio/btp_bap_unicast.c @@ -897,6 +897,11 @@ static void discover_cb(struct bt_conn *conn, int err, enum bt_audio_dir dir) btp_send_discovery_completed_ev(conn, BTP_BAP_DISCOVERY_STATUS_SUCCESS); } +static struct bt_bap_unicast_server_register_param param = { + CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT, + CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT +}; + static struct bt_bap_unicast_client_cb unicast_client_cbs = { .location = unicast_client_location_cb, .available_contexts = available_contexts_cb, @@ -1652,6 +1657,13 @@ int btp_bap_unicast_init(void) (void)memset(connections, 0, sizeof(connections)); + err = bt_bap_unicast_server_register(¶m); + if (err != 0) { + LOG_DBG("Failed to register unicast server (err %d)\n", err); + + return err; + } + err = bt_bap_unicast_server_register_cb(&unicast_server_cb); if (err != 0) { LOG_DBG("Failed to register client callbacks: %d", err); diff --git a/tests/bluetooth/tester/src/audio/btp_bap_unicast.h b/tests/bluetooth/tester/src/audio/btp_bap_unicast.h index e4111289da8c6c..1ac0bac1aa9353 100644 --- a/tests/bluetooth/tester/src/audio/btp_bap_unicast.h +++ b/tests/bluetooth/tester/src/audio/btp_bap_unicast.h @@ -9,9 +9,9 @@ #include #define BTP_BAP_UNICAST_MAX_SNK_STREAMS_COUNT MIN(CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT, \ - CONFIG_BT_ASCS_ASE_SNK_COUNT) + CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT) #define BTP_BAP_UNICAST_MAX_SRC_STREAMS_COUNT MIN(CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT, \ - CONFIG_BT_ASCS_ASE_SRC_COUNT) + CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT) #define BTP_BAP_UNICAST_MAX_STREAMS_COUNT BTP_BAP_UNICAST_MAX_SNK_STREAMS_COUNT + \ BTP_BAP_UNICAST_MAX_SRC_STREAMS_COUNT #define BTP_BAP_UNICAST_MAX_END_POINTS_COUNT CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT + \ diff --git a/tests/bsim/bluetooth/audio/prj.conf b/tests/bsim/bluetooth/audio/prj.conf index 7b3d19740e0080..f10854441e2332 100644 --- a/tests/bsim/bluetooth/audio/prj.conf +++ b/tests/bsim/bluetooth/audio/prj.conf @@ -28,8 +28,8 @@ CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT=4 CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT=2 CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT=2 CONFIG_BT_ASCS=y -CONFIG_BT_ASCS_ASE_SNK_COUNT=2 -CONFIG_BT_ASCS_ASE_SRC_COUNT=2 +CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT=2 +CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT=2 CONFIG_BT_BAP_BROADCAST_SOURCE=y CONFIG_BT_BAP_BROADCAST_SINK=y CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE=196 diff --git a/tests/bsim/bluetooth/audio/src/bap_unicast_server_test.c b/tests/bsim/bluetooth/audio/src/bap_unicast_server_test.c index 7d4d097a615da0..c48d86732e7d86 100644 --- a/tests/bsim/bluetooth/audio/src/bap_unicast_server_test.c +++ b/tests/bsim/bluetooth/audio/src/bap_unicast_server_test.c @@ -68,7 +68,7 @@ static const struct bt_audio_codec_cap lc3_codec_cap = { }; static struct audio_test_stream - test_streams[CONFIG_BT_ASCS_ASE_SNK_COUNT + CONFIG_BT_ASCS_ASE_SRC_COUNT]; + test_streams[CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT + CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT]; static const struct bt_audio_codec_qos_pref qos_pref = BT_AUDIO_CODEC_QOS_PREF(true, BT_GAP_LE_PHY_2M, 0x02, 10, 40000, 40000, 40000, 40000); @@ -225,6 +225,11 @@ static int lc3_release(struct bt_bap_stream *stream, struct bt_bap_ascs_rsp *rsp return 0; } +static struct bt_bap_unicast_server_register_param param = { + CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT, + CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT +}; + static const struct bt_bap_unicast_server_cb unicast_server_cb = { .config = lc3_config, .reconfig = lc3_reconfig, @@ -487,6 +492,13 @@ static void init(void) printk("Bluetooth initialized\n"); + err = bt_bap_unicast_server_register(¶m); + if (err != 0) { + FAIL("Failed to register unicast server (err %d)\n", err); + + return; + } + bt_bap_unicast_server_register_cb(&unicast_server_cb); err = bt_pacs_cap_register(BT_AUDIO_DIR_SINK, &cap); diff --git a/tests/bsim/bluetooth/audio/src/cap_acceptor_test.c b/tests/bsim/bluetooth/audio/src/cap_acceptor_test.c index 3d424eafa39a5b..dbbc308718eb6e 100644 --- a/tests/bsim/bluetooth/audio/src/cap_acceptor_test.c +++ b/tests/bsim/bluetooth/audio/src/cap_acceptor_test.c @@ -76,8 +76,8 @@ static uint32_t bis_index_bitfield; #define UNICAST_CHANNEL_COUNT_1 BIT(0) -static struct bt_cap_stream unicast_streams[CONFIG_BT_ASCS_ASE_SNK_COUNT + - CONFIG_BT_ASCS_ASE_SRC_COUNT]; +static struct bt_cap_stream unicast_streams[CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT + + CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT]; static bool subgroup_data_func_cb(struct bt_data *data, void *user_data) { @@ -560,6 +560,11 @@ static int unicast_server_release(struct bt_bap_stream *stream, struct bt_bap_as return 0; } +static struct bt_bap_unicast_server_register_param param = { + CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT, + CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT +}; + static struct bt_bap_unicast_server_cb unicast_server_cbs = { .config = unicast_server_config, .reconfig = unicast_server_reconfig, @@ -728,6 +733,13 @@ static void init(void) return; } + err = bt_bap_unicast_server_register(¶m); + if (err != 0) { + FAIL("Failed to register unicast server (err %d)\n", err); + + return; + } + err = bt_bap_unicast_server_register_cb(&unicast_server_cbs); if (err != 0) { FAIL("Failed to register unicast server callbacks (err %d)\n", diff --git a/tests/bsim/bluetooth/audio/src/gmap_ugt_test.c b/tests/bsim/bluetooth/audio/src/gmap_ugt_test.c index 4ac3c1cfe0e869..09de70135fefa6 100644 --- a/tests/bsim/bluetooth/audio/src/gmap_ugt_test.c +++ b/tests/bsim/bluetooth/audio/src/gmap_ugt_test.c @@ -48,7 +48,7 @@ static const struct bt_audio_codec_qos_pref unicast_qos_pref = #define UNICAST_CHANNEL_COUNT_1 BIT(0) static struct bt_cap_stream - unicast_streams[CONFIG_BT_ASCS_ASE_SNK_COUNT + CONFIG_BT_ASCS_ASE_SRC_COUNT]; + unicast_streams[CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT + CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT]; CREATE_FLAG(flag_unicast_stream_started); CREATE_FLAG(flag_gmap_discovered); @@ -219,6 +219,11 @@ static int unicast_server_release(struct bt_bap_stream *stream, struct bt_bap_as return 0; } +static struct bt_bap_unicast_server_register_param param = { + CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT, + CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT +}; + static struct bt_bap_unicast_server_cb unicast_server_cbs = { .config = unicast_server_config, .reconfig = unicast_server_reconfig, @@ -404,6 +409,13 @@ static void test_main(void) return; } + err = bt_bap_unicast_server_register(¶m); + if (err != 0) { + FAIL("Failed to register unicast server (err %d)\n", err); + + return; + } + err = bt_bap_unicast_server_register_cb(&unicast_server_cbs); if (err != 0) { FAIL("Failed to register unicast server callbacks (err %d)\n", err);