1 /*
2 * Copyright 2023 NXP
3 * Copyright (c) 2024 Nordic Semiconductor ASA
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7 #include <stdbool.h>
8 #include <stddef.h>
9 #include <stdint.h>
10 #include <string.h>
11
12 #include <zephyr/autoconf.h>
13 #include <zephyr/bluetooth/audio/audio.h>
14 #include <zephyr/bluetooth/audio/bap_lc3_preset.h>
15 #include <zephyr/bluetooth/audio/bap.h>
16 #include <zephyr/bluetooth/audio/cap.h>
17 #include <zephyr/bluetooth/audio/pbp.h>
18 #include <zephyr/bluetooth/bluetooth.h>
19 #include <zephyr/bluetooth/byteorder.h>
20 #include <zephyr/bluetooth/gap.h>
21 #include <zephyr/bluetooth/iso.h>
22 #include <zephyr/bluetooth/uuid.h>
23 #include <zephyr/kernel.h>
24 #include <zephyr/net_buf.h>
25 #include <zephyr/sys/printk.h>
26 #include <zephyr/sys/util.h>
27 #include <zephyr/toolchain.h>
28
29 #include "bap_stream_tx.h"
30 #include "bstests.h"
31 #include "common.h"
32
33 #if defined(CONFIG_BT_PBP)
34 /* PBS ASCII text */
35 #define PBS_DEMO 'P', 'B', 'P'
36 #define SEM_TIMEOUT K_SECONDS(2)
37
38 extern enum bst_result_t bst_result;
39
40 static const uint8_t pba_metadata[] = {
41 BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_PROGRAM_INFO, PBS_DEMO)};
42
43 static uint8_t bis_codec_data[] = {
44 BT_AUDIO_CODEC_DATA(BT_AUDIO_CODEC_CFG_FREQ,
45 BT_BYTES_LIST_LE16(BT_AUDIO_CODEC_CFG_FREQ_48KHZ))};
46
47 static struct audio_test_stream broadcast_source_stream;
48 static struct bt_cap_stream *broadcast_stream;
49
50 static struct bt_cap_initiator_broadcast_stream_param stream_params;
51 static struct bt_cap_initiator_broadcast_subgroup_param subgroup_param;
52 static struct bt_cap_initiator_broadcast_create_param create_param;
53 static struct bt_cap_broadcast_source *broadcast_source;
54
55 static struct bt_bap_lc3_preset broadcast_preset_48_2_1 =
56 BT_BAP_LC3_UNICAST_PRESET_48_2_1(BT_AUDIO_LOCATION_FRONT_LEFT,
57 BT_AUDIO_CONTEXT_TYPE_MEDIA);
58
59 static K_SEM_DEFINE(sem_started, 0U, 1);
60 static K_SEM_DEFINE(sem_stopped, 0U, 1);
61
62 static struct bt_le_ext_adv *adv;
63
started_cb(struct bt_bap_stream * stream)64 static void started_cb(struct bt_bap_stream *stream)
65 {
66 struct audio_test_stream *test_stream = audio_test_stream_from_bap_stream(stream);
67 int err;
68
69 test_stream->seq_num = 0U;
70 test_stream->tx_cnt = 0U;
71
72 printk("Stream %p started\n", stream);
73
74 err = bap_stream_tx_register(stream);
75 if (err != 0) {
76 FAIL("Failed to register stream %p for TX: %d\n", stream, err);
77 return;
78 }
79
80 k_sem_give(&sem_started);
81 }
82
stopped_cb(struct bt_bap_stream * stream,uint8_t reason)83 static void stopped_cb(struct bt_bap_stream *stream, uint8_t reason)
84 {
85 int err;
86
87 printk("Stream %p stopped with reason 0x%02X\n", stream, reason);
88
89 err = bap_stream_tx_unregister(stream);
90 if (err != 0) {
91 FAIL("Failed to unregister stream %p for TX: %d\n", stream, err);
92 return;
93 }
94
95 k_sem_give(&sem_stopped);
96 }
97
setup_extended_adv_data(struct bt_cap_broadcast_source * source,struct bt_le_ext_adv * adv)98 static int setup_extended_adv_data(struct bt_cap_broadcast_source *source,
99 struct bt_le_ext_adv *adv)
100 {
101 /* Broadcast Audio Streaming Endpoint advertising data */
102 NET_BUF_SIMPLE_DEFINE(ad_buf, BT_UUID_SIZE_16 + BT_AUDIO_BROADCAST_ID_SIZE);
103 NET_BUF_SIMPLE_DEFINE(pbp_ad_buf, BT_PBP_MIN_PBA_SIZE + ARRAY_SIZE(pba_metadata));
104 NET_BUF_SIMPLE_DEFINE(base_buf, 128);
105 static enum bt_pbp_announcement_feature pba_params;
106 struct bt_data ext_ad[2];
107 struct bt_data per_ad;
108 uint32_t broadcast_id;
109 int err;
110
111 err = bt_rand(&broadcast_id, BT_AUDIO_BROADCAST_ID_SIZE);
112 if (err) {
113 FAIL("Unable to generate broadcast ID: %d\n", err);
114 return err;
115 }
116
117 /* Broadcast Audio Announcements */
118 net_buf_simple_add_le16(&ad_buf, BT_UUID_BROADCAST_AUDIO_VAL);
119 net_buf_simple_add_le24(&ad_buf, broadcast_id);
120 ext_ad[0].type = BT_DATA_SVC_DATA16;
121 ext_ad[0].data_len = ad_buf.len;
122 ext_ad[0].data = ad_buf.data;
123
124 /**
125 * Create a Public Broadcast Announcement
126 * Cycle between high and standard quality public broadcast audio.
127 */
128 if (pba_params & BT_PBP_ANNOUNCEMENT_FEATURE_HIGH_QUALITY) {
129 pba_params = 0;
130 pba_params |= BT_PBP_ANNOUNCEMENT_FEATURE_STANDARD_QUALITY;
131 printk("Starting stream with standard quality!\n");
132 } else {
133 pba_params = 0;
134 pba_params |= BT_PBP_ANNOUNCEMENT_FEATURE_HIGH_QUALITY;
135 printk("Starting stream with high quality!\n");
136 }
137
138 err = bt_pbp_get_announcement(pba_metadata, ARRAY_SIZE(pba_metadata), pba_params,
139 &pbp_ad_buf);
140 if (err != 0) {
141 printk("Failed to create public broadcast announcement!: %d\n", err);
142
143 return err;
144 }
145 ext_ad[1].type = BT_DATA_SVC_DATA16;
146 ext_ad[1].data_len = pbp_ad_buf.len;
147 ext_ad[1].data = pbp_ad_buf.data;
148
149 err = bt_le_ext_adv_set_data(adv, ext_ad, ARRAY_SIZE(ext_ad), NULL, 0);
150 if (err != 0) {
151 printk("Failed to set extended advertising data: %d\n", err);
152
153 return err;
154 }
155
156 /* Setup periodic advertising data */
157 err = bt_cap_initiator_broadcast_get_base(source, &base_buf);
158 if (err != 0) {
159 printk("Failed to get encoded BASE: %d\n", err);
160
161 return err;
162 }
163
164 per_ad.type = BT_DATA_SVC_DATA16;
165 per_ad.data_len = base_buf.len;
166 per_ad.data = base_buf.data;
167 err = bt_le_per_adv_set_data(adv, &per_ad, 1);
168 if (err != 0) {
169 printk("Failed to set periodic advertising data: %d\n", err);
170
171 return err;
172 }
173
174 return 0;
175 }
176
start_extended_adv(struct bt_le_ext_adv * adv)177 static int start_extended_adv(struct bt_le_ext_adv *adv)
178 {
179 int err;
180
181 /* Start extended advertising */
182 err = bt_le_ext_adv_start(adv, BT_LE_EXT_ADV_START_DEFAULT);
183 if (err) {
184 printk("Failed to start extended advertising: %d\n", err);
185
186 return err;
187 }
188
189 /* Enable Periodic Advertising */
190 err = bt_le_per_adv_start(adv);
191 if (err) {
192 printk("Failed to enable periodic advertising: %d\n", err);
193
194 return err;
195 }
196
197 return 0;
198 }
199
setup_extended_adv(struct bt_le_ext_adv ** adv)200 static int setup_extended_adv(struct bt_le_ext_adv **adv)
201 {
202 int err;
203
204 /* Create a non-connectable advertising set */
205 err = bt_le_ext_adv_create(BT_LE_EXT_ADV_NCONN, NULL, adv);
206 if (err != 0) {
207 printk("Unable to create extended advertising set: %d\n", err);
208
209 return err;
210 }
211
212 /* Set periodic advertising parameters */
213 err = bt_le_per_adv_set_param(*adv, BT_LE_PER_ADV_DEFAULT);
214 if (err) {
215 printk("Failed to set periodic advertising parameters: %d\n", err);
216
217 return err;
218 }
219
220 return 0;
221 }
222
stop_extended_adv(struct bt_le_ext_adv * adv)223 static int stop_extended_adv(struct bt_le_ext_adv *adv)
224 {
225 int err;
226
227 err = bt_le_per_adv_stop(adv);
228 if (err) {
229 printk("Failed to stop periodic advertising: %d\n", err);
230
231 return err;
232 }
233
234 err = bt_le_ext_adv_stop(adv);
235 if (err) {
236 printk("Failed to stop extended advertising: %d\n", err);
237
238 return err;
239 }
240
241 err = bt_le_ext_adv_delete(adv);
242 if (err) {
243 printk("Failed to delete extended advertising: %d\n", err);
244
245 return err;
246 }
247
248 return 0;
249 }
250
251 static struct bt_bap_stream_ops broadcast_stream_ops = {
252 .started = started_cb,
253 .stopped = stopped_cb,
254 .sent = bap_stream_tx_sent_cb,
255 };
256
test_main(void)257 static void test_main(void)
258 {
259 int err;
260 int count = 0;
261
262 err = bt_enable(NULL);
263 if (err) {
264 FAIL("Bluetooth enable failed (err %d)\n", err);
265
266 return;
267 }
268
269 printk("Bluetooth initialized\n");
270 bap_stream_tx_init();
271
272 broadcast_stream = &broadcast_source_stream.stream;
273 bt_bap_stream_cb_register(&broadcast_source_stream.stream.bap_stream,
274 &broadcast_stream_ops);
275
276 stream_params.stream = &broadcast_source_stream.stream;
277 stream_params.data_len = ARRAY_SIZE(bis_codec_data);
278 stream_params.data = bis_codec_data;
279
280 subgroup_param.stream_count = 1U;
281 subgroup_param.stream_params = &stream_params;
282 subgroup_param.codec_cfg = &broadcast_preset_48_2_1.codec_cfg;
283
284 create_param.subgroup_count = 1U;
285 create_param.subgroup_params = &subgroup_param;
286 create_param.qos = &broadcast_preset_48_2_1.qos;
287 create_param.packing = BT_ISO_PACKING_SEQUENTIAL;
288 create_param.encryption = false;
289
290 while (count < PBP_STREAMS_TO_SEND) {
291 k_sem_reset(&sem_started);
292 k_sem_reset(&sem_stopped);
293
294 err = setup_extended_adv(&adv);
295 if (err != 0) {
296 printk("Unable to setup extended advertiser: %d\n", err);
297 FAIL("Public Broadcast source failed\n");
298 }
299
300 err = bt_cap_initiator_broadcast_audio_create(&create_param, &broadcast_source);
301 if (err != 0) {
302 printk("Unable to create broadcast source: %d\n", err);
303 FAIL("Public Broadcast source failed\n");
304 }
305
306 err = bt_cap_initiator_broadcast_audio_start(broadcast_source, adv);
307 if (err != 0) {
308 printk("Unable to start broadcast source: %d\n", err);
309 FAIL("Public Broadcast source failed\n");
310 }
311
312 err = setup_extended_adv_data(broadcast_source, adv);
313 if (err != 0) {
314 printk("Unable to setup extended advertising data: %d\n", err);
315 FAIL("Public Broadcast source failed\n");
316 }
317
318 err = start_extended_adv(adv);
319 if (err != 0) {
320 printk("Unable to start extended advertiser: %d\n", err);
321 FAIL("Public Broadcast source failed\n");
322 }
323
324 k_sem_take(&sem_started, SEM_TIMEOUT);
325
326 /* Wait for other devices to let us know when we can stop the source */
327 printk("Waiting for signal from receiver to stop\n");
328 backchannel_sync_wait_any();
329
330 printk("Stopping broadcast source\n");
331 err = bt_cap_initiator_broadcast_audio_stop(broadcast_source);
332 if (err != 0) {
333 printk("Failed to stop broadcast source: %d\n", err);
334 FAIL("Public Broadcast source failed\n");
335 }
336
337 k_sem_take(&sem_stopped, SEM_TIMEOUT);
338 err = bt_cap_initiator_broadcast_audio_delete(broadcast_source);
339 if (err != 0) {
340 printk("Failed to stop broadcast source: %d\n", err);
341 FAIL("Public Broadcast source failed\n");
342 }
343
344 broadcast_source = NULL;
345
346 err = stop_extended_adv(adv);
347 if (err != 0) {
348 printk("Failed to stop and delete extended advertising: %d\n", err);
349 FAIL("Public Broadcast source failed\n");
350 }
351
352 count++;
353 }
354
355 PASS("Public Broadcast source passed\n");
356 }
357
358 static const struct bst_test_instance test_pbp_broadcaster[] = {
359 {
360 .test_id = "public_broadcast_source",
361 .test_pre_init_f = test_init,
362 .test_tick_f = test_tick,
363 .test_main_f = test_main
364 },
365 BSTEST_END_MARKER
366 };
367
test_public_broadcast_source_install(struct bst_test_list * tests)368 struct bst_test_list *test_public_broadcast_source_install(struct bst_test_list *tests)
369 {
370 return bst_add_tests(tests, test_pbp_broadcaster);
371 }
372
373 #else /* CONFIG_BT_PBP */
374
test_public_broadcast_source_install(struct bst_test_list * tests)375 struct bst_test_list *test_public_broadcast_source_install(struct bst_test_list *tests)
376 {
377 return tests;
378 }
379
380 #endif /* CONFIG_BT_PBP */
381