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_audio_codec_cfg * codec_cfg)66 int bt_bap_unicast_server_reconfig(struct bt_bap_stream *stream,
67 const struct bt_audio_codec_cfg *codec_cfg)
68 {
69 struct bt_bap_ep *ep;
70 struct bt_bap_ascs_rsp rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_SUCCESS,
71 BT_BAP_ASCS_REASON_NONE);
72 int err;
73
74 ep = stream->ep;
75
76 if (unicast_server_cb != NULL &&
77 unicast_server_cb->reconfig != NULL) {
78 err = unicast_server_cb->reconfig(stream, ep->dir, codec_cfg, &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_cfg, codec_cfg, sizeof(*codec_cfg));
88
89 return ascs_ep_set_state(ep, BT_BAP_EP_STATE_CODEC_CONFIGURED);
90 }
91
bt_bap_unicast_server_start(struct bt_bap_stream * stream)92 int bt_bap_unicast_server_start(struct bt_bap_stream *stream)
93 {
94 struct bt_bap_ep *ep = stream->ep;
95
96 if (ep->dir != BT_AUDIO_DIR_SINK) {
97 LOG_DBG("Invalid operation for stream %p with dir %u",
98 stream, ep->dir);
99
100 return -EINVAL;
101 }
102
103 /* If ISO is connected to go streaming state,
104 * else wait for ISO to be connected
105 */
106 if (ep->iso->chan.state == BT_ISO_STATE_CONNECTED) {
107 return ascs_ep_set_state(ep, BT_BAP_EP_STATE_STREAMING);
108 }
109
110 ep->receiver_ready = true;
111
112 return 0;
113 }
114
bt_bap_unicast_server_metadata(struct bt_bap_stream * stream,const uint8_t meta[],size_t meta_len)115 int bt_bap_unicast_server_metadata(struct bt_bap_stream *stream, const uint8_t meta[],
116 size_t meta_len)
117 {
118 struct bt_bap_ep *ep;
119 struct bt_bap_ascs_rsp rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_SUCCESS,
120 BT_BAP_ASCS_REASON_NONE);
121 int err;
122
123 if (meta_len > sizeof(ep->codec_cfg.meta)) {
124 return -ENOMEM;
125 }
126
127 if (unicast_server_cb != NULL && unicast_server_cb->metadata != NULL) {
128 err = unicast_server_cb->metadata(stream, meta, meta_len, &rsp);
129 } else {
130 err = -ENOTSUP;
131 }
132
133
134 if (err) {
135 LOG_ERR("Metadata failed: err %d, code %u, reason %u", err, rsp.code, rsp.reason);
136 return err;
137 }
138
139 ep = stream->ep;
140 (void)memcpy(ep->codec_cfg.meta, meta, meta_len);
141
142 /* Set the state to the same state to trigger the notifications */
143 return ascs_ep_set_state(ep, ep->status.state);
144 }
145
bt_bap_unicast_server_disable(struct bt_bap_stream * stream)146 int bt_bap_unicast_server_disable(struct bt_bap_stream *stream)
147 {
148 return bt_ascs_disable_ase(stream->ep);
149 }
150
bt_bap_unicast_server_release(struct bt_bap_stream * stream)151 int bt_bap_unicast_server_release(struct bt_bap_stream *stream)
152 {
153 return bt_ascs_release_ase(stream->ep);
154 }
155
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_audio_codec_qos_pref * qos_pref)156 int bt_bap_unicast_server_config_ase(struct bt_conn *conn, struct bt_bap_stream *stream,
157 struct bt_audio_codec_cfg *codec_cfg,
158 const struct bt_audio_codec_qos_pref *qos_pref)
159 {
160 return bt_ascs_config_ase(conn, stream, codec_cfg, qos_pref);
161 }
162
bt_bap_unicast_server_foreach_ep(struct bt_conn * conn,bt_bap_ep_func_t func,void * user_data)163 void bt_bap_unicast_server_foreach_ep(struct bt_conn *conn, bt_bap_ep_func_t func, void *user_data)
164 {
165 bt_ascs_foreach_ep(conn, func, user_data);
166 }
167