Index: docs/libs/gst-plugins-base-libs-sections.txt
===================================================================
RCS file: /cvs/gstreamer/gst-plugins-base/docs/libs/gst-plugins-base-libs-sections.txt,v
retrieving revision 1.33
diff -u -3 -r1.33 gst-plugins-base-libs-sections.txt
--- docs/libs/gst-plugins-base-libs-sections.txt	6 Jul 2007 18:19:39 -0000	1.33
+++ docs/libs/gst-plugins-base-libs-sections.txt	20 Jul 2007 15:52:58 -0000
@@ -288,6 +288,8 @@
 <INCLUDE>gst/interfaces/mixer.h</INCLUDE>
 GstMixer
 GstMixerType
+GstMixerFlags
+GstMixerMessageType
 
 gst_mixer_list_tracks
 gst_mixer_get_volume
@@ -303,6 +305,14 @@
 gst_mixer_option_changed
 gst_mixer_get_option
 
+gst_mixer_get_mixer_flags
+
+gst_mixer_message_get_type
+gst_mixer_message_parse_mute_toggled
+gst_mixer_message_parse_option_changed
+gst_mixer_message_parse_record_toggled
+gst_mixer_message_parse_volume_changed
+
 <SUBSECTION Standard>
 GstMixerClass
 GST_TYPE_MIXER
@@ -315,6 +325,8 @@
 GST_IS_MIXER_CLASS
 gst_mixer_get_type
 gst_mixer_type_get_type
+gst_mixer_flags_get_type
+gst_mixer_message_type_get_type
 </SECTION>
 
 <SECTION>Index: ext/alsa/gstalsamixer.c
===================================================================
RCS file: /cvs/gstreamer/gst-plugins-base/ext/alsa/gstalsamixer.c,v
retrieving revision 1.37
diff -u -3 -r1.37 gstalsamixer.c
--- ext/alsa/gstalsamixer.c	25 May 2007 10:07:25 -0000	1.37
+++ ext/alsa/gstalsamixer.c	20 Jul 2007 15:53:05 -0000
@@ -42,6 +42,12 @@
 
 #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 int gst_alsa_mixer_handle_callback (snd_mixer_t * handle, unsigned int mask,
+    snd_mixer_elem_t * elem);
 
 /* First some utils, then the mixer implementation */
 static gboolean
@@ -74,6 +80,8 @@
     goto error;
   }
 
+  snd_mixer_set_callback_private (mixer->handle, mixer);
+  snd_mixer_set_callback (mixer->handle, gst_alsa_mixer_handle_callback);
 
   /* now get the device name, any of this is not fatal */
   g_free (mixer->cardname);
@@ -170,16 +178,79 @@
 }
 
 static void
+gst_alsa_mixer_update (GstAlsaMixer *mixer, snd_mixer_elem_t * elem)
+{
+  GList *item;
+
+  g_return_if_fail (mixer != NULL);
+
+  g_static_rec_mutex_lock (mixer->rec_mutex);
+
+  for (item = mixer->tracklist; item != NULL; item = item->next) {
+    if (GST_IS_ALSA_MIXER_TRACK (item->data)) {
+      if (elem && (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 (elem && (GST_ALSA_MIXER_OPTIONS (item->data)->element != elem))
+        continue;
+
+      gst_alsa_mixer_update_option (mixer, GST_ALSA_MIXER_OPTIONS (item->data));
+    }
+  }
+
+  g_static_rec_mutex_unlock (mixer->rec_mutex);
+}
+
+static 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);
+
+  GST_LOG ("ALSA elem cb");
+
+  g_return_val_if_fail (mixer != NULL, 1);
+
+  gst_alsa_mixer_update (mixer, elem);
+
+  return 0;
+}
+
+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);
+
+  GST_LOG ("ALSA cb");
+
+  g_return_val_if_fail (mixer != NULL, 1);
+
+  /* Hopefully won't be call recursively and will handle pending elem events */
+  snd_mixer_handle_events (mixer->handle);
+
+  gst_alsa_mixer_update (mixer, elem);
+
+  return 0;
+}
+
+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);
@@ -287,8 +358,62 @@
 
     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);
 }
 
+static void
+task_monitor_alsa (gpointer data) 
+{
+  struct pollfd *pfds;
+  unsigned int nfds, rnfds;
+  unsigned short revents;
+  GstAlsaMixer *mixer = (GstAlsaMixer *)data;
+  
+  g_static_rec_mutex_lock (mixer->rec_mutex);
+
+  nfds = snd_mixer_poll_descriptors_count (mixer->handle);
+  if (nfds <= 0) {
+    GST_ERROR ("snd_mixer_poll_descriptors_count <= 0: %d", nfds);
+    /* FIXME: sleep ? stop monitoring ? */
+    return;
+  }
+
+  pfds = g_newa (struct pollfd, nfds + 1);
+  rnfds = snd_mixer_poll_descriptors (mixer->handle, pfds, nfds);
+  g_assert (rnfds <= nfds);
+
+  pfds[rnfds].fd = mixer->pfd[0];
+  pfds[rnfds].events = POLLIN | POLLPRI | POLLHUP | POLLERR;
+  pfds[rnfds].revents = 0;
+
+  g_static_rec_mutex_unlock (mixer->rec_mutex);
+
+  GST_LOG ("task loop");
+  poll (pfds, rnfds + 1, -1);
+
+  g_static_rec_mutex_lock (mixer->rec_mutex);
+
+  snd_mixer_poll_descriptors_revents (mixer->handle, pfds, nfds, &revents);
+  if (revents & POLLIN || revents & POLLPRI) {
+    GST_DEBUG ("Handling events");
+    snd_mixer_handle_events (mixer->handle);
+  }
+
+  g_static_rec_mutex_unlock (mixer->rec_mutex);
+}
 
 /* API */
 
@@ -301,12 +426,28 @@
 
   ret = g_new0 (GstAlsaMixer, 1);
 
+  if (pipe (ret->pfd) == -1)
+    goto error;
+
+  ret->rec_mutex = g_new (GStaticRecMutex, 1);
+  g_static_rec_mutex_init (ret->rec_mutex);
+
+  ret->task_mutex = g_new (GStaticRecMutex, 1);
+  g_static_rec_mutex_init (ret->task_mutex);
+
+  ret->task = gst_task_create (task_monitor_alsa, ret);
+  gst_task_set_lock (ret->task, ret->task_mutex);
+
   ret->device = g_strdup (device);
   ret->dir = dir;
 
   if (!gst_alsa_mixer_open (ret))
     goto error;
 
+  if (gst_task_start (ret->task) == FALSE) {
+    GST_WARNING ("Could not start alsamixer task");
+  }
+
   return ret;
 
   /* ERRORS */
