1 /*
2  * Copyright (c) 2020 Bose Corporation
3  * Copyright (c) 2020 Nordic Semiconductor ASA
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 #include <zephyr/kernel.h>
9 #include <zephyr/sys/byteorder.h>
10 #include <zephyr/sys/check.h>
11 
12 #include <zephyr/device.h>
13 #include <zephyr/init.h>
14 
15 #include <zephyr/bluetooth/bluetooth.h>
16 #include <zephyr/bluetooth/conn.h>
17 #include <zephyr/bluetooth/gatt.h>
18 #include <zephyr/bluetooth/audio/aics.h>
19 
20 #include "aics_internal.h"
21 #include "audio_internal.h"
22 
23 #define LOG_LEVEL CONFIG_BT_AICS_LOG_LEVEL
24 #include <zephyr/logging/log.h>
25 LOG_MODULE_REGISTER(bt_aics);
26 
27 #define VALID_AICS_OPCODE(opcode)                                              \
28 	((opcode) >= BT_AICS_OPCODE_SET_GAIN && (opcode) <= BT_AICS_OPCODE_SET_AUTO)
29 
30 #define AICS_CP_LEN                 0x02
31 #define AICS_CP_SET_GAIN_LEN        0x03
32 
33 
34 static ssize_t write_description(struct bt_conn *conn,
35 				 const struct bt_gatt_attr *attr,
36 				 const void *buf, uint16_t len, uint16_t offset,
37 				 uint8_t flags);
38 
39 static ssize_t write_aics_control(struct bt_conn *conn,
40 				  const struct bt_gatt_attr *attr,
41 				  const void *buf, uint16_t len,
42 				  uint16_t offset, uint8_t flags);
43 
44 #if defined(CONFIG_BT_AICS)
45 static void aics_state_cfg_changed(const struct bt_gatt_attr *attr,
46 				   uint16_t value);
47 static ssize_t read_aics_state(struct bt_conn *conn,
48 			       const struct bt_gatt_attr *attr,
49 			       void *buf, uint16_t len, uint16_t offset);
50 static ssize_t read_aics_gain_settings(struct bt_conn *conn,
51 				       const struct bt_gatt_attr *attr,
52 				       void *buf, uint16_t len,
53 				       uint16_t offset);
54 static ssize_t read_type(struct bt_conn *conn, const struct bt_gatt_attr *attr,
55 			 void *buf, uint16_t len, uint16_t offset);
56 static void aics_input_status_cfg_changed(const struct bt_gatt_attr *attr,
57 					  uint16_t value);
58 static ssize_t read_input_status(struct bt_conn *conn,
59 				 const struct bt_gatt_attr *attr,
60 				 void *buf, uint16_t len, uint16_t offset);
61 static void aics_description_cfg_changed(const struct bt_gatt_attr *attr,
62 					 uint16_t value);
63 static ssize_t read_description(struct bt_conn *conn,
64 				const struct bt_gatt_attr *attr, void *buf,
65 				uint16_t len, uint16_t offset);
66 
67 #define BT_AICS_SERVICE_DEFINITION(_aics) {                                    \
68 	BT_GATT_SECONDARY_SERVICE(BT_UUID_AICS),                               \
69 	BT_AUDIO_CHRC(BT_UUID_AICS_STATE,                                      \
70 		      BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY,                 \
71 		      BT_GATT_PERM_READ_ENCRYPT,                               \
72 		      read_aics_state, NULL, &_aics),                          \
73 	BT_AUDIO_CCC(aics_state_cfg_changed),                                  \
74 	BT_AUDIO_CHRC(BT_UUID_AICS_GAIN_SETTINGS,                              \
75 		      BT_GATT_CHRC_READ,                                       \
76 		      BT_GATT_PERM_READ_ENCRYPT,                               \
77 		      read_aics_gain_settings, NULL, &_aics),                  \
78 	BT_AUDIO_CHRC(BT_UUID_AICS_INPUT_TYPE,                                 \
79 		      BT_GATT_CHRC_READ,                                       \
80 		      BT_GATT_PERM_READ_ENCRYPT,                               \
81 		      read_type, NULL, &_aics),                                \
82 	BT_AUDIO_CHRC(BT_UUID_AICS_INPUT_STATUS,                               \
83 		      BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY,                 \
84 		      BT_GATT_PERM_READ_ENCRYPT,                               \
85 		      read_input_status, NULL, &_aics),                        \
86 	BT_AUDIO_CCC(aics_input_status_cfg_changed),                           \
87 	BT_AUDIO_CHRC(BT_UUID_AICS_CONTROL,                                    \
88 		      BT_GATT_CHRC_WRITE,                                      \
89 		      BT_GATT_PERM_WRITE_ENCRYPT,                              \
90 		      NULL, write_aics_control, &_aics),                       \
91 	BT_AUDIO_CHRC(BT_UUID_AICS_DESCRIPTION,                                \
92 		      BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY,                 \
93 		      BT_GATT_PERM_READ_ENCRYPT,                               \
94 		      read_description, write_description, &_aics),            \
95 	BT_AUDIO_CCC(aics_description_cfg_changed)                             \
96 	}
97 
98 
99 static struct bt_aics aics_insts[CONFIG_BT_AICS_MAX_INSTANCE_COUNT];
100 static uint32_t instance_cnt;
101 BT_GATT_SERVICE_INSTANCE_DEFINE(aics_service_list, aics_insts,
102 				CONFIG_BT_AICS_MAX_INSTANCE_COUNT,
103 				BT_AICS_SERVICE_DEFINITION);
104 
aics_state_cfg_changed(const struct bt_gatt_attr * attr,uint16_t value)105 static void aics_state_cfg_changed(const struct bt_gatt_attr *attr,
106 				   uint16_t value)
107 {
108 	LOG_DBG("value 0x%04x", value);
109 }
110 
read_aics_state(struct bt_conn * conn,const struct bt_gatt_attr * attr,void * buf,uint16_t len,uint16_t offset)111 static ssize_t read_aics_state(struct bt_conn *conn,
112 			       const struct bt_gatt_attr *attr, void *buf,
113 			       uint16_t len, uint16_t offset)
114 {
115 	struct bt_aics *inst = BT_AUDIO_CHRC_USER_DATA(attr);
116 
117 	LOG_DBG("gain %d, mute %u, gain_mode %u, counter %u", inst->srv.state.gain,
118 		inst->srv.state.mute, inst->srv.state.gain_mode, inst->srv.state.change_counter);
119 
120 	return bt_gatt_attr_read(conn, attr, buf, len, offset, &inst->srv.state,
121 				 sizeof(inst->srv.state));
122 }
123 
read_aics_gain_settings(struct bt_conn * conn,const struct bt_gatt_attr * attr,void * buf,uint16_t len,uint16_t offset)124 static ssize_t read_aics_gain_settings(struct bt_conn *conn,
125 				       const struct bt_gatt_attr *attr,
126 				       void *buf, uint16_t len, uint16_t offset)
127 {
128 	struct bt_aics *inst = BT_AUDIO_CHRC_USER_DATA(attr);
129 
130 	LOG_DBG("units %u, min %d, max %d", inst->srv.gain_settings.units,
131 		inst->srv.gain_settings.minimum, inst->srv.gain_settings.maximum);
132 
133 	return bt_gatt_attr_read(conn, attr, buf, len, offset,
134 				 &inst->srv.gain_settings,
135 				 sizeof(inst->srv.gain_settings));
136 }
137 
read_type(struct bt_conn * conn,const struct bt_gatt_attr * attr,void * buf,uint16_t len,uint16_t offset)138 static ssize_t read_type(struct bt_conn *conn, const struct bt_gatt_attr *attr,
139 			 void *buf, uint16_t len, uint16_t offset)
140 {
141 	struct bt_aics *inst = BT_AUDIO_CHRC_USER_DATA(attr);
142 
143 	LOG_DBG("%u", inst->srv.type);
144 
145 	return bt_gatt_attr_read(conn, attr, buf, len, offset, &inst->srv.type,
146 				 sizeof(inst->srv.type));
147 }
148 
aics_input_status_cfg_changed(const struct bt_gatt_attr * attr,uint16_t value)149 static void aics_input_status_cfg_changed(const struct bt_gatt_attr *attr,
150 					  uint16_t value)
151 {
152 	LOG_DBG("value 0x%04x", value);
153 }
154 
read_input_status(struct bt_conn * conn,const struct bt_gatt_attr * attr,void * buf,uint16_t len,uint16_t offset)155 static ssize_t read_input_status(struct bt_conn *conn,
156 				 const struct bt_gatt_attr *attr, void *buf,
157 				 uint16_t len, uint16_t offset)
158 {
159 	struct bt_aics *inst = BT_AUDIO_CHRC_USER_DATA(attr);
160 
161 	LOG_DBG("%u", inst->srv.status);
162 
163 	return bt_gatt_attr_read(conn, attr, buf, len, offset, &inst->srv.status,
164 				 sizeof(inst->srv.status));
165 }
166 
167 #endif /* CONFIG_BT_AICS */
168 
write_aics_control(struct bt_conn * conn,const struct bt_gatt_attr * attr,const void * buf,uint16_t len,uint16_t offset,uint8_t flags)169 static ssize_t write_aics_control(struct bt_conn *conn,
170 				  const struct bt_gatt_attr *attr,
171 				  const void *buf, uint16_t len,
172 				  uint16_t offset, uint8_t flags)
173 {
174 	struct bt_aics *inst = BT_AUDIO_CHRC_USER_DATA(attr);
175 	const struct bt_aics_gain_control *cp = buf;
176 	bool notify = false;
177 
178 	if (offset) {
179 		return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET);
180 	}
181 
182 	if (!len || !buf) {
183 		return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN);
184 	}
185 
186 	/* Check opcode before length */
187 	if (!VALID_AICS_OPCODE(cp->cp.opcode)) {
188 		LOG_DBG("Invalid opcode %u", cp->cp.opcode);
189 		return BT_GATT_ERR(BT_AICS_ERR_OP_NOT_SUPPORTED);
190 	}
191 
192 	if ((len < AICS_CP_LEN) ||
193 	    (len == AICS_CP_SET_GAIN_LEN && cp->cp.opcode != BT_AICS_OPCODE_SET_GAIN) ||
194 	    (len > AICS_CP_SET_GAIN_LEN)) {
195 		return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN);
196 	}
197 
198 	LOG_DBG("Opcode %u, counter %u", cp->cp.opcode, cp->cp.counter);
199 	if (cp->cp.counter != inst->srv.state.change_counter) {
200 		return BT_GATT_ERR(BT_AICS_ERR_INVALID_COUNTER);
201 	}
202 
203 	switch (cp->cp.opcode) {
204 	case BT_AICS_OPCODE_SET_GAIN:
205 		LOG_DBG("Set gain %d", cp->gain_setting);
206 		if (cp->gain_setting < inst->srv.gain_settings.minimum ||
207 		    cp->gain_setting > inst->srv.gain_settings.maximum) {
208 			return BT_GATT_ERR(BT_AICS_ERR_OUT_OF_RANGE);
209 		}
210 		if (BT_AICS_INPUT_MODE_SETTABLE(inst->srv.state.gain_mode) &&
211 		    inst->srv.state.gain != cp->gain_setting) {
212 			inst->srv.state.gain = cp->gain_setting;
213 			notify = true;
214 		}
215 		break;
216 	case BT_AICS_OPCODE_UNMUTE:
217 		LOG_DBG("Unmute");
218 		if (inst->srv.state.mute == BT_AICS_STATE_MUTE_DISABLED) {
219 			return BT_GATT_ERR(BT_AICS_ERR_MUTE_DISABLED);
220 		}
221 		if (inst->srv.state.mute != BT_AICS_STATE_UNMUTED) {
222 			inst->srv.state.mute = BT_AICS_STATE_UNMUTED;
223 			notify = true;
224 		}
225 		break;
226 	case BT_AICS_OPCODE_MUTE:
227 		LOG_DBG("Mute");
228 		if (inst->srv.state.mute == BT_AICS_STATE_MUTE_DISABLED) {
229 			return BT_GATT_ERR(BT_AICS_ERR_MUTE_DISABLED);
230 		}
231 		if (inst->srv.state.mute != BT_AICS_STATE_MUTED) {
232 			inst->srv.state.mute = BT_AICS_STATE_MUTED;
233 			notify = true;
234 		}
235 		break;
236 	case BT_AICS_OPCODE_SET_MANUAL:
237 		LOG_DBG("Set manual mode");
238 		if (BT_AICS_INPUT_MODE_IMMUTABLE(inst->srv.state.gain_mode)) {
239 			return BT_GATT_ERR(BT_AICS_ERR_GAIN_MODE_NOT_ALLOWED);
240 		}
241 		if (inst->srv.state.gain_mode != BT_AICS_MODE_MANUAL) {
242 			inst->srv.state.gain_mode = BT_AICS_MODE_MANUAL;
243 			notify = true;
244 		}
245 		break;
246 	case BT_AICS_OPCODE_SET_AUTO:
247 		LOG_DBG("Set automatic mode");
248 		if (BT_AICS_INPUT_MODE_IMMUTABLE(inst->srv.state.gain_mode)) {
249 			return BT_GATT_ERR(BT_AICS_ERR_GAIN_MODE_NOT_ALLOWED);
250 		}
251 		if (inst->srv.state.gain_mode != BT_AICS_MODE_AUTO) {
252 			inst->srv.state.gain_mode = BT_AICS_MODE_AUTO;
253 			notify = true;
254 		}
255 		break;
256 	default:
257 		return BT_GATT_ERR(BT_AICS_ERR_OP_NOT_SUPPORTED);
258 	}
259 
260 	if (notify) {
261 		inst->srv.state.change_counter++;
262 
263 		LOG_DBG("New state: gain %d, mute %u, gain_mode %u, counter %u",
264 			inst->srv.state.gain, inst->srv.state.mute, inst->srv.state.gain_mode,
265 			inst->srv.state.change_counter);
266 
267 		bt_gatt_notify_uuid(NULL, BT_UUID_AICS_STATE,
268 				    inst->srv.service_p->attrs, &inst->srv.state,
269 				    sizeof(inst->srv.state));
270 
271 		if (inst->srv.cb && inst->srv.cb->state) {
272 			inst->srv.cb->state(inst, 0, inst->srv.state.gain,
273 					inst->srv.state.mute,
274 					inst->srv.state.gain_mode);
275 		} else {
276 			LOG_DBG("Callback not registered for instance %p", inst);
277 		}
278 	}
279 
280 	return len;
281 }
282 
283 #if defined(CONFIG_BT_AICS)
aics_description_cfg_changed(const struct bt_gatt_attr * attr,uint16_t value)284 static void aics_description_cfg_changed(const struct bt_gatt_attr *attr,
285 					 uint16_t value)
286 {
287 	LOG_DBG("value 0x%04x", value);
288 }
289 #endif /* CONFIG_BT_AICS */
290 
write_description(struct bt_conn * conn,const struct bt_gatt_attr * attr,const void * buf,uint16_t len,uint16_t offset,uint8_t flags)291 static ssize_t write_description(struct bt_conn *conn,
292 				 const struct bt_gatt_attr *attr,
293 				 const void *buf, uint16_t len, uint16_t offset,
294 				 uint8_t flags)
295 {
296 	struct bt_aics *inst = BT_AUDIO_CHRC_USER_DATA(attr);
297 
298 	if (len >= sizeof(inst->srv.description)) {
299 		LOG_DBG("Output desc was clipped from length %u to %zu", len,
300 			sizeof(inst->srv.description) - 1);
301 		/* We just clip the string value if it's too long */
302 		len = (uint16_t)sizeof(inst->srv.description) - 1;
303 	}
304 
305 	if (memcmp(buf, inst->srv.description, len)) {
306 		memcpy(inst->srv.description, buf, len);
307 		inst->srv.description[len] = '\0';
308 
309 		bt_gatt_notify_uuid(NULL, BT_UUID_AICS_DESCRIPTION,
310 				    inst->srv.service_p->attrs, &inst->srv.description,
311 				    strlen(inst->srv.description));
312 
313 		if (inst->srv.cb && inst->srv.cb->description) {
314 			inst->srv.cb->description(inst, 0,
315 						  inst->srv.description);
316 		} else {
317 			LOG_DBG("Callback not registered for instance %p", inst);
318 		}
319 	}
320 
321 	LOG_DBG("%s", inst->srv.description);
322 
323 	return len;
324 }
325 
aics_write(struct bt_aics * inst,ssize_t (* write)(struct bt_conn * conn,const struct bt_gatt_attr * attr,const void * buf,uint16_t len,uint16_t offset,uint8_t flags),const void * buf,uint16_t len)326 static int aics_write(struct bt_aics *inst,
327 		      ssize_t (*write)(struct bt_conn *conn,
328 				       const struct bt_gatt_attr *attr,
329 				       const void *buf, uint16_t len,
330 				       uint16_t offset, uint8_t flags),
331 		      const void *buf, uint16_t len)
332 {
333 	struct bt_audio_attr_user_data user_data = {
334 		.user_data = inst,
335 	};
336 	struct bt_gatt_attr attr = {
337 		.user_data = &user_data,
338 	};
339 	int err;
340 
341 	err = write(NULL, &attr, buf, len, 0, 0);
342 	if (err < 0) {
343 		return err;
344 	}
345 
346 	return 0;
347 }
348 
349 #if defined(CONFIG_BT_AICS)
read_description(struct bt_conn * conn,const struct bt_gatt_attr * attr,void * buf,uint16_t len,uint16_t offset)350 static ssize_t read_description(struct bt_conn *conn,
351 				const struct bt_gatt_attr *attr, void *buf,
352 				uint16_t len, uint16_t offset)
353 {
354 	struct bt_aics *inst = BT_AUDIO_CHRC_USER_DATA(attr);
355 
356 	LOG_DBG("%s", inst->srv.description);
357 
358 	return bt_gatt_attr_read(conn, attr, buf, len, offset,
359 				 &inst->srv.description, strlen(inst->srv.description));
360 }
361 
362 /************************ PUBLIC API ************************/
bt_aics_svc_decl_get(struct bt_aics * aics)363 void *bt_aics_svc_decl_get(struct bt_aics *aics)
364 {
365 	CHECKIF(!aics) {
366 		LOG_DBG("NULL instance");
367 		return NULL;
368 	}
369 
370 	return aics->srv.service_p->attrs;
371 }
372 
prepare_aics_instances(void)373 static void prepare_aics_instances(void)
374 {
375 	for (int i = 0; i < ARRAY_SIZE(aics_insts); i++) {
376 		aics_insts[i].srv.service_p = &aics_service_list[i];
377 	}
378 }
379 
bt_aics_register(struct bt_aics * aics,struct bt_aics_register_param * param)380 int bt_aics_register(struct bt_aics *aics, struct bt_aics_register_param *param)
381 {
382 	int err;
383 	static bool instance_prepared;
384 
385 	CHECKIF(!aics) {
386 		LOG_DBG("NULL aics pointer");
387 		return -ENOTCONN;
388 	}
389 
390 	CHECKIF(!param) {
391 		LOG_DBG("NULL param");
392 		return -EINVAL;
393 	}
394 
395 	if (!instance_prepared) {
396 		prepare_aics_instances();
397 		instance_prepared = true;
398 	}
399 
400 	CHECKIF(aics->srv.initialized) {
401 		return -EALREADY;
402 	}
403 
404 	CHECKIF(param->mute > BT_AICS_STATE_MUTE_DISABLED) {
405 		LOG_DBG("Invalid AICS mute value: %u", param->mute);
406 		return -EINVAL;
407 	}
408 
409 	CHECKIF(param->gain_mode > BT_AICS_MODE_AUTO) {
410 		LOG_DBG("Invalid AICS mode value: %u", param->gain_mode);
411 		return -EINVAL;
412 	}
413 
414 	CHECKIF(param->type > BT_AICS_INPUT_TYPE_STREAMING) {
415 		LOG_DBG("Invalid AICS input type value: %u", param->type);
416 		return -EINVAL;
417 	}
418 
419 	CHECKIF(param->units == 0) {
420 		LOG_DBG("AICS units value shall not be 0");
421 		return -EINVAL;
422 	}
423 
424 	CHECKIF(!(param->min_gain <= param->max_gain)) {
425 		LOG_DBG("AICS min gain (%d) shall be lower than or equal to max gain (%d)",
426 			param->min_gain, param->max_gain);
427 		return -EINVAL;
428 	}
429 
430 	CHECKIF(param->gain < param->min_gain || param->gain > param->max_gain) {
431 		LOG_DBG("AICS gain (%d) shall be not lower than min gain (%d) "
432 		       "or higher than max gain (%d)",
433 		       param->gain, param->min_gain, param->max_gain);
434 		return -EINVAL;
435 	}
436 
437 	aics->srv.state.gain = param->gain;
438 	aics->srv.state.mute = param->mute;
439 	aics->srv.state.gain_mode = param->gain_mode;
440 	aics->srv.gain_settings.units = param->units;
441 	aics->srv.gain_settings.minimum = param->min_gain;
442 	aics->srv.gain_settings.maximum = param->max_gain;
443 	aics->srv.type = param->type;
444 	aics->srv.status = param->status ? BT_AICS_STATUS_ACTIVE : BT_AICS_STATUS_INACTIVE;
445 	aics->srv.cb = param->cb;
446 
447 	if (param->description) {
448 		strncpy(aics->srv.description, param->description,
449 			sizeof(aics->srv.description) - 1);
450 		/* strncpy may not always null-terminate */
451 		aics->srv.description[sizeof(aics->srv.description) - 1] = '\0';
452 		if (IS_ENABLED(CONFIG_BT_AICS_LOG_LEVEL_DBG) &&
453 		    strcmp(aics->srv.description, param->description)) {
454 			LOG_DBG("Input desc clipped to %s", aics->srv.description);
455 		}
456 	}
457 
458 	/* Iterate over the attributes in AICS (starting from i = 1 to skip the
459 	 * service declaration) to find the BT_UUID_AICS_DESCRIPTION and update
460 	 * the characteristic value (at [i]), update that with the write
461 	 * permission and callback, and also update the characteristic
462 	 * declaration (always found at [i - 1]) with the
463 	 * BT_GATT_CHRC_WRITE_WITHOUT_RESP property.
464 	 */
465 	if (param->desc_writable) {
466 		for (int i = 1; i < aics->srv.service_p->attr_count; i++) {
467 			struct bt_gatt_attr *attr;
468 
469 			attr = &aics->srv.service_p->attrs[i];
470 
471 			if (!bt_uuid_cmp(attr->uuid, BT_UUID_AICS_DESCRIPTION)) {
472 				/* Update attr and chrc to be writable */
473 				struct bt_gatt_chrc *chrc;
474 
475 				chrc = aics->srv.service_p->attrs[i - 1].user_data;
476 				attr->perm |= BT_GATT_PERM_WRITE_ENCRYPT;
477 				chrc->properties |= BT_GATT_CHRC_WRITE_WITHOUT_RESP;
478 
479 				break;
480 			}
481 		}
482 	}
483 
484 	err = bt_gatt_service_register(aics->srv.service_p);
485 	if (err) {
486 		LOG_DBG("Could not register AICS service");
487 		return err;
488 	}
489 
490 	aics->srv.initialized = true;
491 
492 	return 0;
493 }
494 
bt_aics_free_instance_get(void)495 struct bt_aics *bt_aics_free_instance_get(void)
496 {
497 	if (instance_cnt >= CONFIG_BT_AICS_MAX_INSTANCE_COUNT) {
498 		return NULL;
499 	}
500 
501 	return (struct bt_aics *)&aics_insts[instance_cnt++];
502 }
503 
504 /****************************** PUBLIC API ******************************/
bt_aics_deactivate(struct bt_aics * inst)505 int bt_aics_deactivate(struct bt_aics *inst)
506 {
507 	CHECKIF(!inst) {
508 		LOG_DBG("NULL instance");
509 		return -EINVAL;
510 	}
511 
512 	if (IS_ENABLED(CONFIG_BT_AICS_CLIENT) && inst->client_instance) {
513 		return -ENOTSUP;
514 	}
515 
516 	if (inst->srv.status == BT_AICS_STATUS_ACTIVE) {
517 		inst->srv.status = BT_AICS_STATUS_INACTIVE;
518 		LOG_DBG("Instance %p: Status was set to inactive", inst);
519 
520 		bt_gatt_notify_uuid(NULL, BT_UUID_AICS_INPUT_STATUS,
521 				    inst->srv.service_p->attrs,
522 				    &inst->srv.status,
523 				    sizeof(inst->srv.status));
524 
525 		if (inst->srv.cb && inst->srv.cb->status) {
526 			inst->srv.cb->status(inst, 0, inst->srv.status);
527 		} else {
528 			LOG_DBG("Callback not registered for instance %p", inst);
529 		}
530 	}
531 
532 	return 0;
533 }
534 
bt_aics_activate(struct bt_aics * inst)535 int bt_aics_activate(struct bt_aics *inst)
536 {
537 	CHECKIF(!inst) {
538 		LOG_DBG("NULL instance");
539 		return -EINVAL;
540 	}
541 
542 	if (IS_ENABLED(CONFIG_BT_AICS_CLIENT) && inst->client_instance) {
543 		return -ENOTSUP;
544 	}
545 
546 	if (inst->srv.status == BT_AICS_STATUS_INACTIVE) {
547 		inst->srv.status = BT_AICS_STATUS_ACTIVE;
548 		LOG_DBG("Instance %p: Status was set to active", inst);
549 
550 		bt_gatt_notify_uuid(NULL, BT_UUID_AICS_INPUT_STATUS,
551 				    inst->srv.service_p->attrs,
552 				    &inst->srv.status,
553 				    sizeof(inst->srv.status));
554 
555 		if (inst->srv.cb && inst->srv.cb->status) {
556 			inst->srv.cb->status(inst, 0, inst->srv.status);
557 		} else {
558 			LOG_DBG("Callback not registered for instance %p", inst);
559 		}
560 	}
561 
562 	return 0;
563 }
564 
565 #endif /* CONFIG_BT_AICS */
bt_aics_gain_set_manual_only(struct bt_aics * inst)566 int bt_aics_gain_set_manual_only(struct bt_aics *inst)
567 {
568 	CHECKIF(!inst) {
569 		LOG_DBG("NULL instance");
570 		return -EINVAL;
571 	}
572 
573 	inst->srv.state.gain_mode = BT_AICS_MODE_MANUAL_ONLY;
574 
575 	bt_gatt_notify_uuid(NULL, BT_UUID_AICS_STATE, inst->srv.service_p->attrs,
576 			    &inst->srv.state, sizeof(inst->srv.state));
577 
578 	return 0;
579 }
580 
bt_aics_gain_set_auto_only(struct bt_aics * inst)581 int bt_aics_gain_set_auto_only(struct bt_aics *inst)
582 {
583 	CHECKIF(!inst) {
584 		LOG_DBG("NULL instance");
585 		return -EINVAL;
586 	}
587 
588 	inst->srv.state.gain_mode = BT_AICS_MODE_AUTO_ONLY;
589 
590 	bt_gatt_notify_uuid(NULL, BT_UUID_AICS_STATE, inst->srv.service_p->attrs,
591 			    &inst->srv.state, sizeof(inst->srv.state));
592 
593 	return 0;
594 }
595 
bt_aics_state_get(struct bt_aics * inst)596 int bt_aics_state_get(struct bt_aics *inst)
597 {
598 	CHECKIF(!inst) {
599 		LOG_DBG("NULL instance");
600 		return -EINVAL;
601 	}
602 
603 	if (IS_ENABLED(CONFIG_BT_AICS_CLIENT) && inst->client_instance) {
604 		return bt_aics_client_state_get(inst);
605 	} else if (IS_ENABLED(CONFIG_BT_AICS) && !inst->client_instance) {
606 		if (inst->srv.cb && inst->srv.cb->state) {
607 			inst->srv.cb->state(inst, 0, inst->srv.state.gain,
608 					    inst->srv.state.mute,
609 					    inst->srv.state.gain_mode);
610 		} else {
611 			LOG_DBG("Callback not registered for instance %p", inst);
612 		}
613 		return 0;
614 	}
615 
616 	return -ENOTSUP;
617 }
618 
bt_aics_gain_setting_get(struct bt_aics * inst)619 int bt_aics_gain_setting_get(struct bt_aics *inst)
620 {
621 	CHECKIF(!inst) {
622 		LOG_DBG("NULL instance");
623 		return -EINVAL;
624 	}
625 
626 	if (IS_ENABLED(CONFIG_BT_AICS_CLIENT) && inst->client_instance) {
627 		return bt_aics_client_gain_setting_get(inst);
628 	} else if (IS_ENABLED(CONFIG_BT_AICS) && !inst->client_instance) {
629 		if (inst->srv.cb && inst->srv.cb->gain_setting) {
630 			inst->srv.cb->gain_setting(inst, 0,
631 						   inst->srv.gain_settings.units,
632 						   inst->srv.gain_settings.minimum,
633 						   inst->srv.gain_settings.maximum);
634 		} else {
635 			LOG_DBG("Callback not registered for instance %p", inst);
636 		}
637 		return 0;
638 	}
639 
640 	return -ENOTSUP;
641 }
642 
bt_aics_type_get(struct bt_aics * inst)643 int bt_aics_type_get(struct bt_aics *inst)
644 {
645 	CHECKIF(!inst) {
646 		LOG_DBG("NULL instance");
647 		return -EINVAL;
648 	}
649 
650 	if (IS_ENABLED(CONFIG_BT_AICS_CLIENT) && inst->client_instance) {
651 		return bt_aics_client_type_get(inst);
652 	} else if (IS_ENABLED(CONFIG_BT_AICS) && !inst->client_instance) {
653 		if (inst->srv.cb && inst->srv.cb->type) {
654 			inst->srv.cb->type(inst, 0, inst->srv.type);
655 		} else {
656 			LOG_DBG("Callback not registered for instance %p", inst);
657 		}
658 		return 0;
659 	}
660 
661 	return -ENOTSUP;
662 }
663 
bt_aics_status_get(struct bt_aics * inst)664 int bt_aics_status_get(struct bt_aics *inst)
665 {
666 	CHECKIF(!inst) {
667 		LOG_DBG("NULL instance");
668 		return -EINVAL;
669 	}
670 
671 	if (IS_ENABLED(CONFIG_BT_AICS_CLIENT) && inst->client_instance) {
672 		return bt_aics_client_status_get(inst);
673 	} else if (IS_ENABLED(CONFIG_BT_AICS) && !inst->client_instance) {
674 		if (inst->srv.cb && inst->srv.cb->status) {
675 			inst->srv.cb->status(inst, 0, inst->srv.status);
676 		} else {
677 			LOG_DBG("Callback not registered for instance %p", inst);
678 		}
679 		return 0;
680 	}
681 
682 	return -ENOTSUP;
683 }
684 
bt_aics_disable_mute(struct bt_aics * inst)685 int bt_aics_disable_mute(struct bt_aics *inst)
686 {
687 	CHECKIF(!inst) {
688 		LOG_DBG("NULL instance");
689 		return -EINVAL;
690 	}
691 
692 	inst->srv.state.mute = BT_AICS_STATE_MUTE_DISABLED;
693 
694 	bt_gatt_notify_uuid(NULL, BT_UUID_AICS_STATE, inst->srv.service_p->attrs,
695 			    &inst->srv.state, sizeof(inst->srv.state));
696 
697 	return 0;
698 }
699 
bt_aics_unmute(struct bt_aics * inst)700 int bt_aics_unmute(struct bt_aics *inst)
701 {
702 	CHECKIF(!inst) {
703 		LOG_DBG("NULL instance");
704 		return -EINVAL;
705 	}
706 
707 	if (IS_ENABLED(CONFIG_BT_AICS_CLIENT) && inst->client_instance) {
708 		return bt_aics_client_unmute(inst);
709 	} else if (IS_ENABLED(CONFIG_BT_AICS) && !inst->client_instance) {
710 		struct bt_aics_control cp;
711 
712 		cp.opcode = BT_AICS_OPCODE_UNMUTE;
713 		cp.counter = inst->srv.state.change_counter;
714 
715 		return aics_write(inst, write_aics_control, &cp, sizeof(cp));
716 	}
717 
718 	return -ENOTSUP;
719 }
720 
bt_aics_mute(struct bt_aics * inst)721 int bt_aics_mute(struct bt_aics *inst)
722 {
723 	CHECKIF(!inst) {
724 		LOG_DBG("NULL instance");
725 		return -EINVAL;
726 	}
727 
728 	if (IS_ENABLED(CONFIG_BT_AICS_CLIENT) && inst->client_instance) {
729 		return bt_aics_client_mute(inst);
730 	} else if (IS_ENABLED(CONFIG_BT_AICS) && !inst->client_instance) {
731 		struct bt_aics_control cp;
732 
733 		cp.opcode = BT_AICS_OPCODE_MUTE;
734 		cp.counter = inst->srv.state.change_counter;
735 
736 		return aics_write(inst, write_aics_control, &cp, sizeof(cp));
737 	}
738 
739 	return -ENOTSUP;
740 }
741 
bt_aics_manual_gain_set(struct bt_aics * inst)742 int bt_aics_manual_gain_set(struct bt_aics *inst)
743 {
744 	CHECKIF(!inst) {
745 		LOG_DBG("NULL instance");
746 		return -EINVAL;
747 	}
748 
749 	if (IS_ENABLED(CONFIG_BT_AICS_CLIENT) && inst->client_instance) {
750 		return bt_aics_client_manual_gain_set(inst);
751 	} else if (IS_ENABLED(CONFIG_BT_AICS) && !inst->client_instance) {
752 		struct bt_aics_control cp;
753 
754 		cp.opcode = BT_AICS_OPCODE_SET_MANUAL;
755 		cp.counter = inst->srv.state.change_counter;
756 
757 		return aics_write(inst, write_aics_control, &cp, sizeof(cp));
758 	}
759 
760 	return -ENOTSUP;
761 }
762 
bt_aics_automatic_gain_set(struct bt_aics * inst)763 int bt_aics_automatic_gain_set(struct bt_aics *inst)
764 {
765 	CHECKIF(!inst) {
766 		LOG_DBG("NULL instance");
767 		return -EINVAL;
768 	}
769 
770 	if (IS_ENABLED(CONFIG_BT_AICS_CLIENT) && inst->client_instance) {
771 		return bt_aics_client_automatic_gain_set(inst);
772 	} else if (IS_ENABLED(CONFIG_BT_AICS) && !inst->client_instance) {
773 		struct bt_aics_control cp;
774 
775 		cp.opcode = BT_AICS_OPCODE_SET_AUTO;
776 		cp.counter = inst->srv.state.change_counter;
777 
778 		return aics_write(inst, write_aics_control, &cp, sizeof(cp));
779 	}
780 
781 	return -ENOTSUP;
782 }
783 
bt_aics_gain_set(struct bt_aics * inst,int8_t gain)784 int bt_aics_gain_set(struct bt_aics *inst, int8_t gain)
785 {
786 	CHECKIF(!inst) {
787 		LOG_DBG("NULL instance");
788 		return -EINVAL;
789 	}
790 
791 	if (IS_ENABLED(CONFIG_BT_AICS_CLIENT) && inst->client_instance) {
792 		return bt_aics_client_gain_set(inst, gain);
793 	} else if (IS_ENABLED(CONFIG_BT_AICS) && !inst->client_instance) {
794 		struct bt_aics_gain_control cp;
795 
796 		cp.cp.opcode = BT_AICS_OPCODE_SET_GAIN;
797 		cp.cp.counter = inst->srv.state.change_counter;
798 		cp.gain_setting = gain;
799 
800 		return aics_write(inst, write_aics_control, &cp, sizeof(cp));
801 	}
802 
803 	return -ENOTSUP;
804 }
805 
bt_aics_description_get(struct bt_aics * inst)806 int bt_aics_description_get(struct bt_aics *inst)
807 {
808 	CHECKIF(!inst) {
809 		LOG_DBG("NULL instance");
810 		return -EINVAL;
811 	}
812 
813 	if (IS_ENABLED(CONFIG_BT_AICS_CLIENT) && inst->client_instance) {
814 		return bt_aics_client_description_get(inst);
815 	} else if (IS_ENABLED(CONFIG_BT_AICS) && !inst->client_instance) {
816 		if (inst->srv.cb && inst->srv.cb->description) {
817 			inst->srv.cb->description(inst, 0,
818 						  inst->srv.description);
819 		} else {
820 			LOG_DBG("Callback not registered for instance %p", inst);
821 		}
822 		return 0;
823 	}
824 
825 	return -ENOTSUP;
826 }
827 
bt_aics_description_set(struct bt_aics * inst,const char * description)828 int bt_aics_description_set(struct bt_aics *inst, const char *description)
829 {
830 	CHECKIF(!inst) {
831 		LOG_DBG("NULL instance");
832 		return -EINVAL;
833 	}
834 
835 	CHECKIF(!description) {
836 		LOG_DBG("NULL description");
837 		return -EINVAL;
838 	}
839 
840 	if (IS_ENABLED(CONFIG_BT_AICS_CLIENT) && inst->client_instance) {
841 		return bt_aics_client_description_set(inst, description);
842 	} else if (IS_ENABLED(CONFIG_BT_AICS) && !inst->client_instance) {
843 		return aics_write(inst, write_description, description, strlen(description));
844 	}
845 
846 	return -ENOTSUP;
847 }
848