gchar * gst_alsa_find_device_name (GstObject * obj, const gchar * device, snd_pcm_t * handle, snd_pcm_stream_t stream) { gchar *ret = NULL; if (device != NULL) { gchar *dev, *comma; gint devnum; GST_LOG_OBJECT (obj, "Trying to get device name from string '%s'", device); /* only want name:card bit, but not devices and subdevices */ dev = g_strdup (device); if ((comma = strchr (dev, ','))) { *comma = '\0'; devnum = atoi (comma + 1); ret = gst_alsa_find_device_name_no_handle (obj, dev, devnum, stream); } g_free (dev); } if (ret == NULL && handle != NULL) { snd_pcm_info_t *info; GST_LOG_OBJECT (obj, "Trying to get device name from open handle"); snd_pcm_info_malloc (&info); snd_pcm_info (handle, info); ret = g_strdup (snd_pcm_info_get_name (info)); snd_pcm_info_free (info); } GST_LOG_OBJECT (obj, "Device name for device '%s': %s", GST_STR_NULL (device), GST_STR_NULL (ret)); return ret; }
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; }
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); }
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; }
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; }