summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--backends/Makefile.am8
-rw-r--r--backends/alsa/Makefile.am47
-rw-r--r--backends/alsa/alsa-backend.c508
-rw-r--r--backends/alsa/alsa-backend.h62
-rw-r--r--backends/alsa/alsa-constants.c72
-rw-r--r--backends/alsa/alsa-constants.h35
-rw-r--r--backends/alsa/alsa-device.c941
-rw-r--r--backends/alsa/alsa-device.h74
-rw-r--r--backends/alsa/alsa-element.c53
-rw-r--r--backends/alsa/alsa-element.h61
-rw-r--r--backends/alsa/alsa-stream-control.c739
-rw-r--r--backends/alsa/alsa-stream-control.h111
-rw-r--r--backends/alsa/alsa-stream-input-control.c329
-rw-r--r--backends/alsa/alsa-stream-input-control.h64
-rw-r--r--backends/alsa/alsa-stream-output-control.c329
-rw-r--r--backends/alsa/alsa-stream-output-control.h64
-rw-r--r--backends/alsa/alsa-stream.c273
-rw-r--r--backends/alsa/alsa-stream.h88
-rw-r--r--backends/alsa/alsa-switch-option.c74
-rw-r--r--backends/alsa/alsa-switch-option.h68
-rw-r--r--backends/alsa/alsa-switch.c227
-rw-r--r--backends/alsa/alsa-switch.h65
-rw-r--r--backends/alsa/alsa-toggle.c219
-rw-r--r--backends/alsa/alsa-toggle.h74
-rw-r--r--backends/oss/Makefile.am34
-rw-r--r--backends/oss/oss-backend.c587
-rw-r--r--backends/oss/oss-backend.h63
-rw-r--r--backends/oss/oss-common.h39
-rw-r--r--backends/oss/oss-device.c404
-rw-r--r--backends/oss/oss-device.h77
-rw-r--r--backends/oss/oss-stream-control.c392
-rw-r--r--backends/oss/oss-stream-control.h70
-rw-r--r--backends/oss/oss-stream.c183
-rw-r--r--backends/oss/oss-stream.h74
-rw-r--r--configure.ac75
-rw-r--r--examples/monitor.c302
-rw-r--r--libmatemixer/Makefile.am22
-rw-r--r--libmatemixer/matemixer-backend-module.c149
-rw-r--r--libmatemixer/matemixer-backend-module.h18
-rw-r--r--libmatemixer/matemixer-backend-private.h40
-rw-r--r--libmatemixer/matemixer-backend.c533
-rw-r--r--libmatemixer/matemixer-backend.h131
-rw-r--r--libmatemixer/matemixer-client-stream.c311
-rw-r--r--libmatemixer/matemixer-client-stream.h31
-rw-r--r--libmatemixer/matemixer-context.c (renamed from libmatemixer/matemixer-control.c)895
-rw-r--r--libmatemixer/matemixer-context.h130
-rw-r--r--libmatemixer/matemixer-control.h138
-rw-r--r--libmatemixer/matemixer-device-profile-private.h28
-rw-r--r--libmatemixer/matemixer-device-profile.c66
-rw-r--r--libmatemixer/matemixer-device-profile.h5
-rw-r--r--libmatemixer/matemixer-device.c496
-rw-r--r--libmatemixer/matemixer-device.h63
-rw-r--r--libmatemixer/matemixer-enum-types.c55
-rw-r--r--libmatemixer/matemixer-enum-types.h6
-rw-r--r--libmatemixer/matemixer-enums.h69
-rw-r--r--libmatemixer/matemixer-port-private.h45
-rw-r--r--libmatemixer/matemixer-port.c358
-rw-r--r--libmatemixer/matemixer-port.h68
-rw-r--r--libmatemixer/matemixer-private.h84
-rw-r--r--libmatemixer/matemixer-stream-control-private.h41
-rw-r--r--libmatemixer/matemixer-stream-control.c627
-rw-r--r--libmatemixer/matemixer-stream-control.h160
-rw-r--r--libmatemixer/matemixer-stream.c763
-rw-r--r--libmatemixer/matemixer-stream.h171
-rw-r--r--libmatemixer/matemixer-switch-option-private.h33
-rw-r--r--libmatemixer/matemixer-switch-option.c224
-rw-r--r--libmatemixer/matemixer-switch-option.h64
-rw-r--r--libmatemixer/matemixer-switch-private.h31
-rw-r--r--libmatemixer/matemixer-switch.c283
-rw-r--r--libmatemixer/matemixer-switch.h82
-rw-r--r--libmatemixer/matemixer-toggle.c254
-rw-r--r--libmatemixer/matemixer-toggle.h68
-rw-r--r--libmatemixer/matemixer-types.h35
-rw-r--r--libmatemixer/matemixer.c45
-rw-r--r--libmatemixer/matemixer.h8
75 files changed, 11062 insertions, 2453 deletions
diff --git a/backends/Makefile.am b/backends/Makefile.am
index e223042..4a8afff 100644
--- a/backends/Makefile.am
+++ b/backends/Makefile.am
@@ -8,4 +8,12 @@ if HAVE_PULSEAUDIO
SUBDIRS += pulse
endif
+if HAVE_ALSA
+SUBDIRS += alsa
+endif
+
+if HAVE_OSS
+SUBDIRS += oss
+endif
+
-include $(top_srcdir)/git.mk
diff --git a/backends/alsa/Makefile.am b/backends/alsa/Makefile.am
new file mode 100644
index 0000000..220bb3b
--- /dev/null
+++ b/backends/alsa/Makefile.am
@@ -0,0 +1,47 @@
+backenddir = $(libdir)/libmatemixer
+
+backend_LTLIBRARIES = libmatemixer-alsa.la
+
+AM_CPPFLAGS = \
+ -I$(top_srcdir) \
+ -DG_LOG_DOMAIN=\"libmatemixer-alsa\"
+
+libmatemixer_alsa_la_CFLAGS = \
+ $(GLIB_CFLAGS) \
+ $(ALSA_CFLAGS)
+
+libmatemixer_alsa_la_SOURCES = \
+ alsa-backend.c \
+ alsa-backend.h \
+ alsa-constants.c \
+ alsa-constants.h \
+ alsa-device.c \
+ alsa-device.h \
+ alsa-element.c \
+ alsa-element.h \
+ alsa-stream.c \
+ alsa-stream.h \
+ alsa-stream-control.c \
+ alsa-stream-control.h \
+ alsa-stream-input-control.c \
+ alsa-stream-input-control.h \
+ alsa-stream-output-control.c \
+ alsa-stream-output-control.h \
+ alsa-switch.c \
+ alsa-switch.h \
+ alsa-switch-option.c \
+ alsa-switch-option.h \
+ alsa-toggle.c \
+ alsa-toggle.h
+
+libmatemixer_alsa_la_LIBADD = \
+ $(GLIB_LIBS) \
+ $(ALSA_LIBS)
+
+libmatemixer_alsa_la_LDFLAGS = \
+ -avoid-version \
+ -no-undefined \
+ -export-dynamic \
+ -module
+
+-include $(top_srcdir)/git.mk
diff --git a/backends/alsa/alsa-backend.c b/backends/alsa/alsa-backend.c
new file mode 100644
index 0000000..7a17b85
--- /dev/null
+++ b/backends/alsa/alsa-backend.c
@@ -0,0 +1,508 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the licence, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <glib.h>
+#include <glib-object.h>
+#include <alsa/asoundlib.h>
+
+#include <libmatemixer/matemixer.h>
+#include <libmatemixer/matemixer-private.h>
+
+#include "alsa-backend.h"
+#include "alsa-device.h"
+#include "alsa-stream.h"
+
+#define BACKEND_NAME "ALSA"
+#define BACKEND_PRIORITY 9
+
+struct _AlsaBackendPrivate
+{
+ GSource *timeout_source;
+ GHashTable *devices;
+ GHashTable *devices_ids;
+};
+
+static void alsa_backend_class_init (AlsaBackendClass *klass);
+static void alsa_backend_class_finalize (AlsaBackendClass *klass);
+static void alsa_backend_init (AlsaBackend *alsa);
+static void alsa_backend_dispose (GObject *object);
+static void alsa_backend_finalize (GObject *object);
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunused-function"
+G_DEFINE_DYNAMIC_TYPE (AlsaBackend, alsa_backend, MATE_MIXER_TYPE_BACKEND)
+#pragma clang diagnostic pop
+
+static gboolean alsa_backend_open (MateMixerBackend *backend);
+static void alsa_backend_close (MateMixerBackend *backend);
+static GList * alsa_backend_list_devices (MateMixerBackend *backend);
+static GList * alsa_backend_list_streams (MateMixerBackend *backend);
+
+static gboolean read_devices (AlsaBackend *alsa);
+
+static gboolean read_device (AlsaBackend *alsa,
+ const gchar *card);
+
+static void add_device (AlsaBackend *alsa,
+ AlsaDevice *device);
+
+static void remove_device (AlsaBackend *alsa,
+ AlsaDevice *device);
+static void remove_stream (AlsaBackend *alsa,
+ const gchar *name);
+
+static void select_default_input_stream (AlsaBackend *alsa);
+static void select_default_output_stream (AlsaBackend *alsa);
+
+static MateMixerBackendInfo info;
+
+void
+backend_module_init (GTypeModule *module)
+{
+ alsa_backend_register_type (module);
+
+ info.name = BACKEND_NAME;
+ info.priority = BACKEND_PRIORITY;
+ info.g_type = ALSA_TYPE_BACKEND;
+ info.backend_type = MATE_MIXER_BACKEND_ALSA;
+}
+
+const MateMixerBackendInfo *backend_module_get_info (void)
+{
+ return &info;
+}
+
+static void
+alsa_backend_class_init (AlsaBackendClass *klass)
+{
+ GObjectClass *object_class;
+ MateMixerBackendClass *backend_class;
+
+ object_class = G_OBJECT_CLASS (klass);
+ object_class->dispose = alsa_backend_dispose;
+ object_class->finalize = alsa_backend_finalize;
+
+ backend_class = MATE_MIXER_BACKEND_CLASS (klass);
+ backend_class->open = alsa_backend_open;
+ backend_class->close = alsa_backend_close;
+ backend_class->list_devices = alsa_backend_list_devices;
+ backend_class->list_streams = alsa_backend_list_streams;
+
+ g_type_class_add_private (object_class, sizeof (AlsaBackendPrivate));
+}
+
+/* Called in the code generated by G_DEFINE_DYNAMIC_TYPE() */
+static void
+alsa_backend_class_finalize (AlsaBackendClass *klass)
+{
+}
+
+static void
+alsa_backend_init (AlsaBackend *alsa)
+{
+ alsa->priv = G_TYPE_INSTANCE_GET_PRIVATE (alsa,
+ ALSA_TYPE_BACKEND,
+ AlsaBackendPrivate);
+
+ alsa->priv->devices = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ g_free,
+ g_object_unref);
+
+ alsa->priv->devices_ids = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ g_free,
+ NULL);
+}
+
+static void
+alsa_backend_dispose (GObject *object)
+{
+ MateMixerBackend *backend;
+ MateMixerState state;
+
+ backend = MATE_MIXER_BACKEND (object);
+
+ state = mate_mixer_backend_get_state (backend);
+ if (state != MATE_MIXER_STATE_IDLE)
+ alsa_backend_close (backend);
+
+ G_OBJECT_CLASS (alsa_backend_parent_class)->dispose (object);
+}
+
+static void
+alsa_backend_finalize (GObject *object)
+{
+ AlsaBackend *alsa;
+
+ alsa = ALSA_BACKEND (object);
+
+ g_hash_table_unref (alsa->priv->devices);
+ g_hash_table_unref (alsa->priv->devices_ids);
+
+ G_OBJECT_CLASS (alsa_backend_parent_class)->finalize (object);
+}
+
+static gboolean
+alsa_backend_open (MateMixerBackend *backend)
+{
+ AlsaBackend *alsa;
+
+ g_return_val_if_fail (ALSA_IS_BACKEND (backend), FALSE);
+
+ alsa = ALSA_BACKEND (backend);
+
+ /* Poll ALSA for changes every 500 milliseconds, this actually only
+ * discovers added or changed sound cards, sound card related events
+ * are handled by AlsaDevices */
+ alsa->priv->timeout_source = g_timeout_source_new_seconds (1);
+ g_source_set_callback (alsa->priv->timeout_source,
+ (GSourceFunc) read_devices,
+ alsa,
+ NULL);
+ g_source_attach (alsa->priv->timeout_source,
+ g_main_context_get_thread_default ());
+
+ /* Read the initial list of devices so we have some starting point, there
+ * isn't really a way to detect errors here, failing to add a device may
+ * be a device-related problem so make the backend always open successfully */
+ read_devices (alsa);
+
+ _mate_mixer_backend_set_state (backend, MATE_MIXER_STATE_READY);
+ return TRUE;
+}
+
+void
+alsa_backend_close (MateMixerBackend *backend)
+{
+ AlsaBackend *alsa;
+
+ g_return_if_fail (ALSA_IS_BACKEND (backend));
+
+ alsa = ALSA_BACKEND (backend);
+
+ g_source_destroy (alsa->priv->timeout_source);
+
+ g_hash_table_remove_all (alsa->priv->devices);
+ g_hash_table_remove_all (alsa->priv->devices_ids);
+
+ _mate_mixer_backend_set_state (backend, MATE_MIXER_STATE_IDLE);
+}
+
+static GList *
+alsa_backend_list_devices (MateMixerBackend *backend)
+{
+ GList *list;
+
+ g_return_val_if_fail (ALSA_IS_BACKEND (backend), NULL);
+
+ /* Convert the hash table to a linked list, this list is expected to be
+ * cached in the main library */
+ list = g_hash_table_get_values (ALSA_BACKEND (backend)->priv->devices);
+ if (list != NULL)
+ g_list_foreach (list, (GFunc) g_object_ref, NULL);
+
+ return list;
+}
+
+static GList *
+alsa_backend_list_streams (MateMixerBackend *backend)
+{
+ AlsaBackend *alsa;
+ GHashTableIter iter;
+ gpointer value;
+ GList *list = NULL;
+
+ g_return_val_if_fail (ALSA_IS_BACKEND (backend), NULL);
+
+ alsa = ALSA_BACKEND (backend);
+
+ /* We don't keep a list or hash table of all streams here, instead walk
+ * through the list of devices and create the list manually, each device
+ * has at most one input and one output stream */
+ g_hash_table_iter_init (&iter, alsa->priv->devices);
+
+ while (g_hash_table_iter_next (&iter, NULL, &value)) {
+ AlsaDevice *device = ALSA_DEVICE (value);
+ AlsaStream *stream;
+
+ stream = alsa_device_get_output_stream (device);
+ if (stream != NULL)
+ list = g_list_prepend (list, stream);
+ stream = alsa_device_get_input_stream (device);
+ if (stream != NULL)
+ list = g_list_prepend (list, stream);
+ }
+
+ if (list != NULL)
+ g_list_foreach (list, (GFunc) g_object_ref, NULL);
+
+ return list;
+}
+
+static gboolean
+read_devices (AlsaBackend *alsa)
+{
+ gint num;
+ gint ret;
+ gchar card[16];
+ gboolean changed = FALSE;
+
+ /* Read the default device first, it will be either one of the hardware cards
+ * that will be queried later, or a software mixer */
+ if (read_device (alsa, "default") == TRUE)
+ changed = TRUE;
+
+ for (num = -1;;) {
+ /* Read number of the next sound card */
+ ret = snd_card_next (&num);
+ if (ret < 0 ||
+ num < 0)
+ break;
+
+ g_snprintf (card, sizeof (card), "hw:%d", num);
+
+ if (read_device (alsa, card) == TRUE)
+ changed = TRUE;
+ }
+
+ /* If any card has been added, make sure we have the most suitable default
+ * input and output streams */
+ if (changed == TRUE) {
+ select_default_input_stream (alsa);
+ select_default_output_stream (alsa);
+ }
+ return G_SOURCE_CONTINUE;
+}
+
+static gboolean
+read_device (AlsaBackend *alsa, const gchar *card)
+{
+ AlsaDevice *device;
+ snd_ctl_t *ctl;
+ snd_ctl_card_info_t *info;
+ const gchar *id;
+ gint ret;
+
+ /* The device may be already known, remove it if it's known and fails
+ * to be read, this happens for example when PulseAudio is killed */
+ device = g_hash_table_lookup (alsa->priv->devices, card);
+
+ ret = snd_ctl_open (&ctl, card, 0);
+ if (ret < 0) {
+ g_warning ("Failed to open ALSA control for %s: %s",
+ card,
+ snd_strerror (ret));
+ if (device != NULL)
+ remove_device (alsa, device);
+ return FALSE;
+ }
+
+ snd_ctl_card_info_alloca (&info);
+
+ ret = snd_ctl_card_info (ctl, info);
+ if (ret < 0) {
+ g_warning ("Failed to read card info: %s", snd_strerror (ret));
+ if (device != NULL)
+ remove_device (alsa, device);
+
+ snd_ctl_close (ctl);
+ return FALSE;
+ }
+
+ id = snd_ctl_card_info_get_id (info);
+
+ /* We also keep a list of device identifiers to be sure no card is
+ * added twice, this could commonly happen because some card may
+ * also be assigned to the "default" ALSA device */
+ if (g_hash_table_contains (alsa->priv->devices_ids, id) == TRUE) {
+ snd_ctl_close (ctl);
+ return FALSE;
+ }
+
+ device = alsa_device_new (card, snd_ctl_card_info_get_name (info));
+
+ if (alsa_device_open (device) == FALSE) {
+ g_object_unref (device);
+ snd_ctl_close (ctl);
+ return FALSE;
+ }
+
+ g_object_set_data_full (G_OBJECT (device),
+ "__matemixer_alsa_device_id",
+ g_strdup (id),
+ g_free);
+
+ add_device (alsa, device);
+
+ snd_ctl_close (ctl);
+ return TRUE;
+}
+
+static void
+add_device (AlsaBackend *alsa, AlsaDevice *device)
+{
+ const gchar *name;
+
+ name = mate_mixer_device_get_name (MATE_MIXER_DEVICE (device));
+
+ g_hash_table_insert (alsa->priv->devices,
+ g_strdup (name),
+ g_object_ref (device));
+
+ /* Remember the device identifier, use a single string copy as we only free
+ * the hash table key */
+ g_hash_table_add (alsa->priv->devices_ids,
+ g_strdup (g_object_get_data (G_OBJECT (device),
+ "__matemixer_alsa_device_id")));
+
+ g_signal_connect_swapped (G_OBJECT (device),
+ "closed",
+ G_CALLBACK (remove_device),
+ alsa);
+ g_signal_connect_swapped (G_OBJECT (device),
+ "stream-removed",
+ G_CALLBACK (remove_stream),
+ alsa);
+
+ g_signal_emit_by_name (G_OBJECT (alsa), "device-added", name);
+
+ /* Load the device elements after emitting device-added, because the load
+ * function will most likely emit stream-added on the device and backend */
+ alsa_device_load (device);
+}
+
+static void
+remove_device (AlsaBackend *alsa, AlsaDevice *device)
+{
+ const gchar *name;
+
+ name = mate_mixer_device_get_name (MATE_MIXER_DEVICE (device));
+
+ g_signal_handlers_disconnect_by_func (G_OBJECT (device),
+ G_CALLBACK (remove_device),
+ alsa);
+ g_signal_handlers_disconnect_by_func (G_OBJECT (device),
+ G_CALLBACK (remove_stream),
+ alsa);
+
+ /* Remove the device */
+ g_hash_table_remove (alsa->priv->devices_ids,
+ g_object_get_data (G_OBJECT (device),
+ "__matemixer_alsa_device_id"));
+
+ // XXX close the device and make it remove streams
+ g_hash_table_remove (alsa->priv->devices, name);
+ g_signal_emit_by_name (G_OBJECT (alsa),
+ "device-removed",
+ name);
+}
+
+static void
+remove_stream (AlsaBackend *alsa, const gchar *name)
+{
+ MateMixerStream *stream;
+
+ stream = mate_mixer_backend_get_default_input_stream (MATE_MIXER_BACKEND (alsa));
+
+ // XXX see if the change happens after stream is removed or before
+ if (stream != NULL && strcmp (mate_mixer_stream_get_name (stream), name) == 0)
+ select_default_input_stream (alsa);
+
+ stream = mate_mixer_backend_get_default_output_stream (MATE_MIXER_BACKEND (alsa));
+
+ if (stream != NULL && strcmp (mate_mixer_stream_get_name (stream), name) == 0)
+ select_default_output_stream (alsa);
+}
+
+static void
+select_default_input_stream (AlsaBackend *alsa)
+{
+ AlsaDevice *device;
+ AlsaStream *stream;
+ gchar card[16];
+ gint num;
+
+ /* Always prefer stream in the "default" device */
+ device = g_hash_table_lookup (alsa->priv->devices, "default");
+ if (device != NULL) {
+ stream = alsa_device_get_input_stream (device);
+ if (stream != NULL) {
+ _mate_mixer_backend_set_default_input_stream (MATE_MIXER_BACKEND (alsa),
+ MATE_MIXER_STREAM (stream));
+ return;
+ }
+ }
+
+ /* If there is no input stream in the default device, search the cards in
+ * the correct order */
+ for (num = 0;; num++) {
+ g_snprintf (card, sizeof (card), "hw:%d", num);
+
+ device = g_hash_table_lookup (alsa->priv->devices, card);
+ if (device == NULL)
+ break;
+ stream = alsa_device_get_input_stream (device);
+ if (stream != NULL) {
+ _mate_mixer_backend_set_default_input_stream (MATE_MIXER_BACKEND (alsa),
+ MATE_MIXER_STREAM (stream));
+ return;
+ }
+ }
+
+ /* In the worst case unset the default stream */
+ _mate_mixer_backend_set_default_input_stream (MATE_MIXER_BACKEND (alsa), NULL);
+}
+
+static void
+select_default_output_stream (AlsaBackend *alsa)
+{
+ AlsaDevice *device;
+ AlsaStream *stream;
+ gchar card[16];
+ gint num;
+
+ /* Always prefer stream in the "default" device */
+ device = g_hash_table_lookup (alsa->priv->devices, "default");
+ if (device != NULL) {
+ stream = alsa_device_get_output_stream (device);
+ if (stream != NULL) {
+ _mate_mixer_backend_set_default_output_stream (MATE_MIXER_BACKEND (alsa),
+ MATE_MIXER_STREAM (stream));
+ return;
+ }
+ }
+
+ /* If there is no input stream in the default device, search the cards in
+ * the correct order */
+ for (num = 0;; num++) {
+ g_snprintf (card, sizeof (card), "hw:%d", num);
+
+ device = g_hash_table_lookup (alsa->priv->devices, card);
+ if (device == NULL)
+ break;
+ stream = alsa_device_get_output_stream (device);
+ if (stream != NULL) {
+ _mate_mixer_backend_set_default_output_stream (MATE_MIXER_BACKEND (alsa),
+ MATE_MIXER_STREAM (stream));
+ return;
+ }
+ }
+
+ /* In the worst case unset the default stream */
+ _mate_mixer_backend_set_default_output_stream (MATE_MIXER_BACKEND (alsa), NULL);
+}
diff --git a/backends/alsa/alsa-backend.h b/backends/alsa/alsa-backend.h
new file mode 100644
index 0000000..03fedf0
--- /dev/null
+++ b/backends/alsa/alsa-backend.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the licence, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef ALSA_BACKEND_H
+#define ALSA_BACKEND_H
+
+#include <glib.h>
+#include <glib-object.h>
+#include <libmatemixer/matemixer.h>
+#include <libmatemixer/matemixer-private.h>
+
+#define ALSA_TYPE_BACKEND \
+ (alsa_backend_get_type ())
+#define ALSA_BACKEND(o) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((o), ALSA_TYPE_BACKEND, AlsaBackend))
+#define ALSA_IS_BACKEND(o) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((o), ALSA_TYPE_BACKEND))
+#define ALSA_BACKEND_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_CAST ((k), ALSA_TYPE_BACKEND, AlsaBackendClass))
+#define ALSA_IS_BACKEND_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_TYPE ((k), ALSA_TYPE_BACKEND))
+#define ALSA_BACKEND_GET_CLASS(o) \
+ (G_TYPE_INSTANCE_GET_CLASS ((o), ALSA_TYPE_BACKEND, AlsaBackendClass))
+
+typedef struct _AlsaBackend AlsaBackend;
+typedef struct _AlsaBackendClass AlsaBackendClass;
+typedef struct _AlsaBackendPrivate AlsaBackendPrivate;
+
+struct _AlsaBackend
+{
+ MateMixerBackend parent;
+
+ /*< private >*/
+ AlsaBackendPrivate *priv;
+};
+
+struct _AlsaBackendClass
+{
+ MateMixerBackendClass parent_class;
+};
+
+GType alsa_backend_get_type (void) G_GNUC_CONST;
+
+/* Support function for dynamic loading of the backend module */
+void backend_module_init (GTypeModule *module);
+const MateMixerBackendInfo *backend_module_get_info (void);
+
+#endif /* ALSA_BACKEND_H */
diff --git a/backends/alsa/alsa-constants.c b/backends/alsa/alsa-constants.c
new file mode 100644
index 0000000..2124a2e
--- /dev/null
+++ b/backends/alsa/alsa-constants.c
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the licence, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <alsa/asoundlib.h>
+#include <libmatemixer/matemixer.h>
+
+#include "alsa-constants.h"
+
+// XXX add more and probably move them somewhere else
+const AlsaControlInfo alsa_controls[] =
+{
+ { "Master", N_("Master"), MATE_MIXER_STREAM_CONTROL_ROLE_MASTER },
+ { "Speaker", N_("Speaker"), MATE_MIXER_STREAM_CONTROL_ROLE_MASTER },
+ { "Capture", N_("Capture"), MATE_MIXER_STREAM_CONTROL_ROLE_MASTER },
+ { "PCM", N_("PCM"), MATE_MIXER_STREAM_CONTROL_ROLE_PCM },
+ { "Line", N_("Line"), MATE_MIXER_STREAM_CONTROL_ROLE_PORT },
+ { "Mic", N_("Mic"), MATE_MIXER_STREAM_CONTROL_ROLE_PORT },
+ { NULL }
+};
+
+const MateMixerChannelPosition alsa_channel_map_from[SND_MIXER_SCHN_LAST] =
+{
+ [SND_MIXER_SCHN_FRONT_LEFT] = MATE_MIXER_CHANNEL_FRONT_LEFT,
+ [SND_MIXER_SCHN_FRONT_RIGHT] = MATE_MIXER_CHANNEL_FRONT_RIGHT,
+ [SND_MIXER_SCHN_REAR_LEFT] = MATE_MIXER_CHANNEL_BACK_LEFT,
+ [SND_MIXER_SCHN_REAR_RIGHT] = MATE_MIXER_CHANNEL_BACK_RIGHT,
+ [SND_MIXER_SCHN_FRONT_CENTER] = MATE_MIXER_CHANNEL_FRONT_CENTER,
+ [SND_MIXER_SCHN_WOOFER] = MATE_MIXER_CHANNEL_LFE,
+ [SND_MIXER_SCHN_SIDE_LEFT] = MATE_MIXER_CHANNEL_SIDE_LEFT,
+ [SND_MIXER_SCHN_SIDE_RIGHT] = MATE_MIXER_CHANNEL_SIDE_RIGHT,
+ [SND_MIXER_SCHN_REAR_CENTER] = MATE_MIXER_CHANNEL_BACK_CENTER
+};
+
+const snd_mixer_selem_channel_id_t alsa_channel_map_to[MATE_MIXER_CHANNEL_MAX] =
+{
+ [MATE_MIXER_CHANNEL_UNKNOWN] = SND_MIXER_SCHN_UNKNOWN,
+ [MATE_MIXER_CHANNEL_MONO] = SND_MIXER_SCHN_MONO,
+ [MATE_MIXER_CHANNEL_FRONT_LEFT] = SND_MIXER_SCHN_FRONT_LEFT,
+ [MATE_MIXER_CHANNEL_FRONT_RIGHT] = SND_MIXER_SCHN_FRONT_RIGHT,
+ [MATE_MIXER_CHANNEL_FRONT_CENTER] = SND_MIXER_SCHN_FRONT_CENTER,
+ [MATE_MIXER_CHANNEL_LFE] = SND_MIXER_SCHN_WOOFER,
+ [MATE_MIXER_CHANNEL_BACK_LEFT] = SND_MIXER_SCHN_REAR_LEFT,
+ [MATE_MIXER_CHANNEL_BACK_RIGHT] = SND_MIXER_SCHN_REAR_RIGHT,
+ [MATE_MIXER_CHANNEL_BACK_CENTER] = SND_MIXER_SCHN_REAR_CENTER,
+ [MATE_MIXER_CHANNEL_FRONT_LEFT_CENTER] = SND_MIXER_SCHN_UNKNOWN,
+ [MATE_MIXER_CHANNEL_FRONT_RIGHT_CENTER] = SND_MIXER_SCHN_UNKNOWN,
+ [MATE_MIXER_CHANNEL_SIDE_LEFT] = SND_MIXER_SCHN_SIDE_LEFT,
+ [MATE_MIXER_CHANNEL_SIDE_RIGHT] = SND_MIXER_SCHN_SIDE_RIGHT,
+ [MATE_MIXER_CHANNEL_TOP_FRONT_LEFT] = SND_MIXER_SCHN_UNKNOWN,
+ [MATE_MIXER_CHANNEL_TOP_FRONT_RIGHT] = SND_MIXER_SCHN_UNKNOWN,
+ [MATE_MIXER_CHANNEL_TOP_FRONT_CENTER] = SND_MIXER_SCHN_UNKNOWN,
+ [MATE_MIXER_CHANNEL_TOP_CENTER] = SND_MIXER_SCHN_UNKNOWN,
+ [MATE_MIXER_CHANNEL_TOP_BACK_LEFT] = SND_MIXER_SCHN_UNKNOWN,
+ [MATE_MIXER_CHANNEL_TOP_BACK_RIGHT] = SND_MIXER_SCHN_UNKNOWN,
+ [MATE_MIXER_CHANNEL_TOP_BACK_CENTER] = SND_MIXER_SCHN_UNKNOWN
+};
diff --git a/backends/alsa/alsa-constants.h b/backends/alsa/alsa-constants.h
new file mode 100644
index 0000000..81257c7
--- /dev/null
+++ b/backends/alsa/alsa-constants.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the licence, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef ALSA_CONSTANTS_H
+#define ALSA_CONSTANTS_H
+
+#include <glib.h>
+#include <alsa/asoundlib.h>
+#include <libmatemixer/matemixer.h>
+
+typedef struct {
+ gchar *name;
+ gchar *label;
+ MateMixerStreamControlRole role;
+} AlsaControlInfo;
+
+extern const AlsaControlInfo alsa_controls[];
+extern const MateMixerChannelPosition alsa_channel_map_from[];
+extern const snd_mixer_selem_channel_id_t alsa_channel_map_to[];
+
+#endif /* ALSA_CONSTANTS_H */
diff --git a/backends/alsa/alsa-device.c b/backends/alsa/alsa-device.c
new file mode 100644
index 0000000..5acc6f5
--- /dev/null
+++ b/backends/alsa/alsa-device.c
@@ -0,0 +1,941 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the licence, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <strings.h>
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <glib-object.h>
+#include <alsa/asoundlib.h>
+#include <libmatemixer/matemixer.h>
+
+#include "alsa-constants.h"
+#include "alsa-device.h"
+#include "alsa-element.h"
+#include "alsa-stream.h"
+#include "alsa-stream-control.h"
+#include "alsa-stream-input-control.h"
+#include "alsa-stream-output-control.h"
+#include "alsa-switch.h"
+#include "alsa-switch-option.h"
+#include "alsa-toggle.h"
+
+#define ALSA_DEVICE_ICON "audio-card"
+
+struct _AlsaDevicePrivate
+{
+ snd_mixer_t *handle;
+ GMainContext *context;
+ GMutex mutex;
+ GCond cond;
+ AlsaStream *input;
+ AlsaStream *output;
+ GHashTable *switches;
+ gboolean events_pending;
+};
+
+enum {
+ CLOSED,
+ N_SIGNALS
+};
+
+static guint signals[N_SIGNALS] = { 0, };
+
+static void alsa_device_class_init (AlsaDeviceClass *klass);
+static void alsa_device_init (AlsaDevice *device);
+static void alsa_device_dispose (GObject *object);
+static void alsa_device_finalize (GObject *object);
+
+G_DEFINE_TYPE (AlsaDevice, alsa_device, MATE_MIXER_TYPE_DEVICE)
+
+static MateMixerSwitch *alsa_device_get_switch (MateMixerDevice *mmd,
+ const gchar *name);
+
+static GList * alsa_device_list_streams (MateMixerDevice *mmd);
+static GList * alsa_device_list_switches (MateMixerDevice *mmd);
+
+static gboolean add_stream_input_control (AlsaDevice *device,
+ snd_mixer_elem_t *el);
+static gboolean add_stream_output_control (AlsaDevice *device,
+ snd_mixer_elem_t *el);
+
+static gboolean add_switch (AlsaDevice *device,
+ AlsaStream *stream,
+ snd_mixer_elem_t *el);
+
+static gboolean add_device_switch (AlsaDevice *device,
+ snd_mixer_elem_t *el);
+
+static gboolean add_stream_input_switch (AlsaDevice *device,
+ snd_mixer_elem_t *el);
+static gboolean add_stream_output_switch (AlsaDevice *device,
+ snd_mixer_elem_t *el);
+
+static gboolean add_stream_input_toggle (AlsaDevice *device,
+ snd_mixer_elem_t *el);
+static gboolean add_stream_output_toggle (AlsaDevice *device,
+ snd_mixer_elem_t *el);
+
+static void load_element (AlsaDevice *device,
+ snd_mixer_elem_t *el);
+
+static void load_elements_by_name (AlsaDevice *device,
+ const gchar *name);
+
+static void remove_elements_by_name (AlsaDevice *device,
+ const gchar *name);
+
+static void handle_poll (AlsaDevice *device);
+
+static gboolean handle_process_events (AlsaDevice *device);
+
+static int handle_callback (snd_mixer_t *handle,
+ guint mask,
+ snd_mixer_elem_t *el);
+static int handle_element_callback (snd_mixer_elem_t *el,
+ guint mask);
+
+static void close_device (AlsaDevice *device);
+
+static gchar * get_element_name (snd_mixer_elem_t *el);
+static void get_control_info (snd_mixer_elem_t *el,
+ gchar **name,
+ gchar **label,
+ MateMixerStreamControlRole *role);
+
+static void get_switch_info (snd_mixer_elem_t *el,
+ gchar **name,
+ gchar **label);
+
+static void
+alsa_device_class_init (AlsaDeviceClass *klass)
+{
+ GObjectClass *object_class;
+ MateMixerDeviceClass *device_class;
+
+ object_class = G_OBJECT_CLASS (klass);
+ object_class->dispose = alsa_device_dispose;
+ object_class->finalize = alsa_device_finalize;
+
+ device_class = MATE_MIXER_DEVICE_CLASS (klass);
+ device_class->get_switch = alsa_device_get_switch;
+ device_class->list_streams = alsa_device_list_streams;
+ device_class->list_switches = alsa_device_list_switches;
+
+ signals[CLOSED] =
+ g_signal_new ("closed",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (AlsaDeviceClass, closed),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0,
+ G_TYPE_NONE);
+
+ g_type_class_add_private (object_class, sizeof (AlsaDevicePrivate));
+}
+
+static void
+alsa_device_init (AlsaDevice *device)
+{
+ device->priv = G_TYPE_INSTANCE_GET_PRIVATE (device,
+ ALSA_TYPE_DEVICE,
+ AlsaDevicePrivate);
+
+ device->priv->switches = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ g_free,
+ g_object_unref);
+
+ device->priv->context = g_main_context_ref_thread_default ();
+
+ g_mutex_init (&device->priv->mutex);
+ g_cond_init (&device->priv->cond);
+}
+
+static void
+alsa_device_dispose (GObject *object)
+{
+ AlsaDevice *device;
+
+ device = ALSA_DEVICE (object);
+
+ g_clear_object (&device->priv->input);
+ g_clear_object (&device->priv->output);
+
+ g_hash_table_remove_all (device->priv->switches);
+
+ G_OBJECT_CLASS (alsa_device_parent_class)->dispose (object);
+}
+
+static void
+alsa_device_finalize (GObject *object)
+{
+ AlsaDevice *device;
+
+ device = ALSA_DEVICE (object);
+
+ g_mutex_clear (&device->priv->mutex);
+ g_cond_clear (&device->priv->cond);
+
+ g_hash_table_unref (device->priv->switches);
+ g_main_context_unref (device->priv->context);
+
+ if (device->priv->handle != NULL)
+ snd_mixer_close (device->priv->handle);
+
+ G_OBJECT_CLASS (alsa_device_parent_class)->dispose (object);
+}
+
+AlsaDevice *
+alsa_device_new (const gchar *name, const gchar *label)
+{
+ AlsaDevice *device;
+ gchar *stream_name;
+
+ g_return_val_if_fail (name != NULL, NULL);
+ g_return_val_if_fail (label != NULL, NULL);
+
+ device = g_object_new (ALSA_TYPE_DEVICE,
+ "name", name,
+ "label", label,
+ "icon", ALSA_DEVICE_ICON,
+ NULL);
+
+ /* Create input and output streams, they will exist the whole time, but
+ * the added and removed signals will be emitted when the first control or
+ * switch is added or the last one removed */
+ stream_name = g_strdup_printf ("alsa-input-%s", name);
+ device->priv->input = alsa_stream_new (stream_name,
+ MATE_MIXER_DEVICE (device),
+ MATE_MIXER_STREAM_INPUT);
+ g_free (stream_name);
+
+ stream_name = g_strdup_printf ("alsa-output-%s", name);
+ device->priv->output = alsa_stream_new (stream_name,
+ MATE_MIXER_DEVICE (device),
+ MATE_MIXER_STREAM_OUTPUT);
+ g_free (stream_name);
+
+ return device;
+}
+
+gboolean
+alsa_device_open (AlsaDevice *device)
+{
+ snd_mixer_t *handle;
+ const gchar *name;
+ gint ret;
+
+ g_return_val_if_fail (ALSA_IS_DEVICE (device), FALSE);
+ g_return_val_if_fail (device->priv->handle == NULL, FALSE);
+
+ name = mate_mixer_device_get_name (MATE_MIXER_DEVICE (device));
+
+ g_debug ("Opening device %s (%s)",
+ name,
+ mate_mixer_device_get_label (MATE_MIXER_DEVICE (device)));
+
+ /* Open the mixer for the current device */
+ ret = snd_mixer_open (&handle, 0);
+ if (ret < 0) {
+ g_warning ("Failed to open mixer: %s", snd_strerror (ret));
+ return FALSE;
+ }
+ ret = snd_mixer_attach (handle, name);
+ if (ret < 0) {
+ g_warning ("Failed to attach mixer to %s: %s",
+ name,
+ snd_strerror (ret));
+
+ snd_mixer_close (handle);
+ return FALSE;
+ }
+ ret = snd_mixer_selem_register (handle, NULL, NULL);
+ if (ret < 0) {
+ g_warning ("Failed to register simple element for %s: %s",
+ name,
+ snd_strerror (ret));
+
+ snd_mixer_close (handle);
+ return FALSE;
+ }
+ ret = snd_mixer_load (handle);
+ if (ret < 0) {
+ g_warning ("Failed to load mixer elements for %s: %s",
+ name,
+ snd_strerror (ret));
+
+ snd_mixer_close (handle);
+ return FALSE;
+ }
+
+ device->priv->handle = handle;
+ return TRUE;
+}
+
+void
+alsa_device_load (AlsaDevice *device)
+{
+ GThread *thread;
+ GError *error = NULL;
+ snd_mixer_elem_t *el;
+
+ g_return_if_fail (ALSA_IS_DEVICE (device));
+ g_return_if_fail (device->priv->handle != NULL);
+
+ /* Process the mixer elements */
+ el = snd_mixer_first_elem (device->priv->handle);
+ while (el != NULL) {
+ load_element (device, el);
+
+ el = snd_mixer_elem_next (el);
+ }
+
+ /* Set callback for ALSA events */
+ snd_mixer_set_callback (device->priv->handle, handle_callback);
+ snd_mixer_set_callback_private (device->priv->handle, device);
+
+ /* Start the polling thread */
+ thread = g_thread_try_new ("matemixer-alsa-poll",
+ (GThreadFunc) handle_poll,
+ device,
+ &error);
+ if (thread == NULL) {
+ /* The error is not treated as fatal, because without the polling
+ * thread we still have most of the functionality */
+ g_warning ("Failed to create poll thread: %s", error->message);
+ g_error_free (error);
+ } else
+ g_thread_unref (thread);
+}
+
+AlsaStream *
+alsa_device_get_input_stream (AlsaDevice *device)
+{
+ g_return_val_if_fail (ALSA_IS_DEVICE (device), NULL);
+
+ /* Normally controlless streams should not exist, here we simulate the
+ * behaviour for the owning instance */
+ if (alsa_stream_is_empty (device->priv->input) == FALSE)
+ return device->priv->input;
+
+ return NULL;
+}
+
+AlsaStream *
+alsa_device_get_output_stream (AlsaDevice *device)
+{
+ g_return_val_if_fail (ALSA_IS_DEVICE (device), NULL);
+
+ /* Normally controlless streams should not exist, here we simulate the
+ * behaviour for the owning instance */
+ if (alsa_stream_is_empty (device->priv->output) == FALSE)
+ return device->priv->output;
+
+ return NULL;
+}
+
+static gboolean
+add_element (AlsaDevice *device, AlsaStream *stream, AlsaElement *element)
+{
+ gboolean added = FALSE;
+
+ if (alsa_element_load (element) == FALSE)
+ return FALSE;
+
+ if (stream != NULL) {
+ gboolean empty = FALSE;
+
+ if (alsa_stream_is_empty (stream) == TRUE) {
+ const gchar *name =
+ mate_mixer_stream_get_name (MATE_MIXER_STREAM (stream));
+
+ /* Pretend the stream has just been created now that we are adding
+ * the first control */
+ g_signal_emit_by_name (G_OBJECT (device),
+ "stream-added",
+ name);
+ empty = TRUE;
+ }
+
+ if (ALSA_IS_STREAM_CONTROL (element)) {
+ alsa_stream_add_control (stream, ALSA_STREAM_CONTROL (element));
+
+ /* If this is the first control, set it as the default one.
+ * The controls often seem to come in the order of importance, but this is
+ * driver specific, so we may later see if there is another control which
+ * better matches the default. */
+ if (empty == TRUE)
+ alsa_stream_set_default_control (stream, ALSA_STREAM_CONTROL (element));
+
+ added = TRUE;
+ } else if (ALSA_IS_SWITCH (element)) {
+ /* Switch belonging to a stream */
+ alsa_stream_add_switch (stream, ALSA_SWITCH (element));
+ added = TRUE;
+ }
+ } else if (ALSA_IS_SWITCH (element)) {
+ /* Switch belonging to the device */
+ const gchar *name =
+ mate_mixer_switch_get_name (MATE_MIXER_SWITCH (element));
+
+ g_hash_table_insert (device->priv->switches,
+ g_strdup (name),
+ g_object_ref (element));
+
+ g_signal_emit_by_name (G_OBJECT (device),
+ "switch-added",
+ name);
+ added = TRUE;
+ }
+
+ if G_LIKELY (added == TRUE) {
+ snd_mixer_elem_t *el = alsa_element_get_snd_element (element);
+
+ snd_mixer_elem_set_callback (el, handle_element_callback);
+ snd_mixer_elem_set_callback_private (el, device);
+ }
+ return added;
+}
+
+static MateMixerSwitch *
+alsa_device_get_switch (MateMixerDevice *mmd, const gchar *name)
+{
+ g_return_val_if_fail (ALSA_IS_DEVICE (mmd), NULL);
+ g_return_val_if_fail (name != NULL, NULL);
+
+ return g_hash_table_lookup (ALSA_DEVICE (mmd)->priv->switches, name);
+}
+
+static GList *
+alsa_device_list_streams (MateMixerDevice *mmd)
+{
+ AlsaDevice *device;
+ GList *list = NULL;
+
+ g_return_val_if_fail (ALSA_IS_DEVICE (mmd), NULL);
+
+ device = ALSA_DEVICE (mmd);
+
+ if (device->priv->output != NULL)
+ list = g_list_prepend (list, g_object_ref (device->priv->output));
+ if (device->priv->input != NULL)
+ list = g_list_prepend (list, g_object_ref (device->priv->input));
+
+ return list;
+}
+
+static GList *
+alsa_device_list_switches (MateMixerDevice *mmd)
+{
+ GList *list;
+
+ g_return_val_if_fail (ALSA_IS_DEVICE (mmd), NULL);
+
+ /* Convert the hash table to a linked list, this list is expected to be
+ * cached in the main library */
+ list = g_hash_table_get_values (ALSA_DEVICE (mmd)->priv->switches);
+ if (list != NULL)
+ g_list_foreach (list, (GFunc) g_object_ref, NULL);
+
+ return list;
+}
+
+static gboolean
+add_stream_input_control (AlsaDevice *device, snd_mixer_elem_t *el)
+{
+ AlsaStreamControl *control;
+ gchar *name;
+ gchar *label;
+ MateMixerStreamControlRole role;
+
+ get_control_info (el, &name, &label, &role);
+
+ g_debug ("Found device %s input control %s",
+ mate_mixer_device_get_name (MATE_MIXER_DEVICE (device)),
+ label);
+
+ control = alsa_stream_input_control_new (name, label, role);
+ g_free (name);
+ g_free (label);
+
+ alsa_element_set_snd_element (ALSA_ELEMENT (control), el);
+
+ if (add_element (device, device->priv->input, ALSA_ELEMENT (control)) == FALSE) {
+ g_object_unref (control);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static gboolean
+add_stream_output_control (AlsaDevice *device, snd_mixer_elem_t *el)
+{
+ AlsaStreamControl *control;
+ gchar *label;
+ gchar *name;
+ MateMixerStreamControlRole role;
+
+ get_control_info (el, &name, &label, &role);
+
+ g_debug ("Found device %s output control %s",
+ mate_mixer_device_get_name (MATE_MIXER_DEVICE (device)),
+ label);
+
+ control = alsa_stream_output_control_new (name, label, role);
+ g_free (name);
+ g_free (label);
+
+ alsa_element_set_snd_element (ALSA_ELEMENT (control), el);
+
+ if (add_element (device, device->priv->output, ALSA_ELEMENT (control)) == FALSE) {
+ g_object_unref (control);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static AlsaToggle *
+create_toggle (AlsaDevice *device, snd_mixer_elem_t *el, AlsaToggleType type)
+{
+ AlsaToggle *toggle;
+ AlsaSwitchOption *on;
+ AlsaSwitchOption *off;
+ gchar *name;
+ gchar *label;
+
+ on = alsa_switch_option_new ("On", _("On"), NULL, 1);
+ off = alsa_switch_option_new ("Off", _("Off"), NULL, 0);
+
+ get_switch_info (el, &name, &label);
+ toggle = alsa_toggle_new (name,
+ label,
+ type,
+ on, off);
+ g_free (name);
+ g_free (label);
+
+ alsa_element_set_snd_element (ALSA_ELEMENT (toggle), el);
+
+ g_object_unref (on);
+ g_object_unref (off);
+
+ return toggle;
+}
+
+static gboolean
+add_switch (AlsaDevice *device, AlsaStream *stream, snd_mixer_elem_t *el)
+{
+ AlsaElement *element = NULL;
+ GList *options = NULL;
+ gchar *name;
+ gchar *label;
+ gchar item[128];
+ guint i;
+ gint count;
+ gint ret;
+
+ count = snd_mixer_selem_get_enum_items (el);
+ if G_UNLIKELY (count <= 0) {
+ g_debug ("Skipping mixer switch %s with %d items",
+ snd_mixer_selem_get_name (el),
+ count);
+ return FALSE;
+ }
+
+ for (i = 0; i < count; i++) {
+ ret = snd_mixer_selem_get_enum_item_name (el, i,
+ sizeof (item),
+ item);
+ if G_LIKELY (ret == 0)
+ options = g_list_prepend (options,
+ alsa_switch_option_new (item, item, NULL, i));
+ else
+ g_warning ("Failed to read switch item name: %s", snd_strerror (ret));
+ }
+
+ get_switch_info (el, &name, &label);
+
+ /* Takes ownership of options */
+ element = ALSA_ELEMENT (alsa_switch_new (name, label, g_list_reverse (options)));
+ g_free (name);
+ g_free (label);
+
+ alsa_element_set_snd_element (element, el);
+
+ if (add_element (device, stream, element) == FALSE) {
+ g_object_unref (element);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static gboolean
+add_device_switch (AlsaDevice *device, snd_mixer_elem_t *el)
+{
+ g_debug ("Reading device %s switch %s (%d items)",
+ mate_mixer_device_get_name (MATE_MIXER_DEVICE (device)),
+ snd_mixer_selem_get_name (el),
+ snd_mixer_selem_get_enum_items (el));
+
+ return add_switch (device, NULL, el);
+}
+
+static gboolean
+add_stream_input_switch (AlsaDevice *device, snd_mixer_elem_t *el)
+{
+ g_debug ("Reading device %s input switch %s (%d items)",
+ mate_mixer_device_get_name (MATE_MIXER_DEVICE (device)),
+ snd_mixer_selem_get_name (el),
+ snd_mixer_selem_get_enum_items (el));
+
+ return add_switch (device, device->priv->input, el);
+}
+
+static gboolean
+add_stream_output_switch (AlsaDevice *device, snd_mixer_elem_t *el)
+{
+ g_debug ("Reading device %s output switch %s (%d items)",
+ mate_mixer_device_get_name (MATE_MIXER_DEVICE (device)),
+ snd_mixer_selem_get_name (el),
+ snd_mixer_selem_get_enum_items (el));
+
+ return add_switch (device, device->priv->output, el);
+}
+
+static gboolean
+add_stream_input_toggle (AlsaDevice *device, snd_mixer_elem_t *el)
+{
+ AlsaToggle *toggle;
+
+ g_debug ("Reading device %s input toggle %s",
+ mate_mixer_device_get_name (MATE_MIXER_DEVICE (device)),
+ snd_mixer_selem_get_name (el));
+
+ toggle = create_toggle (device, el, ALSA_TOGGLE_CAPTURE);
+
+ if (add_element (device, device->priv->input, ALSA_ELEMENT (toggle)) == FALSE) {
+ g_object_unref (toggle);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static gboolean
+add_stream_output_toggle (AlsaDevice *device, snd_mixer_elem_t *el)
+{
+ AlsaToggle *toggle;
+
+ g_debug ("Reading device %s output toggle %s",
+ mate_mixer_device_get_name (MATE_MIXER_DEVICE (device)),
+ snd_mixer_selem_get_name (el));
+
+ toggle = create_toggle (device, el, ALSA_TOGGLE_PLAYBACK);
+
+ if (add_element (device, device->priv->output, ALSA_ELEMENT (toggle)) == FALSE) {
+ g_object_unref (toggle);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static void
+load_element (AlsaDevice *device, snd_mixer_elem_t *el)
+{
+ gboolean cvolume = FALSE;
+ gboolean pvolume = FALSE;
+
+ if (snd_mixer_selem_is_enumerated (el) == 1) {
+ gboolean cenum = FALSE;
+ gboolean penum = FALSE;
+
+ if (snd_mixer_selem_is_enum_capture (el) == 1)
+ cenum = TRUE;
+ if (snd_mixer_selem_is_enum_playback (el) == 1)
+ penum = TRUE;
+
+ /* Enumerated controls which are not marked as capture or playback
+ * are considered to be a part of the whole device, although sometimes
+ * this is incorrectly reported by the driver */
+ if (cenum == FALSE && penum == FALSE) {
+ add_device_switch (device, el);
+ }
+ else if (cenum == TRUE)
+ add_stream_input_switch (device, el);
+ else if (penum == TRUE)
+ add_stream_output_switch (device, el);
+ }
+
+ if (snd_mixer_selem_has_capture_volume (el) == 1 ||
+ snd_mixer_selem_has_common_volume (el) == 1)
+ cvolume = TRUE;
+ if (snd_mixer_selem_has_playback_volume (el) == 1 ||
+ snd_mixer_selem_has_common_volume (el) == 1)
+ pvolume = TRUE;
+
+ if (cvolume == FALSE && pvolume == FALSE) {
+ /* Control without volume and with a switch are modelled as toggles */
+ if (snd_mixer_selem_has_capture_switch (el) == 1)
+ add_stream_input_toggle (device, el);
+
+ if (snd_mixer_selem_has_playback_switch (el) == 1)
+ add_stream_output_toggle (device, el);
+ } else {
+ if (cvolume == TRUE)
+ add_stream_input_control (device, el);
+ if (pvolume == TRUE)
+ add_stream_output_control (device, el);
+ }
+}
+
+static void
+load_elements_by_name (AlsaDevice *device, const gchar *name)
+{
+ AlsaElement *element;
+
+ alsa_stream_load_elements (device->priv->input, name);
+ alsa_stream_load_elements (device->priv->output, name);
+
+ element = g_hash_table_lookup (device->priv->switches, name);
+ if (element != NULL)
+ alsa_element_load (element);
+}
+
+static void
+remove_elements_by_name (AlsaDevice *device, const gchar *name)
+{
+ if (alsa_stream_remove_elements (device->priv->input, name) == TRUE) {
+ /* Removing last stream element "removes" the stream */
+ if (alsa_stream_is_empty (device->priv->input) == TRUE) {
+ const gchar *stream_name =
+ mate_mixer_stream_get_name (MATE_MIXER_STREAM (device->priv->input));
+
+ g_signal_emit_by_name (G_OBJECT (device),
+ "stream-removed",
+ stream_name);
+ }
+ }
+
+ if (alsa_stream_remove_elements (device->priv->output, name) == TRUE) {
+ /* Removing last stream element "removes" the stream */
+ if (alsa_stream_is_empty (device->priv->output) == TRUE) {
+ const gchar *stream_name =
+ mate_mixer_stream_get_name (MATE_MIXER_STREAM (device->priv->output));
+
+ g_signal_emit_by_name (G_OBJECT (device),
+ "stream-removed",
+ stream_name);
+ }
+ }
+
+ if (g_hash_table_remove (device->priv->switches, name) == TRUE)
+ g_signal_emit_by_name (G_OBJECT (device),
+ "switch-removed",
+ name);
+}
+
+static void
+handle_poll (AlsaDevice *device)
+{
+ /* This function is called in a worker thread. It is supposed to wait for
+ * ALSA events and call handle_process_events(). Processing the events might
+ * result in emitting the CLOSED signal and unreffing the instance in the
+ * owner, so keep an extra reference during the lifetime of the thread. */
+ g_object_ref (device);
+
+ while (TRUE) {
+ gint ret = snd_mixer_wait (device->priv->handle, -1);
+ if (ret < 0) {
+ if (ret == EINTR)
+ continue;
+ break;
+ }
+
+ device->priv->events_pending = TRUE;
+
+ /* Process the events in the main thread because most events end up
+ * emitting signals */
+ g_main_context_invoke (device->priv->context,
+ (GSourceFunc) handle_process_events,
+ device);
+
+ g_mutex_lock (&device->priv->mutex);
+
+ /* Use a GCond to wait until the events are processed. The processing
+ * function may be called any time later in the main loop and snd_mixer_wait()
+ * returns instantly while there are pending events. Without the wait,
+ * g_main_context_invoke() could be called repeatedly to create idle sources
+ * until the first idle source function is called. */
+ while (device->priv->events_pending == TRUE)
+ g_cond_wait (&device->priv->cond, &device->priv->mutex);
+
+ g_mutex_unlock (&device->priv->mutex);
+
+ /* Exit the thread if the processing function closed the device */
+ if (device->priv->handle == NULL)
+ break;
+ }
+
+ g_debug ("Terminating poll thread for device %s",
+ mate_mixer_device_get_name (MATE_MIXER_DEVICE (device)));
+
+ g_object_unref (device);
+}
+
+static gboolean
+handle_process_events (AlsaDevice *device)
+{
+ g_mutex_lock (&device->priv->mutex);
+
+ if (device->priv->handle != NULL) {
+ gint ret = snd_mixer_handle_events (device->priv->handle);
+ if (ret < 0)
+ close_device (device);
+ }
+
+ device->priv->events_pending = FALSE;
+
+ g_cond_signal (&device->priv->cond);
+ g_mutex_unlock (&device->priv->mutex);
+
+ return G_SOURCE_REMOVE;
+}
+
+/* ALSA has a per-mixer callback and per-element callback, per-mixer callback
+ * is only used for added elements and per-element callback for all the
+ * other messages (no, the documentation doesn't say anything about that). */
+static int
+handle_callback (snd_mixer_t *handle, guint mask, snd_mixer_elem_t *el)
+{
+ if (mask & SND_CTL_EVENT_MASK_ADD) {
+ AlsaDevice *device = snd_mixer_get_callback_private (handle);
+
+ load_element (device, el);
+ }
+ return 0;
+}
+
+static int
+handle_element_callback (snd_mixer_elem_t *el, guint mask)
+{
+ AlsaDevice *device;
+ gchar *name;
+
+ device = snd_mixer_elem_get_callback_private (el);
+ name = get_element_name (el);
+
+ if (mask == SND_CTL_EVENT_MASK_REMOVE) {
+ /* Make sure this function is not called again with the element */
+ snd_mixer_elem_set_callback_private (el, NULL);
+ snd_mixer_elem_set_callback (el, NULL);
+
+ remove_elements_by_name (device, name);
+ } else {
+ if (mask & SND_CTL_EVENT_MASK_INFO) {
+ remove_elements_by_name (device, name);
+ load_element (device, el);
+ }
+ if (mask & SND_CTL_EVENT_MASK_VALUE)
+ load_elements_by_name (device, name);
+ }
+ g_free (name);
+
+ return 0;
+}
+
+static void
+close_device (AlsaDevice *device)
+{
+ if (device->priv->handle != NULL) {
+ snd_mixer_close (device->priv->handle);
+ device->priv->handle = NULL;
+ }
+
+ /* This signal tells the owner that the device has been closed voluntarily
+ * from within the instance */
+ g_signal_emit (G_OBJECT (device), signals[CLOSED], 0);
+}
+
+static gchar *
+get_element_name (snd_mixer_elem_t *el)
+{
+ return g_strdup_printf ("%s-%d",
+ snd_mixer_selem_get_name (el),
+ snd_mixer_selem_get_index (el));
+}
+
+static void
+get_control_info (snd_mixer_elem_t *el,
+ gchar **name,
+ gchar **label,
+ MateMixerStreamControlRole *role)
+{
+ MateMixerStreamControlRole r = MATE_MIXER_STREAM_CONTROL_ROLE_UNKNOWN;
+ const gchar *n;
+ const gchar *l = NULL;
+ gint i;
+
+ n = snd_mixer_selem_get_name (el);
+
+ for (i = 0; alsa_controls[i].name != NULL; i++)
+ if (strcmp (n, alsa_controls[i].name) == 0) {
+ l = alsa_controls[i].label;
+ r = alsa_controls[i].role;
+ break;
+ }
+
+ *name = get_element_name (el);
+ if (l != NULL)
+ *label = g_strdup (l);
+ else
+ *label = g_strdup (n);
+
+ *role = r;
+}
+
+static void
+get_switch_info (snd_mixer_elem_t *el,
+ gchar **name,
+ gchar **label)
+{
+ // MateMixerStreamControlRole r = MATE_MIXER_STREAM_CONTROL_ROLE_UNKNOWN;
+ const gchar *n;
+ const gchar *l = NULL;
+ // gint i;
+
+ n = snd_mixer_selem_get_name (el);
+
+ // TODO provide translated label and flags
+
+/*
+ for (i = 0; alsa_controls[i].name != NULL; i++)
+ if (strcmp (n, alsa_controls[i].name) == 0) {
+ l = alsa_controls[i].label;
+ r = alsa_controls[i].role;
+ break;
+ }
+*/
+ *name = get_element_name (el);
+ if (l != NULL)
+ *label = g_strdup (l);
+ else
+ *label = g_strdup (n);
+
+ // *role = r;
+}
diff --git a/backends/alsa/alsa-device.h b/backends/alsa/alsa-device.h
new file mode 100644
index 0000000..3b3c970
--- /dev/null
+++ b/backends/alsa/alsa-device.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the licence, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef ALSA_DEVICE_H
+#define ALSA_DEVICE_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include "alsa-stream.h"
+
+G_BEGIN_DECLS
+
+#define ALSA_TYPE_DEVICE \
+ (alsa_device_get_type ())
+#define ALSA_DEVICE(o) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((o), ALSA_TYPE_DEVICE, AlsaDevice))
+#define ALSA_IS_DEVICE(o) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((o), ALSA_TYPE_DEVICE))
+#define ALSA_DEVICE_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_CAST ((k), ALSA_TYPE_DEVICE, AlsaDeviceClass))
+#define ALSA_IS_DEVICE_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_TYPE ((k), ALSA_TYPE_DEVICE))
+#define ALSA_DEVICE_GET_CLASS(o) \
+ (G_TYPE_INSTANCE_GET_CLASS ((o), ALSA_TYPE_DEVICE, AlsaDeviceClass))
+
+typedef struct _AlsaDevice AlsaDevice;
+typedef struct _AlsaDeviceClass AlsaDeviceClass;
+typedef struct _AlsaDevicePrivate AlsaDevicePrivate;
+
+struct _AlsaDevice
+{
+ MateMixerDevice parent;
+
+ /*< private >*/
+ AlsaDevicePrivate *priv;
+};
+
+struct _AlsaDeviceClass
+{
+ MateMixerDeviceClass parent_class;
+
+ /*< private >*/
+ void (*closed) (AlsaDevice *device);
+};
+
+GType alsa_device_get_type (void) G_GNUC_CONST;
+
+AlsaDevice *alsa_device_new (const gchar *name,
+ const gchar *label);
+
+gboolean alsa_device_open (AlsaDevice *device);
+void alsa_device_load (AlsaDevice *device);
+
+AlsaStream *alsa_device_get_input_stream (AlsaDevice *device);
+AlsaStream *alsa_device_get_output_stream (AlsaDevice *device);
+
+G_END_DECLS
+
+#endif /* ALSA_DEVICE_H */
diff --git a/backends/alsa/alsa-element.c b/backends/alsa/alsa-element.c
new file mode 100644
index 0000000..f925064
--- /dev/null
+++ b/backends/alsa/alsa-element.c
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the licence, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <glib.h>
+#include <glib-object.h>
+#include <alsa/asoundlib.h>
+
+#include "alsa-element.h"
+
+G_DEFINE_INTERFACE (AlsaElement, alsa_element, G_TYPE_OBJECT)
+
+static void
+alsa_element_default_init (AlsaElementInterface *iface)
+{
+}
+
+snd_mixer_elem_t *
+alsa_element_get_snd_element (AlsaElement *element)
+{
+ g_return_val_if_fail (ALSA_IS_ELEMENT (element), NULL);
+
+ return ALSA_ELEMENT_GET_INTERFACE (element)->get_snd_element (element);
+}
+
+void
+alsa_element_set_snd_element (AlsaElement *element, snd_mixer_elem_t *el)
+{
+ g_return_if_fail (ALSA_IS_ELEMENT (element));
+
+ ALSA_ELEMENT_GET_INTERFACE (element)->set_snd_element (element, el);
+}
+
+gboolean
+alsa_element_load (AlsaElement *element)
+{
+ g_return_val_if_fail (ALSA_IS_ELEMENT (element), FALSE);
+
+ return ALSA_ELEMENT_GET_INTERFACE (element)->load (element);
+}
diff --git a/backends/alsa/alsa-element.h b/backends/alsa/alsa-element.h
new file mode 100644
index 0000000..01d30f1
--- /dev/null
+++ b/backends/alsa/alsa-element.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the licence, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef ALSA_ELEMENT_H
+#define ALSA_ELEMENT_H
+
+#include <glib.h>
+#include <glib-object.h>
+#include <alsa/asoundlib.h>
+
+G_BEGIN_DECLS
+
+#define ALSA_TYPE_ELEMENT \
+ (alsa_element_get_type ())
+#define ALSA_ELEMENT(o) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((o), ALSA_TYPE_ELEMENT, AlsaElement))
+#define ALSA_IS_ELEMENT(o) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((o), ALSA_TYPE_ELEMENT))
+#define ALSA_ELEMENT_GET_INTERFACE(o) \
+ (G_TYPE_INSTANCE_GET_INTERFACE ((o), ALSA_TYPE_ELEMENT, AlsaElementInterface))
+
+typedef struct _AlsaElement AlsaElement; /* dummy object */
+typedef struct _AlsaElementInterface AlsaElementInterface;
+
+struct _AlsaElementInterface
+{
+ GTypeInterface parent_iface;
+
+ /*< private >*/
+ snd_mixer_elem_t *(*get_snd_element) (AlsaElement *element);
+ void (*set_snd_element) (AlsaElement *element,
+ snd_mixer_elem_t *el);
+
+ gboolean (*load) (AlsaElement *element);
+};
+
+GType alsa_element_get_type (void) G_GNUC_CONST;
+
+snd_mixer_elem_t *alsa_element_get_snd_element (AlsaElement *element);
+void alsa_element_set_snd_element (AlsaElement *element,
+ snd_mixer_elem_t *el);
+
+gboolean alsa_element_load (AlsaElement *element);
+
+G_END_DECLS
+
+#endif /* ALSA_ELEMENT_H */
diff --git a/backends/alsa/alsa-stream-control.c b/backends/alsa/alsa-stream-control.c
new file mode 100644
index 0000000..bc7a937
--- /dev/null
+++ b/backends/alsa/alsa-stream-control.c
@@ -0,0 +1,739 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the licence, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <glib.h>
+#include <glib-object.h>
+#include <alsa/asoundlib.h>
+#include <libmatemixer/matemixer.h>
+#include <libmatemixer/matemixer-private.h>
+
+#include "alsa-constants.h"
+#include "alsa-element.h"
+#include "alsa-stream-control.h"
+
+struct _AlsaStreamControlPrivate
+{
+ AlsaControlData data;
+ guint32 channel_mask;
+ snd_mixer_elem_t *element;
+};
+
+static void alsa_element_interface_init (AlsaElementInterface *iface);
+
+static void alsa_stream_control_class_init (AlsaStreamControlClass *klass);
+static void alsa_stream_control_init (AlsaStreamControl *control);
+
+G_DEFINE_ABSTRACT_TYPE_WITH_CODE (AlsaStreamControl, alsa_stream_control,
+ MATE_MIXER_TYPE_STREAM_CONTROL,
+ G_IMPLEMENT_INTERFACE (ALSA_TYPE_ELEMENT,
+ alsa_element_interface_init))
+
+static snd_mixer_elem_t * alsa_stream_control_get_snd_element (AlsaElement *element);
+static void alsa_stream_control_set_snd_element (AlsaElement *element,
+ snd_mixer_elem_t *el);
+
+static gboolean alsa_stream_control_load (AlsaElement *element);
+
+static gboolean alsa_stream_control_set_mute (MateMixerStreamControl *mmsc,
+ gboolean mute);
+
+static guint alsa_stream_control_get_num_channels (MateMixerStreamControl *mmsc);
+
+static guint alsa_stream_control_get_volume (MateMixerStreamControl *mmsc);
+
+static gboolean alsa_stream_control_set_volume (MateMixerStreamControl *mmsc,
+ guint volume);
+
+static gdouble alsa_stream_control_get_decibel (MateMixerStreamControl *mmsc);
+
+static gboolean alsa_stream_control_set_decibel (MateMixerStreamControl *mmsc,
+ gdouble decibel);
+
+static gboolean alsa_stream_control_has_channel_position (MateMixerStreamControl *mmsc,
+ MateMixerChannelPosition position);
+static MateMixerChannelPosition alsa_stream_control_get_channel_position (MateMixerStreamControl *mmsc,
+ guint channel);
+
+static guint alsa_stream_control_get_channel_volume (MateMixerStreamControl *mmsc,
+ guint channel);
+static gboolean alsa_stream_control_set_channel_volume (MateMixerStreamControl *mmsc,
+ guint channel,
+ guint volume);
+
+static gdouble alsa_stream_control_get_channel_decibel (MateMixerStreamControl *mmsc,
+ guint channel);
+static gboolean alsa_stream_control_set_channel_decibel (MateMixerStreamControl *mmsc,
+ guint channel,
+ gdouble decibel);
+
+static gboolean alsa_stream_control_set_balance (MateMixerStreamControl *mmsc,
+ gfloat balance);
+
+static gboolean alsa_stream_control_set_fade (MateMixerStreamControl *mmsc,
+ gfloat fade);
+
+static guint alsa_stream_control_get_min_volume (MateMixerStreamControl *mmsc);
+static guint alsa_stream_control_get_max_volume (MateMixerStreamControl *mmsc);
+static guint alsa_stream_control_get_normal_volume (MateMixerStreamControl *mmsc);
+static guint alsa_stream_control_get_base_volume (MateMixerStreamControl *mmsc);
+
+static void control_data_get_average_left_right (AlsaControlData *data,
+ guint *left,
+ guint *right);
+static void control_data_get_average_front_back (AlsaControlData *data,
+ guint *front,
+ guint *back);
+
+static gfloat control_data_get_balance (AlsaControlData *data);
+static gfloat control_data_get_fade (AlsaControlData *data);
+
+static void
+alsa_element_interface_init (AlsaElementInterface *iface)
+{
+ iface->get_snd_element = alsa_stream_control_get_snd_element;
+ iface->set_snd_element = alsa_stream_control_set_snd_element;
+ iface->load = alsa_stream_control_load;
+}
+
+static void
+alsa_stream_control_class_init (AlsaStreamControlClass *klass)
+{
+ MateMixerStreamControlClass *control_class;
+
+ control_class = MATE_MIXER_STREAM_CONTROL_CLASS (klass);
+
+ control_class->set_mute = alsa_stream_control_set_mute;
+ control_class->get_num_channels = alsa_stream_control_get_num_channels;
+ control_class->get_volume = alsa_stream_control_get_volume;
+ control_class->set_volume = alsa_stream_control_set_volume;
+ control_class->get_decibel = alsa_stream_control_get_decibel;
+ control_class->set_decibel = alsa_stream_control_set_decibel;
+ control_class->has_channel_position = alsa_stream_control_has_channel_position;
+ control_class->get_channel_position = alsa_stream_control_get_channel_position;
+ control_class->get_channel_volume = alsa_stream_control_get_channel_volume;
+ control_class->set_channel_volume = alsa_stream_control_set_channel_volume;
+ control_class->get_channel_decibel = alsa_stream_control_get_channel_decibel;
+ control_class->set_channel_decibel = alsa_stream_control_set_channel_decibel;
+ control_class->set_balance = alsa_stream_control_set_balance;
+ control_class->set_fade = alsa_stream_control_set_fade;
+ control_class->get_min_volume = alsa_stream_control_get_min_volume;
+ control_class->get_max_volume = alsa_stream_control_get_max_volume;
+ control_class->get_normal_volume = alsa_stream_control_get_normal_volume;
+ control_class->get_base_volume = alsa_stream_control_get_base_volume;
+
+ g_type_class_add_private (G_OBJECT_CLASS (klass), sizeof (AlsaStreamControlPrivate));
+}
+
+static void
+alsa_stream_control_init (AlsaStreamControl *control)
+{
+ control->priv = G_TYPE_INSTANCE_GET_PRIVATE (control,
+ ALSA_TYPE_STREAM_CONTROL,
+ AlsaStreamControlPrivate);
+}
+
+AlsaControlData *
+alsa_stream_control_get_data (AlsaStreamControl *control)
+{
+ g_return_val_if_fail (ALSA_IS_STREAM_CONTROL (control), NULL);
+
+ return &control->priv->data;
+}
+
+void
+alsa_stream_control_set_data (AlsaStreamControl *control, AlsaControlData *data)
+{
+ MateMixerStreamControlFlags flags = MATE_MIXER_STREAM_CONTROL_NO_FLAGS;
+ MateMixerStreamControl *mmsc;
+
+ g_return_if_fail (ALSA_IS_STREAM_CONTROL (control));
+ g_return_if_fail (data != NULL);
+
+ mmsc = MATE_MIXER_STREAM_CONTROL (control);
+
+ g_object_freeze_notify (G_OBJECT (control));
+
+ if (data->channels > 0) {
+ if (data->switch_usable == TRUE) {
+ flags |= MATE_MIXER_STREAM_CONTROL_HAS_MUTE;
+ if (data->active == TRUE)
+ flags |= MATE_MIXER_STREAM_CONTROL_CAN_SET_MUTE;
+ }
+ flags |= MATE_MIXER_STREAM_CONTROL_HAS_VOLUME;
+ if (data->active == TRUE)
+ flags |= MATE_MIXER_STREAM_CONTROL_CAN_SET_VOLUME;
+ }
+ if (data->max_decibel > -MATE_MIXER_INFINITY)
+ flags |= MATE_MIXER_STREAM_CONTROL_HAS_DECIBEL;
+
+ control->priv->data = *data;
+ control->priv->channel_mask = _mate_mixer_create_channel_mask (data->c, data->channels);
+
+ if (data->volume_joined == FALSE) {
+ if (MATE_MIXER_CHANNEL_MASK_HAS_LEFT (control->priv->channel_mask) &&
+ MATE_MIXER_CHANNEL_MASK_HAS_RIGHT (control->priv->channel_mask))
+ flags |= MATE_MIXER_STREAM_CONTROL_CAN_BALANCE;
+
+ if (MATE_MIXER_CHANNEL_MASK_HAS_FRONT (control->priv->channel_mask) &&
+ MATE_MIXER_CHANNEL_MASK_HAS_BACK (control->priv->channel_mask))
+ flags |= MATE_MIXER_STREAM_CONTROL_CAN_FADE;
+ }
+
+ _mate_mixer_stream_control_set_flags (mmsc, flags);
+
+ if (data->switch_usable == TRUE) {
+ gboolean mute;
+
+ /* If the mute switch is joined, all the channels get the same value,
+ * otherwise the element has per-channel mute, which we don't support.
+ * In that case, treat the control as unmuted if any channel is
+ * unmuted. */
+ if (data->channels == 1 || data->switch_joined == TRUE) {
+ mute = data->m[0];
+ } else {
+ gint i;
+ mute = TRUE;
+ for (i = 0; i < data->channels; i++)
+ if (data->m[i] == FALSE) {
+ mute = FALSE;
+ break;
+ }
+ }
+ _mate_mixer_stream_control_set_mute (mmsc, mute);
+ } else
+ _mate_mixer_stream_control_set_mute (mmsc, FALSE);
+
+ if (flags & MATE_MIXER_STREAM_CONTROL_CAN_BALANCE)
+ _mate_mixer_stream_control_set_balance (mmsc, control_data_get_balance (data));
+ if (flags & MATE_MIXER_STREAM_CONTROL_CAN_FADE)
+ _mate_mixer_stream_control_set_fade (mmsc, control_data_get_fade (data));
+
+ g_object_thaw_notify (G_OBJECT (control));
+}
+
+static snd_mixer_elem_t *
+alsa_stream_control_get_snd_element (AlsaElement *element)
+{
+ g_return_val_if_fail (ALSA_IS_STREAM_CONTROL (element), NULL);
+
+ return ALSA_STREAM_CONTROL (element)->priv->element;
+}
+
+static void
+alsa_stream_control_set_snd_element (AlsaElement *element, snd_mixer_elem_t *el)
+{
+ g_return_if_fail (ALSA_IS_STREAM_CONTROL (element));
+ g_return_if_fail (el != NULL);
+
+ ALSA_STREAM_CONTROL (element)->priv->element = el;
+}
+
+static gboolean
+alsa_stream_control_load (AlsaElement *element)
+{
+ AlsaStreamControl *control;
+
+ g_return_val_if_fail (ALSA_IS_STREAM_CONTROL (element), FALSE);
+
+ control = ALSA_STREAM_CONTROL (element);
+
+ return ALSA_STREAM_CONTROL_GET_CLASS (control)->load (control);
+}
+
+static gboolean
+alsa_stream_control_set_mute (MateMixerStreamControl *mmsc, gboolean mute)
+{
+ AlsaStreamControl *control;
+ gboolean change = FALSE;
+ gint i;
+
+ g_return_val_if_fail (ALSA_IS_STREAM_CONTROL (mmsc), FALSE);
+
+ control = ALSA_STREAM_CONTROL (mmsc);
+
+ /* If the switch is joined, only verify the first channel */
+ if (control->priv->data.switch_joined == TRUE) {
+ if (control->priv->data.m[0] != mute)
+ change = TRUE;
+ } else {
+ /* Avoid trying to set the mute if all channels are already at the
+ * selected mute value */
+ for (i = 0; i < control->priv->data.channels; i++)
+ if (control->priv->data.m[i] != mute) {
+ change = TRUE;
+ break;
+ }
+ }
+
+ if (change == TRUE) {
+ AlsaStreamControlClass *klass;
+
+ klass = ALSA_STREAM_CONTROL_GET_CLASS (control);
+ if (klass->set_mute (control, mute) == FALSE)
+ return FALSE;
+
+ for (i = 0; i < control->priv->data.channels; i++)
+ control->priv->data.m[i] = mute;
+ }
+ return TRUE;
+}
+
+static guint
+alsa_stream_control_get_num_channels (MateMixerStreamControl *mmsc)
+{
+ g_return_val_if_fail (ALSA_IS_STREAM_CONTROL (mmsc), 0);
+
+ return ALSA_STREAM_CONTROL (mmsc)->priv->data.channels;
+}
+
+static guint
+alsa_stream_control_get_volume (MateMixerStreamControl *mmsc)
+{
+ g_return_val_if_fail (ALSA_IS_STREAM_CONTROL (mmsc), 0);
+
+ return ALSA_STREAM_CONTROL (mmsc)->priv->data.volume;
+}
+
+static gboolean
+alsa_stream_control_set_volume (MateMixerStreamControl *mmsc, guint volume)
+{
+ AlsaStreamControl *control;
+ gboolean change = FALSE;
+ gint i;
+
+ g_return_val_if_fail (ALSA_IS_STREAM_CONTROL (mmsc), FALSE);
+
+ control = ALSA_STREAM_CONTROL (mmsc);
+ volume = CLAMP (volume, control->priv->data.min, control->priv->data.max);
+
+ /* If the volume is joined, only verify the first channel */
+ if (control->priv->data.volume_joined == TRUE) {
+ if (control->priv->data.v[0] != volume)
+ change = TRUE;
+ } else {
+ /* Avoid trying to set the volume if all channels are already at the
+ * selected volume */
+ for (i = 0; i < control->priv->data.channels; i++)
+ if (control->priv->data.v[i] != volume) {
+ change = TRUE;
+ break;
+ }
+ }
+
+ if (change == TRUE) {
+ AlsaStreamControlClass *klass;
+
+ klass = ALSA_STREAM_CONTROL_GET_CLASS (control);
+ if (klass->set_volume (control, volume) == FALSE)
+ return FALSE;
+
+ for (i = 0; i < control->priv->data.channels; i++)
+ control->priv->data.v[i] = volume;
+
+ g_object_notify (G_OBJECT (control), "volume");
+ }
+ return TRUE;
+}
+
+static gdouble
+alsa_stream_control_get_decibel (MateMixerStreamControl *mmsc)
+{
+ AlsaStreamControl *control;
+ AlsaStreamControlClass *klass;
+ guint volume;
+ gdouble decibel;
+
+ g_return_val_if_fail (ALSA_IS_STREAM_CONTROL (mmsc), -MATE_MIXER_INFINITY);
+
+ control = ALSA_STREAM_CONTROL (mmsc);
+ klass = ALSA_STREAM_CONTROL_GET_CLASS (control);
+ volume = alsa_stream_control_get_volume (mmsc);
+
+ if (klass->get_decibel_from_volume (control, volume, &decibel) == FALSE)
+ return FALSE;
+
+ return decibel;
+}
+
+static gboolean
+alsa_stream_control_set_decibel (MateMixerStreamControl *mmsc, gdouble decibel)
+{
+ AlsaStreamControl *control;
+ AlsaStreamControlClass *klass;
+ guint volume;
+
+ g_return_val_if_fail (ALSA_IS_STREAM_CONTROL (mmsc), FALSE);
+
+ control = ALSA_STREAM_CONTROL (mmsc);
+ klass = ALSA_STREAM_CONTROL_GET_CLASS (control);
+
+ if (klass->get_volume_from_decibel (control, decibel, &volume) == FALSE)
+ return FALSE;
+
+ return alsa_stream_control_set_volume (mmsc, volume);
+}
+
+static gboolean
+alsa_stream_control_has_channel_position (MateMixerStreamControl *mmsc,
+ MateMixerChannelPosition position)
+{
+ AlsaStreamControl *control;
+
+ g_return_val_if_fail (ALSA_IS_STREAM_CONTROL (mmsc), FALSE);
+
+ control = ALSA_STREAM_CONTROL (mmsc);
+
+ if MATE_MIXER_CHANNEL_MASK_HAS_CHANNEL (control->priv->channel_mask, position)
+ return TRUE;
+ else
+ return FALSE;
+}
+
+static MateMixerChannelPosition
+alsa_stream_control_get_channel_position (MateMixerStreamControl *mmsc, guint channel)
+{
+ AlsaStreamControl *control;
+
+ g_return_val_if_fail (ALSA_IS_STREAM_CONTROL (mmsc), MATE_MIXER_CHANNEL_UNKNOWN);
+
+ control = ALSA_STREAM_CONTROL (mmsc);
+
+ if (channel >= control->priv->data.channels)
+ return MATE_MIXER_CHANNEL_UNKNOWN;
+
+ return control->priv->data.c[channel];
+}
+
+static guint
+alsa_stream_control_get_channel_volume (MateMixerStreamControl *mmsc, guint channel)
+{
+ AlsaStreamControl *control;
+
+ g_return_val_if_fail (ALSA_IS_STREAM_CONTROL (mmsc), 0);
+
+ control = ALSA_STREAM_CONTROL (mmsc);
+
+ if (channel >= control->priv->data.channels)
+ return FALSE;
+
+ return control->priv->data.v[channel];
+}
+
+static gboolean
+alsa_stream_control_set_channel_volume (MateMixerStreamControl *mmsc, guint channel, guint volume)
+{
+ AlsaStreamControl *control;
+
+ g_return_val_if_fail (ALSA_IS_STREAM_CONTROL (mmsc), FALSE);
+
+ control = ALSA_STREAM_CONTROL (mmsc);
+
+ if (channel >= control->priv->data.channels)
+ return FALSE;
+
+ /* Set volume for all channels at once when channels are joined */
+ if (control->priv->data.volume_joined == TRUE)
+ return alsa_stream_control_set_volume (mmsc, volume);
+
+ if (volume != control->priv->data.v[channel]) {
+ AlsaStreamControlClass *klass;
+
+ /* Convert channel index to ALSA channel position and make sure it is valid */
+ snd_mixer_selem_channel_id_t c = alsa_channel_map_to[control->priv->data.c[channel]];
+ if G_UNLIKELY (c == SND_MIXER_SCHN_UNKNOWN) {
+ g_warn_if_reached ();
+ return FALSE;
+ }
+
+ klass = ALSA_STREAM_CONTROL_GET_CLASS (control);
+ if (klass->set_channel_volume (control, c, volume) == FALSE)
+ return FALSE;
+
+ control->priv->data.v[channel] = volume;
+
+ g_object_notify (G_OBJECT (control), "volume");
+ }
+ return TRUE;
+}
+
+static gdouble
+alsa_stream_control_get_channel_decibel (MateMixerStreamControl *mmsc, guint channel)
+{
+ AlsaStreamControl *control;
+ AlsaStreamControlClass *klass;
+ guint volume;
+ gdouble decibel;
+
+ g_return_val_if_fail (ALSA_IS_STREAM_CONTROL (mmsc), -MATE_MIXER_INFINITY);
+
+ control = ALSA_STREAM_CONTROL (mmsc);
+
+ if (channel >= control->priv->data.channels)
+ return FALSE;
+
+ klass = ALSA_STREAM_CONTROL_GET_CLASS (control);
+ volume = control->priv->data.v[channel];
+
+ if (klass->get_decibel_from_volume (control, volume, &decibel) == FALSE)
+ return FALSE;
+
+ return decibel;
+}
+
+static gboolean
+alsa_stream_control_set_channel_decibel (MateMixerStreamControl *mmsc,
+ guint channel,
+ gdouble decibel)
+{
+ AlsaStreamControl *control;
+ AlsaStreamControlClass *klass;
+ guint volume;
+
+ g_return_val_if_fail (ALSA_IS_STREAM_CONTROL (mmsc), FALSE);
+
+ control = ALSA_STREAM_CONTROL (mmsc);
+ klass = ALSA_STREAM_CONTROL_GET_CLASS (control);
+
+ if (klass->get_volume_from_decibel (control, decibel, &volume) == FALSE)
+ return FALSE;
+
+ return alsa_stream_control_set_channel_volume (mmsc, channel, volume);
+}
+
+static gboolean
+alsa_stream_control_set_balance (MateMixerStreamControl *mmsc, gfloat balance)
+{
+ AlsaStreamControlClass *klass;
+ AlsaStreamControl *control;
+ AlsaControlData *data;
+ guint left,
+ right;
+ guint nleft,
+ nright;
+ guint max;
+ guint channel;
+
+ g_return_val_if_fail (ALSA_IS_STREAM_CONTROL (mmsc), FALSE);
+
+ control = ALSA_STREAM_CONTROL (mmsc);
+ klass = ALSA_STREAM_CONTROL_GET_CLASS (control);
+
+ data = &control->priv->data;
+ control_data_get_average_left_right (data, &left, &right);
+
+ max = MAX (left, right);
+ if (balance <= 0) {
+ nright = (balance + 1.0f) * max;
+ nleft = max;
+ } else {
+ nleft = (1.0f - balance) * max;
+ nright = max;
+ }
+
+ for (channel = 0; channel < data->channels; channel++) {
+ gboolean lc = MATE_MIXER_IS_LEFT_CHANNEL (data->c[channel]);
+ gboolean rc = MATE_MIXER_IS_RIGHT_CHANNEL (data->c[channel]);
+
+ if (lc == TRUE || rc == TRUE) {
+ guint volume;
+ if (lc == TRUE) {
+ if (left == 0)
+ volume = nleft;
+ else
+ volume = CLAMP (((guint64) data->v[channel] * (guint64) nleft) / (guint64) left,
+ data->min,
+ data->max);
+ } else {
+ if (right == 0)
+ volume = nright;
+ else
+ volume = CLAMP (((guint64) data->v[channel] * (guint64) nright) / (guint64) right,
+ data->min,
+ data->max);
+ }
+
+ if (klass->set_channel_volume (control,
+ alsa_channel_map_to[data->c[channel]],
+ volume) == TRUE)
+ data->v[channel] = volume;
+ }
+ }
+ return TRUE;
+}
+
+static gboolean
+alsa_stream_control_set_fade (MateMixerStreamControl *mmsc, gfloat fade)
+{
+ AlsaStreamControlClass *klass;
+ AlsaStreamControl *control;
+ AlsaControlData *data;
+ guint front,
+ back;
+ guint nfront,
+ nback;
+ guint max;
+ guint channel;
+
+ g_return_val_if_fail (ALSA_IS_STREAM_CONTROL (mmsc), FALSE);
+
+ control = ALSA_STREAM_CONTROL (mmsc);
+ klass = ALSA_STREAM_CONTROL_GET_CLASS (control);
+
+ data = &control->priv->data;
+ control_data_get_average_front_back (data, &front, &back);
+
+ max = MAX (front, back);
+ if (fade <= 0) {
+ nback = (fade + 1.0f) * max;
+ nfront = max;
+ } else {
+ nfront = (1.0f - fade) * max;
+ nback = max;
+ }
+
+ for (channel = 0; channel < data->channels; channel++) {
+ gboolean fc = MATE_MIXER_IS_FRONT_CHANNEL (data->c[channel]);
+ gboolean bc = MATE_MIXER_IS_BACK_CHANNEL (data->c[channel]);
+
+ if (fc == TRUE || bc == TRUE) {
+ guint volume;
+ if (fc == TRUE) {
+ if (front == 0)
+ volume = nfront;
+ else
+ volume = CLAMP (((guint64) data->v[channel] * (guint64) nfront) / (guint64) front,
+ data->min,
+ data->max);
+ } else {
+ if (back == 0)
+ volume = nback;
+ else
+ volume = CLAMP (((guint64) data->v[channel] * (guint64) nback) / (guint64) back,
+ data->min,
+ data->max);
+ }
+
+ if (klass->set_channel_volume (control,
+ alsa_channel_map_to[data->c[channel]],
+ volume) == TRUE)
+ data->v[channel] = volume;
+ }
+ }
+ return TRUE;
+}
+
+static guint
+alsa_stream_control_get_min_volume (MateMixerStreamControl *msc)
+{
+ return ALSA_STREAM_CONTROL (msc)->priv->data.min;
+}
+
+static guint
+alsa_stream_control_get_max_volume (MateMixerStreamControl *msc)
+{
+ return ALSA_STREAM_CONTROL (msc)->priv->data.max;
+}
+
+static guint
+alsa_stream_control_get_normal_volume (MateMixerStreamControl *msc)
+{
+ return ALSA_STREAM_CONTROL (msc)->priv->data.max;
+}
+
+static guint
+alsa_stream_control_get_base_volume (MateMixerStreamControl *msc)
+{
+ return ALSA_STREAM_CONTROL (msc)->priv->data.max;
+}
+
+static void
+control_data_get_average_left_right (AlsaControlData *data, guint *left, guint *right)
+{
+ guint l = 0,
+ r = 0;
+ guint nl = 0,
+ nr = 0;
+ guint channel;
+
+ for (channel = 0; channel < data->channels; channel++)
+ if MATE_MIXER_IS_LEFT_CHANNEL (data->c[channel]) {
+ l += data->v[channel];
+ nl++;
+ }
+ else if MATE_MIXER_IS_RIGHT_CHANNEL (data->c[channel]) {
+ r += data->v[channel];
+ nr++;
+ }
+
+ *left = (nl > 0) ? l / nl : data->max;
+ *right = (nr > 0) ? r / nr : data->max;
+}
+
+static void
+control_data_get_average_front_back (AlsaControlData *data, guint *front, guint *back)
+{
+ guint f = 0,
+ b = 0;
+ guint nf = 0,
+ nb = 0;
+ guint channel;
+
+ for (channel = 0; channel < data->channels; channel++)
+ if MATE_MIXER_IS_FRONT_CHANNEL (data->c[channel]) {
+ f += data->v[channel];
+ nf++;
+ }
+ else if MATE_MIXER_IS_RIGHT_CHANNEL (data->c[channel]) {
+ b += data->v[channel];
+ nb++;
+ }
+
+ *front = (nf > 0) ? f / nf : data->max;
+ *back = (nb > 0) ? b / nb : data->max;
+}
+
+static gfloat
+control_data_get_balance (AlsaControlData *data)
+{
+ guint left;
+ guint right;
+
+ control_data_get_average_left_right (data, &left, &right);
+ if (left == right)
+ return 0.0f;
+
+ if (left > right)
+ return -1.0f + ((gfloat) right / (gfloat) left);
+ else
+ return +1.0f - ((gfloat) left / (gfloat) right);
+}
+
+static gfloat
+control_data_get_fade (AlsaControlData *data)
+{
+ guint front;
+ guint back;
+
+ control_data_get_average_front_back (data, &front, &back);
+ if (front == back)
+ return 0.0f;
+
+ if (front > back)
+ return -1.0f + ((gfloat) back / (gfloat) front);
+ else
+ return +1.0f - ((gfloat) front / (gfloat) back);
+}
diff --git a/backends/alsa/alsa-stream-control.h b/backends/alsa/alsa-stream-control.h
new file mode 100644
index 0000000..f9ac6b6
--- /dev/null
+++ b/backends/alsa/alsa-stream-control.h
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the licence, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef ALSA_STREAM_CONTROL_H
+#define ALSA_STREAM_CONTROL_H
+
+#include <glib.h>
+#include <glib-object.h>
+#include <alsa/asoundlib.h>
+#include <libmatemixer/matemixer.h>
+
+G_BEGIN_DECLS
+
+typedef struct {
+ gboolean active;
+ MateMixerChannelPosition c[MATE_MIXER_CHANNEL_MAX];
+ guint v[MATE_MIXER_CHANNEL_MAX];
+ gboolean m[MATE_MIXER_CHANNEL_MAX];
+ guint volume;
+ gboolean volume_joined;
+ gboolean switch_usable;
+ gboolean switch_joined;
+ guint min;
+ guint max;
+ gdouble min_decibel;
+ gdouble max_decibel;
+ guint channels;
+} AlsaControlData;
+
+extern const MateMixerChannelPosition alsa_channel_map_from[SND_MIXER_SCHN_LAST];
+extern const snd_mixer_selem_channel_id_t alsa_channel_map_to[MATE_MIXER_CHANNEL_MAX];
+
+#define ALSA_TYPE_STREAM_CONTROL \
+ (alsa_stream_control_get_type ())
+#define ALSA_STREAM_CONTROL(o) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((o), ALSA_TYPE_STREAM_CONTROL, AlsaStreamControl))
+#define ALSA_IS_STREAM_CONTROL(o) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((o), ALSA_TYPE_STREAM_CONTROL))
+#define ALSA_STREAM_CONTROL_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_CAST ((k), ALSA_TYPE_STREAM_CONTROL, AlsaStreamControlClass))
+#define ALSA_IS_STREAM_CONTROL_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_TYPE ((k), ALSA_TYPE_STREAM_CONTROL))
+#define ALSA_STREAM_CONTROL_GET_CLASS(o) \
+ (G_TYPE_INSTANCE_GET_CLASS ((o), ALSA_TYPE_STREAM_CONTROL, AlsaStreamControlClass))
+
+typedef struct _AlsaStreamControl AlsaStreamControl;
+typedef struct _AlsaStreamControlClass AlsaStreamControlClass;
+typedef struct _AlsaStreamControlPrivate AlsaStreamControlPrivate;
+
+struct _AlsaStreamControl
+{
+ MateMixerStreamControl parent;
+
+ /*< private >*/
+ AlsaStreamControlPrivate *priv;
+
+};
+
+struct _AlsaStreamControlClass
+{
+ MateMixerStreamControlClass parent_class;
+
+ /*< private >*/
+ gboolean (*load) (AlsaStreamControl *control);
+
+ gboolean (*set_mute) (AlsaStreamControl *control,
+ gboolean mute);
+
+ gboolean (*set_volume) (AlsaStreamControl *control,
+ guint volume);
+
+ gboolean (*set_channel_volume) (AlsaStreamControl *control,
+ snd_mixer_selem_channel_id_t channel,
+ guint volume);
+
+ gboolean (*get_volume_from_decibel) (AlsaStreamControl *control,
+ gdouble decibel,
+ guint *volume);
+
+ gboolean (*get_decibel_from_volume) (AlsaStreamControl *control,
+ guint volume,
+ gdouble *decibel);
+};
+
+GType alsa_stream_control_get_type (void) G_GNUC_CONST;
+
+AlsaControlData * alsa_stream_control_get_data (AlsaStreamControl *control);
+
+void alsa_stream_control_set_data (AlsaStreamControl *control,
+ AlsaControlData *data);
+
+gboolean alsa_stream_control_set_role (AlsaStreamControl *control,
+ MateMixerStreamControlRole role);
+
+G_END_DECLS
+
+#endif /* ALSA_STREAM_CONTROL_H */
diff --git a/backends/alsa/alsa-stream-input-control.c b/backends/alsa/alsa-stream-input-control.c
new file mode 100644
index 0000000..2ef0c42
--- /dev/null
+++ b/backends/alsa/alsa-stream-input-control.c
@@ -0,0 +1,329 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the licence, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <glib.h>
+#include <glib-object.h>
+#include <alsa/asoundlib.h>
+
+#include <libmatemixer/matemixer.h>
+#include <libmatemixer/matemixer-private.h>
+
+#include "alsa-element.h"
+#include "alsa-stream-control.h"
+#include "alsa-stream-input-control.h"
+
+static void alsa_stream_input_control_class_init (AlsaStreamInputControlClass *klass);
+static void alsa_stream_input_control_init (AlsaStreamInputControl *control);
+
+G_DEFINE_TYPE (AlsaStreamInputControl, alsa_stream_input_control, ALSA_TYPE_STREAM_CONTROL)
+
+static gboolean alsa_stream_input_control_load (AlsaStreamControl *control);
+
+static gboolean alsa_stream_input_control_set_mute (AlsaStreamControl *control,
+ gboolean mute);
+
+static gboolean alsa_stream_input_control_set_volume (AlsaStreamControl *control,
+ guint volume);
+
+static gboolean alsa_stream_input_control_set_channel_volume (AlsaStreamControl *control,
+ snd_mixer_selem_channel_id_t channel,
+ guint volume);
+
+static gboolean alsa_stream_input_control_get_volume_from_decibel (AlsaStreamControl *control,
+ gdouble decibel,
+ guint *volume);
+
+static gboolean alsa_stream_input_control_get_decibel_from_volume (AlsaStreamControl *control,
+ guint volume,
+ gdouble *decibel);
+
+static void read_volume_data (snd_mixer_elem_t *el,
+ AlsaControlData *data);
+
+static void
+alsa_stream_input_control_class_init (AlsaStreamInputControlClass *klass)
+{
+ AlsaStreamControlClass *control_class;
+
+ control_class = ALSA_STREAM_CONTROL_CLASS (klass);
+
+ control_class->load = alsa_stream_input_control_load;
+ control_class->set_mute = alsa_stream_input_control_set_mute;
+ control_class->set_volume = alsa_stream_input_control_set_volume;
+ control_class->set_channel_volume = alsa_stream_input_control_set_channel_volume;
+ control_class->get_volume_from_decibel = alsa_stream_input_control_get_volume_from_decibel;
+ control_class->get_decibel_from_volume = alsa_stream_input_control_get_decibel_from_volume;
+}
+
+static void
+alsa_stream_input_control_init (AlsaStreamInputControl *control)
+{
+}
+
+AlsaStreamControl *
+alsa_stream_input_control_new (const gchar *name,
+ const gchar *label,
+ MateMixerStreamControlRole role)
+{
+ return g_object_new (ALSA_TYPE_STREAM_INPUT_CONTROL,
+ "name", name,
+ "label", label,
+ "role", role,
+ NULL);
+}
+
+static gboolean
+alsa_stream_input_control_load (AlsaStreamControl *control)
+{
+ AlsaControlData data;
+ snd_mixer_elem_t *el;
+
+ g_return_val_if_fail (ALSA_IS_STREAM_INPUT_CONTROL (control), FALSE);
+
+ el = alsa_element_get_snd_element (ALSA_ELEMENT (control));
+ if G_UNLIKELY (el == NULL)
+ return FALSE;
+
+ /* Expect that the element has a volume control */
+ if G_UNLIKELY (snd_mixer_selem_has_capture_volume (el) == 0 &&
+ snd_mixer_selem_has_common_volume (el) == 0) {
+ g_warn_if_reached ();
+ return FALSE;
+ }
+
+ memset (&data, 0, sizeof (AlsaControlData));
+
+ /* We model any control switch as mute */
+ if (snd_mixer_selem_has_capture_switch (el) == 1 ||
+ snd_mixer_selem_has_common_switch (el) == 1)
+ data.switch_usable = TRUE;
+
+ data.active = snd_mixer_selem_is_active (el);
+
+ /* Read the volume data but do not error out if it fails, since ALSA reports
+ * the control to have a volume, expect the control to match what we need - slider
+ * with an optional mute toggle.
+ * If it fails to read the volume data, just treat it as a volumeless control */
+ read_volume_data (el, &data);
+
+ alsa_stream_control_set_data (control, &data);
+ return TRUE;
+}
+
+static gboolean
+alsa_stream_input_control_set_mute (AlsaStreamControl *control, gboolean mute)
+{
+ snd_mixer_elem_t *el;
+ gint ret;
+
+ g_return_val_if_fail (ALSA_IS_STREAM_CONTROL (control), FALSE);
+
+ el = alsa_element_get_snd_element (ALSA_ELEMENT (control));
+ if G_UNLIKELY (el == NULL)
+ return FALSE;
+
+ /* Set the switch for all channels */
+ ret = snd_mixer_selem_set_capture_switch_all (el, !mute);
+ if (ret < 0) {
+ g_warning ("Failed to set capture switch: %s", snd_strerror (ret));
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static gboolean
+alsa_stream_input_control_set_volume (AlsaStreamControl *control, guint volume)
+{
+ snd_mixer_elem_t *el;
+ gint ret;
+
+ g_return_val_if_fail (ALSA_IS_STREAM_CONTROL (control), FALSE);
+
+ el = alsa_element_get_snd_element (ALSA_ELEMENT (control));
+ if G_UNLIKELY (el == NULL)
+ return FALSE;
+
+ /* Set the volume for all channels */
+ ret = snd_mixer_selem_set_capture_volume_all (el, volume);
+ if (ret < 0) {
+ g_warning ("Failed to set volume: %s", snd_strerror (ret));
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static gboolean
+alsa_stream_input_control_set_channel_volume (AlsaStreamControl *control,
+ snd_mixer_selem_channel_id_t channel,
+ guint volume)
+{
+ snd_mixer_elem_t *el;
+ gint ret;
+
+ g_return_val_if_fail (ALSA_IS_STREAM_CONTROL (control), FALSE);
+
+ el = alsa_element_get_snd_element (ALSA_ELEMENT (control));
+ if G_UNLIKELY (el == NULL)
+ return FALSE;
+
+ /* Set the volume for a single channels, the volume may still be "joined" and
+ * set all the channels by itself */
+ ret = snd_mixer_selem_set_capture_volume (el, channel, volume);
+ if (ret < 0) {
+ g_warning ("Failed to set channel volume: %s", snd_strerror (ret));
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static gboolean
+alsa_stream_input_control_get_volume_from_decibel (AlsaStreamControl *control,
+ gdouble decibel,
+ guint *volume)
+{
+ snd_mixer_elem_t *el;
+ glong value;
+ gint ret;
+
+ g_return_val_if_fail (ALSA_IS_STREAM_CONTROL (control), FALSE);
+
+ el = alsa_element_get_snd_element (ALSA_ELEMENT (control));
+ if G_UNLIKELY (el == NULL)
+ return FALSE;
+
+ ret = snd_mixer_selem_ask_capture_dB_vol (el, (glong) (decibel * 100), 0, &value);
+ if (ret < 0) {
+ g_warning ("Failed to convert volume: %s", snd_strerror (ret));
+ return FALSE;
+ }
+
+ *volume = value;
+ return TRUE;
+}
+
+static gboolean
+alsa_stream_input_control_get_decibel_from_volume (AlsaStreamControl *control,
+ guint volume,
+ gdouble *decibel)
+{
+ snd_mixer_elem_t *el;
+ glong value;
+ gint ret;
+
+ g_return_val_if_fail (ALSA_IS_STREAM_CONTROL (control), FALSE);
+
+ el = alsa_element_get_snd_element (ALSA_ELEMENT (control));
+ if G_UNLIKELY (el == NULL)
+ return FALSE;
+
+ ret = snd_mixer_selem_ask_capture_vol_dB (el, (glong) volume, &value);
+ if (ret < 0) {
+ g_warning ("Failed to convert volume: %s", snd_strerror (ret));
+ return FALSE;
+ }
+
+ *decibel = value / 100.0;
+ return TRUE;
+}
+
+static void
+read_volume_data (snd_mixer_elem_t *el, AlsaControlData *data)
+{
+ glong volume;
+ glong min, max;
+ gint ret;
+ gint i;
+
+ /* Read volume ranges, this call should never fail on valid input */
+ ret = snd_mixer_selem_get_capture_volume_range (el, &min, &max);
+ if G_UNLIKELY (ret < 0) {
+ g_warning ("Failed to read capture volume range: %s", snd_strerror (ret));
+ return;
+ }
+ data->min = (guint) min;
+ data->max = (guint) max;
+
+ /* This fails when decibels are not supported */
+ ret = snd_mixer_selem_get_capture_dB_range (el, &min, &max);
+ if (ret == 0) {
+ data->min_decibel = min / 100.0;
+ data->max_decibel = max / 100.0;
+ } else
+ data->min_decibel = data->max_decibel = -MATE_MIXER_INFINITY;
+
+ for (i = 0; i < MATE_MIXER_CHANNEL_MAX; i++)
+ data->v[i] = data->min;
+
+ data->volume = data->min;
+ data->volume_joined = snd_mixer_selem_has_capture_volume_joined (el);
+
+ if (data->switch_usable == TRUE)
+ data->switch_joined = snd_mixer_selem_has_capture_switch_joined (el);
+
+ if (snd_mixer_selem_is_capture_mono (el) == 1) {
+ /* Special handling for single channel controls */
+ ret = snd_mixer_selem_get_capture_volume (el, SND_MIXER_SCHN_MONO, &volume);
+ if (ret == 0) {
+ data->channels = 1;
+
+ data->c[0] = MATE_MIXER_CHANNEL_MONO;
+ data->v[0] = data->volume = (guint) volume;
+ } else {
+ g_warning ("Failed to read capture volume: %s", snd_strerror (ret));
+ }
+
+ if (data->switch_usable == TRUE) {
+ gint value;
+
+ ret = snd_mixer_selem_get_capture_switch (el, SND_MIXER_SCHN_MONO, &value);
+ if G_LIKELY (ret == 0)
+ data->m[0] = !value;
+ }
+ } else {
+ snd_mixer_selem_channel_id_t channel;
+
+ /* We use numeric channel indices, but ALSA only works with channel
+ * positions, go over all the positions supported by ALSA and create
+ * a list of channels */
+ for (channel = 0; channel < SND_MIXER_SCHN_LAST; channel++) {
+ if (snd_mixer_selem_has_capture_channel (el, channel) == 0)
+ continue;
+
+ if (data->switch_usable == TRUE) {
+ gint value;
+
+ ret = snd_mixer_selem_get_capture_switch (el, channel, &value);
+ if (ret == 0)
+ data->m[channel] = !value;
+ }
+
+ ret = snd_mixer_selem_get_capture_volume (el, channel, &volume);
+ if (ret < 0) {
+ g_warning ("Failed to read capture volume: %s", snd_strerror (ret));
+ continue;
+ }
+ data->channels++;
+
+ /* The single value volume is the highest channel volume */
+ if (data->volume < volume)
+ data->volume = volume;
+
+ data->c[channel] = alsa_channel_map_from[channel];
+ data->v[channel] = (guint) volume;
+ }
+ }
+}
diff --git a/backends/alsa/alsa-stream-input-control.h b/backends/alsa/alsa-stream-input-control.h
new file mode 100644
index 0000000..c427e3c
--- /dev/null
+++ b/backends/alsa/alsa-stream-input-control.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the licence, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef ALSA_STREAM_INPUT_CONTROL_H
+#define ALSA_STREAM_INPUT_CONTROL_H
+
+#include <glib.h>
+#include <glib-object.h>
+#include <libmatemixer/matemixer.h>
+
+#include "alsa-stream-control.h"
+
+G_BEGIN_DECLS
+
+#define ALSA_TYPE_STREAM_INPUT_CONTROL \
+ (alsa_stream_input_control_get_type ())
+#define ALSA_STREAM_INPUT_CONTROL(o) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((o), ALSA_TYPE_STREAM_INPUT_CONTROL, AlsaStreamInputControl))
+#define ALSA_IS_STREAM_INPUT_CONTROL(o) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((o), ALSA_TYPE_STREAM_INPUT_CONTROL))
+#define ALSA_STREAM_INPUT_CONTROL_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_CAST ((k), ALSA_TYPE_STREAM_INPUT_CONTROL, AlsaStreamInputControlClass))
+#define ALSA_IS_STREAM_INPUT_CONTROL_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_TYPE ((k), ALSA_TYPE_STREAM_INPUT_CONTROL))
+#define ALSA_STREAM_INPUT_CONTROL_GET_CLASS(o) \
+ (G_TYPE_INSTANCE_GET_CLASS ((o), ALSA_TYPE_STREAM_INPUT_CONTROL, AlsaStreamInputControlClass))
+
+typedef struct _AlsaStreamInputControl AlsaStreamInputControl;
+typedef struct _AlsaStreamInputControlClass AlsaStreamInputControlClass;
+typedef struct _AlsaStreamInputControlPrivate AlsaStreamInputControlPrivate;
+
+struct _AlsaStreamInputControl
+{
+ AlsaStreamControl parent;
+};
+
+struct _AlsaStreamInputControlClass
+{
+ AlsaStreamControlClass parent_class;
+};
+
+GType alsa_stream_input_control_get_type (void) G_GNUC_CONST;
+
+AlsaStreamControl *alsa_stream_input_control_new (const gchar *name,
+ const gchar *label,
+ MateMixerStreamControlRole role);
+
+G_END_DECLS
+
+#endif /* ALSA_STREAM_INPUT_CONTROL_H */
diff --git a/backends/alsa/alsa-stream-output-control.c b/backends/alsa/alsa-stream-output-control.c
new file mode 100644
index 0000000..5a3e6b3
--- /dev/null
+++ b/backends/alsa/alsa-stream-output-control.c
@@ -0,0 +1,329 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the licence, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <glib.h>
+#include <glib-object.h>
+#include <alsa/asoundlib.h>
+
+#include <libmatemixer/matemixer.h>
+#include <libmatemixer/matemixer-private.h>
+
+#include "alsa-element.h"
+#include "alsa-stream-control.h"
+#include "alsa-stream-output-control.h"
+
+static void alsa_stream_output_control_class_init (AlsaStreamOutputControlClass *klass);
+static void alsa_stream_output_control_init (AlsaStreamOutputControl *control);
+
+G_DEFINE_TYPE (AlsaStreamOutputControl, alsa_stream_output_control, ALSA_TYPE_STREAM_CONTROL)
+
+static gboolean alsa_stream_output_control_load (AlsaStreamControl *control);
+
+static gboolean alsa_stream_output_control_set_mute (AlsaStreamControl *control,
+ gboolean mute);
+
+static gboolean alsa_stream_output_control_set_volume (AlsaStreamControl *control,
+ guint volume);
+
+static gboolean alsa_stream_output_control_set_channel_volume (AlsaStreamControl *control,
+ snd_mixer_selem_channel_id_t channel,
+ guint volume);
+
+static gboolean alsa_stream_output_control_get_volume_from_decibel (AlsaStreamControl *control,
+ gdouble decibel,
+ guint *volume);
+
+static gboolean alsa_stream_output_control_get_decibel_from_volume (AlsaStreamControl *control,
+ guint volume,
+ gdouble *decibel);
+
+static void read_volume_data (snd_mixer_elem_t *el,
+ AlsaControlData *data);
+
+static void
+alsa_stream_output_control_class_init (AlsaStreamOutputControlClass *klass)
+{
+ AlsaStreamControlClass *control_class;
+
+ control_class = ALSA_STREAM_CONTROL_CLASS (klass);
+
+ control_class->load = alsa_stream_output_control_load;
+ control_class->set_mute = alsa_stream_output_control_set_mute;
+ control_class->set_volume = alsa_stream_output_control_set_volume;
+ control_class->set_channel_volume = alsa_stream_output_control_set_channel_volume;
+ control_class->get_volume_from_decibel = alsa_stream_output_control_get_volume_from_decibel;
+ control_class->get_decibel_from_volume = alsa_stream_output_control_get_decibel_from_volume;
+}
+
+static void
+alsa_stream_output_control_init (AlsaStreamOutputControl *control)
+{
+}
+
+AlsaStreamControl *
+alsa_stream_output_control_new (const gchar *name,
+ const gchar *label,
+ MateMixerStreamControlRole role)
+{
+ return g_object_new (ALSA_TYPE_STREAM_OUTPUT_CONTROL,
+ "name", name,
+ "label", label,
+ "role", role,
+ NULL);
+}
+
+static gboolean
+alsa_stream_output_control_load (AlsaStreamControl *control)
+{
+ AlsaControlData data;
+ snd_mixer_elem_t *el;
+
+ g_return_val_if_fail (ALSA_IS_STREAM_OUTPUT_CONTROL (control), FALSE);
+
+ el = alsa_element_get_snd_element (ALSA_ELEMENT (control));
+ if G_UNLIKELY (el == NULL)
+ return FALSE;
+
+ /* Expect that the element has a volume control */
+ if G_UNLIKELY (snd_mixer_selem_has_playback_volume (el) == 0 &&
+ snd_mixer_selem_has_common_volume (el) == 0) {
+ g_warn_if_reached ();
+ return FALSE;
+ }
+
+ memset (&data, 0, sizeof (AlsaControlData));
+
+ /* We model any control switch as mute */
+ if (snd_mixer_selem_has_playback_switch (el) == 1 ||
+ snd_mixer_selem_has_common_switch (el) == 1)
+ data.switch_usable = TRUE;
+
+ data.active = snd_mixer_selem_is_active (el);
+
+ /* Read the volume data but do not error out if it fails, since ALSA reports
+ * the control to have a volume, expect the control to match what we need - slider
+ * with an optional mute toggle.
+ * If it fails to read the volume data, just treat it as a volumeless control */
+ read_volume_data (el, &data);
+
+ alsa_stream_control_set_data (control, &data);
+ return TRUE;
+}
+
+static gboolean
+alsa_stream_output_control_set_mute (AlsaStreamControl *control, gboolean mute)
+{
+ snd_mixer_elem_t *el;
+ gint ret;
+
+ g_return_val_if_fail (ALSA_IS_STREAM_CONTROL (control), FALSE);
+
+ el = alsa_element_get_snd_element (ALSA_ELEMENT (control));
+ if G_UNLIKELY (el == NULL)
+ return FALSE;
+
+ /* Set the switch for all channels */
+ ret = snd_mixer_selem_set_playback_switch_all (el, !mute);
+ if (ret < 0) {
+ g_warning ("Failed to set playback switch: %s", snd_strerror (ret));
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static gboolean
+alsa_stream_output_control_set_volume (AlsaStreamControl *control, guint volume)
+{
+ snd_mixer_elem_t *el;
+ gint ret;
+
+ g_return_val_if_fail (ALSA_IS_STREAM_CONTROL (control), FALSE);
+
+ el = alsa_element_get_snd_element (ALSA_ELEMENT (control));
+ if G_UNLIKELY (el == NULL)
+ return FALSE;
+
+ /* Set the volume for all channels */
+ ret = snd_mixer_selem_set_playback_volume_all (el, volume);
+ if (ret < 0) {
+ g_warning ("Failed to set volume: %s", snd_strerror (ret));
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static gboolean
+alsa_stream_output_control_set_channel_volume (AlsaStreamControl *control,
+ snd_mixer_selem_channel_id_t channel,
+ guint volume)
+{
+ snd_mixer_elem_t *el;
+ gint ret;
+
+ g_return_val_if_fail (ALSA_IS_STREAM_CONTROL (control), FALSE);
+
+ el = alsa_element_get_snd_element (ALSA_ELEMENT (control));
+ if G_UNLIKELY (el == NULL)
+ return FALSE;
+
+ /* Set the volume for a single channels, the volume may still be "joined" and
+ * set all the channels by itself */
+ ret = snd_mixer_selem_set_playback_volume (el, channel, volume);
+ if (ret < 0) {
+ g_warning ("Failed to set channel volume: %s", snd_strerror (ret));
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static gboolean
+alsa_stream_output_control_get_volume_from_decibel (AlsaStreamControl *control,
+ gdouble decibel,
+ guint *volume)
+{
+ snd_mixer_elem_t *el;
+ glong value;
+ gint ret;
+
+ g_return_val_if_fail (ALSA_IS_STREAM_CONTROL (control), FALSE);
+
+ el = alsa_element_get_snd_element (ALSA_ELEMENT (control));
+ if G_UNLIKELY (el == NULL)
+ return FALSE;
+
+ ret = snd_mixer_selem_ask_playback_dB_vol (el, (glong) (decibel * 100), 0, &value);
+ if (ret < 0) {
+ g_warning ("Failed to convert volume: %s", snd_strerror (ret));
+ return FALSE;
+ }
+
+ *volume = value;
+ return TRUE;
+}
+
+static gboolean
+alsa_stream_output_control_get_decibel_from_volume (AlsaStreamControl *control,
+ guint volume,
+ gdouble *decibel)
+{
+ snd_mixer_elem_t *el;
+ glong value;
+ gint ret;
+
+ g_return_val_if_fail (ALSA_IS_STREAM_CONTROL (control), FALSE);
+
+ el = alsa_element_get_snd_element (ALSA_ELEMENT (control));
+ if G_UNLIKELY (el == NULL)
+ return FALSE;
+
+ ret = snd_mixer_selem_ask_playback_vol_dB (el, (glong) volume, &value);
+ if (ret < 0) {
+ g_warning ("Failed to convert volume: %s", snd_strerror (ret));
+ return FALSE;
+ }
+
+ *decibel = value / 100.0;
+ return TRUE;
+}
+
+static void
+read_volume_data (snd_mixer_elem_t *el, AlsaControlData *data)
+{
+ glong volume;
+ glong min, max;
+ gint ret;
+ gint i;
+
+ /* Read volume ranges, this call should never fail on valid input */
+ ret = snd_mixer_selem_get_playback_volume_range (el, &min, &max);
+ if G_UNLIKELY (ret < 0) {
+ g_warning ("Failed to read playback volume range: %s", snd_strerror (ret));
+ return;
+ }
+ data->min = (guint) min;
+ data->max = (guint) max;
+
+ /* This fails when decibels are not supported */
+ ret = snd_mixer_selem_get_playback_dB_range (el, &min, &max);
+ if (ret == 0) {
+ data->min_decibel = min / 100.0;
+ data->max_decibel = max / 100.0;
+ } else
+ data->min_decibel = data->max_decibel = -MATE_MIXER_INFINITY;
+
+ for (i = 0; i < MATE_MIXER_CHANNEL_MAX; i++)
+ data->v[i] = data->min;
+
+ data->volume = data->min;
+ data->volume_joined = snd_mixer_selem_has_playback_volume_joined (el);
+
+ if (data->switch_usable == TRUE)
+ data->switch_joined = snd_mixer_selem_has_playback_switch_joined (el);
+
+ if (snd_mixer_selem_is_playback_mono (el) == 1) {
+ /* Special handling for single channel controls */
+ ret = snd_mixer_selem_get_playback_volume (el, SND_MIXER_SCHN_MONO, &volume);
+ if (ret == 0) {
+ data->channels = 1;
+
+ data->c[0] = MATE_MIXER_CHANNEL_MONO;
+ data->v[0] = data->volume = (guint) volume;
+ } else {
+ g_warning ("Failed to read playback volume: %s", snd_strerror (ret));
+ }
+
+ if (data->switch_usable == TRUE) {
+ gint value;
+
+ ret = snd_mixer_selem_get_playback_switch (el, SND_MIXER_SCHN_MONO, &value);
+ if G_LIKELY (ret == 0)
+ data->m[0] = !value;
+ }
+ } else {
+ snd_mixer_selem_channel_id_t channel;
+
+ /* We use numeric channel indices, but ALSA only works with channel
+ * positions, go over all the positions supported by ALSA and create
+ * a list of channels */
+ for (channel = 0; channel < SND_MIXER_SCHN_LAST; channel++) {
+ if (snd_mixer_selem_has_playback_channel (el, channel) == 0)
+ continue;
+
+ if (data->switch_usable == TRUE) {
+ gint value;
+
+ ret = snd_mixer_selem_get_playback_switch (el, channel, &value);
+ if (ret == 0)
+ data->m[channel] = !value;
+ }
+
+ ret = snd_mixer_selem_get_playback_volume (el, channel, &volume);
+ if (ret < 0) {
+ g_warning ("Failed to read playback volume: %s", snd_strerror (ret));
+ continue;
+ }
+ data->channels++;
+
+ /* The single value volume is the highest channel volume */
+ if (data->volume < volume)
+ data->volume = volume;
+
+ data->c[channel] = alsa_channel_map_from[channel];
+ data->v[channel] = (guint) volume;
+ }
+ }
+}
diff --git a/backends/alsa/alsa-stream-output-control.h b/backends/alsa/alsa-stream-output-control.h
new file mode 100644
index 0000000..845eaae
--- /dev/null
+++ b/backends/alsa/alsa-stream-output-control.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the licence, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef ALSA_STREAM_OUTPUT_CONTROL_H
+#define ALSA_STREAM_OUTPUT_CONTROL_H
+
+#include <glib.h>
+#include <glib-object.h>
+#include <libmatemixer/matemixer.h>
+
+#include "alsa-stream-control.h"
+
+G_BEGIN_DECLS
+
+#define ALSA_TYPE_STREAM_OUTPUT_CONTROL \
+ (alsa_stream_output_control_get_type ())
+#define ALSA_STREAM_OUTPUT_CONTROL(o) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((o), ALSA_TYPE_STREAM_OUTPUT_CONTROL, AlsaStreamOutputControl))
+#define ALSA_IS_STREAM_OUTPUT_CONTROL(o) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((o), ALSA_TYPE_STREAM_OUTPUT_CONTROL))
+#define ALSA_STREAM_OUTPUT_CONTROL_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_CAST ((k), ALSA_TYPE_STREAM_OUTPUT_CONTROL, AlsaStreamOutputControlClass))
+#define ALSA_IS_STREAM_OUTPUT_CONTROL_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_TYPE ((k), ALSA_TYPE_STREAM_OUTPUT_CONTROL))
+#define ALSA_STREAM_OUTPUT_CONTROL_GET_CLASS(o) \
+ (G_TYPE_INSTANCE_GET_CLASS ((o), ALSA_TYPE_STREAM_OUTPUT_CONTROL, AlsaStreamOutputControlClass))
+
+typedef struct _AlsaStreamOutputControl AlsaStreamOutputControl;
+typedef struct _AlsaStreamOutputControlClass AlsaStreamOutputControlClass;
+typedef struct _AlsaStreamOutputControlPrivate AlsaStreamOutputControlPrivate;
+
+struct _AlsaStreamOutputControl
+{
+ AlsaStreamControl parent;
+};
+
+struct _AlsaStreamOutputControlClass
+{
+ AlsaStreamControlClass parent_class;
+};
+
+GType alsa_stream_output_control_get_type (void) G_GNUC_CONST;
+
+AlsaStreamControl *alsa_stream_output_control_new (const gchar *name,
+ const gchar *label,
+ MateMixerStreamControlRole role);
+
+G_END_DECLS
+
+#endif /* ALSA_STREAM_OUTPUT_CONTROL_H */
diff --git a/backends/alsa/alsa-stream.c b/backends/alsa/alsa-stream.c
new file mode 100644
index 0000000..d2f68d4
--- /dev/null
+++ b/backends/alsa/alsa-stream.c
@@ -0,0 +1,273 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the licence, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <glib.h>
+#include <glib-object.h>
+#include <libmatemixer/matemixer.h>
+
+#include "alsa-element.h"
+#include "alsa-stream.h"
+#include "alsa-stream-control.h"
+#include "alsa-switch.h"
+
+struct _AlsaStreamPrivate
+{
+ GHashTable *switches;
+ GHashTable *controls;
+ MateMixerStreamControl *control;
+};
+
+static void alsa_stream_class_init (AlsaStreamClass *klass);
+static void alsa_stream_init (AlsaStream *stream);
+static void alsa_stream_dispose (GObject *object);
+static void alsa_stream_finalize (GObject *object);
+
+G_DEFINE_TYPE (AlsaStream, alsa_stream, MATE_MIXER_TYPE_STREAM)
+
+static MateMixerStreamControl *alsa_stream_get_control (MateMixerStream *mms,
+ const gchar *name);
+static MateMixerStreamControl *alsa_stream_get_default_control (MateMixerStream *mms);
+
+static MateMixerSwitch * alsa_stream_get_switch (MateMixerStream *mms,
+ const gchar *name);
+
+static GList * alsa_stream_list_controls (MateMixerStream *mms);
+static GList * alsa_stream_list_switches (MateMixerStream *mms);
+
+static void
+alsa_stream_class_init (AlsaStreamClass *klass)
+{
+ GObjectClass *object_class;
+ MateMixerStreamClass *stream_class;
+
+ object_class = G_OBJECT_CLASS (klass);
+ object_class->dispose = alsa_stream_dispose;
+ object_class->finalize = alsa_stream_finalize;
+
+ stream_class = MATE_MIXER_STREAM_CLASS (klass);
+ stream_class->get_control = alsa_stream_get_control;
+ stream_class->get_default_control = alsa_stream_get_default_control;
+ stream_class->get_switch = alsa_stream_get_switch;
+ stream_class->list_controls = alsa_stream_list_controls;
+ stream_class->list_switches = alsa_stream_list_switches;
+
+ g_type_class_add_private (object_class, sizeof (AlsaStreamPrivate));
+}
+
+static void
+alsa_stream_init (AlsaStream *stream)
+{
+ stream->priv = G_TYPE_INSTANCE_GET_PRIVATE (stream,
+ ALSA_TYPE_STREAM,
+ AlsaStreamPrivate);
+
+ stream->priv->controls = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ g_free,
+ g_object_unref);
+
+ stream->priv->switches = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ g_free,
+ g_object_unref);
+}
+
+static void
+alsa_stream_dispose (GObject *object)
+{
+ AlsaStream *stream;
+
+ stream = ALSA_STREAM (object);
+
+ g_hash_table_remove_all (stream->priv->controls);
+ g_hash_table_remove_all (stream->priv->switches);
+
+ g_clear_object (&stream->priv->control);
+
+ G_OBJECT_CLASS (alsa_stream_parent_class)->dispose (object);
+}
+
+static void
+alsa_stream_finalize (GObject *object)
+{
+ AlsaStream *stream;
+
+ stream = ALSA_STREAM (object);
+
+ g_hash_table_destroy (stream->priv->controls);
+ g_hash_table_destroy (stream->priv->switches);
+
+ G_OBJECT_CLASS (alsa_stream_parent_class)->finalize (object);
+}
+
+AlsaStream *
+alsa_stream_new (const gchar *name,
+ MateMixerDevice *device,
+ MateMixerStreamFlags flags)
+{
+ return g_object_new (ALSA_TYPE_STREAM,
+ "name", name,
+ "device", device,
+ "flags", flags,
+ NULL);
+}
+
+void
+alsa_stream_add_control (AlsaStream *stream, AlsaStreamControl *control)
+{
+ const gchar *name;
+
+ g_return_if_fail (ALSA_IS_STREAM (stream));
+ g_return_if_fail (ALSA_IS_STREAM_CONTROL (control));
+
+ name = mate_mixer_stream_control_get_name (MATE_MIXER_STREAM_CONTROL (control));
+ g_hash_table_insert (stream->priv->controls,
+ g_strdup (name),
+ g_object_ref (control));
+}
+
+void
+alsa_stream_add_switch (AlsaStream *stream, AlsaSwitch *swtch)
+{
+ const gchar *name;
+
+ g_return_if_fail (ALSA_IS_STREAM (stream));
+ g_return_if_fail (ALSA_IS_SWITCH (swtch));
+
+ name = mate_mixer_switch_get_name (MATE_MIXER_SWITCH (swtch));
+ g_hash_table_insert (stream->priv->switches,
+ g_strdup (name),
+ g_object_ref (swtch));
+}
+
+gboolean
+alsa_stream_is_empty (AlsaStream *stream)
+{
+ g_return_val_if_fail (ALSA_IS_STREAM (stream), FALSE);
+
+ if (g_hash_table_size (stream->priv->controls) > 0 ||
+ g_hash_table_size (stream->priv->switches) > 0)
+ return FALSE;
+
+ return TRUE;
+}
+
+void
+alsa_stream_set_default_control (AlsaStream *stream, AlsaStreamControl *control)
+{
+ g_return_if_fail (ALSA_IS_STREAM (stream));
+ g_return_if_fail (ALSA_IS_STREAM_CONTROL (control));
+
+ /* This function is only used internally so avoid validating that the control
+ * belongs to this stream */
+ if (stream->priv->control != NULL)
+ g_object_unref (stream->priv->control);
+
+ if (control != NULL)
+ stream->priv->control = MATE_MIXER_STREAM_CONTROL (g_object_ref (control));
+ else
+ stream->priv->control = NULL;
+}
+
+void
+alsa_stream_load_elements (AlsaStream *stream, const gchar *name)
+{
+ AlsaElement *element;
+
+ g_return_if_fail (ALSA_IS_STREAM (stream));
+ g_return_if_fail (name != NULL);
+
+ element = g_hash_table_lookup (stream->priv->controls, name);
+ if (element != NULL)
+ alsa_element_load (element);
+
+ element = g_hash_table_lookup (stream->priv->switches, name);
+ if (element != NULL)
+ alsa_element_load (element);
+}
+
+gboolean
+alsa_stream_remove_elements (AlsaStream *stream, const gchar *name)
+{
+ gboolean removed = FALSE;
+
+ g_return_val_if_fail (ALSA_IS_STREAM (stream), FALSE);
+ g_return_val_if_fail (name != NULL, FALSE);
+
+ if (g_hash_table_remove (stream->priv->controls, name) == TRUE)
+ removed = TRUE;
+ if (g_hash_table_remove (stream->priv->switches, name) == TRUE)
+ removed = TRUE;
+
+ return removed;
+}
+
+static MateMixerStreamControl *
+alsa_stream_get_control (MateMixerStream *mms, const gchar *name)
+{
+ g_return_val_if_fail (ALSA_IS_STREAM (mms), NULL);
+
+ return g_hash_table_lookup (ALSA_STREAM (mms)->priv->controls, name);
+}
+
+static MateMixerStreamControl *
+alsa_stream_get_default_control (MateMixerStream *mms)
+{
+ g_return_val_if_fail (ALSA_IS_STREAM (mms), NULL);
+
+ return ALSA_STREAM (mms)->priv->control;
+}
+
+static MateMixerSwitch *
+alsa_stream_get_switch (MateMixerStream *mms, const gchar *name)
+{
+ g_return_val_if_fail (ALSA_IS_STREAM (mms), NULL);
+
+ return g_hash_table_lookup (ALSA_STREAM (mms)->priv->switches, name);
+}
+
+static GList *
+alsa_stream_list_controls (MateMixerStream *mms)
+{
+ GList *list;
+
+ g_return_val_if_fail (ALSA_IS_STREAM (mms), NULL);
+
+ /* Convert the hash table to a linked list, this list is expected to be
+ * cached in the main library */
+ list = g_hash_table_get_values (ALSA_STREAM (mms)->priv->controls);
+ if (list != NULL)
+ g_list_foreach (list, (GFunc) g_object_ref, NULL);
+
+ return list;
+}
+
+static GList *
+alsa_stream_list_switches (MateMixerStream *mms)
+{
+ GList *list;
+
+ g_return_val_if_fail (ALSA_IS_STREAM (mms), NULL);
+
+ /* Convert the hash table to a linked list, this list is expected to be
+ * cached in the main library */
+ list = g_hash_table_get_values (ALSA_STREAM (mms)->priv->switches);
+ if (list != NULL)
+ g_list_foreach (list, (GFunc) g_object_ref, NULL);
+
+ return list;
+}
diff --git a/backends/alsa/alsa-stream.h b/backends/alsa/alsa-stream.h
new file mode 100644
index 0000000..f26a643
--- /dev/null
+++ b/backends/alsa/alsa-stream.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the licence, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef ALSA_STREAM_H
+#define ALSA_STREAM_H
+
+#include <glib.h>
+#include <glib-object.h>
+#include <libmatemixer/matemixer.h>
+
+#include "alsa-element.h"
+#include "alsa-stream-control.h"
+#include "alsa-switch.h"
+
+G_BEGIN_DECLS
+
+#define ALSA_TYPE_STREAM \
+ (alsa_stream_get_type ())
+#define ALSA_STREAM(o) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((o), ALSA_TYPE_STREAM, AlsaStream))
+#define ALSA_IS_STREAM(o) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((o), ALSA_TYPE_STREAM))
+#define ALSA_STREAM_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_CAST ((k), ALSA_TYPE_STREAM, AlsaStreamClass))
+#define ALSA_IS_STREAM_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_TYPE ((k), ALSA_TYPE_STREAM))
+#define ALSA_STREAM_GET_CLASS(o) \
+ (G_TYPE_INSTANCE_GET_CLASS ((o), ALSA_TYPE_STREAM, AlsaStreamClass))
+
+typedef struct _AlsaStream AlsaStream;
+typedef struct _AlsaStreamClass AlsaStreamClass;
+typedef struct _AlsaStreamPrivate AlsaStreamPrivate;
+
+struct _AlsaStream
+{
+ MateMixerStream parent;
+
+ /*< private >*/
+ AlsaStreamPrivate *priv;
+};
+
+struct _AlsaStreamClass
+{
+ MateMixerStreamClass parent_class;
+};
+
+GType alsa_stream_get_type (void) G_GNUC_CONST;
+
+AlsaStream *alsa_stream_new (const gchar *name,
+ MateMixerDevice *device,
+ MateMixerStreamFlags flags);
+
+void alsa_stream_add_control (AlsaStream *stream,
+ AlsaStreamControl *control);
+
+void alsa_stream_add_switch (AlsaStream *stream,
+ AlsaSwitch *swtch);
+
+gboolean alsa_stream_is_empty (AlsaStream *stream);
+
+void alsa_stream_set_default_control (AlsaStream *stream,
+ AlsaStreamControl *control);
+
+void alsa_stream_load_elements (AlsaStream *stream,
+ const gchar *name);
+
+gboolean alsa_stream_remove_elements (AlsaStream *stream,
+ const gchar *name);
+
+void alsa_stream_remove_all (AlsaStream *stream);
+
+G_END_DECLS
+
+#endif /* ALSA_STREAM_H */
diff --git a/backends/alsa/alsa-switch-option.c b/backends/alsa/alsa-switch-option.c
new file mode 100644
index 0000000..2173113
--- /dev/null
+++ b/backends/alsa/alsa-switch-option.c
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the licence, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <glib.h>
+#include <glib-object.h>
+#include <alsa/asoundlib.h>
+
+#include <libmatemixer/matemixer.h>
+#include <libmatemixer/matemixer-private.h>
+
+#include "alsa-switch-option.h"
+
+struct _AlsaSwitchOptionPrivate
+{
+ guint id;
+};
+
+static void alsa_switch_option_class_init (AlsaSwitchOptionClass *klass);
+static void alsa_switch_option_init (AlsaSwitchOption *option);
+
+G_DEFINE_TYPE (AlsaSwitchOption, alsa_switch_option, MATE_MIXER_TYPE_SWITCH_OPTION)
+
+static void
+alsa_switch_option_class_init (AlsaSwitchOptionClass *klass)
+{
+ g_type_class_add_private (G_OBJECT_CLASS (klass), sizeof (AlsaSwitchOptionPrivate));
+}
+
+static void
+alsa_switch_option_init (AlsaSwitchOption *option)
+{
+ option->priv = G_TYPE_INSTANCE_GET_PRIVATE (option,
+ ALSA_TYPE_SWITCH_OPTION,
+ AlsaSwitchOptionPrivate);
+}
+
+AlsaSwitchOption *
+alsa_switch_option_new (const gchar *name,
+ const gchar *label,
+ const gchar *icon,
+ guint id)
+{
+ AlsaSwitchOption *option;
+
+ option = g_object_new (ALSA_TYPE_SWITCH_OPTION,
+ "name", name,
+ "label", label,
+ NULL);
+
+ option->priv->id = id;
+ return option;
+}
+
+guint
+alsa_switch_option_get_id (AlsaSwitchOption *option)
+{
+ g_return_val_if_fail (ALSA_IS_SWITCH_OPTION (option), 0);
+
+ return option->priv->id;
+}
diff --git a/backends/alsa/alsa-switch-option.h b/backends/alsa/alsa-switch-option.h
new file mode 100644
index 0000000..c2dda87
--- /dev/null
+++ b/backends/alsa/alsa-switch-option.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the licence, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef ALSA_SWITCH_OPTION_H
+#define ALSA_SWITCH_OPTION_H
+
+#include <glib.h>
+#include <glib-object.h>
+#include <libmatemixer/matemixer.h>
+
+G_BEGIN_DECLS
+
+#define ALSA_TYPE_SWITCH_OPTION \
+ (alsa_switch_option_get_type ())
+#define ALSA_SWITCH_OPTION(o) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((o), ALSA_TYPE_SWITCH_OPTION, AlsaSwitchOption))
+#define ALSA_IS_SWITCH_OPTION(o) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((o), ALSA_TYPE_SWITCH_OPTION))
+#define ALSA_SWITCH_OPTION_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_CAST ((k), ALSA_TYPE_SWITCH_OPTION, AlsaSwitchOptionClass))
+#define ALSA_IS_SWITCH_OPTION_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_TYPE ((k), ALSA_TYPE_SWITCH_OPTION))
+#define ALSA_SWITCH_OPTION_GET_CLASS(o) \
+ (G_TYPE_INSTANCE_GET_CLASS ((o), ALSA_TYPE_SWITCH_OPTION, AlsaSwitchOptionClass))
+
+typedef struct _AlsaSwitchOption AlsaSwitchOption;
+typedef struct _AlsaSwitchOptionClass AlsaSwitchOptionClass;
+typedef struct _AlsaSwitchOptionPrivate AlsaSwitchOptionPrivate;
+
+struct _AlsaSwitchOption
+{
+ MateMixerSwitchOption parent;
+
+ /*< private >*/
+ AlsaSwitchOptionPrivate *priv;
+};
+
+struct _AlsaSwitchOptionClass
+{
+ MateMixerSwitchOptionClass parent_class;
+};
+
+GType alsa_switch_option_get_type (void) G_GNUC_CONST;
+
+AlsaSwitchOption *alsa_switch_option_new (const gchar *name,
+ const gchar *label,
+ const gchar *icon,
+ guint id);
+
+guint alsa_switch_option_get_id (AlsaSwitchOption *option);
+
+G_END_DECLS
+
+#endif /* ALSA_SWITCH_OPTION_H */
diff --git a/backends/alsa/alsa-switch.c b/backends/alsa/alsa-switch.c
new file mode 100644
index 0000000..15151ae
--- /dev/null
+++ b/backends/alsa/alsa-switch.c
@@ -0,0 +1,227 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the licence, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <glib.h>
+#include <glib-object.h>
+#include <alsa/asoundlib.h>
+
+#include <libmatemixer/matemixer.h>
+#include <libmatemixer/matemixer-private.h>
+
+#include "alsa-element.h"
+#include "alsa-switch.h"
+#include "alsa-switch-option.h"
+
+struct _AlsaSwitchPrivate
+{
+ GList *options;
+ guint32 channel_mask;
+ snd_mixer_elem_t *element;
+};
+
+static void alsa_element_interface_init (AlsaElementInterface *iface);
+
+static void alsa_switch_class_init (AlsaSwitchClass *klass);
+static void alsa_switch_init (AlsaSwitch *swtch);
+
+G_DEFINE_TYPE_WITH_CODE (AlsaSwitch, alsa_switch,
+ MATE_MIXER_TYPE_SWITCH,
+ G_IMPLEMENT_INTERFACE (ALSA_TYPE_ELEMENT,
+ alsa_element_interface_init))
+
+static gboolean alsa_switch_set_active_option (MateMixerSwitch *mms,
+ MateMixerSwitchOption *mmso);
+
+static GList * alsa_switch_list_options (MateMixerSwitch *mms);
+
+static snd_mixer_elem_t * alsa_switch_get_snd_element (AlsaElement *element);
+static void alsa_switch_set_snd_element (AlsaElement *element,
+ snd_mixer_elem_t *el);
+static gboolean alsa_switch_load (AlsaElement *element);
+
+static void
+alsa_element_interface_init (AlsaElementInterface *iface)
+{
+ iface->get_snd_element = alsa_switch_get_snd_element;
+ iface->set_snd_element = alsa_switch_set_snd_element;
+ iface->load = alsa_switch_load;
+}
+
+static void
+alsa_switch_class_init (AlsaSwitchClass *klass)
+{
+ MateMixerSwitchClass *switch_class;
+
+ switch_class = MATE_MIXER_SWITCH_CLASS (klass);
+ switch_class->set_active_option = alsa_switch_set_active_option;
+ switch_class->list_options = alsa_switch_list_options;
+
+ g_type_class_add_private (G_OBJECT_CLASS (klass), sizeof (AlsaSwitchPrivate));
+}
+
+static void
+alsa_switch_init (AlsaSwitch *swtch)
+{
+ swtch->priv = G_TYPE_INSTANCE_GET_PRIVATE (swtch,
+ ALSA_TYPE_SWITCH,
+ AlsaSwitchPrivate);
+}
+
+AlsaSwitch *
+alsa_switch_new (const gchar *name, const gchar *label, GList *options)
+{
+ AlsaSwitch *swtch;
+
+ swtch = g_object_new (ALSA_TYPE_SWITCH,
+ "name", name,
+ "label", label,
+ NULL);
+
+ /* Takes ownership of options */
+ swtch->priv->options = options;
+ return swtch;
+}
+
+static gboolean
+alsa_switch_set_active_option (MateMixerSwitch *mms, MateMixerSwitchOption *mmso)
+{
+ AlsaSwitch *swtch;
+ guint index;
+ gboolean set_item = FALSE;
+ snd_mixer_selem_channel_id_t channel;
+
+ g_return_val_if_fail (ALSA_IS_SWITCH (mms), FALSE);
+ g_return_val_if_fail (ALSA_IS_SWITCH_OPTION (mmso), FALSE);
+
+ swtch = ALSA_SWITCH (mms);
+
+ /* The channel mask is created when reading the active option the first
+ * time, so a successful load must be done before changing the option */
+ if G_UNLIKELY (swtch->priv->channel_mask == 0) {
+ g_debug ("Not setting active switch option, channel mask unknown");
+ return FALSE;
+ }
+
+ index = alsa_switch_option_get_id (ALSA_SWITCH_OPTION (mmso));
+
+ for (channel = 0; channel < SND_MIXER_SCHN_LAST; channel++) {
+ /* The option is set per-channel, make sure to set it only for channels
+ * we successfully read the value from */
+ if (swtch->priv->channel_mask & (1 << channel)) {
+ gint ret = snd_mixer_selem_set_enum_item (swtch->priv->element,
+ channel,
+ index);
+ if (ret == 0)
+ set_item = TRUE;
+ else
+ g_warning ("Failed to set active option of switch %s: %s",
+ snd_mixer_selem_get_name (swtch->priv->element),
+ snd_strerror (ret));
+ }
+ }
+ return set_item;
+}
+
+static GList *
+alsa_switch_list_options (MateMixerSwitch *swtch)
+{
+ g_return_val_if_fail (ALSA_IS_SWITCH (swtch), NULL);
+
+ return ALSA_SWITCH (swtch)->priv->options;
+}
+
+static snd_mixer_elem_t *
+alsa_switch_get_snd_element (AlsaElement *element)
+{
+ g_return_val_if_fail (ALSA_IS_SWITCH (element), NULL);
+
+ return ALSA_SWITCH (element)->priv->element;
+}
+
+static void
+alsa_switch_set_snd_element (AlsaElement *element, snd_mixer_elem_t *el)
+{
+ g_return_if_fail (ALSA_IS_SWITCH (element));
+ g_return_if_fail (el != NULL);
+
+ ALSA_SWITCH (element)->priv->element = el;
+}
+
+static gboolean
+alsa_switch_load (AlsaElement *element)
+{
+ AlsaSwitch *swtch;
+ GList *list;
+ guint item;
+ gint ret;
+ snd_mixer_selem_channel_id_t c;
+
+ swtch = ALSA_SWITCH (element);
+
+ /* When reading the first time we try all the channels, otherwise only the
+ * ones which returned success before */
+ if (swtch->priv->channel_mask == 0) {
+ for (c = 0; c < SND_MIXER_SCHN_LAST; c++) {
+ ret = snd_mixer_selem_get_enum_item (swtch->priv->element, c, &item);
+
+ /* The active enum option is set per-channel, so when reading it the
+ * first time, create a mask of all channels for which we read the
+ * value successfully */
+ if (ret == 0)
+ swtch->priv->channel_mask |= 1 << c;
+ }
+
+ /* The last ALSA call might have failed, but it doesn't matter if we have
+ * a channel mask */
+ if (swtch->priv->channel_mask > 0)
+ ret = 0;
+ } else {
+ for (c = 0; !(swtch->priv->channel_mask & (1 << c)); c++)
+ ;
+
+ /* When not reading the mask, the first usable channel is enough, we don't
+ * support per-channel selections anyway */
+ ret = snd_mixer_selem_get_enum_item (swtch->priv->element, c, &item);
+ }
+
+ if (ret < 0) {
+ g_warning ("Failed to read active option of switch %s: %s",
+ snd_mixer_selem_get_name (swtch->priv->element),
+ snd_strerror (ret));
+ return FALSE;
+ }
+
+ list = swtch->priv->options;
+ while (list != NULL) {
+ AlsaSwitchOption *option = ALSA_SWITCH_OPTION (list->data);
+
+ /* Mark the selected option when we find it, ALSA indentifies them
+ * by numeric indices */
+ if (alsa_switch_option_get_id (option) == item) {
+ _mate_mixer_switch_set_active_option (MATE_MIXER_SWITCH (swtch),
+ MATE_MIXER_SWITCH_OPTION (option));
+ return TRUE;
+ }
+ list = list->next;
+ }
+
+ g_warning ("Unknown active option of switch %s: %d",
+ snd_mixer_selem_get_name (swtch->priv->element),
+ item);
+
+ return FALSE;
+}
diff --git a/backends/alsa/alsa-switch.h b/backends/alsa/alsa-switch.h
new file mode 100644
index 0000000..fdcfb87
--- /dev/null
+++ b/backends/alsa/alsa-switch.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the licence, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef ALSA_SWITCH_H
+#define ALSA_SWITCH_H
+
+#include <glib.h>
+#include <glib-object.h>
+#include <libmatemixer/matemixer.h>
+
+G_BEGIN_DECLS
+
+#define ALSA_TYPE_SWITCH \
+ (alsa_switch_get_type ())
+#define ALSA_SWITCH(o) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((o), ALSA_TYPE_SWITCH, AlsaSwitch))
+#define ALSA_IS_SWITCH(o) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((o), ALSA_TYPE_SWITCH))
+#define ALSA_SWITCH_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_CAST ((k), ALSA_TYPE_SWITCH, AlsaSwitchClass))
+#define ALSA_IS_SWITCH_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_TYPE ((k), ALSA_TYPE_SWITCH))
+#define ALSA_SWITCH_GET_CLASS(o) \
+ (G_TYPE_INSTANCE_GET_CLASS ((o), ALSA_TYPE_SWITCH, AlsaSwitchClass))
+
+typedef struct _AlsaSwitch AlsaSwitch;
+typedef struct _AlsaSwitchClass AlsaSwitchClass;
+typedef struct _AlsaSwitchPrivate AlsaSwitchPrivate;
+
+struct _AlsaSwitch
+{
+ MateMixerSwitch parent;
+
+ /*< private >*/
+ AlsaSwitchPrivate *priv;
+};
+
+struct _AlsaSwitchClass
+{
+ MateMixerSwitchClass parent_class;
+};
+
+GType alsa_switch_get_type (void) G_GNUC_CONST;
+
+AlsaSwitch *alsa_switch_new (const gchar *name,
+ const gchar *label,
+ GList *options);
+
+G_END_DECLS
+
+#endif /* ALSA_SWITCH_H */
diff --git a/backends/alsa/alsa-toggle.c b/backends/alsa/alsa-toggle.c
new file mode 100644
index 0000000..efa3460
--- /dev/null
+++ b/backends/alsa/alsa-toggle.c
@@ -0,0 +1,219 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the licence, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <glib.h>
+#include <glib-object.h>
+#include <alsa/asoundlib.h>
+
+#include <libmatemixer/matemixer.h>
+#include <libmatemixer/matemixer-private.h>
+
+#include "alsa-element.h"
+#include "alsa-switch-option.h"
+#include "alsa-toggle.h"
+
+struct _AlsaTogglePrivate
+{
+ AlsaToggleType type;
+ guint32 channel_mask;
+ snd_mixer_elem_t *element;
+};
+
+static void alsa_element_interface_init (AlsaElementInterface *iface);
+
+static void alsa_toggle_class_init (AlsaToggleClass *klass);
+static void alsa_toggle_init (AlsaToggle *toggle);
+
+G_DEFINE_TYPE_WITH_CODE (AlsaToggle, alsa_toggle, MATE_MIXER_TYPE_TOGGLE,
+ G_IMPLEMENT_INTERFACE (ALSA_TYPE_ELEMENT,
+ alsa_element_interface_init))
+
+static gboolean alsa_toggle_set_active_option (MateMixerSwitch *mms,
+ MateMixerSwitchOption *mmso);
+
+static snd_mixer_elem_t * alsa_toggle_get_snd_element (AlsaElement *element);
+static void alsa_toggle_set_snd_element (AlsaElement *element,
+ snd_mixer_elem_t *el);
+static gboolean alsa_toggle_load (AlsaElement *element);
+
+static void
+alsa_element_interface_init (AlsaElementInterface *iface)
+{
+ iface->get_snd_element = alsa_toggle_get_snd_element;
+ iface->set_snd_element = alsa_toggle_set_snd_element;
+ iface->load = alsa_toggle_load;
+}
+
+static void
+alsa_toggle_class_init (AlsaToggleClass *klass)
+{
+ MateMixerSwitchClass *switch_class;
+
+ switch_class = MATE_MIXER_SWITCH_CLASS (klass);
+ switch_class->set_active_option = alsa_toggle_set_active_option;
+
+ g_type_class_add_private (G_OBJECT_CLASS (klass), sizeof (AlsaTogglePrivate));
+}
+
+static void
+alsa_toggle_init (AlsaToggle *toggle)
+{
+ toggle->priv = G_TYPE_INSTANCE_GET_PRIVATE (toggle,
+ ALSA_TYPE_TOGGLE,
+ AlsaTogglePrivate);
+}
+
+AlsaToggle *
+alsa_toggle_new (const gchar *name,
+ const gchar *label,
+ AlsaToggleType type,
+ AlsaSwitchOption *on,
+ AlsaSwitchOption *off)
+{
+ AlsaToggle *toggle;
+
+ toggle = g_object_new (ALSA_TYPE_TOGGLE,
+ "name", name,
+ "label", label,
+ "state-option-on", on,
+ "state-option-off", off,
+ NULL);
+
+ toggle->priv->type = type;
+ return toggle;
+}
+
+static gboolean
+alsa_toggle_set_active_option (MateMixerSwitch *mms, MateMixerSwitchOption *mmso)
+{
+ AlsaToggle *toggle;
+ gint value;
+ gint ret;
+
+ g_return_val_if_fail (ALSA_IS_TOGGLE (mms), FALSE);
+ g_return_val_if_fail (ALSA_IS_SWITCH_OPTION (mmso), FALSE);
+
+ toggle = ALSA_TOGGLE (mms);
+
+ /* For toggles the 0/1 value is stored as the switch option id */
+ value = alsa_switch_option_get_id (ALSA_SWITCH_OPTION (mmso));
+ if G_UNLIKELY (value != 0 && value != 1) {
+ g_warn_if_reached ();
+ return FALSE;
+ }
+
+ if (toggle->priv->type == ALSA_TOGGLE_CAPTURE)
+ ret = snd_mixer_selem_set_capture_switch_all (toggle->priv->element, value);
+ else
+ ret = snd_mixer_selem_set_playback_switch_all (toggle->priv->element, value);
+
+ if (ret < 0) {
+ g_warning ("Failed to set value of toggle %s: %s",
+ snd_mixer_selem_get_name (toggle->priv->element),
+ snd_strerror (ret));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static snd_mixer_elem_t *
+alsa_toggle_get_snd_element (AlsaElement *element)
+{
+ g_return_val_if_fail (ALSA_IS_TOGGLE (element), NULL);
+
+ return ALSA_TOGGLE (element)->priv->element;
+}
+
+static void
+alsa_toggle_set_snd_element (AlsaElement *element, snd_mixer_elem_t *el)
+{
+ g_return_if_fail (ALSA_IS_TOGGLE (element));
+ g_return_if_fail (el != NULL);
+
+ ALSA_TOGGLE (element)->priv->element = el;
+}
+
+static gboolean
+alsa_toggle_load (AlsaElement *element)
+{
+ AlsaToggle *toggle;
+ gint value;
+ gint ret;
+ snd_mixer_selem_channel_id_t c;
+
+ toggle = ALSA_TOGGLE (element);
+
+ /* When reading the first time we try all the channels, otherwise only the
+ * ones which returned success before */
+ if (toggle->priv->channel_mask == 0) {
+ for (c = 0; c < SND_MIXER_SCHN_LAST; c++) {
+ if (toggle->priv->type == ALSA_TOGGLE_CAPTURE)
+ ret = snd_mixer_selem_get_capture_switch (toggle->priv->element,
+ c,
+ &value);
+ else
+ ret = snd_mixer_selem_get_playback_switch (toggle->priv->element,
+ c,
+ &value);
+
+ /* The active enum option is set per-channel, so when reading it the
+ * first time, create a mask of all channels for which we read the
+ * value successfully */
+ if (ret == 0)
+ toggle->priv->channel_mask |= 1 << c;
+ }
+
+ /* The last ALSA call might have failed, but it doesn't matter if we have
+ * a channel mask */
+ if (toggle->priv->channel_mask > 0)
+ ret = 0;
+ } else {
+ for (c = 0; !(toggle->priv->channel_mask & (1 << c)); c++)
+ ;
+
+ /* When not reading the mask, the first usable channel is enough, we don't
+ * support per-channel selections anyway */
+ if (toggle->priv->type == ALSA_TOGGLE_CAPTURE)
+ ret = snd_mixer_selem_get_capture_switch (toggle->priv->element,
+ c,
+ &value);
+ else
+ ret = snd_mixer_selem_get_playback_switch (toggle->priv->element,
+ c,
+ &value);
+ }
+
+ if (ret == 0) {
+ MateMixerSwitchOption *active;
+
+ if (value > 0)
+ active = mate_mixer_toggle_get_state_option (MATE_MIXER_TOGGLE (toggle), TRUE);
+ else
+ active = mate_mixer_toggle_get_state_option (MATE_MIXER_TOGGLE (toggle), FALSE);
+
+ _mate_mixer_switch_set_active_option (MATE_MIXER_SWITCH (toggle), active);
+
+ return TRUE;
+ }
+
+ g_warning ("Failed to read state of toggle %s: %s",
+ snd_mixer_selem_get_name (toggle->priv->element),
+ snd_strerror (ret));
+
+ return FALSE;
+}
diff --git a/backends/alsa/alsa-toggle.h b/backends/alsa/alsa-toggle.h
new file mode 100644
index 0000000..d9c083b
--- /dev/null
+++ b/backends/alsa/alsa-toggle.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the licence, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef ALSA_TOGGLE_H
+#define ALSA_TOGGLE_H
+
+#include <glib.h>
+#include <glib-object.h>
+#include <libmatemixer/matemixer.h>
+
+#include "alsa-switch-option.h"
+
+G_BEGIN_DECLS
+
+typedef enum {
+ ALSA_TOGGLE_CAPTURE,
+ ALSA_TOGGLE_PLAYBACK
+} AlsaToggleType;
+
+#define ALSA_TYPE_TOGGLE \
+ (alsa_toggle_get_type ())
+#define ALSA_TOGGLE(o) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((o), ALSA_TYPE_TOGGLE, AlsaToggle))
+#define ALSA_IS_TOGGLE(o) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((o), ALSA_TYPE_TOGGLE))
+#define ALSA_TOGGLE_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_CAST ((k), ALSA_TYPE_TOGGLE, AlsaToggleClass))
+#define ALSA_IS_TOGGLE_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_TYPE ((k), ALSA_TYPE_TOGGLE))
+#define ALSA_TOGGLE_GET_CLASS(o) \
+ (G_TYPE_INSTANCE_GET_CLASS ((o), ALSA_TYPE_TOGGLE, AlsaToggleClass))
+
+typedef struct _AlsaToggle AlsaToggle;
+typedef struct _AlsaToggleClass AlsaToggleClass;
+typedef struct _AlsaTogglePrivate AlsaTogglePrivate;
+
+struct _AlsaToggle
+{
+ MateMixerToggle parent;
+
+ /*< private >*/
+ AlsaTogglePrivate *priv;
+};
+
+struct _AlsaToggleClass
+{
+ MateMixerToggleClass parent_class;
+};
+
+GType alsa_toggle_get_type (void) G_GNUC_CONST;
+
+AlsaToggle *alsa_toggle_new (const gchar *name,
+ const gchar *label,
+ AlsaToggleType type,
+ AlsaSwitchOption *on,
+ AlsaSwitchOption *off);
+
+G_END_DECLS
+
+#endif /* ALSA_TOGGLE_H */
diff --git a/backends/oss/Makefile.am b/backends/oss/Makefile.am
new file mode 100644
index 0000000..44caeb8
--- /dev/null
+++ b/backends/oss/Makefile.am
@@ -0,0 +1,34 @@
+backenddir = $(libdir)/libmatemixer
+
+backend_LTLIBRARIES = libmatemixer-oss.la
+
+AM_CPPFLAGS = \
+ -I$(top_srcdir) \
+ -DG_LOG_DOMAIN=\"libmatemixer-oss\"
+
+libmatemixer_oss_la_CFLAGS = \
+ $(GLIB_CFLAGS) \
+ $(OSS_CFLAGS)
+
+libmatemixer_oss_la_SOURCES = \
+ oss-common.h \
+ oss-backend.c \
+ oss-backend.h \
+ oss-device.c \
+ oss-device.h \
+ oss-stream.c \
+ oss-stream.h \
+ oss-stream-control.c \
+ oss-stream-control.h
+
+libmatemixer_oss_la_LIBADD = \
+ $(GLIB_LIBS) \
+ $(OSS_LIBS)
+
+libmatemixer_oss_la_LDFLAGS = \
+ -avoid-version \
+ -no-undefined \
+ -export-dynamic \
+ -module
+
+-include $(top_srcdir)/git.mk
diff --git a/backends/oss/oss-backend.c b/backends/oss/oss-backend.c
new file mode 100644
index 0000000..2b5eca7
--- /dev/null
+++ b/backends/oss/oss-backend.c
@@ -0,0 +1,587 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the licence, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <glib.h>
+#include <glib/gstdio.h>
+#include <glib/gi18n.h>
+#include <glib-object.h>
+
+#include <libmatemixer/matemixer.h>
+#include <libmatemixer/matemixer-private.h>
+
+#include "oss-backend.h"
+#include "oss-common.h"
+#include "oss-device.h"
+#include "oss-stream.h"
+
+#define BACKEND_NAME "OSS"
+#define BACKEND_PRIORITY 9
+
+#if !defined(__linux__) && !defined(__NetBSD__) && !defined(__OpenBSD__)
+ /* At least on systems based on FreeBSD we will need to read device names
+ * from the sndstat file, but avoid even trying that on systems where this
+ * is not needed and the file is not present */
+#define OSS_PATH_SNDSTAT "/dev/sndstat"
+#endif
+
+#define OSS_MAX_DEVICES 32
+
+struct _OssBackendPrivate
+{
+ gchar *default_device;
+ GSource *timeout_source;
+ GHashTable *devices;
+};
+
+static void oss_backend_class_init (OssBackendClass *klass);
+static void oss_backend_class_finalize (OssBackendClass *klass);
+static void oss_backend_init (OssBackend *oss);
+static void oss_backend_dispose (GObject *object);
+static void oss_backend_finalize (GObject *object);
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunused-function"
+G_DEFINE_DYNAMIC_TYPE (OssBackend, oss_backend, MATE_MIXER_TYPE_BACKEND)
+#pragma clang diagnostic pop
+
+static gboolean oss_backend_open (MateMixerBackend *backend);
+static void oss_backend_close (MateMixerBackend *backend);
+static GList * oss_backend_list_devices (MateMixerBackend *backend);
+static GList * oss_backend_list_streams (MateMixerBackend *backend);
+
+static gboolean read_devices (OssBackend *oss);
+
+static gboolean read_device (OssBackend *oss,
+ const gchar *path,
+ gboolean *added);
+
+static gchar * read_device_label (OssBackend *oss,
+ const gchar *path,
+ gint fd);
+
+static gchar * read_device_label_sndstat (OssBackend *oss,
+ const gchar *sndstat,
+ const gchar *path,
+ guint index) G_GNUC_UNUSED;
+
+static void add_device (OssBackend *oss,
+ OssDevice *device);
+static void remove_device (OssBackend *oss,
+ OssDevice *device);
+
+static void remove_stream (OssBackend *oss,
+ const gchar *name);
+
+static void select_default_input_stream (OssBackend *oss);
+static void select_default_output_stream (OssBackend *oss);
+
+static MateMixerBackendInfo info;
+
+void
+backend_module_init (GTypeModule *module)
+{
+ oss_backend_register_type (module);
+
+ info.name = BACKEND_NAME;
+ info.priority = BACKEND_PRIORITY;
+ info.g_type = OSS_TYPE_BACKEND;
+ info.backend_type = MATE_MIXER_BACKEND_OSS;
+}
+
+const MateMixerBackendInfo *backend_module_get_info (void)
+{
+ return &info;
+}
+
+static void
+oss_backend_class_init (OssBackendClass *klass)
+{
+ GObjectClass *object_class;
+ MateMixerBackendClass *backend_class;
+
+ object_class = G_OBJECT_CLASS (klass);
+ object_class->dispose = oss_backend_dispose;
+ object_class->finalize = oss_backend_finalize;
+
+ backend_class = MATE_MIXER_BACKEND_CLASS (klass);
+ backend_class->open = oss_backend_open;
+ backend_class->close = oss_backend_close;
+ backend_class->list_devices = oss_backend_list_devices;
+ backend_class->list_streams = oss_backend_list_streams;
+
+ g_type_class_add_private (object_class, sizeof (OssBackendPrivate));
+}
+
+/* Called in the code generated by G_DEFINE_DYNAMIC_TYPE() */
+static void
+oss_backend_class_finalize (OssBackendClass *klass)
+{
+}
+
+static void
+oss_backend_init (OssBackend *oss)
+{
+ oss->priv = G_TYPE_INSTANCE_GET_PRIVATE (oss,
+ OSS_TYPE_BACKEND,
+ OssBackendPrivate);
+
+ oss->priv->devices = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ g_free,
+ g_object_unref);
+}
+
+static void
+oss_backend_dispose (GObject *object)
+{
+ MateMixerBackend *backend;
+ MateMixerState state;
+
+ backend = MATE_MIXER_BACKEND (object);
+
+ state = mate_mixer_backend_get_state (backend);
+ if (state != MATE_MIXER_STATE_IDLE)
+ oss_backend_close (backend);
+
+ G_OBJECT_CLASS (oss_backend_parent_class)->dispose (object);
+}
+
+static void
+oss_backend_finalize (GObject *object)
+{
+ OssBackend *oss;
+
+ oss = OSS_BACKEND (object);
+
+ g_hash_table_destroy (oss->priv->devices);
+
+ G_OBJECT_CLASS (oss_backend_parent_class)->finalize (object);
+}
+
+static gboolean
+oss_backend_open (MateMixerBackend *backend)
+{
+ OssBackend *oss;
+
+ g_return_val_if_fail (OSS_IS_BACKEND (backend), FALSE);
+
+ oss = OSS_BACKEND (backend);
+
+ /* Discover added or removed OSS devices every second */
+ oss->priv->timeout_source = g_timeout_source_new_seconds (1);
+ g_source_set_callback (oss->priv->timeout_source,
+ (GSourceFunc) read_devices,
+ oss,
+ NULL);
+ g_source_attach (oss->priv->timeout_source,
+ g_main_context_get_thread_default ());
+
+ /* Read the initial list of devices so we have some starting point, there
+ * isn't really a way to detect errors here, failing to add a device may
+ * be a device-related problem so make the backend always open successfully */
+ read_devices (oss);
+
+ _mate_mixer_backend_set_state (backend, MATE_MIXER_STATE_READY);
+ return TRUE;
+}
+
+void
+oss_backend_close (MateMixerBackend *backend)
+{
+ OssBackend *oss;
+
+ g_return_if_fail (OSS_IS_BACKEND (backend));
+
+ oss = OSS_BACKEND (backend);
+
+ g_source_destroy (oss->priv->timeout_source);
+ g_hash_table_remove_all (oss->priv->devices);
+
+ g_free (oss->priv->default_device);
+ oss->priv->default_device = NULL;
+
+ _mate_mixer_backend_set_state (backend, MATE_MIXER_STATE_IDLE);
+}
+
+static GList *
+oss_backend_list_devices (MateMixerBackend *backend)
+{
+ GList *list;
+
+ g_return_val_if_fail (OSS_IS_BACKEND (backend), NULL);
+
+ /* Convert the hash table to a linked list, this list is expected to be
+ * cached in the main library */
+ list = g_hash_table_get_values (OSS_BACKEND (backend)->priv->devices);
+ if (list != NULL)
+ g_list_foreach (list, (GFunc) g_object_ref, NULL);
+
+ return list;
+}
+
+static GList *
+oss_backend_list_streams (MateMixerBackend *backend)
+{
+ OssBackend *oss;
+ GHashTableIter iter;
+ gpointer value;
+ GList *list = NULL;
+
+ g_return_val_if_fail (OSS_IS_BACKEND (backend), NULL);
+
+ oss = OSS_BACKEND (backend);
+
+ /* We don't keep a list or hash table of all streams here, instead walk
+ * through the list of devices and create the list manually, each device
+ * has at most one input and one output stream */
+ g_hash_table_iter_init (&iter, oss->priv->devices);
+
+ while (g_hash_table_iter_next (&iter, NULL, &value)) {
+ OssDevice *device = OSS_DEVICE (value);
+ OssStream *stream;
+
+ stream = oss_device_get_output_stream (device);
+ if (stream != NULL)
+ list = g_list_prepend (list, stream);
+ stream = oss_device_get_input_stream (device);
+ if (stream != NULL)
+ list = g_list_prepend (list, stream);
+ }
+
+ if (list != NULL)
+ g_list_foreach (list, (GFunc) g_object_ref, NULL);
+
+ return list;
+}
+
+static gboolean
+read_devices (OssBackend *oss)
+{
+ gint i;
+ gboolean added = FALSE;
+
+ for (i = 0; i < OSS_MAX_DEVICES; i++) {
+ gboolean added_current;
+ gchar *path = g_strdup_printf ("/dev/mixer%i", i);
+
+ /* On recent FreeBSD both /dev/mixer and /dev/mixer0 point to the same
+ * mixer device, on NetBSD and OpenBSD /dev/mixer is a symlink to one
+ * of the real mixer device nodes, on Linux /dev/mixer is the first
+ * device and /dev/mixer1 is the second device.
+ * Handle all of these cases by trying /dev/mixer if /dev/mixer0 fails */
+ if (read_device (oss, path, &added_current) == FALSE && i == 0)
+ read_device (oss, "/dev/mixer", &added_current);
+
+ if (added_current)
+ added = TRUE;
+
+ g_free (path);
+ }
+
+ /* If any card has been added, make sure we have the most suitable default
+ * input and output streams */
+ if (added == TRUE) {
+ select_default_input_stream (oss);
+ select_default_output_stream (oss);
+ }
+ return G_SOURCE_CONTINUE;
+}
+
+static gboolean
+read_device (OssBackend *oss, const gchar *path, gboolean *added)
+{
+ OssDevice *device;
+ gint fd;
+ gchar *bname;
+ gchar *label;
+
+ device = g_hash_table_lookup (oss->priv->devices, path);
+ *added = FALSE;
+
+ fd = g_open (path, O_RDWR, 0);
+ if (fd == -1) {
+ if (errno != ENOENT && errno != ENXIO)
+ g_debug ("%s: %s", path, g_strerror (errno));
+
+ if (device != NULL)
+ remove_device (oss, device);
+ return FALSE;
+ }
+
+ /* Don't proceed if the device is already known, opening the device was
+ * still tested to be absolutely sure that the device is removed it case
+ * it has disappeared, but normally the device's polling facility should
+ * handle this by itself */
+ if (device != NULL) {
+ close (fd);
+ return TRUE;
+ }
+
+ bname = g_path_get_basename (path);
+ label = read_device_label (oss, path, fd);
+
+ device = oss_device_new (bname, label, path, fd);
+ g_free (bname);
+ g_free (label);
+
+ close (fd);
+
+ if ((*added = oss_device_open (device)) == TRUE)
+ add_device (oss, device);
+
+ g_object_unref (device);
+ return *added;
+}
+
+static gchar *
+read_device_label (OssBackend *oss, const gchar *path, gint fd)
+{
+ guint index;
+
+#ifdef SOUND_MIXER_INFO
+ do {
+ struct mixer_info info;
+
+ /* Prefer device name supplied by the system, but this calls fails
+ * with EINVAL on FreeBSD */
+ if (ioctl (fd, SOUND_MIXER_INFO, &info) == 0)
+ return g_strdup (info.name);
+ } while (0);
+#endif
+
+ index = (guint) g_ascii_strtoull (path + sizeof ("/dev/mixer") - 1,
+ NULL,
+ 10);
+#ifdef OSS_PATH_SNDSTAT
+ /* If the ioctl doesn't succeed, assume that the mixer device number
+ * matches the pcm number in the sndstat file, this is a bit desperate, but
+ * it should be correct on FreeBSD */
+ do {
+ gchar *label;
+
+ label = read_device_label_sndstat (oss, OSS_PATH_SNDSTAT, path, index);
+ if (label != NULL)
+ return label;
+ } while (0);
+#endif
+
+ return g_strdup_printf (_("OSS Mixer %d"), index);
+}
+
+static gchar *
+read_device_label_sndstat (OssBackend *oss,
+ const gchar *sndstat,
+ const gchar *path,
+ guint index)
+{
+ FILE *fp;
+ gchar *label = NULL;
+ gchar *prefix;
+ gchar line[512];
+
+ fp = g_fopen (sndstat, "r");
+ if (fp == NULL) {
+ g_debug ("Failed to open %s: %s", sndstat, g_strerror (errno));
+ return NULL;
+ }
+
+ /* Example line:
+ * pcm0: <ATI R6xx (HDMI)> (play) default */
+ prefix = g_strdup_printf ("pcm%u: ", index);
+
+ while (fgets (line, sizeof (line), fp) != NULL) {
+ gchar *p;
+
+ if (g_str_has_prefix (line, prefix) == FALSE)
+ continue;
+
+ p = strchr (line, '<');
+ if (p != NULL && *p && *(++p)) {
+ gchar *end = strchr (p, '>');
+
+ if (end != NULL) {
+ label = g_strndup (p, end - p);
+
+ /* Normally the default OSS device is /dev/dsp, but on FreeBSD
+ * /dev/dsp doesn't physically exist on the filesystem, but is
+ * managed by the kernel according to the user-settable default
+ * device, in sndstat the default card definition ends with the
+ * word "default" */
+ if (g_str_has_suffix (line, "default")) {
+ g_free (oss->priv->default_device);
+
+ oss->priv->default_device = g_strdup (path);
+ }
+ } else {
+ g_debug ("Failed to read sndstat line: %s", line);
+ }
+ break;
+ }
+ }
+
+ g_free (prefix);
+ fclose (fp);
+
+ return label;
+}
+
+static void
+add_device (OssBackend *oss, OssDevice *device)
+{
+ const gchar *name;
+
+ name = mate_mixer_device_get_name (MATE_MIXER_DEVICE (device));
+
+ g_hash_table_insert (oss->priv->devices,
+ g_strdup (oss_device_get_path (device)),
+ g_object_ref (device));
+
+ // XXX make device emit it when closed
+ g_signal_connect_swapped (G_OBJECT (device),
+ "stream-removed",
+ G_CALLBACK (remove_stream),
+ oss);
+
+ g_signal_emit_by_name (G_OBJECT (oss), "device-added", name);
+
+ oss_device_load (device);
+}
+
+static void
+remove_device (OssBackend *oss, OssDevice *device)
+{
+ const gchar *name;
+ const gchar *path;
+
+ path = oss_device_get_path (device);
+ name = mate_mixer_device_get_name (MATE_MIXER_DEVICE (device));
+
+ g_signal_handlers_disconnect_by_func (G_OBJECT (device),
+ G_CALLBACK (remove_stream),
+ oss);
+
+ // XXX close the device and make it remove streams
+ g_hash_table_remove (oss->priv->devices, path);
+
+ g_signal_emit_by_name (G_OBJECT (oss),
+ "device-removed",
+ name);
+}
+
+static void
+remove_stream (OssBackend *oss, const gchar *name)
+{
+ MateMixerStream *stream;
+
+ stream = mate_mixer_backend_get_default_input_stream (MATE_MIXER_BACKEND (oss));
+
+ // XXX see if the change happens after stream is removed or before
+ if (stream != NULL && strcmp (mate_mixer_stream_get_name (stream), name) == 0)
+ select_default_input_stream (oss);
+
+ stream = mate_mixer_backend_get_default_output_stream (MATE_MIXER_BACKEND (oss));
+
+ if (stream != NULL && strcmp (mate_mixer_stream_get_name (stream), name) == 0)
+ select_default_output_stream (oss);
+}
+
+static void
+select_default_input_stream (OssBackend *oss)
+{
+ OssDevice *device = NULL;
+ OssStream *stream;
+ gint i;
+
+ /* Always prefer stream in the "default" device */
+ if (oss->priv->default_device != NULL)
+ device = g_hash_table_lookup (oss->priv->devices, oss->priv->default_device);
+ if (device != NULL) {
+ stream = oss_device_get_input_stream (device);
+ if (stream != NULL) {
+ _mate_mixer_backend_set_default_input_stream (MATE_MIXER_BACKEND (oss),
+ MATE_MIXER_STREAM (stream));
+ return;
+ }
+ }
+
+ for (i = 0; i < OSS_MAX_DEVICES; i++) {
+ gchar *path = g_strdup_printf ("/dev/mixer%i", i);
+
+ device = g_hash_table_lookup (oss->priv->devices, path);
+ if (device == NULL && i == 0)
+ device = g_hash_table_lookup (oss->priv->devices, "/dev/mixer");
+
+ if (device != NULL) {
+ stream = oss_device_get_input_stream (device);
+ if (stream != NULL) {
+ _mate_mixer_backend_set_default_input_stream (MATE_MIXER_BACKEND (oss),
+ MATE_MIXER_STREAM (stream));
+ g_free (path);
+ return;
+ }
+ }
+ g_free (path);
+ }
+
+ /* In the worst case unset the default stream */
+ _mate_mixer_backend_set_default_input_stream (MATE_MIXER_BACKEND (oss), NULL);
+}
+
+static void
+select_default_output_stream (OssBackend *oss)
+{
+ OssDevice *device = NULL;
+ OssStream *stream;
+ gint i;
+
+ /* Always prefer stream in the "default" device */
+ if (oss->priv->default_device != NULL)
+ device = g_hash_table_lookup (oss->priv->devices, oss->priv->default_device);
+ if (device != NULL) {
+ stream = oss_device_get_output_stream (device);
+ if (stream != NULL) {
+ _mate_mixer_backend_set_default_output_stream (MATE_MIXER_BACKEND (oss),
+ MATE_MIXER_STREAM (stream));
+ return;
+ }
+ }
+
+ for (i = 0; i < OSS_MAX_DEVICES; i++) {
+ gchar *path = g_strdup_printf ("/dev/mixer%i", i);
+
+ device = g_hash_table_lookup (oss->priv->devices, path);
+ if (device == NULL && i == 0)
+ device = g_hash_table_lookup (oss->priv->devices, "/dev/mixer");
+
+ if (device != NULL) {
+ stream = oss_device_get_output_stream (device);
+ if (stream != NULL) {
+ _mate_mixer_backend_set_default_output_stream (MATE_MIXER_BACKEND (oss),
+ MATE_MIXER_STREAM (stream));
+ g_free (path);
+ return;
+ }
+ }
+ g_free (path);
+ }
+
+ /* In the worst case unset the default stream */
+ _mate_mixer_backend_set_default_output_stream (MATE_MIXER_BACKEND (oss), NULL);
+}
diff --git a/backends/oss/oss-backend.h b/backends/oss/oss-backend.h
new file mode 100644
index 0000000..325b61c
--- /dev/null
+++ b/backends/oss/oss-backend.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the licence, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef OSS_BACKEND_H
+#define OSS_BACKEND_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include <libmatemixer/matemixer-backend.h>
+#include <libmatemixer/matemixer-backend-module.h>
+
+#define OSS_TYPE_BACKEND \
+ (oss_backend_get_type ())
+#define OSS_BACKEND(o) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((o), OSS_TYPE_BACKEND, OssBackend))
+#define OSS_IS_BACKEND(o) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((o), OSS_TYPE_BACKEND))
+#define OSS_BACKEND_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_CAST ((k), OSS_TYPE_BACKEND, OssBackendClass))
+#define OSS_IS_BACKEND_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_TYPE ((k), OSS_TYPE_BACKEND))
+#define OSS_BACKEND_GET_CLASS(o) \
+ (G_TYPE_INSTANCE_GET_CLASS ((o), OSS_TYPE_BACKEND, OssBackendClass))
+
+typedef struct _OssBackend OssBackend;
+typedef struct _OssBackendClass OssBackendClass;
+typedef struct _OssBackendPrivate OssBackendPrivate;
+
+struct _OssBackend
+{
+ MateMixerBackend parent;
+
+ /*< private >*/
+ OssBackendPrivate *priv;
+};
+
+struct _OssBackendClass
+{
+ MateMixerBackendClass parent_class;
+};
+
+GType oss_backend_get_type (void) G_GNUC_CONST;
+
+/* Support function for dynamic loading of the backend module */
+void backend_module_init (GTypeModule *module);
+const MateMixerBackendInfo *backend_module_get_info (void);
+
+#endif /* OSS_BACKEND_H */
diff --git a/backends/oss/oss-common.h b/backends/oss/oss-common.h
new file mode 100644
index 0000000..28a138d
--- /dev/null
+++ b/backends/oss/oss-common.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the licence, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef OSS_COMMON_H
+#define OSS_COMMON_H
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#ifdef HAVE_SYS_SOUNDCARD_H
+# include <sys/soundcard.h>
+#elif HAVE_SOUNDCARD_H
+# include <soundcard.h>
+#elif HAVE_MACHINE_SOUNDCARD_H
+# include <machine/soundcard.h>
+#else
+# error "No OSS header file present"
+#endif
+
+#endif /* OSS_COMMON_H */
diff --git a/backends/oss/oss-device.c b/backends/oss/oss-device.c
new file mode 100644
index 0000000..cf51705
--- /dev/null
+++ b/backends/oss/oss-device.c
@@ -0,0 +1,404 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the licence, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <errno.h>
+#include <unistd.h>
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <glib/gstdio.h>
+#include <glib-object.h>
+
+#include <libmatemixer/matemixer.h>
+#include <libmatemixer/matemixer-private.h>
+
+#include "oss-common.h"
+#include "oss-device.h"
+#include "oss-stream.h"
+#include "oss-stream-control.h"
+
+#define OSS_DEVICE_ICON "audio-card"
+
+typedef enum
+{
+ OSS_DEV_ANY,
+ OSS_DEV_INPUT,
+ OSS_DEV_OUTPUT
+} OssDevType;
+
+typedef struct
+{
+ gchar *name;
+ gchar *label;
+ MateMixerStreamControlRole role;
+ OssDevType type;
+} OssDev;
+
+static const OssDev oss_devices[] = {
+ { "vol", N_("Volume"), MATE_MIXER_STREAM_CONTROL_ROLE_MASTER, OSS_DEV_OUTPUT },
+ { "bass", N_("Bass"), MATE_MIXER_STREAM_CONTROL_ROLE_BASS, OSS_DEV_OUTPUT },
+ { "treble", N_("Treble"), MATE_MIXER_STREAM_CONTROL_ROLE_TREBLE, OSS_DEV_OUTPUT },
+ { "synth", N_("Synth"), MATE_MIXER_STREAM_CONTROL_ROLE_UNKNOWN, OSS_DEV_INPUT },
+ { "pcm", N_("PCM"), MATE_MIXER_STREAM_CONTROL_ROLE_PCM, OSS_DEV_OUTPUT },
+ /* OSS manual says this should be the beeper, but Linux OSS seems to assign it to
+ * regular volume control */
+ { "speaker", N_("Speaker"), MATE_MIXER_STREAM_CONTROL_ROLE_SPEAKER, OSS_DEV_OUTPUT },
+ { "line", N_("Line-in"), MATE_MIXER_STREAM_CONTROL_ROLE_PORT, OSS_DEV_INPUT },
+ { "mic", N_("Microphone"), MATE_MIXER_STREAM_CONTROL_ROLE_PORT, OSS_DEV_INPUT },
+ { "cd", N_("CD"), MATE_MIXER_STREAM_CONTROL_ROLE_CD, OSS_DEV_INPUT },
+ /* Recording monitor */
+ { "mix", N_("Mixer"), MATE_MIXER_STREAM_CONTROL_ROLE_UNKNOWN, OSS_DEV_OUTPUT },
+ { "pcm2", N_("PCM-2"), MATE_MIXER_STREAM_CONTROL_ROLE_PCM, OSS_DEV_OUTPUT },
+ /* Recording level (master input) */
+ { "rec", N_("Record"), MATE_MIXER_STREAM_CONTROL_ROLE_MASTER, OSS_DEV_INPUT },
+ { "igain", N_("In-gain"), MATE_MIXER_STREAM_CONTROL_ROLE_UNKNOWN, OSS_DEV_INPUT },
+ { "ogain", N_("Out-gain"), MATE_MIXER_STREAM_CONTROL_ROLE_UNKNOWN, OSS_DEV_OUTPUT },
+ { "line1", N_("Line-1"), MATE_MIXER_STREAM_CONTROL_ROLE_PORT, OSS_DEV_INPUT },
+ { "line2", N_("Line-2"), MATE_MIXER_STREAM_CONTROL_ROLE_PORT, OSS_DEV_INPUT },
+ { "line3", N_("Line-3"), MATE_MIXER_STREAM_CONTROL_ROLE_PORT, OSS_DEV_INPUT },
+ { "dig1", N_("Digital-1"), MATE_MIXER_STREAM_CONTROL_ROLE_PORT, OSS_DEV_ANY },
+ { "dig2", N_("Digital-2"), MATE_MIXER_STREAM_CONTROL_ROLE_PORT, OSS_DEV_ANY },
+ { "dig3", N_("Digital-3"), MATE_MIXER_STREAM_CONTROL_ROLE_PORT, OSS_DEV_ANY },
+ { "phin", N_("Phone-in"), MATE_MIXER_STREAM_CONTROL_ROLE_PORT, OSS_DEV_INPUT },
+ { "phout", N_("Phone-out"), MATE_MIXER_STREAM_CONTROL_ROLE_PORT, OSS_DEV_OUTPUT },
+ { "video", N_("Video"), MATE_MIXER_STREAM_CONTROL_ROLE_PORT, OSS_DEV_INPUT },
+ { "radio", N_("Radio"), MATE_MIXER_STREAM_CONTROL_ROLE_PORT, OSS_DEV_INPUT },
+ { "monitor", N_("Monitor"), MATE_MIXER_STREAM_CONTROL_ROLE_UNKNOWN, OSS_DEV_OUTPUT },
+ { "depth", N_("3D-depth"), MATE_MIXER_STREAM_CONTROL_ROLE_UNKNOWN, OSS_DEV_OUTPUT },
+ { "center", N_("3D-center"), MATE_MIXER_STREAM_CONTROL_ROLE_UNKNOWN, OSS_DEV_OUTPUT },
+ { "midi", N_("MIDI"), MATE_MIXER_STREAM_CONTROL_ROLE_UNKNOWN, OSS_DEV_INPUT }
+};
+
+#define OSS_N_DEVICES MIN (G_N_ELEMENTS (oss_devices), SOUND_MIXER_NRDEVICES)
+
+struct _OssDevicePrivate
+{
+ gint fd;
+ gchar *path;
+ gint devmask;
+ gint stereodevs;
+ gint recmask;
+ gint recsrc;
+ OssStream *input;
+ OssStream *output;
+};
+
+static void oss_device_class_init (OssDeviceClass *klass);
+static void oss_device_init (OssDevice *device);
+static void oss_device_dispose (GObject *object);
+static void oss_device_finalize (GObject *object);
+
+G_DEFINE_TYPE (OssDevice, oss_device, MATE_MIXER_TYPE_DEVICE)
+
+static GList * oss_device_list_streams (MateMixerDevice *device);
+
+static gboolean read_mixer_devices (OssDevice *device);
+
+static gboolean set_stream_default_control (OssStream *stream,
+ OssStreamControl *control,
+ gboolean force);
+
+static void
+oss_device_class_init (OssDeviceClass *klass)
+{
+ GObjectClass *object_class;
+ MateMixerDeviceClass *device_class;
+
+ object_class = G_OBJECT_CLASS (klass);
+ object_class->dispose = oss_device_dispose;
+ object_class->finalize = oss_device_finalize;
+
+ device_class = MATE_MIXER_DEVICE_CLASS (klass);
+ device_class->list_streams = oss_device_list_streams;
+
+ g_type_class_add_private (object_class, sizeof (OssDevicePrivate));
+}
+
+static void
+oss_device_init (OssDevice *device)
+{
+ device->priv = G_TYPE_INSTANCE_GET_PRIVATE (device,
+ OSS_TYPE_DEVICE,
+ OssDevicePrivate);
+}
+
+static void
+oss_device_dispose (GObject *object)
+{
+ OssDevice *device;
+
+ device = OSS_DEVICE (object);
+
+ g_clear_object (&device->priv->input);
+ g_clear_object (&device->priv->output);
+
+ G_OBJECT_CLASS (oss_device_parent_class)->dispose (object);
+}
+
+static void
+oss_device_finalize (GObject *object)
+{
+ OssDevice *device = OSS_DEVICE (object);
+
+ close (device->priv->fd);
+
+ G_OBJECT_CLASS (oss_device_parent_class)->finalize (object);
+}
+
+OssDevice *
+oss_device_new (const gchar *name, const gchar *label, const gchar *path, gint fd)
+{
+ OssDevice *device;
+ gchar *stream_name;
+
+ g_return_val_if_fail (name != NULL, NULL);
+ g_return_val_if_fail (label != NULL, NULL);
+ g_return_val_if_fail (path != NULL, NULL);
+
+ device = g_object_new (OSS_TYPE_DEVICE,
+ "name", name,
+ "label", label,
+ "icon", OSS_DEVICE_ICON,
+ NULL);
+
+ device->priv->fd = dup (fd);
+ device->priv->path = g_strdup (path);
+
+ stream_name = g_strdup_printf ("oss-input-%s", name);
+ device->priv->input = oss_stream_new (stream_name,
+ MATE_MIXER_DEVICE (device),
+ MATE_MIXER_STREAM_INPUT);
+ g_free (stream_name);
+
+ stream_name = g_strdup_printf ("oss-output-%s", name);
+ device->priv->output = oss_stream_new (stream_name,
+ MATE_MIXER_DEVICE (device),
+ MATE_MIXER_STREAM_OUTPUT);
+ g_free (stream_name);
+
+ return device;
+}
+
+gboolean
+oss_device_open (OssDevice *device)
+{
+ gint ret;
+
+ g_return_val_if_fail (OSS_IS_DEVICE (device), FALSE);
+
+ g_debug ("Opening device %s (%s)",
+ device->priv->path,
+ mate_mixer_device_get_label (MATE_MIXER_DEVICE (device)));
+
+ /* Read the essential information about the device, these values are not
+ * expected to change and will not be queried */
+ ret = ioctl (device->priv->fd,
+ MIXER_READ (SOUND_MIXER_DEVMASK),
+ &device->priv->devmask);
+ if (ret != 0)
+ goto fail;
+
+ ret = ioctl (device->priv->fd,
+ MIXER_READ (SOUND_MIXER_STEREODEVS),
+ &device->priv->stereodevs);
+ if (ret < 0)
+ goto fail;
+
+ ret = ioctl (device->priv->fd,
+ MIXER_READ (SOUND_MIXER_RECMASK),
+ &device->priv->recmask);
+ if (ret < 0)
+ goto fail;
+
+ /* The recording source mask may change at any time, here we just read
+ * the initial value */
+ ret = ioctl (device->priv->fd,
+ MIXER_READ (SOUND_MIXER_RECSRC),
+ &device->priv->recsrc);
+ if (ret < 0)
+ goto fail;
+
+ /* NOTE: Linux also supports SOUND_MIXER_OUTSRC and SOUND_MIXER_OUTMASK which
+ * inform about/enable input->output, we could potentially create toggles
+ * for these, but these constants are not defined on any BSD. */
+
+ return TRUE;
+
+fail:
+ g_warning ("Failed to read device %s: %s",
+ device->priv->path,
+ g_strerror (errno));
+
+ return FALSE;
+}
+
+gboolean
+oss_device_load (OssDevice *device)
+{
+ MateMixerStreamControl *control;
+
+ g_return_val_if_fail (OSS_IS_DEVICE (device), FALSE);
+
+ read_mixer_devices (device);
+
+ control = mate_mixer_stream_get_default_control (MATE_MIXER_STREAM (device->priv->input));
+ if (control == NULL) {
+ // XXX pick something
+ }
+
+ if (control != NULL)
+ g_debug ("Default input stream control is %s",
+ mate_mixer_stream_control_get_label (control));
+
+ control = mate_mixer_stream_get_default_control (MATE_MIXER_STREAM (device->priv->output));
+ if (control == NULL) {
+ // XXX pick something
+ }
+
+ if (control != NULL)
+ g_debug ("Default output stream control is %s",
+ mate_mixer_stream_control_get_label (control));
+
+ return TRUE;
+}
+
+gint
+oss_device_get_fd (OssDevice *device)
+{
+ g_return_val_if_fail (OSS_IS_DEVICE (device), -1);
+
+ return device->priv->fd;
+}
+
+const gchar *
+oss_device_get_path (OssDevice *device)
+{
+ g_return_val_if_fail (OSS_IS_DEVICE (device), NULL);
+
+ return device->priv->path;
+}
+
+OssStream *
+oss_device_get_input_stream (OssDevice *device)
+{
+ g_return_val_if_fail (OSS_IS_DEVICE (device), NULL);
+
+ return device->priv->input;
+}
+
+OssStream *
+oss_device_get_output_stream (OssDevice *device)
+{
+ g_return_val_if_fail (OSS_IS_DEVICE (device), NULL);
+
+ return device->priv->output;
+}
+
+static GList *
+oss_device_list_streams (MateMixerDevice *mmd)
+{
+ OssDevice *device;
+ GList *list = NULL;
+
+ g_return_val_if_fail (OSS_IS_DEVICE (mmd), NULL);
+
+ device = OSS_DEVICE (mmd);
+
+ if (device->priv->output != NULL)
+ list = g_list_prepend (list, g_object_ref (device->priv->output));
+ if (device->priv->input != NULL)
+ list = g_list_prepend (list, g_object_ref (device->priv->input));
+
+ return list;
+}
+
+#define OSS_MASK_HAS_DEVICE(mask,i) ((gboolean) (((mask) & (1 << (i))) > 0))
+
+static gboolean
+read_mixer_devices (OssDevice *device)
+{
+ gint i;
+
+ for (i = 0; i < OSS_N_DEVICES; i++) {
+ OssStreamControl *control;
+ gboolean input = FALSE;
+
+ /* Skip unavailable controls */
+ if (OSS_MASK_HAS_DEVICE (device->priv->devmask, i) == FALSE)
+ continue;
+
+ if (oss_devices[i].type == OSS_DEV_ANY) {
+ input = OSS_MASK_HAS_DEVICE (device->priv->recmask, i);
+ }
+ else if (oss_devices[i].type == OSS_DEV_INPUT) {
+ input = TRUE;
+ }
+
+ control = oss_stream_control_new (oss_devices[i].name,
+ oss_devices[i].label,
+ oss_devices[i].role,
+ device->priv->fd,
+ i,
+ OSS_MASK_HAS_DEVICE (device->priv->stereodevs, i));
+
+ if (input == TRUE) {
+ oss_stream_add_control (OSS_STREAM (device->priv->input), control);
+
+ if (i == SOUND_MIXER_RECLEV || i == SOUND_MIXER_IGAIN) {
+ if (i == SOUND_MIXER_RECLEV)
+ set_stream_default_control (OSS_STREAM (device->priv->input),
+ control,
+ TRUE);
+ else
+ set_stream_default_control (OSS_STREAM (device->priv->input),
+ control,
+ FALSE);
+ }
+ } else {
+ oss_stream_add_control (OSS_STREAM (device->priv->output), control);
+
+ if (i == SOUND_MIXER_VOLUME || i == SOUND_MIXER_PCM) {
+ if (i == SOUND_MIXER_VOLUME)
+ set_stream_default_control (OSS_STREAM (device->priv->output),
+ control,
+ TRUE);
+ else
+ set_stream_default_control (OSS_STREAM (device->priv->output),
+ control,
+ FALSE);
+ }
+ }
+
+ g_debug ("Added control %s",
+ mate_mixer_stream_control_get_label (MATE_MIXER_STREAM_CONTROL (control)));
+
+ oss_stream_control_update (control);
+ }
+ return TRUE;
+}
+
+static gboolean
+set_stream_default_control (OssStream *stream, OssStreamControl *control, gboolean force)
+{
+ MateMixerStreamControl *current;
+
+ current = mate_mixer_stream_get_default_control (MATE_MIXER_STREAM (stream));
+ if (current == NULL || force == TRUE) {
+ oss_stream_set_default_control (stream, OSS_STREAM_CONTROL (control));
+ return TRUE;
+ }
+ return FALSE;
+}
diff --git a/backends/oss/oss-device.h b/backends/oss/oss-device.h
new file mode 100644
index 0000000..261a884
--- /dev/null
+++ b/backends/oss/oss-device.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the licence, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef OSS_DEVICE_H
+#define OSS_DEVICE_H
+
+#include <glib.h>
+#include <glib-object.h>
+#include <libmatemixer/matemixer.h>
+
+#include "oss-stream.h"
+
+G_BEGIN_DECLS
+
+#define OSS_TYPE_DEVICE \
+ (oss_device_get_type ())
+#define OSS_DEVICE(o) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((o), OSS_TYPE_DEVICE, OssDevice))
+#define OSS_IS_DEVICE(o) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((o), OSS_TYPE_DEVICE))
+#define OSS_DEVICE_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_CAST ((k), OSS_TYPE_DEVICE, OssDeviceClass))
+#define OSS_IS_DEVICE_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_TYPE ((k), OSS_TYPE_DEVICE))
+#define OSS_DEVICE_GET_CLASS(o) \
+ (G_TYPE_INSTANCE_GET_CLASS ((o), OSS_TYPE_DEVICE, OssDeviceClass))
+
+typedef struct _OssDevice OssDevice;
+typedef struct _OssDeviceClass OssDeviceClass;
+typedef struct _OssDevicePrivate OssDevicePrivate;
+
+struct _OssDevice
+{
+ MateMixerDevice parent;
+
+ /*< private >*/
+ OssDevicePrivate *priv;
+};
+
+struct _OssDeviceClass
+{
+ MateMixerDeviceClass parent;
+};
+
+GType oss_device_get_type (void) G_GNUC_CONST;
+
+OssDevice * oss_device_new (const gchar *name,
+ const gchar *label,
+ const gchar *path,
+ gint fd);
+
+gboolean oss_device_open (OssDevice *device);
+gboolean oss_device_load (OssDevice *device);
+
+gint oss_device_get_fd (OssDevice *device);
+const gchar *oss_device_get_path (OssDevice *device);
+
+OssStream * oss_device_get_input_stream (OssDevice *device);
+OssStream * oss_device_get_output_stream (OssDevice *device);
+
+G_END_DECLS
+
+#endif /* OSS_DEVICE_H */
diff --git a/backends/oss/oss-stream-control.c b/backends/oss/oss-stream-control.c
new file mode 100644
index 0000000..5161528
--- /dev/null
+++ b/backends/oss/oss-stream-control.c
@@ -0,0 +1,392 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the licence, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <errno.h>
+#include <glib.h>
+#include <glib/gstdio.h>
+#include <glib-object.h>
+
+#include <libmatemixer/matemixer.h>
+#include <libmatemixer/matemixer-private.h>
+
+#include "oss-common.h"
+#include "oss-stream-control.h"
+
+struct _OssStreamControlPrivate
+{
+ gint fd;
+ gint devnum;
+ guint volume[2];
+ gfloat balance;
+ gboolean stereo;
+ MateMixerStreamControlRole role;
+ MateMixerStreamControlFlags flags;
+};
+
+static void oss_stream_control_class_init (OssStreamControlClass *klass);
+
+static void oss_stream_control_init (OssStreamControl *control);
+static void oss_stream_control_finalize (GObject *object);
+
+G_DEFINE_TYPE (OssStreamControl, oss_stream_control, MATE_MIXER_TYPE_STREAM_CONTROL)
+
+static gboolean oss_stream_control_set_mute (MateMixerStreamControl *mmsc,
+ gboolean mute);
+
+static guint oss_stream_control_get_num_channels (MateMixerStreamControl *mmsc);
+
+static guint oss_stream_control_get_volume (MateMixerStreamControl *mmsc);
+
+static gboolean oss_stream_control_set_volume (MateMixerStreamControl *mmsc,
+ guint volume);
+
+static gboolean oss_stream_control_has_channel_position (MateMixerStreamControl *mmsc,
+ MateMixerChannelPosition position);
+static MateMixerChannelPosition oss_stream_control_get_channel_position (MateMixerStreamControl *mmsc,
+ guint channel);
+
+static guint oss_stream_control_get_channel_volume (MateMixerStreamControl *mmsc,
+ guint channel);
+static gboolean oss_stream_control_set_channel_volume (MateMixerStreamControl *mmsc,
+ guint channel,
+ guint volume);
+
+static gboolean oss_stream_control_set_balance (MateMixerStreamControl *mmsc,
+ gfloat balance);
+
+static guint oss_stream_control_get_min_volume (MateMixerStreamControl *mmsc);
+static guint oss_stream_control_get_max_volume (MateMixerStreamControl *mmsc);
+static guint oss_stream_control_get_normal_volume (MateMixerStreamControl *mmsc);
+static guint oss_stream_control_get_base_volume (MateMixerStreamControl *mmsc);
+
+static gboolean write_volume (OssStreamControl *control,
+ gint volume);
+
+static void
+oss_stream_control_class_init (OssStreamControlClass *klass)
+{
+ GObjectClass *object_class;
+ MateMixerStreamControlClass *control_class;
+
+ object_class = G_OBJECT_CLASS (klass);
+ object_class->finalize = oss_stream_control_finalize;
+
+ control_class = MATE_MIXER_STREAM_CONTROL_CLASS (klass);
+ control_class->set_mute = oss_stream_control_set_mute;
+ control_class->get_num_channels = oss_stream_control_get_num_channels;
+ control_class->get_volume = oss_stream_control_get_volume;
+ control_class->set_volume = oss_stream_control_set_volume;
+ control_class->get_channel_volume = oss_stream_control_get_channel_volume;
+ control_class->set_channel_volume = oss_stream_control_set_channel_volume;
+ control_class->get_channel_position = oss_stream_control_get_channel_position;
+ control_class->has_channel_position = oss_stream_control_has_channel_position;
+ control_class->set_balance = oss_stream_control_set_balance;
+ control_class->get_min_volume = oss_stream_control_get_min_volume;
+ control_class->get_max_volume = oss_stream_control_get_max_volume;
+ control_class->get_normal_volume = oss_stream_control_get_normal_volume;
+ control_class->get_base_volume = oss_stream_control_get_base_volume;
+
+ g_type_class_add_private (object_class, sizeof (OssStreamControlPrivate));
+}
+
+static void
+oss_stream_control_init (OssStreamControl *control)
+{
+ control->priv = G_TYPE_INSTANCE_GET_PRIVATE (control,
+ OSS_TYPE_STREAM_CONTROL,
+ OssStreamControlPrivate);
+}
+
+static void
+oss_stream_control_finalize (GObject *object)
+{
+ OssStreamControl *control;
+
+ control = OSS_STREAM_CONTROL (object);
+
+ close (control->priv->fd);
+
+ G_OBJECT_CLASS (oss_stream_control_parent_class)->finalize (object);
+}
+
+OssStreamControl *
+oss_stream_control_new (const gchar *name,
+ const gchar *label,
+ MateMixerStreamControlRole role,
+ gint fd,
+ gint devnum,
+ gboolean stereo)
+{
+ OssStreamControl *control;
+ MateMixerStreamControlFlags flags;
+
+ flags = MATE_MIXER_STREAM_CONTROL_HAS_VOLUME |
+ MATE_MIXER_STREAM_CONTROL_CAN_SET_VOLUME;
+ if (stereo == TRUE)
+ flags |= MATE_MIXER_STREAM_CONTROL_CAN_BALANCE;
+
+ control = g_object_new (OSS_TYPE_STREAM_CONTROL,
+ "name", name,
+ "label", label,
+ "flags", flags,
+ NULL);
+
+ control->priv->fd = fd;
+ control->priv->devnum = devnum;
+ control->priv->stereo = stereo;
+ return control;
+}
+
+gboolean
+oss_stream_control_update (OssStreamControl *control)
+{
+ gint v;
+ gint ret;
+
+ g_return_val_if_fail (OSS_IS_STREAM_CONTROL (control), FALSE);
+
+ ret = ioctl (control->priv->fd, MIXER_READ (control->priv->devnum), &v);
+ if (ret < 0) {
+ g_warning ("Failed to read volume: %s", g_strerror (errno));
+ return FALSE;
+ }
+
+ control->priv->volume[0] = v & 0xFF;
+
+ if (control->priv->stereo == TRUE) {
+ gfloat balance;
+ guint left;
+ guint right;
+
+ control->priv->volume[1] = (v >> 8) & 0xFF;
+
+ /* Calculate balance */
+ left = control->priv->volume[0];
+ right = control->priv->volume[1];
+ if (left == right)
+ balance = 0.0f;
+ else if (left > right)
+ balance = -1.0f + ((gfloat) right / (gfloat) left);
+ else
+ balance = +1.0f - ((gfloat) left / (gfloat) right);
+
+ _mate_mixer_stream_control_set_balance (MATE_MIXER_STREAM_CONTROL (control),
+ balance);
+ }
+ return TRUE;
+}
+
+static gboolean
+oss_stream_control_set_mute (MateMixerStreamControl *mmsc, gboolean mute)
+{
+ g_return_val_if_fail (OSS_IS_STREAM_CONTROL (mmsc), FALSE);
+
+ // TODO
+ return TRUE;
+}
+
+static guint
+oss_stream_control_get_num_channels (MateMixerStreamControl *mmsc)
+{
+ g_return_val_if_fail (OSS_IS_STREAM_CONTROL (mmsc), 0);
+
+ return (OSS_STREAM_CONTROL (mmsc)->priv->stereo == TRUE) ? 2 : 1;
+}
+
+static guint
+oss_stream_control_get_volume (MateMixerStreamControl *mmsc)
+{
+ OssStreamControl *control;
+
+ g_return_val_if_fail (OSS_IS_STREAM_CONTROL (mmsc), 0);
+
+ control = OSS_STREAM_CONTROL (mmsc);
+
+ if (control->priv->stereo == TRUE)
+ return MAX (control->priv->volume[0], control->priv->volume[1]);
+ else
+ return control->priv->volume[0];
+}
+
+static gboolean
+oss_stream_control_set_volume (MateMixerStreamControl *mmsc, guint volume)
+{
+ OssStreamControl *control;
+ gint v;
+
+ g_return_val_if_fail (OSS_IS_STREAM_CONTROL (mmsc), FALSE);
+
+ control = OSS_STREAM_CONTROL (mmsc);
+
+ v = CLAMP (volume, 0, 100);
+ if (control->priv->stereo == TRUE)
+ v |= (volume & 0xFF) << 8;
+
+ return write_volume (control, v);
+}
+
+static guint
+oss_stream_control_get_channel_volume (MateMixerStreamControl *mmsc, guint channel)
+{
+ OssStreamControl *control;
+
+ g_return_val_if_fail (OSS_IS_STREAM_CONTROL (mmsc), 0);
+
+ control = OSS_STREAM_CONTROL (mmsc);
+
+ if (control->priv->stereo == TRUE) {
+ if (channel == 0 || channel == 1)
+ return control->priv->volume[channel];
+ } else {
+ if (channel == 0)
+ return control->priv->volume[0];
+ }
+ return 0;
+}
+
+static gboolean
+oss_stream_control_set_channel_volume (MateMixerStreamControl *mmsc,
+ guint channel,
+ guint volume)
+{
+ OssStreamControl *control;
+ gint v;
+
+ g_return_val_if_fail (OSS_IS_STREAM_CONTROL (mmsc), FALSE);
+
+ control = OSS_STREAM_CONTROL (mmsc);
+ volume = CLAMP (volume, 0, 100);
+
+ if (control->priv->stereo == TRUE) {
+ if (channel > 1)
+ return FALSE;
+
+ /* Stereo channel volume - left channel is in the lowest 8 bits and
+ * right channel is in the higher 8 bits */
+ if (channel == 0)
+ v = volume | (control->priv->volume[1] << 8);
+ else
+ v = control->priv->volume[0] | (volume << 8);
+ } else {
+ if (channel > 0)
+ return FALSE;
+
+ /* Single channel volume - only lowest 8 bits are used */
+ v = volume;
+ }
+
+ return write_volume (control, v);
+}
+
+static MateMixerChannelPosition
+oss_stream_control_get_channel_position (MateMixerStreamControl *mmsc, guint channel)
+{
+ OssStreamControl *control;
+
+ g_return_val_if_fail (OSS_IS_STREAM_CONTROL (mmsc), MATE_MIXER_CHANNEL_UNKNOWN);
+
+ control = OSS_STREAM_CONTROL (mmsc);
+
+ if (control->priv->stereo == TRUE) {
+ if (channel == 0)
+ return MATE_MIXER_CHANNEL_FRONT_LEFT;
+ else if (channel == 1)
+ return MATE_MIXER_CHANNEL_FRONT_RIGHT;
+ } else {
+ if (channel == 0)
+ return MATE_MIXER_CHANNEL_MONO;
+ }
+ return MATE_MIXER_CHANNEL_UNKNOWN;
+}
+
+static gboolean
+oss_stream_control_has_channel_position (MateMixerStreamControl *mmsc,
+ MateMixerChannelPosition position)
+{
+ g_return_val_if_fail (OSS_IS_STREAM_CONTROL (mmsc), FALSE);
+
+ if (position == MATE_MIXER_CHANNEL_MONO)
+ return OSS_STREAM_CONTROL (mmsc)->priv->stereo == FALSE;
+
+ if (position == MATE_MIXER_CHANNEL_FRONT_LEFT ||
+ position == MATE_MIXER_CHANNEL_FRONT_RIGHT)
+ return OSS_STREAM_CONTROL (mmsc)->priv->stereo == TRUE;
+
+ return FALSE;
+}
+
+static gboolean
+oss_stream_control_set_balance (MateMixerStreamControl *mmsc, gfloat balance)
+{
+ OssStreamControl *control;
+ guint max;
+ gint v;
+
+ g_return_val_if_fail (OSS_IS_STREAM_CONTROL (mmsc), FALSE);
+
+ control = OSS_STREAM_CONTROL (mmsc);
+
+ max = MAX (control->priv->volume[0], control->priv->volume[1]);
+ if (balance <= 0) {
+ control->priv->volume[1] = (balance + 1.0f) * max;
+ control->priv->volume[0] = max;
+ } else {
+ control->priv->volume[0] = (1.0f - balance) * max;
+ control->priv->volume[1] = max;
+ }
+
+ v = control->priv->volume[0] | (control->priv->volume[1] << 8);
+
+ return write_volume (control, v);
+}
+
+static guint
+oss_stream_control_get_min_volume (MateMixerStreamControl *mmsc)
+{
+ return 0;
+}
+
+static guint
+oss_stream_control_get_max_volume (MateMixerStreamControl *mmsc)
+{
+ return 100;
+}
+
+static guint
+oss_stream_control_get_normal_volume (MateMixerStreamControl *mmsc)
+{
+ return 100;
+}
+
+static guint
+oss_stream_control_get_base_volume (MateMixerStreamControl *mmsc)
+{
+ return 100;
+}
+
+static gboolean
+write_volume (OssStreamControl *control, gint volume)
+{
+ gint ret;
+
+ ret = ioctl (control->priv->fd, MIXER_WRITE (control->priv->devnum), &volume);
+ if (ret < 0) {
+ g_warning ("Failed to set volume: %s", g_strerror (errno));
+ return FALSE;
+ }
+ return TRUE;
+}
diff --git a/backends/oss/oss-stream-control.h b/backends/oss/oss-stream-control.h
new file mode 100644
index 0000000..c839faf
--- /dev/null
+++ b/backends/oss/oss-stream-control.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the licence, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef OSS_STREAM_CONTROL_H
+#define OSS_STREAM_CONTROL_H
+
+#include <glib.h>
+#include <glib-object.h>
+#include <libmatemixer/matemixer.h>
+
+G_BEGIN_DECLS
+
+#define OSS_TYPE_STREAM_CONTROL \
+ (oss_stream_control_get_type ())
+#define OSS_STREAM_CONTROL(o) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((o), OSS_TYPE_STREAM_CONTROL, OssStreamControl))
+#define OSS_IS_STREAM_CONTROL(o) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((o), OSS_TYPE_STREAM_CONTROL))
+#define OSS_STREAM_CONTROL_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_CAST ((k), OSS_TYPE_STREAM_CONTROL, OssStreamControlClass))
+#define OSS_IS_STREAM_CONTROL_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_TYPE ((k), OSS_TYPE_STREAM_CONTROL))
+#define OSS_STREAM_CONTROL_GET_CLASS(o) \
+ (G_TYPE_INSTANCE_GET_CLASS ((o), OSS_TYPE_STREAM_CONTROL, OssStreamControlClass))
+
+typedef struct _OssStreamControl OssStreamControl;
+typedef struct _OssStreamControlClass OssStreamControlClass;
+typedef struct _OssStreamControlPrivate OssStreamControlPrivate;
+
+struct _OssStreamControl
+{
+ MateMixerStreamControl parent;
+
+ /*< private >*/
+ OssStreamControlPrivate *priv;
+};
+
+struct _OssStreamControlClass
+{
+ MateMixerStreamControlClass parent;
+};
+
+GType oss_stream_control_get_type (void) G_GNUC_CONST;
+
+OssStreamControl *oss_stream_control_new (const gchar *name,
+ const gchar *label,
+ MateMixerStreamControlRole role,
+ gint fd,
+ gint devnum,
+ gboolean stereo);
+
+gboolean oss_stream_control_update (OssStreamControl *control);
+
+G_END_DECLS
+
+#endif /* OSS_STREAM_CONTROL_H */
diff --git a/backends/oss/oss-stream.c b/backends/oss/oss-stream.c
new file mode 100644
index 0000000..5f0c629
--- /dev/null
+++ b/backends/oss/oss-stream.c
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the licence, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <glib.h>
+#include <glib-object.h>
+#include <libmatemixer/matemixer.h>
+
+#include "oss-device.h"
+#include "oss-stream.h"
+#include "oss-stream-control.h"
+
+struct _OssStreamPrivate
+{
+ GHashTable *controls;
+ OssStreamControl *control;
+};
+
+static void oss_stream_class_init (OssStreamClass *klass);
+
+static void oss_stream_init (OssStream *ostream);
+static void oss_stream_dispose (GObject *object);
+static void oss_stream_finalize (GObject *object);
+
+G_DEFINE_TYPE (OssStream, oss_stream, MATE_MIXER_TYPE_STREAM)
+
+static MateMixerStreamControl *oss_stream_get_control (MateMixerStream *stream,
+ const gchar *name);
+static MateMixerStreamControl *oss_stream_get_default_control (MateMixerStream *stream);
+
+static GList * oss_stream_list_controls (MateMixerStream *stream);
+
+static void
+oss_stream_class_init (OssStreamClass *klass)
+{
+ GObjectClass *object_class;
+ MateMixerStreamClass *stream_class;
+
+ object_class = G_OBJECT_CLASS (klass);
+ object_class->dispose = oss_stream_dispose;
+ object_class->finalize = oss_stream_finalize;
+
+ stream_class = MATE_MIXER_STREAM_CLASS (klass);
+ stream_class->get_control = oss_stream_get_control;
+ stream_class->get_default_control = oss_stream_get_default_control;
+ stream_class->list_controls = oss_stream_list_controls;
+
+ g_type_class_add_private (object_class, sizeof (OssStreamPrivate));
+}
+
+static void
+oss_stream_init (OssStream *stream)
+{
+ stream->priv = G_TYPE_INSTANCE_GET_PRIVATE (stream,
+ OSS_TYPE_STREAM,
+ OssStreamPrivate);
+
+ stream->priv->controls = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ g_free,
+ g_object_unref);
+}
+
+static void
+oss_stream_dispose (GObject *object)
+{
+ OssStream *stream;
+
+ stream = OSS_STREAM (object);
+
+ g_clear_object (&stream->priv->control);
+ g_hash_table_remove_all (stream->priv->controls);
+
+ G_OBJECT_CLASS (oss_stream_parent_class)->dispose (object);
+}
+
+static void
+oss_stream_finalize (GObject *object)
+{
+ OssStream *stream;
+
+ stream = OSS_STREAM (object);
+
+ g_hash_table_destroy (stream->priv->controls);
+
+ G_OBJECT_CLASS (oss_stream_parent_class)->finalize (object);
+}
+
+OssStream *
+oss_stream_new (const gchar *name,
+ MateMixerDevice *device,
+ MateMixerStreamFlags flags)
+{
+ OssStream *stream;
+
+ stream = g_object_new (OSS_TYPE_STREAM,
+ "name", name,
+ "device", device,
+ "flags", flags,
+ NULL);
+ return stream;
+}
+
+gboolean
+oss_stream_add_control (OssStream *stream, OssStreamControl *control)
+{
+ const gchar *name;
+
+ g_return_val_if_fail (OSS_IS_STREAM (stream), FALSE);
+ g_return_val_if_fail (OSS_IS_STREAM_CONTROL (control), FALSE);
+
+ name = mate_mixer_stream_control_get_name (MATE_MIXER_STREAM_CONTROL (control));
+
+ g_hash_table_insert (stream->priv->controls,
+ g_strdup (name),
+ control);
+ return TRUE;
+}
+
+gboolean
+oss_stream_set_default_control (OssStream *stream, OssStreamControl *control)
+{
+ g_return_val_if_fail (OSS_IS_STREAM (stream), FALSE);
+ g_return_val_if_fail (OSS_IS_STREAM_CONTROL (control), FALSE);
+
+ /* This function is only used internally so avoid validating that the control
+ * belongs to this stream */
+ if (stream->priv->control != NULL)
+ g_object_unref (stream->priv->control);
+
+ if G_LIKELY (control != NULL)
+ stream->priv->control = g_object_ref (control);
+ else
+ stream->priv->control = NULL;
+
+ return TRUE;
+}
+
+static MateMixerStreamControl *
+oss_stream_get_control (MateMixerStream *mms, const gchar *name)
+{
+ g_return_val_if_fail (OSS_IS_STREAM (mms), NULL);
+ g_return_val_if_fail (name != NULL, NULL);
+
+ return g_hash_table_lookup (OSS_STREAM (mms)->priv->controls, name);
+}
+
+static MateMixerStreamControl *
+oss_stream_get_default_control (MateMixerStream *mms)
+{
+ g_return_val_if_fail (OSS_IS_STREAM (mms), NULL);
+
+ return MATE_MIXER_STREAM_CONTROL (OSS_STREAM (mms)->priv->control);
+}
+
+static GList *
+oss_stream_list_controls (MateMixerStream *mms)
+{
+ GList *list;
+
+ g_return_val_if_fail (OSS_IS_STREAM (mms), NULL);
+
+ /* Convert the hash table to a linked list, this list is expected to be
+ * cached in the main library */
+ list = g_hash_table_get_values (OSS_STREAM (mms)->priv->controls);
+ if (list != NULL)
+ g_list_foreach (list, (GFunc) g_object_ref, NULL);
+
+ return list;
+}
diff --git a/backends/oss/oss-stream.h b/backends/oss/oss-stream.h
new file mode 100644
index 0000000..0470eb7
--- /dev/null
+++ b/backends/oss/oss-stream.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the licence, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef OSS_STREAM_H
+#define OSS_STREAM_H
+
+#include <glib.h>
+#include <glib-object.h>
+#include <libmatemixer/matemixer.h>
+
+#include "oss-device.h"
+#include "oss-stream-control.h"
+
+G_BEGIN_DECLS
+
+#define OSS_TYPE_STREAM \
+ (oss_stream_get_type ())
+#define OSS_STREAM(o) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((o), OSS_TYPE_STREAM, OssStream))
+#define OSS_IS_STREAM(o) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((o), OSS_TYPE_STREAM))
+#define OSS_STREAM_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_CAST ((k), OSS_TYPE_STREAM, OssStreamClass))
+#define OSS_IS_STREAM_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_TYPE ((k), OSS_TYPE_STREAM))
+#define OSS_STREAM_GET_CLASS(o) \
+ (G_TYPE_INSTANCE_GET_CLASS ((o), OSS_TYPE_STREAM, OssStreamClass))
+
+typedef struct _OssStream OssStream;
+typedef struct _OssStreamClass OssStreamClass;
+typedef struct _OssStreamPrivate OssStreamPrivate;
+
+struct _OssStream
+{
+ MateMixerStream parent;
+
+ /*< private >*/
+ OssStreamPrivate *priv;
+};
+
+struct _OssStreamClass
+{
+ MateMixerStreamClass parent;
+};
+
+GType oss_stream_get_type (void) G_GNUC_CONST;
+
+OssStream *oss_stream_new (const gchar *name,
+ MateMixerDevice *device,
+ MateMixerStreamFlags flags);
+
+gboolean oss_stream_add_control (OssStream *stream,
+ OssStreamControl *control);
+
+gboolean oss_stream_set_default_control (OssStream *stream,
+ OssStreamControl *control);
+
+G_END_DECLS
+
+#endif /* OSS_STREAM_H */
diff --git a/configure.ac b/configure.ac
index 3adfcba..d376b19 100644
--- a/configure.ac
+++ b/configure.ac
@@ -61,7 +61,7 @@ LT_INIT
# =======================================================================
PKG_PROG_PKG_CONFIG
-GLIB_REQUIRED_VERSION=2.36.0
+GLIB_REQUIRED_VERSION=2.32.0
PKG_CHECK_MODULES(GLIB, [
glib-2.0 >= $GLIB_REQUIRED_VERSION
@@ -118,6 +118,75 @@ AC_SUBST(HAVE_PULSEAUDIO)
AC_SUBST(PULSEAUDIO_CFLAGS)
AC_SUBST(PULSEAUDIO_LIBS)
+# -----------------------------------------------------------------------
+# ALSA
+# -----------------------------------------------------------------------
+ALSA_REQUIRED_VERSION=1.0.0
+
+AC_ARG_ENABLE([alsa],
+ AS_HELP_STRING([--enable-alsa],
+ [Enable ALSA backend module @<:@default=auto@:>@]),
+ enable_alsa=$enableval, enable_alsa=auto)
+
+if test "x$enable_alsa" != "xno"; then
+ PKG_CHECK_MODULES(ALSA, [
+ alsa >= $ALSA_REQUIRED_VERSION
+ gthread-2.0 >= $GLIB_REQUIRED_VERSION
+ ],
+ have_alsa=yes,
+ have_alsa=no)
+
+ if test "x$enable_alsa" = "xyes" -a "x$have_alsa" = "xno"; then
+ AC_MSG_ERROR([ALSA support explicitly requested but dependencies not found])
+ fi
+
+ if test "x$have_alsa" = "xyes" ; then
+ AC_DEFINE(HAVE_ALSA, [], [Define if we have ALSA support])
+ fi
+fi
+
+AM_CONDITIONAL(HAVE_ALSA, test "x$have_alsa" = "xyes")
+
+AC_SUBST(HAVE_ALSA)
+AC_SUBST(ALSA_CFLAGS)
+AC_SUBST(ALSA_LIBS)
+
+# -----------------------------------------------------------------------
+# OSS
+# -----------------------------------------------------------------------
+AC_ARG_ENABLE([oss],
+ AS_HELP_STRING([--enable-oss],
+ [Enable OSS backend module @<:@default=no@:>@]),
+ enable_oss=$enableval, enable_oss=no)
+
+if test "x$enable_oss" != "xno"; then
+ AC_CHECK_HEADERS([soundcard.h sys/soundcard.h machine/soundcard.h])
+ if test "x$ac_cv_header_soundcard_h" = "xyes" -o \
+ "x$ac_cv_header_sys_soundcard_h" = "xyes" -o \
+ "x$ac_cv_header_machine_soundcard_h" = "xyes"; then
+ AC_CHECK_LIB([ossaudio], [_oss_ioctl], [OSS_LIBS="-lossaudio"])
+ have_oss=yes
+ else
+ have_oss=no
+ fi
+
+ if test "x$enable_oss" = "xyes" -a "x$have_oss" = "xno"; then
+ AC_MSG_ERROR([OSS support explicitly requested but dependencies not found])
+ fi
+
+ if test "x$have_oss" = "xyes" ; then
+ AC_DEFINE(HAVE_OSS, [], [Define if we have OSS support])
+ fi
+else
+ have_oss=no
+fi
+
+AM_CONDITIONAL(HAVE_OSS, test "x$have_oss" = "xyes")
+
+AC_SUBST(HAVE_OSS)
+AC_SUBST(OSS_CFLAGS)
+AC_SUBST(OSS_LIBS)
+
# =======================================================================
# Compiler warnings
# =======================================================================
@@ -170,6 +239,8 @@ libmatemixer/Makefile
backends/Makefile
backends/null/Makefile
backends/pulse/Makefile
+backends/alsa/Makefile
+backends/oss/Makefile
data/Makefile
data/libmatemixer.pc
docs/Makefile
@@ -193,5 +264,7 @@ echo "
Build Null module: $have_null
Build PulseAudio module: $have_pulseaudio
+ Build ALSA module: $have_alsa
+ Build OSS module: $have_oss
"
diff --git a/examples/monitor.c b/examples/monitor.c
index 3267b36..71d8b61 100644
--- a/examples/monitor.c
+++ b/examples/monitor.c
@@ -26,7 +26,7 @@
#include <libmatemixer/matemixer.h>
-static MateMixerControl *control;
+static MateMixerContext *context;
static GMainLoop *mainloop;
static gchar *
@@ -57,6 +57,30 @@ create_app_string (const gchar *app_name,
}
static const gchar *
+get_stream_control_role_string (MateMixerStreamControlRole role)
+{
+ switch (role) {
+ case MATE_MIXER_STREAM_CONTROL_ROLE_UNKNOWN:
+ return "Unknown";
+ case MATE_MIXER_STREAM_CONTROL_ROLE_MASTER:
+ return "Master";
+ case MATE_MIXER_STREAM_CONTROL_ROLE_PCM:
+ return "PCM";
+ case MATE_MIXER_STREAM_CONTROL_ROLE_BASS:
+ return "Bass";
+ case MATE_MIXER_STREAM_CONTROL_ROLE_TREBLE:
+ return "Treble";
+ case MATE_MIXER_STREAM_CONTROL_ROLE_CD:
+ return "CD";
+ case MATE_MIXER_STREAM_CONTROL_ROLE_SPEAKER:
+ return "PC Speaker";
+ case MATE_MIXER_STREAM_CONTROL_ROLE_PORT:
+ return "Port";
+ }
+ return "Unknown";
+}
+
+static const gchar *
create_role_string (MateMixerClientStreamRole role)
{
switch (role) {
@@ -89,7 +113,7 @@ create_role_string (MateMixerClientStreamRole role)
}
static gchar *
-create_volume_bar (MateMixerStream *stream, double *percent)
+create_volume_bar (MateMixerStreamControl *ctl, double *percent)
{
GString *string;
gint64 volume;
@@ -100,9 +124,9 @@ create_volume_bar (MateMixerStream *stream, double *percent)
int length = 30;
int stars;
- volume = mate_mixer_stream_get_volume (stream);
- volume_min = mate_mixer_stream_get_min_volume (stream);
- volume_max = mate_mixer_stream_get_normal_volume (stream);
+ volume = mate_mixer_stream_control_get_volume (ctl);
+ volume_min = mate_mixer_stream_control_get_min_volume (ctl);
+ volume_max = mate_mixer_stream_control_get_normal_volume (ctl);
string = g_string_new ("[");
@@ -122,39 +146,21 @@ static void
print_devices (void)
{
const GList *devices;
- const GList *ports;
const GList *profiles;
MateMixerDeviceProfile *active_profile;
- devices = mate_mixer_control_list_devices (control);
+ devices = mate_mixer_context_list_devices (context);
while (devices) {
MateMixerDevice *device = MATE_MIXER_DEVICE (devices->data);
g_print ("Device %s\n"
- " |-| Description : %s\n"
- " |-| Icon Name : %s\n\n",
+ " |-| Label : %s\n"
+ " |-| Icon Name : %s\n\n",
mate_mixer_device_get_name (device),
- mate_mixer_device_get_description (device),
+ mate_mixer_device_get_label (device),
mate_mixer_device_get_icon (device));
- ports = mate_mixer_device_list_ports (device);
- while (ports) {
- MateMixerPort *port = MATE_MIXER_PORT (ports->data);
-
- g_print (" |-| Port %s\n"
- " |-| Description : %s\n"
- " |-| Icon Name : %s\n"
- " |-| Priority : %u\n"
- " |-| Status : \n\n",
- mate_mixer_port_get_name (port),
- mate_mixer_port_get_description (port),
- mate_mixer_port_get_icon (port),
- mate_mixer_port_get_priority (port));
-
- ports = ports->next;
- }
-
profiles = mate_mixer_device_list_profiles (device);
active_profile = mate_mixer_device_get_active_profile (device);
@@ -162,15 +168,15 @@ print_devices (void)
MateMixerDeviceProfile *profile = MATE_MIXER_DEVICE_PROFILE (profiles->data);
g_print (" |%c| Profile %s\n"
- " |-| Description : %s\n"
- " |-| Priority : %u\n"
- " |-| Inputs : %u\n"
- " |-| Outputs : %u\n\n",
+ " |-| Label : %s\n"
+ " |-| Priority : %u\n"
+ " |-| Inputs : %u\n"
+ " |-| Outputs : %u\n\n",
(profile == active_profile)
? 'A'
: '-',
mate_mixer_device_profile_get_name (profile),
- mate_mixer_device_profile_get_description (profile),
+ mate_mixer_device_profile_get_label (profile),
mate_mixer_device_profile_get_priority (profile),
mate_mixer_device_profile_get_num_input_streams (profile),
mate_mixer_device_profile_get_num_output_streams (profile));
@@ -179,6 +185,35 @@ print_devices (void)
}
g_print ("\n");
+ const GList *switches = mate_mixer_device_list_switches (device);
+
+ while (switches != NULL) {
+ MateMixerSwitch *swtch = MATE_MIXER_SWITCH (switches->data);
+ MateMixerSwitchOption *active = mate_mixer_switch_get_active_option (swtch);
+
+ const GList *options;
+
+ options = mate_mixer_switch_list_options (swtch);
+
+ g_print ("Switch %s\n",
+ mate_mixer_switch_get_name (swtch));
+
+ while (options != NULL) {
+ MateMixerSwitchOption *option = MATE_MIXER_SWITCH_OPTION (options->data);
+
+ g_print (" |%c| %s\n",
+ (option == active)
+ ? '*'
+ : '-',
+ mate_mixer_switch_option_get_label (option));
+
+ options = options->next;
+ }
+
+ switches = switches->next;
+ }
+ g_print ("\n");
+
devices = devices->next;
}
}
@@ -187,45 +222,85 @@ static void
print_streams (void)
{
const GList *streams;
- const GList *ports;
- streams = mate_mixer_control_list_streams (control);
+ streams = mate_mixer_context_list_streams (context);
while (streams) {
- MateMixerStream *stream = MATE_MIXER_STREAM (streams->data);
- MateMixerClientStream *client = NULL;
- gchar *volume_bar;
- gdouble volume;
+ MateMixerStream *stream = MATE_MIXER_STREAM (streams->data);
+ MateMixerStreamControl *ctl;
+ MateMixerSwitch *swtch;
+ MateMixerClientStream *client = NULL;
+ gchar *volume_bar;
+ gdouble volume;
+
+ const GList *controls;
+ const GList *switches;
if (mate_mixer_stream_get_flags (stream) & MATE_MIXER_STREAM_CLIENT) {
/* The application-specific details are accessible through the client
* interface, which all client streams implement */
client = MATE_MIXER_CLIENT_STREAM (stream);
+ }
- /* Ignore event streams */
- if (mate_mixer_client_stream_get_role (client) == MATE_MIXER_CLIENT_STREAM_ROLE_EVENT) {
- streams = streams->next;
- continue;
- }
+ controls = mate_mixer_stream_list_controls (stream);
+
+ while (controls != NULL) {
+ ctl = MATE_MIXER_STREAM_CONTROL (controls->data);
+
+ const gchar *role;
+
+ role = get_stream_control_role_string (mate_mixer_stream_control_get_role (ctl));
+
+ // XXX volume is sometimes -nan, use flags
+ volume_bar = create_volume_bar (ctl, &volume);
+
+ g_print ("Stream %s control %s / %s\n"
+ " |-| Volume : %s %.1f %% (%.1f dB)\n"
+ " |-| Muted : %s\n"
+ " |-| Channels : %d\n"
+ " |-| Balance : %.1f\n"
+ " |-| Fade : %.1f\n"
+ " |-| Role : %s\n",
+ mate_mixer_stream_get_name (stream),
+ mate_mixer_stream_control_get_name (ctl),
+ mate_mixer_stream_control_get_label (ctl),
+ volume_bar,
+ volume,
+ mate_mixer_stream_control_get_decibel (ctl),
+ mate_mixer_stream_control_get_mute (ctl) ? "Yes" : "No",
+ mate_mixer_stream_control_get_num_channels (ctl),
+ mate_mixer_stream_control_get_balance (ctl),
+ mate_mixer_stream_control_get_fade (ctl),
+ role);
+
+ g_free (volume_bar);
+
+ controls = controls->next;
}
- volume_bar = create_volume_bar (stream, &volume);
+ switches = mate_mixer_stream_list_switches (stream);
- g_print ("Stream %s\n"
- " |-| Description : %s\n"
- " |-| Volume : %s %.1f %%\n"
- " |-| Muted : %s\n"
- " |-| Channels : %d\n"
- " |-| Balance : %.1f\n"
- " |-| Fade : %.1f\n",
- mate_mixer_stream_get_name (stream),
- mate_mixer_stream_get_description (stream),
- volume_bar,
- volume,
- mate_mixer_stream_get_mute (stream) ? "Yes" : "No",
- mate_mixer_stream_get_num_channels (stream),
- mate_mixer_stream_get_balance (stream),
- mate_mixer_stream_get_fade (stream));
+ while (switches != NULL) {
+ swtch = MATE_MIXER_SWITCH (switches->data);
+ const GList *options;
+
+ options = mate_mixer_switch_list_options (swtch);
+
+ g_print ("Switch %s\n",
+ mate_mixer_switch_get_name (swtch));
+
+ while (options != NULL) {
+ MateMixerSwitchOption *option = MATE_MIXER_SWITCH_OPTION (options->data);
+
+ g_print (" |%c| %s\n",
+ '-',
+ mate_mixer_switch_option_get_label (option));
+
+ options = options->next;
+ }
+
+ options = options->next;
+ }
if (client != NULL) {
MateMixerClientStreamFlags client_flags;
@@ -243,51 +318,36 @@ print_streams (void)
}
g_print ("\n");
- g_free (volume_bar);
-
- ports = mate_mixer_stream_list_ports (stream);
- while (ports) {
- MateMixerPort *port = MATE_MIXER_PORT (ports->data);
-
- g_print (" |-| Port %s\n"
- " |-| Description : %s\n"
- " |-| Icon Name : %s\n"
- " |-| Priority : %u\n"
- " |-| Status : \n\n",
- mate_mixer_port_get_name (port),
- mate_mixer_port_get_description (port),
- mate_mixer_port_get_icon (port),
- mate_mixer_port_get_priority (port));
-
- ports = ports->next;
- }
streams = streams->next;
}
}
static void
-print_cached_streams (void)
+print_stored_streams (void)
{
const GList *streams;
- streams = mate_mixer_control_list_cached_streams (control);
+ streams = mate_mixer_context_list_stored_streams (context);
while (streams) {
MateMixerStream *stream = MATE_MIXER_STREAM (streams->data);
+ MateMixerStreamControl *ctl;
MateMixerClientStream *client;
MateMixerClientStreamFlags client_flags;
MateMixerClientStreamRole client_role;
gchar *volume_bar;
gdouble volume;
- client = MATE_MIXER_CLIENT_STREAM (stream);
+ ctl = mate_mixer_stream_get_default_control (stream);
+
+ client = MATE_MIXER_CLIENT_STREAM (stream);
client_flags = mate_mixer_client_stream_get_flags (client);
client_role = mate_mixer_client_stream_get_role (client);
- volume_bar = create_volume_bar (stream, &volume);
+ volume_bar = create_volume_bar (ctl, &volume);
- g_print ("Cached stream %s\n"
+ g_print ("Stored stream %s\n"
" |-| Role : %s\n"
" |-| Volume : %s %.1f %%\n"
" |-| Muted : %s\n"
@@ -298,10 +358,10 @@ print_cached_streams (void)
create_role_string (client_role),
volume_bar,
volume,
- mate_mixer_stream_get_mute (stream) ? "Yes" : "No",
- mate_mixer_stream_get_num_channels (stream),
- mate_mixer_stream_get_balance (stream),
- mate_mixer_stream_get_fade (stream));
+ mate_mixer_stream_control_get_mute (ctl) ? "Yes" : "No",
+ mate_mixer_stream_control_get_num_channels (ctl),
+ mate_mixer_stream_control_get_balance (ctl),
+ mate_mixer_stream_control_get_fade (ctl));
if (client_flags & MATE_MIXER_CLIENT_STREAM_APPLICATION) {
gchar *app = create_app_string (mate_mixer_client_stream_get_app_name (client),
@@ -323,11 +383,11 @@ static void
connected (void)
{
g_print ("Connected using the %s backend.\n\n",
- mate_mixer_control_get_backend_name (control));
+ mate_mixer_context_get_backend_name (context));
print_devices ();
print_streams ();
- print_cached_streams ();
+ print_stored_streams ();
g_print ("Waiting for events. Hit CTRL+C to quit.\n");
}
@@ -337,7 +397,7 @@ state_cb (void)
{
MateMixerState state;
- state = mate_mixer_control_get_state (control);
+ state = mate_mixer_context_get_state (context);
switch (state) {
case MATE_MIXER_STATE_READY:
@@ -353,25 +413,25 @@ state_cb (void)
}
static void
-device_added_cb (MateMixerControl *control, const gchar *name)
+device_added_cb (MateMixerContext *context, const gchar *name)
{
g_print ("Device added: %s\n", name);
}
static void
-device_removed_cb (MateMixerControl *control, const gchar *name)
+device_removed_cb (MateMixerContext *context, const gchar *name)
{
g_print ("Device removed: %s\n", name);
}
static void
-stream_added_cb (MateMixerControl *control, const gchar *name)
+stream_added_cb (MateMixerContext *context, const gchar *name)
{
g_print ("Stream added: %s\n", name);
}
static void
-stream_removed_cb (MateMixerControl *control, const gchar *name)
+stream_removed_cb (MateMixerContext *context, const gchar *name)
{
g_print ("Stream removed: %s\n", name);
}
@@ -388,22 +448,22 @@ signal_cb (gpointer mainloop)
int main (int argc, char *argv[])
{
MateMixerState state;
- GOptionContext *context;
+ GOptionContext *ctx;
gchar *backend = NULL;
gchar *server = NULL;
GError *error = NULL;
GOptionEntry entries[] = {
- { "backend", 'b', 0, G_OPTION_ARG_STRING, &backend, "Sound system to use (pulseaudio, null)", NULL },
+ { "backend", 'b', 0, G_OPTION_ARG_STRING, &backend, "Sound system to use (pulseaudio, alsa, oss, null)", NULL },
{ "server", 's', 0, G_OPTION_ARG_STRING, &server, "Sound server address", NULL },
{ NULL }
};
- context = g_option_context_new ("- libmatemixer monitor");
+ ctx = g_option_context_new ("- libmatemixer monitor");
- g_option_context_add_main_entries (context, entries, NULL);
+ g_option_context_add_main_entries (ctx, entries, NULL);
- if (!g_option_context_parse (context, &argc, &argv, &error)) {
+ if (!g_option_context_parse (ctx, &argc, &argv, &error)) {
g_printerr ("%s\n", error->message);
g_error_free (error);
return 1;
@@ -415,20 +475,24 @@ int main (int argc, char *argv[])
setlocale (LC_ALL, "");
- /* Set up the controller, through which we access the main functionality */
- control = mate_mixer_control_new ();
+ /* Set up the contextler, through which we access the main functionality */
+ context = mate_mixer_context_new ();
/* Some details about our application, only used with the PulseAudio backend */
- mate_mixer_control_set_app_name (control, "MateMixer Monitor");
- mate_mixer_control_set_app_id (control, "org.mate-desktop.libmatemixer-monitor");
- mate_mixer_control_set_app_version (control, "1.0");
- mate_mixer_control_set_app_icon (control, "multimedia-volume-control");
+ mate_mixer_context_set_app_name (context, "MateMixer Monitor");
+ mate_mixer_context_set_app_id (context, "org.mate-desktop.libmatemixer-monitor");
+ mate_mixer_context_set_app_version (context, "1.0");
+ mate_mixer_context_set_app_icon (context, "multimedia-volume-context");
if (backend) {
if (!strcmp (backend, "pulseaudio"))
- mate_mixer_control_set_backend_type (control, MATE_MIXER_BACKEND_PULSEAUDIO);
+ mate_mixer_context_set_backend_type (context, MATE_MIXER_BACKEND_PULSEAUDIO);
+ else if (!strcmp (backend, "alsa"))
+ mate_mixer_context_set_backend_type (context, MATE_MIXER_BACKEND_ALSA);
+ else if (!strcmp (backend, "oss"))
+ mate_mixer_context_set_backend_type (context, MATE_MIXER_BACKEND_OSS);
else if (!strcmp (backend, "null"))
- mate_mixer_control_set_backend_type (control, MATE_MIXER_BACKEND_NULL);
+ mate_mixer_context_set_backend_type (context, MATE_MIXER_BACKEND_NULL);
else
g_printerr ("Sound system backend '%s' is unknown, it will be auto-detected.\n",
backend);
@@ -437,40 +501,39 @@ int main (int argc, char *argv[])
}
if (server) {
- mate_mixer_control_set_server_address (control, server);
+ mate_mixer_context_set_server_address (context, server);
g_free (server);
}
/* Initiate connection to the sound server */
- if (!mate_mixer_control_open (control)) {
- g_object_unref (control);
- mate_mixer_deinit ();
+ if (!mate_mixer_context_open (context)) {
+ g_object_unref (context);
return 1;
}
- g_signal_connect (G_OBJECT (control),
+ g_signal_connect (G_OBJECT (context),
"device-added",
G_CALLBACK (device_added_cb),
NULL);
- g_signal_connect (G_OBJECT (control),
+ g_signal_connect (G_OBJECT (context),
"device-removed",
G_CALLBACK (device_removed_cb),
NULL);
- g_signal_connect (G_OBJECT (control),
+ g_signal_connect (G_OBJECT (context),
"stream-added",
G_CALLBACK (stream_added_cb),
NULL);
- g_signal_connect (G_OBJECT (control),
+ g_signal_connect (G_OBJECT (context),
"stream-removed",
G_CALLBACK (stream_removed_cb),
NULL);
- /* If mate_mixer_control_open() returns TRUE, the state will be either
+ /* If mate_mixer_context_open() returns TRUE, the state will be either
* MATE_MIXER_STATE_READY or MATE_MIXER_STATE_CONNECTING.
*
- * In case mate_mixer_control_open() returned FALSE, the current state
+ * In case mate_mixer_context_open() returned FALSE, the current state
* would be MATE_MIXER_STATE_FAILED */
- state = mate_mixer_control_get_state (control);
+ state = mate_mixer_context_get_state (context);
switch (state) {
case MATE_MIXER_STATE_READY:
@@ -480,7 +543,7 @@ int main (int argc, char *argv[])
g_print ("Waiting for connection...\n");
/* Wait for the state transition */
- g_signal_connect (control,
+ g_signal_connect (context,
"notify::state",
G_CALLBACK (state_cb),
NULL);
@@ -499,8 +562,7 @@ int main (int argc, char *argv[])
g_main_loop_run (mainloop);
- g_object_unref (control);
- mate_mixer_deinit ();
+ g_object_unref (context);
return 0;
}
diff --git a/libmatemixer/Makefile.am b/libmatemixer/Makefile.am
index 8c219d4..8858b90 100644
--- a/libmatemixer/Makefile.am
+++ b/libmatemixer/Makefile.am
@@ -11,12 +11,16 @@ libmatemixer_includedir = $(includedir)/libmatemixer
libmatemixer_include_HEADERS = \
matemixer.h \
matemixer-client-stream.h \
- matemixer-control.h \
+ matemixer-context.h \
matemixer-device.h \
matemixer-device-profile.h \
matemixer-enums.h \
- matemixer-port.h \
matemixer-stream.h \
+ matemixer-stream-control.h \
+ matemixer-switch.h \
+ matemixer-switch-option.h \
+ matemixer-toggle.h \
+ matemixer-types.h \
matemixer-version.h
libmatemixer_la_CFLAGS = $(GLIB_CFLAGS)
@@ -26,18 +30,24 @@ libmatemixer_la_SOURCES = \
matemixer-private.h \
matemixer-backend.c \
matemixer-backend.h \
+ matemixer-backend-private.h \
matemixer-backend-module.c \
matemixer-backend-module.h \
matemixer-client-stream.c \
- matemixer-control.c \
+ matemixer-context.c \
matemixer-device.c \
matemixer-device-profile.c \
matemixer-device-profile-private.h \
matemixer-enum-types.c \
matemixer-enum-types.h \
- matemixer-port.c \
- matemixer-port-private.h \
- matemixer-stream.c
+ matemixer-stream.c \
+ matemixer-stream-control.c \
+ matemixer-stream-control-private.h \
+ matemixer-switch.c \
+ matemixer-switch-private.h \
+ matemixer-switch-option.c \
+ matemixer-switch-option-private.h \
+ matemixer-toggle.c
libmatemixer_la_LIBADD = $(GLIB_LIBS)
diff --git a/libmatemixer/matemixer-backend-module.c b/libmatemixer/matemixer-backend-module.c
index a3146d2..0e7716e 100644
--- a/libmatemixer/matemixer-backend-module.c
+++ b/libmatemixer/matemixer-backend-module.c
@@ -22,16 +22,19 @@
#include "matemixer-backend.h"
#include "matemixer-backend-module.h"
-struct _MateMixerBackendModulePrivate
-{
- GModule *gmodule;
- gchar *path;
- gboolean loaded;
+/* Initialize backend */
+typedef void (*BackendInit) (GTypeModule *type_module);
- void (*init) (GTypeModule *type_module);
- void (*deinit) (void);
+/* Return information about backend */
+typedef const MateMixerBackendInfo *(*BackendGetInfo) (void);
- const MateMixerBackendInfo *(*get_info) (void);
+struct _MateMixerBackendModulePrivate
+{
+ GModule *gmodule;
+ gchar *path;
+ gboolean loaded;
+ BackendInit init;
+ BackendGetInfo get_info;
};
enum {
@@ -102,6 +105,7 @@ mate_mixer_backend_module_get_property (GObject *object,
case PROP_PATH:
g_value_set_string (value, module->priv->path);
break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
break;
@@ -122,7 +126,10 @@ mate_mixer_backend_module_set_property (GObject *object,
case PROP_PATH:
/* Construct-only string */
module->priv->path = g_strdup (g_value_get_string (value));
+
+ g_type_module_set_name (G_TYPE_MODULE (object), module->priv->path);
break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
break;
@@ -157,8 +164,11 @@ mate_mixer_backend_module_dispose (GObject *object)
static void
mate_mixer_backend_module_finalize (GObject *object)
{
- /* This is in fact never called */
- g_free (MATE_MIXER_BACKEND_MODULE (object)->priv->path);
+ MateMixerBackendModule *module;
+
+ module = MATE_MIXER_BACKEND_MODULE (object);
+
+ g_free (module->priv->path);
G_OBJECT_CLASS (mate_mixer_backend_module_parent_class)->finalize (object);
}
@@ -174,17 +184,11 @@ mate_mixer_backend_module_finalize (GObject *object)
MateMixerBackendModule *
mate_mixer_backend_module_new (const gchar *path)
{
- MateMixerBackendModule *module;
-
g_return_val_if_fail (path != NULL, NULL);
- module = g_object_new (MATE_MIXER_TYPE_BACKEND_MODULE,
- "path", path,
- NULL);
-
- g_type_module_set_name (G_TYPE_MODULE (module), path);
-
- return module;
+ return g_object_new (MATE_MIXER_TYPE_BACKEND_MODULE,
+ "path", path,
+ NULL);
}
/**
@@ -227,76 +231,57 @@ backend_module_load (GTypeModule *type_module)
module = MATE_MIXER_BACKEND_MODULE (type_module);
- if (module->priv->loaded == FALSE) {
- module->priv->gmodule = g_module_open (module->priv->path,
- G_MODULE_BIND_LAZY |
- G_MODULE_BIND_LOCAL);
- if (module->priv->gmodule == NULL) {
- g_warning ("Failed to load backend module %s: %s",
- module->priv->path,
- g_module_error ());
-
- return FALSE;
- }
-
- /* Validate library symbols that each backend module must provide */
- if (g_module_symbol (module->priv->gmodule,
- "backend_module_init",
- (gpointer *) &module->priv->init) == FALSE ||
- g_module_symbol (module->priv->gmodule,
- "backend_module_get_info",
- (gpointer *) &module->priv->get_info) == FALSE) {
- g_warning ("Failed to load backend module %s: %s",
- module->priv->path,
- g_module_error ());
-
- g_module_close (module->priv->gmodule);
- return FALSE;
- }
-
- /* Optional backend function */
+ if (module->priv->loaded == TRUE)
+ return TRUE;
+
+ module->priv->gmodule = g_module_open (module->priv->path,
+ G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL);
+ if (module->priv->gmodule == NULL) {
+ g_warning ("Failed to load backend module %s: %s",
+ module->priv->path,
+ g_module_error ());
+
+ return FALSE;
+ }
+
+ /* Validate library symbols that each backend module must provide */
+ if (g_module_symbol (module->priv->gmodule,
+ "backend_module_init",
+ (gpointer *) &module->priv->init) == FALSE ||
g_module_symbol (module->priv->gmodule,
- "backend_module_deinit",
- (gpointer *) &module->priv->deinit);
-
- module->priv->init (type_module);
- module->priv->loaded = TRUE;
-
- /* Make sure get_info() returns something, so we can avoid checking it
- * in other parts of the library */
- if (G_UNLIKELY (module->priv->get_info () == NULL)) {
- g_critical ("Backend module %s does not provide module information",
- module->priv->path);
-
- /* Close the module but keep the loaded flag to avoid unreffing
- * this instance as the GType has most likely been registered */
- g_module_close (module->priv->gmodule);
- return FALSE;
- }
-
- /* It is not possible to unref this instance, so let's avoid unloading
- * the module and just let the backend module (de)initialize when
- * (de)init functions are called repeatedly */
- g_module_make_resident (module->priv->gmodule);
-
- g_debug ("Loaded backend module %s", module->priv->path);
- } else {
- /* This function was called before, so avoid loading and initialize only */
- module->priv->init (type_module);
+ "backend_module_get_info",
+ (gpointer *) &module->priv->get_info) == FALSE) {
+ g_warning ("Failed to load backend module %s: %s",
+ module->priv->path,
+ g_module_error ());
+
+ g_module_close (module->priv->gmodule);
+ return FALSE;
+ }
+
+ module->priv->init (type_module);
+ module->priv->loaded = TRUE;
+
+ /* Make sure get_info() returns something, so we can avoid checking it
+ * in other parts of the library */
+ if (G_UNLIKELY (module->priv->get_info () == NULL)) {
+ g_critical ("Backend module %s does not provide module information",
+ module->priv->path);
+
+ /* Close the module but keep the loaded flag to avoid unreffing
+ * this instance as the GType has most likely been registered */
+ g_module_close (module->priv->gmodule);
+ return FALSE;
}
+ /* It is not possible to unref this instance, so keep the module alive */
+ g_module_make_resident (module->priv->gmodule);
+
+ g_debug ("Loaded backend module %s", module->priv->path);
return TRUE;
}
static void
backend_module_unload (GTypeModule *type_module)
{
- MateMixerBackendModule *module;
-
- module = MATE_MIXER_BACKEND_MODULE (type_module);
-
- /* Only deinitialize the backend module, do not modify the loaded flag
- * as the module remains loaded */
- if (module->priv->deinit)
- module->priv->deinit ();
}
diff --git a/libmatemixer/matemixer-backend-module.h b/libmatemixer/matemixer-backend-module.h
index 62b0a43..e1dfd8d 100644
--- a/libmatemixer/matemixer-backend-module.h
+++ b/libmatemixer/matemixer-backend-module.h
@@ -21,17 +21,10 @@
#include <glib.h>
#include <glib-object.h>
-#include "matemixer-enums.h"
+#include <libmatemixer/matemixer-enums.h>
G_BEGIN_DECLS
-typedef struct {
- gchar *name;
- guint priority;
- GType g_type;
- MateMixerBackendType backend_type;
-} MateMixerBackendInfo;
-
#define MATE_MIXER_TYPE_BACKEND_MODULE \
(mate_mixer_backend_module_get_type ())
#define MATE_MIXER_BACKEND_MODULE(o) \
@@ -45,6 +38,7 @@ typedef struct {
#define MATE_MIXER_BACKEND_MODULE_GET_CLASS(o) \
(G_TYPE_INSTANCE_GET_CLASS ((o), MATE_MIXER_TYPE_BACKEND_MODULE, MateMixerBackendModuleClass))
+typedef struct _MateMixerBackendInfo MateMixerBackendInfo;
typedef struct _MateMixerBackendModule MateMixerBackendModule;
typedef struct _MateMixerBackendModuleClass MateMixerBackendModuleClass;
typedef struct _MateMixerBackendModulePrivate MateMixerBackendModulePrivate;
@@ -62,6 +56,14 @@ struct _MateMixerBackendModuleClass
GTypeModuleClass parent_class;
};
+struct _MateMixerBackendInfo
+{
+ gchar *name;
+ guint priority;
+ GType g_type;
+ MateMixerBackendType backend_type;
+};
+
GType mate_mixer_backend_module_get_type (void) G_GNUC_CONST;
MateMixerBackendModule * mate_mixer_backend_module_new (const gchar *path);
diff --git a/libmatemixer/matemixer-backend-private.h b/libmatemixer/matemixer-backend-private.h
new file mode 100644
index 0000000..b5de8ae
--- /dev/null
+++ b/libmatemixer/matemixer-backend-private.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the licence, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef MATEMIXER_BACKEND_PRIVATE_H
+#define MATEMIXER_BACKEND_PRIVATE_H
+
+#include <glib.h>
+
+#include "matemixer-backend.h"
+#include "matemixer-enums.h"
+#include "matemixer-stream.h"
+
+G_BEGIN_DECLS
+
+void _mate_mixer_backend_set_state (MateMixerBackend *backend,
+ MateMixerState state);
+
+void _mate_mixer_backend_set_default_input_stream (MateMixerBackend *backend,
+ MateMixerStream *stream);
+
+void _mate_mixer_backend_set_default_output_stream (MateMixerBackend *backend,
+ MateMixerStream *stream);
+
+G_END_DECLS
+
+#endif /* MATEMIXER_BACKEND_PRIVATE_H */
diff --git a/libmatemixer/matemixer-backend.c b/libmatemixer/matemixer-backend.c
index be5c704..fab0883 100644
--- a/libmatemixer/matemixer-backend.c
+++ b/libmatemixer/matemixer-backend.c
@@ -15,61 +15,122 @@
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
+#include <string.h>
#include <glib.h>
#include <glib-object.h>
#include "matemixer-backend.h"
+#include "matemixer-backend-private.h"
#include "matemixer-enums.h"
#include "matemixer-enum-types.h"
#include "matemixer-stream.h"
+struct _MateMixerBackendPrivate
+{
+ GList *devices;
+ GList *streams;
+ GList *stored_streams;
+ MateMixerStream *default_input;
+ MateMixerStream *default_output;
+ MateMixerState state;
+ MateMixerBackendFlags flags;
+};
+
+enum {
+ PROP_0,
+ PROP_STATE,
+ PROP_DEFAULT_INPUT_STREAM,
+ PROP_DEFAULT_OUTPUT_STREAM,
+ N_PROPERTIES
+};
+
+static GParamSpec *properties[N_PROPERTIES] = { NULL, };
+
enum {
DEVICE_ADDED,
DEVICE_REMOVED,
STREAM_ADDED,
STREAM_REMOVED,
- CACHED_STREAM_ADDED,
- CACHED_STREAM_REMOVED,
+ STORED_STREAM_ADDED,
+ STORED_STREAM_REMOVED,
N_SIGNALS
};
static guint signals[N_SIGNALS] = { 0, };
-G_DEFINE_INTERFACE (MateMixerBackend, mate_mixer_backend, G_TYPE_OBJECT)
+static void mate_mixer_backend_class_init (MateMixerBackendClass *klass);
+
+static void mate_mixer_backend_init (MateMixerBackend *backend);
+
+static void mate_mixer_backend_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec);
+static void mate_mixer_backend_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec);
+
+static void mate_mixer_backend_dispose (GObject *object);
+
+G_DEFINE_ABSTRACT_TYPE (MateMixerBackend, mate_mixer_backend, G_TYPE_OBJECT)
+
+static void device_added (MateMixerBackend *backend, const gchar *name);
+static void device_removed (MateMixerBackend *backend, const gchar *name);
+
+static void device_stream_added (MateMixerDevice *device,
+ const gchar *name);
+static void device_stream_removed (MateMixerDevice *device,
+ const gchar *name);
+
+static void free_devices (MateMixerBackend *backend);
+static void free_streams (MateMixerBackend *backend);
+static void free_stored_streams (MateMixerBackend *backend);
+static void stream_removed (MateMixerBackend *backend,
+ const gchar *name);
static void
-mate_mixer_backend_default_init (MateMixerBackendInterface *iface)
+mate_mixer_backend_class_init (MateMixerBackendClass *klass)
{
- g_object_interface_install_property (iface,
- g_param_spec_enum ("state",
- "State",
- "Current backend connection state",
- MATE_MIXER_TYPE_STATE,
- MATE_MIXER_STATE_IDLE,
- G_PARAM_READABLE |
- G_PARAM_STATIC_STRINGS));
-
- g_object_interface_install_property (iface,
- g_param_spec_object ("default-input",
- "Default input",
- "Default input stream",
- MATE_MIXER_TYPE_STREAM,
- G_PARAM_READABLE |
- G_PARAM_STATIC_STRINGS));
-
- g_object_interface_install_property (iface,
- g_param_spec_object ("default-output",
- "Default output",
- "Default output stream",
- MATE_MIXER_TYPE_STREAM,
- G_PARAM_READABLE |
- G_PARAM_STATIC_STRINGS));
+ GObjectClass *object_class;
+
+ object_class = G_OBJECT_CLASS (klass);
+ object_class->dispose = mate_mixer_backend_dispose;
+ object_class->get_property = mate_mixer_backend_get_property;
+ object_class->set_property = mate_mixer_backend_set_property;
+
+ properties[PROP_STATE] =
+ g_param_spec_enum ("state",
+ "State",
+ "Current backend connection state",
+ MATE_MIXER_TYPE_STATE,
+ MATE_MIXER_STATE_IDLE,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_DEFAULT_INPUT_STREAM] =
+ g_param_spec_object ("default-input-stream",
+ "Default input stream",
+ "Default input stream",
+ MATE_MIXER_TYPE_STREAM,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_DEFAULT_OUTPUT_STREAM] =
+ g_param_spec_object ("default-output-stream",
+ "Default output stream",
+ "Default output stream",
+ MATE_MIXER_TYPE_STREAM,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS);
+
+ g_object_class_install_properties (object_class, N_PROPERTIES, properties);
signals[DEVICE_ADDED] =
g_signal_new ("device-added",
- G_TYPE_FROM_INTERFACE (iface),
+ G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (MateMixerBackendInterface, device_added),
+ G_STRUCT_OFFSET (MateMixerBackendClass, device_added),
NULL,
NULL,
g_cclosure_marshal_VOID__STRING,
@@ -79,9 +140,9 @@ mate_mixer_backend_default_init (MateMixerBackendInterface *iface)
signals[DEVICE_REMOVED] =
g_signal_new ("device-removed",
- G_TYPE_FROM_INTERFACE (iface),
+ G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (MateMixerBackendInterface, device_removed),
+ G_STRUCT_OFFSET (MateMixerBackendClass, device_removed),
NULL,
NULL,
g_cclosure_marshal_VOID__STRING,
@@ -91,9 +152,9 @@ mate_mixer_backend_default_init (MateMixerBackendInterface *iface)
signals[STREAM_ADDED] =
g_signal_new ("stream-added",
- G_TYPE_FROM_INTERFACE (iface),
+ G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (MateMixerBackendInterface, stream_added),
+ G_STRUCT_OFFSET (MateMixerBackendClass, stream_added),
NULL,
NULL,
g_cclosure_marshal_VOID__STRING,
@@ -103,9 +164,9 @@ mate_mixer_backend_default_init (MateMixerBackendInterface *iface)
signals[STREAM_REMOVED] =
g_signal_new ("stream-removed",
- G_TYPE_FROM_INTERFACE (iface),
+ G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (MateMixerBackendInterface, stream_removed),
+ G_STRUCT_OFFSET (MateMixerBackendClass, stream_removed),
NULL,
NULL,
g_cclosure_marshal_VOID__STRING,
@@ -113,11 +174,11 @@ mate_mixer_backend_default_init (MateMixerBackendInterface *iface)
1,
G_TYPE_STRING);
- signals[CACHED_STREAM_ADDED] =
- g_signal_new ("cached-stream-added",
- G_TYPE_FROM_INTERFACE (iface),
+ signals[STORED_STREAM_ADDED] =
+ g_signal_new ("stored-stream-added",
+ G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (MateMixerBackendInterface, cached_stream_added),
+ G_STRUCT_OFFSET (MateMixerBackendClass, stored_stream_added),
NULL,
NULL,
g_cclosure_marshal_VOID__STRING,
@@ -125,30 +186,149 @@ mate_mixer_backend_default_init (MateMixerBackendInterface *iface)
1,
G_TYPE_STRING);
- signals[CACHED_STREAM_REMOVED] =
- g_signal_new ("cached-stream-removed",
- G_TYPE_FROM_INTERFACE (iface),
+ signals[STORED_STREAM_REMOVED] =
+ g_signal_new ("stored-stream-removed",
+ G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (MateMixerBackendInterface, cached_stream_removed),
+ G_STRUCT_OFFSET (MateMixerBackendClass, stored_stream_removed),
NULL,
NULL,
g_cclosure_marshal_VOID__STRING,
G_TYPE_NONE,
1,
G_TYPE_STRING);
+
+ g_type_class_add_private (object_class, sizeof (MateMixerBackendPrivate));
+}
+
+static void
+mate_mixer_backend_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ MateMixerBackend *backend;
+
+ backend = MATE_MIXER_BACKEND (object);
+
+ switch (param_id) {
+ case PROP_STATE:
+ g_value_set_enum (value, backend->priv->state);
+ break;
+
+ case PROP_DEFAULT_INPUT_STREAM:
+ g_value_set_object (value, backend->priv->default_input);
+ break;
+
+ case PROP_DEFAULT_OUTPUT_STREAM:
+ g_value_set_object (value, backend->priv->default_output);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ }
+}
+
+static void
+mate_mixer_backend_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ MateMixerBackend *backend;
+
+ backend = MATE_MIXER_BACKEND (object);
+
+ switch (param_id) {
+ case PROP_DEFAULT_INPUT_STREAM:
+ mate_mixer_backend_set_default_input_stream (backend, g_value_get_object (value));
+ break;
+
+ case PROP_DEFAULT_OUTPUT_STREAM:
+ mate_mixer_backend_set_default_output_stream (backend, g_value_get_object (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ }
+}
+
+static void
+mate_mixer_backend_init (MateMixerBackend *backend)
+{
+ backend->priv = G_TYPE_INSTANCE_GET_PRIVATE (backend,
+ MATE_MIXER_TYPE_BACKEND,
+ MateMixerBackendPrivate);
+
+ g_signal_connect (G_OBJECT (backend),
+ "device-added",
+ G_CALLBACK (free_devices),
+ NULL);
+ g_signal_connect (G_OBJECT (backend),
+ "device-added",
+ G_CALLBACK (device_added),
+ NULL);
+
+ g_signal_connect (G_OBJECT (backend),
+ "device-removed",
+ G_CALLBACK (free_devices),
+ NULL);
+ g_signal_connect (G_OBJECT (backend),
+ "device-removed",
+ G_CALLBACK (device_removed),
+ NULL);
+
+ g_signal_connect (G_OBJECT (backend),
+ "stream-added",
+ G_CALLBACK (free_streams),
+ NULL);
+ g_signal_connect (G_OBJECT (backend),
+ "stream-removed",
+ G_CALLBACK (free_streams),
+ NULL);
+
+ g_signal_connect (G_OBJECT (backend),
+ "stored-stream-added",
+ G_CALLBACK (free_stored_streams),
+ NULL);
+ g_signal_connect (G_OBJECT (backend),
+ "stored-stream-removed",
+ G_CALLBACK (free_stored_streams),
+ NULL);
+
+ // XXX also free when changing state
+}
+
+static void
+mate_mixer_backend_dispose (GObject *object)
+{
+ MateMixerBackend *backend;
+
+ backend = MATE_MIXER_BACKEND (object);
+
+ free_devices (backend);
+ free_streams (backend);
+ free_stored_streams (backend);
+
+ g_clear_object (&backend->priv->default_input);
+ g_clear_object (&backend->priv->default_output);
+
+ G_OBJECT_CLASS (mate_mixer_backend_parent_class)->dispose (object);
}
void
-mate_mixer_backend_set_data (MateMixerBackend *backend, const MateMixerBackendData *data)
+mate_mixer_backend_set_data (MateMixerBackend *backend, MateMixerBackendData *data)
{
- MateMixerBackendInterface *iface;
+ MateMixerBackendClass *klass;
g_return_if_fail (MATE_MIXER_IS_BACKEND (backend));
- iface = MATE_MIXER_BACKEND_GET_INTERFACE (backend);
+ klass = MATE_MIXER_BACKEND_GET_CLASS (backend);
- if (iface->set_data)
- iface->set_data (backend, data);
+ if (klass->set_data != NULL)
+ klass->set_data (backend, data);
}
gboolean
@@ -157,20 +337,20 @@ mate_mixer_backend_open (MateMixerBackend *backend)
g_return_val_if_fail (MATE_MIXER_IS_BACKEND (backend), FALSE);
/* Implementation required */
- return MATE_MIXER_BACKEND_GET_INTERFACE (backend)->open (backend);
+ return MATE_MIXER_BACKEND_GET_CLASS (backend)->open (backend);
}
void
mate_mixer_backend_close (MateMixerBackend *backend)
{
- MateMixerBackendInterface *iface;
+ MateMixerBackendClass *klass;
g_return_if_fail (MATE_MIXER_IS_BACKEND (backend));
- iface = MATE_MIXER_BACKEND_GET_INTERFACE (backend);
+ klass = MATE_MIXER_BACKEND_GET_CLASS (backend);
- if (iface->close)
- iface->close (backend);
+ if (klass->close != NULL)
+ klass->close (backend);
}
MateMixerState
@@ -178,113 +358,266 @@ mate_mixer_backend_get_state (MateMixerBackend *backend)
{
g_return_val_if_fail (MATE_MIXER_IS_BACKEND (backend), MATE_MIXER_STATE_UNKNOWN);
- /* Implementation required */
- return MATE_MIXER_BACKEND_GET_INTERFACE (backend)->get_state (backend);
+ return backend->priv->state;
}
-GList *
-mate_mixer_backend_list_devices (MateMixerBackend *backend)
+MateMixerBackendFlags
+mate_mixer_backend_get_flags (MateMixerBackend *backend)
{
- MateMixerBackendInterface *iface;
+ g_return_val_if_fail (MATE_MIXER_IS_BACKEND (backend), MATE_MIXER_BACKEND_NO_FLAGS);
+ return backend->priv->flags;
+}
+
+const GList *
+mate_mixer_backend_list_devices (MateMixerBackend *backend)
+{
g_return_val_if_fail (MATE_MIXER_IS_BACKEND (backend), NULL);
- iface = MATE_MIXER_BACKEND_GET_INTERFACE (backend);
+ if (backend->priv->devices == NULL) {
+ MateMixerBackendClass *klass;
- if (iface->list_devices)
- return iface->list_devices (backend);
+ klass = MATE_MIXER_BACKEND_GET_CLASS (backend);
- return NULL;
+ if (klass->list_devices != NULL)
+ backend->priv->devices = klass->list_devices (backend);
+ }
+
+ return backend->priv->devices;
}
-GList *
+const GList *
mate_mixer_backend_list_streams (MateMixerBackend *backend)
{
- MateMixerBackendInterface *iface;
-
g_return_val_if_fail (MATE_MIXER_IS_BACKEND (backend), NULL);
- iface = MATE_MIXER_BACKEND_GET_INTERFACE (backend);
+ if (backend->priv->streams == NULL) {
+ MateMixerBackendClass *klass;
- if (iface->list_streams)
- return iface->list_streams (backend);
+ klass = MATE_MIXER_BACKEND_GET_CLASS (backend);
- return NULL;
+ if (klass->list_streams != NULL)
+ backend->priv->streams = klass->list_streams (backend);
+ }
+
+ return backend->priv->streams;
}
-GList *
-mate_mixer_backend_list_cached_streams (MateMixerBackend *backend)
+const GList *
+mate_mixer_backend_list_stored_streams (MateMixerBackend *backend)
{
- MateMixerBackendInterface *iface;
-
g_return_val_if_fail (MATE_MIXER_IS_BACKEND (backend), NULL);
- iface = MATE_MIXER_BACKEND_GET_INTERFACE (backend);
+ if (backend->priv->stored_streams == NULL) {
+ MateMixerBackendClass *klass;
- if (iface->list_cached_streams)
- return iface->list_cached_streams (backend);
+ klass = MATE_MIXER_BACKEND_GET_CLASS (backend);
- return NULL;
+ if (klass->list_stored_streams != NULL)
+ backend->priv->stored_streams = klass->list_stored_streams (backend);
+ }
+
+ return backend->priv->stored_streams;
}
MateMixerStream *
mate_mixer_backend_get_default_input_stream (MateMixerBackend *backend)
{
- MateMixerBackendInterface *iface;
+ MateMixerStream *stream = NULL;
g_return_val_if_fail (MATE_MIXER_IS_BACKEND (backend), NULL);
- iface = MATE_MIXER_BACKEND_GET_INTERFACE (backend);
+ g_object_get (G_OBJECT (backend),
+ "default-input-stream", &stream,
+ NULL);
- if (iface->get_default_input_stream)
- return iface->get_default_input_stream (backend);
+ if (stream != NULL)
+ g_object_unref (stream);
- return NULL;
+ return stream;
}
gboolean
mate_mixer_backend_set_default_input_stream (MateMixerBackend *backend,
MateMixerStream *stream)
{
- MateMixerBackendInterface *iface;
-
g_return_val_if_fail (MATE_MIXER_IS_BACKEND (backend), FALSE);
+ g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), FALSE);
+
+ if (backend->priv->default_input != stream) {
+ MateMixerBackendClass *klass;
+
+ klass = MATE_MIXER_BACKEND_GET_CLASS (backend);
- iface = MATE_MIXER_BACKEND_GET_INTERFACE (backend);
+ if (klass->set_default_input_stream == NULL ||
+ klass->set_default_input_stream (backend, stream) == FALSE)
+ return FALSE;
- if (iface->set_default_input_stream)
- return iface->set_default_input_stream (backend, stream);
+ _mate_mixer_backend_set_default_input_stream (backend, stream);
+ }
- return FALSE;
+ return TRUE;
}
MateMixerStream *
mate_mixer_backend_get_default_output_stream (MateMixerBackend *backend)
{
- MateMixerBackendInterface *iface;
+ MateMixerStream *stream = NULL;
g_return_val_if_fail (MATE_MIXER_IS_BACKEND (backend), NULL);
- iface = MATE_MIXER_BACKEND_GET_INTERFACE (backend);
+ g_object_get (G_OBJECT (backend),
+ "default-output-stream", &stream,
+ NULL);
- if (iface->get_default_output_stream)
- return iface->get_default_output_stream (backend);
+ if (stream != NULL)
+ g_object_unref (stream);
- return NULL;
+ return stream;
}
gboolean
mate_mixer_backend_set_default_output_stream (MateMixerBackend *backend,
MateMixerStream *stream)
{
- MateMixerBackendInterface *iface;
-
g_return_val_if_fail (MATE_MIXER_IS_BACKEND (backend), FALSE);
+ g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), FALSE);
+
+ if (backend->priv->default_input != stream) {
+ MateMixerBackendClass *klass;
+
+ klass = MATE_MIXER_BACKEND_GET_CLASS (backend);
+
+ if (klass->set_default_output_stream == NULL ||
+ klass->set_default_output_stream (backend, stream) == FALSE)
+ return FALSE;
+
+ _mate_mixer_backend_set_default_output_stream (backend, stream);
+ }
+
+ return TRUE;
+}
+
+static void
+device_added (MateMixerBackend *backend, const gchar *name)
+{
+ MateMixerDevice *device;
+
+ // device = mate_mixer_backend_get_device (backend, name);
+
+/*
+ g_signal_connect (G_OBJECT (device),
+ "stream-added",
+ G_CALLBACK (device_stream_added));
+ */
+}
+
+static void
+device_removed (MateMixerBackend *backend, const gchar *name)
+{
+}
+
+static void
+device_stream_added (MateMixerDevice *device, const gchar *name)
+{
+ g_signal_emit (G_OBJECT (device),
+ signals[STREAM_ADDED],
+ 0,
+ name);
+}
+
+static void
+device_stream_removed (MateMixerDevice *device, const gchar *name)
+{
+ g_signal_emit (G_OBJECT (device),
+ signals[STREAM_REMOVED],
+ 0,
+ name);
+}
+
+static void
+free_devices (MateMixerBackend *backend)
+{
+ if (backend->priv->devices == NULL)
+ return;
+
+ g_list_free_full (backend->priv->devices, g_object_unref);
+
+ backend->priv->devices = NULL;
+}
+
+static void
+free_streams (MateMixerBackend *backend)
+{
+ if (backend->priv->streams == NULL)
+ return;
+
+ g_list_free_full (backend->priv->streams, g_object_unref);
+
+ backend->priv->streams = NULL;
+}
+
+static void
+free_stored_streams (MateMixerBackend *backend)
+{
+ if (backend->priv->stored_streams == NULL)
+ return;
+
+ g_list_free_full (backend->priv->stored_streams, g_object_unref);
+
+ backend->priv->stored_streams = NULL;
+}
+
+/* Protected */
+void
+_mate_mixer_backend_set_state (MateMixerBackend *backend, MateMixerState state)
+{
+ if (backend->priv->state == state)
+ return;
+
+ backend->priv->state = state;
+
+ g_object_notify_by_pspec (G_OBJECT (backend), properties[PROP_STATE]);
+}
+
+void
+_mate_mixer_backend_set_default_input_stream (MateMixerBackend *backend,
+ MateMixerStream *stream)
+{
+ if (backend->priv->default_input == stream)
+ return;
+
+ if (backend->priv->default_input != NULL)
+ g_object_unref (backend->priv->default_input);
+
+ if (stream != NULL)
+ backend->priv->default_input = g_object_ref (stream);
+ else
+ backend->priv->default_input = NULL;
+
+ g_debug ("Default input stream changed to %s",
+ (stream != NULL) ? mate_mixer_stream_get_name (stream) : "none");
+
+ g_object_notify_by_pspec (G_OBJECT (backend), properties[PROP_DEFAULT_INPUT_STREAM]);
+}
+
+void
+_mate_mixer_backend_set_default_output_stream (MateMixerBackend *backend,
+ MateMixerStream *stream)
+{
+ if (backend->priv->default_output == stream)
+ return;
+
+ if (backend->priv->default_output != NULL)
+ g_object_unref (backend->priv->default_output);
- iface = MATE_MIXER_BACKEND_GET_INTERFACE (backend);
+ if (stream != NULL)
+ backend->priv->default_output = g_object_ref (stream);
+ else
+ backend->priv->default_output = NULL;
- if (iface->set_default_output_stream)
- return iface->set_default_output_stream (backend, stream);
+ g_debug ("Default output stream changed to %s",
+ (stream != NULL) ? mate_mixer_stream_get_name (stream) : "none");
- return FALSE;
+ g_object_notify_by_pspec (G_OBJECT (backend), properties[PROP_DEFAULT_OUTPUT_STREAM]);
}
diff --git a/libmatemixer/matemixer-backend.h b/libmatemixer/matemixer-backend.h
index 8bedfe0..1c918c9 100644
--- a/libmatemixer/matemixer-backend.h
+++ b/libmatemixer/matemixer-backend.h
@@ -21,94 +21,103 @@
#include <glib.h>
#include <glib-object.h>
-#include "matemixer-enums.h"
-#include "matemixer-stream.h"
+#include <libmatemixer/matemixer-enums.h>
+#include <libmatemixer/matemixer-types.h>
G_BEGIN_DECLS
-typedef struct
-{
- gchar *app_name;
- gchar *app_id;
- gchar *app_version;
- gchar *app_icon;
- gchar *server_address;
-} MateMixerBackendData;
-
#define MATE_MIXER_TYPE_BACKEND \
(mate_mixer_backend_get_type ())
#define MATE_MIXER_BACKEND(o) \
(G_TYPE_CHECK_INSTANCE_CAST ((o), MATE_MIXER_TYPE_BACKEND, MateMixerBackend))
#define MATE_MIXER_IS_BACKEND(o) \
(G_TYPE_CHECK_INSTANCE_TYPE ((o), MATE_MIXER_TYPE_BACKEND))
-#define MATE_MIXER_BACKEND_GET_INTERFACE(o) \
- (G_TYPE_INSTANCE_GET_INTERFACE ((o), MATE_MIXER_TYPE_BACKEND, MateMixerBackendInterface))
-
-typedef struct _MateMixerBackend MateMixerBackend; /* dummy object */
-typedef struct _MateMixerBackendInterface MateMixerBackendInterface;
-
-struct _MateMixerBackendInterface
+#define MATE_MIXER_BACKEND_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_CAST ((k), MATE_MIXER_TYPE_BACKEND, MateMixerBackendClass))
+#define MATE_MIXER_IS_BACKEND_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_TYPE ((k), MATE_MIXER_TYPE_BACKEND))
+#define MATE_MIXER_BACKEND_GET_CLASS(o) \
+ (G_TYPE_INSTANCE_GET_CLASS ((o), MATE_MIXER_TYPE_BACKEND, MateMixerBackendClass))
+
+typedef struct _MateMixerBackend MateMixerBackend;
+typedef struct _MateMixerBackendClass MateMixerBackendClass;
+typedef struct _MateMixerBackendData MateMixerBackendData;
+typedef struct _MateMixerBackendPrivate MateMixerBackendPrivate;
+
+struct _MateMixerBackend
{
- GTypeInterface parent_iface;
+ GObject object;
/*< private >*/
- /* Virtual table */
- void (*set_data) (MateMixerBackend *backend,
- const MateMixerBackendData *data);
+ MateMixerBackendPrivate *priv;
+};
- gboolean (*open) (MateMixerBackend *backend);
- void (*close) (MateMixerBackend *backend);
+struct _MateMixerBackendClass
+{
+ GObjectClass parent_class;
- MateMixerState (*get_state) (MateMixerBackend *backend);
+ /*< private >*/
+ void (*set_data) (MateMixerBackend *backend,
+ MateMixerBackendData *data);
- GList *(*list_devices) (MateMixerBackend *backend);
- GList *(*list_streams) (MateMixerBackend *backend);
- GList *(*list_cached_streams) (MateMixerBackend *backend);
+ gboolean (*open) (MateMixerBackend *backend);
+ void (*close) (MateMixerBackend *backend);
- MateMixerStream *(*get_default_input_stream) (MateMixerBackend *backend);
- gboolean (*set_default_input_stream) (MateMixerBackend *backend,
- MateMixerStream *stream);
+ GList *(*list_devices) (MateMixerBackend *backend);
+ GList *(*list_streams) (MateMixerBackend *backend);
+ GList *(*list_stored_streams) (MateMixerBackend *backend);
- MateMixerStream *(*get_default_output_stream) (MateMixerBackend *backend);
- gboolean (*set_default_output_stream) (MateMixerBackend *backend,
- MateMixerStream *stream);
+ gboolean (*set_default_input_stream) (MateMixerBackend *backend,
+ MateMixerStream *stream);
+ gboolean (*set_default_output_stream) (MateMixerBackend *backend,
+ MateMixerStream *stream);
/* Signals */
- void (*device_added) (MateMixerBackend *backend,
- const gchar *name);
- void (*device_removed) (MateMixerBackend *backend,
- const gchar *name);
- void (*stream_added) (MateMixerBackend *backend,
- const gchar *name);
- void (*stream_removed) (MateMixerBackend *backend,
- const gchar *name);
- void (*cached_stream_added) (MateMixerBackend *backend,
- const gchar *name);
- void (*cached_stream_removed) (MateMixerBackend *backend,
- const gchar *name);
+ void (*device_added) (MateMixerBackend *backend,
+ const gchar *name);
+ void (*device_removed) (MateMixerBackend *backend,
+ const gchar *name);
+ void (*stream_added) (MateMixerBackend *backend,
+ const gchar *name);
+ void (*stream_removed) (MateMixerBackend *backend,
+ const gchar *name);
+ void (*stored_stream_added) (MateMixerBackend *backend,
+ const gchar *name);
+ void (*stored_stream_removed) (MateMixerBackend *backend,
+ const gchar *name);
+};
+
+struct _MateMixerBackendData
+{
+ gchar *app_name;
+ gchar *app_id;
+ gchar *app_version;
+ gchar *app_icon;
+ gchar *server_address;
};
-GType mate_mixer_backend_get_type (void) G_GNUC_CONST;
+GType mate_mixer_backend_get_type (void) G_GNUC_CONST;
-void mate_mixer_backend_set_data (MateMixerBackend *backend,
- const MateMixerBackendData *data);
+void mate_mixer_backend_set_data (MateMixerBackend *backend,
+ MateMixerBackendData *data);
-gboolean mate_mixer_backend_open (MateMixerBackend *backend);
-void mate_mixer_backend_close (MateMixerBackend *backend);
+gboolean mate_mixer_backend_open (MateMixerBackend *backend);
+void mate_mixer_backend_close (MateMixerBackend *backend);
-MateMixerState mate_mixer_backend_get_state (MateMixerBackend *backend);
+MateMixerState mate_mixer_backend_get_state (MateMixerBackend *backend);
+MateMixerBackendFlags mate_mixer_backend_get_flags (MateMixerBackend *backend);
-GList * mate_mixer_backend_list_devices (MateMixerBackend *backend);
-GList * mate_mixer_backend_list_streams (MateMixerBackend *backend);
-GList * mate_mixer_backend_list_cached_streams (MateMixerBackend *backend);
+const GList * mate_mixer_backend_list_devices (MateMixerBackend *backend);
+const GList * mate_mixer_backend_list_streams (MateMixerBackend *backend);
+const GList * mate_mixer_backend_list_stored_streams (MateMixerBackend *backend);
-MateMixerStream *mate_mixer_backend_get_default_input_stream (MateMixerBackend *backend);
-gboolean mate_mixer_backend_set_default_input_stream (MateMixerBackend *backend,
- MateMixerStream *stream);
+MateMixerStream * mate_mixer_backend_get_default_input_stream (MateMixerBackend *backend);
+gboolean mate_mixer_backend_set_default_input_stream (MateMixerBackend *backend,
+ MateMixerStream *stream);
-MateMixerStream *mate_mixer_backend_get_default_output_stream (MateMixerBackend *backend);
-gboolean mate_mixer_backend_set_default_output_stream (MateMixerBackend *backend,
- MateMixerStream *stream);
+MateMixerStream * mate_mixer_backend_get_default_output_stream (MateMixerBackend *backend);
+gboolean mate_mixer_backend_set_default_output_stream (MateMixerBackend *backend,
+ MateMixerStream *stream);
G_END_DECLS
diff --git a/libmatemixer/matemixer-client-stream.c b/libmatemixer/matemixer-client-stream.c
index 3ff3c54..fc34622 100644
--- a/libmatemixer/matemixer-client-stream.c
+++ b/libmatemixer/matemixer-client-stream.c
@@ -35,68 +35,170 @@
* A typical example of a client stream is a stream provided by an application.
*/
-G_DEFINE_INTERFACE (MateMixerClientStream, mate_mixer_client_stream, G_TYPE_OBJECT)
+struct _MateMixerClientStreamPrivate
+{
+ gchar *app_name;
+ gchar *app_id;
+ gchar *app_version;
+ gchar *app_icon;
+ MateMixerStream *parent;
+ MateMixerClientStreamFlags client_flags;
+ MateMixerClientStreamRole client_role;
+};
+
+enum {
+ PROP_0,
+ PROP_CLIENT_FLAGS,
+ PROP_CLIENT_ROLE,
+ PROP_PARENT,
+ PROP_APP_NAME,
+ PROP_APP_ID,
+ PROP_APP_VERSION,
+ PROP_APP_ICON,
+ N_PROPERTIES
+};
+
+static GParamSpec *properties[N_PROPERTIES] = { NULL, };
+
+static void mate_mixer_client_stream_class_init (MateMixerClientStreamClass *klass);
+
+static void mate_mixer_client_stream_init (MateMixerClientStream *client);
+
+static void mate_mixer_client_stream_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec);
+static void mate_mixer_client_stream_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec);
+
+static void mate_mixer_client_stream_dispose (GObject *object);
+static void mate_mixer_client_stream_finalize (GObject *object);
+
+G_DEFINE_ABSTRACT_TYPE (MateMixerClientStream, mate_mixer_client_stream, MATE_MIXER_TYPE_STREAM)
+
+static void
+mate_mixer_client_stream_class_init (MateMixerClientStreamClass *klass)
+{
+ GObjectClass *object_class;
+
+ object_class = G_OBJECT_CLASS (klass);
+ object_class->dispose = mate_mixer_client_stream_dispose;
+ object_class->finalize = mate_mixer_client_stream_finalize;
+ object_class->get_property = mate_mixer_client_stream_get_property;
+ object_class->set_property = mate_mixer_client_stream_set_property;
+
+ properties[PROP_CLIENT_FLAGS] =
+ g_param_spec_flags ("client-flags",
+ "Client flags",
+ "Capability flags of the client stream",
+ MATE_MIXER_TYPE_CLIENT_STREAM_FLAGS,
+ MATE_MIXER_CLIENT_STREAM_NO_FLAGS,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_CLIENT_ROLE] =
+ g_param_spec_enum ("role",
+ "Role",
+ "Role of the client stream",
+ MATE_MIXER_TYPE_CLIENT_STREAM_ROLE,
+ MATE_MIXER_CLIENT_STREAM_ROLE_NONE,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_PARENT] =
+ g_param_spec_object ("parent",
+ "Parent",
+ "Parent stream of the client stream",
+ MATE_MIXER_TYPE_STREAM,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_APP_NAME] =
+ g_param_spec_string ("app-name",
+ "App name",
+ "Name of the client stream application",
+ NULL,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_APP_ID] =
+ g_param_spec_string ("app-id",
+ "App ID",
+ "Identifier of the client stream application",
+ NULL,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_APP_VERSION] =
+ g_param_spec_string ("app-version",
+ "App version",
+ "Version of the client stream application",
+ NULL,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_APP_ICON] =
+ g_param_spec_string ("app-icon",
+ "App icon",
+ "Icon name of the client stream application",
+ NULL,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS);
+
+ g_object_class_install_properties (object_class, N_PROPERTIES, properties);
+}
+
+static void
+mate_mixer_client_stream_init (MateMixerClientStream *client)
+{
+ client->priv = G_TYPE_INSTANCE_GET_PRIVATE (client,
+ MATE_MIXER_TYPE_CLIENT_STREAM,
+ MateMixerClientStreamPrivate);
+}
static void
-mate_mixer_client_stream_default_init (MateMixerClientStreamInterface *iface)
+mate_mixer_client_stream_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec)
{
- g_object_interface_install_property (iface,
- g_param_spec_flags ("client-flags",
- "Client flags",
- "Capability flags of the client stream",
- MATE_MIXER_TYPE_CLIENT_STREAM_FLAGS,
- MATE_MIXER_CLIENT_STREAM_NO_FLAGS,
- G_PARAM_READABLE |
- G_PARAM_STATIC_STRINGS));
-
- g_object_interface_install_property (iface,
- g_param_spec_enum ("role",
- "Role",
- "Role of the client stream",
- MATE_MIXER_TYPE_CLIENT_STREAM_ROLE,
- MATE_MIXER_CLIENT_STREAM_ROLE_NONE,
- G_PARAM_READABLE |
- G_PARAM_STATIC_STRINGS));
-
- g_object_interface_install_property (iface,
- g_param_spec_object ("parent",
- "Parent",
- "Parent stream of the client stream",
- MATE_MIXER_TYPE_STREAM,
- G_PARAM_READABLE |
- G_PARAM_STATIC_STRINGS));
-
- g_object_interface_install_property (iface,
- g_param_spec_string ("app-name",
- "App name",
- "Name of the client stream application",
- NULL,
- G_PARAM_READABLE |
- G_PARAM_STATIC_STRINGS));
-
- g_object_interface_install_property (iface,
- g_param_spec_string ("app-id",
- "App ID",
- "Identifier of the client stream application",
- NULL,
- G_PARAM_READABLE |
- G_PARAM_STATIC_STRINGS));
-
- g_object_interface_install_property (iface,
- g_param_spec_string ("app-version",
- "App version",
- "Version of the client stream application",
- NULL,
- G_PARAM_READABLE |
- G_PARAM_STATIC_STRINGS));
-
- g_object_interface_install_property (iface,
- g_param_spec_string ("app-icon",
- "App icon",
- "Icon name of the client stream application",
- NULL,
- G_PARAM_READABLE |
- G_PARAM_STATIC_STRINGS));
+}
+
+static void
+mate_mixer_client_stream_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+}
+
+static void
+mate_mixer_client_stream_dispose (GObject *object)
+{
+ MateMixerClientStream *client;
+
+ client = MATE_MIXER_CLIENT_STREAM (object);
+
+ g_clear_object (&client->priv->parent);
+
+ G_OBJECT_CLASS (mate_mixer_client_stream_parent_class)->dispose (object);
+}
+
+static void
+mate_mixer_client_stream_finalize (GObject *object)
+{
+ MateMixerClientStream *client;
+
+ client = MATE_MIXER_CLIENT_STREAM (object);
+
+ g_free (client->priv->app_name);
+ g_free (client->priv->app_id);
+ g_free (client->priv->app_version);
+ g_free (client->priv->app_icon);
+
+ G_OBJECT_CLASS (mate_mixer_client_stream_parent_class)->finalize (object);
}
/**
@@ -107,16 +209,9 @@ mate_mixer_client_stream_default_init (MateMixerClientStreamInterface *iface)
MateMixerClientStreamFlags
mate_mixer_client_stream_get_flags (MateMixerClientStream *client)
{
- MateMixerClientStreamInterface *iface;
-
g_return_val_if_fail (MATE_MIXER_IS_CLIENT_STREAM (client), MATE_MIXER_CLIENT_STREAM_NO_FLAGS);
- iface = MATE_MIXER_CLIENT_STREAM_GET_INTERFACE (client);
-
- if (iface->get_flags)
- return iface->get_flags (client);
-
- return MATE_MIXER_CLIENT_STREAM_NO_FLAGS;
+ return client->priv->client_flags;
}
/**
@@ -127,16 +222,9 @@ mate_mixer_client_stream_get_flags (MateMixerClientStream *client)
MateMixerClientStreamRole
mate_mixer_client_stream_get_role (MateMixerClientStream *client)
{
- MateMixerClientStreamInterface *iface;
-
g_return_val_if_fail (MATE_MIXER_IS_CLIENT_STREAM (client), MATE_MIXER_CLIENT_STREAM_ROLE_NONE);
- iface = MATE_MIXER_CLIENT_STREAM_GET_INTERFACE (client);
-
- if (iface->get_role)
- return iface->get_role (client);
-
- return MATE_MIXER_CLIENT_STREAM_ROLE_NONE;
+ return client->priv->client_role;
}
/**
@@ -150,16 +238,9 @@ mate_mixer_client_stream_get_role (MateMixerClientStream *client)
MateMixerStream *
mate_mixer_client_stream_get_parent (MateMixerClientStream *client)
{
- MateMixerClientStreamInterface *iface;
-
g_return_val_if_fail (MATE_MIXER_IS_CLIENT_STREAM (client), NULL);
- iface = MATE_MIXER_CLIENT_STREAM_GET_INTERFACE (client);
-
- if (iface->get_parent)
- return iface->get_parent (client);
-
- return NULL;
+ return client->priv->parent;
}
/**
@@ -175,17 +256,25 @@ mate_mixer_client_stream_get_parent (MateMixerClientStream *client)
gboolean
mate_mixer_client_stream_set_parent (MateMixerClientStream *client, MateMixerStream *parent)
{
- MateMixerClientStreamInterface *iface;
-
g_return_val_if_fail (MATE_MIXER_IS_CLIENT_STREAM (client), FALSE);
g_return_val_if_fail (MATE_MIXER_IS_STREAM (parent), FALSE);
- iface = MATE_MIXER_CLIENT_STREAM_GET_INTERFACE (client);
+ if (client->priv->parent != parent) {
+ MateMixerClientStreamClass *klass;
- if (iface->set_parent)
- return iface->set_parent (client, parent);
+ klass = MATE_MIXER_CLIENT_STREAM_GET_CLASS (client);
- return FALSE;
+ if (klass->set_parent == NULL ||
+ klass->set_parent (client, parent) == FALSE)
+ return FALSE;
+
+ if (client->priv->parent != NULL)
+ g_object_unref (client->priv->parent);
+
+ client->priv->parent = g_object_ref (parent);
+ }
+
+ return TRUE;
}
/**
@@ -199,14 +288,14 @@ mate_mixer_client_stream_set_parent (MateMixerClientStream *client, MateMixerStr
gboolean
mate_mixer_client_stream_remove (MateMixerClientStream *client)
{
- MateMixerClientStreamInterface *iface;
+ MateMixerClientStreamClass *klass;
g_return_val_if_fail (MATE_MIXER_IS_CLIENT_STREAM (client), FALSE);
- iface = MATE_MIXER_CLIENT_STREAM_GET_INTERFACE (client);
+ klass = MATE_MIXER_CLIENT_STREAM_GET_CLASS (client);
- if (iface->remove)
- return iface->remove (client);
+ if (klass->remove != NULL)
+ return klass->remove (client);
return FALSE;
}
@@ -224,16 +313,9 @@ mate_mixer_client_stream_remove (MateMixerClientStream *client)
const gchar *
mate_mixer_client_stream_get_app_name (MateMixerClientStream *client)
{
- MateMixerClientStreamInterface *iface;
-
g_return_val_if_fail (MATE_MIXER_IS_CLIENT_STREAM (client), NULL);
- iface = MATE_MIXER_CLIENT_STREAM_GET_INTERFACE (client);
-
- if (iface->get_app_name)
- return iface->get_app_name (client);
-
- return NULL;
+ return client->priv->app_name;
}
/**
@@ -249,16 +331,9 @@ mate_mixer_client_stream_get_app_name (MateMixerClientStream *client)
const gchar *
mate_mixer_client_stream_get_app_id (MateMixerClientStream *client)
{
- MateMixerClientStreamInterface *iface;
-
g_return_val_if_fail (MATE_MIXER_IS_CLIENT_STREAM (client), NULL);
- iface = MATE_MIXER_CLIENT_STREAM_GET_INTERFACE (client);
-
- if (iface->get_app_id)
- return iface->get_app_id (client);
-
- return NULL;
+ return client->priv->app_id;
}
/**
@@ -274,16 +349,9 @@ mate_mixer_client_stream_get_app_id (MateMixerClientStream *client)
const gchar *
mate_mixer_client_stream_get_app_version (MateMixerClientStream *client)
{
- MateMixerClientStreamInterface *iface;
-
g_return_val_if_fail (MATE_MIXER_IS_CLIENT_STREAM (client), NULL);
- iface = MATE_MIXER_CLIENT_STREAM_GET_INTERFACE (client);
-
- if (iface->get_app_version)
- return iface->get_app_version (client);
-
- return NULL;
+ return client->priv->app_version;
}
/**
@@ -299,14 +367,7 @@ mate_mixer_client_stream_get_app_version (MateMixerClientStream *client)
const gchar *
mate_mixer_client_stream_get_app_icon (MateMixerClientStream *client)
{
- MateMixerClientStreamInterface *iface;
-
g_return_val_if_fail (MATE_MIXER_IS_CLIENT_STREAM (client), NULL);
- iface = MATE_MIXER_CLIENT_STREAM_GET_INTERFACE (client);
-
- if (iface->get_app_icon)
- return iface->get_app_icon (client);
-
- return NULL;
+ return client->priv->app_icon;
}
diff --git a/libmatemixer/matemixer-client-stream.h b/libmatemixer/matemixer-client-stream.h
index fae5934..43ab3f0 100644
--- a/libmatemixer/matemixer-client-stream.h
+++ b/libmatemixer/matemixer-client-stream.h
@@ -22,28 +22,39 @@
#include <glib-object.h>
#include <libmatemixer/matemixer-enums.h>
-#include <libmatemixer/matemixer-stream.h>
+#include <libmatemixer/matemixer-types.h>
G_BEGIN_DECLS
-#define MATE_MIXER_TYPE_CLIENT_STREAM \
+#define MATE_MIXER_TYPE_CLIENT_STREAM \
(mate_mixer_client_stream_get_type ())
-#define MATE_MIXER_CLIENT_STREAM(o) \
+#define MATE_MIXER_CLIENT_STREAM(o) \
(G_TYPE_CHECK_INSTANCE_CAST ((o), MATE_MIXER_TYPE_CLIENT_STREAM, MateMixerClientStream))
-#define MATE_MIXER_IS_CLIENT_STREAM(o) \
+#define MATE_MIXER_IS_CLIENT_STREAM(o) \
(G_TYPE_CHECK_INSTANCE_TYPE ((o), MATE_MIXER_TYPE_CLIENT_STREAM))
-#define MATE_MIXER_CLIENT_STREAM_GET_INTERFACE(o) \
- (G_TYPE_INSTANCE_GET_INTERFACE ((o), MATE_MIXER_TYPE_CLIENT_STREAM, MateMixerClientStreamInterface))
+#define MATE_MIXER_CLIENT_STREAM_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_CAST ((k), MATE_MIXER_TYPE_CLIENT_STREAM, MateMixerClientStreamClass))
+#define MATE_MIXER_IS_CLIENT_STREAM_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_TYPE ((k), MATE_MIXER_TYPE_CLIENT_STREAM))
+#define MATE_MIXER_CLIENT_STREAM_GET_CLASS(o) \
+ (G_TYPE_INSTANCE_GET_CLASS ((o), MATE_MIXER_TYPE_CLIENT_STREAM, MateMixerClientStreamClass))
-typedef struct _MateMixerClientStream MateMixerClientStream; /* dummy object */
-typedef struct _MateMixerClientStreamInterface MateMixerClientStreamInterface;
+typedef struct _MateMixerClientStreamClass MateMixerClientStreamClass;
+typedef struct _MateMixerClientStreamPrivate MateMixerClientStreamPrivate;
-struct _MateMixerClientStreamInterface
+struct _MateMixerClientStream
+{
+ GObject *parent;
+
+ /*< private >*/
+ MateMixerClientStreamPrivate *priv;
+};
+
+struct _MateMixerClientStreamClass
{
GTypeInterface parent_iface;
/*< private >*/
- /* Virtual table */
MateMixerClientStreamFlags (*get_flags) (MateMixerClientStream *client);
MateMixerClientStreamRole (*get_role) (MateMixerClientStream *client);
diff --git a/libmatemixer/matemixer-control.c b/libmatemixer/matemixer-context.c
index 45316d5..ecd617f 100644
--- a/libmatemixer/matemixer-control.c
+++ b/libmatemixer/matemixer-context.c
@@ -23,23 +23,20 @@
#include "matemixer-backend.h"
#include "matemixer-backend-module.h"
#include "matemixer-client-stream.h"
-#include "matemixer-control.h"
+#include "matemixer-context.h"
#include "matemixer-enums.h"
#include "matemixer-enum-types.h"
#include "matemixer-private.h"
#include "matemixer-stream.h"
/**
- * SECTION:matemixer-control
+ * SECTION:matemixer-context
* @short_description:The main class for interfacing with the library
* @include: libmatemixer/matemixer.h
*/
-struct _MateMixerControlPrivate
+struct _MateMixerContextPrivate
{
- GList *devices;
- GList *streams;
- GList *cached_streams;
gboolean backend_chosen;
MateMixerState state;
MateMixerBackend *backend;
@@ -56,8 +53,8 @@ enum {
PROP_APP_ICON,
PROP_SERVER_ADDRESS,
PROP_STATE,
- PROP_DEFAULT_INPUT,
- PROP_DEFAULT_OUTPUT,
+ PROP_DEFAULT_INPUT_STREAM,
+ PROP_DEFAULT_OUTPUT_STREAM,
N_PROPERTIES
};
@@ -68,87 +65,82 @@ enum {
DEVICE_REMOVED,
STREAM_ADDED,
STREAM_REMOVED,
- CACHED_STREAM_ADDED,
- CACHED_STREAM_REMOVED,
+ STORED_STREAM_ADDED,
+ STORED_STREAM_REMOVED,
N_SIGNALS
};
static guint signals[N_SIGNALS] = { 0, };
-static void mate_mixer_control_class_init (MateMixerControlClass *klass);
+static void mate_mixer_context_class_init (MateMixerContextClass *klass);
-static void mate_mixer_control_get_property (GObject *object,
+static void mate_mixer_context_get_property (GObject *object,
guint param_id,
GValue *value,
GParamSpec *pspec);
-static void mate_mixer_control_set_property (GObject *object,
+static void mate_mixer_context_set_property (GObject *object,
guint param_id,
const GValue *value,
GParamSpec *pspec);
-static void mate_mixer_control_init (MateMixerControl *control);
-static void mate_mixer_control_dispose (GObject *object);
-static void mate_mixer_control_finalize (GObject *object);
+static void mate_mixer_context_init (MateMixerContext *context);
+static void mate_mixer_context_dispose (GObject *object);
+static void mate_mixer_context_finalize (GObject *object);
-G_DEFINE_TYPE (MateMixerControl, mate_mixer_control, G_TYPE_OBJECT);
+G_DEFINE_TYPE (MateMixerContext, mate_mixer_context, G_TYPE_OBJECT);
-static void on_backend_state_notify (MateMixerBackend *backend,
- GParamSpec *pspec,
- MateMixerControl *control);
+static void on_backend_state_notify (MateMixerBackend *backend,
+ GParamSpec *pspec,
+ MateMixerContext *context);
-static void on_backend_device_added (MateMixerBackend *backend,
- const gchar *name,
- MateMixerControl *control);
-static void on_backend_device_removed (MateMixerBackend *backend,
- const gchar *name,
- MateMixerControl *control);
+static void on_backend_device_added (MateMixerBackend *backend,
+ const gchar *name,
+ MateMixerContext *context);
+static void on_backend_device_removed (MateMixerBackend *backend,
+ const gchar *name,
+ MateMixerContext *context);
-static void on_backend_stream_added (MateMixerBackend *backend,
- const gchar *name,
- MateMixerControl *control);
-static void on_backend_stream_removed (MateMixerBackend *backend,
- const gchar *name,
- MateMixerControl *control);
+static void on_backend_stream_added (MateMixerBackend *backend,
+ const gchar *name,
+ MateMixerContext *context);
+static void on_backend_stream_removed (MateMixerBackend *backend,
+ const gchar *name,
+ MateMixerContext *context);
-static void on_backend_cached_stream_added (MateMixerBackend *backend,
- const gchar *name,
- MateMixerControl *control);
-static void on_backend_cached_stream_removed (MateMixerBackend *backend,
- const gchar *name,
- MateMixerControl *control);
+static void on_backend_stored_stream_added (MateMixerBackend *backend,
+ const gchar *name,
+ MateMixerContext *context);
+static void on_backend_stored_stream_removed (MateMixerBackend *backend,
+ const gchar *name,
+ MateMixerContext *context);
-static void on_backend_default_input_notify (MateMixerBackend *backend,
- GParamSpec *pspec,
- MateMixerControl *control);
-static void on_backend_default_output_notify (MateMixerBackend *backend,
- GParamSpec *pspec,
- MateMixerControl *control);
+static void on_backend_default_input_stream_notify (MateMixerBackend *backend,
+ GParamSpec *pspec,
+ MateMixerContext *context);
+static void on_backend_default_output_stream_notify (MateMixerBackend *backend,
+ GParamSpec *pspec,
+ MateMixerContext *context);
-static gboolean try_next_backend (MateMixerControl *control);
+static gboolean try_next_backend (MateMixerContext *context);
-static void change_state (MateMixerControl *control,
- MateMixerState state);
+static void change_state (MateMixerContext *context,
+ MateMixerState state);
-static void close_control (MateMixerControl *control);
-
-static void free_backend (MateMixerControl *control);
-static void free_devices (MateMixerControl *control);
-static void free_streams (MateMixerControl *control);
-static void free_cached_streams (MateMixerControl *control);
+static void close_context (MateMixerContext *context);
static void
-mate_mixer_control_class_init (MateMixerControlClass *klass)
+mate_mixer_context_class_init (MateMixerContextClass *klass)
{
GObjectClass *object_class;
object_class = G_OBJECT_CLASS (klass);
- object_class->dispose = mate_mixer_control_dispose;
- object_class->finalize = mate_mixer_control_finalize;
- object_class->get_property = mate_mixer_control_get_property;
- object_class->set_property = mate_mixer_control_set_property;
+ object_class->dispose = mate_mixer_context_dispose;
+ object_class->finalize = mate_mixer_context_finalize;
+ object_class->get_property = mate_mixer_context_get_property;
+ object_class->set_property = mate_mixer_context_set_property;
/**
- * MateMixerControl:app-name:
+ * MateMixerContext:app-name:
*
* Localized human readable name of the application.
*/
@@ -160,7 +152,7 @@ mate_mixer_control_class_init (MateMixerControlClass *klass)
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
/**
- * MateMixerControl:app-id:
+ * MateMixerContext:app-id:
*
* Identifier of the application (e.g. org.example.app).
*/
@@ -172,7 +164,7 @@ mate_mixer_control_class_init (MateMixerControlClass *klass)
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
/**
- * MateMixerControl:app-version:
+ * MateMixerContext:app-version:
*
* Version of the application.
*/
@@ -184,7 +176,7 @@ mate_mixer_control_class_init (MateMixerControlClass *klass)
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
/**
- * MateMixerControl:app-icon:
+ * MateMixerContext:app-icon:
*
* An XDG icon name for the application.
*/
@@ -196,7 +188,7 @@ mate_mixer_control_class_init (MateMixerControlClass *klass)
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
/**
- * MateMixerControl:server-address:
+ * MateMixerContext:server-address:
*
* Address of the sound server to connect to.
*
@@ -218,16 +210,16 @@ mate_mixer_control_class_init (MateMixerControlClass *klass)
MATE_MIXER_STATE_IDLE,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
- properties[PROP_DEFAULT_INPUT] =
- g_param_spec_object ("default-input",
- "Default input",
+ properties[PROP_DEFAULT_INPUT_STREAM] =
+ g_param_spec_object ("default-input-stream",
+ "Default input stream",
"Default input stream",
MATE_MIXER_TYPE_STREAM,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
- properties[PROP_DEFAULT_OUTPUT] =
- g_param_spec_object ("default-output",
- "Default output",
+ properties[PROP_DEFAULT_OUTPUT_STREAM] =
+ g_param_spec_object ("default-output-stream",
+ "Default output stream",
"Default output stream",
MATE_MIXER_TYPE_STREAM,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
@@ -235,8 +227,8 @@ mate_mixer_control_class_init (MateMixerControlClass *klass)
g_object_class_install_properties (object_class, N_PROPERTIES, properties);
/**
- * MateMixerControl::device-added:
- * @control: a #MateMixerControl
+ * MateMixerContext::device-added:
+ * @context: a #MateMixerContext
* @name: name of the added device
*
* The signal is emitted each time a device is added to the system.
@@ -245,7 +237,7 @@ mate_mixer_control_class_init (MateMixerControlClass *klass)
g_signal_new ("device-added",
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (MateMixerControlClass, device_added),
+ G_STRUCT_OFFSET (MateMixerContextClass, device_added),
NULL,
NULL,
g_cclosure_marshal_VOID__STRING,
@@ -254,8 +246,8 @@ mate_mixer_control_class_init (MateMixerControlClass *klass)
G_TYPE_STRING);
/**
- * MateMixerControl::device-removed:
- * @control: a #MateMixerControl
+ * MateMixerContext::device-removed:
+ * @context: a #MateMixerContext
* @name: name of the removed device
*
* The signal is emitted each time a device is removed from the system.
@@ -264,7 +256,7 @@ mate_mixer_control_class_init (MateMixerControlClass *klass)
g_signal_new ("device-removed",
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (MateMixerControlClass, device_removed),
+ G_STRUCT_OFFSET (MateMixerContextClass, device_removed),
NULL,
NULL,
g_cclosure_marshal_VOID__STRING,
@@ -273,8 +265,8 @@ mate_mixer_control_class_init (MateMixerControlClass *klass)
G_TYPE_STRING);
/**
- * MateMixerControl::stream-added:
- * @control: a #MateMixerControl
+ * MateMixerContext::stream-added:
+ * @context: a #MateMixerContext
* @name: name of the added stream
*
* The signal is emitted each time a stream is created.
@@ -283,7 +275,7 @@ mate_mixer_control_class_init (MateMixerControlClass *klass)
g_signal_new ("stream-added",
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (MateMixerControlClass, stream_added),
+ G_STRUCT_OFFSET (MateMixerContextClass, stream_added),
NULL,
NULL,
g_cclosure_marshal_VOID__STRING,
@@ -292,8 +284,8 @@ mate_mixer_control_class_init (MateMixerControlClass *klass)
G_TYPE_STRING);
/**
- * MateMixerControl::stream-removed:
- * @control: a #MateMixerControl
+ * MateMixerContext::stream-removed:
+ * @context: a #MateMixerContext
* @name: name of the removed stream
*
* The signal is emitted each time a stream is removed.
@@ -302,7 +294,7 @@ mate_mixer_control_class_init (MateMixerControlClass *klass)
g_signal_new ("stream-removed",
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (MateMixerControlClass, stream_removed),
+ G_STRUCT_OFFSET (MateMixerContextClass, stream_removed),
NULL,
NULL,
g_cclosure_marshal_VOID__STRING,
@@ -311,17 +303,17 @@ mate_mixer_control_class_init (MateMixerControlClass *klass)
G_TYPE_STRING);
/**
- * MateMixerControl::cached-stream-added:
- * @control: a #MateMixerControl
- * @name: name of the added cached stream
+ * MateMixerContext::stored-stream-added:
+ * @context: a #MateMixerContext
+ * @name: name of the added stored stream
*
- * The signal is emitted each time a cached stream is created.
+ * The signal is emitted each time a stored stream is created.
*/
- signals[CACHED_STREAM_ADDED] =
- g_signal_new ("cached-stream-added",
+ signals[STORED_STREAM_ADDED] =
+ g_signal_new ("stored-control-added",
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (MateMixerControlClass, cached_stream_added),
+ G_STRUCT_OFFSET (MateMixerContextClass, stored_stream_added),
NULL,
NULL,
g_cclosure_marshal_VOID__STRING,
@@ -330,17 +322,17 @@ mate_mixer_control_class_init (MateMixerControlClass *klass)
G_TYPE_STRING);
/**
- * MateMixerControl::stream-removed:
- * @control: a #MateMixerControl
+ * MateMixerContext::stream-removed:
+ * @context: a #MateMixerContext
* @name: name of the removed stream
*
* The signal is emitted each time a stream is removed.
*/
- signals[CACHED_STREAM_REMOVED] =
- g_signal_new ("cached-stream-removed",
+ signals[STORED_STREAM_REMOVED] =
+ g_signal_new ("stored-stream-removed",
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (MateMixerControlClass, cached_stream_removed),
+ G_STRUCT_OFFSET (MateMixerContextClass, stored_stream_removed),
NULL,
NULL,
g_cclosure_marshal_VOID__STRING,
@@ -348,43 +340,43 @@ mate_mixer_control_class_init (MateMixerControlClass *klass)
1,
G_TYPE_STRING);
- g_type_class_add_private (object_class, sizeof (MateMixerControlPrivate));
+ g_type_class_add_private (object_class, sizeof (MateMixerContextPrivate));
}
static void
-mate_mixer_control_get_property (GObject *object,
+mate_mixer_context_get_property (GObject *object,
guint param_id,
GValue *value,
GParamSpec *pspec)
{
- MateMixerControl *control;
+ MateMixerContext *context;
- control = MATE_MIXER_CONTROL (object);
+ context = MATE_MIXER_CONTEXT (object);
switch (param_id) {
case PROP_APP_NAME:
- g_value_set_string (value, control->priv->backend_data.app_name);
+ g_value_set_string (value, context->priv->backend_data.app_name);
break;
case PROP_APP_ID:
- g_value_set_string (value, control->priv->backend_data.app_id);
+ g_value_set_string (value, context->priv->backend_data.app_id);
break;
case PROP_APP_VERSION:
- g_value_set_string (value, control->priv->backend_data.app_version);
+ g_value_set_string (value, context->priv->backend_data.app_version);
break;
case PROP_APP_ICON:
- g_value_set_string (value, control->priv->backend_data.app_icon);
+ g_value_set_string (value, context->priv->backend_data.app_icon);
break;
case PROP_SERVER_ADDRESS:
- g_value_set_string (value, control->priv->backend_data.server_address);
+ g_value_set_string (value, context->priv->backend_data.server_address);
break;
case PROP_STATE:
- g_value_set_enum (value, control->priv->state);
+ g_value_set_enum (value, context->priv->state);
break;
- case PROP_DEFAULT_INPUT:
- g_value_set_object (value, mate_mixer_control_get_default_input_stream (control));
+ case PROP_DEFAULT_INPUT_STREAM:
+ g_value_set_object (value, mate_mixer_context_get_default_input_stream (context));
break;
- case PROP_DEFAULT_OUTPUT:
- g_value_set_object (value, mate_mixer_control_get_default_output_stream (control));
+ case PROP_DEFAULT_OUTPUT_STREAM:
+ g_value_set_object (value, mate_mixer_context_get_default_output_stream (context));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
@@ -393,36 +385,36 @@ mate_mixer_control_get_property (GObject *object,
}
static void
-mate_mixer_control_set_property (GObject *object,
+mate_mixer_context_set_property (GObject *object,
guint param_id,
const GValue *value,
GParamSpec *pspec)
{
- MateMixerControl *control;
+ MateMixerContext *context;
- control = MATE_MIXER_CONTROL (object);
+ context = MATE_MIXER_CONTEXT (object);
switch (param_id) {
case PROP_APP_NAME:
- mate_mixer_control_set_app_name (control, g_value_get_string (value));
+ mate_mixer_context_set_app_name (context, g_value_get_string (value));
break;
case PROP_APP_ID:
- mate_mixer_control_set_app_id (control, g_value_get_string (value));
+ mate_mixer_context_set_app_id (context, g_value_get_string (value));
break;
case PROP_APP_VERSION:
- mate_mixer_control_set_app_version (control, g_value_get_string (value));
+ mate_mixer_context_set_app_version (context, g_value_get_string (value));
break;
case PROP_APP_ICON:
- mate_mixer_control_set_app_icon (control, g_value_get_string (value));
+ mate_mixer_context_set_app_icon (context, g_value_get_string (value));
break;
case PROP_SERVER_ADDRESS:
- mate_mixer_control_set_server_address (control, g_value_get_string (value));
+ mate_mixer_context_set_server_address (context, g_value_get_string (value));
break;
- case PROP_DEFAULT_INPUT:
- mate_mixer_control_set_default_input_stream (control, g_value_get_object (value));
+ case PROP_DEFAULT_INPUT_STREAM:
+ mate_mixer_context_set_default_input_stream (context, g_value_get_object (value));
break;
- case PROP_DEFAULT_OUTPUT:
- mate_mixer_control_set_default_output_stream (control, g_value_get_object (value));
+ case PROP_DEFAULT_OUTPUT_STREAM:
+ mate_mixer_context_set_default_output_stream (context, g_value_get_object (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
@@ -431,66 +423,66 @@ mate_mixer_control_set_property (GObject *object,
}
static void
-mate_mixer_control_init (MateMixerControl *control)
+mate_mixer_context_init (MateMixerContext *context)
{
- control->priv = G_TYPE_INSTANCE_GET_PRIVATE (control,
- MATE_MIXER_TYPE_CONTROL,
- MateMixerControlPrivate);
+ context->priv = G_TYPE_INSTANCE_GET_PRIVATE (context,
+ MATE_MIXER_TYPE_CONTEXT,
+ MateMixerContextPrivate);
}
static void
-mate_mixer_control_dispose (GObject *object)
+mate_mixer_context_dispose (GObject *object)
{
- close_control (MATE_MIXER_CONTROL (object));
+ close_context (MATE_MIXER_CONTEXT (object));
- G_OBJECT_CLASS (mate_mixer_control_parent_class)->dispose (object);
+ G_OBJECT_CLASS (mate_mixer_context_parent_class)->dispose (object);
}
static void
-mate_mixer_control_finalize (GObject *object)
+mate_mixer_context_finalize (GObject *object)
{
- MateMixerControl *control;
+ MateMixerContext *context;
- control = MATE_MIXER_CONTROL (object);
+ context = MATE_MIXER_CONTEXT (object);
- g_free (control->priv->backend_data.app_name);
- g_free (control->priv->backend_data.app_id);
- g_free (control->priv->backend_data.app_version);
- g_free (control->priv->backend_data.app_icon);
- g_free (control->priv->backend_data.server_address);
+ g_free (context->priv->backend_data.app_name);
+ g_free (context->priv->backend_data.app_id);
+ g_free (context->priv->backend_data.app_version);
+ g_free (context->priv->backend_data.app_icon);
+ g_free (context->priv->backend_data.server_address);
- G_OBJECT_CLASS (mate_mixer_control_parent_class)->finalize (object);
+ G_OBJECT_CLASS (mate_mixer_context_parent_class)->finalize (object);
}
/**
- * mate_mixer_control_new:
+ * mate_mixer_context_new:
*
- * Creates a new #MateMixerControl instance.
+ * Creates a new #MateMixerContext instance.
*
- * Returns: a new #MateMixerControl instance or %NULL if the library has not
+ * Returns: a new #MateMixerContext instance or %NULL if the library has not
* been initialized using mate_mixer_init().
*/
-MateMixerControl *
-mate_mixer_control_new (void)
+MateMixerContext *
+mate_mixer_context_new (void)
{
if (mate_mixer_is_initialized () == FALSE) {
g_critical ("The library has not been initialized");
return NULL;
}
- return g_object_new (MATE_MIXER_TYPE_CONTROL, NULL);
+ return g_object_new (MATE_MIXER_TYPE_CONTEXT, NULL);
}
/**
- * mate_mixer_control_set_backend_type:
- * @control: a #MateMixerControl
+ * mate_mixer_context_set_backend_type:
+ * @context: a #MateMixerContext
* @backend_type: the sound system backend to use
*
- * Makes the #MateMixerControl use the given #MateMixerBackendType.
+ * Makes the #MateMixerContext use the given #MateMixerBackendType.
*
* By default the backend type is determined automatically. This function can
- * be used before mate_mixer_control_open() to alter this behavior and make the
- * @control use the given backend.
+ * be used before mate_mixer_context_open() to alter this behavior and make the
+ * @context use the given backend.
*
* This function will fail if support for the backend is not installed in
* the system or if the current state is either %MATE_MIXER_STATE_CONNECTING or
@@ -499,27 +491,27 @@ mate_mixer_control_new (void)
* Returns: %TRUE on success or %FALSE on failure.
*/
gboolean
-mate_mixer_control_set_backend_type (MateMixerControl *control,
+mate_mixer_context_set_backend_type (MateMixerContext *context,
MateMixerBackendType backend_type)
{
MateMixerBackendModule *module;
const GList *modules;
const MateMixerBackendInfo *info;
- g_return_val_if_fail (MATE_MIXER_IS_CONTROL (control), FALSE);
+ g_return_val_if_fail (MATE_MIXER_IS_CONTEXT (context), FALSE);
- if (control->priv->state == MATE_MIXER_STATE_CONNECTING ||
- control->priv->state == MATE_MIXER_STATE_READY)
+ if (context->priv->state == MATE_MIXER_STATE_CONNECTING ||
+ context->priv->state == MATE_MIXER_STATE_READY)
return FALSE;
- modules = mate_mixer_get_modules ();
+ modules = _mate_mixer_get_modules ();
while (modules != NULL) {
module = MATE_MIXER_BACKEND_MODULE (modules->data);
info = mate_mixer_backend_module_get_info (module);
if (info->backend_type == backend_type) {
- control->priv->backend_type = backend_type;
+ context->priv->backend_type = backend_type;
return TRUE;
}
modules = modules->next;
@@ -528,8 +520,8 @@ mate_mixer_control_set_backend_type (MateMixerControl *control,
}
/**
- * mate_mixer_control_set_app_name:
- * @control: a #MateMixerControl
+ * mate_mixer_context_set_app_name:
+ * @context: a #MateMixerContext
* @app_name: the name of your application, or %NULL to unset
*
* Sets the name of the application. This feature is only supported in the
@@ -542,27 +534,27 @@ mate_mixer_control_set_backend_type (MateMixerControl *control,
* Returns: %TRUE on success or %FALSE on failure.
*/
gboolean
-mate_mixer_control_set_app_name (MateMixerControl *control, const gchar *app_name)
+mate_mixer_context_set_app_name (MateMixerContext *context, const gchar *app_name)
{
- g_return_val_if_fail (MATE_MIXER_IS_CONTROL (control), FALSE);
+ g_return_val_if_fail (MATE_MIXER_IS_CONTEXT (context), FALSE);
- if (control->priv->state == MATE_MIXER_STATE_CONNECTING ||
- control->priv->state == MATE_MIXER_STATE_READY)
+ if (context->priv->state == MATE_MIXER_STATE_CONNECTING ||
+ context->priv->state == MATE_MIXER_STATE_READY)
return FALSE;
- if (g_strcmp0 (control->priv->backend_data.app_name, app_name) != 0) {
- g_free (control->priv->backend_data.app_name);
+ if (g_strcmp0 (context->priv->backend_data.app_name, app_name) != 0) {
+ g_free (context->priv->backend_data.app_name);
- control->priv->backend_data.app_name = g_strdup (app_name);
+ context->priv->backend_data.app_name = g_strdup (app_name);
- g_object_notify_by_pspec (G_OBJECT (control), properties[PROP_APP_NAME]);
+ g_object_notify_by_pspec (G_OBJECT (context), properties[PROP_APP_NAME]);
}
return TRUE;
}
/**
- * mate_mixer_control_set_app_id:
- * @control: a #MateMixerControl
+ * mate_mixer_context_set_app_id:
+ * @context: a #MateMixerContext
* @app_id: the identifier of your application, or %NULL to unset
*
* Sets the identifier of the application (e.g. org.example.app). This feature
@@ -575,27 +567,27 @@ mate_mixer_control_set_app_name (MateMixerControl *control, const gchar *app_nam
* Returns: %TRUE on success or %FALSE on failure.
*/
gboolean
-mate_mixer_control_set_app_id (MateMixerControl *control, const gchar *app_id)
+mate_mixer_context_set_app_id (MateMixerContext *context, const gchar *app_id)
{
- g_return_val_if_fail (MATE_MIXER_IS_CONTROL (control), FALSE);
+ g_return_val_if_fail (MATE_MIXER_IS_CONTEXT (context), FALSE);
- if (control->priv->state == MATE_MIXER_STATE_CONNECTING ||
- control->priv->state == MATE_MIXER_STATE_READY)
+ if (context->priv->state == MATE_MIXER_STATE_CONNECTING ||
+ context->priv->state == MATE_MIXER_STATE_READY)
return FALSE;
- if (g_strcmp0 (control->priv->backend_data.app_id, app_id) != 0) {
- g_free (control->priv->backend_data.app_id);
+ if (g_strcmp0 (context->priv->backend_data.app_id, app_id) != 0) {
+ g_free (context->priv->backend_data.app_id);
- control->priv->backend_data.app_id = g_strdup (app_id);
+ context->priv->backend_data.app_id = g_strdup (app_id);
- g_object_notify_by_pspec (G_OBJECT (control), properties[PROP_APP_ID]);
+ g_object_notify_by_pspec (G_OBJECT (context), properties[PROP_APP_ID]);
}
return TRUE;
}
/**
- * mate_mixer_control_set_app_version:
- * @control: a #MateMixerControl
+ * mate_mixer_context_set_app_version:
+ * @context: a #MateMixerContext
* @app_version: the version of your application, or %NULL to unset
*
* Sets the version of the application. This feature is only supported in the
@@ -608,27 +600,27 @@ mate_mixer_control_set_app_id (MateMixerControl *control, const gchar *app_id)
* Returns: %TRUE on success or %FALSE on failure.
*/
gboolean
-mate_mixer_control_set_app_version (MateMixerControl *control, const gchar *app_version)
+mate_mixer_context_set_app_version (MateMixerContext *context, const gchar *app_version)
{
- g_return_val_if_fail (MATE_MIXER_IS_CONTROL (control), FALSE);
+ g_return_val_if_fail (MATE_MIXER_IS_CONTEXT (context), FALSE);
- if (control->priv->state == MATE_MIXER_STATE_CONNECTING ||
- control->priv->state == MATE_MIXER_STATE_READY)
+ if (context->priv->state == MATE_MIXER_STATE_CONNECTING ||
+ context->priv->state == MATE_MIXER_STATE_READY)
return FALSE;
- if (g_strcmp0 (control->priv->backend_data.app_version, app_version) != 0) {
- g_free (control->priv->backend_data.app_version);
+ if (g_strcmp0 (context->priv->backend_data.app_version, app_version) != 0) {
+ g_free (context->priv->backend_data.app_version);
- control->priv->backend_data.app_version = g_strdup (app_version);
+ context->priv->backend_data.app_version = g_strdup (app_version);
- g_object_notify_by_pspec (G_OBJECT (control), properties[PROP_APP_VERSION]);
+ g_object_notify_by_pspec (G_OBJECT (context), properties[PROP_APP_VERSION]);
}
return TRUE;
}
/**
- * mate_mixer_control_set_app_icon:
- * @control: a #MateMixerControl
+ * mate_mixer_context_set_app_icon:
+ * @context: a #MateMixerContext
* @app_icon: the XDG icon name of your application, or %NULL to unset
*
* Sets the XDG icon name of the application. This feature is only supported in
@@ -641,27 +633,27 @@ mate_mixer_control_set_app_version (MateMixerControl *control, const gchar *app_
* Returns: %TRUE on success or %FALSE on failure.
*/
gboolean
-mate_mixer_control_set_app_icon (MateMixerControl *control, const gchar *app_icon)
+mate_mixer_context_set_app_icon (MateMixerContext *context, const gchar *app_icon)
{
- g_return_val_if_fail (MATE_MIXER_IS_CONTROL (control), FALSE);
+ g_return_val_if_fail (MATE_MIXER_IS_CONTEXT (context), FALSE);
- if (control->priv->state == MATE_MIXER_STATE_CONNECTING ||
- control->priv->state == MATE_MIXER_STATE_READY)
+ if (context->priv->state == MATE_MIXER_STATE_CONNECTING ||
+ context->priv->state == MATE_MIXER_STATE_READY)
return FALSE;
- if (g_strcmp0 (control->priv->backend_data.app_icon, app_icon) != 0) {
- g_free (control->priv->backend_data.app_icon);
+ if (g_strcmp0 (context->priv->backend_data.app_icon, app_icon) != 0) {
+ g_free (context->priv->backend_data.app_icon);
- control->priv->backend_data.app_icon = g_strdup (app_icon);
+ context->priv->backend_data.app_icon = g_strdup (app_icon);
- g_object_notify_by_pspec (G_OBJECT (control), properties[PROP_APP_ICON]);
+ g_object_notify_by_pspec (G_OBJECT (context), properties[PROP_APP_ICON]);
}
return TRUE;
}
/**
- * mate_mixer_control_set_server_address:
- * @control: a #MateMixerControl
+ * mate_mixer_context_set_server_address:
+ * @context: a #MateMixerContext
* @address: the address of the sound server to connect to or %NULL
*
* Sets the address of the sound server. This feature is only supported in the
@@ -675,27 +667,27 @@ mate_mixer_control_set_app_icon (MateMixerControl *control, const gchar *app_ico
* Returns: %TRUE on success or %FALSE on failure.
*/
gboolean
-mate_mixer_control_set_server_address (MateMixerControl *control, const gchar *address)
+mate_mixer_context_set_server_address (MateMixerContext *context, const gchar *address)
{
- g_return_val_if_fail (MATE_MIXER_IS_CONTROL (control), FALSE);
+ g_return_val_if_fail (MATE_MIXER_IS_CONTEXT (context), FALSE);
- if (control->priv->state == MATE_MIXER_STATE_CONNECTING ||
- control->priv->state == MATE_MIXER_STATE_READY)
+ if (context->priv->state == MATE_MIXER_STATE_CONNECTING ||
+ context->priv->state == MATE_MIXER_STATE_READY)
return FALSE;
- if (g_strcmp0 (control->priv->backend_data.server_address, address) != 0) {
- g_free (control->priv->backend_data.server_address);
+ if (g_strcmp0 (context->priv->backend_data.server_address, address) != 0) {
+ g_free (context->priv->backend_data.server_address);
- control->priv->backend_data.server_address = g_strdup (address);
+ context->priv->backend_data.server_address = g_strdup (address);
- g_object_notify_by_pspec (G_OBJECT (control), properties[PROP_SERVER_ADDRESS]);
+ g_object_notify_by_pspec (G_OBJECT (context), properties[PROP_SERVER_ADDRESS]);
}
return TRUE;
}
/**
- * mate_mixer_control_open:
- * @control: a #MateMixerControl
+ * mate_mixer_context_open:
+ * @context: a #MateMixerContext
*
* Opens connection to a sound system. Unless the backend type was given
* beforehand, the library will find a working sound system automatically.
@@ -706,12 +698,12 @@ mate_mixer_control_set_server_address (MateMixerControl *control, const gchar *a
* asynchronously.
*
* In case this function returns %TRUE, you should check the current state of
- * the connection using mate_mixer_control_get_state(). If the current state
+ * the connection using mate_mixer_context_get_state(). If the current state
* is %MATE_MIXER_STATE_READY, the connection has been established successfully.
* Otherwise the state will be set to %MATE_MIXER_STATE_CONNECTING and the
* result of the operation will be determined asynchronously. You should wait
* for the state transition by connecting to the notification signal of the
- * #MateMixerControl:state property.
+ * #MateMixerContext:state property.
*
* In case this function returns %FALSE, it is not possible to use the selected
* backend and the state will be set to %MATE_MIXER_STATE_FAILED.
@@ -720,31 +712,31 @@ mate_mixer_control_set_server_address (MateMixerControl *control, const gchar *a
* or %FALSE on failure.
*/
gboolean
-mate_mixer_control_open (MateMixerControl *control)
+mate_mixer_context_open (MateMixerContext *context)
{
MateMixerBackendModule *module = NULL;
MateMixerState state;
const GList *modules;
const MateMixerBackendInfo *info = NULL;
- g_return_val_if_fail (MATE_MIXER_IS_CONTROL (control), FALSE);
+ g_return_val_if_fail (MATE_MIXER_IS_CONTEXT (context), FALSE);
- if (control->priv->state == MATE_MIXER_STATE_CONNECTING ||
- control->priv->state == MATE_MIXER_STATE_READY)
+ if (context->priv->state == MATE_MIXER_STATE_CONNECTING ||
+ context->priv->state == MATE_MIXER_STATE_READY)
return FALSE;
/* We are going to choose the first backend to try. It will be either the one
* specified by the application or the one with the highest priority */
- modules = mate_mixer_get_modules ();
+ modules = _mate_mixer_get_modules ();
- if (control->priv->backend_type != MATE_MIXER_BACKEND_UNKNOWN) {
+ if (context->priv->backend_type != MATE_MIXER_BACKEND_UNKNOWN) {
while (modules != NULL) {
const MateMixerBackendInfo *info;
module = MATE_MIXER_BACKEND_MODULE (modules->data);
info = mate_mixer_backend_module_get_info (module);
- if (info->backend_type == control->priv->backend_type)
+ if (info->backend_type == context->priv->backend_type)
break;
module = NULL;
@@ -763,105 +755,105 @@ mate_mixer_control_open (MateMixerControl *control)
if (info == NULL)
info = mate_mixer_backend_module_get_info (module);
- control->priv->module = g_object_ref (module);
- control->priv->backend = g_object_new (info->g_type, NULL);
+ context->priv->module = g_object_ref (module);
+ context->priv->backend = g_object_new (info->g_type, NULL);
- mate_mixer_backend_set_data (control->priv->backend, &control->priv->backend_data);
+ mate_mixer_backend_set_data (context->priv->backend, &context->priv->backend_data);
g_debug ("Trying to open backend %s", info->name);
/* This transitional state is always present, it will change to MATE_MIXER_STATE_READY
* or MATE_MIXER_STATE_FAILED either instantly or asynchronously */
- change_state (control, MATE_MIXER_STATE_CONNECTING);
+ change_state (context, MATE_MIXER_STATE_CONNECTING);
/* The backend initialization might fail in case it is known right now that
* the backend is unusable */
- if (mate_mixer_backend_open (control->priv->backend) == FALSE) {
- if (control->priv->backend_type == MATE_MIXER_BACKEND_UNKNOWN) {
+ if (mate_mixer_backend_open (context->priv->backend) == FALSE) {
+ if (context->priv->backend_type == MATE_MIXER_BACKEND_UNKNOWN) {
/* User didn't request a specific backend, so try another one */
- return try_next_backend (control);
+ return try_next_backend (context);
}
/* User requested a specific backend and it failed */
- close_control (control);
- change_state (control, MATE_MIXER_STATE_FAILED);
+ close_context (context);
+ change_state (context, MATE_MIXER_STATE_FAILED);
return FALSE;
}
- state = mate_mixer_backend_get_state (control->priv->backend);
+ state = mate_mixer_backend_get_state (context->priv->backend);
if (G_UNLIKELY (state != MATE_MIXER_STATE_READY &&
state != MATE_MIXER_STATE_CONNECTING)) {
/* This would be a backend bug */
g_warn_if_reached ();
- if (control->priv->backend_type == MATE_MIXER_BACKEND_UNKNOWN)
- return try_next_backend (control);
+ if (context->priv->backend_type == MATE_MIXER_BACKEND_UNKNOWN)
+ return try_next_backend (context);
- close_control (control);
- change_state (control, MATE_MIXER_STATE_FAILED);
+ close_context (context);
+ change_state (context, MATE_MIXER_STATE_FAILED);
return FALSE;
}
- g_signal_connect (G_OBJECT (control->priv->backend),
+ g_signal_connect (G_OBJECT (context->priv->backend),
"notify::state",
G_CALLBACK (on_backend_state_notify),
- control);
+ context);
- change_state (control, state);
+ change_state (context, state);
return TRUE;
}
/**
- * mate_mixer_control_close:
- * @control: a #MateMixerControl
+ * mate_mixer_context_close:
+ * @context: a #MateMixerContext
*
* Closes connection to the currently used sound system. The state will be
* set to %MATE_MIXER_STATE_IDLE.
*/
void
-mate_mixer_control_close (MateMixerControl *control)
+mate_mixer_context_close (MateMixerContext *context)
{
- g_return_if_fail (MATE_MIXER_IS_CONTROL (control));
+ g_return_if_fail (MATE_MIXER_IS_CONTEXT (context));
- close_control (control);
- change_state (control, MATE_MIXER_STATE_IDLE);
+ close_context (context);
+ change_state (context, MATE_MIXER_STATE_IDLE);
}
/**
- * mate_mixer_control_get_state:
- * @control: a #MateMixerControl
+ * mate_mixer_context_get_state:
+ * @context: a #MateMixerContext
*
- * Gets the current backend connection state of the #MateMixerControl.
+ * Gets the current backend connection state of the #MateMixerContext.
*
* Returns: The current connection state.
*/
MateMixerState
-mate_mixer_control_get_state (MateMixerControl *control)
+mate_mixer_context_get_state (MateMixerContext *context)
{
- g_return_val_if_fail (MATE_MIXER_IS_CONTROL (control), MATE_MIXER_STATE_UNKNOWN);
+ g_return_val_if_fail (MATE_MIXER_IS_CONTEXT (context), MATE_MIXER_STATE_UNKNOWN);
- return control->priv->state;
+ return context->priv->state;
}
/**
- * mate_mixer_control_get_device:
- * @control: a #MateMixerControl
+ * mate_mixer_context_get_device:
+ * @context: a #MateMixerContext
* @name: a device name
*
- * Gets the devices with the given name.
+ * Gets the device with the given name.
*
* Returns: a #MateMixerDevice or %NULL if there is no such device.
*/
MateMixerDevice *
-mate_mixer_control_get_device (MateMixerControl *control, const gchar *name)
+mate_mixer_context_get_device (MateMixerContext *context, const gchar *name)
{
- const GList *list;
+ GList *list;
- g_return_val_if_fail (MATE_MIXER_IS_CONTROL (control), NULL);
+ g_return_val_if_fail (MATE_MIXER_IS_CONTEXT (context), NULL);
g_return_val_if_fail (name != NULL, NULL);
- list = mate_mixer_control_list_devices (control);
+ list = (GList *) mate_mixer_context_list_devices (context);
while (list != NULL) {
MateMixerDevice *device = MATE_MIXER_DEVICE (list->data);
@@ -874,8 +866,8 @@ mate_mixer_control_get_device (MateMixerControl *control, const gchar *name)
}
/**
- * mate_mixer_control_get_stream:
- * @control: a #MateMixerControl
+ * mate_mixer_context_get_stream:
+ * @context: a #MateMixerContext
* @name: a stream name
*
* Gets the stream with the given name.
@@ -883,14 +875,14 @@ mate_mixer_control_get_device (MateMixerControl *control, const gchar *name)
* Returns: a #MateMixerStream or %NULL if there is no such stream.
*/
MateMixerStream *
-mate_mixer_control_get_stream (MateMixerControl *control, const gchar *name)
+mate_mixer_context_get_stream (MateMixerContext *context, const gchar *name)
{
- const GList *list;
+ GList *list;
- g_return_val_if_fail (MATE_MIXER_IS_CONTROL (control), NULL);
+ g_return_val_if_fail (MATE_MIXER_IS_CONTEXT (context), NULL);
g_return_val_if_fail (name != NULL, NULL);
- list = mate_mixer_control_list_streams (control);
+ list = (GList *) mate_mixer_context_list_streams (context);
while (list != NULL) {
MateMixerStream *stream = MATE_MIXER_STREAM (list->data);
@@ -903,21 +895,24 @@ mate_mixer_control_get_stream (MateMixerControl *control, const gchar *name)
}
/**
- * mate_mixer_control_get_cached_stream:
- * @control: a #MateMixerControl
+ * mate_mixer_context_get_stored_stream:
+ * @context: a #MateMixerContext
* @name: a stream name
*
+ * Gets the stream with the given name.
+ *
+ * Returns: a #MateMixerStream or %NULL if there is no such stream.
*/
MateMixerStream *
-mate_mixer_control_get_cached_stream (MateMixerControl *control, const gchar *name)
+mate_mixer_context_get_stored_stream (MateMixerContext *context, const gchar *name)
{
- const GList *list;
+ GList *list;
- g_return_val_if_fail (MATE_MIXER_IS_CONTROL (control), NULL);
+ g_return_val_if_fail (MATE_MIXER_IS_CONTEXT (context), NULL);
g_return_val_if_fail (name != NULL, NULL);
- list = mate_mixer_control_list_cached_streams (control);
- while (list) {
+ list = (GList *) mate_mixer_context_list_stored_streams (context);
+ while (list != NULL) {
MateMixerStream *stream = MATE_MIXER_STREAM (list->data);
if (strcmp (name, mate_mixer_stream_get_name (stream)) == 0)
@@ -929,90 +924,72 @@ mate_mixer_control_get_cached_stream (MateMixerControl *control, const gchar *na
}
/**
- * mate_mixer_control_list_devices:
- * @control: a #MateMixerControl
+ * mate_mixer_context_list_devices:
+ * @context: a #MateMixerContext
*
* Gets a list of devices. Each list item is a #MateMixerDevice representing a
* hardware or software sound device in the system.
*
- * The returned #GList is owned by the #MateMixerControl and may be invalidated
+ * The returned #GList is owned by the #MateMixerContext and may be invalidated
* at any time.
*
* Returns: a #GList of all devices in the system or %NULL if there are none or
* you are not connected to a sound system.
*/
const GList *
-mate_mixer_control_list_devices (MateMixerControl *control)
+mate_mixer_context_list_devices (MateMixerContext *context)
{
- g_return_val_if_fail (MATE_MIXER_IS_CONTROL (control), NULL);
+ g_return_val_if_fail (MATE_MIXER_IS_CONTEXT (context), NULL);
- if (control->priv->state != MATE_MIXER_STATE_READY)
+ if (context->priv->state != MATE_MIXER_STATE_READY)
return NULL;
- /* This list is cached here and invalidated when the backend notifies us
- * about a change */
- if (control->priv->devices == NULL)
- control->priv->devices =
- mate_mixer_backend_list_devices (MATE_MIXER_BACKEND (control->priv->backend));
-
- return (const GList *) control->priv->devices;
+ return mate_mixer_backend_list_devices (MATE_MIXER_BACKEND (context->priv->backend));
}
/**
- * mate_mixer_control_list_streams:
- * @control: a #MateMixerControl
+ * mate_mixer_context_list_streams:
+ * @context: a #MateMixerContext
*
* Gets a list of streams. Each list item is a #MateMixerStream representing an
* input or output of a sound device.
*
- * The returned #GList is owned by the #MateMixerControl and may be invalidated
+ * The returned #GList is owned by the #MateMixerContext and may be invalidated
* at any time.
*
* Returns: a #GList of all streams in the system or %NULL if there are none or
* you are not connected to a sound system.
*/
const GList *
-mate_mixer_control_list_streams (MateMixerControl *control)
+mate_mixer_context_list_streams (MateMixerContext *context)
{
- g_return_val_if_fail (MATE_MIXER_IS_CONTROL (control), NULL);
+ g_return_val_if_fail (MATE_MIXER_IS_CONTEXT (context), NULL);
- if (control->priv->state != MATE_MIXER_STATE_READY)
+ if (context->priv->state != MATE_MIXER_STATE_READY)
return NULL;
- /* This list is cached here and invalidated when the backend notifies us
- * about a change */
- if (control->priv->streams == NULL)
- control->priv->streams =
- mate_mixer_backend_list_streams (MATE_MIXER_BACKEND (control->priv->backend));
-
- return (const GList *) control->priv->streams;
+ return mate_mixer_backend_list_streams (MATE_MIXER_BACKEND (context->priv->backend));
}
/**
- * mate_mixer_control_list_cached_streams:
- * @control: a #MateMixerControl
+ * mate_mixer_context_list_stored_streams:
+ * @context: a #MateMixerContext
*
*/
const GList *
-mate_mixer_control_list_cached_streams (MateMixerControl *control)
+mate_mixer_context_list_stored_streams (MateMixerContext *context)
{
- g_return_val_if_fail (MATE_MIXER_IS_CONTROL (control), NULL);
+ g_return_val_if_fail (MATE_MIXER_IS_CONTEXT (context), NULL);
- if (control->priv->state != MATE_MIXER_STATE_READY)
+ if (context->priv->state != MATE_MIXER_STATE_READY)
return NULL;
- /* This list is cached here and invalidated when the backend notifies us
- * about a change */
- if (control->priv->cached_streams == NULL)
- control->priv->cached_streams =
- mate_mixer_backend_list_cached_streams (MATE_MIXER_BACKEND (control->priv->backend));
-
- return (const GList *) control->priv->cached_streams;
+ return mate_mixer_backend_list_stored_streams (MATE_MIXER_BACKEND (context->priv->backend));
}
/**
- * mate_mixer_control_get_default_input_stream:
- * @control: a #MateMixerControl
+ * mate_mixer_context_get_default_input_stream:
+ * @context: a #MateMixerContext
*
* Gets the default input stream. The returned stream is where sound input is
* directed to by default.
@@ -1021,19 +998,19 @@ mate_mixer_control_list_cached_streams (MateMixerControl *control)
* the system.
*/
MateMixerStream *
-mate_mixer_control_get_default_input_stream (MateMixerControl *control)
+mate_mixer_context_get_default_input_stream (MateMixerContext *context)
{
- g_return_val_if_fail (MATE_MIXER_IS_CONTROL (control), NULL);
+ g_return_val_if_fail (MATE_MIXER_IS_CONTEXT (context), NULL);
- if (control->priv->state != MATE_MIXER_STATE_READY)
+ if (context->priv->state != MATE_MIXER_STATE_READY)
return NULL;
- return mate_mixer_backend_get_default_input_stream (control->priv->backend);
+ return mate_mixer_backend_get_default_input_stream (context->priv->backend);
}
/**
- * mate_mixer_control_set_default_input_stream:
- * @control: a #MateMixerControl
+ * mate_mixer_context_set_default_input_stream:
+ * @context: a #MateMixerContext
* @stream: a #MateMixerStream to set as the default input stream
*
* Changes the default input stream in the system. The @stream must be an
@@ -1042,13 +1019,13 @@ mate_mixer_control_get_default_input_stream (MateMixerControl *control)
* Returns: %TRUE on success or %FALSE on failure.
*/
gboolean
-mate_mixer_control_set_default_input_stream (MateMixerControl *control,
+mate_mixer_context_set_default_input_stream (MateMixerContext *context,
MateMixerStream *stream)
{
- g_return_val_if_fail (MATE_MIXER_IS_CONTROL (control), FALSE);
+ g_return_val_if_fail (MATE_MIXER_IS_CONTEXT (context), FALSE);
g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), FALSE);
- if (control->priv->state != MATE_MIXER_STATE_READY)
+ if (context->priv->state != MATE_MIXER_STATE_READY)
return FALSE;
if (MATE_MIXER_IS_CLIENT_STREAM (stream)) {
@@ -1060,12 +1037,12 @@ mate_mixer_control_set_default_input_stream (MateMixerControl *control,
return FALSE;
}
- return mate_mixer_backend_set_default_input_stream (control->priv->backend, stream);
+ return mate_mixer_backend_set_default_input_stream (context->priv->backend, stream);
}
/**
- * mate_mixer_control_get_default_output_stream:
- * @control: a #MateMixerControl
+ * mate_mixer_context_get_default_output_stream:
+ * @context: a #MateMixerContext
*
* Gets the default output stream. The returned stream is where sound output is
* directed to by default.
@@ -1074,19 +1051,19 @@ mate_mixer_control_set_default_input_stream (MateMixerControl *control,
* the system.
*/
MateMixerStream *
-mate_mixer_control_get_default_output_stream (MateMixerControl *control)
+mate_mixer_context_get_default_output_stream (MateMixerContext *context)
{
- g_return_val_if_fail (MATE_MIXER_IS_CONTROL (control), NULL);
+ g_return_val_if_fail (MATE_MIXER_IS_CONTEXT (context), NULL);
- if (control->priv->state != MATE_MIXER_STATE_READY)
+ if (context->priv->state != MATE_MIXER_STATE_READY)
return NULL;
- return mate_mixer_backend_get_default_output_stream (control->priv->backend);
+ return mate_mixer_backend_get_default_output_stream (context->priv->backend);
}
/**
- * mate_mixer_control_set_default_output_stream:
- * @control: a #MateMixerControl
+ * mate_mixer_context_set_default_output_stream:
+ * @context: a #MateMixerContext
* @stream: a #MateMixerStream to set as the default output stream
*
* Changes the default output stream in the system. The @stream must be an
@@ -1095,13 +1072,13 @@ mate_mixer_control_get_default_output_stream (MateMixerControl *control)
* Returns: %TRUE on success or %FALSE on failure.
*/
gboolean
-mate_mixer_control_set_default_output_stream (MateMixerControl *control,
- MateMixerStream *stream)
+mate_mixer_context_set_default_output_stream (MateMixerContext *context,
+ MateMixerStream *stream)
{
- g_return_val_if_fail (MATE_MIXER_IS_CONTROL (control), FALSE);
+ g_return_val_if_fail (MATE_MIXER_IS_CONTEXT (context), FALSE);
g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), FALSE);
- if (control->priv->state != MATE_MIXER_STATE_READY)
+ if (context->priv->state != MATE_MIXER_STATE_READY)
return FALSE;
if (MATE_MIXER_IS_CLIENT_STREAM (stream)) {
@@ -1113,12 +1090,12 @@ mate_mixer_control_set_default_output_stream (MateMixerControl *control,
return FALSE;
}
- return mate_mixer_backend_set_default_output_stream (control->priv->backend, stream);
+ return mate_mixer_backend_set_default_output_stream (context->priv->backend, stream);
}
/**
- * mate_mixer_control_get_backend_name:
- * @control: a #MateMixerControl
+ * mate_mixer_context_get_backend_name:
+ * @context: a #MateMixerContext
*
* Gets the name of the currently used backend. This function will not
* work until connected to a sound system.
@@ -1126,19 +1103,19 @@ mate_mixer_control_set_default_output_stream (MateMixerControl *control,
* Returns: the name or %NULL on error.
*/
const gchar *
-mate_mixer_control_get_backend_name (MateMixerControl *control)
+mate_mixer_context_get_backend_name (MateMixerContext *context)
{
- g_return_val_if_fail (MATE_MIXER_IS_CONTROL (control), NULL);
+ g_return_val_if_fail (MATE_MIXER_IS_CONTEXT (context), NULL);
- if (control->priv->backend_chosen == FALSE)
+ if (context->priv->backend_chosen == FALSE)
return NULL;
- return mate_mixer_backend_module_get_info (control->priv->module)->name;
+ return mate_mixer_backend_module_get_info (context->priv->module)->name;
}
/**
- * mate_mixer_control_get_backend_type:
- * @control: a #MateMixerControl
+ * mate_mixer_context_get_backend_type:
+ * @context: a #MateMixerContext
*
* Gets the type of the currently used backend. This function will not
* work until connected to a sound system.
@@ -1146,55 +1123,61 @@ mate_mixer_control_get_backend_name (MateMixerControl *control)
* Returns: the backend type or %MATE_MIXER_BACKEND_UNKNOWN on error.
*/
MateMixerBackendType
-mate_mixer_control_get_backend_type (MateMixerControl *control)
+mate_mixer_context_get_backend_type (MateMixerContext *context)
{
- g_return_val_if_fail (MATE_MIXER_IS_CONTROL (control), MATE_MIXER_BACKEND_UNKNOWN);
+ g_return_val_if_fail (MATE_MIXER_IS_CONTEXT (context), MATE_MIXER_BACKEND_UNKNOWN);
- if (control->priv->backend_chosen == FALSE)
+ if (context->priv->backend_chosen == FALSE)
return MATE_MIXER_BACKEND_UNKNOWN;
- return mate_mixer_backend_module_get_info (control->priv->module)->backend_type;
+ return mate_mixer_backend_module_get_info (context->priv->module)->backend_type;
+}
+
+/**
+ * mate_mixer_context_get_backend_flags:
+ * @context: a #MateMixerContext
+ */
+MateMixerBackendFlags
+mate_mixer_context_get_backend_flags (MateMixerContext *context)
+{
+ g_return_val_if_fail (MATE_MIXER_IS_CONTEXT (context), MATE_MIXER_BACKEND_NO_FLAGS);
+
+ return mate_mixer_backend_get_flags (context->priv->backend);
}
static void
on_backend_state_notify (MateMixerBackend *backend,
GParamSpec *pspec,
- MateMixerControl *control)
+ MateMixerContext *context)
{
MateMixerState state = mate_mixer_backend_get_state (backend);
switch (state) {
case MATE_MIXER_STATE_CONNECTING:
g_debug ("Backend %s changed state to CONNECTING",
- mate_mixer_backend_module_get_info (control->priv->module)->name);
+ mate_mixer_backend_module_get_info (context->priv->module)->name);
- if (control->priv->backend_chosen == TRUE) {
- /* Invalidate cached data when reconnecting */
- free_devices (control);
- free_streams (control);
- free_cached_streams (control);
- }
- change_state (control, state);
+ change_state (context, state);
break;
case MATE_MIXER_STATE_READY:
g_debug ("Backend %s changed state to READY",
- mate_mixer_backend_module_get_info (control->priv->module)->name);
+ mate_mixer_backend_module_get_info (context->priv->module)->name);
- change_state (control, state);
+ change_state (context, state);
break;
case MATE_MIXER_STATE_FAILED:
g_debug ("Backend %s changed state to FAILED",
- mate_mixer_backend_module_get_info (control->priv->module)->name);
+ mate_mixer_backend_module_get_info (context->priv->module)->name);
- if (control->priv->backend_type == MATE_MIXER_BACKEND_UNKNOWN) {
+ if (context->priv->backend_type == MATE_MIXER_BACKEND_UNKNOWN) {
/* User didn't request a specific backend, so try another one */
- try_next_backend (control);
+ try_next_backend (context);
} else {
/* User requested a specific backend and it failed */
- close_control (control);
- change_state (control, state);
+ close_context (context);
+ change_state (context, state);
}
break;
@@ -1206,11 +1189,9 @@ on_backend_state_notify (MateMixerBackend *backend,
static void
on_backend_device_added (MateMixerBackend *backend,
const gchar *name,
- MateMixerControl *control)
+ MateMixerContext *context)
{
- free_devices (control);
-
- g_signal_emit (G_OBJECT (control),
+ g_signal_emit (G_OBJECT (context),
signals[DEVICE_ADDED],
0,
name);
@@ -1219,11 +1200,9 @@ on_backend_device_added (MateMixerBackend *backend,
static void
on_backend_device_removed (MateMixerBackend *backend,
const gchar *name,
- MateMixerControl *control)
+ MateMixerContext *context)
{
- free_devices (control);
-
- g_signal_emit (G_OBJECT (control),
+ g_signal_emit (G_OBJECT (context),
signals[DEVICE_REMOVED],
0,
name);
@@ -1232,11 +1211,9 @@ on_backend_device_removed (MateMixerBackend *backend,
static void
on_backend_stream_added (MateMixerBackend *backend,
const gchar *name,
- MateMixerControl *control)
+ MateMixerContext *context)
{
- free_streams (control);
-
- g_signal_emit (G_OBJECT (control),
+ g_signal_emit (G_OBJECT (context),
signals[STREAM_ADDED],
0,
name);
@@ -1245,70 +1222,64 @@ on_backend_stream_added (MateMixerBackend *backend,
static void
on_backend_stream_removed (MateMixerBackend *backend,
const gchar *name,
- MateMixerControl *control)
+ MateMixerContext *context)
{
- free_streams (control);
-
- g_signal_emit (G_OBJECT (control),
+ g_signal_emit (G_OBJECT (context),
signals[STREAM_REMOVED],
0,
name);
}
static void
-on_backend_cached_stream_added (MateMixerBackend *backend,
+on_backend_stored_stream_added (MateMixerBackend *backend,
const gchar *name,
- MateMixerControl *control)
+ MateMixerContext *context)
{
- free_cached_streams (control);
-
- g_signal_emit (G_OBJECT (control),
- signals[CACHED_STREAM_ADDED],
+ g_signal_emit (G_OBJECT (context),
+ signals[STORED_STREAM_ADDED],
0,
name);
}
static void
-on_backend_cached_stream_removed (MateMixerBackend *backend,
+on_backend_stored_stream_removed (MateMixerBackend *backend,
const gchar *name,
- MateMixerControl *control)
+ MateMixerContext *context)
{
- free_cached_streams (control);
-
- g_signal_emit (G_OBJECT (control),
- signals[CACHED_STREAM_REMOVED],
+ g_signal_emit (G_OBJECT (context),
+ signals[STORED_STREAM_REMOVED],
0,
name);
}
static void
-on_backend_default_input_notify (MateMixerBackend *backend,
- GParamSpec *pspec,
- MateMixerControl *control)
+on_backend_default_input_stream_notify (MateMixerBackend *backend,
+ GParamSpec *pspec,
+ MateMixerContext *context)
{
- g_object_notify_by_pspec (G_OBJECT (control), properties[PROP_DEFAULT_INPUT]);
+ g_object_notify_by_pspec (G_OBJECT (context), properties[PROP_DEFAULT_INPUT_STREAM]);
}
static void
-on_backend_default_output_notify (MateMixerBackend *backend,
- GParamSpec *pspec,
- MateMixerControl *control)
+on_backend_default_output_stream_notify (MateMixerBackend *backend,
+ GParamSpec *pspec,
+ MateMixerContext *context)
{
- g_object_notify_by_pspec (G_OBJECT (control), properties[PROP_DEFAULT_OUTPUT]);
+ g_object_notify_by_pspec (G_OBJECT (context), properties[PROP_DEFAULT_OUTPUT_STREAM]);
}
static gboolean
-try_next_backend (MateMixerControl *control)
+try_next_backend (MateMixerContext *context)
{
MateMixerBackendModule *module = NULL;
MateMixerState state;
const GList *modules;
const MateMixerBackendInfo *info = NULL;
- modules = mate_mixer_get_modules ();
+ modules = _mate_mixer_get_modules ();
while (modules != NULL) {
- if (control->priv->module == modules->data) {
+ if (context->priv->module == modules->data) {
/* Found the last tested backend, try to use the next one with a lower
* priority unless we have reached the end of the list */
if (modules->next != NULL)
@@ -1317,11 +1288,11 @@ try_next_backend (MateMixerControl *control)
}
modules = modules->next;
}
- close_control (control);
+ close_context (context);
if (module == NULL) {
/* We have tried all the modules and all of them failed */
- change_state (control, MATE_MIXER_STATE_FAILED);
+ change_state (context, MATE_MIXER_STATE_FAILED);
return FALSE;
}
@@ -1330,143 +1301,99 @@ try_next_backend (MateMixerControl *control)
control->priv->module = g_object_ref (module);
control->priv->backend = g_object_new (info->g_type, NULL);
- mate_mixer_backend_set_data (control->priv->backend, &control->priv->backend_data);
+ mate_mixer_backend_set_data (context->priv->backend, &context->priv->backend_data);
g_debug ("Trying to open backend %s", info->name);
/* Try to open this backend and in case of failure keep trying until we find
* one that works or reach the end of the list */
- if (mate_mixer_backend_open (control->priv->backend) == FALSE)
- return try_next_backend (control);
+ if (mate_mixer_backend_open (context->priv->backend) == FALSE)
+ return try_next_backend (context);
- state = mate_mixer_backend_get_state (control->priv->backend);
+ state = mate_mixer_backend_get_state (context->priv->backend);
if (G_UNLIKELY (state != MATE_MIXER_STATE_READY &&
state != MATE_MIXER_STATE_CONNECTING)) {
/* This would be a backend bug */
g_warn_if_reached ();
- return try_next_backend (control);
+ return try_next_backend (context);
}
- g_signal_connect (G_OBJECT (control->priv->backend),
+ g_signal_connect (G_OBJECT (context->priv->backend),
"notify::state",
G_CALLBACK (on_backend_state_notify),
- control);
+ context);
- change_state (control, state);
+ change_state (context, state);
return TRUE;
}
static void
-change_state (MateMixerControl *control, MateMixerState state)
+change_state (MateMixerContext *context, MateMixerState state)
{
- if (control->priv->state == state)
+ if (context->priv->state == state)
return;
- control->priv->state = state;
+ context->priv->state = state;
- if (state == MATE_MIXER_STATE_READY && control->priv->backend_chosen == FALSE) {
+ if (state == MATE_MIXER_STATE_READY && context->priv->backend_chosen == FALSE) {
/* It is safe to connect to the backend signals after reaching the READY
* state, because the app is not allowed to query any data before that state;
* therefore we won't end up in an inconsistent state by caching a list and
* then missing a notification about a change in the list */
- g_signal_connect (G_OBJECT (control->priv->backend),
+ g_signal_connect (G_OBJECT (context->priv->backend),
"device-added",
G_CALLBACK (on_backend_device_added),
- control);
- g_signal_connect (G_OBJECT (control->priv->backend),
+ context);
+ g_signal_connect (G_OBJECT (context->priv->backend),
"device-removed",
G_CALLBACK (on_backend_device_removed),
- control);
- g_signal_connect (G_OBJECT (control->priv->backend),
+ context);
+ g_signal_connect (G_OBJECT (context->priv->backend),
"stream-added",
G_CALLBACK (on_backend_stream_added),
- control);
- g_signal_connect (G_OBJECT (control->priv->backend),
+ context);
+ g_signal_connect (G_OBJECT (context->priv->backend),
"stream-removed",
G_CALLBACK (on_backend_stream_removed),
- control);
- g_signal_connect (G_OBJECT (control->priv->backend),
- "cached-stream-added",
- G_CALLBACK (on_backend_cached_stream_added),
- control);
- g_signal_connect (G_OBJECT (control->priv->backend),
- "cached-stream-removed",
- G_CALLBACK (on_backend_cached_stream_removed),
- control);
-
- g_signal_connect (G_OBJECT (control->priv->backend),
+ context);
+ g_signal_connect (G_OBJECT (context->priv->backend),
+ "stored-stream-added",
+ G_CALLBACK (on_backend_stored_stream_added),
+ context);
+ g_signal_connect (G_OBJECT (context->priv->backend),
+ "stored-stream-removed",
+ G_CALLBACK (on_backend_stored_stream_removed),
+ context);
+
+ g_signal_connect (G_OBJECT (context->priv->backend),
"notify::default-input",
- G_CALLBACK (on_backend_default_input_notify),
- control);
- g_signal_connect (G_OBJECT (control->priv->backend),
+ G_CALLBACK (on_backend_default_input_stream_notify),
+ context);
+ g_signal_connect (G_OBJECT (context->priv->backend),
"notify::default-output",
- G_CALLBACK (on_backend_default_output_notify),
- control);
+ G_CALLBACK (on_backend_default_output_stream_notify),
+ context);
- control->priv->backend_chosen = TRUE;
+ context->priv->backend_chosen = TRUE;
}
- g_object_notify_by_pspec (G_OBJECT (control), properties[PROP_STATE]);
-}
-
-static void
-close_control (MateMixerControl *control)
-{
- free_backend (control);
- free_devices (control);
- free_streams (control);
- free_cached_streams (control);
-
- g_clear_object (&control->priv->module);
-
- control->priv->backend_chosen = FALSE;
-}
-
-static void
-free_backend (MateMixerControl *control)
-{
- if (control->priv->backend == NULL)
- return;
-
- g_signal_handlers_disconnect_by_data (G_OBJECT (control->priv->backend),
- control);
-
- mate_mixer_backend_close (control->priv->backend);
-
- g_clear_object (&control->priv->backend);
+ g_object_notify_by_pspec (G_OBJECT (context), properties[PROP_STATE]);
}
static void
-free_devices (MateMixerControl *control)
+close_context (MateMixerContext *context)
{
- if (control->priv->devices == NULL)
- return;
-
- g_list_free_full (control->priv->devices, g_object_unref);
+ if (context->priv->backend != NULL) {
+ g_signal_handlers_disconnect_by_data (G_OBJECT (context->priv->backend),
+ context);
- control->priv->devices = NULL;
-}
-
-static void
-free_streams (MateMixerControl *control)
-{
- if (control->priv->streams == NULL)
- return;
-
- g_list_free_full (control->priv->streams, g_object_unref);
-
- control->priv->streams = NULL;
-}
-
-static void
-free_cached_streams (MateMixerControl *control)
-{
- if (control->priv->cached_streams == NULL)
- return;
+ mate_mixer_backend_close (context->priv->backend);
+ g_clear_object (&context->priv->backend);
+ }
- g_list_free_full (control->priv->cached_streams, g_object_unref);
+ g_clear_object (&context->priv->module);
- control->priv->cached_streams = NULL;
+ context->priv->backend_chosen = FALSE;
}
diff --git a/libmatemixer/matemixer-context.h b/libmatemixer/matemixer-context.h
new file mode 100644
index 0000000..3370570
--- /dev/null
+++ b/libmatemixer/matemixer-context.h
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the licence, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef MATEMIXER_CONTEXT_H
+#define MATEMIXER_CONTEXT_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include <libmatemixer/matemixer-enums.h>
+#include <libmatemixer/matemixer-types.h>
+
+G_BEGIN_DECLS
+
+#define MATE_MIXER_TYPE_CONTEXT \
+ (mate_mixer_context_get_type ())
+#define MATE_MIXER_CONTEXT(o) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((o), MATE_MIXER_TYPE_CONTEXT, MateMixerContext))
+#define MATE_MIXER_IS_CONTEXT(o) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((o), MATE_MIXER_TYPE_CONTEXT))
+#define MATE_MIXER_CONTEXT_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_CAST ((k), MATE_MIXER_TYPE_CONTEXT, MateMixerContextClass))
+#define MATE_MIXER_IS_CONTEXT_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_TYPE ((k), MATE_MIXER_TYPE_CONTEXT))
+#define MATE_MIXER_CONTEXT_GET_CLASS(o) \
+ (G_TYPE_INSTANCE_GET_CLASS ((o), MATE_MIXER_TYPE_CONTEXT, MateMixerContextClass))
+
+typedef struct _MateMixerContextClass MateMixerContextClass;
+typedef struct _MateMixerContextPrivate MateMixerContextPrivate;
+
+/**
+ * MateMixerContext:
+ *
+ * The #MateMixerContext structure contains only private data and should only
+ * be accessed using the provided API.
+ */
+struct _MateMixerContext
+{
+ GObject parent;
+
+ /*< private >*/
+ MateMixerContextPrivate *priv;
+};
+
+/**
+ * MateMixerContextClass:
+ *
+ * The class structure of #MateMixerContext.
+ */
+struct _MateMixerContextClass
+{
+ GObjectClass parent_class;
+
+ /*< private >*/
+ void (*device_added) (MateMixerContext *context,
+ const gchar *name);
+ void (*device_removed) (MateMixerContext *context,
+ const gchar *name);
+ void (*stream_added) (MateMixerContext *context,
+ const gchar *name);
+ void (*stream_removed) (MateMixerContext *context,
+ const gchar *name);
+ void (*stored_stream_added) (MateMixerContext *context,
+ const gchar *name);
+ void (*stored_stream_removed) (MateMixerContext *context,
+ const gchar *name);
+};
+
+GType mate_mixer_context_get_type (void) G_GNUC_CONST;
+
+MateMixerContext * mate_mixer_context_new (void);
+
+gboolean mate_mixer_context_set_backend_type (MateMixerContext *context,
+ MateMixerBackendType backend_type);
+gboolean mate_mixer_context_set_app_name (MateMixerContext *context,
+ const gchar *app_name);
+gboolean mate_mixer_context_set_app_id (MateMixerContext *context,
+ const gchar *app_id);
+gboolean mate_mixer_context_set_app_version (MateMixerContext *context,
+ const gchar *app_version);
+gboolean mate_mixer_context_set_app_icon (MateMixerContext *context,
+ const gchar *app_icon);
+gboolean mate_mixer_context_set_server_address (MateMixerContext *context,
+ const gchar *address);
+
+gboolean mate_mixer_context_open (MateMixerContext *context);
+void mate_mixer_context_close (MateMixerContext *context);
+
+MateMixerState mate_mixer_context_get_state (MateMixerContext *context);
+
+MateMixerDevice * mate_mixer_context_get_device (MateMixerContext *context,
+ const gchar *name);
+MateMixerStream * mate_mixer_context_get_stream (MateMixerContext *context,
+ const gchar *name);
+MateMixerStream * mate_mixer_context_get_stored_stream (MateMixerContext *context,
+ const gchar *name);
+
+const GList * mate_mixer_context_list_devices (MateMixerContext *context);
+const GList * mate_mixer_context_list_streams (MateMixerContext *context);
+const GList * mate_mixer_context_list_stored_streams (MateMixerContext *context);
+
+MateMixerStream * mate_mixer_context_get_default_input_stream (MateMixerContext *context);
+gboolean mate_mixer_context_set_default_input_stream (MateMixerContext *context,
+ MateMixerStream *stream);
+
+MateMixerStream * mate_mixer_context_get_default_output_stream (MateMixerContext *context);
+gboolean mate_mixer_context_set_default_output_stream (MateMixerContext *context,
+ MateMixerStream *stream);
+
+const gchar * mate_mixer_context_get_backend_name (MateMixerContext *context);
+MateMixerBackendType mate_mixer_context_get_backend_type (MateMixerContext *context);
+MateMixerBackendFlags mate_mixer_context_get_backend_flags (MateMixerContext *context);
+
+G_END_DECLS
+
+#endif /* MATEMIXER_CONTEXT_H */
diff --git a/libmatemixer/matemixer-control.h b/libmatemixer/matemixer-control.h
deleted file mode 100644
index e6d3afa..0000000
--- a/libmatemixer/matemixer-control.h
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Copyright (C) 2014 Michal Ratajsky <[email protected]>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the licence, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef MATEMIXER_CONTROL_H
-#define MATEMIXER_CONTROL_H
-
-#include <glib.h>
-#include <glib-object.h>
-
-#include <libmatemixer/matemixer-device.h>
-#include <libmatemixer/matemixer-enums.h>
-#include <libmatemixer/matemixer-stream.h>
-
-G_BEGIN_DECLS
-
-#define MATE_MIXER_TYPE_CONTROL \
- (mate_mixer_control_get_type ())
-#define MATE_MIXER_CONTROL(o) \
- (G_TYPE_CHECK_INSTANCE_CAST ((o), MATE_MIXER_TYPE_CONTROL, MateMixerControl))
-#define MATE_MIXER_IS_CONTROL(o) \
- (G_TYPE_CHECK_INSTANCE_TYPE ((o), MATE_MIXER_TYPE_CONTROL))
-#define MATE_MIXER_CONTROL_CLASS(k) \
- (G_TYPE_CHECK_CLASS_CAST ((k), MATE_MIXER_TYPE_CONTROL, MateMixerControlClass))
-#define MATE_MIXER_IS_CONTROL_CLASS(k) \
- (G_TYPE_CHECK_CLASS_TYPE ((k), MATE_MIXER_TYPE_CONTROL))
-#define MATE_MIXER_CONTROL_GET_CLASS(o) \
- (G_TYPE_INSTANCE_GET_CLASS ((o), MATE_MIXER_TYPE_CONTROL, MateMixerControlClass))
-
-typedef struct _MateMixerControl MateMixerControl;
-typedef struct _MateMixerControlClass MateMixerControlClass;
-typedef struct _MateMixerControlPrivate MateMixerControlPrivate;
-
-/**
- * MateMixerControl:
- *
- * The #MateMixerControl structure contains only private data and should only
- * be accessed using the provided API.
- */
-struct _MateMixerControl
-{
- GObject parent;
-
- /*< private >*/
- MateMixerControlPrivate *priv;
-};
-
-/**
- * MateMixerControlClass:
- *
- * The class structure of #MateMixerControl.
- */
-struct _MateMixerControlClass
-{
- GObjectClass parent_class;
-
- /*< private >*/
- /* Signals */
- void (*device_added) (MateMixerControl *control,
- const gchar *name);
- void (*device_changed) (MateMixerControl *control,
- const gchar *name);
- void (*device_removed) (MateMixerControl *control,
- const gchar *name);
- void (*stream_added) (MateMixerControl *control,
- const gchar *name);
- void (*stream_changed) (MateMixerControl *control,
- const gchar *name);
- void (*stream_removed) (MateMixerControl *control,
- const gchar *name);
- void (*cached_stream_added) (MateMixerControl *control,
- const gchar *name);
- void (*cached_stream_changed) (MateMixerControl *control,
- const gchar *name);
- void (*cached_stream_removed) (MateMixerControl *control,
- const gchar *name);
-};
-
-GType mate_mixer_control_get_type (void) G_GNUC_CONST;
-
-MateMixerControl * mate_mixer_control_new (void);
-
-gboolean mate_mixer_control_set_backend_type (MateMixerControl *control,
- MateMixerBackendType backend_type);
-gboolean mate_mixer_control_set_app_name (MateMixerControl *control,
- const gchar *app_name);
-gboolean mate_mixer_control_set_app_id (MateMixerControl *control,
- const gchar *app_id);
-gboolean mate_mixer_control_set_app_version (MateMixerControl *control,
- const gchar *app_version);
-gboolean mate_mixer_control_set_app_icon (MateMixerControl *control,
- const gchar *app_icon);
-gboolean mate_mixer_control_set_server_address (MateMixerControl *control,
- const gchar *address);
-
-gboolean mate_mixer_control_open (MateMixerControl *control);
-void mate_mixer_control_close (MateMixerControl *control);
-
-MateMixerState mate_mixer_control_get_state (MateMixerControl *control);
-
-MateMixerDevice * mate_mixer_control_get_device (MateMixerControl *control,
- const gchar *name);
-MateMixerStream * mate_mixer_control_get_stream (MateMixerControl *control,
- const gchar *name);
-MateMixerStream * mate_mixer_control_get_cached_stream (MateMixerControl *control,
- const gchar *name);
-
-const GList * mate_mixer_control_list_devices (MateMixerControl *control);
-const GList * mate_mixer_control_list_streams (MateMixerControl *control);
-const GList * mate_mixer_control_list_cached_streams (MateMixerControl *control);
-
-MateMixerStream * mate_mixer_control_get_default_input_stream (MateMixerControl *control);
-gboolean mate_mixer_control_set_default_input_stream (MateMixerControl *control,
- MateMixerStream *stream);
-
-MateMixerStream * mate_mixer_control_get_default_output_stream (MateMixerControl *control);
-gboolean mate_mixer_control_set_default_output_stream (MateMixerControl *control,
- MateMixerStream *stream);
-
-const gchar * mate_mixer_control_get_backend_name (MateMixerControl *control);
-MateMixerBackendType mate_mixer_control_get_backend_type (MateMixerControl *control);
-
-G_END_DECLS
-
-#endif /* MATEMIXER_CONTROL_H */
diff --git a/libmatemixer/matemixer-device-profile-private.h b/libmatemixer/matemixer-device-profile-private.h
index 403c7d7..44f2853 100644
--- a/libmatemixer/matemixer-device-profile-private.h
+++ b/libmatemixer/matemixer-device-profile-private.h
@@ -24,20 +24,20 @@
G_BEGIN_DECLS
-MateMixerDeviceProfile *_mate_mixer_device_profile_new (const gchar *name,
- const gchar *description,
- guint priority,
- guint input_streams,
- guint output_streams);
-
-gboolean _mate_mixer_device_profile_update_description (MateMixerDeviceProfile *profile,
- const gchar *description);
-gboolean _mate_mixer_device_profile_update_priority (MateMixerDeviceProfile *profile,
- guint priority);
-gboolean _mate_mixer_device_profile_update_num_input_streams (MateMixerDeviceProfile *profile,
- guint num);
-gboolean _mate_mixer_device_profile_update_num_output_streams (MateMixerDeviceProfile *profile,
- guint num);
+MateMixerDeviceProfile *_mate_mixer_device_profile_new (const gchar *name,
+ const gchar *description,
+ guint priority,
+ guint input_streams,
+ guint output_streams);
+
+gboolean _mate_mixer_device_profile_set_label (MateMixerDeviceProfile *profile,
+ const gchar *label);
+gboolean _mate_mixer_device_profile_set_priority (MateMixerDeviceProfile *profile,
+ guint priority);
+gboolean _mate_mixer_device_profile_set_num_input_streams (MateMixerDeviceProfile *profile,
+ guint num);
+gboolean _mate_mixer_device_profile_set_num_output_streams (MateMixerDeviceProfile *profile,
+ guint num);
G_END_DECLS
diff --git a/libmatemixer/matemixer-device-profile.c b/libmatemixer/matemixer-device-profile.c
index 0485740..d841ff2 100644
--- a/libmatemixer/matemixer-device-profile.c
+++ b/libmatemixer/matemixer-device-profile.c
@@ -30,7 +30,7 @@
struct _MateMixerDeviceProfilePrivate
{
gchar *name;
- gchar *description;
+ gchar *label;
guint priority;
guint num_input_streams;
guint num_output_streams;
@@ -39,7 +39,7 @@ struct _MateMixerDeviceProfilePrivate
enum {
PROP_0,
PROP_NAME,
- PROP_DESCRIPTION,
+ PROP_LABEL,
PROP_PRIORITY,
PROP_NUM_INPUT_STREAMS,
PROP_NUM_OUTPUT_STREAMS,
@@ -83,10 +83,10 @@ mate_mixer_device_profile_class_init (MateMixerDeviceProfileClass *klass)
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS);
- properties[PROP_DESCRIPTION] =
- g_param_spec_string ("description",
- "Description",
- "Description of the profile",
+ properties[PROP_LABEL] =
+ g_param_spec_string ("label",
+ "Label",
+ "Label of the profile",
NULL,
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_READWRITE |
@@ -144,18 +144,23 @@ mate_mixer_device_profile_get_property (GObject *object,
case PROP_NAME:
g_value_set_string (value, profile->priv->name);
break;
- case PROP_DESCRIPTION:
- g_value_set_string (value, profile->priv->description);
+
+ case PROP_LABEL:
+ g_value_set_string (value, profile->priv->label);
break;
+
case PROP_PRIORITY:
g_value_set_uint (value, profile->priv->priority);
break;
+
case PROP_NUM_INPUT_STREAMS:
g_value_set_uint (value, profile->priv->num_input_streams);
break;
+
case PROP_NUM_OUTPUT_STREAMS:
g_value_set_uint (value, profile->priv->num_output_streams);
break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
break;
@@ -177,19 +182,24 @@ mate_mixer_device_profile_set_property (GObject *object,
/* Construct-only string */
profile->priv->name = g_strdup (g_value_get_string (value));
break;
- case PROP_DESCRIPTION:
+
+ case PROP_LABEL:
/* Construct-only string */
- profile->priv->description = g_strdup (g_value_get_string (value));
+ profile->priv->label = g_strdup (g_value_get_string (value));
break;
+
case PROP_PRIORITY:
profile->priv->priority = g_value_get_uint (value);
break;
+
case PROP_NUM_INPUT_STREAMS:
profile->priv->num_input_streams = g_value_get_uint (value);
break;
+
case PROP_NUM_OUTPUT_STREAMS:
profile->priv->num_output_streams = g_value_get_uint (value);
break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
break;
@@ -212,7 +222,7 @@ mate_mixer_device_profile_finalize (GObject *object)
profile = MATE_MIXER_DEVICE_PROFILE (object);
g_free (profile->priv->name);
- g_free (profile->priv->description);
+ g_free (profile->priv->label);
G_OBJECT_CLASS (mate_mixer_device_profile_parent_class)->finalize (object);
}
@@ -230,15 +240,15 @@ mate_mixer_device_profile_get_name (MateMixerDeviceProfile *profile)
}
/**
- * mate_mixer_device_profile_get_description:
+ * mate_mixer_device_profile_get_label:
* @profile: a #MateMixerDeviceProfile
*/
const gchar *
-mate_mixer_device_profile_get_description (MateMixerDeviceProfile *profile)
+mate_mixer_device_profile_get_label (MateMixerDeviceProfile *profile)
{
g_return_val_if_fail (MATE_MIXER_IS_DEVICE_PROFILE (profile), NULL);
- return profile->priv->description;
+ return profile->priv->label;
}
/**
@@ -279,14 +289,14 @@ mate_mixer_device_profile_get_num_output_streams (MateMixerDeviceProfile *profil
MateMixerDeviceProfile *
_mate_mixer_device_profile_new (const gchar *name,
- const gchar *description,
+ const gchar *label,
guint priority,
guint input_streams,
guint output_streams)
{
return g_object_new (MATE_MIXER_TYPE_DEVICE_PROFILE,
"name", name,
- "description", description,
+ "label", label,
"priority", priority,
"num-input-streams", input_streams,
"num-output-streams", output_streams,
@@ -294,17 +304,17 @@ _mate_mixer_device_profile_new (const gchar *name,
}
gboolean
-_mate_mixer_device_profile_update_description (MateMixerDeviceProfile *profile,
- const gchar *description)
+_mate_mixer_device_profile_set_label (MateMixerDeviceProfile *profile,
+ const gchar *label)
{
g_return_val_if_fail (MATE_MIXER_IS_DEVICE_PROFILE (profile), FALSE);
- if (g_strcmp0 (profile->priv->description, description) != 0) {
- g_free (profile->priv->description);
+ if (g_strcmp0 (profile->priv->label, label) != 0) {
+ g_free (profile->priv->label);
- profile->priv->description = g_strdup (description);
+ profile->priv->label = g_strdup (label);
- g_object_notify_by_pspec (G_OBJECT (profile), properties[PROP_DESCRIPTION]);
+ g_object_notify_by_pspec (G_OBJECT (profile), properties[PROP_LABEL]);
return TRUE;
}
@@ -312,8 +322,8 @@ _mate_mixer_device_profile_update_description (MateMixerDeviceProfile *profile,
}
gboolean
-_mate_mixer_device_profile_update_priority (MateMixerDeviceProfile *profile,
- guint priority)
+_mate_mixer_device_profile_set_priority (MateMixerDeviceProfile *profile,
+ guint priority)
{
g_return_val_if_fail (MATE_MIXER_IS_DEVICE_PROFILE (profile), FALSE);
@@ -328,8 +338,8 @@ _mate_mixer_device_profile_update_priority (MateMixerDeviceProfile *profile,
}
gboolean
-_mate_mixer_device_profile_update_num_input_streams (MateMixerDeviceProfile *profile,
- guint num)
+_mate_mixer_device_profile_set_num_input_streams (MateMixerDeviceProfile *profile,
+ guint num)
{
g_return_val_if_fail (MATE_MIXER_IS_DEVICE_PROFILE (profile), FALSE);
@@ -344,8 +354,8 @@ _mate_mixer_device_profile_update_num_input_streams (MateMixerDeviceProfile *pro
}
gboolean
-_mate_mixer_device_profile_update_num_output_streams (MateMixerDeviceProfile *profile,
- guint num)
+_mate_mixer_device_profile_set_num_output_streams (MateMixerDeviceProfile *profile,
+ guint num)
{
g_return_val_if_fail (MATE_MIXER_IS_DEVICE_PROFILE (profile), FALSE);
diff --git a/libmatemixer/matemixer-device-profile.h b/libmatemixer/matemixer-device-profile.h
index e8fae19..8e4221a 100644
--- a/libmatemixer/matemixer-device-profile.h
+++ b/libmatemixer/matemixer-device-profile.h
@@ -20,6 +20,7 @@
#include <glib.h>
#include <glib-object.h>
+#include <libmatemixer/matemixer-types.h>
G_BEGIN_DECLS
@@ -36,7 +37,6 @@ G_BEGIN_DECLS
#define MATE_MIXER_DEVICE_PROFILE_GET_CLASS(o) \
(G_TYPE_INSTANCE_GET_CLASS ((o), MATE_MIXER_TYPE_DEVICE_PROFILE, MateMixerDeviceProfileClass))
-typedef struct _MateMixerDeviceProfile MateMixerDeviceProfile;
typedef struct _MateMixerDeviceProfileClass MateMixerDeviceProfileClass;
typedef struct _MateMixerDeviceProfilePrivate MateMixerDeviceProfilePrivate;
@@ -56,8 +56,9 @@ struct _MateMixerDeviceProfileClass
GType mate_mixer_device_profile_get_type (void) G_GNUC_CONST;
const gchar *mate_mixer_device_profile_get_name (MateMixerDeviceProfile *profile);
-const gchar *mate_mixer_device_profile_get_description (MateMixerDeviceProfile *profile);
+const gchar *mate_mixer_device_profile_get_label (MateMixerDeviceProfile *profile);
guint mate_mixer_device_profile_get_priority (MateMixerDeviceProfile *profile);
+
guint mate_mixer_device_profile_get_num_input_streams (MateMixerDeviceProfile *profile);
guint mate_mixer_device_profile_get_num_output_streams (MateMixerDeviceProfile *profile);
diff --git a/libmatemixer/matemixer-device.c b/libmatemixer/matemixer-device.c
index 0406709..229110f 100644
--- a/libmatemixer/matemixer-device.c
+++ b/libmatemixer/matemixer-device.c
@@ -15,12 +15,14 @@
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
+#include <string.h>
#include <glib.h>
#include <glib-object.h>
#include "matemixer-device.h"
#include "matemixer-device-profile.h"
-#include "matemixer-port.h"
+#include "matemixer-stream.h"
+#include "matemixer-switch.h"
/**
* SECTION:matemixer-device
@@ -28,42 +30,270 @@
* @include: libmatemixer/matemixer.h
*/
-G_DEFINE_INTERFACE (MateMixerDevice, mate_mixer_device, G_TYPE_OBJECT)
+struct _MateMixerDevicePrivate
+{
+ gchar *name;
+ gchar *label;
+ gchar *icon;
+ GList *streams;
+ GList *switches;
+ GList *profiles;
+ MateMixerDeviceProfile *profile;
+};
+
+enum {
+ PROP_0,
+ PROP_NAME,
+ PROP_LABEL,
+ PROP_ICON,
+ PROP_ACTIVE_PROFILE,
+ N_PROPERTIES
+};
+
+static GParamSpec *properties[N_PROPERTIES] = { NULL, };
+
+enum {
+ STREAM_ADDED,
+ STREAM_REMOVED,
+ SWITCH_ADDED,
+ SWITCH_REMOVED,
+ N_SIGNALS
+};
+
+static guint signals[N_SIGNALS] = { 0, };
+
+static void mate_mixer_device_class_init (MateMixerDeviceClass *klass);
+
+static void mate_mixer_device_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec);
+static void mate_mixer_device_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec);
+
+static void mate_mixer_device_init (MateMixerDevice *device);
+static void mate_mixer_device_dispose (GObject *object);
+static void mate_mixer_device_finalize (GObject *object);
+
+G_DEFINE_ABSTRACT_TYPE (MateMixerDevice, mate_mixer_device, G_TYPE_OBJECT)
+
+static MateMixerStream * mate_mixer_device_real_get_stream (MateMixerDevice *device,
+ const gchar *name);
+static MateMixerSwitch * mate_mixer_device_real_get_switch (MateMixerDevice *device,
+ const gchar *name);
+static MateMixerDeviceProfile *mate_mixer_device_real_get_profile (MateMixerDevice *device,
+ const gchar *name);
+
+static void
+mate_mixer_device_class_init (MateMixerDeviceClass *klass)
+{
+ GObjectClass *object_class;
+
+ klass->get_stream = mate_mixer_device_real_get_stream;
+ klass->get_switch = mate_mixer_device_real_get_switch;
+ klass->get_profile = mate_mixer_device_real_get_profile;
+
+ object_class = G_OBJECT_CLASS (klass);
+ object_class->dispose = mate_mixer_device_dispose;
+ object_class->finalize = mate_mixer_device_finalize;
+ object_class->get_property = mate_mixer_device_get_property;
+ object_class->set_property = mate_mixer_device_set_property;
+
+ properties[PROP_NAME] =
+ g_param_spec_string ("name",
+ "Name",
+ "Name of the device",
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_LABEL] =
+ g_param_spec_string ("label",
+ "Label",
+ "Label of the device",
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_ICON] =
+ g_param_spec_string ("icon",
+ "Icon",
+ "Name of the sound device icon",
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_ACTIVE_PROFILE] =
+ g_param_spec_object ("active-profile",
+ "Active profile",
+ "The currently active profile of the device",
+ MATE_MIXER_TYPE_DEVICE_PROFILE,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS);
+
+ g_object_class_install_properties (object_class, N_PROPERTIES, properties);
+
+ signals[STREAM_ADDED] =
+ g_signal_new ("stream-added",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (MateMixerDeviceClass, stream_added),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__STRING,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_STRING);
+
+ signals[STREAM_REMOVED] =
+ g_signal_new ("stream-removed",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (MateMixerDeviceClass, stream_removed),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__STRING,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_STRING);
+
+ signals[SWITCH_ADDED] =
+ g_signal_new ("switch-added",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (MateMixerDeviceClass, switch_added),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__STRING,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_STRING);
+
+ signals[SWITCH_REMOVED] =
+ g_signal_new ("switch-removed",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (MateMixerDeviceClass, switch_removed),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__STRING,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_STRING);
+
+ g_type_class_add_private (object_class, sizeof (MateMixerDevicePrivate));
+}
+
+static void
+mate_mixer_device_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ MateMixerDevice *device;
+
+ device = MATE_MIXER_DEVICE (object);
+
+ switch (param_id) {
+ case PROP_NAME:
+ g_value_set_string (value, device->priv->name);
+ break;
+ case PROP_LABEL:
+ g_value_set_string (value, device->priv->label);
+ break;
+ case PROP_ICON:
+ g_value_set_string (value, device->priv->icon);
+ break;
+ case PROP_ACTIVE_PROFILE:
+ g_value_set_object (value, device->priv->profile);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ }
+}
+
+static void
+mate_mixer_device_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ MateMixerDevice *device;
+
+ device = MATE_MIXER_DEVICE (object);
+
+ switch (param_id) {
+ case PROP_NAME:
+ /* Construct-only string */
+ device->priv->name = g_strdup (g_value_get_string (value));
+ break;
+ case PROP_LABEL:
+ /* Construct-only string */
+ device->priv->label = g_strdup (g_value_get_string (value));
+ break;
+ case PROP_ICON:
+ /* Construct-only string */
+ device->priv->icon = g_strdup (g_value_get_string (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ }
+}
static void
-mate_mixer_device_default_init (MateMixerDeviceInterface *iface)
-{
- g_object_interface_install_property (iface,
- g_param_spec_string ("name",
- "Name",
- "Name of the device",
- NULL,
- G_PARAM_READABLE |
- G_PARAM_STATIC_STRINGS));
-
- g_object_interface_install_property (iface,
- g_param_spec_string ("description",
- "Description",
- "Description of the device",
- NULL,
- G_PARAM_READABLE |
- G_PARAM_STATIC_STRINGS));
-
- g_object_interface_install_property (iface,
- g_param_spec_string ("icon",
- "Icon",
- "Name of the sound device icon",
- NULL,
- G_PARAM_READABLE |
- G_PARAM_STATIC_STRINGS));
-
- g_object_interface_install_property (iface,
- g_param_spec_object ("active-profile",
- "Active profile",
- "The currently active profile of the device",
- MATE_MIXER_TYPE_DEVICE_PROFILE,
- G_PARAM_READABLE |
- G_PARAM_STATIC_STRINGS));
+mate_mixer_device_init (MateMixerDevice *device)
+{
+ device->priv = G_TYPE_INSTANCE_GET_PRIVATE (device,
+ MATE_MIXER_TYPE_DEVICE,
+ MateMixerDevicePrivate);
+}
+
+static void
+mate_mixer_device_dispose (GObject *object)
+{
+ MateMixerDevice *device;
+
+ device = MATE_MIXER_DEVICE (object);
+
+ if (device->priv->streams != NULL) {
+ g_list_free_full (device->priv->streams, g_object_unref);
+ device->priv->streams = NULL;
+ }
+ if (device->priv->switches != NULL) {
+ g_list_free_full (device->priv->switches, g_object_unref);
+ device->priv->switches = NULL;
+ }
+ if (device->priv->profiles != NULL) {
+ g_list_free_full (device->priv->profiles, g_object_unref);
+ device->priv->profiles = NULL;
+ }
+
+ g_clear_object (&device->priv->profile);
+
+ G_OBJECT_CLASS (mate_mixer_device_parent_class)->dispose (object);
+}
+
+static void
+mate_mixer_device_finalize (GObject *object)
+{
+ MateMixerDevice *device;
+
+ device = MATE_MIXER_DEVICE (object);
+
+ g_free (device->priv->name);
+ g_free (device->priv->label);
+ g_free (device->priv->icon);
+
+ G_OBJECT_CLASS (mate_mixer_device_parent_class)->finalize (object);
}
/**
@@ -75,8 +305,7 @@ mate_mixer_device_get_name (MateMixerDevice *device)
{
g_return_val_if_fail (MATE_MIXER_IS_DEVICE (device), NULL);
- /* Implementation required */
- return MATE_MIXER_DEVICE_GET_INTERFACE (device)->get_name (device);
+ return device->priv->name;
}
/**
@@ -84,18 +313,11 @@ mate_mixer_device_get_name (MateMixerDevice *device)
* @device: a #MateMixerDevice
*/
const gchar *
-mate_mixer_device_get_description (MateMixerDevice *device)
+mate_mixer_device_get_label (MateMixerDevice *device)
{
- MateMixerDeviceInterface *iface;
-
g_return_val_if_fail (MATE_MIXER_IS_DEVICE (device), NULL);
- iface = MATE_MIXER_DEVICE_GET_INTERFACE (device);
-
- if (iface->get_description)
- return iface->get_description (device);
-
- return NULL;
+ return device->priv->label;
}
/**
@@ -105,77 +327,80 @@ mate_mixer_device_get_description (MateMixerDevice *device)
const gchar *
mate_mixer_device_get_icon (MateMixerDevice *device)
{
- MateMixerDeviceInterface *iface;
-
g_return_val_if_fail (MATE_MIXER_IS_DEVICE (device), NULL);
- iface = MATE_MIXER_DEVICE_GET_INTERFACE (device);
-
- if (iface->get_icon)
- return iface->get_icon (device);
-
- return NULL;
+ return device->priv->icon;
}
/**
- * mate_mixer_device_get_port:
+ * mate_mixer_device_get_profile:
* @device: a #MateMixerDevice
- * @name: a port name
+ * @name: a profile name
*/
-MateMixerPort *
-mate_mixer_device_get_port (MateMixerDevice *device, const gchar *name)
+MateMixerDeviceProfile *
+mate_mixer_device_get_profile (MateMixerDevice *device, const gchar *name)
{
- MateMixerDeviceInterface *iface;
-
- g_return_val_if_fail (MATE_MIXER_IS_DEVICE (device), NULL);
- g_return_val_if_fail (name != NULL, NULL);
-
- iface = MATE_MIXER_DEVICE_GET_INTERFACE (device);
-
- if (iface->get_port)
- return iface->get_port (device, name);
+ return MATE_MIXER_DEVICE_GET_CLASS (device)->get_profile (device, name);
+}
- return NULL;
+/**
+ * mate_mixer_device_get_stream:
+ * @device: a #MateMixerDevice
+ * @name: a profile name
+ */
+MateMixerStream *
+mate_mixer_device_get_stream (MateMixerDevice *device, const gchar *name)
+{
+ return MATE_MIXER_DEVICE_GET_CLASS (device)->get_stream (device, name);
}
/**
- * mate_mixer_device_get_profile:
+ * mate_mixer_device_get_switch:
* @device: a #MateMixerDevice
* @name: a profile name
*/
-MateMixerDeviceProfile *
-mate_mixer_device_get_profile (MateMixerDevice *device, const gchar *name)
+MateMixerSwitch *
+mate_mixer_device_get_switch (MateMixerDevice *device, const gchar *name)
{
- MateMixerDeviceInterface *iface;
+ return MATE_MIXER_DEVICE_GET_CLASS (device)->get_switch (device, name);
+}
+/**
+ * mate_mixer_device_list_streams:
+ * @device: a #MateMixerDevice
+ */
+const GList *
+mate_mixer_device_list_streams (MateMixerDevice *device)
+{
g_return_val_if_fail (MATE_MIXER_IS_DEVICE (device), NULL);
- g_return_val_if_fail (name != NULL, NULL);
- iface = MATE_MIXER_DEVICE_GET_INTERFACE (device);
+ if (device->priv->streams == NULL) {
+ MateMixerDeviceClass *klass = MATE_MIXER_DEVICE_GET_CLASS (device);
- if (iface->get_profile)
- return iface->get_profile (device, name);
+ if (klass->list_streams != NULL)
+ device->priv->streams = klass->list_streams (device);
+ }
- return NULL;
+ return (const GList *) device->priv->streams;
}
/**
- * mate_mixer_device_list_ports:
+ * mate_mixer_device_list_switches:
* @device: a #MateMixerDevice
*/
const GList *
-mate_mixer_device_list_ports (MateMixerDevice *device)
+mate_mixer_device_list_switches (MateMixerDevice *device)
{
- MateMixerDeviceInterface *iface;
-
g_return_val_if_fail (MATE_MIXER_IS_DEVICE (device), NULL);
- iface = MATE_MIXER_DEVICE_GET_INTERFACE (device);
+ if (device->priv->switches == NULL) {
+ MateMixerDeviceClass *klass = MATE_MIXER_DEVICE_GET_CLASS (device);
- if (iface->list_ports)
- return iface->list_ports (device);
+ if (klass->list_switches != NULL)
+ device->priv->switches = klass->list_switches (device);
+ }
- return NULL;
+ return (const GList *) device->priv->switches;
}
/**
@@ -185,16 +410,16 @@ mate_mixer_device_list_ports (MateMixerDevice *device)
const GList *
mate_mixer_device_list_profiles (MateMixerDevice *device)
{
- MateMixerDeviceInterface *iface;
-
g_return_val_if_fail (MATE_MIXER_IS_DEVICE (device), NULL);
- iface = MATE_MIXER_DEVICE_GET_INTERFACE (device);
+ if (device->priv->profiles == NULL) {
+ MateMixerDeviceClass *klass = MATE_MIXER_DEVICE_GET_CLASS (device);
- if (iface->list_profiles)
- return iface->list_profiles (device);
+ if (klass->list_profiles != NULL)
+ device->priv->profiles = klass->list_profiles (device);
+ }
- return NULL;
+ return (const GList *) device->priv->profiles;
}
/**
@@ -204,16 +429,9 @@ mate_mixer_device_list_profiles (MateMixerDevice *device)
MateMixerDeviceProfile *
mate_mixer_device_get_active_profile (MateMixerDevice *device)
{
- MateMixerDeviceInterface *iface;
-
g_return_val_if_fail (MATE_MIXER_IS_DEVICE (device), NULL);
- iface = MATE_MIXER_DEVICE_GET_INTERFACE (device);
-
- if (iface->get_active_profile)
- return iface->get_active_profile (device);
-
- return NULL;
+ return device->priv->profile;
}
/**
@@ -225,15 +443,83 @@ gboolean
mate_mixer_device_set_active_profile (MateMixerDevice *device,
MateMixerDeviceProfile *profile)
{
- MateMixerDeviceInterface *iface;
-
g_return_val_if_fail (MATE_MIXER_IS_DEVICE (device), FALSE);
g_return_val_if_fail (MATE_MIXER_IS_DEVICE_PROFILE (profile), FALSE);
- iface = MATE_MIXER_DEVICE_GET_INTERFACE (device);
+ if (profile != device->priv->profile) {
+ MateMixerDeviceClass *klass;
+
+ klass = MATE_MIXER_DEVICE_GET_CLASS (device);
+
+ if (klass->set_active_profile == NULL ||
+ klass->set_active_profile (device, profile) == FALSE)
+ return FALSE;
- if (iface->set_active_profile)
- return iface->set_active_profile (device, profile);
+ if (G_LIKELY (device->priv->profile != NULL))
+ g_object_unref (device->priv->profile);
- return FALSE;
+ device->priv->profile = g_object_ref (profile);
+ }
+
+ return TRUE;
+}
+
+static MateMixerStream *
+mate_mixer_device_real_get_stream (MateMixerDevice *device, const gchar *name)
+{
+ const GList *list;
+
+ g_return_val_if_fail (MATE_MIXER_IS_DEVICE (device), NULL);
+ g_return_val_if_fail (name != NULL, NULL);
+
+ list = mate_mixer_device_list_streams (device);
+ while (list != NULL) {
+ MateMixerStream *stream = MATE_MIXER_STREAM (list->data);
+
+ if (strcmp (name, mate_mixer_stream_get_name (stream)) == 0)
+ return stream;
+
+ list = list->next;
+ }
+ return NULL;
+}
+
+static MateMixerSwitch *
+mate_mixer_device_real_get_switch (MateMixerDevice *device, const gchar *name)
+{
+ const GList *list;
+
+ g_return_val_if_fail (MATE_MIXER_IS_DEVICE (device), NULL);
+ g_return_val_if_fail (name != NULL, NULL);
+
+ list = mate_mixer_device_list_switches (device);
+ while (list != NULL) {
+ MateMixerSwitch *swtch = MATE_MIXER_SWITCH (list->data);
+
+ if (strcmp (name, mate_mixer_switch_get_name (swtch)) == 0)
+ return swtch;
+
+ list = list->next;
+ }
+ return NULL;
+}
+
+static MateMixerDeviceProfile *
+mate_mixer_device_real_get_profile (MateMixerDevice *device, const gchar *name)
+{
+ const GList *list;
+
+ g_return_val_if_fail (MATE_MIXER_IS_DEVICE (device), NULL);
+ g_return_val_if_fail (name != NULL, NULL);
+
+ list = mate_mixer_device_list_profiles (device);
+ while (list != NULL) {
+ MateMixerDeviceProfile *profile = MATE_MIXER_DEVICE_PROFILE (list->data);
+
+ if (strcmp (name, mate_mixer_device_profile_get_name (profile)) == 0)
+ return profile;
+
+ list = list->next;
+ }
+ return NULL;
}
diff --git a/libmatemixer/matemixer-device.h b/libmatemixer/matemixer-device.h
index 340496b..885460c 100644
--- a/libmatemixer/matemixer-device.h
+++ b/libmatemixer/matemixer-device.h
@@ -21,8 +21,7 @@
#include <glib.h>
#include <glib-object.h>
-#include <libmatemixer/matemixer-device-profile.h>
-#include <libmatemixer/matemixer-port.h>
+#include "matemixer-types.h"
G_BEGIN_DECLS
@@ -32,48 +31,72 @@ G_BEGIN_DECLS
(G_TYPE_CHECK_INSTANCE_CAST ((o), MATE_MIXER_TYPE_DEVICE, MateMixerDevice))
#define MATE_MIXER_IS_DEVICE(o) \
(G_TYPE_CHECK_INSTANCE_TYPE ((o), MATE_MIXER_TYPE_DEVICE))
-#define MATE_MIXER_DEVICE_GET_INTERFACE(o) \
- (G_TYPE_INSTANCE_GET_INTERFACE ((o), MATE_MIXER_TYPE_DEVICE, MateMixerDeviceInterface))
+#define MATE_MIXER_DEVICE_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_CAST ((k), MATE_MIXER_TYPE_DEVICE, MateMixerDeviceClass))
+#define MATE_MIXER_IS_DEVICE_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_TYPE ((k), MATE_MIXER_TYPE_DEVICE))
+#define MATE_MIXER_DEVICE_GET_CLASS(o) \
+ (G_TYPE_INSTANCE_GET_CLASS ((o), MATE_MIXER_TYPE_DEVICE, MateMixerDeviceClass))
-typedef struct _MateMixerDevice MateMixerDevice; /* dummy object */
-typedef struct _MateMixerDeviceInterface MateMixerDeviceInterface;
+typedef struct _MateMixerDeviceClass MateMixerDeviceClass;
+typedef struct _MateMixerDevicePrivate MateMixerDevicePrivate;
-struct _MateMixerDeviceInterface
+struct _MateMixerDevice
{
- GTypeInterface parent_iface;
+ GObject object;
+
+ /*< private >*/
+ MateMixerDevicePrivate *priv;
+};
+
+struct _MateMixerDeviceClass
+{
+ GObjectClass parent_class;
/*< private >*/
- /* Virtual table */
- const gchar *(*get_name) (MateMixerDevice *device);
- const gchar *(*get_description) (MateMixerDevice *device);
- const gchar *(*get_icon) (MateMixerDevice *device);
- MateMixerPort *(*get_port) (MateMixerDevice *device,
+ MateMixerStream *(*get_stream) (MateMixerDevice *device,
+ const gchar *name);
+ MateMixerSwitch *(*get_switch) (MateMixerDevice *device,
const gchar *name);
MateMixerDeviceProfile *(*get_profile) (MateMixerDevice *device,
const gchar *name);
- const GList *(*list_streams) (MateMixerDevice *device);
- const GList *(*list_ports) (MateMixerDevice *device);
- const GList *(*list_profiles) (MateMixerDevice *device);
+ GList *(*list_streams) (MateMixerDevice *device);
+ GList *(*list_switches) (MateMixerDevice *device);
+ GList *(*list_profiles) (MateMixerDevice *device);
- MateMixerDeviceProfile *(*get_active_profile) (MateMixerDevice *device);
gboolean (*set_active_profile) (MateMixerDevice *device,
MateMixerDeviceProfile *profile);
+
+ /* Signals */
+ void (*stream_added) (MateMixerDevice *device,
+ const gchar *name);
+ void (*stream_removed) (MateMixerDevice *device,
+ const gchar *name);
+ void (*switch_added) (MateMixerDevice *device,
+ const gchar *name);
+ void (*switch_removed) (MateMixerDevice *device,
+ const gchar *name);
};
GType mate_mixer_device_get_type (void) G_GNUC_CONST;
const gchar * mate_mixer_device_get_name (MateMixerDevice *device);
-const gchar * mate_mixer_device_get_description (MateMixerDevice *device);
+const gchar * mate_mixer_device_get_label (MateMixerDevice *device);
const gchar * mate_mixer_device_get_icon (MateMixerDevice *device);
-MateMixerPort * mate_mixer_device_get_port (MateMixerDevice *device,
+MateMixerStream * mate_mixer_device_get_stream (MateMixerDevice *device,
const gchar *name);
+
+MateMixerSwitch * mate_mixer_device_get_switch (MateMixerDevice *device,
+ const gchar *name);
+
MateMixerDeviceProfile *mate_mixer_device_get_profile (MateMixerDevice *device,
const gchar *name);
-const GList * mate_mixer_device_list_ports (MateMixerDevice *device);
+const GList * mate_mixer_device_list_streams (MateMixerDevice *device);
+const GList * mate_mixer_device_list_switches (MateMixerDevice *device);
const GList * mate_mixer_device_list_profiles (MateMixerDevice *device);
MateMixerDeviceProfile *mate_mixer_device_get_active_profile (MateMixerDevice *device);
diff --git a/libmatemixer/matemixer-enum-types.c b/libmatemixer/matemixer-enum-types.c
index 339b673..035be3d 100644
--- a/libmatemixer/matemixer-enum-types.c
+++ b/libmatemixer/matemixer-enum-types.c
@@ -94,14 +94,7 @@ mate_mixer_stream_flags_get_type (void)
{ MATE_MIXER_STREAM_INPUT, "MATE_MIXER_STREAM_INPUT", "input" },
{ MATE_MIXER_STREAM_OUTPUT, "MATE_MIXER_STREAM_OUTPUT", "output" },
{ MATE_MIXER_STREAM_CLIENT, "MATE_MIXER_STREAM_CLIENT", "client" },
- { MATE_MIXER_STREAM_HAS_MUTE, "MATE_MIXER_STREAM_HAS_MUTE", "has-mute" },
- { MATE_MIXER_STREAM_HAS_VOLUME, "MATE_MIXER_STREAM_HAS_VOLUME", "has-volume" },
- { MATE_MIXER_STREAM_HAS_DECIBEL_VOLUME, "MATE_MIXER_STREAM_HAS_DECIBEL_VOLUME", "has-decibel-volume" },
- { MATE_MIXER_STREAM_HAS_FLAT_VOLUME, "MATE_MIXER_STREAM_HAS_FLAT_VOLUME", "has-flat-volume" },
{ MATE_MIXER_STREAM_HAS_MONITOR, "MATE_MIXER_STREAM_HAS_MONITOR", "has-monitor" },
- { MATE_MIXER_STREAM_CAN_SET_VOLUME, "MATE_MIXER_STREAM_CAN_SET_VOLUME", "can-set-volume" },
- { MATE_MIXER_STREAM_CAN_BALANCE, "MATE_MIXER_STREAM_CAN_BALANCE", "can-balance" },
- { MATE_MIXER_STREAM_CAN_FADE, "MATE_MIXER_STREAM_CAN_FADE", "can-fade" },
{ MATE_MIXER_STREAM_CAN_SUSPEND, "MATE_MIXER_STREAM_CAN_SUSPEND", "can-suspend" },
{ 0, NULL, NULL }
};
@@ -133,6 +126,54 @@ mate_mixer_stream_state_get_type (void)
}
GType
+mate_mixer_stream_control_flags_get_type (void)
+{
+ static GType etype = 0;
+
+ if (etype == 0) {
+ static const GFlagsValue values[] = {
+ { MATE_MIXER_STREAM_CONTROL_NO_FLAGS, "MATE_MIXER_STREAM_CONTROL_NO_FLAGS", "no-flags" },
+ { MATE_MIXER_STREAM_CONTROL_HAS_MUTE, "MATE_MIXER_STREAM_CONTROL_HAS_MUTE", "has-mute" },
+ { MATE_MIXER_STREAM_CONTROL_HAS_VOLUME, "MATE_MIXER_STREAM_CONTROL_HAS_VOLUME", "has-volume" },
+ { MATE_MIXER_STREAM_CONTROL_HAS_DECIBEL, "MATE_MIXER_STREAM_CONTROL_HAS_DECIBEL", "has-decibel" },
+ { MATE_MIXER_STREAM_CONTROL_HAS_FLAT_VOLUME, "MATE_MIXER_STREAM_CONTROL_HAS_FLAT_VOLUME", "has-flat-volume" },
+ { MATE_MIXER_STREAM_CONTROL_CAN_SET_VOLUME, "MATE_MIXER_STREAM_CONTROL_CAN_SET_VOLUME", "can-set-volume" },
+ { MATE_MIXER_STREAM_CONTROL_CAN_BALANCE, "MATE_MIXER_STREAM_CONTROL_CAN_BALANCE", "can-balance" },
+ { MATE_MIXER_STREAM_CONTROL_CAN_FADE, "MATE_MIXER_STREAM_CONTROL_CAN_FADE", "can-fade" },
+ { 0, NULL, NULL }
+ };
+ etype = g_flags_register_static (
+ g_intern_static_string ("MateMixerStreamControlFlags"),
+ values);
+ }
+ return etype;
+}
+
+GType
+mate_mixer_stream_control_role_get_type (void)
+{
+ static GType etype = 0;
+
+ if (etype == 0) {
+ static const GEnumValue values[] = {
+ { MATE_MIXER_STREAM_CONTROL_ROLE_UNKNOWN, "MATE_MIXER_STREAM_CONTROL_ROLE_UNKNOWN", "unknown" },
+ { MATE_MIXER_STREAM_CONTROL_ROLE_MASTER, "MATE_MIXER_STREAM_CONTROL_ROLE_MASTER", "master" },
+ { MATE_MIXER_STREAM_CONTROL_ROLE_PORT, "MATE_MIXER_STREAM_CONTROL_ROLE_PORT", "port" },
+ { MATE_MIXER_STREAM_CONTROL_ROLE_PCM, "MATE_MIXER_STREAM_CONTROL_ROLE_PCM", "pcm" },
+ { MATE_MIXER_STREAM_CONTROL_ROLE_BASS, "MATE_MIXER_STREAM_CONTROL_ROLE_BASS", "bass" },
+ { MATE_MIXER_STREAM_CONTROL_ROLE_TREBLE, "MATE_MIXER_STREAM_CONTROL_ROLE_TREBLE", "treble" },
+ { MATE_MIXER_STREAM_CONTROL_ROLE_CD, "MATE_MIXER_STREAM_CONTROL_ROLE_CD", "cd" },
+ { MATE_MIXER_STREAM_CONTROL_ROLE_SPEAKER, "MATE_MIXER_STREAM_CONTROL_ROLE_SPEAKER", "speaker" },
+ { 0, NULL, NULL }
+ };
+ etype = g_enum_register_static (
+ g_intern_static_string ("MateMixerStreamControlRole"),
+ values);
+ }
+ return etype;
+}
+
+GType
mate_mixer_client_stream_flags_get_type (void)
{
static GType etype = 0;
diff --git a/libmatemixer/matemixer-enum-types.h b/libmatemixer/matemixer-enum-types.h
index 03c1297..f2193be 100644
--- a/libmatemixer/matemixer-enum-types.h
+++ b/libmatemixer/matemixer-enum-types.h
@@ -43,6 +43,12 @@ GType mate_mixer_stream_flags_get_type (void) G_GNUC_CONST;
#define MATE_MIXER_TYPE_STREAM_STATE (mate_mixer_stream_state_get_type ())
GType mate_mixer_stream_state_get_type (void) G_GNUC_CONST;
+#define MATE_MIXER_TYPE_STREAM_CONTROL_FLAGS (mate_mixer_stream_control_flags_get_type ())
+GType mate_mixer_stream_control_flags_get_type (void) G_GNUC_CONST;
+
+#define MATE_MIXER_TYPE_STREAM_CONTROL_ROLE (mate_mixer_stream_control_role_get_type ())
+GType mate_mixer_stream_control_role_get_type (void);
+
#define MATE_MIXER_TYPE_CLIENT_STREAM_FLAGS (mate_mixer_client_stream_flags_get_type ())
GType mate_mixer_client_stream_flags_get_type (void) G_GNUC_CONST;
diff --git a/libmatemixer/matemixer-enums.h b/libmatemixer/matemixer-enums.h
index a6326ce..8a88b1c 100644
--- a/libmatemixer/matemixer-enums.h
+++ b/libmatemixer/matemixer-enums.h
@@ -47,6 +47,8 @@ typedef enum {
* PulseAudio sound system backend. It has the highest priority and
* will be the first one to try unless you select a specific backend
* to connect to.
+ * @MATE_MIXER_BACKEND_ALSA:
+ * @MATE_MIXER_BACKEND_OSS:
* @MATE_MIXER_BACKEND_NULL:
* Fallback backend which never fails to initialize, but provides no
* functionality. This backend has the lowest priority and will be used
@@ -56,9 +58,17 @@ typedef enum {
typedef enum {
MATE_MIXER_BACKEND_UNKNOWN,
MATE_MIXER_BACKEND_PULSEAUDIO,
+ MATE_MIXER_BACKEND_ALSA,
+ MATE_MIXER_BACKEND_OSS,
MATE_MIXER_BACKEND_NULL
} MateMixerBackendType;
+typedef enum { /*< flags >*/
+ MATE_MIXER_BACKEND_NO_FLAGS = 0,
+ MATE_MIXER_BACKEND_CAN_SET_DEFAULT_INPUT_STREAM,
+ MATE_MIXER_BACKEND_CAN_SET_DEFAULT_OUTPUT_STREAM
+} MateMixerBackendFlags;
+
/**
* MateMixerPortFlags:
* @MATE_MIXER_PORT_NO_FLAGS:
@@ -79,14 +89,7 @@ typedef enum { /*< flags >*/
* @MATE_MIXER_STREAM_INPUT:
* @MATE_MIXER_STREAM_OUTPUT:
* @MATE_MIXER_STREAM_CLIENT:
- * @MATE_MIXER_STREAM_HAS_MUTE:
- * @MATE_MIXER_STREAM_HAS_VOLUME:
- * @MATE_MIXER_STREAM_HAS_DECIBEL_VOLUME:
- * @MATE_MIXER_STREAM_HAS_FLAT_VOLUME:
* @MATE_MIXER_STREAM_HAS_MONITOR:
- * @MATE_MIXER_STREAM_CAN_SET_VOLUME:
- * @MATE_MIXER_STREAM_CAN_BALANCE:
- * @MATE_MIXER_STREAM_CAN_FADE:
* @MATE_MIXER_STREAM_CAN_SUSPEND:
*/
typedef enum { /*< flags >*/
@@ -94,15 +97,10 @@ typedef enum { /*< flags >*/
MATE_MIXER_STREAM_INPUT = 1 << 0,
MATE_MIXER_STREAM_OUTPUT = 1 << 1,
MATE_MIXER_STREAM_CLIENT = 1 << 2,
- MATE_MIXER_STREAM_HAS_MUTE = 1 << 3,
- MATE_MIXER_STREAM_HAS_VOLUME = 1 << 4,
- MATE_MIXER_STREAM_HAS_DECIBEL_VOLUME = 1 << 5,
- MATE_MIXER_STREAM_HAS_FLAT_VOLUME = 1 << 6,
- MATE_MIXER_STREAM_HAS_MONITOR = 1 << 7,
- MATE_MIXER_STREAM_CAN_SET_VOLUME = 1 << 8,
- MATE_MIXER_STREAM_CAN_BALANCE = 1 << 9,
- MATE_MIXER_STREAM_CAN_FADE = 1 << 10,
- MATE_MIXER_STREAM_CAN_SUSPEND = 1 << 11
+ MATE_MIXER_STREAM_HAS_MONITOR = 1 << 3,
+ MATE_MIXER_STREAM_CAN_SUSPEND = 1 << 4,
+ MATE_MIXER_STREAM_PORTS_FIXED = 1 << 5,
+ MATE_MIXER_STREAM_PORTS_EXCLUSIVE = 1 << 6,
} MateMixerStreamFlags;
/**
@@ -120,6 +118,40 @@ typedef enum {
} MateMixerStreamState;
/**
+ * MateMixerStreamControlFlags:
+ * @MATE_MIXER_STREAM_CONTROL_NO_FLAGS:
+ * @MATE_MIXER_STREAM_CONTROL_HAS_MUTE:
+ * @MATE_MIXER_STREAM_CONTROL_HAS_VOLUME:
+ * @MATE_MIXER_STREAM_CONTROL_HAS_DECIBEL:
+ * @MATE_MIXER_STREAM_CONTROL_HAS_FLAT_VOLUME:
+ * @MATE_MIXER_STREAM_CONTROL_CAN_SET_VOLUME:
+ * @MATE_MIXER_STREAM_CONTROL_CAN_BALANCE:
+ * @MATE_MIXER_STREAM_CONTROL_CAN_FADE:
+ */
+typedef enum {
+ MATE_MIXER_STREAM_CONTROL_NO_FLAGS = 0,
+ MATE_MIXER_STREAM_CONTROL_HAS_MUTE = 1 << 0,
+ MATE_MIXER_STREAM_CONTROL_HAS_VOLUME = 1 << 1,
+ MATE_MIXER_STREAM_CONTROL_HAS_DECIBEL = 1 << 2,
+ MATE_MIXER_STREAM_CONTROL_HAS_FLAT_VOLUME = 1 << 3,
+ MATE_MIXER_STREAM_CONTROL_CAN_SET_MUTE = 1 << 4,
+ MATE_MIXER_STREAM_CONTROL_CAN_SET_VOLUME = 1 << 5,
+ MATE_MIXER_STREAM_CONTROL_CAN_BALANCE = 1 << 6,
+ MATE_MIXER_STREAM_CONTROL_CAN_FADE = 1 << 7
+} MateMixerStreamControlFlags;
+
+typedef enum {
+ MATE_MIXER_STREAM_CONTROL_ROLE_UNKNOWN,
+ MATE_MIXER_STREAM_CONTROL_ROLE_MASTER,
+ MATE_MIXER_STREAM_CONTROL_ROLE_PORT,
+ MATE_MIXER_STREAM_CONTROL_ROLE_PCM,
+ MATE_MIXER_STREAM_CONTROL_ROLE_BASS,
+ MATE_MIXER_STREAM_CONTROL_ROLE_TREBLE,
+ MATE_MIXER_STREAM_CONTROL_ROLE_CD,
+ MATE_MIXER_STREAM_CONTROL_ROLE_SPEAKER,
+} MateMixerStreamControlRole;
+
+/**
* MateMixerClientStreamFlags:
* @MATE_MIXER_CLIENT_STREAM_NO_FLAGS:
* @MATE_MIXER_CLIENT_STREAM_APPLICATION:
@@ -185,7 +217,7 @@ typedef enum {
* @MATE_MIXER_CHANNEL_TOP_BACK_CENTER:
*/
typedef enum {
- MATE_MIXER_CHANNEL_UNKNOWN,
+ MATE_MIXER_CHANNEL_UNKNOWN = 0,
MATE_MIXER_CHANNEL_MONO,
MATE_MIXER_CHANNEL_FRONT_LEFT,
MATE_MIXER_CHANNEL_FRONT_RIGHT,
@@ -204,7 +236,8 @@ typedef enum {
MATE_MIXER_CHANNEL_TOP_CENTER,
MATE_MIXER_CHANNEL_TOP_BACK_LEFT,
MATE_MIXER_CHANNEL_TOP_BACK_RIGHT,
- MATE_MIXER_CHANNEL_TOP_BACK_CENTER
+ MATE_MIXER_CHANNEL_TOP_BACK_CENTER,
+ MATE_MIXER_CHANNEL_MAX
} MateMixerChannelPosition;
#endif /* MATEMIXER_ENUMS_H */
diff --git a/libmatemixer/matemixer-port-private.h b/libmatemixer/matemixer-port-private.h
deleted file mode 100644
index a696d27..0000000
--- a/libmatemixer/matemixer-port-private.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2014 Michal Ratajsky <[email protected]>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the licence, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef MATEMIXER_PORT_PRIVATE_H
-#define MATEMIXER_PORT_PRIVATE_H
-
-#include <glib.h>
-
-#include "matemixer-enums.h"
-#include "matemixer-port.h"
-
-G_BEGIN_DECLS
-
-MateMixerPort *_mate_mixer_port_new (const gchar *name,
- const gchar *description,
- const gchar *icon,
- guint priority,
- MateMixerPortFlags flags);
-
-gboolean _mate_mixer_port_update_description (MateMixerPort *port,
- const gchar *description);
-gboolean _mate_mixer_port_update_icon (MateMixerPort *port,
- const gchar *icon);
-gboolean _mate_mixer_port_update_priority (MateMixerPort *port,
- guint priority);
-gboolean _mate_mixer_port_update_flags (MateMixerPort *port,
- MateMixerPortFlags flags);
-
-G_END_DECLS
-
-#endif /* MATEMIXER_PORT_PRIVATE_H */
diff --git a/libmatemixer/matemixer-port.c b/libmatemixer/matemixer-port.c
deleted file mode 100644
index f89a8bb..0000000
--- a/libmatemixer/matemixer-port.c
+++ /dev/null
@@ -1,358 +0,0 @@
-/*
- * Copyright (C) 2014 Michal Ratajsky <[email protected]>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the licence, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <glib.h>
-#include <glib-object.h>
-
-#include "matemixer-enums.h"
-#include "matemixer-enum-types.h"
-#include "matemixer-port.h"
-#include "matemixer-port-private.h"
-
-/**
- * SECTION:matemixer-port
- * @include: libmatemixer/matemixer.h
- */
-
-struct _MateMixerPortPrivate
-{
- gchar *name;
- gchar *description;
- gchar *icon;
- guint priority;
- MateMixerPortFlags flags;
-};
-
-enum {
- PROP_0,
- PROP_NAME,
- PROP_DESCRIPTION,
- PROP_ICON,
- PROP_PRIORITY,
- PROP_FLAGS,
- N_PROPERTIES
-};
-
-static GParamSpec *properties[N_PROPERTIES] = { NULL, };
-
-static void mate_mixer_port_class_init (MateMixerPortClass *klass);
-
-static void mate_mixer_port_get_property (GObject *object,
- guint param_id,
- GValue *value,
- GParamSpec *pspec);
-static void mate_mixer_port_set_property (GObject *object,
- guint param_id,
- const GValue *value,
- GParamSpec *pspec);
-
-static void mate_mixer_port_init (MateMixerPort *port);
-static void mate_mixer_port_finalize (GObject *object);
-
-G_DEFINE_TYPE (MateMixerPort, mate_mixer_port, G_TYPE_OBJECT);
-
-static void
-mate_mixer_port_class_init (MateMixerPortClass *klass)
-{
- GObjectClass *object_class;
-
- object_class = G_OBJECT_CLASS (klass);
- object_class->finalize = mate_mixer_port_finalize;
- object_class->get_property = mate_mixer_port_get_property;
- object_class->set_property = mate_mixer_port_set_property;
-
- properties[PROP_NAME] =
- g_param_spec_string ("name",
- "Name",
- "Name of the port",
- NULL,
- G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_READWRITE |
- G_PARAM_STATIC_STRINGS);
-
- properties[PROP_DESCRIPTION] =
- g_param_spec_string ("description",
- "Description",
- "Description of the port",
- NULL,
- G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_READWRITE |
- G_PARAM_STATIC_STRINGS);
-
- properties[PROP_ICON] =
- g_param_spec_string ("icon",
- "Icon",
- "Name of the port icon",
- NULL,
- G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_READWRITE |
- G_PARAM_STATIC_STRINGS);
-
- properties[PROP_PRIORITY] =
- g_param_spec_uint ("priority",
- "Priority",
- "Priority of the port",
- 0,
- G_MAXUINT,
- 0,
- G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_READWRITE |
- G_PARAM_STATIC_STRINGS);
-
- properties[PROP_FLAGS] =
- g_param_spec_flags ("flags",
- "Flags",
- "Capability flags of the port",
- MATE_MIXER_TYPE_PORT_FLAGS,
- MATE_MIXER_PORT_NO_FLAGS,
- G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_READWRITE |
- G_PARAM_STATIC_STRINGS);
-
- g_object_class_install_properties (object_class, N_PROPERTIES, properties);
-
- g_type_class_add_private (object_class, sizeof (MateMixerPortPrivate));
-}
-
-static void
-mate_mixer_port_get_property (GObject *object,
- guint param_id,
- GValue *value,
- GParamSpec *pspec)
-{
- MateMixerPort *port;
-
- port = MATE_MIXER_PORT (object);
-
- switch (param_id) {
- case PROP_NAME:
- g_value_set_string (value, port->priv->name);
- break;
- case PROP_DESCRIPTION:
- g_value_set_string (value, port->priv->description);
- break;
- case PROP_ICON:
- g_value_set_string (value, port->priv->icon);
- break;
- case PROP_PRIORITY:
- g_value_set_uint (value, port->priv->priority);
- break;
- case PROP_FLAGS:
- g_value_set_flags (value, port->priv->flags);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
- break;
- }
-}
-
-static void
-mate_mixer_port_set_property (GObject *object,
- guint param_id,
- const GValue *value,
- GParamSpec *pspec)
-{
- MateMixerPort *port;
-
- port = MATE_MIXER_PORT (object);
-
- switch (param_id) {
- case PROP_NAME:
- /* Construct-only string */
- port->priv->name = g_strdup (g_value_get_string (value));
- break;
- case PROP_DESCRIPTION:
- /* Construct-only string */
- port->priv->description = g_strdup (g_value_get_string (value));
- break;
- case PROP_ICON:
- /* Construct-only string */
- port->priv->icon = g_strdup (g_value_get_string (value));
- break;
- case PROP_PRIORITY:
- port->priv->priority = g_value_get_uint (value);
- break;
- case PROP_FLAGS:
- port->priv->flags = g_value_get_flags (value);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
- break;
- }
-}
-
-static void
-mate_mixer_port_init (MateMixerPort *port)
-{
- port->priv = G_TYPE_INSTANCE_GET_PRIVATE (port,
- MATE_MIXER_TYPE_PORT,
- MateMixerPortPrivate);
-}
-
-static void
-mate_mixer_port_finalize (GObject *object)
-{
- MateMixerPort *port;
-
- port = MATE_MIXER_PORT (object);
-
- g_free (port->priv->name);
- g_free (port->priv->description);
- g_free (port->priv->icon);
-
- G_OBJECT_CLASS (mate_mixer_port_parent_class)->finalize (object);
-}
-
-/**
- * mate_mixer_port_get_name:
- * @port: a #MateMixerPort
- */
-const gchar *
-mate_mixer_port_get_name (MateMixerPort *port)
-{
- g_return_val_if_fail (MATE_MIXER_IS_PORT (port), NULL);
-
- return port->priv->name;
-}
-
-/**
- * mate_mixer_port_get_description:
- * @port: a #MateMixerPort
- */
-const gchar *
-mate_mixer_port_get_description (MateMixerPort *port)
-{
- g_return_val_if_fail (MATE_MIXER_IS_PORT (port), NULL);
-
- return port->priv->description;
-}
-
-/**
- * mate_mixer_port_get_icon:
- * @port: a #MateMixerPort
- */
-const gchar *
-mate_mixer_port_get_icon (MateMixerPort *port)
-{
- g_return_val_if_fail (MATE_MIXER_IS_PORT (port), NULL);
-
- return port->priv->icon;
-}
-
-/**
- * mate_mixer_port_get_priority:
- * @port: a #MateMixerPort
- */
-guint
-mate_mixer_port_get_priority (MateMixerPort *port)
-{
- g_return_val_if_fail (MATE_MIXER_IS_PORT (port), 0);
-
- return port->priv->priority;
-}
-
-/**
- * mate_mixer_port_get_flags:
- * @port: a #MateMixerPort
- */
-MateMixerPortFlags
-mate_mixer_port_get_flags (MateMixerPort *port)
-{
- g_return_val_if_fail (MATE_MIXER_IS_PORT (port), MATE_MIXER_PORT_NO_FLAGS);
-
- return port->priv->flags;
-}
-
-MateMixerPort *
-_mate_mixer_port_new (const gchar *name,
- const gchar *description,
- const gchar *icon,
- guint priority,
- MateMixerPortFlags flags)
-{
- return g_object_new (MATE_MIXER_TYPE_PORT,
- "name", name,
- "description", description,
- "icon", icon,
- "priority", priority,
- "flags", flags,
- NULL);
-}
-
-gboolean
-_mate_mixer_port_update_description (MateMixerPort *port, const gchar *description)
-{
- g_return_val_if_fail (MATE_MIXER_IS_PORT (port), FALSE);
-
- if (g_strcmp0 (port->priv->description, description) != 0) {
- g_free (port->priv->description);
-
- port->priv->description = g_strdup (description);
-
- g_object_notify_by_pspec (G_OBJECT (port), properties[PROP_DESCRIPTION]);
- return TRUE;
- }
-
- return FALSE;
-}
-
-gboolean
-_mate_mixer_port_update_icon (MateMixerPort *port, const gchar *icon)
-{
- g_return_val_if_fail (MATE_MIXER_IS_PORT (port), FALSE);
-
- if (g_strcmp0 (port->priv->icon, icon) != 0) {
- g_free (port->priv->icon);
-
- port->priv->icon = g_strdup (icon);
-
- g_object_notify_by_pspec (G_OBJECT (port), properties[PROP_ICON]);
- return TRUE;
- }
-
- return FALSE;
-}
-
-gboolean
-_mate_mixer_port_update_priority (MateMixerPort *port, guint priority)
-{
- g_return_val_if_fail (MATE_MIXER_IS_PORT (port), FALSE);
-
- if (port->priv->priority != priority) {
- port->priv->priority = priority;
-
- g_object_notify_by_pspec (G_OBJECT (port), properties[PROP_PRIORITY]);
- return TRUE;
- }
-
- return FALSE;
-}
-
-gboolean
-_mate_mixer_port_update_flags (MateMixerPort *port, MateMixerPortFlags flags)
-{
- g_return_val_if_fail (MATE_MIXER_IS_PORT (port), FALSE);
-
- if (port->priv->flags != flags) {
- port->priv->flags = flags;
-
- g_object_notify_by_pspec (G_OBJECT (port), properties[PROP_FLAGS]);
- return TRUE;
- }
-
- return FALSE;
-}
diff --git a/libmatemixer/matemixer-port.h b/libmatemixer/matemixer-port.h
deleted file mode 100644
index 61f16f5..0000000
--- a/libmatemixer/matemixer-port.h
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2014 Michal Ratajsky <[email protected]>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the licence, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef MATEMIXER_PORT_H
-#define MATEMIXER_PORT_H
-
-#include <glib.h>
-#include <glib-object.h>
-
-#include <libmatemixer/matemixer-enums.h>
-
-G_BEGIN_DECLS
-
-#define MATE_MIXER_TYPE_PORT \
- (mate_mixer_port_get_type ())
-#define MATE_MIXER_PORT(o) \
- (G_TYPE_CHECK_INSTANCE_CAST ((o), MATE_MIXER_TYPE_PORT, MateMixerPort))
-#define MATE_MIXER_IS_PORT(o) \
- (G_TYPE_CHECK_INSTANCE_TYPE ((o), MATE_MIXER_TYPE_PORT))
-#define MATE_MIXER_PORT_CLASS(k) \
- (G_TYPE_CHECK_CLASS_CAST ((k), MATE_MIXER_TYPE_PORT, MateMixerPortClass))
-#define MATE_MIXER_IS_PORT_CLASS(k) \
- (G_TYPE_CHECK_CLASS_TYPE ((k), MATE_MIXER_TYPE_PORT))
-#define MATE_MIXER_PORT_GET_CLASS(o) \
- (G_TYPE_INSTANCE_GET_CLASS ((o), MATE_MIXER_TYPE_PORT, MateMixerPortClass))
-
-typedef struct _MateMixerPort MateMixerPort;
-typedef struct _MateMixerPortClass MateMixerPortClass;
-typedef struct _MateMixerPortPrivate MateMixerPortPrivate;
-
-struct _MateMixerPort
-{
- GObject parent;
-
- /*< private >*/
- MateMixerPortPrivate *priv;
-};
-
-struct _MateMixerPortClass
-{
- GObjectClass parent_class;
-};
-
-GType mate_mixer_port_get_type (void) G_GNUC_CONST;
-
-const gchar * mate_mixer_port_get_name (MateMixerPort *port);
-const gchar * mate_mixer_port_get_description (MateMixerPort *port);
-const gchar * mate_mixer_port_get_icon (MateMixerPort *port);
-guint mate_mixer_port_get_priority (MateMixerPort *port);
-MateMixerPortFlags mate_mixer_port_get_flags (MateMixerPort *port);
-
-G_END_DECLS
-
-#endif /* MATEMIXER_PORT_H */
diff --git a/libmatemixer/matemixer-private.h b/libmatemixer/matemixer-private.h
index 4dde496..4229000 100644
--- a/libmatemixer/matemixer-private.h
+++ b/libmatemixer/matemixer-private.h
@@ -20,9 +20,91 @@
#include <glib.h>
+#include "matemixer-backend-module.h"
+#include "matemixer-backend-private.h"
+#include "matemixer-device-profile-private.h"
+#include "matemixer-stream-control-private.h"
+#include "matemixer-switch-option-private.h"
+#include "matemixer-switch-private.h"
+
G_BEGIN_DECLS
-const GList *mate_mixer_get_modules (void);
+#define MATE_MIXER_IS_LEFT_CHANNEL(c) \
+ ((c) == MATE_MIXER_CHANNEL_FRONT_LEFT || \
+ (c) == MATE_MIXER_CHANNEL_BACK_LEFT || \
+ (c) == MATE_MIXER_CHANNEL_FRONT_LEFT_CENTER || \
+ (c) == MATE_MIXER_CHANNEL_SIDE_LEFT || \
+ (c) == MATE_MIXER_CHANNEL_TOP_FRONT_LEFT || \
+ (c) == MATE_MIXER_CHANNEL_TOP_BACK_LEFT)
+
+#define MATE_MIXER_IS_RIGHT_CHANNEL(c) \
+ ((c) == MATE_MIXER_CHANNEL_FRONT_RIGHT || \
+ (c) == MATE_MIXER_CHANNEL_BACK_RIGHT || \
+ (c) == MATE_MIXER_CHANNEL_FRONT_RIGHT_CENTER || \
+ (c) == MATE_MIXER_CHANNEL_SIDE_RIGHT || \
+ (c) == MATE_MIXER_CHANNEL_TOP_FRONT_RIGHT || \
+ (c) == MATE_MIXER_CHANNEL_TOP_BACK_RIGHT)
+
+#define MATE_MIXER_IS_FRONT_CHANNEL(c) \
+ ((c) == MATE_MIXER_CHANNEL_FRONT_LEFT || \
+ (c) == MATE_MIXER_CHANNEL_FRONT_RIGHT || \
+ (c) == MATE_MIXER_CHANNEL_FRONT_CENTER || \
+ (c) == MATE_MIXER_CHANNEL_FRONT_LEFT_CENTER || \
+ (c) == MATE_MIXER_CHANNEL_FRONT_RIGHT_CENTER || \
+ (c) == MATE_MIXER_CHANNEL_TOP_FRONT_LEFT || \
+ (c) == MATE_MIXER_CHANNEL_TOP_FRONT_RIGHT || \
+ (c) == MATE_MIXER_CHANNEL_TOP_FRONT_CENTER)
+
+#define MATE_MIXER_IS_BACK_CHANNEL(c) \
+ ((c) == MATE_MIXER_CHANNEL_BACK_LEFT || \
+ (c) == MATE_MIXER_CHANNEL_BACK_RIGHT || \
+ (c) == MATE_MIXER_CHANNEL_BACK_CENTER || \
+ (c) == MATE_MIXER_CHANNEL_TOP_BACK_LEFT || \
+ (c) == MATE_MIXER_CHANNEL_TOP_BACK_RIGHT || \
+ (c) == MATE_MIXER_CHANNEL_TOP_BACK_CENTER)
+
+#define MATE_MIXER_CHANNEL_MASK_LEFT \
+ ((1 << MATE_MIXER_CHANNEL_FRONT_LEFT) | \
+ (1 << MATE_MIXER_CHANNEL_BACK_LEFT) | \
+ (1 << MATE_MIXER_CHANNEL_FRONT_LEFT_CENTER) | \
+ (1 << MATE_MIXER_CHANNEL_SIDE_LEFT) | \
+ (1 << MATE_MIXER_CHANNEL_TOP_FRONT_LEFT) | \
+ (1 << MATE_MIXER_CHANNEL_TOP_BACK_LEFT))
+
+#define MATE_MIXER_CHANNEL_MASK_RIGHT \
+ ((1 << MATE_MIXER_CHANNEL_FRONT_RIGHT) | \
+ (1 << MATE_MIXER_CHANNEL_BACK_RIGHT) | \
+ (1 << MATE_MIXER_CHANNEL_FRONT_RIGHT_CENTER) | \
+ (1 << MATE_MIXER_CHANNEL_SIDE_RIGHT) | \
+ (1 << MATE_MIXER_CHANNEL_TOP_FRONT_RIGHT) | \
+ (1 << MATE_MIXER_CHANNEL_TOP_BACK_RIGHT))
+
+#define MATE_MIXER_CHANNEL_MASK_FRONT \
+ ((1 << MATE_MIXER_CHANNEL_FRONT_LEFT) | \
+ (1 << MATE_MIXER_CHANNEL_FRONT_RIGHT) | \
+ (1 << MATE_MIXER_CHANNEL_FRONT_CENTER) | \
+ (1 << MATE_MIXER_CHANNEL_FRONT_LEFT_CENTER) | \
+ (1 << MATE_MIXER_CHANNEL_FRONT_RIGHT_CENTER) | \
+ (1 << MATE_MIXER_CHANNEL_TOP_FRONT_LEFT) | \
+ (1 << MATE_MIXER_CHANNEL_TOP_FRONT_RIGHT) | \
+ (1 << MATE_MIXER_CHANNEL_TOP_FRONT_CENTER))
+
+#define MATE_MIXER_CHANNEL_MASK_BACK \
+ ((1 << MATE_MIXER_CHANNEL_BACK_LEFT) | \
+ (1 << MATE_MIXER_CHANNEL_BACK_RIGHT) | \
+ (1 << MATE_MIXER_CHANNEL_BACK_CENTER) | \
+ (1 << MATE_MIXER_CHANNEL_TOP_BACK_LEFT) | \
+ (1 << MATE_MIXER_CHANNEL_TOP_BACK_RIGHT) | \
+ (1 << MATE_MIXER_CHANNEL_TOP_BACK_CENTER))
+
+#define MATE_MIXER_CHANNEL_MASK_HAS_CHANNEL(m,c) ((m) & (1 << (c)))
+#define MATE_MIXER_CHANNEL_MASK_HAS_LEFT(m) ((m) & MATE_MIXER_CHANNEL_MASK_LEFT)
+#define MATE_MIXER_CHANNEL_MASK_HAS_RIGHT(m) ((m) & MATE_MIXER_CHANNEL_MASK_RIGHT)
+#define MATE_MIXER_CHANNEL_MASK_HAS_FRONT(m) ((m) & MATE_MIXER_CHANNEL_MASK_FRONT)
+#define MATE_MIXER_CHANNEL_MASK_HAS_BACK(m) ((m) & MATE_MIXER_CHANNEL_MASK_BACK)
+
+const GList *_mate_mixer_get_modules (void);
+guint32 _mate_mixer_create_channel_mask (MateMixerChannelPosition *positions, guint n);
G_END_DECLS
diff --git a/libmatemixer/matemixer-stream-control-private.h b/libmatemixer/matemixer-stream-control-private.h
new file mode 100644
index 0000000..49454b3
--- /dev/null
+++ b/libmatemixer/matemixer-stream-control-private.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the licence, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef MATEMIXER_STREAM_CONTROL_PRIVATE_H
+#define MATEMIXER_STREAM_CONTROL_PRIVATE_H
+
+#include <glib.h>
+#include "matemixer-enums.h"
+#include "matemixer-types.h"
+
+G_BEGIN_DECLS
+
+void _mate_mixer_stream_control_set_flags (MateMixerStreamControl *control,
+ MateMixerStreamControlFlags flags);
+
+void _mate_mixer_stream_control_set_mute (MateMixerStreamControl *control,
+ gboolean mute);
+
+void _mate_mixer_stream_control_set_balance (MateMixerStreamControl *control,
+ gfloat balance);
+
+void _mate_mixer_stream_control_set_fade (MateMixerStreamControl *control,
+ gfloat fade);
+
+G_END_DECLS
+
+#endif /* MATEMIXER_STREAM_CONTROL_PRIVATE_H */
diff --git a/libmatemixer/matemixer-stream-control.c b/libmatemixer/matemixer-stream-control.c
new file mode 100644
index 0000000..ace584a
--- /dev/null
+++ b/libmatemixer/matemixer-stream-control.c
@@ -0,0 +1,627 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the licence, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include "matemixer-enums.h"
+#include "matemixer-enum-types.h"
+#include "matemixer-stream-control.h"
+#include "matemixer-stream-control-private.h"
+
+/**
+ * SECTION:matemixer-stream-control
+ * @include: libmatemixer/matemixer.h
+ */
+
+struct _MateMixerStreamControlPrivate
+{
+ gchar *name;
+ gchar *label;
+ gboolean mute;
+ gfloat balance;
+ gfloat fade;
+ MateMixerStreamControlFlags flags;
+ MateMixerStreamControlRole role;
+};
+
+enum {
+ PROP_0,
+ PROP_NAME,
+ PROP_LABEL,
+ PROP_FLAGS,
+ PROP_ROLE,
+ PROP_MUTE,
+ PROP_VOLUME,
+ PROP_BALANCE,
+ PROP_FADE,
+ N_PROPERTIES
+};
+
+static GParamSpec *properties[N_PROPERTIES] = { NULL, };
+
+static void mate_mixer_stream_control_class_init (MateMixerStreamControlClass *klass);
+
+static void mate_mixer_stream_control_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec);
+static void mate_mixer_stream_control_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec);
+
+static void mate_mixer_stream_control_init (MateMixerStreamControl *control);
+static void mate_mixer_stream_control_finalize (GObject *object);
+
+G_DEFINE_ABSTRACT_TYPE (MateMixerStreamControl, mate_mixer_stream_control, G_TYPE_OBJECT)
+
+static void
+mate_mixer_stream_control_class_init (MateMixerStreamControlClass *klass)
+{
+ GObjectClass *object_class;
+
+ object_class = G_OBJECT_CLASS (klass);
+ object_class->finalize = mate_mixer_stream_control_finalize;
+ object_class->get_property = mate_mixer_stream_control_get_property;
+ object_class->set_property = mate_mixer_stream_control_set_property;
+
+ properties[PROP_NAME] =
+ g_param_spec_string ("name",
+ "Name",
+ "Name of the stream control",
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_LABEL] =
+ g_param_spec_string ("label",
+ "Label",
+ "Label of the stream control",
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_FLAGS] =
+ g_param_spec_flags ("flags",
+ "Flags",
+ "Capability flags of the stream control",
+ MATE_MIXER_TYPE_STREAM_CONTROL_FLAGS,
+ MATE_MIXER_STREAM_CONTROL_NO_FLAGS,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_ROLE] =
+ g_param_spec_enum ("role",
+ "Role",
+ "Role of the stream control",
+ MATE_MIXER_TYPE_STREAM_CONTROL_ROLE,
+ MATE_MIXER_STREAM_CONTROL_ROLE_UNKNOWN,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_MUTE] =
+ g_param_spec_boolean ("mute",
+ "Mute",
+ "Mute state of the stream control",
+ FALSE,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_VOLUME] =
+ g_param_spec_uint ("volume",
+ "Volume",
+ "Volume of the stream control",
+ 0,
+ G_MAXUINT,
+ 0,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_BALANCE] =
+ g_param_spec_float ("balance",
+ "Balance",
+ "Balance value of the stream control",
+ -1.0f,
+ 1.0f,
+ 0.0f,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_FADE] =
+ g_param_spec_float ("fade",
+ "Fade",
+ "Fade value of the stream control",
+ -1.0f,
+ 1.0f,
+ 0.0f,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS);
+
+ g_object_class_install_properties (object_class, N_PROPERTIES, properties);
+
+ g_type_class_add_private (object_class, sizeof (MateMixerStreamControlPrivate));
+}
+
+static void
+mate_mixer_stream_control_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ MateMixerStreamControl *control;
+
+ control = MATE_MIXER_STREAM_CONTROL (object);
+
+ switch (param_id) {
+ case PROP_NAME:
+ g_value_set_string (value, control->priv->name);
+ break;
+ case PROP_LABEL:
+ g_value_set_string (value, control->priv->label);
+ break;
+ case PROP_FLAGS:
+ g_value_set_flags (value, control->priv->flags);
+ break;
+ case PROP_ROLE:
+ g_value_set_enum (value, control->priv->role);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ }
+}
+
+static void
+mate_mixer_stream_control_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ MateMixerStreamControl *control;
+
+ control = MATE_MIXER_STREAM_CONTROL (object);
+
+ switch (param_id) {
+ case PROP_NAME:
+ /* Construct-only string */
+ control->priv->name = g_value_dup_string (value);
+ break;
+ case PROP_LABEL:
+ /* Construct-only string */
+ control->priv->label = g_value_dup_string (value);
+ break;
+ case PROP_FLAGS:
+ control->priv->flags = g_value_get_flags (value);
+ break;
+ case PROP_ROLE:
+ control->priv->role = g_value_get_enum (value);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ }
+}
+
+static void
+mate_mixer_stream_control_init (MateMixerStreamControl *control)
+{
+ control->priv = G_TYPE_INSTANCE_GET_PRIVATE (control,
+ MATE_MIXER_TYPE_STREAM_CONTROL,
+ MateMixerStreamControlPrivate);
+}
+
+static void
+mate_mixer_stream_control_finalize (GObject *object)
+{
+ MateMixerStreamControl *control;
+
+ control = MATE_MIXER_STREAM_CONTROL (object);
+
+ g_free (control->priv->name);
+ g_free (control->priv->label);
+
+ G_OBJECT_CLASS (mate_mixer_stream_control_parent_class)->finalize (object);
+}
+
+const gchar *
+mate_mixer_stream_control_get_name (MateMixerStreamControl *control)
+{
+ g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (control), NULL);
+
+ return control->priv->name;
+}
+
+const gchar *
+mate_mixer_stream_control_get_label (MateMixerStreamControl *control)
+{
+ g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (control), NULL);
+
+ return control->priv->label;
+}
+
+MateMixerStreamControlFlags
+mate_mixer_stream_control_get_flags (MateMixerStreamControl *control)
+{
+ g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (control), MATE_MIXER_STREAM_CONTROL_NO_FLAGS);
+
+ return control->priv->flags;
+}
+
+MateMixerStreamControlRole
+mate_mixer_stream_control_get_role (MateMixerStreamControl *control)
+{
+ g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (control), MATE_MIXER_STREAM_CONTROL_ROLE_UNKNOWN);
+
+ return control->priv->role;
+}
+
+gboolean
+mate_mixer_stream_control_get_mute (MateMixerStreamControl *control)
+{
+ g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (control), FALSE);
+
+ return control->priv->mute;
+}
+
+gboolean
+mate_mixer_stream_control_set_mute (MateMixerStreamControl *control, gboolean mute)
+{
+ g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (control), FALSE);
+
+ if (control->priv->mute == mute)
+ return TRUE;
+
+ if (control->priv->flags & MATE_MIXER_STREAM_CONTROL_HAS_MUTE) {
+ MateMixerStreamControlClass *klass;
+
+ klass = MATE_MIXER_STREAM_CONTROL_GET_CLASS (control);
+
+ if (G_LIKELY (klass->set_mute != NULL))
+ return klass->set_mute (control, mute);
+ }
+ return FALSE;
+}
+
+guint
+mate_mixer_stream_control_get_num_channels (MateMixerStreamControl *control)
+{
+ MateMixerStreamControlClass *klass;
+
+ g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (control), 0);
+
+ klass = MATE_MIXER_STREAM_CONTROL_GET_CLASS (control);
+
+ if (klass->get_num_channels != NULL)
+ return klass->get_num_channels (control);
+
+ return 0;
+}
+
+guint
+mate_mixer_stream_control_get_volume (MateMixerStreamControl *control)
+{
+ g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (control), 0);
+
+ if (control->priv->flags & MATE_MIXER_STREAM_CONTROL_HAS_VOLUME) {
+ MateMixerStreamControlClass *klass;
+
+ klass = MATE_MIXER_STREAM_CONTROL_GET_CLASS (control);
+
+ if G_LIKELY (klass->get_volume != NULL)
+ return klass->get_volume (control);
+ }
+ return 0;
+}
+
+gboolean
+mate_mixer_stream_control_set_volume (MateMixerStreamControl *control, guint volume)
+{
+ g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (control), FALSE);
+
+ if (control->priv->flags & MATE_MIXER_STREAM_CONTROL_HAS_VOLUME) {
+ MateMixerStreamControlClass *klass;
+
+ klass = MATE_MIXER_STREAM_CONTROL_GET_CLASS (control);
+
+ if (G_LIKELY (klass->set_volume != NULL))
+ return klass->set_volume (control, volume);
+ }
+ return FALSE;
+}
+
+gdouble
+mate_mixer_stream_control_get_decibel (MateMixerStreamControl *control)
+{
+ g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (control), -MATE_MIXER_INFINITY);
+
+ if (control->priv->flags & MATE_MIXER_STREAM_CONTROL_HAS_DECIBEL) {
+ MateMixerStreamControlClass *klass;
+
+ klass = MATE_MIXER_STREAM_CONTROL_GET_CLASS (control);
+
+ if (G_LIKELY (klass->get_decibel != NULL))
+ return klass->get_decibel (control);
+ }
+ return -MATE_MIXER_INFINITY;
+}
+
+gboolean
+mate_mixer_stream_control_set_decibel (MateMixerStreamControl *control, gdouble decibel)
+{
+ g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (control), FALSE);
+
+ if (control->priv->flags & MATE_MIXER_STREAM_CONTROL_HAS_DECIBEL) {
+ MateMixerStreamControlClass *klass;
+
+ klass = MATE_MIXER_STREAM_CONTROL_GET_CLASS (control);
+
+ if (G_LIKELY (klass->set_decibel != NULL))
+ return klass->set_decibel (control, decibel);
+ }
+ return FALSE;
+}
+
+MateMixerChannelPosition
+mate_mixer_stream_control_get_channel_position (MateMixerStreamControl *control, guint channel)
+{
+ MateMixerStreamControlClass *klass;
+
+ g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (control), MATE_MIXER_CHANNEL_UNKNOWN);
+
+ klass = MATE_MIXER_STREAM_CONTROL_GET_CLASS (control);
+
+ if (klass->get_channel_position != NULL)
+ return klass->get_channel_position (control, channel);
+
+ return MATE_MIXER_CHANNEL_UNKNOWN;
+}
+
+guint
+mate_mixer_stream_control_get_channel_volume (MateMixerStreamControl *control, guint channel)
+{
+ g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (control), 0);
+
+ if (control->priv->flags & MATE_MIXER_STREAM_CONTROL_HAS_VOLUME) {
+ MateMixerStreamControlClass *klass;
+
+ klass = MATE_MIXER_STREAM_CONTROL_GET_CLASS (control);
+
+ if (G_LIKELY (klass->get_channel_volume != NULL))
+ return klass->get_channel_volume (control, channel);
+ }
+ return 0;
+}
+
+gboolean
+mate_mixer_stream_control_set_channel_volume (MateMixerStreamControl *control,
+ guint channel,
+ guint volume)
+{
+ g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (control), FALSE);
+
+ if (control->priv->flags & MATE_MIXER_STREAM_CONTROL_HAS_VOLUME) {
+ MateMixerStreamControlClass *klass;
+
+ klass = MATE_MIXER_STREAM_CONTROL_GET_CLASS (control);
+
+ if (G_LIKELY (klass->set_channel_volume != NULL))
+ return klass->set_channel_volume (control, channel, volume);
+ }
+ return FALSE;
+}
+
+gdouble
+mate_mixer_stream_control_get_channel_decibel (MateMixerStreamControl *control, guint channel)
+{
+ g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (control), -MATE_MIXER_INFINITY);
+
+ if (control->priv->flags & MATE_MIXER_STREAM_CONTROL_HAS_DECIBEL) {
+ MateMixerStreamControlClass *klass;
+
+ klass = MATE_MIXER_STREAM_CONTROL_GET_CLASS (control);
+
+ if (G_LIKELY (klass->get_channel_decibel != NULL))
+ return klass->get_channel_decibel (control, channel);
+ }
+ return -MATE_MIXER_INFINITY;
+}
+
+gboolean
+mate_mixer_stream_control_set_channel_decibel (MateMixerStreamControl *control,
+ guint channel,
+ gdouble decibel)
+{
+ g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (control), FALSE);
+
+ if (control->priv->flags & MATE_MIXER_STREAM_CONTROL_HAS_DECIBEL) {
+ MateMixerStreamControlClass *klass;
+
+ klass = MATE_MIXER_STREAM_CONTROL_GET_CLASS (control);
+
+ if (G_LIKELY (klass->set_channel_decibel != NULL))
+ return klass->set_channel_decibel (control, channel, decibel);
+ }
+ return FALSE;
+}
+
+gboolean
+mate_mixer_stream_control_has_channel_position (MateMixerStreamControl *control,
+ MateMixerChannelPosition position)
+{
+ MateMixerStreamControlClass *klass;
+
+ g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (control), FALSE);
+
+ klass = MATE_MIXER_STREAM_CONTROL_GET_CLASS (control);
+
+ if (klass->has_channel_position != NULL)
+ return klass->has_channel_position (control, position);
+
+ return FALSE;
+}
+
+gfloat
+mate_mixer_stream_control_get_balance (MateMixerStreamControl *control)
+{
+ g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (control), 0.0f);
+
+ if (control->priv->flags & MATE_MIXER_STREAM_CONTROL_CAN_BALANCE)
+ return control->priv->balance;
+ else
+ return 0.0f;
+}
+
+gboolean
+mate_mixer_stream_control_set_balance (MateMixerStreamControl *control, gfloat balance)
+{
+ g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (control), FALSE);
+
+ if (control->priv->flags & MATE_MIXER_STREAM_CONTROL_CAN_BALANCE) {
+ MateMixerStreamControlClass *klass;
+
+ if (balance < -1.0f || balance > 1.0f)
+ return FALSE;
+
+ klass = MATE_MIXER_STREAM_CONTROL_GET_CLASS (control);
+
+ if (G_LIKELY (klass->set_balance != NULL))
+ return klass->set_balance (control, balance);
+ }
+ return FALSE;
+}
+
+gfloat
+mate_mixer_stream_control_get_fade (MateMixerStreamControl *control)
+{
+ g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (control), 0.0f);
+
+ if (control->priv->flags & MATE_MIXER_STREAM_CONTROL_CAN_FADE)
+ return control->priv->fade;
+ else
+ return 0.0f;
+}
+
+gboolean
+mate_mixer_stream_control_set_fade (MateMixerStreamControl *control, gfloat fade)
+{
+ g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (control), FALSE);
+
+ if (control->priv->flags & MATE_MIXER_STREAM_CONTROL_CAN_FADE) {
+ MateMixerStreamControlClass *klass;
+
+ if (fade < -1.0f || fade > 1.0f)
+ return FALSE;
+
+ klass = MATE_MIXER_STREAM_CONTROL_GET_CLASS (control);
+
+ if (G_LIKELY (klass->set_fade != NULL))
+ return klass->set_fade (control, fade);
+ }
+ return FALSE;
+}
+
+guint
+mate_mixer_stream_control_get_min_volume (MateMixerStreamControl *control)
+{
+ MateMixerStreamControlClass *klass;
+
+ g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (control), 0);
+
+ klass = MATE_MIXER_STREAM_CONTROL_GET_CLASS (control);
+
+ if (klass->get_min_volume != NULL)
+ return klass->get_min_volume (control);
+
+ return 0;
+}
+
+guint
+mate_mixer_stream_control_get_max_volume (MateMixerStreamControl *control)
+{
+ MateMixerStreamControlClass *klass;
+
+ g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (control), 0);
+
+ klass = MATE_MIXER_STREAM_CONTROL_GET_CLASS (control);
+
+ if (klass->get_max_volume != NULL)
+ return klass->get_max_volume (control);
+
+ return 0;
+}
+
+guint
+mate_mixer_stream_control_get_normal_volume (MateMixerStreamControl *control)
+{
+ MateMixerStreamControlClass *klass;
+
+ g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (control), 0);
+
+ klass = MATE_MIXER_STREAM_CONTROL_GET_CLASS (control);
+
+ if (klass->get_normal_volume != NULL)
+ return klass->get_normal_volume (control);
+
+ return 0;
+}
+
+guint
+mate_mixer_stream_control_get_base_volume (MateMixerStreamControl *control)
+{
+ MateMixerStreamControlClass *klass;
+
+ g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (control), 0);
+
+ klass = MATE_MIXER_STREAM_CONTROL_GET_CLASS (control);
+
+ if (klass->get_base_volume != NULL)
+ return klass->get_base_volume (control);
+
+ return 0;
+}
+
+void
+_mate_mixer_stream_control_set_flags (MateMixerStreamControl *control,
+ MateMixerStreamControlFlags flags)
+{
+ control->priv->flags = flags;
+}
+
+void
+_mate_mixer_stream_control_set_mute (MateMixerStreamControl *control, gboolean mute)
+{
+ control->priv->mute = mute;
+}
+
+void
+_mate_mixer_stream_control_set_balance (MateMixerStreamControl *control, gfloat balance)
+{
+ control->priv->balance = balance;
+}
+
+void
+_mate_mixer_stream_control_set_fade (MateMixerStreamControl *control, gfloat fade)
+{
+ control->priv->fade = fade;
+}
diff --git a/libmatemixer/matemixer-stream-control.h b/libmatemixer/matemixer-stream-control.h
new file mode 100644
index 0000000..51d7f95
--- /dev/null
+++ b/libmatemixer/matemixer-stream-control.h
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the licence, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef MATEMIXER_STREAM_CONTROL_H
+#define MATEMIXER_STREAM_CONTROL_H
+
+#include <math.h>
+#include <glib.h>
+#include <glib-object.h>
+
+#include <libmatemixer/matemixer-enums.h>
+#include <libmatemixer/matemixer-types.h>
+
+G_BEGIN_DECLS
+
+#ifdef INFINITY
+# define MATE_MIXER_INFINITY INFINITY
+#else
+# define MATE_MIXER_INFINITY G_MAXDOUBLE
+#endif
+
+#define MATE_MIXER_TYPE_STREAM_CONTROL \
+ (mate_mixer_stream_control_get_type ())
+#define MATE_MIXER_STREAM_CONTROL(o) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((o), MATE_MIXER_TYPE_STREAM_CONTROL, MateMixerStreamControl))
+#define MATE_MIXER_IS_STREAM_CONTROL(o) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((o), MATE_MIXER_TYPE_STREAM_CONTROL))
+#define MATE_MIXER_STREAM_CONTROL_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_CAST ((k), MATE_MIXER_TYPE_STREAM_CONTROL, MateMixerStreamControlClass))
+#define MATE_MIXER_IS_STREAM_CONTROL_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_TYPE ((k), MATE_MIXER_TYPE_STREAM_CONTROL))
+#define MATE_MIXER_STREAM_CONTROL_GET_CLASS(o) \
+ (G_TYPE_INSTANCE_GET_CLASS ((o), MATE_MIXER_TYPE_STREAM_CONTROL, MateMixerStreamControlClass))
+
+typedef struct _MateMixerStreamControlClass MateMixerStreamControlClass;
+typedef struct _MateMixerStreamControlPrivate MateMixerStreamControlPrivate;
+
+struct _MateMixerStreamControl
+{
+ GObject object;
+
+ /*< private >*/
+ MateMixerStreamControlPrivate *priv;
+};
+
+struct _MateMixerStreamControlClass
+{
+ GObjectClass parent_class;
+
+ /*< private >*/
+ gboolean (*set_mute) (MateMixerStreamControl *control,
+ gboolean mute);
+
+ guint (*get_num_channels) (MateMixerStreamControl *control);
+
+ guint (*get_volume) (MateMixerStreamControl *control);
+ gboolean (*set_volume) (MateMixerStreamControl *control,
+ guint volume);
+
+ gdouble (*get_decibel) (MateMixerStreamControl *control);
+ gboolean (*set_decibel) (MateMixerStreamControl *control,
+ gdouble decibel);
+
+ gboolean (*has_channel_position) (MateMixerStreamControl *control,
+ MateMixerChannelPosition position);
+ MateMixerChannelPosition (*get_channel_position) (MateMixerStreamControl *control,
+ guint channel);
+
+ guint (*get_channel_volume) (MateMixerStreamControl *control,
+ guint channel);
+ gboolean (*set_channel_volume) (MateMixerStreamControl *control,
+ guint channel,
+ guint volume);
+
+ gdouble (*get_channel_decibel) (MateMixerStreamControl *control,
+ guint channel);
+ gboolean (*set_channel_decibel) (MateMixerStreamControl *control,
+ guint channel,
+ gdouble decibel);
+
+ gboolean (*set_balance) (MateMixerStreamControl *control,
+ gfloat balance);
+
+ gboolean (*set_fade) (MateMixerStreamControl *control,
+ gfloat fade);
+
+ guint (*get_min_volume) (MateMixerStreamControl *control);
+ guint (*get_max_volume) (MateMixerStreamControl *control);
+ guint (*get_normal_volume) (MateMixerStreamControl *control);
+ guint (*get_base_volume) (MateMixerStreamControl *control);
+};
+
+GType mate_mixer_stream_control_get_type (void) G_GNUC_CONST;
+
+const gchar * mate_mixer_stream_control_get_name (MateMixerStreamControl *control);
+const gchar * mate_mixer_stream_control_get_label (MateMixerStreamControl *control);
+MateMixerStreamControlFlags mate_mixer_stream_control_get_flags (MateMixerStreamControl *control);
+MateMixerStreamControlRole mate_mixer_stream_control_get_role (MateMixerStreamControl *control);
+
+gboolean mate_mixer_stream_control_get_mute (MateMixerStreamControl *control);
+gboolean mate_mixer_stream_control_set_mute (MateMixerStreamControl *control,
+ gboolean mute);
+
+guint mate_mixer_stream_control_get_num_channels (MateMixerStreamControl *control);
+
+guint mate_mixer_stream_control_get_volume (MateMixerStreamControl *control);
+gboolean mate_mixer_stream_control_set_volume (MateMixerStreamControl *control,
+ guint volume);
+
+gdouble mate_mixer_stream_control_get_decibel (MateMixerStreamControl *control);
+gboolean mate_mixer_stream_control_set_decibel (MateMixerStreamControl *control,
+ gdouble decibel);
+
+gboolean mate_mixer_stream_control_has_channel_position (MateMixerStreamControl *control,
+ MateMixerChannelPosition position);
+MateMixerChannelPosition mate_mixer_stream_control_get_channel_position (MateMixerStreamControl *control,
+ guint channel);
+
+guint mate_mixer_stream_control_get_channel_volume (MateMixerStreamControl *control,
+ guint channel);
+gboolean mate_mixer_stream_control_set_channel_volume (MateMixerStreamControl *control,
+ guint channel,
+ guint volume);
+
+gdouble mate_mixer_stream_control_get_channel_decibel (MateMixerStreamControl *control,
+ guint channel);
+gboolean mate_mixer_stream_control_set_channel_decibel (MateMixerStreamControl *control,
+ guint channel,
+ gdouble decibel);
+
+gfloat mate_mixer_stream_control_get_balance (MateMixerStreamControl *control);
+gboolean mate_mixer_stream_control_set_balance (MateMixerStreamControl *control,
+ gfloat balance);
+
+gfloat mate_mixer_stream_control_get_fade (MateMixerStreamControl *control);
+gboolean mate_mixer_stream_control_set_fade (MateMixerStreamControl *control,
+ gfloat fade);
+
+guint mate_mixer_stream_control_get_min_volume (MateMixerStreamControl *control);
+guint mate_mixer_stream_control_get_max_volume (MateMixerStreamControl *control);
+guint mate_mixer_stream_control_get_normal_volume (MateMixerStreamControl *control);
+guint mate_mixer_stream_control_get_base_volume (MateMixerStreamControl *control);
+
+G_END_DECLS
+
+#endif /* MATEMIXER_STREAM_CONTROL_H */
diff --git a/libmatemixer/matemixer-stream.c b/libmatemixer/matemixer-stream.c
index 6bec2be..1902de3 100644
--- a/libmatemixer/matemixer-stream.c
+++ b/libmatemixer/matemixer-stream.c
@@ -15,20 +15,44 @@
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
+#include <string.h>
#include <glib.h>
#include <glib-object.h>
#include "matemixer-device.h"
#include "matemixer-enums.h"
#include "matemixer-enum-types.h"
-#include "matemixer-port.h"
#include "matemixer-stream.h"
+#include "matemixer-stream-control.h"
+#include "matemixer-switch.h"
/**
* SECTION:matemixer-stream
* @include: libmatemixer/matemixer.h
*/
+struct _MateMixerStreamPrivate
+{
+ gchar *name;
+ GList *controls;
+ GList *switches;
+ gboolean monitor_enabled;
+ MateMixerDevice *device;
+ MateMixerStreamFlags flags;
+ MateMixerStreamState state;
+};
+
+enum {
+ PROP_0,
+ PROP_NAME,
+ PROP_DEVICE,
+ PROP_FLAGS,
+ PROP_STATE,
+ N_PROPERTIES
+};
+
+static GParamSpec *properties[N_PROPERTIES] = { NULL, };
+
enum {
MONITOR_VALUE,
N_SIGNALS
@@ -36,449 +60,285 @@ enum {
static guint signals[N_SIGNALS] = { 0, };
-G_DEFINE_INTERFACE (MateMixerStream, mate_mixer_stream, G_TYPE_OBJECT)
+static void mate_mixer_stream_class_init (MateMixerStreamClass *klass);
+
+static void mate_mixer_stream_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec);
+static void mate_mixer_stream_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec);
+
+static void mate_mixer_stream_init (MateMixerStream *stream);
+static void mate_mixer_stream_dispose (GObject *object);
+static void mate_mixer_stream_finalize (GObject *object);
+
+G_DEFINE_ABSTRACT_TYPE (MateMixerStream, mate_mixer_stream, G_TYPE_OBJECT)
+
+static MateMixerStreamControl *mate_mixer_stream_real_get_control (MateMixerStream *stream,
+ const gchar *name);
+static MateMixerSwitch * mate_mixer_stream_real_get_switch (MateMixerStream *stream,
+ const gchar *name);
static void
-mate_mixer_stream_default_init (MateMixerStreamInterface *iface)
-{
- g_object_interface_install_property (iface,
- g_param_spec_string ("name",
- "Name",
- "Name of the stream",
- NULL,
- G_PARAM_READABLE |
- G_PARAM_STATIC_STRINGS));
-
- g_object_interface_install_property (iface,
- g_param_spec_string ("description",
- "Description",
- "Description of the stream",
- NULL,
- G_PARAM_READABLE |
- G_PARAM_STATIC_STRINGS));
-
- g_object_interface_install_property (iface,
- g_param_spec_object ("device",
- "Device",
- "Device the stream belongs to",
- MATE_MIXER_TYPE_DEVICE,
- G_PARAM_READABLE |
- G_PARAM_STATIC_STRINGS));
-
- g_object_interface_install_property (iface,
- g_param_spec_flags ("flags",
- "Flags",
- "Capability flags of the stream",
- MATE_MIXER_TYPE_STREAM_FLAGS,
- MATE_MIXER_STREAM_NO_FLAGS,
- G_PARAM_READABLE |
- G_PARAM_STATIC_STRINGS));
-
- g_object_interface_install_property (iface,
- g_param_spec_enum ("state",
- "State",
- "Current state of the stream",
- MATE_MIXER_TYPE_STREAM_STATE,
- MATE_MIXER_STREAM_STATE_UNKNOWN,
- G_PARAM_READABLE |
- G_PARAM_STATIC_STRINGS));
-
- g_object_interface_install_property (iface,
- g_param_spec_boolean ("mute",
- "Mute",
- "Mute state of the stream",
- FALSE,
- G_PARAM_READABLE |
- G_PARAM_STATIC_STRINGS));
-
- g_object_interface_install_property (iface,
- g_param_spec_uint ("volume",
- "Volume",
- "Volume of the stream",
- 0,
- G_MAXUINT,
- 0,
- G_PARAM_READABLE |
- G_PARAM_STATIC_STRINGS));
-
- g_object_interface_install_property (iface,
- g_param_spec_float ("balance",
- "Balance",
- "Balance value of the stream",
- -1.0f,
- 1.0f,
- 0.0f,
- G_PARAM_READABLE |
- G_PARAM_STATIC_STRINGS));
-
- g_object_interface_install_property (iface,
- g_param_spec_float ("fade",
- "Fade",
- "Fade value of the stream",
- -1.0f,
- 1.0f,
- 0.0f,
- G_PARAM_READABLE |
- G_PARAM_STATIC_STRINGS));
-
- g_object_interface_install_property (iface,
- g_param_spec_object ("active-port",
- "Active port",
- "The currently active port of the stream",
- MATE_MIXER_TYPE_PORT,
- G_PARAM_READABLE |
- G_PARAM_STATIC_STRINGS));
+mate_mixer_stream_class_init (MateMixerStreamClass *klass)
+{
+ GObjectClass *object_class;
+
+ klass->get_control = mate_mixer_stream_real_get_control;
+ klass->get_switch = mate_mixer_stream_real_get_switch;
+
+ object_class = G_OBJECT_CLASS (klass);
+ object_class->dispose = mate_mixer_stream_dispose;
+ object_class->finalize = mate_mixer_stream_finalize;
+ object_class->get_property = mate_mixer_stream_get_property;
+ object_class->set_property = mate_mixer_stream_set_property;
+
+ properties[PROP_NAME] =
+ g_param_spec_string ("name",
+ "Name",
+ "Name of the stream",
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_DEVICE] =
+ g_param_spec_object ("device",
+ "Device",
+ "Device the stream belongs to",
+ MATE_MIXER_TYPE_DEVICE,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_FLAGS] =
+ g_param_spec_flags ("flags",
+ "Flags",
+ "Capability flags of the stream",
+ MATE_MIXER_TYPE_STREAM_FLAGS,
+ MATE_MIXER_STREAM_NO_FLAGS,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_STATE] =
+ g_param_spec_enum ("state",
+ "State",
+ "Current state of the stream",
+ MATE_MIXER_TYPE_STREAM_STATE,
+ MATE_MIXER_STREAM_STATE_UNKNOWN,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS);
+
+ g_object_class_install_properties (object_class, N_PROPERTIES, properties);
signals[MONITOR_VALUE] =
g_signal_new ("monitor-value",
- G_TYPE_FROM_INTERFACE (iface),
+ G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (MateMixerStreamInterface, monitor_value),
+ G_STRUCT_OFFSET (MateMixerStreamClass, monitor_value),
NULL,
NULL,
g_cclosure_marshal_VOID__DOUBLE,
G_TYPE_NONE,
1,
G_TYPE_DOUBLE);
-}
-
-const gchar *
-mate_mixer_stream_get_name (MateMixerStream *stream)
-{
- return MATE_MIXER_STREAM_GET_INTERFACE (stream)->get_name (stream);
-}
-
-const gchar *
-mate_mixer_stream_get_description (MateMixerStream *stream)
-{
- MateMixerStreamInterface *iface;
-
- g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), NULL);
-
- iface = MATE_MIXER_STREAM_GET_INTERFACE (stream);
-
- if (iface->get_description)
- return iface->get_description (stream);
-
- return NULL;
-}
-
-MateMixerDevice *
-mate_mixer_stream_get_device (MateMixerStream *stream)
-{
- MateMixerStreamInterface *iface;
-
- g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), NULL);
-
- iface = MATE_MIXER_STREAM_GET_INTERFACE (stream);
-
- if (iface->get_device)
- return iface->get_device (stream);
-
- return NULL;
-}
-
-MateMixerStreamFlags
-mate_mixer_stream_get_flags (MateMixerStream *stream)
-{
- MateMixerStreamInterface *iface;
-
- g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), MATE_MIXER_STREAM_NO_FLAGS);
-
- iface = MATE_MIXER_STREAM_GET_INTERFACE (stream);
-
- if (iface->get_flags)
- return iface->get_flags (stream);
-
- return MATE_MIXER_STREAM_NO_FLAGS;
-}
-
-MateMixerStreamState
-mate_mixer_stream_get_state (MateMixerStream *stream)
-{
- MateMixerStreamInterface *iface;
-
- g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), MATE_MIXER_STREAM_STATE_UNKNOWN);
-
- iface = MATE_MIXER_STREAM_GET_INTERFACE (stream);
-
- if (iface->get_state)
- return iface->get_state (stream);
-
- return MATE_MIXER_STREAM_STATE_UNKNOWN;
-}
-
-gboolean
-mate_mixer_stream_get_mute (MateMixerStream *stream)
-{
- MateMixerStreamInterface *iface;
-
- g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), FALSE);
-
- iface = MATE_MIXER_STREAM_GET_INTERFACE (stream);
-
- if (iface->get_mute)
- return iface->get_mute (stream);
- return FALSE;
+ g_type_class_add_private (object_class, sizeof (MateMixerStreamPrivate));
}
-gboolean
-mate_mixer_stream_set_mute (MateMixerStream *stream, gboolean mute)
-{
- MateMixerStreamInterface *iface;
-
- g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), FALSE);
-
- iface = MATE_MIXER_STREAM_GET_INTERFACE (stream);
-
- if (iface->set_mute)
- return iface->set_mute (stream, mute);
-
- return FALSE;
-}
-
-guint
-mate_mixer_stream_get_volume (MateMixerStream *stream)
-{
- MateMixerStreamInterface *iface;
-
- g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), 0);
-
- iface = MATE_MIXER_STREAM_GET_INTERFACE (stream);
-
- if (iface->get_volume)
- return iface->get_volume (stream);
-
- return 0;
-}
-
-gboolean
-mate_mixer_stream_set_volume (MateMixerStream *stream, guint volume)
-{
- MateMixerStreamInterface *iface;
-
- g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), FALSE);
-
- iface = MATE_MIXER_STREAM_GET_INTERFACE (stream);
-
- if (iface->set_volume)
- return iface->set_volume (stream, volume);
-
- return FALSE;
+static void
+mate_mixer_stream_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ MateMixerStream *stream;
+
+ stream = MATE_MIXER_STREAM (object);
+
+ switch (param_id) {
+ case PROP_NAME:
+ g_value_set_string (value, stream->priv->name);
+ break;
+ case PROP_DEVICE:
+ g_value_set_object (value, stream->priv->device);
+ break;
+ case PROP_FLAGS:
+ g_value_set_flags (value, stream->priv->flags);
+ break;
+ case PROP_STATE:
+ g_value_set_enum (value, stream->priv->state);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ }
}
-gdouble
-mate_mixer_stream_get_decibel (MateMixerStream *stream)
-{
- MateMixerStreamInterface *iface;
-
- g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), -MATE_MIXER_INFINITY);
-
- iface = MATE_MIXER_STREAM_GET_INTERFACE (stream);
-
- if (iface->get_decibel)
- return iface->get_decibel (stream);
-
- return -MATE_MIXER_INFINITY;
+static void
+mate_mixer_stream_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ MateMixerStream *stream;
+
+ stream = MATE_MIXER_STREAM (object);
+
+ switch (param_id) {
+ case PROP_NAME:
+ /* Construct-only string */
+ stream->priv->name = g_value_dup_string (value);
+ break;
+ case PROP_DEVICE:
+ /* Construct-only object */
+ stream->priv->device = g_value_dup_object (value);
+ break;
+ case PROP_FLAGS:
+ stream->priv->flags = g_value_get_flags (value);
+ break;
+ case PROP_STATE:
+ stream->priv->state = g_value_get_enum (value);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ }
}
-gboolean
-mate_mixer_stream_set_decibel (MateMixerStream *stream, gdouble decibel)
+static void
+mate_mixer_stream_init (MateMixerStream *stream)
{
- MateMixerStreamInterface *iface;
-
- g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), FALSE);
-
- iface = MATE_MIXER_STREAM_GET_INTERFACE (stream);
-
- if (iface->set_decibel)
- return iface->set_decibel (stream, decibel);
-
- return FALSE;
+ stream->priv = G_TYPE_INSTANCE_GET_PRIVATE (stream,
+ MATE_MIXER_TYPE_STREAM,
+ MateMixerStreamPrivate);
}
-guint
-mate_mixer_stream_get_num_channels (MateMixerStream *stream)
+static void
+mate_mixer_stream_dispose (GObject *object)
{
- MateMixerStreamInterface *iface;
-
- g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), 0);
+ MateMixerStream *stream;
- iface = MATE_MIXER_STREAM_GET_INTERFACE (stream);
+ stream = MATE_MIXER_STREAM (object);
- if (iface->get_num_channels)
- return iface->get_num_channels (stream);
+ g_clear_object (&stream->priv->device);
- return 0;
+ G_OBJECT_CLASS (mate_mixer_stream_parent_class)->dispose (object);
}
-MateMixerChannelPosition
-mate_mixer_stream_get_channel_position (MateMixerStream *stream, guint channel)
+static void
+mate_mixer_stream_finalize (GObject *object)
{
- MateMixerStreamInterface *iface;
-
- g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), MATE_MIXER_CHANNEL_UNKNOWN);
+ MateMixerStream *stream;
- iface = MATE_MIXER_STREAM_GET_INTERFACE (stream);
+ stream = MATE_MIXER_STREAM (object);
- if (iface->get_channel_position)
- return iface->get_channel_position (stream, channel);
+ g_free (stream->priv->name);
- return MATE_MIXER_CHANNEL_UNKNOWN;
+ G_OBJECT_CLASS (mate_mixer_stream_parent_class)->finalize (object);
}
-guint
-mate_mixer_stream_get_channel_volume (MateMixerStream *stream, guint channel)
+const gchar *
+mate_mixer_stream_get_name (MateMixerStream *stream)
{
- MateMixerStreamInterface *iface;
-
- g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), 0);
-
- iface = MATE_MIXER_STREAM_GET_INTERFACE (stream);
-
- if (iface->get_channel_volume)
- return iface->get_channel_volume (stream, channel);
+ g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), NULL);
- return 0;
+ return stream->priv->name;
}
-gboolean
-mate_mixer_stream_set_channel_volume (MateMixerStream *stream,
- guint channel,
- guint volume)
+MateMixerDevice *
+mate_mixer_stream_get_device (MateMixerStream *stream)
{
- MateMixerStreamInterface *iface;
-
- g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), FALSE);
-
- iface = MATE_MIXER_STREAM_GET_INTERFACE (stream);
-
- if (iface->set_channel_volume)
- return iface->set_channel_volume (stream, channel, volume);
+ g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), NULL);
- return FALSE;
+ return stream->priv->device;
}
-gdouble
-mate_mixer_stream_get_channel_decibel (MateMixerStream *stream, guint channel)
+MateMixerStreamFlags
+mate_mixer_stream_get_flags (MateMixerStream *stream)
{
- MateMixerStreamInterface *iface;
-
- g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), -MATE_MIXER_INFINITY);
-
- iface = MATE_MIXER_STREAM_GET_INTERFACE (stream);
-
- if (iface->get_channel_decibel)
- return iface->get_channel_decibel (stream, channel);
+ g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), MATE_MIXER_STREAM_NO_FLAGS);
- return -MATE_MIXER_INFINITY;
+ return stream->priv->flags;
}
-gboolean
-mate_mixer_stream_set_channel_decibel (MateMixerStream *stream,
- guint channel,
- gdouble decibel)
+MateMixerStreamState
+mate_mixer_stream_get_state (MateMixerStream *stream)
{
- MateMixerStreamInterface *iface;
-
- g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), FALSE);
-
- iface = MATE_MIXER_STREAM_GET_INTERFACE (stream);
-
- if (iface->set_channel_decibel)
- return iface->set_channel_decibel (stream, channel, decibel);
+ g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), MATE_MIXER_STREAM_STATE_UNKNOWN);
- return FALSE;
+ return stream->priv->state;
}
-gboolean
-mate_mixer_stream_has_channel_position (MateMixerStream *stream,
- MateMixerChannelPosition position)
+MateMixerStreamControl *
+mate_mixer_stream_get_control (MateMixerStream *stream, const gchar *name)
{
- MateMixerStreamInterface *iface;
-
- g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), FALSE);
-
- iface = MATE_MIXER_STREAM_GET_INTERFACE (stream);
-
- if (iface->has_channel_position)
- return iface->has_channel_position (stream, position);
+ g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), NULL);
+ g_return_val_if_fail (name != NULL, NULL);
- return FALSE;
+ return MATE_MIXER_STREAM_GET_CLASS (stream)->get_control (stream, name);
}
-gfloat
-mate_mixer_stream_get_balance (MateMixerStream *stream)
+MateMixerSwitch *
+mate_mixer_stream_get_switch (MateMixerStream *stream, const gchar *name)
{
- MateMixerStreamInterface *iface;
-
- g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), 0.0f);
-
- iface = MATE_MIXER_STREAM_GET_INTERFACE (stream);
-
- if (iface->get_balance)
- return iface->get_balance (stream);
+ g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), NULL);
+ g_return_val_if_fail (name != NULL, NULL);
- return 0.0f;
+ return MATE_MIXER_STREAM_GET_CLASS (stream)->get_switch (stream, name);
}
-gboolean
-mate_mixer_stream_set_balance (MateMixerStream *stream, gfloat balance)
+MateMixerStreamControl *
+mate_mixer_stream_get_default_control (MateMixerStream *stream)
{
- MateMixerStreamInterface *iface;
-
- g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), FALSE);
-
- iface = MATE_MIXER_STREAM_GET_INTERFACE (stream);
-
- if (iface->set_balance)
- return iface->set_balance (stream, balance);
+ g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), NULL);
- return FALSE;
+ return MATE_MIXER_STREAM_GET_CLASS (stream)->get_default_control (stream);
}
-gfloat
-mate_mixer_stream_get_fade (MateMixerStream *stream)
+const GList *
+mate_mixer_stream_list_controls (MateMixerStream *stream)
{
- MateMixerStreamInterface *iface;
-
- g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), 0.0f);
-
- iface = MATE_MIXER_STREAM_GET_INTERFACE (stream);
+ g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), NULL);
- if (iface->get_fade)
- return iface->get_fade (stream);
+ if (stream->priv->controls == NULL)
+ stream->priv->controls = MATE_MIXER_STREAM_GET_CLASS (stream)->list_controls (stream);
- return 0.0f;
+ return (const GList *) stream->priv->controls;
}
-gboolean
-mate_mixer_stream_set_fade (MateMixerStream *stream, gfloat fade)
+const GList *
+mate_mixer_stream_list_switches (MateMixerStream *stream)
{
- MateMixerStreamInterface *iface;
-
- g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), FALSE);
+ g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), NULL);
- iface = MATE_MIXER_STREAM_GET_INTERFACE (stream);
+ if (stream->priv->switches == NULL) {
+ MateMixerStreamClass *klass = MATE_MIXER_STREAM_GET_CLASS (stream);
- if (iface->set_fade)
- return iface->set_fade (stream, fade);
+ if (klass->list_switches != NULL)
+ stream->priv->switches = klass->list_switches (stream);
+ }
- return FALSE;
+ return (const GList *) stream->priv->switches;
}
gboolean
mate_mixer_stream_suspend (MateMixerStream *stream)
{
- MateMixerStreamInterface *iface;
-
g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), FALSE);
- iface = MATE_MIXER_STREAM_GET_INTERFACE (stream);
+ if (stream->priv->state == MATE_MIXER_STREAM_STATE_SUSPENDED)
+ return TRUE;
- if (iface->suspend)
- return iface->suspend (stream);
+ if (stream->priv->flags & MATE_MIXER_STREAM_CAN_SUSPEND)
+ return MATE_MIXER_STREAM_GET_CLASS (stream)->suspend (stream);
return FALSE;
}
@@ -486,178 +346,79 @@ mate_mixer_stream_suspend (MateMixerStream *stream)
gboolean
mate_mixer_stream_resume (MateMixerStream *stream)
{
- MateMixerStreamInterface *iface;
-
g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), FALSE);
- iface = MATE_MIXER_STREAM_GET_INTERFACE (stream);
+ if (stream->priv->state != MATE_MIXER_STREAM_STATE_SUSPENDED)
+ return TRUE;
- if (iface->resume)
- return iface->resume (stream);
+ if (stream->priv->flags & MATE_MIXER_STREAM_CAN_SUSPEND)
+ return MATE_MIXER_STREAM_GET_CLASS (stream)->resume (stream);
return FALSE;
}
gboolean
-mate_mixer_stream_monitor_start (MateMixerStream *stream)
+mate_mixer_stream_monitor_get_enabled (MateMixerStream *stream)
{
- MateMixerStreamInterface *iface;
-
g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), FALSE);
- iface = MATE_MIXER_STREAM_GET_INTERFACE (stream);
-
- if (iface->monitor_start)
- return iface->monitor_start (stream);
-
- return FALSE;
-}
-
-void
-mate_mixer_stream_monitor_stop (MateMixerStream *stream)
-{
- MateMixerStreamInterface *iface;
-
- g_return_if_fail (MATE_MIXER_IS_STREAM (stream));
-
- iface = MATE_MIXER_STREAM_GET_INTERFACE (stream);
-
- if (iface->monitor_stop)
- iface->monitor_stop (stream);
+ return stream->priv->monitor_enabled;
}
gboolean
-mate_mixer_stream_monitor_is_running (MateMixerStream *stream)
+mate_mixer_stream_monitor_set_enabled (MateMixerStream *stream, gboolean enabled)
{
- MateMixerStreamInterface *iface;
-
g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), FALSE);
- iface = MATE_MIXER_STREAM_GET_INTERFACE (stream);
+ if (stream->priv->monitor_enabled == enabled)
+ return TRUE;
- if (iface->monitor_is_running)
- return iface->monitor_is_running (stream);
+ if (stream->priv->flags & MATE_MIXER_STREAM_HAS_MONITOR) {
+ if (enabled)
+ return MATE_MIXER_STREAM_GET_CLASS (stream)->monitor_start (stream);
+ else
+ return MATE_MIXER_STREAM_GET_CLASS (stream)->monitor_stop (stream);
+ }
return FALSE;
}
-gboolean
-mate_mixer_stream_monitor_set_name (MateMixerStream *stream, const gchar *name)
+static MateMixerStreamControl *
+mate_mixer_stream_real_get_control (MateMixerStream *stream, const gchar *name)
{
- MateMixerStreamInterface *iface;
-
- g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), FALSE);
-
- iface = MATE_MIXER_STREAM_GET_INTERFACE (stream);
-
- if (iface->monitor_set_name)
- return iface->monitor_set_name (stream, name);
-
- return FALSE;
-}
-
-const GList *
-mate_mixer_stream_list_ports (MateMixerStream *stream)
-{
- MateMixerStreamInterface *iface;
+ const GList *list;
g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), NULL);
+ g_return_val_if_fail (name != NULL, NULL);
- iface = MATE_MIXER_STREAM_GET_INTERFACE (stream);
+ list = mate_mixer_stream_list_controls (stream);
+ while (list != NULL) {
+ MateMixerStreamControl *control = MATE_MIXER_STREAM_CONTROL (list->data);
- if (iface->list_ports)
- return iface->list_ports (stream);
+ if (strcmp (name, mate_mixer_stream_control_get_name (control)) == 0)
+ return control;
+ list = list->next;
+ }
return NULL;
}
-MateMixerPort *
-mate_mixer_stream_get_active_port (MateMixerStream *stream)
+static MateMixerSwitch *
+mate_mixer_stream_real_get_switch (MateMixerStream *stream, const gchar *name)
{
- MateMixerStreamInterface *iface;
+ const GList *list;
g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), NULL);
+ g_return_val_if_fail (name != NULL, NULL);
- iface = MATE_MIXER_STREAM_GET_INTERFACE (stream);
+ list = mate_mixer_stream_list_switches (stream);
+ while (list != NULL) {
+ MateMixerSwitch *swtch = MATE_MIXER_SWITCH (list->data);
- if (iface->get_active_port)
- return iface->get_active_port (stream);
+ if (strcmp (name, mate_mixer_switch_get_name (swtch)) == 0)
+ return swtch;
+ list = list->next;
+ }
return NULL;
}
-
-gboolean
-mate_mixer_stream_set_active_port (MateMixerStream *stream, MateMixerPort *port)
-{
- MateMixerStreamInterface *iface;
-
- g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), FALSE);
- g_return_val_if_fail (MATE_MIXER_IS_PORT (port), FALSE);
-
- iface = MATE_MIXER_STREAM_GET_INTERFACE (stream);
-
- if (iface->set_active_port)
- return iface->set_active_port (stream, port);
-
- return FALSE;
-}
-
-guint
-mate_mixer_stream_get_min_volume (MateMixerStream *stream)
-{
- MateMixerStreamInterface *iface;
-
- g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), 0);
-
- iface = MATE_MIXER_STREAM_GET_INTERFACE (stream);
-
- if (iface->get_min_volume)
- return iface->get_min_volume (stream);
-
- return 0;
-}
-
-guint
-mate_mixer_stream_get_max_volume (MateMixerStream *stream)
-{
- MateMixerStreamInterface *iface;
-
- g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), 0);
-
- iface = MATE_MIXER_STREAM_GET_INTERFACE (stream);
-
- if (iface->get_max_volume)
- return iface->get_max_volume (stream);
-
- return 0;
-}
-
-guint
-mate_mixer_stream_get_normal_volume (MateMixerStream *stream)
-{
- MateMixerStreamInterface *iface;
-
- g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), 0);
-
- iface = MATE_MIXER_STREAM_GET_INTERFACE (stream);
-
- if (iface->get_normal_volume)
- return iface->get_normal_volume (stream);
-
- return 0;
-}
-
-guint
-mate_mixer_stream_get_base_volume (MateMixerStream *stream)
-{
- MateMixerStreamInterface *iface;
-
- g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), 0);
-
- iface = MATE_MIXER_STREAM_GET_INTERFACE (stream);
-
- if (iface->get_base_volume)
- return iface->get_base_volume (stream);
-
- return 0;
-}
diff --git a/libmatemixer/matemixer-stream.h b/libmatemixer/matemixer-stream.h
index e91a2a5..e73579e 100644
--- a/libmatemixer/matemixer-stream.h
+++ b/libmatemixer/matemixer-stream.h
@@ -18,164 +18,87 @@
#ifndef MATEMIXER_STREAM_H
#define MATEMIXER_STREAM_H
-#include <math.h>
#include <glib.h>
#include <glib-object.h>
-#include <libmatemixer/matemixer-device.h>
#include <libmatemixer/matemixer-enums.h>
-#include <libmatemixer/matemixer-port.h>
+#include <libmatemixer/matemixer-types.h>
G_BEGIN_DECLS
-#ifdef INFINITY
-#define MATE_MIXER_INFINITY INFINITY
-#else
-#define MATE_MIXER_INFINITY G_MAXDOUBLE
-#endif
-
#define MATE_MIXER_TYPE_STREAM \
(mate_mixer_stream_get_type ())
#define MATE_MIXER_STREAM(o) \
(G_TYPE_CHECK_INSTANCE_CAST ((o), MATE_MIXER_TYPE_STREAM, MateMixerStream))
#define MATE_MIXER_IS_STREAM(o) \
(G_TYPE_CHECK_INSTANCE_TYPE ((o), MATE_MIXER_TYPE_STREAM))
-#define MATE_MIXER_STREAM_GET_INTERFACE(o) \
- (G_TYPE_INSTANCE_GET_INTERFACE ((o), MATE_MIXER_TYPE_STREAM, MateMixerStreamInterface))
+#define MATE_MIXER_STREAM_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_CAST ((k), MATE_MIXER_TYPE_STREAM, MateMixerStreamClass))
+#define MATE_MIXER_IS_STREAM_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_TYPE ((k), MATE_MIXER_TYPE_STREAM))
+#define MATE_MIXER_STREAM_GET_CLASS(o) \
+ (G_TYPE_INSTANCE_GET_CLASS ((o), MATE_MIXER_TYPE_STREAM, MateMixerStreamClass))
-typedef struct _MateMixerStream MateMixerStream; /* dummy object */
-typedef struct _MateMixerStreamInterface MateMixerStreamInterface;
+typedef struct _MateMixerStreamClass MateMixerStreamClass;
+typedef struct _MateMixerStreamPrivate MateMixerStreamPrivate;
-struct _MateMixerStreamInterface
+struct _MateMixerStream
{
- GTypeInterface parent_iface;
+ GObject object;
/*< private >*/
- /* Virtual table */
- const gchar * (*get_name) (MateMixerStream *stream);
- const gchar * (*get_description) (MateMixerStream *stream);
- MateMixerDevice * (*get_device) (MateMixerStream *stream);
- MateMixerStreamFlags (*get_flags) (MateMixerStream *stream);
- MateMixerStreamState (*get_state) (MateMixerStream *stream);
- gboolean (*get_mute) (MateMixerStream *stream);
- gboolean (*set_mute) (MateMixerStream *stream,
- gboolean mute);
- guint (*get_num_channels) (MateMixerStream *stream);
- guint (*get_volume) (MateMixerStream *stream);
- gboolean (*set_volume) (MateMixerStream *stream,
- guint volume);
- gdouble (*get_decibel) (MateMixerStream *stream);
- gboolean (*set_decibel) (MateMixerStream *stream,
- gdouble decibel);
- MateMixerChannelPosition (*get_channel_position) (MateMixerStream *stream,
- guint channel);
- guint (*get_channel_volume) (MateMixerStream *stream,
- guint channel);
- gboolean (*set_channel_volume) (MateMixerStream *stream,
- guint channel,
- guint volume);
- gdouble (*get_channel_decibel) (MateMixerStream *stream,
- guint channel);
- gboolean (*set_channel_decibel) (MateMixerStream *stream,
- guint channel,
- gdouble decibel);
- gboolean (*has_channel_position) (MateMixerStream *stream,
- MateMixerChannelPosition position);
- gfloat (*get_balance) (MateMixerStream *stream);
- gboolean (*set_balance) (MateMixerStream *stream,
- gfloat balance);
- gfloat (*get_fade) (MateMixerStream *stream);
- gboolean (*set_fade) (MateMixerStream *stream,
- gfloat fade);
- gboolean (*suspend) (MateMixerStream *stream);
- gboolean (*resume) (MateMixerStream *stream);
- gboolean (*monitor_start) (MateMixerStream *stream);
- void (*monitor_stop) (MateMixerStream *stream);
- gboolean (*monitor_is_running) (MateMixerStream *stream);
- gboolean (*monitor_set_name) (MateMixerStream *stream,
- const gchar *name);
- const GList * (*list_ports) (MateMixerStream *stream);
- MateMixerPort * (*get_active_port) (MateMixerStream *stream);
- gboolean (*set_active_port) (MateMixerStream *stream,
- MateMixerPort *port);
- guint (*get_min_volume) (MateMixerStream *stream);
- guint (*get_max_volume) (MateMixerStream *stream);
- guint (*get_normal_volume) (MateMixerStream *stream);
- guint (*get_base_volume) (MateMixerStream *stream);
-
- /* Signals */
- void (*monitor_value) (MateMixerStream *stream,
- gdouble value);
+ MateMixerStreamPrivate *priv;
};
-GType mate_mixer_stream_get_type (void) G_GNUC_CONST;
-
-const gchar * mate_mixer_stream_get_name (MateMixerStream *stream);
-const gchar * mate_mixer_stream_get_description (MateMixerStream *stream);
-MateMixerDevice * mate_mixer_stream_get_device (MateMixerStream *stream);
-MateMixerStreamFlags mate_mixer_stream_get_flags (MateMixerStream *stream);
-MateMixerStreamState mate_mixer_stream_get_state (MateMixerStream *stream);
-
-gboolean mate_mixer_stream_get_mute (MateMixerStream *stream);
-gboolean mate_mixer_stream_set_mute (MateMixerStream *stream,
- gboolean mute);
-
-guint mate_mixer_stream_get_num_channels (MateMixerStream *stream);
+struct _MateMixerStreamClass
+{
+ GObjectClass parent_class;
-guint mate_mixer_stream_get_volume (MateMixerStream *stream);
-gboolean mate_mixer_stream_set_volume (MateMixerStream *stream,
- guint volume);
+ /*< private >*/
+ MateMixerStreamControl *(*get_control) (MateMixerStream *stream,
+ const gchar *name);
-gdouble mate_mixer_stream_get_decibel (MateMixerStream *stream);
-gboolean mate_mixer_stream_set_decibel (MateMixerStream *stream,
- gdouble decibel);
+ MateMixerStreamControl *(*get_default_control) (MateMixerStream *stream);
-MateMixerChannelPosition mate_mixer_stream_get_channel_position (MateMixerStream *stream,
- guint channel);
+ MateMixerSwitch *(*get_switch) (MateMixerStream *stream,
+ const gchar *name);
-guint mate_mixer_stream_get_channel_volume (MateMixerStream *stream,
- guint channel);
-gboolean mate_mixer_stream_set_channel_volume (MateMixerStream *stream,
- guint channel,
- guint volume);
+ GList *(*list_controls) (MateMixerStream *stream);
+ GList *(*list_switches) (MateMixerStream *stream);
-gdouble mate_mixer_stream_get_channel_decibel (MateMixerStream *stream,
- guint channel);
-gboolean mate_mixer_stream_set_channel_decibel (MateMixerStream *stream,
- guint channel,
- gdouble decibel);
+ gboolean (*suspend) (MateMixerStream *stream);
+ gboolean (*resume) (MateMixerStream *stream);
-gboolean mate_mixer_stream_has_channel_position (MateMixerStream *stream,
- MateMixerChannelPosition position);
+ gboolean (*monitor_start) (MateMixerStream *stream);
+ gboolean (*monitor_stop) (MateMixerStream *stream);
-gfloat mate_mixer_stream_get_balance (MateMixerStream *stream);
-gboolean mate_mixer_stream_set_balance (MateMixerStream *stream,
- gfloat balance);
+ /* Signals */
+ void (*monitor_value) (MateMixerStream *stream, gdouble value);
+};
-gfloat mate_mixer_stream_get_fade (MateMixerStream *stream);
-gboolean mate_mixer_stream_set_fade (MateMixerStream *stream,
- gfloat fade);
+GType mate_mixer_stream_get_type (void) G_GNUC_CONST;
-gboolean mate_mixer_stream_suspend (MateMixerStream *stream);
-gboolean mate_mixer_stream_resume (MateMixerStream *stream);
+const gchar * mate_mixer_stream_get_name (MateMixerStream *stream);
+MateMixerDevice * mate_mixer_stream_get_device (MateMixerStream *stream);
+MateMixerStreamFlags mate_mixer_stream_get_flags (MateMixerStream *stream);
+MateMixerStreamState mate_mixer_stream_get_state (MateMixerStream *stream);
-gboolean mate_mixer_stream_monitor_start (MateMixerStream *stream);
-void mate_mixer_stream_monitor_stop (MateMixerStream *stream);
+MateMixerStreamControl *mate_mixer_stream_get_control (MateMixerStream *stream,
+ const gchar *name);
+MateMixerSwitch * mate_mixer_stream_get_switch (MateMixerStream *stream,
+ const gchar *name);
-gboolean mate_mixer_stream_monitor_is_running (MateMixerStream *stream);
-gboolean mate_mixer_stream_monitor_set_name (MateMixerStream *stream,
- const gchar *name);
+MateMixerStreamControl *mate_mixer_stream_get_default_control (MateMixerStream *stream);
-const GList * mate_mixer_stream_list_ports (MateMixerStream *stream);
+const GList * mate_mixer_stream_list_controls (MateMixerStream *stream);
+const GList * mate_mixer_stream_list_switches (MateMixerStream *stream);
-MateMixerPort * mate_mixer_stream_get_active_port (MateMixerStream *stream);
-gboolean mate_mixer_stream_set_active_port (MateMixerStream *stream,
- MateMixerPort *port);
+gboolean mate_mixer_stream_suspend (MateMixerStream *stream);
+gboolean mate_mixer_stream_resume (MateMixerStream *stream);
-guint mate_mixer_stream_get_min_volume (MateMixerStream *stream);
-guint mate_mixer_stream_get_max_volume (MateMixerStream *stream);
-guint mate_mixer_stream_get_normal_volume (MateMixerStream *stream);
-guint mate_mixer_stream_get_base_volume (MateMixerStream *stream);
+gboolean mate_mixer_stream_monitor_get_enabled (MateMixerStream *stream);
+gboolean mate_mixer_stream_monitor_set_enabled (MateMixerStream *stream,
+ gboolean enabled);
G_END_DECLS
diff --git a/libmatemixer/matemixer-switch-option-private.h b/libmatemixer/matemixer-switch-option-private.h
new file mode 100644
index 0000000..dea7583
--- /dev/null
+++ b/libmatemixer/matemixer-switch-option-private.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the licence, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef MATEMIXER_SWITCH_OPTION_PRIVATE_H
+#define MATEMIXER_SWITCH_OPTION_PRIVATE_H
+
+#include <glib.h>
+
+#include "matemixer-switch-option.h"
+
+G_BEGIN_DECLS
+
+MateMixerSwitchOption *_mate_mixer_switch_option_new (const gchar *name,
+ const gchar *label,
+ const gchar *icon);
+
+G_END_DECLS
+
+#endif /* MATEMIXER_SWITCH_OPTION_PRIVATE_H */
diff --git a/libmatemixer/matemixer-switch-option.c b/libmatemixer/matemixer-switch-option.c
new file mode 100644
index 0000000..e924b46
--- /dev/null
+++ b/libmatemixer/matemixer-switch-option.c
@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the licence, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include "matemixer-switch-option.h"
+#include "matemixer-switch-option-private.h"
+
+/**
+ * SECTION:matemixer-stream-switch-option
+ * @include: libmatemixer/matemixer.h
+ */
+
+struct _MateMixerSwitchOptionPrivate
+{
+ gchar *name;
+ gchar *label;
+ gchar *icon;
+};
+
+enum {
+ PROP_0,
+ PROP_NAME,
+ PROP_LABEL,
+ PROP_ICON,
+ N_PROPERTIES
+};
+
+static GParamSpec *properties[N_PROPERTIES] = { NULL, };
+
+static void mate_mixer_switch_option_class_init (MateMixerSwitchOptionClass *klass);
+
+static void mate_mixer_switch_option_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec);
+static void mate_mixer_switch_option_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec);
+
+static void mate_mixer_switch_option_init (MateMixerSwitchOption *option);
+static void mate_mixer_switch_option_finalize (GObject *object);
+
+G_DEFINE_TYPE (MateMixerSwitchOption, mate_mixer_switch_option, G_TYPE_OBJECT)
+
+static void
+mate_mixer_switch_option_class_init (MateMixerSwitchOptionClass *klass)
+{
+ GObjectClass *object_class;
+
+ object_class = G_OBJECT_CLASS (klass);
+ object_class->finalize = mate_mixer_switch_option_finalize;
+ object_class->get_property = mate_mixer_switch_option_get_property;
+ object_class->set_property = mate_mixer_switch_option_set_property;
+
+ properties[PROP_NAME] =
+ g_param_spec_string ("name",
+ "Name",
+ "Name of the switch option",
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_LABEL] =
+ g_param_spec_string ("label",
+ "Label",
+ "Label of the switch option",
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_ICON] =
+ g_param_spec_string ("icon",
+ "Icon",
+ "Icon of the switch option",
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS);
+
+ g_object_class_install_properties (object_class, N_PROPERTIES, properties);
+
+ g_type_class_add_private (object_class, sizeof (MateMixerSwitchOptionPrivate));
+}
+
+static void
+mate_mixer_switch_option_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ MateMixerSwitchOption *option;
+
+ option = MATE_MIXER_SWITCH_OPTION (object);
+
+ switch (param_id) {
+ case PROP_NAME:
+ g_value_set_string (value, option->priv->name);
+ break;
+ case PROP_LABEL:
+ g_value_set_string (value, option->priv->label);
+ break;
+ case PROP_ICON:
+ g_value_set_string (value, option->priv->icon);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ }
+}
+
+static void
+mate_mixer_switch_option_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ MateMixerSwitchOption *option;
+
+ option = MATE_MIXER_SWITCH_OPTION (object);
+
+ switch (param_id) {
+ case PROP_NAME:
+ /* Construct-only string */
+ option->priv->name = g_value_dup_string (value);
+ break;
+ case PROP_LABEL:
+ /* Construct-only string */
+ option->priv->label = g_value_dup_string (value);
+ break;
+ case PROP_ICON:
+ /* Construct-only string */
+ option->priv->icon = g_value_dup_string (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ }
+}
+
+static void
+mate_mixer_switch_option_init (MateMixerSwitchOption *option)
+{
+ option->priv = G_TYPE_INSTANCE_GET_PRIVATE (option,
+ MATE_MIXER_TYPE_SWITCH_OPTION,
+ MateMixerSwitchOptionPrivate);
+}
+
+static void
+mate_mixer_switch_option_finalize (GObject *object)
+{
+ MateMixerSwitchOption *option;
+
+ option = MATE_MIXER_SWITCH_OPTION (object);
+
+ g_free (option->priv->name);
+ g_free (option->priv->label);
+ g_free (option->priv->icon);
+
+ G_OBJECT_CLASS (mate_mixer_switch_option_parent_class)->finalize (object);
+}
+
+/**
+ * mate_mixer_switch_option_get_name:
+ */
+const gchar *
+mate_mixer_switch_option_get_name (MateMixerSwitchOption *option)
+{
+ g_return_val_if_fail (MATE_MIXER_IS_SWITCH_OPTION (option), NULL);
+
+ return option->priv->name;
+}
+
+/**
+ * mate_mixer_switch_option_get_label:
+ */
+const gchar *
+mate_mixer_switch_option_get_label (MateMixerSwitchOption *option)
+{
+ g_return_val_if_fail (MATE_MIXER_IS_SWITCH_OPTION (option), NULL);
+
+ return option->priv->label;
+}
+
+/**
+ * mate_mixer_switch_option_get_icon:
+ */
+const gchar *
+mate_mixer_switch_option_get_icon (MateMixerSwitchOption *option)
+{
+ g_return_val_if_fail (MATE_MIXER_IS_SWITCH_OPTION (option), NULL);
+
+ return option->priv->icon;
+}
+
+MateMixerSwitchOption *
+_mate_mixer_switch_option_new (const gchar *name,
+ const gchar *label,
+ const gchar *icon)
+{
+ return g_object_new (MATE_MIXER_TYPE_SWITCH_OPTION,
+ "name", name,
+ "label", label,
+ "icon", icon,
+ NULL);
+}
diff --git a/libmatemixer/matemixer-switch-option.h b/libmatemixer/matemixer-switch-option.h
new file mode 100644
index 0000000..b02c42c
--- /dev/null
+++ b/libmatemixer/matemixer-switch-option.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the licence, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef MATEMIXER_SWITCH_OPTION_H
+#define MATEMIXER_SWITCH_OPTION_H
+
+#include <glib.h>
+#include <glib-object.h>
+#include <libmatemixer/matemixer-types.h>
+
+G_BEGIN_DECLS
+
+#define MATE_MIXER_TYPE_SWITCH_OPTION \
+ (mate_mixer_switch_option_get_type ())
+#define MATE_MIXER_SWITCH_OPTION(o) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((o), MATE_MIXER_TYPE_SWITCH_OPTION, MateMixerSwitchOption))
+#define MATE_MIXER_IS_SWITCH_OPTION(o) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((o), MATE_MIXER_TYPE_SWITCH_OPTION))
+#define MATE_MIXER_SWITCH_OPTION_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_CAST ((k), MATE_MIXER_TYPE_SWITCH_OPTION, MateMixerSwitchOptionClass))
+#define MATE_MIXER_IS_SWITCH_OPTION_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_TYPE ((k), MATE_MIXER_TYPE_SWITCH_OPTION))
+#define MATE_MIXER_SWITCH_OPTION_GET_CLASS(o) \
+ (G_TYPE_INSTANCE_GET_CLASS ((o), MATE_MIXER_TYPE_SWITCH_OPTION, MateMixerSwitchOptionClass))
+
+typedef struct _MateMixerSwitchOptionClass MateMixerSwitchOptionClass;
+typedef struct _MateMixerSwitchOptionPrivate MateMixerSwitchOptionPrivate;
+
+struct _MateMixerSwitchOption
+{
+ GObject parent;
+
+ /*< private >*/
+ MateMixerSwitchOptionPrivate *priv;
+};
+
+struct _MateMixerSwitchOptionClass
+{
+ GObjectClass parent_class;
+};
+
+GType mate_mixer_switch_option_get_type (void) G_GNUC_CONST;
+
+const gchar *mate_mixer_switch_option_get_name (MateMixerSwitchOption *option);
+const gchar *mate_mixer_switch_option_get_label (MateMixerSwitchOption *option);
+const gchar *mate_mixer_switch_option_get_icon (MateMixerSwitchOption *option);
+
+G_END_DECLS
+
+#endif /* MATEMIXER_SWITCH_OPTION_H */
diff --git a/libmatemixer/matemixer-switch-private.h b/libmatemixer/matemixer-switch-private.h
new file mode 100644
index 0000000..42390a9
--- /dev/null
+++ b/libmatemixer/matemixer-switch-private.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the licence, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef MATEMIXER_SWITCH_PRIVATE_H
+#define MATEMIXER_SWITCH_PRIVATE_H
+
+#include <glib.h>
+#include "matemixer-types.h"
+
+G_BEGIN_DECLS
+
+void _mate_mixer_switch_set_active_option (MateMixerSwitch *sw,
+ MateMixerSwitchOption *option);
+
+G_END_DECLS
+
+#endif /* MATEMIXER_SWITCH_PRIVATE_H */
diff --git a/libmatemixer/matemixer-switch.c b/libmatemixer/matemixer-switch.c
new file mode 100644
index 0000000..b30e405
--- /dev/null
+++ b/libmatemixer/matemixer-switch.c
@@ -0,0 +1,283 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the licence, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <string.h>
+#include <glib.h>
+#include <glib-object.h>
+
+#include "matemixer-enums.h"
+#include "matemixer-enum-types.h"
+#include "matemixer-switch.h"
+#include "matemixer-switch-private.h"
+#include "matemixer-switch-option.h"
+
+/**
+ * SECTION:matemixer-switch
+ * @include: libmatemixer/matemixer.h
+ */
+
+struct _MateMixerSwitchPrivate
+{
+ gchar *name;
+ gchar *label;
+ GList *options;
+ MateMixerSwitchOption *active;
+};
+
+enum {
+ PROP_0,
+ PROP_NAME,
+ PROP_LABEL,
+ PROP_ACTIVE_OPTION,
+ N_PROPERTIES
+};
+
+static GParamSpec *properties[N_PROPERTIES] = { NULL, };
+
+static void mate_mixer_switch_class_init (MateMixerSwitchClass *klass);
+
+static void mate_mixer_switch_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec);
+static void mate_mixer_switch_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec);
+
+static void mate_mixer_switch_init (MateMixerSwitch *swtch);
+static void mate_mixer_switch_finalize (GObject *object);
+
+G_DEFINE_ABSTRACT_TYPE (MateMixerSwitch, mate_mixer_switch, G_TYPE_OBJECT)
+
+static MateMixerSwitchOption *mate_mixer_switch_real_get_option (MateMixerSwitch *swtch,
+ const gchar *name);
+
+static void
+mate_mixer_switch_class_init (MateMixerSwitchClass *klass)
+{
+ GObjectClass *object_class;
+
+ klass->get_option = mate_mixer_switch_real_get_option;
+
+ object_class = G_OBJECT_CLASS (klass);
+ object_class->finalize = mate_mixer_switch_finalize;
+ object_class->get_property = mate_mixer_switch_get_property;
+ object_class->set_property = mate_mixer_switch_set_property;
+
+ properties[PROP_NAME] =
+ g_param_spec_string ("name",
+ "Name",
+ "Name of the switch",
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_LABEL] =
+ g_param_spec_string ("label",
+ "Label",
+ "Label of the switch",
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_ACTIVE_OPTION] =
+ g_param_spec_object ("active-option",
+ "Active option",
+ "Active option of the switch",
+ MATE_MIXER_TYPE_SWITCH_OPTION,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS);
+
+ g_object_class_install_properties (object_class, N_PROPERTIES, properties);
+
+ g_type_class_add_private (object_class, sizeof (MateMixerSwitchPrivate));
+}
+
+static void
+mate_mixer_switch_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ MateMixerSwitch *swtch;
+
+ swtch = MATE_MIXER_SWITCH (object);
+
+ switch (param_id) {
+ case PROP_NAME:
+ g_value_set_string (value, swtch->priv->name);
+ break;
+ case PROP_LABEL:
+ g_value_set_string (value, swtch->priv->label);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ }
+}
+
+static void
+mate_mixer_switch_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ MateMixerSwitch *swtch;
+
+ swtch = MATE_MIXER_SWITCH (object);
+
+ switch (param_id) {
+ case PROP_NAME:
+ /* Construct-only string */
+ swtch->priv->name = g_value_dup_string (value);
+ break;
+ case PROP_LABEL:
+ /* Construct-only string */
+ swtch->priv->label = g_value_dup_string (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ }
+}
+
+static void
+mate_mixer_switch_init (MateMixerSwitch *swtch)
+{
+ swtch->priv = G_TYPE_INSTANCE_GET_PRIVATE (swtch,
+ MATE_MIXER_TYPE_SWITCH,
+ MateMixerSwitchPrivate);
+}
+
+static void
+mate_mixer_switch_finalize (GObject *object)
+{
+ MateMixerSwitch *swtch;
+
+ swtch = MATE_MIXER_SWITCH (object);
+
+ g_free (swtch->priv->name);
+ g_free (swtch->priv->label);
+
+ G_OBJECT_CLASS (mate_mixer_switch_parent_class)->finalize (object);
+}
+
+const gchar *
+mate_mixer_switch_get_name (MateMixerSwitch *swtch)
+{
+ g_return_val_if_fail (MATE_MIXER_IS_SWITCH (swtch), NULL);
+
+ return swtch->priv->name;
+}
+
+const gchar *
+mate_mixer_switch_get_label (MateMixerSwitch *swtch)
+{
+ g_return_val_if_fail (MATE_MIXER_IS_SWITCH (swtch), NULL);
+
+ return swtch->priv->label;
+}
+
+MateMixerSwitchOption *
+mate_mixer_switch_get_option (MateMixerSwitch *swtch, const gchar *name)
+{
+ g_return_val_if_fail (MATE_MIXER_IS_SWITCH (swtch), NULL);
+
+ return MATE_MIXER_SWITCH_GET_CLASS (swtch)->get_option (swtch, name);
+}
+
+MateMixerSwitchOption *
+mate_mixer_switch_get_active_option (MateMixerSwitch *swtch)
+{
+ g_return_val_if_fail (MATE_MIXER_IS_SWITCH (swtch), NULL);
+
+ return swtch->priv->active;
+}
+
+gboolean
+mate_mixer_switch_set_active_option (MateMixerSwitch *swtch,
+ MateMixerSwitchOption *option)
+{
+ MateMixerSwitchClass *klass;
+
+ g_return_val_if_fail (MATE_MIXER_IS_SWITCH (swtch), FALSE);
+
+ klass = MATE_MIXER_SWITCH_GET_CLASS (swtch);
+ if (klass->set_active_option != NULL) {
+ if (klass->set_active_option (swtch, option) == FALSE)
+ return FALSE;
+
+ _mate_mixer_switch_set_active_option (swtch, option);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+const GList *
+mate_mixer_switch_list_options (MateMixerSwitch *swtch)
+{
+ g_return_val_if_fail (MATE_MIXER_IS_SWITCH (swtch), NULL);
+
+ if (swtch->priv->options == NULL) {
+ MateMixerSwitchClass *klass = MATE_MIXER_SWITCH_GET_CLASS (swtch);
+
+ if (klass->list_options != NULL)
+ swtch->priv->options = klass->list_options (swtch);
+ }
+ return (const GList *) swtch->priv->options;
+}
+
+void
+_mate_mixer_switch_set_active_option (MateMixerSwitch *swtch,
+ MateMixerSwitchOption *option)
+{
+ g_return_if_fail (MATE_MIXER_IS_SWITCH (swtch));
+ g_return_if_fail (MATE_MIXER_IS_SWITCH_OPTION (option));
+
+ if (swtch->priv->active == option)
+ return;
+
+ if (swtch->priv->active != NULL)
+ g_object_unref (swtch->priv->active);
+
+ swtch->priv->active = g_object_ref (option);
+
+ g_object_notify_by_pspec (G_OBJECT (swtch), properties[PROP_ACTIVE_OPTION]);
+}
+
+static MateMixerSwitchOption *
+mate_mixer_switch_real_get_option (MateMixerSwitch *swtch, const gchar *name)
+{
+ const GList *list;
+
+ g_return_val_if_fail (MATE_MIXER_IS_SWITCH (swtch), NULL);
+ g_return_val_if_fail (name != NULL, NULL);
+
+ list = mate_mixer_switch_list_options (swtch);
+ while (list != NULL) {
+ MateMixerSwitchOption *option = MATE_MIXER_SWITCH_OPTION (list->data);
+
+ if (strcmp (name, mate_mixer_switch_option_get_name (option)) == 0)
+ return option;
+
+ list = list->next;
+ }
+ return NULL;
+}
diff --git a/libmatemixer/matemixer-switch.h b/libmatemixer/matemixer-switch.h
new file mode 100644
index 0000000..3035607
--- /dev/null
+++ b/libmatemixer/matemixer-switch.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the licence, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef MATEMIXER_SWITCH_H
+#define MATEMIXER_SWITCH_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include <libmatemixer/matemixer-types.h>
+
+G_BEGIN_DECLS
+
+#define MATE_MIXER_TYPE_SWITCH \
+ (mate_mixer_switch_get_type ())
+#define MATE_MIXER_SWITCH(o) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((o), MATE_MIXER_TYPE_SWITCH, MateMixerSwitch))
+#define MATE_MIXER_IS_SWITCH(o) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((o), MATE_MIXER_TYPE_SWITCH))
+#define MATE_MIXER_SWITCH_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_CAST ((k), MATE_MIXER_TYPE_SWITCH, MateMixerSwitchClass))
+#define MATE_MIXER_IS_SWITCH_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_TYPE ((k), MATE_MIXER_TYPE_SWITCH))
+#define MATE_MIXER_SWITCH_GET_CLASS(o) \
+ (G_TYPE_INSTANCE_GET_CLASS ((o), MATE_MIXER_TYPE_SWITCH, MateMixerSwitchClass))
+
+typedef struct _MateMixerSwitchClass MateMixerSwitchClass;
+typedef struct _MateMixerSwitchPrivate MateMixerSwitchPrivate;
+
+struct _MateMixerSwitch
+{
+ GObject object;
+
+ /*< private >*/
+ MateMixerSwitchPrivate *priv;
+};
+
+struct _MateMixerSwitchClass
+{
+ GObjectClass parent_class;
+
+ /*< private >*/
+ MateMixerSwitchOption *(*get_option) (MateMixerSwitch *swtch,
+ const gchar *name);
+
+ gboolean (*set_active_option) (MateMixerSwitch *swtch,
+ MateMixerSwitchOption *option);
+
+ GList *(*list_options) (MateMixerSwitch *swtch);
+};
+
+GType mate_mixer_switch_get_type (void) G_GNUC_CONST;
+
+const gchar * mate_mixer_switch_get_name (MateMixerSwitch *swtch);
+const gchar * mate_mixer_switch_get_label (MateMixerSwitch *swtch);
+
+MateMixerSwitchOption *mate_mixer_switch_get_option (MateMixerSwitch *swtch,
+ const gchar *name);
+
+MateMixerSwitchOption *mate_mixer_switch_get_active_option (MateMixerSwitch *swtch);
+gboolean mate_mixer_switch_set_active_option (MateMixerSwitch *swtch,
+ MateMixerSwitchOption *option);
+
+const GList * mate_mixer_switch_list_options (MateMixerSwitch *swtch);
+
+G_END_DECLS
+
+#endif /* MATEMIXER_SWITCH_H */
diff --git a/libmatemixer/matemixer-toggle.c b/libmatemixer/matemixer-toggle.c
new file mode 100644
index 0000000..2eea599
--- /dev/null
+++ b/libmatemixer/matemixer-toggle.c
@@ -0,0 +1,254 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the licence, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <string.h>
+#include <glib.h>
+#include <glib-object.h>
+
+#include "matemixer-switch.h"
+#include "matemixer-switch-option.h"
+#include "matemixer-toggle.h"
+
+/**
+ * SECTION:matemixer-toggle
+ * @include: libmatemixer/matemixer.h
+ */
+
+struct _MateMixerTogglePrivate
+{
+ MateMixerSwitchOption *on;
+ MateMixerSwitchOption *off;
+};
+
+enum {
+ PROP_0,
+ PROP_STATE,
+ PROP_STATE_OPTION_ON,
+ PROP_STATE_OPTION_OFF,
+ N_PROPERTIES
+};
+
+static GParamSpec *properties[N_PROPERTIES] = { NULL, };
+
+static void mate_mixer_toggle_class_init (MateMixerToggleClass *klass);
+
+static void mate_mixer_toggle_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec);
+static void mate_mixer_toggle_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec);
+
+static void mate_mixer_toggle_init (MateMixerToggle *toggle);
+static void mate_mixer_toggle_dispose (GObject *object);
+
+G_DEFINE_ABSTRACT_TYPE (MateMixerToggle, mate_mixer_toggle, MATE_MIXER_TYPE_SWITCH)
+
+static MateMixerSwitchOption *mate_mixer_toggle_get_option (MateMixerSwitch *swtch,
+ const gchar *name);
+
+static GList * mate_mixer_toggle_list_options (MateMixerSwitch *swtch);
+
+static void
+mate_mixer_toggle_class_init (MateMixerToggleClass *klass)
+{
+ GObjectClass *object_class;
+ MateMixerSwitchClass *switch_class;
+
+ object_class = G_OBJECT_CLASS (klass);
+ object_class->dispose = mate_mixer_toggle_dispose;
+ object_class->get_property = mate_mixer_toggle_get_property;
+ object_class->set_property = mate_mixer_toggle_set_property;
+
+ switch_class = MATE_MIXER_SWITCH_CLASS (klass);
+ switch_class->get_option = mate_mixer_toggle_get_option;
+ switch_class->list_options = mate_mixer_toggle_list_options;
+
+ properties[PROP_STATE] =
+ g_param_spec_boolean ("state",
+ "State",
+ "Current state",
+ FALSE,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_STATE_OPTION_ON] =
+ g_param_spec_object ("state-option-on",
+ "State option for on",
+ "Option corresponding to the 'on' value of the toggle",
+ MATE_MIXER_TYPE_SWITCH_OPTION,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_STATE_OPTION_OFF] =
+ g_param_spec_object ("state-option-off",
+ "State option for off",
+ "Option corresponding to the 'off' value of the toggle",
+ MATE_MIXER_TYPE_SWITCH_OPTION,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS);
+
+ g_object_class_install_properties (object_class, N_PROPERTIES, properties);
+
+ g_type_class_add_private (object_class, sizeof (MateMixerTogglePrivate));
+}
+
+static void
+mate_mixer_toggle_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ MateMixerToggle *toggle;
+
+ toggle = MATE_MIXER_TOGGLE (object);
+
+ switch (param_id) {
+ case PROP_STATE:
+ g_value_set_boolean (value, mate_mixer_toggle_get_state (toggle));
+ break;
+ case PROP_STATE_OPTION_ON:
+ g_value_set_object (value, toggle->priv->on);
+ break;
+ case PROP_STATE_OPTION_OFF:
+ g_value_set_object (value, toggle->priv->off);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ }
+}
+
+static void
+mate_mixer_toggle_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ MateMixerToggle *toggle;
+
+ toggle = MATE_MIXER_TOGGLE (object);
+
+ switch (param_id) {
+ case PROP_STATE_OPTION_ON:
+ /* Construct-only object */
+ toggle->priv->on = g_value_dup_object (value);
+ break;
+ case PROP_STATE_OPTION_OFF:
+ /* Construct-only object */
+ toggle->priv->off = g_value_dup_object (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ }
+}
+
+static void
+mate_mixer_toggle_init (MateMixerToggle *toggle)
+{
+ toggle->priv = G_TYPE_INSTANCE_GET_PRIVATE (toggle,
+ MATE_MIXER_TYPE_TOGGLE,
+ MateMixerTogglePrivate);
+}
+
+static void
+mate_mixer_toggle_dispose (GObject *object)
+{
+ MateMixerToggle *toggle;
+
+ toggle = MATE_MIXER_TOGGLE (object);
+
+ g_clear_object (&toggle->priv->on);
+ g_clear_object (&toggle->priv->off);
+
+ G_OBJECT_CLASS (mate_mixer_toggle_parent_class)->dispose (object);
+}
+
+gboolean
+mate_mixer_toggle_get_state (MateMixerToggle *toggle)
+{
+ MateMixerSwitchOption *active;
+
+ g_return_val_if_fail (MATE_MIXER_IS_TOGGLE (toggle), FALSE);
+
+ active = mate_mixer_switch_get_active_option (MATE_MIXER_SWITCH (toggle));
+ if (active == toggle->priv->on)
+ return TRUE;
+ else
+ return FALSE;
+}
+
+MateMixerSwitchOption *
+mate_mixer_toggle_get_state_option (MateMixerToggle *toggle, gboolean state)
+{
+ g_return_val_if_fail (MATE_MIXER_IS_TOGGLE (toggle), NULL);
+
+ if (state == TRUE)
+ return toggle->priv->on;
+ else
+ return toggle->priv->off;
+}
+
+gboolean
+mate_mixer_toggle_set_state (MateMixerToggle *toggle, gboolean state)
+{
+ MateMixerSwitchOption *active;
+
+ g_return_val_if_fail (MATE_MIXER_IS_TOGGLE (toggle), FALSE);
+
+ if (state == TRUE)
+ active = toggle->priv->on;
+ else
+ active = toggle->priv->off;
+
+ return mate_mixer_switch_set_active_option (MATE_MIXER_SWITCH (toggle), active);
+}
+
+static MateMixerSwitchOption *
+mate_mixer_toggle_get_option (MateMixerSwitch *swtch, const gchar *name)
+{
+ MateMixerToggle *toggle;
+
+ g_return_val_if_fail (MATE_MIXER_IS_TOGGLE (swtch), NULL);
+
+ toggle = MATE_MIXER_TOGGLE (swtch);
+
+ if (strcmp (name, mate_mixer_switch_option_get_name (toggle->priv->on)) == 0)
+ return toggle->priv->on;
+ if (strcmp (name, mate_mixer_switch_option_get_name (toggle->priv->off)) == 0)
+ return toggle->priv->off;
+
+ return NULL;
+}
+
+static GList *
+mate_mixer_toggle_list_options (MateMixerSwitch *swtch)
+{
+ GList *list = NULL;
+
+ g_return_val_if_fail (MATE_MIXER_IS_TOGGLE (swtch), NULL);
+
+ list = g_list_prepend (list, MATE_MIXER_TOGGLE (swtch)->priv->off);
+ list = g_list_prepend (list, MATE_MIXER_TOGGLE (swtch)->priv->on);
+
+ return list;
+}
diff --git a/libmatemixer/matemixer-toggle.h b/libmatemixer/matemixer-toggle.h
new file mode 100644
index 0000000..1cedfc5
--- /dev/null
+++ b/libmatemixer/matemixer-toggle.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the licence, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef MATEMIXER_TOGGLE_H
+#define MATEMIXER_TOGGLE_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include <libmatemixer/matemixer-types.h>
+
+G_BEGIN_DECLS
+
+#define MATE_MIXER_TYPE_TOGGLE \
+ (mate_mixer_toggle_get_type ())
+#define MATE_MIXER_TOGGLE(o) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((o), MATE_MIXER_TYPE_TOGGLE, MateMixerToggle))
+#define MATE_MIXER_IS_TOGGLE(o) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((o), MATE_MIXER_TYPE_TOGGLE))
+#define MATE_MIXER_TOGGLE_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_CAST ((k), MATE_MIXER_TYPE_TOGGLE, MateMixerToggleClass))
+#define MATE_MIXER_IS_TOGGLE_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_TYPE ((k), MATE_MIXER_TYPE_TOGGLE))
+#define MATE_MIXER_TOGGLE_GET_CLASS(o) \
+ (G_TYPE_INSTANCE_GET_CLASS ((o), MATE_MIXER_TYPE_TOGGLE, MateMixerToggleClass))
+
+typedef struct _MateMixerToggleClass MateMixerToggleClass;
+typedef struct _MateMixerTogglePrivate MateMixerTogglePrivate;
+
+struct _MateMixerToggle
+{
+ MateMixerSwitch object;
+
+ /*< private >*/
+ MateMixerTogglePrivate *priv;
+};
+
+struct _MateMixerToggleClass
+{
+ MateMixerSwitchClass parent_class;
+};
+
+GType mate_mixer_toggle_get_type (void) G_GNUC_CONST;
+
+gboolean mate_mixer_toggle_get_state (MateMixerToggle *toggle);
+gboolean mate_mixer_toggle_set_state (MateMixerToggle *toggle,
+ gboolean state);
+
+MateMixerSwitchOption *mate_mixer_toggle_get_state_option (MateMixerToggle *toggle,
+ gboolean state);
+
+G_END_DECLS
+
+#endif /* MATEMIXER_TOGGLE_H */
diff --git a/libmatemixer/matemixer-types.h b/libmatemixer/matemixer-types.h
new file mode 100644
index 0000000..6601a95
--- /dev/null
+++ b/libmatemixer/matemixer-types.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the licence, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef MATEMIXER_TYPES_H
+#define MATEMIXER_TYPES_H
+
+G_BEGIN_DECLS
+
+typedef struct _MateMixerDevice MateMixerDevice;
+typedef struct _MateMixerClientStream MateMixerClientStream;
+typedef struct _MateMixerContext MateMixerContext;
+typedef struct _MateMixerDeviceProfile MateMixerDeviceProfile;
+typedef struct _MateMixerStream MateMixerStream;
+typedef struct _MateMixerStreamControl MateMixerStreamControl;
+typedef struct _MateMixerSwitch MateMixerSwitch;
+typedef struct _MateMixerSwitchOption MateMixerSwitchOption;
+typedef struct _MateMixerToggle MateMixerToggle;
+
+G_END_DECLS
+
+#endif /* MATEMIXER_TYPES_H */
diff --git a/libmatemixer/matemixer.c b/libmatemixer/matemixer.c
index 0ca09b9..fa83e3f 100644
--- a/libmatemixer/matemixer.c
+++ b/libmatemixer/matemixer.c
@@ -54,6 +54,10 @@ mate_mixer_init (void)
if (initialized == TRUE)
return TRUE;
+#if !GLIB_CHECK_VERSION (2, 36, 0)
+ g_type_init ();
+#endif
+
load_modules ();
if (modules != NULL) {
@@ -96,33 +100,25 @@ mate_mixer_is_initialized (void)
return initialized;
}
-/**
- * mate_mixer_deinit:
- *
- * Deinitializes the library. You should call this function when you are done
- * using the library.
- */
-void
-mate_mixer_deinit (void)
+/* Return a list of loaded backend modules */
+const GList *
+_mate_mixer_get_modules (void)
{
- GList *list;
-
- if (initialized == FALSE)
- return;
-
- list = modules;
- while (list != NULL) {
- g_type_module_unuse (G_TYPE_MODULE (list->data));
- list = list->next;
- }
- initialized = FALSE;
+ return (const GList *) modules;
}
-/* Internal function: return a list of loaded backend modules */
-const GList *
-mate_mixer_get_modules (void)
+guint32
+_mate_mixer_create_channel_mask (MateMixerChannelPosition *positions, guint n)
{
- return (const GList *) modules;
+ guint32 mask = 0;
+ guint i = 0;
+
+ for (i = 0; i < n; i++) {
+ if (positions[i] > MATE_MIXER_CHANNEL_UNKNOWN &&
+ positions[i] < MATE_MIXER_CHANNEL_MAX)
+ mask |= 1 << positions[i];
+ }
+ return mask;
}
static void
@@ -150,7 +146,8 @@ load_modules (void)
continue;
file = g_build_filename (LIBMATEMIXER_BACKEND_DIR, name, NULL);
- modules = g_list_prepend (modules, mate_mixer_backend_module_new (file));
+ modules = g_list_prepend (modules,
+ mate_mixer_backend_module_new (file));
g_free (file);
}
diff --git a/libmatemixer/matemixer.h b/libmatemixer/matemixer.h
index 36a3d39..a6eac79 100644
--- a/libmatemixer/matemixer.h
+++ b/libmatemixer/matemixer.h
@@ -22,19 +22,21 @@
#include <glib-object.h>
#include <libmatemixer/matemixer-client-stream.h>
-#include <libmatemixer/matemixer-control.h>
+#include <libmatemixer/matemixer-context.h>
#include <libmatemixer/matemixer-device.h>
#include <libmatemixer/matemixer-device-profile.h>
#include <libmatemixer/matemixer-enums.h>
-#include <libmatemixer/matemixer-port.h>
#include <libmatemixer/matemixer-stream.h>
+#include <libmatemixer/matemixer-stream-control.h>
+#include <libmatemixer/matemixer-switch.h>
+#include <libmatemixer/matemixer-switch-option.h>
+#include <libmatemixer/matemixer-toggle.h>
#include <libmatemixer/matemixer-version.h>
G_BEGIN_DECLS
gboolean mate_mixer_init (void);
gboolean mate_mixer_is_initialized (void);
-void mate_mixer_deinit (void);
G_END_DECLS