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)
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);
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);
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;
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
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;
}
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;
}
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)
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;
#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
struct snd_pcm_chan *chan = &pcm->chan[channel];
chan->mmap_control->frag_io = 0;
chan->mmap_control->frag_data = 0;
- chan->mmap_control->pos_io = 0;
- chan->mmap_control->pos_data = 0;
+ chan->mmap_control->byte_io = 0;
+ chan->mmap_control->byte_data = 0;
}
void snd_pcm_mmap_status_change(snd_pcm_t *pcm, int channel, int newstatus)
}
}
-static ssize_t snd_pcm_mmap_playback_frags_used(snd_pcm_t *pcm)
+static inline ssize_t snd_pcm_mmap_playback_frags_used(struct snd_pcm_chan *chan)
{
- struct snd_pcm_chan *chan;
ssize_t frags_used;
- chan = &pcm->chan[SND_PCM_CHANNEL_PLAYBACK];
frags_used = chan->mmap_control->frag_data - chan->mmap_control->frag_io;
if (frags_used < (ssize_t)(chan->setup.frags - chan->setup.frag_boundary))
frags_used += chan->setup.frag_boundary;
return frags_used;
}
-static size_t snd_pcm_mmap_capture_frags_used(snd_pcm_t *pcm)
+static inline ssize_t snd_pcm_mmap_playback_bytes_used(struct snd_pcm_chan *chan)
+{
+ ssize_t bytes_used;
+ bytes_used = chan->mmap_control->byte_data - chan->mmap_control->byte_io;
+ if (bytes_used < (ssize_t)(chan->setup.buffer_size - chan->setup.byte_boundary))
+ bytes_used += chan->setup.byte_boundary;
+ return bytes_used;
+}
+
+static ssize_t snd_pcm_mmap_playback_samples_used(snd_pcm_t *pcm)
{
struct snd_pcm_chan *chan;
+ chan = &pcm->chan[SND_PCM_CHANNEL_PLAYBACK];
+ if (chan->setup.mode == SND_PCM_MODE_BLOCK) {
+ ssize_t frags = snd_pcm_mmap_playback_frags_used(chan);
+ return frags * chan->samples_per_frag;
+ } else {
+ ssize_t bytes = snd_pcm_mmap_playback_bytes_used(chan);
+ return bytes * 8 / chan->bits_per_sample;
+ }
+}
+
+static inline size_t snd_pcm_mmap_capture_frags_used(struct snd_pcm_chan *chan)
+{
ssize_t frags_used;
- chan = &pcm->chan[SND_PCM_CHANNEL_CAPTURE];
frags_used = chan->mmap_control->frag_io - chan->mmap_control->frag_data;
if (frags_used < 0)
frags_used += chan->setup.frag_boundary;
return frags_used;
}
-static size_t snd_pcm_mmap_playback_frags_free(snd_pcm_t *pcm)
+static inline size_t snd_pcm_mmap_capture_bytes_used(struct snd_pcm_chan *chan)
{
- return pcm->chan[SND_PCM_CHANNEL_PLAYBACK].setup.frags - snd_pcm_mmap_playback_frags_used(pcm);
+ ssize_t bytes_used;
+ bytes_used = chan->mmap_control->byte_io - chan->mmap_control->byte_data;
+ if (bytes_used < 0)
+ bytes_used += chan->setup.byte_boundary;
+ return bytes_used;
}
-static ssize_t snd_pcm_mmap_capture_frags_free(snd_pcm_t *pcm)
+static size_t snd_pcm_mmap_capture_samples_used(snd_pcm_t *pcm)
{
- return pcm->chan[SND_PCM_CHANNEL_CAPTURE].setup.frags - snd_pcm_mmap_capture_frags_used(pcm);
+ struct snd_pcm_chan *chan;
+ chan = &pcm->chan[SND_PCM_CHANNEL_CAPTURE];
+ if (chan->setup.mode == SND_PCM_MODE_BLOCK) {
+ size_t frags = snd_pcm_mmap_capture_frags_used(chan);
+ return frags * chan->samples_per_frag;
+ } else {
+ size_t bytes = snd_pcm_mmap_capture_bytes_used(chan);
+ return bytes * 8 / chan->bits_per_sample;
+ }
}
-int snd_pcm_mmap_frags_used(snd_pcm_t *pcm, int channel, ssize_t *frags)
+int snd_pcm_mmap_samples_used(snd_pcm_t *pcm, int channel, ssize_t *samples)
{
struct snd_pcm_chan *chan;
if (!pcm)
if (!chan->open || !chan->mmap_control)
return -EBADFD;
if (channel == SND_PCM_CHANNEL_PLAYBACK)
- *frags = snd_pcm_mmap_playback_frags_used(pcm);
+ *samples = snd_pcm_mmap_playback_samples_used(pcm);
else
- *frags = snd_pcm_mmap_capture_frags_used(pcm);
+ *samples = snd_pcm_mmap_capture_samples_used(pcm);
return 0;
}
-int snd_pcm_mmap_frags_free(snd_pcm_t *pcm, int channel, ssize_t *frags)
+static inline size_t snd_pcm_mmap_playback_frags_free(struct snd_pcm_chan *chan)
{
- struct snd_pcm_chan *chan;
- if (!pcm)
- return -EFAULT;
- if (channel < 0 || channel > 1)
- return -EINVAL;
- chan = &pcm->chan[channel];
- if (!chan->open || !chan->mmap_control)
- return -EBADFD;
- if (channel == SND_PCM_CHANNEL_PLAYBACK)
- *frags = snd_pcm_mmap_playback_frags_free(pcm);
- else
- *frags = snd_pcm_mmap_capture_frags_free(pcm);
- return 0;
+ return chan->setup.frags - snd_pcm_mmap_playback_frags_used(chan);
}
-static ssize_t snd_pcm_mmap_playback_bytes_used(snd_pcm_t *pcm)
+static inline size_t snd_pcm_mmap_playback_bytes_free(struct snd_pcm_chan *chan)
{
- struct snd_pcm_chan *chan;
- ssize_t bytes_used;
- chan = &pcm->chan[SND_PCM_CHANNEL_PLAYBACK];
- bytes_used = chan->mmap_control->pos_data - chan->mmap_control->pos_io;
- if (bytes_used < (ssize_t)(chan->setup.buffer_size - chan->setup.pos_boundary))
- bytes_used += chan->setup.pos_boundary;
- return bytes_used;
+ return chan->setup.buffer_size - snd_pcm_mmap_playback_bytes_used(chan);
}
-static size_t snd_pcm_mmap_capture_bytes_used(snd_pcm_t *pcm)
+static size_t snd_pcm_mmap_playback_samples_free(snd_pcm_t *pcm)
{
struct snd_pcm_chan *chan;
- ssize_t bytes_used;
- chan = &pcm->chan[SND_PCM_CHANNEL_CAPTURE];
- bytes_used = chan->mmap_control->pos_io - chan->mmap_control->pos_data;
- if (bytes_used < 0)
- bytes_used += chan->setup.pos_boundary;
- return bytes_used;
+ chan = &pcm->chan[SND_PCM_CHANNEL_PLAYBACK];
+ if (chan->setup.mode == SND_PCM_MODE_BLOCK) {
+ size_t frags = snd_pcm_mmap_playback_frags_free(chan);
+ return frags * chan->samples_per_frag;
+ } else {
+ size_t bytes = snd_pcm_mmap_playback_bytes_free(chan);
+ return bytes * 8 / chan->bits_per_sample;
+ }
}
-int snd_pcm_mmap_bytes_used(snd_pcm_t *pcm, int channel, ssize_t *frags)
+static inline ssize_t snd_pcm_mmap_capture_frags_free(struct snd_pcm_chan *chan)
{
- struct snd_pcm_chan *chan;
- if (!pcm)
- return -EFAULT;
- if (channel < 0 || channel > 1)
- return -EINVAL;
- chan = &pcm->chan[channel];
- if (!chan->open || !chan->mmap_control)
- return -EBADFD;
- if (channel == SND_PCM_CHANNEL_PLAYBACK)
- *frags = snd_pcm_mmap_playback_bytes_used(pcm);
- else
- *frags = snd_pcm_mmap_capture_bytes_used(pcm);
- return 0;
+ return chan->setup.frags - snd_pcm_mmap_capture_frags_used(chan);
}
-static size_t snd_pcm_mmap_playback_bytes_free(snd_pcm_t *pcm)
+
+static inline ssize_t snd_pcm_mmap_capture_bytes_free(struct snd_pcm_chan *chan)
{
- return pcm->chan[SND_PCM_CHANNEL_PLAYBACK].setup.buffer_size - snd_pcm_mmap_playback_bytes_used(pcm);
+ return chan->setup.buffer_size - snd_pcm_mmap_capture_bytes_used(chan);
}
-static ssize_t snd_pcm_mmap_capture_bytes_free(snd_pcm_t *pcm)
+static ssize_t snd_pcm_mmap_capture_samples_free(snd_pcm_t *pcm)
{
- return pcm->chan[SND_PCM_CHANNEL_CAPTURE].setup.buffer_size - snd_pcm_mmap_capture_bytes_used(pcm);
+ struct snd_pcm_chan *chan;
+ chan = &pcm->chan[SND_PCM_CHANNEL_CAPTURE];
+ if (chan->setup.mode == SND_PCM_MODE_BLOCK) {
+ ssize_t frags = snd_pcm_mmap_capture_frags_free(chan);
+ return frags * chan->samples_per_frag;
+ } else {
+ ssize_t bytes = snd_pcm_mmap_capture_bytes_free(chan);
+ return bytes * 8 / chan->bits_per_sample;
+ }
}
-int snd_pcm_mmap_bytes_free(snd_pcm_t *pcm, int channel, ssize_t *frags)
+int snd_pcm_mmap_samples_free(snd_pcm_t *pcm, int channel, ssize_t *samples)
{
struct snd_pcm_chan *chan;
if (!pcm)
if (!chan->open || !chan->mmap_control)
return -EBADFD;
if (channel == SND_PCM_CHANNEL_PLAYBACK)
- *frags = snd_pcm_mmap_playback_bytes_free(pcm);
+ *samples = snd_pcm_mmap_playback_samples_free(pcm);
else
- *frags = snd_pcm_mmap_capture_bytes_free(pcm);
+ *samples = snd_pcm_mmap_capture_samples_free(pcm);
return 0;
}
if (chan->mmap_control->status == SND_PCM_STATUS_XRUN)
return -EPIPE;
if (chan->setup.mode == SND_PCM_MODE_BLOCK) {
- return (chan->setup.frags - snd_pcm_mmap_playback_frags_used(pcm)) >= chan->setup.buf.block.frags_min;
+ return (chan->setup.frags - snd_pcm_mmap_playback_frags_used(chan)) >= chan->setup.buf.block.frags_min;
} else {
- return (chan->setup.buffer_size - snd_pcm_mmap_playback_bytes_used(pcm)) >= chan->setup.buf.stream.bytes_min;
+ return (chan->setup.buffer_size - snd_pcm_mmap_playback_bytes_used(chan)) >= chan->setup.buf.stream.bytes_min;
}
}
return -EPIPE;
}
if (chan->setup.mode == SND_PCM_MODE_BLOCK) {
- if (snd_pcm_mmap_capture_frags_used(pcm) >= chan->setup.buf.block.frags_min)
+ if (snd_pcm_mmap_capture_frags_used(chan) >= chan->setup.buf.block.frags_min)
return 1;
} else {
- if (snd_pcm_mmap_capture_bytes_used(pcm) >= chan->setup.buf.stream.bytes_min)
+ if (snd_pcm_mmap_capture_bytes_used(chan) >= chan->setup.buf.stream.bytes_min)
return 1;
}
return ret;
}
}
-/* Bytes transferrable */
-static size_t snd_pcm_mmap_bytes_playback(snd_pcm_t *pcm, size_t size)
+static size_t snd_pcm_mmap_playback_frags_xfer(snd_pcm_t *pcm, size_t frags)
{
struct snd_pcm_chan *chan = &pcm->chan[SND_PCM_CHANNEL_PLAYBACK];
snd_pcm_mmap_control_t *ctrl = chan->mmap_control;
- size_t bytes_cont, bytes_free;
- unsigned int pos_data = ctrl->pos_data;
- unsigned int pos_io = ctrl->pos_io;
- int bytes_used = pos_data - pos_io;
- if (bytes_used < -(int)(chan->setup.buf.stream.bytes_xrun_max + chan->setup.frag_size))
- bytes_used += chan->setup.pos_boundary;
- bytes_cont = chan->setup.buffer_size - (pos_data % chan->setup.buffer_size);
- if (bytes_cont < size)
- size = bytes_cont;
- bytes_free = chan->setup.buffer_size - bytes_used;
- if (bytes_free < size)
- size = (bytes_free / chan->setup.buf.stream.bytes_align) * chan->setup.buf.stream.bytes_align;
- return size;
+ size_t frags_cont;
+ size_t frag_data = ctrl->frag_data;
+ size_t frags_free = snd_pcm_mmap_playback_frags_free(chan);
+ if (frags_free < frags)
+ frags = frags_free;
+ frags_cont = chan->setup.frags - (frag_data % chan->setup.frags);
+ if (frags_cont < frags)
+ frags = frags_cont;
+ return frags;
}
-/* Bytes transferrable */
-static size_t snd_pcm_mmap_bytes_capture(snd_pcm_t *pcm, size_t size)
+static size_t snd_pcm_mmap_capture_frags_xfer(snd_pcm_t *pcm, size_t frags)
{
struct snd_pcm_chan *chan = &pcm->chan[SND_PCM_CHANNEL_CAPTURE];
snd_pcm_mmap_control_t *ctrl = chan->mmap_control;
+ size_t frags_cont;
+ size_t frag_data = ctrl->frag_data;
+ size_t frags_used = snd_pcm_mmap_capture_frags_used(chan);
+ if (frags_used < frags)
+ frags = frags_used;
+ frags_cont = chan->setup.frags - (frag_data % chan->setup.frags);
+ if (frags_cont < frags)
+ frags = frags_cont;
+ return frags;
+}
+
+static size_t snd_pcm_mmap_playback_bytes_xfer(snd_pcm_t *pcm, size_t bytes)
+{
+ struct snd_pcm_chan *chan = &pcm->chan[SND_PCM_CHANNEL_PLAYBACK];
+ snd_pcm_mmap_control_t *ctrl = chan->mmap_control;
size_t bytes_cont;
- unsigned int pos_data = ctrl->pos_data;
- unsigned int pos_io = ctrl->pos_io;
- int bytes_used = pos_io - pos_data;
- if (bytes_used < 0)
- bytes_used += chan->setup.pos_boundary;
- bytes_cont = chan->setup.buffer_size - (pos_data % chan->setup.buffer_size);
- if (bytes_cont < size)
- size = bytes_cont;
- if ((size_t) bytes_used < size)
- size = (bytes_used / chan->setup.buf.stream.bytes_align) * chan->setup.buf.stream.bytes_align;
- return size;
+ size_t byte_data = ctrl->byte_data;
+ size_t bytes_free = snd_pcm_mmap_playback_bytes_free(chan);
+ if (bytes_free < bytes)
+ bytes = bytes_free;
+ bytes_cont = chan->setup.buffer_size - (byte_data % chan->setup.buffer_size);
+ if (bytes_cont < bytes)
+ bytes = bytes_cont;
+ bytes -= bytes % chan->setup.buf.stream.bytes_align;
+ return bytes;
+}
+
+static size_t snd_pcm_mmap_capture_bytes_xfer(snd_pcm_t *pcm, size_t bytes)
+{
+ struct snd_pcm_chan *chan = &pcm->chan[SND_PCM_CHANNEL_CAPTURE];
+ snd_pcm_mmap_control_t *ctrl = chan->mmap_control;
+ size_t bytes_cont;
+ size_t byte_data = ctrl->byte_data;
+ size_t bytes_used = snd_pcm_mmap_capture_bytes_used(chan);
+ if (bytes_used < bytes)
+ bytes = bytes_used;
+ bytes_cont = chan->setup.buffer_size - (byte_data % chan->setup.buffer_size);
+ if (bytes_cont < bytes)
+ bytes = bytes_cont;
+ bytes -= bytes % chan->setup.buf.stream.bytes_align;
+ return bytes;
}
-typedef int (*transfer_f)(snd_pcm_t *pcm, size_t hwoff, void *data, size_t off, size_t size);
+static ssize_t snd_pcm_mmap_playback_samples_xfer(snd_pcm_t *pcm, size_t samples)
+{
+ struct snd_pcm_chan *chan;
+ chan = &pcm->chan[SND_PCM_CHANNEL_PLAYBACK];
+ if (chan->setup.mode == SND_PCM_MODE_BLOCK) {
+ size_t frags = samples / chan->samples_per_frag;
+ frags = snd_pcm_mmap_playback_frags_xfer(pcm, frags);
+ return frags * chan->samples_per_frag;
+ } else {
+ size_t bytes = samples * chan->bits_per_sample / 8;
+ bytes = snd_pcm_mmap_playback_bytes_xfer(pcm, bytes);
+ return bytes * 8 / chan->bits_per_sample;
+ }
+}
+
+static ssize_t snd_pcm_mmap_capture_samples_xfer(snd_pcm_t *pcm, size_t samples)
+{
+ struct snd_pcm_chan *chan;
+ chan = &pcm->chan[SND_PCM_CHANNEL_CAPTURE];
+ if (chan->setup.mode == SND_PCM_MODE_BLOCK) {
+ size_t frags = samples / chan->samples_per_frag;
+ frags = snd_pcm_mmap_capture_frags_xfer(pcm, frags);
+ return frags * chan->samples_per_frag;
+ } else {
+ size_t bytes = samples * chan->bits_per_sample / 8;
+ bytes = snd_pcm_mmap_capture_bytes_xfer(pcm, bytes);
+ return bytes * 8 / chan->bits_per_sample;
+ }
+}
+
+ssize_t snd_pcm_mmap_samples_xfer(snd_pcm_t *pcm, int channel, size_t samples)
+{
+ struct snd_pcm_chan *chan;
+ if (!pcm)
+ return -EFAULT;
+ if (channel < 0 || channel > 1)
+ return -EINVAL;
+ chan = &pcm->chan[channel];
+ if (!chan->open || !chan->mmap_control)
+ return -EBADFD;
+ if (channel == SND_PCM_CHANNEL_PLAYBACK)
+ return snd_pcm_mmap_playback_samples_xfer(pcm, samples);
+ else
+ return snd_pcm_mmap_capture_samples_xfer(pcm, samples);
+}
+
+ssize_t snd_pcm_mmap_samples_offset(snd_pcm_t *pcm, int channel)
+{
+ struct snd_pcm_chan *chan;
+ snd_pcm_mmap_control_t *ctrl;
+ if (!pcm)
+ return -EFAULT;
+ if (channel < 0 || channel > 1)
+ return -EINVAL;
+ chan = &pcm->chan[channel];
+ if (!chan->open)
+ return -EBADFD;
+ ctrl = chan->mmap_control;
+ if (!ctrl)
+ return -EBADFD;
+ if (chan->setup.mode == SND_PCM_MODE_BLOCK)
+ return (ctrl->frag_data % chan->setup.frags) * chan->samples_per_frag;
+ else
+ return (ctrl->byte_data % chan->setup.buffer_size) * 8 / chan->bits_per_sample;
+}
+int snd_pcm_mmap_commit_samples(snd_pcm_t *pcm, int channel, int samples)
+{
+ struct snd_pcm_chan *chan;
+ snd_pcm_mmap_control_t *ctrl;
+ if (!pcm)
+ return -EFAULT;
+ if (channel < 0 || channel > 1)
+ return -EINVAL;
+ chan = &pcm->chan[channel];
+ if (!chan->open)
+ return -EBADFD;
+ ctrl = chan->mmap_control;
+ if (!ctrl)
+ return -EBADFD;
+ if (chan->setup.mode == SND_PCM_MODE_BLOCK) {
+ size_t frag_data, frags;
+ if (samples % chan->samples_per_frag)
+ return -EINVAL;
+ frags = samples / chan->samples_per_frag;
+ frag_data = ctrl->frag_data + frags;
+ if (frag_data == chan->setup.frag_boundary) {
+ ctrl->frag_data = 0;
+ ctrl->byte_data = 0;
+ } else {
+ ctrl->frag_data = frag_data;
+ ctrl->byte_data = frag_data * chan->setup.frag_size;
+ }
+ } else {
+ size_t byte_data;
+ size_t bytes = samples * chan->bits_per_sample;
+ if (bytes % 8)
+ return -EINVAL;
+ bytes /= 8;
+ byte_data = ctrl->byte_data + bytes;
+ if (byte_data == chan->setup.byte_boundary) {
+ ctrl->byte_data = 0;
+ ctrl->frag_data = 0;
+ } else {
+ ctrl->byte_data = byte_data;
+ ctrl->frag_data = byte_data / chan->setup.frag_size;
+ }
+ }
+ return 0;
+}
-static ssize_t snd_pcm_mmap_write1(snd_pcm_t *pcm, const void *data, size_t count, transfer_f transfer)
+ssize_t snd_pcm_mmap_write_areas(snd_pcm_t *pcm, snd_pcm_voice_area_t *voices, size_t samples)
{
struct snd_pcm_chan *chan;
snd_pcm_mmap_control_t *ctrl;
- size_t frag_size;
size_t offset = 0;
size_t result = 0;
int err;
ctrl = chan->mmap_control;
if (ctrl->status < SND_PCM_STATUS_PREPARED)
return -EBADFD;
- frag_size = chan->setup.frag_size;
if (chan->setup.mode == SND_PCM_MODE_BLOCK) {
- if (count % frag_size != 0)
+ if (samples % chan->samples_per_frag != 0)
return -EINVAL;
} else {
- int tmp = snd_pcm_format_size(chan->setup.format.format, chan->setup.format.voices);
- if (tmp > 0) {
- int r = count % tmp;
- if (r > 0) {
- count -= r;
- if (count == 0)
- return -EINVAL;
- }
- }
+ if (ctrl->status == SND_PCM_STATUS_RUNNING &&
+ chan->mode & SND_PCM_NONBLOCK)
+ snd_pcm_channel_update(pcm, SND_PCM_CHANNEL_PLAYBACK);
}
- if (chan->mode & SND_PCM_NONBLOCK)
- snd_pcm_channel_update(pcm, SND_PCM_CHANNEL_PLAYBACK);
- while (count > 0) {
- size_t bytes;
+ while (samples > 0) {
+ ssize_t mmap_offset;
+ size_t samples1;
int ready = snd_pcm_mmap_playback_ready(pcm);
if (ready < 0)
return ready;
return result > 0 ? result : -EPIPE;
assert(snd_pcm_mmap_playback_ready(pcm));
}
- if (chan->setup.mode == SND_PCM_MODE_BLOCK) {
- size_t frag_data, frag;
- frag_data = ctrl->frag_data;
- frag = frag_data % chan->setup.frags;
- err = transfer(pcm, frag_size * frag, (void *) data, offset, frag_size);
- if (err < 0)
- return result > 0 ? result : err;
- if (ctrl->status == SND_PCM_STATUS_XRUN)
- return result > 0 ? result : -EPIPE;
- frag_data++;
- if (frag_data == chan->setup.frag_boundary) {
- ctrl->frag_data = 0;
- ctrl->pos_data = 0;
- } else {
- ctrl->frag_data = frag_data;
- ctrl->pos_data += frag_size;
- }
- bytes = frag_size;
- } else {
- size_t pos_data;
- bytes = snd_pcm_mmap_bytes_playback(pcm, count);
- pos_data = ctrl->pos_data;
- err = transfer(pcm, pos_data % chan->setup.buffer_size, (void *) data, offset, bytes);
- if (err < 0)
+ samples1 = snd_pcm_mmap_playback_samples_xfer(pcm, samples);
+ assert(samples1 > 0);
+ mmap_offset = snd_pcm_mmap_samples_offset(pcm, SND_PCM_CHANNEL_PLAYBACK);
+ snd_pcm_areas_copy(voices, offset, chan->voices, mmap_offset, chan->setup.format.voices, samples1, chan->setup.format.format);
+ if (ctrl->status == SND_PCM_STATUS_XRUN)
+ return result > 0 ? result : -EPIPE;
+ snd_pcm_mmap_commit_samples(pcm, SND_PCM_CHANNEL_PLAYBACK, samples1);
+ samples -= samples1;
+ offset += samples1;
+ result += samples1;
+ if (ctrl->status == SND_PCM_STATUS_PREPARED &&
+ (chan->setup.start_mode == SND_PCM_START_DATA ||
+ (chan->setup.start_mode == SND_PCM_START_FULL &&
+ !snd_pcm_mmap_playback_ready(pcm)))) {
+ err = snd_pcm_channel_go(pcm, SND_PCM_CHANNEL_PLAYBACK);
+ if (err < 0)
return result > 0 ? result : err;
- if (ctrl->status == SND_PCM_STATUS_XRUN)
- return result > 0 ? result : -EPIPE;
- pos_data += bytes;
- if (pos_data == chan->setup.pos_boundary) {
- ctrl->pos_data = 0;
- ctrl->frag_data = 0;
- } else {
- ctrl->pos_data = pos_data;
- ctrl->frag_data = pos_data / chan->setup.frags;
- }
}
- offset += bytes;
- count -= bytes;
- result += bytes;
- }
-
- if (ctrl->status == SND_PCM_STATUS_PREPARED &&
- (chan->setup.start_mode == SND_PCM_START_DATA ||
- (chan->setup.start_mode == SND_PCM_START_FULL &&
- !snd_pcm_mmap_playback_ready(pcm)))) {
- err = snd_pcm_channel_go(pcm, SND_PCM_CHANNEL_PLAYBACK);
- if (err < 0)
- return result > 0 ? result : err;
}
return result;
}
-static int transfer_write(snd_pcm_t *pcm, size_t hwoff, void* data, size_t off, size_t size)
+ssize_t snd_pcm_mmap_write_samples(snd_pcm_t *pcm, const void *buffer, size_t samples)
{
- struct snd_pcm_chan *chan = &pcm->chan[SND_PCM_CHANNEL_PLAYBACK];
- const char *buf = data;
- unsigned int v, voices;
-#define COPY_LABELS
-#include "plugin/plugin_ops.h"
-#undef COPY_LABELS
- void *copy;
- snd_pcm_voice_setup_t *vsetup;
- int idx;
- size_t vsize, ssize;
- idx = copy_index(chan->setup.format.format);
- if (idx < 0)
- return idx;
- copy = copy_labels[idx];
- voices = chan->setup.format.voices;
- vsetup = chan->voices_setup;
- vsize = snd_pcm_format_size(chan->setup.format.format, 1);
- ssize = vsize * chan->setup.format.voices;
- hwoff /= ssize;
- size /= ssize;
- for (v = 0; v < voices; ++v, ++vsetup) {
- const char *src;
- char *dst;
- size_t dst_step;
- size_t samples = size;
- if (vsetup->first % 8 != 0 ||
- vsetup->step % 8 != 0)
- return -EINVAL;
- src = buf + off + v * vsize;
- dst_step = vsetup->step / 8;
- dst = chan->mmap_data + vsetup->addr + (vsetup->first + vsetup->step * hwoff) / 8;
- while (samples-- > 0) {
- goto *copy;
-#define COPY_END after
-#include "plugin/plugin_ops.h"
-#undef COPY_END
- after:
- src += ssize;
- dst += dst_step;
+ struct snd_pcm_chan *chan;
+ unsigned int nvoices;
+ if (!pcm)
+ return -EFAULT;
+ chan = &pcm->chan[SND_PCM_CHANNEL_PLAYBACK];
+ if (!chan->open || !chan->valid_setup)
+ return -EBADFD;
+ if (!chan->mmap_data || !chan->mmap_control)
+ return -EBADFD;
+ if (samples > 0 && !buffer)
+ return -EFAULT;
+ nvoices = chan->setup.format.voices;
+ if (!chan->setup.format.interleave && nvoices > 1)
+ return -EINVAL;
+ {
+ snd_pcm_voice_area_t voices[nvoices];
+ unsigned int voice;
+ for (voice = 0; voice < nvoices; ++voice) {
+ voices[voice].addr = (char*)buffer;
+ voices[voice].first = chan->sample_width * voice;
+ voices[voice].step = chan->bits_per_sample;
}
+ return snd_pcm_mmap_write_areas(pcm, voices, samples);
}
- return 0;
}
-ssize_t snd_pcm_mmap_write(snd_pcm_t *pcm, const void *buffer, size_t count)
+ssize_t snd_pcm_mmap_write(snd_pcm_t *pcm, const void *buffer, size_t bytes)
{
struct snd_pcm_chan *chan;
+ unsigned int nvoices;
+ ssize_t samples;
if (!pcm)
return -EFAULT;
chan = &pcm->chan[SND_PCM_CHANNEL_PLAYBACK];
- if (!chan->open || !chan->valid_setup || !chan->valid_voices_setup)
+ if (!chan->open || !chan->valid_setup)
return -EBADFD;
if (!chan->mmap_data || !chan->mmap_control)
return -EBADFD;
- if (count > 0 && !buffer)
+ if (bytes > 0 && !buffer)
return -EFAULT;
- if (!chan->setup.format.interleave && chan->setup.format.voices > 1)
+ nvoices = chan->setup.format.voices;
+ if (!chan->setup.format.interleave && nvoices > 1)
return -EINVAL;
- return snd_pcm_mmap_write1(pcm, buffer, count, transfer_write);
-}
-
-static int transfer_writev(snd_pcm_t *pcm, size_t hwoff, void* data, size_t off, size_t size)
-{
- struct snd_pcm_chan *chan = &pcm->chan[SND_PCM_CHANNEL_PLAYBACK];
- struct iovec *vec = data;
- unsigned int v, voices;
-#define COPY_LABELS
-#include "plugin/plugin_ops.h"
-#undef COPY_LABELS
- void *copy;
- snd_pcm_voice_setup_t *vsetup;
- int idx;
- size_t ssize;
- idx = copy_index(chan->setup.format.format);
- if (idx < 0)
- return idx;
- copy = copy_labels[idx];
- voices = chan->setup.format.voices;
- vsetup = chan->voices_setup;
- ssize = snd_pcm_format_size(chan->setup.format.format, chan->setup.format.voices);
- hwoff /= ssize;
- size /= ssize;
- off /= voices;
- for (v = 0; v < voices; ++v, ++vsetup, ++vec) {
- const char *src;
- char *dst;
- size_t dst_step;
- size_t samples = size;
- if (vsetup->first % 8 != 0 ||
- vsetup->step % 8 != 0)
- return -EINVAL;
- src = vec->iov_base + off;
- dst_step = vsetup->step / 8;
- dst = chan->mmap_data + vsetup->addr + (vsetup->first + vsetup->step * hwoff) / 8;
- while (samples-- > 0) {
- goto *copy;
-#define COPY_END after
-#include "plugin/plugin_ops.h"
-#undef COPY_END
- after:
- src += ssize;
- dst += dst_step;
- }
- }
- return 0;
+ samples = bytes * 8 / chan->bits_per_sample;
+ samples = snd_pcm_mmap_write_samples(pcm, buffer, samples);
+ if (samples <= 0)
+ return samples;
+ return samples * chan->bits_per_sample / 8;
}
ssize_t snd_pcm_mmap_writev(snd_pcm_t *pcm, const struct iovec *vector, unsigned long vcount)
{
struct snd_pcm_chan *chan;
size_t result = 0;
- unsigned int b;
+ unsigned int nvoices;
if (!pcm)
return -EFAULT;
chan = &pcm->chan[SND_PCM_CHANNEL_PLAYBACK];
- if (!chan->open || !chan->valid_setup || !chan->valid_voices_setup)
+ if (!chan->open || !chan->valid_setup)
return -EBADFD;
if (!chan->mmap_data || !chan->mmap_control)
return -EBADFD;
if (vcount > 0 && !vector)
return -EFAULT;
+ nvoices = chan->setup.format.voices;
if (chan->setup.format.interleave) {
+ unsigned int b;
for (b = 0; b < vcount; b++) {
- int ret;
- ret = snd_pcm_mmap_write1(pcm, vector[b].iov_base, vector[b].iov_len, transfer_write);
- if (ret < 0)
- return result > 0 ? result : ret;
+ ssize_t ret;
+ size_t samples = vector[b].iov_len * 8 / chan->bits_per_sample;
+ ret = snd_pcm_mmap_write_samples(pcm, vector[b].iov_base, samples);
+ if (ret < 0) {
+ if (result <= 0)
+ return ret;
+ break;
+ }
result += ret;
}
} else {
- unsigned int voices = chan->setup.format.voices;
+ snd_pcm_voice_area_t voices[nvoices];
unsigned long bcount;
- if (vcount % voices)
+ unsigned int b;
+ if (vcount % nvoices)
return -EINVAL;
- bcount = vcount / voices;
+ bcount = vcount / nvoices;
for (b = 0; b < bcount; b++) {
unsigned int v;
- int ret;
- size_t count = 0;
- count = vector[0].iov_len;
- for (v = 0; v < voices; ++v) {
- if (vector[v].iov_len != count)
+ ssize_t ret;
+ size_t bytes = 0;
+ size_t samples;
+ bytes = vector[0].iov_len;
+ for (v = 0; v < nvoices; ++v) {
+ if (vector[v].iov_len != bytes)
return -EINVAL;
+ voices[v].addr = vector[v].iov_base;
+ voices[v].first = 0;
+ voices[v].step = chan->sample_width;
+ }
+ samples = bytes * 8 / chan->sample_width;
+ ret = snd_pcm_mmap_write_areas(pcm, voices, samples);
+ if (ret < 0) {
+ if (result <= 0)
+ return ret;
+ break;
}
- ret = snd_pcm_mmap_write1(pcm, vector, count * voices, transfer_writev);
- if (ret < 0)
- return result > 0 ? result : ret;
result += ret;
- if ((size_t)ret != count * voices)
+ if ((size_t)ret != samples)
break;
- vector += voices;
+ vector += nvoices;
}
}
- return result;
+ return result * chan->bits_per_sample / 8;
}
-static ssize_t snd_pcm_mmap_read1(snd_pcm_t *pcm, void *data, size_t count, transfer_f transfer)
+ssize_t snd_pcm_mmap_read_areas(snd_pcm_t *pcm, snd_pcm_voice_area_t *voices, size_t samples)
{
struct snd_pcm_chan *chan;
snd_pcm_mmap_control_t *ctrl;
- size_t frag_size;
size_t offset = 0;
size_t result = 0;
int err;
ctrl = chan->mmap_control;
if (ctrl->status < SND_PCM_STATUS_PREPARED)
return -EBADFD;
- frag_size = chan->setup.frag_size;
if (chan->setup.mode == SND_PCM_MODE_BLOCK) {
- if (count % frag_size != 0)
+ if (samples % chan->samples_per_frag != 0)
return -EINVAL;
} else {
- int tmp = snd_pcm_format_size(chan->setup.format.format, chan->setup.format.voices);
- if (tmp > 0) {
- int r = count % tmp;
- if (r > 0) {
- count -= r;
- if (count == 0)
- return -EINVAL;
- }
- }
+ if (ctrl->status == SND_PCM_STATUS_RUNNING &&
+ chan->mode & SND_PCM_NONBLOCK)
+ snd_pcm_channel_update(pcm, SND_PCM_CHANNEL_CAPTURE);
}
if (ctrl->status == SND_PCM_STATUS_PREPARED &&
chan->setup.start_mode == SND_PCM_START_DATA) {
if (err < 0)
return err;
}
- if (chan->mode & SND_PCM_NONBLOCK)
- snd_pcm_channel_update(pcm, SND_PCM_CHANNEL_CAPTURE);
- while (count > 0) {
- size_t bytes;
+ while (samples > 0) {
+ ssize_t mmap_offset;
+ size_t samples1;
int ready = snd_pcm_mmap_capture_ready(pcm);
if (ready < 0)
return ready;
return result > 0 ? result : -EPIPE;
assert(snd_pcm_mmap_capture_ready(pcm));
}
- if (chan->setup.mode == SND_PCM_MODE_BLOCK) {
- size_t frag_data, frag;
- frag_data = ctrl->frag_data;
- frag = frag_data % chan->setup.frags;
- err = transfer(pcm, frag_size * frag, data, offset, frag_size);
- if (err < 0)
- return result > 0 ? result : err;
- if (ctrl->status == SND_PCM_STATUS_XRUN &&
- chan->setup.xrun_mode == SND_PCM_XRUN_DRAIN)
- return result > 0 ? result : -EPIPE;
- frag_data++;
- if (frag_data == chan->setup.frag_boundary) {
- ctrl->frag_data = 0;
- ctrl->pos_data = 0;
- } else {
- ctrl->frag_data = frag_data;
- ctrl->pos_data += frag_size;
- }
- bytes = frag_size;
- } else {
- size_t pos_data;
- bytes = snd_pcm_mmap_bytes_capture(pcm, count);
- pos_data = ctrl->pos_data;
- err = transfer(pcm, pos_data % chan->setup.buffer_size, data, offset, bytes);
- if (err < 0)
- return result > 0 ? result : err;
- if (ctrl->status == SND_PCM_STATUS_XRUN &&
- chan->setup.xrun_mode == SND_PCM_XRUN_DRAIN)
- return result > 0 ? result : -EPIPE;
- pos_data += bytes;
- if (pos_data == chan->setup.pos_boundary) {
- ctrl->pos_data = 0;
- ctrl->frag_data = 0;
- } else {
- ctrl->pos_data = pos_data;
- ctrl->frag_data = pos_data / chan->setup.frags;
- }
- }
- offset += bytes;
- count -= bytes;
- result += bytes;
+ samples1 = snd_pcm_mmap_capture_samples_xfer(pcm, samples);
+ assert(samples1 > 0);
+ mmap_offset = snd_pcm_mmap_samples_offset(pcm, SND_PCM_CHANNEL_CAPTURE);
+ snd_pcm_areas_copy(chan->voices, mmap_offset, voices, offset, chan->setup.format.voices, samples1, chan->setup.format.format);
+ if (ctrl->status == SND_PCM_STATUS_XRUN &&
+ chan->setup.xrun_mode == SND_PCM_XRUN_DRAIN)
+ return result > 0 ? result : -EPIPE;
+ snd_pcm_mmap_commit_samples(pcm, SND_PCM_CHANNEL_CAPTURE, samples1);
+ samples -= samples1;
+ offset += samples1;
+ result += samples1;
}
-
return result;
}
-static int transfer_read(snd_pcm_t *pcm, size_t hwoff, void* data, size_t off, size_t size)
+ssize_t snd_pcm_mmap_read_samples(snd_pcm_t *pcm, const void *buffer, size_t samples)
{
- struct snd_pcm_chan *chan = &pcm->chan[SND_PCM_CHANNEL_CAPTURE];
- char *buf = data;
- unsigned int v, voices;
-#define COPY_LABELS
-#include "plugin/plugin_ops.h"
-#undef COPY_LABELS
- void *copy;
- snd_pcm_voice_setup_t *vsetup;
- int idx;
- size_t vsize, ssize;
- idx = copy_index(chan->setup.format.format);
- if (idx < 0)
- return idx;
- copy = copy_labels[idx];
- voices = chan->setup.format.voices;
- vsetup = chan->voices_setup;
- vsize = snd_pcm_format_size(chan->setup.format.format, 1);
- ssize = vsize * chan->setup.format.voices;
- hwoff /= ssize;
- size /= ssize;
- for (v = 0; v < voices; ++v, ++vsetup) {
- const char *src;
- size_t src_step;
- char *dst;
- size_t samples = size;
- if (vsetup->first % 8 != 0 ||
- vsetup->step % 8 != 0)
- return -EINVAL;
- src_step = vsetup->step / 8;
- src = chan->mmap_data + vsetup->addr + (vsetup->first + vsetup->step * hwoff) / 8;
- dst = buf + off + v * vsize;
- while (samples-- > 0) {
- goto *copy;
-#define COPY_END after
-#include "plugin/plugin_ops.h"
-#undef COPY_END
- after:
- src += src_step;
- dst += ssize;
+ struct snd_pcm_chan *chan;
+ unsigned int nvoices;
+ if (!pcm)
+ return -EFAULT;
+ chan = &pcm->chan[SND_PCM_CHANNEL_CAPTURE];
+ if (!chan->open || !chan->valid_setup)
+ return -EBADFD;
+ if (!chan->mmap_data || !chan->mmap_control)
+ return -EBADFD;
+ if (samples > 0 && !buffer)
+ return -EFAULT;
+ nvoices = chan->setup.format.voices;
+ if (!chan->setup.format.interleave && nvoices > 1)
+ return -EINVAL;
+ {
+ snd_pcm_voice_area_t voices[nvoices];
+ unsigned int voice;
+ for (voice = 0; voice < nvoices; ++voice) {
+ voices[voice].addr = (char*)buffer;
+ voices[voice].first = chan->sample_width * voice;
+ voices[voice].step = chan->bits_per_sample;
}
+ return snd_pcm_mmap_read_areas(pcm, voices, samples);
}
- return 0;
}
-ssize_t snd_pcm_mmap_read(snd_pcm_t *pcm, void *buffer, size_t count)
+ssize_t snd_pcm_mmap_read(snd_pcm_t *pcm, void *buffer, size_t bytes)
{
struct snd_pcm_chan *chan;
+ unsigned int nvoices;
+ ssize_t samples;
if (!pcm)
return -EFAULT;
chan = &pcm->chan[SND_PCM_CHANNEL_CAPTURE];
- if (!chan->open || !chan->valid_setup || !chan->valid_voices_setup)
+ if (!chan->open || !chan->valid_setup)
return -EBADFD;
if (!chan->mmap_data || !chan->mmap_control)
return -EBADFD;
- if (count > 0 && !buffer)
+ if (bytes > 0 && !buffer)
return -EFAULT;
- if (!chan->setup.format.interleave && chan->setup.format.voices > 1)
+ nvoices = chan->setup.format.voices;
+ if (!chan->setup.format.interleave && nvoices > 1)
return -EINVAL;
- return snd_pcm_mmap_read1(pcm, buffer, count, transfer_read);
-}
-
-static int transfer_readv(snd_pcm_t *pcm, size_t hwoff, void* data, size_t off, size_t size)
-{
- struct snd_pcm_chan *chan = &pcm->chan[SND_PCM_CHANNEL_CAPTURE];
- struct iovec *vec = data;
- unsigned int v, voices;
-#define COPY_LABELS
-#include "plugin/plugin_ops.h"
-#undef COPY_LABELS
- void *copy;
- snd_pcm_voice_setup_t *vsetup;
- int idx;
- size_t ssize;
- idx = copy_index(chan->setup.format.format);
- if (idx < 0)
- return idx;
- copy = copy_labels[idx];
- voices = chan->setup.format.voices;
- vsetup = chan->voices_setup;
- ssize = snd_pcm_format_size(chan->setup.format.format, chan->setup.format.voices);
- hwoff /= ssize;
- size /= ssize;
- off /= voices;
- for (v = 0; v < voices; ++v, ++vsetup, ++vec) {
- const char *src;
- size_t src_step;
- char *dst;
- size_t samples = size;
- if (vsetup->first % 8 != 0 ||
- vsetup->step % 8 != 0)
- return -EINVAL;
- src_step = vsetup->step / 8;
- src = chan->mmap_data + vsetup->addr + (vsetup->first + vsetup->step * hwoff) / 8;
- dst = vec->iov_base + off;
- while (samples-- > 0) {
- goto *copy;
-#define COPY_END after
-#include "plugin/plugin_ops.h"
-#undef COPY_END
- after:
- src += src_step;
- dst += ssize;
- }
- }
- return 0;
+ samples = bytes * 8 / chan->bits_per_sample;
+ samples = snd_pcm_mmap_read_samples(pcm, buffer, samples);
+ if (samples <= 0)
+ return samples;
+ return samples * chan->bits_per_sample / 8;
}
ssize_t snd_pcm_mmap_readv(snd_pcm_t *pcm, const struct iovec *vector, unsigned long vcount)
{
struct snd_pcm_chan *chan;
size_t result = 0;
- unsigned int b;
+ unsigned int nvoices;
if (!pcm)
return -EFAULT;
chan = &pcm->chan[SND_PCM_CHANNEL_CAPTURE];
- if (!chan->open || !chan->valid_setup || !chan->valid_voices_setup)
+ if (!chan->open || !chan->valid_setup)
return -EBADFD;
if (!chan->mmap_data || !chan->mmap_control)
return -EBADFD;
if (vcount > 0 && !vector)
return -EFAULT;
+ nvoices = chan->setup.format.voices;
if (chan->setup.format.interleave) {
+ unsigned int b;
for (b = 0; b < vcount; b++) {
- int ret;
- ret = snd_pcm_mmap_read1(pcm, vector[b].iov_base, vector[b].iov_len, transfer_write);
- if (ret < 0)
- return result > 0 ? result : ret;
+ ssize_t ret;
+ size_t samples = vector[b].iov_len * 8 / chan->bits_per_sample;
+ ret = snd_pcm_mmap_read_samples(pcm, vector[b].iov_base, samples);
+ if (ret < 0) {
+ if (result <= 0)
+ return ret;
+ break;
+ }
result += ret;
}
} else {
- unsigned int voices = chan->setup.format.voices;
+ snd_pcm_voice_area_t voices[nvoices];
unsigned long bcount;
- if (vcount % voices)
+ unsigned int b;
+ if (vcount % nvoices)
return -EINVAL;
- bcount = vcount / voices;
+ bcount = vcount / nvoices;
for (b = 0; b < bcount; b++) {
unsigned int v;
- int ret;
- size_t count = 0;
- count = vector[0].iov_len;
- for (v = 0; v < voices; ++v) {
- if (vector[v].iov_len != count)
+ ssize_t ret;
+ size_t bytes = 0;
+ size_t samples;
+ bytes = vector[0].iov_len;
+ for (v = 0; v < nvoices; ++v) {
+ if (vector[v].iov_len != bytes)
return -EINVAL;
+ voices[v].addr = vector[v].iov_base;
+ voices[v].first = 0;
+ voices[v].step = chan->sample_width;
+ }
+ samples = bytes * 8 / chan->sample_width;
+ ret = snd_pcm_mmap_read_areas(pcm, voices, samples);
+ if (ret < 0) {
+ if (result <= 0)
+ return ret;
+ break;
}
- ret = snd_pcm_mmap_read1(pcm, (void *) vector, count * voices, transfer_readv);
- if (ret < 0)
- return result > 0 ? result : ret;
result += ret;
- if ((size_t)ret != count * voices)
+ if ((size_t)ret != samples)
break;
- vector += voices;
+ vector += nvoices;
}
}
- return result;
+ return result * chan->bits_per_sample / 8;
}
static void *playback_mmap(void *d)
}
frag = control->frag_io;
- if (snd_pcm_mmap_playback_frags_used(pcm) <= 0) {
+ if (snd_pcm_mmap_playback_frags_used(chan) <= 0) {
fprintf(stderr, "underrun\n");
usleep(10000);
continue;
}
frag = control->frag_io;
- if (snd_pcm_mmap_capture_frags_free(pcm) <= 0) {
+ if (snd_pcm_mmap_capture_frags_free(chan) <= 0) {
fprintf(stderr, "overrun\n");
usleep(10000);
continue;
return 0;
}
+int snd_pcm_mmap_get_areas(snd_pcm_t *pcm, int channel, snd_pcm_voice_area_t *areas)
+{
+ struct snd_pcm_chan *chan;
+ snd_pcm_voice_setup_t s;
+ snd_pcm_voice_area_t *a, *ap;
+ 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 || !chan->mmap_data)
+ return -EBADFD;
+ a = calloc(chan->setup.format.voices, sizeof(*areas));
+ for (voice = 0, ap = a; voice < chan->setup.format.voices; ++voice, ++ap) {
+ s.voice = voice;
+ err = snd_pcm_voice_setup(pcm, channel, &s);
+ if (err < 0) {
+ free(a);
+ return err;
+ }
+ if (areas)
+ areas[voice] = s.area;
+ *ap = s.area;
+ }
+ chan->voices = a;
+ return 0;
+}
+
int snd_pcm_mmap_data(snd_pcm_t *pcm, int channel, void **data)
{
struct snd_pcm_chan *chan;
}
chan->mmap_data = *data;
chan->mmap_data_size = bsize;
- snd_pcm_all_voices_setup(pcm, channel, NULL);
+ err = snd_pcm_mmap_get_areas(pcm, channel, NULL);
+ if (err < 0)
+ return err;
return 0;
}
if ((err = pcm->ops->munmap_data(pcm, channel, chan->mmap_data, chan->mmap_data_size)) < 0)
return err;
}
+ free(chan->voices);
chan->mmap_data = 0;
chan->mmap_data_size = 0;
return 0;
}
/* 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);
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);
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;
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)
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;
}
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) {
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) {
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;
}
}
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);
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;
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;
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;
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;
}
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;
#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;
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;
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);
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;
{
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;
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)
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;
}
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)
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)
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;
}
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 &&
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;
}
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);
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);
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);
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;
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;
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) {
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) {
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;
}
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;
}
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) {
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
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++;
}
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;
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;
}
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;
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 {
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;