Initial code.
#endif
/*
- * Plug-In interface (ala C++)
+ * PCM Plug-In interface
*/
typedef struct snd_stru_pcm_plugin snd_pcm_plugin_t;
+#define snd_pcm_plugin_handle_t snd_pcm_t
typedef enum {
INIT = 0,
PREPARE = 1,
DRAIN = 2,
- FLUSH = 3
+ FLUSH = 3,
} snd_pcm_plugin_action_t;
-#define snd_pcm_plugin_extra_data(plugin) (((char *)plugin) + sizeof(*plugin))
+typedef struct snd_stru_pcm_plugin_voice {
+ void *aptr; /* pointer to the allocated area */
+ void *addr; /* address to voice samples */
+ unsigned int offset; /* offset to first voice in bits */
+ unsigned int next; /* offset to next voice in bits */
+} snd_pcm_plugin_voice_t;
struct snd_stru_pcm_plugin {
- char *name; /* plug-in name */
- int (*transfer_src_ptr)(snd_pcm_plugin_t *plugin, char **src_ptr, size_t *src_size);
+ char *name; /* plug-in name */
+ snd_pcm_format_t src_format; /* source format */
+ snd_pcm_format_t dst_format; /* destination format */
+ int src_width; /* sample width in bits */
+ int dst_width; /* sample width in bits */
+ ssize_t (*src_samples)(snd_pcm_plugin_t *plugin, size_t dst_samples);
+ ssize_t (*dst_samples)(snd_pcm_plugin_t *plugin, size_t src_samples);
+ int (*src_voices)(snd_pcm_plugin_t *plugin,
+ snd_pcm_plugin_voice_t **voices,
+ size_t samples,
+ void *(*plugin_alloc)(snd_pcm_plugin_handle_t *handle, size_t size));
+ int (*dst_voices)(snd_pcm_plugin_t *plugin,
+ snd_pcm_plugin_voice_t **voices,
+ size_t samples,
+ void *(*plugin_alloc)(snd_pcm_plugin_handle_t *handle, size_t size));
ssize_t (*transfer)(snd_pcm_plugin_t *plugin,
- char *src_ptr, size_t src_size,
- char *dst_ptr, size_t dst_size);
- ssize_t (*src_size)(snd_pcm_plugin_t *plugin, size_t dst_size);
- ssize_t (*dst_size)(snd_pcm_plugin_t *plugin, size_t src_size);
+ const snd_pcm_plugin_voice_t *src_voices,
+ const snd_pcm_plugin_voice_t *dst_voices,
+ size_t samples);
int (*action)(snd_pcm_plugin_t *plugin,
snd_pcm_plugin_action_t action,
unsigned long data);
+ int (*parameter_set)(snd_pcm_plugin_t *plugin,
+ const char *name,
+ unsigned long value);
+ int (*parameter_get)(snd_pcm_plugin_t *plugin,
+ const char *name,
+ unsigned long *value);
snd_pcm_plugin_t *prev;
snd_pcm_plugin_t *next;
+ snd_pcm_plugin_handle_t *handle;
void *private_data;
void (*private_free)(snd_pcm_plugin_t *plugin, void *private_data);
+ snd_pcm_plugin_voice_t *voices;
+ void *extra_data;
};
-snd_pcm_plugin_t *snd_pcm_plugin_build(const char *name, int extra);
+snd_pcm_plugin_t *snd_pcm_plugin_build(snd_pcm_plugin_handle_t *handle,
+ const char *name,
+ snd_pcm_format_t *src_format,
+ snd_pcm_format_t *dst_format,
+ int extra);
int snd_pcm_plugin_free(snd_pcm_plugin_t *plugin);
int snd_pcm_plugin_clear(snd_pcm_t *handle, int channel);
int snd_pcm_plugin_insert(snd_pcm_t *handle, int channel, snd_pcm_plugin_t *plugin);
int snd_pcm_plugin_remove_first(snd_pcm_t *handle, int channel);
snd_pcm_plugin_t *snd_pcm_plugin_first(snd_pcm_t *handle, int channel);
snd_pcm_plugin_t *snd_pcm_plugin_last(snd_pcm_t *handle, int channel);
-ssize_t snd_pcm_plugin_transfer_size(snd_pcm_t *handle, int channel, size_t drv_size);
-ssize_t snd_pcm_plugin_hardware_size(snd_pcm_t *handle, int channel, size_t trf_size);
+ssize_t snd_pcm_plugin_client_samples(snd_pcm_t *handle, int channel, size_t drv_samples);
+ssize_t snd_pcm_plugin_hardware_samples(snd_pcm_t *handle, int channel, size_t clt_samples);
+ssize_t snd_pcm_plugin_client_size(snd_pcm_t *handle, int channel, size_t drv_size);
+ssize_t snd_pcm_plugin_hardware_size(snd_pcm_t *handle, int channel, size_t clt_size);
int snd_pcm_plugin_info(snd_pcm_t *handle, snd_pcm_channel_info_t *info);
int snd_pcm_plugin_params(snd_pcm_t *handle, snd_pcm_channel_params_t *params);
int snd_pcm_plugin_setup(snd_pcm_t *handle, snd_pcm_channel_setup_t *setup);
int snd_pcm_plugin_prepare(snd_pcm_t *handle, int channel);
int snd_pcm_plugin_playback_drain(snd_pcm_t *handle);
int snd_pcm_plugin_flush(snd_pcm_t *handle, int channel);
+ssize_t snd_pcm_plugin_transfer_size(snd_pcm_t *handle, int channel);
int snd_pcm_plugin_pointer(snd_pcm_t *pcm, int channel, void **ptr, size_t *size);
ssize_t snd_pcm_plugin_write(snd_pcm_t *handle, const void *buffer, size_t size);
ssize_t snd_pcm_plugin_read(snd_pcm_t *handle, void *bufer, size_t size);
+int snd_pcm_plugin_pointerv(snd_pcm_t *pcm, int channel, struct iovec **vector, int *count);
+ssize_t snd_pcm_plugin_writev(snd_pcm_t *pcm, const struct iovec *vector, int count);
+ssize_t snd_pcm_plugin_readv(snd_pcm_t *pcm, const struct iovec *vector, int count);
+ssize_t snd_pcm_plugin_write_continue(snd_pcm_t *pcm);
+
+/*
+ * Plug-In helpers
+ */
+
+ssize_t snd_pcm_plugin_src_samples_to_size(snd_pcm_plugin_t *plugin, size_t samples);
+ssize_t snd_pcm_plugin_dst_samples_to_size(snd_pcm_plugin_t *plugin, size_t samples);
+ssize_t snd_pcm_plugin_src_size_to_samples(snd_pcm_plugin_t *plugin, size_t size);
+ssize_t snd_pcm_plugin_dst_size_to_samples(snd_pcm_plugin_t *plugin, size_t size);
+int snd_pcm_plugin_src_voices(snd_pcm_plugin_t *plugin,
+ snd_pcm_plugin_voice_t **voices,
+ size_t samples);
+int snd_pcm_plugin_dst_voices(snd_pcm_plugin_t *plugin,
+ snd_pcm_plugin_voice_t **voices,
+ size_t samples);
/*
* Plug-In constructors
*/
/* basic I/O */
-int snd_pcm_plugin_build_stream(snd_pcm_t *handle, int channel, snd_pcm_plugin_t **r_plugin);
-int snd_pcm_plugin_build_block(snd_pcm_t *handle, int channel, snd_pcm_plugin_t **r_plugin);
-int snd_pcm_plugin_build_mmap(snd_pcm_t *handle, int channel, snd_pcm_plugin_t **r_plugin);
+int snd_pcm_plugin_build_stream(snd_pcm_plugin_handle_t *handle, int channel,
+ snd_pcm_format_t *format,
+ snd_pcm_plugin_t **r_plugin);
+int snd_pcm_plugin_build_block(snd_pcm_plugin_handle_t *handle, int channel,
+ snd_pcm_format_t *format,
+ snd_pcm_plugin_t **r_plugin);
+int snd_pcm_plugin_build_mmap(snd_pcm_plugin_handle_t *handle, int channel,
+ snd_pcm_format_t *format,
+ snd_pcm_plugin_t **r_plugin);
/* conversion plugins */
-int snd_pcm_plugin_build_interleave(snd_pcm_format_t *src_format,
+int snd_pcm_plugin_build_interleave(snd_pcm_plugin_handle_t *handle,
+ snd_pcm_format_t *src_format,
snd_pcm_format_t *dst_format,
snd_pcm_plugin_t **r_plugin);
-int snd_pcm_plugin_build_linear(snd_pcm_format_t *src_format,
+int snd_pcm_plugin_build_linear(snd_pcm_plugin_handle_t *handle,
+ snd_pcm_format_t *src_format,
snd_pcm_format_t *dst_format,
snd_pcm_plugin_t **r_plugin);
-int snd_pcm_plugin_build_mulaw(snd_pcm_format_t *src_format,
+int snd_pcm_plugin_build_mulaw(snd_pcm_plugin_handle_t *handle,
+ snd_pcm_format_t *src_format,
snd_pcm_format_t *dst_format,
snd_pcm_plugin_t **r_plugin);
-int snd_pcm_plugin_build_alaw(snd_pcm_format_t *src_format,
+int snd_pcm_plugin_build_alaw(snd_pcm_plugin_handle_t *handle,
+ snd_pcm_format_t *src_format,
snd_pcm_format_t *dst_format,
snd_pcm_plugin_t **r_plugin);
-int snd_pcm_plugin_build_adpcm(snd_pcm_format_t *src_format,
+int snd_pcm_plugin_build_adpcm(snd_pcm_plugin_handle_t *handle,
+ snd_pcm_format_t *src_format,
snd_pcm_format_t *dst_format,
snd_pcm_plugin_t **r_plugin);
-int snd_pcm_plugin_build_rate(snd_pcm_format_t *src_format,
+int snd_pcm_plugin_build_rate(snd_pcm_plugin_handle_t *handle,
+ snd_pcm_format_t *src_format,
snd_pcm_format_t *dst_format,
snd_pcm_plugin_t **r_plugin);
-int snd_pcm_plugin_build_route(snd_pcm_format_t *src_format,
- snd_pcm_format_t *dst_format,
- int *ttable,
- snd_pcm_plugin_t **r_plugin);
+int snd_pcm_plugin_build_route(snd_pcm_plugin_handle_t *handle,
+ snd_pcm_format_t *src_format,
+ snd_pcm_format_t *dst_format,
+ int *ttable,
+ snd_pcm_plugin_t **r_plugin);
/*
* Loopback interface
int plugin_alloc_lock[4];
void *plugin_alloc_xptr[2];
long plugin_alloc_xsize[2];
+ int plugin_alloc_xchannel;
};
unsigned int snd_pcm_plugin_formats(unsigned int formats);
snd_pcm_channel_info_t *hwinfo,
snd_pcm_channel_params_t *hwparams);
int snd_pcm_plugin_format(snd_pcm_t *pcm,
- snd_pcm_channel_params_t *params,
- snd_pcm_channel_params_t *hwparams,
+ snd_pcm_channel_params_t *params,
+ snd_pcm_channel_params_t *hwparams,
snd_pcm_channel_info_t *hwinfo);
#if 0
#include <string.h>
#include <errno.h>
#include <math.h>
+#include <sys/uio.h>
#include "pcm_local.h"
-snd_pcm_plugin_t *snd_pcm_plugin_build(const char *name, int extra)
+static void *snd_pcm_plugin_buf_alloc(snd_pcm_t *pcm, size_t size);
+static void snd_pcm_plugin_buf_free(snd_pcm_t *pcm, void *ptr);
+static void *snd_pcm_plugin_ptr_alloc(snd_pcm_t *pcm, size_t size);
+
+snd_pcm_plugin_t *snd_pcm_plugin_build(snd_pcm_plugin_handle_t *handle,
+ const char *name,
+ snd_pcm_format_t *src_format,
+ snd_pcm_format_t *dst_format,
+ int extra)
{
snd_pcm_plugin_t *plugin;
+ int voices = 0;
if (extra < 0)
return NULL;
- plugin = (snd_pcm_plugin_t *)calloc(1, sizeof(*plugin) + extra);
+ if (src_format)
+ voices = src_format->voices;
+ if (dst_format && dst_format->voices > voices)
+ voices = dst_format->voices;
+ plugin = (snd_pcm_plugin_t *)calloc(1, sizeof(*plugin) + voices * sizeof(snd_pcm_plugin_voice_t) + extra);
if (plugin == NULL)
return NULL;
plugin->name = name ? strdup(name) : NULL;
+ if (src_format) {
+ memcpy(&plugin->src_format, src_format, sizeof(snd_pcm_format_t));
+ if ((plugin->src_width = snd_pcm_format_width(src_format->format)) < 0)
+ return NULL;
+ }
+ if (dst_format) {
+ memcpy(&plugin->dst_format, dst_format, sizeof(snd_pcm_format_t));
+ if ((plugin->dst_width = snd_pcm_format_width(dst_format->format)) < 0)
+ return NULL;
+ }
+ plugin->handle = handle;
+ plugin->voices = (snd_pcm_plugin_voice_t *)((char *)plugin + sizeof(*plugin));
+ plugin->extra_data = (char *)plugin->voices + voices * sizeof(snd_pcm_plugin_voice_t);
return plugin;
}
{
ssize_t transfer;
- transfer = snd_pcm_plugin_transfer_size(pcm, channel, 1000000);
+ transfer = snd_pcm_plugin_client_size(pcm, channel, 1000000);
if (transfer < 0)
return 0;
return (double)transfer / (double)1000000;
if (params->mode == SND_PCM_MODE_STREAM) {
pdprintf("params stream plugin\n");
- err = snd_pcm_plugin_build_stream(pcm, params->channel, &plugin);
+ err = snd_pcm_plugin_build_stream(pcm, params->channel, &hwparams.format, &plugin);
} else if (params->mode == SND_PCM_MODE_BLOCK) {
if (hwinfo.flags & SND_PCM_CHNINFO_MMAP) {
pdprintf("params mmap plugin\n");
- err = snd_pcm_plugin_build_mmap(pcm, params->channel, &plugin);
+ err = snd_pcm_plugin_build_mmap(pcm, params->channel, &hwparams.format, &plugin);
} else {
pdprintf("params block plugin\n");
- err = snd_pcm_plugin_build_block(pcm, params->channel, &plugin);
+ err = snd_pcm_plugin_build_block(pcm, params->channel, &hwparams.format, &plugin);
}
} else {
return -EINVAL;
return err;
if (setup->mode == SND_PCM_MODE_STREAM) {
pdprintf("params setup: queue_size = %i\n", setup->buf.stream.queue_size);
- setup->buf.stream.queue_size = snd_pcm_plugin_transfer_size(pcm, setup->channel, setup->buf.stream.queue_size);
+ setup->buf.stream.queue_size = snd_pcm_plugin_client_size(pcm, setup->channel, setup->buf.stream.queue_size);
pdprintf("params setup: queue_size = %i\n", setup->buf.stream.queue_size);
} else if (setup->mode == SND_PCM_MODE_BLOCK) {
pdprintf("params setup: frag_size = %i\n", setup->buf.block.frag_size);
- setup->buf.block.frag_size = snd_pcm_plugin_transfer_size(pcm, setup->channel, setup->buf.block.frag_size);
+ setup->buf.block.frag_size = snd_pcm_plugin_client_size(pcm, setup->channel, setup->buf.block.frag_size);
pdprintf("params setup: frag_size = %i\n", setup->buf.block.frag_size);
} else {
return -EINVAL;
ratio = snd_pcm_plugin_transfer_ratio(pcm, status->channel);
if (ratio <= 0)
return -EINVAL;
- status->scount = snd_pcm_plugin_transfer_size(pcm, status->channel, status->scount);
- status->count = snd_pcm_plugin_transfer_size(pcm, status->channel, status->count);
- status->free = snd_pcm_plugin_transfer_size(pcm, status->channel, status->free);
+ /* FIXME: scount may overflow */
+ status->scount = snd_pcm_plugin_client_size(pcm, status->channel, status->scount);
+ status->count = snd_pcm_plugin_client_size(pcm, status->channel, status->count);
+ status->free = snd_pcm_plugin_client_size(pcm, status->channel, status->free);
return 0;
}
return snd_pcm_channel_flush(pcm, channel);
}
+ssize_t snd_pcm_plugin_transfer_size(snd_pcm_t *pcm, int channel)
+{
+ ssize_t result;
+
+ if ((result = snd_pcm_transfer_size(pcm, channel)) < 0)
+ return result;
+ return snd_pcm_plugin_client_size(pcm, channel, result);
+}
+
int snd_pcm_plugin_pointer(snd_pcm_t *pcm, int channel, void **ptr, size_t *size)
{
- snd_pcm_plugin_t *plugin;
- int err;
+ snd_pcm_plugin_t *plugin = NULL;
+ snd_pcm_plugin_voice_t *voices;
+ size_t samples;
+ int width;
- if (!ptr || !size)
+ if (!ptr || !size || *size < 1)
return -EINVAL;
*ptr = NULL;
if (!pcm || channel < 0 || channel > 1)
return -EINVAL;
- plugin = pcm->plugin_first[channel];
- if (!plugin)
- return -EINVAL;
- if (plugin->transfer_src_ptr) {
- err = plugin->transfer_src_ptr(plugin, (char **)ptr, size);
- if (err >= 0)
- return 0;
+ if ((*size = snd_pcm_plugin_transfer_size(pcm, channel)) < 0)
+ return *size;
+ if (channel == SND_PCM_CHANNEL_PLAYBACK && plugin->src_voices) {
+ plugin = pcm->plugin_first[channel];
+ if (!plugin)
+ goto __skip;
+ if (!plugin->src_format.interleave)
+ goto __skip;
+ if ((width = snd_pcm_format_width(plugin->src_format.format)) < 0)
+ return width;
+ samples = *size * width;
+ if ((samples % (plugin->src_format.voices * 8)) != 0)
+ return -EINVAL;
+ samples /= (plugin->src_format.voices * 8);
+ pcm->plugin_alloc_xchannel = SND_PCM_CHANNEL_PLAYBACK;
+ if (plugin->src_voices(plugin, &voices, samples,
+ snd_pcm_plugin_ptr_alloc) < 0)
+ goto __skip;
+ *ptr = voices->addr;
+ return 0;
+ } else if (channel == SND_PCM_CHANNEL_CAPTURE && plugin->dst_voices) {
+ plugin = pcm->plugin_last[channel];
+ if (!plugin)
+ goto __skip;
+ if (plugin->dst_format.interleave)
+ goto __skip;
+ if ((width = snd_pcm_format_width(plugin->dst_format.format)) < 0)
+ return width;
+ samples = *size * width;
+ if ((samples % (plugin->dst_format.voices * 8)) != 0)
+ return -EINVAL;
+ samples /= (plugin->src_format.voices * 8);
+ pcm->plugin_alloc_xchannel = SND_PCM_CHANNEL_CAPTURE;
+ if (plugin->dst_voices(plugin, &voices, *size,
+ snd_pcm_plugin_ptr_alloc) < 0)
+ goto __skip;
+ *ptr = voices->addr;
+ return 0;
}
- if (pcm->plugin_alloc_xptr[channel]) {
- if (pcm->plugin_alloc_xsize[channel] >= *size) {
- *ptr = (char *)pcm->plugin_alloc_xptr[channel];
- return 0;
+ __skip:
+ *ptr = snd_pcm_plugin_ptr_alloc(pcm, *size);
+ if (*ptr == NULL)
+ return -ENOMEM;
+ return 0;
+}
+
+ssize_t snd_pcm_plugin_write(snd_pcm_t *pcm, const void *buffer, size_t count)
+{
+ snd_pcm_plugin_t *plugin;
+
+ if ((plugin = snd_pcm_plugin_first(pcm, SND_PCM_CHANNEL_PLAYBACK)) == NULL)
+ return snd_pcm_write(pcm, buffer, count);
+ if (plugin->src_format.interleave) {
+ struct iovec vec;
+ vec.iov_base = (void *)buffer;
+ vec.iov_len = count;
+ return snd_pcm_plugin_writev(pcm, &vec, 1);
+ } else {
+ int idx, voices = plugin->src_format.voices;
+ int size = count / voices;
+ struct iovec vec[voices];
+ for (idx = 0; idx < voices; idx++) {
+ vec[idx].iov_base = (char *)buffer + (size * idx);
+ vec[idx].iov_len = size;
}
- *ptr = (char *)realloc(pcm->plugin_alloc_xptr[channel], *size);
+ return snd_pcm_plugin_writev(pcm, vec, voices);
+ }
+}
+
+ssize_t snd_pcm_plugin_read(snd_pcm_t *pcm, void *buffer, size_t count)
+{
+ snd_pcm_plugin_t *plugin;
+
+ if ((plugin = snd_pcm_plugin_last(pcm, SND_PCM_CHANNEL_CAPTURE)) == NULL)
+ return snd_pcm_write(pcm, buffer, count);
+ if (plugin->dst_format.interleave) {
+ struct iovec vec;
+ vec.iov_base = buffer;
+ vec.iov_len = count;
+ return snd_pcm_plugin_readv(pcm, &vec, 1);
} else {
- *ptr = (char *)malloc(*size);
- if (*ptr != NULL)
- pcm->plugin_alloc_xsize[channel] = *size;
+ int idx, voices = plugin->dst_format.voices;
+ int size = count / voices;
+ struct iovec vec[voices];
+ for (idx = 0; idx < voices; idx++) {
+ vec[idx].iov_base = (char *)buffer + (size * idx);
+ vec[idx].iov_len = size;
+ }
+ return snd_pcm_plugin_readv(pcm, vec, voices);
}
- if (*ptr == NULL)
- return -ENOMEM;
- pcm->plugin_alloc_xptr[channel] = *ptr;
+}
+
+static int snd_pcm_plugin_load_vector(snd_pcm_plugin_t *plugin,
+ snd_pcm_plugin_voice_t **voices,
+ const struct iovec *vector,
+ int count,
+ snd_pcm_format_t *format)
+{
+ snd_pcm_plugin_voice_t *v = plugin->voices;
+ int width, cvoices, voice;
+
+ *voices = NULL;
+ if ((width = snd_pcm_format_width(format->format)) < 0)
+ return width;
+ cvoices = format->voices;
+ if (format->interleave) {
+ if (count != 1)
+ return -EINVAL;
+ for (voice = 0; voice < cvoices; voice++, v++) {
+ v->aptr = NULL;
+ if ((v->addr = vector->iov_base) == NULL)
+ return -EINVAL;
+ v->offset = voice * width;
+ v->next = cvoices * width;
+ }
+ } else {
+ if (count != cvoices)
+ return -EINVAL;
+ for (voice = 0; voice < cvoices; voice++, v++) {
+ v->aptr = NULL;
+ v->addr = vector[voice].iov_base;
+ v->offset = 0;
+ v->next = width;
+ }
+ }
+ *voices = plugin->voices;
return 0;
}
-static void *snd_pcm_plugin_malloc(snd_pcm_t *pcm, long size)
+static inline int snd_pcm_plugin_load_src_vector(snd_pcm_plugin_t *plugin,
+ snd_pcm_plugin_voice_t **voices,
+ const struct iovec *vector,
+ int count)
+{
+ return snd_pcm_plugin_load_vector(plugin, voices, vector, count, &plugin->src_format);
+}
+
+static inline int snd_pcm_plugin_load_dst_vector(snd_pcm_plugin_t *plugin,
+ snd_pcm_plugin_voice_t **voices,
+ const struct iovec *vector,
+ int count)
+{
+ return snd_pcm_plugin_load_vector(plugin, voices, vector, count, &plugin->dst_format);
+}
+
+ssize_t snd_pcm_plugin_writev(snd_pcm_t *pcm, const struct iovec *vector, int count)
+{
+ snd_pcm_plugin_t *plugin, *next;
+ snd_pcm_plugin_voice_t *src_voices, *dst_voices;
+ size_t samples;
+ ssize_t size;
+ int idx, err;
+
+ if ((plugin = snd_pcm_plugin_first(pcm, SND_PCM_CHANNEL_PLAYBACK)) == NULL)
+ return snd_pcm_writev(pcm, vector, count);
+ if ((err = snd_pcm_plugin_load_src_vector(plugin, &src_voices, vector, count)) < 0)
+ return err;
+ size = 0;
+ for (idx = 0; idx < count; idx++)
+ size += vector[idx].iov_len;
+ size = snd_pcm_plugin_src_size_to_samples(plugin, size);
+ if (size < 0)
+ return size;
+ samples = size;
+ while (plugin) {
+ if ((next = plugin->next) != NULL) {
+ if (next->src_voices) {
+ if ((err = next->src_voices(next, &dst_voices, samples, snd_pcm_plugin_buf_alloc)) < 0) {
+ snd_pcm_plugin_buf_free(pcm, src_voices->aptr);
+ return err;
+ }
+ } else {
+ if ((err = snd_pcm_plugin_src_voices(next, &dst_voices, samples)) < 0) {
+ snd_pcm_plugin_buf_free(pcm, src_voices->aptr);
+ return err;
+ }
+ }
+ } else {
+ dst_voices = NULL;
+ }
+ pdprintf("write plugin: %s, %i\n", plugin->name, samples);
+ if ((size = plugin->transfer(plugin, src_voices, dst_voices, samples))<0) {
+ snd_pcm_plugin_buf_free(pcm, src_voices->aptr);
+ if (dst_voices)
+ snd_pcm_plugin_buf_free(pcm, dst_voices->aptr);
+ return size;
+ }
+ snd_pcm_plugin_buf_free(pcm, src_voices->aptr);
+ plugin = plugin->next;
+ src_voices = dst_voices;
+ samples = size;
+ }
+ samples = snd_pcm_plugin_client_samples(pcm, SND_PCM_CHANNEL_PLAYBACK, samples);
+ size = snd_pcm_plugin_src_samples_to_size(pcm->plugin_first[SND_PCM_CHANNEL_PLAYBACK], samples);
+ if (size < 0)
+ return size;
+ pdprintf("writev result = %i\n", size);
+ return size;
+}
+
+ssize_t snd_pcm_plugin_readv(snd_pcm_t *pcm, const struct iovec *vector, int count)
+{
+ snd_pcm_plugin_t *plugin, *next;
+ snd_pcm_plugin_voice_t *src_voices = NULL, *dst_voices;
+ size_t samples;
+ ssize_t size;
+ int idx, err;
+
+ if ((plugin = snd_pcm_plugin_first(pcm, SND_PCM_CHANNEL_CAPTURE)) == NULL)
+ return snd_pcm_readv(pcm, vector, count);
+ if (vector == NULL)
+ return -EINVAL;
+ size = 0;
+ for (idx = 0; idx < count; idx++)
+ size += vector[idx].iov_len;
+ if (size < 0)
+ return size;
+ samples = snd_pcm_plugin_dst_size_to_samples(pcm->plugin_last[SND_PCM_CHANNEL_CAPTURE], size);
+ samples = snd_pcm_plugin_hardware_samples(pcm, SND_PCM_CHANNEL_CAPTURE, samples);
+ while (plugin && samples > 0) {
+ if ((next = plugin->next) != NULL) {
+ if (plugin->dst_voices) {
+ if ((err = plugin->dst_voices(plugin, &dst_voices, samples, snd_pcm_plugin_buf_alloc)) < 0) {
+ if (src_voices)
+ snd_pcm_plugin_buf_free(pcm, src_voices->aptr);
+ return err;
+ }
+ } else {
+ if ((err = snd_pcm_plugin_dst_voices(plugin, &dst_voices, samples)) < 0) {
+ if (src_voices)
+ snd_pcm_plugin_buf_free(pcm, src_voices->aptr);
+ return err;
+ }
+ }
+ } else {
+ if ((err = snd_pcm_plugin_load_dst_vector(plugin, &dst_voices, vector, count)) < 0) {
+ if (src_voices)
+ snd_pcm_plugin_buf_free(pcm, src_voices->aptr);
+ return err;
+ }
+ }
+ pdprintf("read plugin: %s, %i\n", plugin->name, samples);
+ if ((size = plugin->transfer(plugin, src_voices, dst_voices, samples))<0) {
+ if (src_voices)
+ snd_pcm_plugin_buf_free(pcm, src_voices->aptr);
+ snd_pcm_plugin_buf_free(pcm, dst_voices->aptr);
+ return size;
+ }
+ if (src_voices)
+ snd_pcm_plugin_buf_free(pcm, src_voices->aptr);
+ plugin = plugin->next;
+ src_voices = dst_voices;
+ samples = size;
+ }
+ snd_pcm_plugin_buf_free(pcm, dst_voices->aptr);
+ size = snd_pcm_plugin_dst_samples_to_size(pcm->plugin_last[SND_PCM_CHANNEL_CAPTURE], samples);
+ pdprintf("readv result = %i\n", size);
+ return size;
+}
+
+/*
+ * Plugin helpers
+ */
+
+static void *snd_pcm_plugin_buf_alloc(snd_pcm_t *pcm, size_t size)
{
int idx;
void *ptr;
+ if (pcm == NULL || size <= 0)
+ return NULL;
for (idx = 0; idx < 4; idx++) {
if (pcm->plugin_alloc_lock[idx])
continue;
return NULL;
}
-static int snd_pcm_plugin_alloc_unlock(snd_pcm_t *pcm, void *ptr)
+static void snd_pcm_plugin_buf_free(snd_pcm_t *pcm, void *ptr)
{
int idx;
+ if (pcm == NULL || ptr == NULL)
+ return;
for (idx = 0; idx < 4; idx++) {
if (pcm->plugin_alloc_ptr[idx] == ptr) {
pcm->plugin_alloc_lock[idx] = 0;
- return 0;
+ return;
}
}
- return -ENOENT;
}
-ssize_t snd_pcm_plugin_write(snd_pcm_t *pcm, const void *buffer, size_t count)
+static void *snd_pcm_plugin_ptr_alloc(snd_pcm_t *pcm, size_t size)
{
- snd_pcm_plugin_t *plugin, *next;
- char *dst_ptr, *dst_ptr1 = NULL, *src_ptr, *src_ptr1 = NULL;
- size_t dst_size, src_size;
- ssize_t size = 0, result = 0;
- int err;
+ void *ptr;
+ int channel = pcm->plugin_alloc_xchannel;
- if ((plugin = snd_pcm_plugin_first(pcm, SND_PCM_CHANNEL_PLAYBACK)) == NULL)
- return snd_pcm_write(pcm, buffer, count);
- src_ptr = (char *)buffer;
- dst_size = src_size = count;
- while (plugin) {
- next = plugin->next;
- if (plugin->dst_size) {
- dst_size = plugin->dst_size(plugin, dst_size);
- if (dst_size < 0) {
- result = dst_size;
- goto __free;
- }
- }
- if (next != NULL) {
- if (next->transfer_src_ptr) {
- if ((err = next->transfer_src_ptr(next, &dst_ptr, &dst_size)) < 0) {
- if (dst_ptr == NULL)
- goto __alloc;
- result = err;
- goto __free;
- }
- } else {
- __alloc:
- dst_ptr = dst_ptr1 = (char *)snd_pcm_plugin_malloc(pcm, dst_size);
- if (dst_ptr == NULL) {
- result = -ENOMEM;
- goto __free;
- }
- }
- } else {
- dst_ptr = src_ptr;
- dst_size = src_size;
- }
- pdprintf("write plugin: %s, %i, %i\n", plugin->name, src_size, dst_size);
- if ((size = plugin->transfer(plugin, src_ptr, src_size,
- dst_ptr, dst_size))<0) {
- result = size;
- goto __free;
- }
- if (src_ptr1)
- snd_pcm_plugin_alloc_unlock(pcm, src_ptr1);
- plugin = next;
- src_ptr = dst_ptr;
- src_ptr1 = dst_ptr1;
- dst_ptr1 = NULL;
- src_size = dst_size = size;
+ if (pcm->plugin_alloc_xptr[channel]) {
+ if (pcm->plugin_alloc_xsize[channel] >= size)
+ return pcm->plugin_alloc_xptr[channel];
+ ptr = realloc(pcm->plugin_alloc_xptr[channel], size);
+ } else {
+ ptr = malloc(size);
}
- result = snd_pcm_plugin_transfer_size(pcm, SND_PCM_CHANNEL_PLAYBACK, size);
- pdprintf("size = %i, result = %i, count = %i\n", size, result, count);
- __free:
- if (dst_ptr1)
- snd_pcm_plugin_alloc_unlock(pcm, dst_ptr1);
- if (src_ptr1)
- snd_pcm_plugin_alloc_unlock(pcm, src_ptr1);
- return result;
+ if (ptr == NULL)
+ return NULL;
+ pcm->plugin_alloc_xptr[channel] = (char *)ptr;
+ pcm->plugin_alloc_xsize[channel] = size;
+ return ptr;
}
-ssize_t snd_pcm_plugin_read(snd_pcm_t *pcm, void *buffer, size_t count)
+static int snd_pcm_plugin_xvoices(snd_pcm_plugin_t *plugin,
+ snd_pcm_plugin_voice_t **voices,
+ size_t samples,
+ snd_pcm_format_t *format)
{
- snd_pcm_plugin_t *plugin, *next;
- char *dst_ptr, *dst_ptr1 = NULL, *src_ptr, *src_ptr1 = NULL;
- size_t dst_size, src_size;
- ssize_t size = 0, result = 0;
- int err;
-
- if ((plugin = snd_pcm_plugin_first(pcm, SND_PCM_CHANNEL_CAPTURE)) == NULL)
- return snd_pcm_read(pcm, buffer, count);
- src_ptr = NULL;
- src_size = 0;
- dst_size = snd_pcm_plugin_hardware_size(pcm, SND_PCM_CHANNEL_CAPTURE, count);
- if (dst_size < 0)
- return dst_size;
- while (plugin) {
- next = plugin->next;
- if (plugin->dst_size) {
- dst_size = plugin->dst_size(plugin, dst_size);
- if (dst_size < 0) {
- result = dst_size;
- goto __free;
- }
- }
- if (next != NULL) {
- if (next->transfer_src_ptr) {
- if ((err = next->transfer_src_ptr(next, &dst_ptr, &dst_size)) < 0) {
- if (dst_ptr == NULL)
- goto __alloc;
- result = err;
- goto __free;
- }
- } else {
- __alloc:
- dst_ptr = dst_ptr1 = (char *)snd_pcm_plugin_malloc(pcm, dst_size);
- if (dst_ptr == NULL) {
- result = -ENOMEM;
- goto __free;
- }
- }
+ char *ptr;
+ int width, voice;
+ long size;
+ snd_pcm_plugin_voice_t *v;
+
+ *voices = NULL;
+ if ((width = snd_pcm_format_width(format->format)) < 0)
+ return width;
+ size = format->voices * samples * width;
+ if ((size % 8) != 0)
+ return -EINVAL;
+ size /= 8;
+ ptr = (char *)snd_pcm_plugin_buf_alloc(plugin->handle, size);
+ if (ptr == NULL)
+ return -ENOMEM;
+ if ((size % format->voices) != 0)
+ return -EINVAL;
+ size /= format->voices;
+ v = plugin->voices;
+ for (voice = 0; voice < format->voices; voice++, v++) {
+ v->aptr = ptr;
+ if (format->interleave) {
+ v->addr = ptr;
+ v->offset = voice * width;
+ v->next = format->voices * width;
} else {
- dst_ptr = buffer;
- }
- pdprintf("read plugin: %s, %i, %i\n", plugin->name, src_size, dst_size);
- if ((size = plugin->transfer(plugin, src_ptr, src_size,
- dst_ptr, dst_size))<0) {
- result = size;
- goto __free;
+ v->addr = ptr + (voice * size);
+ v->offset = 0;
+ v->next = width;
}
- if (dst_ptr1)
- snd_pcm_plugin_alloc_unlock(pcm, dst_ptr1);
- plugin = plugin->next;
- src_ptr = dst_ptr;
- src_ptr1 = dst_ptr1;
- dst_ptr1 = NULL;
- src_size = dst_size = size;
}
- result = size;
- __free:
- if (dst_ptr1)
- snd_pcm_plugin_alloc_unlock(pcm, dst_ptr1);
- if (src_ptr1)
- snd_pcm_plugin_alloc_unlock(pcm, src_ptr1);
- return result;
+ *voices = plugin->voices;
+ return 0;
+}
+
+int snd_pcm_plugin_src_voices(snd_pcm_plugin_t *plugin,
+ snd_pcm_plugin_voice_t **voices,
+ size_t samples)
+{
+ return snd_pcm_plugin_xvoices(plugin, voices, samples, &plugin->src_format);
+}
+
+int snd_pcm_plugin_dst_voices(snd_pcm_plugin_t *plugin,
+ snd_pcm_plugin_voice_t **voices,
+ size_t samples)
+{
+ return snd_pcm_plugin_xvoices(plugin, voices, samples, &plugin->dst_format);
}
#endif
#include "../include/driver.h"
#include "../include/pcm.h"
-typedef snd_pcm_runtime_t PLUGIN_BASE;
#define snd_pcm_plugin_first(pb, channel) ((pb)->oss.plugin_first)
#define snd_pcm_plugin_last(pb, channel) ((pb)->oss.plugin_last)
#define snd_pcm_plugin_append(pb, channel, plugin) snd_pcm_oss_plugin_append(pb, plugin)
#define my_calloc(size) snd_kcalloc(size, GFP_KERNEL)
#define my_free(ptr) snd_kfree(ptr)
+#define my_strdup(str) snd_kmalloc_strdup(str, GFP_KERNEL)
#else
#include <malloc.h>
#include <errno.h>
+#include <stdio.h>
+#include <string.h>
#include "pcm_local.h"
-typedef snd_pcm_t PLUGIN_BASE;
#define my_calloc(size) calloc(1, size)
#define my_free(ptr) free(ptr)
+#define my_strdup(str) strdup(str)
#endif
+ssize_t snd_pcm_plugin_src_samples_to_size(snd_pcm_plugin_t *plugin, size_t samples)
+{
+ ssize_t result;
+
+ if (plugin == NULL)
+ return -EINVAL;
+ result = samples * plugin->src_format.voices * plugin->src_width;
+ if ((result % 8) != 0)
+ return -EINVAL;
+ return result / 8;
+}
+
+ssize_t snd_pcm_plugin_dst_samples_to_size(snd_pcm_plugin_t *plugin, size_t samples)
+{
+ ssize_t result;
+
+ if (plugin == NULL)
+ return -EINVAL;
+ result = samples * plugin->dst_format.voices * plugin->dst_width;
+ if ((result % 8) != 0)
+ return -EINVAL;
+ return result / 8;
+}
+
+ssize_t snd_pcm_plugin_src_size_to_samples(snd_pcm_plugin_t *plugin, size_t size)
+{
+ ssize_t result;
+ long tmp;
+
+ if (plugin == NULL)
+ return -EINVAL;
+ result = size * 8;
+ tmp = plugin->src_format.voices * plugin->src_width;
+ if ((result % tmp) != 0)
+ return -EINVAL;
+ return result / tmp;
+}
+
+ssize_t snd_pcm_plugin_dst_size_to_samples(snd_pcm_plugin_t *plugin, size_t size)
+{
+ ssize_t result;
+ long tmp;
+
+ if (plugin == NULL)
+ return -EINVAL;
+ result = size * 8;
+ tmp = plugin->dst_format.voices * plugin->dst_width;
+ if ((result % tmp) != 0)
+ return -EINVAL;
+ return result / tmp;
+}
-ssize_t snd_pcm_plugin_transfer_size(PLUGIN_BASE *pb, int channel, size_t drv_size)
+ssize_t snd_pcm_plugin_client_samples(snd_pcm_plugin_handle_t *pb, int channel, size_t drv_samples)
{
snd_pcm_plugin_t *plugin, *plugin_prev, *plugin_next;
if (pb == NULL || (channel != SND_PCM_CHANNEL_PLAYBACK &&
- channel != SND_PCM_CHANNEL_CAPTURE))
+ channel != SND_PCM_CHANNEL_CAPTURE))
return -EINVAL;
- if (drv_size == 0)
+ if (drv_samples == 0)
return 0;
- if (drv_size < 0)
+ if (drv_samples < 0)
return -EINVAL;
if (channel == SND_PCM_CHANNEL_PLAYBACK) {
- plugin = snd_pcm_plugin_last(pb, channel);
- while (plugin) {
+ plugin = snd_pcm_plugin_last(pb, SND_PCM_CHANNEL_PLAYBACK);
+ while (plugin && drv_samples > 0) {
plugin_prev = plugin->prev;
- if (plugin->src_size)
- drv_size = plugin->src_size(plugin, drv_size);
+ if (plugin->src_samples)
+ drv_samples = plugin->src_samples(plugin, drv_samples);
plugin = plugin_prev;
}
} else if (channel == SND_PCM_CHANNEL_CAPTURE) {
- plugin = snd_pcm_plugin_first(pb, channel);
- while (plugin) {
+ plugin = snd_pcm_plugin_first(pb, SND_PCM_CHANNEL_CAPTURE);
+ while (plugin && drv_samples > 0) {
plugin_next = plugin->next;
- if (plugin->dst_size)
- drv_size = plugin->dst_size(plugin, drv_size);
+ if (plugin->dst_samples)
+ drv_samples = plugin->dst_samples(plugin, drv_samples);
plugin = plugin_next;
}
}
- return drv_size;
+ return drv_samples;
}
-ssize_t snd_pcm_plugin_hardware_size(PLUGIN_BASE *pb, int channel, size_t trf_size)
+ssize_t snd_pcm_plugin_hardware_samples(snd_pcm_plugin_handle_t *pb, int channel, size_t clt_samples)
{
snd_pcm_plugin_t *plugin, *plugin_prev, *plugin_next;
if (pb == NULL || (channel != SND_PCM_CHANNEL_PLAYBACK &&
- channel != SND_PCM_CHANNEL_CAPTURE))
+ channel != SND_PCM_CHANNEL_CAPTURE))
return -EINVAL;
- if (trf_size == 0)
+ if (clt_samples == 0)
return 0;
- if (trf_size < 0)
+ if (clt_samples < 0)
return -EINVAL;
if (channel == SND_PCM_CHANNEL_PLAYBACK) {
- plugin = snd_pcm_plugin_first(pb, channel);
- while (plugin) {
+ plugin = snd_pcm_plugin_first(pb, SND_PCM_CHANNEL_PLAYBACK);
+ while (plugin && clt_samples > 0) {
plugin_next = plugin->next;
- if (plugin->dst_size)
- trf_size = plugin->dst_size(plugin, trf_size);
+ if (plugin->dst_samples)
+ clt_samples = plugin->dst_samples(plugin, clt_samples);
plugin = plugin_next;
}
+ if (clt_samples < 0)
+ return clt_samples;
} else if (channel == SND_PCM_CHANNEL_CAPTURE) {
- plugin = snd_pcm_plugin_last(pb, channel);
+ plugin = snd_pcm_plugin_last(pb, SND_PCM_CHANNEL_CAPTURE);
while (plugin) {
plugin_prev = plugin->prev;
- if (plugin->src_size)
- trf_size = plugin->src_size(plugin, trf_size);
+ if (plugin->src_samples)
+ clt_samples = plugin->src_samples(plugin, clt_samples);
plugin = plugin_prev;
}
}
- return trf_size;
+ return clt_samples;
+}
+
+ssize_t snd_pcm_plugin_client_size(snd_pcm_plugin_handle_t *pb, int channel, size_t drv_size)
+{
+ snd_pcm_plugin_t *plugin;
+ ssize_t result = 0;
+
+ if (pb == NULL || (channel != SND_PCM_CHANNEL_PLAYBACK &&
+ channel != SND_PCM_CHANNEL_CAPTURE))
+ return -EINVAL;
+ if (drv_size == 0)
+ return 0;
+ if (drv_size < 0)
+ return -EINVAL;
+ if (channel == SND_PCM_CHANNEL_PLAYBACK) {
+ plugin = snd_pcm_plugin_last(pb, SND_PCM_CHANNEL_PLAYBACK);
+ result = snd_pcm_plugin_src_size_to_samples(plugin, drv_size);
+ result = snd_pcm_plugin_client_samples(pb, SND_PCM_CHANNEL_PLAYBACK, result);
+ if (result < 0)
+ return result;
+ plugin = snd_pcm_plugin_first(pb, SND_PCM_CHANNEL_PLAYBACK);
+ result = snd_pcm_plugin_src_samples_to_size(plugin, result);
+ } else if (channel == SND_PCM_CHANNEL_CAPTURE) {
+ plugin = snd_pcm_plugin_first(pb, SND_PCM_CHANNEL_CAPTURE);
+ result = snd_pcm_plugin_src_size_to_samples(plugin, drv_size);
+ result = snd_pcm_plugin_client_samples(pb, SND_PCM_CHANNEL_PLAYBACK, result);
+ plugin = snd_pcm_plugin_last(pb, SND_PCM_CHANNEL_CAPTURE);
+ result = snd_pcm_plugin_dst_samples_to_size(plugin, result);
+ }
+ return result;
+}
+
+ssize_t snd_pcm_plugin_hardware_size(snd_pcm_plugin_handle_t *pb, int channel, size_t clt_size)
+{
+ snd_pcm_plugin_t *plugin;
+ ssize_t result = 0;
+
+ if (pb == NULL || (channel != SND_PCM_CHANNEL_PLAYBACK &&
+ channel != SND_PCM_CHANNEL_CAPTURE))
+ return -EINVAL;
+ if (clt_size == 0)
+ return 0;
+ if (clt_size < 0)
+ return -EINVAL;
+ if (channel == SND_PCM_CHANNEL_PLAYBACK) {
+ plugin = snd_pcm_plugin_first(pb, SND_PCM_CHANNEL_PLAYBACK);
+ result = snd_pcm_plugin_src_size_to_samples(plugin, clt_size);
+ result = snd_pcm_plugin_hardware_samples(pb, SND_PCM_CHANNEL_PLAYBACK, result);
+ if (result < 0)
+ return result;
+ plugin = snd_pcm_plugin_last(pb, SND_PCM_CHANNEL_PLAYBACK);
+ result = snd_pcm_plugin_dst_samples_to_size(plugin, result);
+ } else if (channel == SND_PCM_CHANNEL_CAPTURE) {
+ plugin = snd_pcm_plugin_last(pb, SND_PCM_CHANNEL_CAPTURE);
+ result = snd_pcm_plugin_src_size_to_samples(plugin, clt_size);
+ result = snd_pcm_plugin_hardware_samples(pb, SND_PCM_CHANNEL_PLAYBACK, result);
+ if (result < 0)
+ return result;
+ plugin = snd_pcm_plugin_first(pb, SND_PCM_CHANNEL_CAPTURE);
+ result = snd_pcm_plugin_dst_samples_to_size(plugin, result);
+ }
+ return result;
}
#define ROUTE_PLUGIN_RESOLUTION 16
-int snd_pcm_plugin_format(PLUGIN_BASE *pb,
+int snd_pcm_plugin_format(snd_pcm_plugin_handle_t *pb,
snd_pcm_channel_params_t *params,
snd_pcm_channel_params_t *hwparams,
snd_pcm_channel_info_t *hwinfo)
/* voices reduction */
if (srcparams->format.voices > dstparams.format.voices) {
+#if 0
int sv = srcparams->format.voices;
int dv = dstparams.format.voices;
int *ttable = my_calloc(dv*sv*sizeof(*ttable));
return err;
}
srcparams->format.voices = tmpparams.format.voices;
+#else
+ snd_pcm_plugin_free(plugin);
+ return -EIO;
+#endif
}
/* Convert to interleaved format if needed */
srcparams->format.voices > 1 &&
srcparams->format.rate != dstparams.format.rate) {
tmpparams.format.interleave = 1;
- err = snd_pcm_plugin_build_interleave(&srcparams->format,
+ err = snd_pcm_plugin_build_interleave(pb,
+ &srcparams->format,
&tmpparams.format,
&plugin);
pdprintf("params interleave change: src=%i, dst=%i returns %i\n", srcparams->format.interleave, tmpparams.format.interleave, err);
snd_pcm_format_width(srcparams->format.format) <= 16 &&
snd_pcm_format_width(srcparams->format.format) >= snd_pcm_format_width(srcparams->format.format)) {
tmpparams.format.rate = dstparams.format.rate;
- err = snd_pcm_plugin_build_rate(&srcparams->format,
+ err = snd_pcm_plugin_build_rate(pb,
+ &srcparams->format,
&tmpparams.format,
&plugin);
pdprintf("params rate down resampling: src=%i, dst=%i returns %i\n", srcparams->format.rate, tmpparams.format.rate, err);
tmpparams.format.format = SND_PCM_SFMT_S16_LE;
switch (srcparams->format.format) {
case SND_PCM_SFMT_MU_LAW:
- err = snd_pcm_plugin_build_mulaw(&srcparams->format,
+ err = snd_pcm_plugin_build_mulaw(pb,
+ &srcparams->format,
&tmpparams.format,
&plugin);
break;
#ifndef __KERNEL__
case SND_PCM_SFMT_A_LAW:
- err = snd_pcm_plugin_build_alaw(&srcparams->format,
+ err = snd_pcm_plugin_build_alaw(pb,
+ &srcparams->format,
&tmpparams.format,
&plugin);
break;
case SND_PCM_SFMT_IMA_ADPCM:
- err = snd_pcm_plugin_build_adpcm(&srcparams->format,
+ err = snd_pcm_plugin_build_adpcm(pb,
+ &srcparams->format,
&tmpparams.format,
&plugin);
break;
tmpparams.format.format = dstparams.format.format;
if (srcparams->format.format == SND_PCM_SFMT_MU_LAW ||
tmpparams.format.format == SND_PCM_SFMT_MU_LAW) {
- err = snd_pcm_plugin_build_mulaw(&srcparams->format,
+ err = snd_pcm_plugin_build_mulaw(pb,
+ &srcparams->format,
&tmpparams.format,
&plugin);
}
#ifndef __KERNEL__
else if (srcparams->format.format == SND_PCM_SFMT_A_LAW ||
tmpparams.format.format == SND_PCM_SFMT_A_LAW) {
- err = snd_pcm_plugin_build_alaw(&srcparams->format,
+ err = snd_pcm_plugin_build_alaw(pb,
+ &srcparams->format,
&tmpparams.format,
&plugin);
}
else if (srcparams->format.format == SND_PCM_SFMT_IMA_ADPCM ||
tmpparams.format.format == SND_PCM_SFMT_IMA_ADPCM) {
- err = snd_pcm_plugin_build_adpcm(&srcparams->format,
+ err = snd_pcm_plugin_build_adpcm(pb,
+ &srcparams->format,
&tmpparams.format,
&plugin);
}
#endif
else if (snd_pcm_format_linear(srcparams->format.format) &&
snd_pcm_format_linear(tmpparams.format.format)) {
- err = snd_pcm_plugin_build_linear(&srcparams->format,
+ err = snd_pcm_plugin_build_linear(pb,
+ &srcparams->format,
&tmpparams.format,
&plugin);
}
/* rate resampling */
if (srcparams->format.rate != dstparams.format.rate) {
tmpparams.format.rate = dstparams.format.rate;
- err = snd_pcm_plugin_build_rate(&srcparams->format,
+ err = snd_pcm_plugin_build_rate(pb,
+ &srcparams->format,
&tmpparams.format,
&plugin);
pdprintf("params rate resampling: src=%i, dst=%i return %i\n", srcparams->format.rate, tmpparams.format.rate, err);
/* voices extension */
if (srcparams->format.voices < dstparams.format.voices) {
+#if 0
int sv = srcparams->format.voices;
int dv = dstparams.format.voices;
int *ttable = my_calloc(dv * sv * sizeof(*ttable));
return err;
}
srcparams->format.voices = tmpparams.format.voices;
+#else
+ snd_pcm_plugin_free(plugin);
+ return -EIO;
+#endif
}
/* interleave change */
hwinfo->mode == SND_PCM_MODE_BLOCK &&
srcparams->format.interleave != dstparams.format.interleave) {
tmpparams.format.interleave = dstparams.format.interleave;
- err = snd_pcm_plugin_build_interleave(&srcparams->format,
+ err = snd_pcm_plugin_build_interleave(pb,
+ &srcparams->format,
&tmpparams.format,
&plugin);
pdprintf("params interleave change: src=%i, dst=%i return %i\n", srcparams->format.interleave, tmpparams.format.interleave, err);
EXTRA_LTLIBRARIES = libpcmplugin.la
libpcmplugin_la_SOURCES = block.c mmap.c stream.c linear.c interleave.c \
- mulaw.c alaw.c adpcm.c rate.c route.c
+ mulaw.c alaw.c adpcm.c rate.c
+# route.c
all: libpcmplugin.la
state_ptr->io_shift = 4;
}
-static inline char adpcm_encoder(int sl, adpcm_state_t * state)
+static char adpcm_encoder(int sl, adpcm_state_t * state)
{
short diff; /* Difference between sl and predicted sample */
short pred_diff; /* Predicted difference to next sample */
}
-static inline int adpcm_decoder(unsigned char code, adpcm_state_t * state)
+static int adpcm_decoder(unsigned char code, adpcm_state_t * state)
{
short pred_diff; /* Predicted difference to next sample */
short step; /* holds previous StepSize value */
* Basic Ima-ADPCM plugin
*/
-typedef enum {
- _S8_ADPCM,
- _U8_ADPCM,
- _S16LE_ADPCM,
- _U16LE_ADPCM,
- _S16BE_ADPCM,
- _U16BE_ADPCM,
- _ADPCM_S8,
- _ADPCM_U8,
- _ADPCM_S16LE,
- _ADPCM_U16LE,
- _ADPCM_S16BE,
- _ADPCM_U16BE
-} combination_t;
-
-struct adpcm_private_data {
- combination_t cmd;
- adpcm_state_t state;
-};
-
-static void adpcm_conv_u8bit_adpcm(adpcm_state_t * state_ptr, unsigned char *src_ptr, unsigned char *dst_ptr, size_t size)
-{
- unsigned int pcm;
-
- while (size-- > 0) {
- pcm = ((*src_ptr++) ^ 0x80) << 8;
-
- state_ptr->io_buffer |= adpcm_encoder((signed short)(pcm), state_ptr) << state_ptr->io_shift;
- if (!(state_ptr->io_shift)) {
- *dst_ptr++ = state_ptr->io_buffer & 0xff;
- state_ptr->io_buffer = 0;
- }
- state_ptr->io_shift ^= 4;
- }
- if (!(state_ptr->io_shift)) {
- *dst_ptr = state_ptr->io_buffer & 0xf0;
- }
-}
-
-static void adpcm_conv_s8bit_adpcm(adpcm_state_t * state_ptr, unsigned char *src_ptr, unsigned char *dst_ptr, size_t size)
-{
- unsigned int pcm;
-
- while (size-- > 0) {
- pcm = *src_ptr++ << 8;
-
- state_ptr->io_buffer |= adpcm_encoder((signed short)(pcm), state_ptr) << state_ptr->io_shift;
- if (!(state_ptr->io_shift)) {
- *dst_ptr++ = state_ptr->io_buffer & 0xff;
- state_ptr->io_buffer = 0;
- }
- state_ptr->io_shift ^= 4;
- }
- if (!(state_ptr->io_shift)) {
- *dst_ptr = state_ptr->io_buffer & 0xf0;
- }
-}
-
-static void adpcm_conv_s16bit_adpcm(adpcm_state_t * state_ptr, unsigned short *src_ptr, unsigned char *dst_ptr, size_t size)
-{
- while (size-- > 0) {
- state_ptr->io_buffer |= adpcm_encoder((signed short)(*src_ptr++), state_ptr) << state_ptr->io_shift;
- if (!(state_ptr->io_shift)) {
- *dst_ptr++ = state_ptr->io_buffer & 0xff;
- state_ptr->io_buffer = 0;
- }
- state_ptr->io_shift ^= 4;
- }
- if (!(state_ptr->io_shift)) {
- *dst_ptr = state_ptr->io_buffer & 0xf0;
- }
-}
-
-static void adpcm_conv_s16bit_swap_adpcm(adpcm_state_t * state_ptr, unsigned short *src_ptr, unsigned char *dst_ptr, size_t size)
-{
- while (size-- > 0) {
- state_ptr->io_buffer |= adpcm_encoder((signed short)(bswap_16(*src_ptr++)), state_ptr) << state_ptr->io_shift;
- if (!(state_ptr->io_shift)) {
- *dst_ptr++ = state_ptr->io_buffer & 0xff;
- state_ptr->io_buffer = 0;
- }
- state_ptr->io_shift ^= 4;
- }
- if (!(state_ptr->io_shift)) {
- *dst_ptr = state_ptr->io_buffer & 0xf0;
- }
-}
-
-static void adpcm_conv_u16bit_adpcm(adpcm_state_t * state_ptr, unsigned short *src_ptr, unsigned char *dst_ptr, size_t size)
-{
- while (size-- > 0) {
- state_ptr->io_buffer |= adpcm_encoder((signed short)((*src_ptr++) ^ 0x8000), state_ptr) << state_ptr->io_shift;
- if (!(state_ptr->io_shift)) {
- *dst_ptr++ = state_ptr->io_buffer & 0xff;
- state_ptr->io_buffer = 0;
- }
- state_ptr->io_shift ^= 4;
- }
- if (!(state_ptr->io_shift)) {
- *dst_ptr = state_ptr->io_buffer & 0xf0;
- }
-}
+typedef void (*adpcm_f)(adpcm_state_t *state, void *src_ptr, void *dst_ptr, int samples);
-static void adpcm_conv_u16bit_swap_adpcm(adpcm_state_t * state_ptr, unsigned short *src_ptr, unsigned char *dst_ptr, size_t size)
-{
- while (size-- > 0) {
- state_ptr->io_buffer |= adpcm_encoder((signed short)(bswap_16(*src_ptr++) ^ 0x8000), state_ptr) << state_ptr->io_shift;
- if (!(state_ptr->io_shift)) {
- *dst_ptr++ = state_ptr->io_buffer & 0xff;
- state_ptr->io_buffer = 0;
- }
- state_ptr->io_shift ^= 4;
- }
- if (!(state_ptr->io_shift)) {
- *dst_ptr = state_ptr->io_buffer & 0xf0;
- }
-}
-
-static void adpcm_conv_adpcm_u8bit(adpcm_state_t * state_ptr, unsigned char *src_ptr, unsigned char *dst_ptr, size_t size)
-{
- while (size-- > 0) {
- if (state_ptr->io_shift) {
- state_ptr->io_buffer = *src_ptr++;
- }
- *dst_ptr++ = (adpcm_decoder((state_ptr->io_buffer >> state_ptr->io_shift) & 0xf, state_ptr) >> 8) ^ 0x80;
- state_ptr->io_shift ^= 4;
- }
-}
-
-static void adpcm_conv_adpcm_s8bit(adpcm_state_t * state_ptr, unsigned char *src_ptr, unsigned char *dst_ptr, size_t size)
-{
- while (size-- > 0) {
- if (state_ptr->io_shift) {
- state_ptr->io_buffer = *src_ptr++;
- }
- *dst_ptr++ = adpcm_decoder((state_ptr->io_buffer >> state_ptr->io_shift) & 0xf, state_ptr) >> 8;
- state_ptr->io_shift ^= 4;
- }
-}
-
-static void adpcm_conv_adpcm_s16bit(adpcm_state_t * state_ptr, unsigned char *src_ptr, unsigned short *dst_ptr, size_t size)
-{
- while (size-- > 0) {
- if (state_ptr->io_shift) {
- state_ptr->io_buffer = *src_ptr++;
- }
- *dst_ptr++ = adpcm_decoder((state_ptr->io_buffer >> state_ptr->io_shift) & 0xf, state_ptr);
- state_ptr->io_shift ^= 4;
- }
+typedef struct adpcm_private_data {
+ adpcm_f func;
+ adpcm_state_t state;
+} adpcm_t;
+
+#define ADPCM_FUNC_DECODE(name, dsttype, val) \
+static void adpcm_decode_##name(adpcm_state_t *state, \
+ void *src_ptr, void *dst_ptr, int samples) \
+{ \
+ unsigned char *src = src_ptr; \
+ dsttype *dst = dst_ptr; \
+ unsigned int s; \
+ samples <<= 1; \
+ while (samples--) { \
+ if (state->io_shift) \
+ state->io_buffer = *src++; \
+ s = adpcm_decoder((state->io_buffer >> state->io_shift) & 0x0f, state); \
+ *dst++ = val; \
+ state->io_shift ^= 4; \
+ } \
}
-static void adpcm_conv_adpcm_swap_s16bit(adpcm_state_t * state_ptr, unsigned char *src_ptr, unsigned short *dst_ptr, size_t size)
-{
- while (size-- > 0) {
- if (state_ptr->io_shift) {
- state_ptr->io_buffer = *src_ptr++;
- }
- *dst_ptr++ = bswap_16(adpcm_decoder((state_ptr->io_buffer >> state_ptr->io_shift) & 0xf, state_ptr));
- state_ptr->io_shift ^= 4;
- }
+#define ADPCM_FUNC_ENCODE(name, srctype, val) \
+static void adpcm_encode_##name(adpcm_state_t *state, \
+ void *src_ptr, void *dst_ptr, int samples) \
+{ \
+ srctype *src = src_ptr; \
+ unsigned char *dst = dst_ptr; \
+ unsigned int s; \
+ samples <<= 1; \
+ while (samples--) { \
+ s = *src++; \
+ state->io_buffer |= adpcm_encoder((signed short)(val), state) << state->io_shift; \
+ if (state->io_shift == 0) { \
+ *dst++ = state->io_buffer & 0xff; \
+ state->io_buffer = 0; \
+ } \
+ state->io_shift ^= 4; \
+ } \
}
-static void adpcm_conv_adpcm_u16bit(adpcm_state_t * state_ptr, unsigned char *src_ptr, unsigned short *dst_ptr, size_t size)
-{
- while (size-- > 0) {
- if (state_ptr->io_shift) {
- state_ptr->io_buffer = *src_ptr++;
- }
- *dst_ptr++ = adpcm_decoder((state_ptr->io_buffer >> state_ptr->io_shift) & 0xf, state_ptr) ^ 0x8000;
- state_ptr->io_shift ^= 4;
- }
-}
+ADPCM_FUNC_DECODE(u8, u_int8_t, (s >> 8) ^ 0x80)
+ADPCM_FUNC_DECODE(s8, u_int8_t, s >> 8)
+ADPCM_FUNC_DECODE(u16n, u_int16_t, s ^ 0x8000)
+ADPCM_FUNC_DECODE(u16s, u_int16_t, bswap_16(s ^ 0x8000))
+ADPCM_FUNC_DECODE(s16n, u_int16_t, s)
+ADPCM_FUNC_DECODE(s16s, u_int16_t, bswap_16(s))
+ADPCM_FUNC_DECODE(u24n, u_int32_t, (s << 8) ^ 0x800000)
+ADPCM_FUNC_DECODE(u24s, u_int32_t, bswap_32((s << 8) ^ 0x800000))
+ADPCM_FUNC_DECODE(s24n, u_int32_t, s << 8)
+ADPCM_FUNC_DECODE(s24s, u_int32_t, bswap_32(s << 8))
+ADPCM_FUNC_DECODE(u32n, u_int32_t, (s << 16) ^ 0x80000000)
+ADPCM_FUNC_DECODE(u32s, u_int32_t, bswap_32((s << 16) ^ 0x80000000))
+ADPCM_FUNC_DECODE(s32n, u_int32_t, s << 16)
+ADPCM_FUNC_DECODE(s32s, u_int32_t, bswap_32(s << 16))
+
+ADPCM_FUNC_ENCODE(u8, u_int8_t, s << 8)
+ADPCM_FUNC_ENCODE(s8, u_int8_t, (s << 8) ^ 0x8000)
+ADPCM_FUNC_ENCODE(u16n, u_int16_t, s ^ 0x8000)
+ADPCM_FUNC_ENCODE(u16s, u_int16_t, bswap_16(s ^ 0x8000))
+ADPCM_FUNC_ENCODE(s16n, u_int16_t, s)
+ADPCM_FUNC_ENCODE(s16s, u_int16_t, bswap_16(s))
+ADPCM_FUNC_ENCODE(u24n, u_int32_t, (s ^ 0x800000) >> 8)
+ADPCM_FUNC_ENCODE(u24s, u_int32_t, bswap_32((s ^ 0x800000) >> 8))
+ADPCM_FUNC_ENCODE(s24n, u_int32_t, s >> 8)
+ADPCM_FUNC_ENCODE(s24s, u_int32_t, bswap_32(s >> 8))
+ADPCM_FUNC_ENCODE(u32n, u_int32_t, (s ^ 0x80000000) >> 16)
+ADPCM_FUNC_ENCODE(u32s, u_int32_t, bswap_32((s ^ 0x80000000) >> 16))
+ADPCM_FUNC_ENCODE(s32n, u_int32_t, s >> 16)
+ADPCM_FUNC_ENCODE(s32s, u_int32_t, bswap_32(s >> 16))
+
+/* wide, sign, swap endian */
+static adpcm_f adpcm_functions_decode[4 * 4 * 2 * 2] = {
+ adpcm_decode_u8, /* decode:8-bit:unsigned:none */
+ adpcm_decode_u8, /* decode:8-bit:unsigned:swap */
+ adpcm_decode_s8, /* decode:8-bit:signed:none */
+ adpcm_decode_s8, /* decode:8-bit:signed:swap */
+ adpcm_decode_u16n, /* decode:16-bit:unsigned:none */
+ adpcm_decode_u16s, /* decode:16-bit:unsigned:swap */
+ adpcm_decode_s16n, /* decode:16-bit:signed:none */
+ adpcm_decode_s16s, /* decode:16-bit:signed:swap */
+ adpcm_decode_u24n, /* decode:24-bit:unsigned:none */
+ adpcm_decode_u24s, /* decode:24-bit:unsigned:swap */
+ adpcm_decode_s24n, /* decode:24-bit:signed:none */
+ adpcm_decode_s24s, /* decode:24-bit:signed:swap */
+ adpcm_decode_u32n, /* decode:32-bit:unsigned:none */
+ adpcm_decode_u32s, /* decode:32-bit:unsigned:swap */
+ adpcm_decode_s32n, /* decode:32-bit:signed:none */
+ adpcm_decode_s32s, /* decode:32-bit:signed:swap */
+};
-static void adpcm_conv_adpcm_swap_u16bit(adpcm_state_t * state_ptr, unsigned char *src_ptr, unsigned short *dst_ptr, size_t size)
-{
- while (size-- > 0) {
- if (state_ptr->io_shift) {
- state_ptr->io_buffer = *src_ptr++;
- }
- *dst_ptr++ = bswap_16(adpcm_decoder((state_ptr->io_buffer >> state_ptr->io_shift) & 0xf, state_ptr) ^ 0x8000);
- state_ptr->io_shift ^= 4;
- }
-}
+/* wide, sign, swap endian */
+static adpcm_f adpcm_functions_encode[4 * 2 * 2] = {
+ adpcm_encode_u8, /* encode:8-bit:unsigned:none */
+ adpcm_encode_u8, /* encode:8-bit:unsigned:swap */
+ adpcm_encode_s8, /* encode:8-bit:signed:none */
+ adpcm_encode_s8, /* encode:8-bit:signed:swap */
+ adpcm_encode_u16n, /* encode:16-bit:unsigned:none */
+ adpcm_encode_u16s, /* encode:16-bit:unsigned:swap */
+ adpcm_encode_s16n, /* encode:16-bit:signed:none */
+ adpcm_encode_s16s, /* encode:16-bit:signed:swap */
+ adpcm_encode_u24n, /* encode:24-bit:unsigned:none */
+ adpcm_encode_u24s, /* encode:24-bit:unsigned:swap */
+ adpcm_encode_s24n, /* encode:24-bit:signed:none */
+ adpcm_encode_s24s, /* encode:24-bit:signed:swap */
+ adpcm_encode_u32n, /* encode:32-bit:unsigned:none */
+ adpcm_encode_u32s, /* encode:32-bit:unsigned:swap */
+ adpcm_encode_s32n, /* encode:32-bit:signed:none */
+ adpcm_encode_s32s, /* encode:32-bit:signed:swap */
+};
-static ssize_t adpcm_transfer(snd_pcm_plugin_t * plugin,
- char *src_ptr, size_t src_size,
- char *dst_ptr, size_t dst_size)
+static ssize_t adpcm_transfer(snd_pcm_plugin_t *plugin,
+ const snd_pcm_plugin_voice_t *src_voices,
+ const snd_pcm_plugin_voice_t *dst_voices,
+ size_t samples)
{
- struct adpcm_private_data *data;
+ adpcm_t *data;
+ int voice;
- if (plugin == NULL || src_ptr == NULL || src_size < 0 ||
- dst_ptr == NULL || dst_size < 0)
+ if (plugin == NULL || src_voices == NULL || dst_voices == NULL || samples < 0)
return -EINVAL;
- if (src_size == 0)
+ if (samples == 0)
return 0;
- data = (struct adpcm_private_data *)snd_pcm_plugin_extra_data(plugin);
- if (data == NULL)
- return -EINVAL;
- switch (data->cmd) {
- case _U8_ADPCM:
- if ((dst_size << 1) < src_size)
- return -EINVAL;
- adpcm_conv_u8bit_adpcm(&data->state, src_ptr, dst_ptr, src_size);
- return src_size >> 1;
- case _S8_ADPCM:
- if ((dst_size << 1) < src_size)
- return -EINVAL;
- adpcm_conv_s8bit_adpcm(&data->state, src_ptr, dst_ptr, src_size);
- return src_size >> 1;
- case _S16LE_ADPCM:
- if ((dst_size << 2) < src_size)
- return -EINVAL;
-#if __BYTE_ORDER == __LITTLE_ENDIAN
- adpcm_conv_s16bit_adpcm(&data->state, (short *) src_ptr, dst_ptr, src_size >> 1);
-#elif __BYTE_ORDER == __BIG_ENDIAN
- adpcm_conv_s16bit_swap_adpcm(&data->state, (short *) src_ptr, dst_ptr, src_size >> 1);
-#else
-#error "Have to be coded..."
-#endif
- return src_size >> 2;
- case _U16LE_ADPCM:
- if ((dst_size << 2) < src_size)
- return -EINVAL;
-#if __BYTE_ORDER == __LITTLE_ENDIAN
- adpcm_conv_u16bit_adpcm(&data->state, (short *) src_ptr, dst_ptr, src_size >> 1);
-#elif __BYTE_ORDER == __BIG_ENDIAN
- adpcm_conv_u16bit_swap_adpcm(&data->state, (short *) src_ptr, dst_ptr, src_size >> 1);
-#else
-#error "Have to be coded..."
-#endif
- return src_size >> 2;
- case _S16BE_ADPCM:
- if ((dst_size << 2) < src_size)
- return -EINVAL;
-#if __BYTE_ORDER == __LITTLE_ENDIAN
- adpcm_conv_s16bit_swap_adpcm(&data->state, (short *) src_ptr, dst_ptr, src_size >> 1);
-#elif __BYTE_ORDER == __BIG_ENDIAN
- adpcm_conv_s16bit_adpcm(&data->state, (short *) src_ptr, dst_ptr, src_size >> 1);
-#else
-#error "Have to be coded..."
-#endif
- return src_size >> 2;
- case _U16BE_ADPCM:
- if ((dst_size << 2) < src_size)
- return -EINVAL;
-#if __BYTE_ORDER == __LITTLE_ENDIAN
- adpcm_conv_u16bit_swap_adpcm(&data->state, (short *) src_ptr, dst_ptr, src_size >> 1);
-#elif __BYTE_ORDER == __BIG_ENDIAN
- adpcm_conv_u16bit_adpcm(&data->state, (short *) src_ptr, dst_ptr, src_size >> 1);
-#else
-#error "Have to be coded..."
-#endif
- return src_size >> 2;
- case _ADPCM_U8:
- if ((dst_size >> 1) < src_size)
- return -EINVAL;
- adpcm_conv_adpcm_u8bit(&data->state, src_ptr, dst_ptr, src_size << 1);
- return src_size << 1;
- case _ADPCM_S8:
- if ((dst_size >> 1) < src_size)
- return -EINVAL;
- adpcm_conv_adpcm_s8bit(&data->state, src_ptr, dst_ptr, src_size << 1);
- return src_size << 1;
- case _ADPCM_S16LE:
- if ((dst_size >> 2) < src_size)
- return -EINVAL;
-#if __BYTE_ORDER == __LITTLE_ENDIAN
- adpcm_conv_adpcm_s16bit(&data->state, src_ptr, (short *) dst_ptr, src_size << 1);
-#elif __BYTE_ORDER == __BIG_ENDIAN
- adpcm_conv_adpcm_swap_s16bit(&data->state, src_ptr, (short *) dst_ptr, src_size << 1);
-#else
-#error "Have to be coded..."
-#endif
- return src_size << 2;
- case _ADPCM_U16LE:
- if ((dst_size >> 2) < src_size)
- return -EINVAL;
-#if __BYTE_ORDER == __LITTLE_ENDIAN
- adpcm_conv_adpcm_u16bit(&data->state, src_ptr, (short *) dst_ptr, src_size << 1);
-#elif __BYTE_ORDER == __BIG_ENDIAN
- adpcm_conv_adpcm_swap_u16bit(&data->state, src_ptr, (short *) dst_ptr, src_size << 1);
-#else
-#error "Have to be coded..."
-#endif
- return src_size << 2;
- case _ADPCM_S16BE:
- if ((dst_size >> 2) < src_size)
- return -EINVAL;
-#if __BYTE_ORDER == __LITTLE_ENDIAN
- adpcm_conv_adpcm_swap_s16bit(&data->state, src_ptr, (short *) dst_ptr, src_size << 1);
-#elif __BYTE_ORDER == __BIG_ENDIAN
- adpcm_conv_adpcm_s16bit(&data->state, src_ptr, (short *) dst_ptr, src_size << 1);
-#else
-#error "Have to be coded..."
-#endif
- return src_size << 2;
- case _ADPCM_U16BE:
- if ((dst_size << 2) < src_size)
- return -EINVAL;
-#if __BYTE_ORDER == __LITTLE_ENDIAN
- adpcm_conv_adpcm_swap_u16bit(&data->state, src_ptr, (short *) dst_ptr, src_size << 1);
-#elif __BYTE_ORDER == __BIG_ENDIAN
- adpcm_conv_adpcm_u16bit(&data->state, src_ptr, (short *) dst_ptr, src_size << 1);
-#else
-#error "Have to be coded..."
-#endif
- return src_size << 2;
- default:
- return -EIO;
+ data = (adpcm_t *)plugin->extra_data;
+ /* FIXME */
+ if (plugin->src_format.interleave) {
+ data->func(&data->state,
+ src_voices[0].addr,
+ dst_voices[0].addr,
+ samples * plugin->src_format.voices);
+ } else {
+ for (voice = 0; voice < plugin->src_format.voices; voice++) {
+ if (src_voices[voice].addr == NULL)
+ continue;
+ data->func(&data->state,
+ src_voices[voice].addr,
+ dst_voices[voice].addr,
+ samples);
+ }
}
+ return samples;
}
static int adpcm_action(snd_pcm_plugin_t * plugin,
snd_pcm_plugin_action_t action,
unsigned long udata)
{
- struct adpcm_private_data *data;
+ adpcm_t *data;
if (plugin == NULL)
return -EINVAL;
- data = (struct adpcm_private_data *)snd_pcm_plugin_extra_data(plugin);
+ data = (adpcm_t *)plugin->extra_data;
if (action == PREPARE)
adpcm_init_state(&data->state);
return 0; /* silenty ignore other actions */
}
-static ssize_t adpcm_src_size(snd_pcm_plugin_t * plugin, size_t size)
-{
- struct adpcm_private_data *data;
-
- if (!plugin || size <= 0)
- return -EINVAL;
- data = (struct adpcm_private_data *)snd_pcm_plugin_extra_data(plugin);
- switch (data->cmd) {
- case _U8_ADPCM:
- case _S8_ADPCM:
- return size * 2;
- case _ADPCM_U8:
- case _ADPCM_S8:
- return size / 2;
- case _U16LE_ADPCM:
- case _S16LE_ADPCM:
- case _U16BE_ADPCM:
- case _S16BE_ADPCM:
- return size * 4;
- case _ADPCM_U16LE:
- case _ADPCM_S16LE:
- case _ADPCM_U16BE:
- case _ADPCM_S16BE:
- return size / 4;
- default:
- return -EIO;
- }
-}
-
-static ssize_t adpcm_dst_size(snd_pcm_plugin_t * plugin, size_t size)
-{
- struct adpcm_private_data *data;
-
- if (!plugin || size <= 0)
- return -EINVAL;
- data = (struct adpcm_private_data *)snd_pcm_plugin_extra_data(plugin);
- switch (data->cmd) {
- case _U8_ADPCM:
- case _S8_ADPCM:
- return size / 2;
- case _ADPCM_U8:
- case _ADPCM_S8:
- return size * 2;
- case _U16LE_ADPCM:
- case _S16LE_ADPCM:
- case _U16BE_ADPCM:
- case _S16BE_ADPCM:
- return size / 4;
- case _ADPCM_U16LE:
- case _ADPCM_S16LE:
- case _ADPCM_U16BE:
- case _ADPCM_S16BE:
- return size * 4;
- default:
- return -EIO;
- }
-}
-
-int snd_pcm_plugin_build_adpcm(snd_pcm_format_t * src_format,
- snd_pcm_format_t * dst_format,
- snd_pcm_plugin_t ** r_plugin)
+int snd_pcm_plugin_build_adpcm(snd_pcm_plugin_handle_t *handle,
+ snd_pcm_format_t *src_format,
+ snd_pcm_format_t *dst_format,
+ snd_pcm_plugin_t **r_plugin)
{
struct adpcm_private_data *data;
snd_pcm_plugin_t *plugin;
- combination_t cmd;
+ int endian, src_width, dst_width, sign;
+ adpcm_f func;
if (!r_plugin || !src_format || !dst_format)
return -EINVAL;
return -EINVAL;
if (dst_format->format == SND_PCM_SFMT_IMA_ADPCM) {
- switch (src_format->format) {
- case SND_PCM_SFMT_U8: cmd = _U8_ADPCM; break;
- case SND_PCM_SFMT_S8: cmd = _S8_ADPCM; break;
- case SND_PCM_SFMT_U16_LE: cmd = _U16LE_ADPCM; break;
- case SND_PCM_SFMT_S16_LE: cmd = _S16LE_ADPCM; break;
- case SND_PCM_SFMT_U16_BE: cmd = _U16BE_ADPCM; break;
- case SND_PCM_SFMT_S16_BE: cmd = _S16BE_ADPCM; break;
- default:
+ if (!snd_pcm_format_linear(src_format->format))
return -EINVAL;
- }
+ sign = snd_pcm_format_signed(src_format->format);
+ src_width = snd_pcm_format_width(src_format->format);
+ if ((src_width % 8) != 0 || src_width < 8 || src_width > 32)
+ return -EINVAL;
+ dst_width = 8;
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ endian = snd_pcm_format_big_endian(src_format->format);
+#elif __BYTE_ORDER == __BIG_ENDIAN
+ endian = snd_pcm_format_little_endian(src_format->format);
+#else
+#error "Unsupported endian..."
+#endif
+ func = ((adpcm_f(*)[2][2])adpcm_functions_encode)[src_width/8][sign][endian];
} else if (src_format->format == SND_PCM_SFMT_IMA_ADPCM) {
- switch (dst_format->format) {
- case SND_PCM_SFMT_U8: cmd = _ADPCM_U8; break;
- case SND_PCM_SFMT_S8: cmd = _ADPCM_S8; break;
- case SND_PCM_SFMT_U16_LE: cmd = _ADPCM_U16LE; break;
- case SND_PCM_SFMT_S16_LE: cmd = _ADPCM_S16LE; break;
- case SND_PCM_SFMT_U16_BE: cmd = _ADPCM_U16BE; break;
- case SND_PCM_SFMT_S16_BE: cmd = _ADPCM_S16BE; break;
- default:
+ if (!snd_pcm_format_linear(dst_format->format))
return -EINVAL;
- }
+ sign = snd_pcm_format_signed(dst_format->format);
+ dst_width = snd_pcm_format_width(dst_format->format);
+ if ((dst_width % 8) != 0 || dst_width < 8 || dst_width > 32)
+ return -EINVAL;
+ src_width = 8;
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ endian = snd_pcm_format_big_endian(dst_format->format);
+#elif __BYTE_ORDER == __BIG_ENDIAN
+ endian = snd_pcm_format_little_endian(dst_format->format);
+#else
+#error "Unsupported endian..."
+#endif
+ func = ((adpcm_f(*)[2][2])adpcm_functions_decode)[dst_width/8][sign][endian];
} else {
return -EINVAL;
}
- plugin = snd_pcm_plugin_build("Ima-ADPCM<->linear conversion",
+ plugin = snd_pcm_plugin_build(handle,
+ "Ima-ADPCM<->linear conversion",
+ src_format,
+ dst_format,
sizeof(struct adpcm_private_data));
if (plugin == NULL)
return -ENOMEM;
- data = (struct adpcm_private_data *)snd_pcm_plugin_extra_data(plugin);
- data->cmd = cmd;
+ data = (adpcm_t *)plugin->extra_data;
plugin->transfer = adpcm_transfer;
- plugin->src_size = adpcm_src_size;
- plugin->dst_size = adpcm_dst_size;
plugin->action = adpcm_action;
*r_plugin = plugin;
return 0;
#include <errno.h>
#include <endian.h>
#include <byteswap.h>
+#include <sys/uio.h>
#include "../pcm_local.h"
#define SIGN_BIT (0x80) /* Sign bit for a A-law byte. */
* For further information see John C. Bellamy's Digital Telephony, 1982,
* John Wiley & Sons, pps 98-111 and 472-476.
*/
-static inline unsigned char linear2alaw(int pcm_val) /* 2's complement (16-bit range) */
+static unsigned char linear2alaw(int pcm_val) /* 2's complement (16-bit range) */
{
int mask;
int seg;
* alaw2linear() - Convert an A-law value to 16-bit linear PCM
*
*/
-static inline int alaw2linear(unsigned char a_val)
+static int alaw2linear(unsigned char a_val)
{
int t;
int seg;
* Basic A-Law plugin
*/
-typedef enum {
- _S8_ALAW,
- _U8_ALAW,
- _S16LE_ALAW,
- _U16LE_ALAW,
- _S16BE_ALAW,
- _U16BE_ALAW,
- _ALAW_S8,
- _ALAW_U8,
- _ALAW_S16LE,
- _ALAW_U16LE,
- _ALAW_S16BE,
- _ALAW_U16BE
-} combination_t;
-
-struct alaw_private_data {
- combination_t cmd;
-};
-
-static void alaw_conv_u8bit_alaw(unsigned char *src_ptr, unsigned char *dst_ptr, size_t size)
-{
- unsigned int pcm;
-
- while (size-- > 0) {
- pcm = ((*src_ptr++) ^ 0x80) << 8;
- *dst_ptr++ = linear2alaw((signed short)(pcm));
- }
+typedef void (*alaw_f)(void *src_ptr, void *dst_ptr, int samples);
+
+typedef struct alaw_private_data {
+ int src_byte_width;
+ int dst_byte_width;
+ alaw_f func;
+} alaw_t;
+
+#define ALAW_FUNC_DECODE(name, dsttype, val) \
+static void alaw_decode_##name(void *src_ptr, void *dst_ptr, int samples) \
+{ \
+ unsigned char *src = src_ptr; \
+ dsttype *dst = dst_ptr; \
+ unsigned int s; \
+ while (samples--) { \
+ s = alaw2linear(*src++); \
+ *dst++ = val; \
+ } \
}
-static void alaw_conv_s8bit_alaw(unsigned char *src_ptr, unsigned char *dst_ptr, size_t size)
-{
- unsigned int pcm;
-
- while (size-- > 0) {
- pcm = *src_ptr++ << 8;
- *dst_ptr++ = linear2alaw((signed short)(pcm));
- }
-}
-
-static void alaw_conv_s16bit_alaw(unsigned short *src_ptr, unsigned char *dst_ptr, size_t size)
-{
- while (size-- > 0)
- *dst_ptr++ = linear2alaw((signed short)(*src_ptr++));
-}
-
-static void alaw_conv_s16bit_swap_alaw(unsigned short *src_ptr, unsigned char *dst_ptr, size_t size)
-{
- while (size-- > 0)
- *dst_ptr++ = linear2alaw((signed short)(bswap_16(*src_ptr++)));
-}
-
-static void alaw_conv_u16bit_alaw(unsigned short *src_ptr, unsigned char *dst_ptr, size_t size)
-{
- while (size-- > 0)
- *dst_ptr++ = linear2alaw((signed short)((*src_ptr++) ^ 0x8000));
-}
-
-static void alaw_conv_u16bit_swap_alaw(unsigned short *src_ptr, unsigned char *dst_ptr, size_t size)
-{
- while (size-- > 0)
- *dst_ptr++ = linear2alaw((signed short)(bswap_16(*src_ptr++) ^ 0x8000));
-}
-
-static void alaw_conv_alaw_u8bit(unsigned char *src_ptr, unsigned char *dst_ptr, size_t size)
-{
- while (size-- > 0)
- *dst_ptr++ = (alaw2linear(*src_ptr++) >> 8) ^ 0x80;
-}
-
-static void alaw_conv_alaw_s8bit(unsigned char *src_ptr, unsigned char *dst_ptr, size_t size)
-{
- while (size-- > 0)
- *dst_ptr++ = alaw2linear(*src_ptr++) >> 8;
-}
-
-static void alaw_conv_alaw_s16bit(unsigned char *src_ptr, unsigned short *dst_ptr, size_t size)
-{
- while (size-- > 0)
- *dst_ptr++ = alaw2linear(*src_ptr++);
+#define ALAW_FUNC_ENCODE(name, srctype, val) \
+static void alaw_encode_##name(void *src_ptr, void *dst_ptr, int samples) \
+{ \
+ srctype *src = src_ptr; \
+ unsigned char *dst = dst_ptr; \
+ unsigned int s; \
+ while (samples--) { \
+ s = *src++; \
+ *dst++ = linear2alaw(val); \
+ } \
}
-static void alaw_conv_alaw_swap_s16bit(unsigned char *src_ptr, unsigned short *dst_ptr, size_t size)
-{
- while (size-- > 0)
- *dst_ptr++ = bswap_16(alaw2linear(*src_ptr++));
-}
-
-static void alaw_conv_alaw_u16bit(unsigned char *src_ptr, unsigned short *dst_ptr, size_t size)
-{
- while (size-- > 0)
- *dst_ptr++ = alaw2linear(*src_ptr++) ^ 0x8000;
-}
+ALAW_FUNC_DECODE(u8, u_int8_t, (s >> 8) ^ 0x80)
+ALAW_FUNC_DECODE(s8, u_int8_t, s >> 8)
+ALAW_FUNC_DECODE(u16n, u_int16_t, s ^ 0x8000)
+ALAW_FUNC_DECODE(u16s, u_int16_t, bswap_16(s ^ 0x8000))
+ALAW_FUNC_DECODE(s16n, u_int16_t, s)
+ALAW_FUNC_DECODE(s16s, u_int16_t, bswap_16(s))
+ALAW_FUNC_DECODE(u24n, u_int32_t, (s << 8) ^ 0x800000)
+ALAW_FUNC_DECODE(u24s, u_int32_t, bswap_32((s << 8) ^ 0x800000))
+ALAW_FUNC_DECODE(s24n, u_int32_t, s << 8)
+ALAW_FUNC_DECODE(s24s, u_int32_t, bswap_32(s << 8))
+ALAW_FUNC_DECODE(u32n, u_int32_t, (s << 16) ^ 0x80000000)
+ALAW_FUNC_DECODE(u32s, u_int32_t, bswap_32((s << 16) ^ 0x80000000))
+ALAW_FUNC_DECODE(s32n, u_int32_t, s << 16)
+ALAW_FUNC_DECODE(s32s, u_int32_t, bswap_32(s << 16))
+
+ALAW_FUNC_ENCODE(u8, u_int8_t, s << 8)
+ALAW_FUNC_ENCODE(s8, u_int8_t, (s << 8) ^ 0x8000)
+ALAW_FUNC_ENCODE(u16n, u_int16_t, s ^ 0x8000)
+ALAW_FUNC_ENCODE(u16s, u_int16_t, bswap_16(s ^ 0x8000))
+ALAW_FUNC_ENCODE(s16n, u_int16_t, s)
+ALAW_FUNC_ENCODE(s16s, u_int16_t, bswap_16(s))
+ALAW_FUNC_ENCODE(u24n, u_int32_t, (s ^ 0x800000) >> 8)
+ALAW_FUNC_ENCODE(u24s, u_int32_t, bswap_32((s ^ 0x800000) >> 8))
+ALAW_FUNC_ENCODE(s24n, u_int32_t, s >> 8)
+ALAW_FUNC_ENCODE(s24s, u_int32_t, bswap_32(s >> 8))
+ALAW_FUNC_ENCODE(u32n, u_int32_t, (s ^ 0x80000000) >> 16)
+ALAW_FUNC_ENCODE(u32s, u_int32_t, bswap_32((s ^ 0x80000000) >> 16))
+ALAW_FUNC_ENCODE(s32n, u_int32_t, s >> 16)
+ALAW_FUNC_ENCODE(s32s, u_int32_t, bswap_32(s >> 16))
+
+/* wide, sign, swap endian */
+static alaw_f alaw_functions_decode[4 * 2 * 2] = {
+ alaw_decode_u8, /* decode:8-bit:unsigned:none */
+ alaw_decode_u8, /* decode:8-bit:unsigned:swap */
+ alaw_decode_s8, /* decode:8-bit:signed:none */
+ alaw_decode_s8, /* decode:8-bit:signed:swap */
+ alaw_decode_u16n, /* decode:16-bit:unsigned:none */
+ alaw_decode_u16s, /* decode:16-bit:unsigned:swap */
+ alaw_decode_s16n, /* decode:16-bit:signed:none */
+ alaw_decode_s16s, /* decode:16-bit:signed:swap */
+ alaw_decode_u24n, /* decode:24-bit:unsigned:none */
+ alaw_decode_u24s, /* decode:24-bit:unsigned:swap */
+ alaw_decode_s24n, /* decode:24-bit:signed:none */
+ alaw_decode_s24s, /* decode:24-bit:signed:swap */
+ alaw_decode_u32n, /* decode:32-bit:unsigned:none */
+ alaw_decode_u32s, /* decode:32-bit:unsigned:swap */
+ alaw_decode_s32n, /* decode:32-bit:signed:none */
+ alaw_decode_s32s, /* decode:32-bit:signed:swap */
+};
-static void alaw_conv_alaw_swap_u16bit(unsigned char *src_ptr, unsigned short *dst_ptr, size_t size)
-{
- while (size-- > 0)
- *dst_ptr++ = bswap_16(alaw2linear(*src_ptr++) ^ 0x8000);
-}
+/* wide, sign, swap endian */
+static alaw_f alaw_functions_encode[4 * 2 * 2] = {
+ alaw_encode_u8, /* encode:8-bit:unsigned:none */
+ alaw_encode_u8, /* encode:8-bit:unsigned:swap */
+ alaw_encode_s8, /* encode:8-bit:signed:none */
+ alaw_encode_s8, /* encode:8-bit:signed:swap */
+ alaw_encode_u16n, /* encode:16-bit:unsigned:none */
+ alaw_encode_u16s, /* encode:16-bit:unsigned:swap */
+ alaw_encode_s16n, /* encode:16-bit:signed:none */
+ alaw_encode_s16s, /* encode:16-bit:signed:swap */
+ alaw_encode_u24n, /* encode:24-bit:unsigned:none */
+ alaw_encode_u24s, /* encode:24-bit:unsigned:swap */
+ alaw_encode_s24n, /* encode:24-bit:signed:none */
+ alaw_encode_s24s, /* encode:24-bit:signed:swap */
+ alaw_encode_u32n, /* encode:32-bit:unsigned:none */
+ alaw_encode_u32s, /* encode:32-bit:unsigned:swap */
+ alaw_encode_s32n, /* encode:32-bit:signed:none */
+ alaw_encode_s32s, /* encode:32-bit:signed:swap */
+};
static ssize_t alaw_transfer(snd_pcm_plugin_t *plugin,
- char *src_ptr, size_t src_size,
- char *dst_ptr, size_t dst_size)
+ const snd_pcm_plugin_voice_t *src_voices,
+ const snd_pcm_plugin_voice_t *dst_voices,
+ size_t samples)
{
- struct alaw_private_data *data;
+ alaw_t *data;
+ int voice;
- if (plugin == NULL || src_ptr == NULL || src_size < 0 ||
- dst_ptr == NULL || dst_size < 0)
+ if (plugin == NULL || src_voices == NULL || dst_voices == NULL || samples < 0)
return -EINVAL;
- if (src_size == 0)
+ if (samples == 0)
return 0;
- data = (struct alaw_private_data *)snd_pcm_plugin_extra_data(plugin);
- if (data == NULL)
- return -EINVAL;
- switch (data->cmd) {
- case _U8_ALAW:
- if (dst_size < src_size)
- return -EINVAL;
- alaw_conv_u8bit_alaw(src_ptr, dst_ptr, src_size);
- return src_size;
- case _S8_ALAW:
- if (dst_size < src_size)
- return -EINVAL;
- alaw_conv_s8bit_alaw(src_ptr, dst_ptr, src_size);
- return src_size;
- case _S16LE_ALAW:
- if ((dst_size << 1) < src_size)
- return -EINVAL;
-#if __BYTE_ORDER == __LITTLE_ENDIAN
- alaw_conv_s16bit_alaw((short *)src_ptr, dst_ptr, src_size >> 1);
-#elif __BYTE_ORDER == __BIG_ENDIAN
- alaw_conv_s16bit_swap_alaw((short *)src_ptr, dst_ptr, src_size >> 1);
-#else
-#error "Have to be coded..."
-#endif
- return src_size >> 1;
- case _U16LE_ALAW:
- if ((dst_size << 1) < src_size)
- return -EINVAL;
-#if __BYTE_ORDER == __LITTLE_ENDIAN
- alaw_conv_u16bit_alaw((short *)src_ptr, dst_ptr, src_size >> 1);
-#elif __BYTE_ORDER == __BIG_ENDIAN
- alaw_conv_u16bit_swap_alaw((short *)src_ptr, dst_ptr, src_size >> 1);
-#else
-#error "Have to be coded..."
-#endif
- return src_size >> 1;
- case _S16BE_ALAW:
- if ((dst_size << 1) < src_size)
- return -EINVAL;
-#if __BYTE_ORDER == __LITTLE_ENDIAN
- alaw_conv_s16bit_swap_alaw((short *)src_ptr, dst_ptr, src_size >> 1);
-#elif __BYTE_ORDER == __BIG_ENDIAN
- alaw_conv_s16bit_alaw((short *)src_ptr, dst_ptr, src_size >> 1);
-#else
-#error "Have to be coded..."
-#endif
- return src_size >> 1;
- case _U16BE_ALAW:
- if ((dst_size << 1) < src_size)
- return -EINVAL;
-#if __BYTE_ORDER == __LITTLE_ENDIAN
- alaw_conv_u16bit_swap_alaw((short *)src_ptr, dst_ptr, src_size >> 1);
-#elif __BYTE_ORDER == __BIG_ENDIAN
- alaw_conv_u16bit_alaw((short *)src_ptr, dst_ptr, src_size >> 1);
-#else
-#error "Have to be coded..."
-#endif
- return src_size >> 1;
- case _ALAW_U8:
- if (dst_size < src_size)
- return -EINVAL;
- alaw_conv_alaw_u8bit(src_ptr, dst_ptr, src_size);
- return src_size;
- case _ALAW_S8:
- if (dst_size < src_size)
- return -EINVAL;
- alaw_conv_alaw_s8bit(src_ptr, dst_ptr, src_size);
- return src_size;
- case _ALAW_S16LE:
- if ((dst_size >> 1) < src_size)
- return -EINVAL;
-#if __BYTE_ORDER == __LITTLE_ENDIAN
- alaw_conv_alaw_s16bit(src_ptr, (short *)dst_ptr, src_size);
-#elif __BYTE_ORDER == __BIG_ENDIAN
- alaw_conv_alaw_swap_s16bit(src_ptr, (short *)dst_ptr, src_size);
-#else
-#error "Have to be coded..."
-#endif
- return src_size << 1;
- case _ALAW_U16LE:
- if ((dst_size >> 1) < src_size)
- return -EINVAL;
-#if __BYTE_ORDER == __LITTLE_ENDIAN
- alaw_conv_alaw_u16bit(src_ptr, (short *)dst_ptr, src_size);
-#elif __BYTE_ORDER == __BIG_ENDIAN
- alaw_conv_alaw_swap_u16bit(src_ptr, (short *)dst_ptr, src_size);
-#else
-#error "Have to be coded..."
-#endif
- return src_size << 1;
- case _ALAW_S16BE:
- if ((dst_size >> 1) < src_size)
- return -EINVAL;
-#if __BYTE_ORDER == __LITTLE_ENDIAN
- alaw_conv_alaw_swap_s16bit(src_ptr, (short *)dst_ptr, src_size);
-#elif __BYTE_ORDER == __BIG_ENDIAN
- alaw_conv_alaw_s16bit(src_ptr, (short *)dst_ptr, src_size);
-#else
-#error "Have to be coded..."
-#endif
- return src_size << 1;
- case _ALAW_U16BE:
- if ((dst_size >> 1) < src_size)
- return -EINVAL;
-#if __BYTE_ORDER == __LITTLE_ENDIAN
- alaw_conv_alaw_swap_u16bit(src_ptr, (short *)dst_ptr, src_size);
-#elif __BYTE_ORDER == __BIG_ENDIAN
- alaw_conv_alaw_u16bit(src_ptr, (short *)dst_ptr, src_size);
-#else
-#error "Have to be coded..."
-#endif
- return src_size << 1;
- default:
- return -EIO;
- }
-}
-
-static ssize_t alaw_src_size(snd_pcm_plugin_t *plugin, size_t size)
-{
- struct alaw_private_data *data;
-
- if (!plugin || size <= 0)
- return -EINVAL;
- data = (struct alaw_private_data *)snd_pcm_plugin_extra_data(plugin);
- switch (data->cmd) {
- case _U8_ALAW:
- case _S8_ALAW:
- case _ALAW_U8:
- case _ALAW_S8:
- return size;
- case _U16LE_ALAW:
- case _S16LE_ALAW:
- case _U16BE_ALAW:
- case _S16BE_ALAW:
- return size * 2;
- case _ALAW_U16LE:
- case _ALAW_S16LE:
- case _ALAW_U16BE:
- case _ALAW_S16BE:
- return size / 2;
- default:
- return -EIO;
- }
+ data = (alaw_t *)plugin->extra_data;
+ if (plugin->src_format.interleave) {
+ data->func(src_voices[0].addr,
+ dst_voices[0].addr,
+ samples * plugin->src_format.voices);
+ } else {
+ for (voice = 0; voice < plugin->src_format.voices; voice++) {
+ if (src_voices[voice].addr == NULL)
+ continue;
+ data->func(src_voices[voice].addr,
+ dst_voices[voice].addr,
+ samples);
+ }
+ }
+ return samples;
}
-static ssize_t alaw_dst_size(snd_pcm_plugin_t *plugin, size_t size)
-{
- struct alaw_private_data *data;
-
- if (!plugin || size <= 0)
- return -EINVAL;
- data = (struct alaw_private_data *)snd_pcm_plugin_extra_data(plugin);
- switch (data->cmd) {
- case _U8_ALAW:
- case _S8_ALAW:
- case _ALAW_U8:
- case _ALAW_S8:
- return size;
- case _U16LE_ALAW:
- case _S16LE_ALAW:
- case _U16BE_ALAW:
- case _S16BE_ALAW:
- return size / 2;
- case _ALAW_U16LE:
- case _ALAW_S16LE:
- case _ALAW_U16BE:
- case _ALAW_S16BE:
- return size * 2;
- default:
- return -EIO;
- }
-}
-
-int snd_pcm_plugin_build_alaw(snd_pcm_format_t *src_format,
+int snd_pcm_plugin_build_alaw(snd_pcm_plugin_handle_t *handle,
+ snd_pcm_format_t *src_format,
snd_pcm_format_t *dst_format,
snd_pcm_plugin_t **r_plugin)
{
struct alaw_private_data *data;
snd_pcm_plugin_t *plugin;
- combination_t cmd;
+ int endian, src_width, dst_width, sign;
+ alaw_f func;
- if (!r_plugin)
+ if (r_plugin == NULL)
return -EINVAL;
*r_plugin = NULL;
if (src_format->voices != dst_format->voices)
return -EINVAL;
- if (dst_format->format == SND_PCM_SFMT_A_LAW) {
- switch (src_format->format) {
- case SND_PCM_SFMT_U8: cmd = _U8_ALAW; break;
- case SND_PCM_SFMT_S8: cmd = _S8_ALAW; break;
- case SND_PCM_SFMT_U16_LE: cmd = _U16LE_ALAW; break;
- case SND_PCM_SFMT_S16_LE: cmd = _S16LE_ALAW; break;
- case SND_PCM_SFMT_U16_BE: cmd = _U16BE_ALAW; break;
- case SND_PCM_SFMT_S16_BE: cmd = _S16BE_ALAW; break;
- default:
+ if (dst_format->format == SND_PCM_SFMT_MU_LAW) {
+ if (!snd_pcm_format_linear(src_format->format))
return -EINVAL;
- }
- } else if (src_format->format == SND_PCM_SFMT_A_LAW) {
- switch (dst_format->format) {
- case SND_PCM_SFMT_U8: cmd = _ALAW_U8; break;
- case SND_PCM_SFMT_S8: cmd = _ALAW_S8; break;
- case SND_PCM_SFMT_U16_LE: cmd = _ALAW_U16LE; break;
- case SND_PCM_SFMT_S16_LE: cmd = _ALAW_S16LE; break;
- case SND_PCM_SFMT_U16_BE: cmd = _ALAW_U16BE; break;
- case SND_PCM_SFMT_S16_BE: cmd = _ALAW_S16BE; break;
- default:
+ sign = snd_pcm_format_signed(src_format->format);
+ src_width = snd_pcm_format_width(src_format->format);
+ if ((src_width % 8) != 0 || src_width < 8 || src_width > 32)
return -EINVAL;
- }
+ dst_width = 8;
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ endian = snd_pcm_format_big_endian(src_format->format);
+#elif __BYTE_ORDER == __BIG_ENDIAN
+ endian = snd_pcm_format_little_endian(src_format->format);
+#else
+#error "Unsupported endian..."
+#endif
+ func = ((alaw_f(*)[2][2])alaw_functions_encode)[(src_width/8)-1][sign][endian];
+ } else if (src_format->format == SND_PCM_SFMT_MU_LAW) {
+ if (!snd_pcm_format_linear(dst_format->format))
+ return -EINVAL;
+ sign = snd_pcm_format_signed(dst_format->format);
+ dst_width = snd_pcm_format_width(dst_format->format);
+ if ((dst_width % 8) != 0 || dst_width < 8 || dst_width > 32)
+ return -EINVAL;
+ src_width = 8;
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ endian = snd_pcm_format_big_endian(dst_format->format);
+#elif __BYTE_ORDER == __BIG_ENDIAN
+ endian = snd_pcm_format_little_endian(dst_format->format);
+#else
+#error "Unsupported endian..."
+#endif
+ func = ((alaw_f(*)[2][2])alaw_functions_decode)[(dst_width/8)-1][sign][endian];
} else {
return -EINVAL;
}
- plugin = snd_pcm_plugin_build("A-Law<->linear conversion",
+ plugin = snd_pcm_plugin_build(handle,
+ "A-Law<->linear conversion",
+ src_format,
+ dst_format,
sizeof(struct alaw_private_data));
if (plugin == NULL)
return -ENOMEM;
- data = (struct alaw_private_data *)snd_pcm_plugin_extra_data(plugin);
- data->cmd = cmd;
+ data = (struct alaw_private_data *)plugin->extra_data;
+ data->src_byte_width = src_width / 8;
+ data->dst_byte_width = dst_width / 8;
+ data->func = func;
plugin->transfer = alaw_transfer;
- plugin->src_size = alaw_src_size;
- plugin->dst_size = alaw_dst_size;
*r_plugin = plugin;
return 0;
}
#include <unistd.h>
#include <string.h>
#include <errno.h>
+#include <sys/uio.h>
#include "../pcm_local.h"
/*
* Basic block plugin
*/
-struct block_private_data {
- snd_pcm_t *pcm;
+typedef struct block_private_data {
int channel;
-};
+} block_t;
static ssize_t block_transfer(snd_pcm_plugin_t *plugin,
- char *src_ptr, size_t src_size,
- char *dst_ptr, size_t dst_size)
+ const snd_pcm_plugin_voice_t *src_voices,
+ const snd_pcm_plugin_voice_t *dst_voices,
+ size_t samples)
{
- struct block_private_data *data;
+ block_t *data;
+ ssize_t result;
+ struct iovec *vec;
+ int count, voice;
- if (plugin == NULL || dst_ptr == NULL || dst_size <= 0)
- return -EINVAL;
- data = (struct block_private_data *)snd_pcm_plugin_extra_data(plugin);
+ if (plugin == NULL)
+ return -EINVAL;
+ data = (block_t *)plugin->extra_data;
if (data == NULL)
return -EINVAL;
+ vec = (struct iovec *)((char *)data + sizeof(*data));
if (data->channel == SND_PCM_CHANNEL_PLAYBACK) {
- return snd_pcm_write(data->pcm, dst_ptr, dst_size);
+ if (src_voices == NULL)
+ return -EINVAL;
+ if ((result = snd_pcm_plugin_src_samples_to_size(plugin, samples)) < 0)
+ return result;
+ if (plugin->src_format.interleave) {
+ vec->iov_base = src_voices->addr;
+ vec->iov_len = result;
+ count = 1;
+ } else {
+ count = plugin->src_format.voices;
+ result /= count;
+ for (voice = 0; voice < count; voice++) {
+ vec[voice].iov_base = src_voices[voice].addr;
+ vec[voice].iov_len = result;
+ }
+ }
+ result = snd_pcm_writev(plugin->handle, vec, count);
+ if (result < 0)
+ return result;
+ return snd_pcm_plugin_src_size_to_samples(plugin, result);
} else if (data->channel == SND_PCM_CHANNEL_CAPTURE) {
- return snd_pcm_read(data->pcm, dst_ptr, dst_size);
+ if (dst_voices == NULL)
+ return -EINVAL;
+ if ((result = snd_pcm_plugin_dst_samples_to_size(plugin, samples)) < 0)
+ return result;
+ if (plugin->dst_format.interleave) {
+ vec->iov_base = dst_voices->addr;
+ vec->iov_len = result;
+ count = 1;
+ } else {
+ count = plugin->dst_format.voices;
+ result /= count;
+ for (voice = 0; voice < count; voice++) {
+ vec[voice].iov_base = dst_voices[voice].addr;
+ vec[voice].iov_len = result;
+ }
+ }
+ result = snd_pcm_readv(plugin->handle, vec, count);
+ return snd_pcm_plugin_dst_size_to_samples(plugin, result);
} else {
return -EINVAL;
}
}
-int snd_pcm_plugin_build_block(snd_pcm_t *pcm, int channel, snd_pcm_plugin_t **r_plugin)
+int snd_pcm_plugin_build_block(snd_pcm_t *pcm, int channel,
+ snd_pcm_format_t *format,
+ snd_pcm_plugin_t **r_plugin)
{
- struct block_private_data *data;
+ block_t *data;
snd_pcm_plugin_t *plugin;
if (r_plugin == NULL)
return -EINVAL;
*r_plugin = NULL;
- if (!pcm || channel < 0 || channel > 1)
+ if (pcm == NULL || channel < 0 || channel > 1 || format == NULL)
return -EINVAL;
- plugin = snd_pcm_plugin_build(channel == SND_PCM_CHANNEL_PLAYBACK ?
+ plugin = snd_pcm_plugin_build(pcm,
+ channel == SND_PCM_CHANNEL_PLAYBACK ?
"I/O block playback" :
"I/O block capture",
- sizeof(struct block_private_data));
+ format, format,
+ sizeof(block_t) + sizeof(struct iovec) * format->voices);
if (plugin == NULL)
return -ENOMEM;
- data = (struct block_private_data *)snd_pcm_plugin_extra_data(plugin);
- data->pcm = pcm;
+ data = (block_t *)plugin->extra_data;
data->channel = channel;
plugin->transfer = block_transfer;
*r_plugin = plugin;
/*
* Interleave / non-interleave conversion Plug-In
- * Copyright (c) 2000 by Abramo Bagnara <abbagnara@racine.ra.it>
+ * Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>,
+ * Jaroslav Kysela <perex@suse.cz>
*
*
* This library is free software; you can redistribute it and/or modify
#include <errno.h>
#include <endian.h>
#include <byteswap.h>
+#include <sys/uio.h>
#include "../pcm_local.h"
#endif
* Basic interleave / non-interleave conversion plugin
*/
-typedef void (*interleave_f)(void* src_ptr, void* dst_ptr,
+typedef void (*interleave_f)(const snd_pcm_plugin_voice_t *src_voices,
+ const snd_pcm_plugin_voice_t *dst_voices,
int voices, size_t samples);
-struct interleave_private_data {
- int sample_size;
- int voices;
+typedef struct interleave_private_data {
interleave_f func;
-};
+} interleave_t;
#define INTERLEAVE_FUNC(name, type) \
-static void name(void* src_ptr, void* dst_ptr, \
- int voices, size_t samples) \
+static void name(const snd_pcm_plugin_voice_t *src_voices, \
+ const snd_pcm_plugin_voice_t *dst_voices, \
+ int voices, size_t samples) \
{ \
- type* src = src_ptr; \
- int voice; \
- for (voice = 0; voice < voices; ++voice) { \
- type *dst = (type*)dst_ptr + voice; \
- int s; \
- for (s = 0; s < samples; ++s) { \
- *dst = *src; \
- src++; \
+ type *src, *dst; \
+ int voice, sample; \
+ for (voice = 0; voice < voices; voice++) { \
+ src = (type *)src_voices[voice].addr; \
+ dst = (type *)dst_voices[voice].addr + voice; \
+ for (sample = 0; sample < samples; sample++) { \
+ *dst = *src++; \
dst += voices; \
} \
} \
} \
#define DEINTERLEAVE_FUNC(name, type) \
-static void name(void* src_ptr, void* dst_ptr, \
- int voices, size_t samples) \
+static void name(const snd_pcm_plugin_voice_t *src_voices, \
+ const snd_pcm_plugin_voice_t *dst_voices, \
+ int voices, size_t samples) \
{ \
- type* dst = dst_ptr; \
- int voice; \
- for (voice = 0; voice < voices; ++voice) { \
- type *src = (type*)src_ptr + voice; \
- int s; \
- for (s = 0; s < samples; ++s) { \
- *dst = *src; \
- dst++; \
+ type *src, *dst; \
+ int voice, sample; \
+ for (voice = 0; voice < voices; voice++) { \
+ src = (type *)src_voices[voice].addr + voice; \
+ dst = (type *)dst_voices[voice].addr; \
+ for (sample = 0; sample < samples; sample++) { \
+ *dst++ = *src; \
src += voices; \
} \
} \
FUNCS(8, int64_t);
static ssize_t interleave_transfer(snd_pcm_plugin_t *plugin,
- char *src_ptr, size_t src_size,
- char *dst_ptr, size_t dst_size)
+ const snd_pcm_plugin_voice_t *src_voices,
+ const snd_pcm_plugin_voice_t *dst_voices,
+ size_t samples)
{
- struct interleave_private_data *data;
+ interleave_t *data;
- if (plugin == NULL || src_ptr == NULL || src_size < 0 ||
- dst_ptr == NULL || dst_size < 0)
+ if (plugin == NULL || src_voices == NULL || src_voices == NULL || samples < 0)
return -EINVAL;
- if (src_size == 0)
+ if (samples == 0)
return 0;
- if (src_size != dst_size)
- return -EINVAL;
- data = (struct interleave_private_data *)snd_pcm_plugin_extra_data(plugin);
+ data = (interleave_t *)plugin->extra_data;
if (data == NULL)
return -EINVAL;
- data->func(src_ptr, dst_ptr, data->voices,
- src_size / (data->voices * data->sample_size));
- return src_size;
+ data->func(src_voices, dst_voices, plugin->src_format.voices, samples);
+ return samples;
}
-int snd_pcm_plugin_build_interleave(snd_pcm_format_t *src_format,
+int snd_pcm_plugin_build_interleave(snd_pcm_plugin_handle_t *handle,
+ snd_pcm_format_t *src_format,
snd_pcm_format_t *dst_format,
snd_pcm_plugin_t **r_plugin)
{
struct interleave_private_data *data;
snd_pcm_plugin_t *plugin;
interleave_f func;
- int size;
- if (r_plugin == NULL)
+ if (r_plugin == NULL || src_format == NULL || dst_format == NULL)
return -EINVAL;
*r_plugin = NULL;
return -EINVAL;
if (src_format->voices != dst_format->voices)
return -EINVAL;
- size = snd_pcm_format_size(dst_format->format, 1);
- if (dst_format->interleave) {
- switch (size) {
- case 1:
+ if (!src_format->interleave) {
+ switch (snd_pcm_format_width(src_format->format)) {
+ case 8:
func = int_1;
break;
- case 2:
+ case 16:
func = int_2;
break;
- case 4:
+ case 32:
func = int_4;
break;
- case 8:
+ case 64:
func = int_8;
break;
default:
return -EINVAL;
}
} else {
- switch (size) {
- case 1:
+ switch (snd_pcm_format_width(src_format->format)) {
+ case 8:
func = deint_1;
break;
- case 2:
+ case 16:
func = deint_2;
break;
- case 4:
+ case 32:
func = deint_4;
break;
- case 8:
+ case 64:
func = deint_8;
break;
default:
}
}
- plugin = snd_pcm_plugin_build("interleave conversion",
- sizeof(struct interleave_private_data));
+ plugin = snd_pcm_plugin_build(handle,
+ "interleave conversion",
+ src_format, dst_format,
+ sizeof(interleave_t));
if (plugin == NULL)
return -ENOMEM;
- data = (struct interleave_private_data *)snd_pcm_plugin_extra_data(plugin);
- data->sample_size = size;
- data->voices = src_format->voices;
+ data = (interleave_t *)plugin->extra_data;
data->func = func;
plugin->transfer = interleave_transfer;
*r_plugin = plugin;
/*
* Linear conversion Plug-In
- * Copyright (c) 1999 by Jaroslav Kysela <perex@suse.cz>
+ * Copyright (c) 1999 by Jaroslav Kysela <perex@suse.cz>,
+ * Abramo Bagnara <abramo@alsa-project.org>
*
*
* This library is free software; you can redistribute it and/or modify
#include <errno.h>
#include <endian.h>
#include <byteswap.h>
+#include <sys/uio.h>
#include "../pcm_local.h"
#endif
typedef void (*linear_f)(void *src, void *dst, size_t size);
-struct linear_private_data {
+typedef struct linear_private_data {
int src_sample_size, dst_sample_size;
linear_f func;
-};
+} linear_t;
#define LIN_FUNC(name, srctype, dsttype, val) \
static void lin_##name(void *src_ptr, void *dst_ptr, size_t size) \
LIN_FUNC(32_end_sign_end, u_int32_t, u_int32_t, src ^ 0x80)
/* src_wid dst_wid src_endswap, dst_endswap, sign_swap */
-linear_f linear_functions[4 * 4 * 2 * 2 * 2] = {
+static linear_f linear_functions[4 * 4 * 2 * 2 * 2] = {
NULL, /* 8->8: Nothing to do */
lin_8_sign, /* 8->8 sign: lin_8_sign */
NULL, /* 8->8 dst_end: Nothing to do */
static ssize_t linear_transfer(snd_pcm_plugin_t *plugin,
- char *src_ptr, size_t src_size,
- char *dst_ptr, size_t dst_size)
+ const snd_pcm_plugin_voice_t *src_voices,
+ const snd_pcm_plugin_voice_t *dst_voices,
+ size_t samples)
{
- struct linear_private_data *data;
+ linear_t *data;
+ int voice;
+ ssize_t result;
- if (plugin == NULL || src_ptr == NULL || src_size < 0 ||
- dst_ptr == NULL || dst_size < 0)
+ if (plugin == NULL || src_voices == NULL || dst_voices == NULL || samples < 0)
return -EINVAL;
- if (src_size == 0)
+ if (samples == 0)
return 0;
- data = (struct linear_private_data *)snd_pcm_plugin_extra_data(plugin);
- if (data == NULL)
- return -EINVAL;
- if (src_size % data->src_sample_size != 0)
- return -EINVAL;
- if (dst_size < src_size*data->dst_sample_size/data->src_sample_size)
- return -EINVAL;
- data->func(src_ptr, dst_ptr, src_size / data->src_sample_size);
- return src_size*data->dst_sample_size/data->src_sample_size;
-}
-
-static ssize_t linear_src_size(snd_pcm_plugin_t *plugin, size_t size)
-{
- struct linear_private_data *data;
-
- if (plugin == NULL || size <= 0)
- return -EINVAL;
- data = (struct linear_private_data *)snd_pcm_plugin_extra_data(plugin);
- if (data == NULL)
- return -EINVAL;
- return size*data->src_sample_size/data->dst_sample_size;
-}
-
-static ssize_t linear_dst_size(snd_pcm_plugin_t *plugin, size_t size)
-{
- struct linear_private_data *data;
-
- if (plugin == NULL || size <= 0)
- return -EINVAL;
- data = (struct linear_private_data *)snd_pcm_plugin_extra_data(plugin);
- if (data == NULL)
- return -EINVAL;
- return size*data->dst_sample_size/data->src_sample_size;
+ data = (linear_t *)plugin->extra_data;
+ for (voice = 0, result = 0; voice < plugin->src_format.voices; voice++) {
+ if (src_voices[voice].addr == NULL)
+ continue;
+ if (dst_voices[voice].addr == NULL)
+ return -EINVAL;
+ data->func(src_voices[voice].addr,
+ dst_voices[voice].addr,
+ samples);
+ }
+ return samples;
}
-int snd_pcm_plugin_build_linear(snd_pcm_format_t *src_format,
+int snd_pcm_plugin_build_linear(snd_pcm_plugin_handle_t *handle,
+ snd_pcm_format_t *src_format,
snd_pcm_format_t *dst_format,
snd_pcm_plugin_t **r_plugin)
{
snd_pcm_plugin_t *plugin;
linear_f func;
int src_endian, dst_endian, sign, src_width, dst_width;
- int src_sample_size, dst_sample_size;
if (r_plugin == NULL)
return -EINVAL;
#error "Unsupported endian..."
#endif
- switch (src_width) {
- case 8:
- src_width = 0;
- src_sample_size = 1;
- break;
- case 16:
- src_width = 1;
- src_sample_size = 2;
- break;
- case 24:
- src_width = 2;
- src_sample_size = 4;
- break;
- case 32:
- src_width = 3;
- src_sample_size = 4;
- break;
- default:
- return -EINVAL;
- }
- switch (dst_width) {
- case 8:
- dst_width = 0;
- dst_sample_size = 1;
- break;
- case 16:
- dst_width = 1;
- dst_sample_size = 2;
- break;
- case 24:
- dst_width = 2;
- dst_sample_size = 4;
- break;
- case 32:
- dst_width = 3;
- dst_sample_size = 4;
- break;
- default:
- return -EINVAL;
- }
+ src_width = snd_pcm_format_width(src_format->format);
+ if (src_width < 0)
+ return src_width;
+ src_width /= 8;
+ src_width--;
+
+ dst_width = snd_pcm_format_width(dst_format->format);
+ if (dst_width < 0)
+ return dst_width;
+ dst_width /= 8;
+ dst_width--;
if (src_endian < 0)
src_endian = 0;
if (func == NULL)
return -EINVAL;
- plugin = snd_pcm_plugin_build("linear format conversion",
- sizeof(struct linear_private_data));
+ plugin = snd_pcm_plugin_build(handle,
+ "linear format conversion",
+ src_format,
+ dst_format,
+ sizeof(linear_t));
if (plugin == NULL)
return -ENOMEM;
- data = (struct linear_private_data *)snd_pcm_plugin_extra_data(plugin);
+ data = (linear_t *)plugin->extra_data;
data->func = func;
- data->src_sample_size = src_sample_size;
- data->dst_sample_size = dst_sample_size;
-
+ data->src_sample_size = plugin->src_width / 8;
+ data->dst_sample_size = plugin->dst_width / 8;
plugin->transfer = linear_transfer;
- plugin->src_size = linear_src_size;
- plugin->dst_size = linear_dst_size;
*r_plugin = plugin;
return 0;
}
#include <string.h>
#include <errno.h>
#include <sys/poll.h>
+#include <sys/uio.h>
#include "../pcm_local.h"
/*
* Basic mmap plugin
*/
-struct mmap_private_data {
- snd_pcm_t *pcm;
+typedef struct mmap_private_data {
int channel;
snd_pcm_mmap_control_t *control;
char *buffer;
int frags, frags_used;
int frags_min, frags_max;
unsigned int lastblock;
-};
+ struct iovec *vector;
+ int vector_count;
+} mmap_t;
-static int playback_ok(struct mmap_private_data *data)
+static int playback_ok(snd_pcm_plugin_t *plugin)
{
+ mmap_t *data = (mmap_t *)plugin->extra_data;
snd_pcm_mmap_control_t *control = data->control;
int delta = control->status.block;
return err < 0 ? err : 0;
}
-static int query_playback(struct mmap_private_data *data, int not_use_poll)
+static int query_playback(snd_pcm_plugin_t *plugin, int not_use_poll)
{
+ mmap_t *data = (mmap_t *)plugin->extra_data;
snd_pcm_mmap_control_t *control = data->control;
int err;
if (data->start_mode == SND_PCM_START_GO)
return -EAGAIN;
if ((data->start_mode == SND_PCM_START_DATA &&
- playback_ok(data)) ||
+ playback_ok(plugin)) ||
(data->start_mode == SND_PCM_START_FULL &&
data->frags_used == data->frags)) {
- err = snd_pcm_channel_go(data->pcm, data->channel);
+ err = snd_pcm_channel_go(plugin->handle, data->channel);
if (err < 0)
return err;
}
case SND_PCM_STATUS_RUNNING:
if (!not_use_poll) {
control->status.expblock = control->status.block + 1;
- err = poll_playback(data->pcm);
+ err = poll_playback(plugin->handle);
if (err < 0)
return err;
}
return 0;
}
-static int capture_ok(struct mmap_private_data *data)
+static int capture_ok(snd_pcm_plugin_t *plugin)
{
+ mmap_t *data = (mmap_t *)plugin->extra_data;
snd_pcm_mmap_control_t *control = data->control;
int delta = control->status.block;
return err < 0 ? err : 0;
}
-static int query_capture(struct mmap_private_data *data, int not_use_poll)
+static int query_capture(snd_pcm_plugin_t *plugin, int not_use_poll)
{
+ mmap_t *data = (mmap_t *)plugin->extra_data;
snd_pcm_mmap_control_t *control = data->control;
int err;
case SND_PCM_STATUS_PREPARED:
if (data->start_mode != SND_PCM_START_DATA)
return -EAGAIN;
- err = snd_pcm_channel_go(data->pcm, data->channel);
+ err = snd_pcm_channel_go(plugin->handle, data->channel);
if (err < 0)
return err;
break;
case SND_PCM_STATUS_RUNNING:
if (!not_use_poll) {
control->status.expblock = control->status.block + data->frags_min;
- err = poll_capture(data->pcm);
+ err = poll_capture(plugin->handle);
if (err < 0)
return err;
}
return 0;
}
-static int mmap_transfer_src_ptr(snd_pcm_plugin_t *plugin, char **buffer, size_t *size)
+static int mmap_src_voices(snd_pcm_plugin_t *plugin,
+ snd_pcm_plugin_voice_t **voices,
+ size_t samples,
+ void *(*plugin_alloc)(snd_pcm_plugin_handle_t *handle, size_t size))
{
- struct mmap_private_data *data;
+ mmap_t *data;
snd_pcm_mmap_control_t *control;
- int interleave, err;
+ snd_pcm_plugin_voice_t *v;
+ int err;
- if (plugin == NULL || buffer == NULL || size == NULL)
+ if (plugin == NULL || voices == NULL)
+ return -EINVAL;
+ *voices = NULL;
+ data = (mmap_t *)plugin->extra_data;
+ if (data->channel != SND_PCM_CHANNEL_PLAYBACK)
+ return -EINVAL;
+ if ((control = data->control) == NULL)
+ return -EBADFD;
+ /* wait until the block is not free */
+ while (!playback_ok(plugin)) {
+ err = query_playback(plugin, 0);
+ if (err < 0)
+ return err;
+ }
+ v = plugin->voices;
+ if (plugin->src_format.interleave) {
+ void *addr;
+ int voice;
+ if (control->status.frag_size != snd_pcm_plugin_dst_samples_to_size(plugin, samples))
+ return -EINVAL;
+ addr = data->buffer + control->fragments[data->frag].addr;
+ for (voice = 0; voice < plugin->src_format.voices; voice++) {
+ v->aptr = NULL;
+ v->addr = addr;
+ v->offset = voice * plugin->src_width;
+ v->next = plugin->src_format.voices * plugin->src_width;
+ }
+ } else {
+ int frag, voice;
+ if (control->status.frag_size != snd_pcm_plugin_src_samples_to_size(plugin, samples) / plugin->src_format.voices)
return -EINVAL;
- data = (struct mmap_private_data *)snd_pcm_plugin_extra_data(plugin);
- if (data == NULL)
+ for (voice = 0; voice < plugin->src_format.voices; voice++) {
+ frag = data->frag + (voice * data->frags);
+ v->aptr = NULL;
+ v->addr = data->buffer + control->fragments[frag].addr;
+ v->offset = 0;
+ v->next = plugin->src_width;
+ }
+ }
+ *voices = plugin->voices;
+ return 0;
+}
+
+static int mmap_dst_voices(snd_pcm_plugin_t *plugin,
+ snd_pcm_plugin_voice_t **voices,
+ size_t samples,
+ void *(*plugin_alloc)(snd_pcm_plugin_handle_t *handle, size_t size))
+{
+ mmap_t *data;
+ snd_pcm_mmap_control_t *control;
+ snd_pcm_plugin_voice_t *v;
+
+ if (plugin == NULL || voices == NULL)
return -EINVAL;
- control = data->control;
- if (control == NULL)
+ *voices = NULL;
+ data = (mmap_t *)plugin->extra_data;
+ if (data->channel != SND_PCM_CHANNEL_CAPTURE)
return -EINVAL;
- interleave = control->status.voices < 0;
- if (interleave) {
- *buffer = data->buffer + control->fragments[data->frag].addr;
- if (data->channel == SND_PCM_CHANNEL_PLAYBACK) {
- /* wait until the block is not free */
- while (!playback_ok(data)) {
- err = query_playback(data, 0);
- if (err < 0)
- return err;
- }
+ if ((control = data->control) == NULL)
+ return -EBADFD;
+ v = plugin->voices;
+ if (plugin->dst_format.interleave) {
+ void *addr;
+ int voice;
+ if (control->status.frag_size != snd_pcm_plugin_dst_samples_to_size(plugin, samples))
+ return -EINVAL;
+ addr = data->buffer + control->fragments[data->frag].addr;
+ for (voice = 0; voice < plugin->dst_format.voices; voice++) {
+ v->addr = addr;
+ v->offset = voice * plugin->src_width;
+ v->next = plugin->dst_format.voices * plugin->dst_width;
}
- *size = control->status.frag_size;
} else {
- *buffer = NULL; /* use another buffer */
+ int frag, voice;
+ if (control->status.frag_size != snd_pcm_plugin_dst_samples_to_size(plugin, samples) / plugin->dst_format.voices)
+ return -EINVAL;
+ for (voice = 0; voice < plugin->dst_format.voices; voice++) {
+ frag = data->frag + (voice * data->frags);
+ v->addr = data->buffer + control->fragments[frag].addr;
+ v->offset = 0;
+ v->next = plugin->dst_width;
+ }
}
+ *voices = plugin->voices;
return 0;
}
static ssize_t mmap_transfer(snd_pcm_plugin_t *plugin,
- char *src_ptr, size_t src_size,
- char *dst_ptr, size_t dst_size)
+ const snd_pcm_plugin_voice_t *src_voices,
+ const snd_pcm_plugin_voice_t *dst_voices,
+ size_t samples)
{
- struct mmap_private_data *data;
+ mmap_t *data;
snd_pcm_mmap_control_t *control;
- int interleave, voice, err;
+ ssize_t size;
+ int voice, err;
char *addr;
- if (plugin == NULL || dst_ptr == NULL || dst_size <= 0)
- return -EINVAL;
- data = (struct mmap_private_data *)snd_pcm_plugin_extra_data(plugin);
- if (data == NULL)
+ if (plugin == NULL)
return -EINVAL;
+ data = (mmap_t *)plugin->extra_data;
control = data->control;
if (control == NULL)
return -EINVAL;
- interleave = control->status.voices < 0;
- if (interleave) {
- if (dst_size != control->status.frag_size)
- return -EINVAL;
- } else {
- if (dst_size != control->status.frag_size * control->status.voices)
- return -EINVAL;
- }
if (data->channel == SND_PCM_CHANNEL_PLAYBACK) {
- while (!playback_ok(data)) {
- err = query_playback(data, 0);
+ if (src_voices == NULL)
+ return -EINVAL;
+ while (!playback_ok(plugin)) {
+ err = query_playback(plugin, 0);
if (err < 0)
return err;
}
- if (interleave) {
+ size = snd_pcm_plugin_src_samples_to_size(plugin, samples);
+ if (size < 0)
+ return size;
+ if (plugin->src_format.interleave) {
+ if (size != control->status.frag_size)
+ return -EINVAL;
addr = data->buffer + control->fragments[data->frag].addr;
- if (dst_ptr != addr)
- memcpy(addr, dst_ptr, dst_size);
+ if (src_voices->addr != addr)
+ memcpy(addr, src_voices->addr, size);
control->fragments[data->frag++].data = 1;
data->frag %= control->status.frags;
data->frags_used++;
+ return samples;
} else {
int frag;
- for (voice = 0; voice < control->status.voices; voice++) {
+ if ((size / plugin->src_format.voices) != control->status.frag_size)
+ return -EINVAL;
+ for (voice = 0; voice < plugin->src_format.voices; voice++) {
frag = data->frag + (voice * data->frags);
while (control->fragments[frag].data) {
- err = query_playback(data, 1);
+ err = query_playback(plugin, 1);
if (err < 0)
return err;
}
addr = data->buffer + control->fragments[frag].addr;
- if (dst_ptr != addr)
- memcpy(addr, dst_ptr, control->status.frag_size);
+ if (src_voices[voice].addr != addr)
+ memcpy(addr, src_voices[voice].addr, control->status.frag_size);
control->fragments[frag].data = 1;
- dst_ptr += control->status.frag_size;
}
data->frag++;
data->frag %= data->frags;
data->frags_used++;
+ return samples;
}
- return dst_size;
} else if (data->channel == SND_PCM_CHANNEL_CAPTURE) {
- while (!capture_ok(data)) {
- err = query_capture(data, 0);
+ if (dst_voices == NULL)
+ return -EINVAL;
+ while (!capture_ok(plugin)) {
+ err = query_capture(plugin, 0);
if (err < 0)
return err;
}
- if (interleave) {
+ size = snd_pcm_plugin_dst_samples_to_size(plugin, samples);
+ if (size < 0)
+ return size;
+ if (plugin->dst_format.interleave) {
+ if (size != control->status.frag_size)
+ return -EINVAL;
addr = data->buffer + control->fragments[data->frag].addr;
- if (dst_ptr != addr)
- memcpy(dst_ptr, addr, dst_size);
+ if (dst_voices->addr != addr)
+ memcpy(dst_voices->addr, addr, size);
control->fragments[data->frag++].data = 0;
data->frag %= control->status.frags;
data->frags_used--;
+ return samples;
} else {
int frag;
- for (voice = 0; voice < control->status.voices; voice++) {
+ if ((size / plugin->dst_format.voices) != control->status.frag_size)
+ return -EINVAL;
+ for (voice = 0; voice < plugin->dst_format.voices; voice++) {
frag = data->frag + (voice * data->frags);
while (!control->fragments[data->frag].data) {
- err = query_capture(data, 1);
+ err = query_capture(plugin, 1);
if (err < 0)
return err;
}
addr = data->buffer + control->fragments[frag].addr;
- if (dst_ptr != addr)
- memcpy(dst_ptr, addr, control->status.frag_size);
+ if (dst_voices[voice].addr != addr)
+ memcpy(dst_voices[voice].addr, addr, control->status.frag_size);
control->fragments[frag].data = 0;
- dst_ptr += control->status.frag_size;
}
data->frag++;
data->frag %= data->frags;
data->frags_used--;
+ return samples;
}
- return dst_size;
} else {
return -EINVAL;
}
if (plugin == NULL)
return -EINVAL;
- data = (struct mmap_private_data *)snd_pcm_plugin_extra_data(plugin);
+ data = (mmap_t *)plugin->extra_data;
if (action == INIT) {
snd_pcm_channel_params_t *params;
snd_pcm_channel_setup_t setup;
- int result, frags;
+ int result;
if (data->control)
- snd_pcm_munmap(data->pcm, data->channel);
- result = snd_pcm_mmap(data->pcm, data->channel, &data->control, (void **)&data->buffer);
+ snd_pcm_munmap(plugin->handle, data->channel);
+ result = snd_pcm_mmap(plugin->handle, data->channel, &data->control, (void **)&data->buffer);
if (result < 0)
return result;
params = (snd_pcm_channel_params_t *)udata;
data->stop_mode = params->stop_mode;
memset(&setup, 0, sizeof(setup));
setup.channel = data->channel;
- if ((result = snd_pcm_channel_setup(data->pcm, &setup)) < 0)
+ if ((result = snd_pcm_channel_setup(plugin->handle, &setup)) < 0)
return result;
data->frags = setup.buf.block.frags;
data->frags_min = setup.buf.block.frags_min;
if (plugin == NULL)
return;
- data = (struct mmap_private_data *)snd_pcm_plugin_extra_data(plugin);
+ data = (mmap_t *)plugin->extra_data;
if (data->control)
- snd_pcm_munmap(data->pcm, data->channel);
+ snd_pcm_munmap(plugin->handle, data->channel);
}
-int snd_pcm_plugin_build_mmap(snd_pcm_t *pcm, int channel, snd_pcm_plugin_t **r_plugin)
+int snd_pcm_plugin_build_mmap(snd_pcm_t *pcm, int channel,
+ snd_pcm_format_t *format,
+ snd_pcm_plugin_t **r_plugin)
{
- struct mmap_private_data *data;
+ mmap_t *data;
snd_pcm_plugin_t *plugin;
if (r_plugin == NULL)
*r_plugin = NULL;
if (!pcm || channel < 0 || channel > 1)
return -EINVAL;
- plugin = snd_pcm_plugin_build(channel == SND_PCM_CHANNEL_PLAYBACK ?
+ plugin = snd_pcm_plugin_build(pcm,
+ channel == SND_PCM_CHANNEL_PLAYBACK ?
"I/O mmap playback" :
"I/O mmap capture",
- sizeof(struct mmap_private_data));
+ format, format,
+ sizeof(mmap_t));
if (plugin == NULL)
return -ENOMEM;
- data = (struct mmap_private_data *)snd_pcm_plugin_extra_data(plugin);
- data->pcm = pcm;
+ data = (mmap_t *)plugin->extra_data;
data->channel = channel;
- plugin->transfer_src_ptr = mmap_transfer_src_ptr;
+ plugin->src_voices = mmap_src_voices;
+ plugin->dst_voices = mmap_dst_voices;
plugin->transfer = mmap_transfer;
plugin->action = mmap_action;
plugin->private_free = mmap_free;
#ifdef __KERNEL__
#include "../../include/driver.h"
+#include "../../include/pcm.h"
#include "../../include/pcm_plugin.h"
-#define bswap_16(x) __swab16((x))
#else
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <endian.h>
#include <byteswap.h>
+#include <sys/uio.h>
#include "../pcm_local.h"
#endif
* For further information see John C. Bellamy's Digital Telephony, 1982,
* John Wiley & Sons, pps 98-111 and 472-476.
*/
-static inline unsigned char linear2ulaw(int pcm_val) /* 2's complement (16-bit range) */
+static unsigned char linear2ulaw(int pcm_val) /* 2's complement (16-bit range) */
{
int mask;
int seg;
* Note that this function expects to be passed the complement of the
* original code word. This is in keeping with ISDN conventions.
*/
-static inline int ulaw2linear(unsigned char u_val)
+static int ulaw2linear(unsigned char u_val)
{
int t;
* Basic Mu-Law plugin
*/
-typedef enum {
- _S8_MULAW,
- _U8_MULAW,
- _S16LE_MULAW,
- _U16LE_MULAW,
- _S16BE_MULAW,
- _U16BE_MULAW,
- _MULAW_S8,
- _MULAW_U8,
- _MULAW_S16LE,
- _MULAW_U16LE,
- _MULAW_S16BE,
- _MULAW_U16BE
-} combination_t;
-
-struct mulaw_private_data {
- combination_t cmd;
-};
-
-static void mulaw_conv_u8bit_mulaw(unsigned char *src_ptr, unsigned char *dst_ptr, size_t size)
-{
- unsigned int pcm;
-
- while (size-- > 0) {
- pcm = ((*src_ptr++) ^ 0x80) << 8;
- *dst_ptr++ = linear2ulaw((signed short)(pcm));
- }
-}
-
-static void mulaw_conv_s8bit_mulaw(unsigned char *src_ptr, unsigned char *dst_ptr, size_t size)
-{
- unsigned int pcm;
-
- while (size-- > 0) {
- pcm = *src_ptr++ << 8;
- *dst_ptr++ = linear2ulaw((signed short)(pcm));
- }
-}
-
-static void mulaw_conv_s16bit_mulaw(unsigned short *src_ptr, unsigned char *dst_ptr, size_t size)
-{
- while (size-- > 0)
- *dst_ptr++ = linear2ulaw((signed short)(*src_ptr++));
-}
-
-static void mulaw_conv_s16bit_swap_mulaw(unsigned short *src_ptr, unsigned char *dst_ptr, size_t size)
-{
- while (size-- > 0)
- *dst_ptr++ = linear2ulaw((signed short)(bswap_16(*src_ptr++)));
-}
-
-static void mulaw_conv_u16bit_mulaw(unsigned short *src_ptr, unsigned char *dst_ptr, size_t size)
-{
- while (size-- > 0)
- *dst_ptr++ = linear2ulaw((signed short)((*src_ptr++) ^ 0x8000));
-}
-
-static void mulaw_conv_u16bit_swap_mulaw(unsigned short *src_ptr, unsigned char *dst_ptr, size_t size)
-{
- while (size-- > 0)
- *dst_ptr++ = linear2ulaw((signed short)(bswap_16(*src_ptr++) ^ 0x8000));
-}
-
-static void mulaw_conv_mulaw_u8bit(unsigned char *src_ptr, unsigned char *dst_ptr, size_t size)
-{
- while (size-- > 0)
- *dst_ptr++ = (ulaw2linear(*src_ptr++) >> 8) ^ 0x80;
-}
-
-static void mulaw_conv_mulaw_s8bit(unsigned char *src_ptr, unsigned char *dst_ptr, size_t size)
-{
- while (size-- > 0)
- *dst_ptr++ = ulaw2linear(*src_ptr++) >> 8;
+typedef void (*mulaw_f)(void *src_ptr, void *dst_ptr, int samples);
+
+typedef struct mulaw_private_data {
+ int src_byte_width;
+ int dst_byte_width;
+ mulaw_f func;
+} mulaw_t;
+
+#define MULAW_FUNC_DECODE(name, dsttype, val) \
+static void mulaw_decode_##name(void *src_ptr, void *dst_ptr, int samples) \
+{ \
+ unsigned char *src = src_ptr; \
+ dsttype *dst = dst_ptr; \
+ unsigned int s; \
+ while (samples--) { \
+ s = ulaw2linear(*src++); \
+ *dst++ = val; \
+ } \
}
-static void mulaw_conv_mulaw_s16bit(unsigned char *src_ptr, unsigned short *dst_ptr, size_t size)
-{
- while (size-- > 0)
- *dst_ptr++ = ulaw2linear(*src_ptr++);
-}
-
-static void mulaw_conv_mulaw_swap_s16bit(unsigned char *src_ptr, unsigned short *dst_ptr, size_t size)
-{
- while (size-- > 0)
- *dst_ptr++ = bswap_16(ulaw2linear(*src_ptr++));
+#define MULAW_FUNC_ENCODE(name, srctype, val) \
+static void mulaw_encode_##name(void *src_ptr, void *dst_ptr, int samples) \
+{ \
+ srctype *src = src_ptr; \
+ unsigned char *dst = dst_ptr; \
+ unsigned int s; \
+ while (samples--) { \
+ s = *src++; \
+ *dst++ = linear2ulaw(val); \
+ } \
}
-static void mulaw_conv_mulaw_u16bit(unsigned char *src_ptr, unsigned short *dst_ptr, size_t size)
-{
- while (size-- > 0)
- *dst_ptr++ = ulaw2linear(*src_ptr++) ^ 0x8000;
-}
+MULAW_FUNC_DECODE(u8, u_int8_t, (s >> 8) ^ 0x80)
+MULAW_FUNC_DECODE(s8, u_int8_t, s >> 8)
+MULAW_FUNC_DECODE(u16n, u_int16_t, s ^ 0x8000)
+MULAW_FUNC_DECODE(u16s, u_int16_t, bswap_16(s ^ 0x8000))
+MULAW_FUNC_DECODE(s16n, u_int16_t, s)
+MULAW_FUNC_DECODE(s16s, u_int16_t, bswap_16(s))
+MULAW_FUNC_DECODE(u24n, u_int32_t, (s << 8) ^ 0x800000)
+MULAW_FUNC_DECODE(u24s, u_int32_t, bswap_32((s << 8) ^ 0x800000))
+MULAW_FUNC_DECODE(s24n, u_int32_t, s << 8)
+MULAW_FUNC_DECODE(s24s, u_int32_t, bswap_32(s << 8))
+MULAW_FUNC_DECODE(u32n, u_int32_t, (s << 16) ^ 0x80000000)
+MULAW_FUNC_DECODE(u32s, u_int32_t, bswap_32((s << 16) ^ 0x80000000))
+MULAW_FUNC_DECODE(s32n, u_int32_t, s << 16)
+MULAW_FUNC_DECODE(s32s, u_int32_t, bswap_32(s << 16))
+
+MULAW_FUNC_ENCODE(u8, u_int8_t, s << 8)
+MULAW_FUNC_ENCODE(s8, u_int8_t, (s << 8) ^ 0x8000)
+MULAW_FUNC_ENCODE(u16n, u_int16_t, s ^ 0x8000)
+MULAW_FUNC_ENCODE(u16s, u_int16_t, bswap_16(s ^ 0x8000))
+MULAW_FUNC_ENCODE(s16n, u_int16_t, s)
+MULAW_FUNC_ENCODE(s16s, u_int16_t, bswap_16(s))
+MULAW_FUNC_ENCODE(u24n, u_int32_t, (s ^ 0x800000) >> 8)
+MULAW_FUNC_ENCODE(u24s, u_int32_t, bswap_32((s ^ 0x800000) >> 8))
+MULAW_FUNC_ENCODE(s24n, u_int32_t, s >> 8)
+MULAW_FUNC_ENCODE(s24s, u_int32_t, bswap_32(s >> 8))
+MULAW_FUNC_ENCODE(u32n, u_int32_t, (s ^ 0x80000000) >> 16)
+MULAW_FUNC_ENCODE(u32s, u_int32_t, bswap_32((s ^ 0x80000000) >> 16))
+MULAW_FUNC_ENCODE(s32n, u_int32_t, s >> 16)
+MULAW_FUNC_ENCODE(s32s, u_int32_t, bswap_32(s >> 16))
+
+/* wide, sign, swap endian */
+static mulaw_f mulaw_functions_decode[4 * 4 * 2 * 2] = {
+ mulaw_decode_u8, /* decode:8-bit:unsigned:none */
+ mulaw_decode_u8, /* decode:8-bit:unsigned:swap */
+ mulaw_decode_s8, /* decode:8-bit:signed:none */
+ mulaw_decode_s8, /* decode:8-bit:signed:swap */
+ mulaw_decode_u16n, /* decode:16-bit:unsigned:none */
+ mulaw_decode_u16s, /* decode:16-bit:unsigned:swap */
+ mulaw_decode_s16n, /* decode:16-bit:signed:none */
+ mulaw_decode_s16s, /* decode:16-bit:signed:swap */
+ mulaw_decode_u24n, /* decode:24-bit:unsigned:none */
+ mulaw_decode_u24s, /* decode:24-bit:unsigned:swap */
+ mulaw_decode_s24n, /* decode:24-bit:signed:none */
+ mulaw_decode_s24s, /* decode:24-bit:signed:swap */
+ mulaw_decode_u32n, /* decode:32-bit:unsigned:none */
+ mulaw_decode_u32s, /* decode:32-bit:unsigned:swap */
+ mulaw_decode_s32n, /* decode:32-bit:signed:none */
+ mulaw_decode_s32s, /* decode:32-bit:signed:swap */
+};
-static void mulaw_conv_mulaw_swap_u16bit(unsigned char *src_ptr, unsigned short *dst_ptr, size_t size)
-{
- while (size-- > 0)
- *dst_ptr++ = bswap_16(ulaw2linear(*src_ptr++) ^ 0x8000);
-}
+/* wide, sign, swap endian */
+static mulaw_f mulaw_functions_encode[4 * 2 * 2] = {
+ mulaw_encode_u8, /* from:8-bit:unsigned:none */
+ mulaw_encode_u8, /* from:8-bit:unsigned:swap */
+ mulaw_encode_s8, /* from:8-bit:signed:none */
+ mulaw_encode_s8, /* from:8-bit:signed:swap */
+ mulaw_encode_u16n, /* from:16-bit:unsigned:none */
+ mulaw_encode_u16s, /* from:16-bit:unsigned:swap */
+ mulaw_encode_s16n, /* from:16-bit:signed:none */
+ mulaw_encode_s16s, /* from:16-bit:signed:swap */
+ mulaw_encode_u24n, /* from:24-bit:unsigned:none */
+ mulaw_encode_u24s, /* from:24-bit:unsigned:swap */
+ mulaw_encode_s24n, /* from:24-bit:signed:none */
+ mulaw_encode_s24s, /* from:24-bit:signed:swap */
+ mulaw_encode_u32n, /* from:32-bit:unsigned:none */
+ mulaw_encode_u32s, /* from:32-bit:unsigned:swap */
+ mulaw_encode_s32n, /* from:32-bit:signed:none */
+ mulaw_encode_s32s, /* from:32-bit:signed:swap */
+};
static ssize_t mulaw_transfer(snd_pcm_plugin_t *plugin,
- char *src_ptr, size_t src_size,
- char *dst_ptr, size_t dst_size)
+ const snd_pcm_plugin_voice_t *src_voices,
+ const snd_pcm_plugin_voice_t *dst_voices,
+ size_t samples)
{
- struct mulaw_private_data *data;
+ mulaw_t *data;
+ int voice;
- if (plugin == NULL || src_ptr == NULL || src_size < 0 ||
- dst_ptr == NULL || dst_size < 0)
+ if (plugin == NULL || src_voices == NULL || dst_voices == NULL || samples < 0)
return -EINVAL;
- if (src_size == 0)
+ if (samples == 0)
return 0;
- data = (struct mulaw_private_data *)snd_pcm_plugin_extra_data(plugin);
- if (data == NULL)
- return -EINVAL;
- switch (data->cmd) {
- case _U8_MULAW:
- if (dst_size < src_size)
- return -EINVAL;
- mulaw_conv_u8bit_mulaw(src_ptr, dst_ptr, src_size);
- return src_size;
- case _S8_MULAW:
- if (dst_size < src_size)
- return -EINVAL;
- mulaw_conv_s8bit_mulaw(src_ptr, dst_ptr, src_size);
- return src_size;
- case _S16LE_MULAW:
- if ((dst_size << 1) < src_size)
- return -EINVAL;
-#if __BYTE_ORDER == __LITTLE_ENDIAN
- mulaw_conv_s16bit_mulaw((short *)src_ptr, dst_ptr, src_size >> 1);
-#elif __BYTE_ORDER == __BIG_ENDIAN
- mulaw_conv_s16bit_swap_mulaw((short *)src_ptr, dst_ptr, src_size >> 1);
-#else
-#error "Have to be coded..."
-#endif
- return src_size >> 1;
- case _U16LE_MULAW:
- if ((dst_size << 1) < src_size)
- return -EINVAL;
-#if __BYTE_ORDER == __LITTLE_ENDIAN
- mulaw_conv_u16bit_mulaw((short *)src_ptr, dst_ptr, src_size >> 1);
-#elif __BYTE_ORDER == __BIG_ENDIAN
- mulaw_conv_u16bit_swap_mulaw((short *)src_ptr, dst_ptr, src_size >> 1);
-#else
-#error "Have to be coded..."
-#endif
- return src_size >> 1;
- case _S16BE_MULAW:
- if ((dst_size << 1) < src_size)
- return -EINVAL;
-#if __BYTE_ORDER == __LITTLE_ENDIAN
- mulaw_conv_s16bit_swap_mulaw((short *)src_ptr, dst_ptr, src_size >> 1);
-#elif __BYTE_ORDER == __BIG_ENDIAN
- mulaw_conv_s16bit_mulaw((short *)src_ptr, dst_ptr, src_size >> 1);
-#else
-#error "Have to be coded..."
-#endif
- return src_size >> 1;
- case _U16BE_MULAW:
- if ((dst_size << 1) < src_size)
- return -EINVAL;
-#if __BYTE_ORDER == __LITTLE_ENDIAN
- mulaw_conv_u16bit_swap_mulaw((short *)src_ptr, dst_ptr, src_size >> 1);
-#elif __BYTE_ORDER == __BIG_ENDIAN
- mulaw_conv_u16bit_mulaw((short *)src_ptr, dst_ptr, src_size >> 1);
-#else
-#error "Have to be coded..."
-#endif
- return src_size >> 1;
- case _MULAW_U8:
- if (dst_size < src_size)
- return -EINVAL;
- mulaw_conv_mulaw_u8bit(src_ptr, dst_ptr, src_size);
- return src_size;
- case _MULAW_S8:
- if (dst_size < src_size)
- return -EINVAL;
- mulaw_conv_mulaw_s8bit(src_ptr, dst_ptr, src_size);
- return src_size;
- case _MULAW_S16LE:
- if ((dst_size >> 1) < src_size)
- return -EINVAL;
-#if __BYTE_ORDER == __LITTLE_ENDIAN
- mulaw_conv_mulaw_s16bit(src_ptr, (short *)dst_ptr, src_size);
-#elif __BYTE_ORDER == __BIG_ENDIAN
- mulaw_conv_mulaw_swap_s16bit(src_ptr, (short *)dst_ptr, src_size);
-#else
-#error "Have to be coded..."
-#endif
- return src_size << 1;
- case _MULAW_U16LE:
- if ((dst_size >> 1) < src_size)
- return -EINVAL;
-#if __BYTE_ORDER == __LITTLE_ENDIAN
- mulaw_conv_mulaw_u16bit(src_ptr, (short *)dst_ptr, src_size);
-#elif __BYTE_ORDER == __BIG_ENDIAN
- mulaw_conv_mulaw_swap_u16bit(src_ptr, (short *)dst_ptr, src_size);
-#else
-#error "Have to be coded..."
-#endif
- return src_size << 1;
- case _MULAW_S16BE:
- if ((dst_size >> 1) < src_size)
- return -EINVAL;
-#if __BYTE_ORDER == __LITTLE_ENDIAN
- mulaw_conv_mulaw_swap_s16bit(src_ptr, (short *)dst_ptr, src_size);
-#elif __BYTE_ORDER == __BIG_ENDIAN
- mulaw_conv_mulaw_s16bit(src_ptr, (short *)dst_ptr, src_size);
-#else
-#error "Have to be coded..."
-#endif
- return src_size << 1;
- case _MULAW_U16BE:
- if ((dst_size >> 1) < src_size)
- return -EINVAL;
-#if __BYTE_ORDER == __LITTLE_ENDIAN
- mulaw_conv_mulaw_swap_u16bit(src_ptr, (short *)dst_ptr, src_size);
-#elif __BYTE_ORDER == __BIG_ENDIAN
- mulaw_conv_mulaw_u16bit(src_ptr, (short *)dst_ptr, src_size);
-#else
-#error "Have to be coded..."
-#endif
- return src_size << 1;
- default:
- return -EIO;
- }
-}
-
-static ssize_t mulaw_src_size(snd_pcm_plugin_t *plugin, size_t size)
-{
- struct mulaw_private_data *data;
-
- if (plugin == NULL || size <= 0)
- return -EINVAL;
- data = (struct mulaw_private_data *)snd_pcm_plugin_extra_data(plugin);
- switch (data->cmd) {
- case _U8_MULAW:
- case _S8_MULAW:
- case _MULAW_U8:
- case _MULAW_S8:
- return size;
- case _U16LE_MULAW:
- case _S16LE_MULAW:
- case _U16BE_MULAW:
- case _S16BE_MULAW:
- return size * 2;
- case _MULAW_U16LE:
- case _MULAW_S16LE:
- case _MULAW_U16BE:
- case _MULAW_S16BE:
- return size / 2;
- default:
- return -EIO;
+ data = (mulaw_t *)plugin->extra_data;
+ if (plugin->src_format.interleave) {
+ data->func(src_voices[0].addr,
+ dst_voices[0].addr,
+ samples * plugin->src_format.voices);
+ } else {
+ for (voice = 0; voice < plugin->src_format.voices; voice++) {
+ if (src_voices[voice].addr == NULL)
+ continue;
+ data->func(src_voices[voice].addr,
+ dst_voices[voice].addr,
+ samples);
+ }
}
+ return samples;
}
-static ssize_t mulaw_dst_size(snd_pcm_plugin_t *plugin, size_t size)
-{
- struct mulaw_private_data *data;
-
- if (plugin == NULL || size <= 0)
- return -EINVAL;
- data = (struct mulaw_private_data *)snd_pcm_plugin_extra_data(plugin);
- switch (data->cmd) {
- case _U8_MULAW:
- case _S8_MULAW:
- case _MULAW_U8:
- case _MULAW_S8:
- return size;
- case _U16LE_MULAW:
- case _S16LE_MULAW:
- case _U16BE_MULAW:
- case _S16BE_MULAW:
- return size / 2;
- case _MULAW_U16LE:
- case _MULAW_S16LE:
- case _MULAW_U16BE:
- case _MULAW_S16BE:
- return size * 2;
- default:
- return -EIO;
- }
-}
-
-int snd_pcm_plugin_build_mulaw(snd_pcm_format_t *src_format,
+int snd_pcm_plugin_build_mulaw(snd_pcm_plugin_handle_t *handle,
+ snd_pcm_format_t *src_format,
snd_pcm_format_t *dst_format,
snd_pcm_plugin_t **r_plugin)
{
struct mulaw_private_data *data;
snd_pcm_plugin_t *plugin;
- combination_t cmd;
+ int endian, src_width, dst_width, sign;
+ mulaw_f func;
if (r_plugin == NULL)
return -EINVAL;
if (src_format->voices != dst_format->voices)
return -EINVAL;
+
if (dst_format->format == SND_PCM_SFMT_MU_LAW) {
- switch (src_format->format) {
- case SND_PCM_SFMT_U8: cmd = _U8_MULAW; break;
- case SND_PCM_SFMT_S8: cmd = _S8_MULAW; break;
- case SND_PCM_SFMT_U16_LE: cmd = _U16LE_MULAW; break;
- case SND_PCM_SFMT_S16_LE: cmd = _S16LE_MULAW; break;
- case SND_PCM_SFMT_U16_BE: cmd = _U16BE_MULAW; break;
- case SND_PCM_SFMT_S16_BE: cmd = _S16BE_MULAW; break;
- default:
+ if (!snd_pcm_format_linear(src_format->format))
return -EINVAL;
- }
+ sign = snd_pcm_format_signed(src_format->format);
+ src_width = snd_pcm_format_width(src_format->format);
+ if ((src_width % 8) != 0 || src_width < 8 || src_width > 32)
+ return -EINVAL;
+ dst_width = 8;
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ endian = snd_pcm_format_big_endian(src_format->format);
+#elif __BYTE_ORDER == __BIG_ENDIAN
+ endian = snd_pcm_format_little_endian(src_format->format);
+#else
+#error "Unsupported endian..."
+#endif
+ func = ((mulaw_f(*)[2][2])mulaw_functions_encode)[(src_width/8)-1][sign][endian];
} else if (src_format->format == SND_PCM_SFMT_MU_LAW) {
- switch (dst_format->format) {
- case SND_PCM_SFMT_U8: cmd = _MULAW_U8; break;
- case SND_PCM_SFMT_S8: cmd = _MULAW_S8; break;
- case SND_PCM_SFMT_U16_LE: cmd = _MULAW_U16LE; break;
- case SND_PCM_SFMT_S16_LE: cmd = _MULAW_S16LE; break;
- case SND_PCM_SFMT_U16_BE: cmd = _MULAW_U16BE; break;
- case SND_PCM_SFMT_S16_BE: cmd = _MULAW_S16BE; break;
- default:
+ if (!snd_pcm_format_linear(dst_format->format))
return -EINVAL;
- }
+ sign = snd_pcm_format_signed(dst_format->format);
+ dst_width = snd_pcm_format_width(dst_format->format);
+ if ((dst_width % 8) != 0 || dst_width < 8 || dst_width > 32)
+ return -EINVAL;
+ src_width = 8;
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ endian = snd_pcm_format_big_endian(dst_format->format);
+#elif __BYTE_ORDER == __BIG_ENDIAN
+ endian = snd_pcm_format_little_endian(dst_format->format);
+#else
+#error "Unsupported endian..."
+#endif
+ func = ((mulaw_f(*)[2][2])mulaw_functions_decode)[(dst_width/8)-1][sign][endian];
} else {
return -EINVAL;
}
- plugin = snd_pcm_plugin_build("Mu-Law<->linear conversion",
+ plugin = snd_pcm_plugin_build(handle,
+ "Mu-Law<->linear conversion",
+ src_format,
+ dst_format,
sizeof(struct mulaw_private_data));
if (plugin == NULL)
return -ENOMEM;
- data = (struct mulaw_private_data *)snd_pcm_plugin_extra_data(plugin);
- data->cmd = cmd;
+ data = (struct mulaw_private_data *)plugin->extra_data;
+ data->src_byte_width = src_width / 8;
+ data->dst_byte_width = dst_width / 8;
+ data->func = func;
plugin->transfer = mulaw_transfer;
- plugin->src_size = mulaw_src_size;
- plugin->dst_size = mulaw_dst_size;
*r_plugin = plugin;
return 0;
}
#ifdef __KERNEL__
#include "../../include/driver.h"
+#include "../../include/pcm.h"
#include "../../include/pcm_plugin.h"
#else
#include <stdio.h>
#define SHIFT 11
#define BITS (1<<SHIFT)
#define MASK (BITS-1)
-#define MAX_VOICES 6
/*
* Basic rate conversion plugin
*/
+
+#define rate_voices(data) ((rate_voice_t *)((char *)data + sizeof(*data)))
+
+typedef signed short (*take_sample_f)(void *ptr);
+typedef void (*put_sample_f)(void *ptr, signed int val);
+
+typedef struct {
+ signed short last_S1;
+ signed short last_S2;
+} rate_voice_t;
-struct rate_private_data {
- int src_voices;
- int dst_voices;
- int src_rate;
- int dst_rate;
- int sample_size;
- int expand: 1;
+typedef struct rate_private_data {
+ snd_pcm_plugin_t *plugin;
+ take_sample_f take;
+ put_sample_f put;
unsigned int pitch;
unsigned int pos;
- signed short last_S1[MAX_VOICES];
- signed short last_S2[MAX_VOICES];
- ssize_t old_src_size, old_dst_size;
-};
+ ssize_t old_src_samples, old_dst_samples;
+} rate_t;
-static void resample16_expand(struct rate_private_data *data, int voices,
- signed short *src_ptr, int src_size,
- signed short *dst_ptr, int dst_size)
+static void rate_init(snd_pcm_plugin_t *plugin, rate_t *data)
{
- unsigned int pos;
- signed int val;
- signed short S1, S2;
int voice;
- signed short *src, *dst;
- int size;
-
- for (voice = 0; voice < voices; ++voice) {
- pos = data->pos;
- S1 = data->last_S1[voice];
- S2 = data->last_S2[voice];
- src = src_ptr + voice;
- dst = dst_ptr + voice;
- size = dst_size;
- if (pos >> SHIFT) {
- pos &= MASK;
- S1 = S2;
- S2 = *src;
- }
- while (size-- > 0) {
- if (pos >> SHIFT) {
- src += voices;
- pos &= MASK;
- S1 = S2;
- if ((src - src_ptr) < src_size * voices)
- S2 = *src;
- }
- val = S1 + ((S2 - S1) * (signed int)pos) / BITS;
- if (val < -32768)
- val = -32768;
- else if (val > 32767)
- val = 32767;
- *dst = val;
- dst += voices;
- pos += data->pitch;
- }
- data->last_S1[voice] = S1;
- data->last_S2[voice] = S2;
- data->pos = pos;
+ rate_voice_t *rvoices = rate_voices(data);
+
+ data->pos = 0;
+ for (voice = 0; plugin->src_format.voices; voice++) {
+ rvoices[voice].last_S1 = 0;
+ rvoices[voice].last_S2 = 0;
}
}
-static void resample16_shrink(struct rate_private_data *data, int voices,
- signed short *src_ptr, int src_size,
- signed short *dst_ptr, int dst_size)
-{
- unsigned int pos;
- signed int val;
- signed short S1, S2;
- int voice;
- signed short *src, *dst;
- int size;
-
- for (voice = 0; voice < voices; ++voice) {
- pos = data->pos;
- S1 = data->last_S1[voice];
- S2 = data->last_S2[voice];
- src = src_ptr + voice;
- dst = dst_ptr + voice;
- size = dst_size;
- while (size > 0) {
- S1 = S2;
- if ((src - src_ptr) < (src_size * voices)) {
- S2 = *src;
- src += voices;
- }
- if (pos >> SHIFT) {
- pos &= MASK;
- val = S1 + ((S2 - S1) * (signed int)pos) / BITS;
- if (val < -32768)
- val = -32768;
- else if (val > 32767)
- val = 32767;
- *dst = val;
- dst += voices;
- size--;
- }
- pos += data->pitch;
- }
- data->last_S1[voice] = S1;
- data->last_S2[voice] = S2;
- data->pos = pos;
- }
+#define RATE_TAKE_SAMPLE(name, type, val) \
+static signed short rate_take_sample_##name(void *ptr) \
+{ \
+ signed int smp = *(type *)ptr; \
+ return val; \
+}
+
+#define RATE_PUT_SAMPLE(name, type, val) \
+static void rate_put_sample_##name(void *ptr, signed int smp) \
+{ \
+ *(type *)ptr = val; \
}
-static void resample8_expand(struct rate_private_data *data, int voices,
- unsigned char *src_ptr, int src_size,
- unsigned char *dst_ptr, int dst_size)
+static void resample_expand(snd_pcm_plugin_t *plugin,
+ const snd_pcm_plugin_voice_t *src_voices,
+ const snd_pcm_plugin_voice_t *dst_voices,
+ int src_samples, int dst_samples)
{
unsigned int pos;
signed int val;
signed short S1, S2;
+ char *src, *dst;
int voice;
- unsigned char *src, *dst;
- int size;
+ int src_step, dst_step;
+ int src_samples1, dst_samples1;
+ rate_t *data = (rate_t *)plugin->extra_data;
+ rate_voice_t *rvoices = rate_voices(data);
- for (voice = 0; voice < voices; ++voice) {
+ for (voice = 0; voice < plugin->src_format.voices; voice++, rvoices++) {
pos = data->pos;
- S1 = data->last_S1[voice];
- S2 = data->last_S2[voice];
- src = src_ptr + voice;
- dst = dst_ptr + voice;
- size = dst_size;
- if (pos >> SHIFT) {
+ S1 = rvoices->last_S1;
+ S2 = rvoices->last_S2;
+ if (src_voices[voice].addr == NULL)
+ continue;
+ src = (char *)src_voices[voice].addr + src_voices[voice].offset / 8;
+ dst = (char *)dst_voices[voice].addr + src_voices[voice].offset / 8;
+ src_step = src_voices[voice].next / 8;
+ dst_step = dst_voices[voice].next / 8;
+ src_samples1 = src_samples;
+ dst_samples1 = dst_samples;
+ if (pos & ~MASK) {
pos &= MASK;
S1 = S2;
- S2 = (*src << 8) ^ 0x8000;
+ S2 = data->take(src);
+ src += src_step;
+ src_samples--;
}
- while (size-- > 0) {
- if (pos >> SHIFT) {
- src += voices;
+ while (dst_samples1-- > 0) {
+ if (pos & ~MASK) {
pos &= MASK;
S1 = S2;
- if ((src - src_ptr) < src_size * voices)
- S2 = (*src << 8) ^ 0x8000;
+ if (src_samples1-- > 0) {
+ S2 = data->take(src);
+ src += src_step;
+ }
}
val = S1 + ((S2 - S1) * (signed int)pos) / BITS;
if (val < -32768)
val = -32768;
else if (val > 32767)
val = 32767;
- *dst = (val >> 8) ^ 0x0080;
- dst += voices;
+ data->put(dst, val);
+ dst += dst_step;
pos += data->pitch;
}
- data->last_S1[voice] = S1;
- data->last_S2[voice] = S2;
+ rvoices->last_S1 = S1;
+ rvoices->last_S2 = S2;
data->pos = pos;
}
}
-static void resample8_shrink(struct rate_private_data *data, int voices,
- unsigned char *src_ptr, int src_size,
- unsigned char *dst_ptr, int dst_size)
+static void resample_shrink(snd_pcm_plugin_t *plugin,
+ const snd_pcm_plugin_voice_t *src_voices,
+ const snd_pcm_plugin_voice_t *dst_voices,
+ int src_samples, int dst_samples)
{
unsigned int pos;
signed int val;
signed short S1, S2;
+ char *src, *dst;
int voice;
- unsigned char *src, *dst;
- int size;
+ int src_step, dst_step;
+ int src_samples1, dst_samples1;
+ rate_t *data = (rate_t *)plugin->extra_data;
+ rate_voice_t *rvoices = rate_voices(data);
- for (voice = 0; voice < voices; ++voice) {
+ for (voice = 0; voice < plugin->src_format.voices; ++voice) {
pos = data->pos;
- S1 = data->last_S1[voice];
- S2 = data->last_S2[voice];
- src = src_ptr + voice;
- dst = dst_ptr + voice;
- size = dst_size;
- while (size > 0) {
+ S1 = rvoices->last_S1;
+ S2 = rvoices->last_S2;
+ if (src_voices[voice].addr == NULL)
+ continue;
+ src = (char *)src_voices[voice].addr + src_voices[voice].offset / 8;
+ dst = (char *)dst_voices[voice].addr + src_voices[voice].offset / 8;
+ src_step = src_voices[voice].next / 8;
+ dst_step = dst_voices[voice].next / 8;
+ src_samples1 = src_samples;
+ dst_samples1 = dst_samples;
+ while (dst_samples1 > 0) {
S1 = S2;
- if ((src - src_ptr) < (src_size * voices)) {
- S2 = (*src << 8) ^ 0x8000;
- src += voices;
+ if (src_samples1-- > 0) {
+ S2 = data->take(src);
+ src += src_step;
}
- if (pos >> SHIFT) {
+ if (pos & ~MASK) {
pos &= MASK;
val = S1 + ((S2 - S1) * (signed int)pos) / BITS;
if (val < -32768)
val = -32768;
else if (val > 32767)
val = 32767;
- *dst = (val >> 8) ^ 0x0080;
- dst += voices;
- size--;
+ data->put(dst, val);
+ dst += dst_step;
+ dst_samples1--;
}
pos += data->pitch;
}
- data->last_S1[voice] = S1;
- data->last_S2[voice] = S2;
+ rvoices->last_S1 = S1;
+ rvoices->last_S2 = S2;
data->pos = pos;
}
}
-static ssize_t rate_src_size(snd_pcm_plugin_t *plugin, size_t size)
+static ssize_t rate_src_samples(snd_pcm_plugin_t *plugin, size_t samples)
{
- struct rate_private_data *data;
+ rate_t *data;
ssize_t res;
- if (plugin == NULL || size <= 0)
+ if (plugin == NULL || samples <= 0)
return -EINVAL;
- data = (struct rate_private_data *)snd_pcm_plugin_extra_data(plugin);
- if (data->expand) {
- res = (((size * data->pitch) + (BITS/2)) >> SHIFT);
+ data = (rate_t *)plugin->extra_data;
+ if (plugin->src_format.rate < plugin->dst_format.rate) {
+ res = (((samples * data->pitch) + (BITS/2)) >> SHIFT);
} else {
- res = (((size << SHIFT) + (data->pitch / 2)) / data->pitch);
+ res = (((samples << SHIFT) + (data->pitch / 2)) / data->pitch);
}
- res = res / (data->src_voices*data->sample_size) * (data->src_voices*data->sample_size);
- if (data->old_src_size > 0) {
- ssize_t size1 = size, res1 = data->old_dst_size;
- while (data->old_src_size < size1) {
- size1 >>= 1;
+ if (data->old_src_samples > 0) {
+ ssize_t samples1 = samples, res1 = data->old_dst_samples;
+ while (data->old_src_samples < samples1) {
+ samples1 >>= 1;
res1 <<= 1;
}
- while (data->old_src_size > size1) {
- size1 <<= 1;
+ while (data->old_src_samples > samples1) {
+ samples1 <<= 1;
res1 >>= 1;
}
- if (data->old_src_size == size1)
+ if (data->old_src_samples == samples1)
return res1;
}
- data->old_src_size = size;
- data->old_dst_size = res;
+ data->old_src_samples = samples;
+ data->old_dst_samples = res;
return res;
}
-static ssize_t rate_dst_size(snd_pcm_plugin_t *plugin, size_t size)
+static ssize_t rate_dst_samples(snd_pcm_plugin_t *plugin, size_t samples)
{
- struct rate_private_data *data;
+ rate_t *data;
ssize_t res;
- if (plugin == NULL || size <= 0)
+ if (plugin == NULL || samples <= 0)
return -EINVAL;
- data = (struct rate_private_data *)snd_pcm_plugin_extra_data(plugin);
- if (data->expand) {
- res = (((size << SHIFT) + (data->pitch / 2)) / data->pitch);
+ data = (rate_t *)plugin->extra_data;
+ if (plugin->src_format.rate < plugin->dst_format.rate) {
+ res = (((samples << SHIFT) + (data->pitch / 2)) / data->pitch);
} else {
- res = (((size * data->pitch) + (BITS/2)) >> SHIFT);
+ res = (((samples * data->pitch) + (BITS/2)) >> SHIFT);
}
- res = res / (data->dst_voices*data->sample_size) * (data->dst_voices*data->sample_size);
- if (data->old_dst_size > 0) {
- ssize_t size1 = size, res1 = data->old_src_size;
- while (data->old_dst_size < size1) {
- size1 >>= 1;
+ if (data->old_dst_samples > 0) {
+ ssize_t samples1 = samples, res1 = data->old_src_samples;
+ while (data->old_dst_samples < samples1) {
+ samples1 >>= 1;
res1 <<= 1;
}
- while (data->old_dst_size > size1) {
- size1 <<= 1;
+ while (data->old_dst_samples > samples1) {
+ samples1 <<= 1;
res1 >>= 1;
}
- if (data->old_dst_size == size1)
+ if (data->old_dst_samples == samples1)
return res1;
}
- data->old_dst_size = size;
- data->old_src_size = res;
+ data->old_dst_samples = samples;
+ data->old_src_samples = res;
return res;
}
static ssize_t rate_transfer(snd_pcm_plugin_t *plugin,
- char *src_ptr, size_t src_size,
- char *dst_ptr, size_t dst_size)
+ const snd_pcm_plugin_voice_t *src_voices,
+ const snd_pcm_plugin_voice_t *dst_voices,
+ size_t samples)
{
- struct rate_private_data *data;
+ size_t dst_samples;
- if (plugin == NULL || src_ptr == NULL || src_size < 0 ||
- dst_ptr == NULL || dst_size < 0)
+ if (plugin == NULL || src_voices == NULL || src_voices == NULL || samples < 0)
return -EINVAL;
- if (src_size == 0)
+ if (samples == 0)
return 0;
- data = (struct rate_private_data *)snd_pcm_plugin_extra_data(plugin);
- if (data == NULL)
- return -EINVAL;
- if (data->sample_size == 2) {
- if (data->src_rate < data->dst_rate) {
- resample16_expand(data, data->src_voices,
- (signed short *)src_ptr, src_size / (data->src_voices * 2),
- (signed short *)dst_ptr, dst_size / (data->dst_voices * 2));
- } else {
- resample16_shrink(data, data->src_voices,
- (signed short *)src_ptr, src_size / (data->src_voices * 2),
- (signed short *)dst_ptr, dst_size / (data->dst_voices * 2));
- }
+ dst_samples = rate_dst_samples(plugin, samples);
+ if (plugin->src_format.rate < plugin->dst_format.rate) {
+ resample_expand(plugin, src_voices, dst_voices, samples, dst_samples);
} else {
- if (data->src_rate < data->dst_rate) {
- resample8_expand(data, data->src_voices,
- src_ptr, src_size / data->src_voices,
- dst_ptr, dst_size / data->dst_voices);
- } else {
- resample8_shrink(data, data->src_voices,
- src_ptr, src_size / data->src_voices,
- dst_ptr, dst_size / data->dst_voices);
- }
+ resample_shrink(plugin, src_voices, dst_voices, samples, dst_samples);
}
- return rate_dst_size(plugin, src_size);
+ return dst_samples;
}
static int rate_action(snd_pcm_plugin_t *plugin,
snd_pcm_plugin_action_t action,
unsigned long udata)
{
- struct rate_private_data *data;
- int voice;
+ rate_t *data;
if (plugin == NULL)
return -EINVAL;
- data = (struct rate_private_data *)snd_pcm_plugin_extra_data(plugin);
+ data = (rate_t *)plugin->extra_data;
switch (action) {
case INIT:
case PREPARE:
case DRAIN:
case FLUSH:
- data->pos = 0;
- for (voice = 0; voice < data->src_voices; ++voice) {
- data->last_S1[voice] = data->last_S2[voice] = 0;
- }
+ rate_init(plugin, data);
break;
}
return 0; /* silenty ignore other actions */
}
-int snd_pcm_plugin_build_rate(snd_pcm_format_t *src_format,
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+#define my_little_swap16(x) (x)
+#define my_little_swap32(x) (x)
+#define my_big_swap16(x) bswap_16(x)
+#define my_big_swap32(x) bswap_32(x)
+#else
+#define my_little_swap16(x) bswap_16(x)
+#define my_little_swap32(x) bswap_32(x)
+#define my_big_swap16(x) (x)
+#define my_big_swap32(x) (x)
+#endif
+
+RATE_TAKE_SAMPLE(s8, int8_t, smp << 8)
+RATE_TAKE_SAMPLE(u8, int8_t, (smp << 8) ^ 0x8000)
+RATE_TAKE_SAMPLE(s16_le, int16_t, my_little_swap16(smp))
+RATE_TAKE_SAMPLE(s16_be, int16_t, my_big_swap16(smp))
+RATE_TAKE_SAMPLE(u16_le, int16_t, my_little_swap16(smp) ^ 0x8000)
+RATE_TAKE_SAMPLE(u16_be, int16_t, my_big_swap16(smp) ^ 0x8000)
+RATE_TAKE_SAMPLE(s24_le, int32_t, my_little_swap32(smp) >> 8)
+RATE_TAKE_SAMPLE(s24_be, int32_t, my_big_swap32(smp) >> 8)
+RATE_TAKE_SAMPLE(u24_le, int32_t, (my_little_swap32(smp) >> 8) ^ 0x8000)
+RATE_TAKE_SAMPLE(u24_be, int32_t, (my_big_swap32(smp) >> 8) ^ 0x8000)
+RATE_TAKE_SAMPLE(s32_le, int32_t, my_little_swap32(smp) >> 16)
+RATE_TAKE_SAMPLE(s32_be, int32_t, my_big_swap32(smp) >> 16)
+RATE_TAKE_SAMPLE(u32_le, int32_t, (my_little_swap32(smp) >> 16) ^ 0x8000)
+RATE_TAKE_SAMPLE(u32_be, int32_t, (my_big_swap32(smp) >> 16) ^ 0x8000)
+
+static take_sample_f rate_take_sample[] = {
+ [SND_PCM_SFMT_S8] rate_take_sample_s8,
+ [SND_PCM_SFMT_U8] rate_take_sample_u8,
+ [SND_PCM_SFMT_S16_LE] rate_take_sample_s16_le,
+ [SND_PCM_SFMT_S16_BE] rate_take_sample_s16_be,
+ [SND_PCM_SFMT_U16_LE] rate_take_sample_u16_le,
+ [SND_PCM_SFMT_U16_BE] rate_take_sample_u16_be,
+ [SND_PCM_SFMT_S24_LE] rate_take_sample_s24_le,
+ [SND_PCM_SFMT_S24_BE] rate_take_sample_s24_be,
+ [SND_PCM_SFMT_U24_LE] rate_take_sample_u24_le,
+ [SND_PCM_SFMT_U24_BE] rate_take_sample_u24_be,
+ [SND_PCM_SFMT_S32_LE] rate_take_sample_s32_le,
+ [SND_PCM_SFMT_S32_BE] rate_take_sample_s32_be,
+ [SND_PCM_SFMT_U32_LE] rate_take_sample_u32_le,
+ [SND_PCM_SFMT_U32_BE] rate_take_sample_u32_be
+};
+
+RATE_PUT_SAMPLE(s8, int8_t, smp >> 8)
+RATE_PUT_SAMPLE(u8, int8_t, (smp >> 8) ^ 0x80)
+RATE_PUT_SAMPLE(s16_le, int16_t, my_little_swap16(smp))
+RATE_PUT_SAMPLE(s16_be, int16_t, my_big_swap16(smp))
+RATE_PUT_SAMPLE(u16_le, int16_t, my_little_swap16(smp ^ 0x8000))
+RATE_PUT_SAMPLE(u16_be, int16_t, my_big_swap16(smp ^ 0x8000))
+RATE_PUT_SAMPLE(s24_le, int32_t, my_little_swap32(smp << 8))
+RATE_PUT_SAMPLE(s24_be, int32_t, my_big_swap32(smp << 8))
+RATE_PUT_SAMPLE(u24_le, int32_t, my_little_swap32((smp ^ 0x8000) >> 8))
+RATE_PUT_SAMPLE(u24_be, int32_t, my_big_swap32((smp ^ 0x8000) >> 8))
+RATE_PUT_SAMPLE(s32_le, int32_t, my_little_swap32(smp >> 16))
+RATE_PUT_SAMPLE(s32_be, int32_t, my_big_swap32(smp >> 16))
+RATE_PUT_SAMPLE(u32_le, int32_t, my_little_swap32((smp ^ 0x8000) >> 16))
+RATE_PUT_SAMPLE(u32_be, int32_t, my_big_swap32((smp ^ 0x8000) >> 16))
+
+static put_sample_f rate_put_sample[] = {
+ [SND_PCM_SFMT_S8] rate_put_sample_s8,
+ [SND_PCM_SFMT_U8] rate_put_sample_u8,
+ [SND_PCM_SFMT_S16_LE] rate_put_sample_s16_le,
+ [SND_PCM_SFMT_S16_BE] rate_put_sample_s16_be,
+ [SND_PCM_SFMT_U16_LE] rate_put_sample_u16_le,
+ [SND_PCM_SFMT_U16_BE] rate_put_sample_u16_be,
+ [SND_PCM_SFMT_S24_LE] rate_put_sample_s24_le,
+ [SND_PCM_SFMT_S24_BE] rate_put_sample_s24_be,
+ [SND_PCM_SFMT_U24_LE] rate_put_sample_u24_le,
+ [SND_PCM_SFMT_U24_BE] rate_put_sample_u24_be,
+ [SND_PCM_SFMT_S32_LE] rate_put_sample_s32_le,
+ [SND_PCM_SFMT_S32_BE] rate_put_sample_s32_be,
+ [SND_PCM_SFMT_U32_LE] rate_put_sample_u32_le,
+ [SND_PCM_SFMT_U32_BE] rate_put_sample_u32_be
+};
+
+int snd_pcm_plugin_build_rate(snd_pcm_plugin_handle_t *handle,
+ snd_pcm_format_t *src_format,
snd_pcm_format_t *dst_format,
snd_pcm_plugin_t **r_plugin)
{
struct rate_private_data *data;
snd_pcm_plugin_t *plugin;
- int voice;
if (r_plugin == NULL)
return -EINVAL;
if (src_format->interleave != dst_format->interleave &&
src_format->voices > 1)
return -EINVAL;
- if (src_format->format != dst_format->format)
- return -EINVAL;
if (!dst_format->interleave)
return -EINVAL;
if (src_format->voices != dst_format->voices)
return -EINVAL;
- if (dst_format->voices < 1 || dst_format->voices > MAX_VOICES)
+ if (dst_format->voices < 1)
return -EINVAL;
-
- if (src_format->format != SND_PCM_SFMT_S16_LE &&
- src_format->format != SND_PCM_SFMT_U8)
+ if (snd_pcm_format_linear(src_format->format) <= 0)
+ return -EINVAL;
+ if (snd_pcm_format_linear(dst_format->format) <= 0)
return -EINVAL;
if (src_format->rate == dst_format->rate)
return -EINVAL;
- plugin = snd_pcm_plugin_build("rate conversion",
- sizeof(struct rate_private_data));
+ plugin = snd_pcm_plugin_build(handle,
+ "rate conversion",
+ src_format,
+ dst_format,
+ sizeof(rate_t) +
+ src_format->voices * sizeof(rate_voice_t));
if (plugin == NULL)
return -ENOMEM;
- data = (struct rate_private_data *)snd_pcm_plugin_extra_data(plugin);
- data->sample_size = src_format->format == SND_PCM_SFMT_S16_LE ? 2 : 1;
- data->src_voices = src_format->voices;
- data->dst_voices = dst_format->voices;
- data->src_rate = src_format->rate;
- data->dst_rate = dst_format->rate;
+ data = (rate_t *)plugin->extra_data;
+ data->plugin = plugin;
+ data->take = rate_take_sample[src_format->format];
+ data->put = rate_put_sample[dst_format->format];
if (src_format->rate < dst_format->rate) {
- data->expand = 1;
data->pitch = ((src_format->rate << SHIFT) + (dst_format->rate >> 1)) / dst_format->rate;
} else {
- data->expand = 0;
data->pitch = ((dst_format->rate << SHIFT) + (src_format->rate >> 1)) / src_format->rate;
}
data->pos = 0;
- for (voice = 0; voice < data->src_voices; ++voice) {
- data->last_S1[voice] = data->last_S2[voice] = 0;
- }
- data->old_src_size = data->old_dst_size = 0;
+ rate_init(plugin, data);
+ data->old_src_samples = data->old_dst_samples = 0;
plugin->transfer = rate_transfer;
- plugin->src_size = rate_src_size;
- plugin->dst_size = rate_dst_size;
+ plugin->src_samples = rate_src_samples;
+ plugin->dst_samples = rate_dst_samples;
plugin->action = rate_action;
*r_plugin = plugin;
return 0;
return -EINVAL;
if (src_size == 0)
return 0;
- data = (struct route_private_data *)snd_pcm_plugin_extra_data(plugin);
+ data = (struct route_private_data *)plugin->extra_data;
data->func(data, src_ptr, dst_ptr, src_size, dst_size);
return dst_size;
}
sizeof(data->ttable[0]) * src_format->voices * dst_format->voices);
if (plugin == NULL)
return -ENOMEM;
- data = (struct route_private_data *)snd_pcm_plugin_extra_data(plugin);
+ data = (struct route_private_data *)plugin->extra_data;
data->src_voices = src_format->voices;
data->dst_voices = dst_format->voices;
#include <unistd.h>
#include <string.h>
#include <errno.h>
+#include <sys/uio.h>
#include "../pcm_local.h"
/*
* Basic stream plugin
*/
-struct stream_private_data {
- snd_pcm_t *pcm;
+typedef struct stream_private_data {
int channel;
-};
+} stream_t;
static ssize_t stream_transfer(snd_pcm_plugin_t *plugin,
- char *src_ptr, size_t src_size,
- char *dst_ptr, size_t dst_size)
+ const snd_pcm_plugin_voice_t *src_voices,
+ const snd_pcm_plugin_voice_t *dst_voices,
+ size_t samples)
{
- struct stream_private_data *data;
+ stream_t *data;
+ ssize_t result;
+ struct iovec *vec;
+ int count, voice;
- if (plugin == NULL || dst_ptr == NULL || dst_size <= 0)
+ if (plugin == NULL)
return -EINVAL;
- data = (struct stream_private_data *)snd_pcm_plugin_extra_data(plugin);
+ data = (stream_t *)plugin->extra_data;
if (data == NULL)
return -EINVAL;
+ vec = (struct iovec *)((char *)data + sizeof(*data));
if (data->channel == SND_PCM_CHANNEL_PLAYBACK) {
- return snd_pcm_write(data->pcm, dst_ptr, dst_size);
+ if (src_voices == NULL)
+ return -EINVAL;
+ if ((result = snd_pcm_plugin_src_samples_to_size(plugin, samples)) < 0)
+ return result;
+ if (plugin->src_format.interleave) {
+ vec->iov_base = src_voices->addr;
+ vec->iov_len = result;
+ count = 1;
+ } else {
+ count = plugin->src_format.voices;
+ result /= count;
+ for (voice = 0; voice < count; voice++) {
+ vec[voice].iov_base = src_voices[voice].addr;
+ vec[voice].iov_len = result;
+ }
+ }
+ result = snd_pcm_writev(plugin->handle, vec, count);
+ if (result < 0)
+ return result;
+ return snd_pcm_plugin_src_size_to_samples(plugin, result);
} else if (data->channel == SND_PCM_CHANNEL_CAPTURE) {
- return snd_pcm_read(data->pcm, dst_ptr, dst_size);
+ if (dst_voices == NULL)
+ return -EINVAL;
+ if ((result = snd_pcm_plugin_dst_samples_to_size(plugin, samples)) < 0)
+ return result;
+ if (plugin->dst_format.interleave) {
+ vec->iov_base = dst_voices->addr;
+ vec->iov_len = result;
+ count = 1;
+ } else {
+ count = plugin->dst_format.voices;
+ result /= count;
+ for (voice = 0; voice < count; voice++) {
+ vec[voice].iov_base = dst_voices[voice].addr;
+ vec[voice].iov_len = result;
+ }
+ }
+ result = snd_pcm_readv(plugin->handle, vec, count);
+ return snd_pcm_plugin_dst_size_to_samples(plugin, result);
} else {
return -EINVAL;
}
}
-int snd_pcm_plugin_build_stream(snd_pcm_t *pcm, int channel, snd_pcm_plugin_t **r_plugin)
+int snd_pcm_plugin_build_stream(snd_pcm_t *pcm, int channel,
+ snd_pcm_format_t *format,
+ snd_pcm_plugin_t **r_plugin)
{
- struct stream_private_data *data;
+ stream_t *data;
snd_pcm_plugin_t *plugin;
if (!r_plugin)
*r_plugin = NULL;
if (!pcm || channel < 0 || channel > 1)
return -EINVAL;
- plugin = snd_pcm_plugin_build(channel == SND_PCM_CHANNEL_PLAYBACK ?
+ plugin = snd_pcm_plugin_build(pcm,
+ channel == SND_PCM_CHANNEL_PLAYBACK ?
"I/O stream playback" :
"I/O stream capture",
- sizeof(struct stream_private_data));
+ format, format,
+ sizeof(stream_t) + sizeof(struct iovec) * format->voices);
if (plugin == NULL)
return -ENOMEM;
- data = (struct stream_private_data *)snd_pcm_plugin_extra_data(plugin);
- data->pcm = pcm;
+ data = (stream_t *)plugin->extra_data;
data->channel = channel;
plugin->transfer = stream_transfer;
*r_plugin = plugin;