xfce4-mixer/xfce4-mixer-4.11.0.20210123git-libalsa-1.2.4.patch

1604 lines
43 KiB
Diff
Raw Normal View History

---
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