1 /*
2 * Copyright 2023 NXP
3 * Copyright (c) 2024 Nordic Semiconductor ASA
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8 #include <stddef.h>
9 #include <stdint.h>
10
11 #include <zephyr/bluetooth/addr.h>
12 #include <zephyr/bluetooth/audio/audio.h>
13 #include <zephyr/bluetooth/audio/bap.h>
14 #include <zephyr/bluetooth/audio/lc3.h>
15 #include <zephyr/bluetooth/audio/pacs.h>
16 #include <zephyr/bluetooth/audio/bap_lc3_preset.h>
17 #include <zephyr/bluetooth/audio/pbp.h>
18 #include <zephyr/bluetooth/bluetooth.h>
19 #include <zephyr/bluetooth/gap.h>
20 #include <zephyr/bluetooth/iso.h>
21 #include <zephyr/bluetooth/uuid.h>
22 #include <zephyr/kernel.h>
23 #include <zephyr/net_buf.h>
24 #include <zephyr/sys/byteorder.h>
25 #include <zephyr/sys/printk.h>
26 #include <zephyr/sys/util.h>
27 #include <zephyr/sys/util_macro.h>
28 #include <zephyr/types.h>
29
30 #define AVAILABLE_SINK_CONTEXT (BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED | \
31 BT_AUDIO_CONTEXT_TYPE_CONVERSATIONAL | \
32 BT_AUDIO_CONTEXT_TYPE_MEDIA | \
33 BT_AUDIO_CONTEXT_TYPE_GAME | \
34 BT_AUDIO_CONTEXT_TYPE_INSTRUCTIONAL)
35
36 #define SEM_TIMEOUT K_SECONDS(10)
37 #define PA_SYNC_SKIP 5
38 #define PA_SYNC_INTERVAL_TO_TIMEOUT_RATIO 20 /* Set the timeout relative to interval */
39
40 static bool pbs_found;
41
42 static K_SEM_DEFINE(sem_pa_synced, 0U, 1U);
43 static K_SEM_DEFINE(sem_base_received, 0U, 1U);
44 static K_SEM_DEFINE(sem_syncable, 0U, 1U);
45 static K_SEM_DEFINE(sem_pa_sync_lost, 0U, 1U);
46
47 static void broadcast_scan_recv(const struct bt_le_scan_recv_info *info,
48 struct net_buf_simple *ad);
49
50 static void broadcast_scan_timeout(void);
51
52 static void broadcast_pa_synced(struct bt_le_per_adv_sync *sync,
53 struct bt_le_per_adv_sync_synced_info *info);
54
55 static void broadcast_pa_recv(struct bt_le_per_adv_sync *sync,
56 const struct bt_le_per_adv_sync_recv_info *info,
57 struct net_buf_simple *buf);
58
59 static void broadcast_pa_terminated(struct bt_le_per_adv_sync *sync,
60 const struct bt_le_per_adv_sync_term_info *info);
61
62 static struct bt_le_scan_cb broadcast_scan_cb = {
63 .recv = broadcast_scan_recv,
64 .timeout = broadcast_scan_timeout
65 };
66
67 static struct bt_le_per_adv_sync_cb broadcast_sync_cb = {
68 .synced = broadcast_pa_synced,
69 .recv = broadcast_pa_recv,
70 .term = broadcast_pa_terminated,
71 };
72
73 static struct bt_bap_broadcast_sink *broadcast_sink;
74 static uint32_t bcast_id;
75 static struct bt_le_per_adv_sync *bcast_pa_sync;
76
77 static struct bt_bap_stream streams[CONFIG_BT_BAP_BROADCAST_SNK_STREAM_COUNT];
78 struct bt_bap_stream *streams_p[ARRAY_SIZE(streams)];
79
80 static const struct bt_audio_codec_cap codec = BT_AUDIO_CODEC_CAP_LC3(
81 BT_AUDIO_CODEC_CAP_FREQ_48KHZ, BT_AUDIO_CODEC_CAP_DURATION_10,
82 BT_AUDIO_CODEC_CAP_CHAN_COUNT_SUPPORT(1), 40u, 60u, 1u, (BT_AUDIO_CONTEXT_TYPE_MEDIA));
83
84 /* Create a mask for the maximum BIS we can sync to using the number of streams
85 * we have. We add an additional 1 since the bis indexes start from 1 and not
86 * 0.
87 */
88 static const uint32_t bis_index_mask = BIT_MASK(ARRAY_SIZE(streams) + 1U);
89 static uint32_t bis_index_bitfield;
90
stream_started_cb(struct bt_bap_stream * stream)91 static void stream_started_cb(struct bt_bap_stream *stream)
92 {
93 printk("Stream %p started\n", stream);
94 }
95
stream_stopped_cb(struct bt_bap_stream * stream,uint8_t reason)96 static void stream_stopped_cb(struct bt_bap_stream *stream, uint8_t reason)
97 {
98 printk("Stream %p stopped with reason 0x%02X\n", stream, reason);
99 }
100
stream_recv_cb(struct bt_bap_stream * stream,const struct bt_iso_recv_info * info,struct net_buf * buf)101 static void stream_recv_cb(struct bt_bap_stream *stream,
102 const struct bt_iso_recv_info *info,
103 struct net_buf *buf)
104 {
105 static uint32_t recv_cnt;
106
107 recv_cnt++;
108 if ((recv_cnt % 20U) == 0U) {
109 printk("Received %u total ISO packets\n", recv_cnt);
110 }
111 }
112
113 static struct bt_bap_stream_ops stream_ops = {
114 .started = stream_started_cb,
115 .stopped = stream_stopped_cb,
116 .recv = stream_recv_cb
117 };
118
119 static struct bt_pacs_cap cap = {
120 .codec_cap = &codec,
121 };
122
interval_to_sync_timeout(uint16_t interval)123 static uint16_t interval_to_sync_timeout(uint16_t interval)
124 {
125 uint32_t interval_us;
126 uint32_t timeout;
127
128 /* Add retries and convert to unit in 10's of ms */
129 interval_us = BT_GAP_PER_ADV_INTERVAL_TO_US(interval);
130 timeout =
131 BT_GAP_US_TO_PER_ADV_SYNC_TIMEOUT(interval_us) * PA_SYNC_INTERVAL_TO_TIMEOUT_RATIO;
132
133 /* Enforce restraints */
134 timeout = CLAMP(timeout, BT_GAP_PER_ADV_MIN_TIMEOUT, BT_GAP_PER_ADV_MAX_TIMEOUT);
135
136 return (uint16_t)timeout;
137 }
138
sync_broadcast_pa(const struct bt_le_scan_recv_info * info,uint32_t broadcast_id)139 static void sync_broadcast_pa(const struct bt_le_scan_recv_info *info,
140 uint32_t broadcast_id)
141 {
142 struct bt_le_per_adv_sync_param param;
143 int err;
144
145 /* Unregister the callbacks to prevent broadcast_scan_recv to be called again */
146 bt_le_scan_cb_unregister(&broadcast_scan_cb);
147
148 err = bt_le_scan_stop();
149 if (err != 0) {
150 printk("Could not stop scan: %d", err);
151 }
152
153 bt_addr_le_copy(¶m.addr, info->addr);
154 param.options = 0;
155 param.sid = info->sid;
156 param.skip = PA_SYNC_SKIP;
157 param.timeout = interval_to_sync_timeout(info->interval);
158 err = bt_le_per_adv_sync_create(¶m, &bcast_pa_sync);
159
160 if (err != 0) {
161 printk("Could not sync to PA: %d", err);
162 } else {
163 bcast_id = broadcast_id;
164 }
165 }
166
scan_check_and_sync_broadcast(struct bt_data * data,void * user_data)167 static bool scan_check_and_sync_broadcast(struct bt_data *data, void *user_data)
168 {
169 enum bt_pbp_announcement_feature source_features;
170 uint32_t *broadcast_id = user_data;
171 struct bt_uuid_16 adv_uuid;
172 uint8_t *tmp_meta = NULL;
173 int ret;
174
175 if (data->type != BT_DATA_SVC_DATA16) {
176 return true;
177 }
178
179 if (!bt_uuid_create(&adv_uuid.uuid, data->data, BT_UUID_SIZE_16)) {
180 return true;
181 }
182
183 if (!bt_uuid_cmp(&adv_uuid.uuid, BT_UUID_BROADCAST_AUDIO)) {
184 *broadcast_id = sys_get_le24(data->data + BT_UUID_SIZE_16);
185 return true;
186 }
187
188 ret = bt_pbp_parse_announcement(data, &source_features, &tmp_meta);
189 if (ret >= 0) {
190 if (!(source_features & BT_PBP_ANNOUNCEMENT_FEATURE_HIGH_QUALITY)) {
191 /* This is a Standard Quality Public Broadcast Audio stream */
192 printk("This is a Standard Quality Public Broadcast Audio stream\n");
193 pbs_found = false;
194
195 return false;
196 }
197
198 printk("Found Suitable Public Broadcast Announcement with %d octets of metadata\n",
199 ret);
200 pbs_found = true;
201
202 /**
203 * Continue parsing if Broadcast Audio Announcement Service
204 * was not found.
205 */
206 if (*broadcast_id == BT_BAP_INVALID_BROADCAST_ID) {
207 return true;
208 }
209 }
210
211 return true;
212 }
213
broadcast_scan_recv(const struct bt_le_scan_recv_info * info,struct net_buf_simple * ad)214 static void broadcast_scan_recv(const struct bt_le_scan_recv_info *info,
215 struct net_buf_simple *ad)
216 {
217 uint32_t broadcast_id;
218
219 pbs_found = false;
220
221 /* We are only interested in non-connectable periodic advertisers */
222 if ((info->adv_props & BT_GAP_ADV_PROP_CONNECTABLE) || info->interval == 0) {
223 return;
224 }
225
226 broadcast_id = BT_BAP_INVALID_BROADCAST_ID;
227 bt_data_parse(ad, scan_check_and_sync_broadcast, (void *)&broadcast_id);
228
229 if ((broadcast_id != BT_BAP_INVALID_BROADCAST_ID) && pbs_found) {
230 sync_broadcast_pa(info, broadcast_id);
231 }
232 }
233
broadcast_scan_timeout(void)234 static void broadcast_scan_timeout(void)
235 {
236 printk("Broadcast scan timed out\n");
237 }
238
pa_decode_base(struct bt_data * data,void * user_data)239 static bool pa_decode_base(struct bt_data *data, void *user_data)
240 {
241 const struct bt_bap_base *base = bt_bap_base_get_base_from_ad(data);
242 uint32_t base_bis_index_bitfield = 0U;
243 int err;
244
245 /* Base is NULL if the data does not contain a valid BASE */
246 if (base == NULL) {
247 return true;
248 }
249
250 err = bt_bap_base_get_bis_indexes(base, &base_bis_index_bitfield);
251 if (err != 0) {
252 return false;
253 }
254
255 bis_index_bitfield = base_bis_index_bitfield & bis_index_mask;
256 k_sem_give(&sem_base_received);
257
258 return false;
259 }
260
broadcast_pa_recv(struct bt_le_per_adv_sync * sync,const struct bt_le_per_adv_sync_recv_info * info,struct net_buf_simple * buf)261 static void broadcast_pa_recv(struct bt_le_per_adv_sync *sync,
262 const struct bt_le_per_adv_sync_recv_info *info,
263 struct net_buf_simple *buf)
264 {
265 bt_data_parse(buf, pa_decode_base, NULL);
266 }
267
syncable_cb(struct bt_bap_broadcast_sink * sink,const struct bt_iso_biginfo * biginfo)268 static void syncable_cb(struct bt_bap_broadcast_sink *sink, const struct bt_iso_biginfo *biginfo)
269 {
270 k_sem_give(&sem_syncable);
271 }
272
base_recv_cb(struct bt_bap_broadcast_sink * sink,const struct bt_bap_base * base,size_t base_size)273 static void base_recv_cb(struct bt_bap_broadcast_sink *sink, const struct bt_bap_base *base,
274 size_t base_size)
275 {
276 k_sem_give(&sem_base_received);
277 }
278
279 static struct bt_bap_broadcast_sink_cb broadcast_sink_cbs = {
280 .syncable = syncable_cb,
281 .base_recv = base_recv_cb,
282 };
283
broadcast_pa_synced(struct bt_le_per_adv_sync * sync,struct bt_le_per_adv_sync_synced_info * info)284 static void broadcast_pa_synced(struct bt_le_per_adv_sync *sync,
285 struct bt_le_per_adv_sync_synced_info *info)
286 {
287 if (sync == bcast_pa_sync) {
288 printk("PA sync %p synced for broadcast sink with broadcast ID 0x%06X\n",
289 sync, bcast_id);
290
291 k_sem_give(&sem_pa_synced);
292 }
293 }
294
broadcast_pa_terminated(struct bt_le_per_adv_sync * sync,const struct bt_le_per_adv_sync_term_info * info)295 static void broadcast_pa_terminated(struct bt_le_per_adv_sync *sync,
296 const struct bt_le_per_adv_sync_term_info *info)
297 {
298 if (sync == bcast_pa_sync) {
299 printk("PA sync %p lost with reason %u\n", sync, info->reason);
300 bcast_pa_sync = NULL;
301
302 k_sem_give(&sem_pa_sync_lost);
303 }
304 }
305
reset(void)306 static int reset(void)
307 {
308 if (broadcast_sink != NULL) {
309 int err = bt_bap_broadcast_sink_delete(broadcast_sink);
310
311 if (err) {
312 printk("Deleting broadcast sink failed (err %d)\n", err);
313
314 return err;
315 }
316
317 broadcast_sink = NULL;
318 }
319 k_sem_reset(&sem_pa_synced);
320 k_sem_reset(&sem_base_received);
321 k_sem_reset(&sem_syncable);
322 k_sem_reset(&sem_pa_sync_lost);
323
324 return 0;
325 }
326
bap_broadcast_sink_init(void)327 int bap_broadcast_sink_init(void)
328 {
329 int err;
330
331 bt_bap_broadcast_sink_register_cb(&broadcast_sink_cbs);
332 bt_le_per_adv_sync_cb_register(&broadcast_sync_cb);
333
334 err = bt_pacs_cap_register(BT_AUDIO_DIR_SINK, &cap);
335 if (err) {
336 printk("Capability register failed (err %d)\n", err);
337
338 return err;
339 }
340
341 for (size_t i = 0U; i < ARRAY_SIZE(streams); i++) {
342 streams[i].ops = &stream_ops;
343 }
344
345 for (size_t i = 0U; i < ARRAY_SIZE(streams_p); i++) {
346 streams_p[i] = &streams[i];
347 }
348
349 return 0;
350 }
351
bap_broadcast_sink_run(void)352 int bap_broadcast_sink_run(void)
353 {
354 while (true) {
355 int err = reset();
356
357 if (err != 0) {
358 printk("Resetting failed: %d - Aborting\n", err);
359
360 return err;
361 }
362
363 /* Register callbacks */
364 bt_le_scan_cb_register(&broadcast_scan_cb);
365
366 /* Start scanning */
367 err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, NULL);
368 if (err) {
369 printk("Scan start failed (err %d)\n", err);
370
371 return err;
372 }
373
374 /* Wait until a suitable source is found */
375 err = k_sem_take(&sem_pa_synced, K_FOREVER);
376 printk("Broadcast source PA synced, waiting for BASE\n");
377
378 /* Wait for BASE decode */
379 err = k_sem_take(&sem_base_received, SEM_TIMEOUT);
380 if (err != 0) {
381 printk("sem_base_received timed out\n");
382
383 return err;
384 }
385
386 /* Create broadcast sink */
387 printk("BASE received, creating broadcast sink\n");
388 err = bt_bap_broadcast_sink_create(bcast_pa_sync, bcast_id, &broadcast_sink);
389 if (err != 0) {
390 printk("bt_bap_broadcast_sink_create failed: %d\n", err);
391
392 return err;
393 }
394
395 k_sem_take(&sem_syncable, SEM_TIMEOUT);
396 if (err != 0) {
397 printk("sem_syncable timed out\n");
398
399 return err;
400 }
401
402 /* Sync to broadcast source */
403 printk("Syncing to broadcast\n");
404 err = bt_bap_broadcast_sink_sync(broadcast_sink, bis_index_bitfield,
405 streams_p, NULL);
406 if (err != 0) {
407 printk("Unable to sync to broadcast source: %d\n", err);
408
409 return err;
410 }
411
412 k_sem_take(&sem_pa_sync_lost, K_FOREVER);
413 }
414
415 return 0;
416 }
417
main(void)418 int main(void)
419 {
420 int err;
421
422 err = bt_enable(NULL);
423 if (err != 0) {
424 printk("Bluetooth init failed (err %d)\n", err);
425
426 return err;
427 }
428 printk("Bluetooth initialized\n");
429
430 printk("Initializing BAP Broadcast Sink\n");
431 err = bap_broadcast_sink_init();
432 if (err != 0) {
433 return err;
434 }
435
436 err = bap_broadcast_sink_run();
437 if (err != 0) {
438 return err;
439 }
440
441 return 0;
442 }
443