Bluetooth: BASS: Add support for dynamic registration of BASS

Added support for dynamic registration and unregistration of the
Broadcast Audio Scan Service (BASS) within the scan delegator.
This enables both scan delegator and BASS to be registered or
unregistered dynamically at runtime.

Signed-off-by: Babak Arisian <bbaa@demant.com>
This commit is contained in:
Babak Arisian 2024-09-20 09:46:01 +02:00 committed by Anas Nashif
commit c0cfe49a54
11 changed files with 174 additions and 23 deletions

View file

@ -288,6 +288,17 @@ Bluetooth Audio
is enabled and that all members are bonded, to comply with the requirements from the CSIP spec.
(:github:`78877`)
* The Broadcast Audio Scan Service (BASS) shall now be registered and unregistered dynamically
at runtime within the scan delegator. Two new APIs, :c:func:`bt_bap_scan_delegator_register()`
and :c:func:`bt_bap_scan_delegator_unregister()`, have been introduced to manage both BASS and
scan delegator registration and initialization dynamically. It should also be mentioned that
the previous callback registration function, :c:func:`bt_bap_scan_delegator_register_cb()` has
now been removed and merged with :c:func:`bt_bap_scan_delegator_register()`.
This change allows more flexibility when registering or unregistering scan delegator and BASS
related functionality without requiring build-time configuration. Existing need to be updated
to use these new APIs.
(:github:`78751`)
Bluetooth Classic
=================

View file

