From f2df2a694856edf1cac3ac6d6582bc57bfdf874d Mon Sep 17 00:00:00 2001 From: Marc-Andre Lureau Date: Tue, 15 May 2007 14:01:26 +0000 Subject: [PATCH] ext/alsa/gstalsamixer.c (main_context, GstAlsaMixerWatch, _GstAlsaMixerWatch, source, n_poll_fds, poll_fds, gst_alsa_... Original commit message from CVS: patch by: Marc-Andre Lureau * ext/alsa/gstalsamixer.c (main_context, GstAlsaMixerWatch, _GstAlsaMixerWatch, source, n_poll_fds, poll_fds, gst_alsa_mixer_watch_funcs, gst_alsa_mixer_prepare, gst_alsa_mixer_check, gst_alsa_mixer_dispatch, gst_alsa_mixer_finalize, gst_alsa_mixer_find_master_mixer, gst_alsa_mixer_handle_source_callback, gst_alsa_mixer_handle_callback, gst_alsa_mixer_elem_handle_callback, gst_alsa_mixer_ensure_track_list, gst_alsa_mixer_free, gst_alsa_mixer_get_volume, gst_alsa_mixer_set_volume, gst_alsa_mixer_set_mute, gst_alsa_mixer_set_record, gst_alsa_mixer_get_option, gst_alsa_mixer_update_option, gst_alsa_mixer_update_track, _gst_alsa_mixer_set_interface): * ext/alsa/gstalsamixer.h (handle_source, interface, dir): * ext/alsa/gstalsamixerelement.c (gst_alsa_mixer_element_details, gst_alsa_mixer_element_interface_supported, gst_alsa_mixer_element_finalize, gst_alsa_mixer_element_init, gst_alsa_mixer_element_set_property, gst_alsa_mixer_element_get_property, gst_alsa_mixer_element_change_state): * ext/alsa/gstalsamixertrack.c (gst_alsa_mixer_track_update): * gst-libs/gst/interfaces/mixer.c (gst_mixer_volume_changed, gst_mixer_option_changed): * gst-libs/gst/interfaces/mixer.h (set_option, get_option, volume_changed, option_changed, _gst_reserved): Implement notification for alsamixer. Fixes #152864 --- ChangeLog | 30 ++++ ext/alsa/gstalsamixer.c | 290 +++++++++++++++++++++++++++++--- ext/alsa/gstalsamixer.h | 5 +- ext/alsa/gstalsamixerelement.c | 75 +++++---- ext/alsa/gstalsamixertrack.c | 20 +++ gst-libs/gst/interfaces/mixer.c | 6 +- gst-libs/gst/interfaces/mixer.h | 19 +-- 7 files changed, 373 insertions(+), 72 deletions(-) diff --git a/ChangeLog b/ChangeLog index 9d4cb65b2d..ac6c06983f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,33 @@ +2007-05-15 Stefan Kost + + patch by: Marc-Andre Lureau + + * ext/alsa/gstalsamixer.c (main_context, GstAlsaMixerWatch, + _GstAlsaMixerWatch, source, n_poll_fds, poll_fds, + gst_alsa_mixer_watch_funcs, gst_alsa_mixer_prepare, + gst_alsa_mixer_check, gst_alsa_mixer_dispatch, + gst_alsa_mixer_finalize, gst_alsa_mixer_find_master_mixer, + gst_alsa_mixer_handle_source_callback, + gst_alsa_mixer_handle_callback, gst_alsa_mixer_elem_handle_callback, + gst_alsa_mixer_ensure_track_list, gst_alsa_mixer_free, + gst_alsa_mixer_get_volume, gst_alsa_mixer_set_volume, + gst_alsa_mixer_set_mute, gst_alsa_mixer_set_record, + gst_alsa_mixer_get_option, gst_alsa_mixer_update_option, + gst_alsa_mixer_update_track, _gst_alsa_mixer_set_interface): + * ext/alsa/gstalsamixer.h (handle_source, interface, dir): + * ext/alsa/gstalsamixerelement.c (gst_alsa_mixer_element_details, + gst_alsa_mixer_element_interface_supported, + gst_alsa_mixer_element_finalize, gst_alsa_mixer_element_init, + gst_alsa_mixer_element_set_property, + gst_alsa_mixer_element_get_property, + gst_alsa_mixer_element_change_state): + * ext/alsa/gstalsamixertrack.c (gst_alsa_mixer_track_update): + * gst-libs/gst/interfaces/mixer.c (gst_mixer_volume_changed, + gst_mixer_option_changed): + * gst-libs/gst/interfaces/mixer.h (set_option, get_option, + volume_changed, option_changed, _gst_reserved): + Implement notification for alsamixer. Fixes #152864 + 2007-05-14 David Schleef * gst/videotestsrc/videotestsrc.c: diff --git a/ext/alsa/gstalsamixer.c b/ext/alsa/gstalsamixer.c index 931d98f346..d66bd9b311 100644 --- a/ext/alsa/gstalsamixer.c +++ b/ext/alsa/gstalsamixer.c @@ -28,7 +28,7 @@ * of an audio device using the ALSA api. * * - * The application should query and use the interfaces provided by this + * The application should query and use the interfaces provided by this * element to control the device. * * @@ -42,6 +42,85 @@ #include "gstalsamixer.h" +static void gst_alsa_mixer_update_option (GstAlsaMixer * mixer, + GstAlsaMixerOptions * alsa_opts); +static void gst_alsa_mixer_update_track (GstAlsaMixer * mixer, + GstAlsaMixerTrack * alsa_track); + +static gboolean gst_alsa_mixer_prepare (GSource * source, gint * timeout); +static gboolean gst_alsa_mixer_check (GSource * source); +static gboolean gst_alsa_mixer_dispatch (GSource * source, GSourceFunc callback, + gpointer user_data); +static void gst_alsa_mixer_finalize (GSource * source); + +static GMainContext *main_context; + +typedef struct _GstAlsaMixerWatch GstAlsaMixerWatch; +struct _GstAlsaMixerWatch +{ + GSource source; + gint n_poll_fds; + GPollFD *poll_fds; +}; + +GSourceFuncs gst_alsa_mixer_watch_funcs = { + gst_alsa_mixer_prepare, + gst_alsa_mixer_check, + gst_alsa_mixer_dispatch, + gst_alsa_mixer_finalize +}; + +static gboolean +gst_alsa_mixer_prepare (GSource * source, gint * timeout) +{ + *timeout = -1; + return FALSE; +} + +static gboolean +gst_alsa_mixer_check (GSource * source) +{ + GstAlsaMixerWatch *watch = (GstAlsaMixerWatch *) source; + gint i; + gushort revents; + + /* Code based on snd_mixer_poll_descriptors_revents() adapted for glib */ + revents = 0; + for (i = 0; i < watch->n_poll_fds; ++i) { + revents |= watch->poll_fds[i].revents & (G_IO_IN | G_IO_ERR | G_IO_HUP); + } + + if (revents & G_IO_ERR || revents & G_IO_HUP) { + GST_WARNING ("ALSA poll fds returned ERR or HUP"); + return FALSE; + } + + return (revents & G_IO_IN); +} + +static gboolean +gst_alsa_mixer_dispatch (GSource * source, GSourceFunc callback, + gpointer user_data) +{ + if (!callback) { + GST_WARNING ("Cannot get callback from ALSA mixer watcher"); + } + + return (*callback) (user_data); +} + +static void +gst_alsa_mixer_finalize (GSource * source) +{ + GstAlsaMixerWatch *watch = (GstAlsaMixerWatch *) source; + + if (watch->poll_fds != NULL) { + g_free (watch->poll_fds); + watch->poll_fds = NULL; + } + + watch->n_poll_fds = 0; +} /* First some utils, then the mixer implementation */ static gboolean @@ -169,11 +248,77 @@ gst_alsa_mixer_find_master_mixer (GstAlsaMixer * mixer, snd_mixer_t * handle) return NULL; } +static gboolean +gst_alsa_mixer_handle_source_callback (gpointer data) +{ + GstAlsaMixer *mixer = (GstAlsaMixer *) data; + + GST_WARNING ("Source cb"); + snd_mixer_handle_events (mixer->handle); + + return TRUE; +} + +static int +gst_alsa_mixer_handle_callback (snd_mixer_t * handle, unsigned int mask, + snd_mixer_elem_t * elem) +{ + GstAlsaMixer *mixer = + (GstAlsaMixer *) snd_mixer_get_callback_private (handle); + GList *item; + + GST_WARNING ("ALSA cb"); + snd_mixer_handle_events (mixer->handle); + + for (item = mixer->tracklist; item != NULL; item = item->next) { + if (GST_IS_ALSA_MIXER_TRACK (item->data)) { + GstAlsaMixerTrack *item_alsa_track = GST_ALSA_MIXER_TRACK (item->data); + + gst_alsa_mixer_update_track (mixer, item_alsa_track); + } else { + GstAlsaMixerOptions *item_alsa_options = + GST_ALSA_MIXER_OPTIONS (item->data); + gst_alsa_mixer_update_option (mixer, item_alsa_options); + } + } + + return 0; +} + +int +gst_alsa_mixer_elem_handle_callback (snd_mixer_elem_t * elem, unsigned int mask) +{ + GstAlsaMixer *mixer = + (GstAlsaMixer *) snd_mixer_elem_get_callback_private (elem); + GList *item; + + GST_WARNING ("ALSA elem cb"); + + for (item = mixer->tracklist; item != NULL; item = item->next) { + if (GST_IS_ALSA_MIXER_TRACK (item->data)) { + if (GST_ALSA_MIXER_TRACK (item->data)->element != elem) + continue; + + gst_alsa_mixer_update_track (mixer, GST_ALSA_MIXER_TRACK (item->data)); + } else if (GST_IS_ALSA_MIXER_OPTIONS (item->data)) { + if (GST_ALSA_MIXER_OPTIONS (item->data)->element != elem) + continue; + + gst_alsa_mixer_update_option (mixer, GST_ALSA_MIXER_OPTIONS (item->data)); + } + } + + return 0; +} + static void gst_alsa_mixer_ensure_track_list (GstAlsaMixer * mixer) { gint i, count; snd_mixer_elem_t *element, *master; + struct pollfd *pfds; + GstAlsaMixerWatch *watch; + GList *item; g_return_if_fail (mixer->handle != NULL); @@ -195,7 +340,6 @@ gst_alsa_mixer_ensure_track_list (GstAlsaMixer * mixer) GstMixerTrack *play_track = NULL; GstMixerTrack *cap_track = NULL; const gchar *name; - GList *item; gint samename = 0; name = snd_mixer_selem_get_name (element); @@ -287,6 +431,63 @@ gst_alsa_mixer_ensure_track_list (GstAlsaMixer * mixer) element = snd_mixer_elem_next (element); } + + if (mixer->handle_source != NULL) + return; + + snd_mixer_set_callback_private (mixer->handle, mixer); + snd_mixer_set_callback (mixer->handle, gst_alsa_mixer_handle_callback); + + main_context = g_main_context_default (); + + mixer->handle_source = + g_source_new (&gst_alsa_mixer_watch_funcs, sizeof (GstAlsaMixerWatch)); + g_return_if_fail (main_context != NULL && mixer->handle_source != NULL); + + watch = (GstAlsaMixerWatch *) mixer->handle_source; + + count = snd_mixer_poll_descriptors_count (mixer->handle); + + pfds = g_newa (struct pollfd, count); + + watch->n_poll_fds = snd_mixer_poll_descriptors (mixer->handle, pfds, count);; + watch->poll_fds = g_new0 (GPollFD, count); + if (watch->poll_fds == NULL) { + GST_WARNING ("Cannot allocate poll descriptors"); + g_source_destroy (mixer->handle_source); + mixer->handle_source = NULL; + return; + } + + for (i = 0; i < watch->n_poll_fds; ++i) { + watch->poll_fds[i].fd = pfds[i].fd; + + if (pfds[i].events & POLLIN) + watch->poll_fds[i].events |= G_IO_IN; + if (pfds[i].events & POLLOUT) + watch->poll_fds[i].events |= G_IO_OUT; + if (pfds[i].events & POLLPRI) + watch->poll_fds[i].events |= G_IO_PRI; + + g_source_add_poll (mixer->handle_source, &watch->poll_fds[i]); + } + + /* FIXME mixer has to be protected, since cb could be made from different thread ? */ + g_source_set_callback (mixer->handle_source, + gst_alsa_mixer_handle_source_callback, mixer, NULL); + g_source_attach (mixer->handle_source, main_context); + + 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); + } } @@ -322,6 +523,16 @@ gst_alsa_mixer_free (GstAlsaMixer * mixer) { g_return_if_fail (mixer != NULL); + if (mixer->interface) { + g_object_unref (G_OBJECT (mixer->interface)); + mixer->interface = NULL; + } + + if (mixer->handle_source) { + g_source_destroy (mixer->handle_source); + mixer->handle_source = NULL; + } + if (mixer->device) { g_free (mixer->device); mixer->device = NULL; @@ -356,16 +567,6 @@ gst_alsa_mixer_list_tracks (GstAlsaMixer * mixer) return (const GList *) mixer->tracklist; } -static void -gst_alsa_mixer_update (GstAlsaMixer * mixer, GstAlsaMixerTrack * alsa_track) -{ - snd_mixer_handle_events (mixer->handle); - - if (alsa_track) - gst_alsa_mixer_track_update (alsa_track); -} - - void gst_alsa_mixer_get_volume (GstAlsaMixer * mixer, GstMixerTrack * track, gint * volumes) @@ -375,7 +576,7 @@ gst_alsa_mixer_get_volume (GstAlsaMixer * mixer, GstMixerTrack * track, g_return_if_fail (mixer->handle != NULL); - gst_alsa_mixer_update (mixer, alsa_track); + gst_alsa_mixer_track_update (alsa_track); if (track->flags & GST_MIXER_TRACK_OUTPUT) { /* return playback volume */ @@ -420,7 +621,7 @@ gst_alsa_mixer_set_volume (GstAlsaMixer * mixer, GstMixerTrack * track, g_return_if_fail (mixer->handle != NULL); - gst_alsa_mixer_update (mixer, alsa_track); + gst_alsa_mixer_track_update (alsa_track); if (track->flags & GST_MIXER_TRACK_OUTPUT) { @@ -461,7 +662,7 @@ gst_alsa_mixer_set_mute (GstAlsaMixer * mixer, GstMixerTrack * track, g_return_if_fail (mixer->handle != NULL); - gst_alsa_mixer_update (mixer, alsa_track); + gst_alsa_mixer_track_update (alsa_track); if (!!(mute) == !!(track->flags & GST_MIXER_TRACK_MUTE)) return; @@ -509,7 +710,7 @@ gst_alsa_mixer_set_record (GstAlsaMixer * mixer, g_return_if_fail (mixer->handle != NULL); - gst_alsa_mixer_update (mixer, alsa_track); + gst_alsa_mixer_track_update (alsa_track); if (!!(record) == !!(track->flags & GST_MIXER_TRACK_RECORD)) return; @@ -536,7 +737,7 @@ gst_alsa_mixer_set_record (GstAlsaMixer * mixer, if (item_alsa_track->alsa_flags & GST_ALSA_MIXER_TRACK_CSWITCH_EXCL && item_alsa_track->capture_group == alsa_track->capture_group) { - gst_alsa_mixer_update (mixer, item_alsa_track); + gst_alsa_mixer_track_update (item_alsa_track); } } } @@ -562,8 +763,6 @@ gst_alsa_mixer_set_option (GstAlsaMixer * mixer, g_return_if_fail (mixer->handle != NULL); - gst_alsa_mixer_update (mixer, NULL); - for (item = opts->values; item != NULL; item = item->next, n++) { if (!strcmp (item->data, value)) { idx = n; @@ -585,11 +784,60 @@ gst_alsa_mixer_get_option (GstAlsaMixer * mixer, GstMixerOptions * opts) g_return_val_if_fail (mixer->handle != NULL, NULL); - gst_alsa_mixer_update (mixer, NULL); - ret = snd_mixer_selem_get_enum_item (alsa_opts->element, 0, &idx); if (ret == 0) return g_list_nth_data (opts->values, idx); else return snd_strerror (ret); /* feeble attempt at error handling */ } + +static void +gst_alsa_mixer_update_option (GstAlsaMixer * mixer, + GstAlsaMixerOptions * alsa_opts) +{ + gint ret; + guint idx; + const gchar *option; + + if (mixer->interface == NULL) { + GST_WARNING ("Cannot send update notifications, no GstMixer * given"); + return; + } + + ret = snd_mixer_selem_get_enum_item (alsa_opts->element, 0, &idx); + if (ret == 0) { + option = g_list_nth_data (GST_MIXER_OPTIONS (alsa_opts)->values, idx); + gst_mixer_option_changed (mixer->interface, GST_MIXER_OPTIONS (alsa_opts), + option); + } +} + +static void +gst_alsa_mixer_update_track (GstAlsaMixer * mixer, + GstAlsaMixerTrack * alsa_track) +{ + GstMixerTrack *track = (GstMixerTrack *) alsa_track; + + if (mixer->interface == NULL) { + GST_WARNING ("Cannot send update notifications, no GstMixer * given"); + return; + } + + gst_alsa_mixer_track_update (alsa_track); + + gst_mixer_record_toggled (mixer->interface, track, + GST_MIXER_TRACK_HAS_FLAG (track, GST_MIXER_TRACK_RECORD)); + gst_mixer_mute_toggled (mixer->interface, track, + GST_MIXER_TRACK_HAS_FLAG (track, GST_MIXER_TRACK_MUTE)); + gst_mixer_volume_changed (mixer->interface, track, alsa_track->volumes); +} + +/* utility function for gstalsamixerelement to set the interface */ +void +_gst_alsa_mixer_set_interface (GstAlsaMixer * mixer, GstMixer * interface) +{ + g_return_if_fail (mixer != NULL && mixer->interface == NULL); + g_return_if_fail (interface != NULL); + + mixer->interface = g_object_ref (G_OBJECT (interface)); +} diff --git a/ext/alsa/gstalsamixer.h b/ext/alsa/gstalsamixer.h index 6c9eb1e7ca..bf6457a0d7 100644 --- a/ext/alsa/gstalsamixer.h +++ b/ext/alsa/gstalsamixer.h @@ -51,7 +51,9 @@ struct _GstAlsaMixer GList * tracklist; /* list of available tracks */ snd_mixer_t * handle; + GSource * handle_source; + GstMixer * interface; gchar * device; gchar * cardname; @@ -61,6 +63,8 @@ struct _GstAlsaMixer GstAlsaMixer* gst_alsa_mixer_new (const gchar *device, GstAlsaMixerDirection dir); +void _gst_alsa_mixer_set_interface (GstAlsaMixer * mixer, + GstMixer * interface); void gst_alsa_mixer_free (GstAlsaMixer *mixer); const GList* gst_alsa_mixer_list_tracks (GstAlsaMixer * mixer); @@ -82,7 +86,6 @@ void gst_alsa_mixer_set_option (GstAlsaMixer * mixer, const gchar* gst_alsa_mixer_get_option (GstAlsaMixer * mixer, GstMixerOptions * opts); - #define GST_IMPLEMENT_ALSA_MIXER_METHODS(Type, interface_as_function) \ static gboolean \ interface_as_function ## _supported (Type *this, GType iface_type) \ diff --git a/ext/alsa/gstalsamixerelement.c b/ext/alsa/gstalsamixerelement.c index 75d5b4a49c..b30d56ebe2 100644 --- a/ext/alsa/gstalsamixerelement.c +++ b/ext/alsa/gstalsamixerelement.c @@ -44,26 +44,26 @@ GST_ELEMENT_DETAILS ("Alsa mixer", static void gst_alsa_mixer_element_init_interfaces (GType type); GST_BOILERPLATE_FULL (GstAlsaMixerElement, gst_alsa_mixer_element, - GstElement, GST_TYPE_ELEMENT, gst_alsa_mixer_element_init_interfaces) + GstElement, GST_TYPE_ELEMENT, gst_alsa_mixer_element_init_interfaces); /* massive macro that takes care of all the GstMixer stuff */ - GST_IMPLEMENT_ALSA_MIXER_METHODS (GstAlsaMixerElement, gst_alsa_mixer_element); +GST_IMPLEMENT_ALSA_MIXER_METHODS (GstAlsaMixerElement, gst_alsa_mixer_element); - static void gst_alsa_mixer_element_get_property (GObject * object, +static void gst_alsa_mixer_element_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec); - static void gst_alsa_mixer_element_set_property (GObject * object, +static void gst_alsa_mixer_element_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec); - static void gst_alsa_mixer_element_finalize (GObject * object); +static void gst_alsa_mixer_element_finalize (GObject * object); - static GstStateChangeReturn gst_alsa_mixer_element_change_state (GstElement +static GstStateChangeReturn gst_alsa_mixer_element_change_state (GstElement * element, GstStateChange transition); - static gboolean - gst_alsa_mixer_element_interface_supported (GstAlsaMixerElement * this, +static gboolean +gst_alsa_mixer_element_interface_supported (GstAlsaMixerElement * self, GType interface_type) { if (interface_type == GST_TYPE_MIXER) { - return gst_alsa_mixer_element_supported (this, interface_type); + return gst_alsa_mixer_element_supported (self, interface_type); } g_return_val_if_reached (FALSE); @@ -133,37 +133,37 @@ gst_alsa_mixer_element_class_init (GstAlsaMixerElementClass * klass) static void gst_alsa_mixer_element_finalize (GObject * obj) { - GstAlsaMixerElement *this = GST_ALSA_MIXER_ELEMENT (obj); + GstAlsaMixerElement *self = GST_ALSA_MIXER_ELEMENT (obj); - g_free (this->device); + g_free (self->device); G_OBJECT_CLASS (parent_class)->finalize (obj); } static void -gst_alsa_mixer_element_init (GstAlsaMixerElement * this, +gst_alsa_mixer_element_init (GstAlsaMixerElement * self, GstAlsaMixerElementClass * klass) { - this->mixer = NULL; - this->device = g_strdup (DEFAULT_PROP_DEVICE); + self->mixer = NULL; + self->device = g_strdup (DEFAULT_PROP_DEVICE); } static void gst_alsa_mixer_element_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) { - GstAlsaMixerElement *this = GST_ALSA_MIXER_ELEMENT (object); + GstAlsaMixerElement *self = GST_ALSA_MIXER_ELEMENT (object); switch (prop_id) { case PROP_DEVICE:{ - GST_OBJECT_LOCK (this); - g_free (this->device); - this->device = g_value_dup_string (value); + GST_OBJECT_LOCK (self); + g_free (self->device); + self->device = g_value_dup_string (value); /* make sure we never set NULL, this is nice when we want to open the * device. */ - if (this->device == NULL) - this->device = g_strdup (DEFAULT_PROP_DEVICE); - GST_OBJECT_UNLOCK (this); + if (self->device == NULL) + self->device = g_strdup (DEFAULT_PROP_DEVICE); + GST_OBJECT_UNLOCK (self); break; } default: @@ -176,23 +176,23 @@ static void gst_alsa_mixer_element_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec) { - GstAlsaMixerElement *this = GST_ALSA_MIXER_ELEMENT (object); + GstAlsaMixerElement *self = GST_ALSA_MIXER_ELEMENT (object); switch (prop_id) { case PROP_DEVICE:{ - GST_OBJECT_LOCK (this); - g_value_set_string (value, this->device); - GST_OBJECT_UNLOCK (this); + GST_OBJECT_LOCK (self); + g_value_set_string (value, self->device); + GST_OBJECT_UNLOCK (self); break; } case PROP_DEVICE_NAME:{ - GST_OBJECT_LOCK (this); - if (this->mixer) { - g_value_set_string (value, this->mixer->cardname); + GST_OBJECT_LOCK (self); + if (self->mixer) { + g_value_set_string (value, self->mixer->cardname); } else { g_value_set_string (value, NULL); } - GST_OBJECT_UNLOCK (this); + GST_OBJECT_UNLOCK (self); break; } default: @@ -206,14 +206,15 @@ gst_alsa_mixer_element_change_state (GstElement * element, GstStateChange transition) { GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; - GstAlsaMixerElement *this = GST_ALSA_MIXER_ELEMENT (element); + GstAlsaMixerElement *self = GST_ALSA_MIXER_ELEMENT (element); switch (transition) { case GST_STATE_CHANGE_NULL_TO_READY: - if (!this->mixer) { - this->mixer = gst_alsa_mixer_new (this->device, GST_ALSA_MIXER_ALL); - if (!this->mixer) + if (!self->mixer) { + self->mixer = gst_alsa_mixer_new (self->device, GST_ALSA_MIXER_ALL); + if (!self->mixer) goto open_failed; + _gst_alsa_mixer_set_interface (self->mixer, GST_MIXER (element)); } break; default: @@ -226,9 +227,9 @@ gst_alsa_mixer_element_change_state (GstElement * element, switch (transition) { case GST_STATE_CHANGE_READY_TO_NULL: - if (this->mixer) { - gst_alsa_mixer_free (this->mixer); - this->mixer = NULL; + if (self->mixer) { + gst_alsa_mixer_free (self->mixer); + self->mixer = NULL; } break; default: @@ -241,7 +242,7 @@ gst_alsa_mixer_element_change_state (GstElement * element, open_failed: { GST_ELEMENT_ERROR (element, RESOURCE, OPEN_READ_WRITE, (NULL), - ("Failed to open alsa mixer device '%s'", this->device)); + ("Failed to open alsa mixer device '%s'", self->device)); return GST_STATE_CHANGE_FAILURE; } } diff --git a/ext/alsa/gstalsamixertrack.c b/ext/alsa/gstalsamixertrack.c index d7b8a931b9..10e6dff45c 100644 --- a/ext/alsa/gstalsamixertrack.c +++ b/ext/alsa/gstalsamixertrack.c @@ -239,6 +239,26 @@ gst_alsa_mixer_track_update (GstAlsaMixerTrack * alsa_track) gint i; gint audible = !(track->flags & GST_MIXER_TRACK_MUTE); + if (alsa_track_has_cap (alsa_track, GST_ALSA_MIXER_TRACK_PVOLUME)) { + /* update playback volume */ + for (i = 0; i < track->num_channels; i++) { + long vol = 0; + + snd_mixer_selem_get_playback_volume (alsa_track->element, i, &vol); + alsa_track->volumes[i] = (gint) vol; + } + } + + if (alsa_track_has_cap (alsa_track, GST_ALSA_MIXER_TRACK_CVOLUME)) { + /* update capture volume */ + for (i = 0; i < track->num_channels; i++) { + long vol = 0; + + snd_mixer_selem_get_capture_volume (alsa_track->element, i, &vol); + alsa_track->volumes[i] = (gint) vol; + } + } + /* Any updates in flags? */ if (alsa_track_has_cap (alsa_track, GST_ALSA_MIXER_TRACK_PSWITCH)) { int v = 0; diff --git a/gst-libs/gst/interfaces/mixer.c b/gst-libs/gst/interfaces/mixer.c index 116bab23bb..6058b9fcf6 100644 --- a/gst-libs/gst/interfaces/mixer.c +++ b/gst-libs/gst/interfaces/mixer.c @@ -340,7 +340,7 @@ gst_mixer_record_toggled (GstMixer * mixer, void gst_mixer_volume_changed (GstMixer * mixer, - GstMixerTrack * track, gint * volumes) + GstMixerTrack * track, const gint * volumes) { g_return_if_fail (mixer != NULL); g_return_if_fail (track != NULL); @@ -353,7 +353,7 @@ gst_mixer_volume_changed (GstMixer * mixer, void gst_mixer_option_changed (GstMixer * mixer, - GstMixerOptions * opts, gchar * value) + GstMixerOptions * opts, const gchar * value) { g_return_if_fail (mixer != NULL); g_return_if_fail (opts != NULL); @@ -361,5 +361,5 @@ gst_mixer_option_changed (GstMixer * mixer, g_signal_emit (G_OBJECT (mixer), gst_mixer_signals[SIGNAL_OPTION_CHANGED], 0, opts, value); - g_signal_emit_by_name (G_OBJECT (opts), "value_changed", value); + g_signal_emit_by_name (G_OBJECT (opts), "option_changed", value); } diff --git a/gst-libs/gst/interfaces/mixer.h b/gst-libs/gst/interfaces/mixer.h index dde73ab485..28c5f1140a 100644 --- a/gst-libs/gst/interfaces/mixer.h +++ b/gst-libs/gst/interfaces/mixer.h @@ -74,6 +74,11 @@ struct _GstMixerClass { void (* set_record) (GstMixer *mixer, GstMixerTrack *track, gboolean record); + void (* set_option) (GstMixer *mixer, + GstMixerOptions *opts, + gchar *value); + const gchar * (* get_option) (GstMixer *mixer, + GstMixerOptions *opts); /* signals */ void (* mute_toggled) (GstMixer *mixer, @@ -84,17 +89,11 @@ struct _GstMixerClass { gboolean record); void (* volume_changed) (GstMixer *mixer, GstMixerTrack *channel, - gint *volumes); - - void (* set_option) (GstMixer *mixer, - GstMixerOptions *opts, - gchar *value); - const gchar * (* get_option) (GstMixer *mixer, - GstMixerOptions *opts); + const gint *volumes); void (* option_changed) (GstMixer *mixer, GstMixerOptions *opts, - gchar *option); + const gchar *option); /*< private >*/ gpointer _gst_reserved[GST_PADDING]; @@ -131,10 +130,10 @@ void gst_mixer_record_toggled (GstMixer *mixer, gboolean record); void gst_mixer_volume_changed (GstMixer *mixer, GstMixerTrack *track, - gint *volumes); + const gint *volumes); void gst_mixer_option_changed (GstMixer *mixer, GstMixerOptions *opts, - gchar *value); + const gchar *value); G_END_DECLS