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 <frdn@demant.com>
This commit is contained in:
parent
442a0686fc
commit
c9da274eb2
39 changed files with 1017 additions and 175 deletions
|
@ -16,7 +16,7 @@ Commands
|
||||||
|
|
||||||
bap --help
|
bap --help
|
||||||
Subcommands:
|
Subcommands:
|
||||||
init
|
init : [ase_sink_count, ase_source_count]
|
||||||
select_broadcast : <stream>
|
select_broadcast : <stream>
|
||||||
create_broadcast : [preset <preset_name>] [enc <broadcast_code>]
|
create_broadcast : [preset <preset_name>] [enc <broadcast_code>]
|
||||||
start_broadcast :
|
start_broadcast :
|
||||||
|
|
|
@ -208,6 +208,19 @@ Bluetooth Audio
|
||||||
This needs to be added to all instances of VCP Volume Renderer callback functions defined.
|
This needs to be added to all instances of VCP Volume Renderer callback functions defined.
|
||||||
(:github:`76992`)
|
(: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
|
Bluetooth Classic
|
||||||
=================
|
=================
|
||||||
|
|
||||||
|
|
|
@ -635,6 +635,22 @@ struct bt_bap_stream_ops {
|
||||||
void (*disconnected)(struct bt_bap_stream *stream, uint8_t reason);
|
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.
|
* @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);
|
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.
|
* @brief Register unicast server callbacks.
|
||||||
*
|
*
|
||||||
* Only one callback structure can be registered, and attempting to
|
* Only one callback structure can be registered, and attempting to
|
||||||
* registering more than one will result in an error.
|
* 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.
|
* @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
|
* May only unregister a callback structure that has previously been
|
||||||
* registered by bt_bap_unicast_server_register_cb().
|
* 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.
|
* @param cb Unicast server callback structure.
|
||||||
*
|
*
|
||||||
* @return 0 in case of success or negative value in case of error.
|
* @return 0 in case of success or negative value in case of error.
|
||||||
|
|
|
@ -89,7 +89,7 @@ enum bt_gmap_ugt_feat {
|
||||||
/**
|
/**
|
||||||
* @brief Source support
|
* @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),
|
BT_GMAP_UGT_FEAT_SOURCE = BIT(0),
|
||||||
/**
|
/**
|
||||||
|
@ -101,7 +101,7 @@ enum bt_gmap_ugt_feat {
|
||||||
/**
|
/**
|
||||||
* @brief Sink support
|
* @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),
|
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
|
* @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
|
* @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),
|
BT_GMAP_UGT_FEAT_MULTISINK = BIT(5),
|
||||||
/**
|
/**
|
||||||
* @brief Support for sending at least two audio channels, each in a separate CIS
|
* @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
|
* @kconfig{CONFIG_BT_ASCS_MAX_ACTIVE_ASES} > 1, and BT_GMAP_UGT_FEAT_SOURCE to be set
|
||||||
* as well
|
* as well
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -5,8 +5,8 @@ CONFIG_BT_ISO_PERIPHERAL=y
|
||||||
CONFIG_BT_AUDIO=y
|
CONFIG_BT_AUDIO=y
|
||||||
CONFIG_BT_BAP_UNICAST_SERVER=y
|
CONFIG_BT_BAP_UNICAST_SERVER=y
|
||||||
CONFIG_BT_ASCS=y
|
CONFIG_BT_ASCS=y
|
||||||
CONFIG_BT_ASCS_ASE_SNK_COUNT=2
|
CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT=2
|
||||||
CONFIG_BT_ASCS_ASE_SRC_COUNT=1
|
CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT=1
|
||||||
CONFIG_BT_ISO_TX_BUF_COUNT=2
|
CONFIG_BT_ISO_TX_BUF_COUNT=2
|
||||||
# Support an ISO channel per ASE
|
# Support an ISO channel per ASE
|
||||||
CONFIG_BT_ISO_MAX_CHAN=4
|
CONFIG_BT_ISO_MAX_CHAN=4
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
BT_AUDIO_CONTEXT_TYPE_MEDIA | \
|
BT_AUDIO_CONTEXT_TYPE_MEDIA | \
|
||||||
BT_AUDIO_CONTEXT_TYPE_GAME)
|
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),
|
BT_ISO_SDU_BUF_SIZE(CONFIG_BT_ISO_TX_MTU),
|
||||||
CONFIG_BT_CONN_TX_USER_DATA_SIZE, NULL);
|
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 bt_conn *default_conn;
|
||||||
static struct k_work_delayable audio_send_work;
|
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 {
|
static struct audio_source {
|
||||||
struct bt_bap_stream stream;
|
struct bt_bap_stream stream;
|
||||||
uint16_t seq_num;
|
uint16_t seq_num;
|
||||||
uint16_t max_sdu;
|
uint16_t max_sdu;
|
||||||
size_t len_to_send;
|
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 size_t configured_source_stream_count;
|
||||||
|
|
||||||
static const struct bt_audio_codec_qos_pref qos_pref =
|
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;
|
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 = {
|
static const struct bt_bap_unicast_server_cb unicast_server_cb = {
|
||||||
.config = lc3_config,
|
.config = lc3_config,
|
||||||
.reconfig = lc3_reconfig,
|
.reconfig = lc3_reconfig,
|
||||||
|
@ -727,6 +732,7 @@ int main(void)
|
||||||
|
|
||||||
printk("Bluetooth initialized\n");
|
printk("Bluetooth initialized\n");
|
||||||
|
|
||||||
|
bt_bap_unicast_server_register(¶m);
|
||||||
bt_bap_unicast_server_register_cb(&unicast_server_cb);
|
bt_bap_unicast_server_register_cb(&unicast_server_cb);
|
||||||
|
|
||||||
bt_pacs_cap_register(BT_AUDIO_DIR_SINK, &cap_sink);
|
bt_pacs_cap_register(BT_AUDIO_DIR_SINK, &cap_sink);
|
||||||
|
@ -780,7 +786,7 @@ int main(void)
|
||||||
|
|
||||||
printk("Advertising successfully started\n");
|
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 */
|
/* Start send timer */
|
||||||
k_work_init_delayable(&audio_send_work, audio_timer_timeout);
|
k_work_init_delayable(&audio_send_work, audio_timer_timeout);
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,8 +23,8 @@ CONFIG_BT_ATT_PREPARE_COUNT=1
|
||||||
|
|
||||||
# Support an ISO channel per ASE
|
# Support an ISO channel per ASE
|
||||||
CONFIG_BT_ASCS=y
|
CONFIG_BT_ASCS=y
|
||||||
CONFIG_BT_ASCS_ASE_SNK_COUNT=1
|
CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT=1
|
||||||
CONFIG_BT_ASCS_ASE_SRC_COUNT=1
|
CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT=1
|
||||||
|
|
||||||
# Support an ISO channel per ASE
|
# Support an ISO channel per ASE
|
||||||
CONFIG_BT_ISO_MAX_CHAN=2
|
CONFIG_BT_ISO_MAX_CHAN=2
|
||||||
|
|
|
@ -402,6 +402,17 @@ int init_cap_acceptor_unicast(struct peer_config *peer)
|
||||||
|
|
||||||
if (!cbs_registered) {
|
if (!cbs_registered) {
|
||||||
int err;
|
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);
|
err = bt_bap_unicast_server_register_cb(&unicast_server_cb);
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
|
|
|
@ -18,8 +18,8 @@ CONFIG_BT_ATT_PREPARE_COUNT=1
|
||||||
CONFIG_BT_AUDIO=y
|
CONFIG_BT_AUDIO=y
|
||||||
CONFIG_BT_BAP_UNICAST_SERVER=y
|
CONFIG_BT_BAP_UNICAST_SERVER=y
|
||||||
CONFIG_BT_ASCS=y
|
CONFIG_BT_ASCS=y
|
||||||
CONFIG_BT_ASCS_ASE_SNK_COUNT=1
|
CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT=1
|
||||||
CONFIG_BT_ASCS_ASE_SRC_COUNT=1
|
CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT=1
|
||||||
# Support an ISO channel per ASE
|
# Support an ISO channel per ASE
|
||||||
CONFIG_BT_ISO_MAX_CHAN=2
|
CONFIG_BT_ISO_MAX_CHAN=2
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
#include <zephyr/bluetooth/audio/bap.h>
|
#include <zephyr/bluetooth/audio/bap.h>
|
||||||
#include <zephyr/bluetooth/audio/pacs.h>
|
#include <zephyr/bluetooth/audio/pacs.h>
|
||||||
|
|
||||||
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),
|
BT_ISO_SDU_BUF_SIZE(CONFIG_BT_ISO_TX_MTU),
|
||||||
CONFIG_BT_CONN_TX_USER_DATA_SIZE, NULL);
|
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 bt_conn *default_conn;
|
||||||
static struct k_work_delayable audio_send_work;
|
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 {
|
static struct audio_source {
|
||||||
struct bt_bap_stream *stream;
|
struct bt_bap_stream *stream;
|
||||||
uint16_t seq_num;
|
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 size_t configured_source_stream_count;
|
||||||
|
|
||||||
static const struct bt_audio_codec_qos_pref qos_pref =
|
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;
|
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 = {
|
static const struct bt_bap_unicast_server_cb unicast_server_cb = {
|
||||||
.config = lc3_config,
|
.config = lc3_config,
|
||||||
.reconfig = lc3_reconfig,
|
.reconfig = lc3_reconfig,
|
||||||
|
@ -394,6 +400,7 @@ static struct bt_pacs_cap cap_source = {
|
||||||
|
|
||||||
int bap_unicast_sr_init(void)
|
int bap_unicast_sr_init(void)
|
||||||
{
|
{
|
||||||
|
bt_bap_unicast_server_register(¶m);
|
||||||
bt_bap_unicast_server_register_cb(&unicast_server_cb);
|
bt_bap_unicast_server_register_cb(&unicast_server_cb);
|
||||||
|
|
||||||
bt_pacs_cap_register(BT_AUDIO_DIR_SINK, &cap_sink);
|
bt_pacs_cap_register(BT_AUDIO_DIR_SINK, &cap_sink);
|
||||||
|
|
|
@ -29,8 +29,8 @@ CONFIG_BT_MCC=y
|
||||||
|
|
||||||
# Support an ISO channel per ASE
|
# Support an ISO channel per ASE
|
||||||
CONFIG_BT_ASCS=y
|
CONFIG_BT_ASCS=y
|
||||||
CONFIG_BT_ASCS_ASE_SNK_COUNT=1
|
CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT=1
|
||||||
CONFIG_BT_ASCS_ASE_SRC_COUNT=1
|
CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT=1
|
||||||
# Support an ISO channel per ASE
|
# Support an ISO channel per ASE
|
||||||
CONFIG_BT_ISO_MAX_CHAN=2
|
CONFIG_BT_ISO_MAX_CHAN=2
|
||||||
|
|
||||||
|
|
|
@ -30,11 +30,12 @@ static const struct bt_audio_codec_cap lc3_codec_cap =
|
||||||
(AVAILABLE_SINK_CONTEXT | AVAILABLE_SOURCE_CONTEXT));
|
(AVAILABLE_SINK_CONTEXT | AVAILABLE_SOURCE_CONTEXT));
|
||||||
|
|
||||||
static struct bt_conn *default_conn;
|
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 {
|
static struct audio_source {
|
||||||
struct bt_bap_stream *stream;
|
struct bt_bap_stream *stream;
|
||||||
uint16_t seq_num;
|
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 size_t configured_source_stream_count;
|
||||||
|
|
||||||
static const struct bt_audio_codec_qos_pref qos_pref =
|
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;
|
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 = {
|
static const struct bt_bap_unicast_server_cb unicast_server_cb = {
|
||||||
.config = lc3_config,
|
.config = lc3_config,
|
||||||
.reconfig = lc3_reconfig,
|
.reconfig = lc3_reconfig,
|
||||||
|
@ -351,6 +357,7 @@ static struct bt_pacs_cap cap = {
|
||||||
|
|
||||||
int bap_unicast_sr_init(void)
|
int bap_unicast_sr_init(void)
|
||||||
{
|
{
|
||||||
|
bt_bap_unicast_server_register(¶m);
|
||||||
bt_bap_unicast_server_register_cb(&unicast_server_cb);
|
bt_bap_unicast_server_register_cb(&unicast_server_cb);
|
||||||
|
|
||||||
if (IS_ENABLED(CONFIG_BT_PAC_SNK)) {
|
if (IS_ENABLED(CONFIG_BT_PAC_SNK)) {
|
||||||
|
|
|
@ -12,16 +12,16 @@ config BT_ASCS
|
||||||
This option enables support for Audio Stream Control Service.
|
This option enables support for Audio Stream Control Service.
|
||||||
|
|
||||||
if BT_ASCS
|
if BT_ASCS
|
||||||
config BT_ASCS_ASE_SNK_COUNT
|
config BT_ASCS_MAX_ASE_SNK_COUNT
|
||||||
int "Number of Audio Stream Endpoint Sink Characteristics"
|
int "Maximum number of Audio Stream Endpoint Sink Characteristics"
|
||||||
default 2
|
default 2
|
||||||
range 0 $(UINT8_MAX)
|
range 0 $(UINT8_MAX)
|
||||||
help
|
help
|
||||||
An ASE Sink characteristic represents the state of an ASE, which is
|
An ASE Sink characteristic represents the state of an ASE, which is
|
||||||
coupled to a single direction of a unicast Audio Stream.
|
coupled to a single direction of a unicast Audio Stream.
|
||||||
|
|
||||||
config BT_ASCS_ASE_SRC_COUNT
|
config BT_ASCS_MAX_ASE_SRC_COUNT
|
||||||
int "Number of Audio Stream Endpoint Source Characteristics"
|
int "Maximum number of Audio Stream Endpoint Source Characteristics"
|
||||||
default 2
|
default 2
|
||||||
range 0 $(UINT8_MAX)
|
range 0 $(UINT8_MAX)
|
||||||
help
|
help
|
||||||
|
@ -29,12 +29,12 @@ config BT_ASCS_ASE_SRC_COUNT
|
||||||
coupled to a single direction of a unicast Audio Stream.
|
coupled to a single direction of a unicast Audio Stream.
|
||||||
|
|
||||||
config BT_ASCS_ASE_SNK
|
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_PAC_SNK
|
||||||
select BT_AUDIO_RX
|
select BT_AUDIO_RX
|
||||||
|
|
||||||
config BT_ASCS_ASE_SRC
|
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_PAC_SRC
|
||||||
select BT_AUDIO_TX
|
select BT_AUDIO_TX
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2020 Intel Corporation
|
* Copyright (c) 2020 Intel Corporation
|
||||||
* Copyright (c) 2022-2023 Nordic Semiconductor ASA
|
* Copyright (c) 2022-2023 Nordic Semiconductor ASA
|
||||||
|
* Copyright (c) 2024 Demant A/S
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* 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 ASE_BUF_SEM_TIMEOUT K_MSEC(CONFIG_BT_ASCS_ASE_BUF_TIMEOUT)
|
||||||
|
|
||||||
#define MAX_ASES_SESSIONS CONFIG_BT_MAX_CONN * \
|
#define MAX_ASES_SESSIONS CONFIG_BT_MAX_CONN * \
|
||||||
(CONFIG_BT_ASCS_ASE_SNK_COUNT + \
|
(CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT + \
|
||||||
CONFIG_BT_ASCS_ASE_SRC_COUNT)
|
CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT)
|
||||||
|
|
||||||
#define NTF_HEADER_SIZE (3) /* opcode (1) + handle (2) */
|
#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_ID(_ase) ase->ep.status.id
|
||||||
#define ASE_DIR(_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) \
|
#define ASE_UUID(_id) \
|
||||||
(_id > CONFIG_BT_ASCS_ASE_SNK_COUNT ? BT_UUID_ASCS_ASE_SRC : BT_UUID_ASCS_ASE_SNK)
|
(_id > CONFIG_BT_ASCS_MAX_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)
|
#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) })
|
#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_conn *conn;
|
||||||
struct bt_bap_ep ep;
|
struct bt_bap_ep ep;
|
||||||
const struct bt_gatt_attr *attr;
|
const struct bt_gatt_attr *attr;
|
||||||
|
@ -81,7 +82,14 @@ static struct bt_ascs_ase {
|
||||||
struct k_work_delayable state_transition_work;
|
struct k_work_delayable state_transition_work;
|
||||||
enum bt_bap_ep_state state_pending;
|
enum bt_bap_ep_state state_pending;
|
||||||
bool unexpected_iso_link_loss;
|
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 */
|
/* 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)
|
#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);
|
LOG_DBG("conn %p", (void *)info->acl);
|
||||||
|
|
||||||
for (size_t i = 0; i < ARRAY_SIZE(ase_pool); i++) {
|
for (size_t i = 0; i < ARRAY_SIZE(ascs.ase_pool); i++) {
|
||||||
struct bt_ascs_ase *ase = &ase_pool[i];
|
struct bt_ascs_ase *ase = &ascs.ase_pool[i];
|
||||||
enum bt_bap_ep_state state;
|
enum bt_bap_ep_state state;
|
||||||
struct bt_iso_chan *chan;
|
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)
|
static void disconnected(struct bt_conn *conn, uint8_t reason)
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < ARRAY_SIZE(ase_pool); i++) {
|
for (size_t i = 0; i < ARRAY_SIZE(ascs.ase_pool); i++) {
|
||||||
struct bt_ascs_ase *ase = &ase_pool[i];
|
struct bt_ascs_ase *ase = &ascs.ase_pool[i];
|
||||||
|
|
||||||
if (ase->conn != conn) {
|
if (ase->conn != conn) {
|
||||||
continue;
|
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);
|
__ASSERT(id > 0 && id <= ASE_COUNT, "invalid ASE_ID 0x%02x", id);
|
||||||
|
|
||||||
for (size_t i = 0; i < ARRAY_SIZE(ase_pool); i++) {
|
for (size_t i = 0; i < ARRAY_SIZE(ascs.ase_pool); i++) {
|
||||||
if (ase_pool[i].conn == NULL) {
|
if (ascs.ase_pool[i].conn == NULL) {
|
||||||
ase = &ase_pool[i];
|
ase = &ascs.ase_pool[i];
|
||||||
break;
|
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)
|
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++) {
|
for (size_t i = 0; i < ARRAY_SIZE(ascs.ase_pool); i++) {
|
||||||
struct bt_ascs_ase *ase = &ase_pool[i];
|
struct bt_ascs_ase *ase = &ascs.ase_pool[i];
|
||||||
|
|
||||||
if (ase->conn == conn && ase->ep.status.id == id) {
|
if (ase->conn == conn && ase->ep.status.id == id) {
|
||||||
return ase;
|
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)
|
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++) {
|
for (size_t i = 0; i < ARRAY_SIZE(ascs.ase_pool); i++) {
|
||||||
struct bt_ascs_ase *ase = &ase_pool[i];
|
struct bt_ascs_ase *ase = &ascs.ase_pool[i];
|
||||||
|
|
||||||
if (ase->conn == conn && ase->ep.stream == stream) {
|
if (ase->conn == conn && ase->ep.stream == stream) {
|
||||||
return &ase->ep;
|
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)
|
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++) {
|
for (size_t i = 0; i < ARRAY_SIZE(ascs.ase_pool); i++) {
|
||||||
struct bt_ascs_ase *ase = &ase_pool[i];
|
struct bt_ascs_ase *ase = &ascs.ase_pool[i];
|
||||||
|
|
||||||
if (ase->conn == conn) {
|
if (ase->conn == conn) {
|
||||||
func(&ase->ep, user_data);
|
func(&ase->ep, user_data);
|
||||||
|
@ -3080,22 +3088,120 @@ respond:
|
||||||
BT_AUDIO_CCC(ascs_ase_cfg_changed)
|
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_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 + \
|
#define BT_ASCS_ASE_SRC_DEFINE(_n, ...) BT_ASCS_ASE_DEFINE(BT_UUID_ASCS_ASE_SRC, (_n) + 1 + \
|
||||||
CONFIG_BT_ASCS_ASE_SNK_COUNT)
|
CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT)
|
||||||
|
|
||||||
BT_GATT_SERVICE_DEFINE(ascs_svc,
|
#define BT_ASCS_CHR_ASE_CONTROL_POINT \
|
||||||
BT_GATT_PRIMARY_SERVICE(BT_UUID_ASCS),
|
BT_AUDIO_CHRC(BT_UUID_ASCS_ASE_CP, \
|
||||||
BT_AUDIO_CHRC(BT_UUID_ASCS_ASE_CP,
|
BT_GATT_CHRC_WRITE | BT_GATT_CHRC_WRITE_WITHOUT_RESP | BT_GATT_CHRC_NOTIFY, \
|
||||||
BT_GATT_CHRC_WRITE | BT_GATT_CHRC_WRITE_WITHOUT_RESP | BT_GATT_CHRC_NOTIFY,
|
BT_GATT_PERM_WRITE_ENCRYPT | BT_GATT_PERM_PREPARE_WRITE, \
|
||||||
BT_GATT_PERM_WRITE_ENCRYPT | BT_GATT_PERM_PREPARE_WRITE,
|
NULL, ascs_cp_write, NULL), \
|
||||||
NULL, ascs_cp_write, NULL),
|
BT_AUDIO_CCC(ascs_cp_cfg_changed)
|
||||||
BT_AUDIO_CCC(ascs_cp_cfg_changed),
|
|
||||||
#if CONFIG_BT_ASCS_ASE_SNK_COUNT > 0
|
#if CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT > 0
|
||||||
LISTIFY(CONFIG_BT_ASCS_ASE_SNK_COUNT, BT_ASCS_ASE_SNK_DEFINE, (,)),
|
#define BT_ASCS_ASE_SINKS \
|
||||||
#endif /* CONFIG_BT_ASCS_ASE_SNK_COUNT > 0 */
|
LISTIFY(CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT, BT_ASCS_ASE_SNK_DEFINE, (,)),
|
||||||
#if CONFIG_BT_ASCS_ASE_SRC_COUNT > 0
|
#else
|
||||||
LISTIFY(CONFIG_BT_ASCS_ASE_SRC_COUNT, BT_ASCS_ASE_SRC_DEFINE, (,)),
|
#define BT_ASCS_ASE_SINKS
|
||||||
#endif /* CONFIG_BT_ASCS_ASE_SRC_COUNT > 0 */
|
#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)
|
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;
|
int err;
|
||||||
|
|
||||||
|
if (!ascs.registered) {
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
|
||||||
if (unicast_server_cb != NULL) {
|
if (unicast_server_cb != NULL) {
|
||||||
return -EALREADY;
|
return -EALREADY;
|
||||||
}
|
}
|
||||||
|
@ -3128,17 +3238,47 @@ int bt_ascs_init(const struct bt_bap_unicast_server_cb *cb)
|
||||||
|
|
||||||
void bt_ascs_cleanup(void)
|
void bt_ascs_cleanup(void)
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < ARRAY_SIZE(ase_pool); i++) {
|
for (size_t i = 0; i < ARRAY_SIZE(ascs.ase_pool); i++) {
|
||||||
struct bt_ascs_ase *ase = &ase_pool[i];
|
struct bt_ascs_ase *ase = &ascs.ase_pool[i];
|
||||||
|
|
||||||
if (ase->conn != NULL) {
|
if (ase->conn != NULL) {
|
||||||
bt_ascs_release_ase(&ase->ep);
|
bt_ascs_release_ase(&ase->ep);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (unicast_server_cb != NULL) {
|
if (unicast_server_cb != NULL) {
|
||||||
bt_iso_server_unregister(&iso_server);
|
bt_iso_server_unregister(&iso_server);
|
||||||
unicast_server_cb = NULL;
|
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 */
|
#endif /* BT_BAP_UNICAST_SERVER */
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
* Copyright (c) 2020 Intel Corporation
|
* Copyright (c) 2020 Intel Corporation
|
||||||
* Copyright (c) 2022-2023 Nordic Semiconductor ASA
|
* Copyright (c) 2022-2023 Nordic Semiconductor ASA
|
||||||
|
* Copyright (c) 2024 Demant A/S
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* 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);
|
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 */
|
#endif /* BT_ASCS_INTERNAL_H */
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2021-2023 Nordic Semiconductor ASA
|
* Copyright (c) 2021-2023 Nordic Semiconductor ASA
|
||||||
|
* Copyright (c) 2024 Demant A/S
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* 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;
|
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 bt_bap_unicast_server_register_cb(const struct bt_bap_unicast_server_cb *cb)
|
||||||
{
|
{
|
||||||
int err;
|
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)
|
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");
|
LOG_DBG("cb is NULL");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 &&
|
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 "
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((ugt_feat & BT_GMAP_UGT_FEAT_MULTISOURCE) != 0 &&
|
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 "
|
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_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;
|
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 "
|
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;
|
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 &&
|
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 "
|
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_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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -199,7 +199,8 @@ struct broadcast_sink {
|
||||||
#if defined(CONFIG_BT_BAP_UNICAST)
|
#if defined(CONFIG_BT_BAP_UNICAST)
|
||||||
|
|
||||||
#define UNICAST_SERVER_STREAM_COUNT \
|
#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))
|
(0))
|
||||||
#define UNICAST_CLIENT_STREAM_COUNT \
|
#define UNICAST_CLIENT_STREAM_COUNT \
|
||||||
COND_CODE_1(CONFIG_BT_BAP_UNICAST_CLIENT, \
|
COND_CODE_1(CONFIG_BT_BAP_UNICAST_CLIENT, \
|
||||||
|
|
|
@ -3683,7 +3683,47 @@ static int cmd_init(const struct shell *sh, size_t argc, char *argv[])
|
||||||
return -ENOEXEC;
|
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)
|
#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);
|
bt_bap_unicast_server_register_cb(&unicast_server_cb);
|
||||||
#endif /* CONFIG_BT_BAP_UNICAST_SERVER */
|
#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 <meta>]" HELP_SEP "[vendor <meta>]]"
|
"[bcast_flag]" HELP_SEP "[extended <meta>]" HELP_SEP "[vendor <meta>]]"
|
||||||
|
|
||||||
SHELL_STATIC_SUBCMD_SET_CREATE(
|
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)
|
#if defined(CONFIG_BT_BAP_BROADCAST_SOURCE)
|
||||||
SHELL_CMD_ARG(select_broadcast, NULL, "<stream>", cmd_select_broadcast_source, 2, 0),
|
SHELL_CMD_ARG(select_broadcast, NULL, "<stream>", cmd_select_broadcast_source, 2, 0),
|
||||||
SHELL_CMD_ARG(create_broadcast, NULL, "[preset <preset_name>] [enc <broadcast_code>]",
|
SHELL_CMD_ARG(create_broadcast, NULL, "[preset <preset_name>] [enc <broadcast_code>]",
|
||||||
|
|
|
@ -96,18 +96,18 @@ static void set_gmap_features(struct bt_gmap_feat *features)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IS_ENABLED(CONFIG_BT_GMAP_UGT_SUPPORTED)) {
|
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);
|
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;
|
features->ugt_feat |= BT_GMAP_UGT_FEAT_MULTISOURCE;
|
||||||
#endif /* CONFIG_BT_ASCS_ASE_SRC_COUNT > 1 */
|
#endif /* CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT > 1 */
|
||||||
#endif /* CONFIG_BT_ASCS_ASE_SRC_COUNT > 0 */
|
#endif /* CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT > 0 */
|
||||||
#if CONFIG_BT_ASCS_ASE_SNK_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);
|
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;
|
features->ugt_feat |= BT_GMAP_UGT_FEAT_MULTISINK;
|
||||||
#endif /* CONFIG_BT_ASCS_ASE_SNK_COUNT > 1 */
|
#endif /* CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT > 1 */
|
||||||
#endif /* CONFIG_BT_ASCS_ASE_SNK_COUNT > 0 */
|
#endif /* CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT > 0 */
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IS_ENABLED(CONFIG_BT_GMAP_BGS_SUPPORTED)) {
|
if (IS_ENABLED(CONFIG_BT_GMAP_BGS_SUPPORTED)) {
|
||||||
|
|
|
@ -7,8 +7,8 @@ CONFIG_BT_ISO_PERIPHERAL=y
|
||||||
CONFIG_BT_ISO_MAX_CHAN=1
|
CONFIG_BT_ISO_MAX_CHAN=1
|
||||||
CONFIG_BT_AUDIO=y
|
CONFIG_BT_AUDIO=y
|
||||||
CONFIG_BT_ASCS=y
|
CONFIG_BT_ASCS=y
|
||||||
CONFIG_BT_ASCS_ASE_SNK_COUNT=1
|
CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT=2
|
||||||
CONFIG_BT_ASCS_ASE_SRC_COUNT=1
|
CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT=2
|
||||||
CONFIG_BT_ASCS_MAX_ACTIVE_ASES=1
|
CONFIG_BT_ASCS_MAX_ACTIVE_ASES=1
|
||||||
CONFIG_BT_BAP_UNICAST_SERVER=y
|
CONFIG_BT_BAP_UNICAST_SERVER=y
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2023 Codecoup
|
* Copyright (c) 2023 Codecoup
|
||||||
|
* Copyright (c) 2024 Demant A/S
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* 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)
|
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));
|
memset(fixture, 0, sizeof(*fixture));
|
||||||
|
|
||||||
|
err = bt_bap_unicast_server_register(¶m);
|
||||||
|
|
||||||
fixture->ase_cp = test_ase_control_point_get();
|
fixture->ase_cp = test_ase_control_point_get();
|
||||||
|
|
||||||
test_conn_init(&fixture->conn);
|
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) {
|
if (fixture->ase_snk.attr != NULL) {
|
||||||
fixture->ase_snk.id = test_ase_id_get(fixture->ase_snk.attr);
|
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) {
|
if (fixture->ase_src.attr != NULL) {
|
||||||
fixture->ase_src.id = test_ase_id_get(fixture->ase_src.attr);
|
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));
|
fixture = malloc(sizeof(*fixture));
|
||||||
zassert_not_null(fixture);
|
zassert_not_null(fixture);
|
||||||
|
|
||||||
ascs_test_suite_fixture_init(fixture);
|
|
||||||
|
|
||||||
return 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)
|
static void ascs_test_suite_teardown(void *f)
|
||||||
{
|
{
|
||||||
free(f);
|
free(f);
|
||||||
|
@ -96,11 +109,15 @@ static void ascs_test_suite_teardown(void *f)
|
||||||
|
|
||||||
static void ascs_test_suite_after(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,
|
ZTEST_SUITE(ascs_test_suite, NULL, ascs_test_suite_setup, ascs_test_suite_before,
|
||||||
ascs_test_suite_teardown);
|
ascs_test_suite_after, ascs_test_suite_teardown);
|
||||||
|
|
||||||
ZTEST_F(ascs_test_suite, test_has_sink_ase_chrc)
|
ZTEST_F(ascs_test_suite, test_has_sink_ase_chrc)
|
||||||
{
|
{
|
||||||
|
@ -136,7 +153,120 @@ 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);
|
zassert_equal(0x00, hdr.ase_state, "unexpected ASE_State 0x%02x", hdr.ase_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
ZTEST_F(ascs_test_suite, test_release_ase_on_callback_unregister)
|
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 test_ase_chrc_value_hdr *hdr;
|
||||||
const struct bt_gatt_attr *ase;
|
const struct bt_gatt_attr *ase;
|
||||||
|
@ -144,6 +274,7 @@ ZTEST_F(ascs_test_suite, test_release_ase_on_callback_unregister)
|
||||||
struct bt_conn *conn = &fixture->conn;
|
struct bt_conn *conn = &fixture->conn;
|
||||||
struct bt_gatt_notify_params *notify_params;
|
struct bt_gatt_notify_params *notify_params;
|
||||||
uint8_t ase_id;
|
uint8_t ase_id;
|
||||||
|
int err;
|
||||||
|
|
||||||
if (IS_ENABLED(CONFIG_BT_ASCS_ASE_SNK)) {
|
if (IS_ENABLED(CONFIG_BT_ASCS_ASE_SNK)) {
|
||||||
ase = fixture->ase_snk.attr;
|
ase = fixture->ase_snk.attr;
|
||||||
|
@ -156,7 +287,47 @@ ZTEST_F(ascs_test_suite, test_release_ase_on_callback_unregister)
|
||||||
zexpect_not_null(ase);
|
zexpect_not_null(ase);
|
||||||
zexpect_true(ase_id != 0x00);
|
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);
|
||||||
|
|
||||||
|
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;
|
||||||
|
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 */
|
/* Set ASE to non-idle state */
|
||||||
test_ase_control_client_config_codec(conn, ase_id, stream);
|
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;
|
const struct bt_gatt_attr *ase;
|
||||||
struct bt_iso_chan *chan;
|
struct bt_iso_chan *chan;
|
||||||
uint8_t ase_id;
|
uint8_t ase_id;
|
||||||
|
int err;
|
||||||
|
|
||||||
if (IS_ENABLED(CONFIG_BT_ASCS_ASE_SNK)) {
|
if (IS_ENABLED(CONFIG_BT_ASCS_ASE_SNK)) {
|
||||||
ase = fixture->ase_snk.attr;
|
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_not_null(ase);
|
||||||
zexpect_true(ase_id != 0x00);
|
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 */
|
/* Set ASE to non-idle state */
|
||||||
test_preamble_state_streaming(conn, ase_id, stream, &chan,
|
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;
|
ase_src_id = fixture->ase_src.id;
|
||||||
zexpect_true(ase_src_id != 0x00);
|
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_codec(conn, ase_snk_id, &snk_stream);
|
||||||
test_ase_control_client_config_qos(conn, ase_snk_id);
|
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 bt_iso_chan *chan;
|
||||||
struct net_buf buf;
|
struct net_buf buf;
|
||||||
|
int err;
|
||||||
|
|
||||||
Z_TEST_SKIP_IFNDEF(CONFIG_BT_ASCS_ASE_SNK);
|
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);
|
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);
|
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);
|
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;
|
const struct bt_gatt_attr *ase;
|
||||||
struct bt_iso_chan *chan;
|
struct bt_iso_chan *chan;
|
||||||
uint8_t ase_id;
|
uint8_t ase_id;
|
||||||
|
int err;
|
||||||
|
|
||||||
if (IS_ENABLED(CONFIG_BT_ASCS_ASE_SNK)) {
|
if (IS_ENABLED(CONFIG_BT_ASCS_ASE_SNK)) {
|
||||||
ase = fixture->ase_snk.attr;
|
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_not_null(ase);
|
||||||
zexpect_true(ase_id != 0x00);
|
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,
|
test_preamble_state_streaming(conn, ase_id, stream, &chan,
|
||||||
!IS_ENABLED(CONFIG_BT_ASCS_ASE_SNK));
|
!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_not_null(ase);
|
||||||
zexpect_true(ase_id != 0x00);
|
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);
|
test_preamble_state_enabling(conn, ase_id, stream);
|
||||||
err = mock_bt_iso_accept(conn, 0x01, 0x01, &chan);
|
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_not_null(ase);
|
||||||
zexpect_true(ase_id != 0x00);
|
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);
|
test_preamble_state_enabling(conn, ase_id, stream);
|
||||||
err = mock_bt_iso_accept(conn, 0x01, 0x01, &chan);
|
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_not_null(ase);
|
||||||
zexpect_true(ase_id != 0x00);
|
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);
|
test_preamble_state_enabling(conn, ase_id, stream);
|
||||||
err = mock_bt_iso_accept(conn, 0x01, 0x01, &chan);
|
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();
|
cp = test_ase_control_point_get();
|
||||||
zexpect_not_null(cp);
|
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;
|
stream_allocated = stream;
|
||||||
mock_bap_unicast_server_cb_config_fake.custom_fake = unicast_server_cb_config_custom_fake;
|
mock_bap_unicast_server_cb_config_fake.custom_fake = unicast_server_cb_config_custom_fake;
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2023 Codecoup
|
* Copyright (c) 2023 Codecoup
|
||||||
|
* Copyright (c) 2024 Demant A/S
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
@ -41,30 +42,50 @@ static void *test_ase_control_params_setup(void)
|
||||||
fixture = malloc(sizeof(*fixture));
|
fixture = malloc(sizeof(*fixture));
|
||||||
zassert_not_null(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;
|
return fixture;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_ase_control_params_before(void *f)
|
static void test_ase_control_params_before(void *f)
|
||||||
{
|
{
|
||||||
struct test_ase_control_params_fixture *fixture = 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);
|
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)
|
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)
|
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)
|
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 */
|
/* Skip if number of ASEs configured is high enough to support any value in the write req */
|
||||||
if (ase_cnt > UINT8_MAX) {
|
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)
|
ZTEST_F(test_ase_control_params, test_codec_configure_invalid_ase_id_unavailable)
|
||||||
{
|
{
|
||||||
/* Test requires support for at least 2 ASEs */
|
/* 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();
|
ztest_test_skip();
|
||||||
}
|
}
|
||||||
|
|
||||||
const uint8_t ase_id_valid = 0x01;
|
const uint8_t ase_id_valid = 0x01;
|
||||||
const uint8_t ase_id_invalid = CONFIG_BT_ASCS_ASE_SNK_COUNT +
|
const uint8_t ase_id_invalid = CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT +
|
||||||
CONFIG_BT_ASCS_ASE_SRC_COUNT + 1;
|
CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT + 1;
|
||||||
const uint8_t buf[] = {
|
const uint8_t buf[] = {
|
||||||
0x01, /* Opcode = Config Codec */
|
0x01, /* Opcode = Config Codec */
|
||||||
0x02, /* Number_of_ASEs */
|
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)
|
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 */
|
/* Skip if number of ASEs configured is high enough to support any value in the write req */
|
||||||
if (ase_cnt > UINT8_MAX) {
|
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)
|
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 */
|
/* Skip if number of ASEs configured is high enough to support any value in the write req */
|
||||||
if (ase_cnt > UINT8_MAX) {
|
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)
|
ZTEST_F(test_ase_control_params, test_enable_invalid_ase_id)
|
||||||
{
|
{
|
||||||
/* Test requires support for at least 2 ASEs */
|
/* 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();
|
ztest_test_skip();
|
||||||
}
|
}
|
||||||
|
|
||||||
const uint8_t ase_id_valid = 0x01;
|
const uint8_t ase_id_valid = 0x01;
|
||||||
const uint8_t ase_id_invalid = CONFIG_BT_ASCS_ASE_SNK_COUNT +
|
const uint8_t ase_id_invalid = CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT +
|
||||||
CONFIG_BT_ASCS_ASE_SRC_COUNT + 1;
|
CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT + 1;
|
||||||
const uint8_t buf[] = {
|
const uint8_t buf[] = {
|
||||||
0x03, /* Opcode = Enable */
|
0x03, /* Opcode = Enable */
|
||||||
0x02, /* Number_of_ASEs */
|
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)
|
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;
|
const struct bt_gatt_attr *ase;
|
||||||
|
|
||||||
Z_TEST_SKIP_IFNDEF(CONFIG_BT_ASCS_ASE_SRC);
|
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)
|
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 */
|
/* Skip if number of ASEs configured is high enough to support any value in the write req */
|
||||||
if (ase_cnt > UINT8_MAX) {
|
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)
|
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;
|
const struct bt_gatt_attr *ase;
|
||||||
|
|
||||||
Z_TEST_SKIP_IFNDEF(CONFIG_BT_ASCS_ASE_SRC);
|
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)
|
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 */
|
/* Skip if number of ASEs configured is high enough to support any value in the write req */
|
||||||
if (ase_cnt > UINT8_MAX) {
|
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)
|
ZTEST_F(test_ase_control_params, test_update_metadata_invalid_ase_id)
|
||||||
{
|
{
|
||||||
/* Test requires support for at least 2 ASEs */
|
/* 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();
|
ztest_test_skip();
|
||||||
}
|
}
|
||||||
|
|
||||||
const uint8_t ase_id_valid = 0x01;
|
const uint8_t ase_id_valid = 0x01;
|
||||||
const uint8_t ase_id_invalid = CONFIG_BT_ASCS_ASE_SNK_COUNT +
|
const uint8_t ase_id_invalid = CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT +
|
||||||
CONFIG_BT_ASCS_ASE_SRC_COUNT + 1;
|
CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT + 1;
|
||||||
const uint8_t buf[] = {
|
const uint8_t buf[] = {
|
||||||
0x07, /* Opcode = Update Metadata */
|
0x07, /* Opcode = Update Metadata */
|
||||||
0x02, /* Number_of_ASEs */
|
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)
|
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 */
|
/* Skip if number of ASEs configured is high enough to support any value in the write req */
|
||||||
if (ase_cnt > UINT8_MAX) {
|
if (ase_cnt > UINT8_MAX) {
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2023 Codecoup
|
* Copyright (c) 2023 Codecoup
|
||||||
|
* Copyright (c) 2024 Demant A/S
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
@ -47,24 +48,74 @@ static void *test_sink_ase_state_transition_setup(void)
|
||||||
fixture = malloc(sizeof(*fixture));
|
fixture = malloc(sizeof(*fixture));
|
||||||
zassert_not_null(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_conn_init(&fixture->conn);
|
||||||
test_ase_snk_get(1, &fixture->ase.attr);
|
test_ase_snk_get(1, &fixture->ase.attr);
|
||||||
if (fixture->ase.attr != NULL) {
|
if (fixture->ase.attr != NULL) {
|
||||||
fixture->ase.id = test_ase_id_get(fixture->ase.attr);
|
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)
|
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)
|
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,
|
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);
|
test_ase_state_transition_teardown);
|
||||||
|
|
||||||
ZTEST_F(test_sink_ase_state_transition, test_client_idle_to_codec_configured)
|
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_unicast_server_cb_config_called_once(conn, EMPTY, BT_AUDIO_DIR_SINK, EMPTY);
|
||||||
expect_bt_bap_stream_ops_configured_called_once(stream, 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)
|
ZTEST_F(test_sink_ase_state_transition, test_client_codec_configured_to_qos_configured)
|
||||||
{
|
{
|
||||||
struct bt_bap_stream *stream = &fixture->stream;
|
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));
|
memset(fixture, 0, sizeof(*fixture));
|
||||||
test_conn_init(&fixture->conn);
|
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) {
|
if (fixture->ase.attr != NULL) {
|
||||||
fixture->ase.id = test_ase_id_get(fixture->ase.attr);
|
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,
|
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);
|
test_ase_state_transition_teardown);
|
||||||
|
|
||||||
ZTEST_F(test_source_ase_state_transition, test_client_idle_to_codec_configured)
|
ZTEST_F(test_source_ase_state_transition, test_client_idle_to_codec_configured)
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2023 Codecoup
|
* Copyright (c) 2023 Codecoup
|
||||||
|
* Copyright (c) 2024 Demant A/S
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
@ -40,23 +41,46 @@ static void *test_ase_state_transition_invalid_setup(void)
|
||||||
fixture = malloc(sizeof(*fixture));
|
fixture = malloc(sizeof(*fixture));
|
||||||
zassert_not_null(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;
|
return fixture;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_ase_state_transition_invalid_before(void *f)
|
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)
|
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)
|
static void test_ase_state_transition_invalid_teardown(void *f)
|
||||||
|
|
|
@ -8,11 +8,11 @@ tests:
|
||||||
bluetooth.audio.ascs.test_snk_only:
|
bluetooth.audio.ascs.test_snk_only:
|
||||||
type: unit
|
type: unit
|
||||||
extra_configs:
|
extra_configs:
|
||||||
- CONFIG_BT_ASCS_ASE_SRC_COUNT=0
|
- CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT=0
|
||||||
bluetooth.audio.ascs.test_src_only:
|
bluetooth.audio.ascs.test_src_only:
|
||||||
type: unit
|
type: unit
|
||||||
extra_configs:
|
extra_configs:
|
||||||
- CONFIG_BT_ASCS_ASE_SNK_COUNT=0
|
- CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT=0
|
||||||
bluetooth.audio.ascs.test_unicast_client_enabled:
|
bluetooth.audio.ascs.test_unicast_client_enabled:
|
||||||
type: unit
|
type: unit
|
||||||
extra_configs:
|
extra_configs:
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#
|
#
|
||||||
# Copyright (c) 2023 Codecoup
|
# Copyright (c) 2023 Codecoup
|
||||||
|
# Coperight (c) 2024 Demant A/S
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: Apache-2.0
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
#
|
#
|
||||||
|
@ -24,6 +25,14 @@ target_include_directories(mocks PUBLIC
|
||||||
${ZEPHYR_BASE}/tests/bluetooth/audio
|
${ZEPHYR_BASE}/tests/bluetooth/audio
|
||||||
${ZEPHYR_BASE}/subsys/bluetooth
|
${ZEPHYR_BASE}/subsys/bluetooth
|
||||||
${ZEPHYR_BASE}/subsys/bluetooth/audio
|
${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)
|
add_subdirectory(${ZEPHYR_BASE}/tests/bluetooth/host host_mocks)
|
||||||
|
|
|
@ -20,5 +20,7 @@ DECLARE_FAKE_VALUE_FUNC(bool, mock_bt_gatt_is_subscribed, struct bt_conn *,
|
||||||
|
|
||||||
void bt_gatt_notify_cb_reset(void);
|
void bt_gatt_notify_cb_reset(void);
|
||||||
uint16_t bt_gatt_get_mtu(struct bt_conn *conn);
|
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_ */
|
#endif /* MOCKS_GATT_H_ */
|
||||||
|
|
|
@ -1,18 +1,30 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2023 Codecoup
|
* Copyright (c) 2023 Codecoup
|
||||||
|
* Copyright (c) 2024 Demant A/S
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdint.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <zephyr/bluetooth/conn.h>
|
||||||
|
#include <zephyr/sys/util.h>
|
||||||
#include <zephyr/types.h>
|
#include <zephyr/types.h>
|
||||||
#include <zephyr/bluetooth/gatt.h>
|
#include <zephyr/bluetooth/gatt.h>
|
||||||
#include <zephyr/bluetooth/att.h>
|
#include <zephyr/bluetooth/att.h>
|
||||||
#include <zephyr/bluetooth/uuid.h>
|
#include <zephyr/bluetooth/uuid.h>
|
||||||
|
#include <zephyr/fff.h>
|
||||||
#include <zephyr/sys/iterable_sections.h>
|
#include <zephyr/sys/iterable_sections.h>
|
||||||
|
#include <ztest_test.h>
|
||||||
|
#include <ztest_assert.h>
|
||||||
|
|
||||||
#include "gatt.h"
|
#include "gatt.h"
|
||||||
#include "conn.h"
|
#include "conn.h"
|
||||||
|
#include "common/bt_str.h"
|
||||||
|
|
||||||
#define LOG_LEVEL CONFIG_BT_GATT_LOG_LEVEL
|
#define LOG_LEVEL CONFIG_BT_GATT_LOG_LEVEL
|
||||||
#include <zephyr/logging/log.h>
|
#include <zephyr/logging/log.h>
|
||||||
|
@ -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 *,
|
DEFINE_FAKE_VALUE_FUNC(bool, mock_bt_gatt_is_subscribed, struct bt_conn *,
|
||||||
const struct bt_gatt_attr *, uint16_t);
|
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,
|
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)
|
uint16_t len, uint16_t offset)
|
||||||
{
|
{
|
||||||
|
@ -182,9 +197,6 @@ void bt_gatt_notify_cb_reset(void)
|
||||||
RESET_FAKE(mock_bt_gatt_notify_cb);
|
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() */
|
/* Exact copy of subsys/bluetooth/host/gatt.c:gatt_foreach_iter() */
|
||||||
static uint8_t gatt_foreach_iter(const struct bt_gatt_attr *attr,
|
static uint8_t gatt_foreach_iter(const struct bt_gatt_attr *attr,
|
||||||
uint16_t handle, uint16_t start_handle,
|
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;
|
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() */
|
/* 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,
|
void bt_gatt_foreach_attr_type(uint16_t start_handle, uint16_t end_handle,
|
||||||
const struct bt_uuid *uuid,
|
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;
|
size_t i;
|
||||||
|
|
||||||
|
LOG_DBG("bt_gatt_foreach_attr_type");
|
||||||
|
|
||||||
if (!num_matches) {
|
if (!num_matches) {
|
||||||
num_matches = UINT16_MAX;
|
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,
|
attr_data, &num_matches,
|
||||||
func, user_data) ==
|
func, user_data) ==
|
||||||
BT_GATT_ITER_STOP) {
|
BT_GATT_ITER_STOP) {
|
||||||
|
LOG_DBG("Returning after searching static DB");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LOG_DBG("foreach_attr_type_dyndb");
|
||||||
/* Iterate over dynamic db */
|
/* Iterate over dynamic db */
|
||||||
foreach_attr_type_dyndb(start_handle, end_handle, uuid, attr_data,
|
foreach_attr_type_dyndb(start_handle, end_handle, uuid, attr_data,
|
||||||
num_matches, func, user_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() */
|
/* 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,
|
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,
|
void *buf, uint16_t buf_len, uint16_t offset,
|
||||||
|
|
|
@ -58,8 +58,8 @@ CONFIG_BT_ISO_RX_MTU=310
|
||||||
|
|
||||||
CONFIG_BT_AUDIO=y
|
CONFIG_BT_AUDIO=y
|
||||||
CONFIG_BT_BAP_UNICAST_SERVER=y
|
CONFIG_BT_BAP_UNICAST_SERVER=y
|
||||||
CONFIG_BT_ASCS_ASE_SNK_COUNT=2
|
CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT=2
|
||||||
CONFIG_BT_ASCS_ASE_SRC_COUNT=2
|
CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT=2
|
||||||
|
|
||||||
CONFIG_BT_BAP_UNICAST_CLIENT=y
|
CONFIG_BT_BAP_UNICAST_CLIENT=y
|
||||||
CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT=4
|
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_AUDIO_CODEC_CAP_MAX_METADATA_SIZE=255
|
||||||
|
|
||||||
CONFIG_BT_ASCS=y
|
CONFIG_BT_ASCS=y
|
||||||
CONFIG_BT_ASCS_ASE_SNK_COUNT=2
|
CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT=2
|
||||||
CONFIG_BT_ASCS_ASE_SRC_COUNT=2
|
CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT=2
|
||||||
CONFIG_BT_BAP_UNICAST_CLIENT=y
|
CONFIG_BT_BAP_UNICAST_CLIENT=y
|
||||||
CONFIG_BT_BAP_BROADCAST_SOURCE=y
|
CONFIG_BT_BAP_BROADCAST_SOURCE=y
|
||||||
CONFIG_BT_BAP_BROADCAST_SRC_SUBGROUP_COUNT=4
|
CONFIG_BT_BAP_BROADCAST_SRC_SUBGROUP_COUNT=4
|
||||||
|
|
|
@ -262,12 +262,12 @@ tests:
|
||||||
extra_args: CONF_FILE="audio.conf"
|
extra_args: CONF_FILE="audio.conf"
|
||||||
build_only: true
|
build_only: true
|
||||||
extra_configs:
|
extra_configs:
|
||||||
- CONFIG_BT_ASCS_ASE_SNK_COUNT=0
|
- CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT=0
|
||||||
bluetooth.audio_shell.no_server_ase_src:
|
bluetooth.audio_shell.no_server_ase_src:
|
||||||
extra_args: CONF_FILE="audio.conf"
|
extra_args: CONF_FILE="audio.conf"
|
||||||
build_only: true
|
build_only: true
|
||||||
extra_configs:
|
extra_configs:
|
||||||
- CONFIG_BT_ASCS_ASE_SRC_COUNT=0
|
- CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT=0
|
||||||
bluetooth.audio_shell.no_client_ase_snk:
|
bluetooth.audio_shell.no_client_ase_snk:
|
||||||
extra_args: CONF_FILE="audio.conf"
|
extra_args: CONF_FILE="audio.conf"
|
||||||
build_only: true
|
build_only: true
|
||||||
|
@ -294,14 +294,14 @@ tests:
|
||||||
extra_configs:
|
extra_configs:
|
||||||
- CONFIG_BT_BAP_BROADCAST_SOURCE=n
|
- CONFIG_BT_BAP_BROADCAST_SOURCE=n
|
||||||
- CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT=0
|
- 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:
|
bluetooth.audio_shell.no_audio_rx:
|
||||||
extra_args: CONF_FILE="audio.conf"
|
extra_args: CONF_FILE="audio.conf"
|
||||||
build_only: true
|
build_only: true
|
||||||
extra_configs:
|
extra_configs:
|
||||||
- CONFIG_BT_BAP_BROADCAST_SINK=n
|
- CONFIG_BT_BAP_BROADCAST_SINK=n
|
||||||
- CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT=0
|
- 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:
|
bluetooth.audio_shell.no_has:
|
||||||
extra_args: CONF_FILE="audio.conf"
|
extra_args: CONF_FILE="audio.conf"
|
||||||
build_only: true
|
build_only: true
|
||||||
|
|
|
@ -57,8 +57,8 @@ CONFIG_BT_BUF_ACL_RX_SIZE=255
|
||||||
|
|
||||||
# ASCS
|
# ASCS
|
||||||
CONFIG_BT_ASCS=y
|
CONFIG_BT_ASCS=y
|
||||||
CONFIG_BT_ASCS_ASE_SNK_COUNT=2
|
CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT=2
|
||||||
CONFIG_BT_ASCS_ASE_SRC_COUNT=2
|
CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT=2
|
||||||
|
|
||||||
# Support an ISO channel per ASE
|
# Support an ISO channel per ASE
|
||||||
CONFIG_BT_ISO_MAX_CHAN=4
|
CONFIG_BT_ISO_MAX_CHAN=4
|
||||||
|
|
|
@ -21,7 +21,7 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME, CONFIG_BTTESTER_LOG_LEVEL);
|
||||||
#include "btp/btp.h"
|
#include "btp/btp.h"
|
||||||
#include "btp_bap_audio_stream.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),
|
CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT),
|
||||||
BT_ISO_SDU_BUF_SIZE(CONFIG_BT_ISO_TX_MTU),
|
BT_ISO_SDU_BUF_SIZE(CONFIG_BT_ISO_TX_MTU),
|
||||||
CONFIG_BT_CONN_TX_USER_DATA_SIZE, NULL);
|
CONFIG_BT_CONN_TX_USER_DATA_SIZE, NULL);
|
||||||
|
|
|
@ -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);
|
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 = {
|
static struct bt_bap_unicast_client_cb unicast_client_cbs = {
|
||||||
.location = unicast_client_location_cb,
|
.location = unicast_client_location_cb,
|
||||||
.available_contexts = available_contexts_cb,
|
.available_contexts = available_contexts_cb,
|
||||||
|
@ -1652,6 +1657,13 @@ int btp_bap_unicast_init(void)
|
||||||
|
|
||||||
(void)memset(connections, 0, sizeof(connections));
|
(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);
|
err = bt_bap_unicast_server_register_cb(&unicast_server_cb);
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
LOG_DBG("Failed to register client callbacks: %d", err);
|
LOG_DBG("Failed to register client callbacks: %d", err);
|
||||||
|
|
|
@ -9,9 +9,9 @@
|
||||||
#include <zephyr/bluetooth/audio/cap.h>
|
#include <zephyr/bluetooth/audio/cap.h>
|
||||||
|
|
||||||
#define BTP_BAP_UNICAST_MAX_SNK_STREAMS_COUNT MIN(CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT, \
|
#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, \
|
#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 + \
|
#define BTP_BAP_UNICAST_MAX_STREAMS_COUNT BTP_BAP_UNICAST_MAX_SNK_STREAMS_COUNT + \
|
||||||
BTP_BAP_UNICAST_MAX_SRC_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 + \
|
#define BTP_BAP_UNICAST_MAX_END_POINTS_COUNT CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT + \
|
||||||
|
|
|
@ -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_SNK_COUNT=2
|
||||||
CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT=2
|
CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT=2
|
||||||
CONFIG_BT_ASCS=y
|
CONFIG_BT_ASCS=y
|
||||||
CONFIG_BT_ASCS_ASE_SNK_COUNT=2
|
CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT=2
|
||||||
CONFIG_BT_ASCS_ASE_SRC_COUNT=2
|
CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT=2
|
||||||
CONFIG_BT_BAP_BROADCAST_SOURCE=y
|
CONFIG_BT_BAP_BROADCAST_SOURCE=y
|
||||||
CONFIG_BT_BAP_BROADCAST_SINK=y
|
CONFIG_BT_BAP_BROADCAST_SINK=y
|
||||||
CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE=196
|
CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE=196
|
||||||
|
|
|
@ -68,7 +68,7 @@ static const struct bt_audio_codec_cap lc3_codec_cap = {
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct audio_test_stream
|
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 =
|
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);
|
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;
|
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 = {
|
static const struct bt_bap_unicast_server_cb unicast_server_cb = {
|
||||||
.config = lc3_config,
|
.config = lc3_config,
|
||||||
.reconfig = lc3_reconfig,
|
.reconfig = lc3_reconfig,
|
||||||
|
@ -487,6 +492,13 @@ static void init(void)
|
||||||
|
|
||||||
printk("Bluetooth initialized\n");
|
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);
|
bt_bap_unicast_server_register_cb(&unicast_server_cb);
|
||||||
|
|
||||||
err = bt_pacs_cap_register(BT_AUDIO_DIR_SINK, &cap);
|
err = bt_pacs_cap_register(BT_AUDIO_DIR_SINK, &cap);
|
||||||
|
|
|
@ -76,8 +76,8 @@ static uint32_t bis_index_bitfield;
|
||||||
|
|
||||||
#define UNICAST_CHANNEL_COUNT_1 BIT(0)
|
#define UNICAST_CHANNEL_COUNT_1 BIT(0)
|
||||||
|
|
||||||
static struct bt_cap_stream unicast_streams[CONFIG_BT_ASCS_ASE_SNK_COUNT +
|
static struct bt_cap_stream unicast_streams[CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT +
|
||||||
CONFIG_BT_ASCS_ASE_SRC_COUNT];
|
CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT];
|
||||||
|
|
||||||
static bool subgroup_data_func_cb(struct bt_data *data, void *user_data)
|
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;
|
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 = {
|
static struct bt_bap_unicast_server_cb unicast_server_cbs = {
|
||||||
.config = unicast_server_config,
|
.config = unicast_server_config,
|
||||||
.reconfig = unicast_server_reconfig,
|
.reconfig = unicast_server_reconfig,
|
||||||
|
@ -728,6 +733,13 @@ static void init(void)
|
||||||
return;
|
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);
|
err = bt_bap_unicast_server_register_cb(&unicast_server_cbs);
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
FAIL("Failed to register unicast server callbacks (err %d)\n",
|
FAIL("Failed to register unicast server callbacks (err %d)\n",
|
||||||
|
|
|
@ -48,7 +48,7 @@ static const struct bt_audio_codec_qos_pref unicast_qos_pref =
|
||||||
#define UNICAST_CHANNEL_COUNT_1 BIT(0)
|
#define UNICAST_CHANNEL_COUNT_1 BIT(0)
|
||||||
|
|
||||||
static struct bt_cap_stream
|
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_unicast_stream_started);
|
||||||
CREATE_FLAG(flag_gmap_discovered);
|
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;
|
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 = {
|
static struct bt_bap_unicast_server_cb unicast_server_cbs = {
|
||||||
.config = unicast_server_config,
|
.config = unicast_server_config,
|
||||||
.reconfig = unicast_server_reconfig,
|
.reconfig = unicast_server_reconfig,
|
||||||
|
@ -404,6 +409,13 @@ static void test_main(void)
|
||||||
return;
|
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);
|
err = bt_bap_unicast_server_register_cb(&unicast_server_cbs);
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
FAIL("Failed to register unicast server callbacks (err %d)\n", err);
|
FAIL("Failed to register unicast server callbacks (err %d)\n", err);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue