From a9a18f8fc3a90d62ed5e5b6c03da20020280651e Mon Sep 17 00:00:00 2001 From: Fredrik Danebjer Date: Fri, 2 Aug 2024 11:08:57 +0200 Subject: [PATCH] Bluetooth: ascs: Add dynamic ASE registration Added option to set the ASE count through the bap API, making ASE configuration runtime available. The upper limit of ASEs are still bound by the Kconfig options set for ASEs. Signed-off-by: Fredrik Danebjer --- include/zephyr/bluetooth/audio/bap.h | 29 +++ include/zephyr/bluetooth/audio/gmap.h | 8 +- samples/bluetooth/bap_unicast_server/prj.conf | 8 +- .../bluetooth/bap_unicast_server/src/main.c | 14 +- samples/bluetooth/cap_acceptor/prj.conf | 4 +- .../cap_acceptor/src/cap_acceptor_unicast.c | 11 + samples/bluetooth/hap_ha/prj.conf | 4 +- samples/bluetooth/hap_ha/src/bap_unicast_sr.c | 13 +- samples/bluetooth/tmap_peripheral/prj.conf | 4 +- .../tmap_peripheral/src/bap_unicast_sr.c | 11 +- subsys/bluetooth/audio/Kconfig.ascs | 12 +- subsys/bluetooth/audio/ascs.c | 144 +++++++++++-- subsys/bluetooth/audio/ascs_internal.h | 4 + subsys/bluetooth/audio/bap_unicast_server.c | 12 ++ subsys/bluetooth/audio/gmap_server.c | 21 +- subsys/bluetooth/audio/shell/audio.h | 3 +- subsys/bluetooth/audio/shell/bap.c | 6 + subsys/bluetooth/audio/shell/gmap.c | 16 +- tests/bluetooth/audio/ascs/prj.conf | 4 +- tests/bluetooth/audio/ascs/src/main.c | 63 ++---- .../audio/ascs/src/test_ase_control_params.c | 66 +++--- .../ascs/src/test_ase_state_transition.c | 45 +++- .../src/test_ase_state_transition_invalid.c | 20 +- tests/bluetooth/audio/ascs/testcase.yaml | 4 +- tests/bluetooth/audio/mocks/CMakeLists.txt | 9 + tests/bluetooth/audio/mocks/include/gatt.h | 2 + tests/bluetooth/audio/mocks/src/gatt.c | 201 +++++++++++++++++- tests/bluetooth/shell/audio.conf | 8 +- tests/bluetooth/shell/testcase.yaml | 8 +- tests/bluetooth/tester/overlay-le-audio.conf | 4 +- .../tester/src/audio/btp_bap_audio_stream.c | 2 +- .../tester/src/audio/btp_bap_unicast.c | 12 ++ .../tester/src/audio/btp_bap_unicast.h | 4 +- tests/bsim/bluetooth/audio/prj.conf | 4 +- .../audio/src/bap_unicast_server_test.c | 14 +- .../bluetooth/audio/src/cap_acceptor_test.c | 16 +- .../bsim/bluetooth/audio/src/gmap_ugt_test.c | 14 +- 37 files changed, 648 insertions(+), 176 deletions(-) diff --git a/include/zephyr/bluetooth/audio/bap.h b/include/zephyr/bluetooth/audio/bap.h index 9e8317be0a6add0..858c6b057a79228 100644 --- a/include/zephyr/bluetooth/audio/bap.h +++ b/include/zephyr/bluetooth/audio/bap.h @@ -1019,6 +1019,35 @@ struct bt_bap_unicast_server_cb { int (*release)(struct bt_bap_stream *stream, struct bt_bap_ascs_rsp *rsp); }; + +struct bt_bap_unicast_server_register_param { + /* Sink Count to register */ + uint8_t snk_cnt; + /* Source Count to register */ + uint8_t src_cnt; +}; + +/** + * @brief Register ASCS in gatt DB. + * + * Register ASCS in gatt DB. This allows the user to set the number + * ASEs to be used, between 0 and BT_ASCS_MAX_ASE_SNK_COUNT / + * BT_ASCS_MAX_ASE_SRC_COUNT. + * + * @param param Registration parameters for ascs. + * + * @return 0 in case of success. + */ +int bt_bap_unicast_server_register(const struct bt_bap_unicast_server_register_param *param); + +/** + * @brief Unregister ASCS in gatt DB. + * + * Register ASCS in gatt DB. This will also clear out any callbacks + * registered by bt_bap_unicast_server_register_cb(). + */ +void bt_bap_unicast_server_unregister(void); + /** * @brief Register unicast server callbacks. * diff --git a/include/zephyr/bluetooth/audio/gmap.h b/include/zephyr/bluetooth/audio/gmap.h index 0fb5c3b064e2dbc..edb38d042dad6c1 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 2705d0c1895642c..a80b779e5730663 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 @@ -16,3 +16,7 @@ CONFIG_BT_ATT_PREPARE_COUNT=1 CONFIG_BT_EXT_ADV=y CONFIG_BT_DEVICE_NAME="Unicast Audio Server" + +CONFIG_BT_ASCS_LOG_LEVEL_DBG=y +#CONFIG_BT_GATT_LOG_LEVEL_DBG=y +CONFIG_LOG_BUFFER_SIZE=2048 \ No newline at end of file diff --git a/samples/bluetooth/bap_unicast_server/src/main.c b/samples/bluetooth/bap_unicast_server/src/main.c index 90bff48719f67f4..bd61142e5fed9b6 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, @@ -722,6 +727,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); @@ -775,7 +781,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 4a67de1e58226d6..36da8d2bb04f6dc 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 9015eb409955a8d..cfc6e7f5b655f81 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 c492cdeb1ecbcc7..938d851fbcdf819 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 6244bb76bf11019..c671ad0ccd76621 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 35f5d15502c2e07..69e721a3c9c77db 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 8e325855e655a1d..a4e81dd0838ba32 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 acf539f3ac8c6e9..61d92c2b4846ef1 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 17aeda10edb3119..d78acd7bf6912ac 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,10 +68,10 @@ 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 { @@ -3080,22 +3081,100 @@ 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_service_register(uint8_t snk_cnt, uint8_t src_cnt) +{ + int err = 0; + + if (snk_cnt < CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT || + src_cnt < CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT) { + configure_ase_char(snk_cnt, src_cnt); + } + + err = bt_gatt_service_register(&ascs_svc); + + if (err != 0) { + LOG_ERR("Failed to register ASCS in gatt DB"); + } + + return err; +} static int control_point_notify(struct bt_conn *conn, const void *data, uint16_t len) { @@ -3135,10 +3214,31 @@ void bt_ascs_cleanup(void) bt_ascs_release_ase(&ase->ep); } } - if (unicast_server_cb != NULL) { bt_iso_server_unregister(&iso_server); unicast_server_cb = NULL; } } + +int bt_ascs_service_unregister(void) +{ + int err; + + bt_ascs_cleanup(); + 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_ERR("Failed to unregister ASCS"); + } else { + struct bt_gatt_attr _ascs_attrs[] = BT_ASCS_SERVICE_DEFINITION(); + + memcpy(&ascs_attrs, &_ascs_attrs, sizeof(struct bt_gatt_attr)); + } + + LOG_DBG("Unregister ASCS returning with err=%d", err); + + return err; +} #endif /* BT_BAP_UNICAST_SERVER */ diff --git a/subsys/bluetooth/audio/ascs_internal.h b/subsys/bluetooth/audio/ascs_internal.h index f96a1905ec52525..9f4732b929ea5ea 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_service_register(uint8_t snk_cnt, uint8_t src_cnt); +int bt_ascs_service_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 0c631186c03a490..25a54ef6912aacf 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,17 @@ 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) +{ + LOG_DBG("reg"); + return bt_ascs_service_register(param->snk_cnt, param->src_cnt); +} + +void bt_bap_unicast_server_unregister(void) +{ + bt_ascs_service_unregister(); +} + int bt_bap_unicast_server_register_cb(const struct bt_bap_unicast_server_cb *cb) { int err; diff --git a/subsys/bluetooth/audio/gmap_server.c b/subsys/bluetooth/audio/gmap_server.c index d80003bf210a79d..b5c96fe3dade852 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 a13879c4c9f4a78..7c6bf99b93e1430 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 9dcffab16354081..12c9bb444b46fc8 100644 --- a/subsys/bluetooth/audio/shell/bap.c +++ b/subsys/bluetooth/audio/shell/bap.c @@ -752,6 +752,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 unicast_server_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, @@ -3650,6 +3655,7 @@ static int cmd_init(const struct shell *sh, size_t argc, char *argv[]) } #if defined(CONFIG_BT_BAP_UNICAST_SERVER) + bt_bap_unicast_server_register(&unicast_server_param); bt_bap_unicast_server_register_cb(&unicast_server_cb); #endif /* CONFIG_BT_BAP_UNICAST_SERVER */ diff --git a/subsys/bluetooth/audio/shell/gmap.c b/subsys/bluetooth/audio/shell/gmap.c index 2ec5d86e2d60ddc..964fbfbadc7a527 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 2ed3485e3358415..a9d4b988b08d456 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=1 +CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT=1 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 69e738dceb8251b..226d6ec7110efb5 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,8 +61,15 @@ 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 + }; + memset(fixture, 0, sizeof(*fixture)); + bt_bap_unicast_server_register(¶m); + fixture->ase_cp = test_ase_control_point_get(); test_conn_init(&fixture->conn); @@ -84,11 +92,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 +108,12 @@ static void ascs_test_suite_teardown(void *f) static void ascs_test_suite_after(void *f) { - bt_ascs_cleanup(); + 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) { @@ -158,7 +171,6 @@ ZTEST_F(ascs_test_suite, test_release_ase_on_callback_unregister) bt_bap_unicast_server_register_cb(&mock_bap_unicast_server_cb); - /* Set ASE to non-idle state */ test_ase_control_client_config_codec(conn, ase_id, stream); /* Reset mock, as we expect ASE notification to be sent */ @@ -179,45 +191,6 @@ ZTEST_F(ascs_test_suite, test_release_ase_on_callback_unregister) zassert_equal(0x00, hdr->ase_state, "unexpected ASE_State 0x%02x", hdr->ase_state); } -ZTEST_F(ascs_test_suite, test_abort_client_operation_if_callback_not_registered) -{ - const struct test_ase_cp_chrc_value_param *param; - const struct test_ase_cp_chrc_value_hdr *hdr; - const struct bt_gatt_attr *ase_cp = fixture->ase_cp; - struct bt_bap_stream *stream = &fixture->stream; - struct bt_conn *conn = &fixture->conn; - struct bt_gatt_notify_params *notify_params; - uint8_t ase_id; - - if (IS_ENABLED(CONFIG_BT_ASCS_ASE_SNK)) { - ase_id = fixture->ase_snk.id; - } else { - ase_id = fixture->ase_src.id; - } - - zexpect_not_null(ase_cp); - zexpect_true(ase_id != 0x00); - - /* Set ASE to non-idle state */ - test_ase_control_client_config_codec(conn, ase_id, stream); - - /* Expected ASE Control Point notification with Unspecified Error was sent */ - expect_bt_gatt_notify_cb_called_once(conn, BT_UUID_ASCS_ASE_CP, ase_cp, - EMPTY, TEST_ASE_CP_CHRC_VALUE_SIZE(1)); - - notify_params = mock_bt_gatt_notify_cb_fake.arg1_val; - hdr = (void *)notify_params->data; - zassert_equal(0x01, hdr->opcode, "unexpected Opcode 0x%02x", hdr->opcode); - zassert_equal(0x01, hdr->number_of_ases, "unexpected Number_of_ASEs 0x%02x", - hdr->number_of_ases); - param = (void *)hdr->params; - zassert_equal(ase_id, param->ase_id, "unexpected ASE_ID 0x%02x", param->ase_id); - /* Expect Unspecified Error */ - zassert_equal(0x0E, param->response_code, "unexpected Response_Code 0x%02x", - param->response_code); - zassert_equal(0x00, param->reason, "unexpected Reason 0x%02x", param->reason); -} - ZTEST_F(ascs_test_suite, test_release_ase_on_acl_disconnection) { struct bt_bap_stream *stream = &fixture->stream; 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 a89af5bf170d97a..193582e9455a92e 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,25 +42,32 @@ 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 + }; ARG_UNUSED(fixture); + bt_bap_unicast_server_register(¶m); + bt_bap_unicast_server_register_cb(&mock_bap_unicast_server_cb); + + 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); + } + } static void test_ase_control_params_after(void *f) @@ -171,7 +179,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 +376,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 +555,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 +665,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 +731,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 +842,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 +943,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 +1033,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 +1135,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 +1201,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 +1273,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 0d4e6928d5f8d26..b7cae461e9433a7 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,19 +48,52 @@ 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 + }; + + bt_bap_unicast_server_register(¶m); + + bt_bap_unicast_server_register_cb(&mock_bap_unicast_server_cb); + + 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) { + 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 + }; + + bt_bap_unicast_server_register(¶m); bt_bap_unicast_server_register_cb(&mock_bap_unicast_server_cb); + + memset(fixture, 0, sizeof(struct test_ase_state_transition_fixture)); + test_conn_init(&fixture->conn); + test_ase_src_get(1, &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) @@ -73,7 +107,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 +124,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; @@ -611,7 +644,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 c36943c0956acf4..cb8644756205016 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,18 +41,27 @@ 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) { + 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 + }; + + bt_bap_unicast_server_register(¶m); bt_bap_unicast_server_register_cb(&mock_bap_unicast_server_cb); + + 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(1, &fixture->ase_snk); + test_ase_src_get(1, &fixture->ase_src); } static void test_ase_state_transition_invalid_after(void *f) diff --git a/tests/bluetooth/audio/ascs/testcase.yaml b/tests/bluetooth/audio/ascs/testcase.yaml index e646ea28bbf118f..ba6e549c306b70b 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 ead819b901abc0a..4f12849fc2e827f 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 43b56dac29e451a..619d35f13e9c685 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 3a9db441cb517c6..4b4b90a538400e7 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,165 @@ 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; + + LOG_ERR("Mock: Registering 0x%04x", attrs->handle); + + 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 e783677ad0fc50f..404a04c885279bd 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 e122332c0b7e02f..321d205f8bd8058 100644 --- a/tests/bluetooth/shell/testcase.yaml +++ b/tests/bluetooth/shell/testcase.yaml @@ -248,12 +248,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 @@ -280,14 +280,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 6b0186e55d8595e..d0c40206f0a8c03 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 4cbc0883f9ea40f..15f979a3b58f72e 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), 8, NULL); diff --git a/tests/bluetooth/tester/src/audio/btp_bap_unicast.c b/tests/bluetooth/tester/src/audio/btp_bap_unicast.c index 531605689fcf9b0..f05d55ec10fcbde 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) { + FAIL("Failed to register unicast server (err %d)\n", err); + + return; + } + 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 e4111289da8c6cd..1ac0bac1aa93538 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 ac1809dbf20d552..c5e429b67e569b4 100644 --- a/tests/bsim/bluetooth/audio/prj.conf +++ b/tests/bsim/bluetooth/audio/prj.conf @@ -25,8 +25,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 c2f2fd2c3c51c74..09319fc106e46fc 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 4e7485b97d0da8a..6088da5b8475d5d 100644 --- a/tests/bsim/bluetooth/audio/src/cap_acceptor_test.c +++ b/tests/bsim/bluetooth/audio/src/cap_acceptor_test.c @@ -88,8 +88,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]; CREATE_FLAG(flag_unicast_stream_configured); @@ -575,6 +575,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, @@ -739,6 +744,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 4ac3c1cfe0e869e..09de70135fefa6b 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);