1 /*
2 * Copyright (c) 2024 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <stddef.h>
8 #include <stdint.h>
9
10 #include <zephyr/bluetooth/audio/audio.h>
11 #include <zephyr/bluetooth/audio/bap_lc3_preset.h>
12 #include <zephyr/bluetooth/audio/cap.h>
13 #include <zephyr/bluetooth/audio/bap.h>
14 #include <zephyr/bluetooth/bluetooth.h>
15 #include <zephyr/bluetooth/crypto.h>
16 #include <zephyr/bluetooth/gap.h>
17 #include <zephyr/bluetooth/uuid.h>
18 #include <zephyr/kernel.h>
19 #include <zephyr/logging/log.h>
20 #include <zephyr/logging/log_core.h>
21 #include <zephyr/net_buf.h>
22 #include <zephyr/sys/byteorder.h>
23 #include <zephyr/sys/util.h>
24 #include <zephyr/types.h>
25
26 #include "cap_initiator.h"
27
28 LOG_MODULE_REGISTER(cap_initiator_broadcast, LOG_LEVEL_INF);
29
30 static struct bt_cap_stream broadcast_stream;
31 uint64_t total_broadcast_tx_iso_packet_count; /* This value is exposed to test code */
32
broadcast_stream_started_cb(struct bt_bap_stream * stream)33 static void broadcast_stream_started_cb(struct bt_bap_stream *stream)
34 {
35 struct bt_cap_stream *cap_stream = CONTAINER_OF(stream, struct bt_cap_stream, bap_stream);
36 int err;
37
38 LOG_INF("Started broadcast stream %p", stream);
39 total_broadcast_tx_iso_packet_count = 0U;
40
41 err = cap_initiator_tx_register_stream(cap_stream);
42 if (err != 0) {
43 LOG_ERR("Failed to register %p for TX: %d", stream, err);
44 }
45 }
46
broadcast_stream_stopped_cb(struct bt_bap_stream * stream,uint8_t reason)47 static void broadcast_stream_stopped_cb(struct bt_bap_stream *stream, uint8_t reason)
48 {
49 struct bt_cap_stream *cap_stream = CONTAINER_OF(stream, struct bt_cap_stream, bap_stream);
50 int err;
51
52 LOG_INF("Stopped broadcast stream %p with reason 0x%02X", stream, reason);
53
54 err = cap_initiator_tx_unregister_stream(cap_stream);
55 if (err != 0) {
56 LOG_ERR("Failed to unregister %p for TX: %d", stream, err);
57 }
58 }
59
broadcast_stream_sent_cb(struct bt_bap_stream * stream)60 static void broadcast_stream_sent_cb(struct bt_bap_stream *stream)
61 {
62 /* Triggered every time we have sent an HCI data packet to the controller */
63
64 if ((total_broadcast_tx_iso_packet_count % 100U) == 0U) {
65 LOG_INF("Sent %llu HCI ISO data packets", total_broadcast_tx_iso_packet_count);
66 }
67
68 total_broadcast_tx_iso_packet_count++;
69 }
70
setup_extended_adv(struct bt_le_ext_adv ** adv)71 static int setup_extended_adv(struct bt_le_ext_adv **adv)
72 {
73 int err;
74
75 /* Create a non-connectable non-scannable advertising set */
76 err = bt_le_ext_adv_create(BT_BAP_ADV_PARAM_BROADCAST_FAST, NULL, adv);
77 if (err != 0) {
78 LOG_ERR("Unable to create extended advertising set: %d", err);
79 return err;
80 }
81
82 /* Set periodic advertising parameters */
83 err = bt_le_per_adv_set_param(*adv, BT_BAP_PER_ADV_PARAM_BROADCAST_FAST);
84 if (err != 0) {
85 LOG_ERR("Failed to set periodic advertising parameters: %d", err);
86 return err;
87 }
88
89 return 0;
90 }
91
broadcast_create(struct bt_cap_broadcast_source ** broadcast_source)92 static int broadcast_create(struct bt_cap_broadcast_source **broadcast_source)
93 {
94 /** For simplicity we use the mandatory configuration 16_2_1 */
95 static struct bt_bap_lc3_preset broadcast_preset_16_2_1 =
96 BT_BAP_LC3_BROADCAST_PRESET_16_2_1(BT_AUDIO_LOCATION_MONO_AUDIO,
97 BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED);
98 struct bt_cap_initiator_broadcast_stream_param stream_params = {
99 .stream = &broadcast_stream,
100 };
101 struct bt_cap_initiator_broadcast_subgroup_param subgroup_param = {
102 .codec_cfg = &broadcast_preset_16_2_1.codec_cfg,
103 .stream_params = &stream_params,
104 .stream_count = 1U,
105 };
106 const struct bt_cap_initiator_broadcast_create_param create_param = {
107 .qos = &broadcast_preset_16_2_1.qos,
108 .subgroup_params = &subgroup_param,
109 .subgroup_count = 1U,
110 };
111 int err;
112
113 LOG_INF("Creating broadcast source");
114
115 err = bt_cap_initiator_broadcast_audio_create(&create_param, broadcast_source);
116 if (err != 0) {
117 LOG_ERR("Unable to start broadcast source: %d", err);
118 return err;
119 }
120
121 return 0;
122 }
123
setup_extended_adv_data(struct bt_cap_broadcast_source * source,struct bt_le_ext_adv * adv)124 static int setup_extended_adv_data(struct bt_cap_broadcast_source *source,
125 struct bt_le_ext_adv *adv)
126 {
127 /* Broadcast Audio Streaming Endpoint advertising data */
128 NET_BUF_SIMPLE_DEFINE(ad_buf, BT_UUID_SIZE_16 + BT_AUDIO_BROADCAST_ID_SIZE);
129 NET_BUF_SIMPLE_DEFINE(base_buf, 64);
130 struct bt_data ext_ad;
131 struct bt_data per_ad;
132 uint32_t broadcast_id;
133 int err;
134
135 #if defined(CONFIG_STATIC_BROADCAST_ID)
136 broadcast_id = CONFIG_BROADCAST_ID;
137 #else
138 err = bt_rand(&broadcast_id, BT_AUDIO_BROADCAST_ID_SIZE);
139 if (err) {
140 LOG_ERR("Unable to generate broadcast ID: %d\n", err);
141 return err;
142 }
143 #endif /* CONFIG_STATIC_BROADCAST_ID */
144
145 /* Setup extended advertising data */
146 net_buf_simple_add_le16(&ad_buf, BT_UUID_BROADCAST_AUDIO_VAL);
147 net_buf_simple_add_le24(&ad_buf, broadcast_id);
148 ext_ad.type = BT_DATA_SVC_DATA16;
149 ext_ad.data_len = ad_buf.len;
150 ext_ad.data = ad_buf.data;
151 err = bt_le_ext_adv_set_data(adv, &ext_ad, 1, NULL, 0);
152 if (err != 0) {
153 LOG_ERR("Failed to set extended advertising data: %d", err);
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 LOG_ERR("Failed to get encoded BASE: %d", err);
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 LOG_ERR("Failed to set periodic advertising data: %d", err);
170 return err;
171 }
172
173 return 0;
174 }
175
start_extended_adv(struct bt_le_ext_adv * adv)176 static int start_extended_adv(struct bt_le_ext_adv *adv)
177 {
178 int err;
179
180 /* Start extended advertising */
181 err = bt_le_ext_adv_start(adv, BT_LE_EXT_ADV_START_DEFAULT);
182 if (err != 0) {
183 LOG_ERR("Failed to start extended advertising: %d", err);
184 return err;
185 }
186
187 /* Enable Periodic Advertising */
188 err = bt_le_per_adv_start(adv);
189 if (err != 0) {
190 LOG_ERR("Failed to enable periodic advertising: %d", err);
191 return err;
192 }
193
194 return 0;
195 }
196
broadcast_start(struct bt_cap_broadcast_source * broadcast_source,struct bt_le_ext_adv * adv)197 static int broadcast_start(struct bt_cap_broadcast_source *broadcast_source,
198 struct bt_le_ext_adv *adv)
199 {
200 int err;
201
202 err = bt_cap_initiator_broadcast_audio_start(broadcast_source, adv);
203 if (err != 0) {
204 LOG_ERR("Unable to start broadcast source: %d", err);
205 return err;
206 }
207
208 LOG_INF("Broadcast source started");
209
210 return 0;
211 }
212
init_cap_initiator(void)213 static int init_cap_initiator(void)
214 {
215 static struct bt_bap_stream_ops broadcast_stream_ops = {
216 .started = broadcast_stream_started_cb,
217 .stopped = broadcast_stream_stopped_cb,
218 .sent = broadcast_stream_sent_cb,
219 };
220
221 bt_cap_stream_ops_register(&broadcast_stream, &broadcast_stream_ops);
222
223 cap_initiator_tx_init();
224
225 return 0;
226 }
227
cap_initiator_broadcast(void)228 int cap_initiator_broadcast(void)
229 {
230 struct bt_cap_broadcast_source *broadcast_source;
231 struct bt_le_ext_adv *adv;
232 int err;
233
234 err = init_cap_initiator();
235 if (err != 0) {
236 return err;
237 }
238
239 LOG_INF("CAP initiator broadcast initialized");
240
241 err = setup_extended_adv(&adv);
242 if (err != 0) {
243 return err;
244 }
245
246 err = broadcast_create(&broadcast_source);
247 if (err != 0) {
248 return err;
249 }
250
251 err = broadcast_start(broadcast_source, adv);
252 if (err != 0) {
253 return err;
254 }
255
256 err = setup_extended_adv_data(broadcast_source, adv);
257 if (err != 0) {
258 return err;
259 }
260
261 err = start_extended_adv(adv);
262 if (err != 0) {
263 return err;
264 }
265
266 return 0;
267 }
268