1 /* Bluetooth MICS
2 *
3 * Copyright (c) 2020 Bose Corporation
4 * Copyright (c) 2020-2022 Nordic Semiconductor ASA
5 *
6 * SPDX-License-Identifier: Apache-2.0
7 */
8
9 #include <errno.h>
10 #include <stdbool.h>
11 #include <stddef.h>
12 #include <stdint.h>
13 #include <sys/types.h>
14
15 #include <zephyr/autoconf.h>
16 #include <zephyr/bluetooth/att.h>
17 #include <zephyr/bluetooth/bluetooth.h>
18 #include <zephyr/bluetooth/conn.h>
19 #include <zephyr/bluetooth/gatt.h>
20 #include <zephyr/bluetooth/audio/micp.h>
21 #include <zephyr/bluetooth/audio/aics.h>
22 #include <zephyr/bluetooth/uuid.h>
23 #include <zephyr/device.h>
24 #include <zephyr/init.h>
25 #include <zephyr/kernel.h>
26 #include <zephyr/logging/log.h>
27 #include <zephyr/sys/__assert.h>
28 #include <zephyr/sys/byteorder.h>
29 #include <zephyr/sys/check.h>
30 #include <zephyr/sys/util.h>
31 #include <zephyr/sys/util_macro.h>
32
33 #include "audio_internal.h"
34
35 LOG_MODULE_REGISTER(bt_micp, CONFIG_BT_MICP_MIC_DEV_LOG_LEVEL);
36
37 struct bt_micp_server {
38 uint8_t mute;
39 struct bt_micp_mic_dev_cb *cb;
40 struct bt_gatt_service *service_p;
41 struct bt_aics *aics_insts[CONFIG_BT_MICP_MIC_DEV_AICS_INSTANCE_COUNT];
42 struct k_work_delayable notify_work;
43 };
44
45 static struct bt_micp_server micp_inst;
46
mute_cfg_changed(const struct bt_gatt_attr * attr,uint16_t value)47 static void mute_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value)
48 {
49 LOG_DBG("value 0x%04x", value);
50 }
51
read_mute(struct bt_conn * conn,const struct bt_gatt_attr * attr,void * buf,uint16_t len,uint16_t offset)52 static ssize_t read_mute(struct bt_conn *conn,
53 const struct bt_gatt_attr *attr, void *buf,
54 uint16_t len, uint16_t offset)
55 {
56 LOG_DBG("Mute %u", micp_inst.mute);
57
58 return bt_gatt_attr_read(conn, attr, buf, len, offset,
59 &micp_inst.mute, sizeof(micp_inst.mute));
60 }
61
notify_work_handler(struct k_work * work)62 static void notify_work_handler(struct k_work *work)
63 {
64 struct k_work_delayable *d_work = k_work_delayable_from_work(work);
65 struct bt_micp_server *server = CONTAINER_OF(d_work, struct bt_micp_server, notify_work);
66 int err;
67
68 err = bt_gatt_notify_uuid(NULL, BT_UUID_MICS_MUTE, server->service_p->attrs, &server->mute,
69 sizeof(server->mute));
70 if (err == 0 || err == -ENOTCONN) {
71 return;
72 }
73
74 if (err == -ENOMEM &&
75 k_work_reschedule(d_work, K_USEC(BT_AUDIO_NOTIFY_RETRY_DELAY_US)) >= 0) {
76 LOG_WRN("Out of buffers for mute state notification. Will retry in %dms",
77 BT_AUDIO_NOTIFY_RETRY_DELAY_US);
78 return;
79 }
80
81 LOG_ERR("Mute state notification err %d", err);
82 }
83
write_mute(struct bt_conn * conn,const struct bt_gatt_attr * attr,const void * buf,uint16_t len,uint16_t offset,uint8_t flags)84 static ssize_t write_mute(struct bt_conn *conn, const struct bt_gatt_attr *attr,
85 const void *buf, uint16_t len, uint16_t offset,
86 uint8_t flags)
87 {
88 const uint8_t *val = buf;
89
90 if (offset > 0) {
91 return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET);
92 }
93
94 if (len != sizeof(micp_inst.mute)) {
95 return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN);
96 }
97
98 if ((conn != NULL && *val == BT_MICP_MUTE_DISABLED) ||
99 *val > BT_MICP_MUTE_DISABLED) {
100 return BT_GATT_ERR(BT_ATT_ERR_VALUE_NOT_ALLOWED);
101 }
102
103 if (conn != NULL && micp_inst.mute == BT_MICP_MUTE_DISABLED) {
104 return BT_GATT_ERR(BT_MICP_ERR_MUTE_DISABLED);
105 }
106
107 LOG_DBG("%u", *val);
108
109 if (*val != micp_inst.mute) {
110 int err;
111
112 micp_inst.mute = *val;
113
114 err = k_work_reschedule(&micp_inst.notify_work, K_NO_WAIT);
115 if (err < 0) {
116 LOG_ERR("Failed to schedule mute state notification err %d", err);
117 }
118
119 if (micp_inst.cb != NULL && micp_inst.cb->mute != NULL) {
120 micp_inst.cb->mute(micp_inst.mute);
121 }
122 }
123
124 return len;
125 }
126
127
128 #define DUMMY_INCLUDE(i, _) BT_GATT_INCLUDE_SERVICE(NULL),
129 #define AICS_INCLUDES(cnt) LISTIFY(cnt, DUMMY_INCLUDE, ())
130
131 #define BT_MICP_SERVICE_DEFINITION \
132 BT_GATT_PRIMARY_SERVICE(BT_UUID_MICS), \
133 AICS_INCLUDES(CONFIG_BT_MICP_MIC_DEV_AICS_INSTANCE_COUNT) \
134 BT_AUDIO_CHRC(BT_UUID_MICS_MUTE, \
135 BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE | BT_GATT_CHRC_NOTIFY, \
136 BT_GATT_PERM_READ_ENCRYPT | BT_GATT_PERM_WRITE_ENCRYPT, \
137 read_mute, write_mute, NULL), \
138 BT_AUDIO_CCC(mute_cfg_changed)
139
140 #define MICS_ATTR_COUNT \
141 ARRAY_SIZE(((struct bt_gatt_attr []){ BT_MICP_SERVICE_DEFINITION }))
142 #define MICS_INCL_COUNT (CONFIG_BT_MICP_MIC_DEV_AICS_INSTANCE_COUNT)
143
144 static struct bt_gatt_attr mics_attrs[] = { BT_MICP_SERVICE_DEFINITION };
145 static struct bt_gatt_service mics_svc;
146
147 #if defined(CONFIG_BT_MICP_MIC_DEV_AICS)
prepare_aics_inst(struct bt_micp_mic_dev_register_param * param)148 static int prepare_aics_inst(struct bt_micp_mic_dev_register_param *param)
149 {
150 int i;
151 int j;
152 int err;
153
154 if (CONFIG_BT_MICP_MIC_DEV_AICS_INSTANCE_COUNT == 0) {
155 return 0;
156 }
157
158 for (j = 0, i = 0; i < ARRAY_SIZE(mics_attrs); i++) {
159 if (bt_uuid_cmp(mics_attrs[i].uuid, BT_UUID_GATT_INCLUDE) == 0) {
160 micp_inst.aics_insts[j] = bt_aics_free_instance_get();
161 if (micp_inst.aics_insts[j] == NULL) {
162 LOG_DBG("Could not get free AICS instances[%u]", j);
163 return -ENOMEM;
164 }
165
166 err = bt_aics_register(micp_inst.aics_insts[j],
167 ¶m->aics_param[j]);
168 if (err != 0) {
169 LOG_DBG("Could not register AICS instance[%u]: %d", j, err);
170 return err;
171 }
172
173 mics_attrs[i].user_data = bt_aics_svc_decl_get(micp_inst.aics_insts[j]);
174 j++;
175
176 if (j == CONFIG_BT_MICP_MIC_DEV_AICS_INSTANCE_COUNT) {
177 break;
178 }
179 }
180 }
181
182 __ASSERT(j == CONFIG_BT_MICP_MIC_DEV_AICS_INSTANCE_COUNT,
183 "Invalid AICS instance count");
184
185 return 0;
186 }
187 #endif /* CONFIG_BT_MICP_MIC_DEV_AICS */
188
189 /****************************** PUBLIC API ******************************/
bt_micp_mic_dev_register(struct bt_micp_mic_dev_register_param * param)190 int bt_micp_mic_dev_register(struct bt_micp_mic_dev_register_param *param)
191 {
192 int err;
193 static bool registered;
194
195 if (registered) {
196 return -EALREADY;
197 }
198
199 __ASSERT(param, "MICS register parameter cannot be NULL");
200
201 #if defined(CONFIG_BT_MICP_MIC_DEV_AICS)
202 err = prepare_aics_inst(param);
203 if (err != 0) {
204 LOG_DBG("Failed to prepare AICS instances: %d", err);
205
206 return err;
207 }
208 #endif /* CONFIG_BT_MICP_MIC_DEV_AICS */
209
210 mics_svc = (struct bt_gatt_service)BT_GATT_SERVICE(mics_attrs);
211 micp_inst.service_p = &mics_svc;
212 err = bt_gatt_service_register(&mics_svc);
213
214 if (err != 0) {
215 LOG_ERR("MICS service register failed: %d", err);
216 }
217
218 micp_inst.cb = param->cb;
219
220 k_work_init_delayable(&micp_inst.notify_work, notify_work_handler);
221
222 registered = true;
223
224 return err;
225 }
226
bt_micp_mic_dev_mute_disable(void)227 int bt_micp_mic_dev_mute_disable(void)
228 {
229 uint8_t val = BT_MICP_MUTE_DISABLED;
230 int err;
231
232 err = write_mute(NULL, NULL, &val, sizeof(val), 0, 0);
233
234 return err > 0 ? 0 : err;
235 }
236
bt_micp_mic_dev_included_get(struct bt_micp_included * included)237 int bt_micp_mic_dev_included_get(struct bt_micp_included *included)
238 {
239 CHECKIF(included == NULL) {
240 LOG_DBG("NULL service pointer");
241 return -EINVAL;
242 }
243
244 #if defined(CONFIG_BT_MICP_MIC_DEV_AICS)
245 included->aics_cnt = ARRAY_SIZE(micp_inst.aics_insts);
246 included->aics = micp_inst.aics_insts;
247 #endif /* CONFIG_BT_MICP_MIC_DEV_AICS */
248
249 return 0;
250 }
251
bt_micp_mic_dev_unmute(void)252 int bt_micp_mic_dev_unmute(void)
253 {
254 const uint8_t val = BT_MICP_MUTE_UNMUTED;
255 const int err = write_mute(NULL, NULL, &val, sizeof(val), 0, 0);
256
257 return err > 0 ? 0 : err;
258 }
259
bt_micp_mic_dev_mute(void)260 int bt_micp_mic_dev_mute(void)
261 {
262 const uint8_t val = BT_MICP_MUTE_MUTED;
263 const int err = write_mute(NULL, NULL, &val, sizeof(val), 0, 0);
264
265 return err > 0 ? 0 : err;
266 }
267
bt_micp_mic_dev_mute_get(void)268 int bt_micp_mic_dev_mute_get(void)
269 {
270 if (micp_inst.cb && micp_inst.cb->mute) {
271 micp_inst.cb->mute(micp_inst.mute);
272 }
273
274 return 0;
275 }
276