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