Skip to content

Commit 70a97a8

Browse files
niym-otkartben
authored andcommitted
Bluetooth: BAP: Add control point cbs to BASS
For the control point operations, add/modify/ remove source, callbacks are added so that Application can decide whether to accept/reject the control point operations. Signed-off-by: Nithin Ramesh Myliattil <niym@demant.com>
1 parent 0f1d7d3 commit 70a97a8

File tree

4 files changed

+176
-22
lines changed

4 files changed

+176
-22
lines changed

include/zephyr/bluetooth/audio/bap.h

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -791,6 +791,52 @@ struct bt_bap_scan_delegator_cb {
791791
* @param is_scanning true if scanning started, false if scanning stopped.
792792
*/
793793
void (*scanning_state)(struct bt_conn *conn, bool is_scanning);
794+
/**
795+
* @brief Add Source operation callback
796+
*
797+
* These callbacks notify the application when a request comes
798+
* in to add a source. The application can return 0 to
799+
* accept or any other value to reject the request.
800+
*
801+
* @param conn Pointer to the connection that initiated the request,
802+
* or NULL if locally triggered.
803+
* @param recv_state Pointer to the requested receive state to be added.
804+
*
805+
* @return 0 in case of accept, or other value to reject.
806+
*/
807+
int (*add_source)(struct bt_conn *conn,
808+
const struct bt_bap_scan_delegator_recv_state *recv_state);
809+
810+
/**
811+
* @brief Modify Source operation callback
812+
*
813+
* These callbacks notify the application when a request comes
814+
* in to modify a source. The application can return 0 to
815+
* accept or any other value to reject the request.
816+
*
817+
* @param conn Pointer to the connection that initiated the request,
818+
* or NULL if locally triggered.
819+
* @param recv_state Pointer to the requested receive state to be modified.
820+
*
821+
* @return 0 in case of accept, or other value to reject.
822+
*/
823+
int (*modify_source)(struct bt_conn *conn,
824+
const struct bt_bap_scan_delegator_recv_state *recv_state);
825+
826+
/**
827+
* @brief Remove Source operation callback
828+
*
829+
* These callbacks notify the application when a request comes
830+
* in to remove a source. The application can return 0 to
831+
* accept or any other value to reject the request.
832+
*
833+
* @param conn Pointer to the connection that initiated the request,
834+
* or NULL if locally triggered.
835+
* @param src_id The Source ID that is requested to be removed.
836+
*
837+
* @return 0 in case of accept, or other value to reject.
838+
*/
839+
int (*remove_source)(struct bt_conn *conn, uint8_t src_id);
794840
};
795841

796842
/** Structure holding information of audio stream endpoint */

subsys/bluetooth/audio/bap_scan_delegator.c

Lines changed: 46 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -743,6 +743,15 @@ static int scan_delegator_add_src(struct bt_conn *conn,
743743
subgroup->metadata_len);
744744
}
745745

746+
if (scan_delegator_cbs != NULL && scan_delegator_cbs->add_source != NULL) {
747+
err = scan_delegator_cbs->add_source(conn, state);
748+
if (err != 0) {
749+
LOG_DBG("add_source callback rejected: 0x%02x", err);
750+
ret = BT_GATT_ERR(BT_ATT_ERR_WRITE_REQ_REJECTED);
751+
goto unlock_return;
752+
}
753+
}
754+
746755
/* The active flag shall be set before any application callbacks, so that any calls for the
747756
* receive state can be processed
748757
*/
@@ -970,6 +979,19 @@ static int scan_delegator_mod_src(struct bt_conn *conn,
970979
}
971980
}
972981

982+
if (scan_delegator_cbs != NULL && scan_delegator_cbs->modify_source != NULL) {
983+
err = scan_delegator_cbs->modify_source(conn, state);
984+
if (err != 0) {
985+
LOG_DBG("Modify Source rejected with reason 0x%02x", err);
986+
(void)memcpy(state, &backup_state, sizeof(backup_state));
987+
988+
err = k_mutex_unlock(&internal_state->mutex);
989+
__ASSERT(err == 0, "Failed to unlock mutex: %d", err);
990+
991+
return BT_GATT_ERR(BT_ATT_ERR_WRITE_REQ_REJECTED);
992+
}
993+
}
994+
973995
/* Only send the sync request to upper layers if it is requested, and
974996
* we are not already synced to the device
975997
*/
@@ -1006,22 +1028,17 @@ static int scan_delegator_mod_src(struct bt_conn *conn,
10061028
} else if (pa_sync == BT_BAP_BASS_PA_REQ_NO_SYNC &&
10071029
(state->pa_sync_state == BT_BAP_PA_STATE_INFO_REQ ||
10081030
state->pa_sync_state == BT_BAP_PA_STATE_SYNCED)) {
1009-
/* Unlock mutex to avoid potential deadlock on app callback */
1010-
err = k_mutex_unlock(&internal_state->mutex);
1011-
__ASSERT(err == 0, "Failed to unlock mutex: %d", err);
1012-
10131031
/* Terminate PA sync */
10141032
err = pa_sync_term_request(conn, &internal_state->state);
10151033

10161034
if (err != 0) {
10171035
LOG_DBG("PA sync term from %p was rejected with reason %d", (void *)conn,
10181036
err);
1019-
1037+
err = k_mutex_unlock(&internal_state->mutex);
1038+
__ASSERT(err == 0, "Failed to unlock mutex: %d", err);
10201039
return BT_GATT_ERR(BT_ATT_ERR_WRITE_REQ_REJECTED);
10211040
}
1022-
10231041
state_changed = true;
1024-
k_mutex_lock(&internal_state->mutex, K_FOREVER);
10251042
}
10261043

