From c1b4872b0910c9aa784d878dca771b21c4690048 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 22 May 2007 22:53:09 +0000 Subject: lots of work git-svn-id: file:///home/lennart/svn/public/libsydney/trunk@30 9ba3c220-e4d3-45a2-8aa3-73fcc9aff6ce --- oss.c | 181 +++++++++++++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 130 insertions(+), 51 deletions(-) (limited to 'oss.c') diff --git a/oss.c b/oss.c index 3adce81..d09f8aa 100644 --- a/oss.c +++ b/oss.c @@ -16,6 +16,7 @@ #include "converter.h" #include "driver.h" #include "thread.h" +#include "bufferq.h" #define DEFAULT_DEVICE "/dev/dsp" #define DRIVER_NAME "oss" @@ -32,6 +33,7 @@ struct oss_stream { unsigned read_nfragments, write_nfragments; sa_thread_t *thread; int socket_fds[2]; + sa_bufferq_t bufferq; }; static int simple_log2(int v) { @@ -118,33 +120,27 @@ int driver_open(sa_stream_t *s) { /* Set fragment settings */ if (s->mode & SA_MODE_WRONLY) { - fs = s->write_upper_watermark - s->write_lower_watermark; - bs = s->write_upper_watermark; + bs = s->write_lower_watermark; } if (s->mode & SA_MODE_RDONLY) { - int rfs, rbs; + int rbs; - rfs = s->read_lower_watermark; rbs = s->read_upper_watermark; - if (s->mode & SA_MODE_WRONLY) { - fs = fs < rfs ? fs : rfs; + if (s->mode & SA_MODE_WRONLY) bs = bs > rbs ? bs : rbs; - } else { - fs = rfs; + else bs = rbs; - } } - if (!s->codec && real_bps) { + if (!s->codec && real_bps) bs = fixup_bps(bs, bps, real_bps); - fs = fixup_bps(fs, bps, real_bps); - } + fs = bs/4; l = simple_log2(fs); - m = (bs+(1< 0x7FFF) m = 0x7FFF; @@ -369,7 +365,7 @@ int driver_open(sa_stream_t *s) { if (phase == 0) { /* Find the next higher sample rate to try */ - for (i = 0; i < (int) elementsof(try_rates); i++) { + for (i = 0; i < (int) SA_ELEMENTSOF(try_rates); i++) { /* Yes, we could optimize a little here */ if (try_rates[i] > r) { @@ -379,7 +375,7 @@ int driver_open(sa_stream_t *s) { } - if (i == elementsof(try_rates)) { + if (i == SA_ELEMENTSOF(try_rates)) { phase = 1; r = s->pcm_attrs.rate; } @@ -388,7 +384,7 @@ int driver_open(sa_stream_t *s) { if (phase == 1) { /* Find the next lower sample rate to try */ - for (i = elementsof(try_rates); i > 0; i--) { + for (i = SA_ELEMENTSOF(try_rates); i > 0; i--) { if (suggested > try_rates[i-1] && suggested < r) { r = suggested; break; @@ -406,7 +402,7 @@ int driver_open(sa_stream_t *s) { if (phase == 0) { /* Find the next lower sample rate to try */ - for (i = elementsof(try_rates); i > 0; i--) { + for (i = SA_ELEMENTSOF(try_rates); i > 0; i--) { if (try_rates[i-1] < r) { r = try_rates[i-1]; @@ -423,7 +419,7 @@ int driver_open(sa_stream_t *s) { if (phase == 1) { /* Find the next higher sample rate to try */ - for (i = 0; i < (int) elementsof(try_rates); i++) { + for (i = 0; i < (int) SA_ELEMENTSOF(try_rates); i++) { if (suggested > r && suggested < try_rates[i]) { r = suggested; break; @@ -433,7 +429,7 @@ int driver_open(sa_stream_t *s) { } } - sa_assert(i < (int) elementsof(try_rates)); + sa_assert(i < (int) SA_ELEMENTSOF(try_rates)); } } @@ -552,6 +548,9 @@ int driver_open(sa_stream_t *s) { if (s->mode & SA_MODE_WRONLY) printf("Chosen for write: %u fragments, %u fragsize\n", oss->write_nfragments, oss->write_fragment_size); + + if (sa_bufferq_init(&oss->bufferq, s->pcm_attrs.nchannels, s->pcm_sample_size) < 0) + goto fail; return SA_SUCCESS; @@ -571,6 +570,8 @@ int driver_destroy(sa_stream_t *s) { if (oss->fd >= 0) close(oss->fd); + sa_bufferq_done(&oss->bufferq); + sa_free(oss->real_pcm_attrs.channel_map); sa_converter_done(&oss->converter_read); sa_converter_done(&oss->converter_write); @@ -581,6 +582,71 @@ int driver_destroy(sa_stream_t *s) { return SA_SUCCESS; } +static int feed(sa_stream_t *s) { + oss_stream_t *oss = OSS_STREAM(s); + size_t w; + int ret; + + sa_assert(s); + + for (;;) { + if ((ret = driver_get_write_size(s, &w)) < 0) + return ret; + + while (w > 0) { + void* i[1]; + size_t nbytes; + uint8_t *d; + int drop; + + sa_bufferq_get(&oss->bufferq, i, &nbytes); + + if (nbytes) { + void **dst; + size_t *stride; + + if ((ret = sa_converter_go_interleaved(&oss->converter_write, i[0], &dst, &stride, 1, &nbytes))) + return ret; + + d = dst[0]; + drop = 1; + + s->state = SA_STATE_RUNNING; + + } else { + nbytes = w > oss->write_fragment_size ? oss->write_fragment_size : w; + + if (!(d = sa_converter_get_zero_buffer(&oss->converter_write, nbytes))) + return SA_ERROR_OOM; + + drop = s->xrun_mode == SA_XRUN_MODE_SPIN; + + if (s->xrun_mode == SA_XRUN_MODE_STOP) + s->state = SA_STATE_STOPPED; + } + + while (nbytes > 0) { + ssize_t l; + + if ((l = write(oss->fd, d, nbytes)) < 0) + return SA_ERROR_SYSTEM; + + sa_assert(l > 0); + + nbytes -= l; + d += l; + + w -= 1; + + if (drop) + sa_bufferq_drop(&oss->bufferq, l); + } + } + } + + return SA_SUCCESS; +} + enum { POLLFD_OSS_FD, POLLFD_SOCKET_FD, @@ -595,10 +661,12 @@ static void thread_func(void *data) { sigfillset(&mask); pthread_sigmask(SIG_BLOCK, &mask, NULL); - - s->event = SA_EVENT_ERROR; - if (s->callback(s, SA_EVENT_INIT_THREAD) < 0) - return; + + if (s->callback) { + s->event = SA_EVENT_INIT_THREAD; + if (s->callback(s, SA_EVENT_INIT_THREAD) < 0) + return; + } memset(pollfds, 0, sizeof(pollfds)); @@ -609,24 +677,47 @@ static void thread_func(void *data) { pollfds[POLLFD_OSS_FD].events = ((s->mode & SA_MODE_RDONLY) ? POLLIN : 0) | ((s->mode & SA_MODE_WRONLY) ? POLLOUT : 0); for (;;) { + int ret; if (poll(pollfds, POLLFD_MAX, -1) < 0) { if (errno == EINTR) continue; + + if (s->callback) { + s->event = SA_EVENT_ERROR; + s->error = SA_ERROR_SYSTEM; + s->callback(s, SA_EVENT_ERROR); + } + break; } if (pollfds[POLLFD_SOCKET_FD].revents) break; if (pollfds[POLLFD_OSS_FD].revents & (POLLERR|POLLHUP|POLLNVAL)) { - s->event = SA_EVENT_ERROR; - s->error = SA_ERROR_SYSTEM; - errno = EIO; - s->callback(s, SA_EVENT_ERROR); + + if (s->callback) { + s->event = SA_EVENT_ERROR; + s->error = SA_ERROR_SYSTEM; + errno = EIO; + s->callback(s, SA_EVENT_ERROR); + } break; } - s->event = SA_EVENT_REQUEST_IO; - s->callback(s, SA_EVENT_REQUEST_IO); + if (s->callback) { + s->event = SA_EVENT_REQUEST_IO; + if (s->callback(s, SA_EVENT_REQUEST_IO) < 0) + break; + } + + if ((ret = feed(s)) < 0) { + if (s->callback) { + s->event = SA_EVENT_ERROR; + s->error = ret; + s->callback(s, SA_EVENT_ERROR); + } + break; + } } } @@ -697,45 +788,32 @@ int driver_change_rate(sa_stream_t *s, unsigned rate) { } int driver_get_state(sa_stream_t *s, sa_state_t *state) { - return SA_ERROR_NOT_SUPPORTED; + *state = s->state; + return SA_SUCCESS; } int driver_get_position(sa_stream_t *s, sa_position_t position, int64_t *pos) { return SA_ERROR_NOT_SUPPORTED; } -int driver_pread(sa_stream_t *s, void *data, size_t nbytes, int64_t offset, sa_seek_t whence) { +int driver_read(sa_stream_t *s, void *data, size_t nbytes) { return SA_ERROR_NOT_SUPPORTED; } int driver_pwrite(sa_stream_t *s, const void *data, size_t nbytes, int64_t offset, sa_seek_t whence) { oss_stream_t *oss = OSS_STREAM(s); - void **dst; - size_t *stride; - int ret; - uint8_t *d; + int ret, ret2; - if ((ret = sa_converter_go_interleaved(&oss->converter_write, data, &dst, &stride, 1, &nbytes))) + if ((ret = sa_bufferq_push(&oss->bufferq, 0, data, nbytes, offset, whence, SA_BUFFERQ_ITEM_STATIC))) return ret; - - d = dst[0]; - while (nbytes > 0) { - ssize_t l; - - if ((l = write(oss->fd, d, nbytes)) < 0) - return SA_ERROR_SYSTEM; - - sa_assert(l > 0); + ret = feed(s); + ret2 = sa_bufferq_realloc(&oss->bufferq); - nbytes -= l; - d += l; - } - - return SA_SUCCESS; + return ret ? ret : ret2; } -int driver_pread_ni(sa_stream_t *s, unsigned channel, void *data, size_t nbytes, int64_t offset, sa_seek_t whence) { +int driver_read_ni(sa_stream_t *s, unsigned channel, void *data, size_t nbytes) { return SA_ERROR_NOT_SUPPORTED; } @@ -761,6 +839,7 @@ int driver_pause(sa_stream_t *s) { int driver_drain(sa_stream_t *s) { oss_stream_t *oss = OSS_STREAM(s); + sa_return_val_if_fail(!oss->thread, SA_ERROR_STATE); if (ioctl(oss->fd, SNDCTL_DSP_SYNC, NULL) < 0) return SA_ERROR_SYSTEM; -- cgit