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, &param->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