alsa-lib's new API issue (snd_ctl_elem_id_compare)

Takashi Sakamoto o-takashi at sakamocchi.jp
Fri Mar 12 02:35:17 CET 2021


On Thu, Mar 11, 2021 at 02:22:45PM +0100, Jaroslav Kysela wrote:
> > Hm. I believe that you agree with the fact that we can make various
> > algorithms to compare a pair of IDs for control elements. When focusing
> > on fields except for numid, we can make the other algorithms against your
> > implementation, since the ID structure is compound one. Each of the
> > algorithms can return different result.
> > 
> > Here, I'd like to shift the discussion to the name of new API. Although it
> > has the most common name, 'snd_ctl_id_compare', it just has one of
> > comparison algorithms. I have a concern that the name can gives wrong idea
> > to users that the ID structure for control element had design to be able to
> > be compared by itself and it would just be a single comparison algorithm.
> > 
> > I suggest to rename the new API to express that it implements one of
> > comparison algorithm. In a case of numid comparison, it would be
> > 'snd_ctl_id_compare_by_numid()'. For your case,
> > 'snd_ctl_id_compare_by_name_arithmetic' or something suitable.
> 
> Perhaps, we can add a third argument defining the sorting algorithm, so we
> don't bloat the symbol tables so much when we add a new sorting type (enum).
> It would mean that the function cannot be used as a direct argument to
> qsort(), but I think that the apps add usually an extra code to own callback
> depending on containers, anyway. Is it more appropriate for you?

I've already investigated the idea you describe, however I concluded
that it has more complexity than convenience.

For example, the prototype would be:

```
int new_api(const snd_ctl_elem_id_t *l, const snd_ctl_elem_id_t *r,
            int (*algorithm)(const snd_ctl_elem_id_t *,
                             const snd_ctl_elem_id_t *));
```

For usage with qsort_r(3), programmer should do:

```
int my_algo(const snd_ctl_elem_id_t *l, snd_ctl_elem_id_t *r)
{
   ...
}

qsort_r(base, nmemb, size, new_api, my_algo);
```

On the other hand, the API has name to express itself appropriately and
we have some of such APIs:

```
int the_api_by_algo_a(const snd_ctl_elem_id_t *l,
                      const snd_ctl_elem_id_t *r);
int the_api_by_algo_b(const snd_ctl_elem_id_t *l,
                      const snd_ctl_elem_id_t *r);
int the_api_by_algo_c(const snd_ctl_elem_id_t *l,
                      const snd_ctl_elem_id_t *r);
...
```

The programmer selects one of them, then:

```
qsort(base, nmemb, size, the_api_by_algo_a);
```

Or select one of them dynamically if need:

```
int (*algo)(const snd_ctl_elem_id_t *, const snd_ctl_elem_id_t *);

switch (cond) {
case A:
    algo = the_api_by_algo_a;
    break;
case B:
    algo = the_api_by_algo_b;
    break;
case C:
    algo = the_api_by_algo_c;
    break;
default:
    return -EINVAL;
}

qsort(base, nmemb, size, algo);
```

For the case of hctl/mixer container about which you mentioned,
qsort_r(3) style is convenient for the case that programmer need to
re-implement own comparison algorithm. However the decision is still
up to the programmer, in short:

```
int my_algo(const snd_ctl_elem_id_t *l,
            const snd_ctl_elem_id_t *r,
            void *arg);
qsort_r(base, nmemb, size, my_algo, my_arg);
```

Here, I think it more worth to share algorithms than keeping less entries
in symbol table in shared library. Just the thought of it, I can devise
some algorithms below:

 * by numid
 * by name arithmetic (=your implementation)
 * by the words 'playback' and 'capture', case-insensitive or sensitive
 * by device and subdevice


Regards

Takashi Sakamoto


More information about the Alsa-devel mailing list