@@ -322,6 +463,40 @@
 {
   g_return_if_fail (mixer != NULL);
 
+  if (mixer->task) {
+    if (write (mixer->pfd[1], "stop", 5) <= 0) {
+      GST_ERROR ("Cannot send ""stop"" to alsamixer task");
+      close (mixer->pfd[1]);
+      mixer->pfd[1] = -1;
+    } 
+
+    if (gst_task_join (mixer->task) == FALSE) {
+      GST_ERROR ("Cannot join alsamixer task");
+    } 
+
+    gst_object_unref (mixer->task);
+    mixer->task = NULL;
+  }
+
+  g_static_rec_mutex_free (mixer->task_mutex);
+  g_free (mixer->task_mutex);
+  mixer->task_mutex = NULL;
+
+  if (mixer->pfd[0] > 0) {
+    close (mixer->pfd[0]);
+    mixer->pfd[0] = -1;
+  }
+
+  if (mixer->pfd[1] > 0) {
+    close (mixer->pfd[1]);
+    mixer->pfd[1] = -1;
+  }
+
+  if (mixer->interface) {
+    g_object_unref (G_OBJECT (mixer->interface));
+    mixer->interface = NULL;
+  }
+
   if (mixer->device) {
     g_free (mixer->device);
     mixer->device = NULL;
@@ -343,6 +518,10 @@
     mixer->handle = NULL;
   }
 
+  g_static_rec_mutex_free (mixer->rec_mutex);
+  g_free (mixer->rec_mutex);
+  mixer->rec_mutex = NULL;
+
   g_free (mixer);
 }
 
@@ -356,16 +535,6 @@
   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 +544,7 @@
 
   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 +589,7 @@
 
   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 +630,7 @@
 
   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 +678,7 @@
 
   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 +705,7 @@
 
           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 +731,6 @@
 
   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 +752,95 @@
 
   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 */
 }
+
+GstMixerFlags
+gst_alsa_mixer_get_mixer_flags (GstAlsaMixer *mixer)
+{
+  g_return_val_if_fail (mixer != NULL, GST_MIXER_FLAG_NONE);
+
+  return GST_MIXER_FLAG_AUTO_NOTIFICATIONS;
+}
+
+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;
+  gboolean old_mute;
+  gboolean old_record;
+  gint i, n_channels;
+  gint *old_volumes;
+
+  GST_DEBUG ("Updating track %" GST_PTR_FORMAT, alsa_track);
+
+  if (mixer->interface == NULL) {
+    GST_WARNING ("Cannot send update notifications, no GstMixer * given");
+    return;
+  }
+
+  old_mute = !!(GST_MIXER_TRACK_HAS_FLAG (track, GST_MIXER_TRACK_MUTE));
+  old_record = !!(GST_MIXER_TRACK_HAS_FLAG (track, GST_MIXER_TRACK_RECORD));
+  old_volumes = g_new (gint, track->num_channels);
+  n_channels = track->num_channels;
+  memcpy (old_volumes, alsa_track->volumes, 
+      sizeof (gint) * track->num_channels);
+
+  gst_alsa_mixer_track_update (alsa_track);
+
+  if (old_record != 
+      !!(GST_MIXER_TRACK_HAS_FLAG (track, GST_MIXER_TRACK_RECORD))) {
+    gst_mixer_record_toggled (mixer->interface, track,
+        !!GST_MIXER_TRACK_HAS_FLAG (track, GST_MIXER_TRACK_RECORD));
+  }
+  if (old_mute != 
+      !!(GST_MIXER_TRACK_HAS_FLAG (track, GST_MIXER_TRACK_MUTE))) {
+    gst_mixer_mute_toggled (mixer->interface, track,
+        !!GST_MIXER_TRACK_HAS_FLAG (track, GST_MIXER_TRACK_MUTE));
+  }
+
+  n_channels = MIN (n_channels, track->num_channels);
+  for (i = 0; i < n_channels; i++) {
+    if (old_volumes[i] != alsa_track->volumes[i]) {
+      gst_mixer_volume_changed (mixer->interface, track, alsa_track->volumes);
+      break;
+    }
+  }
+  g_free (old_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));
+}Index: ext/alsa/gstalsamixer.h
===================================================================
RCS file: /cvs/gstreamer/gst-plugins-base/ext/alsa/gstalsamixer.h,v
retrieving revision 1.13
diff -u -3 -r1.13 gstalsamixer.h
--- ext/alsa/gstalsamixer.h	25 May 2007 10:07:25 -0000	1.13
+++ ext/alsa/gstalsamixer.h	20 Jul 2007 15:53:12 -0000
@@ -52,6 +52,13 @@
 
   snd_mixer_t *         handle;
 
+  GstTask *		task;
+  GStaticRecMutex *	task_mutex;
+  GStaticRecMutex *	rec_mutex;
+
+  int			pfd[2];
+
+  GstMixer *		interface;
   gchar *               device;
   gchar *               cardname;
 
@@ -81,7 +88,9 @@
                                                  gchar * value);
 const gchar*    gst_alsa_mixer_get_option       (GstAlsaMixer * mixer,
                                                  GstMixerOptions * opts);
-
+void		_gst_alsa_mixer_set_interface   (GstAlsaMixer * mixer,
+						 GstMixer * interface);
+GstMixerFlags   gst_alsa_mixer_get_mixer_flags  (GstAlsaMixer *mixer);
 
 #define GST_IMPLEMENT_ALSA_MIXER_METHODS(Type, interface_as_function)           \
 static gboolean                                                                 \
@@ -174,6 +183,17 @@
   return gst_alsa_mixer_get_option (this->mixer, opts);                         \
 }                                                                               \
                                                                                 \
+static GstMixerFlags                                                            \
+interface_as_function ## _get_mixer_flags (GstMixer * mixer)                    \
+{                                                                               \
+  Type *this = (Type*) mixer;                                                   \
+                                                                                \
+  g_return_val_if_fail (this != NULL, GST_MIXER_FLAG_NONE);                     \
+  g_return_val_if_fail (this->mixer != NULL, GST_MIXER_FLAG_NONE);              \
+                                                                                \
+  return gst_alsa_mixer_get_mixer_flags (this->mixer);                          \
+}                                                                               \
+                                                                                \
 static void                                                                     \
 interface_as_function ## _interface_init (GstMixerClass * klass)                \
 {                                                                               \
@@ -187,6 +207,7 @@
   klass->set_record = interface_as_function ## _set_record;                     \
   klass->set_option = interface_as_function ## _set_option;                     \
   klass->get_option = interface_as_function ## _get_option;                     \
+  klass->get_mixer_flags = interface_as_function ## _get_mixer_flags;           \
 }
 
 Index: ext/alsa/gstalsamixerelement.c
===================================================================
RCS file: /cvs/gstreamer/gst-plugins-base/ext/alsa/gstalsamixerelement.c,v
retrieving revision 1.12
diff -u -3 -r1.12 gstalsamixerelement.c
--- ext/alsa/gstalsamixerelement.c	25 May 2007 10:07:25 -0000	1.12
+++ ext/alsa/gstalsamixerelement.c	20 Jul 2007 15:53:16 -0000
@@ -44,22 +44,22 @@
 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 * this,
     GType interface_type)
 {
   if (interface_type == GST_TYPE_MIXER) {
@@ -214,6 +214,7 @@
         this->mixer = gst_alsa_mixer_new (this->device, GST_ALSA_MIXER_ALL);
         if (!this->mixer)
           goto open_failed;
+        _gst_alsa_mixer_set_interface (this->mixer, GST_MIXER (element));
       }
       break;
     default:Index: ext/alsa/gstalsamixertrack.c
===================================================================
RCS file: /cvs/gstreamer/gst-plugins-base/ext/alsa/gstalsamixertrack.c,v
retrieving revision 1.16
diff -u -3 -r1.16 gstalsamixertrack.c
--- ext/alsa/gstalsamixertrack.c	25 May 2007 10:07:25 -0000	1.16
+++ ext/alsa/gstalsamixertrack.c	20 Jul 2007 15:53:21 -0000
@@ -47,6 +47,7 @@
       sizeof (GstAlsaMixerTrack),
       0,
       (GInstanceInitFunc) gst_alsa_mixer_track_init,
+      0
     };
 
     track_type =
@@ -239,7 +240,27 @@
   gint i;
   gint audible = !(track->flags & GST_MIXER_TRACK_MUTE);
 
-  /* Any updates in flags? */
+  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;
 Index: gst-libs/gst/interfaces/mixer.c
===================================================================
RCS file: /cvs/gstreamer/gst-plugins-base/gst-libs/gst/interfaces/mixer.c,v
retrieving revision 1.22
diff -u -3 -r1.22 mixer.c
--- gst-libs/gst/interfaces/mixer.c	25 May 2007 10:07:26 -0000	1.22
+++ gst-libs/gst/interfaces/mixer.c	20 Jul 2007 15:53:25 -0000
@@ -26,11 +26,14 @@
 #include "mixer.h"
 #include "interfaces-marshal.h"
 
+#define GST_MIXER_MESSAGE_NAME "gst-mixer-message"
+
 /**
  * SECTION:gstmixer
  * @short_description: Interface for elements that provide mixer operations
  */
 
+#ifndef GST_DISABLE_DEPRECATED
 enum
 {
   SIGNAL_MUTE_TOGGLED,
@@ -40,10 +43,12 @@
   LAST_SIGNAL
 };
 
-static void gst_mixer_class_init (GstMixerClass * klass);
-
 static guint gst_mixer_signals[LAST_SIGNAL] = { 0 };
 
