mirror of
https://github.com/alsa-project/alsa-lib.git
synced 2025-12-20 08:56:54 -05:00
Removed frag_* fields. Collapsed I/O plugins. Added to mmap plugin support for stream mode
This commit is contained in:
parent
0b2b3c8a81
commit
c582ff51b6
9 changed files with 186 additions and 448 deletions
|
|
@ -1,6 +1,6 @@
|
|||
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
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* PCM Block Plug-In Interface
|
||||
* PCM I/O Plug-In Interface
|
||||
* Copyright (c) 1999 by Jaroslav Kysela <perex@suse.cz>
|
||||
*
|
||||
*
|
||||
|
|
@ -38,26 +38,26 @@
|
|||
#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));
|
||||
|
|
@ -114,7 +114,7 @@ static ssize_t block_transfer(snd_pcm_plugin_t *plugin,
|
|||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
|
|
@ -130,14 +130,14 @@ static int block_src_voices(snd_pcm_plugin_t *plugin,
|
|||
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)
|
||||
|
|
@ -146,17 +146,17 @@ int snd_pcm_plugin_build_block(snd_pcm_plugin_handle_t *pcm,
|
|||
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;
|
||||
}
|
||||
|
|
@ -37,32 +37,31 @@ typedef struct mmap_private_data {
|
|||
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)
|
||||
|
|
@ -86,29 +85,34 @@ static int mmap_src_voices(snd_pcm_plugin_t *plugin,
|
|||
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;
|
||||
|
|
@ -118,15 +122,13 @@ static int mmap_dst_voices(snd_pcm_plugin_t *plugin,
|
|||
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;
|
||||
|
|
@ -156,9 +158,10 @@ static int mmap_dst_voices(snd_pcm_plugin_t *plugin,
|
|||
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;
|
||||
|
|
@ -167,14 +170,13 @@ static int mmap_dst_voices(snd_pcm_plugin_t *plugin,
|
|||
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,
|
||||
|
|
@ -183,11 +185,9 @@ 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)
|
||||
|
|
@ -202,15 +202,13 @@ static ssize_t mmap_playback_transfer(snd_pcm_plugin_t *plugin,
|
|||
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 &&
|
||||
|
|
@ -232,7 +230,6 @@ static ssize_t mmap_capture_transfer(snd_pcm_plugin_t *plugin,
|
|||
mmap_t *data;
|
||||
snd_pcm_channel_setup_t *setup;
|
||||
snd_pcm_mmap_control_t *ctrl;
|
||||
unsigned int frag;
|
||||
|
||||
if (plugin == NULL)
|
||||
return -EINVAL;
|
||||
|
|
@ -243,9 +240,6 @@ static ssize_t mmap_capture_transfer(snd_pcm_plugin_t *plugin,
|
|||
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 */
|
||||
|
|
@ -273,11 +267,13 @@ static int mmap_action(snd_pcm_plugin_t *plugin,
|
|||
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 */
|
||||
|
|
@ -290,8 +286,10 @@ static void mmap_free(snd_pcm_plugin_t *plugin, void *private_data UNUSED)
|
|||
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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,151 +0,0 @@
|
|||
/*
|
||||
* 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;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue