Skip to content

Commit 5b858e6

Browse files
committed
Bluetooth: CAP: Implement broadcast to unicast handover
Implement the broadcast to unicast handover procedure, as per the Bluetooth CAP specificiation. Signed-off-by: Emil Gydesen <[email protected]>
1 parent b9ec859 commit 5b858e6

File tree

12 files changed

+969
-245
lines changed

12 files changed

+969
-245
lines changed

include/zephyr/bluetooth/audio/cap.h

Lines changed: 46 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -903,6 +903,20 @@ struct bt_cap_handover_cb {
903903
void (*unicast_to_broadcast_complete)(int err, struct bt_conn *conn,
904904
struct bt_cap_unicast_group *unicast_group,
905905
struct bt_cap_broadcast_source *broadcast_source);
906+
907+
/**
908+
* @brief The broadcast to unicast handover procedure has finished
909+
*
910+
* @param err 0 if success else a negative errno value.
911+
* @param conn Pointer to the connection where the error occurred or NULL if local failure.
912+
* @param broadcast_source NULL if the broadcast sourced was deleted during the procedure,
913+
* else pointer to the broadcast sourced provided in the parameters.
914+
* @param unicast_group Pointer to newly created unicast group, or NULL in case of an
915+
* error happening before it was created.
916+
*/
917+
void (*broadcast_to_unicast_complete)(int err, struct bt_conn *conn,
918+
struct bt_cap_broadcast_source *broadcast_source,
919+
struct bt_cap_unicast_group *unicast_group);
906920
};
907921

908922
/**
@@ -947,26 +961,45 @@ int bt_cap_handover_unicast_to_broadcast(
947961
/** Parameters for bt_cap_handover_broadcast_to_unicast() */
948962
struct bt_cap_handover_broadcast_to_unicast_param {
949963
/**
950-
* @brief The source broadcast source with the streams.
964+
* @brief Parameters for stopping broadcast audio reception on acceptors
951965
*
952-
* The broadcast source will be stopped and deleted.
966+
* This parameter is optional as stopping the broadcast audio should automatically stop
967+
* broadcast audio reception on the acceptors. Omitting this parameter will rely on the CAP
968+
* acceptors timing out on the BIG once it is stopped. The timeout on the CAP acceptors will
969+
* be between @ref BT_ISO_SYNC_TIMEOUT_MIN and @ref BT_ISO_SYNC_TIMEOUT_MAX.
953970
*/
954-
struct bt_cap_broadcast_source *broadcast_source;
971+
struct bt_cap_commander_broadcast_reception_stop_param *reception_stop_param;
955972

956-
/** The type of the set. */
957-
enum bt_cap_set_type type;
973+
/** @brief Broadcast ID of the @p broadcast_source
974+
*
975+
* Ignored if @p reception_stop_param is not NULL.
976+
*/
977+
uint32_t broadcast_id;
958978

959-
/**
960-
* @brief The number of set members in @p members.
979+
/** @brief Advertising set ID of the @p broadcast_source
961980
*
962-
* This value shall match the number of streams in the
963-
* @p broadcast_source.
981+
* Ignored if @p reception_stop_param is not NULL.
982+
*/
983+
uint8_t adv_sid;
984+
985+
/** @brief Advertising type of the advertising address of @p broadcast_source
964986
*
987+
* Ignored if @p reception_stop_param is not NULL.
965988
*/
966-
size_t count;
989+
uint8_t adv_type;
990+
991+
/**
992+
* @brief The source broadcast source with the streams.
993+
*
994+
* The broadcast source will be stopped and deleted.
995+
*/
996+
struct bt_cap_broadcast_source *broadcast_source;
997+
998+
/* Parameters for the unicast group to be created */
999+
struct bt_cap_unicast_group_param *unicast_group_param;
9671000

968-
/** Coordinated or ad-hoc set members. */
969-
union bt_cap_set_member **members;
1001+
/* Parameters for starting the unicast audio */
1002+
struct bt_cap_unicast_audio_start_param *unicast_start_param;
9701003
};
9711004

