Skip to content

Commit e71460c

Browse files
Thalleyfabiobaltieri
authored andcommitted
Bluetooth: Audio: Only allow receiver to send start command
Only the receiver of the audio is allowed to send the receiver start ready command. Furthermore, this removes the automated transition to the streaming state on the server, as the server now shall call bt_audio_stream_start to put the stream into the streaming state. Signed-off-by: Emil Gydesen <[email protected]>
1 parent 1e0f36e commit e71460c

File tree

5 files changed

+122
-64
lines changed

5 files changed

+122
-64
lines changed

include/zephyr/bluetooth/audio/audio.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1937,6 +1937,17 @@ int bt_audio_stream_disable(struct bt_audio_stream *stream);
19371937
* This procedure is used by a unicast client or unicast server to make a
19381938
* stream start streaming.
19391939
*
1940+
* For the unicast client, this will connect the CIS for the stream before
1941+
* sending the start command.
1942+
*
1943+
* For the unicast server, this will put a @ref BT_AUDIO_DIR_SINK stream into
1944+
* the streaming state if the CIS is connected (initialized by the unicast
1945+
* client). If the CIS is not connected yet, the stream will go into the
1946+
* streaming state as soon as the CIS is connected.
1947+
* @ref BT_AUDIO_DIR_SOURCE streams will go into the streaming state when the
1948+
* unicast client sends the Receiver Start Ready operation, which will trigger
1949+
* the @ref bt_audio_unicast_server_cb.start() callback.
1950+
*
19401951
* This shall only be called for unicast streams.
19411952
* Broadcast sinks will always be started once synchronized, and broadcast
19421953
* source streams shall be started with bt_audio_broadcast_source_start().

samples/bluetooth/unicast_audio_server/src/main.c

Lines changed: 65 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,9 @@ static struct bt_codec lc3_codec =
3838

