From e5e1ca14d4c0cb2a644b135b4452f4205df6135e Mon Sep 17 00:00:00 2001 From: Abramo Bagnara Date: Sat, 14 Oct 2000 10:31:34 +0000 Subject: [PATCH] Fixed mmap wrt shm. Renamed pcm_client, control_client to shm. More error messages. Implemented asoundrc as documented. --- TODO | 1 - aserver/aserver.c | 475 +++++++++++-------- include/aserver.h | 23 +- include/control.h | 9 +- include/pcm.h | 17 +- src/control/Makefile.am | 2 +- src/control/cards.c | 6 +- src/control/control.c | 138 ++---- src/control/control_client.c | 433 ------------------ src/control/control_hw.c | 36 +- src/control/control_local.h | 1 + src/control/control_shm.c | 512 +++++++++++++++++++++ src/pcm/Makefile.am | 2 +- src/pcm/pcm.c | 112 ++--- src/pcm/pcm_adpcm.c | 58 +-- src/pcm/pcm_alaw.c | 58 +-- src/pcm/pcm_client.c | 857 ----------------------------------- src/pcm/pcm_file.c | 102 ++--- src/pcm/pcm_hw.c | 228 +++++----- src/pcm/pcm_linear.c | 58 +-- src/pcm/pcm_local.h | 62 +-- src/pcm/pcm_mmap.c | 108 +---- src/pcm/pcm_mulaw.c | 58 +-- src/pcm/pcm_multi.c | 199 ++++---- src/pcm/pcm_plug.c | 120 ++--- src/pcm/pcm_plugin.c | 70 ++- src/pcm/pcm_plugin.h | 21 +- src/pcm/pcm_rate.c | 59 +-- src/pcm/pcm_route.c | 67 ++- src/pcm/pcm_share.c | 301 ++++++------ 30 files changed, 1640 insertions(+), 2553 deletions(-) delete mode 100644 src/control/control_client.c create mode 100644 src/control/control_shm.c delete mode 100644 src/pcm/pcm_client.c diff --git a/TODO b/TODO index 201b441b..c50d46be 100644 --- a/TODO +++ b/TODO @@ -1,3 +1,2 @@ -H solve multi/server mmap'ing problem M add abstraction layer to timer, rawmidi, hwdep, seq L move OSS emulation to user space? (pseudo device driver and daemon) diff --git a/aserver/aserver.c b/aserver/aserver.c index 7f54885e..a35570c4 100644 --- a/aserver/aserver.c +++ b/aserver/aserver.c @@ -31,29 +31,29 @@ #include #include #include +#include #include "asoundlib.h" -#include "pcm_local.h" #include "aserver.h" #include "list.h" char *command; #if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95) -#define error(...) do {\ - fprintf(stderr, "%s: %s:%d: ", command, __FUNCTION__, __LINE__); \ +#define ERROR(...) do {\ + fprintf(stderr, "%s %s:%i:(%s) ", command, __FILE__, __LINE__, __FUNCTION__); \ fprintf(stderr, __VA_ARGS__); \ putc('\n', stderr); \ } while (0) #else -#define error(args...) do {\ - fprintf(stderr, "%s: %s:%d: ", command, __FUNCTION__, __LINE__); \ +#define ERROR(args...) do {\ + fprintf(stderr, "%s %s:%i:(%s) ", command, __FILE__, __LINE__, __FUNCTION__); \ fprintf(stderr, ##args); \ putc('\n', stderr); \ } while (0) #endif -#define perrno(string) error("%s", strerror(errno)) +#define SYSERR(string) ERROR(string ": %s", strerror(errno)) int make_local_socket(const char *filename) { @@ -65,7 +65,7 @@ int make_local_socket(const char *filename) sock = socket(PF_LOCAL, SOCK_STREAM, 0); if (sock < 0) { int result = -errno; - perrno("socket"); + SYSERR("socket"); return result; } @@ -76,7 +76,7 @@ int make_local_socket(const char *filename) if (bind(sock, (struct sockaddr *) addr, size) < 0) { int result = -errno; - perrno("bind"); + SYSERR("bind"); return result; } @@ -91,7 +91,7 @@ int make_inet_socket(int port) sock = socket(PF_INET, SOCK_STREAM, 0); if (sock < 0) { int result = -errno; - perrno("socket"); + SYSERR("socket"); return result; } @@ -101,7 +101,7 @@ int make_inet_socket(int port) if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { int result = -errno; - perrno("bind"); + SYSERR("bind"); return result; } @@ -135,7 +135,7 @@ int send_fd(int socket, void *data, size_t len, int fd) ret = sendmsg(socket, &msghdr, 0 ); if (ret < 0) { - perrno("sendmsg"); + SYSERR("sendmsg"); return -errno; } return ret; @@ -182,13 +182,6 @@ void del_waiter(int fd) memmove(&pollfds[k], &pollfds[k + 1], pollfds_count - k); } -typedef struct { - struct list_head list; - int fd; - int local; -} master_t; -LIST_HEAD(masters); - typedef struct client client_t; typedef struct { @@ -199,10 +192,9 @@ typedef struct { struct client { struct list_head list; - struct socket { - int fd; - int local; - } data, ctrl; + int poll_fd; + int ctrl_fd; + int local; int transport_type; int dev_type; char name[256]; @@ -250,9 +242,8 @@ typedef struct { struct list_head list; int fd; uint32_t cookie; - int local; -} pending_t; -LIST_HEAD(pendings); +} inet_pending_t; +LIST_HEAD(inet_pendings); int pcm_handler(waiter_t *waiter, unsigned short events) { @@ -260,15 +251,15 @@ int pcm_handler(waiter_t *waiter, unsigned short events) char buf[1]; ssize_t n; if (events & POLLIN) { - n = write(client->data.fd, buf, 1); + n = write(client->poll_fd, buf, 1); if (n != 1) { - perrno("write"); + SYSERR("write"); return -errno; } } else if (events & POLLOUT) { - n = read(client->data.fd, buf, 1); + n = read(client->poll_fd, buf, 1); if (n != 1) { - perrno("read"); + SYSERR("read"); return -errno; } } @@ -283,7 +274,7 @@ int pcm_shm_open(client_t *client, int *cookie) snd_pcm_t *pcm; int err; int result; - err = snd_pcm_open(&pcm, client->name, client->stream, client->mode); + err = snd_pcm_open(&pcm, client->name, client->stream, SND_PCM_NONBLOCK); if (err < 0) return err; client->device.pcm.handle = pcm; @@ -292,7 +283,7 @@ int pcm_shm_open(client_t *client, int *cookie) shmid = shmget(IPC_PRIVATE, PCM_SHM_SIZE, 0666); if (shmid < 0) { result = -errno; - perrno("shmget"); + SYSERR("shmget"); goto _err; } client->transport.shm.ctrl_id = shmid; @@ -300,7 +291,7 @@ int pcm_shm_open(client_t *client, int *cookie) if (!client->transport.shm.ctrl) { result = -errno; shmctl(shmid, IPC_RMID, 0); - perrno("shmat"); + SYSERR("shmat"); goto _err; } *cookie = shmid; @@ -315,38 +306,66 @@ int pcm_shm_open(client_t *client, int *cookie) int pcm_shm_close(client_t *client) { int err; - snd_pcm_client_shm_t *ctrl = client->transport.shm.ctrl; + snd_pcm_shm_ctrl_t *ctrl = client->transport.shm.ctrl; if (client->polling) { del_waiter(client->device.pcm.fd); client->polling = 0; } - /* FIXME: blocking */ err = snd_pcm_close(client->device.pcm.handle); ctrl->result = err; if (err < 0) - perrno("snd_pcm_close"); + SYSERR("snd_pcm_close"); if (client->transport.shm.ctrl) { err = shmdt((void *)client->transport.shm.ctrl); if (err < 0) - perrno("shmdt"); + SYSERR("shmdt"); err = shmctl(client->transport.shm.ctrl_id, IPC_RMID, 0); if (err < 0) - perrno("shmctl"); + SYSERR("shmctl"); client->transport.shm.ctrl = 0; } client->open = 0; return 0; } -int pcm_shm_cmd(client_t *client) +int shm_ack(client_t *client) { - snd_pcm_client_shm_t *ctrl = client->transport.shm.ctrl; struct pollfd pfd; + int err; + char buf[1]; + 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; +} + +int shm_ack_fd(client_t *client, int fd) +{ + struct pollfd pfd; + int err; + char buf[1]; + pfd.fd = client->ctrl_fd; + pfd.events = POLLHUP; + if (poll(&pfd, 1, 0) == 1) + return -EBADFD; + err = send_fd(client->ctrl_fd, buf, 1, fd); + if (err != 1) + return -EBADFD; + return 0; +} + +int pcm_shm_cmd(client_t *client) +{ + snd_pcm_shm_ctrl_t *ctrl = client->transport.shm.ctrl; char buf[1]; int err; int cmd; snd_pcm_t *pcm; - err = read(client->ctrl.fd, buf, 1); + err = read(client->ctrl_fd, buf, 1); if (err != 1) return -EBADFD; cmd = ctrl->cmd; @@ -409,63 +428,74 @@ int pcm_shm_cmd(client_t *client) break; case SND_PCM_IOCTL_LINK: { - struct list_head *item; - list_for_each(item, &clients) { - client_t *client = list_entry(item, client_t, list); - if (!client->open) - continue; - if (client->data.fd == ctrl->u.link) { - ctrl->result = snd_pcm_link(pcm, client->device.pcm.handle); - break; - } - } - ctrl->result = -EBADFD; + /* FIXME */ + ctrl->result = -ENOSYS; 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: + case SND_PCM_IOCTL_MMAP: { - 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; + err = snd_pcm_mmap(pcm); + if (err < 0) + ctrl->result = err; + else + ctrl->result = pcm->mmap_info_count; + break; } - case SND_PCM_IOCTL_MUNMAP_DATA: - case SND_PCM_IOCTL_MUNMAP_CONTROL: - case SND_PCM_IOCTL_MUNMAP_STATUS: + case SND_PCM_IOCTL_MMAP_INFO: + { + snd_pcm_mmap_info_t *i; + unsigned int index = ctrl->u.mmap_info.index; + if (index >= pcm->mmap_info_count) { + ctrl->result = -EINVAL; + break; + } + i = &pcm->mmap_info[index]; + if (i->type == SND_PCM_MMAP_USER) { + i->u.user.shmid = shmget(IPC_PRIVATE, i->size, 0666); + if (i->u.user.shmid < 0) { + SYSERR("shmget"); + return -EINVAL; + } + } + ctrl->u.mmap_info = *i; + ctrl->u.mmap_info.index = index; ctrl->result = 0; + if (i->type == SND_PCM_MMAP_USER) + break; + return shm_ack_fd(client, i->u.kernel.fd); + } + case SND_PCM_IOCTL_MUNMAP: + { + size_t k; + ctrl->result = snd_pcm_munmap(pcm); + if (ctrl->result < 0) + break; + for (k = 0; k < pcm->mmap_info_count; ++k) { + snd_pcm_mmap_info_t *i = &pcm->mmap_info[k]; + if (i->type == SND_PCM_MMAP_USER) { + int err = shmdt(i->addr); + assert(err >= 0); + } + } break; + } case SND_PCM_IOCTL_MMAP_FORWARD: ctrl->result = snd_pcm_mmap_forward(pcm, ctrl->u.mmap_forward); break; + case SND_PCM_IOCTL_POLL_DESCRIPTOR: + ctrl->result = 0; + return shm_ack_fd(client, snd_pcm_poll_descriptor(pcm)); case SND_PCM_IOCTL_CLOSE: client->ops->close(client); break; default: - fprintf(stderr, "Bogus cmd: %x\n", ctrl->cmd); + ERROR("Bogus cmd: %x", 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; - if (!client->polling) { - add_waiter(client->device.pcm.fd, POLLIN | POLLOUT, pcm_handler, client); - client->polling = 1; - } - return 0; + return shm_ack(client); } transport_ops_t pcm_shm_ops = { @@ -480,9 +510,9 @@ int ctl_handler(waiter_t *waiter, unsigned short events) char buf[1]; ssize_t n; if (events & POLLIN) { - n = write(client->data.fd, buf, 1); + n = write(client->poll_fd, buf, 1); if (n != 1) { - perrno("write"); + SYSERR("write"); return -errno; } } @@ -506,7 +536,7 @@ int ctl_shm_open(client_t *client, int *cookie) shmid = shmget(IPC_PRIVATE, CTL_SHM_SIZE, 0666); if (shmid < 0) { result = -errno; - perrno("shmget"); + SYSERR("shmget"); goto _err; } client->transport.shm.ctrl_id = shmid; @@ -514,7 +544,7 @@ int ctl_shm_open(client_t *client, int *cookie) if (!client->transport.shm.ctrl) { result = -errno; shmctl(shmid, IPC_RMID, 0); - perrno("shmat"); + SYSERR("shmat"); goto _err; } *cookie = shmid; @@ -531,23 +561,22 @@ int ctl_shm_open(client_t *client, int *cookie) int ctl_shm_close(client_t *client) { int err; - snd_ctl_client_shm_t *ctrl = client->transport.shm.ctrl; + snd_ctl_shm_ctrl_t *ctrl = client->transport.shm.ctrl; if (client->polling) { del_waiter(client->device.control.fd); client->polling = 0; } - /* FIXME: blocking */ err = snd_ctl_close(client->device.control.handle); ctrl->result = err; if (err < 0) - perrno("snd_ctl_close"); + SYSERR("snd_ctl_close"); if (client->transport.shm.ctrl) { err = shmdt((void *)client->transport.shm.ctrl); if (err < 0) - perrno("shmdt"); + SYSERR("shmdt"); err = shmctl(client->transport.shm.ctrl_id, IPC_RMID, 0); if (err < 0) - perrno("shmctl"); + SYSERR("shmctl"); client->transport.shm.ctrl = 0; } client->open = 0; @@ -558,13 +587,12 @@ extern int snd_ctl_read1(snd_ctl_t *ctl, snd_ctl_event_t *event); int ctl_shm_cmd(client_t *client) { - snd_ctl_client_shm_t *ctrl = client->transport.shm.ctrl; - struct pollfd pfd; + snd_ctl_shm_ctrl_t *ctrl = client->transport.shm.ctrl; char buf[1]; int err; int cmd; snd_ctl_t *ctl; - err = read(client->ctrl.fd, buf, 1); + err = read(client->ctrl_fd, buf, 1); if (err != 1) return -EBADFD; cmd = ctrl->cmd; @@ -612,22 +640,14 @@ int ctl_shm_cmd(client_t *client) case SND_CTL_IOCTL_CLOSE: client->ops->close(client); break; + case SND_PCM_IOCTL_POLL_DESCRIPTOR: + ctrl->result = 0; + return shm_ack_fd(client, snd_ctl_poll_descriptor(ctl)); default: - fprintf(stderr, "Bogus cmd: %x\n", ctrl->cmd); + ERROR("Bogus cmd: %x", 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; - if (!client->polling) { - add_waiter(client->device.control.fd, POLLIN, ctl_handler, client); - client->polling = 1; - } - return 0; + return shm_ack(client); } transport_ops_t ctl_shm_ops = { @@ -643,9 +663,9 @@ int snd_client_open(client_t *client) snd_client_open_answer_t ans; char *name; memset(&ans, 0, sizeof(ans)); - err = read(client->ctrl.fd, &req, sizeof(req)); + err = read(client->ctrl_fd, &req, sizeof(req)); if (err < 0) { - perrno("read"); + SYSERR("read"); exit(1); } if (err != sizeof(req)) { @@ -653,9 +673,9 @@ int snd_client_open(client_t *client) goto _answer; } name = alloca(req.namelen); - err = read(client->ctrl.fd, name, req.namelen); + err = read(client->ctrl_fd, name, req.namelen); if (err < 0) { - perrno("read"); + SYSERR("read"); exit(1); } if (err != req.namelen) { @@ -663,20 +683,17 @@ int snd_client_open(client_t *client) 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: + switch (req.transport_type) { + case SND_TRANSPORT_TYPE_SHM: + if (!client->local) { ans.result = -EINVAL; goto _answer; } - break; - case SND_DEV_TYPE_CONTROL: - switch (req.transport_type) { - case SND_TRANSPORT_TYPE_SHM: + switch (req.dev_type) { + case SND_DEV_TYPE_PCM: + client->ops = &pcm_shm_ops; + break; + case SND_DEV_TYPE_CONTROL: client->ops = &ctl_shm_ops; break; default: @@ -701,27 +718,27 @@ int snd_client_open(client_t *client) ans.result = err; } else { client->open = 1; - ans.result = client->data.fd; + ans.result = 0; } _answer: - err = write(client->ctrl.fd, &ans, sizeof(ans)); + err = write(client->ctrl_fd, &ans, sizeof(ans)); if (err != sizeof(ans)) { - perrno("write"); + SYSERR("write"); exit(1); } return 0; } -int client_data_handler(waiter_t *waiter, unsigned short events ATTRIBUTE_UNUSED) +int client_poll_handler(waiter_t *waiter, unsigned short events ATTRIBUTE_UNUSED) { client_t *client = waiter->private_data; if (client->open) client->ops->close(client); - close(client->data.fd); - close(client->ctrl.fd); - del_waiter(client->data.fd); - del_waiter(client->ctrl.fd); + close(client->poll_fd); + close(client->ctrl_fd); + del_waiter(client->poll_fd); + del_waiter(client->ctrl_fd); list_del(&client->list); free(client); return 0; @@ -730,18 +747,25 @@ int client_data_handler(waiter_t *waiter, unsigned short events ATTRIBUTE_UNUSED int client_ctrl_handler(waiter_t *waiter, unsigned short events) { client_t *client = waiter->private_data; - if (events & POLLHUP) - return client_data_handler(waiter, events); + if (events & POLLHUP) { + if (client->open) + client->ops->close(client); + close(client->ctrl_fd); + del_waiter(client->ctrl_fd); + list_del(&client->list); + free(client); + return 0; + } if (client->open) return client->ops->cmd(client); else return snd_client_open(client); } -int pending_handler(waiter_t *waiter, unsigned short events) +int inet_pending_handler(waiter_t *waiter, unsigned short events) { - pending_t *pending = waiter->private_data; - pending_t *pdata; + inet_pending_t *pending = waiter->private_data; + inet_pending_t *pdata; client_t *client; uint32_t cookie; struct list_head *item; @@ -766,8 +790,8 @@ int pending_handler(waiter_t *waiter, unsigned short events) return 0; } - list_for_each(item, &pendings) { - pdata = list_entry(item, pending_t, list); + list_for_each(item, &inet_pendings) { + pdata = list_entry(item, inet_pending_t, list); if (pdata->cookie == cookie) goto found; } @@ -775,13 +799,12 @@ int pending_handler(waiter_t *waiter, unsigned short events) return 0; found: - client = calloc(sizeof(*client), 1); - client->data.fd = pdata->fd; - client->data.local = pdata->local; - client->ctrl.fd = waiter->fd; - client->ctrl.local = pending->local; - add_waiter(client->ctrl.fd, POLLIN | POLLHUP, client_ctrl_handler, client); - add_waiter(client->data.fd, POLLHUP, client_data_handler, client); + client = calloc(1, sizeof(*client)); + client->local = 0; + client->poll_fd = pdata->fd; + client->ctrl_fd = waiter->fd; + add_waiter(client->ctrl_fd, POLLIN | POLLHUP, client_ctrl_handler, client); + add_waiter(client->poll_fd, POLLHUP, client_poll_handler, client); client->open = 0; list_add_tail(&client->list, &clients); list_del(&pending->list); @@ -791,70 +814,81 @@ int pending_handler(waiter_t *waiter, unsigned short events) return 0; } -int master_handler(waiter_t *waiter, unsigned short events ATTRIBUTE_UNUSED) +int local_handler(waiter_t *waiter, unsigned short events ATTRIBUTE_UNUSED) { - master_t *master = waiter->private_data; int sock; sock = accept(waiter->fd, 0, 0); if (sock < 0) { int result = -errno; - perrno("accept"); + SYSERR("accept"); return result; } else { - pending_t *pending = calloc(sizeof(*pending), 1); + client_t *client = calloc(1, sizeof(*client)); + client->ctrl_fd = sock; + client->local = 1; + client->open = 0; + add_waiter(sock, POLLIN | POLLHUP, client_ctrl_handler, client); + list_add_tail(&client->list, &clients); + } + return 0; +} + +int inet_handler(waiter_t *waiter, unsigned short events ATTRIBUTE_UNUSED) +{ + int sock; + sock = accept(waiter->fd, 0, 0); + if (sock < 0) { + int result = -errno; + SYSERR("accept"); + return result; + } else { + inet_pending_t *pending = calloc(1, sizeof(*pending)); pending->fd = sock; - pending->local = master->local; pending->cookie = 0; - add_waiter(sock, POLLIN, pending_handler, pending); - list_add_tail(&pending->list, &pendings); + add_waiter(sock, POLLIN, inet_pending_handler, pending); + list_add_tail(&pending->list, &inet_pendings); } return 0; } int server(char *sockname, int port) { - struct list_head *item; int err; unsigned int k; + if (!sockname && port < 0) + return -EINVAL; if (sockname) { int sock = make_local_socket(sockname); - master_t *master; if (sock < 0) return sock; - master = calloc(sizeof(*master), 1); - master->fd = sock; - master->local = 1; - add_waiter(sock, POLLIN, master_handler, master); - list_add_tail(&master->list, &masters); + if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0) { + int result = -errno; + SYSERR("fcntl"); + return result; + } + if (listen(sock, 4) < 0) { + int result = -errno; + SYSERR("listen"); + return result; + } + add_waiter(sock, POLLIN, local_handler, NULL); } if (port >= 0) { int sock = make_inet_socket(port); - master_t *master; if (sock < 0) return sock; - master = calloc(sizeof(*master), 1); - master->fd = sock; - master->local = 0; - add_waiter(sock, POLLIN, master_handler, master); - list_add_tail(&master->list, &masters); - } - - if (list_empty(&masters)) - return -EINVAL; - - list_for_each(item, &masters) { - master_t *master = list_entry(item, master_t, list); - if (fcntl(master->fd, F_SETFL, O_NONBLOCK) < 0) { + if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0) { int result = -errno; - perrno("fcntl"); + SYSERR("fcntl"); return result; } - if (listen(master->fd, 4) < 0) { + if (listen(sock, 4) < 0) { int result = -errno; - perrno("listen"); + SYSERR("listen"); return result; } + add_waiter(sock, POLLIN, inet_handler, NULL); } while (1) { @@ -864,7 +898,7 @@ int server(char *sockname, int port) err = poll(pollfds, pollfds_count, 1000); } while (err == 0); if (err < 0) { - perrno("poll"); + SYSERR("poll"); continue; } @@ -878,7 +912,7 @@ int server(char *sockname, int port) continue; err = w->handler(w, pfd->revents); if (err < 0) - perrno("handler"); + SYSERR("handler"); } } } @@ -889,47 +923,102 @@ int server(char *sockname, int port) void usage() { fprintf(stderr, "\ -Usage: %s [OPTIONS] +Usage: %s [OPTIONS] server --help help ---version print current version --l,--local SOCKNAME local socket name --p,--port PORT port number ", command); } +extern int is_local(struct hostent *hent); + 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; + snd_config_t *conf; + snd_config_iterator_t i; + char *socket = NULL; + char *host = NULL; + long port = -1; + int err; + char *srvname; + struct hostent *h; command = argv[0]; - while ((c = getopt_long(argc, argv, "hl:p:", long_options, 0)) != -1) { + while ((c = getopt_long(argc, argv, "h", 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); + if (argc - optind != 1) { + ERROR("you need to specify server name"); return 1; } - - server(local, port); + err = snd_config_update(); + if (err < 0) { + ERROR("cannot read configuration file"); + return 1; + } + srvname = argv[optind]; + err = snd_config_searchv(snd_config, &conf, "server", srvname, 0); + if (err < 0) { + ERROR("unknown server %s", srvname); + return 1; + } + snd_config_foreach(i, conf) { + snd_config_t *n = snd_config_entry(i); + if (strcmp(n->id, "comment") == 0) + continue; + if (strcmp(n->id, "host") == 0) { + err = snd_config_string_get(n, &host); + if (err < 0) { + ERROR("Invalid type for host"); + return 1; + } + continue; + } + if (strcmp(n->id, "socket") == 0) { + err = snd_config_string_get(n, &socket); + if (err < 0) { + ERROR("Invalid type for socket"); + return 1; + } + continue; + } + if (strcmp(n->id, "port") == 0) { + err = snd_config_integer_get(n, &port); + if (err < 0) { + ERROR("Invalid type for port"); + return 1; + } + continue; + } + ERROR("Unknown field: %s", n->id); + return 1; + } + if (!host) { + ERROR("host is not defined"); + return 1; + } + h = gethostbyname(host); + if (!h) { + ERROR("Cannot resolve %s", host); + return 1; + } + if (!is_local(h)) { + ERROR("%s is not the local host", host); + return 1; + } + if (!socket && port < 0) { + ERROR("either socket or port need to be defined"); + return 1; + } + server(socket, port); return 0; } diff --git a/include/aserver.h b/include/aserver.h index d48caf52..9a68b0d7 100644 --- a/include/aserver.h +++ b/include/aserver.h @@ -19,17 +19,17 @@ */ +#include "../src/pcm/pcm_local.h" + #define SND_PCM_IOCTL_STATE _IO ('A', 0xf0) -#define SND_PCM_IOCTL_MMAP_DATA _IO ('A', 0xf1) -#define SND_PCM_IOCTL_MMAP_CONTROL _IO ('A', 0xf2) -#define SND_PCM_IOCTL_MMAP_STATUS _IO ('A', 0xf3) -#define SND_PCM_IOCTL_MUNMAP_DATA _IO ('A', 0xf4) -#define SND_PCM_IOCTL_MUNMAP_CONTROL _IO ('A', 0xf5) -#define SND_PCM_IOCTL_MUNMAP_STATUS _IO ('A', 0xf6) +#define SND_PCM_IOCTL_MMAP _IO ('A', 0xf1) +#define SND_PCM_IOCTL_MUNMAP _IO ('A', 0xf4) #define SND_PCM_IOCTL_MMAP_FORWARD _IO ('A', 0xf7) #define SND_PCM_IOCTL_AVAIL_UPDATE _IO ('A', 0xf8) #define SND_PCM_IOCTL_ASYNC _IO ('A', 0xf9) #define SND_PCM_IOCTL_CLOSE _IO ('A', 0xfa) +#define SND_PCM_IOCTL_MMAP_INFO _IO ('A', 0xfb) +#define SND_PCM_IOCTL_POLL_DESCRIPTOR _IO ('A', 0xfc) typedef struct { long result; @@ -39,6 +39,7 @@ typedef struct { int sig; pid_t pid; } async; + snd_pcm_mmap_info_t mmap_info; snd_pcm_info_t info; snd_pcm_params_t params; snd_pcm_params_info_t params_info; @@ -54,13 +55,13 @@ typedef struct { size_t mmap_forward; } u; char data[0]; -} snd_pcm_client_shm_t; +} snd_pcm_shm_ctrl_t; -#define PCM_SHM_SIZE 65536 -#define PCM_SHM_DATA_MAXLEN (PCM_SHM_SIZE - offsetof(snd_pcm_client_shm_t, data)) +#define PCM_SHM_SIZE sizeof(snd_pcm_shm_ctrl_t) #define SND_CTL_IOCTL_READ _IOR('U', 0xf0, snd_ctl_event_t) #define SND_CTL_IOCTL_CLOSE _IO ('U', 0xf1) +#define SND_CTL_IOCTL_POLL_DESCRIPTOR _IO ('U', 0xf2) typedef struct { int result; @@ -78,10 +79,10 @@ typedef struct { snd_ctl_event_t read; } u; char data[0]; -} snd_ctl_client_shm_t; +} snd_ctl_shm_ctrl_t; #define CTL_SHM_SIZE 65536 -#define CTL_SHM_DATA_MAXLEN (CTL_SHM_SIZE - offsetof(snd_ctl_client_shm_t, data)) +#define CTL_SHM_DATA_MAXLEN (CTL_SHM_SIZE - offsetof(snd_ctl_shm_ctrl_t, data)) typedef struct { unsigned char dev_type; diff --git a/include/control.h b/include/control.h index 07ad251e..e1221a76 100644 --- a/include/control.h +++ b/include/control.h @@ -7,7 +7,10 @@ typedef struct snd_ctl snd_ctl_t; -typedef enum { SND_CTL_TYPE_HW, SND_CTL_TYPE_CLIENT } snd_ctl_type_t; +typedef enum { SND_CTL_TYPE_HW, + SND_CTL_TYPE_SHM, + SND_CTL_TYPE_INET + } snd_ctl_type_t; typedef struct snd_ctl_callbacks { void *private_data; /* may be used by an application */ @@ -37,8 +40,8 @@ int snd_defaults_pcm_device(void); int snd_defaults_rawmidi_card(void); int snd_defaults_rawmidi_device(void); -int snd_ctl_hw_open(snd_ctl_t **handle, int card); -int snd_ctl_client_open(snd_ctl_t **handlep, char *host, int port, int transport, char *name); +int snd_ctl_hw_open(snd_ctl_t **handle, char *name, int card); +int snd_ctl_shm_open(snd_ctl_t **handlep, char *name, char *socket, char *sname); snd_ctl_type_t snd_ctl_type(snd_ctl_t *handle); int snd_ctl_open(snd_ctl_t **handle, char *name); int snd_ctl_close(snd_ctl_t *handle); diff --git a/include/pcm.h b/include/pcm.h index 1671d9e2..d0414943 100644 --- a/include/pcm.h +++ b/include/pcm.h @@ -104,7 +104,8 @@ typedef enum { SND_PCM_TYPE_MULTI, SND_PCM_TYPE_FILE, SND_PCM_TYPE_NULL, - SND_PCM_TYPE_CLIENT, + SND_PCM_TYPE_SHM, + SND_PCM_TYPE_INET, SND_PCM_TYPE_LINEAR, SND_PCM_TYPE_ALAW, SND_PCM_TYPE_MULAW, @@ -118,16 +119,16 @@ typedef enum { SND_PCM_TYPE_LBSERVER, } snd_pcm_type_t; -extern void (*snd_pcm_error)(const char *file, int line, const char *function, const char *fmt, ...); +extern void snd_pcm_error(const char *file, int line, const char *function, const char *fmt, ...) __attribute__ ((weak, format (printf, 4, 5))); -int snd_pcm_open(snd_pcm_t **handle, char *name, +int snd_pcm_open(snd_pcm_t **pcm, char *name, int stream, int mode); /* Obsolete functions */ -int snd_pcm_hw_open_subdevice(snd_pcm_t **handle, int card, int device, int subdevice, int stream, int mode); -int snd_pcm_hw_open_device(snd_pcm_t **handle, int card, int device, int stream, int mode); -int snd_pcm_plug_open_subdevice(snd_pcm_t **handle, int card, int device, int subdevice, int stream, int mode); -int snd_pcm_plug_open_device(snd_pcm_t **handle, int card, int device, int stream, int mode); +int snd_pcm_hw_open_subdevice(snd_pcm_t **pcm, int card, int device, int subdevice, int stream, int mode); +int snd_pcm_hw_open_device(snd_pcm_t **pcm, int card, int device, int stream, int mode); +int snd_pcm_plug_open_subdevice(snd_pcm_t **pcm, int card, int device, int subdevice, int stream, int mode); +int snd_pcm_plug_open_device(snd_pcm_t **pcm, int card, int device, int stream, int mode); #define snd_pcm_write snd_pcm_writei #define snd_pcm_read snd_pcm_readi ssize_t snd_pcm_writev(snd_pcm_t *pcm, const struct iovec *vector, int count); @@ -171,7 +172,7 @@ ssize_t snd_pcm_avail_update(snd_pcm_t *pcm); /* mmap */ -int snd_pcm_mmap(snd_pcm_t *pcm, void **buffer); +int snd_pcm_mmap(snd_pcm_t *pcm); int snd_pcm_munmap(snd_pcm_t *pcm); snd_pcm_channel_area_t *snd_pcm_mmap_areas(snd_pcm_t *pcm); int snd_pcm_mmap_get_areas(snd_pcm_t *pcm, snd_pcm_channel_area_t *stopped_areas, snd_pcm_channel_area_t *running_areas); diff --git a/src/control/Makefile.am b/src/control/Makefile.am index 8592e654..4bfbf260 100644 --- a/src/control/Makefile.am +++ b/src/control/Makefile.am @@ -1,7 +1,7 @@ EXTRA_LTLIBRARIES = libcontrol.la libcontrol_la_SOURCES = cards.c controls.c bag.c defaults.c \ - control.c control_hw.c control_client.c + control.c control_hw.c control_shm.c all: libcontrol.la diff --git a/src/control/cards.c b/src/control/cards.c index e3dabdc6..b139e0c8 100644 --- a/src/control/cards.c +++ b/src/control/cards.c @@ -106,7 +106,7 @@ int snd_card_get_index(const char *string) for (card = 0; card < 32; card++) { if (snd_card_load(card) < 0) continue; - if (snd_ctl_hw_open(&handle, card) < 0) + if (snd_ctl_hw_open(&handle, NULL, card) < 0) continue; if (snd_ctl_hw_info(handle, &info) < 0) { snd_ctl_close(handle); @@ -127,7 +127,7 @@ int snd_card_get_name(int card, char **name) if (name == NULL) return -EINVAL; - if ((err = snd_ctl_hw_open(&handle, card)) < 0) + if ((err = snd_ctl_hw_open(&handle, NULL, card)) < 0) return err; if ((err = snd_ctl_hw_info(handle, &info)) < 0) { snd_ctl_close(handle); @@ -148,7 +148,7 @@ int snd_card_get_longname(int card, char **name) if (name == NULL) return -EINVAL; - if ((err = snd_ctl_hw_open(&handle, card)) < 0) + if ((err = snd_ctl_hw_open(&handle, NULL, card)) < 0) return err; if ((err = snd_ctl_hw_info(handle, &info)) < 0) { snd_ctl_close(handle); diff --git a/src/control/control.c b/src/control/control.c index 2ed0f38b..e0b6c058 100644 --- a/src/control/control.c +++ b/src/control/control.c @@ -26,6 +26,7 @@ #include #include #include +#include #include "asoundlib.h" #include "control_local.h" @@ -148,106 +149,22 @@ int snd_ctl_read(snd_ctl_t *ctl, snd_ctl_callbacks_t * callbacks) return result >= 0 ? count : -errno; } -static int _snd_ctl_open_hw(snd_ctl_t **handlep, snd_config_t *conf) +int snd_ctl_open(snd_ctl_t **ctlp, char *name) { - snd_config_iterator_t i; - long card = -1; char *str; 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, "card") == 0) { - err = snd_config_integer_get(n, &card); - if (err < 0) { - err = snd_config_string_get(n, &str); - if (err < 0) - return -EINVAL; - card = snd_card_get_index(str); - if (card < 0) - return card; - } - continue; - } - return -EINVAL; - } - if (card < 0) - return -EINVAL; - return snd_ctl_hw_open(handlep, card); -} - -static int _snd_ctl_open_client(snd_ctl_t **handlep, snd_config_t *conf) -{ + snd_config_t *ctl_conf, *conf, *type_conf; 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, "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_ctl_client_open(handlep, socket, -1, SND_TRANSPORT_TYPE_SHM, name); - } else { - if (port < 0 || !name) - return -EINVAL; - return snd_ctl_client_open(handlep, host, port, SND_TRANSPORT_TYPE_TCP, name); - } -} - -int snd_ctl_open(snd_ctl_t **handlep, char *name) -{ - char *str; - int err; - snd_config_t *ctl_conf, *conf; - assert(handlep && name); + char *lib = NULL, *open = NULL; + int (*open_func)(snd_ctl_t **ctlp, char *name, snd_config_t *conf); + void *h; + assert(ctlp && name); err = snd_config_update(); if (err < 0) return err; err = snd_config_searchv(snd_config, &ctl_conf, "ctl", name, 0); - if (err < 0) { - int idx = snd_card_get_index(name); - if (idx < 0) - return idx; - return snd_ctl_hw_open(handlep, idx); - } + if (err < 0) + return err; if (snd_config_type(ctl_conf) != SND_CONFIG_TYPE_COMPOUND) return -EINVAL; err = snd_config_search(ctl_conf, "type", &conf); @@ -256,10 +173,37 @@ int snd_ctl_open(snd_ctl_t **handlep, char *name) err = snd_config_string_get(conf, &str); if (err < 0) return err; - if (strcmp(str, "hw") == 0) - return _snd_ctl_open_hw(handlep, ctl_conf); - else if (strcmp(str, "client") == 0) - return _snd_ctl_open_client(handlep, ctl_conf); - else + err = snd_config_searchv(snd_config, &type_conf, "ctltype", str, 0); + if (err < 0) + return err; + snd_config_foreach(i, type_conf) { + snd_config_t *n = snd_config_entry(i); + if (strcmp(n->id, "comment") == 0) + continue; + if (strcmp(n->id, "lib") == 0) { + err = snd_config_string_get(n, &lib); + if (err < 0) + return -EINVAL; + continue; + } + if (strcmp(n->id, "open") == 0) { + err = snd_config_string_get(n, &open); + if (err < 0) + return -EINVAL; + continue; + return -EINVAL; + } + } + if (!open) return -EINVAL; + if (!lib) + lib = "libasound.so"; + h = dlopen(lib, RTLD_NOW); + if (!h) + return -ENOENT; + open_func = dlsym(h, open); + dlclose(h); + if (!open_func) + return -ENXIO; + return open_func(ctlp, name, ctl_conf); } diff --git a/src/control/control_client.c b/src/control/control_client.c deleted file mode 100644 index ef323e60..00000000 --- a/src/control/control_client.c +++ /dev/null @@ -1,433 +0,0 @@ -/* - * Control - Client - * Copyright (c) 2000 by Abramo Bagnara - * - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "control_local.h" -#include "aserver.h" - -typedef struct { - int data_fd; - int ctrl_fd; - union { - struct { - void *ctrl; - } shm; - } u; -} snd_ctl_client_t; - -static void clean_poll(snd_ctl_t *ctl) -{ - snd_ctl_client_t *client = ctl->private; - struct pollfd pfd; - int err; - char buf[1]; - pfd.fd = client->data_fd; - 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); - } -} - -static int snd_ctl_client_shm_action(snd_ctl_t *ctl) -{ - snd_ctl_client_t *client = ctl->private; - int err; - char buf[1]; - snd_ctl_client_shm_t *ctrl = client->u.shm.ctrl; - clean_poll(ctl); - 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_ctl_client_shm_close(snd_ctl_t *ctl) -{ - snd_ctl_client_t *client = ctl->private; - snd_ctl_client_shm_t *ctrl = client->u.shm.ctrl; - int result; - ctrl->cmd = SND_CTL_IOCTL_CLOSE; - result = snd_ctl_client_shm_action(ctl); - if (result >= 0) - result = ctrl->result; - shmdt((void *)ctrl); - close(client->data_fd); - close(client->ctrl_fd); - free(client); - return result; -} - -static int snd_ctl_client_poll_descriptor(snd_ctl_t *ctl) -{ - snd_ctl_client_t *client = ctl->private; - return client->data_fd; -} - -static int snd_ctl_client_shm_hw_info(snd_ctl_t *ctl, snd_ctl_hw_info_t *info) -{ - snd_ctl_client_t *client = ctl->private; - snd_ctl_client_shm_t *ctrl = client->u.shm.ctrl; - int err; -// ctrl->u.hw_info = *info; - ctrl->cmd = SND_CTL_IOCTL_HW_INFO; - err = snd_ctl_client_shm_action(ctl); - if (err < 0) - return err; - *info = ctrl->u.hw_info; - return ctrl->result; -} - -static int snd_ctl_client_shm_clist(snd_ctl_t *ctl, snd_control_list_t *list) -{ - snd_ctl_client_t *client = ctl->private; - snd_ctl_client_shm_t *ctrl = client->u.shm.ctrl; - size_t maxsize = CTL_SHM_DATA_MAXLEN; - size_t bytes = list->controls_request * sizeof(*list->pids); - int err; - snd_control_id_t *pids = list->pids; - if (bytes > maxsize) - return -EINVAL; - ctrl->u.clist = *list; - ctrl->cmd = SND_CTL_IOCTL_CONTROL_LIST; - err = snd_ctl_client_shm_action(ctl); - if (err < 0) - return err; - *list = ctrl->u.clist; - list->pids = pids; - memcpy(pids, ctrl->data, bytes); - return ctrl->result; -} - -static int snd_ctl_client_shm_cinfo(snd_ctl_t *ctl, snd_control_info_t *info) -{ - snd_ctl_client_t *client = ctl->private; - snd_ctl_client_shm_t *ctrl = client->u.shm.ctrl; - int err; - ctrl->u.cinfo = *info; - ctrl->cmd = SND_CTL_IOCTL_CONTROL_INFO; - err = snd_ctl_client_shm_action(ctl); - if (err < 0) - return err; - *info = ctrl->u.cinfo; - return ctrl->result; -} - -static int snd_ctl_client_shm_cread(snd_ctl_t *ctl, snd_control_t *control) -{ - snd_ctl_client_t *client = ctl->private; - snd_ctl_client_shm_t *ctrl = client->u.shm.ctrl; - int err; - ctrl->u.cread = *control; - ctrl->cmd = SND_CTL_IOCTL_CONTROL_READ; - err = snd_ctl_client_shm_action(ctl); - if (err < 0) - return err; - *control = ctrl->u.cread; - return ctrl->result; -} - -static int snd_ctl_client_shm_cwrite(snd_ctl_t *ctl, snd_control_t *control) -{ - snd_ctl_client_t *client = ctl->private; - snd_ctl_client_shm_t *ctrl = client->u.shm.ctrl; - int err; - ctrl->u.cwrite = *control; - ctrl->cmd = SND_CTL_IOCTL_CONTROL_WRITE; - err = snd_ctl_client_shm_action(ctl); - if (err < 0) - return err; - *control = ctrl->u.cwrite; - return ctrl->result; -} - -static int snd_ctl_client_shm_hwdep_info(snd_ctl_t *ctl, snd_hwdep_info_t * info) -{ - snd_ctl_client_t *client = ctl->private; - snd_ctl_client_shm_t *ctrl = client->u.shm.ctrl; - int err; - ctrl->u.hwdep_info = *info; - ctrl->cmd = SND_CTL_IOCTL_HWDEP_INFO; - err = snd_ctl_client_shm_action(ctl); - if (err < 0) - return err; - *info = ctrl->u.hwdep_info; - return ctrl->result; -} - -static int snd_ctl_client_shm_pcm_info(snd_ctl_t *ctl, snd_pcm_info_t * info) -{ - snd_ctl_client_t *client = ctl->private; - snd_ctl_client_shm_t *ctrl = client->u.shm.ctrl; - int err; - ctrl->u.pcm_info = *info; - ctrl->cmd = SND_CTL_IOCTL_PCM_INFO; - err = snd_ctl_client_shm_action(ctl); - if (err < 0) - return err; - *info = ctrl->u.pcm_info; - return ctrl->result; -} - -static int snd_ctl_client_shm_pcm_prefer_subdevice(snd_ctl_t *ctl, int subdev) -{ - snd_ctl_client_t *client = ctl->private; - snd_ctl_client_shm_t *ctrl = client->u.shm.ctrl; - int err; - ctrl->u.pcm_prefer_subdevice = subdev; - ctrl->cmd = SND_CTL_IOCTL_PCM_PREFER_SUBDEVICE; - err = snd_ctl_client_shm_action(ctl); - if (err < 0) - return err; - return ctrl->result; -} - -static int snd_ctl_client_shm_rawmidi_info(snd_ctl_t *ctl, snd_rawmidi_info_t * info) -{ - snd_ctl_client_t *client = ctl->private; - snd_ctl_client_shm_t *ctrl = client->u.shm.ctrl; - int err; - ctrl->u.rawmidi_info = *info; - ctrl->cmd = SND_CTL_IOCTL_RAWMIDI_INFO; - err = snd_ctl_client_shm_action(ctl); - if (err < 0) - return err; - *info = ctrl->u.rawmidi_info; - return ctrl->result; -} - -static int snd_ctl_client_shm_read(snd_ctl_t *ctl, snd_ctl_event_t *event) -{ - snd_ctl_client_t *client = ctl->private; - snd_ctl_client_shm_t *ctrl = client->u.shm.ctrl; - int err; - ctrl->u.read = *event; - ctrl->cmd = SND_CTL_IOCTL_READ; - err = snd_ctl_client_shm_action(ctl); - if (err < 0) - return err; - *event = ctrl->u.read; - return ctrl->result; -} - -struct snd_ctl_ops snd_ctl_client_ops = { - close: snd_ctl_client_shm_close, - poll_descriptor: snd_ctl_client_poll_descriptor, - hw_info: snd_ctl_client_shm_hw_info, - clist: snd_ctl_client_shm_clist, - cinfo: snd_ctl_client_shm_cinfo, - cread: snd_ctl_client_shm_cread, - cwrite: snd_ctl_client_shm_cwrite, - hwdep_info: snd_ctl_client_shm_hwdep_info, - pcm_info: snd_ctl_client_shm_pcm_info, - pcm_prefer_subdevice: snd_ctl_client_shm_pcm_prefer_subdevice, - rawmidi_info: snd_ctl_client_shm_rawmidi_info, - read: snd_ctl_client_shm_read, -}; - -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_ctl_client_open(snd_ctl_t **handlep, char *host, int port, int transport, char *name) -{ - snd_ctl_t *ctl; - snd_ctl_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_ctl_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_CONTROL; - req->transport_type = transport; - req->stream = 0; - req->mode = 0; - 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 = ans.result; - 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; - } - - ctl = calloc(1, sizeof(snd_ctl_t)); - if (!ctl) { - result = -ENOMEM; - goto _err; - } - client = calloc(1, sizeof(snd_ctl_client_t)); - if (!ctl) { - free(ctl); - result = -ENOMEM; - goto _err; - } - - client->data_fd = fds[0]; - client->ctrl_fd = fds[1]; - switch (transport) { - case SND_TRANSPORT_TYPE_SHM: - client->u.shm.ctrl = ctrl; - break; - } - ctl->type = SND_CTL_TYPE_CLIENT; - ctl->ops = &snd_ctl_client_ops; - ctl->private = client; - INIT_LIST_HEAD(&ctl->hlist); - *handlep = ctl; - 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/control/control_hw.c b/src/control/control_hw.c index 8ca8b8b5..5d58ab12 100644 --- a/src/control/control_hw.c +++ b/src/control/control_hw.c @@ -147,7 +147,7 @@ struct snd_ctl_ops snd_ctl_hw_ops = { read: snd_ctl_hw_read, }; -int snd_ctl_hw_open(snd_ctl_t **handle, int card) +int snd_ctl_hw_open(snd_ctl_t **handle, char *name, int card) { int fd, ver; char filename[32]; @@ -185,6 +185,9 @@ int snd_ctl_hw_open(snd_ctl_t **handle, int card) } hw->card = card; hw->fd = fd; + if (name) + ctl->name = strdup(name); + ctl->type = SND_CTL_TYPE_HW; ctl->ops = &snd_ctl_hw_ops; ctl->private = hw; INIT_LIST_HEAD(&ctl->hlist); @@ -192,3 +195,34 @@ int snd_ctl_hw_open(snd_ctl_t **handle, int card) return 0; } +int _snd_ctl_hw_open(snd_ctl_t **handlep, char *name, snd_config_t *conf) +{ + snd_config_iterator_t i; + long card = -1; + char *str; + 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, "card") == 0) { + err = snd_config_integer_get(n, &card); + if (err < 0) { + err = snd_config_string_get(n, &str); + if (err < 0) + return -EINVAL; + card = snd_card_get_index(str); + if (card < 0) + return card; + } + continue; + } + return -EINVAL; + } + if (card < 0) + return -EINVAL; + return snd_ctl_hw_open(handlep, name, card); +} + diff --git a/src/control/control_local.h b/src/control/control_local.h index cf1a5828..34f302d4 100644 --- a/src/control/control_local.h +++ b/src/control/control_local.h @@ -40,6 +40,7 @@ struct snd_ctl_ops { struct snd_ctl { + char *name; snd_ctl_type_t type; struct snd_ctl_ops *ops; void *private; diff --git a/src/control/control_shm.c b/src/control/control_shm.c new file mode 100644 index 00000000..968e1461 --- /dev/null +++ b/src/control/control_shm.c @@ -0,0 +1,512 @@ +/* + * Control - SHM Client + * Copyright (c) 2000 by Abramo Bagnara + * + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "control_local.h" +#include "aserver.h" + +typedef struct { + int socket; + void *ctrl; +} snd_ctl_shm_t; + +extern int receive_fd(int socket, void *data, size_t len, int *fd); + +static int snd_ctl_shm_action(snd_ctl_t *ctl) +{ + snd_ctl_shm_t *shm = ctl->private; + int err; + char buf[1]; + snd_ctl_shm_ctrl_t *ctrl = shm->ctrl; + err = write(shm->socket, buf, 1); + if (err != 1) + return -EBADFD; + err = read(shm->socket, buf, 1); + if (err != 1) + return -EBADFD; + if (ctrl->cmd) { + fprintf(stderr, "Server has not done the cmd\n"); + return -EBADFD; + } + return ctrl->result; +} + +static int snd_ctl_shm_action_fd(snd_ctl_t *ctl, int *fd) +{ + snd_ctl_shm_t *shm = ctl->private; + int err; + char buf[1]; + snd_ctl_shm_ctrl_t *ctrl = shm->ctrl; + err = write(shm->socket, buf, 1); + if (err != 1) + return -EBADFD; + err = receive_fd(shm->socket, buf, 1, fd); + if (err != 1) + return -EBADFD; + if (ctrl->cmd) { + fprintf(stderr, "Server has not done the cmd\n"); + return -EBADFD; + } + return ctrl->result; +} + +static int snd_ctl_shm_close(snd_ctl_t *ctl) +{ + snd_ctl_shm_t *shm = ctl->private; + snd_ctl_shm_ctrl_t *ctrl = shm->ctrl; + int result; + ctrl->cmd = SND_CTL_IOCTL_CLOSE; + result = snd_ctl_shm_action(ctl); + shmdt((void *)ctrl); + close(shm->socket); + free(shm); + return result; +} + +static int snd_ctl_shm_poll_descriptor(snd_ctl_t *ctl) +{ + snd_ctl_shm_t *shm = ctl->private; + snd_ctl_shm_ctrl_t *ctrl = shm->ctrl; + int fd, err; + ctrl->cmd = SND_CTL_IOCTL_POLL_DESCRIPTOR; + err = snd_ctl_shm_action_fd(ctl, &fd); + if (err < 0) + return err; + return fd; +} + +static int snd_ctl_shm_hw_info(snd_ctl_t *ctl, snd_ctl_hw_info_t *info) +{ + snd_ctl_shm_t *shm = ctl->private; + snd_ctl_shm_ctrl_t *ctrl = shm->ctrl; + int err; +// ctrl->u.hw_info = *info; + ctrl->cmd = SND_CTL_IOCTL_HW_INFO; + err = snd_ctl_shm_action(ctl); + if (err < 0) + return err; + *info = ctrl->u.hw_info; + return err; +} + +static int snd_ctl_shm_clist(snd_ctl_t *ctl, snd_control_list_t *list) +{ + snd_ctl_shm_t *shm = ctl->private; + snd_ctl_shm_ctrl_t *ctrl = shm->ctrl; + size_t maxsize = CTL_SHM_DATA_MAXLEN; + size_t bytes = list->controls_request * sizeof(*list->pids); + int err; + snd_control_id_t *pids = list->pids; + if (bytes > maxsize) + return -EINVAL; + ctrl->u.clist = *list; + ctrl->cmd = SND_CTL_IOCTL_CONTROL_LIST; + err = snd_ctl_shm_action(ctl); + if (err < 0) + return err; + *list = ctrl->u.clist; + list->pids = pids; + memcpy(pids, ctrl->data, bytes); + return err; +} + +static int snd_ctl_shm_cinfo(snd_ctl_t *ctl, snd_control_info_t *info) +{ + snd_ctl_shm_t *shm = ctl->private; + snd_ctl_shm_ctrl_t *ctrl = shm->ctrl; + int err; + ctrl->u.cinfo = *info; + ctrl->cmd = SND_CTL_IOCTL_CONTROL_INFO; + err = snd_ctl_shm_action(ctl); + if (err < 0) + return err; + *info = ctrl->u.cinfo; + return err; +} + +static int snd_ctl_shm_cread(snd_ctl_t *ctl, snd_control_t *control) +{ + snd_ctl_shm_t *shm = ctl->private; + snd_ctl_shm_ctrl_t *ctrl = shm->ctrl; + int err; + ctrl->u.cread = *control; + ctrl->cmd = SND_CTL_IOCTL_CONTROL_READ; + err = snd_ctl_shm_action(ctl); + if (err < 0) + return err; + *control = ctrl->u.cread; + return err; +} + +static int snd_ctl_shm_cwrite(snd_ctl_t *ctl, snd_control_t *control) +{ + snd_ctl_shm_t *shm = ctl->private; + snd_ctl_shm_ctrl_t *ctrl = shm->ctrl; + int err; + ctrl->u.cwrite = *control; + ctrl->cmd = SND_CTL_IOCTL_CONTROL_WRITE; + err = snd_ctl_shm_action(ctl); + if (err < 0) + return err; + *control = ctrl->u.cwrite; + return err; +} + +static int snd_ctl_shm_hwdep_info(snd_ctl_t *ctl, snd_hwdep_info_t * info) +{ + snd_ctl_shm_t *shm = ctl->private; + snd_ctl_shm_ctrl_t *ctrl = shm->ctrl; + int err; + ctrl->u.hwdep_info = *info; + ctrl->cmd = SND_CTL_IOCTL_HWDEP_INFO; + err = snd_ctl_shm_action(ctl); + if (err < 0) + return err; + *info = ctrl->u.hwdep_info; + return err; +} + +static int snd_ctl_shm_pcm_info(snd_ctl_t *ctl, snd_pcm_info_t * info) +{ + snd_ctl_shm_t *shm = ctl->private; + snd_ctl_shm_ctrl_t *ctrl = shm->ctrl; + int err; + ctrl->u.pcm_info = *info; + ctrl->cmd = SND_CTL_IOCTL_PCM_INFO; + err = snd_ctl_shm_action(ctl); + if (err < 0) + return err; + *info = ctrl->u.pcm_info; + return err; +} + +static int snd_ctl_shm_pcm_prefer_subdevice(snd_ctl_t *ctl, int subdev) +{ + snd_ctl_shm_t *shm = ctl->private; + snd_ctl_shm_ctrl_t *ctrl = shm->ctrl; + int err; + ctrl->u.pcm_prefer_subdevice = subdev; + ctrl->cmd = SND_CTL_IOCTL_PCM_PREFER_SUBDEVICE; + err = snd_ctl_shm_action(ctl); + if (err < 0) + return err; + return err; +} + +static int snd_ctl_shm_rawmidi_info(snd_ctl_t *ctl, snd_rawmidi_info_t * info) +{ + snd_ctl_shm_t *shm = ctl->private; + snd_ctl_shm_ctrl_t *ctrl = shm->ctrl; + int err; + ctrl->u.rawmidi_info = *info; + ctrl->cmd = SND_CTL_IOCTL_RAWMIDI_INFO; + err = snd_ctl_shm_action(ctl); + if (err < 0) + return err; + *info = ctrl->u.rawmidi_info; + return err; +} + +static int snd_ctl_shm_read(snd_ctl_t *ctl, snd_ctl_event_t *event) +{ + snd_ctl_shm_t *shm = ctl->private; + snd_ctl_shm_ctrl_t *ctrl = shm->ctrl; + int err; + ctrl->u.read = *event; + ctrl->cmd = SND_CTL_IOCTL_READ; + err = snd_ctl_shm_action(ctl); + if (err < 0) + return err; + *event = ctrl->u.read; + return err; +} + +struct snd_ctl_ops snd_ctl_shm_ops = { + close: snd_ctl_shm_close, + poll_descriptor: snd_ctl_shm_poll_descriptor, + hw_info: snd_ctl_shm_hw_info, + clist: snd_ctl_shm_clist, + cinfo: snd_ctl_shm_cinfo, + cread: snd_ctl_shm_cread, + cwrite: snd_ctl_shm_cwrite, + hwdep_info: snd_ctl_shm_hwdep_info, + pcm_info: snd_ctl_shm_pcm_info, + pcm_prefer_subdevice: snd_ctl_shm_pcm_prefer_subdevice, + rawmidi_info: snd_ctl_shm_rawmidi_info, + read: snd_ctl_shm_read, +}; + +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; +} + +#if 0 +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; +} +#endif + +int snd_ctl_shm_open(snd_ctl_t **handlep, char *name, char *socket, char *sname) +{ + snd_ctl_t *ctl; + snd_ctl_shm_t *shm = NULL; + snd_client_open_request_t *req; + snd_client_open_answer_t ans; + size_t snamelen, reqlen; + int err; + int result; + int sock = -1; + snd_ctl_shm_ctrl_t *ctrl = NULL; + snamelen = strlen(sname); + if (snamelen > 255) + return -EINVAL; + + result = make_local_socket(socket); + if (result < 0) { + ERR("server for socket %s is not running", socket); + goto _err; + } + sock = result; + + reqlen = sizeof(*req) + snamelen; + req = alloca(reqlen); + memcpy(req->name, sname, snamelen); + req->dev_type = SND_DEV_TYPE_CONTROL; + req->transport_type = SND_TRANSPORT_TYPE_SHM; + req->stream = 0; + req->mode = 0; + req->namelen = snamelen; + err = write(sock, req, reqlen); + if (err < 0) { + ERR("write error"); + result = -errno; + goto _err; + } + if ((size_t) err != reqlen) { + ERR("write size error"); + result = -EINVAL; + goto _err; + } + err = read(sock, &ans, sizeof(ans)); + if (err < 0) { + ERR("read error"); + result = -errno; + goto _err; + } + if (err != sizeof(ans)) { + ERR("read size error"); + result = -EINVAL; + goto _err; + } + result = ans.result; + if (result < 0) + goto _err; + + ctrl = shmat(ans.cookie, 0, 0); + if (!ctrl) { + result = -errno; + goto _err; + } + + ctl = calloc(1, sizeof(snd_ctl_t)); + if (!ctl) { + result = -ENOMEM; + goto _err; + } + shm = calloc(1, sizeof(snd_ctl_shm_t)); + if (!ctl) { + free(ctl); + result = -ENOMEM; + goto _err; + } + + shm->socket = sock; + shm->ctrl = ctrl; + + if (name) + ctl->name = strdup(name); + ctl->type = SND_CTL_TYPE_SHM; + ctl->ops = &snd_ctl_shm_ops; + ctl->private = shm; + INIT_LIST_HEAD(&ctl->hlist); + *handlep = ctl; + return 0; + + _err: + close(sock); + if (ctrl) + shmdt(ctrl); + if (shm) + free(shm); + return result; +} + +extern int is_local(struct hostent *hent); + +int _snd_ctl_shm_open(snd_ctl_t **handlep, char *name, snd_config_t *conf) +{ + snd_config_iterator_t i; + char *server = NULL; + char *sname = NULL; + snd_config_t *sconfig; + char *host = NULL; + char *socket = NULL; + long port = -1; + int err; + int local; + struct hostent *h; + 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, "server") == 0) { + err = snd_config_string_get(n, &server); + if (err < 0) { + ERR("Invalid type for server"); + return -EINVAL; + } + continue; + } + if (strcmp(n->id, "sname") == 0) { + err = snd_config_string_get(n, &sname); + if (err < 0) { + ERR("Invalid type for sname"); + return -EINVAL; + } + continue; + } + ERR("Unknown field: %s", n->id); + return -EINVAL; + } + if (!sname) { + ERR("sname is not defined"); + return -EINVAL; + } + if (!server) { + ERR("server is not defined"); + return -EINVAL; + } + err = snd_config_searchv(snd_config, &sconfig, "server", server, 0); + if (err < 0) { + ERR("Unknown server %s", server); + return -EINVAL; + } + snd_config_foreach(i, conf) { + snd_config_t *n = snd_config_entry(i); + if (strcmp(n->id, "comment") == 0) + continue; + if (strcmp(n->id, "host") == 0) { + err = snd_config_string_get(n, &host); + if (err < 0) { + ERR("Invalid type for host"); + return -EINVAL; + } + continue; + } + if (strcmp(n->id, "socket") == 0) { + err = snd_config_string_get(n, &socket); + if (err < 0) { + ERR("Invalid type for socket"); + return -EINVAL; + } + continue; + } + if (strcmp(n->id, "port") == 0) { + err = snd_config_integer_get(n, &port); + if (err < 0) { + ERR("Invalid type for port"); + return -EINVAL; + } + continue; + } + ERR("Unknown field: %s", n->id); + return -EINVAL; + } + + if (!host) { + ERR("host is not defined"); + return -EINVAL; + } + if (!socket) { + ERR("socket is not defined"); + return -EINVAL; + } + h = gethostbyname(host); + if (!h) { + ERR("Cannot resolve %s", host); + return -EINVAL; + } + local = is_local(h); + if (!local) { + ERR("%s is not the local host", host); + return -EINVAL; + } + return snd_ctl_shm_open(handlep, name, socket, sname); +} + diff --git a/src/pcm/Makefile.am b/src/pcm/Makefile.am index e932d519..30baaf18 100644 --- a/src/pcm/Makefile.am +++ b/src/pcm/Makefile.am @@ -3,7 +3,7 @@ EXTRA_LTLIBRARIES = libpcm.la libpcm_la_SOURCES = pcm.c pcm_hw.c pcm_plugin.c pcm_linear.c pcm_route.c \ pcm_mulaw.c pcm_alaw.c pcm_adpcm.c pcm_rate.c pcm_plug.c \ - pcm_misc.c pcm_mmap.c pcm_multi.c pcm_client.c pcm_file.c \ + pcm_misc.c pcm_mmap.c pcm_multi.c pcm_shm.c pcm_file.c \ pcm_share.c noinst_HEADERS = pcm_local.h pcm_plugin.h diff --git a/src/pcm/pcm.c b/src/pcm/pcm.c index 4288d3d5..5c85320c 100644 --- a/src/pcm/pcm.c +++ b/src/pcm/pcm.c @@ -30,18 +30,6 @@ #include "pcm_local.h" #include "list.h" -int snd_pcm_init(snd_pcm_t *pcm) -{ - int err; - err = snd_pcm_mmap_status(pcm, NULL); - if (err < 0) - return err; - err = snd_pcm_mmap_control(pcm, NULL); - if (err < 0) - return err; - return 0; -} - snd_pcm_type_t snd_pcm_type(snd_pcm_t *pcm) { assert(pcm); @@ -59,16 +47,8 @@ int snd_pcm_close(snd_pcm_t *pcm) int ret = 0; int err; assert(pcm); - if (pcm->mmap_status) { - if ((err = snd_pcm_munmap_status(pcm)) < 0) - ret = err; - } - if (pcm->mmap_control) { - if ((err = snd_pcm_munmap_control(pcm)) < 0) - ret = err; - } - if (pcm->mmap_data) { - if ((err = snd_pcm_munmap_data(pcm)) < 0) + if (pcm->mmap_info) { + if ((err = snd_pcm_munmap(pcm)) < 0) ret = err; } if ((err = pcm->ops->close(pcm->op_arg)) < 0) @@ -156,12 +136,21 @@ int snd_pcm_params(snd_pcm_t *pcm, snd_pcm_params_t *params) { int err; snd_pcm_setup_t setup; + int mmap = 0; assert(pcm && params); - assert(!pcm->mmap_data); + if (pcm->mmap_info) { + mmap = 1; + err = snd_pcm_munmap(pcm); + if (err < 0) + return err; + } if ((err = pcm->ops->params(pcm->op_arg, params)) < 0) return err; pcm->valid_setup = 0; - return snd_pcm_setup(pcm, &setup); + err = snd_pcm_setup(pcm, &setup); + if (pcm->mmap_auto || mmap) + snd_pcm_mmap(pcm); + return err; } int snd_pcm_status(snd_pcm_t *pcm, snd_pcm_status_t *status) @@ -233,7 +222,7 @@ ssize_t snd_pcm_writei(snd_pcm_t *pcm, const void *buffer, size_t size) assert(size == 0 || buffer); assert(pcm->valid_setup); assert(pcm->setup.xfer_mode == SND_PCM_XFER_INTERLEAVED); - assert(!pcm->mmap_data); + assert(!pcm->mmap_info || pcm->mmap_auto); return _snd_pcm_writei(pcm, buffer, size); } @@ -243,7 +232,7 @@ ssize_t snd_pcm_writen(snd_pcm_t *pcm, void **bufs, size_t size) assert(size == 0 || bufs); assert(pcm->valid_setup); assert(pcm->setup.xfer_mode == SND_PCM_XFER_NONINTERLEAVED); - assert(!pcm->mmap_data); + assert(!pcm->mmap_info || pcm->mmap_auto); return _snd_pcm_writen(pcm, bufs, size); } @@ -253,7 +242,7 @@ ssize_t snd_pcm_readi(snd_pcm_t *pcm, void *buffer, size_t size) assert(size == 0 || buffer); assert(pcm->valid_setup); assert(pcm->setup.xfer_mode == SND_PCM_XFER_INTERLEAVED); - assert(!pcm->mmap_data); + assert(!pcm->mmap_info || pcm->mmap_auto); return _snd_pcm_readi(pcm, buffer, size); } @@ -263,7 +252,7 @@ ssize_t snd_pcm_readn(snd_pcm_t *pcm, void **bufs, size_t size) assert(size == 0 || bufs); assert(pcm->valid_setup); assert(pcm->setup.xfer_mode == SND_PCM_XFER_NONINTERLEAVED); - assert(!pcm->mmap_data); + assert(!pcm->mmap_info || pcm->mmap_auto); return _snd_pcm_readn(pcm, bufs, size); } @@ -331,7 +320,7 @@ int snd_pcm_unlink(snd_pcm_t *pcm) int snd_pcm_poll_descriptor(snd_pcm_t *pcm) { assert(pcm); - return pcm->fast_ops->poll_descriptor(pcm->fast_op_arg); + return pcm->poll_fd; } int snd_pcm_channels_mask(snd_pcm_t *pcm, bitset_t *cmask) @@ -547,62 +536,87 @@ int snd_pcm_open(snd_pcm_t **pcmp, char *name, if (err < 0) return err; err = snd_config_searchv(snd_config, &pcm_conf, "pcm", name, 0); - if (err < 0) + if (err < 0) { + ERR("Unknown PCM %s", name); return err; - if (snd_config_type(pcm_conf) != SND_CONFIG_TYPE_COMPOUND) + } + if (snd_config_type(pcm_conf) != SND_CONFIG_TYPE_COMPOUND) { + ERR("Invalid type for PCM definition"); return -EINVAL; + } err = snd_config_search(pcm_conf, "stream", &conf); if (err >= 0) { err = snd_config_string_get(conf, &str); - if (err < 0) + if (err < 0) { + ERR("Invalid type for stream"); return err; + } if (strcmp(str, "playback") == 0) { if (stream != SND_PCM_STREAM_PLAYBACK) return -EINVAL; } else if (strcmp(str, "capture") == 0) { if (stream != SND_PCM_STREAM_CAPTURE) return -EINVAL; - } else + } else { + ERR("Invalid value for stream"); return -EINVAL; + } } err = snd_config_search(pcm_conf, "type", &conf); - if (err < 0) + if (err < 0) { + ERR("type is not defined"); return err; + } err = snd_config_string_get(conf, &str); - if (err < 0) + if (err < 0) { + ERR("Invalid type for type"); return err; + } err = snd_config_searchv(snd_config, &type_conf, "pcmtype", str, 0); - if (err < 0) + if (err < 0) { + ERR("Unknown PCM type %s", str); return err; + } snd_config_foreach(i, type_conf) { snd_config_t *n = snd_config_entry(i); if (strcmp(n->id, "comment") == 0) continue; if (strcmp(n->id, "lib") == 0) { err = snd_config_string_get(n, &lib); - if (err < 0) + if (err < 0) { + ERR("Invalid type for lib"); return -EINVAL; + } continue; } if (strcmp(n->id, "open") == 0) { err = snd_config_string_get(n, &open); - if (err < 0) + if (err < 0) { + ERR("Invalid type for open"); return -EINVAL; + } continue; + ERR("Unknown field: %s", n->id); return -EINVAL; } } - if (!open) + if (!open) { + ERR("open is not defined"); return -EINVAL; + } if (!lib) lib = "libasound.so"; h = dlopen(lib, RTLD_NOW); - if (!h) + if (!h) { + ERR("Cannot open shared library %s", lib); return -ENOENT; + } open_func = dlsym(h, open); dlclose(h); - if (!open_func) + if (!open_func) { + ERR("symbol %s is not defined inside %s", open, lib); return -ENXIO; + } return open_func(pcmp, name, pcm_conf, stream, mode); } @@ -634,23 +648,11 @@ int snd_pcm_wait(snd_pcm_t *pcm, int timeout) { struct pollfd pfd; int err; -#if 0 - size_t bavail, aavail; - struct timeval before, after, diff; - bavail = snd_pcm_avail_update(pcm); - gettimeofday(&before, 0); -#endif pfd.fd = snd_pcm_poll_descriptor(pcm); pfd.events = pcm->stream == SND_PCM_STREAM_PLAYBACK ? POLLOUT : POLLIN; err = poll(&pfd, 1, timeout); if (err < 0) return err; -#if 0 - aavail = snd_pcm_avail_update(pcm); - gettimeofday(&after, 0); - timersub(&after, &before, &diff); - fprintf(stderr, "%s %ld.%06ld: get=%d (%d-%d)\n", pcm->stream == SND_PCM_STREAM_PLAYBACK ? "playback" : "capture", diff.tv_sec, diff.tv_usec, aavail - bavail, aavail, bavail); -#endif return 0; } @@ -1044,7 +1046,7 @@ ssize_t snd_pcm_write_areas(snd_pcm_t *pcm, snd_pcm_channel_area_t *areas, return err; } -void snd_pcm_error_default(const char *file, int line, const char *function, const char *fmt, ...) +void snd_pcm_error(const char *file, int line, const char *function, const char *fmt, ...) { va_list arg; va_start(arg, fmt); @@ -1053,5 +1055,3 @@ void snd_pcm_error_default(const char *file, int line, const char *function, con putc('\n', stderr); va_end(arg); } - -void (*snd_pcm_error)(const char *file, int line, const char *function, const char *fmt, ...) = snd_pcm_error_default; diff --git a/src/pcm/pcm_adpcm.c b/src/pcm/pcm_adpcm.c index 56d9e76f..4834fe59 100644 --- a/src/pcm/pcm_adpcm.c +++ b/src/pcm/pcm_adpcm.c @@ -377,11 +377,6 @@ static int snd_pcm_adpcm_params(snd_pcm_t *pcm, snd_pcm_params_t * params) params->fail_reason = SND_PCM_PARAMS_FAIL_INVAL; return -EINVAL; } - if (slave->mmap_data) { - err = snd_pcm_munmap_data(slave); - if (err < 0) - return err; - } adpcm->cformat = params->format.sfmt; adpcm->cxfer_mode = params->xfer_mode; adpcm->cmmap_shape = params->mmap_shape; @@ -392,10 +387,6 @@ static int snd_pcm_adpcm_params(snd_pcm_t *pcm, snd_pcm_params_t * params) params->format.sfmt = adpcm->cformat; params->xfer_mode = adpcm->cxfer_mode; params->mmap_shape = adpcm->cmmap_shape; - if (slave->valid_setup) { - int r = snd_pcm_mmap_data(slave, NULL); - assert(r >= 0); - } return err; } @@ -533,7 +524,7 @@ static void snd_pcm_adpcm_dump(snd_pcm_t *pcm, FILE *fp) snd_pcm_dump(adpcm->plug.slave, fp); } -struct snd_pcm_ops snd_pcm_adpcm_ops = { +snd_pcm_ops_t snd_pcm_adpcm_ops = { close: snd_pcm_adpcm_close, info: snd_pcm_plugin_info, params_info: snd_pcm_adpcm_params_info, @@ -545,20 +536,15 @@ struct snd_pcm_ops snd_pcm_adpcm_ops = { dump: snd_pcm_adpcm_dump, nonblock: snd_pcm_plugin_nonblock, async: snd_pcm_plugin_async, - mmap_status: snd_pcm_plugin_mmap_status, - mmap_control: snd_pcm_plugin_mmap_control, - mmap_data: snd_pcm_plugin_mmap_data, - munmap_status: snd_pcm_plugin_munmap_status, - munmap_control: snd_pcm_plugin_munmap_control, - munmap_data: snd_pcm_plugin_munmap_data, + mmap: snd_pcm_plugin_mmap, + munmap: snd_pcm_plugin_munmap, }; -int snd_pcm_adpcm_open(snd_pcm_t **handlep, char *name, int sformat, snd_pcm_t *slave, int close_slave) +int snd_pcm_adpcm_open(snd_pcm_t **pcmp, char *name, int sformat, snd_pcm_t *slave, int close_slave) { - snd_pcm_t *handle; + snd_pcm_t *pcm; snd_pcm_adpcm_t *adpcm; - int err; - assert(handlep && slave); + assert(pcmp && slave); if (snd_pcm_format_linear(sformat) != 1 && sformat != SND_PCM_SFMT_IMA_ADPCM) return -EINVAL; @@ -573,27 +559,25 @@ int snd_pcm_adpcm_open(snd_pcm_t **handlep, char *name, int sformat, snd_pcm_t * adpcm->plug.slave = slave; adpcm->plug.close_slave = close_slave; - handle = calloc(1, sizeof(snd_pcm_t)); - if (!handle) { + pcm = calloc(1, sizeof(snd_pcm_t)); + if (!pcm) { free(adpcm); return -ENOMEM; } if (name) - handle->name = strdup(name); - handle->type = SND_PCM_TYPE_ADPCM; - handle->stream = slave->stream; - handle->ops = &snd_pcm_adpcm_ops; - handle->op_arg = handle; - handle->fast_ops = &snd_pcm_plugin_fast_ops; - handle->fast_op_arg = handle; - handle->mode = slave->mode; - handle->private = adpcm; - err = snd_pcm_init(handle); - if (err < 0) { - snd_pcm_close(handle); - return err; - } - *handlep = handle; + pcm->name = strdup(name); + pcm->type = SND_PCM_TYPE_ADPCM; + pcm->stream = slave->stream; + pcm->mode = slave->mode; + pcm->ops = &snd_pcm_adpcm_ops; + pcm->op_arg = pcm; + pcm->fast_ops = &snd_pcm_plugin_fast_ops; + pcm->fast_op_arg = pcm; + pcm->private = adpcm; + pcm->poll_fd = slave->poll_fd; + pcm->hw_ptr = &adpcm->plug.hw_ptr; + pcm->appl_ptr = &adpcm->plug.appl_ptr; + *pcmp = pcm; return 0; } diff --git a/src/pcm/pcm_alaw.c b/src/pcm/pcm_alaw.c index 7fae5be0..33913b26 100644 --- a/src/pcm/pcm_alaw.c +++ b/src/pcm/pcm_alaw.c @@ -259,11 +259,6 @@ static int snd_pcm_alaw_params(snd_pcm_t *pcm, snd_pcm_params_t * params) params->fail_reason = SND_PCM_PARAMS_FAIL_INVAL; return -EINVAL; } - if (slave->mmap_data) { - err = snd_pcm_munmap_data(slave); - if (err < 0) - return err; - } alaw->cformat = params->format.sfmt; alaw->cxfer_mode = params->xfer_mode; alaw->cmmap_shape = params->mmap_shape; @@ -274,10 +269,6 @@ static int snd_pcm_alaw_params(snd_pcm_t *pcm, snd_pcm_params_t * params) params->format.sfmt = alaw->cformat; params->xfer_mode = alaw->cxfer_mode; params->mmap_shape = alaw->cmmap_shape; - if (slave->valid_setup) { - int r = snd_pcm_mmap_data(slave, NULL); - assert(r >= 0); - } return err; } @@ -401,7 +392,7 @@ static void snd_pcm_alaw_dump(snd_pcm_t *pcm, FILE *fp) snd_pcm_dump(alaw->plug.slave, fp); } -struct snd_pcm_ops snd_pcm_alaw_ops = { +snd_pcm_ops_t snd_pcm_alaw_ops = { close: snd_pcm_plugin_close, info: snd_pcm_plugin_info, params_info: snd_pcm_alaw_params_info, @@ -413,20 +404,15 @@ struct snd_pcm_ops snd_pcm_alaw_ops = { dump: snd_pcm_alaw_dump, nonblock: snd_pcm_plugin_nonblock, async: snd_pcm_plugin_async, - mmap_status: snd_pcm_plugin_mmap_status, - mmap_control: snd_pcm_plugin_mmap_control, - mmap_data: snd_pcm_plugin_mmap_data, - munmap_status: snd_pcm_plugin_munmap_status, - munmap_control: snd_pcm_plugin_munmap_control, - munmap_data: snd_pcm_plugin_munmap_data, + mmap: snd_pcm_plugin_mmap, + munmap: snd_pcm_plugin_munmap, }; -int snd_pcm_alaw_open(snd_pcm_t **handlep, char *name, int sformat, snd_pcm_t *slave, int close_slave) +int snd_pcm_alaw_open(snd_pcm_t **pcmp, char *name, int sformat, snd_pcm_t *slave, int close_slave) { - snd_pcm_t *handle; + snd_pcm_t *pcm; snd_pcm_alaw_t *alaw; - int err; - assert(handlep && slave); + assert(pcmp && slave); if (snd_pcm_format_linear(sformat) != 1 && sformat != SND_PCM_SFMT_A_LAW) return -EINVAL; @@ -440,27 +426,25 @@ int snd_pcm_alaw_open(snd_pcm_t **handlep, char *name, int sformat, snd_pcm_t *s alaw->plug.slave = slave; alaw->plug.close_slave = close_slave; - handle = calloc(1, sizeof(snd_pcm_t)); - if (!handle) { + pcm = calloc(1, sizeof(snd_pcm_t)); + if (!pcm) { free(alaw); return -ENOMEM; } if (name) - handle->name = strdup(name); - handle->type = SND_PCM_TYPE_ALAW; - handle->stream = slave->stream; - handle->ops = &snd_pcm_alaw_ops; - handle->op_arg = handle; - handle->fast_ops = &snd_pcm_plugin_fast_ops; - handle->fast_op_arg = handle; - handle->mode = slave->mode; - handle->private = alaw; - err = snd_pcm_init(handle); - if (err < 0) { - snd_pcm_close(handle); - return err; - } - *handlep = handle; + pcm->name = strdup(name); + pcm->type = SND_PCM_TYPE_ALAW; + pcm->stream = slave->stream; + pcm->mode = slave->mode; + pcm->ops = &snd_pcm_alaw_ops; + pcm->op_arg = pcm; + pcm->fast_ops = &snd_pcm_plugin_fast_ops; + pcm->fast_op_arg = pcm; + pcm->private = alaw; + pcm->poll_fd = slave->poll_fd; + pcm->hw_ptr = &alaw->plug.hw_ptr; + pcm->appl_ptr = &alaw->plug.appl_ptr; + *pcmp = pcm; return 0; } diff --git a/src/pcm/pcm_client.c b/src/pcm/pcm_client.c deleted file mode 100644 index 0222891e..00000000 --- a/src/pcm/pcm_client.c +++ /dev/null @@ -1,857 +0,0 @@ -/* - * PCM - Client - * Copyright (c) 2000 by Abramo Bagnara - * - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "pcm_local.h" -#include "aserver.h" - -typedef struct { - 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; - size_t cmsg_len = CMSG_LEN(sizeof(int)); - struct cmsghdr *cmsg = alloca(cmsg_len); - int *fds = (int *) CMSG_DATA(cmsg); - struct msghdr msghdr; - struct iovec vec; - - vec.iov_base = (void *)&data; - vec.iov_len = len; - - cmsg->cmsg_len = cmsg_len; - cmsg->cmsg_level = SOL_SOCKET; - cmsg->cmsg_type = SCM_RIGHTS; - *fds = -1; - - msghdr.msg_name = NULL; - msghdr.msg_namelen = 0; - msghdr.msg_iov = &vec; - msghdr.msg_iovlen = 1; - msghdr.msg_control = cmsg; - msghdr.msg_controllen = cmsg_len; - msghdr.msg_flags = 0; - - ret = recvmsg(socket, &msghdr, 0); - if (ret < 0) - return -errno; - *fd = *fds; - return ret; -} - -static void clean_poll(snd_pcm_t *pcm) -{ - snd_pcm_client_t *client = pcm->private; - struct pollfd pfd; - int err; - char buf[1]; - pfd.fd = client->data_fd; - switch (pcm->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_t *pcm) -{ - snd_pcm_client_t *client = pcm->private; - int err; - char buf[1]; - snd_pcm_client_shm_t *ctrl = client->u.shm.ctrl; - clean_poll(pcm); - 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_t *pcm) -{ - snd_pcm_client_t *client = pcm->private; - int err; - char buf[1]; - snd_pcm_client_shm_t *ctrl = client->u.shm.ctrl; - int fd; - clean_poll(pcm); - 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(snd_pcm_t *pcm) -{ - snd_pcm_client_t *client = pcm->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(pcm); - if (result >= 0) - result = ctrl->result; - shmdt((void *)ctrl); - close(client->data_fd); - close(client->ctrl_fd); - free(client); - return result; -} - -static int snd_pcm_client_shm_nonblock(snd_pcm_t *pcm ATTRIBUTE_UNUSED, int nonblock ATTRIBUTE_UNUSED) -{ - return 0; -} - -static int snd_pcm_client_async(snd_pcm_t *pcm, int sig, pid_t pid) -{ - snd_pcm_client_t *client = pcm->private; - snd_pcm_client_shm_t *ctrl = client->u.shm.ctrl; - int err; - ctrl->cmd = SND_PCM_IOCTL_ASYNC; - ctrl->u.async.sig = sig; - if (pid == 0) - pid = getpid(); - ctrl->u.async.pid = pid; - err = snd_pcm_client_shm_action(pcm); - if (err < 0) - return err; - return ctrl->result; -} - -static int snd_pcm_client_shm_info(snd_pcm_t *pcm, snd_pcm_info_t * info) -{ - snd_pcm_client_t *client = pcm->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(pcm); - if (err < 0) - return err; - *info = ctrl->u.info; - return ctrl->result; -} - -static int snd_pcm_client_shm_params_info(snd_pcm_t *pcm, snd_pcm_params_info_t * info) -{ - snd_pcm_client_t *client = pcm->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(pcm); - if (err < 0) - return err; - *info = ctrl->u.params_info; - return ctrl->result; -} - -static int snd_pcm_client_shm_params(snd_pcm_t *pcm, snd_pcm_params_t * params) -{ - snd_pcm_client_t *client = pcm->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(pcm); - if (err < 0) - return err; - *params = ctrl->u.params; - return ctrl->result; -} - -static int snd_pcm_client_shm_setup(snd_pcm_t *pcm, snd_pcm_setup_t * setup) -{ - snd_pcm_client_t *client = pcm->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(pcm); - if (err < 0) - return err; - *setup = ctrl->u.setup; - return ctrl->result; -} - -static int snd_pcm_client_shm_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t * info) -{ - snd_pcm_client_t *client = pcm->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(pcm); - if (err < 0) - return err; - *info = ctrl->u.channel_info; - return ctrl->result; -} - -static int snd_pcm_client_shm_channel_params(snd_pcm_t *pcm, snd_pcm_channel_params_t * params) -{ - snd_pcm_client_t *client = pcm->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(pcm); - if (err < 0) - return err; - *params = ctrl->u.channel_params; - return ctrl->result; -} - -static int snd_pcm_client_shm_channel_setup(snd_pcm_t *pcm, snd_pcm_channel_setup_t * setup) -{ - snd_pcm_client_t *client = pcm->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(pcm); - if (err < 0) - return err; - *setup = ctrl->u.channel_setup; - return ctrl->result; -} - -static int snd_pcm_client_shm_status(snd_pcm_t *pcm, snd_pcm_status_t * status) -{ - snd_pcm_client_t *client = pcm->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(pcm); - if (err < 0) - return err; - *status = ctrl->u.status; - return ctrl->result; -} - -static int snd_pcm_client_shm_state(snd_pcm_t *pcm) -{ - snd_pcm_client_t *client = pcm->private; - snd_pcm_client_shm_t *ctrl = client->u.shm.ctrl; - int err; - ctrl->cmd = SND_PCM_IOCTL_STATE; - err = snd_pcm_client_shm_action(pcm); - if (err < 0) - return err; - return ctrl->result; -} - -static int snd_pcm_client_shm_delay(snd_pcm_t *pcm, ssize_t *delayp) -{ - snd_pcm_client_t *client = pcm->private; - snd_pcm_client_shm_t *ctrl = client->u.shm.ctrl; - int err; - ctrl->cmd = SND_PCM_IOCTL_DELAY; - err = snd_pcm_client_shm_action(pcm); - if (err < 0) - return err; - *delayp = ctrl->u.delay; - return ctrl->result; -} - -static ssize_t snd_pcm_client_avail_update(snd_pcm_t *pcm) -{ - snd_pcm_client_t *client = pcm->private; - snd_pcm_client_shm_t *ctrl = client->u.shm.ctrl; - int err; - ctrl->cmd = SND_PCM_IOCTL_AVAIL_UPDATE; - err = snd_pcm_client_shm_action(pcm); - if (err < 0) - return err; - return ctrl->result; -} - -static int snd_pcm_client_shm_prepare(snd_pcm_t *pcm) -{ - snd_pcm_client_t *client = pcm->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(pcm); - if (err < 0) - return err; - return ctrl->result; -} - -static int snd_pcm_client_shm_start(snd_pcm_t *pcm) -{ - snd_pcm_client_t *client = pcm->private; - snd_pcm_client_shm_t *ctrl = client->u.shm.ctrl; - int err; - ctrl->cmd = SND_PCM_IOCTL_START; - err = snd_pcm_client_shm_action(pcm); - if (err < 0) - return err; - return ctrl->result; -} - -static int snd_pcm_client_shm_drop(snd_pcm_t *pcm) -{ - snd_pcm_client_t *client = pcm->private; - snd_pcm_client_shm_t *ctrl = client->u.shm.ctrl; - int err; - ctrl->cmd = SND_PCM_IOCTL_DROP; - err = snd_pcm_client_shm_action(pcm); - if (err < 0) - return err; - return ctrl->result; -} - -static int snd_pcm_client_shm_drain(snd_pcm_t *pcm) -{ - snd_pcm_client_t *client = pcm->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(pcm); - if (err < 0) - return err; - return ctrl->result; -} - -static int snd_pcm_client_shm_pause(snd_pcm_t *pcm, int enable) -{ - snd_pcm_client_t *client = pcm->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(pcm); - if (err < 0) - return err; - return ctrl->result; -} - -static ssize_t snd_pcm_client_shm_rewind(snd_pcm_t *pcm, size_t frames) -{ - snd_pcm_client_t *client = pcm->private; - snd_pcm_client_shm_t *ctrl = client->u.shm.ctrl; - int err; - ctrl->cmd = SND_PCM_IOCTL_REWIND; - ctrl->u.rewind = frames; - err = snd_pcm_client_shm_action(pcm); - if (err < 0) - return err; - return ctrl->result; -} - -static int snd_pcm_client_shm_mmap_status(snd_pcm_t *pcm) -{ - snd_pcm_client_t *client = pcm->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(pcm); - if (fd < 0) - return fd; - /* FIXME: not mmap */ - 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; - pcm->mmap_status = ptr; - return 0; -} - -static int snd_pcm_client_shm_mmap_control(snd_pcm_t *pcm) -{ - snd_pcm_client_t *client = pcm->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(pcm); - if (fd < 0) - return fd; - /* FIXME: not mmap */ - 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; - pcm->mmap_control = ptr; - return 0; -} - -static int snd_pcm_client_shm_mmap_data(snd_pcm_t *pcm) -{ - snd_pcm_client_t *client = pcm->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(pcm); - if (fd < 0) - return fd; - /* FIXME: not mmap */ - prot = pcm->stream == SND_PCM_STREAM_PLAYBACK ? PROT_WRITE : PROT_READ; - ptr = mmap(NULL, pcm->setup.mmap_bytes, prot, MAP_FILE|MAP_SHARED, - fd, SND_PCM_MMAP_OFFSET_DATA); - close(fd); - if (ptr == MAP_FAILED || ptr == NULL) - return -errno; - pcm->mmap_data = ptr; - return 0; -} - -static int snd_pcm_client_shm_munmap_status(snd_pcm_t *pcm) -{ - snd_pcm_client_t *client = pcm->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(pcm); - if (err < 0) - return err; - /* FIXME: not mmap */ - if (munmap((void*)pcm->mmap_status, sizeof(*pcm->mmap_status)) < 0) - return -errno; - return ctrl->result; -} - -static int snd_pcm_client_shm_munmap_control(snd_pcm_t *pcm) -{ - snd_pcm_client_t *client = pcm->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(pcm); - if (err < 0) - return err; - /* FIXME: not mmap */ - if (munmap(pcm->mmap_control, sizeof(*pcm->mmap_control)) < 0) - return -errno; - return ctrl->result; -} - -static int snd_pcm_client_shm_munmap_data(snd_pcm_t *pcm) -{ - snd_pcm_client_t *client = pcm->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(pcm); - if (err < 0) - return err; - /* FIXME: not mmap */ - if (munmap(pcm->mmap_data, pcm->setup.mmap_bytes) < 0) - return -errno; - return ctrl->result; -} - -static ssize_t snd_pcm_client_mmap_forward(snd_pcm_t *pcm, size_t size) -{ - snd_pcm_client_t *client = pcm->private; - snd_pcm_client_shm_t *ctrl = client->u.shm.ctrl; - int err; - ctrl->cmd = SND_PCM_IOCTL_MMAP_FORWARD; - ctrl->u.mmap_forward = size; - err = snd_pcm_client_shm_action(pcm); - if (err < 0) - return err; - return ctrl->result; -} - -static int snd_pcm_client_poll_descriptor(snd_pcm_t *pcm) -{ - snd_pcm_client_t *client = pcm->private; - return client->data_fd; -} - -static int snd_pcm_client_channels_mask(snd_pcm_t *pcm ATTRIBUTE_UNUSED, - bitset_t *cmask ATTRIBUTE_UNUSED) -{ - return 0; -} - -static void snd_pcm_client_dump(snd_pcm_t *pcm, FILE *fp) -{ - fprintf(fp, "Client PCM\n"); - if (pcm->valid_setup) { - fprintf(fp, "\nIts setup is:\n"); - snd_pcm_dump_setup(pcm, 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, - channel_info: snd_pcm_client_shm_channel_info, - channel_params: snd_pcm_client_shm_channel_params, - channel_setup: snd_pcm_client_shm_channel_setup, - dump: snd_pcm_client_dump, - nonblock: snd_pcm_client_shm_nonblock, - async: snd_pcm_client_async, - 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, -}; - -struct snd_pcm_fast_ops snd_pcm_client_fast_ops = { - status: snd_pcm_client_shm_status, - state: snd_pcm_client_shm_state, - delay: snd_pcm_client_shm_delay, - prepare: snd_pcm_client_shm_prepare, - start: snd_pcm_client_shm_start, - drop: snd_pcm_client_shm_drop, - drain: snd_pcm_client_shm_drain, - pause: snd_pcm_client_shm_pause, - rewind: snd_pcm_client_shm_rewind, - writei: snd_pcm_mmap_writei, - writen: snd_pcm_mmap_writen, - readi: snd_pcm_mmap_readi, - readn: snd_pcm_mmap_readn, - poll_descriptor: snd_pcm_client_poll_descriptor, - channels_mask: snd_pcm_client_channels_mask, - avail_update: snd_pcm_client_avail_update, - mmap_forward: snd_pcm_client_mmap_forward, -}; - -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 = ans.result; - 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; - } - } - - client = calloc(1, sizeof(snd_pcm_client_t)); - if (!client) { - result = -ENOMEM; - goto _err; - } - - client->data_fd = fds[0]; - client->ctrl_fd = fds[1]; - switch (transport) { - case SND_TRANSPORT_TYPE_SHM: - client->u.shm.ctrl = ctrl; - break; - } - - handle = calloc(1, sizeof(snd_pcm_t)); - if (!handle) { - free(client); - result = -ENOMEM; - goto _err; - } - handle->type = SND_PCM_TYPE_CLIENT; - handle->stream = stream; - handle->ops = &snd_pcm_client_ops; - handle->op_arg = handle; - handle->fast_ops = &snd_pcm_client_fast_ops; - handle->fast_op_arg = handle; - handle->mode = mode; - handle->private = client; - err = snd_pcm_init(handle); - if (err < 0) { - snd_pcm_close(handle); - return err; - } - *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; -} - -int _snd_pcm_client_open(snd_pcm_t **pcmp, char *name, snd_config_t *conf, - int stream, int mode) -{ - snd_config_iterator_t i; - char *socket = NULL; - char *sname = 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, "sname") == 0) { - err = snd_config_string_get(n, &sname); - if (err < 0) - return -EINVAL; - continue; - } - return -EINVAL; - } - if (!sname) - return -EINVAL; - if (socket) { - if (port >= 0 || host) - return -EINVAL; - return snd_pcm_client_create(pcmp, socket, -1, SND_TRANSPORT_TYPE_SHM, sname, stream, mode); - } else { - if (port < 0 || !name) - return -EINVAL; - return snd_pcm_client_create(pcmp, host, port, SND_TRANSPORT_TYPE_TCP, sname, stream, mode); - } -} - diff --git a/src/pcm/pcm_file.c b/src/pcm/pcm_file.c index 0391554b..60277300 100644 --- a/src/pcm/pcm_file.c +++ b/src/pcm/pcm_file.c @@ -219,7 +219,7 @@ static ssize_t snd_pcm_file_readn(snd_pcm_t *pcm, void **bufs, size_t size) static ssize_t snd_pcm_file_mmap_forward(snd_pcm_t *pcm, size_t size) { snd_pcm_file_t *file = pcm->private; - size_t ofs = pcm->mmap_control->appl_ptr % pcm->setup.buffer_size; + size_t ofs = snd_pcm_mmap_offset(pcm); ssize_t n = snd_pcm_mmap_forward(file->slave, size); size_t xfer = 0; if (n <= 0) @@ -244,60 +244,28 @@ static ssize_t snd_pcm_file_avail_update(snd_pcm_t *pcm) return snd_pcm_avail_update(file->slave); } -static int snd_pcm_file_mmap_status(snd_pcm_t *pcm) +static int snd_pcm_file_mmap(snd_pcm_t *pcm) { snd_pcm_file_t *file = pcm->private; - int err = snd_pcm_mmap_status(file->slave, &pcm->mmap_status); + int err = snd_pcm_mmap(file->slave); if (err < 0) return err; - pcm->mmap_status = file->slave->mmap_status; + pcm->mmap_info_count = file->slave->mmap_info_count; + pcm->mmap_info = file->slave->mmap_info; return 0; } -static int snd_pcm_file_mmap_control(snd_pcm_t *pcm) +static int snd_pcm_file_munmap(snd_pcm_t *pcm) { snd_pcm_file_t *file = pcm->private; - int err = snd_pcm_mmap_control(file->slave, &pcm->mmap_control); + int err = snd_pcm_munmap(file->slave); if (err < 0) return err; - pcm->mmap_control = file->slave->mmap_control; + pcm->mmap_info_count = 0; + pcm->mmap_info = 0; return 0; } -static int snd_pcm_file_mmap_data(snd_pcm_t *pcm) -{ - snd_pcm_file_t *file = pcm->private; - int err = snd_pcm_mmap_data(file->slave, &pcm->mmap_data); - if (err < 0) - return err; - pcm->mmap_data = file->slave->mmap_data; - return 0; -} - -static int snd_pcm_file_munmap_status(snd_pcm_t *pcm) -{ - snd_pcm_file_t *file = pcm->private; - return snd_pcm_munmap_status(file->slave); -} - -static int snd_pcm_file_munmap_control(snd_pcm_t *pcm) -{ - snd_pcm_file_t *file = pcm->private; - return snd_pcm_munmap_control(file->slave); -} - -static int snd_pcm_file_munmap_data(snd_pcm_t *pcm) -{ - snd_pcm_file_t *file = pcm->private; - return snd_pcm_munmap_data(file->slave); -} - -static int snd_pcm_file_poll_descriptor(snd_pcm_t *pcm) -{ - snd_pcm_file_t *file = pcm->private; - return snd_pcm_poll_descriptor(file->slave); -} - static int snd_pcm_file_channels_mask(snd_pcm_t *pcm, bitset_t *cmask) { snd_pcm_file_t *file = pcm->private; @@ -337,7 +305,7 @@ static void snd_pcm_file_dump(snd_pcm_t *pcm, FILE *fp) snd_pcm_dump(file->slave, fp); } -struct snd_pcm_ops snd_pcm_file_ops = { +snd_pcm_ops_t snd_pcm_file_ops = { close: snd_pcm_file_close, info: snd_pcm_file_info, params_info: snd_pcm_file_params_info, @@ -349,15 +317,11 @@ struct snd_pcm_ops snd_pcm_file_ops = { dump: snd_pcm_file_dump, nonblock: snd_pcm_file_nonblock, async: snd_pcm_file_async, - mmap_status: snd_pcm_file_mmap_status, - mmap_control: snd_pcm_file_mmap_control, - mmap_data: snd_pcm_file_mmap_data, - munmap_status: snd_pcm_file_munmap_status, - munmap_control: snd_pcm_file_munmap_control, - munmap_data: snd_pcm_file_munmap_data, + mmap: snd_pcm_file_mmap, + munmap: snd_pcm_file_munmap, }; -struct snd_pcm_fast_ops snd_pcm_file_fast_ops = { +snd_pcm_fast_ops_t snd_pcm_file_fast_ops = { status: snd_pcm_file_status, state: snd_pcm_file_state, delay: snd_pcm_file_delay, @@ -371,18 +335,16 @@ struct snd_pcm_fast_ops snd_pcm_file_fast_ops = { writen: snd_pcm_file_writen, readi: snd_pcm_file_readi, readn: snd_pcm_file_readn, - poll_descriptor: snd_pcm_file_poll_descriptor, channels_mask: snd_pcm_file_channels_mask, avail_update: snd_pcm_file_avail_update, mmap_forward: snd_pcm_file_mmap_forward, }; -int snd_pcm_file_open(snd_pcm_t **handlep, char *name, char *fname, int fd, snd_pcm_t *slave, int close_slave) +int snd_pcm_file_open(snd_pcm_t **pcmp, char *name, char *fname, int fd, snd_pcm_t *slave, int close_slave) { - snd_pcm_t *handle; + snd_pcm_t *pcm; snd_pcm_file_t *file; - int err; - assert(handlep && slave); + assert(pcmp && slave); if (fname) { fd = open(fname, O_WRONLY|O_CREAT, 0666); if (fd < 0) @@ -397,27 +359,25 @@ int snd_pcm_file_open(snd_pcm_t **handlep, char *name, char *fname, int fd, snd_ file->slave = slave; file->close_slave = close_slave; - handle = calloc(1, sizeof(snd_pcm_t)); - if (!handle) { + pcm = calloc(1, sizeof(snd_pcm_t)); + if (!pcm) { free(file); return -ENOMEM; } if (name) - handle->name = strdup(name); - handle->type = SND_PCM_TYPE_FILE; - handle->stream = slave->stream; - handle->ops = &snd_pcm_file_ops; - handle->op_arg = handle; - handle->fast_ops = &snd_pcm_file_fast_ops; - handle->fast_op_arg = handle; - handle->mode = slave->mode; - handle->private = file; - err = snd_pcm_init(handle); - if (err < 0) { - snd_pcm_close(handle); - return err; - } - *handlep = handle; + pcm->name = strdup(name); + pcm->type = SND_PCM_TYPE_FILE; + pcm->stream = slave->stream; + pcm->mode = slave->mode; + pcm->ops = &snd_pcm_file_ops; + pcm->op_arg = pcm; + pcm->fast_ops = &snd_pcm_file_fast_ops; + pcm->fast_op_arg = pcm; + pcm->private = file; + pcm->poll_fd = slave->poll_fd; + pcm->hw_ptr = slave->hw_ptr; + pcm->appl_ptr = slave->appl_ptr; + *pcmp = pcm; return 0; } diff --git a/src/pcm/pcm_hw.c b/src/pcm/pcm_hw.c index 30fd3750..3b1166a6 100644 --- a/src/pcm/pcm_hw.c +++ b/src/pcm/pcm_hw.c @@ -37,25 +37,14 @@ typedef struct { int fd; int card, device, subdevice; - int mmap_emulation; + volatile snd_pcm_mmap_status_t *mmap_status; + snd_pcm_mmap_control_t *mmap_control; } snd_pcm_hw_t; #define SND_FILE_PCM_STREAM_PLAYBACK "/dev/snd/pcmC%iD%ip" #define SND_FILE_PCM_STREAM_CAPTURE "/dev/snd/pcmC%iD%ic" #define SND_PCM_VERSION_MAX SND_PROTOCOL_VERSION(2, 0, 0) -static int snd_pcm_hw_close(snd_pcm_t *pcm) -{ - snd_pcm_hw_t *hw = pcm->private; - int fd = hw->fd; - free(hw); - if (close(fd)) { - ERR("close failed\n"); - return -errno; - } - return 0; -} - static int snd_pcm_hw_nonblock(snd_pcm_t *pcm, int nonblock) { long flags; @@ -158,9 +147,7 @@ static int snd_pcm_hw_setup(snd_pcm_t *pcm, snd_pcm_setup_t * setup) setup->mmap_shape = SND_PCM_MMAP_INTERLEAVED; else setup->mmap_shape = SND_PCM_MMAP_NONINTERLEAVED; - hw->mmap_emulation = 1; - } else - hw->mmap_emulation = 0; + } return 0; } @@ -194,19 +181,21 @@ static int snd_pcm_hw_channel_setup(snd_pcm_t *pcm, snd_pcm_channel_setup_t * se ERR("SND_PCM_IOCTL_CHANNEL_SETUP failed"); return -errno; } - if (hw->mmap_emulation) { - if (pcm->setup.mmap_shape == SND_PCM_MMAP_INTERLEAVED) { - setup->running_area.addr = pcm->mmap_data; + if (!pcm->mmap_info) + return 0; + if (pcm->setup.mmap_shape == SND_PCM_MMAP_UNSPECIFIED) { + if (pcm->setup.xfer_mode == SND_PCM_XFER_INTERLEAVED) { + setup->running_area.addr = pcm->mmap_info->addr; setup->running_area.first = setup->channel * pcm->bits_per_sample; setup->running_area.step = pcm->bits_per_frame; } else { - setup->running_area.addr = pcm->mmap_data + setup->channel * pcm->setup.buffer_size * pcm->bits_per_sample / 8; + setup->running_area.addr = pcm->mmap_info->addr + setup->channel * pcm->setup.buffer_size * pcm->bits_per_sample / 8; setup->running_area.first = 0; setup->running_area.step = pcm->bits_per_sample; } setup->stopped_area = setup->running_area; } else { - setup->running_area.addr = (char *)pcm->mmap_data + (long)setup->running_area.addr; + setup->running_area.addr = pcm->mmap_info->addr + (long)setup->running_area.addr; setup->stopped_area.addr = setup->running_area.addr; } return 0; @@ -225,7 +214,8 @@ static int snd_pcm_hw_status(snd_pcm_t *pcm, snd_pcm_status_t * status) static int snd_pcm_hw_state(snd_pcm_t *pcm) { - return pcm->mmap_status->state; + snd_pcm_hw_t *hw = pcm->private; + return hw->mmap_status->state; } static int snd_pcm_hw_delay(snd_pcm_t *pcm, ssize_t *delayp) @@ -378,7 +368,8 @@ static int snd_pcm_hw_mmap_status(snd_pcm_t *pcm) ERR("status mmap failed"); return -errno; } - pcm->mmap_status = ptr; + hw->mmap_status = ptr; + pcm->hw_ptr = &hw->mmap_status->hw_ptr; return 0; } @@ -392,36 +383,50 @@ static int snd_pcm_hw_mmap_control(snd_pcm_t *pcm) ERR("control mmap failed"); return -errno; } - pcm->mmap_control = ptr; + hw->mmap_control = ptr; + pcm->appl_ptr = &hw->mmap_control->appl_ptr; return 0; } -static int snd_pcm_hw_mmap_data(snd_pcm_t *pcm) +static int snd_pcm_hw_mmap(snd_pcm_t *pcm) { snd_pcm_hw_t *hw = pcm->private; - void *ptr; - if (hw->mmap_emulation) { - ptr = malloc(snd_pcm_frames_to_bytes(pcm, pcm->setup.buffer_size)); - if (!ptr) + pcm->mmap_info = calloc(1, sizeof(*pcm->mmap_info)); + if (!pcm->mmap_info) + return -ENOMEM; + pcm->mmap_info_count = 1; + if (pcm->setup.mmap_shape == SND_PCM_MMAP_UNSPECIFIED) { + pcm->mmap_info->type = SND_PCM_MMAP_USER; + pcm->mmap_info->size = snd_pcm_frames_to_bytes(pcm, pcm->setup.buffer_size); + pcm->mmap_info->addr = valloc(pcm->mmap_info->size); + if (!pcm->mmap_info->addr) { + free(pcm->mmap_info); + pcm->mmap_info = 0; return -ENOMEM; + } } else { - int prot; - prot = PROT_WRITE | PROT_READ; - ptr = mmap(NULL, pcm->setup.mmap_bytes, - prot, MAP_FILE|MAP_SHARED, - hw->fd, SND_PCM_MMAP_OFFSET_DATA); - if (ptr == MAP_FAILED || ptr == NULL) { + pcm->mmap_info->type = SND_PCM_MMAP_KERNEL; + pcm->mmap_info->size = pcm->setup.mmap_bytes; + pcm->mmap_info->addr = mmap(NULL, pcm->setup.mmap_bytes, + PROT_WRITE | PROT_READ, + MAP_FILE|MAP_SHARED, + hw->fd, SND_PCM_MMAP_OFFSET_DATA); + if (pcm->mmap_info->addr == MAP_FAILED || + pcm->mmap_info->addr == NULL) { ERR("data mmap failed"); + free(pcm->mmap_info); + pcm->mmap_info = 0; return -errno; } + pcm->mmap_info->u.kernel.fd = hw->fd; } - pcm->mmap_data = ptr; return 0; } static int snd_pcm_hw_munmap_status(snd_pcm_t *pcm) { - if (munmap((void*)pcm->mmap_status, sizeof(*pcm->mmap_status)) < 0) { + snd_pcm_hw_t *hw = pcm->private; + if (munmap((void*)hw->mmap_status, sizeof(*hw->mmap_status)) < 0) { ERR("status munmap failed"); return -errno; } @@ -430,30 +435,46 @@ static int snd_pcm_hw_munmap_status(snd_pcm_t *pcm) static int snd_pcm_hw_munmap_control(snd_pcm_t *pcm) { - if (munmap(pcm->mmap_control, sizeof(*pcm->mmap_control)) < 0) { + snd_pcm_hw_t *hw = pcm->private; + if (munmap(hw->mmap_control, sizeof(*hw->mmap_control)) < 0) { ERR("control munmap failed"); return -errno; } return 0; } -static int snd_pcm_hw_munmap_data(snd_pcm_t *pcm) +static int snd_pcm_hw_munmap(snd_pcm_t *pcm) { - snd_pcm_hw_t *hw = pcm->private; - if (hw->mmap_emulation) - free(pcm->mmap_data); + if (pcm->setup.mmap_shape == SND_PCM_MMAP_UNSPECIFIED) + free(pcm->mmap_info->addr); else - if (munmap(pcm->mmap_data, pcm->setup.mmap_bytes) < 0) { + if (munmap(pcm->mmap_info->addr, pcm->mmap_info->size) < 0) { ERR("data munmap failed"); return -errno; } + pcm->mmap_info_count = 0; + free(pcm->mmap_info); + pcm->mmap_info = 0; return 0; } -static ssize_t snd_pcm_hw_mmap_forward(snd_pcm_t *pcm, size_t size) +static int snd_pcm_hw_close(snd_pcm_t *pcm) { snd_pcm_hw_t *hw = pcm->private; - if (hw->mmap_emulation && pcm->stream == SND_PCM_STREAM_PLAYBACK) + int fd = hw->fd; + free(hw); + if (close(fd)) { + ERR("close failed\n"); + return -errno; + } + snd_pcm_hw_munmap_status(pcm); + snd_pcm_hw_munmap_control(pcm); + return 0; +} + +static ssize_t snd_pcm_hw_mmap_forward(snd_pcm_t *pcm, size_t size) +{ + if (pcm->setup.mmap_shape == SND_PCM_MMAP_UNSPECIFIED && pcm->stream == SND_PCM_STREAM_PLAYBACK) return snd_pcm_write_mmap(pcm, size); snd_pcm_mmap_appl_forward(pcm, size); return size; @@ -461,7 +482,6 @@ static ssize_t snd_pcm_hw_mmap_forward(snd_pcm_t *pcm, size_t size) static ssize_t snd_pcm_hw_avail_update(snd_pcm_t *pcm) { - snd_pcm_hw_t *hw = pcm->private; size_t avail; ssize_t err; if (pcm->setup.ready_mode == SND_PCM_READY_ASAP || @@ -475,7 +495,7 @@ static ssize_t snd_pcm_hw_avail_update(snd_pcm_t *pcm) avail = snd_pcm_mmap_playback_avail(pcm); } else { avail = snd_pcm_mmap_capture_avail(pcm); - if (avail > 0 && hw->mmap_emulation) { + if (avail > 0 && pcm->setup.mmap_shape == SND_PCM_MMAP_UNSPECIFIED) { err = snd_pcm_read_mmap(pcm, avail); if (err < 0) return err; @@ -488,12 +508,6 @@ static ssize_t snd_pcm_hw_avail_update(snd_pcm_t *pcm) return avail; } -static int snd_pcm_hw_poll_descriptor(snd_pcm_t *pcm) -{ - snd_pcm_hw_t *hw = pcm->private; - return hw->fd; -} - static int snd_pcm_hw_channels_mask(snd_pcm_t *pcm ATTRIBUTE_UNUSED, bitset_t *cmask ATTRIBUTE_UNUSED) { @@ -514,7 +528,7 @@ static void snd_pcm_hw_dump(snd_pcm_t *pcm, FILE *fp) } } -struct snd_pcm_ops snd_pcm_hw_ops = { +snd_pcm_ops_t snd_pcm_hw_ops = { close: snd_pcm_hw_close, info: snd_pcm_hw_info, params_info: snd_pcm_hw_params_info, @@ -526,15 +540,11 @@ struct snd_pcm_ops snd_pcm_hw_ops = { dump: snd_pcm_hw_dump, nonblock: snd_pcm_hw_nonblock, async: snd_pcm_hw_async, - mmap_status: snd_pcm_hw_mmap_status, - mmap_control: snd_pcm_hw_mmap_control, - mmap_data: snd_pcm_hw_mmap_data, - munmap_status: snd_pcm_hw_munmap_status, - munmap_control: snd_pcm_hw_munmap_control, - munmap_data: snd_pcm_hw_munmap_data, + mmap: snd_pcm_hw_mmap, + munmap: snd_pcm_hw_munmap, }; -struct snd_pcm_fast_ops snd_pcm_hw_fast_ops = { +snd_pcm_fast_ops_t snd_pcm_hw_fast_ops = { status: snd_pcm_hw_status, state: snd_pcm_hw_state, delay: snd_pcm_hw_delay, @@ -548,13 +558,12 @@ struct snd_pcm_fast_ops snd_pcm_hw_fast_ops = { writen: snd_pcm_hw_writen, readi: snd_pcm_hw_readi, readn: snd_pcm_hw_readn, - poll_descriptor: snd_pcm_hw_poll_descriptor, channels_mask: snd_pcm_hw_channels_mask, avail_update: snd_pcm_hw_avail_update, mmap_forward: snd_pcm_hw_mmap_forward, }; -int snd_pcm_hw_open_subdevice(snd_pcm_t **handlep, int card, int device, int subdevice, int stream, int mode) +int snd_pcm_hw_open_subdevice(snd_pcm_t **pcmp, int card, int device, int subdevice, int stream, int mode) { char filename[32]; char *filefmt; @@ -564,12 +573,12 @@ int snd_pcm_hw_open_subdevice(snd_pcm_t **handlep, int card, int device, int sub snd_pcm_info_t info; int fmode; snd_ctl_t *ctl; - snd_pcm_t *handle; - snd_pcm_hw_t *hw; + snd_pcm_t *pcm = NULL; + snd_pcm_hw_t *hw = NULL; - assert(handlep); + assert(pcmp); - if ((ret = snd_ctl_hw_open(&ctl, card)) < 0) + if ((ret = snd_ctl_hw_open(&ctl, NULL, card)) < 0) return ret; switch (stream) { @@ -582,37 +591,35 @@ int snd_pcm_hw_open_subdevice(snd_pcm_t **handlep, int card, int device, int sub default: assert(0); } - if ((ret = snd_ctl_pcm_prefer_subdevice(ctl, subdevice)) < 0) - goto __end; + ret = snd_ctl_pcm_prefer_subdevice(ctl, subdevice); + snd_ctl_close(ctl); + if (ret < 0) + return ret; sprintf(filename, filefmt, card, device); __again: - if (attempt++ > 3) { - ret = -EBUSY; - goto __end; - } + if (attempt++ > 3) + return -EBUSY; fmode = O_RDWR; if (mode & SND_PCM_NONBLOCK) fmode |= O_NONBLOCK; if (mode & SND_PCM_ASYNC) fmode |= O_ASYNC; - if ((fd = open(filename, fmode)) < 0) { - ret = -errno; - goto __end; - } + if ((fd = open(filename, fmode)) < 0) + return -errno; if (ioctl(fd, SND_PCM_IOCTL_PVERSION, &ver) < 0) { ret = -errno; - goto __end; + goto _err; } if (SND_PROTOCOL_INCOMPATIBLE(ver, SND_PCM_VERSION_MAX)) { ret = -SND_ERROR_INCOMPATIBLE_VERSION; - goto __end; + goto _err; } if (subdevice >= 0) { memset(&info, 0, sizeof(info)); if (ioctl(fd, SND_PCM_IOCTL_INFO, &info) < 0) { ret = -errno; - goto __end; + goto _err; } if (info.subdevice != subdevice) { close(fd); @@ -622,54 +629,61 @@ int snd_pcm_hw_open_subdevice(snd_pcm_t **handlep, int card, int device, int sub hw = calloc(1, sizeof(snd_pcm_hw_t)); if (!hw) { ret = -ENOMEM; - goto __end; + goto _err; } hw->card = card; hw->device = device; hw->subdevice = subdevice; hw->fd = fd; - handle = calloc(1, sizeof(snd_pcm_t)); - if (!handle) { - free(hw); + pcm = calloc(1, sizeof(snd_pcm_t)); + if (!pcm) { ret = -ENOMEM; - goto __end; - } - handle->type = SND_PCM_TYPE_HW; - handle->stream = stream; - handle->ops = &snd_pcm_hw_ops; - handle->op_arg = handle; - handle->fast_ops = &snd_pcm_hw_fast_ops; - handle->fast_op_arg = handle; - handle->mode = mode; - handle->private = hw; - ret = snd_pcm_init(handle); + goto _err; + } + pcm->type = SND_PCM_TYPE_HW; + pcm->stream = stream; + pcm->mode = mode; + pcm->ops = &snd_pcm_hw_ops; + pcm->op_arg = pcm; + pcm->fast_ops = &snd_pcm_hw_fast_ops; + pcm->fast_op_arg = pcm; + pcm->private = hw; + pcm->poll_fd = fd; + *pcmp = pcm; + ret = snd_pcm_hw_mmap_status(pcm); if (ret < 0) { - snd_pcm_close(handle); - snd_ctl_close(ctl); + snd_pcm_close(pcm); return ret; } - *handlep = handle; + ret = snd_pcm_hw_mmap_control(pcm); + if (ret < 0) { + snd_pcm_close(pcm); + return ret; + } + return 0; - __end: - if (ret < 0 && fd >= 0) - close(fd); - snd_ctl_close(ctl); + _err: + if (hw) + free(hw); + if (pcm) + free(pcm); + close(fd); return ret; } -int snd_pcm_hw_open_device(snd_pcm_t **handlep, int card, int device, int stream, int mode) +int snd_pcm_hw_open_device(snd_pcm_t **pcmp, int card, int device, int stream, int mode) { - return snd_pcm_hw_open_subdevice(handlep, card, device, -1, stream, mode); + return snd_pcm_hw_open_subdevice(pcmp, card, device, -1, stream, mode); } -int snd_pcm_hw_open(snd_pcm_t **handlep, char *name, int card, int device, int subdevice, int stream, int mode) +int snd_pcm_hw_open(snd_pcm_t **pcmp, char *name, int card, int device, int subdevice, int stream, int mode) { - int err = snd_pcm_hw_open_subdevice(handlep, card, device, subdevice, stream, mode); + int err = snd_pcm_hw_open_subdevice(pcmp, card, device, subdevice, stream, mode); if (err < 0) return err; if (name) - (*handlep)->name = strdup(name); + (*pcmp)->name = strdup(name); return 0; } diff --git a/src/pcm/pcm_linear.c b/src/pcm/pcm_linear.c index e92e1cca..31cddbef 100644 --- a/src/pcm/pcm_linear.c +++ b/src/pcm/pcm_linear.c @@ -114,11 +114,6 @@ static int snd_pcm_linear_params(snd_pcm_t *pcm, snd_pcm_params_t * params) params->fail_reason = SND_PCM_PARAMS_FAIL_INVAL; return -EINVAL; } - if (slave->mmap_data) { - err = snd_pcm_munmap_data(slave); - if (err < 0) - return err; - } linear->cformat = params->format.sfmt; linear->cxfer_mode = params->xfer_mode; linear->cmmap_shape = params->mmap_shape; @@ -129,10 +124,6 @@ static int snd_pcm_linear_params(snd_pcm_t *pcm, snd_pcm_params_t * params) params->format.sfmt = linear->cformat; params->xfer_mode = linear->cxfer_mode; params->mmap_shape = linear->cmmap_shape; - if (slave->valid_setup) { - int r = snd_pcm_mmap_data(slave, NULL); - assert(r >= 0); - } return err; } @@ -244,7 +235,7 @@ static void snd_pcm_linear_dump(snd_pcm_t *pcm, FILE *fp) snd_pcm_dump(linear->plug.slave, fp); } -struct snd_pcm_ops snd_pcm_linear_ops = { +snd_pcm_ops_t snd_pcm_linear_ops = { close: snd_pcm_plugin_close, info: snd_pcm_plugin_info, params_info: snd_pcm_linear_params_info, @@ -256,20 +247,15 @@ struct snd_pcm_ops snd_pcm_linear_ops = { dump: snd_pcm_linear_dump, nonblock: snd_pcm_plugin_nonblock, async: snd_pcm_plugin_async, - mmap_status: snd_pcm_plugin_mmap_status, - mmap_control: snd_pcm_plugin_mmap_control, - mmap_data: snd_pcm_plugin_mmap_data, - munmap_status: snd_pcm_plugin_munmap_status, - munmap_control: snd_pcm_plugin_munmap_control, - munmap_data: snd_pcm_plugin_munmap_data, + mmap: snd_pcm_plugin_mmap, + munmap: snd_pcm_plugin_munmap, }; -int snd_pcm_linear_open(snd_pcm_t **handlep, char *name, int sformat, snd_pcm_t *slave, int close_slave) +int snd_pcm_linear_open(snd_pcm_t **pcmp, char *name, int sformat, snd_pcm_t *slave, int close_slave) { - snd_pcm_t *handle; + snd_pcm_t *pcm; snd_pcm_linear_t *linear; - int err; - assert(handlep && slave); + assert(pcmp && slave); if (snd_pcm_format_linear(sformat) != 1) return -EINVAL; linear = calloc(1, sizeof(snd_pcm_linear_t)); @@ -282,27 +268,25 @@ int snd_pcm_linear_open(snd_pcm_t **handlep, char *name, int sformat, snd_pcm_t linear->plug.slave = slave; linear->plug.close_slave = close_slave; - handle = calloc(1, sizeof(snd_pcm_t)); - if (!handle) { + pcm = calloc(1, sizeof(snd_pcm_t)); + if (!pcm) { free(linear); return -ENOMEM; } if (name) - handle->name = strdup(name); - handle->type = SND_PCM_TYPE_LINEAR; - handle->stream = slave->stream; - handle->ops = &snd_pcm_linear_ops; - handle->op_arg = handle; - handle->fast_ops = &snd_pcm_plugin_fast_ops; - handle->fast_op_arg = handle; - handle->mode = slave->mode; - handle->private = linear; - err = snd_pcm_init(handle); - if (err < 0) { - snd_pcm_close(handle); - return err; - } - *handlep = handle; + pcm->name = strdup(name); + pcm->type = SND_PCM_TYPE_LINEAR; + pcm->stream = slave->stream; + pcm->mode = slave->mode; + pcm->ops = &snd_pcm_linear_ops; + pcm->op_arg = pcm; + pcm->fast_ops = &snd_pcm_plugin_fast_ops; + pcm->fast_op_arg = pcm; + pcm->private = linear; + pcm->poll_fd = slave->poll_fd; + pcm->hw_ptr = &linear->plug.hw_ptr; + pcm->appl_ptr = &linear->plug.appl_ptr; + *pcmp = pcm; return 0; } diff --git a/src/pcm/pcm_local.h b/src/pcm/pcm_local.h index 970578c9..6763c853 100644 --- a/src/pcm/pcm_local.h +++ b/src/pcm/pcm_local.h @@ -32,7 +32,7 @@ #define ERR(args...) snd_pcm_error(__FILE__, __LINE__, __FUNCTION__, ##args) #endif -struct snd_pcm_ops { +typedef struct { int (*close)(snd_pcm_t *pcm); int (*nonblock)(snd_pcm_t *pcm, int nonblock); int (*async)(snd_pcm_t *pcm, int sig, pid_t pid); @@ -44,15 +44,11 @@ struct snd_pcm_ops { int (*channel_params)(snd_pcm_t *pcm, snd_pcm_channel_params_t *params); int (*channel_setup)(snd_pcm_t *pcm, snd_pcm_channel_setup_t *setup); void (*dump)(snd_pcm_t *pcm, FILE *fp); - int (*mmap_status)(snd_pcm_t *pcm); - int (*mmap_control)(snd_pcm_t *pcm); - int (*mmap_data)(snd_pcm_t *pcm); - int (*munmap_status)(snd_pcm_t *pcm); - int (*munmap_control)(snd_pcm_t *pcm); - int (*munmap_data)(snd_pcm_t *pcm); -}; + int (*mmap)(snd_pcm_t *pcm); + int (*munmap)(snd_pcm_t *pcm); +} snd_pcm_ops_t; -struct snd_pcm_fast_ops { +typedef struct { int (*status)(snd_pcm_t *pcm, snd_pcm_status_t *status); int (*prepare)(snd_pcm_t *pcm); int (*start)(snd_pcm_t *pcm); @@ -66,43 +62,55 @@ struct snd_pcm_fast_ops { ssize_t (*writen)(snd_pcm_t *pcm, void **bufs, size_t size); ssize_t (*readi)(snd_pcm_t *pcm, void *buffer, size_t size); ssize_t (*readn)(snd_pcm_t *pcm, void **bufs, size_t size); - int (*poll_descriptor)(snd_pcm_t *pcm); int (*channels_mask)(snd_pcm_t *pcm, bitset_t *cmask); ssize_t (*avail_update)(snd_pcm_t *pcm); ssize_t (*mmap_forward)(snd_pcm_t *pcm, size_t size); -}; +} snd_pcm_fast_ops_t; + +typedef struct { + unsigned int index; + enum { SND_PCM_MMAP_KERNEL, SND_PCM_MMAP_USER } type; + void *addr; + size_t size; + union { + struct { + int shmid; + } user; + struct { + int fd; + } kernel; + } u; +} snd_pcm_mmap_info_t; struct snd_pcm { char *name; snd_pcm_type_t type; int stream; int mode; + int poll_fd; int valid_setup; snd_pcm_setup_t setup; size_t bits_per_sample; size_t bits_per_frame; - volatile snd_pcm_mmap_status_t *mmap_status; - snd_pcm_mmap_control_t *mmap_control; - void *mmap_data; + size_t *appl_ptr; + volatile size_t *hw_ptr; + int mmap_auto; + size_t mmap_info_count; + snd_pcm_mmap_info_t *mmap_info; snd_pcm_channel_area_t *running_areas; snd_pcm_channel_area_t *stopped_areas; - struct snd_pcm_ops *ops; - struct snd_pcm_fast_ops *fast_ops; + snd_pcm_ops_t *ops; + snd_pcm_fast_ops_t *fast_ops; snd_pcm_t *op_arg; snd_pcm_t *fast_op_arg; void *private; }; -int snd_pcm_init(snd_pcm_t *pcm); void snd_pcm_areas_from_buf(snd_pcm_t *pcm, snd_pcm_channel_area_t *areas, void *buf); void snd_pcm_areas_from_bufs(snd_pcm_t *pcm, snd_pcm_channel_area_t *areas, void **bufs); -int snd_pcm_mmap_status(snd_pcm_t *pcm, volatile snd_pcm_mmap_status_t **status); -int snd_pcm_mmap_control(snd_pcm_t *pcm, snd_pcm_mmap_control_t **control); -int snd_pcm_mmap_data(snd_pcm_t *pcm, void **buffer); -int snd_pcm_munmap_status(snd_pcm_t *pcm); -int snd_pcm_munmap_control(snd_pcm_t *pcm); -int snd_pcm_munmap_data(snd_pcm_t *pcm); +int snd_pcm_mmap(snd_pcm_t *pcm); +int snd_pcm_munmap(snd_pcm_t *pcm); int snd_pcm_mmap_ready(snd_pcm_t *pcm); ssize_t snd_pcm_mmap_appl_ptr(snd_pcm_t *pcm, off_t offset); void snd_pcm_mmap_appl_backward(snd_pcm_t *pcm, size_t frames); @@ -130,7 +138,7 @@ ssize_t snd_pcm_write_mmap(snd_pcm_t *pcm, size_t size); static inline size_t snd_pcm_mmap_playback_avail(snd_pcm_t *pcm) { ssize_t avail; - avail = pcm->mmap_status->hw_ptr + pcm->setup.buffer_size - pcm->mmap_control->appl_ptr; + avail = *pcm->hw_ptr + pcm->setup.buffer_size - *pcm->appl_ptr; if (avail < 0) avail += pcm->setup.boundary; return avail; @@ -139,7 +147,7 @@ static inline size_t snd_pcm_mmap_playback_avail(snd_pcm_t *pcm) static inline size_t snd_pcm_mmap_capture_avail(snd_pcm_t *pcm) { ssize_t avail; - avail = pcm->mmap_status->hw_ptr - pcm->mmap_control->appl_ptr; + avail = *pcm->hw_ptr - *pcm->appl_ptr; if (avail < 0) avail += pcm->setup.boundary; return avail; @@ -156,7 +164,7 @@ static inline size_t snd_pcm_mmap_avail(snd_pcm_t *pcm) static inline ssize_t snd_pcm_mmap_playback_hw_avail(snd_pcm_t *pcm) { ssize_t avail; - avail = pcm->mmap_status->hw_ptr + pcm->setup.buffer_size - pcm->mmap_control->appl_ptr; + avail = *pcm->hw_ptr + pcm->setup.buffer_size - *pcm->appl_ptr; if (avail < 0) avail += pcm->setup.boundary; return pcm->setup.buffer_size - avail; @@ -165,7 +173,7 @@ static inline ssize_t snd_pcm_mmap_playback_hw_avail(snd_pcm_t *pcm) static inline ssize_t snd_pcm_mmap_capture_hw_avail(snd_pcm_t *pcm) { ssize_t avail; - avail = pcm->mmap_status->hw_ptr - pcm->mmap_control->appl_ptr; + avail = *pcm->hw_ptr - *pcm->appl_ptr; if (avail < 0) avail += pcm->setup.boundary; return pcm->setup.buffer_size - avail; diff --git a/src/pcm/pcm_mmap.c b/src/pcm/pcm_mmap.c index e3afe0b2..ffdb8455 100644 --- a/src/pcm/pcm_mmap.c +++ b/src/pcm/pcm_mmap.c @@ -36,12 +36,11 @@ snd_pcm_channel_area_t *snd_pcm_mmap_areas(snd_pcm_t *pcm) size_t snd_pcm_mmap_playback_xfer(snd_pcm_t *pcm, size_t frames) { - snd_pcm_mmap_control_t *control = pcm->mmap_control; size_t cont; size_t avail = snd_pcm_mmap_playback_avail(pcm); if (avail < frames) frames = avail; - cont = pcm->setup.buffer_size - control->appl_ptr % pcm->setup.buffer_size; + cont = pcm->setup.buffer_size - *pcm->appl_ptr % pcm->setup.buffer_size; if (cont < frames) frames = cont; return frames; @@ -49,12 +48,11 @@ size_t snd_pcm_mmap_playback_xfer(snd_pcm_t *pcm, size_t frames) size_t snd_pcm_mmap_capture_xfer(snd_pcm_t *pcm, size_t frames) { - snd_pcm_mmap_control_t *control = pcm->mmap_control; size_t cont; size_t avail = snd_pcm_mmap_capture_avail(pcm); if (avail < frames) frames = avail; - cont = pcm->setup.buffer_size - control->appl_ptr % pcm->setup.buffer_size; + cont = pcm->setup.buffer_size - *pcm->appl_ptr % pcm->setup.buffer_size; if (cont < frames) frames = cont; return frames; @@ -63,7 +61,6 @@ size_t snd_pcm_mmap_capture_xfer(snd_pcm_t *pcm, size_t frames) size_t snd_pcm_mmap_xfer(snd_pcm_t *pcm, size_t frames) { assert(pcm); - assert(pcm->mmap_status && pcm->mmap_control); if (pcm->stream == SND_PCM_STREAM_PLAYBACK) return snd_pcm_mmap_playback_xfer(pcm, frames); else @@ -73,51 +70,49 @@ size_t snd_pcm_mmap_xfer(snd_pcm_t *pcm, size_t frames) size_t snd_pcm_mmap_offset(snd_pcm_t *pcm) { assert(pcm); - assert(pcm->mmap_control); - return pcm->mmap_control->appl_ptr % pcm->setup.buffer_size; + return *pcm->appl_ptr % pcm->setup.buffer_size; } size_t snd_pcm_mmap_hw_offset(snd_pcm_t *pcm) { assert(pcm); - assert(pcm->mmap_status); - return pcm->mmap_status->hw_ptr % pcm->setup.buffer_size; + return *pcm->hw_ptr % pcm->setup.buffer_size; } void snd_pcm_mmap_appl_backward(snd_pcm_t *pcm, size_t frames) { - ssize_t appl_ptr = pcm->mmap_control->appl_ptr; + ssize_t appl_ptr = *pcm->appl_ptr; appl_ptr -= frames; if (appl_ptr < 0) appl_ptr += pcm->setup.boundary; - pcm->mmap_control->appl_ptr = appl_ptr; + *pcm->appl_ptr = appl_ptr; } void snd_pcm_mmap_appl_forward(snd_pcm_t *pcm, size_t frames) { - size_t appl_ptr = pcm->mmap_control->appl_ptr; + size_t appl_ptr = *pcm->appl_ptr; appl_ptr += frames; if (appl_ptr >= pcm->setup.boundary) appl_ptr -= pcm->setup.boundary; - pcm->mmap_control->appl_ptr = appl_ptr; + *pcm->appl_ptr = appl_ptr; } void snd_pcm_mmap_hw_backward(snd_pcm_t *pcm, size_t frames) { - ssize_t hw_ptr = pcm->mmap_status->hw_ptr; + ssize_t hw_ptr = *pcm->hw_ptr; hw_ptr -= frames; if (hw_ptr < 0) hw_ptr += pcm->setup.boundary; - pcm->mmap_status->hw_ptr = hw_ptr; + *pcm->hw_ptr = hw_ptr; } void snd_pcm_mmap_hw_forward(snd_pcm_t *pcm, size_t frames) { - size_t hw_ptr = pcm->mmap_status->hw_ptr; + size_t hw_ptr = *pcm->hw_ptr; hw_ptr += frames; if (hw_ptr >= pcm->setup.boundary) hw_ptr -= pcm->setup.boundary; - pcm->mmap_status->hw_ptr = hw_ptr; + *pcm->hw_ptr = hw_ptr; } ssize_t snd_pcm_mmap_write_areas(snd_pcm_t *pcm, @@ -216,32 +211,6 @@ ssize_t snd_pcm_mmap_readn(snd_pcm_t *pcm, void **bufs, size_t size) snd_pcm_mmap_read_areas); } -int snd_pcm_mmap_status(snd_pcm_t *pcm, volatile snd_pcm_mmap_status_t **status) -{ - int err; - assert(pcm); - if (!pcm->mmap_status) { - if ((err = pcm->ops->mmap_status(pcm->op_arg)) < 0) - return err; - } - if (status) - *status = pcm->mmap_status; - return 0; -} - -int snd_pcm_mmap_control(snd_pcm_t *pcm, snd_pcm_mmap_control_t **control) -{ - int err; - assert(pcm); - if (!pcm->mmap_control) { - if ((err = pcm->ops->mmap_control(pcm->op_arg)) < 0) - return err; - } - if (control) - *control = pcm->mmap_control; - return 0; -} - int snd_pcm_mmap_get_areas(snd_pcm_t *pcm, snd_pcm_channel_area_t *stopped_areas, snd_pcm_channel_area_t *running_areas) { snd_pcm_channel_setup_t setup; @@ -249,7 +218,7 @@ int snd_pcm_mmap_get_areas(snd_pcm_t *pcm, snd_pcm_channel_area_t *stopped_areas unsigned int channel; int err; assert(pcm); - assert(pcm->mmap_data); + assert(pcm->mmap_info); if (!pcm->running_areas) { r = calloc(pcm->setup.format.channels, sizeof(*r)); s = calloc(pcm->setup.format.channels, sizeof(*s)); @@ -274,75 +243,36 @@ int snd_pcm_mmap_get_areas(snd_pcm_t *pcm, snd_pcm_channel_area_t *stopped_areas return 0; } -int snd_pcm_mmap_data(snd_pcm_t *pcm, void **data) +int snd_pcm_mmap(snd_pcm_t *pcm) { int err; assert(pcm); assert(pcm->valid_setup); - if (pcm->mmap_data) { - if (data) - *data = pcm->mmap_data; + if (pcm->mmap_info) return 0; - } - if ((err = pcm->ops->mmap_data(pcm->op_arg)) < 0) + if ((err = pcm->ops->mmap(pcm->op_arg)) < 0) return err; - if (data) - *data = pcm->mmap_data; err = snd_pcm_mmap_get_areas(pcm, NULL, NULL); if (err < 0) return err; return 0; } -int snd_pcm_munmap_status(snd_pcm_t *pcm) -{ - int err; - assert(pcm); - assert(pcm->mmap_status); - if ((err = pcm->ops->munmap_status(pcm->op_arg)) < 0) - return err; - pcm->mmap_status = 0; - return 0; -} - -int snd_pcm_munmap_control(snd_pcm_t *pcm) -{ - int err; - assert(pcm); - assert(pcm->mmap_control); - if ((err = pcm->ops->munmap_control(pcm->op_arg)) < 0) - return err; - pcm->mmap_control = 0; - return 0; -} - -int snd_pcm_munmap_data(snd_pcm_t *pcm) +int snd_pcm_munmap(snd_pcm_t *pcm) { int err; assert(pcm); - assert(pcm->mmap_data); - if ((err = pcm->ops->munmap_data(pcm->op_arg)) < 0) + assert(pcm->mmap_info); + if ((err = pcm->ops->munmap(pcm->op_arg)) < 0) return err; free(pcm->stopped_areas); free(pcm->running_areas); pcm->stopped_areas = 0; pcm->running_areas = 0; - pcm->mmap_data = 0; return 0; } -int snd_pcm_mmap(snd_pcm_t *pcm, void **data) -{ - return snd_pcm_mmap_data(pcm, data); -} - -int snd_pcm_munmap(snd_pcm_t *pcm) -{ - return snd_pcm_munmap_data(pcm); -} - - ssize_t snd_pcm_write_mmap(snd_pcm_t *pcm, size_t size) { size_t xfer = 0; diff --git a/src/pcm/pcm_mulaw.c b/src/pcm/pcm_mulaw.c index ba6dc888..ae78f39a 100644 --- a/src/pcm/pcm_mulaw.c +++ b/src/pcm/pcm_mulaw.c @@ -276,11 +276,6 @@ static int snd_pcm_mulaw_params(snd_pcm_t *pcm, snd_pcm_params_t * params) params->fail_reason = SND_PCM_PARAMS_FAIL_INVAL; return -EINVAL; } - if (slave->mmap_data) { - err = snd_pcm_munmap_data(slave); - if (err < 0) - return err; - } mulaw->cformat = params->format.sfmt; mulaw->cxfer_mode = params->xfer_mode; mulaw->cmmap_shape = params->mmap_shape; @@ -291,10 +286,6 @@ static int snd_pcm_mulaw_params(snd_pcm_t *pcm, snd_pcm_params_t * params) params->format.sfmt = mulaw->cformat; params->xfer_mode = mulaw->cxfer_mode; params->mmap_shape = mulaw->cmmap_shape; - if (slave->valid_setup) { - int r = snd_pcm_mmap_data(slave, NULL); - assert(r >= 0); - } return err; } @@ -418,7 +409,7 @@ static void snd_pcm_mulaw_dump(snd_pcm_t *pcm, FILE *fp) snd_pcm_dump(mulaw->plug.slave, fp); } -struct snd_pcm_ops snd_pcm_mulaw_ops = { +snd_pcm_ops_t snd_pcm_mulaw_ops = { close: snd_pcm_plugin_close, info: snd_pcm_plugin_info, params_info: snd_pcm_mulaw_params_info, @@ -430,20 +421,15 @@ struct snd_pcm_ops snd_pcm_mulaw_ops = { dump: snd_pcm_mulaw_dump, nonblock: snd_pcm_plugin_nonblock, async: snd_pcm_plugin_async, - mmap_status: snd_pcm_plugin_mmap_status, - mmap_control: snd_pcm_plugin_mmap_control, - mmap_data: snd_pcm_plugin_mmap_data, - munmap_status: snd_pcm_plugin_munmap_status, - munmap_control: snd_pcm_plugin_munmap_control, - munmap_data: snd_pcm_plugin_munmap_data, + mmap: snd_pcm_plugin_mmap, + munmap: snd_pcm_plugin_munmap, }; -int snd_pcm_mulaw_open(snd_pcm_t **handlep, char *name, int sformat, snd_pcm_t *slave, int close_slave) +int snd_pcm_mulaw_open(snd_pcm_t **pcmp, char *name, int sformat, snd_pcm_t *slave, int close_slave) { - snd_pcm_t *handle; + snd_pcm_t *pcm; snd_pcm_mulaw_t *mulaw; - int err; - assert(handlep && slave); + assert(pcmp && slave); if (snd_pcm_format_linear(sformat) != 1 && sformat != SND_PCM_SFMT_MU_LAW) return -EINVAL; @@ -457,27 +443,25 @@ int snd_pcm_mulaw_open(snd_pcm_t **handlep, char *name, int sformat, snd_pcm_t * mulaw->plug.slave = slave; mulaw->plug.close_slave = close_slave; - handle = calloc(1, sizeof(snd_pcm_t)); - if (!handle) { + pcm = calloc(1, sizeof(snd_pcm_t)); + if (!pcm) { free(mulaw); return -ENOMEM; } if (name) - handle->name = strdup(name); - handle->type = SND_PCM_TYPE_MULAW; - handle->stream = slave->stream; - handle->ops = &snd_pcm_mulaw_ops; - handle->op_arg = handle; - handle->fast_ops = &snd_pcm_plugin_fast_ops; - handle->fast_op_arg = handle; - handle->mode = slave->mode; - handle->private = mulaw; - err = snd_pcm_init(handle); - if (err < 0) { - snd_pcm_close(handle); - return err; - } - *handlep = handle; + pcm->name = strdup(name); + pcm->type = SND_PCM_TYPE_MULAW; + pcm->stream = slave->stream; + pcm->mode = slave->mode; + pcm->ops = &snd_pcm_mulaw_ops; + pcm->op_arg = pcm; + pcm->fast_ops = &snd_pcm_plugin_fast_ops; + pcm->fast_op_arg = pcm; + pcm->private = mulaw; + pcm->poll_fd = slave->poll_fd; + pcm->hw_ptr = &mulaw->plug.hw_ptr; + pcm->appl_ptr = &mulaw->plug.appl_ptr; + *pcmp = pcm; return 0; } diff --git a/src/pcm/pcm_multi.c b/src/pcm/pcm_multi.c index c317c112..cd41dd31 100644 --- a/src/pcm/pcm_multi.c +++ b/src/pcm/pcm_multi.c @@ -152,6 +152,60 @@ static int snd_pcm_multi_params_info(snd_pcm_t *pcm, snd_pcm_params_info_t *info return 0; } +static int snd_pcm_multi_mmap(snd_pcm_t *pcm) +{ + snd_pcm_multi_t *multi = pcm->private; + unsigned int i; + size_t count = 0; + for (i = 0; i < multi->slaves_count; ++i) { + snd_pcm_t *slave = multi->slaves[i].pcm; + snd_pcm_setup_t *setup; + int err = snd_pcm_mmap(slave); + if (err < 0) + return err; + count += slave->mmap_info_count; + setup = &slave->setup; + if (pcm->stream == SND_PCM_STREAM_PLAYBACK) { + snd_pcm_channel_area_t r[setup->format.channels]; + snd_pcm_channel_area_t s[setup->format.channels]; + err = snd_pcm_mmap_get_areas(slave, s, r); + if (err < 0) + return err; + err = snd_pcm_areas_silence(s, 0, setup->format.channels, setup->buffer_size, setup->format.sfmt); + if (err < 0) + return err; + err = snd_pcm_areas_silence(r, 0, setup->format.channels, setup->buffer_size, setup->format.sfmt); + if (err < 0) + return err; + } + } + pcm->mmap_info_count = count; + pcm->mmap_info = malloc(count * sizeof(*pcm->mmap_info)); + count = 0; + for (i = 0; i < multi->slaves_count; ++i) { + snd_pcm_t *slave = multi->slaves[i].pcm; + memcpy(&pcm->mmap_info[count], slave->mmap_info, slave->mmap_info_count * sizeof(*pcm->mmap_info)); + count += slave->mmap_info_count; + } + return 0; +} + +static int snd_pcm_multi_munmap(snd_pcm_t *pcm) +{ + snd_pcm_multi_t *multi = pcm->private; + unsigned int i; + for (i = 0; i < multi->slaves_count; ++i) { + snd_pcm_t *slave = multi->slaves[i].pcm; + int err = snd_pcm_munmap(slave); + if (err < 0) + return err; + } + pcm->mmap_info_count = 0; + free(pcm->mmap_info); + pcm->mmap_info = 0; + return 0; +} + static int snd_pcm_multi_params(snd_pcm_t *pcm, snd_pcm_params_t *params) { snd_pcm_multi_t *multi = pcm->private; @@ -166,11 +220,6 @@ static int snd_pcm_multi_params(snd_pcm_t *pcm, snd_pcm_params_t *params) p = *params; for (i = 0; i < multi->slaves_count; ++i) { snd_pcm_t *slave = multi->slaves[i].pcm; - if (slave->mmap_data) { - err = snd_pcm_munmap_data(slave); - if (err < 0) - return err; - } p.format.channels = multi->slaves[i].channels_count; err = snd_pcm_params(slave, &p); if (err < 0) { @@ -179,14 +228,6 @@ static int snd_pcm_multi_params(snd_pcm_t *pcm, snd_pcm_params_t *params) break; } } - for (i = 0; i < multi->slaves_count; ++i) { - snd_pcm_t *slave = multi->slaves[i].pcm; - snd_pcm_mmap_data(slave, NULL); - if (pcm->stream == SND_PCM_STREAM_PLAYBACK && - err == 0) - snd_pcm_areas_silence(snd_pcm_mmap_areas(slave), 0, slave->setup.format.channels, - slave->setup.buffer_size, slave->setup.format.sfmt); - } if (err == 0) multi->xfer_mode = params->xfer_mode; return err; @@ -346,73 +387,6 @@ static ssize_t snd_pcm_multi_rewind(snd_pcm_t *pcm, size_t frames) return frames; } -static int snd_pcm_multi_mmap_status(snd_pcm_t *pcm) -{ - snd_pcm_multi_t *multi = pcm->private; - pcm->mmap_status = multi->slaves[0].pcm->mmap_status; - return 0; -} - -static int snd_pcm_multi_mmap_control(snd_pcm_t *pcm) -{ - snd_pcm_multi_t *multi = pcm->private; - pcm->mmap_control = multi->slaves[0].pcm->mmap_control; - return 0; -} - -static int snd_pcm_multi_mmap_data(snd_pcm_t *pcm) -{ - snd_pcm_multi_t *multi = pcm->private; - unsigned int i; - for (i = 0; i < multi->slaves_count; ++i) { - snd_pcm_t *slave = multi->slaves[i].pcm; - int err = snd_pcm_mmap_data(slave, 0); - snd_pcm_setup_t *setup; - if (err < 0) - return err; - setup = &slave->setup; - if (pcm->stream == SND_PCM_STREAM_PLAYBACK) { - snd_pcm_channel_area_t r[setup->format.channels]; - snd_pcm_channel_area_t s[setup->format.channels]; - err = snd_pcm_mmap_get_areas(slave, s, r); - if (err < 0) - return err; - err = snd_pcm_areas_silence(s, 0, setup->format.channels, setup->buffer_size, setup->format.sfmt); - if (err < 0) - return err; - err = snd_pcm_areas_silence(r, 0, setup->format.channels, setup->buffer_size, setup->format.sfmt); - if (err < 0) - return err; - } - } - pcm->mmap_data = multi->slaves[0].pcm->mmap_data; - return 0; -} - -static int snd_pcm_multi_munmap_status(snd_pcm_t *pcm ATTRIBUTE_UNUSED) -{ - return 0; -} - -static int snd_pcm_multi_munmap_control(snd_pcm_t *pcm ATTRIBUTE_UNUSED) -{ - return 0; -} - -static int snd_pcm_multi_munmap_data(snd_pcm_t *pcm) -{ - snd_pcm_multi_t *multi = pcm->private; - unsigned int i; - int ret = 0; - for (i = 0; i < multi->slaves_count; ++i) { - snd_pcm_t *slave = multi->slaves[i].pcm; - int err = snd_pcm_munmap_data(slave); - if (err < 0) - ret = err; - } - return ret; -} - static ssize_t snd_pcm_multi_mmap_forward(snd_pcm_t *pcm, size_t size) { snd_pcm_multi_t *multi = pcm->private; @@ -500,7 +474,7 @@ static void snd_pcm_multi_dump(snd_pcm_t *pcm, FILE *fp) } } -struct snd_pcm_ops snd_pcm_multi_ops = { +snd_pcm_ops_t snd_pcm_multi_ops = { close: snd_pcm_multi_close, info: snd_pcm_multi_info, params_info: snd_pcm_multi_params_info, @@ -512,15 +486,11 @@ struct snd_pcm_ops snd_pcm_multi_ops = { dump: snd_pcm_multi_dump, nonblock: snd_pcm_multi_nonblock, async: snd_pcm_multi_async, - mmap_status: snd_pcm_multi_mmap_status, - mmap_control: snd_pcm_multi_mmap_control, - mmap_data: snd_pcm_multi_mmap_data, - munmap_status: snd_pcm_multi_munmap_status, - munmap_control: snd_pcm_multi_munmap_control, - munmap_data: snd_pcm_multi_munmap_data, + mmap: snd_pcm_multi_mmap, + munmap: snd_pcm_multi_munmap, }; -struct snd_pcm_fast_ops snd_pcm_multi_fast_ops = { +snd_pcm_fast_ops_t snd_pcm_multi_fast_ops = { status: snd_pcm_multi_status, state: snd_pcm_multi_state, delay: snd_pcm_multi_delay, @@ -534,28 +504,26 @@ struct snd_pcm_fast_ops snd_pcm_multi_fast_ops = { readi: snd_pcm_mmap_readi, readn: snd_pcm_mmap_readn, rewind: snd_pcm_multi_rewind, - poll_descriptor: snd_pcm_multi_poll_descriptor, channels_mask: snd_pcm_multi_channels_mask, avail_update: snd_pcm_multi_avail_update, mmap_forward: snd_pcm_multi_mmap_forward, }; -int snd_pcm_multi_open(snd_pcm_t **handlep, char *name, +int snd_pcm_multi_open(snd_pcm_t **pcmp, char *name, size_t slaves_count, - snd_pcm_t **slaves_handle, size_t *schannels_count, + snd_pcm_t **slaves_pcm, size_t *schannels_count, size_t channels_count, int *sidxs, unsigned int *schannels, int close_slaves) { - snd_pcm_t *handle; + snd_pcm_t *pcm; snd_pcm_multi_t *multi; unsigned int i; - int err; int stream; char slave_map[32][32] = { { 0 } }; - assert(handlep); - assert(slaves_count > 0 && slaves_handle && schannels_count); + assert(pcmp); + assert(slaves_count > 0 && slaves_pcm && schannels_count); assert(channels_count > 0 && sidxs && schannels); multi = calloc(1, sizeof(snd_pcm_multi_t)); @@ -563,7 +531,7 @@ int snd_pcm_multi_open(snd_pcm_t **handlep, char *name, return -ENOMEM; } - stream = slaves_handle[0]->stream; + stream = slaves_pcm[0]->stream; multi->slaves_count = slaves_count; multi->slaves = calloc(slaves_count, sizeof(*multi->slaves)); @@ -571,12 +539,12 @@ int snd_pcm_multi_open(snd_pcm_t **handlep, char *name, multi->channels = calloc(channels_count, sizeof(*multi->channels)); for (i = 0; i < slaves_count; ++i) { snd_pcm_multi_slave_t *slave = &multi->slaves[i]; - assert(slaves_handle[i]->stream == stream); - slave->pcm = slaves_handle[i]; + assert(slaves_pcm[i]->stream == stream); + slave->pcm = slaves_pcm[i]; slave->channels_count = schannels_count[i]; slave->close_slave = close_slaves; if (i != 0) - snd_pcm_link(slaves_handle[i-1], slaves_handle[i]); + snd_pcm_link(slaves_pcm[i-1], slaves_pcm[i]); } for (i = 0; i < channels_count; ++i) { snd_pcm_multi_channel_t *bind = &multi->channels[i]; @@ -591,27 +559,26 @@ int snd_pcm_multi_open(snd_pcm_t **handlep, char *name, } multi->channels_count = channels_count; - handle = calloc(1, sizeof(snd_pcm_t)); - if (!handle) { + pcm = calloc(1, sizeof(snd_pcm_t)); + if (!pcm) { free(multi); return -ENOMEM; } if (name) - handle->name = strdup(name); - handle->type = SND_PCM_TYPE_MULTI; - handle->stream = stream; - handle->mode = multi->slaves[0].pcm->mode; - handle->ops = &snd_pcm_multi_ops; - handle->op_arg = handle; - handle->fast_ops = &snd_pcm_multi_fast_ops; - handle->fast_op_arg = handle; - handle->private = multi; - err = snd_pcm_init(handle); - if (err < 0) { - snd_pcm_close(handle); - return err; - } - *handlep = handle; + pcm->name = strdup(name); + pcm->type = SND_PCM_TYPE_MULTI; + pcm->stream = stream; + pcm->mode = multi->slaves[0].pcm->mode; + pcm->mmap_auto = 1; + pcm->ops = &snd_pcm_multi_ops; + pcm->op_arg = pcm; + pcm->fast_ops = &snd_pcm_multi_fast_ops; + pcm->fast_op_arg = pcm; + pcm->private = multi; + pcm->poll_fd = multi->slaves[0].pcm->poll_fd; + pcm->hw_ptr = multi->slaves[0].pcm->hw_ptr; + pcm->appl_ptr = multi->slaves[0].pcm->appl_ptr; + *pcmp = pcm; return 0; } diff --git a/src/pcm/pcm_plug.c b/src/pcm/pcm_plug.c index 36ea8930..8c2a5f6d 100644 --- a/src/pcm/pcm_plug.c +++ b/src/pcm/pcm_plug.c @@ -323,6 +323,7 @@ static int snd_pcm_plug_change_rate(snd_pcm_t *pcm, snd_pcm_t **new, snd_pcm_for err = snd_pcm_rate_open(new, NULL, slv->sfmt, slv->rate, plug->slave, plug->slave != plug->req_slave); if (err < 0) return err; + (*new)->mmap_auto = 1; slv->rate = clt->rate; if (snd_pcm_format_linear(clt->sfmt)) slv->sfmt = clt->sfmt; @@ -387,6 +388,7 @@ static int snd_pcm_plug_change_channels(snd_pcm_t *pcm, snd_pcm_t **new, snd_pcm err = snd_pcm_route_open(new, NULL, slv->sfmt, slv->channels, ttable, tt_ssize, tt_cused, tt_sused, plug->slave, plug->slave != plug->req_slave); if (err < 0) return err; + (*new)->mmap_auto = 1; slv->channels = clt->channels; if (snd_pcm_format_linear(clt->sfmt)) slv->sfmt = clt->sfmt; @@ -397,7 +399,7 @@ static int snd_pcm_plug_change_format(snd_pcm_t *pcm, snd_pcm_t **new, snd_pcm_f { snd_pcm_plug_t *plug = pcm->private; int err, cfmt; - int (*f)(snd_pcm_t **handle, char *name, int sformat, snd_pcm_t *slave, int close_slave); + int (*f)(snd_pcm_t **pcm, char *name, int sformat, snd_pcm_t *slave, int close_slave); if (snd_pcm_format_linear(slv->sfmt)) { /* Conversion is done in another plugin */ if (clt->sfmt == slv->sfmt || @@ -451,6 +453,7 @@ static int snd_pcm_plug_change_format(snd_pcm_t *pcm, snd_pcm_t **new, snd_pcm_f err = f(new, NULL, slv->sfmt, plug->slave, plug->slave != plug->req_slave); if (err < 0) return err; + (*new)->mmap_auto = 1; slv->sfmt = cfmt; return 1; } @@ -489,6 +492,7 @@ static int snd_pcm_plug_insert_plugins(snd_pcm_t *pcm, } k++; } + plug->slave->mmap_auto = 0; assert(0); return 0; } @@ -563,15 +567,16 @@ static int snd_pcm_plug_params(snd_pcm_t *pcm, snd_pcm_params_t *params) return err; err = snd_pcm_params(plug->slave, params); - if (err < 0) + if (err < 0) { snd_pcm_plug_clear(pcm); - else { - assert(slave->setup.format.sfmt == slave_format->sfmt); - assert(slave->setup.format.channels == slave_format->channels); - assert(slave->setup.format.rate == slave_format->rate); + return err; } - - return err; + assert(slave->setup.format.sfmt == slave_format->sfmt); + assert(slave->setup.format.channels == slave_format->channels); + assert(slave->setup.format.rate == slave_format->rate); + pcm->hw_ptr = slave->hw_ptr; + pcm->appl_ptr = slave->appl_ptr; + return 0; } static int snd_pcm_plug_setup(snd_pcm_t *pcm, snd_pcm_setup_t *setup) @@ -598,53 +603,27 @@ static int snd_pcm_plug_channel_setup(snd_pcm_t *pcm, snd_pcm_channel_setup_t *s return snd_pcm_channel_setup(plug->slave, setup); } -static int snd_pcm_plug_mmap_status(snd_pcm_t *pcm) +static int snd_pcm_plug_mmap(snd_pcm_t *pcm) { snd_pcm_plug_t *plug = pcm->private; - int err = snd_pcm_mmap_status(plug->slave, NULL); + int err = snd_pcm_mmap(plug->slave); if (err < 0) return err; - pcm->mmap_status = plug->slave->mmap_status; + pcm->mmap_info_count = plug->slave->mmap_info_count; + pcm->mmap_info = plug->slave->mmap_info; return 0; } -static int snd_pcm_plug_mmap_control(snd_pcm_t *pcm) +static int snd_pcm_plug_munmap(snd_pcm_t *pcm) { snd_pcm_plug_t *plug = pcm->private; - int err = snd_pcm_mmap_control(plug->slave, NULL); + int err = snd_pcm_munmap(plug->slave); if (err < 0) return err; - pcm->mmap_control = plug->slave->mmap_control; + pcm->mmap_info_count = 0; + pcm->mmap_info = 0; return 0; } - -static int snd_pcm_plug_mmap_data(snd_pcm_t *pcm) -{ - snd_pcm_plug_t *plug = pcm->private; - int err = snd_pcm_mmap_data(plug->slave, NULL); - if (err < 0) - return err; - pcm->mmap_data = plug->slave->mmap_data; - return 0; -} - -static int snd_pcm_plug_munmap_status(snd_pcm_t *pcm) -{ - snd_pcm_plug_t *plug = pcm->private; - return snd_pcm_munmap_status(plug->slave); -} - -static int snd_pcm_plug_munmap_control(snd_pcm_t *pcm) -{ - snd_pcm_plug_t *plug = pcm->private; - return snd_pcm_munmap_control(plug->slave); -} - -static int snd_pcm_plug_munmap_data(snd_pcm_t *pcm) -{ - snd_pcm_plug_t *plug = pcm->private; - return snd_pcm_munmap_data(plug->slave); -} static void snd_pcm_plug_dump(snd_pcm_t *pcm, FILE *fp) { @@ -653,7 +632,7 @@ static void snd_pcm_plug_dump(snd_pcm_t *pcm, FILE *fp) snd_pcm_dump(plug->slave, fp); } -struct snd_pcm_ops snd_pcm_plug_ops = { +snd_pcm_ops_t snd_pcm_plug_ops = { close: snd_pcm_plug_close, info: snd_pcm_plug_info, params_info: snd_pcm_plug_params_info, @@ -665,25 +644,20 @@ struct snd_pcm_ops snd_pcm_plug_ops = { dump: snd_pcm_plug_dump, nonblock: snd_pcm_plug_nonblock, async: snd_pcm_plug_async, - mmap_status: snd_pcm_plug_mmap_status, - mmap_control: snd_pcm_plug_mmap_control, - mmap_data: snd_pcm_plug_mmap_data, - munmap_status: snd_pcm_plug_munmap_status, - munmap_control: snd_pcm_plug_munmap_control, - munmap_data: snd_pcm_plug_munmap_data, + mmap: snd_pcm_plug_mmap, + munmap: snd_pcm_plug_munmap, }; -int snd_pcm_plug_open(snd_pcm_t **handlep, +int snd_pcm_plug_open(snd_pcm_t **pcmp, char *name, ttable_entry_t *ttable, unsigned int tt_ssize, unsigned int tt_cused, unsigned int tt_sused, snd_pcm_t *slave, int close_slave) { - snd_pcm_t *handle; + snd_pcm_t *pcm; snd_pcm_plug_t *plug; - int err; - assert(handlep && slave); + assert(pcmp && slave); plug = calloc(1, sizeof(snd_pcm_plug_t)); if (!plug) return -ENOMEM; @@ -694,44 +668,42 @@ int snd_pcm_plug_open(snd_pcm_t **handlep, plug->tt_cused = tt_cused; plug->tt_sused = tt_sused; - handle = calloc(1, sizeof(snd_pcm_t)); - if (!handle) { + pcm = calloc(1, sizeof(snd_pcm_t)); + if (!pcm) { free(plug); return -ENOMEM; } if (name) - handle->name = strdup(name); - handle->type = SND_PCM_TYPE_PLUG; - handle->stream = slave->stream; - handle->ops = &snd_pcm_plug_ops; - handle->op_arg = handle; - handle->fast_ops = slave->fast_ops; - handle->fast_op_arg = slave->fast_op_arg; - handle->mode = slave->mode; - handle->private = plug; - err = snd_pcm_init(handle); - if (err < 0) { - snd_pcm_close(handle); - return err; - } - *handlep = handle; + pcm->name = strdup(name); + pcm->type = SND_PCM_TYPE_PLUG; + pcm->stream = slave->stream; + pcm->mode = slave->mode; + pcm->ops = &snd_pcm_plug_ops; + pcm->op_arg = pcm; + pcm->fast_ops = slave->fast_ops; + pcm->fast_op_arg = slave->fast_op_arg; + pcm->private = plug; + pcm->poll_fd = slave->poll_fd; + pcm->hw_ptr = slave->hw_ptr; + pcm->appl_ptr = slave->appl_ptr; + *pcmp = pcm; return 0; } -int snd_pcm_plug_open_subdevice(snd_pcm_t **handlep, int card, int device, int subdevice, int stream, int mode) +int snd_pcm_plug_open_subdevice(snd_pcm_t **pcmp, int card, int device, int subdevice, int stream, int mode) { snd_pcm_t *slave; int err; err = snd_pcm_hw_open_subdevice(&slave, card, device, subdevice, stream, mode); if (err < 0) return err; - return snd_pcm_plug_open(handlep, NULL, 0, 0, 0, 0, slave, 1); + return snd_pcm_plug_open(pcmp, NULL, 0, 0, 0, 0, slave, 1); } -int snd_pcm_plug_open_device(snd_pcm_t **handlep, int card, int device, int stream, int mode) +int snd_pcm_plug_open_device(snd_pcm_t **pcmp, int card, int device, int stream, int mode) { - return snd_pcm_plug_open_subdevice(handlep, card, device, -1, stream, mode); + return snd_pcm_plug_open_subdevice(pcmp, card, device, -1, stream, mode); } #define MAX_CHANNELS 32 diff --git a/src/pcm/pcm_plugin.c b/src/pcm/pcm_plugin.c index 7fb5a0b4..18c553a0 100644 --- a/src/pcm/pcm_plugin.c +++ b/src/pcm/pcm_plugin.c @@ -70,12 +70,14 @@ int snd_pcm_plugin_channel_setup(snd_pcm_t *pcm, snd_pcm_channel_setup_t * setup err = snd_pcm_channel_setup(plugin->slave, setup); if (err < 0) return err; + if (!pcm->mmap_info) + return 0; if (pcm->setup.mmap_shape == SND_PCM_MMAP_INTERLEAVED) { - setup->running_area.addr = pcm->mmap_data; + setup->running_area.addr = pcm->mmap_info->addr; setup->running_area.first = setup->channel * pcm->bits_per_sample; setup->running_area.step = pcm->bits_per_frame; } else { - setup->running_area.addr = pcm->mmap_data + setup->channel * pcm->setup.buffer_size * pcm->bits_per_sample / 8; + setup->running_area.addr = pcm->mmap_info->addr + setup->channel * pcm->setup.buffer_size * pcm->bits_per_sample / 8; setup->running_area.first = 0; setup->running_area.step = pcm->bits_per_sample; } @@ -118,8 +120,8 @@ int snd_pcm_plugin_prepare(snd_pcm_t *pcm) int err = snd_pcm_prepare(plugin->slave); if (err < 0) return err; - plugin->mmap_status.hw_ptr = 0; - plugin->mmap_control.appl_ptr = 0; + plugin->hw_ptr = 0; + plugin->appl_ptr = 0; if (plugin->init) { err = plugin->init(pcm); if (err < 0) @@ -276,7 +278,7 @@ ssize_t snd_pcm_plugin_avail_update(snd_pcm_t *pcm) if (slave_size <= 0) return slave_size; if (pcm->stream == SND_PCM_STREAM_PLAYBACK || - !pcm->mmap_data) + !pcm->mmap_info) return plugin->client_frames ? plugin->client_frames(pcm, slave_size) : slave_size; client_xfer = snd_pcm_mmap_capture_avail(pcm); @@ -301,42 +303,39 @@ ssize_t snd_pcm_plugin_avail_update(snd_pcm_t *pcm) return err; } -int snd_pcm_plugin_mmap_status(snd_pcm_t *pcm) +int snd_pcm_plugin_mmap(snd_pcm_t *pcm) { snd_pcm_plugin_t *plugin = pcm->private; - pcm->mmap_status = &plugin->mmap_status; - return 0; -} - -int snd_pcm_plugin_mmap_control(snd_pcm_t *pcm) -{ - snd_pcm_plugin_t *plugin = pcm->private; - pcm->mmap_control = &plugin->mmap_control; - return 0; -} - -int snd_pcm_plugin_mmap_data(snd_pcm_t *pcm) -{ - void *ptr = malloc(snd_pcm_frames_to_bytes(pcm, pcm->setup.buffer_size)); - if (!ptr) + snd_pcm_t *slave = plugin->slave; + int err = snd_pcm_mmap(slave); + if (err < 0) + return err; + pcm->mmap_info = calloc(1, sizeof(*pcm->mmap_info)); + if (!pcm->mmap_info) return -ENOMEM; - pcm->mmap_data = ptr; - return 0; -} - -int snd_pcm_plugin_munmap_status(snd_pcm_t *pcm ATTRIBUTE_UNUSED) -{ - return 0; -} - -int snd_pcm_plugin_munmap_control(snd_pcm_t *pcm ATTRIBUTE_UNUSED) -{ + pcm->mmap_info_count = 1; + pcm->mmap_info->type = SND_PCM_MMAP_USER; + pcm->mmap_info->size = pcm->setup.buffer_size; + pcm->mmap_info->addr = valloc(snd_pcm_frames_to_bytes(pcm, pcm->setup.buffer_size)); + if (!pcm->mmap_info->addr) { + free(pcm->mmap_info); + pcm->mmap_info = 0; + return -ENOMEM; + } return 0; } -int snd_pcm_plugin_munmap_data(snd_pcm_t *pcm ATTRIBUTE_UNUSED) +int snd_pcm_plugin_munmap(snd_pcm_t *pcm) { - free(pcm->mmap_data); + snd_pcm_plugin_t *plugin = pcm->private; + snd_pcm_t *slave = plugin->slave; + int err = snd_pcm_munmap(slave); + if (err < 0) + return err; + free(pcm->mmap_info->addr); + free(pcm->mmap_info); + pcm->mmap_info_count = 0; + pcm->mmap_info = 0; return 0; } @@ -392,7 +391,7 @@ int getput_index(int format) return width * 4 + endian * 2 + sign; } -struct snd_pcm_fast_ops snd_pcm_plugin_fast_ops = { +snd_pcm_fast_ops_t snd_pcm_plugin_fast_ops = { status: snd_pcm_plugin_status, state: snd_pcm_plugin_state, delay: snd_pcm_plugin_delay, @@ -406,7 +405,6 @@ struct snd_pcm_fast_ops snd_pcm_plugin_fast_ops = { writen: snd_pcm_plugin_writen, readi: snd_pcm_plugin_readi, readn: snd_pcm_plugin_readn, - poll_descriptor: snd_pcm_plugin_poll_descriptor, channels_mask: snd_pcm_plugin_channels_mask, avail_update: snd_pcm_plugin_avail_update, mmap_forward: snd_pcm_plugin_mmap_forward, diff --git a/src/pcm/pcm_plugin.h b/src/pcm/pcm_plugin.h index e86b1d06..13ec00af 100644 --- a/src/pcm/pcm_plugin.h +++ b/src/pcm/pcm_plugin.h @@ -26,8 +26,7 @@ typedef struct { snd_pcm_xfer_areas_func_t write; size_t (*client_frames)(snd_pcm_t *pcm, size_t frames); int (*init)(snd_pcm_t *pcm); - snd_pcm_mmap_control_t mmap_control; - snd_pcm_mmap_status_t mmap_status; + size_t appl_ptr, hw_ptr; } snd_pcm_plugin_t; int snd_pcm_plugin_close(snd_pcm_t *pcm); @@ -54,10 +53,10 @@ ssize_t snd_pcm_plugin_mmap_forward(snd_pcm_t *pcm, size_t size); ssize_t snd_pcm_plugin_avail_update(snd_pcm_t *pcm); int snd_pcm_plugin_mmap_status(snd_pcm_t *pcm); int snd_pcm_plugin_mmap_control(snd_pcm_t *pcm); -int snd_pcm_plugin_mmap_data(snd_pcm_t *pcm); +int snd_pcm_plugin_mmap(snd_pcm_t *pcm); int snd_pcm_plugin_munmap_status(snd_pcm_t *pcm); int snd_pcm_plugin_munmap_control(snd_pcm_t *pcm); -int snd_pcm_plugin_munmap_data(snd_pcm_t *pcm); +int snd_pcm_plugin_munmap(snd_pcm_t *pcm); int snd_pcm_plugin_poll_descriptor(snd_pcm_t *pcm); int snd_pcm_plugin_channels_mask(snd_pcm_t *pcm, bitset_t *cmask); int getput_index(int format); @@ -71,7 +70,7 @@ int conv_index(int src_format, int dst_format); SND_PCM_FMT_S32_LE | SND_PCM_FMT_S32_BE | \ SND_PCM_FMT_U32_LE | SND_PCM_FMT_U32_BE) -extern struct snd_pcm_fast_ops snd_pcm_plugin_fast_ops; +extern snd_pcm_fast_ops_t snd_pcm_plugin_fast_ops; #define muldiv64(a,b,d) (((int64_t)(a) * (b) + (b) / 2) / (d)) @@ -88,19 +87,19 @@ typedef int ttable_entry_t; #define FULL ROUTE_PLUGIN_RESOLUTION #endif -int snd_pcm_linear_open(snd_pcm_t **handlep, char *name, int sformat, snd_pcm_t *slave, int close_slave); -int snd_pcm_mulaw_open(snd_pcm_t **handlep, char *name, int sformat, snd_pcm_t *slave, int close_slave); -int snd_pcm_alaw_open(snd_pcm_t **handlep, char *name, int sformat, snd_pcm_t *slave, int close_slave); -int snd_pcm_adpcm_open(snd_pcm_t **handlep, char *name, int sformat, snd_pcm_t *slave, int close_slave); +int snd_pcm_linear_open(snd_pcm_t **pcmp, char *name, int sformat, snd_pcm_t *slave, int close_slave); +int snd_pcm_mulaw_open(snd_pcm_t **pcmp, char *name, int sformat, snd_pcm_t *slave, int close_slave); +int snd_pcm_alaw_open(snd_pcm_t **pcmp, char *name, int sformat, snd_pcm_t *slave, int close_slave); +int snd_pcm_adpcm_open(snd_pcm_t **pcmp, char *name, int sformat, snd_pcm_t *slave, int close_slave); int snd_pcm_route_load_ttable(snd_config_t *tt, ttable_entry_t *ttable, unsigned int tt_csize, unsigned int tt_ssize, unsigned int *tt_cused, unsigned int *tt_sused, int schannels); -int snd_pcm_route_open(snd_pcm_t **handlep, char *name, +int snd_pcm_route_open(snd_pcm_t **pcmp, char *name, int sformat, unsigned int schannels, ttable_entry_t *ttable, unsigned int tt_ssize, unsigned int tt_cused, unsigned int tt_sused, snd_pcm_t *slave, int close_slave); -int snd_pcm_rate_open(snd_pcm_t **handlep, char *name, int sformat, int srate, snd_pcm_t *slave, int close_slave); +int snd_pcm_rate_open(snd_pcm_t **pcmp, char *name, int sformat, int srate, snd_pcm_t *slave, int close_slave); diff --git a/src/pcm/pcm_rate.c b/src/pcm/pcm_rate.c index 43e5ee87..a804df51 100644 --- a/src/pcm/pcm_rate.c +++ b/src/pcm/pcm_rate.c @@ -326,12 +326,6 @@ static int snd_pcm_rate_params(snd_pcm_t *pcm, snd_pcm_params_t * params) return err; } - if (slave->mmap_data) { - err = snd_pcm_munmap_data(slave); - if (err < 0) - return err; - } - if (rate->req_srate - slave_info.min_rate < slave_info.max_rate - rate->req_srate) srate = slave_info.min_rate; else @@ -349,10 +343,6 @@ static int snd_pcm_rate_params(snd_pcm_t *pcm, snd_pcm_params_t * params) err = snd_pcm_params(slave, &slave_params); params->fail_mask = slave_params.fail_mask; params->fail_reason = slave_params.fail_reason; - if (slave->valid_setup) { - int r = snd_pcm_mmap_data(slave, NULL); - assert(r >= 0); - } return err; } @@ -565,7 +555,7 @@ static void snd_pcm_rate_dump(snd_pcm_t *pcm, FILE *fp) snd_pcm_dump(rate->plug.slave, fp); } -struct snd_pcm_ops snd_pcm_rate_ops = { +snd_pcm_ops_t snd_pcm_rate_ops = { close: snd_pcm_rate_close, info: snd_pcm_plugin_info, params_info: snd_pcm_rate_params_info, @@ -577,20 +567,15 @@ struct snd_pcm_ops snd_pcm_rate_ops = { dump: snd_pcm_rate_dump, nonblock: snd_pcm_plugin_nonblock, async: snd_pcm_plugin_async, - mmap_status: snd_pcm_plugin_mmap_status, - mmap_control: snd_pcm_plugin_mmap_control, - mmap_data: snd_pcm_plugin_mmap_data, - munmap_status: snd_pcm_plugin_munmap_status, - munmap_control: snd_pcm_plugin_munmap_control, - munmap_data: snd_pcm_plugin_munmap_data, + mmap: snd_pcm_plugin_mmap, + munmap: snd_pcm_plugin_munmap, }; -int snd_pcm_rate_open(snd_pcm_t **handlep, char *name, int sformat, int srate, snd_pcm_t *slave, int close_slave) +int snd_pcm_rate_open(snd_pcm_t **pcmp, char *name, int sformat, int srate, snd_pcm_t *slave, int close_slave) { - snd_pcm_t *handle; + snd_pcm_t *pcm; snd_pcm_rate_t *rate; - int err; - assert(handlep && slave); + assert(pcmp && slave); if (sformat >= 0 && snd_pcm_format_linear(sformat) != 1) return -EINVAL; rate = calloc(1, sizeof(snd_pcm_rate_t)); @@ -606,27 +591,25 @@ int snd_pcm_rate_open(snd_pcm_t **handlep, char *name, int sformat, int srate, s rate->plug.slave = slave; rate->plug.close_slave = close_slave; - handle = calloc(1, sizeof(snd_pcm_t)); - if (!handle) { + pcm = calloc(1, sizeof(snd_pcm_t)); + if (!pcm) { free(rate); return -ENOMEM; } if (name) - handle->name = strdup(name); - handle->type = SND_PCM_TYPE_RATE; - handle->stream = slave->stream; - handle->ops = &snd_pcm_rate_ops; - handle->op_arg = handle; - handle->fast_ops = &snd_pcm_plugin_fast_ops; - handle->fast_op_arg = handle; - handle->mode = slave->mode; - handle->private = rate; - err = snd_pcm_init(handle); - if (err < 0) { - snd_pcm_close(handle); - return err; - } - *handlep = handle; + pcm->name = strdup(name); + pcm->type = SND_PCM_TYPE_RATE; + pcm->stream = slave->stream; + pcm->mode = slave->mode; + pcm->ops = &snd_pcm_rate_ops; + pcm->op_arg = pcm; + pcm->fast_ops = &snd_pcm_plugin_fast_ops; + pcm->fast_op_arg = pcm; + pcm->private = rate; + pcm->poll_fd = slave->poll_fd; + pcm->hw_ptr = &rate->plug.hw_ptr; + pcm->appl_ptr = &rate->plug.appl_ptr; + *pcmp = pcm; return 0; } diff --git a/src/pcm/pcm_route.c b/src/pcm/pcm_route.c index 347d83e0..c51be601 100644 --- a/src/pcm/pcm_route.c +++ b/src/pcm/pcm_route.c @@ -484,11 +484,6 @@ static int snd_pcm_route_params(snd_pcm_t *pcm, snd_pcm_params_t * params) params->fail_reason = SND_PCM_PARAMS_FAIL_INVAL; return -EINVAL; } - if (slave->mmap_data) { - err = snd_pcm_munmap_data(slave); - if (err < 0) - return err; - } route->cformat = params->format.sfmt; route->cchannels = params->format.channels; route->cxfer_mode = params->xfer_mode; @@ -504,10 +499,6 @@ static int snd_pcm_route_params(snd_pcm_t *pcm, snd_pcm_params_t * params) params->format.channels = route->cchannels; params->xfer_mode = route->cxfer_mode; params->mmap_shape = route->cmmap_shape; - if (slave->valid_setup) { - int r = snd_pcm_mmap_data(slave, NULL); - assert(r >= 0); - } return err; } @@ -599,12 +590,14 @@ static int snd_pcm_route_channel_setup(snd_pcm_t *pcm, snd_pcm_channel_setup_t * if (err < 0) return err; #endif + if (!pcm->mmap_info) + return 0; if (pcm->setup.mmap_shape == SND_PCM_MMAP_INTERLEAVED) { - setup->running_area.addr = pcm->mmap_data; + setup->running_area.addr = pcm->mmap_info->addr; setup->running_area.first = setup->channel * pcm->bits_per_sample; setup->running_area.step = pcm->bits_per_frame; } else { - setup->running_area.addr = pcm->mmap_data + setup->channel * pcm->setup.buffer_size * pcm->bits_per_sample / 8; + setup->running_area.addr = pcm->mmap_info->addr + setup->channel * pcm->setup.buffer_size * pcm->bits_per_sample / 8; setup->running_area.first = 0; setup->running_area.step = pcm->bits_per_sample; } @@ -684,7 +677,7 @@ static void snd_pcm_route_dump(snd_pcm_t *pcm, FILE *fp) snd_pcm_dump(route->plug.slave, fp); } -struct snd_pcm_ops snd_pcm_route_ops = { +snd_pcm_ops_t snd_pcm_route_ops = { close: snd_pcm_route_close, info: snd_pcm_plugin_info, params_info: snd_pcm_route_params_info, @@ -696,12 +689,8 @@ struct snd_pcm_ops snd_pcm_route_ops = { dump: snd_pcm_route_dump, nonblock: snd_pcm_plugin_nonblock, async: snd_pcm_plugin_async, - mmap_status: snd_pcm_plugin_mmap_status, - mmap_control: snd_pcm_plugin_mmap_control, - mmap_data: snd_pcm_plugin_mmap_data, - munmap_status: snd_pcm_plugin_munmap_status, - munmap_control: snd_pcm_plugin_munmap_control, - munmap_data: snd_pcm_plugin_munmap_data, + mmap: snd_pcm_plugin_mmap, + munmap: snd_pcm_plugin_munmap, }; int route_load_ttable(route_params_t *params, int stream, @@ -776,17 +765,17 @@ int route_load_ttable(route_params_t *params, int stream, } -int snd_pcm_route_open(snd_pcm_t **handlep, char *name, +int snd_pcm_route_open(snd_pcm_t **pcmp, char *name, int sformat, unsigned int schannels, ttable_entry_t *ttable, unsigned int tt_ssize, unsigned int tt_cused, unsigned int tt_sused, snd_pcm_t *slave, int close_slave) { - snd_pcm_t *handle; + snd_pcm_t *pcm; snd_pcm_route_t *route; int err; - assert(handlep && slave && ttable); + assert(pcmp && slave && ttable); if (sformat >= 0 && snd_pcm_format_linear(sformat) != 1) return -EINVAL; route = calloc(1, sizeof(snd_pcm_route_t)); @@ -800,32 +789,30 @@ int snd_pcm_route_open(snd_pcm_t **handlep, char *name, route->plug.slave = slave; route->plug.close_slave = close_slave; - handle = calloc(1, sizeof(snd_pcm_t)); - if (!handle) { + pcm = calloc(1, sizeof(snd_pcm_t)); + if (!pcm) { free(route); return -ENOMEM; } if (name) - handle->name = strdup(name); - handle->type = SND_PCM_TYPE_ROUTE; - handle->stream = slave->stream; - handle->ops = &snd_pcm_route_ops; - handle->op_arg = handle; - handle->fast_ops = &snd_pcm_plugin_fast_ops; - handle->fast_op_arg = handle; - handle->mode = slave->mode; - handle->private = route; - err = snd_pcm_init(handle); - if (err < 0) { - snd_pcm_close(handle); - return err; - } - err = route_load_ttable(&route->params, handle->stream, tt_ssize, ttable, tt_cused, tt_sused); + pcm->name = strdup(name); + pcm->type = SND_PCM_TYPE_ROUTE; + pcm->stream = slave->stream; + pcm->mode = slave->mode; + pcm->ops = &snd_pcm_route_ops; + pcm->op_arg = pcm; + pcm->fast_ops = &snd_pcm_plugin_fast_ops; + pcm->fast_op_arg = pcm; + pcm->private = route; + pcm->poll_fd = slave->poll_fd; + pcm->hw_ptr = &route->plug.hw_ptr; + pcm->appl_ptr = &route->plug.appl_ptr; + err = route_load_ttable(&route->params, pcm->stream, tt_ssize, ttable, tt_cused, tt_sused); if (err < 0) { - snd_pcm_close(handle); + snd_pcm_close(pcm); return err; } - *handlep = handle; + *pcmp = pcm; return 0; } diff --git a/src/pcm/pcm_share.c b/src/pcm/pcm_share.c index 0b3e50f9..9876afa9 100644 --- a/src/pcm/pcm_share.c +++ b/src/pcm/pcm_share.c @@ -42,6 +42,7 @@ typedef struct { size_t channels_count; size_t open_count; size_t setup_count; + size_t mmap_count; size_t prepared_count; size_t running_count; size_t safety_threshold; @@ -61,8 +62,9 @@ typedef struct { pid_t async_pid; struct timeval trigger_time; size_t draining_silence; - snd_pcm_mmap_control_t mmap_control; - snd_pcm_mmap_status_t mmap_status; + int state; + size_t hw_ptr; + size_t appl_ptr; int ready; int client_socket; int slave_socket; @@ -79,7 +81,7 @@ static void snd_pcm_share_interrupt(snd_pcm_share_slave_t *slave) snd_pcm_share_t *share = list_entry(i, snd_pcm_share_t, list); snd_pcm_t *pcm = share->pcm; int ready; - switch (share->mmap_status.state) { + switch (share->state) { case SND_PCM_STATE_DRAINING: if (pcm->stream == SND_PCM_STREAM_CAPTURE) ready = 1; @@ -146,7 +148,7 @@ static void snd_pcm_share_stop(snd_pcm_t *pcm, int state) { snd_pcm_share_t *share = pcm->private; snd_pcm_share_slave_t *slave = share->slave; - share->mmap_status.state = state; + share->state = state; gettimeofday(&share->trigger_time, 0); slave->prepared_count--; slave->running_count--; @@ -160,8 +162,8 @@ static void snd_pcm_share_stop(snd_pcm_t *pcm, int state) pcm->setup.format.channels, pcm->setup.buffer_size, pcm->setup.format.sfmt); } - share->mmap_status.hw_ptr = slave->pcm->mmap_status->hw_ptr; - pcm->mmap_status = &share->mmap_status; + share->hw_ptr = *slave->pcm->hw_ptr; + pcm->hw_ptr = &share->hw_ptr; } /* Warning: take the mutex before to call this */ @@ -182,11 +184,11 @@ static void snd_pcm_share_slave_forward(snd_pcm_share_slave_t *slave) buffer_size = slave->pcm->setup.buffer_size; min_frames = buffer_size; max_frames = 0; - slave_appl_ptr = slave->pcm->mmap_control->appl_ptr; + slave_appl_ptr = *slave->pcm->appl_ptr; for (i = slave->clients.next; i != &slave->clients; i = i->next) { snd_pcm_share_t *share = list_entry(i, snd_pcm_share_t, list); snd_pcm_t *pcm = share->pcm; - switch (share->mmap_status.state) { + switch (share->state) { case SND_PCM_STATE_RUNNING: break; case SND_PCM_STATE_DRAINING: @@ -220,7 +222,7 @@ static void snd_pcm_share_slave_forward(snd_pcm_share_slave_t *slave) default: continue; } - frames = share->mmap_control.appl_ptr - slave_appl_ptr; + frames = share->appl_ptr - slave_appl_ptr; if (frames > (ssize_t)buffer_size) frames -= pcm->setup.boundary; else if (frames < -(ssize_t)pcm->setup.buffer_size) @@ -262,7 +264,7 @@ static int snd_pcm_share_close(snd_pcm_t *pcm) snd_pcm_share_t *share = pcm->private; snd_pcm_share_slave_t *slave = share->slave; int err = 0; - if (share->mmap_status.state == SND_PCM_STATE_RUNNING) { + if (share->state == SND_PCM_STATE_RUNNING) { if (pcm->mode & SND_PCM_NONBLOCK) snd_pcm_drop(pcm); else @@ -276,11 +278,14 @@ static int snd_pcm_share_close(snd_pcm_t *pcm) pthread_kill(slave->thread, SIGTERM); err = snd_pcm_close(slave->pcm); list_del(&slave->list); + pthread_mutex_unlock(&slave->mutex); pthread_mutex_destroy(&slave->mutex); free(slave); + list_del(&share->list); + } else { + list_del(&share->list); + pthread_mutex_unlock(&slave->mutex); } - list_del(&share->list); - pthread_mutex_unlock(&slave->mutex); close(share->client_socket); close(share->slave_socket); free(share->slave_channels); @@ -358,6 +363,64 @@ static int snd_pcm_share_params_info(snd_pcm_t *pcm, snd_pcm_params_info_t *info return err; } +static int snd_pcm_share_mmap(snd_pcm_t *pcm) +{ + snd_pcm_share_t *share = pcm->private; + snd_pcm_share_slave_t *slave = share->slave; + snd_pcm_mmap_info_t *i; + int err; + pthread_mutex_lock(&slave->mutex); + if (slave->mmap_count == 0) { + err = snd_pcm_mmap(slave->pcm); + if (err < 0) { + pthread_mutex_unlock(&slave->mutex); + return err; + } + if (slave->pcm->stream == SND_PCM_STREAM_PLAYBACK) + snd_pcm_areas_silence(slave->pcm->running_areas, 0, slave->pcm->setup.format.channels, slave->pcm->setup.buffer_size, slave->pcm->setup.format.sfmt); + slave->mmap_count++; + } + pthread_mutex_unlock(&slave->mutex); + pcm->mmap_info_count = slave->pcm->mmap_info_count + 1; + pcm->mmap_info = malloc(pcm->mmap_info_count * sizeof(*pcm->mmap_info)); + if (!pcm->mmap_info) + return -ENOMEM; + memcpy(pcm->mmap_info, slave->pcm->mmap_info, slave->pcm->mmap_info_count * sizeof(*pcm->mmap_info)); + i = &pcm->mmap_info[slave->pcm->mmap_info_count]; + i->type = SND_PCM_MMAP_USER; + i->size = snd_pcm_frames_to_bytes(pcm, pcm->setup.buffer_size); + share->stopped_data = malloc(i->size); + if (share->stopped_data == 0) { + free(pcm->mmap_info); + pcm->mmap_info = 0; + return -ENOMEM; + } + i->addr = share->stopped_data; + return 0; +} + +static int snd_pcm_share_munmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED) +{ + snd_pcm_share_t *share = pcm->private; + snd_pcm_share_slave_t *slave = share->slave; + int err; + pthread_mutex_lock(&slave->mutex); + slave->mmap_count--; + if (slave->mmap_count == 0) { + err = snd_pcm_munmap(slave->pcm); + if (err < 0) { + pthread_mutex_unlock(&slave->mutex); + return err; + } + } + pthread_mutex_unlock(&slave->mutex); + free(pcm->mmap_info); + pcm->mmap_info_count = 0; + pcm->mmap_info = 0; + free(share->stopped_data); + return 0; +} + static int snd_pcm_share_params(snd_pcm_t *pcm, snd_pcm_params_t *params) { snd_pcm_share_t *share = pcm->private; @@ -367,7 +430,7 @@ static int snd_pcm_share_params(snd_pcm_t *pcm, snd_pcm_params_t *params) if (channels != share->channels_count) { params->fail_mask = SND_PCM_PARAMS_CHANNELS; params->fail_reason = SND_PCM_PARAMS_FAIL_INVAL; - ERR("channels requested (%d) differs from configuration (%d)", channels, share->channels_count); + ERR("channels requested (%d) differs from configuration (%ld)", channels, (long)share->channels_count); return -EINVAL; } share->xfer_mode = params->xfer_mode; @@ -387,22 +450,14 @@ static int snd_pcm_share_params(snd_pcm_t *pcm, snd_pcm_params_t *params) } } else { snd_pcm_params_t sp = *params; - if (slave->pcm->mmap_data) { - err = snd_pcm_munmap_data(slave->pcm); - if (err < 0) - goto _end; - } sp.xfer_mode = SND_PCM_XFER_UNSPECIFIED; sp.xrun_mode = SND_PCM_XRUN_NONE; sp.format.channels = slave->channels_count; err = snd_pcm_params(slave->pcm, &sp); - snd_pcm_mmap_data(slave->pcm, NULL); if (err < 0) goto _end; - if (slave->pcm->stream == SND_PCM_STREAM_PLAYBACK) - snd_pcm_areas_silence(slave->pcm->running_areas, 0, slave->pcm->setup.format.channels, slave->pcm->setup.buffer_size, slave->pcm->setup.format.sfmt); } - share->mmap_status.state = SND_PCM_STATE_SETUP; + share->state = SND_PCM_STATE_SETUP; slave->setup_count++; _end: pthread_mutex_unlock(&slave->mutex); @@ -437,13 +492,13 @@ static int snd_pcm_share_status(snd_pcm_t *pcm, snd_pcm_status_t *status) pthread_mutex_lock(&slave->mutex); if (pcm->stream == SND_PCM_STREAM_PLAYBACK) { status->avail = snd_pcm_mmap_playback_avail(pcm); - if (share->mmap_status.state != SND_PCM_STATE_RUNNING && - share->mmap_status.state != SND_PCM_STATE_DRAINING) + if (share->state != SND_PCM_STATE_RUNNING && + share->state != SND_PCM_STATE_DRAINING) goto _notrunning; d = pcm->setup.buffer_size - status->avail; } else { status->avail = snd_pcm_mmap_capture_avail(pcm); - if (share->mmap_status.state != SND_PCM_STATE_RUNNING) + if (share->state != SND_PCM_STATE_RUNNING) goto _notrunning; d = status->avail; } @@ -452,7 +507,7 @@ static int snd_pcm_share_status(snd_pcm_t *pcm, snd_pcm_status_t *status) goto _end; _notrunning: status->delay = sd + d; - status->state = share->mmap_status.state; + status->state = share->state; status->trigger_time = share->trigger_time; _end: pthread_mutex_unlock(&slave->mutex); @@ -462,7 +517,7 @@ static int snd_pcm_share_status(snd_pcm_t *pcm, snd_pcm_status_t *status) static int snd_pcm_share_state(snd_pcm_t *pcm) { snd_pcm_share_t *share = pcm->private; - return share->mmap_status.state; + return share->state; } static int snd_pcm_share_delay(snd_pcm_t *pcm, ssize_t *delayp) @@ -472,7 +527,7 @@ static int snd_pcm_share_delay(snd_pcm_t *pcm, ssize_t *delayp) int err = 0; ssize_t sd; pthread_mutex_lock(&slave->mutex); - switch (share->mmap_status.state) { + switch (share->state) { case SND_PCM_STATE_XRUN: err = -EPIPE; goto _end; @@ -507,7 +562,7 @@ static ssize_t snd_pcm_share_avail_update(snd_pcm_t *pcm) for (i = slave->clients.next; i != &slave->clients; i = i->next) { snd_pcm_share_t *share = list_entry(i, snd_pcm_share_t, list); snd_pcm_t *pcm = share->pcm; - if (share->mmap_status.state == SND_PCM_STATE_RUNNING && + if (share->state == SND_PCM_STATE_RUNNING && pcm->setup.xrun_mode != SND_PCM_XRUN_NONE) snd_pcm_share_stop(pcm, SND_PCM_STATE_XRUN); } @@ -521,16 +576,16 @@ static ssize_t snd_pcm_share_avail_update(snd_pcm_t *pcm) return ret; } -static ssize_t snd_pcm_share_mmap_forward(snd_pcm_t *pcm, size_t size) +/* Call it with mutex held */ +static ssize_t _snd_pcm_share_mmap_forward(snd_pcm_t *pcm, size_t size) { snd_pcm_share_t *share = pcm->private; snd_pcm_share_slave_t *slave = share->slave; ssize_t ret = 0; ssize_t frames; - pthread_mutex_lock(&slave->mutex); if (pcm->stream == SND_PCM_STREAM_PLAYBACK && - share->mmap_status.state == SND_PCM_STATE_RUNNING) { - frames = slave->pcm->mmap_control->appl_ptr - share->mmap_control.appl_ptr; + share->state == SND_PCM_STATE_RUNNING) { + frames = *slave->pcm->appl_ptr - share->appl_ptr; if (frames > (ssize_t)pcm->setup.buffer_size) frames -= pcm->setup.boundary; else if (frames < -(ssize_t)pcm->setup.buffer_size) @@ -538,19 +593,27 @@ static ssize_t snd_pcm_share_mmap_forward(snd_pcm_t *pcm, size_t size) if (frames > 0) { /* Latecomer PCM */ ret = snd_pcm_rewind(slave->pcm, frames); - if (ret < 0) { - pthread_mutex_unlock(&slave->mutex); + if (ret < 0) return ret; - } size += ret; } } snd_pcm_mmap_appl_forward(pcm, size); snd_pcm_share_slave_forward(share->slave); - pthread_mutex_unlock(&slave->mutex); return size; } +static ssize_t snd_pcm_share_mmap_forward(snd_pcm_t *pcm, size_t size) +{ + snd_pcm_share_t *share = pcm->private; + snd_pcm_share_slave_t *slave = share->slave; + ssize_t ret; + pthread_mutex_lock(&slave->mutex); + ret = _snd_pcm_share_mmap_forward(pcm, size); + pthread_mutex_unlock(&slave->mutex); + return ret; +} + static int snd_pcm_share_prepare(snd_pcm_t *pcm) { snd_pcm_share_t *share = pcm->private; @@ -563,9 +626,9 @@ static int snd_pcm_share_prepare(snd_pcm_t *pcm) goto _end; } slave->prepared_count++; - share->mmap_status.hw_ptr = 0; - share->mmap_control.appl_ptr = 0; - share->mmap_status.state = SND_PCM_STATE_PREPARED; + share->hw_ptr = 0; + share->appl_ptr = 0; + share->state = SND_PCM_STATE_PREPARED; _end: pthread_mutex_unlock(&slave->mutex); return err; @@ -576,10 +639,10 @@ static int snd_pcm_share_start(snd_pcm_t *pcm) snd_pcm_share_t *share = pcm->private; snd_pcm_share_slave_t *slave = share->slave; int err = 0; - if (share->mmap_status.state != SND_PCM_STATE_PREPARED) + if (share->state != SND_PCM_STATE_PREPARED) return -EBADFD; pthread_mutex_lock(&slave->mutex); - share->mmap_status.state = SND_PCM_STATE_RUNNING; + share->state = SND_PCM_STATE_RUNNING; if (pcm->stream == SND_PCM_STREAM_PLAYBACK) { size_t hw_avail = snd_pcm_mmap_playback_hw_avail(pcm); if (hw_avail == 0) { @@ -595,15 +658,15 @@ static int snd_pcm_share_start(snd_pcm_t *pcm) if (err < 0) goto _end; } - assert(share->mmap_status.hw_ptr == 0); - /* Use the same mmap_status of slave */ - pcm->mmap_status = slave->pcm->mmap_status; - share->mmap_control.appl_ptr = slave->pcm->mmap_control->appl_ptr; + assert(share->hw_ptr == 0); + /* Share the same hw_ptr of slave */ + pcm->hw_ptr = slave->pcm->hw_ptr; + share->appl_ptr = *slave->pcm->appl_ptr; snd_pcm_areas_copy(pcm->stopped_areas, 0, pcm->running_areas, snd_pcm_mmap_offset(pcm), pcm->setup.format.channels, hw_avail, pcm->setup.format.sfmt); - snd_pcm_mmap_forward(pcm, pcm->setup.buffer_size); + _snd_pcm_share_mmap_forward(pcm, pcm->setup.buffer_size); } if (slave->running_count == 0) { err = snd_pcm_start(slave->pcm); @@ -623,7 +686,7 @@ static int snd_pcm_share_drop(snd_pcm_t *pcm) snd_pcm_share_slave_t *slave = share->slave; int err = 0; pthread_mutex_lock(&slave->mutex); - switch (share->mmap_status.state) { + switch (share->state) { case SND_PCM_STATE_OPEN: err = -EBADFD; goto _end; @@ -631,7 +694,7 @@ static int snd_pcm_share_drop(snd_pcm_t *pcm) goto _end; case SND_PCM_STATE_DRAINING: if (pcm->stream == SND_PCM_STREAM_CAPTURE) { - share->mmap_status.state = SND_PCM_STATE_SETUP; + share->state = SND_PCM_STATE_SETUP; break; } /* Fall through */ @@ -640,7 +703,7 @@ static int snd_pcm_share_drop(snd_pcm_t *pcm) break; case SND_PCM_STATE_PREPARED: case SND_PCM_STATE_XRUN: - share->mmap_status.state = SND_PCM_STATE_SETUP; + share->state = SND_PCM_STATE_SETUP; break; } @@ -659,7 +722,7 @@ static int snd_pcm_share_drop(snd_pcm_t *pcm) pcm->setup.buffer_size, pcm->setup.format.sfmt); snd_pcm_mmap_forward(pcm, pcm->setup.buffer_size); } - share->mmap_control.appl_ptr = share->mmap_status.hw_ptr = 0; + share->appl_ptr = share->hw_ptr = 0; _end: pthread_mutex_unlock(&slave->mutex); return err; @@ -671,29 +734,29 @@ static int snd_pcm_share_drain(snd_pcm_t *pcm) snd_pcm_share_slave_t *slave = share->slave; int err = 0; pthread_mutex_lock(&slave->mutex); - switch (share->mmap_status.state) { + switch (share->state) { case SND_PCM_STATE_OPEN: err = -EBADFD; goto _end; case SND_PCM_STATE_PREPARED: - share->mmap_status.state = SND_PCM_STATE_SETUP; + share->state = SND_PCM_STATE_SETUP; break; case SND_PCM_STATE_SETUP: case SND_PCM_STATE_DRAINING: goto _end; case SND_PCM_STATE_XRUN: if (pcm->stream == SND_PCM_STREAM_PLAYBACK) { - share->mmap_status.state = SND_PCM_STATE_SETUP; + share->state = SND_PCM_STATE_SETUP; break; } /* Fall through */ case SND_PCM_STATE_RUNNING: if (snd_pcm_mmap_avail(pcm) <= 0) { - share->mmap_status.state = SND_PCM_STATE_SETUP; + share->state = SND_PCM_STATE_SETUP; break; } share->draining_silence = 0; - share->mmap_status.state = SND_PCM_STATE_DRAINING; + share->state = SND_PCM_STATE_DRAINING; break; } _end: @@ -742,7 +805,26 @@ static int snd_pcm_share_channel_setup(snd_pcm_t *pcm, snd_pcm_channel_setup_t * setup->channel = c; err = snd_pcm_channel_setup(slave->pcm, setup); setup->channel = channel; - return err; + if (err < 0) + return err; + if (!pcm->mmap_info) + return 0; + switch (pcm->setup.mmap_shape) { + case SND_PCM_MMAP_INTERLEAVED: + case SND_PCM_MMAP_COMPLEX: + setup->stopped_area.addr = share->stopped_data; + setup->stopped_area.first = channel * pcm->bits_per_sample; + setup->stopped_area.step = pcm->bits_per_frame; + break; + case SND_PCM_MMAP_NONINTERLEAVED: + setup->stopped_area.addr = share->stopped_data + c * pcm->setup.buffer_size * pcm->bits_per_sample / 8; + setup->stopped_area.first = 0; + setup->stopped_area.step = pcm->bits_per_sample; + break; + default: + assert(0); + } + return 0; } static ssize_t snd_pcm_share_rewind(snd_pcm_t *pcm, size_t frames) @@ -751,7 +833,7 @@ static ssize_t snd_pcm_share_rewind(snd_pcm_t *pcm, size_t frames) snd_pcm_share_slave_t *slave = share->slave; int ret = -EBADFD; ssize_t n; - switch (share->mmap_status.state) { + switch (share->state) { case SND_PCM_STATE_RUNNING: break; case SND_PCM_STATE_PREPARED: @@ -774,7 +856,7 @@ static ssize_t snd_pcm_share_rewind(snd_pcm_t *pcm, size_t frames) n = frames; frames -= n; } - if (share->mmap_status.state == SND_PCM_STATE_RUNNING && + if (share->state == SND_PCM_STATE_RUNNING && frames > 0) { pthread_mutex_lock(&slave->mutex); ret = snd_pcm_rewind(slave->pcm, frames); @@ -793,43 +875,6 @@ static ssize_t snd_pcm_share_rewind(snd_pcm_t *pcm, size_t frames) return ret; } -static int snd_pcm_share_mmap_status(snd_pcm_t *pcm) -{ - snd_pcm_share_t *share = pcm->private; - pcm->mmap_status = &share->mmap_status; - return 0; -} - -static int snd_pcm_share_mmap_control(snd_pcm_t *pcm) -{ - snd_pcm_share_t *share = pcm->private; - pcm->mmap_control = &share->mmap_control; - return 0; -} - -static int snd_pcm_share_mmap_data(snd_pcm_t *pcm) -{ - snd_pcm_share_t *share = pcm->private; - snd_pcm_share_slave_t *slave = share->slave; - pcm->mmap_data = slave->pcm->mmap_data; - return 0; -} - -static int snd_pcm_share_munmap_status(snd_pcm_t *pcm ATTRIBUTE_UNUSED) -{ - return 0; -} - -static int snd_pcm_share_munmap_control(snd_pcm_t *pcm ATTRIBUTE_UNUSED) -{ - return 0; -} - -static int snd_pcm_share_munmap_data(snd_pcm_t *pcm ATTRIBUTE_UNUSED) -{ - return 0; -} - static int snd_pcm_share_channels_mask(snd_pcm_t *pcm, bitset_t *cmask) { snd_pcm_share_t *share = pcm->private; @@ -869,7 +914,7 @@ static void snd_pcm_share_dump(snd_pcm_t *pcm, FILE *fp) snd_pcm_dump(slave->pcm, fp); } -struct snd_pcm_ops snd_pcm_share_ops = { +snd_pcm_ops_t snd_pcm_share_ops = { close: snd_pcm_share_close, info: snd_pcm_share_info, params_info: snd_pcm_share_params_info, @@ -881,15 +926,11 @@ struct snd_pcm_ops snd_pcm_share_ops = { dump: snd_pcm_share_dump, nonblock: snd_pcm_share_nonblock, async: snd_pcm_share_async, - mmap_status: snd_pcm_share_mmap_status, - mmap_control: snd_pcm_share_mmap_control, - mmap_data: snd_pcm_share_mmap_data, - munmap_status: snd_pcm_share_munmap_status, - munmap_control: snd_pcm_share_munmap_control, - munmap_data: snd_pcm_share_munmap_data, + mmap: snd_pcm_share_mmap, + munmap: snd_pcm_share_munmap, }; -struct snd_pcm_fast_ops snd_pcm_share_fast_ops = { +snd_pcm_fast_ops_t snd_pcm_share_fast_ops = { status: snd_pcm_share_status, state: snd_pcm_share_state, delay: snd_pcm_share_delay, @@ -903,18 +944,17 @@ struct snd_pcm_fast_ops snd_pcm_share_fast_ops = { readi: snd_pcm_mmap_readi, readn: snd_pcm_mmap_readn, rewind: snd_pcm_share_rewind, - poll_descriptor: snd_pcm_share_poll_descriptor, channels_mask: snd_pcm_share_channels_mask, avail_update: snd_pcm_share_avail_update, mmap_forward: snd_pcm_share_mmap_forward, }; -int snd_pcm_share_open(snd_pcm_t **handlep, char *name, char *sname, +int snd_pcm_share_open(snd_pcm_t **pcmp, char *name, char *sname, size_t schannels_count, size_t channels_count, int *channels_map, int stream, int mode) { - snd_pcm_t *handle; + snd_pcm_t *pcm; snd_pcm_share_t *share; int err; struct list_head *i; @@ -923,7 +963,7 @@ int snd_pcm_share_open(snd_pcm_t **handlep, char *name, char *sname, snd_pcm_share_slave_t *slave = NULL; int sd[2]; - assert(handlep); + assert(pcmp); assert(channels_count > 0 && sname && channels_map); for (k = 0; k < channels_count; ++k) { @@ -951,8 +991,8 @@ int snd_pcm_share_open(snd_pcm_t **handlep, char *name, char *sname, } memcpy(share->slave_channels, channels_map, channels_count * sizeof(*share->slave_channels)); - handle = calloc(1, sizeof(snd_pcm_t)); - if (!handle) { + pcm = calloc(1, sizeof(snd_pcm_t)); + if (!pcm) { free(share->slave_channels); free(share); return -ENOMEM; @@ -976,7 +1016,7 @@ int snd_pcm_share_open(snd_pcm_t **handlep, char *name, char *sname, } if (err < 0) { err = -errno; - free(handle); + free(pcm); free(share->slave_channels); free(share); return err; @@ -997,7 +1037,7 @@ int snd_pcm_share_open(snd_pcm_t **handlep, char *name, char *sname, pthread_mutex_unlock(&slaves_mutex); close(sd[0]); close(sd[1]); - free(handle); + free(pcm); free(share->slave_channels); free(share); return err; @@ -1008,7 +1048,7 @@ int snd_pcm_share_open(snd_pcm_t **handlep, char *name, char *sname, snd_pcm_close(spcm); close(sd[0]); close(sd[1]); - free(handle); + free(pcm); free(share->slave_channels); free(share); return err; @@ -1031,28 +1071,27 @@ int snd_pcm_share_open(snd_pcm_t **handlep, char *name, char *sname, pthread_mutex_unlock(&slave->mutex); share->slave = slave; - share->pcm = handle; + share->pcm = pcm; share->client_socket = sd[0]; share->slave_socket = sd[1]; share->async_sig = SIGIO; share->async_pid = getpid(); if (name) - handle->name = strdup(name); - handle->type = SND_PCM_TYPE_SHARE; - handle->stream = stream; - handle->mode = mode; - handle->ops = &snd_pcm_share_ops; - handle->op_arg = handle; - handle->fast_ops = &snd_pcm_share_fast_ops; - handle->fast_op_arg = handle; - handle->private = share; - err = snd_pcm_init(handle); - if (err < 0) { - snd_pcm_close(handle); - return err; - } - *handlep = handle; + pcm->name = strdup(name); + pcm->type = SND_PCM_TYPE_SHARE; + pcm->stream = stream; + pcm->mode = mode; + pcm->mmap_auto = 1; + pcm->ops = &snd_pcm_share_ops; + pcm->op_arg = pcm; + pcm->fast_ops = &snd_pcm_share_fast_ops; + pcm->fast_op_arg = pcm; + pcm->private = share; + pcm->poll_fd = share->client_socket; + pcm->hw_ptr = &share->hw_ptr; + pcm->appl_ptr = &share->appl_ptr; + *pcmp = pcm; return 0; } @@ -1104,11 +1143,11 @@ int _snd_pcm_share_open(snd_pcm_t **pcmp, char *name, snd_config_t *conf, return -EINVAL; } if (!sname) { - ERR("Missing sname"); + ERR("sname is not defined"); return -EINVAL; } if (!binding) { - ERR("Missing binding"); + ERR("binding is not defined"); return -EINVAL; } snd_config_foreach(i, binding) { -- 2.47.1