summaryrefslogtreecommitdiff
path: root/aserver/aserver.c
diff options
context:
space:
mode:
Diffstat (limited to 'aserver/aserver.c')
-rw-r--r--aserver/aserver.c120
1 files changed, 82 insertions, 38 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;