diff options
-rw-r--r-- | aserver/aserver.c | 120 | ||||
-rw-r--r-- | include/aserver.h | 18 | ||||
-rw-r--r-- | include/local.h | 1 | ||||
-rw-r--r-- | include/pcm.h | 4 | ||||
-rw-r--r-- | src/pcm/pcm.c | 117 | ||||
-rw-r--r-- | src/pcm/pcm_adpcm.c | 4 | ||||
-rw-r--r-- | src/pcm/pcm_alaw.c | 4 | ||||
-rw-r--r-- | src/pcm/pcm_copy.c | 4 | ||||
-rw-r--r-- | src/pcm/pcm_file.c | 4 | ||||
-rw-r--r-- | src/pcm/pcm_hooks.c | 4 | ||||
-rw-r--r-- | src/pcm/pcm_hw.c | 11 | ||||
-rw-r--r-- | src/pcm/pcm_ladspa.c | 4 | ||||
-rw-r--r-- | src/pcm/pcm_lfloat.c | 4 | ||||
-rw-r--r-- | src/pcm/pcm_linear.c | 4 | ||||
-rw-r--r-- | src/pcm/pcm_local.h | 31 | ||||
-rw-r--r-- | src/pcm/pcm_meter.c | 20 | ||||
-rw-r--r-- | src/pcm/pcm_mmap.c | 38 | ||||
-rw-r--r-- | src/pcm/pcm_mulaw.c | 4 | ||||
-rw-r--r-- | src/pcm/pcm_multi.c | 4 | ||||
-rw-r--r-- | src/pcm/pcm_null.c | 17 | ||||
-rw-r--r-- | src/pcm/pcm_plug.c | 13 | ||||
-rw-r--r-- | src/pcm/pcm_plugin.c | 16 | ||||
-rw-r--r-- | src/pcm/pcm_rate.c | 4 | ||||
-rw-r--r-- | src/pcm/pcm_route.c | 4 | ||||
-rw-r--r-- | src/pcm/pcm_share.c | 42 | ||||
-rw-r--r-- | src/pcm/pcm_shm.c | 160 |
26 files changed, 477 insertions, 179 deletions
diff --git a/aserver/aserver.c b/aserver/aserver.c index b9a1996b..f0241382 100644 --- a/aserver/aserver.c +++ b/aserver/aserver.c @@ -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; - - 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; @@ -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; diff --git a/include/aserver.h b/include/aserver.h index 876e9813..27cb58cb 100644 --- a/include/aserver.h +++ b/include/aserver.h @@ -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; diff --git a/include/local.h b/include/local.h index 5151780b..3f35a8fb 100644 --- a/include/local.h +++ b/include/local.h @@ -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); diff --git a/include/pcm.h b/include/pcm.h index 830b4bf5..ef287567 100644 --- a/include/pcm.h +++ b/include/pcm.h @@ -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); diff --git a/src/pcm/pcm.c b/src/pcm/pcm.c index 3dc5f3b8..a6ac6ff1 100644 --- a/src/pcm/pcm.c +++ b/src/pcm/pcm.c @@ -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 diff --git a/src/pcm/pcm_adpcm.c b/src/pcm/pcm_adpcm.c index 07471d7d..26061e5e 100644 --- a/src/pcm/pcm_adpcm.c +++ b/src/pcm/pcm_adpcm.c @@ -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; diff --git a/src/pcm/pcm_alaw.c b/src/pcm/pcm_alaw.c index 0566395d..9a8c8470 100644 --- a/src/pcm/pcm_alaw.c +++ b/src/pcm/pcm_alaw.c @@ -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; diff --git a/src/pcm/pcm_copy.c b/src/pcm/pcm_copy.c index 37e6131d..e27cd937 100644 --- a/src/pcm/pcm_copy.c +++ b/src/pcm/pcm_copy.c @@ -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 = ©->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; diff --git a/src/pcm/pcm_file.c b/src/pcm/pcm_file.c index 6f12d59f..30536ba3 100644 --- a/src/pcm/pcm_file.c +++ b/src/pcm/pcm_file.c @@ -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; diff --git a/src/pcm/pcm_hooks.c b/src/pcm/pcm_hooks.c index 6c204e17..946835de 100644 --- a/src/pcm/pcm_hooks.c +++ b/src/pcm/pcm_hooks.c @@ -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; diff --git a/src/pcm/pcm_hw.c b/src/pcm/pcm_hw.c index d441fea8..aeb8d374 100644 --- a/src/pcm/pcm_hw.c +++ b/src/pcm/pcm_hw.c @@ -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; } diff --git a/src/pcm/pcm_ladspa.c b/src/pcm/pcm_ladspa.c index d932f0a2..0ef781e1 100644 --- a/src/pcm/pcm_ladspa.c +++ b/src/pcm/pcm_ladspa.c @@ -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; diff --git a/src/pcm/pcm_lfloat.c b/src/pcm/pcm_lfloat.c index 6ff66f13..55aee134 100644 --- a/src/pcm/pcm_lfloat.c +++ b/src/pcm/pcm_lfloat.c @@ -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; diff --git a/src/pcm/pcm_linear.c b/src/pcm/pcm_linear.c index 4489cdb2..74aed8dc 100644 --- a/src/pcm/pcm_linear.c +++ b/src/pcm/pcm_linear.c @@ -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; diff --git a/src/pcm/pcm_local.h b/src/pcm/pcm_local.h index 7dddd4ed..aaf0a5de 100644 --- a/src/pcm/pcm_local.h +++ b/src/pcm/pcm_local.h @@ -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 diff --git a/src/pcm/pcm_meter.c b/src/pcm/pcm_meter.c index 2775bc52..c3e41430 100644 --- a/src/pcm/pcm_meter.c +++ b/src/pcm/pcm_meter.c @@ -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); diff --git a/src/pcm/pcm_mmap.c b/src/pcm/pcm_mmap.c index d5d2d0c6..63c05056 100644 --- a/src/pcm/pcm_mmap.c +++ b/src/pcm/pcm_mmap.c @@ -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, diff --git a/src/pcm/pcm_mulaw.c b/src/pcm/pcm_mulaw.c index d6b53047..53b4d319 100644 --- a/src/pcm/pcm_mulaw.c +++ b/src/pcm/pcm_mulaw.c @@ -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; diff --git a/src/pcm/pcm_multi.c b/src/pcm/pcm_multi.c index 59197f33..7f5caac6 100644 --- a/src/pcm/pcm_multi.c +++ b/src/pcm/pcm_multi.c @@ -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; } diff --git a/src/pcm/pcm_null.c b/src/pcm/pcm_null.c index c5f3e70e..253606a8 100644 --- a/src/pcm/pcm_null.c +++ b/src/pcm/pcm_null.c @@ -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; diff --git a/src/pcm/pcm_plug.c b/src/pcm/pcm_plug.c index 86d838c3..d3fe50fb 100644 --- a/src/pcm/pcm_plug.c +++ b/src/pcm/pcm_plug.c @@ -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; @@ -1084,7 +1087,7 @@ int _snd_pcm_plug_open(snd_pcm_t **pcmp, const char *name, return err; } } - + err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode); snd_config_delete(sconf); if (err < 0) diff --git a/src/pcm/pcm_plugin.c b/src/pcm/pcm_plugin.c index bc52233e..2aa6b3ee 100644 --- a/src/pcm/pcm_plugin.c +++ b/src/pcm/pcm_plugin.c @@ -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)) { diff --git a/src/pcm/pcm_rate.c b/src/pcm/pcm_rate.c index 752c3af9..5273d7dc 100644 --- a/src/pcm/pcm_rate.c +++ b/src/pcm/pcm_rate.c @@ -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; diff --git a/src/pcm/pcm_route.c b/src/pcm/pcm_route.c index 2b328a42..2c492c31 100644 --- a/src/pcm/pcm_route.c +++ b/src/pcm/pcm_route.c @@ -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); diff --git a/src/pcm/pcm_share.c b/src/pcm/pcm_share.c index 40f4a8d3..89a1c4f4 100644 --- a/src/pcm/pcm_share.c +++ b/src/pcm/pcm_share.c @@ -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; } diff --git a/src/pcm/pcm_shm.c b/src/pcm/pcm_shm.c index e5ab2707..fe91afbd 100644 --- a/src/pcm/pcm_shm.c +++ b/src/pcm/pcm_shm.c @@ -60,49 +60,50 @@ 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; - - 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) { @@ -112,12 +113,82 @@ static long snd_pcm_shm_action(snd_pcm_t *pcm) 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; @@ -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; |