Index: ext/alsa/gstalsamixer.c
===================================================================
--- ext/alsa/gstalsamixer.c	(revision 9)
+++ ext/alsa/gstalsamixer.c	(revision 10)
@@ -38,6 +38,9 @@
 static gboolean gst_alsa_mixer_supported (GstImplementsInterface * iface,
     GType iface_type);
 
+static gboolean gst_alsa_mixer_handle_events (GIOChannel *source,
+    GIOCondition condition, gpointer data);
+
 /* GStreamer stuff */
 static GstElementStateReturn gst_alsa_mixer_change_state (GstElement * element);
 
@@ -138,6 +141,10 @@
   gint err, device;
   GstAlsa *alsa = GST_ALSA (mixer);
   gchar *nocomma = NULL;
+  gint poll_count, poll_fill_count, i;
+  guint *source_ids;
+  struct pollfd *polls = NULL;
+ 
 
   mixer->mixer_handle = NULL;
 
@@ -184,6 +191,34 @@
       alsa->cardname = name;
   }
 
+  /* Handle alsa events */
+  poll_count = snd_mixer_poll_descriptors_count (mixer->mixer_handle);
+  if (poll_count < 0) goto error;
+
+  polls = g_newa (struct pollfd, poll_count);
+  poll_fill_count = snd_mixer_poll_descriptors (mixer->mixer_handle, polls, poll_count);
+  if (poll_count != poll_fill_count) goto error;
+
+  source_ids = g_new (guint, poll_count);
+
+  for (i = 0; i < poll_count; i++) {
+    GIOCondition condition = 0;
+    const struct pollfd * const pollfd = &polls[i];
+    GIOChannel *channel = g_io_channel_unix_new (pollfd->fd);
+    const short events = pollfd->events;
+
+    if (events & POLLIN)  condition |= G_IO_IN;
+    if (events & POLLOUT) condition |= G_IO_OUT;
+    if (events & POLLPRI) condition |= G_IO_PRI;
+
+    source_ids[i] = g_io_add_watch (channel, condition, gst_alsa_mixer_handle_events, mixer);
+    g_io_channel_unref (channel);
+  }
+
+  mixer->source_ids = source_ids;
+  mixer->source_id_count = (guint) poll_count;
+
+  g_free (polls);
   g_free (nocomma);
 
   return TRUE;
@@ -191,6 +226,7 @@
 error:
   snd_mixer_close (mixer->mixer_handle);
   mixer->mixer_handle = NULL;
+  g_free (polls);
   g_free (nocomma);
   return FALSE;
 }
@@ -199,10 +235,20 @@
 gst_alsa_mixer_close (GstAlsaMixer * mixer)
 {
   GstAlsa *alsa = GST_ALSA (mixer);
+  gint i;
 
   if (mixer->mixer_handle == NULL)
     return;
 
+  if (mixer->source_ids) {
+    for (i = 0; i < mixer->source_id_count; i++) {
+      g_source_remove (mixer->source_ids[i]);
+    }
+    g_free(mixer->source_ids);
+    mixer->source_ids = NULL;
+    mixer->source_id_count = 0;
+  }
+
   if (alsa->cardname) {
     g_free (alsa->cardname);
     alsa->cardname = NULL;
@@ -281,7 +327,7 @@
       while (snd_mixer_selem_has_capture_channel (element, channels))
         channels++;
       track = gst_alsa_mixer_track_new (element, i, channels,
-          flags, GST_ALSA_MIXER_TRACK_CAPTURE);
+          flags, GST_ALSA_MIXER_TRACK_CAPTURE, GST_MIXER (mixer));
       mixer->tracklist = g_list_append (mixer->tracklist, track);
       got_it = TRUE;
     }
@@ -294,13 +340,13 @@
         flags |= GST_MIXER_TRACK_MASTER;
       }
       track = gst_alsa_mixer_track_new (element, i, channels,
-          flags, GST_ALSA_MIXER_TRACK_PLAYBACK);
+          flags, GST_ALSA_MIXER_TRACK_PLAYBACK, GST_MIXER (mixer));
       mixer->tracklist = g_list_append (mixer->tracklist, track);
       got_it = TRUE;
     }
 
     if (snd_mixer_selem_is_enumerated (element)) {
-      opts = gst_alsa_mixer_options_new (element, i);
+      opts = gst_alsa_mixer_options_new (element, i, GST_MIXER (mixer));
       mixer->tracklist = g_list_append (mixer->tracklist, opts);
       got_it = TRUE;
     }
