Skip to content

Commit e9c1be8

Browse files
Thalleynashif
authored andcommitted
Bluetooth: CAP: Add Initiator cancel procedure
Add function to cancel any current proecedure. This is useful in cases where the connection to one or more acceptors is lost or if some acceptor does not respond to our requests for whatever reason. Signed-off-by: Emil Gydesen <[email protected]>
1 parent 65c2f8e commit e9c1be8

File tree

2 files changed

+104
-60
lines changed

2 files changed

+104
-60
lines changed

include/zephyr/bluetooth/audio/cap.h

Lines changed: 39 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -78,21 +78,25 @@ struct bt_cap_initiator_cb {
7878
*
7979
* @param unicast_group The unicast group pointer supplied to
8080
* bt_cap_initiator_unicast_audio_start().
81-
* @param err 0 if success, else BT_GATT_ERR() with a
82-
* specific ATT (BT_ATT_ERR_*) error code.
81+
* @param err 0 if success, BT_GATT_ERR() with a
82+
* specific ATT (BT_ATT_ERR_*) error code or -ECANCELED if cancelled
83+
* by bt_cap_initiator_unicast_audio_cancel().
8384
* @param conn Pointer to the connection where the error
84-
* occurred. NULL if @p err is 0.
85+
* occurred. NULL if @p err is 0 or if cancelled by
86+
* bt_cap_initiator_unicast_audio_cancel()
8587
*/
8688
void (*unicast_start_complete)(struct bt_bap_unicast_group *unicast_group,
8789
int err, struct bt_conn *conn);
8890

8991
/**
9092
* @brief Callback for bt_cap_initiator_unicast_audio_update().
9193
*
92-
* @param err 0 if success, else BT_GATT_ERR() with a
93-
* specific ATT (BT_ATT_ERR_*) error code.
94+
* @param err 0 if success, BT_GATT_ERR() with a
95+
* specific ATT (BT_ATT_ERR_*) error code or -ECANCELED if cancelled
96+
* by bt_cap_initiator_unicast_audio_cancel().
9497
* @param conn Pointer to the connection where the error
95-
* occurred. NULL if @p err is 0.
98+
* occurred. NULL if @p err is 0 or if cancelled by
99+
* bt_cap_initiator_unicast_audio_cancel()
96100
*/
97101
void (*unicast_update_complete)(int err, struct bt_conn *conn);
98102

@@ -107,10 +111,12 @@ struct bt_cap_initiator_cb {
107111
*
108112
* @param unicast_group The unicast group pointer supplied to
109113
* bt_cap_initiator_unicast_audio_stop().
110-
* @param err 0 if success, else BT_GATT_ERR() with a
111-
* specific ATT (BT_ATT_ERR_*) error code.
114+
* @param err 0 if success, BT_GATT_ERR() with a
115+
* specific ATT (BT_ATT_ERR_*) error code or -ECANCELED if cancelled
116+
* by bt_cap_initiator_unicast_audio_cancel().
112117
* @param conn Pointer to the connection where the error
113-
* occurred. NULL if @p err is 0.
118+
* occurred. NULL if @p err is 0 or if cancelled by
119+
* bt_cap_initiator_unicast_audio_cancel()
114120
*/
115121
void (*unicast_stop_complete)(struct bt_bap_unicast_group *unicast_group,
116122
int err, struct bt_conn *conn);
@@ -269,6 +275,30 @@ int bt_cap_initiator_unicast_audio_update(const struct bt_cap_unicast_audio_upda
269275
*/
270276
int bt_cap_initiator_unicast_audio_stop(struct bt_bap_unicast_group *unicast_group);
271277

278+
/** @brief Cancel any current Common Audio Profile procedure
279+
*
280+
* This will stop the current procedure from continuing and making it possible to run a new
281+
* Common Audio Profile procedure.
282+
*
283+
* It is recommended to do this if any existing procedure take longer time than expected, which
284+
* could indicate a missing response from the Common Audio Profile Acceptor.
285+
*
286+
* This does not send any requests to any Common Audio Profile Acceptors involved with the current
287+
* procedure, and thus notifications from the Common Audio Profile Acceptors may arrive after this
288+
* has been called. It is thus recommended to either only use this if a procedure has stalled, or
289+
* wait a short while before starting any new Common Audio Profile procedure after this has been
290+
* called to avoid getting notifications from the cancelled procedure. The wait time depends on
291+
* the connection interval, the number of devices in the previous procedure and the behavior of the
292+
* Common Audio Profile Acceptors.
293+
*
294+
* The respective callbacks of the procedure will be called as part of this with the connection
295+
* pointer set to 0 and the err value set to -ECANCELED.
296+
*
297+
* @retval 0 on success
298+
* @retval -EALREADY if no procedure is active
299+
*/
300+
int bt_cap_initiator_unicast_audio_cancel(void);
301+
272302
struct bt_cap_initiator_broadcast_stream_param {
273303
/** Audio stream */
274304
struct bt_cap_stream *stream;

subsys/bluetooth/audio/cap_initiator.c

Lines changed: 65 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,13 @@ enum {
293293
CAP_UNICAST_PROC_STATE_FLAG_NUM,
294294
} cap_unicast_proc_state;
295295

296+
enum cap_unicast_proc_type {
297+
CAP_UNICAST_PROC_TYPE_NONE,
298+
CAP_UNICAST_PROC_TYPE_START,
299+
CAP_UNICAST_PROC_TYPE_UPDATE,
300+
CAP_UNICAST_PROC_TYPE_STOP,
301+
};
302+
296303
enum cap_unicast_subproc_type {
297304
CAP_UNICAST_SUBPROC_TYPE_NONE,
298305
CAP_UNICAST_SUBPROC_TYPE_CODEC_CONFIG,
@@ -311,6 +318,7 @@ struct cap_unicast_proc {
311318
size_t stream_initiated_cnt;
312319
/* Number of streams done with the procedure */
313320
size_t stream_done_cnt;
321+
enum cap_unicast_proc_type proc_type;
314322
enum cap_unicast_subproc_type subproc_type;
315323
int err;
316324
struct bt_conn *failed_conn;
@@ -809,22 +817,42 @@ static int cap_initiator_unicast_audio_configure(
809817
return 0;
810818
}
811819

812-
static void cap_initiator_unicast_audio_start_complete(void)
820+
static void cap_initiator_unicast_audio_proc_complete(void)
813821
{
814822
struct bt_bap_unicast_group *unicast_group;
823+
enum cap_unicast_proc_type proc_type;
815824
struct bt_conn *failed_conn;
816825
int err;
817826

818-
/* All streams in the procedure share the same unicast group, so we just
819-
* use the reference from the first stream
820-
*/
821-
unicast_group = (struct bt_bap_unicast_group *)active_proc.streams[0]->bap_stream.group;
827+
unicast_group = active_proc.unicast_group;
822828
failed_conn = active_proc.failed_conn;
823829
err = active_proc.err;
824-
830+
proc_type = active_proc.proc_type;
825831
(void)memset(&active_proc, 0, sizeof(active_proc));
826-
if (cap_cb != NULL && cap_cb->unicast_start_complete != NULL) {
827-
cap_cb->unicast_start_complete(unicast_group, err, failed_conn);
832+
833+
if (cap_cb == NULL) {
834+
return;
835+
}
836+
837+
switch (proc_type) {
838+
case CAP_UNICAST_PROC_TYPE_START:
839+
if (cap_cb->unicast_start_complete != NULL) {
840+
cap_cb->unicast_start_complete(unicast_group, err, failed_conn);
841+
}
842+
break;
843+
case CAP_UNICAST_PROC_TYPE_UPDATE:
844+
if (cap_cb->unicast_update_complete != NULL) {
845+
cap_cb->unicast_update_complete(err, failed_conn);
846+
}
847+
break;
848+
case CAP_UNICAST_PROC_TYPE_STOP:
849+
if (cap_cb->unicast_stop_complete != NULL) {
850+
cap_cb->unicast_stop_complete(unicast_group, err, failed_conn);
851+
}
852+
break;
853+
case CAP_UNICAST_PROC_TYPE_NONE:
854+
default:
855+
__ASSERT(false, "Invalid proc_type: %u", proc_type);
828856
}
829857
}
830858

@@ -847,6 +875,7 @@ int bt_cap_initiator_unicast_audio_start(const struct bt_cap_unicast_audio_start
847875
}
848876

849877
active_proc.unicast_group = unicast_group;
878+
active_proc.proc_type = CAP_UNICAST_PROC_TYPE_START;
850879

851880
return cap_initiator_unicast_audio_configure(param);
852881
}
@@ -886,7 +915,7 @@ void bt_cap_initiator_codec_configured(struct bt_cap_stream *cap_stream)
886915

887916
if (cap_proc_is_aborted()) {
888917
if (cap_proc_all_streams_handled()) {
889-
cap_initiator_unicast_audio_start_complete();
918+
cap_initiator_unicast_audio_proc_complete();
890919
}
891920

892921
return;
@@ -944,7 +973,7 @@ void bt_cap_initiator_codec_configured(struct bt_cap_stream *cap_stream)
944973
*/
945974
cap_abort_proc(conns[i], err);
946975
if (i == 0U) {
947-
cap_initiator_unicast_audio_start_complete();
976+
cap_initiator_unicast_audio_proc_complete();
948977
}
949978

950979
return;
@@ -979,7 +1008,7 @@ void bt_cap_initiator_qos_configured(struct bt_cap_stream *cap_stream)
9791008

9801009
if (cap_proc_is_aborted()) {
9811010
if (cap_proc_all_streams_handled()) {
982-
cap_initiator_unicast_audio_start_complete();
1011+
cap_initiator_unicast_audio_proc_complete();
9831012
}
9841013

9851014
return;
@@ -1006,7 +1035,7 @@ void bt_cap_initiator_qos_configured(struct bt_cap_stream *cap_stream)
10061035
*/
10071036
cap_abort_proc(bap_stream->conn, err);
10081037
if (i == 0U) {
1009-
cap_initiator_unicast_audio_start_complete();
1038+
cap_initiator_unicast_audio_proc_complete();
10101039
}
10111040

10121041
return;
@@ -1042,7 +1071,7 @@ void bt_cap_initiator_enabled(struct bt_cap_stream *cap_stream)
10421071

10431072
if (cap_proc_is_aborted()) {
10441073
if (cap_proc_all_streams_handled()) {
1045-
cap_initiator_unicast_audio_start_complete();
1074+
cap_initiator_unicast_audio_proc_complete();
10461075
}
10471076

10481077
return;
@@ -1065,7 +1094,7 @@ void bt_cap_initiator_enabled(struct bt_cap_stream *cap_stream)
10651094
* once all sent requests has completed
10661095
*/
10671096
cap_abort_proc(bap_stream->conn, err);
1068-
cap_initiator_unicast_audio_start_complete();
1097+
cap_initiator_unicast_audio_proc_complete();
10691098

10701099
return;
10711100
}
@@ -1108,24 +1137,10 @@ void bt_cap_initiator_started(struct bt_cap_stream *cap_stream)
11081137
* once all sent requests has completed
11091138
*/
11101139
cap_abort_proc(bap_stream->conn, err);
1111-
cap_initiator_unicast_audio_start_complete();
1140+
cap_initiator_unicast_audio_proc_complete();
11121141
}
11131142
} else {
1114-
cap_initiator_unicast_audio_start_complete();
1115-
}
1116-
}
1117-
1118-
static void cap_initiator_unicast_audio_update_complete(void)
1119-
{
1120-
struct bt_conn *failed_conn;
1121-
int err;
1122-
1123-
failed_conn = active_proc.failed_conn;
1124-
err = active_proc.err;
1125-
1126-
(void)memset(&active_proc, 0, sizeof(active_proc));
1127-
if (cap_cb != NULL && cap_cb->unicast_update_complete != NULL) {
1128-
cap_cb->unicast_update_complete(err, failed_conn);
1143+
cap_initiator_unicast_audio_proc_complete();
11291144
}
11301145
}
11311146

@@ -1208,6 +1223,7 @@ int bt_cap_initiator_unicast_audio_update(const struct bt_cap_unicast_audio_upda
12081223
atomic_set_bit(active_proc.proc_state_flags,
12091224
CAP_UNICAST_PROC_STATE_ACTIVE);
12101225
active_proc.stream_cnt = count;
1226+
active_proc.proc_type = CAP_UNICAST_PROC_TYPE_UPDATE;
12111227

12121228
cap_set_subproc(CAP_UNICAST_SUBPROC_TYPE_META_UPDATE);
12131229

@@ -1242,6 +1258,20 @@ int bt_cap_initiator_unicast_audio_update(const struct bt_cap_unicast_audio_upda
12421258
return 0;
12431259
}
12441260

1261+
int bt_cap_initiator_unicast_audio_cancel(void)
1262+
{
1263+
if (!cap_proc_is_active() && !cap_proc_is_aborted()) {
1264+
LOG_DBG("No CAP procedure is in progress");
1265+
1266+
return -EALREADY;
1267+
}
1268+
1269+
cap_abort_proc(NULL, -ECANCELED);
1270+
cap_initiator_unicast_audio_proc_complete();
1271+
1272+
return 0;
1273+
}
1274+
12451275
void bt_cap_initiator_metadata_updated(struct bt_cap_stream *cap_stream)
12461276
{
12471277
if (!cap_stream_in_active_proc(cap_stream)) {
@@ -1265,30 +1295,13 @@ void bt_cap_initiator_metadata_updated(struct bt_cap_stream *cap_stream)
12651295
return;
12661296
} else if (cap_proc_is_aborted()) {
12671297
if (cap_proc_all_streams_handled()) {
1268-
cap_initiator_unicast_audio_update_complete();
1298+
cap_initiator_unicast_audio_proc_complete();
12691299
}
12701300

12711301
return;
12721302
}
12731303

1274-
cap_initiator_unicast_audio_update_complete();
1275-
}
1276-
1277-
static void cap_initiator_unicast_audio_stop_complete(void)
1278-
{
1279-
struct bt_bap_unicast_group *unicast_group;
1280-
struct bt_conn *failed_conn;
1281-
int err;
1282-
1283-
unicast_group = active_proc.unicast_group;
1284-
failed_conn = active_proc.failed_conn;
1285-
err = active_proc.err;
1286-
1287-
(void)memset(&active_proc, 0, sizeof(active_proc));
1288-
1289-
if (cap_cb != NULL && cap_cb->unicast_stop_complete != NULL) {
1290-
cap_cb->unicast_stop_complete(unicast_group, err, failed_conn);
1291-
}
1304+
cap_initiator_unicast_audio_proc_complete();
12921305
}
12931306

12941307
static bool can_release(const struct bt_bap_stream *bap_stream)
@@ -1343,6 +1356,7 @@ int bt_cap_initiator_unicast_audio_stop(struct bt_bap_unicast_group *unicast_gro
13431356
CAP_UNICAST_PROC_STATE_ACTIVE);
13441357
active_proc.stream_cnt = stream_cnt;
13451358
active_proc.unicast_group = unicast_group;
1359+
active_proc.proc_type = CAP_UNICAST_PROC_TYPE_STOP;
13461360

13471361
cap_set_subproc(CAP_UNICAST_SUBPROC_TYPE_RELEASE);
13481362

@@ -1404,13 +1418,13 @@ void bt_cap_initiator_released(struct bt_cap_stream *cap_stream)
14041418
return;
14051419
} else if (cap_proc_is_aborted()) {
14061420
if (cap_proc_all_streams_handled()) {
1407-
cap_initiator_unicast_audio_stop_complete();
1421+
cap_initiator_unicast_audio_proc_complete();
14081422
}
14091423

14101424
return;
14111425
}
14121426

1413-
cap_initiator_unicast_audio_stop_complete();
1427+
cap_initiator_unicast_audio_proc_complete();
14141428
}
14151429

14161430
#endif /* CONFIG_BT_BAP_UNICAST_CLIENT */

0 commit comments

Comments
 (0)