summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAbramo Bagnara <abramo@alsa-project.org>2000-08-31 11:21:05 +0000
committerAbramo Bagnara <abramo@alsa-project.org>2000-08-31 11:21:05 +0000
commit4637f62ff5134cf9df4640b0ccc931d164024989 (patch)
treed89eb184f51d4b6c31f2a81dd6cf15a41ed90231
parente94033141d96d27c60450f006d627766c884de34 (diff)
First version of ALSA client/server
-rw-r--r--configure.in2
-rw-r--r--include/Makefile.am2
-rw-r--r--include/aserver.h77
-rw-r--r--include/header.h10
-rw-r--r--include/pcm.h25
-rw-r--r--src/Makefile.am2
-rw-r--r--src/aserver/Makefile.am8
-rw-r--r--src/aserver/aserver.c885
-rw-r--r--src/pcm/Makefile.am2
-rw-r--r--src/pcm/pcm.c58
-rw-r--r--src/pcm/pcm_client.c878
-rw-r--r--src/pcm/pcm_hw.c16
12 files changed, 1931 insertions, 34 deletions
diff --git a/configure.in b/configure.in
index 26a143dd..d7fdedcb 100644
--- a/configure.in
+++ b/configure.in
@@ -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)
diff --git a/include/Makefile.am b/include/Makefile.am
index 2761c59a..a930d93a 100644
--- a/include/Makefile.am
+++ b/include/Makefile.am
@@ -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
index 00000000..428ec286
--- /dev/null
+++ b/include/aserver.h
@@ -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 */
+};
diff --git a/include/header.h b/include/header.h
index 93531352..6c667bd2 100644
--- a/include/header.h
+++ b/include/header.h
@@ -35,3 +35,13 @@
#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
+
diff --git a/include/pcm.h b/include/pcm.h
index 7750d9cc..0e67cf71 100644
--- a/include/pcm.h
+++ b/include/pcm.h
@@ -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
diff --git a/src/Makefile.am b/src/Makefile.am
index 4286ea43..60eb8612 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -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
index 00000000..dca5ca07
--- /dev/null
+++ b/src/aserver/Makefile.am
@@ -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
index 00000000..edc749af
--- /dev/null
+++ b/src/aserver/aserver.c
@@ -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;
+}
diff --git a/src/pcm/Makefile.am b/src/pcm/Makefile.am
index 927560ab..f08c8369 100644
--- a/src/pcm/Makefile.am
+++ b/src/pcm/Makefile.am
@@ -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
diff --git a/src/pcm/pcm.c b/src/pcm/pcm.c
index d37a4254..fc2507a1 100644
--- a/src/pcm/pcm.c
+++ b/src/pcm/pcm.c
@@ -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
index 00000000..31069058
--- /dev/null
+++ b/src/pcm/pcm_client.c
@@ -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;
+}
+
diff --git a/src/pcm/pcm_hw.c b/src/pcm/pcm_hw.c
index f0b80bb1..81c1ec82 100644
--- a/src/pcm/pcm_hw.c
+++ b/src/pcm/pcm_hw.c
@@ -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;
}