Skip to content

Commit bb3bab7

Browse files
Andries Kruithofhenrikbrixandersen
authored andcommitted
Bluetooth: Audio: implement the distribute broadcast code procedure
Implemenation of the distribute broadcast code CAP procedure, as well as unittesting Signed-off-by: Andries Kruithof <[email protected]>
1 parent 37fcadc commit bb3bab7

File tree

10 files changed

+500
-2
lines changed

10 files changed

+500
-2
lines changed

include/zephyr/bluetooth/audio/cap.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -820,6 +820,17 @@ struct bt_cap_commander_cb {
820820
* by bt_cap_commander_cancel().
821821
*/
822822
void (*broadcast_reception_stop)(struct bt_conn *conn, int err);
823+
/**
824+
* @brief Callback for bt_cap_commander_distribute_broadcast_code().
825+
*
826+
* @param conn Pointer to the connection where the error
827+
* occurred. NULL if @p err is 0 or if cancelled by
828+
* bt_cap_commander_cancel()
829+
* @param err 0 on success, BT_GATT_ERR() with a
830+
* specific ATT (BT_ATT_ERR_*) error code or -ECANCELED if cancelled
831+
* by bt_cap_commander_cancel().
832+
*/
833+
void (*distribute_broadcast_code)(struct bt_conn *conn, int err);
823834
#endif /* CONFIG_BT_BAP_BROADCAST_ASSISTANT */
824835
};
825836

subsys/bluetooth/audio/cap_commander.c

Lines changed: 181 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -671,10 +671,185 @@ int bt_cap_commander_broadcast_reception_stop(
671671
return 0;
672672
}
673673

