int main(int argc, char *argv[]) { writei_func = snd_pcm_writei; int err; char *pcm_name = "default"; snd_pcm_info_t *info; snd_pcm_info_alloca(&info); stream = SND_PCM_STREAM_PLAYBACK; err = snd_pcm_open(&handle, pcm_name, stream, open_mode); if (err < 0) { // error(_("audio open error: %s"), snd_strerror(err)); return 1; } if ((err = snd_pcm_info(handle, info)) < 0) { // error(_("info error: %s"), snd_strerror(err)); return 1; } snd_pcm_nonblock(handle, 0); printf("set_params!!\n"); // set_params(); //playbackv(&argv[1], argc0); printf("playback!!\n"); playback(argv[1]); return 0; }
int do_play(char* file_name) { char *pcm_name = "default"; int tmp, err, c; snd_pcm_info_t *info; snd_pcm_info_alloca(&info); err = snd_output_stdio_attach(&log, stderr, 0); assert(err >= 0); stream = SND_PCM_STREAM_PLAYBACK; chunk_size = -1; rhwparams.format = DEFAULT_FORMAT; rhwparams.rate = DEFAULT_SPEED; rhwparams.channels = 1; err = snd_pcm_open(&handle, pcm_name, stream, open_mode); if (err < 0) { error(_("audio open error: %s"), snd_strerror(err)); return 1; } if ((err = snd_pcm_info(handle, info)) < 0) { error(_("info error: %s"), snd_strerror(err)); return 1; } if (nonblock) { err = snd_pcm_nonblock(handle, 1); if (err < 0) { error(_("nonblock setting error: %s"), snd_strerror(err)); return 1; } } chunk_size = 1024; hwparams = rhwparams; audiobuf = (u_char *)malloc(1024); if (audiobuf == NULL) { error(_("not enough memory")); return 1; } signal(SIGINT, signal_handler); signal(SIGTERM, signal_handler); signal(SIGABRT, signal_handler); playback(file_name); snd_pcm_close(handle); free(audiobuf); snd_output_close(log); snd_config_update_free_global(); return EXIT_SUCCESS; }
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. }
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; }
static void DumpDevice (vlc_object_t *obj, snd_pcm_t *pcm) { snd_pcm_info_t *info; Dump (obj, " ", snd_pcm_dump, pcm); snd_pcm_info_alloca (&info); if (snd_pcm_info (pcm, info) == 0) { msg_Dbg (obj, " device name : %s", snd_pcm_info_get_name (info)); msg_Dbg (obj, " device ID : %s", snd_pcm_info_get_id (info)); msg_Dbg (obj, " subdevice name: %s", snd_pcm_info_get_subdevice_name (info)); } }
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 int aplaypop_open(void) { int err; snd_pcm_t *handle; if (pcm_handle) return 0; snd_pcm_info_t *info; snd_pcm_info_alloca(&info); snd_output_t *log; err = snd_output_stdio_attach(&log, stderr, 0); assert(err == 0); err = snd_pcm_open(&handle, device, SND_PCM_STREAM_PLAYBACK, 0); if (err != 0) { fprintf(stderr, "snd_pcm_open(): %s\n", snd_strerror(err)); exit(EXIT_FAILURE); } err = snd_pcm_nonblock(handle, 0); if (err != 0) { fprintf(stderr, "snd_pcm_nonblock(): %s\n", snd_strerror(err)); exit(EXIT_FAILURE); } err = snd_pcm_info(handle, info); if (err != 0) { fprintf(stderr, "snd_pcm_info(): %s\n", snd_strerror(err)); exit(EXIT_FAILURE); } // DOESN'T WORK! err = snd_pcm_set_params(handle, SND_PCM_FORMAT_S16_LE, SND_PCM_ACCESS_RW_INTERLEAVED, CHANNELS, RATE, 1, 50000); if (err != 0) { fprintf(stderr, "snd_pcm_set_params(): %s\n", snd_strerror(err)); exit(EXIT_FAILURE); } // RIGHT WAY: snd_pcm_hw_params_t *hwparams; snd_pcm_sw_params_t *swparams; snd_pcm_format_t format = SND_PCM_FORMAT_S16_LE; unsigned int channels = CHANNELS; unsigned int rate = RATE; snd_pcm_hw_params_alloca(&hwparams); snd_pcm_sw_params_alloca(&swparams); err = snd_pcm_hw_params_any(handle, hwparams); if (err != 0) { fprintf(stderr, "Broken configuration for this PCM: %s\n", snd_strerror(err)); exit(EXIT_FAILURE); } err = snd_pcm_hw_params_set_access(handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED); if (err != 0) { fprintf(stderr, "snd_pcm_hw_params_set_access(): %s\n", snd_strerror(err)); exit(EXIT_FAILURE); } err = snd_pcm_hw_params_set_format(handle, hwparams, format); if (err != 0) { fprintf(stderr, "snd_pcm_hw_params_set_format(): %s\n", snd_strerror(err)); exit(EXIT_FAILURE); } err = snd_pcm_hw_params_set_channels(handle, hwparams, channels); if (err != 0) { fprintf(stderr, "snd_pcm_hw_params_set_channels(): %s\n", snd_strerror(err)); exit(EXIT_FAILURE); } err = snd_pcm_hw_params_set_rate_near(handle, hwparams, &rate, 0); if (err != 0) { fprintf(stderr, "snd_pcm_hw_params_set_rate_near(): %s\n", snd_strerror(err)); exit(EXIT_FAILURE); } /* unsigned buffer_time = 0; snd_pcm_uframes_t buffer_frames = 0; if (buffer_time == 0 && buffer_frames == 0) { err = snd_pcm_hw_params_get_buffer_time_max(hwparams, &buffer_time, 0); assert(err == 0); if (buffer_time > 500000) buffer_time = 500000; } unsigned period_time = 0; snd_pcm_uframes_t period_frames = 0; if (period_time == 0 && period_frames == 0) { if (buffer_time > 0) period_time = buffer_time / 4; else period_frames = buffer_frames / 4; } if (period_time > 0) err = snd_pcm_hw_params_set_period_time_near(handle, hwparams, &period_time, 0); else err = snd_pcm_hw_params_set_period_size_near(handle, hwparams, &period_frames, 0); assert(err == 0); if (buffer_time > 0) err = snd_pcm_hw_params_set_buffer_time_near(handle, hwparams, &buffer_time, 0); else err = snd_pcm_hw_params_set_buffer_size_near(handle, hwparams, &buffer_frames); assert(err == 0); int monotonic = snd_pcm_hw_params_is_monotonic(hwparams); int can_pause = snd_pcm_hw_params_can_pause(hwparams); */ err = snd_pcm_hw_params(handle, hwparams); if (err != 0) { fprintf(stderr, "snd_pcm_hw_params(): %s\n", snd_strerror(err)); snd_pcm_hw_params_dump(hwparams, log); exit(EXIT_FAILURE); } snd_pcm_uframes_t chunk_size = 0; snd_pcm_hw_params_get_period_size(hwparams, &chunk_size, 0); snd_pcm_uframes_t buffer_size; snd_pcm_hw_params_get_buffer_size(hwparams, &buffer_size); if (chunk_size == buffer_size) { fprintf(stderr, "Can't use period equal to buffer size (%lu == %lu)", chunk_size, buffer_size); exit(EXIT_FAILURE); } snd_pcm_sw_params_current(handle, swparams); err = snd_pcm_sw_params_set_avail_min(handle, swparams, chunk_size); assert(err == 0); /* round up to closest transfer boundary */ int start_delay = 0; snd_pcm_uframes_t start_threshold; if (start_delay <= 0) start_threshold = buffer_size + (double) rate * start_delay / 1000000; else start_threshold = (double) rate * start_delay / 1000000; start_threshold = start_threshold < 1 ? 1 : start_threshold > buffer_size ? buffer_size : start_threshold; err = snd_pcm_sw_params_set_start_threshold(handle, swparams, start_threshold); assert(err == 0); int stop_delay = 0; snd_pcm_uframes_t stop_threshold; if (stop_delay <= 0) stop_threshold = buffer_size + (double) rate * stop_delay / 1000000; else stop_threshold = (double) rate * stop_delay / 1000000; err = snd_pcm_sw_params_set_stop_threshold(handle, swparams, stop_threshold); assert(err == 0); err = snd_pcm_sw_params(handle, swparams); if (err != 0) { fprintf(stderr, "snd_pcm_sw_params(): %s\n", snd_strerror(err)); snd_pcm_sw_params_dump(swparams, log); exit(EXIT_FAILURE); } // END OF THE RIGHT WAY // snd_pcm_dump(handle, log); size_t bits_per_sample = snd_pcm_format_physical_width(format); size_t bits_per_frame = bits_per_sample * channels; size_t chunk_bytes = chunk_size * bits_per_frame / 8; //audiobuf = realloc(audiobuf, chunk_bytes); fprintf(stderr, "%s: %s, Rate %d Hz, Channels=%u\n", snd_pcm_format_name(format), snd_pcm_format_description(format), rate, channels); fprintf(stderr, " bits_per_sample=%u, bits_per_frame=%u, chunk_bytes=%u\n", bits_per_sample, bits_per_frame, chunk_bytes); frame_bytes = bits_per_frame / 8; pcm_handle = handle; return 0; }
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; }
int run(char *filename) { capture_stop = 0; char *pcm_name = "default"; int tmp, err; snd_pcm_info_t *info; snd_pcm_info_alloca(&info); err = snd_output_stdio_attach(&log, stderr, 0); assert(err >= 0); file_type = FORMAT_DEFAULT; stream = SND_PCM_STREAM_CAPTURE; file_type = FORMAT_WAVE; command = "arecord"; start_delay = 1; chunk_size = -1; rhwparams.format = DEFAULT_FORMAT; rhwparams.rate = DEFAULT_SPEED; rhwparams.channels = 1; file_type = FORMAT_WAVE; // cdr: // rhwparams.format = SND_PCM_FORMAT_S16_BE; rhwparams.format = file_type == FORMAT_AU ? SND_PCM_FORMAT_S16_BE : SND_PCM_FORMAT_S16_LE; rhwparams.rate = 44100; rhwparams.channels = 2; err = snd_pcm_open(&handle, pcm_name, stream, open_mode); if (err < 0) { error(_("audio open error: %s"), snd_strerror(err)); return 1; } if ((err = snd_pcm_info(handle, info)) < 0) { error(_("info error: %s"), snd_strerror(err)); return 1; } if (nonblock) { err = snd_pcm_nonblock(handle, 1); if (err < 0) { error(_("nonblock setting error: %s"), snd_strerror(err)); return 1; } } chunk_size = 1024; hwparams = rhwparams; audiobuf = (u_char *)malloc(1024); if (audiobuf == NULL) { error(_("not enough memory")); return 1; } writei_func = snd_pcm_writei; readi_func = snd_pcm_readi; writen_func = snd_pcm_writen; readn_func = snd_pcm_readn; //signal(SIGINT, signal_handler); //signal(SIGTERM, signal_handler); //signal(SIGABRT, signal_handler); capture(filename); if (fmt_rec_table[file_type].end) { fmt_rec_table[file_type].end(fd); fd = -1; } stream = -1; if (fd > 1) { close(fd); fd = -1; } if (handle) { snd_pcm_close(handle); handle = NULL; } //snd_pcm_close(handle); //free(audiobuf); //snd_output_close(log); //snd_config_update_free_global(); return EXIT_SUCCESS; }
static int findSoundCards(char **cardname) { int idx, dev, err; snd_ctl_t *handle; snd_hctl_t *hctlhandle; snd_ctl_card_info_t *cardinfo; snd_pcm_info_t *pcminfo; char str[32]; snd_ctl_card_info_alloca(&cardinfo); snd_pcm_info_alloca(&pcminfo); snd_hctl_elem_t *elem; snd_ctl_elem_id_t *id; snd_ctl_elem_info_t *info; snd_ctl_elem_id_alloca(&id); snd_ctl_elem_info_alloca(&info); idx = -1; while (1) { if ((err = snd_card_next(&idx)) < 0) { LOGE("Card next error: %s\n", snd_strerror(err)); break; } if (idx < 0) break; sprintf(str, "hw:CARD=%i", idx); if ((err = snd_ctl_open(&handle, str, 0)) < 0) { LOGE("Open error: %s\n", snd_strerror(err)); continue; } if ((err = snd_ctl_card_info(handle, cardinfo)) < 0) { LOGE("HW info error: %s\n", snd_strerror(err)); continue; } LOGD("Soundcard #%i:\n", idx + 1); LOGD(" card - %i\n", snd_ctl_card_info_get_card(cardinfo)); LOGD(" id - '%s'\n", snd_ctl_card_info_get_id(cardinfo)); LOGD(" driver - '%s'\n", snd_ctl_card_info_get_driver(cardinfo)); LOGD(" name - '%s'\n", snd_ctl_card_info_get_name(cardinfo)); LOGD(" longname - '%s'\n", snd_ctl_card_info_get_longname(cardinfo)); LOGD(" mixername - '%s'\n", snd_ctl_card_info_get_mixername(cardinfo)); LOGD(" components - '%s'\n", snd_ctl_card_info_get_components(cardinfo)); strcpy(cardname[idx], snd_ctl_card_info_get_name(cardinfo)); LOGD("\n\n-----get cart name and id: %s : %d",cardname[idx],idx); snd_ctl_close(handle); if ((err = snd_hctl_open(&hctlhandle, str, 0)) < 0) { LOGE("Control %s open error: %s", str, snd_strerror(err)); return err; } if ((err = snd_hctl_load(hctlhandle)) < 0) { LOGE("Control %s local error: %s\n", str, snd_strerror(err)); return err; } for (elem = snd_hctl_first_elem(hctlhandle); elem; elem = snd_hctl_elem_next(elem)) { if ((err = snd_hctl_elem_info(elem, info)) < 0) { LOGE("Control %s snd_hctl_elem_info error: %s\n", str, snd_strerror(err)); return err; } snd_hctl_elem_get_id(elem, id); show_control_id(id); } snd_hctl_close(hctlhandle); } snd_config_update_free_global(); return 0; }
/*----------------------------------------------------------------------- Initialise ALSA and sets the sampling rate and audio format. --------------------------------------------------------------------------*/ snd_pcm_t* alsa_init() { char *pcm_name = "default"; int tmp, err, c; int do_device_list = 0, do_pcm_list = 0; snd_pcm_info_t *info; snd_pcm_info_alloca(&info); err = snd_output_stdio_attach(&log, stderr, 0); assert(err >= 0); stream = SND_PCM_STREAM_PLAYBACK; rhwparams.format = DEFAULT_FORMAT; rhwparams.rate = DEFAULT_SPEED; rhwparams.channels = 1; file_type = FORMAT_RAW; rhwparams.format = SND_PCM_FORMAT_S16_LE; rhwparams.rate = 16000; rhwparams.channels = 1; err = snd_pcm_open(&handle, pcm_name, stream, open_mode); if (err < 0) { error("audio open error: %s", snd_strerror(err)); return 1; } if ((err = snd_pcm_info(handle, info)) < 0) { error("info error: %s", snd_strerror(err)); return 1; } if (nonblock) { err = snd_pcm_nonblock(handle, 1); if (err < 0) { error("nonblock setting error: %s", snd_strerror(err)); return 1; } } chunk_size = 1024; hwparams = rhwparams; audiobuf = (u_char *)malloc(1024); if (audiobuf == NULL) { error("not enough memory"); return 1; } if (mmap_flag) { writei_func = snd_pcm_mmap_writei; readi_func = snd_pcm_mmap_readi; writen_func = snd_pcm_mmap_writen; readn_func = snd_pcm_mmap_readn; } else { writei_func = snd_pcm_writei; readi_func = snd_pcm_readi; writen_func = snd_pcm_writen; readn_func = snd_pcm_readn; } signal(SIGINT, signal_handler); signal(SIGTERM, signal_handler); signal(SIGABRT, signal_handler); return handle; }
void CAESinkALSA::EnumerateDevice(AEDeviceInfoList &list, const std::string &device, const std::string &description, snd_config_t *config) { snd_pcm_t *pcmhandle = NULL; if (!OpenPCMDevice(device, "", ALSA_MAX_CHANNELS, &pcmhandle, config)) return; snd_pcm_info_t *pcminfo; snd_pcm_info_alloca(&pcminfo); memset(pcminfo, 0, snd_pcm_info_sizeof()); int err = snd_pcm_info(pcmhandle, pcminfo); if (err < 0) { CLog::Log(LOGINFO, "CAESinkALSA - Unable to get pcm_info for \"%s\"", device.c_str()); snd_pcm_close(pcmhandle); } int cardNr = snd_pcm_info_get_card(pcminfo); CAEDeviceInfo info; info.m_deviceName = device; info.m_deviceType = AEDeviceTypeFromName(device); if (cardNr >= 0) { /* "HDA NVidia", "HDA Intel", "HDA ATI HDMI", "SB Live! 24-bit External", ... */ char *cardName; if (snd_card_get_name(cardNr, &cardName) == 0) info.m_displayName = cardName; if (info.m_deviceType == AE_DEVTYPE_HDMI && info.m_displayName.size() > 5 && info.m_displayName.substr(info.m_displayName.size()-5) == " HDMI") { /* We already know this is HDMI, strip it */ info.m_displayName.erase(info.m_displayName.size()-5); } /* "CONEXANT Analog", "USB Audio", "HDMI 0", "ALC889 Digital" ... */ std::string pcminfoName = snd_pcm_info_get_name(pcminfo); /* * Filter "USB Audio", in those cases snd_card_get_name() is more * meaningful already */ if (pcminfoName != "USB Audio") info.m_displayNameExtra = pcminfoName; if (info.m_deviceType == AE_DEVTYPE_HDMI) { /* replace, this was likely "HDMI 0" */ info.m_displayNameExtra = "HDMI"; int dev = snd_pcm_info_get_device(pcminfo); if (dev >= 0) { /* lets see if we can get ELD info */ snd_ctl_t *ctlhandle; std::stringstream sstr; sstr << "hw:" << cardNr; std::string strHwName = sstr.str(); if (snd_ctl_open_lconf(&ctlhandle, strHwName.c_str(), 0, config) == 0) { snd_hctl_t *hctl; if (snd_hctl_open_ctl(&hctl, ctlhandle) == 0) { snd_hctl_load(hctl); bool badHDMI = false; if (!GetELD(hctl, dev, info, badHDMI)) CLog::Log(LOGDEBUG, "CAESinkALSA - Unable to obtain ELD information for device \"%s\" (not supported by device, or kernel older than 3.2)", device.c_str()); /* snd_hctl_close also closes ctlhandle */ snd_hctl_close(hctl); if (badHDMI) { /* * Warn about disconnected devices, but keep them enabled * Detection can go wrong on Intel, Nvidia and on all * AMD (fglrx) hardware, so it is not safe to close those * handles */ CLog::Log(LOGDEBUG, "CAESinkALSA - HDMI device \"%s\" may be unconnected (no ELD data)", device.c_str()); } } else { snd_ctl_close(ctlhandle); } } } } else if (info.m_deviceType == AE_DEVTYPE_IEC958) { /* append instead of replace, pcminfoName is useful for S/PDIF */ if (!info.m_displayNameExtra.empty()) info.m_displayNameExtra += ' '; info.m_displayNameExtra += "S/PDIF"; } else if (info.m_displayNameExtra.empty()) { /* for USB audio, it gets a bit confusing as there is * - "SB Live! 24-bit External" * - "SB Live! 24-bit External, S/PDIF" * so add "Analog" qualifier to the first one */ info.m_displayNameExtra = "Analog"; } /* "default" is a device that will be used for all inputs, while * "@" will be mangled to front/default/surroundXX as necessary */ if (device == "@" || device == "default") { /* Make it "Default (whatever)" */ info.m_displayName = "Default (" + info.m_displayName + (info.m_displayNameExtra.empty() ? "" : " " + info.m_displayNameExtra + ")"); info.m_displayNameExtra = ""; } } else { /* virtual devices: "default", "pulse", ... */ /* description can be e.g. "PulseAudio Sound Server" - for hw devices it is * normally uninteresting, like "HDMI Audio Output" or "Default Audio Device", * so we only use it for virtual devices that have no better display name */ info.m_displayName = description; } snd_pcm_hw_params_t *hwparams; snd_pcm_hw_params_alloca(&hwparams); memset(hwparams, 0, snd_pcm_hw_params_sizeof()); /* ensure we can get a playback configuration for the device */ if (snd_pcm_hw_params_any(pcmhandle, hwparams) < 0) { CLog::Log(LOGINFO, "CAESinkALSA - No playback configurations available for device \"%s\"", device.c_str()); snd_pcm_close(pcmhandle); return; } /* 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 = ALSA_MAX_CHANNELS; i >= 1; --i) { /* Reopen the device if needed on the special "surroundXX" cases */ if (info.m_deviceType == AE_DEVTYPE_PCM && (i == 8 || i == 6 || i == 4)) OpenPCMDevice(device, "", i, &pcmhandle, config); if (snd_pcm_hw_params_test_channels(pcmhandle, hwparams, i) >= 0) { channels = i; break; } } if (device == "default" && channels == 2) { /* This looks like the ALSA standard default stereo dmix device, we * probably want to use "@" instead to get surroundXX. */ snd_pcm_close(pcmhandle); EnumerateDevice(list, "@", description, config); return; } 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); }
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; }
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); } }
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); }
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; }
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 ); }
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); }
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); } }
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; } } }
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); } }