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 timecop@japan.co.jp + skunk@mit.edu\n" #define HELP_TEXT \ "usage:\n" \ + " -a use this sound api (oss or alsa) [alsa]\n" \ " -d connect to remote X display\n" \ " -e exclude channel, can be used many times\n" \ " -f parse this config [~/.wmixrc]\n" \ " -h print this help\n" \ " -k disable grabing volume control keys\n" \ - " -m mixer device [/dev/mixer]\n" \ + " -m 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 - +#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. , + * timecop + * + * 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. , + * timecop + * + * 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 + +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 #include -#include - #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();