summaryrefslogtreecommitdiffstats
path: root/oss.c
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2007-10-01 20:16:28 +0000
committerLennart Poettering <lennart@poettering.net>2007-10-01 20:16:28 +0000
commit7d83e5c7816b5e343695a75ba58b32dbe1be969a (patch)
treebfd1dfc9b7c8f4a2aaf66c1b30e78355dee8c88a /oss.c
parent762196328ab7e60f1d2908fd5a337d2ca99726dd (diff)
move all sources down to a seperate src/ tree
git-svn-id: file:///home/lennart/svn/public/libsydney/trunk@34 9ba3c220-e4d3-45a2-8aa3-73fcc9aff6ce
Diffstat (limited to 'oss.c')
-rw-r--r--oss.c858
1 files changed, 0 insertions, 858 deletions
diff --git a/oss.c b/oss.c
deleted file mode 100644
index d09f8aa..0000000
--- a/oss.c
+++ /dev/null
@@ -1,858 +0,0 @@
-#include <signal.h>
-#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <sys/ioctl.h>
-#include <sys/soundcard.h>
-#include <poll.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-
-#include "sydney.h"
-#include "common.h"
-#include "macro.h"
-#include "malloc.h"
-#include "converter.h"
-#include "driver.h"
-#include "thread.h"
-#include "bufferq.h"
-
-#define DEFAULT_DEVICE "/dev/dsp"
-#define DRIVER_NAME "oss"
-
-typedef struct oss_stream oss_stream_t;
-#define OSS_STREAM(x) ((oss_stream_t*) (x->private))
-
-struct oss_stream {
- sa_stream_t *parent;
- int fd;
- pcm_attrs_t real_pcm_attrs;
- sa_converter_t converter_read, converter_write;
- size_t read_fragment_size, write_fragment_size;
- unsigned read_nfragments, write_nfragments;
- sa_thread_t *thread;
- int socket_fds[2];
- sa_bufferq_t bufferq;
-};
-
-static int simple_log2(int v) {
- int k = 0;
-
- for (;;) {
- v >>= 1;
- if (!v) break;
- k++;
- }
-
- return k;
-}
-
-static size_t fixup_bps(size_t s, size_t bps1, size_t bps2) {
- return (s*bps2)/bps1;
-}
-
-int driver_open(sa_stream_t *s) {
- oss_stream_t *oss;
- 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,
- [SA_PCM_FORMAT_ALAW] = AFMT_A_LAW,
- [SA_PCM_FORMAT_S16_LE] = AFMT_S16_LE,
- [SA_PCM_FORMAT_S16_BE] = AFMT_S16_BE,
- [SA_PCM_FORMAT_S24_LE] = AFMT_S16_NE, /* OSS doesn't know this format, hence we pick the best we can */
- [SA_PCM_FORMAT_S24_BE] = AFMT_S16_NE,
- [SA_PCM_FORMAT_S32_LE] = AFMT_S16_NE,
- [SA_PCM_FORMAT_S32_BE] = AFMT_S16_NE,
- [SA_PCM_FORMAT_FLOAT32_LE] = AFMT_S16_NE,
- [SA_PCM_FORMAT_FLOAT32_BE] = AFMT_S16_NE
- };
- static const int try_rates[] = { 8000, 16000, 32000, 44100, 48000, 96000, 192000 };
-
- if (s->driver && strcmp(s->driver, DRIVER_NAME))
- return SA_ERROR_NO_DRIVER;
-
- if (!(s->private = oss = sa_new0(oss_stream_t, 1)))
- return SA_ERROR_OOM;
-
- oss->parent = s;
- oss->socket_fds[0] = oss->socket_fds[1] = -1;
-
- n = s->device ? s->device : DEFAULT_DEVICE;
- if (!s->codec)
- bps = s->pcm_frame_size * s->pcm_attrs.rate;
-
- for (;;) {
- /* We need to loop here, because we have to call SETFRAGMENT
- * as first ioctl after the open, at a point where we
- * don't now yet the sample type, freq and the number of
- * channels we actually settled on. Hence we have to loop
- * here: if the sampling format is too far off we have to call
- * SETFRAGMENT again which can do only after reopening the
- * 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;
- }
-
- /* Set fragment settings */
- 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
- bs = rbs;
- }
-
- if (!s->codec && real_bps)
- bs = fixup_bps(bs, bps, real_bps);
-
- fs = bs/4;
- l = simple_log2(fs);
- if (l < 1) l = 1;
- m = (bs+(1<<l)-1)/(1<<l);
- if (m < 2) m = 2;
- 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)
- f = AFMT_MPEG;
- else {
- 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) {
- f = AFMT_S16_BE;
- bs = 1;
- } else if (f == AFMT_S16_BE && !bs) {
- f = AFMT_S16_LE;
- bs = 1;
- } else if (f == AFMT_S16_LE || f == AFMT_S16_BE) {
- f = AFMT_MU_LAW;
- bs = 0;
- } else if (f == AFMT_MU_LAW && !bs) {
- f = AFMT_A_LAW;
- bs = 1;
- } else if (f == AFMT_A_LAW && !bs) {
- f = AFMT_MU_LAW;
- bs = 1;
- } else if (f == AFMT_A_LAW || f == AFMT_MU_LAW) {
- f = AFMT_U8;
- } else if (f == AFMT_AC3 || f == AFMT_MPEG) {
- r = SA_ERROR_NO_CODEC;
- goto fail;
- } else {
- r = SA_ERROR_NO_PCM_FORMAT;
- 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;
- if (ioctl(oss->fd, SNDCTL_DSP_CHANNELS, &arg) < 0) {
- 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 --) {
- arg = c;
- if (ioctl(oss->fd, SNDCTL_DSP_CHANNELS, &arg) < 0) {
- r = SA_ERROR_SYSTEM;
- goto fail;
- }
-
- if (arg == (int) c) {
- found = 1;
- break;
- }
- }
- }
- } else {
-
- /* First try less channels ... */
- for (c = s->pcm_attrs.nchannels; c > 0; c --) {
- arg = c;
- if (ioctl(oss->fd, SNDCTL_DSP_CHANNELS, &arg) < 0) {
- 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 ++) {
- arg = c;
- if (ioctl(oss->fd, SNDCTL_DSP_CHANNELS, &arg) < 0) {
- 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;
- case 7:
- oss->real_pcm_attrs.channel_map[6] = SA_CHANNEL_REAR_LEFT;
- case 6:
- oss->real_pcm_attrs.channel_map[5] = SA_CHANNEL_FRONT_LEFT;
- case 5:
- oss->real_pcm_attrs.channel_map[4] = SA_CHANNEL_FRONT_RIGHT;
- case 4:
- oss->real_pcm_attrs.channel_map[3] = SA_CHANNEL_LFE;
- case 3:
- oss->real_pcm_attrs.channel_map[2] = SA_CHANNEL_CENTER;
- case 2:
- oss->real_pcm_attrs.channel_map[1] = SA_CHANNEL_RIGHT;
- oss->real_pcm_attrs.channel_map[0] = SA_CHANNEL_LEFT;
- break;
- case 1:
- 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;
-
- if (arg > suggested)
- 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;
- }
- }
-
-
- if (i == SA_ELEMENTSOF(try_rates)) {
- phase = 1;
- r = s->pcm_attrs.rate;
- }
- }
-
- if (phase == 1) {
- /* Find the next lower sample rate to try */
-
- for (i = SA_ELEMENTSOF(try_rates); i > 0; i--) {
- if (suggested > try_rates[i-1] && suggested < r) {
- r = suggested;
- break;
- } else if (try_rates[i-1] < r) {
- r = try_rates[i-1];
- 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;
- }
- }
-
- if (i == 0) {
- phase = 1;
- r = s->pcm_attrs.rate;
- }
- }
-
- if (phase == 1) {
- /* Find the next higher sample rate to try */
-
- for (i = 0; i < (int) SA_ELEMENTSOF(try_rates); i++) {
- if (suggested > r && suggested < try_rates[i]) {
- r = suggested;
- break;
- } else if (try_rates[i] < r) {
- r = try_rates[i];
- break;
- }
- }
-
- sa_assert(i < (int) SA_ELEMENTSOF(try_rates));
- }
- }
-
- }
-
- oss->real_pcm_attrs.rate = r;
-
- printf("Chosen: %u channels, %uHz, format=%u\n", oss->real_pcm_attrs.nchannels, oss->real_pcm_attrs.rate, oss->real_pcm_attrs.format);
-
- real_bps = oss->real_pcm_attrs.nchannels * oss->real_pcm_attrs.rate * sa_get_pcm_sample_size(oss->real_pcm_attrs.format);
-
- if (real_bps != bps && loops < 1) {
- loops++;
-
- sa_free(oss->real_pcm_attrs.channel_map);
- oss->real_pcm_attrs.channel_map = NULL;
-
- close(oss->fd);
-
- printf("bps changed, retrying...\n");
- continue;
- }
- }
-
- break;
- }
-
- /* First, let's try GETBLKSIZE */
- if (ioctl(oss->fd, SNDCTL_DSP_GETBLKSIZE, &arg) >= 0) {
- if (s->mode & SA_MODE_RDONLY) {
- 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;
- goto fail;
- }
-
- if (!s->codec) {
-
- if (s->adjust_nchannels != 0) {
- sa_channel_t *cm;
-
- if (!(cm = sa_newdup(sa_channel_t, oss->real_pcm_attrs.channel_map, oss->real_pcm_attrs.nchannels))) {
- r = SA_ERROR_OOM;
- goto fail;
- }
-
- sa_free(s->pcm_attrs.channel_map);
- s->pcm_attrs.channel_map = cm;
-
- s->pcm_attrs.nchannels = oss->real_pcm_attrs.nchannels;
- }
- if (s->adjust_rate != 0)
- s->pcm_attrs.rate = oss->real_pcm_attrs.rate;
- if (s->adjust_pcm_format != 0)
- s->pcm_attrs.format = oss->real_pcm_attrs.format;
-
- 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;
- }
-
- if (s->adjust_watermarks) {
-
- if (s->mode & SA_MODE_RDONLY) {
- s->read_lower_watermark = oss->read_fragment_size;
- s->read_upper_watermark = oss->read_fragment_size * oss->read_nfragments;
- }
-
- if (s->mode & SA_MODE_WRONLY) {
- s->write_lower_watermark = oss->write_fragment_size;
- 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);
-
- 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;
-
-fail:
- driver_destroy(s);
- return r;
-}
-
-int driver_destroy(sa_stream_t *s) {
- oss_stream_t *oss = OSS_STREAM(s);
-
- if (oss) {
-
- 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;
-}
-
-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,
- POLLFD_MAX
-};
-
-static void thread_func(void *data) {
- struct pollfd pollfds[POLLFD_MAX];
- sa_stream_t *s = data;
- oss_stream_t *oss = OSS_STREAM(s);
- sigset_t mask;
-
- sigfillset(&mask);
- pthread_sigmask(SIG_BLOCK, &mask, NULL);
-
- if (s->callback) {
- s->event = SA_EVENT_INIT_THREAD;
- 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) {
- 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)) {
-
- if (s->callback) {
- s->event = SA_EVENT_ERROR;
- s->error = SA_ERROR_SYSTEM;
- errno = EIO;
- s->callback(s, SA_EVENT_ERROR);
- }
- break;
- }
-
- 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;
- }
- }
-}
-
-int driver_start_thread(sa_stream_t *s, sa_event_callback_t callback) {
- oss_stream_t *oss = OSS_STREAM(s);
- sa_return_val_if_fail(!oss->thread, SA_ERROR_STATE);
-
- s->callback = callback;
-
- if ((socketpair(AF_UNIX, SOCK_DGRAM, 0, oss->socket_fds)) < 0)
- return SA_ERROR_SYSTEM;
-
- if (!(oss->thread = sa_thread_new(thread_func, s)))
- return SA_ERROR_OOM;
-
- return SA_SUCCESS;
-}
-
-int driver_stop_thread(sa_stream_t *s) {
- oss_stream_t *oss = OSS_STREAM(s);
- sa_return_val_if_fail(oss->thread, SA_ERROR_STATE);
- sa_return_val_if_fail(oss->thread != sa_thread_self(), SA_ERROR_STATE);
-
- 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;
-
- return SA_SUCCESS;
-}
-
-int driver_change_read_volume(sa_stream_t *s, const int32_t vol[]) {
- oss_stream_t *oss = OSS_STREAM(s);
-
- sa_return_val_if_fail(!s->codec, SA_ERROR_NOT_SUPPORTED);
-
- sa_converter_set_volume(&oss->converter_read, vol);
-
- return SA_SUCCESS;
-}
-
-int driver_change_write_volume(sa_stream_t *s, const int32_t vol[]) {
- oss_stream_t *oss = OSS_STREAM(s);
-
- sa_return_val_if_fail(!s->codec, SA_ERROR_NOT_SUPPORTED);
-
- sa_converter_set_volume(&oss->converter_write, vol);
-
- return SA_SUCCESS;
-}
-
-int driver_change_rate(sa_stream_t *s, unsigned rate) {
- oss_stream_t *oss = OSS_STREAM(s);
-
- if (s->mode & SA_MODE_RDONLY)
- sa_converter_set_ratio(&oss->converter_read, oss->real_pcm_attrs.rate, s->pcm_attrs.rate);
- if (s->mode & SA_MODE_WRONLY)
- sa_converter_set_ratio(&oss->converter_write, s->pcm_attrs.rate, oss->real_pcm_attrs.rate);
-
- return SA_SUCCESS;
-}
-
-int driver_get_state(sa_stream_t *s, sa_state_t *state) {
- *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_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);
- int ret, ret2;
-
- 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);
-
- return ret ? ret : ret2;
-}
-
-int driver_read_ni(sa_stream_t *s, unsigned channel, void *data, size_t nbytes) {
- return SA_ERROR_NOT_SUPPORTED;
-}
-
-int driver_pwrite_ni(sa_stream_t *s, unsigned channel, const void *data, size_t nbytes, int64_t offset, sa_seek_t whence) {
- return SA_ERROR_NOT_SUPPORTED;
-}
-
-int driver_get_read_size(sa_stream_t *s, size_t *size) {
- return SA_ERROR_NOT_SUPPORTED;
-}
-
-int driver_get_write_size(sa_stream_t *s, size_t *size) {
- return SA_ERROR_NOT_SUPPORTED;
-}
-
-int driver_resume(sa_stream_t *s) {
- return SA_ERROR_NOT_SUPPORTED;
-}
-
-int driver_pause(sa_stream_t *s) {
- return SA_ERROR_NOT_SUPPORTED;
-}
-
-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;
-
- return SA_SUCCESS;
-}
-
-/* Unsupported operations */
-
-int driver_change_device(sa_stream_t *s, const char *device) {
- return SA_ERROR_NOT_SUPPORTED;
-}
-
-int driver_change_meta_data(sa_stream_t *s, const char *name, const void *data, size_t size) {
- return SA_ERROR_NOT_SUPPORTED;
-}