void asound_set_channel(const gchar * channel) { if(m_mixer == NULL || channel == NULL) { return; } if(g_strcmp0(channel, m_channel) == 0) return; // Clean up any previously set channels g_free(m_channel); m_channel = g_strdup(channel); if(m_elem) { snd_mixer_elem_set_callback(m_elem, NULL); m_elem = NULL; } // Setup m_elem using the provided channelname snd_mixer_selem_id_t * sid; snd_mixer_selem_id_malloc(&sid); snd_mixer_selem_id_set_name(sid, channel); m_elem = snd_mixer_find_selem(m_mixer, sid); if(m_elem != NULL) { snd_mixer_elem_set_callback(m_elem, asound_elem_event); snd_mixer_selem_id_free(sid); } }
void lamixer_mixerelem_show(MixerElem *mixer_elem) { if(mixer_elem->playback != NULL) lamixer_volbox_show(mixer_elem->playback, mixer_elem->elem, mixerbox); if(mixer_elem->capture != NULL) lamixer_volbox_show(mixer_elem->capture, mixer_elem->elem, capturebox); if(mixer_elem->pswitch != NULL) lamixer_switchbox_show(mixer_elem->pswitch, switchvbox); if(mixer_elem->cswitch != NULL) lamixer_switchbox_show(mixer_elem->cswitch, switchcapturevbox); if(mixer_elem->penum != NULL) lamixer_enumbox_show(mixer_elem->penum, enumvbox); if(mixer_elem->cenum != NULL) lamixer_enumbox_show(mixer_elem->cenum, enumcapturevbox); if(mixer_elem->playback != NULL || mixer_elem->capture != NULL) { snd_mixer_elem_set_callback(mixer_elem->elem, lamixer_volbox_change); snd_mixer_elem_set_callback_private(mixer_elem->elem, mixer_elem); } }
static int mixer_callback(snd_mixer_t *mixer, unsigned int mask, snd_mixer_elem_t *elem) { if (mask & SND_CTL_EVENT_MASK_ADD) { snd_mixer_elem_set_callback(elem, elem_callback); controls_changed = TRUE; } return 0; }
void lamixer_enumbox_show(EnumBox *enumbox, GtkWidget *enumvbox) { guint evalue; snd_mixer_selem_get_enum_item(enumbox->volelem, SND_MIXER_SCHN_FRONT_LEFT, &evalue); gtk_combo_box_set_active(GTK_COMBO_BOX(enumbox->enumswitch), evalue); gtk_box_pack_start(GTK_BOX(enumvbox), enumbox->enumhbox, TRUE, FALSE, 0); g_signal_connect(G_OBJECT(enumbox->enumswitch), "changed", G_CALLBACK(lamixer_enumbox_changed), enumbox->volelem); snd_mixer_elem_set_callback(enumbox->volelem, lamixer_enumbox_change); snd_mixer_elem_set_callback_private(enumbox->volelem, enumbox); }
static int on_mixer_event(snd_mixer_t *handle, unsigned int mask, snd_mixer_elem_t *elem) { snd_mixer_selem_id_t *sid; if(mask & SND_CTL_EVENT_MASK_ADD) { snd_mixer_selem_id_alloca(&sid); snd_mixer_selem_get_id(elem, sid); DEBUG("set callback for mixer control = %s\n", snd_mixer_selem_id_get_name(sid)); snd_mixer_elem_set_callback(elem, on_mixer_elem_event); } return 0; }
void gam_toggle_set_elem (GamToggle *gam_toggle, snd_mixer_elem_t *elem) { GamTogglePrivate *priv; g_return_if_fail (GAM_IS_TOGGLE (gam_toggle)); priv = GAM_TOGGLE_GET_PRIVATE (gam_toggle); if (priv->elem) snd_mixer_elem_set_callback (priv->elem, NULL); if (elem) { snd_mixer_elem_set_callback_private (elem, gam_toggle); snd_mixer_elem_set_callback (elem, gam_toggle_refresh); } priv->elem = elem; g_object_notify (G_OBJECT (gam_toggle), "elem"); }
void lamixer_switchbox_show(SwitchBox *swbox, GtkWidget *swvbox) { int swstat; snd_mixer_selem_get_playback_switch (swbox->volelem, SND_MIXER_SCHN_FRONT_LEFT, &swstat); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(swbox->volswitch), swstat); swbox->hswsignalid = g_signal_connect(G_OBJECT(swbox->volswitch), "toggled", G_CALLBACK(lamixer_volswitch_changed), swbox->volelem); gtk_box_pack_start(GTK_BOX(swvbox), swbox->volswitch, TRUE, TRUE, 0); snd_mixer_elem_set_callback(swbox->volelem, lamixer_switchbox_change); snd_mixer_elem_set_callback_private(swbox->volelem, swbox); }
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 gint _j4status_alsa_section_mixer_callback(snd_mixer_t *mixer, guint mask, snd_mixer_elem_t *elem) { J4statusAlsaSection *section = snd_mixer_get_callback_private(mixer); if ( mask & SND_CTL_EVENT_MASK_ADD ) { if ( ( snd_mixer_selem_get_index(elem) == 0 ) && ( g_strcmp0(snd_mixer_selem_get_name(elem), "Master") == 0 ) && snd_mixer_selem_has_playback_channel(elem, SND_MIXER_SCHN_FRONT_LEFT) && ( snd_mixer_elem_get_callback_private(elem) == NULL ) ) { snd_mixer_elem_set_callback(elem, _j4status_alsa_section_elem_callback); snd_mixer_elem_set_callback_private(elem, section); } } return 0; }
static void gam_toggle_finalize (GObject *object) { GamToggle *gam_toggle; GamTogglePrivate *priv; g_return_if_fail (GAM_IS_TOGGLE (object)); gam_toggle = GAM_TOGGLE (object); priv = GAM_TOGGLE_GET_PRIVATE (gam_toggle); snd_mixer_elem_set_callback (priv->elem, NULL); g_free (priv->name_config); priv->name_config = NULL; priv->elem = NULL; priv->mixer = NULL; priv->app = NULL; G_OBJECT_CLASS (parent_class)->finalize (object); }
static void gst_alsa_mixer_ensure_track_list (GstAlsaMixer * mixer) { gint i, count; snd_mixer_elem_t *element, *master; GList *item; g_return_if_fail (mixer->handle != NULL); if (mixer->tracklist) return; g_static_rec_mutex_lock (mixer->rec_mutex); master = gst_alsa_mixer_find_master_mixer (mixer, mixer->handle); count = snd_mixer_get_count (mixer->handle); element = snd_mixer_first_elem (mixer->handle); /* build track list * * Some ALSA tracks may have playback and capture capabilities. * Here we model them as two separate GStreamer tracks. */ for (i = 0; i < count; i++) { GstMixerTrack *play_track = NULL; GstMixerTrack *cap_track = NULL; const gchar *name; GList *item; gint samename = 0; name = snd_mixer_selem_get_name (element); /* prevent dup names */ for (item = mixer->tracklist; item != NULL; item = item->next) { snd_mixer_elem_t *temp; if (GST_IS_ALSA_MIXER_OPTIONS (item->data)) temp = GST_ALSA_MIXER_OPTIONS (item->data)->element; else temp = GST_ALSA_MIXER_TRACK (item->data)->element; if (strcmp (name, snd_mixer_selem_get_name (temp)) == 0) samename++; } GST_LOG ("[%s] probing element #%u, mixer->dir=%u", name, i, mixer->dir); if (mixer->dir & GST_ALSA_MIXER_PLAYBACK) { gboolean has_playback_switch, has_playback_volume; has_playback_switch = snd_mixer_selem_has_playback_switch (element); has_playback_volume = snd_mixer_selem_has_playback_volume (element); GST_LOG ("[%s] PLAYBACK: has_playback_volume=%d, has_playback_switch=%d" "%s", name, has_playback_volume, has_playback_switch, (element == master) ? " MASTER" : ""); if (has_playback_volume) { gint flags = GST_MIXER_TRACK_OUTPUT; if (element == master) flags |= GST_MIXER_TRACK_MASTER; play_track = gst_alsa_mixer_track_new (element, samename, i, flags, FALSE, NULL, FALSE); } else if (has_playback_switch) { /* simple mute switch */ play_track = gst_alsa_mixer_track_new (element, samename, i, GST_MIXER_TRACK_OUTPUT, TRUE, NULL, FALSE); } if (snd_mixer_selem_is_enumerated (element)) { GstMixerOptions *opts = gst_alsa_mixer_options_new (element, i); GST_LOG ("[%s] is enumerated (%d)", name, i); mixer->tracklist = g_list_append (mixer->tracklist, opts); } } if (mixer->dir & GST_ALSA_MIXER_CAPTURE) { gboolean has_capture_switch, has_common_switch; gboolean has_capture_volume, has_common_volume; has_capture_switch = snd_mixer_selem_has_capture_switch (element); has_common_switch = snd_mixer_selem_has_common_switch (element); has_capture_volume = snd_mixer_selem_has_capture_volume (element); has_common_volume = snd_mixer_selem_has_common_volume (element); GST_LOG ("[%s] CAPTURE: has_capture_volume=%d, has_common_volume=%d, " "has_capture_switch=%d, has_common_switch=%d, play_track=%p", name, has_capture_volume, has_common_volume, has_capture_switch, has_common_switch, play_track); if (has_capture_volume && !(play_track && has_common_volume)) { cap_track = gst_alsa_mixer_track_new (element, samename, i, GST_MIXER_TRACK_INPUT, FALSE, NULL, play_track != NULL); } else if (has_capture_switch && !(play_track && has_common_switch)) { cap_track = gst_alsa_mixer_track_new (element, samename, i, GST_MIXER_TRACK_INPUT, TRUE, NULL, play_track != NULL); } } if (play_track && cap_track) { GST_ALSA_MIXER_TRACK (play_track)->shared_mute = GST_ALSA_MIXER_TRACK (cap_track); GST_ALSA_MIXER_TRACK (cap_track)->shared_mute = GST_ALSA_MIXER_TRACK (play_track); } if (play_track) mixer->tracklist = g_list_append (mixer->tracklist, play_track); if (cap_track) mixer->tracklist = g_list_append (mixer->tracklist, cap_track); element = snd_mixer_elem_next (element); } for (item = mixer->tracklist; item != NULL; item = item->next) { snd_mixer_elem_t *temp; if (GST_IS_ALSA_MIXER_OPTIONS (item->data)) temp = GST_ALSA_MIXER_OPTIONS (item->data)->element; else temp = GST_ALSA_MIXER_TRACK (item->data)->element; snd_mixer_elem_set_callback (temp, gst_alsa_mixer_elem_handle_callback); snd_mixer_elem_set_callback_private (temp, mixer); } g_static_rec_mutex_unlock (mixer->rec_mutex); }
/** * Initializes the alsa system by getting the cards * and channels and setting the io watch for external * volume changes. * * @return 0 on success otherwise negative error code */ static int alsaset(void) { char *card_name; char *channel; // update list of available cards DEBUG_PRINT("Getting available cards..."); get_cards(); assert(cards != NULL); // get selected card assert(active_card == NULL); card_name = get_selected_card(); DEBUG_PRINT("Selected card: %s", card_name); if (card_name) { active_card = find_card(card_name); g_free(card_name); } // if not available, use the default card if (!active_card) { DEBUG_PRINT("Using default soundcard"); active_card = cards->data; } // If no playable channels, iterate on card list until a valid card is // found. // In most situations, the first card of the list (which is the // Alsa default card) can be opened. // However, in some situations the default card may be unavailable. // For example, when it's an USB DAC, and it's disconnected. if (!active_card->channels) { GSList *item; DEBUG_PRINT("Card '%s' has no playable channels, iterating on card list", active_card->dev); for (item = cards; item; item = item->next) { active_card = item->data; if (active_card->channels) break; } assert(item != NULL); } // open card DEBUG_PRINT("Opening card '%s'...", active_card->dev); smixer_options.device = active_card->dev; handle = open_mixer(active_card->dev, &smixer_options, smixer_level); assert(handle != NULL); // Set the channel // We have to handle the fact that the channel name defined // in PNMixer configuration is not necessarily valid. // For example, this may happen when the default alsa soundcard // is modified. The channel names of the new default card may // not match the channel names of the previous default card. assert(elem == NULL); channel = get_selected_channel(active_card->name); if (channel) { snd_mixer_selem_id_t *sid; snd_mixer_selem_id_alloca(&sid); snd_mixer_selem_id_set_name(sid, channel); elem = snd_mixer_find_selem(handle, sid); g_free(channel); } if (elem == NULL) { elem = snd_mixer_first_elem(handle); } assert(elem != NULL); // Set callback DEBUG_PRINT("Using channel '%s'", snd_mixer_selem_get_name(elem)); snd_mixer_elem_set_callback(elem, alsa_cb); // set watch for volume changes set_io_watch(handle); return 0; }
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); }