Skip to content

Commit 18fc2e3

Browse files
committed
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 <emil.gydesen@nordicsemi.no>
1 parent 136eef9 commit 18fc2e3

File tree

5 files changed

+137
-14
lines changed

5 files changed

+137
-14
lines changed

doc/zephyr.doxyfile.in

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,8 @@ ALIASES = "kconfig{1}=\c \1" \
286286
"kconfig_dep{1}=\attention Available only when the following Kconfig option is enabled: \kconfig{\1}." \
287287
"kconfig_dep{2}=\attention Available only when the following Kconfig options are enabled: \kconfig{\1}, \kconfig{\2}." \
288288
"kconfig_dep{3}=\attention Available only when the following Kconfig options are enabled: \kconfig{\1}, \kconfig{\2}, \kconfig{\3}." \
289+
"kconfig_dep{4}=\attention Available only when the following Kconfig options are enabled: \kconfig{\1}, \kconfig{\2}, \kconfig{\3}, \kconfig{\4}." \
290+
"kconfig_dep{5}=\attention Available only when the following Kconfig options are enabled: \kconfig{\1}, \kconfig{\2}, \kconfig{\3}, \kconfig{\4}, \kconfig{\5}." \
289291
"funcprops=\par \"Function properties (list may not be complete)\"" \
290292
"reschedule=\qualifier reschedule" \
291293
"sleep=\qualifier sleep" \

