Skip to content

Commit bd0fc3c

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 2170353 commit bd0fc3c

File tree

12 files changed

+1008
-300
lines changed

12 files changed

+1008
-300
lines changed

include/zephyr/bluetooth/audio/cap.h

Lines changed: 46 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -888,6 +888,20 @@ struct bt_cap_handover_cb {
888888
void (*unicast_to_broadcast_complete)(int err, struct bt_conn *conn,
889889
struct bt_cap_unicast_group *unicast_group,
890890
struct bt_cap_broadcast_source *broadcast_source);
891+
892+
/**
893+
* @brief The broadcast to unicast handover procedure has finished
894+
*
895+
* @param err 0 if success else a negative errno value.
896+
* @param conn Pointer to the connection where the error occurred or NULL if local failure.
897+
* @param broadcast_source NULL if the broadcast sourced was deleted during the procedure,
898+
* else pointer to the broadcast sourced provided in the parameters.
899+
* @param unicast_group Pointer to newly created unicast group, or NULL in case of an
900+
* error happening before it was created.
901+
*/
902+
void (*broadcast_to_unicast_complete)(int err, struct bt_conn *conn,
903+
struct bt_cap_broadcast_source *broadcast_source,
904+
struct bt_cap_unicast_group *unicast_group);
891905
};
892906

893907
/**
@@ -932,26 +946,45 @@ int bt_cap_handover_unicast_to_broadcast(
932946
/** Parameters for bt_cap_handover_broadcast_to_unicast() */
933947
struct bt_cap_handover_broadcast_to_unicast_param {
934948
/**
935-
* @brief The source broadcast source with the streams.
949+
* @brief Parameters for stopping broadcast audio reception on acceptors
936950
*
937-
* The broadcast source will be stopped and deleted.
951+
* This parameter is optional as stopping the broadcast audio should automatically stop
952+
* broadcast audio reception on the acceptors. Omitting this parameter will rely on the CAP
953+
* acceptors timing out on the BIG once it is stopped. The timeout on the CAP acceptors will
954+
* be between @ref BT_ISO_SYNC_TIMEOUT_MIN and @ref BT_ISO_SYNC_TIMEOUT_MAX.
938955
*/
939-
struct bt_cap_broadcast_source *broadcast_source;
956+
struct bt_cap_commander_broadcast_reception_stop_param *reception_stop_param;
940957

941-
/** The type of the set. */
942-
enum bt_cap_set_type type;
958+
/** @brief Broadcast ID of the @p broadcast_source
959+
*
960+
* Ignored if @p reception_stop_param is not NULL.
961+
*/
962+
uint32_t broadcast_id;
943963

944-
/**
945-
* @brief The number of set members in @p members.
964+
/** @brief Advertising set ID of the @p broadcast_source
946965
*
947-
* This value shall match the number of streams in the
948-
* @p broadcast_source.
966+
* Ignored if @p reception_stop_param is not NULL.
967+
*/
968+
uint8_t adv_sid;
969+
970+
/** @brief Advertising type of the advertising address of @p broadcast_source
949971
*
972+
* Ignored if @p reception_stop_param is not NULL.
950973
*/
951-
size_t count;
974+
uint8_t adv_type;
975+
976+
/**
977+
* @brief The source broadcast source with the streams.
978+
*
979+
* The broadcast source will be stopped and deleted.
980+
*/
981+
struct bt_cap_broadcast_source *broadcast_source;
982+
983+
/* Parameters for the unicast group to be created */
984+
struct bt_cap_unicast_group_param *unicast_group_param;
952985

953-
/** Coordinated or ad-hoc set members. */
954-
union bt_cap_set_member **members;
986+
/* Parameters for starting the unicast audio */
987+
struct bt_cap_unicast_audio_start_param *unicast_start_param;
955988
};
956989

957990
/**
@@ -963,13 +996,11 @@ struct bt_cap_handover_broadcast_to_unicast_param {
963996
* @kconfig_dep{CONFIG_BT_CAP_HANDOVER}
964997
*
965998
* @param[in] param The parameters for the handover.
966-
* @param[out] unicast_group The resulting broadcast source.
967999
*
9681000
* @return 0 on success or negative error value on failure.
9691001
*/
9701002
int bt_cap_handover_broadcast_to_unicast(
971-
const struct bt_cap_handover_broadcast_to_unicast_param *param,
972-
struct bt_bap_unicast_group **unicast_group);
1003+
const struct bt_cap_handover_broadcast_to_unicast_param *param);
9731004

