mirror of
https://github.com/alsa-project/alsa-lib.git
synced 2025-12-16 08:56:42 -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
|
|
@ -213,9 +213,9 @@ struct snd_stru_pcm_plugin {
|
||||||
int dst_width; /* sample width in bits */
|
int dst_width; /* sample width in bits */
|
||||||
ssize_t (*src_samples)(snd_pcm_plugin_t *plugin, size_t dst_samples);
|
ssize_t (*src_samples)(snd_pcm_plugin_t *plugin, size_t dst_samples);
|
||||||
ssize_t (*dst_samples)(snd_pcm_plugin_t *plugin, size_t src_samples);
|
ssize_t (*dst_samples)(snd_pcm_plugin_t *plugin, size_t src_samples);
|
||||||
int (*client_voices)(snd_pcm_plugin_t *plugin,
|
ssize_t (*client_voices)(snd_pcm_plugin_t *plugin,
|
||||||
size_t samples,
|
size_t samples,
|
||||||
snd_pcm_plugin_voice_t **voices);
|
snd_pcm_plugin_voice_t **voices);
|
||||||
int (*src_voices_mask)(snd_pcm_plugin_t *plugin,
|
int (*src_voices_mask)(snd_pcm_plugin_t *plugin,
|
||||||
bitset_t *dst_vmask,
|
bitset_t *dst_vmask,
|
||||||
bitset_t **src_vmask);
|
bitset_t **src_vmask);
|
||||||
|
|
@ -288,16 +288,11 @@ int snd_pcm_plugin_build(snd_pcm_plugin_handle_t *handle,
|
||||||
int extra,
|
int extra,
|
||||||
snd_pcm_plugin_t **ret);
|
snd_pcm_plugin_t **ret);
|
||||||
/* basic I/O */
|
/* basic I/O */
|
||||||
int snd_pcm_plugin_build_stream(snd_pcm_plugin_handle_t *handle,
|
int snd_pcm_plugin_build_io(snd_pcm_plugin_handle_t *handle,
|
||||||
int channel,
|
int channel,
|
||||||
snd_pcm_t *slave,
|
snd_pcm_t *slave,
|
||||||
snd_pcm_format_t *format,
|
snd_pcm_format_t *format,
|
||||||
snd_pcm_plugin_t **r_plugin);
|
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_mmap(snd_pcm_plugin_handle_t *handle,
|
int snd_pcm_plugin_build_mmap(snd_pcm_plugin_handle_t *handle,
|
||||||
int channel,
|
int channel,
|
||||||
snd_pcm_t *slave,
|
snd_pcm_t *slave,
|
||||||
|
|
|
||||||
|
|
@ -269,7 +269,7 @@ static int mmap_playback_go(snd_pcm_t *pcm, int channel)
|
||||||
struct snd_pcm_chan *chan = &pcm->chan[channel];
|
struct snd_pcm_chan *chan = &pcm->chan[channel];
|
||||||
if (chan->mmap_control->status != SND_PCM_STATUS_PREPARED)
|
if (chan->mmap_control->status != SND_PCM_STATUS_PREPARED)
|
||||||
return -EBADFD;
|
return -EBADFD;
|
||||||
if (chan->mmap_control->frag_data == 0)
|
if (chan->mmap_control->byte_data == 0)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
chan->mmap_control->status = SND_PCM_STATUS_RUNNING;
|
chan->mmap_control->status = SND_PCM_STATUS_RUNNING;
|
||||||
pthread_mutex_lock(&chan->mutex);
|
pthread_mutex_lock(&chan->mutex);
|
||||||
|
|
|
||||||
|
|
@ -57,10 +57,10 @@ static int snd_pcm_plugin_dst_voices_mask(snd_pcm_plugin_t *plugin,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int snd_pcm_plugin_side_voices(snd_pcm_plugin_t *plugin,
|
static ssize_t snd_pcm_plugin_side_voices(snd_pcm_plugin_t *plugin,
|
||||||
int client_side,
|
int client_side,
|
||||||
size_t samples,
|
size_t samples,
|
||||||
snd_pcm_plugin_voice_t **voices)
|
snd_pcm_plugin_voice_t **voices)
|
||||||
{
|
{
|
||||||
char *ptr;
|
char *ptr;
|
||||||
int width;
|
int width;
|
||||||
|
|
@ -104,19 +104,19 @@ static int snd_pcm_plugin_side_voices(snd_pcm_plugin_t *plugin,
|
||||||
v->area.step = width;
|
v->area.step = width;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return samples;
|
||||||
}
|
}
|
||||||
|
|
||||||
int snd_pcm_plugin_client_voices(snd_pcm_plugin_t *plugin,
|
ssize_t snd_pcm_plugin_client_voices(snd_pcm_plugin_t *plugin,
|
||||||
size_t samples,
|
size_t samples,
|
||||||
snd_pcm_plugin_voice_t **voices)
|
snd_pcm_plugin_voice_t **voices)
|
||||||
{
|
{
|
||||||
return snd_pcm_plugin_side_voices(plugin, 1, samples, voices);
|
return snd_pcm_plugin_side_voices(plugin, 1, samples, voices);
|
||||||
}
|
}
|
||||||
|
|
||||||
int snd_pcm_plugin_slave_voices(snd_pcm_plugin_t *plugin,
|
ssize_t snd_pcm_plugin_slave_voices(snd_pcm_plugin_t *plugin,
|
||||||
size_t samples,
|
size_t samples,
|
||||||
snd_pcm_plugin_voice_t **voices)
|
snd_pcm_plugin_voice_t **voices)
|
||||||
{
|
{
|
||||||
return snd_pcm_plugin_side_voices(plugin, 0, samples, voices);
|
return snd_pcm_plugin_side_voices(plugin, 0, samples, voices);
|
||||||
}
|
}
|
||||||
|
|
@ -1073,6 +1073,11 @@ ssize_t snd_pcm_plug_write_transfer(snd_pcm_plugin_handle_t *handle, snd_pcm_plu
|
||||||
snd_pcm_plug_buf_unlock(handle, SND_PCM_CHANNEL_PLAYBACK, src_voices->aptr);
|
snd_pcm_plug_buf_unlock(handle, SND_PCM_CHANNEL_PLAYBACK, src_voices->aptr);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
if (err != samples1) {
|
||||||
|
samples = err;
|
||||||
|
if (plugin->src_samples)
|
||||||
|
samples = plugin->src_samples(plugin, samples1);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if ((err = snd_pcm_plugin_slave_voices(plugin, samples, &dst_voices)) < 0)
|
if ((err = snd_pcm_plugin_slave_voices(plugin, samples, &dst_voices)) < 0)
|
||||||
return err;
|
return err;
|
||||||
|
|
@ -1121,6 +1126,7 @@ ssize_t snd_pcm_plug_read_transfer(snd_pcm_plugin_handle_t *handle, snd_pcm_plug
|
||||||
snd_pcm_plug_buf_unlock(handle, SND_PCM_CHANNEL_CAPTURE, src_voices->aptr);
|
snd_pcm_plug_buf_unlock(handle, SND_PCM_CHANNEL_CAPTURE, src_voices->aptr);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
samples = err;
|
||||||
} else {
|
} else {
|
||||||
dst_voices = dst_voices_final;
|
dst_voices = dst_voices_final;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,8 +29,6 @@
|
||||||
static void snd_pcm_mmap_clear(snd_pcm_t *pcm, int channel)
|
static void snd_pcm_mmap_clear(snd_pcm_t *pcm, int channel)
|
||||||
{
|
{
|
||||||
struct snd_pcm_chan *chan = &pcm->chan[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_io = 0;
|
||||||
chan->mmap_control->byte_data = 0;
|
chan->mmap_control->byte_data = 0;
|
||||||
}
|
}
|
||||||
|
|
@ -61,15 +59,6 @@ void snd_pcm_mmap_status_change(snd_pcm_t *pcm, int channel, int newstatus)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
static inline ssize_t snd_pcm_mmap_playback_bytes_used(struct snd_pcm_chan *chan)
|
||||||
{
|
{
|
||||||
ssize_t bytes_used;
|
ssize_t bytes_used;
|
||||||
|
|
@ -81,24 +70,9 @@ static inline ssize_t snd_pcm_mmap_playback_bytes_used(struct snd_pcm_chan *chan
|
||||||
|
|
||||||
static ssize_t snd_pcm_mmap_playback_samples_used(snd_pcm_t *pcm)
|
static ssize_t snd_pcm_mmap_playback_samples_used(snd_pcm_t *pcm)
|
||||||
{
|
{
|
||||||
struct snd_pcm_chan *chan;
|
struct snd_pcm_chan *chan = &pcm->chan[SND_PCM_CHANNEL_PLAYBACK];
|
||||||
chan = &pcm->chan[SND_PCM_CHANNEL_PLAYBACK];
|
ssize_t bytes = snd_pcm_mmap_playback_bytes_used(chan);
|
||||||
if (chan->setup.mode == SND_PCM_MODE_BLOCK) {
|
return bytes * 8 / chan->bits_per_sample;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline size_t snd_pcm_mmap_capture_bytes_used(struct snd_pcm_chan *chan)
|
static inline size_t snd_pcm_mmap_capture_bytes_used(struct snd_pcm_chan *chan)
|
||||||
|
|
@ -112,15 +86,9 @@ 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)
|
static size_t snd_pcm_mmap_capture_samples_used(snd_pcm_t *pcm)
|
||||||
{
|
{
|
||||||
struct snd_pcm_chan *chan;
|
struct snd_pcm_chan *chan = &pcm->chan[SND_PCM_CHANNEL_CAPTURE];
|
||||||
chan = &pcm->chan[SND_PCM_CHANNEL_CAPTURE];
|
size_t bytes = snd_pcm_mmap_capture_bytes_used(chan);
|
||||||
if (chan->setup.mode == SND_PCM_MODE_BLOCK) {
|
return bytes * 8 / chan->bits_per_sample;
|
||||||
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_samples_used(snd_pcm_t *pcm, int channel, ssize_t *samples)
|
int snd_pcm_mmap_samples_used(snd_pcm_t *pcm, int channel, ssize_t *samples)
|
||||||
|
|
@ -140,11 +108,6 @@ int snd_pcm_mmap_samples_used(snd_pcm_t *pcm, int channel, ssize_t *samples)
|
||||||
return 0;
|
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)
|
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);
|
return chan->setup.buffer_size - snd_pcm_mmap_playback_bytes_used(chan);
|
||||||
|
|
@ -152,23 +115,11 @@ static inline size_t snd_pcm_mmap_playback_bytes_free(struct snd_pcm_chan *chan)
|
||||||
|
|
||||||
static size_t snd_pcm_mmap_playback_samples_free(snd_pcm_t *pcm)
|
static size_t snd_pcm_mmap_playback_samples_free(snd_pcm_t *pcm)
|
||||||
{
|
{
|
||||||
struct snd_pcm_chan *chan;
|
struct snd_pcm_chan *chan = &pcm->chan[SND_PCM_CHANNEL_PLAYBACK];
|
||||||
chan = &pcm->chan[SND_PCM_CHANNEL_PLAYBACK];
|
size_t bytes = snd_pcm_mmap_playback_bytes_free(chan);
|
||||||
if (chan->setup.mode == SND_PCM_MODE_BLOCK) {
|
return bytes * 8 / chan->bits_per_sample;
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static inline ssize_t snd_pcm_mmap_capture_bytes_free(struct snd_pcm_chan *chan)
|
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);
|
return chan->setup.buffer_size - snd_pcm_mmap_capture_bytes_used(chan);
|
||||||
|
|
@ -176,15 +127,9 @@ static inline ssize_t snd_pcm_mmap_capture_bytes_free(struct snd_pcm_chan *chan)
|
||||||
|
|
||||||
static ssize_t snd_pcm_mmap_capture_samples_free(snd_pcm_t *pcm)
|
static ssize_t snd_pcm_mmap_capture_samples_free(snd_pcm_t *pcm)
|
||||||
{
|
{
|
||||||
struct snd_pcm_chan *chan;
|
struct snd_pcm_chan *chan = &pcm->chan[SND_PCM_CHANNEL_CAPTURE];
|
||||||
chan = &pcm->chan[SND_PCM_CHANNEL_CAPTURE];
|
ssize_t bytes = snd_pcm_mmap_capture_bytes_free(chan);
|
||||||
if (chan->setup.mode == SND_PCM_MODE_BLOCK) {
|
return bytes * 8 / chan->bits_per_sample;
|
||||||
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_samples_free(snd_pcm_t *pcm, int channel, ssize_t *samples)
|
int snd_pcm_mmap_samples_free(snd_pcm_t *pcm, int channel, ssize_t *samples)
|
||||||
|
|
@ -210,11 +155,7 @@ static int snd_pcm_mmap_playback_ready(snd_pcm_t *pcm)
|
||||||
chan = &pcm->chan[SND_PCM_CHANNEL_PLAYBACK];
|
chan = &pcm->chan[SND_PCM_CHANNEL_PLAYBACK];
|
||||||
if (chan->mmap_control->status == SND_PCM_STATUS_XRUN)
|
if (chan->mmap_control->status == SND_PCM_STATUS_XRUN)
|
||||||
return -EPIPE;
|
return -EPIPE;
|
||||||
if (chan->setup.mode == SND_PCM_MODE_BLOCK) {
|
return (chan->setup.buffer_size - snd_pcm_mmap_playback_bytes_used(chan)) >= chan->setup.bytes_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(chan)) >= chan->setup.buf.stream.bytes_min;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int snd_pcm_mmap_capture_ready(snd_pcm_t *pcm)
|
static int snd_pcm_mmap_capture_ready(snd_pcm_t *pcm)
|
||||||
|
|
@ -227,13 +168,8 @@ static int snd_pcm_mmap_capture_ready(snd_pcm_t *pcm)
|
||||||
if (chan->setup.xrun_mode == SND_PCM_XRUN_DRAIN)
|
if (chan->setup.xrun_mode == SND_PCM_XRUN_DRAIN)
|
||||||
return -EPIPE;
|
return -EPIPE;
|
||||||
}
|
}
|
||||||
if (chan->setup.mode == SND_PCM_MODE_BLOCK) {
|
if (snd_pcm_mmap_capture_bytes_used(chan) >= chan->setup.bytes_min)
|
||||||
if (snd_pcm_mmap_capture_frags_used(chan) >= chan->setup.buf.block.frags_min)
|
return 1;
|
||||||
return 1;
|
|
||||||
} else {
|
|
||||||
if (snd_pcm_mmap_capture_bytes_used(chan) >= chan->setup.buf.stream.bytes_min)
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -258,36 +194,6 @@ int snd_pcm_mmap_ready(snd_pcm_t *pcm, int channel)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
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];
|
struct snd_pcm_chan *chan = &pcm->chan[SND_PCM_CHANNEL_PLAYBACK];
|
||||||
|
|
@ -300,7 +206,7 @@ static size_t snd_pcm_mmap_playback_bytes_xfer(snd_pcm_t *pcm, size_t bytes)
|
||||||
bytes_cont = chan->setup.buffer_size - (byte_data % chan->setup.buffer_size);
|
bytes_cont = chan->setup.buffer_size - (byte_data % chan->setup.buffer_size);
|
||||||
if (bytes_cont < bytes)
|
if (bytes_cont < bytes)
|
||||||
bytes = bytes_cont;
|
bytes = bytes_cont;
|
||||||
bytes -= bytes % chan->setup.buf.stream.bytes_align;
|
bytes -= bytes % chan->setup.bytes_align;
|
||||||
return bytes;
|
return bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -316,38 +222,24 @@ static size_t snd_pcm_mmap_capture_bytes_xfer(snd_pcm_t *pcm, size_t bytes)
|
||||||
bytes_cont = chan->setup.buffer_size - (byte_data % chan->setup.buffer_size);
|
bytes_cont = chan->setup.buffer_size - (byte_data % chan->setup.buffer_size);
|
||||||
if (bytes_cont < bytes)
|
if (bytes_cont < bytes)
|
||||||
bytes = bytes_cont;
|
bytes = bytes_cont;
|
||||||
bytes -= bytes % chan->setup.buf.stream.bytes_align;
|
bytes -= bytes % chan->setup.bytes_align;
|
||||||
return bytes;
|
return bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t snd_pcm_mmap_playback_samples_xfer(snd_pcm_t *pcm, size_t samples)
|
static ssize_t snd_pcm_mmap_playback_samples_xfer(snd_pcm_t *pcm, size_t samples)
|
||||||
{
|
{
|
||||||
struct snd_pcm_chan *chan;
|
struct snd_pcm_chan *chan = &pcm->chan[SND_PCM_CHANNEL_PLAYBACK];
|
||||||
chan = &pcm->chan[SND_PCM_CHANNEL_PLAYBACK];
|
size_t bytes = samples * chan->bits_per_sample / 8;
|
||||||
if (chan->setup.mode == SND_PCM_MODE_BLOCK) {
|
bytes = snd_pcm_mmap_playback_bytes_xfer(pcm, bytes);
|
||||||
size_t frags = samples / chan->samples_per_frag;
|
return bytes * 8 / chan->bits_per_sample;
|
||||||
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)
|
static ssize_t snd_pcm_mmap_capture_samples_xfer(snd_pcm_t *pcm, size_t samples)
|
||||||
{
|
{
|
||||||
struct snd_pcm_chan *chan;
|
struct snd_pcm_chan *chan = &pcm->chan[SND_PCM_CHANNEL_CAPTURE];
|
||||||
chan = &pcm->chan[SND_PCM_CHANNEL_CAPTURE];
|
size_t bytes = samples * chan->bits_per_sample / 8;
|
||||||
if (chan->setup.mode == SND_PCM_MODE_BLOCK) {
|
bytes = snd_pcm_mmap_capture_bytes_xfer(pcm, bytes);
|
||||||
size_t frags = samples / chan->samples_per_frag;
|
return bytes * 8 / chan->bits_per_sample;
|
||||||
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)
|
ssize_t snd_pcm_mmap_samples_xfer(snd_pcm_t *pcm, int channel, size_t samples)
|
||||||
|
|
@ -380,16 +272,14 @@ ssize_t snd_pcm_mmap_samples_offset(snd_pcm_t *pcm, int channel)
|
||||||
ctrl = chan->mmap_control;
|
ctrl = chan->mmap_control;
|
||||||
if (!ctrl)
|
if (!ctrl)
|
||||||
return -EBADFD;
|
return -EBADFD;
|
||||||
if (chan->setup.mode == SND_PCM_MODE_BLOCK)
|
return (ctrl->byte_data % chan->setup.buffer_size) * 8 / chan->bits_per_sample;
|
||||||
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)
|
int snd_pcm_mmap_commit_samples(snd_pcm_t *pcm, int channel, int samples)
|
||||||
{
|
{
|
||||||
struct snd_pcm_chan *chan;
|
struct snd_pcm_chan *chan;
|
||||||
snd_pcm_mmap_control_t *ctrl;
|
snd_pcm_mmap_control_t *ctrl;
|
||||||
|
size_t byte_data, bytes;
|
||||||
if (!pcm)
|
if (!pcm)
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
if (channel < 0 || channel > 1)
|
if (channel < 0 || channel > 1)
|
||||||
|
|
@ -400,33 +290,15 @@ int snd_pcm_mmap_commit_samples(snd_pcm_t *pcm, int channel, int samples)
|
||||||
ctrl = chan->mmap_control;
|
ctrl = chan->mmap_control;
|
||||||
if (!ctrl)
|
if (!ctrl)
|
||||||
return -EBADFD;
|
return -EBADFD;
|
||||||
if (chan->setup.mode == SND_PCM_MODE_BLOCK) {
|
bytes = samples * chan->bits_per_sample;
|
||||||
size_t frag_data, frags;
|
if (bytes % 8)
|
||||||
if (samples % chan->samples_per_frag)
|
return -EINVAL;
|
||||||
return -EINVAL;
|
bytes /= 8;
|
||||||
frags = samples / chan->samples_per_frag;
|
byte_data = ctrl->byte_data + bytes;
|
||||||
frag_data = ctrl->frag_data + frags;
|
if (byte_data == chan->setup.byte_boundary) {
|
||||||
if (frag_data == chan->setup.frag_boundary) {
|
ctrl->byte_data = 0;
|
||||||
ctrl->frag_data = 0;
|
|
||||||
ctrl->byte_data = 0;
|
|
||||||
} else {
|
|
||||||
ctrl->frag_data = frag_data;
|
|
||||||
ctrl->byte_data = frag_data * chan->setup.frag_size;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
size_t byte_data;
|
ctrl->byte_data = 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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -788,26 +660,48 @@ ssize_t snd_pcm_mmap_readv(snd_pcm_t *pcm, const struct iovec *vector, unsigned
|
||||||
return result * chan->bits_per_sample / 8;
|
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)
|
static void *playback_mmap(void *d)
|
||||||
{
|
{
|
||||||
snd_pcm_t *pcm = d;
|
snd_pcm_t *pcm = d;
|
||||||
struct snd_pcm_chan *chan = &pcm->chan[SND_PCM_CHANNEL_PLAYBACK];
|
struct snd_pcm_chan *chan = &pcm->chan[SND_PCM_CHANNEL_PLAYBACK];
|
||||||
snd_pcm_mmap_control_t *control;
|
snd_pcm_mmap_control_t *control;
|
||||||
char *data;
|
char *data;
|
||||||
int frags;
|
size_t voice_size;
|
||||||
int frag_size, voice_size, voice_frag_size;
|
|
||||||
int voices;
|
int voices;
|
||||||
control = chan->mmap_control;
|
control = chan->mmap_control;
|
||||||
data = chan->mmap_data;
|
data = chan->mmap_data;
|
||||||
frags = chan->setup.frags;
|
|
||||||
frag_size = chan->setup.frag_size;
|
|
||||||
voices = chan->setup.format.voices;
|
voices = chan->setup.format.voices;
|
||||||
voice_size = chan->mmap_data_size / voices;
|
voice_size = chan->mmap_data_size / voices;
|
||||||
voice_frag_size = voice_size / frags;
|
|
||||||
while (1) {
|
while (1) {
|
||||||
int err;
|
int err;
|
||||||
struct pollfd pfd;
|
struct pollfd pfd;
|
||||||
unsigned int f, frag;
|
size_t pos, p, bytes;
|
||||||
if (chan->mmap_thread_stop)
|
if (chan->mmap_thread_stop)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
@ -832,25 +726,28 @@ static void *playback_mmap(void *d)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
frag = control->frag_io;
|
pos = control->byte_io;
|
||||||
if (snd_pcm_mmap_playback_frags_used(chan) <= 0) {
|
bytes = mmap_playback_bytes_xfer(chan);
|
||||||
|
if (bytes <= 0) {
|
||||||
fprintf(stderr, "underrun\n");
|
fprintf(stderr, "underrun\n");
|
||||||
usleep(10000);
|
usleep(10000);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
f = frag % frags;
|
p = pos % chan->setup.buffer_size;
|
||||||
if (chan->setup.format.interleave) {
|
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 {
|
} else {
|
||||||
struct iovec vector[voices];
|
struct iovec vector[voices];
|
||||||
struct iovec *v = vector;
|
struct iovec *v = vector;
|
||||||
int voice;
|
int voice;
|
||||||
|
size_t size = bytes / voices;
|
||||||
|
size_t posv = p / voices;
|
||||||
for (voice = 0; voice < voices; ++voice) {
|
for (voice = 0; voice < voices; ++voice) {
|
||||||
v->iov_base = data + voice_size * voice + f * voice_frag_size;
|
v->iov_base = data + voice_size * voice + posv;
|
||||||
v->iov_len = voice_frag_size;
|
v->iov_len = size;
|
||||||
v++;
|
v++;
|
||||||
}
|
}
|
||||||
err = snd_pcm_writev(pcm, vector, voice_frag_size);
|
err = snd_pcm_writev(pcm, vector, voices);
|
||||||
}
|
}
|
||||||
if (err <= 0) {
|
if (err <= 0) {
|
||||||
fprintf(stderr, "write err=%d\n", err);
|
fprintf(stderr, "write err=%d\n", err);
|
||||||
|
|
@ -860,10 +757,10 @@ static void *playback_mmap(void *d)
|
||||||
pthread_mutex_lock(&chan->mutex);
|
pthread_mutex_lock(&chan->mutex);
|
||||||
pthread_cond_signal(&chan->ready_cond);
|
pthread_cond_signal(&chan->ready_cond);
|
||||||
pthread_mutex_unlock(&chan->mutex);
|
pthread_mutex_unlock(&chan->mutex);
|
||||||
frag++;
|
pos += bytes;
|
||||||
if (frag == chan->setup.frag_boundary)
|
if (pos == chan->setup.byte_boundary)
|
||||||
frag = 0;
|
pos = 0;
|
||||||
control->frag_io = frag;
|
control->byte_io = pos;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -887,7 +784,7 @@ static void *capture_mmap(void *d)
|
||||||
while (1) {
|
while (1) {
|
||||||
int err;
|
int err;
|
||||||
struct pollfd pfd;
|
struct pollfd pfd;
|
||||||
unsigned int f, frag;
|
size_t pos, p, bytes;
|
||||||
if (chan->mmap_thread_stop)
|
if (chan->mmap_thread_stop)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
@ -912,35 +809,41 @@ static void *capture_mmap(void *d)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
frag = control->frag_io;
|
pos = control->byte_io;
|
||||||
if (snd_pcm_mmap_capture_frags_free(chan) <= 0) {
|
bytes = mmap_capture_bytes_xfer(chan);
|
||||||
|
if (bytes <= 0) {
|
||||||
fprintf(stderr, "overrun\n");
|
fprintf(stderr, "overrun\n");
|
||||||
usleep(10000);
|
usleep(10000);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
f = frag % frags;
|
p = pos % chan->setup.buffer_size;
|
||||||
if (chan->setup.format.interleave) {
|
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 {
|
} else {
|
||||||
struct iovec vector[voices];
|
struct iovec vector[voices];
|
||||||
struct iovec *v = vector;
|
struct iovec *v = vector;
|
||||||
int voice;
|
int voice;
|
||||||
|
size_t size = bytes / voices;
|
||||||
|
size_t posv = p / voices;
|
||||||
for (voice = 0; voice < voices; ++voice) {
|
for (voice = 0; voice < voices; ++voice) {
|
||||||
v->iov_base = data + voice_size * voice + f * voice_frag_size;
|
v->iov_base = data + voice_size * voice + posv;
|
||||||
v->iov_len = voice_frag_size;
|
v->iov_len = size;
|
||||||
v++;
|
v++;
|
||||||
}
|
}
|
||||||
err = snd_pcm_readv(pcm, vector, voice_frag_size);
|
err = snd_pcm_readv(pcm, vector, voices);
|
||||||
}
|
}
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
fprintf(stderr, "read err=%d\n", err);
|
fprintf(stderr, "read err=%d\n", err);
|
||||||
snd_pcm_mmap_status_change(pcm, SND_PCM_CHANNEL_CAPTURE, -1);
|
snd_pcm_mmap_status_change(pcm, SND_PCM_CHANNEL_CAPTURE, -1);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
frag++;
|
pthread_mutex_lock(&chan->mutex);
|
||||||
if (frag == chan->setup.frag_boundary)
|
pthread_cond_signal(&chan->ready_cond);
|
||||||
frag = 0;
|
pthread_mutex_unlock(&chan->mutex);
|
||||||
control->frag_io = frag;
|
pos += bytes;
|
||||||
|
if (pos == chan->setup.byte_boundary)
|
||||||
|
pos = 0;
|
||||||
|
control->byte_io = pos;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -411,19 +411,12 @@ static int snd_pcm_plug_channel_params(snd_pcm_t *pcm, snd_pcm_channel_params_t
|
||||||
* I/O plugins
|
* I/O plugins
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (params->mode == SND_PCM_MODE_STREAM) {
|
if (slave_info.flags & SND_PCM_CHNINFO_MMAP) {
|
||||||
pdprintf("params stream plugin\n");
|
pdprintf("params mmap plugin\n");
|
||||||
err = snd_pcm_plugin_build_stream(pcm, channel, plug->slave, &slave_params.format, &plugin);
|
err = snd_pcm_plugin_build_mmap(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);
|
|
||||||
}
|
|
||||||
} else {
|
} 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)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
|
|
@ -440,13 +433,11 @@ static int snd_pcm_plug_channel_params(snd_pcm_t *pcm, snd_pcm_channel_params_t
|
||||||
/* compute right sizes */
|
/* compute right sizes */
|
||||||
slave_params.buffer_size = snd_pcm_plug_slave_size(pcm, channel, slave_params.buffer_size);
|
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);
|
slave_params.frag_size = snd_pcm_plug_slave_size(pcm, channel, slave_params.frag_size);
|
||||||
if (params->mode == SND_PCM_MODE_STREAM) {
|
slave_params.bytes_fill_max = snd_pcm_plug_slave_size(pcm, channel, slave_params.bytes_fill_max);
|
||||||
slave_params.buf.stream.bytes_fill_max = snd_pcm_plug_slave_size(pcm, channel, slave_params.buf.stream.bytes_fill_max);
|
slave_params.bytes_min = snd_pcm_plug_slave_size(pcm, channel, slave_params.bytes_min);
|
||||||
slave_params.buf.stream.bytes_min = snd_pcm_plug_slave_size(pcm, channel, slave_params.buf.stream.bytes_min);
|
slave_params.bytes_xrun_max = snd_pcm_plug_slave_size(pcm, channel, slave_params.bytes_xrun_max);
|
||||||
slave_params.buf.stream.bytes_xrun_max = snd_pcm_plug_slave_size(pcm, channel, slave_params.buf.stream.bytes_xrun_max);
|
slave_params.bytes_align = snd_pcm_plug_slave_size(pcm, channel, slave_params.bytes_align);
|
||||||
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;
|
|
||||||
pdprintf("params requested params: format = %i, rate = %i, voices = %i\n", slave_params.format.format, slave_params.format.rate, slave_params.format.voices);
|
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);
|
err = snd_pcm_channel_params(plug->slave, &slave_params);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
|
|
@ -469,17 +460,14 @@ static int snd_pcm_plug_channel_setup(snd_pcm_t *pcm, snd_pcm_channel_setup_t *s
|
||||||
return err;
|
return err;
|
||||||
if (snd_pcm_plug_direct(pcm, setup->channel))
|
if (snd_pcm_plug_direct(pcm, setup->channel))
|
||||||
return 0;
|
return 0;
|
||||||
|
setup->byte_boundary /= setup->frag_size;
|
||||||
setup->frag_size = snd_pcm_plug_client_size(pcm, setup->channel, 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->buffer_size = setup->frags * setup->frag_size;
|
||||||
setup->byte_boundary = setup->frag_boundary * setup->frag_size;
|
setup->bytes_min = snd_pcm_plug_client_size(pcm, setup->channel, setup->bytes_min);
|
||||||
if (setup->mode == SND_PCM_MODE_STREAM) {
|
setup->bytes_align = snd_pcm_plug_client_size(pcm, setup->channel, setup->bytes_align);
|
||||||
setup->buf.stream.bytes_min = snd_pcm_plug_client_size(pcm, setup->channel, setup->buf.stream.bytes_min);
|
setup->bytes_xrun_max = snd_pcm_plug_client_size(pcm, setup->channel, setup->bytes_xrun_max);
|
||||||
setup->buf.stream.bytes_align = snd_pcm_plug_client_size(pcm, setup->channel, setup->buf.stream.bytes_align);
|
setup->bytes_fill_max = snd_pcm_plug_client_size(pcm, setup->channel, setup->bytes_fill_max);
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
plugchan = &plug->chan[setup->channel];
|
plugchan = &plug->chan[setup->channel];
|
||||||
if (setup->channel == SND_PCM_CHANNEL_PLAYBACK)
|
if (setup->channel == SND_PCM_CHANNEL_PLAYBACK)
|
||||||
|
|
@ -504,7 +492,6 @@ static int snd_pcm_plug_channel_status(snd_pcm_t *pcm, snd_pcm_channel_status_t
|
||||||
status->byte_io = snd_pcm_plug_client_size(pcm, status->channel, status->byte_io);
|
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->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_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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
EXTRA_LTLIBRARIES = libpcmplugin.la
|
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
|
mulaw.c alaw.c adpcm.c rate.c route.c
|
||||||
all: libpcmplugin.la
|
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>
|
* Copyright (c) 1999 by Jaroslav Kysela <perex@suse.cz>
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
|
|
@ -38,26 +38,26 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Basic block plugin
|
* Basic io plugin
|
||||||
*/
|
*/
|
||||||
|
|
||||||
typedef struct block_private_data {
|
typedef struct io_private_data {
|
||||||
snd_pcm_plugin_handle_t *slave;
|
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,
|
const snd_pcm_plugin_voice_t *src_voices,
|
||||||
snd_pcm_plugin_voice_t *dst_voices,
|
snd_pcm_plugin_voice_t *dst_voices,
|
||||||
size_t samples)
|
size_t samples)
|
||||||
{
|
{
|
||||||
block_t *data;
|
io_t *data;
|
||||||
ssize_t result;
|
ssize_t result;
|
||||||
struct iovec *vec;
|
struct iovec *vec;
|
||||||
int count, voice;
|
int count, voice;
|
||||||
|
|
||||||
if (plugin == NULL)
|
if (plugin == NULL)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
data = (block_t *)plugin->extra_data;
|
data = (io_t *)plugin->extra_data;
|
||||||
if (data == NULL)
|
if (data == NULL)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
vec = (struct iovec *)((char *)data + sizeof(*data));
|
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,
|
size_t samples,
|
||||||
snd_pcm_plugin_voice_t **voices)
|
snd_pcm_plugin_voice_t **voices)
|
||||||
{
|
{
|
||||||
|
|
@ -130,14 +130,14 @@ static int block_src_voices(snd_pcm_plugin_t *plugin,
|
||||||
return 0;
|
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,
|
int channel,
|
||||||
snd_pcm_plugin_handle_t *slave,
|
snd_pcm_plugin_handle_t *slave,
|
||||||
snd_pcm_format_t *format,
|
snd_pcm_format_t *format,
|
||||||
snd_pcm_plugin_t **r_plugin)
|
snd_pcm_plugin_t **r_plugin)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
block_t *data;
|
io_t *data;
|
||||||
snd_pcm_plugin_t *plugin;
|
snd_pcm_plugin_t *plugin;
|
||||||
|
|
||||||
if (r_plugin == NULL)
|
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)
|
if (pcm == NULL || format == NULL)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
err = snd_pcm_plugin_build(pcm, channel,
|
err = snd_pcm_plugin_build(pcm, channel,
|
||||||
"I/O block",
|
"I/O io",
|
||||||
format, format,
|
format, format,
|
||||||
sizeof(block_t) + sizeof(struct iovec) * format->voices,
|
sizeof(io_t) + sizeof(struct iovec) * format->voices,
|
||||||
&plugin);
|
&plugin);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
data = (block_t *)plugin->extra_data;
|
data = (io_t *)plugin->extra_data;
|
||||||
data->slave = slave;
|
data->slave = slave;
|
||||||
plugin->transfer = block_transfer;
|
plugin->transfer = io_transfer;
|
||||||
if (format->interleave && channel == SND_PCM_CHANNEL_PLAYBACK)
|
if (format->interleave && channel == SND_PCM_CHANNEL_PLAYBACK)
|
||||||
plugin->client_voices = block_src_voices;
|
plugin->client_voices = io_src_voices;
|
||||||
*r_plugin = plugin;
|
*r_plugin = plugin;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -37,32 +37,31 @@ typedef struct mmap_private_data {
|
||||||
snd_pcm_t *slave;
|
snd_pcm_t *slave;
|
||||||
snd_pcm_mmap_control_t *control;
|
snd_pcm_mmap_control_t *control;
|
||||||
void *buffer;
|
void *buffer;
|
||||||
unsigned int frag;
|
#if 0
|
||||||
char *silence;
|
char *silence;
|
||||||
|
#endif
|
||||||
} mmap_t;
|
} mmap_t;
|
||||||
|
|
||||||
|
|
||||||
static int mmap_src_voices(snd_pcm_plugin_t *plugin,
|
static ssize_t mmap_src_voices(snd_pcm_plugin_t *plugin,
|
||||||
size_t samples,
|
size_t samples,
|
||||||
snd_pcm_plugin_voice_t **voices)
|
snd_pcm_plugin_voice_t **voices)
|
||||||
{
|
{
|
||||||
mmap_t *data;
|
mmap_t *data;
|
||||||
unsigned int voice;
|
|
||||||
snd_pcm_plugin_voice_t *sv;
|
snd_pcm_plugin_voice_t *sv;
|
||||||
snd_pcm_voice_area_t *dv;
|
snd_pcm_voice_area_t *dv;
|
||||||
struct snd_pcm_chan *chan;
|
struct snd_pcm_chan *chan;
|
||||||
snd_pcm_channel_setup_t *setup;
|
snd_pcm_channel_setup_t *setup;
|
||||||
snd_pcm_mmap_control_t *ctrl;
|
snd_pcm_mmap_control_t *ctrl;
|
||||||
int frag, f;
|
size_t pos;
|
||||||
int ready;
|
int ready;
|
||||||
|
unsigned int voice;
|
||||||
|
|
||||||
if (plugin == NULL || voices == NULL)
|
if (plugin == NULL || voices == NULL)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
data = (mmap_t *)plugin->extra_data;
|
data = (mmap_t *)plugin->extra_data;
|
||||||
ctrl = data->control;
|
ctrl = data->control;
|
||||||
chan = &data->slave->chan[plugin->channel];
|
chan = &data->slave->chan[plugin->channel];
|
||||||
if (samples != chan->samples_per_frag)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
setup = &chan->setup;
|
setup = &chan->setup;
|
||||||
if (ctrl->status < SND_PCM_STATUS_PREPARED)
|
if (ctrl->status < SND_PCM_STATUS_PREPARED)
|
||||||
|
|
@ -86,29 +85,34 @@ static int mmap_src_voices(snd_pcm_plugin_t *plugin,
|
||||||
return -EPIPE;
|
return -EPIPE;
|
||||||
assert(snd_pcm_mmap_ready(data->slave, plugin->channel));
|
assert(snd_pcm_mmap_ready(data->slave, plugin->channel));
|
||||||
}
|
}
|
||||||
frag = ctrl->frag_data;
|
pos = ctrl->byte_data % setup->buffer_size;
|
||||||
f = frag % setup->frags;
|
if ((pos * 8) % chan->bits_per_sample != 0)
|
||||||
|
return -EINVAL;
|
||||||
|
pos = (pos * 8) / chan->bits_per_sample;
|
||||||
|
|
||||||
sv = plugin->src_voices;
|
sv = plugin->src_voices;
|
||||||
dv = chan->voices;
|
dv = chan->voices;
|
||||||
*voices = sv;
|
*voices = sv;
|
||||||
for (voice = 0; voice < plugin->src_format.voices; ++voice) {
|
for (voice = 0; voice < plugin->src_format.voices; ++voice) {
|
||||||
sv->enabled = 1;
|
sv->enabled = 1;
|
||||||
|
#if 0
|
||||||
sv->wanted = !data->silence[voice * setup->frags + f];
|
sv->wanted = !data->silence[voice * setup->frags + f];
|
||||||
|
#else
|
||||||
|
sv->wanted = 1;
|
||||||
|
#endif
|
||||||
sv->aptr = 0;
|
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.first = dv->first;
|
||||||
sv->area.step = dv->step;
|
sv->area.step = dv->step;
|
||||||
++sv;
|
++sv;
|
||||||
++dv;
|
++dv;
|
||||||
}
|
}
|
||||||
data->frag = frag;
|
return snd_pcm_mmap_samples_xfer(data->slave, plugin->channel, samples);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mmap_dst_voices(snd_pcm_plugin_t *plugin,
|
static ssize_t mmap_dst_voices(snd_pcm_plugin_t *plugin,
|
||||||
size_t samples,
|
size_t samples,
|
||||||
snd_pcm_plugin_voice_t **voices)
|
snd_pcm_plugin_voice_t **voices)
|
||||||
{
|
{
|
||||||
mmap_t *data;
|
mmap_t *data;
|
||||||
int err;
|
int err;
|
||||||
|
|
@ -118,15 +122,13 @@ static int mmap_dst_voices(snd_pcm_plugin_t *plugin,
|
||||||
struct snd_pcm_chan *chan;
|
struct snd_pcm_chan *chan;
|
||||||
snd_pcm_channel_setup_t *setup;
|
snd_pcm_channel_setup_t *setup;
|
||||||
snd_pcm_mmap_control_t *ctrl;
|
snd_pcm_mmap_control_t *ctrl;
|
||||||
int frag, f;
|
size_t pos;
|
||||||
int ready;
|
int ready;
|
||||||
|
|
||||||
if (plugin == NULL || voices == NULL)
|
if (plugin == NULL || voices == NULL)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
data = (mmap_t *)plugin->extra_data;
|
data = (mmap_t *)plugin->extra_data;
|
||||||
chan = &data->slave->chan[plugin->channel];
|
chan = &data->slave->chan[plugin->channel];
|
||||||
if (samples != chan->samples_per_frag)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
setup = &chan->setup;
|
setup = &chan->setup;
|
||||||
ctrl = data->control;
|
ctrl = data->control;
|
||||||
|
|
@ -156,9 +158,10 @@ static int mmap_dst_voices(snd_pcm_plugin_t *plugin,
|
||||||
return -EPIPE;
|
return -EPIPE;
|
||||||
assert(snd_pcm_mmap_ready(data->slave, plugin->channel));
|
assert(snd_pcm_mmap_ready(data->slave, plugin->channel));
|
||||||
}
|
}
|
||||||
|
pos = ctrl->byte_data % setup->buffer_size;
|
||||||
frag = ctrl->frag_data;
|
if ((pos * 8) % chan->bits_per_sample != 0)
|
||||||
f = frag % setup->frags;
|
return -EINVAL;
|
||||||
|
pos = (pos * 8) / chan->bits_per_sample;
|
||||||
|
|
||||||
sv = chan->voices;
|
sv = chan->voices;
|
||||||
dv = plugin->dst_voices;
|
dv = plugin->dst_voices;
|
||||||
|
|
@ -167,14 +170,13 @@ static int mmap_dst_voices(snd_pcm_plugin_t *plugin,
|
||||||
dv->enabled = 1;
|
dv->enabled = 1;
|
||||||
dv->wanted = 0;
|
dv->wanted = 0;
|
||||||
dv->aptr = 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.first = sv->first;
|
||||||
dv->area.step = sv->step;
|
dv->area.step = sv->step;
|
||||||
++sv;
|
++sv;
|
||||||
++dv;
|
++dv;
|
||||||
}
|
}
|
||||||
data->frag = frag;
|
return snd_pcm_mmap_samples_xfer(data->slave, plugin->channel, samples);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t mmap_playback_transfer(snd_pcm_plugin_t *plugin,
|
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)
|
size_t samples)
|
||||||
{
|
{
|
||||||
mmap_t *data;
|
mmap_t *data;
|
||||||
unsigned int voice;
|
|
||||||
snd_pcm_channel_setup_t *setup;
|
snd_pcm_channel_setup_t *setup;
|
||||||
snd_pcm_mmap_control_t *ctrl;
|
snd_pcm_mmap_control_t *ctrl;
|
||||||
struct snd_pcm_chan *chan;
|
struct snd_pcm_chan *chan;
|
||||||
unsigned int frag, f;
|
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if (plugin == NULL)
|
if (plugin == NULL)
|
||||||
|
|
@ -202,15 +202,13 @@ static ssize_t mmap_playback_transfer(snd_pcm_plugin_t *plugin,
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
chan = &data->slave->chan[SND_PCM_CHANNEL_PLAYBACK];
|
chan = &data->slave->chan[SND_PCM_CHANNEL_PLAYBACK];
|
||||||
setup = &chan->setup;
|
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++) {
|
for (voice = 0; voice < plugin->src_format.voices; voice++) {
|
||||||
if (src_voices[voice].enabled)
|
if (src_voices[voice].enabled)
|
||||||
data->silence[voice * setup->frags + f] = 0;
|
data->silence[voice * setup->frags + f] = 0;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
snd_pcm_mmap_commit_samples(data->slave, SND_PCM_CHANNEL_PLAYBACK, samples);
|
snd_pcm_mmap_commit_samples(data->slave, SND_PCM_CHANNEL_PLAYBACK, samples);
|
||||||
if (ctrl->status == SND_PCM_STATUS_PREPARED &&
|
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;
|
mmap_t *data;
|
||||||
snd_pcm_channel_setup_t *setup;
|
snd_pcm_channel_setup_t *setup;
|
||||||
snd_pcm_mmap_control_t *ctrl;
|
snd_pcm_mmap_control_t *ctrl;
|
||||||
unsigned int frag;
|
|
||||||
|
|
||||||
if (plugin == NULL)
|
if (plugin == NULL)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
@ -243,9 +240,6 @@ static ssize_t mmap_capture_transfer(snd_pcm_plugin_t *plugin,
|
||||||
ctrl = data->control;
|
ctrl = data->control;
|
||||||
if (ctrl == NULL)
|
if (ctrl == NULL)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
frag = ctrl->frag_data;
|
|
||||||
if (frag != data->frag)
|
|
||||||
return -EIO;
|
|
||||||
setup = &data->slave->chan[SND_PCM_CHANNEL_CAPTURE].setup;
|
setup = &data->slave->chan[SND_PCM_CHANNEL_CAPTURE].setup;
|
||||||
|
|
||||||
/* FIXME: not here the increment */
|
/* FIXME: not here the increment */
|
||||||
|
|
@ -273,11 +267,13 @@ static int mmap_action(snd_pcm_plugin_t *plugin,
|
||||||
return result;
|
return result;
|
||||||
setup = &data->slave->chan[plugin->channel].setup;
|
setup = &data->slave->chan[plugin->channel].setup;
|
||||||
|
|
||||||
|
#if 0
|
||||||
if (plugin->channel == SND_PCM_CHANNEL_PLAYBACK) {
|
if (plugin->channel == SND_PCM_CHANNEL_PLAYBACK) {
|
||||||
data->silence = malloc(setup->frags * setup->format.voices);
|
data->silence = malloc(setup->frags * setup->format.voices);
|
||||||
memset(data->silence, 0, setup->frags * setup->format.voices);
|
memset(data->silence, 0, setup->frags * setup->format.voices);
|
||||||
} else
|
} else
|
||||||
data->silence = 0;
|
data->silence = 0;
|
||||||
|
#endif
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return 0; /* silenty ignore other actions */
|
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)
|
if (plugin == NULL)
|
||||||
return;
|
return;
|
||||||
data = (mmap_t *)plugin->extra_data;
|
data = (mmap_t *)plugin->extra_data;
|
||||||
|
#if 0
|
||||||
if (data->silence)
|
if (data->silence)
|
||||||
free(data->silence);
|
free(data->silence);
|
||||||
|
#endif
|
||||||
if (data->control)
|
if (data->control)
|
||||||
snd_pcm_munmap(data->slave, plugin->channel);
|
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