Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion samples/bluetooth/cap_acceptor/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ config SAMPLE_UNICAST

config SAMPLE_BROADCAST
bool "Whether or not to search for CAP acceptors for unicast audio"
default y if !SAMPLE_UNICAST
default y
select BT_BAP_SCAN_DELEGATOR
select BT_OBSERVER
select BT_ISO_SYNC_RECEIVER
Expand Down
2 changes: 2 additions & 0 deletions samples/bluetooth/cap_acceptor/prj.conf
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,5 @@ CONFIG_BT_ISO_MAX_CHAN=2

# Support long Metadata size for audio configuration
CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE=24

CONFIG_BT_BAP_SCAN_DELEGATOR_LOG_LEVEL_DBG=y
4 changes: 2 additions & 2 deletions samples/bluetooth/cap_acceptor/src/cap_acceptor.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@
struct peer_config {
/** Stream for the source endpoint */
struct bt_cap_stream source_stream;
/** Stream for the sink endpoint */
struct bt_cap_stream sink_stream;
/** Streams for the sink endpoint */
struct bt_cap_stream sink_streams[CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT];
/** Semaphore to help wait for a release operation if the source stream is not idle */
struct k_sem source_stream_sem;
/** Semaphore to help wait for a release operation if the sink stream is not idle */
Expand Down
5 changes: 4 additions & 1 deletion samples/bluetooth/cap_acceptor/src/cap_acceptor_broadcast.c
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,6 @@ static int check_start_scan(void)
static void broadcast_stream_started_cb(struct bt_bap_stream *bap_stream)
{
LOG_INF("Started bap_stream %p", bap_stream);
total_broadcast_rx_iso_packet_count = 0U;

atomic_clear_bit(flags, FLAG_BROADCAST_SYNCING);
atomic_set_bit(flags, FLAG_BROADCAST_SYNCED);
Expand Down Expand Up @@ -482,6 +481,8 @@ static int bis_sync_req_cb(struct bt_conn *conn,
}

if (broadcast_sink.requested_bis_sync == new_bis_sync_req) {
LOG_INF("New request (0x%08x) is the same as last request; ignoring",
bis_sync_req[0]);
return 0; /* no op */
}

Expand All @@ -491,6 +492,8 @@ static int bis_sync_req_cb(struct bt_conn *conn,
*/
int err;

LOG_INF("Already synced. Stopping current sync and attempt resyncing");

/* The stream stopped callback will be called as part of this,
* and we do not need to wait for any events from the
* controller. Thus, when this returns, the broadcast sink is stopped
Expand Down
9 changes: 7 additions & 2 deletions samples/bluetooth/cap_acceptor/src/cap_acceptor_unicast.c
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,6 @@ static void unicast_stream_enabled_cb(struct bt_bap_stream *bap_stream)
static void unicast_stream_started_cb(struct bt_bap_stream *bap_stream)
{
LOG_INF("Started bap_stream %p", bap_stream);
total_unicast_rx_iso_packet_count = 0U;
}

static void unicast_stream_metadata_updated_cb(struct bt_bap_stream *bap_stream)
Expand Down Expand Up @@ -438,7 +437,10 @@ int init_cap_acceptor_unicast(struct peer_config *peer)
}

bt_cap_stream_ops_register(&peer->source_stream, &unicast_stream_ops);
bt_cap_stream_ops_register(&peer->sink_stream, &unicast_stream_ops);

ARRAY_FOR_EACH_PTR(peer->sink_streams, stream) {
bt_cap_stream_ops_register(stream, &unicast_stream_ops);
}

if (IS_ENABLED(CONFIG_BT_ASCS_ASE_SRC)) {
static bool thread_started;
Expand All @@ -459,5 +461,8 @@ int init_cap_acceptor_unicast(struct peer_config *peer)
k_sem_init(&peer->source_stream_sem, 0, 1);
k_sem_init(&peer->sink_stream_sem, 0, 1);

total_unicast_rx_iso_packet_count = 0U;
total_unicast_tx_iso_packet_count = 0U;

return 0;
}
25 changes: 17 additions & 8 deletions samples/bluetooth/cap_acceptor/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include <zephyr/kernel.h>
#include <zephyr/logging/log.h>
#include <zephyr/logging/log_core.h>
#include <zephyr/sys/__assert.h>
#include <zephyr/sys/util.h>
#include <zephyr/sys/util_macro.h>

Expand Down Expand Up @@ -140,8 +141,12 @@ static int advertise(void)

struct bt_cap_stream *stream_alloc(enum bt_audio_dir dir)
{
if (dir == BT_AUDIO_DIR_SINK && peer.sink_stream.bap_stream.ep == NULL) {
return &peer.sink_stream;
if (dir == BT_AUDIO_DIR_SINK) {
ARRAY_FOR_EACH_PTR(peer.sink_streams, stream) {
if (stream->bap_stream.ep == NULL) {
return stream;
}
}
} else if (dir == BT_AUDIO_DIR_SOURCE && peer.source_stream.bap_stream.ep == NULL) {
return &peer.source_stream;
}
Expand All @@ -153,8 +158,10 @@ void stream_released(const struct bt_cap_stream *cap_stream)
{
if (cap_stream == &peer.source_stream) {
k_sem_give(&peer.source_stream_sem);
} else if (cap_stream == &peer.sink_stream) {
} else if (IS_ARRAY_ELEMENT(peer.sink_streams, cap_stream)) {
k_sem_give(&peer.sink_stream_sem);
} else {
__ASSERT(false, "Invalid stream: %p", cap_stream);
}
}

Expand Down Expand Up @@ -201,11 +208,13 @@ static int reset_cap_acceptor(void)
}
}

if (peer.sink_stream.bap_stream.ep != NULL) {
err = k_sem_take(&peer.sink_stream_sem, SEM_TIMEOUT);
if (err != 0) {
LOG_ERR("Timeout on sink_stream_sem: %d", err);
return err;
ARRAY_FOR_EACH_PTR(peer.sink_streams, stream) {
if (stream->bap_stream.ep != NULL) {
err = k_sem_take(&peer.sink_stream_sem, SEM_TIMEOUT);
if (err != 0) {
LOG_ERR("Timeout on sink_stream_sem: %d", err);
return err;
}
}
}

Expand Down
12 changes: 12 additions & 0 deletions samples/bluetooth/cap_handover/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# SPDX-License-Identifier: Apache-2.0

cmake_minimum_required(VERSION 3.20.0)
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(cap_handover)

target_sources(app PRIVATE
src/main.c
src/cap_stream_tx.c
)

zephyr_library_include_directories(${ZEPHYR_BASE}/samples/bluetooth)
21 changes: 21 additions & 0 deletions samples/bluetooth/cap_handover/Kconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Copyright (c) 2024 Nordic Semiconductor ASA
# SPDX-License-Identifier: Apache-2.0

mainmenu "Bluetooth: Common Audio Profile initiator sample"

config SAMPLE_STATIC_BROADCAST_ID
bool "Use static broadcast ID"
default y
help
Enabling this option will make the application use static broadcast ID, as opposed to a
randomly generated one.

config SAMPLE_BROADCAST_ID
hex "The static broadcast ID to use"
range 0x000000 0xFFFFFF
depends on STATIC_BROADCAST_ID
default 0x123456
help
This is the 3-octet broadcast ID advertised if static broadcast IDs are enabled.

source "Kconfig.zephyr"
15 changes: 15 additions & 0 deletions samples/bluetooth/cap_handover/Kconfig.sysbuild
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Copyright 2023 Nordic Semiconductor ASA
# SPDX-License-Identifier: Apache-2.0

source "share/sysbuild/Kconfig"

config NET_CORE_BOARD
string
default "nrf5340dk/nrf5340/cpunet" if "$(BOARD)" = "nrf5340dk"
default "nrf5340_audio_dk/nrf5340/cpunet" if "$(BOARD)" = "nrf5340_audio_dk"
default "nrf5340bsim/nrf5340/cpunet" if $(BOARD_TARGET_STRING) = "NRF5340BSIM_NRF5340_CPUAPP"

config NET_CORE_IMAGE_HCI_IPC
bool "HCI IPC image on network core"
default y
depends on NET_CORE_BOARD != ""
75 changes: 75 additions & 0 deletions samples/bluetooth/cap_handover/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
.. zephyr:code-sample:: bluetooth_cap_handover
:name: Common Audio Profile (CAP) Handover
:relevant-api: bluetooth bt_bap bt_cap bt_conn

Connects to a CAP acceptor and performs CAP handover procedures

Overview
********

Application demonstrating the CAP handover functionality.
Starts by scanning for a CAP Acceptor then sets up unicast audio, and then switches between unicast
and broadcast using the CAP handover procedures.

This sample can be found under :zephyr_file:`samples/bluetooth/cap_handover` in the Zephyr tree.

Check the :zephyr:code-sample-category:`bluetooth` samples for general information.

Requirements
************

* BlueZ running on the host, or
* A board with Bluetooth Low Energy 5.2 support

Building and Running
********************

When building targeting an nrf52 series board with the Zephyr Bluetooth Controller,
use ``-DEXTRA_CONF_FILE=overlay-bt_ll_sw_split.conf`` to enable the required ISO
feature support.

Building for an nrf5340dk
-------------------------

You can build both the application core image and an appropriate controller image for the network
core with:

.. zephyr-app-commands::
:zephyr-app: samples/bluetooth/cap_handover/
:board: nrf5340dk/nrf5340/cpuapp
:goals: build
:west-args: --sysbuild

If you prefer to only build the application core image, you can do so by doing instead:

.. zephyr-app-commands::
:zephyr-app: samples/bluetooth/cap_handover/
:board: nrf5340dk/nrf5340/cpuapp
:goals: build

In that case you can pair this application core image with the
:zephyr:code-sample:`bluetooth_hci_ipc` sample
:zephyr_file:`samples/bluetooth/hci_ipc/nrf5340_cpunet_iso-bt_ll_sw_split.conf` configuration.

Building for a simulated nrf5340bsim
------------------------------------

Similarly to how you would for real HW, you can do:

.. zephyr-app-commands::
:zephyr-app: samples/bluetooth/cap_handover/
:board: nrf5340bsim/nrf5340/cpuapp
:goals: build
:west-args: --sysbuild

Note this will produce a Linux executable in :file:`./build/zephyr/zephyr.exe`.
For more information, check :ref:`this board documentation <nrf5340bsim>`.

Building for a simulated nrf52_bsim
-----------------------------------

.. zephyr-app-commands::
:zephyr-app: samples/bluetooth/cap_handover/
:board: nrf52_bsim
:goals: build
:gen-args: -DEXTRA_CONF_FILE=overlay-bt_ll_sw_split.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
CONFIG_BT_BUF_EVT_RX_SIZE=255
CONFIG_BT_BUF_ACL_RX_SIZE=255
CONFIG_BT_BUF_ACL_TX_SIZE=251
CONFIG_BT_BUF_CMD_TX_SIZE=255
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
CONFIG_BT_BUF_EVT_RX_SIZE=255
CONFIG_BT_BUF_ACL_RX_SIZE=255
CONFIG_BT_BUF_ACL_TX_SIZE=251
CONFIG_BT_BUF_CMD_TX_SIZE=255
42 changes: 42 additions & 0 deletions samples/bluetooth/cap_handover/overlay-bt_ll_sw_split.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Zephyr Bluetooth Controller
CONFIG_BT_LL_SW_SPLIT=y
CONFIG_BT_CTLR_ASSERT_HANDLER=y
CONFIG_BT_CTLR_DTM_HCI=y

CONFIG_BT_BROADCASTER=y
CONFIG_BT_OBSERVER=y
CONFIG_BT_EXT_ADV=y
CONFIG_BT_PER_ADV=y
CONFIG_BT_PER_ADV_SYNC=y
CONFIG_BT_CENTRAL=y
CONFIG_BT_MAX_CONN=1
CONFIG_BT_CTLR_PHY_CODED=y

# Zephyr Controller tested maximum advertising data that can be set in a single HCI command
CONFIG_BT_CTLR_SCAN_DATA_LEN_MAX=191
CONFIG_BT_CTLR_ADV_DATA_LEN_MAX=191

CONFIG_BT_ISO_BROADCASTER=y
CONFIG_BT_ISO_SYNC_RECEIVER=y
CONFIG_BT_ISO_CENTRAL=y
CONFIG_BT_ISO_TX_MTU=310
CONFIG_BT_ISO_RX_MTU=310
CONFIG_BT_ISO_MAX_CHAN=2

CONFIG_BT_CTLR_ADV_ISO_STREAM_COUNT=2
CONFIG_BT_CTLR_CONN_ISO_GROUPS=1
CONFIG_BT_CTLR_CONN_ISO_STREAMS=2
CONFIG_BT_CTLR_CONN_ISO_STREAMS_PER_GROUP=2

# In theory, CONFIG_BT_ISO_TX_BUF_COUNT=1, should be sufficient but this count
# is used in the context of IPC which falls into a "Newton's Cradle" effect
# where probably (CONFIG_BT_CTLR_ISO_TX_BUFFERS - CONFIG_BT_ISO_TX_BUF_COUNT)
# buffers get throttled. Hence, always have the value equal or greater.
CONFIG_BT_ISO_TX_BUF_COUNT=12
CONFIG_BT_ISO_RX_BUF_COUNT=1

# Support the highest SDU size required by any BAP LC3 presets (310) + 8 bytes of HCI ISO Data
# packet overhead (the Packet_Sequence_Number, ISO_SDU_Length, Packet_Status_Flag fields; and
# the optional Time_Stamp field, if supplied)
CONFIG_BT_CTLR_ISO_TX_BUFFER_SIZE=318
CONFIG_BT_CTLR_ISO_TX_SDU_LEN_MAX=310
52 changes: 52 additions & 0 deletions samples/bluetooth/cap_handover/prj.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
CONFIG_LOG=y
CONFIG_ASSERT=y

CONFIG_BT=y
CONFIG_BT_BROADCASTER=y
CONFIG_BT_CENTRAL=y
CONFIG_BT_GATT_CLIENT=y
CONFIG_BT_GATT_AUTO_DISCOVER_CCC=y
CONFIG_BT_GATT_AUTO_UPDATE_MTU=y
CONFIG_BT_GATT_DYNAMIC_DB=y
CONFIG_BT_KEYS_OVERWRITE_OLDEST=y
CONFIG_BT_SMP=y
CONFIG_BT_EXT_ADV=y
CONFIG_BT_PER_ADV=y
CONFIG_BT_PER_ADV_SYNC=y
CONFIG_BT_DEVICE_NAME="CAP handover central"
CONFIG_BT_AUDIO=y

# ISO configs
CONFIG_BT_ISO_MAX_CHAN=2
CONFIG_BT_ISO_CENTRAL=y
CONFIG_BT_ISO_BROADCASTER=y
CONFIG_BT_ISO_SYNC_RECEIVER=y

# BAP configs
CONFIG_BT_BAP_BROADCAST_ASSISTANT=y

CONFIG_BT_BAP_UNICAST_CLIENT=y
CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT=2
CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT=2

CONFIG_BT_BAP_SCAN_DELEGATOR=y

CONFIG_BT_BAP_BROADCAST_SOURCE=y
CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT=1
CONFIG_BT_BAP_BROADCAST_SRC_SUBGROUP_COUNT=1

CONFIG_BT_BAP_BROADCAST_ASSISTANT=y

# CAP configs
CONFIG_BT_CAP_INITIATOR=y
CONFIG_BT_CAP_COMMANDER=y
CONFIG_BT_CAP_HANDOVER=y

# CSIP configs
CONFIG_BT_CSIP_SET_COORDINATOR=y

CONFIG_BT_CAP_ACCEPTOR_LOG_LEVEL_DBG=y
CONFIG_BT_CAP_COMMANDER_LOG_LEVEL_DBG=y
CONFIG_BT_CAP_COMMON_LOG_LEVEL_DBG=y
CONFIG_BT_CAP_HANDOVER_LOG_LEVEL_DBG=y
CONFIG_BT_BAP_BROADCAST_ASSISTANT_LOG_LEVEL_DBG=y
30 changes: 30 additions & 0 deletions samples/bluetooth/cap_handover/sample.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
sample:
description: Bluetooth Low Energy Common Audio Profile Handover sample
name: Bluetooth Low Energy Common Audio Profile Handover sample
tests:
sample.bluetooth.cap_handover:
harness: bluetooth
platform_allow:
- qemu_cortex_m3
- qemu_x86
- nrf5340dk/nrf5340/cpuapp
- nrf5340bsim/nrf5340/cpuapp
integration_platforms:
- qemu_x86
- nrf5340dk/nrf5340/cpuapp
tags: bluetooth
sysbuild: true
sample.bluetooth.cap_handover.bt_ll_sw_split:
harness: bluetooth
platform_allow:
- nrf52_bsim
- nrf52833dk/nrf52833
- nrf52840dk/nrf52840
- nrf52840dongle/nrf52840
integration_platforms:
- nrf52_bsim
- nrf52833dk/nrf52833
- nrf52840dk/nrf52840
- nrf52840dongle/nrf52840
extra_args: EXTRA_CONF_FILE=overlay-bt_ll_sw_split.conf
tags: bluetooth
Loading
Loading