Exemple #1
0
/**
 * Partly based on get_cards function in alsamixer.
 * This gets all alsa cards and fills the global
 * GSList 'cards'.
 * The list always starts with the 'default' card.
 */
static void
get_cards(void)
{
    int err, num;
    snd_ctl_card_info_t *info;
    snd_ctl_t *ctl;
    char buf[10];
    struct acard *cur_card, *default_card;

    if (cards != NULL)
        g_slist_free_full(cards, card_free);

    cards = NULL;

    default_card = g_malloc(sizeof(struct acard));
    default_card->name = g_strdup("(default)");
    default_card->dev = g_strdup("default");
    default_card->channels = get_channels("default");

    cards = g_slist_append(cards, default_card);

    // don't need to free this as it's alloca'd
    snd_ctl_card_info_alloca(&info);
    num = -1;
    for (;;) {
        err = snd_card_next(&num);
        if (err < 0) {
            report_error("Can't get sounds cards: %s", snd_strerror(err));
            return;
        }
        if (num < 0)
            break;
        sprintf(buf, "hw:%d", num);
        if (snd_ctl_open(&ctl, buf, 0) < 0)
            continue;
        err = snd_ctl_card_info(ctl, info);
        snd_ctl_close(ctl);
        if (err < 0)
            continue;
        cur_card = g_malloc(sizeof(struct acard));
        cur_card->name = g_strdup(snd_ctl_card_info_get_name(info));
        sprintf(buf, "hw:%d", num);
        cur_card->dev = g_strdup(buf);
        cur_card->channels = get_channels(buf);
        cards = g_slist_append(cards, cur_card);
    }
#ifdef DEBUG
    GSList *tmp = cards;
    if (tmp) {
        printf("------ Card list ------\n");
        while (tmp) {
            struct acard *c = tmp->data;
            printf("\t%s\t%s\t%s\n", c->dev, c->name,
                   c->channels ? "" : "No chann");
            tmp = tmp->next;
        }
        printf("-----------------------\n");
    }
#endif
}
Exemple #2
0
static int cards(lua_State *lstate) {
	snd_ctl_t *handle;
	int ret, card, ord;
	char buf[32];
	snd_ctl_card_info_t *info;
	snd_ctl_card_info_alloca(&info);
	ord = 1;
	card = -1;
	lua_newtable(lstate);
	while (1) {
		if ((snd_card_next(&card) < 0) || (card < 0)) break;
		sprintf(buf, "hw:%d", card);
		if ((ret = snd_ctl_open(&handle, buf, 0)) < 0) {
			logmsg("control open: %s\n", snd_strerror(ret));
			continue;
			}
		if ((ret = snd_ctl_card_info(handle, info)) < 0) {
			logmsg("control info: %s\n", snd_strerror(ret));
			continue;
			}
		lua_pushinteger(lstate, ord++);
		lua_newtable(lstate);
		set_string(lstate, "dev", buf);
		set_string(lstate, "name",
				snd_ctl_card_info_get_name(info));
		lua_settable(lstate, -3);
		snd_ctl_close(handle);
		//view_card(buf);
		}
	return 1;
	}
Exemple #3
0
static PyObject *
pyalsacontrol_cardinfo(struct pyalsacontrol *self, PyObject *args)
{
	snd_ctl_card_info_t *info;
	PyObject *d;

	snd_ctl_card_info_alloca(&info);
	int err = snd_ctl_card_info(self->handle, info);
	if (err < 0) {
		PyErr_Format(PyExc_IOError,
		     "Control card info error: %s", strerror(-err));
		return NULL;
	}
	d = PyDict_New();
	if (d) {
		PyDict_SetItem(d, PyString_FromString("card"), PyInt_FromLong(snd_ctl_card_info_get_card(info)));
		PyDict_SetItem(d, PyString_FromString("id"), PyString_FromString(snd_ctl_card_info_get_id(info)));
		PyDict_SetItem(d, PyString_FromString("driver"), PyString_FromString(snd_ctl_card_info_get_driver(info)));
		PyDict_SetItem(d, PyString_FromString("name"), PyString_FromString(snd_ctl_card_info_get_driver(info)));
		PyDict_SetItem(d, PyString_FromString("longname"), PyString_FromString(snd_ctl_card_info_get_longname(info)));
		PyDict_SetItem(d, PyString_FromString("mixername"), PyString_FromString(snd_ctl_card_info_get_mixername(info)));
		PyDict_SetItem(d, PyString_FromString("components"), PyString_FromString(snd_ctl_card_info_get_components(info)));
	}
	return d;
}
Exemple #4
0
static SCM alsa_cards(void) {
	// compile list of available cards
	int card;
	char buf[32];
	char *pt;
	SCM list, alist;
	snd_ctl_card_info_t *info;
	snd_ctl_card_info_alloca(&info);
	card = -1;
	list = SCM_EOL;
	while (1) {
		if ((snd_card_next(&card) < 0) || (card < 0)) break;
		sprintf(buf, "hw:%d", card);
		alist = SCM_EOL;
		alist = scm_assq_set_x(alist, SYM("dev"),
					scm_from_locale_string(buf));
		snd_card_get_name(card, &pt);
		alist = scm_assq_set_x(alist, SYM("name"),
					scm_take_locale_string(pt));
		list = scm_cons(alist, list);
		scm_remember_upto_here_1(alist);
		}
	scm_remember_upto_here_1(list);
	return list;
	}
Exemple #5
0
int main(int argc, char **argv)
{
   register int  err;
   int           cardNum;

   // Start with first card
   cardNum = -1;

   for (;;)
   {
      snd_ctl_t *cardHandle;

      // Get next sound card's card number. When "cardNum" == -1, then ALSA
      // fetches the first card
      if ((err = snd_card_next(&cardNum)) < 0)
      {
         printf("Can't get the next card number: %s\n", snd_strerror(err));
         break;
      }

      // No more cards? ALSA sets "cardNum" to -1 if so
      if (cardNum < 0) break;

      // Open this card's control interface. We specify only the card number -- not
      // any device nor sub-device too
      {
      char   str[64];

      sprintf(str, "hw:%i", cardNum);
      if ((err = snd_ctl_open(&cardHandle, str, 0)) < 0)
      {
         printf("Can't open card %i: %s\n", cardNum, snd_strerror(err));
         continue;
      }
      }

      {
      snd_ctl_card_info_t *cardInfo;

      // We need to get a snd_ctl_card_info_t. Just alloc it on the stack
      snd_ctl_card_info_alloca(&cardInfo);

      // Tell ALSA to fill in our snd_ctl_card_info_t with info about this card
      if ((err = snd_ctl_card_info(cardHandle, cardInfo)) < 0)
         printf("Can't get info for card %i: %s\n", cardNum, snd_strerror(err));
      else
         printf("Card %i = %s\n", cardNum, snd_ctl_card_info_get_name(cardInfo));
      }

      // Close the card's control interface after we're done with it
      snd_ctl_close(cardHandle);
   }

   // ALSA allocates some mem to load its config file when we call some of the
   // above functions. Now that we're done getting the info, let's tell ALSA
   // to unload the info and free up that mem
   snd_config_update_free_global();
}
Exemple #6
0
static char *ListAvailableDevices( demux_t *p_demux, bool b_probe )
{
    snd_ctl_card_info_t *p_info = NULL;
    snd_ctl_card_info_alloca( &p_info );

    snd_pcm_info_t *p_pcminfo = NULL;
    snd_pcm_info_alloca( &p_pcminfo );

    if( !b_probe )
        msg_Dbg( p_demux, "Available alsa capture devices:" );
    int i_card = -1;
    while( !snd_card_next( &i_card ) && i_card >= 0 )
    {
        char psz_devname[10];
        snprintf( psz_devname, 10, "hw:%d", i_card );

        snd_ctl_t *p_ctl = NULL;
        if( snd_ctl_open( &p_ctl, psz_devname, 0 ) < 0 ) continue;

        snd_ctl_card_info( p_ctl, p_info );
        if( !b_probe )
            msg_Dbg( p_demux, "  %s (%s)",
                     snd_ctl_card_info_get_id( p_info ),
                     snd_ctl_card_info_get_name( p_info ) );

        int i_dev = -1;
        while( !snd_ctl_pcm_next_device( p_ctl, &i_dev ) && i_dev >= 0 )
        {
            snd_pcm_info_set_device( p_pcminfo, i_dev );
            snd_pcm_info_set_subdevice( p_pcminfo, 0 );
            snd_pcm_info_set_stream( p_pcminfo, SND_PCM_STREAM_CAPTURE );
            if( snd_ctl_pcm_info( p_ctl, p_pcminfo ) < 0 ) continue;

            if( !b_probe )
                msg_Dbg( p_demux, "    hw:%d,%d : %s (%s)", i_card, i_dev,
                         snd_pcm_info_get_id( p_pcminfo ),
                         snd_pcm_info_get_name( p_pcminfo ) );
            else
            {
                char *psz_device;
                if( asprintf( &psz_device, "hw:%d,%d", i_card, i_dev ) > 0 )
                {
                    if( ProbeAudioDevAlsa( p_demux, psz_device ) )
                    {
                        snd_ctl_close( p_ctl );
                        return psz_device;
                    }
                    else
                        free( psz_device );
                }
            }
        }

        snd_ctl_close( p_ctl );
    }
    return NULL;
}
Exemple #7
0
bool MainWindowImpl::FindRadioshark(string& device)
{
	int card = -1;
	int dev = -1;
	
	snd_ctl_t *handle = NULL;
	snd_ctl_card_info_t *info = NULL;
	snd_pcm_info_t *pcminfo = NULL;
	snd_pcm_stream_t stream = SND_PCM_STREAM_CAPTURE;
	char card_id[32];
	char *name = NULL;

	snd_ctl_card_info_alloca (&info);
	snd_pcm_info_alloca (&pcminfo);

	if (snd_card_next (&card) < 0 || card < 0)
	{
		return false;
	}
	while(card >= 0)
	{
		snprintf (card_id, 32, "hw:%d", card);
		if (snd_ctl_open (&handle, card_id, 0) == 0)
		{
			snd_ctl_card_info (handle, info);
			while (1)
			{
				snd_ctl_pcm_next_device (handle, &dev);
				if (dev < 0){
					break;
				}
				snd_pcm_info_set_device (pcminfo, dev);
				snd_pcm_info_set_subdevice (pcminfo, 0);
				snd_pcm_info_set_stream (pcminfo, stream);
	
				if (snd_ctl_pcm_info (handle, pcminfo) >= 0)
				{
					snd_card_get_name (card, &name);
					if(strncmp(name,"radioSHARK",32) == 0)
					{void PokeScreensaver(void);
						snd_ctl_close(handle);
						free (name);
						snprintf (card_id, 32, "hw:%d,%d", card,dev);
						device = string(card_id);
						return true;
					}
					free (name);
				}
			}
			snd_ctl_close(handle);
		}
		snd_card_next (&card);
	}
	return false;//didn't find the proper Radioshark card.
}
Exemple #8
0
std::vector<HwIDPair>
AlsaLayer::getAudioDeviceIndexMap(bool getCapture) const
{
    snd_ctl_t* handle;
    snd_ctl_card_info_t *info;
    snd_pcm_info_t* pcminfo;
    snd_ctl_card_info_alloca(&info);
    snd_pcm_info_alloca(&pcminfo);

    int numCard = -1;

    std::vector<HwIDPair> audioDevice;

    if (snd_card_next(&numCard) < 0 || numCard < 0)
        return audioDevice;

    do {
        std::stringstream ss;
        ss << numCard;
        std::string name = "hw:" + ss.str();

        if (snd_ctl_open(&handle, name.c_str(), 0) == 0) {
            if (snd_ctl_card_info(handle, info) == 0) {
                snd_pcm_info_set_device(pcminfo, 0);
                snd_pcm_info_set_stream(pcminfo, getCapture ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK);

                int err;

                if ((err = snd_ctl_pcm_info(handle, pcminfo)) < 0) {
                    WARN("Cannot get info for %s %s: %s", getCapture ?
                         "capture device" : "playback device", name.c_str(),
                         snd_strerror(err));
                } else {
                    DEBUG("card %i : %s [%s]",
                          numCard,
                          snd_ctl_card_info_get_id(info),
                          snd_ctl_card_info_get_name(info));
                    std::string description = snd_ctl_card_info_get_name(info);
                    description.append(" - ");
                    description.append(snd_pcm_info_get_name(pcminfo));

                    // The number of the sound card is associated with a string description
                    audioDevice.push_back(HwIDPair(numCard, description));
                }
            }

            snd_ctl_close(handle);
        }
    } while (snd_card_next(&numCard) >= 0 && numCard >= 0);


    return audioDevice;
}
/**
 * ags_devout_list_cards:
 * @soundcard: the #AgsSoundcard
 * @card_id: alsa identifier
 * @card_name: card name
 *
 * List available soundcards.
 *
 * Since: 0.4
 */
