]> git.alsa-project.org Git - alsa-lib.git/commitdiff
First version of ALSA client/server
authorAbramo Bagnara <abramo@alsa-project.org>
Thu, 31 Aug 2000 11:21:05 +0000 (11:21 +0000)
committerAbramo Bagnara <abramo@alsa-project.org>
Thu, 31 Aug 2000 11:21:05 +0000 (11:21 +0000)
12 files changed:
configure.in
include/Makefile.am
include/aserver.h [new file with mode: 0644]
include/header.h
include/pcm.h
src/Makefile.am
src/aserver/Makefile.am [new file with mode: 0644]
src/aserver/aserver.c [new file with mode: 0644]
src/pcm/Makefile.am
src/pcm/pcm.c
src/pcm/pcm_client.c [new file with mode: 0644]
src/pcm/pcm_hw.c

index 26a143dd0fff5699e0cf28c717abe7e925378fb6..d7fdedcb3211e649bc20696fd48f1e2a061dce88 100644 (file)
@@ -53,6 +53,6 @@ AC_OUTPUT(Makefile doc/Makefile include/Makefile src/Makefile \
           src/control/Makefile src/mixer/Makefile src/pcm/Makefile \
          src/pcm/plugin/Makefile src/rawmidi/Makefile src/timer/Makefile \
           src/hwdep/Makefile src/seq/Makefile src/instr/Makefile \
-          src/compat/Makefile src/conf/Makefile \
+          src/compat/Makefile src/conf/Makefile src/aserver/Makefile \
           test/Makefile utils/Makefile \
           utils/alsa-lib.spec)
index 2761c59a7b0f3aa1e56a0d86f0697ab177526ded..a930d93aac6c233ad38764fb4fbda73c94613ac4 100644 (file)
@@ -6,7 +6,7 @@ sysinclude_HEADERS = asoundlib.h
 header_files=header.h version.h error.h control.h mixer.h pcm.h rawmidi.h \
              timer.h hwdep.h seq.h seqmid.h conv.h instr.h conf.h footer.h
 
-noinst_HEADERS=$(header_files) search.h
+noinst_HEADERS=$(header_files) search.h list.h aserver.h
 
 asoundlib.h: $(header_files)
        cat $^ > $@
