]> git.alsa-project.org Git - alsa-lib.git/commitdiff
Moved ring buffer pointers and added a mechanism to transfer them via shm
authorJaroslav Kysela <perex@perex.cz>
Tue, 23 Apr 2002 15:51:29 +0000 (15:51 +0000)
committerJaroslav Kysela <perex@perex.cz>
Tue, 23 Apr 2002 15:51:29 +0000 (15:51 +0000)
26 files changed:
aserver/aserver.c
include/aserver.h
include/local.h
include/pcm.h
src/pcm/pcm.c
src/pcm/pcm_adpcm.c
src/pcm/pcm_alaw.c
src/pcm/pcm_copy.c
src/pcm/pcm_file.c
src/pcm/pcm_hooks.c
src/pcm/pcm_hw.c
src/pcm/pcm_ladspa.c
src/pcm/pcm_lfloat.c
src/pcm/pcm_linear.c
src/pcm/pcm_local.h
src/pcm/pcm_meter.c
src/pcm/pcm_mmap.c
src/pcm/pcm_mulaw.c
src/pcm/pcm_multi.c
src/pcm/pcm_null.c
src/pcm/pcm_plug.c
src/pcm/pcm_plugin.c
src/pcm/pcm_rate.c
src/pcm/pcm_route.c
src/pcm/pcm_share.c
src/pcm/pcm_shm.c

index b9a1996b729c803740432bd85776f3a5e3abdd5c..f0241382d440d945ea338763d396d4a7272ebe21 100644 (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;
-
-    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;
index 876e9813709ec66c24bdf3b4055c1f3ad3b98441..27cb58cbe2d816cd1ce5f9628cb9a3b79bb80a02 100644 (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;
index 5151780b7944a2e6c15836def2ad013f20ab6603..3f35a8fb1c52d295a5af669012baf82cd05a7180 100644 (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);
 
index 830b4bf5c08cceb1cea92669754c4ba3fe9bd973..ef287567ce6274d6e1643d2bd1504404d70cae06 100644 (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);
index 3dc5f3b88951167e8692aad5459d596e3419ea26..a6ac6ff155359eacce7f02b1c29cbff4696be57d 100644 (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
index 07471d7d4f26d2b87e01c5a023cac47371d9a2db..26061e5e2159689c79216b78d2897ea38c9c9281 100644 (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;
index 0566395daba7a2e5d4c4117ee4d6f19d8c5b9b55..9a8c84709451b1ab9e2849f831045d09570e10fb 100644 (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;
index 37e6131dd6d16a0ca568f545fbb5b4f42b4dae92..e27cd9379a28d06fdab61447af6c1b3ae1a8486a 100644 (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;
index 6f12d59f783ce36892bd65a288c79c6795a0b373..30536ba3d8994cf42e6d5af900da93e4e38cadd2 100644 (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;
index 6c204e1781a1c8a3ef359c07c8a40d689970394b..946835deaf766726cf5c28306ae33763b753ca3c 100644 (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;
index d441fea8e46dfa635250153f90805f6b37cada16..aeb8d3745c5113c81fda6a715959875153b9eb99 100644 (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;
 }
 
index d932f0a2872ac447f3d32729bea31d723d0be832..0ef781e18f67cfb7559f6a1d4b52759252361941 100644 (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;
index 6ff66f13c8fe99a128bf09ac03e86f7bed6d84eb..55aee13457cf30f7e23e71643b967a498e3138f3 100644 (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;
index 4489cdb230e6c7e778e3b73c724a73b7237b0c84..74aed8dcf18ed53ee5404fceb6bcf6d5b541e8ee 100644 (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;
index 7dddd4ed05aca6979cf906ed3d9382820596e809..aaf0a5de5bd36aca1469673edc768d6197561d4d 100644 (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
index 2775bc520a45b199cd3f407fcc419d07f26b5950..c3e414302c07a9831eff57dc1e87547f4f5c1d13 100644 (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);
index d5d2d0c697f8c13b641677d5ac1fbba8050790b5..63c0505629ee7392ed86cf12e55893e07b3a8f03 100644 (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,
index d6b53047ad5577e283ad3417d8d1fbb7c48df8fb..53b4d319e7e9b43bf8f064985a18740d05382b05 100644 (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;
index 59197f33d09e9a519bb04e4d1fae60fe8f28809f..7f5caac6108a771800d843976a9ed46e77e7fd93 100644 (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;
 }
index c5f3e70e5271ca499fdabf9a8dd6799357a2bddb..253606a852acfa8cb5f581ebfb0696b02e40d138 100644 (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;
index 86d838c3520d52979e0a1387c1fc60d077e8f492..d3fe50fb855a0d1be4fc9cff4df8cdde83de56b5 100644 (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;
@@ -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)
index bc52233edeeccd6895c21ac7988d64484d05c754..2aa6b3eeb88c1178214f9b80620e4e902db532fb 100644 (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)) {
index 752c3af929ff7c687646c9398d4e3db773df6f28..5273d7dcc2d1470fa74aeb64ff1527749893f082 100644 (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;
index 2b328a4226161a05886de8ed8bda0050ec188e70..2c492c3184022167781e96e0843cc8264f158244 100644 (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);
index 40f4a8d38f89fcadd961d281a2e452316547a4eb..89a1c4f4235e6cb35cbf7558d00abdbe31e5d711 100644 (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;
        }
index e5ab2707ae8a0efab4d8adadb9a882ee2601114f..fe91afbdef4e1926b01f5f8f917e3c5f33ec6085 100644 (file)
@@ -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;