blob: 2aade46edd63b9421d820aaed345f1e6c614c000 [file] [log] [blame]
/* Bluetooth Audio Common Audio Profile internal header */
/*
* Copyright (c) 2022-2025 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdint.h>
#include <zephyr/autoconf.h>
#include <zephyr/bluetooth/audio/audio.h>
#include <zephyr/bluetooth/audio/bap.h>
#include <zephyr/bluetooth/audio/cap.h>
#include <zephyr/bluetooth/audio/csip.h>
#include <zephyr/bluetooth/addr.h>
#include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/bluetooth/conn.h>
#include <zephyr/bluetooth/gatt.h>
#include <zephyr/bluetooth/iso.h>
#include <zephyr/sys/atomic.h>
#include <zephyr/sys/util.h>
#include <zephyr/sys/util_macro.h>
#include <zephyr/types.h>
bool bt_cap_acceptor_ccid_exist(const struct bt_conn *conn, uint8_t ccid);
bool bt_cap_acceptor_ccids_exist(const struct bt_conn *conn, const uint8_t ccids[],
uint8_t ccid_cnt);
void bt_cap_initiator_codec_configured(struct bt_cap_stream *cap_stream);
void bt_cap_initiator_qos_configured(struct bt_cap_stream *cap_stream);
void bt_cap_initiator_enabled(struct bt_cap_stream *cap_stream);
void bt_cap_initiator_started(struct bt_cap_stream *cap_stream);
void bt_cap_initiator_connected(struct bt_cap_stream *cap_stream);
void bt_cap_initiator_metadata_updated(struct bt_cap_stream *cap_stream);
void bt_cap_initiator_disabled(struct bt_cap_stream *cap_stream);
void bt_cap_initiator_stopped(struct bt_cap_stream *cap_stream);
void bt_cap_initiator_released(struct bt_cap_stream *cap_stream);
void bt_cap_stream_ops_register_bap(struct bt_cap_stream *cap_stream);
void bt_cap_initiator_cp_cb(struct bt_cap_stream *cap_stream, enum bt_bap_ascs_rsp_code rsp_code,
enum bt_bap_ascs_reason reason);
enum bt_cap_common_proc_state {
BT_CAP_COMMON_PROC_STATE_ACTIVE,
BT_CAP_COMMON_PROC_STATE_ABORTED,
/* While the handover is technically a procedure, and arguably should use
* `bt_cap_common_set_proc`, we set the it as a flag instead so that we can rely on the API
* functions to perform their procedures
*/
BT_CAP_COMMON_PROC_STATE_HANDOVER,
BT_CAP_COMMON_PROC_STATE_FLAG_NUM,
};
enum bt_cap_common_proc_type {
BT_CAP_COMMON_PROC_TYPE_NONE,
BT_CAP_COMMON_PROC_TYPE_START,
BT_CAP_COMMON_PROC_TYPE_UPDATE,
BT_CAP_COMMON_PROC_TYPE_STOP,
BT_CAP_COMMON_PROC_TYPE_BROADCAST_RECEPTION_START,
BT_CAP_COMMON_PROC_TYPE_BROADCAST_RECEPTION_STOP,
BT_CAP_COMMON_PROC_TYPE_DISTRIBUTE_BROADCAST_CODE,
BT_CAP_COMMON_PROC_TYPE_VOLUME_CHANGE,
BT_CAP_COMMON_PROC_TYPE_VOLUME_OFFSET_CHANGE,
BT_CAP_COMMON_PROC_TYPE_VOLUME_MUTE_CHANGE,
BT_CAP_COMMON_PROC_TYPE_MICROPHONE_GAIN_CHANGE,
BT_CAP_COMMON_PROC_TYPE_MICROPHONE_MUTE_CHANGE,
};
enum bt_cap_common_subproc_type {
BT_CAP_COMMON_SUBPROC_TYPE_NONE,
BT_CAP_COMMON_SUBPROC_TYPE_CODEC_CONFIG,
BT_CAP_COMMON_SUBPROC_TYPE_QOS_CONFIG,
BT_CAP_COMMON_SUBPROC_TYPE_ENABLE,
BT_CAP_COMMON_SUBPROC_TYPE_CONNECT,
BT_CAP_COMMON_SUBPROC_TYPE_START,
BT_CAP_COMMON_SUBPROC_TYPE_META_UPDATE,
BT_CAP_COMMON_SUBPROC_TYPE_DISABLE,
BT_CAP_COMMON_SUBPROC_TYPE_STOP,
BT_CAP_COMMON_SUBPROC_TYPE_RELEASE,
};
struct bt_cap_unicast_group {
struct bt_bap_unicast_group *bap_unicast_group;
};
struct bt_cap_broadcast_source {
struct bt_bap_broadcast_source *bap_broadcast;
};
struct bt_cap_initiator_proc_param {
struct bt_cap_stream *stream;
union {
struct {
struct bt_conn *conn;
struct bt_bap_ep *ep;
struct bt_audio_codec_cfg *codec_cfg;
bool connected;
} start;
struct {
/** Codec Specific Capabilities Metadata count */
size_t meta_len;
/** Codec Specific Capabilities Metadata */
uint8_t meta[CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE];
} meta_update;
struct {
bool release;
} stop;
};
bool in_progress;
};
#if defined(CONFIG_BT_BAP_BROADCAST_ASSISTANT)
struct cap_broadcast_reception_start {
bt_addr_le_t addr;
uint8_t adv_sid;
uint32_t broadcast_id;
uint16_t pa_interval;
uint8_t num_subgroups;
struct bt_bap_bass_subgroup subgroups[CONFIG_BT_BAP_BASS_MAX_SUBGROUPS];
};
struct cap_broadcast_reception_stop {
uint8_t src_id;
uint8_t num_subgroups;
struct bt_bap_bass_subgroup subgroups[CONFIG_BT_BAP_BASS_MAX_SUBGROUPS];
};
/* Note that although the broadcast_code will be the same for all
* we nevertheless store a separate copy for each sink, for
* consistency in the struct bt_cap_commander_proc_param
* There is no memory savings by not having broadcast_code part of the
* union: struct cap_broadcast_reception_start uses minimum 20 bytes
* and struct cap_distribute_broadcast_code uses 17 bytes
*/
struct cap_distribute_broadcast_code {
uint8_t src_id;
uint8_t broadcast_code[BT_ISO_BROADCAST_CODE_SIZE];
};
#endif /* CONFIG_BT_BAP_BROADCAST_ASSISTANT */
struct bt_cap_commander_proc_param {
struct bt_conn *conn;
union {
#if defined(CONFIG_BT_VCP_VOL_CTLR)
struct {
uint8_t volume;
} change_volume;
struct {
bool mute;
} change_vol_mute;
#endif /* CONFIG_BT_VCP_VOL_CTLR */
#if defined(CONFIG_BT_VCP_VOL_CTLR_VOCS)
struct {
int16_t offset;
struct bt_vocs *vocs;
} change_offset;
#endif /* CONFIG_BT_VCP_VOL_CTLR_VOCS */
#if defined(CONFIG_BT_BAP_BROADCAST_ASSISTANT)
struct cap_broadcast_reception_start broadcast_reception_start;
struct cap_broadcast_reception_stop broadcast_reception_stop;
struct cap_distribute_broadcast_code distribute_broadcast_code;
#endif /* CONFIG_BT_BAP_BROADCAST_ASSISTANT */
#if defined(CONFIG_BT_MICP_MIC_CTLR)
struct {
bool mute;
} change_mic_mute;
#if defined(CONFIG_BT_MICP_MIC_CTLR_AICS)
struct {
int8_t gain;
struct bt_aics *aics;
} change_gain;
#endif /* CONFIG_BT_MICP_MIC_CTLR_AICS */
#endif /* CONFIG_BT_MICP_MIC_CTLR */
};
};
#if defined(CONFIG_BT_CAP_HANDOVER)
struct bt_cap_handover_proc_param {
union {
struct {
/* Struct containing the converted unicast group configuration */
struct bt_cap_initiator_broadcast_create_param *broadcast_create_param;
/* The resulting broadcast source */
struct bt_cap_broadcast_source *broadcast_source;
/* The advertising set to start the source on */
struct bt_le_ext_adv *ext_adv;
/* The source unicast group with the streams. */
struct bt_cap_unicast_group *unicast_group;
/* Set type */
enum bt_cap_set_type type;
/* The PA interval of the ext_adv */
uint16_t pa_interval;
/* The broadcast ID the broadcast source will use */
uint32_t broadcast_id;
struct bt_cap_commander_broadcast_reception_start_member_param
reception_start_member_params[CONFIG_BT_MAX_CONN];
} unicast_to_broadcast;
struct {
/* The existing broadcast source */
struct bt_cap_broadcast_source *broadcast_source;
/* The resulting unicast group */
struct bt_cap_unicast_group *unicast_group;
/* Broadcast ID of broadcast_source*/
uint32_t broadcast_id;
/* Advertising SID of broadcast_source*/
uint8_t adv_sid;
/* Advertising type of broadcast_source*/
uint8_t adv_type;
/* States used to determine when the broadcast source can be deleted */
bool broadcast_stopped;
bool reception_stopped;
/* Array of connection objects that we are waiting for a receive state with
* a BIG sync lost event
*/
struct bt_conn *pending_recv_state_conns[MIN(
CONFIG_BT_MAX_CONN,
CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT)];
/* Unicast group create param from caller */
struct bt_cap_unicast_group_param *unicast_group_param;
/* Unicast start param from caller */
struct bt_cap_unicast_audio_start_param *unicast_start_param;
} broadcast_to_unicast;
};
/* Flag to determine which of the two structs above to use */
bool is_unicast_to_broadcast;
};
#endif /* CONFIG_BT_CAP_HANDOVER */
typedef void (*bt_cap_common_discover_func_t)(
struct bt_conn *conn, int err, const struct bt_csip_set_coordinator_set_member *member,
const struct bt_csip_set_coordinator_csis_inst *csis_inst);
struct bt_cap_common_proc_param {
union {
#if defined(CONFIG_BT_CAP_INITIATOR_UNICAST)
struct bt_cap_initiator_proc_param
initiator[CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT];
#endif /* CONFIG_BT_CAP_INITIATOR_UNICAST */
#if defined(CONFIG_BT_CAP_COMMANDER)
struct bt_cap_commander_proc_param commander[CONFIG_BT_MAX_CONN];
#endif /* CONFIG_BT_CAP_COMMANDER */
};
#if defined(CONFIG_BT_CAP_HANDOVER)
/* The handover parameters cannot be part of the union as they need to exist while we are
* performing CAP initiator and CAP Commander procedures
*/
struct bt_cap_handover_proc_param handover;
#endif /* CONFIG_BT_CAP_HANDOVER */
};
struct bt_cap_common_proc {
ATOMIC_DEFINE(proc_state_flags, BT_CAP_COMMON_PROC_STATE_FLAG_NUM);
/* Total number of items (streams or connections) in the procedure*/
size_t proc_cnt;
/* Number of items where a subprocedure have been started */
size_t proc_initiated_cnt;
/* Number of items done with the procedure */
size_t proc_done_cnt;
enum bt_cap_common_proc_type proc_type;
int err;
struct bt_conn *failed_conn;
struct bt_cap_common_proc_param proc_param;
#if defined(CONFIG_BT_CAP_INITIATOR_UNICAST)
enum bt_cap_common_subproc_type subproc_type;
#endif /* CONFIG_BT_CAP_INITIATOR_UNICAST */
};
struct bt_cap_common_client {
struct bt_conn *conn;
struct bt_gatt_discover_params param;
bt_cap_common_discover_func_t discover_cb_func;
uint16_t csis_start_handle;
const struct bt_csip_set_coordinator_csis_inst *csis_inst;
};
struct bt_cap_common_proc *bt_cap_common_get_active_proc(void);
void bt_cap_common_clear_active_proc(void);
void bt_cap_common_set_proc(enum bt_cap_common_proc_type proc_type, size_t proc_cnt);
void bt_cap_common_set_subproc(enum bt_cap_common_subproc_type subproc_type);
void bt_cap_common_set_handover_active(void);
bool bt_cap_common_handover_is_active(void);
bool bt_cap_common_proc_is_type(enum bt_cap_common_proc_type proc_type);
bool bt_cap_common_subproc_is_type(enum bt_cap_common_subproc_type subproc_type);
struct bt_conn *bt_cap_common_get_member_conn(enum bt_cap_set_type type,
const union bt_cap_set_member *member);
bool bt_cap_common_test_and_set_proc_active(void);
bool bt_cap_common_proc_is_active(void);
bool bt_cap_common_proc_is_aborted(void);
bool bt_cap_common_proc_all_handled(void);
bool bt_cap_common_proc_is_done(void);
void bt_cap_common_abort_proc(struct bt_conn *conn, int err);
bool bt_cap_common_conn_in_active_proc(const struct bt_conn *conn);
bool bt_cap_common_stream_in_active_proc(const struct bt_cap_stream *cap_stream);
void bt_cap_common_disconnected(struct bt_conn *conn, uint8_t reason);
struct bt_cap_common_client *bt_cap_common_get_client_by_acl(const struct bt_conn *acl);
struct bt_cap_common_client *
bt_cap_common_get_client_by_csis(const struct bt_csip_set_coordinator_csis_inst *csis_inst);
int bt_cap_common_discover(struct bt_conn *conn, bt_cap_common_discover_func_t func);
bool bt_cap_initiator_broadcast_audio_start_valid_param(
const struct bt_cap_initiator_broadcast_create_param *param);
bool bt_cap_initiator_valid_unicast_audio_start_param(
const struct bt_cap_unicast_audio_start_param *param);
bool bt_cap_initiator_valid_unicast_group_param(const struct bt_cap_unicast_group_param *param);
bool bt_cap_initiator_stream_is_in_state(const struct bt_bap_stream *bap_stream,
enum bt_bap_ep_state state);
bool bt_cap_initiator_valid_unicast_audio_stop_param(
const struct bt_cap_unicast_audio_stop_param *param);
int cap_initiator_unicast_audio_start(const struct bt_cap_unicast_audio_start_param *param);
int cap_initiator_unicast_audio_stop(const struct bt_cap_unicast_audio_stop_param *param);
enum bt_bap_ep_state bt_cap_initiator_stream_get_state(const struct bt_bap_stream *bap_stream);
int cap_commander_broadcast_reception_start(
const struct bt_cap_commander_broadcast_reception_start_param *param);
int cap_commander_broadcast_reception_start(
const struct bt_cap_commander_broadcast_reception_start_param *param);
int cap_commander_broadcast_reception_stop(
const struct bt_cap_commander_broadcast_reception_stop_param *param);
bool bt_cap_commander_valid_broadcast_reception_stop_param(
const struct bt_cap_commander_broadcast_reception_stop_param *param);
void cap_commander_register_broadcast_assistant_callbacks(void);
void bt_cap_handover_complete(void);
void bt_cap_handover_unicast_to_broadcast_setup_broadcast(void);
void bt_cap_handover_unicast_to_broadcast_reception_start(void);
void bt_cap_handover_unicast_proc_complete(void);
void bt_cap_handover_broadcast_source_stopped(uint8_t reason);
void bt_cap_handover_broadcast_audio_stopped(void);
void bt_cap_handover_receive_state_updated(const struct bt_conn *conn,
const struct bt_bap_scan_delegator_recv_state *state);
bool bt_cap_handover_is_handover_broadcast_source(
const struct bt_cap_broadcast_source *cap_broadcast_source);
int bt_cap_handover_broadcast_reception_stopped(void);