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