+#endif
+
+static void gst_mixer_class_init (GstMixerClass * klass);
+
 GType
 gst_mixer_get_type (void)
 {
@@ -74,8 +79,10 @@
 static void
 gst_mixer_class_init (GstMixerClass * klass)
 {
+#ifndef GST_DISABLE_DEPRECATED
   static gboolean initialized = FALSE;
 
+  /* signals (deprecated) */
   if (!initialized) {
     gst_mixer_signals[SIGNAL_RECORD_TOGGLED] =
         g_signal_new ("record-toggled",
@@ -108,6 +115,7 @@
 
     initialized = TRUE;
   }
+#endif
 
   klass->mixer_type = GST_MIXER_SOFTWARE;
 
@@ -313,53 +321,405 @@
   return NULL;
 }
 
+/**
+ * gst_mixer_get_mixer_flags:
+ * @mixer: The #GstMixer implementation
+ *
+ * Get the set of supported flags for this mixer implementation.
+ *
+ * Returns: A set of or-ed GstMixerFlags for supported features.
+ */
+GstMixerFlags
+gst_mixer_get_mixer_flags (GstMixer *mixer)
+{
+  GstMixerClass *klass;
+  g_return_val_if_fail (mixer != NULL, FALSE);
+  klass = GST_MIXER_GET_CLASS (mixer);
+
+  if (klass->get_mixer_flags) {
+    return klass->get_mixer_flags (mixer);
+  }
+  return GST_MIXER_FLAG_NONE;
+}
+
+/**
+ * gst_mixer_mute_toggled:
+ *
+ * @mixer: the #GstMixer (a #GstElement) that owns the track
+ * @track: the GstMixerTrack that has change mute state.
+ * @mute: the new state of the mute flag on the track
+ *
+ * This function is called by the mixer implementation to produce
+ * a notification message on the bus indicating that the given track
+ * has changed mute state.
+ *
+ * This function only works for GstElements that are implementing the
+ * GstMixer interface, and the element needs to have been provided a bus.
+ */
 void
 gst_mixer_mute_toggled (GstMixer * mixer, GstMixerTrack * track, gboolean mute)
 {
+  GstStructure *s;
+  GstMessage *m;
+
   g_return_if_fail (mixer != NULL);
+  g_return_if_fail (GST_IS_ELEMENT (mixer));
   g_return_if_fail (track != NULL);
 
-  g_signal_emit (G_OBJECT (mixer),
-      gst_mixer_signals[SIGNAL_MUTE_TOGGLED], 0, track, mute);
-
-  g_signal_emit_by_name (G_OBJECT (track), "mute_toggled", mute);
+  s = gst_structure_new (GST_MIXER_MESSAGE_NAME,
+      "type", G_TYPE_STRING, "mute-toggled",
+      "track", GST_TYPE_MIXER_TRACK, track, 
+      "mute", G_TYPE_BOOLEAN, mute, NULL);
+
+  m = gst_message_new_element (GST_OBJECT (mixer), s);
+  if (gst_element_post_message (GST_ELEMENT (mixer), m) == FALSE) {
+    GST_WARNING ("This element has no bus, therefore no message sent!");
+  }
 }
 
+/**
+ * gst_mixer_record_toggled:
+ *
+ * @mixer: the #GstMixer (a #GstElement) that owns the track
+ * @track: the GstMixerTrack that has changed recording state.
+ * @record: the new state of the record flag on the track
+ *
+ * This function is called by the mixer implementation to produce
+ * a notification message on the bus indicating that the given track
+ * has changed recording state.
+ *
+ * This function only works for GstElements that are implementing the
+ * GstMixer interface, and the element needs to have been provided a bus.
+ */
 void
 gst_mixer_record_toggled (GstMixer * mixer,
     GstMixerTrack * track, gboolean record)
 {
+  GstStructure *s;
+  GstMessage *m;
+
   g_return_if_fail (mixer != NULL);
+  g_return_if_fail (GST_IS_ELEMENT (mixer));
   g_return_if_fail (track != NULL);
 
-  g_signal_emit (G_OBJECT (mixer),
-      gst_mixer_signals[SIGNAL_RECORD_TOGGLED], 0, track, record);
-
-  g_signal_emit_by_name (G_OBJECT (track), "record_toggled", record);
+  s = gst_structure_new (GST_MIXER_MESSAGE_NAME,
+      "type", G_TYPE_STRING, "record-toggled",
+      "track", GST_TYPE_MIXER_TRACK, track, 
+      "record", G_TYPE_BOOLEAN, record, NULL);
+
+  m = gst_message_new_element (GST_OBJECT (mixer), s);
+  if (gst_element_post_message (GST_ELEMENT (mixer), m) == FALSE) {
+    GST_WARNING ("This element has no bus, therefore no message sent!");
+  }
 }
 
+/**
+ * gst_mixer_volume_changed:
+ *
+ * @mixer: the #GstMixer (a #GstElement) that owns the track
+ * @track: the GstMixerTrack that has changed.
+ * @volumes: Array of volume values, one per channel on the mixer track.
+ *
+ * This function is called by the mixer implementation to produce
+ * a notification message on the bus indicating that the volume(s) for the
+ * given track have changed.
+ *
+ * This function only works for GstElements that are implementing the
+ * GstMixer interface, and the element needs to have been provided a bus.
+ */
 void
 gst_mixer_volume_changed (GstMixer * mixer,
     GstMixerTrack * track, gint * volumes)
 {
+  GstStructure *s;
+  GstMessage *m;
+  GValue l = { 0, };
+  GValue v = { 0, };
+  gint i;
+
   g_return_if_fail (mixer != NULL);
+  g_return_if_fail (GST_IS_ELEMENT (mixer));
   g_return_if_fail (track != NULL);
 
-  g_signal_emit (G_OBJECT (mixer),
-      gst_mixer_signals[SIGNAL_VOLUME_CHANGED], 0, track, volumes);
+  s = gst_structure_new (GST_MIXER_MESSAGE_NAME,
+      "type", G_TYPE_STRING, "volume-changed",
+      "track", GST_TYPE_MIXER_TRACK, track, NULL);
+
+  g_value_init (&l, GST_TYPE_ARRAY);
+
+  g_value_init (&v, G_TYPE_INT);
+
+  /* FIXME 0.11: pass track->num_channels to the function */
+  for (i = 0; i < track->num_channels; ++i) {
+    g_value_set_int (&v, volumes[i]);
+    gst_value_array_append_value (&l, &v);
+  }
+  g_value_unset (&v);
 
-  g_signal_emit_by_name (G_OBJECT (track), "volume_changed", volumes);
+  gst_structure_set_value (s, "volumes", &l);
+  g_value_unset (&l);
+
+  m = gst_message_new_element (GST_OBJECT (mixer), s);
+  if (gst_element_post_message (GST_ELEMENT (mixer), m) == FALSE) {
+    GST_WARNING ("This element has no bus, therefore no message sent!");
+  }
 }
 
+/**
+ * gst_mixer_option_changed:
+ *
+ * @mixer: the #GstMixer (a #GstElement) that owns the options 
+ * @opts: the GstMixerOptions that has changed value.
+ * @value: the new value of the GstMixerOptions.
+ *
+ * This function is called by the mixer implementation to produce
+ * a notification message on the bus indicating that the given options
+ * object has changed state. 
+ *
+ * This function only works for GstElements that are implementing the
+ * GstMixer interface, and the element needs to have been provided a bus.
+ */
 void
 gst_mixer_option_changed (GstMixer * mixer,
     GstMixerOptions * opts, gchar * value)
 {
+  GstStructure *s;
+  GstMessage *m;
+
   g_return_if_fail (mixer != NULL);
+  g_return_if_fail (GST_IS_ELEMENT (mixer));
   g_return_if_fail (opts != NULL);
 
-  g_signal_emit (G_OBJECT (mixer),
-      gst_mixer_signals[SIGNAL_OPTION_CHANGED], 0, opts, value);
+  s = gst_structure_new (GST_MIXER_MESSAGE_NAME,
+      "type", G_TYPE_STRING, "option-changed",
+      "options", GST_TYPE_MIXER_OPTIONS, opts, 
+      "value", G_TYPE_STRING, value, NULL);
+
+  m = gst_message_new_element (GST_OBJECT (mixer), s);
+  if (gst_element_post_message (GST_ELEMENT (mixer), m) == FALSE) {
+    GST_WARNING ("This element has no bus, therefore no message sent!");
+  }
+}
+
+static gboolean
+gst_mixer_message_is_mixer_message (GstMessage * message)
+{
+  const GstStructure *s;
+
+  if (message == NULL)
+    return FALSE;
+  if (GST_MESSAGE_TYPE (message) != GST_MESSAGE_ELEMENT)
+    return FALSE;
+
+  s = gst_message_get_structure (message);
+  return gst_structure_has_name (s, GST_MIXER_MESSAGE_NAME);
+}
+
+/**
+ * gst_mixer_message_get_type:
+ * @message: A GstMessage to inspect.
+ *
+ * Check a bus message to see if it is a GstMixer notification
+ * message and return the GstMixerMessageType identifying which
+ * type of notification it is.
+ *
+ * Returns: The type of the GstMixerMessage, or GST_MIXER_MESSAGE_NONE
+ * if the message is not a GstMixer notification.
+ *
+ * Since: 0.10.14
+ */
+GstMixerMessageType
+gst_mixer_message_get_type (GstMessage * message)
+{
+  const GstStructure *s;
+  const gchar *m_type;
+
+  if (!gst_mixer_message_is_mixer_message (message))
+    return GST_MIXER_MESSAGE_INVALID;
+
+  s = gst_message_get_structure (message);
+  m_type = gst_structure_get_string (s, "type");
+  g_return_val_if_fail (m_type != NULL, GST_MIXER_MESSAGE_INVALID);
+
+  if (g_str_equal (m_type, "mute-toggled"))
+    return GST_MIXER_MESSAGE_MUTE_TOGGLED;
+  else if (g_str_equal (m_type, "record-toggled"))
+    return GST_MIXER_MESSAGE_RECORD_TOGGLED;
+  else if (g_str_equal (m_type, "volume-changed"))
+    return GST_MIXER_MESSAGE_VOLUME_CHANGED;
+  else if (g_str_equal (m_type, "option-changed"))
+    return GST_MIXER_MESSAGE_OPTION_CHANGED;
+
+  return GST_MIXER_MESSAGE_INVALID;
+}
+
+/**
+ * gst_mixer_message_parse_mute_toggled:
+ * @message: A mute-toggled change notification message.
+ * @track: Pointer to hold a GstMixerTrack object, or NULL.
+ * @mute: A pointer to a gboolean variable, or NULL.
+ *
+ * Extracts the contents of a mute-toggled bus message. Reads
+ * the GstMixerTrack that has changed, and the new value of the mute
+ * flag.
+ *
+ * The GstMixerTrack remains valid until the message is freed.
+ *
+ * Since: 0.10.14
+ */
+void
+gst_mixer_message_parse_mute_toggled (GstMessage * message,
+    GstMixerTrack ** track, gboolean * mute)
+{
+  const GstStructure *s;
+  const gchar *m_type;
+
+  g_return_if_fail (gst_mixer_message_is_mixer_message (message));
+  s = gst_message_get_structure (message);
+
+  m_type = gst_structure_get_string (s, "type");
+  g_return_if_fail (m_type == NULL || g_str_equal (m_type, "mute-toggled"));
+
+  if (track) {
+    const GValue *v = gst_structure_get_value (s, "track");
+    g_return_if_fail (v != NULL);
+    *track = (GstMixerTrack *)g_value_get_object (v);
+    g_return_if_fail (GST_IS_MIXER_TRACK (*track));
+  }
+
+  if (mute)
+    g_return_if_fail (gst_structure_get_boolean (s, "mute", mute));
+}
+
+/**
+ * gst_mixer_message_parse_record_toggled:
+ * @message: A record-toggled change notification message.
+ * @track: Pointer to hold a GstMixerTrack object, or NULL.
+ * @record: A pointer to a gboolean variable, or NULL.
+ *
+ * Extracts the contents of a record-toggled bus message. Reads
+ * the GstMixerTrack that has changed, and the new value of the 
+ * recording flag.
+ *
+ * The GstMixerTrack remains valid until the message is freed.
+ *
+ * Since: 0.10.14
+ */
+void
+gst_mixer_message_parse_record_toggled (GstMessage * message,
+    GstMixerTrack ** track, gboolean * record)
+{
+  const GstStructure *s;
+  const gchar *m_type;
+
+  g_return_if_fail (gst_mixer_message_is_mixer_message (message));
+  s = gst_message_get_structure (message);
+
+  m_type = gst_structure_get_string (s, "type");
+  g_return_if_fail (m_type == NULL || g_str_equal (m_type, "record-toggled"));
+
+  if (track) {
+    const GValue *v = gst_structure_get_value (s, "track");
+    g_return_if_fail (v != NULL);
+    *track = (GstMixerTrack *)g_value_get_object (v);
+    g_return_if_fail (GST_IS_MIXER_TRACK (*track));
+  }
+
+  if (record)
+    g_return_if_fail (gst_structure_get_boolean (s, "record", record));
+}
+
+/**
+ * gst_mixer_message_parse_volume_changed:
+ * @message: A volume-changed change notification message.
+ * @track: Pointer to hold a GstMixerTrack object, or NULL.
+ * @volumes: A pointer to receive an array of gint values, or NULL.
+ * @num_channels: Result location to receive the number of channels, or NULL.
+ *
+ * Parses a volume-changed notification message and extracts the track object
+ * it refers to, as well as an array of volumes and the size of the volumes array.
+ *
+ * The track object remains valid until the message is freed.
+ *
+ * The caller must free the array returned in the volumes parameter using g_free
+ * when they are done with it.
+ *
+ * Since: 0.10.14
+ */
+void
+gst_mixer_message_parse_volume_changed (GstMessage * message,
+    GstMixerTrack ** track, gint ** volumes, gint * num_channels)
+{
+  const GstStructure *s;
+  const gchar *m_type;
+
+  g_return_if_fail (gst_mixer_message_is_mixer_message (message));
+  s = gst_message_get_structure (message);
+
+  m_type = gst_structure_get_string (s, "type");
+  g_return_if_fail (m_type == NULL || g_str_equal (m_type, "volume-changed"));
+
+  if (track) {
+    const GValue *v = gst_structure_get_value (s, "track");
+    g_return_if_fail (v != NULL);
+    *track = (GstMixerTrack *)g_value_get_object (v);
+    g_return_if_fail (GST_IS_MIXER_TRACK (*track));
+  }
+
+  if (volumes || num_channels) {
+    gint n_chans, i;
+    const GValue *v = gst_structure_get_value (s, "volumes");
+    g_return_if_fail (v != NULL);
+    g_return_if_fail (GST_VALUE_HOLDS_ARRAY (v));
+     
+    n_chans = gst_value_array_get_size (v);
+    if (num_channels) 
+      *num_channels = n_chans;
+
+    if (volumes) {
+      *volumes = g_new (gint, n_chans);
+      for (i = 0; i < n_chans; i++) {
+        const GValue *e = gst_value_array_get_value (v, i);
+        g_return_if_fail (e != NULL && G_VALUE_HOLDS_INT (e));
+        (*volumes)[i] = g_value_get_int (e);
+      }
+    }
+  }
+}
+
+/**
+ * gst_mixer_message_parse_option_changed:
+ * @message: A volume-changed change notification message.
+ * @options: Pointer to hold a GstMixerOptions object, or NULL.
+ * @value: Result location to receive the new options value, or NULL.
+ *
+ * Extracts the GstMixerOptions and new value from a option-changed bus notification
+ * message.
+ *
+ * The options and value returned remain valid until the message is freed.
+ *
+ * Since: 0.10.14
+ */
+void
+gst_mixer_message_parse_option_changed (GstMessage * message,
+    GstMixerOptions **options, const gchar **value)
+{
+  const GstStructure *s;
+  const gchar *m_type;
+
+  g_return_if_fail (gst_mixer_message_is_mixer_message (message));
+  s = gst_message_get_structure (message);
+
+  m_type = gst_structure_get_string (s, "type");
+  g_return_if_fail (m_type == NULL || g_str_equal (m_type, "option-changed"));
+ 
+  if (options) {
+    const GValue *v = gst_structure_get_value (s, "options");
+    g_return_if_fail (v != NULL);
+    *options = (GstMixerOptions *)g_value_get_object (v);
+    g_return_if_fail (GST_IS_MIXER_OPTIONS (*options));
+  }
 
-  g_signal_emit_by_name (G_OBJECT (opts), "value_changed", value);
+  if (value)
+    *value = gst_structure_get_string (s, "value");
 }Index: gst-libs/gst/interfaces/mixer.h
===================================================================
RCS file: /cvs/gstreamer/gst-plugins-base/gst-libs/gst/interfaces/mixer.h,v
retrieving revision 1.20
diff -u -3 -r1.20 mixer.h
--- gst-libs/gst/interfaces/mixer.h	25 May 2007 10:07:26 -0000	1.20
+++ gst-libs/gst/interfaces/mixer.h	20 Jul 2007 15:53:30 -0000
@@ -53,6 +53,39 @@
   GST_MIXER_SOFTWARE
 } GstMixerType;
 
+/**
+ * GstMixerMessageType:
+ * @GST_MIXER_MESSAGE_INVALID: Not a GstMixer message
+ * @GST_MIXER_MESSAGE_MUTE_TOGGLED: A mute-toggled GstMixer message
+ * @GST_MIXER_MESSAGE_RECORD_TOGGLED: A record-toggled GstMixer message
+ * @GST_MIXER_MESSAGE_VOLUME_CHANGED: A volume-changed GstMixer message
+ * @GST_MIXER_MESSAGE_OPTION_CHANGED: An option-changed GstMixer message
+ * 
+ * An enumeration for the type of a GstMixer message received on the bus
+ */
+typedef enum
+{
+  GST_MIXER_MESSAGE_INVALID,
+  GST_MIXER_MESSAGE_MUTE_TOGGLED,
+  GST_MIXER_MESSAGE_RECORD_TOGGLED,
+  GST_MIXER_MESSAGE_VOLUME_CHANGED,
+  GST_MIXER_MESSAGE_OPTION_CHANGED
+} GstMixerMessageType;
+
+/**
+ * GstMixerFlags:
+ * @GST_MIXER_FLAG_NONE: No flags
+ * @GST_MIXER_AUTO_NOTIFICATIONS: The mixer implementation automatically sends
+ *    notification messages.
+ * 
+ * Flags for supported features. Whether the element automatically sends 
+ * notifications on the bus is the only one for now. */
+typedef enum
+{
+  GST_MIXER_FLAG_NONE                = 0,
+  GST_MIXER_FLAG_AUTO_NOTIFICATIONS  = (1<<0)
+} GstMixerFlags;
+
 struct _GstMixerClass {
   GTypeInterface klass;
 
@@ -74,8 +107,8 @@
   void           (* set_record)    (GstMixer      *mixer,
                                     GstMixerTrack *track,
                                     gboolean       record);
-
-  /* signals */
+#ifndef GST_DISABLE_DEPRECATED
+  /* signals (deprecated) */
   void (* mute_toggled)   (GstMixer      *mixer,
                            GstMixerTrack *channel,
                            gboolean       mute);
@@ -85,6 +118,7 @@
   void (* volume_changed) (GstMixer      *mixer,
                            GstMixerTrack *channel,
                            gint          *volumes);
+#endif /* not GST_DISABLE_DEPRECATED */
 
   void          (* set_option)     (GstMixer      *mixer,
                                     GstMixerOptions *opts,
@@ -92,12 +126,16 @@
   const gchar * (* get_option)     (GstMixer      *mixer,
                                     GstMixerOptions *opts);
 
+#ifndef GST_DISABLE_DEPRECATED
   void (* option_changed) (GstMixer      *mixer,
                            GstMixerOptions *opts,
-                           gchar         *option);
+                           gchar   *option);
+#endif /* not GST_DISABLE_DEPRECATED */
+
+  GstMixerFlags (* get_mixer_flags) (GstMixer *mixer); 
 
   /*< private >*/
-  gpointer _gst_reserved[GST_PADDING];
+  gpointer _gst_reserved[GST_PADDING-1];
 };
 
 GType           gst_mixer_get_type      (void);
@@ -122,7 +160,7 @@
 const gchar *   gst_mixer_get_option     (GstMixer      *mixer,
                                           GstMixerOptions *opts);
 
-/* trigger signals */
+/* trigger bus messages */
 void            gst_mixer_mute_toggled   (GstMixer      *mixer,
                                           GstMixerTrack *track,
                                           gboolean       mute);
@@ -136,6 +174,24 @@
                                           GstMixerOptions *opts,
                                           gchar         *value);
 
