Skip to content

Commit

Permalink
Bluetooth: CAP: Commander Reception start procedure
Browse files Browse the repository at this point in the history
Add the CAP commander reception start procedure which starts reception
on one or more CAP acceptors

Signed-off-by: Andries Kruithof <[email protected]>
  • Loading branch information
kruithofa committed Feb 29, 2024
1 parent 4f34a41 commit 44daaaf
Show file tree
Hide file tree
Showing 4 changed files with 255 additions and 1 deletion.
12 changes: 12 additions & 0 deletions include/zephyr/bluetooth/audio/cap.h
Original file line number Diff line number Diff line change
Expand Up @@ -721,6 +721,18 @@ struct bt_cap_commander_cb {
void (*volume_offset_changed)(struct bt_conn *conn, int err);
#endif /* CONFIG_BT_VCP_VOL_CTLR_VOCS */
#endif /* CONFIG_BT_VCP_VOL_CTLR */

/**
* @brief Callback for bt_cap_commander_broadcast_reception_start().
*
* @param conn Pointer to the connection where the error
* occurred. NULL if @p err is 0 or if cancelled by
* bt_cap_initiator_unucast_audio_cancel()
* @param err 0 on success, BT_GATT_ERR() with a
* specific ATT (BT_ATT_ERR_*) error code or -ECANCELED if cancelled
* by bt_cap_initiator_unicast_audio_cancel().
*/
void (*broadcast_reception_start)(struct bt_conn *conn, int err);
};

/**
Expand Down
234 changes: 233 additions & 1 deletion subsys/bluetooth/audio/cap_commander.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,21 @@ LOG_MODULE_REGISTER(bt_cap_commander, CONFIG_BT_CAP_COMMANDER_LOG_LEVEL);

#include "common/bt_str.h"

static void cap_commander_unicast_audio_proc_complete(void);

static const struct bt_cap_commander_cb *cap_cb;

int bt_cap_commander_register_cb(const struct bt_cap_commander_cb *cb)
{
CHECKIF(cb == NULL) {
LOG_DBG("cb is NULL");

return -EINVAL;
}

CHECKIF(cap_cb != NULL) {
LOG_DBG("callbacks already registered");

return -EALREADY;
}

Expand Down Expand Up @@ -76,17 +80,240 @@ int bt_cap_commander_discover(struct bt_conn *conn)
return bt_cap_common_discover(conn, cap_commander_discover_complete);
}

static struct bt_bap_broadcast_assistant_cb broadcast_assistant_cb;
static bool ba_cb_registered;

static void cap_commander_ba_add_src_cb(struct bt_conn *conn, int err)
{
struct bt_cap_common_proc *active_proc = bt_cap_common_get_active_proc();
struct bt_bap_broadcast_assistant_add_src_param add_src_param = {0};


LOG_DBG("conn %p", (void *)conn);

if (!bt_cap_common_conn_in_active_proc(conn)) {

/* State change happened outside of a procedure; ignore */
return;
}

if (err != 0) {
LOG_DBG("Failed to add source: %d", err);
bt_cap_common_abort_proc(conn, err);
} else {
active_proc->proc_done_cnt++;

LOG_DBG("Conn %p broadcast source added (%zu/%zu streams done)", (void *)conn,
active_proc->proc_done_cnt, active_proc->proc_cnt);
}

if (bt_cap_common_proc_is_aborted()) {
if (bt_cap_common_proc_all_handled()) {
cap_commander_unicast_audio_proc_complete();
}

return;
}

if (!bt_cap_common_proc_is_done()) {
const struct bt_cap_commander_proc_param *proc_param;

proc_param = &active_proc->proc_param.commander[active_proc->proc_done_cnt];
conn = proc_param->conn;

conn = proc_param->conn;
bt_addr_le_copy(&add_src_param.addr, &proc_param->broadcast_reception_start.addr);
add_src_param.adv_sid = proc_param->broadcast_reception_start.adv_sid;
add_src_param.broadcast_id = proc_param->broadcast_reception_start.broadcast_id;
add_src_param.pa_interval = proc_param->broadcast_reception_start.pa_interval;
add_src_param.num_subgroups = proc_param->broadcast_reception_start.num_subgroups;
add_src_param.subgroups = proc_param->broadcast_reception_start.subgroups;

active_proc->proc_initiated_cnt++;
err = bt_bap_broadcast_assistant_add_src(conn, &add_src_param);

if (err != 0) {
LOG_DBG("Failed to perform broadcast reception start for conn %p: %d",
(void *)conn, err);
bt_cap_common_abort_proc(conn, err);
cap_commander_unicast_audio_proc_complete();
}

} else {
cap_commander_unicast_audio_proc_complete();
}
}

