summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--backends/Makefile.am4
-rw-r--r--backends/oss4/Makefile.am29
-rw-r--r--backends/oss4/oss4-backend.c487
-rw-r--r--backends/oss4/oss4-backend.h62
-rw-r--r--backends/oss4/oss4-common.h38
-rw-r--r--backends/oss4/oss4-device.c328
-rw-r--r--backends/oss4/oss4-device.h72
-rw-r--r--configure.ac36
-rw-r--r--libmatemixer/matemixer-device.c9
9 files changed, 1062 insertions, 3 deletions
diff --git a/backends/Makefile.am b/backends/Makefile.am
index 8ca01bd..0cf8dd4 100644
--- a/backends/Makefile.am
+++ b/backends/Makefile.am
@@ -12,4 +12,8 @@ if HAVE_OSS
SUBDIRS += oss
endif
+if HAVE_OSS4
+SUBDIRS += oss4
+endif
+
-include $(top_srcdir)/git.mk
diff --git a/backends/oss4/Makefile.am b/backends/oss4/Makefile.am
new file mode 100644
index 0000000..cca8723
--- /dev/null
+++ b/backends/oss4/Makefile.am
@@ -0,0 +1,29 @@
+backenddir = $(libdir)/libmatemixer
+
+backend_LTLIBRARIES = libmatemixer-oss4.la
+
+AM_CPPFLAGS = \
+ -I$(top_srcdir) \
+ -DG_LOG_DOMAIN=\"libmatemixer-oss4\"
+
+libmatemixer_oss4_la_CFLAGS = \
+ $(GLIB_CFLAGS) \
+ $(OSS4_CFLAGS)
+
+libmatemixer_oss4_la_SOURCES = \
+ oss4-common.h \
+ oss4-backend.c \
+ oss4-backend.h \
+ oss4-device.c \
+ oss4-device.h
+
+libmatemixer_oss4_la_LIBADD = \
+ $(GLIB_LIBS)
+
+libmatemixer_oss4_la_LDFLAGS = \
+ -avoid-version \
+ -no-undefined \
+ -export-dynamic \
+ -module
+
+-include $(top_srcdir)/git.mk
diff --git a/backends/oss4/oss4-backend.c b/backends/oss4/oss4-backend.c
new file mode 100644
index 0000000..bd79fdf
--- /dev/null
+++ b/backends/oss4/oss4-backend.c
@@ -0,0 +1,487 @@
+/*
+ * 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-object.h>
+#include <glib/gstdio.h>
+#include <glib/gprintf.h>
+#include <glib/gi18n.h>
+#include <gio/gio.h>
+
+#include <libmatemixer/matemixer-backend.h>
+#include <libmatemixer/matemixer-backend-module.h>
+#include <libmatemixer/matemixer-enums.h>
+#include <libmatemixer/matemixer-stream.h>
+
+#include "oss4-backend.h"
+#include "oss4-common.h"
+#include "oss4-device.h"
+
+#define BACKEND_NAME "OSS4"
+#define BACKEND_PRIORITY 8
+
+#define PATH_SNDSTAT "/dev/sndstat"
+
+struct _Oss4BackendPrivate
+{
+ gint fd;
+ gchar *sndstat;
+ GHashTable *devices;
+ GHashTable *streams;
+ MateMixerStream *default_input;
+ MateMixerStream *default_output;
+ MateMixerState state;
+};
+
+enum {
+ PROP_0,
+ PROP_STATE,
+ PROP_DEFAULT_INPUT,
+ PROP_DEFAULT_OUTPUT
+};
+
+static void mate_mixer_backend_interface_init (MateMixerBackendInterface *iface);
+
+static void oss4_backend_class_init (Oss4BackendClass *klass);
+static void oss4_backend_class_finalize (Oss4BackendClass *klass);
+
+static void oss4_backend_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec);
+
+static void oss4_backend_init (Oss4Backend *oss);
+static void oss4_backend_dispose (GObject *object);
+static void oss4_backend_finalize (GObject *object);
+
+G_DEFINE_DYNAMIC_TYPE_EXTENDED (Oss4Backend, oss4_backend,
+ G_TYPE_OBJECT, 0,
+ G_IMPLEMENT_INTERFACE_DYNAMIC (MATE_MIXER_TYPE_BACKEND,
+ mate_mixer_backend_interface_init))
+
+static gboolean oss4_backend_open (MateMixerBackend *backend);
+static void oss4_backend_close (MateMixerBackend *backend);
+static GList * oss4_backend_list_devices (MateMixerBackend *backend);
+static GList * oss4_backend_list_streams (MateMixerBackend *backend);
+
+static void change_state (Oss4Backend *oss,
+ MateMixerState state);
+
+static gboolean read_device (Oss4Backend *oss, gint index);
+
+static gchar * read_device_sndstat_description (Oss4Backend *oss,
+ const gchar *prefix);
+
+static void add_device (Oss4Backend *oss, Oss4Device *device);
+static void remove_device (Oss4Backend *oss, Oss4Device *device);
+
+static MateMixerBackendInfo info;
+
+void
+backend_module_init (GTypeModule *module)
+{
+ oss4_backend_register_type (module);
+
+ info.name = BACKEND_NAME;
+ info.priority = BACKEND_PRIORITY;
+ info.g_type = OSS4_TYPE_BACKEND;
+ info.backend_type = MATE_MIXER_BACKEND_OSS4;
+}
+
+const MateMixerBackendInfo *backend_module_get_info (void)
+{
+ return &info;
+}
+
+static void
+mate_mixer_backend_interface_init (MateMixerBackendInterface *iface)
+{
+ iface->open = oss4_backend_open;
+ iface->close = oss4_backend_close;
+ iface->list_devices = oss4_backend_list_devices;
+ iface->list_streams = oss4_backend_list_streams;
+}
+
+static void
+oss4_backend_class_init (Oss4BackendClass *klass)
+{
+ GObjectClass *object_class;
+
+ object_class = G_OBJECT_CLASS (klass);
+ object_class->dispose = oss4_backend_dispose;
+ object_class->finalize = oss4_backend_finalize;
+ object_class->get_property = oss4_backend_get_property;
+
+ g_object_class_override_property (object_class, PROP_STATE, "state");
+ g_object_class_override_property (object_class, PROP_DEFAULT_INPUT, "default-input");
+ g_object_class_override_property (object_class, PROP_DEFAULT_OUTPUT, "default-output");
+
+ g_type_class_add_private (object_class, sizeof (Oss4BackendPrivate));
+}
+
+/* Called in the code generated by G_DEFINE_DYNAMIC_TYPE_EXTENDED() */
+static void
+oss4_backend_class_finalize (Oss4BackendClass *klass)
+{
+}
+
+static void
+oss4_backend_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ Oss4Backend *oss;
+
+ oss = OSS4_BACKEND (object);
+
+ switch (param_id) {
+ case PROP_STATE:
+ g_value_set_enum (value, oss->priv->state);
+ break;
+ case PROP_DEFAULT_INPUT:
+ g_value_set_object (value, oss->priv->default_input);
+ break;
+ case PROP_DEFAULT_OUTPUT:
+ g_value_set_object (value, oss->priv->default_output);
+ break;
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ }
+}
+
+static void
+oss4_backend_init (Oss4Backend *oss)
+{
+ oss->priv = G_TYPE_INSTANCE_GET_PRIVATE (oss,
+ OSS4_TYPE_BACKEND,
+ Oss4BackendPrivate);
+
+ oss->priv->devices = g_hash_table_new_full (g_direct_hash,
+ g_direct_equal,
+ NULL,
+ g_object_unref);
+
+ oss->priv->streams = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ g_free,
+ g_object_unref);
+}
+
+static void
+oss4_backend_dispose (GObject *object)
+{
+ oss4_backend_close (MATE_MIXER_BACKEND (object));
+}
+
+static void
+oss4_backend_finalize (GObject *object)
+{
+ Oss4Backend *oss;
+
+ oss = OSS4_BACKEND (object);
+
+ g_hash_table_destroy (oss->priv->devices);
+ g_hash_table_destroy (oss->priv->streams);
+}
+
+static gboolean
+oss4_backend_open (MateMixerBackend *backend)
+{
+ Oss4Backend *oss;
+ gint fd;
+ gint i;
+ gint ret;
+ struct oss_sysinfo info;
+
+ g_return_val_if_fail (OSS4_IS_BACKEND (backend), FALSE);
+
+ oss = OSS4_BACKEND (backend);
+
+ fd = g_open ("/dev/mixer", O_RDONLY, 0);
+ if (fd == -1)
+ fd = g_open ("/dev/mixer0", O_RDONLY, 0);
+ if (fd == -1) {
+ change_state (oss, MATE_MIXER_STATE_FAILED);
+ return FALSE;
+ }
+
+ /* Query the number of mixer devices */
+ ret = ioctl (fd, OSS_SYSINFO, &info);
+ if (ret == -1) {
+ close (fd);
+ change_state (oss, MATE_MIXER_STATE_FAILED);
+ return FALSE;
+ }
+
+ g_debug ("The sound system is %s version %s",
+ info.product,
+ info.version);
+
+#if !defined(__linux__)
+ /* At least on systems based on FreeBSD we will need to read devices names
+ * from the sndstat file, but avoid even trying that on systems where this
+ * is not needed and the file is not present */
+ oss->priv->sndstat = PATH_SNDSTAT;
+#endif
+
+ oss->priv->fd = fd;
+
+ for (i = 0; i < info.nummixers; i++)
+ read_device (oss, i);
+
+ change_state (oss, MATE_MIXER_STATE_READY);
+ return TRUE;
+}
+
+void
+oss4_backend_close (MateMixerBackend *backend)
+{
+ Oss4Backend *oss;
+
+ g_return_if_fail (OSS4_IS_BACKEND (backend));
+
+ oss = OSS4_BACKEND (backend);
+
+ g_clear_object (&oss->priv->default_input);
+ g_clear_object (&oss->priv->default_output);
+
+ g_hash_table_remove_all (oss->priv->streams);
+ g_hash_table_remove_all (oss->priv->devices);
+}
+
+static GList *
+oss4_backend_list_devices (MateMixerBackend *backend)
+{
+ GList *list;
+
+ g_return_val_if_fail (OSS4_IS_BACKEND (backend), NULL);
+
+ /* Convert the hash table to a sorted linked list, this list is expected
+ * to be cached in the main library */
+ list = g_hash_table_get_values (OSS4_BACKEND (backend)->priv->devices);
+ if (list != NULL) {
+ g_list_foreach (list, (GFunc) g_object_ref, NULL);
+
+ return list;
+ }
+ return NULL;
+}
+
+static GList *
+oss4_backend_list_streams (MateMixerBackend *backend)
+{
+ GList *list;
+
+ g_return_val_if_fail (OSS4_IS_BACKEND (backend), NULL);
+
+ /* Convert the hash table to a sorted linked list, this list is expected
+ * to be cached in the main library */
+ list = g_hash_table_get_values (OSS4_BACKEND (backend)->priv->streams);
+ if (list != NULL) {
+ g_list_foreach (list, (GFunc) g_object_ref, NULL);
+
+ return list;
+ }
+ return NULL;
+}
+
+static void
+change_state (Oss4Backend *oss, MateMixerState state)
+{
+ if (oss->priv->state == state)
+ return;
+
+ oss->priv->state = state;
+
+ g_object_notify (G_OBJECT (oss), "state");
+}
+
+static gboolean
+read_device (Oss4Backend *oss, gint index)
+{
+ Oss4Device *device;
+ gboolean ret;
+ gchar *description = NULL;
+ struct oss_mixerinfo info;
+
+ /* We assume that the name and capabilities of a device do not change */
+ device = g_hash_table_lookup (oss->priv->devices, GINT_TO_POINTER (index));
+ if (G_UNLIKELY (device != NULL)) {
+ g_debug ("Attempt to re-read already know device with index %d", index);
+ return TRUE;
+ }
+
+ info.dev = index;
+ ret = ioctl (oss->priv->fd, SNDCTL_MIXERINFO, &info);
+ if (ret == -1) {
+ g_debug ("Failed to read mixer info: %s", g_strerror (errno));
+ return FALSE;
+ }
+
+ if (info.enabled == 0)
+ return TRUE;
+
+ /* Use the id as the device name and try to figure out the name of the
+ * sound card from the sndstat file if it is available, otherwise use
+ * the name from the mixer info */
+ if (oss->priv->sndstat != NULL &&
+ g_str_has_prefix (info.name, "pcm") == TRUE)
+ description = read_device_sndstat_description (oss, info.name);
+
+ if (description == NULL)
+ description = g_strdup (info.name);
+
+ device = oss4_device_new (info.id, description, oss->priv->fd, index);
+
+ ret = oss4_device_read (device);
+ if (ret == TRUE)
+ add_device (oss, device);
+
+ g_object_unref (device);
+ g_free (description);
+
+ return ret;
+}
+
+static gchar *
+read_device_sndstat_description (Oss4Backend *oss, const gchar *prefix)
+{
+ FILE *fp;
+ gchar line[256];
+ gchar *description = NULL;
+
+ g_debug ("reading prefix %s", prefix);
+
+ fp = fopen (oss->priv->sndstat, "r");
+ if (fp == NULL) {
+ g_warning ("Failed to read %s: %s", oss->priv->sndstat, g_strerror (errno));
+ return FALSE;
+ }
+
+ while (fgets (line, sizeof (line), fp) != NULL) {
+ gchar *p;
+
+ if (g_str_has_prefix (line, prefix) == FALSE)
+ continue;
+
+ /* Example line:
+ * pcm0: <ATI R6xx (HDMI)> (play) default */
+ p = strchr (line, '<');
+ if (p != NULL && *p && *(++p)) {
+ gchar *end = strchr (p, '>');
+
+ if (end != NULL)
+ description = g_strndup (p, end - p);
+ }
+
+ // XXX we can also read "default" at the end of the line
+ // XXX http://ashish.is.lostca.se/2011/05/23/default-sound-device-in-freebsd/
+ if (g_str_has_suffix (line, "default") ||
+ g_str_has_suffix (line, "default)"))
+ ;
+
+ if (description != NULL)
+ break;
+ }
+
+ fclose (fp);
+ return description;
+}
+
+static void
+add_device (Oss4Backend *oss, Oss4Device *device)
+{
+ MateMixerStream *stream;
+
+ /* Add device, file path is used as the key rather than the name, because
+ * the name is not known until an OssDevice instance is created */
+ g_hash_table_insert (oss->priv->devices,
+ GINT_TO_POINTER (oss4_device_get_index (device)),
+ g_object_ref (device));
+
+ g_signal_emit_by_name (G_OBJECT (oss),
+ "device-added",
+ mate_mixer_device_get_name (MATE_MIXER_DEVICE (device)));
+
+ /* Add streams if they exist */
+ stream = oss4_device_get_input_stream (device);
+ if (stream != NULL) {
+ g_hash_table_insert (oss->priv->streams,
+ g_strdup (mate_mixer_stream_get_name (stream)),
+ g_object_ref (stream));
+
+ g_signal_emit_by_name (G_OBJECT (oss),
+ "stream-added",
+ mate_mixer_stream_get_name (stream));
+ }
+
+ stream = oss4_device_get_output_stream (device);
+ if (stream != NULL) {
+ g_hash_table_insert (oss->priv->streams,
+ g_strdup (mate_mixer_stream_get_name (stream)),
+ g_object_ref (stream));
+
+ g_signal_emit_by_name (G_OBJECT (oss),
+ "stream-added",
+ mate_mixer_stream_get_name (stream));
+ }
+}
+
+static void
+remove_device (Oss4Backend *oss, Oss4Device *device)
+{
+ MateMixerStream *stream;
+
+ /* Remove the device streams first as they are a part of the device */
+ stream = oss4_device_get_input_stream (device);
+ if (stream != NULL) {
+ const gchar *name = mate_mixer_stream_get_name (stream);
+
+ g_hash_table_remove (oss->priv->streams, name);
+ g_signal_emit_by_name (G_OBJECT (oss),
+ "stream-removed",
+ name);
+ }
+
+ stream = oss4_device_get_output_stream (device);
+ if (stream != NULL) {
+ const gchar *name = mate_mixer_stream_get_name (stream);
+
+ g_hash_table_remove (oss->priv->streams, stream);
+ g_signal_emit_by_name (G_OBJECT (oss),
+ "stream-removed",
+ name);
+ }
+
+ /* Remove the device */
+ g_object_ref (device);
+
+ g_hash_table_remove (oss->priv->devices,
+ GINT_TO_POINTER (oss4_device_get_index (device)));
+
+ g_signal_emit_by_name (G_OBJECT (oss),
+ "device-removed",
+ mate_mixer_device_get_name (MATE_MIXER_DEVICE (device)));
+
+ g_object_unref (device);
+}
diff --git a/backends/oss4/oss4-backend.h b/backends/oss4/oss4-backend.h
new file mode 100644
index 0000000..bc89e72
--- /dev/null
+++ b/backends/oss4/oss4-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 OSS4_BACKEND_H
+#define OSS4_BACKEND_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include <libmatemixer/matemixer-backend-module.h>
+
+#define OSS4_TYPE_BACKEND \
+ (oss4_backend_get_type ())
+#define OSS4_BACKEND(o) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((o), OSS4_TYPE_BACKEND, Oss4Backend))
+#define OSS4_IS_BACKEND(o) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((o), OSS4_TYPE_BACKEND))
+#define OSS4_BACKEND_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_CAST ((k), OSS4_TYPE_BACKEND, Oss4BackendClass))
+#define OSS4_IS_BACKEND_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_TYPE ((k), OSS4_TYPE_BACKEND))
+#define OSS4_BACKEND_GET_CLASS(o) \
+ (G_TYPE_INSTANCE_GET_CLASS ((o), OSS4_TYPE_BACKEND, Oss4BackendClass))
+
+typedef struct _Oss4Backend Oss4Backend;
+typedef struct _Oss4BackendClass Oss4BackendClass;
+typedef struct _Oss4BackendPrivate Oss4BackendPrivate;
+
+struct _Oss4Backend
+{
+ GObject parent;
+
+ /*< private >*/
+ Oss4BackendPrivate *priv;
+};
+
+struct _Oss4BackendClass
+{
+ GObjectClass parent_class;
+};
+
+GType oss4_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 /* OSS4_BACKEND_H */
diff --git a/backends/oss4/oss4-common.h b/backends/oss4/oss4-common.h
new file mode 100644
index 0000000..fe55b2b
--- /dev/null
+++ b/backends/oss4/oss4-common.h
@@ -0,0 +1,38 @@
+/*
+ * 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 OSS4_COMMON_H
+#define OSS4_COMMON_H
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <fcntl.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 OSS4 header file present"
+#endif
+
+#endif /* OSS4_COMMON_H */
diff --git a/backends/oss4/oss4-device.c b/backends/oss4/oss4-device.c
new file mode 100644
index 0000000..b68648b
--- /dev/null
+++ b/backends/oss4/oss4-device.c
@@ -0,0 +1,328 @@
+/*
+ * 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-device.h>
+#include <libmatemixer/matemixer-enums.h>
+#include <libmatemixer/matemixer-port.h>
+#include <libmatemixer/matemixer-port-private.h>
+#include <libmatemixer/matemixer-stream.h>
+#include <libmatemixer/matemixer-stream-control.h>
+
+#include "oss4-common.h"
+#include "oss4-device.h"
+
+#define OSS4_DEVICE_ICON "audio-card"
+
+struct _Oss4DevicePrivate
+{
+ gint fd;
+ gint index;
+ gchar *name;
+ gchar *description;
+ gchar *icon;
+ MateMixerStream *input;
+ MateMixerStream *output;
+};
+
+enum {
+ PROP_0,
+ PROP_NAME,
+ PROP_DESCRIPTION,
+ PROP_ICON,
+ PROP_ACTIVE_PROFILE,
+ PROP_FD,
+ PROP_INDEX
+};
+
+static void mate_mixer_device_interface_init (MateMixerDeviceInterface *iface);
+
+static void oss4_device_class_init (Oss4DeviceClass *klass);
+
+static void oss4_device_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec);
+static void oss4_device_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec);
+
+static void oss4_device_init (Oss4Device *device);
+static void oss4_device_finalize (GObject *object);
+
+G_DEFINE_TYPE_WITH_CODE (Oss4Device, oss4_device, G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (MATE_MIXER_TYPE_DEVICE,
+ mate_mixer_device_interface_init))
+
+static const gchar *oss4_device_get_name (MateMixerDevice *device);
+static const gchar *oss4_device_get_description (MateMixerDevice *device);
+static const gchar *oss4_device_get_icon (MateMixerDevice *device);
+
+static gboolean read_mixer_devices (Oss4Device *device);
+
+static void
+mate_mixer_device_interface_init (MateMixerDeviceInterface *iface)
+{
+ iface->get_name = oss4_device_get_name;
+ iface->get_description = oss4_device_get_description;
+ iface->get_icon = oss4_device_get_icon;
+}
+
+static void
+oss4_device_class_init (Oss4DeviceClass *klass)
+{
+ GObjectClass *object_class;
+
+ object_class = G_OBJECT_CLASS (klass);
+ object_class->finalize = oss4_device_finalize;
+ object_class->get_property = oss4_device_get_property;
+ object_class->set_property = oss4_device_set_property;
+
+ g_object_class_install_property (object_class,
+ PROP_FD,
+ g_param_spec_int ("fd",
+ "File descriptor",
+ "File descriptor of the device",
+ G_MININT,
+ G_MAXINT,
+ -1,
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (object_class,
+ PROP_INDEX,
+ g_param_spec_int ("index",
+ "Index",
+ "Index of the device",
+ G_MININT,
+ G_MAXINT,
+ 0,
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_class_override_property (object_class, PROP_NAME, "name");
+ g_object_class_override_property (object_class, PROP_DESCRIPTION, "description");
+ g_object_class_override_property (object_class, PROP_ICON, "icon");
+ g_object_class_override_property (object_class, PROP_ACTIVE_PROFILE, "active-profile");
+
+ g_type_class_add_private (object_class, sizeof (Oss4DevicePrivate));
+}
+
+static void
+oss4_device_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ Oss4Device *device;
+
+ device = OSS4_DEVICE (object);
+
+ switch (param_id) {
+ case PROP_NAME:
+ g_value_set_string (value, device->priv->name);
+ break;
+ case PROP_DESCRIPTION:
+ g_value_set_string (value, device->priv->description);
+ break;
+ case PROP_ICON:
+ g_value_set_string (value, OSS4_DEVICE_ICON);
+ break;
+ case PROP_ACTIVE_PROFILE:
+ /* Not supported */
+ g_value_set_object (value, NULL);
+ break;
+ case PROP_FD:
+ g_value_set_int (value, device->priv->fd);
+ break;
+ case PROP_INDEX:
+ g_value_set_int (value, device->priv->index);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ }
+}
+
+static void
+oss4_device_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ Oss4Device *device;
+
+ device = OSS4_DEVICE (object);
+
+ switch (param_id) {
+ case PROP_NAME:
+ /* Construct-only string */
+ device->priv->name = g_strdup (g_value_get_string (value));
+ break;
+ case PROP_DESCRIPTION:
+ /* Construct-only string */
+ device->priv->description = 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;
+ case PROP_FD:
+ device->priv->fd = dup (g_value_get_int (value));
+ break;
+ case PROP_INDEX:
+ device->priv->index = g_value_get_int (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ }
+}
+
+static void
+oss4_device_init (Oss4Device *device)
+{
+ device->priv = G_TYPE_INSTANCE_GET_PRIVATE (device,
+ OSS4_TYPE_DEVICE,
+ Oss4DevicePrivate);
+}
+
+static void
+oss4_device_finalize (GObject *object)
+{
+ Oss4Device *device;
+
+ device = OSS4_DEVICE (object);
+
+ g_free (device->priv->name);
+ g_free (device->priv->description);
+
+ if (device->priv->fd != -1)
+ g_close (device->priv->fd, NULL);
+
+ G_OBJECT_CLASS (oss4_device_parent_class)->finalize (object);
+}
+
+Oss4Device *
+oss4_device_new (const gchar *name,
+ const gchar *description,
+ gint fd,
+ gint index)
+{
+ Oss4Device *device;
+
+ device = g_object_new (OSS4_TYPE_DEVICE,
+ "name", name,
+ "description", description,
+ "fd", fd,
+ "index", index,
+ NULL);
+
+ return device;
+}
+
+gboolean
+oss4_device_read (Oss4Device *odevice)
+{
+ gint exts;
+ gint ret;
+ gint i;
+
+ ret = ioctl (odevice->priv->fd, SNDCTL_MIX_NREXT, &exts);
+ if (ret == -1)
+ return FALSE;
+
+ for (i = 0; i < exts; i++) {
+ oss_mixext ext;
+
+ ext.dev = odevice->priv->index;
+ ext.ctrl = i;
+ ret = ioctl (odevice->priv->fd, SNDCTL_MIX_EXTINFO, &ext);
+ if (ret == -1)
+ continue;
+
+ g_debug ("Mixer control %d type %d\n"
+ " min %d max %d\n"
+ " id %s\n"
+ " extname %s",
+ i,ext.type, ext.minvalue, ext.maxvalue, ext.id, ext.extname);
+ }
+
+ return TRUE;
+}
+
+gint
+oss4_device_get_index (Oss4Device *odevice)
+{
+ g_return_val_if_fail (OSS4_IS_DEVICE (odevice), FALSE);
+
+ return odevice->priv->index;
+}
+
+MateMixerStream *
+oss4_device_get_input_stream (Oss4Device *odevice)
+{
+ g_return_val_if_fail (OSS4_IS_DEVICE (odevice), FALSE);
+
+ return odevice->priv->input;
+}
+
+MateMixerStream *
+oss4_device_get_output_stream (Oss4Device *odevice)
+{
+ g_return_val_if_fail (OSS4_IS_DEVICE (odevice), FALSE);
+
+ return odevice->priv->output;
+}
+
+static gboolean
+read_mixer_devices (Oss4Device *device)
+{
+}
+
+static const gchar *
+oss4_device_get_name (MateMixerDevice *device)
+{
+ g_return_val_if_fail (OSS4_IS_DEVICE (device), NULL);
+
+ return OSS4_DEVICE (device)->priv->name;
+}
+
+static const gchar *
+oss4_device_get_description (MateMixerDevice *device)
+{
+ g_return_val_if_fail (OSS4_IS_DEVICE (device), NULL);
+
+ return OSS4_DEVICE (device)->priv->description;
+}
+
+static const gchar *
+oss4_device_get_icon (MateMixerDevice *device)
+{
+ g_return_val_if_fail (OSS4_IS_DEVICE (device), NULL);
+
+ return OSS4_DEVICE_ICON;
+}
diff --git a/backends/oss4/oss4-device.h b/backends/oss4/oss4-device.h
new file mode 100644
index 0000000..3ec72e7
--- /dev/null
+++ b/backends/oss4/oss4-device.h
@@ -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/>.
+ */
+
+#ifndef OSS4_DEVICE_H
+#define OSS4_DEVICE_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define OSS4_TYPE_DEVICE \
+ (oss4_device_get_type ())
+#define OSS4_DEVICE(o) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((o), OSS4_TYPE_DEVICE, Oss4Device))
+#define OSS4_IS_DEVICE(o) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((o), OSS4_TYPE_DEVICE))
+#define OSS4_DEVICE_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_CAST ((k), OSS4_TYPE_DEVICE, Oss4DeviceClass))
+#define OSS4_IS_DEVICE_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_TYPE ((k), OSS4_TYPE_DEVICE))
+#define OSS4_DEVICE_GET_CLASS(o) \
+ (G_TYPE_INSTANCE_GET_CLASS ((o), OSS4_TYPE_DEVICE, Oss4DeviceClass))
+
+typedef struct _Oss4Device Oss4Device;
+typedef struct _Oss4DeviceClass Oss4DeviceClass;
+typedef struct _Oss4DevicePrivate Oss4DevicePrivate;
+
+struct _Oss4Device
+{
+ GObject parent;
+
+ /*< private >*/
+ Oss4DevicePrivate *priv;
+};
+
+struct _Oss4DeviceClass
+{
+ GObjectClass parent;
+};
+
+GType oss4_device_get_type (void) G_GNUC_CONST;
+
+Oss4Device * oss4_device_new (const gchar *name,
+ const gchar *description,
+ gint fd,
+ gint index);
+
+gboolean oss4_device_read (Oss4Device *device);
+
+gint oss4_device_get_index (Oss4Device *odevice);
+
+MateMixerStream *oss4_device_get_input_stream (Oss4Device *odevice);
+MateMixerStream *oss4_device_get_output_stream (Oss4Device *odevice);
+
+G_END_DECLS
+
+#endif /* OSS_DEVICE_H */
diff --git a/configure.ac b/configure.ac
index 65e06e0..b618913 100644
--- a/configure.ac
+++ b/configure.ac
@@ -155,6 +155,40 @@ AC_SUBST(HAVE_OSS)
AC_SUBST(OSS_CFLAGS)
AC_SUBST(OSS_LIBS)
+# -----------------------------------------------------------------------
+# OSS4
+# -----------------------------------------------------------------------
+AC_ARG_ENABLE([oss4],
+ AS_HELP_STRING([--enable-oss4],
+ [Enable OSS4 backend module @<:@default=no@:>@]),
+ enable_oss4=$enableval, enable_oss4=no)
+
+if test "x$enable_oss4" != "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
+ have_oss4=yes
+ else
+ have_oss4=no
+ fi
+
+ if test "x$enable_oss4" = "xyes" -a "x$have_oss4" = "xno"; then
+ AC_MSG_ERROR([OSS4 support explicitly requested but dependencies not found])
+ fi
+
+ if test "x$have_oss4" = "xyes" ; then
+ AC_DEFINE(HAVE_OSS4, [], [Define if we have OSS support])
+ fi
+else
+ have_oss4=no
+fi
+
+AM_CONDITIONAL(HAVE_OSS4, test "x$have_oss4" = "xyes")
+
+AC_SUBST(HAVE_OSS4)
+AC_SUBST(OSS4_CFLAGS)
+
# =======================================================================
# Compiler warnings
# =======================================================================
@@ -207,6 +241,7 @@ libmatemixer/Makefile
backends/Makefile
backends/null/Makefile
backends/oss/Makefile
+backends/oss4/Makefile
backends/pulse/Makefile
data/Makefile
data/libmatemixer.pc
@@ -232,5 +267,6 @@ echo "
Build Null module: $have_null
Build PulseAudio module: $have_pulseaudio
Build OSS module: $have_oss
+ Build OSS4 module: $have_oss4
"
diff --git a/libmatemixer/matemixer-device.c b/libmatemixer/matemixer-device.c
index 0406709..87517d6 100644
--- a/libmatemixer/matemixer-device.c
+++ b/libmatemixer/matemixer-device.c
@@ -38,7 +38,8 @@ mate_mixer_device_default_init (MateMixerDeviceInterface *iface)
"Name",
"Name of the device",
NULL,
- G_PARAM_READABLE |
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS));
g_object_interface_install_property (iface,
@@ -46,7 +47,8 @@ mate_mixer_device_default_init (MateMixerDeviceInterface *iface)
"Description",
"Description of the device",
NULL,
- G_PARAM_READABLE |
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS));
g_object_interface_install_property (iface,
@@ -54,7 +56,8 @@ mate_mixer_device_default_init (MateMixerDeviceInterface *iface)
"Icon",
"Name of the sound device icon",
NULL,
- G_PARAM_READABLE |
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS));
g_object_interface_install_property (iface,