include/zephyr/bluetooth/audio/bap.h

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1577,6 +1577,32 @@ int bt_bap_unicast_group_add_streams(struct bt_bap_unicast_group *unicast_group,
15771577
*/
15781578
int bt_bap_unicast_group_delete(struct bt_bap_unicast_group *unicast_group);
15791579

1580+
/** Callback function for bt_bap_unicast_group_foreach_stream()
1581+
*
1582+
* @param stream The audio stream
1583+
* @param user_data User data
1584+
*
1585+
* @retval true Stop iterating.
1586+
* @retval false Continue iterating.
1587+
*/
1588+
typedef bool (*bt_bap_unicast_group_foreach_stream_func_t)(struct bt_bap_stream *stream,
1589+
void *user_data);
1590+
1591+
/**
1592+
* @brief Iterate through all streams in a unicast group
1593+
*
1594+
* @param unicast_group The unicast group
1595+
* @param func The callback function
1596+
* @param user_data User specified data that sent to the callback function
1597+
*
1598+
* @retval 0 Success (even if no streams exists in the group).
1599+
* @retval -ECANCELED Iteration was stopped by the callback function before complete.
1600+
* @retval -EINVAL @p unicast_group or @p func were NULL.
1601+
*/
1602+
int bt_bap_unicast_group_foreach_stream(struct bt_bap_unicast_group *unicast_group,
1603+
bt_bap_unicast_group_foreach_stream_func_t func,
1604+
void *user_data);
1605+
15801606
/** Unicast Client callback structure */
15811607
struct bt_bap_unicast_client_cb {
15821608
/**

include/zephyr/bluetooth/audio/cap.h

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -639,21 +639,24 @@ int bt_cap_initiator_broadcast_get_base(struct bt_cap_broadcast_source *broadcas
639639

640640
/** Parameters for bt_cap_initiator_unicast_to_broadcast() */
641641
struct bt_cap_unicast_to_broadcast_param {
642+
/** The type of the set. */
643+
enum bt_cap_set_type type;
644+
642645
/** The source unicast group with the streams. */
643646
struct bt_bap_unicast_group *unicast_group;
644647

645648
/**
646649
* @brief Whether or not to encrypt the streams.
647650
*
648-
* If set to true, then the broadcast code in @p broadcast_code
649-
* will be used to encrypt the streams.
651+
* If set to true, then the broadcast code in
652+
* @p bt_cap_unicast_to_broadcast_param.broadcast_code will be used to encrypt the streams.
650653
*/
651654
bool encrypt;
652655

653656
/**
654657
* @brief 16-octet broadcast code.
655658
*
656-
* Only valid if @p encrypt is true.
659+
* Only valid if @p bt_cap_unicast_to_broadcast_param.encrypt is true.
657660
*
658661
* If the value is a string or a the value is less than 16 octets,
659662
* the remaining octets shall be 0.
@@ -671,10 +674,7 @@ struct bt_cap_unicast_to_broadcast_param {
671674
* The streams in the unicast group will be stopped and the unicast group
672675
* will be deleted. This can only be done for source streams.
673676
*
674-
* @note @kconfig{CONFIG_BT_CAP_INITIATOR},
675-
* @kconfig{CONFIG_BT_BAP_UNICAST_CLIENT} and
676-
* @kconfig{CONFIG_BT_BAP_BROADCAST_SOURCE} must be enabled for this function
677-
* to be enabled.
677+
* @kconfig_dep{CONFIG_BT_CAP_INITIATOR,CONFIG_BT_CAP_COMMANDER,CONFIG_BT_BAP_BROADCAST_ASSISTANT,CONFIG_BT_BAP_BROADCAST_SOURCE,CONFIG_BT_BAP_UNICAST_CLIENT}
678678
*
679679
* @param param The parameters for the handover.
680680
* @param source The resulting broadcast source.
@@ -715,10 +715,7 @@ struct bt_cap_broadcast_to_unicast_param {
715715
* The streams in the broadcast source will be stopped and the broadcast source
716716
* will be deleted.
717717
*
718-
* @note @kconfig{CONFIG_BT_CAP_INITIATOR},
719-
* @kconfig{CONFIG_BT_BAP_UNICAST_CLIENT} and
720-
* @kconfig{CONFIG_BT_BAP_BROADCAST_SOURCE} must be enabled for this function
721-
* to be enabled.
718+
* @kconfig_dep{CONFIG_BT_CAP_INITIATOR,CONFIG_BT_BAP_UNICAST_CLIENT,CONFIG_BT_BAP_BROADCAST_SOURCE}
722719
*
723720
* @param[in] param The parameters for the handover.
724721
* @param[out] unicast_group The resulting broadcast source.

subsys/bluetooth/audio/bap_unicast_client.c

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3136,6 +3136,33 @@ int bt_bap_unicast_group_delete(struct bt_bap_unicast_group *unicast_group)
31363136
return 0;
31373137
}
31383138

3139+
int bt_bap_unicast_group_foreach_stream(struct bt_bap_unicast_group *unicast_group,
3140+
bt_bap_unicast_group_foreach_stream_func_t func,
3141+
void *user_data)
3142+
{
3143+
struct bt_bap_stream *stream, *next;
3144+
3145+
if (unicast_group == NULL) {
3146+
LOG_DBG("unicast_group is NULL");
3147+
return -EINVAL;
3148+
}
3149+
3150+
if (func == NULL) {
3151+
LOG_DBG("func is NULL");
3152+
return -EINVAL;
3153+
}
3154+
3155+
SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&unicast_group->streams, stream, next, _node) {
3156+
const bool stop = func(stream, user_data);
3157+
3158+
if (stop) {
3159+
return -ECANCELED;
3160+
}
3161+
}
3162+
3163+
return 0;
3164+
}
3165+
31393166
int bt_bap_unicast_client_config(struct bt_bap_stream *stream,
31403167
const struct bt_audio_codec_cfg *codec_cfg)
31413168
{

subsys/bluetooth/audio/cap_initiator.c

Lines changed: 74 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2244,13 +2244,82 @@ void bt_cap_initiator_released(struct bt_cap_stream *cap_stream)
22442244

22452245
#endif /* CONFIG_BT_BAP_UNICAST_CLIENT */
22462246

2247-
#if defined(CONFIG_BT_BAP_BROADCAST_SOURCE) && defined(CONFIG_BT_BAP_UNICAST_CLIENT)
2247+
#if defined(CONFIG_BT_CAP_COMMANDER) && defined(CONFIG_BT_BAP_BROADCAST_SOURCE) && \
2248+
defined(CONFIG_BT_BAP_UNICAST_CLIENT) && defined(CONFIG_BT_BAP_BROADCAST_ASSISTANT)
2249+
2250+
static bool valid_unicast_to_broadcast_param(const struct bt_cap_unicast_to_broadcast_param *param)
2251+
{
2252+
const struct bt_bap_unicast_group *unicast_group;
2253+
2254+
if (param == NULL) {
2255+
LOG_DBG("param is NULL");
2256+
return false;
2257+
}
2258+
2259+
unicast_group = param->unicast_group;
2260+
if (unicast_group == NULL) {
2261+
LOG_DBG("param->unicast_group is NULL");
2262+
return false;
2263+
}
2264+
2265+
if (unicast_group->cig == NULL) {
2266+
LOG_DBG("param->unicast_group is not configured");
2267+
return false;
2268+
}
2269+
2270+
/**
2271+
* 1) Get all sink streams in the streaming state from unicast group
2272+
* 2) If number of sink streams exceed the number of broadcast source streams supported
2273+
return error
2274+
* 3) If number of unique metadata configurations exceed number of subgroups supported
2275+
return error
2276+
* 4) Check if remote device supports broadcast before doing anything
2277+
* 5) Release all sink streams with bt_cap_initiator_unicast_audio_stop
2278+
* 6) Once completed, call bt_cap_initiator_broadcast_audio_start
2279+
* 7) Call handover callback once completed
2280+
*/
2281+
2282+
return true;
2283+
}
22482284

22492285
int bt_cap_initiator_unicast_to_broadcast(
22502286
const struct bt_cap_unicast_to_broadcast_param *param,
22512287
struct bt_cap_broadcast_source **source)
22522288
{
2253-
return -ENOSYS;
2289+
struct bt_cap_unicast_audio_stop_param stop_param = {0};
2290+
int err;
2291+
2292+
if (source == NULL) {
2293+
LOG_DBG("source is NULL");
2294+
return -EINVAL;
2295+
}
2296+
2297+
if (!valid_unicast_to_broadcast_param(param)) {
2298+
return -EINVAL;
2299+
}
2300+
2301+
if (bt_cap_common_test_and_set_proc_active()) {
2302+
LOG_DBG("A CAP procedure is already in progress");
2303+
2304+
return -EBUSY;
2305+
}
2306+
2307+
stop_param.type = param->type;
2308+
stop_param.release = true;
2309+
/* TODO: Populate array of streams
2310+
* Since input is a BAP group, how do we ensure they are CAP streams?
2311+
*/
2312+
2313+
err = bt_cap_initiator_unicast_audio_stop(&stop_param);
2314+
if (err != 0) {
2315+
LOG_DBG("Failed to stop unicast audio: %d", err);
2316+
2317+
bt_cap_common_clear_active_proc();
2318+
2319+
return -ENOEXEC;
2320+
}
2321+
2322+
return 0;
22542323
}
22552324

22562325
int bt_cap_initiator_broadcast_to_unicast(const struct bt_cap_broadcast_to_unicast_param *param,
@@ -2259,4 +2328,6 @@ int bt_cap_initiator_broadcast_to_unicast(const struct bt_cap_broadcast_to_unica
22592328
return -ENOSYS;
22602329
}
22612330

2262-
#endif /* CONFIG_BT_BAP_BROADCAST_SOURCE && CONFIG_BT_BAP_UNICAST_CLIENT */
2331+
#endif /* CONFIG_BT_CAP_COMMANDER && CONFIG_BT_BAP_BROADCAST_SOURCE && \
2332+
* CONFIG_BT_BAP_UNICAST_CLIENT && CONFIG_BT_BAP_BROADCAST_ASSISTANT \
2333+
*/

0 commit comments

Comments
 (0)