void asound_setup(const gchar * card, const gchar * channel, void (*volume_changed)(int,gboolean)) { // Make sure (for now) that the setup function only gets called once static int asound_setup_called = 0; assert(asound_setup_called == 0); asound_setup_called++; // Save card, volume_changed strcpy(m_card, card); m_volume_changed = volume_changed; // Load the mixer for the provided cardname snd_mixer_open(&m_mixer, 0); snd_mixer_attach(m_mixer, m_card); snd_mixer_selem_register(m_mixer, NULL, NULL); snd_mixer_load(m_mixer); // Setup g_io_watch for the mixer int count = snd_mixer_poll_descriptors_count(m_mixer); if(count >= 1) { struct pollfd pfd; count = snd_mixer_poll_descriptors(m_mixer, &pfd, 1); if(count == 1) { GIOChannel * giochannel = g_io_channel_unix_new(pfd.fd); g_io_add_watch_full(giochannel, G_PRIORITY_DEFAULT, G_IO_IN, asound_poll_cb, NULL, NULL); } } // Iterate over the elements in the mixer and store them in m_channel_names int elemcount = snd_mixer_get_count(m_mixer); snd_mixer_elem_t * elem = snd_mixer_first_elem(m_mixer); int loop; for(loop = 0; loop < elemcount; loop++) { const char * elemname = snd_mixer_selem_get_name(elem); if(snd_mixer_selem_has_playback_volume(elem)) { m_channel_names = g_list_append(m_channel_names, (gpointer)g_strdup(elemname)); } elem = snd_mixer_elem_next(elem); } // Setup m_elem using the provided channelname if(channel != NULL && asound_channel_exists(channel)) asound_set_channel(channel); else if(m_channel_names != NULL) asound_set_channel((const gchar*)m_channel_names->data); }
void asound_setup(const gchar * card, const gchar * channel, void (*volume_changed)(int,gboolean)) { gchar * card_override = NULL; // used to hold a string like hw:0 if a nice // device name was given as 'card' // Clean up resources from previous calls to setup g_free(m_channel); m_channel = NULL; if(m_elem) { snd_mixer_elem_set_callback(m_elem, NULL); m_elem = NULL; } if(m_mixer) { snd_mixer_close(m_mixer); m_mixer = NULL; } g_list_free_full(m_channel_names, g_free); m_channel_names = NULL; g_list_free_full(m_device_names, g_free); m_device_names = NULL; // Save card, volume_changed g_free(m_device); m_device = g_strdup(card); m_volume_changed = volume_changed; // Populate list of device names int card_number = -1; int ret = snd_card_next(&card_number); snd_ctl_card_info_t * info = NULL; snd_ctl_card_info_alloca(&info); m_device_names = g_list_append(m_device_names, (gpointer)g_strdup("default")); while(ret == 0 && card_number != -1) { char buf[16]; sprintf(buf, "hw:%d", card_number); snd_ctl_t * ctl = NULL; if(snd_ctl_open(&ctl, buf, 0) < 0) { continue; } if(snd_ctl_card_info(ctl, info) < 0) { snd_ctl_close(ctl); continue; } snd_ctl_close(ctl); gchar * nice_name = g_strdup(snd_ctl_card_info_get_name(info)); m_device_names = g_list_append(m_device_names, (gpointer)nice_name); if(g_strcmp0(nice_name, m_device) == 0) { g_free(card_override); card_override = g_strdup_printf("hw:%d", card_number); } ret = snd_card_next(&card_number); } // Load the mixer for the provided cardname snd_mixer_open(&m_mixer, 0); if(snd_mixer_attach(m_mixer, (card_override != NULL ? card_override : m_device)) < 0) { fprintf(stderr, "Failed to open sound device with name: %s\n", (card_override != NULL ? card_override : m_device)); snd_mixer_close(m_mixer); m_mixer = NULL; g_free(card_override); return; } else { g_free(card_override); } snd_mixer_selem_register(m_mixer, NULL, NULL); snd_mixer_load(m_mixer); // Setup g_io_watch for the mixer int count = snd_mixer_poll_descriptors_count(m_mixer); if(count >= 1) { struct pollfd pfd; count = snd_mixer_poll_descriptors(m_mixer, &pfd, 1); if(count == 1) { GIOChannel * giochannel = g_io_channel_unix_new(pfd.fd); g_io_add_watch_full(giochannel, G_PRIORITY_DEFAULT, G_IO_IN | G_IO_ERR , asound_poll_cb, NULL, NULL); } } // Iterate over the elements in the mixer and store them in m_channel_names int elemcount = snd_mixer_get_count(m_mixer); snd_mixer_elem_t * elem = snd_mixer_first_elem(m_mixer); int loop; for(loop = 0; loop < elemcount; loop++) { const char * elemname = snd_mixer_selem_get_name(elem); if(snd_mixer_selem_has_playback_volume(elem)) { m_channel_names = g_list_append(m_channel_names, (gpointer)g_strdup(elemname)); } elem = snd_mixer_elem_next(elem); } // Setup m_elem using the provided channelname if(channel != NULL && asound_channel_exists(channel)) asound_set_channel(channel); else if(m_channel_names != NULL) asound_set_channel((const gchar*)m_channel_names->data); }