- splitted mmap in logical steps

- optimized mmap transfer
- completed mmap helpers
- renamed pcm_plugin_build.c to pcm_common.c
This commit is contained in:
Abramo Bagnara 2000-05-16 15:20:34 +00:00
parent 5b42e338bb
commit 7b054f4dce
17 changed files with 658 additions and 781 deletions

1
TODO
View file

@ -1,6 +1,5 @@
M plug sync and pos problems
M Loopback implementation?
L break up snd_pcm_mmap_* in logical steps
L complete mmap emulation (after plug sync and pos thought)
L add hsearch_r code from glibc (for compatibility with older distributions)
L move OSS emulation to user space (LD_PRELOAD)

View file

@ -97,7 +97,6 @@ int snd_pcm_channel_info(snd_pcm_t *handle, snd_pcm_channel_info_t *info);
int snd_pcm_channel_params(snd_pcm_t *handle, snd_pcm_channel_params_t *params);
int snd_pcm_channel_setup(snd_pcm_t *handle, snd_pcm_channel_setup_t *setup);
int snd_pcm_voice_setup(snd_pcm_t *handle, int channel, snd_pcm_voice_setup_t *setup);
int snd_pcm_all_voices_setup(snd_pcm_t *handle, int channel, snd_pcm_voice_setup_t *setup);
int snd_pcm_channel_status(snd_pcm_t *handle, snd_pcm_channel_status_t *status);
int snd_pcm_channel_update(snd_pcm_t *handle, int channel);
int snd_pcm_playback_prepare(snd_pcm_t *handle);
@ -126,17 +125,36 @@ int snd_pcm_mmap_data(snd_pcm_t *handle, int channel, void **buffer);
int snd_pcm_munmap_control(snd_pcm_t *handle, int channel);
int snd_pcm_munmap_data(snd_pcm_t *handle, int channel);
int snd_pcm_voices_mask(snd_pcm_t *pcm, int channel, bitset_t *client_vmask);
int snd_pcm_mmap_frags_used(snd_pcm_t *pcm, int channel, ssize_t *frags);
int snd_pcm_mmap_frags_free(snd_pcm_t *pcm, int channel, ssize_t *frags);
int snd_pcm_mmap_bytes_used(snd_pcm_t *pcm, int channel, ssize_t *bytes);
int snd_pcm_mmap_bytes_free(snd_pcm_t *pcm, int channel, ssize_t *bytes);
int snd_pcm_mmap_ready(snd_pcm_t *pcm, int channel);
ssize_t snd_pcm_mmap_write(snd_pcm_t *handle, const void *buffer, size_t size);
ssize_t snd_pcm_mmap_read(snd_pcm_t *handle, void *buffer, size_t size);
ssize_t snd_pcm_mmap_writev(snd_pcm_t *pcm, const struct iovec *vector, unsigned long count);
ssize_t snd_pcm_mmap_readv(snd_pcm_t *pcm, const struct iovec *vector, unsigned long count);
int snd_pcm_mmap_samples_used(snd_pcm_t *pcm, int channel, ssize_t *samples);
int snd_pcm_mmap_samples_free(snd_pcm_t *pcm, int channel, ssize_t *samples);
ssize_t snd_pcm_mmap_samples_xfer(snd_pcm_t *pcm, int channel, size_t samples);
ssize_t snd_pcm_mmap_samples_offset(snd_pcm_t *pcm, int channel);
int snd_pcm_mmap_commit_samples(snd_pcm_t *pcm, int channel, int samples);
ssize_t snd_pcm_mmap_write_areas(snd_pcm_t *pcm, snd_pcm_voice_area_t *voices, size_t samples);
ssize_t snd_pcm_mmap_write_samples(snd_pcm_t *pcm, const void *buffer, size_t samples);
ssize_t snd_pcm_mmap_read_areas(snd_pcm_t *pcm, snd_pcm_voice_area_t *voices, size_t samples);
ssize_t snd_pcm_mmap_read_samples(snd_pcm_t *pcm, const void *buffer, size_t samples);
int snd_pcm_mmap_get_areas(snd_pcm_t *pcm, int channel, snd_pcm_voice_area_t *areas);
ssize_t snd_pcm_bytes_per_second(snd_pcm_t *pcm, int channel);
int snd_pcm_area_silence(const snd_pcm_voice_area_t *dst_voice, size_t dst_offset,
size_t samples, int format);
int snd_pcm_areas_silence(const snd_pcm_voice_area_t *dst_voices, size_t dst_offset,
size_t vcount, size_t samples, int format);
int snd_pcm_area_copy(const snd_pcm_voice_area_t *src_voice, size_t src_offset,
const snd_pcm_voice_area_t *dst_voice, size_t dst_offset,
size_t samples, int format);
int snd_pcm_areas_copy(const snd_pcm_voice_area_t *src_voices, size_t src_offset,
const snd_pcm_voice_area_t *dst_voices, size_t dst_offset,
size_t vcount, size_t samples, int format);
/* misc */
int snd_pcm_format_signed(int format);
@ -181,9 +199,7 @@ typedef enum {
typedef struct snd_stru_pcm_plugin_voice {
void *aptr; /* pointer to the allocated area */
void *addr; /* address to voice samples */
unsigned int first; /* offset to first sample in bits */
unsigned int step; /* samples distance in bits */
snd_pcm_voice_area_t area;
unsigned int enabled:1; /* voice need to be processed */
unsigned int wanted:1; /* voice is wanted */
} snd_pcm_plugin_voice_t;

View file

@ -2,7 +2,7 @@ SUBDIRS = plugin
EXTRA_LTLIBRARIES = libpcm.la
libpcm_la_SOURCES = pcm.c pcm_hw.c pcm_plug.c pcm_plugin_build.c pcm_misc.c \
libpcm_la_SOURCES = pcm.c pcm_hw.c pcm_plug.c pcm_common.c pcm_misc.c \
pcm_mmap.c
libpcm_la_LIBADD = plugin/libpcmplugin.la
noinst_HEADERS = pcm_local.h

View file

@ -83,10 +83,6 @@ int snd_pcm_channel_close(snd_pcm_t *pcm, int channel)
ret = err;
chan->open = 0;
chan->valid_setup = 0;
if (chan->valid_voices_setup) {
chan->valid_voices_setup = 0;
free(chan->voices_setup);
}
return ret;
}
@ -182,6 +178,9 @@ int snd_pcm_channel_setup(snd_pcm_t *pcm, snd_pcm_channel_setup_t *setup)
if ((err = pcm->ops->channel_setup(pcm, setup)) < 0)
return err;
memcpy(&chan->setup, setup, sizeof(*setup));
chan->sample_width = snd_pcm_format_physical_width(setup->format.format);
chan->bits_per_sample = chan->sample_width * setup->format.voices;
chan->samples_per_frag = setup->frag_size * 8 / chan->bits_per_sample;
chan->valid_setup = 1;
return 0;
}
@ -209,61 +208,9 @@ int snd_pcm_voice_setup(snd_pcm_t *pcm, int channel, snd_pcm_voice_setup_t *setu
chan = &pcm->chan[channel];
if (!chan->open || !chan->valid_setup)
return -EBADFD;
if (chan->valid_voices_setup) {
if (setup->voice >= chan->setup.format.voices)
return -EINVAL;
memcpy(setup, &chan->voices_setup[setup->voice], sizeof(*setup));
return 0;
}
return pcm->ops->voice_setup(pcm, channel, setup);
}
const snd_pcm_voice_setup_t* snd_pcm_channel_cached_voice_setup(snd_pcm_t *pcm, int channel, unsigned int voice)
{
struct snd_pcm_chan *chan;
if (!pcm)
return 0;
if (channel < 0 || channel > 1)
return 0;
chan = &pcm->chan[channel];
if (!chan->open || !chan->valid_setup)
return 0;
if (voice >= chan->setup.format.voices)
return 0;
return &chan->voices_setup[voice];
}
int snd_pcm_all_voices_setup(snd_pcm_t *pcm, int channel, snd_pcm_voice_setup_t *setup)
{
struct snd_pcm_chan *chan;
snd_pcm_voice_setup_t *vs, *v;
unsigned int voice;
int err;
if (!pcm)
return -EFAULT;
if (channel < 0 || channel > 1)
return -EINVAL;
chan = &pcm->chan[channel];
if (!chan->open || !chan->valid_setup)
return -EBADFD;
vs = calloc(chan->setup.format.voices, sizeof(*setup));
for (voice = 0, v = vs; voice < chan->setup.format.voices; ++voice, ++v) {
v->voice = voice;
err = snd_pcm_voice_setup(pcm, channel, v);
if (err < 0) {
free(vs);
return err;
}
if (setup) {
memcpy(setup, v, sizeof(*setup));
setup++;
}
}
chan->voices_setup = vs;
chan->valid_voices_setup = 1;
return 0;
}
int snd_pcm_channel_status(snd_pcm_t *pcm, snd_pcm_channel_status_t *status)
{
if (!pcm || !status)

View file

@ -82,8 +82,10 @@ struct snd_pcm_chan {
int mode;
int valid_setup;
snd_pcm_channel_setup_t setup;
int valid_voices_setup;
snd_pcm_voice_setup_t *voices_setup;
snd_pcm_voice_area_t *voices;
size_t sample_width;
size_t bits_per_sample;
size_t samples_per_frag;
snd_pcm_mmap_control_t *mmap_control;
size_t mmap_control_size;
int mmap_control_emulation;
@ -141,13 +143,8 @@ void snd_pcm_plug_buf_unlock(snd_pcm_t *pcm, int channel, void *ptr);
#define ROUTE_PLUGIN_RESOLUTION 16
int getput_index(int format);
int copy_index(int format);
int conv_index(int src_format, int dst_format);
void snd_pcm_plugin_silence_voice(snd_pcm_plugin_t *plugin,
const snd_pcm_plugin_voice_t *dst_voice,
size_t samples);
#ifdef PLUGIN_DEBUG
#define pdprintf( args... ) fprintf(stderr, "plugin: " ##args)
#else

File diff suppressed because it is too large Load diff

View file

@ -438,6 +438,7 @@ static int snd_pcm_plug_channel_params(snd_pcm_t *pcm, snd_pcm_channel_params_t
}
/* compute right sizes */
slave_params.buffer_size = snd_pcm_plug_slave_size(pcm, channel, slave_params.buffer_size);
slave_params.frag_size = snd_pcm_plug_slave_size(pcm, channel, slave_params.frag_size);
if (params->mode == SND_PCM_MODE_STREAM) {
slave_params.buf.stream.bytes_fill_max = snd_pcm_plug_slave_size(pcm, channel, slave_params.buf.stream.bytes_fill_max);
@ -471,7 +472,7 @@ static int snd_pcm_plug_channel_setup(snd_pcm_t *pcm, snd_pcm_channel_setup_t *s
setup->buffer_size = snd_pcm_plug_client_size(pcm, setup->channel, setup->buffer_size);
setup->frag_size = snd_pcm_plug_client_size(pcm, setup->channel, setup->frag_size);
/* FIXME: it may overflow */
setup->pos_boundary = snd_pcm_plug_client_size(pcm, setup->channel, setup->pos_boundary);
setup->byte_boundary = snd_pcm_plug_client_size(pcm, setup->channel, setup->byte_boundary);
if (setup->mode == SND_PCM_MODE_STREAM) {
setup->buf.stream.bytes_min = snd_pcm_plug_client_size(pcm, setup->channel, setup->buf.stream.bytes_min);
setup->buf.stream.bytes_align = snd_pcm_plug_client_size(pcm, setup->channel, setup->buf.stream.bytes_align);
@ -500,8 +501,8 @@ static int snd_pcm_plug_channel_status(snd_pcm_t *pcm, snd_pcm_channel_status_t
return 0;
/* FIXME: may overflow */
status->pos_io = snd_pcm_plug_client_size(pcm, status->channel, status->pos_io);
status->pos_data = snd_pcm_plug_client_size(pcm, status->channel, status->pos_data);
status->byte_io = snd_pcm_plug_client_size(pcm, status->channel, status->byte_io);
status->byte_data = snd_pcm_plug_client_size(pcm, status->channel, status->byte_data);
status->bytes_used = snd_pcm_plug_client_size(pcm, status->channel, status->bytes_used);
status->bytes_free = snd_pcm_plug_client_size(pcm, status->channel, status->bytes_free);
return 0;
@ -605,8 +606,8 @@ static int snd_pcm_plug_voice_setup(snd_pcm_t *pcm, int channel, snd_pcm_voice_s
memset(setup, 0, sizeof(*setup));
setup->voice = voice;
chan = &pcm->chan[channel];
if (!chan->mmap_control) {
setup->addr = -1;
if (!chan->mmap_data) {
setup->area.addr = 0;
return 0;
}
if (voice >= chan->setup.format.voices)
@ -617,14 +618,14 @@ static int snd_pcm_plug_voice_setup(snd_pcm_t *pcm, int channel, snd_pcm_voice_s
return width;
size = chan->mmap_data_size;
if (chan->setup.format.interleave) {
setup->addr = 0;
setup->first = voice * width;
setup->step = chan->setup.format.voices * width;
setup->area.addr = chan->mmap_data;
setup->area.first = chan->sample_width;
setup->area.step = chan->bits_per_sample;
} else {
size /= chan->setup.format.voices;
setup->addr = setup->voice * size;
setup->first = 0;
setup->step = width;
setup->area.addr = chan->mmap_data + setup->voice * size;
setup->area.first = 0;
setup->area.step = width;
}
return 0;
}

View file

@ -231,17 +231,17 @@ static void adpcm_decode(snd_pcm_plugin_t *plugin,
adpcm_voice_t *state;
if (!src_voices[voice].enabled) {
if (dst_voices[voice].wanted)
snd_pcm_plugin_silence_voice(plugin, &dst_voices[voice], samples);
snd_pcm_area_silence(&dst_voices[voice].area, 0, samples, plugin->dst_format.format);
dst_voices[voice].enabled = 0;
continue;
}
dst_voices[voice].enabled = 1;
src = src_voices[voice].addr + src_voices[voice].first / 8;
srcbit = src_voices[voice].first % 8;
dst = dst_voices[voice].addr + dst_voices[voice].first / 8;
src_step = src_voices[voice].step / 8;
srcbit_step = src_voices[voice].step % 8;
dst_step = dst_voices[voice].step / 8;
src = src_voices[voice].area.addr + src_voices[voice].area.first / 8;
srcbit = src_voices[voice].area.first % 8;
dst = dst_voices[voice].area.addr + dst_voices[voice].area.first / 8;
src_step = src_voices[voice].area.step / 8;
srcbit_step = src_voices[voice].area.step % 8;
dst_step = dst_voices[voice].area.step / 8;
state = &data->voices[voice];
samples1 = samples;
while (samples1-- > 0) {
@ -290,17 +290,17 @@ static void adpcm_encode(snd_pcm_plugin_t *plugin,
adpcm_voice_t *state;
if (!src_voices[voice].enabled) {
if (dst_voices[voice].wanted)
snd_pcm_plugin_silence_voice(plugin, &dst_voices[voice], samples);
snd_pcm_area_silence(&dst_voices[voice].area, 0, samples, plugin->dst_format.format);
dst_voices[voice].enabled = 0;
continue;
}
dst_voices[voice].enabled = 1;
src = src_voices[voice].addr + src_voices[voice].first / 8;
dst = dst_voices[voice].addr + dst_voices[voice].first / 8;
dstbit = dst_voices[voice].first % 8;
src_step = src_voices[voice].step / 8;
dst_step = dst_voices[voice].step / 8;
dstbit_step = dst_voices[voice].step % 8;
src = src_voices[voice].area.addr + src_voices[voice].area.first / 8;
dst = dst_voices[voice].area.addr + dst_voices[voice].area.first / 8;
dstbit = dst_voices[voice].area.first % 8;
src_step = src_voices[voice].area.step / 8;
dst_step = dst_voices[voice].area.step / 8;
dstbit_step = dst_voices[voice].area.step % 8;
state = &data->voices[voice];
samples1 = samples;
while (samples1-- > 0) {
@ -340,16 +340,16 @@ static ssize_t adpcm_transfer(snd_pcm_plugin_t *plugin,
return 0;
for (voice = 0; voice < plugin->src_format.voices; voice++) {
if (plugin->src_format.format == SND_PCM_SFMT_IMA_ADPCM) {
if (src_voices[voice].first % 4 != 0 ||
src_voices[voice].step % 4 != 0 ||
dst_voices[voice].first % 8 != 0 ||
dst_voices[voice].step % 8 != 0)
if (src_voices[voice].area.first % 4 != 0 ||
src_voices[voice].area.step % 4 != 0 ||
dst_voices[voice].area.first % 8 != 0 ||
dst_voices[voice].area.step % 8 != 0)
return -EINVAL;
} else {
if (src_voices[voice].first % 8 != 0 ||
src_voices[voice].step % 8 != 0 ||
dst_voices[voice].first % 4 != 0 ||
dst_voices[voice].step % 4 != 0)
if (src_voices[voice].area.first % 8 != 0 ||
src_voices[voice].area.step % 8 != 0 ||
dst_voices[voice].area.first % 4 != 0 ||
dst_voices[voice].area.step % 4 != 0)
return -EINVAL;
}
}

View file

@ -161,15 +161,15 @@ static void alaw_decode(snd_pcm_plugin_t *plugin,
size_t samples1;
if (!src_voices[voice].enabled) {
if (dst_voices[voice].wanted)
snd_pcm_plugin_silence_voice(plugin, &dst_voices[voice], samples);
snd_pcm_area_silence(&dst_voices[voice].area, 0, samples, plugin->dst_format.format);
dst_voices[voice].enabled = 0;
continue;
}
dst_voices[voice].enabled = 1;
src = src_voices[voice].addr + src_voices[voice].first / 8;
dst = dst_voices[voice].addr + dst_voices[voice].first / 8;
src_step = src_voices[voice].step / 8;
dst_step = dst_voices[voice].step / 8;
src = src_voices[voice].area.addr + src_voices[voice].area.first / 8;
dst = dst_voices[voice].area.addr + dst_voices[voice].area.first / 8;
src_step = src_voices[voice].area.step / 8;
dst_step = dst_voices[voice].area.step / 8;
samples1 = samples;
while (samples1-- > 0) {
signed short sample = alaw2linear(*src);
@ -204,15 +204,15 @@ static void alaw_encode(snd_pcm_plugin_t *plugin,
size_t samples1;
if (!src_voices[voice].enabled) {
if (dst_voices[voice].wanted)
snd_pcm_plugin_silence_voice(plugin, &dst_voices[voice], samples);
snd_pcm_area_silence(&dst_voices[voice].area, 0, samples, plugin->dst_format.format);
dst_voices[voice].enabled = 0;
continue;
}
dst_voices[voice].enabled = 1;
src = src_voices[voice].addr + src_voices[voice].first / 8;
dst = dst_voices[voice].addr + dst_voices[voice].first / 8;
src_step = src_voices[voice].step / 8;
dst_step = dst_voices[voice].step / 8;
src = src_voices[voice].area.addr + src_voices[voice].area.first / 8;
dst = dst_voices[voice].area.addr + dst_voices[voice].area.first / 8;
src_step = src_voices[voice].area.step / 8;
dst_step = dst_voices[voice].area.step / 8;
samples1 = samples;
while (samples1-- > 0) {
goto *get;
@ -240,11 +240,11 @@ static ssize_t alaw_transfer(snd_pcm_plugin_t *plugin,
if (samples == 0)
return 0;
for (voice = 0; voice < plugin->src_format.voices; voice++) {
if (src_voices[voice].first % 8 != 0 ||
src_voices[voice].step % 8 != 0)
if (src_voices[voice].area.first % 8 != 0 ||
src_voices[voice].area.step % 8 != 0)
return -EINVAL;
if (dst_voices[voice].first % 8 != 0 ||
dst_voices[voice].step % 8 != 0)
if (dst_voices[voice].area.first % 8 != 0 ||
dst_voices[voice].area.step % 8 != 0)
return -EINVAL;
}
data = (alaw_t *)plugin->extra_data;

View file

@ -68,12 +68,12 @@ static ssize_t block_transfer(snd_pcm_plugin_t *plugin,
return result;
count = plugin->src_format.voices;
if (plugin->src_format.interleave) {
result = snd_pcm_write(data->slave, src_voices->addr, result);
result = snd_pcm_write(data->slave, src_voices->area.addr, result);
} else {
result /= count;
for (voice = 0; voice < count; voice++) {
if (src_voices[voice].enabled)
vec[voice].iov_base = src_voices[voice].addr;
vec[voice].iov_base = src_voices[voice].area.addr;
else
vec[voice].iov_base = 0;
vec[voice].iov_len = result;
@ -90,7 +90,7 @@ static ssize_t block_transfer(snd_pcm_plugin_t *plugin,
return result;
count = plugin->dst_format.voices;
if (plugin->dst_format.interleave) {
result = snd_pcm_read(data->slave, dst_voices->addr, result);
result = snd_pcm_read(data->slave, dst_voices->area.addr, result);
for (voice = 0; voice < count; voice++) {
dst_voices[voice].enabled = src_voices[voice].enabled;
}
@ -99,7 +99,7 @@ static ssize_t block_transfer(snd_pcm_plugin_t *plugin,
for (voice = 0; voice < count; voice++) {
dst_voices[voice].enabled = src_voices[voice].enabled;
if (dst_voices[voice].enabled)
vec[voice].iov_base = dst_voices[voice].addr;
vec[voice].iov_base = dst_voices[voice].area.addr;
else
vec[voice].iov_base = 0;
vec[voice].iov_len = result;

View file

@ -35,121 +35,63 @@
#include "../pcm_local.h"
#endif
typedef struct copy_private_data {
int copy;
} copy_t;
static void copy(snd_pcm_plugin_t *plugin,
const snd_pcm_plugin_voice_t *src_voices,
snd_pcm_plugin_voice_t *dst_voices,
size_t samples)
{
#define COPY_LABELS
#include "plugin_ops.h"
#undef COPY_LABELS
copy_t *data = (copy_t *)plugin->extra_data;
void *copy = copy_labels[data->copy];
int voice;
int nvoices = plugin->src_format.voices;
for (voice = 0; voice < nvoices; ++voice) {
char *src;
char *dst;
int src_step, dst_step;
size_t samples1;
if (!src_voices[voice].enabled) {
if (dst_voices[voice].wanted)
snd_pcm_plugin_silence_voice(plugin, &dst_voices[voice], samples);
dst_voices[voice].enabled = 0;
continue;
}
dst_voices[voice].enabled = 1;
src = src_voices[voice].addr + src_voices[voice].first / 8;
dst = dst_voices[voice].addr + dst_voices[voice].first / 8;
src_step = src_voices[voice].step / 8;
dst_step = dst_voices[voice].step / 8;
samples1 = samples;
while (samples1-- > 0) {
goto *copy;
#define COPY_END after
#include "plugin_ops.h"
#undef COPY_END
after:
src += src_step;
dst += dst_step;
}
}
}
static ssize_t copy_transfer(snd_pcm_plugin_t *plugin,
const snd_pcm_plugin_voice_t *src_voices,
snd_pcm_plugin_voice_t *dst_voices,
size_t samples)
{
copy_t *data;
unsigned int voice;
unsigned int nvoices;
if (plugin == NULL || src_voices == NULL || dst_voices == NULL)
return -EFAULT;
data = (copy_t *)plugin->extra_data;
if (samples == 0)
return 0;
for (voice = 0; voice < plugin->src_format.voices; voice++) {
if (src_voices[voice].first % 8 != 0 ||
src_voices[voice].step % 8 != 0)
nvoices = plugin->src_format.voices;
for (voice = 0; voice < nvoices; voice++) {
if (src_voices[voice].area.first % 8 != 0 ||
src_voices[voice].area.step % 8 != 0)
return -EINVAL;
if (dst_voices[voice].first % 8 != 0 ||
dst_voices[voice].step % 8 != 0)
if (dst_voices[voice].area.first % 8 != 0 ||
dst_voices[voice].area.step % 8 != 0)
return -EINVAL;
if (!src_voices->enabled) {
if (dst_voices->wanted)
snd_pcm_area_silence(&dst_voices->area, 0, samples, plugin->dst_format.format);
dst_voices->enabled = 0;
continue;
}
dst_voices[voice].enabled = 1;
snd_pcm_area_copy(&src_voices->area, 0, &dst_voices->area, 0, samples, plugin->src_format.format);
}
copy(plugin, src_voices, dst_voices, samples);
return samples;
}
int copy_index(int format)
{
int size = snd_pcm_format_physical_width(format);
switch (size) {
case 8:
return 0;
case 16:
return 1;
case 32:
return 2;
case 64:
return 3;
default:
return -EINVAL;
}
}
int snd_pcm_plugin_build_copy(snd_pcm_plugin_handle_t *handle,
int channel,
snd_pcm_format_t *format,
snd_pcm_plugin_t **r_plugin)
{
int err;
struct copy_private_data *data;
snd_pcm_plugin_t *plugin;
int copy;
int width;
if (r_plugin == NULL)
return -EFAULT;
*r_plugin = NULL;
copy = copy_index(format->format);
if (copy < 0)
width = snd_pcm_format_physical_width(format->format);
if (width < 0)
return -EINVAL;
err = snd_pcm_plugin_build(handle, channel,
"copy",
format,
format,
sizeof(copy_t),
0,
&plugin);
if (err < 0)
return err;
data = (copy_t *)plugin->extra_data;
data->copy = copy;
plugin->transfer = copy_transfer;
*r_plugin = plugin;
return 0;

View file

@ -63,15 +63,15 @@ static void convert(snd_pcm_plugin_t *plugin,
size_t samples1;
if (!src_voices[voice].enabled) {
if (dst_voices[voice].wanted)
snd_pcm_plugin_silence_voice(plugin, &dst_voices[voice], samples);
snd_pcm_area_silence(&dst_voices[voice].area, 0, samples, plugin->dst_format.format);
dst_voices[voice].enabled = 0;
continue;
}
dst_voices[voice].enabled = 1;
src = src_voices[voice].addr + src_voices[voice].first / 8;
dst = dst_voices[voice].addr + dst_voices[voice].first / 8;
src_step = src_voices[voice].step / 8;
dst_step = dst_voices[voice].step / 8;
src = src_voices[voice].area.addr + src_voices[voice].area.first / 8;
dst = dst_voices[voice].area.addr + dst_voices[voice].area.first / 8;
src_step = src_voices[voice].area.step / 8;
dst_step = dst_voices[voice].area.step / 8;
samples1 = samples;
while (samples1-- > 0) {
goto *conv;
@ -99,11 +99,11 @@ static ssize_t linear_transfer(snd_pcm_plugin_t *plugin,
if (samples == 0)
return 0;
for (voice = 0; voice < plugin->src_format.voices; voice++) {
if (src_voices[voice].first % 8 != 0 ||
src_voices[voice].step % 8 != 0)
if (src_voices[voice].area.first % 8 != 0 ||
src_voices[voice].area.step % 8 != 0)
return -EINVAL;
if (dst_voices[voice].first % 8 != 0 ||
dst_voices[voice].step % 8 != 0)
if (dst_voices[voice].area.first % 8 != 0 ||
dst_voices[voice].area.step % 8 != 0)
return -EINVAL;
}
convert(plugin, src_voices, dst_voices, samples);

View file

@ -38,9 +38,7 @@ typedef struct mmap_private_data {
snd_pcm_mmap_control_t *control;
void *buffer;
unsigned int frag;
size_t samples_frag_size;
char *silence;
snd_pcm_plugin_voice_t voices[0];
} mmap_t;
@ -50,22 +48,22 @@ static int mmap_src_voices(snd_pcm_plugin_t *plugin,
{
mmap_t *data;
unsigned int voice;
snd_pcm_plugin_voice_t *dv, *sv;
snd_pcm_plugin_voice_t *sv;
snd_pcm_voice_area_t *dv;
struct snd_pcm_chan *chan;
snd_pcm_channel_setup_t *setup;
snd_pcm_mmap_control_t *ctrl;
int frag, f;
struct pollfd pfd;
int ready;
if (plugin == NULL || voices == NULL)
return -EINVAL;
data = (mmap_t *)plugin->extra_data;
if (samples != data->samples_frag_size)
ctrl = data->control;
chan = &data->slave->chan[plugin->channel];
if (samples != chan->samples_per_frag)
return -EINVAL;
ctrl = data->control;
chan = &plugin->handle->chan[plugin->channel];
setup = &chan->setup;
if (ctrl->status < SND_PCM_STATUS_PREPARED)
return -EBADFD;
@ -74,11 +72,12 @@ static int mmap_src_voices(snd_pcm_plugin_t *plugin,
if (ready < 0)
return ready;
if (!ready) {
struct pollfd pfd;
if (ctrl->status != SND_PCM_STATUS_RUNNING)
return -EPIPE;
if (chan->mode & SND_PCM_NONBLOCK)
return -EAGAIN;
pfd.fd = snd_pcm_file_descriptor(plugin->handle, plugin->channel);
pfd.fd = snd_pcm_file_descriptor(data->slave, plugin->channel);
pfd.events = POLLOUT | POLLERR;
ready = poll(&pfd, 1, 10000);
if (ready < 0)
@ -90,16 +89,16 @@ static int mmap_src_voices(snd_pcm_plugin_t *plugin,
frag = ctrl->frag_data;
f = frag % setup->frags;
dv = data->voices;
sv = plugin->src_voices;
dv = chan->voices;
*voices = sv;
for (voice = 0; voice < plugin->src_format.voices; ++voice) {
sv->enabled = 1;
sv->wanted = !data->silence[voice * setup->frags + f];
sv->aptr = 0;
sv->addr = dv->addr + (dv->step * data->samples_frag_size * f) / 8;
sv->first = dv->first;
sv->step = dv->step;
sv->area.addr = dv->addr + (dv->step * chan->samples_per_frag * f) / 8;
sv->area.first = dv->first;
sv->area.step = dv->step;
++sv;
++dv;
}
@ -114,21 +113,21 @@ static int mmap_dst_voices(snd_pcm_plugin_t *plugin,
mmap_t *data;
int err;
unsigned int voice;
snd_pcm_plugin_voice_t *dv, *sv;
snd_pcm_plugin_voice_t *dv;
snd_pcm_voice_area_t *sv;
struct snd_pcm_chan *chan;
snd_pcm_channel_setup_t *setup;
snd_pcm_mmap_control_t *ctrl;
int frag, f;
struct pollfd pfd;
int ready;
if (plugin == NULL || voices == NULL)
return -EINVAL;
data = (mmap_t *)plugin->extra_data;
if (samples != data->samples_frag_size)
chan = &data->slave->chan[plugin->channel];
if (samples != chan->samples_per_frag)
return -EINVAL;
chan = &plugin->handle->chan[plugin->channel];
setup = &chan->setup;
ctrl = data->control;
if (ctrl->status < SND_PCM_STATUS_PREPARED)
@ -143,17 +142,12 @@ static int mmap_dst_voices(snd_pcm_plugin_t *plugin,
if (ready < 0)
return ready;
if (!ready) {
if (ctrl->status == SND_PCM_STATUS_PREPARED &&
chan->setup.start_mode == SND_PCM_START_FULL) {
err = snd_pcm_channel_go(data->slave, plugin->channel);
if (err < 0)
return err;
}
struct pollfd pfd;
if (ctrl->status != SND_PCM_STATUS_RUNNING)
return -EPIPE;
if (chan->mode & SND_PCM_NONBLOCK)
return -EAGAIN;
pfd.fd = snd_pcm_file_descriptor(plugin->handle, plugin->channel);
pfd.fd = snd_pcm_file_descriptor(data->slave, plugin->channel);
pfd.events = POLLIN | POLLERR;
ready = poll(&pfd, 1, 10000);
if (ready < 0)
@ -166,16 +160,16 @@ static int mmap_dst_voices(snd_pcm_plugin_t *plugin,
frag = ctrl->frag_data;
f = frag % setup->frags;
sv = data->voices;
sv = chan->voices;
dv = plugin->dst_voices;
*voices = dv;
for (voice = 0; voice < plugin->dst_format.voices; ++voice) {
dv->enabled = 1;
dv->wanted = 0;
dv->aptr = 0;
dv->addr = sv->addr + (sv->step * data->samples_frag_size * f) / 8;
dv->first = sv->first;
dv->step = sv->step;
dv->area.addr = sv->addr + (sv->step * chan->samples_per_frag * f) / 8;
dv->area.first = sv->first;
dv->area.step = sv->step;
++sv;
++dv;
}
@ -218,14 +212,7 @@ static ssize_t mmap_playback_transfer(snd_pcm_plugin_t *plugin,
data->silence[voice * setup->frags + f] = 0;
}
frag++;
if (frag == setup->frag_boundary) {
ctrl->frag_data = 0;
ctrl->pos_data = 0;
} else {
ctrl->frag_data = frag;
ctrl->pos_data += setup->frag_size;
}
snd_pcm_mmap_commit_samples(data->slave, SND_PCM_CHANNEL_PLAYBACK, samples);
if (ctrl->status == SND_PCM_STATUS_PREPARED &&
(chan->setup.start_mode == SND_PCM_START_DATA ||
(chan->setup.start_mode == SND_PCM_START_FULL &&
@ -262,14 +249,7 @@ static ssize_t mmap_capture_transfer(snd_pcm_plugin_t *plugin,
setup = &data->slave->chan[SND_PCM_CHANNEL_CAPTURE].setup;
/* FIXME: not here the increment */
frag++;
if (frag == setup->frag_boundary) {
ctrl->frag_data = 0;
ctrl->pos_data = 0;
} else {
ctrl->frag_data = frag;
ctrl->pos_data += setup->frag_size;
}
snd_pcm_mmap_commit_samples(data->slave, SND_PCM_CHANNEL_CAPTURE, samples);
return samples;
}
@ -285,8 +265,6 @@ static int mmap_action(snd_pcm_plugin_t *plugin,
if (action == INIT) {
snd_pcm_channel_setup_t *setup;
int result;
unsigned int voice;
snd_pcm_plugin_voice_t *v;
if (data->control)
snd_pcm_munmap(data->slave, plugin->channel);
@ -294,22 +272,7 @@ static int mmap_action(snd_pcm_plugin_t *plugin,
if (result < 0)
return result;
setup = &data->slave->chan[plugin->channel].setup;
data->samples_frag_size = setup->frag_size / snd_pcm_format_size(setup->format.format, setup->format.voices);
v = data->voices;
for (voice = 0; voice < setup->format.voices; ++voice) {
snd_pcm_voice_setup_t vsetup;
vsetup.voice = voice;
if ((result = snd_pcm_voice_setup(data->slave, plugin->channel, &vsetup)) < 0)
return result;
if (vsetup.addr < 0)
return -EBADFD;
v->addr = data->buffer + vsetup.addr;
v->first = vsetup.first;
v->step = vsetup.step;
v++;
}
if (plugin->channel == SND_PCM_CHANNEL_PLAYBACK) {
data->silence = malloc(setup->frags * setup->format.voices);
memset(data->silence, 0, setup->frags * setup->format.voices);

View file

@ -177,15 +177,15 @@ static void mulaw_decode(snd_pcm_plugin_t *plugin,
size_t samples1;
if (!src_voices[voice].enabled) {
if (dst_voices[voice].wanted)
snd_pcm_plugin_silence_voice(plugin, &dst_voices[voice], samples);
snd_pcm_area_silence(&dst_voices[voice].area, 0, samples, plugin->dst_format.format);
dst_voices[voice].enabled = 0;
continue;
}
dst_voices[voice].enabled = 1;
src = src_voices[voice].addr + src_voices[voice].first / 8;
dst = dst_voices[voice].addr + dst_voices[voice].first / 8;
src_step = src_voices[voice].step / 8;
dst_step = dst_voices[voice].step / 8;
src = src_voices[voice].area.addr + src_voices[voice].area.first / 8;
dst = dst_voices[voice].area.addr + dst_voices[voice].area.first / 8;
src_step = src_voices[voice].area.step / 8;
dst_step = dst_voices[voice].area.step / 8;
samples1 = samples;
while (samples1-- > 0) {
signed short sample = ulaw2linear(*src);
@ -220,15 +220,15 @@ static void mulaw_encode(snd_pcm_plugin_t *plugin,
size_t samples1;
if (!src_voices[voice].enabled) {
if (dst_voices[voice].wanted)
snd_pcm_plugin_silence_voice(plugin, &dst_voices[voice], samples);
snd_pcm_area_silence(&dst_voices[voice].area, 0, samples, plugin->dst_format.format);
dst_voices[voice].enabled = 0;
continue;
}
dst_voices[voice].enabled = 1;
src = src_voices[voice].addr + src_voices[voice].first / 8;
dst = dst_voices[voice].addr + dst_voices[voice].first / 8;
src_step = src_voices[voice].step / 8;
dst_step = dst_voices[voice].step / 8;
src = src_voices[voice].area.addr + src_voices[voice].area.first / 8;
dst = dst_voices[voice].area.addr + dst_voices[voice].area.first / 8;
src_step = src_voices[voice].area.step / 8;
dst_step = dst_voices[voice].area.step / 8;
samples1 = samples;
while (samples1-- > 0) {
goto *get;
@ -256,11 +256,11 @@ static ssize_t mulaw_transfer(snd_pcm_plugin_t *plugin,
if (samples == 0)
return 0;
for (voice = 0; voice < plugin->src_format.voices; voice++) {
if (src_voices[voice].first % 8 != 0 ||
src_voices[voice].step % 8 != 0)
if (src_voices[voice].area.first % 8 != 0 ||
src_voices[voice].area.step % 8 != 0)
return -EINVAL;
if (dst_voices[voice].first % 8 != 0 ||
dst_voices[voice].step % 8 != 0)
if (dst_voices[voice].area.first % 8 != 0 ||
dst_voices[voice].area.step % 8 != 0)
return -EINVAL;
}
data = (mulaw_t *)plugin->extra_data;

View file

@ -106,15 +106,15 @@ static void resample_expand(snd_pcm_plugin_t *plugin,
S2 = rvoices->last_S2;
if (!src_voices[voice].enabled) {
if (dst_voices[voice].wanted)
snd_pcm_plugin_silence_voice(plugin, &dst_voices[voice], dst_samples);
snd_pcm_area_silence(&dst_voices[voice].area, 0, dst_samples, plugin->dst_format.format);
dst_voices[voice].enabled = 0;
continue;
}
dst_voices[voice].enabled = 1;
src = (char *)src_voices[voice].addr + src_voices[voice].first / 8;
dst = (char *)dst_voices[voice].addr + dst_voices[voice].first / 8;
src_step = src_voices[voice].step / 8;
dst_step = dst_voices[voice].step / 8;
src = (char *)src_voices[voice].area.addr + src_voices[voice].area.first / 8;
dst = (char *)dst_voices[voice].area.addr + dst_voices[voice].area.first / 8;
src_step = src_voices[voice].area.step / 8;
dst_step = dst_voices[voice].area.step / 8;
src_samples1 = src_samples;
dst_samples1 = dst_samples;
if (pos & ~MASK) {
@ -190,15 +190,15 @@ static void resample_shrink(snd_pcm_plugin_t *plugin,
S2 = rvoices->last_S2;
if (!src_voices[voice].enabled) {
if (dst_voices[voice].wanted)
snd_pcm_plugin_silence_voice(plugin, &dst_voices[voice], dst_samples);
snd_pcm_area_silence(&dst_voices[voice].area, 0, dst_samples, plugin->dst_format.format);
dst_voices[voice].enabled = 0;
continue;
}
dst_voices[voice].enabled = 1;
src = (char *)src_voices[voice].addr + src_voices[voice].first / 8;
dst = (char *)dst_voices[voice].addr + dst_voices[voice].first / 8;
src_step = src_voices[voice].step / 8;
dst_step = dst_voices[voice].step / 8;
src = (char *)src_voices[voice].area.addr + src_voices[voice].area.first / 8;
dst = (char *)dst_voices[voice].area.addr + dst_voices[voice].area.first / 8;
src_step = src_voices[voice].area.step / 8;
dst_step = dst_voices[voice].area.step / 8;
src_samples1 = src_samples;
dst_samples1 = dst_samples;
while (dst_samples1 > 0) {
@ -313,11 +313,11 @@ static ssize_t rate_transfer(snd_pcm_plugin_t *plugin,
if (samples == 0)
return 0;
for (voice = 0; voice < plugin->src_format.voices; voice++) {
if (src_voices[voice].first % 8 != 0 ||
src_voices[voice].step % 8 != 0)
if (src_voices[voice].area.first % 8 != 0 ||
src_voices[voice].area.step % 8 != 0)
return -EINVAL;
if (dst_voices[voice].first % 8 != 0 ||
dst_voices[voice].step % 8 != 0)
if (dst_voices[voice].area.first % 8 != 0 ||
dst_voices[voice].area.step % 8 != 0)
return -EINVAL;
}

View file

@ -81,7 +81,7 @@ static void route_to_voice_zero(snd_pcm_plugin_t *plugin,
ttable_dst_t* ttable UNUSED, size_t samples)
{
if (dst_voice->wanted)
snd_pcm_plugin_silence_voice(plugin, dst_voice, samples);
snd_pcm_area_silence(&dst_voice->area, 0, samples, plugin->dst_format.format);
dst_voice->enabled = 0;
}
@ -101,7 +101,7 @@ static void route_to_voice_one(snd_pcm_plugin_t *plugin,
int src_step, dst_step;
for (srcidx = 0; srcidx < ttable->nsrcs; ++srcidx) {
src_voice = &src_voices[ttable->srcs[srcidx].voice];
if (src_voice->addr != NULL)
if (src_voice->area.addr != NULL)
break;
}
if (srcidx == ttable->nsrcs) {
@ -111,10 +111,10 @@ static void route_to_voice_one(snd_pcm_plugin_t *plugin,
dst_voice->enabled = 1;
conv = conv_labels[data->conv];
src = src_voice->addr + src_voice->first / 8;
src_step = src_voice->step / 8;
dst = dst_voice->addr + dst_voice->first / 8;
dst_step = dst_voice->step / 8;
src = src_voice->area.addr + src_voice->area.first / 8;
src_step = src_voice->area.step / 8;
dst = dst_voice->area.addr + dst_voice->area.first / 8;
dst_step = dst_voice->area.step / 8;
while (samples-- > 0) {
goto *conv;
#define CONV_END after
@ -190,8 +190,8 @@ static void route_to_voice(snd_pcm_plugin_t *plugin,
const snd_pcm_plugin_voice_t *src_voice = &src_voices[ttable->srcs[srcidx].voice];
if (!src_voice->enabled)
continue;
srcs[srcidx1] = src_voice->addr + src_voices->first / 8;
src_steps[srcidx1] = src_voice->step / 8;
srcs[srcidx1] = src_voice->area.addr + src_voices->area.first / 8;
src_steps[srcidx1] = src_voice->area.step / 8;
src_tt[srcidx1] = ttable->srcs[srcidx];
srcidx1++;
}
@ -210,8 +210,8 @@ static void route_to_voice(snd_pcm_plugin_t *plugin,
add = add_labels[data->sum_type * 2 + ttable->att];
norm = norm_labels[data->sum_type * 8 + ttable->att * 4 + 4 - data->src_sample_size];
put32 = put32_labels[data->put];
dst = dst_voice->addr + dst_voice->first / 8;
dst_step = dst_voice->step / 8;
dst = dst_voice->area.addr + dst_voice->area.first / 8;
dst_step = dst_voice->area.step / 8;
while (samples-- > 0) {
ttable_src_t *ttp = src_tt;
@ -513,15 +513,15 @@ static ssize_t route_transfer(snd_pcm_plugin_t *plugin,
src_nvoices = plugin->src_format.voices;
for (src_voice = 0; src_voice < src_nvoices; ++src_voice) {
if (src_voices[src_voice].first % 8 != 0 ||
src_voices[src_voice].step % 8 != 0)
if (src_voices[src_voice].area.first % 8 != 0 ||
src_voices[src_voice].area.step % 8 != 0)
return -EINVAL;
}
dst_nvoices = plugin->dst_format.voices;
for (dst_voice = 0; dst_voice < dst_nvoices; ++dst_voice) {
if (dst_voices[dst_voice].first % 8 != 0 ||
dst_voices[dst_voice].step % 8 != 0)
if (dst_voices[dst_voice].area.first % 8 != 0 ||
dst_voices[dst_voice].area.step % 8 != 0)
return -EINVAL;
}

View file

@ -58,12 +58,12 @@ static ssize_t stream_transfer(snd_pcm_plugin_t *plugin,
return result;
count = plugin->src_format.voices;
if (plugin->src_format.interleave) {
result = snd_pcm_write(data->slave, src_voices->addr, result);
result = snd_pcm_write(data->slave, src_voices->area.addr, result);
} else {
result /= count;
for (voice = 0; voice < count; voice++) {
if (src_voices[voice].enabled)
vec[voice].iov_base = src_voices[voice].addr;
vec[voice].iov_base = src_voices[voice].area.addr;
else
vec[voice].iov_base = 0;
vec[voice].iov_len = result;
@ -80,7 +80,7 @@ static ssize_t stream_transfer(snd_pcm_plugin_t *plugin,
return result;
count = plugin->dst_format.voices;
if (plugin->dst_format.interleave) {
result = snd_pcm_read(data->slave, dst_voices->addr, result);
result = snd_pcm_read(data->slave, dst_voices->area.addr, result);
for (voice = 0; voice < count; voice++)
dst_voices[voice].enabled = src_voices[voice].enabled;
} else {
@ -88,7 +88,7 @@ static ssize_t stream_transfer(snd_pcm_plugin_t *plugin,
for (voice = 0; voice < count; voice++) {
dst_voices[voice].enabled = src_voices[voice].enabled;
if (dst_voices[voice].enabled)
vec[voice].iov_base = dst_voices[voice].addr;
vec[voice].iov_base = dst_voices[voice].area.addr;
else
vec[voice].iov_base = 0;
vec[voice].iov_len = result;