Bluetooth: CAP: Do not require CAS unless necessary

Removes the requirement that CAS is found on the remove
device for ad-hoc sets. This makes the CAP API more
versatile as it allows applications to use it with
remote non-CAP devices.

Signed-off-by: Emil Gydesen <emil.gydesen@nordicsemi.no>
This commit is contained in:
Emil Gydesen 2024-05-29 17:14:52 +02:00 committed by Carles Cufí
commit 1af717430a
7 changed files with 74 additions and 144 deletions

View file

@ -113,6 +113,10 @@ Bluetooth
The public_broadcast_sink sample has been renamed to pbp_public_broadcast_sink.
The public_broadcast_source sample has been renamed to pbp_public_broadcast_source.
* The CAP Commander and CAP Initiator now no longer require CAS to be discovered for
:code:`BT_CAP_SET_TYPE_AD_HOC` sets. This allows applications to use these APIs on e.g.
BAP Unicast Servers that do not implement the CAP Acceptor role.
* Host
* Added Nordic UART Service (NUS), enabled by the :kconfig:option:`CONFIG_BT_ZEPHYR_NUS`.

View file

@ -200,15 +200,15 @@ static bool valid_broadcast_reception_start_param(
const struct bt_cap_commander_broadcast_reception_start_member_param *start_param =
&param->param[i];
const union bt_cap_set_member *member = &param->param[i].member;
const struct bt_cap_common_client *client =
bt_cap_common_get_client(param->type, member);
const struct bt_conn *member_conn =
bt_cap_common_get_member_conn(param->type, member);
if (member == NULL) {
LOG_DBG("param->param[%zu].member is NULL", i);
return false;
}
if (client == NULL) {
if (member_conn == NULL) {
LOG_DBG("Invalid param->param[%zu].member", i);
return false;
}
@ -509,15 +509,20 @@ static bool valid_change_volume_param(const struct bt_cap_commander_change_volum
for (size_t i = 0U; i < param->count; i++) {
const union bt_cap_set_member *member = &param->members[i];
const struct bt_cap_common_client *client =
bt_cap_common_get_client(param->type, member);
const struct bt_conn *member_conn =
bt_cap_common_get_member_conn(param->type, member);
if (client == NULL) {
if (member == NULL) {
LOG_DBG("param->members[%zu] is NULL", i);
return false;
}
if (member_conn == NULL) {
LOG_DBG("Invalid param->members[%zu]", i);
return false;
}
if (bt_vcp_vol_ctlr_get_by_conn(client->conn) == NULL) {
if (bt_vcp_vol_ctlr_get_by_conn(member_conn) == NULL) {
LOG_DBG("Volume control not available for param->members[%zu]", i);
return false;
}
@ -678,15 +683,20 @@ static bool valid_change_volume_mute_state_param(
for (size_t i = 0U; i < param->count; i++) {
const union bt_cap_set_member *member = &param->members[i];
const struct bt_cap_common_client *client =
bt_cap_common_get_client(param->type, member);
const struct bt_conn *member_conn =
bt_cap_common_get_member_conn(param->type, member);
CHECKIF(client == NULL) {
if (member == NULL) {
LOG_DBG("param->members[%zu] is NULL", i);
return false;
}
if (member_conn == NULL) {
LOG_DBG("Invalid param->members[%zu]", i);
return false;
}
CHECKIF(bt_vcp_vol_ctlr_get_by_conn(client->conn) == NULL) {
CHECKIF(bt_vcp_vol_ctlr_get_by_conn(member_conn) == NULL) {
LOG_DBG("Volume control not available for param->members[%zu]", i);
return false;
}
@ -861,18 +871,23 @@ valid_change_offset_param(const struct bt_cap_commander_change_volume_offset_par
const struct bt_cap_commander_change_volume_offset_member_param *member_param =
&param->param[i];
const union bt_cap_set_member *member = &member_param->member;
const struct bt_cap_common_client *client =
bt_cap_common_get_client(param->type, member);
const struct bt_conn *member_conn =
bt_cap_common_get_member_conn(param->type, member);
struct bt_vcp_vol_ctlr *vol_ctlr;
struct bt_vcp_included included;
int err;
if (client == NULL) {
if (member == NULL) {
LOG_DBG("param->param[%zu].member is NULL", i);
return false;
}
if (member_conn == NULL) {
LOG_DBG("Invalid param->param[%zu].member", i);
return false;
}
vol_ctlr = bt_vcp_vol_ctlr_get_by_conn(client->conn);
vol_ctlr = bt_vcp_vol_ctlr_get_by_conn(member_conn);
if (vol_ctlr == NULL) {
LOG_DBG("Volume control not available for param->param[%zu].member", i);
return false;
@ -1091,15 +1106,20 @@ static bool valid_change_microphone_mute_state_param(
for (size_t i = 0U; i < param->count; i++) {
const union bt_cap_set_member *member = &param->members[i];
const struct bt_cap_common_client *client =
bt_cap_common_get_client(param->type, member);
const struct bt_conn *member_conn =
bt_cap_common_get_member_conn(param->type, member);
CHECKIF(client == NULL) {
if (member == NULL) {
LOG_DBG("param->members[%zu] is NULL", i);
return false;
}
if (member_conn == NULL) {
LOG_DBG("Invalid param->members[%zu]", i);
return false;
}
CHECKIF(bt_micp_mic_ctlr_get_by_conn(client->conn) == NULL) {
CHECKIF(bt_micp_mic_ctlr_get_by_conn(member_conn) == NULL) {
LOG_DBG("Microphone control not available for param->members[%zu]", i);
return false;
}
@ -1272,18 +1292,23 @@ static bool valid_change_microphone_gain_param(
for (size_t i = 0U; i < param->count; i++) {
const union bt_cap_set_member *member = &param->param[i].member;
const struct bt_cap_common_client *client =
bt_cap_common_get_client(param->type, member);
const struct bt_conn *member_conn =
bt_cap_common_get_member_conn(param->type, member);
struct bt_micp_mic_ctlr *mic_ctlr;
struct bt_micp_included included;
int err;
if (client == NULL) {
if (member == NULL) {
LOG_DBG("param->param[%zu].member is NULL", i);
return false;
}
if (member_conn == NULL) {
LOG_DBG("Invalid param->param[%zu].member", i);
return false;
}
mic_ctlr = bt_micp_mic_ctlr_get_by_conn(client->conn);
mic_ctlr = bt_micp_mic_ctlr_get_by_conn(member_conn);
if (mic_ctlr == NULL) {
LOG_DBG("Microphone control not available for param->param[%zu].member", i);
return false;

View file

@ -54,16 +54,23 @@ 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)
{
if (member == NULL) {
return NULL;
}
if (type == BT_CAP_SET_TYPE_CSIP) {
struct bt_cap_common_client *client;
/* We have verified that `client` won't be NULL in
* `valid_change_volume_param`.
*/
client = bt_cap_common_get_client_by_csis(member->csip);
if (client != NULL) {
return client->conn;
if (client == NULL) {
return NULL;
}
return client->conn;
}
return member->member;
@ -222,44 +229,6 @@ bt_cap_common_get_client_by_csis(const struct bt_csip_set_coordinator_csis_inst
return NULL;
}
struct bt_cap_common_client *bt_cap_common_get_client(enum bt_cap_set_type type,
const union bt_cap_set_member *member)
{
struct bt_cap_common_client *client = NULL;
if (member == NULL) {
LOG_DBG("member is NULL");
return NULL;
}
if (type == BT_CAP_SET_TYPE_AD_HOC) {
CHECKIF(member->member == NULL) {
LOG_DBG("member->member is NULL");
return NULL;
}
client = bt_cap_common_get_client_by_acl(member->member);
} else if (type == BT_CAP_SET_TYPE_CSIP) {
CHECKIF(member->csip == NULL) {
LOG_DBG("member->csip is NULL");
return NULL;
}
client = bt_cap_common_get_client_by_csis(member->csip);
if (client == NULL) {
LOG_DBG("CSIS was not found for member");
return NULL;
}
}
if (client == NULL || !client->cas_found) {
LOG_DBG("CAS was not found for member %p", member);
return NULL;
}
return client;
}
static void cap_common_discover_complete(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)
@ -367,7 +336,6 @@ static uint8_t bt_cap_common_discover_cas_cb(struct bt_conn *conn, const struct
CONTAINER_OF(params, struct bt_cap_common_client, param);
int err;
client->cas_found = true;
client->conn = bt_conn_ref(conn);
if (attr->handle == prim_service->end_handle) {

View file

@ -367,10 +367,15 @@ static bool valid_unicast_audio_start_param(const struct bt_cap_unicast_audio_st
const struct bt_cap_stream *cap_stream = stream_param->stream;
const struct bt_audio_codec_cfg *codec_cfg = stream_param->codec_cfg;
const struct bt_bap_stream *bap_stream;
const struct bt_cap_common_client *client =
bt_cap_common_get_client(param->type, member);
const struct bt_conn *member_conn =
bt_cap_common_get_member_conn(param->type, member);
if (client == NULL) {
if (member == NULL) {
LOG_DBG("param->members[%zu] is NULL", i);
return false;
}
if (member_conn == NULL) {
LOG_DBG("Invalid param->members[%zu]", i);
return false;
}
@ -922,7 +927,6 @@ static bool valid_unicast_audio_update_param(const struct bt_cap_unicast_audio_u
&param->stream_params[i];
const struct bt_cap_stream *cap_stream = stream_param->stream;
const struct bt_bap_stream *bap_stream;
struct bt_cap_common_client *client;
struct bt_conn *conn;
CHECKIF(cap_stream == NULL) {
@ -938,12 +942,6 @@ static bool valid_unicast_audio_update_param(const struct bt_cap_unicast_audio_u
return -EINVAL;
}
client = bt_cap_common_get_client_by_acl(conn);
if (!client->cas_found) {
LOG_DBG("CAS was not found for param->stream_params[%zu].stream", i);
return false;
}
CHECKIF(bap_stream->group == NULL) {
LOG_DBG("param->stream_params[%zu] is not in a unicast group", i);
return false;
@ -1164,7 +1162,6 @@ static bool valid_unicast_audio_stop_param(const struct bt_cap_unicast_audio_sto
for (size_t i = 0U; i < param->count; i++) {
const struct bt_cap_stream *cap_stream = param->streams[i];
const struct bt_bap_stream *bap_stream;
struct bt_cap_common_client *client;
struct bt_conn *conn;
CHECKIF(cap_stream == NULL) {
@ -1180,12 +1177,6 @@ static bool valid_unicast_audio_stop_param(const struct bt_cap_unicast_audio_sto
return -EINVAL;
}
client = bt_cap_common_get_client_by_acl(conn);
if (!client->cas_found) {
LOG_DBG("CAS was not found for param->streams[%zu]", i);
return false;
}
CHECKIF(bap_stream->group == NULL) {
LOG_DBG("param->streams[%zu] is not in a unicast group", i);
return false;

View file

@ -156,7 +156,6 @@ struct bt_cap_common_client {
bt_cap_common_discover_func_t discover_cb_func;
uint16_t csis_start_handle;
const struct bt_csip_set_coordinator_csis_inst *csis_inst;
bool cas_found;
};
struct bt_cap_common_proc *bt_cap_common_get_active_proc(void);
@ -177,6 +176,4 @@ 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);
struct bt_cap_common_client *bt_cap_common_get_client(enum bt_cap_set_type type,
const union bt_cap_set_member *member);
int bt_cap_common_discover(struct bt_conn *conn, bt_cap_common_discover_func_t func);

View file

@ -91,9 +91,6 @@ ZTEST_F(cap_commander_test_micp, test_commander_change_microphone_gain_setting)
for (size_t i = 0; i < ARRAY_SIZE(fixture->conns); i++) {
struct bt_micp_mic_ctlr *mic_ctlr; /* We don't care about this */
err = bt_cap_commander_discover(&fixture->conns[i]);
zassert_equal(0, err, "Unexpected return value %d", err);
err = bt_micp_mic_ctlr_discover(&fixture->conns[i], &mic_ctlr);
zassert_equal(0, err, "Unexpected return value %d", err);
}
@ -127,9 +124,6 @@ ZTEST_F(cap_commander_test_micp, test_commander_change_microphone_gain_setting_d
for (size_t i = 0; i < ARRAY_SIZE(fixture->conns); i++) {
struct bt_micp_mic_ctlr *mic_ctlr; /* We don't care about this */
err = bt_cap_commander_discover(&fixture->conns[i]);
zassert_equal(0, err, "Unexpected return value %d", err);
err = bt_micp_mic_ctlr_discover(&fixture->conns[i], &mic_ctlr);
zassert_equal(0, err, "Unexpected return value %d", err);
}
@ -197,7 +191,7 @@ ZTEST_F(cap_commander_test_micp, test_commander_change_microphone_gain_setting_i
struct bt_cap_commander_change_microphone_gain_setting_member_param
member_params[ARRAY_SIZE(fixture->conns)];
const struct bt_cap_commander_change_microphone_gain_setting_param param = {
.type = BT_CAP_SET_TYPE_AD_HOC,
.type = BT_CAP_SET_TYPE_CSIP,
.param = member_params,
.count = ARRAY_SIZE(member_params),
};
@ -241,11 +235,6 @@ ZTEST_F(cap_commander_test_micp, test_commander_change_microphone_gain_setting_i
err = bt_cap_commander_register_cb(&mock_cap_commander_cb);
zassert_equal(0, err, "Unexpected return value %d", err);
for (size_t i = 0; i < ARRAY_SIZE(fixture->conns); i++) {
err = bt_cap_commander_discover(&fixture->conns[i]);
zassert_equal(0, err, "Unexpected return value %d", err);
}
err = bt_cap_commander_change_microphone_gain_setting(&param);
zassert_equal(-EINVAL, err, "Unexpected return value %d", err);
}
@ -313,9 +302,6 @@ ZTEST_F(cap_commander_test_micp, test_commander_change_microphone_mute_state)
for (size_t i = 0; i < ARRAY_SIZE(fixture->conns); i++) {
struct bt_micp_mic_ctlr *mic_ctlr; /* We don't care about this */
err = bt_cap_commander_discover(&fixture->conns[i]);
zassert_equal(0, err, "Unexpected return value %d", err);
err = bt_micp_mic_ctlr_discover(&fixture->conns[i], &mic_ctlr);
zassert_equal(0, err, "Unexpected return value %d", err);
}
@ -348,9 +334,6 @@ ZTEST_F(cap_commander_test_micp, test_commander_change_microphone_mute_state_dou
for (size_t i = 0; i < ARRAY_SIZE(fixture->conns); i++) {
struct bt_micp_mic_ctlr *mic_ctlr; /* We don't care about this */
err = bt_cap_commander_discover(&fixture->conns[i]);
zassert_equal(0, err, "Unexpected return value %d", err);
err = bt_micp_mic_ctlr_discover(&fixture->conns[i], &mic_ctlr);
zassert_equal(0, err, "Unexpected return value %d", err);
}
@ -417,7 +400,7 @@ ZTEST_F(cap_commander_test_micp, test_commander_change_microphone_mute_state_inv
{
union bt_cap_set_member members[ARRAY_SIZE(fixture->conns)];
const struct bt_cap_commander_change_microphone_mute_state_param param = {
.type = BT_CAP_SET_TYPE_AD_HOC,
.type = BT_CAP_SET_TYPE_CSIP,
.members = members,
.count = ARRAY_SIZE(fixture->conns),
.mute = true,
@ -460,11 +443,6 @@ ZTEST_F(cap_commander_test_micp, test_commander_change_microphone_mute_state_inv
err = bt_cap_commander_register_cb(&mock_cap_commander_cb);
zassert_equal(0, err, "Unexpected return value %d", err);
for (size_t i = 0; i < ARRAY_SIZE(fixture->conns); i++) {
err = bt_cap_commander_discover(&fixture->conns[i]);
zassert_equal(0, err, "Unexpected return value %d", err);
}
err = bt_cap_commander_change_microphone_mute_state(&param);
zassert_equal(-EINVAL, err, "Unexpected return value %d", err);
}

View file

@ -89,9 +89,6 @@ ZTEST_F(cap_commander_test_vcp, test_commander_change_volume)
for (size_t i = 0; i < ARRAY_SIZE(fixture->conns); i++) {
struct bt_vcp_vol_ctlr *vol_ctlr; /* We don't care about this */
err = bt_cap_commander_discover(&fixture->conns[i]);
zassert_equal(0, err, "Unexpected return value %d", err);
err = bt_vcp_vol_ctlr_discover(&fixture->conns[i], &vol_ctlr);
zassert_equal(0, err, "Unexpected return value %d", err);
}
@ -124,9 +121,6 @@ ZTEST_F(cap_commander_test_vcp, test_commander_change_volume_double)
for (size_t i = 0; i < ARRAY_SIZE(fixture->conns); i++) {
struct bt_vcp_vol_ctlr *vol_ctlr; /* We don't care about this */
err = bt_cap_commander_discover(&fixture->conns[i]);
zassert_equal(0, err, "Unexpected return value %d", err);
err = bt_vcp_vol_ctlr_discover(&fixture->conns[i], &vol_ctlr);
zassert_equal(0, err, "Unexpected return value %d", err);
}
@ -191,7 +185,7 @@ ZTEST_F(cap_commander_test_vcp, test_commander_change_volume_inval_missing_cas)
{
union bt_cap_set_member members[ARRAY_SIZE(fixture->conns)];
const struct bt_cap_commander_change_volume_param param = {
.type = BT_CAP_SET_TYPE_AD_HOC,
.type = BT_CAP_SET_TYPE_CSIP,
.members = members,
.count = ARRAY_SIZE(fixture->conns),
.volume = 177,
@ -234,11 +228,6 @@ ZTEST_F(cap_commander_test_vcp, test_commander_change_volume_inval_missing_vcs)
err = bt_cap_commander_register_cb(&mock_cap_commander_cb);
zassert_equal(0, err, "Unexpected return value %d", err);
for (size_t i = 0; i < ARRAY_SIZE(fixture->conns); i++) {
err = bt_cap_commander_discover(&fixture->conns[i]);
zassert_equal(0, err, "Unexpected return value %d", err);
}
err = bt_cap_commander_change_volume(&param);
zassert_equal(-EINVAL, err, "Unexpected return value %d", err);
}
@ -303,9 +292,6 @@ ZTEST_F(cap_commander_test_vcp, test_commander_change_volume_offset)
for (size_t i = 0; i < ARRAY_SIZE(fixture->conns); i++) {
struct bt_vcp_vol_ctlr *vol_ctlr; /* We don't care about this */
err = bt_cap_commander_discover(&fixture->conns[i]);
zassert_equal(0, err, "Unexpected return value %d", err);
err = bt_vcp_vol_ctlr_discover(&fixture->conns[i], &vol_ctlr);
zassert_equal(0, err, "Unexpected return value %d", err);
}
@ -339,9 +325,6 @@ ZTEST_F(cap_commander_test_vcp, test_commander_change_volume_offset_double)
for (size_t i = 0; i < ARRAY_SIZE(fixture->conns); i++) {
struct bt_vcp_vol_ctlr *vol_ctlr; /* We don't care about this */
err = bt_cap_commander_discover(&fixture->conns[i]);
zassert_equal(0, err, "Unexpected return value %d", err);
err = bt_vcp_vol_ctlr_discover(&fixture->conns[i], &vol_ctlr);
zassert_equal(0, err, "Unexpected return value %d", err);
}
@ -407,7 +390,7 @@ ZTEST_F(cap_commander_test_vcp, test_commander_change_volume_offset_inval_missin
struct bt_cap_commander_change_volume_offset_member_param
member_params[ARRAY_SIZE(fixture->conns)];
const struct bt_cap_commander_change_volume_offset_param param = {
.type = BT_CAP_SET_TYPE_AD_HOC,
.type = BT_CAP_SET_TYPE_CSIP,
.param = member_params,
.count = ARRAY_SIZE(member_params),
};
@ -451,11 +434,6 @@ ZTEST_F(cap_commander_test_vcp, test_commander_change_volume_offset_inval_missin
err = bt_cap_commander_register_cb(&mock_cap_commander_cb);
zassert_equal(0, err, "Unexpected return value %d", err);
for (size_t i = 0; i < ARRAY_SIZE(fixture->conns); i++) {
err = bt_cap_commander_discover(&fixture->conns[i]);
zassert_equal(0, err, "Unexpected return value %d", err);
}
err = bt_cap_commander_change_volume_offset(&param);
zassert_equal(-EINVAL, err, "Unexpected return value %d", err);
}
@ -560,9 +538,6 @@ ZTEST_F(cap_commander_test_vcp, test_commander_change_volume_mute_state)
for (size_t i = 0; i < ARRAY_SIZE(fixture->conns); i++) {
struct bt_vcp_vol_ctlr *vol_ctlr; /* We don't care about this */
err = bt_cap_commander_discover(&fixture->conns[i]);
zassert_equal(0, err, "Unexpected return value %d", err);
err = bt_vcp_vol_ctlr_discover(&fixture->conns[i], &vol_ctlr);
zassert_equal(0, err, "Unexpected return value %d", err);
}
@ -595,9 +570,6 @@ ZTEST_F(cap_commander_test_vcp, test_commander_change_volume_mute_state_double)
for (size_t i = 0; i < ARRAY_SIZE(fixture->conns); i++) {
struct bt_vcp_vol_ctlr *vol_ctlr; /* We don't care about this */
err = bt_cap_commander_discover(&fixture->conns[i]);
zassert_equal(0, err, "Unexpected return value %d", err);
err = bt_vcp_vol_ctlr_discover(&fixture->conns[i], &vol_ctlr);
zassert_equal(0, err, "Unexpected return value %d", err);
}
@ -662,7 +634,7 @@ ZTEST_F(cap_commander_test_vcp, test_commander_change_volume_mute_state_inval_mi
{
union bt_cap_set_member members[ARRAY_SIZE(fixture->conns)];
const struct bt_cap_commander_change_volume_mute_state_param param = {
.type = BT_CAP_SET_TYPE_AD_HOC,
.type = BT_CAP_SET_TYPE_CSIP,
.members = members,
.count = ARRAY_SIZE(fixture->conns),
.mute = true,
@ -705,11 +677,6 @@ ZTEST_F(cap_commander_test_vcp, test_commander_change_volume_mute_state_inval_mi
err = bt_cap_commander_register_cb(&mock_cap_commander_cb);
zassert_equal(0, err, "Unexpected return value %d", err);
for (size_t i = 0; i < ARRAY_SIZE(fixture->conns); i++) {
err = bt_cap_commander_discover(&fixture->conns[i]);
zassert_equal(0, err, "Unexpected return value %d", err);
}
err = bt_cap_commander_change_volume_mute_state(&param);
zassert_equal(-EINVAL, err, "Unexpected return value %d", err);
}