static int cap_commander_register_ba_cb(void)
{
int err = 0;

bt_bap_broadcast_assistant_register_cb(&broadcast_assistant_cb);
if (err != 0) {
LOG_DBG("Failed to register broadcast assistant callbacks: %d", err);

return -ENOEXEC;
}

ba_cb_registered = true;

return 0;
}

static bool valid_broadcast_reception_start_param(
const struct bt_cap_commander_broadcast_reception_start_param *param)
{
CHECKIF(param == NULL) {
LOG_DBG("param is NULL");
return false;
}

CHECKIF(param->count == 0) {
LOG_DBG("Invalid param->count: %u", param->count);
return false;
}

CHECKIF(param->count > CONFIG_BT_MAX_CONN) {
LOG_DBG("param->count (%zu) is larger than CONFIG_BT_MAX_CONN (%d)", param->count,
CONFIG_BT_MAX_CONN);
return false;
}

CHECKIF(param->param == NULL) {
LOG_DBG("param->param is NULL");
return false;
}

for (size_t i = 0; i < param->count; i++) {
const struct bt_cap_commander_broadcast_reception_start_member_param *start_param =
&param->param[i];
const union bt_cap_set_member *member = &param->param[i].member;
const struct bt_cap_common_client *client =
bt_cap_common_get_client(param->type, member);

if (client == NULL) {
LOG_DBG("Invalid param->param[%zu].member", i);
return false;
}

for (size_t j = 0U; j < i; j++) {
const union bt_cap_set_member *other = &param->param[j].member;

if (other == member) {
LOG_DBG("param->members[%zu] (%p) is duplicated by "
"param->members[%zu] (%p)",
j, other, i, member);
return false;
}
}

CHECKIF(start_param->num_subgroups == 0) {
LOG_DBG("param->param[%d]->num_subgroups is 0", i);
return false;
}

CHECKIF(start_param->subgroups == NULL) {
LOG_DBG("param->param[%d]->subgroup is NULL", i);
return false;
}
}

return true;
}

int bt_cap_commander_broadcast_reception_start(
const struct bt_cap_commander_broadcast_reception_start_param *param)
{
return -ENOSYS;
const struct bt_cap_commander_proc_param *proc_param;
struct bt_cap_common_proc *active_proc;
struct bt_conn *conn;
struct bt_bap_broadcast_assistant_add_src_param add_src_param = {0};
int err;

if (bt_cap_common_proc_is_active()) {
LOG_DBG("A CAP procedure is already in progress");

return -EBUSY;
}

if (!valid_broadcast_reception_start_param(param)) {
return -EINVAL;
}

bt_cap_common_start_proc(BT_CAP_COMMON_PROC_TYPE_BROADCAST_RECEPTION_START, param->count);

broadcast_assistant_cb.add_src = cap_commander_ba_add_src_cb;
if (!ba_cb_registered && cap_commander_register_ba_cb() != 0) {
LOG_DBG("Failed to register VCP callbacks");

return -ENOEXEC;
}

active_proc = bt_cap_common_get_active_proc();

for (size_t i = 0U; i < param->count; i++) {
const struct bt_cap_commander_broadcast_reception_start_member_param
*member_param = &param->param[i];
struct bt_conn *member_conn =
bt_cap_common_get_member_conn(param->type, &member_param->member);

if (member_conn == NULL) {
LOG_DBG("Invalid param->members[%zu]", i);

return -EINVAL;
}

/* Store the necessary parameters as we cannot assume that the supplied parameters
* are kept valid
* TODO: consider putting this into a function
*/
active_proc->proc_param.commander[i].conn = member_conn;
bt_addr_le_copy(
&active_proc->proc_param.commander[i].broadcast_reception_start.addr,
&member_param->addr);
active_proc->proc_param.commander[i].broadcast_reception_start.adv_sid =
member_param->adv_sid;
active_proc->proc_param.commander[i].broadcast_reception_start.broadcast_id =
member_param->broadcast_id;
active_proc->proc_param.commander[i].broadcast_reception_start.pa_interval =
member_param->pa_interval;
active_proc->proc_param.commander[i].broadcast_reception_start.num_subgroups =
member_param->num_subgroups;
active_proc->proc_param.commander[i].broadcast_reception_start.subgroups =
member_param->subgroups;
}

active_proc->proc_initiated_cnt++;

proc_param = &active_proc->proc_param.commander[0];

conn = proc_param->conn;
bt_addr_le_copy(&add_src_param.addr, &proc_param->broadcast_reception_start.addr);
add_src_param.adv_sid = proc_param->broadcast_reception_start.adv_sid;
add_src_param.broadcast_id = proc_param->broadcast_reception_start.broadcast_id;
add_src_param.pa_interval = proc_param->broadcast_reception_start.pa_interval;
add_src_param.num_subgroups = proc_param->broadcast_reception_start.num_subgroups;
add_src_param.subgroups = proc_param->broadcast_reception_start.subgroups;

/* TODO: what to do if we are modifying a source that has already been added? */
err = bt_bap_broadcast_assistant_add_src(conn, &add_src_param);

if (err != 0) {
LOG_DBG("Failed to start broadcast reception for conn %p: %d",
(void *)conn, err);

return -ENOEXEC;
}

return 0;
}