9741005
/** Callback structure for CAP procedures */
9751006
struct bt_cap_commander_cb {

subsys/bluetooth/audio/bap_unicast_client.c

Lines changed: 35 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -147,8 +147,7 @@ static int unicast_client_ep_set_metadata(struct bt_bap_ep *ep, void *data, uint
147147
static int unicast_client_ep_set_codec_cfg(struct bt_bap_ep *ep, uint8_t id, uint16_t cid,
148148
uint16_t vid, void *data, uint8_t len,
149149
struct bt_audio_codec_cfg *codec_cfg);
150-
static int unicast_client_ep_start(struct bt_bap_ep *ep,
151-
struct net_buf_simple *buf);
150+
static int unicast_client_ep_start(struct bt_bap_ep *ep, struct net_buf_simple *buf);
152151

153152
static int unicast_client_ase_discover(struct bt_conn *conn, uint16_t start_handle);
154153

@@ -160,8 +159,7 @@ static void unicast_client_ep_set_status(struct bt_bap_ep *ep, struct net_buf_si
160159
static int unicast_client_send_start(struct bt_bap_ep *ep)
161160
{
162161
if (ep->receiver_ready != true || ep->dir != BT_AUDIO_DIR_SOURCE) {
163-
LOG_DBG("Invalid ep %p %u %s",
164-
ep, ep->receiver_ready, bt_audio_dir_str(ep->dir));
162+
LOG_DBG("Invalid ep %p %u %s", ep, ep->receiver_ready, bt_audio_dir_str(ep->dir));
165163

166164
return -EINVAL;
167165
}
@@ -181,8 +179,7 @@ static int unicast_client_send_start(struct bt_bap_ep *ep)
181179

182180
err = unicast_client_ep_start(ep, buf);
183181
if (err != 0) {
184-
LOG_DBG("unicast_client_ep_start failed: %d",
185-
err);
182+
LOG_DBG("unicast_client_ep_start failed: %d", err);
186183

187184
return err;
188185
}
@@ -199,8 +196,7 @@ static int unicast_client_send_start(struct bt_bap_ep *ep)
199196

200197
static void unicast_client_ep_idle_state(struct bt_bap_ep *ep);
201198

202-
static struct bt_bap_stream *audio_stream_by_ep_id(const struct bt_conn *conn,
203-
uint8_t id)
199+
static struct bt_bap_stream *audio_stream_by_ep_id(const struct bt_conn *conn, uint8_t id)
204200
{
205201
#if CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 0 || CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 0
206202
const uint8_t conn_index = bt_conn_index(conn);
@@ -343,8 +339,8 @@ static void unicast_client_ep_iso_connected(struct bt_bap_ep *ep)
343339
return;
344340
}
345341

346-
LOG_DBG("stream %p ep %p dir %s receiver_ready %u",
347-
stream, ep, bt_audio_dir_str(ep->dir), ep->receiver_ready);
342+
LOG_DBG("stream %p ep %p dir %s receiver_ready %u", stream, ep, bt_audio_dir_str(ep->dir),
343+
ep->receiver_ready);
348344

349345
#if defined(CONFIG_BT_BAP_DEBUG_STREAM_SEQ_NUM)
350346
/* reset sequence number */
@@ -1561,10 +1557,10 @@ static uint8_t unicast_client_cp_notify(struct bt_conn *conn,
15611557
ase_rsp = net_buf_simple_pull_mem(&buf, sizeof(*ase_rsp));
15621558

15631559
LOG_DBG("op %s (0x%02x) id 0x%02x code %s (0x%02x) "
1564-
"reason %s (0x%02x)", bt_ascs_op_str(rsp->op), rsp->op,
1565-
ase_rsp->id, bt_ascs_rsp_str(ase_rsp->code),
1566-
ase_rsp->code, bt_ascs_reason_str(ase_rsp->reason),
1567-
ase_rsp->reason);
1560+
"reason %s (0x%02x)",
1561+
bt_ascs_op_str(rsp->op), rsp->op, ase_rsp->id,
1562+
bt_ascs_rsp_str(ase_rsp->code), ase_rsp->code,
1563+
bt_ascs_reason_str(ase_rsp->reason), ase_rsp->reason);
15681564

15691565
stream = audio_stream_by_ep_id(conn, ase_rsp->id);
15701566
if (stream == NULL) {
@@ -1983,7 +1979,6 @@ int bt_bap_unicast_client_ep_qos(struct bt_bap_ep *ep, struct net_buf_simple *bu
19831979

19841980
req = net_buf_simple_add(buf, sizeof(*req));
19851981
req->ase = ep->status.id;
1986-
/* TODO: don't hardcode CIG and CIS, they should come from ISO */
19871982
req->cig = conn_iso->info.unicast.cig_id;
19881983
req->cis = conn_iso->info.unicast.cis_id;
19891984
sys_put_le24(qos->interval, req->interval);
@@ -2278,7 +2273,7 @@ static void unicast_client_ep_reset(struct bt_conn *conn, uint8_t reason)
22782273
}
22792274

22802275
static void bt_bap_qos_cfg_to_cig_param(struct bt_iso_cig_param *cig_param,
2281-
const struct bt_bap_unicast_group *group)
2276+
const struct bt_bap_unicast_group *group)
22822277
{
22832278
cig_param->framing = group->cig_param.framing;
22842279
cig_param->c_to_p_interval = group->cig_param.c_to_p_interval;
@@ -2380,8 +2375,7 @@ static int bt_audio_cig_reconfigure(struct bt_bap_unicast_group *group)
23802375
return 0;
23812376
}
23822377

2383-
static void audio_stream_qos_cleanup(const struct bt_conn *conn,
2384-
struct bt_bap_unicast_group *group)
2378+
static void audio_stream_qos_cleanup(const struct bt_conn *conn, struct bt_bap_unicast_group *group)
23852379
{
23862380
struct bt_bap_stream *stream;
23872381

@@ -2500,8 +2494,7 @@ static void unicast_client_qos_cfg_to_iso_qos(struct bt_bap_iso *iso,
25002494
}
25012495

25022496
static void unicast_group_set_iso_stream_param(struct bt_bap_unicast_group *group,
2503-
struct bt_bap_iso *iso,
2504-
struct bt_bap_qos_cfg *qos,
2497+
struct bt_bap_iso *iso, struct bt_bap_qos_cfg *qos,
25052498
enum bt_audio_dir dir)
25062499
{
25072500
/* Store the stream Codec QoS in the bap_iso */
@@ -2673,14 +2666,12 @@ static void unicast_group_free(struct bt_bap_unicast_group *group)
26732666

26742667
static int stream_param_check(const struct bt_bap_unicast_group_stream_param *param)
26752668
{
2676-
CHECKIF(param->stream == NULL)
2677-
{
2669+
CHECKIF(param->stream == NULL) {
26782670
LOG_DBG("param->stream is NULL");
26792671
return -EINVAL;
26802672
}
26812673

2682-
CHECKIF(param->qos == NULL)
2683-
{
2674+
CHECKIF(param->qos == NULL) {
26842675
LOG_DBG("param->qos is NULL");
26852676
return -EINVAL;
26862677
}
@@ -2690,8 +2681,7 @@ static int stream_param_check(const struct bt_bap_unicast_group_stream_param *pa
26902681
return -EALREADY;
26912682
}
26922683

2693-
CHECKIF(bt_audio_verify_qos(param->qos) != BT_BAP_ASCS_REASON_NONE)
2694-
{
2684+
CHECKIF(bt_audio_verify_qos(param->qos) != BT_BAP_ASCS_REASON_NONE) {
26952685
LOG_DBG("Invalid QoS");
26962686
return -EINVAL;
26972687
}
@@ -2703,8 +2693,7 @@ static int stream_pair_param_check(const struct bt_bap_unicast_group_stream_pair
27032693
{
27042694
int err;
27052695

2706-
CHECKIF(param->rx_param == NULL && param->tx_param == NULL)
2707-
{
2696+
CHECKIF(param->rx_param == NULL && param->tx_param == NULL) {
27082697
LOG_DBG("Invalid stream parameters");
27092698
return -EINVAL;
27102699
}
@@ -2875,13 +2864,12 @@ static bool valid_unicast_group_param(struct bt_bap_unicast_group *unicast_group
28752864
}
28762865

28772866
int bt_bap_unicast_group_create(struct bt_bap_unicast_group_param *param,
2878-
struct bt_bap_unicast_group **out_unicast_group)
2867+
struct bt_bap_unicast_group **out_unicast_group)
28792868
{
28802869
struct bt_bap_unicast_group *unicast_group;
28812870
int err;
28822871

2883-
CHECKIF(out_unicast_group == NULL)
2884-
{
2872+
CHECKIF(out_unicast_group == NULL) {
28852873
LOG_DBG("out_unicast_group is NULL");
28862874
return -EINVAL;
28872875
}
@@ -3030,17 +3018,16 @@ int bt_bap_unicast_group_reconfig(struct bt_bap_unicast_group *unicast_group,
30303018
}
30313019

30323020
int bt_bap_unicast_group_add_streams(struct bt_bap_unicast_group *unicast_group,
3033-
struct bt_bap_unicast_group_stream_pair_param params[],
3034-
size_t num_param)
3021+
struct bt_bap_unicast_group_stream_pair_param params[],
3022+
size_t num_param)
30353023
{
30363024
struct bt_bap_stream *tmp_stream;
30373025
size_t total_stream_cnt;
30383026
struct bt_iso_cig *cig;
30393027
size_t num_added;
30403028
int err;
30413029

3042-
CHECKIF(unicast_group == NULL)
3043-
{
3030+
CHECKIF(unicast_group == NULL) {
30443031
LOG_DBG("unicast_group is NULL");
30453032
return -EINVAL;
30463033
}
@@ -3050,14 +3037,12 @@ int bt_bap_unicast_group_add_streams(struct bt_bap_unicast_group *unicast_group,
30503037
return -EINVAL;
30513038
}
30523039

3053-
CHECKIF(params == NULL)
3054-
{
3040+
CHECKIF(params == NULL) {
30553041
LOG_DBG("params is NULL");
30563042
return -EINVAL;
30573043
}
30583044

3059-
CHECKIF(num_param == 0)
3060-
{
3045+
CHECKIF(num_param == 0) {
30613046
LOG_DBG("num_param is 0");
30623047
return -EINVAL;
30633048
}
@@ -3126,8 +3111,7 @@ int bt_bap_unicast_group_delete(struct bt_bap_unicast_group *unicast_group)
31263111
{
31273112
struct bt_bap_stream *stream;
31283113

3129-
CHECKIF(unicast_group == NULL)
3130-
{
3114+
CHECKIF(unicast_group == NULL) {
31313115
LOG_DBG("unicast_group is NULL");
31323116
return -EINVAL;
31333117
}
@@ -3776,8 +3760,7 @@ static bool any_ases_found(const struct unicast_client *client)
37763760
return true;
37773761
}
37783762

3779-
static uint8_t unicast_client_ase_discover_cb(struct bt_conn *conn,
3780-
const struct bt_gatt_attr *attr,
3763+
static uint8_t unicast_client_ase_discover_cb(struct bt_conn *conn, const struct bt_gatt_attr *attr,
37813764
struct bt_gatt_discover_params *discover)
37823765
{
37833766
struct unicast_client *client;
@@ -4357,38 +4340,36 @@ static uint8_t unicast_client_read_func(struct bt_conn *conn, uint8_t err,
43574340
LOG_DBG("pac #%u/%u", i + 1, rsp->num_pac);
43584341

43594342
if (buf->len < sizeof(*pac_codec)) {
4360-
LOG_ERR("Malformed PAC: remaining len %u expected %zu",
4361-
buf->len, sizeof(*pac_codec));
4343+
LOG_ERR("Malformed PAC: remaining len %u expected %zu", buf->len,
4344+
sizeof(*pac_codec));
43624345
break;
43634346
}
43644347

43654348
pac_codec = net_buf_simple_pull_mem(buf, sizeof(*pac_codec));
43664349

43674350
if (buf->len < sizeof(*cc)) {
4368-
LOG_ERR("Malformed PAC: remaining len %u expected %zu",
4369-
buf->len, sizeof(*cc));
4351+
LOG_ERR("Malformed PAC: remaining len %u expected %zu", buf->len,
4352+
sizeof(*cc));
43704353
break;
43714354
}
43724355

43734356
cc = net_buf_simple_pull_mem(buf, sizeof(*cc));
43744357
if (buf->len < cc->len) {
4375-
LOG_ERR("Malformed PAC: remaining len %u expected %zu",
4376-
buf->len, cc->len);
4358+
LOG_ERR("Malformed PAC: remaining len %u expected %zu", buf->len, cc->len);
43774359
break;
43784360
}
43794361

43804362
cc_ltv = net_buf_simple_pull_mem(buf, cc->len);
43814363

43824364
if (buf->len < sizeof(*meta)) {
4383-
LOG_ERR("Malformed PAC: remaining len %u expected %zu",
4384-
buf->len, sizeof(*meta));
4365+
LOG_ERR("Malformed PAC: remaining len %u expected %zu", buf->len,
4366+
sizeof(*meta));
43854367
break;
43864368
}
43874369

43884370
meta = net_buf_simple_pull_mem(buf, sizeof(*meta));
43894371
if (buf->len < meta->len) {
4390-
LOG_ERR("Malformed PAC: remaining len %u expected %u",
4391-
buf->len, meta->len);
4372+
LOG_ERR("Malformed PAC: remaining len %u expected %u", buf->len, meta->len);
43924373
break;
43934374
}
43944375

@@ -4429,8 +4410,7 @@ static uint8_t unicast_client_read_func(struct bt_conn *conn, uint8_t err,
44294410
return BT_GATT_ITER_STOP;
44304411
}
44314412

4432-
static uint8_t unicast_client_pac_discover_cb(struct bt_conn *conn,
4433-
const struct bt_gatt_attr *attr,
4413+
static uint8_t unicast_client_pac_discover_cb(struct bt_conn *conn, const struct bt_gatt_attr *attr,
44344414
struct bt_gatt_discover_params *discover)
44354415
{
44364416
struct unicast_client *client = &uni_cli_insts[bt_conn_index(conn)];

0 commit comments

Comments
 (0)