+GstMixerFlags   gst_mixer_get_mixer_flags (GstMixer *mixer);
+
+/* Functions for recognising and parsing GstMixerMessages on the bus */
+GstMixerMessageType gst_mixer_message_get_type (GstMessage *message);
+void            gst_mixer_message_parse_mute_toggled (GstMessage *message,
+                                                      GstMixerTrack **track,
+                                                      gboolean *mute);
+void            gst_mixer_message_parse_record_toggled (GstMessage *message,
+                                                        GstMixerTrack **track,
+                                                        gboolean *record);
+void            gst_mixer_message_parse_volume_changed (GstMessage *message,
+                                                        GstMixerTrack **track,
+                                                        gint **volumes,
+                                                        gint *num_channels);
+void            gst_mixer_message_parse_option_changed (GstMessage *message,
+                                                        GstMixerOptions **options,
+                                                        const gchar **value);
+
 G_END_DECLS
 
 #endif /* __GST_MIXER_H__ */Index: gst-libs/gst/interfaces/mixeroptions.c
===================================================================
RCS file: /cvs/gstreamer/gst-plugins-base/gst-libs/gst/interfaces/mixeroptions.c,v
retrieving revision 1.4
diff -u -3 -r1.4 mixeroptions.c
--- gst-libs/gst/interfaces/mixeroptions.c	8 Apr 2006 21:02:50 -0000	1.4
+++ gst-libs/gst/interfaces/mixeroptions.c	20 Jul 2007 15:53:34 -0000
@@ -25,19 +25,21 @@
 
 #include "mixeroptions.h"
 
+#ifndef GST_DISABLE_DEPRECATED
 enum
 {
   /* FILL ME */
   SIGNAL_OPTION_CHANGED,
   LAST_SIGNAL
 };
+static guint signals[LAST_SIGNAL] = { 0 };
+#endif
 
 static void gst_mixer_options_class_init (GstMixerOptionsClass * klass);
 static void gst_mixer_options_init (GstMixerOptions * mixer);
 static void gst_mixer_options_dispose (GObject * object);
 
 static GObjectClass *parent_class = NULL;
-static guint signals[LAST_SIGNAL] = { 0 };
 
 GType
 gst_mixer_options_get_type (void)
@@ -72,13 +74,14 @@
   GObjectClass *object_klass = (GObjectClass *) klass;
 
   parent_class = g_type_class_peek_parent (klass);
-
+#ifndef GST_DISABLE_DEPRECATED
   signals[SIGNAL_OPTION_CHANGED] =
       g_signal_new ("option_changed", G_TYPE_FROM_CLASS (klass),
       G_SIGNAL_RUN_LAST,
       G_STRUCT_OFFSET (GstMixerOptionsClass, option_changed),
       NULL, NULL, g_cclosure_marshal_VOID__STRING,
       G_TYPE_NONE, 1, G_TYPE_STRING);
