diff options
-rw-r--r-- | src/Makefile.am | 2 | ||||
-rw-r--r-- | src/pcm/pcm.c | 145 | ||||
-rw-r--r-- | src/pcm/pcm_local.h | 42 | ||||
-rw-r--r-- | src/pcm/pcm_plugin.c | 661 | ||||
-rw-r--r-- | src/pcm/plugin/mmap.c | 14 |
5 files changed, 592 insertions, 272 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 652f5de2..e7d085e9 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -6,7 +6,7 @@ libasound_la_SOURCES = error.c libasound_la_LIBADD = control/libcontrol.la mixer/libmixer.la pcm/libpcm.la \ rawmidi/librawmidi.la timer/libtimer.la hwdep/libhwdep.la \ seq/libseq.la instr/libinstr.la -libasound_la_LDFLAGS = -version-info $(COMPATNUM) +libasound_la_LDFLAGS = -version-info $(COMPATNUM) -lpthread control/libcontrol.la: $(MAKE) -C control libcontrol.la diff --git a/src/pcm/pcm.c b/src/pcm/pcm.c index 8f7e1e97..9754783e 100644 --- a/src/pcm/pcm.c +++ b/src/pcm/pcm.c @@ -139,8 +139,8 @@ int snd_pcm_open_subdevice(snd_pcm_t **handle, int card, int device, int subdevi } pcm->card = card; pcm->device = device; - pcm->fd[SND_PCM_CHANNEL_PLAYBACK] = pfd; - pcm->fd[SND_PCM_CHANNEL_CAPTURE] = cfd; + pcm->chan[SND_PCM_CHANNEL_PLAYBACK].fd = pfd; + pcm->chan[SND_PCM_CHANNEL_CAPTURE].fd = cfd; pcm->mode = mode; pcm->ver = ver; *handle = pcm; @@ -155,10 +155,11 @@ int snd_pcm_close(snd_pcm_t *pcm) if (!pcm) return -EINVAL; for (channel = 0; channel < 2; ++channel) { - snd_pcm_munmap(pcm, channel); + snd_pcm_plugin_munmap(pcm, channel); snd_pcm_plugin_clear(pcm, channel); - if (pcm->fd[channel] >= 0) - if (close(pcm->fd[channel])) + snd_pcm_munmap(pcm, channel); + if (pcm->chan[channel].fd >= 0) + if (close(pcm->chan[channel].fd)) res = -errno; } free(pcm); @@ -171,7 +172,7 @@ int snd_pcm_file_descriptor(snd_pcm_t *pcm, int channel) return -EINVAL; if (channel < 0 || channel > 1) return -EINVAL; - return pcm->fd[channel]; + return pcm->chan[channel].fd; } int snd_pcm_nonblock_mode(snd_pcm_t *pcm, int nonblock) @@ -182,7 +183,7 @@ int snd_pcm_nonblock_mode(snd_pcm_t *pcm, int nonblock) if (!pcm) return -EINVAL; for (channel = 0; channel < 2; ++channel) { - fd = pcm->fd[channel]; + fd = pcm->chan[channel].fd; if (fd < 0) continue; if ((flags = fcntl(fd, F_GETFL)) < 0) @@ -207,7 +208,7 @@ int snd_pcm_info(snd_pcm_t *pcm, snd_pcm_info_t * info) if (!pcm || !info) return -EINVAL; for (channel = 0; channel < 2; ++channel) { - fd = pcm->fd[channel]; + fd = pcm->chan[channel].fd; if (fd >= 0) break; } @@ -223,7 +224,7 @@ int snd_pcm_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t * info) return -EINVAL; if (info->channel < 0 || info->channel > 1) return -EINVAL; - fd = pcm->fd[info->channel]; + fd = pcm->chan[info->channel].fd; if (fd < 0) return -EINVAL; if (ioctl(fd, SND_PCM_IOCTL_CHANNEL_INFO, info) < 0) @@ -235,43 +236,47 @@ int snd_pcm_channel_params(snd_pcm_t *pcm, snd_pcm_channel_params_t * params) { int err; int fd; + struct snd_pcm_chan *chan; if (!pcm || !params) return -EINVAL; if (params->channel < 0 || params->channel > 1) return -EINVAL; - fd = pcm->fd[params->channel]; + chan = &pcm->chan[params->channel]; + fd = chan->fd; if (fd < 0) return -EINVAL; if (ioctl(fd, SND_PCM_IOCTL_CHANNEL_PARAMS, params) < 0) return -errno; - pcm->setup_is_valid[params->channel] = 0; - memset(&pcm->setup[params->channel], 0, sizeof(snd_pcm_channel_setup_t)); - pcm->setup[params->channel].channel = params->channel; - if ((err = snd_pcm_channel_setup(pcm, &pcm->setup[params->channel]))<0) + chan->setup_is_valid = 0; + memset(&chan->setup, 0, sizeof(snd_pcm_channel_setup_t)); + chan->setup.channel = params->channel; + if ((err = snd_pcm_channel_setup(pcm, &chan->setup))<0) return err; - pcm->setup_is_valid[params->channel] = 1; return 0; } int snd_pcm_channel_setup(snd_pcm_t *pcm, snd_pcm_channel_setup_t * setup) { int fd; + struct snd_pcm_chan *chan; + if (!pcm || !setup) return -EINVAL; if (setup->channel < 0 || setup->channel > 1) return -EINVAL; - fd = pcm->fd[setup->channel]; + chan = &pcm->chan[setup->channel]; + fd = chan->fd; if (fd < 0) return -EINVAL; - if (pcm->setup_is_valid[setup->channel]) { - memcpy(setup, &pcm->setup[setup->channel], sizeof(*setup)); - } else { - if (ioctl(fd, SND_PCM_IOCTL_CHANNEL_SETUP, setup) < 0) - return -errno; - memcpy(&pcm->setup[setup->channel], setup, sizeof(*setup)); - pcm->setup_is_valid[setup->channel] = 1; + if (chan->setup_is_valid) { + memcpy(setup, &chan->setup, sizeof(*setup)); + return 0; } + if (ioctl(fd, SND_PCM_IOCTL_CHANNEL_SETUP, setup) < 0) + return -errno; + memcpy(&chan->setup, setup, sizeof(*setup)); + chan->setup_is_valid = 1; return 0; } @@ -282,7 +287,7 @@ int snd_pcm_voice_setup(snd_pcm_t *pcm, int channel, snd_pcm_voice_setup_t * set return -EINVAL; if (channel < 0 || channel > 1) return -EINVAL; - fd = pcm->fd[channel]; + fd = pcm->chan[channel].fd; if (fd < 0) return -EINVAL; if (ioctl(fd, SND_PCM_IOCTL_VOICE_SETUP, setup) < 0) @@ -295,7 +300,7 @@ int snd_pcm_channel_status(snd_pcm_t *pcm, snd_pcm_channel_status_t * status) int fd; if (!pcm || !status) return -EINVAL; - fd = pcm->fd[status->channel]; + fd = pcm->chan[status->channel].fd; if (fd < 0) return -EINVAL; if (ioctl(fd, SND_PCM_IOCTL_CHANNEL_STATUS, status) < 0) @@ -307,9 +312,9 @@ int snd_pcm_playback_prepare(snd_pcm_t *pcm) { if (!pcm) return -EINVAL; - if (pcm->fd[SND_PCM_CHANNEL_PLAYBACK] < 0) + if (pcm->chan[SND_PCM_CHANNEL_PLAYBACK].fd < 0) return -EINVAL; - if (ioctl(pcm->fd[SND_PCM_CHANNEL_PLAYBACK], SND_PCM_IOCTL_CHANNEL_PREPARE) < 0) + if (ioctl(pcm->chan[SND_PCM_CHANNEL_PLAYBACK].fd, SND_PCM_IOCTL_CHANNEL_PREPARE) < 0) return -errno; return 0; } @@ -318,9 +323,9 @@ int snd_pcm_capture_prepare(snd_pcm_t *pcm) { if (!pcm) return -EINVAL; - if (pcm->fd[SND_PCM_CHANNEL_CAPTURE] < 0) + if (pcm->chan[SND_PCM_CHANNEL_CAPTURE].fd < 0) return -EINVAL; - if (ioctl(pcm->fd[SND_PCM_CHANNEL_CAPTURE], SND_PCM_IOCTL_CHANNEL_PREPARE) < 0) + if (ioctl(pcm->chan[SND_PCM_CHANNEL_CAPTURE].fd, SND_PCM_IOCTL_CHANNEL_PREPARE) < 0) return -errno; return 0; } @@ -341,9 +346,9 @@ int snd_pcm_playback_go(snd_pcm_t *pcm) { if (!pcm) return -EINVAL; - if (pcm->fd[SND_PCM_CHANNEL_PLAYBACK] < 0) + if (pcm->chan[SND_PCM_CHANNEL_PLAYBACK].fd < 0) return -EINVAL; - if (ioctl(pcm->fd[SND_PCM_CHANNEL_PLAYBACK], SND_PCM_IOCTL_CHANNEL_GO) < 0) + if (ioctl(pcm->chan[SND_PCM_CHANNEL_PLAYBACK].fd, SND_PCM_IOCTL_CHANNEL_GO) < 0) return -errno; return 0; } @@ -352,9 +357,9 @@ int snd_pcm_capture_go(snd_pcm_t *pcm) { if (!pcm) return -EINVAL; - if (pcm->fd[SND_PCM_CHANNEL_CAPTURE] < 0) + if (pcm->chan[SND_PCM_CHANNEL_CAPTURE].fd < 0) return -EINVAL; - if (ioctl(pcm->fd[SND_PCM_CHANNEL_CAPTURE], SND_PCM_IOCTL_CHANNEL_GO) < 0) + if (ioctl(pcm->chan[SND_PCM_CHANNEL_CAPTURE].fd, SND_PCM_IOCTL_CHANNEL_GO) < 0) return -errno; return 0; } @@ -375,9 +380,9 @@ int snd_pcm_sync_go(snd_pcm_t *pcm, snd_pcm_sync_t *sync) { if (!pcm || !sync) return -EINVAL; - if (pcm->fd[SND_PCM_CHANNEL_PLAYBACK] < 0) + if (pcm->chan[SND_PCM_CHANNEL_PLAYBACK].fd < 0) return -EINVAL; - if (ioctl(pcm->fd[SND_PCM_CHANNEL_PLAYBACK], SND_PCM_IOCTL_SYNC_GO, sync) < 0) + if (ioctl(pcm->chan[SND_PCM_CHANNEL_PLAYBACK].fd, SND_PCM_IOCTL_SYNC_GO, sync) < 0) return -errno; return 0; } @@ -386,9 +391,9 @@ int snd_pcm_playback_drain(snd_pcm_t *pcm) { if (!pcm) return -EINVAL; - if (pcm->fd[SND_PCM_CHANNEL_PLAYBACK] < 0) + if (pcm->chan[SND_PCM_CHANNEL_PLAYBACK].fd < 0) return -EINVAL; - if (ioctl(pcm->fd[SND_PCM_CHANNEL_PLAYBACK], SND_PCM_IOCTL_CHANNEL_DRAIN) < 0) + if (ioctl(pcm->chan[SND_PCM_CHANNEL_PLAYBACK].fd, SND_PCM_IOCTL_CHANNEL_DRAIN) < 0) return -errno; return 0; } @@ -397,9 +402,9 @@ int snd_pcm_playback_flush(snd_pcm_t *pcm) { if (!pcm) return -EINVAL; - if (pcm->fd[SND_PCM_CHANNEL_PLAYBACK] < 0) + if (pcm->chan[SND_PCM_CHANNEL_PLAYBACK].fd < 0) return -EINVAL; - if (ioctl(pcm->fd[SND_PCM_CHANNEL_PLAYBACK], SND_PCM_IOCTL_CHANNEL_FLUSH) < 0) + if (ioctl(pcm->chan[SND_PCM_CHANNEL_PLAYBACK].fd, SND_PCM_IOCTL_CHANNEL_FLUSH) < 0) return -errno; return 0; } @@ -408,9 +413,9 @@ int snd_pcm_capture_flush(snd_pcm_t *pcm) { if (!pcm) return -EINVAL; - if (pcm->fd[SND_PCM_CHANNEL_CAPTURE] < 0) + if (pcm->chan[SND_PCM_CHANNEL_CAPTURE].fd < 0) return -EINVAL; - if (ioctl(pcm->fd[SND_PCM_CHANNEL_CAPTURE], SND_PCM_IOCTL_CHANNEL_FLUSH) < 0) + if (ioctl(pcm->chan[SND_PCM_CHANNEL_CAPTURE].fd, SND_PCM_IOCTL_CHANNEL_FLUSH) < 0) return -errno; return 0; } @@ -431,22 +436,24 @@ int snd_pcm_playback_pause(snd_pcm_t *pcm, int enable) { if (!pcm) return -EINVAL; - if (pcm->fd[SND_PCM_CHANNEL_PLAYBACK] < 0) + if (pcm->chan[SND_PCM_CHANNEL_PLAYBACK].fd < 0) return -EINVAL; - if (ioctl(pcm->fd[SND_PCM_CHANNEL_PLAYBACK], SND_PCM_IOCTL_CHANNEL_PAUSE, &enable) < 0) + if (ioctl(pcm->chan[SND_PCM_CHANNEL_PLAYBACK].fd, SND_PCM_IOCTL_CHANNEL_PAUSE, &enable) < 0) return -errno; return 0; } ssize_t snd_pcm_transfer_size(snd_pcm_t *pcm, int channel) { + struct snd_pcm_chan *chan; if (!pcm || channel < 0 || channel > 1) return -EINVAL; - if (!pcm->setup_is_valid[channel]) + chan = &pcm->chan[channel]; + if (!chan->setup_is_valid) return -EBADFD; - if (pcm->setup[channel].mode != SND_PCM_MODE_BLOCK) + if (chan->setup.mode != SND_PCM_MODE_BLOCK) return -EBADFD; - return pcm->setup[channel].buf.block.frag_size; + return chan->setup.buf.block.frag_size; } ssize_t snd_pcm_write(snd_pcm_t *pcm, const void *buffer, size_t size) @@ -455,9 +462,9 @@ ssize_t snd_pcm_write(snd_pcm_t *pcm, const void *buffer, size_t size) if (!pcm || (!buffer && size > 0) || size < 0) return -EINVAL; - if (pcm->fd[SND_PCM_CHANNEL_PLAYBACK] < 0) + if (pcm->chan[SND_PCM_CHANNEL_PLAYBACK].fd < 0) return -EINVAL; - result = write(pcm->fd[SND_PCM_CHANNEL_PLAYBACK], buffer, size); + result = write(pcm->chan[SND_PCM_CHANNEL_PLAYBACK].fd, buffer, size); if (result < 0) return -errno; return result; @@ -469,16 +476,16 @@ ssize_t snd_pcm_writev(snd_pcm_t *pcm, const struct iovec *vector, int count) if (!pcm || (!vector && count > 0) || count < 0) return -EINVAL; - if (pcm->fd[SND_PCM_CHANNEL_PLAYBACK] < 0) + if (pcm->chan[SND_PCM_CHANNEL_PLAYBACK].fd < 0) return -EINVAL; #if 0 - result = writev(pcm->fd[SND_PCM_CHANNEL_PLAYBACK], vector, count); + result = writev(pcm->chan[SND_PCM_CHANNEL_PLAYBACK].fd, vector, count); #else { snd_v_args_t args; args.vector = vector; args.count = count; - result = ioctl(pcm->fd[SND_PCM_CHANNEL_PLAYBACK], SND_IOCTL_WRITEV, &args); + result = ioctl(pcm->chan[SND_PCM_CHANNEL_PLAYBACK].fd, SND_IOCTL_WRITEV, &args); } #endif if (result < 0) @@ -492,9 +499,9 @@ ssize_t snd_pcm_read(snd_pcm_t *pcm, void *buffer, size_t size) if (!pcm || (!buffer && size > 0) || size < 0) return -EINVAL; - if (pcm->fd[SND_PCM_CHANNEL_CAPTURE] < 0) + if (pcm->chan[SND_PCM_CHANNEL_CAPTURE].fd < 0) return -EINVAL; - result = read(pcm->fd[SND_PCM_CHANNEL_CAPTURE], buffer, size); + result = read(pcm->chan[SND_PCM_CHANNEL_CAPTURE].fd, buffer, size); if (result < 0) return -errno; return result; @@ -506,16 +513,16 @@ ssize_t snd_pcm_readv(snd_pcm_t *pcm, const struct iovec *vector, int count) if (!pcm || (!vector && count > 0) || count < 0) return -EINVAL; - if (pcm->fd[SND_PCM_CHANNEL_CAPTURE] < 0) + if (pcm->chan[SND_PCM_CHANNEL_CAPTURE].fd < 0) return -EINVAL; #if 0 - result = readv(pcm->fd[SND_PCM_CHANNEL_CAPTURE], vector, count); + result = readv(pcm->chan[SND_PCM_CHANNEL_CAPTURE].fd, vector, count); #else { snd_v_args_t args; args.vector = vector; args.count = count; - result = ioctl(pcm->fd[SND_PCM_CHANNEL_CAPTURE], SND_IOCTL_READV, &args); + result = ioctl(pcm->chan[SND_PCM_CHANNEL_CAPTURE].fd, SND_IOCTL_READV, &args); } #endif if (result < 0) @@ -528,6 +535,7 @@ int snd_pcm_mmap(snd_pcm_t *pcm, int channel, snd_pcm_mmap_control_t **control, snd_pcm_channel_info_t info; int err, fd, prot; void *caddr, *daddr; + struct snd_pcm_chan *chan; if (control) *control = NULL; @@ -535,7 +543,8 @@ int snd_pcm_mmap(snd_pcm_t *pcm, int channel, snd_pcm_mmap_control_t **control, *buffer = NULL; if (!pcm || channel < 0 || channel > 1 || !control || !buffer) return -EINVAL; - fd = pcm->fd[channel]; + chan = &pcm->chan[channel]; + fd = chan->fd; if (fd < 0) return -EINVAL; memset(&info, 0, sizeof(info)); @@ -552,24 +561,26 @@ int snd_pcm_mmap(snd_pcm_t *pcm, int channel, snd_pcm_mmap_control_t **control, munmap(caddr, sizeof(snd_pcm_mmap_control_t)); return err; } - *control = pcm->mmap_caddr[channel] = caddr; - *buffer = pcm->mmap_daddr[channel] = daddr; - pcm->mmap_size[channel] = info.mmap_size; + *control = chan->mmap_control = caddr; + *buffer = chan->mmap_data = daddr; + chan->mmap_size = info.mmap_size; return 0; } int snd_pcm_munmap(snd_pcm_t *pcm, int channel) { + struct snd_pcm_chan *chan; if (!pcm || channel < 0 || channel > 1) return -EINVAL; - if (pcm->mmap_caddr[channel]) { - munmap(pcm->mmap_caddr[channel], sizeof(snd_pcm_mmap_control_t)); - pcm->mmap_caddr[channel] = NULL; + chan = &pcm->chan[channel]; + if (chan->mmap_control) { + munmap(chan->mmap_control, sizeof(snd_pcm_mmap_control_t)); + chan->mmap_control = NULL; } - if (pcm->mmap_daddr[channel]) { - munmap(pcm->mmap_daddr[channel], pcm->mmap_size[channel]); - pcm->mmap_daddr[channel] = NULL; - pcm->mmap_size[channel] = 0; + if (chan->mmap_data) { + munmap(chan->mmap_data, chan->mmap_size); + chan->mmap_data = NULL; + chan->mmap_size = 0; } return 0; } diff --git a/src/pcm/pcm_local.h b/src/pcm/pcm_local.h index 1a9758d4..eca8cedb 100644 --- a/src/pcm/pcm_local.h +++ b/src/pcm/pcm_local.h @@ -19,27 +19,41 @@ * */ +#include <pthread.h> #include "asoundlib.h" +struct snd_pcm_plug { + snd_pcm_plugin_t *first; + snd_pcm_plugin_t *last; + void *alloc_ptr[2]; + long alloc_size[2]; + int alloc_lock[2]; + snd_pcm_mmap_control_t *mmap_control; + char *mmap_data; + long mmap_size; + pthread_t thread; + int thread_stop; + int setup_is_valid; + snd_pcm_channel_setup_t setup; + int hwstatus; +}; + +struct snd_pcm_chan { + int fd; + int setup_is_valid; + snd_pcm_channel_setup_t setup; + snd_pcm_mmap_control_t *mmap_control; + char *mmap_data; + long mmap_size; + struct snd_pcm_plug plug; +}; + struct snd_pcm { int card; int device; int mode; int ver; - int fd[2]; - int setup_is_valid[2]; - snd_pcm_channel_setup_t setup[2]; - snd_pcm_mmap_control_t *mmap_caddr[2]; - char *mmap_daddr[2]; - long mmap_size[2]; - snd_pcm_plugin_t *plugin_first[2]; - snd_pcm_plugin_t *plugin_last[2]; - void *plugin_alloc_ptr[4]; - long plugin_alloc_size[4]; - int plugin_alloc_lock[4]; - void *plugin_alloc_xptr[2]; - long plugin_alloc_xsize[2]; - int plugin_alloc_xchannel; + struct snd_pcm_chan chan[2]; }; unsigned int snd_pcm_plugin_formats(unsigned int formats); diff --git a/src/pcm/pcm_plugin.c b/src/pcm/pcm_plugin.c index d0f1afd8..edaa114f 100644 --- a/src/pcm/pcm_plugin.c +++ b/src/pcm/pcm_plugin.c @@ -26,11 +26,11 @@ #include <errno.h> #include <math.h> #include <sys/uio.h> +#include <sys/poll.h> #include "pcm_local.h" -static void *snd_pcm_plugin_buf_alloc(snd_pcm_t *pcm, size_t size); -static void snd_pcm_plugin_buf_free(snd_pcm_t *pcm, void *ptr); -static void *snd_pcm_plugin_ptr_alloc(snd_pcm_t *pcm, size_t size); +static void *snd_pcm_plugin_buf_alloc(snd_pcm_t *pcm, int channel, size_t size); +static void snd_pcm_plugin_buf_free(snd_pcm_t *pcm, int channel, void *ptr); snd_pcm_plugin_t *snd_pcm_plugin_build(snd_pcm_plugin_handle_t *handle, const char *name, @@ -64,6 +64,8 @@ snd_pcm_plugin_t *snd_pcm_plugin_build(snd_pcm_plugin_handle_t *handle, plugin->handle = handle; plugin->voices = (snd_pcm_plugin_voice_t *)((char *)plugin + sizeof(*plugin)); plugin->extra_data = (char *)plugin->voices + voices * sizeof(snd_pcm_plugin_voice_t); + plugin->src_voices = snd_pcm_plugin_src_voices; + plugin->dst_voices = snd_pcm_plugin_dst_voices; return plugin; } @@ -82,29 +84,27 @@ int snd_pcm_plugin_free(snd_pcm_plugin_t *plugin) int snd_pcm_plugin_clear(snd_pcm_t *pcm, int channel) { snd_pcm_plugin_t *plugin, *plugin_next; + struct snd_pcm_plug *plug; int idx; if (!pcm) return -EINVAL; - plugin = pcm->plugin_first[channel]; - pcm->plugin_first[channel] = NULL; - pcm->plugin_last[channel] = NULL; + plugin = pcm->chan[channel].plug.first; + pcm->chan[channel].plug.first = NULL; + pcm->chan[channel].plug.last = NULL; while (plugin) { plugin_next = plugin->next; snd_pcm_plugin_free(plugin); plugin = plugin_next; } - for (idx = 0; idx < 4; idx++) { - if (pcm->plugin_alloc_ptr[idx]) - free(pcm->plugin_alloc_ptr[idx]); - pcm->plugin_alloc_ptr[idx] = 0; - pcm->plugin_alloc_size[idx] = 0; - pcm->plugin_alloc_lock[idx] = 0; - } - if (pcm->plugin_alloc_xptr[channel]) - free(pcm->plugin_alloc_xptr[channel]); - pcm->plugin_alloc_xptr[channel] = NULL; - pcm->plugin_alloc_xsize[channel] = 0; + plug = &pcm->chan[channel].plug; + for (idx = 0; idx < 2; idx++) { + if (plug->alloc_ptr[idx]) + free(plug->alloc_ptr[idx]); + plug->alloc_ptr[idx] = 0; + plug->alloc_size[idx] = 0; + plug->alloc_lock[idx] = 0; + } return 0; } @@ -112,14 +112,14 @@ int snd_pcm_plugin_insert(snd_pcm_t *pcm, int channel, snd_pcm_plugin_t *plugin) { if (!pcm || channel < 0 || channel > 1 || !plugin) return -EINVAL; - plugin->next = pcm->plugin_first[channel]; + plugin->next = pcm->chan[channel].plug.first; plugin->prev = NULL; - if (pcm->plugin_first[channel]) { - pcm->plugin_first[channel]->prev = plugin; - pcm->plugin_first[channel] = plugin; + if (pcm->chan[channel].plug.first) { + pcm->chan[channel].plug.first->prev = plugin; + pcm->chan[channel].plug.first = plugin; } else { - pcm->plugin_last[channel] = - pcm->plugin_first[channel] = plugin; + pcm->chan[channel].plug.last = + pcm->chan[channel].plug.first = plugin; } return 0; } @@ -129,13 +129,13 @@ int snd_pcm_plugin_append(snd_pcm_t *pcm, int channel, snd_pcm_plugin_t *plugin) if (!pcm || channel < 0 || channel > 1 || !plugin) return -EINVAL; plugin->next = NULL; - plugin->prev = pcm->plugin_last[channel]; - if (pcm->plugin_last[channel]) { - pcm->plugin_last[channel]->next = plugin; - pcm->plugin_last[channel] = plugin; + plugin->prev = pcm->chan[channel].plug.last; + if (pcm->chan[channel].plug.last) { + pcm->chan[channel].plug.last->next = plugin; + pcm->chan[channel].plug.last = plugin; } else { - pcm->plugin_last[channel] = - pcm->plugin_first[channel] = plugin; + pcm->chan[channel].plug.last = + pcm->chan[channel].plug.first = plugin; } return 0; } @@ -149,9 +149,9 @@ int snd_pcm_plugin_remove_to(snd_pcm_t *pcm, int channel, snd_pcm_plugin_t *plug plugin1 = plugin; while (plugin1->prev) plugin1 = plugin1->prev; - if (pcm->plugin_first[channel] != plugin1) + if (pcm->chan[channel].plug.first != plugin1) return -EINVAL; - pcm->plugin_first[channel] = plugin; + pcm->chan[channel].plug.first = plugin; plugin1 = plugin->prev; plugin->prev = NULL; while (plugin1) { @@ -166,7 +166,7 @@ int snd_pcm_plugin_remove_first(snd_pcm_t *pcm, int channel) { snd_pcm_plugin_t *plugin; - plugin = pcm->plugin_first[channel]; + plugin = pcm->chan[channel].plug.first; if (plugin->next) { plugin = plugin->next; } else { @@ -179,14 +179,14 @@ snd_pcm_plugin_t *snd_pcm_plugin_first(snd_pcm_t *pcm, int channel) { if (!pcm || channel < 0 || channel > 1) return NULL; - return pcm->plugin_first[channel]; + return pcm->chan[channel].plug.first; } snd_pcm_plugin_t *snd_pcm_plugin_last(snd_pcm_t *pcm, int channel) { if (!pcm || channel < 0 || channel > 1) return NULL; - return pcm->plugin_last[channel]; + return pcm->chan[channel].plug.last; } @@ -223,7 +223,16 @@ int snd_pcm_plugin_info(snd_pcm_t *pcm, snd_pcm_channel_info_t *info) info->formats = snd_pcm_plugin_formats(info->formats); info->min_rate = 4000; info->max_rate = 192000; - info->rates = SND_PCM_RATE_8000_48000; + info->min_voices = 1; + info->max_voices = 32; + info->rates = SND_PCM_RATE_CONTINUOUS; + info->buffer_size = snd_pcm_plugin_client_size(pcm, info->channel, info->buffer_size); + info->min_fragment_size = snd_pcm_plugin_client_size(pcm, info->channel, info->min_fragment_size); + info->max_fragment_size = snd_pcm_plugin_client_size(pcm, info->channel, info->max_fragment_size); + info->fragment_align = snd_pcm_plugin_client_size(pcm, info->channel, info->fragment_align); + info->fifo_size = snd_pcm_plugin_client_size(pcm, info->channel, info->fifo_size); + info->transfer_block_size = snd_pcm_plugin_client_size(pcm, info->channel, info->transfer_block_size); + info->mmap_size = snd_pcm_plugin_client_size(pcm, info->channel, info->mmap_size); return 0; } @@ -233,7 +242,7 @@ static int snd_pcm_plugin_action(snd_pcm_t *pcm, int channel, int action, snd_pcm_plugin_t *plugin; int err; - plugin = pcm->plugin_first[channel]; + plugin = pcm->chan[channel].plug.first; while (plugin) { if (plugin->action) { if ((err = plugin->action(plugin, action, data))<0) @@ -249,11 +258,16 @@ int snd_pcm_plugin_params(snd_pcm_t *pcm, snd_pcm_channel_params_t *params) snd_pcm_channel_params_t hwparams, params1; snd_pcm_channel_info_t hwinfo; snd_pcm_plugin_t *plugin; + struct snd_pcm_plug *plug; int err; if (!pcm || !params || params->channel < 0 || params->channel > 1) return -EINVAL; + plug = &pcm->chan[params->channel].plug; + if (plug->mmap_data) + return -EBADFD; + /* * try to decide, if a conversion is required */ @@ -276,6 +290,9 @@ int snd_pcm_plugin_params(snd_pcm_t *pcm, snd_pcm_channel_params_t *params) if ((err = snd_pcm_plugin_format(pcm, ¶ms1, &hwparams, &hwinfo)) < 0) return err; + if (snd_pcm_plugin_first(pcm, params->channel) == NULL) + return snd_pcm_channel_params(pcm, params); + /* * I/O plugins */ @@ -323,6 +340,12 @@ int snd_pcm_plugin_params(snd_pcm_t *pcm, snd_pcm_channel_params_t *params) err = snd_pcm_channel_params(pcm, &hwparams); if (err < 0) return err; + + plug->setup_is_valid = 0; + memset(&plug->setup, 0, sizeof(snd_pcm_channel_setup_t)); + plug->setup.channel = params->channel; + if ((err = snd_pcm_plugin_setup(pcm, &plug->setup))<0) + return err; err = snd_pcm_plugin_action(pcm, hwparams.channel, INIT, (long)&hwparams); if (err < 0) return err; @@ -332,9 +355,17 @@ int snd_pcm_plugin_params(snd_pcm_t *pcm, snd_pcm_channel_params_t *params) int snd_pcm_plugin_setup(snd_pcm_t *pcm, snd_pcm_channel_setup_t *setup) { int err; + struct snd_pcm_plug *plug; if (!pcm || !setup || setup->channel < 0 || setup->channel > 1) return -EINVAL; + plug = &pcm->chan[setup->channel].plug; + if (plug->first == NULL) + return snd_pcm_channel_setup(pcm, setup); + if (plug->setup_is_valid) { + memcpy(setup, &plug->setup, sizeof(*setup)); + return 0; + } err = snd_pcm_channel_setup(pcm, setup); if (err < 0) return err; @@ -349,12 +380,17 @@ int snd_pcm_plugin_setup(snd_pcm_t *pcm, snd_pcm_channel_setup_t *setup) } else { return -EINVAL; } + if (setup->channel == SND_PCM_CHANNEL_PLAYBACK) + setup->format = plug->first->src_format; + else + setup->format = plug->last->dst_format; + memcpy(&plug->setup, setup, sizeof(*setup)); + plug->setup_is_valid = 1; return 0; } int snd_pcm_plugin_status(snd_pcm_t *pcm, snd_pcm_channel_status_t *status) { - double ratio; int err; if (!pcm || !status || status->channel < 0 || status->channel > 1) @@ -362,9 +398,6 @@ int snd_pcm_plugin_status(snd_pcm_t *pcm, snd_pcm_channel_status_t *status) err = snd_pcm_channel_status(pcm, status); if (err < 0) return err; - ratio = snd_pcm_plugin_transfer_ratio(pcm, status->channel); - if (ratio <= 0) - return -EINVAL; /* FIXME: scount may overflow */ status->scount = snd_pcm_plugin_client_size(pcm, status->channel, status->scount); status->count = snd_pcm_plugin_client_size(pcm, status->channel, status->count); @@ -372,13 +405,100 @@ int snd_pcm_plugin_status(snd_pcm_t *pcm, snd_pcm_channel_status_t *status) return 0; } +static void mmap_clear(struct snd_pcm_plug *plug) +{ + int idx; + snd_pcm_mmap_fragment_t *f; + + f = plug->mmap_control->fragments; + for (idx = 0; idx < plug->setup.buf.block.frags; idx++) { + f->data = 0; + f->io = 0; + f->res[0] = 0; + f->res[1] = 0; + f++; + } + plug->mmap_control->status.frag_io = 0; + plug->mmap_control->status.block = 0; + plug->mmap_control->status.expblock = 0; +} + +static void snd_pcm_plugin_status_change(snd_pcm_t *pcm, int channel) +{ + struct snd_pcm_chan *chan; + struct snd_pcm_plug *plug; + snd_pcm_channel_status_t status; + int newstatus; + + chan = &pcm->chan[channel]; + plug = &chan->plug; + if (!plug->mmap_data) + return; + if (chan->mmap_control) { + newstatus = chan->mmap_control->status.status; + } else { + status.channel = channel; + if (snd_pcm_channel_status(pcm, &status) < 0) + newstatus = SND_PCM_STATUS_NOTREADY; + else + newstatus = status.status; + } + if (plug->mmap_control->status.status == SND_PCM_STATUS_RUNNING && + newstatus != SND_PCM_STATUS_RUNNING) { + mmap_clear(plug); + } + plug->mmap_control->status.status = newstatus; +} + int snd_pcm_plugin_prepare(snd_pcm_t *pcm, int channel) { int err; if ((err = snd_pcm_plugin_action(pcm, channel, PREPARE, 0))<0) return err; - return snd_pcm_channel_prepare(pcm, channel); + if ((err = snd_pcm_channel_prepare(pcm, channel)) < 0) + return err; + snd_pcm_plugin_status_change(pcm, channel); + return 0; +} + +int snd_pcm_plugin_go(snd_pcm_t *pcm, int channel) +{ + struct snd_pcm_chan *chan; + struct snd_pcm_plug *plug; + if (!pcm || channel < 0 || channel > 1) + return -EINVAL; + chan = &pcm->chan[channel]; + plug = &chan->plug; + if (plug->first == NULL) + return snd_pcm_channel_go(pcm, channel); + if (plug->mmap_control) { + if (plug->mmap_control->status.status != SND_PCM_STATUS_PREPARED) + return -EBADFD; + if (channel == SND_PCM_CHANNEL_PLAYBACK) { + if (!plug->mmap_control->fragments[0].data) + return -EIO; + } else { + if (plug->mmap_control->fragments[0].data) + return -EIO; + } + plug->mmap_control->status.status = SND_PCM_STATUS_RUNNING; + } + return 0; +} + +int snd_pcm_plugin_sync_go(snd_pcm_t *pcm, snd_pcm_sync_t *sync) +{ + int err; + if (!pcm || !sync) + return -EINVAL; + if (snd_pcm_plugin_first(pcm, SND_PCM_CHANNEL_PLAYBACK) || + snd_pcm_plugin_first(pcm, SND_PCM_CHANNEL_CAPTURE)) { + if ((err = snd_pcm_plugin_go(pcm, SND_PCM_CHANNEL_PLAYBACK)) < 0) + return err; + return snd_pcm_plugin_go(pcm, SND_PCM_CHANNEL_CAPTURE); + } + return snd_pcm_sync_go(pcm, sync); } int snd_pcm_plugin_playback_drain(snd_pcm_t *pcm) @@ -387,7 +507,10 @@ int snd_pcm_plugin_playback_drain(snd_pcm_t *pcm) if ((err = snd_pcm_plugin_action(pcm, SND_PCM_CHANNEL_PLAYBACK, DRAIN, 0))<0) return err; - return snd_pcm_playback_drain(pcm); + if ((err = snd_pcm_playback_drain(pcm)) < 0) + return err; + snd_pcm_plugin_status_change(pcm, SND_PCM_CHANNEL_PLAYBACK); + return 0; } int snd_pcm_plugin_flush(snd_pcm_t *pcm, int channel) @@ -397,73 +520,75 @@ int snd_pcm_plugin_flush(snd_pcm_t *pcm, int channel) pdprintf("flush\n"); if ((err = snd_pcm_plugin_action(pcm, channel, FLUSH, 0))<0) return err; - return snd_pcm_channel_flush(pcm, channel); + if ((err = snd_pcm_channel_flush(pcm, channel)) < 0) + return err; + snd_pcm_plugin_status_change(pcm, channel); + return 0; } -ssize_t snd_pcm_plugin_transfer_size(snd_pcm_t *pcm, int channel) +int snd_pcm_plugin_pause(snd_pcm_t *pcm, int enable) { - ssize_t result; - - if ((result = snd_pcm_transfer_size(pcm, channel)) < 0) - return result; - return snd_pcm_plugin_client_size(pcm, channel, result); + int err; + + if ((err = snd_pcm_playback_pause(pcm, enable)) < 0) + return err; + snd_pcm_plugin_status_change(pcm, SND_PCM_CHANNEL_PLAYBACK); + return 0; } -int snd_pcm_plugin_pointer(snd_pcm_t *pcm, int channel, void **ptr, size_t *size) +ssize_t snd_pcm_plugin_transfer_size(snd_pcm_t *pcm, int channel) { - snd_pcm_plugin_t *plugin = NULL; - snd_pcm_plugin_voice_t *voices; - size_t samples; - int width; + struct snd_pcm_plug *plug; + if (!pcm || channel < 0 || channel > 1) + return -EINVAL; + plug = &pcm->chan[channel].plug; + if (plug->first == NULL) + return snd_pcm_plugin_transfer_size(pcm, channel); + if (!plug->setup_is_valid) + return -EBADFD; + if (plug->setup.mode != SND_PCM_MODE_BLOCK) + return -EBADFD; + return plug->setup.buf.block.frag_size; +} - if (!ptr || !size || *size < 1) +int snd_pcm_plugin_voice_setup(snd_pcm_t *pcm, int channel, snd_pcm_voice_setup_t *setup) +{ + int voice, width, size; + struct snd_pcm_plug* plug; + + if (!pcm || !setup) return -EINVAL; - *ptr = NULL; - if (!pcm || channel < 0 || channel > 1) + if (channel < 0 || channel > 1) return -EINVAL; - if ((*size = snd_pcm_plugin_transfer_size(pcm, channel)) < 0) - return *size; - if (channel == SND_PCM_CHANNEL_PLAYBACK && plugin->src_voices) { - plugin = pcm->plugin_first[channel]; - if (!plugin) - goto __skip; - if (!plugin->src_format.interleave) - goto __skip; - if ((width = snd_pcm_format_width(plugin->src_format.format)) < 0) - return width; - samples = *size * width; - if ((samples % (plugin->src_format.voices * 8)) != 0) - return -EINVAL; - samples /= (plugin->src_format.voices * 8); - pcm->plugin_alloc_xchannel = SND_PCM_CHANNEL_PLAYBACK; - if (plugin->src_voices(plugin, &voices, samples, - snd_pcm_plugin_ptr_alloc) < 0) - goto __skip; - *ptr = voices->addr; - return 0; - } else if (channel == SND_PCM_CHANNEL_CAPTURE && plugin->dst_voices) { - plugin = pcm->plugin_last[channel]; - if (!plugin) - goto __skip; - if (plugin->dst_format.interleave) - goto __skip; - if ((width = snd_pcm_format_width(plugin->dst_format.format)) < 0) - return width; - samples = *size * width; - if ((samples % (plugin->dst_format.voices * 8)) != 0) - return -EINVAL; - samples /= (plugin->src_format.voices * 8); - pcm->plugin_alloc_xchannel = SND_PCM_CHANNEL_CAPTURE; - if (plugin->dst_voices(plugin, &voices, *size, - snd_pcm_plugin_ptr_alloc) < 0) - goto __skip; - *ptr = voices->addr; + voice = setup->voice; + memset(setup, 0, sizeof(*setup)); + setup->voice = voice; + if (voice < 0) + return -EINVAL; + plug = &pcm->chan[channel].plug; + if (plug->first == NULL) + return snd_pcm_voice_setup(pcm, channel, setup); + if (!plug->mmap_control) { + setup->addr = -1; return 0; } - __skip: - *ptr = snd_pcm_plugin_ptr_alloc(pcm, *size); - if (*ptr == NULL) - return -ENOMEM; + if (voice >= plug->setup.format.voices) + return -EINVAL; + + width = snd_pcm_format_physical_width(plug->setup.format.format); + if (width < 0) + return width; + size = plug->mmap_size; + if (plug->setup.format.interleave) { + setup->addr = 0; + setup->first = voice * width; + setup->step = plug->setup.format.voices * width; + } else { + size /= plug->setup.format.voices; + setup->addr = setup->voice * size; + setup->first = 0; + setup->step = width; + } return 0; } @@ -528,7 +653,7 @@ static ssize_t snd_pcm_plugin_writev1(snd_pcm_t *pcm, const struct iovec *vector ssize_t size; int idx, err; - plugin = pcm->plugin_first[SND_PCM_CHANNEL_PLAYBACK]; + plugin = snd_pcm_plugin_first(pcm, SND_PCM_CHANNEL_PLAYBACK); if ((err = snd_pcm_plugin_load_src_vector(plugin, &src_voices, vector, count)) < 0) return err; size = 0; @@ -542,33 +667,26 @@ static ssize_t snd_pcm_plugin_writev1(snd_pcm_t *pcm, const struct iovec *vector ssize_t samples1 = samples; if (plugin->dst_samples) samples1 = plugin->dst_samples(plugin, samples); - if (next->src_voices) { - if ((err = next->src_voices(next, &dst_voices, samples1, snd_pcm_plugin_buf_alloc)) < 0) { - snd_pcm_plugin_buf_free(pcm, src_voices->aptr); - return err; - } - } else { - if ((err = snd_pcm_plugin_src_voices(next, &dst_voices, samples1)) < 0) { - snd_pcm_plugin_buf_free(pcm, src_voices->aptr); - return err; - } + if ((err = next->src_voices(next, &dst_voices, samples1)) < 0) { + snd_pcm_plugin_buf_free(pcm, SND_PCM_CHANNEL_PLAYBACK, src_voices->aptr); + return err; } } else { dst_voices = NULL; } pdprintf("write plugin: %s, %i\n", plugin->name, samples); if ((samples = plugin->transfer(plugin, src_voices, dst_voices, samples)) < 0) { - snd_pcm_plugin_buf_free(pcm, src_voices->aptr); + snd_pcm_plugin_buf_free(pcm, SND_PCM_CHANNEL_PLAYBACK, src_voices->aptr); if (dst_voices) - snd_pcm_plugin_buf_free(pcm, dst_voices->aptr); + snd_pcm_plugin_buf_free(pcm, SND_PCM_CHANNEL_PLAYBACK, dst_voices->aptr); return samples; } - snd_pcm_plugin_buf_free(pcm, src_voices->aptr); + snd_pcm_plugin_buf_free(pcm, SND_PCM_CHANNEL_PLAYBACK, src_voices->aptr); plugin = plugin->next; src_voices = dst_voices; } samples = snd_pcm_plugin_client_samples(pcm, SND_PCM_CHANNEL_PLAYBACK, samples); - size = snd_pcm_plugin_src_samples_to_size(pcm->plugin_first[SND_PCM_CHANNEL_PLAYBACK], samples); + size = snd_pcm_plugin_src_samples_to_size(snd_pcm_plugin_first(pcm, SND_PCM_CHANNEL_PLAYBACK), samples); if (size < 0) return size; pdprintf("writev result = %i\n", size); @@ -582,7 +700,7 @@ ssize_t snd_pcm_plugin_writev(snd_pcm_t *pcm, const struct iovec *vector, int co int size = 0; if (vector == NULL) return -EFAULT; - plugin = pcm->plugin_first[SND_PCM_CHANNEL_PLAYBACK]; + plugin = snd_pcm_plugin_first(pcm, SND_PCM_CHANNEL_PLAYBACK); if (plugin == NULL) return snd_pcm_readv(pcm, vector, count); voices = plugin->src_format.voices; @@ -621,50 +739,42 @@ static ssize_t snd_pcm_plugin_readv1(snd_pcm_t *pcm, const struct iovec *vector, ssize_t size; int idx, err; - plugin = pcm->plugin_first[SND_PCM_CHANNEL_CAPTURE]; + plugin = snd_pcm_plugin_first(pcm, SND_PCM_CHANNEL_CAPTURE); size = 0; for (idx = 0; idx < count; idx++) size += vector[idx].iov_len; if (size < 0) return size; - samples = snd_pcm_plugin_dst_size_to_samples(pcm->plugin_last[SND_PCM_CHANNEL_CAPTURE], size); + samples = snd_pcm_plugin_dst_size_to_samples(snd_pcm_plugin_last(pcm, SND_PCM_CHANNEL_CAPTURE), size); samples = snd_pcm_plugin_hardware_samples(pcm, SND_PCM_CHANNEL_CAPTURE, samples); while (plugin && samples > 0) { if ((next = plugin->next) != NULL) { - if (plugin->dst_voices) { - if ((err = plugin->dst_voices(plugin, &dst_voices, samples, snd_pcm_plugin_buf_alloc)) < 0) { - if (src_voices) - snd_pcm_plugin_buf_free(pcm, src_voices->aptr); - return err; - } - } else { - if ((err = snd_pcm_plugin_dst_voices(plugin, &dst_voices, samples)) < 0) { - if (src_voices) - snd_pcm_plugin_buf_free(pcm, src_voices->aptr); - return err; - } + if ((err = plugin->dst_voices(plugin, &dst_voices, samples)) < 0) { + if (src_voices) + snd_pcm_plugin_buf_free(pcm, SND_PCM_CHANNEL_CAPTURE, src_voices->aptr); + return err; } } else { if ((err = snd_pcm_plugin_load_dst_vector(plugin, &dst_voices, vector, count)) < 0) { if (src_voices) - snd_pcm_plugin_buf_free(pcm, src_voices->aptr); + snd_pcm_plugin_buf_free(pcm, SND_PCM_CHANNEL_CAPTURE, src_voices->aptr); return err; } } pdprintf("read plugin: %s, %i\n", plugin->name, samples); if ((samples = plugin->transfer(plugin, src_voices, dst_voices, samples)) < 0) { if (src_voices) - snd_pcm_plugin_buf_free(pcm, src_voices->aptr); - snd_pcm_plugin_buf_free(pcm, dst_voices->aptr); + snd_pcm_plugin_buf_free(pcm, SND_PCM_CHANNEL_CAPTURE, src_voices->aptr); + snd_pcm_plugin_buf_free(pcm, SND_PCM_CHANNEL_CAPTURE, dst_voices->aptr); return samples; } if (src_voices) - snd_pcm_plugin_buf_free(pcm, src_voices->aptr); + snd_pcm_plugin_buf_free(pcm, SND_PCM_CHANNEL_CAPTURE, src_voices->aptr); plugin = plugin->next; src_voices = dst_voices; } - snd_pcm_plugin_buf_free(pcm, dst_voices->aptr); - size = snd_pcm_plugin_dst_samples_to_size(pcm->plugin_last[SND_PCM_CHANNEL_CAPTURE], samples); + snd_pcm_plugin_buf_free(pcm, SND_PCM_CHANNEL_CAPTURE, dst_voices->aptr); + size = snd_pcm_plugin_dst_samples_to_size(snd_pcm_plugin_last(pcm, SND_PCM_CHANNEL_CAPTURE), samples); pdprintf("readv result = %i\n", size); return size; } @@ -676,7 +786,7 @@ ssize_t snd_pcm_plugin_readv(snd_pcm_t *pcm, const struct iovec *vector, int cou int size = 0; if (vector == NULL) return -EFAULT; - plugin = pcm->plugin_last[SND_PCM_CHANNEL_CAPTURE]; + plugin = snd_pcm_plugin_last(pcm, SND_PCM_CHANNEL_CAPTURE); if (plugin == NULL) return snd_pcm_readv(pcm, vector, count); voices = plugin->dst_format.voices; @@ -712,7 +822,7 @@ ssize_t snd_pcm_plugin_write(snd_pcm_t *pcm, const void *buffer, size_t count) snd_pcm_plugin_t *plugin; int voices; - if ((plugin = pcm->plugin_first[SND_PCM_CHANNEL_PLAYBACK]) == NULL) + if ((plugin = snd_pcm_plugin_first(pcm, SND_PCM_CHANNEL_PLAYBACK)) == NULL) return snd_pcm_write(pcm, buffer, count); voices = plugin->src_format.voices; if (count % voices != 0) @@ -739,7 +849,7 @@ ssize_t snd_pcm_plugin_read(snd_pcm_t *pcm, void *buffer, size_t count) snd_pcm_plugin_t *plugin; int voices; - if ((plugin = pcm->plugin_last[SND_PCM_CHANNEL_CAPTURE]) == NULL) + if ((plugin = snd_pcm_plugin_last(pcm, SND_PCM_CHANNEL_CAPTURE)) == NULL) return snd_pcm_read(pcm, buffer, count); voices = plugin->dst_format.voices; if (count % voices != 0) @@ -765,82 +875,69 @@ ssize_t snd_pcm_plugin_read(snd_pcm_t *pcm, void *buffer, size_t count) * Plugin helpers */ -static void *snd_pcm_plugin_buf_alloc(snd_pcm_t *pcm, size_t size) +static void *snd_pcm_plugin_buf_alloc(snd_pcm_t *pcm, int channel, size_t size) { int idx; void *ptr; + struct snd_pcm_plug *plug; if (pcm == NULL || size <= 0) return NULL; - for (idx = 0; idx < 4; idx++) { - if (pcm->plugin_alloc_lock[idx]) + plug = &pcm->chan[channel].plug; + for (idx = 0; idx < 2; idx++) { + if (plug->alloc_lock[idx]) continue; - if (pcm->plugin_alloc_ptr[idx] == NULL) + if (plug->alloc_ptr[idx] == NULL) continue; - if (pcm->plugin_alloc_size[idx] >= size) { - pcm->plugin_alloc_lock[idx] = 1; - return pcm->plugin_alloc_ptr[idx]; + if (plug->alloc_size[idx] >= size) { + plug->alloc_lock[idx] = 1; + return plug->alloc_ptr[idx]; } } - for (idx = 0; idx < 4; idx++) { - if (pcm->plugin_alloc_lock[idx]) + for (idx = 0; idx < 2; idx++) { + if (plug->alloc_lock[idx]) continue; - if (pcm->plugin_alloc_ptr[idx] == NULL) + if (plug->alloc_ptr[idx] == NULL) continue; - ptr = realloc(pcm->plugin_alloc_ptr[idx], size); + ptr = realloc(plug->alloc_ptr[idx], size); if (ptr == NULL) continue; - pcm->plugin_alloc_size[idx] = size; - pcm->plugin_alloc_lock[idx] = 1; - return pcm->plugin_alloc_ptr[idx] = ptr; + plug->alloc_size[idx] = size; + plug->alloc_lock[idx] = 1; + return plug->alloc_ptr[idx] = ptr; } - for (idx = 0; idx < 4; idx++) { - if (pcm->plugin_alloc_ptr[idx] != NULL) + for (idx = 0; idx < 2; idx++) { + if (plug->alloc_ptr[idx] != NULL) continue; ptr = malloc(size); if (ptr == NULL) continue; - pcm->plugin_alloc_size[idx] = size; - pcm->plugin_alloc_lock[idx] = 1; - return pcm->plugin_alloc_ptr[idx] = ptr; + plug->alloc_size[idx] = size; + plug->alloc_lock[idx] = 1; + return plug->alloc_ptr[idx] = ptr; } return NULL; } -static void snd_pcm_plugin_buf_free(snd_pcm_t *pcm, void *ptr) +static void snd_pcm_plugin_buf_free(snd_pcm_t *pcm, int channel, void *ptr) { int idx; + struct snd_pcm_plug *plug; + if (pcm == NULL || ptr == NULL) return; - for (idx = 0; idx < 4; idx++) { - if (pcm->plugin_alloc_ptr[idx] == ptr) { - pcm->plugin_alloc_lock[idx] = 0; + plug = &pcm->chan[channel].plug; + for (idx = 0; idx < 2; idx++) { + if (plug->alloc_ptr[idx] == ptr) { + plug->alloc_lock[idx] = 0; return; } } } -static void *snd_pcm_plugin_ptr_alloc(snd_pcm_t *pcm, size_t size) -{ - void *ptr; - int channel = pcm->plugin_alloc_xchannel; - - if (pcm->plugin_alloc_xptr[channel]) { - if (pcm->plugin_alloc_xsize[channel] >= size) - return pcm->plugin_alloc_xptr[channel]; - ptr = realloc(pcm->plugin_alloc_xptr[channel], size); - } else { - ptr = malloc(size); - } - if (ptr == NULL) - return NULL; - pcm->plugin_alloc_xptr[channel] = (char *)ptr; - pcm->plugin_alloc_xsize[channel] = size; - return ptr; -} - static int snd_pcm_plugin_xvoices(snd_pcm_plugin_t *plugin, + int channel, snd_pcm_plugin_voice_t **voices, size_t samples, snd_pcm_format_t *format) @@ -857,7 +954,7 @@ static int snd_pcm_plugin_xvoices(snd_pcm_plugin_t *plugin, if ((size % 8) != 0) return -EINVAL; size /= 8; - ptr = (char *)snd_pcm_plugin_buf_alloc(plugin->handle, size); + ptr = (char *)snd_pcm_plugin_buf_alloc(plugin->handle, channel, size); if (ptr == NULL) return -ENOMEM; if ((size % format->voices) != 0) @@ -884,12 +981,212 @@ int snd_pcm_plugin_src_voices(snd_pcm_plugin_t *plugin, snd_pcm_plugin_voice_t **voices, size_t samples) { - return snd_pcm_plugin_xvoices(plugin, voices, samples, &plugin->src_format); + return snd_pcm_plugin_xvoices(plugin, SND_PCM_CHANNEL_PLAYBACK, voices, samples, &plugin->src_format); } int snd_pcm_plugin_dst_voices(snd_pcm_plugin_t *plugin, snd_pcm_plugin_voice_t **voices, size_t samples) { - return snd_pcm_plugin_xvoices(plugin, voices, samples, &plugin->dst_format); + return snd_pcm_plugin_xvoices(plugin, SND_PCM_CHANNEL_CAPTURE, voices, samples, &plugin->dst_format); +} + +static void *playback_mmap(void *data) +{ + snd_pcm_t *pcm = data; + struct snd_pcm_chan *chan = &pcm->chan[SND_PCM_CHANNEL_PLAYBACK]; + struct snd_pcm_plug *plug = &chan->plug; + snd_pcm_mmap_control_t *control; + void *buffer; + int frags; + int frag_size, voice_size, voice_frag_size; + int voices; + control = plug->mmap_control; + buffer = plug->mmap_data; + frags = plug->setup.buf.block.frags; + frag_size = plug->setup.buf.block.frag_size; + voices = plug->setup.format.voices; + voice_size = plug->mmap_size / voices; + voice_frag_size = voice_size / frags; + while (1) { + int err; + struct pollfd pfd; + int frag = control->status.frag_io; + if (plug->thread_stop) + break; + if (control->status.status != SND_PCM_STATUS_RUNNING && + control->status.status != SND_PCM_STATUS_PREPARED) { + usleep(100000); + continue; + } + pfd.fd = chan->fd; + pfd.events = POLLOUT; + pfd.revents = 0; + err = poll(&pfd, 1, -1); + if (err < 0) { + fprintf(stderr, "error on poll\n"); + continue; + } + if (!control->fragments[frag].data) { + usleep(10000); + continue; + } + /* NYI: status.block */ + control->fragments[frag].io = 1; + if (plug->setup.format.interleave) { + err = snd_pcm_plugin_write(pcm, buffer + frag * frag_size, frag_size); + } else { + struct iovec vector[voices]; + struct iovec *v = vector; + int voice; + for (voice = 0; voice < voices; ++voice) { + v->iov_base = buffer + voice_size * voice + frag * voice_frag_size; + v->iov_len = voice_frag_size; + v++; + } + err = snd_pcm_plugin_writev(pcm, vector, voice_frag_size); + } + if (err <= 0) { + control->fragments[frag].io = 0; + snd_pcm_plugin_status_change(pcm, SND_PCM_CHANNEL_PLAYBACK); + continue; + } + control->fragments[frag].io = 0; + control->fragments[frag].data = 0; + frag++; + if (frag == frags) + frag = 0; + control->status.frag_io = frag; + } + return 0; +} + +static void *capture_mmap(void *data) +{ + snd_pcm_t *pcm = data; + struct snd_pcm_chan *chan = &pcm->chan[SND_PCM_CHANNEL_CAPTURE]; + struct snd_pcm_plug *plug = &chan->plug; + snd_pcm_mmap_control_t *control; + void *buffer; + int frag, frags; + int frag_size, voice_size, voice_frag_size; + int voices; + control = plug->mmap_control; + buffer = plug->mmap_data; + frag = 0; + frags = plug->setup.buf.block.frags; + frag_size = plug->setup.buf.block.frag_size; + voices = plug->setup.format.voices; + voice_size = plug->mmap_size / voices; + voice_frag_size = voice_size / frags; + while (1) { + int err; + struct pollfd pfd; + if (plug->thread_stop) + break; + if (control->status.status != SND_PCM_STATUS_RUNNING) { + usleep(100000); + continue; + } + pfd.fd = chan->fd; + pfd.events = POLLIN; + pfd.revents = 0; + err = poll(&pfd, 1, -1); + if (err < 0) { + printf("error on poll\n"); + continue; + } + if (control->fragments[frag].data) { + usleep(10000); + continue; + } + /* NYI: status.block */ + control->status.frag_io = frag; + control->fragments[frag].io = 1; + if (plug->setup.format.interleave) { + err = snd_pcm_plugin_read(pcm, buffer + frag * frag_size, frag_size); + } else { + struct iovec vector[voices]; + struct iovec *v = vector; + int voice; + for (voice = 0; voice < voices; ++voice) { + v->iov_base = buffer + voice_size * voice + frag * voice_frag_size; + v->iov_len = voice_frag_size; + v++; + } + err = snd_pcm_plugin_readv(pcm, vector, voice_frag_size); + } + if (err < 0) { + snd_pcm_plugin_status_change(pcm, SND_PCM_CHANNEL_CAPTURE); + continue; + } + control->fragments[frag].io = 0; + control->fragments[frag].data = 1; + frag++; + if (frag == frags) + frag = 0; + } + return 0; +} + +int snd_pcm_plugin_mmap(snd_pcm_t *pcm, int channel, snd_pcm_mmap_control_t **control, void **data) +{ + int err; + + struct snd_pcm_plug *plug; + if (!pcm || channel < 0 || channel > 1 || !control || !data) + return -EINVAL; + + plug = &pcm->chan[channel].plug; + if (plug->first == NULL) + return snd_pcm_mmap(pcm, channel, control, data); + if (!plug->setup_is_valid) + return -EBADFD; + if (plug->setup.mode != SND_PCM_MODE_BLOCK) + return -EINVAL; + + if (plug->mmap_data) { + *control = plug->mmap_control; + *data = plug->mmap_data; + return 0; + } + + plug->mmap_control = malloc(sizeof(snd_pcm_mmap_control_t)); + plug->mmap_size = plug->setup.buf.block.frag_size * plug->setup.buf.block.frags; + plug->mmap_data = malloc(plug->mmap_size); + + mmap_clear(plug); + + *control = plug->mmap_control; + *data = plug->mmap_data; + + plug->thread_stop = 0; + if (channel == SND_PCM_CHANNEL_PLAYBACK) + err = pthread_create(&plug->thread, NULL, playback_mmap, pcm); + else + err = pthread_create(&plug->thread, NULL, capture_mmap, pcm); + if (err < 0) { + snd_pcm_plugin_munmap(pcm, channel); + return err; + } + return 0; +} + +int snd_pcm_plugin_munmap(snd_pcm_t *pcm, int channel) +{ + struct snd_pcm_plug *plug; + if (!pcm || channel < 0 || channel > 1) + return -EINVAL; + plug = &pcm->chan[channel].plug; + if (plug->first == NULL) + return snd_pcm_munmap(pcm, channel); + if (plug->mmap_data) { + plug->thread_stop = 1; + pthread_join(plug->thread, NULL); + free(plug->mmap_control); + plug->mmap_control = 0; + free(plug->mmap_data); + plug->mmap_data = 0; + } + return 0; } diff --git a/src/pcm/plugin/mmap.c b/src/pcm/plugin/mmap.c index f38f990e..421c530b 100644 --- a/src/pcm/plugin/mmap.c +++ b/src/pcm/plugin/mmap.c @@ -75,7 +75,7 @@ static int poll_playback(snd_pcm_t *pcm) if (pcm->mode & SND_PCM_OPEN_NONBLOCK) return -EAGAIN; - pfd.fd = pcm->fd[SND_PCM_CHANNEL_PLAYBACK]; + pfd.fd = pcm->chan[SND_PCM_CHANNEL_PLAYBACK].fd; pfd.events = POLLOUT; pfd.revents = 0; err = poll(&pfd, 1, 1000); @@ -146,7 +146,7 @@ static int poll_capture(snd_pcm_t *pcm) if (pcm->mode & SND_PCM_OPEN_NONBLOCK) return -EAGAIN; - pfd.fd = pcm->fd[SND_PCM_CHANNEL_CAPTURE]; + pfd.fd = pcm->chan[SND_PCM_CHANNEL_CAPTURE].fd; pfd.events = POLLIN; pfd.revents = 0; err = poll(&pfd, 1, 1000); @@ -185,8 +185,7 @@ static int query_capture(snd_pcm_plugin_t *plugin, int not_use_poll) static int mmap_src_voices(snd_pcm_plugin_t *plugin, snd_pcm_plugin_voice_t **voices, - size_t samples, - void *(*plugin_alloc)(snd_pcm_plugin_handle_t *handle, size_t size)) + size_t samples) { mmap_t *data; int err; @@ -221,8 +220,7 @@ static int mmap_src_voices(snd_pcm_plugin_t *plugin, static int mmap_dst_voices(snd_pcm_plugin_t *plugin, snd_pcm_plugin_voice_t **voices, - size_t samples, - void *(*plugin_alloc)(snd_pcm_plugin_handle_t *handle, size_t size)) + size_t samples) { mmap_t *data; int voice; @@ -275,7 +273,7 @@ static ssize_t mmap_transfer(snd_pcm_plugin_t *plugin, size = snd_pcm_plugin_src_samples_to_size(plugin, samples); if (size != data->frag_size) return -EINVAL; - if (src_voices != data->voices) { + if (plugin->prev == NULL) { if (plugin->src_format.interleave) { void *dst = data->voices[0].addr + data->frag * data->frag_size; /* Paranoia: add check for src_voices */ @@ -306,7 +304,7 @@ static ssize_t mmap_transfer(snd_pcm_plugin_t *plugin, size = snd_pcm_plugin_dst_samples_to_size(plugin, samples); if (size != data->frag_size) return -EINVAL; - if (dst_voices != data->voices) { + if (plugin->next == NULL) { if (plugin->dst_format.interleave) { void *src = data->voices[0].addr + data->frag * data->frag_size; /* Paranoia: add check for dst_voices */ |