9721005
/**
@@ -978,13 +1011,11 @@ struct bt_cap_handover_broadcast_to_unicast_param {
9781011
* @kconfig_dep{CONFIG_BT_CAP_HANDOVER}
9791012
*
9801013
* @param[in] param The parameters for the handover.
981-
* @param[out] unicast_group The resulting broadcast source.
9821014
*
9831015
* @return 0 on success or negative error value on failure.
9841016
*/
9851017
int bt_cap_handover_broadcast_to_unicast(
986-
const struct bt_cap_handover_broadcast_to_unicast_param *param,
987-
struct bt_bap_unicast_group **unicast_group);
1018+
const struct bt_cap_handover_broadcast_to_unicast_param *param);
9881019

9891020
/** Callback structure for CAP procedures */
9901021
struct bt_cap_commander_cb {

subsys/bluetooth/audio/bap_unicast_client.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2039,7 +2039,6 @@ int bt_bap_unicast_client_ep_qos(struct bt_bap_ep *ep, struct net_buf_simple *bu
20392039

20402040
req = net_buf_simple_add(buf, sizeof(*req));
20412041
req->ase = ep->id;
2042-
/* TODO: don't hardcode CIG and CIS, they should come from ISO */
20432042
req->cig = conn_iso->info.unicast.cig_id;
20442043
req->cis = conn_iso->info.unicast.cis_id;
20452044
sys_put_le24(qos->interval, req->interval);

subsys/bluetooth/audio/cap_commander.c

Lines changed: 83 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -101,9 +101,6 @@ int bt_cap_commander_discover(struct bt_conn *conn)
101101
}
102102

103103
#if defined(CONFIG_BT_BAP_BROADCAST_ASSISTANT)
104-
static struct bt_bap_broadcast_assistant_cb broadcast_assistant_cb;
105-
static bool broadcast_assistant_cb_registered;
106-
107104
static void
108105
copy_broadcast_reception_start_param(struct bt_bap_broadcast_assistant_add_src_param *add_src_param,
109106
struct cap_broadcast_reception_start *start_param)
@@ -172,22 +169,6 @@ static void cap_commander_broadcast_assistant_add_src_cb(struct bt_conn *conn, i
172169
}
173170
}
174171