3939
static struct bt_conn *default_conn;
4040
static struct k_work_delayable audio_send_work;
41-
static struct bt_audio_stream streams[CONFIG_BT_ASCS_ASE_SNK_COUNT + CONFIG_BT_ASCS_ASE_SRC_COUNT];
41+
static struct bt_audio_stream sink_streams[CONFIG_BT_ASCS_ASE_SNK_COUNT];
4242
static struct bt_audio_source {
43-
struct bt_audio_stream *stream;
43+
struct bt_audio_stream stream;
4444
uint16_t seq_num;
4545
uint16_t max_sdu;
4646
size_t len_to_send;
@@ -72,7 +72,7 @@ static const struct bt_data ad[] = {
7272
static uint16_t get_and_incr_seq_num(const struct bt_audio_stream *stream)
7373
{
7474
for (size_t i = 0U; i < configured_source_stream_count; i++) {
75-
if (stream == source_streams[i].stream) {
75+
if (stream == &source_streams[i].stream) {
7676
return source_streams[i].seq_num++;
7777
}
7878
}
@@ -190,7 +190,7 @@ static void audio_timer_timeout(struct k_work *work)
190190
* data going to the server)
191191
*/
192192
for (size_t i = 0; i < configured_source_stream_count; i++) {
193-
struct bt_audio_stream *stream = source_streams[i].stream;
193+
struct bt_audio_stream *stream = &source_streams[i].stream;
194194

195195
buf = net_buf_alloc(&tx_pool, K_FOREVER);
196196
net_buf_reserve(buf, BT_ISO_CHAN_SEND_RESERVE);
@@ -217,13 +217,41 @@ static void audio_timer_timeout(struct k_work *work)
217217
k_work_schedule(&audio_send_work, K_MSEC(1000U));
218218
}
219219

220-
static struct bt_audio_stream *stream_alloc(void)
220+
static enum bt_audio_dir stream_dir(const struct bt_audio_stream *stream)
221221
{
222-
for (size_t i = 0; i < ARRAY_SIZE(streams); i++) {
223-
struct bt_audio_stream *stream = &streams[i];
222+
for (size_t i = 0U; i < ARRAY_SIZE(source_streams); i++) {
223+
if (stream == &source_streams[i].stream) {
224+
return BT_AUDIO_DIR_SOURCE;
225+
}
226+
}
224227

225-
if (!stream->conn) {
226-
return stream;
228+
for (size_t i = 0U; i < ARRAY_SIZE(sink_streams); i++) {
229+
if (stream == &sink_streams[i]) {
230+
return BT_AUDIO_DIR_SINK;
231+
}
232+
}
233+
234+
__ASSERT(false, "Invalid stream %p", stream);
235+
return 0;
236+
}
237+
238+
static struct bt_audio_stream *stream_alloc(enum bt_audio_dir dir)
239+
{
240+
if (dir == BT_AUDIO_DIR_SOURCE) {
241+
for (size_t i = 0; i < ARRAY_SIZE(source_streams); i++) {
242+
struct bt_audio_stream *stream = &source_streams[i].stream;
243+
244+
if (!stream->conn) {
245+
return stream;
246+
}
247+
}
248+
} else {
249+
for (size_t i = 0; i < ARRAY_SIZE(sink_streams); i++) {
250+
struct bt_audio_stream *stream = &sink_streams[i];
251+
252+
if (!stream->conn) {
253+
return stream;
254+
}
227255
}
228256
}
229257

@@ -238,7 +266,7 @@ static int lc3_config(struct bt_conn *conn, const struct bt_audio_ep *ep, enum b
238266

239267
print_codec(codec);
240268

241-
*stream = stream_alloc();
269+
*stream = stream_alloc(dir);
242270
if (*stream == NULL) {
243271
printk("No streams available\n");
244272

@@ -248,7 +276,7 @@ static int lc3_config(struct bt_conn *conn, const struct bt_audio_ep *ep, enum b
248276
printk("ASE Codec Config stream %p\n", *stream);
249277

250278
if (dir == BT_AUDIO_DIR_SOURCE) {
251-
source_streams[configured_source_stream_count++].stream = *stream;
279+
configured_source_stream_count++;
252280
}
253281

254282
*pref = qos_pref;
@@ -284,7 +312,7 @@ static int lc3_qos(struct bt_audio_stream *stream, const struct bt_codec_qos *qo
284312
print_qos(qos);
285313

286314
for (size_t i = 0U; i < configured_source_stream_count; i++) {
287-
if (source_streams[i].stream == stream) {
315+
if (stream == &source_streams[i].stream) {
288316
source_streams[i].max_sdu = qos->sdu;
289317
break;
290318
}
@@ -335,8 +363,9 @@ static int lc3_start(struct bt_audio_stream *stream)
335363
printk("Start: stream %p\n", stream);
336364

337365
for (size_t i = 0U; i < configured_source_stream_count; i++) {
338-
if (source_streams[i].stream == stream) {
366+
if (stream == &source_streams[i].stream) {
339367
source_streams[i].seq_num = 0U;
368+
source_streams[i].len_to_send = 0U;
340369
break;
341370
}
342371
}
@@ -514,13 +543,29 @@ static void stream_stopped(struct bt_audio_stream *stream)
514543
k_work_cancel_delayable(&audio_send_work);
515544
}
516545

546+
547+
static void stream_enabled_cb(struct bt_audio_stream *stream)
548+
{
549+
/* The unicast server is responsible for starting sink ASEs after the
550+
* client has enabled them.
551+
*/
552+
if (stream_dir(stream) == BT_AUDIO_DIR_SINK) {
553+
const int err = bt_audio_stream_start(stream);
554+
555+
if (err != 0) {
556+
printk("Failed to start stream %p: %d", stream, err);
557+
}
558+
}
559+
}
560+
517561
static struct bt_audio_stream_ops stream_ops = {
518562
#if defined(CONFIG_LIBLC3)
519563
.recv = stream_recv_lc3_codec,
520564
#else
521565
.recv = stream_recv,
522566
#endif
523567
.stopped = stream_stopped,
568+
.enabled = stream_enabled_cb,
524569
};
525570

526571
static void connected(struct bt_conn *conn, uint8_t err)
@@ -674,8 +719,13 @@ void main(void)
674719
bt_pacs_cap_register(BT_AUDIO_DIR_SINK, &cap_sink);
675720
bt_pacs_cap_register(BT_AUDIO_DIR_SOURCE, &cap_source);
676721

677-
for (size_t i = 0; i < ARRAY_SIZE(streams); i++) {
678-
bt_audio_stream_cb_register(&streams[i], &stream_ops);
722+
for (size_t i = 0; i < ARRAY_SIZE(sink_streams); i++) {
723+
bt_audio_stream_cb_register(&sink_streams[i], &stream_ops);
724+
}
725+
726+
for (size_t i = 0; i < ARRAY_SIZE(source_streams); i++) {
727+
bt_audio_stream_cb_register(&source_streams[i].stream,
728+
&stream_ops);
679729
}
680730

681731
err = set_location();
@@ -726,7 +776,6 @@ void main(void)
726776
}
727777

728778
/* reset data */
729-
(void)memset(source_streams, 0, sizeof(source_streams));
730779
configured_source_stream_count = 0U;
731780
k_work_cancel_delayable_sync(&audio_send_work, &sync);
732781

subsys/bluetooth/audio/ascs.c

Lines changed: 31 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -567,50 +567,28 @@ static void ascs_iso_sent(struct bt_iso_chan *chan)
567567
}
568568
}
569569

570-
static int ase_stream_start(struct bt_audio_stream *stream)
571-
{
572-
int err = 0;
573-
574-
if (unicast_server_cb != NULL && unicast_server_cb->start != NULL) {
575-
err = unicast_server_cb->start(stream);
576-
} else {
577-
err = -ENOTSUP;
578-
}
579-
580-
ascs_ep_set_state(stream->ep, BT_AUDIO_EP_STATE_STREAMING);
581-
582-
return err;
583-
}
584-
585570
static void ascs_ep_iso_connected(struct bt_audio_ep *ep)
586571
{
587572
struct bt_audio_stream *stream;
588-
int err;
589573

590574
if (ep->status.state != BT_AUDIO_EP_STATE_ENABLING) {
591575
LOG_DBG("ep %p not in enabling state: %s",
592576
ep, bt_audio_ep_state_str(ep->status.state));
593577
return;
594578
}
595579

596-
if (ep->dir == BT_AUDIO_DIR_SOURCE && !ep->receiver_ready) {
597-
return;
598-
} else if (ep->dir == BT_AUDIO_DIR_SINK) {
599-
/* SINK ASEs can autonomously go into the streaming state if
600-
* the CIS is connected
601-
*/
602-
ascs_ep_set_state(ep, BT_AUDIO_EP_STATE_STREAMING);
603-
}
604-
605580
stream = ep->stream;
606581
if (stream == NULL) {
607582
LOG_ERR("No stream for ep %p", ep);
608583
return;
609584
}
610585

611-
err = ase_stream_start(stream);
612-
if (err) {
613-
LOG_ERR("Could not start stream %d", err);
586+
if (ep->dir == BT_AUDIO_DIR_SINK && ep->receiver_ready) {
587+
/* Source ASEs shall be ISO connected first, and then receive
588+
* the receiver start ready command to enter the streaming
589+
* state
590+
*/
591+
ascs_ep_set_state(ep, BT_AUDIO_EP_STATE_STREAMING);
614592
}
615593
}
616594

@@ -2000,6 +1978,7 @@ static ssize_t ascs_enable(struct bt_ascs *ascs, struct net_buf_simple *buf)
20001978
static void ase_start(struct bt_ascs_ase *ase)
20011979
{
20021980
struct bt_audio_ep *ep;
1981+
int err;
20031982

20041983
LOG_DBG("ase %p", ase);
20051984

@@ -2024,22 +2003,36 @@ static void ase_start(struct bt_ascs_ase *ase)
20242003
ascs_cp_rsp_add(ASE_ID(ase), BT_ASCS_START_OP,
20252004
BT_ASCS_RSP_INVALID_DIR, BT_ASCS_REASON_NONE);
20262005
return;
2006+
} else if (ep->iso->chan.state != BT_ISO_STATE_CONNECTED) {
2007+
/* An ASE may not go into the streaming state unless the CIS
2008+
* is connected
2009+
*/
2010+
LOG_WRN("Start failed: CIS not connected: %u",
2011+
ep->iso->chan.state);
2012+
ascs_cp_rsp_add(ASE_ID(ase), BT_ASCS_START_OP,
2013+
BT_ASCS_RSP_INVALID_ASE_STATE,
2014+
BT_ASCS_REASON_NONE);
2015+
return;
20272016
}
20282017

2029-
ep->receiver_ready = true;
2018+
if (unicast_server_cb != NULL && unicast_server_cb->start != NULL) {
2019+
err = unicast_server_cb->start(ep->stream);
2020+
} else {
2021+
err = -ENOTSUP;
2022+
}
20302023

2031-
if (ep->iso->chan.state == BT_ISO_STATE_CONNECTED) {
2032-
int err;
2024+
if (err) {
2025+
LOG_ERR("Start failed: %d", err);
2026+
ascs_cp_rsp_add(ASE_ID(ase), BT_ASCS_START_OP, err,
2027+
BT_ASCS_REASON_NONE);
20332028

2034-
err = ase_stream_start(ep->stream);
2035-
if (err) {
2036-
LOG_ERR("Start failed: %d", err);
2037-
ascs_cp_rsp_add(ASE_ID(ase), BT_ASCS_START_OP, err,
2038-
BT_ASCS_REASON_NONE);
2039-
return;
2040-
}
2029+
return;
20412030
}
20422031

2032+
ep->receiver_ready = true;
2033+
2034+
ascs_ep_set_state(ep, BT_AUDIO_EP_STATE_STREAMING);
2035+
20432036
ascs_cp_rsp_success(ASE_ID(ase), BT_ASCS_START_OP);
20442037
}
20452038

subsys/bluetooth/audio/endpoint.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ struct bt_audio_ep {
4444
struct bt_codec_qos_pref qos_pref;
4545
struct bt_audio_iso *iso;
4646

47-
/* FIXME: Replace with metastate */
47+
/* Used by the unicast server */
4848
bool receiver_ready;
4949

5050
/* TODO: Create a union to reduce memory usage */

subsys/bluetooth/audio/unicast_server.c

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
#include <zephyr/bluetooth/audio/audio.h>
1212

13+
#include "audio_iso.h"
1314
#include "pacs_internal.h"
1415
#include "endpoint.h"
1516

@@ -82,19 +83,23 @@ int bt_unicast_server_reconfig(struct bt_audio_stream *stream,
8283

8384
int bt_unicast_server_start(struct bt_audio_stream *stream)
8485
{
85-
int err;
86+
struct bt_audio_ep *ep = stream->ep;
8687

87-
if (unicast_server_cb != NULL && unicast_server_cb->start != NULL) {
88-
err = unicast_server_cb->start(stream);
89-
} else {
90-
err = -ENOTSUP;
91-
}
88+
if (ep->dir != BT_AUDIO_DIR_SINK) {
89+
LOG_DBG("Invalid operation for stream %p with dir %u",
90+
stream, ep->dir);
9291

93-
if (err != 0) {
94-
return err;
92+
return -EINVAL;
9593
}
9694

97-
ascs_ep_set_state(stream->ep, BT_AUDIO_EP_STATE_STREAMING);
95+
/* If ISO is connected to go streaming state,
96+
* else wait for ISO to be connected
97+
*/
98+
if (ep->iso->chan.state == BT_ISO_STATE_CONNECTED) {
99+
ascs_ep_set_state(ep, BT_AUDIO_EP_STATE_STREAMING);
100+
} else {
101+
ep->receiver_ready = true;
102+
}
98103

99104
return 0;
100105
}

0 commit comments

Comments
 (0)