10271044
/* Store requested_bis_sync after everything has been validated */
@@ -1122,22 +1139,30 @@ static int scan_delegator_rem_src(struct bt_conn *conn,
11221139
state = &internal_state->state;
11231140

11241141
/* If conn == NULL then it's a local operation and we do not need to ask the application */
1125-
if (conn != NULL && (state->pa_sync_state == BT_BAP_PA_STATE_INFO_REQ ||
1126-
state->pa_sync_state == BT_BAP_PA_STATE_SYNCED)) {
1127-
/* Unlock mutex to avoid potential deadlock on app callback */
1128-
err = k_mutex_unlock(&internal_state->mutex);
1129-
__ASSERT(err == 0, "Failed to unlock mutex: %d", err);
1130-
1131-
/* Terminate PA sync */
1132-
err = pa_sync_term_request(conn, &internal_state->state);
1133-
if (err != 0) {
1134-
LOG_DBG("PA sync term from %p was rejected with reason %d", (void *)conn,
1135-
err);
1136-
1137-
return BT_GATT_ERR(BT_ATT_ERR_WRITE_REQ_REJECTED);
1142+
if (conn != NULL) {
1143+
1144+
if (scan_delegator_cbs != NULL && scan_delegator_cbs->remove_source != NULL) {
1145+
err = scan_delegator_cbs->remove_source(conn, src_id);
1146+
if (err != 0) {
1147+
LOG_DBG("Remove Source rejected with reason 0x%02x", err);
1148+
err = k_mutex_unlock(&internal_state->mutex);
1149+
__ASSERT(err == 0, "Failed to unlock mutex: %d", err);
1150+
return BT_GATT_ERR(BT_ATT_ERR_WRITE_REQ_REJECTED);
1151+
}
11381152
}
11391153

1140-
k_mutex_lock(&internal_state->mutex, K_FOREVER);
1154+
if (state->pa_sync_state == BT_BAP_PA_STATE_INFO_REQ ||
1155+
state->pa_sync_state == BT_BAP_PA_STATE_SYNCED) {
1156+
/* Terminate PA sync */
1157+
err = pa_sync_term_request(conn, &internal_state->state);
1158+
if (err != 0) {
1159+
LOG_DBG("PA sync term from %p was rejected with reason %d",
1160+
(void *)conn, err);
1161+
err = k_mutex_unlock(&internal_state->mutex);
1162+
__ASSERT(err == 0, "Failed to unlock mutex: %d", err);
1163+
return BT_GATT_ERR(BT_ATT_ERR_WRITE_REQ_REJECTED);
1164+
}
1165+
}
11411166
}
11421167

11431168
for (uint8_t i = 0U; i < state->num_subgroups; i++) {

tests/bsim/bluetooth/audio/src/bap_broadcast_assistant_test.c

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ CREATE_FLAG(flag_recv_state_updated_with_bis_sync);
5151
CREATE_FLAG(flag_recv_state_removed);
5252
CREATE_FLAG(flag_broadcast_code_requested);
5353
CREATE_FLAG(flag_incorrect_broadcast_code);
54+
CREATE_FLAG(flag_remove_source_cb_called);
55+
CREATE_FLAG(flag_remove_source_rejected);
5456

5557
/* Broadcaster variables */
5658
static bt_addr_le_t g_broadcaster_addr;
@@ -256,8 +258,16 @@ static void bap_broadcast_assistant_broadcast_code_cb(struct bt_conn *conn, int
256258

257259
static void bap_broadcast_assistant_rem_src_cb(struct bt_conn *conn, int err)
258260
{
261+
SET_FLAG(flag_remove_source_cb_called);
262+
259263
if (err != 0) {
260-
FAIL("BASS remove source failed (%d)\n", err);
264+
if (err == BT_ATT_ERR_WRITE_REQ_REJECTED) {
265+
SET_FLAG(flag_remove_source_rejected);
266+
printk("Remove source rejected (expected): err=%d\n", err);
267+
return;
268+
}
269+
270+
FAIL("BASS remove source failed (err %d)\n", err);
261271
return;
262272
}
263273

@@ -690,12 +700,23 @@ static void test_bass_remove_source(void)
690700
printk("Removing source\n");
691701
UNSET_FLAG(flag_cb_called);
692702
UNSET_FLAG(flag_write_complete);
703+
UNSET_FLAG(flag_remove_source_cb_called);
704+
UNSET_FLAG(flag_remove_source_rejected);
705+
693706
err = bt_bap_broadcast_assistant_rem_src(default_conn, recv_state.src_id);
694707
if (err != 0) {
695708
FAIL("Could not remove source (err %d)\n", err);
696709
return;
697710
}
698711

712+
/* Wait for the remove callback to be invoked */
713+
WAIT_FOR_FLAG(flag_remove_source_cb_called);
714+
715+
if (TEST_FLAG(flag_remove_source_rejected)) {
716+
printk("Remove source was rejected as expected\n");
717+
return;
718+
}
719+
699720
WAIT_FOR_FLAG(flag_cb_called);
700721
WAIT_FOR_FLAG(flag_write_complete);
701722
printk("Source removed\n");
@@ -803,6 +824,12 @@ static void test_main_server_sync_client_rem(void)
803824
printk("Waiting for receive state with BIS sync\n");
804825
WAIT_FOR_FLAG(flag_recv_state_updated_with_bis_sync);
805826

827+
printk("Attempting to remove source for the first time\n");
828+
test_bass_remove_source();
829+
830+
WAIT_FOR_FLAG(flag_remove_source_rejected);
831+
printk("First remove source attempt was rejected as expected\n");
832+
806833
test_bass_remove_source();
807834

808835
PASS("BAP Broadcast Assistant Server Sync Passed\n");

tests/bsim/bluetooth/audio/src/bap_scan_delegator_test.c

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,13 @@ CREATE_FLAG(flag_broadcast_code_received);
4040
CREATE_FLAG(flag_recv_state_updated);
4141
CREATE_FLAG(flag_bis_sync_requested);
4242
CREATE_FLAG(flag_bis_sync_term_requested);
43+
CREATE_FLAG(flag_broadcast_source_added);
44+
CREATE_FLAG(flag_broadcast_source_modified);
45+
CREATE_FLAG(flag_broadcast_source_removed);
46+
CREATE_FLAG(flag_remove_source_rejected);
47+
4348
static volatile uint32_t g_broadcast_id;
49+
static bool reject_control_op;
4450

4551
struct sync_state {
4652
uint8_t src_id;
@@ -240,13 +246,21 @@ static void recv_state_updated_cb(struct bt_conn *conn,
240246
SET_FLAG(flag_recv_state_updated);
241247
}
242248

249+
static void reset_cp_flags(void)
250+
{
251+
UNSET_FLAG(flag_broadcast_source_added);
252+
UNSET_FLAG(flag_broadcast_source_modified);
253+
UNSET_FLAG(flag_broadcast_source_removed);
254+
}
255+
243256
static int pa_sync_req_cb(struct bt_conn *conn,
244257
const struct bt_bap_scan_delegator_recv_state *recv_state,
245258
bool past_avail, uint16_t pa_interval)
246259
{
247260
struct sync_state *state;
248261
int err;
249262

263+
reset_cp_flags();
250264
printk("PA Sync request: past_avail %u, pa_interval 0x%04x\n: %p",
251265
past_avail, pa_interval, recv_state);
252266

@@ -351,12 +365,44 @@ static int bis_sync_req_cb(struct bt_conn *conn,
351365
return 0;
352366
}
353367

368+
static int add_source_cb(struct bt_conn *conn,
369+
const struct bt_bap_scan_delegator_recv_state *recv_state)
370+
{
371+
printk("Add Source callback: src_id=%u\n", recv_state->src_id);
372+
SET_FLAG(flag_broadcast_source_added);
373+
return 0;
374+
}
375+
376+
static int modify_source_cb(struct bt_conn *conn,
377+
const struct bt_bap_scan_delegator_recv_state *recv_state)
378+
{
379+
printk("Modify Source callback: src_id=%u\n", recv_state->src_id);
380+
SET_FLAG(flag_broadcast_source_modified);
381+
return 0;
382+
}
383+
384+
static int remove_source_cb(struct bt_conn *conn, uint8_t src_id)
385+
{
386+
printk("Remove Source callback: src_id=%u\n", src_id);
387+
388+
if (reject_control_op) {
389+
SET_FLAG(flag_remove_source_rejected);
390+
return BT_ATT_ERR_WRITE_REQ_REJECTED;
391+
}
392+
393+
SET_FLAG(flag_broadcast_source_removed);
394+
return 0;
395+
}
396+
354397
static struct bt_bap_scan_delegator_cb scan_delegator_cb = {
355398
.recv_state_updated = recv_state_updated_cb,
356399
.pa_sync_req = pa_sync_req_cb,
357400
.pa_sync_term_req = pa_sync_term_req_cb,
358401
.broadcast_code = broadcast_code_cb,
359402
.bis_sync_req = bis_sync_req_cb,
403+
.add_source = add_source_cb,
404+
.modify_source = modify_source_cb,
405+
.remove_source = remove_source_cb
360406
};
361407

362408
static void pa_synced_cb(struct bt_le_per_adv_sync *sync,
@@ -728,13 +774,15 @@ static void test_main_client_sync(void)
728774
return;
729775
}
730776

777+
WAIT_FOR_FLAG(flag_broadcast_source_added);
731778
/* Wait for broadcast assistant to request us to sync to PA */
732779
printk("Waiting for flag_pa_synced\n");
733780
WAIT_FOR_FLAG(flag_pa_synced);
734781

735782
/* Mod all sources by modifying the metadata */
736783
mod_all_sources();
737784

785+
WAIT_FOR_FLAG(flag_broadcast_source_modified);
738786
/* Wait for broadcast assistant to tell us to BIS sync */
739787
printk("Waiting for flag_bis_sync_requested\n");
740788
WAIT_FOR_FLAG(flag_bis_sync_requested);
@@ -750,6 +798,7 @@ static void test_main_client_sync(void)
750798
printk("Waiting for flag_pa_terminated\n");
751799
WAIT_FOR_FLAG(flag_pa_terminated);
752800

801+
WAIT_FOR_FLAG(flag_broadcast_source_removed);
753802
PASS("BAP Scan Delegator Client Sync passed\n");
754803
}
755804

@@ -788,6 +837,13 @@ static void test_main_server_sync_client_rem(void)
788837
/* Set the BIS sync state */
789838
sync_all_broadcasts();
790839

840+
/* Enable rejection for the first remove source request */
841+
reject_control_op = true;
842+
843+
WAIT_FOR_FLAG(flag_remove_source_rejected);
844+
845+
/* Disable rejection for subsequent remove source requests */
846+
reject_control_op = false;
791847
/* For for client to remove source and thus terminate the PA */
792848
printk("Waiting for flag_pa_terminated\n");
793849
WAIT_FOR_FLAG(flag_pa_terminated);

0 commit comments

Comments
 (0)