Bluetooth: MICP: Allow for multiple mic_ctrl cb registers
Modify the MICP microphone controller callbacks to support multiple registers by making it into a linked list. This allow for multiple applications to get the information from procedures or notifications. Signed-off-by: Emil Gydesen <emil.gydesen@nordicsemi.no>
This commit is contained in:
parent
b3c643b7ee
commit
562166b685
2 changed files with 219 additions and 87 deletions
|
@ -185,6 +185,9 @@ struct bt_micp_mic_ctlr_cb {
|
|||
/** Audio Input Control Service client callback */
|
||||
struct bt_aics_cb aics_cb;
|
||||
#endif /* CONFIG_BT_MICP_MIC_CTLR_AICS */
|
||||
|
||||
/** Internally used field for list handling */
|
||||
sys_snode_t _node;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
/*
|
||||
* Copyright (c) 2020 Bose Corporation
|
||||
* Copyright (c) 2020-2022 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2020-2023 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
@ -28,7 +28,7 @@ LOG_MODULE_REGISTER(bt_micp_mic_ctlr, CONFIG_BT_MICP_MIC_CTLR_LOG_LEVEL);
|
|||
#include "common/bt_str.h"
|
||||
|
||||
/* Callback functions */
|
||||
static struct bt_micp_mic_ctlr_cb *micp_mic_ctlr_cb;
|
||||
static sys_slist_t micp_mic_ctlr_cbs = SYS_SLIST_STATIC_INIT(&micp_mic_ctlr_cbs);
|
||||
|
||||
static struct bt_micp_mic_ctlr mic_ctlrs[CONFIG_BT_MAX_CONN];
|
||||
static const struct bt_uuid *mics_uuid = BT_UUID_MICS;
|
||||
|
@ -38,8 +38,46 @@ static struct bt_micp_mic_ctlr *mic_ctlr_get_by_conn(const struct bt_conn *conn)
|
|||
return &mic_ctlrs[bt_conn_index(conn)];
|
||||
}
|
||||
|
||||
static uint8_t mute_notify_handler(struct bt_conn *conn,
|
||||
struct bt_gatt_subscribe_params *params,
|
||||
static void micp_mic_ctlr_mute_changed(struct bt_micp_mic_ctlr *mic_ctlr, int err, uint8_t mute_val)
|
||||
{
|
||||
struct bt_micp_mic_ctlr_cb *listener, *next;
|
||||
|
||||
SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&micp_mic_ctlr_cbs, listener, next, _node) {
|
||||
if (listener->mute) {
|
||||
listener->mute(mic_ctlr, err, mute_val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void micp_mic_ctlr_mute_written(struct bt_micp_mic_ctlr *mic_ctlr, int err, uint8_t mute_val)
|
||||
{
|
||||
struct bt_micp_mic_ctlr_cb *listener, *next;
|
||||
|
||||
SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&micp_mic_ctlr_cbs, listener, next, _node) {
|
||||
if (mute_val == BT_MICP_MUTE_UNMUTED) {
|
||||
if (listener->unmute_written) {
|
||||
listener->unmute_written(mic_ctlr, err);
|
||||
}
|
||||
} else {
|
||||
if (listener->mute_written) {
|
||||
listener->mute_written(mic_ctlr, err);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void micp_mic_ctlr_discover_complete(struct bt_micp_mic_ctlr *mic_ctlr, int err)
|
||||
{
|
||||
struct bt_micp_mic_ctlr_cb *listener, *next;
|
||||
|
||||
SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&micp_mic_ctlr_cbs, listener, next, _node) {
|
||||
if (listener->discover) {
|
||||
listener->discover(mic_ctlr, err, err == 0 ? mic_ctlr->aics_inst_cnt : 0U);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t mute_notify_handler(struct bt_conn *conn, struct bt_gatt_subscribe_params *params,
|
||||
const void *data, uint16_t length)
|
||||
{
|
||||
uint8_t *mute_val;
|
||||
|
@ -55,13 +93,10 @@ static uint8_t mute_notify_handler(struct bt_conn *conn,
|
|||
if (length == sizeof(*mute_val)) {
|
||||
mute_val = (uint8_t *)data;
|
||||
LOG_DBG("Mute %u", *mute_val);
|
||||
if (micp_mic_ctlr_cb != NULL &&
|
||||
micp_mic_ctlr_cb->mute != NULL) {
|
||||
micp_mic_ctlr_cb->mute(mic_ctlr, 0, *mute_val);
|
||||
}
|
||||
} else {
|
||||
LOG_DBG("Invalid length %u (expected %zu)", length, sizeof(*mute_val));
|
||||
micp_mic_ctlr_mute_changed(mic_ctlr, 0, *mute_val);
|
||||
}
|
||||
} else {
|
||||
LOG_DBG("Invalid length %u (expected %zu)", length, sizeof(*mute_val));
|
||||
}
|
||||
|
||||
return BT_GATT_ITER_CONTINUE;
|
||||
|
@ -89,9 +124,7 @@ static uint8_t micp_mic_ctlr_read_mute_cb(struct bt_conn *conn, uint8_t err,
|
|||
}
|
||||
}
|
||||
|
||||
if (micp_mic_ctlr_cb != NULL && micp_mic_ctlr_cb->mute != NULL) {
|
||||
micp_mic_ctlr_cb->mute(mic_ctlr, cb_err, mute_val);
|
||||
}
|
||||
micp_mic_ctlr_mute_changed(mic_ctlr, cb_err, mute_val);
|
||||
|
||||
return BT_GATT_ITER_STOP;
|
||||
}
|
||||
|
@ -106,18 +139,7 @@ static void micp_mic_ctlr_write_mics_mute_cb(struct bt_conn *conn, uint8_t err,
|
|||
|
||||
mic_ctlr->busy = false;
|
||||
|
||||
if (mute_val == BT_MICP_MUTE_UNMUTED) {
|
||||
if (micp_mic_ctlr_cb != NULL &&
|
||||
micp_mic_ctlr_cb->unmute_written != NULL) {
|
||||
micp_mic_ctlr_cb->unmute_written(mic_ctlr, err);
|
||||
}
|
||||
|
||||
} else {
|
||||
if (micp_mic_ctlr_cb != NULL &&
|
||||
micp_mic_ctlr_cb->mute_written != NULL) {
|
||||
micp_mic_ctlr_cb->mute_written(mic_ctlr, err);
|
||||
}
|
||||
}
|
||||
micp_mic_ctlr_mute_written(mic_ctlr, err, mute_val);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_BT_MICP_MIC_CTLR_AICS)
|
||||
|
@ -136,21 +158,143 @@ static struct bt_micp_mic_ctlr *lookup_micp_by_aics(const struct bt_aics *aics)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static void aics_discover_cb(struct bt_aics *inst, int err)
|
||||
static void micp_mic_ctlr_aics_state_cb(struct bt_aics *inst, int err, int8_t gain, uint8_t mute,
|
||||
uint8_t mode)
|
||||
{
|
||||
struct bt_micp_mic_ctlr_cb *listener, *next;
|
||||
|
||||
SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&micp_mic_ctlr_cbs, listener, next, _node) {
|
||||
if (listener->aics_cb.state) {
|
||||
listener->aics_cb.state(inst, err, gain, mute, mode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void micp_mic_ctlr_aics_gain_setting_cb(struct bt_aics *inst, int err, uint8_t units,
|
||||
int8_t minimum, int8_t maximum)
|
||||
{
|
||||
struct bt_micp_mic_ctlr_cb *listener, *next;
|
||||
|
||||
SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&micp_mic_ctlr_cbs, listener, next, _node) {
|
||||
if (listener->aics_cb.gain_setting) {
|
||||
listener->aics_cb.gain_setting(inst, err, units, minimum, maximum);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void micp_mic_ctlr_aics_type_cb(struct bt_aics *inst, int err, uint8_t type)
|
||||
{
|
||||
struct bt_micp_mic_ctlr_cb *listener, *next;
|
||||
|
||||
SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&micp_mic_ctlr_cbs, listener, next, _node) {
|
||||
if (listener->aics_cb.type) {
|
||||
listener->aics_cb.type(inst, err, type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void micp_mic_ctlr_aics_status_cb(struct bt_aics *inst, int err, bool active)
|
||||
{
|
||||
struct bt_micp_mic_ctlr_cb *listener, *next;
|
||||
|
||||
SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&micp_mic_ctlr_cbs, listener, next, _node) {
|
||||
if (listener->aics_cb.status) {
|
||||
listener->aics_cb.status(inst, err, active);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void micp_mic_ctlr_aics_description_cb(struct bt_aics *inst, int err, char *description)
|
||||
{
|
||||
struct bt_micp_mic_ctlr_cb *listener, *next;
|
||||
|
||||
SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&micp_mic_ctlr_cbs, listener, next, _node) {
|
||||
if (listener->aics_cb.description) {
|
||||
listener->aics_cb.description(inst, err, description);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void micp_mic_ctlr_aics_discover_cb(struct bt_aics *inst, int err)
|
||||
{
|
||||
struct bt_micp_mic_ctlr *mic_ctlr = lookup_micp_by_aics(inst);
|
||||
struct bt_micp_mic_ctlr_cb *listener, *next;
|
||||
|
||||
if (mic_ctlr == NULL) {
|
||||
LOG_ERR("Could not lookup mic_ctlr from aics");
|
||||
micp_mic_ctlr_discover_complete(mic_ctlr, BT_GATT_ERR(BT_ATT_ERR_UNLIKELY));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (err == 0) {
|
||||
/* Continue discovery of included services */
|
||||
err = bt_gatt_discover(mic_ctlr->conn,
|
||||
&mic_ctlr->discover_params);
|
||||
err = bt_gatt_discover(mic_ctlr->conn, &mic_ctlr->discover_params);
|
||||
}
|
||||
|
||||
if (err != 0) {
|
||||
LOG_DBG("Discover failed (err %d)", err);
|
||||
if (micp_mic_ctlr_cb != NULL &&
|
||||
micp_mic_ctlr_cb->discover != NULL) {
|
||||
micp_mic_ctlr_cb->discover(mic_ctlr, err, 0);
|
||||
micp_mic_ctlr_discover_complete(mic_ctlr, err);
|
||||
}
|
||||
|
||||
SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&micp_mic_ctlr_cbs, listener, next, _node) {
|
||||
if (listener->aics_cb.discover) {
|
||||
listener->aics_cb.discover(inst, err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void micp_mic_ctlr_aics_set_gain_cb(struct bt_aics *inst, int err)
|
||||
{
|
||||
struct bt_micp_mic_ctlr_cb *listener, *next;
|
||||
|
||||
SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&micp_mic_ctlr_cbs, listener, next, _node) {
|
||||
if (listener->aics_cb.set_gain) {
|
||||
listener->aics_cb.set_gain(inst, err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void micp_mic_ctlr_aics_unmute_cb(struct bt_aics *inst, int err)
|
||||
{
|
||||
struct bt_micp_mic_ctlr_cb *listener, *next;
|
||||
|
||||
SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&micp_mic_ctlr_cbs, listener, next, _node) {
|
||||
if (listener->aics_cb.unmute) {
|
||||
listener->aics_cb.unmute(inst, err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void micp_mic_ctlr_aics_mute_cb(struct bt_aics *inst, int err)
|
||||
{
|
||||
struct bt_micp_mic_ctlr_cb *listener, *next;
|
||||
|
||||
SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&micp_mic_ctlr_cbs, listener, next, _node) {
|
||||
if (listener->aics_cb.mute) {
|
||||
listener->aics_cb.mute(inst, err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void micp_mic_ctlr_aics_set_manual_mode_cb(struct bt_aics *inst, int err)
|
||||
{
|
||||
struct bt_micp_mic_ctlr_cb *listener, *next;
|
||||
|
||||
SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&micp_mic_ctlr_cbs, listener, next, _node) {
|
||||
if (listener->aics_cb.set_manual_mode) {
|
||||
listener->aics_cb.set_manual_mode(inst, err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void micp_mic_ctlr_aics_set_auto_mode_cb(struct bt_aics *inst, int err)
|
||||
{
|
||||
struct bt_micp_mic_ctlr_cb *listener, *next;
|
||||
|
||||
SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&micp_mic_ctlr_cbs, listener, next, _node) {
|
||||
if (listener->aics_cb.set_auto_mode) {
|
||||
listener->aics_cb.set_auto_mode(inst, err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -166,11 +310,7 @@ static uint8_t micp_discover_include_func(
|
|||
LOG_DBG("Discover include complete for MICS: %u AICS", mic_ctlr->aics_inst_cnt);
|
||||
(void)memset(params, 0, sizeof(*params));
|
||||
|
||||
if (micp_mic_ctlr_cb != NULL &&
|
||||
micp_mic_ctlr_cb->discover != NULL) {
|
||||
micp_mic_ctlr_cb->discover(mic_ctlr, 0,
|
||||
mic_ctlr->aics_inst_cnt);
|
||||
}
|
||||
micp_mic_ctlr_discover_complete(mic_ctlr, 0);
|
||||
|
||||
return BT_GATT_ITER_STOP;
|
||||
}
|
||||
|
@ -201,12 +341,9 @@ static uint8_t micp_discover_include_func(
|
|||
¶m);
|
||||
if (err != 0) {
|
||||
LOG_DBG("AICS Discover failed (err %d)", err);
|
||||
if (micp_mic_ctlr_cb != NULL &&
|
||||
micp_mic_ctlr_cb->discover != NULL) {
|
||||
micp_mic_ctlr_cb->discover(mic_ctlr, err,
|
||||
0);
|
||||
}
|
||||
micp_mic_ctlr_discover_complete(mic_ctlr, err);
|
||||
}
|
||||
|
||||
return BT_GATT_ITER_STOP;
|
||||
}
|
||||
}
|
||||
|
@ -241,17 +378,12 @@ static uint8_t micp_discover_func(struct bt_conn *conn,
|
|||
&mic_ctlr->discover_params);
|
||||
if (err != 0) {
|
||||
LOG_DBG("Discover AICS failed (err %d)", err);
|
||||
if (micp_mic_ctlr_cb != NULL &&
|
||||
micp_mic_ctlr_cb->discover != NULL) {
|
||||
micp_mic_ctlr_cb->discover(mic_ctlr, err, 0);
|
||||
}
|
||||
micp_mic_ctlr_discover_complete(mic_ctlr, err);
|
||||
}
|
||||
} else {
|
||||
if (micp_mic_ctlr_cb != NULL &&
|
||||
micp_mic_ctlr_cb->discover != NULL) {
|
||||
micp_mic_ctlr_cb->discover(mic_ctlr, err, 0);
|
||||
}
|
||||
micp_mic_ctlr_discover_complete(mic_ctlr, err);
|
||||
}
|
||||
|
||||
return BT_GATT_ITER_STOP;
|
||||
}
|
||||
|
||||
|
@ -299,10 +431,8 @@ static uint8_t primary_discover_func(struct bt_conn *conn,
|
|||
|
||||
if (attr == NULL) {
|
||||
LOG_DBG("Could not find a MICS instance on the server");
|
||||
if (micp_mic_ctlr_cb != NULL &&
|
||||
micp_mic_ctlr_cb->discover != NULL) {
|
||||
micp_mic_ctlr_cb->discover(mic_ctlr, -ENODATA, 0);
|
||||
}
|
||||
micp_mic_ctlr_discover_complete(mic_ctlr, -ENODATA);
|
||||
|
||||
return BT_GATT_ITER_STOP;
|
||||
}
|
||||
|
||||
|
@ -327,10 +457,7 @@ static uint8_t primary_discover_func(struct bt_conn *conn,
|
|||
err = bt_gatt_discover(conn, &mic_ctlr->discover_params);
|
||||
if (err != 0) {
|
||||
LOG_DBG("Discover failed (err %d)", err);
|
||||
if (micp_mic_ctlr_cb != NULL &&
|
||||
micp_mic_ctlr_cb->discover != NULL) {
|
||||
micp_mic_ctlr_cb->discover(mic_ctlr, err, 0);
|
||||
}
|
||||
micp_mic_ctlr_discover_complete(mic_ctlr, err);
|
||||
}
|
||||
|
||||
return BT_GATT_ITER_STOP;
|
||||
|
@ -405,19 +532,34 @@ int bt_micp_mic_ctlr_discover(struct bt_conn *conn, struct bt_micp_mic_ctlr **mi
|
|||
static bool initialized;
|
||||
|
||||
if (!initialized) {
|
||||
for (int i = 0; i < ARRAY_SIZE(mic_ctlr->aics); i++) {
|
||||
mic_ctlr->aics[i] = bt_aics_client_free_instance_get();
|
||||
for (size_t i = 0U; i < ARRAY_SIZE(mic_ctlrs); i++) {
|
||||
for (size_t j = 0U; j < ARRAY_SIZE(mic_ctlr->aics); j++) {
|
||||
static struct bt_aics_cb aics_cb = {
|
||||
.state = micp_mic_ctlr_aics_state_cb,
|
||||
.gain_setting = micp_mic_ctlr_aics_gain_setting_cb,
|
||||
.type = micp_mic_ctlr_aics_type_cb,
|
||||
.status = micp_mic_ctlr_aics_status_cb,
|
||||
.description = micp_mic_ctlr_aics_description_cb,
|
||||
.discover = micp_mic_ctlr_aics_discover_cb,
|
||||
.set_gain = micp_mic_ctlr_aics_set_gain_cb,
|
||||
.unmute = micp_mic_ctlr_aics_unmute_cb,
|
||||
.mute = micp_mic_ctlr_aics_mute_cb,
|
||||
.set_manual_mode = micp_mic_ctlr_aics_set_manual_mode_cb,
|
||||
.set_auto_mode = micp_mic_ctlr_aics_set_auto_mode_cb,
|
||||
};
|
||||
|
||||
if (mic_ctlr->aics[i] == NULL) {
|
||||
return -ENOMEM;
|
||||
mic_ctlrs[i].aics[j] = bt_aics_client_free_instance_get();
|
||||
|
||||
if (mic_ctlrs[i].aics[j] == NULL) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
bt_aics_client_cb_register(mic_ctlrs[i].aics[j], &aics_cb);
|
||||
}
|
||||
|
||||
bt_aics_client_cb_register(mic_ctlr->aics[i],
|
||||
&micp_mic_ctlr_cb->aics_cb);
|
||||
}
|
||||
}
|
||||
|
||||
initialized = true;
|
||||
initialized = true;
|
||||
}
|
||||
#endif /* CONFIG_BT_MICP_MIC_CTLR_AICS */
|
||||
|
||||
mic_ctlr->conn = bt_conn_ref(conn);
|
||||
|
@ -437,33 +579,20 @@ int bt_micp_mic_ctlr_discover(struct bt_conn *conn, struct bt_micp_mic_ctlr **mi
|
|||
|
||||
int bt_micp_mic_ctlr_cb_register(struct bt_micp_mic_ctlr_cb *cb)
|
||||
{
|
||||
#if defined(CONFIG_BT_MICP_MIC_CTLR_AICS)
|
||||
struct bt_aics_cb *aics_cb = NULL;
|
||||
struct bt_micp_mic_ctlr_cb *tmp;
|
||||
|
||||
if (cb != NULL) {
|
||||
/* Ensure that the cb->aics_cb.discover is the aics_discover_cb */
|
||||
CHECKIF(cb->aics_cb.discover != NULL &&
|
||||
cb->aics_cb.discover != aics_discover_cb) {
|
||||
LOG_ERR("AICS discover callback shall not be set");
|
||||
return -EINVAL;
|
||||
}
|
||||
cb->aics_cb.discover = aics_discover_cb;
|
||||
|
||||
aics_cb = &cb->aics_cb;
|
||||
CHECKIF(cb == NULL) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (int i = 0; i < ARRAY_SIZE(mic_ctlrs); i++) {
|
||||
for (int j = 0; j < ARRAY_SIZE(mic_ctlrs[i].aics); j++) {
|
||||
struct bt_aics *aics = mic_ctlrs[i].aics[j];
|
||||
|
||||
if (aics != NULL) {
|
||||
bt_aics_client_cb_register(aics, aics_cb);
|
||||
}
|
||||
SYS_SLIST_FOR_EACH_CONTAINER(&micp_mic_ctlr_cbs, tmp, _node) {
|
||||
if (tmp == cb) {
|
||||
LOG_DBG("Already registered");
|
||||
return -EALREADY;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_BT_MICP_MIC_CTLR_AICS */
|
||||
|
||||
micp_mic_ctlr_cb = cb;
|
||||
sys_slist_append(&micp_mic_ctlr_cbs, &cb->_node);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue