diff --git a/samples/bluetooth/bap_unicast_client/src/main.c b/samples/bluetooth/bap_unicast_client/src/main.c index b8861bb6956960..082b9fe7d528ea 100644 --- a/samples/bluetooth/bap_unicast_client/src/main.c +++ b/samples/bluetooth/bap_unicast_client/src/main.c @@ -236,7 +236,7 @@ static void stream_enabled(struct bt_bap_stream *stream) k_sem_give(&sem_stream_enabled); } -static bool stream_is_tx(const struct bt_bap_stream *stream) +static bool stream_tx_can_send(const struct bt_bap_stream *stream) { struct bt_bap_ep_info info; int err; @@ -272,7 +272,7 @@ static void stream_started(struct bt_bap_stream *stream) { printk("Audio Stream %p started\n", stream); /* Register the stream for TX if it can send */ - if (IS_ENABLED(CONFIG_BT_AUDIO_TX) && stream_is_tx(stream)) { + if (IS_ENABLED(CONFIG_BT_AUDIO_TX) && stream_tx_can_send(stream)) { const int err = stream_tx_register(stream); if (err != 0) { @@ -298,7 +298,7 @@ static void stream_stopped(struct bt_bap_stream *stream, uint8_t reason) printk("Audio Stream %p stopped with reason 0x%02X\n", stream, reason); /* Unregister the stream for TX if it can send */ - if (IS_ENABLED(CONFIG_BT_AUDIO_TX) && stream_is_tx(stream)) { + if (IS_ENABLED(CONFIG_BT_AUDIO_TX) && stream_tx_can_send(stream)) { const int err = stream_tx_unregister(stream); if (err != 0) { diff --git a/tests/bsim/bluetooth/audio/src/bap_broadcast_source_test.c b/tests/bsim/bluetooth/audio/src/bap_broadcast_source_test.c index de0d7764779823..6905b9b76d7fca 100644 --- a/tests/bsim/bluetooth/audio/src/bap_broadcast_source_test.c +++ b/tests/bsim/bluetooth/audio/src/bap_broadcast_source_test.c @@ -26,6 +26,7 @@ #include #include "bap_common.h" +#include "bap_stream_tx.h" #include "bstests.h" #include "common.h" @@ -35,22 +36,7 @@ #define SUPPORTED_MAX_FRAMES_PER_SDU 1 #if defined(CONFIG_BT_BAP_BROADCAST_SOURCE) -/* When BROADCAST_ENQUEUE_COUNT > 1 we can enqueue enough buffers to ensure that - * the controller is never idle - */ -#define BROADCAST_ENQUEUE_COUNT 2U -#define TOTAL_BUF_NEEDED (BROADCAST_ENQUEUE_COUNT * CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT) - -BUILD_ASSERT(CONFIG_BT_ISO_TX_BUF_COUNT >= TOTAL_BUF_NEEDED, - "CONFIG_BT_ISO_TX_BUF_COUNT should be at least " - "BROADCAST_ENQUEUE_COUNT * CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT"); - -NET_BUF_POOL_FIXED_DEFINE(tx_pool, - TOTAL_BUF_NEEDED, - BT_ISO_SDU_BUF_SIZE(CONFIG_BT_ISO_TX_MTU), - CONFIG_BT_CONN_TX_USER_DATA_SIZE, NULL); -extern enum bst_result_t bst_result; static struct audio_test_stream broadcast_source_streams[CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT]; static struct bt_bap_lc3_preset preset_16_2_1 = BT_BAP_LC3_BROADCAST_PRESET_16_2_1( BT_AUDIO_LOCATION_FRONT_LEFT, BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED); @@ -214,6 +200,12 @@ static void started_cb(struct bt_bap_stream *stream) return; } + err = stream_tx_register(stream); + if (err != 0) { + FAIL("Failed to register stream %p for TX: %d\n", stream, err); + return; + } + printk("Stream %p started\n", stream); validate_stream_codec_cfg(stream); k_sem_give(&sem_started); @@ -221,53 +213,23 @@ static void started_cb(struct bt_bap_stream *stream) static void stopped_cb(struct bt_bap_stream *stream, uint8_t reason) { - printk("Stream %p stopped with reason 0x%02X\n", stream, reason); - k_sem_give(&sem_stopped); -} - -static void stream_sent_cb(struct bt_bap_stream *stream) -{ - struct audio_test_stream *test_stream = audio_test_stream_from_bap_stream(stream); - struct net_buf *buf; - int ret; - - if (!test_stream->tx_active) { - return; - } - - if ((test_stream->tx_cnt % 100U) == 0U) { - printk("Sent with seq_num %u\n", test_stream->seq_num); - } - - buf = net_buf_alloc(&tx_pool, K_FOREVER); - if (buf == NULL) { - printk("Could not allocate buffer when sending on %p\n", - stream); - return; - } - - net_buf_reserve(buf, BT_ISO_CHAN_SEND_RESERVE); - net_buf_add_mem(buf, mock_iso_data, test_stream->tx_sdu_size); - ret = bt_bap_stream_send(stream, buf, test_stream->seq_num++); - if (ret < 0) { - /* This will end broadcasting on this stream. */ - net_buf_unref(buf); + int err; - /* Only fail if tx is active (may fail if we are disabling the stream) */ - if (test_stream->tx_active) { - FAIL("Unable to broadcast data on %p: %d\n", stream, ret); - } + printk("Stream %p stopped with reason 0x%02X\n", stream, reason); + err = stream_tx_unregister(stream); + if (err != 0) { + FAIL("Failed to unregister stream %p for TX: %d\n", stream, err); return; } - test_stream->tx_cnt++; + k_sem_give(&sem_stopped); } static struct bt_bap_stream_ops stream_ops = { .started = started_cb, .stopped = stopped_cb, - .sent = stream_sent_cb, + .sent = stream_tx_sent_cb, }; static int setup_broadcast_source(struct bt_bap_broadcast_source **source, bool encryption) @@ -509,10 +471,6 @@ static void test_broadcast_source_stop(struct bt_bap_broadcast_source *source) printk("Stopping broadcast source\n"); - for (size_t i = 0U; i < ARRAY_SIZE(broadcast_source_streams); i++) { - broadcast_source_streams[i].tx_active = false; - } - err = bt_bap_broadcast_source_stop(source); if (err != 0) { FAIL("Unable to stop broadcast source: %d\n", err); @@ -577,6 +535,7 @@ static void test_main(void) } printk("Bluetooth initialized\n"); + stream_tx_init(); err = setup_broadcast_source(&source, false); if (err != 0) { @@ -594,17 +553,6 @@ static void test_main(void) test_broadcast_source_start(source, adv); - /* Initialize sending */ - printk("Sending data\n"); - for (size_t i = 0U; i < ARRAY_SIZE(broadcast_source_streams); i++) { - for (unsigned int j = 0U; j < BROADCAST_ENQUEUE_COUNT; j++) { - struct audio_test_stream *test_stream = &broadcast_source_streams[i]; - - test_stream->tx_active = true; - stream_sent_cb(&test_stream->stream.bap_stream); - } - } - /* Wait for other devices to have received what they wanted */ backchannel_sync_wait_any(); @@ -657,6 +605,7 @@ static void test_main_encrypted(void) } printk("Bluetooth initialized\n"); + stream_tx_init(); err = setup_broadcast_source(&source, true); if (err != 0) { @@ -672,17 +621,6 @@ static void test_main_encrypted(void) test_broadcast_source_start(source, adv); - /* Initialize sending */ - printk("Sending data\n"); - for (size_t i = 0U; i < ARRAY_SIZE(broadcast_source_streams); i++) { - for (unsigned int j = 0U; j < BROADCAST_ENQUEUE_COUNT; j++) { - struct audio_test_stream *test_stream = &broadcast_source_streams[i]; - - test_stream->tx_active = true; - stream_sent_cb(&test_stream->stream.bap_stream); - } - } - /* Wait for other devices to have received data */ backchannel_sync_wait_any(); diff --git a/tests/bsim/bluetooth/audio/src/bap_stream_rx.c b/tests/bsim/bluetooth/audio/src/bap_stream_rx.c index e2133a44a761ab..32ae34d2150329 100644 --- a/tests/bsim/bluetooth/audio/src/bap_stream_rx.c +++ b/tests/bsim/bluetooth/audio/src/bap_stream_rx.c @@ -13,14 +13,14 @@ #include "common.h" #include -LOG_MODULE_REGISTER(stream_tx, LOG_LEVEL_INF); +LOG_MODULE_REGISTER(stream_rx, LOG_LEVEL_INF); static void log_stream_rx(struct bt_bap_stream *stream, const struct bt_iso_recv_info *info, struct net_buf *buf) { struct audio_test_stream *test_stream = audio_test_stream_from_bap_stream(stream); - LOG_INF("[%zu]: Incoming audio on stream %p len %u, flags 0x%02X, seq_num %u and ts %u\n", + LOG_INF("[%zu]: Incoming audio on stream %p len %u, flags 0x%02X, seq_num %u and ts %u", test_stream->rx_cnt, stream, buf->len, info->flags, info->seq_num, info->ts); } @@ -35,13 +35,13 @@ void bap_stream_rx_recv_cb(struct bt_bap_stream *stream, const struct bt_iso_rec if (test_stream->rx_cnt > 0U && info->ts == test_stream->last_info.ts) { log_stream_rx(stream, info, buf); - FAIL("Duplicated timestamp received: %u\n", test_stream->last_info.ts); + FAIL("Duplicated timestamp received: %u", test_stream->last_info.ts); return; } if (test_stream->rx_cnt > 0U && info->seq_num == test_stream->last_info.seq_num) { log_stream_rx(stream, info, buf); - FAIL("Duplicated PSN received: %u\n", test_stream->last_info.seq_num); + FAIL("Duplicated PSN received: %u", test_stream->last_info.seq_num); return; } @@ -49,7 +49,7 @@ void bap_stream_rx_recv_cb(struct bt_bap_stream *stream, const struct bt_iso_rec /* Fail the test if we have not received what we expected */ if (!TEST_FLAG(flag_audio_received)) { log_stream_rx(stream, info, buf); - FAIL("ISO receive error\n"); + FAIL("ISO receive error"); } return; @@ -57,7 +57,7 @@ void bap_stream_rx_recv_cb(struct bt_bap_stream *stream, const struct bt_iso_rec if (info->flags & BT_ISO_FLAGS_LOST) { log_stream_rx(stream, info, buf); - FAIL("ISO receive lost\n"); + FAIL("ISO receive lost"); return; } @@ -70,6 +70,6 @@ void bap_stream_rx_recv_cb(struct bt_bap_stream *stream, const struct bt_iso_rec } } else { log_stream_rx(stream, info, buf); - FAIL("Unexpected data received\n"); + FAIL("Unexpected data received"); } } diff --git a/tests/bsim/bluetooth/audio/src/bap_stream_tx.c b/tests/bsim/bluetooth/audio/src/bap_stream_tx.c new file mode 100644 index 00000000000000..3ad550e4ba5f85 --- /dev/null +++ b/tests/bsim/bluetooth/audio/src/bap_stream_tx.c @@ -0,0 +1,221 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "bap_stream_tx.h" +#include "common.h" + +/** Enqueue at least 2 per stream, but otherwise equal distribution based on the buf count */ +#define ENQUEUE_CNT MAX(2, (CONFIG_BT_ISO_TX_BUF_COUNT / CONFIG_BT_ISO_MAX_CHAN)) + +LOG_MODULE_REGISTER(stream_tx, LOG_LEVEL_INF); + +struct tx_stream { + struct bt_bap_stream *bap_stream; + uint16_t seq_num; + atomic_t enqueued; +}; + +static struct tx_stream tx_streams[CONFIG_BT_ISO_MAX_CHAN]; + +static bool stream_is_streaming(const struct bt_bap_stream *bap_stream) +{ + struct bt_bap_ep_info ep_info; + int err; + + if (bap_stream == NULL) { + return false; + } + + /* No-op if stream is not configured */ + if (bap_stream->ep == NULL) { + return false; + } + + err = bt_bap_ep_get_info(bap_stream->ep, &ep_info); + if (err != 0) { + return false; + } + + if (ep_info.iso_chan == NULL || ep_info.iso_chan->state != BT_ISO_STATE_CONNECTED) { + return false; + } + + return ep_info.state == BT_BAP_EP_STATE_STREAMING; +} + +static void tx_thread_func(void *arg1, void *arg2, void *arg3) +{ + NET_BUF_POOL_FIXED_DEFINE(tx_pool, CONFIG_BT_ISO_TX_BUF_COUNT, + BT_ISO_SDU_BUF_SIZE(CONFIG_BT_ISO_TX_MTU), + CONFIG_BT_CONN_TX_USER_DATA_SIZE, NULL); + + /* This loop will attempt to send on all streams in the streaming state in a round robin + * fashion. + * The TX is controlled by the number of buffers configured, and increasing + * CONFIG_BT_ISO_TX_BUF_COUNT will allow for more streams in parallel, or to submit more + * buffers per stream. + * Once a buffer has been freed by the stack, it triggers the next TX. + */ + while (true) { + int err = -ENOEXEC; + + for (size_t i = 0U; i < ARRAY_SIZE(tx_streams); i++) { + struct bt_bap_stream *bap_stream = tx_streams[i].bap_stream; + + if (stream_is_streaming(bap_stream) && + atomic_get(&tx_streams[i].enqueued) < ENQUEUE_CNT) { + struct net_buf *buf; + + buf = net_buf_alloc(&tx_pool, K_FOREVER); + net_buf_reserve(buf, BT_ISO_CHAN_SEND_RESERVE); + + net_buf_add_mem(buf, mock_iso_data, bap_stream->qos->sdu); + + err = bt_bap_stream_send(bap_stream, buf, tx_streams[i].seq_num); + if (err == 0) { + tx_streams[i].seq_num++; + atomic_inc(&tx_streams[i].enqueued); + } else { + if (!stream_is_streaming(bap_stream)) { + /* Can happen if we disconnected while waiting for a + * buffer - Ignore + */ + } else { + FAIL("Unable to send: %d", err); + } + + net_buf_unref(buf); + } + } /* No-op if stream is not streaming */ + } + + if (err != 0) { + /* In case of any errors, retry with a delay */ + k_sleep(K_MSEC(10)); + } + } +} + +int stream_tx_register(struct bt_bap_stream *bap_stream) +{ + if (bap_stream == NULL) { + return -EINVAL; + } + + if (!stream_tx_can_send(bap_stream)) { + return -EINVAL; + } + + for (size_t i = 0U; i < ARRAY_SIZE(tx_streams); i++) { + if (tx_streams[i].bap_stream == NULL) { + tx_streams[i].bap_stream = bap_stream; + tx_streams[i].seq_num = 0U; + + LOG_INF("Registered %p for TX", bap_stream); + + return 0; + } + } + + return -ENOMEM; +} + +int stream_tx_unregister(struct bt_bap_stream *bap_stream) +{ + if (bap_stream == NULL) { + return -EINVAL; + } + + for (size_t i = 0U; i < ARRAY_SIZE(tx_streams); i++) { + if (tx_streams[i].bap_stream == bap_stream) { + tx_streams[i].bap_stream = NULL; + atomic_set(&tx_streams[i].enqueued, 0); + + LOG_INF("Unregistered %p for TX", bap_stream); + + return 0; + } + } + + return -ENODATA; +} + +void stream_tx_init(void) +{ + static bool thread_started; + + if (!thread_started) { + static K_KERNEL_STACK_DEFINE(tx_thread_stack, 1024U); + const int tx_thread_prio = K_PRIO_PREEMPT(5); + static struct k_thread tx_thread; + + k_thread_create(&tx_thread, tx_thread_stack, K_KERNEL_STACK_SIZEOF(tx_thread_stack), + tx_thread_func, NULL, NULL, NULL, tx_thread_prio, 0, K_NO_WAIT); + k_thread_name_set(&tx_thread, "TX thread"); + thread_started = true; + } +} + +bool stream_tx_can_send(const struct bt_bap_stream *stream) +{ + struct bt_bap_ep_info info; + int err; + + if (stream == NULL || stream->ep == NULL) { + return false; + } + + err = bt_bap_ep_get_info(stream->ep, &info); + if (err != 0) { + return false; + } + + return info.can_send; +} + +void stream_tx_sent_cb(struct bt_bap_stream *stream) +{ + struct audio_test_stream *test_stream = audio_test_stream_from_bap_stream(stream); + + if ((test_stream->tx_cnt % 100U) == 0U) { + LOG_INF("Stream %p sent %zu SDUs", stream, test_stream->tx_cnt); + } + + test_stream->tx_cnt++; + + for (size_t i = 0U; i < ARRAY_SIZE(tx_streams); i++) { + if (tx_streams[i].bap_stream == stream) { + const atomic_val_t old = atomic_dec(&tx_streams[i].enqueued); + + if (old == 0) { + FAIL("Old enqueue count was 0"); + } + } + } +} diff --git a/tests/bsim/bluetooth/audio/src/bap_stream_tx.h b/tests/bsim/bluetooth/audio/src/bap_stream_tx.h new file mode 100644 index 00000000000000..bfd7beefa5aad6 --- /dev/null +++ b/tests/bsim/bluetooth/audio/src/bap_stream_tx.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef STREAM_TX_H +#define STREAM_TX_H + +#include + +#include +#include +#include +#include + +/** + * @brief Initialize TX + * + * This will initialize TX if not already initialized. This creates and starts a thread that + * will attempt to send data on all streams registered with stream_tx_register(). + */ +void stream_tx_init(void); + +/** + * @brief Register a stream for TX + * + * This will add it to the list of streams the TX thread will attempt to send on. + * + * @param bap_stream The stream to register + * + * @retval 0 on success + * @retval -EINVAL @p bap_stream is NULL + * @retval -EINVAL @p bap_stream is not configured for TX + * @retval -EINVAL @p bap_stream.codec_cfg contains invalid values + * @retval -ENOMEM if not more streams can be registered + */ +int stream_tx_register(struct bt_bap_stream *bap_stream); + +/** + * @brief Unregister a stream for TX + * + * This will remove it to the list of streams the TX thread will attempt to send on. + * + * @param bap_stream The stream to unregister + * + * @retval 0 on success + * @retval -EINVAL @p bap_stream is NULL + * @retval -EINVAL @p bap_stream is not configured for TX + * @retval -EALREADY @p bap_stream is currently not registered + */ +int stream_tx_unregister(struct bt_bap_stream *bap_stream); + +/** + * @brief Test if the provided stream has been configured for TX + * + * @param bap_stream The stream to test for TX support + * + * @retval true if it has been configured for TX, and false if not + */ +bool stream_tx_can_send(const struct bt_bap_stream *stream); + +/** + * @brief Callback to indicate a TX complete + * + * @param stream The stream that completed TX + */ +void stream_tx_sent_cb(struct bt_bap_stream *stream); +#endif /* STREAM_TX_H */ diff --git a/tests/bsim/bluetooth/audio/src/bap_unicast_client_test.c b/tests/bsim/bluetooth/audio/src/bap_unicast_client_test.c index 970983e2cbe330..b49733cee422f2 100644 --- a/tests/bsim/bluetooth/audio/src/bap_unicast_client_test.c +++ b/tests/bsim/bluetooth/audio/src/bap_unicast_client_test.c @@ -30,6 +30,7 @@ #include #include "bap_stream_rx.h" +#include "bap_stream_tx.h" #include "bstests.h" #include "common.h" #include "bap_common.h" @@ -38,11 +39,6 @@ #define BAP_STREAM_RETRY_WAIT K_MSEC(100) -#define ENQUEUE_COUNT 2U -#define TOTAL_BUF_NEEDED (ENQUEUE_COUNT * CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT) -NET_BUF_POOL_FIXED_DEFINE(tx_pool, TOTAL_BUF_NEEDED, BT_ISO_SDU_BUF_SIZE(CONFIG_BT_ISO_TX_MTU), - CONFIG_BT_CONN_TX_USER_DATA_SIZE, NULL); - extern enum bst_result_t bst_result; static struct audio_test_stream test_streams[CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT]; @@ -106,6 +102,16 @@ static void stream_started(struct bt_bap_stream *stream) { printk("Started stream %p\n", stream); + if (stream_tx_can_send(stream)) { + int err; + + err = stream_tx_register(stream); + if (err != 0) { + FAIL("Failed to register stream %p for TX: %d\n", stream, err); + return; + } + } + SET_FLAG(flag_stream_started); } @@ -132,10 +138,6 @@ static void stream_metadata_updated(struct bt_bap_stream *stream) static void stream_disabled(struct bt_bap_stream *stream) { - struct audio_test_stream *test_stream = audio_test_stream_from_bap_stream(stream); - - test_stream->tx_active = false; - printk("Disabled stream %p\n", stream); SET_FLAG(flag_stream_disabled); @@ -145,6 +147,16 @@ static void stream_stopped(struct bt_bap_stream *stream, uint8_t reason) { printk("Stopped stream %p with reason 0x%02X\n", stream, reason); + if (stream_tx_can_send(stream)) { + int err; + + err = stream_tx_unregister(stream); + if (err != 0) { + FAIL("Failed to unregister stream %p for TX: %d\n", stream, err); + return; + } + } + SET_FLAG(flag_stream_stopped); } @@ -155,40 +167,6 @@ static void stream_released(struct bt_bap_stream *stream) SET_FLAG(flag_stream_released); } -static void stream_sent_cb(struct bt_bap_stream *stream) -{ - struct audio_test_stream *test_stream = audio_test_stream_from_bap_stream(stream); - struct net_buf *buf; - int ret; - - if (!test_stream->tx_active) { - return; - } - - buf = net_buf_alloc(&tx_pool, K_FOREVER); - if (buf == NULL) { - printk("Could not allocate buffer when sending on %p\n", stream); - return; - } - - net_buf_reserve(buf, BT_ISO_CHAN_SEND_RESERVE); - net_buf_add_mem(buf, mock_iso_data, test_stream->tx_sdu_size); - ret = bt_bap_stream_send(stream, buf, test_stream->seq_num++); - if (ret < 0) { - /* This will end broadcasting on this stream. */ - net_buf_unref(buf); - - /* Only fail if tx is active (may fail if we are disabling the stream) */ - if (test_stream->tx_active) { - FAIL("Unable to send data on %p: %d\n", stream, ret); - } - - return; - } - - test_stream->tx_cnt++; -} - static struct bt_bap_stream_ops stream_ops = { .configured = stream_configured, .qos_set = stream_qos_set, @@ -199,7 +177,7 @@ static struct bt_bap_stream_ops stream_ops = { .stopped = stream_stopped, .released = stream_released, .recv = bap_stream_rx_recv_cb, - .sent = stream_sent_cb, + .sent = stream_tx_sent_cb, .connected = stream_connected, .disconnected = stream_disconnected, }; @@ -496,6 +474,9 @@ static void init(void) return; } + printk("Bluetooth initialized\n"); + stream_tx_init(); + for (size_t i = 0; i < ARRAY_SIZE(test_streams); i++) { struct bt_bap_stream *bap_stream = bap_stream_from_audio_test_stream(&test_streams[i]); @@ -846,11 +827,6 @@ static void transceive_streams(void) struct audio_test_stream *test_stream = audio_test_stream_from_bap_stream(sink_stream); - test_stream->tx_active = true; - for (unsigned int i = 0U; i < ENQUEUE_COUNT; i++) { - stream_sent_cb(sink_stream); - } - /* Keep sending until we reach the minimum expected */ while (test_stream->tx_cnt < MIN_SEND_COUNT) { k_sleep(K_MSEC(100)); diff --git a/tests/bsim/bluetooth/audio/src/bap_unicast_server_test.c b/tests/bsim/bluetooth/audio/src/bap_unicast_server_test.c index 5db704fad342a9..7499b5687a050f 100644 --- a/tests/bsim/bluetooth/audio/src/bap_unicast_server_test.c +++ b/tests/bsim/bluetooth/audio/src/bap_unicast_server_test.c @@ -28,6 +28,7 @@ #include "bap_common.h" #include "bap_stream_rx.h" +#include "bap_stream_tx.h" #include "bstests.h" #include "common.h" @@ -39,11 +40,6 @@ extern enum bst_result_t bst_result; #define PREF_CONTEXT (BT_AUDIO_CONTEXT_TYPE_CONVERSATIONAL | BT_AUDIO_CONTEXT_TYPE_MEDIA) -#define ENQUEUE_COUNT 2U -#define TOTAL_BUF_NEEDED (ENQUEUE_COUNT * CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT) -NET_BUF_POOL_FIXED_DEFINE(tx_pool, TOTAL_BUF_NEEDED, BT_ISO_SDU_BUF_SIZE(CONFIG_BT_ISO_TX_MTU), - CONFIG_BT_CONN_TX_USER_DATA_SIZE, NULL); - static const struct bt_audio_codec_cap lc3_codec_cap = { .path_id = BT_ISO_DATA_PATH_HCI, .id = BT_HCI_CODING_FORMAT_LC3, @@ -203,12 +199,8 @@ static int lc3_metadata(struct bt_bap_stream *stream, const uint8_t meta[], size static int lc3_disable(struct bt_bap_stream *stream, struct bt_bap_ascs_rsp *rsp) { - struct audio_test_stream *test_stream = audio_test_stream_from_bap_stream(stream); - printk("Disable: stream %p\n", stream); - test_stream->tx_active = false; - return 0; } @@ -271,48 +263,41 @@ static void stream_started_cb(struct bt_bap_stream *stream) { printk("Started: stream %p\n", stream); + if (stream_tx_can_send(stream)) { + int err; + + err = stream_tx_register(stream); + if (err != 0) { + FAIL("Failed to register stream %p for TX: %d\n", stream, err); + return; + } + } + SET_FLAG(flag_stream_started); } -static void stream_sent_cb(struct bt_bap_stream *stream) +static void stream_stopped_cb(struct bt_bap_stream *stream, uint8_t reason) { - struct audio_test_stream *test_stream = audio_test_stream_from_bap_stream(stream); - struct net_buf *buf; - int ret; + printk("Stopped stream %p with reason 0x%02X\n", stream, reason); - if (!test_stream->tx_active) { - return; - } - - buf = net_buf_alloc(&tx_pool, K_FOREVER); - if (buf == NULL) { - printk("Could not allocate buffer when sending on %p\n", stream); - return; - } - - net_buf_reserve(buf, BT_ISO_CHAN_SEND_RESERVE); - net_buf_add_mem(buf, mock_iso_data, test_stream->tx_sdu_size); - ret = bt_bap_stream_send(stream, buf, test_stream->seq_num++); - if (ret < 0) { - /* This will end broadcasting on this stream. */ - net_buf_unref(buf); + if (stream_tx_can_send(stream)) { + int err; - /* Only fail if tx is active (may fail if we are disabling the stream) */ - if (test_stream->tx_active) { - FAIL("Unable to send data on %p: %d\n", stream, ret); + err = stream_tx_unregister(stream); + if (err != 0) { + FAIL("Failed to unregister stream %p for TX: %d\n", stream, err); + return; } - - return; } - - test_stream->tx_cnt++; } + static struct bt_bap_stream_ops stream_ops = { .enabled = stream_enabled_cb, .started = stream_started_cb, + .stopped = stream_stopped_cb, .recv = bap_stream_rx_recv_cb, - .sent = stream_sent_cb, + .sent = stream_tx_sent_cb, }; static void transceive_test_streams(void) @@ -358,11 +343,6 @@ static void transceive_test_streams(void) struct audio_test_stream *test_stream = audio_test_stream_from_bap_stream(source_stream); - test_stream->tx_active = true; - for (unsigned int i = 0U; i < ENQUEUE_COUNT; i++) { - stream_sent_cb(source_stream); - } - /* Keep sending until we reach the minimum expected */ while (test_stream->tx_cnt < MIN_SEND_COUNT) { k_sleep(K_MSEC(100)); @@ -450,6 +430,7 @@ static void init(void) } printk("Bluetooth initialized\n"); + stream_tx_init(); err = bt_bap_unicast_server_register(¶m); if (err != 0) { diff --git a/tests/bsim/bluetooth/audio/src/cap_initiator_broadcast_test.c b/tests/bsim/bluetooth/audio/src/cap_initiator_broadcast_test.c index ea6eacef4fb7ac..68ef8f8fbef8d9 100644 --- a/tests/bsim/bluetooth/audio/src/cap_initiator_broadcast_test.c +++ b/tests/bsim/bluetooth/audio/src/cap_initiator_broadcast_test.c @@ -29,6 +29,7 @@ #include #include "bap_common.h" +#include "bap_stream_tx.h" #include "bstests.h" #include "common.h" @@ -47,19 +48,10 @@ BT_GAP_MS_TO_PER_ADV_INTERVAL(150), BT_LE_PER_ADV_OPT_NONE) #define BROADCAST_STREMT_CNT CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT -#define BROADCAST_ENQUEUE_COUNT 18U -#define TOTAL_BUF_NEEDED (BROADCAST_ENQUEUE_COUNT * BROADCAST_STREMT_CNT) #define CAP_AC_MAX_STREAM 2 #define LOCATION (BT_AUDIO_LOCATION_FRONT_LEFT | BT_AUDIO_LOCATION_FRONT_RIGHT) #define CONTEXT (BT_AUDIO_CONTEXT_TYPE_MEDIA) -BUILD_ASSERT(CONFIG_BT_ISO_TX_BUF_COUNT >= TOTAL_BUF_NEEDED, - "CONFIG_BT_ISO_TX_BUF_COUNT should be at least " - "BROADCAST_ENQUEUE_COUNT * BROADCAST_STREMT_CNT"); - -NET_BUF_POOL_FIXED_DEFINE(tx_pool, TOTAL_BUF_NEEDED, BT_ISO_SDU_BUF_SIZE(CONFIG_BT_ISO_TX_MTU), - CONFIG_BT_CONN_TX_USER_DATA_SIZE, NULL); - struct cap_initiator_ac_param { char *name; size_t stream_cnt; @@ -117,70 +109,41 @@ static const struct named_lc3_preset lc3_broadcast_presets[] = { static void broadcast_started_cb(struct bt_bap_stream *stream) { struct audio_test_stream *test_stream = audio_test_stream_from_bap_stream(stream); + int err; test_stream->seq_num = 0U; test_stream->tx_cnt = 0U; printk("Stream %p started\n", stream); - k_sem_give(&sem_broadcast_started); -} - -static void broadcast_stopped_cb(struct bt_bap_stream *stream, uint8_t reason) -{ - printk("Stream %p stopped with reason 0x%02X\n", stream, reason); - k_sem_give(&sem_broadcast_stopped); -} - -static void broadcast_sent_cb(struct bt_bap_stream *bap_stream) -{ - struct audio_test_stream *test_stream = audio_test_stream_from_bap_stream(bap_stream); - struct bt_cap_stream *cap_stream = cap_stream_from_audio_test_stream(test_stream); - struct net_buf *buf; - int ret; - - if (!test_stream->tx_active) { - return; - } - - if ((test_stream->tx_cnt % 100U) == 0U) { - printk("[%zu]: Stream %p sent with seq_num %u\n", test_stream->tx_cnt, cap_stream, - test_stream->seq_num); - } - if (test_stream->tx_sdu_size > CONFIG_BT_ISO_TX_MTU) { - FAIL("Invalid SDU %u for the MTU: %d", test_stream->tx_sdu_size, - CONFIG_BT_ISO_TX_MTU); + err = stream_tx_register(stream); + if (err != 0) { + FAIL("Failed to register stream %p for TX: %d\n", stream, err); return; } - buf = net_buf_alloc(&tx_pool, K_FOREVER); - if (buf == NULL) { - printk("Could not allocate buffer when sending on %p\n", bap_stream); - return; - } + k_sem_give(&sem_broadcast_started); +} - net_buf_reserve(buf, BT_ISO_CHAN_SEND_RESERVE); - net_buf_add_mem(buf, mock_iso_data, test_stream->tx_sdu_size); - ret = bt_cap_stream_send(cap_stream, buf, test_stream->seq_num++); - if (ret < 0) { - /* This will end broadcasting on this stream. */ - net_buf_unref(buf); +static void broadcast_stopped_cb(struct bt_bap_stream *stream, uint8_t reason) +{ + int err; - /* Only fail if tx is active (may fail if we are disabling the stream) */ - if (test_stream->tx_active) { - FAIL("Unable to broadcast data on %p: %d\n", cap_stream, ret); - } + printk("Stream %p stopped with reason 0x%02X\n", stream, reason); + err = stream_tx_unregister(stream); + if (err != 0) { + FAIL("Failed to unregister stream %p for TX: %d\n", stream, err); return; } - test_stream->tx_cnt++; + k_sem_give(&sem_broadcast_stopped); } static struct bt_bap_stream_ops broadcast_stream_ops = { .started = broadcast_started_cb, .stopped = broadcast_stopped_cb, - .sent = broadcast_sent_cb, + .sent = stream_tx_sent_cb, }; static void init(void) @@ -193,6 +156,9 @@ static void init(void) return; } + printk("Bluetooth initialized\n"); + stream_tx_init(); + (void)memset(broadcast_source_streams, 0, sizeof(broadcast_source_streams)); for (size_t i = 0; i < ARRAY_SIZE(broadcast_streams); i++) { @@ -592,10 +558,6 @@ static void test_broadcast_audio_stop(struct bt_cap_broadcast_source *broadcast_ printk("Stopping broadcast source\n"); - for (size_t i = 0U; i < ARRAY_SIZE(broadcast_source_streams); i++) { - broadcast_source_streams[i].tx_active = false; - } - err = bt_cap_initiator_broadcast_audio_stop(broadcast_source); if (err != 0) { FAIL("Failed to stop broadcast source: %d\n", err); @@ -682,17 +644,6 @@ static void test_main_cap_initiator_broadcast(void) k_sem_take(&sem_broadcast_started, K_FOREVER); } - /* Initialize sending */ - for (size_t i = 0U; i < stream_count; i++) { - struct audio_test_stream *test_stream = &broadcast_source_streams[i]; - - test_stream->tx_active = true; - - for (unsigned int j = 0U; j < BROADCAST_ENQUEUE_COUNT; j++) { - broadcast_sent_cb(bap_stream_from_audio_test_stream(test_stream)); - } - } - /* Wait for other devices to have received what they wanted */ backchannel_sync_wait_any(); @@ -788,17 +739,6 @@ static int test_cap_initiator_ac(const struct cap_initiator_ac_param *param) k_sem_take(&sem_broadcast_started, K_FOREVER); } - /* Initialize sending */ - for (size_t i = 0U; i < stream_count; i++) { - struct audio_test_stream *test_stream = &broadcast_source_streams[i]; - - test_stream->tx_active = true; - - for (unsigned int j = 0U; j < BROADCAST_ENQUEUE_COUNT; j++) { - broadcast_sent_cb(bap_stream_from_audio_test_stream(test_stream)); - } - } - /* Wait for other devices to have received what they wanted */ backchannel_sync_wait_any(); diff --git a/tests/bsim/bluetooth/audio/src/common.h b/tests/bsim/bluetooth/audio/src/common.h index 5487e45593628d..9e9b8a354b84a3 100644 --- a/tests/bsim/bluetooth/audio/src/common.h +++ b/tests/bsim/bluetooth/audio/src/common.h @@ -107,7 +107,7 @@ extern enum bst_result_t bst_result; #define PA_SYNC_INTERVAL_TO_TIMEOUT_RATIO 20 /* Set the timeout relative to interval */ #define PA_SYNC_SKIP 5 -#define PBP_STREAMS_TO_SEND 2 +#define PBP_STREAMS_TO_SEND 2 extern struct bt_le_scan_cb common_scan_cb; extern const struct bt_data ad[AD_SIZE]; @@ -135,7 +135,6 @@ struct audio_test_stream { struct bt_cap_stream stream; uint16_t seq_num; - bool tx_active; size_t tx_cnt; uint16_t tx_sdu_size; diff --git a/tests/bsim/bluetooth/audio/src/gmap_ugg_test.c b/tests/bsim/bluetooth/audio/src/gmap_ugg_test.c index a1512936128855..e3e2170769be0b 100644 --- a/tests/bsim/bluetooth/audio/src/gmap_ugg_test.c +++ b/tests/bsim/bluetooth/audio/src/gmap_ugg_test.c @@ -34,6 +34,7 @@ #include #include +#include "bap_stream_tx.h" #include "bstests.h" #include "common.h" #include "bap_common.h" @@ -65,17 +66,6 @@ #define GMAP_UNICAST_AC_MAX_PAIR MAX(GMAP_UNICAST_AC_MAX_SNK, GMAP_UNICAST_AC_MAX_SRC) #define GMAP_UNICAST_AC_MAX_STREAM (GMAP_UNICAST_AC_MAX_SNK + GMAP_UNICAST_AC_MAX_SRC) -#define MAX_ISO_CHAN_COUNT 2U -#define ISO_ENQUEUE_COUNT 2U -#define TOTAL_BUF_NEEDED (ISO_ENQUEUE_COUNT * MAX_ISO_CHAN_COUNT) - -BUILD_ASSERT( - CONFIG_BT_ISO_TX_BUF_COUNT >= TOTAL_BUF_NEEDED, - "CONFIG_BT_ISO_TX_BUF_COUNT should be at least ISO_ENQUEUE_COUNT * MAX_ISO_CHAN_COUNT"); - -NET_BUF_POOL_FIXED_DEFINE(tx_pool, TOTAL_BUF_NEEDED, BT_ISO_SDU_BUF_SIZE(CONFIG_BT_ISO_TX_MTU), - CONFIG_BT_CONN_TX_USER_DATA_SIZE, NULL); - extern enum bst_result_t bst_result; static const struct named_lc3_preset *snk_named_preset; static const struct named_lc3_preset *src_named_preset; @@ -178,52 +168,6 @@ const struct named_lc3_preset *gmap_get_named_preset(bool is_unicast, enum bt_au return NULL; } -static void stream_sent_cb(struct bt_bap_stream *bap_stream) -{ - struct audio_test_stream *test_stream = audio_test_stream_from_bap_stream(bap_stream); - struct bt_cap_stream *cap_stream = cap_stream_from_audio_test_stream(test_stream); - struct net_buf *buf; - int ret; - - if (!test_stream->tx_active) { - return; - } - - if ((test_stream->tx_cnt % 100U) == 0U) { - printk("[%zu]: Stream %p sent with seq_num %u\n", test_stream->tx_cnt, cap_stream, - test_stream->seq_num); - } - - if (test_stream->tx_sdu_size > CONFIG_BT_ISO_TX_MTU) { - FAIL("Invalid SDU %u for the MTU: %d", test_stream->tx_sdu_size, - CONFIG_BT_ISO_TX_MTU); - return; - } - - buf = net_buf_alloc(&tx_pool, K_FOREVER); - if (buf == NULL) { - printk("Could not allocate buffer when sending on %p\n", bap_stream); - return; - } - - net_buf_reserve(buf, BT_ISO_CHAN_SEND_RESERVE); - net_buf_add_mem(buf, mock_iso_data, test_stream->tx_sdu_size); - ret = bt_cap_stream_send(cap_stream, buf, test_stream->seq_num++); - if (ret < 0) { - /* This will end broadcasting on this stream. */ - net_buf_unref(buf); - - /* Only fail if tx is active (may fail if we are disabling the stream) */ - if (test_stream->tx_active) { - FAIL("Unable to broadcast data on %p: %d\n", cap_stream, ret); - } - - return; - } - - test_stream->tx_cnt++; -} - static void stream_configured_cb(struct bt_bap_stream *stream, const struct bt_bap_qos_cfg_pref *pref) { @@ -247,6 +191,17 @@ static void stream_enabled_cb(struct bt_bap_stream *stream) static void stream_started_cb(struct bt_bap_stream *stream) { printk("Started stream %p\n", stream); + + if (stream_tx_can_send(stream)) { + int err; + + err = stream_tx_register(stream); + if (err != 0) { + FAIL("Failed to register stream %p for TX: %d\n", stream, err); + return; + } + } + k_sem_give(&sem_stream_started); } @@ -263,6 +218,17 @@ static void stream_disabled_cb(struct bt_bap_stream *stream) static void stream_stopped_cb(struct bt_bap_stream *stream, uint8_t reason) { printk("Stream %p stopped with reason 0x%02X\n", stream, reason); + + if (stream_tx_can_send(stream)) { + int err; + + err = stream_tx_unregister(stream); + if (err != 0) { + FAIL("Failed to unregister stream %p for TX: %d\n", stream, err); + return; + } + } + k_sem_give(&sem_stream_stopped); } @@ -280,7 +246,7 @@ static struct bt_bap_stream_ops stream_ops = { .disabled = stream_disabled_cb, .stopped = stream_stopped_cb, .released = stream_released_cb, - .sent = stream_sent_cb, + .sent = stream_tx_sent_cb, }; static void cap_discovery_complete_cb(struct bt_conn *conn, int err, @@ -473,6 +439,9 @@ static void init(void) return; } + printk("Bluetooth initialized\n"); + stream_tx_init(); + bt_gatt_cb_register(&gatt_callbacks); err = bt_bap_unicast_client_register_cb(&unicast_client_cbs); @@ -1153,10 +1122,6 @@ static void broadcast_audio_stop(struct bt_cap_broadcast_source *broadcast_sourc printk("Stopping broadcast source\n"); - for (size_t i = 0U; i < ARRAY_SIZE(broadcast_streams); i++) { - broadcast_streams[i].tx_active = false; - } - err = bt_cap_initiator_broadcast_audio_stop(broadcast_source); if (err != 0) { FAIL("Failed to stop broadcast source: %d\n", err); @@ -1257,18 +1222,6 @@ static int test_gmap_ugg_broadcast_ac(const struct gmap_broadcast_ac_param *para k_sem_take(&sem_stream_started, K_FOREVER); } - /* Initialize sending */ - printk("Starting sending\n"); - for (size_t i = 0U; i < param->stream_cnt; i++) { - struct audio_test_stream *test_stream = &broadcast_streams[i]; - - test_stream->tx_active = true; - - for (unsigned int j = 0U; j < ISO_ENQUEUE_COUNT; j++) { - stream_sent_cb(bap_stream_from_audio_test_stream(test_stream)); - } - } - /* Wait for other devices to have received what they wanted */ backchannel_sync_wait_any(); diff --git a/tests/bsim/bluetooth/audio/src/pbp_public_broadcast_source_test.c b/tests/bsim/bluetooth/audio/src/pbp_public_broadcast_source_test.c index 8947e386efee4a..a9ecbe67a6e4a1 100644 --- a/tests/bsim/bluetooth/audio/src/pbp_public_broadcast_source_test.c +++ b/tests/bsim/bluetooth/audio/src/pbp_public_broadcast_source_test.c @@ -26,30 +26,17 @@ #include #include +#include "bap_stream_tx.h" #include "bstests.h" #include "common.h" #if defined(CONFIG_BT_PBP) -/* When BROADCAST_ENQUEUE_COUNT > 1 we can enqueue enough buffers to ensure that - * the controller is never idle - */ -#define BROADCAST_ENQUEUE_COUNT 2U -#define BUF_NEEDED (BROADCAST_ENQUEUE_COUNT * CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT) /* PBS ASCII text */ #define PBS_DEMO 'P', 'B', 'P' #define SEM_TIMEOUT K_SECONDS(2) extern enum bst_result_t bst_result; -BUILD_ASSERT(CONFIG_BT_ISO_TX_BUF_COUNT >= BUF_NEEDED, - "CONFIG_BT_ISO_TX_BUF_COUNT should be at least " - "BROADCAST_ENQUEUE_COUNT * CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT"); - -NET_BUF_POOL_FIXED_DEFINE(tx_pool, - BUF_NEEDED, - BT_ISO_SDU_BUF_SIZE(CONFIG_BT_ISO_TX_MTU), - CONFIG_BT_CONN_TX_USER_DATA_SIZE, NULL); - static const uint8_t pba_metadata[] = { BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_PROGRAM_INFO, PBS_DEMO)}; @@ -58,6 +45,7 @@ static uint8_t bis_codec_data[] = { BT_BYTES_LIST_LE16(BT_AUDIO_CODEC_CFG_FREQ_48KHZ))}; static struct audio_test_stream broadcast_source_stream; +static struct bt_cap_stream *broadcast_stream; static struct bt_cap_initiator_broadcast_stream_param stream_params; static struct bt_cap_initiator_broadcast_subgroup_param subgroup_param; @@ -76,55 +64,35 @@ static struct bt_le_ext_adv *adv; static void started_cb(struct bt_bap_stream *stream) { struct audio_test_stream *test_stream = audio_test_stream_from_bap_stream(stream); + int err; test_stream->seq_num = 0U; test_stream->tx_cnt = 0U; printk("Stream %p started\n", stream); + + err = stream_tx_register(stream); + if (err != 0) { + FAIL("Failed to register stream %p for TX: %d\n", stream, err); + return; + } + k_sem_give(&sem_started); } static void stopped_cb(struct bt_bap_stream *stream, uint8_t reason) { - printk("Stream %p stopped with reason 0x%02X\n", stream, reason); - k_sem_give(&sem_stopped); -} - -static void sent_cb(struct bt_bap_stream *stream) -{ - struct audio_test_stream *test_stream = audio_test_stream_from_bap_stream(stream); - struct net_buf *buf; - int ret; - - if (!test_stream->tx_active) { - return; - } + int err; - if (broadcast_preset_48_2_1.qos.sdu > CONFIG_BT_ISO_TX_MTU) { - printk("Invalid SDU %u for the MTU: %d", - broadcast_preset_48_2_1.qos.sdu, CONFIG_BT_ISO_TX_MTU); - return; - } + printk("Stream %p stopped with reason 0x%02X\n", stream, reason); - buf = net_buf_alloc(&tx_pool, K_FOREVER); - if (buf == NULL) { - printk("Could not allocate buffer when sending on %p\n", stream); + err = stream_tx_unregister(stream); + if (err != 0) { + FAIL("Failed to unregister stream %p for TX: %d\n", stream, err); return; } - net_buf_reserve(buf, BT_ISO_CHAN_SEND_RESERVE); - net_buf_add_mem(buf, mock_iso_data, broadcast_preset_48_2_1.qos.sdu); - ret = bt_bap_stream_send(stream, buf, test_stream->seq_num++); - if (ret < 0) { - /* This will end broadcasting on this stream. */ - net_buf_unref(buf); - - /* Only fail if tx is active (may fail if we are disabling the stream) */ - if (test_stream->tx_active) { - FAIL("Unable to broadcast data on %p: %d\n", stream, ret); - } - return; - } + k_sem_give(&sem_stopped); } static int setup_extended_adv_data(struct bt_cap_broadcast_source *source, @@ -283,7 +251,7 @@ static int stop_extended_adv(struct bt_le_ext_adv *adv) static struct bt_bap_stream_ops broadcast_stream_ops = { .started = started_cb, .stopped = stopped_cb, - .sent = sent_cb + .sent = stream_tx_sent_cb, }; static void test_main(void) @@ -298,6 +266,10 @@ static void test_main(void) return; } + printk("Bluetooth initialized\n"); + stream_tx_init(); + + broadcast_stream = &broadcast_source_stream.stream; bt_bap_stream_cb_register(&broadcast_source_stream.stream.bap_stream, &broadcast_stream_ops); @@ -351,19 +323,11 @@ static void test_main(void) k_sem_take(&sem_started, SEM_TIMEOUT); - /* Initialize sending */ - broadcast_source_stream.tx_active = true; - for (unsigned int j = 0U; j < BROADCAST_ENQUEUE_COUNT; j++) { - sent_cb(&broadcast_source_stream.stream.bap_stream); - } - /* Wait for other devices to let us know when we can stop the source */ printk("Waiting for signal from receiver to stop\n"); backchannel_sync_wait_any(); printk("Stopping broadcast source\n"); - broadcast_source_stream.tx_active = false; - err = bt_cap_initiator_broadcast_audio_stop(broadcast_source); if (err != 0) { printk("Failed to stop broadcast source: %d\n", err);