Re: [PATCH BlueZ 1/1] bap: Replace global bcast_pa_requests with a queue for each adapter

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Vlad,

On Mon, Apr 8, 2024 at 10:28 AM Vlad Pruteanu <vlad.pruteanu@xxxxxxx> wrote:
>
> This patch replaces the old global implementation of the bcast_pa_requests
> queue with one that stores the queue per adapter. The pa_timer has also
> been modified to be per adapter. The timer is now stopped when the queue is
> empty. The bcast_pa_requests queue, along with the pa_timer_id are now
> stored in the bap_data structure. Each adapter already has a coresponding
> entry in the sessions queue. Operations on the old bcast_pa_requests have
> been modified to be made on the appropriate bap_data entry.
>
> The bap_bcast_remove function has also been updated to remove from the
> queue entries of devices that were freed.
> ---
>  profiles/audio/bap.c | 109 +++++++++++++++++++++++++++++++------------
>  1 file changed, 79 insertions(+), 30 deletions(-)
>
> diff --git a/profiles/audio/bap.c b/profiles/audio/bap.c
> index db0af7e7c..82c6cf313 100644
> --- a/profiles/audio/bap.c
> +++ b/profiles/audio/bap.c
> @@ -107,6 +107,8 @@ struct bap_data {
>         struct queue *snks;
>         struct queue *bcast;
>         struct queue *streams;
> +       struct queue *bcast_pa_requests;
> +       unsigned int pa_timer_id;
>         GIOChannel *listen_io;
>         int selecting;
>         void *user_data;
> @@ -127,8 +129,6 @@ struct bap_bcast_pa_req {
>  };
>
>  static struct queue *sessions;
> -static struct queue *bcast_pa_requests;
> -static unsigned int pa_timer_id;
>
>  /* Structure holding the parameters for Periodic Advertisement create sync.
>   * The full QOS is populated at the time the user selects and endpoint and
> @@ -965,15 +965,25 @@ static DBusMessage *set_configuration(DBusConnection *conn, DBusMessage *msg,
>         return NULL;
>  }
>
> +static bool match_adapter_entry(const void *data, const void *match_data)
> +{
> +       const struct bap_data *bdata = data;
> +       const struct btd_adapter *adapter = match_data;
> +
> +       return (bdata->user_data == adapter) && (bdata->device == NULL);
> +}
> +
>  static void iso_bcast_confirm_cb(GIOChannel *io, GError *err, void *user_data)
>  {
>         struct bap_bcast_pa_req *req = user_data;
>         struct bap_setup *setup = req->data.setup;
> +       struct bap_data *bap_data = queue_find(sessions,
> +                       match_adapter_entry, setup->ep->data->adapter);

These lookups sound suspicious, couldn't you just store the bap_data
in the pa_req?

>         int fd;
>
>         DBG("BIG Sync completed");
>
> -       queue_remove(bcast_pa_requests, req);
> +       queue_remove(bap_data->bcast_pa_requests, req);
>
>         /* This device is no longer needed */
>         btd_service_connecting_complete(setup->ep->data->service, 0);
> @@ -1109,6 +1119,7 @@ static void iso_pa_sync_confirm_cb(GIOChannel *io, void *user_data)
>         GError *err = NULL;
>         struct bap_bcast_pa_req *pa_req = user_data;
>         struct bap_data *data = btd_service_get_user_data(pa_req->data.service);
> +       struct bt_bap *bap = data->bap;
>         struct bt_iso_base base;
>         struct bt_iso_qos qos;
>
> @@ -1130,12 +1141,13 @@ static void iso_pa_sync_confirm_cb(GIOChannel *io, void *user_data)
>         g_io_channel_unref(data->listen_io);
>         g_io_channel_shutdown(io, TRUE, NULL);
>         data->listen_io = NULL;
> -       queue_remove(bcast_pa_requests, pa_req);
> +       data = queue_find(sessions, match_adapter_entry, data->adapter);
> +       queue_remove(data->bcast_pa_requests, pa_req);

Ditto.

>
>         /* Analyze received BASE data and create remote media endpoints for each
>          * BIS matching our capabilities
>          */
> -       parse_base(data->bap, &base, bap_debug);
> +       parse_base(bap, &base, bap_debug);
>  }
>
>  static bool match_data_bap_data(const void *data, const void *match_data)
> @@ -2015,25 +2027,37 @@ static void pa_and_big_sync(struct bap_bcast_pa_req *req);
>
>  static gboolean pa_idle_timer(gpointer user_data)
>  {
> -       struct bap_bcast_pa_req *req = user_data;
> +       struct bap_data *bap_data = user_data;
> +       struct bap_bcast_pa_req *req =
> +                               queue_peek_head(bap_data->bcast_pa_requests);
>         bool in_progress = FALSE;
>
> +       /* If the queue is empty, stop the timer. It will be started,later on,
> +        * if any new requests arrive.
> +        */
> +       if (req == NULL) {
> +               /* Set the adapter's pa_timer id to 0. This will later be
> +                * used to check if the timer is on or off.
> +                */
> +               bap_data->pa_timer_id = 0;
> +               /* Stop the adapter's pa_timer by returning FALSE */
> +               return FALSE;
> +       }
> +
>         /* Handle timer if no request is in progress */
> -       queue_foreach(bcast_pa_requests, check_pa_req_in_progress,
> +       queue_foreach(bap_data->bcast_pa_requests, check_pa_req_in_progress,
>                         &in_progress);
>         if (in_progress == FALSE) {
> -               req = queue_peek_head(bcast_pa_requests);
> -               if (req != NULL)
> -                       switch (req->type) {
> -                       case BAP_PA_SHORT_REQ:
> -                               DBG("do short lived PA Sync");
> -                               short_lived_pa_sync(req);
> -                               break;
> -                       case BAP_PA_BIG_SYNC_REQ:
> -                               DBG("do PA Sync and BIG Sync");
> -                               pa_and_big_sync(req);
> -                               break;
> -                       }
> +               switch (req->type) {
> +               case BAP_PA_SHORT_REQ:
> +                       DBG("do short lived PA Sync");
> +                       short_lived_pa_sync(req);
> +                       break;
> +               case BAP_PA_BIG_SYNC_REQ:
> +                       DBG("do PA Sync and BIG Sync");
> +                       pa_and_big_sync(req);
> +                       break;
> +               }
>         }
>
>         return TRUE;
> @@ -2043,15 +2067,25 @@ static void setup_accept_io_broadcast(struct bap_data *data,
>                                         struct bap_setup *setup)
>  {
>         struct bap_bcast_pa_req *pa_req = new0(struct bap_bcast_pa_req, 1);
> +       struct bap_data *bap_data = queue_find(sessions,
> +               match_adapter_entry, data->adapter);

Wait, you do have bap_data already passed to this function, why do you
need to lookup for another?

> +
> +       /* Timer could be stopped if all the short lived requests were treated.
> +        * Check the state of the timer and turn it on so that this requests
> +        * can also be treated.
> +        */
> +       if (bap_data->pa_timer_id == 0)
> +               bap_data->pa_timer_id = g_timeout_add_seconds(
> +               PA_IDLE_TIMEOUT, pa_idle_timer, bap_data);
>
>         /* Add this request to the PA queue.
> -        * We don't need to check the queue here and the timer, as we cannot
> -        * have BAP_PA_BIG_SYNC_REQ before a short PA (BAP_PA_SHORT_REQ)
> +        * We don't need to check the queue here, as we cannot have
> +        * BAP_PA_BIG_SYNC_REQ before a short PA (BAP_PA_SHORT_REQ)
>          */
>         pa_req->type = BAP_PA_BIG_SYNC_REQ;
>         pa_req->in_progress = FALSE;
>         pa_req->data.setup = setup;
> -       queue_push_tail(bcast_pa_requests, pa_req);
> +       queue_push_tail(bap_data->bcast_pa_requests, pa_req);
>  }
>
>  static void setup_create_ucast_io(struct bap_data *data,
> @@ -2878,6 +2912,8 @@ static int bap_bcast_probe(struct btd_service *service)
>  {
>         struct btd_device *device = btd_service_get_device(service);
>         struct btd_adapter *adapter = device_get_adapter(device);
> +       struct bap_data *bap_data = queue_find(sessions,
> +                                               match_adapter_entry, adapter);

Don't we store the bap_data into the server user_data?

>         struct bap_bcast_pa_req *pa_req =
>                         new0(struct bap_bcast_pa_req, 1);
>
> @@ -2886,12 +2922,10 @@ static int bap_bcast_probe(struct btd_service *service)
>                 return -ENOTSUP;
>         }
>
> -       /* First time initialize the queue and start the idle timer */
> -       if (bcast_pa_requests == NULL) {
> -               bcast_pa_requests = queue_new();
> -               pa_timer_id = g_timeout_add_seconds(PA_IDLE_TIMEOUT,
> -                                       pa_idle_timer, NULL);
> -       }
> +       /* Start the PA timer if it isn't active */
> +       if (bap_data->pa_timer_id == 0)
> +               bap_data->pa_timer_id = g_timeout_add_seconds(
> +               PA_IDLE_TIMEOUT, pa_idle_timer, bap_data);
>
>         /* Enqueue this device advertisement so that we can do short-lived
>          */
> @@ -2899,17 +2933,31 @@ static int bap_bcast_probe(struct btd_service *service)
>         pa_req->type = BAP_PA_SHORT_REQ;
>         pa_req->in_progress = FALSE;
>         pa_req->data.service = service;
> -       queue_push_tail(bcast_pa_requests, pa_req);
> +       queue_push_tail(bap_data->bcast_pa_requests, pa_req);
>
>         return 0;
>  }
>
> +static bool remove_service(const void *data, const void *match_data)
> +{
> +       struct bap_bcast_pa_req *pa_req = (struct bap_bcast_pa_req *)data;
> +
> +       if (pa_req->type == BAP_PA_SHORT_REQ &&
> +               pa_req->data.service == match_data)
> +               return true;
> +       return false;
> +}
> +
>  static void bap_bcast_remove(struct btd_service *service)
>  {
>         struct btd_device *device = btd_service_get_device(service);
> -       struct bap_data *data;
> +       struct btd_adapter *adapter = device_get_adapter(device);
> +       struct bap_data *data = queue_find(sessions,
> +                                               match_adapter_entry, adapter);

Ditto.

>         char addr[18];
>
> +       queue_remove_if(data->bcast_pa_requests, remove_service, service);

Not really sure what this would be doing, aren't you supposed to clean
up if there is pa_req pending for the given service/device and stop
the pa_sync if it is in progress? It seems you just remove it from the
list but it is not free/cancel after this point.

>         ba2str(device_get_address(device), addr);
>         DBG("%s", addr);
>
> @@ -3035,6 +3083,7 @@ static int bap_adapter_probe(struct btd_profile *p,
>
>         data->bap = bt_bap_new(btd_gatt_database_get_db(database),
>                                         btd_gatt_database_get_db(database));
> +       data->bcast_pa_requests = queue_new();
>         if (!data->bap) {
>                 error("Unable to create BAP instance");
>                 free(data);
> --
> 2.40.1
>


-- 
Luiz Augusto von Dentz





[Index of Archives]     [Bluez Devel]     [Linux Wireless Networking]     [Linux Wireless Personal Area Networking]     [Linux ATH6KL]     [Linux USB Devel]     [Linux Media Drivers]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Big List of Linux Books]

  Powered by Linux