1 /*
2 * Copyright (c) 2024 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <errno.h>
8 #include <stddef.h>
9 #include <stdint.h>
10
11 #include <zephyr/autoconf.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/iso.h>
16 #include <zephyr/kernel.h>
17 #include <zephyr/kernel/thread_stack.h>
18 #include <zephyr/logging/log.h>
19 #include <zephyr/logging/log_core.h>
20 #include <zephyr/net_buf.h>
21 #include <zephyr/sys/byteorder.h>
22 #include <zephyr/sys/util.h>
23 #include <zephyr/sys/util_macro.h>
24 #include <zephyr/types.h>
25
26 #include "cap_initiator.h"
27
28 LOG_MODULE_REGISTER(cap_initiator_tx, LOG_LEVEL_INF);
29
30 struct tx_stream
31 tx_streams[IS_ENABLED(CONFIG_SAMPLE_UNICAST) + IS_ENABLED(CONFIG_SAMPLE_BROADCAST)];
32
tx_thread_func(void * arg1,void * arg2,void * arg3)33 static void tx_thread_func(void *arg1, void *arg2, void *arg3)
34 {
35 NET_BUF_POOL_FIXED_DEFINE(tx_pool, CONFIG_BT_ISO_TX_BUF_COUNT,
36 BT_ISO_SDU_BUF_SIZE(CONFIG_BT_ISO_TX_MTU),
37 CONFIG_BT_CONN_TX_USER_DATA_SIZE, NULL);
38 static uint8_t data[CONFIG_BT_ISO_TX_MTU];
39
40 for (size_t i = 0U; i < ARRAY_SIZE(data); i++) {
41 data[i] = (uint8_t)i;
42 }
43
44 while (true) {
45 int err = -ENOEXEC;
46
47 for (size_t i = 0U; i < ARRAY_SIZE(tx_streams); i++) {
48 struct bt_cap_stream *cap_stream = tx_streams[i].stream;
49 const struct bt_bap_stream *bap_stream;
50 struct bt_bap_ep_info ep_info;
51
52 if (cap_stream == NULL) {
53 continue;
54 }
55
56 bap_stream = &cap_stream->bap_stream;
57
58 /* No-op if stream is not configured */
59 if (bap_stream->ep == NULL) {
60 continue;
61 }
62
63 err = bt_bap_ep_get_info(bap_stream->ep, &ep_info);
64 if (err != 0) {
65 continue;
66 }
67
68 if (ep_info.state == BT_BAP_EP_STATE_STREAMING) {
69 struct net_buf *buf;
70
71 buf = net_buf_alloc(&tx_pool, K_FOREVER);
72 net_buf_reserve(buf, BT_ISO_CHAN_SEND_RESERVE);
73
74 net_buf_add_mem(buf, data, bap_stream->qos->sdu);
75
76 err = bt_cap_stream_send(cap_stream, buf, tx_streams[i].seq_num);
77 if (err == 0) {
78 tx_streams[i].seq_num++;
79 } else {
80 LOG_ERR("Unable to send: %d", err);
81 net_buf_unref(buf);
82 }
83 }
84 }
85
86 if (err != 0) {
87 /* In case of any errors, retry with a delay */
88 k_sleep(K_MSEC(100));
89 }
90 }
91 }
92
cap_initiator_tx_register_stream(struct bt_cap_stream * cap_stream)93 int cap_initiator_tx_register_stream(struct bt_cap_stream *cap_stream)
94 {
95 if (cap_stream == NULL) {
96 return -EINVAL;
97 }
98
99 for (size_t i = 0U; i < ARRAY_SIZE(tx_streams); i++) {
100 if (tx_streams[i].stream == NULL) {
101 tx_streams[i].stream = cap_stream;
102 tx_streams[i].seq_num = 0U;
103
104 return 0;
105 }
106 }
107
108 return -ENOMEM;
109 }
110
cap_initiator_tx_unregister_stream(struct bt_cap_stream * cap_stream)111 int cap_initiator_tx_unregister_stream(struct bt_cap_stream *cap_stream)
112 {
113 if (cap_stream == NULL) {
114 return -EINVAL;
115 }
116
117 for (size_t i = 0U; i < ARRAY_SIZE(tx_streams); i++) {
118 if (tx_streams[i].stream == cap_stream) {
119 tx_streams[i].stream = NULL;
120
121 return 0;
122 }
123 }
124
125 return -ENODATA;
126 }
127
cap_initiator_tx_init(void)128 void cap_initiator_tx_init(void)
129 {
130 static bool thread_started;
131
132 if (!thread_started) {
133 static K_KERNEL_STACK_DEFINE(tx_thread_stack, 1024);
134 const int tx_thread_prio = K_PRIO_PREEMPT(5);
135 static struct k_thread tx_thread;
136
137 k_thread_create(&tx_thread, tx_thread_stack, K_KERNEL_STACK_SIZEOF(tx_thread_stack),
138 tx_thread_func, NULL, NULL, NULL, tx_thread_prio, 0, K_NO_WAIT);
139 k_thread_name_set(&tx_thread, "TX thread");
140 thread_started = true;
141 }
142 }
143