+#endif
 
   object_klass->dispose = gst_mixer_options_dispose;
 }Index: gst-libs/gst/interfaces/mixeroptions.h
===================================================================
RCS file: /cvs/gstreamer/gst-plugins-base/gst-libs/gst/interfaces/mixeroptions.h,v
retrieving revision 1.4
diff -u -3 -r1.4 mixeroptions.h
--- gst-libs/gst/interfaces/mixeroptions.h	6 Dec 2005 19:42:00 -0000	1.4
+++ gst-libs/gst/interfaces/mixeroptions.h	20 Jul 2007 15:53:39 -0000
@@ -57,9 +57,11 @@
 struct _GstMixerOptionsClass {
   GstMixerTrackClass parent;
 
+#ifndef GST_DISABLE_DEPRECATED
   /* signals */
   void (* option_changed) (GstMixerOptions *opts,
                            gchar           *value);
+#endif /* not GST_DISABLE_DEPRECATED */
 
   gpointer _gst_reserved[GST_PADDING];
 };Index: gst-libs/gst/interfaces/mixertrack.c
===================================================================
RCS file: /cvs/gstreamer/gst-plugins-base/gst-libs/gst/interfaces/mixertrack.c,v
retrieving revision 1.9
diff -u -3 -r1.9 mixertrack.c
--- gst-libs/gst/interfaces/mixertrack.c	7 Mar 2007 18:50:09 -0000	1.9
+++ gst-libs/gst/interfaces/mixertrack.c	20 Jul 2007 15:53:45 -0000
@@ -24,7 +24,7 @@
 #endif
 
 #include "mixertrack.h"
-
+#ifndef GST_DISABLE_DEPRECATED
 enum
 {
   /* FILL ME */
@@ -33,6 +33,8 @@
   SIGNAL_MUTE_TOGGLED,
   LAST_SIGNAL
 };
+static guint signals[LAST_SIGNAL] = { 0 };
+#endif
 
 enum
 {
@@ -55,7 +57,6 @@
     const GValue * value, GParamSpec * pspec);
 
 static GObjectClass *parent_class = NULL;
-static guint signals[LAST_SIGNAL] = { 0 };
 
 GType
 gst_mixer_track_get_type (void)
@@ -135,6 +136,7 @@
           "The number of channels contained within the track",
           0, G_MAXINT, 0, G_PARAM_READABLE));
 
+#ifndef GST_DISABLE_DEPRECATED
   signals[SIGNAL_RECORD_TOGGLED] =
       g_signal_new ("record_toggled", G_TYPE_FROM_CLASS (klass),
       G_SIGNAL_RUN_LAST,
@@ -156,6 +158,7 @@
           volume_changed),
       NULL, NULL, g_cclosure_marshal_VOID__POINTER,
       G_TYPE_NONE, 1, G_TYPE_POINTER);
+#endif
 
   object_klass->dispose = gst_mixer_track_dispose;
 }Index: gst-libs/gst/interfaces/mixertrack.h
===================================================================
RCS file: /cvs/gstreamer/gst-plugins-base/gst-libs/gst/interfaces/mixertrack.h,v
retrieving revision 1.11
diff -u -3 -r1.11 mixertrack.h
--- gst-libs/gst/interfaces/mixertrack.h	20 Nov 2006 12:20:39 -0000	1.11
+++ gst-libs/gst/interfaces/mixertrack.h	20 Jul 2007 15:53:50 -0000
@@ -88,13 +88,15 @@
 struct _GstMixerTrackClass {
   GObjectClass parent;
 
-  /* signals */
+#ifndef GST_DISABLE_DEPRECATED
+  /* signals (deprecated) */
   void (* mute_toggled)   (GstMixerTrack *channel,
                            gboolean       mute);
   void (* record_toggled) (GstMixerTrack *channel,
                            gboolean       record);
   void (* volume_changed) (GstMixerTrack *channel,
                            gint          *volumes);
+#endif /* not GST_DISABLE_DEPRECATED */
 
   gpointer _gst_reserved[GST_PADDING];
 };Index: tests/check/Makefile.am
===================================================================
RCS file: /cvs/gstreamer/gst-plugins-base/tests/check/Makefile.am,v
retrieving revision 1.74
diff -u -3 -r1.74 Makefile.am
--- tests/check/Makefile.am	27 Jun 2007 10:14:03 -0000	1.74
+++ tests/check/Makefile.am	20 Jul 2007 15:53:54 -0000
@@ -89,6 +89,7 @@
 	gst/typefindfunctions \
 	libs/audio \
 	libs/cddabasesrc \
+	libs/mixer \
 	libs/netbuffer \
 	libs/pbutils \
 	libs/tag \
@@ -138,6 +139,16 @@
 	$(GST_BASE_LIBS) \
 	$(LDADD)
 
+libs_mixer_CFLAGS = \
+	$(GST_PLUGINS_BASE_CFLAGS) \
+        $(GST_BASE_CFLAGS) \
+        $(AM_CFLAGS)
+
+libs_mixer_LDADD = \
+	$(top_builddir)/gst-libs/gst/interfaces/libgstinterfaces-@GST_MAJORMINOR@.la \
+        $(GST_BASE_LIBS) \
+        $(LDADD)
+
 libs_netbuffer_CFLAGS = \
 	$(GST_PLUGINS_BASE_CFLAGS) \
 	$(AM_CFLAGS)Index: tests/check/libs/mixer.c
