File xfce4-mixer-alsa.patch of Package xfce4-mixer

---
 configure.ac                             |   18 
 libxfce4mixer/Makefile.am                |   25 
 libxfce4mixer/audio.h                    |    8 
 libxfce4mixer/libxfce4mixer.c            |   40 +
 libxfce4mixer/libxfce4mixer.h            |    2 
 libxfce4mixer/xfce-mixer-preferences.h   |    3 
 libxfce4mixer/xfce-mixer-track-combo.c   |    3 
 libxfce4mixer/xfce-mixer-track-combo.h   |    3 
 libxfce4mixer/xfce-mixer-track-type.h    |    2 
 libxfce4mixer/xfce4-mixer-alsa.c         |  974 +++++++++++++++++++++++++++++++
 libxfce4mixer/xfce4-mixer-alsa.h         |  192 ++++++
 panel-plugin/Makefile.am                 |   15 
 panel-plugin/xfce-plugin-dialog.c        |    3 
 panel-plugin/xfce-plugin-dialog.h        |    3 
 xfce4-mixer/Makefile.am                  |   11 
 xfce4-mixer/xfce-mixer-container.c       |    3 
 xfce4-mixer/xfce-mixer-controls-dialog.c |    3 
 xfce4-mixer/xfce-mixer-option.c          |    3 
 xfce4-mixer/xfce-mixer-switch.c          |    3 
 xfce4-mixer/xfce-mixer-track.c           |    3 
 xfce4-mixer/xfce-mixer-window.c          |    4 
 21 files changed, 1278 insertions(+), 43 deletions(-)

--- a/libxfce4mixer/libxfce4mixer.c
+++ b/libxfce4mixer/libxfce4mixer.c
@@ -31,8 +31,7 @@
 
 #include <dbus/dbus-glib.h>
 
-#include <gst/audio/mixerutils.h>
-#include <gst/interfaces/mixer.h>
+#include "audio.h"
 
 #include <libxfce4util/libxfce4util.h>
 
@@ -40,8 +39,10 @@
 
 
 
+#ifndef XFCE4_MIXER_ALSA
 static gboolean _xfce_mixer_filter_mixer     (GstMixer   *mixer,
                                               gpointer    user_data);
+#endif
 static void     _xfce_mixer_add_track_labels (gpointer    data,
                                               gpointer    user_data);
 static void     _xfce_mixer_init_mixer       (gpointer    data,
@@ -88,7 +89,11 @@ xfce_mixer_init (void)
       gtk_icon_theme_append_search_path (icon_theme, MIXER_DATADIR G_DIR_SEPARATOR_S "icons");
 
       /* Get list of all available mixer devices */
+#ifdef XFCE4_MIXER_ALSA
+      mixers = gst_mixer_probe_devices ();
+#else
       mixers = gst_audio_default_registry_mixer_filter (_xfce_mixer_filter_mixer, FALSE, &counter);
+#endif
 
       /* Create a GstBus for notifications */
       bus = gst_bus_new ();
@@ -396,6 +401,9 @@ xfce_mixer_get_max_volume (gint *volumes
 
 
 
+static void set_mixer_name (GstMixer *mixer, const gchar *name);
+
+#ifndef XFCE4_MIXER_ALSA
 static gboolean 
 _xfce_mixer_filter_mixer (GstMixer *mixer,
                           gpointer  user_data)
@@ -427,8 +435,24 @@ _xfce_mixer_filter_mixer (GstMixer *mixe
   /* Free device name */
   g_free (device_name);
 
+  set_mixer_name (mixer, name);
+  g_free (name);
+
+  /* Keep the mixer (we want all devices to be visible) */
+  return TRUE;
+}
+#endif /* !XFCE4_MIXER_ALSA */
+
+static void
+set_mixer_name (GstMixer *mixer, const gchar *name)
+{
+  gint               length;
+  const gchar       *p;
+  gchar             *internal_name;
+
   /* Set name to be used by xfce4-mixer */
-  g_object_set_data_full (G_OBJECT (mixer), "xfce-mixer-name", name, (GDestroyNotify) g_free);
+  g_object_set_data_full (G_OBJECT (mixer), "xfce-mixer-name",
+			  g_strdup (name), (GDestroyNotify) g_free);
 
   /* Count alpha-numeric characters in the name */
   for (length = 0, p = name; *p != '\0'; ++p)
@@ -442,15 +466,11 @@ _xfce_mixer_filter_mixer (GstMixer *mixe
       internal_name[length++] = *p;
   internal_name[length] = '\0';
 
-  /* Remember name for use by xfce4-mixer */
+  /* Set name to be used by xfce4-mixer */
   g_object_set_data_full (G_OBJECT (mixer), "xfce-mixer-internal-name", internal_name, (GDestroyNotify) g_free);
-
-  /* Keep the mixer (we want all devices to be visible) */
-  return TRUE;
 }
 
 
-
 static void
 _xfce_mixer_add_track_labels (gpointer data,
                               gpointer user_data)
@@ -492,6 +512,10 @@ _xfce_mixer_init_mixer (gpointer data,
 {
   GstMixer *card = GST_MIXER (data);
 
+#ifdef XFCE4_MIXER_ALSA
+  set_mixer_name (card, gst_mixer_get_card_name (card));
+#endif
+
   /* Add custom labels to all tracks */
   _xfce_mixer_add_track_labels (card, NULL);
 
--- a/libxfce4mixer/libxfce4mixer.h
+++ b/libxfce4mixer/libxfce4mixer.h
@@ -26,7 +26,7 @@
 
 #include <dbus/dbus-glib.h>
 
-#include <gst/interfaces/mixer.h>
+#include "audio.h"
 
 #include "xfce-mixer-preferences.h"
 #include "xfce-mixer-card-combo.h"
--- /dev/null
+++ b/libxfce4mixer/xfce4-mixer-alsa.h
@@ -0,0 +1,192 @@
+/*
+ * Simple alternative GstMixer implementation with ALSA-native API
+ */
+
+#ifndef __XFCE4_MIXER_ALSA_H
+#define __XFCE4_MIXER_ALSA_H
+
+G_BEGIN_DECLS
+
+/*
+ * GstMixer
+ */
+
+GType gst_mixer_get_type (void);
+
+#define GST_TYPE_MIXER \
+  (gst_mixer_get_type ())
+#define GST_MIXER(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_MIXER, GstMixer))
+#define GST_MIXER_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_MIXER, GstMixerClass))
+#define GST_IS_MIXER(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_MIXER))
+#define GST_IS_MIXER_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_MIXER))
+#define GST_MIXER_GET_CLASS(inst) \
+  (G_TYPE_INSTANCE_GET_INTERFACE ((inst), GST_TYPE_MIXER, GstMixerClass))
+
+typedef struct _GstMixer GstMixer;
+typedef struct _GstMixerClass GstMixerClass;
+
+typedef enum {
+  GST_MIXER_FLAG_NONE                = 0,
+  GST_MIXER_FLAG_AUTO_NOTIFICATIONS  = (1<<0),
+  GST_MIXER_FLAG_HAS_WHITELIST       = (1<<1),
+  GST_MIXER_FLAG_GROUPING            = (1<<2),
+} GstMixerFlags;
+
+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,
+  GST_MIXER_MESSAGE_OPTIONS_LIST_CHANGED,
+  GST_MIXER_MESSAGE_MIXER_CHANGED
+} GstMixerMessageType;
+
+struct _GstMixer {
+  GstElement element;
+  GList *tracklist;
+  void *handle; /* snd_mixer_t */
+  const char *name;
+  const gchar *card_name;
+  GSource *src;
+};
+
+struct _GstMixerClass {
+  GstElementClass parent_class;
+};
+
+const GList *gst_mixer_list_tracks (GstMixer *mixer);
+
+static inline GstMixerFlags
+gst_mixer_get_mixer_flags (GstMixer * mixer)
+{
+  return GST_MIXER_FLAG_AUTO_NOTIFICATIONS;
+}
+
+GstMixerMessageType gst_mixer_message_get_type (GstMessage *message);
+
+int gst_mixer_new (const char *name, GstMixer **mixer_ret);
+GList *gst_mixer_probe_devices (void);
+const gchar *gst_mixer_get_card_name (GstMixer *mixer);
+
+/*
+ * GstMixerTrack
+ */
+
+GType gst_mixer_track_get_type (void);
+
+#define GST_TYPE_MIXER_TRACK \
+  (gst_mixer_track_get_type ())
+#define GST_MIXER_TRACK(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_MIXER_TRACK, \
+                               GstMixerTrack))
+#define GST_MIXER_TRACK_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_MIXER_TRACK, \
+                            GstMixerTrackClass))
+#define GST_IS_MIXER_TRACK(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_MIXER_TRACK))
+#define GST_IS_MIXER_TRACK_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_MIXER_TRACK))
+
+typedef struct _GstMixerTrack GstMixerTrack;
+typedef struct _GstMixerTrackClass GstMixerTrackClass;
+
+typedef enum {
+  GST_MIXER_TRACK_INPUT  = (1<<0),
+  GST_MIXER_TRACK_OUTPUT = (1<<1),
+  GST_MIXER_TRACK_MUTE   = (1<<2),
+  GST_MIXER_TRACK_RECORD = (1<<3),
+  GST_MIXER_TRACK_MASTER = (1<<4),
+  GST_MIXER_TRACK_SOFTWARE = (1<<5),
+  GST_MIXER_TRACK_NO_RECORD = (1<<6),
+  GST_MIXER_TRACK_NO_MUTE = (1<<7),
+  GST_MIXER_TRACK_WHITELIST = (1<<8),
+  GST_MIXER_TRACK_READONLY = (1<<9),
+  GST_MIXER_TRACK_WRITEONLY = (1<<10)
+} GstMixerTrackFlags;
+
+struct _GstMixerTrack {
+  GObject parent;
+  void *element;
+  gchar *label;
+  gchar *untranslated_label;
+  guint index;
+  GstMixerTrackFlags flags;
+  gint num_channels;
+  gint *volumes;
+  gint min_volume;
+  gint max_volume;
+  GstMixerTrack *shared_mute;
+  gboolean has_volume;
+  gboolean has_switch;
+};
+
+struct _GstMixerTrackClass {
+  GObjectClass parent;
+};
+
+#define GST_MIXER_TRACK_HAS_FLAG(track, flag)	((track)->flags & (flag))
+
+void gst_mixer_get_volume (GstMixer *mixer, GstMixerTrack *track, gint *volumes);
+void gst_mixer_set_volume (GstMixer *mixer, GstMixerTrack *track, gint *volumes);
+void gst_mixer_set_mute (GstMixer *mixer, GstMixerTrack *track, gboolean mute);
+void gst_mixer_set_record (GstMixer *mixer, GstMixerTrack *track, gboolean record);
+
+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);
+
+/*
+ * GstMixerOptions
+ */
+
+GType gst_mixer_options_get_type (void);
+
+#define GST_TYPE_MIXER_OPTIONS \
+  (gst_mixer_options_get_type ())
+#define GST_MIXER_OPTIONS(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_MIXER_OPTIONS, GstMixerOptions))
+#define GST_MIXER_OPTIONS_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_MIXER_OPTIONS, GstMixerOptionsClass))
+#define GST_IS_MIXER_OPTIONS(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_MIXER_OPTIONS))
+#define GST_IS_MIXER_OPTIONS_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_MIXER_OPTIONS))
+#define GST_MIXER_OPTIONS_GET_CLASS(inst) \
+  (G_TYPE_INSTANCE_GET_INTERFACE ((inst), GST_TYPE_MIXER_OPTIONS, GstMixerOptionsClass))
+
+typedef struct _GstMixerOptions GstMixerOptions;
+typedef struct _GstMixerOptionsClass GstMixerOptionsClass;
+
+struct _GstMixerOptions {
+  GstMixerTrack parent;
+  GList *values;
+};
+
+struct _GstMixerOptionsClass {
+  GstMixerTrackClass parent;
+};
+
+void gst_mixer_set_option (GstMixer * mixer, GstMixerOptions * opts, gchar * value);
+const gchar * gst_mixer_get_option (GstMixer * mixer, GstMixerOptions * opts);
+GList * gst_mixer_options_get_values (GstMixerOptions *mixer_options);
+void gst_mixer_message_parse_option_changed (GstMessage *message,
+					     GstMixerOptions ** options,
+					     const gchar **value);
+void gst_mixer_message_parse_options_list_changed (GstMessage *message,
+						   GstMixerOptions **options);
+
+G_END_DECLS
+
+#endif /* __XFCE4_MIXER_ALSA_H */
--- a/libxfce4mixer/xfce-mixer-preferences.h
+++ b/libxfce4mixer/xfce-mixer-preferences.h
@@ -24,8 +24,7 @@
 
 #include <glib-object.h>
 
-#include <gst/gst.h>
-#include <gst/interfaces/mixer.h>
+#include "audio.h"
 
 G_BEGIN_DECLS
 
--- a/libxfce4mixer/xfce-mixer-track-combo.c
+++ b/libxfce4mixer/xfce-mixer-track-combo.c
@@ -27,8 +27,7 @@
 
 #include <gtk/gtk.h>
 
-#include <gst/gst.h>
-#include <gst/interfaces/mixer.h>
+#include "audio.h"
 
 #include "libxfce4mixer.h"
 #include "xfce-mixer-track-type.h"
--- a/libxfce4mixer/xfce-mixer-track-combo.h
+++ b/libxfce4mixer/xfce-mixer-track-combo.h
@@ -24,8 +24,7 @@
 
 #include <gtk/gtk.h>
 
-#include <gst/gst.h>
-#include <gst/interfaces/mixer.h>
+#include "audio.h"
 
 G_BEGIN_DECLS
 
