summarylogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndreas Benzler2020-01-07 00:08:57 +0100
committerAndreas Benzler2020-01-07 00:08:57 +0100
commit76f3586f87d02bbe1ab1a66b18c01b747bf1d778 (patch)
tree18dda16d68e72e3cd8a353d58e5d217628d7b064
parent9b10623d622799c2f16bf60b9fec68ed32854dea (diff)
downloadaur-76f3586f87d02bbe1ab1a66b18c01b747bf1d778.tar.gz
XFCE4 Mixer update from stable git reference. Include now patches from OpenSuSE gstream -> alsamixer. No gstream 0.10 needed.
-rw-r--r--PKGBUILD24
-rw-r--r--no-full-debug-default-for-git.patch16
-rw-r--r--xfce4-mixer-alsa-git.patch1603
-rw-r--r--xfce4-mixer-dbus-glib.patch36
4 files changed, 1632 insertions, 47 deletions
diff --git a/PKGBUILD b/PKGBUILD
index 8aa506685d7d..de9569b8d37f 100644
--- a/PKGBUILD
+++ b/PKGBUILD
@@ -6,28 +6,30 @@ pkgdesc="A volume control application based on GStreamer"
arch=('i686' 'x86_64' 'mips64el' 'armv6h' 'armv7h' 'arm' 'aarch64')
url="https://git.xfce.org/apps/xfce4-mixer/"
license=('GPL2')
-depends=('xfce4-panel' 'gstreamer0.10-base-plugins>=0.10.25' 'libunique>=1.1')
+depends=('xfce4-panel' 'libunique>=1.1' 'alsa-lib>=1.2.1')
makedepends=('xfce4-dev-tools')
-source=(https://git.xfce.org/apps/xfce4-mixer/snapshot/$pkgname-$pkgver.tar.gz
- xfce4-mixer-dbus-glib.patch)
+source=('git+https://git.xfce.org/apps/xfce4-mixer#commit=ce642ac52e0bed7495261694fd630748bf71157f'
+ xfce4-mixer-alsa-git.patch
+ no-full-debug-default-for-git.patch)
+
+sha256sums=('SKIP'
+ 'd044469a259a86e44dfa107f2b8051774848ef43bc72d0d91220dd40641efeb6'
+ '85d5226a930aae0fa43e6ab8b8dab4f28f3555f40b05f0f8f315d7d4cd60d408')
prepare() {
- cd "$srcdir/$pkgname-$pkgver"
- patch -Np1 -i "${srcdir}/xfce4-mixer-dbus-glib.patch"
+ cd "$srcdir/$pkgname"
+ patch -Np1 -i "${srcdir}/xfce4-mixer-alsa-git.patch"
+ patch -Np1 -i "${srcdir}/no-full-debug-default-for-git.patch"
}
build() {
- cd "$srcdir/$pkgname-$pkgver"
+ cd "$srcdir/$pkgname"
./autogen.sh --localstatedir=/var --prefix=/usr --sysconfdir=/etc
make
}
package ()
{
- cd "$srcdir/$pkgname-$pkgver"
+ cd "$srcdir/$pkgname"
make DESTDIR="$pkgdir" install
}
-
-# vim:set ts=2 sw=2 et:
-sha256sums=('e3e8e8d304834bd2183d681c276e8d51cffb97a2feaad3472289b0c3e1de5267'
- '12e3286f9093889a2bee7647e7ef9179eec0758f9c85f57faa3a9ec06c6db116')
diff --git a/no-full-debug-default-for-git.patch b/no-full-debug-default-for-git.patch
new file mode 100644
index 000000000000..e37557cb6c54
--- /dev/null
+++ b/no-full-debug-default-for-git.patch
@@ -0,0 +1,16 @@
+---
+ configure.ac.in | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/configure.ac.in
++++ b/configure.ac.in
+@@ -32,7 +32,7 @@ m4_define([xfce4_mixer_version], [xfce4_
+ dnl *******************************************
+ dnl *** Debugging support for git snapshots ***
+ dnl *******************************************
+-m4_define([mixer_debug_default], [ifelse(xfce4_mixer_version_tag(), [git], [full], [minimum])])
++m4_define([mixer_debug_default], [minimum])
+
+ dnl ***************************
+ dnl *** Initialize autoconf ***
+
diff --git a/xfce4-mixer-alsa-git.patch b/xfce4-mixer-alsa-git.patch
new file mode 100644
index 000000000000..96c1d70a746e
--- /dev/null
+++ b/xfce4-mixer-alsa-git.patch
@@ -0,0 +1,1603 @@
+---
+ configure.ac.in | 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/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
+@@ -34,7 +34,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
+--- a/configure.ac.in
++++ b/configure.ac.in
+@@ -96,13 +96,29 @@ dnl ***********************************
+ XDT_CHECK_PACKAGE([GLIB], [glib-2.0], [2.42.0])
+ XDT_CHECK_PACKAGE([GTHREAD], [gthread-2.0], [2.42.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+-3.0], [3.14.0])
+ XDT_CHECK_PACKAGE([LIBXFCE4UTIL], [libxfce4util-1.0], [4.12.0])
+ XDT_CHECK_PACKAGE([LIBXFCE4UI], [libxfce4ui-2], [4.12.0])
+ XDT_CHECK_PACKAGE([LIBXFCE4PANEL], [libxfce4panel-2.0], [4.12.0])
+ XDT_CHECK_PACKAGE([XFCONF], [libxfconf-0], [4.12.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
diff --git a/xfce4-mixer-dbus-glib.patch b/xfce4-mixer-dbus-glib.patch
deleted file mode 100644
index 854453853038..000000000000
--- a/xfce4-mixer-dbus-glib.patch
+++ /dev/null
@@ -1,36 +0,0 @@
---- xfce4-mixer-4.11.0/panel-plugin/Makefile.am~ 2014-04-09 19:07:46.000000000 +0000
-+++ xfce4-mixer-4.11.0/panel-plugin/Makefile.am 2018-06-10 20:54:10.332489213 +0000
-@@ -22,6 +22,7 @@
- libmixer_la_CFLAGS = \
- $(PLATFORM_CFLAGS) \
- $(GLIB_CFLAGS) \
-+ $(DBUS_GLIB_CFLAGS) \
- $(GTK_CFLAGS) \
- $(LIBXFCE4UTIL_CFLAGS) \
- $(LIBXFCE4UI_CFLAGS) \
-@@ -42,6 +43,7 @@
- $(PLATFORM_LDFLAGS)
-
- libmixer_la_LIBADD = \
-+ $(DBUS_GLIB_LIBS) \
- $(GLIB_LIBS) \
- $(GTK_LIBS) \
- $(LIBXFCE4UTIL_LIBS) \
---- xfce4-mixer-4.11.0/xfce4-mixer/Makefile.am~ 2014-04-09 19:07:46.000000000 +0000
-+++ xfce4-mixer-4.11.0/xfce4-mixer/Makefile.am 2018-06-10 20:56:41.439687277 +0000
-@@ -27,6 +27,7 @@
- -DG_LOG_DOMAIN=\"xfce4-mixer\"
-
- xfce4_mixer_CFLAGS = \
-+ $(DBUS_GLIB_CFLAGS) \
- $(GLIB_CFLAGS) \
- $(GTK_CFLAGS) \
- $(UNIQUE_CFLAGS) \
-@@ -41,6 +42,7 @@
- xfce4_mixer_LDFLAGS = \
- $(top_builddir)/libxfce4mixer/libxfce4mixer.la \
- $(GLIB_LIBS) \
-+ $(DBUS_GLIB_LIBS) \
- $(GTHREAD_LIBS) \
- $(GTK_LIBS) \
- $(UNIQUE_LIBS) \