1 /*  Bluetooth Audio Unicast Server */
2 
3 /*
4  * Copyright (c) 2021-2023 Nordic Semiconductor ASA
5  *
6  * SPDX-License-Identifier: Apache-2.0
7  */
8 
9 #include <zephyr/sys/check.h>
10 
11 #include <zephyr/bluetooth/audio/audio.h>
12 #include <zephyr/bluetooth/audio/bap.h>
13 
14 #include "bap_iso.h"
15 #include "pacs_internal.h"
16 #include "bap_endpoint.h"
17 
18 #include <zephyr/logging/log.h>
19 
20 LOG_MODULE_REGISTER(bt_bap_unicast_server, CONFIG_BT_BAP_UNICAST_SERVER_LOG_LEVEL);
21 
22 static const struct bt_bap_unicast_server_cb *unicast_server_cb;
23 
bt_bap_unicast_server_register_cb(const struct bt_bap_unicast_server_cb * cb)24 int bt_bap_unicast_server_register_cb(const struct bt_bap_unicast_server_cb *cb)
25 {
26 	int err;
27 
28 	CHECKIF(cb == NULL) {
29 		LOG_DBG("cb is NULL");
30 		return -EINVAL;
31 	}
32 
33 	if (unicast_server_cb != NULL) {
34 		LOG_DBG("callback structure already registered");
35 		return -EALREADY;
36 	}
37 
38 	err = bt_ascs_init(cb);
39 	if (err != 0) {
40 		return err;
41 	}
42 
43 	unicast_server_cb = cb;
44 
45 	return 0;
46 }
47 
bt_bap_unicast_server_unregister_cb(const struct bt_bap_unicast_server_cb * cb)48 int bt_bap_unicast_server_unregister_cb(const struct bt_bap_unicast_server_cb *cb)
49 {
50 	CHECKIF(cb == NULL) {
51 		LOG_DBG("cb is NULL");
52 		return -EINVAL;
53 	}
54 
55 	if (unicast_server_cb != cb) {
56 		LOG_DBG("callback structure not registered");
57 		return -EINVAL;
58 	}
59 
60 	bt_ascs_cleanup();
61 	unicast_server_cb = NULL;
62 
63 	return 0;
64 }
65 
bt_bap_unicast_server_reconfig(struct bt_bap_stream * stream,const struct bt_codec * codec)66 int bt_bap_unicast_server_reconfig(struct bt_bap_stream *stream, const struct bt_codec *codec)
67 {
68 	struct bt_bap_ep *ep;
69 	struct bt_bap_ascs_rsp rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_SUCCESS,
70 						     BT_BAP_ASCS_REASON_NONE);
71 	int err;
72 
73 	ep = stream->ep;
74 
75 	if (unicast_server_cb != NULL &&
76 		unicast_server_cb->reconfig != NULL) {
77 		err = unicast_server_cb->reconfig(stream, ep->dir, codec,
78 						  &ep->qos_pref, &rsp);
79 	} else {
80 		err = -ENOTSUP;
81 	}
82 
83 	if (err != 0) {
84 		return err;
85 	}
86 
87 	(void)memcpy(&ep->codec, &codec, sizeof(codec));
88 
89 	ascs_ep_set_state(ep, BT_BAP_EP_STATE_CODEC_CONFIGURED);
90 
91 	return 0;
92 }
93 
bt_bap_unicast_server_start(struct bt_bap_stream * stream)94 int bt_bap_unicast_server_start(struct bt_bap_stream *stream)
95 {
96 	struct bt_bap_ep *ep = stream->ep;
97 
98 	if (ep->dir != BT_AUDIO_DIR_SINK) {
99 		LOG_DBG("Invalid operation for stream %p with dir %u",
100 			stream, ep->dir);
101 
102 		return -EINVAL;
103 	}
104 
105 	/* If ISO is connected to go streaming state,
106 	 * else wait for ISO to be connected
107 	 */
108 	if (ep->iso->chan.state == BT_ISO_STATE_CONNECTED) {
109 		ascs_ep_set_state(ep, BT_BAP_EP_STATE_STREAMING);
110 	} else {
111 		ep->receiver_ready = true;
112 	}
113 
114 	return 0;
115 }
116 
bt_bap_unicast_server_metadata(struct bt_bap_stream * stream,struct bt_codec_data meta[],size_t meta_count)117 int bt_bap_unicast_server_metadata(struct bt_bap_stream *stream, struct bt_codec_data meta[],
118 				   size_t meta_count)
119 {
120 	struct bt_bap_ep *ep;
121 	struct bt_bap_ascs_rsp rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_SUCCESS,
122 						     BT_BAP_ASCS_REASON_NONE);
123 	int err;
124 
125 
126 	if (unicast_server_cb != NULL && unicast_server_cb->metadata != NULL) {
127 		err = unicast_server_cb->metadata(stream, meta, meta_count, &rsp);
128 	} else {
129 		err = -ENOTSUP;
130 	}
131 
132 	ep = stream->ep;
133 	for (size_t i = 0U; i < meta_count; i++) {
134 		(void)memcpy(&ep->codec.meta[i], &meta[i],
135 			     sizeof(ep->codec.meta[i]));
136 	}
137 
138 	if (err) {
139 		LOG_ERR("Metadata failed: err %d, code %u, reason %u", err, rsp.code, rsp.reason);
140 		return err;
141 	}
142 
143 	/* Set the state to the same state to trigger the notifications */
144 	ascs_ep_set_state(ep, ep->status.state);
145 
146 	return 0;
147 }
148 
bt_bap_unicast_server_disable(struct bt_bap_stream * stream)149 int bt_bap_unicast_server_disable(struct bt_bap_stream *stream)
150 {
151 	struct bt_bap_ep *ep;
152 	struct bt_bap_ascs_rsp rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_SUCCESS,
153 						     BT_BAP_ASCS_REASON_NONE);
154 	int err;
155 
156 	if (unicast_server_cb != NULL && unicast_server_cb->disable != NULL) {
157 		err = unicast_server_cb->disable(stream, &rsp);
158 	} else {
159 		err = -ENOTSUP;
160 	}
161 
162 	if (err != 0) {
163 		LOG_ERR("Disable failed: err %d, code %u, reason %u", err, rsp.code, rsp.reason);
164 		return err;
165 	}
166 
167 	ep = stream->ep;
168 
169 	/* The ASE state machine goes into different states from this operation
170 	 * based on whether it is a source or a sink ASE.
171 	 */
172 	if (ep->dir == BT_AUDIO_DIR_SOURCE) {
173 		ascs_ep_set_state(ep, BT_BAP_EP_STATE_DISABLING);
174 	} else {
175 		ascs_ep_set_state(ep, BT_BAP_EP_STATE_QOS_CONFIGURED);
176 	}
177 
178 	return 0;
179 }
180 
bt_bap_unicast_server_release(struct bt_bap_stream * stream)181 int bt_bap_unicast_server_release(struct bt_bap_stream *stream)
182 {
183 	struct bt_bap_ascs_rsp rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_SUCCESS,
184 						     BT_BAP_ASCS_REASON_NONE);
185 	int err;
186 
187 	if (unicast_server_cb != NULL && unicast_server_cb->release != NULL) {
188 		err = unicast_server_cb->release(stream, &rsp);
189 	} else {
190 		err = -ENOTSUP;
191 	}
192 
193 	if (err != 0) {
194 		LOG_ERR("Release failed: err %d, code %u, reason %u", err, rsp.code, rsp.reason);
195 		return err;
196 	}
197 
198 	/* ase_process will set the state to IDLE after sending the
199 	 * notification, finalizing the release
200 	 */
201 	ascs_ep_set_state(stream->ep, BT_BAP_EP_STATE_RELEASING);
202 
203 	return 0;
204 }
205 
bt_bap_unicast_server_config_ase(struct bt_conn * conn,struct bt_bap_stream * stream,struct bt_codec * codec,const struct bt_codec_qos_pref * qos_pref)206 int bt_bap_unicast_server_config_ase(struct bt_conn *conn, struct bt_bap_stream *stream,
207 				     struct bt_codec *codec,
208 				     const struct bt_codec_qos_pref *qos_pref)
209 {
210 	return bt_ascs_config_ase(conn, stream, codec, qos_pref);
211 }
212 
bt_bap_unicast_server_foreach_ep(struct bt_conn * conn,bt_bap_ep_func_t func,void * user_data)213 void bt_bap_unicast_server_foreach_ep(struct bt_conn *conn, bt_bap_ep_func_t func, void *user_data)
214 {
215 	bt_ascs_foreach_ep(conn, func, user_data);
216 }
217