1 /*
2 * Copyright (c) 2024 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include "zephyr/bluetooth/audio/bap.h"
8 #include "test_common.h"
9
10 static sys_slist_t broadcast_assistant_cbs = SYS_SLIST_STATIC_INIT(&broadcast_assistant_cbs);
11
12 struct bap_broadcast_assistant_recv_state_info {
13 uint8_t src_id;
14 /** Cached PAST available */
15 bool past_avail;
16 uint8_t adv_sid;
17 uint32_t broadcast_id;
18 bt_addr_le_t addr;
19 };
20
21 struct bap_broadcast_assistant_instance {
22 struct bt_conn *conn;
23 struct bap_broadcast_assistant_recv_state_info recv_states;
24 /*
25 * the following are not part of the broadcast_assistant instance, but adding them allow us
26 * to easily check pa_sync and bis_sync states
27 */
28 enum bt_bap_pa_state pa_sync_state;
29 uint8_t num_subgroups;
30 struct bt_bap_bass_subgroup subgroups[CONFIG_BT_BAP_BASS_MAX_SUBGROUPS];
31 };
32
33 static struct bap_broadcast_assistant_instance broadcast_assistants[CONFIG_BT_MAX_CONN];
34 static uint8_t max_src_id;
35
inst_by_conn(struct bt_conn * conn)36 static struct bap_broadcast_assistant_instance *inst_by_conn(struct bt_conn *conn)
37 {
38 struct bap_broadcast_assistant_instance *inst;
39
40 zassert_not_null(conn, "conn is NULL");
41
42 inst = &broadcast_assistants[bt_conn_index(conn)];
43
44 return inst;
45 }
46
bt_bap_broadcast_assistant_register_cb(struct bt_bap_broadcast_assistant_cb * cb)47 int bt_bap_broadcast_assistant_register_cb(struct bt_bap_broadcast_assistant_cb *cb)
48 {
49 struct bt_bap_broadcast_assistant_cb *tmp;
50
51 if (cb == NULL) {
52 return -EINVAL;
53 }
54
55 SYS_SLIST_FOR_EACH_CONTAINER(&broadcast_assistant_cbs, tmp, _node) {
56 if (tmp == cb) {
57 return -EALREADY;
58 }
59 }
60
61 sys_slist_append(&broadcast_assistant_cbs, &cb->_node);
62
63 return 0;
64 }
65
bt_bap_broadcast_assistant_unregister_cb(struct bt_bap_broadcast_assistant_cb * cb)66 int bt_bap_broadcast_assistant_unregister_cb(struct bt_bap_broadcast_assistant_cb *cb)
67 {
68 if (cb == NULL) {
69 return -EINVAL;
70 }
71
72 if (!sys_slist_find_and_remove(&broadcast_assistant_cbs, &cb->_node)) {
73 return -EALREADY;
74 }
75
76 return 0;
77 }
78
bt_bap_broadcast_assistant_add_src(struct bt_conn * conn,const struct bt_bap_broadcast_assistant_add_src_param * param)79 int bt_bap_broadcast_assistant_add_src(struct bt_conn *conn,
80 const struct bt_bap_broadcast_assistant_add_src_param *param)
81 {
82 struct bap_broadcast_assistant_instance *inst;
83 struct bt_bap_scan_delegator_recv_state state;
84 struct bt_bap_broadcast_assistant_cb *listener, *next;
85
86 /* Note that proper parameter checking is done in the caller */
87 zassert_not_null(conn, "conn is NULL");
88 zassert_not_null(param, "param is NULL");
89
90 inst = inst_by_conn(conn);
91 zassert_not_null(inst, "inst is NULL");
92
93 max_src_id++;
94 inst->recv_states.src_id = max_src_id;
95 inst->recv_states.past_avail = false;
96 inst->recv_states.adv_sid = param->adv_sid;
97 inst->recv_states.broadcast_id = param->broadcast_id;
98 inst->pa_sync_state = param->pa_sync;
99 inst->num_subgroups = param->num_subgroups;
100 state.pa_sync_state = param->pa_sync;
101 state.src_id = max_src_id;
102 state.num_subgroups = param->num_subgroups;
103 for (size_t i = 0; i < param->num_subgroups; i++) {
104 state.subgroups[i].bis_sync = param->subgroups[i].bis_sync;
105 inst->subgroups[i].bis_sync = param->subgroups[i].bis_sync;
106 }
107
108 bt_addr_le_copy(&inst->recv_states.addr, ¶m->addr);
109
110 SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&broadcast_assistant_cbs, listener, next, _node) {
111 if (listener->add_src != NULL) {
112 listener->add_src(conn, 0);
113 }
114 if (listener->recv_state != NULL) {
115 listener->recv_state(conn, 0, &state);
116 }
117 }
118
119 return 0;
120 }
121
bt_bap_broadcast_assistant_mod_src(struct bt_conn * conn,const struct bt_bap_broadcast_assistant_mod_src_param * param)122 int bt_bap_broadcast_assistant_mod_src(struct bt_conn *conn,
123 const struct bt_bap_broadcast_assistant_mod_src_param *param)
124 {
125 struct bap_broadcast_assistant_instance *inst;
126 struct bt_bap_scan_delegator_recv_state state;
127 struct bt_bap_broadcast_assistant_cb *listener, *next;
128
129 zassert_not_null(conn, "conn is NULL");
130 zassert_not_null(param, "param is NULL");
131
132 inst = inst_by_conn(conn);
133 zassert_not_null(inst, "inst is NULL");
134
135 state.pa_sync_state = param->pa_sync ? BT_BAP_PA_STATE_SYNCED : BT_BAP_PA_STATE_NOT_SYNCED;
136 state.src_id = param->src_id;
137 inst->recv_states.src_id = param->src_id;
138 inst->pa_sync_state = param->pa_sync;
139
140 state.num_subgroups = param->num_subgroups;
141 inst->num_subgroups = param->num_subgroups;
142 for (size_t i = 0; i < param->num_subgroups; i++) {
143 state.subgroups[i].bis_sync = param->subgroups[i].bis_sync;
144 inst->subgroups[i].bis_sync = param->subgroups[i].bis_sync;
145 }
146 SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&broadcast_assistant_cbs, listener, next, _node) {
147 if (listener->mod_src != NULL) {
148 listener->mod_src(conn, 0);
149 }
150 if (listener->recv_state != NULL) {
151 listener->recv_state(conn, 0, &state);
152 }
153 }
154
155 return 0;
156 }
157
bt_bap_broadcast_assistant_rem_src(struct bt_conn * conn,uint8_t src_id)158 int bt_bap_broadcast_assistant_rem_src(struct bt_conn *conn, uint8_t src_id)
159 {
160 struct bap_broadcast_assistant_instance *inst;
161 struct bt_bap_broadcast_assistant_cb *listener, *next;
162
163 zassert_not_null(conn, "conn is NULL");
164
165 inst = inst_by_conn(conn);
166 zassert_equal(src_id, inst->recv_states.src_id, "Invalid src_id");
167 zassert_equal(BT_BAP_PA_STATE_NOT_SYNCED, inst->pa_sync_state, "Invalid sync state");
168 for (int i = 0; i < inst->num_subgroups; i++) {
169 zassert_equal(0, inst->subgroups[i].bis_sync);
170 }
171
172 SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&broadcast_assistant_cbs, listener, next, _node) {
173 if (listener->rem_src != NULL) {
174 listener->rem_src(conn, 0);
175 }
176 }
177
178 return 0;
179 }
180
bt_bap_broadcast_assistant_set_broadcast_code(struct bt_conn * conn,uint8_t src_id,const uint8_t broadcast_code[BT_ISO_BROADCAST_CODE_SIZE])181 int bt_bap_broadcast_assistant_set_broadcast_code(
182 struct bt_conn *conn, uint8_t src_id,
183 const uint8_t broadcast_code[BT_ISO_BROADCAST_CODE_SIZE])
184 {
185 struct bt_bap_broadcast_assistant_cb *listener, *next;
186 int err;
187
188 zassert_not_null(conn, "conn is NULL");
189
190 zassert_equal(src_id, RANDOM_SRC_ID, "Invalid src_id");
191
192 err = strncmp((const char *)broadcast_code, BROADCAST_CODE, sizeof(BROADCAST_CODE));
193 zassert_equal(0, err, "Unexpected broadcast code");
194
195 SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&broadcast_assistant_cbs, listener, next, _node) {
196 if (listener->broadcast_code != NULL) {
197 listener->broadcast_code(conn, 0);
198 }
199 }
200
201 return 0;
202 }
203