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; }
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. }
static void deviceList(int type, vector_DevMap *devmap) { snd_ctl_t* handle; snd_pcm_info_t pcminfo; int max_cards, card, err, dev; DevMap entry; char name[1024]; struct snd_ctl_hw_info info; void* temp; max_cards = snd_cards(); if(max_cards < 0) return; VECTOR_RESERVE(*devmap, max_cards+1); VECTOR_RESIZE(*devmap, 0); entry.name = strdup(qsaDevice); entry.card = 0; entry.dev = 0; VECTOR_PUSH_BACK(*devmap, entry); for(card = 0;card < max_cards;card++) { if((err=snd_ctl_open(&handle, card)) < 0) continue; if((err=snd_ctl_hw_info(handle, &info)) < 0) { snd_ctl_close(handle); continue; } for(dev = 0;dev < (int)info.pcmdevs;dev++) { if((err=snd_ctl_pcm_info(handle, dev, &pcminfo)) < 0) continue; if((type==SND_PCM_CHANNEL_PLAYBACK && (pcminfo.flags&SND_PCM_INFO_PLAYBACK)) || (type==SND_PCM_CHANNEL_CAPTURE && (pcminfo.flags&SND_PCM_INFO_CAPTURE))) { snprintf(name, sizeof(name), "%s [%s] (hw:%d,%d)", info.name, pcminfo.name, card, dev); entry.name = strdup(name); entry.card = card; entry.dev = dev; VECTOR_PUSH_BACK(*devmap, entry); TRACE("Got device \"%s\", card %d, dev %d\n", name, card, dev); } } snd_ctl_close(handle); } }
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; }
bool AlsaLayer::soundCardIndexExists(int card, DeviceType stream) { snd_pcm_info_t *pcminfo; snd_pcm_info_alloca(&pcminfo); std::string name("hw:"); std::stringstream ss; ss << card; name.append(ss.str()); snd_ctl_t* handle; if (snd_ctl_open(&handle, name.c_str(), 0) != 0) return false; snd_pcm_info_set_stream(pcminfo, stream == DeviceType::PLAYBACK ? SND_PCM_STREAM_PLAYBACK : SND_PCM_STREAM_CAPTURE); bool ret = snd_ctl_pcm_info(handle, pcminfo) >= 0; snd_ctl_close(handle); return ret; }
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); } }
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; }
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; }
static int list_devices_for_card(int card, struct modlist *ml, const struct dmDrive *drive, const uint32_t parent, const char *mask, unsigned long opt) { char dev[64]; char *card_name; int err; int pcm_device=-1; int cards=0; snd_ctl_t *ctl; snprintf(dev, sizeof(dev), "hw:%i", card); #ifdef ALSA_DEBUG fprintf(stderr, "ALSA snd_ctl_open(&ctl, \"%s\", 0) = ", dev); #endif if ((err=snd_ctl_open(&ctl, dev, 0))<0) { #ifdef ALSA_DEBUG fprintf(stderr, "failed: %s\n", snd_strerror(-err)); #endif return cards; } #ifdef ALSA_DEBUG fprintf(stderr, "ok\n"); fprintf(stderr, "ALSA snd_card_get_name(%i, &card_name) = ", card); #endif if ((err=snd_card_get_name(card, &card_name))!=0) { #ifdef ALSA_DEBUG fprintf(stderr, "failed: %s\n", snd_strerror(-err)); #endif card_name="Unknown card"; } #ifdef ALSA_DEBUG fprintf(stderr, "ok, %s name: %s\n", dev, card_name); #endif while(1) { #ifdef ALSA_DEBUG fprintf(stderr, "ALSA snd_ctl_pcm_next_device(ctl, &pcm_device (%i)) = ", pcm_device); #endif if ((err=snd_ctl_pcm_next_device(ctl, &pcm_device))<0) { #ifdef ALSA_DEBUG fprintf(stderr, " failed: %s\n", snd_strerror(-err)); #endif pcm_device=-1; } #ifdef ALSA_DEBUG fprintf(stderr, "ok, pcm_device=%i\n", pcm_device); #endif if (pcm_device<0) break; #ifdef ALSA_DEBUG fprintf(stderr, "ALSA snd_pcm_info_set_device(pcm_info, %i)\n", pcm_device); #endif snd_pcm_info_set_device(pcm_info, pcm_device); #ifdef ALSA_DEBUG fprintf(stderr, "ALSA snd_pcm_info_set_subdevice(pcm_info, 0)\n"); #endif snd_pcm_info_set_subdevice(pcm_info, 0); #ifdef ALSA_DEBUG fprintf(stderr, "ALSA snd_pcm_info_set_stream(pcm_info, SND_PCM_STREAM_PLAYBACK)\n"); #endif snd_pcm_info_set_stream(pcm_info, SND_PCM_STREAM_PLAYBACK); #ifdef ALSA_DEBUG fprintf(stderr, "ALSA snd_ctl_pcm_info(ctl, pcm_info) = "); #endif if ((err=snd_ctl_pcm_info(ctl, pcm_info))<0) { #ifdef ALSA_DEBUG fprintf(stderr, "failed: %s\n", snd_strerror(-err)); #endif if (err!=-ENOENT) fprintf(stderr, "ALSA: snd_device_from_card(): snd_ctl_pcm_info(%d:%d) failed: %s\n", card, pcm_device, snd_strerror(-err)); continue; } #ifdef ALSA_DEBUG fprintf(stderr, "ALSA: hw:%d,%d: name %s\n", card, pcm_device, snd_pcm_info_get_name(pcm_info)); #endif if (ml) { struct modlistentry entry; memset(&entry, 0, sizeof(entry)); snprintf(entry.shortname, sizeof(entry.shortname), "hw:%d,%d.dev", card, pcm_device); strcpy(entry.name, entry.shortname); entry.drive=drive; entry.dirdbfullpath=dirdbFindAndRef(parent, entry.name); entry.flags=MODLIST_FLAG_FILE|MODLIST_FLAG_VIRTUAL; entry.fileref=mdbGetModuleReference(entry.name, 0); if (entry.fileref!=0xffffffff) { struct moduleinfostruct mi; mdbGetModuleInfo(&mi, entry.fileref); mi.flags1&=~MDB_VIRTUAL; mi.channels=2; snprintf(mi.modname, sizeof(mi.modname), "%s", snd_pcm_info_get_name(pcm_info)); mi.modtype=mtUnRead; mdbWriteModuleInfo(entry.fileref, &mi); } entry.adb_ref=0xffffffff; entry.Read=0; entry.ReadHeader=0; entry.ReadHandle=alsaSelectPcmOut; modlist_append(ml, &entry); dirdbUnref(entry.dirdbfullpath); } cards++; } #ifdef ALSA_DEBUG fprintf(stderr, "ALSA snd_ctl_close(ctl)\n"); #endif snd_ctl_close(ctl); return cards; }
/* 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; }
bool AlsaBackend::ProbeDevice(DeviceInfo* device, StreamSpec& spec) { char *name; if (devicesList.size() <= 1) UpdateDevicesList(); size_t i = 1; // find device in device pool by given ID for (; i < devicesList.size(); ++i) { if ((device->guid[0] == 0 && device->id == devicesList.at(i).id) || strncmp(devicesList.at(i).guid, device->guid, DEVICE_NAME_MAXLEN) == 0) { Log("found device"); name = device->displayName; break; } } if (i >= devicesList.size()) { Log("ProbeDevice failed!"); return false; } // If device is BLUETOOTH type, don't waste time and start with 8KHz immediately. A2DP is not supported. if (device->type == DeviceInfo::TYPE_BLUETOOTH) { spec.rate = 8000; spec.channels = 1; } int result; char hwctl[8]; snd_ctl_t *chandle = 0; int openMode = SND_PCM_ASYNC; snd_pcm_stream_t stream; snd_pcm_info_t *pcminfo; snd_pcm_info_alloca(&pcminfo); snd_pcm_t *phandle = 0; snd_pcm_hw_params_t *params; snd_pcm_hw_params_alloca(¶ms); // Probe mixer for device if (!device->mixer) device->mixer = new AlsaVolumeControl; static_cast<AlsaVolumeControl*>(device->mixer)->ProbeMixer(device); // First try for playback stream = SND_PCM_STREAM_PLAYBACK; bool skipPlayback = false; if (device->type == DeviceInfo::TYPE_HW) { snprintf(hwctl, 8, "hw:%d", device->id); Log("Trying to open ctl %s", hwctl); result = snd_ctl_open(&chandle, hwctl, SND_CTL_NONBLOCK); //@todo snd_ctl_card_info() call? if (result >= 0) { snd_pcm_info_set_device(pcminfo, device->id); snd_pcm_info_set_subdevice(pcminfo, 0); snd_pcm_info_set_stream(pcminfo, stream); result = snd_ctl_pcm_info(chandle, pcminfo); if (result < 0) { Log("Device probably doesn't support playback (dev %d): %s", device->id, snd_strerror(result)); skipPlayback = true; } } else { Log("Device probably doesn't have ctl interface."); chandle = 0; } } if (!skipPlayback) { result = snd_pcm_open(&phandle, device->guid, stream, openMode | SND_PCM_NONBLOCK); if (result >= 0) { // The device is open ... fill the parameter structure. result = snd_pcm_hw_params_any(phandle, params); if (result >= 0) { // Get output channel information. unsigned int value; result = snd_pcm_hw_params_get_channels_max(params, &value); if (result >= 0) { device->outMaxChannels = value; snd_pcm_close(phandle); } else { snd_pcm_close(phandle); // @todo unify handle closing calls in case of errors Log("error getting device %s output channels: %s", name, snd_strerror(result)); } } else { snd_pcm_close(phandle); // @todo unify handle closing calls in case of errors (_EE_CALL) Log("snd_pcm_hw_params error for device %s: %s", name, snd_strerror(result)); } } else { Log("snd_pcm_open error for playback on device %s: %s", name, snd_strerror(result)); } } // Now try for capture stream = SND_PCM_STREAM_CAPTURE; snd_pcm_info_set_stream(pcminfo, stream); if (device->type == DeviceInfo::TYPE_HW && chandle) { result = snd_ctl_pcm_info(chandle, pcminfo); snd_ctl_close(chandle); if (result < 0) { Log("Device probably doesn't support capture: %s", snd_strerror(result)); if (device->outMaxChannels == 0) // cannot playback/capture at all { Log("ProbeDevice failed!"); return false; } return ProbeParameters(device, spec, phandle, stream, pcminfo, name, params); } } result = snd_pcm_open(&phandle, device->guid, stream, openMode | SND_PCM_NONBLOCK); if (result < 0) { Log("snd_pcm_open error for capture on device %s: %s", name, snd_strerror(result)); if (device->outMaxChannels == 0) { Log("ProbeDevice failed!"); return false; } return ProbeParameters(device, spec, phandle, stream, pcminfo, name, params); } // The device is open ... fill the parameter structure. result = snd_pcm_hw_params_any(phandle, params); if (result < 0) { snd_pcm_close(phandle); Log("snd_pcm_hw_params error for device %s: %s", name, snd_strerror(result)); if (device->outMaxChannels == 0) { Log("ProbeDevice failed!"); return false; } return ProbeParameters(device, spec, phandle, stream, pcminfo, name, params); } unsigned int value; result = snd_pcm_hw_params_get_channels_max(params, &value); if (result < 0) { snd_pcm_close(phandle); Log("error getting device %s input channels: %s", name, snd_strerror(result)); if (device->outMaxChannels == 0) { Log("ProbeDevice failed!"); return false; } return ProbeParameters(device, spec, phandle, stream, pcminfo, name, params); } device->inMaxChannels = value; snd_pcm_close(phandle); return ProbeParameters(device, spec, phandle, stream, pcminfo, name, params); }
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; } } } }/*}}}*/
void ALSAAudioCaptureDevice::enumerateDevices(std::vector<AudioCaptureDevice::DeviceIdPtr>& devices) { /* Enumerate all ALSA cards and devices: */ int cardIndex=-1; // Start with first card while(true) { /* Get the index of the next card: */ if(snd_card_next(&cardIndex)!=0||cardIndex<0) { /* There was an error, or there are no more cards: */ break; } /* Open the card's control interface: */ char cardName[20]; snprintf(cardName,sizeof(cardName),"hw:%d",cardIndex); snd_ctl_t* cardHandle; if(snd_ctl_open(&cardHandle,cardName,0)!=0) break; /* Enumerate all PCM devices on this card: */ int numCardDevices=0; int pcmIndex=-1; while(true) { /* Get the index of the next PCM device: */ if(snd_ctl_pcm_next_device(cardHandle,&pcmIndex)!=0||pcmIndex<0) { /* There was an error, or there are no more PCM devices: */ break; } /* Create an info structure for the PCM device: */ snd_pcm_info_t* pcmInfo; snd_pcm_info_alloca(&pcmInfo); snd_pcm_info_set_device(pcmInfo,pcmIndex); snd_pcm_info_set_stream(pcmInfo,SND_PCM_STREAM_CAPTURE); /* Get the number of capture subdevices for the device: */ if(snd_ctl_pcm_info(cardHandle,pcmInfo)!=0) break; int numSubDevices=snd_pcm_info_get_subdevices_count(pcmInfo); for(int subDeviceIndex=0;subDeviceIndex<numSubDevices;++subDeviceIndex) { /* Query information about the subdevice: */ snd_pcm_info_set_subdevice(pcmInfo,subDeviceIndex); if(snd_ctl_pcm_info(cardHandle,pcmInfo)==0) { /* Query the card's name: */ char* cardName; if(snd_card_get_name(cardIndex,&cardName)==0) { /* Create a device ID: */ std::string deviceName=cardName; free(cardName); if(numCardDevices>0) { char suffix[10]; snprintf(suffix,sizeof(suffix),":%d",numCardDevices); deviceName.append(suffix); } DeviceId* newDeviceId=new DeviceId(deviceName); /* Set the PCM device name: */ char pcmDeviceName[20]; if(numSubDevices>1) snprintf(pcmDeviceName,sizeof(pcmDeviceName),"plughw:%d,%d,%d",snd_pcm_info_get_card(pcmInfo),snd_pcm_info_get_device(pcmInfo),snd_pcm_info_get_subdevice(pcmInfo)); else snprintf(pcmDeviceName,sizeof(pcmDeviceName),"plughw:%d,%d",snd_pcm_info_get_card(pcmInfo),snd_pcm_info_get_device(pcmInfo)); newDeviceId->pcmDeviceName=pcmDeviceName; /* Store the device ID: */ devices.push_back(newDeviceId); ++numCardDevices; } } } } /* Close the card's control interface: */ snd_ctl_close(cardHandle); } }
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 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); } }
static void GetDevicesForCard( module_config_t *p_item, int i_card ) { int i_pcm_device = -1; int i_err = 0; snd_pcm_info_t *p_pcm_info; snd_ctl_t *p_ctl; char psz_dev[64]; char *psz_card_name; sprintf( psz_dev, "hw:%i", i_card ); if( ( i_err = snd_ctl_open( &p_ctl, psz_dev, 0 ) ) < 0 ) return; if( ( i_err = snd_card_get_name( i_card, &psz_card_name ) ) != 0) psz_card_name = _("Unknown soundcard"); snd_pcm_info_alloca( &p_pcm_info ); for (;;) { char *psz_device, *psz_descr; if( ( i_err = snd_ctl_pcm_next_device( p_ctl, &i_pcm_device ) ) < 0 ) i_pcm_device = -1; if( i_pcm_device < 0 ) break; snd_pcm_info_set_device( p_pcm_info, i_pcm_device ); snd_pcm_info_set_subdevice( p_pcm_info, 0 ); snd_pcm_info_set_stream( p_pcm_info, SND_PCM_STREAM_PLAYBACK ); if( ( i_err = snd_ctl_pcm_info( p_ctl, p_pcm_info ) ) < 0 ) { if( i_err != -ENOENT ) { /*printf( "get_devices_for_card(): " "snd_ctl_pcm_info() " "failed (%d:%d): %s.\n", i_card, i_pcm_device, snd_strerror( -i_err ) );*/ } continue; } if( asprintf( &psz_device, "hw:%d,%d", i_card, i_pcm_device ) == -1 ) break; if( asprintf( &psz_descr, "%s: %s (%s)", psz_card_name, snd_pcm_info_get_name(p_pcm_info), psz_device ) == -1 ) { free( psz_device ); break; } p_item->ppsz_list = (char **)realloc( p_item->ppsz_list, (p_item->i_list + 2) * sizeof(char *) ); p_item->ppsz_list_text = (char **)realloc( p_item->ppsz_list_text, (p_item->i_list + 2) * sizeof(char *) ); p_item->ppsz_list[ p_item->i_list ] = psz_device; p_item->ppsz_list_text[ p_item->i_list ] = psz_descr; p_item->i_list++; p_item->ppsz_list[ p_item->i_list ] = NULL; p_item->ppsz_list_text[ p_item->i_list ] = NULL; } snd_ctl_close( p_ctl ); }
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; }
// 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 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; }
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); }
/* 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 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; }
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 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); }
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; } } }