void AlsaOutputDeviceFactory::rescan() {
	device_names.clear();	
	device_channels.clear();
	//In the following, we always assume that the device supports 8 channels.
	//Todo: can we get more info out of Alsa somehow?
	void** hints = nullptr;
	auto hint_success = snd_device_name_hint(-1, "pcm", &hints);
	if(hint_success != 0 || hints == nullptr) {
		output_count = 0;
		return; //Advertise no devices because scanning failed.
	}
	for(int i = 0; hints[i] != nullptr; i++) {
		auto hint = hints[i];
		auto name = snd_device_name_get_hint(hint, "NAME");
		if(name == nullptr) continue; 
		auto desc = snd_device_name_get_hint(hint, "DESC");
		auto ioid = snd_device_name_get_hint(hint, "IOID");
		if(ioid != nullptr && strcmp(ioid, "Input") != 0) goto freeing;
		device_names.push_back(std::string(name));
		device_channels.push_back(8); //Can we do better?
		freeing:
		if(name) free(name);
		if(desc) free(desc);
		if(ioid) free(ioid);
	}
	snd_device_name_free_hint(hints);
	output_count = device_names.size();
}
示例#2
0
// derived from alsa-utils/aplay.c
static void
palsa_enum_soundcards (void (*callback)(const char *name, const char *desc, void *), void *userdata) {
    void **hints, **n;
    char *name, *descr, *io;
    const char *filter = "Output";
    if (snd_device_name_hint(-1, "pcm", &hints) < 0)
        return;
    n = hints;
    while (*n != NULL) {
        name = snd_device_name_get_hint(*n, "NAME");
        descr = snd_device_name_get_hint(*n, "DESC");
        io = snd_device_name_get_hint(*n, "IOID");
        if (io == NULL || !strcmp(io, filter)) {
            if (name && descr && callback) {
                callback (name, descr, userdata);
            }
        }
        if (name != NULL)
            free(name);
        if (descr != NULL)
            free(descr);
        if (io != NULL)
            free(io);
        n++;
    }
    snd_device_name_free_hint(hints);
}
示例#3
0
文件: AudioAlsa.cpp 项目: uro5h/lmms
/**
 * @brief Creates a list of all available devices.
 *
 * Uses the hints API of ALSA to collect all devices. This also includes plug
 * devices. The reason to collect these and not the raw hardware devices
 * (e.g. hw:0,0) is that hardware devices often have a very limited number of
 * supported formats, etc. Plugs on the other hand are software components that
 * map all types of formats and inputs to the hardware and therefore they are
 * much more flexible and more what we want.
 *
 * Further helpful info http://jan.newmarch.name/LinuxSound/Sampled/Alsa/.
 *
 * @return A collection of devices found on the system.
 */
AudioAlsa::DeviceInfoCollection AudioAlsa::getAvailableDevices()
{
	DeviceInfoCollection deviceInfos;

	char **hints;

	/* Enumerate sound devices */
	int err = snd_device_name_hint(-1, "pcm", (void***)&hints);
	if (err != 0)
	{
		return deviceInfos;
	}

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

		if (name != 0 && description != 0)
		{
			deviceInfos.push_back(DeviceInfo(QString(name), QString(description)));
		}

		free(name);
		free(description);

		n++;
	}

	//Free the hint buffer
	snd_device_name_free_hint((void**)hints);

	return deviceInfos;
}
示例#4
0
文件: alsa_pcm.c 项目: recri/keyer
static int alsa_pcm_list(ClientData clientData, Tcl_Interp *interp)
{
  void **hints, **n;
  Tcl_Obj *pcm = Tcl_NewListObj(0, NULL);

  if (snd_device_name_hint(-1, "pcm", &hints) >= 0) {
    n = hints;
    while (*n != NULL) {
      char *name, *descr, *io;
      name = snd_device_name_get_hint(*n, "NAME");
      descr = snd_device_name_get_hint(*n, "DESC");
      io = snd_device_name_get_hint(*n, "IOID");
      Tcl_ListObjAppendElement(interp, pcm, Tcl_ObjPrintf("%s %s %s", name?name:"(null)", descr?descr:"(null)", io?io:"(null)"));
      if (name != NULL)
	free(name);
      if (descr != NULL)
	free(descr);
      if (io != NULL)
	free(io);
      n++;
    }
    snd_device_name_free_hint(hints);
  }
  Tcl_SetObjResult(interp, pcm);
  return TCL_OK;
}
示例#5
0
void AlsaDeviceListModel::init(
    const char * _iface,
    const char * _filter)
{
    void **hints, **n;
    char *name, *descr, *io;

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

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

        // Filter out non-null or filtered items
        if (io == NULL || _filter == NULL || strcmp(io, _filter) == 0)
            m_devices.append(StringPair(name, descr));

        if (name != NULL)
            free(name);
        if (descr != NULL)
            free(descr);
        if (io != NULL)
            free(io);
        n++;
    }
    snd_device_name_free_hint(hints);
}
示例#6
0
Array AudioDriverALSA::get_device_list() {

	Array list;

	list.push_back("Default");

	void **hints;

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

	for (void **n = hints; *n != NULL; n++) {
		char *name = snd_device_name_get_hint(*n, "NAME");
		char *desc = snd_device_name_get_hint(*n, "DESC");

		if (name != NULL && !strncmp(name, "plughw", 6)) {
			if (desc) {
				list.push_back(String(name) + ";" + String(desc));
			} else {
				list.push_back(String(name));
			}
		}

		if (desc != NULL)
			free(desc);
		if (name != NULL)
			free(name);
	}
	snd_device_name_free_hint(hints);

	return list;
}
示例#7
0
文件: main.c 项目: hessu/aisdecoder
void printInDevices() {
    char **hints;
    /* Enumerate sound devices */
    int err = snd_device_name_hint(0, "pcm", (void***)&hints);
    if (err != 0) {
        fprintf(stderr, "Can't read data\n");
        exit(EXIT_FAILURE);
    }

    char** n = hints;
    while (*n != NULL) {
        char *name = snd_device_name_get_hint(*n, "NAME");
        char *desc = snd_device_name_get_hint(*n, "DESC");
        char *type = snd_device_name_get_hint(*n, "IOID");
        if (name != NULL && desc != NULL) {
            if (type == NULL || !strcmp(type, "Input")) {
                printf("%s\n%s: <%s>\n\n", desc, type == NULL ? "Input/Output" : "Input",name);
            }
        }
        if (name != NULL) free(name);
        if (name != NULL) free(desc);
        if (name != NULL) free(type);
        n++;
    }

    //Free hint buffer too
    snd_device_name_free_hint((void**)hints);
    snd_config_update_free_global();
}
QList<QByteArray> QAlsaAudioDeviceInfo::availableDevices(QAudio::Mode mode)
{
    QList<QByteArray> devices;
    QByteArray filter;

#if(SND_LIB_MAJOR == 1 && SND_LIB_MINOR == 0 && SND_LIB_SUBMINOR >= 14)
    // Create a list of all current audio devices that support mode
    void **hints, **n;
    char *name, *descr, *io;

    if(snd_device_name_hint(-1, "pcm", &hints) < 0) {
        qWarning() << "no alsa devices available";
        return devices;
    }
    n = hints;

    if(mode == QAudio::AudioInput) {
        filter = "Input";
    } else {
        filter = "Output";
    }

    while (*n != NULL) {
        name = snd_device_name_get_hint(*n, "NAME");
        if (name != 0 && qstrcmp(name, "null") != 0) {
            descr = snd_device_name_get_hint(*n, "DESC");
            io = snd_device_name_get_hint(*n, "IOID");

            if ((descr != NULL) && ((io == NULL) || (io == filter))) {
                QString deviceName = QLatin1String(name);
                QString deviceDescription = QLatin1String(descr);
                if (deviceDescription.contains(QLatin1String("Default Audio Device")))
                    devices.prepend(deviceName.toLocal8Bit().constData());
                else
                    devices.append(deviceName.toLocal8Bit().constData());
            }

            free(descr);
            free(io);
        }
        free(name);
        ++n;
    }
    snd_device_name_free_hint(hints);
#else
    int idx = 0;
    char* name;

    while(snd_card_get_name(idx,&name) == 0) {
        devices.append(name);
        idx++;
    }
#endif

    if (devices.size() > 0)
        devices.append("default");

    return devices;
}
std::vector<std::string> alsa_get_devicelist()
{
	std::vector<std::string> result;

	char **hints;
	int err = snd_device_name_hint(-1, "pcm", (void***)&hints);

	// Error initializing ALSA
	if (err != 0)
		return result;

	// special value to automatically detect on initialization
	result.push_back("auto");

	char** n = hints;
	while (*n != NULL)
	{
		// Get the type (NULL/Input/Output)
		char *type = snd_device_name_get_hint(*n, "IOID");
		char *name = snd_device_name_get_hint(*n, "NAME");

		if (name != NULL)
		{
			// We only want output or special devices (like "default" or "pulse")
			// TODO Only those with type == NULL?
			if (type == NULL || strcmp(type, "Output") == 0)
			{
				// TODO Check if device works (however we need to hash the resulting list then)
				/*snd_pcm_t *handle;
				int rc = snd_pcm_open(&handle, name, SND_PCM_STREAM_PLAYBACK, 0);

				if (rc == 0)
				{
					result.push_back(name);
					snd_pcm_close(handle);
				}
				*/

				result.push_back(name);
			}

		}

		if (type != NULL)
			free(type);

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

		n++;
	}

	snd_device_name_free_hint((void**)hints);

	return result;
}
示例#10
0
QList<QByteArray> QAudioDeviceInfoInternal::deviceList(QAudio::Mode mode)
{
    QList<QByteArray> devices;
    QByteArray filter;

    // Create a list of all current audio devices that support mode
    void **hints, **n;
    char *name, *descr, *io;

    if(snd_device_name_hint(-1, "pcm", &hints) < 0) {
        qWarning() << "no alsa devices available";
        return devices;
    }
    n = hints;

    if(mode == QAudio::AudioInput) {
        filter = "Input";
    } else {
        filter = "Output";
    }

    while (*n != NULL) {
        name = snd_device_name_get_hint(*n, "NAME");
        descr = snd_device_name_get_hint(*n, "DESC");
        io = snd_device_name_get_hint(*n, "IOID");
        if((name != NULL) && (descr != NULL) && ((io == NULL) || (io == filter))) {
            QString str = QLatin1String(name);

            if(str.contains(QLatin1String("default"))) {
                int pos = str.indexOf(QLatin1String("="),0);
                devices.append(str.mid(pos+1).toLocal8Bit().constData());
            }
        }
        if(name != NULL)
            free(name);
        if(descr != NULL)
            free(descr);
        if(io != NULL)
            free(io);
        ++n;
    }
    snd_device_name_free_hint(hints);

    if(devices.size() > 0) {
        devices.append("default");
    }

    return devices;
}
示例#11
0
static void *alsa_device_list_new(void *data)
{
   void **hints, **n;
   union string_list_elem_attr attr;
   struct string_list *s = string_list_new();

   if (!s)
      return NULL;

   attr.i = 0;

   if (snd_device_name_hint(-1, "pcm", &hints) != 0)
      goto error;

   n      = hints;

   while (*n != NULL)
   {
      char *name = snd_device_name_get_hint(*n, "NAME");
      char *io   = snd_device_name_get_hint(*n, "IOID");
      char *desc = snd_device_name_get_hint(*n, "DESC");

      /* description of device IOID - input / output identifcation
       * ("Input" or "Output"), NULL means both) */

      if (!io || string_is_equal(io,"Output"))
         string_list_append(s, name, attr);

      if (name)
         free(name);
      if (io)
         free(io);
      if (desc)
         free(desc);

      n++;
   }

   /* free hint buffer too */
   snd_device_name_free_hint(hints);

   return s;

error:
   string_list_free(s);
   return NULL;
}
示例#12
0
int main()
{
    size_t start, end;
    std::string desc;
    void ** hints, ** str_c;
    char * name_c, * desc_c;
    int index = 0;
    const char * ifaces[] = {
        "card", "pcm", "rawmidi", "timer", "seq", "hwdep", 0
    };

    snd_config_update();

    while (ifaces[index]) {
        std::cout << "---- Trying \"" << ifaces[index] << "\" ----\n\n";
        if (snd_device_name_hint(-1, ifaces[index], &hints) < 0) {
            std::cerr << "hint failed on \"" << ifaces[index] << "\"\n\n";
            ++index;
            continue;
        }

        str_c = hints;
        while (*str_c) {
            name_c = snd_device_name_get_hint(*str_c, "NAME");
            desc_c = snd_device_name_get_hint(*str_c, "DESC");

            std::cout << name_c << "\n";
            start = 0;
            desc = desc_c;
            do {
                end = desc.find("\n", start);
                std::cout << "   " << desc.substr(start, end - start) << "\n";
                start = end + 1;
            } while (end != std::string::npos);
            std::cout << "\n";
            free(name_c);
            free(desc_c);
            ++str_c;
        }
        snd_device_name_free_hint(hints);
        ++index;
    }
    return 0;
}
示例#13
0
void
moko_alsa_volume_control_set_device_from_name (MokoAlsaVolumeControl *control,
					      const gchar *name)
{
	gint i = -1;
	
	if (!name) {
		moko_alsa_volume_control_set_device (control, NULL);
		return;
	}

	while (snd_card_next (&i) == 0) {
		void **hints;
		
		if (i == -1) break;
	
		if (snd_device_name_hint (i, "pcm", &hints) == 0) {
			gchar *separator;
			gchar *device = strdup (snd_device_name_get_hint (
				hints[0], "DESC"));
			
			if ((separator = strchr (device, ',')))
			  *separator = '\0';
			
			if (strcmp (device, name) == 0) {
				g_free (device);
				
				device = strdup (snd_device_name_get_hint (
					hints[0], "NAME"));
				snd_device_name_free_hint (hints);
				strchr (device, ':')[0] = '\0';
				
				moko_alsa_volume_control_set_device (
					control, device);
				return;
			}
			snd_device_name_free_hint (hints);
			g_free (device);
		}
	}
	
	g_debug ("Card '%s' not found", name);
}
static
char *
find_pcm_name(const char *device_longname)
{
    char *pcm_name = NULL;
    int   card = -1;
    int   done = 0;

    if (!device_longname)
        return strdup("default");

    while (!done) {
        int err = snd_card_next(&card);
        if (err != 0)
            break;
        if (card == -1)
            break;

        char *longname = NULL;
        if (snd_card_get_longname(card, &longname) != 0)
            goto next_0;

        if (!longname)
            goto next_0;

        if (strcmp(device_longname, longname) != 0)
            goto next_2;

        void **hints;
        if (snd_device_name_hint(card, "pcm", &hints) != 0)
            goto next_2;

        for (int k = 0; hints[k] != NULL; k ++) {
            pcm_name = snd_device_name_get_hint(hints[k], "NAME");
            if (strncmp(pcm_name, "default:", strlen("default:")) == 0) {
                done = 1;
                goto next_3;
            }
            free(pcm_name);
            pcm_name = NULL;
        }

    next_3:
        snd_device_name_free_hint(hints);
    next_2:
        free(longname);
    next_0:
        continue;
    }

    if (!pcm_name)
        pcm_name = strdup("default");

    return pcm_name;
}
示例#15
0
void QAudioDeviceInfoInternal::checkSurround()
{
    QList<QByteArray> devices;
    surround40 = false;
    surround51 = false;
    surround71 = false;

    void **hints, **n;
    char *name, *descr, *io;

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

    n = hints;

    while (*n != NULL) {
        name = snd_device_name_get_hint(*n, "NAME");
        descr = snd_device_name_get_hint(*n, "DESC");
        io = snd_device_name_get_hint(*n, "IOID");
        if((name != NULL) && (descr != NULL)) {
            QString deviceName = QLatin1String(name);
            if (mode == QAudio::AudioOutput) {
                if(deviceName.contains(QLatin1String("surround40")))
                    surround40 = true;
                if(deviceName.contains(QLatin1String("surround51")))
                    surround51 = true;
                if(deviceName.contains(QLatin1String("surround71")))
                    surround71 = true;
            }
        }
        if(name != NULL)
            free(name);
        if(descr != NULL)
            free(descr);
        if(io != NULL)
            free(io);
        ++n;
    }
    snd_device_name_free_hint(hints);
}
示例#16
0
int main(int argc, char** argv) {
    
    if (argc != 2) {
        fprintf(stderr, "Usage: %s Input|Output\n", argv[0]);
        fprintf(stderr, "The \"Input\" filter lists all mics, the \"Output\" filter all playback devices.\n");
        fprintf(stderr, "The filter name is case senstive!\n");
        return 1;
    }
    
    void **hints;
    char *name, *desc, *io;
    const char *filter = argv[1];
    
    int err = snd_device_name_hint(-1, "pcm", &hints);
    if (err != 0)
        return err;
    
    //filter = stream == SND_PCM_STREAM_CAPTURE ? "Input" : "Output";
    
    for(void** n = hints; *n != NULL; n++) {
        name = snd_device_name_get_hint(*n, "NAME");
        desc = snd_device_name_get_hint(*n, "DESC");
        io   = snd_device_name_get_hint(*n, "IOID");
        
        if ( io != NULL && strcmp(io, filter) == 0 ) {
            printf("name: %s\n", name);
            printf("  desc: %s\n", desc);
            printf("  io: %s\n", io);
        }
        
        free(name);
        free(desc);
        free(io);
    }
    
    snd_device_name_free_hint(hints);
    
    return 0;
}
示例#17
0
文件: alsa.c 项目: DEGAUSSE/alsa
void detect_pcm(AudioCapture *capture) {
  void **hints, **n;
  char *name, *desc, *io;
  
  snd_device_name_hint(-1, "pcm", &hints);
  n = hints;
  
  char *detected_name = NULL;
    
  int pcm_id = 0;
  fprintf(stderr, "Selecting (%d)\r\n", capture->selected_device);
  
  while(*n && !detected_name) {
		io = snd_device_name_get_hint(*n, "IOID");
    if(!io || strcmp(io, "Input")) {
      if(io) free(io);
      n++;
      pcm_id++;
      continue;
    }
    name = snd_device_name_get_hint(*n, "NAME");
    desc = snd_device_name_get_hint(*n, "DESC");
    if((capture->selected_device < 0 && strstr(desc, "USB") && strstr(desc, "Default Audio")) || capture->selected_device == pcm_id) {
      detected_name = (char *)malloc(strlen(name) + 1);
      strcpy(detected_name, name);
    }
    free(name);
    free(desc);
    n++;
  }
  
  snd_device_name_free_hint(hints);
  // This is so for USB
  //capture->pcm_id = 1;
  
  fprintf(stderr, "Selected (%d)\r\n", pcm_id);
  capture->pcm_name = detected_name;
}
示例#18
0
/* API: refresh the device list */
static pj_status_t alsa_factory_refresh(pjmedia_aud_dev_factory *f)
{
    struct alsa_factory *af = (struct alsa_factory*)f;
    char **hints, **n;
    int err;

    TRACE_((THIS_FILE, "pjmedia_snd_init: Enumerate sound devices"));

    if (af->pool != NULL) {
	pj_pool_release(af->pool);
	af->pool = NULL;
    }

    af->pool = pj_pool_create(af->pf, "alsa_aud", 256, 256, NULL);
    af->dev_cnt = 0;

    /* Enumerate sound devices */
    err = snd_device_name_hint(-1, "pcm", (void***)&hints);
    if (err != 0)
	return PJMEDIA_EAUD_SYSERR;

    /* Set a null error handler prior to enumeration to suppress errors */
    snd_lib_error_set_handler(null_alsa_error_handler);

    n = hints;
    while (*n != NULL) {
	char *name = snd_device_name_get_hint(*n, "NAME");
	if (name != NULL) {
	    if (0 != strcmp("null", name))
		add_dev(af, name);
	    free(name);
	}
	n++;
    }

    /* Get the mixer name */
    get_mixer_name(af);

    /* Install error handler after enumeration, otherwise we'll get many
     * error messages about invalid card/device ID.
     */
    snd_lib_error_set_handler(alsa_error_handler);

    err = snd_device_name_free_hint((void**)hints);

    PJ_LOG(4,(THIS_FILE, "ALSA driver found %d devices", af->dev_cnt));

    return PJ_SUCCESS;
}
示例#19
0
void list_devices(void) {
	void **hints, **n;
	if (snd_device_name_hint(-1, "pcm", &hints) >= 0) {
		n = hints;
		printf("Output devices:\n");
		while (*n) {
			char *name = snd_device_name_get_hint(*n, "NAME");
			char *desc = snd_device_name_get_hint(*n, "DESC");
			if (name) printf("  %-30s", name);
			if (desc) {
				char *s1 = strtok(desc, "\n");
				char *s2 = strtok(NULL, "\n");
				if (s1) printf(" - %s", s1);
				if (s2) printf(" - %s", s2);
			}
			printf("\n");
			if (name) free(name);
			if (desc) free(desc);
			n++;
		}
		snd_device_name_free_hint(hints);
	}
	printf("\n");
}
示例#20
0
void
moko_alsa_volume_control_set_device_from_card_number (
	MokoAlsaVolumeControl *control, gint number)
{
	void **hints;
	
	if (snd_device_name_hint (number, "pcm", &hints) == 0) {
		gchar *device = strdup (snd_device_name_get_hint (
			hints[0], "NAME"));
		snd_device_name_free_hint (hints);
		strchr (device, ':')[0] = '\0';
		
		moko_alsa_volume_control_set_device (control, device);
		g_free (device);
	} else
		g_debug ("Unable to find card number %d", number);
}
void ProjectOptions::InitDevInfo()
{
	snd_config_update();

	int ctlNum = -1;
	SoundDevInfo *inf = waveList.AddItem();
	inf->name = "default";
	inf->id = -1;
	inf->sub = -1;
	inf->type = 0;
	inf->info = NULL;

	while (snd_card_next(&ctlNum) == 0 && ctlNum >= 0 )
	{
#if SND_LIB_VERSION >= 0x1000E
		void **hints = 0;
		void **hh;
		if (snd_device_name_hint(ctlNum, "pcm", &hints) == 0)
		{
			hh = hints;
			while (*hh)
			{
				char *name = snd_device_name_get_hint(*hh, "NAME");
				char *desc = snd_device_name_get_hint(*hh, "DESC");
				for (char *cp = desc; *cp; cp++)
				{
					if (*cp < 0x20)
						*cp = ' ';
				}
				SoundDevInfo *inf = waveList.AddItem();
				inf->id = ctlNum;
				inf->sub = 0;
				inf->type = 0;
				inf->name = desc;
				inf->info = name;
				if (desc)
					free(desc);
				hh++;
			}
			snd_device_name_free_hint(hints);
		}
		if (snd_device_name_hint(ctlNum, "rawmidi", &hints) == 0)
		{
			hh = hints;
			while (*hh)
			{
				char *name = snd_device_name_get_hint(*hh, "NAME");
				char *desc = snd_device_name_get_hint(*hh, "DESC");
				for (char *cp = desc; *cp; cp++)
				{
					if (*cp < 0x20)
						*cp = ' ';
				}
				SoundDevInfo *inf = midiList.AddItem();
				inf->id = ctlNum;
				inf->sub = 0;
				inf->type = 0;
				inf->name = desc;
				inf->info = name;
				if (desc)
					free(desc);
				hh++;
			}
			snd_device_name_free_hint(hints);
		}
#endif
		/*
        snd_ctl_card_info_t *devInfo;
        snd_pcm_t *pcmHandle;
        snd_pcm_info_t *pcmInfo;
        snd_rawmidi_t *midiHandle;
        snd_rawmidi_info_t *midiInfo;

        char hw[128];

        snprintf(hw, sizeof(hw), "hw:%d", ctlNum);

        int devNum;
        snd_ctl_t *ctl;
        if (snd_ctl_open(&ctl, hw, 0) >= 0)
        {
        	devNum = -1;
			while (snd_ctl_pcm_next_device(ctl, &devNum) == 0 && devNum >= 0)
			{

				snprintf(hw, sizeof(hw), "hw:%d,%d", ctlNum, devNum);
				if (snd_pcm_open(&pcmHandle, hw, SND_PCM_STREAM_PLAYBACK, 0) >= 0)
				{
					snd_pcm_info_malloc(&pcmInfo);
					snd_pcm_info(pcmHandle, pcmInfo);
					SoundDevInfo *inf = waveList.AddItem();
					inf->id = ctlNum;
					inf->sub = devNum;
					inf->type = 0;
					inf->info = (void*)pcmInfo;
					inf->name = snd_pcm_info_get_name(pcmInfo);
					//inf->name += " - ";
					//inf->name += snd_pcm_info_get_subdevice_name(pcmInfo);
					snd_pcm_close(pcmHandle);
					pcmHandle = 0;
				}
			}
			devNum = -1;
			while (snd_ctl_rawmidi_next_device(ctl, &devNum) == 0 && devNum >= 0)
			{
				snprintf(hw, sizeof(hw), "hw:%d,%d", ctlNum, devNum);
				if (snd_rawmidi_open(&midiHandle, NULL, hw, 0) >= 0)
				{
					snd_rawmidi_info_malloc(&midiInfo);
					snd_rawmidi_info(midiHandle, midiInfo);
					SoundDevInfo *inf = midiList.AddItem();
					inf->id = ctlNum;
					inf->sub = devNum;
					inf->type = 1;
					inf->info = (void*)midiInfo;
					inf->name = snd_rawmidi_info_get_name(midiInfo);
					//inf->name += " - ";
					//inf->name += snd_rawmidi_info_get_subdevice_name(midiInfo);
					snd_rawmidi_close(midiHandle);
				}
			}
//			SoundDevInfo *inf = waveList.AddItem();
//			snd_ctl_card_info_alloca(&devInfo);
//	        snd_ctl_card_info(ctl, devInfo);
//			inf->name = snd_ctl_card_info_get_name(devInfo);
//			inf->info = reinterpret_cast<void*>(devInfo);
//			inf->id = (long)devNum;
			snd_ctl_close(ctl);
		}*/
	}
	// TODO:
	//snd_lib_error_set_handler(alsa_error_handler);
}
size_t stack_alsa_audio_device_list_outputs(StackAudioDeviceDesc **outputs)
{
	static const int common_sample_rates[] = {8000, 11025, 16000, 22050, 32000, 44100, 48000, 88200, 96000, 176400, 192000};
	static const size_t num_common_sample_rates = 11;

	// Initialise pulse audio
	if (!stack_init_alsa_audio())
	{
		// Failed to initialise, return NULL
		*outputs = NULL;
		return 0;	
	}

	// Get some hints	
	void **hints = NULL;
	int result = snd_device_name_hint(-1, "pcm", &hints);
	if (result != 0)
	{
		*outputs = NULL;
		return 0;
	}

	size_t alsa_device_count = 0, stack_device_count = 0;

	// Count how many devices we find
	for (size_t i = 0; hints[i] != NULL; i++)
	{
		alsa_device_count = i + 1;
	}

	// If there are no devices, return immediately
	if (alsa_device_count == 0)
	{
		snd_device_name_free_hint(hints);
		*outputs = NULL;
		return 0;
	}

	StackAudioDeviceDesc* devices = new StackAudioDeviceDesc[alsa_device_count];

	// Iterate over the devices and build information
	for (size_t alsa_device_idx = 0, stack_device_idx = 0; alsa_device_idx < alsa_device_count; alsa_device_idx++)
	{
		char *name = snd_device_name_get_hint(hints[alsa_device_idx], "NAME");
		char *desc = snd_device_name_get_hint(hints[alsa_device_idx], "DESC");

		// Open the device
		snd_pcm_t* pcm = NULL;
		if (snd_pcm_open(&pcm, name, SND_PCM_STREAM_PLAYBACK, 0) != 0)
		{
			free(name);
			free(desc);
			continue;
		}

		// Get parameters
		snd_pcm_hw_params_t* hw_params = NULL;
		snd_pcm_hw_params_malloc(&hw_params);
		snd_pcm_hw_params_any(pcm, hw_params);

		// Get minimum and maximum number of channels
		unsigned int min, max;
		snd_pcm_hw_params_get_channels_min(hw_params, &min);
		snd_pcm_hw_params_get_channels_max(hw_params, &max);

		// Limit the maximum to 32 channels, as some devices return "-1" channels
		if (max > 32)
		{
			max = 32;
		}

		// Store channel counts
		devices[stack_device_idx].min_channels = min;
		devices[stack_device_idx].max_channels = max;

		// Get minimum and maximum sample rates
		int dir;
		snd_pcm_hw_params_get_rate_min(hw_params, &min, &dir);
		snd_pcm_hw_params_get_rate_max(hw_params, &max, &dir);

		// Iterate over our common sample rates and see which ones are valid
		size_t sample_rate_count = 0;
		for (size_t common_rate_idx = 0; common_rate_idx < num_common_sample_rates; common_rate_idx++)
		{
			if (common_sample_rates[common_rate_idx] >= min && common_sample_rates[common_rate_idx] <= max)
			{
				if (snd_pcm_hw_params_test_rate(pcm, hw_params, common_sample_rates[common_rate_idx], 0) == 0)
				{
					sample_rate_count++;
				}
			}
		}

		// Store the sample rates
		devices[stack_device_idx].num_rates = sample_rate_count;
		if (sample_rate_count > 0)
		{
			devices[stack_device_idx].rates = new uint32_t[sample_rate_count];
			for (size_t rate_idx = 0, common_rate_idx = 0; common_rate_idx < num_common_sample_rates; common_rate_idx++)
			{
				if (common_sample_rates[common_rate_idx] >= min && common_sample_rates[common_rate_idx] <= max)
				{
					devices[stack_device_idx].rates[rate_idx] = common_sample_rates[common_rate_idx];
					rate_idx++;
				}
			}

		}
		else
		{
			devices[stack_device_idx].rates = NULL;
		}

		// Store the name and description
		devices[stack_device_idx].name = strdup(name);
		devices[stack_device_idx].desc = strdup(desc);

		// Tidy up
		free(name);
		free(desc);
		snd_pcm_hw_params_free(hw_params);
		snd_pcm_close(pcm);
		stack_device_count++;
		stack_device_idx++;
	}

	// Tidy up
	snd_device_name_free_hint(hints);

	// We can technically return an array that contains more elements than
	// we say (if a device fails to open, for example), but this is not a 
	// problem, as we only allocate and indeed free the internals of the
	// number we say, but we tidy up the whole array
	*outputs = devices;
	return stack_device_count;
}
示例#23
0
void CAESinkALSA::EnumerateDevicesEx(AEDeviceInfoList &list, bool force)
{
  /* ensure that ALSA has been initialized */
  snd_lib_error_set_handler(sndLibErrorHandler);
  if(!snd_config || force)
  {
    if(force)
      snd_config_update_free_global();

    snd_config_update();
  }

  snd_config_t *config;
  snd_config_copy(&config, snd_config);

  /* Always enumerate the default device.
   * Note: If "default" is a stereo device, EnumerateDevice()
   * will automatically add "@" instead to enable surroundXX mangling.
   * We don't want to do that if "default" can handle multichannel
   * itself (e.g. in case of a pulseaudio server). */
  EnumerateDevice(list, "default", "", config);

  void **hints;

  if (snd_device_name_hint(-1, "pcm", &hints) < 0)
  {
    CLog::Log(LOGINFO, "CAESinkALSA - Unable to get a list of devices");
    return;
  }

  std::string defaultDescription;

  for (void** hint = hints; *hint != NULL; ++hint)
  {
    char *io = snd_device_name_get_hint(*hint, "IOID");
    char *name = snd_device_name_get_hint(*hint, "NAME");
    char *desc = snd_device_name_get_hint(*hint, "DESC");
    if ((!io || strcmp(io, "Output") == 0) && name
        && strcmp(name, "null") != 0)
    {
      std::string baseName = std::string(name);
      baseName = baseName.substr(0, baseName.find(':'));

      if (strcmp(name, "default") == 0)
      {
        /* added already, but lets get the description if we have one */
        if (desc)
          defaultDescription = desc;
      }
      else if (baseName == "front")
      {
        /* Enumerate using the surroundXX mangling */
        /* do not enumerate basic "front", it is already handled
         * by the default "@" entry added in the very beginning */
        if (strcmp(name, "front") != 0)
          EnumerateDevice(list, std::string("@") + (name+5), desc ? desc : name, config);
      }

      /* Do not enumerate "default", it is already enumerated above. */

      /* Do not enumerate the sysdefault or surroundXX devices, those are
       * always accompanied with a "front" device and it is handled above
       * as "@". The below devices will be automatically used if available
       * for a "@" device. */

      /* Ubuntu has patched their alsa-lib so that "defaults.namehint.extended"
       * defaults to "on" instead of upstream "off", causing lots of unwanted
       * extra devices (many of which are not actually routed properly) to be
       * found by the enumeration process. Skip them as well ("hw", "dmix",
       * "plughw", "dsnoop"). */

      else if (baseName != "default"
            && baseName != "sysdefault"
            && baseName != "surround40"
            && baseName != "surround41"
            && baseName != "surround50"
            && baseName != "surround51"
            && baseName != "surround71"
            && baseName != "hw"
            && baseName != "dmix"
            && baseName != "plughw"
            && baseName != "dsnoop")
      {
        EnumerateDevice(list, name, desc ? desc : name, config);
      }
    }
    free(io);
    free(name);
    free(desc);
  }
  snd_device_name_free_hint(hints);

  /* set the displayname for default device */
  if (!list.empty() && list[0].m_deviceName == "default")
  {
    /* If we have one from a hint (DESC), use it */
    if (!defaultDescription.empty())
      list[0].m_displayName = defaultDescription;
    /* Otherwise use the discovered name or (unlikely) "Default" */
    else if (list[0].m_displayName.empty())
      list[0].m_displayName = "Default";
  }

  /* lets check uniqueness, we may need to append DEV or CARD to DisplayName */
  /* If even a single device of card/dev X clashes with Y, add suffixes to
   * all devices of both them, for clarity. */

  /* clashing card names, e.g. "NVidia", "NVidia_2" */
  std::set<std::string> cardsToAppend;

  /* clashing basename + cardname combinations, e.g. ("hdmi","Nvidia") */
  std::set<std::pair<std::string, std::string> > devsToAppend;

  for (AEDeviceInfoList::iterator it1 = list.begin(); it1 != list.end(); ++it1)
  {
    for (AEDeviceInfoList::iterator it2 = it1+1; it2 != list.end(); ++it2)
    {
      if (it1->m_displayName == it2->m_displayName
       && it1->m_displayNameExtra == it2->m_displayNameExtra)
      {
        /* something needs to be done */
        std::string cardString1 = GetParamFromName(it1->m_deviceName, "CARD");
        std::string cardString2 = GetParamFromName(it2->m_deviceName, "CARD");

        if (cardString1 != cardString2)
        {
          /* card name differs, add identifiers to all devices */
          cardsToAppend.insert(cardString1);
          cardsToAppend.insert(cardString2);
          continue;
        }

        std::string devString1 = GetParamFromName(it1->m_deviceName, "DEV");
        std::string devString2 = GetParamFromName(it2->m_deviceName, "DEV");

        if (devString1 != devString2)
        {
          /* device number differs, add identifiers to all such devices */
          devsToAppend.insert(std::make_pair(it1->m_deviceName.substr(0, it1->m_deviceName.find(':')), cardString1));
          devsToAppend.insert(std::make_pair(it2->m_deviceName.substr(0, it2->m_deviceName.find(':')), cardString2));
          continue;
        }

        /* if we got here, the configuration is really weird, just append the whole device string */
        it1->m_displayName += " (" + it1->m_deviceName + ")";
        it2->m_displayName += " (" + it2->m_deviceName + ")";
      }
    }
  }

  for (std::set<std::string>::iterator it = cardsToAppend.begin();
       it != cardsToAppend.end(); ++it)
  {
    for (AEDeviceInfoList::iterator itl = list.begin(); itl != list.end(); ++itl)
    {
      std::string cardString = GetParamFromName(itl->m_deviceName, "CARD");
      if (cardString == *it)
        /* "HDA NVidia (NVidia)", "HDA NVidia (NVidia_2)", ... */
        itl->m_displayName += " (" + cardString + ")";
    }
  }

  for (std::set<std::pair<std::string, std::string> >::iterator it = devsToAppend.begin();
       it != devsToAppend.end(); ++it)
  {
    for (AEDeviceInfoList::iterator itl = list.begin(); itl != list.end(); ++itl)
    {
      std::string baseName = itl->m_deviceName.substr(0, itl->m_deviceName.find(':'));
      std::string cardString = GetParamFromName(itl->m_deviceName, "CARD");
      if (baseName == it->first && cardString == it->second)
      {
        std::string devString = GetParamFromName(itl->m_deviceName, "DEV");
        /* "HDMI #0", "HDMI #1" ... */
        itl->m_displayNameExtra += " #" + devString;
      }
    }
  }
}
示例#24
0
/* API: refresh the device list */
static pj_status_t alsa_factory_refresh(pjmedia_aud_dev_factory *f)
{
    struct alsa_factory *af = (struct alsa_factory*)f;
    char **hints, **n;
    int err;

    TRACE_((THIS_FILE, "pjmedia_snd_init: Enumerate sound devices"));

    if (af->pool != NULL) {
	pj_pool_release(af->pool);
	af->pool = NULL;
    }

    af->pool = pj_pool_create(af->pf, "alsa_aud", 256, 256, NULL);
    af->dev_cnt = 0;

    /* Enumerate sound devices */
    err = snd_device_name_hint(-1, "pcm", (void***)&hints);
    if (err != 0)
	return PJMEDIA_EAUD_SYSERR;

    /* Set a null error handler prior to enumeration to suppress errors */
    snd_lib_error_set_handler(null_alsa_error_handler);

    n = hints;
    while (*n != NULL) {
	char *name = snd_device_name_get_hint(*n, "NAME");
	char *desc = snd_device_name_get_hint(*n, "DESC");
	if (name != NULL) {
	    if (strncmp("null", name, 4) == 0 ||
                strncmp("front", name, 5) == 0 ||
                strncmp("rear", name, 4) == 0 ||
                strncmp("side", name, 4) == 0 ||
                strncmp("dmix", name, 4) == 0 ||
                strncmp("dsnoop", name, 6) == 0 ||
                strncmp("hw", name, 2) == 0 ||
                strncmp("plughw", name, 6) == 0 ||
                strncmp("center_lfe", name, 10) == 0 ||
	        strncmp("surround40", name, 10) == 0 ||
	        strncmp("surround41", name, 10) == 0 ||
	        strncmp("surround50", name, 10) == 0 ||
	        strncmp("surround51", name, 10) == 0 ||
	        strncmp("surround71", name, 10) == 0 ||
	        (strncmp("default", name, 7) == 0 && strstr(name, ":CARD=") != NULL)) {
	        /* skip these devices, 'sysdefault' always contains the relevant information */
	        ;
	    } else {
	        add_dev(af, name, desc);
	    }
	    free(name);
	    free(desc);
	}
	n++;
    }

    /* Install error handler after enumeration, otherwise we'll get many
     * error messages about invalid card/device ID.
     */
    snd_lib_error_set_handler(alsa_error_handler);

    err = snd_device_name_free_hint((void**)hints);

    PJ_LOG(4,(THIS_FILE, "ALSA driver found %d devices", af->dev_cnt));

    return PJ_SUCCESS;
}
示例#25
0
void AlsaBackend::UpdateDevicesList()
{
    Log("AlsaBackend::UpdateDeviceList\n");

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

    InitDevicesList();

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

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

    snd_config_update();

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

    n = hints;

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

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

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

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

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

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

        n++;
    }
    snd_device_name_free_hint(hints);

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

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

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

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

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

        err = snd_ctl_card_info(handle, cardinfo);

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

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

        dev = -1;

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

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

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

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

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

            devicesList.push_back(info);

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

        snd_ctl_close(handle);
    }

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

    snd_config_t *topNode = NULL;
    assert(snd_config);

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

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

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

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

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

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

            devicesList.push_back(info);
        }
    }