-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)
#include <stddef.h>
#include <getopt.h>
#include <netinet/in.h>
+#include <netdb.h>
#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)
{
sock = socket(PF_LOCAL, SOCK_STREAM, 0);
if (sock < 0) {
int result = -errno;
- perrno("socket");
+ SYSERR("socket");
return result;
}
if (bind(sock, (struct sockaddr *) addr, size) < 0) {
int result = -errno;
- perrno("bind");
+ SYSERR("bind");
return result;
}
sock = socket(PF_INET, SOCK_STREAM, 0);
if (sock < 0) {
int result = -errno;
- perrno("socket");
+ SYSERR("socket");
return result;
}
if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
int result = -errno;
- perrno("bind");
+ SYSERR("bind");
return result;
}
ret = sendmsg(socket, &msghdr, 0 );
if (ret < 0) {
- perrno("sendmsg");
+ SYSERR("sendmsg");
return -errno;
}
return ret;
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 {
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];
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)
{
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;
}
}
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;
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;
if (!client->transport.shm.ctrl) {
result = -errno;
shmctl(shmid, IPC_RMID, 0);
- perrno("shmat");
+ SYSERR("shmat");
goto _err;
}
*cookie = shmid;
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;
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 = {
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;
}
}
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;
if (!client->transport.shm.ctrl) {
result = -errno;
shmctl(shmid, IPC_RMID, 0);
- perrno("shmat");
+ SYSERR("shmat");
goto _err;
}
*cookie = shmid;
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;
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;
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 = {
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)) {
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) {
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:
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;
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;
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;
}
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);
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) {
err = poll(pollfds, pollfds_count, 1000);
} while (err == 0);
if (err < 0) {
- perrno("poll");
+ SYSERR("poll");
continue;
}
continue;
err = w->handler(w, pfd->revents);
if (err < 0)
- perrno("handler");
+ SYSERR("handler");
}
}
}
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;
}
*/
+#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;
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;
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;
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;
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 */
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);
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,
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);
/* 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);
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
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);
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);
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);
#include <errno.h>
#include <fcntl.h>
#include <assert.h>
+#include <dlfcn.h>
#include "asoundlib.h"
#include "control_local.h"
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);
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);
}
+++ /dev/null
-/*
- * Control - Client
- * Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>
- *
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Library General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stddef.h>
-#include <unistd.h>
-#include <string.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <sys/shm.h>
-#include <sys/socket.h>
-#include <sys/poll.h>
-#include <sys/un.h>
-#include <sys/uio.h>
-#include <sys/mman.h>
-#include <netinet/in.h>
-#include <netdb.h>
-#include "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;
-}
-
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];
}
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);
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);
+}
+
struct snd_ctl {
+ char *name;
snd_ctl_type_t type;
struct snd_ctl_ops *ops;
void *private;
--- /dev/null
+/*
+ * Control - SHM Client
+ * Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>
+ *
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/shm.h>
+#include <sys/socket.h>
+#include <sys/poll.h>
+#include <sys/un.h>
+#include <sys/uio.h>
+#include <sys/mman.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include "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);
+}
+
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
#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);
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)
{
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)
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);
}
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);
}
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);
}
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);
}
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)
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);
}
{
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;
}
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);
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;
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;
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;
}
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,
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;
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;
}
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;
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;
}
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,
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;
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;
}
+++ /dev/null
-/*
- * PCM - Client
- * Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>
- *
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Library General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stddef.h>
-#include <unistd.h>
-#include <string.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <sys/shm.h>
-#include <sys/socket.h>
-#include <sys/poll.h>
-#include <sys/un.h>
-#include <sys/mman.h>
-#include <netinet/in.h>
-#include <netdb.h>
-#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);
- }
-}
-
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)
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;
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,
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,
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)
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;
}
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;
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;
}
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;
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)
ERR("status mmap failed");
return -errno;
}
- pcm->mmap_status = ptr;
+ hw->mmap_status = ptr;
+ pcm->hw_ptr = &hw->mmap_status->hw_ptr;
return 0;
}
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;
}
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;
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 ||
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;
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)
{
}
}
-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,
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,
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;
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) {
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);
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;
}
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;
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;
}
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,
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));
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;
}
#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);
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);
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);
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;
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;
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;
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;
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;
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;
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
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,
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;
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));
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;
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;
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;
}
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,
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;
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;
}
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;
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) {
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;
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;
}
}
-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,
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,
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));
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));
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];
}
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;
}
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;
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;
{
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 ||
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;
}
}
k++;
}
+ plug->slave->mmap_auto = 0;
assert(0);
return 0;
}
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)
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)
{
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,
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;
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
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;
}
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)
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);
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;
}
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,
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,
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);
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);
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))
#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);
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
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;
}
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,
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));
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;
}
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;
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;
}
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;
}
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,
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,
}
-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));
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;
}
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;
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;
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;
{
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--;
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 */
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:
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)
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
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);
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;
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;
}
} 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);
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;
}
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);
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)
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;
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);
}
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)
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;
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;
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) {
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);
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;
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 */
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;
}
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;
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:
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)
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:
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);
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;
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,
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,
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;
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) {
}
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;
}
if (err < 0) {
err = -errno;
- free(handle);
+ free(pcm);
free(share->slave_channels);
free(share);
return err;
pthread_mutex_unlock(&slaves_mutex);
close(sd[0]);
close(sd[1]);
- free(handle);
+ free(pcm);
free(share->slave_channels);
free(share);
return err;
snd_pcm_close(spcm);
close(sd[0]);
close(sd[1]);
- free(handle);
+ free(pcm);
free(share->slave_channels);
free(share);
return err;
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;
}
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) {