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_BAP_CONN_PARAM_RELAXED, &broadcast_sink_conn);
387 			if (err != 0) {
388 				printk("Failed creating connection (err=%u)\n", err);
389 				scan_for_broadcast_sink();
390 			}
391 
392 			k_sem_give(&sem_sink_discovered);
393 		}
394 	}
395 }
396 
scan_timeout_cb(void)397 static void scan_timeout_cb(void)
398 {
399 	printk("Scan timeout\n");
400 }
401 
402 static struct bt_le_scan_cb scan_callbacks = {
403 	.recv = scan_recv_cb,
404 	.timeout = scan_timeout_cb,
405 };
406 
scan_for_broadcast_source(void)407 static void scan_for_broadcast_source(void)
408 {
409 	int err;
410 
411 	scanning_for_broadcast_source = true;
412 
413 	err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, NULL);
414 	if (err) {
415 		printk("Scanning failed to start (err %d)\n", err);
416 		return;
417 	}
418 
419 	printk("Scanning for Broadcast Source successfully started\n");
420 
421 	err = k_sem_take(&sem_source_discovered, K_FOREVER);
422 	if (err != 0) {
423 		printk("Failed to take sem_source_discovered (err %d)\n", err);
424 	}
425 }
426 
scan_for_broadcast_sink(void)427 static void scan_for_broadcast_sink(void)
428 {
429 	int err;
430 
431 	scanning_for_broadcast_source = false;
432 
433 	err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, NULL);
434 	if (err) {
435 		printk("Scanning failed to start (err %d)\n", err);
436 		return;
437 	}
438 
439 	printk("Scanning for Broadcast Sink successfully started\n");
440 
441 	err = k_sem_take(&sem_sink_discovered, K_FOREVER);
442 	if (err != 0) {
443 		printk("Failed to take sem_sink_discovered (err %d)\n", err);
444 	}
445 }
446 
connected(struct bt_conn * conn,uint8_t err)447 static void connected(struct bt_conn *conn, uint8_t err)
448 {
449 	char addr[BT_ADDR_LE_STR_LEN];
450 
451 	(void)bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
452 
453 	if (err != 0) {
454 		printk("Failed to connect to %s %u %s\n", addr, err, bt_hci_err_to_str(err));
455 
456 		bt_conn_unref(broadcast_sink_conn);
457 		broadcast_sink_conn = NULL;
458 
459 		scan_for_broadcast_sink();
460 		return;
461 	}
462 
463 	if (conn != broadcast_sink_conn) {
464 		return;
465 	}
466 
467 	printk("Connected: %s\n", addr);
468 	k_sem_give(&sem_sink_connected);
469 }
470 
disconnected(struct bt_conn * conn,uint8_t reason)471 static void disconnected(struct bt_conn *conn, uint8_t reason)
472 {
473 	char addr[BT_ADDR_LE_STR_LEN];
474 
475 	if (conn != broadcast_sink_conn) {
476 		return;
477 	}
478 
479 	(void)bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
480 
481 	printk("Disconnected: %s, reason 0x%02x %s\n", addr, reason, bt_hci_err_to_str(reason));
482 
483 	bt_conn_unref(broadcast_sink_conn);
484 	broadcast_sink_conn = NULL;
485 
486 	k_sem_give(&sem_sink_disconnected);
487 }
488 
security_changed_cb(struct bt_conn * conn,bt_security_t level,enum bt_security_err err)489 static void security_changed_cb(struct bt_conn *conn, bt_security_t level,
490 				enum bt_security_err err)
491 {
492 	if (err == 0) {
493 		printk("Security level changed: %u\n", level);
494 		k_sem_give(&sem_security_updated);
495 	} else {
496 		printk("Failed to set security level: %s(%u)\n", bt_security_err_to_str(err), err);
497 	}
498 }
499 
bap_broadcast_assistant_discover_cb(struct bt_conn * conn,int err,uint8_t recv_state_count)500 static void bap_broadcast_assistant_discover_cb(struct bt_conn *conn, int err,
501 						uint8_t recv_state_count)
502 {
503 	if (err == 0) {
504 		printk("BASS discover done with %u recv states\n",
505 		       recv_state_count);
506 		k_sem_give(&sem_bass_discovered);
507 	} else {
508 		printk("BASS discover failed (%d)\n", err);
509 	}
510 }
511 
bap_broadcast_assistant_add_src_cb(struct bt_conn * conn,int err)512 static void bap_broadcast_assistant_add_src_cb(struct bt_conn *conn, int err)
513 {
514 	if (err == 0) {
515 		printk("BASS add source successful\n");
516 	} else {
517 		printk("BASS add source failed (%d)\n", err);
518 	}
519 }
520 
pa_sync_synced_cb(struct bt_le_per_adv_sync * sync,struct bt_le_per_adv_sync_synced_info * info)521 static void pa_sync_synced_cb(struct bt_le_per_adv_sync *sync,
522 			      struct bt_le_per_adv_sync_synced_info *info)
523 {
524 	if (sync == pa_sync) {
525 		printk("PA sync %p synced for broadcast sink with broadcast ID 0x%06X\n", sync,
526 		       selected_broadcast_id);
527 
528 		k_sem_give(&sem_pa_synced);
529 	}
530 }
531 
532 static struct bt_bap_broadcast_assistant_cb ba_cbs = {
533 	.discover = bap_broadcast_assistant_discover_cb,
534 	.add_src = bap_broadcast_assistant_add_src_cb,
535 };
536 
537 static struct bt_le_per_adv_sync_cb pa_synced_cb = {
538 	.synced = pa_sync_synced_cb,
539 	.recv = pa_recv,
540 };
541 
reset(void)542 static void reset(void)
543 {
544 	printk("\n\nReset...\n\n");
545 
546 	broadcast_sink_conn = NULL;
547 	selected_broadcast_id = BT_BAP_INVALID_BROADCAST_ID;
548 	selected_sid = 0;
549 	selected_pa_interval = 0;
550 	(void)memset(&selected_addr, 0, sizeof(selected_addr));
551 
552 	k_sem_reset(&sem_source_discovered);
553 	k_sem_reset(&sem_sink_discovered);
554 	k_sem_reset(&sem_sink_connected);
555 	k_sem_reset(&sem_sink_disconnected);
556 	k_sem_reset(&sem_security_updated);
557 	k_sem_reset(&sem_bass_discovered);
558 	k_sem_reset(&sem_pa_synced);
559 	k_sem_reset(&sem_received_base_subgroups);
560 }
561 
562 BT_CONN_CB_DEFINE(conn_callbacks) = {
563 	.connected = connected,
564 	.disconnected = disconnected,
565 	.security_changed = security_changed_cb
566 };
567 
main(void)568 int main(void)
569 {
570 	int err;
571 	struct bt_bap_broadcast_assistant_add_src_param param = { 0 };
572 
573 	err = bt_enable(NULL);
574 	if (err) {
575 		printk("Bluetooth init failed (err %d)\n", err);
576 		return 0;
577 	}
578 
579 	printk("Bluetooth initialized\n");
580 
581 	bt_bap_broadcast_assistant_register_cb(&ba_cbs);
582 	bt_le_per_adv_sync_cb_register(&pa_synced_cb);
583 	bt_le_scan_cb_register(&scan_callbacks);
584 
585 	k_mutex_init(&base_store_mutex);
586 
587 	while (true) {
588 		scan_for_broadcast_sink();
589 
590 		err = k_sem_take(&sem_sink_connected, K_FOREVER);
591 		if (err != 0) {
592 			printk("Failed to take sem_sink_connected (err %d)\n", err);
593 		}
594 
595 		err = bt_bap_broadcast_assistant_discover(broadcast_sink_conn);
596 		if (err != 0) {
597 			printk("Failed to discover BASS on the sink (err %d)\n", err);
598 		}
599 
600 		err = k_sem_take(&sem_security_updated, K_SECONDS(10));
601 		if (err != 0) {
602 			printk("Failed to take sem_security_updated (err %d), resetting\n", err);
603 			bt_conn_disconnect(broadcast_sink_conn, BT_HCI_ERR_AUTH_FAIL);
604 
605 			if (k_sem_take(&sem_sink_disconnected, K_SECONDS(10)) != 0) {
606 				/* This should not happen */
607 				return -ETIMEDOUT;
608 			}
609 
610 			reset();
611 			continue;
612 		}
613 
614 		err = k_sem_take(&sem_bass_discovered, K_SECONDS(10));
615 		if (err != 0) {
616 			if (err == -EAGAIN) {
617 				printk("Failed to take sem_bass_discovered (err %d)\n", err);
618 			}
619 			bt_conn_disconnect(broadcast_sink_conn, BT_HCI_ERR_UNSUPP_REMOTE_FEATURE);
620 
621 			if (k_sem_take(&sem_sink_disconnected, K_SECONDS(10)) != 0) {
622 				/* This should not happen */
623 				return -ETIMEDOUT;
624 			}
625 
626 			reset();
627 			continue;
628 		}
629 
630 		/* TODO: Discover and parse the PACS on the sink and use the information
631 		 * when discovering and adding a source to the sink.
632 		 * Also, before populating the parameters to sync to the broadcast source
633 		 * first, parse the source BASE and determine if the sink supports the source.
634 		 * If not, then look for another source.
635 		 */
636 
637 		scan_for_broadcast_source();
638 
639 		printk("Scan stopped, attempting to PA sync to the broadcaster with id 0x%06X\n",
640 		       selected_broadcast_id);
641 		err = pa_sync_create();
642 		if (err != 0) {
643 			printk("Could not create Broadcast PA sync: %d, resetting\n", err);
644 			return -ETIMEDOUT;
645 		}
646 
647 		printk("Waiting for PA synced\n");
648 		err = k_sem_take(&sem_pa_synced, K_FOREVER);
649 		if (err != 0) {
650 			printk("sem_pa_synced timed out, resetting\n");
651 			return err;
652 		}
653 
654 		memset(bass_subgroups, 0, sizeof(bass_subgroups));
655 		bt_addr_le_copy(&param.addr, &selected_addr);
656 		param.adv_sid = selected_sid;
657 		param.pa_interval = selected_pa_interval;
658 		param.broadcast_id = selected_broadcast_id;
659 		param.pa_sync = true;
660 		param.subgroups = bass_subgroups;
661 
662 		/* Wait to receive subgroups */
663 		err = k_sem_take(&sem_received_base_subgroups, K_FOREVER);
664 		if (err != 0) {
665 			printk("Failed to take sem_received_base_subgroups (err %d)\n", err);
666 			return err;
667 		}
668 
669 		k_mutex_lock(&base_store_mutex, K_FOREVER);
670 		err = bt_bap_base_foreach_subgroup((const struct bt_bap_base *)received_base,
671 						   add_pa_sync_base_subgroup_cb, &param);
672 		k_mutex_unlock(&base_store_mutex);
673 
674 		if (err < 0) {
675 			printk("Could not add BASE to params %d\n", err);
676 			continue;
677 		}
678 
679 		err = bt_bap_broadcast_assistant_add_src(broadcast_sink_conn, &param);
680 		if (err) {
681 			printk("Failed to add source: %d\n", err);
682 			bt_conn_disconnect(broadcast_sink_conn, BT_HCI_ERR_UNSUPP_REMOTE_FEATURE);
683 
684 			if (k_sem_take(&sem_sink_disconnected, K_SECONDS(10)) != 0) {
685 				/* This should not happen */
686 				return -ETIMEDOUT;
687 			}
688 
689 			reset();
690 			continue;
691 		}
692 
693 		/* Reset if the sink disconnects */
694 		err = k_sem_take(&sem_sink_disconnected, K_FOREVER);
695 		if (err != 0) {
696 			printk("Failed to take sem_sink_disconnected (err %d)\n", err);
697 		}
698 
699 		reset();
700 	}
701 
702 	return 0;
703 }
704