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