summaryrefslogtreecommitdiffstats
path: root/oss.c
diff options
context:
space:
mode:
Diffstat (limited to 'oss.c')
-rw-r--r--oss.c181
1 files changed, 130 insertions, 51 deletions
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<<l)-1)/(1<<l);
if (l < 1) l = 1;
+ m = (bs+(1<<l)-1)/(1<<l);
if (m < 2) m = 2;
if (m > 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;