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; }
INT32 PORT_GetPortMixerCount() { INT32 mixerCount; int card; char devname[16]; int err; snd_ctl_t *handle; snd_ctl_card_info_t* info; TRACE0("> PORT_GetPortMixerCount\n"); initAlsaSupport(); snd_ctl_card_info_malloc(&info); card = -1; mixerCount = 0; if (snd_card_next(&card) >= 0) { while (card >= 0) { sprintf(devname, ALSA_HARDWARE_CARD, card); TRACE1("PORT_GetPortMixerCount: 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", card, snd_strerror(err)); } else { mixerCount++; snd_ctl_close(handle); } if (snd_card_next(&card) < 0) { break; } } } snd_ctl_card_info_free(info); TRACE0("< PORT_GetPortMixerCount\n"); return mixerCount; }
void bg_alsa_create_card_parameters(bg_parameter_info_t * ret, int record) { snd_ctl_card_info_t *info; snd_ctl_t *handle; snd_pcm_info_t *pcminfo; snd_pcm_stream_t stream; int err; int card, dev; stream = record ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK; ret->name = gavl_strdup("card"); ret->long_name = gavl_strdup(TRS("Card")); ret->type = BG_PARAMETER_STRINGLIST; snd_ctl_card_info_malloc(&info); card = -1; if (snd_card_next(&card) < 0 || card < 0) { bg_log(BG_LOG_ERROR, LOG_DOMAIN, "No soundcards found"); return; } /* Default is always supported */ ret->val_default.val_str = gavl_strdup("default"); append_card(ret, gavl_strdup("default"), gavl_strdup(TRS("Default"))); while (card >= 0) { char name[32]; sprintf(name, "hw:%d", card); if ((err = snd_ctl_open(&handle, name, 0)) < 0) { bg_log(BG_LOG_ERROR, LOG_DOMAIN, "control open failed (%i): %s", card, snd_strerror(err)); goto next_card; } if ((err = snd_ctl_card_info(handle, info)) < 0) { bg_log(BG_LOG_ERROR, LOG_DOMAIN, "control hardware info failed (%i): %s", card, snd_strerror(err)); snd_ctl_close(handle); goto next_card; } dev = -1; while (1) { char * name, *label; snd_pcm_info_malloc(&pcminfo); if (snd_ctl_pcm_next_device(handle, &dev)<0) { bg_log(BG_LOG_ERROR, LOG_DOMAIN, "snd_ctl_pcm_next_device failed"); snd_pcm_info_free(pcminfo); break; } if (dev < 0) { snd_pcm_info_free(pcminfo); 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) bg_log(BG_LOG_ERROR, LOG_DOMAIN, "control digital audio info failed (%i): %s", card, snd_strerror(err)); snd_pcm_info_free(pcminfo); continue; } name = bg_sprintf("hw:%d,%d", card, dev); label = gavl_strdup(snd_pcm_info_get_name(pcminfo)); append_card(ret, name, label); snd_pcm_info_free(pcminfo); } snd_ctl_close(handle); next_card: if (snd_card_next(&card) < 0) break; } snd_ctl_card_info_free(info); }
// for each ALSA device, call iterator. userData is passed to the iterator // returns total number of iterations int iteratePCMDevices(DeviceIteratorPtr iterator, void* userData) { int count = 0; int subdeviceCount; int card, dev, subDev; char devname[16]; int err; snd_ctl_t *handle; snd_pcm_t *pcm; snd_pcm_info_t* pcminfo; snd_ctl_card_info_t *cardinfo, *defcardinfo = NULL; UINT32 deviceID; int doContinue = TRUE; snd_pcm_info_malloc(&pcminfo); snd_ctl_card_info_malloc(&cardinfo); // 1st try "default" device err = snd_pcm_open(&pcm, ALSA_DEFAULT_DEVICE_NAME, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK); if (err < 0) { // try with the other direction err = snd_pcm_open(&pcm, ALSA_DEFAULT_DEVICE_NAME, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK); } if (err < 0) { ERROR1("ERROR: snd_pcm_open (\"default\"): %s\n", snd_strerror(err)); } else { err = snd_pcm_info(pcm, pcminfo); snd_pcm_close(pcm); if (err < 0) { ERROR1("ERROR: snd_pcm_info (\"default\"): %s\n", snd_strerror(err)); } else { // try to get card info card = snd_pcm_info_get_card(pcminfo); if (card >= 0) { sprintf(devname, ALSA_HARDWARE_CARD, card); if (snd_ctl_open(&handle, devname, SND_CTL_NONBLOCK) >= 0) { if (snd_ctl_card_info(handle, cardinfo) >= 0) { defcardinfo = cardinfo; } snd_ctl_close(handle); } } // call callback function for the device if (iterator != NULL) { doContinue = (*iterator)(ALSA_DEFAULT_DEVICE_ID, pcminfo, defcardinfo, userData); } count++; } } // iterate cards card = -1; while (doContinue) { if (snd_card_next(&card) < 0) { break; } if (card < 0) { break; } sprintf(devname, ALSA_HARDWARE_CARD, card); TRACE1("Opening alsa device \"%s\"...\n", devname); err = snd_ctl_open(&handle, devname, SND_CTL_NONBLOCK); if (err < 0) { ERROR2("ERROR: snd_ctl_open, card=%d: %s\n", card, snd_strerror(err)); } else { err = snd_ctl_card_info(handle, cardinfo); if (err < 0) { ERROR2("ERROR: snd_ctl_card_info, card=%d: %s\n", card, snd_strerror(err)); } else { dev = -1; while (doContinue) { if (snd_ctl_pcm_next_device(handle, &dev) < 0) { ERROR0("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, SND_PCM_STREAM_PLAYBACK); err = snd_ctl_pcm_info(handle, pcminfo); if (err == -ENOENT) { // try with the other direction snd_pcm_info_set_stream(pcminfo, SND_PCM_STREAM_CAPTURE); err = snd_ctl_pcm_info(handle, pcminfo); } if (err < 0) { if (err != -ENOENT) { ERROR2("ERROR: snd_ctl_pcm_info, card=%d: %s", card, snd_strerror(err)); } } else { subdeviceCount = needEnumerateSubdevices(ALSA_PCM) ? snd_pcm_info_get_subdevices_count(pcminfo) : 1; if (iterator!=NULL) { for (subDev = 0; subDev < subdeviceCount; subDev++) { deviceID = encodeDeviceID(card, dev, subDev); doContinue = (*iterator)(deviceID, pcminfo, cardinfo, userData); count++; if (!doContinue) { break; } } } else { count += subdeviceCount; } } } // of while(doContinue) } snd_ctl_close(handle); } } snd_ctl_card_info_free(cardinfo); snd_pcm_info_free(pcminfo); return count; }
/* First some utils, then the mixer implementation */ static gboolean gst_alsa_mixer_open (GstAlsaMixer * mixer) { gint err; snd_ctl_t *ctl; snd_ctl_card_info_t *card_info; g_return_val_if_fail (mixer->handle == NULL, FALSE); /* open and initialize the mixer device */ err = snd_mixer_open (&mixer->handle, 0); if (err < 0 || mixer->handle == NULL) goto open_failed; if ((err = snd_mixer_attach (mixer->handle, mixer->device)) < 0) { GST_WARNING ("Cannot open mixer for sound device '%s': %s", mixer->device, snd_strerror (err)); goto error; } if ((err = snd_mixer_selem_register (mixer->handle, NULL, NULL)) < 0) { GST_WARNING ("Cannot register mixer elements: %s", snd_strerror (err)); goto error; } if ((err = snd_mixer_load (mixer->handle)) < 0) { GST_WARNING ("Cannot load mixer settings: %s", snd_strerror (err)); goto error; } snd_mixer_set_callback_private (mixer->handle, mixer); snd_mixer_set_callback (mixer->handle, gst_alsa_mixer_handle_callback); /* now get the device name, any of this is not fatal */ g_free (mixer->cardname); if ((err = snd_ctl_open (&ctl, mixer->device, 0)) < 0) { GST_WARNING ("Cannot open CTL: %s", snd_strerror (err)); goto no_card_name; } snd_ctl_card_info_malloc (&card_info); if ((err = snd_ctl_card_info (ctl, card_info)) < 0) { GST_WARNING ("Cannot get card info: %s", snd_strerror (err)); snd_ctl_close (ctl); goto no_card_name; } mixer->cardname = g_strdup (snd_ctl_card_info_get_name (card_info)); GST_DEBUG ("Card name = %s", GST_STR_NULL (mixer->cardname)); snd_ctl_card_info_free (card_info); snd_ctl_close (ctl); no_card_name: if (mixer->cardname == NULL) { mixer->cardname = g_strdup ("Unknown"); GST_DEBUG ("Cannot find card name"); } GST_INFO ("Successfully opened mixer for device '%s'.", mixer->device); return TRUE; /* ERROR */ open_failed: { GST_WARNING ("Cannot open mixer: %s", snd_strerror (err)); mixer->handle = NULL; return FALSE; } error: { snd_mixer_close (mixer->handle); mixer->handle = NULL; return FALSE; } }
static void probe_devices(snd_pcm_stream_t stream, vector_DevMap *DeviceList) { const char *main_prefix = "plughw:"; snd_ctl_t *handle; snd_ctl_card_info_t *info; snd_pcm_info_t *pcminfo; int card, err, dev; DevMap entry; clear_devlist(DeviceList); snd_ctl_card_info_malloc(&info); snd_pcm_info_malloc(&pcminfo); AL_STRING_INIT(entry.name); AL_STRING_INIT(entry.device_name); al_string_copy_cstr(&entry.name, alsaDevice); al_string_copy_cstr(&entry.device_name, GetConfigValue(NULL, "alsa", (stream==SND_PCM_STREAM_PLAYBACK) ? "device" : "capture", "default")); VECTOR_PUSH_BACK(*DeviceList, entry); card = -1; if((err=snd_card_next(&card)) < 0) ERR("Failed to find a card: %s\n", snd_strerror(err)); ConfigValueStr(NULL, "alsa", prefix_name(stream), &main_prefix); while(card >= 0) { const char *card_prefix = main_prefix; const char *cardname, *cardid; char name[256]; snprintf(name, sizeof(name), "hw:%d", card); if((err = snd_ctl_open(&handle, name, 0)) < 0) { ERR("control open (hw:%d): %s\n", card, snd_strerror(err)); goto next_card; } if((err = snd_ctl_card_info(handle, info)) < 0) { ERR("control hardware info (hw:%d): %s\n", card, snd_strerror(err)); snd_ctl_close(handle); goto next_card; } cardname = snd_ctl_card_info_get_name(info); cardid = snd_ctl_card_info_get_id(info); snprintf(name, sizeof(name), "%s-%s", prefix_name(stream), cardid); ConfigValueStr(NULL, "alsa", name, &card_prefix); dev = -1; while(1) { const char *device_prefix = card_prefix; const char *devname; char device[128]; if(snd_ctl_pcm_next_device(handle, &dev) < 0) ERR("snd_ctl_pcm_next_device failed\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) ERR("control digital audio info (hw:%d): %s\n", card, snd_strerror(err)); continue; } devname = snd_pcm_info_get_name(pcminfo); snprintf(name, sizeof(name), "%s-%s-%d", prefix_name(stream), cardid, dev); ConfigValueStr(NULL, "alsa", name, &device_prefix); snprintf(name, sizeof(name), "%s, %s (CARD=%s,DEV=%d)", cardname, devname, cardid, dev); snprintf(device, sizeof(device), "%sCARD=%s,DEV=%d", device_prefix, cardid, dev); TRACE("Got device \"%s\", \"%s\"\n", name, device); AL_STRING_INIT(entry.name); AL_STRING_INIT(entry.device_name); al_string_copy_cstr(&entry.name, name); al_string_copy_cstr(&entry.device_name, device); VECTOR_PUSH_BACK(*DeviceList, entry); } snd_ctl_close(handle); next_card: if(snd_card_next(&card) < 0) { ERR("snd_card_next failed\n"); break; } } snd_pcm_info_free(pcminfo); snd_ctl_card_info_free(info); }
// for each ALSA device, call iterator. userData is passed to the iterator // returns total number of iterations static int iterateRawmidiDevices(snd_rawmidi_stream_t direction, DeviceIteratorPtr iterator, void* userData) { int count = 0; int subdeviceCount; int card, dev, subDev; char devname[16]; int err; snd_ctl_t *handle; snd_rawmidi_t *rawmidi; snd_rawmidi_info_t *rawmidi_info; snd_ctl_card_info_t *card_info, *defcardinfo = NULL; UINT32 deviceID; int doContinue = TRUE; snd_rawmidi_info_malloc(&rawmidi_info); snd_ctl_card_info_malloc(&card_info); // 1st try "default" device if (direction == SND_RAWMIDI_STREAM_INPUT) { err = snd_rawmidi_open(&rawmidi, NULL, ALSA_DEFAULT_DEVICE_NAME, SND_RAWMIDI_NONBLOCK); } else if (direction == SND_RAWMIDI_STREAM_OUTPUT) { err = snd_rawmidi_open(NULL, &rawmidi, ALSA_DEFAULT_DEVICE_NAME, SND_RAWMIDI_NONBLOCK); } else { ERROR0("ERROR: iterateRawmidiDevices(): direction is neither" " SND_RAWMIDI_STREAM_INPUT nor SND_RAWMIDI_STREAM_OUTPUT\n"); err = MIDI_INVALID_ARGUMENT; } if (err < 0) { ERROR1("ERROR: snd_rawmidi_open (\"default\"): %s\n", snd_strerror(err)); } else { err = snd_rawmidi_info(rawmidi, rawmidi_info); snd_rawmidi_close(rawmidi); if (err < 0) { ERROR1("ERROR: snd_rawmidi_info (\"default\"): %s\n", snd_strerror(err)); } else { // try to get card info card = snd_rawmidi_info_get_card(rawmidi_info); if (card >= 0) { sprintf(devname, ALSA_HARDWARE_CARD, card); if (snd_ctl_open(&handle, devname, SND_CTL_NONBLOCK) >= 0) { if (snd_ctl_card_info(handle, card_info) >= 0) { defcardinfo = card_info; } snd_ctl_close(handle); } } // call calback function for the device if (iterator != NULL) { doContinue = (*iterator)(ALSA_DEFAULT_DEVICE_ID, rawmidi_info, defcardinfo, userData); } count++; } } // iterate cards card = -1; TRACE0("testing for cards...\n"); if (snd_card_next(&card) >= 0) { TRACE1("Found card %d\n", card); while (doContinue && (card >= 0)) { sprintf(devname, ALSA_HARDWARE_CARD, card); TRACE1("Opening control for alsa rawmidi device \"%s\"...\n", devname); err = snd_ctl_open(&handle, devname, SND_CTL_NONBLOCK); if (err < 0) { ERROR2("ERROR: snd_ctl_open, card=%d: %s\n", card, snd_strerror(err)); } else { TRACE0("snd_ctl_open() SUCCESS\n"); err = snd_ctl_card_info(handle, card_info); if (err < 0) { ERROR2("ERROR: snd_ctl_card_info, card=%d: %s\n", card, snd_strerror(err)); } else { TRACE0("snd_ctl_card_info() SUCCESS\n"); dev = -1; while (doContinue) { if (snd_ctl_rawmidi_next_device(handle, &dev) < 0) { ERROR0("snd_ctl_rawmidi_next_device\n"); } TRACE0("snd_ctl_rawmidi_next_device() SUCCESS\n"); if (dev < 0) { break; } snd_rawmidi_info_set_device(rawmidi_info, dev); snd_rawmidi_info_set_subdevice(rawmidi_info, 0); snd_rawmidi_info_set_stream(rawmidi_info, direction); err = snd_ctl_rawmidi_info(handle, rawmidi_info); TRACE0("after snd_ctl_rawmidi_info()\n"); if (err < 0) { if (err != -ENOENT) { ERROR2("ERROR: snd_ctl_rawmidi_info, card=%d: %s", card, snd_strerror(err)); } } else { TRACE0("snd_ctl_rawmidi_info() SUCCESS\n"); subdeviceCount = needEnumerateSubdevices(ALSA_RAWMIDI) ? snd_rawmidi_info_get_subdevices_count(rawmidi_info) : 1; if (iterator!=NULL) { for (subDev = 0; subDev < subdeviceCount; subDev++) { TRACE3(" Iterating %d,%d,%d\n", card, dev, subDev); deviceID = encodeDeviceID(card, dev, subDev); doContinue = (*iterator)(deviceID, rawmidi_info, card_info, userData); count++; TRACE0("returned from iterator\n"); if (!doContinue) { break; } } } else { count += subdeviceCount; } } } // of while(doContinue) } snd_ctl_close(handle); } if (snd_card_next(&card) < 0) { break; } } } else { ERROR0("No cards found!\n"); } snd_ctl_card_info_free(card_info); snd_rawmidi_info_free(rawmidi_info); return count; }
static DevMap *probe_devices(snd_pcm_stream_t stream, ALuint *count) { const char *main_prefix = "plughw:"; snd_ctl_t *handle; int card, err, dev, idx; snd_ctl_card_info_t *info; snd_pcm_info_t *pcminfo; DevMap *DevList; snd_ctl_card_info_malloc(&info); snd_pcm_info_malloc(&pcminfo); DevList = malloc(sizeof(DevMap) * 1); DevList[0].name = strdup(alsaDevice); DevList[0].device = strdup(GetConfigValue("alsa", (stream==SND_PCM_STREAM_PLAYBACK) ? "device" : "capture", "default")); idx = 1; card = -1; if((err=snd_card_next(&card)) < 0) ERR("Failed to find a card: %s\n", snd_strerror(err)); ConfigValueStr("alsa", prefix_name(stream), &main_prefix); while(card >= 0) { const char *card_prefix = main_prefix; const char *cardname, *cardid; char name[256]; snprintf(name, sizeof(name), "hw:%d", card); if((err = snd_ctl_open(&handle, name, 0)) < 0) { ERR("control open (hw:%d): %s\n", card, snd_strerror(err)); goto next_card; } if((err = snd_ctl_card_info(handle, info)) < 0) { ERR("control hardware info (hw:%d): %s\n", card, snd_strerror(err)); snd_ctl_close(handle); goto next_card; } cardname = snd_ctl_card_info_get_name(info); cardid = snd_ctl_card_info_get_id(info); snprintf(name, sizeof(name), "%s-%s", prefix_name(stream), cardid); ConfigValueStr("alsa", name, &card_prefix); dev = -1; while(1) { const char *devname; void *temp; if(snd_ctl_pcm_next_device(handle, &dev) < 0) ERR("snd_ctl_pcm_next_device failed\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) ERR("control digital audio info (hw:%d): %s\n", card, snd_strerror(err)); continue; } temp = realloc(DevList, sizeof(DevMap) * (idx+1)); if(temp) { const char *device_prefix = card_prefix; char device[128]; DevList = temp; devname = snd_pcm_info_get_name(pcminfo); snprintf(name, sizeof(name), "%s-%s-%d", prefix_name(stream), cardid, dev); ConfigValueStr("alsa", name, &device_prefix); snprintf(name, sizeof(name), "%s, %s (CARD=%s,DEV=%d)", cardname, devname, cardid, dev); snprintf(device, sizeof(device), "%sCARD=%s,DEV=%d", device_prefix, cardid, dev); TRACE("Got device \"%s\", \"%s\"\n", name, device); DevList[idx].name = strdup(name); DevList[idx].device = strdup(device); idx++; } } snd_ctl_close(handle); next_card: if(snd_card_next(&card) < 0) { ERR("snd_card_next failed\n"); break; } } snd_pcm_info_free(pcminfo); snd_ctl_card_info_free(info); *count = idx; return DevList; }
static GList * gst_alsa_get_device_list (snd_pcm_stream_t stream) { snd_ctl_t *handle; int card, dev; snd_ctl_card_info_t *info; snd_pcm_info_t *pcminfo; gboolean mixer = (stream == -1); GList *list = NULL; if (stream == -1) stream = 0; snd_ctl_card_info_malloc (&info); snd_pcm_info_malloc (&pcminfo); card = -1; if (snd_card_next (&card) < 0 || card < 0) { /* no soundcard found */ GST_WARNING ("No soundcard found"); goto beach; } while (card >= 0) { gchar name[32]; g_snprintf (name, sizeof (name), "hw:%d", card); if (snd_ctl_open (&handle, name, 0) < 0) { goto next_card; } if (snd_ctl_card_info (handle, info) < 0) { snd_ctl_close (handle); goto next_card; } if (mixer) { list = g_list_append (list, g_strdup (name)); } else { dev = -1; while (1) { gchar *gst_device; 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) { continue; } gst_device = g_strdup_printf ("hw:%d,%d", card, dev); list = g_list_append (list, gst_device); } } snd_ctl_close (handle); next_card: if (snd_card_next (&card) < 0) { break; } } beach: snd_ctl_card_info_free (info); snd_pcm_info_free (pcminfo); return list; }
/* returns the card name when the device number is unknown or -1 */ static gchar * gst_alsa_find_device_name_no_handle (GstObject * obj, const gchar * devcard, gint device_num, snd_pcm_stream_t stream) { snd_ctl_card_info_t *info = NULL; snd_ctl_t *ctl = NULL; gchar *ret = NULL; gint dev = -1; GST_LOG_OBJECT (obj, "[%s] device=%d", devcard, device_num); if (snd_ctl_open (&ctl, devcard, 0) < 0) return NULL; snd_ctl_card_info_malloc (&info); if (snd_ctl_card_info (ctl, info) < 0) goto done; if (device_num != -1) { while (snd_ctl_pcm_next_device (ctl, &dev) == 0 && dev >= 0) { if (dev == device_num) { snd_pcm_info_t *pcminfo; snd_pcm_info_malloc (&pcminfo); 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 (ctl, pcminfo) < 0) { snd_pcm_info_free (pcminfo); break; } ret = (gchar *) snd_pcm_info_get_name (pcminfo); if (ret) { ret = g_strdup (ret); GST_LOG_OBJECT (obj, "name from pcminfo: %s", ret); } snd_pcm_info_free (pcminfo); if (ret) break; } } } if (ret == NULL) { char *name = NULL; gint card; GST_LOG_OBJECT (obj, "trying card name"); card = snd_ctl_card_info_get_card (info); snd_card_get_name (card, &name); ret = g_strdup (name); free (name); } done: snd_ctl_card_info_free (info); snd_ctl_close (ctl); return ret; }
/* Try and find an IEC958 PCM device and mixer on card 0 and open it * This function is only used on older ALSA installs that don't have the * correct iec958 alias stuff set up, and relies on there being only * one IEC958 PCM device (relies IEC958 in the device name) and one IEC958 * mixer control for doing the settings. */ static int alsaspdifsink_find_pcm_device (AlsaSPDIFSink * sink) { int err = -1, dev, idx, count; const gchar *ctl_name = "hw:0"; const gchar *spdif_name = SND_CTL_NAME_IEC958 ("", PLAYBACK, NONE); int card = sink->card; gchar pcm_name[24]; snd_pcm_t *pcm = NULL; snd_ctl_t *ctl = NULL; snd_ctl_card_info_t *info = NULL; snd_ctl_elem_list_t *clist = NULL; snd_ctl_elem_id_t *cid = NULL; snd_pcm_info_t *pinfo = NULL; GST_WARNING ("Opening IEC958 named device failed. Trying to autodetect"); if ((err = snd_ctl_open (&ctl, ctl_name, card)) < 0) return err; snd_ctl_card_info_malloc (&info); snd_pcm_info_malloc (&pinfo); /* Find a mixer for IEC958 settings */ snd_ctl_elem_list_malloc (&clist); if ((err = snd_ctl_elem_list (ctl, clist)) < 0) goto beach; if ((err = snd_ctl_elem_list_alloc_space (clist, snd_ctl_elem_list_get_count (clist))) < 0) goto beach; if ((err = snd_ctl_elem_list (ctl, clist)) < 0) goto beach; count = snd_ctl_elem_list_get_used (clist); for (idx = 0; idx < count; idx++) { if (strstr (snd_ctl_elem_list_get_name (clist, idx), spdif_name) != NULL) break; } if (idx == count) { /* No SPDIF mixer availble */ err = 0; goto beach; } snd_ctl_elem_id_malloc (&cid); snd_ctl_elem_list_get_id (clist, idx, cid); /* Now find a PCM device for IEC 958 */ if ((err = snd_ctl_card_info (ctl, info)) < 0) goto beach; dev = -1; do { if (snd_ctl_pcm_next_device (ctl, &dev) < 0) goto beach; if (dev < 0) break; /* No more devices */ /* Filter for playback devices */ snd_pcm_info_set_device (pinfo, dev); snd_pcm_info_set_subdevice (pinfo, 0); snd_pcm_info_set_stream (pinfo, SND_PCM_STREAM_PLAYBACK); if ((err = snd_ctl_pcm_info (ctl, pinfo)) < 0) { if (err != -ENOENT) goto beach; /* Genuine error */ /* Device has no playback streams */ continue; } if (strstr (snd_pcm_info_get_name (pinfo), "IEC958") == NULL) continue; /* Not the device we are looking for */ count = snd_pcm_info_get_subdevices_count (pinfo); GST_LOG_OBJECT (sink, "Device %d has %d subdevices\n", dev, snd_pcm_info_get_subdevices_count (pinfo)); for (idx = 0; idx < count; idx++) { snd_pcm_info_set_subdevice (pinfo, idx); if ((err = snd_ctl_pcm_info (ctl, pinfo)) < 0) goto beach; g_assert (snd_pcm_info_get_stream (pinfo) == SND_PCM_STREAM_PLAYBACK); GST_LOG_OBJECT (sink, "Found playback stream on dev %d sub-d %d\n", dev, idx); /* Found a suitable PCM device, let's open it */ g_snprintf (pcm_name, 24, "hw:%d,%d", card, dev); if ((err = snd_pcm_open (&(pcm), pcm_name, SND_PCM_STREAM_PLAYBACK, 0)) < 0) goto beach; break; } } while (pcm == NULL); if (pcm != NULL) { snd_ctl_elem_value_t *cval; snd_aes_iec958_t iec958; /* Have a PCM device and a mixer, set things up */ snd_ctl_elem_value_malloc (&cval); snd_ctl_elem_value_set_id (cval, cid); snd_ctl_elem_value_get_iec958 (cval, &iec958); iec958.status[0] = IEC958_AES0_NONAUDIO; iec958.status[1] = IEC958_AES1_CON_ORIGINAL | IEC958_AES1_CON_PCM_CODER; iec958.status[2] = 0; iec958.status[3] = IEC958_AES3_CON_FS_48000; snd_ctl_elem_value_set_iec958 (cval, &iec958); snd_ctl_elem_value_free (cval); sink->pcm = pcm; pcm = NULL; err = 0; } beach: if (pcm) snd_pcm_close (pcm); if (clist) snd_ctl_elem_list_clear (clist); if (ctl) snd_ctl_close (ctl); if (clist) snd_ctl_elem_list_free (clist); if (cid) snd_ctl_elem_id_free (cid); if (info) snd_ctl_card_info_free (info); if (pinfo) snd_pcm_info_free (pinfo); return err; }
std::vector<ALSAInput::Source> ALSAInput::GetSourceList() { std::vector<Source> list; /* This code is based on the ALSA device detection code used in PortAudio. I just ported it to C++ and improved it a bit. All credit goes to the PortAudio devs, they saved me a lot of time :). */ // these ALSA plugins are blacklisted because they are always defined but rarely useful // 'pulse' is also blacklisted because the native PulseAudio backend is more reliable std::vector<std::string> plugin_blacklist = { "cards", "default", "sysdefault", "hw", "plughw", "plug", "dmix", "dsnoop", "shm", "tee", "file", "null", "front", "rear", "center_lfe", "side", "surround40", "surround41", "surround50", "surround51", "surround71", "iec958", "spdif", "hdmi", "modem", "phoneline", "pulse", }; std::sort(plugin_blacklist.begin(), plugin_blacklist.end()); // the 'default' PCM must be first, so add it explicitly list.push_back(Source("default", "Default source")); Logger::LogInfo("[ALSAInput::GetSourceList] " + Logger::tr("Generating source list ...")); snd_ctl_card_info_t *alsa_card_info = NULL; snd_pcm_info_t *alsa_pcm_info = NULL; snd_ctl_t *alsa_ctl = NULL; try { // allocate card and PCM info structure if(snd_ctl_card_info_malloc(&alsa_card_info) < 0) { throw std::bad_alloc(); } if(snd_pcm_info_malloc(&alsa_pcm_info) < 0) { throw std::bad_alloc(); } // update the ALSA configuration snd_config_update_free_global(); if(snd_config_update() < 0) { Logger::LogError("[ALSAInput::GetSourceList] " + Logger::tr("Error: Could not update ALSA configuration!")); throw ALSAException(); } // find all PCM plugins (by parsing the config file) snd_config_t *alsa_config_pcms = NULL; if(snd_config_search(snd_config, "pcm", &alsa_config_pcms) == 0) { snd_config_iterator_t i, next; snd_config_for_each(i, next, alsa_config_pcms) { snd_config_t *alsa_config_pcm = snd_config_iterator_entry(i); // get the name const char *id = NULL; if(snd_config_get_id(alsa_config_pcm, &id) < 0 || id == NULL) continue; std::string plugin_name = id; // ignore the plugin if it is blacklisted if(std::binary_search(plugin_blacklist.begin(), plugin_blacklist.end(), plugin_name)) continue; // try to get the description std::string plugin_description; snd_config_t *alsa_config_description = NULL; if(snd_config_search(alsa_config_pcm, "hint.description", &alsa_config_description) == 0) { const char *str = NULL; if(snd_config_get_string(alsa_config_description, &str) >= 0 && str != NULL) { plugin_description = str; } } // if there is no description, ignore it, because it's probably not meant to be used if(plugin_description.empty()) continue; // if there is no description, use the type instead /*if(plugin_description.empty()) { snd_config_t *alsa_config_type = NULL; if(snd_config_search(alsa_config_pcm, "type", &alsa_config_type) >= 0) { const char *str = NULL; if(snd_config_get_string(alsa_config_type, &str) >= 0 && str != NULL) { plugin_description = std::string(str) + " plugin"; } } }*/ // add to list Logger::LogInfo("[ALSAInput::GetSourceList] " + Logger::tr("Found plugin: [%1] %2").arg(QString::fromStdString(plugin_name)).arg(QString::fromStdString(plugin_description))); list.push_back(Source(plugin_name, plugin_description)); } }
static DevMap *probe_devices(snd_pcm_stream_t stream, ALuint *count) { snd_ctl_t *handle; int card, err, dev, idx; snd_ctl_card_info_t *info; snd_pcm_info_t *pcminfo; DevMap *DevList; char name[1024]; snd_ctl_card_info_malloc(&info); snd_pcm_info_malloc(&pcminfo); card = -1; if((err=snd_card_next(&card)) < 0) ERR("Failed to find a card: %s\n", snd_strerror(err)); DevList = malloc(sizeof(DevMap) * 1); DevList[0].name = strdup("ALSA Default"); DevList[0].card = NULL; DevList[0].dev = 0; idx = 1; while(card >= 0) { sprintf(name, "hw:%d", card); if((err = snd_ctl_open(&handle, name, 0)) < 0) { ERR("control open (%i): %s\n", card, snd_strerror(err)); goto next_card; } if((err = snd_ctl_card_info(handle, info)) < 0) { ERR("control hardware info (%i): %s\n", card, snd_strerror(err)); snd_ctl_close(handle); goto next_card; } dev = -1; while(1) { const char *cname, *dname, *cid; void *temp; if(snd_ctl_pcm_next_device(handle, &dev) < 0) ERR("snd_ctl_pcm_next_device failed\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) ERR("control digital audio info (%i): %s\n", card, snd_strerror(err)); continue; } temp = realloc(DevList, sizeof(DevMap) * (idx+1)); if(temp) { DevList = temp; cname = snd_ctl_card_info_get_name(info); dname = snd_pcm_info_get_name(pcminfo); cid = snd_ctl_card_info_get_id(info); snprintf(name, sizeof(name), "%s, %s (CARD=%s,DEV=%d)", cname, dname, cid, dev); DevList[idx].name = strdup(name); DevList[idx].card = strdup(cid); DevList[idx].dev = dev; idx++; } } snd_ctl_close(handle); next_card: if(snd_card_next(&card) < 0) { ERR("snd_card_next failed\n"); break; } } snd_pcm_info_free(pcminfo); snd_ctl_card_info_free(info); *count = idx; return DevList; }