674+
static void cap_commander_broadcast_assistant_set_broadcast_code_cb(struct bt_conn *conn, int err)
675+
{
676+
struct bt_cap_common_proc *active_proc = bt_cap_common_get_active_proc();
677+
678+
LOG_DBG("conn %p", (void *)conn);
679+
680+
if (!bt_cap_common_conn_in_active_proc(conn)) {
681+
/* State change happened outside of a procedure; ignore */
682+
return;
683+
}
684+
685+
if (err != 0) {
686+
LOG_DBG("Failed to distribute broadcast code: %d", err);
687+
688+
bt_cap_common_abort_proc(conn, err);
689+
} else {
690+
active_proc->proc_done_cnt++;
691+
692+
LOG_DBG("Conn %p broadcast code set (%zu/%zu done)", (void *)conn,
693+
active_proc->proc_done_cnt, active_proc->proc_cnt);
694+
}
695+
696+
if (bt_cap_common_proc_is_aborted()) {
697+
if (bt_cap_common_proc_all_handled()) {
698+
cap_commander_proc_complete();
699+
}
700+
701+
return;
702+
}
703+
704+
if (!bt_cap_common_proc_is_done()) {
705+
struct bt_cap_commander_proc_param *proc_param;
706+
707+
proc_param = &active_proc->proc_param.commander[active_proc->proc_done_cnt];
708+
conn = proc_param->conn;
709+
710+
active_proc->proc_initiated_cnt++;
711+
err = bt_bap_broadcast_assistant_set_broadcast_code(
712+
conn, proc_param->distribute_broadcast_code.src_id,
713+
proc_param->distribute_broadcast_code.broadcast_code);
714+
if (err != 0) {
715+
LOG_DBG("Failed to perform set broadcast code for conn %p: %d",
716+
(void *)conn, err);
717+
bt_cap_common_abort_proc(conn, err);
718+
cap_commander_proc_complete();
719+
}
720+
} else {
721+
cap_commander_proc_complete();
722+
}
723+
}
724+
725+
static bool valid_distribute_broadcast_code_param(
726+
const struct bt_cap_commander_distribute_broadcast_code_param *param)
727+
{
728+
CHECKIF(param == NULL) {
729+
LOG_DBG("param is NULL");
730+
return false;
731+
}
732+
733+
CHECKIF(param->count == 0) {
734+
LOG_DBG("Invalid param->count: %zu", param->count);
735+
return false;
736+
}
737+
738+
CHECKIF(param->count > CONFIG_BT_MAX_CONN) {
739+
LOG_DBG("param->count (%zu) is larger than CONFIG_BT_MAX_CONN (%d)", param->count,
740+
CONFIG_BT_MAX_CONN);
741+
return false;
742+
}
743+
744+
CHECKIF(param->param == NULL) {
745+
LOG_DBG("param->param is NULL");
746+
return false;
747+
}
748+
749+
for (size_t i = 0; i < param->count; i++) {
750+
const union bt_cap_set_member *member = &param->param[i].member;
751+
const struct bt_conn *member_conn =
752+
bt_cap_common_get_member_conn(param->type, member);
753+
754+
if (member == NULL) {
755+
LOG_DBG("param->param[%zu].member is NULL", i);
756+
return false;
757+
}
758+
759+
if (member_conn == NULL) {
760+
LOG_DBG("Invalid param->param[%zu].member", i);
761+
return false;
762+
}
763+
764+
for (size_t j = 0U; j < i; j++) {
765+
const union bt_cap_set_member *other = &param->param[j].member;
766+
const struct bt_conn *other_conn =
767+
bt_cap_common_get_member_conn(param->type, other);
768+
769+
if (other_conn == member_conn) {
770+
LOG_DBG("param->param[%zu].member.member (%p) is duplicated by "
771+
"param->member[%zu].member.member (%p)",
772+
j, (void *)other_conn, i, (void *)member_conn);
773+
return false;
774+
}
775+
}
776+
}
777+
778+
return true;
779+
}
780+
674781
int bt_cap_commander_distribute_broadcast_code(
675782
const struct bt_cap_commander_distribute_broadcast_code_param *param)
676783
{
677-
return -ENOSYS;
784+
struct bt_cap_commander_proc_param *proc_param;
785+
struct bt_cap_common_proc *active_proc;
786+
struct bt_conn *conn;
787+
int err;
788+
789+
if (bt_cap_common_proc_is_active()) {
790+
LOG_DBG("A CAP procedure is already in progress");
791+
792+
return -EBUSY;
793+
}
794+
795+
if (!valid_distribute_broadcast_code_param(param)) {
796+
return -EINVAL;
797+
}
798+
799+
bt_cap_common_start_proc(BT_CAP_COMMON_PROC_TYPE_DISTRIBUTE_BROADCAST_CODE, param->count);
800+
801+
broadcast_assistant_cb.broadcast_code =
802+
cap_commander_broadcast_assistant_set_broadcast_code_cb;
803+
if (!broadcast_assistant_cb_registered &&
804+
cap_commander_register_broadcast_assistant_cb() != 0) {
805+
LOG_DBG("Failed to register broadcast assistant callbacks");
806+
807+
return -ENOEXEC;
808+
}
809+
810+
active_proc = bt_cap_common_get_active_proc();
811+
812+
for (size_t i = 0U; i < param->count; i++) {
813+
const struct bt_cap_commander_distribute_broadcast_code_member_param *member_param =
814+
&param->param[i];
815+
struct bt_cap_commander_proc_param *stored_param;
816+
struct bt_conn *member_conn =
817+
bt_cap_common_get_member_conn(param->type, &member_param->member);
818+
819+
if (member_conn == NULL) {
820+
LOG_DBG("Invalid param->member[%zu]", i);
821+
822+
return -EINVAL;
823+
}
824+
825+
/* Store the necessary parameters as we cannot assume that the
826+
* supplied parameters are kept valid
827+
*/
828+
stored_param = &active_proc->proc_param.commander[i];
829+
stored_param->conn = member_conn;
830+
stored_param->distribute_broadcast_code.src_id = member_param->src_id;
831+
memcpy(stored_param->distribute_broadcast_code.broadcast_code,
832+
param->broadcast_code, BT_ISO_BROADCAST_CODE_SIZE);
833+
}
834+
835+
active_proc->proc_initiated_cnt++;
836+
837+
proc_param = &active_proc->proc_param.commander[0];
838+
839+
conn = proc_param->conn;
840+
841+
err = bt_bap_broadcast_assistant_set_broadcast_code(
842+
conn, proc_param->distribute_broadcast_code.src_id,
843+
proc_param->distribute_broadcast_code.broadcast_code);
844+
845+
if (err != 0) {
846+
LOG_DBG("Failed to start distribute broadcast code for conn %p: %d", (void *)conn,
847+
err);
848+
849+
return -ENOEXEC;
850+
}
851+
852+
return 0;
678853
}
679854

680855
#endif /* CONFIG_BT_BAP_BROADCAST_ASSISTANT */
@@ -740,6 +915,11 @@ static void cap_commander_proc_complete(void)
740915
cap_cb->broadcast_reception_stop(failed_conn, err);
741916
}
742917
break;
918+
case BT_CAP_COMMON_PROC_TYPE_DISTRIBUTE_BROADCAST_CODE:
919+
if (cap_cb->distribute_broadcast_code != NULL) {
920+
cap_cb->distribute_broadcast_code(failed_conn, err);
921+
}
922+
break;
743923
#endif /* CONFIG_BT_BAP_BROADCAST_ASSISTANT */
744924
case BT_CAP_COMMON_PROC_TYPE_NONE:
745925
default:

