Re: [PATCH v3 3/3] a2dp: Fix not calling SelectConfiguration on other available endpoints

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

 



Hi Pali,

On Mon, Apr 29, 2019 at 3:03 PM Luiz Augusto von Dentz
<luiz.dentz@xxxxxxxxx> wrote:
>
> From: Luiz Augusto von Dentz <luiz.von.dentz@xxxxxxxxx>
>
> Endpoint may not be able to select a valid configuration but there could
> be other endpoints available that could be used, so instead of just
> using the first match this collects all the matching endpoints and put
> them into a queue (ordered by priority) then proceed to next endpoint
> only failing if none of the available endpoits can select a valid
> configuration.
> ---
>  profiles/audio/a2dp.c | 77 ++++++++++++++++++++++++++++---------------
>  1 file changed, 50 insertions(+), 27 deletions(-)
>
> diff --git a/profiles/audio/a2dp.c b/profiles/audio/a2dp.c
> index a23abdd97..4d378a91a 100644
> --- a/profiles/audio/a2dp.c
> +++ b/profiles/audio/a2dp.c
> @@ -105,6 +105,7 @@ struct a2dp_setup_cb {
>  struct a2dp_setup {
>         struct a2dp_channel *chan;
>         struct avdtp *session;
> +       struct queue *eps;
>         struct a2dp_sep *sep;
>         struct a2dp_remote_sep *rsep;
>         struct avdtp_stream *stream;
> @@ -2406,23 +2407,44 @@ void a2dp_remove_sep(struct a2dp_sep *sep)
>
>  static void select_cb(struct a2dp_setup *setup, void *ret, int size)
>  {
> -       if (size < 0) {
> -               DBG("Endpoint replied an invalid configuration");
> +       struct avdtp_service_capability *service;
> +       struct avdtp_media_codec_capability *codec;
> +       int err;
> +
> +       if (size) {
> +               caps_add_codec(&setup->caps, setup->sep->codec, ret, size);
>                 goto done;
>         }
>
> -       caps_add_codec(&setup->caps, setup->sep->codec, ret, size);
> +       setup->sep = queue_pop_head(setup->eps);
> +       if (!setup->sep) {
> +               error("Unable to select a valid configuration");
> +               queue_destroy(setup->eps, NULL);
> +               goto done;
> +       }
> +
> +       setup->rsep = find_remote_sep(setup->chan, setup->sep);
> +       service = avdtp_get_codec(setup->rsep->sep);
> +       codec = (struct avdtp_media_codec_capability *) service->data;
> +
> +       err = setup->sep->endpoint->select_configuration(setup->sep,
> +                                       codec->data,
> +                                       service->length - sizeof(*codec),
> +                                       setup_ref(setup),
> +                                       select_cb, setup->sep->user_data);
> +       if (err == 0)
> +               return;
>
>  done:
>         finalize_select(setup);
>         setup_unref(setup);
>  }
>
> -static struct a2dp_sep *a2dp_find_sep(struct avdtp *session, GSList *list,
> +static struct queue *a2dp_find_eps(struct avdtp *session, GSList *list,
>                                         const char *sender)
>  {
> -       struct a2dp_sep *first = NULL;
>         struct a2dp_channel *chan = find_channel(session);
> +       struct queue *seps = NULL;
>
>         for (; list; list = list->next) {
>                 struct a2dp_sep *sep = list->data;
> @@ -2444,26 +2466,25 @@ static struct a2dp_sep *a2dp_find_sep(struct avdtp *session, GSList *list,
>                 if (!rsep)
>                         continue;
>
> -               /* Locate last used if set */
> -               if (chan->last_used) {
> -                       if (chan->last_used->sep == rsep)
> -                               return sep;
> -                       first = sep;
> -                       continue;
> -               }
> +               if (!seps)
> +                       seps = queue_new();
>
> -               return sep;
> +               /* Prepend last used so it is preferred over others */
> +               if (chan->last_used && chan->last_used->sep == rsep)
> +                       queue_push_head(seps, sep);
> +               else
> +                       queue_push_tail(seps, sep);
>
>         }
>
> -       return first;
> +       return seps;
>  }
>
> -static struct a2dp_sep *a2dp_select_sep(struct avdtp *session, uint8_t type,
> +static struct queue *a2dp_select_eps(struct avdtp *session, uint8_t type,
>                                         const char *sender)
>  {
>         struct a2dp_server *server;
> -       struct a2dp_sep *sep;
> +       struct queue *seps;
>         GSList *l;
>
>         server = find_server(servers, avdtp_get_adapter(session));
> @@ -2473,11 +2494,11 @@ static struct a2dp_sep *a2dp_select_sep(struct avdtp *session, uint8_t type,
>         l = type == AVDTP_SEP_TYPE_SINK ? server->sources : server->sinks;
>
>         /* Check sender's seps first */
> -       sep = a2dp_find_sep(session, l, sender);
> -       if (sep != NULL)
> -               return sep;
> +       seps = a2dp_find_eps(session, l, sender);
> +       if (seps != NULL)
> +               return seps;
>
> -       return a2dp_find_sep(session, l, NULL);
> +       return a2dp_find_eps(session, l, NULL);
>  }
>
>  static void store_remote_sep(void *data, void *user_data)
> @@ -2580,13 +2601,13 @@ unsigned int a2dp_select_capabilities(struct avdtp *session,
>  {
>         struct a2dp_setup *setup;
>         struct a2dp_setup_cb *cb_data;
> -       struct a2dp_sep *sep;
> +       struct queue *eps;
>         struct avdtp_service_capability *service;
>         struct avdtp_media_codec_capability *codec;
>         int err;
>
> -       sep = a2dp_select_sep(session, type, sender);
> -       if (!sep) {
> +       eps = a2dp_select_eps(session, type, sender);
> +       if (!eps) {
>                 error("Unable to select SEP");
>                 return 0;
>         }
> @@ -2599,8 +2620,9 @@ unsigned int a2dp_select_capabilities(struct avdtp *session,
>         cb_data->select_cb = cb;
>         cb_data->user_data = user_data;
>
> -       setup->sep = sep;
> -       setup->rsep = find_remote_sep(setup->chan, sep);
> +       setup->eps = eps;
> +       setup->sep = queue_pop_head(eps);
> +       setup->rsep = find_remote_sep(setup->chan, setup->sep);
>
>         if (setup->rsep == NULL) {
>                 error("Could not find remote sep");
> @@ -2610,10 +2632,11 @@ unsigned int a2dp_select_capabilities(struct avdtp *session,
>         service = avdtp_get_codec(setup->rsep->sep);
>         codec = (struct avdtp_media_codec_capability *) service->data;
>
> -       err = sep->endpoint->select_configuration(sep, codec->data,
> +       err = setup->sep->endpoint->select_configuration(setup->sep,
> +                                       codec->data,
>                                         service->length - sizeof(*codec),
>                                         setup_ref(setup),
> -                                       select_cb, sep->user_data);
> +                                       select_cb, setup->sep->user_data);
>         if (err == 0)
>                 return cb_data->id;
>
> --
> 2.20.1

Le me know if you find any problem with this change, my headsets seems
to always succeed the first try so I cannot really reproduce the
problem.


-- 
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