void moko_alsa_volume_control_set_element_from_name (MokoAlsaVolumeControl *control, const gchar *name) { MokoAlsaVolumeControlPrivate *priv = ALSA_VOLUME_CONTROL_PRIVATE (control); if (!priv->device) return; detach_mixer (control); if (!name) { moko_alsa_volume_control_set_element (control, NULL); return; } open_mixer (control); if ((snd_mixer_attach (priv->mixer_handle, priv->device) == 0) && (snd_mixer_selem_register (priv->mixer_handle, NULL, NULL) == 0) && (snd_mixer_load (priv->mixer_handle) == 0)) { snd_mixer_elem_t *elem; elem = snd_mixer_first_elem (priv->mixer_handle); while (elem) { const char *elem_name = snd_mixer_selem_get_name (elem); if (strcmp (elem_name, name) == 0) break; elem = snd_mixer_elem_next (elem); } if (!elem) { snd_mixer_detach (priv->mixer_handle, priv->device); close_mixer (control); g_warning ("Mixer element '%s' not found", name); attach_mixer (control); } else { snd_mixer_selem_id_t *id; if (snd_mixer_selem_id_malloc (&id) != 0) { g_warning ("Unable to allocate element id"); snd_mixer_detach ( priv->mixer_handle, priv->device); close_mixer (control); } else { snd_mixer_selem_get_id (elem, id); snd_mixer_detach ( priv->mixer_handle, priv->device); close_mixer (control); g_debug ("Setting element ID"); moko_alsa_volume_control_set_element ( control, id); snd_mixer_selem_id_free (id); } } } else g_warning ("Unable to open mixer on card '%s'", priv->device); }
static void attach_mixer (MokoAlsaVolumeControl *self) { MokoAlsaVolumeControlPrivate *priv = ALSA_VOLUME_CONTROL_PRIVATE (self); g_debug ("Trying to attach... %p, %s, %p", priv->mixer_handle, priv->device, priv->element); open_mixer (self); if (priv->mixer_handle && priv->device && priv->element && (snd_mixer_attach (priv->mixer_handle, priv->device) == 0) && (snd_mixer_selem_register (priv->mixer_handle, NULL, NULL) == 0) && (snd_mixer_load (priv->mixer_handle) == 0)) { priv->mixer_elem = snd_mixer_find_selem ( priv->mixer_handle, priv->element); if (!priv->mixer_elem) { g_warning ("Unable to find mixer element"); snd_mixer_detach (priv->mixer_handle, priv->device); close_mixer (self); } else { g_debug ("Attached to mixer"); if (snd_mixer_selem_has_playback_volume ( priv->mixer_elem)) { priv->control_type = PLAYBACK; snd_mixer_selem_get_playback_volume_range ( priv->mixer_elem, &priv->min, &priv->max); } else if (snd_mixer_selem_has_capture_volume ( priv->mixer_elem)) { priv->control_type = CAPTURE; snd_mixer_selem_get_capture_volume_range ( priv->mixer_elem, &priv->min, &priv->max); } else priv->control_type = CONTROL; snd_mixer_elem_set_callback ( priv->mixer_elem, mixer_elem_event_cb); snd_mixer_elem_set_callback_private ( priv->mixer_elem, self); start_polling (self); update_volume (self); } } else { close_mixer (self); } }
static void detach_mixer (MokoAlsaVolumeControl *self) { MokoAlsaVolumeControlPrivate *priv = ALSA_VOLUME_CONTROL_PRIVATE (self); if (priv->mixer_handle && priv->device && priv->element && priv->mixer_elem) { snd_mixer_detach (priv->mixer_handle, priv->device); priv->mixer_elem = NULL; g_debug ("Detached from mixer"); close_mixer (self); } }
/** * Deinitializes the alsa system by * closing the mixer. */ static void alsaunset(void) { if (active_card == NULL) return; unset_io_watch(); // 'elem' must be set to NULL at last, because alsa_cb() // is invoked when closing mixer, and elem is needed. close_mixer(handle, active_card->dev); handle = NULL; elem = NULL; active_card = NULL; }
/** * Get all playable channels for a single alsa card and * return them as a GSList. * * @param card HCTL name of the alsa card * @return the GSList of channels */ static GSList * get_channels(const char *card) { int ccount, i; snd_mixer_t *mixer; snd_mixer_elem_t *telem; GSList *channels = NULL; mixer = open_mixer(card, NULL, 0); if (mixer == NULL) return NULL; ccount = snd_mixer_get_count(mixer); telem = snd_mixer_first_elem(mixer); for (i = 0; i < ccount; i++) { if (snd_mixer_selem_has_playback_volume(telem)) channels = g_slist_append(channels, strdup(snd_mixer_selem_get_name(telem))); telem = snd_mixer_elem_next(telem); } #ifdef DEBUG GSList *tmp = channels; if (tmp) { printf("Card %s: available channels\n", card); while (tmp) { printf("\t%s\n", (char *) tmp->data); tmp = tmp->next; } } else { printf("Card %s: no playable channels\n", card); } #endif close_mixer(mixer, card); return channels; }