#include <stdio.h>
#include <alsa/asoundlib.h>
void print_card_info(snd_ctl_card_info_t *info)
{
printf("Card #%d: id=%s, driver=%s, name=%s, longname=%s, mixername=%s, components=%s\n",
snd_ctl_card_info_get_card(info),
snd_ctl_card_info_get_id(info),
snd_ctl_card_info_get_driver(info),
snd_ctl_card_info_get_name(info),
snd_ctl_card_info_get_longname(info),
snd_ctl_card_info_get_mixername(info),
snd_ctl_card_info_get_components(info));
}
void print_elem_id(snd_ctl_elem_id_t *id)
{
printf("elem_id: numid=%d, interface=%s, device=%d, subdevice=%d, name=%s, index=%d\n",
snd_ctl_elem_id_get_numid(id),
snd_ctl_elem_iface_name(snd_ctl_elem_id_get_interface(id)),
snd_ctl_elem_id_get_device(id),
snd_ctl_elem_id_get_subdevice(id),
snd_ctl_elem_id_get_name(id),
snd_ctl_elem_id_get_index(id));
}
void print_elem_info(snd_ctl_elem_list_t *list, unsigned int i)
{
snd_ctl_elem_id_t *id;
printf("Element #%d: numid=%d, interface=%s, device=%d, subdevice=%d, name=%s, index=%d, elem_id follows:\n\t",
i,
snd_ctl_elem_list_get_numid(list, i),
snd_ctl_elem_iface_name(snd_ctl_elem_list_get_interface(list, i)),
snd_ctl_elem_list_get_device(list, i),
snd_ctl_elem_list_get_subdevice(list, i),
snd_ctl_elem_list_get_name(list, i),
snd_ctl_elem_list_get_index(list, i));
if (snd_ctl_elem_id_malloc(&id))
{
printf("Error allocating snd_ctl_elem_id_t, aborting\n");
return;
}
snd_ctl_elem_list_get_id(list, i, id);
print_elem_id(id);
snd_ctl_elem_id_free(id);
}
void print_power_state(unsigned int state)
{
char *str;
switch(state & SND_CTL_POWER_MASK) {
case SND_CTL_POWER_D0:
str = "D0";
break;
case SND_CTL_POWER_D1:
str = "D1";
break;
case SND_CTL_POWER_D2:
str = "D2";
break;
case SND_CTL_POWER_D3hot:
str = "D3 hot";
break;
case SND_CTL_POWER_D3cold:
str = "D3 cold";
break;
default:
str = "Unknown";
}
printf("Power state = %s\n", str);
}
void print_ctl_type(snd_ctl_type_t type)
{
char *str;
switch(type) {
case SND_CTL_TYPE_HW:
str = "Kernel level CTL";
break;
case SND_CTL_TYPE_SHM:
str = "Shared memory client CTL";
break;
case SND_CTL_TYPE_INET:
str = "INET client CTL";
break;
case SND_CTL_TYPE_EXT:
str = "External control plugin";
break;
default:
str = "Unknown";
}
printf("CTL type = %s\n", str);
}
void print_pcm_hw_params(snd_pcm_t *pcm)
{
snd_pcm_hw_params_t *params;
if (snd_pcm_hw_params_malloc(¶ms)) {
printf("Error allocating hw params, skipping\n");
return;
}
if (snd_pcm_hw_params_any(pcm, params)) {
printf("Error getting hw params, skipping\n");
snd_pcm_hw_params_free(params);
return;
}
snd_pcm_hw_params_free(params);
}
void print_pcm_devices(snd_ctl_t *handle)
{
int card;
int device = -1;
char deviceascii[25];
snd_ctl_card_info_t *card_info;
snd_pcm_t *pcm_playback, *pcm_capture;
int playback, capture;
if (snd_ctl_card_info_malloc(&card_info)) {
printf("Error allocating snd_ctl_card_info_t structure, aborting print_pcm_devices\n");
return;
}
if (snd_ctl_card_info(handle, card_info)) {
printf("Error getting card info, aborting print_pcm_devices\n");
snd_ctl_card_info_free(card_info);
return;
}
card = snd_ctl_card_info_get_card(card_info);
snd_ctl_card_info_free(card_info);
while (!snd_ctl_pcm_next_device(handle, &device) && device >= 0) {
printf("Found PCM device #%d\n", device);
snprintf(deviceascii, sizeof(deviceascii), "hw:%d,%d", card, device);
playback = capture = -1;
playback = snd_pcm_open(&pcm_playback, deviceascii, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
capture = snd_pcm_open(&pcm_capture, deviceascii, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK);
printf("Playback=%s, Capture=%s, Full Duplex=%s\n", playback ? "no" : "yes", capture ? "no" : "yes", (!playback && !capture) ? "yes" : "no");
printf("Playback capabilities:\n");
print_pcm_hw_params(pcm_playback);
printf("Capture capabilities:\n");
print_pcm_hw_params(pcm_capture);
if (!playback && snd_pcm_close(pcm_playback)) {
printf("Error closing PCM device #%d, LEAKING MEMORY\n", device);
}
if (!capture && snd_pcm_close(pcm_capture)) {
printf("Error closing PCM device #%d, LEAKING MEMORY\n", device);
}
}
}
int main(int argc, char **argv)
{
int card = -1;
char cardascii[14];
snd_ctl_t *handle;
snd_ctl_card_info_t *card_info;
snd_ctl_elem_list_t *elem_list;
unsigned int used, count, power_state;
while (snd_card_next(&card) >= 0 && card >= 0) {
snprintf(cardascii, sizeof(cardascii), "hw:%d", card);
if (snd_ctl_open(&handle, cardascii, 0)) {
printf("Error opening card #%d, skipping\n", card);
continue;
}
if (snd_ctl_card_info_malloc(&card_info)) {
printf("Error allocating snd_ctl_card_info_t structure, skipping\n");
snd_ctl_close(handle);
continue;
}
if (snd_ctl_card_info(handle, card_info)) {
printf("Error getting info for card #%d, skipping\n", card);
snd_ctl_close(handle);
snd_ctl_card_info_free(card_info);
continue;
}
print_card_info(card_info);
snd_ctl_card_info_free(card_info);
if (snd_ctl_elem_list_malloc(&elem_list)) {
printf("Error allocating snd_ctl_elem_list_t, skipping\n");
snd_ctl_close(handle);
continue;
}
if (snd_ctl_elem_list(handle, elem_list)) {
printf("Error getting element list, skipping\n");
snd_ctl_close(handle);
snd_ctl_elem_list_free(elem_list);
continue;
}
used = snd_ctl_elem_list_get_used(elem_list);
count = snd_ctl_elem_list_get_count(elem_list);
printf("Element used = %d, count = %d. Allocating space for %d entries...\n", used, count, count);
if (snd_ctl_elem_list_alloc_space(elem_list, count)) {
printf("Error allocating element list space, skipping\n");
snd_ctl_close(handle);
snd_ctl_elem_list_free(elem_list);
continue;
}
if (snd_ctl_elem_list(handle, elem_list)) {
printf("Error getting element list, skipping\n");
snd_ctl_close(handle);
snd_ctl_elem_list_free(elem_list);
snd_ctl_elem_list_free_space(elem_list);
continue;
}
used = snd_ctl_elem_list_get_used(elem_list);
count = snd_ctl_elem_list_get_count(elem_list);
printf("Element used = %d, count = %d\n", used, count);
for (unsigned int i = 0; i < used; i++) {
print_elem_info(elem_list, i);
}
snd_ctl_elem_list_free_space(elem_list);
snd_ctl_elem_list_free(elem_list);
if (snd_ctl_get_power_state(handle, &power_state)) {
printf("Error getting power state, skipping\n");
snd_ctl_close(handle);
continue;
}
print_power_state(power_state);
print_ctl_type(snd_ctl_type(handle));
print_pcm_devices(handle);
snd_ctl_close(handle);
}
printf("No more cards!\n");
return 0;
}