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