1 /*
2  * Copyright (c) 2024 Demant A/S
3  * Copyright (c) 2024 Nordic Semiconductor ASA
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 #include <errno.h>
9 #include <stddef.h>
10 #include <stdint.h>
11 #include <string.h>
12 #include <strings.h>
13 
14 #include <zephyr/autoconf.h>
15 #include <zephyr/bluetooth/addr.h>
16 #include <zephyr/bluetooth/audio/audio.h>
17 #include <zephyr/bluetooth/audio/bap.h>
18 #include <zephyr/bluetooth/bluetooth.h>
19 #include <zephyr/bluetooth/conn.h>
20 #include <zephyr/bluetooth/gap.h>
21 #include <zephyr/bluetooth/hci.h>
22 #include <zephyr/bluetooth/hci_types.h>
23 #include <zephyr/bluetooth/iso.h>
24 #include <zephyr/bluetooth/uuid.h>
25 #include <zephyr/kernel.h>
26 #include <zephyr/net_buf.h>
27 #include <zephyr/sys/byteorder.h>
28 #include <zephyr/sys/printk.h>
29 #include <zephyr/sys/util.h>
30 #include <zephyr/types.h>
31 
32 #define NAME_LEN 30
33 #define PA_SYNC_SKIP         5
34 #define PA_SYNC_INTERVAL_TO_TIMEOUT_RATIO 20 /* Set the timeout relative to interval */
35 /* Broadcast IDs are 24bit, so this is out of valid range */
36 
37 static void scan_for_broadcast_sink(void);
38 
39 /* Struct to collect information from scanning
40  * for Broadcast Source or Sink
41  */
42 struct scan_recv_info {
43 	char bt_name[NAME_LEN];
44 	char broadcast_name[NAME_LEN];
45 	uint32_t broadcast_id;
46 	bool has_bass;
47 	bool has_pacs;
48 };
49 
50 static struct bt_conn *broadcast_sink_conn;
51 static uint32_t selected_broadcast_id;
52 static uint8_t selected_sid;
53 static uint16_t selected_pa_interval;
54 static bt_addr_le_t selected_addr;
55 static struct bt_le_per_adv_sync *pa_sync;
56 static uint8_t received_base[UINT8_MAX];
57 static size_t received_base_size;
58 static struct bt_bap_bass_subgroup
59 	bass_subgroups[CONFIG_BT_BAP_BASS_MAX_SUBGROUPS];
60 
61 static bool scanning_for_broadcast_source;
62 
63 static struct k_mutex base_store_mutex;
64 static K_SEM_DEFINE(sem_source_discovered, 0, 1);
65 static K_SEM_DEFINE(sem_sink_discovered, 0, 1);
66 static K_SEM_DEFINE(sem_sink_connected, 0, 1);
67 static K_SEM_DEFINE(sem_sink_disconnected, 0, 1);
68 static K_SEM_DEFINE(sem_security_updated, 0, 1);
69 static K_SEM_DEFINE(sem_bass_discovered, 0, 1);
70 static K_SEM_DEFINE(sem_pa_synced, 0, 1);
71 static K_SEM_DEFINE(sem_received_base_subgroups, 0, 1);
72 
device_found(struct bt_data * data,void * user_data)73 static bool device_found(struct bt_data *data, void *user_data)
74 {
75 	struct scan_recv_info *sr_info = (struct scan_recv_info *)user_data;
76 	struct bt_uuid_16 adv_uuid;
77 
78 	switch (data->type) {
79 	case BT_DATA_NAME_SHORTENED:
80 	case BT_DATA_NAME_COMPLETE:
81 		memcpy(sr_info->bt_name, data->data, MIN(data->data_len, NAME_LEN - 1));
82 		return true;
83 	case BT_DATA_BROADCAST_NAME:
84 		memcpy(sr_info->broadcast_name, data->data, MIN(data->data_len, NAME_LEN - 1));
85 		return true;
86 	case BT_DATA_SVC_DATA16:
87 		/* Check for Broadcast ID */
88 		if (data->data_len < BT_UUID_SIZE_16 + BT_AUDIO_BROADCAST_ID_SIZE) {
89 			return true;
90 		}
91 
92 		if (!bt_uuid_create(&adv_uuid.uuid, data->data, BT_UUID_SIZE_16)) {
93 			return true;
94 		}
95 
96 		if (bt_uuid_cmp(&adv_uuid.uuid, BT_UUID_BROADCAST_AUDIO) != 0) {
97 			return true;
98 		}
99 
100 		sr_info->broadcast_id = sys_get_le24(data->data + BT_UUID_SIZE_16);
101 		return true;
102 	case BT_DATA_UUID16_SOME:
103 	case BT_DATA_UUID16_ALL:
104 		/* NOTE: According to the BAP 1.0.1 Spec,
105 		 * Section 3.9.2. Additional Broadcast Audio Scan Service requirements,
106 		 * If the Scan Delegator implements a Broadcast Sink, it should also
107 		 * advertise a Service Data field containing the Broadcast Audio
108 		 * Scan Service (BASS) UUID.
109 		 *
110 		 * However, it seems that this is not the case with the sinks available
111 		 * while developing this sample application.  Therefore, we instead,
112 		 * search for the existence of BASS and PACS in the list of service UUIDs,
113 		 * which does seem to exist in the sinks available.
114 		 */
115 
116 		/* Check for BASS and PACS */
117 		if (data->data_len % sizeof(uint16_t) != 0U) {
118 			printk("UUID16 AD malformed\n");
119 			return true;
120 		}
121 
122 		for (size_t i = 0; i < data->data_len; i += sizeof(uint16_t)) {
123 			const struct bt_uuid *uuid;
124 			uint16_t u16;
125 
126 			memcpy(&u16, &data->data[i], sizeof(u16));
127 			uuid = BT_UUID_DECLARE_16(sys_le16_to_cpu(u16));
128 
129 			if (bt_uuid_cmp(uuid, BT_UUID_BASS) == 0) {
130 				sr_info->has_bass = true;
131 				continue;
132 			}
133 
134 			if (bt_uuid_cmp(uuid, BT_UUID_PACS) == 0) {
135 				sr_info->has_pacs = true;
136 				continue;
137 			}
138 		}
139 		return true;
140 	default:
141 		return true;
142 	}
143 }
144 
base_store(struct bt_data * data,void * user_data)145 static bool base_store(struct bt_data *data, void *user_data)
146 {
147 	const struct bt_bap_base *base = bt_bap_base_get_base_from_ad(data);
148 	int base_size;
149 	int base_subgroup_count;
150 
151 	/* Base is NULL if the data does not contain a valid BASE */
152 	if (base == NULL) {
153 		return true;
154 	}
155 
156 	/* Can not fit all the received subgroups with the size CONFIG_BT_BAP_BASS_MAX_SUBGROUPS */
157 	base_subgroup_count = bt_bap_base_get_subgroup_count(base);
158 	if (base_subgroup_count < 0 || base_subgroup_count > CONFIG_BT_BAP_BASS_MAX_SUBGROUPS) {
159 		printk("Got invalid subgroup count: %d\n", base_subgroup_count);
160 		return true;
161 	}
162 
163 	base_size = bt_bap_base_get_size(base);
164 	if (base_size < 0) {
165 		printk("BASE get size failed (%d)\n", base_size);
166 
167 		return true;
168 	}
169 
170 	/* Compare BASE and copy if different */
171 	k_mutex_lock(&base_store_mutex, K_FOREVER);
172 	if ((size_t)base_size != received_base_size ||
173 	    memcmp(base, received_base, (size_t)base_size) != 0) {
174 		(void)memcpy(received_base, base, base_size);
175 		received_base_size = (size_t)base_size;
176 	}
177 	k_mutex_unlock(&base_store_mutex);
178 
179 	/* Stop parsing */
180 	k_sem_give(&sem_received_base_subgroups);
181 	return false;
182 }
183 
pa_recv(struct bt_le_per_adv_sync * sync,const struct bt_le_per_adv_sync_recv_info * info,struct net_buf_simple * buf)184 static void pa_recv(struct bt_le_per_adv_sync *sync,
185 			 const struct bt_le_per_adv_sync_recv_info *info,
186 			 struct net_buf_simple *buf)
187 {
188 	bt_data_parse(buf, base_store, NULL);
189 }
190 
add_pa_sync_base_subgroup_bis_cb(const struct bt_bap_base_subgroup_bis * bis,void * user_data)191 static bool add_pa_sync_base_subgroup_bis_cb(const struct bt_bap_base_subgroup_bis *bis,
192 					     void *user_data)
193 {
194 	struct bt_bap_bass_subgroup *subgroup_param = user_data;
195 
196 	subgroup_param->bis_sync |= BT_ISO_BIS_INDEX_BIT(bis->index);
197 
198 	return true;
199 }
200 
add_pa_sync_base_subgroup_cb(const struct bt_bap_base_subgroup * subgroup,void * user_data)201 static bool add_pa_sync_base_subgroup_cb(const struct bt_bap_base_subgroup *subgroup,
202 					 void *user_data)
203 {
204 	struct bt_bap_broadcast_assistant_add_src_param *param = user_data;
205 	struct bt_bap_bass_subgroup *subgroup_param;
206 	uint8_t *data;
207 	int ret;
208 
209 	ret = bt_bap_base_get_subgroup_codec_meta(subgroup, &data);
210 	if (ret < 0) {
211 		return false;
212 	}
213 
214 	subgroup_param = param->subgroups;
215 
216 	if (ret > ARRAY_SIZE(subgroup_param->metadata)) {
217 		printk("Cannot fit %d octets into subgroup param with size %zu", ret,
218 		       ARRAY_SIZE(subgroup_param->metadata));
219 		return false;
220 	}
221 
222 	ret = bt_bap_base_subgroup_foreach_bis(subgroup, add_pa_sync_base_subgroup_bis_cb,
223 					       subgroup_param);
224 	if (ret < 0) {
225 		return false;
226 	}
227 
228 	param->num_subgroups++;
229 
230 	return true;
231 }
232 
is_substring(const char * substr,const char * str)233 static bool is_substring(const char *substr, const char *str)
234 {
235 	const size_t str_len = strlen(str);
236 	const size_t sub_str_len = strlen(substr);
237 
238 	if (sub_str_len > str_len) {
239 		return false;
240 	}
241 
242 	for (size_t pos = 0; pos < str_len; pos++) {
243 		if (pos + sub_str_len > str_len) {
244 			return false;
245 		}
246 
247 		if (strncasecmp(substr, &str[pos], sub_str_len) == 0) {
248 			return true;
249 		}
250 	}
251 
252 	return false;
253 }
254 
interval_to_sync_timeout(uint16_t pa_interval)255 static uint16_t interval_to_sync_timeout(uint16_t pa_interval)
256 {
257 	uint16_t pa_timeout;
258 
259 	if (pa_interval == BT_BAP_PA_INTERVAL_UNKNOWN) {
260 		/* Use maximum value to maximize chance of success */
261 		pa_timeout = BT_GAP_PER_ADV_MAX_TIMEOUT;
262 	} else {
263 		uint32_t interval_us;
264 		uint32_t timeout;
265 
266 		/* Add retries and convert to unit in 10's of ms */
267 		interval_us = BT_GAP_PER_ADV_INTERVAL_TO_US(pa_interval);
268 		timeout = BT_GAP_US_TO_PER_ADV_SYNC_TIMEOUT(interval_us) *
269 			  PA_SYNC_INTERVAL_TO_TIMEOUT_RATIO;
270 
271 		/* Enforce restraints */
272 		pa_timeout = CLAMP(timeout, BT_GAP_PER_ADV_MIN_TIMEOUT, BT_GAP_PER_ADV_MAX_TIMEOUT);
273 	}
274 
275 	return pa_timeout;
276 }
277 
pa_sync_create(void)278 static int pa_sync_create(void)
279 {
280 	struct bt_le_per_adv_sync_param create_params = {0};
281 
282 	bt_addr_le_copy(&create_params.addr, &selected_addr);
283 	create_params.options = BT_LE_PER_ADV_SYNC_OPT_FILTER_DUPLICATE;
284 	create_params.sid = selected_sid;
285 	create_params.skip = PA_SYNC_SKIP;
286 	create_params.timeout = interval_to_sync_timeout(selected_pa_interval);
287 
288 	return bt_le_per_adv_sync_create(&create_params, &pa_sync);
289 }
290 
scan_recv_cb(const struct bt_le_scan_recv_info * info,struct net_buf_simple * ad)291 static void scan_recv_cb(const struct bt_le_scan_recv_info *info,
292 			 struct net_buf_simple *ad)
293 {
294 	int err;
295 	struct scan_recv_info sr_info = {0};
296 
297 	if (scanning_for_broadcast_source) {
298 		/* Scan for and select Broadcast Source */
299 
300 		sr_info.broadcast_id = BT_BAP_INVALID_BROADCAST_ID;
301 
302 		/* We are only interested in non-connectable periodic advertisers */
303 		if ((info->adv_props & BT_GAP_ADV_PROP_CONNECTABLE) != 0 ||
304 		    info->interval == 0) {
305 			return;
306 		}
307 
308 		bt_data_parse(ad, device_found, (void *)&sr_info);
309 
310 		if (sr_info.broadcast_id != BT_BAP_INVALID_BROADCAST_ID) {
311 			printk("Broadcast Source Found:\n");
312 			printk("  BT Name:        %s\n", sr_info.bt_name);
313 			printk("  Broadcast Name: %s\n", sr_info.broadcast_name);
314 			printk("  Broadcast ID:   0x%06x\n\n", sr_info.broadcast_id);
315 
316 #if defined(CONFIG_SELECT_SOURCE_NAME)
317 			if (strlen(CONFIG_SELECT_SOURCE_NAME) > 0U) {
318 				/* Compare names with CONFIG_SELECT_SOURCE_NAME */
319 				if (is_substring(CONFIG_SELECT_SOURCE_NAME, sr_info.bt_name) ||
320 				    is_substring(CONFIG_SELECT_SOURCE_NAME,
321 						 sr_info.broadcast_name)) {
322 					printk("Match found for '%s'\n", CONFIG_SELECT_SOURCE_NAME);
323 				} else {
324 					printk("'%s' not found in names\n\n",
325 					       CONFIG_SELECT_SOURCE_NAME);
326 					return;
327 				}
328 			}
329 #endif /* CONFIG_SELECT_SOURCE_NAME */
330 
331 			err = bt_le_scan_stop();
332 			if (err != 0) {
333 				printk("bt_le_scan_stop failed with %d\n", err);
334 			}
335 
336 			/* TODO: Add support for syncing to the PA and parsing the BASE
337 			 * in order to obtain the right subgroup information to send to
338 			 * the sink when adding a broadcast source (see in main function below).
339 			 */
340 
341 			printk("Selecting Broadcast ID: 0x%06x\n", sr_info.broadcast_id);
342 
343 			selected_broadcast_id = sr_info.broadcast_id;
344 			selected_sid = info->sid;
345 			selected_pa_interval = info->interval;
346 			bt_addr_le_copy(&selected_addr, info->addr);
347 
348 			k_sem_give(&sem_source_discovered);
349 
350 			printk("Attempting to PA sync to the broadcaster with id 0x%06X\n",
351 			       selected_broadcast_id);
352 		}
353 	} else {
354 		/* Scan for and connect to Broadcast Sink */
355 
356 		/* We are only interested in connectable advertisers */
357 		if ((info->adv_props & BT_GAP_ADV_PROP_CONNECTABLE) == 0) {
358 			return;
359 		}
360 
361 		bt_data_parse(ad, device_found, (void *)&sr_info);
362 
363 		if (sr_info.has_bass && sr_info.has_pacs) {
364 			printk("Broadcast Sink Found:\n");
365 			printk("  BT Name:        %s\n", sr_info.bt_name);
366 
367 			if (strlen(CONFIG_SELECT_SINK_NAME) > 0U) {
368 				/* Compare names with CONFIG_SELECT_SINK_NAME */
369 				if (is_substring(CONFIG_SELECT_SINK_NAME, sr_info.bt_name)) {
370 					printk("Match found for '%s'\n", CONFIG_SELECT_SINK_NAME);
371 				} else {
372 					printk("'%s' not found in names\n\n",
373 					       CONFIG_SELECT_SINK_NAME);
374 					return;
375 				}
376 			}
377 
378 			err = bt_le_scan_stop();
379 			if (err != 0) {
380 				printk("bt_le_scan_stop failed with %d\n", err);
381 			}
382 
383 			printk("Connecting to Broadcast Sink: %s\n", sr_info.bt_name);
384 
385 			err = bt_conn_le_create(info->addr, BT_CONN_LE_CREATE_CONN,
386 						BT_LE_CONN_PARAM_DEFAULT,
387 						&broadcast_sink_conn);
388 			if (err != 0) {
389 				printk("Failed creating connection (err=%u)\n", err);
390 				scan_for_broadcast_sink();
391 			}
392 
393 			k_sem_give(&sem_sink_discovered);
394 		}
395 	}
396 }
397 
scan_timeout_cb(void)398 static void scan_timeout_cb(void)
399 {
400 	printk("Scan timeout\n");
401 }
402 
403 static struct bt_le_scan_cb scan_callbacks = {
404 	.recv = scan_recv_cb,
405 	.timeout = scan_timeout_cb,
406 };
407 
scan_for_broadcast_source(void)408 static void scan_for_broadcast_source(void)
409 {
410 	int err;
411 
412 	scanning_for_broadcast_source = true;
413 
414 	err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, NULL);
415 	if (err) {
416 		printk("Scanning failed to start (err %d)\n", err);
417 		return;
418 	}
419 
420 	printk("Scanning for Broadcast Source successfully started\n");
421 
422 	err = k_sem_take(&sem_source_discovered, K_FOREVER);
423 	if (err != 0) {
424 		printk("Failed to take sem_source_discovered (err %d)\n", err);
425 	}
426 }
427 
scan_for_broadcast_sink(void)428 static void scan_for_broadcast_sink(void)
429 {
430 	int err;
431 
432 	scanning_for_broadcast_source = false;
433 
434 	err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, NULL);
435 	if (err) {
436 		printk("Scanning failed to start (err %d)\n", err);
437 		return;
438 	}
439 
440 	printk("Scanning for Broadcast Sink successfully started\n");
441 
442 	err = k_sem_take(&sem_sink_discovered, K_FOREVER);
443 	if (err != 0) {
444 		printk("Failed to take sem_sink_discovered (err %d)\n", err);
445 	}
446 }
447 
connected(struct bt_conn * conn,uint8_t err)448 static void connected(struct bt_conn *conn, uint8_t err)
449 {
450 	char addr[BT_ADDR_LE_STR_LEN];
451 
452 	(void)bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
453 
454 	if (err != 0) {
455 		printk("Failed to connect to %s %u %s\n", addr, err, bt_hci_err_to_str(err));
456 
457 		bt_conn_unref(broadcast_sink_conn);
458 		broadcast_sink_conn = NULL;
459 
460 		scan_for_broadcast_sink();
461 		return;
462 	}
463 
464 	if (conn != broadcast_sink_conn) {
465 		return;
466 	}
467 
468 	printk("Connected: %s\n", addr);
469 	k_sem_give(&sem_sink_connected);
470 }
471 
disconnected(struct bt_conn * conn,uint8_t reason)472 static void disconnected(struct bt_conn *conn, uint8_t reason)
473 {
474 	char addr[BT_ADDR_LE_STR_LEN];
475 
476 	if (conn != broadcast_sink_conn) {
477 		return;
478 	}
479 
480 	(void)bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
481 
482 	printk("Disconnected: %s, reason 0x%02x %s\n", addr, reason, bt_hci_err_to_str(reason));
483 
484 	bt_conn_unref(broadcast_sink_conn);
485 	broadcast_sink_conn = NULL;
486 
487 	k_sem_give(&sem_sink_disconnected);
488 }
489 
security_changed_cb(struct bt_conn * conn,bt_security_t level,enum bt_security_err err)490 static void security_changed_cb(struct bt_conn *conn, bt_security_t level,
491 				enum bt_security_err err)
492 {
493 	if (err == 0) {
494 		printk("Security level changed: %u\n", level);
495 		k_sem_give(&sem_security_updated);
496 	} else {
497 		printk("Failed to set security level: %s(%u)\n", bt_security_err_to_str(err), err);
498 	}
499 }
500 
bap_broadcast_assistant_discover_cb(struct bt_conn * conn,int err,uint8_t recv_state_count)501 static void bap_broadcast_assistant_discover_cb(struct bt_conn *conn, int err,
502 						uint8_t recv_state_count)
503 {
504 	if (err == 0) {
505 		printk("BASS discover done with %u recv states\n",
506 		       recv_state_count);
507 		k_sem_give(&sem_bass_discovered);
508 	} else {
509 		printk("BASS discover failed (%d)\n", err);
510 	}
511 }
512 
bap_broadcast_assistant_add_src_cb(struct bt_conn * conn,int err)513 static void bap_broadcast_assistant_add_src_cb(struct bt_conn *conn, int err)
514 {
515 	if (err == 0) {
516 		printk("BASS add source successful\n");
517 	} else {
518 		printk("BASS add source failed (%d)\n", err);
519 	}
520 }
521 
pa_sync_synced_cb(struct bt_le_per_adv_sync * sync,struct bt_le_per_adv_sync_synced_info * info)522 static void pa_sync_synced_cb(struct bt_le_per_adv_sync *sync,
523 			      struct bt_le_per_adv_sync_synced_info *info)
524 {
525 	if (sync == pa_sync) {
526 		printk("PA sync %p synced for broadcast sink with broadcast ID 0x%06X\n", sync,
527 		       selected_broadcast_id);
528 
529 		k_sem_give(&sem_pa_synced);
530 	}
531 }
532 
533 static struct bt_bap_broadcast_assistant_cb ba_cbs = {
534 	.discover = bap_broadcast_assistant_discover_cb,
535 	.add_src = bap_broadcast_assistant_add_src_cb,
536 };
537 
538 static struct bt_le_per_adv_sync_cb pa_synced_cb = {
539 	.synced = pa_sync_synced_cb,
540 	.recv = pa_recv,
541 };
542 
reset(void)543 static void reset(void)
544 {
545 	printk("\n\nReset...\n\n");
546 
547 	broadcast_sink_conn = NULL;
548 	selected_broadcast_id = BT_BAP_INVALID_BROADCAST_ID;
549 	selected_sid = 0;
550 	selected_pa_interval = 0;
551 	(void)memset(&selected_addr, 0, sizeof(selected_addr));
552 
553 	k_sem_reset(&sem_source_discovered);
554 	k_sem_reset(&sem_sink_discovered);
555 	k_sem_reset(&sem_sink_connected);
556 	k_sem_reset(&sem_sink_disconnected);
557 	k_sem_reset(&sem_security_updated);
558 	k_sem_reset(&sem_bass_discovered);
559 	k_sem_reset(&sem_pa_synced);
560 	k_sem_reset(&sem_received_base_subgroups);
561 }
562 
563 BT_CONN_CB_DEFINE(conn_callbacks) = {
564 	.connected = connected,
565 	.disconnected = disconnected,
566 	.security_changed = security_changed_cb
567 };
568 
main(void)569 int main(void)
570 {
571 	int err;
572 	struct bt_bap_broadcast_assistant_add_src_param param = { 0 };
573 
574 	err = bt_enable(NULL);
575 	if (err) {
576 		printk("Bluetooth init failed (err %d)\n", err);
577 		return 0;
578 	}
579 
580 	printk("Bluetooth initialized\n");
581 
582 	bt_bap_broadcast_assistant_register_cb(&ba_cbs);
583 	bt_le_per_adv_sync_cb_register(&pa_synced_cb);
584 	bt_le_scan_cb_register(&scan_callbacks);
585 
586 	k_mutex_init(&base_store_mutex);
587 
588 	while (true) {
589 		scan_for_broadcast_sink();
590 
591 		err = k_sem_take(&sem_sink_connected, K_FOREVER);
592 		if (err != 0) {
593 			printk("Failed to take sem_sink_connected (err %d)\n", err);
594 		}
595 
596 		err = bt_bap_broadcast_assistant_discover(broadcast_sink_conn);
597 		if (err != 0) {
598 			printk("Failed to discover BASS on the sink (err %d)\n", err);
599 		}
600 
601 		err = k_sem_take(&sem_security_updated, K_SECONDS(10));
602 		if (err != 0) {
603 			printk("Failed to take sem_security_updated (err %d), resetting\n", err);
604 			bt_conn_disconnect(broadcast_sink_conn, BT_HCI_ERR_AUTH_FAIL);
605 
606 			if (k_sem_take(&sem_sink_disconnected, K_SECONDS(10)) != 0) {
607 				/* This should not happen */
608 				return -ETIMEDOUT;
609 			}
610 
611 			reset();
612 			continue;
613 		}
614 
615 		err = k_sem_take(&sem_bass_discovered, K_SECONDS(10));
616 		if (err != 0) {
617 			if (err == -EAGAIN) {
618 				printk("Failed to take sem_bass_discovered (err %d)\n", err);
619 			}
620 			bt_conn_disconnect(broadcast_sink_conn, BT_HCI_ERR_UNSUPP_REMOTE_FEATURE);
621 
622 			if (k_sem_take(&sem_sink_disconnected, K_SECONDS(10)) != 0) {
623 				/* This should not happen */
624 				return -ETIMEDOUT;
625 			}
626 
627 			reset();
628 			continue;
629 		}
630 
631 		/* TODO: Discover and parse the PACS on the sink and use the information
632 		 * when discovering and adding a source to the sink.
633 		 * Also, before populating the parameters to sync to the broadcast source
634 		 * first, parse the source BASE and determine if the sink supports the source.
635 		 * If not, then look for another source.
636 		 */
637 
638 		scan_for_broadcast_source();
639 
640 		printk("Scan stopped, attempting to PA sync to the broadcaster with id 0x%06X\n",
641 		       selected_broadcast_id);
642 		err = pa_sync_create();
643 		if (err != 0) {
644 			printk("Could not create Broadcast PA sync: %d, resetting\n", err);
645 			return -ETIMEDOUT;
646 		}
647 
648 		printk("Waiting for PA synced\n");
649 		err = k_sem_take(&sem_pa_synced, K_FOREVER);
650 		if (err != 0) {
651 			printk("sem_pa_synced timed out, resetting\n");
652 			return err;
653 		}
654 
655 		memset(bass_subgroups, 0, sizeof(bass_subgroups));
656 		bt_addr_le_copy(&param.addr, &selected_addr);
657 		param.adv_sid = selected_sid;
658 		param.pa_interval = selected_pa_interval;
659 		param.broadcast_id = selected_broadcast_id;
660 		param.pa_sync = true;
661 		param.subgroups = bass_subgroups;
662 
663 		/* Wait to receive subgroups */
664 		err = k_sem_take(&sem_received_base_subgroups, K_FOREVER);
665 		if (err != 0) {
666 			printk("Failed to take sem_received_base_subgroups (err %d)\n", err);
667 			return err;
668 		}
669 
670 		k_mutex_lock(&base_store_mutex, K_FOREVER);
671 		err = bt_bap_base_foreach_subgroup((const struct bt_bap_base *)received_base,
672 						   add_pa_sync_base_subgroup_cb, &param);
673 		k_mutex_unlock(&base_store_mutex);
674 
675 		if (err < 0) {
676 			printk("Could not add BASE to params %d\n", err);
677 			continue;
678 		}
679 
680 		err = bt_bap_broadcast_assistant_add_src(broadcast_sink_conn, &param);
681 		if (err) {
682 			printk("Failed to add source: %d\n", err);
683 			bt_conn_disconnect(broadcast_sink_conn, BT_HCI_ERR_UNSUPP_REMOTE_FEATURE);
684 
685 			if (k_sem_take(&sem_sink_disconnected, K_SECONDS(10)) != 0) {
686 				/* This should not happen */
687 				return -ETIMEDOUT;
688 			}
689 
690 			reset();
691 			continue;
692 		}
693 
694 		/* Reset if the sink disconnects */
695 		err = k_sem_take(&sem_sink_disconnected, K_FOREVER);
696 		if (err != 0) {
697 			printk("Failed to take sem_sink_disconnected (err %d)\n", err);
698 		}
699 
700 		reset();
701 	}
702 
703 	return 0;
704 }
705