1 /*
2 * Copyright (c) 2024 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6 #include <errno.h>
7 #include <stdbool.h>
8 #include <stddef.h>
9 #include <stdint.h>
10
11 #include <zephyr/autoconf.h>
12 #include <zephyr/bluetooth/addr.h>
13 #include <zephyr/bluetooth/conn.h>
14 #include <zephyr/bluetooth/audio/bap.h>
15 #include <zephyr/bluetooth/iso.h>
16 #include <zephyr/sys/slist.h>
17 #include <zephyr/ztest_assert.h>
18
19 #include "bap_broadcast_assistant.h"
20 #include "test_common.h"
21
22 static sys_slist_t broadcast_assistant_cbs = SYS_SLIST_STATIC_INIT(&broadcast_assistant_cbs);
23
24 /* when > 0 immediately return from the add_src callback the specified number of times
25 * This allows us to test the CAP cancel command by not successfully sending all the
26 * requests, so that we can cancel before the CAP commander implementation is done
27 * with the procedure.
28 * This is based on the fact that we are not actually sending any requests on air, and
29 * that we are using this function as a synchronous function, rather than an asynchronous
30 * function.
31 */
32 static unsigned int add_src_skip;
33
set_skip_add_src(unsigned int setting)34 void set_skip_add_src(unsigned int setting)
35 {
36 add_src_skip = setting;
37 }
38
39 struct bap_broadcast_assistant_recv_state_info {
40 uint8_t src_id;
41 /** Cached PAST available */
42 bool past_avail;
43 uint8_t adv_sid;
44 uint32_t broadcast_id;
45 bt_addr_le_t addr;
46 };
47
48 struct bap_broadcast_assistant_instance {
49 struct bt_conn *conn;
50 struct bap_broadcast_assistant_recv_state_info recv_states;
51 /*
52 * the following are not part of the broadcast_assistant instance, but adding them allow us
53 * to easily check pa_sync and bis_sync states
54 */
55 enum bt_bap_pa_state pa_sync_state;
56 uint8_t num_subgroups;
57 struct bt_bap_bass_subgroup subgroups[CONFIG_BT_BAP_BASS_MAX_SUBGROUPS];
58 };
59
60 static struct bap_broadcast_assistant_instance broadcast_assistants[CONFIG_BT_MAX_CONN];
61 static uint8_t max_src_id;
62
inst_by_conn(struct bt_conn * conn)63 static struct bap_broadcast_assistant_instance *inst_by_conn(struct bt_conn *conn)
64 {
65 struct bap_broadcast_assistant_instance *inst;
66
67 zassert_not_null(conn, "conn is NULL");
68
69 inst = &broadcast_assistants[bt_conn_index(conn)];
70
71 return inst;
72 }
73
bt_bap_broadcast_assistant_register_cb(struct bt_bap_broadcast_assistant_cb * cb)74 int bt_bap_broadcast_assistant_register_cb(struct bt_bap_broadcast_assistant_cb *cb)
75 {
76 struct bt_bap_broadcast_assistant_cb *tmp;
77
78 if (cb == NULL) {
79 return -EINVAL;
80 }
81
82 SYS_SLIST_FOR_EACH_CONTAINER(&broadcast_assistant_cbs, tmp, _node) {
83 if (tmp == cb) {
84 return -EALREADY;
85 }
86 }
87
88 sys_slist_append(&broadcast_assistant_cbs, &cb->_node);
89
90 return 0;
91 }
92
bt_bap_broadcast_assistant_unregister_cb(struct bt_bap_broadcast_assistant_cb * cb)93 int bt_bap_broadcast_assistant_unregister_cb(struct bt_bap_broadcast_assistant_cb *cb)
94 {
95 if (cb == NULL) {
96 return -EINVAL;
97 }
98
99 if (!sys_slist_find_and_remove(&broadcast_assistant_cbs, &cb->_node)) {
100 return -EALREADY;
101 }
102
103 return 0;
104 }
105
bt_bap_broadcast_assistant_add_src(struct bt_conn * conn,const struct bt_bap_broadcast_assistant_add_src_param * param)106 int bt_bap_broadcast_assistant_add_src(struct bt_conn *conn,
107 const struct bt_bap_broadcast_assistant_add_src_param *param)
108 {
109 struct bap_broadcast_assistant_instance *inst;
110 struct bt_bap_scan_delegator_recv_state state;
111 struct bt_bap_broadcast_assistant_cb *listener, *next;
112
113 if (add_src_skip != 0) {
114 add_src_skip--;
115
116 return 0;
117 }
118
119 /* Note that proper parameter checking is done in the caller */
120 zassert_not_null(conn, "conn is NULL");
121 zassert_not_null(param, "param is NULL");
122
123 inst = inst_by_conn(conn);
124 zassert_not_null(inst, "inst is NULL");
125
126 max_src_id++;
127 inst->recv_states.src_id = max_src_id;
128 inst->recv_states.past_avail = false;
129 inst->recv_states.adv_sid = param->adv_sid;
130 inst->recv_states.broadcast_id = param->broadcast_id;
131 inst->pa_sync_state = param->pa_sync;
132 inst->num_subgroups = param->num_subgroups;
133 state.pa_sync_state = param->pa_sync;
134 state.src_id = max_src_id;
135 state.num_subgroups = param->num_subgroups;
136 for (size_t i = 0; i < param->num_subgroups; i++) {
137 state.subgroups[i].bis_sync = param->subgroups[i].bis_sync;
138 inst->subgroups[i].bis_sync = param->subgroups[i].bis_sync;
139 }
140
141 bt_addr_le_copy(&inst->recv_states.addr, ¶m->addr);
142
143 SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&broadcast_assistant_cbs, listener, next, _node) {
144 if (listener->add_src != NULL) {
145 listener->add_src(conn, 0);
146 }
147 if (listener->recv_state != NULL) {
148 listener->recv_state(conn, 0, &state);
149 }
150 }
151
152 return 0;
153 }
154
bt_bap_broadcast_assistant_mod_src(struct bt_conn * conn,const struct bt_bap_broadcast_assistant_mod_src_param * param)155 int bt_bap_broadcast_assistant_mod_src(struct bt_conn *conn,
156 const struct bt_bap_broadcast_assistant_mod_src_param *param)
157 {
158 struct bap_broadcast_assistant_instance *inst;
159 struct bt_bap_scan_delegator_recv_state state;
160 struct bt_bap_broadcast_assistant_cb *listener, *next;
161
162 zassert_not_null(conn, "conn is NULL");
163 zassert_not_null(param, "param is NULL");
164
165 inst = inst_by_conn(conn);
166 zassert_not_null(inst, "inst is NULL");
167
168 state.pa_sync_state = param->pa_sync ? BT_BAP_PA_STATE_SYNCED : BT_BAP_PA_STATE_NOT_SYNCED;
169 state.src_id = param->src_id;
170 inst->recv_states.src_id = param->src_id;
171 inst->pa_sync_state = param->pa_sync;
172
173 state.num_subgroups = param->num_subgroups;
174 inst->num_subgroups = param->num_subgroups;
175 for (size_t i = 0; i < param->num_subgroups; i++) {
176 state.subgroups[i].bis_sync = param->subgroups[i].bis_sync;
177 inst->subgroups[i].bis_sync = param->subgroups[i].bis_sync;
178 }
179 SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&broadcast_assistant_cbs, listener, next, _node) {
180 if (listener->mod_src != NULL) {
181 listener->mod_src(conn, 0);
182 }
183 if (listener->recv_state != NULL) {
184 listener->recv_state(conn, 0, &state);
185 }
186 }
187
188 return 0;
189 }
190
bt_bap_broadcast_assistant_rem_src(struct bt_conn * conn,uint8_t src_id)191 int bt_bap_broadcast_assistant_rem_src(struct bt_conn *conn, uint8_t src_id)
192 {
193 struct bap_broadcast_assistant_instance *inst;
194 struct bt_bap_broadcast_assistant_cb *listener, *next;
195
196 zassert_not_null(conn, "conn is NULL");
197
198 inst = inst_by_conn(conn);
199 zassert_equal(src_id, inst->recv_states.src_id, "Invalid src_id");
200 zassert_equal(BT_BAP_PA_STATE_NOT_SYNCED, inst->pa_sync_state, "Invalid sync state");
201 for (int i = 0; i < inst->num_subgroups; i++) {
202 zassert_equal(0, inst->subgroups[i].bis_sync);
203 }
204
205 SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&broadcast_assistant_cbs, listener, next, _node) {
206 if (listener->rem_src != NULL) {
207 listener->rem_src(conn, 0);
208 }
209 }
210
211 return 0;
212 }
213
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])214 int bt_bap_broadcast_assistant_set_broadcast_code(
215 struct bt_conn *conn, uint8_t src_id,
216 const uint8_t broadcast_code[BT_ISO_BROADCAST_CODE_SIZE])
217 {
218 struct bt_bap_broadcast_assistant_cb *listener, *next;
219 int err;
220
221 zassert_not_null(conn, "conn is NULL");
222
223 zassert_equal(src_id, RANDOM_SRC_ID, "Invalid src_id");
224
225 err = strncmp((const char *)broadcast_code, BROADCAST_CODE, sizeof(BROADCAST_CODE));
226 zassert_equal(0, err, "Unexpected broadcast code");
227
228 SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&broadcast_assistant_cbs, listener, next, _node) {
229 if (listener->broadcast_code != NULL) {
230 listener->broadcast_code(conn, 0);
231 }
232 }
233
234 return 0;
235 }
236