Skip to content

Commit

Permalink
bap: Set generated BASE on all setups from the same BIG
Browse files Browse the repository at this point in the history
Set the BASE generated in BlueZ on all setups from the same BIG,
and use defer to inform the kernel when to create the BIG.
  • Loading branch information
silviubarbulescu authored and Vudentz committed Feb 27, 2024
1 parent dd57562 commit 92f3ed1
Showing 1 changed file with 196 additions and 16 deletions.
212 changes: 196 additions & 16 deletions profiles/audio/bap.c
Expand Up @@ -950,8 +950,12 @@ static DBusMessage *set_configuration(DBusConnection *conn, DBusMessage *msg,
if (dbus_message_iter_get_arg_type(&props) != DBUS_TYPE_DICT_ENTRY)
return btd_error_invalid_args(msg);

/* Disconnect IOs if connecting since QoS is going to be reconfigured */
ep_close(ep);
/* Broadcast source supports multiple setups, each setup will be BIS
* and will be configured with the set_configuration command
* TO DO reconfiguration of a BIS.
*/
if (bt_bap_pac_get_type(ep->lpac) != BT_BAP_BCAST_SOURCE)
ep_close(ep);

setup = setup_new(ep);

Expand Down Expand Up @@ -987,7 +991,6 @@ static DBusMessage *set_configuration(DBusConnection *conn, DBusMessage *msg,
if (bt_bap_pac_get_type(ep->lpac) == BT_BAP_BCAST_SINK)
setup->msg = dbus_message_ref(msg);
else {
setup->base = bt_bap_stream_get_base(setup->stream);
setup->id = 0;
}

Expand Down Expand Up @@ -1853,7 +1856,7 @@ static void setup_connect_io(struct bap_data *data, struct bap_setup *setup,
static void setup_connect_io_broadcast(struct bap_data *data,
struct bap_setup *setup,
struct bt_bap_stream *stream,
struct bt_iso_qos *qos)
struct bt_iso_qos *qos, int defer)
{
struct btd_adapter *adapter = data->user_data;
GIOChannel *io = NULL;
Expand Down Expand Up @@ -1890,7 +1893,7 @@ static void setup_connect_io_broadcast(struct bap_data *data,
BT_IO_OPT_MODE, BT_IO_MODE_ISO,
BT_IO_OPT_QOS, qos,
BT_IO_OPT_BASE, &base,
BT_IO_OPT_DEFER_TIMEOUT, false,
BT_IO_OPT_DEFER_TIMEOUT, defer,
BT_IO_OPT_INVALID);

if (!io) {
Expand Down Expand Up @@ -2019,9 +2022,6 @@ static void setup_create_bcast_io(struct bap_data *data,

memset(&iso_qos, 0, sizeof(iso_qos));

if (!defer)
goto done;

iso_qos.bcast.big = setup->qos.bcast.big;
iso_qos.bcast.bis = setup->qos.bcast.bis;
iso_qos.bcast.sync_factor = setup->qos.bcast.sync_factor;
Expand All @@ -2038,9 +2038,10 @@ static void setup_create_bcast_io(struct bap_data *data,
iso_qos.bcast.timeout = setup->qos.bcast.timeout;
memcpy(&iso_qos.bcast.out, &setup->qos.bcast.io_qos,
sizeof(struct bt_iso_io_qos));
done:

if (bt_bap_pac_get_type(setup->ep->lpac) == BT_BAP_BCAST_SOURCE)
setup_connect_io_broadcast(data, setup, stream, &iso_qos);
setup_connect_io_broadcast(data, setup, stream, &iso_qos,
defer);
else
setup_listen_io_broadcast(data, setup, stream, &iso_qos);
}
Expand Down Expand Up @@ -2128,11 +2129,135 @@ static void bap_state(struct bt_bap_stream *stream, uint8_t old_state,
}
}

/* This function will call setup_create_io on all BISes from a BIG.
* The defer parameter will be set on true on all but the last one.
* This is done to inform the kernel when to when to start the BIG.
*/
static bool create_io_bises(struct bap_setup *setup,
uint8_t nb_bises, struct bap_data *data)
{
const struct queue_entry *entry;
struct bap_setup *ent_setup;
bool defer = true;
uint8_t active_bis_cnt = 1;

for (entry = queue_get_entries(setup->ep->setups);
entry; entry = entry->next) {
ent_setup = entry->data;

if (bt_bap_stream_get_qos(ent_setup->stream)->bcast.big !=
bt_bap_stream_get_qos(setup->stream)->bcast.big)
continue;

if (active_bis_cnt == nb_bises)
defer = false;

setup_create_io(data, ent_setup, ent_setup->stream, defer);
if (!ent_setup->io) {
error("Unable to create io");
goto fail;
}

active_bis_cnt++;
}

return true;

fail:
/* Clear the io of the created sockets if one
* socket creation fails.
*/
for (entry = queue_get_entries(setup->ep->setups);
entry; entry = entry->next) {
ent_setup = entry->data;

if (bt_bap_stream_get_qos(ent_setup->stream)->bcast.big !=
bt_bap_stream_get_qos(setup->stream)->bcast.big)
continue;

if (setup->io)
g_io_channel_unref(setup->io);
}
return false;
}

static void iterate_setup_update_base(void *data, void *user_data)
{
struct bap_setup *setup = data;
struct bap_setup *data_setup = user_data;

if ((setup->stream != data_setup->stream) &&
(setup->qos.bcast.big == data_setup->qos.bcast.big)) {

if (setup->base)
util_iov_free(setup->base, 1);

setup->base = util_iov_dup(data_setup->base, 1);
}
}

/* Function checks the state of all streams in the same BIG
* as the parameter stream, so it can decide if any sockets need
* to be created. Returns he number of streams that need a socket
* from that BIG.
*/
static uint8_t get_streams_nb_by_state(struct bap_setup *setup)
{
const struct queue_entry *entry;
struct bap_setup *ent_setup;
uint8_t stream_cnt = 0;

if (setup->qos.bcast.big == BT_ISO_QOS_BIG_UNSET)
/* If BIG ID is unset this is a single BIS BIG.
* return 1 as create one socket only for this BIS
*/
return 1;

for (entry = queue_get_entries(setup->ep->setups);
entry; entry = entry->next) {
ent_setup = entry->data;

/* Skip the curent stream form testing */
if (ent_setup == setup) {
stream_cnt++;
continue;
}

/* Test only BISes for the same BIG */
if (bt_bap_stream_get_qos(ent_setup->stream)->bcast.big !=
bt_bap_stream_get_qos(setup->stream)->bcast.big)
continue;

if (bt_bap_stream_get_state(ent_setup->stream) ==
BT_BAP_STREAM_STATE_STREAMING)
/* If one stream in a multiple BIS BIG is in
* streaming state this means that just the current
* stream must have is socket created so return 1.
*/
return 1;
else if (bt_bap_stream_get_state(ent_setup->stream) !=
BT_BAP_STREAM_STATE_CONFIG)
/* Not all streams form a BIG have received transport
* acquire, so wait for the other streams to.
*/
return 0;

stream_cnt++;
}

/* Return the number of streams for the BIG
* as all are ready to create sockets
*/
return stream_cnt;
}

static void bap_state_bcast(struct bt_bap_stream *stream, uint8_t old_state,
uint8_t new_state, void *user_data)
{
struct bap_data *data = user_data;
struct bap_setup *setup;
bool defer = false;
uint8_t nb_bises = 0;

DBG("stream %p: %s(%u) -> %s(%u)", stream,
bt_bap_stream_statestr(old_state), old_state,
Expand All @@ -2153,14 +2278,69 @@ static void bap_state_bcast(struct bt_bap_stream *stream, uint8_t old_state,
queue_remove(data->streams, stream);
break;
case BT_BAP_STREAM_STATE_CONFIG:
if (setup && !setup->id) {
setup_create_io(data, setup, stream, true);
if (!setup || setup->id)
break;
if (bt_bap_stream_io_dir(stream) ==
BT_BAP_BCAST_SOURCE) {
/* If the stream is attached to a
* broadcast sink endpoint.
*/
setup_create_io(data, setup, stream, defer);
if (!setup->io) {
error("Unable to create io");
if (old_state != BT_BAP_STREAM_STATE_RELEASING)
bt_bap_stream_release(stream, NULL,
NULL);
return;
if (old_state !=
BT_BAP_STREAM_STATE_RELEASING)
bt_bap_stream_release(stream,
NULL, NULL);
}
} else {
/* If the stream attached to a broadcast
* source endpoint generate the base.
*/
if (setup->base == NULL) {
setup->base = bt_bap_stream_get_base(
setup->stream);
/* Set the generated BASE on all setups
* from the same BIG.
*/
queue_foreach(setup->ep->setups,
iterate_setup_update_base, setup);
}
/* The kernel has 2 requirements when handling
* multiple BIS connections for the same BIG:
* 1 - setup_create_io for all but the last BIS
* must be with defer true so we can inform the
* kernel when to start the BIG.
* 2 - The order in which the setup_create_io
* are called must be in the order of BIS
* indexes in BASE from first to last.
* To address this requirement we will call
* setup_create_io on all BISes only when all
* transport acquire have been received and will
* send it in the order of the BIS index
* from BASE.
*/
nb_bises = get_streams_nb_by_state(setup);

if (nb_bises == 1) {
setup_create_io(data, setup,
stream, defer);
if (!setup->io) {
error("Unable to create io");
if (old_state !=
BT_BAP_STREAM_STATE_RELEASING)
bt_bap_stream_release(stream,
NULL, NULL);
}
break;
} else if (nb_bises == 0)
break;

if (!create_io_bises(setup, nb_bises, data)) {
if (old_state !=
BT_BAP_STREAM_STATE_RELEASING)
bt_bap_stream_release(stream,
NULL, NULL);
}
}
break;
Expand Down

0 comments on commit 92f3ed1

Please sign in to comment.