diff --git a/include/aserver.h b/include/aserver.h
new file mode 100644 (file)
index 0000000..428ec28
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ *  ALSA client/server header file
+ *  Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>
+ *
+ *   This library is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU Library General Public License as
+ *   published by the Free Software Foundation; either version 2 of
+ *   the License, or (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU Library General Public License for more details.
+ *
+ *   You should have received a copy of the GNU Library General Public
+ *   License along with this library; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+  
+
+#define SND_PCM_IOCTL_MMAP_DATA                _IO ('A', 0xf0)
+#define SND_PCM_IOCTL_MMAP_CONTROL     _IO ('A', 0xf1)
+#define SND_PCM_IOCTL_MMAP_STATUS      _IO ('A', 0xf2)
+#define SND_PCM_IOCTL_MUNMAP_DATA      _IO ('A', 0xf3)
+#define SND_PCM_IOCTL_MUNMAP_CONTROL   _IO ('A', 0xf4)
+#define SND_PCM_IOCTL_MUNMAP_STATUS    _IO ('A', 0xf5)
+#define SND_PCM_IOCTL_CLOSE            _IO ('A', 0xf6)
+
+typedef struct {
+       int result;
+       int cmd;
+       union {
+               snd_pcm_info_t info;
+               snd_pcm_params_t params;
+               snd_pcm_params_info_t params_info;
+               snd_pcm_setup_t setup;
+               snd_pcm_status_t status;
+               int pause;
+               snd_pcm_channel_info_t channel_info;
+               snd_pcm_channel_params_t channel_params;
+               snd_pcm_channel_setup_t channel_setup;
+               off_t frame_data;
+               int frame_io;
+               int link;
+               snd_xfer_t read;
+               snd_xfer_t write;
+               snd_xferv_t readv;
+               snd_xferv_t writev;
+       } u;
+       char data[0];
+} snd_pcm_client_shm_t;
+
+#define PCM_SHM_SIZE 65536
+#define PCM_SHM_DATA_MAXLEN (PCM_SHM_SIZE - offsetof(snd_pcm_client_shm_t, data))
+               
+typedef struct {
+       unsigned char dev_type;
+       unsigned char transport_type;
+       unsigned char stream;
+       unsigned char mode;
+       unsigned char namelen;
+       char name[0];
+} snd_client_open_request_t;
+
+typedef struct {
+       long result;
+       long cookie;
+} snd_client_open_answer_t;
+
+struct cmsg_fd
+{
+    int len;   /* sizeof structure */
+    int level; /* SOL_SOCKET */
+    int type;  /* SCM_RIGHTS */
+    int fd;    /* fd to pass */
+};
index 93531352fec47f09394bb45e48313ce9132a4045..6c667bd26b773fc4c849e6edcb7942329dd228bc 100644 (file)
 #define ATTRIBUTE_UNUSED __attribute__ ((__unused__))
 #endif
 
+#define SND_DEV_TYPE_PCM       0
+#define SND_DEV_TYPE_CONTROL   1
+#define SND_DEV_TYPE_RAWMIDI   2
+#define SND_DEV_TYPE_TIMER     3
+#define SND_DEV_TYPE_HWDEP     4
+#define SND_DEV_TYPE_SEQ       5
+
+#define SND_TRANSPORT_TYPE_SHM 0
+#define SND_TRANSPORT_TYPE_TCP 1
+
index 7750d9cc16c84f21b043460bdf21d438941d86ee..0e67cf7168faeac8f3dd145ff8e7332da7a88993 100644 (file)
@@ -98,28 +98,7 @@ static inline size_t bitset_count(bitset_t *bitset, size_t nbits)
 typedef struct snd_pcm snd_pcm_t;
 typedef struct snd_pcm_loopback snd_pcm_loopback_t;
 
-typedef enum { SND_PCM_TYPE_HW, SND_PCM_TYPE_PLUG, SND_PCM_TYPE_MULTI } snd_pcm_type_t;
-
-#if 0
-typedef struct {
-       snd_pcm_t *handle;
-       snd_timestamp_t tstamp;
-       int result;
-       union {
-               char reserved[256];
-       } arg;
-} snd_pcm_synchro_request_t;
-
-typedef enum { SND_PCM_SYNCHRO_GO } snd_pcm_synchro_cmd_t;
-
-#define snd_pcm_synchro_mode_t snd_pcm_sync_mode_t
-#define SND_PCM_SYNCHRO_MODE_NORMAL SND_PCM_SYNC_MODE_NORMAL
-#define SND_PCM_SYNCHRO_MODE_HARDWARE SND_PCM_SYNC_MODE_HARDWARE
-#define SND_PCM_SYNCHRO_MODE_RELAXED SND_PCM_SYNC_MODE_RELAXED
-int snd_pcm_synchro(snd_pcm_synchro_cmd_t cmd, 
-                   unsigned int reqs_count, snd_pcm_synchro_request_t *reqs,
-                   snd_pcm_synchro_mode_t mode);
-#endif
+typedef enum { SND_PCM_TYPE_HW, SND_PCM_TYPE_PLUG, SND_PCM_TYPE_MULTI, SND_PCM_TYPE_CLIENT } snd_pcm_type_t;
 
 
 int snd_pcm_open(snd_pcm_t **handle, char *name, 
@@ -384,6 +363,8 @@ int snd_pcm_multi_create(snd_pcm_t **handlep, size_t slaves_count,
                         unsigned int *binds_slave, unsigned int *binds_slave_channel,
                         int close_slaves);
 
+int snd_pcm_client_create(snd_pcm_t **handlep, char *host, int port, int transport, char *name, int stream, int mode);
+
 #ifdef __cplusplus
 }
 #endif
index 4286ea43916f670f83a7d837f952c1ad0be091bb..60eb86129b1952405b86605beb788896bac058b6 100644 (file)
@@ -1,4 +1,4 @@
-SUBDIRS=control mixer pcm rawmidi timer hwdep seq instr compat conf
+SUBDIRS=control mixer pcm rawmidi timer hwdep seq instr compat conf aserver
 COMPATNUM=@LIBTOOL_VERSION_INFO@
 
 lib_LTLIBRARIES = libasound.la
diff --git a/src/aserver/Makefile.am b/src/aserver/Makefile.am
new file mode 100644 (file)
index 0000000..dca5ca0
--- /dev/null
@@ -0,0 +1,8 @@
+
+bin_PROGRAMS = aserver
+aserver_SOURCES = aserver.c
+aserver_LDADD = -lasound
+
+all: aserver
+
+INCLUDES=-I$(top_srcdir)/include -I$(top_srcdir)/src/pcm
diff --git a/src/aserver/aserver.c b/src/aserver/aserver.c
new file mode 100644 (file)
index 0000000..edc749a
--- /dev/null
@@ -0,0 +1,885 @@
+/*
+ *  ALSA server
+ *  Copyright (c) by Abramo Bagnara <abramo@alsa-project.org>
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <sys/shm.h>
+#include <sys/socket.h>
+#include <sys/poll.h>
+#include <sys/un.h>
+#include <sys/uio.h>
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <stddef.h>
+#include <getopt.h>
+#include <netinet/in.h>
+
+#include "asoundlib.h"
+#include "pcm_local.h"
+#include "aserver.h"
+
+char *command;
+
+#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95)
+#define error(...) do {\
+       fprintf(stderr, "%s: %s:%d: ", command, __FUNCTION__, __LINE__); \
+       fprintf(stderr, __VA_ARGS__); \
+       putc('\n', stderr); \
+} while (0)
+#else
+#define error(args...) do {\
+       fprintf(stderr, "%s: %s:%d: ", command, __FUNCTION__, __LINE__); \
+       fprintf(stderr, ##args); \
+       putc('\n', stderr); \
+} while (0)
+#endif 
+
+#define perrno(string) error("%s", strerror(errno))
+
+int make_local_socket(const char *filename)
+{
+       size_t l = strlen(filename);
+       size_t size = offsetof(struct sockaddr_un, sun_path) + l;
+       struct sockaddr_un *addr = alloca(size);
+       int sock;
+
+       sock = socket(PF_LOCAL, SOCK_STREAM, 0);
+       if (sock < 0) {
+               int result = -errno;
+               perrno("socket");
+               return result;
+       }
+       
+       unlink(filename);
+
+       addr->sun_family = AF_LOCAL;
+       memcpy(addr->sun_path, filename, l);
+
+       if (bind(sock, (struct sockaddr *) addr, size) < 0) {
+               int result = -errno;
+               perrno("bind");
+               return result;
+       }
+
+       return sock;
+}
+
+int make_inet_socket(int port)
+{
+       struct sockaddr_in addr;
+       int sock;
+
+       sock = socket(PF_INET, SOCK_STREAM, 0);
+       if (sock < 0) {
+               int result = -errno;
+               perrno("socket");
+               return result;
+       }
+       
+       addr.sin_family = AF_INET;
+       addr.sin_port = htons(port);
+       addr.sin_addr.s_addr = INADDR_ANY;
+
+       if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+               int result = -errno;
+               perrno("bind");
+               return result;
+       }
+
+       return sock;
+}
+
+int send_fd(int socket, void *data, size_t len, int fd)
+{
+    int ret;
+    struct cmsg_fd cmsg;
+    struct msghdr msghdr;
+    struct iovec vec;
+
+    vec.iov_base = (void *)&data;
+    vec.iov_len = len;
+
+    cmsg.len = sizeof(cmsg);
+    cmsg.level = SOL_SOCKET;
+    cmsg.type = SCM_RIGHTS;
+    cmsg.fd = fd;
+
+    msghdr.msg_name = NULL;
+    msghdr.msg_namelen = 0;
+    msghdr.msg_iov = &vec;
+    msghdr.msg_iovlen = 1;
+    msghdr.msg_control = &cmsg;
+    msghdr.msg_controllen = sizeof(cmsg);
+    msghdr.msg_flags = 0;
+
+    ret = sendmsg(socket, &msghdr, 0 );
+    if (ret < 0)
+           return -errno;
+    return ret;
+}
+
+typedef struct client client_t;
+
+typedef struct {
+       int (*open)(client_t *client, long *cookie);
+       int (*cmd)(client_t *client);
+       int (*close)(client_t *client);
+       int (*poll_prepare)(client_t *client, struct pollfd *pfds, int pindex);
+       void (*poll_events)(client_t *client, struct pollfd *pfds);
+} transport_ops_t;
+
+struct client {
+       struct socket {
+               int fd;
+               int pindex;
+               int local;
+       } data, ctrl;
+       int transport_type;
+       int dev_type;
+       char name[256];
+       int stream;
+       int mode;
+       transport_ops_t *ops;
+       union {
+               struct {
+                       snd_pcm_t *handle;
+                       int fd;
+                       int pindex;
+               } pcm;
+#if 0
+               struct {
+                       snd_ctl_t *handle;
+               } control;
+               struct {
+                       snd_rawmidi_t *handle;
+               } rawmidi;
+               struct {
+                       snd_timer_open_t *handle;
+               } timer;
+               struct {
+                       snd_hwdep_t *handle;
+               } hwdep;
+               struct {
+                       snd_seq_t *handle;
+               } seq;
+#endif
+       } device;
+       enum { CLOSED = 0, STOPPED, NORMAL, UNKNOWN } state;
+       int cookie;
+       union {
+               struct {
+                       int ctrl_id;
+                       void *ctrl;
+               } shm;
+       } transport;
+};
+
+#define PENDINGS_MAX 4
+#define CLIENTS_MAX 2
+
+client_t clients[CLIENTS_MAX];
+int clients_count = 0;
+
+int pcm_shm_open(client_t *client, long *cookie)
+{
+       int shmid;
+       snd_pcm_t *pcm;
+       int err;
+       int result;
+       err = snd_pcm_open(&pcm, client->name, client->stream, client->mode);
+       if (err < 0)
+               return err;
+       client->device.pcm.handle = pcm;
+       client->device.pcm.fd = snd_pcm_file_descriptor(pcm);
+
+       shmid = shmget(IPC_PRIVATE, PCM_SHM_SIZE, 0666);
+       if (shmid < 0) {
+               result = -errno;
+               perrno("shmget");
+               goto _err;
+       }
+       client->transport.shm.ctrl_id = shmid;
+       client->transport.shm.ctrl = shmat(shmid, 0, 0);
+       if (!client->transport.shm.ctrl) {
+               result = -errno;
+               shmctl(shmid, IPC_RMID, 0);
+               perrno("shmat");
+               goto _err;
+       }
+       *cookie = shmid;
+       return 0;
+
+ _err:
+       snd_pcm_close(pcm);
+       return result;
+
+}
+
+int pcm_shm_close(client_t *client)
+{
+       int err;
+       snd_pcm_client_shm_t *ctrl = client->transport.shm.ctrl;
+       /* FIXME: blocking */
+       err = snd_pcm_close(client->device.pcm.handle);
+       ctrl->result = err;
+       if (err < 0) 
+               perrno("snd_pcm_close");
+       if (client->transport.shm.ctrl) {
+               err = shmdt((void *)client->transport.shm.ctrl);
+               if (err < 0)
+                       perrno("shmdt");
+               err = shmctl(client->transport.shm.ctrl_id, IPC_RMID, 0);
+               if (err < 0)
+                       perrno("shmctl");
+               client->transport.shm.ctrl = 0;
+       }
+       client->state = CLOSED;
+       return 0;
+}
+
+int pcm_poll_prepare(client_t *client, struct pollfd *pfds, int pindex)
+{
+       struct pollfd *pfd = &pfds[pindex];
+       pfd->events = 0;
+       switch (client->state) {
+       case UNKNOWN:
+               pfd->events = client->stream == SND_PCM_STREAM_PLAYBACK ? POLLOUT : POLLIN;
+       case NORMAL:
+               pfd->fd = client->device.pcm.fd;
+               client->device.pcm.pindex = pindex;
+               return 1;
+               break;
+       default:
+               client->device.pcm.pindex = -1;
+               return 0;
+       }
+}
+
+void pcm_poll_events(client_t *client, struct pollfd *pfds)
+{
+       int n;
+       char zero = 0;
+       struct pollfd *pfd;
+       if (client->device.pcm.pindex < 0)
+               return;
+       pfd = &pfds[client->device.pcm.pindex];
+       if (pfd->revents & POLLIN) {
+               client->state = NORMAL;
+               n = write(client->data.fd, &zero, 1);
+               if (n != 1) {
+                       perrno("write");
+                       exit(1);
+               }
+       } else if (pfd->revents & POLLOUT) {
+               client->state = NORMAL;
+               n = read(client->data.fd, &zero, 1);
+               if (n != 1) {
+                       perrno("read");
+                       exit(1);
+               }
+       }
+}
+
+int pcm_shm_cmd(client_t *client)
+{
+       snd_pcm_client_shm_t *ctrl = client->transport.shm.ctrl;
+       struct pollfd pfd;
+       char buf[1];
+       int err;
+       int cmd;
+       snd_pcm_t *pcm;
+       err = read(client->ctrl.fd, buf, 1);
+       if (err != 1)
+               return -EBADFD;
+       cmd = ctrl->cmd;
+       ctrl->cmd = 0;
+       pcm = client->device.pcm.handle;
+       switch (cmd) {
+       case SND_PCM_IOCTL_INFO:
+               ctrl->result = snd_pcm_info(pcm, &ctrl->u.info);
+               break;
+       case SND_PCM_IOCTL_PARAMS:
+               ctrl->result = snd_pcm_params(pcm, &ctrl->u.params);
+               break;
+       case SND_PCM_IOCTL_PARAMS_INFO:
+               ctrl->result = snd_pcm_params_info(pcm, &ctrl->u.params_info);
+               break;
+       case SND_PCM_IOCTL_SETUP:
+               ctrl->result = snd_pcm_setup(pcm, &ctrl->u.setup);
+               break;
+       case SND_PCM_IOCTL_STATUS:
+               ctrl->result = snd_pcm_status(pcm, &ctrl->u.status);
+               break;
+       case SND_PCM_IOCTL_FRAME_IO:
+               ctrl->result = snd_pcm_frame_io(pcm, ctrl->u.frame_io);
+               break;
+       case SND_PCM_IOCTL_PREPARE:
+               ctrl->result = snd_pcm_prepare(pcm);
+               break;
+       case SND_PCM_IOCTL_GO:
+               ctrl->result = snd_pcm_go(pcm);
+               break;
+       case SND_PCM_IOCTL_FLUSH:
+               ctrl->result = snd_pcm_flush(pcm);
+               break;
+       case SND_PCM_IOCTL_DRAIN:
+               ctrl->result = snd_pcm_drain(pcm);
+               break;
+       case SND_PCM_IOCTL_PAUSE:
+               ctrl->result = snd_pcm_pause(pcm, ctrl->u.pause);
+               break;
+       case SND_PCM_IOCTL_CHANNEL_INFO:
+               ctrl->result = snd_pcm_channel_info(pcm, &ctrl->u.channel_info);
+               break;
+       case SND_PCM_IOCTL_CHANNEL_PARAMS:
+               ctrl->result = snd_pcm_channel_params(pcm, &ctrl->u.channel_params);
+               break;
+       case SND_PCM_IOCTL_CHANNEL_SETUP:
+               ctrl->result = snd_pcm_channel_setup(pcm, &ctrl->u.channel_setup);
+               break;
+       case SND_PCM_IOCTL_WRITE_FRAMES:
+       {
+               size_t maxsize = PCM_SHM_DATA_MAXLEN;
+               client->state = UNKNOWN;
+               maxsize = snd_pcm_bytes_to_frames(pcm, maxsize);
+               if (ctrl->u.write.count > maxsize) {
+                       ctrl->result = -EFAULT;
+                       break;
+               }
+               /* FIXME: blocking */
+               ctrl->result = snd_pcm_write(pcm, ctrl->data, ctrl->u.write.count);
+               break;
+       }
+       case SND_PCM_IOCTL_READ_FRAMES:
+       {
+               size_t maxsize = PCM_SHM_DATA_MAXLEN;
+               client->state = UNKNOWN;
+               maxsize = snd_pcm_bytes_to_frames(pcm, maxsize);
+               if (ctrl->u.read.count > maxsize) {
+                       ctrl->result = -EFAULT;
+                       break;
+               }
+               /* FIXME: blocking */
+               ctrl->result = snd_pcm_read(pcm, ctrl->data, ctrl->u.read.count);
+               break;
+       }
+       case SND_PCM_IOCTL_WRITEV_FRAMES:
+       {
+               /* FIXME: interleaved */
+               size_t maxsize = PCM_SHM_DATA_MAXLEN;
+               unsigned long k;
+               struct iovec *vector;
+               size_t vecsize;
+               char *base;
+               int bits_per_sample = snd_pcm_samples_to_bytes(pcm, 8);
+               client->state = UNKNOWN;
+               vecsize = ctrl->u.writev.count * sizeof(struct iovec);
+               if (vecsize > maxsize) {
+                       ctrl->result = -EFAULT;
+                       break;
+               }
+               maxsize -= vecsize;
+               vector = (struct iovec *) ctrl->data;
+               base = ctrl->data + vecsize;
+               for (k = 0; k < ctrl->u.writev.count; ++k) {
+                       unsigned long ofs = (unsigned long) vector[k].iov_base;
+                       size_t len = vector[k].iov_len * bits_per_sample / 8;
+                       if (ofs + len > maxsize)
+                               return -EFAULT;
+                       vector[k].iov_base = base + ofs;
+               }
+               /* FIXME: blocking */
+               ctrl->result = snd_pcm_writev(pcm, vector, ctrl->u.writev.count);
+               break;
+       }
+       case SND_PCM_IOCTL_READV_FRAMES:
+       {
+               /* FIXME: interleaved */
+               size_t maxsize = PCM_SHM_DATA_MAXLEN;
+               unsigned long k;
+               struct iovec *vector;
+               size_t vecsize;
+               char *base;
+               int bits_per_sample = snd_pcm_samples_to_bytes(pcm, 8);
+               client->state = UNKNOWN;
+               vecsize = ctrl->u.readv.count * sizeof(struct iovec);
+               if (vecsize > maxsize) {
+                       ctrl->result = -EFAULT;
+                       break;
+               }
+               maxsize -= vecsize;
+               vector = (struct iovec *) ctrl->data;
+               base = ctrl->data + vecsize;
+               for (k = 0; k < ctrl->u.readv.count; ++k) {
+                       unsigned long ofs = (unsigned long) vector[k].iov_base;
+                       size_t len = vector[k].iov_len * bits_per_sample / 8;
+                       if (ofs + len > maxsize)
+                               return -EFAULT;
+                       vector[k].iov_base = base + ofs;
+               }
+               /* FIXME: blocking */
+               ctrl->result = snd_pcm_readv(pcm, vector, ctrl->u.readv.count);
+               break;
+       }
+       case SND_PCM_IOCTL_FRAME_DATA:
+               client->state = UNKNOWN;
+               ctrl->result = snd_pcm_frame_data(pcm, ctrl->u.frame_data);
+               break;
+       case SND_PCM_IOCTL_LINK:
+       {
+               int k;
+               for (k = 0; k < clients_count; ++k) {
+                       if (clients[k].state == CLOSED)
+                               continue;
+                       if (clients[k].data.fd == ctrl->u.link) {
+                               ctrl->result = snd_pcm_link(pcm, clients[k].device.pcm.handle);
+                               break;
+                       }
+               }
+               ctrl->result = -EBADFD;
+               break;
+       }
+       case SND_PCM_IOCTL_UNLINK:
+               ctrl->result = snd_pcm_unlink(pcm);
+               break;
+       case SND_PCM_IOCTL_MMAP_DATA:
+       case SND_PCM_IOCTL_MMAP_CONTROL:
+       case SND_PCM_IOCTL_MMAP_STATUS:
+       {
+               pfd.fd = client->ctrl.fd;
+               pfd.events = POLLHUP;
+               if (poll(&pfd, 1, 0) == 1)
+                       return -EBADFD;
+               err = send_fd(client->ctrl.fd, buf, 1, client->device.pcm.fd);
+               if (err != 1)
+                       return -EBADFD;
+               ctrl->result = 0;
+               return 0;
+       }
+#if 0
+       case SND_PCM_IOCTL_MUNMAP_DATA:
+       case SND_PCM_IOCTL_MUNMAP_CONTROL:
+       case SND_PCM_IOCTL_MUNMAP_STATUS:
+               ctrl->result = 0;
+               break;
+       }
+#endif
+       case SND_PCM_IOCTL_CLOSE:
+               client->ops->close(client);
+               break;
+       default:
+               fprintf(stderr, "Bogus cmd: %x\n", ctrl->cmd);
+               ctrl->result = -ENOSYS;
+       }
+       pfd.fd = client->ctrl.fd;
+       pfd.events = POLLHUP;
+       if (poll(&pfd, 1, 0) == 1)
+               return -EBADFD;
+       err = write(client->ctrl.fd, buf, 1);
+       if (err != 1)
+               return -EBADFD;
+       return 0;
+}
+
+transport_ops_t pcm_shm_ops = {
+       open: pcm_shm_open,
+       cmd: pcm_shm_cmd,
+       close: pcm_shm_close,
+       poll_prepare: pcm_poll_prepare,
+       poll_events: pcm_poll_events,
+};
+
+void snd_client_open(client_t *client)
+{
+       int err;
+       snd_client_open_request_t req;
+       snd_client_open_answer_t ans;
+       char *name;
+       memset(&ans, 0, sizeof(ans));
+       err = read(client->ctrl.fd, &req, sizeof(req));
+       if (err < 0) {
+               perrno("read");
+               exit(1);
+       }
+       if (err != sizeof(req)) {
+               ans.result = -EINVAL;
+               goto _answer;
+       }
+       name = alloca(req.namelen);
+       err = read(client->ctrl.fd, name, req.namelen);
+       if (err < 0) {
+               perrno("read");
+               exit(1);
+       }
+       if (err != req.namelen) {
+               ans.result = -EINVAL;
+               goto _answer;
+       }
+
+       switch (req.dev_type) {
+       case SND_DEV_TYPE_PCM:
+               switch (req.transport_type) {
+               case SND_TRANSPORT_TYPE_SHM:
+                       client->ops = &pcm_shm_ops;
+                       break;
+               default:
+                       ans.result = -EINVAL;
+                       goto _answer;
+               }
+               break;
+       default:
+               ans.result = -EINVAL;
+               goto _answer;
+       }
+
+       name[req.namelen] = '\0';
+
+       client->transport_type = req.transport_type;
+       strcpy(client->name, name);
+       client->stream = req.stream;
+       client->mode = req.mode;
+
+       err = client->ops->open(client, &ans.cookie);
+       if (err < 0) {
+               ans.result = err;
+       } else {
+               client->state = STOPPED;
+               ans.result = client->data.fd;
+       }
+
+ _answer:
+       ans.result = htonl(ans.result);
+       ans.cookie = htonl(ans.cookie);
+       err = write(client->ctrl.fd, &ans, sizeof(ans));
+       if (err != sizeof(ans)) {
+               perrno("write");
+               exit(1);
+       }
+       return;
+}
+
+int server(char *sockname, int port)
+{
+       typedef struct {
+               int fd;
+               int pindex;
+               int local;
+       } master_t;
+       master_t masters[2];
+       int masters_count = 0;
+       typedef struct {
+               int fd;
+               int pindex;
+               uint32_t cookie;
+               int local;
+       } pending_t;
+       pending_t pendings[PENDINGS_MAX];
+       int pendings_count = 0;
+       struct pollfd pfds[CLIENTS_MAX * 3 + 16];
+       int pfds_count;
+       int err;
+       int k;
+
+       if (sockname) {
+               int master = make_local_socket(sockname);
+               if (master < 0)
+                       return master;
+               masters[masters_count].fd = master;
+               masters[masters_count].local = 1;
+               masters_count++;
+       }
+       if (port >= 0) {
+               int master = make_inet_socket(port);
+               if (master < 0)
+                       return master;
+               masters[masters_count].fd = master;
+               masters[masters_count].local = 0;
+               masters_count++;
+       }
+
+       if (masters_count == 0)
+               return -EINVAL;
+
+       for (k = 0; k < masters_count; ++k) {
+               master_t *master = &masters[k];
+               if (fcntl(master->fd, F_SETFL, O_NONBLOCK) < 0) {
+                       int result = -errno;
+                       perrno("fcntl");
+                       return result;
+               }
+               if (listen(master->fd, 4) < 0) {
+                       int result = -errno;
+                       perrno("listen");
+                       return result;
+               }
+       }
+
+       for (k = 0; k < PENDINGS_MAX; ++k) {
+               pendings[k].fd = -1;
+       }
+
+       while (1) {
+               pfds_count = 0;
+               
+               /* Prepare to poll masters */
+               if (pendings_count < PENDINGS_MAX) {
+                       for (k = 0; k < masters_count; ++k) {
+                               master_t *master = &masters[k];
+                               master->pindex = pfds_count;
+                               pfds[pfds_count].fd = master->fd;
+                               pfds[pfds_count].events = POLLIN;
+                               pfds_count++;
+                       }
+               } else {
+                       for (k = 0; k < masters_count; ++k) {
+                               master_t *master = &masters[k];
+                               master->pindex = -1;
+                       }
+               }
+
+               /* Prepare to poll pendings */
+               for (k = 0; k < PENDINGS_MAX; ++k) {
+                       pending_t *pending = &pendings[k];
+                       if (pending->fd < 0 ||
+                           pending->cookie != 0) {
+                               pending->pindex = -1;
+                               continue;
+                       }
+                       pending->pindex = pfds_count;
+                       pfds[pfds_count].fd = pending->fd;
+                       pfds[pfds_count].events = POLLHUP;
+                       if (pendings_count < PENDINGS_MAX &&
+                           clients_count < CLIENTS_MAX)
+                               pfds[pfds_count].events |= POLLIN;
+                       pfds_count++;
+               }
+
+               /* Prepare to poll clients */
+               for (k = 0; k < clients_count; ++k) {
+                       client_t *client = &clients[k];
+                       client->data.pindex = pfds_count;
+                       pfds[pfds_count].fd = client->data.fd;
+                       pfds[pfds_count].events = POLLHUP;
+                       pfds_count++;
+
+                       client->ctrl.pindex = pfds_count;
+                       pfds[pfds_count].fd = client->ctrl.fd;
+                       pfds[pfds_count].events = POLLIN | POLLHUP;
+                       pfds_count++;
+               }
+
+               /* Prepare to poll devices */
+               for (k = 0; k < clients_count; ++k) {
+                       client_t *client = &clients[k];
+                       int n;
+                       if (client->state == CLOSED)
+                               continue;
+                       n = client->ops->poll_prepare(client, pfds, pfds_count);
+                       pfds_count += n;
+               }
+               
+
+               /* Poll */
+               do {
+                       err = poll(pfds, pfds_count, 1000);
+               } while (err == 0);
+               if (err < 0) {
+                       int result = -errno;
+                       perrno("poll");
+                       return result;
+               }
+
+               /* Handle clients events */
+               for (k = clients_count - 1; k >= 0; --k) {
+                       client_t *client;
+                       struct pollfd *data_pfd = &pfds[clients[k].data.pindex];
+                       struct pollfd *ctrl_pfd = &pfds[clients[k].ctrl.pindex];
+                       if (!data_pfd->revents && !ctrl_pfd->revents)
+                               continue;
+                       client = &clients[k];
+                       if ((data_pfd->revents & POLLHUP) ||
+                           (ctrl_pfd->revents & POLLHUP)) {
+                               if (client->state != CLOSED) {
+                                       client->ops->close(client);
+                               }
+                               close(client->data.fd);
+                               if (client->ctrl.fd >= 0)
+                                       close(client->ctrl.fd);
+                               memmove(client, client + 1,
+                                       (clients_count - k) * sizeof(client_t));
+                               clients_count--;
+                               continue;
+                       }
+                       if (ctrl_pfd->revents & POLLIN) {
+                               if (client->state == CLOSED)
+                                       snd_client_open(client);
+                               else
+                                       client->ops->cmd(client);
+                       }
+               }
+
+               /* Handle device events */
+               for (k = 0; k < clients_count; ++k) {
+                       client_t *client = &clients[k];
+                       client->ops->poll_events(client, pfds);
+               }
+
+               /* Handle pending events */
+               for (k = 0; k < PENDINGS_MAX; ++k) {
+                       struct pollfd *pfd;
+                       uint32_t cookie;
+                       int j;
+                       pending_t *pending = &pendings[k];
+                       client_t *client;
+                       int remove = 0;
+                       if (pending->pindex < 0)
+                               continue;
+                       pfd = &pfds[pending->pindex];
+                       if (!pfd->revents)
+                               continue;
+                       if (pfd->revents & POLLHUP)
+                               remove = 1;
+                       else {
+                               if (clients_count >= CLIENTS_MAX)
+                                       continue;
+                               err = read(pfd->fd, &cookie, sizeof(cookie));
+                               if (err != sizeof(cookie))
+                                       remove = 1;
+                               else {
+                                       err = write(pfd->fd, &cookie, sizeof(cookie));
+                                       if (err != sizeof(cookie))
+                                               remove = 1;
+                               }
+                       }
+                       if (remove) {
+                               close(pending->fd);
+                               pending->fd = -1;
+                               pendings_count--;
+                               continue;
+                       }
+
+                       for (j = 0; j < PENDINGS_MAX; ++j) {
+                               if (pendings[j].cookie == cookie)
+                                       break;
+                       }
+                       if (j == PENDINGS_MAX) {
+                               pendings[k].cookie = cookie;
+                               continue;
+                       }
+                       
+                       client = &clients[clients_count];
+                       memset(client, 0, sizeof(*client));
+                       client->data.fd = pendings[j].fd;
+                       client->data.local = pendings[j].local;
+                       client->ctrl.fd = pendings[k].fd;
+                       client->ctrl.local = pendings[k].local;
+                       client->state = CLOSED;
+                       clients_count++;
+                       pendings[j].fd = -1;
+                       pendings[k].fd = -1;
+                       pendings_count -= 2;
+               }
+
+               /* Handle master events */
+               for (k = 0; k < masters_count; ++k) {
+                       struct pollfd *pfd;
+                       master_t *master;
+                       int sock;
+                       if (pendings_count >= PENDINGS_MAX)
+                               break;
+                       master = &masters[k];
+                       if (master->pindex < 0)
+                               continue;
+                       pfd = &pfds[master->pindex];
+                       if (!pfd->revents)
+                               continue;
+                       
+                       sock = accept(master->fd, 0, 0);
+                       if (sock < 0) {
+                               int result = -errno;
+                                perrno("accept");
+                                return result;
+                       } else {
+                               int j;
+                               for (j = 0; j < PENDINGS_MAX; ++j) {
+                                       if (pendings[j].fd < 0)
+                                               break;
+                               }
+                               assert(j < PENDINGS_MAX);
+                               pendings[j].fd = sock;
+                               pendings[j].local = master->local;
+                               pendings[j].cookie = 0;
+                               pendings_count++;
+                       }
+               }
+               
+       }
+       return 0;
+}
+                                       
+
+void usage()
+{
+       fprintf(stderr, "\
+Usage: %s [OPTIONS]
+
+--help                 help
+--version              print current version
+-l,--local SOCKNAME    local socket name
+-p,--port PORT         port number
+", command);
+}
+
+int main(int argc, char **argv)
+{
+       static struct option long_options[] = {
+               {"local", 1, 0, 'l'},
+               {"port", 1, 0, 'p'},
+               {"help", 0, 0, 'h'}
+       };
+       int c;
+       char *local = NULL;
+       int port = -1;
+       command = argv[0];
+       while ((c = getopt_long(argc, argv, "hl:p:", long_options, 0)) != -1) {
+               switch (c) {
+               case 'h':
+                       usage();
+                       return 0;
+               case 'l':
+                       local = optarg;
+                       break;
+               case 'p':
+                       port = atoi(optarg);
+                       break;
+               default:
+                       fprintf(stderr, "Try `%s --help' for more information\n", command);
+                       return 1;
+               }
+       }
+       if (!local && port == -1) {
+               fprintf(stderr, "%s: you need to specify at least one master socket\n", command);
+               return 1;
+       }
+
+       server(local, port);
+       return 0;
+}
index 927560abc21efb0117c65dedbdbe7151cc475152..f08c836998ba1f0d2f307c4bfaa6b8dc105e227e 100644 (file)
@@ -3,7 +3,7 @@ SUBDIRS = plugin
 EXTRA_LTLIBRARIES = libpcm.la
 
 libpcm_la_SOURCES = pcm.c pcm_hw.c pcm_plug.c pcm_common.c \
-                   pcm_misc.c pcm_mmap.c pcm_multi.c
+                   pcm_misc.c pcm_mmap.c pcm_multi.c pcm_client.c
 libpcm_la_LIBADD = plugin/libpcmplugin.la
 noinst_HEADERS = pcm_local.h
 
index d37a4254919aad3816d745c00bc05900914c1d0b..fc2507a1143a36996627f020e768693d1ee4845e 100644 (file)
@@ -736,6 +736,62 @@ _free:
        return err;
 }
 
