mirror of
https://github.com/alsa-project/alsa-lib.git
synced 2025-12-19 08:57:08 -05:00
Massive fixes in the mmap plugin (NONBLOCK, poll).
This commit is contained in:
parent
a8a134e334
commit
c808ac0806
2 changed files with 108 additions and 64 deletions
|
|
@ -193,6 +193,10 @@ int snd_pcm_nonblock_mode(snd_pcm_t *pcm, int nonblock)
|
||||||
flags &= ~O_NONBLOCK;
|
flags &= ~O_NONBLOCK;
|
||||||
if (fcntl(fd, F_SETFL, flags) < 0)
|
if (fcntl(fd, F_SETFL, flags) < 0)
|
||||||
return -errno;
|
return -errno;
|
||||||
|
if (nonblock)
|
||||||
|
pcm->mode |= SND_PCM_OPEN_NONBLOCK;
|
||||||
|
else
|
||||||
|
pcm->mode &= ~SND_PCM_OPEN_NONBLOCK;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <sys/poll.h>
|
||||||
#include "../pcm_local.h"
|
#include "../pcm_local.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -38,6 +39,90 @@ struct mmap_private_data {
|
||||||
int frag;
|
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)
|
static int mmap_transfer_src_ptr(snd_pcm_plugin_t *plugin, char **buffer, size_t *size)
|
||||||
{
|
{
|
||||||
struct mmap_private_data *data;
|
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) {
|
if (data->channel == SND_PCM_CHANNEL_PLAYBACK) {
|
||||||
/* wait until the block is not free */
|
/* wait until the block is not free */
|
||||||
while (control->fragments[data->frag].data) {
|
while (control->fragments[data->frag].data) {
|
||||||
switch (control->status.status) {
|
err = query_playback(data, control, 0);
|
||||||
case SND_PCM_STATUS_PREPARED:
|
|
||||||
err = snd_pcm_channel_go(data->pcm, data->channel);
|
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
break;
|
|
||||||
case SND_PCM_STATUS_RUNNING:
|
|
||||||
usleep(10000);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return -EIO;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*size = control->status.frag_size;
|
*size = control->status.frag_size;
|
||||||
|
|
@ -105,21 +181,12 @@ static ssize_t mmap_transfer(snd_pcm_plugin_t *plugin,
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
if (data->channel == SND_PCM_CHANNEL_PLAYBACK) {
|
if (data->channel == SND_PCM_CHANNEL_PLAYBACK) {
|
||||||
if (interleave) {
|
|
||||||
while (control->fragments[data->frag].data) {
|
while (control->fragments[data->frag].data) {
|
||||||
switch (control->status.status) {
|
err = query_playback(data, control, 0);
|
||||||
case SND_PCM_STATUS_PREPARED:
|
|
||||||
err = snd_pcm_channel_go(data->pcm, data->channel);
|
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
break;
|
|
||||||
case SND_PCM_STATUS_RUNNING:
|
|
||||||
usleep(10000);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return -EIO;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
if (interleave) {
|
||||||
addr = data->buffer + control->fragments[data->frag].addr;
|
addr = data->buffer + control->fragments[data->frag].addr;
|
||||||
if (dst_ptr != addr)
|
if (dst_ptr != addr)
|
||||||
memcpy(addr, dst_ptr, dst_size);
|
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++) {
|
for (voice = 0; voice < control->status.voices; voice++) {
|
||||||
frag = data->frag + (voice * (control->status.frags / control->status.voices));
|
frag = data->frag + (voice * (control->status.frags / control->status.voices));
|
||||||
while (control->fragments[frag].data) {
|
while (control->fragments[frag].data) {
|
||||||
switch (control->status.status) {
|
err = query_playback(data, control, 1);
|
||||||
case SND_PCM_STATUS_PREPARED:
|
|
||||||
err = snd_pcm_channel_go(data->pcm, data->channel);
|
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
break;
|
|
||||||
case SND_PCM_STATUS_RUNNING:
|
|
||||||
usleep(10000);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return -EIO;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
addr = data->buffer + control->fragments[frag].addr;
|
addr = data->buffer + control->fragments[frag].addr;
|
||||||
if (dst_ptr != addr)
|
if (dst_ptr != addr)
|
||||||
|
|
@ -155,21 +213,12 @@ static ssize_t mmap_transfer(snd_pcm_plugin_t *plugin,
|
||||||
}
|
}
|
||||||
return dst_size;
|
return dst_size;
|
||||||
} else if (data->channel == SND_PCM_CHANNEL_CAPTURE) {
|
} else if (data->channel == SND_PCM_CHANNEL_CAPTURE) {
|
||||||
if (interleave) {
|
|
||||||
while (!control->fragments[data->frag].data) {
|
while (!control->fragments[data->frag].data) {
|
||||||
switch (control->status.status) {
|
err = query_capture(data, control, 0);
|
||||||
case SND_PCM_STATUS_PREPARED:
|
|
||||||
err = snd_pcm_channel_go(data->pcm, data->channel);
|
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
break;
|
|
||||||
case SND_PCM_STATUS_RUNNING:
|
|
||||||
usleep(10000);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return -EIO;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
if (interleave) {
|
||||||
addr = data->buffer + control->fragments[data->frag].addr;
|
addr = data->buffer + control->fragments[data->frag].addr;
|
||||||
if (dst_ptr != addr)
|
if (dst_ptr != addr)
|
||||||
memcpy(dst_ptr, addr, dst_size);
|
memcpy(dst_ptr, addr, dst_size);
|
||||||
|
|
@ -178,18 +227,9 @@ static ssize_t mmap_transfer(snd_pcm_plugin_t *plugin,
|
||||||
} else {
|
} else {
|
||||||
for (voice = 0; voice < control->status.voices; voice++) {
|
for (voice = 0; voice < control->status.voices; voice++) {
|
||||||
while (!control->fragments[data->frag].data) {
|
while (!control->fragments[data->frag].data) {
|
||||||
switch (control->status.status) {
|
err = query_capture(data, control, 1);
|
||||||
case SND_PCM_STATUS_PREPARED:
|
|
||||||
err = snd_pcm_channel_go(data->pcm, data->channel);
|
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
break;
|
|
||||||
case SND_PCM_STATUS_RUNNING:
|
|
||||||
usleep(10000);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return -EIO;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
addr = data->buffer + control->fragments[data->frag].addr;
|
addr = data->buffer + control->fragments[data->frag].addr;
|
||||||
if (dst_ptr != addr)
|
if (dst_ptr != addr)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue