From: Johannes Holmberg <johan...@update.uu.se>

---
 wmix/Makefile             |   6 +-
 wmix/config.c             |  38 +++--
 wmix/include/config.h     |   7 +-
 wmix/include/mixer-alsa.h |  43 +++++
 wmix/include/mixer-oss.h  |  42 +++++
 wmix/include/mixer.h      |  49 +++---
 wmix/mixer-alsa.c         | 399 ++++++++++++++++++++++++++++++++++++++++++++++
 wmix/mixer-oss.c          | 116 +++++++-------
 wmix/wmix.c               |  57 ++++++-
 9 files changed, 654 insertions(+), 103 deletions(-)
 create mode 100644 wmix/include/mixer-alsa.h
 create mode 100644 wmix/include/mixer-oss.h
 create mode 100644 wmix/mixer-alsa.c

diff --git a/wmix/Makefile b/wmix/Makefile
index 8f9a2eb..6e94a34 100644
--- a/wmix/Makefile
+++ b/wmix/Makefile
@@ -1,8 +1,8 @@
 CC             = gcc
-CFLAGS         = -O3 -W -Wall
+CFLAGS         = -std=gnu99 -O3 -W -Wall `pkg-config --cflags alsa`
 LDFLAGS                = -L/usr/X11R6/lib
-LIBS           = -lXpm -lXext -lX11 -lm
-OBJECTS                = misc.o config.o mixer-oss.o ui_x.o mmkeys.o wmix.o
+LIBS           = -lXpm -lXext -lX11 -lm `pkg-config --libs alsa`
+OBJECTS                = misc.o config.o mixer-alsa.o mixer-oss.o ui_x.o 
mmkeys.o wmix.o
 
 # where to install this program (also for packaging stuff)
 PREFIX         = /usr/local
diff --git a/wmix/config.c b/wmix/config.c
index 7034271..c11c2fe 100644
--- a/wmix/config.c
+++ b/wmix/config.c
@@ -30,19 +30,21 @@
 
 #include "include/common.h"
 #include "include/config.h"
-
+#include "include/misc.h"
 
 #define VERSION_TEXT \
        "WMixer " VERSION " by time...@japan.co.jp + sk...@mit.edu\n"
 
 #define HELP_TEXT \
        "usage:\n" \
+        "  -a <api>  use this sound api (oss or alsa) [alsa]\n" \
        "  -d <dsp>  connect to remote X display\n" \
        "  -e <name> exclude channel, can be used many times\n" \
        "  -f <file> parse this config [~/.wmixrc]\n" \
        "  -h        print this help\n" \
        "  -k        disable grabing volume control keys\n" \
-       "  -m <dev>  mixer device [/dev/mixer]\n" \
+       "  -m <dev>  oss mixer device [/dev/mixer]\n" \
+       "            or alsa card name [default]\n" \
        "  -v        verbose -> id, long name, name\n" \
 
 /* The global configuration */
@@ -50,7 +52,7 @@ struct _Config config;
 
 /* The default device used for Mixer control */
 static const char default_mixer_device[] = "/dev/mixer";
-
+static const char default_card_name[] = "default";
 /* Default color for OSD */
 const char default_osd_color[] = "green";
 
@@ -61,8 +63,8 @@ const char default_osd_color[] = "green";
 void config_init(void)
 {
        memset(&config, 0, sizeof(config));
-
-       config.mixer_device = (char *) default_mixer_device;
+        config.api = 0;
+       config.mixer_device = NULL;
        config.mousewheel = 1;
        config.scrolltext = 1;
        config.mmkeys = 1;
@@ -89,13 +91,14 @@ void config_release(void)
        if (config.display_name)
                free(config.display_name);
 
-       if (config.mixer_device != default_mixer_device)
+       if (config.mixer_device != default_mixer_device
+            && config.mixer_device != default_card_name)
                free(config.mixer_device);
 
        if (config.osd_color != default_osd_color)
                free(config.osd_color);
 
-       for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
+       for (i = 0; i < EXCLUDE_MAX_COUNT; i++) {
                if (config.exclude_channel[i])
                        free(config.exclude_channel[i]);
                else
@@ -119,7 +122,7 @@ void parse_cli_options(int argc, char **argv)
        config.verbose = false;
        error_found = false;
        for (;;) {
-               opt = getopt(argc, argv, ":d:e:f:hkm:v");
+               opt = getopt(argc, argv, ":a:d:e:f:hkm:v");
                if (opt == -1)
                        break;
 
@@ -133,7 +136,12 @@ void parse_cli_options(int argc, char **argv)
                        fprintf(stderr, "wmix:error: missing argument for 
option '-%c'\n", optopt);
                        error_found = true;
                        break;
-
+               case 'a':
+                       if(!strcmp("oss", optarg))
+                               config.api = 1;
+                       else if (strcmp("alsa", optarg))
+                               fprintf(stderr, "Warning: Incorrect sound api 
specified, defaulting to alsa\n");
+                       break;
                case 'd':
                        if (config.display_name)
                                free(config.display_name);
@@ -141,7 +149,7 @@ void parse_cli_options(int argc, char **argv)
                        break;
 
                case 'e':
-                       if (count_exclude < SOUND_MIXER_NRDEVICES) {
+                       if (count_exclude < EXCLUDE_MAX_COUNT) {
                                config.exclude_channel[count_exclude] = 
strdup(optarg);
                                count_exclude++;
                        } else
@@ -180,6 +188,13 @@ void parse_cli_options(int argc, char **argv)
        }
        config.exclude_channel[count_exclude] = NULL;
 
+       if (!config.mixer_device) {
+               if (config.api == 0)
+                       config.mixer_device = (char *)default_card_name;
+               else if (config.api == 1)
+                       config.mixer_device = (char *)default_mixer_device;
+       }
+
        if (optind < argc) {
                fprintf(stderr, "wmix:error: argument '%s' not understood\n", 
argv[optind]);
                error_found = true;
@@ -296,9 +311,10 @@ void config_read(void)
                } else if (strcmp(keyword, "exclude") == 0) {
                        int i;
 
-                       for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
+                       for (i = 0; i < EXCLUDE_MAX_COUNT; i++) {
                                if (config.exclude_channel[i] == NULL) {
                                        config.exclude_channel[i] = 
strdup(value);
+                                       config.exclude_channel[i+1] = NULL;
                                        break;
                                }
 
diff --git a/wmix/include/config.h b/wmix/include/config.h
index 1f45fc9..609336d 100644
--- a/wmix/include/config.h
+++ b/wmix/include/config.h
@@ -20,9 +20,7 @@
 #ifndef WMIX_CONFIG_H
 #define WMIX_CONFIG_H
 
-/* Needed for SOUND_MIXER_NRDEVICES */
-#include <sys/soundcard.h>
-
+#define EXCLUDE_MAX_COUNT 100
 
 /* Global Configuration */
 extern struct _Config {
@@ -30,6 +28,7 @@ extern struct _Config {
        char        *display_name;              /* X Display to connect to */
        char        *mixer_device;              /* device file to use for 
controlling Mixer volumes */
 
+       unsigned int api;               /* Sound API (0 = ALSA, 1 = OSS) */
        unsigned int verbose    : 1;    /* be Verbose when starting */
        unsigned int osd        : 1;    /* show OSD? */
        unsigned int mousewheel : 1;    /* mousewheel enabled? */
@@ -42,7 +41,7 @@ extern struct _Config {
        float        scrollstep;                /* scroll mouse step adjustment 
*/
        char        *osd_color;                 /* osd color */
 
-       char        *exclude_channel[SOUND_MIXER_NRDEVICES + 1];        /* 
Devices to exclude from GUI's list */
+       char        *exclude_channel[EXCLUDE_MAX_COUNT + 1];    /* Devices to 
exclude from GUI's list */
 } config;
 
 /* Default color for OSD */
diff --git a/wmix/include/mixer-alsa.h b/wmix/include/mixer-alsa.h
new file mode 100644
index 0000000..263fb47
--- /dev/null
+++ b/wmix/include/mixer-alsa.h
@@ -0,0 +1,43 @@
+/* WMix 3.0 -- a mixer using the OSS mixer API.
+ * Copyright (C) 2000, 2001
+ *     Daniel Richard G. <sk...@mit.edu>,
+ *     timecop <time...@japan.co.jp>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 
USA.
+ */
+
+void mixer_alsa_init(const char *mixer_oss_device,
+                     bool verbose,
+                     const char *exclude[]);
+bool mixer_alsa_is_changed(void);
+int mixer_alsa_get_channel_count(void);
+int mixer_alsa_get_channel(void);
+const char *mixer_alsa_get_channel_name(void);
+const char *mixer_alsa_get_short_name(void);
+void mixer_alsa_set_channel(int channel);
+void mixer_alsa_set_channel_rel(int delta_channel);
+float mixer_alsa_get_volume(void);
+void mixer_alsa_set_volume(float volume);
+void mixer_alsa_set_volume_rel(float delta_volume);
+float mixer_alsa_get_balance(void);
+void mixer_alsa_set_balance(float balance);
+void mixer_alsa_set_balance_rel(float delta_balance);
+void mixer_alsa_toggle_mute(void);
+void mixer_alsa_toggle_rec(void);
+bool mixer_alsa_is_muted(void);
+bool mixer_alsa_is_stereo(void);
+bool mixer_alsa_is_rec(void);
+bool mixer_alsa_can_rec (void);
+void mixer_alsa_tick(void);
diff --git a/wmix/include/mixer-oss.h b/wmix/include/mixer-oss.h
new file mode 100644
index 0000000..ae358cf
--- /dev/null
+++ b/wmix/include/mixer-oss.h
@@ -0,0 +1,42 @@
+/* WMix 3.0 -- a mixer using the OSS mixer API.
+ * Copyright (C) 2000, 2001
+ *     Daniel Richard G. <sk...@mit.edu>,
+ *     timecop <time...@japan.co.jp>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 
USA.
+ */
+
+void mixer_oss_init(const char *mixer_oss_device,
+                    bool verbose,
+                    const char *exclude[]);
+bool mixer_oss_is_changed(void);
+int mixer_oss_get_channel_count(void);
+int mixer_oss_get_channel(void);
+const char *mixer_oss_get_channel_name(void);
+const char *mixer_oss_get_short_name(void);
+void mixer_oss_set_channel(int channel);
+void mixer_oss_set_channel_rel(int delta_channel);
+float mixer_oss_get_volume(void);
+void mixer_oss_set_volume(float volume);
+void mixer_oss_set_volume_rel(float delta_volume);
+float mixer_oss_get_balance(void);
+void mixer_oss_set_balance(float balance);
+void mixer_oss_set_balance_rel(float delta_balance);
+void mixer_oss_toggle_mute(void);
+void mixer_oss_toggle_rec(void);
+bool mixer_oss_is_muted(void);
+bool mixer_oss_is_stereo(void);
+bool mixer_oss_is_rec(void);
+bool mixer_oss_can_rec(void);
diff --git a/wmix/include/mixer.h b/wmix/include/mixer.h
index 0195291..116d8ed 100644
--- a/wmix/include/mixer.h
+++ b/wmix/include/mixer.h
@@ -55,27 +55,28 @@
  * - Muting must occur independently of the volume level.
  */
 
-void           mixer_init                      (const char *mixer_device,
-                                                bool verbose,
-                                                const char *exclude[]);
-bool           mixer_is_changed                (void);
-int            mixer_get_channel_count         (void);
-int            mixer_get_channel               (void);
-const char *   mixer_get_channel_name          (void);
-const char *   mixer_get_short_name            (void);
-void           mixer_set_channel               (int channel);
-void           mixer_set_channel_rel           (int delta_channel);
-float          mixer_get_volume                (void);
-void           mixer_set_volume                (float volume);
-void           mixer_set_volume_rel            (float delta_volume);
-float          mixer_get_balance               (void);
-void           mixer_set_balance               (float balance);
-void           mixer_set_balance_rel           (float delta_balance);
-void           mixer_toggle_mute               (void);
-void           mixer_toggle_rec                (void);
-bool           mixer_is_muted                  (void);
-bool           mixer_is_stereo                 (void);
-bool           mixer_is_rec                    (void);
-bool           mixer_can_rec                   (void);
-bool            is_exclude                      (const char *short_name,
-                                                const char *exclude[]);
+void (*mixer_init)(const char *mixer_device,
+                   bool verbose,
+                   const char *exclude[]);
+bool (*mixer_is_changed)(void);
+int (*mixer_get_channel_count)(void);
+int (*mixer_get_channel)(void);
+const char *(*mixer_get_channel_name)(void);
+const char *(*mixer_get_short_name)(void);
+void (*mixer_set_channel)(int channel);
+void (*mixer_set_channel_rel)(int delta_channel);
+float (*mixer_get_volume)(void);
+void (*mixer_set_volume)(float volume);
+void (*mixer_set_volume_rel)(float delta_volume);
+float (*mixer_get_balance)(void);
+void (*mixer_set_balance)(float balance);
+void (*mixer_set_balance_rel)(float delta_balance);
+void (*mixer_toggle_mute)(void);
+void (*mixer_toggle_rec)(void);
+bool (*mixer_is_muted)(void);
+bool (*mixer_is_stereo)(void);
+bool (*mixer_is_rec)(void);
+bool (*mixer_can_rec)(void);
+bool (*is_exclude)(const char *short_name,
+                   const char *exclude[]);
+void (*mixer_tick)(void);
diff --git a/wmix/mixer-alsa.c b/wmix/mixer-alsa.c
new file mode 100644
index 0000000..065e01a
--- /dev/null
+++ b/wmix/mixer-alsa.c
@@ -0,0 +1,399 @@
+#include "include/common.h"
+#include "include/misc.h"
+#include "include/mixer-alsa.h"
+
+#include <alsa/asoundlib.h>
+
+static bool get_mixer_state(void);
+
+struct mixer_element {
+    const char *name;          /* name of channel */
+    const char *sname;         /* short name of the channel */
+    snd_mixer_elem_t *element;  /* Mixer element pointer */
+    long min;                   /* Min volume */
+    long max;                   /* Max volume */
+    int dev;                   /* channel device number */
+    int prev_dev_lr_volume;    /* last known left/right volume
+                                * (in device format) */
+    float volume;              /* volume, in [0, 1] */
+    float balance;             /* balance, in [-1, 1] */
+    bool has_playback;
+    bool has_playback_switch;
+    bool has_capture;
+    bool has_capture_switch;
+    bool is_recording;         /* is it recording? */
+    bool is_stereo;            /* capable of stereo? */
+    bool is_muted;             /* is it muted? */
+    int (*get_volume)(snd_mixer_elem_t *, snd_mixer_selem_channel_id_t, long 
*);
+    int (*set_volume)(snd_mixer_elem_t *, snd_mixer_selem_channel_id_t, long);
+};
+
+static snd_mixer_t *mixer;
+static struct mixer_element *element;
+static int cur_element = 0;
+static int n_elements;
+static bool needs_update = true;
+
+static int elem_callback(__attribute__((unused)) snd_mixer_elem_t *elem,
+                         __attribute__((unused)) unsigned int mask)
+{
+    needs_update = true;
+    return 0;
+}
+
+static int mixer_callback(__attribute__((unused)) snd_mixer_t *ctl,
+                          unsigned int mask,
+                         snd_mixer_elem_t *elem)
+{
+    if (mask & SND_CTL_EVENT_MASK_ADD) {
+        snd_mixer_elem_set_callback(elem, elem_callback);
+        needs_update = true;
+    }
+    return 0;
+}
+
+static bool is_exclude(const char *short_name,
+                       const char *exclude[])
+{
+    for (int i = 0; exclude[i] != NULL; i++) {
+        if (!strcmp(short_name, exclude[i])) {
+            return true;
+        }
+    }
+    return false;
+}
+
+void mixer_alsa_init(const char *mixer_device, bool verbose, const char * 
exclude[])
+{
+    int err;
+    static struct snd_mixer_selem_regopt selem_regopt = {
+        .ver = 1,
+        .abstract = SND_MIXER_SABSTRACT_NONE,
+    };
+    selem_regopt.device = mixer_device;
+    if (verbose) {
+        printf("Sound card: %s\n", mixer_device);
+        puts("Supported elements:");
+    }
+
+    if ((err = snd_mixer_open(&mixer, 0)) < 0) {
+        fprintf(stderr, "snd_mixer_open error");
+        mixer = NULL;
+        return;
+    }
+
+    if ((err = snd_mixer_selem_register(mixer, &selem_regopt, NULL)) < 0) {
+        fprintf(stderr, "snd_mixer_selem_register error");
+        snd_mixer_close(mixer);
+        mixer = NULL;
+        return;
+    }
+
+    snd_mixer_set_callback(mixer, mixer_callback);
+
+    if ((err = snd_mixer_load(mixer)) < 0) {
+        fprintf(stderr, "snd_mixer_load error");
+        snd_mixer_close(mixer);
+        mixer = NULL;
+        return;
+    }
+
+    int all_elements = snd_mixer_get_count(mixer);
+    element = (struct mixer_element *)malloc(all_elements *
+                                             sizeof(struct mixer_element));
+    memset(element, 0, all_elements * sizeof(struct mixer_element));
+    snd_mixer_elem_t *elem = snd_mixer_first_elem(mixer);
+
+    int f = 0;
+    for (int e = 0; e < all_elements; e++) {
+        element[f].element = elem;
+        element[f].name = snd_mixer_selem_get_name(elem);
+
+        if (is_exclude(element[f].name, exclude)) {
+            if (verbose)
+                printf("  x: '%s' - disabled\n", element[f].name);
+            elem = snd_mixer_elem_next(elem);
+            continue;
+        }
+
+        element[f].sname = element[f].name;
+
+        element[f].has_capture = snd_mixer_selem_has_capture_volume(elem);
+        element[f].has_capture &= snd_mixer_selem_has_capture_channel(elem, 
SND_MIXER_SCHN_FRONT_LEFT);
+
+        element[f].has_playback = snd_mixer_selem_has_playback_volume(elem);
+        element[f].has_playback &= 
snd_mixer_selem_has_playback_channel(elem,SND_MIXER_SCHN_FRONT_LEFT);
+
+        if (element[f].has_playback) {
+            snd_mixer_selem_get_playback_volume_range(elem, &(element[f].min), 
&(element[f].max));
+            element[f].is_stereo = !snd_mixer_selem_is_playback_mono(elem);
+            element[f].is_stereo &= 
snd_mixer_selem_has_playback_channel(elem,SND_MIXER_SCHN_FRONT_RIGHT);
+            element[f].get_volume = snd_mixer_selem_get_playback_volume;
+            element[f].set_volume = snd_mixer_selem_set_playback_volume;
+            element[f].has_playback_switch = 
snd_mixer_selem_has_playback_switch(elem);
+        }
+        else if (element[f].has_capture) {
+            snd_mixer_selem_get_capture_volume_range(elem, &(element[f].min), 
&(element[f].max));
+            element[f].is_stereo = 
!snd_mixer_selem_is_capture_mono(element[f].element);
+            element[f].is_stereo &= 
snd_mixer_selem_has_capture_channel(elem,SND_MIXER_SCHN_FRONT_RIGHT);
+            element[f].get_volume = snd_mixer_selem_get_capture_volume;
+            element[f].set_volume = snd_mixer_selem_set_capture_volume;
+            element[f].has_capture_switch = 
snd_mixer_selem_has_capture_switch(elem);
+        } else {
+            elem = snd_mixer_elem_next(elem);
+            continue;
+        }
+
+        if (verbose) {
+            printf("  %d: '%s'%s%s%s%s %s (%ld - %ld)\n",
+                   f,
+                   element[f].name,
+                   element[f].has_playback? " pvolume" : "",
+                   element[f].has_playback_switch? " pswitch" : "",
+                   element[f].has_capture? " cvolume" : "",
+                   element[f].has_capture_switch? " cswitch" : "",
+                   element[f].is_stereo? "Stereo" : "Mono",
+                   element[f].min, element[f].max);
+        }
+
+        elem = snd_mixer_elem_next(elem);
+        f++;
+    }
+    n_elements = f;
+    get_mixer_state();
+}
+
+static bool element_is_muted(int e)
+{
+    if (!element[e].has_playback_switch)
+        return false;
+
+    snd_mixer_elem_t *elem = element[e].element;
+    int left_on;
+    snd_mixer_selem_get_playback_switch(elem, SND_MIXER_SCHN_FRONT_LEFT, 
&left_on);
+    if (left_on)
+        return false;
+    if (element[e].is_stereo) {
+        int right_on;
+        snd_mixer_selem_get_playback_switch(elem, SND_MIXER_SCHN_FRONT_RIGHT, 
&right_on);
+        if (right_on)
+            return false;
+    }
+    return true;
+}
+
+static bool element_is_recording(int e)
+{
+    if (!element[e].has_capture_switch)
+        return false;
+
+    snd_mixer_elem_t *elem = element[e].element;
+    int left_on;
+    snd_mixer_selem_get_capture_switch(elem, SND_MIXER_SCHN_FRONT_LEFT, 
&left_on);
+    if (left_on)
+        return true;
+    if (element[e].is_stereo) {
+        int right_on;
+        snd_mixer_selem_get_capture_switch(elem, SND_MIXER_SCHN_FRONT_RIGHT, 
&right_on);
+        if (right_on)
+            return true;
+    }
+    return false;
+}
+
+static bool get_mixer_state(void)
+{
+    if (!needs_update)
+        return false;
+    needs_update = false;
+
+    for (int e = 0; e < n_elements; e++) {
+        snd_mixer_elem_t *elem = element[e].element;
+        long left, right;
+
+        element[e].get_volume(elem, SND_MIXER_SCHN_FRONT_LEFT, &left);
+        float fleft = 1.0 * (left-element[e].min) / 
(element[e].max-element[e].min);
+        if (element[e].is_stereo) {
+            element[e].get_volume(elem, SND_MIXER_SCHN_FRONT_RIGHT, &right);
+            float fright = 1.0 * (right-element[e].min) /
+                (element[e].max-element[e].min);
+            lr_to_vb(fleft, fright, &(element[e].volume), 
&(element[e].balance));
+        } else {
+            element[e].volume = fleft;
+            element[e].balance = 0.0;
+        }
+
+        element[e].is_muted = element_is_muted(e);
+        element[e].is_recording = element_is_recording(e);
+
+        //printf("Channel %s, has_vol: %d, stereo: %d, muted: %d, max: %ld, 
min: %ld, left: %ld, right: %ld, vol: %f, bal: %f\n", element[e].name, 
element[e].has_playback, element[e].is_stereo, element[e].is_muted, 
element[e].max, element[e].min, left, element[e].is_stereo?right:-1, 
element[e].volume, element[e].balance);            
+    }
+    return true;
+}
+
+static void set_mixer_state(void)
+{
+    float left, right;
+    long dev_left_volume, dev_right_volume;
+    if (!element[cur_element].has_playback && 
!element[cur_element].has_capture)
+        return;
+
+    bool muted = element_is_muted(cur_element);
+    if (muted != element[cur_element].is_muted) {
+        snd_mixer_selem_set_playback_switch_all(element[cur_element].element,
+                                                element[cur_element].is_muted?
+                                                0:1);
+    }
+
+    bool recording = element_is_recording(cur_element);
+    if (recording != element[cur_element].is_recording) {
+        snd_mixer_selem_set_capture_switch_all(element[cur_element].element,
+                                               
element[cur_element].is_recording?
+                                               1:0);
+    }
+
+    if (element[cur_element].is_stereo)
+        vb_to_lr(element[cur_element].volume,
+                 element[cur_element].balance, &left, &right);
+    else
+        left = element[cur_element].volume;
+
+    long range = element[cur_element].max - element[cur_element].min;
+    dev_left_volume = element[cur_element].min + (long) (range * left);
+    element[cur_element].set_volume(element[cur_element].element,
+                                    SND_MIXER_SCHN_FRONT_LEFT,
+                                    dev_left_volume);
+    if (element[cur_element].is_stereo) {
+        dev_right_volume = element[cur_element].min + (long) (range * right);
+        element[cur_element].set_volume(element[cur_element].element,
+                                        SND_MIXER_SCHN_FRONT_RIGHT,
+                                        dev_right_volume);
+    }
+}
+
+bool mixer_alsa_is_changed(void)
+{
+    return get_mixer_state();
+}
+
+int mixer_alsa_get_channel_count(void)
+{
+    return n_elements;
+}
+
+int mixer_alsa_get_channel(void)
+{
+    return cur_element;
+}
+
+const char *mixer_alsa_get_channel_name(void)
+{
+    return element[cur_element].name;
+}
+
+const char *mixer_alsa_get_short_name(void)
+{
+    return element[cur_element].sname;
+}
+
+void mixer_alsa_set_channel(int element)
+{
+    assert((element >= 0) && (element < n_elements));
+
+    cur_element = element;
+    get_mixer_state();
+}
+
+void mixer_alsa_set_channel_rel(int delta_element)
+{
+    cur_element = (cur_element + delta_element) % n_elements;
+    if (cur_element < 0)
+       cur_element += n_elements;
+    get_mixer_state();
+}
+
+float mixer_alsa_get_volume(void)
+{
+    get_mixer_state();
+    return element[cur_element].volume;
+}
+
+void mixer_alsa_set_volume(float volume)
+{
+    assert((volume >= 0.0) && (volume <= 1.0));
+    element[cur_element].volume = volume;
+    set_mixer_state();
+}
+
+void mixer_alsa_set_volume_rel(float delta_volume)
+{
+    element[cur_element].volume += delta_volume;
+    element[cur_element].volume = CLAMP(element[cur_element].volume, 0.0, 1.0);
+    set_mixer_state();
+}
+
+float mixer_alsa_get_balance(void)
+{
+    get_mixer_state();
+    return element[cur_element].balance;
+}
+
+void mixer_alsa_set_balance(float balance)
+{
+    assert((balance >= -1.0) && (balance <= 1.0));
+    if (element[cur_element].is_stereo) {
+       element[cur_element].balance = balance;
+       set_mixer_state();
+    }
+}
+
+void mixer_alsa_set_balance_rel(float delta_balance)
+{
+    if (element[cur_element].is_stereo) {
+       element[cur_element].balance += delta_balance;
+       element[cur_element].balance =
+           CLAMP(element[cur_element].balance, -1.0, 1.0);
+       set_mixer_state();
+    }
+}
+
+void mixer_alsa_toggle_mute(void)
+{
+    if (element[cur_element].has_playback_switch) {
+        element[cur_element].is_muted ^= 1;
+        set_mixer_state();
+    }
+}
+
+void mixer_alsa_toggle_rec(void)
+{
+    if (element[cur_element].has_capture_switch) {
+        element[cur_element].is_recording ^= 1;
+        set_mixer_state();
+    }
+}
+
+bool mixer_alsa_is_muted(void)
+{
+    return element[cur_element].is_muted;
+}
+
+bool mixer_alsa_is_stereo(void)
+{
+    return element[cur_element].is_stereo;
+}
+
+bool mixer_alsa_is_rec(void)
+{
+    return element[cur_element].is_recording;
+}
+
+bool mixer_alsa_can_rec(void)
+{
+    return element[cur_element].has_capture;
+}
+
+void mixer_alsa_tick(void)
+{
+    snd_mixer_handle_events(mixer);
+}
diff --git a/wmix/mixer-oss.c b/wmix/mixer-oss.c
index 3f0ca8f..0c0e03f 100644
--- a/wmix/mixer-oss.c
+++ b/wmix/mixer-oss.c
@@ -32,7 +32,7 @@
 
 #include "include/common.h"
 #include "include/misc.h"
-#include "include/mixer.h"
+#include "include/mixer-oss.h"
 
 #define WMVOLUME_CHANNEL_NAMES \
        "Master volume", \
@@ -221,7 +221,43 @@ static void set_record_state(void)
     }
 }
 
-void mixer_init(const char *mixer_device, bool verbose, const char * exclude[])
+static bool is_exclude(const char *short_name, const char *exclude[])
+{
+    int count;
+    int len;
+
+    for (count = 0; exclude[count] != NULL; count++) {
+
+        /*
+         * Short names may be padded with spaces, because apparently there is 
a minimum
+         * length requirement of 6 characters for the name, and we do not want 
to
+         * include this padding in the match
+         */
+        len = strlen(short_name);
+        while (len > 0) {
+            if (short_name[len - 1] == ' ')
+                len--;
+            else
+                break;
+        }
+
+        if (strncmp(short_name, exclude[count], len) != 0)
+            continue;
+
+        if (exclude[count][len] != '\0')
+            continue;
+
+        /* Check the remaining in short name is only space */
+        while (short_name[len] == ' ')
+            len++;
+
+        if (short_name[len] == '\0')
+            return true;
+    }
+    return false;
+}
+
+void mixer_oss_init(const char *mixer_device, bool verbose, const char * 
exclude[])
 {
     int devmask, srcmask, recmask, stmask;
     struct mixer_info m_info;
@@ -288,32 +324,32 @@ void mixer_init(const char *mixer_device, bool verbose, 
const char * exclude[])
     get_mixer_state();
 }
 
-bool mixer_is_changed(void)
+bool mixer_oss_is_changed(void)
 {
     return get_mixer_state();
 }
 
-int mixer_get_channel_count(void)
+int mixer_oss_get_channel_count(void)
 {
     return n_channels;
 }
 
-int mixer_get_channel(void)
+int mixer_oss_get_channel(void)
 {
     return cur_channel;
 }
 
-const char *mixer_get_channel_name(void)
+const char *mixer_oss_get_channel_name(void)
 {
     return mixer[cur_channel].name;
 }
 
-const char *mixer_get_short_name(void)
+const char *mixer_oss_get_short_name(void)
 {
     return mixer[cur_channel].sname;
 }
 
-void mixer_set_channel(int channel)
+void mixer_oss_set_channel(int channel)
 {
     assert((channel >= 0) && (channel < n_channels));
 
@@ -321,7 +357,7 @@ void mixer_set_channel(int channel)
     get_record_state();
 }
 
-void mixer_set_channel_rel(int delta_channel)
+void mixer_oss_set_channel_rel(int delta_channel)
 {
     cur_channel = (cur_channel + delta_channel) % n_channels;
     if (cur_channel < 0)
@@ -329,13 +365,13 @@ void mixer_set_channel_rel(int delta_channel)
     get_record_state();
 }
 
-float mixer_get_volume(void)
+float mixer_oss_get_volume(void)
 {
     get_mixer_state();
     return mixer[cur_channel].volume;
 }
 
-void mixer_set_volume(float volume)
+void mixer_oss_set_volume(float volume)
 {
     assert((volume >= 0.0) && (volume <= 1.0));
 
@@ -343,20 +379,20 @@ void mixer_set_volume(float volume)
     set_mixer_state();
 }
 
-void mixer_set_volume_rel(float delta_volume)
+void mixer_oss_set_volume_rel(float delta_volume)
 {
     mixer[cur_channel].volume += delta_volume;
     mixer[cur_channel].volume = CLAMP(mixer[cur_channel].volume, 0.0, 1.0);
     set_mixer_state();
 }
 
-float mixer_get_balance(void)
+float mixer_oss_get_balance(void)
 {
     get_mixer_state();
     return mixer[cur_channel].balance;
 }
 
-void mixer_set_balance(float balance)
+void mixer_oss_set_balance(float balance)
 {
     assert((balance >= -1.0) && (balance <= 1.0));
 
@@ -366,7 +402,7 @@ void mixer_set_balance(float balance)
     }
 }
 
-void mixer_set_balance_rel(float delta_balance)
+void mixer_oss_set_balance_rel(float delta_balance)
 {
     if (mixer[cur_channel].is_stereo) {
        mixer[cur_channel].balance += delta_balance;
@@ -376,14 +412,14 @@ void mixer_set_balance_rel(float delta_balance)
     }
 }
 
-void mixer_toggle_mute(void)
+void mixer_oss_toggle_mute(void)
 {
     mixer[cur_channel].is_muted = !mixer[cur_channel].is_muted;
 
     set_mixer_state();
 }
 
-void mixer_toggle_rec(void)
+void mixer_oss_toggle_rec(void)
 {
     if (mixer[cur_channel].can_record) {
        mixer[cur_channel].is_recording = !mixer[cur_channel].is_recording;
@@ -392,60 +428,22 @@ void mixer_toggle_rec(void)
     }
 }
 
-bool mixer_is_muted(void)
+bool mixer_oss_is_muted(void)
 {
     return mixer[cur_channel].is_muted;
 }
 
-bool mixer_is_stereo(void)
+bool mixer_oss_is_stereo(void)
 {
     return mixer[cur_channel].is_stereo;
 }
 
-bool mixer_is_rec(void)
+bool mixer_oss_is_rec(void)
 {
     return mixer[cur_channel].is_recording;
 }
 
-bool mixer_can_rec(void)
+bool mixer_oss_can_rec(void)
 {
     return mixer[cur_channel].can_record;
 }
-
-bool is_exclude(const char *short_name, const char *exclude[])
-{
-       int count;
-       int len;
-
-       for (count = 0; count < SOUND_MIXER_NRDEVICES; count++) {
-               if (exclude[count] == NULL)
-                       break;
-
-               /*
-                * Short names may be padded with spaces, because apparently 
there is a minimum
-                * length requirement of 6 characters for the name, and we do 
not want to
-                * include this padding in the match
-                */
-               len = strlen(short_name);
-               while (len > 0) {
-                       if (short_name[len - 1] == ' ')
-                               len--;
-                       else
-                               break;
-               }
-
-               if (strncmp(short_name, exclude[count], len) != 0)
-                       continue;
-
-               if (exclude[count][len] != '\0')
-                       continue;
-
-               /* Check the remaining in short name is only space */
-               while (short_name[len] == ' ')
-                       len++;
-
-               if (short_name[len] == '\0')
-                       return true;
-       }
-       return false;
-}
diff --git a/wmix/wmix.c b/wmix/wmix.c
index b2ff99f..13d1593 100644
--- a/wmix/wmix.c
+++ b/wmix/wmix.c
@@ -31,14 +31,14 @@
 #include <X11/Xlib.h>
 #include <X11/Xutil.h>
 
-#include <sys/soundcard.h>
-
 #include "include/common.h"
 #include "include/mixer.h"
 #include "include/misc.h"
 #include "include/ui_x.h"
 #include "include/mmkeys.h"
 #include "include/config.h"
+#include "include/mixer-oss.h"
+#include "include/mixer-alsa.h"
 
 
 static Display *display;
@@ -58,6 +58,7 @@ static void button_press_event(XButtonEvent *event);
 static void button_release_event(XButtonEvent *event);
 static int  key_press_event(XKeyEvent *event);
 static void motion_event(XMotionEvent *event);
+static void choose_api(int api);
 
 
 int main(int argc, char **argv)
@@ -67,6 +68,7 @@ int main(int argc, char **argv)
     config_init();
     parse_cli_options(argc, argv);
     config_read();
+    choose_api(config.api);
 
     mixer_init(config.mixer_device, config.verbose, (const char 
**)config.exclude_channel);
     mixer_set_channel(0);
@@ -154,6 +156,8 @@ int main(int argc, char **argv)
            }
        } else {
            usleep(100000);
+            if (mixer_tick)
+                mixer_tick();
            scroll_text(3, 4, 57, false);
            /* rescroll message after some delay */
            if (idle_loop++ > 256) {
@@ -196,6 +200,55 @@ static void signal_catch(int sig)
     }
 }
 
+static void choose_api(int api)
+{
+    if (api == 0) {
+        mixer_init = &mixer_alsa_init;
+        mixer_is_changed = &mixer_alsa_is_changed;
+        mixer_get_channel_count = mixer_alsa_get_channel_count;
+        mixer_get_channel = mixer_alsa_get_channel;
+        mixer_get_channel_name = mixer_alsa_get_channel_name;
+        mixer_get_short_name = mixer_alsa_get_short_name;
+        mixer_set_channel = mixer_alsa_set_channel;
+        mixer_set_channel_rel = mixer_alsa_set_channel_rel;
+        mixer_get_volume = mixer_alsa_get_volume;
+        mixer_set_volume = mixer_alsa_set_volume;
+        mixer_set_volume_rel = mixer_alsa_set_volume_rel;
+        mixer_get_balance = mixer_alsa_get_balance;
+        mixer_set_balance = mixer_alsa_set_balance;
+        mixer_set_balance_rel = mixer_alsa_set_balance_rel;
+        mixer_toggle_mute = mixer_alsa_toggle_mute;
+        mixer_toggle_rec = mixer_alsa_toggle_rec;
+        mixer_is_muted = mixer_alsa_is_muted;
+        mixer_is_stereo = mixer_alsa_is_stereo;
+        mixer_is_rec = mixer_alsa_is_rec;
+        mixer_can_rec = mixer_alsa_can_rec;
+        mixer_tick = mixer_alsa_tick;
+    } else if (api == 1) {
+        mixer_init = &mixer_oss_init;
+        mixer_is_changed = &mixer_oss_is_changed;
+        mixer_get_channel_count = mixer_oss_get_channel_count;
+        mixer_get_channel = mixer_oss_get_channel;
+        mixer_get_channel_name = mixer_oss_get_channel_name;
+        mixer_get_short_name = mixer_oss_get_short_name;
+        mixer_set_channel = mixer_oss_set_channel;
+        mixer_set_channel_rel = mixer_oss_set_channel_rel;
+        mixer_get_volume = mixer_oss_get_volume;
+        mixer_set_volume = mixer_oss_set_volume;
+        mixer_set_volume_rel = mixer_oss_set_volume_rel;
+        mixer_get_balance = mixer_oss_get_balance;
+        mixer_set_balance = mixer_oss_set_balance;
+        mixer_set_balance_rel = mixer_oss_set_balance_rel;
+        mixer_toggle_mute = mixer_oss_toggle_mute;
+        mixer_toggle_rec = mixer_oss_toggle_rec;
+        mixer_is_muted = mixer_oss_is_muted;
+        mixer_is_stereo = mixer_oss_is_stereo;
+        mixer_is_rec = mixer_oss_is_rec;
+        mixer_can_rec = mixer_oss_can_rec;
+        mixer_tick = NULL;
+    }
+}
+
 static void button_press_event(XButtonEvent *event)
 {
     double button_press_time = get_current_time();
-- 
2.1.4


-- 
To unsubscribe, send mail to wmaker-dev-unsubscr...@lists.windowmaker.org.

Reply via email to