From c808ac0806453ca387ebb82eb7419106277f45e3 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Fri, 28 Jan 2000 22:45:18 +0000 Subject: [PATCH] Massive fixes in the mmap plugin (NONBLOCK, poll). --- src/pcm/pcm.c | 4 + src/pcm/plugin/mmap.c | 168 ++++++++++++++++++++++++++---------------- 2 files changed, 108 insertions(+), 64 deletions(-) diff --git a/src/pcm/pcm.c b/src/pcm/pcm.c index ccb5b934..4cb9f01a 100644 --- a/src/pcm/pcm.c +++ b/src/pcm/pcm.c @@ -193,6 +193,10 @@ int snd_pcm_nonblock_mode(snd_pcm_t *pcm, int nonblock) flags &= ~O_NONBLOCK; if (fcntl(fd, F_SETFL, flags) < 0) return -errno; + if (nonblock) + pcm->mode |= SND_PCM_OPEN_NONBLOCK; + else + pcm->mode &= ~SND_PCM_OPEN_NONBLOCK; } return 0; } diff --git a/src/pcm/plugin/mmap.c b/src/pcm/plugin/mmap.c index 46d87468..9e912915 100644 --- a/src/pcm/plugin/mmap.c +++ b/src/pcm/plugin/mmap.c @@ -24,6 +24,7 @@ #include #include #include +#include #include "../pcm_local.h" /* @@ -38,6 +39,90 @@ struct mmap_private_data { int frag; }; +static int poll_playback(snd_pcm_t *pcm) +{ + int err; + struct pollfd pfd; + + if (pcm->mode & SND_PCM_OPEN_NONBLOCK) + return -EAGAIN; + pfd.fd = pcm->fd[SND_PCM_CHANNEL_PLAYBACK]; + pfd.events = POLLOUT; + pfd.revents = 0; + err = poll(&pfd, 1, 1000); + return err < 0 ? err : 0; +} + +static int query_playback(struct mmap_private_data *data, + snd_pcm_mmap_control_t *control, + int not_use_poll) +{ + int err; + + switch (control->status.status) { + case SND_PCM_STATUS_PREPARED: + err = snd_pcm_channel_go(data->pcm, data->channel); + if (err < 0) + return err; + break; + case SND_PCM_STATUS_RUNNING: + if (!not_use_poll) { + control->status.expblock = control->status.block + 1; + err = poll_playback(data->pcm); + if (err < 0) + return err; + } + break; + case SND_PCM_STATUS_UNDERRUN: + return -EAGAIN; + default: + return -EIO; + } + return 0; +} + +static int poll_capture(snd_pcm_t *pcm) +{ + int err; + struct pollfd pfd; + + if (pcm->mode & SND_PCM_OPEN_NONBLOCK) + return -EAGAIN; + pfd.fd = pcm->fd[SND_PCM_CHANNEL_CAPTURE]; + pfd.events = POLLIN; + pfd.revents = 0; + err = poll(&pfd, 1, 1000); + return err < 0 ? err : 0; +} + +static int query_capture(struct mmap_private_data *data, + snd_pcm_mmap_control_t *control, + int not_use_poll) +{ + int err; + + switch (control->status.status) { + case SND_PCM_STATUS_PREPARED: + err = snd_pcm_channel_go(data->pcm, data->channel); + if (err < 0) + return err; + break; + case SND_PCM_STATUS_RUNNING: + if (!not_use_poll) { + control->status.expblock = control->status.block + 1; + err = poll_capture(data->pcm); + if (err < 0) + return err; + } + break; + case SND_PCM_STATUS_OVERRUN: + return -EAGAIN; + default: + return -EIO; + } + return 0; +} + static int mmap_transfer_src_ptr(snd_pcm_plugin_t *plugin, char **buffer, size_t *size) { struct mmap_private_data *data; @@ -58,18 +143,9 @@ static int mmap_transfer_src_ptr(snd_pcm_plugin_t *plugin, char **buffer, size_t if (data->channel == SND_PCM_CHANNEL_PLAYBACK) { /* wait until the block is not free */ while (control->fragments[data->frag].data) { - switch (control->status.status) { - case SND_PCM_STATUS_PREPARED: - err = snd_pcm_channel_go(data->pcm, data->channel); - if (err < 0) - return err; - break; - case SND_PCM_STATUS_RUNNING: - usleep(10000); - break; - default: - return -EIO; - } + err = query_playback(data, control, 0); + if (err < 0) + return err; } } *size = control->status.frag_size; @@ -105,21 +181,12 @@ static ssize_t mmap_transfer(snd_pcm_plugin_t *plugin, return -EINVAL; } if (data->channel == SND_PCM_CHANNEL_PLAYBACK) { + while (control->fragments[data->frag].data) { + err = query_playback(data, control, 0); + if (err < 0) + return err; + } if (interleave) { - while (control->fragments[data->frag].data) { - switch (control->status.status) { - case SND_PCM_STATUS_PREPARED: - err = snd_pcm_channel_go(data->pcm, data->channel); - if (err < 0) - return err; - break; - case SND_PCM_STATUS_RUNNING: - usleep(10000); - break; - default: - return -EIO; - } - } addr = data->buffer + control->fragments[data->frag].addr; if (dst_ptr != addr) memcpy(addr, dst_ptr, dst_size); @@ -131,18 +198,9 @@ static ssize_t mmap_transfer(snd_pcm_plugin_t *plugin, for (voice = 0; voice < control->status.voices; voice++) { frag = data->frag + (voice * (control->status.frags / control->status.voices)); while (control->fragments[frag].data) { - switch (control->status.status) { - case SND_PCM_STATUS_PREPARED: - err = snd_pcm_channel_go(data->pcm, data->channel); - if (err < 0) - return err; - break; - case SND_PCM_STATUS_RUNNING: - usleep(10000); - break; - default: - return -EIO; - } + err = query_playback(data, control, 1); + if (err < 0) + return err; } addr = data->buffer + control->fragments[frag].addr; if (dst_ptr != addr) @@ -155,21 +213,12 @@ static ssize_t mmap_transfer(snd_pcm_plugin_t *plugin, } return dst_size; } else if (data->channel == SND_PCM_CHANNEL_CAPTURE) { + while (!control->fragments[data->frag].data) { + err = query_capture(data, control, 0); + if (err < 0) + return err; + } if (interleave) { - while (!control->fragments[data->frag].data) { - switch (control->status.status) { - case SND_PCM_STATUS_PREPARED: - err = snd_pcm_channel_go(data->pcm, data->channel); - if (err < 0) - return err; - break; - case SND_PCM_STATUS_RUNNING: - usleep(10000); - break; - default: - return -EIO; - } - } addr = data->buffer + control->fragments[data->frag].addr; if (dst_ptr != addr) memcpy(dst_ptr, addr, dst_size); @@ -178,18 +227,9 @@ static ssize_t mmap_transfer(snd_pcm_plugin_t *plugin, } else { for (voice = 0; voice < control->status.voices; voice++) { while (!control->fragments[data->frag].data) { - switch (control->status.status) { - case SND_PCM_STATUS_PREPARED: - err = snd_pcm_channel_go(data->pcm, data->channel); - if (err < 0) - return err; - break; - case SND_PCM_STATUS_RUNNING: - usleep(10000); - break; - default: - return -EIO; - } + err = query_capture(data, control, 1); + if (err < 0) + return err; } addr = data->buffer + control->fragments[data->frag].addr; if (dst_ptr != addr) -- 2.47.1