@ -318,7 +318,7 @@ struct bt_bap_scan_delegator_recv_state {
/**
* @brief Struct to hold the Basic Audio Profile Scan Delegator callbacks
*
* These can be registered for usage with bt_bap_scan_delegator_register_cb().
* These can be registered for usage with bt_bap_scan_delegator_register().
*/
struct bt_bap_scan_delegator_cb {
/**
@ -2048,14 +2048,29 @@ int bt_bap_broadcast_sink_delete(struct bt_bap_broadcast_sink *sink);
/** @} */ /* End of group bt_bap_broadcast_sink */
/**
* @brief Register the callbacks for the Basic Audio Profile Scan Delegator
* @brief Register the Basic Audio Profile Scan Delegator and BASS.
*
* Register the scan deligator and Broadcast Audio Scan Service (BASS)
* dynamically at runtime.
*
* Only one set of callbacks can be registered at any one time, and calling this function multiple
* times will override any previously registered callbacks.
*
* @param cb Pointer to the callback struct
*
* @return 0 in case of success or negative value in case of error.
*/
void bt_bap_scan_delegator_register_cb(struct bt_bap_scan_delegator_cb *cb);
int bt_bap_scan_delegator_register(struct bt_bap_scan_delegator_cb *cb);
/**
* @brief unregister the Basic Audio Profile Scan Delegator and BASS.
*
* Unregister the scan deligator and Broadcast Audio Scan Service (BASS)
* dynamically at runtime.
*
* @return 0 in case of success or negative value in case of error.
*/
int bt_bap_scan_delegator_unregister(void);
/**
* @brief Set the periodic advertising sync state to syncing

View file

@ -1308,8 +1308,13 @@ static int init(void)
return err;
}
err = bt_bap_scan_delegator_register(&scan_delegator_cbs);
if (err) {
printk("Scan delegator register failed (err %d)\n", err);
return err;
}
bt_bap_broadcast_sink_register_cb(&broadcast_sink_cbs);
bt_bap_scan_delegator_register_cb(&scan_delegator_cbs);
bt_le_per_adv_sync_cb_register(&bap_pa_sync_cb);
bt_le_scan_cb_register(&bap_scan_cb);

View file

@ -731,6 +731,13 @@ int init_cap_acceptor_broadcast(void)
.recv = broadcast_scan_recv,
};
err = bt_bap_scan_delegator_register(&scan_delegator_cbs);
if (err != 0) {
LOG_ERR("Scan delegator register failed (err %d)", err);
return err;
}
err = bt_bap_broadcast_sink_register_cb(&broadcast_sink_cbs);
if (err != 0) {
LOG_ERR("Failed to register BAP broadcast sink callbacks: %d", err);
@ -739,7 +746,6 @@ int init_cap_acceptor_broadcast(void)
}
bt_cap_stream_ops_register(&broadcast_sink.broadcast_stream, &broadcast_stream_ops);
bt_bap_scan_delegator_register_cb(&scan_delegator_cbs);
bt_le_per_adv_sync_cb_register(&bap_pa_sync_cb);
if (IS_ENABLED(CONFIG_SAMPLE_SCAN_SELF)) {

View file

@ -211,6 +211,7 @@ config BT_BAP_SCAN_DELEGATOR
select BT_EXT_ADV
select BT_PER_ADV_SYNC
select BT_ISO_SYNC_RECEIVER
select BT_GATT_DYNAMIC_DB
depends on BT_BONDABLE
help
This option enables support for the Scan Delegator role and the

View file

@ -87,7 +87,16 @@ struct bt_bap_scan_delegator_inst {
[CONFIG_BT_BAP_SCAN_DELEGATOR_RECV_STATE_COUNT];
};
static bool conn_cb_registered;
enum scan_delegator_flag {
SCAN_DELEGATOR_FLAG_REGISTERED_CONN_CB,
SCAN_DELEGATOR_FLAG_REGISTERED_SCAN_DELIGATOR,
SCAN_DELEGATOR_FLAG_REGISTERED_PA_SYNC_CB,
SCAN_DELEGATOR_FLAG_NUM,
};
static ATOMIC_DEFINE(scan_delegator_flags, SCAN_DELEGATOR_FLAG_NUM);
static struct bt_bap_scan_delegator_inst scan_delegator;
static struct bt_bap_scan_delegator_cb *scan_delegator_cbs;
@ -325,9 +334,9 @@ static struct broadcast_assistant *get_bap_broadcast_assistant(struct bt_conn *c
}
}
if (!conn_cb_registered) {
if (!atomic_test_and_set_bit(scan_delegator_flags,
SCAN_DELEGATOR_FLAG_REGISTERED_CONN_CB)) {
bt_conn_cb_register(&conn_cb);
conn_cb_registered = true;
}
return new;
@ -1157,7 +1166,7 @@ static ssize_t read_recv_state(struct bt_conn *conn,
read_recv_state, NULL, UINT_TO_POINTER(idx)), \
BT_AUDIO_CCC(recv_state_cfg_changed)
BT_GATT_SERVICE_DEFINE(bass_svc,
static struct bt_gatt_attr attr_bass_svc[] = {
BT_GATT_PRIMARY_SERVICE(BT_UUID_BASS),
BT_AUDIO_CHRC(BT_UUID_BASS_CONTROL_POINT,
BT_GATT_CHRC_WRITE_WITHOUT_RESP | BT_GATT_CHRC_WRITE,
@ -1170,10 +1179,58 @@ BT_GATT_SERVICE_DEFINE(bass_svc,
RECEIVE_STATE_CHARACTERISTIC(2)
#endif /* CONFIG_BT_BAP_SCAN_DELEGATOR_RECV_STATE_COUNT > 2 */
#endif /* CONFIG_BT_BAP_SCAN_DELEGATOR_RECV_STATE_COUNT > 1 */
);
};
static int bt_bap_scan_delegator_init(void)
static struct bt_gatt_service bass_svc = BT_GATT_SERVICE(attr_bass_svc);
static int bass_register(void)
{
int err;
err = bt_gatt_service_register(&bass_svc);
if (err) {
LOG_DBG("Failed to register BASS service (err %d)", err);
return err;
}
LOG_DBG("BASS service registered");
return 0;
}
static int bass_unregister(void)
{
int err;
err = bt_gatt_service_unregister(&bass_svc);
if (err) {
LOG_DBG("Failed to unregister BASS service (err %d)", err);
return err;
}
LOG_DBG("BASS service unregistered");
return 0;
}
/****************************** PUBLIC API ******************************/
int bt_bap_scan_delegator_register(struct bt_bap_scan_delegator_cb *cb)
{
int err;
if (atomic_test_and_set_bit(scan_delegator_flags,
SCAN_DELEGATOR_FLAG_REGISTERED_SCAN_DELIGATOR)) {
LOG_DBG("Scan delegator already registered");
return -EALREADY;
}
err = bass_register();
if (err) {
atomic_clear_bit(scan_delegator_flags,
SCAN_DELEGATOR_FLAG_REGISTERED_SCAN_DELIGATOR);
return err;
}
/* Store the pointer to the first characteristic in each receive state */
scan_delegator.recv_states[0].attr = &bass_svc.attrs[3];
scan_delegator.recv_states[0].index = 0;
@ -1186,17 +1243,43 @@ static int bt_bap_scan_delegator_init(void)
#endif /* CONFIG_BT_BAP_SCAN_DELEGATOR_RECV_STATE_COUNT > 2 */
#endif /* CONFIG_BT_BAP_SCAN_DELEGATOR_RECV_STATE_COUNT > 1 */
bt_le_per_adv_sync_cb_register(&pa_sync_cb);
if (!atomic_test_and_set_bit(scan_delegator_flags,
SCAN_DELEGATOR_FLAG_REGISTERED_PA_SYNC_CB)) {
err = bt_le_per_adv_sync_cb_register(&pa_sync_cb);
if (err) {
atomic_clear_bit(scan_delegator_flags,
SCAN_DELEGATOR_FLAG_REGISTERED_PA_SYNC_CB);
atomic_clear_bit(scan_delegator_flags,
SCAN_DELEGATOR_FLAG_REGISTERED_SCAN_DELIGATOR);
return err;
}
}
scan_delegator_cbs = cb;
return 0;
}
SYS_INIT(bt_bap_scan_delegator_init, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEVICE);
/****************************** PUBLIC API ******************************/
void bt_bap_scan_delegator_register_cb(struct bt_bap_scan_delegator_cb *cb)
int bt_bap_scan_delegator_unregister(void)
{
scan_delegator_cbs = cb;
int err;
if (!atomic_test_and_clear_bit(scan_delegator_flags,
SCAN_DELEGATOR_FLAG_REGISTERED_SCAN_DELIGATOR)) {
LOG_DBG("Scan delegator not yet registered");
return -EALREADY;
}
err = bass_unregister();
if (err) {
atomic_set_bit(scan_delegator_flags,
SCAN_DELEGATOR_FLAG_REGISTERED_SCAN_DELIGATOR);
return err;
}
scan_delegator_cbs = NULL;
return 0;
}
int bt_bap_scan_delegator_set_pa_state(uint8_t src_id,

View file

@ -436,8 +436,19 @@ static int cmd_bap_scan_delegator_init(const struct shell *sh, size_t argc,
static bool registered;
if (!registered) {
bt_le_per_adv_sync_cb_register(&pa_sync_cb);
bt_bap_scan_delegator_register_cb(&scan_delegator_cb);
int err;
err = bt_bap_scan_delegator_register(&scan_delegator_cb);
if (err) {
shell_error(sh, "Failed to register scan delegator (err: %d)", err);
return -ENOEXEC;
}
err = bt_le_per_adv_sync_cb_register(&pa_sync_cb);
if (err) {
shell_error(sh, "Failed to register PA sync callbacks (err: %d)", err);
return -ENOEXEC;
}
registered = true;
}

View file

@ -1033,7 +1033,10 @@ uint8_t btp_bap_broadcast_sink_setup(const void *cmd, uint16_t cmd_len,
}
/* For Scan Delegator role */
bt_bap_scan_delegator_register_cb(&scan_delegator_cbs);
err = bt_bap_scan_delegator_register(&scan_delegator_cbs);
if (err != 0) {
return BTP_STATUS_FAILED;
}
/* For Broadcast Sink role */
bt_bap_broadcast_sink_register_cb(&broadcast_sink_cbs);

View file

@ -642,6 +642,12 @@ static int init(void)
return err;
}
err = bt_bap_scan_delegator_register(&scan_delegator_cbs);
if (err) {
FAIL("Scan delegator register failed (err %d)\n", err);
return err;
}
/* Test invalid input */
err = bt_bap_broadcast_sink_register_cb(NULL);
if (err == 0) {
@ -655,7 +661,6 @@ static int init(void)
return err;
}
bt_bap_scan_delegator_register_cb(&scan_delegator_cbs);
bt_le_per_adv_sync_cb_register(&bap_pa_sync_cb);
bt_le_scan_cb_register(&bap_scan_cb);

View file

@ -685,7 +685,12 @@ static int common_init(void)
printk("Bluetooth initialized\n");
bt_bap_scan_delegator_register_cb(&scan_delegator_cb);
err = bt_bap_scan_delegator_register(&scan_delegator_cb);
if (err) {
FAIL("Scan delegator register failed (err %d)\n", err);
return err;
}
bt_le_per_adv_sync_cb_register(&pa_sync_cb);
err = bt_le_adv_start(BT_LE_ADV_CONN_ONE_TIME, ad, AD_SIZE, NULL, 0);

View file

@ -774,10 +774,16 @@ static void init(void)
return;
}
err = bt_bap_scan_delegator_register(&scan_delegator_cbs);
if (err != 0) {
FAIL("Scan deligator register failed (err %d)\n", err);
return;
}
bt_bap_broadcast_sink_register_cb(&broadcast_sink_cbs);
bt_le_per_adv_sync_cb_register(&bap_pa_sync_cb);
bt_le_scan_cb_register(&bap_scan_cb);
bt_bap_scan_delegator_register_cb(&scan_delegator_cbs);
UNSET_FLAG(flag_broadcaster_found);
UNSET_FLAG(flag_broadcast_code);