1 /** @file
2 * @brief Bluetooth Common Audio Profile (CAP) Acceptor unicast.
3 *
4 * Copyright (c) 2021-2024 Nordic Semiconductor ASA
5 * Copyright (c) 2023 NXP
6 *
7 * SPDX-License-Identifier: Apache-2.0
8 */
9
10 #include <autoconf.h>
11 #include <errno.h>
12 #include <stdbool.h>
13 #include <stddef.h>
14 #include <stdint.h>
15
16 #include <zephyr/bluetooth/audio/audio.h>
17 #include <zephyr/bluetooth/audio/bap.h>
18 #include <zephyr/bluetooth/audio/cap.h>
19 #include <zephyr/bluetooth/audio/lc3.h>
20 #include <zephyr/bluetooth/bluetooth.h>
21 #include <zephyr/bluetooth/conn.h>
22 #include <zephyr/bluetooth/gap.h>
23 #include <zephyr/bluetooth/hci_types.h>
24 #include <zephyr/bluetooth/iso.h>
25 #include <zephyr/kernel.h>
26 #include <zephyr/kernel/thread_stack.h>
27 #include <zephyr/logging/log.h>
28 #include <zephyr/logging/log_core.h>
29 #include <zephyr/net_buf.h>
30 #include <zephyr/sys/util.h>
31 #include <zephyr/sys/util_macro.h>
32
33 #include "cap_acceptor.h"
34
35 LOG_MODULE_REGISTER(cap_acceptor_unicast, LOG_LEVEL_INF);
36
37 #define PREF_PHY BT_GAP_LE_PHY_2M
38 #define MIN_PD 20000U
39 #define MAX_PD 40000U
40 #define UNFRAMED_SUPPORTED true
41 #define LATENCY 20U
42 #define RTN 2U
43
44 static const struct bt_bap_qos_cfg_pref qos_pref = BT_BAP_QOS_CFG_PREF(
45 UNFRAMED_SUPPORTED, PREF_PHY, RTN, LATENCY, MIN_PD, MAX_PD, MIN_PD, MAX_PD);
46 uint64_t total_unicast_rx_iso_packet_count; /* This value is exposed to test code */
47 uint64_t total_unicast_tx_iso_packet_count; /* This value is exposed to test code */
48
log_codec_cfg_cb(struct bt_data * data,void * user_data)49 static bool log_codec_cfg_cb(struct bt_data *data, void *user_data)
50 {
51 const char *str = (const char *)user_data;
52
53 LOG_DBG("\t%s: type 0x%02x value_len %u", str, data->type, data->data_len);
54 LOG_HEXDUMP_DBG(data->data, data->data_len, "\t\tdata");
55
56 return true;
57 }
58
log_codec_cfg(const struct bt_audio_codec_cfg * codec_cfg)59 static void log_codec_cfg(const struct bt_audio_codec_cfg *codec_cfg)
60 {
61 LOG_INF("codec_cfg 0x%02x cid 0x%04x vid 0x%04x count %u", codec_cfg->id, codec_cfg->cid,
62 codec_cfg->vid, codec_cfg->data_len);
63
64 if (codec_cfg->id == BT_HCI_CODING_FORMAT_LC3) {
65 enum bt_audio_location chan_allocation;
66 int ret;
67
68 /* LC3 uses the generic LTV format - other codecs might do as well */
69
70 bt_audio_data_parse(codec_cfg->data, codec_cfg->data_len, log_codec_cfg_cb, "data");
71
72 ret = bt_audio_codec_cfg_get_freq(codec_cfg);
73 if (ret > 0) {
74 LOG_INF("\tFrequency: %d Hz", bt_audio_codec_cfg_freq_to_freq_hz(ret));
75 }
76
77 ret = bt_audio_codec_cfg_get_frame_dur(codec_cfg);
78 if (ret > 0) {
79 LOG_INF("\tFrame Duration: %d us",
80 bt_audio_codec_cfg_frame_dur_to_frame_dur_us(ret));
81 }
82
83 if (bt_audio_codec_cfg_get_chan_allocation(codec_cfg, &chan_allocation, true) ==
84 0) {
85 LOG_INF("\tChannel allocation: 0x%08X", chan_allocation);
86 }
87
88 ret = bt_audio_codec_cfg_get_octets_per_frame(codec_cfg);
89 if (ret > 0) {
90 LOG_INF("\tOctets per frame: %d", ret);
91 }
92
93 LOG_INF("\tFrames per SDU: %d",
94 bt_audio_codec_cfg_get_frame_blocks_per_sdu(codec_cfg, true));
95 } else {
96 LOG_HEXDUMP_DBG(codec_cfg->data, codec_cfg->data_len, "data");
97 }
98
99 bt_audio_data_parse(codec_cfg->meta, codec_cfg->meta_len, log_codec_cfg_cb, "meta");
100 }
101
log_qos(const struct bt_bap_qos_cfg * qos)102 static void log_qos(const struct bt_bap_qos_cfg *qos)
103 {
104 LOG_INF("QoS: interval %u framing 0x%02x phy 0x%02x sdu %u rtn %u latency %u pd %u",
105 qos->interval, qos->framing, qos->phy, qos->sdu, qos->rtn, qos->latency, qos->pd);
106 }
107
unicast_server_config_cb(struct bt_conn * conn,const struct bt_bap_ep * ep,enum bt_audio_dir dir,const struct bt_audio_codec_cfg * codec_cfg,struct bt_bap_stream ** bap_stream,struct bt_bap_qos_cfg_pref * const pref,struct bt_bap_ascs_rsp * rsp)108 static int unicast_server_config_cb(struct bt_conn *conn, const struct bt_bap_ep *ep,
109 enum bt_audio_dir dir,
110 const struct bt_audio_codec_cfg *codec_cfg,
111 struct bt_bap_stream **bap_stream,
112 struct bt_bap_qos_cfg_pref *const pref,
113 struct bt_bap_ascs_rsp *rsp)
114 {
115 struct bt_cap_stream *cap_stream;
116
117 LOG_INF("ASE Codec Config: conn %p ep %p dir %u", (void *)conn, (void *)ep, dir);
118
119 log_codec_cfg(codec_cfg);
120
121 cap_stream = stream_alloc(dir);
122 if (cap_stream == NULL) {
123 LOG_WRN("No streams available");
124 *rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_NO_MEM, BT_BAP_ASCS_REASON_NONE);
125
126 return -ENOMEM;
127 }
128
129 *bap_stream = &cap_stream->bap_stream;
130
131 LOG_INF("ASE Codec Config bap_stream %p", *bap_stream);
132
133 *pref = qos_pref;
134
135 return 0;
136 }
137
unicast_server_reconfig_cb(struct bt_bap_stream * bap_stream,enum bt_audio_dir dir,const struct bt_audio_codec_cfg * codec_cfg,struct bt_bap_qos_cfg_pref * const pref,struct bt_bap_ascs_rsp * rsp)138 static int unicast_server_reconfig_cb(struct bt_bap_stream *bap_stream, enum bt_audio_dir dir,
139 const struct bt_audio_codec_cfg *codec_cfg,
140 struct bt_bap_qos_cfg_pref *const pref,
141 struct bt_bap_ascs_rsp *rsp)
142 {
143 LOG_INF("ASE Codec Reconfig: bap_stream %p", bap_stream);
144 log_codec_cfg(codec_cfg);
145 *pref = qos_pref;
146
147 return 0;
148 }
149
unicast_server_qos_cb(struct bt_bap_stream * bap_stream,const struct bt_bap_qos_cfg * qos,struct bt_bap_ascs_rsp * rsp)150 static int unicast_server_qos_cb(struct bt_bap_stream *bap_stream, const struct bt_bap_qos_cfg *qos,
151 struct bt_bap_ascs_rsp *rsp)
152 {
153 LOG_INF("QoS: bap_stream %p qos %p", bap_stream, qos);
154
155 log_qos(qos);
156
157 return 0;
158 }
159
unicast_server_enable_cb(struct bt_bap_stream * bap_stream,const uint8_t meta[],size_t meta_len,struct bt_bap_ascs_rsp * rsp)160 static int unicast_server_enable_cb(struct bt_bap_stream *bap_stream, const uint8_t meta[],
161 size_t meta_len, struct bt_bap_ascs_rsp *rsp)
162 {
163 LOG_INF("Enable: bap_stream %p meta_len %zu", bap_stream, meta_len);
164
165 return 0;
166 }
167
unicast_server_start_cb(struct bt_bap_stream * bap_stream,struct bt_bap_ascs_rsp * rsp)168 static int unicast_server_start_cb(struct bt_bap_stream *bap_stream, struct bt_bap_ascs_rsp *rsp)
169 {
170 LOG_INF("Start: bap_stream %p", bap_stream);
171
172 return 0;
173 }
174
175 struct data_func_param {
176 struct bt_bap_ascs_rsp *rsp;
177 bool stream_context_present;
178 };
179
data_func_cb(struct bt_data * data,void * user_data)180 static bool data_func_cb(struct bt_data *data, void *user_data)
181 {
182 struct data_func_param *func_param = (struct data_func_param *)user_data;
183
184 if (data->type == BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT) {
185 func_param->stream_context_present = true;
186 }
187
188 return true;
189 }
190
unicast_server_metadata_cb(struct bt_bap_stream * bap_stream,const uint8_t meta[],size_t meta_len,struct bt_bap_ascs_rsp * rsp)191 static int unicast_server_metadata_cb(struct bt_bap_stream *bap_stream, const uint8_t meta[],
192 size_t meta_len, struct bt_bap_ascs_rsp *rsp)
193 {
194 struct data_func_param func_param = {
195 .rsp = rsp,
196 .stream_context_present = false,
197 };
198 int err;
199
200 LOG_INF("Metadata: bap_stream %p meta_len %zu", bap_stream, meta_len);
201
202 err = bt_audio_data_parse(meta, meta_len, data_func_cb, &func_param);
203 if (err != 0) {
204 return err;
205 }
206
207 if (!func_param.stream_context_present) {
208 LOG_ERR("Stream audio context not present");
209 *rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_METADATA_REJECTED,
210 BT_BAP_ASCS_REASON_NONE);
211
212 return -EINVAL;
213 }
214
215 return 0;
216 }
217
unicast_server_disable_cb(struct bt_bap_stream * bap_stream,struct bt_bap_ascs_rsp * rsp)218 static int unicast_server_disable_cb(struct bt_bap_stream *bap_stream, struct bt_bap_ascs_rsp *rsp)
219 {
220 LOG_INF("Disable: bap_stream %p", bap_stream);
221
222 return 0;
223 }
224
unicast_server_stop_cb(struct bt_bap_stream * bap_stream,struct bt_bap_ascs_rsp * rsp)225 static int unicast_server_stop_cb(struct bt_bap_stream *bap_stream, struct bt_bap_ascs_rsp *rsp)
226 {
227 LOG_INF("Stop: bap_stream %p", bap_stream);
228
229 return 0;
230 }
231
unicast_server_release_cb(struct bt_bap_stream * bap_stream,struct bt_bap_ascs_rsp * rsp)232 static int unicast_server_release_cb(struct bt_bap_stream *bap_stream, struct bt_bap_ascs_rsp *rsp)
233 {
234 LOG_INF("Release: bap_stream %p", bap_stream);
235
236 return 0;
237 }
238
239 static const struct bt_bap_unicast_server_cb unicast_server_cb = {
240 .config = unicast_server_config_cb,
241 .reconfig = unicast_server_reconfig_cb,
242 .qos = unicast_server_qos_cb,
243 .enable = unicast_server_enable_cb,
244 .start = unicast_server_start_cb,
245 .metadata = unicast_server_metadata_cb,
246 .disable = unicast_server_disable_cb,
247 .stop = unicast_server_stop_cb,
248 .release = unicast_server_release_cb,
249 };
250
unicast_stream_configured_cb(struct bt_bap_stream * bap_stream,const struct bt_bap_qos_cfg_pref * pref)251 static void unicast_stream_configured_cb(struct bt_bap_stream *bap_stream,
252 const struct bt_bap_qos_cfg_pref *pref)
253 {
254 LOG_INF("Configured bap_stream %p", bap_stream);
255
256 /* TODO: The preference should be used/taken into account when
257 * setting the QoS
258 */
259
260 LOG_INF("Local preferences: unframed %s, phy %u, rtn %u, latency %u, pd_min %u, pd_max "
261 "%u, pref_pd_min %u, pref_pd_max %u",
262 pref->unframed_supported ? "supported" : "not supported", pref->phy, pref->rtn,
263 pref->latency, pref->pd_min, pref->pd_max, pref->pref_pd_min, pref->pref_pd_max);
264 }
265
unicast_stream_qos_set_cb(struct bt_bap_stream * bap_stream)266 static void unicast_stream_qos_set_cb(struct bt_bap_stream *bap_stream)
267 {
268 LOG_INF("QoS set bap_stream %p", bap_stream);
269 }
270
unicast_stream_enabled_cb(struct bt_bap_stream * bap_stream)271 static void unicast_stream_enabled_cb(struct bt_bap_stream *bap_stream)
272 {
273 struct bt_bap_ep_info ep_info;
274 int err;
275
276 LOG_INF("Enabled bap_stream %p", bap_stream);
277
278 err = bt_bap_ep_get_info(bap_stream->ep, &ep_info);
279 if (err != 0) {
280 LOG_ERR("Failed to get ep info: %d", err);
281
282 return;
283 }
284
285 if (ep_info.dir == BT_AUDIO_DIR_SINK) {
286 /* Automatically do the receiver start ready operation */
287 err = bt_bap_stream_start(bap_stream);
288 if (err != 0) {
289 LOG_ERR("Failed to start: %d", err);
290
291 return;
292 }
293 }
294 }
295
unicast_stream_started_cb(struct bt_bap_stream * bap_stream)296 static void unicast_stream_started_cb(struct bt_bap_stream *bap_stream)
297 {
298 LOG_INF("Started bap_stream %p", bap_stream);
299 total_unicast_rx_iso_packet_count = 0U;
300 }
301
unicast_stream_metadata_updated_cb(struct bt_bap_stream * bap_stream)302 static void unicast_stream_metadata_updated_cb(struct bt_bap_stream *bap_stream)
303 {
304 LOG_INF("Metadata updated bap_stream %p", bap_stream);
305 }
306
unicast_stream_disabled_cb(struct bt_bap_stream * bap_stream)307 static void unicast_stream_disabled_cb(struct bt_bap_stream *bap_stream)
308 {
309 LOG_INF("Disabled bap_stream %p", bap_stream);
310 }
311
unicast_stream_stopped_cb(struct bt_bap_stream * bap_stream,uint8_t reason)312 static void unicast_stream_stopped_cb(struct bt_bap_stream *bap_stream, uint8_t reason)
313 {
314 LOG_INF("Stopped bap_stream %p with reason 0x%02X", bap_stream, reason);
315 }
316
unicast_stream_released_cb(struct bt_bap_stream * bap_stream)317 static void unicast_stream_released_cb(struct bt_bap_stream *bap_stream)
318 {
319 struct bt_cap_stream *cap_stream =
320 CONTAINER_OF(bap_stream, struct bt_cap_stream, bap_stream);
321
322 LOG_INF("Released bap_stream %p", bap_stream);
323
324 stream_released(cap_stream);
325 }
326
unicast_stream_recv_cb(struct bt_bap_stream * bap_stream,const struct bt_iso_recv_info * info,struct net_buf * buf)327 static void unicast_stream_recv_cb(struct bt_bap_stream *bap_stream,
328 const struct bt_iso_recv_info *info, struct net_buf *buf)
329 {
330 /* Triggered every time we receive an HCI data packet from the controller.
331 * A call to this does not indicate valid data
332 * (see the `info->flags` for which flags to check),
333 */
334
335 if ((total_unicast_rx_iso_packet_count % 100U) == 0U) {
336 LOG_INF("Received %llu HCI ISO data packets", total_unicast_rx_iso_packet_count);
337 }
338
339 total_unicast_rx_iso_packet_count++;
340 }
341
unicast_stream_sent_cb(struct bt_bap_stream * stream)342 static void unicast_stream_sent_cb(struct bt_bap_stream *stream)
343 {
344 /* Triggered every time we have sent an HCI data packet to the controller */
345
346 if ((total_unicast_tx_iso_packet_count % 100U) == 0U) {
347 LOG_INF("Sent %llu HCI ISO data packets", total_unicast_tx_iso_packet_count);
348 }
349
350 total_unicast_tx_iso_packet_count++;
351 }
352
tx_thread_func(void * arg1,void * arg2,void * arg3)353 static void tx_thread_func(void *arg1, void *arg2, void *arg3)
354 {
355 NET_BUF_POOL_FIXED_DEFINE(tx_pool, CONFIG_BT_ISO_TX_BUF_COUNT,
356 BT_ISO_SDU_BUF_SIZE(CONFIG_BT_ISO_TX_MTU),
357 CONFIG_BT_CONN_TX_USER_DATA_SIZE, NULL);
358 static uint8_t data[CONFIG_BT_ISO_TX_MTU];
359 struct peer_config *peer = arg1;
360 struct bt_cap_stream *cap_stream = &peer->source_stream;
361 struct bt_bap_stream *bap_stream = &cap_stream->bap_stream;
362
363 for (size_t i = 0U; i < ARRAY_SIZE(data); i++) {
364 data[i] = (uint8_t)i;
365 }
366
367 while (true) {
368 /* No-op if stream is not configured */
369 if (bap_stream->ep != NULL) {
370 struct bt_bap_ep_info ep_info;
371 int err;
372
373 err = bt_bap_ep_get_info(bap_stream->ep, &ep_info);
374 if (err == 0) {
375 if (ep_info.state == BT_BAP_EP_STATE_STREAMING) {
376 struct net_buf *buf;
377
378 buf = net_buf_alloc(&tx_pool, K_FOREVER);
379 net_buf_reserve(buf, BT_ISO_CHAN_SEND_RESERVE);
380
381 net_buf_add_mem(buf, data, bap_stream->qos->sdu);
382
383 err = bt_cap_stream_send(cap_stream, buf, peer->tx_seq_num);
384 if (err == 0) {
385 peer->tx_seq_num++;
386 continue; /* Attempt to send again ASAP */
387 } else {
388 LOG_ERR("Unable to send: %d", err);
389 net_buf_unref(buf);
390 }
391 }
392 }
393 }
394
395 /* In case of any errors, retry with a delay */
396 k_sleep(K_MSEC(100));
397 }
398 }
399
init_cap_acceptor_unicast(struct peer_config * peer)400 int init_cap_acceptor_unicast(struct peer_config *peer)
401 {
402 static struct bt_bap_stream_ops unicast_stream_ops = {
403 .configured = unicast_stream_configured_cb,
404 .qos_set = unicast_stream_qos_set_cb,
405 .enabled = unicast_stream_enabled_cb,
406 .started = unicast_stream_started_cb,
407 .metadata_updated = unicast_stream_metadata_updated_cb,
408 .disabled = unicast_stream_disabled_cb,
409 .stopped = unicast_stream_stopped_cb,
410 .released = unicast_stream_released_cb,
411 .recv = unicast_stream_recv_cb,
412 .sent = unicast_stream_sent_cb,
413 };
414 static bool cbs_registered;
415
416 if (!cbs_registered) {
417 int err;
418 struct bt_bap_unicast_server_register_param param = {
419 CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT,
420 CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT
421 };
422
423 err = bt_bap_unicast_server_register(¶m);
424 if (err != 0) {
425 LOG_ERR("Failed to register BAP unicast server: %d", err);
426
427 return -ENOEXEC;
428 }
429
430 err = bt_bap_unicast_server_register_cb(&unicast_server_cb);
431 if (err != 0) {
432 LOG_ERR("Failed to register BAP unicast server callbacks: %d", err);
433
434 return -ENOEXEC;
435 }
436
437 cbs_registered = true;
438 }
439
440 bt_cap_stream_ops_register(&peer->source_stream, &unicast_stream_ops);
441 bt_cap_stream_ops_register(&peer->sink_stream, &unicast_stream_ops);
442
443 if (IS_ENABLED(CONFIG_BT_ASCS_ASE_SRC)) {
444 static bool thread_started;
445
446 if (!thread_started) {
447 static K_KERNEL_STACK_DEFINE(tx_thread_stack, 1024);
448 const int tx_thread_prio = K_PRIO_PREEMPT(5);
449 static struct k_thread tx_thread;
450
451 k_thread_create(&tx_thread, tx_thread_stack,
452 K_KERNEL_STACK_SIZEOF(tx_thread_stack), tx_thread_func,
453 peer, NULL, NULL, tx_thread_prio, 0, K_NO_WAIT);
454 k_thread_name_set(&tx_thread, "TX thread");
455 thread_started = true;
456 }
457 }
458
459 return 0;
460 }
461