X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~mdw/git/disorder/blobdiff_plain/5b053666c0488ce2b0f0acc4304ac1a1d92a7035..b50cfb8a0d4fc71877ae0bfcd7b28879886a2ac1:/lib/uaudio-oss.c diff --git a/lib/uaudio-oss.c b/lib/uaudio-oss.c index 7bdfb35..d4c3711 100644 --- a/lib/uaudio-oss.c +++ b/lib/uaudio-oss.c @@ -41,10 +41,22 @@ # endif #endif +/* documentation does not match implementation! */ +#ifndef SOUND_MIXER_READ +# define SOUND_MIXER_READ(x) MIXER_READ(x) +#endif +#ifndef SOUND_MIXER_WRITE +# define SOUND_MIXER_WRITE(x) MIXER_WRITE(x) +#endif + static int oss_fd = -1; +static int oss_mixer_fd = -1; +static int oss_mixer_channel; static const char *const oss_options[] = { "device", + "mixer-device", + "mixer-channel", NULL }; @@ -59,7 +71,7 @@ static size_t oss_play(void *buffer, size_t samples) { /** @brief Open the OSS sound device */ static void oss_open(void) { - const char *device = uaudio_get("device"); + const char *device = uaudio_get("device", NULL); #if EMPEG_HOST if(!device || !*device || !strcmp(device, "default")) @@ -129,13 +141,71 @@ static void oss_stop(void) { uaudio_thread_stop(); } +/** @brief Channel names */ +static const char *oss_channels[] = SOUND_DEVICE_NAMES; + +static int oss_mixer_find_channel(const char *channel) { + if(!channel[strspn(c, "0123456789")]) + return atoi(channel); + else { + for(int n = 0; n < sizeof oss_channels / sizeof *oss_channels; ++n) + if(!strcmp(oss_channels[n], channels)) + return n; + return -1; + } +} + +static void oss_open_mixer(void) { + const char *mixer = uaudio_get("mixer-device", "/dev/mixer"); + /* TODO infer mixer-device from device */ + if((oss_mixer_fd = open(mixer, O_RDWR, 0)) < 0) + fatal(errno, "error opening %s", mixer); + const char *channel = uaudio_get("mixer-channel", "pcm"); + oss_mixer_channel = oss_mixer_find_channel(channel); + if(oss_mixer_channel < 0) + fatal(0, "no such channel as '%s'", channel); +} + +static void oss_close_mixer(void) { + close(oss_mixer_fd); + oss_mixer_fd = -1; +} + +static void oss_get_volume(int *left, int *right) { + int r; + + *left = *right = 0; + if(ioctl(oss_mixer_fd, SOUND_MIXER_READ(ch), &r) < 0) + error(errno, "error getting volume"); + else { + *left = r & 0xff; + *right = (r >> 8) & 0xff; + } +} + +static void oss_set_volume(int *left, int *right) { + int r = (*left & 0xff) + (*right & 0xff) * 256; + if(ioctl(fd, SOUND_MIXER_WRITE(ch), &r) == -1) + error(errno, "error setting volume"); + else if(ioctl(oss_mixer_fd, SOUND_MIXER_READ(ch), &r) < 0) + error(errno, "error getting volume"); + else { + *left = r & 0xff; + *right = (r >> 8) & 0xff; + } +} + const struct uaudio uaudio_oss = { .name = "oss", .options = oss_options, .start = oss_start, .stop = oss_stop, .activate = oss_activate, - .deactivate = oss_deactivate + .deactivate = oss_deactivate, + .open_mixer = oss_open_mixer, + .close_mixer = oss_close_mixer, + .get_volume = oss_get_volume, + .set_volume = oss_set_volume, }; #endif