+static int _snd_pcm_open_client(snd_pcm_t **handlep, snd_config_t *conf, 
+                               int stream, int mode)
+{
+       snd_config_iterator_t i;
+       char *socket = NULL;
+       char *name = NULL;
+       char *host = NULL;
+       long port = -1;
+       int err;
+       snd_config_foreach(i, conf) {
+               snd_config_t *n = snd_config_entry(i);
+               if (strcmp(n->id, "comment") == 0)
+                       continue;
+               if (strcmp(n->id, "type") == 0)
+                       continue;
+               if (strcmp(n->id, "stream") == 0)
+                       continue;
+               if (strcmp(n->id, "socket") == 0) {
+                       err = snd_config_string_get(n, &socket);
+                       if (err < 0)
+                               return -EINVAL;
+                       continue;
+               }
+               if (strcmp(n->id, "host") == 0) {
+                       err = snd_config_string_get(n, &host);
+                       if (err < 0)
+                               return -EINVAL;
+                       continue;
+               }
+               if (strcmp(n->id, "port") == 0) {
+                       err = snd_config_integer_get(n, &port);
+                       if (err < 0)
+                               return -EINVAL;
+                       continue;
+               }
+               if (strcmp(n->id, "name") == 0) {
+                       err = snd_config_string_get(n, &name);
+                       if (err < 0)
+                               return -EINVAL;
+                       continue;
+               }
+               return -EINVAL;
+       }
+       if (!name)
+               return -EINVAL;
+       if (socket) {
+               if (port >= 0 || host)
+                       return -EINVAL;
+               return snd_pcm_client_create(handlep, socket, -1, SND_TRANSPORT_TYPE_SHM, name, stream, mode);
+       } else  {
+               if (port < 0 || !name)
+                       return -EINVAL;
+               return snd_pcm_client_create(handlep, host, port, SND_TRANSPORT_TYPE_SHM, name, stream, mode);
+       }
+}
+                               
 int snd_pcm_open(snd_pcm_t **handlep, char *name, 
                 int stream, int mode)
 {
@@ -777,6 +833,8 @@ int snd_pcm_open(snd_pcm_t **handlep, char *name,
                return _snd_pcm_open_plug(handlep, pcm_conf, stream, mode);
        else if (strcmp(str, "multi") == 0)
                return _snd_pcm_open_multi(handlep, pcm_conf, stream, mode);
+       else if (strcmp(str, "client") == 0)
+               return _snd_pcm_open_client(handlep, pcm_conf, stream, mode);
        else
                return -EINVAL;
 }
diff --git a/src/pcm/pcm_client.c b/src/pcm/pcm_client.c
new file mode 100644 (file)
index 0000000..3106905
--- /dev/null
@@ -0,0 +1,878 @@
+/*
+ *  PCM - Client
+ *  Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>
+ *
+ *
+ *   This library is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU Library General Public License as
+ *   published by the Free Software Foundation; either version 2 of
+ *   the License, or (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU Library General Public License for more details.
+ *
+ *   You should have received a copy of the GNU Library General Public
+ *   License along with this library; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+  
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/shm.h>
+#include <sys/socket.h>
+#include <sys/poll.h>
+#include <sys/un.h>
+#include <sys/uio.h>
+#include <sys/mman.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include "pcm_local.h"
+#include "aserver.h"
+
+typedef struct {
+       snd_pcm_t *handle;
+       int data_fd;
+       int ctrl_fd;
+       union {
+               struct {
+                       void *ctrl;
+               } shm;
+       } u;
+} snd_pcm_client_t;
+
+int receive_fd(int socket, void *data, size_t len, int *fd)
+{
+    int ret;
+    struct cmsg_fd cmsg;
+    struct msghdr msghdr;
+    struct iovec vec;
+
+    vec.iov_base = (void *)&data;
+    vec.iov_len = len;
+
+    cmsg.len  = sizeof(cmsg);
+    cmsg.level = SOL_SOCKET;
+    cmsg.type = SCM_RIGHTS;
+    cmsg.fd = -1;
+
+    msghdr.msg_name = NULL;
+    msghdr.msg_namelen = 0;
+    msghdr.msg_iov = &vec;
+    msghdr.msg_iovlen = 1;
+    msghdr.msg_control = &cmsg;
+    msghdr.msg_controllen = sizeof(cmsg);
+    msghdr.msg_flags = 0;
+
+    ret = recvmsg(socket, &msghdr, 0);
+    if (ret < 0)
+           return -errno;
+    *fd = cmsg.fd;
+    return ret;
+}
+
+static void clean_state(snd_pcm_client_t *client)
+{
+       struct pollfd pfd;
+       int err;
+       char buf[1];
+       pfd.fd = client->data_fd;
+       switch (client->handle->stream) {
+       case SND_PCM_STREAM_PLAYBACK:
+               pfd.events = POLLOUT;
+               while (1) {
+                       err = poll(&pfd, 1, 0);
+                       if (err == 0)
+                               break;
+                       assert(err > 0);
+                       err = write(client->data_fd, buf, 1);
+                       assert(err == 1);
+               }
+               break;
+       case SND_PCM_STREAM_CAPTURE:
+               pfd.events = POLLIN;
+               while (1) {
+                       err = poll(&pfd, 1, 0);
+                       if (err == 0)
+                               break;
+                       assert(err > 0);
+                       err = read(client->data_fd, buf, 1);
+                       assert(err == 1);
+               }
+               break;
+       }
+}
+
+static int snd_pcm_client_shm_action(snd_pcm_client_t *client)
+{
+       int err;
+       char buf[1];
+       snd_pcm_client_shm_t *ctrl = client->u.shm.ctrl;
+       err = write(client->ctrl_fd, buf, 1);
+       if (err != 1)
+               return -EBADFD;
+       err = read(client->ctrl_fd, buf, 1);
+       if (err != 1)
+               return -EBADFD;
+       if (ctrl->cmd) {
+               fprintf(stderr, "Server has not done the cmd\n");
+               return -EBADFD;
+       }
+       return 0;
+}
+
+static int snd_pcm_client_shm_action_fd(snd_pcm_client_t *client)
+{
+       int err;
+       char buf[1];
+       snd_pcm_client_shm_t *ctrl = client->u.shm.ctrl;
+       int fd;
+       err = write(client->ctrl_fd, buf, 1);
+       if (err != 1)
+               return -EBADFD;
+       err = receive_fd(client->ctrl_fd, buf, 1, &fd);
+       if (err != 1)
+               return -EBADFD;
+       if (ctrl->cmd) {
+               fprintf(stderr, "Server has not done the cmd\n");
+               return -EBADFD;
+       }
+       if (ctrl->result < 0)
+               return ctrl->result;
+       return fd;
+}
+
+static int snd_pcm_client_shm_close(void *private)
+{
+       snd_pcm_client_t *client = (snd_pcm_client_t*) private;
+       snd_pcm_client_shm_t *ctrl = client->u.shm.ctrl;
+       int result;
+       ctrl->cmd = SND_PCM_IOCTL_CLOSE;
+       result = snd_pcm_client_shm_action(client);
+       if (result >= 0)
+               result = ctrl->result;
+       shmdt((void *)ctrl);
+       close(client->data_fd);
+       close(client->ctrl_fd);
+       return result;
+}
+
+static int snd_pcm_client_shm_nonblock(void *private, int nonblock)
+{
+       /* FIXME */
+       return 0;
+}
+
+static int snd_pcm_client_shm_info(void *private, snd_pcm_info_t * info)
+{
+       snd_pcm_client_t *client = (snd_pcm_client_t*) private;
+       snd_pcm_client_shm_t *ctrl = client->u.shm.ctrl;
+       int err;
+//     ctrl->u.info = *info;
+       ctrl->cmd = SND_PCM_IOCTL_INFO;
+       err = snd_pcm_client_shm_action(client);
+       if (err < 0)
+               return err;
+       memcpy(info, &ctrl->u.info, sizeof(*info));
+       return ctrl->result;
+}
+
+static int snd_pcm_client_shm_params_info(void *private, snd_pcm_params_info_t * info)
+{
+       snd_pcm_client_t *client = (snd_pcm_client_t*) private;
+       snd_pcm_client_shm_t *ctrl = client->u.shm.ctrl;
+       int err;
+       ctrl->cmd = SND_PCM_IOCTL_PARAMS_INFO;
+       ctrl->u.params_info = *info;
+       err = snd_pcm_client_shm_action(client);
+       if (err < 0)
+               return err;
+       *info = ctrl->u.params_info;
+       return ctrl->result;
+}
+
+static int snd_pcm_client_shm_params(void *private, snd_pcm_params_t * params)
+{
+       snd_pcm_client_t *client = (snd_pcm_client_t*) private;
+       snd_pcm_client_shm_t *ctrl = client->u.shm.ctrl;
+       int err;
+       ctrl->cmd = SND_PCM_IOCTL_PARAMS;
+       ctrl->u.params = *params;
+       err = snd_pcm_client_shm_action(client);
+       if (err < 0)
+               return err;
+       *params = ctrl->u.params;
+       return ctrl->result;
+}
+
+static int snd_pcm_client_shm_setup(void *private, snd_pcm_setup_t * setup)
+{
+       snd_pcm_client_t *client = (snd_pcm_client_t*) private;
+       snd_pcm_client_shm_t *ctrl = client->u.shm.ctrl;
+       int err;
+       ctrl->cmd = SND_PCM_IOCTL_SETUP;
+       // ctrl->u.setup = *setup;
+       err = snd_pcm_client_shm_action(client);
+       if (err < 0)
+               return err;
+       *setup = ctrl->u.setup;
+       return ctrl->result;
+}
+
+static int snd_pcm_client_shm_channel_info(void *private, snd_pcm_channel_info_t * info)
+{
+       snd_pcm_client_t *client = (snd_pcm_client_t*) private;
+       snd_pcm_client_shm_t *ctrl = client->u.shm.ctrl;
+       int err;
+       ctrl->cmd = SND_PCM_IOCTL_CHANNEL_INFO;
+       ctrl->u.channel_info = *info;
+       err = snd_pcm_client_shm_action(client);
+       if (err < 0)
+               return err;
+       *info = ctrl->u.channel_info;
+       return ctrl->result;
+}
+
+static int snd_pcm_client_shm_channel_params(void *private, snd_pcm_channel_params_t * params)
+{
+       snd_pcm_client_t *client = (snd_pcm_client_t*) private;
+       snd_pcm_client_shm_t *ctrl = client->u.shm.ctrl;
+       int err;
+       ctrl->cmd = SND_PCM_IOCTL_CHANNEL_PARAMS;
+       ctrl->u.channel_params = *params;
+       err = snd_pcm_client_shm_action(client);
+       if (err < 0)
+               return err;
+       *params = ctrl->u.channel_params;
+       return ctrl->result;
+}
+
+static int snd_pcm_client_shm_channel_setup(void *private, snd_pcm_channel_setup_t * setup)
+{
+       snd_pcm_client_t *client = (snd_pcm_client_t*) private;
+       snd_pcm_client_shm_t *ctrl = client->u.shm.ctrl;
+       int err;
+       ctrl->cmd = SND_PCM_IOCTL_CHANNEL_SETUP;
+       ctrl->u.channel_setup = *setup;
+       err = snd_pcm_client_shm_action(client);
+       if (err < 0)
+               return err;
+       *setup = ctrl->u.channel_setup;
+       return ctrl->result;
+}
+
+static int snd_pcm_client_shm_status(void *private, snd_pcm_status_t * status)
+{
+       snd_pcm_client_t *client = (snd_pcm_client_t*) private;
+       snd_pcm_client_shm_t *ctrl = client->u.shm.ctrl;
+       int err;
+       ctrl->cmd = SND_PCM_IOCTL_STATUS;
+       // ctrl->u.status = *status;
+       err = snd_pcm_client_shm_action(client);
+       if (err < 0)
+               return err;
+       *status = ctrl->u.status;
+       return ctrl->result;
+}
+
+static int snd_pcm_client_shm_state(void *private)
+{
+       snd_pcm_status_t status;
+       int err = snd_pcm_client_shm_status(private, &status);
+       if (err < 0)
+               return err;
+       return status.state;
+}
+
+static ssize_t snd_pcm_client_shm_frame_io(void *private, int update)
+{
+       snd_pcm_client_t *client = (snd_pcm_client_t*) private;
+       snd_pcm_client_shm_t *ctrl = client->u.shm.ctrl;
+       int err;
+       ctrl->cmd = SND_PCM_IOCTL_FRAME_IO;
+       ctrl->u.frame_io = update;
+       err = snd_pcm_client_shm_action(client);
+       if (err < 0)
+               return err;
+       return ctrl->result;
+}
+
+static int snd_pcm_client_shm_prepare(void *private)
+{
+       snd_pcm_client_t *client = (snd_pcm_client_t*) private;
+       snd_pcm_client_shm_t *ctrl = client->u.shm.ctrl;
+       int err;
+       ctrl->cmd = SND_PCM_IOCTL_PREPARE;
+       err = snd_pcm_client_shm_action(client);
+       if (err < 0)
+               return err;
+       return ctrl->result;
+}
+
+static int snd_pcm_client_shm_go(void *private)
+{
+       snd_pcm_client_t *client = (snd_pcm_client_t*) private;
+       snd_pcm_client_shm_t *ctrl = client->u.shm.ctrl;
+       int err;
+       ctrl->cmd = SND_PCM_IOCTL_GO;
+       err = snd_pcm_client_shm_action(client);
+       if (err < 0)
+               return err;
+       return ctrl->result;
+}
+
+static int snd_pcm_client_shm_drain(void *private)
+{
+       snd_pcm_client_t *client = (snd_pcm_client_t*) private;
+       snd_pcm_client_shm_t *ctrl = client->u.shm.ctrl;
+       int err;
+       ctrl->cmd = SND_PCM_IOCTL_DRAIN;
+       err = snd_pcm_client_shm_action(client);
+       if (err < 0)
+               return err;
+       return ctrl->result;
+}
+
+static int snd_pcm_client_shm_flush(void *private)
+{
+       snd_pcm_client_t *client = (snd_pcm_client_t*) private;
+       snd_pcm_client_shm_t *ctrl = client->u.shm.ctrl;
+       int err;
+       ctrl->cmd = SND_PCM_IOCTL_FLUSH;
+       err = snd_pcm_client_shm_action(client);
+       if (err < 0)
+               return err;
+       return ctrl->result;
+}
+
+static int snd_pcm_client_shm_pause(void *private, int enable)
+{
+       snd_pcm_client_t *client = (snd_pcm_client_t*) private;
+       snd_pcm_client_shm_t *ctrl = client->u.shm.ctrl;
+       int err;
+       ctrl->cmd = SND_PCM_IOCTL_PAUSE;
+       ctrl->u.pause = enable;
+       err = snd_pcm_client_shm_action(client);
+       if (err < 0)
+               return err;
+       return ctrl->result;
+}
+
+static ssize_t snd_pcm_client_shm_frame_data(void *private, off_t offset)
+{
+       snd_pcm_client_t *client = (snd_pcm_client_t*) private;
+       snd_pcm_client_shm_t *ctrl = client->u.shm.ctrl;
+       int err;
+       ctrl->cmd = SND_PCM_IOCTL_FRAME_DATA;
+       ctrl->u.frame_data = offset;
+       clean_state(client);
+       err = snd_pcm_client_shm_action(client);
+       if (err < 0)
+               return err;
+       return ctrl->result;
+}
+
+static ssize_t snd_pcm_client_shm_write(void *private, snd_timestamp_t *tstamp, const void *buffer, size_t size)
+{
+       snd_pcm_client_t *client = (snd_pcm_client_t*) private;
+       snd_pcm_client_shm_t *ctrl = client->u.shm.ctrl;
+       size_t maxsize = PCM_SHM_DATA_MAXLEN;
+       size_t bytes = snd_pcm_frames_to_bytes(client->handle, size);
+       int err;
+       if (bytes > maxsize)
+               return -EINVAL;
+       ctrl->cmd = SND_PCM_IOCTL_WRITE_FRAMES;
+//     ctrl->u.write.tstamp = *tstamp;
+       ctrl->u.write.count = size;
+       memcpy(ctrl->data, buffer, bytes);
+       clean_state(client);
+       err = snd_pcm_client_shm_action(client);
+       if (err < 0)
+               return err;
+       return ctrl->result;
+}
+
+static ssize_t snd_pcm_client_shm_writev(void *private, snd_timestamp_t *tstamp, const struct iovec *vector, unsigned long count)
+{
+       /* FIXME: interleaved */
+       snd_pcm_client_t *client = (snd_pcm_client_t*) private;
+       snd_pcm_client_shm_t *ctrl = client->u.shm.ctrl;
+       size_t vecsize = count * sizeof(struct iovec);
+       size_t maxsize = PCM_SHM_DATA_MAXLEN;
+       int bits_per_sample = client->handle->bits_per_sample;
+       char *base;
+       struct iovec *vec;
+       unsigned long k;
+       size_t ofs;
+       int err;
+       if (vecsize > maxsize)
+               return -EINVAL;
+       maxsize -= vecsize;
+       ctrl->cmd = SND_PCM_IOCTL_WRITEV_FRAMES;
+//     ctrl->u.writev.tstamp = *tstamp;
+       ctrl->u.writev.count = count;
+       memcpy(ctrl->data, vector, vecsize);
+       vec = (struct iovec *) ctrl->data;
+       base = ctrl->data + vecsize;
+       ofs = 0;
+       for (k = 0; k < count; ++k) {
+               size_t len = vector[k].iov_len * bits_per_sample / 8;
+               memcpy(base + ofs, vector[k].iov_base, len);
+               vec[k].iov_base = (void *) ofs;
+               ofs += len;
+       }
+       clean_state(client);
+       err = snd_pcm_client_shm_action(client);
+       if (err < 0)
+               return err;
+       return ctrl->result;
+}
+
+static ssize_t snd_pcm_client_shm_read(void *private, snd_timestamp_t *tstamp, void *buffer, size_t size)
+{
+       snd_pcm_client_t *client = (snd_pcm_client_t*) private;
+       snd_pcm_client_shm_t *ctrl = client->u.shm.ctrl;
+       size_t maxsize = PCM_SHM_DATA_MAXLEN;
+       size_t bytes = snd_pcm_frames_to_bytes(client->handle, size);
+       int err;
+       if (bytes > maxsize)
+               return -EINVAL;
+       ctrl->cmd = SND_PCM_IOCTL_READ_FRAMES;
+//     ctrl->u.read.tstamp = *tstamp;
+       ctrl->u.read.count = size;
+       clean_state(client);
+       err = snd_pcm_client_shm_action(client);
+       if (err < 0)
+               return err;
+       if (ctrl->result <= 0)
+               return ctrl->result;
+       bytes = snd_pcm_frames_to_bytes(client->handle, ctrl->result);
+       memcpy(buffer, ctrl->data, bytes);
+       return ctrl->result;
+}
+
+ssize_t snd_pcm_client_shm_readv(void *private, snd_timestamp_t *tstamp, const struct iovec *vector, unsigned long count)
+{
+       /* FIXME: interleaved */
+       snd_pcm_client_t *client = (snd_pcm_client_t*) private;
+       snd_pcm_client_shm_t *ctrl = client->u.shm.ctrl;
+       size_t vecsize = count * sizeof(struct iovec);
+       size_t maxsize = PCM_SHM_DATA_MAXLEN;
+       int bits_per_sample = client->handle->bits_per_sample;
+       char *base;
+       struct iovec *vec;
+       unsigned long k;
+       size_t ofs, bytes;
+       int err;
+       if (vecsize > maxsize)
+               return -EINVAL;
+       maxsize -= vecsize;
+       ctrl->cmd = SND_PCM_IOCTL_WRITEV_FRAMES;
+//     ctrl->u.writev.tstamp = *tstamp;
+       ctrl->u.writev.count = count;
+       memcpy(ctrl->data, vector, vecsize);
+       vec = (struct iovec *) ctrl->data;
+       base = ctrl->data + vecsize;
+       ofs = 0;
+       for (k = 0; k < count; ++k) {
+               size_t len = vector[k].iov_len * bits_per_sample / 8;
+               vec[k].iov_base = (void *) ofs;
+               ofs += len;
+       }
+       clean_state(client);
+       err = snd_pcm_client_shm_action(client);
+       if (err < 0)
+               return err;
+       if (ctrl->result <= 0)
+               return ctrl->result;
+       bytes = snd_pcm_frames_to_bytes(client->handle, ctrl->result);
+       ofs = 0;
+       for (k = 0; k < count; ++k) {
+               /* FIXME: optimize partial read */
+               size_t len = vector[k].iov_len * bits_per_sample / 8;
+               memcpy(vector[k].iov_base, base + ofs, len);
+               ofs += len;
+       }
+       return ctrl->result;
+}
+
+static int snd_pcm_client_shm_mmap_status(void *private, snd_pcm_mmap_status_t **status)
+{
+       snd_pcm_client_t *client = (snd_pcm_client_t*) private;
+       snd_pcm_client_shm_t *ctrl = client->u.shm.ctrl;
+       void *ptr;
+       int fd;
+       ctrl->cmd = SND_PCM_IOCTL_MMAP_STATUS;
+       fd = snd_pcm_client_shm_action_fd(client);
+       if (fd < 0)
+               return fd;
+       ptr = mmap(NULL, sizeof(snd_pcm_mmap_status_t), PROT_READ, MAP_FILE|MAP_SHARED, 
+                  fd, SND_PCM_MMAP_OFFSET_STATUS);
+       close(fd);
+       if (ptr == MAP_FAILED || ptr == NULL)
+               return -errno;
+       *status = ptr;
+       return 0;
+}
+
+static int snd_pcm_client_shm_mmap_control(void *private, snd_pcm_mmap_control_t **control)
+{
+       snd_pcm_client_t *client = (snd_pcm_client_t*) private;
+       snd_pcm_client_shm_t *ctrl = client->u.shm.ctrl;
+       void *ptr;
+       int fd;
+       ctrl->cmd = SND_PCM_IOCTL_MMAP_CONTROL;
+       fd = snd_pcm_client_shm_action_fd(client);
+       if (fd < 0)
+               return fd;
+       ptr = mmap(NULL, sizeof(snd_pcm_mmap_control_t), PROT_READ|PROT_WRITE, MAP_FILE|MAP_SHARED, 
+                  fd, SND_PCM_MMAP_OFFSET_CONTROL);
+       close(fd);
+       if (ptr == MAP_FAILED || ptr == NULL)
+               return -errno;
+       *control = ptr;
+       return 0;
+}
+
+static int snd_pcm_client_shm_mmap_data(void *private, void **buffer, size_t bsize ATTRIBUTE_UNUSED)
+{
+       snd_pcm_client_t *client = (snd_pcm_client_t*) private;
+       snd_pcm_client_shm_t *ctrl = client->u.shm.ctrl;
+       void *ptr;
+       int prot;
+       int fd;
+       ctrl->cmd = SND_PCM_IOCTL_MMAP_DATA;
+       fd = snd_pcm_client_shm_action_fd(client);
+       if (fd < 0)
+               return fd;
+       prot = client->handle->stream == SND_PCM_STREAM_PLAYBACK ? PROT_WRITE : PROT_READ;
+       ptr = mmap(NULL, bsize, prot, MAP_FILE|MAP_SHARED, 
+                    fd, SND_PCM_MMAP_OFFSET_DATA);
+       close(fd);
+       if (ptr == MAP_FAILED || ptr == NULL)
+               return -errno;
+       *buffer = ptr;
+       return 0;
+}
+
+static int snd_pcm_client_shm_munmap_status(void *private ATTRIBUTE_UNUSED, snd_pcm_mmap_status_t *status ATTRIBUTE_UNUSED)
+{
+#if 0
+       snd_pcm_client_t *client = (snd_pcm_client_t*) private;
+       snd_pcm_client_shm_t *ctrl = client->u.shm.ctrl;
+       int err;
+       ctrl->cmd = SND_PCM_IOCTL_MUNMAP_STATUS;
+       err = snd_pcm_client_shm_action(client);
+       if (err < 0)
+               return err;
+       return ctrl->result;
+#else
+       if (munmap(status, sizeof(*status)) < 0)
+               return -errno;
+       return 0;
+#endif
+}
+
+static int snd_pcm_client_shm_munmap_control(void *private ATTRIBUTE_UNUSED, snd_pcm_mmap_control_t *control ATTRIBUTE_UNUSED)
+{
+#if 0
+       snd_pcm_client_t *client = (snd_pcm_client_t*) private;
+       snd_pcm_client_shm_t *ctrl = client->u.shm.ctrl;
+       int err;
+       ctrl->cmd = SND_PCM_IOCTL_MUNMAP_CONTROL;
+       err = snd_pcm_client_shm_action(client);
+       if (err < 0)
+               return err;
+       return ctrl->result;
+#else
+       if (munmap(control, sizeof(*control)) < 0)
+               return -errno;
+       return 0;
+#endif
+}
+
+static int snd_pcm_client_shm_munmap_data(void *private ATTRIBUTE_UNUSED, void *buffer, size_t bsize)
+{
+#if 0
+       snd_pcm_client_t *client = (snd_pcm_client_t*) private;
+       snd_pcm_client_shm_t *ctrl = client->u.shm.ctrl;
+       int err;
+       ctrl->cmd = SND_PCM_IOCTL_MUNMAP_DATA;
+       err = snd_pcm_client_shm_action(client);
+       if (err < 0)
+               return err;
+       return ctrl->result;
+#else
+       if (munmap(buffer, bsize) < 0)
+               return -errno;
+       return 0;
+#endif
+}
+
+static int snd_pcm_client_file_descriptor(void *private)
+{
+       snd_pcm_client_t *client = (snd_pcm_client_t*) private;
+       return client->data_fd;
+}
+
+static int snd_pcm_client_channels_mask(void *private ATTRIBUTE_UNUSED,
+                                       bitset_t *client_vmask ATTRIBUTE_UNUSED)
+{
+       return 0;
+}
+
+static void snd_pcm_client_dump(void *private, FILE *fp)
+{
+       snd_pcm_client_t *client = (snd_pcm_client_t*) private;
+       snd_pcm_t *handle = client->handle;
+       fprintf(fp, "Client PCM\n");
+       if (handle->valid_setup) {
+               fprintf(fp, "\nIts setup is:\n");
+               snd_pcm_dump_setup(handle, fp);
+       }
+}
+
+struct snd_pcm_ops snd_pcm_client_ops = {
+       close: snd_pcm_client_shm_close,
+       info: snd_pcm_client_shm_info,
+       params_info: snd_pcm_client_shm_params_info,
+       params: snd_pcm_client_shm_params,
+       setup: snd_pcm_client_shm_setup,
+       dump: snd_pcm_client_dump,
+};
+
+struct snd_pcm_fast_ops snd_pcm_client_fast_ops = {
+       nonblock: snd_pcm_client_shm_nonblock,
+       channel_info: snd_pcm_client_shm_channel_info,
+       channel_params: snd_pcm_client_shm_channel_params,
+       channel_setup: snd_pcm_client_shm_channel_setup,
+       status: snd_pcm_client_shm_status,
+       frame_io: snd_pcm_client_shm_frame_io,
+       state: snd_pcm_client_shm_state,
+       prepare: snd_pcm_client_shm_prepare,
+       go: snd_pcm_client_shm_go,
+       drain: snd_pcm_client_shm_drain,
+       flush: snd_pcm_client_shm_flush,
+       pause: snd_pcm_client_shm_pause,
+       frame_data: snd_pcm_client_shm_frame_data,
+       write: snd_pcm_client_shm_write,
+       writev: snd_pcm_client_shm_writev,
+       read: snd_pcm_client_shm_read,
+       readv: snd_pcm_client_shm_readv,
+       mmap_status: snd_pcm_client_shm_mmap_status,
+       mmap_control: snd_pcm_client_shm_mmap_control,
+       mmap_data: snd_pcm_client_shm_mmap_data,
+       munmap_status: snd_pcm_client_shm_munmap_status,
+       munmap_control: snd_pcm_client_shm_munmap_control,
+       munmap_data: snd_pcm_client_shm_munmap_data,
+       file_descriptor: snd_pcm_client_file_descriptor,
+       channels_mask: snd_pcm_client_channels_mask,
+};
+
+static int make_local_socket(const char *filename)
+{
+       size_t l = strlen(filename);
+       size_t size = offsetof(struct sockaddr_un, sun_path) + l;
+       struct sockaddr_un *addr = alloca(size);
+       int sock;
+
+       sock = socket(PF_LOCAL, SOCK_STREAM, 0);
+       if (sock < 0)
+               return -errno;
+       
+       addr->sun_family = AF_LOCAL;
+       memcpy(addr->sun_path, filename, l);
+
+       if (connect(sock, (struct sockaddr *) addr, size) < 0)
+               return -errno;
+       return sock;
+}
+
+static int make_inet_socket(const char *host, int port)
+{
+       struct sockaddr_in addr;
+       int sock;
+       struct hostent *h = gethostbyname(host);
+       if (!h)
+               return -ENOENT;
+
+       sock = socket(PF_INET, SOCK_STREAM, 0);
+       if (sock < 0)
+               return -errno;
+       
+       addr.sin_family = AF_INET;
+       addr.sin_port = htons(port);
+       memcpy(&addr.sin_addr, h->h_addr_list[0], sizeof(struct in_addr));
+
+       if (connect(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0)
+               return -errno;
+       return sock;
+}
+
+/* port == -1 -> PF_LOCAL and host is the socket name */
+int snd_pcm_client_create(snd_pcm_t **handlep, char *host, int port, int transport, char *name, int stream, int mode)
+{
+       snd_pcm_t *handle;
+       snd_pcm_client_t *client;
+       snd_client_open_request_t *req;
+       snd_client_open_answer_t ans;
+       size_t namelen, reqlen;
+       int err;
+       int result;
+       int fds[2] = {-1, -1};
+       int k;
+       snd_pcm_client_shm_t *ctrl = NULL;
+       uint32_t rcookie, scookie = getpid();
+       namelen = strlen(name);
+       if (namelen > 255)
+               return -EINVAL;
+
+       for (k = 0; k < 2; ++k) {
+               if (port == -1)
+                       fds[k] = make_local_socket(host);
+               else
+                       fds[k] = make_inet_socket(host, port);
+               if (fds[k] < 0) {
+                       result = fds[k];
+                       goto _err;
+               }
+               err = write(fds[k], &scookie, sizeof(scookie));
+               if (err != sizeof(scookie)) {
+                       result = -EBADFD;
+                       goto _err;
+               }
+               err = read(fds[k], &rcookie, sizeof(rcookie));
+               if (err != sizeof(rcookie) ||
+                   rcookie != scookie) {
+                       result = -EBADFD;
+                       goto _err;
+               }
+       }
+
+       reqlen = sizeof(*req) + namelen;
+       req = alloca(reqlen);
+       memcpy(req->name, name, namelen);
+       req->dev_type = SND_DEV_TYPE_PCM;
+       req->transport_type = transport;
+       req->stream = stream;
+       req->mode = mode;
+       req->namelen = namelen;
+       err = write(fds[1], req, reqlen);
+       if (err < 0) {
+               result = -errno;
+               goto _err;
+       }
+       if ((size_t) err != reqlen) {
+               result = -EINVAL;
+               goto _err;
+       }
+       err = read(fds[1], &ans, sizeof(ans));
+       if (err < 0) {
+               result = -errno;
+               goto _err;
+       }
+       if (err != sizeof(ans)) {
+               result = -EINVAL;
+               goto _err;
+       }
+       result = ntohl(ans.result);
+       ans.cookie = ntohl(ans.cookie);
+       if (result < 0)
+               goto _err;
+
+       switch (transport) {
+       case SND_TRANSPORT_TYPE_SHM:
+               ctrl = shmat(ans.cookie, 0, 0);
+               if (!ctrl) {
+                       result = -errno;
+                       goto _err;
+               }
+               break;
+       default:
+               result = -ENOSYS;
+               goto _err;
+       }
+               
+       if (stream == SND_PCM_STREAM_PLAYBACK) {
+               struct pollfd pfd;
+               char buf[1];
+               int bufsize = 1;
+               pfd.fd = fds[0];
+               pfd.events = POLLOUT;
+               err = setsockopt(fds[0], SOL_SOCKET, SO_SNDBUF, &bufsize, sizeof(bufsize));
+               if (err < 0) {
+                       result = -errno;
+                       goto _err;
+               }
+               if (poll(&pfd, 1, 0) != 1) {
+                       result = -errno;
+                       goto _err;
+               }
+               while (1) {
+                       err = write(fds[0], buf, 1);
+                       if (err != 1) {
+                               result = -errno;
+                               goto _err;
+                       }
+                       err = poll(&pfd, 1, 0);
+                       if (err < 0) {
+                               result = -errno;
+                               goto _err;
+                       }
+                       if (err == 0)
+                               break;
+               }
+       }
+
+       handle = calloc(1, sizeof(snd_pcm_t));
+       if (!handle) {
+               result = -ENOMEM;
+               goto _err;
+       }
+       client = calloc(1, sizeof(snd_pcm_client_t));
+       if (!handle) {
+               free(handle);
+               result = -ENOMEM;
+               goto _err;
+       }
+
+       client->handle = handle;
+       client->data_fd = fds[0];
+       client->ctrl_fd = fds[1];
+       switch (transport) {
+       case SND_TRANSPORT_TYPE_SHM:
+               client->u.shm.ctrl = ctrl;
+               break;
+       }
+       handle->type = SND_PCM_TYPE_CLIENT;
+       handle->stream = stream;
+       handle->ops = &snd_pcm_client_ops;
+       handle->op_arg = client;
+       handle->fast_ops = &snd_pcm_client_fast_ops;
+       handle->fast_op_arg = client;
+       handle->mode = mode;
+       handle->private = client;
+       *handlep = handle;
+       return 0;
+
+ _err:
+       if (fds[0] >= 0)
+               close(fds[0]);
+       if (fds[1] >= 0)
+               close(fds[1]);
+       switch (transport) {
+       case SND_TRANSPORT_TYPE_SHM:
+               if (ctrl)
+                       shmdt(ctrl);
+               break;
+       }
+       return result;
+}
+
index f0b80bb1ff0389d88ce2d8efb58691bf3627337b..81c1ec8220280974a3a2782c777552280c0d9943 100644 (file)
@@ -292,9 +292,9 @@ ssize_t snd_pcm_hw_readv(void *private, snd_timestamp_t *tstamp, const struct io
 
 static int snd_pcm_hw_mmap_status(void *private, snd_pcm_mmap_status_t **status)
 {
-       void *ptr;
        snd_pcm_hw_t *hw = (snd_pcm_hw_t*) private;
-       ptr = mmap(NULL, sizeof(snd_pcm_mmap_control_t), PROT_READ, MAP_FILE|MAP_SHARED, 
+       void *ptr;
+       ptr = mmap(NULL, sizeof(snd_pcm_mmap_status_t), PROT_READ, MAP_FILE|MAP_SHARED, 
                   hw->fd, SND_PCM_MMAP_OFFSET_STATUS);
        if (ptr == MAP_FAILED || ptr == NULL)
                return -errno;
@@ -304,8 +304,8 @@ static int snd_pcm_hw_mmap_status(void *private, snd_pcm_mmap_status_t **status)
 
 static int snd_pcm_hw_mmap_control(void *private, snd_pcm_mmap_control_t **control)
 {
-       void *ptr;
        snd_pcm_hw_t *hw = (snd_pcm_hw_t*) private;
+       void *ptr;
        ptr = mmap(NULL, sizeof(snd_pcm_mmap_control_t), PROT_READ|PROT_WRITE, MAP_FILE|MAP_SHARED, 
                   hw->fd, SND_PCM_MMAP_OFFSET_CONTROL);
        if (ptr == MAP_FAILED || ptr == NULL)
@@ -316,15 +316,15 @@ static int snd_pcm_hw_mmap_control(void *private, snd_pcm_mmap_control_t **contr
 
 static int snd_pcm_hw_mmap_data(void *private, void **buffer, size_t bsize)
 {
-       int prot;
-       void *daddr;
        snd_pcm_hw_t *hw = (snd_pcm_hw_t*) private;
+       void *ptr;
+       int prot;
        prot = hw->handle->stream == SND_PCM_STREAM_PLAYBACK ? PROT_WRITE : PROT_READ;
-       daddr = mmap(NULL, bsize, prot, MAP_FILE|MAP_SHARED, 
+       ptr = mmap(NULL, bsize, prot, MAP_FILE|MAP_SHARED, 
                     hw->fd, SND_PCM_MMAP_OFFSET_DATA);
-       if (daddr == MAP_FAILED || daddr == NULL)
+       if (ptr == MAP_FAILED || ptr == NULL)
                return -errno;
-       *buffer = daddr;
+       *buffer = ptr;
        return 0;
 }