/* SPDX-License-Identifier: GPL-2.0 */ /** \file oss_mix.c The OSS mixer plugin. */ #include #include #include "para.h" #include "error.h" #include "mix.h" #include "fd.h" #include "string.h" struct oss_mixer_channel { const char *name; int id; }; static const struct oss_mixer_channel channels[] = { {.name = "volume", .id = SOUND_MIXER_VOLUME}, {.name = "bass", .id = SOUND_MIXER_BASS}, {.name = "treble", .id = SOUND_MIXER_TREBLE}, {.name = "synth", .id = SOUND_MIXER_SYNTH}, {.name = "pcm", .id = SOUND_MIXER_PCM}, {.name = "speaker", .id = SOUND_MIXER_SPEAKER}, {.name = "line", .id = SOUND_MIXER_LINE}, {.name = "mic", .id = SOUND_MIXER_MIC}, {.name = "cd", .id = SOUND_MIXER_CD}, {.name = "imix", .id = SOUND_MIXER_IMIX}, {.name = "altpcm", .id = SOUND_MIXER_ALTPCM}, {.name = "reclev", .id = SOUND_MIXER_RECLEV}, {.name = "igain", .id = SOUND_MIXER_IGAIN}, {.name = "ogain", .id = SOUND_MIXER_OGAIN}, }; /** Iterate over all defined mixer channels. */ #define FOR_EACH_CHANNEL(i) for ((i) = 0; (i) < ARRAY_SIZE(channels); (i)++) struct mixer_handle { int fd; int id; }; static int oss_mix_open(const char *dev, struct mixer_handle **handle) { int ret; struct mixer_handle *h; *handle = NULL; if (!dev) dev = "/dev/mixer"; PARA_INFO_LOG("opening %s\n", dev); ret = para_open(dev, O_RDWR, 42); if (ret < 0) { PARA_ERROR_LOG("could not open %s\n", dev); return ret; } h = alloc(sizeof(*h)); h->fd = ret; *handle = h; return 1; } static char *oss_mix_get_channels(__a_unused struct mixer_handle *handle) { int i; char *list = NULL; FOR_EACH_CHANNEL(i) { const char *name = channels[i].name; char *tmp = list; list = make_message("%s%s%s", list? list : "", list? ", " : "", name); free(tmp); } return list; } static int oss_mix_set_channel(struct mixer_handle *handle, const char *mixer_channel) { int i; if (!mixer_channel) { handle->id = SOUND_MIXER_VOLUME; /* default */ return 0; } FOR_EACH_CHANNEL(i) { if (strcasecmp(channels[i].name, mixer_channel)) continue; handle->id = i; return 1; } return -E_BAD_CHANNEL; } static int oss_mix_get(const struct mixer_handle *handle) { int val, fd = handle->fd, id = handle->id; if (ioctl(fd, MIXER_READ(id), &val) < 0) return -ERRNO_TO_PARA_ERROR(errno); /* take the mean value of left and right */ return (val % 256 + (val >> 8)) / 2; } static int oss_mix_set(struct mixer_handle *handle, int val) { int fd = handle->fd, id = handle->id, tmp = (val << 8) + val; if (ioctl(fd, MIXER_WRITE(id), &tmp) < 0) return -ERRNO_TO_PARA_ERROR(errno); return 1; } static void oss_mix_close(struct mixer_handle *h) { if (h && h->fd >= 0) close(h->fd); free(h); } /** The mixer operations for the OSS mixer. */ const struct mixer oss_mixer = { .name = "oss", .open = oss_mix_open, .get_channels = oss_mix_get_channels, .set_channel = oss_mix_set_channel, .close = oss_mix_close, .get = oss_mix_get, .set = oss_mix_set };