Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bluetooth: BAP: Unicast client Split start and connect #73032

Merged
merged 1 commit into from
Jun 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 34 additions & 15 deletions doc/connectivity/bluetooth/api/audio/shell/bap.rst
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ Commands
stream_qos : interval [framing] [latency] [pd] [sdu] [phy] [rtn]
qos : Send QoS configure for Unicast Group
enable : [context]
connect : Connect the CIS of the stream
stop
list
print_ase_info : Print ASE info for default connection
Expand Down Expand Up @@ -62,10 +63,8 @@ Commands
[extended <meta>]
[vendor <meta>]]
send : Send to Audio Stream [data]
start_sine : Start sending a LC3 encoded sine wave [all]
stop_sine : Stop sending a LC3 encoded sine wave [all]
recv_stats : Sets or gets the receive statistics reporting interval
in # of packets
bap_stats : Sets or gets the statistics reporting interval in # of
packets
set_location : <direction: sink, source> <location bitmask>
set_context : <direction: sink, source><context bitmask> <type:
supported, available>
Expand All @@ -80,19 +79,19 @@ Commands
"config","discover","idle/codec-configured/qos-configured","codec-configured"
"qos","config","codec-configured/qos-configured","qos-configured"
"enable","qos","qos-configured","enabling"
"[start]","enable","enabling","streaming"
"connect","qos/enable","qos-configured/enabling","qos-configured/enabling"
"[start]","enable/connect","enabling","streaming"
"disable","enable", "enabling/streaming","disabling"
"[stop]","disable","disabling","qos-configure/idle"
"release","config","any","releasing/codec-configure/idle"
"list","none","any","none"
"select_unicast","none","any","none"
"connect","discover","idle/codec-configured/qos-configured","codec-configured"
"send","enable","streaming","none"

Example Central
***************

Connect and establish a stream:
Connect and establish a sink stream:

.. code-block:: console

Expand All @@ -104,17 +103,22 @@ Connect and establish a stream:
uart:~$ bap config sink 0
uart:~$ bap qos
uart:~$ bap enable
uart:~$ bap connect

Or using connect command:
Connect and establish a source stream:

.. code-block:: console

uart:~$ bt init
uart:~$ bap init
uart:~$ bt connect <address>
uart:~$ gatt exchange-mtu
uart:~$ bap discover sink
uart:~$ bap connect sink 0
uart:~$ bap discover source
uart:~$ bap config source 0
uart:~$ bap qos
uart:~$ bap enable
uart:~$ bap connect
uart:~$ bap start
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Trying this against a Samsung earbud, the audio flows fine, but it already seems to start streaming after calling 'connect'

