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