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