BAP stream reconfiguration
v3 cover BAP stream reconfiguration
Implement ClearConfiguration() and Reconfigure() for BAP unicast MediaEndpoints.
v3:
- Add bt_bap_stream_lock(), instead of bt_bap_stream_discard()
- Separate commit for "detach on RELEASING"
- Move "bap: do not try QoS before links are updated" first, as it makes sense standalone
- Add "bap: don't show error when releasing stream"
- Add "bap: delay QoS & IO creation if CIG is busy or setups configuring"
This reworks the unicast stream creation/QoS/CIG activation logic, to avoid doing operations that are impossible due to CIG state machine rules, or lead to ID conflicts.
Unicast tested manually on:
- Sony Linkbuds S: switching between AC 6(ii), 8(ii), 11(ii)
- Earfun Air Pro 3: switching between AC 6(i), 11(i)
with corresponding Pipewire branch
https://gitlab.freedesktop.org/pvir/pipewire/-/commits/bap-codec-switch-select
Some more testing is probably warranted.
Broadcast has not been tested.
Pauli Virtanen (10):
bap: do not try QoS before links are updated & io created shared/bap: detach ucast io on RELEASING and unlink streams shared/bap: add client ASE reuse and upper level stream locking
bap: lock streams when used
bap: add ready callback for setup configuration
bap: support removing streams with ClearConfiguration()
bap: add callback at the end of ucast client select/config
bap: implement Reconfigure()
bap: don't show error when releasing stream
bap: delay QoS & IO creation if CIG is busy or setups configuring
profiles/audio/bap.c | 1085 ++++++++++++++++++++++++++++-------- profiles/audio/transport.c | 20 +- profiles/audio/transport.h | 1 + src/shared/bap.c | 168 ++++-- src/shared/bap.h | 3 + 5 files changed, 1005 insertions(+), 272 deletions(-)
Signature · 1 line
2.49.0
PATCH v3 1/10 bap: do not try QoS before links are updated & io created
In setup config, QoS must be done after corresponding bap_state callback, because stream links are updated only at that point. If the ASE was in CONFIG state before reconfiguration, this gets done in wrong order.
Track explicitly that bap_state() is done after bt_bap_stream_config(), before proceeding to QoS.
--- profiles/audio/bap.c | 82 ++++++++++++++++++++++++++------------------ 1 file changed, 49 insertions(+), 33 deletions(-)
profiles/audio/bap.c +49 -33
@@ -75,6 +75,7 @@ struct bap_setup {bool recreate;bool cig_active;uint8_t sid; +bool config_pending;struct iovec *caps;struct iovec *metadata;unsigned int id;
@@ -720,6 +721,46 @@ static void qos_cb(struct bt_bap_stream *stream, uint8_t code, uint8_t reason, setup->msg =NULL ; } +static void setup_create_io (struct bap_data *data,struct bap_setup *setup, +struct bt_bap_stream *stream,int defer); + +static int setup_qos (struct bap_setup *setup) +{ +struct bap_data *data = setup->ep->data; +struct bt_bap_stream *stream = setup->stream; + +if (!stream) +return -EINVAL ; +if (bt_bap_stream_get_state (stream) !=BT_BAP_STREAM_STATE_CONFIG ) + goto error; +if (setup->id) + goto error; + +setup_create_io (data, setup, stream, true); +if (!setup->io) { +error ("Unable to create io" ); + goto error; + } + +/* Wait QoS response to respond */ + setup->id =bt_bap_stream_qos (stream, &setup->qos, qos_cb, setup); +if (!setup->id) { +error ("Failed to Configure QoS" ); + goto error; + } + +/* Bcast does not call the callback */ +if (bt_bap_stream_get_type (setup->stream) ==BT_BAP_STREAM_TYPE_BCAST ) + setup->id =0 ; + +return 0 ; + +error: +if (bt_bap_stream_get_state (stream) !=BT_BAP_STREAM_STATE_RELEASING ) +bt_bap_stream_release (stream,NULL ,NULL ); +return -EIO ; +} +static void config_cb (struct bt_bap_stream *stream,uint8_t code,uint8_t reason,void *user_data)
@@ -732,17 +773,8 @@ static void config_cb(struct bt_bap_stream *stream, setup->id =0 ;if (!code) { -/* Check state is already set to config then proceed to qos */ -if (bt_bap_stream_get_state (stream) == -BT_BAP_STREAM_STATE_CONFIG ) { - setup->id =bt_bap_stream_qos (stream, &setup->qos, - qos_cb, setup); -if (!setup->id) { -error ("Failed to Configure QoS" ); -bt_bap_stream_release (stream,NULL ,NULL ); - } - } - +if (!setup->config_pending) +setup_qos (setup);return ; }
@@ -984,6 +1016,7 @@ static DBusMessage *set_configuration(DBusConnection *conn, DBusMessage *msg, setup->stream =bt_bap_stream_new (ep->data->bap, ep->lpac, ep->rpac, &setup->qos, setup->caps);bt_bap_stream_set_user_data (setup->stream, ep->path); + setup->config_pending = true; setup->id =bt_bap_stream_config (setup->stream, &setup->qos, setup->caps, config_cb, setup);if (!setup->id) {
@@ -1003,6 +1036,7 @@ static DBusMessage *set_configuration(DBusConnection *conn, DBusMessage *msg,case BT_BAP_STREAM_TYPE_BCAST :/* No message sent over the air for broadcast */ setup->id =0 ; + setup->config_pending = false;if (ep->data->service)service_set_connecting (ep->data->service);
@@ -1401,6 +1435,7 @@ static void setup_config(void *data, void *user_data) ep->rpac, &setup->qos, setup->caps); + setup->config_pending = true; setup->id =bt_bap_stream_config (setup->stream, &setup->qos, setup->caps, config_cb, setup);if (!setup->id) {
@@ -1805,9 +1840,6 @@ static bool is_cig_busy(struct bap_data *data, uint8_t cig)return queue_find (sessions, cig_busy_session, &info); } -static void setup_create_io (struct bap_data *data,struct bap_setup *setup, -struct bt_bap_stream *stream,int defer); -static gboolean setup_io_recreate (void *user_data) {struct bap_setup *setup = user_data;
@@ -2187,25 +2219,9 @@ static void bap_state(struct bt_bap_stream *stream, uint8_t old_state,queue_remove (data->server_streams, stream);break ;case BT_BAP_STREAM_STATE_CONFIG : -if (setup && !setup->id) { -setup_create_io (data, setup, stream, true); -if (!setup->io) { -error ("Unable to create io" ); -if (old_state !=BT_BAP_STREAM_STATE_RELEASING ) -bt_bap_stream_release (stream,NULL , -NULL ); -return ; - } - -/* Wait QoS response to respond */ - setup->id =bt_bap_stream_qos (stream, - &setup->qos, - qos_cb, setup); -if (!setup->id) { -error ("Failed to Configure QoS" ); -bt_bap_stream_release (stream, -NULL ,NULL ); - } +if (setup) { + setup->config_pending = false; +setup_qos (setup); }break ;case BT_BAP_STREAM_STATE_QOS :
Signature · 1 line
2.49.0
This is automated email and please do not reply to this email!
Dear submitter,
Thank you for submitting the patches to the linux bluetooth mailing list. This is a CI test results with your patch series:
PW Link:https://patchwork.kernel.org/project/bluetooth/list/?series=969627
---Test result---
Test Summary:
CheckPatch PENDING 0.26 seconds GitLint PENDING 0.23 seconds BuildEll PASS 20.03 seconds BluezMake PASS 2603.71 seconds MakeCheck PASS 20.48 seconds MakeDistcheck PASS 197.56 seconds CheckValgrind PASS 273.63 seconds CheckSmatch WARNING 301.96 seconds bluezmakeextell PASS 130.84 seconds IncrementalBuild PENDING 0.26 seconds ScanBuild PASS 901.38 seconds
Details
##############################
Test: CheckPatch - PENDING
Desc: Run checkpatch.pl script Output:
##############################
Test: GitLint - PENDING
Desc: Run gitlint
Output:
##############################
Test: CheckSmatch - WARNING
Desc: Run smatch tool with source
Output:src/shared/bap.c:317:25: warning: array of flexible structuressrc/shared/bap.c: note: in included file:./src/shared/ascs.h:88:25: warning: array of flexible structuressrc/shared/bap.c:317:25: warning: array of flexible structuressrc/shared/bap.c: note: in included file:./src/shared/ascs.h:88:25: warning: array of flexible structuressrc/shared/bap.c:317:25: warning: array of flexible structuressrc/shared/bap.c: note: in included file:./src/shared/ascs.h:88:25: warning: array of flexible structuressrc/shared/bap.c:317:25: warning: array of flexible structuressrc/shared/bap.c: note: in included file:./src/shared/ascs.h:88:25: warning: array of flexible structuressrc/shared/bap.c:317:25: warning: array of flexible structuressrc/shared/bap.c: note: in included file:./src/shared/ascs.h:88:25: warning: array of flexible structuressrc/shared/bap.c:317:25: warning: array of flexible structuressrc/shared/bap.c: note: in included file:./src/shared/ascs.h:88:25: warning: array of flexible structures
##############################
Test: IncrementalBuild - PENDING
Desc: Incremental build with the patches in the series
Output:
---
Regards,
Linux Bluetooth
PATCH v3 2/10 shared/bap: detach ucast io on RELEASING and unlink streams
In reply to Pauli VirtanenWhen RELEASING, ucast stream QoS becomes invalid and client stream transport can no longer be acquired. Client shall close the CIS when ASE is RELEASING (BAP v1.0.2 §5.6.6).
As client, detach IO when RELEASING. Clear the stream links, as the QoS is no longer valid. Even if caching config the ASE may be reused for different purpose, and stream will anyway be reconfigured & re-linked as needed.
Also clear the stream transport, as it's not in acquirable state, and its configuration may change after this. This makes BAP Client to have existing transports only for streams that are >= QOS. (BAP Server is not changed here.)
--- src/shared/bap.c | 35 +++++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-)
src/shared/bap.c +33 -2
@@ -1508,6 +1508,13 @@ static void bap_stream_state_changed(struct bt_bap_stream *stream)if (stream->client)bt_bap_stream_stop (stream, stream_stop_complete,NULL );break ; +case BT_ASCS_ASE_STATE_RELEASING : +if (stream->client) { +bap_stream_clear_cfm (stream); +bap_stream_io_detach (stream); +bt_bap_stream_io_unlink (stream,NULL ); + } +break ; } }
@@ -2623,6 +2630,30 @@ static int bap_ucast_io_link(struct bt_bap_stream *stream,return 0 ; } +static void stream_unlink_ucast (void *data) +{ +struct bt_bap_stream *link = data; + +DBG (link->bap,"stream %p unlink" , link); + +queue_destroy (link->links,NULL ); + link->links =NULL ; +} + +static int bap_ucast_io_unlink (struct bt_bap_stream *stream, +struct bt_bap_stream *link) +{ +if (!stream) +return -EINVAL ; + +queue_destroy (stream->links, stream_unlink_ucast); + stream->links =NULL ; + +DBG (stream->bap,"stream %p unlink" , stream); +return 0 ; + +} +static void stream_link (void *data,void *user_data) {struct bt_bap_stream *stream = (void *)data;
@@ -2728,7 +2759,7 @@ static const struct bt_bap_stream_ops stream_ops[] = { bap_ucast_release, bap_ucast_detach, bap_ucast_set_io, bap_ucast_get_io, bap_ucast_io_dir, bap_ucast_io_link, - NULL), + bap_ucast_io_unlink), STREAM_OPS(BT_BAP_SOURCE, bap_ucast_set_state, bap_ucast_get_state, bap_ucast_config, bap_ucast_qos, bap_ucast_enable,
@@ -2738,7 +2769,7 @@ static const struct bt_bap_stream_ops stream_ops[] = { bap_ucast_release, bap_ucast_detach, bap_ucast_set_io, bap_ucast_get_io, bap_ucast_io_dir, bap_ucast_io_link, - NULL), + bap_ucast_io_unlink), STREAM_OPS(BT_BAP_BCAST_SINK, bap_bcast_set_state, bap_bcast_get_state, bap_bcast_config, bap_bcast_qos, bap_bcast_sink_enable,
Signature · 1 line
2.49.0
PATCH v3 3/10 shared/bap: add client ASE reuse and upper level stream locking
In reply to Pauli VirtanenChange ucast client stream design so that:
* upper level locks streams to indicate which ones it is using
* unused streams are reused when upper level wants a new stream
* only locked streams are used for bidi CIS linking
* streams (still) correspond 1-to-1 to non-idle ASEs
This fixes some issues:
* bap_ucast_stream_new() could pick a stream upper level is already using if lpac & rpac match (can occur with multi-stream AC 6(ii) etc)
* Avoids assuming ASE enters idle state at end of stream life cycle. This is False for some devices like Sony headsets, which always cache codec config so RELEASING -> CONFIG always, never RELEASING -> IDLE, so ASE never go IDLE again.
* Allows reconfiguring an ASE with different codec in this case.
* Allows upper level to only QoS some of the streams.
Reconfiguring ASE in QOS/CONFIG state with different codec here results to need_reconfig=true state, where ASE and stream configs do not match, and upper level needs to do bt_bap_stream_config() to sync them.
--- src/shared/bap.c | 133 ++++++++++++++++++++++++++++++----------------- src/shared/bap.h | 3 ++ 2 files changed, 89 insertions(+), 47 deletions(-)
src/shared/bap.c +86 -47
@@ -296,6 +296,8 @@ struct bt_bap_stream {struct queue *pending_states;bool no_cache_config;bool client; +bool locked; +bool need_reconfig;void *user_data; };
@@ -1925,6 +1927,9 @@ static unsigned int bap_ucast_qos(struct bt_bap_stream *stream,if (!stream->client)return 0 ; +if (stream->need_reconfig) +return 0 ; +memset (&qos,0 ,sizeof (qos));/* TODO: Figure out how to pass these values around */
@@ -2327,7 +2332,6 @@ static unsigned int bap_ucast_release(struct bt_bap_stream *stream,/* If stream does not belong to a client session, clean it up now */ if (!bap_stream_valid (stream)) {stream_set_state (stream,BT_BAP_STREAM_STATE_IDLE ); - stream =NULL ;return 0 ; }
@@ -2610,6 +2614,9 @@ static int bap_ucast_io_link(struct bt_bap_stream *stream, stream->ep->dir == link->ep->dir)return -EINVAL ; +if (stream->client && !(stream->locked && link->locked)) +return -EINVAL ; +if (!stream->links) stream->links =queue_new ();
@@ -5073,6 +5080,8 @@ static void ep_status_config(struct bt_bap *bap, struct bt_bap_endpoint *ep, ep->stream->cc = new0(struct iovec, 1);util_iov_memcpy (ep->stream->cc, cfg->cc, cfg->cc_len); + + ep->stream->need_reconfig = false; }static void bap_stream_config_cfm_cb (struct bt_bap_stream *stream,int err)
@@ -5980,43 +5989,6 @@ bool bt_bap_pac_bcast_is_local(struct bt_bap *bap, struct bt_bap_pac *pac)return false; } -static bool find_ep_unused (const void *data,const void *user_data) -{ -const struct bt_bap_endpoint *ep = data; -const struct match_pac *match = user_data; - -if (ep->stream) -return false; - -if (match->rpac) -return ep->dir == match->rpac->type; -else -return true; -} - -static bool find_ep_pacs (const void *data,const void *user_data) -{ -const struct bt_bap_endpoint *ep = data; -const struct match_pac *match = user_data; - -if (!ep->stream) -return false; - -if (ep->stream->lpac != match->lpac) -return false; - -if (ep->stream->rpac != match->rpac) -return false; - -switch (ep->state) { -case BT_BAP_STREAM_STATE_CONFIG : -case BT_BAP_STREAM_STATE_QOS : -return true; - } - -return false; -} -static bool find_ep_source (const void *data,const void *user_data) {const struct bt_bap_endpoint *ep = data;
@@ -6196,6 +6168,48 @@ static struct bt_bap_stream *bap_bcast_stream_new(struct bt_bap *bap,return stream; } +static bool find_ep_ucast (const void *data,const void *user_data) +{ +const struct bt_bap_endpoint *ep = data; +const struct match_pac *match = user_data; + +if (ep->stream) { +if (!ep->stream->client) +return false; +if (ep->stream->locked) +return false; +if (!queue_isempty (ep->stream->pending_states)) +return false; + +switch (ep->stream->state) { +case BT_BAP_STREAM_STATE_IDLE : +case BT_BAP_STREAM_STATE_CONFIG : +case BT_BAP_STREAM_STATE_QOS : +break ; +default : +return false; + } + } + +if (ep->dir != match->rpac->type) +return false; + +switch (match->lpac->type) { +case BT_BAP_SOURCE : +if (ep->dir !=BT_BAP_SINK ) +return false; +break ; +case BT_BAP_SINK : +if (ep->dir !=BT_BAP_SOURCE ) +return false; +break ; +default : +return false; + } + +return true; +} + static struct bt_bap_stream *bap_ucast_stream_new(struct bt_bap *bap, struct bt_bap_pac *lpac, struct bt_bap_pac *rpac,
@@ -6213,20 +6227,26 @@ static struct bt_bap_stream *bap_ucast_stream_new(struct bt_bap *bap, match.lpac = lpac; match.rpac = rpac; -/* Check for existing stream */ - ep =queue_find (bap->remote_eps, find_ep_pacs, &match); +/* Get free ASE */ + ep =queue_find (bap->remote_eps, find_ep_ucast, &match);if (!ep) { -/* Check for unused ASE */ - ep =queue_find (bap->remote_eps, find_ep_unused, &match); -if (!ep) { -DBG (bap,"Unable to find unused ASE" ); -return NULL ; - } +DBG (bap,"Unable to find usable ASE" ); +return NULL ; } stream = ep->stream; -if (!stream) +if (stream) { +/* Replace lpac: the stream generally needs to be reconfigured +* after this, otherwise things like codec config not match. +*/ +bap_stream_clear_cfm (stream); + stream->lpac = lpac; +util_iov_free (stream->cc,1 ); + stream->cc =util_iov_dup (data,1 ); + stream->need_reconfig = true; + }else { stream =bap_stream_new (bap, ep, lpac, rpac, data, true); + }return stream; }
@@ -6247,6 +6267,25 @@ struct bt_bap_stream *bt_bap_stream_new(struct bt_bap *bap,return bap_bcast_stream_new (bap, lpac, pqos, data); } +void bt_bap_stream_lock (struct bt_bap_stream *stream) +{ +if (!stream || !stream->client) +return ; + +/* Reserve stream ASE for use by upper level, so it won't get +* reallocated +*/ + stream->locked = true; +} + +void bt_bap_stream_unlock (struct bt_bap_stream *stream) +{ +if (!stream || !stream->client) +return ; + + stream->locked = false; +} +struct bt_bap *bt_bap_stream_get_session (struct bt_bap_stream *stream) {if (!stream)
src/shared/bap.h +3 -0
@@ -183,6 +183,9 @@ struct bt_bap_stream *bt_bap_stream_new(struct bt_bap *bap,struct bt_bap_qos *pqos, struct iovec *data); +void bt_bap_stream_lock (struct bt_bap_stream *stream); +void bt_bap_stream_unlock (struct bt_bap_stream *stream); +struct bt_bap *bt_bap_stream_get_session (struct bt_bap_stream *stream);uint8_t bt_bap_stream_get_state (struct bt_bap_stream *stream);
Signature · 1 line
2.49.0
PATCH v3 4/10 bap: lock streams when used
In reply to Pauli VirtanenIndicate to lower layer when we are using the streams.
When setup is freed, make sure the corresponding stream is released after unlocking.
--- profiles/audio/bap.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-)
profiles/audio/bap.c +20 -1
@@ -861,6 +861,17 @@ static struct bap_setup *setup_new(struct bap_ep *ep)return setup; } +static void release_stream (struct bt_bap_stream *stream) +{ +switch (bt_bap_stream_get_state (stream)) { +case BT_BAP_STREAM_STATE_IDLE : +case BT_BAP_STREAM_STATE_RELEASING : +break ; +default : +bt_bap_stream_release (stream,NULL ,NULL ); + } +} +static void setup_free (void *data) {struct bap_setup *setup = data;
@@ -892,6 +903,10 @@ static void setup_free(void *data)if (setup->destroy) setup->destroy (setup); +bt_bap_stream_unlock (setup->stream); + +release_stream (setup->stream); +free (setup); }
@@ -1015,6 +1030,7 @@ static DBusMessage *set_configuration(DBusConnection *conn, DBusMessage *msg, setup->stream =bt_bap_stream_new (ep->data->bap, ep->lpac, ep->rpac, &setup->qos, setup->caps); +bt_bap_stream_lock (setup->stream);bt_bap_stream_set_user_data (setup->stream, ep->path); setup->config_pending = true; setup->id = bt_bap_stream_config(setup->stream, &setup->qos,
@@ -1107,6 +1123,7 @@ static void create_stream_for_bis(struct bap_data *bap_data,/* Create and configure stream */ setup->stream =bt_bap_stream_new (bap_data->bap, lpac,NULL , &setup->qos, caps); +bt_bap_stream_lock (setup->stream); setup->sid = sid;bt_bap_stream_set_user_data (setup->stream, path);
@@ -1430,10 +1447,12 @@ static void setup_config(void *data, void *user_data)/* TODO: Check if stream capabilities match add support for Latency * and PHY. */ -if (!setup->stream) +if (!setup->stream) { setup->stream =bt_bap_stream_new (ep->data->bap, ep->lpac, ep->rpac, &setup->qos, setup->caps); +bt_bap_stream_lock (setup->stream); + } setup->config_pending = true; setup->id = bt_bap_stream_config(setup->stream, &setup->qos,
Signature · 1 line
2.49.0
PATCH v3 5/10 bap: add ready callback for setup configuration
In reply to Pauli VirtanenOperations like SetConfiguration need to wait until setup configuration finishes. Abstract this to a setup_config() callback emitted on QoS completion or failure, instead of hardcoding DBus reply.
--- profiles/audio/bap.c | 179 +++++++++++++++++++++++++++---------------- 1 file changed, 112 insertions(+), 67 deletions(-)
profiles/audio/bap.c +112 -67
@@ -63,6 +63,11 @@#define MEDIA_ENDPOINT_INTERFACE "org.bluez.MediaEndpoint1"#define MEDIA_INTERFACE "org.bluez.Media1" +struct bap_setup ; + +typedef void (*bap_setup_ready_func_t )(struct bap_setup *setup,int code, +uint8_t reason,void *data); +struct bap_setup {struct bap_ep *ep;struct bap_data *data;
@@ -76,11 +81,13 @@ struct bap_setup {bool cig_active;uint8_t sid;bool config_pending; +bool readying;struct iovec *caps;struct iovec *metadata;unsigned int id;struct iovec *base; -DBusMessage *msg; +bap_setup_ready_func_t ready_cb; +void *ready_cb_data;void (*destroy)(struct bap_setup *setup); };
@@ -116,6 +123,10 @@ struct bap_data {static struct queue *sessions; +static int setup_config (struct bap_setup *setup,bap_setup_ready_func_t cb, +void *user_data); + +static bool bap_data_set_user_data (struct bap_data *data,void *user_data) {if (!data)
@@ -697,28 +708,32 @@ fail:return -EINVAL ; } +static void setup_ready (struct bap_setup *setup,int code, +uint8_t reason) +{ +if (!setup->readying) +return ; + + setup->readying = false; + +if (setup->ready_cb) { + setup->ready_cb (setup, code, reason, setup->ready_cb_data); + setup->ready_cb =NULL ; + setup->ready_cb_data =NULL ; + } +} +static void qos_cb (struct bt_bap_stream *stream,uint8_t code,uint8_t reason,void *user_data) {struct bap_setup *setup = user_data; -DBusMessage *reply;DBG ("stream %p code 0x%02x reason 0x%02x" , stream, code, reason); setup->id =0 ; -if (!setup->msg) -return ; - -if (!code) - reply =dbus_message_new_method_return (setup->msg); -else - reply =btd_error_failed (setup->msg,"Unable to configure" ); - -g_dbus_send_message (btd_get_dbus_connection (), reply); - -dbus_message_unref (setup->msg); - setup->msg =NULL ; +if (code) +setup_ready (setup, code, reason); } static void setup_create_io(struct bap_data *data, struct bap_setup *setup,
@@ -766,26 +781,19 @@ static void config_cb(struct bt_bap_stream *stream, void *user_data) {struct bap_setup *setup = user_data; -DBusMessage *reply; +int err =0 ;DBG ("stream %p code 0x%02x reason 0x%02x" , stream, code, reason); setup->id =0 ; -if (!code) { -if (!setup->config_pending) -setup_qos (setup); -return ; - } +if (code) + err = code; +else if (!setup->config_pending) + err =setup_qos (setup); -if (!setup->msg) -return ; - - reply =btd_error_failed (setup->msg,"Unable to configure" ); -g_dbus_send_message (btd_get_dbus_connection (), reply); - -dbus_message_unref (setup->msg); - setup->msg =NULL ; +if (err) +setup_ready (setup, err, reason); }static void setup_io_close (void *data,void *user_data)
@@ -875,22 +883,16 @@ static void release_stream(struct bt_bap_stream *stream)static void setup_free (void *data) {struct bap_setup *setup = data; -DBusMessage *reply;DBG ("%p" , setup); +setup_ready (setup, -ECANCELED ,0 ); +if (setup->stream && setup->id) {bt_bap_stream_cancel (setup->stream, setup->id); setup->id =0 ; } -if (setup->msg) { - reply =btd_error_failed (setup->msg,"Canceled" ); -g_dbus_send_message (btd_get_dbus_connection (), reply); -dbus_message_unref (setup->msg); - setup->msg =NULL ; - } -if (setup->ep)queue_remove (setup->ep->setups, setup);
@@ -987,6 +989,29 @@ static bool setup_mismatch_qos(const void *data, const void *user_data)return !match_bcast_qos (&setup->qos.bcast, &match->qos.bcast); } +struct set_configuration_data { +struct bap_setup *setup; +DBusMessage *msg; +}; + +static void set_configuration_ready (struct bap_setup *setup,int code, +uint8_t reason,void *user_data) +{ +struct set_configuration_data *data = user_data; +DBusMessage *reply; + +if (!code) + reply =dbus_message_new_method_return (data->msg); +else if (code == -ECANCELED ) + reply =btd_error_failed (data->msg,"Canceled" ); +else + reply =btd_error_failed (data->msg,"Unable to configure" ); + +g_dbus_send_message (btd_get_dbus_connection (), reply); +dbus_message_unref (data->msg); +free (data); +} +static DBusMessage *set_configuration (DBusConnection *conn,DBusMessage *msg,void *data) {
@@ -994,6 +1019,7 @@ static DBusMessage *set_configuration(DBusConnection *conn, DBusMessage *msg,struct bap_setup *setup;const char *path;DBusMessageIter args, props; +struct set_configuration_data *cbdata;dbus_message_iter_init (msg, &args);
@@ -1028,36 +1054,23 @@ static DBusMessage *set_configuration(DBusConnection *conn, DBusMessage *msg,return btd_error_invalid_args (msg); } - setup->stream =bt_bap_stream_new (ep->data->bap, ep->lpac, ep->rpac, - &setup->qos, setup->caps); -bt_bap_stream_lock (setup->stream); -bt_bap_stream_set_user_data (setup->stream, ep->path); - setup->config_pending = true; - setup->id =bt_bap_stream_config (setup->stream, &setup->qos, - setup->caps, config_cb, setup); -if (!setup->id) { + cbdata = new0(struct set_configuration_data, 1); + cbdata->setup = setup; + +if (setup_config (setup, set_configuration_ready, cbdata)) {DBG ("Unable to config stream" );setup_free (setup); +free (cbdata);return btd_error_invalid_args (msg); } -if (setup->metadata && setup->metadata->iov_len) -bt_bap_stream_metadata (setup->stream, setup->metadata,NULL , -NULL ); + cbdata->msg =dbus_message_ref (msg);switch (bt_bap_stream_get_type (setup->stream)) { -case BT_BAP_STREAM_TYPE_UCAST : - setup->msg =dbus_message_ref (msg); -break ;case BT_BAP_STREAM_TYPE_BCAST : -/* No message sent over the air for broadcast */ - setup->id =0 ; - setup->config_pending = false; -if (ep->data->service)service_set_connecting (ep->data->service); - -return g_dbus_create_reply (msg,DBUS_TYPE_INVALID ); +break ; }return NULL ;
@@ -1436,11 +1449,14 @@ static struct bap_ep *ep_register(struct btd_service *service,return ep; } -static void setup_config (void *data,void *user_data) +static int setup_config (struct bap_setup *setup,bap_setup_ready_func_t cb, +void *user_data) { -struct bap_setup *setup = data;struct bap_ep *ep = setup->ep; +if (setup->readying) +return -EBUSY ; +DBG ("setup %p caps %p metadata %p" , setup, setup->caps, setup->metadata);
@@ -1454,27 +1470,49 @@ static void setup_config(void *data, void *user_data)bt_bap_stream_lock (setup->stream); } - setup->config_pending = true; +bt_bap_stream_set_user_data (setup->stream, ep->path); setup->id =bt_bap_stream_config (setup->stream, &setup->qos, setup->caps, config_cb, setup); -if (!setup->id) { -DBG ("Unable to config stream" ); -setup_free (setup); -return ; +if (!setup->id) +return -EINVAL ; + +switch (bt_bap_stream_get_type (setup->stream)) { +case BT_BAP_STREAM_TYPE_UCAST : + setup->config_pending = true; +break ; +case BT_BAP_STREAM_TYPE_BCAST : +/* Broadcast does not call the callback */ + setup->id =0 ; +break ; }if (setup->metadata && setup->metadata->iov_len)bt_bap_stream_metadata (setup->stream, setup->metadata,NULL ,NULL ); -bt_bap_stream_set_user_data (setup->stream, ep->path); + setup->readying = true; + setup->ready_cb = cb; + setup->ready_cb_data = user_data; + +return 0 ; +} + +static void bap_config_setup (void *data,void *user_data) +{ +struct bap_setup *setup = data; + +if (setup_config (setup,NULL ,NULL )) { +DBG ("Unable to config stream" ); +setup_free (setup); +return ; + } }static void bap_config (void *data,void *user_data) {struct bap_ep *ep = data; -queue_foreach (ep->setups, setup_config,NULL ); +queue_foreach (ep->setups, bap_config_setup,NULL ); } static void select_cb(struct bt_bap_pac *pac, int err, struct iovec *caps,
@@ -2240,11 +2278,18 @@ static void bap_state(struct bt_bap_stream *stream, uint8_t old_state,case BT_BAP_STREAM_STATE_CONFIG :if (setup) { setup->config_pending = false; -setup_qos (setup); +if (!setup->id) { +int err =setup_qos (setup); + +if (err) +setup_ready (setup, err,0 ); + } }break ;case BT_BAP_STREAM_STATE_QOS : -setup_create_io (data, setup, stream, true); +setup_create_io (data, setup, stream, true); +if (setup) +setup_ready (setup,0 ,0 );break ;case BT_BAP_STREAM_STATE_ENABLING :if (setup)
Signature · 1 line
2.49.0
PATCH v3 6/10 bap: support removing streams with ClearConfiguration()
In reply to Pauli VirtanenImplement removing streams via ClearConfiguration().
--- profiles/audio/bap.c | 184 +++++++++++++++++++++++++++++++++---- profiles/audio/transport.c | 17 ++++ profiles/audio/transport.h | 1 + 3 files changed, 185 insertions(+), 17 deletions(-)
profiles/audio/bap.c +167 -17
@@ -57,6 +57,8 @@#include "src/log.h" #include "src/error.h" +#include "transport.h" +#define ISO_SOCKET_UUID "6fbaf188-05e0-496a-9885-d6ddfdb4e03e"#define PACS_UUID_STR "00001850-0000-1000-8000-00805f9b34fb"#define BCAAS_UUID_STR "00001852-0000-1000-8000-00805f9b34fb"
@@ -67,6 +69,7 @@ struct bap_setup;typedef void (*bap_setup_ready_func_t )(struct bap_setup *setup,int code,uint8_t reason,void *data); +typedef void (*bap_setup_close_func_t )(struct bap_setup *setup,void *data);struct bap_setup {struct bap_ep *ep;
@@ -82,12 +85,15 @@ struct bap_setup {uint8_t sid;bool config_pending;bool readying; +bool closing;struct iovec *caps;struct iovec *metadata;unsigned int id;struct iovec *base;bap_setup_ready_func_t ready_cb;void *ready_cb_data; +bap_setup_close_func_t close_cb; +void *close_cb_data;void (*destroy)(struct bap_setup *setup); };
@@ -746,6 +752,8 @@ static int setup_qos(struct bap_setup *setup)if (!stream)return -EINVAL ; +if (setup->closing) +return -EINVAL ;if (bt_bap_stream_get_state (stream) !=BT_BAP_STREAM_STATE_CONFIG ) goto error;if (setup->id)
@@ -822,12 +830,103 @@ static void setup_io_close(void *data, void *user_data)bt_bap_stream_io_connecting (setup->stream,-1 ); } -static void ep_close (struct bap_ep *ep) +static bool release_stream (struct bt_bap_stream *stream) { -if (!ep) +if (!stream) +return true; + +switch (bt_bap_stream_get_state (stream)) { +case BT_BAP_STREAM_STATE_IDLE : +case BT_BAP_STREAM_STATE_RELEASING : +return true; +default : +bt_bap_stream_release (stream,NULL ,NULL ); +return false; + } +} + +static int setup_close (struct bap_setup *setup,bap_setup_close_func_t cb, +void *user_data) +{ +if (setup->closing) +return -EBUSY ; + +DBG ("%p" , setup); + + setup->close_cb = cb; + setup->close_cb_data = user_data; + setup->closing = true; + +bt_bap_stream_unlock (setup->stream); + +if (release_stream (setup->stream)) { +setup_free (setup); +return 0 ; + } + +return 0 ; +} + +struct ep_close_data { +int remaining; +int count; +const char *path; +void (*cb)(int count,void *user_data); +void *user_data; +}; + +static void ep_close_setup_cb (struct bap_setup *setup,void *user_data) +{ +struct ep_close_data *epdata = user_data; + + epdata->remaining--; + +DBG ("closed setup %p remain %d" , setup, epdata->remaining); + +if (epdata->remaining)return ; -queue_foreach (ep->setups, setup_io_close,NULL ); +if (epdata->cb) + epdata->cb (epdata->count, epdata->user_data); + +free (epdata); +} + +static void ep_close_setup (void *data,void *user_data) +{ +struct bap_setup *setup = data; +struct ep_close_data *epdata = user_data; +struct bt_bap_stream *stream = setup->stream; +const char *path =media_transport_stream_path (stream); + +if (epdata->path && (!path ||strcmp (epdata->path, path))) +return ; + + epdata->remaining++; +if (setup_close (setup, ep_close_setup_cb, epdata)) + epdata->remaining--; +else + epdata->count++; +} + +static void ep_close (struct bap_ep *ep,const char *transport_path, +void (*cb)(int count,void *user_data),void *user_data) +{ +struct ep_close_data *epdata; + +DBG ("close ep %p path %s" , ep, transport_path ? transport_path :"-" ); + + epdata = new0(struct ep_close_data, 1); + epdata->cb = cb; + epdata->path = transport_path; + epdata->user_data = user_data; + epdata->remaining =1 ; + +if (ep) +queue_foreach (ep->setups, ep_close_setup, epdata); + + epdata->path =NULL ; +ep_close_setup_cb (NULL , epdata); }static struct bap_setup *setup_new (struct bap_ep *ep)
@@ -869,17 +968,6 @@ static struct bap_setup *setup_new(struct bap_ep *ep)return setup; } -static void release_stream (struct bt_bap_stream *stream) -{ -switch (bt_bap_stream_get_state (stream)) { -case BT_BAP_STREAM_STATE_IDLE : -case BT_BAP_STREAM_STATE_RELEASING : -break ; -default : -bt_bap_stream_release (stream,NULL ,NULL ); - } -} -static void setup_free (void *data) {struct bap_setup *setup = data;
@@ -888,6 +976,9 @@ static void setup_free(void *data)setup_ready (setup, -ECANCELED ,0 ); +if (setup->closing && setup->close_cb) + setup->close_cb (setup, setup->close_cb_data); +if (setup->stream && setup->id) {bt_bap_stream_cancel (setup->stream, setup->id); setup->id =0 ;
@@ -1035,7 +1126,7 @@ static DBusMessage *set_configuration(DBusConnection *conn, DBusMessage *msg,* TO DO reconfiguration of a BIS. */ if (bt_bap_pac_get_type (ep->lpac) !=BT_BAP_BCAST_SOURCE ) -ep_close (ep); +ep_close (ep,NULL ,NULL ,NULL ); setup =setup_new (ep);
@@ -1076,6 +1167,51 @@ static DBusMessage *set_configuration(DBusConnection *conn, DBusMessage *msg,return NULL ; } +struct clear_configuration_data { +DBusMessage *msg; +bool all; +}; + +static void clear_configuration_cb (int count,void *user_data) +{ +struct clear_configuration_data *data = user_data; +DBusMessage *reply; + +DBG ("%p" , data); + +if (!data->all && count ==0 ) + reply =btd_error_invalid_args (data->msg); +else + reply =dbus_message_new_method_return (data->msg); + +g_dbus_send_message (btd_get_dbus_connection (), reply); +dbus_message_unref (data->msg); +free (data); +} + +static DBusMessage *clear_configuration (DBusConnection *conn,DBusMessage *msg, +void *data) +{ +struct bap_ep *ep = data; +const char *path; +struct clear_configuration_data *cbdata; +DBusMessageIter args; + +dbus_message_iter_init (msg, &args); +dbus_message_iter_get_basic (&args, &path); + +if (strcmp (path, ep->path) ==0 ) + path =NULL ; + + cbdata = new0(struct clear_configuration_data, 1); + cbdata->msg =dbus_message_ref (msg); + cbdata->all = (path ==NULL ); + +DBG ("%p %s %s" , cbdata, ep->path, path ? path :"NULL" ); +ep_close (ep, path, clear_configuration_cb, cbdata); +return NULL ; +} +static bool stream_io_unset (const void *data,const void *user_data) {struct bt_bap_stream *stream = (struct bt_bap_stream *)data;
@@ -1249,6 +1385,9 @@ static const GDBusMethodTable ep_methods[] = { GDBUS_ARGS({ "endpoint", "o" }, { "Configuration", "a{sv}" } ), NULL, set_configuration) }, + {GDBUS_EXPERIMENTAL_ASYNC_METHOD ("ClearConfiguration" , + GDBUS_ARGS({ "transport", "o" }), + NULL, clear_configuration) }, { }, };
@@ -1259,10 +1398,9 @@ static void ep_free(void *data)struct bap_ep *ep = data;struct queue *setups = ep->setups; -ep_cancel_select (ep); - ep->setups =NULL ;queue_destroy (setups, setup_free); +ep_cancel_select (ep);free (ep->path);free (ep); }
@@ -1456,6 +1594,8 @@ static int setup_config(struct bap_setup *setup, bap_setup_ready_func_t cb,if (setup->readying)return -EBUSY ; +if (setup->closing) +return -EINVAL ;DBG ("setup %p caps %p metadata %p" , setup, setup->caps, setup->metadata);
@@ -2235,6 +2375,9 @@ static void setup_create_bcast_io(struct bap_data *data,static void setup_create_io (struct bap_data *data,struct bap_setup *setup,struct bt_bap_stream *stream,int defer) { +if (setup && setup->closing) +return ; +DBG ("setup %p stream %p defer %s" , setup, stream, defer ?"true" :"false" );
@@ -2267,6 +2410,13 @@ static void bap_state(struct bt_bap_stream *stream, uint8_t old_state, setup =bap_find_setup_by_stream (data, stream); +if (setup && setup->closing) { +if (old_state ==BT_BAP_STREAM_STATE_RELEASING ) { +setup_free (setup); +return ; + } + } +switch (new_state) {case BT_BAP_STREAM_STATE_IDLE :/* Release stream if idle */
profiles/audio/transport.c +17 -0
@@ -2670,3 +2670,20 @@ void media_transport_update_device_volume(struct btd_device *dev,btd_device_set_volume (dev, volume); } + +const char *media_transport_stream_path (void *stream) +{ +GSList *l; + +if (!stream) +return NULL ; + +for (l = transports; l; l = l->next) { +struct media_transport *transport = l->data; + +if (media_transport_get_stream (transport) == stream) +return transport->path; + } + +return NULL ; +}
profiles/audio/transport.h +1 -0
@@ -33,3 +33,4 @@ void transport_get_properties(struct media_transport *transport,int media_transport_get_device_volume (struct btd_device *dev);void media_transport_update_device_volume (struct btd_device *dev,int volume); +const char *media_transport_stream_path (void *stream);
Signature · 1 line
2.49.0
PATCH v3 7/10 bap: add callback at the end of ucast client select/config
In reply to Pauli VirtanenRestructure pac_select() and add a callback that is called when all setups reach QoS.
--- profiles/audio/bap.c | 172 +++++++++++++++++++++++++++++++++---------- 1 file changed, 133 insertions(+), 39 deletions(-)
profiles/audio/bap.c +133 -39
@@ -70,6 +70,7 @@ struct bap_setup;typedef void (*bap_setup_ready_func_t )(struct bap_setup *setup,int code,uint8_t reason,void *data);typedef void (*bap_setup_close_func_t )(struct bap_setup *setup,void *data); +typedef void (*bap_select_done_t )(int err,void *data);struct bap_setup {struct bap_ep *ep;
@@ -97,6 +98,15 @@ struct bap_setup {void (*destroy)(struct bap_setup *setup); }; +struct bap_select { +struct bap_data *data; +struct queue *eps; +int remaining; +int err; +bap_select_done_t done_cb; +void *done_cb_data; +}; +struct bap_ep {char *path;struct bap_data *data;
@@ -106,6 +116,7 @@ struct bap_ep {uint16_t supported_context;uint16_t context;struct queue *setups; +struct bap_select *select; };struct bap_data {
@@ -123,7 +134,6 @@ struct bap_data {struct queue *server_streams;GIOChannel *listen_io;unsigned int io_id; -int selecting;void *user_data; };
@@ -1637,14 +1647,37 @@ static int setup_config(struct bap_setup *setup, bap_setup_ready_func_t cb,return 0 ; } -static void bap_config_setup (void *data,void *user_data) +static void bap_config_setup_cb (struct bap_setup *setup,int code, +uint8_t reason,void *user_data) { -struct bap_setup *setup = data; +struct bap_select *select = user_data; -if (setup_config (setup,NULL ,NULL )) { + select->remaining--; + +DBG ("setup %p code %d remain %d" , setup, code, select->remaining); + +if (code) + select->err = code; + +if (select->remaining) +return ; + +if (select->done_cb) + select->done_cb (select->err, select->done_cb_data); + +free (select); +} + +static void bap_config_setup (void *item,void *user_data) +{ +struct bap_setup *setup = item; +struct bap_select *select = user_data; + + select->remaining++; +if (setup_config (setup, bap_config_setup_cb, select)) {DBG ("Unable to config stream" );setup_free (setup); -return ; + select->remaining--; } }
@@ -1652,7 +1685,37 @@ static void bap_config(void *data, void *user_data) {struct bap_ep *ep = data; -queue_foreach (ep->setups, bap_config_setup,NULL ); +queue_foreach (ep->setups, bap_config_setup, user_data); +} + +static void pac_select_clear_ep (void *data) +{ +struct bap_ep *ep = data; + + ep->select =NULL ; +} + +static void bap_select_complete_select (struct bap_select *select) +{ + select->remaining--; + +DBG ("selecting %d" , select->remaining); + +if (select->remaining) +return ; + +DBG ("configure (err %d)" , select->err); + +queue_destroy (select->eps, pac_select_clear_ep); + + select->remaining++; + +if (!select->err) { +queue_foreach (select->data->srcs, bap_config, select); +queue_foreach (select->data->snks, bap_config, select); + } + +bap_config_setup_cb (NULL ,0 ,0 , select); } static void select_cb(struct bt_bap_pac *pac, int err, struct iovec *caps,
@@ -1660,11 +1723,11 @@ static void select_cb(struct bt_bap_pac *pac, int err, struct iovec *caps, void *user_data) {struct bap_ep *ep = user_data; +struct bap_select *select = ep->select;struct bap_setup *setup;if (err) {error ("err %d" , err); - ep->data->selecting--; goto done; }
@@ -1673,38 +1736,15 @@ static void select_cb(struct bt_bap_pac *pac, int err, struct iovec *caps, setup->metadata =util_iov_dup (metadata,1 ); setup->qos = *qos; -DBG ("selecting %d" , ep->data->selecting); - ep->data->selecting--; - done: -if (ep->data->selecting) -return ; - -queue_foreach (ep->data->srcs, bap_config,NULL ); -queue_foreach (ep->data->snks, bap_config,NULL ); -queue_foreach (ep->data->bcast, bap_config,NULL ); -} - -static bool pac_register (struct bt_bap_pac *lpac,struct bt_bap_pac *rpac, -void *user_data) -{ -struct btd_service *service = user_data; -struct bap_ep *ep; - -DBG ("lpac %p rpac %p" , lpac, rpac); - - ep =ep_register (service, lpac, rpac); -if (!ep) -error ("Unable to register endpoint for pac %p" , rpac); - -return true; +bap_select_complete_select (select); }static bool pac_select (struct bt_bap_pac *lpac,struct bt_bap_pac *rpac,void *user_data) { -struct btd_service *service = user_data; -struct bap_data *data =btd_service_get_user_data (service); +struct bap_select *select = user_data; +struct bap_data *data = select->data;struct match_ep match = { lpac, rpac };struct queue *queue;struct bap_ep *ep;
@@ -1726,9 +1766,57 @@ static bool pac_select(struct bt_bap_pac *lpac, struct bt_bap_pac *rpac,return true; } +if (ep->select && ep->select != select) { + select->err = -EBUSY ; +return true; + } +/* TODO: Cache LRU? */ -if (btd_service_is_initiator (service)) -bt_bap_select (lpac, rpac, &ep->data->selecting, select_cb, ep); + +if (!ep->select) { + ep->select = select; +queue_push_tail (select->eps, ep); + } + +bt_bap_select (lpac, rpac, &select->remaining, select_cb, ep); + +return true; +} + +static int bap_select_all (struct bap_data *data,bap_select_done_t cb, +void *user_data) +{ +struct bap_select *select; + +if (!btd_service_is_initiator (data->service)) +return -EINVAL ; + + select = new0(struct bap_select, 1); + select->remaining =1 ; + select->data = data; + select->eps =queue_new (); + select->done_cb = cb; + select->done_cb_data = user_data; + +bt_bap_foreach_pac (data->bap,BT_BAP_SOURCE , pac_select, select); +bt_bap_foreach_pac (data->bap,BT_BAP_SINK , pac_select, select); + +bap_select_complete_select (select); + +return 0 ; +} + +static bool pac_register (struct bt_bap_pac *lpac,struct bt_bap_pac *rpac, +void *user_data) +{ +struct btd_service *service = user_data; +struct bap_ep *ep; + +DBG ("lpac %p rpac %p" , lpac, rpac); + + ep =ep_register (service, lpac, rpac); +if (!ep) +error ("Unable to register endpoint for pac %p" , rpac);return true; }
@@ -1746,9 +1834,16 @@ static bool pac_cancel_select(struct bt_bap_pac *lpac, struct bt_bap_pac *rpac,static void ep_cancel_select (struct bap_ep *ep) {struct bt_bap *bap = ep->data->bap; +struct bap_select *select;bt_bap_foreach_pac (bap,BT_BAP_SOURCE , pac_cancel_select, ep);bt_bap_foreach_pac (bap,BT_BAP_SINK , pac_cancel_select, ep); + + select = ep->select; +if (select) { +queue_remove (select->eps, ep); + ep->select =NULL ; + } } static bool pac_found_bcast(struct bt_bap_pac *lpac, struct bt_bap_pac *rpac,
@@ -1775,6 +1870,7 @@ static bool pac_found_bcast(struct bt_bap_pac *lpac, struct bt_bap_pac *rpac,static void bap_ready (struct bt_bap *bap,void *user_data) {struct btd_service *service = user_data; +struct bap_data *data =btd_service_get_user_data (service);DBG ("bap %p" , bap);
@@ -1784,8 +1880,7 @@ static void bap_ready(struct bt_bap *bap, void *user_data)bt_bap_foreach_pac (bap,BT_BAP_SOURCE , pac_register, service);bt_bap_foreach_pac (bap,BT_BAP_SINK , pac_register, service); -bt_bap_foreach_pac (bap,BT_BAP_SOURCE , pac_select, service); -bt_bap_foreach_pac (bap,BT_BAP_SINK , pac_select, service); +bap_select_all (data,NULL ,NULL ); }static bool match_setup_stream (const void *data,const void *user_data)
@@ -2742,8 +2837,7 @@ static void pac_added(struct bt_bap_pac *pac, void *user_data)bt_bap_foreach_pac (data->bap,BT_BAP_SOURCE , pac_register, service);bt_bap_foreach_pac (data->bap,BT_BAP_SINK , pac_register, service); -bt_bap_foreach_pac (data->bap,BT_BAP_SOURCE , pac_select, service); -bt_bap_foreach_pac (data->bap,BT_BAP_SINK , pac_select, service); +bap_select_all (data,NULL ,NULL ); }static void pac_added_broadcast (struct bt_bap_pac *pac,void *user_data)
Signature · 1 line
2.49.0
PATCH v3 8/10 bap: implement Reconfigure()
In reply to Pauli VirtanenAdd Reconfigure() on a BAP unicast endpoint, which triggers its reconfiguration or marks it for reconfiguration.
First, all associated streams are closed. After that, endpoints marked for reconfiguration are reconfigured using the same flow as in the initial configuration.
--- profiles/audio/bap.c | 151 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 146 insertions(+), 5 deletions(-)
profiles/audio/bap.c +146 -5
@@ -101,6 +101,7 @@ struct bap_setup {struct bap_select {struct bap_data *data;struct queue *eps; +bool reconfigure;int remaining;int err;bap_select_done_t done_cb;
@@ -117,6 +118,7 @@ struct bap_ep {uint16_t context;struct queue *setups;struct bap_select *select; +bool reconfigure; };struct bap_data {
@@ -141,7 +143,8 @@ static struct queue *sessions;static int setup_config (struct bap_setup *setup,bap_setup_ready_func_t cb,void *user_data); - +static int bap_select_all (struct bap_data *data,bool reconfigure, +bap_select_done_t cb,void *user_data);static bool bap_data_set_user_data (struct bap_data *data,void *user_data) {
@@ -1222,6 +1225,132 @@ static DBusMessage *clear_configuration(DBusConnection *conn, DBusMessage *msg,return NULL ; } +static int reconfigure_parse (DBusMessageIter *props,bool *defer) +{ +const char *key; + +if (dbus_message_iter_get_arg_type (props) !=DBUS_TYPE_DICT_ENTRY ) +return -EINVAL ; + +while (dbus_message_iter_get_arg_type (props) ==DBUS_TYPE_DICT_ENTRY ) { +DBusMessageIter value, entry; +int var; + +dbus_message_iter_recurse (props, &entry); +dbus_message_iter_get_basic (&entry, &key); + +dbus_message_iter_next (&entry); +dbus_message_iter_recurse (&entry, &value); + + var =dbus_message_iter_get_arg_type (&value); + +if (!strcasecmp (key,"Defer" )) { +dbus_bool_t flag; + +if (var !=DBUS_TYPE_BOOLEAN ) + goto fail; + +dbus_message_iter_get_basic (&value, &flag); + *defer = flag; + } + +dbus_message_iter_next (props); + } + +return 0 ; + +fail: +DBG ("Failed parsing %s" , key); + +return -EINVAL ; +} + +struct reconfigure_data { +int remaining; +struct bap_data *data; +DBusMessage *msg; +}; + +static void reconfigure_select_cb (int err,void *user_data) +{ +struct reconfigure_data *data = user_data; +DBusMessage *reply; + +if (!err) + reply =dbus_message_new_method_return (data->msg); +else + reply =btd_error_failed (data->msg,"Failed to configure" ); + +g_dbus_send_message (btd_get_dbus_connection (), reply); +dbus_message_unref (data->msg); +free (data); +} + +static void reconfigure_close_cb (int count,void *user_data) +{ +struct reconfigure_data *data = user_data; + + data->remaining--; + +DBG ("remain %d" , data->remaining); + +if (data->remaining) +return ; + +bap_select_all (data->data, true, reconfigure_select_cb, data); +} + +static void ep_close_if_reconfigure (void *obj,void *user_data) +{ +struct bap_ep *ep = obj; +struct reconfigure_data *data = user_data; + +if (ep->reconfigure) { + data->remaining++; +ep_close (ep,NULL , reconfigure_close_cb, data); + } +} + +static DBusMessage *reconfigure (DBusConnection *conn,DBusMessage *msg, +void *user_data) +{ +struct bap_ep *ep = user_data; +struct bap_data *data = ep->data; +struct reconfigure_data *cbdata; +bool defer = false; +DBusMessageIter args, props; + +switch (bt_bap_pac_get_type (ep->lpac)) { +case BT_BAP_SOURCE : +case BT_BAP_SINK : +break ; +default : +return btd_error_invalid_args (msg); + } + +dbus_message_iter_init (msg, &args); +dbus_message_iter_recurse (&args, &props); +if (reconfigure_parse (&props, &defer)) +return btd_error_invalid_args (msg); + +DBG ("%s defer %d" , ep->path, (int )defer); + + ep->reconfigure = true; +if (defer) +return dbus_message_new_method_return (msg); + + cbdata = new0(struct reconfigure_data, 1); + cbdata->data = ep->data; + cbdata->msg =dbus_message_ref (msg); + cbdata->remaining =1 ; + +queue_foreach (data->snks, ep_close_if_reconfigure, cbdata); +queue_foreach (data->srcs, ep_close_if_reconfigure, cbdata); + +reconfigure_close_cb (0 , cbdata); +return NULL ; +} +static bool stream_io_unset (const void *data,const void *user_data) {struct bt_bap_stream *stream = (struct bt_bap_stream *)data;
@@ -1398,6 +1527,10 @@ static const GDBusMethodTable ep_methods[] = { {GDBUS_EXPERIMENTAL_ASYNC_METHOD ("ClearConfiguration" , GDBUS_ARGS({ "transport", "o" }), NULL, clear_configuration) }, + { GDBUS_EXPERIMENTAL_ASYNC_METHOD("Reconfigure", +GDBUS_ARGS ( + { "properties", "a{sv}" }), + NULL, reconfigure) }, { }, };
@@ -1771,6 +1904,11 @@ static bool pac_select(struct bt_bap_pac *lpac, struct bt_bap_pac *rpac,return true; } +if (select->reconfigure && !ep->reconfigure) +return true; + + ep->reconfigure = false; +/* TODO: Cache LRU? */ if (!ep->select) {
@@ -1783,15 +1921,18 @@ static bool pac_select(struct bt_bap_pac *lpac, struct bt_bap_pac *rpac,return true; } -static int bap_select_all (struct bap_data *data,bap_select_done_t cb, -void *user_data) +static int bap_select_all (struct bap_data *data,bool reconfigure, +bap_select_done_t cb,void *user_data) {struct bap_select *select;if (!btd_service_is_initiator (data->service))return -EINVAL ; +DBG ("data %p reconfig %d" , data, (int )reconfigure); + select = new0(struct bap_select, 1); + select->reconfigure = reconfigure; select->remaining =1 ; select->data = data; select->eps =queue_new ();
@@ -1880,7 +2021,7 @@ static void bap_ready(struct bt_bap *bap, void *user_data)bt_bap_foreach_pac (bap,BT_BAP_SOURCE , pac_register, service);bt_bap_foreach_pac (bap,BT_BAP_SINK , pac_register, service); -bap_select_all (data,NULL ,NULL ); +bap_select_all (data, false,NULL ,NULL ); }static bool match_setup_stream (const void *data,const void *user_data)
@@ -2837,7 +2978,7 @@ static void pac_added(struct bt_bap_pac *pac, void *user_data)bt_bap_foreach_pac (data->bap,BT_BAP_SOURCE , pac_register, service);bt_bap_foreach_pac (data->bap,BT_BAP_SINK , pac_register, service); -bap_select_all (data,NULL ,NULL ); +bap_select_all (data, false,NULL ,NULL ); }static void pac_added_broadcast (struct bt_bap_pac *pac,void *user_data)
Signature · 1 line
2.49.0
PATCH v3 9/10 bap: don't show error when releasing stream
In reply to Pauli VirtanenWhen stream is released, just set transport to not playing and don't show error about missing io.
--- profiles/audio/transport.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
profiles/audio/transport.c +2 -1
@@ -2147,7 +2147,8 @@ static void bap_state_changed(struct bt_bap_stream *stream, uint8_t old_state,case BT_BAP_STREAM_STATE_RELEASING :if (bt_bap_stream_io_dir (stream) ==BT_BAP_BCAST_SINK )return ; -break ; +transport_update_playing (transport, FALSE); + goto done; } io =bt_bap_stream_get_io (stream);
Signature · 1 line
2.49.0
PATCH v3 10/10 bap: delay QoS & IO creation if CIG is busy or setups configuring
In reply to Pauli VirtanenUnicast Client IO creation / activation should be done synchronously for whole adapter, as active CIG has to be removed before it can be reconfigured (Core v6.0 Sec 4.5.14.3). Some adapters support only one active CIG.
Move related logic to bap_update_cig*() which does QoS and IO creation as needed by current state.
If CIG is active or setups are being configured or closed, delay transitions to QoS and IO recreation until that completes. Also delay activating CIG (= enabling CIS) until setups have finished readying or closing.
Operations are delayed within the same CIG, with the exception that streams with unassigned CIG delay every CIG. This is because such streams are likely meant to go to some existing CIG, so we must wait them to be configurable before asking kernel to assign IDs.
Fixes race conditions:
* setup starts readying while CIG is active
* CIG is activated while a setup is readying
* new stream creates IO before old stream IO is recreated
These result to kernel assigning new streams to a different CIG (problematic on controllers that can do only one) or CIS ID conflicts.
--- profiles/audio/bap.c | 394 +++++++++++++++++++++++++++++++------------ 1 file changed, 285 insertions(+), 109 deletions(-)
profiles/audio/bap.c +285 -109
@@ -81,8 +81,10 @@ struct bap_setup { DBusMessageIter *iter);GIOChannel *io;unsigned int io_id; -bool recreate; -bool cig_active; +bool want_qos; +bool want_io; +bool want_cis; +bool cis_active;uint8_t sid;bool config_pending;bool readying;
@@ -136,6 +138,7 @@ struct bap_data {struct queue *server_streams;GIOChannel *listen_io;unsigned int io_id; +unsigned int cig_update_id;void *user_data; };
@@ -145,6 +148,9 @@ static int setup_config(struct bap_setup *setup, bap_setup_ready_func_t cb, void *user_data);static int bap_select_all (struct bap_data *data,bool reconfigure,bap_select_done_t cb,void *user_data); +static void setup_create_io (struct bap_data *data,struct bap_setup *setup, +struct bt_bap_stream *stream,int defer); +static void bap_update_cigs (struct bap_data *data);static bool bap_data_set_user_data (struct bap_data *data,void *user_data) {
@@ -183,6 +189,9 @@ static void bap_data_free(struct bap_data *data)if (data->io_id)g_source_remove (data->io_id); +if (data->cig_update_id) +g_source_remove (data->cig_update_id); +if (data->service &&btd_service_get_user_data (data->service) == data)btd_service_set_user_data (data->service,NULL );
@@ -740,6 +749,8 @@ static void setup_ready(struct bap_setup *setup, int code, setup->ready_cb =NULL ; setup->ready_cb_data =NULL ; } + +bap_update_cigs (setup->ep->data); } static void qos_cb(struct bt_bap_stream *stream, uint8_t code, uint8_t reason,
@@ -753,10 +764,9 @@ static void qos_cb(struct bt_bap_stream *stream, uint8_t code, uint8_t reason,if (code)setup_ready (setup, code, reason); -} -static void setup_create_io (struct bap_data *data,struct bap_setup *setup, -struct bt_bap_stream *stream,int defer); +bap_update_cigs (setup->ep->data); +}static int setup_qos (struct bap_setup *setup) {
@@ -802,19 +812,15 @@ static void config_cb(struct bt_bap_stream *stream, void *user_data) {struct bap_setup *setup = user_data; -int err =0 ;DBG ("stream %p code 0x%02x reason 0x%02x" , stream, code, reason); setup->id =0 ;if (code) - err = code; -else if (!setup->config_pending) - err =setup_qos (setup); +setup_ready (setup, code, reason); -if (err) -setup_ready (setup, err, reason); +bap_update_cigs (setup->ep->data); }static void setup_io_close (void *data,void *user_data)
@@ -838,7 +844,7 @@ static void setup_io_close(void *data, void *user_data)g_io_channel_unref (setup->io); setup->io =NULL ; - setup->cig_active = false; + setup->cis_active = false;bt_bap_stream_io_connecting (setup->stream,-1 ); }
@@ -987,6 +993,8 @@ static void setup_free(void *data)DBG ("%p" , setup); + setup->closing = true; +setup_ready (setup, -ECANCELED ,0 );if (setup->closing && setup->close_cb)
@@ -1013,6 +1021,8 @@ static void setup_free(void *data)release_stream (setup->stream); +bap_update_cigs (setup->ep->data); +free (setup); }
@@ -2219,7 +2229,7 @@ static void setup_accept_io(struct bap_setup *setup, } } - setup->cig_active = true; + setup->cis_active = true;return ;
@@ -2227,129 +2237,299 @@ fail:close (fd); } -struct cig_busy_data { -struct btd_adapter *adapter; +struct find_cig_data { +const struct btd_adapter *adapter; +bool (*func)(const void *data,const void *match_data); +struct bap_setup *found; +struct queue *cigs;uint8_t cig; }; -static bool match_cig_active (const void *data,const void *match_data) +static bool find_cig_readying_setup (const void *data,const void *match_data) +{ +struct bap_setup *setup = (void *)data; +struct find_cig_data *info = (void *)match_data; +struct bt_bap_stream *stream = setup->stream; +struct bt_bap_qos *qos =bt_bap_stream_get_qos (stream); + +/* Streams with automatically assigned CIG are considered to potentially +* belong to any CIG. +*/ +if (qos && qos->ucast.cig_id != info->cig && + info->cig !=BT_ISO_QOS_CIG_UNSET && + qos->ucast.cig_id !=BT_ISO_QOS_CIG_UNSET ) +return false; + +return setup->readying || setup->closing || + setup->config_pending || setup->id; +} + +static bool find_cig_busy_setup (const void *data,const void *match_data) {const struct bap_setup *setup = data; -const struct cig_busy_data *info = match_data; +struct find_cig_data *info = (void *)match_data; +struct bt_bap_stream *stream = setup->stream; +struct bt_bap_qos *qos =bt_bap_stream_get_qos (stream); -return (setup->qos.ucast.cig_id == info->cig) && setup->cig_active; +if (qos && qos->ucast.cig_id != info->cig && + info->cig !=BT_ISO_QOS_CIG_UNSET && + qos->ucast.cig_id !=BT_ISO_QOS_CIG_UNSET ) +return false; + +return setup->cis_active || setup->closing || + setup->config_pending || setup->id; } -static bool cig_busy_ep (const void *data,const void *match_data) +static bool find_cig_enumerate_setup (const void *data,const void *match_data) +{ +const struct bap_setup *setup = data; +struct find_cig_data *info = (void *)match_data; +struct bt_bap_stream *stream = setup->stream; +struct bt_bap_qos *qos =bt_bap_stream_get_qos (stream); + +if (qos && info->cigs) { +queue_remove (info->cigs,UINT_TO_PTR (qos->ucast.cig_id)); +queue_push_tail (info->cigs,UINT_TO_PTR (qos->ucast.cig_id)); + } + +return false; +} + +static bool find_cig_ep (const void *data,const void *match_data) {const struct bap_ep *ep = data; -const struct cig_busy_data *info = match_data; +struct find_cig_data *info = (void *)match_data; -return queue_find (ep->setups, match_cig_active, info); + info->found =queue_find (ep->setups, info->func, match_data); +return info->found; } -static bool cig_busy_session (const void *data,const void *match_data) +static bool find_cig_session (const void *data,const void *match_data) {const struct bap_data *session = data; -const struct cig_busy_data *info = match_data; +const struct find_cig_data *info = match_data;if (device_get_adapter (session->device) != info->adapter)return false; -return queue_find (session->snks, cig_busy_ep, match_data) || -queue_find (session->srcs, cig_busy_ep, match_data); +return queue_find (session->snks, find_cig_ep, match_data) || +queue_find (session->srcs, find_cig_ep, match_data); } -static bool is_cig_busy (struct bap_data *data,uint8_t cig) +static struct bap_setup *find_cig_busy (struct bap_data *data,uint8_t cig) { -struct cig_busy_data info; +struct find_cig_data info = { + .adapter =device_get_adapter (data->device), + .cig = cig, + .func = find_cig_busy_setup, + }; -if (cig ==BT_ISO_QOS_CIG_UNSET ) -return false; - - info.adapter =device_get_adapter (data->device); - info.cig = cig; - -return queue_find (sessions, cig_busy_session, &info); +queue_find (sessions, find_cig_session, &info); +return info.found; } -static gboolean setup_io_recreate (void *user_data) +static struct bap_setup *find_cig_readying (struct bap_data *data,uint8_t cig) { -struct bap_setup *setup = user_data; +struct find_cig_data info = { + .adapter =device_get_adapter (data->device), + .cig = cig, + .func = find_cig_readying_setup, + }; + +queue_find (sessions, find_cig_session, &info); +return info.found; +} + +static struct queue *find_cig_enumerate (struct bap_data *data) +{ +struct find_cig_data info = { + .adapter =device_get_adapter (data->device), + .func = find_cig_enumerate_setup, + .cigs =queue_new (), + }; + +queue_find (sessions, find_cig_session, &info); +return info.cigs; +} + +struct update_cig_data { +struct btd_adapter *adapter; +void (*func)(void *data,void *match_data); +uint8_t cig; +unsigned int count; +}; + +static void update_cig_setup_enable (void *data,void *match_data) +{ +struct bap_setup *setup = data; +struct update_cig_data *info = match_data; +struct bt_bap_stream *stream = setup->stream; +struct bt_bap_qos *qos =bt_bap_stream_get_qos (stream); + +if (qos && qos->ucast.cig_id != info->cig) +return ; +if (!stream || !setup->io || setup->closing || setup->cis_active) +return ; +if (!setup->want_cis) +return ; +if (bt_bap_stream_get_state (stream) !=BT_BAP_STREAM_STATE_ENABLING ) +return ;DBG ("%p" , setup); - setup->io_id =0 ; + setup->want_cis = false; +setup_create_io (setup->ep->data, setup, setup->stream, false); + info->count++; +} +static void update_cig_setup_io (void *data,void *match_data) +{ +struct bap_setup *setup = data; +struct update_cig_data *info = match_data; +struct bt_bap_stream *stream = setup->stream; +struct bt_bap_qos *qos =bt_bap_stream_get_qos (stream); + +if (qos && qos->ucast.cig_id != info->cig) +return ; +if (!setup->want_io || !stream || setup->io || setup->closing) +return ; +if (bt_bap_stream_get_state (stream) !=BT_BAP_STREAM_STATE_QOS ) +return ; + +DBG ("%p" , setup); + + setup->want_io = false;setup_create_io (setup->ep->data, setup, setup->stream, true); + info->count++; +} + +static void update_cig_setup_qos (void *data,void *match_data) +{ +struct bap_setup *setup = data; +struct update_cig_data *info = match_data; +struct bt_bap_stream *stream = setup->stream; +int err; +struct bt_bap_qos *qos =bt_bap_stream_get_qos (stream); + +if (qos && qos->ucast.cig_id != info->cig) +return ; +if (!setup->want_qos || !stream || setup->closing) +return ; +if (bt_bap_stream_get_state (stream) !=BT_BAP_STREAM_STATE_CONFIG ) +return ; + +DBG ("%p" , setup); + + setup->want_qos = false; + err =setup_qos (setup); +if (err) +setup_ready (setup, err,0 ); +else + info->count++; +} + +static void update_cig_check_ep (void *data,void *match_data) +{ +struct bap_ep *ep = data; +struct update_cig_data *info = match_data; + +queue_foreach (ep->setups, info->func, match_data); +} + +static void update_cig_check_session (void *data,void *match_data) +{ +struct bap_data *session = data; +struct update_cig_data *info = match_data; + +if (device_get_adapter (session->device) != info->adapter) +return ; + +queue_foreach (session->snks, update_cig_check_ep, match_data); +queue_foreach (session->srcs, update_cig_check_ep, match_data); +} + +static void bap_update_cig (void *item,void *user_data) +{ +unsigned int cig =PTR_TO_UINT (item); +struct bap_data *data = user_data; +struct update_cig_data info; +struct bap_setup *setup; + + info.adapter =device_get_adapter (data->device); + info.count =0 ; + info.cig = cig; + +DBG ("adapter %p CIG 0x%x" , info.adapter, info.cig); + +/* Do stream QoS & IO re-creation only when CIG is no longer +* busy and all pending Config/QoS requests have completed. +*/ + setup =find_cig_busy (data, cig); +if (!setup) { +/* Recreate IO before QoS of new streams, so that we reserve +* their CIS IDs in kernel before allocating new streams. +*/ + info.func = update_cig_setup_io; +queue_foreach (sessions, update_cig_check_session, &info); + + info.func = update_cig_setup_qos; +queue_foreach (sessions, update_cig_check_session, &info); + }else { +DBG ("setup %p stream %p busy" , setup, setup->stream); + } + +/* Do CIS creation only after all setups have finished readying. +*/ + setup =find_cig_readying (data, cig); +if (!setup) { + info.func = update_cig_setup_enable; +queue_foreach (sessions, update_cig_check_session, &info); + }else { +DBG ("setup %p stream %p readying" , setup, setup->stream); + } +} + +static gboolean bap_update_cigs_cb (void *user_data) +{ +struct bap_data *data = user_data; +struct queue *cigs; +bool unset; + + data->cig_update_id =0 ; + + cigs =find_cig_enumerate (data); + unset =queue_remove (cigs,UINT_TO_PTR (BT_ISO_QOS_CIG_UNSET )); +queue_foreach (cigs, bap_update_cig, data); +queue_destroy (cigs,NULL ); + +/* Handle streams with unset CIG last, so that kernel CIG allocation +* knows which IDs are reserved. +*/ +if (unset) +bap_update_cig (UINT_TO_PTR (BT_ISO_QOS_CIG_UNSET ), data);return FALSE; } -static void setup_recreate (void *data,void *match_data) +static void bap_update_cigs (struct bap_data *data) { -struct bap_setup *setup = data; -struct cig_busy_data *info = match_data; - -if (setup->qos.ucast.cig_id != info->cig || !setup->recreate || - setup->io_id) +if (data->cig_update_id)return ; - setup->recreate = false; - setup->io_id =g_idle_add (setup_io_recreate, setup); -} - -static void recreate_cig_ep (void *data,void *match_data) -{ -struct bap_ep *ep = data; - -queue_foreach (ep->setups, setup_recreate, match_data); -} - -static void recreate_cig_session (void *data,void *match_data) -{ -struct bap_data *session = data; -struct cig_busy_data *info = match_data; - -if (device_get_adapter (session->device) != info->adapter) -return ; - -queue_foreach (session->snks, recreate_cig_ep, match_data); -queue_foreach (session->srcs, recreate_cig_ep, match_data); -} - -static void recreate_cig (struct bap_setup *setup) -{ -struct bap_data *data = setup->ep->data; -struct cig_busy_data info; - - info.adapter =device_get_adapter (data->device); - info.cig = setup->qos.ucast.cig_id; - -DBG ("adapter %p setup %p recreate CIG %d" , info.adapter, setup, - info.cig); - -if (setup->qos.ucast.cig_id ==BT_ISO_QOS_CIG_UNSET ) { -recreate_cig_ep (setup->ep, &info); -return ; - } - -queue_foreach (sessions, recreate_cig_session, &info); + data->cig_update_id =g_idle_add (bap_update_cigs_cb, data); }static void setup_io_disconnected (int cond,void *user_data) {struct bap_setup *setup = user_data; -DBG ("%p recreate %s" , setup, setup->recreate ?"true" :"false" ); - setup->io_id =0 ; +DBG ("%p" , setup); +setup_io_close (setup,NULL ); -/* Check if connecting recreate IO */ -if (!is_cig_busy (setup->ep->data, setup->qos.ucast.cig_id)) -recreate_cig (setup); +bap_update_cigs (setup->ep->data); } static void bap_connect_bcast_io_cb(GIOChannel *chan, GError *err,
@@ -2393,13 +2573,9 @@ static void setup_connect_io(struct bap_data *data, struct bap_setup *setup,return ; } -/* If IO channel still up or CIG is busy, wait for it to be -* disconnected and then recreate. -*/ -if (setup->io ||is_cig_busy (data, setup->qos.ucast.cig_id)) { -DBG ("setup %p stream %p defer %s wait recreate" , setup, stream, - defer ?"true" :"false" ); - setup->recreate = true; +/* If IO channel still up */ +if (setup->io) { +DBG ("setup %p stream %p io already up" , setup, stream);return ; }
@@ -2433,7 +2609,7 @@ static void setup_connect_io(struct bap_data *data, struct bap_setup *setup, setup->io_id =io_glib_add_err_watch (io, setup_io_disconnected, setup); setup->io = io; - setup->cig_active = !defer; + setup->cis_active = !defer;bt_bap_stream_io_connecting (stream,g_io_channel_unix_get_fd (io)); }
@@ -2664,22 +2840,25 @@ static void bap_state(struct bt_bap_stream *stream, uint8_t old_state,case BT_BAP_STREAM_STATE_CONFIG :if (setup) { setup->config_pending = false; -if (!setup->id) { -int err =setup_qos (setup); - -if (err) -setup_ready (setup, err,0 ); - } + setup->want_qos = true; +bap_update_cigs (setup->ep->data); }break ;case BT_BAP_STREAM_STATE_QOS : -setup_create_io (data, setup, stream, true); -if (setup) +if (setup) { + setup->want_qos = false; + setup->want_io = true;setup_ready (setup,0 ,0 ); +bap_update_cigs (setup->ep->data); + }else { +setup_create_io (data, setup, stream, true); + }break ;case BT_BAP_STREAM_STATE_ENABLING : -if (setup) -setup_create_io (data, setup, stream, false); +if (setup) { + setup->want_cis = true; +bap_update_cigs (setup->ep->data); + }break ;case BT_BAP_STREAM_STATE_STREAMING :break ;
@@ -3146,7 +3325,6 @@ static void bap_connecting(struct bt_bap_stream *stream, bool state, int fd,if (!setup)return ; - setup->recreate = false; qos = &setup->qos;if (!setup->io) {
@@ -3191,8 +3369,6 @@ static void bap_connecting_bcast(struct bt_bap_stream *stream, bool state,if (!setup)return ; - setup->recreate = false; -if (!setup->io) { io =g_io_channel_unix_new (fd); setup->io_id = io_glib_add_err_watch(io, setup_io_disconnected,
Signature · 1 line
2.49.0
This series was applied to bluetooth/bluez.git (master) by Luiz Augusto von Dentz <[email protected]>:
Hello:
This series was applied to bluetooth/bluez.git (master) by Luiz Augusto von Dentz <[email protected]>:
Quoted 8 lines · On Mon, 9 Jun 2025 00:32:12 +0300 you wrote:
Implement
ClearConfiguration()andReconfigure()for BAP unicast MediaEndpoints.v3:
- Add
bt_bap_stream_lock(), instead ofbt_bap_stream_discard()[...]
Here is the summary with links:
- [BlueZ,v3,01/10] bap: do not try QoS before links are updated & io created
https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=7d8eaa56b8cb - [BlueZ,v3,02/10] shared/bap: detach ucast io on RELEASING and unlink streams https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=2f853e4d86d8 - [BlueZ,v3,03/10] shared/bap: add client ASE reuse and upper level stream locking https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=d1eb496cc605 - [BlueZ,v3,04/10] bap: lock streams when used https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=40b91712b932 - [BlueZ,v3,05/10] bap: add ready callback for setup configuration https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=ebed99caa7a1 - [BlueZ,v3,06/10] bap: support removing streams with ClearConfiguration() https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=9e0dc968de50 - [BlueZ,v3,07/10] bap: add callback at the end of ucast client select/config (no matching commit) - [BlueZ,v3,08/10] bap: implement Reconfigure() https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=128b0695e2b5 - [BlueZ,v3,09/10] bap: don't show error when releasing stream https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=1d3907561f8e - [BlueZ,v3,10/10] bap: delay QoS & IO creation if CIG is busy or setups configuring https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=7feff47a9fbe
You are awesome, thank you!
Signature · 2 lines
Deet-doot-dot, I am a bot. https://korg.docs.kernel.org/patchwork/pwbot.html
Luiz Augusto von Dentz
maintainerHi Pauli,
Quoted 29 lines · On Mon, Jun 9, 2025 at 3:04 PM <[email protected]> wrote:
Hello:
This series was applied to bluetooth/bluez.git (master) by Luiz Augusto von Dentz <[email protected]>:
Quoted 8 lines · On Mon, 9 Jun 2025 00:32:12 +0300 you wrote:
Implement
ClearConfiguration()andReconfigure()for BAP unicast MediaEndpoints.v3:
- Add
bt_bap_stream_lock(), instead ofbt_bap_stream_discard()[...]
Here is the summary with links:
- [BlueZ,v3,01/10] bap: do not try QoS before links are updated & io createdhttps://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=7d8eaa56b8cb - [BlueZ,v3,02/10] shared/bap: detach ucast io on RELEASING and unlink streams https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=2f853e4d86d8 - [BlueZ,v3,03/10] shared/bap: add client ASE reuse and upper level stream locking https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=d1eb496cc605 - [BlueZ,v3,04/10] bap: lock streams when used https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=40b91712b932 - [BlueZ,v3,05/10] bap: add ready callback for setup configuration https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=ebed99caa7a1 - [BlueZ,v3,06/10] bap: support removing streams with ClearConfiguration() https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=9e0dc968de50
Quoted 2 lines
- [BlueZ,v3,07/10] bap: add callback at the end of ucast client select/config (no matching commit)
Did a minor change to this one:
%s/bap_select_complete_select/bap_select_complete
Quoted 14 lines
- [BlueZ,v3,08/10] bap: implement
Reconfigure()https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=128b0695e2b5 - [BlueZ,v3,09/10] bap: don't show error when releasing stream https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=1d3907561f8e - [BlueZ,v3,10/10] bap: delay QoS & IO creation if CIG is busy or setups configuring https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=7feff47a9fbeYou are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
Signature · 1 line
Luiz Augusto von Dentz