From 8436ec1641eee8868128755f6d1475230cea25e6 Mon Sep 17 00:00:00 2001 From: Michal Ratajsky Date: Sun, 27 Jul 2014 13:12:53 +0200 Subject: Beginning of OSS4 support --- backends/oss4/Makefile.am | 29 +++ backends/oss4/oss4-backend.c | 487 +++++++++++++++++++++++++++++++++++++++++++ backends/oss4/oss4-backend.h | 62 ++++++ backends/oss4/oss4-common.h | 38 ++++ backends/oss4/oss4-device.c | 328 +++++++++++++++++++++++++++++ backends/oss4/oss4-device.h | 72 +++++++ 6 files changed, 1016 insertions(+) create mode 100644 backends/oss4/Makefile.am create mode 100644 backends/oss4/oss4-backend.c create mode 100644 backends/oss4/oss4-backend.h create mode 100644 backends/oss4/oss4-common.h create mode 100644 backends/oss4/oss4-device.c create mode 100644 backends/oss4/oss4-device.h (limited to 'backends/oss4') 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 + * + * 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 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#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: (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 + * + * 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 . + */ + +#ifndef OSS4_BACKEND_H +#define OSS4_BACKEND_H + +#include +#include + +#include + +#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 + * + * 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 . + */ + +#ifndef OSS4_COMMON_H +#define OSS4_COMMON_H + +#include "config.h" + +#include +#include +#include +#include + +#ifdef HAVE_SYS_SOUNDCARD_H +# include +#elif HAVE_SOUNDCARD_H +# include +#elif HAVE_MACHINE_SOUNDCARD_H +# include +#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 + * + * 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 . + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#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 + * + * 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 . + */ + +#ifndef OSS4_DEVICE_H +#define OSS4_DEVICE_H + +#include +#include + +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 */ -- cgit v1.2.1