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;
-
- 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;
-
- 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;
+ 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;
+
+ 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;
+
+ ret = sendmsg(sock, &msghdr, 0 );
+ if (ret < 0) {
+ SYSERROR("sendmsg failed");
+ return -errno;
+ }
+ return ret;
}
struct pollfd *pollfds;
}
#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;
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) {
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);
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);
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:
{
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;
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;
#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;
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;
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);
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);
* \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);
* \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);
*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);
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);
}
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)
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
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;
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;
pcm->fast_ops = &snd_pcm_plugin_fast_ops;
pcm->private_data = copy;
pcm->poll_fd = slave->poll_fd;
- pcm->hw_ptr = ©->plug.hw_ptr;
- pcm->appl_ptr = ©->plug.appl_ptr;
+ snd_pcm_set_hw_ptr(pcm, ©->plug.hw_ptr, -1, 0);
+ snd_pcm_set_appl_ptr(pcm, ©->plug.appl_ptr, -1, 0);
*pcmp = pcm;
return 0;
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;
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;
#include <stdio.h>
#include <stdlib.h>
+#include <stddef.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
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,
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;
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;
}
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;
}
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;
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;
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;
/** 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 */
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;
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);
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)
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;
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)
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
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;
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)) {
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;
}
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;
}
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;
}
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;
}
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);
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,
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;
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;
}
{
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;
}
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;
}
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;
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;
}
snd_pcm_plug_t *plug;
int err;
assert(pcmp && slave);
+
plug = calloc(1, sizeof(snd_pcm_plug_t));
if (!plug)
return -ENOMEM;
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;
return err;
}
}
-
+
err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode);
snd_config_delete(sconf);
if (err < 0)
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);
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);
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:
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)) {
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;
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);
{
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)
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;
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;
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);
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)
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) {
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)
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);
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)
/* 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;
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);
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--;
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);
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);
\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 {
# or
slave { # Slave definition
pcm STR # Slave PCM name
- # or
- pcm { } # Slave PCM definition
}
bindings {
N INT # Slave channel INT for client channel N
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;
}
#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;
-
- 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;
-
- 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;
+ 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;
+
+ 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;
+
+ 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 = read(shm->socket, buf, 1);
+ err = receive_fd(shm->socket, buf, 1, fd);
if (err != 1)
return -EBADFD;
if (ctrl->cmd) {
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;
+ err = read(shm->socket, buf, 1);
+ if (err != 1)
+ return -EBADFD;
+ if (ctrl->cmd) {
+ SNDERR("Server has not done the cmd");
+ return -EBADFD;
+ }
+ 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)
{
snd_pcm_shm_t *shm = pcm->private_data;
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;
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;
}
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))
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;