1 /*  Bluetooth Audio Unicast Server */
2 
3 /*
4  * Copyright (c) 2021-2023 Nordic Semiconductor ASA
5  * Copyright (c) 2024 Demant A/S
6  *
7  * SPDX-License-Identifier: Apache-2.0
8  */
9 #include <errno.h>
10 #include <stdbool.h>
11 #include <stddef.h>
12 #include <stdint.h>
13 #include <string.h>
14 
15 #include <zephyr/autoconf.h>
16 #include <zephyr/bluetooth/audio/audio.h>
17 #include <zephyr/bluetooth/audio/bap.h>
18 #include <zephyr/bluetooth/conn.h>
19 #include <zephyr/bluetooth/iso.h>
20 #include <zephyr/logging/log.h>
21 #include <zephyr/sys/check.h>
22 
23 #include "ascs_internal.h"
24 #include "bap_iso.h"
25 #include "bap_endpoint.h"
26 #include "pacs_internal.h"
27 
28 LOG_MODULE_REGISTER(bt_bap_unicast_server, CONFIG_BT_BAP_UNICAST_SERVER_LOG_LEVEL);
29 
30 static const struct bt_bap_unicast_server_cb *unicast_server_cb;
31 
bt_bap_unicast_server_register(const struct bt_bap_unicast_server_register_param * param)32 int bt_bap_unicast_server_register(const struct bt_bap_unicast_server_register_param *param)
33 {
34 	if (param == NULL) {
35 		LOG_DBG("param is NULL");
36 		return -EINVAL;
37 	}
38 
39 	return bt_ascs_register(param->snk_cnt, param->src_cnt);
40 }
41 
bt_bap_unicast_server_unregister(void)42 int bt_bap_unicast_server_unregister(void)
43 {
44 	if (unicast_server_cb != NULL) {
45 		LOG_DBG("Callbacks are still registered");
46 		return -EAGAIN;
47 	}
48 
49 	return bt_ascs_unregister();
50 }
51 
bt_bap_unicast_server_register_cb(const struct bt_bap_unicast_server_cb * cb)52 int bt_bap_unicast_server_register_cb(const struct bt_bap_unicast_server_cb *cb)
53 {
54 	int err;
55 
56 	CHECKIF(cb == NULL) {
57 		LOG_DBG("cb is NULL");
58 		return -EINVAL;
59 	}
60 
61 	if (unicast_server_cb != NULL) {
62 		LOG_DBG("callback structure already registered");
63 		return -EALREADY;
64 	}
65 
66 	err = bt_ascs_init(cb);
67 	if (err != 0) {
68 		return err;
69 	}
70 
71 	unicast_server_cb = cb;
72 
73 	return 0;
74 }
75 
bt_bap_unicast_server_unregister_cb(const struct bt_bap_unicast_server_cb * cb)76 int bt_bap_unicast_server_unregister_cb(const struct bt_bap_unicast_server_cb *cb)
77 {
78 	if (unicast_server_cb == NULL) {
79 		LOG_DBG("no callback is registered");
80 		return -EALREADY;
81 	}
82 
83 	if (cb == NULL) {
84 		LOG_DBG("cb is NULL");
85 		return -EINVAL;
86 	}
87 
88 	if (unicast_server_cb != cb) {
89 		LOG_DBG("callback structure not registered");
90 		return -EINVAL;
91 	}
92 
93 	bt_ascs_cleanup();
94 	unicast_server_cb = NULL;
95 
96 	return 0;
97 }
98 
bt_bap_unicast_server_reconfig(struct bt_bap_stream * stream,const struct bt_audio_codec_cfg * codec_cfg)99 int bt_bap_unicast_server_reconfig(struct bt_bap_stream *stream,
100 				   const struct bt_audio_codec_cfg *codec_cfg)
101 {
102 	struct bt_bap_ep *ep;
103 	struct bt_bap_ascs_rsp rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_SUCCESS,
104 						     BT_BAP_ASCS_REASON_NONE);
105 	int err;
106 
107 	ep = stream->ep;
108 
109 	if (unicast_server_cb != NULL &&
110 		unicast_server_cb->reconfig != NULL) {
111 		err = unicast_server_cb->reconfig(stream, ep->dir, codec_cfg, &ep->qos_pref, &rsp);
112 	} else {
113 		err = -ENOTSUP;
114 	}
115 
116 	if (err != 0) {
117 		return err;
118 	}
119 
120 	(void)memcpy(&ep->codec_cfg, codec_cfg, sizeof(*codec_cfg));
121 
122 	return ascs_ep_set_state(ep, BT_BAP_EP_STATE_CODEC_CONFIGURED);
123 }
124 
bt_bap_unicast_server_start(struct bt_bap_stream * stream)125 int bt_bap_unicast_server_start(struct bt_bap_stream *stream)
126 {
127 	struct bt_bap_ep *ep = stream->ep;
128 
129 	if (ep->dir != BT_AUDIO_DIR_SINK) {
130 		LOG_DBG("Invalid operation for stream %p with dir %u",
131 			stream, ep->dir);
132 
133 		return -EINVAL;
134 	}
135 
136 	/* If ISO is connected to go streaming state,
137 	 * else wait for ISO to be connected
138 	 */
139 	if (ep->iso->chan.state == BT_ISO_STATE_CONNECTED) {
140 		return ascs_ep_set_state(ep, BT_BAP_EP_STATE_STREAMING);
141 	}
142 
143 	ep->receiver_ready = true;
144 
145 	return 0;
146 }
147 
bt_bap_unicast_server_metadata(struct bt_bap_stream * stream,const uint8_t meta[],size_t meta_len)148 int bt_bap_unicast_server_metadata(struct bt_bap_stream *stream, const uint8_t meta[],
149 				   size_t meta_len)
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 (meta_len > sizeof(ep->codec_cfg.meta)) {
157 		return -ENOMEM;
158 	}
159 
160 	if (unicast_server_cb != NULL && unicast_server_cb->metadata != NULL) {
161 		err = unicast_server_cb->metadata(stream, meta, meta_len, &rsp);
162 	} else {
163 		err = -ENOTSUP;
164 	}
165 
166 
167 	if (err) {
168 		LOG_ERR("Metadata failed: err %d, code %u, reason %u", err, rsp.code, rsp.reason);
169 		return err;
170 	}
171 
172 	ep = stream->ep;
173 	(void)memcpy(ep->codec_cfg.meta, meta, meta_len);
174 
175 	/* Set the state to the same state to trigger the notifications */
176 	return ascs_ep_set_state(ep, ep->status.state);
177 }
178 
bt_bap_unicast_server_disable(struct bt_bap_stream * stream)179 int bt_bap_unicast_server_disable(struct bt_bap_stream *stream)
180 {
181 	return bt_ascs_disable_ase(stream->ep);
182 }
183 
bt_bap_unicast_server_release(struct bt_bap_stream * stream)184 int bt_bap_unicast_server_release(struct bt_bap_stream *stream)
185 {
186 	return bt_ascs_release_ase(stream->ep);
187 }
188 
bt_bap_unicast_server_config_ase(struct bt_conn * conn,struct bt_bap_stream * stream,struct bt_audio_codec_cfg * codec_cfg,const struct bt_bap_qos_cfg_pref * qos_pref)189 int bt_bap_unicast_server_config_ase(struct bt_conn *conn, struct bt_bap_stream *stream,
190 				     struct bt_audio_codec_cfg *codec_cfg,
191 				     const struct bt_bap_qos_cfg_pref *qos_pref)
192 {
193 	return bt_ascs_config_ase(conn, stream, codec_cfg, qos_pref);
194 }
195 
bt_bap_unicast_server_foreach_ep(struct bt_conn * conn,bt_bap_ep_func_t func,void * user_data)196 void bt_bap_unicast_server_foreach_ep(struct bt_conn *conn, bt_bap_ep_func_t func, void *user_data)
197 {
198 	bt_ascs_foreach_ep(conn, func, user_data);
199 }
200