@@ -310,7 +356,7 @@
           snd_mixer_selem_has_playback_switch (element)) {
         /* simple mute switch */
         track = gst_alsa_mixer_track_new (element, i, 0,
-            flags, GST_ALSA_MIXER_TRACK_PLAYBACK);
+            flags, GST_ALSA_MIXER_TRACK_PLAYBACK, GST_MIXER (mixer));
         mixer->tracklist = g_list_append (mixer->tracklist, track);
       }
     }
@@ -329,6 +375,16 @@
   mixer->tracklist = NULL;
 }
 
+static gboolean
+gst_alsa_mixer_handle_events (GIOChannel *source, GIOCondition condition, gpointer data)
+{
+  GstAlsaMixer *mixer = GST_ALSA_MIXER (data);
+  
+  snd_mixer_handle_events (mixer->mixer_handle);
+
+  return TRUE;
+}
+
 /*** GSTREAMER FUNCTIONS ******************************************************/
 
 static GstElementStateReturn
@@ -507,6 +563,7 @@
   if (idx == -1)
     return;
 
+  alsa_opts->idx = idx;
   snd_mixer_selem_set_enum_item (alsa_opts->element, 0, idx);
 }
 
Index: ext/alsa/gstalsamixer.h
===================================================================
--- ext/alsa/gstalsamixer.h	(revision 9)
+++ ext/alsa/gstalsamixer.h	(revision 10)
@@ -39,6 +39,9 @@
   GstAlsa	parent;
   GList *	tracklist;	/* list of available tracks */
   snd_mixer_t *	mixer_handle;
+
+  guint         source_id_count;
+  guint        *source_ids;
 };
 
 struct _GstAlsaMixerClass {
Index: ext/alsa/gstalsamixeroptions.c
===================================================================
--- ext/alsa/gstalsamixeroptions.c	(revision 9)
+++ ext/alsa/gstalsamixeroptions.c	(revision 10)
@@ -26,7 +26,11 @@
 static void gst_alsa_mixer_options_init (GstAlsaMixerOptions * alsa_opts);
 static void gst_alsa_mixer_options_class_init (gpointer g_class,
     gpointer class_data);
+static void gst_alsa_mixer_options_dispose (GObject * object);
 
+static int  gst_alsa_mixer_options_callback (snd_mixer_elem_t * element,
+    unsigned int mask);
+
 static GstMixerOptionsClass *parent_class = NULL;
 
 GType
@@ -57,9 +61,13 @@
 
 static void
 gst_alsa_mixer_options_class_init (gpointer g_class, gpointer class_data)
-{
+{ 
+  GObjectClass *object_klass = (GObjectClass *) g_class;
+
   if (parent_class == NULL)
     parent_class = g_type_class_ref (GST_TYPE_MIXER_TRACK);
+
+  object_klass->dispose = gst_alsa_mixer_options_dispose;
 }
 
 static void
@@ -68,12 +76,13 @@
 }
 
 GstMixerOptions *
-gst_alsa_mixer_options_new (snd_mixer_elem_t * element, gint track_num)
+gst_alsa_mixer_options_new (snd_mixer_elem_t * element,
+    gint track_num, GstMixer * mixer)
 {
   GstMixerOptions *opts = g_object_new (GST_ALSA_MIXER_OPTIONS_TYPE, NULL);
   GstAlsaMixerOptions *alsa_opts = (GstAlsaMixerOptions *) opts;
   GstMixerTrack *track = (GstMixerTrack *) opts;
-  gint num, i;
+  gint num, i, idx;
   gchar str[256];
 
   /* set basic information */
@@ -82,6 +91,7 @@
   track->flags = 0;
   alsa_opts->element = element;
   alsa_opts->track_num = track_num;
+  alsa_opts->mixer = mixer;
 
   /* get enumerations for switch/options object */
   num = snd_mixer_selem_get_enum_items (element);
@@ -94,5 +104,49 @@
     opts->values = g_list_append (opts->values, g_strdup (str));
   }
 
+  snd_mixer_selem_get_enum_item (alsa_opts->element, 0, &idx);
+  alsa_opts->idx = idx;
+
+  /* set callback information */
+  snd_mixer_elem_set_callback_private (element, alsa_opts);
+  snd_mixer_elem_set_callback (element, gst_alsa_mixer_options_callback);
+
   return opts;
 }
