Skip to content

Bluetooth: CAP: Add cap_unicast_group API #86014

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 17, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions doc/releases/release-notes-4.2.rst
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,12 @@ New APIs and options
* :c:macro:`BT_BAP_PER_ADV_PARAM_BROADCAST_SLOW`
* :c:func:`bt_csip_set_member_set_size_and_rank`
* :c:func:`bt_csip_set_member_get_info`
* :c:func:`bt_bap_unicast_group_foreach_stream`
* :c:func:`bt_cap_unicast_group_create`
* :c:func:`bt_cap_unicast_group_reconfig`
* :c:func:`bt_cap_unicast_group_add_streams`
* :c:func:`bt_cap_unicast_group_delete`
* :c:func:`bt_cap_unicast_group_foreach_stream`

* Host

Expand Down
28 changes: 27 additions & 1 deletion include/zephyr/bluetooth/audio/bap.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* @brief Header for Bluetooth BAP.
*
* Copyright (c) 2020 Bose Corporation
* Copyright (c) 2021-2024 Nordic Semiconductor ASA
* Copyright (c) 2021-2025 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
Expand Down Expand Up @@ -1720,6 +1720,32 @@ int bt_bap_unicast_group_add_streams(struct bt_bap_unicast_group *unicast_group,
*/
int bt_bap_unicast_group_delete(struct bt_bap_unicast_group *unicast_group);

/** Callback function for bt_bap_unicast_group_foreach_stream()
*
* @param stream The audio stream
* @param user_data User data
*
* @retval true Stop iterating.
* @retval false Continue iterating.
*/
typedef bool (*bt_bap_unicast_group_foreach_stream_func_t)(struct bt_bap_stream *stream,
void *user_data);

/**
* @brief Iterate through all streams in a unicast group
*
* @param unicast_group The unicast group
* @param func The callback function
* @param user_data User specified data that sent to the callback function
*
* @retval 0 Success (even if no streams exists in the group).
* @retval -ECANCELED Iteration was stopped by the callback function before complete.
* @retval -EINVAL @p unicast_group or @p func were NULL.
*/
int bt_bap_unicast_group_foreach_stream(struct bt_bap_unicast_group *unicast_group,
bt_bap_unicast_group_foreach_stream_func_t func,
void *user_data);

/** Unicast Client callback structure */
struct bt_bap_unicast_client_cb {
/**
Expand Down
172 changes: 171 additions & 1 deletion include/zephyr/bluetooth/audio/cap.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
*/

/*
* Copyright (c) 2022-2024 Nordic Semiconductor ASA
* Copyright (c) 2022-2025 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
Expand Down Expand Up @@ -50,6 +50,9 @@ extern "C" {
/** @brief Abstract Audio Broadcast Source structure. */
struct bt_cap_broadcast_source;

/** @brief Abstract CAP Unicast Group structure. */
struct bt_cap_unicast_group;

/**
* @brief Register the Common Audio Service.
*
Expand Down Expand Up @@ -254,6 +257,173 @@ int bt_cap_stream_send_ts(struct bt_cap_stream *stream, struct net_buf *buf, uin
*/
int bt_cap_stream_get_tx_sync(struct bt_cap_stream *stream, struct bt_iso_tx_info *info);

/** Parameter struct for each stream in the unicast group */
struct bt_cap_unicast_group_stream_param {
/** Pointer to a stream object. */
struct bt_cap_stream *stream;

/** The QoS settings for the stream object. */
struct bt_bap_qos_cfg *qos_cfg;
};

/**
* @brief Parameter struct for the unicast group functions
*
* Parameter struct for the bt_cap_unicast_group_create() and
* bt_cap_unicast_group_add_streams() functions.
*/
struct bt_cap_unicast_group_stream_pair_param {
/** Pointer to a receiving stream parameters. */
struct bt_cap_unicast_group_stream_param *rx_param;

/** Pointer to a transmitting stream parameters. */
struct bt_cap_unicast_group_stream_param *tx_param;
};

/** Parameters for the creating unicast groups with bt_cap_unicast_group_create() */
struct bt_cap_unicast_group_param {
/** The number of parameters in @p params */
size_t params_count;

/** Array of stream parameters */
struct bt_cap_unicast_group_stream_pair_param *params;

/**
* @brief Unicast Group packing mode.
*
* @ref BT_ISO_PACKING_SEQUENTIAL or @ref BT_ISO_PACKING_INTERLEAVED.
*
* @note This is a recommendation to the controller, which the controller may ignore.
*/
uint8_t packing;

#if defined(CONFIG_BT_ISO_TEST_PARAMS) || defined(__DOXYGEN__)
/**
* @brief Central to Peripheral flush timeout
*
* The flush timeout in multiples of ISO_Interval for each payload sent
* from the Central to Peripheral.
*
* Value range from @ref BT_ISO_FT_MIN to @ref BT_ISO_FT_MAX
*/
uint8_t c_to_p_ft;

/**
* @brief Peripheral to Central flush timeout
*
* The flush timeout in multiples of ISO_Interval for each payload sent
* from the Peripheral to Central.
*
* Value range from @ref BT_ISO_FT_MIN to @ref BT_ISO_FT_MAX.
*/
uint8_t p_to_c_ft;

/**
* @brief ISO interval
*
* Time between consecutive CIS anchor points.
*
* Value range from @ref BT_ISO_ISO_INTERVAL_MIN to @ref BT_ISO_ISO_INTERVAL_MAX.
*/
uint16_t iso_interval;
#endif /* CONFIG_BT_ISO_TEST_PARAMS */
};

/**
* @brief Create unicast group.
*
* Create a new audio unicast group with one or more audio streams as a unicast client.
* All streams shall share the same framing.
* All streams in the same direction shall share the same interval and latency (see
* @ref bt_bap_qos_cfg).
*
* @param[in] param The unicast group create parameters.
* @param[out] unicast_group Pointer to the unicast group created.
*
* @return Zero on success or (negative) error code otherwise.
*/
int bt_cap_unicast_group_create(const struct bt_cap_unicast_group_param *param,
struct bt_cap_unicast_group **unicast_group);

/**
* @brief Reconfigure unicast group.
*
* Reconfigure a unicast group with one or more audio streams as a unicast client.
* All streams shall share the same framing.
* All streams in the same direction shall share the same interval and latency (see
* @ref bt_bap_qos_cfg).
* All streams in @p param shall already belong to @p unicast_group.
* Use bt_cap_unicast_group_add_streams() to add additional streams.
*
* @param unicast_group Pointer to the unicast group created.
* @param param The unicast group reconfigure parameters.
*
* @return Zero on success or (negative) error code otherwise.
*/
int bt_cap_unicast_group_reconfig(struct bt_cap_unicast_group *unicast_group,
const struct bt_cap_unicast_group_param *param);

/**
* @brief Add streams to a unicast group as a unicast client
*
* This function can be used to add additional streams to a bt_cap_unicast_group.
*
* This can be called at any time before any of the streams in the group has been started
* (see bt_bap_stream_ops.started()).
* This can also be called after the streams have been stopped (see bt_bap_stream_ops.stopped()).
*
* Once a stream has been added to a unicast group, it cannot be removed. To remove a stream from a
* group, the group must be deleted with bt_cap_unicast_group_delete(), but this will require all
* streams in the group to be released first.
*
* @param unicast_group Pointer to the unicast group
* @param params Array of stream parameters with streams being added to the group.
* @param num_param Number of parameters in @p params.
*
* @return 0 in case of success or negative value in case of error.
*/
int bt_cap_unicast_group_add_streams(struct bt_cap_unicast_group *unicast_group,
const struct bt_cap_unicast_group_stream_pair_param params[],
size_t num_param);

/**
* @brief Delete audio unicast group.
*
* Delete a audio unicast group as a client. All streams in the group shall
* be in the idle or configured state.
*
* @param unicast_group Pointer to the unicast group to delete
*
* @return Zero on success or (negative) error code otherwise.
*/
int bt_cap_unicast_group_delete(struct bt_cap_unicast_group *unicast_group);

/** Callback function for bt_bap_unicast_group_foreach_stream()
*
* @param stream The audio stream
* @param user_data User data
*
* @retval true Stop iterating.
* @retval false Continue iterating.
*/
typedef bool (*bt_cap_unicast_group_foreach_stream_func_t)(struct bt_cap_stream *stream,
void *user_data);

/**
* @brief Iterate through all streams in a unicast group
*
* @param unicast_group The unicast group
* @param func The callback function
* @param user_data User specified data that sent to the callback function
*
* @retval 0 Success (even if no streams exists in the group).
* @retval -ECANCELED Iteration was stopped by the callback function before complete.
* @retval -EINVAL @p unicast_group or @p func were NULL.
*/
int bt_cap_unicast_group_foreach_stream(struct bt_cap_unicast_group *unicast_group,
bt_cap_unicast_group_foreach_stream_func_t func,
void *user_data);

/** Stream specific parameters for the bt_cap_initiator_unicast_audio_start() function */
struct bt_cap_unicast_audio_start_stream_param {
/** Coordinated or ad-hoc set member. */
Expand Down
22 changes: 11 additions & 11 deletions samples/bluetooth/cap_initiator/src/cap_initiator_unicast.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ LOG_MODULE_REGISTER(cap_initiator_unicast, LOG_LEVEL_INF);
*/
static struct bt_bap_lc3_preset unicast_preset_16_2_1 = BT_BAP_LC3_UNICAST_PRESET_16_2_1(
BT_AUDIO_LOCATION_MONO_AUDIO, BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED);
static struct bt_bap_unicast_group *unicast_group;
static struct bt_cap_unicast_group *unicast_group;
uint64_t total_rx_iso_packet_count; /* This value is exposed to test code */
uint64_t total_unicast_tx_iso_packet_count; /* This value is exposed to test code */

Expand Down Expand Up @@ -336,16 +336,16 @@ static int discover_sources(void)

static int unicast_group_create(void)
{
struct bt_bap_unicast_group_stream_param source_stream_param = {
.qos = &unicast_preset_16_2_1.qos,
.stream = &peer.source_stream.bap_stream,
struct bt_cap_unicast_group_stream_param source_stream_param = {
.qos_cfg = &unicast_preset_16_2_1.qos,
.stream = &peer.source_stream,
};
struct bt_bap_unicast_group_stream_param sink_stream_param = {
.qos = &unicast_preset_16_2_1.qos,
.stream = &peer.sink_stream.bap_stream,
struct bt_cap_unicast_group_stream_param sink_stream_param = {
.qos_cfg = &unicast_preset_16_2_1.qos,
.stream = &peer.sink_stream,
};
struct bt_bap_unicast_group_stream_pair_param pair_params = {0};
struct bt_bap_unicast_group_param group_param = {0};
struct bt_cap_unicast_group_stream_pair_param pair_params = {0};
struct bt_cap_unicast_group_param group_param = {0};
int err;

if (peer.source_ep != NULL) {
Expand All @@ -359,7 +359,7 @@ static int unicast_group_create(void)
group_param.params_count = 1U;
group_param.params = &pair_params;

err = bt_bap_unicast_group_create(&group_param, &unicast_group);
err = bt_cap_unicast_group_create(&group_param, &unicast_group);
if (err != 0) {
LOG_ERR("Failed to create group: %d", err);
return err;
Expand All @@ -374,7 +374,7 @@ static int unicast_group_delete(void)
{
int err;

err = bt_bap_unicast_group_delete(unicast_group);
err = bt_cap_unicast_group_delete(unicast_group);
if (err != 0) {
LOG_ERR("Failed to delete group: %d", err);
return err;
Expand Down
16 changes: 8 additions & 8 deletions samples/bluetooth/tmap_central/src/cap_initiator.c
Original file line number Diff line number Diff line change
Expand Up @@ -313,23 +313,23 @@ static struct bt_bap_unicast_client_cb unicast_client_cbs = {
.endpoint = endpoint_cb,
};

static int unicast_group_create(struct bt_bap_unicast_group **out_unicast_group)
static int unicast_group_create(struct bt_cap_unicast_group **out_unicast_group)
{
int err = 0;
struct bt_bap_unicast_group_stream_param group_stream_params;
struct bt_bap_unicast_group_stream_pair_param pair_params;
struct bt_bap_unicast_group_param group_param;
struct bt_cap_unicast_group_stream_param group_stream_params;
struct bt_cap_unicast_group_stream_pair_param pair_params;
struct bt_cap_unicast_group_param group_param;

group_stream_params.qos = &unicast_preset_48_2_1.qos;
group_stream_params.stream = &unicast_streams[0].bap_stream;
group_stream_params.qos_cfg = &unicast_preset_48_2_1.qos;
group_stream_params.stream = &unicast_streams[0];
pair_params.tx_param = &group_stream_params;
pair_params.rx_param = NULL;

group_param.packing = BT_ISO_PACKING_SEQUENTIAL;
group_param.params_count = 1;
group_param.params = &pair_params;

err = bt_bap_unicast_group_create(&group_param, out_unicast_group);
err = bt_cap_unicast_group_create(&group_param, out_unicast_group);
if (err != 0) {
printk("Failed to create group: %d\n", err);
return err;
Expand Down Expand Up @@ -444,7 +444,7 @@ int cap_initiator_init(void)
int cap_initiator_setup(struct bt_conn *conn)
{
int err = 0;
struct bt_bap_unicast_group *unicast_group;
struct bt_cap_unicast_group *unicast_group;

k_sem_reset(&sem_cas_discovery);
k_sem_reset(&sem_discover_sink);
Expand Down
Loading