diff --git a/subsys/bluetooth/audio/cap_initiator.c b/subsys/bluetooth/audio/cap_initiator.c index 7362ea94341..46b39afcb41 100644 --- a/subsys/bluetooth/audio/cap_initiator.c +++ b/subsys/bluetooth/audio/cap_initiator.c @@ -10,6 +10,7 @@ #include #include #include "cap_internal.h" +#include "ccid_internal.h" #include "csip_internal.h" #include "bap_endpoint.h" @@ -38,9 +39,14 @@ int bt_cap_initiator_register_cb(const struct bt_cap_initiator_cb *cb) return 0; } +struct valid_metadata_param { + bool stream_context_found; + bool valid; +}; + static bool data_func_cb(struct bt_data *data, void *user_data) { - bool *stream_context_found = (bool *)user_data; + struct valid_metadata_param *metadata_param = (struct valid_metadata_param *)user_data; LOG_DBG("type %u len %u data %s", data->type, data->data_len, bt_hex(data->data, data->data_len)); @@ -50,8 +56,21 @@ static bool data_func_cb(struct bt_data *data, void *user_data) return false; } - *stream_context_found = true; - return false; + metadata_param->stream_context_found = true; + } else if (IS_ENABLED(CONFIG_BT_CCID) && data->type == BT_AUDIO_METADATA_TYPE_CCID_LIST) { + /* If the application supplies a CCID list, we verify that the CCIDs exist on our + * device + */ + for (uint8_t i = 0U; i < data->data_len; i++) { + const uint8_t ccid = data->data[i]; + + if (bt_ccid_find_attr(ccid) == NULL) { + LOG_DBG("Unknown characterstic for CCID 0x%02X", ccid); + metadata_param->valid = false; + + return false; + } + } } return true; @@ -59,21 +78,24 @@ static bool data_func_cb(struct bt_data *data, void *user_data) static bool cap_initiator_valid_metadata(const uint8_t meta[], size_t meta_len) { - bool stream_context_found = false; + struct valid_metadata_param metadata_param = { + .stream_context_found = false, + .valid = true, + }; int err; LOG_DBG("meta %p len %zu", meta, meta_len); - err = bt_audio_data_parse(meta, meta_len, data_func_cb, &stream_context_found); + err = bt_audio_data_parse(meta, meta_len, data_func_cb, &metadata_param); if (err != 0 && err != -ECANCELED) { return false; } - if (!stream_context_found) { + if (!metadata_param.stream_context_found) { LOG_DBG("No streaming context supplied"); } - return stream_context_found; + return metadata_param.stream_context_found && metadata_param.valid; } #if defined(CONFIG_BT_BAP_BROADCAST_SOURCE) diff --git a/subsys/bluetooth/audio/ccid.c b/subsys/bluetooth/audio/ccid.c index c7bd56db234..c3a9d6a2b42 100644 --- a/subsys/bluetooth/audio/ccid.c +++ b/subsys/bluetooth/audio/ccid.c @@ -6,6 +6,9 @@ * * SPDX-License-Identifier: Apache-2.0 */ +#include +#include +#include #include "ccid_internal.h" @@ -23,3 +26,41 @@ uint8_t bt_ccid_get_value(void) return ccid_value++; } + +struct ccid_search_param { + const struct bt_gatt_attr *attr; + uint8_t ccid; +}; + +static uint8_t ccid_attr_cb(const struct bt_gatt_attr *attr, uint16_t handle, void *user_data) +{ + struct ccid_search_param *search_param = user_data; + + if (attr->read != NULL) { + uint8_t ccid = 0U; + ssize_t res; + + res = attr->read(NULL, attr, &ccid, sizeof(ccid), 0); + + if (res == sizeof(ccid) && search_param->ccid == ccid) { + search_param->attr = attr; + + return BT_GATT_ITER_STOP; + } + } + + return BT_GATT_ITER_CONTINUE; +} + +const struct bt_gatt_attr *bt_ccid_find_attr(uint8_t ccid) +{ + struct ccid_search_param search_param = { + .attr = NULL, + .ccid = ccid, + }; + + bt_gatt_foreach_attr_type(BT_ATT_FIRST_ATTRIBUTE_HANDLE, BT_ATT_LAST_ATTRIBUTE_HANDLE, + BT_UUID_CCID, NULL, 0, ccid_attr_cb, &search_param); + + return search_param.attr; +} diff --git a/subsys/bluetooth/audio/ccid_internal.h b/subsys/bluetooth/audio/ccid_internal.h index e68b7bdb8f8..87cca3d7098 100644 --- a/subsys/bluetooth/audio/ccid_internal.h +++ b/subsys/bluetooth/audio/ccid_internal.h @@ -23,4 +23,16 @@ */ uint8_t bt_ccid_get_value(void); +/** + * @brief Get the GATT attribute of a CCID value + * + * Searches the current GATT database for a CCID characteristic that has the supplied CCID value. + * + * @param ccid The CCID the search for + * + * @retval NULL if none was found + * @retval A pointer to a GATT attribute if found + */ +const struct bt_gatt_attr *bt_ccid_find_attr(uint8_t ccid); + #endif /* ZEPHYR_INCLUDE_BLUETOOTH_CCID_H_ */ diff --git a/tests/bsim/bluetooth/audio/src/cap_initiator_broadcast_test.c b/tests/bsim/bluetooth/audio/src/cap_initiator_broadcast_test.c index 6e533255a19..b5c98ba1a9c 100644 --- a/tests/bsim/bluetooth/audio/src/cap_initiator_broadcast_test.c +++ b/tests/bsim/bluetooth/audio/src/cap_initiator_broadcast_test.c @@ -406,11 +406,18 @@ static void test_broadcast_audio_update_inval(struct bt_cap_broadcast_source *br static void test_broadcast_audio_update(struct bt_cap_broadcast_source *broadcast_source) { - const uint16_t mock_ccid = 0xAB; +#if defined(CONFIG_BT_TBS) + /* TODO: We do not have a way to get the CCID value of GTBS, but for now set to 0x00 as we + * know that it is the first content control service initialized + */ + const uint16_t gtbs_ccid = 0x00; +#endif /* CONFIG_BT_TBS */ const uint8_t new_metadata[] = { BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT, - BT_BYTES_LIST_LE16(BT_AUDIO_CONTEXT_TYPE_MEDIA)), - BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_CCID_LIST, mock_ccid), + BT_BYTES_LIST_LE16(BT_AUDIO_CONTEXT_TYPE_CONVERSATIONAL)), +#if defined(CONFIG_BT_TBS) + BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_CCID_LIST, gtbs_ccid), +#endif /* CONFIG_BT_TBS */ }; int err;