+
+static void
+gst_alsa_mixer_options_dispose (GObject * object)
+{
+  GstAlsaMixerOptions *alsa_opts = GST_ALSA_MIXER_OPTIONS (object);
+
+  snd_mixer_elem_set_callback (alsa_opts->element, NULL);
+  snd_mixer_elem_set_callback_private (alsa_opts->element, NULL);
+
+  if (G_OBJECT_CLASS(parent_class)->dispose) {
+    G_OBJECT_CLASS(parent_class)->dispose (object);
+  }
+}
+
+static int
+gst_alsa_mixer_options_callback (snd_mixer_elem_t * element,
+    unsigned int mask)
+{
+  gpointer data = snd_mixer_elem_get_callback_private (element);
+  GstAlsaMixerOptions *alsa_opts;
+  GstMixerOptions *opts;
+  gint idx = -1;
+
+  g_return_val_if_fail (GST_IS_ALSA_MIXER_OPTIONS (data), -1);
+
+  alsa_opts = (GstAlsaMixerOptions *) data;
+  opts = (GstMixerOptions *) data;
+
+  snd_mixer_selem_get_enum_item (alsa_opts->element, 0, &idx);
+  if (idx != alsa_opts->idx) {
+    alsa_opts->idx = idx;
+    gst_mixer_option_changed (alsa_opts->mixer, opts, g_list_nth_data (opts->values, idx));
+  }
+
+  return 0;
+}
+
Index: ext/alsa/gstalsamixeroptions.h
===================================================================
--- ext/alsa/gstalsamixeroptions.h	(revision 9)
+++ ext/alsa/gstalsamixeroptions.h	(revision 10)
@@ -21,6 +21,7 @@
 
 #include "gstalsa.h"
 #include <gst/mixer/mixeroptions.h>
+#include <gst/mixer/mixer.h>
 
 G_BEGIN_DECLS
 
@@ -38,6 +39,8 @@
   GstMixerOptions	 parent;
   snd_mixer_elem_t	*element; /* the ALSA mixer element for this track */
   gint			track_num;
+  gint			idx;
+  GstMixer		*mixer;
 };
 
 struct _GstAlsaMixerOptionsClass {
@@ -46,7 +49,8 @@
 
 GType		gst_alsa_mixer_options_get_type	(void);
 GstMixerOptions *gst_alsa_mixer_options_new	(snd_mixer_elem_t *	element,
-						 gint			track_num);
+						 gint			track_num,
+						 GstMixer *             mixer);
 
 G_END_DECLS
 
Index: ext/alsa/gstalsamixertrack.c
===================================================================
--- ext/alsa/gstalsamixertrack.c	(revision 9)
+++ ext/alsa/gstalsamixertrack.c	(revision 10)
@@ -26,7 +26,12 @@
 static void gst_alsa_mixer_track_init (GstAlsaMixerTrack * alsa_track);
 static void gst_alsa_mixer_track_class_init (gpointer g_class,
     gpointer class_data);
+static void gst_alsa_mixer_track_dispose (GObject * object);
 
+static int  gst_alsa_mixer_track_callback (snd_mixer_elem_t * element,
+    unsigned int mask);
+
+
 static GstMixerTrackClass *parent_class = NULL;
 
 GType
@@ -58,8 +63,12 @@
 static void
 gst_alsa_mixer_track_class_init (gpointer g_class, gpointer class_data)
 {
+  GObjectClass *object_klass = (GObjectClass *) g_class;
+  
   if (parent_class == NULL)
     parent_class = g_type_class_ref (GST_TYPE_MIXER_TRACK);
+
+  object_klass->dispose = gst_alsa_mixer_track_dispose;
 }
 
 static void
@@ -69,7 +78,7 @@
 
 GstMixerTrack *
 gst_alsa_mixer_track_new (snd_mixer_elem_t * element,
-    gint track_num, gint channels, gint flags, gint alsa_flags)
+    gint track_num, gint channels, gint flags, gint alsa_flags, GstMixer * mixer)
 {
   gint i;
   long min = 0, max = 0;
@@ -84,6 +93,7 @@
   alsa_track->element = element;
   alsa_track->alsa_flags = alsa_flags;
   alsa_track->track_num = track_num;
+  alsa_track->mixer = mixer;
 
   /* set volume information */
   if (channels) {
@@ -123,5 +133,103 @@
       track->flags |= GST_MIXER_TRACK_RECORD;
   }
 
+  /* set callback information */
+  snd_mixer_elem_set_callback_private (element, alsa_track);
+  snd_mixer_elem_set_callback (element, gst_alsa_mixer_track_callback);
+
   return track;
 }
