Bluetooth: CAP: Shell: Initiator fix chan_alloc

When using the CAP initiator shell AC commands, the channel
allocation were not done correctly, leading to cases where
we attempted to set e.g. 2 LEFT streams for the same device.

Signed-off-by: Emil Gydesen <emil.gydesen@nordicsemi.no>
This commit is contained in:
Emil Gydesen 2024-04-26 11:10:29 +02:00 committed by Anas Nashif
commit 7d4c13f55f

View file

@ -623,23 +623,6 @@ static int cap_ac_unicast_start(const struct bap_unicast_ac_param *param,
snk_stream_cnt++;
stream_cnt++;
/* If we have more than 1 connection or stream in one direction, we set the
* location bit accordingly
*/
if (param->conn_cnt > 1U || param->snk_cnt[i] > 1U) {
const int err = bt_audio_codec_cfg_set_chan_allocation(
stream_param->codec_cfg, (enum bt_audio_location)BIT(i));
if (err < 0) {
shell_error(ctx_shell,
"Failed to set channel allocation for "
"snk[%zu][%zu]: %d",
i, j, err);
return err;
}
}
}
for (size_t j = 0U; j < param->src_cnt[i]; j++) {
@ -653,23 +636,6 @@ static int cap_ac_unicast_start(const struct bap_unicast_ac_param *param,
src_stream_cnt++;
stream_cnt++;
/* If we have more than 1 connection or stream in one direction, we set the
* location bit accordingly
*/
if (param->conn_cnt > 1U || param->src_cnt[i] > 1U) {
const int err = bt_audio_codec_cfg_set_chan_allocation(
stream_param->codec_cfg, (enum bt_audio_location)BIT(i));
if (err < 0) {
shell_error(ctx_shell,
"Failed to set channel allocation for "
"src[%zu][%zu]: %d",
i, j, err);
return err;
}
}
}
}
@ -680,6 +646,82 @@ static int cap_ac_unicast_start(const struct bap_unicast_ac_param *param,
return bt_cap_initiator_unicast_audio_start(&start_param);
}
static int set_codec_config(const struct shell *sh, struct shell_stream *sh_stream,
struct named_lc3_preset *preset, size_t conn_cnt, size_t ep_cnt,
size_t chan_cnt, size_t conn_index, size_t ep_index)
{
enum bt_audio_location new_chan_alloc;
enum bt_audio_location chan_alloc;
int err;
copy_unicast_stream_preset(sh_stream, preset);
if (chan_cnt == 1U) {
/* - When we have a single channel on a single connection then we make it mono
* - When we have a single channel on a multiple connections then we make it left on
* the first connection and right on the second connection
* - When we have multiple channels streams for a connection, we make them either
* left or right, regardless of the connection count
*/
if (ep_cnt == 1) {
if (conn_cnt == 1) {
new_chan_alloc = BT_AUDIO_LOCATION_MONO_AUDIO;
} else if (conn_cnt == 2) {
if (conn_index == 0) {
new_chan_alloc = BT_AUDIO_LOCATION_FRONT_LEFT;
} else if (conn_index == 1) {
new_chan_alloc = BT_AUDIO_LOCATION_FRONT_RIGHT;
} else {
return 0;
}
} else {
return 0;
}
} else if (ep_cnt == 2) {
if (ep_index == 0) {
new_chan_alloc = BT_AUDIO_LOCATION_FRONT_LEFT;
} else if (ep_index == 1) {
new_chan_alloc = BT_AUDIO_LOCATION_FRONT_RIGHT;
} else {
return 0;
}
} else {
return 0;
}
} else if (chan_cnt == 2U) {
/* Some audio configuration requires multiple sink channels,
* so multiply the SDU based on the channel count
*/
sh_stream->qos.sdu *= chan_cnt;
/* If a stream has 2 channels, we make it stereo */
new_chan_alloc = BT_AUDIO_LOCATION_FRONT_LEFT | BT_AUDIO_LOCATION_FRONT_RIGHT;
} else {
return 0;
}
err = bt_audio_codec_cfg_get_chan_allocation(&sh_stream->codec_cfg, &chan_alloc);
if (err != 0) {
if (err == -ENODATA) {
chan_alloc = BT_AUDIO_LOCATION_MONO_AUDIO;
}
}
if (chan_alloc != new_chan_alloc) {
shell_info(sh,
"[%zu][%zu]: Overwriting existing channel allocation 0x%08X with 0x%08X",
conn_index, ep_index, chan_alloc, new_chan_alloc);
err = bt_audio_codec_cfg_set_chan_allocation(&sh_stream->codec_cfg, new_chan_alloc);
if (err < 0) {
return err;
}
}
return 0;
}
int cap_ac_unicast(const struct shell *sh, const struct bap_unicast_ac_param *param)
{
/* Allocate params large enough for any params, but only use what is required */
@ -735,10 +777,36 @@ int cap_ac_unicast(const struct shell *sh, const struct bap_unicast_ac_param *pa
*/
for (size_t i = 0U; i < param->conn_cnt; i++) {
for (size_t j = 0U; j < param->snk_cnt[i]; j++) {
struct shell_stream *snk_uni_stream;
snk_uni_stream = snk_uni_streams[snk_cnt] = &unicast_streams[snk_cnt];
err = set_codec_config(sh, snk_uni_stream, &default_sink_preset,
param->conn_cnt, param->snk_cnt[i],
param->snk_chan_cnt, i, j);
if (err != 0) {
shell_error(sh, "Failed to set codec configuration: %d", err);
return -ENOEXEC;
}
snk_cnt++;
}
for (size_t j = 0U; j < param->src_cnt[i]; j++) {
struct shell_stream *src_uni_stream;
src_uni_stream = snk_uni_streams[src_cnt] = &unicast_streams[src_cnt];
err = set_codec_config(sh, src_uni_stream, &default_source_preset,
param->conn_cnt, param->src_cnt[i],
param->src_chan_cnt, i, j);
if (err != 0) {
shell_error(sh, "Failed to set codec configuration: %d", err);
return -ENOEXEC;
}
src_cnt++;
}
}
@ -747,37 +815,6 @@ int cap_ac_unicast(const struct shell *sh, const struct bap_unicast_ac_param *pa
ctx_shell = sh;
}
/* Setup arrays of parameters based on the preset for easier access. This also copies the
* preset so that we can modify them (e.g. update the metadata)
*/
for (size_t i = 0U; i < snk_cnt; i++) {
struct shell_stream *snk_uni_stream = snk_uni_streams[i] = &unicast_streams[i];
if (snk_uni_stream->stream.bap_stream.conn != NULL) {
shell_error(sh, "unicast_streams[%zu] already in use", i);
return -ENOEXEC;
}
copy_unicast_stream_preset(snk_uni_stream, &default_sink_preset);
/* Some audio configuration requires multiple sink channels,
* so multiply the SDU based on the channel count
*/
snk_uni_stream->qos.sdu *= param->snk_chan_cnt;
}
for (size_t i = 0U; i < src_cnt; i++) {
struct shell_stream *src_uni_stream = src_uni_streams[i] =
&unicast_streams[i + snk_cnt];
if (src_uni_stream->stream.bap_stream.conn != NULL) {
shell_error(sh, "unicast_streams[%zu] already in use", i + snk_cnt);
return -ENOEXEC;
}
copy_unicast_stream_preset(src_uni_stream, &default_source_preset);
}
err = bap_ac_create_unicast_group(param, snk_uni_streams, snk_cnt, src_uni_streams,
src_cnt);
if (err != 0) {