int bt_cap_commander_broadcast_reception_stop(
const struct bt_cap_commander_broadcast_reception_stop_param *param)
{
return -ENOSYS;
}

static void cap_commander_unicast_audio_proc_complete(void)
{
struct bt_cap_common_proc *active_proc = bt_cap_common_get_active_proc();
Expand Down Expand Up @@ -123,6 +350,11 @@ static void cap_commander_unicast_audio_proc_complete(void)
break;
#endif /* CONFIG_BT_VCP_VOL_CTLR_VOCS */
#endif /* CONFIG_BT_VCP_VOL_CTLR */
case BT_CAP_COMMON_PROC_TYPE_BROADCAST_RECEPTION_START:
if (cap_cb->broadcast_reception_start != NULL) {
cap_cb->broadcast_reception_start(failed_conn, err);
}
break;
case BT_CAP_COMMON_PROC_TYPE_NONE:
default:
__ASSERT(false, "Invalid proc_type: %u", proc_type);
Expand Down
1 change: 1 addition & 0 deletions subsys/bluetooth/audio/cap_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ static bool active_proc_is_commander(void)
case BT_CAP_COMMON_PROC_TYPE_VOLUME_CHANGE:
case BT_CAP_COMMON_PROC_TYPE_VOLUME_OFFSET_CHANGE:
case BT_CAP_COMMON_PROC_TYPE_VOLUME_MUTE_CHANGE:
case BT_CAP_COMMON_PROC_TYPE_BROADCAST_RECEPTION_START:
return true;
default:
return false;
Expand Down
9 changes: 9 additions & 0 deletions subsys/bluetooth/audio/cap_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ enum bt_cap_common_proc_type {
BT_CAP_COMMON_PROC_TYPE_START,
BT_CAP_COMMON_PROC_TYPE_UPDATE,
BT_CAP_COMMON_PROC_TYPE_STOP,
BT_CAP_COMMON_PROC_TYPE_BROADCAST_RECEPTION_START,
BT_CAP_COMMON_PROC_TYPE_VOLUME_CHANGE,
BT_CAP_COMMON_PROC_TYPE_VOLUME_OFFSET_CHANGE,
BT_CAP_COMMON_PROC_TYPE_VOLUME_MUTE_CHANGE,
Expand Down Expand Up @@ -85,6 +86,14 @@ struct bt_cap_commander_proc_param {
struct bt_vocs *vocs;
} change_offset;
#endif /* CONFIG_BT_VCP_VOL_CTLR_VOCS */
struct {
bt_addr_le_t addr;
uint8_t adv_sid;
uint32_t broadcast_id;
uint16_t pa_interval;
uint8_t num_subgroups;
struct bt_bap_bass_subgroup *subgroups;
} broadcast_reception_start;

/* TODO Add other procedures */
};
Expand Down

0 comments on commit 44daaaf

Please sign in to comment.