+
+static void
+gst_alsa_mixer_track_dispose (GObject * object)
+{
+  GstAlsaMixerTrack *alsa_track = GST_ALSA_MIXER_TRACK (object);
+
+  snd_mixer_elem_set_callback (alsa_track->element, NULL);
+  snd_mixer_elem_set_callback_private (alsa_track->element, NULL);
+
+  if (G_OBJECT_CLASS(parent_class)->dispose) {
+    G_OBJECT_CLASS(parent_class)->dispose (object);
+  }
+}
+
+static int
+gst_alsa_mixer_track_callback (snd_mixer_elem_t * element,
+    unsigned int mask)
+{
+  gpointer data = snd_mixer_elem_get_callback_private (element);
+  GstAlsaMixerTrack *alsa_track;
+  GstMixerTrack *track;
+  gint i;
+  gboolean volume_changed = FALSE, volume_not_mute = FALSE;
+
+  g_return_val_if_fail (GST_IS_ALSA_MIXER_TRACK (data), -1);
+
+  alsa_track = (GstAlsaMixerTrack *) data;
+  track = (GstMixerTrack *) data;
+
+  for (i = 0; i < track->num_channels; i++) {
+    long volume = 0;
+
+    if (alsa_track->alsa_flags & GST_ALSA_MIXER_TRACK_PLAYBACK) {
+      snd_mixer_selem_get_playback_volume (element, i, &volume);
+    } else if (alsa_track->alsa_flags & GST_ALSA_MIXER_TRACK_CAPTURE) {
+      snd_mixer_selem_get_capture_volume (element, i, &volume);
+    }
+
+    if (alsa_track->volumes[i] != (gint) volume) {
+      volume_changed = TRUE;
+    } else if (volume != 0) {
+      volume_not_mute = TRUE;
+    }
+  }
+
+  if (volume_changed && (snd_mixer_selem_has_playback_switch (alsa_track->element) ||
+			 ((track->flags & GST_MIXER_TRACK_MUTE) && !volume_not_mute))) {
+    for (i = 0; i < track->num_channels; i++) {
+      long volume = 0;
+
+      if (alsa_track->alsa_flags & GST_ALSA_MIXER_TRACK_PLAYBACK) {
+        snd_mixer_selem_get_playback_volume (element, i, &volume);
+      } else if (alsa_track->alsa_flags & GST_ALSA_MIXER_TRACK_CAPTURE) {
+        snd_mixer_selem_get_capture_volume (element, i, &volume);
+      }
+
+      alsa_track->volumes[i] = (gint) volume;
+    }
+    gst_mixer_volume_changed (alsa_track->mixer, track, alsa_track->volumes);
+  }
+
+  if (snd_mixer_selem_has_playback_switch (alsa_track->element)) {
+    int val = 1;
+
+    snd_mixer_selem_get_playback_switch (element, 0, &val);
+    if ((track->flags & GST_MIXER_TRACK_MUTE) ^ !val) {
+      if (val) {
+        track->flags &= ~GST_MIXER_TRACK_MUTE;
+      } else {
+        track->flags |= GST_MIXER_TRACK_MUTE;
+      }
+      gst_mixer_mute_toggled (alsa_track->mixer, track, val ? FALSE : TRUE);
+    }
+  } else if ((track->flags & GST_MIXER_TRACK_MUTE) && volume_not_mute) {
+    track->flags &= ~GST_MIXER_TRACK_MUTE;
+    gst_mixer_mute_toggled (alsa_track->mixer, track, FALSE);
+  }
+
+  if (track->flags & GST_MIXER_TRACK_INPUT) {
+    int record = 0;
+
+    snd_mixer_selem_get_capture_switch (element, 0, &record);
+    if ((track->flags & GST_MIXER_TRACK_RECORD) ^ record) {
+      if (record) {
+        track->flags |= GST_MIXER_TRACK_RECORD;
+      } else {
+        track->flags &= ~GST_MIXER_TRACK_RECORD;
+      }
+    }
+    gst_mixer_record_toggled (alsa_track->mixer, track, record ? TRUE : FALSE);
+  }
+
+  return 0;
+}
Index: ext/alsa/gstalsamixertrack.h
===================================================================
--- ext/alsa/gstalsamixertrack.h	(revision 9)
+++ ext/alsa/gstalsamixertrack.h	(revision 10)
@@ -21,6 +21,7 @@
 
 #include "gstalsa.h"
 #include <gst/mixer/mixertrack.h>
+#include <gst/mixer/mixer.h>
 
 G_BEGIN_DECLS
 
@@ -43,6 +44,7 @@
   gint			track_num;
   gint			alsa_flags;
   gint			volumes[GST_ALSA_MAX_CHANNELS];
+  GstMixer		*mixer;
 };
 
 struct _GstAlsaMixerTrackClass {
@@ -54,7 +56,8 @@
 						 gint			track_num,
 						 gint			channels,
 						 gint			flags,
-						 gint			alsa_flags);
+						 gint			alsa_flags,
+						 GstMixer *		mixer);
 
 G_END_DECLS
 
