diff --git a/include/zephyr/bluetooth/audio/pacs.h b/include/zephyr/bluetooth/audio/pacs.h index e956e0da7f47231..93ebb6bcbccf522 100644 --- a/include/zephyr/bluetooth/audio/pacs.h +++ b/include/zephyr/bluetooth/audio/pacs.h @@ -45,6 +45,18 @@ struct bt_pacs_cap { sys_snode_t _node; }; + +/** Structure for registering PACS */ +struct bt_bap_pacs_register_param { + bool snk_pac; + bool snk_pac_loc; + bool src_pac; + bool src_pac_loc; +}; + +int bt_pacs_register(const struct bt_bap_pacs_register_param *param); +int bt_pacs_unregister(void); + /** * @typedef bt_pacs_cap_foreach_func_t * @brief Published Audio Capability iterator callback. diff --git a/subsys/bluetooth/audio/pacs.c b/subsys/bluetooth/audio/pacs.c index 30e5d64d9a405ca..d0b88abcd765c58 100644 --- a/subsys/bluetooth/audio/pacs.c +++ b/subsys/bluetooth/audio/pacs.c @@ -53,13 +53,13 @@ LOG_MODULE_REGISTER(bt_pacs, CONFIG_BT_PACS_LOG_LEVEL); #if defined(CONFIG_BT_PAC_SRC) static uint32_t pacs_src_location; -static sys_slist_t src_pacs_list = SYS_SLIST_STATIC_INIT(&src_pacs_list); +static sys_slist_t src_pac_list = SYS_SLIST_STATIC_INIT(&src_pac_list); static uint16_t src_supported_contexts; #endif /* CONFIG_BT_PAC_SRC */ #if defined(CONFIG_BT_PAC_SNK) static uint32_t pacs_snk_location; -static sys_slist_t snk_pacs_list = SYS_SLIST_STATIC_INIT(&snk_pacs_list); +static sys_slist_t snk_pac_list = SYS_SLIST_STATIC_INIT(&snk_pac_list); static uint16_t snk_supported_contexts; #endif /* CONFIG_BT_PAC_SNK */ @@ -77,7 +77,7 @@ enum { FLAG_NUM, }; -static struct pacs_client { +struct pacs_client { bt_addr_le_t addr; #if defined(CONFIG_BT_PAC_SNK) @@ -92,7 +92,13 @@ static struct pacs_client { /* Pending notification flags */ ATOMIC_DEFINE(flags, FLAG_NUM); -} clients[CONFIG_BT_MAX_PAIRED]; +}; + +struct pacs { + bool registered; + struct bt_bap_pacs_register_param param; + struct pacs_client clients[CONFIG_BT_MAX_PAIRED]; +} pacs; static atomic_t notify_rdy; @@ -117,10 +123,10 @@ static struct pacs_client *client_lookup_conn(const struct bt_conn *conn) { __ASSERT_NO_MSG(conn != NULL); - for (size_t i = 0; i < ARRAY_SIZE(clients); i++) { - if (atomic_test_bit(clients[i].flags, FLAG_ACTIVE) && - bt_addr_le_eq(&clients[i].addr, bt_conn_get_dst(conn))) { - return &clients[i]; + for (size_t i = 0; i < ARRAY_SIZE(pacs.clients); i++) { + if (atomic_test_bit(pacs.clients[i].flags, FLAG_ACTIVE) && + bt_addr_le_eq(&pacs.clients[i].addr, bt_conn_get_dst(conn))) { + return &pacs.clients[i]; } } @@ -129,9 +135,9 @@ static struct pacs_client *client_lookup_conn(const struct bt_conn *conn) static void pacs_set_notify_bit(int bit) { - for (size_t i = 0U; i < ARRAY_SIZE(clients); i++) { - if (atomic_test_bit(clients[i].flags, FLAG_ACTIVE)) { - atomic_set_bit(clients[i].flags, bit); + for (size_t i = 0U; i < ARRAY_SIZE(pacs.clients); i++) { + if (atomic_test_bit(pacs.clients[i].flags, FLAG_ACTIVE)) { + atomic_set_bit(pacs.clients[i].flags, bit); } } } @@ -226,14 +232,14 @@ static enum bt_audio_context pacs_get_available_contexts_for_conn(struct bt_conn switch (dir) { case BT_AUDIO_DIR_SINK: #if defined(CONFIG_BT_PAC_SNK) - if (client->snk_available_contexts != NULL) { + if (pacs.param.snk_pac && client->snk_available_contexts != NULL) { return POINTER_TO_UINT(client->snk_available_contexts); } #endif /* CONFIG_BT_PAC_SNK */ break; case BT_AUDIO_DIR_SOURCE: #if defined(CONFIG_BT_PAC_SRC) - if (client->src_available_contexts != NULL) { + if (pacs.param.snk_pac && client->src_available_contexts != NULL) { return POINTER_TO_UINT(client->src_available_contexts); } #endif /* CONFIG_BT_PAC_SRC */ @@ -273,11 +279,15 @@ static uint16_t supported_context_get(enum bt_audio_dir dir) switch (dir) { #if defined(CONFIG_BT_PAC_SNK) case BT_AUDIO_DIR_SINK: - return snk_supported_contexts | BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED; + if (pacs.param.snk_pac) { + return snk_supported_contexts | BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED; + } #endif /* CONFIG_BT_PAC_SNK */ #if defined(CONFIG_BT_PAC_SRC) case BT_AUDIO_DIR_SOURCE: - return src_supported_contexts | BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED; + if (pacs.param.src_pac) { + return src_supported_contexts | BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED; + } #endif /* CONFIG_BT_PAC_SRC */ default: break; @@ -371,7 +381,7 @@ static ssize_t snk_read(struct bt_conn *conn, const struct bt_gatt_attr *attr, return BT_GATT_ERR(BT_ATT_ERR_INSUFFICIENT_RESOURCES); } - get_pac_records(&snk_pacs_list, &read_buf); + get_pac_records(&snk_pac_list, &read_buf); ret_val = bt_gatt_attr_read(conn, attr, buf, len, offset, read_buf.data, read_buf.len); @@ -415,15 +425,17 @@ static void snk_loc_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value) static void set_snk_location(enum bt_audio_location audio_location) { - if (audio_location == pacs_snk_location) { - return; - } + if (pacs.param.snk_pac_loc) { + if (audio_location == pacs_snk_location) { + return; + } - pacs_snk_location = audio_location; + pacs_snk_location = audio_location; - if (IS_ENABLED(CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE)) { - pacs_set_notify_bit(FLAG_SINK_AUDIO_LOCATIONS_CHANGED); - k_work_submit(&deferred_nfy_work); + if (IS_ENABLED(CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE)) { + pacs_set_notify_bit(FLAG_SINK_AUDIO_LOCATIONS_CHANGED); + k_work_submit(&deferred_nfy_work); + } } } #else @@ -476,7 +488,7 @@ static ssize_t src_read(struct bt_conn *conn, const struct bt_gatt_attr *attr, return BT_GATT_ERR(BT_ATT_ERR_INSUFFICIENT_RESOURCES); } - get_pac_records(&src_pacs_list, &read_buf); + get_pac_records(&src_pac_list, &read_buf); ret_val = bt_gatt_attr_read(conn, attr, buf, len, offset, read_buf.data, read_buf.len); @@ -520,15 +532,17 @@ static void src_loc_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value) static void set_src_location(enum bt_audio_location audio_location) { - if (audio_location == pacs_src_location) { - return; - } + if (pacs.param.src_pac_loc) { + if (audio_location == pacs_src_location) { + return; + } - pacs_src_location = audio_location; + pacs_src_location = audio_location; - if (IS_ENABLED(CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE)) { - pacs_set_notify_bit(FLAG_SOURCE_AUDIO_LOCATIONS_CHANGED); - k_work_submit(&deferred_nfy_work); + if (IS_ENABLED(CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE)) { + pacs_set_notify_bit(FLAG_SOURCE_AUDIO_LOCATIONS_CHANGED); + k_work_submit(&deferred_nfy_work); + } } } #else @@ -566,22 +580,29 @@ static ssize_t src_loc_write(struct bt_conn *conn, #endif /* CONFIG_BT_PAC_SRC_LOC_WRITEABLE */ -static sys_slist_t *pacs_get(enum bt_audio_dir dir) +static sys_slist_t *pacs_get_pac(enum bt_audio_dir dir) { switch (dir) { #if defined(CONFIG_BT_PAC_SNK) case BT_AUDIO_DIR_SINK: - return &snk_pacs_list; + if (pacs.param.snk_pac) { + return &snk_pac_list; + } + return NULL; #endif /* CONFIG_BT_PAC_SNK */ #if defined(CONFIG_BT_PAC_SRC) case BT_AUDIO_DIR_SOURCE: - return &src_pacs_list; + if (pacs.param.src_pac) { + return &src_pac_list; + } + return NULL; #endif /* CONFIG_BT_PAC_SRC */ default: return NULL; } } +#if defined(CONFIG_BT_PAC_SNK) #define BT_PACS_SNK_PROP \ BT_GATT_CHRC_READ \ IF_ENABLED(CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE, (|BT_GATT_CHRC_NOTIFY)) @@ -609,7 +630,12 @@ static sys_slist_t *pacs_get(enum bt_audio_dir dir) COND_CODE_1(CONFIG_BT_PAC_SNK_LOC_WRITEABLE, (snk_loc_write), (NULL)), \ NULL), \ IF_ENABLED(CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE, (BT_AUDIO_CCC(snk_loc_cfg_changed),)) +#else +#define BT_PAC_SNK(_read) +#define BT_PACS_SNK_LOC(_read) +#endif +#if defined(CONFIG_BT_PAC_SRC) #define BT_PACS_SRC_PROP \ BT_GATT_CHRC_READ \ IF_ENABLED(CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE, (|BT_GATT_CHRC_NOTIFY)) @@ -637,6 +663,10 @@ static sys_slist_t *pacs_get(enum bt_audio_dir dir) COND_CODE_1(CONFIG_BT_PAC_SRC_LOC_WRITEABLE, (src_loc_write), (NULL)), \ NULL), \ IF_ENABLED(CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE, (BT_AUDIO_CCC(src_loc_cfg_changed),)) +#else +#define BT_PAC_SRC(_read) +#define BT_PACS_SRC_LOC(_read) +#endif #define BT_PAC_AVAILABLE_CONTEXT(_read) \ BT_AUDIO_CHRC(BT_UUID_PACS_AVAILABLE_CONTEXT, \ @@ -657,23 +687,150 @@ static sys_slist_t *pacs_get(enum bt_audio_dir dir) IF_ENABLED(CONFIG_BT_PACS_SUPPORTED_CONTEXT_NOTIFIABLE, \ (BT_AUDIO_CCC(supported_context_cfg_changed),)) -BT_GATT_SERVICE_DEFINE(pacs_svc, - BT_GATT_PRIMARY_SERVICE(BT_UUID_PACS), -#if defined(CONFIG_BT_PAC_SNK) - BT_PAC_SNK(snk_read) -#if defined(CONFIG_BT_PAC_SNK_LOC) - BT_PACS_SNK_LOC(snk_loc_read) -#endif /* CONFIG_BT_PAC_SNK_LOC */ -#endif /* CONFIG_BT_PAC_SNK */ -#if defined(CONFIG_BT_PAC_SRC) - BT_PAC_SRC(src_read) -#if defined(CONFIG_BT_PAC_SRC_LOC) - BT_PACS_SRC_LOC(src_loc_read) -#endif /* CONFIG_BT_PAC_SRC_LOC */ -#endif /* CONFIG_BT_PAC_SRC */ - BT_PAC_AVAILABLE_CONTEXT(available_contexts_read) - BT_PAC_SUPPORTED_CONTEXT(supported_context_read) -); +#define BT_PACS_SERVICE_DEFINITION() { \ + BT_GATT_PRIMARY_SERVICE(BT_UUID_PACS), \ + BT_PAC_SNK(snk_read) \ + BT_PACS_SNK_LOC(snk_loc_read) \ + BT_PAC_SRC(src_read) \ + BT_PACS_SRC_LOC(src_loc_read) \ + BT_PAC_AVAILABLE_CONTEXT(available_contexts_read) \ + BT_PAC_SUPPORTED_CONTEXT(supported_context_read) \ +} + +static struct bt_gatt_attr pacs_attrs[] = BT_PACS_SERVICE_DEFINITION(); +static struct bt_gatt_service pacs_svc = (struct bt_gatt_service)BT_GATT_SERVICE(pacs_attrs); + + + + +#if defined(BT_PAC_SNK_NOTIFIABLE) +#define PACS_SINK_PAC_CHAR_ATTR_COUNT 3 /* declaration + value + cccd */ +#else +#define PACS_SINK_PAC_CHAR_ATTR_COUNT 2 /* declaration + value */ +#endif /* BT_PAC_SNK_NOTIFIABLE */ + +#if defined(BT_PAC_SNK_LOC_NOTIFIABLE) +#define PACS_SINK_PAC_LOC_CHAR_ATTR_COUNT 3 /* declaration + value + cccd */ +#else +#define PACS_SINK_PAC_LOC_CHAR_ATTR_COUNT 2 /* declaration + value*/ +#endif /* BT_PAC_SNK_LOC_NOTIFIABLE */ + +#if defined(BT_PAC_SRC_NOTIFIABLE) +#define PACS_SOURCE_PAC_CHAR_ATTR_COUNT 3 /* declaration + value + cccd */ +#else +#define PACS_SOURCE_PAC_CHAR_ATTR_COUNT 2 /* declaration + value */ +#endif /* BT_PAC_SRC_NOTIFIABLE */ + +#if defined(BT_PAC_SRC_LOC_NOTIFIABLE) +#define PACS_SOURCE_PAC_LOC_CHAR_ATTR_COUNT 3 /* declaration + value + cccd */ +#else +#define PACS_SOURCE_PAC_LOC_CHAR_ATTR_COUNT 2 /* declaration + value*/ +#endif /* BT_PAC_SRC_LOC_NOTIFIABLE */ + +static void configure_pacs_char(const struct bt_bap_pacs_register_param *param) +{ + size_t attrs_to_rem; + uint8_t first_to_rem; + + /* Remove the Sink PAC and Location */ + if (!param->snk_pac) { + first_to_rem = 0; + attrs_to_rem = PACS_SINK_PAC_CHAR_ATTR_COUNT + PACS_SINK_PAC_LOC_CHAR_ATTR_COUNT; + } else if (!param->snk_pac_loc) { + first_to_rem = PACS_SINK_PAC_CHAR_ATTR_COUNT; + attrs_to_rem = PACS_SINK_PAC_LOC_CHAR_ATTR_COUNT; + } else { + first_to_rem = pacs_svc.attr_count; + attrs_to_rem = 0; + } + + for (size_t i = first_to_rem + attrs_to_rem; i < pacs_svc.attr_count; i++) { + pacs_svc.attrs[i - attrs_to_rem] = pacs_svc.attrs[i]; + } + pacs_svc.attr_count -= attrs_to_rem; + + /* Set first_to_rem to the start of Source PAC Char, for cleaner offset calc */ + first_to_rem = PACS_SINK_PAC_CHAR_ATTR_COUNT + PACS_SINK_PAC_LOC_CHAR_ATTR_COUNT; + + /* Remove the Source PAC and Location */ + if (!param->snk_pac) { + first_to_rem -= attrs_to_rem; + attrs_to_rem = PACS_SOURCE_PAC_CHAR_ATTR_COUNT + + PACS_SOURCE_PAC_LOC_CHAR_ATTR_COUNT; + } else if (!param->snk_pac_loc) { + first_to_rem = first_to_rem + PACS_SOURCE_PAC_CHAR_ATTR_COUNT - attrs_to_rem; + attrs_to_rem = PACS_SINK_PAC_LOC_CHAR_ATTR_COUNT; + } else { + return; + } + + for (size_t i = first_to_rem; i < pacs_svc.attr_count; i++) { + pacs_svc.attrs[i - attrs_to_rem] = pacs_svc.attrs[i]; + } + pacs_svc.attr_count -= attrs_to_rem; +} + + + +int bt_pacs_register(const struct bt_bap_pacs_register_param *param) +{ + int err = 0; + + if (pacs.registered) { + LOG_DBG("PACS already registered"); + + return -EALREADY; + } + + /* Save registration param so we can guard functions accordingly */ + memcpy(&pacs.param, param, sizeof(struct bt_bap_pacs_register_param)); + + /* Remove characteristics if necessary */ + configure_pacs_char(param); + + err = bt_gatt_service_register(&pacs_svc); + if (err != 0) { + LOG_DBG("Failed to register ASCS in gatt DB"); + + return err; + } + + pacs.registered = true; + + return 0; +} + +int bt_pacs_unregister(void) +{ + int err; + struct bt_gatt_attr _pacs_attrs[] = BT_PACS_SERVICE_DEFINITION(); + + /* TODO: This whole function needs to be thread-safe. There are several places where + * data is being accessed and notified, that has to be guarded. In general we should + * add a mutex or atomic check everywhere were data can be accessed/mutated before we + * allows the unregistration to go through. + */ + if (!pacs.registered) { + LOG_DBG("No pacs instance registered"); + return -EALREADY; + } + + err = bt_gatt_service_unregister(&pacs_svc); + /* If unregistration was succesfull, make sure to reset pacs_attrs so it can be used for + * new registrations + */ + if (err != 0) { + LOG_DBG("Failed to unregister PACS"); + return err; + } + + memcpy(&pacs_attrs, &_pacs_attrs, sizeof(struct bt_gatt_attr)); + pacs_svc.attr_count = ARRAY_SIZE(pacs_attrs); + + pacs.registered = false; + + return err; +} #if defined(CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE) || defined(CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE) static int pac_notify_loc(struct bt_conn *conn, enum bt_audio_dir dir) @@ -713,7 +870,7 @@ static int pac_notify_loc(struct bt_conn *conn, enum bt_audio_dir dir) static int pac_notify(struct bt_conn *conn, enum bt_audio_dir dir) { int err = 0; - sys_slist_t *pacs; + sys_slist_t *pac; const struct bt_uuid *uuid; switch (dir) { @@ -738,9 +895,9 @@ static int pac_notify(struct bt_conn *conn, enum bt_audio_dir dir) return err; } - pacs = pacs_get(dir); - __ASSERT(pacs, "Failed to get pacs.\n"); - get_pac_records(pacs, &read_buf); + pac = pacs_get_pac(dir); + __ASSERT(pac, "Failed to get pacs.\n"); + get_pac_records(pac, &read_buf); err = pacs_gatt_notify(conn, uuid, pacs_svc.attrs, read_buf.data, read_buf.len); @@ -866,6 +1023,9 @@ static void notify_cb(struct bt_conn *conn, void *data) #if defined(CONFIG_BT_PAC_SNK_NOTIFIABLE) if (atomic_test_bit(client->flags, FLAG_SINK_PAC_CHANGED)) { LOG_DBG("Notifying Sink PAC"); + /* TODO: We might have thread-safe issue here. If another thread unregisters the + * service right at this spot, causing below function to access invalid data + */ err = pac_notify(conn, BT_AUDIO_DIR_SINK); if (!err) { atomic_clear_bit(client->flags, FLAG_SINK_PAC_CHANGED); @@ -876,6 +1036,9 @@ static void notify_cb(struct bt_conn *conn, void *data) #if defined(CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE) if (atomic_test_bit(client->flags, FLAG_SINK_AUDIO_LOCATIONS_CHANGED)) { LOG_DBG("Notifying Sink Audio Location"); + /* TODO: We might have thread-safe issue here. If another thread unregisters the + * service right at this spot, causing below function to access invalid data + */ err = pac_notify_loc(conn, BT_AUDIO_DIR_SINK); if (!err) { atomic_clear_bit(client->flags, FLAG_SINK_AUDIO_LOCATIONS_CHANGED); @@ -886,6 +1049,9 @@ static void notify_cb(struct bt_conn *conn, void *data) #if defined(CONFIG_BT_PAC_SRC_NOTIFIABLE) if (atomic_test_bit(client->flags, FLAG_SOURCE_PAC_CHANGED)) { LOG_DBG("Notifying Source PAC"); + /* TODO: We might have thread-safe issue here. If another thread unregisters the + * service right at this spot, causing below function to access invalid data + */ err = pac_notify(conn, BT_AUDIO_DIR_SOURCE); if (!err) { atomic_clear_bit(client->flags, FLAG_SOURCE_PAC_CHANGED); @@ -896,6 +1062,9 @@ static void notify_cb(struct bt_conn *conn, void *data) #if defined(CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE) if (atomic_test_and_clear_bit(client->flags, FLAG_SOURCE_AUDIO_LOCATIONS_CHANGED)) { LOG_DBG("Notifying Source Audio Location"); + /* TODO: We might have thread-safe issue here. If another thread unregisters the + * service right at this spot, causing below function to access invalid data + */ err = pac_notify_loc(conn, BT_AUDIO_DIR_SOURCE); if (!err) { atomic_clear_bit(client->flags, FLAG_SOURCE_AUDIO_LOCATIONS_CHANGED); @@ -905,6 +1074,9 @@ static void notify_cb(struct bt_conn *conn, void *data) if (atomic_test_bit(client->flags, FLAG_AVAILABLE_AUDIO_CONTEXT_CHANGED)) { LOG_DBG("Notifying Available Contexts"); + /* TODO: We might have thread-safe issue here. If another thread unregisters the + * service right at this spot, causing below function to access invalid data + */ err = available_contexts_notify(conn); if (!err) { atomic_clear_bit(client->flags, FLAG_AVAILABLE_AUDIO_CONTEXT_CHANGED); @@ -914,6 +1086,9 @@ static void notify_cb(struct bt_conn *conn, void *data) if (IS_ENABLED(CONFIG_BT_PACS_SUPPORTED_CONTEXT_NOTIFIABLE) && atomic_test_bit(client->flags, FLAG_SUPPORTED_AUDIO_CONTEXT_CHANGED)) { LOG_DBG("Notifying Supported Contexts"); + /* TODO: We might have thread-safe issue here. If another thread unregisters the + * service right at this spot, causing below function to access invalid data + */ err = supported_contexts_notify(conn); if (!err) { atomic_clear_bit(client->flags, FLAG_SUPPORTED_AUDIO_CONTEXT_CHANGED); @@ -936,18 +1111,18 @@ static void pacs_auth_pairing_complete(struct bt_conn *conn, bool bonded) } /* Check if already in list, and do nothing if it is */ - for (size_t i = 0U; i < ARRAY_SIZE(clients); i++) { - if (atomic_test_bit(clients[i].flags, FLAG_ACTIVE) && - bt_addr_le_eq(bt_conn_get_dst(conn), &clients[i].addr)) { + for (size_t i = 0U; i < ARRAY_SIZE(pacs.clients); i++) { + if (atomic_test_bit(pacs.clients[i].flags, FLAG_ACTIVE) && + bt_addr_le_eq(bt_conn_get_dst(conn), &pacs.clients[i].addr)) { return; } } /* Else add the device */ - for (size_t i = 0U; i < ARRAY_SIZE(clients); i++) { - if (!atomic_test_bit(clients[i].flags, FLAG_ACTIVE)) { - atomic_set_bit(clients[i].flags, FLAG_ACTIVE); - memcpy(&clients[i].addr, bt_conn_get_dst(conn), sizeof(bt_addr_le_t)); + for (size_t i = 0U; i < ARRAY_SIZE(pacs.clients); i++) { + if (!atomic_test_bit(pacs.clients[i].flags, FLAG_ACTIVE)) { + atomic_set_bit(pacs.clients[i].flags, FLAG_ACTIVE); + memcpy(&pacs.clients[i].addr, bt_conn_get_dst(conn), sizeof(bt_addr_le_t)); /* Send out all pending notifications */ k_work_submit(&deferred_nfy_work); @@ -959,14 +1134,14 @@ static void pacs_auth_pairing_complete(struct bt_conn *conn, bool bonded) static void pacs_bond_deleted(uint8_t id, const bt_addr_le_t *peer) { /* Find the device entry to delete */ - for (size_t i = 0U; i < ARRAY_SIZE(clients); i++) { + for (size_t i = 0U; i < ARRAY_SIZE(pacs.clients); i++) { /* Check if match, and if active, if so, reset */ - if (atomic_test_bit(clients[i].flags, FLAG_ACTIVE) && - bt_addr_le_eq(peer, &clients[i].addr)) { + if (atomic_test_bit(pacs.clients[i].flags, FLAG_ACTIVE) && + bt_addr_le_eq(peer, &pacs.clients[i].addr)) { for (size_t j = 0U; j < FLAG_NUM; j++) { - atomic_clear_bit(clients[i].flags, j); + atomic_clear_bit(pacs.clients[i].flags, j); } - (void)memset(&clients[i].addr, 0, sizeof(bt_addr_le_t)); + (void)memset(&pacs.clients[i].addr, 0, sizeof(bt_addr_le_t)); return; } } @@ -985,9 +1160,9 @@ static void pacs_security_changed(struct bt_conn *conn, bt_security_t level, return; } - for (size_t i = 0U; i < ARRAY_SIZE(clients); i++) { + for (size_t i = 0U; i < ARRAY_SIZE(pacs.clients); i++) { for (size_t j = 0U; j < FLAG_NUM; j++) { - if (atomic_test_bit(clients[i].flags, j)) { + if (atomic_test_bit(pacs.clients[i].flags, j)) { /** * It's enough that one flag is set, as the defer work will go @@ -1010,7 +1185,7 @@ static void pacs_disconnected(struct bt_conn *conn, uint8_t reason) } #if defined(CONFIG_BT_PAC_SNK) - if (client->snk_available_contexts != NULL) { + if (pacs.param.snk_pac && client->snk_available_contexts != NULL) { uint16_t old = POINTER_TO_UINT(client->snk_available_contexts); uint16_t new; @@ -1022,7 +1197,7 @@ static void pacs_disconnected(struct bt_conn *conn, uint8_t reason) #endif /* CONFIG_BT_PAC_SNK */ #if defined(CONFIG_BT_PAC_SRC) - if (client->src_available_contexts != NULL) { + if (pacs.param.src_pac && client->src_available_contexts != NULL) { uint16_t old = POINTER_TO_UINT(client->src_available_contexts); uint16_t new; @@ -1053,7 +1228,7 @@ void bt_pacs_cap_foreach(enum bt_audio_dir dir, bt_pacs_cap_foreach_func_t func, return; } - pac = pacs_get(dir); + pac = pacs_get_pac(dir); if (!pac) { return; } @@ -1063,14 +1238,14 @@ void bt_pacs_cap_foreach(enum bt_audio_dir dir, bt_pacs_cap_foreach_func_t func, static void add_bonded_addr_to_client_list(const struct bt_bond_info *info, void *data) { - for (uint8_t i = 0; i < ARRAY_SIZE(clients); i++) { + for (uint8_t i = 0; i < ARRAY_SIZE(pacs.clients); i++) { /* Check if device is registered, it not, add it */ - if (!atomic_test_bit(clients[i].flags, FLAG_ACTIVE)) { + if (!atomic_test_bit(pacs.clients[i].flags, FLAG_ACTIVE)) { char addr_str[BT_ADDR_LE_STR_LEN]; - atomic_set_bit(clients[i].flags, FLAG_ACTIVE); - memcpy(&clients[i].addr, &info->addr, sizeof(bt_addr_le_t)); - bt_addr_le_to_str(&clients[i].addr, addr_str, sizeof(addr_str)); + atomic_set_bit(pacs.clients[i].flags, FLAG_ACTIVE); + memcpy(&pacs.clients[i].addr, &info->addr, sizeof(bt_addr_le_t)); + bt_addr_le_to_str(&pacs.clients[i].addr, addr_str, sizeof(addr_str)); LOG_DBG("Added %s to bonded list\n", addr_str); return; } @@ -1090,7 +1265,7 @@ int bt_pacs_cap_register(enum bt_audio_dir dir, struct bt_pacs_cap *cap) codec_cap = cap->codec_cap; - pac = pacs_get(dir); + pac = pacs_get_pac(dir); if (!pac) { return -EINVAL; } @@ -1132,7 +1307,7 @@ int bt_pacs_cap_unregister(enum bt_audio_dir dir, struct bt_pacs_cap *cap) return -EINVAL; } - pac = pacs_get(dir); + pac = pacs_get_pac(dir); if (!pac) { return -EINVAL; } @@ -1181,13 +1356,22 @@ int bt_pacs_set_location(enum bt_audio_dir dir, enum bt_audio_location location) int bt_pacs_set_available_contexts(enum bt_audio_dir dir, enum bt_audio_context contexts) { + if (!pacs.registered) { + return -EINVAL; + } switch (dir) { case BT_AUDIO_DIR_SINK: - return set_available_contexts(contexts, &snk_available_contexts, - supported_context_get(dir)); + if (pacs.param.snk_pac) { + return set_available_contexts(contexts, &snk_available_contexts, + supported_context_get(dir)); + } + return -EINVAL; case BT_AUDIO_DIR_SOURCE: - return set_available_contexts(contexts, &src_available_contexts, - supported_context_get(dir)); + if (pacs.param.src_pac) { + return set_available_contexts(contexts, &src_available_contexts, + supported_context_get(dir)); + } + return -EINVAL; } return -EINVAL; @@ -1215,23 +1399,29 @@ int bt_pacs_conn_set_available_contexts_for_conn(struct bt_conn *conn, enum bt_a switch (dir) { #if defined(CONFIG_BT_PAC_SNK) case BT_AUDIO_DIR_SINK: - if (contexts != NULL) { - client->snk_available_contexts = UINT_TO_POINTER(*contexts); - } else { - client->snk_available_contexts = NULL; + if (pacs.param.snk_pac) { + if (contexts != NULL) { + client->snk_available_contexts = UINT_TO_POINTER(*contexts); + } else { + client->snk_available_contexts = NULL; + } + break; } - break; + return -EINVAL; #endif /* CONFIG_BT_PAC_SNK */ #if defined(CONFIG_BT_PAC_SRC) case BT_AUDIO_DIR_SOURCE: - if (contexts != NULL) { - client->src_available_contexts = UINT_TO_POINTER(*contexts); - } else { - client->src_available_contexts = NULL; + if (pacs.param.src_pac) { + if (contexts != NULL) { + client->src_available_contexts = UINT_TO_POINTER(*contexts); + } else { + client->src_available_contexts = NULL; + } + break; } - break; + return -EINVAL; #endif /* CONFIG_BT_PAC_SRC */ default: return -EINVAL; @@ -1260,16 +1450,22 @@ int bt_pacs_set_supported_contexts(enum bt_audio_dir dir, enum bt_audio_context switch (dir) { case BT_AUDIO_DIR_SINK: #if defined(CONFIG_BT_PAC_SNK) - supported_contexts = &snk_supported_contexts; - available_contexts = &snk_available_contexts; - break; + if (pacs.param.snk_pac) { + supported_contexts = &snk_supported_contexts; + available_contexts = &snk_available_contexts; + break; + } + return -EINVAL; #endif /* CONFIG_BT_PAC_SNK */ return -ENOTSUP; case BT_AUDIO_DIR_SOURCE: #if defined(CONFIG_BT_PAC_SRC) - supported_contexts = &src_supported_contexts; - available_contexts = &src_available_contexts; - break; + if (pacs.param.src_pac) { + supported_contexts = &src_supported_contexts; + available_contexts = &src_available_contexts; + break; + } + return -EINVAL; #endif /* CONFIG_BT_PAC_SRC */ return -ENOTSUP; default: @@ -1287,9 +1483,15 @@ enum bt_audio_context bt_pacs_get_available_contexts(enum bt_audio_dir dir) { switch (dir) { case BT_AUDIO_DIR_SINK: - return snk_available_contexts; + if (pacs.param.snk_pac) { + return snk_available_contexts; + } + return -EINVAL; case BT_AUDIO_DIR_SOURCE: - return src_available_contexts; + if (pacs.param.src_pac) { + return src_available_contexts; + } + return -EINVAL; } return BT_AUDIO_CONTEXT_TYPE_PROHIBITED; diff --git a/subsys/bluetooth/audio/shell/bap.c b/subsys/bluetooth/audio/shell/bap.c index d06d055318d4ff1..e9db0a2ce69c763 100644 --- a/subsys/bluetooth/audio/shell/bap.c +++ b/subsys/bluetooth/audio/shell/bap.c @@ -3782,7 +3782,12 @@ static int cmd_init(const struct shell *sh, size_t argc, char *argv[]) CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT, CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT }; - + struct bt_bap_pacs_register_param pacs_param = { + 1, + 1, + 1, + 1 + }; if (argc == 3) { snk_cnt = shell_strtoul(argv[1], 0, &err); @@ -3809,6 +3814,7 @@ static int cmd_init(const struct shell *sh, size_t argc, char *argv[]) src_cnt = CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT; } + bt_pacs_register(&pacs_param); bt_bap_unicast_server_register(&unicast_server_param); bt_bap_unicast_server_register_cb(&unicast_server_cb); #endif /* CONFIG_BT_BAP_UNICAST_SERVER */ diff --git a/tests/bsim/bluetooth/audio/src/bap_broadcast_sink_test.c b/tests/bsim/bluetooth/audio/src/bap_broadcast_sink_test.c index d7f59bc4e00726b..d73487afa1a2d12 100644 --- a/tests/bsim/bluetooth/audio/src/bap_broadcast_sink_test.c +++ b/tests/bsim/bluetooth/audio/src/bap_broadcast_sink_test.c @@ -606,6 +606,12 @@ static struct bt_bap_stream_ops stream_ops = { static int init(void) { + const struct bt_bap_pacs_register_param pacs_param = { + 1, + 1, + 1, + 1 + }; int err; err = bt_enable(NULL); @@ -616,6 +622,12 @@ static int init(void) printk("Bluetooth initialized\n"); + err = bt_pacs_register(&pacs_param); + if (err) { + FAIL("Could not register PACS (err %d)", err); + return err; + } + err = bt_pacs_cap_register(BT_AUDIO_DIR_SINK, &cap); if (err) { FAIL("Capability register failed (err %d)\n", err); diff --git a/tests/bsim/bluetooth/audio/src/cap_acceptor_test.c b/tests/bsim/bluetooth/audio/src/cap_acceptor_test.c index 963d5dcd51ff8cd..f3c2d2f5de2ba28 100644 --- a/tests/bsim/bluetooth/audio/src/cap_acceptor_test.c +++ b/tests/bsim/bluetooth/audio/src/cap_acceptor_test.c @@ -697,6 +697,12 @@ static void init(void) BT_AUDIO_CODEC_CAP_FREQ_ANY, BT_AUDIO_CODEC_CAP_DURATION_ANY, BT_AUDIO_CODEC_CAP_CHAN_COUNT_SUPPORT(1, 2), 30, 240, 2, (BT_AUDIO_CONTEXT_TYPE_CONVERSATIONAL | BT_AUDIO_CONTEXT_TYPE_MEDIA)); + const struct bt_bap_pacs_register_param pacs_param = { + 1, + 1, + 1, + 1 + }; int err; err = bt_enable(NULL); @@ -707,6 +713,12 @@ static void init(void) printk("Bluetooth initialized\n"); + err = bt_pacs_register(&pacs_param); + if (err) { + FAIL("Could not register PACS (err %d)", err); + return; + } + if (IS_ENABLED(CONFIG_BT_CAP_ACCEPTOR_SET_MEMBER)) { err = bt_cap_acceptor_register(&csip_set_member_param, &csip_set_member); if (err != 0) { diff --git a/tests/bsim/bluetooth/audio/src/pacs_notify_server_test.c b/tests/bsim/bluetooth/audio/src/pacs_notify_server_test.c index cbd4fc75111f593..82f72f03833f904 100644 --- a/tests/bsim/bluetooth/audio/src/pacs_notify_server_test.c +++ b/tests/bsim/bluetooth/audio/src/pacs_notify_server_test.c @@ -161,6 +161,12 @@ static void test_main(void) const struct bt_data ad[] = { BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)), }; + const struct bt_bap_pacs_register_param pacs_param = { + 1, + 1, + 1, + 1 + }; LOG_DBG("Enabling Bluetooth"); err = bt_enable(NULL); @@ -169,6 +175,12 @@ static void test_main(void) return; } + err = bt_pacs_register(&pacs_param); + if (err) { + FAIL("Could not register PACS (err %d)", err); + return; + } + bt_pacs_set_supported_contexts(BT_AUDIO_DIR_SINK, BT_AUDIO_CONTEXT_TYPE_ANY); bt_pacs_set_supported_contexts(BT_AUDIO_DIR_SOURCE, BT_AUDIO_CONTEXT_TYPE_ANY); bt_pacs_set_available_contexts(BT_AUDIO_DIR_SINK, BT_AUDIO_CONTEXT_TYPE_ANY);