Message ID | 20240318163853.68598-4-silviu.barbulescu@nxp.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | Broadcast source reconfiguration support | expand |
Context | Check | Description |
---|---|---|
tedd_an/pre-ci_am | success | Success |
tedd_an/CheckPatch | success | CheckPatch PASS |
tedd_an/GitLint | success | Gitlint PASS |
Hi Silviu, On Mon, Mar 18, 2024 at 4:39 PM Silviu Florian Barbulescu <silviu.barbulescu@nxp.com> wrote: > > If a BIS is reconfigured, the metadata and codec capabilities are updated. > Also, the BASE is updated to reflect the update. > > --- > profiles/audio/bap.c | 76 ++++++++++++++++++++++++++++++++++++++ > profiles/audio/transport.c | 6 ++- > src/shared/bap.c | 11 +++++- > 3 files changed, 91 insertions(+), 2 deletions(-) > > diff --git a/profiles/audio/bap.c b/profiles/audio/bap.c > index 964ba9c21..e508e03ba 100644 > --- a/profiles/audio/bap.c > +++ b/profiles/audio/bap.c > @@ -580,6 +580,11 @@ static int setup_parse_bcast_qos(struct bap_setup *setup, const char *key, > return -EINVAL; > > dbus_message_iter_get_basic(iter, &qos->bcast.big); > + } else if (!strcasecmp(key, "BIS")) { > + if (var != DBUS_TYPE_BYTE) > + return -EINVAL; > + > + dbus_message_iter_get_basic(iter, &qos->bcast.bis); > } else if (!strcasecmp(key, "Options")) { > if (var != DBUS_TYPE_BYTE) > return -EINVAL; > @@ -884,6 +889,53 @@ static void setup_free(void *data) > free(setup); > } > > +static void iterate_setups(struct bap_setup *setup) > +{ > + const struct queue_entry *entry; > + struct bap_setup *ent_setup; > + uint8_t bis_cnt = 1; > + > + for (entry = queue_get_entries(setup->ep->setups); > + entry; entry = entry->next) { > + ent_setup = entry->data; > + > + if (setup->qos.bcast.big != ent_setup->qos.bcast.big) > + continue; > + > + util_iov_free(ent_setup->base, 1); > + ent_setup->base = NULL; I do wonder why we need to store the base as part of the setup? Can't we just generate it later when it is actually about to be configured into the socket like I did? > + if (setup->qos.bcast.bis == bis_cnt) { > + bt_bap_stream_config(ent_setup->stream, &setup->qos, > + setup->caps, NULL, NULL); > + bt_bap_stream_metadata(ent_setup->stream, > + setup->metadata, NULL, NULL); > + } > + > + bis_cnt++; > + } > +} > + > +static bool verify_state(struct bap_setup *setup) > +{ > + const struct queue_entry *entry; > + struct bap_setup *ent_setup; > + > + for (entry = queue_get_entries(setup->ep->setups); > + entry; entry = entry->next) { > + ent_setup = entry->data; > + > + if (setup->qos.bcast.big != ent_setup->qos.bcast.big) > + continue; > + > + if (bt_bap_stream_get_state(ent_setup->stream) == > + BT_BAP_STREAM_STATE_STREAMING) > + return false; > + } > + > + return true; > +} > + > static DBusMessage *set_configuration(DBusConnection *conn, DBusMessage *msg, > void *data) > { > @@ -925,6 +977,30 @@ static DBusMessage *set_configuration(DBusConnection *conn, DBusMessage *msg, > util_iov_free(setup->metadata, 1); > setup->metadata = util_iov_dup( > bt_bap_pac_get_metadata(ep->rpac), 1); > + } else if (bt_bap_pac_get_type(ep->lpac) == BT_BAP_BCAST_SOURCE) { > + if (setup->qos.bcast.bis != BT_ISO_QOS_BIS_UNSET) { > + if ((setup->qos.bcast.bis > queue_length(ep->setups)) || > + (setup->qos.bcast.bis == 0)) { > + setup_free(setup); > + return btd_error_invalid_args(msg); > + } > + > + /* Verify that no BIS in the BIG is in streaming state > + */ > + if (!verify_state(setup)) { > + setup_free(setup); > + return btd_error_not_permitted(msg, > + "Broadcast Audio Stream state is invalid"); > + } I was thinking we could delay the BASE setup until later when the code actually needs it then the code for stream_get_base can actually detect what are the streams with the same BIG and generate the BASE just once. > + /* Find and update the BIS specified in > + * set_configuration command > + */ > + iterate_setups(setup); > + > + setup_free(setup); > + return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); > + } > } > > setup->stream = bt_bap_stream_new(ep->data->bap, ep->lpac, ep->rpac, > diff --git a/profiles/audio/transport.c b/profiles/audio/transport.c > index 122c3339e..a060f8c61 100644 > --- a/profiles/audio/transport.c > +++ b/profiles/audio/transport.c > @@ -1643,8 +1643,12 @@ static void bap_state_changed(struct bt_bap_stream *stream, uint8_t old_state, > bap_update_links(transport); > if (!media_endpoint_is_broadcast(transport->endpoint)) > bap_update_qos(transport); > - else if (bt_bap_stream_io_dir(stream) != BT_BAP_BCAST_SOURCE) > + else if (bt_bap_stream_io_dir(stream) != BT_BAP_BCAST_SOURCE) { > bap_update_bcast_qos(transport); > + if (old_state == BT_BAP_STREAM_STATE_QOS) > + bap_update_bcast_config(transport); > + } > + > transport_update_playing(transport, FALSE); > return; > case BT_BAP_STREAM_STATE_DISABLING: > diff --git a/src/shared/bap.c b/src/shared/bap.c > index fd99cbbca..603d6d646 100644 > --- a/src/shared/bap.c > +++ b/src/shared/bap.c > @@ -1701,7 +1701,16 @@ static unsigned int bap_bcast_config(struct bt_bap_stream *stream, > struct bt_bap_qos *qos, struct iovec *data, > bt_bap_stream_func_t func, void *user_data) > { > - stream->qos = *qos; > + if (qos) { > + stream->qos = *qos; > + stream->qos.bcast.bcode = util_iov_dup(qos->bcast.bcode, 1); > + } > + > + if (data) { > + util_iov_free(stream->cc, 1); > + stream->cc = util_iov_dup(data, 1); > + } > + > stream->lpac->ops->config(stream, stream->cc, &stream->qos, > ep_config_cb, stream->lpac->user_data); > > -- > 2.39.2 These changes to shared/bap shall be submitted in a separate patch with a proper description.
diff --git a/profiles/audio/bap.c b/profiles/audio/bap.c index 964ba9c21..e508e03ba 100644 --- a/profiles/audio/bap.c +++ b/profiles/audio/bap.c @@ -580,6 +580,11 @@ static int setup_parse_bcast_qos(struct bap_setup *setup, const char *key, return -EINVAL; dbus_message_iter_get_basic(iter, &qos->bcast.big); + } else if (!strcasecmp(key, "BIS")) { + if (var != DBUS_TYPE_BYTE) + return -EINVAL; + + dbus_message_iter_get_basic(iter, &qos->bcast.bis); } else if (!strcasecmp(key, "Options")) { if (var != DBUS_TYPE_BYTE) return -EINVAL; @@ -884,6 +889,53 @@ static void setup_free(void *data) free(setup); } +static void iterate_setups(struct bap_setup *setup) +{ + const struct queue_entry *entry; + struct bap_setup *ent_setup; + uint8_t bis_cnt = 1; + + for (entry = queue_get_entries(setup->ep->setups); + entry; entry = entry->next) { + ent_setup = entry->data; + + if (setup->qos.bcast.big != ent_setup->qos.bcast.big) + continue; + + util_iov_free(ent_setup->base, 1); + ent_setup->base = NULL; + + if (setup->qos.bcast.bis == bis_cnt) { + bt_bap_stream_config(ent_setup->stream, &setup->qos, + setup->caps, NULL, NULL); + bt_bap_stream_metadata(ent_setup->stream, + setup->metadata, NULL, NULL); + } + + bis_cnt++; + } +} + +static bool verify_state(struct bap_setup *setup) +{ + const struct queue_entry *entry; + struct bap_setup *ent_setup; + + for (entry = queue_get_entries(setup->ep->setups); + entry; entry = entry->next) { + ent_setup = entry->data; + + if (setup->qos.bcast.big != ent_setup->qos.bcast.big) + continue; + + if (bt_bap_stream_get_state(ent_setup->stream) == + BT_BAP_STREAM_STATE_STREAMING) + return false; + } + + return true; +} + static DBusMessage *set_configuration(DBusConnection *conn, DBusMessage *msg, void *data) { @@ -925,6 +977,30 @@ static DBusMessage *set_configuration(DBusConnection *conn, DBusMessage *msg, util_iov_free(setup->metadata, 1); setup->metadata = util_iov_dup( bt_bap_pac_get_metadata(ep->rpac), 1); + } else if (bt_bap_pac_get_type(ep->lpac) == BT_BAP_BCAST_SOURCE) { + if (setup->qos.bcast.bis != BT_ISO_QOS_BIS_UNSET) { + if ((setup->qos.bcast.bis > queue_length(ep->setups)) || + (setup->qos.bcast.bis == 0)) { + setup_free(setup); + return btd_error_invalid_args(msg); + } + + /* Verify that no BIS in the BIG is in streaming state + */ + if (!verify_state(setup)) { + setup_free(setup); + return btd_error_not_permitted(msg, + "Broadcast Audio Stream state is invalid"); + } + + /* Find and update the BIS specified in + * set_configuration command + */ + iterate_setups(setup); + + setup_free(setup); + return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); + } } setup->stream = bt_bap_stream_new(ep->data->bap, ep->lpac, ep->rpac, diff --git a/profiles/audio/transport.c b/profiles/audio/transport.c index 122c3339e..a060f8c61 100644 --- a/profiles/audio/transport.c +++ b/profiles/audio/transport.c @@ -1643,8 +1643,12 @@ static void bap_state_changed(struct bt_bap_stream *stream, uint8_t old_state, bap_update_links(transport); if (!media_endpoint_is_broadcast(transport->endpoint)) bap_update_qos(transport); - else if (bt_bap_stream_io_dir(stream) != BT_BAP_BCAST_SOURCE) + else if (bt_bap_stream_io_dir(stream) != BT_BAP_BCAST_SOURCE) { bap_update_bcast_qos(transport); + if (old_state == BT_BAP_STREAM_STATE_QOS) + bap_update_bcast_config(transport); + } + transport_update_playing(transport, FALSE); return; case BT_BAP_STREAM_STATE_DISABLING: diff --git a/src/shared/bap.c b/src/shared/bap.c index fd99cbbca..603d6d646 100644 --- a/src/shared/bap.c +++ b/src/shared/bap.c @@ -1701,7 +1701,16 @@ static unsigned int bap_bcast_config(struct bt_bap_stream *stream, struct bt_bap_qos *qos, struct iovec *data, bt_bap_stream_func_t func, void *user_data) { - stream->qos = *qos; + if (qos) { + stream->qos = *qos; + stream->qos.bcast.bcode = util_iov_dup(qos->bcast.bcode, 1); + } + + if (data) { + util_iov_free(stream->cc, 1); + stream->cc = util_iov_dup(data, 1); + } + stream->lpac->ops->config(stream, stream->cc, &stream->qos, ep_config_cb, stream->lpac->user_data);