subsys/bluetooth/audio/cap_common.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,7 @@ static bool active_proc_is_commander(void)
164164
case BT_CAP_COMMON_PROC_TYPE_MICROPHONE_MUTE_CHANGE:
165165
case BT_CAP_COMMON_PROC_TYPE_BROADCAST_RECEPTION_START:
166166
case BT_CAP_COMMON_PROC_TYPE_BROADCAST_RECEPTION_STOP:
167+
case BT_CAP_COMMON_PROC_TYPE_DISTRIBUTE_BROADCAST_CODE:
167168
return true;
168169
default:
169170
return false;

subsys/bluetooth/audio/cap_internal.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ enum bt_cap_common_proc_type {
5151
BT_CAP_COMMON_PROC_TYPE_STOP,
5252
BT_CAP_COMMON_PROC_TYPE_BROADCAST_RECEPTION_START,
5353
BT_CAP_COMMON_PROC_TYPE_BROADCAST_RECEPTION_STOP,
54+
BT_CAP_COMMON_PROC_TYPE_DISTRIBUTE_BROADCAST_CODE,
5455
BT_CAP_COMMON_PROC_TYPE_VOLUME_CHANGE,
5556
BT_CAP_COMMON_PROC_TYPE_VOLUME_OFFSET_CHANGE,
5657
BT_CAP_COMMON_PROC_TYPE_VOLUME_MUTE_CHANGE,
@@ -109,6 +110,18 @@ struct cap_broadcast_reception_stop {
109110
uint8_t num_subgroups;
110111
struct bt_bap_bass_subgroup subgroups[CONFIG_BT_BAP_BASS_MAX_SUBGROUPS];
111112
};
113+
114+
/* Note that although the broadcast_code will be the same for all
115+
* we nevertheless store a separate copy for each sink, for
116+
* consistensy in the struct bt_cap_commander_proc_param
117+
* There is no memory savings by not having broadcast_code part of the
118+
* union: struct cap_broadcast_reception_start uses minimum 20 bytes
119+
* and struct cap_distribute_broadcast_code uses 17 bytes
120+
*/
121+
struct cap_distribute_broadcast_code {
122+
uint8_t src_id;
123+
uint8_t broadcast_code[BT_ISO_BROADCAST_CODE_SIZE];
124+
};
112125
#endif /* CONFIG_BT_BAP_BROADCAST_ASSISTANT */
113126

114127
struct bt_cap_commander_proc_param {
@@ -131,6 +144,7 @@ struct bt_cap_commander_proc_param {
131144
#if defined(CONFIG_BT_BAP_BROADCAST_ASSISTANT)
132145
struct cap_broadcast_reception_start broadcast_reception_start;
133146
struct cap_broadcast_reception_stop broadcast_reception_stop;
147+
struct cap_distribute_broadcast_code distribute_broadcast_code;
134148
#endif /* CONFIG_BT_BAP_BROADCAST_ASSISTANT */
135149
#if defined(CONFIG_BT_MICP_MIC_CTLR)
136150
struct {

tests/bluetooth/audio/cap_commander/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,5 @@ target_sources(testbinary
1919
src/test_vcp.c
2020
src/test_micp.c
2121
src/test_broadcast_reception.c
22+
src/test_distribute_broadcast_code.c
2223
)

tests/bluetooth/audio/cap_commander/include/cap_commander.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,5 +25,6 @@ DECLARE_FAKE_VOID_FUNC(mock_cap_commander_microphone_mute_changed_cb, struct bt_
2525
DECLARE_FAKE_VOID_FUNC(mock_cap_commander_microphone_gain_changed_cb, struct bt_conn *, int);
2626
DECLARE_FAKE_VOID_FUNC(mock_cap_commander_broadcast_reception_start_cb, struct bt_conn *, int);
2727
DECLARE_FAKE_VOID_FUNC(mock_cap_commander_broadcast_reception_stop_cb, struct bt_conn *, int);
28+
DECLARE_FAKE_VOID_FUNC(mock_cap_commander_distribute_broadcast_code_cb, struct bt_conn *, int);
2829

2930
#endif /* MOCKS_CAP_COMMANDER_H_ */

tests/bluetooth/audio/cap_commander/include/test_common.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66
* SPDX-License-Identifier: Apache-2.0
77
*/
88

9+
#define BROADCAST_CODE "BroadcastCode"
10+
#define RANDOM_SRC_ID 0x55
11+
912
void test_mocks_init(void);
1013
void test_mocks_cleanup(void);
1114

0 commit comments

Comments
 (0)