Skip to content

Commit

Permalink
Sort ALSA control elements by internal rules
Browse files Browse the repository at this point in the history
Please note, that this commit changes ordering of ALSA low level
control interface. Most applications use high level control interface
which sorts control elements by itself. It is most likely that in
such applications control elements will be ordered by name.
  • Loading branch information
arkq committed Jul 13, 2022
1 parent 6ca3deb commit ed63ab0
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 27 deletions.
36 changes: 31 additions & 5 deletions src/asound/bluealsa-ctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,19 @@
#include "shared/dbus-client.h"
#include "shared/defs.h"

/**
* Control element type.
*
* Note: The order of enum values is important - it
* determines control elements ordering. */
enum ctl_elem_type {
CTL_ELEM_TYPE_BATTERY,
CTL_ELEM_TYPE_SWITCH,
CTL_ELEM_TYPE_VOLUME,
CTL_ELEM_TYPE_BATTERY,
};

/**
* Control element. */
struct ctl_elem {
enum ctl_elem_type type;
struct bt_dev *dev;
Expand Down Expand Up @@ -132,10 +139,29 @@ static int bluealsa_elem_cmp(const void *p1, const void *p2) {
const struct ctl_elem *e2 = (const struct ctl_elem *)p2;
int rv;

if ((rv = strcmp(e1->name, e2->name)) == 0)
rv = bacmp(&e1->pcm->addr, &e2->pcm->addr);
/* Sort elements by device names. In case were names
* are the same sort by device addresses. */
if ((rv = bacmp(&e1->pcm->addr, &e2->pcm->addr)) != 0) {
const int dev_rv = strcmp(e1->dev->name, e2->dev->name);
return dev_rv != 0 ? dev_rv : rv;
}

return rv;
/* Within a single device order elements by:
* - element type (keep battery last)
* - PCM transport type
* - playback/capture
* - element type
* */
if (e1->type == CTL_ELEM_TYPE_BATTERY ||
e2->type == CTL_ELEM_TYPE_BATTERY)
return e1->type - e2->type;
if ((rv = e1->pcm->transport - e2->pcm->transport))
return rv;
if ((rv = e1->playback - e2->playback) != 0)
return -rv;
if ((rv = e1->type - e2->type) != 0)
return rv;
return 0;
}

static DBusMessage *bluealsa_dbus_get_property(DBusConnection *conn,
Expand Down Expand Up @@ -552,7 +578,7 @@ static int bluealsa_create_elem_list(struct bluealsa_ctl *ctl) {

}

/* Sort control elements alphabetically. */
/* Sort control elements according to our sorting rules. */
qsort(elem_list, count, sizeof(*elem_list), bluealsa_elem_cmp);

/* Detect element name duplicates and annotate them with the
Expand Down
44 changes: 22 additions & 22 deletions test/test-alsa-ctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -103,21 +103,21 @@ START_TEST(test_controls) {

ck_assert_int_eq(snd_ctl_elem_list_get_used(elems), 13);

ck_assert_str_eq(snd_ctl_elem_list_get_name(elems, 0), "12:34:56:78:9A:BC - A2DP Capture Switch");
ck_assert_str_eq(snd_ctl_elem_list_get_name(elems, 1), "12:34:56:78:9A:BC - A2DP Capture Volume");
ck_assert_str_eq(snd_ctl_elem_list_get_name(elems, 2), "12:34:56:78:9A:BC - A2DP Playback Switch");
ck_assert_str_eq(snd_ctl_elem_list_get_name(elems, 3), "12:34:56:78:9A:BC - A2DP Playback Volume");

ck_assert_str_eq(snd_ctl_elem_list_get_name(elems, 4), "12:34:56:78:9A:BC - SCO Capture Switch");
ck_assert_str_eq(snd_ctl_elem_list_get_name(elems, 5), "12:34:56:78:9A:BC - SCO Capture Volume");
ck_assert_str_eq(snd_ctl_elem_list_get_name(elems, 6), "12:34:56:78:9A:BC - SCO Playback Switch");
ck_assert_str_eq(snd_ctl_elem_list_get_name(elems, 7), "12:34:56:78:9A:BC - SCO Playback Volume");
ck_assert_str_eq(snd_ctl_elem_list_get_name(elems, 0), "12:34:56:78:9A:BC - A2DP Playback Switch");
ck_assert_str_eq(snd_ctl_elem_list_get_name(elems, 1), "12:34:56:78:9A:BC - A2DP Playback Volume");
ck_assert_str_eq(snd_ctl_elem_list_get_name(elems, 2), "12:34:56:78:9A:BC - A2DP Capture Switch");
ck_assert_str_eq(snd_ctl_elem_list_get_name(elems, 3), "12:34:56:78:9A:BC - A2DP Capture Volume");

ck_assert_str_eq(snd_ctl_elem_list_get_name(elems, 4), "12:34:56:78:9A:BC - SCO Playback Switch");
ck_assert_str_eq(snd_ctl_elem_list_get_name(elems, 5), "12:34:56:78:9A:BC - SCO Playback Volume");
ck_assert_str_eq(snd_ctl_elem_list_get_name(elems, 6), "12:34:56:78:9A:BC - SCO Capture Switch");
ck_assert_str_eq(snd_ctl_elem_list_get_name(elems, 7), "12:34:56:78:9A:BC - SCO Capture Volume");
ck_assert_str_eq(snd_ctl_elem_list_get_name(elems, 8), "12:34:56:78:9A:BC | Battery Playback Volume");

ck_assert_str_eq(snd_ctl_elem_list_get_name(elems, 9), "23:45:67:89:AB:CD - A2DP Capture Switch");
ck_assert_str_eq(snd_ctl_elem_list_get_name(elems, 10), "23:45:67:89:AB:CD - A2DP Capture Volume");
ck_assert_str_eq(snd_ctl_elem_list_get_name(elems, 11), "23:45:67:89:AB:CD - A2DP Playback Switch");
ck_assert_str_eq(snd_ctl_elem_list_get_name(elems, 12), "23:45:67:89:AB:CD - A2DP Playback Volume");
ck_assert_str_eq(snd_ctl_elem_list_get_name(elems, 9), "23:45:67:89:AB:CD - A2DP Playback Switch");
ck_assert_str_eq(snd_ctl_elem_list_get_name(elems, 10), "23:45:67:89:AB:CD - A2DP Playback Volume");
ck_assert_str_eq(snd_ctl_elem_list_get_name(elems, 11), "23:45:67:89:AB:CD - A2DP Capture Switch");
ck_assert_str_eq(snd_ctl_elem_list_get_name(elems, 12), "23:45:67:89:AB:CD - A2DP Capture Volume");

ck_assert_int_eq(test_pcm_close(pid, ctl), 0);

Expand Down Expand Up @@ -148,8 +148,8 @@ START_TEST(test_device_name_duplicates) {
ck_assert_int_eq(snd_ctl_elem_list(ctl, elems), 0);

ck_assert_str_eq(snd_ctl_elem_list_get_name(elems, 0), "Long Bluetooth #1 - A2DP Playback Switch");
ck_assert_str_eq(snd_ctl_elem_list_get_name(elems, 1), "Long Bluetooth #2 - A2DP Playback Switch");
ck_assert_str_eq(snd_ctl_elem_list_get_name(elems, 2), "Long Bluetooth #1 - A2DP Playback Volume");
ck_assert_str_eq(snd_ctl_elem_list_get_name(elems, 1), "Long Bluetooth #1 - A2DP Playback Volume");
ck_assert_str_eq(snd_ctl_elem_list_get_name(elems, 2), "Long Bluetooth #2 - A2DP Playback Switch");
ck_assert_str_eq(snd_ctl_elem_list_get_name(elems, 3), "Long Bluetooth #2 - A2DP Playback Volume");

ck_assert_int_eq(test_pcm_close(pid, ctl), 0);
Expand All @@ -167,7 +167,7 @@ START_TEST(test_mute_and_volume) {
snd_ctl_elem_value_t *elem_switch;
snd_ctl_elem_value_alloca(&elem_switch);
/* 23:45:67:89:AB:CD - A2DP Playback Switch */
snd_ctl_elem_value_set_numid(elem_switch, 12);
snd_ctl_elem_value_set_numid(elem_switch, 10);

ck_assert_int_eq(snd_ctl_elem_read(ctl, elem_switch), 0);
ck_assert_int_eq(snd_ctl_elem_value_get_boolean(elem_switch, 0), 1);
Expand All @@ -180,7 +180,7 @@ START_TEST(test_mute_and_volume) {
snd_ctl_elem_value_t *elem_volume;
snd_ctl_elem_value_alloca(&elem_volume);
/* 23:45:67:89:AB:CD - A2DP Playback Volume */
snd_ctl_elem_value_set_numid(elem_volume, 13);
snd_ctl_elem_value_set_numid(elem_volume, 11);

ck_assert_int_eq(snd_ctl_elem_read(ctl, elem_volume), 0);
ck_assert_int_eq(snd_ctl_elem_value_get_integer(elem_volume, 0), 127);
Expand Down Expand Up @@ -209,7 +209,7 @@ START_TEST(test_volume_db_range) {
snd_ctl_elem_id_t *elem;
snd_ctl_elem_id_alloca(&elem);
/* 12:34:56:78:9A:BC - A2DP Playback Volume */
snd_ctl_elem_id_set_numid(elem, 4);
snd_ctl_elem_id_set_numid(elem, 2);

long min, max;
ck_assert_int_eq(snd_ctl_get_dB_range(ctl, elem, &min, &max), 0);
Expand Down Expand Up @@ -250,10 +250,10 @@ START_TEST(test_single_device) {
ck_assert_int_eq(snd_ctl_elem_list_alloc_space(elems, 4), 0);
ck_assert_int_eq(snd_ctl_elem_list(ctl, elems), 0);

ck_assert_str_eq(snd_ctl_elem_list_get_name(elems, 0), "A2DP Capture Switch");
ck_assert_str_eq(snd_ctl_elem_list_get_name(elems, 1), "A2DP Capture Volume");
ck_assert_str_eq(snd_ctl_elem_list_get_name(elems, 2), "A2DP Playback Switch");
ck_assert_str_eq(snd_ctl_elem_list_get_name(elems, 3), "A2DP Playback Volume");
ck_assert_str_eq(snd_ctl_elem_list_get_name(elems, 0), "A2DP Playback Switch");
ck_assert_str_eq(snd_ctl_elem_list_get_name(elems, 1), "A2DP Playback Volume");
ck_assert_str_eq(snd_ctl_elem_list_get_name(elems, 2), "A2DP Capture Switch");
ck_assert_str_eq(snd_ctl_elem_list_get_name(elems, 3), "A2DP Capture Volume");

ck_assert_int_eq(test_pcm_close(pid, ctl), 0);

Expand Down

0 comments on commit ed63ab0

Please sign in to comment.