image

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your comment is for the Connect and establish a source stream when you are doing it on a sink stream. See the above steps for sink streams

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes... I see that now (was following the steps in the previous push that had config sink... all good... and approved :D


Disconnect and release:

Expand Down Expand Up @@ -479,8 +483,7 @@ parameters.
Enable
******

The :code:`enable` command attempts to enable the stream previously configured,
if the remote peer accepts then the ISO connection procedure is also initiated.
The :code:`enable` command attempts to enable the stream previously configured.

.. csv-table:: State Machine Transitions
:header: "Depends", "Allowed States", "Next States"
Expand All @@ -493,17 +496,33 @@ if the remote peer accepts then the ISO connection procedure is also initiated.
uart:~$ bap enable [context]
uart:~$ bap enable Media

Connect
*******

The :code:`connect` command attempts to connect the stream previously configured.
Sink streams will have to be started by the unicast server, and source streams will have to be
started by the unicast client.

.. csv-table:: State Machine Transitions
:header: "Depends", "Allowed States", "Next States"
:widths: auto

"qos/enable","qos-configured/enabling","qos-configured/enabling"

.. code-block:: console

uart:~$ bap connect

Start
*****

The :code:`start` command is only necessary when acting as a sink as it
indicates to the source the stack is ready to start receiving data.
The :code:`start` command is only necessary when starting a source stream.

.. csv-table:: State Machine Transitions
:header: "Depends", "Allowed States", "Next States"
:widths: auto

"enable","enabling","streaming"
"enable/connect","enabling","streaming"

.. code-block:: console

Expand Down
4 changes: 4 additions & 0 deletions doc/releases/migration-guide-3.7.rst
Original file line number Diff line number Diff line change
Expand Up @@ -447,6 +447,10 @@ Bluetooth Audio
This needs to be added to all instances of CAP discovery callback functions defined.
(:github:`72797`)

* :c:func:`bt_bap_stream_start` no longer connects the CIS. To connect the CIS,
the :c:func:`bt_bap_stream_connect` shall now be called before :c:func:`bt_bap_stream_start`.
(:github:`73032`)

* All occurrences of ``set_sirk`` have been changed to just ``sirk`` as the ``s`` in ``sirk`` stands
for set. (:github:`73413`)

Expand Down
41 changes: 32 additions & 9 deletions include/zephyr/bluetooth/audio/bap.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* @brief Header for Bluetooth BAP.
*
* Copyright (c) 2020 Bose Corporation
* Copyright (c) 2021-2023 Nordic Semiconductor ASA
* Copyright (c) 2021-2024 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
Expand Down Expand Up @@ -715,20 +715,43 @@ int bt_bap_stream_metadata(struct bt_bap_stream *stream, const uint8_t meta[], s
*/
int bt_bap_stream_disable(struct bt_bap_stream *stream);

/**
* @brief Connect unicast audio stream
*
* This procedure is used by a unicast client to connect the connected isochronous stream (CIS)
* associated with the audio stream. If two audio streams share a CIS, then this only needs to be
* done once for those streams. This can only be done for streams in the QoS configured or enabled
* states.
*
* The bt_bap_stream_ops.connected() callback will be called on the streams once this has finished.
*
* This shall only be called for unicast streams, and only as the unicast client
* (@kconfig{CONFIG_BT_BAP_UNICAST_CLIENT}).
*
* @param stream Stream object
*
* @retval 0 in case of success
* @retval -EINVAL if the stream, endpoint, ISO channel or connection is NULL
* @retval -EBADMSG if the stream or ISO channel is in an invalid state for connection
* @retval -EOPNOTSUPP if the role of the stream is not @ref BT_HCI_ROLE_CENTRAL
* @retval -EALREADY if the ISO channel is already connecting or connected
* @retval -EBUSY if another ISO channel is connecting
* @retval -ENOEXEC if otherwise rejected by the ISO layer
*/
int bt_bap_stream_connect(struct bt_bap_stream *stream);

/**
* @brief Start Audio Stream
*
* This procedure is used by a unicast client or unicast server to make a stream start streaming.
*
* For the unicast client, this will connect the CIS for the stream before
* sending the start command.
* For the unicast client, this will send the receiver start ready command to the unicast server for
* @ref BT_AUDIO_DIR_SOURCE ASEs. The CIS is required to be connected first by
* bt_bap_stream_connect() before the command can be sent.
*
* For the unicast server, this will put a @ref BT_AUDIO_DIR_SINK stream into the streaming state if
* the CIS is connected (initialized by the unicast client). If the CIS is not connected yet, the
* stream will go into the streaming state as soon as the CIS is connected.
* @ref BT_AUDIO_DIR_SOURCE streams will go into the streaming state when the unicast client sends
* the Receiver Start Ready operation, which will trigger the @ref bt_bap_unicast_server_cb.start()
* callback.
* For the unicast server, this will execute the receiver start ready command on the unicast server
* for @ref BT_AUDIO_DIR_SINK ASEs. If the CIS is not connected yet, the stream will go into the
* streaming state as soon as the CIS is connected.
*
* This shall only be called for unicast streams.
*
Expand Down
76 changes: 69 additions & 7 deletions samples/bluetooth/bap_unicast_client/src/main.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2021-2023 Nordic Semiconductor ASA
* Copyright (c) 2021-2024 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
Expand Down Expand Up @@ -59,6 +59,7 @@ static K_SEM_DEFINE(sem_stream_configured, 0, 1);
static K_SEM_DEFINE(sem_stream_qos, 0, ARRAY_SIZE(sinks) + ARRAY_SIZE(sources));
static K_SEM_DEFINE(sem_stream_enabled, 0, 1);
static K_SEM_DEFINE(sem_stream_started, 0, 1);
static K_SEM_DEFINE(sem_stream_connected, 0, 1);

#define AUDIO_DATA_TIMEOUT_US 1000000UL /* Send data every 1 second */

Expand Down Expand Up @@ -518,9 +519,9 @@ static void stream_enabled(struct bt_bap_stream *stream)
k_sem_give(&sem_stream_enabled);
}

static void stream_started(struct bt_bap_stream *stream)
static void stream_connected_cb(struct bt_bap_stream *stream)
{
printk("Audio Stream %p started\n", stream);
printk("Audio Stream %p connected\n", stream);

/* Reset sequence number for sinks */
for (size_t i = 0U; i < configured_sink_stream_count; i++) {
Expand All @@ -530,6 +531,13 @@ static void stream_started(struct bt_bap_stream *stream)
}
}

k_sem_give(&sem_stream_connected);
}

