mirror of
https://github.com/alsa-project/alsa-lib.git
synced 2025-10-29 05:40:25 -04:00
Added support for auto mmap. Much improved version of pcm_share (without async signals)
This commit is contained in:
parent
8d3919707e
commit
9a435c2d93
14 changed files with 621 additions and 328 deletions
|
|
@ -74,7 +74,9 @@ sname Slave PCM name on server
|
|||
- share Share PCM
|
||||
Fields:
|
||||
sname Slave name
|
||||
[schannels] Slave channels
|
||||
[schannels] Slave channels
|
||||
[sformat] Slave format
|
||||
[srate] Slave rate
|
||||
binding Bindings table
|
||||
.N Slave channel for client channel N
|
||||
|
||||
|
|
|
|||
|
|
@ -26,6 +26,8 @@
|
|||
#include <stdarg.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/poll.h>
|
||||
#include <sys/shm.h>
|
||||
#include <sys/mman.h>
|
||||
#include <dlfcn.h>
|
||||
#include "pcm_local.h"
|
||||
#include "list.h"
|
||||
|
|
@ -138,27 +140,39 @@ int snd_pcm_channel_setup(snd_pcm_t *pcm, snd_pcm_channel_setup_t *setup)
|
|||
return pcm->ops->channel_setup(pcm->op_arg, setup);
|
||||
}
|
||||
|
||||
int snd_pcm_params(snd_pcm_t *pcm, snd_pcm_params_t *params)
|
||||
int _snd_pcm_params(snd_pcm_t *pcm, snd_pcm_params_t *params)
|
||||
{
|
||||
int err;
|
||||
snd_pcm_setup_t setup;
|
||||
int mmap = 0;
|
||||
assert(pcm && params);
|
||||
if ((err = pcm->ops->params(pcm->op_arg, params)) < 0)
|
||||
return err;
|
||||
pcm->valid_setup = 0;
|
||||
return snd_pcm_setup(pcm, &setup);
|
||||
}
|
||||
|
||||
int snd_pcm_params_mmap(snd_pcm_t *pcm, snd_pcm_params_t *params)
|
||||
{
|
||||
int err;
|
||||
if (pcm->mmap_info) {
|
||||
mmap = 1;
|
||||
err = snd_pcm_munmap(pcm);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
if ((err = pcm->ops->params(pcm->op_arg, params)) < 0)
|
||||
return err;
|
||||
pcm->valid_setup = 0;
|
||||
err = snd_pcm_setup(pcm, &setup);
|
||||
if (pcm->mmap_auto || mmap)
|
||||
snd_pcm_mmap(pcm);
|
||||
err = _snd_pcm_params(pcm, params);
|
||||
if (pcm->valid_setup)
|
||||
snd_pcm_mmap(pcm);
|
||||
return err;
|
||||
}
|
||||
|
||||
int snd_pcm_params(snd_pcm_t *pcm, snd_pcm_params_t *params)
|
||||
{
|
||||
assert(pcm && params);
|
||||
if (pcm->mmap_auto)
|
||||
return snd_pcm_params_mmap(pcm, params);
|
||||
assert(!pcm->mmap_info);
|
||||
return _snd_pcm_params(pcm, params);
|
||||
}
|
||||
|
||||
int snd_pcm_status(snd_pcm_t *pcm, snd_pcm_status_t *status)
|
||||
{
|
||||
assert(pcm && status);
|
||||
|
|
@ -227,7 +241,7 @@ int snd_pcm_set_avail_min(snd_pcm_t *pcm, size_t frames)
|
|||
int err;
|
||||
assert(pcm);
|
||||
assert(pcm->valid_setup);
|
||||
assert(frames > 0 && frames < pcm->setup.buffer_size);
|
||||
assert(frames > 0);
|
||||
err = pcm->fast_ops->set_avail_min(pcm->fast_op_arg, frames);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
|
@ -1069,6 +1083,60 @@ ssize_t snd_pcm_write_areas(snd_pcm_t *pcm, snd_pcm_channel_area_t *areas,
|
|||
return err;
|
||||
}
|
||||
|
||||
int snd_pcm_alloc_user_mmap(snd_pcm_t *pcm, snd_pcm_mmap_info_t *i)
|
||||
{
|
||||
i->type = SND_PCM_MMAP_USER;
|
||||
i->size = snd_pcm_frames_to_bytes(pcm, pcm->setup.buffer_size);
|
||||
i->u.user.shmid = shmget(IPC_PRIVATE, i->size, 0666);
|
||||
if (i->u.user.shmid < 0) {
|
||||
SYSERR("shmget failed");
|
||||
return -errno;
|
||||
}
|
||||
i->addr = shmat(i->u.user.shmid, 0, 0);
|
||||
if (i->addr == (void*) -1) {
|
||||
SYSERR("shmat failed");
|
||||
return -errno;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int snd_pcm_alloc_kernel_mmap(snd_pcm_t *pcm, snd_pcm_mmap_info_t *i, int fd)
|
||||
{
|
||||
i->type = SND_PCM_MMAP_KERNEL;
|
||||
i->size = pcm->setup.mmap_bytes;
|
||||
i->addr = mmap(NULL, pcm->setup.mmap_bytes,
|
||||
PROT_WRITE | PROT_READ,
|
||||
MAP_FILE|MAP_SHARED,
|
||||
fd, SND_PCM_MMAP_OFFSET_DATA);
|
||||
if (i->addr == MAP_FAILED ||
|
||||
i->addr == NULL) {
|
||||
SYSERR("data mmap failed");
|
||||
return -errno;
|
||||
}
|
||||
i->u.kernel.fd = fd;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int snd_pcm_free_mmap(snd_pcm_t *pcm, snd_pcm_mmap_info_t *i)
|
||||
{
|
||||
if (i->type == SND_PCM_MMAP_USER) {
|
||||
if (shmdt(i->addr) < 0) {
|
||||
SYSERR("shmdt failed");
|
||||
return -errno;
|
||||
}
|
||||
if (shmctl(i->u.user.shmid, IPC_RMID, 0) < 0) {
|
||||
SYSERR("shmctl IPC_RMID failed");
|
||||
return -errno;
|
||||
}
|
||||
} else {
|
||||
if (munmap(pcm->mmap_info->addr, pcm->mmap_info->size) < 0) {
|
||||
SYSERR("data munmap failed");
|
||||
return -errno;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void snd_pcm_error(const char *file, int line, const char *function, int err, const char *fmt, ...)
|
||||
{
|
||||
va_list arg;
|
||||
|
|
|
|||
|
|
@ -383,7 +383,7 @@ static int snd_pcm_adpcm_params(snd_pcm_t *pcm, snd_pcm_params_t * params)
|
|||
params->format.sfmt = adpcm->sformat;
|
||||
params->xfer_mode = SND_PCM_XFER_UNSPECIFIED;
|
||||
params->mmap_shape = SND_PCM_MMAP_UNSPECIFIED;;
|
||||
err = snd_pcm_params(slave, params);
|
||||
err = snd_pcm_params_mmap(slave, params);
|
||||
params->format.sfmt = adpcm->cformat;
|
||||
params->xfer_mode = adpcm->cxfer_mode;
|
||||
params->mmap_shape = adpcm->cmmap_shape;
|
||||
|
|
|
|||
|
|
@ -265,7 +265,7 @@ static int snd_pcm_alaw_params(snd_pcm_t *pcm, snd_pcm_params_t * params)
|
|||
params->format.sfmt = alaw->sformat;
|
||||
params->xfer_mode = SND_PCM_XFER_UNSPECIFIED;
|
||||
params->mmap_shape = SND_PCM_MMAP_UNSPECIFIED;;
|
||||
err = snd_pcm_params(slave, params);
|
||||
err = snd_pcm_params_mmap(slave, params);
|
||||
params->format.sfmt = alaw->cformat;
|
||||
params->xfer_mode = alaw->cxfer_mode;
|
||||
params->mmap_shape = alaw->cmmap_shape;
|
||||
|
|
|
|||
|
|
@ -393,37 +393,21 @@ static int snd_pcm_hw_mmap(snd_pcm_t *pcm)
|
|||
{
|
||||
snd_pcm_hw_t *hw = pcm->private;
|
||||
snd_pcm_mmap_info_t *i = calloc(1, sizeof(*i));
|
||||
int err;
|
||||
if (!i)
|
||||
return -ENOMEM;
|
||||
if (pcm->setup.mmap_shape == SND_PCM_MMAP_UNSPECIFIED) {
|
||||
i->type = SND_PCM_MMAP_USER;
|
||||
i->size = snd_pcm_frames_to_bytes(pcm, pcm->setup.buffer_size);
|
||||
i->u.user.shmid = shmget(IPC_PRIVATE, i->size, 0666);
|
||||
if (i->u.user.shmid < 0) {
|
||||
SYSERR("shmget failed");
|
||||
err = snd_pcm_alloc_user_mmap(pcm, i);
|
||||
if (err < 0) {
|
||||
free(i);
|
||||
return -errno;
|
||||
}
|
||||
i->addr = shmat(i->u.user.shmid, 0, 0);
|
||||
if (i->addr == (void*) -1) {
|
||||
SYSERR("shmat failed");
|
||||
free(i);
|
||||
return -errno;
|
||||
return err;
|
||||
}
|
||||
} else {
|
||||
i->type = SND_PCM_MMAP_KERNEL;
|
||||
i->size = pcm->setup.mmap_bytes;
|
||||
i->addr = mmap(NULL, pcm->setup.mmap_bytes,
|
||||
PROT_WRITE | PROT_READ,
|
||||
MAP_FILE|MAP_SHARED,
|
||||
hw->fd, SND_PCM_MMAP_OFFSET_DATA);
|
||||
if (i->addr == MAP_FAILED ||
|
||||
i->addr == NULL) {
|
||||
SYSERR("data mmap failed");
|
||||
err = snd_pcm_alloc_kernel_mmap(pcm, i, hw->fd);
|
||||
if (err < 0) {
|
||||
free(i);
|
||||
return -errno;
|
||||
return err;
|
||||
}
|
||||
i->u.kernel.fd = hw->fd;
|
||||
}
|
||||
pcm->mmap_info = i;
|
||||
pcm->mmap_info_count = 1;
|
||||
|
|
@ -452,21 +436,9 @@ static int snd_pcm_hw_munmap_control(snd_pcm_t *pcm)
|
|||
|
||||
static int snd_pcm_hw_munmap(snd_pcm_t *pcm)
|
||||
{
|
||||
if (pcm->setup.mmap_shape == SND_PCM_MMAP_UNSPECIFIED) {
|
||||
if (shmdt(pcm->mmap_info->addr) < 0) {
|
||||
SYSERR("shmdt failed");
|
||||
return -errno;
|
||||
}
|
||||
if (shmctl(pcm->mmap_info->u.user.shmid, IPC_RMID, 0) < 0) {
|
||||
SYSERR("shmctl IPC_RMID failed");
|
||||
return -errno;
|
||||
}
|
||||
} else {
|
||||
if (munmap(pcm->mmap_info->addr, pcm->mmap_info->size) < 0) {
|
||||
SYSERR("data munmap failed");
|
||||
return -errno;
|
||||
}
|
||||
}
|
||||
int err = snd_pcm_free_mmap(pcm, pcm->mmap_info);
|
||||
if (err < 0)
|
||||
return err;
|
||||
pcm->mmap_info_count = 0;
|
||||
free(pcm->mmap_info);
|
||||
pcm->mmap_info = 0;
|
||||
|
|
|
|||
|
|
@ -120,7 +120,7 @@ static int snd_pcm_linear_params(snd_pcm_t *pcm, snd_pcm_params_t * params)
|
|||
params->format.sfmt = linear->sformat;
|
||||
params->xfer_mode = SND_PCM_XFER_UNSPECIFIED;
|
||||
params->mmap_shape = SND_PCM_MMAP_UNSPECIFIED;
|
||||
err = snd_pcm_params(slave, params);
|
||||
err = snd_pcm_params_mmap(slave, params);
|
||||
params->format.sfmt = linear->cformat;
|
||||
params->xfer_mode = linear->cxfer_mode;
|
||||
params->mmap_shape = linear->cmmap_shape;
|
||||
|
|
|
|||
|
|
@ -112,8 +112,7 @@ struct snd_pcm {
|
|||
void snd_pcm_areas_from_buf(snd_pcm_t *pcm, snd_pcm_channel_area_t *areas, void *buf);
|
||||
void snd_pcm_areas_from_bufs(snd_pcm_t *pcm, snd_pcm_channel_area_t *areas, void **bufs);
|
||||
|
||||
int snd_pcm_mmap(snd_pcm_t *pcm);
|
||||
int snd_pcm_munmap(snd_pcm_t *pcm);
|
||||
int snd_pcm_params_mmap(snd_pcm_t *pcm, snd_pcm_params_t *params);
|
||||
int snd_pcm_mmap_ready(snd_pcm_t *pcm);
|
||||
ssize_t snd_pcm_mmap_appl_ptr(snd_pcm_t *pcm, off_t offset);
|
||||
void snd_pcm_mmap_appl_backward(snd_pcm_t *pcm, size_t frames);
|
||||
|
|
@ -137,6 +136,9 @@ ssize_t snd_pcm_write_areas(snd_pcm_t *pcm, snd_pcm_channel_area_t *areas,
|
|||
snd_pcm_xfer_areas_func_t func);
|
||||
ssize_t snd_pcm_read_mmap(snd_pcm_t *pcm, size_t size);
|
||||
ssize_t snd_pcm_write_mmap(snd_pcm_t *pcm, size_t size);
|
||||
int snd_pcm_alloc_user_mmap(snd_pcm_t *pcm, snd_pcm_mmap_info_t *i);
|
||||
int snd_pcm_alloc_kernel_mmap(snd_pcm_t *pcm, snd_pcm_mmap_info_t *i, int fd);
|
||||
int snd_pcm_free_mmap(snd_pcm_t *pcm, snd_pcm_mmap_info_t *i);
|
||||
|
||||
static inline size_t snd_pcm_mmap_playback_avail(snd_pcm_t *pcm)
|
||||
{
|
||||
|
|
@ -158,10 +160,13 @@ static inline size_t snd_pcm_mmap_capture_avail(snd_pcm_t *pcm)
|
|||
|
||||
static inline size_t snd_pcm_mmap_avail(snd_pcm_t *pcm)
|
||||
{
|
||||
ssize_t avail;
|
||||
avail = *pcm->hw_ptr - *pcm->appl_ptr;
|
||||
if (pcm->stream == SND_PCM_STREAM_PLAYBACK)
|
||||
return snd_pcm_mmap_playback_avail(pcm);
|
||||
else
|
||||
return snd_pcm_mmap_capture_avail(pcm);
|
||||
avail += pcm->setup.buffer_size;
|
||||
if (avail < 0)
|
||||
avail += pcm->setup.boundary;
|
||||
return avail;
|
||||
}
|
||||
|
||||
static inline ssize_t snd_pcm_mmap_playback_hw_avail(snd_pcm_t *pcm)
|
||||
|
|
@ -184,10 +189,13 @@ static inline ssize_t snd_pcm_mmap_capture_hw_avail(snd_pcm_t *pcm)
|
|||
|
||||
static inline ssize_t snd_pcm_mmap_hw_avail(snd_pcm_t *pcm)
|
||||
{
|
||||
ssize_t avail;
|
||||
avail = *pcm->hw_ptr - *pcm->appl_ptr;
|
||||
if (pcm->stream == SND_PCM_STREAM_PLAYBACK)
|
||||
return snd_pcm_mmap_playback_hw_avail(pcm);
|
||||
else
|
||||
return snd_pcm_mmap_capture_hw_avail(pcm);
|
||||
avail += pcm->setup.buffer_size;
|
||||
if (avail < 0)
|
||||
avail += pcm->setup.boundary;
|
||||
return pcm->setup.buffer_size - avail;
|
||||
}
|
||||
|
||||
#define snd_pcm_mmap_playback_delay snd_pcm_mmap_playback_hw_avail
|
||||
|
|
|
|||
|
|
@ -282,7 +282,7 @@ static int snd_pcm_mulaw_params(snd_pcm_t *pcm, snd_pcm_params_t * params)
|
|||
params->format.sfmt = mulaw->sformat;
|
||||
params->xfer_mode = SND_PCM_XFER_UNSPECIFIED;
|
||||
params->mmap_shape = SND_PCM_MMAP_UNSPECIFIED;;
|
||||
err = snd_pcm_params(slave, params);
|
||||
err = snd_pcm_params_mmap(slave, params);
|
||||
params->format.sfmt = mulaw->cformat;
|
||||
params->xfer_mode = mulaw->cxfer_mode;
|
||||
params->mmap_shape = mulaw->cmmap_shape;
|
||||
|
|
|
|||
|
|
@ -221,7 +221,7 @@ static int snd_pcm_multi_params(snd_pcm_t *pcm, snd_pcm_params_t *params)
|
|||
for (i = 0; i < multi->slaves_count; ++i) {
|
||||
snd_pcm_t *slave = multi->slaves[i].pcm;
|
||||
p.format.channels = multi->slaves[i].channels_count;
|
||||
err = snd_pcm_params(slave, &p);
|
||||
err = snd_pcm_params_mmap(slave, &p);
|
||||
if (err < 0) {
|
||||
params->fail_mask = p.fail_mask;
|
||||
params->fail_reason = p.fail_reason;
|
||||
|
|
|
|||
|
|
@ -323,7 +323,6 @@ static int snd_pcm_plug_change_rate(snd_pcm_t *pcm, snd_pcm_t **new, snd_pcm_for
|
|||
err = snd_pcm_rate_open(new, NULL, slv->sfmt, slv->rate, plug->slave, plug->slave != plug->req_slave);
|
||||
if (err < 0)
|
||||
return err;
|
||||
(*new)->mmap_auto = 1;
|
||||
slv->rate = clt->rate;
|
||||
if (snd_pcm_format_linear(clt->sfmt))
|
||||
slv->sfmt = clt->sfmt;
|
||||
|
|
@ -388,7 +387,6 @@ static int snd_pcm_plug_change_channels(snd_pcm_t *pcm, snd_pcm_t **new, snd_pcm
|
|||
err = snd_pcm_route_open(new, NULL, slv->sfmt, slv->channels, ttable, tt_ssize, tt_cused, tt_sused, plug->slave, plug->slave != plug->req_slave);
|
||||
if (err < 0)
|
||||
return err;
|
||||
(*new)->mmap_auto = 1;
|
||||
slv->channels = clt->channels;
|
||||
if (snd_pcm_format_linear(clt->sfmt))
|
||||
slv->sfmt = clt->sfmt;
|
||||
|
|
@ -453,7 +451,6 @@ static int snd_pcm_plug_change_format(snd_pcm_t *pcm, snd_pcm_t **new, snd_pcm_f
|
|||
err = f(new, NULL, slv->sfmt, plug->slave, plug->slave != plug->req_slave);
|
||||
if (err < 0)
|
||||
return err;
|
||||
(*new)->mmap_auto = 1;
|
||||
slv->sfmt = cfmt;
|
||||
return 1;
|
||||
}
|
||||
|
|
@ -492,7 +489,6 @@ static int snd_pcm_plug_insert_plugins(snd_pcm_t *pcm,
|
|||
}
|
||||
k++;
|
||||
}
|
||||
plug->slave->mmap_auto = 0;
|
||||
assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -322,19 +322,10 @@ int snd_pcm_plugin_mmap(snd_pcm_t *pcm)
|
|||
i = calloc(1, sizeof(*i));
|
||||
if (!i)
|
||||
return -ENOMEM;
|
||||
i->type = SND_PCM_MMAP_USER;
|
||||
i->size = snd_pcm_frames_to_bytes(pcm, pcm->setup.buffer_size);
|
||||
i->u.user.shmid = shmget(IPC_PRIVATE, i->size, 0666);
|
||||
if (i->u.user.shmid < 0) {
|
||||
SYSERR("shmget failed");
|
||||
err = snd_pcm_alloc_user_mmap(pcm, i);
|
||||
if (err < 0) {
|
||||
free(i);
|
||||
return -errno;
|
||||
}
|
||||
i->addr = shmat(i->u.user.shmid, 0, 0);
|
||||
if (i->addr == (void*) -1) {
|
||||
SYSERR("shmat failed");
|
||||
free(i);
|
||||
return -errno;
|
||||
return err;
|
||||
}
|
||||
pcm->mmap_info = i;
|
||||
pcm->mmap_info_count = 1;
|
||||
|
|
@ -348,14 +339,9 @@ int snd_pcm_plugin_munmap(snd_pcm_t *pcm)
|
|||
int err = snd_pcm_munmap(slave);
|
||||
if (err < 0)
|
||||
return err;
|
||||
if (shmdt(pcm->mmap_info->addr) < 0) {
|
||||
SYSERR("shmdt failed");
|
||||
return -errno;
|
||||
}
|
||||
if (shmctl(pcm->mmap_info->u.user.shmid, IPC_RMID, 0) < 0) {
|
||||
SYSERR("shmctl IPC_RMID failed");
|
||||
return -errno;
|
||||
}
|
||||
err = snd_pcm_free_mmap(pcm, pcm->mmap_info);
|
||||
if (err < 0)
|
||||
return err;
|
||||
free(pcm->mmap_info);
|
||||
pcm->mmap_info_count = 0;
|
||||
pcm->mmap_info = 0;
|
||||
|
|
|
|||
|
|
@ -342,7 +342,7 @@ static int snd_pcm_rate_params(snd_pcm_t *pcm, snd_pcm_params_t * params)
|
|||
/* FIXME: boundary? */
|
||||
slave_params.xfer_mode = SND_PCM_XFER_UNSPECIFIED;
|
||||
slave_params.mmap_shape = SND_PCM_MMAP_UNSPECIFIED;;
|
||||
err = snd_pcm_params(slave, &slave_params);
|
||||
err = snd_pcm_params_mmap(slave, &slave_params);
|
||||
params->fail_mask = slave_params.fail_mask;
|
||||
params->fail_reason = slave_params.fail_reason;
|
||||
return err;
|
||||
|
|
|
|||
|
|
@ -494,7 +494,7 @@ static int snd_pcm_route_params(snd_pcm_t *pcm, snd_pcm_params_t * params)
|
|||
params->format.channels = route->req_schannels;
|
||||
params->xfer_mode = SND_PCM_XFER_UNSPECIFIED;
|
||||
params->mmap_shape = SND_PCM_MMAP_UNSPECIFIED;;
|
||||
err = snd_pcm_params(slave, params);
|
||||
err = snd_pcm_params_mmap(slave, params);
|
||||
params->format.sfmt = route->cformat;
|
||||
params->format.channels = route->cchannels;
|
||||
params->xfer_mode = route->cxfer_mode;
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue