summaryrefslogtreecommitdiffstats
path: root/src/oss.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/oss.c')
-rw-r--r--src/oss.c201
1 files changed, 104 insertions, 97 deletions
diff --git a/src/oss.c b/src/oss.c
index d09f8aa..3ad1a9d 100644
--- a/src/oss.c
+++ b/src/oss.c
@@ -1,3 +1,7 @@
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
#include <signal.h>
#include <string.h>
#include <unistd.h>
@@ -31,7 +35,7 @@ struct oss_stream {
sa_converter_t converter_read, converter_write;
size_t read_fragment_size, write_fragment_size;
unsigned read_nfragments, write_nfragments;
- sa_thread_t *thread;
+ sa_thread *thread;
int socket_fds[2];
sa_bufferq_t bufferq;
};
@@ -47,6 +51,9 @@ static int simple_log2(int v) {
return k;
}
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
static size_t fixup_bps(size_t s, size_t bps1, size_t bps2) {
return (s*bps2)/bps1;
@@ -54,12 +61,12 @@ static size_t fixup_bps(size_t s, size_t bps1, size_t bps2) {
int driver_open(sa_stream_t *s) {
oss_stream_t *oss;
- char *n;
+ const char *n;
int f, arg, bs, r, phase, i, found, suggested, fs, l, m;
unsigned c;
size_t real_bps = 0, bps;
int loops = 0;
-
+
static const int format_map[_SA_PCM_FORMAT_MAX] = {
[SA_PCM_FORMAT_U8] = AFMT_U8,
[SA_PCM_FORMAT_ULAW] = AFMT_MU_LAW,
@@ -98,23 +105,23 @@ int driver_open(sa_stream_t *s) {
* device again. */
if ((oss->fd = open(n, s->mode == SA_MODE_RDONLY ? O_RDONLY : (s->mode == SA_MODE_WRONLY ? O_WRONLY : O_RDWR) | O_NOCTTY | O_NONBLOCK)) < 0) {
-
+
if (errno == ENODEV || errno == ENOENT)
r = SA_ERROR_NO_DEVICE;
else
r = SA_ERROR_SYSTEM;
-
+
goto fail;
}
-
+
fcntl(oss->fd, F_SETFL, fcntl(oss->fd, F_GETFL) & ~O_NONBLOCK); /* FIXME*/
-
+
if (!s->device) {
if (!(n = sa_strdup(n))) {
r = SA_ERROR_OOM;
goto fail;
}
-
+
s->device = n;
}
@@ -122,12 +129,12 @@ int driver_open(sa_stream_t *s) {
if (s->mode & SA_MODE_WRONLY) {
bs = s->write_lower_watermark;
}
-
+
if (s->mode & SA_MODE_RDONLY) {
int rbs;
-
+
rbs = s->read_upper_watermark;
-
+
if (s->mode & SA_MODE_WRONLY)
bs = bs > rbs ? bs : rbs;
else
@@ -145,14 +152,14 @@ int driver_open(sa_stream_t *s) {
if (m > 0x7FFF) m = 0x7FFF;
printf("Asking OSS for: %u fragments, %u fragsize\n", m, 1 << l);
-
+
arg = (m << 16) | l;
-
+
ioctl(oss->fd, SNDCTL_DSP_SETFRAGMENT, &arg);
/* We ignore errors on this call, since it's merely a hint anyway */
-
+
if (s->codec) {
-
+
if (strcmp(s->codec, SA_CODEC_AC3) == 0)
f = AFMT_AC3;
else if (strcmp(s->codec, SA_CODEC_MPEG) == 0)
@@ -161,27 +168,27 @@ int driver_open(sa_stream_t *s) {
r = SA_ERROR_NO_CODEC;
goto fail;
}
-
+
} else
f = format_map[s->pcm_attrs.format];
-
+
bs = 0;
-
+
for (;;) {
arg = f;
-
+
if (ioctl(oss->fd, SNDCTL_DSP_SETFMT, &arg) < 0) {
r = SA_ERROR_SYSTEM;
goto fail;
}
-
+
if (arg == f)
break;
-
+
/* Hmm, the device doesn't support what we're looking for,
* let's try our luck */
-
- if (f == AFMT_S16_LE && !bs) {
+
+ if (f == AFMT_S16_LE && !bs) {
f = AFMT_S16_BE;
bs = 1;
} else if (f == AFMT_S16_BE && !bs) {
@@ -206,39 +213,39 @@ int driver_open(sa_stream_t *s) {
goto fail;
}
}
-
+
if (!s->codec) {
-
+
switch (f) {
case AFMT_MU_LAW:
oss->real_pcm_attrs.format = SA_PCM_FORMAT_ULAW;
break;
-
+
case AFMT_A_LAW:
oss->real_pcm_attrs.format = SA_PCM_FORMAT_ALAW;
break;
-
+
case AFMT_U8:
oss->real_pcm_attrs.format = SA_PCM_FORMAT_U8;
break;
-
+
case AFMT_S16_LE:
oss->real_pcm_attrs.format = SA_PCM_FORMAT_S16_LE;
break;
-
+
case AFMT_S16_BE:
oss->real_pcm_attrs.format = SA_PCM_FORMAT_S16_BE;
break;
-
+
default:
sa_assert_not_reached();
}
-
-
+
+
found = 0;
-
+
if (s->adjust_nchannels >= 0) {
-
+
/* First try more channels ... */
for (c = s->pcm_attrs.nchannels; c < 8 || c == s->pcm_attrs.nchannels; c ++) {
arg = c;
@@ -246,13 +253,13 @@ int driver_open(sa_stream_t *s) {
r = SA_ERROR_SYSTEM;
goto fail;
}
-
+
if (arg == (int) c) {
found = 1;
break;
}
}
-
+
/* ... then try less channels */
if (!found) {
for (c = s->pcm_attrs.nchannels - 1; c > 0; c --) {
@@ -261,7 +268,7 @@ int driver_open(sa_stream_t *s) {
r = SA_ERROR_SYSTEM;
goto fail;
}
-
+
if (arg == (int) c) {
found = 1;
break;
@@ -269,7 +276,7 @@ int driver_open(sa_stream_t *s) {
}
}
} else {
-
+
/* First try less channels ... */
for (c = s->pcm_attrs.nchannels; c > 0; c --) {
arg = c;
@@ -277,13 +284,13 @@ int driver_open(sa_stream_t *s) {
r = SA_ERROR_SYSTEM;
goto fail;
}
-
+
if (arg == (int) c) {
found = 1;
break;
}
}
-
+
/* ... then try more channels */
if (!found) {
for (c = s->pcm_attrs.nchannels + 1; c < 8; c ++) {
@@ -292,28 +299,28 @@ int driver_open(sa_stream_t *s) {
r = SA_ERROR_SYSTEM;
goto fail;
}
-
+
if (arg == (int) c) {
found = 1;
break;
}
}
- }
+ }
}
-
+
if (!found) {
errno = EIO;
r = SA_ERROR_SYSTEM;
goto fail;
}
-
+
oss->real_pcm_attrs.nchannels = c;
-
+
if (!(oss->real_pcm_attrs.channel_map = sa_new(sa_channel_t, c))) {
r = SA_ERROR_OOM;
goto fail;
}
-
+
switch (c) {
case 8:
oss->real_pcm_attrs.channel_map[7] = SA_CHANNEL_REAR_RIGHT;
@@ -335,25 +342,25 @@ int driver_open(sa_stream_t *s) {
oss->real_pcm_attrs.channel_map[0] = SA_CHANNEL_MONO;
break;
}
-
+
r = s->pcm_attrs.rate;
-
+
if (r < 8000)
r = 8000;
-
+
suggested = 0;
phase = 0;
-
+
for (;;) {
arg = r;
-
+
if (ioctl(oss->fd, SNDCTL_DSP_SPEED, &arg) < 0) {
r = SA_ERROR_SYSTEM;
goto fail;
}
sa_assert(arg > 0);
-
+
if (arg >= r*0.95 || arg <= r *1.05)
break;
@@ -361,20 +368,20 @@ int driver_open(sa_stream_t *s) {
suggested = arg;
if (s->adjust_rate >= 0) {
-
+
if (phase == 0) {
/* Find the next higher sample rate to try */
-
+
for (i = 0; i < (int) SA_ELEMENTSOF(try_rates); i++) {
/* Yes, we could optimize a little here */
-
+
if (try_rates[i] > r) {
r = try_rates[i];
- break;
+ break;
}
}
-
-
+
+
if (i == SA_ELEMENTSOF(try_rates)) {
phase = 1;
r = s->pcm_attrs.rate;
@@ -393,23 +400,23 @@ int driver_open(sa_stream_t *s) {
break;
}
}
-
+
sa_assert(i > 0);
}
-
+
} else {
if (phase == 0) {
/* Find the next lower sample rate to try */
for (i = SA_ELEMENTSOF(try_rates); i > 0; i--) {
-
+
if (try_rates[i-1] < r) {
r = try_rates[i-1];
- break;
+ break;
}
}
-
+
if (i == 0) {
phase = 1;
r = s->pcm_attrs.rate;
@@ -428,7 +435,7 @@ int driver_open(sa_stream_t *s) {
break;
}
}
-
+
sa_assert(i < (int) SA_ELEMENTSOF(try_rates));
}
}
@@ -463,38 +470,38 @@ int driver_open(sa_stream_t *s) {
oss->read_fragment_size = arg;
oss->read_nfragments = 2;
}
-
+
if (s->mode & SA_MODE_WRONLY) {
oss->write_fragment_size = arg;
oss->write_nfragments = 2;
}
}
-
+
/* Now, let's use GETxSPACE */
if (s->mode & SA_MODE_RDONLY) {
audio_buf_info info;
-
+
if (ioctl(oss->fd, SNDCTL_DSP_GETISPACE, &info) >= 0) {
oss->read_fragment_size = info.fragsize;
oss->read_nfragments = info.fragstotal;
}
}
-
+
if (s->mode & SA_MODE_WRONLY) {
audio_buf_info info;
-
+
if (ioctl(oss->fd, SNDCTL_DSP_GETOSPACE, &info) >= 0) {
oss->write_fragment_size = info.fragsize;
oss->write_nfragments = info.fragstotal;
}
}
-
+
if (s->mode & SA_MODE_WRONLY && (oss->write_fragment_size <= 0 || oss->write_nfragments <= 1)) {
errno = EIO;
r = SA_ERROR_SYSTEM;
goto fail;
}
-
+
if (s->mode & SA_MODE_RDONLY && (oss->read_fragment_size <= 0 || oss->read_nfragments <= 1)) {
errno = EIO;
r = SA_ERROR_SYSTEM;
@@ -502,7 +509,7 @@ int driver_open(sa_stream_t *s) {
}
if (!s->codec) {
-
+
if (s->adjust_nchannels != 0) {
sa_channel_t *cm;
@@ -524,7 +531,7 @@ int driver_open(sa_stream_t *s) {
if (s->mode & SA_MODE_RDONLY)
if ((r = sa_converter_init(&oss->converter_read, &oss->real_pcm_attrs, &s->pcm_attrs, s->dynamic_rate_enabled)) < 0)
goto fail;
-
+
if (s->mode & SA_MODE_WRONLY)
if ((r = sa_converter_init(&oss->converter_write, &s->pcm_attrs, &oss->real_pcm_attrs, s->dynamic_rate_enabled)) < 0)
goto fail;
@@ -542,7 +549,7 @@ int driver_open(sa_stream_t *s) {
s->write_upper_watermark = oss->write_fragment_size * oss->write_nfragments;
}
}
-
+
if (s->mode & SA_MODE_RDONLY)
printf("Chosen for read: %u fragments, %u fragsize\n", oss->read_nfragments, oss->read_fragment_size);
@@ -551,7 +558,7 @@ int driver_open(sa_stream_t *s) {
if (sa_bufferq_init(&oss->bufferq, s->pcm_attrs.nchannels, s->pcm_sample_size) < 0)
goto fail;
-
+
return SA_SUCCESS;
fail:
@@ -566,19 +573,19 @@ int driver_destroy(sa_stream_t *s) {
if (oss->thread)
driver_stop_thread(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);
sa_free(oss);
}
-
+
return SA_SUCCESS;
}
@@ -586,7 +593,7 @@ static int feed(sa_stream_t *s) {
oss_stream_t *oss = OSS_STREAM(s);
size_t w;
int ret;
-
+
sa_assert(s);
for (;;) {
@@ -612,10 +619,10 @@ static int feed(sa_stream_t *s) {
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;
@@ -627,17 +634,17 @@ static int feed(sa_stream_t *s) {
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);
}
@@ -667,15 +674,15 @@ static void thread_func(void *data) {
if (s->callback(s, SA_EVENT_INIT_THREAD) < 0)
return;
}
-
+
memset(pollfds, 0, sizeof(pollfds));
pollfds[POLLFD_SOCKET_FD].fd = oss->socket_fds[0];
pollfds[POLLFD_SOCKET_FD].events = POLLIN;
-
+
pollfds[POLLFD_OSS_FD].fd = oss->fd;
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) {
@@ -732,7 +739,7 @@ int driver_start_thread(sa_stream_t *s, sa_event_callback_t callback) {
if (!(oss->thread = sa_thread_new(thread_func, s)))
return SA_ERROR_OOM;
-
+
return SA_SUCCESS;
}
@@ -743,13 +750,13 @@ int driver_stop_thread(sa_stream_t *s) {
if (oss->socket_fds[0] >= 0)
close(oss->socket_fds[0]);
-
+
if (oss->socket_fds[1] >= 0)
close(oss->socket_fds[1]);
-
+
if (oss->thread)
sa_thread_free(oss->thread);
-
+
oss->thread = NULL;
oss->socket_fds[0] = oss->socket_fds[1] = -1;
@@ -762,7 +769,7 @@ int driver_change_read_volume(sa_stream_t *s, const int32_t vol[]) {
sa_return_val_if_fail(!s->codec, SA_ERROR_NOT_SUPPORTED);
sa_converter_set_volume(&oss->converter_read, vol);
-
+
return SA_SUCCESS;
}
@@ -772,7 +779,7 @@ int driver_change_write_volume(sa_stream_t *s, const int32_t vol[]) {
sa_return_val_if_fail(!s->codec, SA_ERROR_NOT_SUPPORTED);
sa_converter_set_volume(&oss->converter_write, vol);
-
+
return SA_SUCCESS;
}
@@ -806,7 +813,7 @@ int driver_pwrite(sa_stream_t *s, const void *data, size_t nbytes, int64_t offse
if ((ret = sa_bufferq_push(&oss->bufferq, 0, data, nbytes, offset, whence, SA_BUFFERQ_ITEM_STATIC)))
return ret;
-
+
ret = feed(s);
ret2 = sa_bufferq_realloc(&oss->bufferq);
@@ -843,7 +850,7 @@ int driver_drain(sa_stream_t *s) {
if (ioctl(oss->fd, SNDCTL_DSP_SYNC, NULL) < 0)
return SA_ERROR_SYSTEM;
-
+
return SA_SUCCESS;
}