void
ags_devout_list_cards(AgsSoundcard *soundcard,
		      GList **card_id, GList **card_name)
{
  snd_ctl_t *card_handle;
  snd_ctl_card_info_t *card_info;
  char *name;
  gchar *str;
  int card_num;
  int error;

  *card_id = NULL;
  *card_name = NULL;
  card_num = -1;

  while(TRUE){
    error = snd_card_next(&card_num);

    if(card_num < 0){
      break;
    }

    if(error < 0){
      continue;
    }

    str = g_strdup_printf("hw:%i\0", card_num);
    error = snd_ctl_open(&card_handle, str, 0);

    if(error < 0){
      continue;
    }

    snd_ctl_card_info_alloca(&card_info);
    error = snd_ctl_card_info(card_handle, card_info);

    if(error < 0){
      continue;
    }

    *card_id = g_list_prepend(*card_id, str);
    *card_name = g_list_prepend(*card_name, g_strdup(snd_ctl_card_info_get_name(card_info)));

    snd_ctl_close(card_handle);
  }

  snd_config_update_free_global();

  *card_id = g_list_reverse(*card_id);
  *card_name = g_list_reverse(*card_name);
}
Exemple #10
0
const std::string AlsaWork::getCardName(int index)
{
	const std::string card(AlsaDevice::formatCardName(index));
	snd_ctl_t *ctl;
	int err = snd_ctl_open(&ctl, card.c_str(), SND_CTL_NONBLOCK);
	if (err < 0) {
		checkError(err);
		return std::string();
	}
	snd_ctl_card_info_t *cardInfo;
	snd_ctl_card_info_alloca(&cardInfo);
	err = snd_ctl_card_info(ctl, cardInfo);
	if (err < 0) {
		checkError(err);
		return std::string();
	}
	const std::string cardName = snd_ctl_card_info_get_name(cardInfo);
	checkError(snd_ctl_close(ctl));
	return cardName;
}
Exemple #11
0
void list_cards(void)
{
    snd_ctl_card_info_t *p_info = NULL;
    snd_ctl_card_info_alloca(&p_info);

    snd_pcm_info_t *p_pcminfo = NULL;
    snd_pcm_info_alloca(&p_pcminfo);

    printf("Availible alsa capture devices:\n");

    int i_card = -1;
    while (!snd_card_next(&i_card) && i_card >= 0)
    {
        char devname[10];
        snprintf( devname, 10, "hw:%d", i_card );

        snd_ctl_t *p_ctl = NULL;
        if ( snd_ctl_open( &p_ctl, devname, 0 ) < 0) continue;

        snd_ctl_card_info( p_ctl, p_info);
        printf("\t%s (%s)\n", snd_ctl_card_info_get_id(p_info), snd_ctl_card_info_get_name(p_info));

        int i_dev = -1;
        while (!snd_ctl_pcm_next_device(p_ctl, &i_dev) && i_dev >= 0)
        {
            snd_pcm_info_set_device(p_pcminfo, i_dev);
            snd_pcm_info_set_subdevice(p_pcminfo, 0);
            snd_pcm_info_set_stream(p_pcminfo, SND_PCM_STREAM_CAPTURE);

            if (snd_ctl_pcm_info(p_ctl, p_pcminfo) < 0) continue;

            printf("\t\thw:%d,%d : %s (%s)\n", i_card, i_dev, 
                    snd_pcm_info_get_id(p_pcminfo), 
                    snd_pcm_info_get_name(p_pcminfo));
        }

        snd_ctl_close(p_ctl);
    }

}
Exemple #12
0
static void
as_setup_card_combo (GtkWidget *combo , SoundParams *sparams)
{
   int card;
   int i ;
   int err;
   snd_ctl_t *handle;
   snd_ctl_card_info_t *info;
   char name[32];
   
   gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), "- default");
   
   snd_ctl_card_info_alloca(&info);
   sparams->firstcard = -1;
   card = -1;
   for( i = 0 ;   ; i++ ){
      if (snd_card_next(&card) < 0 || card < 0) {
	 if ( i == 0 ) {
	    msg_error(_("no soundcards found..."));
	 }
	 return;
      }
      if ( sparams->firstcard < 0 ) {
	  sparams->firstcard = card;
      }
      sprintf(name, "hw:%d", card);
      if ((err = snd_ctl_open(&handle, name, 0)) < 0) {
	 msg_error(_("control open (%i): %s"), card, snd_strerror(err));
	 continue;
      }
      if ((err = snd_ctl_card_info(handle, info)) < 0) {
	 msg_error(_("control hardware info (%i): %s"), card, snd_strerror(err));
	 snd_ctl_close(handle);
	 continue;
      }
      sprintf(name, "%d %s", card,  snd_ctl_card_info_get_name(info) );
      gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), name );
      snd_ctl_close(handle);
   }
}
Exemple #13
0
static int card_to_num(const char* device)
{
    int err;
    char* ctl_name;
    snd_ctl_card_info_t *card_info;
    snd_ctl_t* ctl_handle;
    int i = -1;

    snd_ctl_card_info_alloca (&card_info);

    ctl_name = get_control_device_name(device);
    if (ctl_name == NULL) {
        jack_error("get_control_device_name() failed.");
        goto fail;
    }

    if ((err = snd_ctl_open (&ctl_handle, ctl_name, 0)) < 0) {
        jack_error ("control open \"%s\" (%s)", ctl_name,
                    snd_strerror(err));
        goto free;
    }

    if ((err = snd_ctl_card_info(ctl_handle, card_info)) < 0) {
        jack_error ("control hardware info \"%s\" (%s)",
                    device, snd_strerror (err));
        goto close;
    }

    i = snd_ctl_card_info_get_card(card_info);

close:
    snd_ctl_close(ctl_handle);

free:
    free(ctl_name);

fail:
    return i;
}
Exemple #14
0
void SoundPref::getHwList(int mode)
{
	snd_ctl_t *handle;
	int card, err;
	//int dev;

	snd_ctl_card_info_t *info;
	//snd_pcm_info_t *pcminfo;

	snd_ctl_card_info_alloca(&info);
	//snd_pcm_info_alloca(&pcminfo);

	card = -1;
	if (snd_card_next(&card) < 0 || card < 0) {
		qDebug() << "no soundcards found ...";
		return;
	}

	while (card >= 0) {
		QString hwName = QString("hw:%1").arg(card);
		if ((err = snd_ctl_open(&handle, strdup(hwName.toAscii().data()), 0)) < 0) {
			qDebug() << "Error while opening (" << card << "): " << card, snd_strerror(err);
			if (snd_card_next(&card) < 0) {
				// no more cards
				break;
			} else continue;

		}
		if ((err = snd_ctl_card_info(handle, info)) < 0) {
			qDebug() << "Error while getting hardware info (" << card << "):" << snd_strerror(err);
			snd_ctl_close(handle);
			if (snd_card_next(&card) < 0) {
				// no more cards
				break;
			} else continue;
		}

/*
		dev = -1;
		int indx = 0;
		while (1) {
			if (snd_ctl_pcm_next_device(handle, &dev) < 0)
				qDebug() << "no devices found ...";
			if (dev < 0)
				break;

			snd_pcm_info_set_device(pcminfo, dev);
			snd_pcm_info_set_subdevice(pcminfo, 0);
			snd_pcm_info_set_stream(pcminfo, SND_PCM_STREAM_PLAYBACK);

			if ((err = snd_ctl_pcm_info(handle, pcminfo)) < 0) {
				if (err != -ENOENT)
					qDebug() << "error while getting digital audio info (" << card << "): "
						 << snd_strerror(err);
				continue;
			}

			hwDeviceInfo *hw = new hwDeviceInfo;
			hw->hwName = hwName;
			hw->card = card;
			hw->cardName = snd_ctl_card_info_get_name(info);
			hw->device = dev;
			hw->deviceName = snd_pcm_info_get_name(pcminfo);
			hwList->append(hw);
			indx ++;

			// append to selection list (ui)
			QListWidgetItem *it = new QListWidgetItem(hw->fullName(), ui.devicesLst);
			it->setData(Qt::UserRole, QVariant(indx));
			qDebug() << "inserting one card item";
		}
*/

		hwDeviceInfo *hw = new hwDeviceInfo;
		hw->card = card;
		hw->cardName = snd_ctl_card_info_get_name(info);

		hwList->insert(hwName, hw);

		QListWidgetItem *it = new QListWidgetItem(hw->cardName, ui.playbackDevicesLst);
		it->setData(Qt::UserRole, QVariant(hwName));

		if (hwName == mixerCard) {
			// select this item if it is default
			it->setSelected(true);
		}

		snd_ctl_close(handle);

		if (snd_card_next(&card) < 0) {
			// no more cards
			break;
		} else continue;
	}

	//snd_pcm_info_free(pcminfo);
	//snd_ctl_card_info_free(info);
}
Exemple #15
0
static
jack_driver_param_constraint_desc_t *
enum_alsa_devices()
{
    snd_ctl_t * handle;
    snd_ctl_card_info_t * info;
    snd_pcm_info_t * pcminfo_capture;
    snd_pcm_info_t * pcminfo_playback;
    int card_no = -1;
    char card_id[JACK_DRIVER_PARAM_STRING_MAX + 1];
    char device_id[JACK_DRIVER_PARAM_STRING_MAX + 1];
    char description[64];
    int device_no;
    bool has_capture;
    bool has_playback;
    jack_driver_param_constraint_desc_t * constraint_ptr;
    uint32_t array_size = 0;

    snd_ctl_card_info_alloca(&info);
    snd_pcm_info_alloca(&pcminfo_capture);
    snd_pcm_info_alloca(&pcminfo_playback);

    constraint_ptr = NULL;

    while(snd_card_next(&card_no) >= 0 && card_no >= 0)
    {
        snprintf(card_id, sizeof(card_id), "hw:%d", card_no);

        if (snd_ctl_open(&handle, card_id, 0) >= 0 &&
            snd_ctl_card_info(handle, info) >= 0)
        {
            fill_device(&constraint_ptr, &array_size, card_id, snd_ctl_card_info_get_name(info));

            device_no = -1;

            while (snd_ctl_pcm_next_device(handle, &device_no) >= 0 && device_no != -1)
            {
                snprintf(device_id, sizeof(device_id), "%s,%d", card_id, device_no);

                snd_pcm_info_set_device(pcminfo_capture, device_no);
                snd_pcm_info_set_subdevice(pcminfo_capture, 0);
                snd_pcm_info_set_stream(pcminfo_capture, SND_PCM_STREAM_CAPTURE);
                has_capture = snd_ctl_pcm_info(handle, pcminfo_capture) >= 0;

                snd_pcm_info_set_device(pcminfo_playback, device_no);
                snd_pcm_info_set_subdevice(pcminfo_playback, 0);
                snd_pcm_info_set_stream(pcminfo_playback, SND_PCM_STREAM_PLAYBACK);
                has_playback = snd_ctl_pcm_info(handle, pcminfo_playback) >= 0;

                if (has_capture && has_playback)
                {
                    snprintf(description, sizeof(description),"%s (duplex)", snd_pcm_info_get_name(pcminfo_capture));
                }
                else if (has_capture)
                {
                    snprintf(description, sizeof(description),"%s (capture)", snd_pcm_info_get_name(pcminfo_capture));
                }
                else if (has_playback)
                {
                    snprintf(description, sizeof(description),"%s (playback)", snd_pcm_info_get_name(pcminfo_playback));
                }
                else
                {
                    continue;
                }

                fill_device(&constraint_ptr, &array_size, device_id, description);
            }

            snd_ctl_close(handle);
        }
    }

    return constraint_ptr;
}
Exemple #16
0
static int findSoundCards(char **cardname)
{
	int idx, dev, err;
	snd_ctl_t *handle;
	snd_hctl_t *hctlhandle;
	snd_ctl_card_info_t *cardinfo;
	snd_pcm_info_t *pcminfo;
	char str[32];

	snd_ctl_card_info_alloca(&cardinfo);
	snd_pcm_info_alloca(&pcminfo);

	snd_hctl_elem_t *elem;
	snd_ctl_elem_id_t *id;
	snd_ctl_elem_info_t *info;
	snd_ctl_elem_id_alloca(&id);
	snd_ctl_elem_info_alloca(&info);

	idx = -1;
	while (1) {
		if ((err = snd_card_next(&idx)) < 0) {
			LOGE("Card next error: %s\n", snd_strerror(err));
			break;
		}
		if (idx < 0)
			break;
		sprintf(str, "hw:CARD=%i", idx);
		if ((err = snd_ctl_open(&handle, str, 0)) < 0) {
			LOGE("Open error: %s\n", snd_strerror(err));
			continue;
		}
		if ((err = snd_ctl_card_info(handle, cardinfo)) < 0) {
			LOGE("HW info error: %s\n", snd_strerror(err));
			continue;
		}
		LOGD("Soundcard #%i:\n", idx + 1);
		LOGD("  card - %i\n", snd_ctl_card_info_get_card(cardinfo));
		LOGD("  id - '%s'\n", snd_ctl_card_info_get_id(cardinfo));
		LOGD("  driver - '%s'\n", snd_ctl_card_info_get_driver(cardinfo));
		LOGD("  name - '%s'\n", snd_ctl_card_info_get_name(cardinfo));
		LOGD("  longname - '%s'\n", snd_ctl_card_info_get_longname(cardinfo));
		LOGD("  mixername - '%s'\n", snd_ctl_card_info_get_mixername(cardinfo));
		LOGD("  components - '%s'\n", snd_ctl_card_info_get_components(cardinfo));

		strcpy(cardname[idx], snd_ctl_card_info_get_name(cardinfo));
		LOGD("\n\n-----get cart name and id: %s : %d",cardname[idx],idx);
		snd_ctl_close(handle);

		if ((err = snd_hctl_open(&hctlhandle, str, 0)) < 0) {
			LOGE("Control %s open error: %s", str, snd_strerror(err));
			return err;
		}
		if ((err = snd_hctl_load(hctlhandle)) < 0) {
			LOGE("Control %s local error: %s\n", str, snd_strerror(err));
			return err;
		}

		for (elem = snd_hctl_first_elem(hctlhandle); elem; elem = snd_hctl_elem_next(elem)) {
			if ((err = snd_hctl_elem_info(elem, info)) < 0) {
				LOGE("Control %s snd_hctl_elem_info error: %s\n", str, snd_strerror(err));
				return err;
			}
			snd_hctl_elem_get_id(elem, id);
			show_control_id(id);
		}
		snd_hctl_close(hctlhandle);
	}
	snd_config_update_free_global();
	return 0;
}
Exemple #17
0
int main()
{
    int cardNumber = -1;
    int errNum;
    char *controlType;
    char deviceID[16];

    // ------------------------------------------------------------------------
    //  ALSA control elements.
    // ------------------------------------------------------------------------
    snd_ctl_t *ctl;                 // Simple control handle.
    snd_ctl_elem_id_t *id;          // Simple control element id.
    snd_ctl_elem_value_t *control;  // Simple control element value.
    snd_ctl_elem_type_t type;       // Simple control element type.
    snd_ctl_elem_info_t *info;      // Simple control element info container.
    snd_ctl_card_info_t *card;      // Simple control card info container.

    snd_hctl_t *hctl;               // High level control handle;
    snd_hctl_elem_t *elem;          // High level control element handle.

    // ------------------------------------------------------------------------
    //  Initialise ALSA card and device types.
    // ------------------------------------------------------------------------
    snd_ctl_card_info_alloca( &card );
    snd_ctl_elem_value_alloca( &control );
    snd_ctl_elem_id_alloca( &id );
    snd_ctl_elem_info_alloca( &info );

    // ------------------------------------------------------------------------
    //  Start card section.
    // ------------------------------------------------------------------------
    // For each card.
    while (1)
    {
        // Find next card number. If < 0 then returns 1st card.
        errNum = snd_card_next( &cardNumber );
        if (( errNum < 0 ) || ( cardNumber < 0 )) break;

        // Concatenate strings to get card's control interface.
        sprintf( deviceID, "hw:%i", cardNumber );

        //  Try to open card.
        if ( snd_ctl_open( &ctl, deviceID, 0 ) < 0 )
        {
            printf( "Error opening card.\n" );
            continue;
        }

        // Fill control card info element.
        if ( snd_ctl_card_info( ctl, card ) < 0 )
        {
            printf( "Error getting card info.\n" );
            continue;
        }

        // --------------------------------------------------------------------
        //  Print header block.
        // --------------------------------------------------------------------
        printf( "\t+-----------------------------" );
        printf( "-----------------------------+\n" );
        printf( "\t| Card: %d - %-46s |",
                        cardNumber,
                        snd_ctl_card_info_get_name( card ));
        printf( "\n" );
        printf( "\t+--------+------------" );
        printf( "+------------------------------------+\n" );
        printf( "\t| Device | Type       " );
        printf( "| Name                               |\n" );
        printf( "\t+--------+------------" );
        printf( "+------------------------------------+\n" );

        // --------------------------------------------------------------------
        //  Start control section.
        // --------------------------------------------------------------------
        // Open an empty high level control.
        if ( snd_hctl_open( &hctl, deviceID, 0 ) < 0 )
            printf( "Error opening high level control.\n" );

        // Load high level control element.
        if ( snd_hctl_load( hctl ) < 0 )
            printf( "Error loading high level control.\n" );

        // --------------------------------------------------------------------
        //  For each control element.
        // --------------------------------------------------------------------
        for ( elem = snd_hctl_first_elem( hctl );
                    elem;
                    elem = snd_hctl_elem_next( elem ))
        {
            // Get ID of high level control element.
            snd_hctl_elem_get_id( elem, id );

            // ----------------------------------------------------------------
            //  Determine control type.
            // ----------------------------------------------------------------
            if ( snd_hctl_elem_info( elem, info ) < 0 )
                printf( "Can't get control information.\n" );

            type = snd_ctl_elem_info_get_type( info );

            switch ( type )
            {
                case SND_CTL_ELEM_TYPE_NONE:
                    controlType = "None";
                    break;
                case SND_CTL_ELEM_TYPE_BOOLEAN:
                    controlType = "Boolean";
                    break;
                case SND_CTL_ELEM_TYPE_INTEGER:
                    controlType = "Integer";
                    break;
                case SND_CTL_ELEM_TYPE_INTEGER64:
                    controlType = "Integer64";
                    break;
                case SND_CTL_ELEM_TYPE_ENUMERATED:
                    controlType = "Enumerated";
                    break;
                case SND_CTL_ELEM_TYPE_BYTES:
                    controlType = "Bytes";
                    break;
                case SND_CTL_ELEM_TYPE_IEC958:
                    controlType = "IEC958";
                    break;
                default:
                    controlType = "Not Found";
                    break;
            }
            printf( "\t| %-6i | %-10s | %-34s |\n",
                snd_hctl_elem_get_numid( elem ),
                controlType,
                snd_hctl_elem_get_name( elem ));
        }
        printf( "\t+--------+------------" );
        printf( "+------------------------------------+\n\n" );

        // --------------------------------------------------------------------
        //  Tidy up.
        // --------------------------------------------------------------------
        snd_hctl_close( hctl );
        snd_ctl_close( ctl );
    }

    return 0;
}
Exemple #18
0
static int find_hwdep_device(int *cardP, int *devP)
{
	snd_ctl_t *ctl_handle;
	snd_ctl_card_info_t *card_info;
	snd_hwdep_info_t *hwdep_info;

	int card;
	int dev;
	int err;
	char card_id[32];

	ctl_handle = NULL;

	snd_ctl_card_info_alloca(&card_info);
	snd_hwdep_info_alloca(&hwdep_info);

	for (card = 0; card < 7; card++) {
		*cardP = card;

		if (ctl_handle) {
			snd_ctl_close(ctl_handle);
			ctl_handle = NULL;
		}
		// Get control handle for selected card
		sprintf(card_id, "hw:%i", card);
		if ((err = snd_ctl_open(&ctl_handle, card_id, 0)) < 0) {
			fprintf(stderr, "control open (%s): %s", card_id, snd_strerror(err));
			return -1;
		}
		// Read control hardware info from card
		if ((err = snd_ctl_card_info(ctl_handle, card_info)) < 0) {
			fprintf(stderr, "control hardware info (%s): %s", card_id, snd_strerror(err));
			continue;
		}
		//if (strcmp(snd_ctl_card_info_get_driver(card_info),"BT SCO (d)"))
		//    continue;
		dev = -1;
		err = 1;
		while (1) {
			int if_type;
			if (snd_ctl_hwdep_next_device(ctl_handle, &dev) < 0)
				fprintf(stderr, "hwdep next device (%s): %s", card_id, snd_strerror(err));
			if (dev < 0) 
				break;
			snd_hwdep_info_set_device(hwdep_info, dev);
			if (snd_ctl_hwdep_info(ctl_handle, hwdep_info) < 0) {
				if (err != -ENOENT)
					fprintf(stderr, "control hwdep info (%s): %s", card_id, snd_strerror(err));
				continue;
			}
			if_type = snd_hwdep_info_get_iface(hwdep_info);
			if (if_type == SNDRV_HWDEP_IFACE_BT_SCO || if_type==12) {
				snd_ctl_close(ctl_handle);
				*devP = dev;
				return 0;
			}
		}
	}
	if (ctl_handle)
		snd_ctl_close(ctl_handle);

	return -1;
}
Exemple #19
0
void CAESinkALSA::EnumerateDevicesEx(AEDeviceInfoList &list)
{
  /* ensure that ALSA has been initialized */
  if(!snd_config)
    snd_config_update();

  snd_ctl_t *ctlhandle;
  snd_pcm_t *pcmhandle;

  snd_ctl_card_info_t *ctlinfo;
  snd_ctl_card_info_alloca(&ctlinfo);
  memset(ctlinfo, 0, snd_ctl_card_info_sizeof());

  snd_pcm_hw_params_t *hwparams;
  snd_pcm_hw_params_alloca(&hwparams);
  memset(hwparams, 0, snd_pcm_hw_params_sizeof());

  snd_pcm_info_t *pcminfo;
  snd_pcm_info_alloca(&pcminfo);
  memset(pcminfo, 0, snd_pcm_info_sizeof());

  /* get the sound config */
  snd_config_t *config;
  snd_config_copy(&config, snd_config);

  std::string strHwName;
  int n_cards = -1;
  while (snd_card_next(&n_cards) == 0 && n_cards != -1)
  {
    std::stringstream sstr;
    sstr << "hw:" << n_cards;
    std::string strHwName = sstr.str();

    if (snd_ctl_open_lconf(&ctlhandle, strHwName.c_str(), 0, config) != 0)
    {
      CLog::Log(LOGDEBUG, "CAESinkALSA::EnumerateDevicesEx - Unable to open control for device %s", strHwName.c_str());
      continue;
    }

    if (snd_ctl_card_info(ctlhandle, ctlinfo) != 0)
    {
      CLog::Log(LOGDEBUG, "CAESinkALSA::EnumerateDevicesEx - Unable to get card control info for device %s", strHwName.c_str());
      snd_ctl_close(ctlhandle);
      continue;
    }

    snd_hctl_t *hctl;
    if (snd_hctl_open_ctl(&hctl, ctlhandle) != 0)
      hctl = NULL;
    snd_hctl_load(hctl);

    int pcm_index    = 0;
    int iec958_index = 0;
    int hdmi_index   = 0;

    int dev = -1;
    while (snd_ctl_pcm_next_device(ctlhandle, &dev) == 0 && dev != -1)
    {
      snd_pcm_info_set_device   (pcminfo, dev);
      snd_pcm_info_set_subdevice(pcminfo, 0  );
      snd_pcm_info_set_stream   (pcminfo, SND_PCM_STREAM_PLAYBACK);

      if (snd_ctl_pcm_info(ctlhandle, pcminfo) < 0)
      {
        CLog::Log(LOGDEBUG, "CAESinkALSA::EnumerateDevicesEx - Skipping device %s,%d as it does not have PCM playback ability", strHwName.c_str(), dev);
        continue;
      }

      int dev_index;
      sstr.str(std::string());
      CAEDeviceInfo info;
      std::string devname = snd_pcm_info_get_name(pcminfo);

      bool maybeHDMI = false;

      /* detect HDMI */
      if (devname.find("HDMI") != std::string::npos)
      { 
        info.m_deviceType = AE_DEVTYPE_HDMI;
        dev_index = hdmi_index++;
        sstr << "hdmi";
      }
      else
      {
        /* detect IEC958 */

        /* some HDMI devices (intel) report Digital for HDMI also */
        if (devname.find("Digital") != std::string::npos)
          maybeHDMI = true;

        if (maybeHDMI || devname.find("IEC958" ) != std::string::npos)
        {
          info.m_deviceType = AE_DEVTYPE_IEC958;
          dev_index = iec958_index; /* dont increment, it might be HDMI */
          sstr << "iec958";
        }
        else
        {
          info.m_deviceType = AE_DEVTYPE_PCM;
          dev_index = pcm_index++;
          sstr << "hw";
        }
      }

      /* build the driver string to pass to ALSA */
      sstr << ":CARD=" << snd_ctl_card_info_get_id(ctlinfo) << ",DEV=" << dev_index;
      info.m_deviceName = sstr.str();

      /* get the friendly display name*/
      info.m_displayName      = snd_ctl_card_info_get_name(ctlinfo);
      info.m_displayNameExtra = devname;

      /* open the device for testing */
      int err = snd_pcm_open_lconf(&pcmhandle, info.m_deviceName.c_str(), SND_PCM_STREAM_PLAYBACK, 0, config);

      /* if open of possible IEC958 failed and it could be HDMI, try as HDMI */
      if (err < 0 && maybeHDMI)
      {
        /* check for HDMI if it failed */
        sstr.str(std::string());
        dev_index = hdmi_index;

        sstr << "hdmi";
        sstr << ":CARD=" << snd_ctl_card_info_get_id(ctlinfo) << ",DEV=" << dev_index;
        info.m_deviceName = sstr.str();
        err = snd_pcm_open_lconf(&pcmhandle, info.m_deviceName.c_str(), SND_PCM_STREAM_PLAYBACK, 0, config);

        /* if it was valid, increment the index and set the type */
        if (err >= 0)
        {
          ++hdmi_index;
          info.m_deviceType = AE_DEVTYPE_HDMI;
        }
      }

      /* if it's still IEC958, increment the index */
      if (info.m_deviceType == AE_DEVTYPE_IEC958)
        ++iec958_index;

      /* final error check */
      if (err < 0)
      {
        CLog::Log(LOGINFO, "CAESinkALSA::EnumerateDevicesEx - Unable to open %s for capability detection", strHwName.c_str());
        continue;
      }

      /* see if we can get ELD for this device */
      if (info.m_deviceType == AE_DEVTYPE_HDMI)
      {
        bool badHDMI = false;
        if (hctl && !GetELD(hctl, dev, info, badHDMI))
          CLog::Log(LOGDEBUG, "CAESinkALSA::EnumerateDevicesEx - Unable to obtain ELD information for device %s, make sure you have ALSA >= 1.0.25", info.m_deviceName.c_str());

        if (badHDMI)
        {
          CLog::Log(LOGDEBUG, "CAESinkALSA::EnumerateDevicesEx - Skipping HDMI device %s as it has no ELD data", info.m_deviceName.c_str());
          continue;
        }
      }

      /* ensure we can get a playback configuration for the device */
      if (snd_pcm_hw_params_any(pcmhandle, hwparams) < 0)
      {
        CLog::Log(LOGINFO, "CAESinkALSA::EnumerateDevicesEx - No playback configurations available for device %s", info.m_deviceName.c_str());
        snd_pcm_close(pcmhandle);
        continue;
      }

      /* detect the available sample rates */
      for (unsigned int *rate = ALSASampleRateList; *rate != 0; ++rate)
        if (snd_pcm_hw_params_test_rate(pcmhandle, hwparams, *rate, 0) >= 0)
          info.m_sampleRates.push_back(*rate);

      /* detect the channels available */
      int channels = 0;
      for (int i = 1; i <= ALSA_MAX_CHANNELS; ++i)
        if (snd_pcm_hw_params_test_channels(pcmhandle, hwparams, i) >= 0)
          channels = i;

      CAEChannelInfo alsaChannels;
      for (int i = 0; i < channels; ++i)
      {
        if (!info.m_channels.HasChannel(ALSAChannelMap[i]))
          info.m_channels += ALSAChannelMap[i];
        alsaChannels += ALSAChannelMap[i];
      }

      /* remove the channels from m_channels that we cant use */
      info.m_channels.ResolveChannels(alsaChannels);

      /* detect the PCM sample formats that are available */
      for (enum AEDataFormat i = AE_FMT_MAX; i > AE_FMT_INVALID; i = (enum AEDataFormat)((int)i - 1))
      {
        if (AE_IS_RAW(i) || i == AE_FMT_MAX)
          continue;
        snd_pcm_format_t fmt = AEFormatToALSAFormat(i);
        if (fmt == SND_PCM_FORMAT_UNKNOWN)
          continue;

        if (snd_pcm_hw_params_test_format(pcmhandle, hwparams, fmt) >= 0)
          info.m_dataFormats.push_back(i);
      }

      snd_pcm_close(pcmhandle);
      list.push_back(info);
    }

    /* snd_hctl_close also closes ctlhandle */
    if (hctl)
      snd_hctl_close(hctl);
    else
      snd_ctl_close(ctlhandle);
  }
}
bool LapsusAlsaMixer::init()
{
	int err;
	snd_ctl_t *ctl_handle;
	snd_ctl_card_info_t *hw_info;

	snd_ctl_card_info_alloca(&hw_info);

	if ((err = snd_ctl_open (&ctl_handle, "default", 0)) < 0)
		return false;
	if ((err = snd_ctl_card_info (ctl_handle, hw_info)) < 0)
		return false;

	snd_ctl_close (ctl_handle);

	if ((err = snd_mixer_open (&_handle, 0)) < 0)
		return false;
	if ((err = snd_mixer_attach (_handle, "default")) < 0)
		return false;
	if ((err = snd_mixer_selem_register (_handle, 0, 0)) < 0)
		return false;

	if ((err = snd_mixer_load (_handle)) < 0)
		return false;

	// printf("Card name: '%s'\n", snd_ctl_card_info_get_name(hw_info));
	// printf("Device name: '%s'\n", snd_ctl_card_info_get_mixername(hw_info));

	snd_mixer_elem_t *elem;
	snd_mixer_selem_id_t *tmp_sid = 0;

	for (elem = snd_mixer_first_elem(_handle); elem; elem = snd_mixer_elem_next(elem))
	{
		if (snd_mixer_selem_is_active(elem))
		{
			if (!tmp_sid) tmp_sid = (snd_mixer_selem_id_t*) malloc(snd_mixer_selem_id_sizeof());

			snd_mixer_selem_get_id(elem, tmp_sid);

			const char *name = snd_mixer_selem_id_get_name( tmp_sid );

			if (!strcasecmp(name, "Headphone"))
			{
				if (sids[ID_HP]) delete sids[ID_HP];
				sids[ID_HP] = new SIDInfo(_handle, tmp_sid);
				tmp_sid = 0;
			}
			else if (!strcasecmp(name, "Front"))
			{
				if (sids[ID_F]) delete sids[ID_F];
				sids[ID_F] = new SIDInfo(_handle, tmp_sid);
				tmp_sid = 0;
			}
			else if (!strcasecmp(name, "Master"))
			{
				if (sids[ID_M]) delete sids[ID_M];
				sids[ID_M] = new SIDInfo(_handle, tmp_sid);
				tmp_sid = 0;
			}
		}
	}

	if (tmp_sid) free(tmp_sid);

	bool foundAny = false;

	for (int i = 0; i < ID_LAST; ++i)
	{
		if (sids[i])
		{
			if (sids[i]->hasMute)
			{
				foundAny = true;
			}

			if (sids[i]->hasVolume)
			{
				foundAny = true;

				long range = sids[i]->max - sids[i]->min;

				if (range > _globalMax)
					_globalMax = range;
			}
		}
	}

	if (_globalMax > INT_MAX)
		_globalMax = INT_MAX;

	if (!foundAny) return false;

	for (int i = 0; i < ID_LAST; ++i)
	{
		if (sids[i]) sids[i]->setGlobalMax(_globalMax);
	}

	if ((_count = snd_mixer_poll_descriptors_count(_handle)) < 0)
		return false;

	_fds = (struct pollfd*) calloc(_count, sizeof(struct pollfd));

	if (!_fds) return false;

	if ((err = snd_mixer_poll_descriptors(_handle, _fds, _count)) < 0)
		return false;

	if (err != _count) return 0;

	_sns = new QSocketNotifier*[_count];

	for ( int i = 0; i < _count; ++i )
	{
		_sns[i] = new QSocketNotifier(_fds[i].fd, QSocketNotifier::Read);
		connect(_sns[i], SIGNAL(activated(int)), this, SLOT(alsaEvent()));
	}

	// To read our current parameters. Signals will be emited, but those signals
	// are not yet connected to anything - this method is called from constructor
	// only.
	getVolume();
	mixerIsMuted();

	return true;
}
Exemple #21
0
static
jack_driver_param_constraint_desc_t *
enum_alsa_devices()
{
    snd_ctl_t * handle;
    snd_ctl_card_info_t * info;
    snd_pcm_info_t * pcminfo_capture;
    snd_pcm_info_t * pcminfo_playback;
    int card_no = -1;
    jack_driver_param_value_t card_id;
    jack_driver_param_value_t device_id;
    char description[64];
    int device_no;
    bool has_capture;
    bool has_playback;
    jack_driver_param_constraint_desc_t * constraint_ptr;
    uint32_t array_size = 0;

    snd_ctl_card_info_alloca(&info);
    snd_pcm_info_alloca(&pcminfo_capture);
    snd_pcm_info_alloca(&pcminfo_playback);

    constraint_ptr = NULL;

    while(snd_card_next(&card_no) >= 0 && card_no >= 0)
    {
        snprintf(card_id.str, sizeof(card_id.str), "hw:%d", card_no);

        if (snd_ctl_open(&handle, card_id.str, 0) >= 0 &&
                snd_ctl_card_info(handle, info) >= 0)
        {
            snprintf(card_id.str, sizeof(card_id.str), "hw:%s", snd_ctl_card_info_get_id(info));
            if (!jack_constraint_add_enum(
                        &constraint_ptr,
                        &array_size,
                        &card_id,
                        snd_ctl_card_info_get_name(info)))
                goto fail;

            device_no = -1;

            while (snd_ctl_pcm_next_device(handle, &device_no) >= 0 && device_no != -1)
            {
                snprintf(device_id.str, sizeof(device_id.str), "%s,%d", card_id.str, device_no);

                snd_pcm_info_set_device(pcminfo_capture, device_no);
                snd_pcm_info_set_subdevice(pcminfo_capture, 0);
                snd_pcm_info_set_stream(pcminfo_capture, SND_PCM_STREAM_CAPTURE);
                has_capture = snd_ctl_pcm_info(handle, pcminfo_capture) >= 0;

                snd_pcm_info_set_device(pcminfo_playback, device_no);
                snd_pcm_info_set_subdevice(pcminfo_playback, 0);
                snd_pcm_info_set_stream(pcminfo_playback, SND_PCM_STREAM_PLAYBACK);
                has_playback = snd_ctl_pcm_info(handle, pcminfo_playback) >= 0;

                if (has_capture && has_playback)
                {
                    snprintf(description, sizeof(description),"%s (duplex)", snd_pcm_info_get_name(pcminfo_capture));
                }
                else if (has_capture)
                {
                    snprintf(description, sizeof(description),"%s (capture)", snd_pcm_info_get_name(pcminfo_capture));
                }
                else if (has_playback)
                {
                    snprintf(description, sizeof(description),"%s (playback)", snd_pcm_info_get_name(pcminfo_playback));
                }
                else
                {
                    continue;
                }

                if (!jack_constraint_add_enum(
                            &constraint_ptr,
                            &array_size,
                            &device_id,
                            description))
                    goto fail;
            }

            snd_ctl_close(handle);
        }
    }

    return constraint_ptr;
fail:
    jack_constraint_free(constraint_ptr);
    return NULL;
}
Exemple #22
0
void AudioALSA::list_devices(ArrayList<char*> *devices, int pcm_title, int mode)
{
	snd_ctl_t *handle;
	int card, err, dev, idx;
	snd_ctl_card_info_t *info;
	snd_pcm_info_t *pcminfo;
	char string[BCTEXTLEN];
	snd_pcm_stream_t stream = SND_PCM_STREAM_PLAYBACK;
	int error;
	switch(mode)
	{
		case MODERECORD:
			stream = SND_PCM_STREAM_CAPTURE;
			break;
		case MODEPLAY:
			stream = SND_PCM_STREAM_PLAYBACK;
			break;
	}

	snd_ctl_card_info_alloca(&info);
	snd_pcm_info_alloca(&pcminfo);

	card = -1;
#define DEFAULT_DEVICE "default"
	char *result = new char[strlen(DEFAULT_DEVICE) + 1];
	devices->append(result);
	devices->set_array_delete();     // since we are allocating by new[]
	strcpy(result, DEFAULT_DEVICE);

	while(snd_card_next(&card) >= 0)
	{
		char name[BCTEXTLEN];
		if(card < 0) break;
		sprintf(name, "hw:%i", card);

		if((err = snd_ctl_open(&handle, name, 0)) < 0)
		{
			printf("AudioALSA::list_devices card=%i: %s\n", card, snd_strerror(err));
			continue;
		}

		if((err = snd_ctl_card_info(handle, info)) < 0)
		{
			printf("AudioALSA::list_devices card=%i: %s\n", card, snd_strerror(err));
			snd_ctl_close(handle);
			continue;
		}

		dev = -1;

		while(1)
		{
			unsigned int count;
			if(snd_ctl_pcm_next_device(handle, &dev) < 0)
				printf("AudioALSA::list_devices: snd_ctl_pcm_next_device\n");

			if (dev < 0)
				break;

			snd_pcm_info_set_device(pcminfo, dev);
			snd_pcm_info_set_subdevice(pcminfo, 0);
			snd_pcm_info_set_stream(pcminfo, stream);

			if((err = snd_ctl_pcm_info(handle, pcminfo)) < 0) 
			{
				if(err != -ENOENT)
					printf("AudioALSA::list_devices card=%i: %s\n", card, snd_strerror(err));
				continue;
			}

			if(pcm_title)
			{
				sprintf(string, "plughw:%d,%d", card, dev);
//				strcpy(string, "cards.pcm.front");
			}
			else
			{
				sprintf(string, "%s #%d", 
					snd_ctl_card_info_get_name(info), 
					dev);
			}

			char *result = devices->append(new char[strlen(string) + 1]);
			strcpy(result, string);
		}

		snd_ctl_close(handle);
	}

//	snd_ctl_card_info_free(info);
//	snd_pcm_info_free(pcminfo);
}
void qjackctlInterfaceComboBox::populateModel (void)
{
	bool bBlockSignals = QComboBox::blockSignals(true);

	QComboBox::setUpdatesEnabled(false);
	QComboBox::setDuplicatesEnabled(false);

	QLineEdit *pLineEdit = QComboBox::lineEdit();

	// FIXME: Only valid for ALSA, Sun and OSS devices,
	// for the time being... and also CoreAudio ones too.
	const QString& sDriver = m_pDriverComboBox->currentText();
	bool bAlsa      = (sDriver == "alsa");
	bool bSun       = (sDriver == "sun");
	bool bOss       = (sDriver == "oss");
#ifdef CONFIG_COREAUDIO
	bool bCoreaudio = (sDriver == "coreaudio");
	std::map<QString, AudioDeviceID> coreaudioIdMap;
#endif
#ifdef CONFIG_PORTAUDIO
	bool bPortaudio = (sDriver == "portaudio");
#endif
	QString sCurName = pLineEdit->text();
	QString sName, sSubName;
	
	int iCards = 0;

	clearCards();

	int iCurCard = -1;

	if (bAlsa) {
#ifdef CONFIG_ALSA_SEQ
		// Enumerate the ALSA cards and PCM harfware devices...
		snd_ctl_t *handle;
		snd_ctl_card_info_t *info;
		snd_pcm_info_t *pcminfo;
		snd_ctl_card_info_alloca(&info);
		snd_pcm_info_alloca(&pcminfo);
		const QString sPrefix("hw:%1");
		const QString sSuffix(" (%1)");
		const QString sSubSuffix("%1,%2");
		QString sName2, sSubName2;
		bool bCapture, bPlayback;
		int iCard = -1;
		while (snd_card_next(&iCard) >= 0 && iCard >= 0) {
			sName = sPrefix.arg(iCard);
			if (snd_ctl_open(&handle, sName.toUtf8().constData(), 0) >= 0
				&& snd_ctl_card_info(handle, info) >= 0) {
				sName2 = sPrefix.arg(snd_ctl_card_info_get_id(info));
				addCard(sName2, snd_ctl_card_info_get_name(info) + sSuffix.arg(sName));
				if (sCurName == sName || sCurName == sName2)
					iCurCard = iCards;
				++iCards;
				int iDevice = -1;
				while (snd_ctl_pcm_next_device(handle, &iDevice) >= 0
					&& iDevice >= 0) {
					// Capture devices..
					bCapture = false;
					if (m_iAudio == QJACKCTL_CAPTURE ||
						m_iAudio == QJACKCTL_DUPLEX) {
						snd_pcm_info_set_device(pcminfo, iDevice);
						snd_pcm_info_set_subdevice(pcminfo, 0);
						snd_pcm_info_set_stream(pcminfo, SND_PCM_STREAM_CAPTURE);
						bCapture = (snd_ctl_pcm_info(handle, pcminfo) >= 0);
					}
					// Playback devices..
					bPlayback = false;
					if (m_iAudio == QJACKCTL_PLAYBACK ||
						m_iAudio == QJACKCTL_DUPLEX) {
						snd_pcm_info_set_device(pcminfo, iDevice);
						snd_pcm_info_set_subdevice(pcminfo, 0);
						snd_pcm_info_set_stream(pcminfo, SND_PCM_STREAM_PLAYBACK);
						bPlayback = (snd_ctl_pcm_info(handle, pcminfo) >= 0);
					}
					// List iif compliant with the audio mode criteria...
					if ((m_iAudio == QJACKCTL_CAPTURE && bCapture && !bPlayback) ||
						(m_iAudio == QJACKCTL_PLAYBACK && !bCapture && bPlayback) ||
						(m_iAudio == QJACKCTL_DUPLEX && bCapture && bPlayback)) {
						sSubName  = sSubSuffix.arg(sName).arg(iDevice);
						sSubName2 = sSubSuffix.arg(sName2).arg(iDevice);
						addCard(sSubName2, snd_pcm_info_get_name(pcminfo) + sSuffix.arg(sSubName));
						if (sCurName == sSubName || sCurName == sSubName2)
							iCurCard = iCards;
						++iCards;
					}
				}
				snd_ctl_close(handle);
			}
		}
#endif 	// CONFIG_ALSA_SEQ
	}
	else
	if (bSun) {
		QFile file("/var/run/dmesg.boot");
		if (file.open(QIODevice::ReadOnly)) {
			QTextStream stream(&file);
			QString sLine;
			QRegExp rxDevice("audio([0-9]) at (.*)");
			while (!stream.atEnd()) {
				sLine = stream.readLine();
				if (rxDevice.exactMatch(sLine)) {
					sName = "/dev/audio" + rxDevice.cap(1);
					addCard(sName, rxDevice.cap(2));
					if (sCurName == sName)
						iCurCard = iCards;
					++iCards;
				}
			}
			file.close();
		}
	}
	else
	if (bOss) {
		// Enumerate the OSS Audio devices...
		QFile file("/dev/sndstat");
		if (file.open(QIODevice::ReadOnly)) {
			QTextStream stream(&file);
			QString sLine;
			bool bAudioDevices = false;
			QRegExp rxHeader("Audio devices.*", Qt::CaseInsensitive);
			QRegExp rxDevice("([0-9]+):[ ]+(.*)");
			while (!stream.atEnd()) {
				sLine = stream.readLine();
				if (bAudioDevices) {
					if (rxDevice.exactMatch(sLine)) {
						sName = "/dev/dsp" + rxDevice.cap(1);
						addCard(sName, rxDevice.cap(2));
						if (sCurName == sName)
							iCurCard = iCards;
						++iCards;
					}
					else break;
				}
				else if (rxHeader.exactMatch(sLine))
					bAudioDevices = true;
			}
			file.close();
		}
	}
#ifdef CONFIG_COREAUDIO
	else if (bCoreaudio) {
		// Find out how many Core Audio devices are there, if any...
		// (code snippet gently "borrowed" from Stephane Letz jackdmp;)
		OSStatus err;
		Boolean isWritable;
		UInt32 outSize = sizeof(isWritable);
		err = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices,
				&outSize, &isWritable);
		if (err == noErr) {
			// Calculate the number of device available...
			int numCoreDevices = outSize / sizeof(AudioDeviceID);
			// Make space for the devices we are about to get...
			AudioDeviceID *coreDeviceIDs = new AudioDeviceID [numCoreDevices];
			err = AudioHardwareGetProperty(kAudioHardwarePropertyDevices,
					&outSize, (void *) coreDeviceIDs);
			if (err == noErr) {
				// Look for the CoreAudio device name...
				char coreDeviceName[256];
				UInt32 nameSize = 256;
				for (int i = 0; i < numCoreDevices; i++) {
					err = AudioDeviceGetPropertyInfo(coreDeviceIDs[i],
							0, true, kAudioDevicePropertyDeviceName,
							&outSize, &isWritable);
					if (err == noErr) {
						err = AudioDeviceGetProperty(coreDeviceIDs[i],
								0, true, kAudioDevicePropertyDeviceName,
								&nameSize, (void *) coreDeviceName);
						if (err == noErr) {
							char drivername[128];
							UInt32 dnsize = 128;
							// this returns the unique id for the device
							// that must be used on the commandline for jack
							if (getDeviceUIDFromID(coreDeviceIDs[i],
								drivername, dnsize) == noErr) {
								sName = drivername;
							} else {
								sName = "Error";
							}
							coreaudioIdMap[sName] = coreDeviceIDs[i];
							// TODO: hide this ugly ID from the user,
							// only show human readable name
							// humanreadable \t UID
							sSubName = QString(coreDeviceName);
							addCard(sSubName, sName);
							if (sCurName == sName || sCurName == sSubName)
								iCurCard = iCards;
							++iCards;
						}
					}
				}
			}
			delete [] coreDeviceIDs;
		}
	}