static void stream_started(struct bt_bap_stream *stream)
{
printk("Audio Stream %p started\n", stream);

k_sem_give(&sem_stream_started);
}

Expand Down Expand Up @@ -576,7 +584,8 @@ static struct bt_bap_stream_ops stream_ops = {
.disabled = stream_disabled,
.stopped = stream_stopped,
.released = stream_released,
.recv = stream_recv
.recv = stream_recv,
.connected = stream_connected_cb,
};

static void add_remote_source(struct bt_bap_ep *ep)
Expand Down Expand Up @@ -1018,17 +1027,62 @@ static int enable_streams(void)
return 0;
}

static int start_streams(void)
static int connect_streams(void)
{
for (size_t i = 0U; i < configured_stream_count; i++) {
int err;

err = bt_bap_stream_start(&streams[i]);
if (err != 0) {
k_sem_reset(&sem_stream_connected);

err = bt_bap_stream_connect(&streams[i]);
if (err == -EALREADY) {
/* We have already connected a paired stream */
continue;
} else if (err != 0) {
printk("Unable to start stream: %d\n", err);
return err;
}

err = k_sem_take(&sem_stream_connected, K_FOREVER);
if (err != 0) {
printk("failed to take sem_stream_connected (err %d)\n", err);
return err;
}
}

return 0;
}

static enum bt_audio_dir stream_dir(const struct bt_bap_stream *stream)
{
struct bt_bap_ep_info ep_info;
int err;

err = bt_bap_ep_get_info(stream->ep, &ep_info);
if (err != 0) {
printk("Failed to get ep info for %p: %d\n", stream, err);
__ASSERT_NO_MSG(false);

return 0;
}

return ep_info.dir;
}

static int start_streams(void)
{
for (size_t i = 0U; i < configured_stream_count; i++) {
struct bt_bap_stream *stream = &streams[i];
int err;

if (stream_dir(stream) == BT_AUDIO_DIR_SOURCE) {
err = bt_bap_stream_start(&streams[i]);
if (err != 0) {
printk("Unable to start stream: %d\n", err);
return err;
}
} /* Sink streams are started by the unicast server */

err = k_sem_take(&sem_stream_started, K_FOREVER);
if (err != 0) {
printk("failed to take sem_stream_started (err %d)\n", err);
Expand All @@ -1051,6 +1105,7 @@ static void reset_data(void)
k_sem_reset(&sem_stream_qos);
k_sem_reset(&sem_stream_enabled);
k_sem_reset(&sem_stream_started);
k_sem_reset(&sem_stream_connected);

configured_sink_stream_count = 0;
configured_source_stream_count = 0;
Expand Down Expand Up @@ -1131,6 +1186,13 @@ int main(void)
}
printk("Streams enabled\n");

printk("Connecting streams\n");
err = connect_streams();
if (err != 0) {
return 0;
}
printk("Streams connected\n");

printk("Starting streams\n");
err = start_streams();
if (err != 0) {
Expand Down
19 changes: 16 additions & 3 deletions samples/bluetooth/tmap_peripheral/src/bap_unicast_sr.c
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/** @file
* @brief Bluetooth Basic Audio Profile (BAP) Unicast Server role.
*
* Copyright (c) 2021-2023 Nordic Semiconductor ASA
* Copyright (c) 2021-2024 Nordic Semiconductor ASA
* Copyright (c) 2022 Codecoup
* Copyright (c) 2023 NXP
*
Expand Down Expand Up @@ -293,10 +293,23 @@ static void stream_recv(struct bt_bap_stream *stream, const struct bt_iso_recv_i

static void stream_enabled(struct bt_bap_stream *stream)
{
const int err = bt_bap_stream_start(stream);
struct bt_bap_ep_info ep_info;
int err;

err = bt_bap_ep_get_info(stream->ep, &ep_info);
if (err != 0) {
printk("Failed to start stream %p: %d", stream, err);
printk("Failed to get ep info: %d\n", err);
return;
}

/* The unicast server is responsible for starting the sink streams */
if (ep_info.dir == BT_AUDIO_DIR_SINK) {
/* Automatically do the receiver start ready operation */
err = bt_bap_stream_start(stream);

if (err != 0) {
printk("Failed to start stream %p: %d", stream, err);
}
}
}

Expand Down
Loading
Loading