From fc2a5e82957eac30d8cbda2ab43b4da4a477ac1f Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Mon, 22 Sep 2025 14:14:40 +0200 Subject: [PATCH 1/3] Bluetooth: BAP: Add bt_bap_ep_get_conn Add a new function, bt_bap_ep_get_conn, which returns the ACL connection for the endpoint. This works because endpoints are specific to an ACL in BAP. The function returns a pointer with a new reference similar to the lookup functions from conn.h The conn pointer was not added to the bt_bap_ep_info struct, as doing so would be more likely to cause reference leaks if the caller did not care about the conn pointer when using bt_bap_ep_get_info. It can be added later if that is requested. Signed-off-by: Emil Gydesen --- include/zephyr/bluetooth/audio/bap.h | 15 +++++++++ subsys/bluetooth/audio/ascs.c | 12 +++++++ subsys/bluetooth/audio/ascs_internal.h | 1 + subsys/bluetooth/audio/bap_internal.h | 2 ++ subsys/bluetooth/audio/bap_stream.c | 25 +++++++++++++++ subsys/bluetooth/audio/bap_unicast_client.c | 35 +++++++++++++++++++++ subsys/bluetooth/audio/bap_unicast_server.c | 5 +++ 7 files changed, 95 insertions(+) diff --git a/include/zephyr/bluetooth/audio/bap.h b/include/zephyr/bluetooth/audio/bap.h index ef994cc050189..54beef46022ee 100644 --- a/include/zephyr/bluetooth/audio/bap.h +++ b/include/zephyr/bluetooth/audio/bap.h @@ -882,6 +882,21 @@ struct bt_bap_ep_info { */ int bt_bap_ep_get_info(const struct bt_bap_ep *ep, struct bt_bap_ep_info *info); +/** + * @brief Get the pointer to the ACL connection of an endpoint + * + * The caller gets a new reference to the connection object, if not NULL, which must be + * released with bt_conn_unref() once done using the object. + * + * @param ep The endpoint to get the ACL connection of + * + * @return The ACL connection pointer. + * Will always be NULL for broadcast endpoints. + * Will be NULL for Unicast Server endpoints if the endpoint is not configured by a client. + * Will be NULL for Unicast Client endpoints if @p does not match a discovered endpoint. + */ +struct bt_conn *bt_bap_ep_get_conn(const struct bt_bap_ep *ep); + /** * @brief Basic Audio Profile stream structure. * diff --git a/subsys/bluetooth/audio/ascs.c b/subsys/bluetooth/audio/ascs.c index 9072c220e5f98..4a59198d50dc2 100644 --- a/subsys/bluetooth/audio/ascs.c +++ b/subsys/bluetooth/audio/ascs.c @@ -3259,4 +3259,16 @@ int bt_ascs_unregister(void) return err; } +struct bt_conn *bt_ascs_ep_get_conn(const struct bt_bap_ep *ep) +{ + struct bt_ascs_ase *ase = CONTAINER_OF(ep, struct bt_ascs_ase, ep); + + __ASSERT_NO_MSG(bt_ascs_has_ep(ep)); + + if (ase->conn == NULL) { + return NULL; + } + + return bt_conn_ref(ase->conn); +} #endif /* BT_BAP_UNICAST_SERVER */ diff --git a/subsys/bluetooth/audio/ascs_internal.h b/subsys/bluetooth/audio/ascs_internal.h index 649b5c1706571..041727712dfc4 100644 --- a/subsys/bluetooth/audio/ascs_internal.h +++ b/subsys/bluetooth/audio/ascs_internal.h @@ -364,5 +364,6 @@ void bt_ascs_foreach_ep(struct bt_conn *conn, bt_bap_ep_func_t func, void *user_ int bt_ascs_register(uint8_t snk_cnt, uint8_t src_cnt); int bt_ascs_unregister(void); +struct bt_conn *bt_ascs_ep_get_conn(const struct bt_bap_ep *ep); #endif /* BT_ASCS_INTERNAL_H */ diff --git a/subsys/bluetooth/audio/bap_internal.h b/subsys/bluetooth/audio/bap_internal.h index 6d7ff219b3543..d6a20ef769af2 100644 --- a/subsys/bluetooth/audio/bap_internal.h +++ b/subsys/bluetooth/audio/bap_internal.h @@ -147,3 +147,5 @@ bool bt_bap_broadcast_sink_has_ep(const struct bt_bap_ep *ep); bool bt_bap_broadcast_source_has_ep(const struct bt_bap_ep *ep); bool bt_bap_unicast_client_has_ep(const struct bt_bap_ep *ep); bool bt_bap_unicast_server_has_ep(const struct bt_bap_ep *ep); +struct bt_conn *bt_bap_unicast_client_ep_get_conn(const struct bt_bap_ep *ep); +struct bt_conn *bt_bap_unicast_server_ep_get_conn(const struct bt_bap_ep *ep); diff --git a/subsys/bluetooth/audio/bap_stream.c b/subsys/bluetooth/audio/bap_stream.c index e33a7d79f6bde..b463d74113c2b 100644 --- a/subsys/bluetooth/audio/bap_stream.c +++ b/subsys/bluetooth/audio/bap_stream.c @@ -173,6 +173,31 @@ int bt_bap_ep_get_info(const struct bt_bap_ep *ep, struct bt_bap_ep_info *info) return 0; } +struct bt_conn *bt_bap_ep_get_conn(const struct bt_bap_ep *ep) +{ + struct bt_conn *conn; + + if (ep == NULL) { + LOG_DBG("ep is NULL"); + + return NULL; + } + + if ((IS_ENABLED(CONFIG_BT_BAP_BROADCAST_SOURCE) && bt_bap_broadcast_source_has_ep(ep)) || + (IS_ENABLED(CONFIG_BT_BAP_BROADCAST_SINK) && bt_bap_broadcast_sink_has_ep(ep))) { + conn = NULL; + } else if (IS_ENABLED(CONFIG_BT_BAP_UNICAST_CLIENT) && bt_bap_unicast_client_has_ep(ep)) { + conn = bt_bap_unicast_client_ep_get_conn(ep); + } else if (IS_ENABLED(CONFIG_BT_BAP_UNICAST_SERVER) && bt_bap_unicast_server_has_ep(ep)) { + conn = bt_bap_unicast_server_ep_get_conn(ep); + } else { + LOG_DBG("Invalid endpoint %p", ep); + conn = NULL; + } + + return conn; +} + enum bt_bap_ascs_reason bt_audio_verify_qos(const struct bt_bap_qos_cfg *qos) { if (qos->interval < BT_ISO_SDU_INTERVAL_MIN || diff --git a/subsys/bluetooth/audio/bap_unicast_client.c b/subsys/bluetooth/audio/bap_unicast_client.c index 197a86967e29d..af18735381f02 100644 --- a/subsys/bluetooth/audio/bap_unicast_client.c +++ b/subsys/bluetooth/audio/bap_unicast_client.c @@ -460,6 +460,41 @@ bool bt_bap_unicast_client_has_ep(const struct bt_bap_ep *ep) return false; } +struct bt_conn *bt_bap_unicast_client_ep_get_conn(const struct bt_bap_ep *ep) +{ + for (size_t i = 0U; i < ARRAY_SIZE(uni_cli_insts); i++) { +#if CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 0 + if (PART_OF_ARRAY(uni_cli_insts[i].snks, ep)) { + ARRAY_FOR_EACH_PTR(uni_cli_insts[i].snks, client_ep) { + if (&client_ep->ep == ep) { + if (client_ep->handle == BAP_HANDLE_UNUSED) { + return NULL; + } + + return bt_conn_lookup_index((uint8_t)i); + } + } + } +#endif /* CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 0 */ + +#if CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 0 + if (PART_OF_ARRAY(uni_cli_insts[i].srcs, ep)) { + ARRAY_FOR_EACH_PTR(uni_cli_insts[i].srcs, client_ep) { + if (&client_ep->ep == ep) { + if (client_ep->handle == BAP_HANDLE_UNUSED) { + return NULL; + } + + return bt_conn_lookup_index((uint8_t)i); + } + } + } +#endif /* CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 0 */ + } + + return NULL; +} + static void unicast_client_ep_init(struct bt_bap_ep *ep, uint16_t handle, uint8_t dir) { struct bt_bap_unicast_client_ep *client_ep; diff --git a/subsys/bluetooth/audio/bap_unicast_server.c b/subsys/bluetooth/audio/bap_unicast_server.c index e46ed4ff4b282..f7edb918b0297 100644 --- a/subsys/bluetooth/audio/bap_unicast_server.c +++ b/subsys/bluetooth/audio/bap_unicast_server.c @@ -227,3 +227,8 @@ bool bt_bap_unicast_server_has_ep(const struct bt_bap_ep *ep) { return bt_ascs_has_ep(ep); } + +struct bt_conn *bt_bap_unicast_server_ep_get_conn(const struct bt_bap_ep *ep) +{ + return bt_ascs_ep_get_conn(ep); +} From 0d3d2d34cb15bfae2b4d094ee3d38e8544482628 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Mon, 22 Sep 2025 14:15:50 +0200 Subject: [PATCH 2/3] doc: releases: Add entry for bt_bap_ep_get_conn Add entry for the new function bt_bap_ep_get_conn. Signed-off-by: Emil Gydesen --- doc/releases/release-notes-4.4.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/releases/release-notes-4.4.rst b/doc/releases/release-notes-4.4.rst index a33b0b3e9d0e0..3d15dead1a3fa 100644 --- a/doc/releases/release-notes-4.4.rst +++ b/doc/releases/release-notes-4.4.rst @@ -73,6 +73,10 @@ New APIs and options * Bluetooth + * Audio + + * :c:func:`bt_bap_ep_get_conn` + * Host * :c:func:`bt_gatt_cb_unregister` Added an API to unregister GATT callback handlers. From 7bf4634249441a12e6f0b13669170d54e2c6cd6d Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Mon, 22 Sep 2025 14:16:18 +0200 Subject: [PATCH 3/3] tests: Bluetooth: BAP: Test bt_bap_ep_get_conn in BSIM Add steps in the BAP tests to verify the correctness of bt_bap_ep_get_conn. Signed-off-by: Emil Gydesen --- .../audio/src/bap_broadcast_sink_test.c | 7 +++++++ .../audio/src/bap_broadcast_source_test.c | 7 +++++++ .../audio/src/bap_unicast_client_test.c | 9 +++++++++ .../audio/src/bap_unicast_server_test.c | 20 +++++++++++++++++-- 4 files changed, 41 insertions(+), 2 deletions(-) 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 d7cb7867bf697..ec7646f3cb66b 100644 --- a/tests/bsim/bluetooth/audio/src/bap_broadcast_sink_test.c +++ b/tests/bsim/bluetooth/audio/src/bap_broadcast_sink_test.c @@ -565,6 +565,7 @@ static void stream_started_cb(struct bt_bap_stream *stream) { struct audio_test_stream *test_stream = audio_test_stream_from_bap_stream(stream); struct bt_bap_ep_info info; + struct bt_conn *ep_conn; int err; memset(&test_stream->last_info, 0, sizeof(test_stream->last_info)); @@ -603,6 +604,12 @@ static void stream_started_cb(struct bt_bap_stream *stream) return; } + ep_conn = bt_bap_ep_get_conn(stream->ep); + if (ep_conn != NULL) { + FAIL("Invalid conn from endpoint: %p", ep_conn); + return; + } + printk("Stream %p started\n", stream); k_sem_give(&sem_stream_started); diff --git a/tests/bsim/bluetooth/audio/src/bap_broadcast_source_test.c b/tests/bsim/bluetooth/audio/src/bap_broadcast_source_test.c index 9f6417eee2901..7613d07cdb8d2 100644 --- a/tests/bsim/bluetooth/audio/src/bap_broadcast_source_test.c +++ b/tests/bsim/bluetooth/audio/src/bap_broadcast_source_test.c @@ -178,6 +178,7 @@ static void stream_started_cb(struct bt_bap_stream *stream) { struct audio_test_stream *test_stream = audio_test_stream_from_bap_stream(stream); struct bt_bap_ep_info info; + struct bt_conn *ep_conn; int err; test_stream->seq_num = 0U; @@ -214,6 +215,12 @@ static void stream_started_cb(struct bt_bap_stream *stream) return; } + ep_conn = bt_bap_ep_get_conn(stream->ep); + if (ep_conn != NULL) { + FAIL("Invalid conn from endpoint: %p", ep_conn); + return; + } + err = bap_stream_tx_register(stream); if (err != 0) { FAIL("Failed to register stream %p for TX: %d\n", stream, err); diff --git a/tests/bsim/bluetooth/audio/src/bap_unicast_client_test.c b/tests/bsim/bluetooth/audio/src/bap_unicast_client_test.c index f3ac063a61cfa..adec42861b385 100644 --- a/tests/bsim/bluetooth/audio/src/bap_unicast_client_test.c +++ b/tests/bsim/bluetooth/audio/src/bap_unicast_client_test.c @@ -69,12 +69,21 @@ CREATE_FLAG(flag_operation_success); static void stream_configured(struct bt_bap_stream *stream, const struct bt_bap_qos_cfg_pref *pref) { + struct bt_conn *ep_conn; + printk("Configured stream %p\n", stream); /* TODO: The preference should be used/taken into account when * setting the QoS */ + ep_conn = bt_bap_ep_get_conn(stream->ep); + if (ep_conn == NULL || stream->conn != ep_conn) { + FAIL("Invalid conn from endpoint: %p", ep_conn); + return; + } + bt_conn_unref(ep_conn); + SET_FLAG(flag_stream_codec_configured); } diff --git a/tests/bsim/bluetooth/audio/src/bap_unicast_server_test.c b/tests/bsim/bluetooth/audio/src/bap_unicast_server_test.c index 515b4714d842b..dae34c5290530 100644 --- a/tests/bsim/bluetooth/audio/src/bap_unicast_server_test.c +++ b/tests/bsim/bluetooth/audio/src/bap_unicast_server_test.c @@ -114,8 +114,6 @@ static int lc3_config(struct bt_conn *conn, const struct bt_bap_ep *ep, enum bt_ bt_bap_unicast_server_foreach_ep(conn, print_ase_info, NULL); - SET_FLAG(flag_stream_configured); - *pref = qos_pref; return 0; @@ -222,6 +220,23 @@ static const struct bt_bap_unicast_server_cb unicast_server_cb = { .release = lc3_release, }; +static void stream_configured_cb(struct bt_bap_stream *stream, + const struct bt_bap_qos_cfg_pref *pref) +{ + struct bt_conn *ep_conn; + + printk("Configured stream %p\n", stream); + + ep_conn = bt_bap_ep_get_conn(stream->ep); + if (ep_conn == NULL || stream->conn != ep_conn) { + FAIL("Invalid conn from endpoint: %p", ep_conn); + return; + } + bt_conn_unref(ep_conn); + + SET_FLAG(flag_stream_configured); +} + static void stream_enabled_cb(struct bt_bap_stream *stream) { struct bt_bap_ep_info ep_info; @@ -279,6 +294,7 @@ static void stream_stopped_cb(struct bt_bap_stream *stream, uint8_t reason) } static struct bt_bap_stream_ops stream_ops = { + .configured = stream_configured_cb, .enabled = stream_enabled_cb, .started = stream_started_cb, .stopped = stream_stopped_cb,