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); } }
static int alsa_setup(struct snd_format* f) { int err; snd_pcm_hw_params_t* hwparams; snd_pcm_sw_params_t* swparams; unsigned int alsa_buffer_time, alsa_period_time; snd_pcm_uframes_t alsa_buffer_size, alsa_period_size; free(outputf); outputf = snd_format_alloc(f->rate, f->channels); printf(" Opening device %s ... ", alsa_cb.pcm_device); if((err = snd_pcm_open(&alsa_pcm, alsa_cb.pcm_device, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK)) < 0) { printf("alsa_setup(): Failed to open pcm device (%s): %s\n", alsa_cb.pcm_device, snd_strerror(-err)); alsa_pcm = NULL; free(outputf); outputf = NULL; return -1; } /* doesn't care about non-blocking */ /* snd_pcm_nonblock(alsa_pcm, 0); */ if(0) { //debug snd_pcm_info_t* info; int alsa_card, alsa_device, alsa_subdevice; snd_pcm_info_alloca(&info); snd_pcm_info(alsa_pcm, info); alsa_card = snd_pcm_info_get_card(info); alsa_device = snd_pcm_info_get_device(info); alsa_subdevice = snd_pcm_info_get_subdevice(info); printf("Card %i, Device %i, Subdevice %i\n", alsa_card, alsa_device, alsa_subdevice); } snd_pcm_hw_params_alloca(&hwparams); if((err = snd_pcm_hw_params_any(alsa_pcm, hwparams)) < 0) { printf("alsa_setup(): No configuration available for " "playback: %s\n", snd_strerror(-err)); return -1; } if((err = snd_pcm_hw_params_set_access(alsa_pcm, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) { printf("alsa_setup(): Cannot set direct write mode: %s\n", snd_strerror(-err)); return -1; } if((err = snd_pcm_hw_params_set_format(alsa_pcm, hwparams, outputf->format)) < 0) { printf("alsa_setup(): Sample format not " "available for playback: %s\n", snd_strerror(-err)); return -1; } if((err = snd_pcm_hw_params_set_channels_near(alsa_pcm, hwparams, &outputf->channels)) < 0) { printf ("alsa_setup(): snd_pcm_hw_params_set_channels_near failed: %s.\n", snd_strerror(-err)); return -1; } snd_pcm_hw_params_set_rate_near(alsa_pcm, hwparams, &outputf->rate, 0); if(outputf->rate == 0) { printf("alsa_setup(): No usable samplerate available.\n"); return -1; } outputf->sample_bits = snd_pcm_format_physical_width(outputf->format); outputf->bps = (outputf->rate * outputf->sample_bits * outputf->channels) >> 3; alsa_buffer_time = alsa_cb.buffer_time * 1000; if((err = snd_pcm_hw_params_set_buffer_time_near(alsa_pcm, hwparams, &alsa_buffer_time, 0)) < 0) { printf("alsa_setup(): Set buffer time failed: %s.\n", snd_strerror(-err)); return -1; } alsa_period_time = alsa_cb.period_time * 1000; if((err = snd_pcm_hw_params_set_period_time_near(alsa_pcm, hwparams, &alsa_period_time, 0)) < 0) { printf("alsa_setup(): Set period time failed: %s.\n", snd_strerror(-err)); return -1; } if(snd_pcm_hw_params(alsa_pcm, hwparams) < 0) { printf("alsa_setup(): Unable to install hw params\n"); return -1; } if((err = snd_pcm_hw_params_get_buffer_size(hwparams, &alsa_buffer_size)) < 0) { printf("alsa_setup(): snd_pcm_hw_params_get_buffer_size() " "failed: %s\n", snd_strerror(-err)); return -1; } if((err = snd_pcm_hw_params_get_period_size(hwparams, &alsa_period_size, 0)) < 0) { printf("alsa_setup(): snd_pcm_hw_params_get_period_size() " "failed: %s\n", snd_strerror(-err)); return -1; } snd_pcm_sw_params_alloca(&swparams); snd_pcm_sw_params_current(alsa_pcm, swparams); if((err = snd_pcm_sw_params_set_start_threshold(alsa_pcm, swparams, alsa_buffer_size - alsa_period_size) < 0)) printf("alsa_setup(): setting start " "threshold failed: %s\n", snd_strerror(-err)); if(snd_pcm_sw_params(alsa_pcm, swparams) < 0) { printf("alsa_setup(): Unable to install sw params\n"); return -1; } hw_buffer_size = snd_pcm_frames_to_bytes(alsa_pcm, alsa_buffer_size); hw_period_size = snd_pcm_frames_to_bytes(alsa_pcm, alsa_period_size); if(inputf->bps != outputf->bps) { int align = (inputf->sample_bits * inputf->channels) / 8; hw_buffer_size_in = ((u_int) hw_buffer_size * inputf->bps + outputf->bps / 2) / outputf->bps; hw_period_size_in = ((u_int) hw_period_size * inputf->bps + outputf->bps / 2) / outputf->bps; hw_buffer_size_in -= hw_buffer_size_in % align; hw_period_size_in -= hw_period_size_in % align; } else { hw_buffer_size_in = hw_buffer_size; hw_period_size_in = hw_period_size; } #if 0 printf("Device setup: buffer time: %i, size: %i.\n", alsa_buffer_time, hw_buffer_size); printf("Device setup: period time: %i, size: %i.\n", alsa_period_time, hw_period_size); printf("bits per sample: %i; frame size: %i; Bps: %i\n", snd_pcm_format_physical_width(outputf->format), snd_pcm_frames_to_bytes(alsa_pcm, 1), outputf->bps); #endif printf("success.\n"); return 0; }