summaryrefslogtreecommitdiffstats
path: root/oss.c
diff options
context:
space:
mode:
Diffstat (limited to 'oss.c')
-rw-r--r--oss.c192
1 files changed, 125 insertions, 67 deletions
diff --git a/oss.c b/oss.c
index f39571c..7b351ae 100644
--- a/oss.c
+++ b/oss.c
@@ -9,46 +9,23 @@
#include "common.h"
#include "macro.h"
#include "malloc.h"
+#include "converter.h"
#define DEFAULT_DEVICE "/dev/dsp"
#define DRIVER_NAME "oss"
typedef struct oss_device oss_device_t;
-#define OSS_DEVICE(x) ((oss_device_t*) (x))
+#define OSS_DEVICE(x) ((oss_device_t*) (x->private))
struct oss_device {
- sa_device_t parent;
+ sa_device_t *parent;
int fd;
-
- unsigned real_rate;
- unsigned real_nchannels;
- sa_pcm_format_t real_pcm_format;
+ pcm_attrs_t real_pcm_attrs;
+ converter_t converter_read, converter_write;
};
-int device_create_opaque(sa_device_t **dev, const char *client_name, sa_mode_t mode, const char *codec) {
- int error;
-
- if ((error = device_alloc_opaque(dev, sizeof(oss_device_t), client_name, mode, codec)))
- return error;
-
- OSS_DEVICE(*dev)->fd = -1;
-
- return SA_SUCCESS;
-}
-
-int device_create_pcm(sa_device_t **dev, const char *client_name, sa_mode_t mode, sa_pcm_format_t format, unsigned rate, unsigned channels) {
- int error;
-
- if ((error = device_alloc_pcm(dev, sizeof(oss_device_t), client_name, mode, format, rate, channels)))
- return error;
-
- OSS_DEVICE(*dev)->fd = -1;
-
- return SA_SUCCESS;
-}
-
int device_open(sa_device_t *dev) {
- oss_device_t *oss = OSS_DEVICE(dev);
+ oss_device_t *oss;
char *n;
int f, arg, bs, r, phase, i, found, suggested;
unsigned c;
@@ -70,8 +47,11 @@ int device_open(sa_device_t *dev) {
if (dev->driver && strcmp(dev->driver, DRIVER_NAME))
return SA_ERROR_NO_DRIVER;
-
- sa_assert(oss->fd < 0);
+
+ if (!(dev->private = oss = sa_new0(oss_device_t, 1)))
+ return SA_ERROR_OOM;
+
+ oss->parent = dev;
n = dev->device ? dev->device : DEFAULT_DEVICE;
if ((oss->fd = open(n, dev->mode == SA_MODE_RDONLY ? O_RDONLY : (dev->mode == SA_MODE_WRONLY ? O_WRONLY : O_RDWR) | O_NOCTTY | O_NONBLOCK)) < 0) {
@@ -99,7 +79,7 @@ int device_open(sa_device_t *dev) {
return SA_ERROR_NO_CODEC;
} else
- f = format_map[dev->pcm_format];
+ f = format_map[dev->pcm_attrs.format];
bs = 0;
@@ -142,23 +122,23 @@ int device_open(sa_device_t *dev) {
switch (f) {
case AFMT_MU_LAW:
- oss->real_pcm_format = SA_PCM_FORMAT_ULAW;
+ oss->real_pcm_attrs.format = SA_PCM_FORMAT_ULAW;
break;
case AFMT_A_LAW:
- oss->real_pcm_format = SA_PCM_FORMAT_ALAW;
+ oss->real_pcm_attrs.format = SA_PCM_FORMAT_ALAW;
break;
case AFMT_U8:
- oss->real_pcm_format = SA_PCM_FORMAT_U8;
+ oss->real_pcm_attrs.format = SA_PCM_FORMAT_U8;
break;
case AFMT_S16_LE:
- oss->real_pcm_format = SA_PCM_FORMAT_S16_LE;
+ oss->real_pcm_attrs.format = SA_PCM_FORMAT_S16_LE;
break;
case AFMT_S16_BE:
- oss->real_pcm_format = SA_PCM_FORMAT_S16_BE;
+ oss->real_pcm_attrs.format = SA_PCM_FORMAT_S16_BE;
break;
default:
@@ -171,7 +151,7 @@ int device_open(sa_device_t *dev) {
if (dev->adjust_nchannels >= 0) {
/* First try more channels ... */
- for (c = dev->nchannels; c < 16 || c == dev->nchannels; c ++) {
+ for (c = dev->pcm_attrs.nchannels; c < 8 || c == dev->pcm_attrs.nchannels; c ++) {
arg = c;
if (ioctl(oss->fd, SNDCTL_DSP_CHANNELS, &arg) < 0)
return SA_ERROR_SYSTEM;
@@ -184,7 +164,7 @@ int device_open(sa_device_t *dev) {
/* ... then try less channels */
if (!found) {
- for (c = dev->nchannels - 1; c > 0; c --) {
+ for (c = dev->pcm_attrs.nchannels - 1; c > 0; c --) {
arg = c;
if (ioctl(oss->fd, SNDCTL_DSP_CHANNELS, &arg) < 0)
return SA_ERROR_SYSTEM;
@@ -198,7 +178,7 @@ int device_open(sa_device_t *dev) {
} else {
/* First try less channels ... */
- for (c = dev->nchannels; c > 0; c --) {
+ for (c = dev->pcm_attrs.nchannels; c > 0; c --) {
arg = c;
if (ioctl(oss->fd, SNDCTL_DSP_CHANNELS, &arg) < 0)
return SA_ERROR_SYSTEM;
@@ -211,7 +191,7 @@ int device_open(sa_device_t *dev) {
/* ... then try more channels */
if (!found) {
- for (c = dev->nchannels + 1; c < 16; c ++) {
+ for (c = dev->pcm_attrs.nchannels + 1; c < 8; c ++) {
arg = c;
if (ioctl(oss->fd, SNDCTL_DSP_CHANNELS, &arg) < 0)
return SA_ERROR_SYSTEM;
@@ -229,9 +209,35 @@ int device_open(sa_device_t *dev) {
return SA_ERROR_SYSTEM;
}
- oss->real_nchannels = c;
+ oss->real_pcm_attrs.nchannels = c;
- r = dev->rate;
+ if (!(oss->real_pcm_attrs.channel_map = sa_new(sa_channel_t, c)))
+ return SA_ERROR_OOM;
+
+ 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 = dev->pcm_attrs.rate;
+ r = 44100;
suggested = 0;
phase = 0;
@@ -266,7 +272,7 @@ int device_open(sa_device_t *dev) {
if (i == elementsof(try_rates)) {
phase = 1;
- r = dev->rate;
+ r = dev->pcm_attrs.rate;
}
}
@@ -301,7 +307,7 @@ int device_open(sa_device_t *dev) {
if (i == 0) {
phase = 1;
- r = dev->rate;
+ r = dev->pcm_attrs.rate;
}
}
@@ -324,16 +330,24 @@ int device_open(sa_device_t *dev) {
}
- oss->real_rate = r;
+ oss->real_pcm_attrs.rate = r;
- printf("Chosen: %u channels, %uHz, format=%u\n", oss->real_nchannels, oss->real_rate, oss->real_pcm_format);
+ printf("Chosen: %u channels, %uHz, format=%u\n", oss->real_pcm_attrs.nchannels, oss->real_pcm_attrs.rate, oss->real_pcm_attrs.format);
if (dev->adjust_nchannels != 0)
- dev->nchannels = oss->real_nchannels;
+ dev->pcm_attrs.nchannels = oss->real_pcm_attrs.nchannels;
if (dev->adjust_rate != 0)
- dev->rate = oss->real_rate;
- if (dev->pcm_format != 0)
- dev->pcm_format = oss->real_pcm_format;
+ dev->pcm_attrs.rate = oss->real_pcm_attrs.rate;
+ if (dev->adjust_pcm_format != 0)
+ dev->pcm_attrs.format = oss->real_pcm_attrs.format;
+
+ if (dev->mode & SA_MODE_RDONLY)
+ if ((r = converter_init(&oss->converter_read, &oss->real_pcm_attrs, &dev->pcm_attrs, dev->dynamic_rate_enabled)) < 0)
+ return r;
+
+ if (dev->mode & SA_MODE_WRONLY)
+ if ((r = converter_init(&oss->converter_write, &dev->pcm_attrs, &oss->real_pcm_attrs, dev->dynamic_rate_enabled)) < 0)
+ return r;
}
return SA_SUCCESS;
@@ -344,8 +358,11 @@ int device_destroy(sa_device_t *dev) {
if (oss->fd >= 0)
close(oss->fd);
-
- device_free(dev);
+
+ sa_free(oss->real_pcm_attrs.channel_map);
+ converter_done(&oss->converter_read);
+ converter_done(&oss->converter_write);
+ sa_free(oss);
return SA_SUCCESS;
}
@@ -353,16 +370,33 @@ int device_start_thread(sa_device_t *dev, sa_event_callback_t *callback) {
return SA_ERROR_NOT_SUPPORTED;
}
-int device_change_input_volume(sa_device_t *dev, int *vol) {
- return SA_ERROR_NOT_SUPPORTED;
+int device_change_input_volume(sa_device_t *dev, int vol[]) {
+ oss_device_t *oss = OSS_DEVICE(dev);
+
+ sa_return_val_if_fail(!dev->codec, SA_ERROR_NOT_SUPPORTED);
+
+ converter_set_volume(&oss->converter_read, vol);
+
+ return SA_SUCCESS;
}
-int device_change_output_volume(sa_device_t *dev, int *vol) {
- return SA_ERROR_NOT_SUPPORTED;
+int device_change_output_volume(sa_device_t *dev, int vol[]) {
+ oss_device_t *oss = OSS_DEVICE(dev);
+
+ sa_return_val_if_fail(!dev->codec, SA_ERROR_NOT_SUPPORTED);
+
+ converter_set_volume(&oss->converter_write, vol);
+
+ return SA_SUCCESS;
}
-int device_change_sampling_rate(sa_device_t *dev, unsigned rate) {
- return SA_ERROR_NOT_SUPPORTED;
+int device_change_rate(sa_device_t *dev, unsigned rate) {
+ oss_device_t *oss = OSS_DEVICE(dev);
+
+ converter_set_ratio(&oss->converter_read, oss->real_pcm_attrs.rate, dev->pcm_attrs.rate);
+ converter_set_ratio(&oss->converter_write, dev->pcm_attrs.rate, oss->real_pcm_attrs.rate);
+
+ return SA_SUCCESS;
}
int device_get_state(sa_device_t *dev, sa_state_t *state) {
@@ -378,7 +412,30 @@ int device_pread(sa_device_t *dev, void *data, size_t nbytes, int64_t offset, sa
}
int device_pwrite(sa_device_t *dev, const void *data, size_t nbytes, int64_t offset, sa_seek_t whence) {
- return SA_ERROR_NOT_SUPPORTED;
+ oss_device_t *oss = OSS_DEVICE(dev);
+ void **dst;
+ size_t *stride;
+ int ret;
+ uint8_t *d;
+
+ if ((ret = converter_go_interleaved(&oss->converter_write, data, &dst, &stride, 1, &nbytes)))
+ 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);
+
+ nbytes -= l;
+ d += l;
+ }
+
+ return SA_SUCCESS;
}
int device_pread_ni(sa_device_t *dev, unsigned channel, void *data, size_t nbytes, int64_t offset, sa_seek_t whence) {
@@ -406,19 +463,20 @@ int device_pause(sa_device_t *dev) {
}
int device_drain(sa_device_t *dev) {
- return SA_ERROR_NOT_SUPPORTED;
+ oss_device_t *oss = OSS_DEVICE(dev);
+
+ if (ioctl(oss->fd, SNDCTL_DSP_SYNC, NULL) < 0)
+ return SA_ERROR_SYSTEM;
+
+ return SA_SUCCESS;
}
/* Unsupported operations */
-int device_change_device(sa_device_t *dev, const char *device_name) {
- return SA_ERROR_NOT_SUPPORTED;
-}
-
-int device_change_client_name(sa_device_t *dev, const char *client_name) {
+int device_change_device(sa_device_t *dev) {
return SA_ERROR_NOT_SUPPORTED;
}
-int device_change_stream_name(sa_device_t *dev, const char *stream_name) {
+int device_change_meta_data(sa_device_t *dev, const char *name, const void *data, size_t size) {
return SA_ERROR_NOT_SUPPORTED;
}