$OpenBSD: patch-libogleao_obsd_audio_c,v 1.3 2009/12/09 10:19:33 jakemsr Exp $ --- libogleao/obsd_audio.c.orig Sat Feb 22 07:06:51 2003 +++ libogleao/obsd_audio.c Wed Oct 28 11:48:59 2009 @@ -18,45 +18,54 @@ #ifdef LIBOGLEAO_OBSD +#include +#include +#include #include #include -#include +#include #include -#include -#include -#include - -#include -#include - -#include - #include "ogle_ao.h" #include "ogle_ao_private.h" typedef struct obsd_instance_s { ogle_ao_instance_t ao; - int fd; + struct sio_hdl *hdl; int sample_rate; int samples_written; + int samples_played; int sample_frame_size; int initialized; + int started; } obsd_instance_t; +static +void obsd_onmove(void *addr, int delta) +{ + obsd_instance_t *instance = (obsd_instance_t *)addr; + instance->samples_played += delta; +} static int obsd_init(ogle_ao_instance_t *_instance, ogle_ao_audio_info_t *audio_info) { - int single_sample_size; - audio_info_t info; obsd_instance_t *instance = (obsd_instance_t *)_instance; - - AUDIO_INITINFO(&info); - info.play.sample_rate = audio_info->sample_rate; - info.play.precision = audio_info->sample_resolution; + struct sio_par par, askpar; + int single_sample_size; + int reinit; + reinit = 0; + if (instance->started == 1) { + reinit = 1; + if (!sio_stop(instance->hdl)) { + fprintf(stderr, "sio_stop failed\n"); + return -1; + } + instance->started = 0; + } + if(audio_info->chtypes != OGLE_AO_CHTYPE_UNSPECIFIED) { // do this only if we have requested specific channels in chtypes // otherwise trust the nr channels @@ -69,40 +78,57 @@ int obsd_init(ogle_ao_instance_t *_instance, } audio_info->chlist = NULL; - info.play.channels = audio_info->channels; - info.lowat = 5; - switch(audio_info->encoding) { - case OGLE_AO_ENCODING_LINEAR: - default: - info.play.encoding = AUDIO_ENCODING_LINEAR; - break; + sio_initpar(&par); + + par.bits = audio_info->sample_resolution; + par.sig = 1; + par.le = 1; + par.pchan = audio_info->channels; + par.rate = audio_info->sample_rate; + par.appbufsz = par.rate / 4; + + askpar = par; + + if (!sio_setpar(instance->hdl, &par)) { + fprintf(stderr, "sio_setpar failed\n"); + return -1; } - - /* set the audio format */ - if(ioctl(instance->fd, AUDIO_SETINFO, &info) == -1) { - perror("setinfo"); + if (!sio_getpar(instance->hdl, &par)) { + fprintf(stderr, "sio_getpar failed\n"); return -1; } - - /* Check that we actually got the requested nuber of channles, - * the frequency and precision that we asked for? */ + if (par.pchan != askpar.pchan || + par.bits != askpar.bits || + (par.rate * 100 > askpar.rate * 105 || par.rate * 100 < askpar.rate * 95)) { + fprintf(stderr, "could not configure audio device as desired\n"); + return -1; + } if(audio_info->chtypes != OGLE_AO_CHTYPE_UNSPECIFIED) { - audio_info->chlist = malloc(info.play.channels * sizeof(ogle_ao_chtype_t)); + audio_info->chlist = malloc(par.pchan * sizeof(ogle_ao_chtype_t)); audio_info->chlist[0] = OGLE_AO_CHTYPE_LEFT; audio_info->chlist[1] = OGLE_AO_CHTYPE_RIGHT; } - /* Stored as 8bit, 16bit, or 32bit */ - single_sample_size = (info.play.precision + 7) / 8; - if(single_sample_size > 2) { - single_sample_size = 4; + single_sample_size = par.bps; + instance->sample_frame_size = single_sample_size * par.pchan; + instance->sample_rate = par.rate; + + if (!reinit) + sio_onmove(instance->hdl, obsd_onmove, instance); + instance->samples_played = 0; + instance->samples_written = 0; + + if (!sio_start(instance->hdl)) { + fprintf(stderr, "sio_start failed\n"); + return -1; } - instance->sample_frame_size = single_sample_size*info.play.channels; + instance->started = 1; + + audio_info->sample_frame_size = instance->sample_frame_size; instance->initialized = 1; - audio_info->sample_frame_size = instance->sample_frame_size; return 0; } @@ -112,9 +138,9 @@ int obsd_play(ogle_ao_instance_t *_instance, void *sam obsd_instance_t *instance = (obsd_instance_t *)_instance; int written; - written = write(instance->fd, samples, nbyte); - if(written == -1) { - perror("audio write"); + written = sio_write(instance->hdl, samples, nbyte); + if(written != nbyte) { + fprintf(stderr, "sio_write failed\n"); return -1; } @@ -126,15 +152,20 @@ static int obsd_odelay(ogle_ao_instance_t *_instance, uint32_t *samples_return) { obsd_instance_t *instance = (obsd_instance_t *)_instance; - audio_info_t info; + struct pollfd pfd; + int revents, n; int odelay; - if (ioctl(instance->fd, AUDIO_GETINFO, &info) == -1) { - perror("AUDIO_GETINFO"); - return -1; - } + // update counters + n = sio_pollfd(instance->hdl, &pfd, POLLOUT); + while(poll(&pfd, n, 0) < 0 && errno == EINTR) + ; + revents = sio_revents(instance->hdl, &pfd); - odelay = info.play.seek / instance->sample_frame_size; + odelay = instance->samples_written - instance->samples_played; + + if (odelay < 0) + odelay = 0; *samples_return = odelay; return 0; @@ -145,31 +176,18 @@ void obsd_close(ogle_ao_instance_t *_instance) { obsd_instance_t *instance = (obsd_instance_t *)_instance; - close(instance->fd); + sio_close(instance->hdl); } static -int obsd_flush(ogle_ao_instance_t *_instance) +int obsd_drain(ogle_ao_instance_t *_instance) { - obsd_instance_t *instance = (obsd_instance_t *)_instance; - - fprintf(stderr, "AUDIO_FLUSH called\n"); - ioctl(instance->fd, AUDIO_FLUSH, NULL); - - instance->samples_written = 0; - - ioctl(instance->fd, AUDIO_DRAIN, 0); - return 0; } static -int obsd_drain(ogle_ao_instance_t *_instance) +int obsd_flush(ogle_ao_instance_t *_instance) { - obsd_instance_t *instance = (obsd_instance_t *)_instance; - - ioctl(instance->fd, AUDIO_DRAIN, 0); - return 0; } @@ -184,22 +202,28 @@ ogle_ao_instance_t *obsd_open(char *dev) instance->ao.init = obsd_init; instance->ao.play = obsd_play; - instance->ao.close = obsd_close; instance->ao.odelay = obsd_odelay; instance->ao.flush = obsd_flush; instance->ao.drain = obsd_drain; + instance->ao.close = obsd_close; instance->initialized = 0; instance->sample_rate = 0; instance->samples_written = 0; + instance->samples_played = 0; instance->sample_frame_size = 0; + + if(strncmp(dev, "ao_obsd_default", 15) == 0) + instance->hdl = sio_open(NULL, SIO_PLAY, 0); + else + instance->hdl = sio_open(dev, SIO_PLAY, 0); - instance->fd = open(dev, O_WRONLY); - if(instance->fd < 0) { + if(instance->hdl == NULL) { fprintf(stderr, "Can not open %s\n", dev); free(instance); return NULL; } + instance->started = 0; return (ogle_ao_instance_t *)instance; }