X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~mdw/git/disorder/blobdiff_plain/42f738c244c06450e25775631b73ac2fa0878da5..a89e0ecf7c67ef6af6678985060a0d8e7bae5fba:/lib/uaudio-oss.c diff --git a/lib/uaudio-oss.c b/lib/uaudio-oss.c index 081e1eb..abf0354 100644 --- a/lib/uaudio-oss.c +++ b/lib/uaudio-oss.c @@ -28,10 +28,12 @@ #include #include #include +#include #include "mem.h" #include "log.h" #include "uaudio.h" +#include "configuration.h" #ifndef AFMT_U16_NE # if BYTE_ORDER == BIG_ENDIAN @@ -60,22 +62,13 @@ static const char *const oss_options[] = { NULL }; -/** @brief Actually play sound via OSS */ -static size_t oss_play(void *buffer, size_t samples) { - const size_t bytes = samples * uaudio_sample_size; - int rc = write(oss_fd, buffer, bytes); - if(rc < 0) - fatal(errno, "error writing to sound device"); - return rc / uaudio_sample_size; -} - /** @brief Open the OSS sound device */ static void oss_open(void) { const char *device = uaudio_get("device", NULL); #if EMPEG_HOST if(!device || !*device || !strcmp(device, "default")) - device "/dev/audio"; + device = "/dev/audio"; #else if(!device || !*device || !strcmp(device, "default")) { if(access("/dev/dsp", W_OK) == 0) @@ -85,60 +78,86 @@ static void oss_open(void) { } #endif if((oss_fd = open(device, O_WRONLY, 0)) < 0) - fatal(errno, "error opening %s", device); + disorder_fatal(errno, "error opening %s", device); #if !EMPEG_HOST int stereo = (uaudio_channels == 2), format; if(ioctl(oss_fd, SNDCTL_DSP_STEREO, &stereo) < 0) - fatal(errno, "error calling ioctl SNDCTL_DSP_STEREO %d", stereo); + disorder_fatal(errno, "error calling ioctl SNDCTL_DSP_STEREO %d", stereo); if(uaudio_bits == 16) format = uaudio_signed ? AFMT_S16_NE : AFMT_U16_NE; else format = uaudio_signed ? AFMT_S8 : AFMT_U8; if(ioctl(oss_fd, SNDCTL_DSP_SETFMT, &format) < 0) - fatal(errno, "error calling ioctl SNDCTL_DSP_SETFMT %#x", format); + disorder_fatal(errno, "error calling ioctl SNDCTL_DSP_SETFMT %#x", format); int rate = uaudio_rate; if(ioctl(oss_fd, SNDCTL_DSP_SPEED, &rate) < 0) - fatal(errno, "error calling ioctl SNDCTL_DSP_SPEED %d", rate); + disorder_fatal(errno, "error calling ioctl SNDCTL_DSP_SPEED %d", rate); if(rate != uaudio_rate) - error(0, "asked for %dHz, got %dHz", uaudio_rate, rate); + disorder_error(0, "asked for %dHz, got %dHz", uaudio_rate, rate); #endif } -static void oss_activate(void) { - oss_open(); - uaudio_thread_activate(); +/** @brief Close the OSS sound device */ +static void oss_close(void) { + if(oss_fd != -1) { + close(oss_fd); + oss_fd = -1; + } } -static void oss_deactivate(void) { - uaudio_thread_deactivate(); - close(oss_fd); - oss_fd = -1; +/** @brief Actually play sound via OSS */ +static size_t oss_play(void *buffer, size_t samples, unsigned flags) { + /* cf uaudio-alsa.c:alsa-play() */ + if(flags & UAUDIO_PAUSED) { + if(flags & UAUDIO_PAUSE) + oss_close(); + if(samples > 64) + samples /= 2; + const uint64_t ns = ((uint64_t)samples * 1000000000 + / (uaudio_rate * uaudio_channels)); + struct timespec ts[1]; + ts->tv_sec = ns / 1000000000; + ts->tv_nsec = ns % 1000000000; + while(nanosleep(ts, ts) < 0 && errno == EINTR) + ; + return samples; + } + if(flags & UAUDIO_RESUME) + oss_open(); + const size_t bytes = samples * uaudio_sample_size; + int rc = write(oss_fd, buffer, bytes); + if(rc < 0) + disorder_fatal(errno, "error writing to sound device"); + return rc / uaudio_sample_size; } - + static void oss_start(uaudio_callback *callback, void *userdata) { if(uaudio_channels != 1 && uaudio_channels != 2) - fatal(0, "asked for %d channels but only support 1 or 2", + disorder_fatal(0, "asked for %d channels but only support 1 or 2", uaudio_channels); if(uaudio_bits != 8 && uaudio_bits != 16) - fatal(0, "asked for %d bits/channel but only support 8 or 16", + disorder_fatal(0, "asked for %d bits/channel but only support 8 or 16", uaudio_bits); #if EMPEG_HOST /* Very specific buffer size requirements here apparently */ uaudio_thread_start(callback, userdata, oss_play, 4608 / uaudio_sample_size, - 4608 / uaudio_sample_size); + 4608 / uaudio_sample_size, + 0); #else /* We could SNDCTL_DSP_GETBLKSIZE but only when the device is already open, * which is kind of inconvenient. We go with 1-4Kbyte for now. */ uaudio_thread_start(callback, userdata, oss_play, 32 / uaudio_sample_size, - 4096 / uaudio_sample_size); + 4096 / uaudio_sample_size, + 0); #endif } static void oss_stop(void) { uaudio_thread_stop(); + oss_close(); /* might not have been paused */ } /** @brief Channel names */ @@ -159,11 +178,11 @@ 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); + disorder_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); + disorder_fatal(0, "no such channel as '%s'", channel); } static void oss_close_mixer(void) { @@ -176,7 +195,7 @@ static void oss_get_volume(int *left, int *right) { *left = *right = 0; if(ioctl(oss_mixer_fd, SOUND_MIXER_READ(oss_mixer_channel), &r) < 0) - error(errno, "error getting volume"); + disorder_error(errno, "error getting volume"); else { *left = r & 0xff; *right = (r >> 8) & 0xff; @@ -186,26 +205,33 @@ static void oss_get_volume(int *left, int *right) { static void oss_set_volume(int *left, int *right) { int r = (*left & 0xff) + (*right & 0xff) * 256; if(ioctl(oss_mixer_fd, SOUND_MIXER_WRITE(oss_mixer_channel), &r) == -1) - error(errno, "error setting volume"); + disorder_error(errno, "error setting volume"); else if(ioctl(oss_mixer_fd, SOUND_MIXER_READ(oss_mixer_channel), &r) < 0) - error(errno, "error getting volume"); + disorder_error(errno, "error getting volume"); else { *left = r & 0xff; *right = (r >> 8) & 0xff; } } +static void oss_configure(void) { + uaudio_set("device", config->device); + uaudio_set("mixer-device", config->mixer); + uaudio_set("mixer-channel", config->channel); +} + const struct uaudio uaudio_oss = { .name = "oss", .options = oss_options, .start = oss_start, .stop = oss_stop, - .activate = oss_activate, - .deactivate = oss_deactivate, + .activate = uaudio_thread_activate, + .deactivate = uaudio_thread_deactivate, .open_mixer = oss_open_mixer, .close_mixer = oss_close_mixer, .get_volume = oss_get_volume, .set_volume = oss_set_volume, + .configure = oss_configure, }; #endif