Skip to content

Commit 8b8f727

Browse files
Thalleycarlescufi
authored andcommitted
Bluetooth: BAP: Add support for reconfiguring unicast group
This allows applications to modify the values set by an existing unicast group, assuming that none of the streams in the CIG has been connected. Signed-off-by: Emil Gydesen <[email protected]>
1 parent 175855e commit 8b8f727

File tree

6 files changed

+308
-50
lines changed

6 files changed

+308
-50
lines changed

include/zephyr/bluetooth/audio/bap.h

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1156,7 +1156,7 @@ struct bt_bap_unicast_group_param {
11561156
};
11571157

11581158
/**
1159-
* @brief Create audio unicast group.
1159+
* @brief Create unicast group.
11601160
*
11611161
* Create a new audio unicast group with one or more audio streams as a unicast client.
11621162
* All streams shall share the same framing.
@@ -1171,6 +1171,24 @@ struct bt_bap_unicast_group_param {
11711171
int bt_bap_unicast_group_create(struct bt_bap_unicast_group_param *param,
11721172
struct bt_bap_unicast_group **unicast_group);
11731173

1174+
/**
1175+
* @brief Reconfigure unicast group.
1176+
*
1177+
* Reconfigure a unicast group with one or more audio streams as a unicast client.
1178+
* All streams shall share the same framing.
1179+
* All streams in the same direction shall share the same interval and latency (see
1180+
* @ref bt_audio_codec_qos).
1181+
* All streams in @p param shall already belong to @p unicast_group.
1182+
* Use bt_bap_unicast_group_add_streams() to add additional streams.
1183+
*
1184+
* @param unicast_group Pointer to the unicast group created.
1185+
* @param param The unicast group reconfigure parameters.
1186+
*
1187+
* @return Zero on success or (negative) error code otherwise.
1188+
*/
1189+
int bt_bap_unicast_group_reconfig(struct bt_bap_unicast_group *unicast_group,
1190+
const struct bt_bap_unicast_group_param *param);
1191+
11741192
/**
11751193
* @brief Add streams to a unicast group as a unicast client
11761194
*

subsys/bluetooth/audio/bap_endpoint.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,10 @@ struct bt_bap_unicast_group {
8585
/* Unicast group fields */
8686
uint8_t index;
8787
bool allocated;
88+
/* Used to determine whether any stream in this group has been started which will prevent
89+
* reconfiguring it
90+
*/
91+
bool has_been_connected;
8892
struct bt_iso_cig *cig;
8993
/* The ISO API for CIG creation requires an array of pointers to ISO channels */
9094
struct bt_iso_chan *cis[UNICAST_GROUP_STREAM_CNT];

subsys/bluetooth/audio/bap_unicast_client.c

Lines changed: 157 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,10 @@ static void unicast_client_ep_iso_connected(struct bt_bap_ep *ep)
318318
const struct bt_bap_stream_ops *stream_ops;
319319
struct bt_bap_stream *stream;
320320

321+
if (ep->unicast_group != NULL) {
322+
ep->unicast_group->has_been_connected = true;
323+
}
324+
321325
if (ep->status.state != BT_BAP_EP_STATE_ENABLING) {
322326
LOG_DBG("endpoint not in enabling state: %s",
323327
bt_bap_ep_state_str(ep->status.state));
@@ -2171,25 +2175,30 @@ static void bt_audio_codec_qos_to_cig_param(struct bt_iso_cig_param *cig_param,
21712175
}
21722176
}
21732177

2174-
static int bt_audio_cig_create(struct bt_bap_unicast_group *group)
2178+
static uint8_t unicast_group_get_cis_count(const struct bt_bap_unicast_group *unicast_group)
21752179
{
2176-
struct bt_iso_cig_param param = {0};
2177-
uint8_t cis_count;
2178-
int err;
2180+
uint8_t cis_count = 0U;
21792181

2180-
LOG_DBG("group %p", group);
2181-
2182-
cis_count = 0U;
2183-
for (size_t i = 0U; i < ARRAY_SIZE(group->cis); i++) {
2184-
if (group->cis[i] == NULL) {
2182+
for (size_t i = 0U; i < ARRAY_SIZE(unicast_group->cis); i++) {
2183+
if (unicast_group->cis[i] == NULL) {
21852184
/* A NULL CIS acts as a NULL terminator */
21862185
break;
21872186
}
21882187

21892188
cis_count++;
21902189
}
21912190

2192-
param.num_cis = cis_count;
2191+
return cis_count;
2192+
}
2193+
2194+
static int bt_audio_cig_create(struct bt_bap_unicast_group *group)
2195+
{
2196+
struct bt_iso_cig_param param = {0};
2197+
int err;
2198+
2199+
LOG_DBG("group %p", group);
2200+
2201+
param.num_cis = unicast_group_get_cis_count(group);
21932202
param.cis_channels = group->cis;
21942203
bt_audio_codec_qos_to_cig_param(&param, group);
21952204

@@ -2352,6 +2361,27 @@ static void unicast_client_codec_qos_to_iso_qos(struct bt_bap_iso *iso,
23522361
}
23532362
}
23542363

2364+
static void unicast_group_set_iso_stream_param(struct bt_bap_unicast_group *group,
2365+
struct bt_bap_iso *iso,
2366+
struct bt_audio_codec_qos *qos,
2367+
enum bt_audio_dir dir)
2368+
{
2369+
/* Store the stream Codec QoS in the bap_iso */
2370+
unicast_client_codec_qos_to_iso_qos(iso, qos, dir);
2371+
2372+
/* Store the group Codec QoS in the group - This assume thats the parameters have been
2373+
* verified first
2374+
*/
2375+
group->cig_param.framing = qos->framing;
2376+
if (dir == BT_AUDIO_DIR_SOURCE) {
2377+
group->cig_param.p_to_c_interval = qos->interval;
2378+
group->cig_param.p_to_c_latency = qos->latency;
2379+
} else {
2380+
group->cig_param.c_to_p_interval = qos->interval;
2381+
group->cig_param.c_to_p_latency = qos->latency;
2382+
}
2383+
}
2384+
23552385
static void unicast_group_add_stream(struct bt_bap_unicast_group *group,
23562386
struct bt_bap_unicast_group_stream_param *param,
23572387
struct bt_bap_iso *iso, enum bt_audio_dir dir)
@@ -2372,20 +2402,7 @@ static void unicast_group_add_stream(struct bt_bap_unicast_group *group,
23722402
bt_bap_iso_bind_ep(iso, stream->ep);
23732403
}
23742404

2375-
/* Store the stream Codec QoS in the bap_iso */
2376-
unicast_client_codec_qos_to_iso_qos(iso, qos, dir);
2377-
2378-
/* Store the group Codec QoS in the group - This assume thats the parameters have been
2379-
* verified first
2380-
*/
2381-
group->cig_param.framing = qos->framing;
2382-
if (dir == BT_AUDIO_DIR_SOURCE) {
2383-
group->cig_param.p_to_c_interval = qos->interval;
2384-
group->cig_param.p_to_c_latency = qos->latency;
2385-
} else {
2386-
group->cig_param.c_to_p_interval = qos->interval;
2387-
group->cig_param.c_to_p_latency = qos->latency;
2388-
}
2405+
unicast_group_set_iso_stream_param(group, iso, qos, dir);
23892406

23902407
sys_slist_append(&group->streams, &stream->_node);
23912408
}
@@ -2574,7 +2591,8 @@ static int stream_pair_param_check(const struct bt_bap_unicast_group_stream_pair
25742591
}
25752592

25762593
/** Validates that the stream parameter does not contain invalid values */
2577-
static bool valid_unicast_group_stream_param(const struct bt_bap_unicast_group_stream_param *param,
2594+
static bool valid_unicast_group_stream_param(const struct bt_bap_unicast_group *unicast_group,
2595+
const struct bt_bap_unicast_group_stream_param *param,
25782596
struct bt_bap_unicast_group_cig_param *cig_param,
25792597
enum bt_audio_dir dir)
25802598
{
@@ -2591,7 +2609,13 @@ static bool valid_unicast_group_stream_param(const struct bt_bap_unicast_group_s
25912609
}
25922610

25932611
if (param->stream != NULL && param->stream->group != NULL) {
2594-
LOG_DBG("stream %p already part of group %p", param->stream, param->stream->group);
2612+
if (unicast_group != NULL && param->stream->group != unicast_group) {
2613+
LOG_DBG("stream %p not part of group %p (%p)", param->stream, unicast_group,
2614+
param->stream->group);
2615+
} else {
2616+
LOG_DBG("stream %p already part of group %p", param->stream,
2617+
param->stream->group);
2618+
}
25952619
return -EALREADY;
25962620
}
25972621

@@ -2659,23 +2683,23 @@ valid_group_stream_pair_param(const struct bt_bap_unicast_group *unicast_group,
26592683
}
26602684

26612685
if (pair_param->rx_param != NULL) {
2662-
if (!valid_unicast_group_stream_param(pair_param->rx_param, &cig_param,
2663-
BT_AUDIO_DIR_SOURCE)) {
2686+
if (!valid_unicast_group_stream_param(unicast_group, pair_param->rx_param,
2687+
&cig_param, BT_AUDIO_DIR_SOURCE)) {
26642688
return false;
26652689
}
26662690
}
26672691

26682692
if (pair_param->tx_param != NULL) {
2669-
if (!valid_unicast_group_stream_param(pair_param->tx_param, &cig_param,
2670-
BT_AUDIO_DIR_SINK)) {
2693+
if (!valid_unicast_group_stream_param(unicast_group, pair_param->tx_param,
2694+
&cig_param, BT_AUDIO_DIR_SINK)) {
26712695
return false;
26722696
}
26732697
}
26742698

26752699
return true;
26762700
}
26772701

2678-
static bool valid_unicast_group_param(const struct bt_bap_unicast_group *unicast_group,
2702+
static bool valid_unicast_group_param(struct bt_bap_unicast_group *unicast_group,
26792703
const struct bt_bap_unicast_group_param *param)
26802704
{
26812705
CHECKIF(param == NULL) {
@@ -2689,6 +2713,17 @@ static bool valid_unicast_group_param(const struct bt_bap_unicast_group *unicast
26892713
return false;
26902714
}
26912715

2716+
if (unicast_group != NULL) {
2717+
const size_t group_cis_cnt = unicast_group_get_cis_count(unicast_group);
2718+
2719+
if (param->params_count != group_cis_cnt) {
2720+
LOG_DBG("Mismatch between group CIS count (%zu) and params_count (%zu)",
2721+
group_cis_cnt, param->params_count);
2722+
2723+
return false;
2724+
}
2725+
}
2726+
26922727
for (size_t i = 0U; i < param->params_count; i++) {
26932728
if (!valid_group_stream_pair_param(unicast_group, &param->params[i])) {
26942729
return false;
@@ -2718,7 +2753,7 @@ int bt_bap_unicast_group_create(struct bt_bap_unicast_group_param *param,
27182753
return -ENOMEM;
27192754
}
27202755

2721-
if (!valid_unicast_group_param(unicast_group, param)) {
2756+
if (!valid_unicast_group_param(NULL, param)) {
27222757
unicast_group_free(unicast_group);
27232758

27242759
return -EINVAL;
@@ -2758,6 +2793,91 @@ int bt_bap_unicast_group_create(struct bt_bap_unicast_group_param *param,
27582793
return 0;
27592794
}
27602795

2796+
int bt_bap_unicast_group_reconfig(struct bt_bap_unicast_group *unicast_group,
2797+
const struct bt_bap_unicast_group_param *param)
2798+
{
2799+
struct bt_iso_chan_io_qos rx_io_qos_backup[UNICAST_GROUP_STREAM_CNT];
2800+
struct bt_iso_chan_io_qos tx_io_qos_backup[UNICAST_GROUP_STREAM_CNT];
2801+
struct bt_bap_unicast_group_cig_param cig_param_backup;
2802+
struct bt_bap_stream *tmp_stream;
2803+
size_t idx;
2804+
int err;
2805+
2806+
IF_ENABLED(CONFIG_BT_ISO_TEST_PARAMS,
2807+
(uint8_t num_subevents_backup[UNICAST_GROUP_STREAM_CNT]));
2808+
2809+
CHECKIF(unicast_group == NULL) {
2810+
LOG_DBG("unicast_group is NULL");
2811+
return -EINVAL;
2812+
}
2813+
2814+
if (unicast_group->has_been_connected) {
2815+
LOG_DBG("Cannot modify a unicast_group where a CIS has been connected");
2816+
return -EINVAL;
2817+
}
2818+
2819+
if (!valid_unicast_group_param(unicast_group, param)) {
2820+
return -EINVAL;
2821+
}
2822+
2823+
/* Make backups of the values in case that the reconfigure request is rejected by e.g. the
2824+
* controller
2825+
*/
2826+
idx = 0U;
2827+
SYS_SLIST_FOR_EACH_CONTAINER(&unicast_group->streams, tmp_stream, _node) {
2828+
memcpy(&rx_io_qos_backup[idx], tmp_stream->bap_iso->chan.qos->rx,
2829+
sizeof(rx_io_qos_backup[idx]));
2830+
memcpy(&tx_io_qos_backup[idx], tmp_stream->bap_iso->chan.qos->tx,
2831+
sizeof(tx_io_qos_backup[idx]));
2832+
IF_ENABLED(
2833+
CONFIG_BT_ISO_TEST_PARAMS,
2834+
(num_subevents_backup[idx] = tmp_stream->bap_iso->chan.qos->num_subevents));
2835+
idx++;
2836+
}
2837+
memcpy(&cig_param_backup, &unicast_group->cig_param, sizeof(cig_param_backup));
2838+
2839+
/* Update the stream and group parameters */
2840+
for (size_t i = 0U; i < param->params_count; i++) {
2841+
struct bt_bap_unicast_group_stream_pair_param *stream_param = &param->params[i];
2842+
struct bt_bap_unicast_group_stream_param *rx_param = stream_param->rx_param;
2843+
struct bt_bap_unicast_group_stream_param *tx_param = stream_param->tx_param;
2844+
2845+
if (rx_param != NULL) {
2846+
unicast_group_set_iso_stream_param(unicast_group, rx_param->stream->bap_iso,
2847+
rx_param->qos, BT_AUDIO_DIR_SOURCE);
2848+
}
2849+
2850+
if (tx_param != NULL) {
2851+
unicast_group_set_iso_stream_param(unicast_group, tx_param->stream->bap_iso,
2852+
tx_param->qos, BT_AUDIO_DIR_SOURCE);
2853+
}
2854+
}
2855+
2856+
/* Reconfigure the CIG based on the above new values */
2857+
err = bt_audio_cig_reconfigure(unicast_group);
2858+
if (err != 0) {
2859+
LOG_DBG("bt_audio_cig_reconfigure failed: %d", err);
2860+
2861+
/* Revert any changes above */
2862+
memcpy(&unicast_group->cig_param, &cig_param_backup, sizeof(cig_param_backup));
2863+
idx = 0U;
2864+
SYS_SLIST_FOR_EACH_CONTAINER(&unicast_group->streams, tmp_stream, _node) {
2865+
memcpy(tmp_stream->bap_iso->chan.qos->rx, &rx_io_qos_backup[idx],
2866+
sizeof(rx_io_qos_backup[idx]));
2867+
memcpy(tmp_stream->bap_iso->chan.qos->tx, &tx_io_qos_backup[idx],
2868+
sizeof(tx_io_qos_backup[idx]));
2869+
IF_ENABLED(CONFIG_BT_ISO_TEST_PARAMS,
2870+
(tmp_stream->bap_iso->chan.qos->num_subevents =
2871+
num_subevents_backup[idx]));
2872+
idx++;
2873+
}
2874+
2875+
return err;
2876+
}
2877+
2878+
return 0;
2879+
}
2880+
27612881
int bt_bap_unicast_group_add_streams(struct bt_bap_unicast_group *unicast_group,
27622882
struct bt_bap_unicast_group_stream_pair_param params[],
27632883
size_t num_param)
@@ -2774,6 +2894,11 @@ int bt_bap_unicast_group_add_streams(struct bt_bap_unicast_group *unicast_group,
27742894
return -EINVAL;
27752895
}
27762896

2897+
if (unicast_group->has_been_connected) {
2898+
LOG_DBG("Cannot modify a unicast_group where a CIS has been connected");
2899+
return -EINVAL;
2900+
}
2901+
27772902
CHECKIF(params == NULL)
27782903
{
27792904
LOG_DBG("params is NULL");

0 commit comments

Comments
 (0)