Moved ring buffer pointers and added a mechanism to transfer them via shm

This commit is contained in:
Jaroslav Kysela 2002-04-23 15:51:29 +00:00
parent f063381430
commit c941c548f8
26 changed files with 469 additions and 171 deletions

View file

@ -108,35 +108,35 @@ static int make_inet_socket(int port)
static int send_fd(int sock, void *data, size_t len, int fd)
{
int ret;
size_t cmsg_len = CMSG_LEN(sizeof(int));
struct cmsghdr *cmsg = alloca(cmsg_len);
int *fds = (int *) CMSG_DATA(cmsg);
struct msghdr msghdr;
struct iovec vec;
int ret;
size_t cmsg_len = CMSG_LEN(sizeof(int));
struct cmsghdr *cmsg = alloca(cmsg_len);
int *fds = (int *) CMSG_DATA(cmsg);
struct msghdr msghdr;
struct iovec vec;
vec.iov_base = (void *)&data;
vec.iov_len = len;
vec.iov_base = (void *)&data;
vec.iov_len = len;
cmsg->cmsg_len = cmsg_len;
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
*fds = fd;
cmsg->cmsg_len = cmsg_len;
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
*fds = fd;
msghdr.msg_name = NULL;
msghdr.msg_namelen = 0;
msghdr.msg_iov = &vec;
msghdr.msg_iovlen = 1;
msghdr.msg_control = cmsg;
msghdr.msg_controllen = cmsg_len;
msghdr.msg_flags = 0;
msghdr.msg_name = NULL;
msghdr.msg_namelen = 0;
msghdr.msg_iov = &vec;
msghdr.msg_iovlen = 1;
msghdr.msg_control = cmsg;
msghdr.msg_controllen = cmsg_len;
msghdr.msg_flags = 0;
ret = sendmsg(sock, &msghdr, 0 );
if (ret < 0) {
SYSERROR("sendmsg failed");
return -errno;
}
return ret;
ret = sendmsg(sock, &msghdr, 0 );
if (ret < 0) {
SYSERROR("sendmsg failed");
return -errno;
}
return ret;
}
struct pollfd *pollfds;
@ -271,6 +271,44 @@ static int pcm_handler(waiter_t *waiter, unsigned short events)
}
#endif
static void pcm_shm_hw_ptr_changed(snd_pcm_t *pcm, snd_pcm_t *src ATTRIBUTE_UNUSED)
{
client_t *client = pcm->hw.private_data;
volatile snd_pcm_shm_ctrl_t *ctrl = client->transport.shm.ctrl;
snd_pcm_t *loop;
ctrl->hw.changed = 1;
if (pcm->hw.fd >= 0) {
ctrl->hw.use_mmap = 1;
ctrl->hw.offset = pcm->hw.offset;
return;
}
ctrl->hw.use_mmap = 0;
ctrl->hw.ptr = pcm->hw.ptr ? *pcm->hw.ptr : 0;
for (loop = pcm->hw.master; loop; loop = loop->hw.master)
loop->hw.ptr = &ctrl->hw.ptr;
pcm->hw.ptr = &ctrl->hw.ptr;
}
static void pcm_shm_appl_ptr_changed(snd_pcm_t *pcm, snd_pcm_t *src ATTRIBUTE_UNUSED)
{
client_t *client = pcm->appl.private_data;
volatile snd_pcm_shm_ctrl_t *ctrl = client->transport.shm.ctrl;
snd_pcm_t *loop;
ctrl->appl.changed = 1;
if (pcm->appl.fd >= 0) {
ctrl->appl.use_mmap = 1;
ctrl->appl.offset = pcm->appl.offset;
return;
}
ctrl->appl.use_mmap = 0;
ctrl->appl.ptr = pcm->appl.ptr ? *pcm->appl.ptr : 0;
for (loop = pcm->appl.master; loop; loop = loop->appl.master)
loop->appl.ptr = &ctrl->appl.ptr;
pcm->appl.ptr = &ctrl->appl.ptr;
}
static int pcm_shm_open(client_t *client, int *cookie)
{
int shmid;
@ -282,6 +320,10 @@ static int pcm_shm_open(client_t *client, int *cookie)
return err;
client->device.pcm.handle = pcm;
client->device.pcm.fd = _snd_pcm_poll_descriptor(pcm);
pcm->hw.private_data = client;
pcm->hw.changed = pcm_shm_hw_ptr_changed;
pcm->appl.private_data = client;
pcm->appl.changed = pcm_shm_appl_ptr_changed;
shmid = shmget(IPC_PRIVATE, PCM_SHM_SIZE, 0666);
if (shmid < 0) {
@ -361,6 +403,13 @@ static int shm_ack_fd(client_t *client, int fd)
return 0;
}
static int shm_rbptr_fd(client_t *client, snd_pcm_rbptr_t *rbptr)
{
if (rbptr->fd < 0)
return -EINVAL;
return shm_ack_fd(client, rbptr->fd);
}
static void async_handler(snd_async_handler_t *handler)
{
client_t *client = snd_async_handler_get_callback_private(handler);
@ -424,22 +473,15 @@ static int pcm_shm_cmd(client_t *client)
break;
case SND_PCM_IOCTL_AVAIL_UPDATE:
ctrl->result = snd_pcm_avail_update(pcm);
ctrl->hw_ptr = *pcm->hw_ptr;
break;
case SNDRV_PCM_IOCTL_PREPARE:
ctrl->result = snd_pcm_prepare(pcm);
ctrl->appl_ptr = *pcm->appl_ptr;
ctrl->hw_ptr = *pcm->hw_ptr;
break;
case SNDRV_PCM_IOCTL_RESET:
ctrl->result = snd_pcm_reset(pcm);
ctrl->appl_ptr = *pcm->appl_ptr;
ctrl->hw_ptr = *pcm->hw_ptr;
break;
case SNDRV_PCM_IOCTL_START:
ctrl->result = snd_pcm_start(pcm);
ctrl->appl_ptr = *pcm->appl_ptr;
ctrl->hw_ptr = *pcm->hw_ptr;
break;
case SNDRV_PCM_IOCTL_DRAIN:
ctrl->result = snd_pcm_drain(pcm);
@ -458,7 +500,6 @@ static int pcm_shm_cmd(client_t *client)
break;
case SNDRV_PCM_IOCTL_REWIND:
ctrl->result = snd_pcm_rewind(pcm, ctrl->u.rewind.frames);
ctrl->appl_ptr = *pcm->appl_ptr;
break;
case SNDRV_PCM_IOCTL_LINK:
{
@ -485,7 +526,6 @@ static int pcm_shm_cmd(client_t *client)
ctrl->result = snd_pcm_mmap_commit(pcm,
ctrl->u.mmap_commit.offset,
ctrl->u.mmap_commit.frames);
ctrl->appl_ptr = *pcm->appl_ptr;
break;
case SND_PCM_IOCTL_POLL_DESCRIPTOR:
ctrl->result = 0;
@ -493,6 +533,10 @@ static int pcm_shm_cmd(client_t *client)
case SND_PCM_IOCTL_CLOSE:
client->ops->close(client);
break;
case SND_PCM_IOCTL_HW_PTR_FD:
return shm_rbptr_fd(client, &pcm->hw);
case SND_PCM_IOCTL_APPL_PTR_FD:
return shm_rbptr_fd(client, &pcm->appl);
default:
ERROR("Bogus cmd: %x", ctrl->cmd);
ctrl->result = -ENOSYS;

View file

@ -47,12 +47,21 @@ typedef enum _snd_transport_type {
#define SND_PCM_IOCTL_ASYNC _IO ('A', 0xf6)
#define SND_PCM_IOCTL_CLOSE _IO ('A', 0xf7)
#define SND_PCM_IOCTL_POLL_DESCRIPTOR _IO ('A', 0xf8)
#define SND_PCM_IOCTL_HW_PTR_FD _IO ('A', 0xf9)
#define SND_PCM_IOCTL_APPL_PTR_FD _IO ('A', 0xfa)
typedef struct {
snd_pcm_uframes_t ptr;
int use_mmap;
off_t offset; /* for mmap */
int changed;
} snd_pcm_shm_rbptr_t;
typedef struct {
long result;
int cmd;
snd_pcm_uframes_t hw_ptr;
snd_pcm_uframes_t appl_ptr;
snd_pcm_shm_rbptr_t hw;
snd_pcm_shm_rbptr_t appl;
union {
struct {
int sig;
@ -80,6 +89,11 @@ typedef struct {
snd_pcm_uframes_t offset;
snd_pcm_uframes_t frames;
} mmap_commit;
struct {
char use_mmap;
int shmid;
off_t offset;
} rbptr;
} u;
char data[0];
} snd_pcm_shm_ctrl_t;

View file

@ -139,6 +139,7 @@ typedef enum _snd_set_mode {
size_t page_align(size_t size);
size_t page_size(void);
size_t page_ptr(size_t object_offset, size_t object_size, size_t *offset, size_t *mmap_offset);
int safe_strtol(const char *str, long *val);

View file

@ -827,8 +827,8 @@ int snd_pcm_format_set_silence(snd_pcm_format_t format, void *buf, unsigned int
snd_pcm_sframes_t snd_pcm_bytes_to_frames(snd_pcm_t *pcm, ssize_t bytes);
ssize_t snd_pcm_frames_to_bytes(snd_pcm_t *pcm, snd_pcm_sframes_t frames);
int snd_pcm_bytes_to_samples(snd_pcm_t *pcm, ssize_t bytes);
ssize_t snd_pcm_samples_to_bytes(snd_pcm_t *pcm, int samples);
long snd_pcm_bytes_to_samples(snd_pcm_t *pcm, ssize_t bytes);
ssize_t snd_pcm_samples_to_bytes(snd_pcm_t *pcm, long samples);
int snd_pcm_area_silence(const snd_pcm_channel_area_t *dst_channel, snd_pcm_uframes_t dst_offset,
unsigned int samples, snd_pcm_format_t format);

View file

@ -1528,7 +1528,7 @@ ssize_t snd_pcm_frames_to_bytes(snd_pcm_t *pcm, snd_pcm_sframes_t frames)
* \param bytes quantity in bytes
* \return quantity expressed in samples
*/
int snd_pcm_bytes_to_samples(snd_pcm_t *pcm, ssize_t bytes)
long snd_pcm_bytes_to_samples(snd_pcm_t *pcm, ssize_t bytes)
{
assert(pcm);
assert(pcm->setup);
@ -1541,7 +1541,7 @@ int snd_pcm_bytes_to_samples(snd_pcm_t *pcm, ssize_t bytes)
* \param samples quantity in samples
* \return quantity expressed in bytes
*/
ssize_t snd_pcm_samples_to_bytes(snd_pcm_t *pcm, int samples)
ssize_t snd_pcm_samples_to_bytes(snd_pcm_t *pcm, long samples)
{
assert(pcm);
assert(pcm->setup);
@ -5131,7 +5131,7 @@ int snd_pcm_mmap_begin(snd_pcm_t *pcm,
*areas = pcm->stopped_areas;
else
*areas = pcm->running_areas;
*offset = *pcm->appl_ptr % pcm->buffer_size;
*offset = *pcm->appl.ptr % pcm->buffer_size;
cont = pcm->buffer_size - *offset;
f = *frames;
avail = snd_pcm_mmap_avail(pcm);
@ -5202,7 +5202,7 @@ snd_pcm_sframes_t snd_pcm_mmap_commit(snd_pcm_t *pcm,
snd_pcm_uframes_t frames)
{
assert(pcm);
assert(offset == *pcm->appl_ptr % pcm->buffer_size);
assert(offset == *pcm->appl.ptr % pcm->buffer_size);
assert(frames <= snd_pcm_mmap_avail(pcm));
return pcm->fast_ops->mmap_commit(pcm->fast_op_arg, offset, frames);
}
@ -5421,7 +5421,7 @@ snd_pcm_sframes_t snd_pcm_write_areas(snd_pcm_t *pcm, const snd_pcm_channel_area
snd_pcm_uframes_t _snd_pcm_mmap_hw_ptr(snd_pcm_t *pcm)
{
return *pcm->hw_ptr;
return *pcm->hw.ptr;
}
snd_pcm_uframes_t _snd_pcm_boundary(snd_pcm_t *pcm)
@ -5581,4 +5581,111 @@ int snd_pcm_conf_generic_id(const char *id)
return 0;
}
static void snd_pcm_set_ptr(snd_pcm_t *pcm, snd_pcm_rbptr_t *rbptr,
volatile snd_pcm_uframes_t *hw_ptr, int fd, off_t offset)
{
rbptr->master = NULL; /* I'm master */
rbptr->ptr = hw_ptr;
rbptr->fd = fd;
rbptr->offset = offset;
if (rbptr->changed)
rbptr->changed(pcm, NULL);
}
void snd_pcm_set_hw_ptr(snd_pcm_t *pcm, volatile snd_pcm_uframes_t *hw_ptr, int fd, off_t offset)
{
assert(pcm);
assert(hw_ptr);
snd_pcm_set_ptr(pcm, &pcm->hw, hw_ptr, fd, offset);
}
void snd_pcm_set_appl_ptr(snd_pcm_t *pcm, volatile snd_pcm_uframes_t *appl_ptr, int fd, off_t offset)
{
assert(pcm);
assert(appl_ptr);
snd_pcm_set_ptr(pcm, &pcm->appl, appl_ptr, fd, offset);
}
static void snd_pcm_link_ptr(snd_pcm_t *pcm, snd_pcm_rbptr_t *pcm_rbptr,
snd_pcm_t *slave, snd_pcm_rbptr_t *slave_rbptr)
{
snd_pcm_t **a;
int idx;
a = slave_rbptr->link_dst;
for (idx = 0; idx < slave_rbptr->link_dst_count; idx++)
if (a[idx] == NULL) {
a[idx] = pcm;
goto __found_free_place;
}
a = realloc(a, sizeof(snd_pcm_t *) * (slave_rbptr->link_dst_count + 1));
if (a == NULL) {
pcm_rbptr->ptr = NULL;
pcm_rbptr->fd = -1;
pcm_rbptr->offset = 0UL;
return;
}
a[slave_rbptr->link_dst_count++] = pcm;
__found_free_place:
pcm_rbptr->master = slave_rbptr->master ? slave_rbptr->master : slave;
pcm_rbptr->ptr = slave_rbptr->ptr;
pcm_rbptr->fd = slave_rbptr->fd;
pcm_rbptr->offset = slave_rbptr->offset;
slave_rbptr->link_dst = a;
if (pcm_rbptr->changed)
pcm_rbptr->changed(pcm, slave);
}
static void snd_pcm_unlink_ptr(snd_pcm_t *pcm, snd_pcm_rbptr_t *pcm_rbptr,
snd_pcm_t *slave, snd_pcm_rbptr_t *slave_rbptr)
{
snd_pcm_t **a;
int idx;
a = slave_rbptr->link_dst;
for (idx = 0; idx < slave_rbptr->link_dst_count; idx++)
if (a[idx] == pcm) {
a[idx] = NULL;
goto __found;
}
assert(0);
return;
__found:
pcm_rbptr->master = NULL;
pcm_rbptr->ptr = NULL;
pcm_rbptr->fd = -1;
pcm_rbptr->offset = 0UL;
if (pcm_rbptr->changed)
pcm_rbptr->changed(pcm, slave);
}
void snd_pcm_link_hw_ptr(snd_pcm_t *pcm, snd_pcm_t *slave)
{
assert(pcm);
assert(slave);
snd_pcm_link_ptr(pcm, &pcm->hw, slave, &slave->hw);
}
void snd_pcm_link_appl_ptr(snd_pcm_t *pcm, snd_pcm_t *slave)
{
assert(pcm);
assert(slave);
snd_pcm_link_ptr(pcm, &pcm->appl, slave, &slave->appl);
}
void snd_pcm_unlink_hw_ptr(snd_pcm_t *pcm, snd_pcm_t *slave)
{
assert(pcm);
assert(slave);
snd_pcm_unlink_ptr(pcm, &pcm->hw, slave, &slave->hw);
}
void snd_pcm_unlink_appl_ptr(snd_pcm_t *pcm, snd_pcm_t *slave)
{
assert(pcm);
assert(slave);
snd_pcm_unlink_ptr(pcm, &pcm->appl, slave, &slave->appl);
}
#endif

View file

@ -569,8 +569,8 @@ int snd_pcm_adpcm_open(snd_pcm_t **pcmp, const char *name, snd_pcm_format_t sfor
pcm->fast_ops = &snd_pcm_plugin_fast_ops;
pcm->private_data = adpcm;
pcm->poll_fd = slave->poll_fd;
pcm->hw_ptr = &adpcm->plug.hw_ptr;
pcm->appl_ptr = &adpcm->plug.appl_ptr;
snd_pcm_set_hw_ptr(pcm, &adpcm->plug.hw_ptr, -1, 0);
snd_pcm_set_appl_ptr(pcm, &adpcm->plug.appl_ptr, -1, 0);
*pcmp = pcm;
return 0;

View file

@ -442,8 +442,8 @@ int snd_pcm_alaw_open(snd_pcm_t **pcmp, const char *name, snd_pcm_format_t sform
pcm->fast_ops = &snd_pcm_plugin_fast_ops;
pcm->private_data = alaw;
pcm->poll_fd = slave->poll_fd;
pcm->hw_ptr = &alaw->plug.hw_ptr;
pcm->appl_ptr = &alaw->plug.appl_ptr;
snd_pcm_set_hw_ptr(pcm, &alaw->plug.hw_ptr, -1, 0);
snd_pcm_set_appl_ptr(pcm, &alaw->plug.appl_ptr, -1, 0);
*pcmp = pcm;
return 0;

View file

@ -205,8 +205,8 @@ int snd_pcm_copy_open(snd_pcm_t **pcmp, const char *name, snd_pcm_t *slave, int
pcm->fast_ops = &snd_pcm_plugin_fast_ops;
pcm->private_data = copy;
pcm->poll_fd = slave->poll_fd;
pcm->hw_ptr = &copy->plug.hw_ptr;
pcm->appl_ptr = &copy->plug.appl_ptr;
snd_pcm_set_hw_ptr(pcm, &copy->plug.hw_ptr, -1, 0);
snd_pcm_set_appl_ptr(pcm, &copy->plug.appl_ptr, -1, 0);
*pcmp = pcm;
return 0;

View file

@ -485,8 +485,8 @@ int snd_pcm_file_open(snd_pcm_t **pcmp, const char *name,
pcm->fast_ops = &snd_pcm_file_fast_ops;
pcm->private_data = file;
pcm->poll_fd = slave->poll_fd;
pcm->hw_ptr = slave->hw_ptr;
pcm->appl_ptr = slave->appl_ptr;
snd_pcm_link_hw_ptr(pcm, slave);
snd_pcm_link_appl_ptr(pcm, slave);
*pcmp = pcm;
return 0;

View file

@ -344,8 +344,8 @@ int snd_pcm_hooks_open(snd_pcm_t **pcmp, const char *name, snd_pcm_t *slave, int
pcm->fast_ops = &snd_pcm_hooks_fast_ops;
pcm->private_data = h;
pcm->poll_fd = slave->poll_fd;
pcm->hw_ptr = slave->hw_ptr;
pcm->appl_ptr = slave->appl_ptr;
snd_pcm_link_hw_ptr(pcm, slave);
snd_pcm_link_appl_ptr(pcm, slave);
*pcmp = pcm;
return 0;

View file

@ -29,6 +29,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
@ -60,7 +61,7 @@ typedef struct {
int fd;
int card, device, subdevice;
int mmap_emulation;
volatile struct sndrv_pcm_mmap_status *mmap_status;
volatile struct sndrv_pcm_mmap_status * mmap_status;
struct sndrv_pcm_mmap_control *mmap_control;
int shadow_appl_ptr: 1,
avail_update_flag: 1,
@ -256,10 +257,10 @@ static int snd_pcm_hw_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params)
if (hw->mmap_shm) {
hw->shadow_appl_ptr = 1;
hw->appl_ptr = 0;
pcm->appl_ptr = &hw->appl_ptr;
snd_pcm_set_appl_ptr(pcm, &hw->appl_ptr, -1, 0);
} else {
hw->shadow_appl_ptr = 0;
pcm->appl_ptr = &hw->mmap_control->appl_ptr;
snd_pcm_set_appl_ptr(pcm, &hw->mmap_control->appl_ptr, hw->fd, SNDRV_PCM_MMAP_OFFSET_CONTROL);
}
}
return 0;
@ -529,7 +530,7 @@ static int snd_pcm_hw_mmap_status(snd_pcm_t *pcm)
return -errno;
}
hw->mmap_status = ptr;
pcm->hw_ptr = &hw->mmap_status->hw_ptr;
snd_pcm_set_hw_ptr(pcm, &hw->mmap_status->hw_ptr, hw->fd, SNDRV_PCM_MMAP_OFFSET_STATUS + offsetof(struct sndrv_pcm_mmap_status, hw_ptr));
return 0;
}
@ -545,7 +546,7 @@ static int snd_pcm_hw_mmap_control(snd_pcm_t *pcm)
return -errno;
}
hw->mmap_control = ptr;
pcm->appl_ptr = &hw->mmap_control->appl_ptr;
snd_pcm_set_appl_ptr(pcm, &hw->mmap_control->appl_ptr, hw->fd, SNDRV_PCM_MMAP_OFFSET_CONTROL);
return 0;
}

View file

@ -1173,8 +1173,8 @@ int snd_pcm_ladspa_open(snd_pcm_t **pcmp, const char *name,
pcm->fast_ops = &snd_pcm_plugin_fast_ops;
pcm->private_data = ladspa;
pcm->poll_fd = slave->poll_fd;
pcm->hw_ptr = &ladspa->plug.hw_ptr;
pcm->appl_ptr = &ladspa->plug.appl_ptr;
snd_pcm_set_hw_ptr(pcm, &ladspa->plug.hw_ptr, -1, 0);
snd_pcm_set_appl_ptr(pcm, &ladspa->plug.appl_ptr, -1, 0);
*pcmp = pcm;
return 0;

View file

@ -407,8 +407,8 @@ int snd_pcm_lfloat_open(snd_pcm_t **pcmp, const char *name, snd_pcm_format_t sfo
pcm->fast_ops = &snd_pcm_plugin_fast_ops;
pcm->private_data = lfloat;
pcm->poll_fd = slave->poll_fd;
pcm->hw_ptr = &lfloat->plug.hw_ptr;
pcm->appl_ptr = &lfloat->plug.appl_ptr;
snd_pcm_set_hw_ptr(pcm, &lfloat->plug.hw_ptr, -1, 0);
snd_pcm_set_appl_ptr(pcm, &lfloat->plug.appl_ptr, -1, 0);
*pcmp = pcm;
return 0;

View file

@ -346,8 +346,8 @@ int snd_pcm_linear_open(snd_pcm_t **pcmp, const char *name, snd_pcm_format_t sfo
pcm->fast_ops = &snd_pcm_plugin_fast_ops;
pcm->private_data = linear;
pcm->poll_fd = slave->poll_fd;
pcm->hw_ptr = &linear->plug.hw_ptr;
pcm->appl_ptr = &linear->plug.appl_ptr;
snd_pcm_set_hw_ptr(pcm, &linear->plug.hw_ptr, -1, 0);
snd_pcm_set_appl_ptr(pcm, &linear->plug.appl_ptr, -1, 0);
*pcmp = pcm;
return 0;

View file

@ -91,6 +91,17 @@ typedef enum sndrv_pcm_hw_param snd_pcm_hw_param_t;
/** device can do a kind of synchronized start */
#define SND_PCM_INFO_SYNC_START SNDRV_PCM_INFO_SYNC_START
typedef struct _snd_pcm_rbptr {
snd_pcm_t *master;
volatile snd_pcm_uframes_t *ptr;
int fd;
off_t offset;
int link_dst_count;
snd_pcm_t **link_dst;
void *private_data;
void (*changed)(snd_pcm_t *pcm, snd_pcm_t *src);
} snd_pcm_rbptr_t;
typedef struct _snd_pcm_channel_info {
unsigned int channel;
void *addr; /* base address of channel samples */
@ -178,9 +189,9 @@ struct _snd_pcm {
snd_pcm_uframes_t buffer_size;
unsigned int sample_bits;
unsigned int frame_bits;
snd_pcm_uframes_t *appl_ptr;
snd_pcm_rbptr_t appl;
snd_pcm_rbptr_t hw;
snd_pcm_uframes_t min_align;
volatile snd_pcm_uframes_t *hw_ptr;
int mmap_rw;
snd_pcm_channel_info_t *mmap_channels;
snd_pcm_channel_area_t *running_areas;
@ -207,6 +218,12 @@ int snd_pcm_async(snd_pcm_t *pcm, int sig, pid_t pid);
int snd_pcm_mmap(snd_pcm_t *pcm);
int snd_pcm_munmap(snd_pcm_t *pcm);
int snd_pcm_mmap_ready(snd_pcm_t *pcm);
void snd_pcm_set_hw_ptr(snd_pcm_t *pcm, volatile snd_pcm_uframes_t *hw_ptr, int fd, off_t offset);
void snd_pcm_set_appl_ptr(snd_pcm_t *pcm, volatile snd_pcm_uframes_t *appl_ptr, int fd, off_t offset);
void snd_pcm_link_hw_ptr(snd_pcm_t *pcm, snd_pcm_t *slave);
void snd_pcm_link_appl_ptr(snd_pcm_t *pcm, snd_pcm_t *slave);
void snd_pcm_unlink_hw_ptr(snd_pcm_t *pcm, snd_pcm_t *slave);
void snd_pcm_unlink_appl_ptr(snd_pcm_t *pcm, snd_pcm_t *slave);
snd_pcm_sframes_t snd_pcm_mmap_appl_ptr(snd_pcm_t *pcm, off_t offset);
void snd_pcm_mmap_appl_backward(snd_pcm_t *pcm, snd_pcm_uframes_t frames);
void snd_pcm_mmap_appl_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames);
@ -238,7 +255,7 @@ int _snd_pcm_poll_descriptor(snd_pcm_t *pcm);
static inline snd_pcm_uframes_t snd_pcm_mmap_playback_avail(snd_pcm_t *pcm)
{
snd_pcm_sframes_t avail;
avail = *pcm->hw_ptr + pcm->buffer_size - *pcm->appl_ptr;
avail = *pcm->hw.ptr + pcm->buffer_size - *pcm->appl.ptr;
if (avail < 0)
avail += pcm->boundary;
else if ((snd_pcm_uframes_t) avail >= pcm->boundary)
@ -249,7 +266,7 @@ static inline snd_pcm_uframes_t snd_pcm_mmap_playback_avail(snd_pcm_t *pcm)
static inline snd_pcm_uframes_t snd_pcm_mmap_capture_avail(snd_pcm_t *pcm)
{
snd_pcm_sframes_t avail;
avail = *pcm->hw_ptr - *pcm->appl_ptr;
avail = *pcm->hw.ptr - *pcm->appl.ptr;
if (avail < 0)
avail += pcm->boundary;
return avail;
@ -276,7 +293,7 @@ static inline snd_pcm_sframes_t snd_pcm_mmap_capture_hw_avail(snd_pcm_t *pcm)
static inline snd_pcm_sframes_t snd_pcm_mmap_hw_avail(snd_pcm_t *pcm)
{
snd_pcm_sframes_t avail;
avail = *pcm->hw_ptr - *pcm->appl_ptr;
avail = *pcm->hw.ptr - *pcm->appl.ptr;
if (pcm->stream == SND_PCM_STREAM_PLAYBACK)
avail += pcm->buffer_size;
if (avail < 0)
@ -295,13 +312,13 @@ static inline const snd_pcm_channel_area_t *snd_pcm_mmap_areas(snd_pcm_t *pcm)
static inline snd_pcm_uframes_t snd_pcm_mmap_offset(snd_pcm_t *pcm)
{
assert(pcm);
return *pcm->appl_ptr % pcm->buffer_size;
return *pcm->appl.ptr % pcm->buffer_size;
}
static inline snd_pcm_uframes_t snd_pcm_mmap_hw_offset(snd_pcm_t *pcm)
{
assert(pcm);
return *pcm->hw_ptr % pcm->buffer_size;
return *pcm->hw.ptr % pcm->buffer_size;
}
#define snd_pcm_mmap_playback_delay snd_pcm_mmap_playback_hw_avail

View file

@ -105,7 +105,7 @@ static void snd_pcm_meter_update_main(snd_pcm_t *pcm)
int locked;
locked = (pthread_mutex_trylock(&meter->update_mutex) >= 0);
areas = snd_pcm_mmap_areas(pcm);
rptr = *pcm->hw_ptr;
rptr = *pcm->hw.ptr;
old_rptr = meter->rptr;
meter->rptr = rptr;
frames = rptr - old_rptr;
@ -131,7 +131,7 @@ static int snd_pcm_meter_update_scope(snd_pcm_t *pcm)
pthread_mutex_lock(&meter->update_mutex);
areas = snd_pcm_mmap_areas(pcm);
_again:
rptr = *pcm->hw_ptr;
rptr = *pcm->hw.ptr;
old_rptr = meter->rptr;
rmb();
if (atomic_read(&meter->reset)) {
@ -333,9 +333,9 @@ static int snd_pcm_meter_prepare(snd_pcm_t *pcm)
err = snd_pcm_prepare(meter->slave);
if (err >= 0) {
if (pcm->stream == SND_PCM_STREAM_PLAYBACK)
meter->rptr = *pcm->appl_ptr;
meter->rptr = *pcm->appl.ptr;
else
meter->rptr = *pcm->hw_ptr;
meter->rptr = *pcm->hw.ptr;
}
return err;
}
@ -346,7 +346,7 @@ static int snd_pcm_meter_reset(snd_pcm_t *pcm)
int err = snd_pcm_reset(meter->slave);
if (err >= 0) {
if (pcm->stream == SND_PCM_STREAM_PLAYBACK)
meter->rptr = *pcm->appl_ptr;
meter->rptr = *pcm->appl.ptr;
}
return err;
}
@ -386,7 +386,7 @@ static snd_pcm_sframes_t snd_pcm_meter_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t
snd_pcm_meter_t *meter = pcm->private_data;
snd_pcm_sframes_t err = snd_pcm_rewind(meter->slave, frames);
if (err > 0 && pcm->stream == SND_PCM_STREAM_PLAYBACK)
meter->rptr = *pcm->appl_ptr;
meter->rptr = *pcm->appl.ptr;
return err;
}
@ -401,13 +401,13 @@ static snd_pcm_sframes_t snd_pcm_meter_mmap_commit(snd_pcm_t *pcm,
snd_pcm_uframes_t size)
{
snd_pcm_meter_t *meter = pcm->private_data;
snd_pcm_uframes_t old_rptr = *pcm->appl_ptr;
snd_pcm_uframes_t old_rptr = *pcm->appl.ptr;
snd_pcm_sframes_t result = snd_pcm_mmap_commit(meter->slave, offset, size);
if (result <= 0)
return result;
if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
snd_pcm_meter_add_frames(pcm, snd_pcm_mmap_areas(pcm), old_rptr, result);
meter->rptr = *pcm->appl_ptr;
meter->rptr = *pcm->appl.ptr;
}
return result;
}
@ -648,8 +648,8 @@ int snd_pcm_meter_open(snd_pcm_t **pcmp, const char *name, unsigned int frequenc
pcm->fast_ops = &snd_pcm_meter_fast_ops;
pcm->private_data = meter;
pcm->poll_fd = slave->poll_fd;
pcm->hw_ptr = slave->hw_ptr;
pcm->appl_ptr = slave->appl_ptr;
snd_pcm_link_hw_ptr(pcm, slave);
snd_pcm_link_appl_ptr(pcm, slave);
*pcmp = pcm;
pthread_mutex_init(&meter->update_mutex, NULL);

View file

@ -36,48 +36,66 @@ size_t page_size(void)
size_t page_align(size_t size)
{
size_t r;
long psz = sysconf(_SC_PAGE_SIZE);
assert(psz > 0);
long psz = page_size();
r = size % psz;
if (r)
return size + psz - r;
return size;
}
size_t page_ptr(size_t object_offset, size_t object_size, size_t *offset, size_t *mmap_offset)
{
size_t r;
long psz = page_size();
assert(offset);
assert(mmap_offset);
*mmap_offset = object_offset;
object_offset %= psz;
*mmap_offset -= object_offset;
object_size += object_offset;
r = object_size % psz;
if (r)
r = object_size + psz - r;
else
r = object_size;
*offset = object_offset;
return r;
}
void snd_pcm_mmap_appl_backward(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
{
snd_pcm_sframes_t appl_ptr = *pcm->appl_ptr;
snd_pcm_sframes_t appl_ptr = *pcm->appl.ptr;
appl_ptr -= frames;
if (appl_ptr < 0)
appl_ptr += pcm->boundary;
*pcm->appl_ptr = appl_ptr;
*pcm->appl.ptr = appl_ptr;
}
void snd_pcm_mmap_appl_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
{
snd_pcm_uframes_t appl_ptr = *pcm->appl_ptr;
snd_pcm_uframes_t appl_ptr = *pcm->appl.ptr;
appl_ptr += frames;
if (appl_ptr >= pcm->boundary)
appl_ptr -= pcm->boundary;
*pcm->appl_ptr = appl_ptr;
*pcm->appl.ptr = appl_ptr;
}
void snd_pcm_mmap_hw_backward(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
{
snd_pcm_sframes_t hw_ptr = *pcm->hw_ptr;
snd_pcm_sframes_t hw_ptr = *pcm->hw.ptr;
hw_ptr -= frames;
if (hw_ptr < 0)
hw_ptr += pcm->boundary;
*pcm->hw_ptr = hw_ptr;
*pcm->hw.ptr = hw_ptr;
}
void snd_pcm_mmap_hw_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
{
snd_pcm_uframes_t hw_ptr = *pcm->hw_ptr;
snd_pcm_uframes_t hw_ptr = *pcm->hw.ptr;
hw_ptr += frames;
if (hw_ptr >= pcm->boundary)
hw_ptr -= pcm->boundary;
*pcm->hw_ptr = hw_ptr;
*pcm->hw.ptr = hw_ptr;
}
static snd_pcm_sframes_t snd_pcm_mmap_write_areas(snd_pcm_t *pcm,

View file

@ -457,8 +457,8 @@ int snd_pcm_mulaw_open(snd_pcm_t **pcmp, const char *name, snd_pcm_format_t sfor
pcm->fast_ops = &snd_pcm_plugin_fast_ops;
pcm->private_data = mulaw;
pcm->poll_fd = slave->poll_fd;
pcm->hw_ptr = &mulaw->plug.hw_ptr;
pcm->appl_ptr = &mulaw->plug.appl_ptr;
snd_pcm_set_hw_ptr(pcm, &mulaw->plug.hw_ptr, -1, 0);
snd_pcm_set_appl_ptr(pcm, &mulaw->plug.appl_ptr, -1, 0);
*pcmp = pcm;
return 0;

View file

@ -690,8 +690,8 @@ int snd_pcm_multi_open(snd_pcm_t **pcmp, const char *name,
pcm->fast_ops = &snd_pcm_multi_fast_ops;
pcm->private_data = multi;
pcm->poll_fd = multi->slaves[master_slave].pcm->poll_fd;
pcm->hw_ptr = multi->slaves[master_slave].pcm->hw_ptr;
pcm->appl_ptr = multi->slaves[master_slave].pcm->appl_ptr;
snd_pcm_link_hw_ptr(pcm, multi->slaves[master_slave].pcm);
snd_pcm_link_appl_ptr(pcm, multi->slaves[master_slave].pcm);
*pcmp = pcm;
return 0;
}

View file

@ -112,16 +112,15 @@ static int snd_pcm_null_prepare(snd_pcm_t *pcm)
{
snd_pcm_null_t *null = pcm->private_data;
null->state = SND_PCM_STATE_PREPARED;
null->appl_ptr = 0;
null->hw_ptr = 0;
*pcm->appl.ptr = 0;
*pcm->hw.ptr = 0;
return 0;
}
static int snd_pcm_null_reset(snd_pcm_t *pcm)
{
snd_pcm_null_t *null = pcm->private_data;
null->appl_ptr = 0;
null->hw_ptr = 0;
*pcm->appl.ptr = 0;
*pcm->hw.ptr = 0;
return 0;
}
@ -131,9 +130,9 @@ static int snd_pcm_null_start(snd_pcm_t *pcm)
assert(null->state == SND_PCM_STATE_PREPARED);
null->state = SND_PCM_STATE_RUNNING;
if (pcm->stream == SND_PCM_STREAM_CAPTURE)
*pcm->hw_ptr = *pcm->appl_ptr + pcm->buffer_size;
*pcm->hw.ptr = *pcm->appl.ptr + pcm->buffer_size;
else
*pcm->hw_ptr = *pcm->appl_ptr;
*pcm->hw.ptr = *pcm->appl.ptr;
return 0;
}
@ -387,8 +386,8 @@ int snd_pcm_null_open(snd_pcm_t **pcmp, const char *name, snd_pcm_stream_t strea
pcm->fast_ops = &snd_pcm_null_fast_ops;
pcm->private_data = null;
pcm->poll_fd = fd;
pcm->hw_ptr = &null->hw_ptr;
pcm->appl_ptr = &null->appl_ptr;
snd_pcm_set_hw_ptr(pcm, &null->hw_ptr, -1, 0);
snd_pcm_set_appl_ptr(pcm, &null->appl_ptr, -1, 0);
*pcmp = pcm;
return 0;

View file

@ -832,8 +832,10 @@ static int snd_pcm_plug_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
snd_pcm_plug_clear(pcm);
return err;
}
pcm->hw_ptr = slave->hw_ptr;
pcm->appl_ptr = slave->appl_ptr;
snd_pcm_unlink_hw_ptr(pcm, plug->req_slave);
snd_pcm_unlink_appl_ptr(pcm, plug->req_slave);
snd_pcm_link_hw_ptr(pcm, slave);
snd_pcm_link_appl_ptr(pcm, slave);
return 0;
}
@ -915,6 +917,7 @@ int snd_pcm_plug_open(snd_pcm_t **pcmp,
snd_pcm_plug_t *plug;
int err;
assert(pcmp && slave);
plug = calloc(1, sizeof(snd_pcm_plug_t));
if (!plug)
return -ENOMEM;
@ -939,8 +942,8 @@ int snd_pcm_plug_open(snd_pcm_t **pcmp,
pcm->fast_op_arg = slave->fast_op_arg;
pcm->private_data = plug;
pcm->poll_fd = slave->poll_fd;
pcm->hw_ptr = slave->hw_ptr;
pcm->appl_ptr = slave->appl_ptr;
snd_pcm_link_hw_ptr(pcm, slave);
snd_pcm_link_appl_ptr(pcm, slave);
*pcmp = pcm;
return 0;

View file

@ -211,8 +211,8 @@ int snd_pcm_plugin_prepare(snd_pcm_t *pcm)
snd_atomic_write_end(&plugin->watom);
return err;
}
plugin->hw_ptr = 0;
plugin->appl_ptr = 0;
*pcm->hw.ptr = 0;
*pcm->appl.ptr = 0;
snd_atomic_write_end(&plugin->watom);
if (plugin->init) {
err = plugin->init(pcm);
@ -232,8 +232,8 @@ static int snd_pcm_plugin_reset(snd_pcm_t *pcm)
snd_atomic_write_end(&plugin->watom);
return err;
}
plugin->hw_ptr = 0;
plugin->appl_ptr = 0;
*pcm->hw.ptr = 0;
*pcm->appl.ptr = 0;
snd_atomic_write_end(&plugin->watom);
if (plugin->init) {
err = plugin->init(pcm);
@ -504,12 +504,12 @@ snd_pcm_sframes_t snd_pcm_plugin_avail_update(snd_pcm_t *pcm)
pcm->access != SND_PCM_ACCESS_RW_NONINTERLEAVED)
goto _capture;
if (plugin->client_frames) {
plugin->hw_ptr = plugin->client_frames(pcm, *slave->hw_ptr);
*pcm->hw.ptr = plugin->client_frames(pcm, *slave->hw.ptr);
if (slave_size <= 0)
return slave_size;
return plugin->client_frames(pcm, slave_size);
} else {
plugin->hw_ptr = *slave->hw_ptr;
*pcm->hw.ptr = *slave->hw.ptr;
return slave_size;
}
_capture:
@ -599,8 +599,8 @@ int snd_pcm_plugin_status(snd_pcm_t *pcm, snd_pcm_status_t * status)
snd_atomic_read_ok(&ratom);
return err;
}
status->appl_ptr = plugin->appl_ptr;
status->hw_ptr = plugin->hw_ptr;
status->appl_ptr = *pcm->appl.ptr;
status->hw_ptr = *pcm->hw.ptr;
status->avail = pcm->buffer_size;
snd_pcm_plugin_delay(pcm, &status->delay);
if (!snd_atomic_read_ok(&ratom)) {

View file

@ -593,8 +593,8 @@ int snd_pcm_rate_open(snd_pcm_t **pcmp, const char *name, snd_pcm_format_t sform
pcm->fast_ops = &snd_pcm_plugin_fast_ops;
pcm->private_data = rate;
pcm->poll_fd = slave->poll_fd;
pcm->hw_ptr = &rate->plug.hw_ptr;
pcm->appl_ptr = &rate->plug.appl_ptr;
snd_pcm_set_hw_ptr(pcm, &rate->plug.hw_ptr, -1, 0);
snd_pcm_set_appl_ptr(pcm, &rate->plug.appl_ptr, -1, 0);
*pcmp = pcm;
return 0;

View file

@ -800,8 +800,8 @@ int snd_pcm_route_open(snd_pcm_t **pcmp, const char *name,
pcm->fast_ops = &snd_pcm_plugin_fast_ops;
pcm->private_data = route;
pcm->poll_fd = slave->poll_fd;
pcm->hw_ptr = &route->plug.hw_ptr;
pcm->appl_ptr = &route->plug.appl_ptr;
snd_pcm_set_hw_ptr(pcm, &route->plug.hw_ptr, -1, 0);
snd_pcm_set_appl_ptr(pcm, &route->plug.appl_ptr, -1, 0);
err = route_load_ttable(&route->params, pcm->stream, tt_ssize, ttable, tt_cused, tt_sused);
if (err < 0) {
snd_pcm_close(pcm);

View file

@ -123,7 +123,7 @@ static snd_pcm_uframes_t snd_pcm_share_slave_avail(snd_pcm_share_slave_t *slave)
{
snd_pcm_sframes_t avail;
snd_pcm_t *pcm = slave->pcm;
avail = slave->hw_ptr - *pcm->appl_ptr;
avail = slave->hw_ptr - *pcm->appl.ptr;
if (pcm->stream == SND_PCM_STREAM_PLAYBACK)
avail += pcm->buffer_size;
if (avail < 0)
@ -147,7 +147,7 @@ static snd_pcm_uframes_t _snd_pcm_share_slave_forward(snd_pcm_share_slave_t *sla
buffer_size = slave->pcm->buffer_size;
min_frames = slave_avail;
max_frames = 0;
slave_appl_ptr = *slave->pcm->appl_ptr;
slave_appl_ptr = *slave->pcm->appl.ptr;
list_for_each(i, &slave->clients) {
snd_pcm_share_t *share = list_entry(i, snd_pcm_share_t, list);
snd_pcm_t *pcm = share->pcm;
@ -336,7 +336,7 @@ static snd_pcm_uframes_t _snd_pcm_share_slave_missing(snd_pcm_share_slave_t *sla
snd_pcm_uframes_t missing = INT_MAX;
struct list_head *i;
/* snd_pcm_sframes_t avail = */ snd_pcm_avail_update(slave->pcm);
slave->hw_ptr = *slave->pcm->hw_ptr;
slave->hw_ptr = *slave->pcm->hw.ptr;
list_for_each(i, &slave->clients) {
snd_pcm_share_t *share = list_entry(i, snd_pcm_share_t, list);
snd_pcm_t *pcm = share->pcm;
@ -353,6 +353,7 @@ static void *snd_pcm_share_thread(void *data)
snd_pcm_t *spcm = slave->pcm;
struct pollfd pfd[2];
int err;
pfd[0].fd = slave->poll[0];
pfd[0].events = POLLIN;
err = snd_pcm_poll_descriptors(spcm, &pfd[1], 1);
@ -373,7 +374,7 @@ static void *snd_pcm_share_thread(void *data)
if (hw_ptr >= spcm->boundary)
hw_ptr -= spcm->boundary;
hw_ptr -= hw_ptr % spcm->period_size;
avail_min = hw_ptr - *spcm->appl_ptr;
avail_min = hw_ptr - *spcm->appl.ptr;
if (spcm->stream == SND_PCM_STREAM_PLAYBACK)
avail_min += spcm->buffer_size;
if (avail_min < 0)
@ -408,7 +409,7 @@ static void _snd_pcm_share_update(snd_pcm_t *pcm)
snd_pcm_t *spcm = slave->pcm;
snd_pcm_uframes_t missing;
/* snd_pcm_sframes_t avail = */ snd_pcm_avail_update(spcm);
slave->hw_ptr = *slave->pcm->hw_ptr;
slave->hw_ptr = *slave->pcm->hw.ptr;
missing = _snd_pcm_share_missing(pcm);
// printf("missing %ld\n", missing);
if (!slave->polling) {
@ -423,7 +424,7 @@ static void _snd_pcm_share_update(snd_pcm_t *pcm)
if (hw_ptr >= spcm->boundary)
hw_ptr -= spcm->boundary;
hw_ptr -= hw_ptr % spcm->period_size;
avail_min = hw_ptr - *spcm->appl_ptr;
avail_min = hw_ptr - *spcm->appl.ptr;
if (spcm->stream == SND_PCM_STREAM_PLAYBACK)
avail_min += spcm->buffer_size;
if (avail_min < 0)
@ -760,7 +761,7 @@ static snd_pcm_sframes_t snd_pcm_share_avail_update(snd_pcm_t *pcm)
Pthread_mutex_unlock(&slave->mutex);
return avail;
}
share->hw_ptr = *slave->pcm->hw_ptr;
share->hw_ptr = *slave->pcm->hw.ptr;
}
Pthread_mutex_unlock(&slave->mutex);
avail = snd_pcm_mmap_avail(pcm);
@ -781,7 +782,7 @@ static snd_pcm_sframes_t _snd_pcm_share_mmap_commit(snd_pcm_t *pcm,
snd_pcm_sframes_t frames;
if (pcm->stream == SND_PCM_STREAM_PLAYBACK &&
share->state == SND_PCM_STATE_RUNNING) {
frames = *spcm->appl_ptr - share->appl_ptr;
frames = *spcm->appl.ptr - share->appl_ptr;
if (frames > (snd_pcm_sframes_t)pcm->buffer_size)
frames -= pcm->boundary;
else if (frames < -(snd_pcm_sframes_t)pcm->buffer_size)
@ -860,7 +861,7 @@ static int snd_pcm_share_reset(snd_pcm_t *pcm)
/* FIXME? */
Pthread_mutex_lock(&slave->mutex);
snd_pcm_areas_silence(pcm->running_areas, 0, pcm->channels, pcm->buffer_size, pcm->format);
share->hw_ptr = *slave->pcm->hw_ptr;
share->hw_ptr = *slave->pcm->hw.ptr;
share->appl_ptr = share->hw_ptr;
Pthread_mutex_unlock(&slave->mutex);
return err;
@ -893,8 +894,8 @@ static int snd_pcm_share_start(snd_pcm_t *pcm)
goto _end;
}
assert(share->hw_ptr == 0);
share->hw_ptr = *spcm->hw_ptr;
share->appl_ptr = *spcm->appl_ptr;
share->hw_ptr = *spcm->hw.ptr;
share->appl_ptr = *spcm->appl.ptr;
while (xfer < hw_avail) {
snd_pcm_uframes_t frames = hw_avail - xfer;
snd_pcm_uframes_t offset = snd_pcm_mmap_offset(pcm);
@ -1142,6 +1143,7 @@ static int snd_pcm_share_close(snd_pcm_t *pcm)
snd_pcm_share_t *share = pcm->private_data;
snd_pcm_share_slave_t *slave = share->slave;
int err = 0;
Pthread_mutex_lock(&snd_pcm_share_slaves_mutex);
Pthread_mutex_lock(&slave->mutex);
slave->open_count--;
@ -1353,7 +1355,9 @@ int snd_pcm_share_open(snd_pcm_t **pcmp, const char *name, const char *sname,
free(share);
return err;
}
slave = calloc(1, sizeof(*slave));
/* FIXME: bellow is a real ugly hack to get things working */
/* there is a memory leak somewhere, but I'm unable to trace it --jk */
slave = calloc(1, sizeof(snd_pcm_share_slave_t) * 8);
if (!slave) {
Pthread_mutex_unlock(&snd_pcm_share_slaves_mutex);
snd_pcm_close(spcm);
@ -1408,8 +1412,8 @@ int snd_pcm_share_open(snd_pcm_t **pcmp, const char *name, const char *sname,
pcm->fast_ops = &snd_pcm_share_fast_ops;
pcm->private_data = share;
pcm->poll_fd = share->client_socket;
pcm->hw_ptr = &share->hw_ptr;
pcm->appl_ptr = &share->appl_ptr;
snd_pcm_set_hw_ptr(pcm, &share->hw_ptr, -1, 0);
snd_pcm_set_appl_ptr(pcm, &share->appl_ptr, -1, 0);
slave->open_count++;
list_add_tail(&share->list, &slave->clients);
@ -1424,7 +1428,11 @@ int snd_pcm_share_open(snd_pcm_t **pcmp, const char *name, const char *sname,
\section pcm_plugins_share Plugin: Share
This plugin allows sharing of multiple channels with more clients.
This plugin allows sharing of multiple channels with more clients. The access
to each channel is exlusive (samples are not mixed together). It means, if
the channel zero is used with first client, the channel cannot be used with
second one. If you are looking for a mixing plugin, use the
\ref pcm_plugins_smix "smix plugin".
\code
pcm.name {
@ -1433,8 +1441,6 @@ pcm.name {
# or
slave { # Slave definition
pcm STR # Slave PCM name
# or
pcm { } # Slave PCM definition
}
bindings {
N INT # Slave channel INT for client channel N
@ -1520,7 +1526,7 @@ int _snd_pcm_share_open(snd_pcm_t **pcmp, const char *name,
err = snd_config_get_string(sconf, &sname);
sname = err >= 0 && sname ? strdup(sname) : NULL;
snd_config_delete(sconf);
if (err < 0) {
if (sname == NULL) {
SNDERR("slave.pcm is not a string");
return err;
}

View file

@ -60,45 +60,100 @@ typedef struct {
#ifndef DOC_HIDDEN
int receive_fd(int sock, void *data, size_t len, int *fd)
{
int ret;
size_t cmsg_len = CMSG_LEN(sizeof(int));
struct cmsghdr *cmsg = alloca(cmsg_len);
int *fds = (int *) CMSG_DATA(cmsg);
struct msghdr msghdr;
struct iovec vec;
int ret;
size_t cmsg_len = CMSG_LEN(sizeof(int));
struct cmsghdr *cmsg = alloca(cmsg_len);
int *fds = (int *) CMSG_DATA(cmsg);
struct msghdr msghdr;
struct iovec vec;
vec.iov_base = (void *)&data;
vec.iov_len = len;
vec.iov_base = (void *)&data;
vec.iov_len = len;
cmsg->cmsg_len = cmsg_len;
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
*fds = -1;
cmsg->cmsg_len = cmsg_len;
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
*fds = -1;
msghdr.msg_name = NULL;
msghdr.msg_namelen = 0;
msghdr.msg_iov = &vec;
msghdr.msg_iovlen = 1;
msghdr.msg_control = cmsg;
msghdr.msg_controllen = cmsg_len;
msghdr.msg_flags = 0;
msghdr.msg_name = NULL;
msghdr.msg_namelen = 0;
msghdr.msg_iov = &vec;
msghdr.msg_iovlen = 1;
msghdr.msg_control = cmsg;
msghdr.msg_controllen = cmsg_len;
msghdr.msg_flags = 0;
ret = recvmsg(sock, &msghdr, 0);
if (ret < 0) {
SYSERR("recvmsg failed");
return -errno;
}
*fd = *fds;
return ret;
ret = recvmsg(sock, &msghdr, 0);
if (ret < 0) {
SYSERR("recvmsg failed");
return -errno;
}
*fd = *fds;
return ret;
}
#endif
static long snd_pcm_shm_action(snd_pcm_t *pcm)
static long snd_pcm_shm_action_fd0(snd_pcm_t *pcm, int *fd)
{
snd_pcm_shm_t *shm = pcm->private_data;
int err;
char buf[1];
volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl;
err = write(shm->socket, buf, 1);
if (err != 1)
return -EBADFD;
err = receive_fd(shm->socket, buf, 1, fd);
if (err != 1)
return -EBADFD;
if (ctrl->cmd) {
SNDERR("Server has not done the cmd");
return -EBADFD;
}
return ctrl->result;
}
static int snd_pcm_shm_new_rbptr(snd_pcm_t *pcm, snd_pcm_shm_t *shm,
snd_pcm_rbptr_t *rbptr, volatile snd_pcm_shm_rbptr_t *shm_rbptr)
{
if (!shm_rbptr->use_mmap) {
if (&pcm->hw == rbptr)
snd_pcm_set_hw_ptr(pcm, &shm_rbptr->ptr, -1, 0);
else
snd_pcm_set_appl_ptr(pcm, &shm_rbptr->ptr, -1, 0);
} else {
void *ptr;
size_t mmap_size, mmap_offset, offset;
int fd;
long result;
shm->ctrl->cmd = &pcm->hw == rbptr ? SND_PCM_IOCTL_HW_PTR_FD : SND_PCM_IOCTL_APPL_PTR_FD;
result = snd_pcm_shm_action_fd0(pcm, &fd);
if (result < 0)
return result;
mmap_size = page_ptr(shm_rbptr->offset, sizeof(snd_pcm_uframes_t), &offset, &mmap_offset);
ptr = mmap(NULL, mmap_size, PROT_READ|PROT_WRITE, MAP_FILE|MAP_SHARED, fd, mmap_offset);
if (ptr == MAP_FAILED || ptr == NULL) {
SYSERR("shm rbptr mmap failed");
return -errno;
}
if (&pcm->hw == rbptr)
snd_pcm_set_hw_ptr(pcm, (snd_pcm_uframes_t *)((char *)ptr + offset), fd, shm_rbptr->offset);
else
snd_pcm_set_appl_ptr(pcm, (snd_pcm_uframes_t *)((char *)ptr + offset), fd, shm_rbptr->offset);
}
return 0;
}
static long snd_pcm_shm_action(snd_pcm_t *pcm)
{
snd_pcm_shm_t *shm = pcm->private_data;
int err, result;
char buf[1];
volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl;
if (ctrl->hw.changed || ctrl->appl.changed)
return -EBADFD;
err = write(shm->socket, buf, 1);
if (err != 1)
return -EBADFD;
@ -109,7 +164,20 @@ static long snd_pcm_shm_action(snd_pcm_t *pcm)
SNDERR("Server has not done the cmd");
return -EBADFD;
}
return ctrl->result;
result = ctrl->result;
if (ctrl->hw.changed) {
err = snd_pcm_shm_new_rbptr(pcm, shm, &pcm->hw, &ctrl->hw);
if (err < 0)
return err;
ctrl->hw.changed = 0;
}
if (ctrl->appl.changed) {
err = snd_pcm_shm_new_rbptr(pcm, shm, &pcm->appl, &ctrl->appl);
if (err < 0)
return err;
ctrl->appl.changed = 0;
}
return result;
}
static long snd_pcm_shm_action_fd(snd_pcm_t *pcm, int *fd)
@ -118,6 +186,9 @@ static long snd_pcm_shm_action_fd(snd_pcm_t *pcm, int *fd)
int err;
char buf[1];
volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl;
if (ctrl->hw.changed || ctrl->appl.changed)
return -EBADFD;
err = write(shm->socket, buf, 1);
if (err != 1)
return -EBADFD;
@ -128,6 +199,18 @@ static long snd_pcm_shm_action_fd(snd_pcm_t *pcm, int *fd)
SNDERR("Server has not done the cmd");
return -EBADFD;
}
if (ctrl->hw.changed) {
err = snd_pcm_shm_new_rbptr(pcm, shm, &pcm->hw, &ctrl->hw);
if (err < 0)
return err;
ctrl->hw.changed = 0;
}
if (ctrl->appl.changed) {
err = snd_pcm_shm_new_rbptr(pcm, shm, &pcm->appl, &ctrl->appl);
if (err < 0)
return err;
ctrl->appl.changed = 0;
}
return ctrl->result;
}
@ -422,8 +505,13 @@ static int snd_pcm_shm_drain(snd_pcm_t *pcm)
snd_pcm_shm_t *shm = pcm->private_data;
volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl;
int err;
ctrl->cmd = SNDRV_PCM_IOCTL_DRAIN;
err = snd_pcm_shm_action(pcm);
do {
ctrl->cmd = SNDRV_PCM_IOCTL_DRAIN;
err = snd_pcm_shm_action(pcm);
if (err != -EAGAIN)
break;
usleep(10000);
} while (1);
if (err < 0)
return err;
if (!(pcm->mode & SND_PCM_NONBLOCK))
@ -691,8 +779,8 @@ int snd_pcm_shm_open(snd_pcm_t **pcmp, const char *name,
return err;
}
pcm->poll_fd = err;
pcm->hw_ptr = &ctrl->hw_ptr;
pcm->appl_ptr = &ctrl->appl_ptr;
snd_pcm_set_hw_ptr(pcm, &ctrl->hw.ptr, -1, 0);
snd_pcm_set_appl_ptr(pcm, &ctrl->appl.ptr, -1, 0);
*pcmp = pcm;
return 0;