Browse Source

Bluetooth: ISO: Make setting ISO data explicit

The stack will no longer implicitly set the data path
for ISO channel, and the responsibility for doing that is
now for the upper layers/applications.

This provides additional flexibility for the higher layers
as they can better control the values and timing of the data
path, as well as support removing and even reconfiguring the
data path at will.
This also removes some complexity from the stack.

This commit also fixed a inconsistency in the disconnected
handler. CIS for centrals as well as BIS were still valid
bt_iso_chan channels in the disconnected callback,
but CIS for peripherals were completely cleaned up at this
point. This issue is fixed by moving the disconnected callback
handling to before the code to cleanup the channel for
peripherals.

Since there is a difference in how you remove data paths
depending on the GAP role (central/peripheral), the
iso_info struct type has been expanded to be more
concise of which type of CIS it is.

Signed-off-by: Emil Gydesen <emil.gydesen@nordicsemi.no>
pull/87425/head
Emil Gydesen 1 year ago committed by Benjamin Cabé
parent
commit
065dca7e92
  1. 9
      doc/releases/migration-guide-4.2.rst
  2. 149
      include/zephyr/bluetooth/iso.h
  3. 14
      samples/bluetooth/iso_broadcast/src/main.c
  4. 14
      samples/bluetooth/iso_broadcast_benchmark/src/broadcaster.c
  5. 14
      samples/bluetooth/iso_broadcast_benchmark/src/receiver.c
  6. 26
      samples/bluetooth/iso_central/src/main.c
  7. 43
      samples/bluetooth/iso_connected_benchmark/src/main.c
  8. 15
      samples/bluetooth/iso_peripheral/src/main.c
  9. 15
      samples/bluetooth/iso_receive/src/main.c
  10. 21
      subsys/bluetooth/audio/ascs.c
  11. 6
      subsys/bluetooth/audio/bap_broadcast_sink.c
  12. 8
      subsys/bluetooth/audio/bap_broadcast_source.c
  13. 65
      subsys/bluetooth/audio/bap_iso.c
  14. 6
      subsys/bluetooth/audio/bap_iso.h
  15. 21
      subsys/bluetooth/audio/bap_unicast_client.c
  16. 5
      subsys/bluetooth/host/conn.c
  17. 379
      subsys/bluetooth/host/iso.c
  18. 51
      subsys/bluetooth/host/shell/iso.c
  19. 13
      tests/bluetooth/audio/mocks/src/iso.c
  20. 26
      tests/bsim/bluetooth/host/iso/bis/src/bis_broadcaster.c
  21. 12
      tests/bsim/bluetooth/host/iso/bis/src/bis_receiver.c
  22. 6
      tests/bsim/bluetooth/host/iso/cis/CMakeLists.txt
  23. 37
      tests/bsim/bluetooth/host/iso/cis/src/cis_central.c
  24. 30
      tests/bsim/bluetooth/host/iso/cis/src/cis_peripheral.c
  25. 13
      tests/bsim/bluetooth/host/iso/frag/src/broadcaster.c
  26. 13
      tests/bsim/bluetooth/host/iso/frag_2/src/broadcaster.c
  27. 41
      tests/bsim/bluetooth/ll/bis/src/test_bis.c
  28. 55
      tests/bsim/bluetooth/ll/cis/src/main.c

9
doc/releases/migration-guide-4.2.rst

@ -112,6 +112,15 @@ Bluetooth Host
:zephyr_file:`include/zephyr/bluetooth/conn.h` have been renamed :zephyr_file:`include/zephyr/bluetooth/conn.h` have been renamed
to ``BT_LE_CS_TONE_ANTENNA_CONFIGURATION_A<NUMBER>_B<NUMBER>``. to ``BT_LE_CS_TONE_ANTENNA_CONFIGURATION_A<NUMBER>_B<NUMBER>``.
* 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 Networking
********** **********

149
include/zephyr/bluetooth/iso.h

@ -5,7 +5,7 @@
/* /*
* Copyright (c) 2020 Intel Corporation * 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 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -70,6 +70,14 @@ extern "C" {
/** Unknown SDU interval */ /** Unknown SDU interval */
#define BT_ISO_SDU_INTERVAL_UNKNOWN 0x000000U #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 */ /** Minimum interval value in microseconds */
#define BT_ISO_SDU_INTERVAL_MIN 0x0000FFU #define BT_ISO_SDU_INTERVAL_MIN 0x0000FFU
/** Maximum interval value in microseconds */ /** Maximum interval value in microseconds */
@ -178,7 +186,8 @@ enum bt_iso_state {
*/ */
enum bt_iso_chan_type { enum bt_iso_chan_type {
BT_ISO_CHAN_TYPE_NONE, /**< No channel 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_BROADCASTER, /**< Isochronous broadcaster */
BT_ISO_CHAN_TYPE_SYNC_RECEIVER /**< Synchronized receiver */ 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. * This value is ignored if any advanced ISO parameters are set.
*/ */
uint8_t rtn; 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__) #if defined(CONFIG_BT_ISO_TEST_PARAMS) || defined(__DOXYGEN__)
/** /**
@ -293,20 +295,37 @@ struct bt_iso_chan_qos {
/** @brief ISO Channel Data Path structure. */ /** @brief ISO Channel Data Path structure. */
struct bt_iso_chan_path { struct bt_iso_chan_path {
/** Default path ID */ /**
uint8_t pid; * @brief Default path ID
/** Coding Format */ *
uint8_t format; * @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 */ /** Company ID */
uint16_t cid; uint16_t cid;
/** Vendor-defined Codec ID */ /** Vendor-defined Codec ID */
uint16_t vid; uint16_t vid;
/** Controller Delay */ /**
uint32_t delay; * @brief Controller Delay in microseconds
/** Codec Configuration length*/ *
uint8_t cc_len; * Value range from @ref BT_ISO_CONTROLLER_DELAY_MIN to @ref BT_ISO_CONTROLLER_DELAY_MAX.
/** Pointer to an array containing the Codec Configuration */ */
uint8_t *cc; 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 */ /** ISO packet status flag bits */
@ -691,6 +710,14 @@ struct bt_iso_chan_ops {
* channel is disconnected, including when a connection gets * channel is disconnected, including when a connection gets
* rejected or when setting security fails. * 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 chan The channel that has been Disconnected
* @param reason BT_HCI_ERR_* reason for the disconnection. * @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, int bt_iso_chan_send_ts(struct bt_iso_chan *chan, struct net_buf *buf, uint16_t seq_num,
uint32_t ts); 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 */ /** @brief ISO Unicast TX Info Structure */
struct bt_iso_unicast_tx_info { struct bt_iso_unicast_tx_info {
/** The transport latency in us */ /** The transport latency in us */
@ -1082,20 +1173,30 @@ struct bt_iso_info {
/** Connection Type specific Info.*/ /** Connection Type specific Info.*/
union { union {
#if defined(CONFIG_BT_ISO_UNICAST) || defined(__DOXYGEN__) #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. * 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; struct bt_iso_unicast_info unicast;
#endif /* CONFIG_BT_ISO_UNICAST */ #endif /* CONFIG_BT_ISO_UNICAST */
#if defined(CONFIG_BT_ISO_BROADCASTER) || defined(__DOXYGEN__) #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. * 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; struct bt_iso_broadcaster_info broadcaster;
#endif /* CONFIG_BT_ISO_BROADCASTER */ #endif /* CONFIG_BT_ISO_BROADCASTER */
#if defined(CONFIG_BT_ISO_SYNC_RECEIVER) || defined(__DOXYGEN__) #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. * 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; struct bt_iso_sync_receiver_info sync_receiver;
#endif /* CONFIG_BT_ISO_SYNC_RECEIVER */ #endif /* CONFIG_BT_ISO_SYNC_RECEIVER */

14
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 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -8,6 +8,7 @@
#include <zephyr/bluetooth/bluetooth.h> #include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/bluetooth/gap.h> #include <zephyr/bluetooth/gap.h>
#include <zephyr/bluetooth/hci_types.h>
#include <zephyr/bluetooth/iso.h> #include <zephyr/bluetooth/iso.h>
#include <zephyr/sys/byteorder.h> #include <zephyr/sys/byteorder.h>
@ -31,10 +32,21 @@ static uint16_t seq_num;
static void iso_connected(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;
printk("ISO Channel %p connected\n", chan); printk("ISO Channel %p connected\n", chan);
seq_num = 0U; 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); k_sem_give(&sem_big_cmplt);
} }

14
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 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -9,6 +9,7 @@
#include <stdint.h> #include <stdint.h>
#include <zephyr/bluetooth/gap.h> #include <zephyr/bluetooth/gap.h>
#include <zephyr/bluetooth/hci_types.h>
#include <zephyr/console/console.h> #include <zephyr/console/console.h>
#include <zephyr/bluetooth/bluetooth.h> #include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/bluetooth/iso.h> #include <zephyr/bluetooth/iso.h>
@ -72,8 +73,19 @@ static const struct bt_data ad[] = {
static void iso_connected(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); 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++; connected_bis++;
if (connected_bis == big_create_param.num_bis) { if (connected_bis == big_create_param.num_bis) {
seq_num = 0U; seq_num = 0U;

14
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 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -7,6 +7,7 @@
#include <ctype.h> #include <ctype.h>
#include <zephyr/bluetooth/bluetooth.h> #include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/bluetooth/conn.h> #include <zephyr/bluetooth/conn.h>
#include <zephyr/bluetooth/hci_types.h>
#include <zephyr/bluetooth/iso.h> #include <zephyr/bluetooth/iso.h>
#include <zephyr/sys/byteorder.h> #include <zephyr/sys/byteorder.h>
#include <zephyr/console/console.h> #include <zephyr/console/console.h>
@ -229,10 +230,21 @@ static void iso_recv(struct bt_iso_chan *chan,
static void iso_connected(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); LOG_INF("ISO Channel %p connected", chan);
big_sync_start_time = k_uptime_get(); 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); k_sem_give(&sem_big_sync);
} }

26
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 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -16,6 +16,7 @@
#include <zephyr/bluetooth/conn.h> #include <zephyr/bluetooth/conn.h>
#include <zephyr/bluetooth/uuid.h> #include <zephyr/bluetooth/uuid.h>
#include <zephyr/bluetooth/gatt.h> #include <zephyr/bluetooth/gatt.h>
#include <zephyr/bluetooth/hci_types.h>
#include <zephyr/bluetooth/iso.h> #include <zephyr/bluetooth/iso.h>
#include <zephyr/settings/settings.h> #include <zephyr/settings/settings.h>
#include <zephyr/sys/byteorder.h> #include <zephyr/sys/byteorder.h>
@ -142,18 +143,36 @@ static void start_scan(void)
static void iso_connected(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;
printk("ISO Channel %p connected\n", chan); printk("ISO Channel %p connected\n", chan);
seq_num = 0U; seq_num = 0U;
/* Start send timer */ err = bt_iso_setup_data_path(chan, BT_HCI_DATAPATH_DIR_HOST_TO_CTLR, &hci_path);
k_work_schedule(&iso_send_work, K_MSEC(0)); 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) 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); printk("ISO Channel %p disconnected (reason 0x%02x)\n", chan, reason);
k_work_cancel_delayable(&iso_send_work); 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 = { 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, .sdu = CONFIG_BT_ISO_TX_MTU,
.phy = BT_GAP_LE_PHY_2M, .phy = BT_GAP_LE_PHY_2M,
.rtn = 1, .rtn = 1,
.path = NULL,
}; };
static struct bt_iso_chan_qos iso_qos = { static struct bt_iso_chan_qos iso_qos = {

43
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 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -7,6 +7,7 @@
#include <ctype.h> #include <ctype.h>
#include <zephyr/bluetooth/conn.h> #include <zephyr/bluetooth/conn.h>
#include <zephyr/bluetooth/gap.h> #include <zephyr/bluetooth/gap.h>
#include <zephyr/bluetooth/hci_types.h>
#include <zephyr/kernel.h> #include <zephyr/kernel.h>
#include <string.h> #include <string.h>
#include <stdint.h> #include <stdint.h>
@ -306,7 +307,12 @@ static void iso_recv(struct bt_iso_chan *chan,
static void iso_connected(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 iso_chan_work *chan_work;
struct bt_iso_info iso_info;
int err; int err;
LOG_INF("ISO Channel %p connected", chan); 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 = CONTAINER_OF(chan, struct iso_chan_work, chan);
chan_work->seq_num = 0U; 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); 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. * of the last created CIS.
*/ */
static int64_t average_duration; static int64_t average_duration;
struct bt_iso_info iso_info;
uint64_t iso_conn_duration; uint64_t iso_conn_duration;
uint64_t total_duration; uint64_t total_duration;
int err;
if (iso_conn_start_time > 0) { if (iso_conn_start_time > 0) {
iso_conn_duration = k_uptime_get() - iso_conn_start_time; 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); chan, reason, iso_conn_duration, average_duration);
k_sem_give(&sem_iso_disconnected); 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 = { static struct bt_iso_chan_ops iso_ops = {

15
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 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -15,6 +15,7 @@
#include <zephyr/bluetooth/bluetooth.h> #include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/bluetooth/hci.h> #include <zephyr/bluetooth/hci.h>
#include <zephyr/bluetooth/conn.h> #include <zephyr/bluetooth/conn.h>
#include <zephyr/bluetooth/hci_types.h>
#include <zephyr/bluetooth/iso.h> #include <zephyr/bluetooth/iso.h>
#include <zephyr/settings/settings.h> #include <zephyr/settings/settings.h>
@ -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) 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); 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) 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 = { static struct bt_iso_chan_io_qos iso_rx = {
.sdu = CONFIG_BT_ISO_TX_MTU, .sdu = CONFIG_BT_ISO_TX_MTU,
.path = NULL,
}; };
static struct bt_iso_chan_qos iso_qos = { static struct bt_iso_chan_qos iso_qos = {

15
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 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -9,6 +9,7 @@
#include <zephyr/drivers/gpio.h> #include <zephyr/drivers/gpio.h>
#include <zephyr/bluetooth/bluetooth.h> #include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/bluetooth/conn.h> #include <zephyr/bluetooth/conn.h>
#include <zephyr/bluetooth/hci_types.h>
#include <zephyr/bluetooth/iso.h> #include <zephyr/bluetooth/iso.h>
#include <zephyr/sys/byteorder.h> #include <zephyr/sys/byteorder.h>
@ -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) 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); 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); k_sem_give(&sem_big_sync);
} }

21
subsys/bluetooth/audio/ascs.c

@ -3,7 +3,7 @@
*/ */
/* /*
* Copyright (c) 2020 Intel Corporation * 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 * Copyright (c) 2024 Demant A/S
* *
* SPDX-License-Identifier: Apache-2.0 * 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); __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; ops = stream->ops;
if (ops != NULL && ops->started != NULL) { if (ops != NULL && ops->started != NULL) {
ops->started(stream); ops->started(stream);
@ -417,6 +422,14 @@ static void ase_exit_state_streaming(struct bt_ascs_ase *ase)
reason = BT_HCI_ERR_UNSPECIFIED; 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; 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; ep->qos = *qos;
stream->qos = &ep->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->cig_id = cig_id;
ep->cis_id = cis_id; ep->cis_id = cis_id;

6
subsys/bluetooth/audio/bap_broadcast_sink.c

@ -1,7 +1,7 @@
/* Bluetooth Audio Broadcast Sink */ /* Bluetooth Audio Broadcast Sink */
/* /*
* Copyright (c) 2021-2024 Nordic Semiconductor ASA * Copyright (c) 2021-2025 Nordic Semiconductor ASA
* *
* SPDX-License-Identifier: Apache-2.0 * 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); 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) { if (ops != NULL && ops->started != NULL) {
ops->started(stream); ops->started(stream);
} else { } 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_iso_bind_ep(iso, ep);
bt_bap_qos_cfg_to_iso_qos(iso->chan.qos->rx, &sink->qos_cfg); 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); bt_bap_iso_unref(iso);

8
subsys/bluetooth/audio/bap_broadcast_source.c

@ -1,7 +1,7 @@
/* Bluetooth Audio Broadcast Source */ /* Bluetooth Audio Broadcast Source */
/* /*
* Copyright (c) 2021-2024 Nordic Semiconductor ASA * Copyright (c) 2021-2025 Nordic Semiconductor ASA
* *
* SPDX-License-Identifier: Apache-2.0 * 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; stream->_prev_seq_num = 0U;
#endif /* CONFIG_BT_BAP_DEBUG_STREAM_SEQ_NUM */ #endif /* CONFIG_BT_BAP_DEBUG_STREAM_SEQ_NUM */
/* Setup the ISO data path */
bt_bap_setup_iso_data_path(stream);
ops = stream->ops; ops = stream->ops;
if (ops != NULL && ops->connected != NULL) { if (ops != NULL && ops->connected != NULL) {
ops->connected(stream); 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_iso_bind_ep(iso, ep);
bt_bap_qos_cfg_to_iso_qos(iso->chan.qos->tx, qos); 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) #if defined(CONFIG_BT_ISO_TEST_PARAMS)
iso->chan.qos->num_subevents = qos->num_subevents; iso->chan.qos->num_subevents = qos->num_subevents;
#endif /* CONFIG_BT_ISO_TEST_PARAMS */ #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) { SYS_SLIST_FOR_EACH_CONTAINER(&subgroup->streams, stream, _node) {
bt_bap_stream_attach(NULL, stream, stream->ep, codec_cfg); bt_bap_stream_attach(NULL, stream, stream->ep, codec_cfg);
bt_bap_iso_configure_data_path(stream->ep, codec_cfg);
} }
} }

65
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_bap_iso *bap_iso = ep->iso;
struct bt_iso_chan_qos *qos = bap_iso->chan.qos;
const bool is_unicast_client = const bool is_unicast_client =
IS_ENABLED(CONFIG_BT_BAP_UNICAST_CLIENT) && bt_bap_ep_is_unicast_client(ep); 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_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) { if (iso_dir == &bap_iso->rx) {
qos->rx->path = path; dir = BT_HCI_DATAPATH_DIR_CTLR_TO_HOST;
} else { } 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 /* 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 * be transparent to indicate that the transcoding happens somewhere else
*/ */
path->pid = codec_cfg->path_id;
if (codec_cfg->ctlr_transcode) { if (codec_cfg->ctlr_transcode) {
path->format = codec_cfg->id; path.format = codec_cfg->id;
path->cid = codec_cfg->cid; path.cid = codec_cfg->cid;
path->vid = codec_cfg->vid; path.vid = codec_cfg->vid;
path->delay = 0; path.cc_len = codec_cfg->data_len;
path->cc_len = codec_cfg->data_len; path.cc = codec_cfg->data;
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 { } else {
path->format = BT_HCI_CODING_FORMAT_TRANSPARENT; dir = BT_HCI_DATAPATH_DIR_HOST_TO_CTLR;
path->cid = 0; }
path->vid = 0;
path->delay = 0; err = bt_iso_remove_data_path(&bap_iso->chan, dir);
path->cc_len = 0; if (err != 0) {
path->cc = NULL; 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) 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); return IS_ENABLED(CONFIG_BT_BAP_UNICAST_CLIENT) && bt_bap_ep_is_unicast_client(ep);

6
subsys/bluetooth/audio/bap_iso.h

@ -2,7 +2,7 @@
* @brief Internal APIs for BAP ISO handling * @brief Internal APIs for BAP ISO handling
* *
* Copyright (c) 2022 Codecoup * Copyright (c) 2022 Codecoup
* Copyright (c) 2023 Nordic Semiconductor ASA * Copyright (c) 2023-2024 Nordic Semiconductor ASA
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -19,7 +19,6 @@
struct bt_bap_iso_dir { struct bt_bap_iso_dir {
struct bt_bap_stream *stream; struct bt_bap_stream *stream;
struct bt_bap_ep *ep; struct bt_bap_ep *ep;
struct bt_iso_chan_path path;
struct bt_iso_chan_io_qos qos; struct bt_iso_chan_io_qos qos;
uint8_t cc[CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE]; 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); 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_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_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); 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, struct bt_bap_ep *bt_bap_iso_get_ep(bool unicast_client, struct bt_bap_iso *iso,
enum bt_audio_dir dir); enum bt_audio_dir dir);

21
subsys/bluetooth/audio/bap_unicast_client.c

@ -4,7 +4,7 @@
/* /*
* Copyright (c) 2020 Intel Corporation * 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 * 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) { if (err != 0) {
LOG_ERR("Failed to disconnect stream: %d", err); 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 */ /* 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); 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 /* Notify upper layer
* *
* If the state did not change then only the metadata was changed * 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; 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) { if (ops != NULL && ops->stopped != NULL) {
ops->stopped(stream, reason); ops->stopped(stream, reason);
} else { } else {

5
subsys/bluetooth/host/conn.c

@ -7,6 +7,7 @@
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
#include <zephyr/bluetooth/iso.h>
#include <zephyr/kernel.h> #include <zephyr/kernel.h>
#include <string.h> #include <string.h>
#include <errno.h> #include <errno.h>
@ -2978,7 +2979,9 @@ int bt_conn_get_info(const struct bt_conn *conn, struct bt_conn_info *info)
#if defined(CONFIG_BT_ISO) #if defined(CONFIG_BT_ISO)
case BT_CONN_TYPE_ISO: case BT_CONN_TYPE_ISO:
if (IS_ENABLED(CONFIG_BT_ISO_UNICAST) && 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.dst = &conn->iso.acl->le.dst;
info->le.src = &bt_dev.id_addr[conn->iso.acl->id]; info->le.src = &bt_dev.id_addr[conn->iso.acl->id];
} else { } else {

379
subsys/bluetooth/host/iso.c

@ -2,7 +2,7 @@
/* /*
* Copyright (c) 2020 Intel Corporation * 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 * 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]; 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 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); static int hci_le_create_cis(const struct bt_iso_connect_param *param, size_t count);
#endif /* CONFIG_BT_ISO_CENTRAL */ #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; uint8_t *cc;
int err; 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); buf = bt_hci_cmd_create(BT_HCI_OP_LE_SETUP_ISO_PATH, sizeof(*cp) + path->cc_len);
if (!buf) { if (!buf) {
return -ENOBUFS; 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); 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; 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; iso = chan->iso;
if (iso == NULL) {
LOG_DBG("chan %p not associated with a CIS/BIS handle", chan);
tx_qos = chan->qos->tx; return -ENODEV;
rx_qos = chan->qos->rx; }
/* The following code sets the in and out paths for ISO data. if (!iso->iso.info.can_recv && dir == BT_HCI_DATAPATH_DIR_CTLR_TO_HOST) {
* If the application provides a path for a direction (tx/rx) we use LOG_DBG("Invalid dir %u for chan %p that cannot receive data", dir, chan);
* 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 (tx_qos != NULL && iso->iso.info.can_send) { return -EINVAL;
if (tx_qos->path != NULL) { /* Use application path */
in_path = tx_qos->path;
} else { /* else fallback to HCI path */
in_path = &default_hci_path;
}
} }
if (rx_qos != NULL && iso->iso.info.can_recv) { if (!iso->iso.info.can_send && dir == BT_HCI_DATAPATH_DIR_HOST_TO_CTLR) {
if (rx_qos->path != NULL) { /* Use application path */ LOG_DBG("Invalid dir %u for chan %p that cannot send data", dir, chan);
out_path = rx_qos->path;
} else { /* else fallback to HCI path */ return -EINVAL;
out_path = &default_hci_path;
}
} }
__ASSERT(in_path || out_path, "At least one path shall be shell: in %p out %p", in_path, CHECKIF(path->pid != BT_ISO_DATA_PATH_HCI &&
out_path); !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) && return -EINVAL;
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); CHECKIF(path->format > BT_HCI_CODING_FORMAT_G729A &&
if (err != 0) { path->format != BT_HCI_CODING_FORMAT_VS) {
LOG_DBG("Failed to set broadcaster data path: %d", err); 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; 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(chan->iso, dir, path);
err = hci_le_setup_iso_data_path(iso, dir, out_path); if (err != 0) {
if (err != 0) { LOG_DBG("Failed to set data path: %d", err);
LOG_DBG("Failed to set sync receiver 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; 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) { rp = (void *)rsp->data;
/* Enable RX */ if (rp->status || (sys_le16_to_cpu(rp->handle) != iso->handle)) {
dir = BT_HCI_DATAPATH_DIR_CTLR_TO_HOST; err = -EIO;
err = hci_le_setup_iso_data_path(iso, dir, out_path); }
if (err) {
LOG_DBG("Failed to setup ctlr-to-host path: %d", err); net_buf_unref(rsp);
return err;
} 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; 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) void bt_iso_connected(struct bt_conn *iso)
{ {
struct bt_iso_chan *chan; struct bt_iso_chan *chan;
int err;
if (iso == NULL || iso->type != BT_CONN_TYPE_ISO) { if (iso == NULL || iso->type != BT_CONN_TYPE_ISO) {
LOG_DBG("Invalid parameters: iso %p iso->type %u", iso, iso ? iso->type : 0); 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; 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); bt_iso_chan_set_state(chan, BT_ISO_STATE_CONNECTED);
if (chan->ops->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) 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); LOG_DBG("%p, reason 0x%02x", chan, reason);
__ASSERT(chan->iso != NULL, "NULL conn for iso chan %p", chan); __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_iso_chan_set_state(chan, BT_ISO_STATE_DISCONNECTED);
bt_conn_set_state(chan->iso, BT_CONN_DISCONNECT_COMPLETE); 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 /* The peripheral does not have the concept of a CIG, so once a CIS
* disconnects it is completely freed by unref'ing it * disconnects it is completely freed by unref'ing it
*/ */
if (IS_ENABLED(CONFIG_BT_ISO_UNICAST) && 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); 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); bt_conn_unref(chan->iso);
chan->iso = NULL; chan->iso = NULL;
#if defined(CONFIG_BT_ISO_CENTRAL) #if defined(CONFIG_BT_ISO_CENTRAL)
} else { } 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; bool is_chan_connected;
struct bt_iso_cig *cig; struct bt_iso_cig *cig;
struct bt_iso_chan *cis_chan; 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 */ #endif /* CONFIG_BT_ISO_CENTRAL */
} }
} }
if (chan->ops->disconnected) {
chan->ops->disconnected(chan, reason);
}
} }
void bt_iso_disconnected(struct bt_conn *iso) 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); 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 { } else {
/* values are already set for central - Verify */ /* values are already set for central - Verify */
if (tx != NULL && tx->phy != c_phy) { if (tx != NULL && tx->phy != c_phy) {
@ -1548,7 +1606,7 @@ void hci_le_cis_req(struct net_buf *buf)
return; 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.cig_id = evt->cig_id;
iso->iso.cis_id = evt->cis_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 */ #endif /* CONFIG_BT_ISO_PERIPHERAL */
#if defined(CONFIG_BT_ISO_CENTRAL) #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) static bool valid_chan_qos(const struct bt_iso_chan_qos *qos, bool advanced)
{ {
#if defined(CONFIG_BT_ISO_TEST_PARAMS) #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 = &cis->iso->iso;
iso_conn->cig_id = cig->id; 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++; iso_conn->cis_id = cig->num_cis++;
bt_iso_chan_add(cis->iso, 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_conn *iso = &iso_conns[i];
const struct bt_iso_chan *iso_chan; 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; continue;
} }

51
subsys/bluetooth/host/shell/iso.c

@ -5,7 +5,7 @@
/* /*
* Copyright (c) 2020 Intel Corporation * Copyright (c) 2020 Intel Corporation
* Copyright (c) 2021 Nordic Semiconductor ASA * Copyright (c) 2021-2025 Nordic Semiconductor ASA
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -13,6 +13,7 @@
#include <stddef.h> #include <stddef.h>
#include <stdlib.h> #include <stdlib.h>
#include <ctype.h> #include <ctype.h>
#include <zephyr/bluetooth/hci_types.h>
#include <zephyr/kernel.h> #include <zephyr/kernel.h>
#include <zephyr/shell/shell.h> #include <zephyr/shell/shell.h>
#include <zephyr/sys/byteorder.h> #include <zephyr/sys/byteorder.h>
@ -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) 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; struct bt_iso_info iso_info;
int err; int err;
@ -92,12 +97,13 @@ static void iso_connected(struct bt_iso_chan *chan)
err = bt_iso_chan_get_info(chan, &iso_info); err = bt_iso_chan_get_info(chan, &iso_info);
if (err != 0) { if (err != 0) {
printk("Failed to get ISO info: %d", err); bt_shell_error("Failed to get ISO info: %d", err);
return; return;
} }
#if defined(CONFIG_BT_ISO_TX) #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 = 0U;
cis_sn_last_updated_ticks = k_uptime_ticks(); cis_sn_last_updated_ticks = k_uptime_ticks();
} else { } else {
@ -105,12 +111,47 @@ static void iso_connected(struct bt_iso_chan *chan)
bis_sn_last_updated_ticks = k_uptime_ticks(); bis_sn_last_updated_ticks = k_uptime_ticks();
} }
#endif /* CONFIG_BT_ISO_TX */ #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) static void iso_disconnected(struct bt_iso_chan *chan, uint8_t reason)
{ {
bt_shell_print("ISO Channel %p disconnected with reason 0x%02x", struct bt_iso_info iso_info;
chan, reason); 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 = { static struct bt_iso_chan_ops iso_ops = {

13
tests/bluetooth/audio/mocks/src/iso.c

@ -1,6 +1,6 @@
/* /*
* Copyright (c) 2023 Codecoup * Copyright (c) 2023 Codecoup
* Copyright (c) 2024 Nordic Semiconductor ASA * Copyright (c) 2024-2025 Nordic Semiconductor ASA
* *
* SPDX-License-Identifier: Apache-2.0 * 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) void mock_bt_iso_connected(struct bt_conn *iso)
{ {
struct bt_iso_chan *chan = iso->chan; struct bt_iso_chan *chan = iso->chan;

26
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 * SPDX-License-Identifier: Apache-2.0
*/ */
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <zephyr/autoconf.h>
#include <zephyr/bluetooth/bluetooth.h> #include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/bluetooth/gap.h>
#include <zephyr/bluetooth/hci_types.h>
#include <zephyr/bluetooth/iso.h> #include <zephyr/bluetooth/iso.h>
#include <zephyr/kernel.h>
#include <zephyr/logging/log.h> #include <zephyr/logging/log.h>
#include <zephyr/logging/log_core.h>
#include <zephyr/net_buf.h>
#include <zephyr/sys/util.h>
#include <zephyr/sys_clock.h>
#include "babblekit/flags.h" #include "babblekit/flags.h"
#include "babblekit/sync.h" #include "babblekit/sync.h"
#include "babblekit/testcase.h" #include "babblekit/testcase.h"
#include "bstests.h"
LOG_MODULE_REGISTER(bis_broadcaster, LOG_LEVEL_INF); 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) 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); LOG_INF("ISO Channel %p connected", chan);
if (chan == default_chan) { if (chan == default_chan) {
@ -93,6 +113,9 @@ static void iso_connected_cb(struct bt_iso_chan *chan)
SET_FLAG(flag_iso_connected); 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) 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, .sdu = CONFIG_BT_ISO_TX_MTU,
.phy = BT_GAP_LE_PHY_2M, .phy = BT_GAP_LE_PHY_2M,
.rtn = 1, .rtn = 1,
.path = NULL,
}; };
static struct bt_iso_chan_qos iso_qos = { static struct bt_iso_chan_qos iso_qos = {
.tx = &iso_tx, .tx = &iso_tx,

12
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 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -8,6 +8,7 @@
#include <zephyr/bluetooth/bluetooth.h> #include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/bluetooth/gap.h> #include <zephyr/bluetooth/gap.h>
#include <zephyr/bluetooth/hci_types.h>
#include <zephyr/bluetooth/iso.h> #include <zephyr/bluetooth/iso.h>
#include <zephyr/logging/log.h> #include <zephyr/logging/log.h>
#include <zephyr/sys/util.h> #include <zephyr/sys/util.h>
@ -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) 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); LOG_INF("ISO Channel %p connected", chan);
SET_FLAG(flag_iso_connected); 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) static void iso_disconnected(struct bt_iso_chan *chan, uint8_t reason)

6
tests/bsim/bluetooth/host/iso/cis/CMakeLists.txt

@ -3,7 +3,10 @@
cmake_minimum_required(VERSION 3.20.0) cmake_minimum_required(VERSION 3.20.0)
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) 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 target_sources(app PRIVATE
src/common.c src/common.c
@ -18,7 +21,6 @@ zephyr_include_directories(
) )
add_subdirectory(${ZEPHYR_BASE}/tests/bluetooth/common/testlib testlib) add_subdirectory(${ZEPHYR_BASE}/tests/bluetooth/common/testlib testlib)
add_subdirectory(${ZEPHYR_BASE}/tests/bsim/babblekit babblekit)
target_link_libraries(app PRIVATE target_link_libraries(app PRIVATE
testlib testlib

37
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 * SPDX-License-Identifier: Apache-2.0
*/ */
#include "babblekit/testcase.h" #include <stddef.h>
#include "babblekit/flags.h" #include <stdint.h>
#include "common.h"
#include <zephyr/autoconf.h>
#include <zephyr/bluetooth/addr.h>
#include <zephyr/bluetooth/bluetooth.h> #include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/bluetooth/conn.h>
#include <zephyr/bluetooth/gap.h>
#include <zephyr/bluetooth/hci_types.h>
#include <zephyr/bluetooth/iso.h> #include <zephyr/bluetooth/iso.h>
#include <zephyr/kernel.h>
#include <zephyr/net_buf.h>
#include <zephyr/sys/printk.h> #include <zephyr/sys/printk.h>
#include <zephyr/sys/util.h>
#include <zephyr/sys_clock.h>
#include <zephyr/toolchain.h>
#include "babblekit/testcase.h"
#include "babblekit/flags.h"
#include "bstests.h"
#include "common.h"
#define ENQUEUE_COUNT 2 #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) 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); printk("ISO Channel %p connected\n", chan);
seq_num = 0U; seq_num = 0U;
@ -115,10 +135,15 @@ static void iso_connected(struct bt_iso_chan *chan)
SET_FLAG(flag_iso_connected); 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) 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); printk("ISO Channel %p disconnected (reason 0x%02x)\n", chan, reason);
if (chan == default_chan) { 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); 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) static void sdu_sent_cb(struct bt_iso_chan *chan)
@ -156,7 +184,6 @@ static void init(void)
.sdu = CONFIG_BT_ISO_TX_MTU, .sdu = CONFIG_BT_ISO_TX_MTU,
.phy = BT_GAP_LE_PHY_2M, .phy = BT_GAP_LE_PHY_2M,
.rtn = 1, .rtn = 1,
.path = NULL,
}; };
static struct bt_iso_chan_qos iso_qos = { static struct bt_iso_chan_qos iso_qos = {
.tx = &iso_tx, .tx = &iso_tx,

30
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 * SPDX-License-Identifier: Apache-2.0
*/ */
#include <errno.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include "babblekit/testcase.h" #include <zephyr/autoconf.h>
#include "babblekit/flags.h"
#include "common.h"
#include <zephyr/bluetooth/bluetooth.h> #include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/bluetooth/conn.h>
#include <zephyr/bluetooth/gap.h>
#include <zephyr/bluetooth/hci_types.h>
#include <zephyr/bluetooth/iso.h> #include <zephyr/bluetooth/iso.h>
#include <zephyr/net_buf.h>
#include <zephyr/sys/printk.h> #include <zephyr/sys/printk.h>
#include <zephyr/sys/util.h>
#include <testlib/conn.h> #include <testlib/conn.h>
#include "babblekit/testcase.h"
#include "babblekit/flags.h"
#include "bstests.h"
#include "common.h"
extern enum bst_result_t bst_result; extern enum bst_result_t bst_result;
DEFINE_FLAG_STATIC(flag_data_received); 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) 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); 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) 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 = { static struct bt_iso_chan_io_qos iso_rx = {
.sdu = CONFIG_BT_ISO_TX_MTU, .sdu = CONFIG_BT_ISO_TX_MTU,
.path = NULL,
}; };
static struct bt_iso_server iso_server = { static struct bt_iso_server iso_server = {
#if defined(CONFIG_BT_SMP) #if defined(CONFIG_BT_SMP)

13
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 * SPDX-License-Identifier: Apache-2.0
*/ */
#include <zephyr/bluetooth/hci_types.h>
#include <zephyr/sys/byteorder.h> #include <zephyr/sys/byteorder.h>
#include <zephyr/bluetooth/bluetooth.h> #include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/bluetooth/iso.h> #include <zephyr/bluetooth/iso.h>
@ -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) 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); LOG_INF("ISO Channel %p connected", chan);
SET_FLAG(iso_connected); SET_FLAG(iso_connected);
@ -155,7 +165,6 @@ static void init(void)
.sdu = CONFIG_BT_ISO_TX_MTU, .sdu = CONFIG_BT_ISO_TX_MTU,
.phy = BT_GAP_LE_PHY_2M, .phy = BT_GAP_LE_PHY_2M,
.rtn = 1, .rtn = 1,
.path = NULL,
}; };
static struct bt_iso_chan_qos iso_qos = { static struct bt_iso_chan_qos iso_qos = {
.tx = &iso_tx, .tx = &iso_tx,

13
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 * SPDX-License-Identifier: Apache-2.0
*/ */
#include <zephyr/bluetooth/hci_types.h>
#include <zephyr/sys/byteorder.h> #include <zephyr/sys/byteorder.h>
#include <zephyr/bluetooth/bluetooth.h> #include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/bluetooth/iso.h> #include <zephyr/bluetooth/iso.h>
@ -57,6 +58,15 @@ static int send_data(struct bt_iso_chan *chan)
static void iso_connected_cb(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); LOG_INF("ISO Channel %p connected", chan);
SET_FLAG(iso_connected); SET_FLAG(iso_connected);
@ -152,7 +162,6 @@ static struct bt_iso_chan_io_qos iso_tx = {
.sdu = CONFIG_BT_ISO_TX_MTU, .sdu = CONFIG_BT_ISO_TX_MTU,
.phy = BT_GAP_LE_PHY_2M, .phy = BT_GAP_LE_PHY_2M,
.rtn = 1, .rtn = 1,
.path = NULL,
}; };
static struct bt_iso_chan_qos iso_qos = { static struct bt_iso_chan_qos iso_qos = {
.tx = &iso_tx, .tx = &iso_tx,

41
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 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -12,6 +12,7 @@
#include <zephyr/bluetooth/bluetooth.h> #include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/bluetooth/hci.h> #include <zephyr/bluetooth/hci.h>
#include <zephyr/bluetooth/hci_types.h>
#include <zephyr/bluetooth/iso.h> #include <zephyr/bluetooth/iso.h>
#include "subsys/bluetooth/host/hci_core.h" #include "subsys/bluetooth/host/hci_core.h"
@ -71,14 +72,12 @@ static struct bt_iso_chan_ops iso_ops = {
.recv = iso_recv, .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_qos bis_iso_qos;
static struct bt_iso_chan_io_qos iso_tx_qos; static struct bt_iso_chan_io_qos iso_tx_qos;
static struct bt_iso_chan_io_qos iso_rx_qos = { static struct bt_iso_chan_io_qos iso_rx_qos;
.path = &iso_path_rx 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 = { static struct bt_iso_chan bis_iso_chan = {
@ -611,10 +610,34 @@ static void iso_recv(struct bt_iso_chan *chan,
static void iso_connected(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); printk("ISO Channel %p connected\n", chan);
seq_num = 0U; seq_num = 0U;
is_iso_connected = true; 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) static void iso_disconnected(struct bt_iso_chan *chan, uint8_t reason)
@ -941,7 +964,7 @@ static void test_iso_recv_main(void)
big_param.mse = 1; big_param.mse = 1;
big_param.sync_timeout = 100; /* 1000 ms */ big_param.sync_timeout = 100; /* 1000 ms */
big_param.encryption = false; 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)); memset(big_param.bcode, 0, sizeof(big_param.bcode));
err = bt_iso_big_sync(sync, &big_param, &big); err = bt_iso_big_sync(sync, &big_param, &big);
if (err) { if (err) {
@ -1161,7 +1184,7 @@ static void test_iso_recv_vs_dp_main(void)
is_iso_connected = false; is_iso_connected = false;
is_iso_disconnected = 0U; is_iso_disconnected = 0U;
is_iso_vs_emitted = false; 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); err = bt_iso_big_sync(sync, &big_param, &big);
if (err) { if (err) {

55
tests/bsim/bluetooth/ll/cis/src/main.c

@ -1,7 +1,7 @@
/* main.c - Application main entry point */ /* 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 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -13,6 +13,7 @@
#include <zephyr/bluetooth/bluetooth.h> #include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/bluetooth/conn.h> #include <zephyr/bluetooth/conn.h>
#include <zephyr/bluetooth/hci_types.h>
#include <zephyr/bluetooth/iso.h> #include <zephyr/bluetooth/iso.h>
#include <zephyr/bluetooth/hci.h> #include <zephyr/bluetooth/hci.h>
#include <zephyr/sys/util.h> #include <zephyr/sys/util.h>
@ -312,16 +313,65 @@ void iso_sent(struct bt_iso_chan *chan)
static void iso_connected(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); printk("ISO Channel %p connected\n", chan);
k_sem_give(&sem_iso_conn); 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) 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); printk("ISO Channel %p disconnected (reason 0x%02x)\n", chan, reason);
k_sem_give(&sem_iso_disc); 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 = { 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++) { for (int i = 0; i < CONFIG_BT_ISO_MAX_CHAN; i++) {
iso_tx[i].sdu = CONFIG_BT_ISO_TX_MTU; iso_tx[i].sdu = CONFIG_BT_ISO_TX_MTU;
iso_tx[i].phy = BT_GAP_LE_PHY_2M; iso_tx[i].phy = BT_GAP_LE_PHY_2M;
iso_tx[i].path = NULL;
if (IS_ENABLED(CONFIG_TEST_FT_SKIP_SUBEVENTS)) { if (IS_ENABLED(CONFIG_TEST_FT_SKIP_SUBEVENTS)) {
iso_tx[i].rtn = 2U; iso_tx[i].rtn = 2U;
} else { } else {
@ -374,7 +423,6 @@ static void test_cis_central(void)
iso_rx[i].sdu = CONFIG_BT_ISO_RX_MTU; iso_rx[i].sdu = CONFIG_BT_ISO_RX_MTU;
iso_rx[i].phy = BT_GAP_LE_PHY_2M; iso_rx[i].phy = BT_GAP_LE_PHY_2M;
iso_rx[i].path = NULL;
if (IS_ENABLED(CONFIG_TEST_FT_SKIP_SUBEVENTS)) { if (IS_ENABLED(CONFIG_TEST_FT_SKIP_SUBEVENTS)) {
iso_rx[i].rtn = 2U; iso_rx[i].rtn = 2U;
} else { } else {
@ -658,7 +706,6 @@ static void test_cis_peripheral(void)
for (int i = 0; i < CONFIG_BT_ISO_MAX_CHAN; i++) { 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].sdu = CONFIG_BT_ISO_TX_MTU;
iso_tx_p[i].phy = BT_GAP_LE_PHY_2M; iso_tx_p[i].phy = BT_GAP_LE_PHY_2M;
iso_tx_p[i].path = NULL;
if (IS_ENABLED(CONFIG_TEST_FT_SKIP_SUBEVENTS)) { if (IS_ENABLED(CONFIG_TEST_FT_SKIP_SUBEVENTS)) {
iso_tx_p[i].rtn = 2U; iso_tx_p[i].rtn = 2U;
} else { } else {

Loading…
Cancel
Save