Skip to content

Commit 965bcd6

Browse files
Thalleycarlescufi
authored andcommitted
Bluetooth: CAP: Implement unicast to broadcast handover
Implement the unicast to broadcast handover procedure, as per the Bluetooth CAP specificiation. Signed-off-by: Emil Gydesen <[email protected]>
1 parent c535d6e commit 965bcd6

21 files changed

+2655
-147
lines changed

include/zephyr/bluetooth/audio/cap.h

Lines changed: 77 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -812,55 +812,99 @@ int bt_cap_initiator_broadcast_audio_delete(struct bt_cap_broadcast_source *broa
812812
int bt_cap_initiator_broadcast_get_base(struct bt_cap_broadcast_source *broadcast_source,
813813
struct net_buf_simple *base_buf);
814814

815-
/** Parameters for bt_cap_initiator_unicast_to_broadcast() */
816-
struct bt_cap_unicast_to_broadcast_param {
815+
/** Parameters for bt_cap_handover_unicast_to_broadcast() */
816+
struct bt_cap_handover_unicast_to_broadcast_param {
817+
/** The type of the set. */
818+
enum bt_cap_set_type type;
819+
817820
/** The source unicast group with the streams. */
818-
struct bt_bap_unicast_group *unicast_group;
821+
struct bt_cap_unicast_group *unicast_group;
819822

820823
/**
821-
* @brief Whether or not to encrypt the streams.
824+
* @brief The advertising set to use for the broadcast source
822825
*
823-
* If set to true, then the broadcast code in @p broadcast_code
824-
* will be used to encrypt the streams.
826+
* This shall remain valid until the procedure has completed.
827+
* If the advertising set is not started at the time of calling
828+
* bt_cap_handover_unicast_to_broadcast(),
829+
* the procedure will start the advertising set with @ref BT_LE_EXT_ADV_START_DEFAULT.
825830
*/
826-
bool encrypt;
831+
struct bt_le_ext_adv *ext_adv;
832+
833+
/** The SID of the advertising set. */
834+
uint8_t sid;
835+
836+
/** The periodic advertising interval configured for the advertising set. */
837+
uint16_t pa_interval;
838+
839+
/** The broadcast ID the advertising set is, or will be, using. */
840+
uint32_t broadcast_id;
827841

828842
/**
829-
* @brief 16-octet broadcast code.
830-
*
831-
* Only valid if @p encrypt is true.
843+
* @brief Broadcast source parameters.
832844
*
833-
* If the value is a string or a the value is less than 16 octets,
834-
* the remaining octets shall be 0.
845+
* These parameters shall remain valid until the procedure has completed.
846+
*/
847+
struct bt_cap_initiator_broadcast_create_param *broadcast_create_param;
848+
};
849+
850+
/** Callback structure for CAP procedures */
851+
struct bt_cap_handover_cb {
852+
/**
853+
* @brief The unicast to broadcast handover procedure has finished
835854
*
836-
* Example:
837-
* The string "Broadcast Code" shall be
838-
* [42 72 6F 61 64 63 61 73 74 20 43 6F 64 65 00 00]
855+
* @param err 0 if success else a negative errno value.
856+
* @param conn Pointer to the connection where the error occurred or NULL if local failure.
857+
* @param unicast_group NULL if the unicast group was deleted during the procedure, else
858+
* pointer to the unicast group provided in the parameters.
859+
* @param broadcast_source Pointer to newly created broadcast source, or NULL in case of an
860+
* error happening before it was created.
839861
*/
840-
uint8_t broadcast_code[BT_ISO_BROADCAST_CODE_SIZE];
862+
void (*unicast_to_broadcast_complete)(int err, struct bt_conn *conn,
863+
struct bt_cap_unicast_group *unicast_group,
864+
struct bt_cap_broadcast_source *broadcast_source);
841865
};
842866

843867
/**
844-
* @brief Hands over the data streams in a unicast group to a broadcast source.
868+
* @brief Register Common Audio Profile Handover callbacks
845869
*
846-
* The streams in the unicast group will be stopped and the unicast group
847-
* will be deleted. This can only be done for source streams.
870+
* @param cb The callback structure. Shall remain static.
848871
*
849-
* @note @kconfig{CONFIG_BT_CAP_INITIATOR},
850-
* @kconfig{CONFIG_BT_BAP_UNICAST_CLIENT} and
851-
* @kconfig{CONFIG_BT_BAP_BROADCAST_SOURCE} must be enabled for this function
852-
* to be enabled.
872+
* @return 0 on success or negative error value on failure.
873+
*/
874+
int bt_cap_handover_register_cb(const struct bt_cap_handover_cb *cb);
875+
876+
/**
877+
* @brief Unregister Common Audio Profile Handover callbacks
853878
*
854-
* @param param The parameters for the handover.
855-
* @param source The resulting broadcast source.
879+
* @param cb The callback structure that was previously registered.
880+
*
881+
* @retval 0 Success
882+
* @retval -EINVAL @p cb is NULL or @p cb was not registered
883+
*/
884+
int bt_cap_handover_unregister_cb(const struct bt_cap_handover_cb *cb);
885+
886+
/**
887+
* @brief Hands over the sink streams in a unicast group to a broadcast source.
888+
*
889+
* All streams in the provided unicast group will be stopped and released. The sink streams will be
890+
* tranferred to a broadcast source, and the broadcast source information will be shared with
891+
* all accepters that are currently receiving audio. Any stream that is not in the streaming state
892+
* will only be released.
893+
*
894+
* bt_bap_broadcast_assistant_discover() must have been successfully perform for all members in @p
895+
* param before starting this procedure.
896+
*
897+
* @kconfig_dep{CONFIG_BT_CAP_HANDOVER}
898+
*
899+
* @param param The parameters for the handover.
856900
*
857901
* @return 0 on success or negative error value on failure.
858902
*/
859-
int bt_cap_initiator_unicast_to_broadcast(const struct bt_cap_unicast_to_broadcast_param *param,
860-
struct bt_cap_broadcast_source **source);
903+
int bt_cap_handover_unicast_to_broadcast(
904+
const struct bt_cap_handover_unicast_to_broadcast_param *param);
861905

862-
/** Parameters for bt_cap_initiator_broadcast_to_unicast() */
863-
struct bt_cap_broadcast_to_unicast_param {
906+
/** Parameters for bt_cap_handover_broadcast_to_unicast() */
907+
struct bt_cap_handover_broadcast_to_unicast_param {
864908
/**
865909
* @brief The source broadcast source with the streams.
866910
*
@@ -890,18 +934,16 @@ struct bt_cap_broadcast_to_unicast_param {
890934
* The streams in the broadcast source will be stopped and the broadcast source
891935
* will be deleted.
892936
*
893-
* @note @kconfig{CONFIG_BT_CAP_INITIATOR},
894-
* @kconfig{CONFIG_BT_BAP_UNICAST_CLIENT} and
895-
* @kconfig{CONFIG_BT_BAP_BROADCAST_SOURCE} must be enabled for this function
896-
* to be enabled.
937+
* @kconfig_dep{CONFIG_BT_CAP_HANDOVER}
897938
*
898939
* @param[in] param The parameters for the handover.
899940
* @param[out] unicast_group The resulting broadcast source.
900941
*
901942
* @return 0 on success or negative error value on failure.
902943
*/
903-
int bt_cap_initiator_broadcast_to_unicast(const struct bt_cap_broadcast_to_unicast_param *param,
904-
struct bt_bap_unicast_group **unicast_group);
944+
int bt_cap_handover_broadcast_to_unicast(
945+
const struct bt_cap_handover_broadcast_to_unicast_param *param,
946+
struct bt_bap_unicast_group **unicast_group);
905947

906948
/** Callback structure for CAP procedures */
907949
struct bt_cap_commander_cb {

subsys/bluetooth/Kconfig.logging

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,12 @@ module-str = "Common Audio Profile Commander"
213213
source "subsys/logging/Kconfig.template.log_config_inherit"
214214
endif # BT_CAP_COMMANDER
215215

216+
if BT_CAP_HANDOVER
217+
module = BT_CAP_HANDOVER
218+
module-str = "Common Audio Profile Handover"
219+
source "subsys/logging/Kconfig.template.log_config_inherit"
220+
endif # BT_CAP_HANDOVER
221+
216222
if BT_AUDIO
217223
module = BT_CAP_COMMON
218224
module-str = "Common Audio Profile Common"

subsys/bluetooth/audio/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ zephyr_library_sources_ifdef(CONFIG_BT_CAP cap_stream.c)
6666
zephyr_library_sources_ifdef(CONFIG_BT_CAP_ACCEPTOR cap_acceptor.c)
6767
zephyr_library_sources_ifdef(CONFIG_BT_CAP_INITIATOR cap_initiator.c)
6868
zephyr_library_sources_ifdef(CONFIG_BT_CAP_COMMANDER cap_commander.c)
69+
zephyr_library_sources_ifdef(CONFIG_BT_CAP_HANDOVER cap_handover.c)
6970
if (CONFIG_BT_CAP_INITIATOR_UNICAST OR CONFIG_BT_CAP_COMMANDER)
7071
zephyr_library_sources(cap_common.c)
7172
endif()

subsys/bluetooth/audio/Kconfig.cap

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,3 +48,11 @@ config BT_CAP_COMMANDER
4848
BT_MCC
4949
help
5050
Enabling this will enable the CAP Initiator role.
51+
52+
config BT_CAP_HANDOVER
53+
bool "Common Audio Profile Handover Procedures"
54+
depends on BT_CAP_COMMANDER && BT_CAP_INITIATOR && BT_BAP_BROADCAST_ASSISTANT && \
55+
BT_BAP_BROADCAST_SOURCE && BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 0
56+
help
57+
Enable support for the CAP Handover procedures, allowing a device to switch between
58+
broadcast and unicast for a usecase.

subsys/bluetooth/audio/cap_commander.c

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2022-2023 Nordic Semiconductor ASA
2+
* Copyright (c) 2022-2025 Nordic Semiconductor ASA
33
*
44
* SPDX-License-Identifier: Apache-2.0
55
*/
@@ -28,6 +28,7 @@
2828
#include <zephyr/sys/__assert.h>
2929
#include <zephyr/sys/check.h>
3030
#include <zephyr/sys/util.h>
31+
#include <zephyr/sys/util_macro.h>
3132

3233
#include "audio_internal.h"
3334
#include "bap_endpoint.h"
@@ -325,7 +326,7 @@ static bool valid_broadcast_reception_start_param(
325326
return true;
326327
}
327328

328-
int bt_cap_commander_broadcast_reception_start(
329+
int cap_commander_broadcast_reception_start(
329330
const struct bt_cap_commander_broadcast_reception_start_param *param)
330331
{
331332
struct bt_bap_broadcast_assistant_add_src_param add_src_param = {0};
@@ -334,16 +335,6 @@ int bt_cap_commander_broadcast_reception_start(
334335
struct bt_conn *conn;
335336
int err;
336337

337-
if (!valid_broadcast_reception_start_param(param)) {
338-
return -EINVAL;
339-
}
340-
341-
if (bt_cap_common_test_and_set_proc_active()) {
342-
LOG_DBG("A CAP procedure is already in progress");
343-
344-
return -EBUSY;
345-
}
346-
347338
broadcast_assistant_cb.add_src = cap_commander_broadcast_assistant_add_src_cb;
348339
if (!broadcast_assistant_cb_registered) {
349340
err = cap_commander_register_broadcast_assistant_cb();
@@ -406,6 +397,22 @@ int bt_cap_commander_broadcast_reception_start(
406397
return 0;
407398
}
408399

400+
int bt_cap_commander_broadcast_reception_start(
401+
const struct bt_cap_commander_broadcast_reception_start_param *param)
402+
{
403+
if (!valid_broadcast_reception_start_param(param)) {
404+
return -EINVAL;
405+
}
406+
407+
if (bt_cap_common_test_and_set_proc_active()) {
408+
LOG_DBG("A CAP procedure is already in progress");
409+
410+
return -EBUSY;
411+
}
412+
413+
return cap_commander_broadcast_reception_start(param);
414+
}
415+
409416
static void
410417
copy_broadcast_reception_stop_param(struct bt_bap_broadcast_assistant_mod_src_param *mod_src_param,
411418
struct cap_broadcast_reception_stop *stop_param)
@@ -875,6 +882,18 @@ static void cap_commander_proc_complete(void)
875882
failed_conn = active_proc->failed_conn;
876883
err = active_proc->err;
877884
proc_type = active_proc->proc_type;
885+
886+
if (IS_ENABLED(CONFIG_BT_CAP_HANDOVER) && bt_cap_common_handover_is_active()) {
887+
/* Complete handover procedure. At this point we do not know if the remote
888+
* device will attempt to use PAST or scan for itself, so it's best to leave
889+
* this up to the application layer
890+
*/
891+
__ASSERT_NO_MSG(proc_type == BT_CAP_COMMON_PROC_TYPE_BROADCAST_RECEPTION_START);
892+
893+
bt_cap_handover_proc_complete();
894+
return;
895+
}
896+
878897
bt_cap_common_clear_active_proc();
879898

880899
if (cap_cb == NULL) {

subsys/bluetooth/audio/cap_common.c

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2023-2024 Nordic Semiconductor ASA
2+
* Copyright (c) 2023-2025 Nordic Semiconductor ASA
33
*
44
* SPDX-License-Identifier: Apache-2.0
55
*/
@@ -21,6 +21,7 @@
2121
#include <zephyr/sys/atomic.h>
2222
#include <zephyr/sys/check.h>
2323
#include <zephyr/sys/util.h>
24+
#include <zephyr/sys/util_macro.h>
2425

2526
#include "cap_internal.h"
2627
#include "csip_internal.h"
@@ -74,6 +75,18 @@ bool bt_cap_common_subproc_is_type(enum bt_cap_common_subproc_type subproc_type)
7475
}
7576
#endif /* CONFIG_BT_CAP_INITIATOR_UNICAST */
7677

78+
#if defined(CONFIG_BT_CAP_HANDOVER)
79+
void bt_cap_common_set_handover_active(void)
80+
{
81+
atomic_set_bit(active_proc.proc_state_flags, BT_CAP_COMMON_PROC_STATE_HANDOVER);
82+
}
83+
84+
bool bt_cap_common_handover_is_active(void)
85+
{
86+
return atomic_test_bit(active_proc.proc_state_flags, BT_CAP_COMMON_PROC_STATE_HANDOVER);
87+
}
88+
#endif /* CONFIG_BT_CAP_HANDOVER */
89+
7790
struct bt_conn *bt_cap_common_get_member_conn(enum bt_cap_set_type type,
7891
const union bt_cap_set_member *member)
7992
{

0 commit comments

Comments
 (0)