int dst_width; /* sample width in bits */
ssize_t (*src_samples)(snd_pcm_plugin_t *plugin, size_t dst_samples);
ssize_t (*dst_samples)(snd_pcm_plugin_t *plugin, size_t src_samples);
- int (*client_voices)(snd_pcm_plugin_t *plugin,
- size_t samples,
- snd_pcm_plugin_voice_t **voices);
+ ssize_t (*client_voices)(snd_pcm_plugin_t *plugin,
+ size_t samples,
+ snd_pcm_plugin_voice_t **voices);
int (*src_voices_mask)(snd_pcm_plugin_t *plugin,
bitset_t *dst_vmask,
bitset_t **src_vmask);
int extra,
snd_pcm_plugin_t **ret);
/* basic I/O */
-int snd_pcm_plugin_build_stream(snd_pcm_plugin_handle_t *handle,
- int channel,
- snd_pcm_t *slave,
- snd_pcm_format_t *format,
- snd_pcm_plugin_t **r_plugin);
-int snd_pcm_plugin_build_block(snd_pcm_plugin_handle_t *handle,
- int channel,
- snd_pcm_t *slave,
- snd_pcm_format_t *format,
- snd_pcm_plugin_t **r_plugin);
+int snd_pcm_plugin_build_io(snd_pcm_plugin_handle_t *handle,
+ int channel,
+ snd_pcm_t *slave,
+ snd_pcm_format_t *format,
+ snd_pcm_plugin_t **r_plugin);
int snd_pcm_plugin_build_mmap(snd_pcm_plugin_handle_t *handle,
int channel,
snd_pcm_t *slave,
struct snd_pcm_chan *chan = &pcm->chan[channel];
if (chan->mmap_control->status != SND_PCM_STATUS_PREPARED)
return -EBADFD;
- if (chan->mmap_control->frag_data == 0)
+ if (chan->mmap_control->byte_data == 0)
return -EIO;
chan->mmap_control->status = SND_PCM_STATUS_RUNNING;
pthread_mutex_lock(&chan->mutex);
return 0;
}
-static int snd_pcm_plugin_side_voices(snd_pcm_plugin_t *plugin,
- int client_side,
- size_t samples,
- snd_pcm_plugin_voice_t **voices)
+static ssize_t snd_pcm_plugin_side_voices(snd_pcm_plugin_t *plugin,
+ int client_side,
+ size_t samples,
+ snd_pcm_plugin_voice_t **voices)
{
char *ptr;
int width;
v->area.step = width;
}
}
- return 0;
+ return samples;
}
-int snd_pcm_plugin_client_voices(snd_pcm_plugin_t *plugin,
- size_t samples,
- snd_pcm_plugin_voice_t **voices)
+ssize_t snd_pcm_plugin_client_voices(snd_pcm_plugin_t *plugin,
+ size_t samples,
+ snd_pcm_plugin_voice_t **voices)
{
return snd_pcm_plugin_side_voices(plugin, 1, samples, voices);
}
-int snd_pcm_plugin_slave_voices(snd_pcm_plugin_t *plugin,
- size_t samples,
- snd_pcm_plugin_voice_t **voices)
+ssize_t snd_pcm_plugin_slave_voices(snd_pcm_plugin_t *plugin,
+ size_t samples,
+ snd_pcm_plugin_voice_t **voices)
{
return snd_pcm_plugin_side_voices(plugin, 0, samples, voices);
}
snd_pcm_plug_buf_unlock(handle, SND_PCM_CHANNEL_PLAYBACK, src_voices->aptr);
return err;
}
+ if (err != samples1) {
+ samples = err;
+ if (plugin->src_samples)
+ samples = plugin->src_samples(plugin, samples1);
+ }
} else {
if ((err = snd_pcm_plugin_slave_voices(plugin, samples, &dst_voices)) < 0)
return err;
snd_pcm_plug_buf_unlock(handle, SND_PCM_CHANNEL_CAPTURE, src_voices->aptr);
return err;
}
+ samples = err;
} else {
dst_voices = dst_voices_final;
}
static void snd_pcm_mmap_clear(snd_pcm_t *pcm, int channel)
{
struct snd_pcm_chan *chan = &pcm->chan[channel];
- chan->mmap_control->frag_io = 0;
- chan->mmap_control->frag_data = 0;
chan->mmap_control->byte_io = 0;
chan->mmap_control->byte_data = 0;
}
}
}
-static inline ssize_t snd_pcm_mmap_playback_frags_used(struct snd_pcm_chan *chan)
-{
- ssize_t frags_used;
- 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 inline ssize_t snd_pcm_mmap_playback_bytes_used(struct snd_pcm_chan *chan)
{
ssize_t 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;
- 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;
+ struct snd_pcm_chan *chan = &pcm->chan[SND_PCM_CHANNEL_PLAYBACK];
+ 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_bytes_used(struct snd_pcm_chan *chan)
static size_t snd_pcm_mmap_capture_samples_used(snd_pcm_t *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;
- }
+ struct snd_pcm_chan *chan = &pcm->chan[SND_PCM_CHANNEL_CAPTURE];
+ size_t bytes = snd_pcm_mmap_capture_bytes_used(chan);
+ return bytes * 8 / chan->bits_per_sample;
}
int snd_pcm_mmap_samples_used(snd_pcm_t *pcm, int channel, ssize_t *samples)
return 0;
}
-static inline size_t snd_pcm_mmap_playback_frags_free(struct snd_pcm_chan *chan)
-{
- return chan->setup.frags - snd_pcm_mmap_playback_frags_used(chan);
-}
-
static inline size_t snd_pcm_mmap_playback_bytes_free(struct snd_pcm_chan *chan)
{
return chan->setup.buffer_size - snd_pcm_mmap_playback_bytes_used(chan);
static size_t snd_pcm_mmap_playback_samples_free(snd_pcm_t *pcm)
{
- struct snd_pcm_chan *chan;
- 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;
- }
-}
-
-static inline ssize_t snd_pcm_mmap_capture_frags_free(struct snd_pcm_chan *chan)
-{
- return chan->setup.frags - snd_pcm_mmap_capture_frags_used(chan);
+ struct snd_pcm_chan *chan = &pcm->chan[SND_PCM_CHANNEL_PLAYBACK];
+ size_t bytes = snd_pcm_mmap_playback_bytes_free(chan);
+ return bytes * 8 / chan->bits_per_sample;
}
-
static inline ssize_t snd_pcm_mmap_capture_bytes_free(struct snd_pcm_chan *chan)
{
return chan->setup.buffer_size - snd_pcm_mmap_capture_bytes_used(chan);
static ssize_t snd_pcm_mmap_capture_samples_free(snd_pcm_t *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;
- }
+ struct snd_pcm_chan *chan = &pcm->chan[SND_PCM_CHANNEL_CAPTURE];
+ ssize_t bytes = snd_pcm_mmap_capture_bytes_free(chan);
+ return bytes * 8 / chan->bits_per_sample;
}
int snd_pcm_mmap_samples_free(snd_pcm_t *pcm, int channel, ssize_t *samples)
chan = &pcm->chan[SND_PCM_CHANNEL_PLAYBACK];
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(chan)) >= chan->setup.buf.block.frags_min;
- } else {
- return (chan->setup.buffer_size - snd_pcm_mmap_playback_bytes_used(chan)) >= chan->setup.buf.stream.bytes_min;
- }
+ return (chan->setup.buffer_size - snd_pcm_mmap_playback_bytes_used(chan)) >= chan->setup.bytes_min;
}
static int snd_pcm_mmap_capture_ready(snd_pcm_t *pcm)
if (chan->setup.xrun_mode == SND_PCM_XRUN_DRAIN)
return -EPIPE;
}
- if (chan->setup.mode == SND_PCM_MODE_BLOCK) {
- if (snd_pcm_mmap_capture_frags_used(chan) >= chan->setup.buf.block.frags_min)
- return 1;
- } else {
- if (snd_pcm_mmap_capture_bytes_used(chan) >= chan->setup.buf.stream.bytes_min)
- return 1;
- }
+ if (snd_pcm_mmap_capture_bytes_used(chan) >= chan->setup.bytes_min)
+ return 1;
return ret;
}
}
}
-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 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;
-}
-
-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];
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;
+ bytes -= bytes % chan->setup.bytes_align;
return bytes;
}
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;
+ bytes -= bytes % chan->setup.bytes_align;
return bytes;
}
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;
- }
+ struct snd_pcm_chan *chan = &pcm->chan[SND_PCM_CHANNEL_PLAYBACK];
+ 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;
- }
+ struct snd_pcm_chan *chan = &pcm->chan[SND_PCM_CHANNEL_CAPTURE];
+ 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)
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;
+ 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;
+ size_t byte_data, bytes;
if (!pcm)
return -EFAULT;
if (channel < 0 || channel > 1)
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;
- }
+ 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;
} 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;
- }
+ ctrl->byte_data = byte_data;
}
return 0;
}
return result * chan->bits_per_sample / 8;
}
+static ssize_t mmap_playback_bytes_xfer(struct snd_pcm_chan *chan)
+{
+ snd_pcm_mmap_control_t *ctrl = chan->mmap_control;
+ size_t bytes_cont;
+ size_t byte_io = ctrl->byte_io;
+ ssize_t bytes = snd_pcm_mmap_playback_bytes_used(chan);
+ bytes_cont = chan->setup.buffer_size - (byte_io % chan->setup.buffer_size);
+ if ((ssize_t)bytes_cont < bytes)
+ bytes = bytes_cont;
+ bytes -= bytes % chan->setup.bytes_align;
+ return bytes;
+}
+
+static ssize_t mmap_capture_bytes_xfer(struct snd_pcm_chan *chan)
+{
+ snd_pcm_mmap_control_t *ctrl = chan->mmap_control;
+ size_t bytes_cont;
+ size_t byte_io = ctrl->byte_io;
+ ssize_t bytes = snd_pcm_mmap_capture_bytes_free(chan);
+ bytes_cont = chan->setup.buffer_size - (byte_io % chan->setup.buffer_size);
+ if ((ssize_t)bytes_cont < bytes)
+ bytes = bytes_cont;
+ bytes -= bytes % chan->setup.bytes_align;
+ return bytes;
+}
+
static void *playback_mmap(void *d)
{
snd_pcm_t *pcm = d;
struct snd_pcm_chan *chan = &pcm->chan[SND_PCM_CHANNEL_PLAYBACK];
snd_pcm_mmap_control_t *control;
char *data;
- int frags;
- int frag_size, voice_size, voice_frag_size;
+ size_t voice_size;
int voices;
control = chan->mmap_control;
data = chan->mmap_data;
- frags = chan->setup.frags;
- frag_size = chan->setup.frag_size;
voices = chan->setup.format.voices;
voice_size = chan->mmap_data_size / voices;
- voice_frag_size = voice_size / frags;
while (1) {
int err;
struct pollfd pfd;
- unsigned int f, frag;
+ size_t pos, p, bytes;
if (chan->mmap_thread_stop)
break;
continue;
}
- frag = control->frag_io;
- if (snd_pcm_mmap_playback_frags_used(chan) <= 0) {
+ pos = control->byte_io;
+ bytes = mmap_playback_bytes_xfer(chan);
+ if (bytes <= 0) {
fprintf(stderr, "underrun\n");
usleep(10000);
continue;
}
- f = frag % frags;
+ p = pos % chan->setup.buffer_size;
if (chan->setup.format.interleave) {
- err = snd_pcm_write(pcm, data + f * frag_size, frag_size);
+ err = snd_pcm_write(pcm, data + pos, bytes);
} else {
struct iovec vector[voices];
struct iovec *v = vector;
int voice;
+ size_t size = bytes / voices;
+ size_t posv = p / voices;
for (voice = 0; voice < voices; ++voice) {
- v->iov_base = data + voice_size * voice + f * voice_frag_size;
- v->iov_len = voice_frag_size;
+ v->iov_base = data + voice_size * voice + posv;
+ v->iov_len = size;
v++;
}
- err = snd_pcm_writev(pcm, vector, voice_frag_size);
+ err = snd_pcm_writev(pcm, vector, voices);
}
if (err <= 0) {
fprintf(stderr, "write err=%d\n", err);
pthread_mutex_lock(&chan->mutex);
pthread_cond_signal(&chan->ready_cond);
pthread_mutex_unlock(&chan->mutex);
- frag++;
- if (frag == chan->setup.frag_boundary)
- frag = 0;
- control->frag_io = frag;
+ pos += bytes;
+ if (pos == chan->setup.byte_boundary)
+ pos = 0;
+ control->byte_io = pos;
}
return 0;
}
while (1) {
int err;
struct pollfd pfd;
- unsigned int f, frag;
+ size_t pos, p, bytes;
if (chan->mmap_thread_stop)
break;
continue;
}
- frag = control->frag_io;
- if (snd_pcm_mmap_capture_frags_free(chan) <= 0) {
+ pos = control->byte_io;
+ bytes = mmap_capture_bytes_xfer(chan);
+ if (bytes <= 0) {
fprintf(stderr, "overrun\n");
usleep(10000);
continue;
}
- f = frag % frags;
+ p = pos % chan->setup.buffer_size;
if (chan->setup.format.interleave) {
- err = snd_pcm_read(pcm, data + f * frag_size, frag_size);
+ err = snd_pcm_read(pcm, data + pos, bytes);
} else {
struct iovec vector[voices];
struct iovec *v = vector;
int voice;
+ size_t size = bytes / voices;
+ size_t posv = p / voices;
for (voice = 0; voice < voices; ++voice) {
- v->iov_base = data + voice_size * voice + f * voice_frag_size;
- v->iov_len = voice_frag_size;
+ v->iov_base = data + voice_size * voice + posv;
+ v->iov_len = size;
v++;
}
- err = snd_pcm_readv(pcm, vector, voice_frag_size);
+ err = snd_pcm_readv(pcm, vector, voices);
}
if (err < 0) {
fprintf(stderr, "read err=%d\n", err);
snd_pcm_mmap_status_change(pcm, SND_PCM_CHANNEL_CAPTURE, -1);
continue;
}
- frag++;
- if (frag == chan->setup.frag_boundary)
- frag = 0;
- control->frag_io = frag;
+ pthread_mutex_lock(&chan->mutex);
+ pthread_cond_signal(&chan->ready_cond);
+ pthread_mutex_unlock(&chan->mutex);
+ pos += bytes;
+ if (pos == chan->setup.byte_boundary)
+ pos = 0;
+ control->byte_io = pos;
}
return 0;
}
* I/O plugins
*/
- if (params->mode == SND_PCM_MODE_STREAM) {
- pdprintf("params stream plugin\n");
- err = snd_pcm_plugin_build_stream(pcm, channel, plug->slave, &slave_params.format, &plugin);
- } else if (params->mode == SND_PCM_MODE_BLOCK) {
- if (slave_info.flags & SND_PCM_CHNINFO_MMAP) {
- pdprintf("params mmap plugin\n");
- err = snd_pcm_plugin_build_mmap(pcm, channel, plug->slave, &slave_params.format, &plugin);
- } else {
- pdprintf("params block plugin\n");
- err = snd_pcm_plugin_build_block(pcm, channel, plug->slave, &slave_params.format, &plugin);
- }
+ if (slave_info.flags & SND_PCM_CHNINFO_MMAP) {
+ pdprintf("params mmap plugin\n");
+ err = snd_pcm_plugin_build_mmap(pcm, channel, plug->slave, &slave_params.format, &plugin);
} else {
- return -EINVAL;
+ pdprintf("params I/O plugin\n");
+ err = snd_pcm_plugin_build_io(pcm, channel, plug->slave, &slave_params.format, &plugin);
}
if (err < 0)
return err;
/* 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);
- slave_params.buf.stream.bytes_min = snd_pcm_plug_slave_size(pcm, channel, slave_params.buf.stream.bytes_min);
- slave_params.buf.stream.bytes_xrun_max = snd_pcm_plug_slave_size(pcm, channel, slave_params.buf.stream.bytes_xrun_max);
- slave_params.buf.stream.bytes_align = snd_pcm_plug_slave_size(pcm, channel, slave_params.buf.stream.bytes_align);
- } else if (params->mode != SND_PCM_MODE_BLOCK)
- return -EINVAL;
+ slave_params.bytes_fill_max = snd_pcm_plug_slave_size(pcm, channel, slave_params.bytes_fill_max);
+ slave_params.bytes_min = snd_pcm_plug_slave_size(pcm, channel, slave_params.bytes_min);
+ slave_params.bytes_xrun_max = snd_pcm_plug_slave_size(pcm, channel, slave_params.bytes_xrun_max);
+ slave_params.bytes_align = snd_pcm_plug_slave_size(pcm, channel, slave_params.bytes_align);
+
pdprintf("params requested params: format = %i, rate = %i, voices = %i\n", slave_params.format.format, slave_params.format.rate, slave_params.format.voices);
err = snd_pcm_channel_params(plug->slave, &slave_params);
if (err < 0)
return err;
if (snd_pcm_plug_direct(pcm, setup->channel))
return 0;
+ setup->byte_boundary /= setup->frag_size;
setup->frag_size = snd_pcm_plug_client_size(pcm, setup->channel, setup->frag_size);
+ setup->byte_boundary *= setup->frag_size;
setup->buffer_size = setup->frags * setup->frag_size;
- setup->byte_boundary = setup->frag_boundary * setup->frag_size;
- 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);
- setup->buf.stream.bytes_xrun_max = snd_pcm_plug_client_size(pcm, setup->channel, setup->buf.stream.bytes_xrun_max);
- setup->buf.stream.bytes_fill_max = snd_pcm_plug_client_size(pcm, setup->channel, setup->buf.stream.bytes_fill_max);
- } else if (setup->mode != SND_PCM_MODE_BLOCK) {
- return -EINVAL;
- }
+ setup->bytes_min = snd_pcm_plug_client_size(pcm, setup->channel, setup->bytes_min);
+ setup->bytes_align = snd_pcm_plug_client_size(pcm, setup->channel, setup->bytes_align);
+ setup->bytes_xrun_max = snd_pcm_plug_client_size(pcm, setup->channel, setup->bytes_xrun_max);
+ setup->bytes_fill_max = snd_pcm_plug_client_size(pcm, setup->channel, setup->bytes_fill_max);
plugchan = &plug->chan[setup->channel];
if (setup->channel == SND_PCM_CHANNEL_PLAYBACK)
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;
}
EXTRA_LTLIBRARIES = libpcmplugin.la
-libpcmplugin_la_SOURCES = block.c mmap.c stream.c copy.c linear.c \
+libpcmplugin_la_SOURCES = io.c mmap.c copy.c linear.c \
mulaw.c alaw.c adpcm.c rate.c route.c
all: libpcmplugin.la
/*
- * PCM Block Plug-In Interface
+ * PCM I/O Plug-In Interface
* Copyright (c) 1999 by Jaroslav Kysela <perex@suse.cz>
*
*
#endif
/*
- * Basic block plugin
+ * Basic io plugin
*/
-typedef struct block_private_data {
+typedef struct io_private_data {
snd_pcm_plugin_handle_t *slave;
-} block_t;
+} io_t;
-static ssize_t block_transfer(snd_pcm_plugin_t *plugin,
+static ssize_t io_transfer(snd_pcm_plugin_t *plugin,
const snd_pcm_plugin_voice_t *src_voices,
snd_pcm_plugin_voice_t *dst_voices,
size_t samples)
{
- block_t *data;
+ io_t *data;
ssize_t result;
struct iovec *vec;
int count, voice;
if (plugin == NULL)
return -EINVAL;
- data = (block_t *)plugin->extra_data;
+ data = (io_t *)plugin->extra_data;
if (data == NULL)
return -EINVAL;
vec = (struct iovec *)((char *)data + sizeof(*data));
}
}
-static int block_src_voices(snd_pcm_plugin_t *plugin,
+static int io_src_voices(snd_pcm_plugin_t *plugin,
size_t samples,
snd_pcm_plugin_voice_t **voices)
{
return 0;
}
-int snd_pcm_plugin_build_block(snd_pcm_plugin_handle_t *pcm,
+int snd_pcm_plugin_build_io(snd_pcm_plugin_handle_t *pcm,
int channel,
snd_pcm_plugin_handle_t *slave,
snd_pcm_format_t *format,
snd_pcm_plugin_t **r_plugin)
{
int err;
- block_t *data;
+ io_t *data;
snd_pcm_plugin_t *plugin;
if (r_plugin == NULL)
if (pcm == NULL || format == NULL)
return -EINVAL;
err = snd_pcm_plugin_build(pcm, channel,
- "I/O block",
+ "I/O io",
format, format,
- sizeof(block_t) + sizeof(struct iovec) * format->voices,
+ sizeof(io_t) + sizeof(struct iovec) * format->voices,
&plugin);
if (err < 0)
return err;
- data = (block_t *)plugin->extra_data;
+ data = (io_t *)plugin->extra_data;
data->slave = slave;
- plugin->transfer = block_transfer;
+ plugin->transfer = io_transfer;
if (format->interleave && channel == SND_PCM_CHANNEL_PLAYBACK)
- plugin->client_voices = block_src_voices;
+ plugin->client_voices = io_src_voices;
*r_plugin = plugin;
return 0;
}
snd_pcm_t *slave;
snd_pcm_mmap_control_t *control;
void *buffer;
- unsigned int frag;
+#if 0
char *silence;
+#endif
} mmap_t;
-static int mmap_src_voices(snd_pcm_plugin_t *plugin,
- size_t samples,
- snd_pcm_plugin_voice_t **voices)
+static ssize_t mmap_src_voices(snd_pcm_plugin_t *plugin,
+ size_t samples,
+ snd_pcm_plugin_voice_t **voices)
{
mmap_t *data;
- unsigned int voice;
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;
+ size_t pos;
int ready;
+ unsigned int voice;
if (plugin == NULL || voices == NULL)
return -EINVAL;
data = (mmap_t *)plugin->extra_data;
ctrl = data->control;
chan = &data->slave->chan[plugin->channel];
- if (samples != chan->samples_per_frag)
- return -EINVAL;
setup = &chan->setup;
if (ctrl->status < SND_PCM_STATUS_PREPARED)
return -EPIPE;
assert(snd_pcm_mmap_ready(data->slave, plugin->channel));
}
- frag = ctrl->frag_data;
- f = frag % setup->frags;
+ pos = ctrl->byte_data % setup->buffer_size;
+ if ((pos * 8) % chan->bits_per_sample != 0)
+ return -EINVAL;
+ pos = (pos * 8) / chan->bits_per_sample;
sv = plugin->src_voices;
dv = chan->voices;
*voices = sv;
for (voice = 0; voice < plugin->src_format.voices; ++voice) {
sv->enabled = 1;
+#if 0
sv->wanted = !data->silence[voice * setup->frags + f];
+#else
+ sv->wanted = 1;
+#endif
sv->aptr = 0;
- sv->area.addr = dv->addr + (dv->step * chan->samples_per_frag * f) / 8;
+ sv->area.addr = dv->addr + dv->step * pos / 8;
sv->area.first = dv->first;
sv->area.step = dv->step;
++sv;
++dv;
}
- data->frag = frag;
- return 0;
+ return snd_pcm_mmap_samples_xfer(data->slave, plugin->channel, samples);
}
-static int mmap_dst_voices(snd_pcm_plugin_t *plugin,
- size_t samples,
- snd_pcm_plugin_voice_t **voices)
+static ssize_t mmap_dst_voices(snd_pcm_plugin_t *plugin,
+ size_t samples,
+ snd_pcm_plugin_voice_t **voices)
{
mmap_t *data;
int err;
struct snd_pcm_chan *chan;
snd_pcm_channel_setup_t *setup;
snd_pcm_mmap_control_t *ctrl;
- int frag, f;
+ size_t pos;
int ready;
if (plugin == NULL || voices == NULL)
return -EINVAL;
data = (mmap_t *)plugin->extra_data;
chan = &data->slave->chan[plugin->channel];
- if (samples != chan->samples_per_frag)
- return -EINVAL;
setup = &chan->setup;
ctrl = data->control;
return -EPIPE;
assert(snd_pcm_mmap_ready(data->slave, plugin->channel));
}
-
- frag = ctrl->frag_data;
- f = frag % setup->frags;
+ pos = ctrl->byte_data % setup->buffer_size;
+ if ((pos * 8) % chan->bits_per_sample != 0)
+ return -EINVAL;
+ pos = (pos * 8) / chan->bits_per_sample;
sv = chan->voices;
dv = plugin->dst_voices;
dv->enabled = 1;
dv->wanted = 0;
dv->aptr = 0;
- dv->area.addr = sv->addr + (sv->step * chan->samples_per_frag * f) / 8;
+ dv->area.addr = sv->addr + sv->step * pos / 8;
dv->area.first = sv->first;
dv->area.step = sv->step;
++sv;
++dv;
}
- data->frag = frag;
- return 0;
+ return snd_pcm_mmap_samples_xfer(data->slave, plugin->channel, samples);
}
static ssize_t mmap_playback_transfer(snd_pcm_plugin_t *plugin,
size_t samples)
{
mmap_t *data;
- unsigned int voice;
snd_pcm_channel_setup_t *setup;
snd_pcm_mmap_control_t *ctrl;
struct snd_pcm_chan *chan;
- unsigned int frag, f;
int err;
if (plugin == NULL)
return -EINVAL;
chan = &data->slave->chan[SND_PCM_CHANNEL_PLAYBACK];
setup = &chan->setup;
- frag = ctrl->frag_data;
- if (frag != data->frag)
- return -EIO;
- f = frag % setup->frags;
+#if 0
for (voice = 0; voice < plugin->src_format.voices; voice++) {
if (src_voices[voice].enabled)
data->silence[voice * setup->frags + f] = 0;
}
+#endif
snd_pcm_mmap_commit_samples(data->slave, SND_PCM_CHANNEL_PLAYBACK, samples);
if (ctrl->status == SND_PCM_STATUS_PREPARED &&
mmap_t *data;
snd_pcm_channel_setup_t *setup;
snd_pcm_mmap_control_t *ctrl;
- unsigned int frag;
if (plugin == NULL)
return -EINVAL;
ctrl = data->control;
if (ctrl == NULL)
return -EINVAL;
- frag = ctrl->frag_data;
- if (frag != data->frag)
- return -EIO;
setup = &data->slave->chan[SND_PCM_CHANNEL_CAPTURE].setup;
/* FIXME: not here the increment */
return result;
setup = &data->slave->chan[plugin->channel].setup;
+#if 0
if (plugin->channel == SND_PCM_CHANNEL_PLAYBACK) {
data->silence = malloc(setup->frags * setup->format.voices);
memset(data->silence, 0, setup->frags * setup->format.voices);
} else
data->silence = 0;
+#endif
return 0;
}
return 0; /* silenty ignore other actions */
if (plugin == NULL)
return;
data = (mmap_t *)plugin->extra_data;
+#if 0
if (data->silence)
free(data->silence);
+#endif
if (data->control)
snd_pcm_munmap(data->slave, plugin->channel);
}
+++ /dev/null
-/*
- * PCM Stream Plug-In Interface
- * Copyright (c) 1999 by Jaroslav Kysela <perex@suse.cz>
- *
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Library General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <errno.h>
-#include <sys/uio.h>
-#include "../pcm_local.h"
-
-/*
- * Basic stream plugin
- */
-
-typedef struct stream_private_data {
- snd_pcm_t *slave;
-} stream_t;
-
-static ssize_t stream_transfer(snd_pcm_plugin_t *plugin,
- const snd_pcm_plugin_voice_t *src_voices,
- snd_pcm_plugin_voice_t *dst_voices,
- size_t samples)
-{
- stream_t *data;
- ssize_t result;
- struct iovec *vec;
- int count, voice;
-
- if (plugin == NULL)
- return -EINVAL;
- data = (stream_t *)plugin->extra_data;
- if (data == NULL)
- return -EINVAL;
- vec = (struct iovec *)((char *)data + sizeof(*data));
- if (plugin->channel == SND_PCM_CHANNEL_PLAYBACK) {
- if (src_voices == NULL)
- return -EINVAL;
- if ((result = snd_pcm_plugin_src_samples_to_size(plugin, samples)) < 0)
- return result;
- count = plugin->src_format.voices;
- if (plugin->src_format.interleave) {
- 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].area.addr;
- else
- vec[voice].iov_base = 0;
- vec[voice].iov_len = result;
- }
- result = snd_pcm_writev(data->slave, vec, count);
- }
- if (result < 0)
- return result;
- return snd_pcm_plugin_src_size_to_samples(plugin, result);
- } else if (plugin->channel == SND_PCM_CHANNEL_CAPTURE) {
- if (dst_voices == NULL)
- return -EINVAL;
- if ((result = snd_pcm_plugin_dst_samples_to_size(plugin, samples)) < 0)
- return result;
- count = plugin->dst_format.voices;
- if (plugin->dst_format.interleave) {
- 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 {
- result /= count;
- 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].area.addr;
- else
- vec[voice].iov_base = 0;
- vec[voice].iov_len = result;
- }
- result = snd_pcm_readv(data->slave, vec, count);
- }
- if (result < 0)
- return result;
- return snd_pcm_plugin_dst_size_to_samples(plugin, result);
- } else {
- return -EINVAL;
- }
-}
-
-static int stream_src_voices(snd_pcm_plugin_t *plugin,
- size_t samples,
- snd_pcm_plugin_voice_t **voices)
-{
- int err;
- unsigned int voice;
- snd_pcm_plugin_voice_t *v;
- err = snd_pcm_plugin_client_voices(plugin, samples, &v);
- if (err < 0)
- return err;
- *voices = v;
- for (voice = 0; voice < plugin->src_format.voices; ++voice, ++v)
- v->wanted = 1;
- return 0;
-}
-
-int snd_pcm_plugin_build_stream(snd_pcm_plugin_handle_t *pcm,
- int channel,
- snd_pcm_t *slave,
- snd_pcm_format_t *format,
- snd_pcm_plugin_t **r_plugin)
-{
- int err;
- stream_t *data;
- snd_pcm_plugin_t *plugin;
-
- if (!r_plugin)
- return -EINVAL;
- *r_plugin = NULL;
- if (!pcm || channel < 0 || channel > 1)
- return -EINVAL;
- err = snd_pcm_plugin_build(pcm, channel,
- "I/O stream",
- format, format,
- sizeof(stream_t) + sizeof(struct iovec) * format->voices,
- &plugin);
- if (err < 0)
- return err;
- data = (stream_t *)plugin->extra_data;
- data->slave = slave;
- plugin->transfer = stream_transfer;
- if (format->interleave && channel == SND_PCM_CHANNEL_PLAYBACK)
- plugin->client_voices = stream_src_voices;
- *r_plugin = plugin;
- return 0;
-}