#endif 	// CONFIG_COREAUDIO
#ifdef CONFIG_PORTAUDIO
	else if (bPortaudio) {
		if (Pa_Initialize() == paNoError) {
			// Fill hostapi info...
			PaHostApiIndex iNumHostApi = Pa_GetHostApiCount();
			QString *pHostName = new QString[iNumHostApi];
			for (PaHostApiIndex i = 0; i < iNumHostApi; ++i)
				pHostName[i] = QString(Pa_GetHostApiInfo(i)->name);
			// Fill device info...
			PaDeviceIndex iNumDevice = Pa_GetDeviceCount();
			PaDeviceInfo **ppDeviceInfo = new PaDeviceInfo * [iNumDevice];
			for (PaDeviceIndex i = 0; i < iNumDevice; ++i) {
				ppDeviceInfo[i] = const_cast<PaDeviceInfo *> (Pa_GetDeviceInfo(i));
				sName = pHostName[ppDeviceInfo[i]->hostApi] + "::" + QString(ppDeviceInfo[i]->name);
				addCard(sName, QString());
				if (sCurName == sName)
					iCurCard = iCards;
				++iCards;
			}
			Pa_Terminate();
		}
	}
#endif  // CONFIG_PORTAUDIO

	addCard(m_sDefName, QString());
	if (sCurName == m_sDefName || sCurName.isEmpty())
		iCurCard = iCards;
	++iCards;

	QTreeView *pTreeView = static_cast<QTreeView *> (QComboBox::view());
	pTreeView->setMinimumWidth(
		pTreeView->sizeHint().width() + QComboBox::iconSize().width());

	QComboBox::setCurrentIndex(iCurCard);

	pLineEdit->setText(sCurName);

	QComboBox::setUpdatesEnabled(true);
	QComboBox::blockSignals(bBlockSignals);
}
void
ManglerAlsa::getDeviceList(std::vector<ManglerAudioDevice*>& inputDevices, std::vector<ManglerAudioDevice*>& outputDevices) {/*{{{*/
    snd_pcm_stream_t stream[2] = { SND_PCM_STREAM_PLAYBACK, SND_PCM_STREAM_CAPTURE };
    int ctr;

    for (ctr = 0; ctr < 2; ctr++) { // the rest is just copypasta, with bad code from alsa
        snd_ctl_t *handle;
        int card, err, dev, idx_p = 0, idx_c = 0;
        snd_ctl_card_info_t *info;
        snd_pcm_info_t *pcminfo;

        card = -1;
        snd_ctl_card_info_alloca(&info);
        snd_pcm_info_alloca(&pcminfo);
        if (snd_card_next(&card) < 0 || card < 0) {
            fputs("alsa: no sound cards found!\n", stderr);
            return;
        }
        while (card >= 0) {
            char hw[256] = "";
            snprintf(hw, 255, "hw:%i", card);
            if ((err = snd_ctl_open(&handle, hw, 0)) < 0) {
                fprintf(stderr, "alsa: control open (%i): %s\n", card, snd_strerror(err));
                if (snd_card_next(&card) < 0) {
                    fprintf(stderr, "alsa: snd_ctl_open: snd_card_next\n");
                    break;
                }
                continue;
            }
            if ((err = snd_ctl_card_info(handle, info)) < 0) {
                fprintf(stderr, "alsa: control hardware info (%i): %s\n", card, snd_strerror(err));
                snd_ctl_close(handle);
                if (snd_card_next(&card) < 0) {
                    fprintf(stderr, "alsa: snd_ctl_card_info: snd_card_next\n");
                    break;
                }
                continue;
            }
            dev = -1;
            for (;;) {
                if (snd_ctl_pcm_next_device(handle, &dev) < 0) {
                    fprintf(stderr, "alsa: snd_ctl_pcm_next_device\n");
                }
                if (dev < 0) {
                    break;
                }
                snd_pcm_info_set_device(pcminfo, dev);
                snd_pcm_info_set_subdevice(pcminfo, 0);
                snd_pcm_info_set_stream(pcminfo, stream[ctr]);
                if ((err = snd_ctl_pcm_info(handle, pcminfo)) < 0) {
                    if (err != -ENOENT) {
                        fprintf(stderr, "alsa: control digital audio info (%i): %s\n", card, snd_strerror(err));
                    }
                    continue;
                }
                char name[256] = "", desc[512] = "";
                snprintf(name, 255, "hw:%i,%i", card, dev);
                snprintf(desc, 511, "%s: %s (%s)",
                         snd_ctl_card_info_get_name(info),
                         snd_pcm_info_get_name(pcminfo),
                         name
                        );
                switch (stream[ctr]) {
                case SND_PCM_STREAM_PLAYBACK:
                    outputDevices.push_back(
                        new ManglerAudioDevice(
                            idx_p++,
                            name,
                            desc)
                    );
                    break;
                case SND_PCM_STREAM_CAPTURE:
                    inputDevices.push_back(
                        new ManglerAudioDevice(
                            idx_c++,
                            name,
                            desc)
                    );
                    break;
                }
            }
            snd_ctl_close(handle);
            if (snd_card_next(&card) < 0) {
                fprintf(stderr, "alsa: snd_card_next\n");
                break;
            }
        }
    }
}/*}}}*/
static void device_list(snd_pcm_stream_t stream)
{
      snd_ctl_t *handle;
      int card, err, dev, idx;
      snd_ctl_card_info_t *info;
      snd_pcm_info_t *pcminfo;
      snd_ctl_card_info_alloca(&info);
      snd_pcm_info_alloca(&pcminfo);

      card = -1;
      if (snd_card_next(&card) < 0 || card < 0) {
            error(_("no soundcards found..."));
            return;
      }
      printf(_("**** List of %s Hardware Devices ****\n"),
             snd_pcm_stream_name(stream));
      while (card >= 0) {
            char name[32];
            sprintf(name, "hw:%d", card);
            if ((err = snd_ctl_open(&handle, name, 0)) < 0) {
                  error("control open (%i): %s", card, snd_strerror(err));
                  goto next_card;
            }
            if ((err = snd_ctl_card_info(handle, info)) < 0) {
                  error("control hardware info (%i): %s", card, snd_strerror(err));
                  snd_ctl_close(handle);
                  goto next_card;
            }
            dev = -1;
            while (1) {
                  unsigned int count;
                  if (snd_ctl_pcm_next_device(handle, &dev)<0)
                        error("snd_ctl_pcm_next_device");
                  if (dev < 0)
                        break;
                  snd_pcm_info_set_device(pcminfo, dev);
                  snd_pcm_info_set_subdevice(pcminfo, 0);
                  snd_pcm_info_set_stream(pcminfo, stream);
                  if ((err = snd_ctl_pcm_info(handle, pcminfo)) < 0) {
                        if (err != -ENOENT)
                              error("control digital audio info (%i): %s", card, snd_strerror(err));
                        continue;
                  }
                  printf(_("card %i: [%s,%i] %s [%s], device %i: %s [%s]\n"),
			 card, name, dev, snd_ctl_card_info_get_id(info), snd_ctl_card_info_get_name(info),
                        dev,
                        snd_pcm_info_get_id(pcminfo),
                        snd_pcm_info_get_name(pcminfo));
                  count = snd_pcm_info_get_subdevices_count(pcminfo);
                  printf( _("  Subdevices: %i/%i\n"),
                        snd_pcm_info_get_subdevices_avail(pcminfo), count);
                  for (idx = 0; idx < (int)count; idx++) {
                        snd_pcm_info_set_subdevice(pcminfo, idx);
                        if ((err = snd_ctl_pcm_info(handle, pcminfo)) < 0) {
                              error("control digital audio playback info (%i): %s", card, snd_strerror(err));
                        } else {
                              printf(_("  Subdevice #%i: %s\n"),
                                    idx, snd_pcm_info_get_subdevice_name(pcminfo));
                        }
                  }
            }
            snd_ctl_close(handle);
      next_card:
            if (snd_card_next(&card) < 0) {
                  error("snd_card_next");
                  break;
            }
      }
}
void asound_setup(const gchar * card, const gchar * channel,
                  void (*volume_changed)(int,gboolean))
{
    gchar * card_override = NULL; // used to hold a string like hw:0 if a nice
    // device name was given as 'card'

    // Clean up resources from previous calls to setup
    g_free(m_channel);
    m_channel = NULL;
    if(m_elem) {
        snd_mixer_elem_set_callback(m_elem, NULL);
        m_elem = NULL;
    }
    if(m_mixer) {
        snd_mixer_close(m_mixer);
        m_mixer = NULL;
    }
    g_list_free_full(m_channel_names, g_free);
    m_channel_names = NULL;
    g_list_free_full(m_device_names, g_free);
    m_device_names = NULL;

    // Save card, volume_changed
    g_free(m_device);
    m_device = g_strdup(card);
    m_volume_changed = volume_changed;

    // Populate list of device names
    int card_number = -1;
    int ret = snd_card_next(&card_number);
    snd_ctl_card_info_t * info = NULL;
    snd_ctl_card_info_alloca(&info);
    m_device_names = g_list_append(m_device_names, (gpointer)g_strdup("default"));
    while(ret == 0 && card_number != -1) {
        char buf[16];
        sprintf(buf, "hw:%d", card_number);
        snd_ctl_t * ctl = NULL;
        if(snd_ctl_open(&ctl, buf, 0) < 0) {
            continue;
        }
        if(snd_ctl_card_info(ctl, info) < 0) {
            snd_ctl_close(ctl);
            continue;
        }
        snd_ctl_close(ctl);

        gchar * nice_name = g_strdup(snd_ctl_card_info_get_name(info));
        m_device_names = g_list_append(m_device_names, (gpointer)nice_name);

        if(g_strcmp0(nice_name, m_device) == 0) {
            g_free(card_override);
            card_override = g_strdup_printf("hw:%d", card_number);
        }
        ret = snd_card_next(&card_number);
    }

    // Load the mixer for the provided cardname
    snd_mixer_open(&m_mixer, 0);
    if(snd_mixer_attach(m_mixer, (card_override != NULL ? card_override : m_device)) < 0) {
        fprintf(stderr, "Failed to open sound device with name: %s\n",
                (card_override != NULL ? card_override : m_device));
        snd_mixer_close(m_mixer);
        m_mixer = NULL;
        g_free(card_override);
        return;
    } else {
        g_free(card_override);
    }
    snd_mixer_selem_register(m_mixer, NULL, NULL);
    snd_mixer_load(m_mixer);

    // Setup g_io_watch for the mixer
    int count = snd_mixer_poll_descriptors_count(m_mixer);
    if(count >= 1)
    {
        struct pollfd pfd;

        count = snd_mixer_poll_descriptors(m_mixer, &pfd, 1);
        if(count == 1)
        {
            GIOChannel * giochannel = g_io_channel_unix_new(pfd.fd);
            g_io_add_watch_full(giochannel, G_PRIORITY_DEFAULT,
                                G_IO_IN | G_IO_ERR , asound_poll_cb, NULL, NULL);
        }
    }

    // Iterate over the elements in the mixer and store them in m_channel_names
    int elemcount = snd_mixer_get_count(m_mixer);
    snd_mixer_elem_t * elem = snd_mixer_first_elem(m_mixer);
    int loop;
    for(loop = 0; loop < elemcount; loop++)
    {
        const char * elemname = snd_mixer_selem_get_name(elem);
        if(snd_mixer_selem_has_playback_volume(elem))
        {
            m_channel_names = g_list_append(m_channel_names,
                                            (gpointer)g_strdup(elemname));
        }
        elem = snd_mixer_elem_next(elem);
    }

    // Setup m_elem using the provided channelname
    if(channel != NULL && asound_channel_exists(channel))
        asound_set_channel(channel);
    else if(m_channel_names != NULL)
        asound_set_channel((const gchar*)m_channel_names->data);
}
static int get_controls(int cardno, snd_config_t *top)
{
	snd_ctl_t *handle;
	snd_ctl_card_info_t *info;
	snd_config_t *state, *card, *control;
	snd_ctl_elem_list_t *list;
	unsigned int idx;
	int err;
	char name[32];
	unsigned int count;
	const char *id;
	snd_ctl_card_info_alloca(&info);
	snd_ctl_elem_list_alloca(&list);

	sprintf(name, "hw:%d", cardno);
	err = snd_ctl_open(&handle, name, SND_CTL_READONLY);
	if (err < 0) {
		error("snd_ctl_open error: %s", snd_strerror(err));
		return err;
	}
	err = snd_ctl_card_info(handle, info);
	if (err < 0) {
		error("snd_ctl_card_info error: %s", snd_strerror(err));
		goto _close;
	}
	id = snd_ctl_card_info_get_id(info);
	err = snd_config_search(top, "state", &state);
	if (err == 0 &&
	    snd_config_get_type(state) != SND_CONFIG_TYPE_COMPOUND) {
		error("config state node is not a compound");
		err = -EINVAL;
		goto _close;
	}
	if (err < 0) {
		err = snd_config_compound_add(top, "state", 1, &state);
		if (err < 0) {
			error("snd_config_compound_add: %s", snd_strerror(err));
			goto _close;
		}
	}
	err = snd_config_search(state, id, &card);
	if (err == 0 &&
	    snd_config_get_type(card) != SND_CONFIG_TYPE_COMPOUND) {
		error("config state.%s node is not a compound", id);
		err = -EINVAL;
		goto _close;
	}
	if (err < 0) {
		err = snd_config_compound_add(state, id, 0, &card);
		if (err < 0) {
			error("snd_config_compound_add: %s", snd_strerror(err));
			goto _close;
		}
	}
	err = snd_config_search(card, "control", &control);
	if (err == 0) {
		err = snd_config_delete(control);
		if (err < 0) {
			error("snd_config_delete: %s", snd_strerror(err));
			goto _close;
		}
	}
	err = snd_ctl_elem_list(handle, list);
	if (err < 0) {
		error("Cannot determine controls: %s", snd_strerror(err));
		goto _close;
	}
	count = snd_ctl_elem_list_get_count(list);
	err = snd_config_compound_add(card, "control", count > 0, &control);
	if (err < 0) {
		error("snd_config_compound_add: %s", snd_strerror(err));
		goto _close;
	}
	if (count == 0) {
		err = 0;
		goto _close;
	}
	snd_ctl_elem_list_set_offset(list, 0);
	if (snd_ctl_elem_list_alloc_space(list, count) < 0) {
		error("No enough memory...");
		goto _close;
	}
	if ((err = snd_ctl_elem_list(handle, list)) < 0) {
		error("Cannot determine controls (2): %s", snd_strerror(err));
		goto _free;
	}
	for (idx = 0; idx < count; ++idx) {
		snd_ctl_elem_id_t *id;
		snd_ctl_elem_id_alloca(&id);
		snd_ctl_elem_list_get_id(list, idx, id);
		err = get_control(handle, id, control);
		if (err < 0)
			goto _free;
	}		
		
	err = 0;
 _free:
	snd_ctl_elem_list_free_space(list);
 _close:
	snd_ctl_close(handle);
	return err;
}
void AlsaBackend::UpdateDevicesList()
{
    Log("AlsaBackend::UpdateDeviceList\n");

    DeviceInfo info;
    void **hints, **n;
    char *name, *descr, *desc;
    unsigned devices = 0;

    InitDevicesList();

    info.SetDevice(devices++, "default", "Default device", "default");
    info.type = DeviceInfo::TYPE_PLUG;
    info.direction = 0;
    PcmPreProbe(info, OUTPUT);
    PcmPreProbe(info, INPUT);
    devicesList.push_back(info);

    // Start with safe alsa detection, list the devices from software config.

    snd_config_update();

    if (snd_device_name_hint(-1, "pcm", &hints) < 0)
        return;

    n = hints;

    while (*n != NULL) {
        name = snd_device_name_get_hint(*n, "NAME");
        descr = snd_device_name_get_hint(*n, "DESC");

        if (!descr)
            desc = (char*)"";
        else
        {
            desc = descr;
            for (int i = strlen(desc); i > 0; i--)
                if (desc[i-1] == '\n')
                    desc[i-1] = ' ';
        }

        if (IgnorePlugin(name))
        {
            Log("Ignoring ALSA device %s", name);
        }
        else
        {
            info.SetDevice(devices++, name, desc, name);
            info.type = DeviceInfo::TYPE_PLUG;
            info.probed = false;
            info.direction = 0;

            PcmPreProbe(info, OUTPUT);
            PcmPreProbe(info, INPUT);

            if (info.direction != 0)
                devicesList.push_back(info);
        }

        if (name != NULL)
            free(name);
        if (descr != NULL)
            free(descr);

        n++;
    }
    snd_device_name_free_hint(hints);

    // Continue with new detection, this is a more thorough test with probing device characteristics

    enum { IDLEN = 12 };
    char hwdev[IDLEN+1];
    int card, err, dev;
    snd_ctl_t*             handle = NULL;
    snd_ctl_card_info_t*   cardinfo;
    snd_pcm_info_t*        pcminfo;

    snd_ctl_card_info_alloca(&cardinfo);
    snd_pcm_info_alloca(&pcminfo);

    card = -1;
    while (snd_card_next(&card) == 0 && card >= 0)
    {
        snprintf(hwdev, IDLEN, "hw:%d", card);
        err = snd_ctl_open(&handle, hwdev, 0);

        if (sc_errcheck(err, "opening control interface", card, -1))
            continue;

        err = snd_ctl_card_info(handle, cardinfo);

        if (sc_errcheck(err, "obtaining card info", card, -1))
        {
            snd_ctl_close(handle);
            continue;
        }

        Log("Card %d, ID '%s', name '%s'", card, snd_ctl_card_info_get_id(cardinfo), snd_ctl_card_info_get_name(cardinfo));

        dev = -1;

        if (snd_ctl_pcm_next_device(handle, &dev) < 0)
        {
            snd_ctl_close(handle);
            continue;
        }

        while (dev >= 0)
        {
            if (!DevProbe(handle, pcminfo, card, dev, OUTPUT) && !DevProbe(handle, pcminfo, card, dev, INPUT))
            {
                if (snd_ctl_pcm_next_device(handle, &dev) < 0)
                    break;
            }

            snprintf(hwdev, IDLEN, "hw:%d,%d", card, dev);
            char strbuf[DEVICE_NAME_MAXLEN];
            snprintf(strbuf, DEVICE_NAME_MAXLEN, "%s, %s", snd_ctl_card_info_get_name(cardinfo), snd_pcm_info_get_name(pcminfo));
            info.SetDevice(devices++, hwdev, strbuf, hwdev);
            info.type = DeviceInfo::TYPE_HW;
            info.probed = false;
            info.direction = 0;

            PcmPreProbe(info, OUTPUT);
            PcmPreProbe(info, INPUT);

            Log("**********\n%s :: %s\n**********\n", info.guid, info.displayName);

            devicesList.push_back(info);

            if (snd_ctl_pcm_next_device(handle, &dev) < 0)
                break;
        }

        snd_ctl_close(handle);
    }

    // And complement with chewing a bit on user-defined entries, too.
    // from PortAudio
    /* Iterate over plugin devices */

    snd_config_t *topNode = NULL;
    assert(snd_config);

    if ((err = snd_config_search(snd_config, "pcm", &topNode)) >= 0)
    {
        snd_config_iterator_t i, next;

        snd_config_for_each(i, next, topNode)
        {
            const char *tpStr = "unknown", *idStr = NULL;
            int err = 0;

            snd_config_t *n = snd_config_iterator_entry(i), *tp = NULL;

            if ((err = snd_config_search(n, "type", &tp)) < 0)
            {
                if (-ENOENT != err)
                {
                    Log("plugin list error: %s", snd_strerror(err));
                }
            }
            else
            {
                snd_config_get_string(tp, &tpStr);
            }
            snd_config_get_id(n, &idStr);
            if (IgnorePlugin(idStr))
            {
                Log("Ignoring ALSA plugin device %s of type %s", idStr, tpStr);
                continue;
            }
            Log("Found plugin %s of type %s", idStr, tpStr);

            info.SetDevice(devices++, idStr, idStr, tpStr);
            info.probed = false;
            info.direction = 0;

            if (strncmp(tpStr, "bluetooth", 9)==0)
                info.type = DeviceInfo::TYPE_BLUETOOTH;
            else if(strncmp(tpStr, "null", 4) == 0)
            {
                info.type = DeviceInfo::TYPE_NULL;
                // Never need to probe the null device.
                info.probed = true;
            }
            else if(strncmp(tpStr, "unknown", 4) == 0)
                info.type = DeviceInfo::TYPE_UNKNOWN;
            else
            {
                info.type = DeviceInfo::TYPE_PLUG;
                // No need to preprobe bluetooth, null and unknown(?) types.
                PcmPreProbe(info, OUTPUT);
                PcmPreProbe(info, INPUT);
            }

            devicesList.push_back(info);
        }
    }