175-
static int cap_commander_register_broadcast_assistant_cb(void)
176-
{
177-
int err;
178-
179-
err = bt_bap_broadcast_assistant_register_cb(&broadcast_assistant_cb);
180-
if (err != 0) {
181-
LOG_DBG("Failed to register broadcast assistant callbacks: %d", err);
182-
183-
return -ENOEXEC;
184-
}
185-
186-
broadcast_assistant_cb_registered = true;
187-
188-
return 0;
189-
}
190-
191172
static bool valid_broadcast_reception_start_param(
192173
const struct bt_cap_commander_broadcast_reception_start_param *param)
193174
{
@@ -335,11 +316,7 @@ int cap_commander_broadcast_reception_start(
335316
struct bt_conn *conn;
336317
int err;
337318

338-
broadcast_assistant_cb.add_src = cap_commander_broadcast_assistant_add_src_cb;
339-
if (!broadcast_assistant_cb_registered) {
340-
err = cap_commander_register_broadcast_assistant_cb();
341-
__ASSERT(err == 0, "Failed to register broadcast assistant callbacks: %d", err);
342-
}
319+
cap_commander_register_broadcast_assistant_callbacks();
343320

344321
bt_cap_common_set_proc(BT_CAP_COMMON_PROC_TYPE_BROADCAST_RECEPTION_START, param->count);
345322

@@ -356,8 +333,6 @@ int cap_commander_broadcast_reception_start(
356333
if (member_conn == NULL) {
357334
LOG_DBG("Invalid param->members[%zu]", i);
358335

359-
bt_cap_common_clear_active_proc();
360-
361336
return -EINVAL;
362337
}
363338

@@ -389,8 +364,6 @@ int cap_commander_broadcast_reception_start(
389364
if (err != 0) {
390365
LOG_DBG("Failed to start broadcast reception for conn %p: %d", (void *)conn, err);
391366

392-
bt_cap_common_clear_active_proc();
393-
394367
return -ENOEXEC;
395368
}
396369

@@ -400,6 +373,8 @@ int cap_commander_broadcast_reception_start(
400373
int bt_cap_commander_broadcast_reception_start(
401374
const struct bt_cap_commander_broadcast_reception_start_param *param)
402375
{
376+
int err;
377+
403378
if (!valid_broadcast_reception_start_param(param)) {
404379
return -EINVAL;
405380
}
@@ -410,7 +385,12 @@ int bt_cap_commander_broadcast_reception_start(
410385
return -EBUSY;
411386
}
412387

413-
return cap_commander_broadcast_reception_start(param);
388+
err = cap_commander_broadcast_reception_start(param);
389+
if (err != 0) {
390+
bt_cap_common_clear_active_proc();
391+
}
392+
393+
return err;
414394
}
415395

416396
static void
@@ -436,6 +416,10 @@ static void cap_commander_broadcast_assistant_recv_state_cb(
436416
return;
437417
}
438418

419+
if (IS_ENABLED(CONFIG_BT_CAP_HANDOVER) && bt_cap_common_handover_is_active()) {
420+
bt_cap_handover_receive_state_updated(conn, state);
421+
}
422+
439423
if (bt_cap_common_conn_in_active_proc(conn) &&
440424
active_proc->proc_type == BT_CAP_COMMON_PROC_TYPE_BROADCAST_RECEPTION_STOP) {
441425

@@ -539,7 +523,7 @@ static void cap_commander_broadcast_assistant_mod_src_cb(struct bt_conn *conn, i
539523
}
540524
}
541525

542-
static bool valid_broadcast_reception_stop_param(
526+
bool bt_cap_commander_valid_broadcast_reception_stop_param(
543527
const struct bt_cap_commander_broadcast_reception_stop_param *param)
544528
{
545529
CHECKIF(param == NULL) {
@@ -607,7 +591,7 @@ static bool valid_broadcast_reception_stop_param(
607591
return true;
608592
}
609593

610-
int bt_cap_commander_broadcast_reception_stop(
594+
int cap_commander_broadcast_reception_stop(
611595
const struct bt_cap_commander_broadcast_reception_stop_param *param)
612596
{
613597
struct bt_bap_broadcast_assistant_mod_src_param mod_src_param = {0};
@@ -616,23 +600,7 @@ int bt_cap_commander_broadcast_reception_stop(
616600
struct bt_conn *conn;
617601
int err;
618602

619-
if (!valid_broadcast_reception_stop_param(param)) {
620-
return -EINVAL;
621-
}
622-
623-
if (bt_cap_common_test_and_set_proc_active()) {
624-
LOG_DBG("A CAP procedure is already in progress");
625-
626-
return -EBUSY;
627-
}
628-
629-
broadcast_assistant_cb.mod_src = cap_commander_broadcast_assistant_mod_src_cb;
630-
broadcast_assistant_cb.rem_src = cap_commander_broadcast_assistant_rem_src_cb;
631-
broadcast_assistant_cb.recv_state = cap_commander_broadcast_assistant_recv_state_cb;
632-
if (!broadcast_assistant_cb_registered) {
633-
err = cap_commander_register_broadcast_assistant_cb();
634-
__ASSERT(err == 0, "Failed to register broadcast assistant callbacks: %d", err);
635-
}
603+
cap_commander_register_broadcast_assistant_callbacks();
636604

637605
bt_cap_common_set_proc(BT_CAP_COMMON_PROC_TYPE_BROADCAST_RECEPTION_STOP, param->count);
638606

@@ -649,8 +617,6 @@ int bt_cap_commander_broadcast_reception_stop(
649617
if (member_conn == NULL) {
650618
LOG_DBG("Invalid param->member[%zu]", i);
651619

652-
bt_cap_common_clear_active_proc();
653-
654620
return -EINVAL;
655621
}
656622

@@ -678,14 +644,35 @@ int bt_cap_commander_broadcast_reception_stop(
678644
if (err != 0) {
679645
LOG_DBG("Failed to stop broadcast reception for conn %p: %d", (void *)conn, err);
680646

681-
bt_cap_common_clear_active_proc();
682-
683647
return -ENOEXEC;
684648
}
685649

686650
return 0;
687651
}
688652

653+
int bt_cap_commander_broadcast_reception_stop(
654+
const struct bt_cap_commander_broadcast_reception_stop_param *param)
655+
{
656+
int err;
657+
658+
if (!bt_cap_commander_valid_broadcast_reception_stop_param(param)) {
659+
return -EINVAL;
660+
}
661+
662+
if (bt_cap_common_test_and_set_proc_active()) {
663+
LOG_DBG("A CAP procedure is already in progress");
664+
665+
return -EBUSY;
666+
}
667+
668+
err = cap_commander_broadcast_reception_stop(param);
669+
if (err != 0) {
670+
bt_cap_common_clear_active_proc();
671+
}
672+
673+
return err;
674+
}
675+
689676
static void cap_commander_broadcast_assistant_set_broadcast_code_cb(struct bt_conn *conn, int err)
690677
{
691678
struct bt_cap_common_proc *active_proc = bt_cap_common_get_active_proc();
@@ -811,12 +798,7 @@ int bt_cap_commander_distribute_broadcast_code(
811798
return -EBUSY;
812799
}
813800

814-
broadcast_assistant_cb.broadcast_code =
815-
cap_commander_broadcast_assistant_set_broadcast_code_cb;
816-
if (!broadcast_assistant_cb_registered) {
817-
err = cap_commander_register_broadcast_assistant_cb();
818-
__ASSERT(err == 0, "Failed to register broadcast assistant callbacks: %d", err);
819-
}
801+
cap_commander_register_broadcast_assistant_callbacks();
820802

821803
bt_cap_common_set_proc(BT_CAP_COMMON_PROC_TYPE_DISTRIBUTE_BROADCAST_CODE, param->count);
822804

@@ -870,6 +852,26 @@ int bt_cap_commander_distribute_broadcast_code(
870852
return 0;
871853
}
872854

855+
void cap_commander_register_broadcast_assistant_callbacks(void)
856+
{
857+
static bool broadcast_assistant_cb_registered;
858+
859+
if (!broadcast_assistant_cb_registered) {
860+
static struct bt_bap_broadcast_assistant_cb broadcast_assistant_cb = {
861+
.add_src = cap_commander_broadcast_assistant_add_src_cb,
862+
.mod_src = cap_commander_broadcast_assistant_mod_src_cb,
863+
.rem_src = cap_commander_broadcast_assistant_rem_src_cb,
864+
.recv_state = cap_commander_broadcast_assistant_recv_state_cb,
865+
.broadcast_code = cap_commander_broadcast_assistant_set_broadcast_code_cb,
866+
};
867+
int err;
868+
869+
err = bt_bap_broadcast_assistant_register_cb(&broadcast_assistant_cb);
870+
__ASSERT(err == 0, "Failed to register broadcast assistant callbacks: %d", err);
871+
872+
broadcast_assistant_cb_registered = true;
873+
}
874+
}
873875
#endif /* CONFIG_BT_BAP_BROADCAST_ASSISTANT */
874876

875877
static void cap_commander_proc_complete(void)
@@ -884,13 +886,30 @@ static void cap_commander_proc_complete(void)
884886
proc_type = active_proc->proc_type;
885887

886888
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);
889+
if (proc_type == BT_CAP_COMMON_PROC_TYPE_BROADCAST_RECEPTION_START) {
890+
/* Complete unicast to broadcast handover procedure. At this point we do not
891+
* know if the remote device will attempt to use PAST or scan for itself, so
892+
* it's best to leave this up to the application layer
893+
*/
894+
895+
bt_cap_handover_complete();
896+
} else if (proc_type == BT_CAP_COMMON_PROC_TYPE_BROADCAST_RECEPTION_STOP) {
897+
if (err != 0) {
898+
bt_cap_handover_complete();
899+
} else {
900+
/* We've successfully stopped broadcast reception on all the
901+
* acceptors. We can now stop and delete the broadcast source before
902+
* starting the unicast audio
903+
*/
904+
err = bt_cap_handover_broadcast_reception_stopped();
905+
if (err != 0) {
906+
bt_cap_handover_complete();
907+
}
908+
}
909+
} else {
910+
__ASSERT(false, "invalid proc_type %d", proc_type);
911+
}
892912

893-
bt_cap_handover_proc_complete();
894913
return;
895914
}
896915

0 commit comments

Comments
 (0)