1 /*
2  * Copyright (c) 2022-2024 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <errno.h>
8 #include <stddef.h>
9 #include <stdbool.h>
10 #include <stdint.h>
11 
12 #include <zephyr/autoconf.h>
13 #include <zephyr/bluetooth/audio/audio.h>
14 #include <zephyr/bluetooth/audio/bap.h>
15 #include <zephyr/bluetooth/audio/cap.h>
16 #include <zephyr/bluetooth/conn.h>
17 #include <zephyr/bluetooth/hci_types.h>
18 #include <zephyr/bluetooth/iso.h>
19 #include <zephyr/logging/log.h>
20 #include <zephyr/net/buf.h>
21 #include <zephyr/sys/check.h>
22 #include <zephyr/sys/util.h>
23 #include <zephyr/sys/util_macro.h>
24 
25 #include "cap_internal.h"
26 
27 LOG_MODULE_REGISTER(bt_cap_stream, CONFIG_BT_CAP_STREAM_LOG_LEVEL);
28 
stream_is_central(struct bt_bap_stream * bap_stream)29 static bool stream_is_central(struct bt_bap_stream *bap_stream)
30 {
31 	if (IS_ENABLED(CONFIG_BT_CONN)) {
32 		struct bt_conn_info info;
33 		int err;
34 
35 		if (bap_stream->conn == NULL) {
36 			return false;
37 		}
38 
39 		err = bt_conn_get_info(bap_stream->conn, &info);
40 		if (err == 0 && info.role == BT_HCI_ROLE_CENTRAL) {
41 			return true;
42 		}
43 	}
44 
45 	return false;
46 }
47 
48 #if defined(CONFIG_BT_BAP_UNICAST)
cap_stream_configured_cb(struct bt_bap_stream * bap_stream,const struct bt_audio_codec_qos_pref * pref)49 static void cap_stream_configured_cb(struct bt_bap_stream *bap_stream,
50 				     const struct bt_audio_codec_qos_pref *pref)
51 {
52 	struct bt_cap_stream *cap_stream = CONTAINER_OF(bap_stream,
53 							struct bt_cap_stream,
54 							bap_stream);
55 	struct bt_bap_stream_ops *ops = cap_stream->ops;
56 
57 	LOG_DBG("%p", cap_stream);
58 
59 	if (IS_ENABLED(CONFIG_BT_CAP_INITIATOR) && IS_ENABLED(CONFIG_BT_BAP_UNICAST_CLIENT) &&
60 	    stream_is_central(bap_stream)) {
61 		bt_cap_initiator_codec_configured(cap_stream);
62 	}
63 
64 	if (ops != NULL && ops->configured != NULL) {
65 		ops->configured(bap_stream, pref);
66 	}
67 }
68 
cap_stream_qos_set_cb(struct bt_bap_stream * bap_stream)69 static void cap_stream_qos_set_cb(struct bt_bap_stream *bap_stream)
70 {
71 	struct bt_cap_stream *cap_stream = CONTAINER_OF(bap_stream,
72 							struct bt_cap_stream,
73 							bap_stream);
74 	struct bt_bap_stream_ops *ops = cap_stream->ops;
75 
76 	LOG_DBG("%p", cap_stream);
77 
78 	if (IS_ENABLED(CONFIG_BT_CAP_INITIATOR) && IS_ENABLED(CONFIG_BT_BAP_UNICAST_CLIENT) &&
79 	    stream_is_central(bap_stream)) {
80 		bt_cap_initiator_qos_configured(cap_stream);
81 	}
82 
83 	if (ops != NULL && ops->qos_set != NULL) {
84 		ops->qos_set(bap_stream);
85 	}
86 }
87 
cap_stream_enabled_cb(struct bt_bap_stream * bap_stream)88 static void cap_stream_enabled_cb(struct bt_bap_stream *bap_stream)
89 {
90 	struct bt_cap_stream *cap_stream = CONTAINER_OF(bap_stream,
91 							struct bt_cap_stream,
92 							bap_stream);
93 	struct bt_bap_stream_ops *ops = cap_stream->ops;
94 
95 	LOG_DBG("%p", cap_stream);
96 
97 	if (IS_ENABLED(CONFIG_BT_CAP_INITIATOR) && IS_ENABLED(CONFIG_BT_BAP_UNICAST_CLIENT) &&
98 	    stream_is_central(bap_stream)) {
99 		bt_cap_initiator_enabled(cap_stream);
100 	}
101 
102 	if (ops != NULL && ops->enabled != NULL) {
103 		ops->enabled(bap_stream);
104 	}
105 }
106 
cap_stream_metadata_updated_cb(struct bt_bap_stream * bap_stream)107 static void cap_stream_metadata_updated_cb(struct bt_bap_stream *bap_stream)
108 {
109 	struct bt_cap_stream *cap_stream = CONTAINER_OF(bap_stream,
110 							struct bt_cap_stream,
111 							bap_stream);
112 	struct bt_bap_stream_ops *ops = cap_stream->ops;
113 
114 	LOG_DBG("%p", cap_stream);
115 
116 	if (IS_ENABLED(CONFIG_BT_CAP_INITIATOR) && IS_ENABLED(CONFIG_BT_BAP_UNICAST_CLIENT) &&
117 	    stream_is_central(bap_stream)) {
118 		bt_cap_initiator_metadata_updated(cap_stream);
119 	}
120 
121 	if (ops != NULL && ops->metadata_updated != NULL) {
122 		ops->metadata_updated(bap_stream);
123 	}
124 }
125 
cap_stream_disabled_cb(struct bt_bap_stream * bap_stream)126 static void cap_stream_disabled_cb(struct bt_bap_stream *bap_stream)
127 {
128 	struct bt_cap_stream *cap_stream = CONTAINER_OF(bap_stream,
129 							struct bt_cap_stream,
130 							bap_stream);
131 	struct bt_bap_stream_ops *ops = cap_stream->ops;
132 
133 	LOG_DBG("%p", cap_stream);
134 
135 	if (ops != NULL && ops->disabled != NULL) {
136 		ops->disabled(bap_stream);
137 	}
138 }
139 
cap_stream_released_cb(struct bt_bap_stream * bap_stream)140 static void cap_stream_released_cb(struct bt_bap_stream *bap_stream)
141 {
142 	struct bt_cap_stream *cap_stream = CONTAINER_OF(bap_stream,
143 							struct bt_cap_stream,
144 							bap_stream);
145 	struct bt_bap_stream_ops *ops = cap_stream->ops;
146 
147 	LOG_DBG("%p", cap_stream);
148 
149 	/* Here we cannot use stream_is_central as bap_stream->conn is NULL, so fall back to
150 	 * a more generic, less accurate check
151 	 */
152 	if (IS_ENABLED(CONFIG_BT_CAP_INITIATOR) && IS_ENABLED(CONFIG_BT_BAP_UNICAST_CLIENT)) {
153 		bt_cap_initiator_released(cap_stream);
154 	}
155 
156 	if (ops != NULL && ops->released != NULL) {
157 		ops->released(bap_stream);
158 	}
159 }
160 
161 #endif /* CONFIG_BT_BAP_UNICAST */
162 
cap_stream_started_cb(struct bt_bap_stream * bap_stream)163 static void cap_stream_started_cb(struct bt_bap_stream *bap_stream)
164 {
165 	struct bt_cap_stream *cap_stream = CONTAINER_OF(bap_stream,
166 							struct bt_cap_stream,
167 							bap_stream);
168 	struct bt_bap_stream_ops *ops = cap_stream->ops;
169 
170 	LOG_DBG("%p", cap_stream);
171 
172 	if (IS_ENABLED(CONFIG_BT_CAP_INITIATOR) && IS_ENABLED(CONFIG_BT_BAP_UNICAST_CLIENT) &&
173 	    stream_is_central(bap_stream)) {
174 		bt_cap_initiator_started(cap_stream);
175 	}
176 
177 	if (ops != NULL && ops->started != NULL) {
178 		ops->started(bap_stream);
179 	}
180 }
181 
cap_stream_stopped_cb(struct bt_bap_stream * bap_stream,uint8_t reason)182 static void cap_stream_stopped_cb(struct bt_bap_stream *bap_stream, uint8_t reason)
183 {
184 	struct bt_cap_stream *cap_stream = CONTAINER_OF(bap_stream,
185 							struct bt_cap_stream,
186 							bap_stream);
187 	struct bt_bap_stream_ops *ops = cap_stream->ops;
188 
189 	LOG_DBG("%p", cap_stream);
190 
191 	if (ops != NULL && ops->stopped != NULL) {
192 		ops->stopped(bap_stream, reason);
193 	}
194 }
195 
196 #if defined(CONFIG_BT_AUDIO_RX)
cap_stream_recv_cb(struct bt_bap_stream * bap_stream,const struct bt_iso_recv_info * info,struct net_buf * buf)197 static void cap_stream_recv_cb(struct bt_bap_stream *bap_stream,
198 			       const struct bt_iso_recv_info *info, struct net_buf *buf)
199 {
200 	struct bt_cap_stream *cap_stream = CONTAINER_OF(bap_stream,
201 							struct bt_cap_stream,
202 							bap_stream);
203 	struct bt_bap_stream_ops *ops = cap_stream->ops;
204 
205 	if (ops != NULL && ops->recv != NULL) {
206 		ops->recv(bap_stream, info, buf);
207 	}
208 }
209 #endif /* CONFIG_BT_AUDIO_RX */
210 
211 #if defined(CONFIG_BT_AUDIO_TX)
cap_stream_sent_cb(struct bt_bap_stream * bap_stream)212 static void cap_stream_sent_cb(struct bt_bap_stream *bap_stream)
213 {
214 	struct bt_cap_stream *cap_stream = CONTAINER_OF(bap_stream,
215 							struct bt_cap_stream,
216 							bap_stream);
217 	struct bt_bap_stream_ops *ops = cap_stream->ops;
218 
219 	if (ops != NULL && ops->sent != NULL) {
220 		ops->sent(bap_stream);
221 	}
222 }
223 #endif /* CONFIG_BT_AUDIO_TX */
224 
cap_stream_connected_cb(struct bt_bap_stream * bap_stream)225 static void cap_stream_connected_cb(struct bt_bap_stream *bap_stream)
226 {
227 	struct bt_cap_stream *cap_stream =
228 		CONTAINER_OF(bap_stream, struct bt_cap_stream, bap_stream);
229 	struct bt_bap_stream_ops *ops = cap_stream->ops;
230 
231 	if (IS_ENABLED(CONFIG_BT_CAP_INITIATOR) && IS_ENABLED(CONFIG_BT_BAP_UNICAST_CLIENT) &&
232 	    stream_is_central(bap_stream)) {
233 		bt_cap_initiator_connected(cap_stream);
234 	}
235 
236 	if (ops != NULL && ops->connected != NULL) {
237 		ops->connected(bap_stream);
238 	}
239 }
240 
cap_stream_disconnected_cb(struct bt_bap_stream * bap_stream,uint8_t reason)241 static void cap_stream_disconnected_cb(struct bt_bap_stream *bap_stream, uint8_t reason)
242 {
243 	struct bt_cap_stream *cap_stream =
244 		CONTAINER_OF(bap_stream, struct bt_cap_stream, bap_stream);
245 	struct bt_bap_stream_ops *ops = cap_stream->ops;
246 
247 	if (ops != NULL && ops->disconnected != NULL) {
248 		ops->disconnected(bap_stream, reason);
249 	}
250 }
251 
252 static struct bt_bap_stream_ops bap_stream_ops = {
253 #if defined(CONFIG_BT_BAP_UNICAST)
254 	.configured = cap_stream_configured_cb,
255 	.qos_set = cap_stream_qos_set_cb,
256 	.enabled = cap_stream_enabled_cb,
257 	.metadata_updated = cap_stream_metadata_updated_cb,
258 	.disabled = cap_stream_disabled_cb,
259 	.released = cap_stream_released_cb,
260 #endif /* CONFIG_BT_BAP_UNICAST */
261 	.started = cap_stream_started_cb,
262 	.stopped = cap_stream_stopped_cb,
263 #if defined(CONFIG_BT_AUDIO_RX)
264 	.recv = cap_stream_recv_cb,
265 #endif /* CONFIG_BT_AUDIO_RX */
266 #if defined(CONFIG_BT_AUDIO_TX)
267 	.sent = cap_stream_sent_cb,
268 #endif /* CONFIG_BT_AUDIO_TX */
269 	.connected = cap_stream_connected_cb,
270 	.disconnected = cap_stream_disconnected_cb,
271 };
272 
bt_cap_stream_ops_register_bap(struct bt_cap_stream * cap_stream)273 void bt_cap_stream_ops_register_bap(struct bt_cap_stream *cap_stream)
274 {
275 	bt_bap_stream_cb_register(&cap_stream->bap_stream, &bap_stream_ops);
276 }
277 
bt_cap_stream_ops_register(struct bt_cap_stream * stream,struct bt_bap_stream_ops * ops)278 void bt_cap_stream_ops_register(struct bt_cap_stream *stream,
279 				struct bt_bap_stream_ops *ops)
280 {
281 	stream->ops = ops;
282 
283 	/* CAP basically just forwards the BAP callbacks after doing what it (CAP) needs to do,
284 	 * so we can just always register the BAP callbacks here
285 	 *
286 	 * It is, however, only the CAP Initiator Unicast that depend on the callbacks being set in
287 	 * order to work, so for the CAP Initiator Unicast we need an additional register to ensure
288 	 * correctness.
289 	 */
290 
291 	bt_cap_stream_ops_register_bap(stream);
292 }
293 
294 #if defined(CONFIG_BT_AUDIO_TX)
bt_cap_stream_send(struct bt_cap_stream * stream,struct net_buf * buf,uint16_t seq_num)295 int bt_cap_stream_send(struct bt_cap_stream *stream, struct net_buf *buf, uint16_t seq_num)
296 {
297 	CHECKIF(stream == NULL) {
298 		LOG_DBG("stream is NULL");
299 
300 		return -EINVAL;
301 	}
302 
303 	return bt_bap_stream_send(&stream->bap_stream, buf, seq_num);
304 }
305 
bt_cap_stream_send_ts(struct bt_cap_stream * stream,struct net_buf * buf,uint16_t seq_num,uint32_t ts)306 int bt_cap_stream_send_ts(struct bt_cap_stream *stream, struct net_buf *buf, uint16_t seq_num,
307 			  uint32_t ts)
308 {
309 	CHECKIF(stream == NULL) {
310 		LOG_DBG("stream is NULL");
311 
312 		return -EINVAL;
313 	}
314 
315 	return bt_bap_stream_send_ts(&stream->bap_stream, buf, seq_num, ts);
316 }
317 
bt_cap_stream_get_tx_sync(struct bt_cap_stream * stream,struct bt_iso_tx_info * info)318 int bt_cap_stream_get_tx_sync(struct bt_cap_stream *stream, struct bt_iso_tx_info *info)
319 {
320 	CHECKIF(stream == NULL) {
321 		LOG_DBG("stream is NULL");
322 
323 		return -EINVAL;
324 	}
325 
326 	return bt_bap_stream_get_tx_sync(&stream->bap_stream, info);
327 }
328 #endif /* CONFIG_BT_AUDIO_TX */
329