alsa: more tapdancing to enumerate physical hardware devices.
authorRyan C. Gordon <icculus@icculus.org>
Mon, 10 Oct 2016 15:29:18 -0400
changeset 1050684611383c7ef
parent 10505 fd70d94948bc
child 10507 fe2700e08d39
alsa: more tapdancing to enumerate physical hardware devices.

Apparently some systems see "hw:", some see "default:" and some see
"sysdefault:" (and maybe others!). My workstation sees both "hw:" and
"sysdefault:" ...

Try to find a prefix we like and prioritize the prefixes we (think) we want
most. If everything else fails, if there's a "default" (not a prefix) device
name, list that by itself so the user gets _something_ here.

If we can't find a prefix we like _and_ there's no "default" device, report
no hardware found at all.
src/audio/alsa/SDL_alsa_audio.c
     1.1 --- a/src/audio/alsa/SDL_alsa_audio.c	Mon Oct 10 02:58:29 2016 -0700
     1.2 +++ b/src/audio/alsa/SDL_alsa_audio.c	Mon Oct 10 15:29:18 2016 -0400
     1.3 @@ -773,23 +773,40 @@
     1.4              ALSA_Device *unseen = devices;
     1.5              ALSA_Device *seen = NULL;
     1.6              ALSA_Device *prev;
     1.7 -            int i;
     1.8 -            const char *match = "default:";
     1.9 -            size_t match_len = strlen(match);
    1.10 +            int i, j;
    1.11 +            const char *match = NULL;
    1.12 +            int bestmatch = 0xFFFF;
    1.13 +            size_t match_len = 0;
    1.14 +            int defaultdev = -1;
    1.15 +            static const char * const prefixes[] = {
    1.16 +                "hw:", "sysdefault:", "default:", NULL
    1.17 +            };
    1.18  
    1.19 -            /* determine what kind of name to match.  Use "hw:" devices if they
    1.20 -               exist, otherwise use "default:" */
    1.21 +            /* Apparently there are several different ways that ALSA lists
    1.22 +               actual hardware. It could be prefixed with "hw:" or "default:"
    1.23 +               or "sysdefault:" and maybe others. Go through the list and see
    1.24 +               if we can find a preferred prefix for the system. */
    1.25              for (i = 0; hints[i]; i++) {
    1.26                  char *name = ALSA_snd_device_name_get_hint(hints[i], "NAME");
    1.27                  if (!name) {
    1.28                      continue;
    1.29                  }
    1.30  
    1.31 -                if (SDL_strncmp(name, "hw:", 3) == 0) {
    1.32 -                    match = "hw:";
    1.33 -                    match_len = strlen(match);
    1.34 -                    free(name);
    1.35 -                    break;
    1.36 +                /* full name, not a prefix */
    1.37 +                if ((defaultdev == -1) && (SDL_strcmp(name, "default") == 0)) {
    1.38 +                    defaultdev = i;
    1.39 +                }
    1.40 +
    1.41 +                for (j = 0; prefixes[j]; j++) {
    1.42 +                    const char *prefix = prefixes[j];
    1.43 +                    const size_t prefixlen = strlen(prefix);
    1.44 +                    if (SDL_strncmp(name, prefix, prefixlen) == 0) {
    1.45 +                        if (j < bestmatch) {
    1.46 +                            bestmatch = j;
    1.47 +                            match = prefix;
    1.48 +                            match_len = prefixlen;
    1.49 +                        }
    1.50 +                    }
    1.51                  }
    1.52  
    1.53                  free(name);
    1.54 @@ -797,13 +814,20 @@
    1.55  
    1.56              /* look through the list of device names to find matches */
    1.57              for (i = 0; hints[i]; i++) {
    1.58 -                char *name = ALSA_snd_device_name_get_hint(hints[i], "NAME");
    1.59 +                char *name;
    1.60 +
    1.61 +                /* if we didn't find a device name prefix we like at all... */
    1.62 +                if ((!match) && (defaultdev != i)) {
    1.63 +                    continue;  /* ...skip anything that isn't the default device. */
    1.64 +                }
    1.65 +
    1.66 +                name = ALSA_snd_device_name_get_hint(hints[i], "NAME");
    1.67                  if (!name) {
    1.68                      continue;
    1.69                  }
    1.70  
    1.71                  /* only want physical hardware interfaces */
    1.72 -                if (SDL_strncmp(name, match, match_len) == 0) {
    1.73 +                if (!match || (SDL_strncmp(name, match, match_len) == 0)) {
    1.74                      char *ioid = ALSA_snd_device_name_get_hint(hints[i], "IOID");
    1.75                      const SDL_bool isoutput = (ioid == NULL) || (SDL_strcmp(ioid, "Output") == 0);
    1.76                      const SDL_bool isinput = (ioid == NULL) || (SDL_strcmp(ioid, "Input") == 0);