1 /*
2  * Copyright (c) 2022-2023 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/bluetooth/audio/cap.h>
8 #include <zephyr/sys/check.h>
9 
10 #include "cap_internal.h"
11 
12 #include <zephyr/logging/log.h>
13 
14 LOG_MODULE_REGISTER(bt_cap_stream, CONFIG_BT_CAP_STREAM_LOG_LEVEL);
15 
16 #if defined(CONFIG_BT_BAP_UNICAST)
cap_stream_configured_cb(struct bt_bap_stream * bap_stream,const struct bt_audio_codec_qos_pref * pref)17 static void cap_stream_configured_cb(struct bt_bap_stream *bap_stream,
18 				     const struct bt_audio_codec_qos_pref *pref)
19 {
20 	struct bt_cap_stream *cap_stream = CONTAINER_OF(bap_stream,
21 							struct bt_cap_stream,
22 							bap_stream);
23 	struct bt_bap_stream_ops *ops = cap_stream->ops;
24 
25 	LOG_DBG("%p", cap_stream);
26 
27 	if (IS_ENABLED(CONFIG_BT_CAP_INITIATOR)) {
28 		bt_cap_initiator_codec_configured(cap_stream);
29 	}
30 
31 	if (ops != NULL && ops->configured != NULL) {
32 		ops->configured(bap_stream, pref);
33 	}
34 }
35 
cap_stream_qos_set_cb(struct bt_bap_stream * bap_stream)36 static void cap_stream_qos_set_cb(struct bt_bap_stream *bap_stream)
37 {
38 	struct bt_cap_stream *cap_stream = CONTAINER_OF(bap_stream,
39 							struct bt_cap_stream,
40 							bap_stream);
41 	struct bt_bap_stream_ops *ops = cap_stream->ops;
42 
43 	LOG_DBG("%p", cap_stream);
44 
45 	if (IS_ENABLED(CONFIG_BT_CAP_INITIATOR)) {
46 		bt_cap_initiator_qos_configured(cap_stream);
47 	}
48 
49 	if (ops != NULL && ops->qos_set != NULL) {
50 		ops->qos_set(bap_stream);
51 	}
52 }
53 
cap_stream_enabled_cb(struct bt_bap_stream * bap_stream)54 static void cap_stream_enabled_cb(struct bt_bap_stream *bap_stream)
55 {
56 	struct bt_cap_stream *cap_stream = CONTAINER_OF(bap_stream,
57 							struct bt_cap_stream,
58 							bap_stream);
59 	struct bt_bap_stream_ops *ops = cap_stream->ops;
60 
61 	LOG_DBG("%p", cap_stream);
62 
63 	if (IS_ENABLED(CONFIG_BT_CAP_INITIATOR)) {
64 		bt_cap_initiator_enabled(cap_stream);
65 	}
66 
67 	if (ops != NULL && ops->enabled != NULL) {
68 		ops->enabled(bap_stream);
69 	}
70 }
71 
cap_stream_metadata_updated_cb(struct bt_bap_stream * bap_stream)72 static void cap_stream_metadata_updated_cb(struct bt_bap_stream *bap_stream)
73 {
74 	struct bt_cap_stream *cap_stream = CONTAINER_OF(bap_stream,
75 							struct bt_cap_stream,
76 							bap_stream);
77 	struct bt_bap_stream_ops *ops = cap_stream->ops;
78 
79 	LOG_DBG("%p", cap_stream);
80 
81 	if (IS_ENABLED(CONFIG_BT_CAP_INITIATOR)) {
82 		bt_cap_initiator_metadata_updated(cap_stream);
83 	}
84 
85 	if (ops != NULL && ops->metadata_updated != NULL) {
86 		ops->metadata_updated(bap_stream);
87 	}
88 }
89 
cap_stream_disabled_cb(struct bt_bap_stream * bap_stream)90 static void cap_stream_disabled_cb(struct bt_bap_stream *bap_stream)
91 {
92 	struct bt_cap_stream *cap_stream = CONTAINER_OF(bap_stream,
93 							struct bt_cap_stream,
94 							bap_stream);
95 	struct bt_bap_stream_ops *ops = cap_stream->ops;
96 
97 	LOG_DBG("%p", cap_stream);
98 
99 	if (ops != NULL && ops->disabled != NULL) {
100 		ops->disabled(bap_stream);
101 	}
102 }
103 
cap_stream_released_cb(struct bt_bap_stream * bap_stream)104 static void cap_stream_released_cb(struct bt_bap_stream *bap_stream)
105 {
106 	struct bt_cap_stream *cap_stream = CONTAINER_OF(bap_stream,
107 							struct bt_cap_stream,
108 							bap_stream);
109 	struct bt_bap_stream_ops *ops = cap_stream->ops;
110 
111 	LOG_DBG("%p", cap_stream);
112 
113 	if (IS_ENABLED(CONFIG_BT_CAP_INITIATOR)) {
114 		bt_cap_initiator_released(cap_stream);
115 	}
116 
117 	if (ops != NULL && ops->released != NULL) {
118 		ops->released(bap_stream);
119 	}
120 }
121 
122 #endif /* CONFIG_BT_BAP_UNICAST */
123 
cap_stream_started_cb(struct bt_bap_stream * bap_stream)124 static void cap_stream_started_cb(struct bt_bap_stream *bap_stream)
125 {
126 	struct bt_cap_stream *cap_stream = CONTAINER_OF(bap_stream,
127 							struct bt_cap_stream,
128 							bap_stream);
129 	struct bt_bap_stream_ops *ops = cap_stream->ops;
130 
131 	LOG_DBG("%p", cap_stream);
132 
133 	if (IS_ENABLED(CONFIG_BT_CAP_INITIATOR) && IS_ENABLED(CONFIG_BT_BAP_UNICAST)) {
134 		bt_cap_initiator_started(cap_stream);
135 	}
136 
137 	if (ops != NULL && ops->started != NULL) {
138 		ops->started(bap_stream);
139 	}
140 }
141 
cap_stream_stopped_cb(struct bt_bap_stream * bap_stream,uint8_t reason)142 static void cap_stream_stopped_cb(struct bt_bap_stream *bap_stream, uint8_t reason)
143 {
144 	struct bt_cap_stream *cap_stream = CONTAINER_OF(bap_stream,
145 							struct bt_cap_stream,
146 							bap_stream);
147 	struct bt_bap_stream_ops *ops = cap_stream->ops;
148 
149 	LOG_DBG("%p", cap_stream);
150 
151 	if (ops != NULL && ops->stopped != NULL) {
152 		ops->stopped(bap_stream, reason);
153 	}
154 }
155 
156 #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)157 static void cap_stream_recv_cb(struct bt_bap_stream *bap_stream,
158 			       const struct bt_iso_recv_info *info, struct net_buf *buf)
159 {
160 	struct bt_cap_stream *cap_stream = CONTAINER_OF(bap_stream,
161 							struct bt_cap_stream,
162 							bap_stream);
163 	struct bt_bap_stream_ops *ops = cap_stream->ops;
164 
165 	if (ops != NULL && ops->recv != NULL) {
166 		ops->recv(bap_stream, info, buf);
167 	}
168 }
169 #endif /* CONFIG_BT_AUDIO_RX */
170 
171 #if defined(CONFIG_BT_AUDIO_TX)
cap_stream_sent_cb(struct bt_bap_stream * bap_stream)172 static void cap_stream_sent_cb(struct bt_bap_stream *bap_stream)
173 {
174 	struct bt_cap_stream *cap_stream = CONTAINER_OF(bap_stream,
175 							struct bt_cap_stream,
176 							bap_stream);
177 	struct bt_bap_stream_ops *ops = cap_stream->ops;
178 
179 	if (ops != NULL && ops->sent != NULL) {
180 		ops->sent(bap_stream);
181 	}
182 }
183 #endif /* CONFIG_BT_AUDIO_TX */
184 
185 static struct bt_bap_stream_ops bap_stream_ops = {
186 #if defined(CONFIG_BT_BAP_UNICAST)
187 	.configured = cap_stream_configured_cb,
188 	.qos_set = cap_stream_qos_set_cb,
189 	.enabled = cap_stream_enabled_cb,
190 	.metadata_updated = cap_stream_metadata_updated_cb,
191 	.disabled = cap_stream_disabled_cb,
192 	.released = cap_stream_released_cb,
193 #endif /* CONFIG_BT_BAP_UNICAST */
194 	.started = cap_stream_started_cb,
195 	.stopped = cap_stream_stopped_cb,
196 #if defined(CONFIG_BT_AUDIO_RX)
197 	.recv = cap_stream_recv_cb,
198 #endif /* CONFIG_BT_AUDIO_RX */
199 #if defined(CONFIG_BT_AUDIO_TX)
200 	.sent = cap_stream_sent_cb,
201 #endif /* CONFIG_BT_AUDIO_TX */
202 };
203 
bt_cap_stream_ops_register_bap(struct bt_cap_stream * cap_stream)204 void bt_cap_stream_ops_register_bap(struct bt_cap_stream *cap_stream)
205 {
206 	bt_bap_stream_cb_register(&cap_stream->bap_stream, &bap_stream_ops);
207 }
208 
bt_cap_stream_ops_register(struct bt_cap_stream * stream,struct bt_bap_stream_ops * ops)209 void bt_cap_stream_ops_register(struct bt_cap_stream *stream,
210 				struct bt_bap_stream_ops *ops)
211 {
212 	stream->ops = ops;
213 
214 	/* CAP basically just forwards the BAP callbacks after doing what it (CAP) needs to do,
215 	 * so we can just always register the BAP callbacks here
216 	 *
217 	 * It is, however, only the CAP Initiator Unicast that depend on the callbacks being set in
218 	 * order to work, so for the CAP Initiator Unicast we need an additional register to ensure
219 	 * correctness.
220 	 */
221 
222 	bt_cap_stream_ops_register_bap(stream);
223 }
224 
225 #if defined(CONFIG_BT_AUDIO_TX)
bt_cap_stream_send(struct bt_cap_stream * stream,struct net_buf * buf,uint16_t seq_num,uint32_t ts)226 int bt_cap_stream_send(struct bt_cap_stream *stream, struct net_buf *buf, uint16_t seq_num,
227 		       uint32_t ts)
228 {
229 	CHECKIF(stream == NULL) {
230 		LOG_DBG("stream is NULL");
231 
232 		return -EINVAL;
233 	}
234 
235 	return bt_bap_stream_send(&stream->bap_stream, buf, seq_num, ts);
236 }
237 
bt_cap_stream_get_tx_sync(struct bt_cap_stream * stream,struct bt_iso_tx_info * info)238 int bt_cap_stream_get_tx_sync(struct bt_cap_stream *stream, struct bt_iso_tx_info *info)
239 {
240 	CHECKIF(stream == NULL) {
241 		LOG_DBG("stream is NULL");
242 
243 		return -EINVAL;
244 	}
245 
246 	return bt_bap_stream_get_tx_sync(&stream->bap_stream, info);
247 }
248 #endif /* CONFIG_BT_AUDIO_TX */
249