From a64e85acf96bc0c55363fe55c9e9116aef2a8584 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 12 May 2007 23:38:38 +0000 Subject: resampling works git-svn-id: file:///home/lennart/svn/public/libsydney/trunk@4 9ba3c220-e4d3-45a2-8aa3-73fcc9aff6ce --- oss.c | 192 +++++++++++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 125 insertions(+), 67 deletions(-) (limited to 'oss.c') 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; } -- cgit