===================================================================
RCS file: tests/check/libs/mixer.c
diff -N tests/check/libs/mixer.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/check/libs/mixer.c	20 Jul 2007 15:53:58 -0000
@@ -0,0 +1,215 @@
+/* GStreamer
+ *
+ * unit tests for audio support library
+ *
+ * Copyright (C) 2007 Jan Schmidt <thaytan@noraisin.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/check/gstcheck.h>
+
+#include <gst/interfaces/mixer.h>
+
+#include <string.h>
+
+#define TEST_ELEMENT_TYPE (test_element_get_type())
+
+typedef struct TestElement TestElement;
+typedef struct TestElementClass TestElementClass;
+
+struct TestElement {
+  GstElement parent;
+};
+
+struct TestElementClass {
+  GstElementClass parent_class;
+};
+
+static void init_interface (GType type);
+static void gst_implements_interface_init (GstImplementsInterfaceClass * klass);
+
+GST_BOILERPLATE_FULL (TestElement, test_element, GstElement, GST_TYPE_ELEMENT, init_interface);
+
+static void test_element_mixer_interface_init (GstMixerClass * klass)
+{
+  /* Not actually implementing any interfaces for this test atm */
+}
+
+static void init_interface (GType type)
+{
+ static const GInterfaceInfo mixer_iface_info = {
+    (GInterfaceInitFunc) test_element_mixer_interface_init,
+    NULL,
+    NULL,
+  };
+  static const GInterfaceInfo implements_iface_info = {
+    (GInterfaceInitFunc) gst_implements_interface_init,
+    NULL,
+    NULL,
+  };
+
+  g_type_add_interface_static (type, GST_TYPE_IMPLEMENTS_INTERFACE,
+      &implements_iface_info);
+  g_type_add_interface_static (type, GST_TYPE_MIXER, &mixer_iface_info);
+}
+
+static void test_element_base_init (gpointer klass)
+{
+}
+
+static void test_element_class_init (TestElementClass *klass)
+{
+}
+
+static gboolean
+test_element_interface_supported (TestElement *this, GType interface_type)
+{
+  if (interface_type == GST_TYPE_MIXER)
+    return TRUE;
+
+  return FALSE;
+}
+
+static void
+gst_implements_interface_init (GstImplementsInterfaceClass * klass)
+{
+  klass->supported = (gpointer) test_element_interface_supported;
+}
+
+static void test_element_init (TestElement *this,
+    TestElementClass *klass)
+{
+}
+
+GST_START_TEST (test_messages)
+{
+  /* Create an empty GstElement that has a GstMixer interface and then
+   * send some notifications and validate them */
+  GstElement *test_element = 
+       (GstElement *) g_object_new (TEST_ELEMENT_TYPE, NULL);
+  GstBus *bus = gst_bus_new ();
+  GstMixerTrack *mtrack = g_object_new (GST_TYPE_MIXER_TRACK, NULL);
+  GstMixerOptions *mopts = g_object_new (GST_TYPE_MIXER_OPTIONS, NULL);
+  GstMixerTrack *t;
+  GstMixerOptions *o;
+  gint vols_in[2] = {50, 75};
+  gboolean mute, record;
+  gint *vols_out;
+  gint n_chans, i;
+  const gchar *val;
+  GstMessage *message;
+  
+  mtrack->num_channels = 2;
+  mtrack->flags = GST_MIXER_TRACK_MUTE|GST_MIXER_TRACK_RECORD;
+
+  gst_element_set_bus (test_element, bus);
+
+  /* Test mute-toggled */
+  gst_mixer_mute_toggled (GST_MIXER (test_element), mtrack, TRUE);
+  message = gst_bus_poll (bus, GST_MESSAGE_ELEMENT, GST_CLOCK_TIME_NONE);
+  fail_if (message == NULL);
+  fail_unless (gst_mixer_message_get_type (message) == 
+       GST_MIXER_MESSAGE_MUTE_TOGGLED);
+  /* Test that we can pass NULL args */
+  gst_mixer_message_parse_mute_toggled (message, NULL, NULL);
+  /* Test the parsing */
+  gst_mixer_message_parse_mute_toggled (message, &t, &mute);
+  fail_unless (t == mtrack);
+  fail_unless (mute == TRUE);
+  gst_message_unref (message);
+
+  /* Test record-toggled */
+  gst_mixer_record_toggled (GST_MIXER (test_element), mtrack, TRUE);
+  message = gst_bus_poll (bus, GST_MESSAGE_ELEMENT, GST_CLOCK_TIME_NONE);
+  fail_if (message == NULL);
+  fail_unless (gst_mixer_message_get_type (message) == 
+       GST_MIXER_MESSAGE_RECORD_TOGGLED);
+  gst_mixer_message_parse_record_toggled (message, NULL, NULL);
+  gst_mixer_message_parse_record_toggled (message, &t, &record);
+  fail_unless (t == mtrack);
+  fail_unless (record == TRUE);
+  gst_message_unref (message);
+
+  /* Test volume-changed */
+  gst_mixer_volume_changed (GST_MIXER (test_element), mtrack, vols_in);
+  message = gst_bus_poll (bus, GST_MESSAGE_ELEMENT, GST_CLOCK_TIME_NONE);
+  fail_if (message == NULL);
+  fail_unless (gst_mixer_message_get_type (message) == 
+       GST_MIXER_MESSAGE_VOLUME_CHANGED);
+  gst_mixer_message_parse_volume_changed (message, NULL, NULL, NULL);
+  gst_mixer_message_parse_volume_changed (message, NULL, NULL, &n_chans);
+  fail_unless (n_chans == 2);
+  gst_mixer_message_parse_volume_changed (message, &t, &vols_out, &n_chans);
+  fail_unless (mtrack == t);
+  for (i = 0; i < n_chans; i++)
+    fail_unless (vols_out[i] == vols_in[i]);
+
+  gst_message_unref (message);
+  g_free (vols_out);
+
+  /* Test options-changed */
+  gst_mixer_option_changed (GST_MIXER (test_element), mopts, "TESTING");
+  message = gst_bus_poll (bus, GST_MESSAGE_ELEMENT, GST_CLOCK_TIME_NONE);
+  fail_if (message == NULL);
+  fail_unless (gst_mixer_message_get_type (message) == 
+      GST_MIXER_MESSAGE_OPTION_CHANGED);
+  gst_mixer_message_parse_option_changed (message, NULL, NULL);
+  gst_mixer_message_parse_option_changed (message, &o, &val);
+  fail_unless (o == mopts);
+  fail_unless (g_str_equal (val, "TESTING"));
+  gst_message_unref (message);
+   
+  gst_object_unref (mtrack);
+  gst_object_unref (mopts);
+  gst_object_unref (bus);
+  gst_object_unref (test_element);
+}
+GST_END_TEST;
+
+static Suite *
+mixer_suite (void)
+{
+  Suite *s = suite_create ("mixer interface");
+  TCase *tc_chain = tcase_create ("notifications");
+
+  suite_add_tcase (s, tc_chain);
+  tcase_add_test (tc_chain, test_messages);
+
+  return s;
+}
+
+int
+main (int argc, char **argv)
+{
+  int nf;
+
+  Suite *s = mixer_suite ();
+  SRunner *sr = srunner_create (s);
+
+  gst_check_init (&argc, &argv);
+
+  srunner_run_all (sr, CK_NORMAL);
+  nf = srunner_ntests_failed (sr);
+  srunner_free (sr);
+
+  return nf;
+}
+