diff options
79 files changed, 9567 insertions, 4671 deletions
diff --git a/backends/Makefile.am b/backends/Makefile.am index 0cf8dd4..4a8afff 100644 --- a/backends/Makefile.am +++ b/backends/Makefile.am @@ -8,12 +8,12 @@ if HAVE_PULSEAUDIO  SUBDIRS += pulse  endif -if HAVE_OSS -SUBDIRS += oss +if HAVE_ALSA +SUBDIRS += alsa  endif -if HAVE_OSS4 -SUBDIRS += oss4 +if HAVE_OSS +SUBDIRS += oss  endif  -include $(top_srcdir)/git.mk diff --git a/backends/alsa/Makefile.am b/backends/alsa/Makefile.am new file mode 100644 index 0000000..220bb3b --- /dev/null +++ b/backends/alsa/Makefile.am @@ -0,0 +1,47 @@ +backenddir = $(libdir)/libmatemixer + +backend_LTLIBRARIES = libmatemixer-alsa.la + +AM_CPPFLAGS =                                                   \ +        -I$(top_srcdir)                                         \ +        -DG_LOG_DOMAIN=\"libmatemixer-alsa\" + +libmatemixer_alsa_la_CFLAGS =                                   \ +        $(GLIB_CFLAGS)                                          \ +        $(ALSA_CFLAGS) + +libmatemixer_alsa_la_SOURCES =                                  \ +        alsa-backend.c                                          \ +        alsa-backend.h                                          \ +        alsa-constants.c                                        \ +        alsa-constants.h                                        \ +        alsa-device.c                                           \ +        alsa-device.h                                           \ +        alsa-element.c                                          \ +        alsa-element.h                                          \ +        alsa-stream.c                                           \ +        alsa-stream.h                                           \ +        alsa-stream-control.c                                   \ +        alsa-stream-control.h                                   \ +        alsa-stream-input-control.c                             \ +        alsa-stream-input-control.h                             \ +        alsa-stream-output-control.c                            \ +        alsa-stream-output-control.h                            \ +        alsa-switch.c                                           \ +        alsa-switch.h                                           \ +        alsa-switch-option.c                                    \ +        alsa-switch-option.h                                    \ +        alsa-toggle.c                                           \ +        alsa-toggle.h + +libmatemixer_alsa_la_LIBADD =                                   \ +        $(GLIB_LIBS)                                            \ +        $(ALSA_LIBS) + +libmatemixer_alsa_la_LDFLAGS =                                  \ +        -avoid-version                                          \ +        -no-undefined                                           \ +        -export-dynamic                                         \ +        -module + +-include $(top_srcdir)/git.mk diff --git a/backends/alsa/alsa-backend.c b/backends/alsa/alsa-backend.c new file mode 100644 index 0000000..7a17b85 --- /dev/null +++ b/backends/alsa/alsa-backend.c @@ -0,0 +1,508 @@ +/* + * Copyright (C) 2014 Michal Ratajsky <[email protected]> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the licence, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#include <glib.h> +#include <glib-object.h> +#include <alsa/asoundlib.h> + +#include <libmatemixer/matemixer.h> +#include <libmatemixer/matemixer-private.h> + +#include "alsa-backend.h" +#include "alsa-device.h" +#include "alsa-stream.h" + +#define BACKEND_NAME      "ALSA" +#define BACKEND_PRIORITY  9 + +struct _AlsaBackendPrivate +{ +    GSource    *timeout_source; +    GHashTable *devices; +    GHashTable *devices_ids; +}; + +static void alsa_backend_class_init     (AlsaBackendClass *klass); +static void alsa_backend_class_finalize (AlsaBackendClass *klass); +static void alsa_backend_init           (AlsaBackend      *alsa); +static void alsa_backend_dispose        (GObject          *object); +static void alsa_backend_finalize       (GObject          *object); + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-function" +G_DEFINE_DYNAMIC_TYPE (AlsaBackend, alsa_backend, MATE_MIXER_TYPE_BACKEND) +#pragma clang diagnostic pop + +static gboolean alsa_backend_open            (MateMixerBackend *backend); +static void     alsa_backend_close           (MateMixerBackend *backend); +static GList *  alsa_backend_list_devices    (MateMixerBackend *backend); +static GList *  alsa_backend_list_streams    (MateMixerBackend *backend); + +static gboolean read_devices                 (AlsaBackend      *alsa); + +static gboolean read_device                  (AlsaBackend      *alsa, +                                              const gchar      *card); + +static void     add_device                   (AlsaBackend      *alsa, +                                              AlsaDevice       *device); + +static void     remove_device                (AlsaBackend      *alsa, +                                              AlsaDevice       *device); +static void     remove_stream                (AlsaBackend      *alsa, +                                              const gchar      *name); + +static void     select_default_input_stream  (AlsaBackend      *alsa); +static void     select_default_output_stream (AlsaBackend      *alsa); + +static MateMixerBackendInfo info; + +void +backend_module_init (GTypeModule *module) +{ +    alsa_backend_register_type (module); + +    info.name         = BACKEND_NAME; +    info.priority     = BACKEND_PRIORITY; +    info.g_type       = ALSA_TYPE_BACKEND; +    info.backend_type = MATE_MIXER_BACKEND_ALSA; +} + +const MateMixerBackendInfo *backend_module_get_info (void) +{ +    return &info; +} + +static void +alsa_backend_class_init (AlsaBackendClass *klass) +{ +    GObjectClass          *object_class; +    MateMixerBackendClass *backend_class; + +    object_class = G_OBJECT_CLASS (klass); +    object_class->dispose  = alsa_backend_dispose; +    object_class->finalize = alsa_backend_finalize; + +    backend_class = MATE_MIXER_BACKEND_CLASS (klass); +    backend_class->open         = alsa_backend_open; +    backend_class->close        = alsa_backend_close; +    backend_class->list_devices = alsa_backend_list_devices; +    backend_class->list_streams = alsa_backend_list_streams; + +    g_type_class_add_private (object_class, sizeof (AlsaBackendPrivate)); +} + +/* Called in the code generated by G_DEFINE_DYNAMIC_TYPE() */ +static void +alsa_backend_class_finalize (AlsaBackendClass *klass) +{ +} + +static void +alsa_backend_init (AlsaBackend *alsa) +{ +    alsa->priv = G_TYPE_INSTANCE_GET_PRIVATE (alsa, +                                             ALSA_TYPE_BACKEND, +                                             AlsaBackendPrivate); + +    alsa->priv->devices = g_hash_table_new_full (g_str_hash, +                                                 g_str_equal, +                                                 g_free, +                                                 g_object_unref); + +    alsa->priv->devices_ids = g_hash_table_new_full (g_str_hash, +                                                     g_str_equal, +                                                     g_free, +                                                     NULL); +} + +static void +alsa_backend_dispose (GObject *object) +{ +    MateMixerBackend *backend; +    MateMixerState    state; + +    backend = MATE_MIXER_BACKEND (object); + +    state = mate_mixer_backend_get_state (backend); +    if (state != MATE_MIXER_STATE_IDLE) +        alsa_backend_close (backend); + +    G_OBJECT_CLASS (alsa_backend_parent_class)->dispose (object); +} + +static void +alsa_backend_finalize (GObject *object) +{ +    AlsaBackend *alsa; + +    alsa = ALSA_BACKEND (object); + +    g_hash_table_unref (alsa->priv->devices); +    g_hash_table_unref (alsa->priv->devices_ids); + +    G_OBJECT_CLASS (alsa_backend_parent_class)->finalize (object); +} + +static gboolean +alsa_backend_open (MateMixerBackend *backend) +{ +    AlsaBackend *alsa; + +    g_return_val_if_fail (ALSA_IS_BACKEND (backend), FALSE); + +    alsa = ALSA_BACKEND (backend); + +    /* Poll ALSA for changes every 500 milliseconds, this actually only +     * discovers added or changed sound cards, sound card related events +     * are handled by AlsaDevices */ +    alsa->priv->timeout_source = g_timeout_source_new_seconds (1); +    g_source_set_callback (alsa->priv->timeout_source, +                           (GSourceFunc) read_devices, +                           alsa, +                           NULL); +    g_source_attach (alsa->priv->timeout_source, +                     g_main_context_get_thread_default ()); + +    /* Read the initial list of devices so we have some starting point, there +     * isn't really a way to detect errors here, failing to add a device may +     * be a device-related problem so make the backend always open successfully */ +    read_devices (alsa); + +    _mate_mixer_backend_set_state (backend, MATE_MIXER_STATE_READY); +    return TRUE; +} + +void +alsa_backend_close (MateMixerBackend *backend) +{ +    AlsaBackend *alsa; + +    g_return_if_fail (ALSA_IS_BACKEND (backend)); + +    alsa = ALSA_BACKEND (backend); + +    g_source_destroy (alsa->priv->timeout_source); + +    g_hash_table_remove_all (alsa->priv->devices); +    g_hash_table_remove_all (alsa->priv->devices_ids); + +    _mate_mixer_backend_set_state (backend, MATE_MIXER_STATE_IDLE); +} + +static GList * +alsa_backend_list_devices (MateMixerBackend *backend) +{ +    GList *list; + +    g_return_val_if_fail (ALSA_IS_BACKEND (backend), NULL); + +    /* Convert the hash table to a linked list, this list is expected to be +     * cached in the main library */ +    list = g_hash_table_get_values (ALSA_BACKEND (backend)->priv->devices); +    if (list != NULL) +        g_list_foreach (list, (GFunc) g_object_ref, NULL); + +    return list; +} + +static GList * +alsa_backend_list_streams (MateMixerBackend *backend) +{ +    AlsaBackend   *alsa; +    GHashTableIter iter; +    gpointer       value; +    GList         *list = NULL; + +    g_return_val_if_fail (ALSA_IS_BACKEND (backend), NULL); + +    alsa = ALSA_BACKEND (backend); + +    /* We don't keep a list or hash table of all streams here, instead walk +     * through the list of devices and create the list manually, each device +     * has at most one input and one output stream */ +    g_hash_table_iter_init (&iter, alsa->priv->devices); + +    while (g_hash_table_iter_next (&iter, NULL, &value)) { +        AlsaDevice *device = ALSA_DEVICE (value); +        AlsaStream *stream; + +        stream = alsa_device_get_output_stream (device); +        if (stream != NULL) +            list = g_list_prepend (list, stream); +        stream = alsa_device_get_input_stream (device); +        if (stream != NULL) +            list = g_list_prepend (list, stream); +    } + +    if (list != NULL) +        g_list_foreach (list, (GFunc) g_object_ref, NULL); + +    return list; +} + +static gboolean +read_devices (AlsaBackend *alsa) +{ +    gint     num; +    gint     ret; +    gchar    card[16]; +    gboolean changed = FALSE; + +    /* Read the default device first, it will be either one of the hardware cards +     * that will be queried later, or a software mixer */ +    if (read_device (alsa, "default") == TRUE) +        changed = TRUE; + +    for (num = -1;;) { +        /* Read number of the next sound card */ +        ret = snd_card_next (&num); +        if (ret < 0 || +            num < 0) +            break; + +        g_snprintf (card, sizeof (card), "hw:%d", num); + +        if (read_device (alsa, card) == TRUE) +            changed = TRUE; +    } + +    /* If any card has been added, make sure we have the most suitable default +     * input and output streams */ +    if (changed == TRUE) { +        select_default_input_stream (alsa); +        select_default_output_stream (alsa); +    } +    return G_SOURCE_CONTINUE; +} + +static gboolean +read_device (AlsaBackend *alsa, const gchar *card) +{ +    AlsaDevice          *device; +    snd_ctl_t           *ctl; +    snd_ctl_card_info_t *info; +    const gchar         *id; +    gint                 ret; + +    /* The device may be already known, remove it if it's known and fails +     * to be read, this happens for example when PulseAudio is killed */ +    device = g_hash_table_lookup (alsa->priv->devices, card); + +    ret = snd_ctl_open (&ctl, card, 0); +    if (ret < 0) { +        g_warning ("Failed to open ALSA control for %s: %s", +                   card, +                   snd_strerror (ret)); +        if (device != NULL) +            remove_device (alsa, device); +        return FALSE; +    } + +    snd_ctl_card_info_alloca (&info); + +    ret = snd_ctl_card_info (ctl, info); +    if (ret < 0) { +        g_warning ("Failed to read card info: %s", snd_strerror (ret)); +        if (device != NULL) +            remove_device (alsa, device); + +        snd_ctl_close (ctl); +        return FALSE; +    } + +    id = snd_ctl_card_info_get_id (info); + +    /* We also keep a list of device identifiers to be sure no card is +     * added twice, this could commonly happen because some card may +     * also be assigned to the "default" ALSA device */ +    if (g_hash_table_contains (alsa->priv->devices_ids, id) == TRUE) { +        snd_ctl_close (ctl); +        return FALSE; +    } + +    device = alsa_device_new (card, snd_ctl_card_info_get_name (info)); + +    if (alsa_device_open (device) == FALSE) { +        g_object_unref (device); +        snd_ctl_close (ctl); +        return FALSE; +    } + +    g_object_set_data_full (G_OBJECT (device), +                            "__matemixer_alsa_device_id", +                            g_strdup (id), +                            g_free); + +    add_device (alsa, device); + +    snd_ctl_close (ctl); +    return TRUE; +} + +static void +add_device (AlsaBackend *alsa, AlsaDevice *device) +{ +    const gchar *name; + +    name = mate_mixer_device_get_name (MATE_MIXER_DEVICE (device)); + +    g_hash_table_insert (alsa->priv->devices, +                         g_strdup (name), +                         g_object_ref (device)); + +    /* Remember the device identifier, use a single string copy as we only free +     * the hash table key */ +    g_hash_table_add (alsa->priv->devices_ids, +                      g_strdup (g_object_get_data (G_OBJECT (device), +                                                   "__matemixer_alsa_device_id"))); + +    g_signal_connect_swapped (G_OBJECT (device), +                              "closed", +                              G_CALLBACK (remove_device), +                              alsa); +    g_signal_connect_swapped (G_OBJECT (device), +                              "stream-removed", +                              G_CALLBACK (remove_stream), +                              alsa); + +    g_signal_emit_by_name (G_OBJECT (alsa), "device-added", name); + +    /* Load the device elements after emitting device-added, because the load +     * function will most likely emit stream-added on the device and backend */ +    alsa_device_load (device); +} + +static void +remove_device (AlsaBackend *alsa, AlsaDevice *device) +{ +    const gchar *name; + +    name = mate_mixer_device_get_name (MATE_MIXER_DEVICE (device)); + +    g_signal_handlers_disconnect_by_func (G_OBJECT (device), +                                          G_CALLBACK (remove_device), +                                          alsa); +    g_signal_handlers_disconnect_by_func (G_OBJECT (device), +                                          G_CALLBACK (remove_stream), +                                          alsa); + +    /* Remove the device */ +    g_hash_table_remove (alsa->priv->devices_ids, +                         g_object_get_data (G_OBJECT (device), +                                            "__matemixer_alsa_device_id")); + +    // XXX close the device and make it remove streams +    g_hash_table_remove (alsa->priv->devices, name); +    g_signal_emit_by_name (G_OBJECT (alsa), +                           "device-removed", +                           name); +} + +static void +remove_stream (AlsaBackend *alsa, const gchar *name) +{ +    MateMixerStream *stream; + +    stream = mate_mixer_backend_get_default_input_stream (MATE_MIXER_BACKEND (alsa)); + +    // XXX see if the change happens after stream is removed or before +    if (stream != NULL && strcmp (mate_mixer_stream_get_name (stream), name) == 0) +        select_default_input_stream (alsa); + +    stream = mate_mixer_backend_get_default_output_stream (MATE_MIXER_BACKEND (alsa)); + +    if (stream != NULL && strcmp (mate_mixer_stream_get_name (stream), name) == 0) +        select_default_output_stream (alsa); +} + +static void +select_default_input_stream (AlsaBackend *alsa) +{ +    AlsaDevice *device; +    AlsaStream *stream; +    gchar       card[16]; +    gint        num; + +    /* Always prefer stream in the "default" device */ +    device = g_hash_table_lookup (alsa->priv->devices, "default"); +    if (device != NULL) { +        stream = alsa_device_get_input_stream (device); +        if (stream != NULL) { +            _mate_mixer_backend_set_default_input_stream (MATE_MIXER_BACKEND (alsa), +                                                          MATE_MIXER_STREAM (stream)); +            return; +        } +    } + +    /* If there is no input stream in the default device, search the cards in +     * the correct order */ +    for (num = 0;; num++) { +        g_snprintf (card, sizeof (card), "hw:%d", num); + +        device = g_hash_table_lookup (alsa->priv->devices, card); +        if (device == NULL) +            break; +        stream = alsa_device_get_input_stream (device); +        if (stream != NULL) { +            _mate_mixer_backend_set_default_input_stream (MATE_MIXER_BACKEND (alsa), +                                                          MATE_MIXER_STREAM (stream)); +            return; +        } +    } + +    /* In the worst case unset the default stream */ +    _mate_mixer_backend_set_default_input_stream (MATE_MIXER_BACKEND (alsa), NULL); +} + +static void +select_default_output_stream (AlsaBackend *alsa) +{ +    AlsaDevice *device; +    AlsaStream *stream; +    gchar       card[16]; +    gint        num; + +    /* Always prefer stream in the "default" device */ +    device = g_hash_table_lookup (alsa->priv->devices, "default"); +    if (device != NULL) { +        stream = alsa_device_get_output_stream (device); +        if (stream != NULL) { +            _mate_mixer_backend_set_default_output_stream (MATE_MIXER_BACKEND (alsa), +                                                           MATE_MIXER_STREAM (stream)); +            return; +        } +    } + +    /* If there is no input stream in the default device, search the cards in +     * the correct order */ +    for (num = 0;; num++) { +        g_snprintf (card, sizeof (card), "hw:%d", num); + +        device = g_hash_table_lookup (alsa->priv->devices, card); +        if (device == NULL) +            break; +        stream = alsa_device_get_output_stream (device); +        if (stream != NULL) { +            _mate_mixer_backend_set_default_output_stream (MATE_MIXER_BACKEND (alsa), +                                                           MATE_MIXER_STREAM (stream)); +            return; +        } +    } + +    /* In the worst case unset the default stream */ +    _mate_mixer_backend_set_default_output_stream (MATE_MIXER_BACKEND (alsa), NULL); +} diff --git a/backends/alsa/alsa-backend.h b/backends/alsa/alsa-backend.h new file mode 100644 index 0000000..03fedf0 --- /dev/null +++ b/backends/alsa/alsa-backend.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2014 Michal Ratajsky <[email protected]> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the licence, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef ALSA_BACKEND_H +#define ALSA_BACKEND_H + +#include <glib.h> +#include <glib-object.h> +#include <libmatemixer/matemixer.h> +#include <libmatemixer/matemixer-private.h> + +#define ALSA_TYPE_BACKEND                       \ +        (alsa_backend_get_type ()) +#define ALSA_BACKEND(o)                         \ +        (G_TYPE_CHECK_INSTANCE_CAST ((o), ALSA_TYPE_BACKEND, AlsaBackend)) +#define ALSA_IS_BACKEND(o)                      \ +        (G_TYPE_CHECK_INSTANCE_TYPE ((o), ALSA_TYPE_BACKEND)) +#define ALSA_BACKEND_CLASS(k)                   \ +        (G_TYPE_CHECK_CLASS_CAST ((k), ALSA_TYPE_BACKEND, AlsaBackendClass)) +#define ALSA_IS_BACKEND_CLASS(k)                \ +        (G_TYPE_CHECK_CLASS_TYPE ((k), ALSA_TYPE_BACKEND)) +#define ALSA_BACKEND_GET_CLASS(o)               \ +        (G_TYPE_INSTANCE_GET_CLASS ((o), ALSA_TYPE_BACKEND, AlsaBackendClass)) + +typedef struct _AlsaBackend         AlsaBackend; +typedef struct _AlsaBackendClass    AlsaBackendClass; +typedef struct _AlsaBackendPrivate  AlsaBackendPrivate; + +struct _AlsaBackend +{ +    MateMixerBackend parent; + +    /*< private >*/ +    AlsaBackendPrivate *priv; +}; + +struct _AlsaBackendClass +{ +    MateMixerBackendClass parent_class; +}; + +GType                       alsa_backend_get_type   (void) G_GNUC_CONST; + +/* Support function for dynamic loading of the backend module */ +void                        backend_module_init     (GTypeModule *module); +const MateMixerBackendInfo *backend_module_get_info (void); + +#endif /* ALSA_BACKEND_H */ diff --git a/backends/alsa/alsa-constants.c b/backends/alsa/alsa-constants.c new file mode 100644 index 0000000..2124a2e --- /dev/null +++ b/backends/alsa/alsa-constants.c @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2014 Michal Ratajsky <[email protected]> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the licence, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#include <glib.h> +#include <glib/gi18n.h> +#include <alsa/asoundlib.h> +#include <libmatemixer/matemixer.h> + +#include "alsa-constants.h" + +// XXX add more and probably move them somewhere else +const AlsaControlInfo alsa_controls[] = +{ +    { "Master",   N_("Master"),  MATE_MIXER_STREAM_CONTROL_ROLE_MASTER }, +    { "Speaker",  N_("Speaker"), MATE_MIXER_STREAM_CONTROL_ROLE_MASTER }, +    { "Capture",  N_("Capture"), MATE_MIXER_STREAM_CONTROL_ROLE_MASTER }, +    { "PCM",      N_("PCM"),     MATE_MIXER_STREAM_CONTROL_ROLE_PCM }, +    { "Line",     N_("Line"),    MATE_MIXER_STREAM_CONTROL_ROLE_PORT }, +    { "Mic",      N_("Mic"),     MATE_MIXER_STREAM_CONTROL_ROLE_PORT }, +    { NULL } +}; + +const MateMixerChannelPosition alsa_channel_map_from[SND_MIXER_SCHN_LAST] = +{ +    [SND_MIXER_SCHN_FRONT_LEFT]             = MATE_MIXER_CHANNEL_FRONT_LEFT, +    [SND_MIXER_SCHN_FRONT_RIGHT]            = MATE_MIXER_CHANNEL_FRONT_RIGHT, +    [SND_MIXER_SCHN_REAR_LEFT]              = MATE_MIXER_CHANNEL_BACK_LEFT, +    [SND_MIXER_SCHN_REAR_RIGHT]             = MATE_MIXER_CHANNEL_BACK_RIGHT, +    [SND_MIXER_SCHN_FRONT_CENTER]           = MATE_MIXER_CHANNEL_FRONT_CENTER, +    [SND_MIXER_SCHN_WOOFER]                 = MATE_MIXER_CHANNEL_LFE, +    [SND_MIXER_SCHN_SIDE_LEFT]              = MATE_MIXER_CHANNEL_SIDE_LEFT, +    [SND_MIXER_SCHN_SIDE_RIGHT]             = MATE_MIXER_CHANNEL_SIDE_RIGHT, +    [SND_MIXER_SCHN_REAR_CENTER]            = MATE_MIXER_CHANNEL_BACK_CENTER +}; + +const snd_mixer_selem_channel_id_t alsa_channel_map_to[MATE_MIXER_CHANNEL_MAX] = +{ +    [MATE_MIXER_CHANNEL_UNKNOWN]            = SND_MIXER_SCHN_UNKNOWN, +    [MATE_MIXER_CHANNEL_MONO]               = SND_MIXER_SCHN_MONO, +    [MATE_MIXER_CHANNEL_FRONT_LEFT]         = SND_MIXER_SCHN_FRONT_LEFT, +    [MATE_MIXER_CHANNEL_FRONT_RIGHT]        = SND_MIXER_SCHN_FRONT_RIGHT, +    [MATE_MIXER_CHANNEL_FRONT_CENTER]       = SND_MIXER_SCHN_FRONT_CENTER, +    [MATE_MIXER_CHANNEL_LFE]                = SND_MIXER_SCHN_WOOFER, +    [MATE_MIXER_CHANNEL_BACK_LEFT]          = SND_MIXER_SCHN_REAR_LEFT, +    [MATE_MIXER_CHANNEL_BACK_RIGHT]         = SND_MIXER_SCHN_REAR_RIGHT, +    [MATE_MIXER_CHANNEL_BACK_CENTER]        = SND_MIXER_SCHN_REAR_CENTER, +    [MATE_MIXER_CHANNEL_FRONT_LEFT_CENTER]  = SND_MIXER_SCHN_UNKNOWN, +    [MATE_MIXER_CHANNEL_FRONT_RIGHT_CENTER] = SND_MIXER_SCHN_UNKNOWN, +    [MATE_MIXER_CHANNEL_SIDE_LEFT]          = SND_MIXER_SCHN_SIDE_LEFT, +    [MATE_MIXER_CHANNEL_SIDE_RIGHT]         = SND_MIXER_SCHN_SIDE_RIGHT, +    [MATE_MIXER_CHANNEL_TOP_FRONT_LEFT]     = SND_MIXER_SCHN_UNKNOWN, +    [MATE_MIXER_CHANNEL_TOP_FRONT_RIGHT]    = SND_MIXER_SCHN_UNKNOWN, +    [MATE_MIXER_CHANNEL_TOP_FRONT_CENTER]   = SND_MIXER_SCHN_UNKNOWN, +    [MATE_MIXER_CHANNEL_TOP_CENTER]         = SND_MIXER_SCHN_UNKNOWN, +    [MATE_MIXER_CHANNEL_TOP_BACK_LEFT]      = SND_MIXER_SCHN_UNKNOWN, +    [MATE_MIXER_CHANNEL_TOP_BACK_RIGHT]     = SND_MIXER_SCHN_UNKNOWN, +    [MATE_MIXER_CHANNEL_TOP_BACK_CENTER]    = SND_MIXER_SCHN_UNKNOWN +}; diff --git a/backends/alsa/alsa-constants.h b/backends/alsa/alsa-constants.h new file mode 100644 index 0000000..81257c7 --- /dev/null +++ b/backends/alsa/alsa-constants.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2014 Michal Ratajsky <[email protected]> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the licence, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef ALSA_CONSTANTS_H +#define ALSA_CONSTANTS_H + +#include <glib.h> +#include <alsa/asoundlib.h> +#include <libmatemixer/matemixer.h> + +typedef struct { +    gchar                     *name; +    gchar                     *label; +    MateMixerStreamControlRole role; +} AlsaControlInfo; + +extern const AlsaControlInfo                alsa_controls[]; +extern const MateMixerChannelPosition       alsa_channel_map_from[]; +extern const snd_mixer_selem_channel_id_t   alsa_channel_map_to[]; + +#endif /* ALSA_CONSTANTS_H */ diff --git a/backends/alsa/alsa-device.c b/backends/alsa/alsa-device.c new file mode 100644 index 0000000..5acc6f5 --- /dev/null +++ b/backends/alsa/alsa-device.c @@ -0,0 +1,941 @@ +/* + * Copyright (C) 2014 Michal Ratajsky <[email protected]> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the licence, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#include <strings.h> +#include <glib.h> +#include <glib/gi18n.h> +#include <glib-object.h> +#include <alsa/asoundlib.h> +#include <libmatemixer/matemixer.h> + +#include "alsa-constants.h" +#include "alsa-device.h" +#include "alsa-element.h" +#include "alsa-stream.h" +#include "alsa-stream-control.h" +#include "alsa-stream-input-control.h" +#include "alsa-stream-output-control.h" +#include "alsa-switch.h" +#include "alsa-switch-option.h" +#include "alsa-toggle.h" + +#define ALSA_DEVICE_ICON "audio-card" + +struct _AlsaDevicePrivate +{ +    snd_mixer_t  *handle; +    GMainContext *context; +    GMutex        mutex; +    GCond         cond; +    AlsaStream   *input; +    AlsaStream   *output; +    GHashTable   *switches; +    gboolean      events_pending; +}; + +enum { +    CLOSED, +    N_SIGNALS +}; + +static guint signals[N_SIGNALS] = { 0, }; + +static void alsa_device_class_init (AlsaDeviceClass *klass); +static void alsa_device_init       (AlsaDevice      *device); +static void alsa_device_dispose    (GObject         *object); +static void alsa_device_finalize   (GObject         *object); + +G_DEFINE_TYPE (AlsaDevice, alsa_device, MATE_MIXER_TYPE_DEVICE) + +static MateMixerSwitch *alsa_device_get_switch    (MateMixerDevice            *mmd, +                                                   const gchar                *name); + +static GList *          alsa_device_list_streams  (MateMixerDevice            *mmd); +static GList *          alsa_device_list_switches (MateMixerDevice            *mmd); + +static gboolean         add_stream_input_control  (AlsaDevice                 *device, +                                                   snd_mixer_elem_t           *el); +static gboolean         add_stream_output_control (AlsaDevice                 *device, +                                                   snd_mixer_elem_t           *el); + +static gboolean         add_switch                (AlsaDevice                 *device, +                                                   AlsaStream                 *stream, +                                                   snd_mixer_elem_t           *el); + +static gboolean         add_device_switch         (AlsaDevice                 *device, +                                                   snd_mixer_elem_t           *el); + +static gboolean         add_stream_input_switch   (AlsaDevice                 *device, +                                                   snd_mixer_elem_t           *el); +static gboolean         add_stream_output_switch  (AlsaDevice                 *device, +                                                   snd_mixer_elem_t           *el); + +static gboolean         add_stream_input_toggle   (AlsaDevice                 *device, +                                                   snd_mixer_elem_t           *el); +static gboolean         add_stream_output_toggle  (AlsaDevice                 *device, +                                                   snd_mixer_elem_t           *el); + +static void             load_element              (AlsaDevice                 *device, +                                                   snd_mixer_elem_t           *el); + +static void             load_elements_by_name     (AlsaDevice                 *device, +                                                   const gchar                *name); + +static void             remove_elements_by_name   (AlsaDevice                 *device, +                                                   const gchar                *name); + +static void             handle_poll               (AlsaDevice                 *device); + +static gboolean         handle_process_events     (AlsaDevice                 *device); + +static int              handle_callback           (snd_mixer_t                *handle, +                                                   guint                       mask, +                                                   snd_mixer_elem_t           *el); +static int              handle_element_callback   (snd_mixer_elem_t           *el, +                                                   guint                       mask); + +static void             close_device              (AlsaDevice                 *device); + +static gchar *          get_element_name          (snd_mixer_elem_t           *el); +static void             get_control_info          (snd_mixer_elem_t           *el, +                                                   gchar                     **name, +                                                   gchar                     **label, +                                                   MateMixerStreamControlRole *role); + +static void             get_switch_info           (snd_mixer_elem_t           *el, +                                                   gchar                     **name, +                                                   gchar                     **label); + +static void +alsa_device_class_init (AlsaDeviceClass *klass) +{ +    GObjectClass         *object_class; +    MateMixerDeviceClass *device_class; + +    object_class = G_OBJECT_CLASS (klass); +    object_class->dispose  = alsa_device_dispose; +    object_class->finalize = alsa_device_finalize; + +    device_class = MATE_MIXER_DEVICE_CLASS (klass); +    device_class->get_switch    = alsa_device_get_switch; +    device_class->list_streams  = alsa_device_list_streams; +    device_class->list_switches = alsa_device_list_switches; + +    signals[CLOSED] = +        g_signal_new ("closed", +                      G_TYPE_FROM_CLASS (object_class), +                      G_SIGNAL_RUN_LAST, +                      G_STRUCT_OFFSET (AlsaDeviceClass, closed), +                      NULL, +                      NULL, +                      g_cclosure_marshal_VOID__VOID, +                      G_TYPE_NONE, +                      0, +                      G_TYPE_NONE); + +    g_type_class_add_private (object_class, sizeof (AlsaDevicePrivate)); +} + +static void +alsa_device_init (AlsaDevice *device) +{ +    device->priv = G_TYPE_INSTANCE_GET_PRIVATE (device, +                                                ALSA_TYPE_DEVICE, +                                                AlsaDevicePrivate); + +    device->priv->switches = g_hash_table_new_full (g_str_hash, +                                                    g_str_equal, +                                                    g_free, +                                                    g_object_unref); + +    device->priv->context = g_main_context_ref_thread_default (); + +    g_mutex_init (&device->priv->mutex); +    g_cond_init (&device->priv->cond); +} + +static void +alsa_device_dispose (GObject *object) +{ +    AlsaDevice *device; + +    device = ALSA_DEVICE (object); + +    g_clear_object (&device->priv->input); +    g_clear_object (&device->priv->output); + +    g_hash_table_remove_all (device->priv->switches); + +    G_OBJECT_CLASS (alsa_device_parent_class)->dispose (object); +} + +static void +alsa_device_finalize (GObject *object) +{ +    AlsaDevice *device; + +    device = ALSA_DEVICE (object); + +    g_mutex_clear (&device->priv->mutex); +    g_cond_clear (&device->priv->cond); + +    g_hash_table_unref (device->priv->switches); +    g_main_context_unref (device->priv->context); + +    if (device->priv->handle != NULL) +        snd_mixer_close (device->priv->handle); + +    G_OBJECT_CLASS (alsa_device_parent_class)->dispose (object); +} + +AlsaDevice * +alsa_device_new (const gchar *name, const gchar *label) +{ +    AlsaDevice  *device; +    gchar       *stream_name; + +    g_return_val_if_fail (name != NULL, NULL); +    g_return_val_if_fail (label != NULL, NULL); + +    device = g_object_new (ALSA_TYPE_DEVICE, +                           "name", name, +                           "label", label, +                           "icon", ALSA_DEVICE_ICON, +                           NULL); + +    /* Create input and output streams, they will exist the whole time, but +     * the added and removed signals will be emitted when the first control or +     * switch is added or the last one removed */ +    stream_name = g_strdup_printf ("alsa-input-%s", name); +    device->priv->input = alsa_stream_new (stream_name, +                                           MATE_MIXER_DEVICE (device), +                                           MATE_MIXER_STREAM_INPUT); +    g_free (stream_name); + +    stream_name = g_strdup_printf ("alsa-output-%s", name); +    device->priv->output = alsa_stream_new (stream_name, +                                            MATE_MIXER_DEVICE (device), +                                            MATE_MIXER_STREAM_OUTPUT); +    g_free (stream_name); + +    return device; +} + +gboolean +alsa_device_open (AlsaDevice *device) +{ +    snd_mixer_t *handle; +    const gchar *name; +    gint         ret; + +    g_return_val_if_fail (ALSA_IS_DEVICE (device), FALSE); +    g_return_val_if_fail (device->priv->handle == NULL, FALSE); + +    name = mate_mixer_device_get_name (MATE_MIXER_DEVICE (device)); + +    g_debug ("Opening device %s (%s)", +             name, +             mate_mixer_device_get_label (MATE_MIXER_DEVICE (device))); + +    /* Open the mixer for the current device */ +    ret = snd_mixer_open (&handle, 0); +    if (ret < 0) { +        g_warning ("Failed to open mixer: %s", snd_strerror (ret)); +        return FALSE; +    } +    ret = snd_mixer_attach (handle, name); +    if (ret < 0) { +        g_warning ("Failed to attach mixer to %s: %s", +                   name, +                   snd_strerror (ret)); + +        snd_mixer_close (handle); +        return FALSE; +    } +    ret = snd_mixer_selem_register (handle, NULL, NULL); +    if (ret < 0) { +        g_warning ("Failed to register simple element for %s: %s", +                   name, +                   snd_strerror (ret)); + +        snd_mixer_close (handle); +        return FALSE; +    } +    ret = snd_mixer_load (handle); +    if (ret < 0) { +        g_warning ("Failed to load mixer elements for %s: %s", +                   name, +                   snd_strerror (ret)); + +        snd_mixer_close (handle); +        return FALSE; +    } + +    device->priv->handle = handle; +    return TRUE; +} + +void +alsa_device_load (AlsaDevice *device) +{ +    GThread          *thread; +    GError           *error = NULL; +    snd_mixer_elem_t *el; + +    g_return_if_fail (ALSA_IS_DEVICE (device)); +    g_return_if_fail (device->priv->handle != NULL); + +    /* Process the mixer elements */ +    el = snd_mixer_first_elem (device->priv->handle); +    while (el != NULL) { +        load_element (device, el); + +        el = snd_mixer_elem_next (el); +    } + +    /* Set callback for ALSA events */ +    snd_mixer_set_callback (device->priv->handle, handle_callback); +    snd_mixer_set_callback_private (device->priv->handle, device); + +    /* Start the polling thread */ +    thread = g_thread_try_new ("matemixer-alsa-poll", +                               (GThreadFunc) handle_poll, +                               device, +                               &error); +    if (thread == NULL) { +        /* The error is not treated as fatal, because without the polling +         * thread we still have most of the functionality */ +        g_warning ("Failed to create poll thread: %s", error->message); +        g_error_free (error); +    } else +        g_thread_unref (thread); +} + +AlsaStream * +alsa_device_get_input_stream (AlsaDevice *device) +{ +    g_return_val_if_fail (ALSA_IS_DEVICE (device), NULL); + +    /* Normally controlless streams should not exist, here we simulate the +     * behaviour for the owning instance */ +    if (alsa_stream_is_empty (device->priv->input) == FALSE) +        return device->priv->input; + +    return NULL; +} + +AlsaStream * +alsa_device_get_output_stream (AlsaDevice *device) +{ +    g_return_val_if_fail (ALSA_IS_DEVICE (device), NULL); + +    /* Normally controlless streams should not exist, here we simulate the +     * behaviour for the owning instance */ +    if (alsa_stream_is_empty (device->priv->output) == FALSE) +        return device->priv->output; + +    return NULL; +} + +static gboolean +add_element (AlsaDevice *device, AlsaStream *stream, AlsaElement *element) +{ +    gboolean added = FALSE; + +    if (alsa_element_load (element) == FALSE) +        return FALSE; + +    if (stream != NULL) { +        gboolean empty = FALSE; + +        if (alsa_stream_is_empty (stream) == TRUE) { +            const gchar *name = +                mate_mixer_stream_get_name (MATE_MIXER_STREAM (stream)); + +            /* Pretend the stream has just been created now that we are adding +             * the first control */ +            g_signal_emit_by_name (G_OBJECT (device), +                                   "stream-added", +                                   name); +            empty = TRUE; +        } + +        if (ALSA_IS_STREAM_CONTROL (element)) { +            alsa_stream_add_control (stream, ALSA_STREAM_CONTROL (element)); + +            /* If this is the first control, set it as the default one. +             * The controls often seem to come in the order of importance, but this is +             * driver specific, so we may later see if there is another control which +             * better matches the default. */ +            if (empty == TRUE) +                alsa_stream_set_default_control (stream, ALSA_STREAM_CONTROL (element)); + +            added = TRUE; +        } else if (ALSA_IS_SWITCH (element)) { +            /* Switch belonging to a stream */ +            alsa_stream_add_switch (stream, ALSA_SWITCH (element)); +            added = TRUE; +        } +    } else if (ALSA_IS_SWITCH (element)) { +        /* Switch belonging to the device */ +        const gchar *name = +            mate_mixer_switch_get_name (MATE_MIXER_SWITCH (element)); + +        g_hash_table_insert (device->priv->switches, +                             g_strdup (name), +                             g_object_ref (element)); + +        g_signal_emit_by_name (G_OBJECT (device), +                               "switch-added", +                               name); +        added = TRUE; +    } + +    if G_LIKELY (added == TRUE) { +        snd_mixer_elem_t *el = alsa_element_get_snd_element (element); + +        snd_mixer_elem_set_callback (el, handle_element_callback); +        snd_mixer_elem_set_callback_private (el, device); +    } +    return added; +} + +static MateMixerSwitch * +alsa_device_get_switch (MateMixerDevice *mmd, const gchar *name) +{ +    g_return_val_if_fail (ALSA_IS_DEVICE (mmd), NULL); +    g_return_val_if_fail (name != NULL, NULL); + +    return g_hash_table_lookup (ALSA_DEVICE (mmd)->priv->switches, name); +} + +static GList * +alsa_device_list_streams (MateMixerDevice *mmd) +{ +    AlsaDevice *device; +    GList      *list = NULL; + +    g_return_val_if_fail (ALSA_IS_DEVICE (mmd), NULL); + +    device = ALSA_DEVICE (mmd); + +    if (device->priv->output != NULL) +        list = g_list_prepend (list, g_object_ref (device->priv->output)); +    if (device->priv->input != NULL) +        list = g_list_prepend (list, g_object_ref (device->priv->input)); + +    return list; +} + +static GList * +alsa_device_list_switches (MateMixerDevice *mmd) +{ +    GList *list; + +    g_return_val_if_fail (ALSA_IS_DEVICE (mmd), NULL); + +    /* Convert the hash table to a linked list, this list is expected to be +     * cached in the main library */ +    list = g_hash_table_get_values (ALSA_DEVICE (mmd)->priv->switches); +    if (list != NULL) +        g_list_foreach (list, (GFunc) g_object_ref, NULL); + +    return list; +} + +static gboolean +add_stream_input_control (AlsaDevice *device, snd_mixer_elem_t *el) +{ +    AlsaStreamControl         *control; +    gchar                     *name; +    gchar                     *label; +    MateMixerStreamControlRole role; + +    get_control_info (el, &name, &label, &role); + +    g_debug ("Found device %s input control %s", +             mate_mixer_device_get_name (MATE_MIXER_DEVICE (device)), +             label); + +    control = alsa_stream_input_control_new (name, label, role); +    g_free (name); +    g_free (label); + +    alsa_element_set_snd_element (ALSA_ELEMENT (control), el); + +    if (add_element (device, device->priv->input, ALSA_ELEMENT (control)) == FALSE) { +        g_object_unref (control); +        return FALSE; +    } +    return TRUE; +} + +static gboolean +add_stream_output_control (AlsaDevice *device, snd_mixer_elem_t *el) +{ +    AlsaStreamControl         *control; +    gchar                     *label; +    gchar                     *name; +    MateMixerStreamControlRole role; + +    get_control_info (el, &name, &label, &role); + +    g_debug ("Found device %s output control %s", +             mate_mixer_device_get_name (MATE_MIXER_DEVICE (device)), +             label); + +    control = alsa_stream_output_control_new (name, label, role); +    g_free (name); +    g_free (label); + +    alsa_element_set_snd_element (ALSA_ELEMENT (control), el); + +    if (add_element (device, device->priv->output, ALSA_ELEMENT (control)) == FALSE) { +        g_object_unref (control); +        return FALSE; +    } +    return TRUE; +} + +static AlsaToggle * +create_toggle (AlsaDevice *device, snd_mixer_elem_t *el, AlsaToggleType type) +{ +    AlsaToggle       *toggle; +    AlsaSwitchOption *on; +    AlsaSwitchOption *off; +    gchar            *name; +    gchar            *label; + +    on  = alsa_switch_option_new ("On", _("On"), NULL, 1); +    off = alsa_switch_option_new ("Off", _("Off"), NULL, 0); + +    get_switch_info (el, &name, &label); +    toggle = alsa_toggle_new (name, +                              label, +                              type, +                              on, off); +    g_free (name); +    g_free (label); + +    alsa_element_set_snd_element (ALSA_ELEMENT (toggle), el); + +    g_object_unref (on); +    g_object_unref (off); + +    return toggle; +} + +static gboolean +add_switch (AlsaDevice *device, AlsaStream *stream, snd_mixer_elem_t *el) +{ +    AlsaElement *element = NULL; +    GList       *options = NULL; +    gchar       *name; +    gchar       *label; +    gchar        item[128]; +    guint        i; +    gint         count; +    gint         ret; + +    count = snd_mixer_selem_get_enum_items (el); +    if G_UNLIKELY (count <= 0) { +        g_debug ("Skipping mixer switch %s with %d items", +                 snd_mixer_selem_get_name (el), +                 count); +        return FALSE; +    } + +    for (i = 0; i < count; i++) { +        ret = snd_mixer_selem_get_enum_item_name (el, i, +                                                  sizeof (item), +                                                  item); +        if G_LIKELY (ret == 0) +            options = g_list_prepend (options, +                                      alsa_switch_option_new (item, item, NULL, i)); +        else +            g_warning ("Failed to read switch item name: %s", snd_strerror (ret)); +    } + +    get_switch_info (el, &name, &label); + +    /* Takes ownership of options */ +    element = ALSA_ELEMENT (alsa_switch_new (name, label, g_list_reverse (options))); +    g_free (name); +    g_free (label); + +    alsa_element_set_snd_element (element, el); + +    if (add_element (device, stream, element) == FALSE) { +        g_object_unref (element); +        return FALSE; +    } +    return TRUE; +} + +static gboolean +add_device_switch (AlsaDevice *device, snd_mixer_elem_t *el) +{ +    g_debug ("Reading device %s switch %s (%d items)", +             mate_mixer_device_get_name (MATE_MIXER_DEVICE (device)), +             snd_mixer_selem_get_name (el), +             snd_mixer_selem_get_enum_items (el)); + +    return add_switch (device, NULL, el); +} + +static gboolean +add_stream_input_switch (AlsaDevice *device, snd_mixer_elem_t *el) +{ +    g_debug ("Reading device %s input switch %s (%d items)", +             mate_mixer_device_get_name (MATE_MIXER_DEVICE (device)), +             snd_mixer_selem_get_name (el), +             snd_mixer_selem_get_enum_items (el)); + +    return add_switch (device, device->priv->input, el); +} + +static gboolean +add_stream_output_switch (AlsaDevice *device, snd_mixer_elem_t *el) +{ +    g_debug ("Reading device %s output switch %s (%d items)", +             mate_mixer_device_get_name (MATE_MIXER_DEVICE (device)), +             snd_mixer_selem_get_name (el), +             snd_mixer_selem_get_enum_items (el)); + +    return add_switch (device, device->priv->output, el); +} + +static gboolean +add_stream_input_toggle (AlsaDevice *device, snd_mixer_elem_t *el) +{ +    AlsaToggle *toggle; + +    g_debug ("Reading device %s input toggle %s", +             mate_mixer_device_get_name (MATE_MIXER_DEVICE (device)), +             snd_mixer_selem_get_name (el)); + +    toggle = create_toggle (device, el, ALSA_TOGGLE_CAPTURE); + +    if (add_element (device, device->priv->input, ALSA_ELEMENT (toggle)) == FALSE) { +        g_object_unref (toggle); +        return FALSE; +    } +    return TRUE; +} + +static gboolean +add_stream_output_toggle (AlsaDevice *device, snd_mixer_elem_t *el) +{ +    AlsaToggle *toggle; + +    g_debug ("Reading device %s output toggle %s", +             mate_mixer_device_get_name (MATE_MIXER_DEVICE (device)), +             snd_mixer_selem_get_name (el)); + +    toggle = create_toggle (device, el, ALSA_TOGGLE_PLAYBACK); + +    if (add_element (device, device->priv->output, ALSA_ELEMENT (toggle)) == FALSE) { +        g_object_unref (toggle); +        return FALSE; +    } +    return TRUE; +} + +static void +load_element (AlsaDevice *device, snd_mixer_elem_t *el) +{ +    gboolean cvolume = FALSE; +    gboolean pvolume = FALSE; + +    if (snd_mixer_selem_is_enumerated (el) == 1) { +        gboolean cenum = FALSE; +        gboolean penum = FALSE; + +        if (snd_mixer_selem_is_enum_capture (el) == 1) +            cenum = TRUE; +        if (snd_mixer_selem_is_enum_playback (el) == 1) +            penum = TRUE; + +        /* Enumerated controls which are not marked as capture or playback +         * are considered to be a part of the whole device, although sometimes +         * this is incorrectly reported by the driver */ +        if (cenum == FALSE && penum == FALSE) { +            add_device_switch (device, el); +        } +        else if (cenum == TRUE) +            add_stream_input_switch (device, el); +        else if (penum == TRUE) +            add_stream_output_switch (device, el); +    } + +    if (snd_mixer_selem_has_capture_volume (el) == 1 || +        snd_mixer_selem_has_common_volume (el) == 1) +        cvolume = TRUE; +    if (snd_mixer_selem_has_playback_volume (el) == 1 || +        snd_mixer_selem_has_common_volume (el) == 1) +        pvolume = TRUE; + +    if (cvolume == FALSE && pvolume == FALSE) { +        /* Control without volume and with a switch are modelled as toggles */ +        if (snd_mixer_selem_has_capture_switch (el) == 1) +            add_stream_input_toggle (device, el); + +        if (snd_mixer_selem_has_playback_switch (el) == 1) +            add_stream_output_toggle (device, el); +    } else { +        if (cvolume == TRUE) +            add_stream_input_control (device, el); +        if (pvolume == TRUE) +            add_stream_output_control (device, el); +    } +} + +static void +load_elements_by_name (AlsaDevice *device, const gchar *name) +{ +    AlsaElement *element; + +    alsa_stream_load_elements (device->priv->input, name); +    alsa_stream_load_elements (device->priv->output, name); + +    element = g_hash_table_lookup (device->priv->switches, name); +    if (element != NULL) +        alsa_element_load (element); +} + +static void +remove_elements_by_name (AlsaDevice *device, const gchar *name) +{ +    if (alsa_stream_remove_elements (device->priv->input, name) == TRUE) { +        /* Removing last stream element "removes" the stream */ +        if (alsa_stream_is_empty (device->priv->input) == TRUE) { +            const gchar *stream_name = +                mate_mixer_stream_get_name (MATE_MIXER_STREAM (device->priv->input)); + +            g_signal_emit_by_name (G_OBJECT (device), +                                   "stream-removed", +                                   stream_name); +        } +    } + +    if (alsa_stream_remove_elements (device->priv->output, name) == TRUE) { +        /* Removing last stream element "removes" the stream */ +        if (alsa_stream_is_empty (device->priv->output) == TRUE) { +            const gchar *stream_name = +                mate_mixer_stream_get_name (MATE_MIXER_STREAM (device->priv->output)); + +            g_signal_emit_by_name (G_OBJECT (device), +                                   "stream-removed", +                                   stream_name); +        } +    } + +    if (g_hash_table_remove (device->priv->switches, name) == TRUE) +        g_signal_emit_by_name (G_OBJECT (device), +                               "switch-removed", +                               name); +} + +static void +handle_poll (AlsaDevice *device) +{ +    /* This function is called in a worker thread. It is supposed to wait for +     * ALSA events and call handle_process_events(). Processing the events might +     * result in emitting the CLOSED signal and unreffing the instance in the +     * owner, so keep an extra reference during the lifetime of the thread. */ +    g_object_ref (device); + +    while (TRUE) { +        gint ret = snd_mixer_wait (device->priv->handle, -1); +        if (ret < 0) { +            if (ret == EINTR) +                continue; +            break; +        } + +        device->priv->events_pending = TRUE; + +        /* Process the events in the main thread because most events end up +         * emitting signals */ +        g_main_context_invoke (device->priv->context, +                               (GSourceFunc) handle_process_events, +                               device); + +        g_mutex_lock (&device->priv->mutex); + +        /* Use a GCond to wait until the events are processed. The processing +         * function may be called any time later in the main loop and snd_mixer_wait() +         * returns instantly while there are pending events. Without the wait, +         * g_main_context_invoke() could be called repeatedly to create idle sources +         * until the first idle source function is called. */ +        while (device->priv->events_pending == TRUE) +            g_cond_wait (&device->priv->cond, &device->priv->mutex); + +        g_mutex_unlock (&device->priv->mutex); + +        /* Exit the thread if the processing function closed the device */ +        if (device->priv->handle == NULL) +            break; +    } + +    g_debug ("Terminating poll thread for device %s", +             mate_mixer_device_get_name (MATE_MIXER_DEVICE (device))); + +    g_object_unref (device); +} + +static gboolean +handle_process_events (AlsaDevice *device) +{ +    g_mutex_lock (&device->priv->mutex); + +    if (device->priv->handle != NULL) { +        gint ret = snd_mixer_handle_events (device->priv->handle); +        if (ret < 0) +            close_device (device); +    } + +    device->priv->events_pending = FALSE; + +    g_cond_signal (&device->priv->cond); +    g_mutex_unlock (&device->priv->mutex); + +    return G_SOURCE_REMOVE; +} + +/* ALSA has a per-mixer callback and per-element callback, per-mixer callback + * is only used for added elements and per-element callback for all the + * other messages (no, the documentation doesn't say anything about that). */ +static int +handle_callback (snd_mixer_t *handle, guint mask, snd_mixer_elem_t *el) +{ +    if (mask & SND_CTL_EVENT_MASK_ADD) { +        AlsaDevice *device = snd_mixer_get_callback_private (handle); + +        load_element (device, el); +    } +    return 0; +} + +static int +handle_element_callback (snd_mixer_elem_t *el, guint mask) +{ +    AlsaDevice *device; +    gchar      *name; + +    device = snd_mixer_elem_get_callback_private (el); +    name = get_element_name (el); + +    if (mask == SND_CTL_EVENT_MASK_REMOVE) { +        /* Make sure this function is not called again with the element */ +        snd_mixer_elem_set_callback_private (el, NULL); +        snd_mixer_elem_set_callback (el, NULL); + +        remove_elements_by_name (device, name); +    } else { +        if (mask & SND_CTL_EVENT_MASK_INFO) { +            remove_elements_by_name (device, name); +            load_element (device, el); +        } +        if (mask & SND_CTL_EVENT_MASK_VALUE) +            load_elements_by_name (device, name); +    } +    g_free (name); + +    return 0; +} + +static void +close_device (AlsaDevice *device) +{ +    if (device->priv->handle != NULL) { +        snd_mixer_close (device->priv->handle); +        device->priv->handle = NULL; +    } + +    /* This signal tells the owner that the device has been closed voluntarily +     * from within the instance */ +    g_signal_emit (G_OBJECT (device), signals[CLOSED], 0); +} + +static gchar * +get_element_name (snd_mixer_elem_t *el) +{ +    return g_strdup_printf ("%s-%d", +                            snd_mixer_selem_get_name (el), +                            snd_mixer_selem_get_index (el)); +} + +static void +get_control_info (snd_mixer_elem_t           *el, +                  gchar                     **name, +                  gchar                     **label, +                  MateMixerStreamControlRole *role) +{ +    MateMixerStreamControlRole r = MATE_MIXER_STREAM_CONTROL_ROLE_UNKNOWN; +    const gchar               *n; +    const gchar               *l = NULL; +    gint                       i; + +    n = snd_mixer_selem_get_name (el); + +    for (i = 0; alsa_controls[i].name != NULL; i++) +        if (strcmp (n, alsa_controls[i].name) == 0) { +            l = alsa_controls[i].label; +            r = alsa_controls[i].role; +            break; +        } + +    *name = get_element_name (el); +    if (l != NULL) +        *label = g_strdup (l); +    else +        *label = g_strdup (n); + +    *role = r; +} + +static void +get_switch_info (snd_mixer_elem_t           *el, +                 gchar                     **name, +                 gchar                     **label) +{ +    // MateMixerStreamControlRole r = MATE_MIXER_STREAM_CONTROL_ROLE_UNKNOWN; +    const gchar               *n; +    const gchar               *l = NULL; +    // gint                       i; + +    n = snd_mixer_selem_get_name (el); + +    // TODO provide translated label and flags + +/* +    for (i = 0; alsa_controls[i].name != NULL; i++) +        if (strcmp (n, alsa_controls[i].name) == 0) { +            l = alsa_controls[i].label; +            r = alsa_controls[i].role; +            break; +        } +*/ +    *name = get_element_name (el); +    if (l != NULL) +        *label = g_strdup (l); +    else +        *label = g_strdup (n); + +    // *role = r; +} diff --git a/backends/alsa/alsa-device.h b/backends/alsa/alsa-device.h new file mode 100644 index 0000000..3b3c970 --- /dev/null +++ b/backends/alsa/alsa-device.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2014 Michal Ratajsky <[email protected]> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the licence, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef ALSA_DEVICE_H +#define ALSA_DEVICE_H + +#include <glib.h> +#include <glib-object.h> + +#include "alsa-stream.h" + +G_BEGIN_DECLS + +#define ALSA_TYPE_DEVICE                        \ +        (alsa_device_get_type ()) +#define ALSA_DEVICE(o)                          \ +        (G_TYPE_CHECK_INSTANCE_CAST ((o), ALSA_TYPE_DEVICE, AlsaDevice)) +#define ALSA_IS_DEVICE(o)                       \ +        (G_TYPE_CHECK_INSTANCE_TYPE ((o), ALSA_TYPE_DEVICE)) +#define ALSA_DEVICE_CLASS(k)                    \ +        (G_TYPE_CHECK_CLASS_CAST ((k), ALSA_TYPE_DEVICE, AlsaDeviceClass)) +#define ALSA_IS_DEVICE_CLASS(k)                 \ +        (G_TYPE_CHECK_CLASS_TYPE ((k), ALSA_TYPE_DEVICE)) +#define ALSA_DEVICE_GET_CLASS(o)                \ +        (G_TYPE_INSTANCE_GET_CLASS ((o), ALSA_TYPE_DEVICE, AlsaDeviceClass)) + +typedef struct _AlsaDevice         AlsaDevice; +typedef struct _AlsaDeviceClass    AlsaDeviceClass; +typedef struct _AlsaDevicePrivate  AlsaDevicePrivate; + +struct _AlsaDevice +{ +    MateMixerDevice parent; + +    /*< private >*/ +    AlsaDevicePrivate *priv; +}; + +struct _AlsaDeviceClass +{ +    MateMixerDeviceClass parent_class; + +    /*< private >*/ +    void (*closed) (AlsaDevice *device); +}; + +GType       alsa_device_get_type          (void) G_GNUC_CONST; + +AlsaDevice *alsa_device_new               (const gchar *name, +                                           const gchar *label); + +gboolean    alsa_device_open              (AlsaDevice  *device); +void        alsa_device_load              (AlsaDevice  *device); + +AlsaStream *alsa_device_get_input_stream  (AlsaDevice  *device); +AlsaStream *alsa_device_get_output_stream (AlsaDevice  *device); + +G_END_DECLS + +#endif /* ALSA_DEVICE_H */ diff --git a/backends/alsa/alsa-element.c b/backends/alsa/alsa-element.c new file mode 100644 index 0000000..f925064 --- /dev/null +++ b/backends/alsa/alsa-element.c @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2014 Michal Ratajsky <[email protected]> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the licence, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#include <glib.h> +#include <glib-object.h> +#include <alsa/asoundlib.h> + +#include "alsa-element.h" + +G_DEFINE_INTERFACE (AlsaElement, alsa_element, G_TYPE_OBJECT) + +static void +alsa_element_default_init (AlsaElementInterface *iface) +{ +} + +snd_mixer_elem_t * +alsa_element_get_snd_element (AlsaElement *element) +{ +    g_return_val_if_fail (ALSA_IS_ELEMENT (element), NULL); + +    return ALSA_ELEMENT_GET_INTERFACE (element)->get_snd_element (element); +} + +void +alsa_element_set_snd_element (AlsaElement *element, snd_mixer_elem_t *el) +{ +    g_return_if_fail (ALSA_IS_ELEMENT (element)); + +    ALSA_ELEMENT_GET_INTERFACE (element)->set_snd_element (element, el); +} + +gboolean +alsa_element_load (AlsaElement *element) +{ +    g_return_val_if_fail (ALSA_IS_ELEMENT (element), FALSE); + +    return ALSA_ELEMENT_GET_INTERFACE (element)->load (element); +} diff --git a/backends/alsa/alsa-element.h b/backends/alsa/alsa-element.h new file mode 100644 index 0000000..01d30f1 --- /dev/null +++ b/backends/alsa/alsa-element.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2014 Michal Ratajsky <[email protected]> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the licence, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef ALSA_ELEMENT_H +#define ALSA_ELEMENT_H + +#include <glib.h> +#include <glib-object.h> +#include <alsa/asoundlib.h> + +G_BEGIN_DECLS + +#define ALSA_TYPE_ELEMENT                       \ +        (alsa_element_get_type ()) +#define ALSA_ELEMENT(o)                         \ +        (G_TYPE_CHECK_INSTANCE_CAST ((o), ALSA_TYPE_ELEMENT, AlsaElement)) +#define ALSA_IS_ELEMENT(o)                      \ +        (G_TYPE_CHECK_INSTANCE_TYPE ((o), ALSA_TYPE_ELEMENT)) +#define ALSA_ELEMENT_GET_INTERFACE(o)           \ +        (G_TYPE_INSTANCE_GET_INTERFACE ((o), ALSA_TYPE_ELEMENT, AlsaElementInterface)) + +typedef struct _AlsaElement           AlsaElement; /* dummy object */ +typedef struct _AlsaElementInterface  AlsaElementInterface; + +struct _AlsaElementInterface +{ +    GTypeInterface parent_iface; + +    /*< private >*/ +    snd_mixer_elem_t *(*get_snd_element) (AlsaElement      *element); +    void              (*set_snd_element) (AlsaElement      *element, +                                          snd_mixer_elem_t *el); + +    gboolean          (*load)            (AlsaElement      *element); +}; + +GType             alsa_element_get_type        (void) G_GNUC_CONST; + +snd_mixer_elem_t *alsa_element_get_snd_element (AlsaElement      *element); +void              alsa_element_set_snd_element (AlsaElement      *element, +                                                snd_mixer_elem_t *el); + +gboolean          alsa_element_load            (AlsaElement      *element); + +G_END_DECLS + +#endif /* ALSA_ELEMENT_H */ diff --git a/backends/alsa/alsa-stream-control.c b/backends/alsa/alsa-stream-control.c new file mode 100644 index 0000000..bc7a937 --- /dev/null +++ b/backends/alsa/alsa-stream-control.c @@ -0,0 +1,739 @@ +/* + * Copyright (C) 2014 Michal Ratajsky <[email protected]> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the licence, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#include <glib.h> +#include <glib-object.h> +#include <alsa/asoundlib.h> +#include <libmatemixer/matemixer.h> +#include <libmatemixer/matemixer-private.h> + +#include "alsa-constants.h" +#include "alsa-element.h" +#include "alsa-stream-control.h" + +struct _AlsaStreamControlPrivate +{ +    AlsaControlData   data; +    guint32           channel_mask; +    snd_mixer_elem_t *element; +}; + +static void alsa_element_interface_init    (AlsaElementInterface   *iface); + +static void alsa_stream_control_class_init (AlsaStreamControlClass *klass); +static void alsa_stream_control_init       (AlsaStreamControl      *control); + +G_DEFINE_ABSTRACT_TYPE_WITH_CODE (AlsaStreamControl, alsa_stream_control, +                                  MATE_MIXER_TYPE_STREAM_CONTROL, +                                  G_IMPLEMENT_INTERFACE (ALSA_TYPE_ELEMENT, +                                                         alsa_element_interface_init)) + +static snd_mixer_elem_t *       alsa_stream_control_get_snd_element      (AlsaElement             *element); +static void                     alsa_stream_control_set_snd_element      (AlsaElement             *element, +                                                                          snd_mixer_elem_t        *el); + +static gboolean                 alsa_stream_control_load                 (AlsaElement             *element); + +static gboolean                 alsa_stream_control_set_mute             (MateMixerStreamControl  *mmsc, +                                                                          gboolean                 mute); + +static guint                    alsa_stream_control_get_num_channels     (MateMixerStreamControl  *mmsc); + +static guint                    alsa_stream_control_get_volume           (MateMixerStreamControl  *mmsc); + +static gboolean                 alsa_stream_control_set_volume           (MateMixerStreamControl  *mmsc, +                                                                          guint                    volume); + +static gdouble                  alsa_stream_control_get_decibel          (MateMixerStreamControl  *mmsc); + +static gboolean                 alsa_stream_control_set_decibel          (MateMixerStreamControl  *mmsc, +                                                                          gdouble                  decibel); + +static gboolean                 alsa_stream_control_has_channel_position (MateMixerStreamControl  *mmsc, +                                                                          MateMixerChannelPosition position); +static MateMixerChannelPosition alsa_stream_control_get_channel_position (MateMixerStreamControl  *mmsc, +                                                                          guint                    channel); + +static guint                    alsa_stream_control_get_channel_volume   (MateMixerStreamControl  *mmsc, +                                                                          guint                    channel); +static gboolean                 alsa_stream_control_set_channel_volume   (MateMixerStreamControl  *mmsc, +                                                                          guint                    channel, +                                                                          guint                    volume); + +static gdouble                  alsa_stream_control_get_channel_decibel  (MateMixerStreamControl  *mmsc, +                                                                          guint                    channel); +static gboolean                 alsa_stream_control_set_channel_decibel  (MateMixerStreamControl  *mmsc, +                                                                          guint                    channel, +                                                                          gdouble                  decibel); + +static gboolean                 alsa_stream_control_set_balance          (MateMixerStreamControl  *mmsc, +                                                                          gfloat                   balance); + +static gboolean                 alsa_stream_control_set_fade             (MateMixerStreamControl  *mmsc, +                                                                          gfloat                   fade); + +static guint                    alsa_stream_control_get_min_volume       (MateMixerStreamControl  *mmsc); +static guint                    alsa_stream_control_get_max_volume       (MateMixerStreamControl  *mmsc); +static guint                    alsa_stream_control_get_normal_volume    (MateMixerStreamControl  *mmsc); +static guint                    alsa_stream_control_get_base_volume      (MateMixerStreamControl  *mmsc); + +static void                     control_data_get_average_left_right      (AlsaControlData         *data, +                                                                          guint                   *left, +                                                                          guint                   *right); +static void                     control_data_get_average_front_back      (AlsaControlData         *data, +                                                                          guint                   *front, +                                                                          guint                   *back); + +static gfloat                   control_data_get_balance                 (AlsaControlData         *data); +static gfloat                   control_data_get_fade                    (AlsaControlData         *data); + +static void +alsa_element_interface_init (AlsaElementInterface *iface) +{ +    iface->get_snd_element = alsa_stream_control_get_snd_element; +    iface->set_snd_element = alsa_stream_control_set_snd_element; +    iface->load            = alsa_stream_control_load; +} + +static void +alsa_stream_control_class_init (AlsaStreamControlClass *klass) +{ +    MateMixerStreamControlClass *control_class; + +    control_class = MATE_MIXER_STREAM_CONTROL_CLASS (klass); + +    control_class->set_mute             = alsa_stream_control_set_mute; +    control_class->get_num_channels     = alsa_stream_control_get_num_channels; +    control_class->get_volume           = alsa_stream_control_get_volume; +    control_class->set_volume           = alsa_stream_control_set_volume; +    control_class->get_decibel          = alsa_stream_control_get_decibel; +    control_class->set_decibel          = alsa_stream_control_set_decibel; +    control_class->has_channel_position = alsa_stream_control_has_channel_position; +    control_class->get_channel_position = alsa_stream_control_get_channel_position; +    control_class->get_channel_volume   = alsa_stream_control_get_channel_volume; +    control_class->set_channel_volume   = alsa_stream_control_set_channel_volume; +    control_class->get_channel_decibel  = alsa_stream_control_get_channel_decibel; +    control_class->set_channel_decibel  = alsa_stream_control_set_channel_decibel; +    control_class->set_balance          = alsa_stream_control_set_balance; +    control_class->set_fade             = alsa_stream_control_set_fade; +    control_class->get_min_volume       = alsa_stream_control_get_min_volume; +    control_class->get_max_volume       = alsa_stream_control_get_max_volume; +    control_class->get_normal_volume    = alsa_stream_control_get_normal_volume; +    control_class->get_base_volume      = alsa_stream_control_get_base_volume; + +    g_type_class_add_private (G_OBJECT_CLASS (klass), sizeof (AlsaStreamControlPrivate)); +} + +static void +alsa_stream_control_init (AlsaStreamControl *control) +{ +    control->priv = G_TYPE_INSTANCE_GET_PRIVATE (control, +                                                 ALSA_TYPE_STREAM_CONTROL, +                                                 AlsaStreamControlPrivate); +} + +AlsaControlData * +alsa_stream_control_get_data (AlsaStreamControl *control) +{ +    g_return_val_if_fail (ALSA_IS_STREAM_CONTROL (control), NULL); + +    return &control->priv->data; +} + +void +alsa_stream_control_set_data (AlsaStreamControl *control, AlsaControlData *data) +{ +    MateMixerStreamControlFlags flags = MATE_MIXER_STREAM_CONTROL_NO_FLAGS; +    MateMixerStreamControl     *mmsc; + +    g_return_if_fail (ALSA_IS_STREAM_CONTROL (control)); +    g_return_if_fail (data != NULL); + +    mmsc = MATE_MIXER_STREAM_CONTROL (control); + +    g_object_freeze_notify (G_OBJECT (control)); + +    if (data->channels > 0) { +        if (data->switch_usable == TRUE) { +            flags |= MATE_MIXER_STREAM_CONTROL_HAS_MUTE; +            if (data->active == TRUE) +                flags |= MATE_MIXER_STREAM_CONTROL_CAN_SET_MUTE; +        } +        flags |= MATE_MIXER_STREAM_CONTROL_HAS_VOLUME; +        if (data->active == TRUE) +            flags |= MATE_MIXER_STREAM_CONTROL_CAN_SET_VOLUME; +    } +    if (data->max_decibel > -MATE_MIXER_INFINITY) +        flags |= MATE_MIXER_STREAM_CONTROL_HAS_DECIBEL; + +    control->priv->data = *data; +    control->priv->channel_mask = _mate_mixer_create_channel_mask (data->c, data->channels); + +    if (data->volume_joined == FALSE) { +        if (MATE_MIXER_CHANNEL_MASK_HAS_LEFT (control->priv->channel_mask) && +            MATE_MIXER_CHANNEL_MASK_HAS_RIGHT (control->priv->channel_mask)) +            flags |= MATE_MIXER_STREAM_CONTROL_CAN_BALANCE; + +        if (MATE_MIXER_CHANNEL_MASK_HAS_FRONT (control->priv->channel_mask) && +            MATE_MIXER_CHANNEL_MASK_HAS_BACK (control->priv->channel_mask)) +            flags |= MATE_MIXER_STREAM_CONTROL_CAN_FADE; +    } + +    _mate_mixer_stream_control_set_flags (mmsc, flags); + +    if (data->switch_usable == TRUE) { +        gboolean mute; + +        /* If the mute switch is joined, all the channels get the same value, +         * otherwise the element has per-channel mute, which we don't support. +         * In that case, treat the control as unmuted if any channel is +         * unmuted. */ +        if (data->channels == 1 || data->switch_joined == TRUE) { +            mute = data->m[0]; +        } else { +            gint i; +            mute = TRUE; +            for (i = 0; i < data->channels; i++) +                if (data->m[i] == FALSE) { +                    mute = FALSE; +                    break; +                } +        } +        _mate_mixer_stream_control_set_mute (mmsc, mute); +    } else +        _mate_mixer_stream_control_set_mute (mmsc, FALSE); + +    if (flags & MATE_MIXER_STREAM_CONTROL_CAN_BALANCE) +        _mate_mixer_stream_control_set_balance (mmsc, control_data_get_balance (data)); +    if (flags & MATE_MIXER_STREAM_CONTROL_CAN_FADE) +        _mate_mixer_stream_control_set_fade (mmsc, control_data_get_fade (data)); + +    g_object_thaw_notify (G_OBJECT (control)); +} + +static snd_mixer_elem_t * +alsa_stream_control_get_snd_element (AlsaElement *element) +{ +    g_return_val_if_fail (ALSA_IS_STREAM_CONTROL (element), NULL); + +    return ALSA_STREAM_CONTROL (element)->priv->element; +} + +static void +alsa_stream_control_set_snd_element (AlsaElement *element, snd_mixer_elem_t *el) +{ +    g_return_if_fail (ALSA_IS_STREAM_CONTROL (element)); +    g_return_if_fail (el != NULL); + +    ALSA_STREAM_CONTROL (element)->priv->element = el; +} + +static gboolean +alsa_stream_control_load (AlsaElement *element) +{ +    AlsaStreamControl *control; + +    g_return_val_if_fail (ALSA_IS_STREAM_CONTROL (element), FALSE); + +    control = ALSA_STREAM_CONTROL (element); + +    return ALSA_STREAM_CONTROL_GET_CLASS (control)->load (control); +} + +static gboolean +alsa_stream_control_set_mute (MateMixerStreamControl *mmsc, gboolean mute) +{ +    AlsaStreamControl *control; +    gboolean           change = FALSE; +    gint               i; + +    g_return_val_if_fail (ALSA_IS_STREAM_CONTROL (mmsc), FALSE); + +    control = ALSA_STREAM_CONTROL (mmsc); + +    /* If the switch is joined, only verify the first channel */ +    if (control->priv->data.switch_joined == TRUE) { +        if (control->priv->data.m[0] != mute) +            change = TRUE; +    } else { +        /* Avoid trying to set the mute if all channels are already at the +         * selected mute value */ +        for (i = 0; i < control->priv->data.channels; i++) +            if (control->priv->data.m[i] != mute) { +                change = TRUE; +                break; +            } +    } + +    if (change == TRUE) { +        AlsaStreamControlClass *klass; + +        klass = ALSA_STREAM_CONTROL_GET_CLASS (control); +        if (klass->set_mute (control, mute) == FALSE) +            return FALSE; + +        for (i = 0; i < control->priv->data.channels; i++) +            control->priv->data.m[i] = mute; +    } +    return TRUE; +} + +static guint +alsa_stream_control_get_num_channels (MateMixerStreamControl *mmsc) +{ +    g_return_val_if_fail (ALSA_IS_STREAM_CONTROL (mmsc), 0); + +    return ALSA_STREAM_CONTROL (mmsc)->priv->data.channels; +} + +static guint +alsa_stream_control_get_volume (MateMixerStreamControl *mmsc) +{ +    g_return_val_if_fail (ALSA_IS_STREAM_CONTROL (mmsc), 0); + +    return ALSA_STREAM_CONTROL (mmsc)->priv->data.volume; +} + +static gboolean +alsa_stream_control_set_volume (MateMixerStreamControl *mmsc, guint volume) +{ +    AlsaStreamControl *control; +    gboolean           change = FALSE; +    gint               i; + +    g_return_val_if_fail (ALSA_IS_STREAM_CONTROL (mmsc), FALSE); + +    control = ALSA_STREAM_CONTROL (mmsc); +    volume  = CLAMP (volume, control->priv->data.min, control->priv->data.max); + +    /* If the volume is joined, only verify the first channel */ +    if (control->priv->data.volume_joined == TRUE) { +        if (control->priv->data.v[0] != volume) +            change = TRUE; +    } else { +        /* Avoid trying to set the volume if all channels are already at the +         * selected volume */ +        for (i = 0; i < control->priv->data.channels; i++) +            if (control->priv->data.v[i] != volume) { +                change = TRUE; +                break; +            } +    } + +    if (change == TRUE) { +        AlsaStreamControlClass *klass; + +        klass = ALSA_STREAM_CONTROL_GET_CLASS (control); +        if (klass->set_volume (control, volume) == FALSE) +            return FALSE; + +        for (i = 0; i < control->priv->data.channels; i++) +            control->priv->data.v[i] = volume; + +        g_object_notify (G_OBJECT (control), "volume"); +    } +    return TRUE; +} + +static gdouble +alsa_stream_control_get_decibel (MateMixerStreamControl *mmsc) +{ +    AlsaStreamControl      *control; +    AlsaStreamControlClass *klass; +    guint                   volume; +    gdouble                 decibel; + +    g_return_val_if_fail (ALSA_IS_STREAM_CONTROL (mmsc), -MATE_MIXER_INFINITY); + +    control = ALSA_STREAM_CONTROL (mmsc); +    klass   = ALSA_STREAM_CONTROL_GET_CLASS (control); +    volume  = alsa_stream_control_get_volume (mmsc); + +    if (klass->get_decibel_from_volume (control, volume, &decibel) == FALSE) +        return FALSE; + +    return decibel; +} + +static gboolean +alsa_stream_control_set_decibel (MateMixerStreamControl *mmsc, gdouble decibel) +{ +    AlsaStreamControl      *control; +    AlsaStreamControlClass *klass; +    guint                   volume; + +    g_return_val_if_fail (ALSA_IS_STREAM_CONTROL (mmsc), FALSE); + +    control = ALSA_STREAM_CONTROL (mmsc); +    klass   = ALSA_STREAM_CONTROL_GET_CLASS (control); + +    if (klass->get_volume_from_decibel (control, decibel, &volume) == FALSE) +        return FALSE; + +    return alsa_stream_control_set_volume (mmsc, volume); +} + +static gboolean +alsa_stream_control_has_channel_position (MateMixerStreamControl  *mmsc, +                                          MateMixerChannelPosition position) +{ +    AlsaStreamControl *control; + +    g_return_val_if_fail (ALSA_IS_STREAM_CONTROL (mmsc), FALSE); + +    control = ALSA_STREAM_CONTROL (mmsc); + +    if MATE_MIXER_CHANNEL_MASK_HAS_CHANNEL (control->priv->channel_mask, position) +        return TRUE; +    else +        return FALSE; +} + +static MateMixerChannelPosition +alsa_stream_control_get_channel_position (MateMixerStreamControl *mmsc, guint channel) +{ +    AlsaStreamControl *control; + +    g_return_val_if_fail (ALSA_IS_STREAM_CONTROL (mmsc), MATE_MIXER_CHANNEL_UNKNOWN); + +    control = ALSA_STREAM_CONTROL (mmsc); + +    if (channel >= control->priv->data.channels) +        return MATE_MIXER_CHANNEL_UNKNOWN; + +    return control->priv->data.c[channel]; +} + +static guint +alsa_stream_control_get_channel_volume (MateMixerStreamControl *mmsc, guint channel) +{ +    AlsaStreamControl *control; + +    g_return_val_if_fail (ALSA_IS_STREAM_CONTROL (mmsc), 0); + +    control = ALSA_STREAM_CONTROL (mmsc); + +    if (channel >= control->priv->data.channels) +        return FALSE; + +    return control->priv->data.v[channel]; +} + +static gboolean +alsa_stream_control_set_channel_volume (MateMixerStreamControl *mmsc, guint channel, guint volume) +{ +    AlsaStreamControl *control; + +    g_return_val_if_fail (ALSA_IS_STREAM_CONTROL (mmsc), FALSE); + +    control = ALSA_STREAM_CONTROL (mmsc); + +    if (channel >= control->priv->data.channels) +        return FALSE; + +    /* Set volume for all channels at once when channels are joined */ +    if (control->priv->data.volume_joined == TRUE) +        return alsa_stream_control_set_volume (mmsc, volume); + +    if (volume != control->priv->data.v[channel]) { +        AlsaStreamControlClass *klass; + +        /* Convert channel index to ALSA channel position and make sure it is valid */ +        snd_mixer_selem_channel_id_t c = alsa_channel_map_to[control->priv->data.c[channel]]; +        if G_UNLIKELY (c == SND_MIXER_SCHN_UNKNOWN) { +            g_warn_if_reached (); +            return FALSE; +        } + +        klass = ALSA_STREAM_CONTROL_GET_CLASS (control); +        if (klass->set_channel_volume (control, c, volume) == FALSE) +            return FALSE; + +        control->priv->data.v[channel] = volume; + +        g_object_notify (G_OBJECT (control), "volume"); +    } +    return TRUE; +} + +static gdouble +alsa_stream_control_get_channel_decibel (MateMixerStreamControl *mmsc, guint channel) +{ +    AlsaStreamControl      *control; +    AlsaStreamControlClass *klass; +    guint                   volume; +    gdouble                 decibel; + +    g_return_val_if_fail (ALSA_IS_STREAM_CONTROL (mmsc), -MATE_MIXER_INFINITY); + +    control = ALSA_STREAM_CONTROL (mmsc); + +    if (channel >= control->priv->data.channels) +        return FALSE; + +    klass  = ALSA_STREAM_CONTROL_GET_CLASS (control); +    volume = control->priv->data.v[channel]; + +    if (klass->get_decibel_from_volume (control, volume, &decibel) == FALSE) +        return FALSE; + +    return decibel; +} + +static gboolean +alsa_stream_control_set_channel_decibel (MateMixerStreamControl *mmsc, +                                         guint                   channel, +                                         gdouble                 decibel) +{ +    AlsaStreamControl      *control; +    AlsaStreamControlClass *klass; +    guint                   volume; + +    g_return_val_if_fail (ALSA_IS_STREAM_CONTROL (mmsc), FALSE); + +    control = ALSA_STREAM_CONTROL (mmsc); +    klass   = ALSA_STREAM_CONTROL_GET_CLASS (control); + +    if (klass->get_volume_from_decibel (control, decibel, &volume) == FALSE) +        return FALSE; + +    return alsa_stream_control_set_channel_volume (mmsc, channel, volume); +} + +static gboolean +alsa_stream_control_set_balance (MateMixerStreamControl *mmsc, gfloat balance) +{ +    AlsaStreamControlClass *klass; +    AlsaStreamControl      *control; +    AlsaControlData        *data; +    guint                   left, +                            right; +    guint                   nleft, +                            nright; +    guint                   max; +    guint                   channel; + +    g_return_val_if_fail (ALSA_IS_STREAM_CONTROL (mmsc), FALSE); + +    control = ALSA_STREAM_CONTROL (mmsc); +    klass   = ALSA_STREAM_CONTROL_GET_CLASS (control); + +    data = &control->priv->data; +    control_data_get_average_left_right (data, &left, &right); + +    max = MAX (left, right); +    if (balance <= 0) { +        nright = (balance + 1.0f) * max; +        nleft  = max; +    } else { +        nleft  = (1.0f - balance) * max; +        nright = max; +    } + +    for (channel = 0; channel < data->channels; channel++) { +        gboolean lc = MATE_MIXER_IS_LEFT_CHANNEL (data->c[channel]); +        gboolean rc = MATE_MIXER_IS_RIGHT_CHANNEL (data->c[channel]); + +        if (lc == TRUE || rc == TRUE) { +            guint volume; +            if (lc == TRUE) { +                if (left == 0) +                    volume = nleft; +                else +                    volume = CLAMP (((guint64) data->v[channel] * (guint64) nleft) / (guint64) left, +                                    data->min, +                                    data->max); +            } else { +                if (right == 0) +                    volume = nright; +                else +                    volume = CLAMP (((guint64) data->v[channel] * (guint64) nright) / (guint64) right, +                                    data->min, +                                    data->max); +            } + +            if (klass->set_channel_volume (control, +                                           alsa_channel_map_to[data->c[channel]], +                                           volume) == TRUE) +                data->v[channel] = volume; +        } +    } +    return TRUE; +} + +static gboolean +alsa_stream_control_set_fade (MateMixerStreamControl *mmsc, gfloat fade) +{ +    AlsaStreamControlClass *klass; +    AlsaStreamControl      *control; +    AlsaControlData        *data; +    guint                   front, +                            back; +    guint                   nfront, +                            nback; +    guint                   max; +    guint                   channel; + +    g_return_val_if_fail (ALSA_IS_STREAM_CONTROL (mmsc), FALSE); + +    control = ALSA_STREAM_CONTROL (mmsc); +    klass   = ALSA_STREAM_CONTROL_GET_CLASS (control); + +    data = &control->priv->data; +    control_data_get_average_front_back (data, &front, &back); + +    max = MAX (front, back); +    if (fade <= 0) { +        nback  = (fade + 1.0f) * max; +        nfront = max; +    } else { +        nfront = (1.0f - fade) * max; +        nback  = max; +    } + +    for (channel = 0; channel < data->channels; channel++) { +        gboolean fc = MATE_MIXER_IS_FRONT_CHANNEL (data->c[channel]); +        gboolean bc = MATE_MIXER_IS_BACK_CHANNEL (data->c[channel]); + +        if (fc == TRUE || bc == TRUE) { +            guint volume; +            if (fc == TRUE) { +                if (front == 0) +                    volume = nfront; +                else +                    volume = CLAMP (((guint64) data->v[channel] * (guint64) nfront) / (guint64) front, +                                    data->min, +                                    data->max); +            } else { +                if (back == 0) +                    volume = nback; +                else +                    volume = CLAMP (((guint64) data->v[channel] * (guint64) nback) / (guint64) back, +                                    data->min, +                                    data->max); +            } + +            if (klass->set_channel_volume (control, +                                           alsa_channel_map_to[data->c[channel]], +                                           volume) == TRUE) +                data->v[channel] = volume; +        } +    } +    return TRUE; +} + +static guint +alsa_stream_control_get_min_volume (MateMixerStreamControl *msc) +{ +    return ALSA_STREAM_CONTROL (msc)->priv->data.min; +} + +static guint +alsa_stream_control_get_max_volume (MateMixerStreamControl *msc) +{ +    return ALSA_STREAM_CONTROL (msc)->priv->data.max; +} + +static guint +alsa_stream_control_get_normal_volume (MateMixerStreamControl *msc) +{ +    return ALSA_STREAM_CONTROL (msc)->priv->data.max; +} + +static guint +alsa_stream_control_get_base_volume (MateMixerStreamControl *msc) +{ +    return ALSA_STREAM_CONTROL (msc)->priv->data.max; +} + +static void +control_data_get_average_left_right (AlsaControlData *data, guint *left, guint *right) +{ +    guint l = 0, +          r = 0; +    guint nl = 0, +          nr = 0; +    guint channel; + +    for (channel = 0; channel < data->channels; channel++) +        if MATE_MIXER_IS_LEFT_CHANNEL (data->c[channel]) { +            l += data->v[channel]; +            nl++; +        } +        else if MATE_MIXER_IS_RIGHT_CHANNEL (data->c[channel]) { +            r += data->v[channel]; +            nr++; +        } + +    *left  = (nl > 0) ? l / nl : data->max; +    *right = (nr > 0) ? r / nr : data->max; +} + +static void +control_data_get_average_front_back (AlsaControlData *data, guint *front, guint *back) +{ +    guint f = 0, +          b = 0; +    guint nf = 0, +          nb = 0; +    guint channel; + +    for (channel = 0; channel < data->channels; channel++) +        if MATE_MIXER_IS_FRONT_CHANNEL (data->c[channel]) { +            f += data->v[channel]; +            nf++; +        } +        else if MATE_MIXER_IS_RIGHT_CHANNEL (data->c[channel]) { +            b += data->v[channel]; +            nb++; +        } + +    *front = (nf > 0) ? f / nf : data->max; +    *back  = (nb > 0) ? b / nb : data->max; +} + +static gfloat +control_data_get_balance (AlsaControlData *data) +{ +    guint left; +    guint right; + +    control_data_get_average_left_right (data, &left, &right); +    if (left == right) +        return 0.0f; + +    if (left > right) +        return -1.0f + ((gfloat) right / (gfloat) left); +    else +        return +1.0f - ((gfloat) left / (gfloat) right); +} + +static gfloat +control_data_get_fade (AlsaControlData *data) +{ +    guint front; +    guint back; + +    control_data_get_average_front_back (data, &front, &back); +    if (front == back) +        return 0.0f; + +    if (front > back) +        return -1.0f + ((gfloat) back / (gfloat) front); +    else +        return +1.0f - ((gfloat) front / (gfloat) back); +} diff --git a/backends/alsa/alsa-stream-control.h b/backends/alsa/alsa-stream-control.h new file mode 100644 index 0000000..f9ac6b6 --- /dev/null +++ b/backends/alsa/alsa-stream-control.h @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2014 Michal Ratajsky <[email protected]> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the licence, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef ALSA_STREAM_CONTROL_H +#define ALSA_STREAM_CONTROL_H + +#include <glib.h> +#include <glib-object.h> +#include <alsa/asoundlib.h> +#include <libmatemixer/matemixer.h> + +G_BEGIN_DECLS + +typedef struct { +    gboolean                 active; +    MateMixerChannelPosition c[MATE_MIXER_CHANNEL_MAX]; +    guint                    v[MATE_MIXER_CHANNEL_MAX]; +    gboolean                 m[MATE_MIXER_CHANNEL_MAX]; +    guint                    volume; +    gboolean                 volume_joined; +    gboolean                 switch_usable; +    gboolean                 switch_joined; +    guint                    min; +    guint                    max; +    gdouble                  min_decibel; +    gdouble                  max_decibel; +    guint                    channels; +} AlsaControlData; + +extern const MateMixerChannelPosition     alsa_channel_map_from[SND_MIXER_SCHN_LAST]; +extern const snd_mixer_selem_channel_id_t alsa_channel_map_to[MATE_MIXER_CHANNEL_MAX]; + +#define ALSA_TYPE_STREAM_CONTROL                \ +        (alsa_stream_control_get_type ()) +#define ALSA_STREAM_CONTROL(o)                  \ +        (G_TYPE_CHECK_INSTANCE_CAST ((o), ALSA_TYPE_STREAM_CONTROL, AlsaStreamControl)) +#define ALSA_IS_STREAM_CONTROL(o)               \ +        (G_TYPE_CHECK_INSTANCE_TYPE ((o), ALSA_TYPE_STREAM_CONTROL)) +#define ALSA_STREAM_CONTROL_CLASS(k)            \ +        (G_TYPE_CHECK_CLASS_CAST ((k), ALSA_TYPE_STREAM_CONTROL, AlsaStreamControlClass)) +#define ALSA_IS_STREAM_CONTROL_CLASS(k)         \ +        (G_TYPE_CHECK_CLASS_TYPE ((k), ALSA_TYPE_STREAM_CONTROL)) +#define ALSA_STREAM_CONTROL_GET_CLASS(o)        \ +        (G_TYPE_INSTANCE_GET_CLASS ((o), ALSA_TYPE_STREAM_CONTROL, AlsaStreamControlClass)) + +typedef struct _AlsaStreamControl         AlsaStreamControl; +typedef struct _AlsaStreamControlClass    AlsaStreamControlClass; +typedef struct _AlsaStreamControlPrivate  AlsaStreamControlPrivate; + +struct _AlsaStreamControl +{ +    MateMixerStreamControl parent; + +    /*< private >*/ +    AlsaStreamControlPrivate *priv; + +}; + +struct _AlsaStreamControlClass +{ +    MateMixerStreamControlClass parent_class; + +    /*< private >*/ +    gboolean (*load)                    (AlsaStreamControl           *control); + +    gboolean (*set_mute)                (AlsaStreamControl           *control, +                                         gboolean                     mute); + +    gboolean (*set_volume)              (AlsaStreamControl           *control, +                                         guint                        volume); + +    gboolean (*set_channel_volume)      (AlsaStreamControl           *control, +                                         snd_mixer_selem_channel_id_t channel, +                                         guint                        volume); + +    gboolean (*get_volume_from_decibel) (AlsaStreamControl           *control, +                                         gdouble                      decibel, +                                         guint                       *volume); + +    gboolean (*get_decibel_from_volume) (AlsaStreamControl           *control, +                                         guint                        volume, +                                         gdouble                     *decibel); +}; + +GType              alsa_stream_control_get_type        (void) G_GNUC_CONST; + +AlsaControlData *  alsa_stream_control_get_data        (AlsaStreamControl         *control); + +void               alsa_stream_control_set_data        (AlsaStreamControl         *control, +                                                        AlsaControlData           *data); + +gboolean           alsa_stream_control_set_role        (AlsaStreamControl         *control, +                                                        MateMixerStreamControlRole role); + +G_END_DECLS + +#endif /* ALSA_STREAM_CONTROL_H */ diff --git a/backends/alsa/alsa-stream-input-control.c b/backends/alsa/alsa-stream-input-control.c new file mode 100644 index 0000000..2ef0c42 --- /dev/null +++ b/backends/alsa/alsa-stream-input-control.c @@ -0,0 +1,329 @@ +/* + * Copyright (C) 2014 Michal Ratajsky <[email protected]> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the licence, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#include <glib.h> +#include <glib-object.h> +#include <alsa/asoundlib.h> + +#include <libmatemixer/matemixer.h> +#include <libmatemixer/matemixer-private.h> + +#include "alsa-element.h" +#include "alsa-stream-control.h" +#include "alsa-stream-input-control.h" + +static void alsa_stream_input_control_class_init (AlsaStreamInputControlClass *klass); +static void alsa_stream_input_control_init       (AlsaStreamInputControl      *control); + +G_DEFINE_TYPE (AlsaStreamInputControl, alsa_stream_input_control, ALSA_TYPE_STREAM_CONTROL) + +static gboolean alsa_stream_input_control_load                    (AlsaStreamControl           *control); + +static gboolean alsa_stream_input_control_set_mute                (AlsaStreamControl           *control, +                                                                   gboolean                     mute); + +static gboolean alsa_stream_input_control_set_volume              (AlsaStreamControl           *control, +                                                                   guint                        volume); + +static gboolean alsa_stream_input_control_set_channel_volume      (AlsaStreamControl           *control, +                                                                   snd_mixer_selem_channel_id_t channel, +                                                                   guint                        volume); + +static gboolean alsa_stream_input_control_get_volume_from_decibel (AlsaStreamControl           *control, +                                                                   gdouble                      decibel, +                                                                   guint                       *volume); + +static gboolean alsa_stream_input_control_get_decibel_from_volume (AlsaStreamControl           *control, +                                                                   guint                        volume, +                                                                   gdouble                     *decibel); + +static void     read_volume_data (snd_mixer_elem_t *el, +                                  AlsaControlData  *data); + +static void +alsa_stream_input_control_class_init (AlsaStreamInputControlClass *klass) +{ +    AlsaStreamControlClass *control_class; + +    control_class = ALSA_STREAM_CONTROL_CLASS (klass); + +    control_class->load                    = alsa_stream_input_control_load; +    control_class->set_mute                = alsa_stream_input_control_set_mute; +    control_class->set_volume              = alsa_stream_input_control_set_volume; +    control_class->set_channel_volume      = alsa_stream_input_control_set_channel_volume; +    control_class->get_volume_from_decibel = alsa_stream_input_control_get_volume_from_decibel; +    control_class->get_decibel_from_volume = alsa_stream_input_control_get_decibel_from_volume; +} + +static void +alsa_stream_input_control_init (AlsaStreamInputControl *control) +{ +} + +AlsaStreamControl * +alsa_stream_input_control_new (const gchar               *name, +                               const gchar               *label, +                               MateMixerStreamControlRole role) +{ +    return g_object_new (ALSA_TYPE_STREAM_INPUT_CONTROL, +                         "name", name, +                         "label", label, +                         "role", role, +                         NULL); +} + +static gboolean +alsa_stream_input_control_load (AlsaStreamControl *control) +{ +    AlsaControlData   data; +    snd_mixer_elem_t *el; + +    g_return_val_if_fail (ALSA_IS_STREAM_INPUT_CONTROL (control), FALSE); + +    el = alsa_element_get_snd_element (ALSA_ELEMENT (control)); +    if G_UNLIKELY (el == NULL) +        return FALSE; + +    /* Expect that the element has a volume control */ +    if G_UNLIKELY (snd_mixer_selem_has_capture_volume (el) == 0 && +                   snd_mixer_selem_has_common_volume (el) == 0) { +        g_warn_if_reached (); +        return FALSE; +    } + +    memset (&data, 0, sizeof (AlsaControlData)); + +    /* We model any control switch as mute */ +    if (snd_mixer_selem_has_capture_switch (el) == 1 || +        snd_mixer_selem_has_common_switch (el) == 1) +        data.switch_usable = TRUE; + +    data.active = snd_mixer_selem_is_active (el); + +    /* Read the volume data but do not error out if it fails, since ALSA reports +     * the control to have a volume, expect the control to match what we need - slider +     * with an optional mute toggle. +     * If it fails to read the volume data, just treat it as a volumeless control */ +    read_volume_data (el, &data); + +    alsa_stream_control_set_data (control, &data); +    return TRUE; +} + +static gboolean +alsa_stream_input_control_set_mute (AlsaStreamControl *control, gboolean mute) +{ +    snd_mixer_elem_t *el; +    gint              ret; + +    g_return_val_if_fail (ALSA_IS_STREAM_CONTROL (control), FALSE); + +    el = alsa_element_get_snd_element (ALSA_ELEMENT (control)); +    if G_UNLIKELY (el == NULL) +        return FALSE; + +    /* Set the switch for all channels */ +    ret = snd_mixer_selem_set_capture_switch_all (el, !mute); +    if (ret < 0) { +        g_warning ("Failed to set capture switch: %s", snd_strerror (ret)); +        return FALSE; +    } +    return TRUE; +} + +static gboolean +alsa_stream_input_control_set_volume (AlsaStreamControl *control, guint volume) +{ +    snd_mixer_elem_t *el; +    gint              ret; + +    g_return_val_if_fail (ALSA_IS_STREAM_CONTROL (control), FALSE); + +    el = alsa_element_get_snd_element (ALSA_ELEMENT (control)); +    if G_UNLIKELY (el == NULL) +        return FALSE; + +    /* Set the volume for all channels */ +    ret = snd_mixer_selem_set_capture_volume_all (el, volume); +    if (ret < 0) { +        g_warning ("Failed to set volume: %s", snd_strerror (ret)); +        return FALSE; +    } +    return TRUE; +} + +static gboolean +alsa_stream_input_control_set_channel_volume (AlsaStreamControl           *control, +                                              snd_mixer_selem_channel_id_t channel, +                                              guint                        volume) +{ +    snd_mixer_elem_t *el; +    gint              ret; + +    g_return_val_if_fail (ALSA_IS_STREAM_CONTROL (control), FALSE); + +    el = alsa_element_get_snd_element (ALSA_ELEMENT (control)); +    if G_UNLIKELY (el == NULL) +        return FALSE; + +    /* Set the volume for a single channels, the volume may still be "joined" and +     * set all the channels by itself */ +    ret = snd_mixer_selem_set_capture_volume (el, channel, volume); +    if (ret < 0) { +        g_warning ("Failed to set channel volume: %s", snd_strerror (ret)); +        return FALSE; +    } +    return TRUE; +} + +static gboolean +alsa_stream_input_control_get_volume_from_decibel (AlsaStreamControl *control, +                                                   gdouble            decibel, +                                                   guint             *volume) +{ +    snd_mixer_elem_t *el; +    glong             value; +    gint              ret; + +    g_return_val_if_fail (ALSA_IS_STREAM_CONTROL (control), FALSE); + +    el = alsa_element_get_snd_element (ALSA_ELEMENT (control)); +    if G_UNLIKELY (el == NULL) +        return FALSE; + +    ret = snd_mixer_selem_ask_capture_dB_vol (el, (glong) (decibel * 100), 0, &value); +    if (ret < 0) { +        g_warning ("Failed to convert volume: %s", snd_strerror (ret)); +        return FALSE; +    } + +    *volume = value; +    return TRUE; +} + +static gboolean +alsa_stream_input_control_get_decibel_from_volume (AlsaStreamControl *control, +                                                   guint              volume, +                                                   gdouble           *decibel) +{ +    snd_mixer_elem_t *el; +    glong             value; +    gint              ret; + +    g_return_val_if_fail (ALSA_IS_STREAM_CONTROL (control), FALSE); + +    el = alsa_element_get_snd_element (ALSA_ELEMENT (control)); +    if G_UNLIKELY (el == NULL) +        return FALSE; + +    ret = snd_mixer_selem_ask_capture_vol_dB (el, (glong) volume, &value); +    if (ret < 0) { +        g_warning ("Failed to convert volume: %s", snd_strerror (ret)); +        return FALSE; +    } + +    *decibel = value / 100.0; +    return TRUE; +} + +static void +read_volume_data (snd_mixer_elem_t *el, AlsaControlData *data) +{ +    glong volume; +    glong min, max; +    gint  ret; +    gint  i; + +    /* Read volume ranges, this call should never fail on valid input */ +    ret = snd_mixer_selem_get_capture_volume_range (el, &min, &max); +    if G_UNLIKELY (ret < 0) { +        g_warning ("Failed to read capture volume range: %s", snd_strerror (ret)); +        return; +    } +    data->min = (guint) min; +    data->max = (guint) max; + +    /* This fails when decibels are not supported */ +    ret = snd_mixer_selem_get_capture_dB_range (el, &min, &max); +    if (ret == 0) { +        data->min_decibel = min / 100.0; +        data->max_decibel = max / 100.0; +    } else +        data->min_decibel = data->max_decibel = -MATE_MIXER_INFINITY; + +    for (i = 0; i < MATE_MIXER_CHANNEL_MAX; i++) +        data->v[i] = data->min; + +    data->volume = data->min; +    data->volume_joined = snd_mixer_selem_has_capture_volume_joined (el); + +    if (data->switch_usable == TRUE) +        data->switch_joined = snd_mixer_selem_has_capture_switch_joined (el); + +    if (snd_mixer_selem_is_capture_mono (el) == 1) { +        /* Special handling for single channel controls */ +        ret = snd_mixer_selem_get_capture_volume (el, SND_MIXER_SCHN_MONO, &volume); +        if (ret == 0) { +            data->channels = 1; + +            data->c[0] = MATE_MIXER_CHANNEL_MONO; +            data->v[0] = data->volume = (guint) volume; +        } else { +            g_warning ("Failed to read capture volume: %s", snd_strerror (ret)); +        } + +        if (data->switch_usable == TRUE) { +            gint value; + +            ret = snd_mixer_selem_get_capture_switch (el, SND_MIXER_SCHN_MONO, &value); +            if G_LIKELY (ret == 0) +                data->m[0] = !value; +        } +    } else { +        snd_mixer_selem_channel_id_t channel; + +        /* We use numeric channel indices, but ALSA only works with channel +         * positions, go over all the positions supported by ALSA and create +         * a list of channels */ +         for (channel = 0; channel < SND_MIXER_SCHN_LAST; channel++) { +            if (snd_mixer_selem_has_capture_channel (el, channel) == 0) +                continue; + +            if (data->switch_usable == TRUE) { +                gint value; + +                ret = snd_mixer_selem_get_capture_switch (el, channel, &value); +                if (ret == 0) +                    data->m[channel] = !value; +            } + +            ret = snd_mixer_selem_get_capture_volume (el, channel, &volume); +            if (ret < 0) { +                g_warning ("Failed to read capture volume: %s", snd_strerror (ret)); +                continue; +            } +            data->channels++; + +            /* The single value volume is the highest channel volume */ +            if (data->volume < volume) +                data->volume = volume; + +            data->c[channel] = alsa_channel_map_from[channel]; +            data->v[channel] = (guint) volume; +        } +    } +} diff --git a/backends/alsa/alsa-stream-input-control.h b/backends/alsa/alsa-stream-input-control.h new file mode 100644 index 0000000..c427e3c --- /dev/null +++ b/backends/alsa/alsa-stream-input-control.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2014 Michal Ratajsky <[email protected]> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the licence, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef ALSA_STREAM_INPUT_CONTROL_H +#define ALSA_STREAM_INPUT_CONTROL_H + +#include <glib.h> +#include <glib-object.h> +#include <libmatemixer/matemixer.h> + +#include "alsa-stream-control.h" + +G_BEGIN_DECLS + +#define ALSA_TYPE_STREAM_INPUT_CONTROL          \ +        (alsa_stream_input_control_get_type ()) +#define ALSA_STREAM_INPUT_CONTROL(o)            \ +        (G_TYPE_CHECK_INSTANCE_CAST ((o), ALSA_TYPE_STREAM_INPUT_CONTROL, AlsaStreamInputControl)) +#define ALSA_IS_STREAM_INPUT_CONTROL(o)         \ +        (G_TYPE_CHECK_INSTANCE_TYPE ((o), ALSA_TYPE_STREAM_INPUT_CONTROL)) +#define ALSA_STREAM_INPUT_CONTROL_CLASS(k)      \ +        (G_TYPE_CHECK_CLASS_CAST ((k), ALSA_TYPE_STREAM_INPUT_CONTROL, AlsaStreamInputControlClass)) +#define ALSA_IS_STREAM_INPUT_CONTROL_CLASS(k)   \ +        (G_TYPE_CHECK_CLASS_TYPE ((k), ALSA_TYPE_STREAM_INPUT_CONTROL)) +#define ALSA_STREAM_INPUT_CONTROL_GET_CLASS(o)  \ +        (G_TYPE_INSTANCE_GET_CLASS ((o), ALSA_TYPE_STREAM_INPUT_CONTROL, AlsaStreamInputControlClass)) + +typedef struct _AlsaStreamInputControl         AlsaStreamInputControl; +typedef struct _AlsaStreamInputControlClass    AlsaStreamInputControlClass; +typedef struct _AlsaStreamInputControlPrivate  AlsaStreamInputControlPrivate; + +struct _AlsaStreamInputControl +{ +    AlsaStreamControl parent; +}; + +struct _AlsaStreamInputControlClass +{ +    AlsaStreamControlClass parent_class; +}; + +GType              alsa_stream_input_control_get_type (void) G_GNUC_CONST; + +AlsaStreamControl *alsa_stream_input_control_new      (const gchar               *name, +                                                       const gchar               *label, +                                                       MateMixerStreamControlRole role); + +G_END_DECLS + +#endif /* ALSA_STREAM_INPUT_CONTROL_H */ diff --git a/backends/alsa/alsa-stream-output-control.c b/backends/alsa/alsa-stream-output-control.c new file mode 100644 index 0000000..5a3e6b3 --- /dev/null +++ b/backends/alsa/alsa-stream-output-control.c @@ -0,0 +1,329 @@ +/* + * Copyright (C) 2014 Michal Ratajsky <[email protected]> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the licence, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#include <glib.h> +#include <glib-object.h> +#include <alsa/asoundlib.h> + +#include <libmatemixer/matemixer.h> +#include <libmatemixer/matemixer-private.h> + +#include "alsa-element.h" +#include "alsa-stream-control.h" +#include "alsa-stream-output-control.h" + +static void alsa_stream_output_control_class_init (AlsaStreamOutputControlClass *klass); +static void alsa_stream_output_control_init       (AlsaStreamOutputControl      *control); + +G_DEFINE_TYPE (AlsaStreamOutputControl, alsa_stream_output_control, ALSA_TYPE_STREAM_CONTROL) + +static gboolean alsa_stream_output_control_load                    (AlsaStreamControl           *control); + +static gboolean alsa_stream_output_control_set_mute                (AlsaStreamControl           *control, +                                                                    gboolean                     mute); + +static gboolean alsa_stream_output_control_set_volume              (AlsaStreamControl           *control, +                                                                    guint                        volume); + +static gboolean alsa_stream_output_control_set_channel_volume      (AlsaStreamControl           *control, +                                                                    snd_mixer_selem_channel_id_t channel, +                                                                    guint                        volume); + +static gboolean alsa_stream_output_control_get_volume_from_decibel (AlsaStreamControl           *control, +                                                                    gdouble                      decibel, +                                                                    guint                       *volume); + +static gboolean alsa_stream_output_control_get_decibel_from_volume (AlsaStreamControl           *control, +                                                                    guint                        volume, +                                                                    gdouble                     *decibel); + +static void     read_volume_data (snd_mixer_elem_t *el, +                                  AlsaControlData  *data); + +static void +alsa_stream_output_control_class_init (AlsaStreamOutputControlClass *klass) +{ +    AlsaStreamControlClass *control_class; + +    control_class = ALSA_STREAM_CONTROL_CLASS (klass); + +    control_class->load                    = alsa_stream_output_control_load; +    control_class->set_mute                = alsa_stream_output_control_set_mute; +    control_class->set_volume              = alsa_stream_output_control_set_volume; +    control_class->set_channel_volume      = alsa_stream_output_control_set_channel_volume; +    control_class->get_volume_from_decibel = alsa_stream_output_control_get_volume_from_decibel; +    control_class->get_decibel_from_volume = alsa_stream_output_control_get_decibel_from_volume; +} + +static void +alsa_stream_output_control_init (AlsaStreamOutputControl *control) +{ +} + +AlsaStreamControl * +alsa_stream_output_control_new (const gchar               *name, +                                const gchar               *label, +                                MateMixerStreamControlRole role) +{ +    return g_object_new (ALSA_TYPE_STREAM_OUTPUT_CONTROL, +                         "name", name, +                         "label", label, +                         "role", role, +                         NULL); +} + +static gboolean +alsa_stream_output_control_load (AlsaStreamControl *control) +{ +    AlsaControlData   data; +    snd_mixer_elem_t *el; + +    g_return_val_if_fail (ALSA_IS_STREAM_OUTPUT_CONTROL (control), FALSE); + +    el = alsa_element_get_snd_element (ALSA_ELEMENT (control)); +    if G_UNLIKELY (el == NULL) +        return FALSE; + +    /* Expect that the element has a volume control */ +    if G_UNLIKELY (snd_mixer_selem_has_playback_volume (el) == 0 && +                   snd_mixer_selem_has_common_volume (el) == 0) { +        g_warn_if_reached (); +        return FALSE; +    } + +    memset (&data, 0, sizeof (AlsaControlData)); + +    /* We model any control switch as mute */ +    if (snd_mixer_selem_has_playback_switch (el) == 1 || +        snd_mixer_selem_has_common_switch (el) == 1) +        data.switch_usable = TRUE; + +    data.active = snd_mixer_selem_is_active (el); + +    /* Read the volume data but do not error out if it fails, since ALSA reports +     * the control to have a volume, expect the control to match what we need - slider +     * with an optional mute toggle. +     * If it fails to read the volume data, just treat it as a volumeless control */ +    read_volume_data (el, &data); + +    alsa_stream_control_set_data (control, &data); +    return TRUE; +} + +static gboolean +alsa_stream_output_control_set_mute (AlsaStreamControl *control, gboolean mute) +{ +    snd_mixer_elem_t *el; +    gint              ret; + +    g_return_val_if_fail (ALSA_IS_STREAM_CONTROL (control), FALSE); + +    el = alsa_element_get_snd_element (ALSA_ELEMENT (control)); +    if G_UNLIKELY (el == NULL) +        return FALSE; + +    /* Set the switch for all channels */ +    ret = snd_mixer_selem_set_playback_switch_all (el, !mute); +    if (ret < 0) { +        g_warning ("Failed to set playback switch: %s", snd_strerror (ret)); +        return FALSE; +    } +    return TRUE; +} + +static gboolean +alsa_stream_output_control_set_volume (AlsaStreamControl *control, guint volume) +{ +    snd_mixer_elem_t *el; +    gint              ret; + +    g_return_val_if_fail (ALSA_IS_STREAM_CONTROL (control), FALSE); + +    el = alsa_element_get_snd_element (ALSA_ELEMENT (control)); +    if G_UNLIKELY (el == NULL) +        return FALSE; + +    /* Set the volume for all channels */ +    ret = snd_mixer_selem_set_playback_volume_all (el, volume); +    if (ret < 0) { +        g_warning ("Failed to set volume: %s", snd_strerror (ret)); +        return FALSE; +    } +    return TRUE; +} + +static gboolean +alsa_stream_output_control_set_channel_volume (AlsaStreamControl           *control, +                                               snd_mixer_selem_channel_id_t channel, +                                               guint                        volume) +{ +    snd_mixer_elem_t *el; +    gint              ret; + +    g_return_val_if_fail (ALSA_IS_STREAM_CONTROL (control), FALSE); + +    el = alsa_element_get_snd_element (ALSA_ELEMENT (control)); +    if G_UNLIKELY (el == NULL) +        return FALSE; + +    /* Set the volume for a single channels, the volume may still be "joined" and +     * set all the channels by itself */ +    ret = snd_mixer_selem_set_playback_volume (el, channel, volume); +    if (ret < 0) { +        g_warning ("Failed to set channel volume: %s", snd_strerror (ret)); +        return FALSE; +    } +    return TRUE; +} + +static gboolean +alsa_stream_output_control_get_volume_from_decibel (AlsaStreamControl *control, +                                                    gdouble            decibel, +                                                    guint             *volume) +{ +    snd_mixer_elem_t *el; +    glong             value; +    gint              ret; + +    g_return_val_if_fail (ALSA_IS_STREAM_CONTROL (control), FALSE); + +    el = alsa_element_get_snd_element (ALSA_ELEMENT (control)); +    if G_UNLIKELY (el == NULL) +        return FALSE; + +    ret = snd_mixer_selem_ask_playback_dB_vol (el, (glong) (decibel * 100), 0, &value); +    if (ret < 0) { +        g_warning ("Failed to convert volume: %s", snd_strerror (ret)); +        return FALSE; +    } + +    *volume = value; +    return TRUE; +} + +static gboolean +alsa_stream_output_control_get_decibel_from_volume (AlsaStreamControl *control, +                                                    guint              volume, +                                                    gdouble           *decibel) +{ +    snd_mixer_elem_t *el; +    glong             value; +    gint              ret; + +    g_return_val_if_fail (ALSA_IS_STREAM_CONTROL (control), FALSE); + +    el = alsa_element_get_snd_element (ALSA_ELEMENT (control)); +    if G_UNLIKELY (el == NULL) +        return FALSE; + +    ret = snd_mixer_selem_ask_playback_vol_dB (el, (glong) volume, &value); +    if (ret < 0) { +        g_warning ("Failed to convert volume: %s", snd_strerror (ret)); +        return FALSE; +    } + +    *decibel = value / 100.0; +    return TRUE; +} + +static void +read_volume_data (snd_mixer_elem_t *el, AlsaControlData *data) +{ +    glong volume; +    glong min, max; +    gint  ret; +    gint  i; + +    /* Read volume ranges, this call should never fail on valid input */ +    ret = snd_mixer_selem_get_playback_volume_range (el, &min, &max); +    if G_UNLIKELY (ret < 0) { +        g_warning ("Failed to read playback volume range: %s", snd_strerror (ret)); +        return; +    } +    data->min = (guint) min; +    data->max = (guint) max; + +    /* This fails when decibels are not supported */ +    ret = snd_mixer_selem_get_playback_dB_range (el, &min, &max); +    if (ret == 0) { +        data->min_decibel = min / 100.0; +        data->max_decibel = max / 100.0; +    } else +        data->min_decibel = data->max_decibel = -MATE_MIXER_INFINITY; + +    for (i = 0; i < MATE_MIXER_CHANNEL_MAX; i++) +        data->v[i] = data->min; + +    data->volume = data->min; +    data->volume_joined = snd_mixer_selem_has_playback_volume_joined (el); + +    if (data->switch_usable == TRUE) +        data->switch_joined = snd_mixer_selem_has_playback_switch_joined (el); + +    if (snd_mixer_selem_is_playback_mono (el) == 1) { +        /* Special handling for single channel controls */ +        ret = snd_mixer_selem_get_playback_volume (el, SND_MIXER_SCHN_MONO, &volume); +        if (ret == 0) { +            data->channels = 1; + +            data->c[0] = MATE_MIXER_CHANNEL_MONO; +            data->v[0] = data->volume = (guint) volume; +        } else { +            g_warning ("Failed to read playback volume: %s", snd_strerror (ret)); +        } + +        if (data->switch_usable == TRUE) { +            gint value; + +            ret = snd_mixer_selem_get_playback_switch (el, SND_MIXER_SCHN_MONO, &value); +            if G_LIKELY (ret == 0) +                data->m[0] = !value; +        } +    } else { +        snd_mixer_selem_channel_id_t channel; + +        /* We use numeric channel indices, but ALSA only works with channel +         * positions, go over all the positions supported by ALSA and create +         * a list of channels */ +         for (channel = 0; channel < SND_MIXER_SCHN_LAST; channel++) { +            if (snd_mixer_selem_has_playback_channel (el, channel) == 0) +                continue; + +            if (data->switch_usable == TRUE) { +                gint value; + +                ret = snd_mixer_selem_get_playback_switch (el, channel, &value); +                if (ret == 0) +                    data->m[channel] = !value; +            } + +            ret = snd_mixer_selem_get_playback_volume (el, channel, &volume); +            if (ret < 0) { +                g_warning ("Failed to read playback volume: %s", snd_strerror (ret)); +                continue; +            } +            data->channels++; + +            /* The single value volume is the highest channel volume */ +            if (data->volume < volume) +                data->volume = volume; + +            data->c[channel] = alsa_channel_map_from[channel]; +            data->v[channel] = (guint) volume; +        } +    } +} diff --git a/backends/alsa/alsa-stream-output-control.h b/backends/alsa/alsa-stream-output-control.h new file mode 100644 index 0000000..845eaae --- /dev/null +++ b/backends/alsa/alsa-stream-output-control.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2014 Michal Ratajsky <[email protected]> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the licence, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef ALSA_STREAM_OUTPUT_CONTROL_H +#define ALSA_STREAM_OUTPUT_CONTROL_H + +#include <glib.h> +#include <glib-object.h> +#include <libmatemixer/matemixer.h> + +#include "alsa-stream-control.h" + +G_BEGIN_DECLS + +#define ALSA_TYPE_STREAM_OUTPUT_CONTROL         \ +        (alsa_stream_output_control_get_type ()) +#define ALSA_STREAM_OUTPUT_CONTROL(o)           \ +        (G_TYPE_CHECK_INSTANCE_CAST ((o), ALSA_TYPE_STREAM_OUTPUT_CONTROL, AlsaStreamOutputControl)) +#define ALSA_IS_STREAM_OUTPUT_CONTROL(o)        \ +        (G_TYPE_CHECK_INSTANCE_TYPE ((o), ALSA_TYPE_STREAM_OUTPUT_CONTROL)) +#define ALSA_STREAM_OUTPUT_CONTROL_CLASS(k)     \ +        (G_TYPE_CHECK_CLASS_CAST ((k), ALSA_TYPE_STREAM_OUTPUT_CONTROL, AlsaStreamOutputControlClass)) +#define ALSA_IS_STREAM_OUTPUT_CONTROL_CLASS(k)  \ +        (G_TYPE_CHECK_CLASS_TYPE ((k), ALSA_TYPE_STREAM_OUTPUT_CONTROL)) +#define ALSA_STREAM_OUTPUT_CONTROL_GET_CLASS(o) \ +        (G_TYPE_INSTANCE_GET_CLASS ((o), ALSA_TYPE_STREAM_OUTPUT_CONTROL, AlsaStreamOutputControlClass)) + +typedef struct _AlsaStreamOutputControl         AlsaStreamOutputControl; +typedef struct _AlsaStreamOutputControlClass    AlsaStreamOutputControlClass; +typedef struct _AlsaStreamOutputControlPrivate  AlsaStreamOutputControlPrivate; + +struct _AlsaStreamOutputControl +{ +    AlsaStreamControl parent; +}; + +struct _AlsaStreamOutputControlClass +{ +    AlsaStreamControlClass parent_class; +}; + +GType              alsa_stream_output_control_get_type (void) G_GNUC_CONST; + +AlsaStreamControl *alsa_stream_output_control_new      (const gchar               *name, +                                                        const gchar               *label, +                                                        MateMixerStreamControlRole role); + +G_END_DECLS + +#endif /* ALSA_STREAM_OUTPUT_CONTROL_H */ diff --git a/backends/alsa/alsa-stream.c b/backends/alsa/alsa-stream.c new file mode 100644 index 0000000..d2f68d4 --- /dev/null +++ b/backends/alsa/alsa-stream.c @@ -0,0 +1,273 @@ +/* + * Copyright (C) 2014 Michal Ratajsky <[email protected]> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the licence, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#include <glib.h> +#include <glib-object.h> +#include <libmatemixer/matemixer.h> + +#include "alsa-element.h" +#include "alsa-stream.h" +#include "alsa-stream-control.h" +#include "alsa-switch.h" + +struct _AlsaStreamPrivate +{ +    GHashTable             *switches; +    GHashTable             *controls; +    MateMixerStreamControl *control; +}; + +static void alsa_stream_class_init (AlsaStreamClass *klass); +static void alsa_stream_init       (AlsaStream      *stream); +static void alsa_stream_dispose    (GObject         *object); +static void alsa_stream_finalize   (GObject         *object); + +G_DEFINE_TYPE (AlsaStream, alsa_stream, MATE_MIXER_TYPE_STREAM) + +static MateMixerStreamControl *alsa_stream_get_control         (MateMixerStream *mms, +                                                                const gchar     *name); +static MateMixerStreamControl *alsa_stream_get_default_control (MateMixerStream *mms); + +static MateMixerSwitch *       alsa_stream_get_switch          (MateMixerStream *mms, +                                                                const gchar     *name); + +static GList *                 alsa_stream_list_controls       (MateMixerStream *mms); +static GList *                 alsa_stream_list_switches       (MateMixerStream *mms); + +static void +alsa_stream_class_init (AlsaStreamClass *klass) +{ +    GObjectClass         *object_class; +    MateMixerStreamClass *stream_class; + +    object_class = G_OBJECT_CLASS (klass); +    object_class->dispose  = alsa_stream_dispose; +    object_class->finalize = alsa_stream_finalize; + +    stream_class = MATE_MIXER_STREAM_CLASS (klass); +    stream_class->get_control         = alsa_stream_get_control; +    stream_class->get_default_control = alsa_stream_get_default_control; +    stream_class->get_switch          = alsa_stream_get_switch; +    stream_class->list_controls       = alsa_stream_list_controls; +    stream_class->list_switches       = alsa_stream_list_switches; + +    g_type_class_add_private (object_class, sizeof (AlsaStreamPrivate)); +} + +static void +alsa_stream_init (AlsaStream *stream) +{ +    stream->priv = G_TYPE_INSTANCE_GET_PRIVATE (stream, +                                                ALSA_TYPE_STREAM, +                                                AlsaStreamPrivate); + +    stream->priv->controls = g_hash_table_new_full (g_str_hash, +                                                    g_str_equal, +                                                    g_free, +                                                    g_object_unref); + +    stream->priv->switches = g_hash_table_new_full (g_str_hash, +                                                    g_str_equal, +                                                    g_free, +                                                    g_object_unref); +} + +static void +alsa_stream_dispose (GObject *object) +{ +    AlsaStream *stream; + +    stream = ALSA_STREAM (object); + +    g_hash_table_remove_all (stream->priv->controls); +    g_hash_table_remove_all (stream->priv->switches); + +    g_clear_object (&stream->priv->control); + +    G_OBJECT_CLASS (alsa_stream_parent_class)->dispose (object); +} + +static void +alsa_stream_finalize (GObject *object) +{ +    AlsaStream *stream; + +    stream = ALSA_STREAM (object); + +    g_hash_table_destroy (stream->priv->controls); +    g_hash_table_destroy (stream->priv->switches); + +    G_OBJECT_CLASS (alsa_stream_parent_class)->finalize (object); +} + +AlsaStream * +alsa_stream_new (const gchar         *name, +                 MateMixerDevice     *device, +                 MateMixerStreamFlags flags) +{ +    return g_object_new (ALSA_TYPE_STREAM, +                         "name", name, +                         "device", device, +                         "flags", flags, +                         NULL); +} + +void +alsa_stream_add_control (AlsaStream *stream, AlsaStreamControl *control) +{ +    const gchar *name; + +    g_return_if_fail (ALSA_IS_STREAM (stream)); +    g_return_if_fail (ALSA_IS_STREAM_CONTROL (control)); + +    name = mate_mixer_stream_control_get_name (MATE_MIXER_STREAM_CONTROL (control)); +    g_hash_table_insert (stream->priv->controls, +                         g_strdup (name), +                         g_object_ref (control)); +} + +void +alsa_stream_add_switch (AlsaStream *stream, AlsaSwitch *swtch) +{ +    const gchar *name; + +    g_return_if_fail (ALSA_IS_STREAM (stream)); +    g_return_if_fail (ALSA_IS_SWITCH (swtch)); + +    name = mate_mixer_switch_get_name (MATE_MIXER_SWITCH (swtch)); +    g_hash_table_insert (stream->priv->switches, +                         g_strdup (name), +                         g_object_ref (swtch)); +} + +gboolean +alsa_stream_is_empty (AlsaStream *stream) +{ +    g_return_val_if_fail (ALSA_IS_STREAM (stream), FALSE); + +    if (g_hash_table_size (stream->priv->controls) > 0 || +        g_hash_table_size (stream->priv->switches) > 0) +        return FALSE; + +    return TRUE; +} + +void +alsa_stream_set_default_control (AlsaStream *stream, AlsaStreamControl *control) +{ +    g_return_if_fail (ALSA_IS_STREAM (stream)); +    g_return_if_fail (ALSA_IS_STREAM_CONTROL (control)); + +    /* This function is only used internally so avoid validating that the control +     * belongs to this stream */ +    if (stream->priv->control != NULL) +        g_object_unref (stream->priv->control); + +    if (control != NULL) +        stream->priv->control = MATE_MIXER_STREAM_CONTROL (g_object_ref (control)); +    else +        stream->priv->control = NULL; +} + +void +alsa_stream_load_elements (AlsaStream *stream, const gchar *name) +{ +    AlsaElement *element; + +    g_return_if_fail (ALSA_IS_STREAM (stream)); +    g_return_if_fail (name != NULL); + +    element = g_hash_table_lookup (stream->priv->controls, name); +    if (element != NULL) +        alsa_element_load (element); + +    element = g_hash_table_lookup (stream->priv->switches, name); +    if (element != NULL) +        alsa_element_load (element); +} + +gboolean +alsa_stream_remove_elements (AlsaStream *stream, const gchar *name) +{ +    gboolean removed = FALSE; + +    g_return_val_if_fail (ALSA_IS_STREAM (stream), FALSE); +    g_return_val_if_fail (name != NULL, FALSE); + +    if (g_hash_table_remove (stream->priv->controls, name) == TRUE) +        removed = TRUE; +    if (g_hash_table_remove (stream->priv->switches, name) == TRUE) +        removed = TRUE; + +    return removed; +} + +static MateMixerStreamControl * +alsa_stream_get_control (MateMixerStream *mms, const gchar *name) +{ +    g_return_val_if_fail (ALSA_IS_STREAM (mms), NULL); + +    return g_hash_table_lookup (ALSA_STREAM (mms)->priv->controls, name); +} + +static MateMixerStreamControl * +alsa_stream_get_default_control (MateMixerStream *mms) +{ +    g_return_val_if_fail (ALSA_IS_STREAM (mms), NULL); + +    return ALSA_STREAM (mms)->priv->control; +} + +static MateMixerSwitch * +alsa_stream_get_switch (MateMixerStream *mms, const gchar *name) +{ +    g_return_val_if_fail (ALSA_IS_STREAM (mms), NULL); + +    return g_hash_table_lookup (ALSA_STREAM (mms)->priv->switches, name); +} + +static GList * +alsa_stream_list_controls (MateMixerStream *mms) +{ +    GList *list; + +    g_return_val_if_fail (ALSA_IS_STREAM (mms), NULL); + +    /* Convert the hash table to a linked list, this list is expected to be +     * cached in the main library */ +    list = g_hash_table_get_values (ALSA_STREAM (mms)->priv->controls); +    if (list != NULL) +        g_list_foreach (list, (GFunc) g_object_ref, NULL); + +    return list; +} + +static GList * +alsa_stream_list_switches (MateMixerStream *mms) +{ +    GList *list; + +    g_return_val_if_fail (ALSA_IS_STREAM (mms), NULL); + +    /* Convert the hash table to a linked list, this list is expected to be +     * cached in the main library */ +    list = g_hash_table_get_values (ALSA_STREAM (mms)->priv->switches); +    if (list != NULL) +        g_list_foreach (list, (GFunc) g_object_ref, NULL); + +    return list; +} diff --git a/backends/alsa/alsa-stream.h b/backends/alsa/alsa-stream.h new file mode 100644 index 0000000..f26a643 --- /dev/null +++ b/backends/alsa/alsa-stream.h @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2014 Michal Ratajsky <[email protected]> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the licence, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef ALSA_STREAM_H +#define ALSA_STREAM_H + +#include <glib.h> +#include <glib-object.h> +#include <libmatemixer/matemixer.h> + +#include "alsa-element.h" +#include "alsa-stream-control.h" +#include "alsa-switch.h" + +G_BEGIN_DECLS + +#define ALSA_TYPE_STREAM                        \ +        (alsa_stream_get_type ()) +#define ALSA_STREAM(o)                          \ +        (G_TYPE_CHECK_INSTANCE_CAST ((o), ALSA_TYPE_STREAM, AlsaStream)) +#define ALSA_IS_STREAM(o)                       \ +        (G_TYPE_CHECK_INSTANCE_TYPE ((o), ALSA_TYPE_STREAM)) +#define ALSA_STREAM_CLASS(k)                    \ +        (G_TYPE_CHECK_CLASS_CAST ((k), ALSA_TYPE_STREAM, AlsaStreamClass)) +#define ALSA_IS_STREAM_CLASS(k)                 \ +        (G_TYPE_CHECK_CLASS_TYPE ((k), ALSA_TYPE_STREAM)) +#define ALSA_STREAM_GET_CLASS(o)                \ +        (G_TYPE_INSTANCE_GET_CLASS ((o), ALSA_TYPE_STREAM, AlsaStreamClass)) + +typedef struct _AlsaStream         AlsaStream; +typedef struct _AlsaStreamClass    AlsaStreamClass; +typedef struct _AlsaStreamPrivate  AlsaStreamPrivate; + +struct _AlsaStream +{ +    MateMixerStream parent; + +    /*< private >*/ +    AlsaStreamPrivate *priv; +}; + +struct _AlsaStreamClass +{ +    MateMixerStreamClass parent_class; +}; + +GType       alsa_stream_get_type            (void) G_GNUC_CONST; + +AlsaStream *alsa_stream_new                 (const gchar         *name, +                                             MateMixerDevice     *device, +                                             MateMixerStreamFlags flags); + +void        alsa_stream_add_control         (AlsaStream          *stream, +                                             AlsaStreamControl   *control); + +void        alsa_stream_add_switch          (AlsaStream          *stream, +                                             AlsaSwitch          *swtch); + +gboolean    alsa_stream_is_empty            (AlsaStream          *stream); + +void        alsa_stream_set_default_control (AlsaStream          *stream, +                                             AlsaStreamControl   *control); + +void        alsa_stream_load_elements       (AlsaStream          *stream, +                                             const gchar         *name); + +gboolean    alsa_stream_remove_elements     (AlsaStream          *stream, +                                             const gchar         *name); + +void        alsa_stream_remove_all          (AlsaStream          *stream); + +G_END_DECLS + +#endif /* ALSA_STREAM_H */ diff --git a/backends/alsa/alsa-switch-option.c b/backends/alsa/alsa-switch-option.c new file mode 100644 index 0000000..2173113 --- /dev/null +++ b/backends/alsa/alsa-switch-option.c @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2014 Michal Ratajsky <[email protected]> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the licence, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#include <glib.h> +#include <glib-object.h> +#include <alsa/asoundlib.h> + +#include <libmatemixer/matemixer.h> +#include <libmatemixer/matemixer-private.h> + +#include "alsa-switch-option.h" + +struct _AlsaSwitchOptionPrivate +{ +    guint id; +}; + +static void alsa_switch_option_class_init (AlsaSwitchOptionClass *klass); +static void alsa_switch_option_init       (AlsaSwitchOption      *option); + +G_DEFINE_TYPE (AlsaSwitchOption, alsa_switch_option, MATE_MIXER_TYPE_SWITCH_OPTION) + +static void +alsa_switch_option_class_init (AlsaSwitchOptionClass *klass) +{ +    g_type_class_add_private (G_OBJECT_CLASS (klass), sizeof (AlsaSwitchOptionPrivate)); +} + +static void +alsa_switch_option_init (AlsaSwitchOption *option) +{ +    option->priv = G_TYPE_INSTANCE_GET_PRIVATE (option, +                                                ALSA_TYPE_SWITCH_OPTION, +                                                AlsaSwitchOptionPrivate); +} + +AlsaSwitchOption * +alsa_switch_option_new (const gchar *name, +                        const gchar *label, +                        const gchar *icon, +                        guint        id) +{ +    AlsaSwitchOption *option; + +    option = g_object_new (ALSA_TYPE_SWITCH_OPTION, +                           "name", name, +                           "label", label, +                           NULL); + +    option->priv->id = id; +    return option; +} + +guint +alsa_switch_option_get_id (AlsaSwitchOption *option) +{ +    g_return_val_if_fail (ALSA_IS_SWITCH_OPTION (option), 0); + +    return option->priv->id; +} diff --git a/backends/alsa/alsa-switch-option.h b/backends/alsa/alsa-switch-option.h new file mode 100644 index 0000000..c2dda87 --- /dev/null +++ b/backends/alsa/alsa-switch-option.h @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2014 Michal Ratajsky <[email protected]> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the licence, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef ALSA_SWITCH_OPTION_H +#define ALSA_SWITCH_OPTION_H + +#include <glib.h> +#include <glib-object.h> +#include <libmatemixer/matemixer.h> + +G_BEGIN_DECLS + +#define ALSA_TYPE_SWITCH_OPTION                        \ +        (alsa_switch_option_get_type ()) +#define ALSA_SWITCH_OPTION(o)                          \ +        (G_TYPE_CHECK_INSTANCE_CAST ((o), ALSA_TYPE_SWITCH_OPTION, AlsaSwitchOption)) +#define ALSA_IS_SWITCH_OPTION(o)                       \ +        (G_TYPE_CHECK_INSTANCE_TYPE ((o), ALSA_TYPE_SWITCH_OPTION)) +#define ALSA_SWITCH_OPTION_CLASS(k)                    \ +        (G_TYPE_CHECK_CLASS_CAST ((k), ALSA_TYPE_SWITCH_OPTION, AlsaSwitchOptionClass)) +#define ALSA_IS_SWITCH_OPTION_CLASS(k)                 \ +        (G_TYPE_CHECK_CLASS_TYPE ((k), ALSA_TYPE_SWITCH_OPTION)) +#define ALSA_SWITCH_OPTION_GET_CLASS(o)                \ +        (G_TYPE_INSTANCE_GET_CLASS ((o), ALSA_TYPE_SWITCH_OPTION, AlsaSwitchOptionClass)) + +typedef struct _AlsaSwitchOption         AlsaSwitchOption; +typedef struct _AlsaSwitchOptionClass    AlsaSwitchOptionClass; +typedef struct _AlsaSwitchOptionPrivate  AlsaSwitchOptionPrivate; + +struct _AlsaSwitchOption +{ +    MateMixerSwitchOption parent; + +    /*< private >*/ +    AlsaSwitchOptionPrivate *priv; +}; + +struct _AlsaSwitchOptionClass +{ +    MateMixerSwitchOptionClass parent_class; +}; + +GType             alsa_switch_option_get_type (void) G_GNUC_CONST; + +AlsaSwitchOption *alsa_switch_option_new      (const gchar      *name, +                                               const gchar      *label, +                                               const gchar      *icon, +                                               guint             id); + +guint             alsa_switch_option_get_id   (AlsaSwitchOption *option); + +G_END_DECLS + +#endif /* ALSA_SWITCH_OPTION_H */ diff --git a/backends/alsa/alsa-switch.c b/backends/alsa/alsa-switch.c new file mode 100644 index 0000000..15151ae --- /dev/null +++ b/backends/alsa/alsa-switch.c @@ -0,0 +1,227 @@ +/* + * Copyright (C) 2014 Michal Ratajsky <[email protected]> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the licence, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#include <glib.h> +#include <glib-object.h> +#include <alsa/asoundlib.h> + +#include <libmatemixer/matemixer.h> +#include <libmatemixer/matemixer-private.h> + +#include "alsa-element.h" +#include "alsa-switch.h" +#include "alsa-switch-option.h" + +struct _AlsaSwitchPrivate +{ +    GList            *options; +    guint32           channel_mask; +    snd_mixer_elem_t *element; +}; + +static void alsa_element_interface_init (AlsaElementInterface *iface); + +static void alsa_switch_class_init      (AlsaSwitchClass      *klass); +static void alsa_switch_init            (AlsaSwitch           *swtch); + +G_DEFINE_TYPE_WITH_CODE (AlsaSwitch, alsa_switch, +                         MATE_MIXER_TYPE_SWITCH, +                         G_IMPLEMENT_INTERFACE (ALSA_TYPE_ELEMENT, +                                                alsa_element_interface_init)) + +static gboolean               alsa_switch_set_active_option (MateMixerSwitch       *mms, +                                                             MateMixerSwitchOption *mmso); + +static GList *                alsa_switch_list_options      (MateMixerSwitch       *mms); + +static snd_mixer_elem_t *     alsa_switch_get_snd_element   (AlsaElement           *element); +static void                   alsa_switch_set_snd_element   (AlsaElement           *element, +                                                             snd_mixer_elem_t      *el); +static gboolean               alsa_switch_load              (AlsaElement           *element); + +static void +alsa_element_interface_init (AlsaElementInterface *iface) +{ +    iface->get_snd_element = alsa_switch_get_snd_element; +    iface->set_snd_element = alsa_switch_set_snd_element; +    iface->load            = alsa_switch_load; +} + +static void +alsa_switch_class_init (AlsaSwitchClass *klass) +{ +    MateMixerSwitchClass *switch_class; + +    switch_class = MATE_MIXER_SWITCH_CLASS (klass); +    switch_class->set_active_option = alsa_switch_set_active_option; +    switch_class->list_options      = alsa_switch_list_options; + +    g_type_class_add_private (G_OBJECT_CLASS (klass), sizeof (AlsaSwitchPrivate)); +} + +static void +alsa_switch_init (AlsaSwitch *swtch) +{ +    swtch->priv = G_TYPE_INSTANCE_GET_PRIVATE (swtch, +                                               ALSA_TYPE_SWITCH, +                                               AlsaSwitchPrivate); +} + +AlsaSwitch * +alsa_switch_new (const gchar *name, const gchar *label, GList *options) +{ +    AlsaSwitch *swtch; + +    swtch = g_object_new (ALSA_TYPE_SWITCH, +                          "name", name, +                          "label", label, +                          NULL); + +    /* Takes ownership of options */ +    swtch->priv->options = options; +    return swtch; +} + +static gboolean +alsa_switch_set_active_option (MateMixerSwitch *mms, MateMixerSwitchOption *mmso) +{ +    AlsaSwitch                  *swtch; +    guint                        index; +    gboolean                     set_item = FALSE; +    snd_mixer_selem_channel_id_t channel; + +    g_return_val_if_fail (ALSA_IS_SWITCH (mms), FALSE); +    g_return_val_if_fail (ALSA_IS_SWITCH_OPTION (mmso), FALSE); + +    swtch = ALSA_SWITCH (mms); + +    /* The channel mask is created when reading the active option the first +     * time, so a successful load must be done before changing the option */ +    if G_UNLIKELY (swtch->priv->channel_mask == 0) { +        g_debug ("Not setting active switch option, channel mask unknown"); +        return FALSE; +    } + +    index = alsa_switch_option_get_id (ALSA_SWITCH_OPTION (mmso)); + +    for (channel = 0; channel < SND_MIXER_SCHN_LAST; channel++) { +        /* The option is set per-channel, make sure to set it only for channels +         * we successfully read the value from */ +        if (swtch->priv->channel_mask & (1 << channel)) { +            gint ret = snd_mixer_selem_set_enum_item (swtch->priv->element, +                                                      channel, +                                                      index); +            if (ret == 0) +                set_item = TRUE; +            else +                g_warning ("Failed to set active option of switch %s: %s", +                           snd_mixer_selem_get_name (swtch->priv->element), +                           snd_strerror (ret)); +        } +    } +    return set_item; +} + +static GList * +alsa_switch_list_options (MateMixerSwitch *swtch) +{ +    g_return_val_if_fail (ALSA_IS_SWITCH (swtch), NULL); + +    return ALSA_SWITCH (swtch)->priv->options; +} + +static snd_mixer_elem_t * +alsa_switch_get_snd_element (AlsaElement *element) +{ +    g_return_val_if_fail (ALSA_IS_SWITCH (element), NULL); + +    return ALSA_SWITCH (element)->priv->element; +} + +static void +alsa_switch_set_snd_element (AlsaElement *element, snd_mixer_elem_t *el) +{ +    g_return_if_fail (ALSA_IS_SWITCH (element)); +    g_return_if_fail (el != NULL); + +    ALSA_SWITCH (element)->priv->element = el; +} + +static gboolean +alsa_switch_load (AlsaElement *element) +{ +    AlsaSwitch                  *swtch; +    GList                       *list; +    guint                        item; +    gint                         ret; +    snd_mixer_selem_channel_id_t c; + +    swtch = ALSA_SWITCH (element); + +    /* When reading the first time we try all the channels, otherwise only the +     * ones which returned success before */ +    if (swtch->priv->channel_mask == 0) { +        for (c = 0; c < SND_MIXER_SCHN_LAST; c++) { +            ret = snd_mixer_selem_get_enum_item (swtch->priv->element, c, &item); + +            /* The active enum option is set per-channel, so when reading it the +             * first time, create a mask of all channels for which we read the +             * value successfully */ +            if (ret == 0) +                swtch->priv->channel_mask |= 1 << c; +        } + +        /* The last ALSA call might have failed, but it doesn't matter if we have +         * a channel mask */ +        if (swtch->priv->channel_mask > 0) +            ret = 0; +    } else { +        for (c = 0; !(swtch->priv->channel_mask & (1 << c)); c++) +            ; + +        /* When not reading the mask, the first usable channel is enough, we don't +         * support per-channel selections anyway */ +        ret = snd_mixer_selem_get_enum_item (swtch->priv->element, c, &item); +    } + +    if (ret < 0) { +        g_warning ("Failed to read active option of switch %s: %s", +                   snd_mixer_selem_get_name (swtch->priv->element), +                   snd_strerror (ret)); +        return FALSE; +    } + +    list = swtch->priv->options; +    while (list != NULL) { +        AlsaSwitchOption *option = ALSA_SWITCH_OPTION (list->data); + +        /* Mark the selected option when we find it, ALSA indentifies them +         * by numeric indices */ +        if (alsa_switch_option_get_id (option) == item) { +            _mate_mixer_switch_set_active_option (MATE_MIXER_SWITCH (swtch), +                                                  MATE_MIXER_SWITCH_OPTION (option)); +            return TRUE; +        } +        list = list->next; +    } + +    g_warning ("Unknown active option of switch %s: %d", +               snd_mixer_selem_get_name (swtch->priv->element), +               item); + +    return FALSE; +} diff --git a/backends/alsa/alsa-switch.h b/backends/alsa/alsa-switch.h new file mode 100644 index 0000000..fdcfb87 --- /dev/null +++ b/backends/alsa/alsa-switch.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2014 Michal Ratajsky <[email protected]> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the licence, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef ALSA_SWITCH_H +#define ALSA_SWITCH_H + +#include <glib.h> +#include <glib-object.h> +#include <libmatemixer/matemixer.h> + +G_BEGIN_DECLS + +#define ALSA_TYPE_SWITCH                        \ +        (alsa_switch_get_type ()) +#define ALSA_SWITCH(o)                          \ +        (G_TYPE_CHECK_INSTANCE_CAST ((o), ALSA_TYPE_SWITCH, AlsaSwitch)) +#define ALSA_IS_SWITCH(o)                       \ +        (G_TYPE_CHECK_INSTANCE_TYPE ((o), ALSA_TYPE_SWITCH)) +#define ALSA_SWITCH_CLASS(k)                    \ +        (G_TYPE_CHECK_CLASS_CAST ((k), ALSA_TYPE_SWITCH, AlsaSwitchClass)) +#define ALSA_IS_SWITCH_CLASS(k)                 \ +        (G_TYPE_CHECK_CLASS_TYPE ((k), ALSA_TYPE_SWITCH)) +#define ALSA_SWITCH_GET_CLASS(o)                \ +        (G_TYPE_INSTANCE_GET_CLASS ((o), ALSA_TYPE_SWITCH, AlsaSwitchClass)) + +typedef struct _AlsaSwitch         AlsaSwitch; +typedef struct _AlsaSwitchClass    AlsaSwitchClass; +typedef struct _AlsaSwitchPrivate  AlsaSwitchPrivate; + +struct _AlsaSwitch +{ +    MateMixerSwitch parent; + +    /*< private >*/ +    AlsaSwitchPrivate *priv; +}; + +struct _AlsaSwitchClass +{ +    MateMixerSwitchClass parent_class; +}; + +GType       alsa_switch_get_type (void) G_GNUC_CONST; + +AlsaSwitch *alsa_switch_new      (const gchar *name, +                                  const gchar *label, +                                  GList       *options); + +G_END_DECLS + +#endif /* ALSA_SWITCH_H */ diff --git a/backends/alsa/alsa-toggle.c b/backends/alsa/alsa-toggle.c new file mode 100644 index 0000000..efa3460 --- /dev/null +++ b/backends/alsa/alsa-toggle.c @@ -0,0 +1,219 @@ +/* + * Copyright (C) 2014 Michal Ratajsky <[email protected]> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the licence, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#include <glib.h> +#include <glib-object.h> +#include <alsa/asoundlib.h> + +#include <libmatemixer/matemixer.h> +#include <libmatemixer/matemixer-private.h> + +#include "alsa-element.h" +#include "alsa-switch-option.h" +#include "alsa-toggle.h" + +struct _AlsaTogglePrivate +{ +    AlsaToggleType    type; +    guint32           channel_mask; +    snd_mixer_elem_t *element; +}; + +static void alsa_element_interface_init (AlsaElementInterface *iface); + +static void alsa_toggle_class_init      (AlsaToggleClass      *klass); +static void alsa_toggle_init            (AlsaToggle           *toggle); + +G_DEFINE_TYPE_WITH_CODE (AlsaToggle, alsa_toggle, MATE_MIXER_TYPE_TOGGLE, +                         G_IMPLEMENT_INTERFACE (ALSA_TYPE_ELEMENT, +                                                alsa_element_interface_init)) + +static gboolean               alsa_toggle_set_active_option (MateMixerSwitch       *mms, +                                                             MateMixerSwitchOption *mmso); + +static snd_mixer_elem_t *     alsa_toggle_get_snd_element   (AlsaElement           *element); +static void                   alsa_toggle_set_snd_element   (AlsaElement           *element, +                                                             snd_mixer_elem_t      *el); +static gboolean               alsa_toggle_load              (AlsaElement           *element); + +static void +alsa_element_interface_init (AlsaElementInterface *iface) +{ +    iface->get_snd_element = alsa_toggle_get_snd_element; +    iface->set_snd_element = alsa_toggle_set_snd_element; +    iface->load            = alsa_toggle_load; +} + +static void +alsa_toggle_class_init (AlsaToggleClass *klass) +{ +    MateMixerSwitchClass *switch_class; + +    switch_class = MATE_MIXER_SWITCH_CLASS (klass); +    switch_class->set_active_option = alsa_toggle_set_active_option; + +    g_type_class_add_private (G_OBJECT_CLASS (klass), sizeof (AlsaTogglePrivate)); +} + +static void +alsa_toggle_init (AlsaToggle *toggle) +{ +    toggle->priv = G_TYPE_INSTANCE_GET_PRIVATE (toggle, +                                                ALSA_TYPE_TOGGLE, +                                                AlsaTogglePrivate); +} + +AlsaToggle * +alsa_toggle_new (const gchar      *name, +                 const gchar      *label, +                 AlsaToggleType    type, +                 AlsaSwitchOption *on, +                 AlsaSwitchOption *off) +{ +    AlsaToggle *toggle; + +    toggle = g_object_new (ALSA_TYPE_TOGGLE, +                           "name", name, +                           "label", label, +                           "state-option-on", on, +                           "state-option-off", off, +                           NULL); + +    toggle->priv->type = type; +    return toggle; +} + +static gboolean +alsa_toggle_set_active_option (MateMixerSwitch *mms, MateMixerSwitchOption *mmso) +{ +    AlsaToggle *toggle; +    gint        value; +    gint        ret; + +    g_return_val_if_fail (ALSA_IS_TOGGLE (mms), FALSE); +    g_return_val_if_fail (ALSA_IS_SWITCH_OPTION (mmso), FALSE); + +    toggle = ALSA_TOGGLE (mms); + +    /* For toggles the 0/1 value is stored as the switch option id */ +    value = alsa_switch_option_get_id (ALSA_SWITCH_OPTION (mmso)); +    if G_UNLIKELY (value != 0 && value != 1) { +        g_warn_if_reached (); +        return FALSE; +    } + +    if (toggle->priv->type == ALSA_TOGGLE_CAPTURE) +        ret = snd_mixer_selem_set_capture_switch_all (toggle->priv->element, value); +    else +        ret = snd_mixer_selem_set_playback_switch_all (toggle->priv->element, value); + +    if (ret < 0) { +        g_warning ("Failed to set value of toggle %s: %s", +                   snd_mixer_selem_get_name (toggle->priv->element), +                   snd_strerror (ret)); +        return FALSE; +    } + +    return TRUE; +} + +static snd_mixer_elem_t * +alsa_toggle_get_snd_element (AlsaElement *element) +{ +    g_return_val_if_fail (ALSA_IS_TOGGLE (element), NULL); + +    return ALSA_TOGGLE (element)->priv->element; +} + +static void +alsa_toggle_set_snd_element (AlsaElement *element, snd_mixer_elem_t *el) +{ +    g_return_if_fail (ALSA_IS_TOGGLE (element)); +    g_return_if_fail (el != NULL); + +    ALSA_TOGGLE (element)->priv->element = el; +} + +static gboolean +alsa_toggle_load (AlsaElement *element) +{ +    AlsaToggle                  *toggle; +    gint                         value; +    gint                         ret; +    snd_mixer_selem_channel_id_t c; + +    toggle = ALSA_TOGGLE (element); + +    /* When reading the first time we try all the channels, otherwise only the +     * ones which returned success before */ +    if (toggle->priv->channel_mask == 0) { +        for (c = 0; c < SND_MIXER_SCHN_LAST; c++) { +            if (toggle->priv->type == ALSA_TOGGLE_CAPTURE) +                ret = snd_mixer_selem_get_capture_switch (toggle->priv->element, +                                                          c, +                                                          &value); +            else +                ret = snd_mixer_selem_get_playback_switch (toggle->priv->element, +                                                           c, +                                                           &value); + +            /* The active enum option is set per-channel, so when reading it the +             * first time, create a mask of all channels for which we read the +             * value successfully */ +            if (ret == 0) +                toggle->priv->channel_mask |= 1 << c; +        } + +        /* The last ALSA call might have failed, but it doesn't matter if we have +         * a channel mask */ +        if (toggle->priv->channel_mask > 0) +            ret = 0; +    } else { +        for (c = 0; !(toggle->priv->channel_mask & (1 << c)); c++) +            ; + +        /* When not reading the mask, the first usable channel is enough, we don't +         * support per-channel selections anyway */ +        if (toggle->priv->type == ALSA_TOGGLE_CAPTURE) +            ret = snd_mixer_selem_get_capture_switch (toggle->priv->element, +                                                      c, +                                                      &value); +        else +            ret = snd_mixer_selem_get_playback_switch (toggle->priv->element, +                                                       c, +                                                       &value); +    } + +    if (ret == 0) { +        MateMixerSwitchOption *active; + +        if (value > 0) +            active = mate_mixer_toggle_get_state_option (MATE_MIXER_TOGGLE (toggle), TRUE); +        else +            active = mate_mixer_toggle_get_state_option (MATE_MIXER_TOGGLE (toggle), FALSE); + +        _mate_mixer_switch_set_active_option (MATE_MIXER_SWITCH (toggle), active); + +        return TRUE; +    } + +    g_warning ("Failed to read state of toggle %s: %s", +               snd_mixer_selem_get_name (toggle->priv->element), +               snd_strerror (ret)); + +    return FALSE; +} diff --git a/backends/alsa/alsa-toggle.h b/backends/alsa/alsa-toggle.h new file mode 100644 index 0000000..d9c083b --- /dev/null +++ b/backends/alsa/alsa-toggle.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2014 Michal Ratajsky <[email protected]> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the licence, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef ALSA_TOGGLE_H +#define ALSA_TOGGLE_H + +#include <glib.h> +#include <glib-object.h> +#include <libmatemixer/matemixer.h> + +#include "alsa-switch-option.h" + +G_BEGIN_DECLS + +typedef enum { +    ALSA_TOGGLE_CAPTURE, +    ALSA_TOGGLE_PLAYBACK +} AlsaToggleType; + +#define ALSA_TYPE_TOGGLE                        \ +        (alsa_toggle_get_type ()) +#define ALSA_TOGGLE(o)                          \ +        (G_TYPE_CHECK_INSTANCE_CAST ((o), ALSA_TYPE_TOGGLE, AlsaToggle)) +#define ALSA_IS_TOGGLE(o)                       \ +        (G_TYPE_CHECK_INSTANCE_TYPE ((o), ALSA_TYPE_TOGGLE)) +#define ALSA_TOGGLE_CLASS(k)                    \ +        (G_TYPE_CHECK_CLASS_CAST ((k), ALSA_TYPE_TOGGLE, AlsaToggleClass)) +#define ALSA_IS_TOGGLE_CLASS(k)                 \ +        (G_TYPE_CHECK_CLASS_TYPE ((k), ALSA_TYPE_TOGGLE)) +#define ALSA_TOGGLE_GET_CLASS(o)                \ +        (G_TYPE_INSTANCE_GET_CLASS ((o), ALSA_TYPE_TOGGLE, AlsaToggleClass)) + +typedef struct _AlsaToggle         AlsaToggle; +typedef struct _AlsaToggleClass    AlsaToggleClass; +typedef struct _AlsaTogglePrivate  AlsaTogglePrivate; + +struct _AlsaToggle +{ +    MateMixerToggle parent; + +    /*< private >*/ +    AlsaTogglePrivate *priv; +}; + +struct _AlsaToggleClass +{ +    MateMixerToggleClass parent_class; +}; + +GType       alsa_toggle_get_type (void) G_GNUC_CONST; + +AlsaToggle *alsa_toggle_new      (const gchar      *name, +                                  const gchar      *label, +                                  AlsaToggleType    type, +                                  AlsaSwitchOption *on, +                                  AlsaSwitchOption *off); + +G_END_DECLS + +#endif /* ALSA_TOGGLE_H */ diff --git a/backends/oss/oss-backend.c b/backends/oss/oss-backend.c index 6e058f8..2b5eca7 100644 --- a/backends/oss/oss-backend.c +++ b/backends/oss/oss-backend.c @@ -19,91 +19,78 @@  #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 <glib-object.h> -#include <libmatemixer/matemixer-backend.h> -#include <libmatemixer/matemixer-backend-module.h> -#include <libmatemixer/matemixer-enums.h> -#include <libmatemixer/matemixer-stream.h> +#include <libmatemixer/matemixer.h> +#include <libmatemixer/matemixer-private.h>  #include "oss-backend.h"  #include "oss-common.h"  #include "oss-device.h" +#include "oss-stream.h"  #define BACKEND_NAME      "OSS"  #define BACKEND_PRIORITY  9 -#define PATH_SNDSTAT      "/dev/sndstat" +#if !defined(__linux__) && !defined(__NetBSD__) && !defined(__OpenBSD__) +    /* At least on systems based on FreeBSD we will need to read device names +     * from the sndstat file, but avoid even trying that on systems where this +     * is not needed and the file is not present */ +#define OSS_PATH_SNDSTAT  "/dev/sndstat" +#endif + +#define OSS_MAX_DEVICES   32  struct _OssBackendPrivate  { -    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 +    gchar      *default_device; +    GSource    *timeout_source; +    GHashTable *devices;  }; -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)) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-function" +G_DEFINE_DYNAMIC_TYPE (OssBackend, oss_backend, MATE_MIXER_TYPE_BACKEND) +#pragma clang diagnostic pop + +static gboolean oss_backend_open             (MateMixerBackend *backend); +static void     oss_backend_close            (MateMixerBackend *backend); +static GList *  oss_backend_list_devices     (MateMixerBackend *backend); +static GList *  oss_backend_list_streams     (MateMixerBackend *backend); -static gboolean oss_backend_open         (MateMixerBackend  *backend); -static void     oss_backend_close        (MateMixerBackend  *backend); -static GList *  oss_backend_list_devices (MateMixerBackend  *backend); -static GList *  oss_backend_list_streams (MateMixerBackend  *backend); +static gboolean read_devices                 (OssBackend       *oss); -static void     change_state                    (OssBackend        *oss, -                                                 MateMixerState     state); +static gboolean read_device                  (OssBackend       *oss, +                                              const gchar      *path, +                                              gboolean         *added); -static void     on_dev_monitor_changed          (GFileMonitor      *monitor, -                                                 GFile             *file, -                                                 GFile             *other_file, -                                                 GFileMonitorEvent  event_type, -                                                 OssBackend        *oss); +static gchar *  read_device_label            (OssBackend       *oss, +                                              const gchar      *path, +                                              gint              fd); -static gboolean read_device                     (OssBackend        *oss, -                                                 const gchar        *path); +static gchar *  read_device_label_sndstat    (OssBackend       *oss, +                                              const gchar      *sndstat, +                                              const gchar      *path, +                                              guint             index) G_GNUC_UNUSED; -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 void     add_device                      (OssBackend        *oss, -                                                 OssDevice         *device); -static void     remove_device                   (OssBackend        *oss, -                                                 OssDevice         *device); +static void     remove_stream                (OssBackend       *oss, +                                              const gchar      *name); + +static void     select_default_input_stream  (OssBackend       *oss); +static void     select_default_output_stream (OssBackend       *oss);  static MateMixerBackendInfo info; @@ -124,65 +111,31 @@ const MateMixerBackendInfo *backend_module_get_info (void)  }  static void -mate_mixer_backend_interface_init (MateMixerBackendInterface *iface) -{ -    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  oss_backend_class_init (OssBackendClass *klass)  { -    GObjectClass *object_class; +    GObjectClass          *object_class; +    MateMixerBackendClass *backend_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; +    object_class->dispose  = oss_backend_dispose; +    object_class->finalize = oss_backend_finalize; -    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"); +    backend_class = MATE_MIXER_BACKEND_CLASS (klass); +    backend_class->open         = oss_backend_open; +    backend_class->close        = oss_backend_close; +    backend_class->list_devices = oss_backend_list_devices; +    backend_class->list_streams = oss_backend_list_streams;      g_type_class_add_private (object_class, sizeof (OssBackendPrivate));  } -/* Called in the code generated by G_DEFINE_DYNAMIC_TYPE_EXTENDED() */ +/* Called in the code generated by G_DEFINE_DYNAMIC_TYPE() */  static void  oss_backend_class_finalize (OssBackendClass *klass)  {  }  static void -oss_backend_get_property (GObject    *object, -                          guint       param_id, -                          GValue     *value, -                          GParamSpec *pspec) -{ -    OssBackend *oss; - -    oss = OSS_BACKEND (object); - -    switch (param_id) { -    case PROP_STATE: -        g_value_set_enum (value, oss->priv->state); -        break; -    case PROP_DEFAULT_INPUT: -        g_value_set_object (value, oss->priv->default_input); -        break; -    case PROP_DEFAULT_OUTPUT: -        g_value_set_object (value, oss->priv->default_output); -        break; -        break; -    default: -        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); -        break; -    } -} - -static void  oss_backend_init (OssBackend *oss)  {      oss->priv = G_TYPE_INSTANCE_GET_PRIVATE (oss, @@ -193,17 +146,21 @@ oss_backend_init (OssBackend *oss)                                                  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)); +    MateMixerBackend *backend; +    MateMixerState    state; + +    backend = MATE_MIXER_BACKEND (object); + +    state = mate_mixer_backend_get_state (backend); +    if (state != MATE_MIXER_STATE_IDLE) +        oss_backend_close (backend); + +    G_OBJECT_CLASS (oss_backend_parent_class)->dispose (object);  }  static void @@ -214,61 +171,34 @@ oss_backend_finalize (GObject *object)      oss = OSS_BACKEND (object);      g_hash_table_destroy (oss->priv->devices); -    g_hash_table_destroy (oss->priv->streams); + +    G_OBJECT_CLASS (oss_backend_parent_class)->finalize (object);  }  static gboolean  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); +    /* Discover added or removed OSS devices every second */ +    oss->priv->timeout_source = g_timeout_source_new_seconds (1); +    g_source_set_callback (oss->priv->timeout_source, +                           (GSourceFunc) read_devices, +                           oss, +                           NULL); +    g_source_attach (oss->priv->timeout_source, +                     g_main_context_get_thread_default ()); + +    /* Read the initial list of devices so we have some starting point, there +     * isn't really a way to detect errors here, failing to add a device may +     * be a device-related problem so make the backend always open successfully */ +    read_devices (oss); + +    _mate_mixer_backend_set_state (backend, MATE_MIXER_STATE_READY);      return TRUE;  } @@ -281,15 +211,13 @@ oss_backend_close (MateMixerBackend *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_source_destroy (oss->priv->timeout_source);      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); +    g_free (oss->priv->default_device); +    oss->priv->default_device = NULL; + +    _mate_mixer_backend_set_state (backend, MATE_MIXER_STATE_IDLE);  }  static GList * @@ -299,306 +227,361 @@ oss_backend_list_devices (MateMixerBackend *backend)      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 */ +    /* Convert the hash table to a linked list, this list is expected to be +     * cached in the main library */      list = g_hash_table_get_values (OSS_BACKEND (backend)->priv->devices); -    if (list != NULL) { +    if (list != NULL)          g_list_foreach (list, (GFunc) g_object_ref, NULL); -        return list; -    } -    return NULL; +    return list;  }  static GList *  oss_backend_list_streams (MateMixerBackend *backend)  { -    GList *list; +    OssBackend    *oss; +    GHashTableIter iter; +    gpointer       value; +    GList         *list = NULL;      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); +    oss = OSS_BACKEND (backend); -        return list; +    /* We don't keep a list or hash table of all streams here, instead walk +     * through the list of devices and create the list manually, each device +     * has at most one input and one output stream */ +    g_hash_table_iter_init (&iter, oss->priv->devices); + +    while (g_hash_table_iter_next (&iter, NULL, &value)) { +        OssDevice *device = OSS_DEVICE (value); +        OssStream *stream; + +        stream = oss_device_get_output_stream (device); +        if (stream != NULL) +            list = g_list_prepend (list, stream); +        stream = oss_device_get_input_stream (device); +        if (stream != NULL) +            list = g_list_prepend (list, stream);      } -    return NULL; -} - -static void -change_state (OssBackend *oss, MateMixerState state) -{ -    if (oss->priv->state == state) -        return; -    oss->priv->state = state; +    if (list != NULL) +        g_list_foreach (list, (GFunc) g_object_ref, NULL); -    g_object_notify (G_OBJECT (oss), "state"); +    return list;  } -static void -on_dev_monitor_changed (GFileMonitor     *monitor, -                        GFile            *file, -                        GFile            *other_file, -                        GFileMonitorEvent event_type, -                        OssBackend       *oss) +static gboolean +read_devices (OssBackend *oss)  { -    gchar *path; +    gint     i; +    gboolean added = FALSE; -    if (event_type != G_FILE_MONITOR_EVENT_CREATED && -        event_type != G_FILE_MONITOR_EVENT_DELETED) -        return; +    for (i = 0; i < OSS_MAX_DEVICES; i++) { +        gboolean added_current; +        gchar   *path = g_strdup_printf ("/dev/mixer%i", i); -    path = g_file_get_path (file); +        /* On recent FreeBSD both /dev/mixer and /dev/mixer0 point to the same +         * mixer device, on NetBSD and OpenBSD /dev/mixer is a symlink to one +         * of the real mixer device nodes, on Linux /dev/mixer is the first +         * device and /dev/mixer1 is the second device. +         * Handle all of these cases by trying /dev/mixer if /dev/mixer0 fails */ +        if (read_device (oss, path, &added_current) == FALSE && i == 0) +            read_device (oss, "/dev/mixer", &added_current); + +        if (added_current) +            added = TRUE; -    /* 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); +    /* If any card has been added, make sure we have the most suitable default +     * input and output streams */ +    if (added == TRUE) { +        select_default_input_stream (oss); +        select_default_output_stream (oss); +    } +    return G_SOURCE_CONTINUE;  }  static gboolean -read_device (OssBackend *oss, const gchar *path) +read_device (OssBackend *oss, const gchar *path, gboolean *added)  { -    OssDevice   *device; -    gint         fd; -    gboolean     ret; -    const gchar *description; +    OssDevice *device; +    gint       fd; +    gchar     *bname; +    gchar     *label; -    /* 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; -    } +    *added = FALSE;      fd = g_open (path, O_RDWR, 0);      if (fd == -1) {          if (errno != ENOENT && errno != ENXIO)              g_debug ("%s: %s", path, g_strerror (errno)); + +        if (device != NULL) +            remove_device (oss, device);          return FALSE;      } -    device = oss_device_new (path, fd); +    /* Don't proceed if the device is already known, opening the device was +     * still tested to be absolutely sure that the device is removed it case +     * it has disappeared, but normally the device's polling facility should +     * handle this by itself */ +    if (device != NULL) { +        close (fd); +        return TRUE; +    } -    description = read_device_description (oss, path, fd); -    if (description != NULL) -        oss_device_set_description (device, description); -    else -        oss_device_set_description (device, _("Unknown device")); +    bname = g_path_get_basename (path); +    label = read_device_label (oss, path, fd); -    /* Close the descriptor as the device should dup it if it intends -     * to keep it */ -    g_close (fd, NULL); +    device = oss_device_new (bname, label, path, fd); +    g_free (bname); +    g_free (label); -    ret = oss_device_read (device); -    if (ret == TRUE) +    close (fd); + +    if ((*added = oss_device_open (device)) == TRUE)          add_device (oss, device);      g_object_unref (device); -    return ret; +    return *added;  }  static gchar * -read_device_description (OssBackend *oss, const gchar *path, gint fd) +read_device_label (OssBackend *oss, const gchar *path, gint fd)  { -    struct mixer_info info; +    guint index; -    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); -    } +#ifdef SOUND_MIXER_INFO +    do { +        struct mixer_info info; -    /* 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); +        /* Prefer device name supplied by the system, but this calls fails +         * with EINVAL on FreeBSD */ +        if (ioctl (fd, SOUND_MIXER_INFO, &info) == 0) +            return g_strdup (info.name); +    } while (0); +#endif -                g_clear_object (&oss->priv->sndstat); -            } -            g_error_free (error); -        } else -            return read_device_sndstat_description (path, input); -    } +    index = (guint) g_ascii_strtoull (path + sizeof ("/dev/mixer") - 1, +                                      NULL, +                                      10); +#ifdef OSS_PATH_SNDSTAT +    /* If the ioctl doesn't succeed, assume that the mixer device number +     * matches the pcm number in the sndstat file, this is a bit desperate, but +     * it should be correct on FreeBSD */ +    do { +        gchar *label; + +        label = read_device_label_sndstat (oss, OSS_PATH_SNDSTAT, path, index); +        if (label != NULL) +            return label; +    } while (0); +#endif -    return NULL; +    return g_strdup_printf (_("OSS Mixer %d"), index);  }  static gchar * -read_device_sndstat_description (const gchar *path, GFileInputStream *input) +read_device_label_sndstat (OssBackend  *oss, +                           const gchar *sndstat, +                           const gchar *path, +                           guint        index)  { -    gchar            *line; -    gchar            *prefix; -    gchar            *description = NULL; -    GDataInputStream *stream; - -    if (G_UNLIKELY (g_str_has_prefix (path, "/dev/mixer")) == FALSE) { -        g_warn_if_reached (); +    FILE  *fp; +    gchar *label = NULL; +    gchar *prefix; +    gchar  line[512]; + +    fp = g_fopen (sndstat, "r"); +    if (fp == NULL) { +        g_debug ("Failed to open %s: %s", sndstat, g_strerror (errno));          return NULL;      } -    /* 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; -        } +    /* Example line: +     * pcm0: <ATI R6xx (HDMI)> (play) default */ +    prefix = g_strdup_printf ("pcm%u: ", index); + +    while (fgets (line, sizeof (line), fp) != NULL) { +        gchar *p;          if (g_str_has_prefix (line, prefix) == FALSE)              continue; -        /* 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); -        } +            if (end != NULL) { +                label = 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)")) -            ; +                /* Normally the default OSS device is /dev/dsp, but on FreeBSD +                 * /dev/dsp doesn't physically exist on the filesystem, but is +                 * managed by the kernel according to the user-settable default +                 * device, in sndstat the default card definition ends with the +                 * word "default" */ +                if (g_str_has_suffix (line, "default")) { +                    g_free (oss->priv->default_device); -        if (description != NULL) +                    oss->priv->default_device = g_strdup (path); +                } +            } else { +                g_debug ("Failed to read sndstat line: %s", line); +            }              break; +        }      } -    g_object_unref (stream);      g_free (prefix); +    fclose (fp); -    return description; +    return label;  }  static void  add_device (OssBackend *oss, OssDevice *device)  { -    MateMixerStream *stream; +    const gchar *name; + +    name = mate_mixer_device_get_name (MATE_MIXER_DEVICE (device)); -    /* 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)); -    } +    // XXX make device emit it when closed +    g_signal_connect_swapped (G_OBJECT (device), +                              "stream-removed", +                              G_CALLBACK (remove_stream), +                              oss); -    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), "device-added", name); -        g_signal_emit_by_name (G_OBJECT (oss), -                               "stream-added", -                               mate_mixer_stream_get_name (stream)); -    } +    oss_device_load (device);  }  static void  remove_device (OssBackend *oss, OssDevice *device)  { +    const gchar *name; +    const gchar *path; + +    path = oss_device_get_path (device); +    name = mate_mixer_device_get_name (MATE_MIXER_DEVICE (device)); + +    g_signal_handlers_disconnect_by_func (G_OBJECT (device), +                                          G_CALLBACK (remove_stream), +                                          oss); + +    // XXX close the device and make it remove streams +    g_hash_table_remove (oss->priv->devices, path); + +    g_signal_emit_by_name (G_OBJECT (oss), +                           "device-removed", +                           name); +} + +static void +remove_stream (OssBackend *oss, const gchar *name) +{      MateMixerStream *stream; -    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); +    stream = mate_mixer_backend_get_default_input_stream (MATE_MIXER_BACKEND (oss)); + +    // XXX see if the change happens after stream is removed or before +    if (stream != NULL && strcmp (mate_mixer_stream_get_name (stream), name) == 0) +        select_default_input_stream (oss); + +    stream = mate_mixer_backend_get_default_output_stream (MATE_MIXER_BACKEND (oss)); + +    if (stream != NULL && strcmp (mate_mixer_stream_get_name (stream), name) == 0) +        select_default_output_stream (oss); +} -        g_hash_table_remove (oss->priv->streams, name); -        g_signal_emit_by_name (G_OBJECT (oss), -                               "stream-removed", -                               name); +static void +select_default_input_stream (OssBackend *oss) +{ +    OssDevice *device = NULL; +    OssStream *stream; +    gint       i; + +    /* Always prefer stream in the "default" device */ +    if (oss->priv->default_device != NULL) +        device = g_hash_table_lookup (oss->priv->devices, oss->priv->default_device); +    if (device != NULL) { +        stream = oss_device_get_input_stream (device); +        if (stream != NULL) { +            _mate_mixer_backend_set_default_input_stream (MATE_MIXER_BACKEND (oss), +                                                          MATE_MIXER_STREAM (stream)); +            return; +        }      } -    stream = oss_device_get_output_stream (device); -    if (stream != NULL) { -        const gchar *name = mate_mixer_stream_get_name (stream); +    for (i = 0; i < OSS_MAX_DEVICES; i++) { +        gchar *path = g_strdup_printf ("/dev/mixer%i", i); -        g_hash_table_remove (oss->priv->streams, stream); -        g_signal_emit_by_name (G_OBJECT (oss), -                               "stream-removed", -                               name); +        device = g_hash_table_lookup (oss->priv->devices, path); +        if (device == NULL && i == 0) +            device = g_hash_table_lookup (oss->priv->devices, "/dev/mixer"); + +        if (device != NULL) { +            stream = oss_device_get_input_stream (device); +            if (stream != NULL) { +                _mate_mixer_backend_set_default_input_stream (MATE_MIXER_BACKEND (oss), +                                                              MATE_MIXER_STREAM (stream)); +                g_free (path); +                return; +            } +        } +        g_free (path);      } -    path = oss_device_get_path (device); +    /* In the worst case unset the default stream */ +    _mate_mixer_backend_set_default_input_stream (MATE_MIXER_BACKEND (oss), NULL); +} -    /* Remove the device */ -    g_object_ref (device); +static void +select_default_output_stream (OssBackend *oss) +{ +    OssDevice *device = NULL; +    OssStream *stream; +    gint       i; + +    /* Always prefer stream in the "default" device */ +    if (oss->priv->default_device != NULL) +        device = g_hash_table_lookup (oss->priv->devices, oss->priv->default_device); +    if (device != NULL) { +        stream = oss_device_get_output_stream (device); +        if (stream != NULL) { +            _mate_mixer_backend_set_default_output_stream (MATE_MIXER_BACKEND (oss), +                                                           MATE_MIXER_STREAM (stream)); +            return; +        } +    } -    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))); +    for (i = 0; i < OSS_MAX_DEVICES; i++) { +        gchar *path = g_strdup_printf ("/dev/mixer%i", i); -    g_object_unref (device); +        device = g_hash_table_lookup (oss->priv->devices, path); +        if (device == NULL && i == 0) +            device = g_hash_table_lookup (oss->priv->devices, "/dev/mixer"); + +        if (device != NULL) { +            stream = oss_device_get_output_stream (device); +            if (stream != NULL) { +                _mate_mixer_backend_set_default_output_stream (MATE_MIXER_BACKEND (oss), +                                                               MATE_MIXER_STREAM (stream)); +                g_free (path); +                return; +            } +        } +        g_free (path); +    } + +    /* In the worst case unset the default stream */ +    _mate_mixer_backend_set_default_output_stream (MATE_MIXER_BACKEND (oss), NULL);  } diff --git a/backends/oss/oss-backend.h b/backends/oss/oss-backend.h index b766799..325b61c 100644 --- a/backends/oss/oss-backend.h +++ b/backends/oss/oss-backend.h @@ -21,6 +21,7 @@  #include <glib.h>  #include <glib-object.h> +#include <libmatemixer/matemixer-backend.h>  #include <libmatemixer/matemixer-backend-module.h>  #define OSS_TYPE_BACKEND                        \ @@ -42,7 +43,7 @@ typedef struct _OssBackendPrivate  OssBackendPrivate;  struct _OssBackend  { -    GObject parent; +    MateMixerBackend parent;      /*< private >*/      OssBackendPrivate *priv; @@ -50,7 +51,7 @@ struct _OssBackend  struct _OssBackendClass  { -    GObjectClass parent_class; +    MateMixerBackendClass parent_class;  };  GType                       oss_backend_get_type   (void) G_GNUC_CONST; diff --git a/backends/oss/oss-common.h b/backends/oss/oss-common.h index 7251b86..28a138d 100644 --- a/backends/oss/oss-common.h +++ b/backends/oss/oss-common.h @@ -24,6 +24,7 @@  #include <sys/stat.h>  #include <sys/ioctl.h>  #include <fcntl.h> +#include <unistd.h>  #ifdef HAVE_SYS_SOUNDCARD_H  #  include <sys/soundcard.h> diff --git a/backends/oss/oss-device.c b/backends/oss/oss-device.c index f33ff57..cf51705 100644 --- a/backends/oss/oss-device.c +++ b/backends/oss/oss-device.c @@ -22,12 +22,8 @@  #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 <libmatemixer/matemixer.h> +#include <libmatemixer/matemixer-private.h>  #include "oss-common.h"  #include "oss-device.h" @@ -36,490 +32,373 @@  #define OSS_DEVICE_ICON "audio-card" +typedef enum +{ +    OSS_DEV_ANY, +    OSS_DEV_INPUT, +    OSS_DEV_OUTPUT +} OssDevType; +  typedef struct  {      gchar                     *name; -    gchar                     *description; +    gchar                     *label;      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 }, +    OssDevType                 type; +} OssDev; + +static const OssDev oss_devices[] = { +    { "vol",     N_("Volume"),     MATE_MIXER_STREAM_CONTROL_ROLE_MASTER,  OSS_DEV_OUTPUT }, +    { "bass",    N_("Bass"),       MATE_MIXER_STREAM_CONTROL_ROLE_BASS,    OSS_DEV_OUTPUT }, +    { "treble",  N_("Treble"),     MATE_MIXER_STREAM_CONTROL_ROLE_TREBLE,  OSS_DEV_OUTPUT }, +    { "synth",   N_("Synth"),      MATE_MIXER_STREAM_CONTROL_ROLE_UNKNOWN, OSS_DEV_INPUT }, +    { "pcm",     N_("PCM"),        MATE_MIXER_STREAM_CONTROL_ROLE_PCM,     OSS_DEV_OUTPUT }, +    /* OSS manual says this should be the beeper, but Linux OSS seems to assign it to +     * regular volume control */ +    { "speaker", N_("Speaker"),    MATE_MIXER_STREAM_CONTROL_ROLE_SPEAKER, OSS_DEV_OUTPUT }, +    { "line",    N_("Line-in"),    MATE_MIXER_STREAM_CONTROL_ROLE_PORT,    OSS_DEV_INPUT }, +    { "mic",     N_("Microphone"), MATE_MIXER_STREAM_CONTROL_ROLE_PORT,    OSS_DEV_INPUT }, +    { "cd",      N_("CD"),         MATE_MIXER_STREAM_CONTROL_ROLE_CD,      OSS_DEV_INPUT },      /* Recording monitor */ -    { "mix",     N_("Mixer"),      MATE_MIXER_STREAM_CONTROL_ROLE_UNKNOWN, MATE_MIXER_STREAM_OUTPUT }, -    { "pcm2",    N_("PCM-2"),      MATE_MIXER_STREAM_CONTROL_ROLE_PCM,     MATE_MIXER_STREAM_OUTPUT }, +    { "mix",     N_("Mixer"),      MATE_MIXER_STREAM_CONTROL_ROLE_UNKNOWN, OSS_DEV_OUTPUT }, +    { "pcm2",    N_("PCM-2"),      MATE_MIXER_STREAM_CONTROL_ROLE_PCM,     OSS_DEV_OUTPUT },      /* Recording level (master input) */ -    { "rec",     N_("Record"),     MATE_MIXER_STREAM_CONTROL_ROLE_MASTER,  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 } +    { "rec",     N_("Record"),     MATE_MIXER_STREAM_CONTROL_ROLE_MASTER,  OSS_DEV_INPUT }, +    { "igain",   N_("In-gain"),    MATE_MIXER_STREAM_CONTROL_ROLE_UNKNOWN, OSS_DEV_INPUT }, +    { "ogain",   N_("Out-gain"),   MATE_MIXER_STREAM_CONTROL_ROLE_UNKNOWN, OSS_DEV_OUTPUT }, +    { "line1",   N_("Line-1"),     MATE_MIXER_STREAM_CONTROL_ROLE_PORT,    OSS_DEV_INPUT }, +    { "line2",   N_("Line-2"),     MATE_MIXER_STREAM_CONTROL_ROLE_PORT,    OSS_DEV_INPUT }, +    { "line3",   N_("Line-3"),     MATE_MIXER_STREAM_CONTROL_ROLE_PORT,    OSS_DEV_INPUT }, +    { "dig1",    N_("Digital-1"),  MATE_MIXER_STREAM_CONTROL_ROLE_PORT,    OSS_DEV_ANY }, +    { "dig2",    N_("Digital-2"),  MATE_MIXER_STREAM_CONTROL_ROLE_PORT,    OSS_DEV_ANY }, +    { "dig3",    N_("Digital-3"),  MATE_MIXER_STREAM_CONTROL_ROLE_PORT,    OSS_DEV_ANY }, +    { "phin",    N_("Phone-in"),   MATE_MIXER_STREAM_CONTROL_ROLE_PORT,    OSS_DEV_INPUT }, +    { "phout",   N_("Phone-out"),  MATE_MIXER_STREAM_CONTROL_ROLE_PORT,    OSS_DEV_OUTPUT }, +    { "video",   N_("Video"),      MATE_MIXER_STREAM_CONTROL_ROLE_PORT,    OSS_DEV_INPUT }, +    { "radio",   N_("Radio"),      MATE_MIXER_STREAM_CONTROL_ROLE_PORT,    OSS_DEV_INPUT }, +    { "monitor", N_("Monitor"),    MATE_MIXER_STREAM_CONTROL_ROLE_UNKNOWN, OSS_DEV_OUTPUT }, +    { "depth",   N_("3D-depth"),   MATE_MIXER_STREAM_CONTROL_ROLE_UNKNOWN, OSS_DEV_OUTPUT }, +    { "center",  N_("3D-center"),  MATE_MIXER_STREAM_CONTROL_ROLE_UNKNOWN, OSS_DEV_OUTPUT }, +    { "midi",    N_("MIDI"),       MATE_MIXER_STREAM_CONTROL_ROLE_UNKNOWN, OSS_DEV_INPUT }  }; +#define OSS_N_DEVICES MIN (G_N_ELEMENTS (oss_devices), SOUND_MIXER_NRDEVICES) +  struct _OssDevicePrivate  { -    gint             fd; -    gchar           *path; -    gchar           *name; -    gchar           *description; -    MateMixerStream *input; -    MateMixerStream *output; -}; - -enum { -    PROP_0, -    PROP_NAME, -    PROP_DESCRIPTION, -    PROP_ICON, -    PROP_ACTIVE_PROFILE, -    PROP_PATH, -    PROP_FD +    gint       fd; +    gchar     *path; +    gint       devmask; +    gint       stereodevs; +    gint       recmask; +    gint       recsrc; +    OssStream *input; +    OssStream *output;  }; -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_dispose      (GObject        *object);  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)) +G_DEFINE_TYPE (OssDevice, oss_device, MATE_MIXER_TYPE_DEVICE) -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 GList *  oss_device_list_streams    (MateMixerDevice  *device); -static gboolean     read_mixer_devices         (OssDevice       *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 gboolean set_stream_default_control (OssStream        *stream, +                                            OssStreamControl *control, +                                            gboolean          force);  static void  oss_device_class_init (OssDeviceClass *klass)  { -    GObjectClass *object_class; +    GObjectClass         *object_class; +    MateMixerDeviceClass *device_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"); +    object_class->dispose  = oss_device_dispose; +    object_class->finalize = oss_device_finalize; + +    device_class = MATE_MIXER_DEVICE_CLASS (klass); +    device_class->list_streams = oss_device_list_streams;      g_type_class_add_private (object_class, sizeof (OssDevicePrivate));  }  static void -oss_device_get_property (GObject    *object, -                         guint       param_id, -                         GValue     *value, -                         GParamSpec *pspec) +oss_device_init (OssDevice *device)  { -    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; -    } +    device->priv = G_TYPE_INSTANCE_GET_PRIVATE (device, +                                                OSS_TYPE_DEVICE, +                                                OssDevicePrivate);  }  static void -oss_device_set_property (GObject      *object, -                         guint         param_id, -                         const GValue *value, -                         GParamSpec   *pspec) +oss_device_dispose (GObject *object)  {      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; -    } -} +    g_clear_object (&device->priv->input); +    g_clear_object (&device->priv->output); -static void -oss_device_init (OssDevice *device) -{ -    device->priv = G_TYPE_INSTANCE_GET_PRIVATE (device, -                                                OSS_TYPE_DEVICE, -                                                OssDevicePrivate); +    G_OBJECT_CLASS (oss_device_parent_class)->dispose (object);  }  static void  oss_device_finalize (GObject *object)  { -    OssDevice *device; - -    device = OSS_DEVICE (object); - -    g_free (device->priv->name); -    g_free (device->priv->description); +    OssDevice *device = OSS_DEVICE (object); -    if (device->priv->fd != -1) -        g_close (device->priv->fd, NULL); +    close (device->priv->fd);      G_OBJECT_CLASS (oss_device_parent_class)->finalize (object);  }  OssDevice * -oss_device_new (const gchar *path, gint fd) +oss_device_new (const gchar *name, const gchar *label, const gchar *path, gint fd)  {      OssDevice *device; -    gchar     *basename; +    gchar     *stream_name; -    g_return_val_if_fail (path != NULL, NULL); +    g_return_val_if_fail (name  != NULL, NULL); +    g_return_val_if_fail (label != NULL, NULL); +    g_return_val_if_fail (path  != NULL, NULL);      device = g_object_new (OSS_TYPE_DEVICE, -                           "path", path, -                           "fd", fd, +                           "name", name, +                           "label", label, +                           "icon", OSS_DEVICE_ICON,                             NULL); -    basename = g_path_get_basename (path); +    device->priv->fd   = dup (fd); +    device->priv->path = g_strdup (path); -    device->priv->name = g_strdup_printf ("oss-%s", basename); -    g_free (basename); +    stream_name = g_strdup_printf ("oss-input-%s", name); +    device->priv->input = oss_stream_new (stream_name, +                                          MATE_MIXER_DEVICE (device), +                                          MATE_MIXER_STREAM_INPUT); +    g_free (stream_name); + +    stream_name = g_strdup_printf ("oss-output-%s", name); +    device->priv->output = oss_stream_new (stream_name, +                                           MATE_MIXER_DEVICE (device), +                                           MATE_MIXER_STREAM_OUTPUT); +    g_free (stream_name);      return device;  }  gboolean -oss_device_read (OssDevice *device) +oss_device_open (OssDevice *device)  { -    gchar                  *name; -    gchar                  *basename; -    MateMixerStreamControl *ctl; +    gint ret;      g_return_val_if_fail (OSS_IS_DEVICE (device), FALSE); -    // XXX avoid calling this function repeatedly - -    g_debug ("Querying device %s (%s)", +    g_debug ("Opening 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); +             mate_mixer_device_get_label (MATE_MIXER_DEVICE (device))); + +    /* Read the essential information about the device, these values are not +     * expected to change and will not be queried */ +    ret = ioctl (device->priv->fd, +                 MIXER_READ (SOUND_MIXER_DEVMASK), +                 &device->priv->devmask); +    if (ret != 0) +        goto fail; + +    ret = ioctl (device->priv->fd, +                 MIXER_READ (SOUND_MIXER_STEREODEVS), +                 &device->priv->stereodevs); +    if (ret < 0) +        goto fail; + +    ret = ioctl (device->priv->fd, +                 MIXER_READ (SOUND_MIXER_RECMASK), +                 &device->priv->recmask); +    if (ret < 0) +        goto fail; + +    /* The recording source mask may change at any time, here we just read +     * the initial value */ +    ret = ioctl (device->priv->fd, +                 MIXER_READ (SOUND_MIXER_RECSRC), +                 &device->priv->recsrc); +    if (ret < 0) +        goto fail; + +    /* NOTE: Linux also supports SOUND_MIXER_OUTSRC and SOUND_MIXER_OUTMASK which +     * inform about/enable input->output, we could potentially create toggles +     * for these, but these constants are not defined on any BSD. */ + +    return TRUE; + +fail: +    g_warning ("Failed to read device %s: %s", +               device->priv->path, +               g_strerror (errno)); + +    return FALSE; +} + +gboolean +oss_device_load (OssDevice *device) +{ +    MateMixerStreamControl *control; + +    g_return_val_if_fail (OSS_IS_DEVICE (device), FALSE); + +    read_mixer_devices (device); + +    control = mate_mixer_stream_get_default_control (MATE_MIXER_STREAM (device->priv->input)); +    if (control == NULL) { +        // XXX pick something      } -    if (ctl != NULL) +    if (control != 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); +                 mate_mixer_stream_control_get_label (control)); + +    control = mate_mixer_stream_get_default_control (MATE_MIXER_STREAM (device->priv->output)); +    if (control == NULL) { +        // XXX pick something      } -    if (ctl != NULL) +    if (control != NULL)          g_debug ("Default output stream control is %s", -                 mate_mixer_stream_control_get_description (ctl)); +                 mate_mixer_stream_control_get_label (control));      return TRUE;  } +gint +oss_device_get_fd (OssDevice *device) +{ +    g_return_val_if_fail (OSS_IS_DEVICE (device), -1); + +    return device->priv->fd; +} +  const gchar * -oss_device_get_path (OssDevice *odevice) +oss_device_get_path (OssDevice *device)  { -    g_return_val_if_fail (OSS_IS_DEVICE (odevice), FALSE); +    g_return_val_if_fail (OSS_IS_DEVICE (device), NULL); -    return odevice->priv->path; +    return device->priv->path;  } -MateMixerStream * -oss_device_get_input_stream (OssDevice *odevice) +OssStream * +oss_device_get_input_stream (OssDevice *device)  { -    g_return_val_if_fail (OSS_IS_DEVICE (odevice), FALSE); +    g_return_val_if_fail (OSS_IS_DEVICE (device), NULL); -    return odevice->priv->input; +    return device->priv->input;  } -MateMixerStream * -oss_device_get_output_stream (OssDevice *odevice) +OssStream * +oss_device_get_output_stream (OssDevice *device)  { -    g_return_val_if_fail (OSS_IS_DEVICE (odevice), FALSE); +    g_return_val_if_fail (OSS_IS_DEVICE (device), NULL); -    return odevice->priv->output; +    return device->priv->output;  } -gboolean -oss_device_set_description (OssDevice *odevice, const gchar *description) +static GList * +oss_device_list_streams (MateMixerDevice *mmd)  { -    g_return_val_if_fail (OSS_IS_DEVICE (odevice), FALSE); +    OssDevice *device; +    GList     *list = NULL; -    if (g_strcmp0 (odevice->priv->description, description) != 0) { -        g_free (odevice->priv->description); +    g_return_val_if_fail (OSS_IS_DEVICE (mmd), NULL); -        odevice->priv->description = g_strdup (description); +    device = OSS_DEVICE (mmd); -        g_object_notify (G_OBJECT (odevice), "description"); -        return TRUE; -    } -    return FALSE; +    if (device->priv->output != NULL) +        list = g_list_prepend (list, g_object_ref (device->priv->output)); +    if (device->priv->input != NULL) +        list = g_list_prepend (list, g_object_ref (device->priv->input)); + +    return list;  } +#define OSS_MASK_HAS_DEVICE(mask,i) ((gboolean) (((mask) & (1 << (i))) > 0)) +  static gboolean  read_mixer_devices (OssDevice *device)  { -    gint              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; +    gint i; -    for (i = 0; i < MIN (G_N_ELEMENTS (oss_devices), SOUND_MIXER_NRDEVICES); i++) { -        gboolean       stereo; -        gboolean       input = FALSE; -        MateMixerPort *port = NULL; +    for (i = 0; i < OSS_N_DEVICES; i++) { +        OssStreamControl *control; +        gboolean          input = FALSE;          /* Skip unavailable controls */ -        if ((devmask & (1 << i)) == 0) +        if (OSS_MASK_HAS_DEVICE (device->priv->devmask, i) == FALSE)              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].type == OSS_DEV_ANY) { +            input = OSS_MASK_HAS_DEVICE (device->priv->recmask, i);          } -        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; -            } +        else if (oss_devices[i].type == OSS_DEV_INPUT) {              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); +        control = oss_stream_control_new (oss_devices[i].name, +                                          oss_devices[i].label, +                                          oss_devices[i].role, +                                          device->priv->fd, +                                          i, +                                          OSS_MASK_HAS_DEVICE (device->priv->stereodevs, i));          if (input == TRUE) { -            oss_stream_add_control (OSS_STREAM (device->priv->input), ctl); +            oss_stream_add_control (OSS_STREAM (device->priv->input), control);              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 (i == SOUND_MIXER_RECLEV) +                    set_stream_default_control (OSS_STREAM (device->priv->input), +                                                control, +                                                TRUE); +                else +                    set_stream_default_control (OSS_STREAM (device->priv->input), +                                                control, +                                                FALSE);              } - -            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); +            oss_stream_add_control (OSS_STREAM (device->priv->output), control); + +            if (i == SOUND_MIXER_VOLUME || i == SOUND_MIXER_PCM) { +                if (i == SOUND_MIXER_VOLUME) +                    set_stream_default_control (OSS_STREAM (device->priv->output), +                                                control, +                                                TRUE); +                else +                    set_stream_default_control (OSS_STREAM (device->priv->output), +                                                control, +                                                FALSE);              } - -            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))); +                 mate_mixer_stream_control_get_label (MATE_MIXER_STREAM_CONTROL (control))); -        oss_stream_control_update (ctl); +        oss_stream_control_update (control);      }      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) +static gboolean +set_stream_default_control (OssStream *stream, OssStreamControl *control, gboolean force)  { -    g_return_val_if_fail (OSS_IS_DEVICE (device), NULL); +    MateMixerStreamControl *current; -    return OSS_DEVICE_ICON; +    current = mate_mixer_stream_get_default_control (MATE_MIXER_STREAM (stream)); +    if (current == NULL || force == TRUE) { +        oss_stream_set_default_control (stream, OSS_STREAM_CONTROL (control)); +        return TRUE; +    } +    return FALSE;  } diff --git a/backends/oss/oss-device.h b/backends/oss/oss-device.h index fe40eb2..261a884 100644 --- a/backends/oss/oss-device.h +++ b/backends/oss/oss-device.h @@ -20,6 +20,9 @@  #include <glib.h>  #include <glib-object.h> +#include <libmatemixer/matemixer.h> + +#include "oss-stream.h"  G_BEGIN_DECLS @@ -42,7 +45,7 @@ typedef struct _OssDevicePrivate  OssDevicePrivate;  struct _OssDevice  { -    GObject parent; +    MateMixerDevice parent;      /*< private >*/      OssDevicePrivate *priv; @@ -50,23 +53,24 @@ struct _OssDevice  struct _OssDeviceClass  { -    GObjectClass parent; +    MateMixerDeviceClass parent;  }; -GType            oss_device_get_type          (void) G_GNUC_CONST; - -OssDevice *      oss_device_new               (const gchar *path, -                                               gint         fd); +GType        oss_device_get_type          (void) G_GNUC_CONST; -gboolean         oss_device_read              (OssDevice   *device); +OssDevice *  oss_device_new               (const gchar *name, +                                           const gchar *label, +                                           const gchar *path, +                                           gint         fd); -const gchar *    oss_device_get_path          (OssDevice   *odevice); +gboolean     oss_device_open              (OssDevice   *device); +gboolean     oss_device_load              (OssDevice   *device); -MateMixerStream *oss_device_get_input_stream  (OssDevice   *odevice); -MateMixerStream *oss_device_get_output_stream (OssDevice   *odevice); +gint         oss_device_get_fd            (OssDevice   *device); +const gchar *oss_device_get_path          (OssDevice   *device); -gboolean         oss_device_set_description   (OssDevice   *odevice, -                                               const gchar *description); +OssStream *  oss_device_get_input_stream  (OssDevice   *device); +OssStream *  oss_device_get_output_stream (OssDevice   *device);  G_END_DECLS diff --git a/backends/oss/oss-stream-control.c b/backends/oss/oss-stream-control.c index 0b1db26..5161528 100644 --- a/backends/oss/oss-stream-control.c +++ b/backends/oss/oss-stream-control.c @@ -15,14 +15,13 @@   * 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 <libmatemixer/matemixer.h> +#include <libmatemixer/matemixer-private.h>  #include "oss-common.h"  #include "oss-stream-control.h" @@ -30,437 +29,279 @@  struct _OssStreamControlPrivate  {      gint                        fd; -    gint                        dev_number; -    gchar                      *name; -    gchar                      *description; +    gint                        devnum;      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_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      *control); +static void oss_stream_control_finalize   (GObject               *object); -static void oss_stream_control_init         (OssStreamControl      *octl); -static void oss_stream_control_finalize     (GObject               *object); +G_DEFINE_TYPE (OssStreamControl, oss_stream_control, MATE_MIXER_TYPE_STREAM_CONTROL) -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 gboolean                 oss_stream_control_set_mute             (MateMixerStreamControl  *mmsc, +                                                                         gboolean                 mute); -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  *mmsc); -static guint                    oss_stream_control_get_num_channels     (MateMixerStreamControl  *ctl); +static guint                    oss_stream_control_get_volume           (MateMixerStreamControl  *mmsc); -static gboolean                 oss_stream_control_set_volume           (MateMixerStreamControl  *ctl, +static gboolean                 oss_stream_control_set_volume           (MateMixerStreamControl  *mmsc,                                                                           guint                    volume); -static guint                    oss_stream_control_get_channel_volume   (MateMixerStreamControl  *ctl, +static gboolean                 oss_stream_control_has_channel_position (MateMixerStreamControl  *mmsc, +                                                                         MateMixerChannelPosition position); +static MateMixerChannelPosition oss_stream_control_get_channel_position (MateMixerStreamControl  *mmsc,                                                                           guint                    channel); -static gboolean                 oss_stream_control_set_channel_volume   (MateMixerStreamControl  *ctl, -                                                                         guint                    channel, -                                                                         guint                    volume); -static MateMixerChannelPosition oss_stream_control_get_channel_position (MateMixerStreamControl  *ctl, +static guint                    oss_stream_control_get_channel_volume   (MateMixerStreamControl  *mmsc,                                                                           guint                    channel); -static gboolean                 oss_stream_control_has_channel_position (MateMixerStreamControl  *ctl, -                                                                         MateMixerChannelPosition position); +static gboolean                 oss_stream_control_set_channel_volume   (MateMixerStreamControl  *mmsc, +                                                                         guint                    channel, +                                                                         guint                    volume); -static gboolean                 oss_stream_control_set_balance          (MateMixerStreamControl  *ctl, +static gboolean                 oss_stream_control_set_balance          (MateMixerStreamControl  *mmsc,                                                                           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 guint                    oss_stream_control_get_min_volume       (MateMixerStreamControl  *mmsc); +static guint                    oss_stream_control_get_max_volume       (MateMixerStreamControl  *mmsc); +static guint                    oss_stream_control_get_normal_volume    (MateMixerStreamControl  *mmsc); +static guint                    oss_stream_control_get_base_volume      (MateMixerStreamControl  *mmsc); -static 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 gboolean                 write_volume                            (OssStreamControl        *control, +                                                                         gint                     volume);  static void  oss_stream_control_class_init (OssStreamControlClass *klass)  { -    GObjectClass *object_class; +    GObjectClass                *object_class; +    MateMixerStreamControlClass *control_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"); +    object_class->finalize = oss_stream_control_finalize; + +    control_class = MATE_MIXER_STREAM_CONTROL_CLASS (klass); +    control_class->set_mute             = oss_stream_control_set_mute; +    control_class->get_num_channels     = oss_stream_control_get_num_channels; +    control_class->get_volume           = oss_stream_control_get_volume; +    control_class->set_volume           = oss_stream_control_set_volume; +    control_class->get_channel_volume   = oss_stream_control_get_channel_volume; +    control_class->set_channel_volume   = oss_stream_control_set_channel_volume; +    control_class->get_channel_position = oss_stream_control_get_channel_position; +    control_class->has_channel_position = oss_stream_control_has_channel_position; +    control_class->set_balance          = oss_stream_control_set_balance; +    control_class->get_min_volume       = oss_stream_control_get_min_volume; +    control_class->get_max_volume       = oss_stream_control_get_max_volume; +    control_class->get_normal_volume    = oss_stream_control_get_normal_volume; +    control_class->get_base_volume      = oss_stream_control_get_base_volume;      g_type_class_add_private (object_class, sizeof (OssStreamControlPrivate));  }  static void -oss_stream_control_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) +oss_stream_control_init (OssStreamControl *control)  { -    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); +    control->priv = G_TYPE_INSTANCE_GET_PRIVATE (control, +                                                 OSS_TYPE_STREAM_CONTROL, +                                                 OssStreamControlPrivate);  }  static void  oss_stream_control_finalize (GObject *object)  { -    OssStreamControl *octl; - -    octl = OSS_STREAM_CONTROL (object); +    OssStreamControl *control; -    g_free (octl->priv->name); -    g_free (octl->priv->description); +    control = OSS_STREAM_CONTROL (object); -    if (octl->priv->fd != -1) -        g_close (octl->priv->fd, NULL); +    close (control->priv->fd);      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) +oss_stream_control_new (const gchar               *name, +                        const gchar               *label, +                        MateMixerStreamControlRole role, +                        gint                       fd, +                        gint                       devnum, +                        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); +    OssStreamControl           *control; +    MateMixerStreamControlFlags flags; -    return ctl; +    flags = MATE_MIXER_STREAM_CONTROL_HAS_VOLUME | +            MATE_MIXER_STREAM_CONTROL_CAN_SET_VOLUME; +    if (stereo == TRUE) +        flags |= MATE_MIXER_STREAM_CONTROL_CAN_BALANCE; + +    control = g_object_new (OSS_TYPE_STREAM_CONTROL, +                            "name", name, +                            "label", label, +                            "flags", flags, +                            NULL); + +    control->priv->fd = fd; +    control->priv->devnum = devnum; +    control->priv->stereo = stereo; +    return control;  }  gboolean -oss_stream_control_update (OssStreamControl *octl) +oss_stream_control_update (OssStreamControl *control)  {      gint v;      gint ret; -    g_return_val_if_fail (OSS_IS_STREAM_CONTROL (octl), FALSE); +    g_return_val_if_fail (OSS_IS_STREAM_CONTROL (control), FALSE); -    ret = ioctl (octl->priv->fd, MIXER_READ (octl->priv->dev_number), &v); +    ret = ioctl (control->priv->fd, MIXER_READ (control->priv->devnum), &v);      if (ret < 0) {          g_warning ("Failed to read volume: %s", g_strerror (errno));          return FALSE;      } -    octl->priv->volume[0] = v & 0xFF; +    control->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); +    if (control->priv->stereo == TRUE) { +        gfloat balance; +        guint  left; +        guint  right; -    // XXX provide property +        control->priv->volume[1] = (v >> 8) & 0xFF; -    if (octl->priv->port != NULL) -        g_object_unref (octl->priv->port); +        /* Calculate balance */ +        left  = control->priv->volume[0]; +        right = control->priv->volume[1]; +        if (left == right) +            balance = 0.0f; +        else if (left > right) +            balance = -1.0f + ((gfloat) right / (gfloat) left); +        else +            balance = +1.0f - ((gfloat) left / (gfloat) right); -    octl->priv->port = g_object_ref (port); +        _mate_mixer_stream_control_set_balance (MATE_MIXER_STREAM_CONTROL (control), +                                                balance); +    }      return TRUE;  } -gboolean -oss_stream_control_set_role (OssStreamControl *octl, MateMixerStreamControlRole role) +static gboolean +oss_stream_control_set_mute (MateMixerStreamControl *mmsc, gboolean mute)  { -    g_return_val_if_fail (OSS_IS_STREAM_CONTROL (octl), FALSE); +    g_return_val_if_fail (OSS_IS_STREAM_CONTROL (mmsc), FALSE); -    octl->priv->role = role; +    // TODO      return TRUE;  } -static const gchar * -oss_stream_control_get_name (MateMixerStreamControl *ctl) +static guint +oss_stream_control_get_num_channels (MateMixerStreamControl *mmsc)  { -    g_return_val_if_fail (OSS_IS_STREAM_CONTROL (ctl), NULL); +    g_return_val_if_fail (OSS_IS_STREAM_CONTROL (mmsc), 0); -    return OSS_STREAM_CONTROL (ctl)->priv->name; +    return (OSS_STREAM_CONTROL (mmsc)->priv->stereo == TRUE) ? 2 : 1;  } -static const gchar * -oss_stream_control_get_description (MateMixerStreamControl *ctl) +static guint +oss_stream_control_get_volume (MateMixerStreamControl *mmsc)  { -    g_return_val_if_fail (OSS_IS_STREAM_CONTROL (ctl), NULL); +    OssStreamControl *control; -    return OSS_STREAM_CONTROL (ctl)->priv->description; -} +    g_return_val_if_fail (OSS_IS_STREAM_CONTROL (mmsc), 0); -static guint -oss_stream_control_get_num_channels (MateMixerStreamControl *ctl) -{ -    g_return_val_if_fail (OSS_IS_STREAM_CONTROL (ctl), 0); +    control = OSS_STREAM_CONTROL (mmsc); -    if (OSS_STREAM_CONTROL (ctl)->priv->stereo == TRUE) -        return 2; +    if (control->priv->stereo == TRUE) +        return MAX (control->priv->volume[0], control->priv->volume[1]);      else -        return 1; +        return control->priv->volume[0];  }  static gboolean -oss_stream_control_set_volume (MateMixerStreamControl *ctl, guint volume) +oss_stream_control_set_volume (MateMixerStreamControl *mmsc, guint volume)  { -    OssStreamControl *octl; -    int v; -    int ret; - -    g_return_val_if_fail (OSS_IS_STREAM_CONTROL (ctl), FALSE); +    OssStreamControl *control; +    gint              v; -    octl = OSS_STREAM_CONTROL (ctl); +    g_return_val_if_fail (OSS_IS_STREAM_CONTROL (mmsc), FALSE); -    /* Some backends may allow setting higher value than maximum, but not here */ -    if (volume > 100) -        volume = 100; +    control = OSS_STREAM_CONTROL (mmsc); -    v = volume; -    if (octl->priv->stereo == TRUE) +    v = CLAMP (volume, 0, 100); +    if (control->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; +    return write_volume (control, v);  }  static guint -oss_stream_control_get_channel_volume (MateMixerStreamControl *ctl, guint channel) +oss_stream_control_get_channel_volume (MateMixerStreamControl *mmsc, guint channel)  { -    OssStreamControl *octl; +    OssStreamControl *control; -    g_return_val_if_fail (OSS_IS_STREAM_CONTROL (ctl), 0); +    g_return_val_if_fail (OSS_IS_STREAM_CONTROL (mmsc), 0); -    octl = OSS_STREAM_CONTROL (ctl); +    control = OSS_STREAM_CONTROL (mmsc); -    if (channel > 1) -        return 0; - -    /* Right channel on mono stream will always have zero volume */ -    return octl->priv->volume[channel]; +    if (control->priv->stereo == TRUE) { +        if (channel == 0 || channel == 1) +            return control->priv->volume[channel]; +    } else { +        if (channel == 0) +            return control->priv->volume[0]; +    } +    return 0;  }  static gboolean -oss_stream_control_set_channel_volume (MateMixerStreamControl *ctl, +oss_stream_control_set_channel_volume (MateMixerStreamControl *mmsc,                                         guint                   channel,                                         guint                   volume)  { -    OssStreamControl *octl; -    int ret; -    int v; +    OssStreamControl *control; +    gint              v; -    g_return_val_if_fail (OSS_IS_STREAM_CONTROL (ctl), FALSE); +    g_return_val_if_fail (OSS_IS_STREAM_CONTROL (mmsc), 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]; +    control = OSS_STREAM_CONTROL (mmsc); +    volume  = CLAMP (volume, 0, 100); -    if (channel == 1) { -        if (octl->priv->stereo == FALSE) +    if (control->priv->stereo == TRUE) { +        if (channel > 1)              return FALSE; -        v |= volume << 8; -    } else -        v |= octl->priv->volume[1] << 8; +        /* Stereo channel volume - left channel is in the lowest 8 bits and +         * right channel is in the higher 8 bits */ +        if (channel == 0) +            v = volume | (control->priv->volume[1] << 8); +        else +            v = control->priv->volume[0] | (volume << 8); +    } else { +        if (channel > 0) +            return FALSE; -    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; +        /* Single channel volume - only lowest 8 bits are used */ +        v = volume;      } -    return TRUE; + +    return write_volume (control, v);  }  static MateMixerChannelPosition -oss_stream_control_get_channel_position (MateMixerStreamControl *ctl, guint channel) +oss_stream_control_get_channel_position (MateMixerStreamControl *mmsc, guint channel)  { -    OssStreamControl *octl; +    OssStreamControl *control; -    g_return_val_if_fail (OSS_IS_STREAM_CONTROL (ctl), MATE_MIXER_CHANNEL_UNKNOWN); +    g_return_val_if_fail (OSS_IS_STREAM_CONTROL (mmsc), MATE_MIXER_CHANNEL_UNKNOWN); -    octl = OSS_STREAM_CONTROL (ctl); +    control = OSS_STREAM_CONTROL (mmsc); -    if (octl->priv->stereo == TRUE) { +    if (control->priv->stereo == TRUE) {          if (channel == 0)              return MATE_MIXER_CHANNEL_FRONT_LEFT;          else if (channel == 1) @@ -473,57 +314,79 @@ oss_stream_control_get_channel_position (MateMixerStreamControl *ctl, guint chan  }  static gboolean -oss_stream_control_has_channel_position (MateMixerStreamControl  *ctl, +oss_stream_control_has_channel_position (MateMixerStreamControl  *mmsc,                                           MateMixerChannelPosition position)  { -    g_return_val_if_fail (OSS_IS_STREAM_CONTROL (ctl), FALSE); +    g_return_val_if_fail (OSS_IS_STREAM_CONTROL (mmsc), FALSE);      if (position == MATE_MIXER_CHANNEL_MONO) -        return OSS_STREAM_CONTROL (ctl)->priv->stereo == FALSE; +        return OSS_STREAM_CONTROL (mmsc)->priv->stereo == FALSE;      if (position == MATE_MIXER_CHANNEL_FRONT_LEFT ||          position == MATE_MIXER_CHANNEL_FRONT_RIGHT) -        return OSS_STREAM_CONTROL (ctl)->priv->stereo == TRUE; +        return OSS_STREAM_CONTROL (mmsc)->priv->stereo == TRUE;      return FALSE;  }  static gboolean -oss_stream_control_set_balance (MateMixerStreamControl *ctl, gfloat balance) +oss_stream_control_set_balance (MateMixerStreamControl *mmsc, gfloat balance)  { -    OssStreamControl *octl; +    OssStreamControl *control; +    guint             max; +    gint              v; -    g_return_val_if_fail (OSS_IS_STREAM_CONTROL (ctl), FALSE); +    g_return_val_if_fail (OSS_IS_STREAM_CONTROL (mmsc), FALSE); -    octl = OSS_STREAM_CONTROL (ctl); +    control = OSS_STREAM_CONTROL (mmsc); -    if (octl->priv->stereo == FALSE) -        return FALSE; +    max = MAX (control->priv->volume[0], control->priv->volume[1]); +    if (balance <= 0) { +        control->priv->volume[1] = (balance + 1.0f) * max; +        control->priv->volume[0] = max; +    } else { +        control->priv->volume[0] = (1.0f - balance) * max; +        control->priv->volume[1] = max; +    } -    // XXX -    return TRUE; +    v = control->priv->volume[0] | (control->priv->volume[1] << 8); + +    return write_volume (control, v);  }  static guint -oss_stream_control_get_min_volume (MateMixerStreamControl *ctl) +oss_stream_control_get_min_volume (MateMixerStreamControl *mmsc)  {      return 0;  }  static guint -oss_stream_control_get_max_volume (MateMixerStreamControl *ctl) +oss_stream_control_get_max_volume (MateMixerStreamControl *mmsc)  {      return 100;  }  static guint -oss_stream_control_get_normal_volume (MateMixerStreamControl *ctl) +oss_stream_control_get_normal_volume (MateMixerStreamControl *mmsc)  {      return 100;  }  static guint -oss_stream_control_get_base_volume (MateMixerStreamControl *ctl) +oss_stream_control_get_base_volume (MateMixerStreamControl *mmsc)  {      return 100;  } + +static gboolean +write_volume (OssStreamControl *control, gint volume) +{ +    gint ret; + +    ret = ioctl (control->priv->fd, MIXER_WRITE (control->priv->devnum), &volume); +    if (ret < 0) { +        g_warning ("Failed to set volume: %s", g_strerror (errno)); +        return FALSE; +    } +    return TRUE; +} diff --git a/backends/oss/oss-stream-control.h b/backends/oss/oss-stream-control.h index 420af48..c839faf 100644 --- a/backends/oss/oss-stream-control.h +++ b/backends/oss/oss-stream-control.h @@ -20,6 +20,7 @@  #include <glib.h>  #include <glib-object.h> +#include <libmatemixer/matemixer.h>  G_BEGIN_DECLS @@ -42,7 +43,7 @@ typedef struct _OssStreamControlPrivate  OssStreamControlPrivate;  struct _OssStreamControl  { -    GObject parent; +    MateMixerStreamControl parent;      /*< private >*/      OssStreamControlPrivate *priv; @@ -50,24 +51,19 @@ struct _OssStreamControl  struct _OssStreamControlClass  { -    GObjectClass parent; +    MateMixerStreamControlClass parent;  }; -GType             oss_stream_control_get_type    (void) G_GNUC_CONST; +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); +OssStreamControl *oss_stream_control_new      (const gchar               *name, +                                               const gchar               *label, +                                               MateMixerStreamControlRole role, +                                               gint                       fd, +                                               gint                       devnum, +                                               gboolean                   stereo); -gboolean          oss_stream_control_update      (OssStreamControl *octl); - -gboolean          oss_stream_control_set_port    (OssStreamControl *octl, -                                                  MateMixerPort    *port); - -gboolean          oss_stream_control_set_role    (OssStreamControl *octl, -                                                  MateMixerStreamControlRole role); +gboolean          oss_stream_control_update   (OssStreamControl          *control);  G_END_DECLS diff --git a/backends/oss/oss-stream.c b/backends/oss/oss-stream.c index 69bfd06..5f0c629 100644 --- a/backends/oss/oss-stream.c +++ b/backends/oss/oss-stream.c @@ -15,301 +15,169 @@   * 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.h> -#include <libmatemixer/matemixer-device.h> -#include <libmatemixer/matemixer-enums.h> -#include <libmatemixer/matemixer-stream.h> - +#include "oss-device.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, +    GHashTable       *controls; +    OssStreamControl *control;  }; -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); +G_DEFINE_TYPE (OssStream, oss_stream, MATE_MIXER_TYPE_STREAM)  static MateMixerStreamControl *oss_stream_get_control         (MateMixerStream *stream,                                                                 const gchar     *name);  static MateMixerStreamControl *oss_stream_get_default_control (MateMixerStream *stream); -static 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 GList *                 oss_stream_list_controls       (MateMixerStream *stream);  static void  oss_stream_class_init (OssStreamClass *klass)  { -    GObjectClass *object_class; +    GObjectClass         *object_class; +    MateMixerStreamClass *stream_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; +    object_class->dispose  = oss_stream_dispose; +    object_class->finalize = oss_stream_finalize; -    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"); +    stream_class = MATE_MIXER_STREAM_CLASS (klass); +    stream_class->get_control         = oss_stream_get_control; +    stream_class->get_default_control = oss_stream_get_default_control; +    stream_class->list_controls       = oss_stream_list_controls;      g_type_class_add_private (object_class, sizeof (OssStreamPrivate));  }  static void -oss_stream_get_property (GObject    *object, -                         guint       param_id, -                         GValue     *value, -                         GParamSpec *pspec) +oss_stream_init (OssStream *stream)  { -    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; -    } -} +    stream->priv = G_TYPE_INSTANCE_GET_PRIVATE (stream, +                                                OSS_TYPE_STREAM, +                                                OssStreamPrivate); -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); +    stream->priv->controls = g_hash_table_new_full (g_str_hash, +                                                    g_str_equal, +                                                    g_free, +                                                    g_object_unref);  }  static void  oss_stream_dispose (GObject *object)  { -    OssStream *ostream; +    OssStream *stream; -    ostream = OSS_STREAM (object); +    stream = OSS_STREAM (object); -    g_hash_table_remove_all (ostream->priv->controls); -    g_hash_table_remove_all (ostream->priv->ports); +    g_clear_object (&stream->priv->control); +    g_hash_table_remove_all (stream->priv->controls); -    G_OBJECT_CLASS (oss_stream_parent_class)->finalize (object); +    G_OBJECT_CLASS (oss_stream_parent_class)->dispose (object);  }  static void  oss_stream_finalize (GObject *object)  { -    OssStream *ostream; - -    ostream = OSS_STREAM (object); +    OssStream *stream; -    g_free (ostream->priv->name); -    g_free (ostream->priv->description); +    stream = OSS_STREAM (object); -    g_hash_table_destroy (ostream->priv->controls); -    g_hash_table_destroy (ostream->priv->ports); +    g_hash_table_destroy (stream->priv->controls);      G_OBJECT_CLASS (oss_stream_parent_class)->finalize (object);  }  OssStream *  oss_stream_new (const gchar         *name, -                const gchar         *description, +                MateMixerDevice     *device,                  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; - +    stream = g_object_new (OSS_TYPE_STREAM, +                           "name", name, +                           "device", device, +                           "flags", flags, +                           NULL);      return stream;  }  gboolean -oss_stream_add_control (OssStream *ostream, OssStreamControl *octl) +oss_stream_add_control (OssStream *stream, OssStreamControl *control)  {      const gchar *name; -    g_return_val_if_fail (OSS_IS_STREAM (ostream), FALSE); -    g_return_val_if_fail (OSS_IS_STREAM_CONTROL (octl), FALSE); +    g_return_val_if_fail (OSS_IS_STREAM (stream), FALSE); +    g_return_val_if_fail (OSS_IS_STREAM_CONTROL (control), FALSE); -    name = mate_mixer_stream_control_get_name (MATE_MIXER_STREAM_CONTROL (octl)); +    name = mate_mixer_stream_control_get_name (MATE_MIXER_STREAM_CONTROL (control)); -    g_hash_table_insert (ostream->priv->controls, +    g_hash_table_insert (stream->priv->controls,                           g_strdup (name), -                         octl); +                         control);      return TRUE;  }  gboolean -oss_stream_set_default_control (OssStream *ostream, OssStreamControl *octl) +oss_stream_set_default_control (OssStream *stream, OssStreamControl *control)  { -    g_return_val_if_fail (OSS_IS_STREAM (ostream), FALSE); -    g_return_val_if_fail (OSS_IS_STREAM_CONTROL (octl), FALSE); +    g_return_val_if_fail (OSS_IS_STREAM (stream), FALSE); +    g_return_val_if_fail (OSS_IS_STREAM_CONTROL (control), FALSE);      /* This function is only used internally so avoid validating that the control       * belongs to this stream */ -    if (ostream->priv->control != NULL) -        g_object_unref (ostream->priv->control); - -    ostream->priv->control = g_object_ref (octl); -    return TRUE; -} +    if (stream->priv->control != NULL) +        g_object_unref (stream->priv->control); -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); +    if G_LIKELY (control != NULL) +        stream->priv->control = g_object_ref (control); +    else +        stream->priv->control = NULL; -    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) +oss_stream_get_control (MateMixerStream *mms, const gchar *name)  { -    g_return_val_if_fail (OSS_IS_STREAM (stream), NULL); +    g_return_val_if_fail (OSS_IS_STREAM (mms), NULL);      g_return_val_if_fail (name != NULL, NULL); -    return g_hash_table_lookup (OSS_STREAM (stream)->priv->controls, name); +    return g_hash_table_lookup (OSS_STREAM (mms)->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) +oss_stream_get_default_control (MateMixerStream *mms)  { -    OssStream *ostream; - -    g_return_val_if_fail (OSS_IS_STREAM (stream), NULL); - -    ostream = OSS_STREAM (stream); +    g_return_val_if_fail (OSS_IS_STREAM (mms), NULL); -    if (ostream->priv->controls_list == NULL) -        ostream->priv->controls_list = g_hash_table_get_values (ostream->priv->controls); - -    return ostream->priv->controls_list; +    return MATE_MIXER_STREAM_CONTROL (OSS_STREAM (mms)->priv->control);  } -static const GList * -oss_stream_list_ports (MateMixerStream *stream) +static GList * +oss_stream_list_controls (MateMixerStream *mms)  { -    OssStream *ostream; - -    g_return_val_if_fail (OSS_IS_STREAM (stream), NULL); +    GList *list; -    ostream = OSS_STREAM (stream); +    g_return_val_if_fail (OSS_IS_STREAM (mms), NULL); -    if (ostream->priv->ports_list == NULL) -        ostream->priv->ports_list = g_hash_table_get_values (ostream->priv->ports); +    /* Convert the hash table to a linked list, this list is expected to be +     * cached in the main library */ +    list = g_hash_table_get_values (OSS_STREAM (mms)->priv->controls); +    if (list != NULL) +        g_list_foreach (list, (GFunc) g_object_ref, NULL); -    return ostream->priv->ports_list; +    return list;  } diff --git a/backends/oss/oss-stream.h b/backends/oss/oss-stream.h index d6c2fb2..0470eb7 100644 --- a/backends/oss/oss-stream.h +++ b/backends/oss/oss-stream.h @@ -20,7 +20,9 @@  #include <glib.h>  #include <glib-object.h> +#include <libmatemixer/matemixer.h> +#include "oss-device.h"  #include "oss-stream-control.h"  G_BEGIN_DECLS @@ -44,7 +46,7 @@ typedef struct _OssStreamPrivate  OssStreamPrivate;  struct _OssStream  { -    GObject parent; +    MateMixerStream parent;      /*< private >*/      OssStreamPrivate *priv; @@ -52,23 +54,20 @@ struct _OssStream  struct _OssStreamClass  { -    GObjectClass parent; +    MateMixerStreamClass parent;  }; -GType             oss_stream_get_type            (void) G_GNUC_CONST; +GType      oss_stream_get_type            (void) G_GNUC_CONST; -OssStream *       oss_stream_new                 (const gchar         *name, -                                                  const gchar         *description, -                                                  MateMixerStreamFlags flags); +OssStream *oss_stream_new                 (const gchar         *name, +                                           MateMixerDevice     *device, +                                           MateMixerStreamFlags flags); -gboolean          oss_stream_add_control         (OssStream           *stream, -                                                  OssStreamControl    *ctl); +gboolean   oss_stream_add_control         (OssStream           *stream, +                                           OssStreamControl    *control); -gboolean          oss_stream_set_default_control (OssStream           *stream, -                                                  OssStreamControl    *ctl); - -gboolean          oss_stream_add_port            (OssStream           *ostream, -                                                  MateMixerPort       *port); +gboolean   oss_stream_set_default_control (OssStream           *stream, +                                           OssStreamControl    *control);  G_END_DECLS diff --git a/backends/oss4/Makefile.am b/backends/oss4/Makefile.am deleted file mode 100644 index cca8723..0000000 --- a/backends/oss4/Makefile.am +++ /dev/null @@ -1,29 +0,0 @@ -backenddir = $(libdir)/libmatemixer - -backend_LTLIBRARIES = libmatemixer-oss4.la - -AM_CPPFLAGS =                                                   \ -        -I$(top_srcdir)                                         \ -        -DG_LOG_DOMAIN=\"libmatemixer-oss4\" - -libmatemixer_oss4_la_CFLAGS =                                   \ -        $(GLIB_CFLAGS)                                          \ -        $(OSS4_CFLAGS) - -libmatemixer_oss4_la_SOURCES =                                  \ -        oss4-common.h                                           \ -        oss4-backend.c                                          \ -        oss4-backend.h                                          \ -        oss4-device.c                                           \ -        oss4-device.h - -libmatemixer_oss4_la_LIBADD =                                   \ -        $(GLIB_LIBS) - -libmatemixer_oss4_la_LDFLAGS =                                  \ -        -avoid-version                                          \ -        -no-undefined                                           \ -        -export-dynamic                                         \ -        -module - --include $(top_srcdir)/git.mk diff --git a/backends/oss4/oss4-backend.c b/backends/oss4/oss4-backend.c deleted file mode 100644 index bd79fdf..0000000 --- a/backends/oss4/oss4-backend.c +++ /dev/null @@ -1,487 +0,0 @@ -/* - * Copyright (C) 2014 Michal Ratajsky <[email protected]> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the licence, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/>. - */ - -#include <stdio.h> -#include <string.h> -#include <errno.h> -#include <glib.h> -#include <glib-object.h> -#include <glib/gstdio.h> -#include <glib/gprintf.h> -#include <glib/gi18n.h> -#include <gio/gio.h> - -#include <libmatemixer/matemixer-backend.h> -#include <libmatemixer/matemixer-backend-module.h> -#include <libmatemixer/matemixer-enums.h> -#include <libmatemixer/matemixer-stream.h> - -#include "oss4-backend.h" -#include "oss4-common.h" -#include "oss4-device.h" - -#define BACKEND_NAME      "OSS4" -#define BACKEND_PRIORITY  8 - -#define PATH_SNDSTAT      "/dev/sndstat" - -struct _Oss4BackendPrivate -{ -    gint fd; -    gchar           *sndstat; -    GHashTable      *devices; -    GHashTable      *streams; -    MateMixerStream *default_input; -    MateMixerStream *default_output; -    MateMixerState   state; -}; - -enum { -    PROP_0, -    PROP_STATE, -    PROP_DEFAULT_INPUT, -    PROP_DEFAULT_OUTPUT -}; - -static void mate_mixer_backend_interface_init (MateMixerBackendInterface *iface); - -static void oss4_backend_class_init     (Oss4BackendClass *klass); -static void oss4_backend_class_finalize (Oss4BackendClass *klass); - -static void oss4_backend_get_property   (GObject         *object, -                                         guint            param_id, -                                         GValue          *value, -                                         GParamSpec      *pspec); - -static void oss4_backend_init           (Oss4Backend     *oss); -static void oss4_backend_dispose        (GObject         *object); -static void oss4_backend_finalize       (GObject         *object); - -G_DEFINE_DYNAMIC_TYPE_EXTENDED (Oss4Backend, oss4_backend, -                                G_TYPE_OBJECT, 0, -                                G_IMPLEMENT_INTERFACE_DYNAMIC (MATE_MIXER_TYPE_BACKEND, -                                                               mate_mixer_backend_interface_init)) - -static gboolean oss4_backend_open         (MateMixerBackend  *backend); -static void     oss4_backend_close        (MateMixerBackend  *backend); -static GList *  oss4_backend_list_devices (MateMixerBackend  *backend); -static GList *  oss4_backend_list_streams (MateMixerBackend  *backend); - -static void     change_state                    (Oss4Backend       *oss, -                                                 MateMixerState     state); - -static gboolean read_device (Oss4Backend *oss, gint index); - -static gchar *  read_device_sndstat_description (Oss4Backend *oss, -                                                 const gchar *prefix); - -static void     add_device      (Oss4Backend *oss, Oss4Device *device); -static void     remove_device   (Oss4Backend *oss, Oss4Device *device); - -static MateMixerBackendInfo info; - -void -backend_module_init (GTypeModule *module) -{ -    oss4_backend_register_type (module); - -    info.name         = BACKEND_NAME; -    info.priority     = BACKEND_PRIORITY; -    info.g_type       = OSS4_TYPE_BACKEND; -    info.backend_type = MATE_MIXER_BACKEND_OSS4; -} - -const MateMixerBackendInfo *backend_module_get_info (void) -{ -    return &info; -} - -static void -mate_mixer_backend_interface_init (MateMixerBackendInterface *iface) -{ -    iface->open         = oss4_backend_open; -    iface->close        = oss4_backend_close; -    iface->list_devices = oss4_backend_list_devices; -    iface->list_streams = oss4_backend_list_streams; -} - -static void -oss4_backend_class_init (Oss4BackendClass *klass) -{ -    GObjectClass *object_class; - -    object_class = G_OBJECT_CLASS (klass); -    object_class->dispose      = oss4_backend_dispose; -    object_class->finalize     = oss4_backend_finalize; -    object_class->get_property = oss4_backend_get_property; - -    g_object_class_override_property (object_class, PROP_STATE, "state"); -    g_object_class_override_property (object_class, PROP_DEFAULT_INPUT, "default-input"); -    g_object_class_override_property (object_class, PROP_DEFAULT_OUTPUT, "default-output"); - -    g_type_class_add_private (object_class, sizeof (Oss4BackendPrivate)); -} - -/* Called in the code generated by G_DEFINE_DYNAMIC_TYPE_EXTENDED() */ -static void -oss4_backend_class_finalize (Oss4BackendClass *klass) -{ -} - -static void -oss4_backend_get_property (GObject    *object, -                           guint       param_id, -                           GValue     *value, -                           GParamSpec *pspec) -{ -    Oss4Backend *oss; - -    oss = OSS4_BACKEND (object); - -    switch (param_id) { -    case PROP_STATE: -        g_value_set_enum (value, oss->priv->state); -        break; -    case PROP_DEFAULT_INPUT: -        g_value_set_object (value, oss->priv->default_input); -        break; -    case PROP_DEFAULT_OUTPUT: -        g_value_set_object (value, oss->priv->default_output); -        break; -        break; -    default: -        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); -        break; -    } -} - -static void -oss4_backend_init (Oss4Backend *oss) -{ -    oss->priv = G_TYPE_INSTANCE_GET_PRIVATE (oss, -                                             OSS4_TYPE_BACKEND, -                                             Oss4BackendPrivate); - -    oss->priv->devices = g_hash_table_new_full (g_direct_hash, -                                                g_direct_equal, -                                                NULL, -                                                g_object_unref); - -    oss->priv->streams = g_hash_table_new_full (g_str_hash, -                                                g_str_equal, -                                                g_free, -                                                g_object_unref); -} - -static void -oss4_backend_dispose (GObject *object) -{ -    oss4_backend_close (MATE_MIXER_BACKEND (object)); -} - -static void -oss4_backend_finalize (GObject *object) -{ -    Oss4Backend *oss; - -    oss = OSS4_BACKEND (object); - -    g_hash_table_destroy (oss->priv->devices); -    g_hash_table_destroy (oss->priv->streams); -} - -static gboolean -oss4_backend_open (MateMixerBackend *backend) -{ -    Oss4Backend       *oss; -    gint               fd; -    gint               i; -    gint               ret; -    struct oss_sysinfo info; - -    g_return_val_if_fail (OSS4_IS_BACKEND (backend), FALSE); - -    oss = OSS4_BACKEND (backend); - -    fd = g_open ("/dev/mixer", O_RDONLY, 0); -    if (fd == -1) -        fd = g_open ("/dev/mixer0", O_RDONLY, 0); -    if (fd == -1) { -        change_state (oss, MATE_MIXER_STATE_FAILED); -        return FALSE; -    } - -    /* Query the number of mixer devices */ -    ret = ioctl (fd, OSS_SYSINFO, &info); -    if (ret == -1) { -        close (fd); -        change_state (oss, MATE_MIXER_STATE_FAILED); -        return FALSE; -    } - -    g_debug ("The sound system is %s version %s", -             info.product, -             info.version); - -#if !defined(__linux__) -    /* At least on systems based on FreeBSD we will need to read devices names -     * from the sndstat file, but avoid even trying that on systems where this -     * is not needed and the file is not present */ -    oss->priv->sndstat = PATH_SNDSTAT; -#endif - -    oss->priv->fd = fd; - -    for (i = 0; i < info.nummixers; i++) -        read_device (oss, i); - -    change_state (oss, MATE_MIXER_STATE_READY); -    return TRUE; -} - -void -oss4_backend_close (MateMixerBackend *backend) -{ -    Oss4Backend *oss; - -    g_return_if_fail (OSS4_IS_BACKEND (backend)); - -    oss = OSS4_BACKEND (backend); - -    g_clear_object (&oss->priv->default_input); -    g_clear_object (&oss->priv->default_output); - -    g_hash_table_remove_all (oss->priv->streams); -    g_hash_table_remove_all (oss->priv->devices); -} - -static GList * -oss4_backend_list_devices (MateMixerBackend *backend) -{ -    GList *list; - -    g_return_val_if_fail (OSS4_IS_BACKEND (backend), NULL); - -    /* Convert the hash table to a sorted linked list, this list is expected -     * to be cached in the main library */ -    list = g_hash_table_get_values (OSS4_BACKEND (backend)->priv->devices); -    if (list != NULL) { -        g_list_foreach (list, (GFunc) g_object_ref, NULL); - -        return list; -    } -    return NULL; -} - -static GList * -oss4_backend_list_streams (MateMixerBackend *backend) -{ -    GList *list; - -    g_return_val_if_fail (OSS4_IS_BACKEND (backend), NULL); - -    /* Convert the hash table to a sorted linked list, this list is expected -     * to be cached in the main library */ -    list = g_hash_table_get_values (OSS4_BACKEND (backend)->priv->streams); -    if (list != NULL) { -        g_list_foreach (list, (GFunc) g_object_ref, NULL); - -        return list; -    } -    return NULL; -} - -static void -change_state (Oss4Backend *oss, MateMixerState state) -{ -    if (oss->priv->state == state) -        return; - -    oss->priv->state = state; - -    g_object_notify (G_OBJECT (oss), "state"); -} - -static gboolean -read_device (Oss4Backend *oss, gint index) -{ -    Oss4Device          *device; -    gboolean             ret; -    gchar               *description = NULL; -    struct oss_mixerinfo info; - -    /* We assume that the name and capabilities of a device do not change */ -    device = g_hash_table_lookup (oss->priv->devices, GINT_TO_POINTER (index)); -    if (G_UNLIKELY (device != NULL)) { -        g_debug ("Attempt to re-read already know device with index %d", index); -        return TRUE; -    } - -    info.dev = index; -    ret = ioctl (oss->priv->fd, SNDCTL_MIXERINFO, &info); -    if (ret == -1) { -        g_debug ("Failed to read mixer info: %s", g_strerror (errno)); -        return FALSE; -    } - -    if (info.enabled == 0) -        return TRUE; - -    /* Use the id as the device name and try to figure out the name of the -     * sound card from the sndstat file if it is available, otherwise use -     * the name from the mixer info */ -    if (oss->priv->sndstat != NULL && -        g_str_has_prefix (info.name, "pcm") == TRUE) -        description = read_device_sndstat_description (oss, info.name); - -    if (description == NULL) -        description = g_strdup (info.name); - -    device = oss4_device_new (info.id, description, oss->priv->fd, index); - -    ret = oss4_device_read (device); -    if (ret == TRUE) -        add_device (oss, device); - -    g_object_unref (device); -    g_free (description); - -    return ret; -} - -static gchar * -read_device_sndstat_description (Oss4Backend *oss, const gchar *prefix) -{ -    FILE  *fp; -    gchar  line[256]; -    gchar *description = NULL; - -    g_debug ("reading prefix %s", prefix); - -    fp = fopen (oss->priv->sndstat, "r"); -    if (fp == NULL) { -        g_warning ("Failed to read %s: %s", oss->priv->sndstat, g_strerror (errno)); -        return FALSE; -    } - -    while (fgets (line, sizeof (line), fp) != NULL) { -        gchar *p; - -        if (g_str_has_prefix (line, prefix) == FALSE) -            continue; - -        /* Example line: -         * pcm0: <ATI R6xx (HDMI)> (play) default */ -        p = strchr (line, '<'); -        if (p != NULL && *p && *(++p)) { -            gchar *end = strchr (p, '>'); - -            if (end != NULL) -                description = g_strndup (p, end - p); -        } - -        // XXX we can also read "default" at the end of the line -        // XXX http://ashish.is.lostca.se/2011/05/23/default-sound-device-in-freebsd/ -        if (g_str_has_suffix (line, "default") || -            g_str_has_suffix (line, "default)")) -            ; - -        if (description != NULL) -            break; -    } - -    fclose (fp); -    return description; -} - -static void -add_device (Oss4Backend *oss, Oss4Device *device) -{ -    MateMixerStream *stream; - -    /* Add device, file path is used as the key rather than the name, because -     * the name is not known until an OssDevice instance is created */ -    g_hash_table_insert (oss->priv->devices, -                         GINT_TO_POINTER (oss4_device_get_index (device)), -                         g_object_ref (device)); - -    g_signal_emit_by_name (G_OBJECT (oss), -                           "device-added", -                           mate_mixer_device_get_name (MATE_MIXER_DEVICE (device))); - -    /* Add streams if they exist */ -    stream = oss4_device_get_input_stream (device); -    if (stream != NULL) { -        g_hash_table_insert (oss->priv->streams, -                             g_strdup (mate_mixer_stream_get_name (stream)), -                             g_object_ref (stream)); - -        g_signal_emit_by_name (G_OBJECT (oss), -                               "stream-added", -                               mate_mixer_stream_get_name (stream)); -    } - -    stream = oss4_device_get_output_stream (device); -    if (stream != NULL) { -        g_hash_table_insert (oss->priv->streams, -                             g_strdup (mate_mixer_stream_get_name (stream)), -                             g_object_ref (stream)); - -        g_signal_emit_by_name (G_OBJECT (oss), -                               "stream-added", -                               mate_mixer_stream_get_name (stream)); -    } -} - -static void -remove_device (Oss4Backend *oss, Oss4Device *device) -{ -    MateMixerStream *stream; - -    /* Remove the device streams first as they are a part of the device */ -    stream = oss4_device_get_input_stream (device); -    if (stream != NULL) { -        const gchar *name = mate_mixer_stream_get_name (stream); - -        g_hash_table_remove (oss->priv->streams, name); -        g_signal_emit_by_name (G_OBJECT (oss), -                               "stream-removed", -                               name); -    } - -    stream = oss4_device_get_output_stream (device); -    if (stream != NULL) { -        const gchar *name = mate_mixer_stream_get_name (stream); - -        g_hash_table_remove (oss->priv->streams, stream); -        g_signal_emit_by_name (G_OBJECT (oss), -                               "stream-removed", -                               name); -    } - -    /* Remove the device */ -    g_object_ref (device); - -    g_hash_table_remove (oss->priv->devices, -                         GINT_TO_POINTER (oss4_device_get_index (device))); - -    g_signal_emit_by_name (G_OBJECT (oss), -                           "device-removed", -                           mate_mixer_device_get_name (MATE_MIXER_DEVICE (device))); - -    g_object_unref (device); -} diff --git a/backends/oss4/oss4-backend.h b/backends/oss4/oss4-backend.h deleted file mode 100644 index bc89e72..0000000 --- a/backends/oss4/oss4-backend.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (C) 2014 Michal Ratajsky <[email protected]> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the licence, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/>. - */ - -#ifndef OSS4_BACKEND_H -#define OSS4_BACKEND_H - -#include <glib.h> -#include <glib-object.h> - -#include <libmatemixer/matemixer-backend-module.h> - -#define OSS4_TYPE_BACKEND                       \ -        (oss4_backend_get_type ()) -#define OSS4_BACKEND(o)                         \ -        (G_TYPE_CHECK_INSTANCE_CAST ((o), OSS4_TYPE_BACKEND, Oss4Backend)) -#define OSS4_IS_BACKEND(o)                      \ -        (G_TYPE_CHECK_INSTANCE_TYPE ((o), OSS4_TYPE_BACKEND)) -#define OSS4_BACKEND_CLASS(k)                   \ -        (G_TYPE_CHECK_CLASS_CAST ((k), OSS4_TYPE_BACKEND, Oss4BackendClass)) -#define OSS4_IS_BACKEND_CLASS(k)                \ -        (G_TYPE_CHECK_CLASS_TYPE ((k), OSS4_TYPE_BACKEND)) -#define OSS4_BACKEND_GET_CLASS(o)               \ -        (G_TYPE_INSTANCE_GET_CLASS ((o), OSS4_TYPE_BACKEND, Oss4BackendClass)) - -typedef struct _Oss4Backend         Oss4Backend; -typedef struct _Oss4BackendClass    Oss4BackendClass; -typedef struct _Oss4BackendPrivate  Oss4BackendPrivate; - -struct _Oss4Backend -{ -    GObject parent; - -    /*< private >*/ -    Oss4BackendPrivate *priv; -}; - -struct _Oss4BackendClass -{ -    GObjectClass parent_class; -}; - -GType                       oss4_backend_get_type   (void) G_GNUC_CONST; - -/* Support function for dynamic loading of the backend module */ -void                        backend_module_init     (GTypeModule *module); -const MateMixerBackendInfo *backend_module_get_info (void); - -#endif /* OSS4_BACKEND_H */ diff --git a/backends/oss4/oss4-device.c b/backends/oss4/oss4-device.c deleted file mode 100644 index b68648b..0000000 --- a/backends/oss4/oss4-device.c +++ /dev/null @@ -1,328 +0,0 @@ -/* - * Copyright (C) 2014 Michal Ratajsky <[email protected]> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the licence, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/>. - */ - -#include <errno.h> -#include <unistd.h> -#include <glib.h> -#include <glib/gi18n.h> -#include <glib/gstdio.h> -#include <glib-object.h> - -#include <libmatemixer/matemixer-device.h> -#include <libmatemixer/matemixer-enums.h> -#include <libmatemixer/matemixer-port.h> -#include <libmatemixer/matemixer-port-private.h> -#include <libmatemixer/matemixer-stream.h> -#include <libmatemixer/matemixer-stream-control.h> - -#include "oss4-common.h" -#include "oss4-device.h" - -#define OSS4_DEVICE_ICON "audio-card" - -struct _Oss4DevicePrivate -{ -    gint             fd; -    gint             index; -    gchar           *name; -    gchar           *description; -    gchar           *icon; -    MateMixerStream *input; -    MateMixerStream *output; -}; - -enum { -    PROP_0, -    PROP_NAME, -    PROP_DESCRIPTION, -    PROP_ICON, -    PROP_ACTIVE_PROFILE, -    PROP_FD, -    PROP_INDEX -}; - -static void mate_mixer_device_interface_init (MateMixerDeviceInterface *iface); - -static void oss4_device_class_init   (Oss4DeviceClass *klass); - -static void oss4_device_get_property (GObject        *object, -                                      guint           param_id, -                                      GValue         *value, -                                      GParamSpec     *pspec); -static void oss4_device_set_property (GObject        *object, -                                      guint           param_id, -                                      const GValue   *value, -                                      GParamSpec     *pspec); - -static void oss4_device_init         (Oss4Device     *device); -static void oss4_device_finalize     (GObject        *object); - -G_DEFINE_TYPE_WITH_CODE (Oss4Device, oss4_device, G_TYPE_OBJECT, -                         G_IMPLEMENT_INTERFACE (MATE_MIXER_TYPE_DEVICE, -                                                mate_mixer_device_interface_init)) - -static const gchar *oss4_device_get_name        (MateMixerDevice *device); -static const gchar *oss4_device_get_description (MateMixerDevice *device); -static const gchar *oss4_device_get_icon        (MateMixerDevice *device); - -static gboolean     read_mixer_devices          (Oss4Device      *device); - -static void -mate_mixer_device_interface_init (MateMixerDeviceInterface *iface) -{ -    iface->get_name        = oss4_device_get_name; -    iface->get_description = oss4_device_get_description; -    iface->get_icon        = oss4_device_get_icon; -} - -static void -oss4_device_class_init (Oss4DeviceClass *klass) -{ -    GObjectClass *object_class; - -    object_class = G_OBJECT_CLASS (klass); -    object_class->finalize     = oss4_device_finalize; -    object_class->get_property = oss4_device_get_property; -    object_class->set_property = oss4_device_set_property; - -    g_object_class_install_property (object_class, -                                     PROP_FD, -                                     g_param_spec_int ("fd", -                                                       "File descriptor", -                                                       "File descriptor of the device", -                                                       G_MININT, -                                                       G_MAXINT, -                                                       -1, -                                                       G_PARAM_CONSTRUCT_ONLY | -                                                       G_PARAM_READWRITE | -                                                       G_PARAM_STATIC_STRINGS)); - -    g_object_class_install_property (object_class, -                                     PROP_INDEX, -                                     g_param_spec_int ("index", -                                                       "Index", -                                                       "Index of the device", -                                                       G_MININT, -                                                       G_MAXINT, -                                                       0, -                                                       G_PARAM_CONSTRUCT_ONLY | -                                                       G_PARAM_READWRITE | -                                                       G_PARAM_STATIC_STRINGS)); - -    g_object_class_override_property (object_class, PROP_NAME, "name"); -    g_object_class_override_property (object_class, PROP_DESCRIPTION, "description"); -    g_object_class_override_property (object_class, PROP_ICON, "icon"); -    g_object_class_override_property (object_class, PROP_ACTIVE_PROFILE, "active-profile"); - -    g_type_class_add_private (object_class, sizeof (Oss4DevicePrivate)); -} - -static void -oss4_device_get_property (GObject    *object, -                         guint       param_id, -                         GValue     *value, -                         GParamSpec *pspec) -{ -    Oss4Device *device; - -    device = OSS4_DEVICE (object); - -    switch (param_id) { -    case PROP_NAME: -        g_value_set_string (value, device->priv->name); -        break; -    case PROP_DESCRIPTION: -        g_value_set_string (value, device->priv->description); -        break; -    case PROP_ICON: -        g_value_set_string (value, OSS4_DEVICE_ICON); -        break; -    case PROP_ACTIVE_PROFILE: -        /* Not supported */ -        g_value_set_object (value, NULL); -        break; -    case PROP_FD: -        g_value_set_int (value, device->priv->fd); -        break; -    case PROP_INDEX: -        g_value_set_int (value, device->priv->index); -        break; -    default: -        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); -        break; -    } -} - -static void -oss4_device_set_property (GObject      *object, -                         guint         param_id, -                         const GValue *value, -                         GParamSpec   *pspec) -{ -    Oss4Device *device; - -    device = OSS4_DEVICE (object); - -    switch (param_id) { -    case PROP_NAME: -        /* Construct-only string */ -        device->priv->name = g_strdup (g_value_get_string (value)); -        break; -    case PROP_DESCRIPTION: -        /* Construct-only string */ -        device->priv->description = g_strdup (g_value_get_string (value)); -        break; -    case PROP_ICON: -        /* Construct-only string */ -        device->priv->icon = g_strdup (g_value_get_string (value)); -        break; -    case PROP_FD: -        device->priv->fd = dup (g_value_get_int (value)); -        break; -    case PROP_INDEX: -        device->priv->index = g_value_get_int (value); -        break; -    default: -        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); -        break; -    } -} - -static void -oss4_device_init (Oss4Device *device) -{ -    device->priv = G_TYPE_INSTANCE_GET_PRIVATE (device, -                                                OSS4_TYPE_DEVICE, -                                                Oss4DevicePrivate); -} - -static void -oss4_device_finalize (GObject *object) -{ -    Oss4Device *device; - -    device = OSS4_DEVICE (object); - -    g_free (device->priv->name); -    g_free (device->priv->description); - -    if (device->priv->fd != -1) -        g_close (device->priv->fd, NULL); - -    G_OBJECT_CLASS (oss4_device_parent_class)->finalize (object); -} - -Oss4Device * -oss4_device_new (const gchar *name, -                 const gchar *description, -                 gint         fd, -                 gint         index) -{ -    Oss4Device *device; - -    device = g_object_new (OSS4_TYPE_DEVICE, -                           "name", name, -                           "description", description, -                           "fd", fd, -                           "index", index, -                           NULL); - -    return device; -} - -gboolean -oss4_device_read (Oss4Device *odevice) -{ -    gint exts; -    gint ret; -    gint i; - -    ret = ioctl (odevice->priv->fd, SNDCTL_MIX_NREXT, &exts); -    if (ret == -1) -        return FALSE; - -    for (i = 0; i < exts; i++) { -        oss_mixext ext; - -        ext.dev  = odevice->priv->index; -        ext.ctrl = i; -        ret = ioctl (odevice->priv->fd, SNDCTL_MIX_EXTINFO, &ext); -        if (ret == -1) -            continue; - -        g_debug ("Mixer control %d type %d\n" -                 " min %d max %d\n" -                 " id %s\n" -                 " extname %s", -                 i,ext.type, ext.minvalue, ext.maxvalue, ext.id, ext.extname); -    } - -    return TRUE; -} - -gint -oss4_device_get_index (Oss4Device *odevice) -{ -    g_return_val_if_fail (OSS4_IS_DEVICE (odevice), FALSE); - -    return odevice->priv->index; -} - -MateMixerStream * -oss4_device_get_input_stream (Oss4Device *odevice) -{ -    g_return_val_if_fail (OSS4_IS_DEVICE (odevice), FALSE); - -    return odevice->priv->input; -} - -MateMixerStream * -oss4_device_get_output_stream (Oss4Device *odevice) -{ -    g_return_val_if_fail (OSS4_IS_DEVICE (odevice), FALSE); - -    return odevice->priv->output; -} - -static gboolean -read_mixer_devices (Oss4Device *device) -{ -} - -static const gchar * -oss4_device_get_name (MateMixerDevice *device) -{ -    g_return_val_if_fail (OSS4_IS_DEVICE (device), NULL); - -    return OSS4_DEVICE (device)->priv->name; -} - -static const gchar * -oss4_device_get_description (MateMixerDevice *device) -{ -    g_return_val_if_fail (OSS4_IS_DEVICE (device), NULL); - -    return OSS4_DEVICE (device)->priv->description; -} - -static const gchar * -oss4_device_get_icon (MateMixerDevice *device) -{ -    g_return_val_if_fail (OSS4_IS_DEVICE (device), NULL); - -    return OSS4_DEVICE_ICON; -} diff --git a/backends/oss4/oss4-device.h b/backends/oss4/oss4-device.h deleted file mode 100644 index 3ec72e7..0000000 --- a/backends/oss4/oss4-device.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (C) 2014 Michal Ratajsky <[email protected]> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the licence, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/>. - */ - -#ifndef OSS4_DEVICE_H -#define OSS4_DEVICE_H - -#include <glib.h> -#include <glib-object.h> - -G_BEGIN_DECLS - -#define OSS4_TYPE_DEVICE                        \ -        (oss4_device_get_type ()) -#define OSS4_DEVICE(o)                          \ -        (G_TYPE_CHECK_INSTANCE_CAST ((o), OSS4_TYPE_DEVICE, Oss4Device)) -#define OSS4_IS_DEVICE(o)                       \ -        (G_TYPE_CHECK_INSTANCE_TYPE ((o), OSS4_TYPE_DEVICE)) -#define OSS4_DEVICE_CLASS(k)                    \ -        (G_TYPE_CHECK_CLASS_CAST ((k), OSS4_TYPE_DEVICE, Oss4DeviceClass)) -#define OSS4_IS_DEVICE_CLASS(k)                 \ -        (G_TYPE_CHECK_CLASS_TYPE ((k), OSS4_TYPE_DEVICE)) -#define OSS4_DEVICE_GET_CLASS(o)                \ -        (G_TYPE_INSTANCE_GET_CLASS ((o), OSS4_TYPE_DEVICE, Oss4DeviceClass)) - -typedef struct _Oss4Device         Oss4Device; -typedef struct _Oss4DeviceClass    Oss4DeviceClass; -typedef struct _Oss4DevicePrivate  Oss4DevicePrivate; - -struct _Oss4Device -{ -    GObject parent; - -    /*< private >*/ -    Oss4DevicePrivate *priv; -}; - -struct _Oss4DeviceClass -{ -    GObjectClass parent; -}; - -GType            oss4_device_get_type          (void) G_GNUC_CONST; - -Oss4Device *     oss4_device_new (const gchar *name, -                                  const gchar *description, -                                  gint         fd, -                                  gint         index); - -gboolean         oss4_device_read              (Oss4Device   *device); - -gint             oss4_device_get_index         (Oss4Device *odevice); - -MateMixerStream *oss4_device_get_input_stream  (Oss4Device   *odevice); -MateMixerStream *oss4_device_get_output_stream (Oss4Device   *odevice); - -G_END_DECLS - -#endif /* OSS_DEVICE_H */ diff --git a/configure.ac b/configure.ac index b618913..d376b19 100644 --- a/configure.ac +++ b/configure.ac @@ -61,13 +61,12 @@ LT_INIT  # =======================================================================  PKG_PROG_PKG_CONFIG -GLIB_REQUIRED_VERSION=2.36.0 +GLIB_REQUIRED_VERSION=2.32.0  PKG_CHECK_MODULES(GLIB, [          glib-2.0 >= $GLIB_REQUIRED_VERSION          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]) @@ -120,6 +119,39 @@ AC_SUBST(PULSEAUDIO_CFLAGS)  AC_SUBST(PULSEAUDIO_LIBS)  # ----------------------------------------------------------------------- +# ALSA +# ----------------------------------------------------------------------- +ALSA_REQUIRED_VERSION=1.0.0 + +AC_ARG_ENABLE([alsa], +              AS_HELP_STRING([--enable-alsa], +                             [Enable ALSA backend module @<:@default=auto@:>@]), +              enable_alsa=$enableval, enable_alsa=auto) + +if test "x$enable_alsa" != "xno"; then +  PKG_CHECK_MODULES(ALSA, [ +        alsa >= $ALSA_REQUIRED_VERSION +        gthread-2.0 >= $GLIB_REQUIRED_VERSION +        ], +        have_alsa=yes, +        have_alsa=no) + +  if test "x$enable_alsa" = "xyes" -a "x$have_alsa" = "xno"; then +    AC_MSG_ERROR([ALSA support explicitly requested but dependencies not found]) +  fi + +  if test "x$have_alsa" = "xyes" ; then +    AC_DEFINE(HAVE_ALSA, [], [Define if we have ALSA support]) +  fi +fi + +AM_CONDITIONAL(HAVE_ALSA, test "x$have_alsa" = "xyes") + +AC_SUBST(HAVE_ALSA) +AC_SUBST(ALSA_CFLAGS) +AC_SUBST(ALSA_LIBS) + +# -----------------------------------------------------------------------  # OSS  # -----------------------------------------------------------------------  AC_ARG_ENABLE([oss], @@ -155,40 +187,6 @@ AC_SUBST(HAVE_OSS)  AC_SUBST(OSS_CFLAGS)  AC_SUBST(OSS_LIBS) -# ----------------------------------------------------------------------- -# OSS4 -# ----------------------------------------------------------------------- -AC_ARG_ENABLE([oss4], -              AS_HELP_STRING([--enable-oss4], -                             [Enable OSS4 backend module @<:@default=no@:>@]), -              enable_oss4=$enableval, enable_oss4=no) - -if test "x$enable_oss4" != "xno"; then -  AC_CHECK_HEADERS([soundcard.h sys/soundcard.h machine/soundcard.h]) -  if test "x$ac_cv_header_soundcard_h" = "xyes" -o \ -          "x$ac_cv_header_sys_soundcard_h" = "xyes" -o \ -          "x$ac_cv_header_machine_soundcard_h" = "xyes"; then -    have_oss4=yes -  else -    have_oss4=no -  fi - -  if test "x$enable_oss4" = "xyes" -a "x$have_oss4" = "xno"; then -    AC_MSG_ERROR([OSS4 support explicitly requested but dependencies not found]) -  fi - -  if test "x$have_oss4" = "xyes" ; then -    AC_DEFINE(HAVE_OSS4, [], [Define if we have OSS support]) -  fi -else -  have_oss4=no -fi - -AM_CONDITIONAL(HAVE_OSS4, test "x$have_oss4" = "xyes") - -AC_SUBST(HAVE_OSS4) -AC_SUBST(OSS4_CFLAGS) -  # =======================================================================  # Compiler warnings  # ======================================================================= @@ -240,9 +238,9 @@ Makefile  libmatemixer/Makefile  backends/Makefile  backends/null/Makefile -backends/oss/Makefile -backends/oss4/Makefile  backends/pulse/Makefile +backends/alsa/Makefile +backends/oss/Makefile  data/Makefile  data/libmatemixer.pc  docs/Makefile @@ -266,7 +264,7 @@ echo "          Build Null module:           $have_null          Build PulseAudio module:     $have_pulseaudio +        Build ALSA module:           $have_alsa          Build OSS module:            $have_oss -        Build OSS4 module:           $have_oss4  " diff --git a/examples/monitor.c b/examples/monitor.c index dca5105..71d8b61 100644 --- a/examples/monitor.c +++ b/examples/monitor.c @@ -26,7 +26,7 @@  #include <libmatemixer/matemixer.h> -static MateMixerControl *control; +static MateMixerContext *context;  static GMainLoop *mainloop;  static gchar * @@ -57,6 +57,30 @@ create_app_string (const gchar *app_name,  }  static const gchar * +get_stream_control_role_string (MateMixerStreamControlRole role) +{ +    switch (role) { +    case MATE_MIXER_STREAM_CONTROL_ROLE_UNKNOWN: +        return "Unknown"; +    case MATE_MIXER_STREAM_CONTROL_ROLE_MASTER: +        return "Master"; +    case MATE_MIXER_STREAM_CONTROL_ROLE_PCM: +        return "PCM"; +    case MATE_MIXER_STREAM_CONTROL_ROLE_BASS: +        return "Bass"; +    case MATE_MIXER_STREAM_CONTROL_ROLE_TREBLE: +        return "Treble"; +    case MATE_MIXER_STREAM_CONTROL_ROLE_CD: +        return "CD"; +    case MATE_MIXER_STREAM_CONTROL_ROLE_SPEAKER: +        return "PC Speaker"; +    case MATE_MIXER_STREAM_CONTROL_ROLE_PORT: +        return "Port"; +    } +    return "Unknown"; +} + +static const gchar *  create_role_string (MateMixerClientStreamRole role)  {      switch (role) { @@ -122,39 +146,21 @@ static void  print_devices (void)  {      const GList            *devices; -    const GList            *ports;      const GList            *profiles;      MateMixerDeviceProfile *active_profile; -    devices = mate_mixer_control_list_devices (control); +    devices = mate_mixer_context_list_devices (context);      while (devices) {          MateMixerDevice *device = MATE_MIXER_DEVICE (devices->data);          g_print ("Device %s\n" -                 "       |-| Description : %s\n" -                 "       |-| Icon Name   : %s\n\n", +                 "       |-| Label     : %s\n" +                 "       |-| Icon Name : %s\n\n",                   mate_mixer_device_get_name (device), -                 mate_mixer_device_get_description (device), +                 mate_mixer_device_get_label (device),                   mate_mixer_device_get_icon (device)); -        ports = mate_mixer_device_list_ports (device); -        while (ports) { -            MateMixerPort *port = MATE_MIXER_PORT (ports->data); - -            g_print ("       |-| Port %s\n" -                     "                |-| Description : %s\n" -                     "                |-| Icon Name   : %s\n" -                     "                |-| Priority    : %u\n" -                     "                |-| Status      : \n\n", -                     mate_mixer_port_get_name (port), -                     mate_mixer_port_get_description (port), -                     mate_mixer_port_get_icon (port), -                     mate_mixer_port_get_priority (port)); - -            ports = ports->next; -        } -          profiles = mate_mixer_device_list_profiles (device);          active_profile = mate_mixer_device_get_active_profile (device); @@ -162,15 +168,15 @@ print_devices (void)              MateMixerDeviceProfile *profile = MATE_MIXER_DEVICE_PROFILE (profiles->data);              g_print ("       |%c| Profile %s\n" -                     "                |-| Description : %s\n" -                     "                |-| Priority    : %u\n" -                     "                |-| Inputs      : %u\n" -                     "                |-| Outputs     : %u\n\n", +                     "                |-| Label    : %s\n" +                     "                |-| Priority : %u\n" +                     "                |-| Inputs   : %u\n" +                     "                |-| Outputs  : %u\n\n",                       (profile == active_profile)                          ? 'A'                          : '-',                       mate_mixer_device_profile_get_name (profile), -                     mate_mixer_device_profile_get_description (profile), +                     mate_mixer_device_profile_get_label (profile),                       mate_mixer_device_profile_get_priority (profile),                       mate_mixer_device_profile_get_num_input_streams (profile),                       mate_mixer_device_profile_get_num_output_streams (profile)); @@ -179,6 +185,35 @@ print_devices (void)          }          g_print ("\n"); +        const GList *switches = mate_mixer_device_list_switches (device); + +        while (switches != NULL) { +            MateMixerSwitch *swtch = MATE_MIXER_SWITCH (switches->data); +            MateMixerSwitchOption *active = mate_mixer_switch_get_active_option (swtch); + +            const GList *options; + +            options = mate_mixer_switch_list_options (swtch); + +            g_print ("Switch %s\n", +                     mate_mixer_switch_get_name (swtch)); + +            while (options != NULL) { +                MateMixerSwitchOption *option = MATE_MIXER_SWITCH_OPTION (options->data); + +                g_print ("       |%c| %s\n", +                         (option == active) +                            ? '*' +                            : '-', +                         mate_mixer_switch_option_get_label (option)); + +                options = options->next; +            } + +            switches = switches->next; +        } +        g_print ("\n"); +          devices = devices->next;      }  } @@ -187,42 +222,85 @@ static void  print_streams (void)  {      const GList *streams; -    const GList *ports; -    streams = mate_mixer_control_list_streams (control); +    streams = mate_mixer_context_list_streams (context);      while (streams) {          MateMixerStream        *stream = MATE_MIXER_STREAM (streams->data);          MateMixerStreamControl *ctl; +        MateMixerSwitch        *swtch;          MateMixerClientStream  *client = NULL;          gchar                  *volume_bar;          gdouble                 volume; +        const GList *controls; +        const GList *switches; +          if (mate_mixer_stream_get_flags (stream) & MATE_MIXER_STREAM_CLIENT) {              /* The application-specific details are accessible through the client               * interface, which all client streams implement */              client = MATE_MIXER_CLIENT_STREAM (stream);          } -        ctl = mate_mixer_stream_get_default_control (stream); +        controls = mate_mixer_stream_list_controls (stream); -        volume_bar = create_volume_bar (ctl, &volume); +        while (controls != NULL) { +            ctl = MATE_MIXER_STREAM_CONTROL (controls->data); -        g_print ("Stream %s\n" -                 "       |-| Description : %s\n" -                 "       |-| Volume      : %s %.1f %%\n" -                 "       |-| Muted       : %s\n" -                 "       |-| Channels    : %d\n" -                 "       |-| Balance     : %.1f\n" -                 "       |-| Fade        : %.1f\n", -                 mate_mixer_stream_get_name (stream), -                 mate_mixer_stream_get_description (stream), -                 volume_bar, -                 volume, -                 mate_mixer_stream_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)); +            const gchar *role; + +            role = get_stream_control_role_string (mate_mixer_stream_control_get_role (ctl)); + +            // XXX volume is sometimes -nan, use flags +            volume_bar = create_volume_bar (ctl, &volume); + +            g_print ("Stream %s control %s / %s\n" +                     "       |-| Volume      : %s %.1f %% (%.1f dB)\n" +                     "       |-| Muted       : %s\n" +                     "       |-| Channels    : %d\n" +                     "       |-| Balance     : %.1f\n" +                     "       |-| Fade        : %.1f\n" +                     "       |-| Role        : %s\n", +                     mate_mixer_stream_get_name (stream), +                     mate_mixer_stream_control_get_name (ctl), +                     mate_mixer_stream_control_get_label (ctl), +                     volume_bar, +                     volume, +                     mate_mixer_stream_control_get_decibel (ctl), +                     mate_mixer_stream_control_get_mute (ctl) ? "Yes" : "No", +                     mate_mixer_stream_control_get_num_channels (ctl), +                     mate_mixer_stream_control_get_balance (ctl), +                     mate_mixer_stream_control_get_fade (ctl), +                     role); + +            g_free (volume_bar); + +            controls = controls->next; +        } + +        switches = mate_mixer_stream_list_switches (stream); + +        while (switches != NULL) { +            swtch = MATE_MIXER_SWITCH (switches->data); +            const GList *options; + +            options = mate_mixer_switch_list_options (swtch); + +            g_print ("Switch %s\n", +                     mate_mixer_switch_get_name (swtch)); + +            while (options != NULL) { +                MateMixerSwitchOption *option = MATE_MIXER_SWITCH_OPTION (options->data); + +                g_print ("       |%c| %s\n", +                         '-', +                         mate_mixer_switch_option_get_label (option)); + +                options = options->next; +            } + +            options = options->next; +        }          if (client != NULL) {              MateMixerClientStreamFlags client_flags; @@ -240,35 +318,17 @@ print_streams (void)          }          g_print ("\n"); -        g_free (volume_bar); - -        ports = mate_mixer_stream_list_ports (stream); -        while (ports) { -            MateMixerPort *port = MATE_MIXER_PORT (ports->data); - -            g_print ("       |-| Port %s\n" -                     "                |-| Description : %s\n" -                     "                |-| Icon Name   : %s\n" -                     "                |-| Priority    : %u\n" -                     "                |-| Status      : \n\n", -                     mate_mixer_port_get_name (port), -                     mate_mixer_port_get_description (port), -                     mate_mixer_port_get_icon (port), -                     mate_mixer_port_get_priority (port)); - -            ports = ports->next; -        }          streams = streams->next;      }  }  static void -print_cached_streams (void) +print_stored_streams (void)  {      const GList *streams; -    streams = mate_mixer_control_list_cached_streams (control); +    streams = mate_mixer_context_list_stored_streams (context);      while (streams) {          MateMixerStream           *stream = MATE_MIXER_STREAM (streams->data); @@ -287,7 +347,7 @@ print_cached_streams (void)          volume_bar = create_volume_bar (ctl, &volume); -        g_print ("Cached stream %s\n" +        g_print ("Stored stream %s\n"                   "       |-| Role        : %s\n"                   "       |-| Volume      : %s %.1f %%\n"                   "       |-| Muted       : %s\n" @@ -323,11 +383,11 @@ static void  connected (void)  {      g_print ("Connected using the %s backend.\n\n", -             mate_mixer_control_get_backend_name (control)); +             mate_mixer_context_get_backend_name (context));      print_devices ();      print_streams (); -    print_cached_streams (); +    print_stored_streams ();      g_print ("Waiting for events. Hit CTRL+C to quit.\n");  } @@ -337,7 +397,7 @@ state_cb (void)  {      MateMixerState state; -    state = mate_mixer_control_get_state (control); +    state = mate_mixer_context_get_state (context);      switch (state) {      case MATE_MIXER_STATE_READY: @@ -353,25 +413,25 @@ state_cb (void)  }  static void -device_added_cb (MateMixerControl *control, const gchar *name) +device_added_cb (MateMixerContext *context, const gchar *name)  {      g_print ("Device added: %s\n", name);  }  static void -device_removed_cb (MateMixerControl *control, const gchar *name) +device_removed_cb (MateMixerContext *context, const gchar *name)  {      g_print ("Device removed: %s\n", name);  }  static void -stream_added_cb (MateMixerControl *control, const gchar *name) +stream_added_cb (MateMixerContext *context, const gchar *name)  {      g_print ("Stream added: %s\n", name);  }  static void -stream_removed_cb (MateMixerControl *control, const gchar *name) +stream_removed_cb (MateMixerContext *context, const gchar *name)  {      g_print ("Stream removed: %s\n", name);  } @@ -388,22 +448,22 @@ signal_cb (gpointer mainloop)  int main (int argc, char *argv[])  {      MateMixerState  state; -    GOptionContext *context; +    GOptionContext *ctx;      gchar          *backend = NULL;      gchar          *server = NULL;      GError         *error = NULL;      GOptionEntry    entries[] = { -        { "backend", 'b', 0, G_OPTION_ARG_STRING, &backend, "Sound system to use (pulseaudio, oss, oss4, null)", NULL }, +        { "backend", 'b', 0, G_OPTION_ARG_STRING, &backend, "Sound system to use (pulseaudio, alsa, oss, null)", NULL },          { "server",  's', 0, G_OPTION_ARG_STRING, &server,  "Sound server address", NULL },          { NULL }      }; -    context = g_option_context_new ("- libmatemixer monitor"); +    ctx = g_option_context_new ("- libmatemixer monitor"); -    g_option_context_add_main_entries (context, entries, NULL); +    g_option_context_add_main_entries (ctx, entries, NULL); -    if (!g_option_context_parse (context, &argc, &argv, &error)) { +    if (!g_option_context_parse (ctx, &argc, &argv, &error)) {          g_printerr ("%s\n", error->message);          g_error_free (error);          return 1; @@ -415,24 +475,24 @@ int main (int argc, char *argv[])      setlocale (LC_ALL, ""); -    /* Set up the controller, through which we access the main functionality */ -    control = mate_mixer_control_new (); +    /* Set up the contextler, through which we access the main functionality */ +    context = mate_mixer_context_new ();      /* Some details about our application, only used with the PulseAudio backend */ -    mate_mixer_control_set_app_name (control, "MateMixer Monitor"); -    mate_mixer_control_set_app_id (control, "org.mate-desktop.libmatemixer-monitor"); -    mate_mixer_control_set_app_version (control, "1.0"); -    mate_mixer_control_set_app_icon (control, "multimedia-volume-control"); +    mate_mixer_context_set_app_name (context, "MateMixer Monitor"); +    mate_mixer_context_set_app_id (context, "org.mate-desktop.libmatemixer-monitor"); +    mate_mixer_context_set_app_version (context, "1.0"); +    mate_mixer_context_set_app_icon (context, "multimedia-volume-context");      if (backend) {          if (!strcmp (backend, "pulseaudio")) -            mate_mixer_control_set_backend_type (control, MATE_MIXER_BACKEND_PULSEAUDIO); +            mate_mixer_context_set_backend_type (context, MATE_MIXER_BACKEND_PULSEAUDIO); +        else if (!strcmp (backend, "alsa")) +            mate_mixer_context_set_backend_type (context, MATE_MIXER_BACKEND_ALSA);          else if (!strcmp (backend, "oss")) -            mate_mixer_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); +            mate_mixer_context_set_backend_type (context, MATE_MIXER_BACKEND_OSS);          else if (!strcmp (backend, "null")) -            mate_mixer_control_set_backend_type (control, MATE_MIXER_BACKEND_NULL); +            mate_mixer_context_set_backend_type (context, MATE_MIXER_BACKEND_NULL);          else              g_printerr ("Sound system backend '%s' is unknown, it will be auto-detected.\n",                          backend); @@ -441,40 +501,39 @@ int main (int argc, char *argv[])      }      if (server) { -        mate_mixer_control_set_server_address (control, server); +        mate_mixer_context_set_server_address (context, server);          g_free (server);      }      /* Initiate connection to the sound server */ -    if (!mate_mixer_control_open (control)) { -        g_object_unref (control); -        mate_mixer_deinit (); +    if (!mate_mixer_context_open (context)) { +        g_object_unref (context);          return 1;      } -    g_signal_connect (G_OBJECT (control), +    g_signal_connect (G_OBJECT (context),                        "device-added",                        G_CALLBACK (device_added_cb),                        NULL); -    g_signal_connect (G_OBJECT (control), +    g_signal_connect (G_OBJECT (context),                        "device-removed",                        G_CALLBACK (device_removed_cb),                        NULL); -    g_signal_connect (G_OBJECT (control), +    g_signal_connect (G_OBJECT (context),                        "stream-added",                        G_CALLBACK (stream_added_cb),                        NULL); -    g_signal_connect (G_OBJECT (control), +    g_signal_connect (G_OBJECT (context),                        "stream-removed",                        G_CALLBACK (stream_removed_cb),                        NULL); -    /* If mate_mixer_control_open() returns TRUE, the state will be either +    /* If mate_mixer_context_open() returns TRUE, the state will be either       * MATE_MIXER_STATE_READY or MATE_MIXER_STATE_CONNECTING.       * -     * In case mate_mixer_control_open() returned FALSE, the current state +     * In case mate_mixer_context_open() returned FALSE, the current state       * would be MATE_MIXER_STATE_FAILED */ -    state = mate_mixer_control_get_state (control); +    state = mate_mixer_context_get_state (context);      switch (state) {      case MATE_MIXER_STATE_READY: @@ -484,7 +543,7 @@ int main (int argc, char *argv[])          g_print ("Waiting for connection...\n");          /* Wait for the state transition */ -        g_signal_connect (control, +        g_signal_connect (context,                            "notify::state",                            G_CALLBACK (state_cb),                            NULL); @@ -503,8 +562,7 @@ int main (int argc, char *argv[])      g_main_loop_run (mainloop); -    g_object_unref (control); -    mate_mixer_deinit (); +    g_object_unref (context);      return 0;  } diff --git a/libmatemixer/Makefile.am b/libmatemixer/Makefile.am index 9666684..8858b90 100644 --- a/libmatemixer/Makefile.am +++ b/libmatemixer/Makefile.am @@ -11,13 +11,16 @@ libmatemixer_includedir = $(includedir)/libmatemixer  libmatemixer_include_HEADERS =                                  \          matemixer.h                                             \          matemixer-client-stream.h                               \ -        matemixer-control.h                                     \ +        matemixer-context.h                                     \          matemixer-device.h                                      \          matemixer-device-profile.h                              \          matemixer-enums.h                                       \ -        matemixer-port.h                                        \          matemixer-stream.h                                      \          matemixer-stream-control.h                              \ +        matemixer-switch.h                                      \ +        matemixer-switch-option.h                               \ +        matemixer-toggle.h                                      \ +        matemixer-types.h                                       \          matemixer-version.h  libmatemixer_la_CFLAGS = $(GLIB_CFLAGS) @@ -27,19 +30,24 @@ libmatemixer_la_SOURCES =                                       \          matemixer-private.h                                     \          matemixer-backend.c                                     \          matemixer-backend.h                                     \ +        matemixer-backend-private.h                             \          matemixer-backend-module.c                              \          matemixer-backend-module.h                              \          matemixer-client-stream.c                               \ -        matemixer-control.c                                     \ +        matemixer-context.c                                     \          matemixer-device.c                                      \          matemixer-device-profile.c                              \          matemixer-device-profile-private.h                      \          matemixer-enum-types.c                                  \          matemixer-enum-types.h                                  \ -        matemixer-port.c                                        \ -        matemixer-port-private.h                                \          matemixer-stream.c                                      \ -        matemixer-stream-control.c +        matemixer-stream-control.c                              \ +        matemixer-stream-control-private.h                      \ +        matemixer-switch.c                                      \ +        matemixer-switch-private.h                              \ +        matemixer-switch-option.c                               \ +        matemixer-switch-option-private.h                       \ +        matemixer-toggle.c  libmatemixer_la_LIBADD = $(GLIB_LIBS) diff --git a/libmatemixer/matemixer-backend-module.c b/libmatemixer/matemixer-backend-module.c index a3146d2..0e7716e 100644 --- a/libmatemixer/matemixer-backend-module.c +++ b/libmatemixer/matemixer-backend-module.c @@ -22,16 +22,19 @@  #include "matemixer-backend.h"  #include "matemixer-backend-module.h" -struct _MateMixerBackendModulePrivate -{ -    GModule  *gmodule; -    gchar    *path; -    gboolean  loaded; +/* Initialize backend */ +typedef void (*BackendInit) (GTypeModule *type_module); -    void (*init)   (GTypeModule *type_module); -    void (*deinit) (void); +/* Return information about backend */ +typedef const MateMixerBackendInfo *(*BackendGetInfo) (void); -    const MateMixerBackendInfo *(*get_info) (void); +struct _MateMixerBackendModulePrivate +{ +    GModule       *gmodule; +    gchar         *path; +    gboolean       loaded; +    BackendInit    init; +    BackendGetInfo get_info;  };  enum { @@ -102,6 +105,7 @@ mate_mixer_backend_module_get_property (GObject    *object,      case PROP_PATH:          g_value_set_string (value, module->priv->path);          break; +      default:          G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);          break; @@ -122,7 +126,10 @@ mate_mixer_backend_module_set_property (GObject      *object,      case PROP_PATH:          /* Construct-only string */          module->priv->path = g_strdup (g_value_get_string (value)); + +        g_type_module_set_name (G_TYPE_MODULE (object), module->priv->path);          break; +      default:          G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);          break; @@ -157,8 +164,11 @@ mate_mixer_backend_module_dispose (GObject *object)  static void  mate_mixer_backend_module_finalize (GObject *object)  { -    /* This is in fact never called */ -    g_free (MATE_MIXER_BACKEND_MODULE (object)->priv->path); +    MateMixerBackendModule *module; + +    module = MATE_MIXER_BACKEND_MODULE (object); + +    g_free (module->priv->path);      G_OBJECT_CLASS (mate_mixer_backend_module_parent_class)->finalize (object);  } @@ -174,17 +184,11 @@ mate_mixer_backend_module_finalize (GObject *object)  MateMixerBackendModule *  mate_mixer_backend_module_new (const gchar *path)  { -    MateMixerBackendModule *module; -      g_return_val_if_fail (path != NULL, NULL); -    module = g_object_new (MATE_MIXER_TYPE_BACKEND_MODULE, -                           "path", path, -                           NULL); - -    g_type_module_set_name (G_TYPE_MODULE (module), path); - -    return module; +    return g_object_new (MATE_MIXER_TYPE_BACKEND_MODULE, +                         "path", path, +                         NULL);  }  /** @@ -227,76 +231,57 @@ backend_module_load (GTypeModule *type_module)      module = MATE_MIXER_BACKEND_MODULE (type_module); -    if (module->priv->loaded == FALSE) { -        module->priv->gmodule = g_module_open (module->priv->path, -                                               G_MODULE_BIND_LAZY | -                                               G_MODULE_BIND_LOCAL); -        if (module->priv->gmodule == NULL) { -            g_warning ("Failed to load backend module %s: %s", -                       module->priv->path, -                       g_module_error ()); - -            return FALSE; -        } - -        /* Validate library symbols that each backend module must provide */ -        if (g_module_symbol (module->priv->gmodule, -                             "backend_module_init", -                             (gpointer *) &module->priv->init) == FALSE || -            g_module_symbol (module->priv->gmodule, -                             "backend_module_get_info", -                             (gpointer *) &module->priv->get_info) == FALSE) { -            g_warning ("Failed to load backend module %s: %s", -                       module->priv->path, -                       g_module_error ()); - -            g_module_close (module->priv->gmodule); -            return FALSE; -        } - -        /* Optional backend function */ +    if (module->priv->loaded == TRUE) +        return TRUE; + +    module->priv->gmodule = g_module_open (module->priv->path, +                                           G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL); +    if (module->priv->gmodule == NULL) { +        g_warning ("Failed to load backend module %s: %s", +                   module->priv->path, +                   g_module_error ()); + +        return FALSE; +    } + +    /* Validate library symbols that each backend module must provide */ +    if (g_module_symbol (module->priv->gmodule, +                         "backend_module_init", +                         (gpointer *) &module->priv->init) == FALSE ||          g_module_symbol (module->priv->gmodule, -                         "backend_module_deinit", -                         (gpointer *) &module->priv->deinit); - -        module->priv->init (type_module); -        module->priv->loaded = TRUE; - -        /* Make sure get_info() returns something, so we can avoid checking it -         * in other parts of the library */ -        if (G_UNLIKELY (module->priv->get_info () == NULL)) { -            g_critical ("Backend module %s does not provide module information", -                        module->priv->path); - -            /* Close the module but keep the loaded flag to avoid unreffing -             * this instance as the GType has most likely been registered */ -            g_module_close (module->priv->gmodule); -            return FALSE; -        } - -        /* It is not possible to unref this instance, so let's avoid unloading -         * the module and just let the backend module (de)initialize when -         * (de)init functions are called repeatedly */ -        g_module_make_resident (module->priv->gmodule); - -        g_debug ("Loaded backend module %s", module->priv->path); -    } else { -        /* This function was called before, so avoid loading and initialize only */ -        module->priv->init (type_module); +                         "backend_module_get_info", +                         (gpointer *) &module->priv->get_info) == FALSE) { +        g_warning ("Failed to load backend module %s: %s", +                   module->priv->path, +                   g_module_error ()); + +        g_module_close (module->priv->gmodule); +        return FALSE; +    } + +    module->priv->init (type_module); +    module->priv->loaded = TRUE; + +    /* Make sure get_info() returns something, so we can avoid checking it +     * in other parts of the library */ +    if (G_UNLIKELY (module->priv->get_info () == NULL)) { +        g_critical ("Backend module %s does not provide module information", +                    module->priv->path); + +        /* Close the module but keep the loaded flag to avoid unreffing +         * this instance as the GType has most likely been registered */ +        g_module_close (module->priv->gmodule); +        return FALSE;      } +    /* It is not possible to unref this instance, so keep the module alive */ +    g_module_make_resident (module->priv->gmodule); + +    g_debug ("Loaded backend module %s", module->priv->path);      return TRUE;  }  static void  backend_module_unload (GTypeModule *type_module)  { -    MateMixerBackendModule *module; - -    module = MATE_MIXER_BACKEND_MODULE (type_module); - -    /* Only deinitialize the backend module, do not modify the loaded flag -     * as the module remains loaded */ -    if (module->priv->deinit) -        module->priv->deinit ();  } diff --git a/libmatemixer/matemixer-backend-module.h b/libmatemixer/matemixer-backend-module.h index 62b0a43..e1dfd8d 100644 --- a/libmatemixer/matemixer-backend-module.h +++ b/libmatemixer/matemixer-backend-module.h @@ -21,17 +21,10 @@  #include <glib.h>  #include <glib-object.h> -#include "matemixer-enums.h" +#include <libmatemixer/matemixer-enums.h>  G_BEGIN_DECLS -typedef struct { -    gchar                *name; -    guint                 priority; -    GType                 g_type; -    MateMixerBackendType  backend_type; -} MateMixerBackendInfo; -  #define MATE_MIXER_TYPE_BACKEND_MODULE          \          (mate_mixer_backend_module_get_type ())  #define MATE_MIXER_BACKEND_MODULE(o)            \ @@ -45,6 +38,7 @@ typedef struct {  #define MATE_MIXER_BACKEND_MODULE_GET_CLASS(o)  \          (G_TYPE_INSTANCE_GET_CLASS ((o), MATE_MIXER_TYPE_BACKEND_MODULE, MateMixerBackendModuleClass)) +typedef struct _MateMixerBackendInfo           MateMixerBackendInfo;  typedef struct _MateMixerBackendModule         MateMixerBackendModule;  typedef struct _MateMixerBackendModuleClass    MateMixerBackendModuleClass;  typedef struct _MateMixerBackendModulePrivate  MateMixerBackendModulePrivate; @@ -62,6 +56,14 @@ struct _MateMixerBackendModuleClass      GTypeModuleClass parent_class;  }; +struct _MateMixerBackendInfo +{ +    gchar                *name; +    guint                 priority; +    GType                 g_type; +    MateMixerBackendType  backend_type; +}; +  GType                       mate_mixer_backend_module_get_type (void) G_GNUC_CONST;  MateMixerBackendModule *    mate_mixer_backend_module_new      (const gchar            *path); diff --git a/libmatemixer/matemixer-backend-private.h b/libmatemixer/matemixer-backend-private.h new file mode 100644 index 0000000..b5de8ae --- /dev/null +++ b/libmatemixer/matemixer-backend-private.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2014 Michal Ratajsky <[email protected]> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the licence, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef MATEMIXER_BACKEND_PRIVATE_H +#define MATEMIXER_BACKEND_PRIVATE_H + +#include <glib.h> + +#include "matemixer-backend.h" +#include "matemixer-enums.h" +#include "matemixer-stream.h" + +G_BEGIN_DECLS + +void _mate_mixer_backend_set_state (MateMixerBackend *backend, +                                    MateMixerState    state); + +void _mate_mixer_backend_set_default_input_stream (MateMixerBackend *backend, +                                                   MateMixerStream  *stream); + +void _mate_mixer_backend_set_default_output_stream (MateMixerBackend *backend, +                                                    MateMixerStream  *stream); + +G_END_DECLS + +#endif /* MATEMIXER_BACKEND_PRIVATE_H */ diff --git a/libmatemixer/matemixer-backend.c b/libmatemixer/matemixer-backend.c index e070090..fab0883 100644 --- a/libmatemixer/matemixer-backend.c +++ b/libmatemixer/matemixer-backend.c @@ -15,61 +15,122 @@   * License along with this library; if not, see <http://www.gnu.org/licenses/>.   */ +#include <string.h>  #include <glib.h>  #include <glib-object.h>  #include "matemixer-backend.h" +#include "matemixer-backend-private.h"  #include "matemixer-enums.h"  #include "matemixer-enum-types.h"  #include "matemixer-stream.h" +struct _MateMixerBackendPrivate +{ +    GList                *devices; +    GList                *streams; +    GList                *stored_streams; +    MateMixerStream      *default_input; +    MateMixerStream      *default_output; +    MateMixerState        state; +    MateMixerBackendFlags flags; +}; + +enum { +    PROP_0, +    PROP_STATE, +    PROP_DEFAULT_INPUT_STREAM, +    PROP_DEFAULT_OUTPUT_STREAM, +    N_PROPERTIES +}; + +static GParamSpec *properties[N_PROPERTIES] = { NULL, }; +  enum {      DEVICE_ADDED,      DEVICE_REMOVED,      STREAM_ADDED,      STREAM_REMOVED, -    CACHED_STREAM_ADDED, -    CACHED_STREAM_REMOVED, +    STORED_STREAM_ADDED, +    STORED_STREAM_REMOVED,      N_SIGNALS  };  static guint signals[N_SIGNALS] = { 0, }; -G_DEFINE_INTERFACE (MateMixerBackend, mate_mixer_backend, G_TYPE_OBJECT) +static void mate_mixer_backend_class_init   (MateMixerBackendClass *klass); + +static void mate_mixer_backend_init         (MateMixerBackend      *backend); + +static void mate_mixer_backend_get_property (GObject               *object, +                                             guint                  param_id, +                                             GValue                *value, +                                             GParamSpec            *pspec); +static void mate_mixer_backend_set_property (GObject               *object, +                                             guint                  param_id, +                                             const GValue          *value, +                                             GParamSpec            *pspec); + +static void mate_mixer_backend_dispose      (GObject               *object); + +G_DEFINE_ABSTRACT_TYPE (MateMixerBackend, mate_mixer_backend, G_TYPE_OBJECT) + +static void device_added (MateMixerBackend *backend, const gchar *name); +static void device_removed (MateMixerBackend *backend, const gchar *name); + +static void device_stream_added   (MateMixerDevice *device, +                                   const gchar     *name); +static void device_stream_removed (MateMixerDevice *device, +                                   const gchar     *name); + +static void free_devices        (MateMixerBackend *backend); +static void free_streams        (MateMixerBackend *backend); +static void free_stored_streams (MateMixerBackend *backend); +static void stream_removed      (MateMixerBackend *backend, +                                 const gchar      *name);  static void -mate_mixer_backend_default_init (MateMixerBackendInterface *iface) +mate_mixer_backend_class_init (MateMixerBackendClass *klass)  { -    g_object_interface_install_property (iface, -                                         g_param_spec_enum ("state", -                                                            "State", -                                                            "Current backend connection state", -                                                            MATE_MIXER_TYPE_STATE, -                                                            MATE_MIXER_STATE_IDLE, -                                                            G_PARAM_READABLE | -                                                            G_PARAM_STATIC_STRINGS)); - -    g_object_interface_install_property (iface, -                                         g_param_spec_object ("default-input", -                                                              "Default input", -                                                              "Default input stream", -                                                              MATE_MIXER_TYPE_STREAM, -                                                              G_PARAM_READABLE | -                                                              G_PARAM_STATIC_STRINGS)); - -    g_object_interface_install_property (iface, -                                         g_param_spec_object ("default-output", -                                                              "Default output", -                                                              "Default output stream", -                                                              MATE_MIXER_TYPE_STREAM, -                                                              G_PARAM_READABLE | -                                                              G_PARAM_STATIC_STRINGS)); +    GObjectClass *object_class; + +    object_class = G_OBJECT_CLASS (klass); +    object_class->dispose      = mate_mixer_backend_dispose; +    object_class->get_property = mate_mixer_backend_get_property; +    object_class->set_property = mate_mixer_backend_set_property; + +    properties[PROP_STATE] = +        g_param_spec_enum ("state", +                           "State", +                           "Current backend connection state", +                           MATE_MIXER_TYPE_STATE, +                           MATE_MIXER_STATE_IDLE, +                           G_PARAM_READABLE | +                           G_PARAM_STATIC_STRINGS); + +    properties[PROP_DEFAULT_INPUT_STREAM] = +        g_param_spec_object ("default-input-stream", +                             "Default input stream", +                             "Default input stream", +                             MATE_MIXER_TYPE_STREAM, +                             G_PARAM_READABLE | +                             G_PARAM_STATIC_STRINGS); + +    properties[PROP_DEFAULT_OUTPUT_STREAM] = +        g_param_spec_object ("default-output-stream", +                             "Default output stream", +                             "Default output stream", +                             MATE_MIXER_TYPE_STREAM, +                             G_PARAM_READABLE | +                             G_PARAM_STATIC_STRINGS); + +    g_object_class_install_properties (object_class, N_PROPERTIES, properties);      signals[DEVICE_ADDED] =          g_signal_new ("device-added", -                      G_TYPE_FROM_INTERFACE (iface), +                      G_TYPE_FROM_CLASS (object_class),                        G_SIGNAL_RUN_LAST, -                      G_STRUCT_OFFSET (MateMixerBackendInterface, device_added), +                      G_STRUCT_OFFSET (MateMixerBackendClass, device_added),                        NULL,                        NULL,                        g_cclosure_marshal_VOID__STRING, @@ -79,9 +140,9 @@ mate_mixer_backend_default_init (MateMixerBackendInterface *iface)      signals[DEVICE_REMOVED] =          g_signal_new ("device-removed", -                      G_TYPE_FROM_INTERFACE (iface), +                      G_TYPE_FROM_CLASS (object_class),                        G_SIGNAL_RUN_LAST, -                      G_STRUCT_OFFSET (MateMixerBackendInterface, device_removed), +                      G_STRUCT_OFFSET (MateMixerBackendClass, device_removed),                        NULL,                        NULL,                        g_cclosure_marshal_VOID__STRING, @@ -91,9 +152,9 @@ mate_mixer_backend_default_init (MateMixerBackendInterface *iface)      signals[STREAM_ADDED] =          g_signal_new ("stream-added", -                      G_TYPE_FROM_INTERFACE (iface), +                      G_TYPE_FROM_CLASS (object_class),                        G_SIGNAL_RUN_LAST, -                      G_STRUCT_OFFSET (MateMixerBackendInterface, stream_added), +                      G_STRUCT_OFFSET (MateMixerBackendClass, stream_added),                        NULL,                        NULL,                        g_cclosure_marshal_VOID__STRING, @@ -103,9 +164,9 @@ mate_mixer_backend_default_init (MateMixerBackendInterface *iface)      signals[STREAM_REMOVED] =          g_signal_new ("stream-removed", -                      G_TYPE_FROM_INTERFACE (iface), +                      G_TYPE_FROM_CLASS (object_class),                        G_SIGNAL_RUN_LAST, -                      G_STRUCT_OFFSET (MateMixerBackendInterface, stream_removed), +                      G_STRUCT_OFFSET (MateMixerBackendClass, stream_removed),                        NULL,                        NULL,                        g_cclosure_marshal_VOID__STRING, @@ -113,11 +174,11 @@ mate_mixer_backend_default_init (MateMixerBackendInterface *iface)                        1,                        G_TYPE_STRING); -    signals[CACHED_STREAM_ADDED] = -        g_signal_new ("cached-stream-added", -                      G_TYPE_FROM_INTERFACE (iface), +    signals[STORED_STREAM_ADDED] = +        g_signal_new ("stored-stream-added", +                      G_TYPE_FROM_CLASS (object_class),                        G_SIGNAL_RUN_LAST, -                      G_STRUCT_OFFSET (MateMixerBackendInterface, cached_stream_added), +                      G_STRUCT_OFFSET (MateMixerBackendClass, stored_stream_added),                        NULL,                        NULL,                        g_cclosure_marshal_VOID__STRING, @@ -125,30 +186,149 @@ mate_mixer_backend_default_init (MateMixerBackendInterface *iface)                        1,                        G_TYPE_STRING); -    signals[CACHED_STREAM_REMOVED] = -        g_signal_new ("cached-stream-removed", -                      G_TYPE_FROM_INTERFACE (iface), +    signals[STORED_STREAM_REMOVED] = +        g_signal_new ("stored-stream-removed", +                      G_TYPE_FROM_CLASS (object_class),                        G_SIGNAL_RUN_LAST, -                      G_STRUCT_OFFSET (MateMixerBackendInterface, cached_stream_removed), +                      G_STRUCT_OFFSET (MateMixerBackendClass, stored_stream_removed),                        NULL,                        NULL,                        g_cclosure_marshal_VOID__STRING,                        G_TYPE_NONE,                        1,                        G_TYPE_STRING); + +    g_type_class_add_private (object_class, sizeof (MateMixerBackendPrivate)); +} + +static void +mate_mixer_backend_get_property (GObject    *object, +                                 guint       param_id, +                                 GValue     *value, +                                 GParamSpec *pspec) +{ +    MateMixerBackend *backend; + +    backend = MATE_MIXER_BACKEND (object); + +    switch (param_id) { +    case PROP_STATE: +        g_value_set_enum (value, backend->priv->state); +        break; + +    case PROP_DEFAULT_INPUT_STREAM: +        g_value_set_object (value, backend->priv->default_input); +        break; + +    case PROP_DEFAULT_OUTPUT_STREAM: +        g_value_set_object (value, backend->priv->default_output); +        break; + +    default: +        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); +        break; +    } +} + +static void +mate_mixer_backend_set_property (GObject      *object, +                                 guint         param_id, +                                 const GValue *value, +                                 GParamSpec   *pspec) +{ +    MateMixerBackend *backend; + +    backend = MATE_MIXER_BACKEND (object); + +    switch (param_id) { +    case PROP_DEFAULT_INPUT_STREAM: +        mate_mixer_backend_set_default_input_stream (backend, g_value_get_object (value)); +        break; + +    case PROP_DEFAULT_OUTPUT_STREAM: +        mate_mixer_backend_set_default_output_stream (backend, g_value_get_object (value)); +        break; + +    default: +        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); +        break; +    } +} + +static void +mate_mixer_backend_init (MateMixerBackend *backend) +{ +    backend->priv = G_TYPE_INSTANCE_GET_PRIVATE (backend, +                                                 MATE_MIXER_TYPE_BACKEND, +                                                 MateMixerBackendPrivate); + +    g_signal_connect (G_OBJECT (backend), +                      "device-added", +                      G_CALLBACK (free_devices), +                      NULL); +    g_signal_connect (G_OBJECT (backend), +                      "device-added", +                      G_CALLBACK (device_added), +                      NULL); + +    g_signal_connect (G_OBJECT (backend), +                      "device-removed", +                      G_CALLBACK (free_devices), +                      NULL); +    g_signal_connect (G_OBJECT (backend), +                      "device-removed", +                      G_CALLBACK (device_removed), +                      NULL); + +    g_signal_connect (G_OBJECT (backend), +                      "stream-added", +                      G_CALLBACK (free_streams), +                      NULL); +    g_signal_connect (G_OBJECT (backend), +                      "stream-removed", +                      G_CALLBACK (free_streams), +                      NULL); + +    g_signal_connect (G_OBJECT (backend), +                      "stored-stream-added", +                      G_CALLBACK (free_stored_streams), +                      NULL); +    g_signal_connect (G_OBJECT (backend), +                      "stored-stream-removed", +                      G_CALLBACK (free_stored_streams), +                      NULL); + +    // XXX also free when changing state +} + +static void +mate_mixer_backend_dispose (GObject *object) +{ +    MateMixerBackend *backend; + +    backend = MATE_MIXER_BACKEND (object); + +    free_devices (backend); +    free_streams (backend); +    free_stored_streams (backend); + +    g_clear_object (&backend->priv->default_input); +    g_clear_object (&backend->priv->default_output); + +    G_OBJECT_CLASS (mate_mixer_backend_parent_class)->dispose (object);  }  void -mate_mixer_backend_set_data (MateMixerBackend *backend, const MateMixerBackendData *data) +mate_mixer_backend_set_data (MateMixerBackend *backend, MateMixerBackendData *data)  { -    MateMixerBackendInterface *iface; +    MateMixerBackendClass *klass;      g_return_if_fail (MATE_MIXER_IS_BACKEND (backend)); -    iface = MATE_MIXER_BACKEND_GET_INTERFACE (backend); +    klass = MATE_MIXER_BACKEND_GET_CLASS (backend); -    if (iface->set_data) -        iface->set_data (backend, data); +    if (klass->set_data != NULL) +        klass->set_data (backend, data);  }  gboolean @@ -157,79 +337,87 @@ mate_mixer_backend_open (MateMixerBackend *backend)      g_return_val_if_fail (MATE_MIXER_IS_BACKEND (backend), FALSE);      /* Implementation required */ -    return MATE_MIXER_BACKEND_GET_INTERFACE (backend)->open (backend); +    return MATE_MIXER_BACKEND_GET_CLASS (backend)->open (backend);  }  void  mate_mixer_backend_close (MateMixerBackend *backend)  { -    MateMixerBackendInterface *iface; +    MateMixerBackendClass *klass;      g_return_if_fail (MATE_MIXER_IS_BACKEND (backend)); -    iface = MATE_MIXER_BACKEND_GET_INTERFACE (backend); +    klass = MATE_MIXER_BACKEND_GET_CLASS (backend); -    if (iface->close) -        iface->close (backend); +    if (klass->close != NULL) +        klass->close (backend);  }  MateMixerState  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); -    g_object_get (G_OBJECT (backend), -                  "state", &state, -                  NULL); +    return backend->priv->state; +} -    return state; +MateMixerBackendFlags +mate_mixer_backend_get_flags (MateMixerBackend *backend) +{ +    g_return_val_if_fail (MATE_MIXER_IS_BACKEND (backend), MATE_MIXER_BACKEND_NO_FLAGS); + +    return backend->priv->flags;  } -GList * +const GList *  mate_mixer_backend_list_devices (MateMixerBackend *backend)  { -    MateMixerBackendInterface *iface; -      g_return_val_if_fail (MATE_MIXER_IS_BACKEND (backend), NULL); -    iface = MATE_MIXER_BACKEND_GET_INTERFACE (backend); +    if (backend->priv->devices == NULL) { +        MateMixerBackendClass *klass; + +        klass = MATE_MIXER_BACKEND_GET_CLASS (backend); -    if (iface->list_devices) -        return iface->list_devices (backend); +        if (klass->list_devices != NULL) +            backend->priv->devices = klass->list_devices (backend); +    } -    return NULL; +    return backend->priv->devices;  } -GList * +const GList *  mate_mixer_backend_list_streams (MateMixerBackend *backend)  { -    MateMixerBackendInterface *iface; -      g_return_val_if_fail (MATE_MIXER_IS_BACKEND (backend), NULL); -    iface = MATE_MIXER_BACKEND_GET_INTERFACE (backend); +    if (backend->priv->streams == NULL) { +        MateMixerBackendClass *klass; + +        klass = MATE_MIXER_BACKEND_GET_CLASS (backend); -    if (iface->list_streams) -        return iface->list_streams (backend); +        if (klass->list_streams != NULL) +            backend->priv->streams = klass->list_streams (backend); +    } -    return NULL; +    return backend->priv->streams;  } -GList * -mate_mixer_backend_list_cached_streams (MateMixerBackend *backend) +const GList * +mate_mixer_backend_list_stored_streams (MateMixerBackend *backend)  { -    MateMixerBackendInterface *iface; -      g_return_val_if_fail (MATE_MIXER_IS_BACKEND (backend), NULL); -    iface = MATE_MIXER_BACKEND_GET_INTERFACE (backend); +    if (backend->priv->stored_streams == NULL) { +        MateMixerBackendClass *klass; + +        klass = MATE_MIXER_BACKEND_GET_CLASS (backend); -    if (iface->list_cached_streams) -        return iface->list_cached_streams (backend); +        if (klass->list_stored_streams != NULL) +            backend->priv->stored_streams = klass->list_stored_streams (backend); +    } -    return NULL; +    return backend->priv->stored_streams;  }  MateMixerStream * @@ -239,8 +427,8 @@ mate_mixer_backend_get_default_input_stream (MateMixerBackend *backend)      g_return_val_if_fail (MATE_MIXER_IS_BACKEND (backend), NULL); -    g_object_get (G_OBJECT (stream), -                  "default-input", &stream, +    g_object_get (G_OBJECT (backend), +                  "default-input-stream", &stream,                    NULL);      if (stream != NULL) @@ -253,16 +441,22 @@ gboolean  mate_mixer_backend_set_default_input_stream (MateMixerBackend *backend,                                               MateMixerStream  *stream)  { -    MateMixerBackendInterface *iface; -      g_return_val_if_fail (MATE_MIXER_IS_BACKEND (backend), FALSE); +    g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), FALSE); + +    if (backend->priv->default_input != stream) { +        MateMixerBackendClass *klass; + +        klass = MATE_MIXER_BACKEND_GET_CLASS (backend); -    iface = MATE_MIXER_BACKEND_GET_INTERFACE (backend); +        if (klass->set_default_input_stream == NULL || +            klass->set_default_input_stream (backend, stream) == FALSE) +            return FALSE; -    if (iface->set_default_input_stream) -        return iface->set_default_input_stream (backend, stream); +        _mate_mixer_backend_set_default_input_stream (backend, stream); +    } -    return FALSE; +    return TRUE;  }  MateMixerStream * @@ -272,8 +466,8 @@ mate_mixer_backend_get_default_output_stream (MateMixerBackend *backend)      g_return_val_if_fail (MATE_MIXER_IS_BACKEND (backend), NULL); -    g_object_get (G_OBJECT (stream), -                  "default-output", &stream, +    g_object_get (G_OBJECT (backend), +                  "default-output-stream", &stream,                    NULL);      if (stream != NULL) @@ -286,14 +480,144 @@ gboolean  mate_mixer_backend_set_default_output_stream (MateMixerBackend *backend,                                                MateMixerStream  *stream)  { -    MateMixerBackendInterface *iface; -      g_return_val_if_fail (MATE_MIXER_IS_BACKEND (backend), FALSE); +    g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), FALSE); + +    if (backend->priv->default_input != stream) { +        MateMixerBackendClass *klass; -    iface = MATE_MIXER_BACKEND_GET_INTERFACE (backend); +        klass = MATE_MIXER_BACKEND_GET_CLASS (backend); + +        if (klass->set_default_output_stream == NULL || +            klass->set_default_output_stream (backend, stream) == FALSE) +            return FALSE; + +        _mate_mixer_backend_set_default_output_stream (backend, stream); +    } + +    return TRUE; +} + +static void +device_added (MateMixerBackend *backend, const gchar *name) +{ +    MateMixerDevice *device; + +    // device = mate_mixer_backend_get_device (backend, name); + +/* +    g_signal_connect (G_OBJECT (device), +                      "stream-added", +                      G_CALLBACK (device_stream_added)); +                      */ +} + +static void +device_removed (MateMixerBackend *backend, const gchar *name) +{ +} + +static void +device_stream_added (MateMixerDevice *device, const gchar *name) +{ +    g_signal_emit (G_OBJECT (device), +                   signals[STREAM_ADDED], +                   0, +                   name); +} + +static void +device_stream_removed (MateMixerDevice *device, const gchar *name) +{ +    g_signal_emit (G_OBJECT (device), +                   signals[STREAM_REMOVED], +                   0, +                   name); +} + +static void +free_devices (MateMixerBackend *backend) +{ +    if (backend->priv->devices == NULL) +        return; + +    g_list_free_full (backend->priv->devices, g_object_unref); + +    backend->priv->devices = NULL; +} + +static void +free_streams (MateMixerBackend *backend) +{ +    if (backend->priv->streams == NULL) +        return; + +    g_list_free_full (backend->priv->streams, g_object_unref); + +    backend->priv->streams = NULL; +} + +static void +free_stored_streams (MateMixerBackend *backend) +{ +    if (backend->priv->stored_streams == NULL) +        return; + +    g_list_free_full (backend->priv->stored_streams, g_object_unref); + +    backend->priv->stored_streams = NULL; +} + +/* Protected */ +void +_mate_mixer_backend_set_state (MateMixerBackend *backend, MateMixerState state) +{ +    if (backend->priv->state == state) +        return; + +    backend->priv->state = state; + +    g_object_notify_by_pspec (G_OBJECT (backend), properties[PROP_STATE]); +} + +void +_mate_mixer_backend_set_default_input_stream (MateMixerBackend *backend, +                                              MateMixerStream  *stream) +{ +    if (backend->priv->default_input == stream) +        return; + +    if (backend->priv->default_input != NULL) +        g_object_unref (backend->priv->default_input); + +    if (stream != NULL) +        backend->priv->default_input = g_object_ref (stream); +    else +        backend->priv->default_input = NULL; + +    g_debug ("Default input stream changed to %s", +             (stream != NULL) ? mate_mixer_stream_get_name (stream) : "none"); + +    g_object_notify_by_pspec (G_OBJECT (backend), properties[PROP_DEFAULT_INPUT_STREAM]); +} + +void +_mate_mixer_backend_set_default_output_stream (MateMixerBackend *backend, +                                               MateMixerStream  *stream) +{ +    if (backend->priv->default_output == stream) +        return; + +    if (backend->priv->default_output != NULL) +        g_object_unref (backend->priv->default_output); + +    if (stream != NULL) +        backend->priv->default_output = g_object_ref (stream); +    else +        backend->priv->default_output = NULL; -    if (iface->set_default_output_stream) -        return iface->set_default_output_stream (backend, stream); +    g_debug ("Default output stream changed to %s", +             (stream != NULL) ? mate_mixer_stream_get_name (stream) : "none"); -    return FALSE; +    g_object_notify_by_pspec (G_OBJECT (backend), properties[PROP_DEFAULT_OUTPUT_STREAM]);  } diff --git a/libmatemixer/matemixer-backend.h b/libmatemixer/matemixer-backend.h index 8bedfe0..1c918c9 100644 --- a/libmatemixer/matemixer-backend.h +++ b/libmatemixer/matemixer-backend.h @@ -21,94 +21,103 @@  #include <glib.h>  #include <glib-object.h> -#include "matemixer-enums.h" -#include "matemixer-stream.h" +#include <libmatemixer/matemixer-enums.h> +#include <libmatemixer/matemixer-types.h>  G_BEGIN_DECLS -typedef struct -{ -    gchar *app_name; -    gchar *app_id; -    gchar *app_version; -    gchar *app_icon; -    gchar *server_address; -} MateMixerBackendData; -  #define MATE_MIXER_TYPE_BACKEND                 \          (mate_mixer_backend_get_type ())  #define MATE_MIXER_BACKEND(o)                   \          (G_TYPE_CHECK_INSTANCE_CAST ((o), MATE_MIXER_TYPE_BACKEND, MateMixerBackend))  #define MATE_MIXER_IS_BACKEND(o)                \          (G_TYPE_CHECK_INSTANCE_TYPE ((o), MATE_MIXER_TYPE_BACKEND)) -#define MATE_MIXER_BACKEND_GET_INTERFACE(o)     \ -        (G_TYPE_INSTANCE_GET_INTERFACE ((o), MATE_MIXER_TYPE_BACKEND, MateMixerBackendInterface)) - -typedef struct _MateMixerBackend           MateMixerBackend; /* dummy object */ -typedef struct _MateMixerBackendInterface  MateMixerBackendInterface; - -struct _MateMixerBackendInterface +#define MATE_MIXER_BACKEND_CLASS(k)             \ +        (G_TYPE_CHECK_CLASS_CAST ((k), MATE_MIXER_TYPE_BACKEND, MateMixerBackendClass)) +#define MATE_MIXER_IS_BACKEND_CLASS(k)          \ +        (G_TYPE_CHECK_CLASS_TYPE ((k), MATE_MIXER_TYPE_BACKEND)) +#define MATE_MIXER_BACKEND_GET_CLASS(o)         \ +        (G_TYPE_INSTANCE_GET_CLASS ((o), MATE_MIXER_TYPE_BACKEND, MateMixerBackendClass)) + +typedef struct _MateMixerBackend         MateMixerBackend; +typedef struct _MateMixerBackendClass    MateMixerBackendClass; +typedef struct _MateMixerBackendData     MateMixerBackendData; +typedef struct _MateMixerBackendPrivate  MateMixerBackendPrivate; + +struct _MateMixerBackend  { -    GTypeInterface parent_iface; +    GObject object;      /*< private >*/ -    /* Virtual table */ -    void             (*set_data)                  (MateMixerBackend           *backend, -                                                   const MateMixerBackendData *data); +    MateMixerBackendPrivate *priv; +}; -    gboolean         (*open)                      (MateMixerBackend           *backend); -    void             (*close)                     (MateMixerBackend           *backend); +struct _MateMixerBackendClass +{ +    GObjectClass parent_class; -    MateMixerState   (*get_state)                 (MateMixerBackend           *backend); +    /*< private >*/ +    void      (*set_data)                  (MateMixerBackend     *backend, +                                            MateMixerBackendData *data); -    GList           *(*list_devices)              (MateMixerBackend           *backend); -    GList           *(*list_streams)              (MateMixerBackend           *backend); -    GList           *(*list_cached_streams)       (MateMixerBackend           *backend); +    gboolean  (*open)                      (MateMixerBackend     *backend); +    void      (*close)                     (MateMixerBackend     *backend); -    MateMixerStream *(*get_default_input_stream)  (MateMixerBackend           *backend); -    gboolean         (*set_default_input_stream)  (MateMixerBackend           *backend, -                                                   MateMixerStream            *stream); +    GList    *(*list_devices)              (MateMixerBackend     *backend); +    GList    *(*list_streams)              (MateMixerBackend     *backend); +    GList    *(*list_stored_streams)       (MateMixerBackend     *backend); -    MateMixerStream *(*get_default_output_stream) (MateMixerBackend           *backend); -    gboolean         (*set_default_output_stream) (MateMixerBackend           *backend, -                                                   MateMixerStream            *stream); +    gboolean  (*set_default_input_stream)  (MateMixerBackend     *backend, +                                            MateMixerStream      *stream); +    gboolean  (*set_default_output_stream) (MateMixerBackend     *backend, +                                            MateMixerStream      *stream);      /* Signals */ -    void             (*device_added)              (MateMixerBackend           *backend, -                                                   const gchar                *name); -    void             (*device_removed)            (MateMixerBackend           *backend, -                                                   const gchar                *name); -    void             (*stream_added)              (MateMixerBackend           *backend, -                                                   const gchar                *name); -    void             (*stream_removed)            (MateMixerBackend           *backend, -                                                   const gchar                *name); -    void             (*cached_stream_added)       (MateMixerBackend           *backend, -                                                   const gchar                *name); -    void             (*cached_stream_removed)     (MateMixerBackend           *backend, -                                                   const gchar                *name); +    void      (*device_added)              (MateMixerBackend     *backend, +                                            const gchar          *name); +    void      (*device_removed)            (MateMixerBackend     *backend, +                                            const gchar          *name); +    void      (*stream_added)              (MateMixerBackend     *backend, +                                            const gchar          *name); +    void      (*stream_removed)            (MateMixerBackend     *backend, +                                            const gchar          *name); +    void      (*stored_stream_added)       (MateMixerBackend     *backend, +                                            const gchar          *name); +    void      (*stored_stream_removed)     (MateMixerBackend     *backend, +                                            const gchar          *name); +}; + +struct _MateMixerBackendData +{ +    gchar *app_name; +    gchar *app_id; +    gchar *app_version; +    gchar *app_icon; +    gchar *server_address;  }; -GType            mate_mixer_backend_get_type                  (void) G_GNUC_CONST; +GType                 mate_mixer_backend_get_type                  (void) G_GNUC_CONST; -void             mate_mixer_backend_set_data                  (MateMixerBackend           *backend, -                                                               const MateMixerBackendData *data); +void                  mate_mixer_backend_set_data                  (MateMixerBackend     *backend, +                                                                    MateMixerBackendData *data); -gboolean         mate_mixer_backend_open                      (MateMixerBackend           *backend); -void             mate_mixer_backend_close                     (MateMixerBackend           *backend); +gboolean              mate_mixer_backend_open                      (MateMixerBackend     *backend); +void                  mate_mixer_backend_close                     (MateMixerBackend     *backend); -MateMixerState   mate_mixer_backend_get_state                 (MateMixerBackend           *backend); +MateMixerState        mate_mixer_backend_get_state                 (MateMixerBackend     *backend); +MateMixerBackendFlags mate_mixer_backend_get_flags                 (MateMixerBackend     *backend); -GList *          mate_mixer_backend_list_devices              (MateMixerBackend           *backend); -GList *          mate_mixer_backend_list_streams              (MateMixerBackend           *backend); -GList *          mate_mixer_backend_list_cached_streams       (MateMixerBackend           *backend); +const GList *         mate_mixer_backend_list_devices              (MateMixerBackend     *backend); +const GList *         mate_mixer_backend_list_streams              (MateMixerBackend     *backend); +const GList *         mate_mixer_backend_list_stored_streams       (MateMixerBackend     *backend); -MateMixerStream *mate_mixer_backend_get_default_input_stream  (MateMixerBackend           *backend); -gboolean         mate_mixer_backend_set_default_input_stream  (MateMixerBackend           *backend, -                                                               MateMixerStream            *stream); +MateMixerStream *     mate_mixer_backend_get_default_input_stream  (MateMixerBackend     *backend); +gboolean              mate_mixer_backend_set_default_input_stream  (MateMixerBackend     *backend, +                                                                    MateMixerStream      *stream); -MateMixerStream *mate_mixer_backend_get_default_output_stream (MateMixerBackend           *backend); -gboolean         mate_mixer_backend_set_default_output_stream (MateMixerBackend           *backend, -                                                               MateMixerStream            *stream); +MateMixerStream *     mate_mixer_backend_get_default_output_stream (MateMixerBackend     *backend); +gboolean              mate_mixer_backend_set_default_output_stream (MateMixerBackend     *backend, +                                                                    MateMixerStream      *stream);  G_END_DECLS diff --git a/libmatemixer/matemixer-client-stream.c b/libmatemixer/matemixer-client-stream.c index 3ff3c54..fc34622 100644 --- a/libmatemixer/matemixer-client-stream.c +++ b/libmatemixer/matemixer-client-stream.c @@ -35,68 +35,170 @@   * A typical example of a client stream is a stream provided by an application.   */ -G_DEFINE_INTERFACE (MateMixerClientStream, mate_mixer_client_stream, G_TYPE_OBJECT) +struct _MateMixerClientStreamPrivate +{ +    gchar                     *app_name; +    gchar                     *app_id; +    gchar                     *app_version; +    gchar                     *app_icon; +    MateMixerStream           *parent; +    MateMixerClientStreamFlags client_flags; +    MateMixerClientStreamRole  client_role; +}; + +enum { +    PROP_0, +    PROP_CLIENT_FLAGS, +    PROP_CLIENT_ROLE, +    PROP_PARENT, +    PROP_APP_NAME, +    PROP_APP_ID, +    PROP_APP_VERSION, +    PROP_APP_ICON, +    N_PROPERTIES +}; + +static GParamSpec *properties[N_PROPERTIES] = { NULL, }; + +static void mate_mixer_client_stream_class_init   (MateMixerClientStreamClass *klass); + +static void mate_mixer_client_stream_init         (MateMixerClientStream      *client); + +static void mate_mixer_client_stream_get_property (GObject                    *object, +                                                   guint                       param_id, +                                                   GValue                     *value, +                                                   GParamSpec                 *pspec); +static void mate_mixer_client_stream_set_property (GObject                    *object, +                                                   guint                       param_id, +                                                   const GValue               *value, +                                                   GParamSpec                 *pspec); + +static void mate_mixer_client_stream_dispose      (GObject                    *object); +static void mate_mixer_client_stream_finalize     (GObject                    *object); + +G_DEFINE_ABSTRACT_TYPE (MateMixerClientStream, mate_mixer_client_stream, MATE_MIXER_TYPE_STREAM) + +static void +mate_mixer_client_stream_class_init (MateMixerClientStreamClass *klass) +{ +    GObjectClass *object_class; + +    object_class = G_OBJECT_CLASS (klass); +    object_class->dispose      = mate_mixer_client_stream_dispose; +    object_class->finalize     = mate_mixer_client_stream_finalize; +    object_class->get_property = mate_mixer_client_stream_get_property; +    object_class->set_property = mate_mixer_client_stream_set_property; + +    properties[PROP_CLIENT_FLAGS] = +        g_param_spec_flags ("client-flags", +                            "Client flags", +                            "Capability flags of the client stream", +                            MATE_MIXER_TYPE_CLIENT_STREAM_FLAGS, +                            MATE_MIXER_CLIENT_STREAM_NO_FLAGS, +                            G_PARAM_READABLE | +                            G_PARAM_STATIC_STRINGS); + +    properties[PROP_CLIENT_ROLE] = +        g_param_spec_enum ("role", +                           "Role", +                           "Role of the client stream", +                           MATE_MIXER_TYPE_CLIENT_STREAM_ROLE, +                           MATE_MIXER_CLIENT_STREAM_ROLE_NONE, +                           G_PARAM_READABLE | +                           G_PARAM_STATIC_STRINGS); + +    properties[PROP_PARENT] = +        g_param_spec_object ("parent", +                             "Parent", +                             "Parent stream of the client stream", +                             MATE_MIXER_TYPE_STREAM, +                             G_PARAM_READABLE | +                             G_PARAM_STATIC_STRINGS); + +    properties[PROP_APP_NAME] = +        g_param_spec_string ("app-name", +                             "App name", +                             "Name of the client stream application", +                             NULL, +                             G_PARAM_READABLE | +                             G_PARAM_STATIC_STRINGS); + +    properties[PROP_APP_ID] = +        g_param_spec_string ("app-id", +                             "App ID", +                             "Identifier of the client stream application", +                             NULL, +                             G_PARAM_READABLE | +                             G_PARAM_STATIC_STRINGS); + +    properties[PROP_APP_VERSION] = +        g_param_spec_string ("app-version", +                             "App version", +                             "Version of the client stream application", +                             NULL, +                             G_PARAM_READABLE | +                             G_PARAM_STATIC_STRINGS); + +    properties[PROP_APP_ICON] = +        g_param_spec_string ("app-icon", +                             "App icon", +                             "Icon name of the client stream application", +                             NULL, +                             G_PARAM_READABLE | +                             G_PARAM_STATIC_STRINGS); + +    g_object_class_install_properties (object_class, N_PROPERTIES, properties); +} + +static void +mate_mixer_client_stream_init (MateMixerClientStream *client) +{ +    client->priv = G_TYPE_INSTANCE_GET_PRIVATE (client, +                                                MATE_MIXER_TYPE_CLIENT_STREAM, +                                                MateMixerClientStreamPrivate); +}  static void -mate_mixer_client_stream_default_init (MateMixerClientStreamInterface *iface) +mate_mixer_client_stream_get_property (GObject    *object, +                                       guint       param_id, +                                       GValue     *value, +                                       GParamSpec *pspec)  { -    g_object_interface_install_property (iface, -                                         g_param_spec_flags ("client-flags", -                                                             "Client flags", -                                                             "Capability flags of the client stream", -                                                             MATE_MIXER_TYPE_CLIENT_STREAM_FLAGS, -                                                             MATE_MIXER_CLIENT_STREAM_NO_FLAGS, -                                                             G_PARAM_READABLE | -                                                             G_PARAM_STATIC_STRINGS)); - -    g_object_interface_install_property (iface, -                                         g_param_spec_enum ("role", -                                                            "Role", -                                                            "Role of the client stream", -                                                            MATE_MIXER_TYPE_CLIENT_STREAM_ROLE, -                                                            MATE_MIXER_CLIENT_STREAM_ROLE_NONE, -                                                            G_PARAM_READABLE | -                                                            G_PARAM_STATIC_STRINGS)); - -    g_object_interface_install_property (iface, -                                         g_param_spec_object ("parent", -                                                              "Parent", -                                                              "Parent stream of the client stream", -                                                              MATE_MIXER_TYPE_STREAM, -                                                              G_PARAM_READABLE | -                                                              G_PARAM_STATIC_STRINGS)); - -    g_object_interface_install_property (iface, -                                         g_param_spec_string ("app-name", -                                                              "App name", -                                                              "Name of the client stream application", -                                                              NULL, -                                                              G_PARAM_READABLE | -                                                              G_PARAM_STATIC_STRINGS)); - -    g_object_interface_install_property (iface, -                                         g_param_spec_string ("app-id", -                                                              "App ID", -                                                              "Identifier of the client stream application", -                                                              NULL, -                                                              G_PARAM_READABLE | -                                                              G_PARAM_STATIC_STRINGS)); - -    g_object_interface_install_property (iface, -                                         g_param_spec_string ("app-version", -                                                              "App version", -                                                              "Version of the client stream application", -                                                              NULL, -                                                              G_PARAM_READABLE | -                                                              G_PARAM_STATIC_STRINGS)); - -    g_object_interface_install_property (iface, -                                         g_param_spec_string ("app-icon", -                                                              "App icon", -                                                              "Icon name of the client stream application", -                                                              NULL, -                                                              G_PARAM_READABLE | -                                                              G_PARAM_STATIC_STRINGS)); +} + +static void +mate_mixer_client_stream_set_property (GObject      *object, +                                       guint         param_id, +                                       const GValue *value, +                                       GParamSpec   *pspec) +{ +} + +static void +mate_mixer_client_stream_dispose (GObject *object) +{ +    MateMixerClientStream *client; + +    client = MATE_MIXER_CLIENT_STREAM (object); + +    g_clear_object (&client->priv->parent); + +    G_OBJECT_CLASS (mate_mixer_client_stream_parent_class)->dispose (object); +} + +static void +mate_mixer_client_stream_finalize (GObject *object) +{ +    MateMixerClientStream *client; + +    client = MATE_MIXER_CLIENT_STREAM (object); + +    g_free (client->priv->app_name); +    g_free (client->priv->app_id); +    g_free (client->priv->app_version); +    g_free (client->priv->app_icon); + +    G_OBJECT_CLASS (mate_mixer_client_stream_parent_class)->finalize (object);  }  /** @@ -107,16 +209,9 @@ mate_mixer_client_stream_default_init (MateMixerClientStreamInterface *iface)  MateMixerClientStreamFlags  mate_mixer_client_stream_get_flags (MateMixerClientStream *client)  { -    MateMixerClientStreamInterface *iface; -      g_return_val_if_fail (MATE_MIXER_IS_CLIENT_STREAM (client), MATE_MIXER_CLIENT_STREAM_NO_FLAGS); -    iface = MATE_MIXER_CLIENT_STREAM_GET_INTERFACE (client); - -    if (iface->get_flags) -        return iface->get_flags (client); - -    return MATE_MIXER_CLIENT_STREAM_NO_FLAGS; +    return client->priv->client_flags;  }  /** @@ -127,16 +222,9 @@ mate_mixer_client_stream_get_flags (MateMixerClientStream *client)  MateMixerClientStreamRole  mate_mixer_client_stream_get_role (MateMixerClientStream *client)  { -    MateMixerClientStreamInterface *iface; -      g_return_val_if_fail (MATE_MIXER_IS_CLIENT_STREAM (client), MATE_MIXER_CLIENT_STREAM_ROLE_NONE); -    iface = MATE_MIXER_CLIENT_STREAM_GET_INTERFACE (client); - -    if (iface->get_role) -        return iface->get_role (client); - -    return MATE_MIXER_CLIENT_STREAM_ROLE_NONE; +    return client->priv->client_role;  }  /** @@ -150,16 +238,9 @@ mate_mixer_client_stream_get_role (MateMixerClientStream *client)  MateMixerStream *  mate_mixer_client_stream_get_parent (MateMixerClientStream *client)  { -    MateMixerClientStreamInterface *iface; -      g_return_val_if_fail (MATE_MIXER_IS_CLIENT_STREAM (client), NULL); -    iface = MATE_MIXER_CLIENT_STREAM_GET_INTERFACE (client); - -    if (iface->get_parent) -        return iface->get_parent (client); - -    return NULL; +    return client->priv->parent;  }  /** @@ -175,17 +256,25 @@ mate_mixer_client_stream_get_parent (MateMixerClientStream *client)  gboolean  mate_mixer_client_stream_set_parent (MateMixerClientStream *client, MateMixerStream *parent)  { -    MateMixerClientStreamInterface *iface; -      g_return_val_if_fail (MATE_MIXER_IS_CLIENT_STREAM (client), FALSE);      g_return_val_if_fail (MATE_MIXER_IS_STREAM (parent), FALSE); -    iface = MATE_MIXER_CLIENT_STREAM_GET_INTERFACE (client); +    if (client->priv->parent != parent) { +        MateMixerClientStreamClass *klass; -    if (iface->set_parent) -        return iface->set_parent (client, parent); +        klass = MATE_MIXER_CLIENT_STREAM_GET_CLASS (client); -    return FALSE; +        if (klass->set_parent == NULL || +            klass->set_parent (client, parent) == FALSE) +            return FALSE; + +        if (client->priv->parent != NULL) +            g_object_unref (client->priv->parent); + +        client->priv->parent = g_object_ref (parent); +    } + +    return TRUE;  }  /** @@ -199,14 +288,14 @@ mate_mixer_client_stream_set_parent (MateMixerClientStream *client, MateMixerStr  gboolean  mate_mixer_client_stream_remove (MateMixerClientStream *client)  { -    MateMixerClientStreamInterface *iface; +    MateMixerClientStreamClass *klass;      g_return_val_if_fail (MATE_MIXER_IS_CLIENT_STREAM (client), FALSE); -    iface = MATE_MIXER_CLIENT_STREAM_GET_INTERFACE (client); +    klass = MATE_MIXER_CLIENT_STREAM_GET_CLASS (client); -    if (iface->remove) -        return iface->remove (client); +    if (klass->remove != NULL) +        return klass->remove (client);      return FALSE;  } @@ -224,16 +313,9 @@ mate_mixer_client_stream_remove (MateMixerClientStream *client)  const gchar *  mate_mixer_client_stream_get_app_name (MateMixerClientStream *client)  { -    MateMixerClientStreamInterface *iface; -      g_return_val_if_fail (MATE_MIXER_IS_CLIENT_STREAM (client), NULL); -    iface = MATE_MIXER_CLIENT_STREAM_GET_INTERFACE (client); - -    if (iface->get_app_name) -        return iface->get_app_name (client); - -    return NULL; +    return client->priv->app_name;  }  /** @@ -249,16 +331,9 @@ mate_mixer_client_stream_get_app_name (MateMixerClientStream *client)  const gchar *  mate_mixer_client_stream_get_app_id (MateMixerClientStream *client)  { -    MateMixerClientStreamInterface *iface; -      g_return_val_if_fail (MATE_MIXER_IS_CLIENT_STREAM (client), NULL); -    iface = MATE_MIXER_CLIENT_STREAM_GET_INTERFACE (client); - -    if (iface->get_app_id) -        return iface->get_app_id (client); - -    return NULL; +    return client->priv->app_id;  }  /** @@ -274,16 +349,9 @@ mate_mixer_client_stream_get_app_id (MateMixerClientStream *client)  const gchar *  mate_mixer_client_stream_get_app_version (MateMixerClientStream *client)  { -    MateMixerClientStreamInterface *iface; -      g_return_val_if_fail (MATE_MIXER_IS_CLIENT_STREAM (client), NULL); -    iface = MATE_MIXER_CLIENT_STREAM_GET_INTERFACE (client); - -    if (iface->get_app_version) -        return iface->get_app_version (client); - -    return NULL; +    return client->priv->app_version;  }  /** @@ -299,14 +367,7 @@ mate_mixer_client_stream_get_app_version (MateMixerClientStream *client)  const gchar *  mate_mixer_client_stream_get_app_icon (MateMixerClientStream *client)  { -    MateMixerClientStreamInterface *iface; -      g_return_val_if_fail (MATE_MIXER_IS_CLIENT_STREAM (client), NULL); -    iface = MATE_MIXER_CLIENT_STREAM_GET_INTERFACE (client); - -    if (iface->get_app_icon) -        return iface->get_app_icon (client); - -    return NULL; +    return client->priv->app_icon;  } diff --git a/libmatemixer/matemixer-client-stream.h b/libmatemixer/matemixer-client-stream.h index fae5934..43ab3f0 100644 --- a/libmatemixer/matemixer-client-stream.h +++ b/libmatemixer/matemixer-client-stream.h @@ -22,28 +22,39 @@  #include <glib-object.h>  #include <libmatemixer/matemixer-enums.h> -#include <libmatemixer/matemixer-stream.h> +#include <libmatemixer/matemixer-types.h>  G_BEGIN_DECLS -#define MATE_MIXER_TYPE_CLIENT_STREAM                  \ +#define MATE_MIXER_TYPE_CLIENT_STREAM           \          (mate_mixer_client_stream_get_type ()) -#define MATE_MIXER_CLIENT_STREAM(o)                    \ +#define MATE_MIXER_CLIENT_STREAM(o)             \          (G_TYPE_CHECK_INSTANCE_CAST ((o), MATE_MIXER_TYPE_CLIENT_STREAM, MateMixerClientStream)) -#define MATE_MIXER_IS_CLIENT_STREAM(o)                 \ +#define MATE_MIXER_IS_CLIENT_STREAM(o)          \          (G_TYPE_CHECK_INSTANCE_TYPE ((o), MATE_MIXER_TYPE_CLIENT_STREAM)) -#define MATE_MIXER_CLIENT_STREAM_GET_INTERFACE(o)      \ -        (G_TYPE_INSTANCE_GET_INTERFACE ((o), MATE_MIXER_TYPE_CLIENT_STREAM, MateMixerClientStreamInterface)) +#define MATE_MIXER_CLIENT_STREAM_CLASS(k)       \ +        (G_TYPE_CHECK_CLASS_CAST ((k), MATE_MIXER_TYPE_CLIENT_STREAM, MateMixerClientStreamClass)) +#define MATE_MIXER_IS_CLIENT_STREAM_CLASS(k)    \ +        (G_TYPE_CHECK_CLASS_TYPE ((k), MATE_MIXER_TYPE_CLIENT_STREAM)) +#define MATE_MIXER_CLIENT_STREAM_GET_CLASS(o)   \ +        (G_TYPE_INSTANCE_GET_CLASS ((o), MATE_MIXER_TYPE_CLIENT_STREAM, MateMixerClientStreamClass)) -typedef struct _MateMixerClientStream           MateMixerClientStream; /* dummy object */ -typedef struct _MateMixerClientStreamInterface  MateMixerClientStreamInterface; +typedef struct _MateMixerClientStreamClass    MateMixerClientStreamClass; +typedef struct _MateMixerClientStreamPrivate  MateMixerClientStreamPrivate; -struct _MateMixerClientStreamInterface +struct _MateMixerClientStream +{ +    GObject *parent; + +    /*< private >*/ +    MateMixerClientStreamPrivate *priv; +}; + +struct _MateMixerClientStreamClass  {      GTypeInterface parent_iface;      /*< private >*/ -    /* Virtual table */      MateMixerClientStreamFlags (*get_flags)       (MateMixerClientStream *client);      MateMixerClientStreamRole  (*get_role)        (MateMixerClientStream *client); diff --git a/libmatemixer/matemixer-control.c b/libmatemixer/matemixer-context.c index b501f1e..5bdc7a8 100644 --- a/libmatemixer/matemixer-control.c +++ b/libmatemixer/matemixer-context.c @@ -23,23 +23,20 @@  #include "matemixer-backend.h"  #include "matemixer-backend-module.h"  #include "matemixer-client-stream.h" -#include "matemixer-control.h" +#include "matemixer-context.h"  #include "matemixer-enums.h"  #include "matemixer-enum-types.h"  #include "matemixer-private.h"  #include "matemixer-stream.h"  /** - * SECTION:matemixer-control + * SECTION:matemixer-context   * @short_description:The main class for interfacing with the library   * @include: libmatemixer/matemixer.h   */ -struct _MateMixerControlPrivate +struct _MateMixerContextPrivate  { -    GList                  *devices; -    GList                  *streams; -    GList                  *cached_streams;      gboolean                backend_chosen;      MateMixerState          state;      MateMixerBackend       *backend; @@ -56,8 +53,8 @@ enum {      PROP_APP_ICON,      PROP_SERVER_ADDRESS,      PROP_STATE, -    PROP_DEFAULT_INPUT, -    PROP_DEFAULT_OUTPUT, +    PROP_DEFAULT_INPUT_STREAM, +    PROP_DEFAULT_OUTPUT_STREAM,      N_PROPERTIES  }; @@ -68,87 +65,82 @@ enum {      DEVICE_REMOVED,      STREAM_ADDED,      STREAM_REMOVED, -    CACHED_STREAM_ADDED, -    CACHED_STREAM_REMOVED, +    STORED_STREAM_ADDED, +    STORED_STREAM_REMOVED,      N_SIGNALS  };  static guint signals[N_SIGNALS] = { 0, }; -static void mate_mixer_control_class_init   (MateMixerControlClass *klass); +static void mate_mixer_context_class_init   (MateMixerContextClass *klass); -static void mate_mixer_control_get_property (GObject               *object, +static void mate_mixer_context_get_property (GObject               *object,                                               guint                  param_id,                                               GValue                *value,                                               GParamSpec            *pspec); -static void mate_mixer_control_set_property (GObject               *object, +static void mate_mixer_context_set_property (GObject               *object,                                               guint                  param_id,                                               const GValue          *value,                                               GParamSpec            *pspec); -static void mate_mixer_control_init         (MateMixerControl      *control); -static void mate_mixer_control_dispose      (GObject               *object); -static void mate_mixer_control_finalize     (GObject               *object); +static void mate_mixer_context_init         (MateMixerContext      *context); +static void mate_mixer_context_dispose      (GObject               *object); +static void mate_mixer_context_finalize     (GObject               *object); -G_DEFINE_TYPE (MateMixerControl, mate_mixer_control, G_TYPE_OBJECT); +G_DEFINE_TYPE (MateMixerContext, mate_mixer_context, G_TYPE_OBJECT); -static void     on_backend_state_notify          (MateMixerBackend *backend, -                                                  GParamSpec       *pspec, -                                                  MateMixerControl *control); +static void     on_backend_state_notify                 (MateMixerBackend *backend, +                                                         GParamSpec       *pspec, +                                                         MateMixerContext *context); -static void     on_backend_device_added          (MateMixerBackend *backend, -                                                  const gchar      *name, -                                                  MateMixerControl *control); -static void     on_backend_device_removed        (MateMixerBackend *backend, -                                                  const gchar      *name, -                                                  MateMixerControl *control); +static void     on_backend_device_added                 (MateMixerBackend *backend, +                                                         const gchar      *name, +                                                         MateMixerContext *context); +static void     on_backend_device_removed               (MateMixerBackend *backend, +                                                         const gchar      *name, +                                                         MateMixerContext *context); -static void     on_backend_stream_added          (MateMixerBackend *backend, -                                                  const gchar      *name, -                                                  MateMixerControl *control); -static void     on_backend_stream_removed        (MateMixerBackend *backend, -                                                  const gchar      *name, -                                                  MateMixerControl *control); +static void     on_backend_stream_added                 (MateMixerBackend *backend, +                                                         const gchar      *name, +                                                         MateMixerContext *context); +static void     on_backend_stream_removed               (MateMixerBackend *backend, +                                                         const gchar      *name, +                                                         MateMixerContext *context); -static void     on_backend_cached_stream_added   (MateMixerBackend *backend, -                                                  const gchar      *name, -                                                  MateMixerControl *control); -static void     on_backend_cached_stream_removed (MateMixerBackend *backend, -                                                  const gchar      *name, -                                                  MateMixerControl *control); +static void     on_backend_stored_stream_added          (MateMixerBackend *backend, +                                                         const gchar      *name, +                                                         MateMixerContext *context); +static void     on_backend_stored_stream_removed        (MateMixerBackend *backend, +                                                         const gchar      *name, +                                                         MateMixerContext *context); -static void     on_backend_default_input_notify  (MateMixerBackend *backend, -                                                  GParamSpec       *pspec, -                                                  MateMixerControl *control); -static void     on_backend_default_output_notify (MateMixerBackend *backend, -                                                  GParamSpec       *pspec, -                                                  MateMixerControl *control); +static void     on_backend_default_input_stream_notify  (MateMixerBackend *backend, +                                                         GParamSpec       *pspec, +                                                         MateMixerContext *context); +static void     on_backend_default_output_stream_notify (MateMixerBackend *backend, +                                                         GParamSpec       *pspec, +                                                         MateMixerContext *context); -static gboolean try_next_backend                 (MateMixerControl *control); +static gboolean try_next_backend                        (MateMixerContext *context); -static void     change_state                     (MateMixerControl *control, -                                                  MateMixerState    state); +static void     change_state                            (MateMixerContext *context, +                                                         MateMixerState    state); -static void     close_control                    (MateMixerControl *control); - -static void     free_backend                     (MateMixerControl *control); -static void     free_devices                     (MateMixerControl *control); -static void     free_streams                     (MateMixerControl *control); -static void     free_cached_streams              (MateMixerControl *control); +static void     close_context                           (MateMixerContext *context);  static void -mate_mixer_control_class_init (MateMixerControlClass *klass) +mate_mixer_context_class_init (MateMixerContextClass *klass)  {      GObjectClass *object_class;      object_class = G_OBJECT_CLASS (klass); -    object_class->dispose      = mate_mixer_control_dispose; -    object_class->finalize     = mate_mixer_control_finalize; -    object_class->get_property = mate_mixer_control_get_property; -    object_class->set_property = mate_mixer_control_set_property; +    object_class->dispose      = mate_mixer_context_dispose; +    object_class->finalize     = mate_mixer_context_finalize; +    object_class->get_property = mate_mixer_context_get_property; +    object_class->set_property = mate_mixer_context_set_property;      /** -     * MateMixerControl:app-name: +     * MateMixerContext:app-name:       *       * Localized human readable name of the application.       */ @@ -160,7 +152,7 @@ mate_mixer_control_class_init (MateMixerControlClass *klass)                               G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);      /** -     * MateMixerControl:app-id: +     * MateMixerContext:app-id:       *       * Identifier of the application (e.g. org.example.app).       */ @@ -172,7 +164,7 @@ mate_mixer_control_class_init (MateMixerControlClass *klass)                               G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);      /** -     * MateMixerControl:app-version: +     * MateMixerContext:app-version:       *       * Version of the application.       */ @@ -184,7 +176,7 @@ mate_mixer_control_class_init (MateMixerControlClass *klass)                               G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);      /** -     * MateMixerControl:app-icon: +     * MateMixerContext:app-icon:       *       * An XDG icon name for the application.       */ @@ -196,7 +188,7 @@ mate_mixer_control_class_init (MateMixerControlClass *klass)                               G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);      /** -     * MateMixerControl:server-address: +     * MateMixerContext:server-address:       *       * Address of the sound server to connect to.       * @@ -218,16 +210,16 @@ mate_mixer_control_class_init (MateMixerControlClass *klass)                             MATE_MIXER_STATE_IDLE,                             G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); -    properties[PROP_DEFAULT_INPUT] = -        g_param_spec_object ("default-input", -                             "Default input", +    properties[PROP_DEFAULT_INPUT_STREAM] = +        g_param_spec_object ("default-input-stream", +                             "Default input stream",                               "Default input stream",                               MATE_MIXER_TYPE_STREAM,                               G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); -    properties[PROP_DEFAULT_OUTPUT] = -        g_param_spec_object ("default-output", -                             "Default output", +    properties[PROP_DEFAULT_OUTPUT_STREAM] = +        g_param_spec_object ("default-output-stream", +                             "Default output stream",                               "Default output stream",                               MATE_MIXER_TYPE_STREAM,                               G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); @@ -235,8 +227,8 @@ mate_mixer_control_class_init (MateMixerControlClass *klass)      g_object_class_install_properties (object_class, N_PROPERTIES, properties);      /** -     * MateMixerControl::device-added: -     * @control: a #MateMixerControl +     * MateMixerContext::device-added: +     * @context: a #MateMixerContext       * @name: name of the added device       *       * The signal is emitted each time a device is added to the system. @@ -245,7 +237,7 @@ mate_mixer_control_class_init (MateMixerControlClass *klass)          g_signal_new ("device-added",                        G_TYPE_FROM_CLASS (object_class),                        G_SIGNAL_RUN_LAST, -                      G_STRUCT_OFFSET (MateMixerControlClass, device_added), +                      G_STRUCT_OFFSET (MateMixerContextClass, device_added),                        NULL,                        NULL,                        g_cclosure_marshal_VOID__STRING, @@ -254,8 +246,8 @@ mate_mixer_control_class_init (MateMixerControlClass *klass)                        G_TYPE_STRING);      /** -     * MateMixerControl::device-removed: -     * @control: a #MateMixerControl +     * MateMixerContext::device-removed: +     * @context: a #MateMixerContext       * @name: name of the removed device       *       * The signal is emitted each time a device is removed from the system. @@ -264,7 +256,7 @@ mate_mixer_control_class_init (MateMixerControlClass *klass)          g_signal_new ("device-removed",                        G_TYPE_FROM_CLASS (object_class),                        G_SIGNAL_RUN_LAST, -                      G_STRUCT_OFFSET (MateMixerControlClass, device_removed), +                      G_STRUCT_OFFSET (MateMixerContextClass, device_removed),                        NULL,                        NULL,                        g_cclosure_marshal_VOID__STRING, @@ -273,8 +265,8 @@ mate_mixer_control_class_init (MateMixerControlClass *klass)                        G_TYPE_STRING);      /** -     * MateMixerControl::stream-added: -     * @control: a #MateMixerControl +     * MateMixerContext::stream-added: +     * @context: a #MateMixerContext       * @name: name of the added stream       *       * The signal is emitted each time a stream is created. @@ -283,7 +275,7 @@ mate_mixer_control_class_init (MateMixerControlClass *klass)          g_signal_new ("stream-added",                        G_TYPE_FROM_CLASS (object_class),                        G_SIGNAL_RUN_LAST, -                      G_STRUCT_OFFSET (MateMixerControlClass, stream_added), +                      G_STRUCT_OFFSET (MateMixerContextClass, stream_added),                        NULL,                        NULL,                        g_cclosure_marshal_VOID__STRING, @@ -292,8 +284,8 @@ mate_mixer_control_class_init (MateMixerControlClass *klass)                        G_TYPE_STRING);      /** -     * MateMixerControl::stream-removed: -     * @control: a #MateMixerControl +     * MateMixerContext::stream-removed: +     * @context: a #MateMixerContext       * @name: name of the removed stream       *       * The signal is emitted each time a stream is removed. @@ -302,7 +294,7 @@ mate_mixer_control_class_init (MateMixerControlClass *klass)          g_signal_new ("stream-removed",                        G_TYPE_FROM_CLASS (object_class),                        G_SIGNAL_RUN_LAST, -                      G_STRUCT_OFFSET (MateMixerControlClass, stream_removed), +                      G_STRUCT_OFFSET (MateMixerContextClass, stream_removed),                        NULL,                        NULL,                        g_cclosure_marshal_VOID__STRING, @@ -311,17 +303,17 @@ mate_mixer_control_class_init (MateMixerControlClass *klass)                        G_TYPE_STRING);      /** -     * MateMixerControl::cached-stream-added: -     * @control: a #MateMixerControl -     * @name: name of the added cached stream +     * MateMixerContext::stored-stream-added: +     * @context: a #MateMixerContext +     * @name: name of the added stored stream       * -     * The signal is emitted each time a cached stream is created. +     * The signal is emitted each time a stored stream is created.       */ -    signals[CACHED_STREAM_ADDED] = -        g_signal_new ("cached-stream-added", +    signals[STORED_STREAM_ADDED] = +        g_signal_new ("stored-control-added",                        G_TYPE_FROM_CLASS (object_class),                        G_SIGNAL_RUN_LAST, -                      G_STRUCT_OFFSET (MateMixerControlClass, cached_stream_added), +                      G_STRUCT_OFFSET (MateMixerContextClass, stored_stream_added),                        NULL,                        NULL,                        g_cclosure_marshal_VOID__STRING, @@ -330,17 +322,17 @@ mate_mixer_control_class_init (MateMixerControlClass *klass)                        G_TYPE_STRING);      /** -     * MateMixerControl::stream-removed: -     * @control: a #MateMixerControl +     * MateMixerContext::stream-removed: +     * @context: a #MateMixerContext       * @name: name of the removed stream       *       * The signal is emitted each time a stream is removed.       */ -    signals[CACHED_STREAM_REMOVED] = -        g_signal_new ("cached-stream-removed", +    signals[STORED_STREAM_REMOVED] = +        g_signal_new ("stored-stream-removed",                        G_TYPE_FROM_CLASS (object_class),                        G_SIGNAL_RUN_LAST, -                      G_STRUCT_OFFSET (MateMixerControlClass, cached_stream_removed), +                      G_STRUCT_OFFSET (MateMixerContextClass, stored_stream_removed),                        NULL,                        NULL,                        g_cclosure_marshal_VOID__STRING, @@ -348,43 +340,43 @@ mate_mixer_control_class_init (MateMixerControlClass *klass)                        1,                        G_TYPE_STRING); -    g_type_class_add_private (object_class, sizeof (MateMixerControlPrivate)); +    g_type_class_add_private (object_class, sizeof (MateMixerContextPrivate));  }  static void -mate_mixer_control_get_property (GObject    *object, +mate_mixer_context_get_property (GObject    *object,                                   guint       param_id,                                   GValue     *value,                                   GParamSpec *pspec)  { -    MateMixerControl *control; +    MateMixerContext *context; -    control = MATE_MIXER_CONTROL (object); +    context = MATE_MIXER_CONTEXT (object);      switch (param_id) {      case PROP_APP_NAME: -        g_value_set_string (value, control->priv->backend_data.app_name); +        g_value_set_string (value, context->priv->backend_data.app_name);          break;      case PROP_APP_ID: -        g_value_set_string (value, control->priv->backend_data.app_id); +        g_value_set_string (value, context->priv->backend_data.app_id);          break;      case PROP_APP_VERSION: -        g_value_set_string (value, control->priv->backend_data.app_version); +        g_value_set_string (value, context->priv->backend_data.app_version);          break;      case PROP_APP_ICON: -        g_value_set_string (value, control->priv->backend_data.app_icon); +        g_value_set_string (value, context->priv->backend_data.app_icon);          break;      case PROP_SERVER_ADDRESS: -        g_value_set_string (value, control->priv->backend_data.server_address); +        g_value_set_string (value, context->priv->backend_data.server_address);          break;      case PROP_STATE: -        g_value_set_enum (value, control->priv->state); +        g_value_set_enum (value, context->priv->state);          break; -    case PROP_DEFAULT_INPUT: -        g_value_set_object (value, mate_mixer_control_get_default_input_stream (control)); +    case PROP_DEFAULT_INPUT_STREAM: +        g_value_set_object (value, mate_mixer_context_get_default_input_stream (context));          break; -    case PROP_DEFAULT_OUTPUT: -        g_value_set_object (value, mate_mixer_control_get_default_output_stream (control)); +    case PROP_DEFAULT_OUTPUT_STREAM: +        g_value_set_object (value, mate_mixer_context_get_default_output_stream (context));          break;      default:          G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); @@ -393,36 +385,36 @@ mate_mixer_control_get_property (GObject    *object,  }  static void -mate_mixer_control_set_property (GObject      *object, +mate_mixer_context_set_property (GObject      *object,                                   guint         param_id,                                   const GValue *value,                                   GParamSpec   *pspec)  { -    MateMixerControl *control; +    MateMixerContext *context; -    control = MATE_MIXER_CONTROL (object); +    context = MATE_MIXER_CONTEXT (object);      switch (param_id) {      case PROP_APP_NAME: -        mate_mixer_control_set_app_name (control, g_value_get_string (value)); +        mate_mixer_context_set_app_name (context, g_value_get_string (value));          break;      case PROP_APP_ID: -        mate_mixer_control_set_app_id (control, g_value_get_string (value)); +        mate_mixer_context_set_app_id (context, g_value_get_string (value));          break;      case PROP_APP_VERSION: -        mate_mixer_control_set_app_version (control, g_value_get_string (value)); +        mate_mixer_context_set_app_version (context, g_value_get_string (value));          break;      case PROP_APP_ICON: -        mate_mixer_control_set_app_icon (control, g_value_get_string (value)); +        mate_mixer_context_set_app_icon (context, g_value_get_string (value));          break;      case PROP_SERVER_ADDRESS: -        mate_mixer_control_set_server_address (control, g_value_get_string (value)); +        mate_mixer_context_set_server_address (context, g_value_get_string (value));          break; -    case PROP_DEFAULT_INPUT: -        mate_mixer_control_set_default_input_stream (control, g_value_get_object (value)); +    case PROP_DEFAULT_INPUT_STREAM: +        mate_mixer_context_set_default_input_stream (context, g_value_get_object (value));          break; -    case PROP_DEFAULT_OUTPUT: -        mate_mixer_control_set_default_output_stream (control, g_value_get_object (value)); +    case PROP_DEFAULT_OUTPUT_STREAM: +        mate_mixer_context_set_default_output_stream (context, g_value_get_object (value));          break;      default:          G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); @@ -431,66 +423,66 @@ mate_mixer_control_set_property (GObject      *object,  }  static void -mate_mixer_control_init (MateMixerControl *control) +mate_mixer_context_init (MateMixerContext *context)  { -    control->priv = G_TYPE_INSTANCE_GET_PRIVATE (control, -                                                 MATE_MIXER_TYPE_CONTROL, -                                                 MateMixerControlPrivate); +    context->priv = G_TYPE_INSTANCE_GET_PRIVATE (context, +                                                 MATE_MIXER_TYPE_CONTEXT, +                                                 MateMixerContextPrivate);  }  static void -mate_mixer_control_dispose (GObject *object) +mate_mixer_context_dispose (GObject *object)  { -    close_control (MATE_MIXER_CONTROL (object)); +    close_context (MATE_MIXER_CONTEXT (object)); -    G_OBJECT_CLASS (mate_mixer_control_parent_class)->dispose (object); +    G_OBJECT_CLASS (mate_mixer_context_parent_class)->dispose (object);  }  static void -mate_mixer_control_finalize (GObject *object) +mate_mixer_context_finalize (GObject *object)  { -    MateMixerControl *control; +    MateMixerContext *context; -    control = MATE_MIXER_CONTROL (object); +    context = MATE_MIXER_CONTEXT (object); -    g_free (control->priv->backend_data.app_name); -    g_free (control->priv->backend_data.app_id); -    g_free (control->priv->backend_data.app_version); -    g_free (control->priv->backend_data.app_icon); -    g_free (control->priv->backend_data.server_address); +    g_free (context->priv->backend_data.app_name); +    g_free (context->priv->backend_data.app_id); +    g_free (context->priv->backend_data.app_version); +    g_free (context->priv->backend_data.app_icon); +    g_free (context->priv->backend_data.server_address); -    G_OBJECT_CLASS (mate_mixer_control_parent_class)->finalize (object); +    G_OBJECT_CLASS (mate_mixer_context_parent_class)->finalize (object);  }  /** - * mate_mixer_control_new: + * mate_mixer_context_new:   * - * Creates a new #MateMixerControl instance. + * Creates a new #MateMixerContext instance.   * - * Returns: a new #MateMixerControl instance or %NULL if the library has not + * Returns: a new #MateMixerContext instance or %NULL if the library has not   * been initialized using mate_mixer_init().   */ -MateMixerControl * -mate_mixer_control_new (void) +MateMixerContext * +mate_mixer_context_new (void)  {      if (mate_mixer_is_initialized () == FALSE) {          g_critical ("The library has not been initialized");          return NULL;      } -    return g_object_new (MATE_MIXER_TYPE_CONTROL, NULL); +    return g_object_new (MATE_MIXER_TYPE_CONTEXT, NULL);  }  /** - * mate_mixer_control_set_backend_type: - * @control: a #MateMixerControl + * mate_mixer_context_set_backend_type: + * @context: a #MateMixerContext   * @backend_type: the sound system backend to use   * - * Makes the #MateMixerControl use the given #MateMixerBackendType. + * Makes the #MateMixerContext use the given #MateMixerBackendType.   *   * By default the backend type is determined automatically. This function can - * be used before mate_mixer_control_open() to alter this behavior and make the - * @control use the given backend. + * be used before mate_mixer_context_open() to alter this behavior and make the + * @context use the given backend.   *   * This function will fail if support for the backend is not installed in   * the system or if the current state is either %MATE_MIXER_STATE_CONNECTING or @@ -499,27 +491,27 @@ mate_mixer_control_new (void)   * Returns: %TRUE on success or %FALSE on failure.   */  gboolean -mate_mixer_control_set_backend_type (MateMixerControl     *control, +mate_mixer_context_set_backend_type (MateMixerContext     *context,                                       MateMixerBackendType  backend_type)  {      MateMixerBackendModule     *module;      const GList                *modules;      const MateMixerBackendInfo *info; -    g_return_val_if_fail (MATE_MIXER_IS_CONTROL (control), FALSE); +    g_return_val_if_fail (MATE_MIXER_IS_CONTEXT (context), FALSE); -    if (control->priv->state == MATE_MIXER_STATE_CONNECTING || -        control->priv->state == MATE_MIXER_STATE_READY) +    if (context->priv->state == MATE_MIXER_STATE_CONNECTING || +        context->priv->state == MATE_MIXER_STATE_READY)          return FALSE; -    modules = mate_mixer_get_modules (); +    modules = _mate_mixer_get_modules ();      while (modules != NULL) {          module = MATE_MIXER_BACKEND_MODULE (modules->data);          info   = mate_mixer_backend_module_get_info (module);          if (info->backend_type == backend_type) { -            control->priv->backend_type = backend_type; +            context->priv->backend_type = backend_type;              return TRUE;          }          modules = modules->next; @@ -528,8 +520,8 @@ mate_mixer_control_set_backend_type (MateMixerControl     *control,  }  /** - * mate_mixer_control_set_app_name: - * @control: a #MateMixerControl + * mate_mixer_context_set_app_name: + * @context: a #MateMixerContext   * @app_name: the name of your application, or %NULL to unset   *   * Sets the name of the application. This feature is only supported in the @@ -542,27 +534,27 @@ mate_mixer_control_set_backend_type (MateMixerControl     *control,   * Returns: %TRUE on success or %FALSE on failure.   */  gboolean -mate_mixer_control_set_app_name (MateMixerControl *control, const gchar *app_name) +mate_mixer_context_set_app_name (MateMixerContext *context, const gchar *app_name)  { -    g_return_val_if_fail (MATE_MIXER_IS_CONTROL (control), FALSE); +    g_return_val_if_fail (MATE_MIXER_IS_CONTEXT (context), FALSE); -    if (control->priv->state == MATE_MIXER_STATE_CONNECTING || -        control->priv->state == MATE_MIXER_STATE_READY) +    if (context->priv->state == MATE_MIXER_STATE_CONNECTING || +        context->priv->state == MATE_MIXER_STATE_READY)          return FALSE; -    if (g_strcmp0 (control->priv->backend_data.app_name, app_name) != 0) { -        g_free (control->priv->backend_data.app_name); +    if (g_strcmp0 (context->priv->backend_data.app_name, app_name) != 0) { +        g_free (context->priv->backend_data.app_name); -        control->priv->backend_data.app_name = g_strdup (app_name); +        context->priv->backend_data.app_name = g_strdup (app_name); -        g_object_notify_by_pspec (G_OBJECT (control), properties[PROP_APP_NAME]); +        g_object_notify_by_pspec (G_OBJECT (context), properties[PROP_APP_NAME]);      }      return TRUE;  }  /** - * mate_mixer_control_set_app_id: - * @control: a #MateMixerControl + * mate_mixer_context_set_app_id: + * @context: a #MateMixerContext   * @app_id: the identifier of your application, or %NULL to unset   *   * Sets the identifier of the application (e.g. org.example.app). This feature @@ -575,27 +567,27 @@ mate_mixer_control_set_app_name (MateMixerControl *control, const gchar *app_nam   * Returns: %TRUE on success or %FALSE on failure.   */  gboolean -mate_mixer_control_set_app_id (MateMixerControl *control, const gchar *app_id) +mate_mixer_context_set_app_id (MateMixerContext *context, const gchar *app_id)  { -    g_return_val_if_fail (MATE_MIXER_IS_CONTROL (control), FALSE); +    g_return_val_if_fail (MATE_MIXER_IS_CONTEXT (context), FALSE); -    if (control->priv->state == MATE_MIXER_STATE_CONNECTING || -        control->priv->state == MATE_MIXER_STATE_READY) +    if (context->priv->state == MATE_MIXER_STATE_CONNECTING || +        context->priv->state == MATE_MIXER_STATE_READY)          return FALSE; -    if (g_strcmp0 (control->priv->backend_data.app_id, app_id) != 0) { -        g_free (control->priv->backend_data.app_id); +    if (g_strcmp0 (context->priv->backend_data.app_id, app_id) != 0) { +        g_free (context->priv->backend_data.app_id); -        control->priv->backend_data.app_id = g_strdup (app_id); +        context->priv->backend_data.app_id = g_strdup (app_id); -        g_object_notify_by_pspec (G_OBJECT (control), properties[PROP_APP_ID]); +        g_object_notify_by_pspec (G_OBJECT (context), properties[PROP_APP_ID]);      }      return TRUE;  }  /** - * mate_mixer_control_set_app_version: - * @control: a #MateMixerControl + * mate_mixer_context_set_app_version: + * @context: a #MateMixerContext   * @app_version: the version of your application, or %NULL to unset   *   * Sets the version of the application. This feature is only supported in the @@ -608,27 +600,27 @@ mate_mixer_control_set_app_id (MateMixerControl *control, const gchar *app_id)   * Returns: %TRUE on success or %FALSE on failure.   */  gboolean -mate_mixer_control_set_app_version (MateMixerControl *control, const gchar *app_version) +mate_mixer_context_set_app_version (MateMixerContext *context, const gchar *app_version)  { -    g_return_val_if_fail (MATE_MIXER_IS_CONTROL (control), FALSE); +    g_return_val_if_fail (MATE_MIXER_IS_CONTEXT (context), FALSE); -    if (control->priv->state == MATE_MIXER_STATE_CONNECTING || -        control->priv->state == MATE_MIXER_STATE_READY) +    if (context->priv->state == MATE_MIXER_STATE_CONNECTING || +        context->priv->state == MATE_MIXER_STATE_READY)          return FALSE; -    if (g_strcmp0 (control->priv->backend_data.app_version, app_version) != 0) { -        g_free (control->priv->backend_data.app_version); +    if (g_strcmp0 (context->priv->backend_data.app_version, app_version) != 0) { +        g_free (context->priv->backend_data.app_version); -        control->priv->backend_data.app_version = g_strdup (app_version); +        context->priv->backend_data.app_version = g_strdup (app_version); -        g_object_notify_by_pspec (G_OBJECT (control), properties[PROP_APP_VERSION]); +        g_object_notify_by_pspec (G_OBJECT (context), properties[PROP_APP_VERSION]);      }      return TRUE;  }  /** - * mate_mixer_control_set_app_icon: - * @control: a #MateMixerControl + * mate_mixer_context_set_app_icon: + * @context: a #MateMixerContext   * @app_icon: the XDG icon name of your application, or %NULL to unset   *   * Sets the XDG icon name of the application. This feature is only supported in @@ -641,27 +633,27 @@ mate_mixer_control_set_app_version (MateMixerControl *control, const gchar *app_   * Returns: %TRUE on success or %FALSE on failure.   */  gboolean -mate_mixer_control_set_app_icon (MateMixerControl *control, const gchar *app_icon) +mate_mixer_context_set_app_icon (MateMixerContext *context, const gchar *app_icon)  { -    g_return_val_if_fail (MATE_MIXER_IS_CONTROL (control), FALSE); +    g_return_val_if_fail (MATE_MIXER_IS_CONTEXT (context), FALSE); -    if (control->priv->state == MATE_MIXER_STATE_CONNECTING || -        control->priv->state == MATE_MIXER_STATE_READY) +    if (context->priv->state == MATE_MIXER_STATE_CONNECTING || +        context->priv->state == MATE_MIXER_STATE_READY)          return FALSE; -    if (g_strcmp0 (control->priv->backend_data.app_icon, app_icon) != 0) { -        g_free (control->priv->backend_data.app_icon); +    if (g_strcmp0 (context->priv->backend_data.app_icon, app_icon) != 0) { +        g_free (context->priv->backend_data.app_icon); -        control->priv->backend_data.app_icon = g_strdup (app_icon); +        context->priv->backend_data.app_icon = g_strdup (app_icon); -        g_object_notify_by_pspec (G_OBJECT (control), properties[PROP_APP_ICON]); +        g_object_notify_by_pspec (G_OBJECT (context), properties[PROP_APP_ICON]);      }      return TRUE;  }  /** - * mate_mixer_control_set_server_address: - * @control: a #MateMixerControl + * mate_mixer_context_set_server_address: + * @context: a #MateMixerContext   * @address: the address of the sound server to connect to or %NULL   *   * Sets the address of the sound server. This feature is only supported in the @@ -675,27 +667,27 @@ mate_mixer_control_set_app_icon (MateMixerControl *control, const gchar *app_ico   * Returns: %TRUE on success or %FALSE on failure.   */  gboolean -mate_mixer_control_set_server_address (MateMixerControl *control, const gchar *address) +mate_mixer_context_set_server_address (MateMixerContext *context, const gchar *address)  { -    g_return_val_if_fail (MATE_MIXER_IS_CONTROL (control), FALSE); +    g_return_val_if_fail (MATE_MIXER_IS_CONTEXT (context), FALSE); -    if (control->priv->state == MATE_MIXER_STATE_CONNECTING || -        control->priv->state == MATE_MIXER_STATE_READY) +    if (context->priv->state == MATE_MIXER_STATE_CONNECTING || +        context->priv->state == MATE_MIXER_STATE_READY)          return FALSE; -    if (g_strcmp0 (control->priv->backend_data.server_address, address) != 0) { -        g_free (control->priv->backend_data.server_address); +    if (g_strcmp0 (context->priv->backend_data.server_address, address) != 0) { +        g_free (context->priv->backend_data.server_address); -        control->priv->backend_data.server_address = g_strdup (address); +        context->priv->backend_data.server_address = g_strdup (address); -        g_object_notify_by_pspec (G_OBJECT (control), properties[PROP_SERVER_ADDRESS]); +        g_object_notify_by_pspec (G_OBJECT (context), properties[PROP_SERVER_ADDRESS]);      }      return TRUE;  }  /** - * mate_mixer_control_open: - * @control: a #MateMixerControl + * mate_mixer_context_open: + * @context: a #MateMixerContext   *   * Opens connection to a sound system. Unless the backend type was given   * beforehand, the library will find a working sound system automatically. @@ -706,12 +698,12 @@ mate_mixer_control_set_server_address (MateMixerControl *control, const gchar *a   * asynchronously.   *   * In case this function returns %TRUE, you should check the current state of - * the connection using mate_mixer_control_get_state(). If the current state + * the connection using mate_mixer_context_get_state(). If the current state   * is %MATE_MIXER_STATE_READY, the connection has been established successfully.   * Otherwise the state will be set to %MATE_MIXER_STATE_CONNECTING and the   * result of the operation will be determined asynchronously. You should wait   * for the state transition by connecting to the notification signal of the - * #MateMixerControl:state property. + * #MateMixerContext:state property.   *   * In case this function returns %FALSE, it is not possible to use the selected   * backend and the state will be set to %MATE_MIXER_STATE_FAILED. @@ -720,31 +712,31 @@ mate_mixer_control_set_server_address (MateMixerControl *control, const gchar *a   * or %FALSE on failure.   */  gboolean -mate_mixer_control_open (MateMixerControl *control) +mate_mixer_context_open (MateMixerContext *context)  {      MateMixerBackendModule     *module = NULL;      MateMixerState              state;      const GList                *modules;      const MateMixerBackendInfo *info = NULL; -    g_return_val_if_fail (MATE_MIXER_IS_CONTROL (control), FALSE); +    g_return_val_if_fail (MATE_MIXER_IS_CONTEXT (context), FALSE); -    if (control->priv->state == MATE_MIXER_STATE_CONNECTING || -        control->priv->state == MATE_MIXER_STATE_READY) +    if (context->priv->state == MATE_MIXER_STATE_CONNECTING || +        context->priv->state == MATE_MIXER_STATE_READY)          return FALSE;      /* We are going to choose the first backend to try. It will be either the one       * specified by the application or the one with the highest priority */ -    modules = mate_mixer_get_modules (); +    modules = _mate_mixer_get_modules (); -    if (control->priv->backend_type != MATE_MIXER_BACKEND_UNKNOWN) { +    if (context->priv->backend_type != MATE_MIXER_BACKEND_UNKNOWN) {          while (modules != NULL) {              const MateMixerBackendInfo *info;              module = MATE_MIXER_BACKEND_MODULE (modules->data);              info   = mate_mixer_backend_module_get_info (module); -            if (info->backend_type == control->priv->backend_type) +            if (info->backend_type == context->priv->backend_type)                  break;              module = NULL; @@ -756,110 +748,110 @@ mate_mixer_control_open (MateMixerControl *control)      }      if (module == NULL) {          /* Most likely the selected backend is not installed */ -        change_state (control, MATE_MIXER_STATE_FAILED); +        change_state (context, MATE_MIXER_STATE_FAILED);          return FALSE;      }      if (info == NULL)          info = mate_mixer_backend_module_get_info (module); -    control->priv->module  = g_object_ref (module); -    control->priv->backend = g_object_new (info->g_type, NULL); +    context->priv->module  = g_object_ref (module); +    context->priv->backend = g_object_new (info->g_type, NULL); -    mate_mixer_backend_set_data (control->priv->backend, &control->priv->backend_data); +    mate_mixer_backend_set_data (context->priv->backend, &context->priv->backend_data);      /* This transitional state is always present, it will change to MATE_MIXER_STATE_READY       * or MATE_MIXER_STATE_FAILED either instantly or asynchronously */ -    change_state (control, MATE_MIXER_STATE_CONNECTING); +    change_state (context, MATE_MIXER_STATE_CONNECTING);      /* The backend initialization might fail in case it is known right now that       * the backend is unusable */ -    if (mate_mixer_backend_open (control->priv->backend) == FALSE) { -        if (control->priv->backend_type == MATE_MIXER_BACKEND_UNKNOWN) { +    if (mate_mixer_backend_open (context->priv->backend) == FALSE) { +        if (context->priv->backend_type == MATE_MIXER_BACKEND_UNKNOWN) {              /* User didn't request a specific backend, so try another one */ -            return try_next_backend (control); +            return try_next_backend (context);          }          /* User requested a specific backend and it failed */ -        close_control (control); -        change_state (control, MATE_MIXER_STATE_FAILED); +        close_context (context); +        change_state (context, MATE_MIXER_STATE_FAILED);          return FALSE;      } -    state = mate_mixer_backend_get_state (control->priv->backend); +    state = mate_mixer_backend_get_state (context->priv->backend);      if (G_UNLIKELY (state != MATE_MIXER_STATE_READY &&                      state != MATE_MIXER_STATE_CONNECTING)) {          /* This would be a backend bug */          g_warn_if_reached (); -        if (control->priv->backend_type == MATE_MIXER_BACKEND_UNKNOWN) -            return try_next_backend (control); +        if (context->priv->backend_type == MATE_MIXER_BACKEND_UNKNOWN) +            return try_next_backend (context); -        close_control (control); -        change_state (control, MATE_MIXER_STATE_FAILED); +        close_context (context); +        change_state (context, MATE_MIXER_STATE_FAILED);          return FALSE;      } -    g_signal_connect (G_OBJECT (control->priv->backend), +    g_signal_connect (G_OBJECT (context->priv->backend),                        "notify::state",                        G_CALLBACK (on_backend_state_notify), -                      control); +                      context); -    change_state (control, state); +    change_state (context, state);      return TRUE;  }  /** - * mate_mixer_control_close: - * @control: a #MateMixerControl + * mate_mixer_context_close: + * @context: a #MateMixerContext   *   * Closes connection to the currently used sound system. The state will be   * set to %MATE_MIXER_STATE_IDLE.   */  void -mate_mixer_control_close (MateMixerControl *control) +mate_mixer_context_close (MateMixerContext *context)  { -    g_return_if_fail (MATE_MIXER_IS_CONTROL (control)); +    g_return_if_fail (MATE_MIXER_IS_CONTEXT (context)); -    close_control (control); -    change_state (control, MATE_MIXER_STATE_IDLE); +    close_context (context); +    change_state (context, MATE_MIXER_STATE_IDLE);  }  /** - * mate_mixer_control_get_state: - * @control: a #MateMixerControl + * mate_mixer_context_get_state: + * @context: a #MateMixerContext   * - * Gets the current backend connection state of the #MateMixerControl. + * Gets the current backend connection state of the #MateMixerContext.   *   * Returns: The current connection state.   */  MateMixerState -mate_mixer_control_get_state (MateMixerControl *control) +mate_mixer_context_get_state (MateMixerContext *context)  { -    g_return_val_if_fail (MATE_MIXER_IS_CONTROL (control), MATE_MIXER_STATE_UNKNOWN); +    g_return_val_if_fail (MATE_MIXER_IS_CONTEXT (context), MATE_MIXER_STATE_UNKNOWN); -    return control->priv->state; +    return context->priv->state;  }  /** - * mate_mixer_control_get_device: - * @control: a #MateMixerControl + * mate_mixer_context_get_device: + * @context: a #MateMixerContext   * @name: a device name   * - * Gets the devices with the given name. + * Gets the device with the given name.   *   * Returns: a #MateMixerDevice or %NULL if there is no such device.   */  MateMixerDevice * -mate_mixer_control_get_device (MateMixerControl *control, const gchar *name) +mate_mixer_context_get_device (MateMixerContext *context, const gchar *name)  { -    const GList *list; +    GList *list; -    g_return_val_if_fail (MATE_MIXER_IS_CONTROL (control), NULL); +    g_return_val_if_fail (MATE_MIXER_IS_CONTEXT (context), NULL);      g_return_val_if_fail (name != NULL, NULL); -    list = mate_mixer_control_list_devices (control); +    list = (GList *) mate_mixer_context_list_devices (context);      while (list != NULL) {          MateMixerDevice *device = MATE_MIXER_DEVICE (list->data); @@ -872,8 +864,8 @@ mate_mixer_control_get_device (MateMixerControl *control, const gchar *name)  }  /** - * mate_mixer_control_get_stream: - * @control: a #MateMixerControl + * mate_mixer_context_get_stream: + * @context: a #MateMixerContext   * @name: a stream name   *   * Gets the stream with the given name. @@ -881,14 +873,14 @@ mate_mixer_control_get_device (MateMixerControl *control, const gchar *name)   * Returns: a #MateMixerStream or %NULL if there is no such stream.   */  MateMixerStream * -mate_mixer_control_get_stream (MateMixerControl *control, const gchar *name) +mate_mixer_context_get_stream (MateMixerContext *context, const gchar *name)  { -    const GList *list; +    GList *list; -    g_return_val_if_fail (MATE_MIXER_IS_CONTROL (control), NULL); +    g_return_val_if_fail (MATE_MIXER_IS_CONTEXT (context), NULL);      g_return_val_if_fail (name != NULL, NULL); -    list = mate_mixer_control_list_streams (control); +    list = (GList *) mate_mixer_context_list_streams (context);      while (list != NULL) {          MateMixerStream *stream = MATE_MIXER_STREAM (list->data); @@ -901,21 +893,24 @@ mate_mixer_control_get_stream (MateMixerControl *control, const gchar *name)  }  /** - * mate_mixer_control_get_cached_stream: - * @control: a #MateMixerControl + * mate_mixer_context_get_stored_stream: + * @context: a #MateMixerContext   * @name: a stream name   * + * Gets the stream with the given name. + * + * Returns: a #MateMixerStream or %NULL if there is no such stream.   */  MateMixerStream * -mate_mixer_control_get_cached_stream (MateMixerControl *control, const gchar *name) +mate_mixer_context_get_stored_stream (MateMixerContext *context, const gchar *name)  { -    const GList *list; +    GList *list; -    g_return_val_if_fail (MATE_MIXER_IS_CONTROL (control), NULL); +    g_return_val_if_fail (MATE_MIXER_IS_CONTEXT (context), NULL);      g_return_val_if_fail (name != NULL, NULL); -    list = mate_mixer_control_list_cached_streams (control); -    while (list) { +    list = (GList *) mate_mixer_context_list_stored_streams (context); +    while (list != NULL) {          MateMixerStream *stream = MATE_MIXER_STREAM (list->data);          if (strcmp (name, mate_mixer_stream_get_name (stream)) == 0) @@ -927,90 +922,72 @@ mate_mixer_control_get_cached_stream (MateMixerControl *control, const gchar *na  }  /** - * mate_mixer_control_list_devices: - * @control: a #MateMixerControl + * mate_mixer_context_list_devices: + * @context: a #MateMixerContext   *   * Gets a list of devices. Each list item is a #MateMixerDevice representing a   * hardware or software sound device in the system.   * - * The returned #GList is owned by the #MateMixerControl and may be invalidated + * The returned #GList is owned by the #MateMixerContext and may be invalidated   * at any time.   *   * Returns: a #GList of all devices in the system or %NULL if there are none or   * you are not connected to a sound system.   */  const GList * -mate_mixer_control_list_devices (MateMixerControl *control) +mate_mixer_context_list_devices (MateMixerContext *context)  { -    g_return_val_if_fail (MATE_MIXER_IS_CONTROL (control), NULL); +    g_return_val_if_fail (MATE_MIXER_IS_CONTEXT (context), NULL); -    if (control->priv->state != MATE_MIXER_STATE_READY) +    if (context->priv->state != MATE_MIXER_STATE_READY)          return NULL; -    /* This list is cached here and invalidated when the backend notifies us -     * about a change */ -    if (control->priv->devices == NULL) -        control->priv->devices = -            mate_mixer_backend_list_devices (MATE_MIXER_BACKEND (control->priv->backend)); - -    return (const GList *) control->priv->devices; +    return mate_mixer_backend_list_devices (MATE_MIXER_BACKEND (context->priv->backend));  }  /** - * mate_mixer_control_list_streams: - * @control: a #MateMixerControl + * mate_mixer_context_list_streams: + * @context: a #MateMixerContext   *   * Gets a list of streams. Each list item is a #MateMixerStream representing an   * input or output of a sound device.   * - * The returned #GList is owned by the #MateMixerControl and may be invalidated + * The returned #GList is owned by the #MateMixerContext and may be invalidated   * at any time.   *   * Returns: a #GList of all streams in the system or %NULL if there are none or   * you are not connected to a sound system.   */  const GList * -mate_mixer_control_list_streams (MateMixerControl *control) +mate_mixer_context_list_streams (MateMixerContext *context)  { -    g_return_val_if_fail (MATE_MIXER_IS_CONTROL (control), NULL); +    g_return_val_if_fail (MATE_MIXER_IS_CONTEXT (context), NULL); -    if (control->priv->state != MATE_MIXER_STATE_READY) +    if (context->priv->state != MATE_MIXER_STATE_READY)          return NULL; -    /* This list is cached here and invalidated when the backend notifies us -     * about a change */ -    if (control->priv->streams == NULL) -        control->priv->streams = -            mate_mixer_backend_list_streams (MATE_MIXER_BACKEND (control->priv->backend)); - -    return (const GList *) control->priv->streams; +    return mate_mixer_backend_list_streams (MATE_MIXER_BACKEND (context->priv->backend));  }  /** - * mate_mixer_control_list_cached_streams: - * @control: a #MateMixerControl + * mate_mixer_context_list_stored_streams: + * @context: a #MateMixerContext   *   */  const GList * -mate_mixer_control_list_cached_streams (MateMixerControl *control) +mate_mixer_context_list_stored_streams (MateMixerContext *context)  { -    g_return_val_if_fail (MATE_MIXER_IS_CONTROL (control), NULL); +    g_return_val_if_fail (MATE_MIXER_IS_CONTEXT (context), NULL); -    if (control->priv->state != MATE_MIXER_STATE_READY) +    if (context->priv->state != MATE_MIXER_STATE_READY)          return NULL; -    /* This list is cached here and invalidated when the backend notifies us -     * about a change */ -    if (control->priv->cached_streams == NULL) -        control->priv->cached_streams = -            mate_mixer_backend_list_cached_streams (MATE_MIXER_BACKEND (control->priv->backend)); - -    return (const GList *) control->priv->cached_streams; +    return mate_mixer_backend_list_stored_streams (MATE_MIXER_BACKEND (context->priv->backend));  }  /** - * mate_mixer_control_get_default_input_stream: - * @control: a #MateMixerControl + * mate_mixer_context_get_default_input_stream: + * @context: a #MateMixerContext   *   * Gets the default input stream. The returned stream is where sound input is   * directed to by default. @@ -1019,19 +996,19 @@ mate_mixer_control_list_cached_streams (MateMixerControl *control)   * the system.   */  MateMixerStream * -mate_mixer_control_get_default_input_stream (MateMixerControl *control) +mate_mixer_context_get_default_input_stream (MateMixerContext *context)  { -    g_return_val_if_fail (MATE_MIXER_IS_CONTROL (control), NULL); +    g_return_val_if_fail (MATE_MIXER_IS_CONTEXT (context), NULL); -    if (control->priv->state != MATE_MIXER_STATE_READY) +    if (context->priv->state != MATE_MIXER_STATE_READY)          return NULL; -    return mate_mixer_backend_get_default_input_stream (control->priv->backend); +    return mate_mixer_backend_get_default_input_stream (context->priv->backend);  }  /** - * mate_mixer_control_set_default_input_stream: - * @control: a #MateMixerControl + * mate_mixer_context_set_default_input_stream: + * @context: a #MateMixerContext   * @stream: a #MateMixerStream to set as the default input stream   *   * Changes the default input stream in the system. The @stream must be an @@ -1040,13 +1017,13 @@ mate_mixer_control_get_default_input_stream (MateMixerControl *control)   * Returns: %TRUE on success or %FALSE on failure.   */  gboolean -mate_mixer_control_set_default_input_stream (MateMixerControl *control, +mate_mixer_context_set_default_input_stream (MateMixerContext *context,                                               MateMixerStream  *stream)  { -    g_return_val_if_fail (MATE_MIXER_IS_CONTROL (control), FALSE); +    g_return_val_if_fail (MATE_MIXER_IS_CONTEXT (context), FALSE);      g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), FALSE); -    if (control->priv->state != MATE_MIXER_STATE_READY) +    if (context->priv->state != MATE_MIXER_STATE_READY)          return FALSE;      if (MATE_MIXER_IS_CLIENT_STREAM (stream)) { @@ -1058,12 +1035,12 @@ mate_mixer_control_set_default_input_stream (MateMixerControl *control,          return FALSE;      } -    return mate_mixer_backend_set_default_input_stream (control->priv->backend, stream); +    return mate_mixer_backend_set_default_input_stream (context->priv->backend, stream);  }  /** - * mate_mixer_control_get_default_output_stream: - * @control: a #MateMixerControl + * mate_mixer_context_get_default_output_stream: + * @context: a #MateMixerContext   *   * Gets the default output stream. The returned stream is where sound output is   * directed to by default. @@ -1072,19 +1049,19 @@ mate_mixer_control_set_default_input_stream (MateMixerControl *control,   * the system.   */  MateMixerStream * -mate_mixer_control_get_default_output_stream (MateMixerControl *control) +mate_mixer_context_get_default_output_stream (MateMixerContext *context)  { -    g_return_val_if_fail (MATE_MIXER_IS_CONTROL (control), NULL); +    g_return_val_if_fail (MATE_MIXER_IS_CONTEXT (context), NULL); -    if (control->priv->state != MATE_MIXER_STATE_READY) +    if (context->priv->state != MATE_MIXER_STATE_READY)          return NULL; -    return mate_mixer_backend_get_default_output_stream (control->priv->backend); +    return mate_mixer_backend_get_default_output_stream (context->priv->backend);  }  /** - * mate_mixer_control_set_default_output_stream: - * @control: a #MateMixerControl + * mate_mixer_context_set_default_output_stream: + * @context: a #MateMixerContext   * @stream: a #MateMixerStream to set as the default output stream   *   * Changes the default output stream in the system. The @stream must be an @@ -1093,13 +1070,13 @@ mate_mixer_control_get_default_output_stream (MateMixerControl *control)   * Returns: %TRUE on success or %FALSE on failure.   */  gboolean -mate_mixer_control_set_default_output_stream (MateMixerControl *control, -                                              MateMixerStream  *stream) +mate_mixer_context_set_default_output_stream (MateMixerContext *context, +                                              MateMixerStream *stream)  { -    g_return_val_if_fail (MATE_MIXER_IS_CONTROL (control), FALSE); +    g_return_val_if_fail (MATE_MIXER_IS_CONTEXT (context), FALSE);      g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), FALSE); -    if (control->priv->state != MATE_MIXER_STATE_READY) +    if (context->priv->state != MATE_MIXER_STATE_READY)          return FALSE;      if (MATE_MIXER_IS_CLIENT_STREAM (stream)) { @@ -1111,12 +1088,12 @@ mate_mixer_control_set_default_output_stream (MateMixerControl *control,          return FALSE;      } -    return mate_mixer_backend_set_default_output_stream (control->priv->backend, stream); +    return mate_mixer_backend_set_default_output_stream (context->priv->backend, stream);  }  /** - * mate_mixer_control_get_backend_name: - * @control: a #MateMixerControl + * mate_mixer_context_get_backend_name: + * @context: a #MateMixerContext   *   * Gets the name of the currently used backend. This function will not   * work until connected to a sound system. @@ -1124,19 +1101,19 @@ mate_mixer_control_set_default_output_stream (MateMixerControl *control,   * Returns: the name or %NULL on error.   */  const gchar * -mate_mixer_control_get_backend_name (MateMixerControl *control) +mate_mixer_context_get_backend_name (MateMixerContext *context)  { -    g_return_val_if_fail (MATE_MIXER_IS_CONTROL (control), NULL); +    g_return_val_if_fail (MATE_MIXER_IS_CONTEXT (context), NULL); -    if (control->priv->backend_chosen == FALSE) +    if (context->priv->backend_chosen == FALSE)          return NULL; -    return mate_mixer_backend_module_get_info (control->priv->module)->name; +    return mate_mixer_backend_module_get_info (context->priv->module)->name;  }  /** - * mate_mixer_control_get_backend_type: - * @control: a #MateMixerControl + * mate_mixer_context_get_backend_type: + * @context: a #MateMixerContext   *   * Gets the type of the currently used backend. This function will not   * work until connected to a sound system. @@ -1144,55 +1121,61 @@ mate_mixer_control_get_backend_name (MateMixerControl *control)   * Returns: the backend type or %MATE_MIXER_BACKEND_UNKNOWN on error.   */  MateMixerBackendType -mate_mixer_control_get_backend_type (MateMixerControl *control) +mate_mixer_context_get_backend_type (MateMixerContext *context)  { -    g_return_val_if_fail (MATE_MIXER_IS_CONTROL (control), MATE_MIXER_BACKEND_UNKNOWN); +    g_return_val_if_fail (MATE_MIXER_IS_CONTEXT (context), MATE_MIXER_BACKEND_UNKNOWN); -    if (control->priv->backend_chosen == FALSE) +    if (context->priv->backend_chosen == FALSE)          return MATE_MIXER_BACKEND_UNKNOWN; -    return mate_mixer_backend_module_get_info (control->priv->module)->backend_type; +    return mate_mixer_backend_module_get_info (context->priv->module)->backend_type; +} + +/** + * mate_mixer_context_get_backend_flags: + * @context: a #MateMixerContext + */ +MateMixerBackendFlags +mate_mixer_context_get_backend_flags (MateMixerContext *context) +{ +    g_return_val_if_fail (MATE_MIXER_IS_CONTEXT (context), MATE_MIXER_BACKEND_NO_FLAGS); + +    return mate_mixer_backend_get_flags (context->priv->backend);  }  static void  on_backend_state_notify (MateMixerBackend *backend,                           GParamSpec       *pspec, -                         MateMixerControl *control) +                         MateMixerContext *context)  {      MateMixerState state = mate_mixer_backend_get_state (backend);      switch (state) {      case MATE_MIXER_STATE_CONNECTING:          g_debug ("Backend %s changed state to CONNECTING", -                 mate_mixer_backend_module_get_info (control->priv->module)->name); +                 mate_mixer_backend_module_get_info (context->priv->module)->name); -        if (control->priv->backend_chosen == TRUE) { -            /* Invalidate cached data when reconnecting */ -            free_devices (control); -            free_streams (control); -            free_cached_streams (control); -        } -        change_state (control, state); +        change_state (context, state);          break;      case MATE_MIXER_STATE_READY:          g_debug ("Backend %s changed state to READY", -                 mate_mixer_backend_module_get_info (control->priv->module)->name); +                 mate_mixer_backend_module_get_info (context->priv->module)->name); -        change_state (control, state); +        change_state (context, state);          break;      case MATE_MIXER_STATE_FAILED:          g_debug ("Backend %s changed state to FAILED", -                 mate_mixer_backend_module_get_info (control->priv->module)->name); +                 mate_mixer_backend_module_get_info (context->priv->module)->name); -        if (control->priv->backend_type == MATE_MIXER_BACKEND_UNKNOWN) { +        if (context->priv->backend_type == MATE_MIXER_BACKEND_UNKNOWN) {              /* User didn't request a specific backend, so try another one */ -            try_next_backend (control); +            try_next_backend (context);          } else {              /* User requested a specific backend and it failed */ -            close_control (control); -            change_state (control, state); +            close_context (context); +            change_state (context, state);          }          break; @@ -1204,11 +1187,9 @@ on_backend_state_notify (MateMixerBackend *backend,  static void  on_backend_device_added (MateMixerBackend *backend,                           const gchar      *name, -                         MateMixerControl *control) +                         MateMixerContext *context)  { -    free_devices (control); - -    g_signal_emit (G_OBJECT (control), +    g_signal_emit (G_OBJECT (context),                     signals[DEVICE_ADDED],                     0,                     name); @@ -1217,11 +1198,9 @@ on_backend_device_added (MateMixerBackend *backend,  static void  on_backend_device_removed (MateMixerBackend *backend,                             const gchar      *name, -                           MateMixerControl *control) +                           MateMixerContext *context)  { -    free_devices (control); - -    g_signal_emit (G_OBJECT (control), +    g_signal_emit (G_OBJECT (context),                     signals[DEVICE_REMOVED],                     0,                     name); @@ -1230,11 +1209,9 @@ on_backend_device_removed (MateMixerBackend *backend,  static void  on_backend_stream_added (MateMixerBackend *backend,                           const gchar      *name, -                         MateMixerControl *control) +                         MateMixerContext *context)  { -    free_streams (control); - -    g_signal_emit (G_OBJECT (control), +    g_signal_emit (G_OBJECT (context),                     signals[STREAM_ADDED],                     0,                     name); @@ -1243,69 +1220,63 @@ on_backend_stream_added (MateMixerBackend *backend,  static void  on_backend_stream_removed (MateMixerBackend *backend,                             const gchar      *name, -                           MateMixerControl *control) +                           MateMixerContext *context)  { -    free_streams (control); - -    g_signal_emit (G_OBJECT (control), +    g_signal_emit (G_OBJECT (context),                     signals[STREAM_REMOVED],                     0,                     name);  }  static void -on_backend_cached_stream_added (MateMixerBackend *backend, +on_backend_stored_stream_added (MateMixerBackend *backend,                                  const gchar      *name, -                                MateMixerControl *control) +                                MateMixerContext *context)  { -    free_cached_streams (control); - -    g_signal_emit (G_OBJECT (control), -                   signals[CACHED_STREAM_ADDED], +    g_signal_emit (G_OBJECT (context), +                   signals[STORED_STREAM_ADDED],                     0,                     name);  }  static void -on_backend_cached_stream_removed (MateMixerBackend *backend, +on_backend_stored_stream_removed (MateMixerBackend *backend,                                    const gchar      *name, -                                  MateMixerControl *control) +                                  MateMixerContext *context)  { -    free_cached_streams (control); - -    g_signal_emit (G_OBJECT (control), -                   signals[CACHED_STREAM_REMOVED], +    g_signal_emit (G_OBJECT (context), +                   signals[STORED_STREAM_REMOVED],                     0,                     name);  }  static void -on_backend_default_input_notify (MateMixerBackend *backend, -                                 GParamSpec       *pspec, -                                 MateMixerControl *control) +on_backend_default_input_stream_notify (MateMixerBackend *backend, +                                        GParamSpec       *pspec, +                                        MateMixerContext *context)  { -    g_object_notify_by_pspec (G_OBJECT (control), properties[PROP_DEFAULT_INPUT]); +    g_object_notify_by_pspec (G_OBJECT (context), properties[PROP_DEFAULT_INPUT_STREAM]);  }  static void -on_backend_default_output_notify (MateMixerBackend *backend, -                                  GParamSpec       *pspec, -                                  MateMixerControl *control) +on_backend_default_output_stream_notify (MateMixerBackend *backend, +                                         GParamSpec       *pspec, +                                         MateMixerContext *context)  { -    g_object_notify_by_pspec (G_OBJECT (control), properties[PROP_DEFAULT_OUTPUT]); +    g_object_notify_by_pspec (G_OBJECT (context), properties[PROP_DEFAULT_OUTPUT_STREAM]);  }  static gboolean -try_next_backend (MateMixerControl *control) +try_next_backend (MateMixerContext *context)  {      const GList            *modules;      MateMixerBackendModule *module = NULL;      MateMixerState          state; -    modules = mate_mixer_get_modules (); +    modules = _mate_mixer_get_modules ();      while (modules != NULL) { -        if (control->priv->module == modules->data) { +        if (context->priv->module == modules->data) {              /* Found the last tested backend, try to use the next one with a lower               * priority unless we have reached the end of the list */              if (modules->next != NULL) @@ -1314,153 +1285,109 @@ try_next_backend (MateMixerControl *control)          }          modules = modules->next;      } -    close_control (control); +    close_context (context);      if (module == NULL) {          /* We have tried all the modules and all of them failed */ -        change_state (control, MATE_MIXER_STATE_FAILED); +        change_state (context, MATE_MIXER_STATE_FAILED);          return FALSE;      } -    control->priv->module  = g_object_ref (module); -    control->priv->backend = +    context->priv->module  = g_object_ref (module); +    context->priv->backend =          g_object_new (mate_mixer_backend_module_get_info (module)->g_type, NULL); -    mate_mixer_backend_set_data (control->priv->backend, &control->priv->backend_data); +    mate_mixer_backend_set_data (context->priv->backend, &context->priv->backend_data);      /* Try to open this backend and in case of failure keep trying until we find       * one that works or reach the end of the list */ -    if (mate_mixer_backend_open (control->priv->backend) == FALSE) -        return try_next_backend (control); +    if (mate_mixer_backend_open (context->priv->backend) == FALSE) +        return try_next_backend (context); -    state = mate_mixer_backend_get_state (control->priv->backend); +    state = mate_mixer_backend_get_state (context->priv->backend);      if (G_UNLIKELY (state != MATE_MIXER_STATE_READY &&                      state != MATE_MIXER_STATE_CONNECTING)) {          /* This would be a backend bug */          g_warn_if_reached (); -        return try_next_backend (control); +        return try_next_backend (context);      } -    g_signal_connect (G_OBJECT (control->priv->backend), +    g_signal_connect (G_OBJECT (context->priv->backend),                        "notify::state",                        G_CALLBACK (on_backend_state_notify), -                      control); +                      context); -    change_state (control, state); +    change_state (context, state);      return TRUE;  }  static void -change_state (MateMixerControl *control, MateMixerState state) +change_state (MateMixerContext *context, MateMixerState state)  { -    if (control->priv->state == state) +    if (context->priv->state == state)          return; -    control->priv->state = state; +    context->priv->state = state; -    if (state == MATE_MIXER_STATE_READY && control->priv->backend_chosen == FALSE) { +    if (state == MATE_MIXER_STATE_READY && context->priv->backend_chosen == FALSE) {          /* It is safe to connect to the backend signals after reaching the READY           * state, because the app is not allowed to query any data before that state;           * therefore we won't end up in an inconsistent state by caching a list and           * then missing a notification about a change in the list */ -        g_signal_connect (G_OBJECT (control->priv->backend), +        g_signal_connect (G_OBJECT (context->priv->backend),                            "device-added",                            G_CALLBACK (on_backend_device_added), -                          control); -        g_signal_connect (G_OBJECT (control->priv->backend), +                          context); +        g_signal_connect (G_OBJECT (context->priv->backend),                            "device-removed",                            G_CALLBACK (on_backend_device_removed), -                          control); -        g_signal_connect (G_OBJECT (control->priv->backend), +                          context); +        g_signal_connect (G_OBJECT (context->priv->backend),                            "stream-added",                            G_CALLBACK (on_backend_stream_added), -                          control); -        g_signal_connect (G_OBJECT (control->priv->backend), +                          context); +        g_signal_connect (G_OBJECT (context->priv->backend),                            "stream-removed",                            G_CALLBACK (on_backend_stream_removed), -                          control); -        g_signal_connect (G_OBJECT (control->priv->backend), -                          "cached-stream-added", -                          G_CALLBACK (on_backend_cached_stream_added), -                          control); -        g_signal_connect (G_OBJECT (control->priv->backend), -                          "cached-stream-removed", -                          G_CALLBACK (on_backend_cached_stream_removed), -                          control); - -        g_signal_connect (G_OBJECT (control->priv->backend), +                          context); +        g_signal_connect (G_OBJECT (context->priv->backend), +                          "stored-stream-added", +                          G_CALLBACK (on_backend_stored_stream_added), +                          context); +        g_signal_connect (G_OBJECT (context->priv->backend), +                          "stored-stream-removed", +                          G_CALLBACK (on_backend_stored_stream_removed), +                          context); + +        g_signal_connect (G_OBJECT (context->priv->backend),                            "notify::default-input", -                          G_CALLBACK (on_backend_default_input_notify), -                          control); -        g_signal_connect (G_OBJECT (control->priv->backend), +                          G_CALLBACK (on_backend_default_input_stream_notify), +                          context); +        g_signal_connect (G_OBJECT (context->priv->backend),                            "notify::default-output", -                          G_CALLBACK (on_backend_default_output_notify), -                          control); +                          G_CALLBACK (on_backend_default_output_stream_notify), +                          context); -        control->priv->backend_chosen = TRUE; +        context->priv->backend_chosen = TRUE;      } -    g_object_notify_by_pspec (G_OBJECT (control), properties[PROP_STATE]); -} - -static void -close_control (MateMixerControl *control) -{ -    free_backend (control); -    free_devices (control); -    free_streams (control); -    free_cached_streams (control); - -    g_clear_object (&control->priv->module); - -    control->priv->backend_chosen = FALSE; -} - -static void -free_backend (MateMixerControl *control) -{ -    if (control->priv->backend == NULL) -        return; - -    g_signal_handlers_disconnect_by_data (G_OBJECT (control->priv->backend), -                                          control); - -    mate_mixer_backend_close (control->priv->backend); - -    g_clear_object (&control->priv->backend); -} - -static void -free_devices (MateMixerControl *control) -{ -    if (control->priv->devices == NULL) -        return; - -    g_list_free_full (control->priv->devices, g_object_unref); - -    control->priv->devices = NULL; +    g_object_notify_by_pspec (G_OBJECT (context), properties[PROP_STATE]);  }  static void -free_streams (MateMixerControl *control) +close_context (MateMixerContext *context)  { -    if (control->priv->streams == NULL) -        return; - -    g_list_free_full (control->priv->streams, g_object_unref); +    if (context->priv->backend != NULL) { +        g_signal_handlers_disconnect_by_data (G_OBJECT (context->priv->backend), +                                              context); -    control->priv->streams = NULL; -} - -static void -free_cached_streams (MateMixerControl *control) -{ -    if (control->priv->cached_streams == NULL) -        return; +        mate_mixer_backend_close (context->priv->backend); +        g_clear_object (&context->priv->backend); +    } -    g_list_free_full (control->priv->cached_streams, g_object_unref); +    g_clear_object (&context->priv->module); -    control->priv->cached_streams = NULL; +    context->priv->backend_chosen = FALSE;  } diff --git a/libmatemixer/matemixer-context.h b/libmatemixer/matemixer-context.h new file mode 100644 index 0000000..3370570 --- /dev/null +++ b/libmatemixer/matemixer-context.h @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2014 Michal Ratajsky <[email protected]> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the licence, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef MATEMIXER_CONTEXT_H +#define MATEMIXER_CONTEXT_H + +#include <glib.h> +#include <glib-object.h> + +#include <libmatemixer/matemixer-enums.h> +#include <libmatemixer/matemixer-types.h> + +G_BEGIN_DECLS + +#define MATE_MIXER_TYPE_CONTEXT                 \ +        (mate_mixer_context_get_type ()) +#define MATE_MIXER_CONTEXT(o)                   \ +        (G_TYPE_CHECK_INSTANCE_CAST ((o), MATE_MIXER_TYPE_CONTEXT, MateMixerContext)) +#define MATE_MIXER_IS_CONTEXT(o)                \ +        (G_TYPE_CHECK_INSTANCE_TYPE ((o), MATE_MIXER_TYPE_CONTEXT)) +#define MATE_MIXER_CONTEXT_CLASS(k)             \ +        (G_TYPE_CHECK_CLASS_CAST ((k), MATE_MIXER_TYPE_CONTEXT, MateMixerContextClass)) +#define MATE_MIXER_IS_CONTEXT_CLASS(k)          \ +        (G_TYPE_CHECK_CLASS_TYPE ((k), MATE_MIXER_TYPE_CONTEXT)) +#define MATE_MIXER_CONTEXT_GET_CLASS(o)         \ +        (G_TYPE_INSTANCE_GET_CLASS ((o), MATE_MIXER_TYPE_CONTEXT, MateMixerContextClass)) + +typedef struct _MateMixerContextClass    MateMixerContextClass; +typedef struct _MateMixerContextPrivate  MateMixerContextPrivate; + +/** + * MateMixerContext: + * + * The #MateMixerContext structure contains only private data and should only + * be accessed using the provided API. + */ +struct _MateMixerContext +{ +    GObject parent; + +    /*< private >*/ +    MateMixerContextPrivate *priv; +}; + +/** + * MateMixerContextClass: + * + * The class structure of #MateMixerContext. + */ +struct _MateMixerContextClass +{ +    GObjectClass parent_class; + +    /*< private >*/ +    void (*device_added)          (MateMixerContext *context, +                                   const gchar      *name); +    void (*device_removed)        (MateMixerContext *context, +                                   const gchar      *name); +    void (*stream_added)          (MateMixerContext *context, +                                   const gchar      *name); +    void (*stream_removed)        (MateMixerContext *context, +                                   const gchar      *name); +    void (*stored_stream_added)   (MateMixerContext *context, +                                   const gchar      *name); +    void (*stored_stream_removed) (MateMixerContext *context, +                                   const gchar      *name); +}; + +GType                 mate_mixer_context_get_type                  (void) G_GNUC_CONST; + +MateMixerContext *    mate_mixer_context_new                       (void); + +gboolean              mate_mixer_context_set_backend_type          (MateMixerContext     *context, +                                                                    MateMixerBackendType  backend_type); +gboolean              mate_mixer_context_set_app_name              (MateMixerContext     *context, +                                                                    const gchar          *app_name); +gboolean              mate_mixer_context_set_app_id                (MateMixerContext     *context, +                                                                    const gchar          *app_id); +gboolean              mate_mixer_context_set_app_version           (MateMixerContext     *context, +                                                                    const gchar          *app_version); +gboolean              mate_mixer_context_set_app_icon              (MateMixerContext     *context, +                                                                    const gchar          *app_icon); +gboolean              mate_mixer_context_set_server_address        (MateMixerContext     *context, +                                                                    const gchar          *address); + +gboolean              mate_mixer_context_open                      (MateMixerContext     *context); +void                  mate_mixer_context_close                     (MateMixerContext     *context); + +MateMixerState        mate_mixer_context_get_state                 (MateMixerContext     *context); + +MateMixerDevice *     mate_mixer_context_get_device                (MateMixerContext     *context, +                                                                    const gchar          *name); +MateMixerStream *     mate_mixer_context_get_stream                (MateMixerContext     *context, +                                                                    const gchar          *name); +MateMixerStream *     mate_mixer_context_get_stored_stream         (MateMixerContext     *context, +                                                                    const gchar          *name); + +const GList *         mate_mixer_context_list_devices              (MateMixerContext     *context); +const GList *         mate_mixer_context_list_streams              (MateMixerContext     *context); +const GList *         mate_mixer_context_list_stored_streams       (MateMixerContext     *context); + +MateMixerStream  *    mate_mixer_context_get_default_input_stream  (MateMixerContext     *context); +gboolean              mate_mixer_context_set_default_input_stream  (MateMixerContext     *context, +                                                                    MateMixerStream      *stream); + +MateMixerStream  *    mate_mixer_context_get_default_output_stream (MateMixerContext     *context); +gboolean              mate_mixer_context_set_default_output_stream (MateMixerContext     *context, +                                                                    MateMixerStream      *stream); + +const gchar *         mate_mixer_context_get_backend_name          (MateMixerContext     *context); +MateMixerBackendType  mate_mixer_context_get_backend_type          (MateMixerContext     *context); +MateMixerBackendFlags mate_mixer_context_get_backend_flags         (MateMixerContext     *context); + +G_END_DECLS + +#endif /* MATEMIXER_CONTEXT_H */ diff --git a/libmatemixer/matemixer-control.h b/libmatemixer/matemixer-control.h deleted file mode 100644 index e6d3afa..0000000 --- a/libmatemixer/matemixer-control.h +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Copyright (C) 2014 Michal Ratajsky <[email protected]> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the licence, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/>. - */ - -#ifndef MATEMIXER_CONTROL_H -#define MATEMIXER_CONTROL_H - -#include <glib.h> -#include <glib-object.h> - -#include <libmatemixer/matemixer-device.h> -#include <libmatemixer/matemixer-enums.h> -#include <libmatemixer/matemixer-stream.h> - -G_BEGIN_DECLS - -#define MATE_MIXER_TYPE_CONTROL                 \ -        (mate_mixer_control_get_type ()) -#define MATE_MIXER_CONTROL(o)                   \ -        (G_TYPE_CHECK_INSTANCE_CAST ((o), MATE_MIXER_TYPE_CONTROL, MateMixerControl)) -#define MATE_MIXER_IS_CONTROL(o)                \ -        (G_TYPE_CHECK_INSTANCE_TYPE ((o), MATE_MIXER_TYPE_CONTROL)) -#define MATE_MIXER_CONTROL_CLASS(k)             \ -        (G_TYPE_CHECK_CLASS_CAST ((k), MATE_MIXER_TYPE_CONTROL, MateMixerControlClass)) -#define MATE_MIXER_IS_CONTROL_CLASS(k)          \ -        (G_TYPE_CHECK_CLASS_TYPE ((k), MATE_MIXER_TYPE_CONTROL)) -#define MATE_MIXER_CONTROL_GET_CLASS(o)         \ -        (G_TYPE_INSTANCE_GET_CLASS ((o), MATE_MIXER_TYPE_CONTROL, MateMixerControlClass)) - -typedef struct _MateMixerControl         MateMixerControl; -typedef struct _MateMixerControlClass    MateMixerControlClass; -typedef struct _MateMixerControlPrivate  MateMixerControlPrivate; - -/** - * MateMixerControl: - * - * The #MateMixerControl structure contains only private data and should only - * be accessed using the provided API. - */ -struct _MateMixerControl -{ -    GObject parent; - -    /*< private >*/ -    MateMixerControlPrivate *priv; -}; - -/** - * MateMixerControlClass: - * - * The class structure of #MateMixerControl. - */ -struct _MateMixerControlClass -{ -    GObjectClass parent_class; - -    /*< private >*/ -    /* Signals */ -    void (*device_added)            (MateMixerControl *control, -                                     const gchar      *name); -    void (*device_changed)          (MateMixerControl *control, -                                     const gchar      *name); -    void (*device_removed)          (MateMixerControl *control, -                                     const gchar      *name); -    void (*stream_added)            (MateMixerControl *control, -                                     const gchar      *name); -    void (*stream_changed)          (MateMixerControl *control, -                                     const gchar      *name); -    void (*stream_removed)          (MateMixerControl *control, -                                     const gchar      *name); -    void (*cached_stream_added)     (MateMixerControl *control, -                                     const gchar      *name); -    void (*cached_stream_changed)   (MateMixerControl *control, -                                     const gchar      *name); -    void (*cached_stream_removed)   (MateMixerControl *control, -                                     const gchar      *name); -}; - -GType                 mate_mixer_control_get_type                  (void) G_GNUC_CONST; - -MateMixerControl *    mate_mixer_control_new                       (void); - -gboolean              mate_mixer_control_set_backend_type          (MateMixerControl     *control, -                                                                    MateMixerBackendType  backend_type); -gboolean              mate_mixer_control_set_app_name              (MateMixerControl     *control, -                                                                    const gchar          *app_name); -gboolean              mate_mixer_control_set_app_id                (MateMixerControl     *control, -                                                                    const gchar          *app_id); -gboolean              mate_mixer_control_set_app_version           (MateMixerControl     *control, -                                                                    const gchar          *app_version); -gboolean              mate_mixer_control_set_app_icon              (MateMixerControl     *control, -                                                                    const gchar          *app_icon); -gboolean              mate_mixer_control_set_server_address        (MateMixerControl     *control, -                                                                    const gchar          *address); - -gboolean              mate_mixer_control_open                      (MateMixerControl     *control); -void                  mate_mixer_control_close                     (MateMixerControl     *control); - -MateMixerState        mate_mixer_control_get_state                 (MateMixerControl     *control); - -MateMixerDevice *     mate_mixer_control_get_device                (MateMixerControl     *control, -                                                                    const gchar          *name); -MateMixerStream *     mate_mixer_control_get_stream                (MateMixerControl     *control, -                                                                    const gchar          *name); -MateMixerStream *     mate_mixer_control_get_cached_stream         (MateMixerControl     *control, -                                                                    const gchar          *name); - -const GList *         mate_mixer_control_list_devices              (MateMixerControl     *control); -const GList *         mate_mixer_control_list_streams              (MateMixerControl     *control); -const GList *         mate_mixer_control_list_cached_streams       (MateMixerControl     *control); - -MateMixerStream  *    mate_mixer_control_get_default_input_stream  (MateMixerControl     *control); -gboolean              mate_mixer_control_set_default_input_stream  (MateMixerControl     *control, -                                                                    MateMixerStream      *stream); - -MateMixerStream  *    mate_mixer_control_get_default_output_stream (MateMixerControl     *control); -gboolean              mate_mixer_control_set_default_output_stream (MateMixerControl     *control, -                                                                    MateMixerStream      *stream); - -const gchar *         mate_mixer_control_get_backend_name          (MateMixerControl     *control); -MateMixerBackendType  mate_mixer_control_get_backend_type          (MateMixerControl     *control); - -G_END_DECLS - -#endif /* MATEMIXER_CONTROL_H */ diff --git a/libmatemixer/matemixer-device-profile-private.h b/libmatemixer/matemixer-device-profile-private.h index 403c7d7..44f2853 100644 --- a/libmatemixer/matemixer-device-profile-private.h +++ b/libmatemixer/matemixer-device-profile-private.h @@ -24,20 +24,20 @@  G_BEGIN_DECLS -MateMixerDeviceProfile *_mate_mixer_device_profile_new                       (const gchar            *name, -                                                                              const gchar            *description, -                                                                              guint                   priority, -                                                                              guint                   input_streams, -                                                                              guint                   output_streams); - -gboolean                _mate_mixer_device_profile_update_description        (MateMixerDeviceProfile *profile, -                                                                              const gchar            *description); -gboolean                _mate_mixer_device_profile_update_priority           (MateMixerDeviceProfile *profile, -                                                                              guint                   priority); -gboolean                _mate_mixer_device_profile_update_num_input_streams  (MateMixerDeviceProfile *profile, -                                                                              guint                   num); -gboolean                _mate_mixer_device_profile_update_num_output_streams (MateMixerDeviceProfile *profile, -                                                                              guint                   num); +MateMixerDeviceProfile *_mate_mixer_device_profile_new                    (const gchar            *name, +                                                                           const gchar            *description, +                                                                           guint                   priority, +                                                                           guint                   input_streams, +                                                                           guint                   output_streams); + +gboolean                _mate_mixer_device_profile_set_label              (MateMixerDeviceProfile *profile, +                                                                           const gchar            *label); +gboolean                _mate_mixer_device_profile_set_priority           (MateMixerDeviceProfile *profile, +                                                                           guint                   priority); +gboolean                _mate_mixer_device_profile_set_num_input_streams  (MateMixerDeviceProfile *profile, +                                                                           guint                   num); +gboolean                _mate_mixer_device_profile_set_num_output_streams (MateMixerDeviceProfile *profile, +                                                                           guint                   num);  G_END_DECLS diff --git a/libmatemixer/matemixer-device-profile.c b/libmatemixer/matemixer-device-profile.c index 0485740..d841ff2 100644 --- a/libmatemixer/matemixer-device-profile.c +++ b/libmatemixer/matemixer-device-profile.c @@ -30,7 +30,7 @@  struct _MateMixerDeviceProfilePrivate  {      gchar *name; -    gchar *description; +    gchar *label;      guint  priority;      guint  num_input_streams;      guint  num_output_streams; @@ -39,7 +39,7 @@ struct _MateMixerDeviceProfilePrivate  enum {      PROP_0,      PROP_NAME, -    PROP_DESCRIPTION, +    PROP_LABEL,      PROP_PRIORITY,      PROP_NUM_INPUT_STREAMS,      PROP_NUM_OUTPUT_STREAMS, @@ -83,10 +83,10 @@ mate_mixer_device_profile_class_init (MateMixerDeviceProfileClass *klass)                               G_PARAM_READWRITE |                               G_PARAM_STATIC_STRINGS); -    properties[PROP_DESCRIPTION] = -        g_param_spec_string ("description", -                             "Description", -                             "Description of the profile", +    properties[PROP_LABEL] = +        g_param_spec_string ("label", +                             "Label", +                             "Label of the profile",                               NULL,                               G_PARAM_CONSTRUCT_ONLY |                               G_PARAM_READWRITE | @@ -144,18 +144,23 @@ mate_mixer_device_profile_get_property (GObject    *object,      case PROP_NAME:          g_value_set_string (value, profile->priv->name);          break; -    case PROP_DESCRIPTION: -        g_value_set_string (value, profile->priv->description); + +    case PROP_LABEL: +        g_value_set_string (value, profile->priv->label);          break; +      case PROP_PRIORITY:          g_value_set_uint (value, profile->priv->priority);          break; +      case PROP_NUM_INPUT_STREAMS:          g_value_set_uint (value, profile->priv->num_input_streams);          break; +      case PROP_NUM_OUTPUT_STREAMS:          g_value_set_uint (value, profile->priv->num_output_streams);          break; +      default:          G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);          break; @@ -177,19 +182,24 @@ mate_mixer_device_profile_set_property (GObject      *object,          /* Construct-only string */          profile->priv->name = g_strdup (g_value_get_string (value));          break; -    case PROP_DESCRIPTION: + +    case PROP_LABEL:          /* Construct-only string */ -        profile->priv->description = g_strdup (g_value_get_string (value)); +        profile->priv->label = g_strdup (g_value_get_string (value));          break; +      case PROP_PRIORITY:          profile->priv->priority = g_value_get_uint (value);          break; +      case PROP_NUM_INPUT_STREAMS:          profile->priv->num_input_streams = g_value_get_uint (value);          break; +      case PROP_NUM_OUTPUT_STREAMS:          profile->priv->num_output_streams = g_value_get_uint (value);          break; +      default:          G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);          break; @@ -212,7 +222,7 @@ mate_mixer_device_profile_finalize (GObject *object)      profile = MATE_MIXER_DEVICE_PROFILE (object);      g_free (profile->priv->name); -    g_free (profile->priv->description); +    g_free (profile->priv->label);      G_OBJECT_CLASS (mate_mixer_device_profile_parent_class)->finalize (object);  } @@ -230,15 +240,15 @@ mate_mixer_device_profile_get_name (MateMixerDeviceProfile *profile)  }  /** - * mate_mixer_device_profile_get_description: + * mate_mixer_device_profile_get_label:   * @profile: a #MateMixerDeviceProfile   */  const gchar * -mate_mixer_device_profile_get_description (MateMixerDeviceProfile *profile) +mate_mixer_device_profile_get_label (MateMixerDeviceProfile *profile)  {      g_return_val_if_fail (MATE_MIXER_IS_DEVICE_PROFILE (profile), NULL); -    return profile->priv->description; +    return profile->priv->label;  }  /** @@ -279,14 +289,14 @@ mate_mixer_device_profile_get_num_output_streams (MateMixerDeviceProfile *profil  MateMixerDeviceProfile *  _mate_mixer_device_profile_new (const gchar *name, -                                const gchar *description, +                                const gchar *label,                                  guint        priority,                                  guint        input_streams,                                  guint        output_streams)  {      return g_object_new (MATE_MIXER_TYPE_DEVICE_PROFILE,                           "name", name, -                         "description", description, +                         "label", label,                           "priority", priority,                           "num-input-streams", input_streams,                           "num-output-streams", output_streams, @@ -294,17 +304,17 @@ _mate_mixer_device_profile_new (const gchar *name,  }  gboolean -_mate_mixer_device_profile_update_description (MateMixerDeviceProfile *profile, -                                               const gchar            *description) +_mate_mixer_device_profile_set_label (MateMixerDeviceProfile *profile, +                                      const gchar            *label)  {      g_return_val_if_fail (MATE_MIXER_IS_DEVICE_PROFILE (profile), FALSE); -    if (g_strcmp0 (profile->priv->description, description) != 0) { -        g_free (profile->priv->description); +    if (g_strcmp0 (profile->priv->label, label) != 0) { +        g_free (profile->priv->label); -        profile->priv->description = g_strdup (description); +        profile->priv->label = g_strdup (label); -        g_object_notify_by_pspec (G_OBJECT (profile), properties[PROP_DESCRIPTION]); +        g_object_notify_by_pspec (G_OBJECT (profile), properties[PROP_LABEL]);          return TRUE;      } @@ -312,8 +322,8 @@ _mate_mixer_device_profile_update_description (MateMixerDeviceProfile *profile,  }  gboolean -_mate_mixer_device_profile_update_priority (MateMixerDeviceProfile *profile, -                                            guint                   priority) +_mate_mixer_device_profile_set_priority (MateMixerDeviceProfile *profile, +                                         guint                   priority)  {      g_return_val_if_fail (MATE_MIXER_IS_DEVICE_PROFILE (profile), FALSE); @@ -328,8 +338,8 @@ _mate_mixer_device_profile_update_priority (MateMixerDeviceProfile *profile,  }  gboolean -_mate_mixer_device_profile_update_num_input_streams (MateMixerDeviceProfile *profile, -                                                     guint                   num) +_mate_mixer_device_profile_set_num_input_streams (MateMixerDeviceProfile *profile, +                                                  guint                   num)  {      g_return_val_if_fail (MATE_MIXER_IS_DEVICE_PROFILE (profile), FALSE); @@ -344,8 +354,8 @@ _mate_mixer_device_profile_update_num_input_streams (MateMixerDeviceProfile *pro  }  gboolean -_mate_mixer_device_profile_update_num_output_streams (MateMixerDeviceProfile *profile, -                                                      guint                   num) +_mate_mixer_device_profile_set_num_output_streams (MateMixerDeviceProfile *profile, +                                                   guint                   num)  {      g_return_val_if_fail (MATE_MIXER_IS_DEVICE_PROFILE (profile), FALSE); diff --git a/libmatemixer/matemixer-device-profile.h b/libmatemixer/matemixer-device-profile.h index e8fae19..8e4221a 100644 --- a/libmatemixer/matemixer-device-profile.h +++ b/libmatemixer/matemixer-device-profile.h @@ -20,6 +20,7 @@  #include <glib.h>  #include <glib-object.h> +#include <libmatemixer/matemixer-types.h>  G_BEGIN_DECLS @@ -36,7 +37,6 @@ G_BEGIN_DECLS  #define MATE_MIXER_DEVICE_PROFILE_GET_CLASS(o)         \          (G_TYPE_INSTANCE_GET_CLASS ((o), MATE_MIXER_TYPE_DEVICE_PROFILE, MateMixerDeviceProfileClass)) -typedef struct _MateMixerDeviceProfile         MateMixerDeviceProfile;  typedef struct _MateMixerDeviceProfileClass    MateMixerDeviceProfileClass;  typedef struct _MateMixerDeviceProfilePrivate  MateMixerDeviceProfilePrivate; @@ -56,8 +56,9 @@ struct _MateMixerDeviceProfileClass  GType        mate_mixer_device_profile_get_type               (void) G_GNUC_CONST;  const gchar *mate_mixer_device_profile_get_name               (MateMixerDeviceProfile *profile); -const gchar *mate_mixer_device_profile_get_description        (MateMixerDeviceProfile *profile); +const gchar *mate_mixer_device_profile_get_label              (MateMixerDeviceProfile *profile);  guint        mate_mixer_device_profile_get_priority           (MateMixerDeviceProfile *profile); +  guint        mate_mixer_device_profile_get_num_input_streams  (MateMixerDeviceProfile *profile);  guint        mate_mixer_device_profile_get_num_output_streams (MateMixerDeviceProfile *profile); diff --git a/libmatemixer/matemixer-device.c b/libmatemixer/matemixer-device.c index 87517d6..229110f 100644 --- a/libmatemixer/matemixer-device.c +++ b/libmatemixer/matemixer-device.c @@ -15,12 +15,14 @@   * License along with this library; if not, see <http://www.gnu.org/licenses/>.   */ +#include <string.h>  #include <glib.h>  #include <glib-object.h>  #include "matemixer-device.h"  #include "matemixer-device-profile.h" -#include "matemixer-port.h" +#include "matemixer-stream.h" +#include "matemixer-switch.h"  /**   * SECTION:matemixer-device @@ -28,45 +30,270 @@   * @include: libmatemixer/matemixer.h   */ -G_DEFINE_INTERFACE (MateMixerDevice, mate_mixer_device, G_TYPE_OBJECT) +struct _MateMixerDevicePrivate +{ +    gchar                  *name; +    gchar                  *label; +    gchar                  *icon; +    GList                  *streams; +    GList                  *switches; +    GList                  *profiles; +    MateMixerDeviceProfile *profile; +}; + +enum { +    PROP_0, +    PROP_NAME, +    PROP_LABEL, +    PROP_ICON, +    PROP_ACTIVE_PROFILE, +    N_PROPERTIES +}; + +static GParamSpec *properties[N_PROPERTIES] = { NULL, }; + +enum { +    STREAM_ADDED, +    STREAM_REMOVED, +    SWITCH_ADDED, +    SWITCH_REMOVED, +    N_SIGNALS +}; + +static guint signals[N_SIGNALS] = { 0, }; + +static void mate_mixer_device_class_init   (MateMixerDeviceClass *klass); + +static void mate_mixer_device_get_property (GObject              *object, +                                            guint                 param_id, +                                            GValue               *value, +                                            GParamSpec           *pspec); +static void mate_mixer_device_set_property (GObject              *object, +                                            guint                 param_id, +                                            const GValue         *value, +                                            GParamSpec           *pspec); + +static void mate_mixer_device_init         (MateMixerDevice      *device); +static void mate_mixer_device_dispose      (GObject              *object); +static void mate_mixer_device_finalize     (GObject              *object); + +G_DEFINE_ABSTRACT_TYPE (MateMixerDevice, mate_mixer_device, G_TYPE_OBJECT) + +static MateMixerStream *       mate_mixer_device_real_get_stream  (MateMixerDevice *device, +                                                                   const gchar     *name); +static MateMixerSwitch *       mate_mixer_device_real_get_switch  (MateMixerDevice *device, +                                                                   const gchar     *name); +static MateMixerDeviceProfile *mate_mixer_device_real_get_profile (MateMixerDevice *device, +                                                                   const gchar     *name); + +static void +mate_mixer_device_class_init (MateMixerDeviceClass *klass) +{ +    GObjectClass *object_class; + +    klass->get_stream  = mate_mixer_device_real_get_stream; +    klass->get_switch  = mate_mixer_device_real_get_switch; +    klass->get_profile = mate_mixer_device_real_get_profile; + +    object_class = G_OBJECT_CLASS (klass); +    object_class->dispose      = mate_mixer_device_dispose; +    object_class->finalize     = mate_mixer_device_finalize; +    object_class->get_property = mate_mixer_device_get_property; +    object_class->set_property = mate_mixer_device_set_property; + +    properties[PROP_NAME] = +        g_param_spec_string ("name", +                             "Name", +                             "Name of the device", +                             NULL, +                             G_PARAM_READWRITE | +                             G_PARAM_CONSTRUCT_ONLY | +                             G_PARAM_STATIC_STRINGS); + +    properties[PROP_LABEL] = +        g_param_spec_string ("label", +                             "Label", +                             "Label of the device", +                             NULL, +                             G_PARAM_READWRITE | +                             G_PARAM_CONSTRUCT_ONLY | +                             G_PARAM_STATIC_STRINGS); + +    properties[PROP_ICON] = +        g_param_spec_string ("icon", +                             "Icon", +                             "Name of the sound device icon", +                             NULL, +                             G_PARAM_READWRITE | +                             G_PARAM_CONSTRUCT_ONLY | +                             G_PARAM_STATIC_STRINGS); + +    properties[PROP_ACTIVE_PROFILE] = +        g_param_spec_object ("active-profile", +                             "Active profile", +                             "The currently active profile of the device", +                             MATE_MIXER_TYPE_DEVICE_PROFILE, +                             G_PARAM_READABLE | +                             G_PARAM_STATIC_STRINGS); + +    g_object_class_install_properties (object_class, N_PROPERTIES, properties); + +    signals[STREAM_ADDED] = +        g_signal_new ("stream-added", +                      G_TYPE_FROM_CLASS (object_class), +                      G_SIGNAL_RUN_LAST, +                      G_STRUCT_OFFSET (MateMixerDeviceClass, stream_added), +                      NULL, +                      NULL, +                      g_cclosure_marshal_VOID__STRING, +                      G_TYPE_NONE, +                      1, +                      G_TYPE_STRING); + +    signals[STREAM_REMOVED] = +        g_signal_new ("stream-removed", +                      G_TYPE_FROM_CLASS (object_class), +                      G_SIGNAL_RUN_LAST, +                      G_STRUCT_OFFSET (MateMixerDeviceClass, stream_removed), +                      NULL, +                      NULL, +                      g_cclosure_marshal_VOID__STRING, +                      G_TYPE_NONE, +                      1, +                      G_TYPE_STRING); + +    signals[SWITCH_ADDED] = +        g_signal_new ("switch-added", +                      G_TYPE_FROM_CLASS (object_class), +                      G_SIGNAL_RUN_LAST, +                      G_STRUCT_OFFSET (MateMixerDeviceClass, switch_added), +                      NULL, +                      NULL, +                      g_cclosure_marshal_VOID__STRING, +                      G_TYPE_NONE, +                      1, +                      G_TYPE_STRING); + +    signals[SWITCH_REMOVED] = +        g_signal_new ("switch-removed", +                      G_TYPE_FROM_CLASS (object_class), +                      G_SIGNAL_RUN_LAST, +                      G_STRUCT_OFFSET (MateMixerDeviceClass, switch_removed), +                      NULL, +                      NULL, +                      g_cclosure_marshal_VOID__STRING, +                      G_TYPE_NONE, +                      1, +                      G_TYPE_STRING); + +    g_type_class_add_private (object_class, sizeof (MateMixerDevicePrivate)); +} + +static void +mate_mixer_device_get_property (GObject    *object, +                                guint       param_id, +                                GValue     *value, +                                GParamSpec *pspec) +{ +    MateMixerDevice *device; + +    device = MATE_MIXER_DEVICE (object); + +    switch (param_id) { +    case PROP_NAME: +        g_value_set_string (value, device->priv->name); +        break; +    case PROP_LABEL: +        g_value_set_string (value, device->priv->label); +        break; +    case PROP_ICON: +        g_value_set_string (value, device->priv->icon); +        break; +    case PROP_ACTIVE_PROFILE: +        g_value_set_object (value, device->priv->profile); +        break; + +    default: +        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); +        break; +    } +} + +static void +mate_mixer_device_set_property (GObject      *object, +                                guint         param_id, +                                const GValue *value, +                                GParamSpec   *pspec) +{ +    MateMixerDevice *device; + +    device = MATE_MIXER_DEVICE (object); + +    switch (param_id) { +    case PROP_NAME: +        /* Construct-only string */ +        device->priv->name = g_strdup (g_value_get_string (value)); +        break; +    case PROP_LABEL: +        /* Construct-only string */ +        device->priv->label = g_strdup (g_value_get_string (value)); +        break; +    case PROP_ICON: +        /* Construct-only string */ +        device->priv->icon = g_strdup (g_value_get_string (value)); +        break; + +    default: +        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); +        break; +    } +}  static void -mate_mixer_device_default_init (MateMixerDeviceInterface *iface) -{ -    g_object_interface_install_property (iface, -                                         g_param_spec_string ("name", -                                                              "Name", -                                                              "Name of the device", -                                                              NULL, -                                                              G_PARAM_READWRITE | -                                                              G_PARAM_CONSTRUCT_ONLY | -                                                              G_PARAM_STATIC_STRINGS)); - -    g_object_interface_install_property (iface, -                                         g_param_spec_string ("description", -                                                              "Description", -                                                              "Description of the device", -                                                              NULL, -                                                              G_PARAM_READWRITE | -                                                              G_PARAM_CONSTRUCT_ONLY | -                                                              G_PARAM_STATIC_STRINGS)); - -    g_object_interface_install_property (iface, -                                         g_param_spec_string ("icon", -                                                              "Icon", -                                                              "Name of the sound device icon", -                                                              NULL, -                                                              G_PARAM_READWRITE | -                                                              G_PARAM_CONSTRUCT_ONLY | -                                                              G_PARAM_STATIC_STRINGS)); - -    g_object_interface_install_property (iface, -                                         g_param_spec_object ("active-profile", -                                                              "Active profile", -                                                              "The currently active profile of the device", -                                                              MATE_MIXER_TYPE_DEVICE_PROFILE, -                                                              G_PARAM_READABLE | -                                                              G_PARAM_STATIC_STRINGS)); +mate_mixer_device_init (MateMixerDevice *device) +{ +    device->priv = G_TYPE_INSTANCE_GET_PRIVATE (device, +                                                MATE_MIXER_TYPE_DEVICE, +                                                MateMixerDevicePrivate); +} + +static void +mate_mixer_device_dispose (GObject *object) +{ +    MateMixerDevice *device; + +    device = MATE_MIXER_DEVICE (object); + +    if (device->priv->streams != NULL) { +        g_list_free_full (device->priv->streams, g_object_unref); +        device->priv->streams = NULL; +    } +    if (device->priv->switches != NULL) { +        g_list_free_full (device->priv->switches, g_object_unref); +        device->priv->switches = NULL; +    } +    if (device->priv->profiles != NULL) { +        g_list_free_full (device->priv->profiles, g_object_unref); +        device->priv->profiles = NULL; +    } + +    g_clear_object (&device->priv->profile); + +    G_OBJECT_CLASS (mate_mixer_device_parent_class)->dispose (object); +} + +static void +mate_mixer_device_finalize (GObject *object) +{ +    MateMixerDevice *device; + +    device = MATE_MIXER_DEVICE (object); + +    g_free (device->priv->name); +    g_free (device->priv->label); +    g_free (device->priv->icon); + +    G_OBJECT_CLASS (mate_mixer_device_parent_class)->finalize (object);  }  /** @@ -78,8 +305,7 @@ mate_mixer_device_get_name (MateMixerDevice *device)  {      g_return_val_if_fail (MATE_MIXER_IS_DEVICE (device), NULL); -    /* Implementation required */ -    return MATE_MIXER_DEVICE_GET_INTERFACE (device)->get_name (device); +    return device->priv->name;  }  /** @@ -87,18 +313,11 @@ mate_mixer_device_get_name (MateMixerDevice *device)   * @device: a #MateMixerDevice   */  const gchar * -mate_mixer_device_get_description (MateMixerDevice *device) +mate_mixer_device_get_label (MateMixerDevice *device)  { -    MateMixerDeviceInterface *iface; -      g_return_val_if_fail (MATE_MIXER_IS_DEVICE (device), NULL); -    iface = MATE_MIXER_DEVICE_GET_INTERFACE (device); - -    if (iface->get_description) -        return iface->get_description (device); - -    return NULL; +    return device->priv->label;  }  /** @@ -108,77 +327,80 @@ mate_mixer_device_get_description (MateMixerDevice *device)  const gchar *  mate_mixer_device_get_icon (MateMixerDevice *device)  { -    MateMixerDeviceInterface *iface; -      g_return_val_if_fail (MATE_MIXER_IS_DEVICE (device), NULL); -    iface = MATE_MIXER_DEVICE_GET_INTERFACE (device); - -    if (iface->get_icon) -        return iface->get_icon (device); - -    return NULL; +    return device->priv->icon;  }  /** - * mate_mixer_device_get_port: + * mate_mixer_device_get_profile:   * @device: a #MateMixerDevice - * @name: a port name + * @name: a profile name   */ -MateMixerPort * -mate_mixer_device_get_port (MateMixerDevice *device, const gchar *name) +MateMixerDeviceProfile * +mate_mixer_device_get_profile (MateMixerDevice *device, const gchar *name)  { -    MateMixerDeviceInterface *iface; - -    g_return_val_if_fail (MATE_MIXER_IS_DEVICE (device), NULL); -    g_return_val_if_fail (name != NULL, NULL); - -    iface = MATE_MIXER_DEVICE_GET_INTERFACE (device); - -    if (iface->get_port) -        return iface->get_port (device, name); +    return MATE_MIXER_DEVICE_GET_CLASS (device)->get_profile (device, name); +} -    return NULL; +/** + * mate_mixer_device_get_stream: + * @device: a #MateMixerDevice + * @name: a profile name + */ +MateMixerStream * +mate_mixer_device_get_stream (MateMixerDevice *device, const gchar *name) +{ +    return MATE_MIXER_DEVICE_GET_CLASS (device)->get_stream (device, name);  }  /** - * mate_mixer_device_get_profile: + * mate_mixer_device_get_switch:   * @device: a #MateMixerDevice   * @name: a profile name   */ -MateMixerDeviceProfile * -mate_mixer_device_get_profile (MateMixerDevice *device, const gchar *name) +MateMixerSwitch * +mate_mixer_device_get_switch (MateMixerDevice *device, const gchar *name)  { -    MateMixerDeviceInterface *iface; +    return MATE_MIXER_DEVICE_GET_CLASS (device)->get_switch (device, name); +} +/** + * mate_mixer_device_list_streams: + * @device: a #MateMixerDevice + */ +const GList * +mate_mixer_device_list_streams (MateMixerDevice *device) +{      g_return_val_if_fail (MATE_MIXER_IS_DEVICE (device), NULL); -    g_return_val_if_fail (name != NULL, NULL); -    iface = MATE_MIXER_DEVICE_GET_INTERFACE (device); +    if (device->priv->streams == NULL) { +        MateMixerDeviceClass *klass = MATE_MIXER_DEVICE_GET_CLASS (device); -    if (iface->get_profile) -        return iface->get_profile (device, name); +        if (klass->list_streams != NULL) +            device->priv->streams = klass->list_streams (device); +    } -    return NULL; +    return (const GList *) device->priv->streams;  }  /** - * mate_mixer_device_list_ports: + * mate_mixer_device_list_switches:   * @device: a #MateMixerDevice   */  const GList * -mate_mixer_device_list_ports (MateMixerDevice *device) +mate_mixer_device_list_switches (MateMixerDevice *device)  { -    MateMixerDeviceInterface *iface; -      g_return_val_if_fail (MATE_MIXER_IS_DEVICE (device), NULL); -    iface = MATE_MIXER_DEVICE_GET_INTERFACE (device); +    if (device->priv->switches == NULL) { +        MateMixerDeviceClass *klass = MATE_MIXER_DEVICE_GET_CLASS (device); -    if (iface->list_ports) -        return iface->list_ports (device); +        if (klass->list_switches != NULL) +            device->priv->switches = klass->list_switches (device); +    } -    return NULL; +    return (const GList *) device->priv->switches;  }  /** @@ -188,16 +410,16 @@ mate_mixer_device_list_ports (MateMixerDevice *device)  const GList *  mate_mixer_device_list_profiles (MateMixerDevice *device)  { -    MateMixerDeviceInterface *iface; -      g_return_val_if_fail (MATE_MIXER_IS_DEVICE (device), NULL); -    iface = MATE_MIXER_DEVICE_GET_INTERFACE (device); +    if (device->priv->profiles == NULL) { +        MateMixerDeviceClass *klass = MATE_MIXER_DEVICE_GET_CLASS (device); -    if (iface->list_profiles) -        return iface->list_profiles (device); +        if (klass->list_profiles != NULL) +            device->priv->profiles = klass->list_profiles (device); +    } -    return NULL; +    return (const GList *) device->priv->profiles;  }  /** @@ -207,16 +429,9 @@ mate_mixer_device_list_profiles (MateMixerDevice *device)  MateMixerDeviceProfile *  mate_mixer_device_get_active_profile (MateMixerDevice *device)  { -    MateMixerDeviceInterface *iface; -      g_return_val_if_fail (MATE_MIXER_IS_DEVICE (device), NULL); -    iface = MATE_MIXER_DEVICE_GET_INTERFACE (device); - -    if (iface->get_active_profile) -        return iface->get_active_profile (device); - -    return NULL; +    return device->priv->profile;  }  /** @@ -228,15 +443,83 @@ gboolean  mate_mixer_device_set_active_profile (MateMixerDevice        *device,                                        MateMixerDeviceProfile *profile)  { -    MateMixerDeviceInterface *iface; -      g_return_val_if_fail (MATE_MIXER_IS_DEVICE (device), FALSE);      g_return_val_if_fail (MATE_MIXER_IS_DEVICE_PROFILE (profile), FALSE); -    iface = MATE_MIXER_DEVICE_GET_INTERFACE (device); +    if (profile != device->priv->profile) { +        MateMixerDeviceClass *klass; + +        klass = MATE_MIXER_DEVICE_GET_CLASS (device); + +        if (klass->set_active_profile == NULL || +            klass->set_active_profile (device, profile) == FALSE) +            return FALSE; -    if (iface->set_active_profile) -        return iface->set_active_profile (device, profile); +        if (G_LIKELY (device->priv->profile != NULL)) +            g_object_unref (device->priv->profile); -    return FALSE; +        device->priv->profile = g_object_ref (profile); +    } + +    return TRUE; +} + +static MateMixerStream * +mate_mixer_device_real_get_stream (MateMixerDevice *device, const gchar *name) +{ +    const GList *list; + +    g_return_val_if_fail (MATE_MIXER_IS_DEVICE (device), NULL); +    g_return_val_if_fail (name != NULL, NULL); + +    list = mate_mixer_device_list_streams (device); +    while (list != NULL) { +        MateMixerStream *stream = MATE_MIXER_STREAM (list->data); + +        if (strcmp (name, mate_mixer_stream_get_name (stream)) == 0) +            return stream; + +        list = list->next; +    } +    return NULL; +} + +static MateMixerSwitch * +mate_mixer_device_real_get_switch (MateMixerDevice *device, const gchar *name) +{ +    const GList *list; + +    g_return_val_if_fail (MATE_MIXER_IS_DEVICE (device), NULL); +    g_return_val_if_fail (name != NULL, NULL); + +    list = mate_mixer_device_list_switches (device); +    while (list != NULL) { +        MateMixerSwitch *swtch = MATE_MIXER_SWITCH (list->data); + +        if (strcmp (name, mate_mixer_switch_get_name (swtch)) == 0) +            return swtch; + +        list = list->next; +    } +    return NULL; +} + +static MateMixerDeviceProfile * +mate_mixer_device_real_get_profile (MateMixerDevice *device, const gchar *name) +{ +    const GList *list; + +    g_return_val_if_fail (MATE_MIXER_IS_DEVICE (device), NULL); +    g_return_val_if_fail (name != NULL, NULL); + +    list = mate_mixer_device_list_profiles (device); +    while (list != NULL) { +        MateMixerDeviceProfile *profile = MATE_MIXER_DEVICE_PROFILE (list->data); + +        if (strcmp (name, mate_mixer_device_profile_get_name (profile)) == 0) +            return profile; + +        list = list->next; +    } +    return NULL;  } diff --git a/libmatemixer/matemixer-device.h b/libmatemixer/matemixer-device.h index 340496b..885460c 100644 --- a/libmatemixer/matemixer-device.h +++ b/libmatemixer/matemixer-device.h @@ -21,8 +21,7 @@  #include <glib.h>  #include <glib-object.h> -#include <libmatemixer/matemixer-device-profile.h> -#include <libmatemixer/matemixer-port.h> +#include "matemixer-types.h"  G_BEGIN_DECLS @@ -32,48 +31,72 @@ G_BEGIN_DECLS          (G_TYPE_CHECK_INSTANCE_CAST ((o), MATE_MIXER_TYPE_DEVICE, MateMixerDevice))  #define MATE_MIXER_IS_DEVICE(o)                 \          (G_TYPE_CHECK_INSTANCE_TYPE ((o), MATE_MIXER_TYPE_DEVICE)) -#define MATE_MIXER_DEVICE_GET_INTERFACE(o)      \ -        (G_TYPE_INSTANCE_GET_INTERFACE ((o), MATE_MIXER_TYPE_DEVICE, MateMixerDeviceInterface)) +#define MATE_MIXER_DEVICE_CLASS(k)              \ +        (G_TYPE_CHECK_CLASS_CAST ((k), MATE_MIXER_TYPE_DEVICE, MateMixerDeviceClass)) +#define MATE_MIXER_IS_DEVICE_CLASS(k)           \ +        (G_TYPE_CHECK_CLASS_TYPE ((k), MATE_MIXER_TYPE_DEVICE)) +#define MATE_MIXER_DEVICE_GET_CLASS(o)          \ +        (G_TYPE_INSTANCE_GET_CLASS ((o), MATE_MIXER_TYPE_DEVICE, MateMixerDeviceClass)) -typedef struct _MateMixerDevice           MateMixerDevice; /* dummy object */ -typedef struct _MateMixerDeviceInterface  MateMixerDeviceInterface; +typedef struct _MateMixerDeviceClass    MateMixerDeviceClass; +typedef struct _MateMixerDevicePrivate  MateMixerDevicePrivate; -struct _MateMixerDeviceInterface +struct _MateMixerDevice  { -    GTypeInterface parent_iface; +    GObject object; + +    /*< private >*/ +    MateMixerDevicePrivate *priv; +}; + +struct _MateMixerDeviceClass +{ +    GObjectClass parent_class;      /*< private >*/ -    /* Virtual table */ -    const gchar            *(*get_name)           (MateMixerDevice        *device); -    const gchar            *(*get_description)    (MateMixerDevice        *device); -    const gchar            *(*get_icon)           (MateMixerDevice        *device); -    MateMixerPort          *(*get_port)           (MateMixerDevice        *device, +    MateMixerStream        *(*get_stream)         (MateMixerDevice        *device, +                                                   const gchar            *name); +    MateMixerSwitch        *(*get_switch)         (MateMixerDevice        *device,                                                     const gchar            *name);      MateMixerDeviceProfile *(*get_profile)        (MateMixerDevice        *device,                                                     const gchar            *name); -    const GList            *(*list_streams)       (MateMixerDevice        *device); -    const GList            *(*list_ports)         (MateMixerDevice        *device); -    const GList            *(*list_profiles)      (MateMixerDevice        *device); +    GList                  *(*list_streams)       (MateMixerDevice        *device); +    GList                  *(*list_switches)      (MateMixerDevice        *device); +    GList                  *(*list_profiles)      (MateMixerDevice        *device); -    MateMixerDeviceProfile *(*get_active_profile) (MateMixerDevice        *device);      gboolean                (*set_active_profile) (MateMixerDevice        *device,                                                     MateMixerDeviceProfile *profile); + +    /* Signals */ +    void (*stream_added)       (MateMixerDevice *device, +                                const gchar     *name); +    void (*stream_removed)     (MateMixerDevice *device, +                                const gchar     *name); +    void (*switch_added)       (MateMixerDevice *device, +                                const gchar     *name); +    void (*switch_removed)     (MateMixerDevice *device, +                                const gchar     *name);  };  GType                   mate_mixer_device_get_type           (void) G_GNUC_CONST;  const gchar *           mate_mixer_device_get_name           (MateMixerDevice        *device); -const gchar *           mate_mixer_device_get_description    (MateMixerDevice        *device); +const gchar *           mate_mixer_device_get_label          (MateMixerDevice        *device);  const gchar *           mate_mixer_device_get_icon           (MateMixerDevice        *device); -MateMixerPort *         mate_mixer_device_get_port           (MateMixerDevice        *device, +MateMixerStream *       mate_mixer_device_get_stream         (MateMixerDevice        *device,                                                                const gchar            *name); + +MateMixerSwitch *       mate_mixer_device_get_switch         (MateMixerDevice        *device, +                                                              const gchar            *name); +  MateMixerDeviceProfile *mate_mixer_device_get_profile        (MateMixerDevice        *device,                                                                const gchar            *name); -const GList *           mate_mixer_device_list_ports         (MateMixerDevice        *device); +const GList *           mate_mixer_device_list_streams       (MateMixerDevice        *device); +const GList *           mate_mixer_device_list_switches      (MateMixerDevice        *device);  const GList *           mate_mixer_device_list_profiles      (MateMixerDevice        *device);  MateMixerDeviceProfile *mate_mixer_device_get_active_profile (MateMixerDevice        *device); diff --git a/libmatemixer/matemixer-enum-types.c b/libmatemixer/matemixer-enum-types.c index 50e3bf4..035be3d 100644 --- a/libmatemixer/matemixer-enum-types.c +++ b/libmatemixer/matemixer-enum-types.c @@ -135,7 +135,7 @@ mate_mixer_stream_control_flags_get_type (void)              { 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_DECIBEL, "MATE_MIXER_STREAM_CONTROL_HAS_DECIBEL", "has-decibel" },              { MATE_MIXER_STREAM_CONTROL_HAS_FLAT_VOLUME, "MATE_MIXER_STREAM_CONTROL_HAS_FLAT_VOLUME", "has-flat-volume" },              { MATE_MIXER_STREAM_CONTROL_CAN_SET_VOLUME, "MATE_MIXER_STREAM_CONTROL_CAN_SET_VOLUME", "can-set-volume" },              { MATE_MIXER_STREAM_CONTROL_CAN_BALANCE, "MATE_MIXER_STREAM_CONTROL_CAN_BALANCE", "can-balance" }, @@ -150,6 +150,30 @@ mate_mixer_stream_control_flags_get_type (void)  }  GType +mate_mixer_stream_control_role_get_type (void) +{ +    static GType etype = 0; + +    if (etype == 0) { +        static const GEnumValue values[] = { +            { MATE_MIXER_STREAM_CONTROL_ROLE_UNKNOWN, "MATE_MIXER_STREAM_CONTROL_ROLE_UNKNOWN", "unknown" }, +            { MATE_MIXER_STREAM_CONTROL_ROLE_MASTER, "MATE_MIXER_STREAM_CONTROL_ROLE_MASTER", "master" }, +            { MATE_MIXER_STREAM_CONTROL_ROLE_PORT, "MATE_MIXER_STREAM_CONTROL_ROLE_PORT", "port" }, +            { MATE_MIXER_STREAM_CONTROL_ROLE_PCM, "MATE_MIXER_STREAM_CONTROL_ROLE_PCM", "pcm" }, +            { MATE_MIXER_STREAM_CONTROL_ROLE_BASS, "MATE_MIXER_STREAM_CONTROL_ROLE_BASS", "bass" }, +            { MATE_MIXER_STREAM_CONTROL_ROLE_TREBLE, "MATE_MIXER_STREAM_CONTROL_ROLE_TREBLE", "treble" }, +            { MATE_MIXER_STREAM_CONTROL_ROLE_CD, "MATE_MIXER_STREAM_CONTROL_ROLE_CD", "cd" }, +            { MATE_MIXER_STREAM_CONTROL_ROLE_SPEAKER, "MATE_MIXER_STREAM_CONTROL_ROLE_SPEAKER", "speaker" }, +            { 0, NULL, NULL } +        }; +        etype = g_enum_register_static ( +            g_intern_static_string ("MateMixerStreamControlRole"), +            values); +    } +    return etype; +} + +GType  mate_mixer_client_stream_flags_get_type (void)  {      static GType etype = 0; diff --git a/libmatemixer/matemixer-enum-types.h b/libmatemixer/matemixer-enum-types.h index 1dc13cc..f2193be 100644 --- a/libmatemixer/matemixer-enum-types.h +++ b/libmatemixer/matemixer-enum-types.h @@ -46,6 +46,9 @@ GType mate_mixer_stream_state_get_type (void) G_GNUC_CONST;  #define MATE_MIXER_TYPE_STREAM_CONTROL_FLAGS (mate_mixer_stream_control_flags_get_type ())  GType mate_mixer_stream_control_flags_get_type (void) G_GNUC_CONST; +#define MATE_MIXER_TYPE_STREAM_CONTROL_ROLE (mate_mixer_stream_control_role_get_type ()) +GType mate_mixer_stream_control_role_get_type (void); +  #define MATE_MIXER_TYPE_CLIENT_STREAM_FLAGS (mate_mixer_client_stream_flags_get_type ())  GType mate_mixer_client_stream_flags_get_type (void) G_GNUC_CONST; diff --git a/libmatemixer/matemixer-enums.h b/libmatemixer/matemixer-enums.h index b99f4c5..8a88b1c 100644 --- a/libmatemixer/matemixer-enums.h +++ b/libmatemixer/matemixer-enums.h @@ -47,8 +47,8 @@ typedef enum {   *     PulseAudio sound system backend. It has the highest priority and   *     will be the first one to try unless you select a specific backend   *     to connect to. + * @MATE_MIXER_BACKEND_ALSA:   * @MATE_MIXER_BACKEND_OSS: - * @MATE_MIXER_BACKEND_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,11 +58,17 @@ typedef enum {  typedef enum {      MATE_MIXER_BACKEND_UNKNOWN,      MATE_MIXER_BACKEND_PULSEAUDIO, +    MATE_MIXER_BACKEND_ALSA,      MATE_MIXER_BACKEND_OSS, -    MATE_MIXER_BACKEND_OSS4,      MATE_MIXER_BACKEND_NULL  } MateMixerBackendType; +typedef enum { /*< flags >*/ +    MATE_MIXER_BACKEND_NO_FLAGS    = 0, +    MATE_MIXER_BACKEND_CAN_SET_DEFAULT_INPUT_STREAM, +    MATE_MIXER_BACKEND_CAN_SET_DEFAULT_OUTPUT_STREAM +} MateMixerBackendFlags; +  /**   * MateMixerPortFlags:   * @MATE_MIXER_PORT_NO_FLAGS: @@ -116,7 +122,7 @@ typedef enum {   * @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_DECIBEL:   * @MATE_MIXER_STREAM_CONTROL_HAS_FLAT_VOLUME:   * @MATE_MIXER_STREAM_CONTROL_CAN_SET_VOLUME:   * @MATE_MIXER_STREAM_CONTROL_CAN_BALANCE: @@ -126,22 +132,23 @@ 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_DECIBEL         = 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 +    MATE_MIXER_STREAM_CONTROL_CAN_SET_MUTE        = 1 << 4, +    MATE_MIXER_STREAM_CONTROL_CAN_SET_VOLUME      = 1 << 5, +    MATE_MIXER_STREAM_CONTROL_CAN_BALANCE         = 1 << 6, +    MATE_MIXER_STREAM_CONTROL_CAN_FADE            = 1 << 7  } MateMixerStreamControlFlags;  typedef enum {      MATE_MIXER_STREAM_CONTROL_ROLE_UNKNOWN,      MATE_MIXER_STREAM_CONTROL_ROLE_MASTER, +    MATE_MIXER_STREAM_CONTROL_ROLE_PORT,      MATE_MIXER_STREAM_CONTROL_ROLE_PCM,      MATE_MIXER_STREAM_CONTROL_ROLE_BASS,      MATE_MIXER_STREAM_CONTROL_ROLE_TREBLE,      MATE_MIXER_STREAM_CONTROL_ROLE_CD,      MATE_MIXER_STREAM_CONTROL_ROLE_SPEAKER, -    MATE_MIXER_STREAM_CONTROL_ROLE_PORT  } MateMixerStreamControlRole;  /** @@ -210,7 +217,7 @@ typedef enum {   * @MATE_MIXER_CHANNEL_TOP_BACK_CENTER:   */  typedef enum { -    MATE_MIXER_CHANNEL_UNKNOWN, +    MATE_MIXER_CHANNEL_UNKNOWN = 0,      MATE_MIXER_CHANNEL_MONO,      MATE_MIXER_CHANNEL_FRONT_LEFT,      MATE_MIXER_CHANNEL_FRONT_RIGHT, @@ -229,7 +236,8 @@ typedef enum {      MATE_MIXER_CHANNEL_TOP_CENTER,      MATE_MIXER_CHANNEL_TOP_BACK_LEFT,      MATE_MIXER_CHANNEL_TOP_BACK_RIGHT, -    MATE_MIXER_CHANNEL_TOP_BACK_CENTER +    MATE_MIXER_CHANNEL_TOP_BACK_CENTER, +    MATE_MIXER_CHANNEL_MAX  } MateMixerChannelPosition;  #endif /* MATEMIXER_ENUMS_H */ diff --git a/libmatemixer/matemixer-port-private.h b/libmatemixer/matemixer-port-private.h deleted file mode 100644 index a696d27..0000000 --- a/libmatemixer/matemixer-port-private.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (C) 2014 Michal Ratajsky <[email protected]> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the licence, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/>. - */ - -#ifndef MATEMIXER_PORT_PRIVATE_H -#define MATEMIXER_PORT_PRIVATE_H - -#include <glib.h> - -#include "matemixer-enums.h" -#include "matemixer-port.h" - -G_BEGIN_DECLS - -MateMixerPort *_mate_mixer_port_new                (const gchar       *name, -                                                    const gchar       *description, -                                                    const gchar       *icon, -                                                    guint              priority, -                                                    MateMixerPortFlags flags); - -gboolean       _mate_mixer_port_update_description (MateMixerPort     *port, -                                                    const gchar       *description); -gboolean       _mate_mixer_port_update_icon        (MateMixerPort     *port, -                                                    const gchar       *icon); -gboolean       _mate_mixer_port_update_priority    (MateMixerPort     *port, -                                                    guint              priority); -gboolean       _mate_mixer_port_update_flags       (MateMixerPort     *port, -                                                    MateMixerPortFlags flags); - -G_END_DECLS - -#endif /* MATEMIXER_PORT_PRIVATE_H */ diff --git a/libmatemixer/matemixer-port.c b/libmatemixer/matemixer-port.c deleted file mode 100644 index f89a8bb..0000000 --- a/libmatemixer/matemixer-port.c +++ /dev/null @@ -1,358 +0,0 @@ -/* - * Copyright (C) 2014 Michal Ratajsky <[email protected]> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the licence, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/>. - */ - -#include <glib.h> -#include <glib-object.h> - -#include "matemixer-enums.h" -#include "matemixer-enum-types.h" -#include "matemixer-port.h" -#include "matemixer-port-private.h" - -/** - * SECTION:matemixer-port - * @include: libmatemixer/matemixer.h - */ - -struct _MateMixerPortPrivate -{ -    gchar              *name; -    gchar              *description; -    gchar              *icon; -    guint               priority; -    MateMixerPortFlags  flags; -}; - -enum { -    PROP_0, -    PROP_NAME, -    PROP_DESCRIPTION, -    PROP_ICON, -    PROP_PRIORITY, -    PROP_FLAGS, -    N_PROPERTIES -}; - -static GParamSpec *properties[N_PROPERTIES] = { NULL, }; - -static void mate_mixer_port_class_init (MateMixerPortClass *klass); - -static void mate_mixer_port_get_property (GObject       *object, -                                          guint          param_id, -                                          GValue        *value, -                                          GParamSpec    *pspec); -static void mate_mixer_port_set_property (GObject       *object, -                                          guint          param_id, -                                          const GValue  *value, -                                          GParamSpec    *pspec); - -static void mate_mixer_port_init         (MateMixerPort *port); -static void mate_mixer_port_finalize     (GObject       *object); - -G_DEFINE_TYPE (MateMixerPort, mate_mixer_port, G_TYPE_OBJECT); - -static void -mate_mixer_port_class_init (MateMixerPortClass *klass) -{ -    GObjectClass *object_class; - -    object_class = G_OBJECT_CLASS (klass); -    object_class->finalize     = mate_mixer_port_finalize; -    object_class->get_property = mate_mixer_port_get_property; -    object_class->set_property = mate_mixer_port_set_property; - -    properties[PROP_NAME] = -        g_param_spec_string ("name", -                             "Name", -                             "Name of the port", -                             NULL, -                             G_PARAM_CONSTRUCT_ONLY | -                             G_PARAM_READWRITE | -                             G_PARAM_STATIC_STRINGS); - -    properties[PROP_DESCRIPTION] = -        g_param_spec_string ("description", -                             "Description", -                             "Description of the port", -                             NULL, -                             G_PARAM_CONSTRUCT_ONLY | -                             G_PARAM_READWRITE | -                             G_PARAM_STATIC_STRINGS); - -    properties[PROP_ICON] = -        g_param_spec_string ("icon", -                             "Icon", -                             "Name of the port icon", -                             NULL, -                             G_PARAM_CONSTRUCT_ONLY | -                             G_PARAM_READWRITE | -                             G_PARAM_STATIC_STRINGS); - -    properties[PROP_PRIORITY] = -        g_param_spec_uint ("priority", -                           "Priority", -                           "Priority of the port", -                           0, -                           G_MAXUINT, -                           0, -                           G_PARAM_CONSTRUCT_ONLY | -                           G_PARAM_READWRITE | -                           G_PARAM_STATIC_STRINGS); - -    properties[PROP_FLAGS] = -        g_param_spec_flags ("flags", -                            "Flags", -                            "Capability flags of the port", -                            MATE_MIXER_TYPE_PORT_FLAGS, -                            MATE_MIXER_PORT_NO_FLAGS, -                            G_PARAM_CONSTRUCT_ONLY | -                            G_PARAM_READWRITE | -                            G_PARAM_STATIC_STRINGS); - -    g_object_class_install_properties (object_class, N_PROPERTIES, properties); - -    g_type_class_add_private (object_class, sizeof (MateMixerPortPrivate)); -} - -static void -mate_mixer_port_get_property (GObject    *object, -                              guint       param_id, -                              GValue     *value, -                              GParamSpec *pspec) -{ -    MateMixerPort *port; - -    port = MATE_MIXER_PORT (object); - -    switch (param_id) { -    case PROP_NAME: -        g_value_set_string (value, port->priv->name); -        break; -    case PROP_DESCRIPTION: -        g_value_set_string (value, port->priv->description); -        break; -    case PROP_ICON: -        g_value_set_string (value, port->priv->icon); -        break; -    case PROP_PRIORITY: -        g_value_set_uint (value, port->priv->priority); -        break; -    case PROP_FLAGS: -        g_value_set_flags (value, port->priv->flags); -        break; -    default: -        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); -        break; -    } -} - -static void -mate_mixer_port_set_property (GObject      *object, -                              guint         param_id, -                              const GValue *value, -                              GParamSpec   *pspec) -{ -    MateMixerPort *port; - -    port = MATE_MIXER_PORT (object); - -    switch (param_id) { -    case PROP_NAME: -        /* Construct-only string */ -        port->priv->name = g_strdup (g_value_get_string (value)); -        break; -    case PROP_DESCRIPTION: -        /* Construct-only string */ -        port->priv->description = g_strdup (g_value_get_string (value)); -        break; -    case PROP_ICON: -        /* Construct-only string */ -        port->priv->icon = g_strdup (g_value_get_string (value)); -        break; -    case PROP_PRIORITY: -        port->priv->priority = g_value_get_uint (value); -        break; -    case PROP_FLAGS: -        port->priv->flags = g_value_get_flags (value); -        break; -    default: -        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); -        break; -    } -} - -static void -mate_mixer_port_init (MateMixerPort *port) -{ -    port->priv = G_TYPE_INSTANCE_GET_PRIVATE (port, -                                              MATE_MIXER_TYPE_PORT, -                                              MateMixerPortPrivate); -} - -static void -mate_mixer_port_finalize (GObject *object) -{ -    MateMixerPort *port; - -    port = MATE_MIXER_PORT (object); - -    g_free (port->priv->name); -    g_free (port->priv->description); -    g_free (port->priv->icon); - -    G_OBJECT_CLASS (mate_mixer_port_parent_class)->finalize (object); -} - -/** - * mate_mixer_port_get_name: - * @port: a #MateMixerPort - */ -const gchar * -mate_mixer_port_get_name (MateMixerPort *port) -{ -    g_return_val_if_fail (MATE_MIXER_IS_PORT (port), NULL); - -    return port->priv->name; -} - -/** - * mate_mixer_port_get_description: - * @port: a #MateMixerPort - */ -const gchar * -mate_mixer_port_get_description (MateMixerPort *port) -{ -    g_return_val_if_fail (MATE_MIXER_IS_PORT (port), NULL); - -    return port->priv->description; -} - -/** - * mate_mixer_port_get_icon: - * @port: a #MateMixerPort - */ -const gchar * -mate_mixer_port_get_icon (MateMixerPort *port) -{ -    g_return_val_if_fail (MATE_MIXER_IS_PORT (port), NULL); - -    return port->priv->icon; -} - -/** - * mate_mixer_port_get_priority: - * @port: a #MateMixerPort - */ -guint -mate_mixer_port_get_priority (MateMixerPort *port) -{ -    g_return_val_if_fail (MATE_MIXER_IS_PORT (port), 0); - -    return port->priv->priority; -} - -/** - * mate_mixer_port_get_flags: - * @port: a #MateMixerPort - */ -MateMixerPortFlags -mate_mixer_port_get_flags (MateMixerPort *port) -{ -    g_return_val_if_fail (MATE_MIXER_IS_PORT (port), MATE_MIXER_PORT_NO_FLAGS); - -    return port->priv->flags; -} - -MateMixerPort * -_mate_mixer_port_new (const gchar       *name, -                      const gchar       *description, -                      const gchar       *icon, -                      guint              priority, -                      MateMixerPortFlags flags) -{ -    return g_object_new (MATE_MIXER_TYPE_PORT, -                         "name", name, -                         "description", description, -                         "icon", icon, -                         "priority", priority, -                         "flags", flags, -                         NULL); -} - -gboolean -_mate_mixer_port_update_description (MateMixerPort *port, const gchar *description) -{ -    g_return_val_if_fail (MATE_MIXER_IS_PORT (port), FALSE); - -    if (g_strcmp0 (port->priv->description, description) != 0) { -        g_free (port->priv->description); - -        port->priv->description = g_strdup (description); - -        g_object_notify_by_pspec (G_OBJECT (port), properties[PROP_DESCRIPTION]); -        return TRUE; -    } - -    return FALSE; -} - -gboolean -_mate_mixer_port_update_icon (MateMixerPort *port, const gchar *icon) -{ -    g_return_val_if_fail (MATE_MIXER_IS_PORT (port), FALSE); - -    if (g_strcmp0 (port->priv->icon, icon) != 0) { -        g_free (port->priv->icon); - -        port->priv->icon = g_strdup (icon); - -        g_object_notify_by_pspec (G_OBJECT (port), properties[PROP_ICON]); -        return TRUE; -    } - -    return FALSE; -} - -gboolean -_mate_mixer_port_update_priority (MateMixerPort *port, guint priority) -{ -    g_return_val_if_fail (MATE_MIXER_IS_PORT (port), FALSE); - -    if (port->priv->priority != priority) { -        port->priv->priority = priority; - -        g_object_notify_by_pspec (G_OBJECT (port), properties[PROP_PRIORITY]); -        return TRUE; -    } - -    return FALSE; -} - -gboolean -_mate_mixer_port_update_flags (MateMixerPort *port, MateMixerPortFlags flags) -{ -    g_return_val_if_fail (MATE_MIXER_IS_PORT (port), FALSE); - -    if (port->priv->flags != flags) { -        port->priv->flags = flags; - -        g_object_notify_by_pspec (G_OBJECT (port), properties[PROP_FLAGS]); -        return TRUE; -    } - -    return FALSE; -} diff --git a/libmatemixer/matemixer-port.h b/libmatemixer/matemixer-port.h deleted file mode 100644 index 61f16f5..0000000 --- a/libmatemixer/matemixer-port.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (C) 2014 Michal Ratajsky <[email protected]> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the licence, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/>. - */ - -#ifndef MATEMIXER_PORT_H -#define MATEMIXER_PORT_H - -#include <glib.h> -#include <glib-object.h> - -#include <libmatemixer/matemixer-enums.h> - -G_BEGIN_DECLS - -#define MATE_MIXER_TYPE_PORT                    \ -        (mate_mixer_port_get_type ()) -#define MATE_MIXER_PORT(o)                      \ -        (G_TYPE_CHECK_INSTANCE_CAST ((o), MATE_MIXER_TYPE_PORT, MateMixerPort)) -#define MATE_MIXER_IS_PORT(o)                   \ -        (G_TYPE_CHECK_INSTANCE_TYPE ((o), MATE_MIXER_TYPE_PORT)) -#define MATE_MIXER_PORT_CLASS(k)                \ -        (G_TYPE_CHECK_CLASS_CAST ((k), MATE_MIXER_TYPE_PORT, MateMixerPortClass)) -#define MATE_MIXER_IS_PORT_CLASS(k)             \ -        (G_TYPE_CHECK_CLASS_TYPE ((k), MATE_MIXER_TYPE_PORT)) -#define MATE_MIXER_PORT_GET_CLASS(o)            \ -        (G_TYPE_INSTANCE_GET_CLASS ((o), MATE_MIXER_TYPE_PORT, MateMixerPortClass)) - -typedef struct _MateMixerPort         MateMixerPort; -typedef struct _MateMixerPortClass    MateMixerPortClass; -typedef struct _MateMixerPortPrivate  MateMixerPortPrivate; - -struct _MateMixerPort -{ -    GObject parent; - -    /*< private >*/ -    MateMixerPortPrivate *priv; -}; - -struct _MateMixerPortClass -{ -    GObjectClass parent_class; -}; - -GType              mate_mixer_port_get_type        (void) G_GNUC_CONST; - -const gchar *      mate_mixer_port_get_name        (MateMixerPort *port); -const gchar *      mate_mixer_port_get_description (MateMixerPort *port); -const gchar *      mate_mixer_port_get_icon        (MateMixerPort *port); -guint              mate_mixer_port_get_priority    (MateMixerPort *port); -MateMixerPortFlags mate_mixer_port_get_flags       (MateMixerPort *port); - -G_END_DECLS - -#endif /* MATEMIXER_PORT_H */ diff --git a/libmatemixer/matemixer-private.h b/libmatemixer/matemixer-private.h index 4dde496..4229000 100644 --- a/libmatemixer/matemixer-private.h +++ b/libmatemixer/matemixer-private.h @@ -20,9 +20,91 @@  #include <glib.h> +#include "matemixer-backend-module.h" +#include "matemixer-backend-private.h" +#include "matemixer-device-profile-private.h" +#include "matemixer-stream-control-private.h" +#include "matemixer-switch-option-private.h" +#include "matemixer-switch-private.h" +  G_BEGIN_DECLS -const GList *mate_mixer_get_modules (void); +#define MATE_MIXER_IS_LEFT_CHANNEL(c)                   \ +    ((c) == MATE_MIXER_CHANNEL_FRONT_LEFT ||            \ +     (c) == MATE_MIXER_CHANNEL_BACK_LEFT ||             \ +     (c) == MATE_MIXER_CHANNEL_FRONT_LEFT_CENTER ||     \ +     (c) == MATE_MIXER_CHANNEL_SIDE_LEFT ||             \ +     (c) == MATE_MIXER_CHANNEL_TOP_FRONT_LEFT ||        \ +     (c) == MATE_MIXER_CHANNEL_TOP_BACK_LEFT) + +#define MATE_MIXER_IS_RIGHT_CHANNEL(c)                  \ +    ((c) == MATE_MIXER_CHANNEL_FRONT_RIGHT ||           \ +     (c) == MATE_MIXER_CHANNEL_BACK_RIGHT ||            \ +     (c) == MATE_MIXER_CHANNEL_FRONT_RIGHT_CENTER ||    \ +     (c) == MATE_MIXER_CHANNEL_SIDE_RIGHT ||            \ +     (c) == MATE_MIXER_CHANNEL_TOP_FRONT_RIGHT ||       \ +     (c) == MATE_MIXER_CHANNEL_TOP_BACK_RIGHT) + +#define MATE_MIXER_IS_FRONT_CHANNEL(c)                  \ +    ((c) == MATE_MIXER_CHANNEL_FRONT_LEFT ||            \ +     (c) == MATE_MIXER_CHANNEL_FRONT_RIGHT ||           \ +     (c) == MATE_MIXER_CHANNEL_FRONT_CENTER ||          \ +     (c) == MATE_MIXER_CHANNEL_FRONT_LEFT_CENTER ||     \ +     (c) == MATE_MIXER_CHANNEL_FRONT_RIGHT_CENTER ||    \ +     (c) == MATE_MIXER_CHANNEL_TOP_FRONT_LEFT ||        \ +     (c) == MATE_MIXER_CHANNEL_TOP_FRONT_RIGHT ||       \ +     (c) == MATE_MIXER_CHANNEL_TOP_FRONT_CENTER) + +#define MATE_MIXER_IS_BACK_CHANNEL(c)                   \ +    ((c) == MATE_MIXER_CHANNEL_BACK_LEFT ||             \ +     (c) == MATE_MIXER_CHANNEL_BACK_RIGHT ||            \ +     (c) == MATE_MIXER_CHANNEL_BACK_CENTER ||           \ +     (c) == MATE_MIXER_CHANNEL_TOP_BACK_LEFT ||         \ +     (c) == MATE_MIXER_CHANNEL_TOP_BACK_RIGHT ||        \ +     (c) == MATE_MIXER_CHANNEL_TOP_BACK_CENTER) + +#define MATE_MIXER_CHANNEL_MASK_LEFT                    \ +    ((1 << MATE_MIXER_CHANNEL_FRONT_LEFT) |             \ +     (1 << MATE_MIXER_CHANNEL_BACK_LEFT) |              \ +     (1 << MATE_MIXER_CHANNEL_FRONT_LEFT_CENTER) |      \ +     (1 << MATE_MIXER_CHANNEL_SIDE_LEFT) |              \ +     (1 << MATE_MIXER_CHANNEL_TOP_FRONT_LEFT) |         \ +     (1 << MATE_MIXER_CHANNEL_TOP_BACK_LEFT)) + +#define MATE_MIXER_CHANNEL_MASK_RIGHT                   \ +    ((1 << MATE_MIXER_CHANNEL_FRONT_RIGHT) |            \ +     (1 << MATE_MIXER_CHANNEL_BACK_RIGHT) |             \ +     (1 << MATE_MIXER_CHANNEL_FRONT_RIGHT_CENTER) |     \ +     (1 << MATE_MIXER_CHANNEL_SIDE_RIGHT) |             \ +     (1 << MATE_MIXER_CHANNEL_TOP_FRONT_RIGHT) |        \ +     (1 << MATE_MIXER_CHANNEL_TOP_BACK_RIGHT)) + +#define MATE_MIXER_CHANNEL_MASK_FRONT                   \ +    ((1 << MATE_MIXER_CHANNEL_FRONT_LEFT) |             \ +     (1 << MATE_MIXER_CHANNEL_FRONT_RIGHT) |            \ +     (1 << MATE_MIXER_CHANNEL_FRONT_CENTER) |           \ +     (1 << MATE_MIXER_CHANNEL_FRONT_LEFT_CENTER) |      \ +     (1 << MATE_MIXER_CHANNEL_FRONT_RIGHT_CENTER) |     \ +     (1 << MATE_MIXER_CHANNEL_TOP_FRONT_LEFT) |         \ +     (1 << MATE_MIXER_CHANNEL_TOP_FRONT_RIGHT) |        \ +     (1 << MATE_MIXER_CHANNEL_TOP_FRONT_CENTER)) + +#define MATE_MIXER_CHANNEL_MASK_BACK                    \ +    ((1 << MATE_MIXER_CHANNEL_BACK_LEFT) |              \ +     (1 << MATE_MIXER_CHANNEL_BACK_RIGHT) |             \ +     (1 << MATE_MIXER_CHANNEL_BACK_CENTER) |            \ +     (1 << MATE_MIXER_CHANNEL_TOP_BACK_LEFT) |          \ +     (1 << MATE_MIXER_CHANNEL_TOP_BACK_RIGHT) |         \ +     (1 << MATE_MIXER_CHANNEL_TOP_BACK_CENTER)) + +#define MATE_MIXER_CHANNEL_MASK_HAS_CHANNEL(m,c)    ((m) & (1 << (c))) +#define MATE_MIXER_CHANNEL_MASK_HAS_LEFT(m)         ((m) & MATE_MIXER_CHANNEL_MASK_LEFT) +#define MATE_MIXER_CHANNEL_MASK_HAS_RIGHT(m)        ((m) & MATE_MIXER_CHANNEL_MASK_RIGHT) +#define MATE_MIXER_CHANNEL_MASK_HAS_FRONT(m)        ((m) & MATE_MIXER_CHANNEL_MASK_FRONT) +#define MATE_MIXER_CHANNEL_MASK_HAS_BACK(m)         ((m) & MATE_MIXER_CHANNEL_MASK_BACK) + +const GList *_mate_mixer_get_modules         (void); +guint32      _mate_mixer_create_channel_mask (MateMixerChannelPosition *positions, guint n);  G_END_DECLS diff --git a/libmatemixer/matemixer-stream-control-private.h b/libmatemixer/matemixer-stream-control-private.h new file mode 100644 index 0000000..49454b3 --- /dev/null +++ b/libmatemixer/matemixer-stream-control-private.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2014 Michal Ratajsky <[email protected]> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the licence, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef MATEMIXER_STREAM_CONTROL_PRIVATE_H +#define MATEMIXER_STREAM_CONTROL_PRIVATE_H + +#include <glib.h> +#include "matemixer-enums.h" +#include "matemixer-types.h" + +G_BEGIN_DECLS + +void _mate_mixer_stream_control_set_flags   (MateMixerStreamControl     *control, +                                             MateMixerStreamControlFlags flags); + +void _mate_mixer_stream_control_set_mute    (MateMixerStreamControl     *control, +                                             gboolean                    mute); + +void _mate_mixer_stream_control_set_balance (MateMixerStreamControl     *control, +                                             gfloat                      balance); + +void _mate_mixer_stream_control_set_fade    (MateMixerStreamControl     *control, +                                             gfloat                      fade); + +G_END_DECLS + +#endif /* MATEMIXER_STREAM_CONTROL_PRIVATE_H */ diff --git a/libmatemixer/matemixer-stream-control.c b/libmatemixer/matemixer-stream-control.c index 388308e..ace584a 100644 --- a/libmatemixer/matemixer-stream-control.c +++ b/libmatemixer/matemixer-stream-control.c @@ -21,425 +21,607 @@  #include "matemixer-enums.h"  #include "matemixer-enum-types.h"  #include "matemixer-stream-control.h" +#include "matemixer-stream-control-private.h"  /**   * SECTION:matemixer-stream-control   * @include: libmatemixer/matemixer.h   */ -G_DEFINE_INTERFACE (MateMixerStreamControl, mate_mixer_stream_control, G_TYPE_OBJECT) +struct _MateMixerStreamControlPrivate +{ +    gchar                      *name; +    gchar                      *label; +    gboolean                    mute; +    gfloat                      balance; +    gfloat                      fade; +    MateMixerStreamControlFlags flags; +    MateMixerStreamControlRole  role; +}; + +enum { +    PROP_0, +    PROP_NAME, +    PROP_LABEL, +    PROP_FLAGS, +    PROP_ROLE, +    PROP_MUTE, +    PROP_VOLUME, +    PROP_BALANCE, +    PROP_FADE, +    N_PROPERTIES +}; + +static GParamSpec *properties[N_PROPERTIES] = { NULL, }; + +static void mate_mixer_stream_control_class_init   (MateMixerStreamControlClass *klass); + +static void mate_mixer_stream_control_get_property (GObject                     *object, +                                                    guint                        param_id, +                                                    GValue                      *value, +                                                    GParamSpec                  *pspec); +static void mate_mixer_stream_control_set_property (GObject                     *object, +                                                    guint                        param_id, +                                                    const GValue                *value, +                                                    GParamSpec                  *pspec); + +static void mate_mixer_stream_control_init         (MateMixerStreamControl      *control); +static void mate_mixer_stream_control_finalize     (GObject                     *object); + +G_DEFINE_ABSTRACT_TYPE (MateMixerStreamControl, mate_mixer_stream_control, G_TYPE_OBJECT) + +static void +mate_mixer_stream_control_class_init (MateMixerStreamControlClass *klass) +{ +    GObjectClass *object_class; + +    object_class = G_OBJECT_CLASS (klass); +    object_class->finalize     = mate_mixer_stream_control_finalize; +    object_class->get_property = mate_mixer_stream_control_get_property; +    object_class->set_property = mate_mixer_stream_control_set_property; + +    properties[PROP_NAME] = +        g_param_spec_string ("name", +                             "Name", +                             "Name of the stream control", +                             NULL, +                             G_PARAM_READWRITE | +                             G_PARAM_CONSTRUCT_ONLY | +                             G_PARAM_STATIC_STRINGS); + +    properties[PROP_LABEL] = +        g_param_spec_string ("label", +                             "Label", +                             "Label of the stream control", +                             NULL, +                             G_PARAM_READWRITE | +                             G_PARAM_CONSTRUCT_ONLY | +                             G_PARAM_STATIC_STRINGS); + +    properties[PROP_FLAGS] = +        g_param_spec_flags ("flags", +                            "Flags", +                            "Capability flags of the stream control", +                            MATE_MIXER_TYPE_STREAM_CONTROL_FLAGS, +                            MATE_MIXER_STREAM_CONTROL_NO_FLAGS, +                            G_PARAM_READWRITE | +                            G_PARAM_CONSTRUCT_ONLY | +                            G_PARAM_STATIC_STRINGS); + +    properties[PROP_ROLE] = +        g_param_spec_enum ("role", +                            "Role", +                            "Role of the stream control", +                            MATE_MIXER_TYPE_STREAM_CONTROL_ROLE, +                            MATE_MIXER_STREAM_CONTROL_ROLE_UNKNOWN, +                            G_PARAM_READWRITE | +                            G_PARAM_CONSTRUCT_ONLY | +                            G_PARAM_STATIC_STRINGS); + +    properties[PROP_MUTE] = +        g_param_spec_boolean ("mute", +                              "Mute", +                              "Mute state of the stream control", +                              FALSE, +                              G_PARAM_READABLE | +                              G_PARAM_STATIC_STRINGS); + +    properties[PROP_VOLUME] = +        g_param_spec_uint ("volume", +                           "Volume", +                           "Volume of the stream control", +                           0, +                           G_MAXUINT, +                           0, +                           G_PARAM_READABLE | +                           G_PARAM_STATIC_STRINGS); + +    properties[PROP_BALANCE] = +        g_param_spec_float ("balance", +                            "Balance", +                            "Balance value of the stream control", +                            -1.0f, +                            1.0f, +                            0.0f, +                            G_PARAM_READABLE | +                            G_PARAM_STATIC_STRINGS); + +    properties[PROP_FADE] = +        g_param_spec_float ("fade", +                            "Fade", +                            "Fade value of the stream control", +                            -1.0f, +                            1.0f, +                            0.0f, +                            G_PARAM_READABLE | +                            G_PARAM_STATIC_STRINGS); + +    g_object_class_install_properties (object_class, N_PROPERTIES, properties); + +    g_type_class_add_private (object_class, sizeof (MateMixerStreamControlPrivate)); +} + +static void +mate_mixer_stream_control_get_property (GObject    *object, +                                        guint       param_id, +                                        GValue     *value, +                                        GParamSpec *pspec) +{ +    MateMixerStreamControl *control; + +    control = MATE_MIXER_STREAM_CONTROL (object); + +    switch (param_id) { +    case PROP_NAME: +        g_value_set_string (value, control->priv->name); +        break; +    case PROP_LABEL: +        g_value_set_string (value, control->priv->label); +        break; +    case PROP_FLAGS: +        g_value_set_flags (value, control->priv->flags); +        break; +    case PROP_ROLE: +        g_value_set_enum (value, control->priv->role); +        break; + +    default: +        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); +        break; +    } +} + +static void +mate_mixer_stream_control_set_property (GObject      *object, +                                        guint         param_id, +                                        const GValue *value, +                                        GParamSpec   *pspec) +{ +    MateMixerStreamControl *control; + +    control = MATE_MIXER_STREAM_CONTROL (object); + +    switch (param_id) { +    case PROP_NAME: +        /* Construct-only string */ +        control->priv->name = g_value_dup_string (value); +        break; +    case PROP_LABEL: +        /* Construct-only string */ +        control->priv->label = g_value_dup_string (value); +        break; +    case PROP_FLAGS: +        control->priv->flags = g_value_get_flags (value); +        break; +    case PROP_ROLE: +        control->priv->role = g_value_get_enum (value); +        break; + +    default: +        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); +        break; +    } +} + +static void +mate_mixer_stream_control_init (MateMixerStreamControl *control) +{ +    control->priv = G_TYPE_INSTANCE_GET_PRIVATE (control, +                                                 MATE_MIXER_TYPE_STREAM_CONTROL, +                                                 MateMixerStreamControlPrivate); +}  static void -mate_mixer_stream_control_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)); +mate_mixer_stream_control_finalize (GObject *object) +{ +    MateMixerStreamControl *control; + +    control = MATE_MIXER_STREAM_CONTROL (object); + +    g_free (control->priv->name); +    g_free (control->priv->label); + +    G_OBJECT_CLASS (mate_mixer_stream_control_parent_class)->finalize (object);  }  const gchar * -mate_mixer_stream_control_get_name (MateMixerStreamControl *ctl) +mate_mixer_stream_control_get_name (MateMixerStreamControl *control)  { -    g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (ctl), NULL); +    g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (control), NULL); -    /* Implementation required */ -    return MATE_MIXER_STREAM_CONTROL_GET_INTERFACE (ctl)->get_name (ctl); +    return control->priv->name;  }  const gchar * -mate_mixer_stream_control_get_description (MateMixerStreamControl *ctl) +mate_mixer_stream_control_get_label (MateMixerStreamControl *control)  { -    g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (ctl), NULL); +    g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (control), NULL); -    /* Implementation required */ -    return MATE_MIXER_STREAM_CONTROL_GET_INTERFACE (ctl)->get_description (ctl); +    return control->priv->label;  }  MateMixerStreamControlFlags -mate_mixer_stream_control_get_flags (MateMixerStreamControl *ctl) +mate_mixer_stream_control_get_flags (MateMixerStreamControl *control)  { -    MateMixerStreamControlFlags flags = MATE_MIXER_STREAM_CONTROL_NO_FLAGS; +    g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (control), MATE_MIXER_STREAM_CONTROL_NO_FLAGS); -    g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (ctl), MATE_MIXER_STREAM_CONTROL_NO_FLAGS); +    return control->priv->flags; +} -    g_object_get (G_OBJECT (ctl), -                  "flags", &flags, -                  NULL); +MateMixerStreamControlRole +mate_mixer_stream_control_get_role (MateMixerStreamControl *control) +{ +    g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (control), MATE_MIXER_STREAM_CONTROL_ROLE_UNKNOWN); -    return flags; +    return control->priv->role;  }  gboolean -mate_mixer_stream_control_get_mute (MateMixerStreamControl *ctl) +mate_mixer_stream_control_get_mute (MateMixerStreamControl *control)  { -    gboolean mute = FALSE; - -    g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (ctl), FALSE); +    g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (control), FALSE); -    g_object_get (G_OBJECT (ctl), -                  "mute", &mute, -                  NULL); - -    return mute; +    return control->priv->mute;  }  gboolean -mate_mixer_stream_control_set_mute (MateMixerStreamControl *ctl, gboolean mute) +mate_mixer_stream_control_set_mute (MateMixerStreamControl *control, gboolean mute)  { -    MateMixerStreamControlInterface *iface; +    g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (control), FALSE); -    g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (ctl), FALSE); +    if (control->priv->mute == mute) +        return TRUE; -    iface = MATE_MIXER_STREAM_CONTROL_GET_INTERFACE (ctl); +    if (control->priv->flags & MATE_MIXER_STREAM_CONTROL_HAS_MUTE) { +        MateMixerStreamControlClass *klass; -    if (iface->set_mute != NULL) -        return iface->set_mute (ctl, mute); +        klass = MATE_MIXER_STREAM_CONTROL_GET_CLASS (control); +        if (G_LIKELY (klass->set_mute != NULL)) +            return klass->set_mute (control, mute); +    }      return FALSE;  }  guint -mate_mixer_stream_control_get_volume (MateMixerStreamControl *ctl) +mate_mixer_stream_control_get_num_channels (MateMixerStreamControl *control)  { -    guint volume = 0; +    MateMixerStreamControlClass *klass; + +    g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (control), 0); -    g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (ctl), 0); +    klass = MATE_MIXER_STREAM_CONTROL_GET_CLASS (control); -    g_object_get (G_OBJECT (ctl), -                  "volume", &volume, -                  NULL); +    if (klass->get_num_channels != NULL) +        return klass->get_num_channels (control); -    return volume; +    return 0;  } -gboolean -mate_mixer_stream_control_set_volume (MateMixerStreamControl *ctl, guint volume) +guint +mate_mixer_stream_control_get_volume (MateMixerStreamControl *control)  { -    MateMixerStreamControlInterface *iface; - -    g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (ctl), FALSE); +    g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (control), 0); -    iface = MATE_MIXER_STREAM_CONTROL_GET_INTERFACE (ctl); +    if (control->priv->flags & MATE_MIXER_STREAM_CONTROL_HAS_VOLUME) { +        MateMixerStreamControlClass *klass; -    if (iface->set_volume != NULL) -        return iface->set_volume (ctl, volume); +        klass = MATE_MIXER_STREAM_CONTROL_GET_CLASS (control); -    return FALSE; +        if G_LIKELY (klass->get_volume != NULL) +            return klass->get_volume (control); +    } +    return 0;  } -gdouble -mate_mixer_stream_control_get_decibel (MateMixerStreamControl *ctl) +gboolean +mate_mixer_stream_control_set_volume (MateMixerStreamControl *control, guint volume)  { -    MateMixerStreamControlInterface *iface; +    g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (control), FALSE); -    g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (ctl), -MATE_MIXER_INFINITY); +    if (control->priv->flags & MATE_MIXER_STREAM_CONTROL_HAS_VOLUME) { +        MateMixerStreamControlClass *klass; -    iface = MATE_MIXER_STREAM_CONTROL_GET_INTERFACE (ctl); +        klass = MATE_MIXER_STREAM_CONTROL_GET_CLASS (control); -    if (iface->get_decibel != NULL) -        return iface->get_decibel (ctl); - -    return -MATE_MIXER_INFINITY; +        if (G_LIKELY (klass->set_volume != NULL)) +            return klass->set_volume (control, volume); +    } +    return FALSE;  } -gboolean -mate_mixer_stream_control_set_decibel (MateMixerStreamControl *ctl, gdouble decibel) +gdouble +mate_mixer_stream_control_get_decibel (MateMixerStreamControl *control)  { -    MateMixerStreamControlInterface *iface; +    g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (control), -MATE_MIXER_INFINITY); -    g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (ctl), FALSE); +    if (control->priv->flags & MATE_MIXER_STREAM_CONTROL_HAS_DECIBEL) { +        MateMixerStreamControlClass *klass; -    iface = MATE_MIXER_STREAM_CONTROL_GET_INTERFACE (ctl); +        klass = MATE_MIXER_STREAM_CONTROL_GET_CLASS (control); -    if (iface->set_decibel != NULL) -        return iface->set_decibel (ctl, decibel); - -    return FALSE; +        if (G_LIKELY (klass->get_decibel != NULL)) +            return klass->get_decibel (control); +    } +    return -MATE_MIXER_INFINITY;  } -guint -mate_mixer_stream_control_get_num_channels (MateMixerStreamControl *ctl) +gboolean +mate_mixer_stream_control_set_decibel (MateMixerStreamControl *control, gdouble decibel)  { -    MateMixerStreamControlInterface *iface; - -    g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (ctl), 0); +    g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (control), FALSE); -    iface = MATE_MIXER_STREAM_CONTROL_GET_INTERFACE (ctl); +    if (control->priv->flags & MATE_MIXER_STREAM_CONTROL_HAS_DECIBEL) { +        MateMixerStreamControlClass *klass; -    if (iface->get_num_channels != NULL) -        return iface->get_num_channels (ctl); +        klass = MATE_MIXER_STREAM_CONTROL_GET_CLASS (control); -    return 0; +        if (G_LIKELY (klass->set_decibel != NULL)) +            return klass->set_decibel (control, decibel); +    } +    return FALSE;  }  MateMixerChannelPosition -mate_mixer_stream_control_get_channel_position (MateMixerStreamControl *ctl, guint channel) +mate_mixer_stream_control_get_channel_position (MateMixerStreamControl *control, guint channel)  { -    MateMixerStreamControlInterface *iface; +    MateMixerStreamControlClass *klass; -    g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (ctl), MATE_MIXER_CHANNEL_UNKNOWN); +    g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (control), MATE_MIXER_CHANNEL_UNKNOWN); -    iface = MATE_MIXER_STREAM_CONTROL_GET_INTERFACE (ctl); +    klass = MATE_MIXER_STREAM_CONTROL_GET_CLASS (control); -    if (iface->get_channel_position != NULL) -        return iface->get_channel_position (ctl, channel); +    if (klass->get_channel_position != NULL) +        return klass->get_channel_position (control, channel);      return MATE_MIXER_CHANNEL_UNKNOWN;  }  guint -mate_mixer_stream_control_get_channel_volume (MateMixerStreamControl *ctl, guint channel) +mate_mixer_stream_control_get_channel_volume (MateMixerStreamControl *control, guint channel)  { -    MateMixerStreamControlInterface *iface; +    g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (control), 0); -    g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (ctl), 0); +    if (control->priv->flags & MATE_MIXER_STREAM_CONTROL_HAS_VOLUME) { +        MateMixerStreamControlClass *klass; -    iface = MATE_MIXER_STREAM_CONTROL_GET_INTERFACE (ctl); - -    if (iface->get_channel_volume != NULL) -        return iface->get_channel_volume (ctl, channel); +        klass = MATE_MIXER_STREAM_CONTROL_GET_CLASS (control); +        if (G_LIKELY (klass->get_channel_volume != NULL)) +            return klass->get_channel_volume (control, channel); +    }      return 0;  }  gboolean -mate_mixer_stream_control_set_channel_volume (MateMixerStreamControl *ctl, +mate_mixer_stream_control_set_channel_volume (MateMixerStreamControl *control,                                                guint                   channel,                                                guint                   volume)  { -    MateMixerStreamControlInterface *iface; - -    g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (ctl), FALSE); +    g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (control), FALSE); -    iface = MATE_MIXER_STREAM_CONTROL_GET_INTERFACE (ctl); +    if (control->priv->flags & MATE_MIXER_STREAM_CONTROL_HAS_VOLUME) { +        MateMixerStreamControlClass *klass; -    if (iface->set_channel_volume != NULL) -        return iface->set_channel_volume (ctl, channel, volume); +        klass = MATE_MIXER_STREAM_CONTROL_GET_CLASS (control); +        if (G_LIKELY (klass->set_channel_volume != NULL)) +            return klass->set_channel_volume (control, channel, volume); +    }      return FALSE;  }  gdouble -mate_mixer_stream_control_get_channel_decibel (MateMixerStreamControl *ctl, guint channel) +mate_mixer_stream_control_get_channel_decibel (MateMixerStreamControl *control, guint channel)  { -    MateMixerStreamControlInterface *iface; +    g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (control), -MATE_MIXER_INFINITY); -    g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (ctl), -MATE_MIXER_INFINITY); +    if (control->priv->flags & MATE_MIXER_STREAM_CONTROL_HAS_DECIBEL) { +        MateMixerStreamControlClass *klass; -    iface = MATE_MIXER_STREAM_CONTROL_GET_INTERFACE (ctl); - -    if (iface->get_channel_decibel != NULL) -        return iface->get_channel_decibel (ctl, channel); +        klass = MATE_MIXER_STREAM_CONTROL_GET_CLASS (control); +        if (G_LIKELY (klass->get_channel_decibel != NULL)) +            return klass->get_channel_decibel (control, channel); +    }      return -MATE_MIXER_INFINITY;  }  gboolean -mate_mixer_stream_control_set_channel_decibel (MateMixerStreamControl *ctl, +mate_mixer_stream_control_set_channel_decibel (MateMixerStreamControl *control,                                                 guint                   channel,                                                 gdouble                 decibel)  { -    MateMixerStreamControlInterface *iface; - -    g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (ctl), FALSE); +    g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (control), FALSE); -    iface = MATE_MIXER_STREAM_CONTROL_GET_INTERFACE (ctl); +    if (control->priv->flags & MATE_MIXER_STREAM_CONTROL_HAS_DECIBEL) { +        MateMixerStreamControlClass *klass; -    if (iface->set_channel_decibel != NULL) -        return iface->set_channel_decibel (ctl, channel, decibel); +        klass = MATE_MIXER_STREAM_CONTROL_GET_CLASS (control); +        if (G_LIKELY (klass->set_channel_decibel != NULL)) +            return klass->set_channel_decibel (control, channel, decibel); +    }      return FALSE;  }  gboolean -mate_mixer_stream_control_has_channel_position (MateMixerStreamControl   *ctl, +mate_mixer_stream_control_has_channel_position (MateMixerStreamControl   *control,                                                  MateMixerChannelPosition  position)  { -    MateMixerStreamControlInterface *iface; +    MateMixerStreamControlClass *klass; -    g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (ctl), FALSE); +    g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (control), FALSE); -    iface = MATE_MIXER_STREAM_CONTROL_GET_INTERFACE (ctl); +    klass = MATE_MIXER_STREAM_CONTROL_GET_CLASS (control); -    if (iface->has_channel_position != NULL) -        return iface->has_channel_position (ctl, position); +    if (klass->has_channel_position != NULL) +        return klass->has_channel_position (control, position);      return FALSE;  }  gfloat -mate_mixer_stream_control_get_balance (MateMixerStreamControl *ctl) +mate_mixer_stream_control_get_balance (MateMixerStreamControl *control)  { -    gfloat balance = 0.0f; +    g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (control), 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 balance; +    if (control->priv->flags & MATE_MIXER_STREAM_CONTROL_CAN_BALANCE) +        return control->priv->balance; +    else +        return 0.0f;  }  gboolean -mate_mixer_stream_control_set_balance (MateMixerStreamControl *ctl, gfloat balance) +mate_mixer_stream_control_set_balance (MateMixerStreamControl *control, gfloat balance)  { -    MateMixerStreamControlInterface *iface; +    g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (control), FALSE); -    g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (ctl), FALSE); +    if (control->priv->flags & MATE_MIXER_STREAM_CONTROL_CAN_BALANCE) { +        MateMixerStreamControlClass *klass; -    iface = MATE_MIXER_STREAM_CONTROL_GET_INTERFACE (ctl); +        if (balance < -1.0f || balance > 1.0f) +            return FALSE; -    if (iface->set_balance != NULL) -        return iface->set_balance (ctl, balance); +        klass = MATE_MIXER_STREAM_CONTROL_GET_CLASS (control); +        if (G_LIKELY (klass->set_balance != NULL)) +            return klass->set_balance (control, balance); +    }      return FALSE;  }  gfloat -mate_mixer_stream_control_get_fade (MateMixerStreamControl *ctl) +mate_mixer_stream_control_get_fade (MateMixerStreamControl *control)  { -    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); +    g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (control), 0.0f); -    return fade; +    if (control->priv->flags & MATE_MIXER_STREAM_CONTROL_CAN_FADE) +        return control->priv->fade; +    else +        return 0.0f;  }  gboolean -mate_mixer_stream_control_set_fade (MateMixerStreamControl *ctl, gfloat fade) +mate_mixer_stream_control_set_fade (MateMixerStreamControl *control, gfloat fade)  { -    MateMixerStreamControlInterface *iface; +    g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (control), FALSE); -    g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (ctl), FALSE); +    if (control->priv->flags & MATE_MIXER_STREAM_CONTROL_CAN_FADE) { +        MateMixerStreamControlClass *klass; -    iface = MATE_MIXER_STREAM_CONTROL_GET_INTERFACE (ctl); +        if (fade < -1.0f || fade > 1.0f) +            return FALSE; -    if (iface->set_fade != NULL) -        return iface->set_fade (ctl, fade); +        klass = MATE_MIXER_STREAM_CONTROL_GET_CLASS (control); +        if (G_LIKELY (klass->set_fade != NULL)) +            return klass->set_fade (control, fade); +    }      return FALSE;  }  guint -mate_mixer_stream_control_get_min_volume (MateMixerStreamControl *ctl) +mate_mixer_stream_control_get_min_volume (MateMixerStreamControl *control)  { -    MateMixerStreamControlInterface *iface; +    MateMixerStreamControlClass *klass; -    g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (ctl), 0); +    g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (control), 0); -    iface = MATE_MIXER_STREAM_CONTROL_GET_INTERFACE (ctl); +    klass = MATE_MIXER_STREAM_CONTROL_GET_CLASS (control); -    if (iface->get_min_volume != NULL) -        return iface->get_min_volume (ctl); +    if (klass->get_min_volume != NULL) +        return klass->get_min_volume (control);      return 0;  }  guint -mate_mixer_stream_control_get_max_volume (MateMixerStreamControl *ctl) +mate_mixer_stream_control_get_max_volume (MateMixerStreamControl *control)  { -    MateMixerStreamControlInterface *iface; +    MateMixerStreamControlClass *klass; -    g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (ctl), 0); +    g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (control), 0); -    iface = MATE_MIXER_STREAM_CONTROL_GET_INTERFACE (ctl); +    klass = MATE_MIXER_STREAM_CONTROL_GET_CLASS (control); -    if (iface->get_max_volume != NULL) -        return iface->get_max_volume (ctl); +    if (klass->get_max_volume != NULL) +        return klass->get_max_volume (control);      return 0;  }  guint -mate_mixer_stream_control_get_normal_volume (MateMixerStreamControl *ctl) +mate_mixer_stream_control_get_normal_volume (MateMixerStreamControl *control)  { -    MateMixerStreamControlInterface *iface; +    MateMixerStreamControlClass *klass; -    g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (ctl), 0); +    g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (control), 0); -    iface = MATE_MIXER_STREAM_CONTROL_GET_INTERFACE (ctl); +    klass = MATE_MIXER_STREAM_CONTROL_GET_CLASS (control); -    if (iface->get_normal_volume != NULL) -        return iface->get_normal_volume (ctl); +    if (klass->get_normal_volume != NULL) +        return klass->get_normal_volume (control);      return 0;  }  guint -mate_mixer_stream_control_get_base_volume (MateMixerStreamControl *ctl) +mate_mixer_stream_control_get_base_volume (MateMixerStreamControl *control)  { -    MateMixerStreamControlInterface *iface; +    MateMixerStreamControlClass *klass; -    g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (ctl), 0); +    g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (control), 0); -    iface = MATE_MIXER_STREAM_CONTROL_GET_INTERFACE (ctl); +    klass = MATE_MIXER_STREAM_CONTROL_GET_CLASS (control); -    if (iface->get_base_volume != NULL) -        return iface->get_base_volume (ctl); +    if (klass->get_base_volume != NULL) +        return klass->get_base_volume (control);      return 0;  } + +void +_mate_mixer_stream_control_set_flags (MateMixerStreamControl     *control, +                                      MateMixerStreamControlFlags flags) +{ +    control->priv->flags = flags; +} + +void +_mate_mixer_stream_control_set_mute (MateMixerStreamControl *control, gboolean mute) +{ +    control->priv->mute = mute; +} + +void +_mate_mixer_stream_control_set_balance (MateMixerStreamControl *control, gfloat balance) +{ +    control->priv->balance = balance; +} + +void +_mate_mixer_stream_control_set_fade (MateMixerStreamControl *control, gfloat fade) +{ +    control->priv->fade = fade; +} diff --git a/libmatemixer/matemixer-stream-control.h b/libmatemixer/matemixer-stream-control.h index 727ed54..51d7f95 100644 --- a/libmatemixer/matemixer-stream-control.h +++ b/libmatemixer/matemixer-stream-control.h @@ -23,6 +23,7 @@  #include <glib-object.h>  #include <libmatemixer/matemixer-enums.h> +#include <libmatemixer/matemixer-types.h>  G_BEGIN_DECLS @@ -32,116 +33,127 @@ G_BEGIN_DECLS  #  define MATE_MIXER_INFINITY G_MAXDOUBLE  #endif -#define MATE_MIXER_TYPE_STREAM_CONTROL                  \ +#define MATE_MIXER_TYPE_STREAM_CONTROL          \          (mate_mixer_stream_control_get_type ()) -#define MATE_MIXER_STREAM_CONTROL(o)                    \ +#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)                 \ +#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)) +#define MATE_MIXER_STREAM_CONTROL_CLASS(k)      \ +        (G_TYPE_CHECK_CLASS_CAST ((k), MATE_MIXER_TYPE_STREAM_CONTROL, MateMixerStreamControlClass)) +#define MATE_MIXER_IS_STREAM_CONTROL_CLASS(k)   \ +        (G_TYPE_CHECK_CLASS_TYPE ((k), MATE_MIXER_TYPE_STREAM_CONTROL)) +#define MATE_MIXER_STREAM_CONTROL_GET_CLASS(o)  \ +        (G_TYPE_INSTANCE_GET_CLASS ((o), MATE_MIXER_TYPE_STREAM_CONTROL, MateMixerStreamControlClass)) -typedef struct _MateMixerStreamControl           MateMixerStreamControl; /* dummy object */ -typedef struct _MateMixerStreamControlInterface  MateMixerStreamControlInterface; +typedef struct _MateMixerStreamControlClass    MateMixerStreamControlClass; +typedef struct _MateMixerStreamControlPrivate  MateMixerStreamControlPrivate; -struct _MateMixerStreamControlInterface +struct _MateMixerStreamControl  { -    GTypeInterface parent_iface; +    GObject object;      /*< 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); +    MateMixerStreamControlPrivate *priv; +}; -    gboolean                    (*set_fade)               (MateMixerStreamControl   *ctl, -                                                           gfloat                    fade); +struct _MateMixerStreamControlClass +{ +    GObjectClass parent_class; -    guint                       (*get_min_volume)         (MateMixerStreamControl   *ctl); -    guint                       (*get_max_volume)         (MateMixerStreamControl   *ctl); -    guint                       (*get_normal_volume)      (MateMixerStreamControl   *ctl); -    guint                       (*get_base_volume)        (MateMixerStreamControl   *ctl); +    /*< private >*/ +    gboolean                    (*set_mute)             (MateMixerStreamControl   *control, +                                                         gboolean                  mute); + +    guint                       (*get_num_channels)     (MateMixerStreamControl   *control); + +    guint                       (*get_volume)           (MateMixerStreamControl   *control); +    gboolean                    (*set_volume)           (MateMixerStreamControl   *control, +                                                         guint                     volume); + +    gdouble                     (*get_decibel)          (MateMixerStreamControl   *control); +    gboolean                    (*set_decibel)          (MateMixerStreamControl   *control, +                                                         gdouble                   decibel); + +    gboolean                    (*has_channel_position) (MateMixerStreamControl   *control, +                                                         MateMixerChannelPosition  position); +    MateMixerChannelPosition    (*get_channel_position) (MateMixerStreamControl   *control, +                                                         guint                     channel); + +    guint                       (*get_channel_volume)   (MateMixerStreamControl   *control, +                                                         guint                     channel); +    gboolean                    (*set_channel_volume)   (MateMixerStreamControl   *control, +                                                         guint                     channel, +                                                         guint                     volume); + +    gdouble                     (*get_channel_decibel)  (MateMixerStreamControl   *control, +                                                         guint                     channel); +    gboolean                    (*set_channel_decibel)  (MateMixerStreamControl   *control, +                                                         guint                     channel, +                                                         gdouble                   decibel); + +    gboolean                    (*set_balance)          (MateMixerStreamControl   *control, +                                                         gfloat                    balance); + +    gboolean                    (*set_fade)             (MateMixerStreamControl   *control, +                                                         gfloat                    fade); + +    guint                       (*get_min_volume)       (MateMixerStreamControl   *control); +    guint                       (*get_max_volume)       (MateMixerStreamControl   *control); +    guint                       (*get_normal_volume)    (MateMixerStreamControl   *control); +    guint                       (*get_base_volume)      (MateMixerStreamControl   *control);  };  GType                       mate_mixer_stream_control_get_type             (void) G_GNUC_CONST; -const gchar *               mate_mixer_stream_control_get_name             (MateMixerStreamControl   *ctl); -const gchar *               mate_mixer_stream_control_get_description      (MateMixerStreamControl   *ctl); -MateMixerStreamControlFlags mate_mixer_stream_control_get_flags            (MateMixerStreamControl   *ctl); +const gchar *               mate_mixer_stream_control_get_name             (MateMixerStreamControl   *control); +const gchar *               mate_mixer_stream_control_get_label            (MateMixerStreamControl   *control); +MateMixerStreamControlFlags mate_mixer_stream_control_get_flags            (MateMixerStreamControl   *control); +MateMixerStreamControlRole  mate_mixer_stream_control_get_role             (MateMixerStreamControl   *control); -gboolean                    mate_mixer_stream_control_get_mute             (MateMixerStreamControl   *ctl); -gboolean                    mate_mixer_stream_control_set_mute             (MateMixerStreamControl   *ctl, +gboolean                    mate_mixer_stream_control_get_mute             (MateMixerStreamControl   *control); +gboolean                    mate_mixer_stream_control_set_mute             (MateMixerStreamControl   *control,                                                                              gboolean                  mute); -guint                       mate_mixer_stream_control_get_num_channels     (MateMixerStreamControl   *ctl); +guint                       mate_mixer_stream_control_get_num_channels     (MateMixerStreamControl   *control); -guint                       mate_mixer_stream_control_get_volume           (MateMixerStreamControl   *ctl); -gboolean                    mate_mixer_stream_control_set_volume           (MateMixerStreamControl   *ctl, +guint                       mate_mixer_stream_control_get_volume           (MateMixerStreamControl   *control); +gboolean                    mate_mixer_stream_control_set_volume           (MateMixerStreamControl   *control,                                                                              guint                     volume); -gdouble                     mate_mixer_stream_control_get_decibel          (MateMixerStreamControl   *ctl); -gboolean                    mate_mixer_stream_control_set_decibel          (MateMixerStreamControl   *ctl, +gdouble                     mate_mixer_stream_control_get_decibel          (MateMixerStreamControl   *control); +gboolean                    mate_mixer_stream_control_set_decibel          (MateMixerStreamControl   *control,                                                                              gdouble                   decibel); -gboolean                    mate_mixer_stream_control_has_channel_position (MateMixerStreamControl   *ctl, +gboolean                    mate_mixer_stream_control_has_channel_position (MateMixerStreamControl   *control,                                                                              MateMixerChannelPosition  position); -MateMixerChannelPosition    mate_mixer_stream_control_get_channel_position (MateMixerStreamControl   *ctl, +MateMixerChannelPosition    mate_mixer_stream_control_get_channel_position (MateMixerStreamControl   *control,                                                                              guint                     channel); -guint                       mate_mixer_stream_control_get_channel_volume   (MateMixerStreamControl   *ctl, +guint                       mate_mixer_stream_control_get_channel_volume   (MateMixerStreamControl   *control,                                                                              guint                     channel); -gboolean                    mate_mixer_stream_control_set_channel_volume   (MateMixerStreamControl   *ctl, +gboolean                    mate_mixer_stream_control_set_channel_volume   (MateMixerStreamControl   *control,                                                                              guint                     channel,                                                                              guint                     volume); -gdouble                     mate_mixer_stream_control_get_channel_decibel  (MateMixerStreamControl   *ctl, +gdouble                     mate_mixer_stream_control_get_channel_decibel  (MateMixerStreamControl   *control,                                                                              guint                     channel); -gboolean                    mate_mixer_stream_control_set_channel_decibel  (MateMixerStreamControl   *ctl, +gboolean                    mate_mixer_stream_control_set_channel_decibel  (MateMixerStreamControl   *control,                                                                              guint                     channel,                                                                              gdouble                   decibel); -gfloat                      mate_mixer_stream_control_get_balance          (MateMixerStreamControl   *ctl); -gboolean                    mate_mixer_stream_control_set_balance          (MateMixerStreamControl   *ctl, +gfloat                      mate_mixer_stream_control_get_balance          (MateMixerStreamControl   *control); +gboolean                    mate_mixer_stream_control_set_balance          (MateMixerStreamControl   *control,                                                                              gfloat                    balance); -gfloat                      mate_mixer_stream_control_get_fade             (MateMixerStreamControl   *ctl); -gboolean                    mate_mixer_stream_control_set_fade             (MateMixerStreamControl   *ctl, +gfloat                      mate_mixer_stream_control_get_fade             (MateMixerStreamControl   *control); +gboolean                    mate_mixer_stream_control_set_fade             (MateMixerStreamControl   *control,                                                                              gfloat                    fade); -guint                       mate_mixer_stream_control_get_min_volume       (MateMixerStreamControl   *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); +guint                       mate_mixer_stream_control_get_min_volume       (MateMixerStreamControl   *control); +guint                       mate_mixer_stream_control_get_max_volume       (MateMixerStreamControl   *control); +guint                       mate_mixer_stream_control_get_normal_volume    (MateMixerStreamControl   *control); +guint                       mate_mixer_stream_control_get_base_volume      (MateMixerStreamControl   *control);  G_END_DECLS diff --git a/libmatemixer/matemixer-stream.c b/libmatemixer/matemixer-stream.c index 888fddb..1902de3 100644 --- a/libmatemixer/matemixer-stream.c +++ b/libmatemixer/matemixer-stream.c @@ -15,20 +15,44 @@   * License along with this library; if not, see <http://www.gnu.org/licenses/>.   */ +#include <string.h>  #include <glib.h>  #include <glib-object.h>  #include "matemixer-device.h"  #include "matemixer-enums.h"  #include "matemixer-enum-types.h" -#include "matemixer-port.h"  #include "matemixer-stream.h" +#include "matemixer-stream-control.h" +#include "matemixer-switch.h"  /**   * SECTION:matemixer-stream   * @include: libmatemixer/matemixer.h   */ +struct _MateMixerStreamPrivate +{ +    gchar                  *name; +    GList                  *controls; +    GList                  *switches; +    gboolean                monitor_enabled; +    MateMixerDevice        *device; +    MateMixerStreamFlags    flags; +    MateMixerStreamState    state; +}; + +enum { +    PROP_0, +    PROP_NAME, +    PROP_DEVICE, +    PROP_FLAGS, +    PROP_STATE, +    N_PROPERTIES +}; + +static GParamSpec *properties[N_PROPERTIES] = { NULL, }; +  enum {      MONITOR_VALUE,      N_SIGNALS @@ -36,245 +60,285 @@ enum {  static guint signals[N_SIGNALS] = { 0, }; -G_DEFINE_INTERFACE (MateMixerStream, mate_mixer_stream, G_TYPE_OBJECT) +static void mate_mixer_stream_class_init   (MateMixerStreamClass *klass); + +static void mate_mixer_stream_get_property (GObject              *object, +                                            guint                 param_id, +                                            GValue               *value, +                                            GParamSpec           *pspec); +static void mate_mixer_stream_set_property (GObject              *object, +                                            guint                 param_id, +                                            const GValue         *value, +                                            GParamSpec           *pspec); + +static void mate_mixer_stream_init         (MateMixerStream      *stream); +static void mate_mixer_stream_dispose      (GObject              *object); +static void mate_mixer_stream_finalize     (GObject              *object); + +G_DEFINE_ABSTRACT_TYPE (MateMixerStream, mate_mixer_stream, G_TYPE_OBJECT) + +static MateMixerStreamControl *mate_mixer_stream_real_get_control (MateMixerStream *stream, +                                                                   const gchar     *name); +static MateMixerSwitch *       mate_mixer_stream_real_get_switch  (MateMixerStream *stream, +                                                                   const gchar     *name);  static void -mate_mixer_stream_default_init (MateMixerStreamInterface *iface) +mate_mixer_stream_class_init (MateMixerStreamClass *klass)  { -    g_object_interface_install_property (iface, -                                         g_param_spec_string ("name", -                                                              "Name", -                                                              "Name of the stream", -                                                              NULL, -                                                              G_PARAM_READABLE | -                                                              G_PARAM_STATIC_STRINGS)); - -    g_object_interface_install_property (iface, -                                         g_param_spec_string ("description", -                                                              "Description", -                                                              "Description of the stream", -                                                              NULL, -                                                              G_PARAM_READABLE | -                                                              G_PARAM_STATIC_STRINGS)); - -    g_object_interface_install_property (iface, -                                         g_param_spec_object ("device", -                                                              "Device", -                                                              "Device the stream belongs to", -                                                              MATE_MIXER_TYPE_DEVICE, -                                                              G_PARAM_READABLE | -                                                              G_PARAM_STATIC_STRINGS)); - -    g_object_interface_install_property (iface, -                                         g_param_spec_flags ("flags", -                                                             "Flags", -                                                             "Capability flags of the stream", -                                                              MATE_MIXER_TYPE_STREAM_FLAGS, -                                                              MATE_MIXER_STREAM_NO_FLAGS, -                                                              G_PARAM_READABLE | -                                                              G_PARAM_STATIC_STRINGS)); - -    g_object_interface_install_property (iface, -                                         g_param_spec_enum ("state", -                                                            "State", -                                                            "Current state of the stream", -                                                            MATE_MIXER_TYPE_STREAM_STATE, -                                                            MATE_MIXER_STREAM_STATE_UNKNOWN, -                                                            G_PARAM_READABLE | -                                                            G_PARAM_STATIC_STRINGS)); - -    g_object_interface_install_property (iface, -                                         g_param_spec_object ("active-port", -                                                              "Active port", -                                                              "The currently active port of the stream", -                                                              MATE_MIXER_TYPE_PORT, -                                                              G_PARAM_READABLE | -                                                              G_PARAM_STATIC_STRINGS)); +    GObjectClass *object_class; + +    klass->get_control = mate_mixer_stream_real_get_control; +    klass->get_switch  = mate_mixer_stream_real_get_switch; + +    object_class = G_OBJECT_CLASS (klass); +    object_class->dispose      = mate_mixer_stream_dispose; +    object_class->finalize     = mate_mixer_stream_finalize; +    object_class->get_property = mate_mixer_stream_get_property; +    object_class->set_property = mate_mixer_stream_set_property; + +    properties[PROP_NAME] = +        g_param_spec_string ("name", +                             "Name", +                             "Name of the stream", +                             NULL, +                             G_PARAM_READWRITE | +                             G_PARAM_CONSTRUCT_ONLY | +                             G_PARAM_STATIC_STRINGS); + +    properties[PROP_DEVICE] = +        g_param_spec_object ("device", +                             "Device", +                             "Device the stream belongs to", +                             MATE_MIXER_TYPE_DEVICE, +                             G_PARAM_READWRITE | +                             G_PARAM_CONSTRUCT_ONLY | +                             G_PARAM_STATIC_STRINGS); + +    properties[PROP_FLAGS] = +        g_param_spec_flags ("flags", +                            "Flags", +                            "Capability flags of the stream", +                            MATE_MIXER_TYPE_STREAM_FLAGS, +                            MATE_MIXER_STREAM_NO_FLAGS, +                            G_PARAM_READWRITE | +                            G_PARAM_CONSTRUCT_ONLY | +                            G_PARAM_STATIC_STRINGS); + +    properties[PROP_STATE] = +        g_param_spec_enum ("state", +                           "State", +                           "Current state of the stream", +                           MATE_MIXER_TYPE_STREAM_STATE, +                           MATE_MIXER_STREAM_STATE_UNKNOWN, +                           G_PARAM_READWRITE | +                           G_PARAM_CONSTRUCT_ONLY | +                           G_PARAM_STATIC_STRINGS); + +    g_object_class_install_properties (object_class, N_PROPERTIES, properties);      signals[MONITOR_VALUE] =          g_signal_new ("monitor-value", -                      G_TYPE_FROM_INTERFACE (iface), +                      G_TYPE_FROM_CLASS (klass),                        G_SIGNAL_RUN_LAST, -                      G_STRUCT_OFFSET (MateMixerStreamInterface, monitor_value), +                      G_STRUCT_OFFSET (MateMixerStreamClass, monitor_value),                        NULL,                        NULL,                        g_cclosure_marshal_VOID__DOUBLE,                        G_TYPE_NONE,                        1,                        G_TYPE_DOUBLE); + +    g_type_class_add_private (object_class, sizeof (MateMixerStreamPrivate));  } -const gchar * -mate_mixer_stream_get_name (MateMixerStream *stream) +static void +mate_mixer_stream_get_property (GObject    *object, +                                guint       param_id, +                                GValue     *value, +                                GParamSpec *pspec)  { -    g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), NULL); - -    /* Implementation required */ -    return MATE_MIXER_STREAM_GET_INTERFACE (stream)->get_name (stream); +    MateMixerStream *stream; + +    stream = MATE_MIXER_STREAM (object); + +    switch (param_id) { +    case PROP_NAME: +        g_value_set_string (value, stream->priv->name); +        break; +    case PROP_DEVICE: +        g_value_set_object (value, stream->priv->device); +        break; +    case PROP_FLAGS: +        g_value_set_flags (value, stream->priv->flags); +        break; +    case PROP_STATE: +        g_value_set_enum (value, stream->priv->state); +        break; + +    default: +        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); +        break; +    }  } -const gchar * -mate_mixer_stream_get_description (MateMixerStream *stream) +static void +mate_mixer_stream_set_property (GObject      *object, +                                guint         param_id, +                                const GValue *value, +                                GParamSpec   *pspec)  { -    g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), NULL); - -    /* Implementation required */ -    return MATE_MIXER_STREAM_GET_INTERFACE (stream)->get_description (stream); +    MateMixerStream *stream; + +    stream = MATE_MIXER_STREAM (object); + +    switch (param_id) { +    case PROP_NAME: +        /* Construct-only string */ +        stream->priv->name = g_value_dup_string (value); +        break; +    case PROP_DEVICE: +        /* Construct-only object */ +        stream->priv->device = g_value_dup_object (value); +        break; +    case PROP_FLAGS: +        stream->priv->flags = g_value_get_flags (value); +        break; +    case PROP_STATE: +        stream->priv->state = g_value_get_enum (value); +        break; + +    default: +        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); +        break; +    }  } -MateMixerDevice * -mate_mixer_stream_get_device (MateMixerStream *stream) +static void +mate_mixer_stream_init (MateMixerStream *stream)  { -    MateMixerDevice *device = NULL; - -    g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), NULL); - -    g_object_get (G_OBJECT (stream), -                  "device", &device, -                  NULL); - -    if (device != NULL) -        g_object_unref (device); - -    return device; - +    stream->priv = G_TYPE_INSTANCE_GET_PRIVATE (stream, +                                                MATE_MIXER_TYPE_STREAM, +                                                MateMixerStreamPrivate);  } -MateMixerStreamFlags -mate_mixer_stream_get_flags (MateMixerStream *stream) +static void +mate_mixer_stream_dispose (GObject *object)  { -    MateMixerStreamFlags flags = MATE_MIXER_STREAM_NO_FLAGS; +    MateMixerStream *stream; -    g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), MATE_MIXER_STREAM_NO_FLAGS); +    stream = MATE_MIXER_STREAM (object); -    g_object_get (G_OBJECT (stream), -                  "flags", &flags, -                  NULL); +    g_clear_object (&stream->priv->device); -    return flags; +    G_OBJECT_CLASS (mate_mixer_stream_parent_class)->dispose (object);  } -MateMixerStreamState -mate_mixer_stream_get_state (MateMixerStream *stream) +static void +mate_mixer_stream_finalize (GObject *object)  { -    MateMixerStreamState state = MATE_MIXER_STREAM_STATE_UNKNOWN; +    MateMixerStream *stream; -    g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), MATE_MIXER_STREAM_STATE_UNKNOWN); +    stream = MATE_MIXER_STREAM (object); -    g_object_get (G_OBJECT (stream), -                  "state", &state, -                  NULL); +    g_free (stream->priv->name); -    return state; +    G_OBJECT_CLASS (mate_mixer_stream_parent_class)->finalize (object);  } -MateMixerStreamControl * -mate_mixer_stream_get_control (MateMixerStream *stream, const gchar *name) +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_control (stream, name); +    return stream->priv->name;  } -MateMixerStreamControl * -mate_mixer_stream_get_default_control (MateMixerStream *stream) +MateMixerDevice * +mate_mixer_stream_get_device (MateMixerStream *stream)  {      g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), NULL); -    /* Implementation required */ -    return MATE_MIXER_STREAM_GET_INTERFACE (stream)->get_default_control (stream); +    return stream->priv->device;  } -MateMixerPort * -mate_mixer_stream_get_port (MateMixerStream *stream, const gchar *name) +MateMixerStreamFlags +mate_mixer_stream_get_flags (MateMixerStream *stream)  { -    MateMixerStreamInterface *iface; - -    g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), NULL); +    g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), MATE_MIXER_STREAM_NO_FLAGS); -    iface = MATE_MIXER_STREAM_GET_INTERFACE (stream); +    return stream->priv->flags; +} -    if (iface->get_port != NULL) -        return iface->get_port (stream, name); +MateMixerStreamState +mate_mixer_stream_get_state (MateMixerStream *stream) +{ +    g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), MATE_MIXER_STREAM_STATE_UNKNOWN); -    return FALSE; +    return stream->priv->state;  } -MateMixerPort * -mate_mixer_stream_get_active_port (MateMixerStream *stream) +MateMixerStreamControl * +mate_mixer_stream_get_control (MateMixerStream *stream, const gchar *name)  { -    MateMixerPort *port = NULL; -      g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), NULL); +    g_return_val_if_fail (name != NULL, NULL); -    g_object_get (G_OBJECT (stream), -                  "active-port", &port, -                  NULL); - -    if (port != NULL) -        g_object_unref (port); - -    return port; +    return MATE_MIXER_STREAM_GET_CLASS (stream)->get_control (stream, name);  } -gboolean -mate_mixer_stream_set_active_port (MateMixerStream *stream, MateMixerPort *port) +MateMixerSwitch * +mate_mixer_stream_get_switch (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); +    g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), NULL); +    g_return_val_if_fail (name != NULL, NULL); -    iface = MATE_MIXER_STREAM_GET_INTERFACE (stream); +    return MATE_MIXER_STREAM_GET_CLASS (stream)->get_switch (stream, name); +} -    if (iface->set_active_port != NULL) -        return iface->set_active_port (stream, port); +MateMixerStreamControl * +mate_mixer_stream_get_default_control (MateMixerStream *stream) +{ +    g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), NULL); -    return FALSE; +    return MATE_MIXER_STREAM_GET_CLASS (stream)->get_default_control (stream);  }  const GList *  mate_mixer_stream_list_controls (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_controls != NULL) -        return iface->list_controls (stream); +    if (stream->priv->controls == NULL) +        stream->priv->controls = MATE_MIXER_STREAM_GET_CLASS (stream)->list_controls (stream); -    return NULL; +    return (const GList *) stream->priv->controls;  }  const GList * -mate_mixer_stream_list_ports (MateMixerStream *stream) +mate_mixer_stream_list_switches (MateMixerStream *stream)  { -    MateMixerStreamInterface *iface; -      g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), NULL); -    iface = MATE_MIXER_STREAM_GET_INTERFACE (stream); +    if (stream->priv->switches == NULL) { +        MateMixerStreamClass *klass = MATE_MIXER_STREAM_GET_CLASS (stream); -    if (iface->list_ports != NULL) -        return iface->list_ports (stream); +        if (klass->list_switches != NULL) +            stream->priv->switches = klass->list_switches (stream); +    } -    return NULL; +    return (const GList *) stream->priv->switches;  }  gboolean  mate_mixer_stream_suspend (MateMixerStream *stream)  { -    MateMixerStreamInterface *iface; -      g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), FALSE); -    iface = MATE_MIXER_STREAM_GET_INTERFACE (stream); +    if (stream->priv->state == MATE_MIXER_STREAM_STATE_SUSPENDED) +        return TRUE; -    if (iface->suspend != NULL) -        return iface->suspend (stream); +    if (stream->priv->flags & MATE_MIXER_STREAM_CAN_SUSPEND) +        return MATE_MIXER_STREAM_GET_CLASS (stream)->suspend (stream);      return FALSE;  } @@ -282,14 +346,13 @@ mate_mixer_stream_suspend (MateMixerStream *stream)  gboolean  mate_mixer_stream_resume (MateMixerStream *stream)  { -    MateMixerStreamInterface *iface; -      g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), FALSE); -    iface = MATE_MIXER_STREAM_GET_INTERFACE (stream); +    if (stream->priv->state != MATE_MIXER_STREAM_STATE_SUSPENDED) +        return TRUE; -    if (iface->resume != NULL) -        return iface->resume (stream); +    if (stream->priv->flags & MATE_MIXER_STREAM_CAN_SUSPEND) +        return MATE_MIXER_STREAM_GET_CLASS (stream)->resume (stream);      return FALSE;  } @@ -297,58 +360,65 @@ mate_mixer_stream_resume (MateMixerStream *stream)  gboolean  mate_mixer_stream_monitor_get_enabled (MateMixerStream *stream)  { -    gboolean enabled = FALSE; -      g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), FALSE); -    g_object_get (G_OBJECT (stream), -                  "monitor-enabled", &enabled, -                  NULL); - -    return enabled; +    return stream->priv->monitor_enabled;  }  gboolean  mate_mixer_stream_monitor_set_enabled (MateMixerStream *stream, gboolean enabled)  { -    MateMixerStreamInterface *iface; -      g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), FALSE); -    iface = MATE_MIXER_STREAM_GET_INTERFACE (stream); +    if (stream->priv->monitor_enabled == enabled) +        return TRUE; -    if (iface->monitor_set_enabled != NULL) -        return iface->monitor_set_enabled (stream, enabled); +    if (stream->priv->flags & MATE_MIXER_STREAM_HAS_MONITOR) { +        if (enabled) +            return MATE_MIXER_STREAM_GET_CLASS (stream)->monitor_start (stream); +        else +            return MATE_MIXER_STREAM_GET_CLASS (stream)->monitor_stop (stream); +    }      return FALSE;  } -const gchar * -mate_mixer_stream_monitor_get_name (MateMixerStream *stream) +static MateMixerStreamControl * +mate_mixer_stream_real_get_control (MateMixerStream *stream, const gchar *name)  { -    MateMixerStreamInterface *iface; +    const GList *list;      g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), NULL); +    g_return_val_if_fail (name != NULL, NULL); -    iface = MATE_MIXER_STREAM_GET_INTERFACE (stream); +    list = mate_mixer_stream_list_controls (stream); +    while (list != NULL) { +        MateMixerStreamControl *control = MATE_MIXER_STREAM_CONTROL (list->data); -    if (iface->monitor_get_name != NULL) -        return iface->monitor_get_name (stream); +        if (strcmp (name, mate_mixer_stream_control_get_name (control)) == 0) +            return control; -    return FALSE; +        list = list->next; +    } +    return NULL;  } -gboolean -mate_mixer_stream_monitor_set_name (MateMixerStream *stream, const gchar *name) +static MateMixerSwitch * +mate_mixer_stream_real_get_switch (MateMixerStream *stream, const gchar *name)  { -    MateMixerStreamInterface *iface; +    const GList *list; -    g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), FALSE); +    g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), NULL); +    g_return_val_if_fail (name != NULL, NULL); -    iface = MATE_MIXER_STREAM_GET_INTERFACE (stream); +    list = mate_mixer_stream_list_switches (stream); +    while (list != NULL) { +        MateMixerSwitch *swtch = MATE_MIXER_SWITCH (list->data); -    if (iface->monitor_set_name != NULL) -        return iface->monitor_set_name (stream, name); +        if (strcmp (name, mate_mixer_switch_get_name (swtch)) == 0) +            return swtch; -    return FALSE; +        list = list->next; +    } +    return NULL;  } diff --git a/libmatemixer/matemixer-stream.h b/libmatemixer/matemixer-stream.h index aecf40e..e73579e 100644 --- a/libmatemixer/matemixer-stream.h +++ b/libmatemixer/matemixer-stream.h @@ -21,88 +21,77 @@  #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> +#include <libmatemixer/matemixer-types.h>  G_BEGIN_DECLS -#ifdef INFINITY -#define MATE_MIXER_INFINITY INFINITY -#else -#define MATE_MIXER_INFINITY G_MAXDOUBLE -#endif -  #define MATE_MIXER_TYPE_STREAM                  \          (mate_mixer_stream_get_type ())  #define MATE_MIXER_STREAM(o)                    \          (G_TYPE_CHECK_INSTANCE_CAST ((o), MATE_MIXER_TYPE_STREAM, MateMixerStream))  #define MATE_MIXER_IS_STREAM(o)                 \          (G_TYPE_CHECK_INSTANCE_TYPE ((o), MATE_MIXER_TYPE_STREAM)) -#define MATE_MIXER_STREAM_GET_INTERFACE(o)      \ -        (G_TYPE_INSTANCE_GET_INTERFACE ((o), MATE_MIXER_TYPE_STREAM, MateMixerStreamInterface)) +#define MATE_MIXER_STREAM_CLASS(k)              \ +        (G_TYPE_CHECK_CLASS_CAST ((k), MATE_MIXER_TYPE_STREAM, MateMixerStreamClass)) +#define MATE_MIXER_IS_STREAM_CLASS(k)           \ +        (G_TYPE_CHECK_CLASS_TYPE ((k), MATE_MIXER_TYPE_STREAM)) +#define MATE_MIXER_STREAM_GET_CLASS(o)          \ +        (G_TYPE_INSTANCE_GET_CLASS ((o), MATE_MIXER_TYPE_STREAM, MateMixerStreamClass)) -typedef struct _MateMixerStream           MateMixerStream; /* dummy object */ -typedef struct _MateMixerStreamInterface  MateMixerStreamInterface; +typedef struct _MateMixerStreamClass    MateMixerStreamClass; +typedef struct _MateMixerStreamPrivate  MateMixerStreamPrivate; -struct _MateMixerStreamInterface +struct _MateMixerStream  { -    GTypeInterface parent_iface; +    GObject object;      /*< private >*/ -    const gchar *           (*get_name)            (MateMixerStream *stream); -    const gchar *           (*get_description)     (MateMixerStream *stream); +    MateMixerStreamPrivate *priv; +}; + +struct _MateMixerStreamClass +{ +    GObjectClass parent_class; +    /*< private >*/      MateMixerStreamControl *(*get_control)         (MateMixerStream *stream,                                                      const gchar     *name); +      MateMixerStreamControl *(*get_default_control) (MateMixerStream *stream); -    MateMixerPort *         (*get_port)            (MateMixerStream *stream, +    MateMixerSwitch        *(*get_switch)          (MateMixerStream *stream,                                                      const gchar     *name); -    gboolean                (*set_active_port)     (MateMixerStream *stream, -                                                    MateMixerPort   *port); - -    const GList *           (*list_controls)       (MateMixerStream *stream); -    const GList *           (*list_ports)          (MateMixerStream *stream); +    GList                  *(*list_controls)       (MateMixerStream *stream); +    GList                  *(*list_switches)       (MateMixerStream *stream);      gboolean                (*suspend)             (MateMixerStream *stream);      gboolean                (*resume)              (MateMixerStream *stream); -    gboolean                (*monitor_set_enabled) (MateMixerStream *stream, -                                                    gboolean         enabled); - -    const gchar *           (*monitor_get_name)    (MateMixerStream *stream); -    gboolean                (*monitor_set_name)    (MateMixerStream *stream, -                                                    const gchar     *name); +    gboolean                (*monitor_start)       (MateMixerStream *stream); +    gboolean                (*monitor_stop)        (MateMixerStream *stream);      /* Signals */ -    void                    (*monitor_value)       (MateMixerStream *stream, -                                                    gdouble          value); +    void (*monitor_value) (MateMixerStream *stream, gdouble value);  };  GType                   mate_mixer_stream_get_type            (void) G_GNUC_CONST;  const gchar *           mate_mixer_stream_get_name            (MateMixerStream *stream); -const gchar *           mate_mixer_stream_get_description     (MateMixerStream *stream);  MateMixerDevice *       mate_mixer_stream_get_device          (MateMixerStream *stream);  MateMixerStreamFlags    mate_mixer_stream_get_flags           (MateMixerStream *stream);  MateMixerStreamState    mate_mixer_stream_get_state           (MateMixerStream *stream);  MateMixerStreamControl *mate_mixer_stream_get_control         (MateMixerStream *stream,                                                                 const gchar     *name); -MateMixerStreamControl *mate_mixer_stream_get_default_control (MateMixerStream *stream); - -MateMixerPort *         mate_mixer_stream_get_port            (MateMixerStream *stream, +MateMixerSwitch *       mate_mixer_stream_get_switch          (MateMixerStream *stream,                                                                 const gchar     *name); -MateMixerPort *         mate_mixer_stream_get_active_port     (MateMixerStream *stream); -gboolean                mate_mixer_stream_set_active_port     (MateMixerStream *stream, -                                                               MateMixerPort   *port); +MateMixerStreamControl *mate_mixer_stream_get_default_control (MateMixerStream *stream);  const GList *           mate_mixer_stream_list_controls       (MateMixerStream *stream); -const GList *           mate_mixer_stream_list_ports          (MateMixerStream *stream); +const GList *           mate_mixer_stream_list_switches       (MateMixerStream *stream);  gboolean                mate_mixer_stream_suspend             (MateMixerStream *stream);  gboolean                mate_mixer_stream_resume              (MateMixerStream *stream); @@ -111,10 +100,6 @@ gboolean                mate_mixer_stream_monitor_get_enabled (MateMixerStream *  gboolean                mate_mixer_stream_monitor_set_enabled (MateMixerStream *stream,                                                                 gboolean         enabled); -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  #endif /* MATEMIXER_STREAM_H */ diff --git a/libmatemixer/matemixer-switch-option-private.h b/libmatemixer/matemixer-switch-option-private.h new file mode 100644 index 0000000..dea7583 --- /dev/null +++ b/libmatemixer/matemixer-switch-option-private.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2014 Michal Ratajsky <[email protected]> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the licence, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef MATEMIXER_SWITCH_OPTION_PRIVATE_H +#define MATEMIXER_SWITCH_OPTION_PRIVATE_H + +#include <glib.h> + +#include "matemixer-switch-option.h" + +G_BEGIN_DECLS + +MateMixerSwitchOption *_mate_mixer_switch_option_new (const gchar *name, +                                                      const gchar *label, +                                                      const gchar *icon); + +G_END_DECLS + +#endif /* MATEMIXER_SWITCH_OPTION_PRIVATE_H */ diff --git a/libmatemixer/matemixer-switch-option.c b/libmatemixer/matemixer-switch-option.c new file mode 100644 index 0000000..e924b46 --- /dev/null +++ b/libmatemixer/matemixer-switch-option.c @@ -0,0 +1,224 @@ +/* + * Copyright (C) 2014 Michal Ratajsky <[email protected]> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the licence, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#include <glib.h> +#include <glib-object.h> + +#include "matemixer-switch-option.h" +#include "matemixer-switch-option-private.h" + +/** + * SECTION:matemixer-stream-switch-option + * @include: libmatemixer/matemixer.h + */ + +struct _MateMixerSwitchOptionPrivate +{ +    gchar *name; +    gchar *label; +    gchar *icon; +}; + +enum { +    PROP_0, +    PROP_NAME, +    PROP_LABEL, +    PROP_ICON, +    N_PROPERTIES +}; + +static GParamSpec *properties[N_PROPERTIES] = { NULL, }; + +static void mate_mixer_switch_option_class_init   (MateMixerSwitchOptionClass *klass); + +static void mate_mixer_switch_option_get_property (GObject                    *object, +                                                   guint                       param_id, +                                                   GValue                     *value, +                                                   GParamSpec                 *pspec); +static void mate_mixer_switch_option_set_property (GObject                    *object, +                                                   guint                       param_id, +                                                   const GValue               *value, +                                                   GParamSpec                 *pspec); + +static void mate_mixer_switch_option_init         (MateMixerSwitchOption      *option); +static void mate_mixer_switch_option_finalize     (GObject                    *object); + +G_DEFINE_TYPE (MateMixerSwitchOption, mate_mixer_switch_option, G_TYPE_OBJECT) + +static void +mate_mixer_switch_option_class_init (MateMixerSwitchOptionClass *klass) +{ +    GObjectClass *object_class; + +    object_class = G_OBJECT_CLASS (klass); +    object_class->finalize     = mate_mixer_switch_option_finalize; +    object_class->get_property = mate_mixer_switch_option_get_property; +    object_class->set_property = mate_mixer_switch_option_set_property; + +    properties[PROP_NAME] = +        g_param_spec_string ("name", +                             "Name", +                             "Name of the switch option", +                             NULL, +                             G_PARAM_READWRITE | +                             G_PARAM_CONSTRUCT_ONLY | +                             G_PARAM_STATIC_STRINGS); + +    properties[PROP_LABEL] = +        g_param_spec_string ("label", +                             "Label", +                             "Label of the switch option", +                             NULL, +                             G_PARAM_READWRITE | +                             G_PARAM_CONSTRUCT_ONLY | +                             G_PARAM_STATIC_STRINGS); + +    properties[PROP_ICON] = +        g_param_spec_string ("icon", +                             "Icon", +                             "Icon of the switch option", +                             NULL, +                             G_PARAM_READWRITE | +                             G_PARAM_CONSTRUCT_ONLY | +                             G_PARAM_STATIC_STRINGS); + +    g_object_class_install_properties (object_class, N_PROPERTIES, properties); + +    g_type_class_add_private (object_class, sizeof (MateMixerSwitchOptionPrivate)); +} + +static void +mate_mixer_switch_option_get_property (GObject    *object, +                                       guint       param_id, +                                       GValue     *value, +                                       GParamSpec *pspec) +{ +    MateMixerSwitchOption *option; + +    option = MATE_MIXER_SWITCH_OPTION (object); + +    switch (param_id) { +    case PROP_NAME: +        g_value_set_string (value, option->priv->name); +        break; +    case PROP_LABEL: +        g_value_set_string (value, option->priv->label); +        break; +    case PROP_ICON: +        g_value_set_string (value, option->priv->icon); +        break; +    default: +        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); +        break; +    } +} + +static void +mate_mixer_switch_option_set_property (GObject      *object, +                                       guint         param_id, +                                       const GValue *value, +                                       GParamSpec   *pspec) +{ +    MateMixerSwitchOption *option; + +    option = MATE_MIXER_SWITCH_OPTION (object); + +    switch (param_id) { +    case PROP_NAME: +        /* Construct-only string */ +        option->priv->name = g_value_dup_string (value); +        break; +    case PROP_LABEL: +        /* Construct-only string */ +        option->priv->label = g_value_dup_string (value); +        break; +    case PROP_ICON: +        /* Construct-only string */ +        option->priv->icon = g_value_dup_string (value); +        break; +    default: +        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); +        break; +    } +} + +static void +mate_mixer_switch_option_init (MateMixerSwitchOption *option) +{ +    option->priv = G_TYPE_INSTANCE_GET_PRIVATE (option, +                                                MATE_MIXER_TYPE_SWITCH_OPTION, +                                                MateMixerSwitchOptionPrivate); +} + +static void +mate_mixer_switch_option_finalize (GObject *object) +{ +    MateMixerSwitchOption *option; + +    option = MATE_MIXER_SWITCH_OPTION (object); + +    g_free (option->priv->name); +    g_free (option->priv->label); +    g_free (option->priv->icon); + +    G_OBJECT_CLASS (mate_mixer_switch_option_parent_class)->finalize (object); +} + +/** + * mate_mixer_switch_option_get_name: + */ +const gchar * +mate_mixer_switch_option_get_name (MateMixerSwitchOption *option) +{ +    g_return_val_if_fail (MATE_MIXER_IS_SWITCH_OPTION (option), NULL); + +    return option->priv->name; +} + +/** + * mate_mixer_switch_option_get_label: + */ +const gchar * +mate_mixer_switch_option_get_label (MateMixerSwitchOption *option) +{ +    g_return_val_if_fail (MATE_MIXER_IS_SWITCH_OPTION (option), NULL); + +    return option->priv->label; +} + +/** + * mate_mixer_switch_option_get_icon: + */ +const gchar * +mate_mixer_switch_option_get_icon (MateMixerSwitchOption *option) +{ +    g_return_val_if_fail (MATE_MIXER_IS_SWITCH_OPTION (option), NULL); + +    return option->priv->icon; +} + +MateMixerSwitchOption * +_mate_mixer_switch_option_new (const gchar *name, +                               const gchar *label, +                               const gchar *icon) +{ +    return g_object_new (MATE_MIXER_TYPE_SWITCH_OPTION, +                         "name", name, +                         "label", label, +                         "icon", icon, +                         NULL); +} diff --git a/libmatemixer/matemixer-switch-option.h b/libmatemixer/matemixer-switch-option.h new file mode 100644 index 0000000..b02c42c --- /dev/null +++ b/libmatemixer/matemixer-switch-option.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2014 Michal Ratajsky <[email protected]> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the licence, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef MATEMIXER_SWITCH_OPTION_H +#define MATEMIXER_SWITCH_OPTION_H + +#include <glib.h> +#include <glib-object.h> +#include <libmatemixer/matemixer-types.h> + +G_BEGIN_DECLS + +#define MATE_MIXER_TYPE_SWITCH_OPTION           \ +        (mate_mixer_switch_option_get_type ()) +#define MATE_MIXER_SWITCH_OPTION(o)             \ +        (G_TYPE_CHECK_INSTANCE_CAST ((o), MATE_MIXER_TYPE_SWITCH_OPTION, MateMixerSwitchOption)) +#define MATE_MIXER_IS_SWITCH_OPTION(o)          \ +        (G_TYPE_CHECK_INSTANCE_TYPE ((o), MATE_MIXER_TYPE_SWITCH_OPTION)) +#define MATE_MIXER_SWITCH_OPTION_CLASS(k)       \ +        (G_TYPE_CHECK_CLASS_CAST ((k), MATE_MIXER_TYPE_SWITCH_OPTION, MateMixerSwitchOptionClass)) +#define MATE_MIXER_IS_SWITCH_OPTION_CLASS(k)    \ +        (G_TYPE_CHECK_CLASS_TYPE ((k), MATE_MIXER_TYPE_SWITCH_OPTION)) +#define MATE_MIXER_SWITCH_OPTION_GET_CLASS(o)   \ +        (G_TYPE_INSTANCE_GET_CLASS ((o), MATE_MIXER_TYPE_SWITCH_OPTION, MateMixerSwitchOptionClass)) + +typedef struct _MateMixerSwitchOptionClass    MateMixerSwitchOptionClass; +typedef struct _MateMixerSwitchOptionPrivate  MateMixerSwitchOptionPrivate; + +struct _MateMixerSwitchOption +{ +    GObject parent; + +    /*< private >*/ +    MateMixerSwitchOptionPrivate *priv; +}; + +struct _MateMixerSwitchOptionClass +{ +    GObjectClass parent_class; +}; + +GType        mate_mixer_switch_option_get_type  (void) G_GNUC_CONST; + +const gchar *mate_mixer_switch_option_get_name  (MateMixerSwitchOption *option); +const gchar *mate_mixer_switch_option_get_label (MateMixerSwitchOption *option); +const gchar *mate_mixer_switch_option_get_icon  (MateMixerSwitchOption *option); + +G_END_DECLS + +#endif /* MATEMIXER_SWITCH_OPTION_H */ diff --git a/backends/oss4/oss4-common.h b/libmatemixer/matemixer-switch-private.h index fe55b2b..42390a9 100644 --- a/backends/oss4/oss4-common.h +++ b/libmatemixer/matemixer-switch-private.h @@ -15,24 +15,17 @@   * License along with this library; if not, see <http://www.gnu.org/licenses/>.   */ -#ifndef OSS4_COMMON_H -#define OSS4_COMMON_H +#ifndef MATEMIXER_SWITCH_PRIVATE_H +#define MATEMIXER_SWITCH_PRIVATE_H -#include "config.h" +#include <glib.h> +#include "matemixer-types.h" -#include <sys/types.h> -#include <sys/stat.h> -#include <sys/ioctl.h> -#include <fcntl.h> +G_BEGIN_DECLS -#ifdef HAVE_SYS_SOUNDCARD_H -#  include <sys/soundcard.h> -#elif HAVE_SOUNDCARD_H -#  include <soundcard.h> -#elif HAVE_MACHINE_SOUNDCARD_H -#  include <machine/soundcard.h> -#else -#  error "No OSS4 header file present" -#endif +void _mate_mixer_switch_set_active_option (MateMixerSwitch       *sw, +                                           MateMixerSwitchOption *option); -#endif /* OSS4_COMMON_H */ +G_END_DECLS + +#endif /* MATEMIXER_SWITCH_PRIVATE_H */ diff --git a/libmatemixer/matemixer-switch.c b/libmatemixer/matemixer-switch.c new file mode 100644 index 0000000..b30e405 --- /dev/null +++ b/libmatemixer/matemixer-switch.c @@ -0,0 +1,283 @@ +/* + * Copyright (C) 2014 Michal Ratajsky <[email protected]> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the licence, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#include <string.h> +#include <glib.h> +#include <glib-object.h> + +#include "matemixer-enums.h" +#include "matemixer-enum-types.h" +#include "matemixer-switch.h" +#include "matemixer-switch-private.h" +#include "matemixer-switch-option.h" + +/** + * SECTION:matemixer-switch + * @include: libmatemixer/matemixer.h + */ + +struct _MateMixerSwitchPrivate +{ +    gchar                 *name; +    gchar                 *label; +    GList                 *options; +    MateMixerSwitchOption *active; +}; + +enum { +    PROP_0, +    PROP_NAME, +    PROP_LABEL, +    PROP_ACTIVE_OPTION, +    N_PROPERTIES +}; + +static GParamSpec *properties[N_PROPERTIES] = { NULL, }; + +static void mate_mixer_switch_class_init   (MateMixerSwitchClass *klass); + +static void mate_mixer_switch_get_property (GObject              *object, +                                            guint                 param_id, +                                            GValue               *value, +                                            GParamSpec           *pspec); +static void mate_mixer_switch_set_property (GObject              *object, +                                            guint                 param_id, +                                            const GValue         *value, +                                            GParamSpec           *pspec); + +static void mate_mixer_switch_init         (MateMixerSwitch      *swtch); +static void mate_mixer_switch_finalize     (GObject              *object); + +G_DEFINE_ABSTRACT_TYPE (MateMixerSwitch, mate_mixer_switch, G_TYPE_OBJECT) + +static MateMixerSwitchOption *mate_mixer_switch_real_get_option (MateMixerSwitch *swtch, +                                                                 const gchar     *name); + +static void +mate_mixer_switch_class_init (MateMixerSwitchClass *klass) +{ +    GObjectClass *object_class; + +    klass->get_option = mate_mixer_switch_real_get_option; + +    object_class = G_OBJECT_CLASS (klass); +    object_class->finalize     = mate_mixer_switch_finalize; +    object_class->get_property = mate_mixer_switch_get_property; +    object_class->set_property = mate_mixer_switch_set_property; + +    properties[PROP_NAME] = +        g_param_spec_string ("name", +                             "Name", +                             "Name of the switch", +                             NULL, +                             G_PARAM_READWRITE | +                             G_PARAM_CONSTRUCT_ONLY | +                             G_PARAM_STATIC_STRINGS); + +    properties[PROP_LABEL] = +        g_param_spec_string ("label", +                             "Label", +                             "Label of the switch", +                             NULL, +                             G_PARAM_READWRITE | +                             G_PARAM_CONSTRUCT_ONLY | +                             G_PARAM_STATIC_STRINGS); + +    properties[PROP_ACTIVE_OPTION] = +        g_param_spec_object ("active-option", +                             "Active option", +                             "Active option of the switch", +                             MATE_MIXER_TYPE_SWITCH_OPTION, +                             G_PARAM_READABLE | +                             G_PARAM_STATIC_STRINGS); + +    g_object_class_install_properties (object_class, N_PROPERTIES, properties); + +    g_type_class_add_private (object_class, sizeof (MateMixerSwitchPrivate)); +} + +static void +mate_mixer_switch_get_property (GObject    *object, +                                guint       param_id, +                                GValue     *value, +                                GParamSpec *pspec) +{ +    MateMixerSwitch *swtch; + +    swtch = MATE_MIXER_SWITCH (object); + +    switch (param_id) { +    case PROP_NAME: +        g_value_set_string (value, swtch->priv->name); +        break; +    case PROP_LABEL: +        g_value_set_string (value, swtch->priv->label); +        break; +    default: +        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); +        break; +    } +} + +static void +mate_mixer_switch_set_property (GObject      *object, +                                guint         param_id, +                                const GValue *value, +                                GParamSpec   *pspec) +{ +    MateMixerSwitch *swtch; + +    swtch = MATE_MIXER_SWITCH (object); + +    switch (param_id) { +    case PROP_NAME: +        /* Construct-only string */ +        swtch->priv->name = g_value_dup_string (value); +        break; +    case PROP_LABEL: +        /* Construct-only string */ +        swtch->priv->label = g_value_dup_string (value); +        break; +    default: +        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); +        break; +    } +} + +static void +mate_mixer_switch_init (MateMixerSwitch *swtch) +{ +    swtch->priv = G_TYPE_INSTANCE_GET_PRIVATE (swtch, +                                               MATE_MIXER_TYPE_SWITCH, +                                               MateMixerSwitchPrivate); +} + +static void +mate_mixer_switch_finalize (GObject *object) +{ +    MateMixerSwitch *swtch; + +    swtch = MATE_MIXER_SWITCH (object); + +    g_free (swtch->priv->name); +    g_free (swtch->priv->label); + +    G_OBJECT_CLASS (mate_mixer_switch_parent_class)->finalize (object); +} + +const gchar * +mate_mixer_switch_get_name (MateMixerSwitch *swtch) +{ +    g_return_val_if_fail (MATE_MIXER_IS_SWITCH (swtch), NULL); + +    return swtch->priv->name; +} + +const gchar * +mate_mixer_switch_get_label (MateMixerSwitch *swtch) +{ +    g_return_val_if_fail (MATE_MIXER_IS_SWITCH (swtch), NULL); + +    return swtch->priv->label; +} + +MateMixerSwitchOption * +mate_mixer_switch_get_option (MateMixerSwitch *swtch, const gchar *name) +{ +    g_return_val_if_fail (MATE_MIXER_IS_SWITCH (swtch), NULL); + +    return MATE_MIXER_SWITCH_GET_CLASS (swtch)->get_option (swtch, name); +} + +MateMixerSwitchOption * +mate_mixer_switch_get_active_option (MateMixerSwitch *swtch) +{ +    g_return_val_if_fail (MATE_MIXER_IS_SWITCH (swtch), NULL); + +    return swtch->priv->active; +} + +gboolean +mate_mixer_switch_set_active_option (MateMixerSwitch       *swtch, +                                     MateMixerSwitchOption *option) +{ +    MateMixerSwitchClass *klass; + +    g_return_val_if_fail (MATE_MIXER_IS_SWITCH (swtch), FALSE); + +    klass = MATE_MIXER_SWITCH_GET_CLASS (swtch); +    if (klass->set_active_option != NULL) { +        if (klass->set_active_option (swtch, option) == FALSE) +            return FALSE; + +        _mate_mixer_switch_set_active_option (swtch, option); +        return TRUE; +    } +    return FALSE; +} + +const GList * +mate_mixer_switch_list_options (MateMixerSwitch *swtch) +{ +    g_return_val_if_fail (MATE_MIXER_IS_SWITCH (swtch), NULL); + +    if (swtch->priv->options == NULL) { +        MateMixerSwitchClass *klass = MATE_MIXER_SWITCH_GET_CLASS (swtch); + +        if (klass->list_options != NULL) +            swtch->priv->options = klass->list_options (swtch); +    } +    return (const GList *) swtch->priv->options; +} + +void +_mate_mixer_switch_set_active_option (MateMixerSwitch       *swtch, +                                      MateMixerSwitchOption *option) +{ +    g_return_if_fail (MATE_MIXER_IS_SWITCH (swtch)); +    g_return_if_fail (MATE_MIXER_IS_SWITCH_OPTION (option)); + +    if (swtch->priv->active == option) +        return; + +    if (swtch->priv->active != NULL) +        g_object_unref (swtch->priv->active); + +    swtch->priv->active = g_object_ref (option); + +    g_object_notify_by_pspec (G_OBJECT (swtch), properties[PROP_ACTIVE_OPTION]); +} + +static MateMixerSwitchOption * +mate_mixer_switch_real_get_option (MateMixerSwitch *swtch, const gchar *name) +{ +    const GList *list; + +    g_return_val_if_fail (MATE_MIXER_IS_SWITCH (swtch), NULL); +    g_return_val_if_fail (name != NULL, NULL); + +    list = mate_mixer_switch_list_options (swtch); +    while (list != NULL) { +        MateMixerSwitchOption *option = MATE_MIXER_SWITCH_OPTION (list->data); + +        if (strcmp (name, mate_mixer_switch_option_get_name (option)) == 0) +            return option; + +        list = list->next; +    } +    return NULL; +} diff --git a/libmatemixer/matemixer-switch.h b/libmatemixer/matemixer-switch.h new file mode 100644 index 0000000..3035607 --- /dev/null +++ b/libmatemixer/matemixer-switch.h @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2014 Michal Ratajsky <[email protected]> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the licence, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef MATEMIXER_SWITCH_H +#define MATEMIXER_SWITCH_H + +#include <glib.h> +#include <glib-object.h> + +#include <libmatemixer/matemixer-types.h> + +G_BEGIN_DECLS + +#define MATE_MIXER_TYPE_SWITCH           \ +        (mate_mixer_switch_get_type ()) +#define MATE_MIXER_SWITCH(o)             \ +        (G_TYPE_CHECK_INSTANCE_CAST ((o), MATE_MIXER_TYPE_SWITCH, MateMixerSwitch)) +#define MATE_MIXER_IS_SWITCH(o)          \ +        (G_TYPE_CHECK_INSTANCE_TYPE ((o), MATE_MIXER_TYPE_SWITCH)) +#define MATE_MIXER_SWITCH_CLASS(k)       \ +        (G_TYPE_CHECK_CLASS_CAST ((k), MATE_MIXER_TYPE_SWITCH, MateMixerSwitchClass)) +#define MATE_MIXER_IS_SWITCH_CLASS(k)    \ +        (G_TYPE_CHECK_CLASS_TYPE ((k), MATE_MIXER_TYPE_SWITCH)) +#define MATE_MIXER_SWITCH_GET_CLASS(o)   \ +        (G_TYPE_INSTANCE_GET_CLASS ((o), MATE_MIXER_TYPE_SWITCH, MateMixerSwitchClass)) + +typedef struct _MateMixerSwitchClass    MateMixerSwitchClass; +typedef struct _MateMixerSwitchPrivate  MateMixerSwitchPrivate; + +struct _MateMixerSwitch +{ +    GObject object; + +    /*< private >*/ +    MateMixerSwitchPrivate *priv; +}; + +struct _MateMixerSwitchClass +{ +    GObjectClass parent_class; + +    /*< private >*/ +    MateMixerSwitchOption *(*get_option)        (MateMixerSwitch       *swtch, +                                                 const gchar           *name); + +    gboolean               (*set_active_option) (MateMixerSwitch       *swtch, +                                                 MateMixerSwitchOption *option); + +    GList                 *(*list_options)      (MateMixerSwitch       *swtch); +}; + +GType                  mate_mixer_switch_get_type          (void) G_GNUC_CONST; + +const gchar *          mate_mixer_switch_get_name          (MateMixerSwitch       *swtch); +const gchar *          mate_mixer_switch_get_label         (MateMixerSwitch       *swtch); + +MateMixerSwitchOption *mate_mixer_switch_get_option        (MateMixerSwitch       *swtch, +                                                            const gchar           *name); + +MateMixerSwitchOption *mate_mixer_switch_get_active_option (MateMixerSwitch       *swtch); +gboolean               mate_mixer_switch_set_active_option (MateMixerSwitch       *swtch, +                                                            MateMixerSwitchOption *option); + +const GList *          mate_mixer_switch_list_options      (MateMixerSwitch       *swtch); + +G_END_DECLS + +#endif /* MATEMIXER_SWITCH_H */ diff --git a/libmatemixer/matemixer-toggle.c b/libmatemixer/matemixer-toggle.c new file mode 100644 index 0000000..2eea599 --- /dev/null +++ b/libmatemixer/matemixer-toggle.c @@ -0,0 +1,254 @@ +/* + * Copyright (C) 2014 Michal Ratajsky <[email protected]> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the licence, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#include <string.h> +#include <glib.h> +#include <glib-object.h> + +#include "matemixer-switch.h" +#include "matemixer-switch-option.h" +#include "matemixer-toggle.h" + +/** + * SECTION:matemixer-toggle + * @include: libmatemixer/matemixer.h + */ + +struct _MateMixerTogglePrivate +{ +    MateMixerSwitchOption *on; +    MateMixerSwitchOption *off; +}; + +enum { +    PROP_0, +    PROP_STATE, +    PROP_STATE_OPTION_ON, +    PROP_STATE_OPTION_OFF, +    N_PROPERTIES +}; + +static GParamSpec *properties[N_PROPERTIES] = { NULL, }; + +static void mate_mixer_toggle_class_init   (MateMixerToggleClass *klass); + +static void mate_mixer_toggle_get_property (GObject              *object, +                                            guint                 param_id, +                                            GValue               *value, +                                            GParamSpec           *pspec); +static void mate_mixer_toggle_set_property (GObject              *object, +                                            guint                 param_id, +                                            const GValue         *value, +                                            GParamSpec           *pspec); + +static void mate_mixer_toggle_init         (MateMixerToggle      *toggle); +static void mate_mixer_toggle_dispose      (GObject              *object); + +G_DEFINE_ABSTRACT_TYPE (MateMixerToggle, mate_mixer_toggle, MATE_MIXER_TYPE_SWITCH) + +static MateMixerSwitchOption *mate_mixer_toggle_get_option   (MateMixerSwitch *swtch, +                                                              const gchar     *name); + +static GList *                mate_mixer_toggle_list_options (MateMixerSwitch *swtch); + +static void +mate_mixer_toggle_class_init (MateMixerToggleClass *klass) +{ +    GObjectClass         *object_class; +    MateMixerSwitchClass *switch_class; + +    object_class = G_OBJECT_CLASS (klass); +    object_class->dispose      = mate_mixer_toggle_dispose; +    object_class->get_property = mate_mixer_toggle_get_property; +    object_class->set_property = mate_mixer_toggle_set_property; + +    switch_class = MATE_MIXER_SWITCH_CLASS (klass); +    switch_class->get_option   = mate_mixer_toggle_get_option; +    switch_class->list_options = mate_mixer_toggle_list_options; + +    properties[PROP_STATE] = +        g_param_spec_boolean ("state", +                              "State", +                              "Current state", +                              FALSE, +                              G_PARAM_READABLE | +                              G_PARAM_STATIC_STRINGS); + +    properties[PROP_STATE_OPTION_ON] = +        g_param_spec_object ("state-option-on", +                             "State option for on", +                             "Option corresponding to the 'on' value of the toggle", +                             MATE_MIXER_TYPE_SWITCH_OPTION, +                             G_PARAM_READWRITE | +                             G_PARAM_CONSTRUCT_ONLY | +                             G_PARAM_STATIC_STRINGS); + +    properties[PROP_STATE_OPTION_OFF] = +        g_param_spec_object ("state-option-off", +                             "State option for off", +                             "Option corresponding to the 'off' value of the toggle", +                             MATE_MIXER_TYPE_SWITCH_OPTION, +                             G_PARAM_READWRITE | +                             G_PARAM_CONSTRUCT_ONLY | +                             G_PARAM_STATIC_STRINGS); + +    g_object_class_install_properties (object_class, N_PROPERTIES, properties); + +    g_type_class_add_private (object_class, sizeof (MateMixerTogglePrivate)); +} + +static void +mate_mixer_toggle_get_property (GObject    *object, +                                guint       param_id, +                                GValue     *value, +                                GParamSpec *pspec) +{ +    MateMixerToggle *toggle; + +    toggle = MATE_MIXER_TOGGLE (object); + +    switch (param_id) { +    case PROP_STATE: +        g_value_set_boolean (value, mate_mixer_toggle_get_state (toggle)); +        break; +    case PROP_STATE_OPTION_ON: +        g_value_set_object (value, toggle->priv->on); +        break; +    case PROP_STATE_OPTION_OFF: +        g_value_set_object (value, toggle->priv->off); +        break; +    default: +        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); +        break; +    } +} + +static void +mate_mixer_toggle_set_property (GObject      *object, +                                guint         param_id, +                                const GValue *value, +                                GParamSpec   *pspec) +{ +    MateMixerToggle *toggle; + +    toggle = MATE_MIXER_TOGGLE (object); + +    switch (param_id) { +    case PROP_STATE_OPTION_ON: +        /* Construct-only object */ +        toggle->priv->on = g_value_dup_object (value); +        break; +    case PROP_STATE_OPTION_OFF: +        /* Construct-only object */ +        toggle->priv->off = g_value_dup_object (value); +        break; +    default: +        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); +        break; +    } +} + +static void +mate_mixer_toggle_init (MateMixerToggle *toggle) +{ +    toggle->priv = G_TYPE_INSTANCE_GET_PRIVATE (toggle, +                                                MATE_MIXER_TYPE_TOGGLE, +                                                MateMixerTogglePrivate); +} + +static void +mate_mixer_toggle_dispose (GObject *object) +{ +    MateMixerToggle *toggle; + +    toggle = MATE_MIXER_TOGGLE (object); + +    g_clear_object (&toggle->priv->on); +    g_clear_object (&toggle->priv->off); + +    G_OBJECT_CLASS (mate_mixer_toggle_parent_class)->dispose (object); +} + +gboolean +mate_mixer_toggle_get_state (MateMixerToggle *toggle) +{ +    MateMixerSwitchOption *active; + +    g_return_val_if_fail (MATE_MIXER_IS_TOGGLE (toggle), FALSE); + +    active = mate_mixer_switch_get_active_option (MATE_MIXER_SWITCH (toggle)); +    if (active == toggle->priv->on) +        return TRUE; +    else +        return FALSE; +} + +MateMixerSwitchOption * +mate_mixer_toggle_get_state_option (MateMixerToggle *toggle, gboolean state) +{ +    g_return_val_if_fail (MATE_MIXER_IS_TOGGLE (toggle), NULL); + +    if (state == TRUE) +        return toggle->priv->on; +    else +        return toggle->priv->off; +} + +gboolean +mate_mixer_toggle_set_state (MateMixerToggle *toggle, gboolean state) +{ +    MateMixerSwitchOption *active; + +    g_return_val_if_fail (MATE_MIXER_IS_TOGGLE (toggle), FALSE); + +    if (state == TRUE) +        active = toggle->priv->on; +    else +        active = toggle->priv->off; + +    return mate_mixer_switch_set_active_option (MATE_MIXER_SWITCH (toggle), active); +} + +static MateMixerSwitchOption * +mate_mixer_toggle_get_option (MateMixerSwitch *swtch, const gchar *name) +{ +    MateMixerToggle *toggle; + +    g_return_val_if_fail (MATE_MIXER_IS_TOGGLE (swtch), NULL); + +    toggle = MATE_MIXER_TOGGLE (swtch); + +    if (strcmp (name, mate_mixer_switch_option_get_name (toggle->priv->on)) == 0) +        return toggle->priv->on; +    if (strcmp (name, mate_mixer_switch_option_get_name (toggle->priv->off)) == 0) +        return toggle->priv->off; + +    return NULL; +} + +static GList * +mate_mixer_toggle_list_options (MateMixerSwitch *swtch) +{ +    GList *list = NULL; + +    g_return_val_if_fail (MATE_MIXER_IS_TOGGLE (swtch), NULL); + +    list = g_list_prepend (list, MATE_MIXER_TOGGLE (swtch)->priv->off); +    list = g_list_prepend (list, MATE_MIXER_TOGGLE (swtch)->priv->on); + +    return list; +} diff --git a/libmatemixer/matemixer-toggle.h b/libmatemixer/matemixer-toggle.h new file mode 100644 index 0000000..1cedfc5 --- /dev/null +++ b/libmatemixer/matemixer-toggle.h @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2014 Michal Ratajsky <[email protected]> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the licence, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef MATEMIXER_TOGGLE_H +#define MATEMIXER_TOGGLE_H + +#include <glib.h> +#include <glib-object.h> + +#include <libmatemixer/matemixer-types.h> + +G_BEGIN_DECLS + +#define MATE_MIXER_TYPE_TOGGLE           \ +        (mate_mixer_toggle_get_type ()) +#define MATE_MIXER_TOGGLE(o)             \ +        (G_TYPE_CHECK_INSTANCE_CAST ((o), MATE_MIXER_TYPE_TOGGLE, MateMixerToggle)) +#define MATE_MIXER_IS_TOGGLE(o)          \ +        (G_TYPE_CHECK_INSTANCE_TYPE ((o), MATE_MIXER_TYPE_TOGGLE)) +#define MATE_MIXER_TOGGLE_CLASS(k)       \ +        (G_TYPE_CHECK_CLASS_CAST ((k), MATE_MIXER_TYPE_TOGGLE, MateMixerToggleClass)) +#define MATE_MIXER_IS_TOGGLE_CLASS(k)    \ +        (G_TYPE_CHECK_CLASS_TYPE ((k), MATE_MIXER_TYPE_TOGGLE)) +#define MATE_MIXER_TOGGLE_GET_CLASS(o)   \ +        (G_TYPE_INSTANCE_GET_CLASS ((o), MATE_MIXER_TYPE_TOGGLE, MateMixerToggleClass)) + +typedef struct _MateMixerToggleClass    MateMixerToggleClass; +typedef struct _MateMixerTogglePrivate  MateMixerTogglePrivate; + +struct _MateMixerToggle +{ +    MateMixerSwitch object; + +    /*< private >*/ +    MateMixerTogglePrivate *priv; +}; + +struct _MateMixerToggleClass +{ +    MateMixerSwitchClass parent_class; +}; + +GType                  mate_mixer_toggle_get_type         (void) G_GNUC_CONST; + +gboolean               mate_mixer_toggle_get_state        (MateMixerToggle *toggle); +gboolean               mate_mixer_toggle_set_state        (MateMixerToggle *toggle, +                                                           gboolean         state); + +MateMixerSwitchOption *mate_mixer_toggle_get_state_option (MateMixerToggle *toggle, +                                                           gboolean         state); + +G_END_DECLS + +#endif /* MATEMIXER_TOGGLE_H */ diff --git a/libmatemixer/matemixer-types.h b/libmatemixer/matemixer-types.h new file mode 100644 index 0000000..6601a95 --- /dev/null +++ b/libmatemixer/matemixer-types.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2014 Michal Ratajsky <[email protected]> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the licence, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef MATEMIXER_TYPES_H +#define MATEMIXER_TYPES_H + +G_BEGIN_DECLS + +typedef struct _MateMixerDevice         MateMixerDevice; +typedef struct _MateMixerClientStream   MateMixerClientStream; +typedef struct _MateMixerContext        MateMixerContext; +typedef struct _MateMixerDeviceProfile  MateMixerDeviceProfile; +typedef struct _MateMixerStream         MateMixerStream; +typedef struct _MateMixerStreamControl  MateMixerStreamControl; +typedef struct _MateMixerSwitch         MateMixerSwitch; +typedef struct _MateMixerSwitchOption   MateMixerSwitchOption; +typedef struct _MateMixerToggle         MateMixerToggle; + +G_END_DECLS + +#endif /* MATEMIXER_TYPES_H */ diff --git a/libmatemixer/matemixer.c b/libmatemixer/matemixer.c index 0ca09b9..fa83e3f 100644 --- a/libmatemixer/matemixer.c +++ b/libmatemixer/matemixer.c @@ -54,6 +54,10 @@ mate_mixer_init (void)      if (initialized == TRUE)          return TRUE; +#if !GLIB_CHECK_VERSION (2, 36, 0) +    g_type_init (); +#endif +      load_modules ();      if (modules != NULL) { @@ -96,33 +100,25 @@ mate_mixer_is_initialized (void)      return initialized;  } -/** - * mate_mixer_deinit: - * - * Deinitializes the library. You should call this function when you are done - * using the library. - */ -void -mate_mixer_deinit (void) +/* Return a list of loaded backend modules */ +const GList * +_mate_mixer_get_modules (void)  { -    GList *list; - -    if (initialized == FALSE) -        return; - -    list = modules; -    while (list != NULL) { -        g_type_module_unuse (G_TYPE_MODULE (list->data)); -        list = list->next; -    } -    initialized = FALSE; +    return (const GList *) modules;  } -/* Internal function: return a list of loaded backend modules */ -const GList * -mate_mixer_get_modules (void) +guint32 +_mate_mixer_create_channel_mask (MateMixerChannelPosition *positions, guint n)  { -    return (const GList *) modules; +    guint32 mask = 0; +    guint   i = 0; + +    for (i = 0; i < n; i++) { +        if (positions[i] > MATE_MIXER_CHANNEL_UNKNOWN && +            positions[i] < MATE_MIXER_CHANNEL_MAX) +            mask |= 1 << positions[i]; +    } +    return mask;  }  static void @@ -150,7 +146,8 @@ load_modules (void)                      continue;                  file = g_build_filename (LIBMATEMIXER_BACKEND_DIR, name, NULL); -                modules = g_list_prepend (modules, mate_mixer_backend_module_new (file)); +                modules = g_list_prepend (modules, +                                          mate_mixer_backend_module_new (file));                  g_free (file);              } diff --git a/libmatemixer/matemixer.h b/libmatemixer/matemixer.h index 36a3d39..a6eac79 100644 --- a/libmatemixer/matemixer.h +++ b/libmatemixer/matemixer.h @@ -22,19 +22,21 @@  #include <glib-object.h>  #include <libmatemixer/matemixer-client-stream.h> -#include <libmatemixer/matemixer-control.h> +#include <libmatemixer/matemixer-context.h>  #include <libmatemixer/matemixer-device.h>  #include <libmatemixer/matemixer-device-profile.h>  #include <libmatemixer/matemixer-enums.h> -#include <libmatemixer/matemixer-port.h>  #include <libmatemixer/matemixer-stream.h> +#include <libmatemixer/matemixer-stream-control.h> +#include <libmatemixer/matemixer-switch.h> +#include <libmatemixer/matemixer-switch-option.h> +#include <libmatemixer/matemixer-toggle.h>  #include <libmatemixer/matemixer-version.h>  G_BEGIN_DECLS  gboolean mate_mixer_init           (void);  gboolean mate_mixer_is_initialized (void); -void     mate_mixer_deinit         (void);  G_END_DECLS  | 
