INT32 PORT_GetPortMixerDescription(INT32 mixerIndex, PortMixerDescription* description) {
    snd_ctl_t* handle;
    snd_ctl_card_info_t* card_info;
    char devname[16];
    int err;
    char buffer[100];

    TRACE0("> PORT_GetPortMixerDescription\n");
    snd_ctl_card_info_malloc(&card_info);

    sprintf(devname, ALSA_HARDWARE_CARD, (int) mixerIndex);
    TRACE1("Opening alsa device \"%s\"...\n", devname);
    err = snd_ctl_open(&handle, devname, 0);
    if (err < 0) {
        ERROR2("ERROR: snd_ctl_open, card=%d: %s\n", (int) mixerIndex, snd_strerror(err));
        return FALSE;
    }
    err = snd_ctl_card_info(handle, card_info);
    if (err < 0) {
        ERROR2("ERROR: snd_ctl_card_info, card=%d: %s\n", (int) mixerIndex, snd_strerror(err));
    }
    strncpy(description->name, snd_ctl_card_info_get_id(card_info), PORT_STRING_LENGTH - 1);
    sprintf(buffer, " [%s]", devname);
    strncat(description->name, buffer, PORT_STRING_LENGTH - 1 - strlen(description->name));
    strncpy(description->vendor, "ALSA (http://www.alsa-project.org)", PORT_STRING_LENGTH - 1);
    strncpy(description->description, snd_ctl_card_info_get_name(card_info), PORT_STRING_LENGTH - 1);
    strncat(description->description, ", ", PORT_STRING_LENGTH - 1 - strlen(description->description));
    strncat(description->description, snd_ctl_card_info_get_mixername(card_info), PORT_STRING_LENGTH - 1 - strlen(description->description));
    getALSAVersion(description->version, PORT_STRING_LENGTH - 1);

    snd_ctl_close(handle);
    snd_ctl_card_info_free(card_info);
    TRACE0("< PORT_GetPortMixerDescription\n");
    return TRUE;
}
int deviceInfoIterator(UINT32 deviceID, snd_pcm_info_t* pcminfo,
                       snd_ctl_card_info_t* cardinfo, void* userData) {
    char buffer[300];
    ALSA_AudioDeviceDescription* desc = (ALSA_AudioDeviceDescription*)userData;
#ifdef ALSA_PCM_USE_PLUGHW
    int usePlugHw = 1;
#else
    int usePlugHw = 0;
#endif

    initAlsaSupport();
    if (desc->index == 0) {
        // we found the device with correct index
        *(desc->maxSimultaneousLines) = needEnumerateSubdevices(ALSA_PCM) ?
                1 : snd_pcm_info_get_subdevices_count(pcminfo);
        *desc->deviceID = deviceID;
        buffer[0]=' '; buffer[1]='[';
        // buffer[300] is enough to store the actual device string w/o overrun
        getDeviceStringFromDeviceID(&buffer[2], deviceID, usePlugHw, ALSA_PCM);
        strncat(buffer, "]", sizeof(buffer) - strlen(buffer) - 1);
        strncpy(desc->name,
                (cardinfo != NULL)
                    ? snd_ctl_card_info_get_id(cardinfo)
                    : snd_pcm_info_get_id(pcminfo),
                desc->strLen - strlen(buffer));
        strncat(desc->name, buffer, desc->strLen - strlen(desc->name));
        strncpy(desc->vendor, "ALSA (http://www.alsa-project.org)", desc->strLen);
        strncpy(desc->description,
                (cardinfo != NULL)
                    ? snd_ctl_card_info_get_name(cardinfo)
                    : snd_pcm_info_get_name(pcminfo),
                desc->strLen);
        strncat(desc->description, ", ", desc->strLen - strlen(desc->description));
        strncat(desc->description, snd_pcm_info_get_id(pcminfo), desc->strLen - strlen(desc->description));
        strncat(desc->description, ", ", desc->strLen - strlen(desc->description));
        strncat(desc->description, snd_pcm_info_get_name(pcminfo), desc->strLen - strlen(desc->description));
        getALSAVersion(desc->version, desc->strLen);
        TRACE4("Returning %s, %s, %s, %s\n", desc->name, desc->vendor, desc->description, desc->version);
        return FALSE; // do not continue iteration
    }
    desc->index--;
    return TRUE;
}
int getMidiDeviceVersion(int index, char *name, UINT32 nameLength) {
    getALSAVersion(name, nameLength);
    return MIDI_SUCCESS;
}