diff --git a/include/zephyr/bluetooth/audio/vcp.h b/include/zephyr/bluetooth/audio/vcp.h index f050786ab63019..a902ceaed4d298 100644 --- a/include/zephyr/bluetooth/audio/vcp.h +++ b/include/zephyr/bluetooth/audio/vcp.h @@ -353,6 +353,9 @@ struct bt_vcp_vol_ctlr_cb { /* Audio Input Control Service callbacks */ struct bt_aics_cb aics_cb; + + /** Internally used field for list handling */ + sys_snode_t _node; }; /** @@ -360,10 +363,23 @@ struct bt_vcp_vol_ctlr_cb { * * @param cb The callback structure. * - * @return 0 if success, errno on failure. + * @retval 0 on success + * @retval -EINVAL if @p cb is NULL + * @retval -EALREADY if @p cb was already registered */ int bt_vcp_vol_ctlr_cb_register(struct bt_vcp_vol_ctlr_cb *cb); +/** + * @brief Unregisters the callbacks used by the Volume Controller. + * + * @param cb The callback structure. + * + * @retval 0 on success + * @retval -EINVAL if @p cb is NULL + * @retval -EALREADY if @p cb was not registered + */ +int bt_vcp_vol_ctlr_cb_unregister(struct bt_vcp_vol_ctlr_cb *cb); + /** * @brief Discover Volume Control Service and included services. * diff --git a/subsys/bluetooth/audio/shell/vcp_vol_ctlr.c b/subsys/bluetooth/audio/shell/vcp_vol_ctlr.c index 2925d594280c32..38d0abb0915d37 100644 --- a/subsys/bluetooth/audio/shell/vcp_vol_ctlr.c +++ b/subsys/bluetooth/audio/shell/vcp_vol_ctlr.c @@ -326,16 +326,21 @@ static struct bt_vcp_vol_ctlr_cb vcp_cbs = { static int cmd_vcp_vol_ctlr_discover(const struct shell *sh, size_t argc, char **argv) { + static bool cb_registered; int result; if (!ctx_shell) { ctx_shell = sh; } - result = bt_vcp_vol_ctlr_cb_register(&vcp_cbs); - if (result != 0) { - shell_print(sh, "CB register failed: %d", result); - return result; + if (!cb_registered) { + result = bt_vcp_vol_ctlr_cb_register(&vcp_cbs); + if (result != 0) { + shell_print(sh, "CB register failed: %d", result); + return result; + } + + cb_registered = true; } if (default_conn == NULL) { diff --git a/subsys/bluetooth/audio/vcp_vol_ctlr.c b/subsys/bluetooth/audio/vcp_vol_ctlr.c index 3defcfbf91734a..4cc2af2762d0f9 100644 --- a/subsys/bluetooth/audio/vcp_vol_ctlr.c +++ b/subsys/bluetooth/audio/vcp_vol_ctlr.c @@ -29,7 +29,7 @@ LOG_MODULE_REGISTER(bt_vcp_vol_ctlr, CONFIG_BT_VCP_VOL_CTLR_LOG_LEVEL); #include "common/bt_str.h" /* Callback functions */ -static struct bt_vcp_vol_ctlr_cb *vcp_vol_ctlr_cb; +static sys_slist_t vcp_vol_ctlr_cbs = SYS_SLIST_STATIC_INIT(&vcp_vol_ctlr_cbs); static struct bt_vcp_vol_ctlr vol_ctlr_insts[CONFIG_BT_MAX_CONN]; static int vcp_vol_ctlr_common_vcs_cp(struct bt_vcp_vol_ctlr *vol_ctlr, uint8_t opcode); @@ -39,6 +39,41 @@ static struct bt_vcp_vol_ctlr *vol_ctlr_get_by_conn(const struct bt_conn *conn) return &vol_ctlr_insts[bt_conn_index(conn)]; } +static void vcp_vol_ctlr_state_changed(struct bt_vcp_vol_ctlr *vol_ctlr, int err) +{ + struct bt_vcp_vol_ctlr_cb *listener, *next; + + SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&vcp_vol_ctlr_cbs, listener, next, _node) { + if (listener->state) { + listener->state(vol_ctlr, err, err == 0 ? vol_ctlr->state.volume : 0, + err == 0 ? vol_ctlr->state.mute : 0); + } + } +} + +static void vcp_vol_ctlr_flags_changed(struct bt_vcp_vol_ctlr *vol_ctlr, int err) +{ + struct bt_vcp_vol_ctlr_cb *listener, *next; + + SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&vcp_vol_ctlr_cbs, listener, next, _node) { + if (listener->flags) { + listener->flags(vol_ctlr, err, err == 0 ? vol_ctlr->flags : 0); + } + } +} + +static void vcp_vol_ctlr_discover_complete(struct bt_vcp_vol_ctlr *vol_ctlr, int err) +{ + struct bt_vcp_vol_ctlr_cb *listener, *next; + + SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&vcp_vol_ctlr_cbs, listener, next, _node) { + if (listener->discover) { + listener->discover(vol_ctlr, err, err == 0 ? vol_ctlr->vocs_inst_cnt : 0, + err == 0 ? vol_ctlr->aics_inst_cnt : 0); + } + } +} + static uint8_t vcp_vol_ctlr_notify_handler(struct bt_conn *conn, struct bt_gatt_subscribe_params *params, const void *data, uint16_t length) @@ -58,17 +93,12 @@ static uint8_t vcp_vol_ctlr_notify_handler(struct bt_conn *conn, LOG_DBG("Volume %u, mute %u, counter %u", vol_ctlr->state.volume, vol_ctlr->state.mute, vol_ctlr->state.change_counter); - if (vcp_vol_ctlr_cb && vcp_vol_ctlr_cb->state) { - vcp_vol_ctlr_cb->state(vol_ctlr, 0, vol_ctlr->state.volume, - vol_ctlr->state.mute); - } + vcp_vol_ctlr_state_changed(vol_ctlr, 0); } else if (handle == vol_ctlr->flag_handle && length == sizeof(vol_ctlr->flags)) { memcpy(&vol_ctlr->flags, data, length); LOG_DBG("Flags %u", vol_ctlr->flags); - if (vcp_vol_ctlr_cb && vcp_vol_ctlr_cb->flags) { - vcp_vol_ctlr_cb->flags(vol_ctlr, 0, vol_ctlr->flags); - } + vcp_vol_ctlr_flags_changed(vol_ctlr, 0); } return BT_GATT_ITER_CONTINUE; @@ -99,15 +129,7 @@ static uint8_t vcp_vol_ctlr_read_vol_state_cb(struct bt_conn *conn, uint8_t err, } } - if (vcp_vol_ctlr_cb && vcp_vol_ctlr_cb->state) { - if (cb_err) { - vcp_vol_ctlr_cb->state(vol_ctlr, cb_err, 0, 0); - } else { - vcp_vol_ctlr_cb->state(vol_ctlr, cb_err, - vol_ctlr->state.volume, - vol_ctlr->state.mute); - } - } + vcp_vol_ctlr_state_changed(vol_ctlr, cb_err); return BT_GATT_ITER_STOP; } @@ -134,62 +156,58 @@ static uint8_t vcp_vol_ctlr_read_flag_cb(struct bt_conn *conn, uint8_t err, } } - if (vcp_vol_ctlr_cb && vcp_vol_ctlr_cb->flags) { - if (cb_err) { - vcp_vol_ctlr_cb->flags(vol_ctlr, cb_err, 0); - } else { - vcp_vol_ctlr_cb->flags(vol_ctlr, cb_err, vol_ctlr->flags); - } - } + vcp_vol_ctlr_flags_changed(vol_ctlr, cb_err); return BT_GATT_ITER_STOP; } static void vcs_cp_notify_app(struct bt_vcp_vol_ctlr *vol_ctlr, uint8_t opcode, int err) { - if (vcp_vol_ctlr_cb == NULL) { - return; - } + struct bt_vcp_vol_ctlr_cb *listener, *next; - switch (opcode) { - case BT_VCP_OPCODE_REL_VOL_DOWN: - if (vcp_vol_ctlr_cb->vol_down) { - vcp_vol_ctlr_cb->vol_down(vol_ctlr, err); - } - break; - case BT_VCP_OPCODE_REL_VOL_UP: - if (vcp_vol_ctlr_cb->vol_up) { - vcp_vol_ctlr_cb->vol_up(vol_ctlr, err); - } - break; - case BT_VCP_OPCODE_UNMUTE_REL_VOL_DOWN: - if (vcp_vol_ctlr_cb->vol_down_unmute) { - vcp_vol_ctlr_cb->vol_down_unmute(vol_ctlr, err); - } - break; - case BT_VCP_OPCODE_UNMUTE_REL_VOL_UP: - if (vcp_vol_ctlr_cb->vol_up_unmute) { - vcp_vol_ctlr_cb->vol_up_unmute(vol_ctlr, err); - } - break; - case BT_VCP_OPCODE_SET_ABS_VOL: - if (vcp_vol_ctlr_cb->vol_set) { - vcp_vol_ctlr_cb->vol_set(vol_ctlr, err); - } - break; - case BT_VCP_OPCODE_UNMUTE: - if (vcp_vol_ctlr_cb->unmute) { - vcp_vol_ctlr_cb->unmute(vol_ctlr, err); - } - break; - case BT_VCP_OPCODE_MUTE: - if (vcp_vol_ctlr_cb->mute) { - vcp_vol_ctlr_cb->mute(vol_ctlr, err); + LOG_DBG("%p opcode %u err %d", vol_ctlr, opcode, err); + + SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&vcp_vol_ctlr_cbs, listener, next, _node) { + switch (opcode) { + case BT_VCP_OPCODE_REL_VOL_DOWN: + if (listener->vol_down) { + listener->vol_down(vol_ctlr, err); + } + break; + case BT_VCP_OPCODE_REL_VOL_UP: + if (listener->vol_up) { + listener->vol_up(vol_ctlr, err); + } + break; + case BT_VCP_OPCODE_UNMUTE_REL_VOL_DOWN: + if (listener->vol_down_unmute) { + listener->vol_down_unmute(vol_ctlr, err); + } + break; + case BT_VCP_OPCODE_UNMUTE_REL_VOL_UP: + if (listener->vol_up_unmute) { + listener->vol_up_unmute(vol_ctlr, err); + } + break; + case BT_VCP_OPCODE_SET_ABS_VOL: + if (listener->vol_set) { + listener->vol_set(vol_ctlr, err); + } + break; + case BT_VCP_OPCODE_UNMUTE: + if (listener->unmute) { + listener->unmute(vol_ctlr, err); + } + break; + case BT_VCP_OPCODE_MUTE: + if (listener->mute) { + listener->mute(vol_ctlr, err); + } + break; + default: + LOG_DBG("Unknown opcode 0x%02x", opcode); + break; } - break; - default: - LOG_DBG("Unknown opcode 0x%02x", opcode); - break; } } @@ -300,14 +318,7 @@ static uint8_t vcs_discover_include_func(struct bt_conn *conn, vol_ctlr->aics_inst_cnt, vol_ctlr->vocs_inst_cnt); (void)memset(params, 0, sizeof(*params)); - if (vcp_vol_ctlr_cb && vcp_vol_ctlr_cb->discover) { - /* - * TODO: Validate that all mandatory handles were found - */ - vcp_vol_ctlr_cb->discover(vol_ctlr, 0, - vol_ctlr->vocs_inst_cnt, - vol_ctlr->aics_inst_cnt); - } + vcp_vol_ctlr_discover_complete(vol_ctlr, 0); return BT_GATT_ITER_STOP; } @@ -339,10 +350,7 @@ static uint8_t vcs_discover_include_func(struct bt_conn *conn, ¶m); if (err != 0) { LOG_DBG("AICS Discover failed (err %d)", err); - if (vcp_vol_ctlr_cb && vcp_vol_ctlr_cb->discover) { - vcp_vol_ctlr_cb->discover(vol_ctlr, err, - 0, 0); - } + vcp_vol_ctlr_discover_complete(vol_ctlr, err); } return BT_GATT_ITER_STOP; @@ -367,10 +375,7 @@ static uint8_t vcs_discover_include_func(struct bt_conn *conn, ¶m); if (err != 0) { LOG_DBG("VOCS Discover failed (err %d)", err); - if (vcp_vol_ctlr_cb && vcp_vol_ctlr_cb->discover) { - vcp_vol_ctlr_cb->discover(vol_ctlr, err, - 0, 0); - } + vcp_vol_ctlr_discover_complete(vol_ctlr, err); } return BT_GATT_ITER_STOP; @@ -409,14 +414,10 @@ static uint8_t vcs_discover_func(struct bt_conn *conn, err = bt_gatt_discover(conn, &vol_ctlr->discover_params); if (err != 0) { LOG_DBG("Discover failed (err %d)", err); - if (vcp_vol_ctlr_cb && vcp_vol_ctlr_cb->discover) { - vcp_vol_ctlr_cb->discover(vol_ctlr, err, 0, 0); - } + vcp_vol_ctlr_discover_complete(vol_ctlr, err); } #else - if (vcp_vol_ctlr_cb && vcp_vol_ctlr_cb->discover) { - vcp_vol_ctlr_cb->discover(vol_ctlr, err, 0, 0); - } + vcp_vol_ctlr_discover_complete(vol_ctlr, err); #endif /* (CONFIG_BT_VCP_VOL_CTLR_MAX_AICS_INST > 0 || CONFIG_BT_VCP_VOL_CTLR_MAX_VOCS_INST > 0) */ return BT_GATT_ITER_STOP; @@ -476,9 +477,8 @@ static uint8_t primary_discover_func(struct bt_conn *conn, if (attr == NULL) { LOG_DBG("Could not find a vol_ctlr instance on the server"); - if (vcp_vol_ctlr_cb && vcp_vol_ctlr_cb->discover) { - vcp_vol_ctlr_cb->discover(vol_ctlr, -ENODATA, 0, 0); - } + vcp_vol_ctlr_discover_complete(vol_ctlr, -ENODATA); + return BT_GATT_ITER_STOP; } @@ -503,9 +503,7 @@ static uint8_t primary_discover_func(struct bt_conn *conn, err = bt_gatt_discover(conn, &vol_ctlr->discover_params); if (err != 0) { LOG_DBG("Discover failed (err %d)", err); - if (vcp_vol_ctlr_cb && vcp_vol_ctlr_cb->discover) { - vcp_vol_ctlr_cb->discover(vol_ctlr, err, 0, 0); - } + vcp_vol_ctlr_discover_complete(vol_ctlr, err); } return BT_GATT_ITER_STOP; @@ -567,20 +565,143 @@ static struct bt_vcp_vol_ctlr *lookup_vcp_by_aics(const struct bt_aics *aics) return NULL; } -static void aics_discover_cb(struct bt_aics *inst, int err) +static void vcp_vol_ctlr_aics_state_cb(struct bt_aics *inst, int err, int8_t gain, uint8_t mute, + uint8_t mode) +{ + struct bt_vcp_vol_ctlr_cb *listener, *next; + + SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&vcp_vol_ctlr_cbs, listener, next, _node) { + if (listener->aics_cb.state) { + listener->aics_cb.state(inst, err, gain, mute, mode); + } + } +} + +static void vcp_vol_ctlr_aics_gain_setting_cb(struct bt_aics *inst, int err, uint8_t units, + int8_t minimum, int8_t maximum) +{ + struct bt_vcp_vol_ctlr_cb *listener, *next; + + SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&vcp_vol_ctlr_cbs, listener, next, _node) { + if (listener->aics_cb.gain_setting) { + listener->aics_cb.gain_setting(inst, err, units, minimum, maximum); + } + } +} + +static void vcp_vol_ctlr_aics_type_cb(struct bt_aics *inst, int err, uint8_t type) +{ + struct bt_vcp_vol_ctlr_cb *listener, *next; + + SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&vcp_vol_ctlr_cbs, listener, next, _node) { + if (listener->aics_cb.type) { + listener->aics_cb.type(inst, err, type); + } + } +} + +static void vcp_vol_ctlr_aics_status_cb(struct bt_aics *inst, int err, bool active) +{ + struct bt_vcp_vol_ctlr_cb *listener, *next; + + SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&vcp_vol_ctlr_cbs, listener, next, _node) { + if (listener->aics_cb.status) { + listener->aics_cb.status(inst, err, active); + } + } +} + +static void vcp_vol_ctlr_aics_description_cb(struct bt_aics *inst, int err, char *description) +{ + struct bt_vcp_vol_ctlr_cb *listener, *next; + + SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&vcp_vol_ctlr_cbs, listener, next, _node) { + if (listener->aics_cb.description) { + listener->aics_cb.description(inst, err, description); + } + } +} + +static void vcp_vol_ctlr_aics_discover_cb(struct bt_aics *inst, int err) { struct bt_vcp_vol_ctlr *vol_ctlr = lookup_vcp_by_aics(inst); + struct bt_vcp_vol_ctlr_cb *listener, *next; + + if (vol_ctlr == NULL) { + LOG_ERR("Could not lookup vol_ctlr from aics"); + vcp_vol_ctlr_discover_complete(vol_ctlr, BT_GATT_ERR(BT_ATT_ERR_UNLIKELY)); + + return; + } if (err == 0) { /* Continue discovery of included services */ - err = bt_gatt_discover(vol_ctlr->conn, - &vol_ctlr->discover_params); + err = bt_gatt_discover(vol_ctlr->conn, &vol_ctlr->discover_params); } if (err != 0) { LOG_DBG("Discover failed (err %d)", err); - if (vcp_vol_ctlr_cb && vcp_vol_ctlr_cb->discover) { - vcp_vol_ctlr_cb->discover(vol_ctlr, err, 0, 0); + vcp_vol_ctlr_discover_complete(vol_ctlr, err); + } + + SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&vcp_vol_ctlr_cbs, listener, next, _node) { + if (listener->aics_cb.discover) { + listener->aics_cb.discover(inst, err); + } + } +} + +static void vcp_vol_ctlr_aics_set_gain_cb(struct bt_aics *inst, int err) +{ + struct bt_vcp_vol_ctlr_cb *listener, *next; + + SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&vcp_vol_ctlr_cbs, listener, next, _node) { + if (listener->aics_cb.set_gain) { + listener->aics_cb.set_gain(inst, err); + } + } +} + +static void vcp_vol_ctlr_aics_unmute_cb(struct bt_aics *inst, int err) +{ + struct bt_vcp_vol_ctlr_cb *listener, *next; + + SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&vcp_vol_ctlr_cbs, listener, next, _node) { + if (listener->aics_cb.unmute) { + listener->aics_cb.unmute(inst, err); + } + } +} + +static void vcp_vol_ctlr_aics_mute_cb(struct bt_aics *inst, int err) +{ + struct bt_vcp_vol_ctlr_cb *listener, *next; + + SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&vcp_vol_ctlr_cbs, listener, next, _node) { + if (listener->aics_cb.mute) { + listener->aics_cb.mute(inst, err); + } + } +} + +static void vcp_vol_ctlr_aics_set_manual_mode_cb(struct bt_aics *inst, int err) +{ + struct bt_vcp_vol_ctlr_cb *listener, *next; + + SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&vcp_vol_ctlr_cbs, listener, next, _node) { + if (listener->aics_cb.set_manual_mode) { + listener->aics_cb.set_manual_mode(inst, err); + } + } +} + +static void vcp_vol_ctlr_aics_set_auto_mode_cb(struct bt_aics *inst, int err) +{ + struct bt_vcp_vol_ctlr_cb *listener, *next; + + SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&vcp_vol_ctlr_cbs, listener, next, _node) { + if (listener->aics_cb.set_auto_mode) { + listener->aics_cb.set_auto_mode(inst, err); } } } @@ -602,32 +723,75 @@ static struct bt_vcp_vol_ctlr *lookup_vcp_by_vocs(const struct bt_vocs *vocs) return NULL; } -static void vocs_discover_cb(struct bt_vocs *inst, int err) +static void vcp_vol_ctlr_vocs_state_cb(struct bt_vocs *inst, int err, int16_t offset) +{ + struct bt_vcp_vol_ctlr_cb *listener, *next; + + SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&vcp_vol_ctlr_cbs, listener, next, _node) { + if (listener->vocs_cb.state) { + listener->vocs_cb.state(inst, err, offset); + } + } +} + +static void vcp_vol_ctlr_vocs_location_cb(struct bt_vocs *inst, int err, uint32_t location) +{ + struct bt_vcp_vol_ctlr_cb *listener, *next; + + SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&vcp_vol_ctlr_cbs, listener, next, _node) { + if (listener->vocs_cb.location) { + listener->vocs_cb.location(inst, err, location); + } + } +} + +static void vcp_vol_ctlr_vocs_description_cb(struct bt_vocs *inst, int err, char *description) +{ + struct bt_vcp_vol_ctlr_cb *listener, *next; + + SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&vcp_vol_ctlr_cbs, listener, next, _node) { + if (listener->vocs_cb.description) { + listener->vocs_cb.description(inst, err, description); + } + } +} + +static void vcp_vol_ctlr_vocs_discover_cb(struct bt_vocs *inst, int err) { struct bt_vcp_vol_ctlr *vol_ctlr = lookup_vcp_by_vocs(inst); + struct bt_vcp_vol_ctlr_cb *listener, *next; if (vol_ctlr == NULL) { LOG_ERR("Could not lookup vol_ctlr from vocs"); - - if (vcp_vol_ctlr_cb && vcp_vol_ctlr_cb->discover) { - vcp_vol_ctlr_cb->discover(vol_ctlr, - BT_GATT_ERR(BT_ATT_ERR_UNLIKELY), - 0, 0); - } + vcp_vol_ctlr_discover_complete(vol_ctlr, BT_GATT_ERR(BT_ATT_ERR_UNLIKELY)); return; } if (err == 0) { /* Continue discovery of included services */ - err = bt_gatt_discover(vol_ctlr->conn, - &vol_ctlr->discover_params); + err = bt_gatt_discover(vol_ctlr->conn, &vol_ctlr->discover_params); } if (err != 0) { LOG_DBG("Discover failed (err %d)", err); - if (vcp_vol_ctlr_cb && vcp_vol_ctlr_cb->discover) { - vcp_vol_ctlr_cb->discover(vol_ctlr, err, 0, 0); + vcp_vol_ctlr_discover_complete(vol_ctlr, err); + } + + SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&vcp_vol_ctlr_cbs, listener, next, _node) { + if (listener->vocs_cb.discover) { + listener->vocs_cb.discover(inst, err); + } + } +} + +static void vcp_vol_ctlr_vocs_set_offset_cb(struct bt_vocs *inst, int err) +{ + struct bt_vcp_vol_ctlr_cb *listener, *next; + + SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&vcp_vol_ctlr_cbs, listener, next, _node) { + if (listener->vocs_cb.set_offset) { + listener->vocs_cb.set_offset(inst, err); } } } @@ -679,37 +843,53 @@ BT_CONN_CB_DEFINE(conn_callbacks) = { static void bt_vcp_vol_ctlr_init(void) { - int i, j; +#if defined(CONFIG_BT_VCP_VOL_CTLR_VOCS) + for (size_t i = 0U; i < ARRAY_SIZE(vol_ctlr_insts); i++) { + for (size_t j = 0U; j < ARRAY_SIZE(vol_ctlr_insts[i].vocs); j++) { + static struct bt_vocs_cb vocs_cb = { + .state = vcp_vol_ctlr_vocs_state_cb, + .location = vcp_vol_ctlr_vocs_location_cb, + .description = vcp_vol_ctlr_vocs_description_cb, + .discover = vcp_vol_ctlr_vocs_discover_cb, + .set_offset = vcp_vol_ctlr_vocs_set_offset_cb, + }; - if (IS_ENABLED(CONFIG_BT_VOCS_CLIENT) && - CONFIG_BT_VCP_VOL_CTLR_MAX_VOCS_INST > 0) { - for (i = 0; i < ARRAY_SIZE(vol_ctlr_insts); i++) { - for (j = 0; j < ARRAY_SIZE(vol_ctlr_insts[i].vocs); j++) { - vol_ctlr_insts[i].vocs[j] = bt_vocs_client_free_instance_get(); + vol_ctlr_insts[i].vocs[j] = bt_vocs_client_free_instance_get(); - __ASSERT(vol_ctlr_insts[i].vocs[j], - "Could not allocate VOCS client instance"); + __ASSERT(vol_ctlr_insts[i].vocs[j], + "Could not allocate VOCS client instance"); - bt_vocs_client_cb_register(vol_ctlr_insts[i].vocs[j], - &vcp_vol_ctlr_cb->vocs_cb); - } + bt_vocs_client_cb_register(vol_ctlr_insts[i].vocs[j], &vocs_cb); } } +#endif /* CONFIG_BT_VCP_VOL_CTLR_VOCS */ - if (IS_ENABLED(CONFIG_BT_AICS_CLIENT) && - CONFIG_BT_VCP_VOL_CTLR_MAX_AICS_INST > 0) { - for (i = 0; i < ARRAY_SIZE(vol_ctlr_insts); i++) { - for (j = 0; j < ARRAY_SIZE(vol_ctlr_insts[i].aics); j++) { - vol_ctlr_insts[i].aics[j] = bt_aics_client_free_instance_get(); +#if defined(CONFIG_BT_VCP_VOL_CTLR_AICS) + for (size_t i = 0U; i < ARRAY_SIZE(vol_ctlr_insts); i++) { + for (size_t j = 0U; j < ARRAY_SIZE(vol_ctlr_insts[i].aics); j++) { + static struct bt_aics_cb aics_cb = { + .state = vcp_vol_ctlr_aics_state_cb, + .gain_setting = vcp_vol_ctlr_aics_gain_setting_cb, + .type = vcp_vol_ctlr_aics_type_cb, + .status = vcp_vol_ctlr_aics_status_cb, + .description = vcp_vol_ctlr_aics_description_cb, + .discover = vcp_vol_ctlr_aics_discover_cb, + .set_gain = vcp_vol_ctlr_aics_set_gain_cb, + .unmute = vcp_vol_ctlr_aics_unmute_cb, + .mute = vcp_vol_ctlr_aics_mute_cb, + .set_manual_mode = vcp_vol_ctlr_aics_set_manual_mode_cb, + .set_auto_mode = vcp_vol_ctlr_aics_set_auto_mode_cb, + }; - __ASSERT(vol_ctlr_insts[i].aics[j], - "Could not allocate AICS client instance"); + vol_ctlr_insts[i].aics[j] = bt_aics_client_free_instance_get(); - bt_aics_client_cb_register(vol_ctlr_insts[i].aics[j], - &vcp_vol_ctlr_cb->aics_cb); - } + __ASSERT(vol_ctlr_insts[i].aics[j], + "Could not allocate AICS client instance"); + + bt_aics_client_cb_register(vol_ctlr_insts[i].aics[j], &aics_cb); } } +#endif /* CONFIG_BT_VCP_VOL_CTLR_AICS */ } int bt_vcp_vol_ctlr_discover(struct bt_conn *conn, struct bt_vcp_vol_ctlr **out_vol_ctlr) @@ -769,59 +949,33 @@ int bt_vcp_vol_ctlr_discover(struct bt_conn *conn, struct bt_vcp_vol_ctlr **out_ int bt_vcp_vol_ctlr_cb_register(struct bt_vcp_vol_ctlr_cb *cb) { -#if defined(CONFIG_BT_VCP_VOL_CTLR_VOCS) - struct bt_vocs_cb *vocs_cb = NULL; - - if (cb != NULL) { - /* Ensure that the cb->vocs_cb.discover is the vocs_discover_cb */ - CHECKIF(cb->vocs_cb.discover != NULL && - cb->vocs_cb.discover != vocs_discover_cb) { - LOG_ERR("VOCS discover callback shall not be set"); - return -EINVAL; - } - cb->vocs_cb.discover = vocs_discover_cb; + struct bt_vcp_vol_ctlr_cb *tmp; - vocs_cb = &cb->vocs_cb; + CHECKIF(cb == NULL) { + return -EINVAL; } - for (int i = 0; i < ARRAY_SIZE(vol_ctlr_insts); i++) { - for (int j = 0; j < ARRAY_SIZE(vol_ctlr_insts[i].vocs); j++) { - struct bt_vocs *vocs = vol_ctlr_insts[i].vocs[j]; - - if (vocs != NULL) { - bt_vocs_client_cb_register(vocs, vocs_cb); - } + SYS_SLIST_FOR_EACH_CONTAINER(&vcp_vol_ctlr_cbs, tmp, _node) { + if (tmp == cb) { + LOG_DBG("Already registered"); + return -EALREADY; } } -#endif /* CONFIG_BT_VCP_VOL_CTLR_VOCS */ -#if defined(CONFIG_BT_VCP_VOL_CTLR_AICS) - struct bt_aics_cb *aics_cb = NULL; + sys_slist_append(&vcp_vol_ctlr_cbs, &cb->_node); - 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; + return 0; +} - aics_cb = &cb->aics_cb; +int bt_vcp_vol_ctlr_cb_unregister(struct bt_vcp_vol_ctlr_cb *cb) +{ + CHECKIF(cb == NULL) { + return -EINVAL; } - for (int i = 0; i < ARRAY_SIZE(vol_ctlr_insts); i++) { - for (int j = 0; j < ARRAY_SIZE(vol_ctlr_insts[i].aics); j++) { - struct bt_aics *aics = vol_ctlr_insts[i].aics[j]; - - if (aics != NULL) { - bt_aics_client_cb_register(aics, aics_cb); - } - } + if (!sys_slist_find_and_remove(&vcp_vol_ctlr_cbs, &cb->_node)) { + return -EALREADY; } -#endif /* CONFIG_BT_VCP_VOL_CTLR_AICS */ - - vcp_vol_ctlr_cb = cb; return 0; } diff --git a/tests/bluetooth/tester/src/btp_vcp.c b/tests/bluetooth/tester/src/btp_vcp.c index 04e82c35807b8c..1f3bd1b920341c 100644 --- a/tests/bluetooth/tester/src/btp_vcp.c +++ b/tests/bluetooth/tester/src/btp_vcp.c @@ -1024,6 +1024,13 @@ uint8_t tester_init_vcp(void) uint8_t tester_unregister_vcp(void) { - (void)bt_vcp_vol_ctlr_cb_register(NULL); + int err; + + err = bt_vcp_vol_ctlr_cb_unregister(&vcp_cbs); + if (err != 0) { + LOG_DBG("Failed to unregister callbacks: %d", err); + return BTP_STATUS_FAILED; + } + return BTP_STATUS_SUCCESS; }