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