--- a/libxfce4mixer/xfce-mixer-track-type.h
+++ b/libxfce4mixer/xfce-mixer-track-type.h
@@ -22,7 +22,7 @@
 #define __XFCE_TRACK_TYPE_H__
 
 #include <glib-object.h>
-#include <gst/interfaces/mixer.h>
+#include "audio.h"
 
 G_BEGIN_DECLS
 
--- /dev/null
+++ b/libxfce4mixer/xfce4-mixer-alsa.c
@@ -0,0 +1,974 @@
+/*
+ * Simple alternative GstMixer implementation with ALSA-native API
+ */
+
+#include "config.h"
+#include "audio.h"
+
+#include <alsa/asoundlib.h>
+
+#define GST_MIXER_MESSAGE_NAME "gst-mixer-message"
+
+/*
+ * GstMixer
+ */
+
+G_DEFINE_TYPE (GstMixer, gst_mixer, GST_TYPE_ELEMENT);
+
+static void gst_mixer_init (GstMixer *mixer)
+{
+}
+
+static void gst_mixer_dispose (GObject * object)
+{
+  GstMixer *mixer = GST_MIXER (object);
+
+  if (mixer->src) {
+    g_source_destroy (mixer->src);
+    mixer->src = NULL;
+  }
+
+  if (mixer->handle) {
+    snd_mixer_close (mixer->handle);
+    mixer->handle = NULL;
+  }
+
+  g_list_free_full (mixer->tracklist, g_object_unref);
+  mixer->tracklist = NULL;
+
+  g_free ((gpointer *) mixer->name);
+  mixer->name = NULL;
+
+  g_free ((gpointer *) mixer->card_name);
+  mixer->card_name = NULL;
+
+  G_OBJECT_CLASS (gst_mixer_parent_class)->dispose (object);
+}
+
+static void gst_mixer_class_init (GstMixerClass *klass)
+{
+  GstElementClass *element_klass = GST_ELEMENT_CLASS (klass);
+  GObjectClass *object_klass = G_OBJECT_CLASS (klass);
+
+  gst_element_class_set_static_metadata (element_klass,
+	"ALSA mixer", "Generic/Audio",
+	"Control audio mixer via ALSA API",
+	"Takashi Iwai <tiwai@suse.de>");
+
+  object_klass->dispose = gst_mixer_dispose;
+}
+
+/*
+ * GstMixerTrack
+ */
+
+G_DEFINE_TYPE (GstMixerTrack, gst_mixer_track, G_TYPE_OBJECT);
+
+static void gst_mixer_track_init (GstMixerTrack *track)
+{
+}
+
+static void notify_mute_change (GstMixer *mixer, GstMixerTrack *track,
+				gboolean mute)
+{
+  GstStructure *s;
+  GstMessage *m;
+
+  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);
+  gst_element_post_message (GST_ELEMENT (mixer), m);
+}
+
+static void update_mute (GstMixer *mixer, GstMixerTrack *track, gboolean mute)
+{
+  int old_flag = track->flags & GST_MIXER_TRACK_MUTE;
+
+  if (mute) {
+    track->flags |= GST_MIXER_TRACK_MUTE;
+    if (track->shared_mute)
+      track->shared_mute->flags |= GST_MIXER_TRACK_MUTE;
+  } else {
+    track->flags &= ~GST_MIXER_TRACK_MUTE;
+    if (track->shared_mute)
+      track->shared_mute->flags &= ~GST_MIXER_TRACK_MUTE;
+  }
+
+  if ((track->flags & GST_MIXER_TRACK_MUTE) != old_flag)
+    notify_mute_change (mixer, track, mute);
+}
+
+static void notify_recording_change (GstMixer *mixer, GstMixerTrack *track,
+				     gboolean recording)
+{
+  GstStructure *s;
+  GstMessage *m;
+
+  s = gst_structure_new (GST_MIXER_MESSAGE_NAME,
+			 "type", G_TYPE_STRING, "record-toggled",
+			 "track", GST_TYPE_MIXER_TRACK, track,
+			 "record", G_TYPE_BOOLEAN, recording,
+			 NULL);
+  m = gst_message_new_element (GST_OBJECT (mixer), s);
+  gst_element_post_message (GST_ELEMENT (mixer), m);
+}
+
+static void update_recording (GstMixer *mixer, GstMixerTrack *track,
+			      gboolean recording)
+{
+  int old_flag = track->flags & GST_MIXER_TRACK_RECORD;
+
+  if (recording)
+    track->flags |= GST_MIXER_TRACK_RECORD;
+  else
+    track->flags &= ~GST_MIXER_TRACK_RECORD;
+
+  if ((track->flags & GST_MIXER_TRACK_RECORD) != old_flag)
+    notify_recording_change (mixer, track, recording);
+}
+
+static void notify_volume_change (GstMixer *mixer, GstMixerTrack *track)
+{
+  GstStructure *s;
+  GstMessage *m;
+  GValue l = { 0, };
+  GValue v = { 0, };
+  int i;
+
+  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);
+
+  for (i = 0; i < track->num_channels; i++) {
+    g_value_set_int (&v, track->volumes[i]);
+    gst_value_array_append_value (&l, &v);
+  }
+
+  gst_structure_set_value (s, "volumes", &l);
+  g_value_unset (&v);
+  g_value_unset (&l);
+
+  m = gst_message_new_element (GST_OBJECT (mixer), s);
+  gst_element_post_message (GST_ELEMENT (mixer), m);
+}
+
+static void track_update (GstMixer *mixer, GstMixerTrack *track)
+{
+  gboolean vol_changed = FALSE;
+  int i;
+
+  if (track->flags & GST_MIXER_TRACK_OUTPUT) {
+    int audible = 0;
+    if (track->has_switch) {
+      for (i = 0; i < track->num_channels; i++) {
+	int v = 0;
+	snd_mixer_selem_get_playback_switch (track->element, i, &v);
+	if (v)
+	  audible = 1;
+      }
+    }
+
+    if (track->has_volume) {
+      for (i = 0; i < track->num_channels; i++) {
+	long vol = 0;
+	snd_mixer_selem_get_playback_volume (track->element, i, &vol);
+	if (track->volumes[i] != vol)
+	  vol_changed = TRUE;
+	track->volumes[i] = vol;
+	if (!track->has_switch &&
+	    vol > track->min_volume)
+	  audible = 1;
+      }
+    }
+
+    update_mute (mixer, track, !audible);
+  }
+
+  if (track->flags & GST_MIXER_TRACK_INPUT) {
+    int recording = 0;
+    if (track->has_switch) {
+      for (i = 0; i < track->num_channels; i++) {
+	int v = 0;
+	snd_mixer_selem_get_capture_switch (track->element, i, &v);
+	if (v)
+	  recording = 1;
+      }
+    }
+
+    if (track->has_volume) {
+      for (i = 0; i < track->num_channels; i++) {
+	long vol = 0;
+	snd_mixer_selem_get_capture_volume (track->element, i, &vol);
+	if (track->volumes[i] != vol)
+	  vol_changed = TRUE;
+	track->volumes[i] = vol;
+	if (!track->has_switch &&
+	    vol > track->min_volume)
+	  recording = 1;
+      }
+    }
+
+    update_recording (mixer, track, recording);
+  }
+
+  if (vol_changed)
+    notify_volume_change (mixer, track);
+}
+
+static GstMixerTrack *track_new (snd_mixer_elem_t *element, int num,
+				int flags, gboolean append_capture)
+{
+  GstMixerTrack *track;
+  const char *name;
+
+  track = (GstMixerTrack *) g_object_new (GST_TYPE_MIXER_TRACK, NULL);
+  track->index = snd_mixer_selem_get_index (element);
+  track->element = element;
+  track->flags = flags;
+
+  if (flags & GST_MIXER_TRACK_OUTPUT) {
+    while (snd_mixer_selem_has_playback_channel (element,
+						 track->num_channels))
+      track->num_channels++;
+  } else if (flags & GST_MIXER_TRACK_INPUT) {
+    while (snd_mixer_selem_has_capture_channel (element,
+						track->num_channels))
+      track->num_channels++;
+  }
+
+  track->volumes = g_new (gint, track->num_channels);
+
+  name = snd_mixer_selem_get_name (element);
+  track->untranslated_label = g_strdup (name);
+
+  if (!num)
+    track->label = g_strdup_printf ("%s%s", name,
+				    append_capture ? " Capture" : "");
+  else
+    track->label = g_strdup_printf ("%s%s %d", name,
+				    append_capture ? " Capture" : "",
+				    num);
+
+  return track;
+}
+
+enum {
+  ARG_0,
+  ARG_LABEL,
+  ARG_UNTRANSLATED_LABEL,
+  ARG_INDEX,
+};
+
+static void gst_mixer_track_get_property (GObject *object, guint prop_id,
+					  GValue *value, GParamSpec *pspec)
+{
+  GstMixerTrack *track = GST_MIXER_TRACK (object);
+
+  switch (prop_id) {
+  case ARG_LABEL:
+    g_value_set_string (value, track->label);
+    break;
+  case ARG_UNTRANSLATED_LABEL:
+    g_value_set_string (value, track->untranslated_label);
+    break;
+  case ARG_INDEX:
+    g_value_set_uint (value, track->index);
+    break;
+  default:
+    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    break;
+  }
+}
+
+static void gst_mixer_track_set_property (GObject *object,
+					  guint prop_id,
+					  const GValue *value,
+					  GParamSpec * pspec)
+{
+  GstMixerTrack *track;
+
+  track = GST_MIXER_TRACK (object);
+
+  switch (prop_id) {
+    case ARG_LABEL:
+      g_free (track->label);
+      track->label = g_value_dup_string (value);
+      break;
+    case ARG_UNTRANSLATED_LABEL:
+      g_free (track->untranslated_label);
+      track->untranslated_label = g_value_dup_string (value);
+      break;
+    case ARG_INDEX:
+      track->index = g_value_get_uint (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void gst_mixer_track_dispose (GObject * object)
+{
+  GstMixerTrack *track = GST_MIXER_TRACK (object);
+
+  if (track->label) {
+    g_free (track->label);
+    track->label = NULL;
+  }
+
+  if (track->untranslated_label) {
+    g_free (track->untranslated_label);
+    track->untranslated_label = NULL;
+  }
+
+  G_OBJECT_CLASS (gst_mixer_track_parent_class)->dispose (object);
+}
+
+static void gst_mixer_track_class_init (GstMixerTrackClass * klass)
+{
+  GObjectClass *object_klass = G_OBJECT_CLASS (klass);
+
+  object_klass->get_property = gst_mixer_track_get_property;
+  object_klass->set_property = gst_mixer_track_set_property;
+
+  g_object_class_install_property (object_klass, ARG_UNTRANSLATED_LABEL,
+      g_param_spec_string ("untranslated-label",
+			   "Untranslated track label",
+			   "The untranslated label assigned to the track (since 0.10.13)",
+			   NULL,
+			   G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (object_klass, ARG_LABEL,
+	g_param_spec_string ("label", "Track label",
+			     "The label assigned to the track (may be translated)",
+			     NULL,
+			     G_PARAM_READABLE | G_PARAM_STATIC_STRINGS | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (object_klass, ARG_INDEX,
+	g_param_spec_uint ("index", "Index",
+			   "Track index",
+			   0, G_MAXUINT, 0,
+			   G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+  object_klass->dispose = gst_mixer_track_dispose;
+}
+
+static void get_playback_min_max (GstMixerTrack *track)
+{
+  if (track->has_volume) {
+    long min = 0, max = 0;
+    snd_mixer_selem_get_playback_volume_range (track->element, &min, &max);
+    track->min_volume = min;
+    track->max_volume = max;
+  }
+}
+	
+static void get_capture_min_max (GstMixerTrack *track)
+{
+  if (track->has_volume) {
+    long min = 0, max = 0;
+    snd_mixer_selem_get_capture_volume_range (track->element, &min, &max);
+    track->min_volume = min;
+    track->max_volume = max;
+  }
+}
+	
+static GstMixerTrack *get_named_playback_track (GstMixer *mixer,
+						const char *name)
+{
+  GList *item;
+  GstMixerTrack *track;
+
+  for (item = mixer->tracklist; item; item = item->next) {
+    track = GST_MIXER_TRACK (item->data);
+    if (! (track->flags & GST_MIXER_TRACK_OUTPUT))
+      continue;
+    if (!strcmp (track->label, name))
+      return track;
+  }
+  return NULL;
+}
+
+static void mark_master_track (GstMixer *mixer)
+{
+  GList *item;
+  GstMixerTrack *track;
+
+  if ((track = get_named_playback_track (mixer, "Master")) ||
+      (track = get_named_playback_track (mixer, "Front")) ||
+      (track = get_named_playback_track (mixer, "PCM")) ||
+      (track = get_named_playback_track (mixer, "Speaker")))
+    goto found;
+	    
+  /* If not found, take a mono track with both volume and switch */
+  for (item = mixer->tracklist; item; item = item->next) {
+    track = GST_MIXER_TRACK (item->data);
+    if (! (track->flags & GST_MIXER_TRACK_OUTPUT))
+      continue;
+    if (track->has_volume && track->has_switch &&
+	track->num_channels == 1)
+      goto found;
+  }
+
+  /* If not found, take any track with both volume and switch */
+  for (item = mixer->tracklist; item; item = item->next) {
+    track = GST_MIXER_TRACK (item->data);
+    if (! (track->flags & GST_MIXER_TRACK_OUTPUT))
+      continue;
+    if (track->has_volume && track->has_switch)
+      goto found;
+  }
+
+  /* If not found, take any track with volume */
+  for (item = mixer->tracklist; item; item = item->next) {
+    track = GST_MIXER_TRACK (item->data);
+    if (! (track->flags & GST_MIXER_TRACK_OUTPUT))
+      continue;
+    if (track->has_volume)
+      goto found;
+  }
+
+  return;
+
+ found:
+  track->flags |= GST_MIXER_TRACK_MASTER;
+  return;
+}
+
+static int mixer_elem_callback (snd_mixer_elem_t *elem, unsigned int mask)
+{
+  GstMixer *mixer = snd_mixer_elem_get_callback_private (elem);
+  GList *item;
+
+  for (item = mixer->tracklist; item; item = item->next) {
+    GstMixerTrack *track = GST_MIXER_TRACK (item->data);
+    if (track->element == elem)
+      track_update (mixer, track);
+  }
+
+  return 0;
+}
+
+static int mixer_callback (snd_mixer_t *ctl, unsigned int mask,
+			   snd_mixer_elem_t *elem)
+{
+  GstMixer *mixer = snd_mixer_get_callback_private (ctl);
+	
+  snd_mixer_handle_events (mixer->handle);
+  return 0;
+}
+
+const GList *gst_mixer_list_tracks (GstMixer *mixer)
+{
+  return mixer->tracklist;
+}
+
+static gboolean same_volumes (gint num_channels, const gint *volumes)
+{
+  gint i;
+
+  for (i = 1; i < num_channels; i++) {
+    if (volumes[0] != volumes[i])
+      return FALSE;
+  }
+
+  return TRUE;
+}
+
+void gst_mixer_set_volume (GstMixer *mixer, GstMixerTrack *track, gint *volumes)
+{
+  gint i;
+
+  track_update (mixer, track);
+
+  if (!track->has_volume)
+    return;
+
+  for (i = 0; i < track->num_channels; i++)
+    track->volumes[i] = volumes[i];
+
+  if (track->flags & GST_MIXER_TRACK_OUTPUT) {
+    if (!track->has_switch && (track->flags & GST_MIXER_TRACK_MUTE))
+      return;
+    if (same_volumes (track->num_channels, volumes)) {
+      snd_mixer_selem_set_playback_volume_all (track->element,
+					       volumes[0]);
+    } else {
+      for (i = 0; i < track->num_channels; i++)
+	snd_mixer_selem_set_playback_volume (track->element, i,
+					     volumes[i]);
+    }
+  } else {
+    if (!track->has_switch && ! (track->flags & GST_MIXER_TRACK_RECORD))
+      return;
+    if (same_volumes (track->num_channels, volumes)) {
+      snd_mixer_selem_set_capture_volume_all (track->element,
+					      volumes[0]);
+    } else {
+      for (i = 0; i < track->num_channels; i++)
+	snd_mixer_selem_set_capture_volume (track->element, i,
+					    volumes[i]);
+    }
+  }
+}
+
+void gst_mixer_get_volume (GstMixer *mixer, GstMixerTrack *track, gint *volumes)
+{
+  int i;
+
+  if (!track->has_volume)
+    return;
+
+  track_update (mixer, track);
+  for (i = 0; i < track->num_channels; i++)
+    volumes[i] = track->volumes[i];
+}
+
+void gst_mixer_set_mute (GstMixer *mixer, GstMixerTrack *track, gboolean mute)
+{
+  int i;
+
+  if (track->flags & GST_MIXER_TRACK_INPUT) {
+    if (track->shared_mute)
+      track = track->shared_mute;
+    else
+      return;
+  }
+
+  track_update (mixer, track);
+
+  mute = !!mute;
+  if (mute == !! (track->flags & GST_MIXER_TRACK_MUTE))
+    return;
+
+  update_mute (mixer, track, mute);
+
+  if (track->has_switch) {
+    snd_mixer_selem_set_playback_switch_all (track->element, !mute);
+  } else {
+    for (i = 0; i < track->num_channels; i++) {
+      long vol = mute ? track->min_volume : track->volumes[i];
+      snd_mixer_selem_set_playback_volume (track->element, i, vol);
+    }
+  }
+}
+
+void gst_mixer_set_record (GstMixer * mixer, GstMixerTrack *track, gboolean record)
+{
+  int i;
+
+  if (! (track->flags & GST_MIXER_TRACK_INPUT))
+    return;
+
+  track_update (mixer, track);
+
+  record = !!record;
+  if (record == !! (track->flags & GST_MIXER_TRACK_RECORD))
+    return;
+
+  if (record)
+    track->flags |= GST_MIXER_TRACK_RECORD;
+  else
+    track->flags &= ~GST_MIXER_TRACK_RECORD;
+
+  if (track->has_switch) {
+    snd_mixer_selem_set_capture_switch_all (track->element, record);
+  } else {
+    for (i = 0; i < track->num_channels; i++) {
+      long vol = record ? track->volumes[i] : track->min_volume;
+      snd_mixer_selem_set_capture_volume (track->element, i, vol);
+    }
+  }
+}
+
+GstMixerMessageType
+gst_mixer_message_get_type (GstMessage * message)
+{
+  const GstStructure *s;
+  const gchar *m_type;
+
+  s = gst_message_get_structure (message);
+  m_type = gst_structure_get_string (s, "type");
+  if (!m_type)
+    return 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;
+  else if (g_str_equal (m_type, "options-list-changed"))
+    return GST_MIXER_MESSAGE_OPTIONS_LIST_CHANGED;
+  else if (g_str_equal (m_type, "mixer-changed"))
+    return GST_MIXER_MESSAGE_MIXER_CHANGED;
+
+  return GST_MIXER_MESSAGE_INVALID;
+}
+
+static void message_parse_track (const GstStructure *s, GstMixerTrack **track)
+{
+  if (track) {
+    const GValue *v = gst_structure_get_value (s, "track");
+    *track = (GstMixerTrack *)g_value_get_object (v);
+  }
+}
+
+void gst_mixer_message_parse_mute_toggled (GstMessage *message,
+					   GstMixerTrack **track,
+					   gboolean *mute)
+{
+  const GstStructure *s = gst_message_get_structure (message);
+
+  message_parse_track (s, track);
+  if (mute)
+    gst_structure_get_boolean (s, "mute", mute);
+}
+
+void gst_mixer_message_parse_record_toggled (GstMessage *message,
+					     GstMixerTrack **track,
+					     gboolean *record)
+{
+  const GstStructure *s = gst_message_get_structure (message);
+
+  message_parse_track (s, track);
+  if (record)
+    gst_structure_get_boolean (s, "record", record);
+}
+
+void gst_mixer_message_parse_volume_changed (GstMessage *message,
+					    GstMixerTrack **track,
+					    gint **volumes,
+					    gint *num_channels)
+{
+  const GstStructure *s = gst_message_get_structure (message);
+
+  message_parse_track (s, track);
+  if (volumes || num_channels) {
+    gint n_chans, i;
+    const GValue *v = gst_structure_get_value (s, "volumes");
+
+    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);
+
+	(*volumes)[i] = g_value_get_int (e);
+      }
+    }
+  }
+}
+
+/*
+ * GstMixerOptions
+ */
+
+G_DEFINE_TYPE (GstMixerOptions, gst_mixer_options, GST_TYPE_MIXER_TRACK);
+
+static GstMixerOptions *
+mixer_options_new (snd_mixer_elem_t *element, int num)
+{
+  GstMixerOptions *opt;
+  GstMixerTrack *track;
+  const char *label;
+  int i;
+
+  label = snd_mixer_selem_get_name (element);
+  opt = g_object_new (GST_TYPE_MIXER_OPTIONS,
+		      "untranslated-label", label,
+		      "index", snd_mixer_selem_get_index (element),
+		      NULL);
+  track = GST_MIXER_TRACK (opt);
+  track->element = element;
+  if (!num)
+    track->label = g_strdup (label);
+  else
+    track->label = g_strdup_printf ("%s %d", label, num);
+
+  num = snd_mixer_selem_get_enum_items (element);
+  for (i = 0; i < num; i++) {
+    char str[256];
+    if (snd_mixer_selem_get_enum_item_name (element, i, sizeof(str), str) < 0)
+      break;
+    opt->values = g_list_append (opt->values, g_strdup (str));
+  }
+
+  return opt;
+}
+
+static void gst_mixer_options_dispose (GObject * object)
+{
+  GstMixerOptions *opt = GST_MIXER_OPTIONS (object);
+
+  g_list_free_full (opt->values, g_free);
+  opt->values = NULL;
+
+  G_OBJECT_CLASS (gst_mixer_options_parent_class)->dispose (object);
+}
+
+static void gst_mixer_options_init (GstMixerOptions *opt)
+{
+}
+
+static void gst_mixer_options_class_init (GstMixerOptionsClass * klass)
+{
+  GObjectClass *object_klass = G_OBJECT_CLASS (klass);
+
+  object_klass->dispose = gst_mixer_options_dispose;
+}
+
+const gchar *gst_mixer_get_option (GstMixer *mixer, GstMixerOptions *opt)
+{
+  unsigned int idx;
+
+  if (snd_mixer_selem_get_enum_item (opt->parent.element, 0, &idx) < 0)
+    return "error";
+  return g_list_nth_data (opt->values, idx);
+}
+
+void gst_mixer_set_option (GstMixer *mixer, GstMixerOptions *opt,
+			   gchar *value)
+{
+  int n = 0;
+  GList *item;
+
+  for (item = opt->values; item; item = item->next, n++) {
+    if (!strcmp (item->data, value)) {
+      snd_mixer_selem_set_enum_item (opt->parent.element, 0, n);
+      break;
+    }
+  }
+}
+
+GList *gst_mixer_options_get_values (GstMixerOptions *opt)
+{
+  return opt->values;
+}
+
+static void message_parse_options (const GstStructure *s,
+				   GstMixerOptions ** options)
+{
+  if (options) {
+    const GValue *v = gst_structure_get_value (s, "options");
+    *options = (GstMixerOptions *) g_value_get_object (v);
+  }
+}
+
+void gst_mixer_message_parse_option_changed (GstMessage *message,
+					     GstMixerOptions ** options,
+					     const gchar **value)
+{
+  const GstStructure *s = gst_message_get_structure (message);
+
+  message_parse_options (s, options);
+  if (value)
+    *value = gst_structure_get_string (s, "value");
+}
+
+void gst_mixer_message_parse_options_list_changed (GstMessage *message,
+						   GstMixerOptions **options)
+{
+  const GstStructure *s = gst_message_get_structure (message);
+
+  message_parse_options (s, options);
+}
+
+/*
+ */
+
+static void create_track_list (GstMixer *mixer)
+{
+  snd_mixer_elem_t *element, *temp;
+  GList *item;
+
+  if (mixer->tracklist)
+    return;
+
+  for (element = snd_mixer_first_elem (mixer->handle); element;
+       element = snd_mixer_elem_next (element)) {
+    GstMixerTrack *play_track = NULL;
+    GstMixerTrack *cap_track = NULL;
+    const gchar *name = snd_mixer_selem_get_name (element);
+    int index = 0;
+    int has_volume, has_switch;
+
+    for (item = mixer->tracklist; item; item = item->next) {
+      temp = GST_MIXER_TRACK (item->data)->element;
+      if (strcmp (name, snd_mixer_selem_get_name (temp)) == 0)
+	index++;
+    }
+
+    has_volume = snd_mixer_selem_has_playback_volume (element);
+    has_switch = snd_mixer_selem_has_playback_switch (element);
+    if (has_volume || has_switch) {
+      play_track = track_new (element, index,
+			      GST_MIXER_TRACK_OUTPUT, FALSE);
+      play_track->has_volume = has_volume;
+      play_track->has_switch = has_switch;
+      get_playback_min_max (play_track);
+    }
+
+    has_volume = snd_mixer_selem_has_capture_volume (element);
+    has_switch = snd_mixer_selem_has_capture_switch (element);
+    if (play_track && snd_mixer_selem_has_common_volume (element))
+      has_volume = 0;
+    if (play_track && snd_mixer_selem_has_common_switch (element))
+      has_switch = 0;
+    if (has_volume || has_switch) {
+      cap_track = track_new (element, index,
+			     GST_MIXER_TRACK_INPUT,
+			     play_track != NULL);
+      cap_track->has_volume = has_volume;
+      cap_track->has_switch = has_switch;
+      get_capture_min_max (cap_track);
+    }
+
+    if (play_track && cap_track) {
+      play_track->shared_mute = cap_track;
+      cap_track->shared_mute = play_track;
+    }
+
+    if (play_track) {
+      track_update (mixer, play_track);
+      mixer->tracklist = g_list_append (mixer->tracklist, play_track);
+    }
+
+    if (cap_track) {
+      track_update (mixer, cap_track);
+      mixer->tracklist = g_list_append (mixer->tracklist, cap_track);
+    }
+
+    if (snd_mixer_selem_is_enumerated (element)) {
+      mixer->tracklist = g_list_append (mixer->tracklist,
+					mixer_options_new (element, index));
+    }
+
+    snd_mixer_elem_set_callback_private (element, mixer);
+    snd_mixer_elem_set_callback (element, mixer_elem_callback);
+  }
+
+  mark_master_track (mixer);
+}
+
+static gboolean mixer_src_callback (gpointer user_data)
+{
+  GstMixer *mixer = (GstMixer *)user_data;
+
+  snd_mixer_handle_events (mixer->handle);
+  return TRUE;
+}
+
+static gboolean mixer_src_dispatch (GSource *source,
+				    GSourceFunc callback,
+				    gpointer user_data)
+{
+  return callback (user_data);
+}
+
+static void mixer_src_attach (GstMixer *mixer)
+{
+  static GSourceFuncs func = {
+    .dispatch = mixer_src_dispatch,
+  };
+  struct pollfd pfd;
+
+  if (snd_mixer_poll_descriptors (mixer->handle, &pfd, 1) != 1)
+    return;
+
+  mixer->src = g_source_new (&func, sizeof (*mixer->src));
+  g_source_add_unix_fd (mixer->src, pfd.fd, G_IO_IN | G_IO_ERR);
+  g_source_set_callback (mixer->src, mixer_src_callback, mixer, NULL);
+  g_source_attach (mixer->src, g_main_context_default ());
+}
+
+/*
+ * These are new functions that didn't exist in the original gstreamer API;
+ * instead of lengthy probing using factory, just provide a simpler method
+ */
+
+int gst_mixer_new (const char *name, GstMixer **mixer_ret)
+{
+  GstMixer *mixer;
+  snd_hctl_t *hctl;
+  int err;
+
+  mixer = (GstMixer *) g_object_new (GST_TYPE_MIXER, NULL);
+  mixer->name = g_strdup (name);
+
+  err = snd_mixer_open ((snd_mixer_t **) &mixer->handle, 0);
+  if (err < 0)
+    return err;
+
+  err = snd_mixer_attach (mixer->handle, name);
+  if (err < 0)
+    goto error;
+
+  err = snd_mixer_selem_register (mixer->handle, NULL, NULL);
+  if (err < 0)
+    goto error;
+
+  err = snd_mixer_load (mixer->handle);
+  if (err < 0)
+    goto error;
+
+  snd_mixer_get_hctl (mixer->handle, name, &hctl);
+  {
+    snd_ctl_card_info_t *info;
+
+    snd_ctl_card_info_alloca (&info);
+    snd_ctl_card_info (snd_hctl_ctl (hctl), info);
+    mixer->card_name = g_strdup_printf ("%s (Alsa mixer)",
+					snd_ctl_card_info_get_name (info));
+  }
+
+  snd_mixer_set_callback_private (mixer->handle, mixer);
+  snd_mixer_set_callback (mixer->handle, mixer_callback);
+  
+  create_track_list (mixer);
+
+  mixer_src_attach (mixer);
+
+  *mixer_ret = mixer;
+  return 0;
+
+ error:
+  gst_object_unref (mixer);
+  return err;
+}
+
+GList *gst_mixer_probe_devices (void)
+{
+  int card = -1;
+  GList *card_list = NULL;
+
+  while (snd_card_next(&card) >= 0 && card >= 0) {
+    GstMixer *mixer;
+    char name [16];
+    int err;
+
+    sprintf (name, "hw:%d", card);
+    err = gst_mixer_new (name, &mixer);
+    if (err < 0)
+      continue;
+    card_list = g_list_append (card_list, mixer);
+  }
+
+  return card_list;
+}
+
+const gchar *gst_mixer_get_card_name (GstMixer *mixer)
+{
+  return mixer->card_name;
+}
--- a/panel-plugin/xfce-plugin-dialog.c
+++ b/panel-plugin/xfce-plugin-dialog.c
@@ -25,8 +25,7 @@
 
 #include <gtk/gtk.h>
 
-#include <gst/gst.h>
-#include <gst/interfaces/mixer.h>
+#include "../libxfce4mixer/audio.h"
 
 #include <libxfce4ui/libxfce4ui.h>
 #include <libxfce4panel/libxfce4panel.h>
--- a/panel-plugin/xfce-plugin-dialog.h
+++ b/panel-plugin/xfce-plugin-dialog.h
@@ -24,8 +24,7 @@
 
 #include <gtk/gtk.h>
 
-#include <gst/gst.h>
-#include <gst/interfaces/mixer.h>
+#include "../libxfce4mixer/audio.h"
 
 G_BEGIN_DECLS
 
--- a/xfce4-mixer/xfce-mixer-container.c
+++ b/xfce4-mixer/xfce-mixer-container.c
@@ -23,8 +23,7 @@
 #include <config.h>
 #endif
 
-#include <gst/gst.h>
-#include <gst/interfaces/mixer.h>
+#include "../libxfce4mixer/audio.h"
 
 #include <libxfce4util/libxfce4util.h>
 #include <libxfce4ui/libxfce4ui.h>
--- a/xfce4-mixer/xfce-mixer-controls-dialog.c
+++ b/xfce4-mixer/xfce-mixer-controls-dialog.c
@@ -23,8 +23,7 @@
 #include <config.h>
 #endif
 
-#include <gst/gst.h>
-#include <gst/interfaces/mixer.h>
+#include "../libxfce4mixer/audio.h"
 
 #include <libxfce4util/libxfce4util.h>
 #include <libxfce4ui/libxfce4ui.h>
--- a/xfce4-mixer/xfce-mixer-option.c
+++ b/xfce4-mixer/xfce-mixer-option.c
@@ -23,8 +23,7 @@
 #include <config.h>
 #endif
 
-#include <gst/gst.h>
-#include <gst/interfaces/mixer.h>
+#include "../libxfce4mixer/audio.h"
 
 #include <libxfce4util/libxfce4util.h>
 #include <libxfce4ui/libxfce4ui.h>
--- a/xfce4-mixer/xfce-mixer-switch.c
+++ b/xfce4-mixer/xfce-mixer-switch.c
@@ -23,8 +23,7 @@
 #include <config.h>
 #endif
 
-#include <gst/gst.h>
-#include <gst/interfaces/mixer.h>
+#include "../libxfce4mixer/audio.h"
 
 #include <libxfce4util/libxfce4util.h>
 #include <libxfce4ui/libxfce4ui.h>
--- a/xfce4-mixer/xfce-mixer-track.c
+++ b/xfce4-mixer/xfce-mixer-track.c
@@ -27,8 +27,7 @@
 #include <math.h>
 #endif
 
-#include <gst/gst.h>
-#include <gst/interfaces/mixer.h>
+#include "../libxfce4mixer/audio.h"
 
 #include <libxfce4util/libxfce4util.h>
 #include <libxfce4ui/libxfce4ui.h>
--- a/xfce4-mixer/xfce-mixer-window.c
+++ b/xfce4-mixer/xfce-mixer-window.c
@@ -23,9 +23,7 @@
 #include <config.h>
 #endif
 
-#include <gst/gst.h>
-#include <gst/audio/mixerutils.h>
-#include <gst/interfaces/mixer.h>
+#include "../libxfce4mixer/audio.h"
 
 #include <libxfce4util/libxfce4util.h>
 #include <libxfce4ui/libxfce4ui.h>
--- a/configure.ac
+++ b/configure.ac
@@ -101,7 +101,6 @@ dnl ***********************************
 XDT_CHECK_PACKAGE([GLIB], [glib-2.0], [2.24.0])
 XDT_CHECK_PACKAGE([GTHREAD], [gthread-2.0], [2.24.0])
 XDT_CHECK_PACKAGE([DBUS_GLIB], [dbus-glib-1], [0.84])
-XDT_CHECK_PACKAGE([GST_PLUGINS_BASE], [gstreamer-plugins-base-0.10], [0.10.25])
 XDT_CHECK_PACKAGE([GTK], [gtk+-2.0], [2.20.0])
 XDT_CHECK_PACKAGE([UNIQUE], [unique-1.0], [1.1])
 XDT_CHECK_PACKAGE([LIBXFCE4UTIL], [libxfce4util-1.0], [4.10.0])
@@ -109,6 +108,23 @@ XDT_CHECK_PACKAGE([LIBXFCE4UI], [libxfce
 XDT_CHECK_PACKAGE([LIBXFCE4PANEL], [libxfce4panel-1.0], [4.10.0])
 XDT_CHECK_PACKAGE([XFCONF], [libxfconf-0], [4.10.0])
 
+AC_MSG_CHECKING(for audio engine)
+AC_ARG_WITH(audio,
+  AS_HELP_STRING([--with-audio],
+    [audio engine, either gstmixer or alsa (default)]),
+  audio="$withval", audio="alsa")
+
+if test "$audio" = "gstmixer"; then
+  AC_MSG_RESULT(gstreamer-0.10 native mixer)
+  XDT_CHECK_PACKAGE([GST], [gstreamer-plugins-base-0.10], [0.10.25])
+else
+  AC_MSG_RESULT(gstreamer-1.0 ALSA mixer)
+  XDT_CHECK_PACKAGE([GST], [gstreamer-1.0], [1.0])
+  XDT_CHECK_PACKAGE([ALSA], [alsa], [0.9])
+  AC_DEFINE([XFCE4_MIXER_ALSA], 1, [Built-in ALSA-based gstreamer mixer i/f])
+fi
+AM_CONDITIONAL([XFCE4_MIXER_ALSA], [test x"$audio" != x"gstmixer"])
+
 dnl ***********************************
 dnl *** Check for optional packages ***
 dnl ***********************************
--- a/libxfce4mixer/Makefile.am
+++ b/libxfce4mixer/Makefile.am
@@ -17,7 +17,14 @@ libxfce4mixer_la_SOURCES =						\
 	xfce-mixer-preferences.h					\
 	xfce-mixer-preferences.c					\
 	xfce-mixer-debug.h						\
-	xfce-mixer-debug.c
+	xfce-mixer-debug.c						\
+	audio.h
+
+if XFCE4_MIXER_ALSA
+libxfce4mixer_la_SOURCES +=						\
+	xfce4-mixer-alsa.h						\
+	xfce4-mixer-alsa.c
+endif
 
 libxfce4mixer_la_CPPFLAGS = 						\
 	-I$(top_builddir)						\
@@ -35,7 +42,12 @@ libxfce4mixer_la_CFLAGS = 						\
 	$(LIBXFCE4UI_CFLAGS)						\
 	$(XFCONF_CFLAGS)						\
 	$(DBUS_GLIB_CFLAGS)						\
-	$(GST_PLUGINS_BASE_CFLAGS)
+	$(GST_CFLAGS)
+
+if XFCE4_MIXER_ALSA
+libxfce4mixer_la_CFLAGS += 						\
+	$(ALSA_CFLAGS)
+endif
 
 libxfce4mixer_la_LDFLAGS =						\
 	-no-undefined
@@ -48,6 +60,13 @@ libxfce4mixer_la_LIBADD =						\
 	$(LIBXFCE4UI_LIBS)						\
 	$(XFCONF_LIBS)							\
 	$(DBUS_GLIB_LIBS)						\
-	$(GST_PLUGINS_BASE_LIBS)					\
+	$(GST_LIBS)
+
+if XFCE4_MIXER_ALSA
+libxfce4mixer_la_LIBADD +=						\
+	$(ALSA_LIBS)
+else
+libxfce4mixer_la_LIBADD +=						\
 	-lgstaudio-0.10							\
 	-lgstinterfaces-0.10
+endif
--- a/panel-plugin/Makefile.am
+++ b/panel-plugin/Makefile.am
@@ -27,7 +27,7 @@ libmixer_la_CFLAGS =							\
 	$(LIBXFCE4UI_CFLAGS)						\
 	$(LIBXFCE4PANEL_CFLAGS)						\
 	$(XFCONF_CFLAGS)						\
-	$(GST_PLUGINS_BASE_CFLAGS)					\
+	$(GST_CFLAGS)							\
 	$(KEYBINDER_CFLAGS)
 
 libmixer_la_DEPENDENCIES =						\
@@ -48,11 +48,18 @@ libmixer_la_LIBADD =							\
 	$(LIBXFCE4UI_LIBS)						\
 	$(LIBXFCE4PANEL_LIBS)						\
 	$(XFCONF_LIBS)							\
-	$(GST_PLUGINS_BASE_LIBS)					\
-	-lgstaudio-0.10							\
-	-lgstinterfaces-0.10						\
+	$(GST_LIBS)							\
 	$(KEYBINDER_LIBS)
 
+if XFCE4_MIXER_ALSA
+libmixer_la_LIBADD +=							\
+	$(ALSA_LIBS)
+else
+libmixer_la_LIBADD +=							\
+	-lgstaudio-0.10							\
+	-lgstinterfaces-0.10
+endif
+
 desktopdir = $(datadir)/xfce4/panel/plugins
 
 desktop_in_files = mixer.desktop.in
--- a/xfce4-mixer/Makefile.am
+++ b/xfce4-mixer/Makefile.am
@@ -33,7 +33,7 @@ xfce4_mixer_CFLAGS = 							\
 	$(LIBXFCE4UTIL_CFLAGS)						\
 	$(LIBXFCE4UI_CFLAGS)						\
 	$(XFCONF_CFLAGS)						\
-	$(GST_PLUGINS_BASE_CFLAGS)
+	$(GST_CFLAGS)
 
 xfce4_mixer_DEPENDENCIES = 						\
 	$(top_builddir)/libxfce4mixer/libxfce4mixer.la
@@ -47,9 +47,16 @@ xfce4_mixer_LDFLAGS = 							\
 	$(LIBXFCE4UTIL_LIBS)						\
 	$(LIBXFCE4UI_LIBS)						\
 	$(XFCONF_LIBS)							\
-	$(GST_PLUGINS_BASE_LIBS)					\
+	$(GST_LIBS)
+
+if XFCE4_MIXER_ALSA
+xfce4_mixer_LDFLAGS += 							\
+	$(ALSA_LIBS)
+else
+xfce4_mixer_LDFLAGS += 							\
 	-lgstaudio-0.10							\
 	-lgstinterfaces-0.10
+endif
 
 dist_man_MANS = xfce4-mixer.1
 
--- /dev/null
+++ b/libxfce4mixer/audio.h
@@ -0,0 +1,8 @@
+#ifdef XFCE4_MIXER_ALSA
+#include <gst/gst.h>
+#include "xfce4-mixer-alsa.h"
+#else
+#include <gst/gst.h>
+#include <gst/interfaces/mixer.h>
+#include <gst/audio/mixerutils.h>
+#endif
openSUSE Build Service is sponsored by