diff options
author | Michal Ratajsky <[email protected]> | 2014-07-25 23:47:46 +0200 |
---|---|---|
committer | Michal Ratajsky <[email protected]> | 2014-07-25 23:47:46 +0200 |
commit | 59a9aabf7b66e130f68b797c5a3674798fae437b (patch) | |
tree | 2645bf1511fb6e23540941796373b60a04767bfb | |
parent | 0bc3aa762cd794da510f03229840d939ee7bc0c9 (diff) | |
download | libmatemixer-59a9aabf7b66e130f68b797c5a3674798fae437b.tar.bz2 libmatemixer-59a9aabf7b66e130f68b797c5a3674798fae437b.tar.xz |
Support OSS
-rw-r--r-- | backends/oss/Makefile.am | 12 | ||||
-rw-r--r-- | backends/oss/oss-backend.c | 498 | ||||
-rw-r--r-- | backends/oss/oss-backend.h | 8 | ||||
-rw-r--r-- | backends/oss/oss-common.h | 38 | ||||
-rw-r--r-- | backends/oss/oss-device.c | 525 | ||||
-rw-r--r-- | backends/oss/oss-device.h | 73 | ||||
-rw-r--r-- | backends/oss/oss-stream-control.c | 529 | ||||
-rw-r--r-- | backends/oss/oss-stream-control.h | 74 | ||||
-rw-r--r-- | backends/oss/oss-stream.c | 315 | ||||
-rw-r--r-- | backends/oss/oss-stream.h | 75 | ||||
-rw-r--r-- | configure.ac | 3 | ||||
-rw-r--r-- | examples/monitor.c | 56 | ||||
-rw-r--r-- | libmatemixer/Makefile.am | 4 | ||||
-rw-r--r-- | libmatemixer/matemixer-backend.c | 33 | ||||
-rw-r--r-- | libmatemixer/matemixer-enum-types.c | 31 | ||||
-rw-r--r-- | libmatemixer/matemixer-enum-types.h | 3 | ||||
-rw-r--r-- | libmatemixer/matemixer-enums.h | 55 | ||||
-rw-r--r-- | libmatemixer/matemixer-stream-control.c | 445 | ||||
-rw-r--r-- | libmatemixer/matemixer-stream-control.h | 148 | ||||
-rw-r--r-- | libmatemixer/matemixer-stream.c | 475 | ||||
-rw-r--r-- | libmatemixer/matemixer-stream.h | 156 |
21 files changed, 2974 insertions, 582 deletions
diff --git a/backends/oss/Makefile.am b/backends/oss/Makefile.am index 3f0b8ea..44caeb8 100644 --- a/backends/oss/Makefile.am +++ b/backends/oss/Makefile.am @@ -11,11 +11,19 @@ libmatemixer_oss_la_CFLAGS = \ $(OSS_CFLAGS) libmatemixer_oss_la_SOURCES = \ + oss-common.h \ oss-backend.c \ - oss-backend.h + 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) + $(GLIB_LIBS) \ + $(OSS_LIBS) libmatemixer_oss_la_LDFLAGS = \ -avoid-version \ diff --git a/backends/oss/oss-backend.c b/backends/oss/oss-backend.c index 22d3547..6e058f8 100644 --- a/backends/oss/oss-backend.c +++ b/backends/oss/oss-backend.c @@ -15,43 +15,95 @@ * 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 "oss-backend.h" +#include "oss-common.h" +#include "oss-device.h" #define BACKEND_NAME "OSS" -#define BACKEND_PRIORITY 90 +#define BACKEND_PRIORITY 9 + +#define PATH_SNDSTAT "/dev/sndstat" + +struct _OssBackendPrivate +{ + GFile *sndstat; + GFile *dev; + GFileMonitor *dev_monitor; + GHashTable *devices; + GHashTable *streams; + MateMixerStream *default_input; + MateMixerStream *default_output; + MateMixerState state; +}; enum { PROP_0, PROP_STATE, PROP_DEFAULT_INPUT, - PROP_DEFAULT_OUTPUT, - N_PROPERTIES + PROP_DEFAULT_OUTPUT }; static void mate_mixer_backend_interface_init (MateMixerBackendInterface *iface); static void oss_backend_class_init (OssBackendClass *klass); static void oss_backend_class_finalize (OssBackendClass *klass); + static void oss_backend_get_property (GObject *object, guint param_id, GValue *value, GParamSpec *pspec); + static void oss_backend_init (OssBackend *oss); +static void oss_backend_dispose (GObject *object); +static void oss_backend_finalize (GObject *object); G_DEFINE_DYNAMIC_TYPE_EXTENDED (OssBackend, oss_backend, G_TYPE_OBJECT, 0, G_IMPLEMENT_INTERFACE_DYNAMIC (MATE_MIXER_TYPE_BACKEND, mate_mixer_backend_interface_init)) -static gboolean backend_open (MateMixerBackend *backend); -static MateMixerState backend_get_state (MateMixerBackend *backend); +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 void change_state (OssBackend *oss, + MateMixerState state); + +static void on_dev_monitor_changed (GFileMonitor *monitor, + GFile *file, + GFile *other_file, + GFileMonitorEvent event_type, + OssBackend *oss); + +static gboolean read_device (OssBackend *oss, + const gchar *path); + +static gchar * read_device_description (OssBackend *oss, + const gchar *path, + gint fd); +static gchar * read_device_sndstat_description (const gchar *path, + GFileInputStream *input); + +static void add_device (OssBackend *oss, + OssDevice *device); +static void remove_device (OssBackend *oss, + OssDevice *device); static MateMixerBackendInfo info; @@ -66,8 +118,7 @@ backend_module_init (GTypeModule *module) info.backend_type = MATE_MIXER_BACKEND_OSS; } -const MateMixerBackendInfo * -backend_module_get_info (void) +const MateMixerBackendInfo *backend_module_get_info (void) { return &info; } @@ -75,8 +126,10 @@ backend_module_get_info (void) static void mate_mixer_backend_interface_init (MateMixerBackendInterface *iface) { - iface->open = backend_open; - iface->get_state = backend_get_state; + iface->open = oss_backend_open; + iface->close = oss_backend_close; + iface->list_devices = oss_backend_list_devices; + iface->list_streams = oss_backend_list_streams; } static void @@ -85,11 +138,15 @@ oss_backend_class_init (OssBackendClass *klass) GObjectClass *object_class; object_class = G_OBJECT_CLASS (klass); + object_class->dispose = oss_backend_dispose; + object_class->finalize = oss_backend_finalize; object_class->get_property = oss_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 (OssBackendPrivate)); } /* Called in the code generated by G_DEFINE_DYNAMIC_TYPE_EXTENDED() */ @@ -104,13 +161,20 @@ oss_backend_get_property (GObject *object, GValue *value, GParamSpec *pspec) { + OssBackend *oss; + + oss = OSS_BACKEND (object); + switch (param_id) { case PROP_STATE: - g_value_set_enum (value, MATE_MIXER_STATE_READY); + 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, NULL); + g_value_set_object (value, oss->priv->default_output); + break; break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); @@ -121,16 +185,420 @@ oss_backend_get_property (GObject *object, 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); + + oss->priv->streams = g_hash_table_new_full (g_str_hash, + g_str_equal, + g_free, + g_object_unref); +} + +static void +oss_backend_dispose (GObject *object) +{ + oss_backend_close (MATE_MIXER_BACKEND (object)); +} + +static void +oss_backend_finalize (GObject *object) +{ + OssBackend *oss; + + oss = OSS_BACKEND (object); + + g_hash_table_destroy (oss->priv->devices); + g_hash_table_destroy (oss->priv->streams); } static gboolean -backend_open (MateMixerBackend *backend) +oss_backend_open (MateMixerBackend *backend) { + OssBackend *oss; + GError *error = NULL; + gint i; + + g_return_val_if_fail (OSS_IS_BACKEND (backend), FALSE); + + oss = OSS_BACKEND (backend); + + /* Monitor changes on /dev to catch hot-(un)plugged devices */ + // XXX works on linux, doesn't on freebsd, what to do on netbsd/openbsd? + oss->priv->dev = g_file_new_for_path ("/dev"); + oss->priv->dev_monitor = g_file_monitor_directory (oss->priv->dev, + G_FILE_MONITOR_NONE, + NULL, + &error); + if (oss->priv->dev_monitor != NULL) { + g_signal_connect (G_OBJECT (oss->priv->dev_monitor), + "changed", + G_CALLBACK (on_dev_monitor_changed), + oss); + } else { + g_debug ("Failed to monitor /dev: %s", error->message); + g_error_free (error); + } + +#if !defined(__linux__) && !defined(__NetBSD__) && !defined(__OpenBSD__) + /* 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 = g_file_new_for_path (PATH_SNDSTAT); +#endif + + for (i = 0; i < 5; i++) { + /* According to the OSS documentation the mixer devices are + * /dev/mixer0 - /dev/mixer4, of course some systems create them + * dynamically but this approach should be good enough */ + gchar *path = g_strdup_printf ("/dev/mixer%i", i); + + if (read_device (oss, path) == FALSE && i == 0) { + /* For the first mixer device check also /dev/mixer, but it + * might be a symlink to a real mixer device */ + if (g_file_test ("/dev/mixer", G_FILE_TEST_IS_SYMLINK) == FALSE) + read_device (oss, "/dev/mixer"); + } + + g_free (path); + } + + change_state (oss, MATE_MIXER_STATE_READY); return TRUE; } -static MateMixerState -backend_get_state (MateMixerBackend *backend) +void +oss_backend_close (MateMixerBackend *backend) +{ + OssBackend *oss; + + g_return_if_fail (OSS_IS_BACKEND (backend)); + + oss = OSS_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); + + g_clear_object (&oss->priv->dev_monitor); + g_clear_object (&oss->priv->dev); + g_clear_object (&oss->priv->sndstat); +} + +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 sorted 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; + } + return NULL; +} + +static GList * +oss_backend_list_streams (MateMixerBackend *backend) +{ + GList *list; + + g_return_val_if_fail (OSS_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 (OSS_BACKEND (backend)->priv->streams); + if (list != NULL) { + g_list_foreach (list, (GFunc) g_object_ref, NULL); + + return list; + } + return NULL; +} + +static void +change_state (OssBackend *oss, MateMixerState state) +{ + if (oss->priv->state == state) + return; + + oss->priv->state = state; + + g_object_notify (G_OBJECT (oss), "state"); +} + +static void +on_dev_monitor_changed (GFileMonitor *monitor, + GFile *file, + GFile *other_file, + GFileMonitorEvent event_type, + OssBackend *oss) +{ + gchar *path; + + if (event_type != G_FILE_MONITOR_EVENT_CREATED && + event_type != G_FILE_MONITOR_EVENT_DELETED) + return; + + path = g_file_get_path (file); + + /* Only handle creation and deletion of mixer devices */ + if (g_str_has_prefix (path, "/dev/mixer") == FALSE) { + g_free (path); + return; + } + if (strcmp (path, "/dev/mixer") == 0 && + g_file_test (path, G_FILE_TEST_IS_SYMLINK) == TRUE) { + g_free (path); + return; + } + + if (event_type == G_FILE_MONITOR_EVENT_DELETED) { + OssDevice *device; + + device = g_hash_table_lookup (oss->priv->devices, path); + if (device != NULL) + remove_device (oss, device); + } else + read_device (oss, path); + + g_free (path); +} + +static gboolean +read_device (OssBackend *oss, const gchar *path) +{ + OssDevice *device; + gint fd; + gboolean ret; + const gchar *description; + + /* We assume that the name and capabilities of a device do not change */ + device = g_hash_table_lookup (oss->priv->devices, path); + if (G_UNLIKELY (device != NULL)) { + g_debug ("Attempt to re-read already know device %s", path); + return TRUE; + } + + fd = g_open (path, O_RDWR, 0); + if (fd == -1) { + if (errno != ENOENT && errno != ENXIO) + g_debug ("%s: %s", path, g_strerror (errno)); + return FALSE; + } + + device = oss_device_new (path, fd); + + description = read_device_description (oss, path, fd); + if (description != NULL) + oss_device_set_description (device, description); + else + oss_device_set_description (device, _("Unknown device")); + + /* Close the descriptor as the device should dup it if it intends + * to keep it */ + g_close (fd, NULL); + + ret = oss_device_read (device); + if (ret == TRUE) + add_device (oss, device); + + g_object_unref (device); + return ret; +} + +static gchar * +read_device_description (OssBackend *oss, const gchar *path, gint fd) +{ + struct mixer_info info; + + if (ioctl (fd, SOUND_MIXER_INFO, &info) == 0) { + /* Prefer device name supplied by the system, but this fails on FreeBSD */ + return g_strdup (info.name); + } + + /* Reading the sndstat file is a bit desperate, but seem to be the only + * way to determine the name of the sound card on FreeBSD, it also has an + * advantage in being able to find out the default one */ + if (oss->priv->sndstat != NULL) { + GError *error = NULL; + GFileInputStream *input = g_file_read (oss->priv->sndstat, NULL, &error); + + if (input == NULL) { + /* The file can only be open by one application, otherwise the call + * fails with EBUSY */ + if (error->code == G_IO_ERROR_BUSY) { + g_debug ("Delayed reading %s as it is busy", PATH_SNDSTAT); + // XXX use timeout and try again + } else { + if (error->code == G_IO_ERROR_NOT_FOUND) + g_debug ("Device description is unknown as %s does not exist", + PATH_SNDSTAT); + else + g_debug ("%s: %s", PATH_SNDSTAT, error->message); + + g_clear_object (&oss->priv->sndstat); + } + g_error_free (error); + } else + return read_device_sndstat_description (path, input); + } + + return NULL; +} + +static gchar * +read_device_sndstat_description (const gchar *path, GFileInputStream *input) { - return MATE_MIXER_STATE_READY; + gchar *line; + gchar *prefix; + gchar *description = NULL; + GDataInputStream *stream; + + if (G_UNLIKELY (g_str_has_prefix (path, "/dev/mixer")) == FALSE) { + g_warn_if_reached (); + return NULL; + } + + /* We assume that the mixer device number matches the pcm number in the + * sndstat file, this is a bit desperate, but it seems to do the + * right thing in practice */ + prefix = g_strdup_printf ("pcm%u: ", + (guint) g_ascii_strtoull (path + sizeof ("/dev/mixer") - 1, + NULL, + 10)); + + stream = g_data_input_stream_new (G_INPUT_STREAM (input)); + + while (TRUE) { + GError *error = NULL; + gchar *p; + + line = g_data_input_stream_read_line (stream, NULL, NULL, &error); + if (line == NULL) { + if (error != NULL) { + g_warning ("%s: %s", path, error->message); + g_error_free (error); + } + break; + } + + 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; + } + + g_object_unref (stream); + g_free (prefix); + + return description; +} + +static void +add_device (OssBackend *oss, OssDevice *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, + g_strdup (oss_device_get_path (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 = oss_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 = oss_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 (OssBackend *oss, OssDevice *device) +{ + MateMixerStream *stream; + const gchar *path; + + /* Remove the device streams first as they are a part of the device */ + stream = oss_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 = oss_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); + } + + path = oss_device_get_path (device); + + /* Remove the device */ + g_object_ref (device); + + g_hash_table_remove (oss->priv->devices, path); + 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/oss/oss-backend.h b/backends/oss/oss-backend.h index 02567ed..b766799 100644 --- a/backends/oss/oss-backend.h +++ b/backends/oss/oss-backend.h @@ -36,12 +36,16 @@ #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 _OssBackend OssBackend; +typedef struct _OssBackendClass OssBackendClass; +typedef struct _OssBackendPrivate OssBackendPrivate; struct _OssBackend { GObject parent; + + /*< private >*/ + OssBackendPrivate *priv; }; struct _OssBackendClass diff --git a/backends/oss/oss-common.h b/backends/oss/oss-common.h new file mode 100644 index 0000000..7251b86 --- /dev/null +++ b/backends/oss/oss-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 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> + +#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..f33ff57 --- /dev/null +++ b/backends/oss/oss-device.c @@ -0,0 +1,525 @@ +/* + * 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 "oss-common.h" +#include "oss-device.h" +#include "oss-stream.h" +#include "oss-stream-control.h" + +#define OSS_DEVICE_ICON "audio-card" + +typedef struct +{ + gchar *name; + gchar *description; + MateMixerStreamControlRole role; + MateMixerStreamFlags flags; +} OssDeviceName; + +static const OssDeviceName const oss_devices[] = { + { "vol", N_("Volume"), MATE_MIXER_STREAM_CONTROL_ROLE_MASTER, MATE_MIXER_STREAM_OUTPUT }, + { "bass", N_("Bass"), MATE_MIXER_STREAM_CONTROL_ROLE_BASS, MATE_MIXER_STREAM_OUTPUT }, + { "treble", N_("Treble"), MATE_MIXER_STREAM_CONTROL_ROLE_TREBLE, MATE_MIXER_STREAM_OUTPUT }, + { "synth", N_("Synth"), MATE_MIXER_STREAM_CONTROL_ROLE_UNKNOWN, MATE_MIXER_STREAM_INPUT }, + { "pcm", N_("PCM"), MATE_MIXER_STREAM_CONTROL_ROLE_PCM, MATE_MIXER_STREAM_OUTPUT }, + { "speaker", N_("Speaker"), MATE_MIXER_STREAM_CONTROL_ROLE_SPEAKER, MATE_MIXER_STREAM_OUTPUT }, + { "line", N_("Line-in"), MATE_MIXER_STREAM_CONTROL_ROLE_PORT, MATE_MIXER_STREAM_INPUT }, + { "mic", N_("Microphone"), MATE_MIXER_STREAM_CONTROL_ROLE_PORT, MATE_MIXER_STREAM_INPUT }, + { "cd", N_("CD"), MATE_MIXER_STREAM_CONTROL_ROLE_CD, MATE_MIXER_STREAM_INPUT }, + /* Recording monitor */ + { "mix", N_("Mixer"), MATE_MIXER_STREAM_CONTROL_ROLE_UNKNOWN, MATE_MIXER_STREAM_OUTPUT }, + { "pcm2", N_("PCM-2"), MATE_MIXER_STREAM_CONTROL_ROLE_PCM, MATE_MIXER_STREAM_OUTPUT }, + /* Recording level (master input) */ + { "rec", N_("Record"), MATE_MIXER_STREAM_CONTROL_ROLE_MASTER, MATE_MIXER_STREAM_INPUT }, + { "igain", N_("In-gain"), MATE_MIXER_STREAM_CONTROL_ROLE_UNKNOWN, MATE_MIXER_STREAM_INPUT }, + { "ogain", N_("Out-gain"), MATE_MIXER_STREAM_CONTROL_ROLE_UNKNOWN, MATE_MIXER_STREAM_OUTPUT }, + { "line1", N_("Line-1"), MATE_MIXER_STREAM_CONTROL_ROLE_PORT, MATE_MIXER_STREAM_INPUT }, + { "line2", N_("Line-2"), MATE_MIXER_STREAM_CONTROL_ROLE_PORT, MATE_MIXER_STREAM_INPUT }, + { "line3", N_("Line-3"), MATE_MIXER_STREAM_CONTROL_ROLE_PORT, MATE_MIXER_STREAM_INPUT }, + { "dig1", N_("Digital-1"), MATE_MIXER_STREAM_CONTROL_ROLE_PORT, MATE_MIXER_STREAM_NO_FLAGS }, + { "dig2", N_("Digital-2"), MATE_MIXER_STREAM_CONTROL_ROLE_PORT, MATE_MIXER_STREAM_NO_FLAGS }, + { "dig3", N_("Digital-3"), MATE_MIXER_STREAM_CONTROL_ROLE_PORT, MATE_MIXER_STREAM_NO_FLAGS }, + { "phin", N_("Phone-in"), MATE_MIXER_STREAM_CONTROL_ROLE_PORT, MATE_MIXER_STREAM_INPUT }, + { "phout", N_("Phone-out"), MATE_MIXER_STREAM_CONTROL_ROLE_PORT, MATE_MIXER_STREAM_OUTPUT }, + { "video", N_("Video"), MATE_MIXER_STREAM_CONTROL_ROLE_PORT, MATE_MIXER_STREAM_INPUT }, + { "radio", N_("Radio"), MATE_MIXER_STREAM_CONTROL_ROLE_PORT, MATE_MIXER_STREAM_INPUT }, + { "monitor", N_("Monitor"), MATE_MIXER_STREAM_CONTROL_ROLE_UNKNOWN, MATE_MIXER_STREAM_OUTPUT }, + { "depth", N_("3D-depth"), MATE_MIXER_STREAM_CONTROL_ROLE_UNKNOWN, MATE_MIXER_STREAM_OUTPUT }, + { "center", N_("3D-center"), MATE_MIXER_STREAM_CONTROL_ROLE_UNKNOWN, MATE_MIXER_STREAM_OUTPUT }, + { "midi", N_("MIDI"), MATE_MIXER_STREAM_CONTROL_ROLE_UNKNOWN, MATE_MIXER_STREAM_INPUT } +}; + +struct _OssDevicePrivate +{ + gint fd; + gchar *path; + gchar *name; + gchar *description; + MateMixerStream *input; + MateMixerStream *output; +}; + +enum { + PROP_0, + PROP_NAME, + PROP_DESCRIPTION, + PROP_ICON, + PROP_ACTIVE_PROFILE, + PROP_PATH, + PROP_FD +}; + +static void mate_mixer_device_interface_init (MateMixerDeviceInterface *iface); + +static void oss_device_class_init (OssDeviceClass *klass); + +static void oss_device_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec); +static void oss_device_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec); + +static void oss_device_init (OssDevice *device); +static void oss_device_finalize (GObject *object); + +G_DEFINE_TYPE_WITH_CODE (OssDevice, oss_device, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (MATE_MIXER_TYPE_DEVICE, + mate_mixer_device_interface_init)) + +static const gchar *oss_device_get_name (MateMixerDevice *device); +static const gchar *oss_device_get_description (MateMixerDevice *device); +static const gchar *oss_device_get_icon (MateMixerDevice *device); + +static gboolean read_mixer_devices (OssDevice *device); + +static void +mate_mixer_device_interface_init (MateMixerDeviceInterface *iface) +{ + iface->get_name = oss_device_get_name; + iface->get_description = oss_device_get_description; + iface->get_icon = oss_device_get_icon; +} + +static void +oss_device_class_init (OssDeviceClass *klass) +{ + GObjectClass *object_class; + + object_class = G_OBJECT_CLASS (klass); + object_class->finalize = oss_device_finalize; + object_class->get_property = oss_device_get_property; + object_class->set_property = oss_device_set_property; + + g_object_class_install_property (object_class, + PROP_PATH, + g_param_spec_string ("path", + "Path", + "Path to the device", + NULL, + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + + 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_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 (OssDevicePrivate)); +} + +static void +oss_device_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec) +{ + OssDevice *device; + + device = OSS_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, OSS_DEVICE_ICON); + break; + case PROP_ACTIVE_PROFILE: + /* Not supported */ + g_value_set_object (value, NULL); + break; + case PROP_PATH: + g_value_set_string (value, device->priv->path); + break; + case PROP_FD: + g_value_set_int (value, device->priv->fd); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } +} + +static void +oss_device_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec) +{ + OssDevice *device; + + device = OSS_DEVICE (object); + + switch (param_id) { + case PROP_PATH: + /* Construct-only string */ + device->priv->path = g_strdup (g_value_get_string (value)); + break; + case PROP_FD: + device->priv->fd = dup (g_value_get_int (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } +} + +static void +oss_device_init (OssDevice *device) +{ + device->priv = G_TYPE_INSTANCE_GET_PRIVATE (device, + OSS_TYPE_DEVICE, + OssDevicePrivate); +} + +static void +oss_device_finalize (GObject *object) +{ + OssDevice *device; + + device = OSS_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 (oss_device_parent_class)->finalize (object); +} + +OssDevice * +oss_device_new (const gchar *path, gint fd) +{ + OssDevice *device; + gchar *basename; + + g_return_val_if_fail (path != NULL, NULL); + + device = g_object_new (OSS_TYPE_DEVICE, + "path", path, + "fd", fd, + NULL); + + basename = g_path_get_basename (path); + + device->priv->name = g_strdup_printf ("oss-%s", basename); + g_free (basename); + + return device; +} + +gboolean +oss_device_read (OssDevice *device) +{ + gchar *name; + gchar *basename; + MateMixerStreamControl *ctl; + + g_return_val_if_fail (OSS_IS_DEVICE (device), FALSE); + + // XXX avoid calling this function repeatedly + + g_debug ("Querying device %s (%s)", + device->priv->path, + device->priv->description); + + basename = g_path_get_basename (device->priv->path); + + name = g_strdup_printf ("oss-input-%s", basename); + device->priv->input = MATE_MIXER_STREAM (oss_stream_new (name, + device->priv->description, + MATE_MIXER_STREAM_INPUT)); + g_free (name); + + name = g_strdup_printf ("oss-output-%s", basename); + device->priv->output = MATE_MIXER_STREAM (oss_stream_new (name, + device->priv->description, + MATE_MIXER_STREAM_OUTPUT | + MATE_MIXER_STREAM_PORTS_FIXED)); + g_free (name); + + if (read_mixer_devices (device) == FALSE) + return FALSE; + + // XXX prefer active ports as default if there is no default + + ctl = mate_mixer_stream_get_default_control (device->priv->input); + if (ctl == NULL) { + const GList *list = mate_mixer_stream_list_controls (device->priv->input); + + if (list != NULL) { + ctl = MATE_MIXER_STREAM_CONTROL (list->data); + oss_stream_set_default_control (OSS_STREAM (device->priv->input), + OSS_STREAM_CONTROL (ctl)); + } else + g_clear_object (&device->priv->input); + } + + if (ctl != NULL) + g_debug ("Default input stream control is %s", + mate_mixer_stream_control_get_description (ctl)); + + ctl = mate_mixer_stream_get_default_control (device->priv->output); + if (ctl == NULL) { + const GList *list = mate_mixer_stream_list_controls (device->priv->output); + + if (list != NULL) { + ctl = MATE_MIXER_STREAM_CONTROL (list->data); + oss_stream_set_default_control (OSS_STREAM (device->priv->output), + OSS_STREAM_CONTROL (ctl)); + } else + g_clear_object (&device->priv->output); + } + + if (ctl != NULL) + g_debug ("Default output stream control is %s", + mate_mixer_stream_control_get_description (ctl)); + + return TRUE; +} + +const gchar * +oss_device_get_path (OssDevice *odevice) +{ + g_return_val_if_fail (OSS_IS_DEVICE (odevice), FALSE); + + return odevice->priv->path; +} + +MateMixerStream * +oss_device_get_input_stream (OssDevice *odevice) +{ + g_return_val_if_fail (OSS_IS_DEVICE (odevice), FALSE); + + return odevice->priv->input; +} + +MateMixerStream * +oss_device_get_output_stream (OssDevice *odevice) +{ + g_return_val_if_fail (OSS_IS_DEVICE (odevice), FALSE); + + return odevice->priv->output; +} + +gboolean +oss_device_set_description (OssDevice *odevice, const gchar *description) +{ + g_return_val_if_fail (OSS_IS_DEVICE (odevice), FALSE); + + if (g_strcmp0 (odevice->priv->description, description) != 0) { + g_free (odevice->priv->description); + + odevice->priv->description = g_strdup (description); + + g_object_notify (G_OBJECT (odevice), "description"); + return TRUE; + } + return FALSE; +} + +static gboolean +read_mixer_devices (OssDevice *device) +{ + gint devmask, + stereomask, + recmask; + gint ret; + gint i; + OssStreamControl *ctl; + + ret = ioctl (device->priv->fd, MIXER_READ (SOUND_MIXER_DEVMASK), &devmask); + if (ret < 0) + goto fail; + ret = ioctl (device->priv->fd, MIXER_READ (SOUND_MIXER_STEREODEVS), &stereomask); + if (ret < 0) + goto fail; + ret = ioctl (device->priv->fd, MIXER_READ (SOUND_MIXER_RECMASK), &recmask); + if (ret < 0) + goto fail; + + for (i = 0; i < MIN (G_N_ELEMENTS (oss_devices), SOUND_MIXER_NRDEVICES); i++) { + gboolean stereo; + gboolean input = FALSE; + MateMixerPort *port = NULL; + + /* Skip unavailable controls */ + if ((devmask & (1 << i)) == 0) + continue; + + if ((stereomask & (1 << i)) > 0) + stereo = TRUE; + else + stereo = FALSE; + + if (oss_devices[i].flags == MATE_MIXER_STREAM_NO_FLAGS) { + if ((recmask & (1 << i)) > 0) + input = TRUE; + } + if (oss_devices[i].flags == MATE_MIXER_STREAM_INPUT) { + if ((recmask & (1 << i)) == 0) { + g_debug ("Skipping non-input device %s", oss_devices[i].name); + continue; + } + input = TRUE; + } + + ctl = oss_stream_control_new (device->priv->fd, + i, + oss_devices[i].name, + oss_devices[i].description, + stereo); + + if (oss_devices[i].role == MATE_MIXER_STREAM_CONTROL_ROLE_PORT) + port = _mate_mixer_port_new (oss_devices[i].name, + oss_devices[i].description, + NULL, + 0, + 0); + + if (input == TRUE) { + oss_stream_add_control (OSS_STREAM (device->priv->input), ctl); + + if (i == SOUND_MIXER_RECLEV || i == SOUND_MIXER_IGAIN) { + if (i == SOUND_MIXER_RECLEV) { + oss_stream_set_default_control (OSS_STREAM (device->priv->input), ctl); + } else { + MateMixerStreamControl *defctl; + + defctl = mate_mixer_stream_get_default_control (device->priv->input); + if (defctl == NULL) + oss_stream_set_default_control (OSS_STREAM (device->priv->input), ctl); + } + } + + if (port != NULL) + oss_stream_add_port (OSS_STREAM (device->priv->input), port); + } else { + oss_stream_add_control (OSS_STREAM (device->priv->output), ctl); + + if (i == SOUND_MIXER_VOLUME) { + oss_stream_set_default_control (OSS_STREAM (device->priv->output), ctl); + } + else if (i == SOUND_MIXER_PCM) { + MateMixerStreamControl *defctl; + + defctl = mate_mixer_stream_get_default_control (device->priv->output); + if (defctl == NULL) + oss_stream_set_default_control (OSS_STREAM (device->priv->output), ctl); + } + + if (port != NULL) + oss_stream_add_port (OSS_STREAM (device->priv->output), port); + } + + if (port != NULL) + oss_stream_control_set_port (ctl, port); + + oss_stream_control_set_role (ctl, oss_devices[i].role); + + g_debug ("Added control %s", + mate_mixer_stream_control_get_description (MATE_MIXER_STREAM_CONTROL (ctl))); + + oss_stream_control_update (ctl); + } + return TRUE; + +fail: + g_warning ("Failed to read device %s: %s", + device->priv->path, + g_strerror (errno)); + + return FALSE; +} + +static const gchar * +oss_device_get_name (MateMixerDevice *device) +{ + g_return_val_if_fail (OSS_IS_DEVICE (device), NULL); + + return OSS_DEVICE (device)->priv->name; +} + +static const gchar * +oss_device_get_description (MateMixerDevice *device) +{ + g_return_val_if_fail (OSS_IS_DEVICE (device), NULL); + + return OSS_DEVICE (device)->priv->description; +} + +static const gchar * +oss_device_get_icon (MateMixerDevice *device) +{ + g_return_val_if_fail (OSS_IS_DEVICE (device), NULL); + + return OSS_DEVICE_ICON; +} diff --git a/backends/oss/oss-device.h b/backends/oss/oss-device.h new file mode 100644 index 0000000..fe40eb2 --- /dev/null +++ b/backends/oss/oss-device.h @@ -0,0 +1,73 @@ +/* + * 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> + +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 +{ + GObject parent; + + /*< private >*/ + OssDevicePrivate *priv; +}; + +struct _OssDeviceClass +{ + GObjectClass parent; +}; + +GType oss_device_get_type (void) G_GNUC_CONST; + +OssDevice * oss_device_new (const gchar *path, + gint fd); + +gboolean oss_device_read (OssDevice *device); + +const gchar * oss_device_get_path (OssDevice *odevice); + +MateMixerStream *oss_device_get_input_stream (OssDevice *odevice); +MateMixerStream *oss_device_get_output_stream (OssDevice *odevice); + +gboolean oss_device_set_description (OssDevice *odevice, + const gchar *description); + +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..0b1db26 --- /dev/null +++ b/backends/oss/oss-stream-control.c @@ -0,0 +1,529 @@ +/* + * 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 <unistd.h> +#include <errno.h> +#include <glib.h> +#include <glib/gstdio.h> +#include <glib-object.h> + +#include <libmatemixer/matemixer-port.h> +#include <libmatemixer/matemixer-stream-control.h> + +#include "oss-common.h" +#include "oss-stream-control.h" + +struct _OssStreamControlPrivate +{ + gint fd; + gint dev_number; + gchar *name; + gchar *description; + guint volume[2]; + gfloat balance; + gboolean stereo; + MateMixerPort *port; + MateMixerStreamControlRole role; + MateMixerStreamControlFlags flags; +}; + +enum { + PROP_0, + PROP_NAME, + PROP_DESCRIPTION, + PROP_FLAGS, + PROP_MUTE, + PROP_VOLUME, + PROP_BALANCE, + PROP_FADE, + PROP_FD, + PROP_DEV_NUMBER, + PROP_STEREO +}; + +static void mate_mixer_stream_control_interface_init (MateMixerStreamControlInterface *iface); + +static void oss_stream_control_class_init (OssStreamControlClass *klass); + +static void oss_stream_control_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec); +static void oss_stream_control_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec); + +static void oss_stream_control_init (OssStreamControl *octl); +static void oss_stream_control_finalize (GObject *object); + +G_DEFINE_TYPE_WITH_CODE (OssStreamControl, oss_stream_control, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (MATE_MIXER_TYPE_STREAM_CONTROL, + mate_mixer_stream_control_interface_init)) + +static const gchar * oss_stream_control_get_name (MateMixerStreamControl *ctl); +static const gchar * oss_stream_control_get_description (MateMixerStreamControl *ctl); + +static guint oss_stream_control_get_num_channels (MateMixerStreamControl *ctl); + +static gboolean oss_stream_control_set_volume (MateMixerStreamControl *ctl, + guint volume); + +static guint oss_stream_control_get_channel_volume (MateMixerStreamControl *ctl, + guint channel); +static gboolean oss_stream_control_set_channel_volume (MateMixerStreamControl *ctl, + guint channel, + guint volume); + +static MateMixerChannelPosition oss_stream_control_get_channel_position (MateMixerStreamControl *ctl, + guint channel); +static gboolean oss_stream_control_has_channel_position (MateMixerStreamControl *ctl, + MateMixerChannelPosition position); + +static gboolean oss_stream_control_set_balance (MateMixerStreamControl *ctl, + gfloat balance); + +static guint oss_stream_control_get_min_volume (MateMixerStreamControl *ctl); +static guint oss_stream_control_get_max_volume (MateMixerStreamControl *ctl); +static guint oss_stream_control_get_normal_volume (MateMixerStreamControl *ctl); +static guint oss_stream_control_get_base_volume (MateMixerStreamControl *ctl); + +static void +mate_mixer_stream_control_interface_init (MateMixerStreamControlInterface *iface) +{ + iface->get_name = oss_stream_control_get_name; + iface->get_description = oss_stream_control_get_description; + iface->get_num_channels = oss_stream_control_get_num_channels; + iface->set_volume = oss_stream_control_set_volume; + iface->get_channel_volume = oss_stream_control_get_channel_volume; + iface->set_channel_volume = oss_stream_control_set_channel_volume; + iface->get_channel_position = oss_stream_control_get_channel_position; + iface->has_channel_position = oss_stream_control_has_channel_position; + iface->set_balance = oss_stream_control_set_balance; + iface->get_min_volume = oss_stream_control_get_min_volume; + iface->get_max_volume = oss_stream_control_get_max_volume; + iface->get_normal_volume = oss_stream_control_get_normal_volume; + iface->get_base_volume = oss_stream_control_get_base_volume; +} + +static void +oss_stream_control_class_init (OssStreamControlClass *klass) +{ + GObjectClass *object_class; + + object_class = G_OBJECT_CLASS (klass); + object_class->finalize = oss_stream_control_finalize; + object_class->get_property = oss_stream_control_get_property; + object_class->set_property = oss_stream_control_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_DEV_NUMBER, + g_param_spec_int ("dev-number", + "Dev number", + "OSS device number", + G_MININT, + G_MAXINT, + 0, + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (object_class, + PROP_STEREO, + g_param_spec_boolean ("stereo", + "Stereo", + "Stereo", + FALSE, + 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_FLAGS, "flags"); + g_object_class_override_property (object_class, PROP_MUTE, "mute"); + g_object_class_override_property (object_class, PROP_VOLUME, "volume"); + g_object_class_override_property (object_class, PROP_BALANCE, "balance"); + g_object_class_override_property (object_class, PROP_FADE, "fade"); + + g_type_class_add_private (object_class, sizeof (OssStreamControlPrivate)); +} + +static void +oss_stream_control_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec) +{ + OssStreamControl *octl; + + octl = OSS_STREAM_CONTROL (object); + + switch (param_id) { + case PROP_NAME: + g_value_set_string (value, octl->priv->name); + break; + case PROP_DESCRIPTION: + g_value_set_string (value, octl->priv->description); + break; + case PROP_FLAGS: + g_value_set_flags (value, octl->priv->flags); + break; + case PROP_MUTE: + /* Not supported */ + g_value_set_boolean (value, FALSE); + break; + case PROP_VOLUME: + g_value_set_uint (value, MAX (octl->priv->volume[0], octl->priv->volume[1])); + break; + case PROP_BALANCE: + g_value_set_float (value, octl->priv->balance); + break; + case PROP_FADE: + /* Not supported */ + g_value_set_float (value, 0.0f); + break; + case PROP_FD: + g_value_set_int (value, octl->priv->fd); + break; + case PROP_DEV_NUMBER: + g_value_set_int (value, octl->priv->dev_number); + break; + case PROP_STEREO: + g_value_set_boolean (value, octl->priv->stereo); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } +} + +static void +oss_stream_control_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec) +{ + OssStreamControl *octl; + + octl = OSS_STREAM_CONTROL (object); + + switch (param_id) { + case PROP_FD: + octl->priv->fd = dup (g_value_get_int (value)); + break; + case PROP_DEV_NUMBER: + octl->priv->dev_number = g_value_get_int (value); + break; + case PROP_STEREO: + octl->priv->stereo = g_value_get_boolean (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } +} + +static void +oss_stream_control_init (OssStreamControl *octl) +{ + octl->priv = G_TYPE_INSTANCE_GET_PRIVATE (octl, + OSS_TYPE_STREAM_CONTROL, + OssStreamControlPrivate); +} + +static void +oss_stream_control_finalize (GObject *object) +{ + OssStreamControl *octl; + + octl = OSS_STREAM_CONTROL (object); + + g_free (octl->priv->name); + g_free (octl->priv->description); + + if (octl->priv->fd != -1) + g_close (octl->priv->fd, NULL); + + G_OBJECT_CLASS (oss_stream_control_parent_class)->finalize (object); +} + +OssStreamControl * +oss_stream_control_new (gint fd, + gint dev_number, + const gchar *name, + const gchar *description, + gboolean stereo) +{ + OssStreamControl *ctl; + + ctl = g_object_new (OSS_TYPE_STREAM_CONTROL, + "fd", fd, + "dev-number", dev_number, + "stereo", stereo, + NULL); + + ctl->priv->name = g_strdup (name); + ctl->priv->description = g_strdup (description); + + return ctl; +} + +gboolean +oss_stream_control_update (OssStreamControl *octl) +{ + gint v; + gint ret; + + g_return_val_if_fail (OSS_IS_STREAM_CONTROL (octl), FALSE); + + ret = ioctl (octl->priv->fd, MIXER_READ (octl->priv->dev_number), &v); + if (ret < 0) { + g_warning ("Failed to read volume: %s", g_strerror (errno)); + return FALSE; + } + + octl->priv->volume[0] = v & 0xFF; + + if (octl->priv->stereo == TRUE) + octl->priv->volume[1] = (v >> 8) & 0xFF; + + return TRUE; +} + +gboolean +oss_stream_control_set_port (OssStreamControl *octl, MateMixerPort *port) +{ + g_return_val_if_fail (OSS_IS_STREAM_CONTROL (octl), FALSE); + + // XXX provide property + + if (octl->priv->port != NULL) + g_object_unref (octl->priv->port); + + octl->priv->port = g_object_ref (port); + return TRUE; +} + +gboolean +oss_stream_control_set_role (OssStreamControl *octl, MateMixerStreamControlRole role) +{ + g_return_val_if_fail (OSS_IS_STREAM_CONTROL (octl), FALSE); + + octl->priv->role = role; + return TRUE; +} + +static const gchar * +oss_stream_control_get_name (MateMixerStreamControl *ctl) +{ + g_return_val_if_fail (OSS_IS_STREAM_CONTROL (ctl), NULL); + + return OSS_STREAM_CONTROL (ctl)->priv->name; +} + +static const gchar * +oss_stream_control_get_description (MateMixerStreamControl *ctl) +{ + g_return_val_if_fail (OSS_IS_STREAM_CONTROL (ctl), NULL); + + return OSS_STREAM_CONTROL (ctl)->priv->description; +} + +static guint +oss_stream_control_get_num_channels (MateMixerStreamControl *ctl) +{ + g_return_val_if_fail (OSS_IS_STREAM_CONTROL (ctl), 0); + + if (OSS_STREAM_CONTROL (ctl)->priv->stereo == TRUE) + return 2; + else + return 1; +} + +static gboolean +oss_stream_control_set_volume (MateMixerStreamControl *ctl, guint volume) +{ + OssStreamControl *octl; + int v; + int ret; + + g_return_val_if_fail (OSS_IS_STREAM_CONTROL (ctl), FALSE); + + octl = OSS_STREAM_CONTROL (ctl); + + /* Some backends may allow setting higher value than maximum, but not here */ + if (volume > 100) + volume = 100; + + v = volume; + if (octl->priv->stereo == TRUE) + v |= (volume & 0xFF) << 8; + + ret = ioctl (octl->priv->fd, MIXER_WRITE (octl->priv->dev_number), &v); + if (ret < 0) { + g_warning ("Failed to set volume: %s", g_strerror (errno)); + return FALSE; + } + return TRUE; +} + +static guint +oss_stream_control_get_channel_volume (MateMixerStreamControl *ctl, guint channel) +{ + OssStreamControl *octl; + + g_return_val_if_fail (OSS_IS_STREAM_CONTROL (ctl), 0); + + octl = OSS_STREAM_CONTROL (ctl); + + if (channel > 1) + return 0; + + /* Right channel on mono stream will always have zero volume */ + return octl->priv->volume[channel]; +} + +static gboolean +oss_stream_control_set_channel_volume (MateMixerStreamControl *ctl, + guint channel, + guint volume) +{ + OssStreamControl *octl; + int ret; + int v; + + g_return_val_if_fail (OSS_IS_STREAM_CONTROL (ctl), FALSE); + + if (channel > 1) + return FALSE; + + octl = OSS_STREAM_CONTROL (ctl); + + /* Some backends may allow setting higher value than maximum, but not here */ + if (volume > 100) + volume = 100; + + if (channel == 0) + v = volume; + else + v = octl->priv->volume[0]; + + if (channel == 1) { + if (octl->priv->stereo == FALSE) + return FALSE; + + v |= volume << 8; + } else + v |= octl->priv->volume[1] << 8; + + ret = ioctl (octl->priv->fd, MIXER_WRITE (octl->priv->dev_number), &v); + if (ret < 0) { + g_warning ("Failed to set channel volume: %s", g_strerror (errno)); + return FALSE; + } + return TRUE; +} + +static MateMixerChannelPosition +oss_stream_control_get_channel_position (MateMixerStreamControl *ctl, guint channel) +{ + OssStreamControl *octl; + + g_return_val_if_fail (OSS_IS_STREAM_CONTROL (ctl), MATE_MIXER_CHANNEL_UNKNOWN); + + octl = OSS_STREAM_CONTROL (ctl); + + if (octl->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 *ctl, + MateMixerChannelPosition position) +{ + g_return_val_if_fail (OSS_IS_STREAM_CONTROL (ctl), FALSE); + + if (position == MATE_MIXER_CHANNEL_MONO) + return OSS_STREAM_CONTROL (ctl)->priv->stereo == FALSE; + + if (position == MATE_MIXER_CHANNEL_FRONT_LEFT || + position == MATE_MIXER_CHANNEL_FRONT_RIGHT) + return OSS_STREAM_CONTROL (ctl)->priv->stereo == TRUE; + + return FALSE; +} + +static gboolean +oss_stream_control_set_balance (MateMixerStreamControl *ctl, gfloat balance) +{ + OssStreamControl *octl; + + g_return_val_if_fail (OSS_IS_STREAM_CONTROL (ctl), FALSE); + + octl = OSS_STREAM_CONTROL (ctl); + + if (octl->priv->stereo == FALSE) + return FALSE; + + // XXX + return TRUE; +} + +static guint +oss_stream_control_get_min_volume (MateMixerStreamControl *ctl) +{ + return 0; +} + +static guint +oss_stream_control_get_max_volume (MateMixerStreamControl *ctl) +{ + return 100; +} + +static guint +oss_stream_control_get_normal_volume (MateMixerStreamControl *ctl) +{ + return 100; +} + +static guint +oss_stream_control_get_base_volume (MateMixerStreamControl *ctl) +{ + return 100; +} diff --git a/backends/oss/oss-stream-control.h b/backends/oss/oss-stream-control.h new file mode 100644 index 0000000..420af48 --- /dev/null +++ b/backends/oss/oss-stream-control.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_CONTROL_H +#define OSS_STREAM_CONTROL_H + +#include <glib.h> +#include <glib-object.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 +{ + GObject parent; + + /*< private >*/ + OssStreamControlPrivate *priv; +}; + +struct _OssStreamControlClass +{ + GObjectClass parent; +}; + +GType oss_stream_control_get_type (void) G_GNUC_CONST; + +OssStreamControl *oss_stream_control_new (gint fd, + gint dev_number, + const gchar *name, + const gchar *description, + gboolean stereo); + +gboolean oss_stream_control_update (OssStreamControl *octl); + +gboolean oss_stream_control_set_port (OssStreamControl *octl, + MateMixerPort *port); + +gboolean oss_stream_control_set_role (OssStreamControl *octl, + MateMixerStreamControlRole role); + +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..69bfd06 --- /dev/null +++ b/backends/oss/oss-stream.c @@ -0,0 +1,315 @@ +/* + * 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 <libmatemixer/matemixer-device.h> +#include <libmatemixer/matemixer-enums.h> +#include <libmatemixer/matemixer-stream.h> + +#include "oss-stream.h" +#include "oss-stream-control.h" + +struct _OssStreamPrivate +{ + gchar *name; + gchar *description; + MateMixerDevice *device; + MateMixerStreamFlags flags; + MateMixerStreamState state; + GHashTable *ports; + GList *ports_list; + GHashTable *controls; + GList *controls_list; + OssStreamControl *control; +}; + +enum { + PROP_0, + PROP_NAME, + PROP_DESCRIPTION, + PROP_DEVICE, + PROP_FLAGS, + PROP_STATE, + PROP_ACTIVE_PORT, +}; + +static void mate_mixer_stream_interface_init (MateMixerStreamInterface *iface); + +static void oss_stream_class_init (OssStreamClass *klass); + +static void oss_stream_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec); + +static void oss_stream_init (OssStream *ostream); +static void oss_stream_dispose (GObject *object); +static void oss_stream_finalize (GObject *object); + +G_DEFINE_TYPE_WITH_CODE (OssStream, oss_stream, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (MATE_MIXER_TYPE_STREAM, + mate_mixer_stream_interface_init)) + +static const gchar * oss_stream_get_name (MateMixerStream *stream); +static const gchar * oss_stream_get_description (MateMixerStream *stream); + +static MateMixerStreamControl *oss_stream_get_control (MateMixerStream *stream, + const gchar *name); +static MateMixerStreamControl *oss_stream_get_default_control (MateMixerStream *stream); + +static const GList * oss_stream_list_controls (MateMixerStream *stream); +static const GList * oss_stream_list_ports (MateMixerStream *stream); + +static void +mate_mixer_stream_interface_init (MateMixerStreamInterface *iface) +{ + iface->get_name = oss_stream_get_name; + iface->get_description = oss_stream_get_description; + iface->get_control = oss_stream_get_control; + iface->get_default_control = oss_stream_get_default_control; + iface->list_controls = oss_stream_list_controls; + iface->list_ports = oss_stream_list_ports; +} + +static void +oss_stream_class_init (OssStreamClass *klass) +{ + GObjectClass *object_class; + + object_class = G_OBJECT_CLASS (klass); + object_class->dispose = oss_stream_dispose; + object_class->finalize = oss_stream_finalize; + object_class->get_property = oss_stream_get_property; + + 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_DEVICE, "device"); + g_object_class_override_property (object_class, PROP_FLAGS, "flags"); + g_object_class_override_property (object_class, PROP_STATE, "state"); + g_object_class_override_property (object_class, PROP_ACTIVE_PORT, "active-port"); + + g_type_class_add_private (object_class, sizeof (OssStreamPrivate)); +} + +static void +oss_stream_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec) +{ + OssStream *ostream; + + ostream = OSS_STREAM (object); + + switch (param_id) { + case PROP_NAME: + g_value_set_string (value, ostream->priv->name); + break; + case PROP_DESCRIPTION: + g_value_set_string (value, ostream->priv->description); + break; + case PROP_DEVICE: + g_value_set_object (value, ostream->priv->device); + break; + case PROP_FLAGS: + g_value_set_flags (value, ostream->priv->flags); + break; + case PROP_STATE: + /* Not supported */ + g_value_set_enum (value, MATE_MIXER_STREAM_STATE_UNKNOWN); + break; + case PROP_ACTIVE_PORT: + // XXX + g_value_set_object (value, NULL); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } +} + +static void +oss_stream_init (OssStream *ostream) +{ + ostream->priv = G_TYPE_INSTANCE_GET_PRIVATE (ostream, + OSS_TYPE_STREAM, + OssStreamPrivate); + + ostream->priv->controls = g_hash_table_new_full (g_str_hash, + g_str_equal, + g_free, + g_object_unref); + + ostream->priv->ports = g_hash_table_new_full (g_str_hash, + g_str_equal, + g_free, + g_object_unref); +} + +static void +oss_stream_dispose (GObject *object) +{ + OssStream *ostream; + + ostream = OSS_STREAM (object); + + g_hash_table_remove_all (ostream->priv->controls); + g_hash_table_remove_all (ostream->priv->ports); + + G_OBJECT_CLASS (oss_stream_parent_class)->finalize (object); +} + +static void +oss_stream_finalize (GObject *object) +{ + OssStream *ostream; + + ostream = OSS_STREAM (object); + + g_free (ostream->priv->name); + g_free (ostream->priv->description); + + g_hash_table_destroy (ostream->priv->controls); + g_hash_table_destroy (ostream->priv->ports); + + G_OBJECT_CLASS (oss_stream_parent_class)->finalize (object); +} + +OssStream * +oss_stream_new (const gchar *name, + const gchar *description, + MateMixerStreamFlags flags) +{ + OssStream *stream; + + stream = g_object_new (OSS_TYPE_STREAM, NULL); + + stream->priv->name = g_strdup (name); + stream->priv->description = g_strdup (description); + stream->priv->flags = flags; + + return stream; +} + +gboolean +oss_stream_add_control (OssStream *ostream, OssStreamControl *octl) +{ + const gchar *name; + + g_return_val_if_fail (OSS_IS_STREAM (ostream), FALSE); + g_return_val_if_fail (OSS_IS_STREAM_CONTROL (octl), FALSE); + + name = mate_mixer_stream_control_get_name (MATE_MIXER_STREAM_CONTROL (octl)); + + g_hash_table_insert (ostream->priv->controls, + g_strdup (name), + octl); + return TRUE; +} + +gboolean +oss_stream_set_default_control (OssStream *ostream, OssStreamControl *octl) +{ + g_return_val_if_fail (OSS_IS_STREAM (ostream), FALSE); + g_return_val_if_fail (OSS_IS_STREAM_CONTROL (octl), FALSE); + + /* This function is only used internally so avoid validating that the control + * belongs to this stream */ + if (ostream->priv->control != NULL) + g_object_unref (ostream->priv->control); + + ostream->priv->control = g_object_ref (octl); + return TRUE; +} + +gboolean +oss_stream_add_port (OssStream *ostream, MateMixerPort *port) +{ + g_return_val_if_fail (OSS_IS_STREAM (ostream), FALSE); + g_return_val_if_fail (MATE_MIXER_IS_PORT (port), FALSE); + + g_hash_table_insert (ostream->priv->ports, + g_strdup (mate_mixer_port_get_name (port)), + port); + return TRUE; +} + +static const gchar * +oss_stream_get_name (MateMixerStream *stream) +{ + g_return_val_if_fail (OSS_IS_STREAM (stream), NULL); + + return OSS_STREAM (stream)->priv->name; +} + +static const gchar * +oss_stream_get_description (MateMixerStream *stream) +{ + g_return_val_if_fail (OSS_IS_STREAM (stream), NULL); + + return OSS_STREAM (stream)->priv->description; +} + +static MateMixerStreamControl * +oss_stream_get_control (MateMixerStream *stream, const gchar *name) +{ + g_return_val_if_fail (OSS_IS_STREAM (stream), NULL); + g_return_val_if_fail (name != NULL, NULL); + + return g_hash_table_lookup (OSS_STREAM (stream)->priv->controls, name); +} + +static MateMixerStreamControl * +oss_stream_get_default_control (MateMixerStream *stream) +{ + g_return_val_if_fail (OSS_IS_STREAM (stream), NULL); + + return MATE_MIXER_STREAM_CONTROL (OSS_STREAM (stream)->priv->control); +} + +static const GList * +oss_stream_list_controls (MateMixerStream *stream) +{ + OssStream *ostream; + + g_return_val_if_fail (OSS_IS_STREAM (stream), NULL); + + ostream = OSS_STREAM (stream); + + if (ostream->priv->controls_list == NULL) + ostream->priv->controls_list = g_hash_table_get_values (ostream->priv->controls); + + return ostream->priv->controls_list; +} + +static const GList * +oss_stream_list_ports (MateMixerStream *stream) +{ + OssStream *ostream; + + g_return_val_if_fail (OSS_IS_STREAM (stream), NULL); + + ostream = OSS_STREAM (stream); + + if (ostream->priv->ports_list == NULL) + ostream->priv->ports_list = g_hash_table_get_values (ostream->priv->ports); + + return ostream->priv->ports_list; +} diff --git a/backends/oss/oss-stream.h b/backends/oss/oss-stream.h new file mode 100644 index 0000000..d6c2fb2 --- /dev/null +++ b/backends/oss/oss-stream.h @@ -0,0 +1,75 @@ +/* + * 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 "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 +{ + GObject parent; + + /*< private >*/ + OssStreamPrivate *priv; +}; + +struct _OssStreamClass +{ + GObjectClass parent; +}; + +GType oss_stream_get_type (void) G_GNUC_CONST; + +OssStream * oss_stream_new (const gchar *name, + const gchar *description, + MateMixerStreamFlags flags); + +gboolean oss_stream_add_control (OssStream *stream, + OssStreamControl *ctl); + +gboolean oss_stream_set_default_control (OssStream *stream, + OssStreamControl *ctl); + +gboolean oss_stream_add_port (OssStream *ostream, + MateMixerPort *port); + +G_END_DECLS + +#endif /* OSS_STREAM_H */ diff --git a/configure.ac b/configure.ac index d9bffc6..65e06e0 100644 --- a/configure.ac +++ b/configure.ac @@ -67,6 +67,7 @@ PKG_CHECK_MODULES(GLIB, [ glib-2.0 >= $GLIB_REQUIRED_VERSION gobject-2.0 >= $GLIB_REQUIRED_VERSION gmodule-2.0 >= $GLIB_REQUIRED_VERSION + gio-2.0 >= $GLIB_REQUIRED_VERSION ]) GTK_DOC_CHECK([1.10], [--flavour no-tmpl]) @@ -131,6 +132,7 @@ if test "x$enable_oss" != "xno"; then 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 @@ -151,6 +153,7 @@ AM_CONDITIONAL(HAVE_OSS, test "x$have_oss" = "xyes") AC_SUBST(HAVE_OSS) AC_SUBST(OSS_CFLAGS) +AC_SUBST(OSS_LIBS) # ======================================================================= # Compiler warnings diff --git a/examples/monitor.c b/examples/monitor.c index 3267b36..dca5105 100644 --- a/examples/monitor.c +++ b/examples/monitor.c @@ -89,7 +89,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 +100,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 ("["); @@ -192,24 +192,21 @@ print_streams (void) streams = mate_mixer_control_list_streams (control); 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; + MateMixerClientStream *client = NULL; + gchar *volume_bar; + gdouble volume; 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; - } } - volume_bar = create_volume_bar (stream, &volume); + ctl = mate_mixer_stream_get_default_control (stream); + + volume_bar = create_volume_bar (ctl, &volume); g_print ("Stream %s\n" " |-| Description : %s\n" @@ -222,10 +219,10 @@ print_streams (void) 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)); + 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 != NULL) { MateMixerClientStreamFlags client_flags; @@ -275,17 +272,20 @@ print_cached_streams (void) 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" " |-| Role : %s\n" @@ -298,10 +298,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), @@ -394,7 +394,7 @@ int main (int argc, char *argv[]) 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, oss, oss4, null)", NULL }, { "server", 's', 0, G_OPTION_ARG_STRING, &server, "Sound server address", NULL }, { NULL } }; @@ -427,6 +427,10 @@ int main (int argc, char *argv[]) if (backend) { if (!strcmp (backend, "pulseaudio")) mate_mixer_control_set_backend_type (control, MATE_MIXER_BACKEND_PULSEAUDIO); + else if (!strcmp (backend, "oss")) + mate_mixer_control_set_backend_type (control, MATE_MIXER_BACKEND_OSS); + else if (!strcmp (backend, "oss4")) + mate_mixer_control_set_backend_type (control, MATE_MIXER_BACKEND_OSS4); else if (!strcmp (backend, "null")) mate_mixer_control_set_backend_type (control, MATE_MIXER_BACKEND_NULL); else diff --git a/libmatemixer/Makefile.am b/libmatemixer/Makefile.am index 8c219d4..9666684 100644 --- a/libmatemixer/Makefile.am +++ b/libmatemixer/Makefile.am @@ -17,6 +17,7 @@ libmatemixer_include_HEADERS = \ matemixer-enums.h \ matemixer-port.h \ matemixer-stream.h \ + matemixer-stream-control.h \ matemixer-version.h libmatemixer_la_CFLAGS = $(GLIB_CFLAGS) @@ -37,7 +38,8 @@ libmatemixer_la_SOURCES = \ matemixer-enum-types.h \ matemixer-port.c \ matemixer-port-private.h \ - matemixer-stream.c + matemixer-stream.c \ + matemixer-stream-control.c libmatemixer_la_LIBADD = $(GLIB_LIBS) diff --git a/libmatemixer/matemixer-backend.c b/libmatemixer/matemixer-backend.c index be5c704..e070090 100644 --- a/libmatemixer/matemixer-backend.c +++ b/libmatemixer/matemixer-backend.c @@ -176,10 +176,15 @@ mate_mixer_backend_close (MateMixerBackend *backend) MateMixerState mate_mixer_backend_get_state (MateMixerBackend *backend) { + MateMixerState state = MATE_MIXER_STATE_UNKNOWN; + 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); + g_object_get (G_OBJECT (backend), + "state", &state, + NULL); + + return state; } GList * @@ -230,16 +235,18 @@ mate_mixer_backend_list_cached_streams (MateMixerBackend *backend) 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 (stream), + "default-input", &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 @@ -261,16 +268,18 @@ mate_mixer_backend_set_default_input_stream (MateMixerBackend *backend, 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 (stream), + "default-output", &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 diff --git a/libmatemixer/matemixer-enum-types.c b/libmatemixer/matemixer-enum-types.c index 339b673..50e3bf4 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,30 @@ 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_VOLUME, "MATE_MIXER_STREAM_CONTROL_HAS_DECIBEL_VOLUME", "has-decibel-volume" }, + { 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_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..1dc13cc 100644 --- a/libmatemixer/matemixer-enum-types.h +++ b/libmatemixer/matemixer-enum-types.h @@ -43,6 +43,9 @@ 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_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 7e523bb..b99f4c5 100644 --- a/libmatemixer/matemixer-enums.h +++ b/libmatemixer/matemixer-enums.h @@ -48,6 +48,7 @@ typedef enum { * will be the first one to try unless you select a specific backend * to connect to. * @MATE_MIXER_BACKEND_OSS: + * @MATE_MIXER_BACKEND_OSS4: * @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 @@ -58,6 +59,7 @@ typedef enum { MATE_MIXER_BACKEND_UNKNOWN, MATE_MIXER_BACKEND_PULSEAUDIO, MATE_MIXER_BACKEND_OSS, + MATE_MIXER_BACKEND_OSS4, MATE_MIXER_BACKEND_NULL } MateMixerBackendType; @@ -81,14 +83,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 >*/ @@ -96,15 +91,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; /** @@ -122,6 +112,39 @@ 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_VOLUME: + * @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_VOLUME = 1 << 2, + MATE_MIXER_STREAM_CONTROL_HAS_FLAT_VOLUME = 1 << 3, + MATE_MIXER_STREAM_CONTROL_CAN_SET_VOLUME = 1 << 4, + MATE_MIXER_STREAM_CONTROL_CAN_BALANCE = 1 << 5, + MATE_MIXER_STREAM_CONTROL_CAN_FADE = 1 << 6 +} MateMixerStreamControlFlags; + +typedef enum { + MATE_MIXER_STREAM_CONTROL_ROLE_UNKNOWN, + MATE_MIXER_STREAM_CONTROL_ROLE_MASTER, + 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, + MATE_MIXER_STREAM_CONTROL_ROLE_PORT +} MateMixerStreamControlRole; + +/** * MateMixerClientStreamFlags: * @MATE_MIXER_CLIENT_STREAM_NO_FLAGS: * @MATE_MIXER_CLIENT_STREAM_APPLICATION: diff --git a/libmatemixer/matemixer-stream-control.c b/libmatemixer/matemixer-stream-control.c new file mode 100644 index 0000000..19d35a1 --- /dev/null +++ b/libmatemixer/matemixer-stream-control.c @@ -0,0 +1,445 @@ +/* + * 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" + +/** + * SECTION:matemixer-stream-control + * @include: libmatemixer/matemixer.h + */ + +G_DEFINE_INTERFACE (MateMixerStreamControl, mate_mixer_stream_control, G_TYPE_OBJECT) + +static void +mate_mixer_stream_control_default_init (MateMixerStreamControlInterface *iface) +{ + g_object_interface_install_property (iface, + g_param_spec_string ("name", + "Name", + "Name of the stream control", + NULL, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); + + g_object_interface_install_property (iface, + g_param_spec_string ("description", + "Description", + "Description of the stream control", + NULL, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); + + g_object_interface_install_property (iface, + 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_READABLE | + G_PARAM_STATIC_STRINGS)); + + g_object_interface_install_property (iface, + g_param_spec_boolean ("mute", + "Mute", + "Mute state of the stream control", + FALSE, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); + + g_object_interface_install_property (iface, + g_param_spec_uint ("volume", + "Volume", + "Volume of the stream control", + 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 control", + -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 control", + -1.0f, + 1.0f, + 0.0f, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); +} + +const gchar * +mate_mixer_stream_control_get_name (MateMixerStreamControl *ctl) +{ + g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (ctl), NULL); + + /* Implementation required */ + return MATE_MIXER_STREAM_CONTROL_GET_INTERFACE (ctl)->get_name (ctl); +} + +const gchar * +mate_mixer_stream_control_get_description (MateMixerStreamControl *ctl) +{ + g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (ctl), NULL); + + /* Implementation required */ + return MATE_MIXER_STREAM_CONTROL_GET_INTERFACE (ctl)->get_description (ctl); +} + +MateMixerStreamControlFlags +mate_mixer_stream_control_get_flags (MateMixerStreamControl *ctl) +{ + MateMixerStreamControlFlags flags = MATE_MIXER_STREAM_CONTROL_NO_FLAGS; + + g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (ctl), MATE_MIXER_STREAM_CONTROL_NO_FLAGS); + + g_object_get (G_OBJECT (ctl), + "flags", &flags, + NULL); + + return flags; +} + +gboolean +mate_mixer_stream_control_get_mute (MateMixerStreamControl *ctl) +{ + gboolean mute = FALSE; + + g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (ctl), FALSE); + + g_object_get (G_OBJECT (ctl), + "mute", &mute, + NULL); + + return mute; +} + +gboolean +mate_mixer_stream_control_set_mute (MateMixerStreamControl *ctl, gboolean mute) +{ + MateMixerStreamControlInterface *iface; + + g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (ctl), FALSE); + + iface = MATE_MIXER_STREAM_CONTROL_GET_INTERFACE (ctl); + + if (iface->set_mute != NULL) + return iface->set_mute (ctl, mute); + + return FALSE; +} + +guint +mate_mixer_stream_control_get_volume (MateMixerStreamControl *ctl) +{ + guint volume = 0; + + g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (ctl), 0); + + g_object_get (G_OBJECT (ctl), + "volume", &volume, + NULL); + + return volume; +} + +gboolean +mate_mixer_stream_control_set_volume (MateMixerStreamControl *ctl, guint volume) +{ + MateMixerStreamControlInterface *iface; + + g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (ctl), FALSE); + + iface = MATE_MIXER_STREAM_CONTROL_GET_INTERFACE (ctl); + + if (iface->set_volume != NULL) + return iface->set_volume (ctl, volume); + + return FALSE; +} + +gdouble +mate_mixer_stream_control_get_decibel (MateMixerStreamControl *ctl) +{ + MateMixerStreamControlInterface *iface; + + g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (ctl), -MATE_MIXER_INFINITY); + + iface = MATE_MIXER_STREAM_CONTROL_GET_INTERFACE (ctl); + + if (iface->get_decibel != NULL) + return iface->get_decibel (ctl); + + return -MATE_MIXER_INFINITY; +} + +gboolean +mate_mixer_stream_control_set_decibel (MateMixerStreamControl *ctl, gdouble decibel) +{ + MateMixerStreamControlInterface *iface; + + g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (ctl), FALSE); + + iface = MATE_MIXER_STREAM_CONTROL_GET_INTERFACE (ctl); + + if (iface->set_decibel != NULL) + return iface->set_decibel (ctl, decibel); + + return FALSE; +} + +guint +mate_mixer_stream_control_get_num_channels (MateMixerStreamControl *ctl) +{ + MateMixerStreamControlInterface *iface; + + g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (ctl), 0); + + iface = MATE_MIXER_STREAM_CONTROL_GET_INTERFACE (ctl); + + if (iface->get_num_channels != NULL) + return iface->get_num_channels (ctl); + + return 0; +} + +MateMixerChannelPosition +mate_mixer_stream_control_get_channel_position (MateMixerStreamControl *ctl, guint channel) +{ + MateMixerStreamControlInterface *iface; + + g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (ctl), MATE_MIXER_CHANNEL_UNKNOWN); + + iface = MATE_MIXER_STREAM_CONTROL_GET_INTERFACE (ctl); + + if (iface->get_channel_position != NULL) + return iface->get_channel_position (ctl, channel); + + return MATE_MIXER_CHANNEL_UNKNOWN; +} + +guint +mate_mixer_stream_control_get_channel_volume (MateMixerStreamControl *ctl, guint channel) +{ + MateMixerStreamControlInterface *iface; + + g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (ctl), 0); + + iface = MATE_MIXER_STREAM_CONTROL_GET_INTERFACE (ctl); + + if (iface->get_channel_volume != NULL) + return iface->get_channel_volume (ctl, channel); + + return 0; +} + +gboolean +mate_mixer_stream_control_set_channel_volume (MateMixerStreamControl *ctl, + guint channel, + guint volume) +{ + MateMixerStreamControlInterface *iface; + + g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (ctl), FALSE); + + iface = MATE_MIXER_STREAM_CONTROL_GET_INTERFACE (ctl); + + if (iface->set_channel_volume != NULL) + return iface->set_channel_volume (ctl, channel, volume); + + return FALSE; +} + +gdouble +mate_mixer_stream_control_get_channel_decibel (MateMixerStreamControl *ctl, guint channel) +{ + MateMixerStreamControlInterface *iface; + + g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (ctl), -MATE_MIXER_INFINITY); + + iface = MATE_MIXER_STREAM_CONTROL_GET_INTERFACE (ctl); + + if (iface->get_channel_decibel != NULL) + return iface->get_channel_decibel (ctl, channel); + + return -MATE_MIXER_INFINITY; +} + +gboolean +mate_mixer_stream_control_set_channel_decibel (MateMixerStreamControl *ctl, + guint channel, + gdouble decibel) +{ + MateMixerStreamControlInterface *iface; + + g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (ctl), FALSE); + + iface = MATE_MIXER_STREAM_CONTROL_GET_INTERFACE (ctl); + + if (iface->set_channel_decibel != NULL) + return iface->set_channel_decibel (ctl, channel, decibel); + + return FALSE; +} + +gboolean +mate_mixer_stream_control_has_channel_position (MateMixerStreamControl *ctl, + MateMixerChannelPosition position) +{ + MateMixerStreamControlInterface *iface; + + g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (ctl), FALSE); + + iface = MATE_MIXER_STREAM_CONTROL_GET_INTERFACE (ctl); + + if (iface->has_channel_position != NULL) + return iface->has_channel_position (ctl, position); + + return FALSE; +} + +gfloat +mate_mixer_stream_control_get_balance (MateMixerStreamControl *ctl) +{ + gfloat balance = 0.0f; + + g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (ctl), 0.0f); + + g_object_get (G_OBJECT (ctl), + "balance", &balance, + NULL); + + return 0.0f; +} + +gboolean +mate_mixer_stream_control_set_balance (MateMixerStreamControl *ctl, gfloat balance) +{ + MateMixerStreamControlInterface *iface; + + g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (ctl), FALSE); + + iface = MATE_MIXER_STREAM_CONTROL_GET_INTERFACE (ctl); + + if (iface->set_balance != NULL) + return iface->set_balance (ctl, balance); + + return FALSE; +} + +gfloat +mate_mixer_stream_control_get_fade (MateMixerStreamControl *ctl) +{ + gfloat fade = 0.0f; + + g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (ctl), 0.0f); + + g_object_get (G_OBJECT (ctl), + "fade", &fade, + NULL); + + return fade; +} + +gboolean +mate_mixer_stream_control_set_fade (MateMixerStreamControl *ctl, gfloat fade) +{ + MateMixerStreamControlInterface *iface; + + g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (ctl), FALSE); + + iface = MATE_MIXER_STREAM_CONTROL_GET_INTERFACE (ctl); + + if (iface->set_fade != NULL) + return iface->set_fade (ctl, fade); + + return FALSE; +} + +guint +mate_mixer_stream_control_get_min_volume (MateMixerStreamControl *ctl) +{ + MateMixerStreamControlInterface *iface; + + g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (ctl), 0); + + iface = MATE_MIXER_STREAM_CONTROL_GET_INTERFACE (ctl); + + if (iface->get_min_volume != NULL) + return iface->get_min_volume (ctl); + + return 0; +} + +guint +mate_mixer_stream_control_get_max_volume (MateMixerStreamControl *ctl) +{ + MateMixerStreamControlInterface *iface; + + g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (ctl), 0); + + iface = MATE_MIXER_STREAM_CONTROL_GET_INTERFACE (ctl); + + if (iface->get_max_volume != NULL) + return iface->get_max_volume (ctl); + + return 0; +} + +guint +mate_mixer_stream_control_get_normal_volume (MateMixerStreamControl *ctl) +{ + MateMixerStreamControlInterface *iface; + + g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (ctl), 0); + + iface = MATE_MIXER_STREAM_CONTROL_GET_INTERFACE (ctl); + + if (iface->get_normal_volume != NULL) + return iface->get_normal_volume (ctl); + + return 0; +} + +guint +mate_mixer_stream_control_get_base_volume (MateMixerStreamControl *ctl) +{ + MateMixerStreamControlInterface *iface; + + g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (ctl), 0); + + iface = MATE_MIXER_STREAM_CONTROL_GET_INTERFACE (ctl); + + if (iface->get_base_volume != NULL) + return iface->get_base_volume (ctl); + + return 0; +} diff --git a/libmatemixer/matemixer-stream-control.h b/libmatemixer/matemixer-stream-control.h new file mode 100644 index 0000000..727ed54 --- /dev/null +++ b/libmatemixer/matemixer-stream-control.h @@ -0,0 +1,148 @@ +/* + * 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> + +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_GET_INTERFACE(o) \ + (G_TYPE_INSTANCE_GET_INTERFACE ((o), MATE_MIXER_TYPE_STREAM_CONTROL, MateMixerStreamControlInterface)) + +typedef struct _MateMixerStreamControl MateMixerStreamControl; /* dummy object */ +typedef struct _MateMixerStreamControlInterface MateMixerStreamControlInterface; + +struct _MateMixerStreamControlInterface +{ + GTypeInterface parent_iface; + + /*< private >*/ + const gchar * (*get_name) (MateMixerStreamControl *ctl); + const gchar * (*get_description) (MateMixerStreamControl *ctl); + + gboolean (*set_mute) (MateMixerStreamControl *ctl, + gboolean mute); + + guint (*get_num_channels) (MateMixerStreamControl *ctl); + + gboolean (*set_volume) (MateMixerStreamControl *ctl, + guint volume); + + gdouble (*get_decibel) (MateMixerStreamControl *ctl); + gboolean (*set_decibel) (MateMixerStreamControl *ctl, + gdouble decibel); + + gboolean (*has_channel_position) (MateMixerStreamControl *ctl, + MateMixerChannelPosition position); + MateMixerChannelPosition (*get_channel_position) (MateMixerStreamControl *ctl, + guint channel); + + guint (*get_channel_volume) (MateMixerStreamControl *ctl, + guint channel); + gboolean (*set_channel_volume) (MateMixerStreamControl *ctl, + guint channel, + guint volume); + + gdouble (*get_channel_decibel) (MateMixerStreamControl *ctl, + guint channel); + gboolean (*set_channel_decibel) (MateMixerStreamControl *ctl, + guint channel, + gdouble decibel); + + gboolean (*set_balance) (MateMixerStreamControl *ctl, + gfloat balance); + + gboolean (*set_fade) (MateMixerStreamControl *ctl, + gfloat fade); + + guint (*get_min_volume) (MateMixerStreamControl *ctl); + guint (*get_max_volume) (MateMixerStreamControl *ctl); + guint (*get_normal_volume) (MateMixerStreamControl *ctl); + guint (*get_base_volume) (MateMixerStreamControl *ctl); +}; + +GType mate_mixer_stream_control_get_type (void) G_GNUC_CONST; + +const gchar * mate_mixer_stream_control_get_name (MateMixerStreamControl *ctl); +const gchar * mate_mixer_stream_control_get_description (MateMixerStreamControl *ctl); +MateMixerStreamControlFlags mate_mixer_stream_control_get_flags (MateMixerStreamControl *ctl); + +gboolean mate_mixer_stream_control_get_mute (MateMixerStreamControl *ctl); +gboolean mate_mixer_stream_control_set_mute (MateMixerStreamControl *ctl, + gboolean mute); + +guint mate_mixer_stream_control_get_num_channels (MateMixerStreamControl *ctl); + +guint mate_mixer_stream_control_get_volume (MateMixerStreamControl *ctl); +gboolean mate_mixer_stream_control_set_volume (MateMixerStreamControl *ctl, + guint volume); + +gdouble mate_mixer_stream_control_get_decibel (MateMixerStreamControl *ctl); +gboolean mate_mixer_stream_control_set_decibel (MateMixerStreamControl *ctl, + gdouble decibel); + +gboolean mate_mixer_stream_control_has_channel_position (MateMixerStreamControl *ctl, + MateMixerChannelPosition position); +MateMixerChannelPosition mate_mixer_stream_control_get_channel_position (MateMixerStreamControl *ctl, + guint channel); + +guint mate_mixer_stream_control_get_channel_volume (MateMixerStreamControl *ctl, + guint channel); +gboolean mate_mixer_stream_control_set_channel_volume (MateMixerStreamControl *ctl, + guint channel, + guint volume); + +gdouble mate_mixer_stream_control_get_channel_decibel (MateMixerStreamControl *ctl, + guint channel); +gboolean mate_mixer_stream_control_set_channel_decibel (MateMixerStreamControl *ctl, + guint channel, + gdouble decibel); + +gfloat mate_mixer_stream_control_get_balance (MateMixerStreamControl *ctl); +gboolean mate_mixer_stream_control_set_balance (MateMixerStreamControl *ctl, + gfloat balance); + +gfloat mate_mixer_stream_control_get_fade (MateMixerStreamControl *ctl); +gboolean mate_mixer_stream_control_set_fade (MateMixerStreamControl *ctl, + gfloat fade); + +guint mate_mixer_stream_control_get_min_volume (MateMixerStreamControl *ctl); +guint mate_mixer_stream_control_get_max_volume (MateMixerStreamControl *ctl); +guint mate_mixer_stream_control_get_normal_volume (MateMixerStreamControl *ctl); +guint mate_mixer_stream_control_get_base_volume (MateMixerStreamControl *ctl); + +G_END_DECLS + +#endif /* MATEMIXER_STREAM_CONTROL_H */ diff --git a/libmatemixer/matemixer-stream.c b/libmatemixer/matemixer-stream.c index 6bec2be..888fddb 100644 --- a/libmatemixer/matemixer-stream.c +++ b/libmatemixer/matemixer-stream.c @@ -84,44 +84,6 @@ mate_mixer_stream_default_init (MateMixerStreamInterface *iface) 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", @@ -145,327 +107,161 @@ mate_mixer_stream_default_init (MateMixerStreamInterface *iface) const gchar * mate_mixer_stream_get_name (MateMixerStream *stream) { + g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), NULL); + + /* Implementation required */ 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; + /* Implementation required */ + return MATE_MIXER_STREAM_GET_INTERFACE (stream)->get_description (stream); } MateMixerDevice * mate_mixer_stream_get_device (MateMixerStream *stream) { - MateMixerStreamInterface *iface; + MateMixerDevice *device = NULL; g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), NULL); - iface = MATE_MIXER_STREAM_GET_INTERFACE (stream); + g_object_get (G_OBJECT (stream), + "device", &device, + NULL); - if (iface->get_device) - return iface->get_device (stream); + if (device != NULL) + g_object_unref (device); + + return device; - return NULL; } MateMixerStreamFlags mate_mixer_stream_get_flags (MateMixerStream *stream) { - MateMixerStreamInterface *iface; + MateMixerStreamFlags flags = MATE_MIXER_STREAM_NO_FLAGS; 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); + g_object_get (G_OBJECT (stream), + "flags", &flags, + NULL); - return MATE_MIXER_STREAM_NO_FLAGS; + return flags; } MateMixerStreamState mate_mixer_stream_get_state (MateMixerStream *stream) { - MateMixerStreamInterface *iface; + MateMixerStreamState state = MATE_MIXER_STREAM_STATE_UNKNOWN; 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); + g_object_get (G_OBJECT (stream), + "state", &state, + NULL); - return MATE_MIXER_STREAM_STATE_UNKNOWN; + return state; } -gboolean -mate_mixer_stream_get_mute (MateMixerStream *stream) +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->get_mute) - return iface->get_mute (stream); - - return FALSE; -} - -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; -} - -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; -} - -gboolean -mate_mixer_stream_set_decibel (MateMixerStream *stream, gdouble decibel) -{ - 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; -} - -guint -mate_mixer_stream_get_num_channels (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_num_channels) - return iface->get_num_channels (stream); - - return 0; -} - -MateMixerChannelPosition -mate_mixer_stream_get_channel_position (MateMixerStream *stream, guint channel) -{ - MateMixerStreamInterface *iface; - - g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), MATE_MIXER_CHANNEL_UNKNOWN); - - iface = MATE_MIXER_STREAM_GET_INTERFACE (stream); - - if (iface->get_channel_position) - return iface->get_channel_position (stream, channel); - - return MATE_MIXER_CHANNEL_UNKNOWN; -} - -guint -mate_mixer_stream_get_channel_volume (MateMixerStream *stream, guint channel) -{ - 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); - - return 0; -} - -gboolean -mate_mixer_stream_set_channel_volume (MateMixerStream *stream, - guint channel, - 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_channel_volume) - return iface->set_channel_volume (stream, channel, volume); - - return FALSE; -} - -gdouble -mate_mixer_stream_get_channel_decibel (MateMixerStream *stream, guint channel) -{ - 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), NULL); - return -MATE_MIXER_INFINITY; + /* Implementation required */ + return MATE_MIXER_STREAM_GET_INTERFACE (stream)->get_control (stream, name); } -gboolean -mate_mixer_stream_set_channel_decibel (MateMixerStream *stream, - guint channel, - gdouble decibel) +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_channel_decibel) - return iface->set_channel_decibel (stream, channel, decibel); + g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), NULL); - return FALSE; + /* Implementation required */ + return MATE_MIXER_STREAM_GET_INTERFACE (stream)->get_default_control (stream); } -gboolean -mate_mixer_stream_has_channel_position (MateMixerStream *stream, - MateMixerChannelPosition position) +MateMixerPort * +mate_mixer_stream_get_port (MateMixerStream *stream, const gchar *name) { 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 (iface->has_channel_position) - return iface->has_channel_position (stream, position); + if (iface->get_port != NULL) + return iface->get_port (stream, name); return FALSE; } -gfloat -mate_mixer_stream_get_balance (MateMixerStream *stream) +MateMixerPort * +mate_mixer_stream_get_active_port (MateMixerStream *stream) { - MateMixerStreamInterface *iface; + MateMixerPort *port = NULL; - g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), 0.0f); + g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), NULL); - iface = MATE_MIXER_STREAM_GET_INTERFACE (stream); + g_object_get (G_OBJECT (stream), + "active-port", &port, + NULL); - if (iface->get_balance) - return iface->get_balance (stream); + if (port != NULL) + g_object_unref (port); - return 0.0f; + return port; } gboolean -mate_mixer_stream_set_balance (MateMixerStream *stream, gfloat balance) +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_balance) - return iface->set_balance (stream, balance); + if (iface->set_active_port != NULL) + return iface->set_active_port (stream, port); return FALSE; } -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); + g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), NULL); iface = MATE_MIXER_STREAM_GET_INTERFACE (stream); - if (iface->get_fade) - return iface->get_fade (stream); + if (iface->list_controls != NULL) + return iface->list_controls (stream); - return 0.0f; + return NULL; } -gboolean -mate_mixer_stream_set_fade (MateMixerStream *stream, gfloat fade) +const GList * +mate_mixer_stream_list_ports (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 (iface->set_fade) - return iface->set_fade (stream, fade); + if (iface->list_ports != NULL) + return iface->list_ports (stream); - return FALSE; + return NULL; } gboolean @@ -477,7 +273,7 @@ mate_mixer_stream_suspend (MateMixerStream *stream) iface = MATE_MIXER_STREAM_GET_INTERFACE (stream); - if (iface->suspend) + if (iface->suspend != NULL) return iface->suspend (stream); return FALSE; @@ -492,57 +288,28 @@ mate_mixer_stream_resume (MateMixerStream *stream) iface = MATE_MIXER_STREAM_GET_INTERFACE (stream); - if (iface->resume) + if (iface->resume != NULL) return iface->resume (stream); return FALSE; } gboolean -mate_mixer_stream_monitor_start (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); -} - -gboolean -mate_mixer_stream_monitor_is_running (MateMixerStream *stream) +mate_mixer_stream_monitor_get_enabled (MateMixerStream *stream) { - MateMixerStreamInterface *iface; + gboolean enabled = FALSE; g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), FALSE); - iface = MATE_MIXER_STREAM_GET_INTERFACE (stream); - - if (iface->monitor_is_running) - return iface->monitor_is_running (stream); + g_object_get (G_OBJECT (stream), + "monitor-enabled", &enabled, + NULL); - return FALSE; + return enabled; } gboolean -mate_mixer_stream_monitor_set_name (MateMixerStream *stream, const gchar *name) +mate_mixer_stream_monitor_set_enabled (MateMixerStream *stream, gboolean enabled) { MateMixerStreamInterface *iface; @@ -550,29 +317,14 @@ mate_mixer_stream_monitor_set_name (MateMixerStream *stream, const gchar *name) iface = MATE_MIXER_STREAM_GET_INTERFACE (stream); - if (iface->monitor_set_name) - return iface->monitor_set_name (stream, name); + if (iface->monitor_set_enabled != NULL) + return iface->monitor_set_enabled (stream, enabled); return FALSE; } -const GList * -mate_mixer_stream_list_ports (MateMixerStream *stream) -{ - MateMixerStreamInterface *iface; - - g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), NULL); - - iface = MATE_MIXER_STREAM_GET_INTERFACE (stream); - - if (iface->list_ports) - return iface->list_ports (stream); - - return NULL; -} - -MateMixerPort * -mate_mixer_stream_get_active_port (MateMixerStream *stream) +const gchar * +mate_mixer_stream_monitor_get_name (MateMixerStream *stream) { MateMixerStreamInterface *iface; @@ -580,84 +332,23 @@ mate_mixer_stream_get_active_port (MateMixerStream *stream) iface = MATE_MIXER_STREAM_GET_INTERFACE (stream); - if (iface->get_active_port) - return iface->get_active_port (stream); + if (iface->monitor_get_name != NULL) + return iface->monitor_get_name (stream); - return NULL; + return FALSE; } gboolean -mate_mixer_stream_set_active_port (MateMixerStream *stream, MateMixerPort *port) +mate_mixer_stream_monitor_set_name (MateMixerStream *stream, const gchar *name) { 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); + if (iface->monitor_set_name != NULL) + return iface->monitor_set_name (stream, name); 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..aecf40e 100644 --- a/libmatemixer/matemixer-stream.h +++ b/libmatemixer/matemixer-stream.h @@ -18,13 +18,13 @@ #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-stream-control.h> G_BEGIN_DECLS @@ -51,131 +51,69 @@ struct _MateMixerStreamInterface GTypeInterface parent_iface; /*< 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); + const gchar * (*get_name) (MateMixerStream *stream); + const gchar * (*get_description) (MateMixerStream *stream); - /* Signals */ - void (*monitor_value) (MateMixerStream *stream, - gdouble value); -}; - -GType mate_mixer_stream_get_type (void) G_GNUC_CONST; + MateMixerStreamControl *(*get_control) (MateMixerStream *stream, + const gchar *name); + MateMixerStreamControl *(*get_default_control) (MateMixerStream *stream); -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); + MateMixerPort * (*get_port) (MateMixerStream *stream, + const gchar *name); -gboolean mate_mixer_stream_get_mute (MateMixerStream *stream); -gboolean mate_mixer_stream_set_mute (MateMixerStream *stream, - gboolean mute); + gboolean (*set_active_port) (MateMixerStream *stream, + MateMixerPort *port); -guint mate_mixer_stream_get_num_channels (MateMixerStream *stream); + const GList * (*list_controls) (MateMixerStream *stream); + const GList * (*list_ports) (MateMixerStream *stream); -guint mate_mixer_stream_get_volume (MateMixerStream *stream); -gboolean mate_mixer_stream_set_volume (MateMixerStream *stream, - guint volume); + gboolean (*suspend) (MateMixerStream *stream); + gboolean (*resume) (MateMixerStream *stream); -gdouble mate_mixer_stream_get_decibel (MateMixerStream *stream); -gboolean mate_mixer_stream_set_decibel (MateMixerStream *stream, - gdouble decibel); + gboolean (*monitor_set_enabled) (MateMixerStream *stream, + gboolean enabled); -MateMixerChannelPosition mate_mixer_stream_get_channel_position (MateMixerStream *stream, - guint channel); + const gchar * (*monitor_get_name) (MateMixerStream *stream); + gboolean (*monitor_set_name) (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); - -gdouble mate_mixer_stream_get_channel_decibel (MateMixerStream *stream, - guint channel); -gboolean mate_mixer_stream_set_channel_decibel (MateMixerStream *stream, - guint channel, - gdouble decibel); + /* Signals */ + void (*monitor_value) (MateMixerStream *stream, + gdouble value); +}; -gboolean mate_mixer_stream_has_channel_position (MateMixerStream *stream, - MateMixerChannelPosition position); +GType mate_mixer_stream_get_type (void) G_GNUC_CONST; -gfloat mate_mixer_stream_get_balance (MateMixerStream *stream); -gboolean mate_mixer_stream_set_balance (MateMixerStream *stream, - gfloat balance); +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); -gfloat mate_mixer_stream_get_fade (MateMixerStream *stream); -gboolean mate_mixer_stream_set_fade (MateMixerStream *stream, - gfloat fade); +MateMixerStreamControl *mate_mixer_stream_get_control (MateMixerStream *stream, + const gchar *name); +MateMixerStreamControl *mate_mixer_stream_get_default_control (MateMixerStream *stream); -gboolean mate_mixer_stream_suspend (MateMixerStream *stream); -gboolean mate_mixer_stream_resume (MateMixerStream *stream); +MateMixerPort * mate_mixer_stream_get_port (MateMixerStream *stream, + const gchar *name); -gboolean mate_mixer_stream_monitor_start (MateMixerStream *stream); -void mate_mixer_stream_monitor_stop (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_monitor_is_running (MateMixerStream *stream); -gboolean mate_mixer_stream_monitor_set_name (MateMixerStream *stream, - const gchar *name); +const GList * mate_mixer_stream_list_controls (MateMixerStream *stream); +const GList * mate_mixer_stream_list_ports (MateMixerStream *stream); -const GList * mate_mixer_stream_list_ports (MateMixerStream *stream); +gboolean mate_mixer_stream_suspend (MateMixerStream *stream); +gboolean mate_mixer_stream_resume (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_monitor_get_enabled (MateMixerStream *stream); +gboolean mate_mixer_stream_monitor_set_enabled (MateMixerStream *stream, + gboolean enabled); -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); +const gchar * mate_mixer_stream_monitor_get_name (MateMixerStream *stream); +gboolean mate_mixer_stream_monitor_set_name (MateMixerStream *stream, + const gchar *name); G_END_DECLS |