X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~mdw/git/disorder/blobdiff_plain/7a2c706849ecf6cee19d9e502f8491ffac3322e0..5b053666c0488ce2b0f0acc4304ac1a1d92a7035:/lib/uaudio-oss.c diff --git a/lib/uaudio-oss.c b/lib/uaudio-oss.c index 06ffb73..7bdfb35 100644 --- a/lib/uaudio-oss.c +++ b/lib/uaudio-oss.c @@ -25,147 +25,108 @@ # include #endif #include -#include #include #include #include -#include #include "mem.h" #include "log.h" -#include "syscalls.h" +#include "uaudio.h" + +#ifndef AFMT_U16_NE +# if BYTE_ORDER == BIG_ENDIAN +# define AFMT_U16_NE AFMT_U16_BE +# else +# define AFMT_U16_NE AFMT_U16_LE +# endif +#endif static int oss_fd = -1; -static pthread_t oss_thread; -static uaudio_callback *oss_callback; -static int oss_started; -static int oss_activated; -static int oss_going; -static pthread_mutex_t oss_lock = PTHREAD_MUTEX_INITIALIZER; -static pthread_cond_t oss_cond = PTHREAD_COND_INITIALIZER; -static int oss_bufsize; static const char *const oss_options[] = { "device", NULL }; -static void *oss_thread(void *userdata) { - int16_t *buffer; - pthread_mutex_lock(&oss_lock); - buffer = xmalloc(XXX); - while(oss_started) { - while(oss_started && !oss_activated) - pthread_cond_wait(&oss_cond, &oss_lock); - if(!oss_started) - break; - /* We are definitely active now */ - oss_going = 1; - pthread_cond_signal(&oss_cond); - while(oss_activated) { - const int nsamples = oss_callback(buffer, oss_bufsizeXXX, userdata);; - if(write(oss_fd, buffer, XXX) < 0) - fatal(errno, "error playing audio"); - // TODO short writes! - } - oss_going = 0; - pthread_cond_signal(&oss_cond); - } - pthread_mutex_unlock(&oss_lock); - return NULL; -} - -static void oss_start(uaudio_callback *callback, - void *userdata) { - int e; - oss_callback = callback; - if((e = pthread_create(&oss_thread, - NULL, - oss_thread_fn, - userdata))) - fatal(e, "pthread_create"); +/** @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; } -static void oss_stop(void) { - void *result; +/** @brief Open the OSS sound device */ +static void oss_open(void) { + const char *device = uaudio_get("device"); - oss_deactivate(); - pthread_mutex_lock(&oss_lock); - oss_started = 0; - pthread_cond_signal(&oss_cond); - pthread_mutex_unlock(&oss_lock); - pthread_join(oss_thread, &result); +#if EMPEG_HOST + if(!device || !*device || !strcmp(device, "default")) + device "/dev/audio"; +#else + if(!device || !*device || !strcmp(device, "default")) { + if(access("/dev/dsp", W_OK) == 0) + device = "/dev/dsp"; + else + device = "/dev/audio"; + } +#endif + if((oss_fd = open(device, O_WRONLY, 0)) < 0) + 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); + 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); + int rate = uaudio_rate; + if(ioctl(oss_fd, SNDCTL_DSP_SPEED, &rate) < 0) + fatal(errno, "error calling ioctl SNDCTL_DSP_SPEED %d", rate); + if(rate != uaudio_rate) + error(0, "asked for %dHz, got %dHz", uaudio_rate, rate); +#endif } static void oss_activate(void) { - pthread_mutex_lock(&oss_lock); - if(!oss_activated) { - const char *device = uaudio_get(&uadiuo_oss, "device"); + oss_open(); + uaudio_thread_activate(); +} +static void oss_deactivate(void) { + uaudio_thread_deactivate(); + close(oss_fd); + oss_fd = -1; +} + +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", + uaudio_channels); + if(uaudio_bits != 8 && uaudio_bits != 16) + fatal(0, "asked for %d bits/channel but only support 8 or 16", + uaudio_bits); #if EMPEG_HOST - if(!device || !*device || !strcmp(device, "default")) { - device "/dev/audio"; -#else - if(!device || !*device || !strcmp(device, "default")) { - if(access("/dev/dsp", W_OK) == 0) - device = "/dev/dsp"; - else - device = "/dev/audio"; - } -#endif - if((oss_fd = open(device, O_WRONLY, 0)) < 0) - fatal(errno, "error opening %s", device); -#if EMPEG_HOST - /* empeg audio driver only knows /dev/audio, only supports the equivalent - * of AFMT_S16_NE, has a fixed buffer size, and does not support the - * SNDCTL_ ioctls. */ - oss_bufsize = 4608; + /* Very specific buffer size requirements here apparently */ + uaudio_thread_start(callback, userdata, oss_play, + 4608 / uaudio_sample_size, + 4608 / uaudio_sample_size); #else - int stereo = (config->sample_format.channels == 2), format, rate; - if(ioctl(ossfd, SNDCTL_DSP_STEREO, &stereo) < 0) { - error(errno, "error calling ioctl SNDCTL_DSP_STEREO %d", stereo); - goto failed; - } - /* TODO we need to think about where we decide this */ - if(config->sample_format.bits == 8) - format = AFMT_U8; - else if(config->sample_format.bits == 16) - format = (config->sample_format.endian == ENDIAN_LITTLE - ? AFMT_S16_LE : AFMT_S16_BE); - else - fatal(0, "unsupported sample_format for oss backend"); - if(ioctl(oss_fd, SNDCTL_DSP_SETFMT, &format) < 0) - fatal(errno, "error calling ioctl SNDCTL_DSP_SETFMT %#x", format); - rate = config->sample_format.rate; - if(ioctl(oss_fd, SNDCTL_DSP_SPEED, &rate) < 0) - fatal(errno, "error calling ioctl SNDCTL_DSP_SPEED %d", rate); - if((unsigned)rate != config->sample_format.rate) - error(0, "asked for %luHz, got %dHz", - (unsigned long)config->sample_format.rate, rate); - if(ioctl(oss_fd, SNDCTL_DSP_GETBLKSIZE, &oss_bufsize) < 0) { - error(errno, "ioctl SNDCTL_DSP_GETBLKSIZE"); - oss_bufsize = 2048; /* guess */ - } + /* 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); #endif - oss_activated = 1; - pthread_cond_signal(&oss_cond); - while(!oss_going) - pthread_cond_wait(&oss_cond, &oss_lock); - } - pthread_mutex_unlock(&oss_lock); } -static void oss_deactivate(void) { - pthread_mutex_lock(&oss_lock); - if(oss_activated) { - oss_activated = 0; - pthread_cond_signal(&oss_cond); - while(oss_going) - pthread_cond_wait(&oss_cond, &oss_lock); - close(oss_fd); - oss_fd = -1; - } - pthread_mutex_unlock(&oss_lock); +static void oss_stop(void) { + uaudio_thread_stop(); } const struct uaudio uaudio_oss = {