X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~mdw/git/disorder/blobdiff_plain/f845e711f93952805f2773900d64a499e293b270..a1bedb6db8934e6788075a1e1cda001356cf1d8b:/lib/mixer.c diff --git a/lib/mixer.c b/lib/mixer.c index 5ef30a2..58d9e60 100644 --- a/lib/mixer.c +++ b/lib/mixer.c @@ -1,6 +1,6 @@ /* * This file is part of DisOrder - * Copyright (C) 2004 Richard Kettlewell + * Copyright (C) 2007 Richard Kettlewell * * 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 @@ -17,98 +17,89 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA */ +/** @file lib/mixer.c + * @brief Mixer support + */ #include - -#include -#include -#include -#include -#include -#include -#include -#include +#include "types.h" #include "configuration.h" #include "mixer.h" #include "log.h" -#include "syscalls.h" +#include "mem.h" -#if HAVE_SYS_SOUNDCARD_H -#include +/** @brief Whether lack of volume support has been reported yet */ +static int none_reported; + +/** @brief Get/set volume stub if volume control is not supported */ +static int none_get_set(int attribute((unused)) *left, + int attribute((unused)) *right) { + if(!none_reported) { + error(0, "don't know how to get/set volume with this api"); + none_reported = 1; + } + return -1; +} + +/** @brief Stub mixer control */ +static const struct mixer mixer_none = { + -1, + none_get_set, + none_get_set, + "", + "" +}; -/* documentation does not match implementation! */ -#ifndef SOUND_MIXER_READ -# define SOUND_MIXER_READ(x) MIXER_READ(x) +/** @brief Table of mixer definitions */ +static const struct mixer *mixers[] = { +#if HAVE_SYS_SOUNDCARD_H + &mixer_oss, #endif -#ifndef SOUND_MIXER_WRITE -# define SOUND_MIXER_WRITE(x) MIXER_WRITE(x) +#if HAVE_ALSA_ASOUNDLIB_H + &mixer_alsa, #endif + &mixer_none /* make sure array is never empty */ +}; -static const char *channels[] = SOUND_DEVICE_NAMES; +/** @brief Number of mixer definitions */ +#define NMIXERS (sizeof mixers / sizeof *mixers) -int mixer_channel(const char *c) { - unsigned n; - - if(!c[strspn(c, "0123456789")]) - return atoi(c); - else { - for(n = 0; n < sizeof channels / sizeof *channels; ++n) - if(!strcmp(channels[n], c)) - return n; - return -1; - } -} +/** @brief Find the mixer definition */ +static const struct mixer *find_mixer(int api) { + size_t n; -int mixer_control(int *left, int *right, int set) { - int fd, ch, r; - - if(config->mixer - && config->channel - && (ch = mixer_channel(config->channel)) != -1) { - if((fd = open(config->mixer, O_RDWR, 0)) < 0) { - error(errno, "error opening %s", config->mixer); - return -1; - } - if(set) { - r = (*left & 0xff) + (*right & 0xff) * 256; - if(ioctl(fd, SOUND_MIXER_WRITE(ch), &r) == -1) { - error(errno, "error changing %s channel %s", - config->mixer, config->channel); - xclose(fd); - return -1; - } - } - if(ioctl(fd, SOUND_MIXER_READ(ch), &r) == -1) { - error(errno, "error reading %s channel %s", - config->mixer, config->channel); - xclose(fd); - return -1; - } - *left = r & 0xff; - *right = (r >> 8) & 0xff; - xclose(fd); - return 0; - } else - return -1; -} -#else -int mixer_channel(const char attribute((unused)) *c) { - return 0; + for(n = 0; n < NMIXERS; ++n) + if(mixers[n]->api == api) + return mixers[n]; + return &mixer_none; } -int mixer_control(int attribute((unused)) *left, - int attribute((unused)) *right, - int attribute((unused)) set) { - static int reported; +/** @brief Get/set volume + * @param left Left channel level, 0-100 + * @param right Right channel level, 0-100 + * @param set Set volume if non-0 + * @return 0 on success, non-0 on error + * + * If getting the volume then @p left and @p right are filled in. + * + * If setting the volume then the target levels are read from @p left and + * @p right, and the actual level set is stored in them. + */ +int mixer_control(int *left, int *right, int set) { + const struct mixer *const m = find_mixer(config->api); - if(!reported) { - error(0, "don't know how to set volume on this platform"); - reported = 1; - } - return -1; + /* We impose defaults bizarrely late, but this has the advantage of + * not making everything depend on sound libraries */ + if(!config->mixer) + config->mixer = xstrdup(m->device); + if(!config->channel) + config->channel = xstrdup(m->channel); + if(set) + return m->set(left, right); + else + return m->get(left, right); } -#endif /* Local Variables: