diff --git a/doc/releases/migration-guide-4.2.rst b/doc/releases/migration-guide-4.2.rst index 34e9c1665abd..992a360d8c10 100644 --- a/doc/releases/migration-guide-4.2.rst +++ b/doc/releases/migration-guide-4.2.rst @@ -124,6 +124,15 @@ Bluetooth Host :zephyr_file:`include/zephyr/bluetooth/conn.h` have been renamed to ``BT_LE_CS_TONE_ANTENNA_CONFIGURATION_A_B``. +* The ISO data paths are not longer setup automatically, and shall explicitly be setup and removed + by the application by calling :c:func:`bt_iso_setup_data_path` and + :c:func:`bt_iso_remove_data_path` respectively. (:github:`75549`) + +* ``BT_ISO_CHAN_TYPE_CONNECTED`` has been split into ``BT_ISO_CHAN_TYPE_CENTRAL`` and + ``BT_ISO_CHAN_TYPE_PERIPHERAL`` to better describe the type of the ISO channel, as behavior for + each role may be different. Any existing uses/checks for ``BT_ISO_CHAN_TYPE_CONNECTED`` + can be replaced with an ``||`` of the two. (:github:`75549`) + Networking ********** diff --git a/include/zephyr/bluetooth/iso.h b/include/zephyr/bluetooth/iso.h index ff62661b9e8f..de38d102b7de 100644 --- a/include/zephyr/bluetooth/iso.h +++ b/include/zephyr/bluetooth/iso.h @@ -5,7 +5,7 @@ /* * Copyright (c) 2020 Intel Corporation - * Copyright (c) 2021-2024 Nordic Semiconductor ASA + * Copyright (c) 2021-2025 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ @@ -70,6 +70,14 @@ extern "C" { /** Unknown SDU interval */ #define BT_ISO_SDU_INTERVAL_UNKNOWN 0x000000U +/** The minimum value for vendor specific data path ID */ +#define BT_ISO_DATA_PATH_VS_ID_MIN 0x01 +/** The maximum value for vendor specific data path ID */ +#define BT_ISO_DATA_PATH_VS_ID_MAX 0xFE +/** Minimum controller delay in microseconds (0 s) */ +#define BT_ISO_CONTROLLER_DELAY_MIN 0x000000 +/** Maximum controller delay in microseconds (4 s) */ +#define BT_ISO_CONTROLLER_DELAY_MAX 0x3D0900 /** Minimum interval value in microseconds */ #define BT_ISO_SDU_INTERVAL_MIN 0x0000FFU /** Maximum interval value in microseconds */ @@ -178,7 +186,8 @@ enum bt_iso_state { */ enum bt_iso_chan_type { BT_ISO_CHAN_TYPE_NONE, /**< No channel type */ - BT_ISO_CHAN_TYPE_CONNECTED, /**< Connected */ + BT_ISO_CHAN_TYPE_CENTRAL, /**< Connected as central */ + BT_ISO_CHAN_TYPE_PERIPHERAL, /**< Connected as peripheral */ BT_ISO_CHAN_TYPE_BROADCASTER, /**< Isochronous broadcaster */ BT_ISO_CHAN_TYPE_SYNC_RECEIVER /**< Synchronized receiver */ }; @@ -230,13 +239,6 @@ struct bt_iso_chan_io_qos { * This value is ignored if any advanced ISO parameters are set. */ uint8_t rtn; - /** - * @brief Channel data path reference - * - * Setting to NULL default to HCI data path (same as setting path.pid - * to @ref BT_ISO_DATA_PATH_HCI). - */ - struct bt_iso_chan_path *path; #if defined(CONFIG_BT_ISO_TEST_PARAMS) || defined(__DOXYGEN__) /** @@ -293,20 +295,37 @@ struct bt_iso_chan_qos { /** @brief ISO Channel Data Path structure. */ struct bt_iso_chan_path { - /** Default path ID */ - uint8_t pid; - /** Coding Format */ - uint8_t format; + /** + * @brief Default path ID + * + * @ref BT_ISO_DATA_PATH_HCI to use ISO over HCI or between @ref BT_ISO_DATA_PATH_VS_ID_MIN + * and @ref BT_ISO_DATA_PATH_VS_ID_MAX for vendor specific data paths. + */ + uint8_t pid; + /** + * @brief Coding Format + * + * See the BT_HCI_CODING_FORMAT_* values for valid values. + */ + uint8_t format; /** Company ID */ - uint16_t cid; + uint16_t cid; /** Vendor-defined Codec ID */ - uint16_t vid; - /** Controller Delay */ - uint32_t delay; - /** Codec Configuration length*/ - uint8_t cc_len; - /** Pointer to an array containing the Codec Configuration */ - uint8_t *cc; + uint16_t vid; + /** + * @brief Controller Delay in microseconds + * + * Value range from @ref BT_ISO_CONTROLLER_DELAY_MIN to @ref BT_ISO_CONTROLLER_DELAY_MAX. + */ + uint32_t delay; + /** Codec Configuration length */ + uint8_t cc_len; + /** + * @brief Pointer to an array containing the Codec Configuration + * + * Shall not be NULL if bt_iso_chan_path.cc_len is non-zero. + */ + uint8_t *cc; }; /** ISO packet status flag bits */ @@ -691,6 +710,14 @@ struct bt_iso_chan_ops { * channel is disconnected, including when a connection gets * rejected or when setting security fails. * + * If the channel was established (i.e. @ref bt_iso_chan_ops.connected has been called + * for this channel), then the channel object is still valid and the memory of the channel + * shall not be memset to 0 or otherwise free'd. + * To avoid any issues it is recommended to use a @ref k_work_submit or similar to not + * overwrite any data while in the callback. + * + * For the above reason it is still possible to use bt_iso_chan_get_info() on the @p chan. + * * @param chan The channel that has been Disconnected * @param reason BT_HCI_ERR_* reason for the disconnection. */ @@ -957,6 +984,70 @@ int bt_iso_chan_send(struct bt_iso_chan *chan, struct net_buf *buf, uint16_t seq int bt_iso_chan_send_ts(struct bt_iso_chan *chan, struct net_buf *buf, uint16_t seq_num, uint32_t ts); +/** + * @brief Sets up the ISO data path for a ISO channel + * + * The channel must be associated with a BIS or CIS handle first which it is when the + * bt_iso_chan_ops.connected() callback is called. + * + * @param chan The channel to setup the ISO data path for + * @param dir The direction to setup, either @ref BT_HCI_DATAPATH_DIR_CTLR_TO_HOST or + * @ref BT_HCI_DATAPATH_DIR_HOST_TO_CTLR. For ISO broadcast channels this can only be + * @ref BT_HCI_DATAPATH_DIR_HOST_TO_CTLR, and for ISO sync receiver channels this can + * only be @ref BT_HCI_DATAPATH_DIR_CTLR_TO_HOST. + * @param path The data path + * + * @retval 0 Success + * @retval -EINVAL Invalid parameters + * @retval -ENOBUFS No HCI command buffer could be allocated + * @retval -EIO The controller rejected the request or response contains invalid data + * @retval -ENODEV @p chan is not associated with a CIS or BIS handle + * @retval -EACCES The controller rejected the request as disallowed + * @retval -ENOEXEC Unexpected error occurred + */ +int bt_iso_setup_data_path(const struct bt_iso_chan *chan, uint8_t dir, + const struct bt_iso_chan_path *path); + +/** + * @brief Removes the ISO data path for a ISO channel + * + * Removes the ISO data path configured by bt_iso_setup_data_path() for the provided @p dir. + * + * The data paths of CIS for Peripherals are deleted by the controller, + * and thus it is not necessary (or possible) to remove + * data paths of CIS after they have disconnected for a Peripheral, + * as per Bluetooth Core specification 6.0, Vol 4, Part E, Section 7.7.5. + * The data paths for CIS for a Central remain valid, even after a disconnection, and thus a Central + * device should call bt_iso_remove_data_path() on disconnect if it no longer wants to use that CIS. + * All data paths created by a Central are removed when the CIG is removed with + * bt_iso_cig_terminate(). + * + * Any data paths associated with an ISO Sync Receiver BIG are removed by the controller + * when the BIG sync is lost or terminated, and thus it is not necessary (or possible) to remove + * data paths of ISO channels associated with a BIG for a Sync Receiver, + * as per Bluetooth Core specification 6.0, Vol 4, Part E, Section 7.7.65.30 + * + * All data paths associated with an ISO Broadcaster BIG are removed when the BIG is terminated by + * bt_iso_big_terminate(), and thus it is not necessary (or possible) to remove data paths of ISO + * channels associated with a BIG for a Broadcaster, + * as per Bluetooth Core specification 6.0, Vol 4, Part E, Section 7.8.105 + * + * @param chan The channel to setup the ISO data path for + * @param dir The direction to setup, either @ref BT_HCI_DATAPATH_DIR_CTLR_TO_HOST or + * @ref BT_HCI_DATAPATH_DIR_HOST_TO_CTLR. For ISO broadcast channels this can only be + * @ref BT_HCI_DATAPATH_DIR_HOST_TO_CTLR, and for ISO sync receiver channels this can + * only be @ref BT_HCI_DATAPATH_DIR_CTLR_TO_HOST. + + * @retval 0 Success + * @retval -EINVAL Invalid parameters + * @retval -ENOBUFS No HCI command buffer could be allocated + * @retval -EIO The controller rejected the request or response contains invalid data + * @retval -ENODEV @p chan is not associated with a CIS or BIS handle + * @retval -EACCES The controller rejected the request as disallowed + * @retval -ENOEXEC Unexpected error occurred + */ +int bt_iso_remove_data_path(const struct bt_iso_chan *chan, uint8_t dir); + /** @brief ISO Unicast TX Info Structure */ struct bt_iso_unicast_tx_info { /** The transport latency in us */ @@ -1082,20 +1173,30 @@ struct bt_iso_info { /** Connection Type specific Info.*/ union { #if defined(CONFIG_BT_ISO_UNICAST) || defined(__DOXYGEN__) - /** Unicast specific Info. + /** + * @brief Unicast specific Info. + * * Only available when @kconfig{CONFIG_BT_ISO_UNICAST} is enabled. + * Use this when the @ref bt_iso_info.type is @ref BT_ISO_CHAN_TYPE_CENTRAL or + * @ref BT_ISO_CHAN_TYPE_PERIPHERAL. */ struct bt_iso_unicast_info unicast; #endif /* CONFIG_BT_ISO_UNICAST */ #if defined(CONFIG_BT_ISO_BROADCASTER) || defined(__DOXYGEN__) - /** Broadcaster specific Info. + /** + * @brief Broadcaster specific Info. + * * Only available when @kconfig{CONFIG_BT_ISO_BROADCASTER} is enabled. + * Use this when the @ref bt_iso_info.type is @ref BT_ISO_CHAN_TYPE_BROADCASTER. */ struct bt_iso_broadcaster_info broadcaster; #endif /* CONFIG_BT_ISO_BROADCASTER */ #if defined(CONFIG_BT_ISO_SYNC_RECEIVER) || defined(__DOXYGEN__) - /** Sync receiver specific Info. + /** + * @brief Sync receiver specific Info. + * * Only available when @kconfig{CONFIG_BT_ISO_SYNC_RECEIVER} is enabled. + * Use this when the @ref bt_iso_info.type is @ref BT_ISO_CHAN_TYPE_SYNC_RECEIVER. */ struct bt_iso_sync_receiver_info sync_receiver; #endif /* CONFIG_BT_ISO_SYNC_RECEIVER */ diff --git a/samples/bluetooth/iso_broadcast/src/main.c b/samples/bluetooth/iso_broadcast/src/main.c index da06a9c417df..cef28fa1c1db 100644 --- a/samples/bluetooth/iso_broadcast/src/main.c +++ b/samples/bluetooth/iso_broadcast/src/main.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021-2024 Nordic Semiconductor ASA + * Copyright (c) 2021-2025 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ @@ -8,6 +8,7 @@ #include #include +#include #include #include @@ -31,10 +32,21 @@ static uint16_t seq_num; static void iso_connected(struct bt_iso_chan *chan) { + const struct bt_iso_chan_path hci_path = { + .pid = BT_ISO_DATA_PATH_HCI, + .format = BT_HCI_CODING_FORMAT_TRANSPARENT, + }; + int err; + printk("ISO Channel %p connected\n", chan); seq_num = 0U; + err = bt_iso_setup_data_path(chan, BT_HCI_DATAPATH_DIR_HOST_TO_CTLR, &hci_path); + if (err != 0) { + printk("Failed to setup ISO TX data path: %d\n", err); + } + k_sem_give(&sem_big_cmplt); } diff --git a/samples/bluetooth/iso_broadcast_benchmark/src/broadcaster.c b/samples/bluetooth/iso_broadcast_benchmark/src/broadcaster.c index 4665eed3ca87..3f12619ed81e 100644 --- a/samples/bluetooth/iso_broadcast_benchmark/src/broadcaster.c +++ b/samples/bluetooth/iso_broadcast_benchmark/src/broadcaster.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021-2024 Nordic Semiconductor ASA + * Copyright (c) 2021-2025 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ @@ -9,6 +9,7 @@ #include #include +#include #include #include #include @@ -72,8 +73,19 @@ static const struct bt_data ad[] = { static void iso_connected(struct bt_iso_chan *chan) { + const struct bt_iso_chan_path hci_path = { + .pid = BT_ISO_DATA_PATH_HCI, + .format = BT_HCI_CODING_FORMAT_TRANSPARENT, + }; + int err; + LOG_INF("ISO Channel %p connected", chan); + err = bt_iso_setup_data_path(chan, BT_HCI_DATAPATH_DIR_HOST_TO_CTLR, &hci_path); + if (err != 0) { + printk("Failed to setup ISO TX data path: %d\n", err); + } + connected_bis++; if (connected_bis == big_create_param.num_bis) { seq_num = 0U; diff --git a/samples/bluetooth/iso_broadcast_benchmark/src/receiver.c b/samples/bluetooth/iso_broadcast_benchmark/src/receiver.c index af684cecc52f..45efaf66a4bb 100644 --- a/samples/bluetooth/iso_broadcast_benchmark/src/receiver.c +++ b/samples/bluetooth/iso_broadcast_benchmark/src/receiver.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Nordic Semiconductor ASA + * Copyright (c) 2021-2025 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -229,10 +230,21 @@ static void iso_recv(struct bt_iso_chan *chan, static void iso_connected(struct bt_iso_chan *chan) { + const struct bt_iso_chan_path hci_path = { + .pid = BT_ISO_DATA_PATH_HCI, + .format = BT_HCI_CODING_FORMAT_TRANSPARENT, + }; + int err; + LOG_INF("ISO Channel %p connected", chan); big_sync_start_time = k_uptime_get(); + err = bt_iso_setup_data_path(chan, BT_HCI_DATAPATH_DIR_CTLR_TO_HOST, &hci_path); + if (err != 0) { + printk("Failed to setup ISO RX data path: %d\n", err); + } + k_sem_give(&sem_big_sync); } diff --git a/samples/bluetooth/iso_central/src/main.c b/samples/bluetooth/iso_central/src/main.c index a9352363714c..24b2f0d06682 100644 --- a/samples/bluetooth/iso_central/src/main.c +++ b/samples/bluetooth/iso_central/src/main.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021-2024 Nordic Semiconductor ASA + * Copyright (c) 2021-2025 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -142,18 +143,36 @@ static void start_scan(void) static void iso_connected(struct bt_iso_chan *chan) { + const struct bt_iso_chan_path hci_path = { + .pid = BT_ISO_DATA_PATH_HCI, + .format = BT_HCI_CODING_FORMAT_TRANSPARENT, + }; + int err; + printk("ISO Channel %p connected\n", chan); seq_num = 0U; - /* Start send timer */ - k_work_schedule(&iso_send_work, K_MSEC(0)); + err = bt_iso_setup_data_path(chan, BT_HCI_DATAPATH_DIR_HOST_TO_CTLR, &hci_path); + if (err != 0) { + printk("Failed to setup ISO TX data path: %d\n", err); + } else { + /* Start send timer */ + k_work_schedule(&iso_send_work, K_NO_WAIT); + } } static void iso_disconnected(struct bt_iso_chan *chan, uint8_t reason) { + int err; + printk("ISO Channel %p disconnected (reason 0x%02x)\n", chan, reason); k_work_cancel_delayable(&iso_send_work); + + err = bt_iso_remove_data_path(chan, BT_HCI_DATAPATH_DIR_HOST_TO_CTLR); + if (err != 0) { + printk("Failed to setup ISO TX data path: %d\n", err); + } } static struct bt_iso_chan_ops iso_ops = { @@ -165,7 +184,6 @@ static struct bt_iso_chan_io_qos iso_tx = { .sdu = CONFIG_BT_ISO_TX_MTU, .phy = BT_GAP_LE_PHY_2M, .rtn = 1, - .path = NULL, }; static struct bt_iso_chan_qos iso_qos = { diff --git a/samples/bluetooth/iso_connected_benchmark/src/main.c b/samples/bluetooth/iso_connected_benchmark/src/main.c index 1933033f8442..c6c807125ad6 100644 --- a/samples/bluetooth/iso_connected_benchmark/src/main.c +++ b/samples/bluetooth/iso_connected_benchmark/src/main.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Nordic Semiconductor ASA + * Copyright (c) 2021-2025 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -306,7 +307,12 @@ static void iso_recv(struct bt_iso_chan *chan, static void iso_connected(struct bt_iso_chan *chan) { + const struct bt_iso_chan_path hci_path = { + .pid = BT_ISO_DATA_PATH_HCI, + .format = BT_HCI_CODING_FORMAT_TRANSPARENT, + }; struct iso_chan_work *chan_work; + struct bt_iso_info iso_info; int err; LOG_INF("ISO Channel %p connected", chan); @@ -325,6 +331,20 @@ static void iso_connected(struct bt_iso_chan *chan) chan_work = CONTAINER_OF(chan, struct iso_chan_work, chan); chan_work->seq_num = 0U; + if (iso_info.can_recv) { + err = bt_iso_setup_data_path(chan, BT_HCI_DATAPATH_DIR_CTLR_TO_HOST, &hci_path); + if (err != 0) { + LOG_ERR("Failed to setup ISO RX data path: %d", err); + } + } + + if (iso_info.can_send) { + err = bt_iso_setup_data_path(chan, BT_HCI_DATAPATH_DIR_HOST_TO_CTLR, &hci_path); + if (err != 0) { + LOG_ERR("Failed to setup ISO TX data path: %d", err); + } + } + k_sem_give(&sem_iso_connected); } @@ -337,8 +357,10 @@ static void iso_disconnected(struct bt_iso_chan *chan, uint8_t reason) * of the last created CIS. */ static int64_t average_duration; + struct bt_iso_info iso_info; uint64_t iso_conn_duration; uint64_t total_duration; + int err; if (iso_conn_start_time > 0) { iso_conn_duration = k_uptime_get() - iso_conn_start_time; @@ -354,6 +376,25 @@ static void iso_disconnected(struct bt_iso_chan *chan, uint8_t reason) chan, reason, iso_conn_duration, average_duration); k_sem_give(&sem_iso_disconnected); + + err = bt_iso_chan_get_info(chan, &iso_info); + if (err != 0) { + LOG_ERR("Failed to get ISO info: %d\n", err); + } else if (iso_info.type == BT_ISO_CHAN_TYPE_CENTRAL) { + if (iso_info.can_recv) { + err = bt_iso_remove_data_path(chan, BT_HCI_DATAPATH_DIR_CTLR_TO_HOST); + if (err != 0) { + LOG_ERR("Failed to remove ISO RX data path: %d\n", err); + } + } + + if (iso_info.can_send) { + err = bt_iso_remove_data_path(chan, BT_HCI_DATAPATH_DIR_HOST_TO_CTLR); + if (err != 0) { + LOG_ERR("Failed to remove ISO TX data path: %d\n", err); + } + } + } } static struct bt_iso_chan_ops iso_ops = { diff --git a/samples/bluetooth/iso_peripheral/src/main.c b/samples/bluetooth/iso_peripheral/src/main.c index d11baa9633fa..47d69595b5e3 100644 --- a/samples/bluetooth/iso_peripheral/src/main.c +++ b/samples/bluetooth/iso_peripheral/src/main.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Nordic Semiconductor ASA + * Copyright (c) 2021-2025 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -104,7 +105,18 @@ static void iso_recv(struct bt_iso_chan *chan, const struct bt_iso_recv_info *in static void iso_connected(struct bt_iso_chan *chan) { + const struct bt_iso_chan_path hci_path = { + .pid = BT_ISO_DATA_PATH_HCI, + .format = BT_HCI_CODING_FORMAT_TRANSPARENT, + }; + int err; + printk("ISO Channel %p connected\n", chan); + + err = bt_iso_setup_data_path(chan, BT_HCI_DATAPATH_DIR_CTLR_TO_HOST, &hci_path); + if (err != 0) { + printk("Failed to setup ISO RX data path: %d", err); + } } static void iso_disconnected(struct bt_iso_chan *chan, uint8_t reason) @@ -120,7 +132,6 @@ static struct bt_iso_chan_ops iso_ops = { static struct bt_iso_chan_io_qos iso_rx = { .sdu = CONFIG_BT_ISO_TX_MTU, - .path = NULL, }; static struct bt_iso_chan_qos iso_qos = { diff --git a/samples/bluetooth/iso_receive/src/main.c b/samples/bluetooth/iso_receive/src/main.c index e51bbe6d34be..81f2b80da663 100644 --- a/samples/bluetooth/iso_receive/src/main.c +++ b/samples/bluetooth/iso_receive/src/main.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Nordic Semiconductor ASA + * Copyright (c) 2021-2024 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -233,7 +234,19 @@ static void iso_recv(struct bt_iso_chan *chan, const struct bt_iso_recv_info *in static void iso_connected(struct bt_iso_chan *chan) { + const struct bt_iso_chan_path hci_path = { + .pid = BT_ISO_DATA_PATH_HCI, + .format = BT_HCI_CODING_FORMAT_TRANSPARENT, + }; + int err; + printk("ISO Channel %p connected\n", chan); + + err = bt_iso_setup_data_path(chan, BT_HCI_DATAPATH_DIR_CTLR_TO_HOST, &hci_path); + if (err != 0) { + printk("Failed to setup ISO RX data path: %d\n", err); + } + k_sem_give(&sem_big_sync); } diff --git a/subsys/bluetooth/audio/ascs.c b/subsys/bluetooth/audio/ascs.c index f2edf555a936..6f4924dc60d4 100644 --- a/subsys/bluetooth/audio/ascs.c +++ b/subsys/bluetooth/audio/ascs.c @@ -3,7 +3,7 @@ */ /* * Copyright (c) 2020 Intel Corporation - * Copyright (c) 2022-2023 Nordic Semiconductor ASA + * Copyright (c) 2022-2025 Nordic Semiconductor ASA * Copyright (c) 2024 Demant A/S * * SPDX-License-Identifier: Apache-2.0 @@ -384,6 +384,11 @@ static void ase_enter_state_streaming(struct bt_ascs_ase *ase) __ASSERT_NO_MSG(stream != NULL); + /* Setup the ISO data path when the stream is started. We could do it earlier when the CIS + * is connected, but then we would just receive audio data that we would then just discard + */ + bt_bap_setup_iso_data_path(stream); + ops = stream->ops; if (ops != NULL && ops->started != NULL) { ops->started(stream); @@ -417,6 +422,14 @@ static void ase_exit_state_streaming(struct bt_ascs_ase *ase) reason = BT_HCI_ERR_UNSPECIFIED; } + if (ase->ep.iso != NULL && ase->ep.iso->chan.state == BT_ISO_STATE_CONNECTED) { + /* Remove the ISO data path as we no longer want to process any ISO data for this + * stream, but only if the CIS is still connected. If the CIS disconnected, then the + * data path is automatically removed by the controller + */ + bt_bap_remove_iso_data_path(stream); + } + ops = stream->ops; /* @@ -1996,12 +2009,6 @@ static void ase_qos(struct bt_ascs_ase *ase, uint8_t cig_id, uint8_t cis_id, ep->qos = *qos; stream->qos = &ep->qos; - /* We setup the data path here, as this is the earliest where - * we have the ISO <-> EP coupling completed (due to setting - * the CIS ID in the QoS procedure). - */ - bt_bap_iso_configure_data_path(ep, stream->codec_cfg); - ep->cig_id = cig_id; ep->cis_id = cis_id; diff --git a/subsys/bluetooth/audio/bap_broadcast_sink.c b/subsys/bluetooth/audio/bap_broadcast_sink.c index fa1f0b8ee564..9bb13aec5b95 100644 --- a/subsys/bluetooth/audio/bap_broadcast_sink.c +++ b/subsys/bluetooth/audio/bap_broadcast_sink.c @@ -1,7 +1,7 @@ /* Bluetooth Audio Broadcast Sink */ /* - * Copyright (c) 2021-2024 Nordic Semiconductor ASA + * Copyright (c) 2021-2025 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ @@ -356,6 +356,9 @@ static void broadcast_sink_iso_connected(struct bt_iso_chan *chan) broadcast_sink_set_ep_state(ep, BT_BAP_EP_STATE_STREAMING); + /* Setup the ISO data path */ + bt_bap_setup_iso_data_path(stream); + if (ops != NULL && ops->started != NULL) { ops->started(stream); } else { @@ -973,7 +976,6 @@ static int bt_bap_broadcast_sink_setup_stream(struct bt_bap_broadcast_sink *sink bt_bap_iso_bind_ep(iso, ep); bt_bap_qos_cfg_to_iso_qos(iso->chan.qos->rx, &sink->qos_cfg); - bt_bap_iso_configure_data_path(ep, codec_cfg); bt_bap_iso_unref(iso); diff --git a/subsys/bluetooth/audio/bap_broadcast_source.c b/subsys/bluetooth/audio/bap_broadcast_source.c index 132dca5580a3..748d9d68db9c 100644 --- a/subsys/bluetooth/audio/bap_broadcast_source.c +++ b/subsys/bluetooth/audio/bap_broadcast_source.c @@ -1,7 +1,7 @@ /* Bluetooth Audio Broadcast Source */ /* - * Copyright (c) 2021-2024 Nordic Semiconductor ASA + * Copyright (c) 2021-2025 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ @@ -191,6 +191,9 @@ static void broadcast_source_iso_connected(struct bt_iso_chan *chan) stream->_prev_seq_num = 0U; #endif /* CONFIG_BT_BAP_DEBUG_STREAM_SEQ_NUM */ + /* Setup the ISO data path */ + bt_bap_setup_iso_data_path(stream); + ops = stream->ops; if (ops != NULL && ops->connected != NULL) { ops->connected(stream); @@ -317,7 +320,7 @@ static int broadcast_source_setup_stream(uint8_t index, struct bt_bap_stream *st bt_bap_iso_bind_ep(iso, ep); bt_bap_qos_cfg_to_iso_qos(iso->chan.qos->tx, qos); - bt_bap_iso_configure_data_path(ep, codec_cfg); + #if defined(CONFIG_BT_ISO_TEST_PARAMS) iso->chan.qos->num_subevents = qos->num_subevents; #endif /* CONFIG_BT_ISO_TEST_PARAMS */ @@ -967,7 +970,6 @@ int bt_bap_broadcast_source_reconfig(struct bt_bap_broadcast_source *source, */ SYS_SLIST_FOR_EACH_CONTAINER(&subgroup->streams, stream, _node) { bt_bap_stream_attach(NULL, stream, stream->ep, codec_cfg); - bt_bap_iso_configure_data_path(stream->ep, codec_cfg); } } diff --git a/subsys/bluetooth/audio/bap_iso.c b/subsys/bluetooth/audio/bap_iso.c index e58e139a7719..a661e4c357bf 100644 --- a/subsys/bluetooth/audio/bap_iso.c +++ b/subsys/bluetooth/audio/bap_iso.c @@ -170,43 +170,68 @@ static struct bt_bap_iso_dir *bap_iso_get_iso_dir(bool unicast_client, struct bt } } -void bt_bap_iso_configure_data_path(struct bt_bap_ep *ep, struct bt_audio_codec_cfg *codec_cfg) +void bt_bap_setup_iso_data_path(struct bt_bap_stream *stream) { + struct bt_audio_codec_cfg *codec_cfg = stream->codec_cfg; + struct bt_bap_ep *ep = stream->ep; struct bt_bap_iso *bap_iso = ep->iso; - struct bt_iso_chan_qos *qos = bap_iso->chan.qos; const bool is_unicast_client = IS_ENABLED(CONFIG_BT_BAP_UNICAST_CLIENT) && bt_bap_ep_is_unicast_client(ep); struct bt_bap_iso_dir *iso_dir = bap_iso_get_iso_dir(is_unicast_client, bap_iso, ep->dir); - struct bt_iso_chan_path *path = &iso_dir->path; + struct bt_iso_chan_path path = {0}; + uint8_t dir; + int err; - /* Setup the data path objects */ if (iso_dir == &bap_iso->rx) { - qos->rx->path = path; + dir = BT_HCI_DATAPATH_DIR_CTLR_TO_HOST; } else { - qos->tx->path = path; + dir = BT_HCI_DATAPATH_DIR_HOST_TO_CTLR; } + path.pid = codec_cfg->path_id; + /* Configure the data path to either use the controller for transcoding, or set the path to * be transparent to indicate that the transcoding happens somewhere else */ - path->pid = codec_cfg->path_id; - if (codec_cfg->ctlr_transcode) { - path->format = codec_cfg->id; - path->cid = codec_cfg->cid; - path->vid = codec_cfg->vid; - path->delay = 0; - path->cc_len = codec_cfg->data_len; - path->cc = codec_cfg->data; + path.format = codec_cfg->id; + path.cid = codec_cfg->cid; + path.vid = codec_cfg->vid; + path.cc_len = codec_cfg->data_len; + path.cc = codec_cfg->data; + } else { + path.format = BT_HCI_CODING_FORMAT_TRANSPARENT; + } + + err = bt_iso_setup_data_path(&bap_iso->chan, dir, &path); + if (err != 0) { + LOG_ERR("Failed to set ISO data path for ep %p and codec_cfg %p: %d", ep, codec_cfg, + err); + } +} + +void bt_bap_remove_iso_data_path(struct bt_bap_stream *stream) +{ + struct bt_bap_ep *ep = stream->ep; + struct bt_bap_iso *bap_iso = ep->iso; + const bool is_unicast_client = + IS_ENABLED(CONFIG_BT_BAP_UNICAST_CLIENT) && bt_bap_ep_is_unicast_client(ep); + struct bt_bap_iso_dir *iso_dir = bap_iso_get_iso_dir(is_unicast_client, bap_iso, ep->dir); + uint8_t dir; + int err; + + if (iso_dir == &bap_iso->rx) { + dir = BT_HCI_DATAPATH_DIR_CTLR_TO_HOST; } else { - path->format = BT_HCI_CODING_FORMAT_TRANSPARENT; - path->cid = 0; - path->vid = 0; - path->delay = 0; - path->cc_len = 0; - path->cc = NULL; + dir = BT_HCI_DATAPATH_DIR_HOST_TO_CTLR; + } + + err = bt_iso_remove_data_path(&bap_iso->chan, dir); + if (err != 0) { + LOG_ERR("Failed to remove ISO data path for ep %p: %d", ep, err); } } + static bool is_unicast_client_ep(struct bt_bap_ep *ep) { return IS_ENABLED(CONFIG_BT_BAP_UNICAST_CLIENT) && bt_bap_ep_is_unicast_client(ep); diff --git a/subsys/bluetooth/audio/bap_iso.h b/subsys/bluetooth/audio/bap_iso.h index f1ebd0eed9b2..18a65c1ac7a7 100644 --- a/subsys/bluetooth/audio/bap_iso.h +++ b/subsys/bluetooth/audio/bap_iso.h @@ -2,7 +2,7 @@ * @brief Internal APIs for BAP ISO handling * * Copyright (c) 2022 Codecoup - * Copyright (c) 2023 Nordic Semiconductor ASA + * Copyright (c) 2023-2024 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ @@ -19,7 +19,6 @@ struct bt_bap_iso_dir { struct bt_bap_stream *stream; struct bt_bap_ep *ep; - struct bt_iso_chan_path path; struct bt_iso_chan_io_qos qos; uint8_t cc[CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE]; }; @@ -46,7 +45,8 @@ void bt_bap_iso_foreach(bt_bap_iso_func_t func, void *user_data); struct bt_bap_iso *bt_bap_iso_find(bt_bap_iso_func_t func, void *user_data); void bt_bap_iso_init(struct bt_bap_iso *iso, struct bt_iso_chan_ops *ops); void bt_bap_iso_bind_ep(struct bt_bap_iso *iso, struct bt_bap_ep *ep); -void bt_bap_iso_configure_data_path(struct bt_bap_ep *ep, struct bt_audio_codec_cfg *codec_cfg); +void bt_bap_setup_iso_data_path(struct bt_bap_stream *stream); +void bt_bap_remove_iso_data_path(struct bt_bap_stream *stream); void bt_bap_iso_unbind_ep(struct bt_bap_iso *iso, struct bt_bap_ep *ep); struct bt_bap_ep *bt_bap_iso_get_ep(bool unicast_client, struct bt_bap_iso *iso, enum bt_audio_dir dir); diff --git a/subsys/bluetooth/audio/bap_unicast_client.c b/subsys/bluetooth/audio/bap_unicast_client.c index 2b52c000b11b..1f081ee805b1 100644 --- a/subsys/bluetooth/audio/bap_unicast_client.c +++ b/subsys/bluetooth/audio/bap_unicast_client.c @@ -4,7 +4,7 @@ /* * Copyright (c) 2020 Intel Corporation - * Copyright (c) 2022-2023 Nordic Semiconductor ASA + * Copyright (c) 2022-2025 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ @@ -1019,13 +1019,6 @@ static void unicast_client_ep_qos_state(struct bt_bap_ep *ep, struct net_buf_sim if (err != 0) { LOG_ERR("Failed to disconnect stream: %d", err); } - } else { - /* We setup the data path here, as this is the earliest where - * we have the ISO <-> EP coupling completed (due to setting - * the CIS ID in the QoS procedure). - */ - - bt_bap_iso_configure_data_path(ep, stream->codec_cfg); } /* Notify upper layer */ @@ -1108,6 +1101,11 @@ static void unicast_client_ep_streaming_state(struct bt_bap_ep *ep, struct net_b LOG_DBG("dir %s cig 0x%02x cis 0x%02x", bt_audio_dir_str(ep->dir), ep->cig_id, ep->cis_id); + /* Setup the ISO data path when the stream is started. We could do it earlier when the CIS + * is connected, but then we would just receive audio data that we would then just discard + */ + bt_bap_setup_iso_data_path(stream); + /* Notify upper layer * * If the state did not change then only the metadata was changed @@ -1222,6 +1220,13 @@ static void unicast_client_ep_set_status(struct bt_bap_ep *ep, struct net_buf_si ep->reason = BT_HCI_ERR_SUCCESS; } + if (ep->iso != NULL) { + /* Remove the ISO data path as we no longer want to process any ISO + * data for this stream. + */ + bt_bap_remove_iso_data_path(stream); + } + if (ops != NULL && ops->stopped != NULL) { ops->stopped(stream, reason); } else { diff --git a/subsys/bluetooth/host/conn.c b/subsys/bluetooth/host/conn.c index 92ebec4ad4dc..366ba197c4b1 100644 --- a/subsys/bluetooth/host/conn.c +++ b/subsys/bluetooth/host/conn.c @@ -7,6 +7,7 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include #include #include #include @@ -2978,7 +2979,9 @@ int bt_conn_get_info(const struct bt_conn *conn, struct bt_conn_info *info) #if defined(CONFIG_BT_ISO) case BT_CONN_TYPE_ISO: if (IS_ENABLED(CONFIG_BT_ISO_UNICAST) && - conn->iso.info.type == BT_ISO_CHAN_TYPE_CONNECTED && conn->iso.acl != NULL) { + (conn->iso.info.type == BT_ISO_CHAN_TYPE_CENTRAL || + conn->iso.info.type == BT_ISO_CHAN_TYPE_PERIPHERAL) && + conn->iso.acl != NULL) { info->le.dst = &conn->iso.acl->le.dst; info->le.src = &bt_dev.id_addr[conn->iso.acl->id]; } else { diff --git a/subsys/bluetooth/host/iso.c b/subsys/bluetooth/host/iso.c index 973a9c61f764..cc881e3d8ce9 100644 --- a/subsys/bluetooth/host/iso.c +++ b/subsys/bluetooth/host/iso.c @@ -2,7 +2,7 @@ /* * Copyright (c) 2020 Intel Corporation - * Copyright (c) 2021-2024 Nordic Semiconductor ASA + * Copyright (c) 2021-2025 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ @@ -77,7 +77,6 @@ struct bt_conn iso_conns[CONFIG_BT_ISO_MAX_CHAN]; struct bt_iso_cig cigs[CONFIG_BT_ISO_MAX_CIG]; static struct bt_iso_cig *get_cig(const struct bt_iso_chan *iso_chan); -static void bt_iso_remove_data_path(struct bt_conn *iso); static int hci_le_create_cis(const struct bt_iso_connect_param *param, size_t count); #endif /* CONFIG_BT_ISO_CENTRAL */ @@ -197,15 +196,6 @@ static int hci_le_setup_iso_data_path(const struct bt_conn *iso, uint8_t dir, uint8_t *cc; int err; - __ASSERT(dir == BT_HCI_DATAPATH_DIR_HOST_TO_CTLR || dir == BT_HCI_DATAPATH_DIR_CTLR_TO_HOST, - "invalid ISO data path dir: %u", dir); - - if ((path->cc == NULL && path->cc_len != 0)) { - LOG_DBG("Invalid ISO data path CC: %p %u", path->cc, path->cc_len); - - return -EINVAL; - } - buf = bt_hci_cmd_create(BT_HCI_OP_LE_SETUP_ISO_PATH, sizeof(*cp) + path->cc_len); if (!buf) { return -ENOBUFS; @@ -249,103 +239,197 @@ static void bt_iso_chan_add(struct bt_conn *iso, struct bt_iso_chan *chan) LOG_DBG("iso %p chan %p", iso, chan); } -static int bt_iso_setup_data_path(struct bt_iso_chan *chan) +static int validate_iso_setup_data_path_parms(const struct bt_iso_chan *chan, uint8_t dir, + const struct bt_iso_chan_path *path) { - int err; - struct bt_iso_chan_path default_hci_path = {.pid = BT_ISO_DATA_PATH_HCI, - .format = BT_HCI_CODING_FORMAT_TRANSPARENT, - .cc_len = 0x00}; - struct bt_iso_chan_path *out_path = NULL; - struct bt_iso_chan_path *in_path = NULL; - struct bt_iso_chan_io_qos *tx_qos; - struct bt_iso_chan_io_qos *rx_qos; struct bt_conn *iso; - uint8_t dir; + + CHECKIF(chan == NULL) { + LOG_DBG("chan is NULL"); + + return -EINVAL; + } + + CHECKIF(path == NULL) { + LOG_DBG("path is NULL"); + + return -EINVAL; + } + + CHECKIF(dir != BT_HCI_DATAPATH_DIR_HOST_TO_CTLR && + dir != BT_HCI_DATAPATH_DIR_CTLR_TO_HOST) { + LOG_DBG("Invalid dir: %u", dir); + + return -EINVAL; + } iso = chan->iso; + if (iso == NULL) { + LOG_DBG("chan %p not associated with a CIS/BIS handle", chan); - tx_qos = chan->qos->tx; - rx_qos = chan->qos->rx; + return -ENODEV; + } - /* The following code sets the in and out paths for ISO data. - * If the application provides a path for a direction (tx/rx) we use - * that, otherwise we simply fall back to HCI. - * - * If the direction is not set (by whether tx_qos or rx_qos is NULL), - * then we fallback to the HCI path object, but we disable the direction - * in the controller. - */ + if (!iso->iso.info.can_recv && dir == BT_HCI_DATAPATH_DIR_CTLR_TO_HOST) { + LOG_DBG("Invalid dir %u for chan %p that cannot receive data", dir, chan); - if (tx_qos != NULL && iso->iso.info.can_send) { - if (tx_qos->path != NULL) { /* Use application path */ - in_path = tx_qos->path; - } else { /* else fallback to HCI path */ - in_path = &default_hci_path; - } + return -EINVAL; } - if (rx_qos != NULL && iso->iso.info.can_recv) { - if (rx_qos->path != NULL) { /* Use application path */ - out_path = rx_qos->path; - } else { /* else fallback to HCI path */ - out_path = &default_hci_path; - } + if (!iso->iso.info.can_send && dir == BT_HCI_DATAPATH_DIR_HOST_TO_CTLR) { + LOG_DBG("Invalid dir %u for chan %p that cannot send data", dir, chan); + + return -EINVAL; } - __ASSERT(in_path || out_path, "At least one path shall be shell: in %p out %p", in_path, - out_path); + CHECKIF(path->pid != BT_ISO_DATA_PATH_HCI && + !IN_RANGE(path->pid, BT_ISO_DATA_PATH_VS_ID_MIN, BT_ISO_DATA_PATH_VS_ID_MAX)) { + LOG_DBG("Invalid pid %u", path->pid); - if (IS_ENABLED(CONFIG_BT_ISO_BROADCASTER) && - iso->iso.info.type == BT_ISO_CHAN_TYPE_BROADCASTER && in_path) { - dir = BT_HCI_DATAPATH_DIR_HOST_TO_CTLR; - err = hci_le_setup_iso_data_path(iso, dir, in_path); - if (err != 0) { - LOG_DBG("Failed to set broadcaster data path: %d", err); - } + return -EINVAL; + } + + CHECKIF(path->format > BT_HCI_CODING_FORMAT_G729A && + path->format != BT_HCI_CODING_FORMAT_VS) { + LOG_DBG("Invalid format %u", path->format); + + return -EINVAL; + } + + CHECKIF(path->delay > BT_ISO_CONTROLLER_DELAY_MAX) { + LOG_DBG("Invalid delay: %u", path->delay); + + return -EINVAL; + } + CHECKIF(path->cc_len > 0U && path->cc == NULL) { + LOG_DBG("No CC provided for CC length %u", path->cc_len); + + return -EINVAL; + } + + return 0; +} + +int bt_iso_setup_data_path(const struct bt_iso_chan *chan, uint8_t dir, + const struct bt_iso_chan_path *path) +{ + int err; + + err = validate_iso_setup_data_path_parms(chan, dir, path); + if (err != 0) { return err; - } else if (IS_ENABLED(CONFIG_BT_ISO_SYNC_RECEIVER) && - iso->iso.info.type == BT_ISO_CHAN_TYPE_SYNC_RECEIVER && out_path) { - dir = BT_HCI_DATAPATH_DIR_CTLR_TO_HOST; - err = hci_le_setup_iso_data_path(iso, dir, out_path); - if (err != 0) { - LOG_DBG("Failed to set sync receiver data path: %d", err); + } + + err = hci_le_setup_iso_data_path(chan->iso, dir, path); + if (err != 0) { + LOG_DBG("Failed to set data path: %d", err); + + /* Return known possible errors */ + if (err == -ENOBUFS || err == -EIO || err == -EACCES) { + return err; } + LOG_DBG("Unknown error from hci_le_setup_iso_data_path: %d", err); + + return -ENOEXEC; + } + + return 0; +} + +static int hci_le_remove_iso_data_path(struct bt_conn *iso, uint8_t dir) +{ + struct bt_hci_cp_le_remove_iso_path *cp; + struct bt_hci_rp_le_remove_iso_path *rp; + struct net_buf *buf, *rsp; + int err; + + buf = bt_hci_cmd_create(BT_HCI_OP_LE_REMOVE_ISO_PATH, sizeof(*cp)); + if (!buf) { + return -ENOBUFS; + } + + cp = net_buf_add(buf, sizeof(*cp)); + cp->handle = sys_cpu_to_le16(iso->handle); + /* The path_dir is a bitfield and it's technically possible to do BIT(0) | BIT(1) but for + * simplicity our API only supports removing a single ISO data path at a time. + * We can convert from BT_HCI_DATAPATH_DIR_HOST_TO_CTLR and BT_HCI_DATAPATH_DIR_CTLR_TO_HOST + * to the proper values just by using `BIT` + */ + cp->path_dir = BIT(dir); + + err = bt_hci_cmd_send_sync(BT_HCI_OP_LE_REMOVE_ISO_PATH, buf, &rsp); + if (err) { return err; - } else if (IS_ENABLED(CONFIG_BT_ISO_UNICAST) && - iso->iso.info.type == BT_ISO_CHAN_TYPE_CONNECTED) { - if (in_path != NULL) { - /* Enable TX */ - dir = BT_HCI_DATAPATH_DIR_HOST_TO_CTLR; - err = hci_le_setup_iso_data_path(iso, dir, in_path); - if (err) { - LOG_DBG("Failed to setup host-to-ctrl path: %d", err); - return err; - } - } + } - if (out_path != NULL) { - /* Enable RX */ - dir = BT_HCI_DATAPATH_DIR_CTLR_TO_HOST; - err = hci_le_setup_iso_data_path(iso, dir, out_path); - if (err) { - LOG_DBG("Failed to setup ctlr-to-host path: %d", err); - return err; - } - } + rp = (void *)rsp->data; + if (rp->status || (sys_le16_to_cpu(rp->handle) != iso->handle)) { + err = -EIO; + } + + net_buf_unref(rsp); + + return err; +} + +static int validate_iso_remove_data_path(const struct bt_iso_chan *chan, uint8_t dir) +{ + struct bt_conn *iso; + + CHECKIF(chan == NULL) { + LOG_DBG("chan is NULL"); - return 0; - } else { - __ASSERT(false, "Invalid iso.info.type: %u", iso->iso.info.type); return -EINVAL; } + + CHECKIF(dir != BT_HCI_DATAPATH_DIR_HOST_TO_CTLR && + dir != BT_HCI_DATAPATH_DIR_CTLR_TO_HOST) { + LOG_DBG("Invalid dir: %u", dir); + + return -EINVAL; + } + + iso = chan->iso; + if (iso == NULL) { + LOG_DBG("chan %p not associated with a CIS/BIS handle", chan); + + return -ENODEV; + } + + return 0; +} + +int bt_iso_remove_data_path(const struct bt_iso_chan *chan, uint8_t dir) +{ + int err; + + err = validate_iso_remove_data_path(chan, dir); + if (err != 0) { + return err; + } + + err = hci_le_remove_iso_data_path(chan->iso, dir); + if (err != 0) { + LOG_DBG("Failed to remove data path: %d", err); + + /* Return known possible errors */ + if (err == -ENOBUFS || err == -EIO || err == -EACCES) { + return err; + } + + LOG_DBG("Unknown error from hci_le_remove_iso_data_path: %d", err); + + return -ENOEXEC; + } + + return 0; } void bt_iso_connected(struct bt_conn *iso) { struct bt_iso_chan *chan; - int err; if (iso == NULL || iso->type != BT_CONN_TYPE_ISO) { LOG_DBG("Invalid parameters: iso %p iso->type %u", iso, iso ? iso->type : 0); @@ -360,32 +444,6 @@ void bt_iso_connected(struct bt_conn *iso) return; } - err = bt_iso_setup_data_path(chan); - if (err != 0) { - if (false) { - -#if defined(CONFIG_BT_ISO_BROADCAST) - } else if (iso->iso.info.type == BT_ISO_CHAN_TYPE_BROADCASTER || - iso->iso.info.type == BT_ISO_CHAN_TYPE_SYNC_RECEIVER) { - struct bt_iso_big *big; - - big = lookup_big_by_handle(iso->iso.big_handle); - - err = bt_iso_big_terminate(big); - if (err != 0) { - LOG_ERR("Could not terminate BIG: %d", err); - } -#endif /* CONFIG_BT_ISO_BROADCAST */ - - } else if (IS_ENABLED(CONFIG_BT_ISO_UNICAST) && - iso->iso.info.type == BT_ISO_CHAN_TYPE_CONNECTED) { - bt_conn_disconnect(iso, BT_HCI_ERR_REMOTE_USER_TERM_CONN); - } else { - __ASSERT(false, "Invalid iso.info.type: %u", iso->iso.info.type); - } - return; - } - bt_iso_chan_set_state(chan, BT_ISO_STATE_CONNECTED); if (chan->ops->connected) { @@ -395,6 +453,7 @@ void bt_iso_connected(struct bt_conn *iso) static void bt_iso_chan_disconnected(struct bt_iso_chan *chan, uint8_t reason) { + const uint8_t conn_type = chan->iso->iso.info.type; LOG_DBG("%p, reason 0x%02x", chan, reason); __ASSERT(chan->iso != NULL, "NULL conn for iso chan %p", chan); @@ -402,23 +461,26 @@ static void bt_iso_chan_disconnected(struct bt_iso_chan *chan, uint8_t reason) bt_iso_chan_set_state(chan, BT_ISO_STATE_DISCONNECTED); bt_conn_set_state(chan->iso, BT_CONN_DISCONNECT_COMPLETE); + /* Calling disconnected before final cleanup allows users to use bt_iso_chan_get_info in + * the callback and to be more similar to the ACL disconnected callback. This also means + * that the channel cannot be reused or memset in the callback + */ + if (chan->ops->disconnected) { + chan->ops->disconnected(chan, reason); + } + /* The peripheral does not have the concept of a CIG, so once a CIS * disconnects it is completely freed by unref'ing it */ if (IS_ENABLED(CONFIG_BT_ISO_UNICAST) && - chan->iso->iso.info.type == BT_ISO_CHAN_TYPE_CONNECTED) { + (conn_type == BT_ISO_CHAN_TYPE_CENTRAL || conn_type == BT_ISO_CHAN_TYPE_PERIPHERAL)) { bt_iso_cleanup_acl(chan->iso); - if (chan->iso->role == BT_HCI_ROLE_PERIPHERAL) { + if (conn_type == BT_ISO_CHAN_TYPE_PERIPHERAL) { bt_conn_unref(chan->iso); chan->iso = NULL; #if defined(CONFIG_BT_ISO_CENTRAL) } else { - /* ISO data paths are automatically removed when the - * peripheral disconnects, so we only need to - * move it for the central - */ - bt_iso_remove_data_path(chan->iso); bool is_chan_connected; struct bt_iso_cig *cig; struct bt_iso_chan *cis_chan; @@ -442,10 +504,6 @@ static void bt_iso_chan_disconnected(struct bt_iso_chan *chan, uint8_t reason) #endif /* CONFIG_BT_ISO_CENTRAL */ } } - - if (chan->ops->disconnected) { - chan->ops->disconnected(chan, reason); - } } void bt_iso_disconnected(struct bt_conn *iso) @@ -1131,7 +1189,7 @@ static void store_cis_info(const struct bt_hci_evt_le_cis_established *evt, stru tx->sdu = sys_le16_to_cpu(evt->p_max_pdu); } - iso_conn->info.type = BT_ISO_CHAN_TYPE_CONNECTED; + iso_conn->info.type = BT_ISO_CHAN_TYPE_PERIPHERAL; } else { /* values are already set for central - Verify */ if (tx != NULL && tx->phy != c_phy) { @@ -1548,7 +1606,7 @@ void hci_le_cis_req(struct net_buf *buf) return; } - iso->iso.info.type = BT_ISO_CHAN_TYPE_CONNECTED; + iso->iso.info.type = BT_ISO_CHAN_TYPE_PERIPHERAL; iso->iso.cig_id = evt->cig_id; iso->iso.cis_id = evt->cis_id; @@ -1591,80 +1649,6 @@ static struct bt_conn *bt_conn_add_iso(struct bt_conn *acl) #endif /* CONFIG_BT_ISO_PERIPHERAL */ #if defined(CONFIG_BT_ISO_CENTRAL) -static int hci_le_remove_iso_data_path(struct bt_conn *iso, uint8_t dir) -{ - struct bt_hci_cp_le_remove_iso_path *cp; - struct bt_hci_rp_le_remove_iso_path *rp; - struct net_buf *buf, *rsp; - int err; - - buf = bt_hci_cmd_create(BT_HCI_OP_LE_REMOVE_ISO_PATH, sizeof(*cp)); - if (!buf) { - return -ENOBUFS; - } - - cp = net_buf_add(buf, sizeof(*cp)); - cp->handle = sys_cpu_to_le16(iso->handle); - cp->path_dir = dir; - - err = bt_hci_cmd_send_sync(BT_HCI_OP_LE_REMOVE_ISO_PATH, buf, &rsp); - if (err) { - return err; - } - - rp = (void *)rsp->data; - if (rp->status || (sys_le16_to_cpu(rp->handle) != iso->handle)) { - err = -EIO; - } - - net_buf_unref(rsp); - - return err; -} - -static void bt_iso_remove_data_path(struct bt_conn *iso) -{ - enum bt_iso_chan_type type = iso->iso.info.type; - - LOG_DBG("%p", iso); - - /* TODO: Removing the ISO data path is never used for broadcast: - * Remove the following broadcast implementation? - */ - if ((IS_ENABLED(CONFIG_BT_ISO_BROADCASTER) && type == BT_ISO_CHAN_TYPE_BROADCASTER) || - (IS_ENABLED(CONFIG_BT_ISO_SYNC_RECEIVER) && type == BT_ISO_CHAN_TYPE_SYNC_RECEIVER)) { - struct bt_iso_chan *chan; - struct bt_iso_chan_io_qos *tx_qos; - uint8_t dir; - - chan = iso_chan(iso); - if (chan == NULL) { - return; - } - - tx_qos = chan->qos->tx; - - /* Only remove one data path for BIS as per the spec */ - if (tx_qos) { - dir = BIT(BT_HCI_DATAPATH_DIR_HOST_TO_CTLR); - } else { - dir = BIT(BT_HCI_DATAPATH_DIR_CTLR_TO_HOST); - } - - (void)hci_le_remove_iso_data_path(iso, dir); - } else if (IS_ENABLED(CONFIG_BT_ISO_UNICAST) && type == BT_ISO_CHAN_TYPE_CONNECTED) { - /* Remove both directions for CIS*/ - - /* TODO: Check which has been setup first to avoid removing - * data paths that are not setup - */ - (void)hci_le_remove_iso_data_path(iso, BIT(BT_HCI_DATAPATH_DIR_HOST_TO_CTLR)); - (void)hci_le_remove_iso_data_path(iso, BIT(BT_HCI_DATAPATH_DIR_CTLR_TO_HOST)); - } else { - __ASSERT(false, "Invalid iso.type: %u", type); - } -} - static bool valid_chan_qos(const struct bt_iso_chan_qos *qos, bool advanced) { #if defined(CONFIG_BT_ISO_TEST_PARAMS) @@ -1984,7 +1968,7 @@ static int cig_init_cis(struct bt_iso_cig *cig, const struct bt_iso_cig_param *p iso_conn = &cis->iso->iso; iso_conn->cig_id = cig->id; - iso_conn->info.type = BT_ISO_CHAN_TYPE_CONNECTED; + iso_conn->info.type = BT_ISO_CHAN_TYPE_CENTRAL; iso_conn->cis_id = cig->num_cis++; bt_iso_chan_add(cis->iso, cis); @@ -2553,7 +2537,8 @@ static bool iso_chans_connecting(void) const struct bt_conn *iso = &iso_conns[i]; const struct bt_iso_chan *iso_chan; - if (iso == NULL || iso->iso.info.type != BT_ISO_CHAN_TYPE_CONNECTED) { + if (iso == NULL || !(iso->iso.info.type == BT_ISO_CHAN_TYPE_CENTRAL || + iso->iso.info.type == BT_ISO_CHAN_TYPE_PERIPHERAL)) { continue; } diff --git a/subsys/bluetooth/host/shell/iso.c b/subsys/bluetooth/host/shell/iso.c index 9113859b7135..47a6cfb87bd3 100644 --- a/subsys/bluetooth/host/shell/iso.c +++ b/subsys/bluetooth/host/shell/iso.c @@ -5,7 +5,7 @@ /* * Copyright (c) 2020 Intel Corporation - * Copyright (c) 2021 Nordic Semiconductor ASA + * Copyright (c) 2021-2025 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -85,6 +86,10 @@ static void iso_recv(struct bt_iso_chan *chan, const struct bt_iso_recv_info *in static void iso_connected(struct bt_iso_chan *chan) { + const struct bt_iso_chan_path hci_path = { + .pid = BT_ISO_DATA_PATH_HCI, + .format = BT_HCI_CODING_FORMAT_TRANSPARENT, + }; struct bt_iso_info iso_info; int err; @@ -92,12 +97,13 @@ static void iso_connected(struct bt_iso_chan *chan) err = bt_iso_chan_get_info(chan, &iso_info); if (err != 0) { - printk("Failed to get ISO info: %d", err); + bt_shell_error("Failed to get ISO info: %d", err); return; } #if defined(CONFIG_BT_ISO_TX) - if (iso_info.type == BT_ISO_CHAN_TYPE_CONNECTED) { + if (iso_info.type == BT_ISO_CHAN_TYPE_CENTRAL || + iso_info.type == BT_ISO_CHAN_TYPE_PERIPHERAL) { cis_sn_last = 0U; cis_sn_last_updated_ticks = k_uptime_ticks(); } else { @@ -105,12 +111,47 @@ static void iso_connected(struct bt_iso_chan *chan) bis_sn_last_updated_ticks = k_uptime_ticks(); } #endif /* CONFIG_BT_ISO_TX */ + + if (iso_info.can_recv) { + err = bt_iso_setup_data_path(chan, BT_HCI_DATAPATH_DIR_CTLR_TO_HOST, &hci_path); + if (err != 0) { + bt_shell_error("Failed to setup ISO RX data path: %d", err); + } + } + + if (iso_info.can_send) { + err = bt_iso_setup_data_path(chan, BT_HCI_DATAPATH_DIR_HOST_TO_CTLR, &hci_path); + if (err != 0) { + bt_shell_error("Failed to setup ISO TX data path: %d", err); + } + } } static void iso_disconnected(struct bt_iso_chan *chan, uint8_t reason) { - bt_shell_print("ISO Channel %p disconnected with reason 0x%02x", - chan, reason); + struct bt_iso_info iso_info; + int err; + + bt_shell_print("ISO Channel %p disconnected with reason 0x%02x", chan, reason); + + err = bt_iso_chan_get_info(chan, &iso_info); + if (err != 0) { + bt_shell_error("Failed to get ISO info: %d", err); + } else if (iso_info.type == BT_ISO_CHAN_TYPE_CENTRAL) { + if (iso_info.can_recv) { + err = bt_iso_remove_data_path(chan, BT_HCI_DATAPATH_DIR_CTLR_TO_HOST); + if (err != 0) { + bt_shell_error("Failed to remove ISO RX data path: %d", err); + } + } + + if (iso_info.can_send) { + err = bt_iso_remove_data_path(chan, BT_HCI_DATAPATH_DIR_HOST_TO_CTLR); + if (err != 0) { + bt_shell_error("Failed to remove ISO TX data path: %d", err); + } + } + } } static struct bt_iso_chan_ops iso_ops = { diff --git a/tests/bluetooth/audio/mocks/src/iso.c b/tests/bluetooth/audio/mocks/src/iso.c index cd00681d9671..ac4e58314c10 100644 --- a/tests/bluetooth/audio/mocks/src/iso.c +++ b/tests/bluetooth/audio/mocks/src/iso.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2023 Codecoup - * Copyright (c) 2024 Nordic Semiconductor ASA + * Copyright (c) 2024-2025 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ @@ -82,6 +82,17 @@ void mock_bt_iso_cleanup(void) } +int bt_iso_setup_data_path(const struct bt_iso_chan *chan, uint8_t dir, + const struct bt_iso_chan_path *path) +{ + return 0; +} + +int bt_iso_remove_data_path(const struct bt_iso_chan *chan, uint8_t dir) +{ + return 0; +} + void mock_bt_iso_connected(struct bt_conn *iso) { struct bt_iso_chan *chan = iso->chan; diff --git a/tests/bsim/bluetooth/host/iso/bis/src/bis_broadcaster.c b/tests/bsim/bluetooth/host/iso/bis/src/bis_broadcaster.c index d18bc3050531..cabb51697be9 100644 --- a/tests/bsim/bluetooth/host/iso/bis/src/bis_broadcaster.c +++ b/tests/bsim/bluetooth/host/iso/bis/src/bis_broadcaster.c @@ -1,15 +1,29 @@ /* - * Copyright (c) 2024 Nordic Semiconductor + * Copyright (c) 2024-2025 Nordic Semiconductor * * SPDX-License-Identifier: Apache-2.0 */ + +#include +#include +#include + +#include #include +#include +#include #include +#include #include +#include +#include +#include +#include #include "babblekit/flags.h" #include "babblekit/sync.h" #include "babblekit/testcase.h" +#include "bstests.h" LOG_MODULE_REGISTER(bis_broadcaster, LOG_LEVEL_INF); @@ -86,6 +100,12 @@ static void send_data_cb(struct k_work *work) static void iso_connected_cb(struct bt_iso_chan *chan) { + const struct bt_iso_chan_path hci_path = { + .pid = BT_ISO_DATA_PATH_HCI, + .format = BT_HCI_CODING_FORMAT_TRANSPARENT, + }; + int err; + LOG_INF("ISO Channel %p connected", chan); if (chan == default_chan) { @@ -93,6 +113,9 @@ static void iso_connected_cb(struct bt_iso_chan *chan) SET_FLAG(flag_iso_connected); } + + err = bt_iso_setup_data_path(chan, BT_HCI_DATAPATH_DIR_HOST_TO_CTLR, &hci_path); + TEST_ASSERT(err == 0, "Failed to set ISO data path: %d", err); } static void iso_disconnected_cb(struct bt_iso_chan *chan, uint8_t reason) @@ -127,7 +150,6 @@ static void init(void) .sdu = CONFIG_BT_ISO_TX_MTU, .phy = BT_GAP_LE_PHY_2M, .rtn = 1, - .path = NULL, }; static struct bt_iso_chan_qos iso_qos = { .tx = &iso_tx, diff --git a/tests/bsim/bluetooth/host/iso/bis/src/bis_receiver.c b/tests/bsim/bluetooth/host/iso/bis/src/bis_receiver.c index 5f80abdd1c1d..aea23723ff01 100644 --- a/tests/bsim/bluetooth/host/iso/bis/src/bis_receiver.c +++ b/tests/bsim/bluetooth/host/iso/bis/src/bis_receiver.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Nordic Semiconductor + * Copyright (c) 2024-2025 Nordic Semiconductor * * SPDX-License-Identifier: Apache-2.0 */ @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -82,9 +83,18 @@ static void iso_recv(struct bt_iso_chan *chan, const struct bt_iso_recv_info *in static void iso_connected(struct bt_iso_chan *chan) { + const struct bt_iso_chan_path hci_path = { + .pid = BT_ISO_DATA_PATH_HCI, + .format = BT_HCI_CODING_FORMAT_TRANSPARENT, + }; + int err; + LOG_INF("ISO Channel %p connected", chan); SET_FLAG(flag_iso_connected); + + err = bt_iso_setup_data_path(chan, BT_HCI_DATAPATH_DIR_CTLR_TO_HOST, &hci_path); + TEST_ASSERT(err == 0, "Failed to setup ISO RX data path: %d\n", err); } static void iso_disconnected(struct bt_iso_chan *chan, uint8_t reason) diff --git a/tests/bsim/bluetooth/host/iso/cis/CMakeLists.txt b/tests/bsim/bluetooth/host/iso/cis/CMakeLists.txt index a0328bc68707..346345967c55 100644 --- a/tests/bsim/bluetooth/host/iso/cis/CMakeLists.txt +++ b/tests/bsim/bluetooth/host/iso/cis/CMakeLists.txt @@ -3,7 +3,10 @@ cmake_minimum_required(VERSION 3.20.0) find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) -project(bsim_test_l2cap_send_on_connect) +project(bsim_test_iso_cis) + +add_subdirectory(${ZEPHYR_BASE}/tests/bsim/babblekit babblekit) +target_link_libraries(app PRIVATE babblekit) target_sources(app PRIVATE src/common.c @@ -18,7 +21,6 @@ zephyr_include_directories( ) add_subdirectory(${ZEPHYR_BASE}/tests/bluetooth/common/testlib testlib) -add_subdirectory(${ZEPHYR_BASE}/tests/bsim/babblekit babblekit) target_link_libraries(app PRIVATE testlib diff --git a/tests/bsim/bluetooth/host/iso/cis/src/cis_central.c b/tests/bsim/bluetooth/host/iso/cis/src/cis_central.c index f67afe3d3994..dc7d46100a9e 100644 --- a/tests/bsim/bluetooth/host/iso/cis/src/cis_central.c +++ b/tests/bsim/bluetooth/host/iso/cis/src/cis_central.c @@ -1,16 +1,30 @@ /* - * Copyright (c) 2023 Nordic Semiconductor + * Copyright (c) 2023-2025 Nordic Semiconductor * * SPDX-License-Identifier: Apache-2.0 */ -#include "babblekit/testcase.h" -#include "babblekit/flags.h" -#include "common.h" +#include +#include +#include +#include #include +#include +#include +#include #include +#include +#include #include +#include +#include +#include + +#include "babblekit/testcase.h" +#include "babblekit/flags.h" +#include "bstests.h" +#include "common.h" #define ENQUEUE_COUNT 2 @@ -104,6 +118,12 @@ static void device_found(const bt_addr_le_t *addr, int8_t rssi, uint8_t type, static void iso_connected(struct bt_iso_chan *chan) { + const struct bt_iso_chan_path hci_path = { + .pid = BT_ISO_DATA_PATH_HCI, + .format = BT_HCI_CODING_FORMAT_TRANSPARENT, + }; + int err; + printk("ISO Channel %p connected\n", chan); seq_num = 0U; @@ -115,10 +135,15 @@ static void iso_connected(struct bt_iso_chan *chan) SET_FLAG(flag_iso_connected); } + + err = bt_iso_setup_data_path(chan, BT_HCI_DATAPATH_DIR_HOST_TO_CTLR, &hci_path); + TEST_ASSERT(err == 0, "Failed to set ISO data path: %d", err); } static void iso_disconnected(struct bt_iso_chan *chan, uint8_t reason) { + int err; + printk("ISO Channel %p disconnected (reason 0x%02x)\n", chan, reason); if (chan == default_chan) { @@ -126,6 +151,9 @@ static void iso_disconnected(struct bt_iso_chan *chan, uint8_t reason) UNSET_FLAG(flag_iso_connected); } + + err = bt_iso_remove_data_path(chan, BT_HCI_DATAPATH_DIR_HOST_TO_CTLR); + TEST_ASSERT(err == 0, "Failed to remove ISO data path: %d", err); } static void sdu_sent_cb(struct bt_iso_chan *chan) @@ -156,7 +184,6 @@ static void init(void) .sdu = CONFIG_BT_ISO_TX_MTU, .phy = BT_GAP_LE_PHY_2M, .rtn = 1, - .path = NULL, }; static struct bt_iso_chan_qos iso_qos = { .tx = &iso_tx, diff --git a/tests/bsim/bluetooth/host/iso/cis/src/cis_peripheral.c b/tests/bsim/bluetooth/host/iso/cis/src/cis_peripheral.c index ef0ede7b0817..96b8865c1f4e 100644 --- a/tests/bsim/bluetooth/host/iso/cis/src/cis_peripheral.c +++ b/tests/bsim/bluetooth/host/iso/cis/src/cis_peripheral.c @@ -1,21 +1,31 @@ /* - * Copyright (c) 2023 Nordic Semiconductor + * Copyright (c) 2023-2025 Nordic Semiconductor * * SPDX-License-Identifier: Apache-2.0 */ +#include #include +#include +#include -#include "babblekit/testcase.h" -#include "babblekit/flags.h" -#include "common.h" - +#include #include +#include +#include +#include #include +#include #include +#include #include +#include "babblekit/testcase.h" +#include "babblekit/flags.h" +#include "bstests.h" +#include "common.h" + extern enum bst_result_t bst_result; DEFINE_FLAG_STATIC(flag_data_received); @@ -74,7 +84,16 @@ static void iso_recv(struct bt_iso_chan *chan, const struct bt_iso_recv_info *in static void iso_connected(struct bt_iso_chan *chan) { + const struct bt_iso_chan_path hci_path = { + .pid = BT_ISO_DATA_PATH_HCI, + .format = BT_HCI_CODING_FORMAT_TRANSPARENT, + }; + int err; + printk("ISO Channel %p connected\n", chan); + + err = bt_iso_setup_data_path(chan, BT_HCI_DATAPATH_DIR_CTLR_TO_HOST, &hci_path); + TEST_ASSERT(err == 0, "Failed to set ISO data path: %d", err); } static void iso_disconnected(struct bt_iso_chan *chan, uint8_t reason) @@ -101,7 +120,6 @@ static void init(void) { static struct bt_iso_chan_io_qos iso_rx = { .sdu = CONFIG_BT_ISO_TX_MTU, - .path = NULL, }; static struct bt_iso_server iso_server = { #if defined(CONFIG_BT_SMP) diff --git a/tests/bsim/bluetooth/host/iso/frag/src/broadcaster.c b/tests/bsim/bluetooth/host/iso/frag/src/broadcaster.c index cdc9d68aceee..7688bb822d2c 100644 --- a/tests/bsim/bluetooth/host/iso/frag/src/broadcaster.c +++ b/tests/bsim/bluetooth/host/iso/frag/src/broadcaster.c @@ -1,9 +1,10 @@ /* - * Copyright (c) 2024 Nordic Semiconductor + * Copyright (c) 2024-2025 Nordic Semiconductor * * SPDX-License-Identifier: Apache-2.0 */ +#include #include #include #include @@ -58,6 +59,15 @@ static int send_data(struct bt_iso_chan *chan, bool ts) static void iso_connected_cb(struct bt_iso_chan *chan) { + const struct bt_iso_chan_path hci_path = { + .pid = BT_ISO_DATA_PATH_HCI, + .format = BT_HCI_CODING_FORMAT_TRANSPARENT, + }; + int err; + + err = bt_iso_setup_data_path(chan, BT_HCI_DATAPATH_DIR_HOST_TO_CTLR, &hci_path); + TEST_ASSERT(err == 0, "Unable to setup ISO TX path: %d", err); + LOG_INF("ISO Channel %p connected", chan); SET_FLAG(iso_connected); @@ -155,7 +165,6 @@ static void init(void) .sdu = CONFIG_BT_ISO_TX_MTU, .phy = BT_GAP_LE_PHY_2M, .rtn = 1, - .path = NULL, }; static struct bt_iso_chan_qos iso_qos = { .tx = &iso_tx, diff --git a/tests/bsim/bluetooth/host/iso/frag_2/src/broadcaster.c b/tests/bsim/bluetooth/host/iso/frag_2/src/broadcaster.c index c5491a5520fb..1850adcdd11c 100644 --- a/tests/bsim/bluetooth/host/iso/frag_2/src/broadcaster.c +++ b/tests/bsim/bluetooth/host/iso/frag_2/src/broadcaster.c @@ -1,9 +1,10 @@ /* - * Copyright (c) 2024 Nordic Semiconductor + * Copyright (c) 2024-2025 Nordic Semiconductor * * SPDX-License-Identifier: Apache-2.0 */ +#include #include #include #include @@ -57,6 +58,15 @@ static int send_data(struct bt_iso_chan *chan) static void iso_connected_cb(struct bt_iso_chan *chan) { + const struct bt_iso_chan_path hci_path = { + .pid = BT_ISO_DATA_PATH_HCI, + .format = BT_HCI_CODING_FORMAT_TRANSPARENT, + }; + int err; + + err = bt_iso_setup_data_path(chan, BT_HCI_DATAPATH_DIR_HOST_TO_CTLR, &hci_path); + TEST_ASSERT(err == 0, "Unable to setup ISO TX path: %d", err); + LOG_INF("ISO Channel %p connected", chan); SET_FLAG(iso_connected); @@ -152,7 +162,6 @@ static struct bt_iso_chan_io_qos iso_tx = { .sdu = CONFIG_BT_ISO_TX_MTU, .phy = BT_GAP_LE_PHY_2M, .rtn = 1, - .path = NULL, }; static struct bt_iso_chan_qos iso_qos = { .tx = &iso_tx, diff --git a/tests/bsim/bluetooth/ll/bis/src/test_bis.c b/tests/bsim/bluetooth/ll/bis/src/test_bis.c index 57aab410fff6..a3cb8fe90771 100644 --- a/tests/bsim/bluetooth/ll/bis/src/test_bis.c +++ b/tests/bsim/bluetooth/ll/bis/src/test_bis.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Nordic Semiconductor ASA + * Copyright (c) 2020-2025 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ @@ -12,6 +12,7 @@ #include #include +#include #include #include "subsys/bluetooth/host/hci_core.h" @@ -71,14 +72,12 @@ static struct bt_iso_chan_ops iso_ops = { .recv = iso_recv, }; -static struct bt_iso_chan_path iso_path_rx = { - .pid = BT_HCI_DATAPATH_ID_HCI -}; - static struct bt_iso_chan_qos bis_iso_qos; static struct bt_iso_chan_io_qos iso_tx_qos; -static struct bt_iso_chan_io_qos iso_rx_qos = { - .path = &iso_path_rx +static struct bt_iso_chan_io_qos iso_rx_qos; +static struct bt_iso_chan_path hci_path = { + .pid = BT_HCI_DATAPATH_ID_HCI, + .format = BT_HCI_CODING_FORMAT_TRANSPARENT, }; static struct bt_iso_chan bis_iso_chan = { @@ -609,10 +608,34 @@ static void iso_recv(struct bt_iso_chan *chan, static void iso_connected(struct bt_iso_chan *chan) { + struct bt_iso_info iso_info; + int err; + printk("ISO Channel %p connected\n", chan); seq_num = 0U; is_iso_connected = true; + + err = bt_iso_chan_get_info(chan, &iso_info); + if (err != 0) { + FAIL("Failed to get ISO info: %d\n", err); + } else { + if (iso_info.can_recv) { + err = bt_iso_setup_data_path(chan, BT_HCI_DATAPATH_DIR_CTLR_TO_HOST, + &hci_path); + if (err != 0) { + FAIL("Failed to setup ISO RX data path: %d\n", err); + } + } + + if (iso_info.can_send) { + err = bt_iso_setup_data_path(chan, BT_HCI_DATAPATH_DIR_HOST_TO_CTLR, + &hci_path); + if (err != 0) { + FAIL("Failed to setup ISO TX data path: %d\n", err); + } + } + } } static void iso_disconnected(struct bt_iso_chan *chan, uint8_t reason) @@ -938,7 +961,7 @@ static void test_iso_recv_main(void) big_param.mse = 1; big_param.sync_timeout = 100; /* 1000 ms */ big_param.encryption = false; - iso_path_rx.pid = BT_HCI_DATAPATH_ID_HCI; + hci_path.pid = BT_HCI_DATAPATH_ID_HCI; memset(big_param.bcode, 0, sizeof(big_param.bcode)); err = bt_iso_big_sync(sync, &big_param, &big); if (err) { @@ -1158,7 +1181,7 @@ static void test_iso_recv_vs_dp_main(void) is_iso_connected = false; is_iso_disconnected = 0U; is_iso_vs_emitted = false; - iso_path_rx.pid = BT_HCI_DATAPATH_ID_VS; + hci_path.pid = BT_HCI_DATAPATH_ID_VS; err = bt_iso_big_sync(sync, &big_param, &big); if (err) { diff --git a/tests/bsim/bluetooth/ll/cis/src/main.c b/tests/bsim/bluetooth/ll/cis/src/main.c index a3a8b0c91697..d835052be5fc 100644 --- a/tests/bsim/bluetooth/ll/cis/src/main.c +++ b/tests/bsim/bluetooth/ll/cis/src/main.c @@ -1,7 +1,7 @@ /* main.c - Application main entry point */ /* - * Copyright (c) 2023 Nordic Semiconductor ASA + * Copyright (c) 2023-2025 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ @@ -13,6 +13,7 @@ #include #include +#include #include #include #include @@ -312,16 +313,65 @@ void iso_sent(struct bt_iso_chan *chan) static void iso_connected(struct bt_iso_chan *chan) { + const struct bt_iso_chan_path hci_path = { + .pid = BT_ISO_DATA_PATH_HCI, + .format = BT_HCI_CODING_FORMAT_TRANSPARENT, + }; + struct bt_iso_info iso_info; + int err; + + err = bt_iso_chan_get_info(chan, &iso_info); + if (err != 0) { + FAIL("Failed to get ISO info: %d\n", err); + return; + } + printk("ISO Channel %p connected\n", chan); k_sem_give(&sem_iso_conn); + + if (iso_info.can_recv) { + err = bt_iso_setup_data_path(chan, BT_HCI_DATAPATH_DIR_CTLR_TO_HOST, &hci_path); + if (err != 0) { + FAIL("Failed to setup ISO RX data path: %d\n", err); + } + } + + if (iso_info.can_send) { + err = bt_iso_setup_data_path(chan, BT_HCI_DATAPATH_DIR_HOST_TO_CTLR, &hci_path); + if (err != 0) { + FAIL("Failed to setup ISO TX data path: %d\n", err); + } + } } static void iso_disconnected(struct bt_iso_chan *chan, uint8_t reason) { + struct bt_iso_info iso_info; + int err; + printk("ISO Channel %p disconnected (reason 0x%02x)\n", chan, reason); k_sem_give(&sem_iso_disc); + + err = bt_iso_chan_get_info(chan, &iso_info); + if (err != 0) { + FAIL("Failed to get ISO info: %d\n", err); + } else if (iso_info.type == BT_ISO_CHAN_TYPE_CENTRAL) { + if (iso_info.can_recv) { + err = bt_iso_remove_data_path(chan, BT_HCI_DATAPATH_DIR_CTLR_TO_HOST); + if (err != 0) { + FAIL("Failed to remove ISO RX data path: %d\n", err); + } + } + + if (iso_info.can_send) { + err = bt_iso_remove_data_path(chan, BT_HCI_DATAPATH_DIR_HOST_TO_CTLR); + if (err != 0) { + FAIL("Failed to remove ISO TX data path: %d\n", err); + } + } + } } static struct bt_iso_chan_ops iso_ops = { @@ -358,7 +408,6 @@ static void test_cis_central(void) for (int i = 0; i < CONFIG_BT_ISO_MAX_CHAN; i++) { iso_tx[i].sdu = CONFIG_BT_ISO_TX_MTU; iso_tx[i].phy = BT_GAP_LE_PHY_2M; - iso_tx[i].path = NULL; if (IS_ENABLED(CONFIG_TEST_FT_SKIP_SUBEVENTS)) { iso_tx[i].rtn = 2U; } else { @@ -374,7 +423,6 @@ static void test_cis_central(void) iso_rx[i].sdu = CONFIG_BT_ISO_RX_MTU; iso_rx[i].phy = BT_GAP_LE_PHY_2M; - iso_rx[i].path = NULL; if (IS_ENABLED(CONFIG_TEST_FT_SKIP_SUBEVENTS)) { iso_rx[i].rtn = 2U; } else { @@ -658,7 +706,6 @@ static void test_cis_peripheral(void) for (int i = 0; i < CONFIG_BT_ISO_MAX_CHAN; i++) { iso_tx_p[i].sdu = CONFIG_BT_ISO_TX_MTU; iso_tx_p[i].phy = BT_GAP_LE_PHY_2M; - iso_tx_p[i].path = NULL; if (IS_ENABLED(CONFIG_TEST_FT_SKIP_SUBEVENTS)) { iso_tx_p[i].rtn = 2U; } else {