From 11c29cccb3409fb4d0fea5171a56230253583864 Mon Sep 17 00:00:00 2001 From: Viliam Mateicka Date: Sat, 10 Jan 2009 17:53:33 +0100 Subject: Introducing mixer api This patch tryes to introduce pluggable mixer (struct mixer_plugin) along with some basic infrastructure (mixer_* functions). Instance of mixer (struct mixer) is used in alsa and oss output plugin --- src/Makefile.am | 1 + src/mixer/alsa_mixer.c | 60 ++++++++++++++++++++++++--------------- src/mixer/oss_mixer.c | 65 +++++++++++++++++++++++------------------- src/mixer_api.c | 45 +++++++++++++++++++++++++++++ src/mixer_api.h | 74 +++++++++++++++++++++++++++++++++--------------- src/output/alsa_plugin.c | 15 +++++----- src/output/oss_plugin.c | 16 +++++------ 7 files changed, 186 insertions(+), 90 deletions(-) create mode 100644 src/mixer_api.c (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am index e1977494a..65bfd45e4 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -128,6 +128,7 @@ mpd_SOURCES = \ main.c \ event_pipe.c \ daemon.c \ + mixer_api.c \ normalize.c \ compress.c \ pipe.c \ diff --git a/src/mixer/alsa_mixer.c b/src/mixer/alsa_mixer.c index c1331993b..6930fa8a0 100644 --- a/src/mixer/alsa_mixer.c +++ b/src/mixer/alsa_mixer.c @@ -18,7 +18,7 @@ struct alsa_mixer { int volume_set; }; -struct alsa_mixer * +static struct mixer_data * alsa_mixer_init(void) { struct alsa_mixer *am = g_malloc(sizeof(struct alsa_mixer)); @@ -29,18 +29,20 @@ alsa_mixer_init(void) am->volume_min = 0; am->volume_max = 0; am->volume_set = -1; - return am; + return (struct mixer_data *)am; } -void -alsa_mixer_finish(struct alsa_mixer *am) +static void +alsa_mixer_finish(struct mixer_data *data) { + struct alsa_mixer *am = (struct alsa_mixer *)data; g_free(am); } -void -alsa_mixer_configure(struct alsa_mixer *am, ConfigParam *param) +static void +alsa_mixer_configure(struct mixer_data *data, ConfigParam *param) { + struct alsa_mixer *am = (struct alsa_mixer *)data; BlockParam *bp; if ((bp = getBlockParam(param, "mixer_device"))) @@ -49,16 +51,18 @@ alsa_mixer_configure(struct alsa_mixer *am, ConfigParam *param) am->control = bp->value; } -void -alsa_mixer_close(struct alsa_mixer *am) +static void +alsa_mixer_close(struct mixer_data *data) { + struct alsa_mixer *am = (struct alsa_mixer *)data; if (am->handle) snd_mixer_close(am->handle); am->handle = NULL; } -bool -alsa_mixer_open(struct alsa_mixer *am) +static bool +alsa_mixer_open(struct mixer_data *data) { + struct alsa_mixer *am = (struct alsa_mixer *)data; int err; snd_mixer_elem_t *elem; const char *control_name = VOLUME_MIXER_ALSA_CONTROL_DEFAULT; @@ -77,7 +81,7 @@ alsa_mixer_open(struct alsa_mixer *am) if ((err = snd_mixer_attach(am->handle, device)) < 0) { g_warning("problems attaching alsa mixer: %s\n", snd_strerror(err)); - alsa_mixer_close(am); + alsa_mixer_close(data); return false; } @@ -85,14 +89,14 @@ alsa_mixer_open(struct alsa_mixer *am) NULL)) < 0) { g_warning("problems snd_mixer_selem_register'ing: %s\n", snd_strerror(err)); - alsa_mixer_close(am); + alsa_mixer_close(data); return false; } if ((err = snd_mixer_load(am->handle)) < 0) { g_warning("problems snd_mixer_selem_register'ing: %s\n", snd_strerror(err)); - alsa_mixer_close(am); + alsa_mixer_close(data); return false; } @@ -122,18 +126,19 @@ alsa_mixer_open(struct alsa_mixer *am) g_warning("can't find alsa mixer control \"%s\"\n", control_name); - alsa_mixer_close(am); + alsa_mixer_close(data); return false; } -bool -alsa_mixer_control(struct alsa_mixer *am, int cmd, void *arg) +static bool +alsa_mixer_control(struct mixer_data *data, int cmd, void *arg) { + struct alsa_mixer *am = (struct alsa_mixer *)data; switch (cmd) { case AC_MIXER_CONFIGURE: - alsa_mixer_configure(am, (ConfigParam *)arg); + alsa_mixer_configure(data, (ConfigParam *)arg); if (am->handle) - alsa_mixer_close(am); + alsa_mixer_close(data); return true; case AC_MIXER_GETVOL: { @@ -141,20 +146,20 @@ alsa_mixer_control(struct alsa_mixer *am, int cmd, void *arg) int ret, *volume = arg; long level; - if (!am->handle && !alsa_mixer_open(am)) { + if (!am->handle && !alsa_mixer_open(data)) { return false; } if ((err = snd_mixer_handle_events(am->handle)) < 0) { g_warning("problems getting alsa volume: %s (snd_mixer_%s)\n", snd_strerror(err), "handle_events"); - alsa_mixer_close(am); + alsa_mixer_close(data); return false; } if ((err = snd_mixer_selem_get_playback_volume(am->elem, SND_MIXER_SCHN_FRONT_LEFT, &level)) < 0) { g_warning("problems getting alsa volume: %s (snd_mixer_%s)\n", snd_strerror(err), "selem_get_playback_volume"); - alsa_mixer_close(am); + alsa_mixer_close(data); return false; } ret = ((am->volume_set / 100.0) * (am->volume_max - am->volume_min) @@ -175,7 +180,7 @@ alsa_mixer_control(struct alsa_mixer *am, int cmd, void *arg) int *volume = arg; int err; - if (!am->handle && !alsa_mixer_open(am)) { + if (!am->handle && !alsa_mixer_open(data)) { return false; } vol = *volume; @@ -193,7 +198,7 @@ alsa_mixer_control(struct alsa_mixer *am, int cmd, void *arg) level)) < 0) { g_warning("problems setting alsa volume: %s\n", snd_strerror(err)); - alsa_mixer_close(am); + alsa_mixer_close(data); return false; } return true; @@ -204,3 +209,12 @@ alsa_mixer_control(struct alsa_mixer *am, int cmd, void *arg) } return false; } + +struct mixer_plugin alsa_mixer = { + .init = alsa_mixer_init, + .finish = alsa_mixer_finish, + .configure = alsa_mixer_configure, + .open = alsa_mixer_open, + .control = alsa_mixer_control, + .close = alsa_mixer_close +}; diff --git a/src/mixer/oss_mixer.c b/src/mixer/oss_mixer.c index b4b2ed7c6..db8431ab9 100644 --- a/src/mixer/oss_mixer.c +++ b/src/mixer/oss_mixer.c @@ -25,14 +25,7 @@ struct oss_mixer { int volume_control; }; -struct oss_mixer *oss_mixer_init(void); -void oss_mixer_finish(struct oss_mixer *am); -void oss_mixer_configure(struct oss_mixer *am, ConfigParam *param); -bool oss_mixer_open(struct oss_mixer *am); -bool oss_mixer_control(struct oss_mixer *am, int cmd, void *arg); -void oss_mixer_close(struct oss_mixer *am); - -struct oss_mixer * +static struct mixer_data * oss_mixer_init(void) { struct oss_mixer *om = g_malloc(sizeof(struct oss_mixer)); @@ -40,18 +33,20 @@ oss_mixer_init(void) om->control = NULL; om->device_fd = -1; om->volume_control = SOUND_MIXER_PCM; - return om; + return (struct mixer_data *)om; } -void -oss_mixer_finish(struct oss_mixer *om) +static void +oss_mixer_finish(struct mixer_data *data) { + struct oss_mixer *om = (struct oss_mixer *) data; g_free(om); } -void -oss_mixer_configure(struct oss_mixer *om, ConfigParam *param) +static void +oss_mixer_configure(struct mixer_data *data, ConfigParam *param) { + struct oss_mixer *om = (struct oss_mixer *) data; BlockParam *bp; bp = getBlockParam(param, "mixer_device"); if (bp) { @@ -63,9 +58,10 @@ oss_mixer_configure(struct oss_mixer *om, ConfigParam *param) } } -void -oss_mixer_close(struct oss_mixer *om) +static void +oss_mixer_close(struct mixer_data *data) { + struct oss_mixer *om = (struct oss_mixer *) data; if (om->device_fd != -1) while (close(om->device_fd) && errno == EINTR) ; om->device_fd = -1; @@ -86,9 +82,10 @@ oss_find_mixer(const char *name) return -1; } -bool -oss_mixer_open(struct oss_mixer *om) +static bool +oss_mixer_open(struct mixer_data *data) { + struct oss_mixer *om = (struct oss_mixer *) data; const char *device = VOLUME_MIXER_OSS_DEFAULT; if (om->device) { @@ -106,7 +103,7 @@ oss_mixer_open(struct oss_mixer *om) if (ioctl(om->device_fd, SOUND_MIXER_READ_DEVMASK, &devmask) < 0) { g_warning("errors getting read_devmask for oss mixer\n"); - oss_mixer_close(om); + oss_mixer_close(data); return false; } i = oss_find_mixer(om->control); @@ -114,12 +111,12 @@ oss_mixer_open(struct oss_mixer *om) if (i < 0) { g_warning("mixer control \"%s\" not found\n", om->control); - oss_mixer_close(om); + oss_mixer_close(data); return false; } else if (!((1 << i) & devmask)) { g_warning("mixer control \"%s\" not usable\n", om->control); - oss_mixer_close(om); + oss_mixer_close(data); return false; } om->volume_control = i; @@ -127,14 +124,15 @@ oss_mixer_open(struct oss_mixer *om) return true; } -bool -oss_mixer_control(struct oss_mixer *om, int cmd, void *arg) +static bool +oss_mixer_control(struct mixer_data *data, int cmd, void *arg) { + struct oss_mixer *om = (struct oss_mixer *) data; switch (cmd) { case AC_MIXER_CONFIGURE: - oss_mixer_configure(om, (ConfigParam *)arg); - //if (om->device_fd >= 0) - oss_mixer_close(om); + oss_mixer_configure(data, (ConfigParam *)arg); + if (om->device_fd >= 0) + oss_mixer_close(data); return true; break; case AC_MIXER_GETVOL: @@ -142,12 +140,12 @@ oss_mixer_control(struct oss_mixer *om, int cmd, void *arg) int left, right, level; int *ret; - if (om->device_fd < 0 && !oss_mixer_open(om)) { + if (om->device_fd < 0 && !oss_mixer_open(data)) { return false; } if (ioctl(om->device_fd, MIXER_READ(om->volume_control), &level) < 0) { - oss_mixer_close(om); + oss_mixer_close(data); g_warning("unable to read oss volume\n"); return false; } @@ -169,7 +167,7 @@ oss_mixer_control(struct oss_mixer *om, int cmd, void *arg) int level; int *value = arg; - if (om->device_fd < 0 && !oss_mixer_open(om)) { + if (om->device_fd < 0 && !oss_mixer_open(data)) { return false; } @@ -184,7 +182,7 @@ oss_mixer_control(struct oss_mixer *om, int cmd, void *arg) if (ioctl(om->device_fd, MIXER_WRITE(om->volume_control), &level) < 0) { g_warning("unable to set oss volume\n"); - oss_mixer_close(om); + oss_mixer_close(data); return false; } return true; @@ -195,3 +193,12 @@ oss_mixer_control(struct oss_mixer *om, int cmd, void *arg) } return false; } + +struct mixer_plugin oss_mixer = { + .init = oss_mixer_init, + .finish = oss_mixer_finish, + .configure = oss_mixer_configure, + .open = oss_mixer_open, + .control = oss_mixer_control, + .close = oss_mixer_close +}; diff --git a/src/mixer_api.c b/src/mixer_api.c new file mode 100644 index 000000000..f77f764cf --- /dev/null +++ b/src/mixer_api.c @@ -0,0 +1,45 @@ + +#include +#include + +#include "mixer_api.h" + +void mixer_init(struct mixer *mixer, struct mixer_plugin *plugin) +{ + assert(plugin != NULL); + assert(mixer != NULL); + mixer->plugin = plugin; + mixer->data = mixer->plugin->init(); +} + +void mixer_finish(struct mixer *mixer) +{ + assert(mixer != NULL && mixer->plugin != NULL); + mixer->plugin->finish(mixer->data); + mixer->data = NULL; + mixer->plugin = NULL; +} + +void mixer_configure(struct mixer *mixer, ConfigParam *param) +{ + assert(mixer != NULL && mixer->plugin != NULL); + mixer->plugin->configure(mixer->data, param); +} + +bool mixer_open(struct mixer *mixer) +{ + assert(mixer != NULL && mixer->plugin != NULL); + return mixer->plugin->open(mixer->data); +} + +bool mixer_control(struct mixer *mixer, int cmd, void *arg) +{ + assert(mixer != NULL && mixer->plugin != NULL); + return mixer->plugin->control(mixer->data, cmd, arg); +} + +void mixer_close(struct mixer *mixer) +{ + assert(mixer != NULL && mixer->plugin != NULL); + mixer->plugin->close(mixer->data); +} diff --git a/src/mixer_api.h b/src/mixer_api.h index 43dc3299d..67d08427c 100644 --- a/src/mixer_api.h +++ b/src/mixer_api.h @@ -4,30 +4,58 @@ #include "conf.h" -/** - * alsa mixer +/* + * list of currently implemented mixers */ -struct alsa_mixer; - -struct alsa_mixer *alsa_mixer_init(void); -void alsa_mixer_finish(struct alsa_mixer *am); -void alsa_mixer_configure(struct alsa_mixer *am, ConfigParam *param); -bool alsa_mixer_open(struct alsa_mixer *am); -bool alsa_mixer_control(struct alsa_mixer *am, int cmd, void *arg); -void alsa_mixer_close(struct alsa_mixer *am); - -/** - * oss mixer - */ - -struct oss_mixer; - -struct oss_mixer *oss_mixer_init(void); -void oss_mixer_finish(struct oss_mixer *am); -void oss_mixer_configure(struct oss_mixer *am, ConfigParam *param); -bool oss_mixer_open(struct oss_mixer *am); -bool oss_mixer_control(struct oss_mixer *am, int cmd, void *arg); -void oss_mixer_close(struct oss_mixer *am); +extern struct mixer_plugin alsa_mixer; +extern struct mixer_plugin oss_mixer; + +struct mixer_data; + +struct mixer_plugin { + + /** + * Allocate and initialize mixer data + */ + struct mixer_data *(*init)(void); + + /** + * Finish and free mixer data + */ + void (*finish)(struct mixer_data *data); + + /** + * Setup and configure mixer + */ + void (*configure)(struct mixer_data *data, ConfigParam *param); + + /** + * Open mixer device + */ + bool (*open)(struct mixer_data *data); + + /** + * Control mixer device. + */ + bool (*control)(struct mixer_data *data, int cmd, void *arg); + + /** + * Close mixer device + */ + void (*close)(struct mixer_data *data); +}; + +struct mixer { + struct mixer_plugin *plugin; + struct mixer_data *data; +}; + +void mixer_init(struct mixer *mixer, struct mixer_plugin *plugin); +void mixer_finish(struct mixer *mixer); +void mixer_configure(struct mixer *mixer, ConfigParam *param); +bool mixer_open(struct mixer *mixer); +bool mixer_control(struct mixer *mixer, int cmd, void *arg); +void mixer_close(struct mixer *mixer); #endif diff --git a/src/output/alsa_plugin.c b/src/output/alsa_plugin.c index fc5c56c21..58f549800 100644 --- a/src/output/alsa_plugin.c +++ b/src/output/alsa_plugin.c @@ -52,7 +52,7 @@ typedef struct _AlsaData { int sampleSize; int useMmap; - struct alsa_mixer *mixer; + struct mixer mixer; } AlsaData; @@ -74,7 +74,8 @@ static AlsaData *newAlsaData(void) ret->buffer_time = MPD_ALSA_BUFFER_TIME_US; ret->period_time = 0; - ret->mixer = alsa_mixer_init(); + //use alsa mixer by default + mixer_init(&ret->mixer, &alsa_mixer); return ret; } @@ -82,7 +83,7 @@ static AlsaData *newAlsaData(void) static void freeAlsaData(AlsaData * ad) { g_free(ad->device); - alsa_mixer_finish(ad->mixer); + mixer_finish(&ad->mixer); free(ad); } @@ -133,7 +134,7 @@ static void *alsa_initDriver(G_GNUC_UNUSED struct audio_output *ao, if (param) { alsa_configure(ad, param); - alsa_mixer_configure(ad->mixer, param); + mixer_configure(&ad->mixer, param); } return ad; @@ -189,7 +190,7 @@ static bool alsa_openDevice(void *data, struct audio_format *audioFormat) unsigned int period_time, period_time_ro; unsigned int buffer_time; - alsa_mixer_open(ad->mixer); + mixer_open(&ad->mixer); if ((bitformat = get_bitformat(audioFormat)) == SND_PCM_FORMAT_UNKNOWN) g_warning("ALSA device \"%s\" doesn't support %u bit audio\n", @@ -413,7 +414,7 @@ static void alsa_closeDevice(void *data) snd_pcm_close(ad->pcmHandle); ad->pcmHandle = NULL; } - alsa_mixer_close(ad->mixer); + mixer_close(&ad->mixer); } static bool @@ -451,7 +452,7 @@ static bool alsa_control(void *data, int cmd, void *arg) { AlsaData *ad = data; - return alsa_mixer_control(ad->mixer, cmd, arg); + return mixer_control(&ad->mixer, cmd, arg); } const struct audio_output_plugin alsaPlugin = { diff --git a/src/output/oss_plugin.c b/src/output/oss_plugin.c index f46377254..175aace1a 100644 --- a/src/output/oss_plugin.c +++ b/src/output/oss_plugin.c @@ -55,7 +55,7 @@ typedef struct _OssData { int numSupported[3]; int *unsupported[3]; int numUnsupported[3]; - struct oss_mixer *mixer; + struct mixer mixer; } OssData; enum oss_support { @@ -276,7 +276,7 @@ static OssData *newOssData(void) supportParam(ret, SNDCTL_DSP_CHANNELS, 2); supportParam(ret, SNDCTL_DSP_SAMPLESIZE, 16); - ret->mixer = oss_mixer_init(); + mixer_init( &ret->mixer, &oss_mixer); return ret; } @@ -290,7 +290,7 @@ static void freeOssData(OssData * od) g_free(od->unsupported[OSS_CHANNELS]); g_free(od->unsupported[OSS_BITS]); - oss_mixer_finish(od->mixer); + mixer_finish(&od->mixer); free(od); } @@ -355,7 +355,7 @@ static void *oss_open_default(ConfigParam *param) if (ret[i] == 0) { OssData *od = newOssData(); od->device = default_devices[i]; - oss_mixer_configure(od->mixer, param); + mixer_configure(&od->mixer, param); return od; } } @@ -396,7 +396,7 @@ static void *oss_initDriver(G_GNUC_UNUSED struct audio_output *audioOutput, if (bp) { OssData *od = newOssData(); od->device = bp->value; - oss_mixer_configure(od->mixer, param); + mixer_configure(&od->mixer, param); return od; } } @@ -522,7 +522,7 @@ oss_openDevice(void *data, struct audio_format *audioFormat) od->audio_format.bits, od->audio_format.channels, od->audio_format.sample_rate); - oss_mixer_open(od->mixer); + mixer_open(&od->mixer); return ret; } @@ -532,7 +532,7 @@ static void oss_closeDevice(void *data) OssData *od = data; oss_close(od); - oss_mixer_close(od->mixer); + mixer_close(&od->mixer); } static void oss_dropBufferedAudio(void *data) @@ -575,7 +575,7 @@ static bool oss_control(void *data, int cmd, void *arg) { OssData *od = data; - return oss_mixer_control(od->mixer, cmd, arg); + return mixer_control(&od->mixer, cmd, arg); } const struct audio_output_plugin ossPlugin = { -- cgit v1.2.3