Fixed mmap wrt shm. Renamed pcm_client, control_client to shm. More error messages. Implemented asoundrc as documented.

This commit is contained in:
Abramo Bagnara 2000-10-14 10:31:34 +00:00
parent dcc88ffaa7
commit e5e1ca14d4
30 changed files with 1642 additions and 2555 deletions

1
TODO
View file

@ -1,3 +1,2 @@
H solve multi/server mmap'ing problem
M add abstraction layer to timer, rawmidi, hwdep, seq
L move OSS emulation to user space? (pseudo device driver and daemon)

View file

@ -31,29 +31,29 @@
#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)
{
@ -65,7 +65,7 @@ int make_local_socket(const char *filename)
sock = socket(PF_LOCAL, SOCK_STREAM, 0);
if (sock < 0) {
int result = -errno;
perrno("socket");
SYSERR("socket");
return result;
}
@ -76,7 +76,7 @@ int make_local_socket(const char *filename)
if (bind(sock, (struct sockaddr *) addr, size) < 0) {
int result = -errno;
perrno("bind");
SYSERR("bind");
return result;
}
@ -91,7 +91,7 @@ int make_inet_socket(int port)
sock = socket(PF_INET, SOCK_STREAM, 0);
if (sock < 0) {
int result = -errno;
perrno("socket");
SYSERR("socket");
return result;
}
@ -101,7 +101,7 @@ int make_inet_socket(int port)
if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
int result = -errno;
perrno("bind");
SYSERR("bind");
return result;
}
@ -135,7 +135,7 @@ int send_fd(int socket, void *data, size_t len, int fd)
ret = sendmsg(socket, &msghdr, 0 );
if (ret < 0) {
perrno("sendmsg");
SYSERR("sendmsg");
return -errno;
}
return ret;
@ -182,13 +182,6 @@ void del_waiter(int fd)
memmove(&pollfds[k], &pollfds[k + 1], pollfds_count - k);
}
typedef struct {
struct list_head list;
int fd;
int local;
} master_t;
LIST_HEAD(masters);
typedef struct client client_t;
typedef struct {
@ -199,10 +192,9 @@ typedef struct {
struct client {
struct list_head list;
struct socket {
int fd;
int local;
} data, ctrl;
int poll_fd;
int ctrl_fd;
int local;
int transport_type;
int dev_type;
char name[256];
@ -250,9 +242,8 @@ typedef struct {
struct list_head list;
int fd;
uint32_t cookie;
int local;
} pending_t;
LIST_HEAD(pendings);
} inet_pending_t;
LIST_HEAD(inet_pendings);
int pcm_handler(waiter_t *waiter, unsigned short events)
{
@ -260,15 +251,15 @@ int pcm_handler(waiter_t *waiter, unsigned short events)
char buf[1];
ssize_t n;
if (events & POLLIN) {
n = write(client->data.fd, buf, 1);
n = write(client->poll_fd, buf, 1);
if (n != 1) {
perrno("write");
SYSERR("write");
return -errno;
}
} else if (events & POLLOUT) {
n = read(client->data.fd, buf, 1);
n = read(client->poll_fd, buf, 1);
if (n != 1) {
perrno("read");
SYSERR("read");
return -errno;
}
}
@ -283,7 +274,7 @@ int pcm_shm_open(client_t *client, int *cookie)
snd_pcm_t *pcm;
int err;
int result;
err = snd_pcm_open(&pcm, client->name, client->stream, client->mode);
err = snd_pcm_open(&pcm, client->name, client->stream, SND_PCM_NONBLOCK);
if (err < 0)
return err;
client->device.pcm.handle = pcm;
@ -292,7 +283,7 @@ int pcm_shm_open(client_t *client, int *cookie)
shmid = shmget(IPC_PRIVATE, PCM_SHM_SIZE, 0666);
if (shmid < 0) {
result = -errno;
perrno("shmget");
SYSERR("shmget");
goto _err;
}
client->transport.shm.ctrl_id = shmid;
@ -300,7 +291,7 @@ int pcm_shm_open(client_t *client, int *cookie)
if (!client->transport.shm.ctrl) {
result = -errno;
shmctl(shmid, IPC_RMID, 0);
perrno("shmat");
SYSERR("shmat");
goto _err;
}
*cookie = shmid;
@ -315,38 +306,66 @@ int pcm_shm_open(client_t *client, int *cookie)
int pcm_shm_close(client_t *client)
{
int err;
snd_pcm_client_shm_t *ctrl = client->transport.shm.ctrl;
snd_pcm_shm_ctrl_t *ctrl = client->transport.shm.ctrl;
if (client->polling) {
del_waiter(client->device.pcm.fd);
client->polling = 0;
}
/* FIXME: blocking */
err = snd_pcm_close(client->device.pcm.handle);
ctrl->result = err;
if (err < 0)
perrno("snd_pcm_close");
SYSERR("snd_pcm_close");
if (client->transport.shm.ctrl) {
err = shmdt((void *)client->transport.shm.ctrl);
if (err < 0)
perrno("shmdt");
SYSERR("shmdt");
err = shmctl(client->transport.shm.ctrl_id, IPC_RMID, 0);
if (err < 0)
perrno("shmctl");
SYSERR("shmctl");
client->transport.shm.ctrl = 0;
}
client->open = 0;
return 0;
}
int shm_ack(client_t *client)
{
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_client_shm_t *ctrl = client->transport.shm.ctrl;
struct pollfd pfd;
snd_pcm_shm_ctrl_t *ctrl = client->transport.shm.ctrl;
char buf[1];
int err;
int cmd;
snd_pcm_t *pcm;
err = read(client->ctrl.fd, buf, 1);
err = read(client->ctrl_fd, buf, 1);
if (err != 1)
return -EBADFD;
cmd = ctrl->cmd;
@ -409,63 +428,74 @@ int pcm_shm_cmd(client_t *client)
break;
case SND_PCM_IOCTL_LINK:
{
struct list_head *item;
list_for_each(item, &clients) {
client_t *client = list_entry(item, client_t, list);
if (!client->open)
continue;
if (client->data.fd == ctrl->u.link) {
ctrl->result = snd_pcm_link(pcm, client->device.pcm.handle);
break;
}
}
ctrl->result = -EBADFD;
/* FIXME */
ctrl->result = -ENOSYS;
break;
}
case SND_PCM_IOCTL_UNLINK:
ctrl->result = snd_pcm_unlink(pcm);
break;
case SND_PCM_IOCTL_MMAP_DATA:
case SND_PCM_IOCTL_MMAP_CONTROL:
case SND_PCM_IOCTL_MMAP_STATUS:
case SND_PCM_IOCTL_MMAP:
{
pfd.fd = client->ctrl.fd;
pfd.events = POLLHUP;
if (poll(&pfd, 1, 0) == 1)
return -EBADFD;
err = send_fd(client->ctrl.fd, buf, 1, client->device.pcm.fd);
if (err != 1)
return -EBADFD;
ctrl->result = 0;
return 0;
}
case SND_PCM_IOCTL_MUNMAP_DATA:
case SND_PCM_IOCTL_MUNMAP_CONTROL:
case SND_PCM_IOCTL_MUNMAP_STATUS:
ctrl->result = 0;
err = snd_pcm_mmap(pcm);
if (err < 0)
ctrl->result = err;
else
ctrl->result = pcm->mmap_info_count;
break;
}
case SND_PCM_IOCTL_MMAP_INFO:
{
snd_pcm_mmap_info_t *i;
unsigned int index = ctrl->u.mmap_info.index;
if (index >= pcm->mmap_info_count) {
ctrl->result = -EINVAL;
break;
}
i = &pcm->mmap_info[index];
if (i->type == SND_PCM_MMAP_USER) {
i->u.user.shmid = shmget(IPC_PRIVATE, i->size, 0666);
if (i->u.user.shmid < 0) {
SYSERR("shmget");
return -EINVAL;
}
}
ctrl->u.mmap_info = *i;
ctrl->u.mmap_info.index = index;
ctrl->result = 0;
if (i->type == SND_PCM_MMAP_USER)
break;
return shm_ack_fd(client, i->u.kernel.fd);
}
case SND_PCM_IOCTL_MUNMAP:
{
size_t k;
ctrl->result = snd_pcm_munmap(pcm);
if (ctrl->result < 0)
break;
for (k = 0; k < pcm->mmap_info_count; ++k) {
snd_pcm_mmap_info_t *i = &pcm->mmap_info[k];
if (i->type == SND_PCM_MMAP_USER) {
int err = shmdt(i->addr);
assert(err >= 0);
}
}
break;
}
case SND_PCM_IOCTL_MMAP_FORWARD:
ctrl->result = snd_pcm_mmap_forward(pcm, ctrl->u.mmap_forward);
break;
case SND_PCM_IOCTL_POLL_DESCRIPTOR:
ctrl->result = 0;
return shm_ack_fd(client, snd_pcm_poll_descriptor(pcm));
case SND_PCM_IOCTL_CLOSE:
client->ops->close(client);
break;
default:
fprintf(stderr, "Bogus cmd: %x\n", ctrl->cmd);
ERROR("Bogus cmd: %x", ctrl->cmd);
ctrl->result = -ENOSYS;
}
pfd.fd = client->ctrl.fd;
pfd.events = POLLHUP;
if (poll(&pfd, 1, 0) == 1)
return -EBADFD;
err = write(client->ctrl.fd, buf, 1);
if (err != 1)
return -EBADFD;
if (!client->polling) {
add_waiter(client->device.pcm.fd, POLLIN | POLLOUT, pcm_handler, client);
client->polling = 1;
}
return 0;
return shm_ack(client);
}
transport_ops_t pcm_shm_ops = {
@ -480,9 +510,9 @@ int ctl_handler(waiter_t *waiter, unsigned short events)
char buf[1];
ssize_t n;
if (events & POLLIN) {
n = write(client->data.fd, buf, 1);
n = write(client->poll_fd, buf, 1);
if (n != 1) {
perrno("write");
SYSERR("write");
return -errno;
}
}
@ -506,7 +536,7 @@ int ctl_shm_open(client_t *client, int *cookie)
shmid = shmget(IPC_PRIVATE, CTL_SHM_SIZE, 0666);
if (shmid < 0) {
result = -errno;
perrno("shmget");
SYSERR("shmget");
goto _err;
}
client->transport.shm.ctrl_id = shmid;
@ -514,7 +544,7 @@ int ctl_shm_open(client_t *client, int *cookie)
if (!client->transport.shm.ctrl) {
result = -errno;
shmctl(shmid, IPC_RMID, 0);
perrno("shmat");
SYSERR("shmat");
goto _err;
}
*cookie = shmid;
@ -531,23 +561,22 @@ int ctl_shm_open(client_t *client, int *cookie)
int ctl_shm_close(client_t *client)
{
int err;
snd_ctl_client_shm_t *ctrl = client->transport.shm.ctrl;
snd_ctl_shm_ctrl_t *ctrl = client->transport.shm.ctrl;
if (client->polling) {
del_waiter(client->device.control.fd);
client->polling = 0;
}
/* FIXME: blocking */
err = snd_ctl_close(client->device.control.handle);
ctrl->result = err;
if (err < 0)
perrno("snd_ctl_close");
SYSERR("snd_ctl_close");
if (client->transport.shm.ctrl) {
err = shmdt((void *)client->transport.shm.ctrl);
if (err < 0)
perrno("shmdt");
SYSERR("shmdt");
err = shmctl(client->transport.shm.ctrl_id, IPC_RMID, 0);
if (err < 0)
perrno("shmctl");
SYSERR("shmctl");
client->transport.shm.ctrl = 0;
}
client->open = 0;
@ -558,13 +587,12 @@ extern int snd_ctl_read1(snd_ctl_t *ctl, snd_ctl_event_t *event);
int ctl_shm_cmd(client_t *client)
{
snd_ctl_client_shm_t *ctrl = client->transport.shm.ctrl;
struct pollfd pfd;
snd_ctl_shm_ctrl_t *ctrl = client->transport.shm.ctrl;
char buf[1];
int err;
int cmd;
snd_ctl_t *ctl;
err = read(client->ctrl.fd, buf, 1);
err = read(client->ctrl_fd, buf, 1);
if (err != 1)
return -EBADFD;
cmd = ctrl->cmd;
@ -612,22 +640,14 @@ int ctl_shm_cmd(client_t *client)
case SND_CTL_IOCTL_CLOSE:
client->ops->close(client);
break;
case SND_PCM_IOCTL_POLL_DESCRIPTOR:
ctrl->result = 0;
return shm_ack_fd(client, snd_ctl_poll_descriptor(ctl));
default:
fprintf(stderr, "Bogus cmd: %x\n", ctrl->cmd);
ERROR("Bogus cmd: %x", ctrl->cmd);
ctrl->result = -ENOSYS;
}
pfd.fd = client->ctrl.fd;
pfd.events = POLLHUP;
if (poll(&pfd, 1, 0) == 1)
return -EBADFD;
err = write(client->ctrl.fd, buf, 1);
if (err != 1)
return -EBADFD;
if (!client->polling) {
add_waiter(client->device.control.fd, POLLIN, ctl_handler, client);
client->polling = 1;
}
return 0;
return shm_ack(client);
}
transport_ops_t ctl_shm_ops = {
@ -643,9 +663,9 @@ int snd_client_open(client_t *client)
snd_client_open_answer_t ans;
char *name;
memset(&ans, 0, sizeof(ans));
err = read(client->ctrl.fd, &req, sizeof(req));
err = read(client->ctrl_fd, &req, sizeof(req));
if (err < 0) {
perrno("read");
SYSERR("read");
exit(1);
}
if (err != sizeof(req)) {
@ -653,9 +673,9 @@ int snd_client_open(client_t *client)
goto _answer;
}
name = alloca(req.namelen);
err = read(client->ctrl.fd, name, req.namelen);
err = read(client->ctrl_fd, name, req.namelen);
if (err < 0) {
perrno("read");
SYSERR("read");
exit(1);
}
if (err != req.namelen) {
@ -663,20 +683,17 @@ int snd_client_open(client_t *client)
goto _answer;
}
switch (req.dev_type) {
case SND_DEV_TYPE_PCM:
switch (req.transport_type) {
case SND_TRANSPORT_TYPE_SHM:
client->ops = &pcm_shm_ops;
break;
default:
switch (req.transport_type) {
case SND_TRANSPORT_TYPE_SHM:
if (!client->local) {
ans.result = -EINVAL;
goto _answer;
}
break;
case SND_DEV_TYPE_CONTROL:
switch (req.transport_type) {
case SND_TRANSPORT_TYPE_SHM:
switch (req.dev_type) {
case SND_DEV_TYPE_PCM:
client->ops = &pcm_shm_ops;
break;
case SND_DEV_TYPE_CONTROL:
client->ops = &ctl_shm_ops;
break;
default:
@ -701,27 +718,27 @@ int snd_client_open(client_t *client)
ans.result = err;
} else {
client->open = 1;
ans.result = client->data.fd;
ans.result = 0;
}
_answer:
err = write(client->ctrl.fd, &ans, sizeof(ans));
err = write(client->ctrl_fd, &ans, sizeof(ans));
if (err != sizeof(ans)) {
perrno("write");
SYSERR("write");
exit(1);
}
return 0;
}
int client_data_handler(waiter_t *waiter, unsigned short events ATTRIBUTE_UNUSED)
int client_poll_handler(waiter_t *waiter, unsigned short events ATTRIBUTE_UNUSED)
{
client_t *client = waiter->private_data;
if (client->open)
client->ops->close(client);
close(client->data.fd);
close(client->ctrl.fd);
del_waiter(client->data.fd);
del_waiter(client->ctrl.fd);
close(client->poll_fd);
close(client->ctrl_fd);
del_waiter(client->poll_fd);
del_waiter(client->ctrl_fd);
list_del(&client->list);
free(client);
return 0;
@ -730,18 +747,25 @@ int client_data_handler(waiter_t *waiter, unsigned short events ATTRIBUTE_UNUSED
int client_ctrl_handler(waiter_t *waiter, unsigned short events)
{
client_t *client = waiter->private_data;
if (events & POLLHUP)
return client_data_handler(waiter, events);
if (events & POLLHUP) {
if (client->open)
client->ops->close(client);
close(client->ctrl_fd);
del_waiter(client->ctrl_fd);
list_del(&client->list);
free(client);
return 0;
}
if (client->open)
return client->ops->cmd(client);
else
return snd_client_open(client);
}
int pending_handler(waiter_t *waiter, unsigned short events)
int inet_pending_handler(waiter_t *waiter, unsigned short events)
{
pending_t *pending = waiter->private_data;
pending_t *pdata;
inet_pending_t *pending = waiter->private_data;
inet_pending_t *pdata;
client_t *client;
uint32_t cookie;
struct list_head *item;
@ -766,8 +790,8 @@ int pending_handler(waiter_t *waiter, unsigned short events)
return 0;
}
list_for_each(item, &pendings) {
pdata = list_entry(item, pending_t, list);
list_for_each(item, &inet_pendings) {
pdata = list_entry(item, inet_pending_t, list);
if (pdata->cookie == cookie)
goto found;
}
@ -775,13 +799,12 @@ int pending_handler(waiter_t *waiter, unsigned short events)
return 0;
found:
client = calloc(sizeof(*client), 1);
client->data.fd = pdata->fd;
client->data.local = pdata->local;
client->ctrl.fd = waiter->fd;
client->ctrl.local = pending->local;
add_waiter(client->ctrl.fd, POLLIN | POLLHUP, client_ctrl_handler, client);
add_waiter(client->data.fd, POLLHUP, client_data_handler, client);
client = calloc(1, sizeof(*client));
client->local = 0;
client->poll_fd = pdata->fd;
client->ctrl_fd = waiter->fd;
add_waiter(client->ctrl_fd, POLLIN | POLLHUP, client_ctrl_handler, client);
add_waiter(client->poll_fd, POLLHUP, client_poll_handler, client);
client->open = 0;
list_add_tail(&client->list, &clients);
list_del(&pending->list);
@ -791,70 +814,81 @@ int pending_handler(waiter_t *waiter, unsigned short events)
return 0;
}
int master_handler(waiter_t *waiter, unsigned short events ATTRIBUTE_UNUSED)
int local_handler(waiter_t *waiter, unsigned short events ATTRIBUTE_UNUSED)
{
master_t *master = waiter->private_data;
int sock;
sock = accept(waiter->fd, 0, 0);
if (sock < 0) {
int result = -errno;
perrno("accept");
SYSERR("accept");
return result;
} else {
pending_t *pending = calloc(sizeof(*pending), 1);
client_t *client = calloc(1, sizeof(*client));
client->ctrl_fd = sock;
client->local = 1;
client->open = 0;
add_waiter(sock, POLLIN | POLLHUP, client_ctrl_handler, client);
list_add_tail(&client->list, &clients);
}
return 0;
}
int inet_handler(waiter_t *waiter, unsigned short events ATTRIBUTE_UNUSED)
{
int sock;
sock = accept(waiter->fd, 0, 0);
if (sock < 0) {
int result = -errno;
SYSERR("accept");
return result;
} else {
inet_pending_t *pending = calloc(1, sizeof(*pending));
pending->fd = sock;
pending->local = master->local;
pending->cookie = 0;
add_waiter(sock, POLLIN, pending_handler, pending);
list_add_tail(&pending->list, &pendings);
add_waiter(sock, POLLIN, inet_pending_handler, pending);
list_add_tail(&pending->list, &inet_pendings);
}
return 0;
}
int server(char *sockname, int port)
{
struct list_head *item;
int err;
unsigned int k;
if (!sockname && port < 0)
return -EINVAL;
if (sockname) {
int sock = make_local_socket(sockname);
master_t *master;
if (sock < 0)
return sock;
master = calloc(sizeof(*master), 1);
master->fd = sock;
master->local = 1;
add_waiter(sock, POLLIN, master_handler, master);
list_add_tail(&master->list, &masters);
if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0) {
int result = -errno;
SYSERR("fcntl");
return result;
}
if (listen(sock, 4) < 0) {
int result = -errno;
SYSERR("listen");
return result;
}
add_waiter(sock, POLLIN, local_handler, NULL);
}
if (port >= 0) {
int sock = make_inet_socket(port);
master_t *master;
if (sock < 0)
return sock;
master = calloc(sizeof(*master), 1);
master->fd = sock;
master->local = 0;
add_waiter(sock, POLLIN, master_handler, master);
list_add_tail(&master->list, &masters);
}
if (list_empty(&masters))
return -EINVAL;
list_for_each(item, &masters) {
master_t *master = list_entry(item, master_t, list);
if (fcntl(master->fd, F_SETFL, O_NONBLOCK) < 0) {
if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0) {
int result = -errno;
perrno("fcntl");
SYSERR("fcntl");
return result;
}
if (listen(master->fd, 4) < 0) {
if (listen(sock, 4) < 0) {
int result = -errno;
perrno("listen");
SYSERR("listen");
return result;
}
add_waiter(sock, POLLIN, inet_handler, NULL);
}
while (1) {
@ -864,7 +898,7 @@ int server(char *sockname, int port)
err = poll(pollfds, pollfds_count, 1000);
} while (err == 0);
if (err < 0) {
perrno("poll");
SYSERR("poll");
continue;
}
@ -878,7 +912,7 @@ int server(char *sockname, int port)
continue;
err = w->handler(w, pfd->revents);
if (err < 0)
perrno("handler");
SYSERR("handler");
}
}
}
@ -889,47 +923,102 @@ int server(char *sockname, int port)
void usage()
{
fprintf(stderr, "\
Usage: %s [OPTIONS]
Usage: %s [OPTIONS] server
--help help
--version print current version
-l,--local SOCKNAME local socket name
-p,--port PORT port number
", command);
}
extern int is_local(struct hostent *hent);
int main(int argc, char **argv)
{
static struct option long_options[] = {
{"local", 1, 0, 'l'},
{"port", 1, 0, 'p'},
{"help", 0, 0, 'h'}
};
int c;
char *local = NULL;
int port = -1;
snd_config_t *conf;
snd_config_iterator_t i;
char *socket = NULL;
char *host = NULL;
long port = -1;
int err;
char *srvname;
struct hostent *h;
command = argv[0];
while ((c = getopt_long(argc, argv, "hl:p:", long_options, 0)) != -1) {
while ((c = getopt_long(argc, argv, "h", long_options, 0)) != -1) {
switch (c) {
case 'h':
usage();
return 0;
case 'l':
local = optarg;
break;
case 'p':
port = atoi(optarg);
break;
default:
fprintf(stderr, "Try `%s --help' for more information\n", command);
return 1;
}
}
if (!local && port == -1) {
fprintf(stderr, "%s: you need to specify at least one master socket\n", command);
if (argc - optind != 1) {
ERROR("you need to specify server name");
return 1;
}
server(local, port);
err = snd_config_update();
if (err < 0) {
ERROR("cannot read configuration file");
return 1;
}
srvname = argv[optind];
err = snd_config_searchv(snd_config, &conf, "server", srvname, 0);
if (err < 0) {
ERROR("unknown server %s", srvname);
return 1;
}
snd_config_foreach(i, conf) {
snd_config_t *n = snd_config_entry(i);
if (strcmp(n->id, "comment") == 0)
continue;
if (strcmp(n->id, "host") == 0) {
err = snd_config_string_get(n, &host);
if (err < 0) {
ERROR("Invalid type for host");
return 1;
}
continue;
}
if (strcmp(n->id, "socket") == 0) {
err = snd_config_string_get(n, &socket);
if (err < 0) {
ERROR("Invalid type for socket");
return 1;
}
continue;
}
if (strcmp(n->id, "port") == 0) {
err = snd_config_integer_get(n, &port);
if (err < 0) {
ERROR("Invalid type for port");
return 1;
}
continue;
}
ERROR("Unknown field: %s", n->id);
return 1;
}
if (!host) {
ERROR("host is not defined");
return 1;
}
h = gethostbyname(host);
if (!h) {
ERROR("Cannot resolve %s", host);
return 1;
}
if (!is_local(h)) {
ERROR("%s is not the local host", host);
return 1;
}
if (!socket && port < 0) {
ERROR("either socket or port need to be defined");
return 1;
}
server(socket, port);
return 0;
}

View file

@ -19,17 +19,17 @@
*/
#include "../src/pcm/pcm_local.h"
#define SND_PCM_IOCTL_STATE _IO ('A', 0xf0)
#define SND_PCM_IOCTL_MMAP_DATA _IO ('A', 0xf1)
#define SND_PCM_IOCTL_MMAP_CONTROL _IO ('A', 0xf2)
#define SND_PCM_IOCTL_MMAP_STATUS _IO ('A', 0xf3)
#define SND_PCM_IOCTL_MUNMAP_DATA _IO ('A', 0xf4)
#define SND_PCM_IOCTL_MUNMAP_CONTROL _IO ('A', 0xf5)
#define SND_PCM_IOCTL_MUNMAP_STATUS _IO ('A', 0xf6)
#define SND_PCM_IOCTL_MMAP _IO ('A', 0xf1)
#define SND_PCM_IOCTL_MUNMAP _IO ('A', 0xf4)
#define SND_PCM_IOCTL_MMAP_FORWARD _IO ('A', 0xf7)
#define SND_PCM_IOCTL_AVAIL_UPDATE _IO ('A', 0xf8)
#define SND_PCM_IOCTL_ASYNC _IO ('A', 0xf9)
#define SND_PCM_IOCTL_CLOSE _IO ('A', 0xfa)
#define SND_PCM_IOCTL_MMAP_INFO _IO ('A', 0xfb)
#define SND_PCM_IOCTL_POLL_DESCRIPTOR _IO ('A', 0xfc)
typedef struct {
long result;
@ -39,6 +39,7 @@ typedef struct {
int sig;
pid_t pid;
} async;
snd_pcm_mmap_info_t mmap_info;
snd_pcm_info_t info;
snd_pcm_params_t params;
snd_pcm_params_info_t params_info;
@ -54,13 +55,13 @@ typedef struct {
size_t mmap_forward;
} u;
char data[0];
} snd_pcm_client_shm_t;
} snd_pcm_shm_ctrl_t;
#define PCM_SHM_SIZE 65536
#define PCM_SHM_DATA_MAXLEN (PCM_SHM_SIZE - offsetof(snd_pcm_client_shm_t, data))
#define PCM_SHM_SIZE sizeof(snd_pcm_shm_ctrl_t)
#define SND_CTL_IOCTL_READ _IOR('U', 0xf0, snd_ctl_event_t)
#define SND_CTL_IOCTL_CLOSE _IO ('U', 0xf1)
#define SND_CTL_IOCTL_POLL_DESCRIPTOR _IO ('U', 0xf2)
typedef struct {
int result;
@ -78,10 +79,10 @@ typedef struct {
snd_ctl_event_t read;
} u;
char data[0];
} snd_ctl_client_shm_t;
} snd_ctl_shm_ctrl_t;
#define CTL_SHM_SIZE 65536
#define CTL_SHM_DATA_MAXLEN (CTL_SHM_SIZE - offsetof(snd_ctl_client_shm_t, data))
#define CTL_SHM_DATA_MAXLEN (CTL_SHM_SIZE - offsetof(snd_ctl_shm_ctrl_t, data))
typedef struct {
unsigned char dev_type;

View file

@ -7,7 +7,10 @@
typedef struct snd_ctl snd_ctl_t;
typedef enum { SND_CTL_TYPE_HW, SND_CTL_TYPE_CLIENT } snd_ctl_type_t;
typedef enum { SND_CTL_TYPE_HW,
SND_CTL_TYPE_SHM,
SND_CTL_TYPE_INET
} snd_ctl_type_t;
typedef struct snd_ctl_callbacks {
void *private_data; /* may be used by an application */
@ -37,8 +40,8 @@ int snd_defaults_pcm_device(void);
int snd_defaults_rawmidi_card(void);
int snd_defaults_rawmidi_device(void);
int snd_ctl_hw_open(snd_ctl_t **handle, int card);
int snd_ctl_client_open(snd_ctl_t **handlep, char *host, int port, int transport, char *name);
int snd_ctl_hw_open(snd_ctl_t **handle, char *name, int card);
int snd_ctl_shm_open(snd_ctl_t **handlep, char *name, char *socket, char *sname);
snd_ctl_type_t snd_ctl_type(snd_ctl_t *handle);
int snd_ctl_open(snd_ctl_t **handle, char *name);
int snd_ctl_close(snd_ctl_t *handle);

View file

@ -104,7 +104,8 @@ typedef enum {
SND_PCM_TYPE_MULTI,
SND_PCM_TYPE_FILE,
SND_PCM_TYPE_NULL,
SND_PCM_TYPE_CLIENT,
SND_PCM_TYPE_SHM,
SND_PCM_TYPE_INET,
SND_PCM_TYPE_LINEAR,
SND_PCM_TYPE_ALAW,
SND_PCM_TYPE_MULAW,
@ -118,16 +119,16 @@ typedef enum {
SND_PCM_TYPE_LBSERVER,
} snd_pcm_type_t;
extern void (*snd_pcm_error)(const char *file, int line, const char *function, const char *fmt, ...);
extern void snd_pcm_error(const char *file, int line, const char *function, const char *fmt, ...) __attribute__ ((weak, format (printf, 4, 5)));
int snd_pcm_open(snd_pcm_t **handle, char *name,
int snd_pcm_open(snd_pcm_t **pcm, char *name,
int stream, int mode);
/* Obsolete functions */
int snd_pcm_hw_open_subdevice(snd_pcm_t **handle, int card, int device, int subdevice, int stream, int mode);
int snd_pcm_hw_open_device(snd_pcm_t **handle, int card, int device, int stream, int mode);
int snd_pcm_plug_open_subdevice(snd_pcm_t **handle, int card, int device, int subdevice, int stream, int mode);
int snd_pcm_plug_open_device(snd_pcm_t **handle, int card, int device, int stream, int mode);
int snd_pcm_hw_open_subdevice(snd_pcm_t **pcm, int card, int device, int subdevice, int stream, int mode);
int snd_pcm_hw_open_device(snd_pcm_t **pcm, int card, int device, int stream, int mode);
int snd_pcm_plug_open_subdevice(snd_pcm_t **pcm, int card, int device, int subdevice, int stream, int mode);
int snd_pcm_plug_open_device(snd_pcm_t **pcm, int card, int device, int stream, int mode);
#define snd_pcm_write snd_pcm_writei
#define snd_pcm_read snd_pcm_readi
ssize_t snd_pcm_writev(snd_pcm_t *pcm, const struct iovec *vector, int count);
@ -171,7 +172,7 @@ ssize_t snd_pcm_avail_update(snd_pcm_t *pcm);
/* mmap */
int snd_pcm_mmap(snd_pcm_t *pcm, void **buffer);
int snd_pcm_mmap(snd_pcm_t *pcm);
int snd_pcm_munmap(snd_pcm_t *pcm);
snd_pcm_channel_area_t *snd_pcm_mmap_areas(snd_pcm_t *pcm);
int snd_pcm_mmap_get_areas(snd_pcm_t *pcm, snd_pcm_channel_area_t *stopped_areas, snd_pcm_channel_area_t *running_areas);

View file

@ -1,7 +1,7 @@
EXTRA_LTLIBRARIES = libcontrol.la
libcontrol_la_SOURCES = cards.c controls.c bag.c defaults.c \
control.c control_hw.c control_client.c
control.c control_hw.c control_shm.c
all: libcontrol.la

View file

@ -106,7 +106,7 @@ int snd_card_get_index(const char *string)
for (card = 0; card < 32; card++) {
if (snd_card_load(card) < 0)
continue;
if (snd_ctl_hw_open(&handle, card) < 0)
if (snd_ctl_hw_open(&handle, NULL, card) < 0)
continue;
if (snd_ctl_hw_info(handle, &info) < 0) {
snd_ctl_close(handle);
@ -127,7 +127,7 @@ int snd_card_get_name(int card, char **name)
if (name == NULL)
return -EINVAL;
if ((err = snd_ctl_hw_open(&handle, card)) < 0)
if ((err = snd_ctl_hw_open(&handle, NULL, card)) < 0)
return err;
if ((err = snd_ctl_hw_info(handle, &info)) < 0) {
snd_ctl_close(handle);
@ -148,7 +148,7 @@ int snd_card_get_longname(int card, char **name)
if (name == NULL)
return -EINVAL;
if ((err = snd_ctl_hw_open(&handle, card)) < 0)
if ((err = snd_ctl_hw_open(&handle, NULL, card)) < 0)
return err;
if ((err = snd_ctl_hw_info(handle, &info)) < 0) {
snd_ctl_close(handle);

View file

@ -26,6 +26,7 @@
#include <errno.h>
#include <fcntl.h>
#include <assert.h>
#include <dlfcn.h>
#include "asoundlib.h"
#include "control_local.h"
@ -148,106 +149,22 @@ int snd_ctl_read(snd_ctl_t *ctl, snd_ctl_callbacks_t * callbacks)
return result >= 0 ? count : -errno;
}
static int _snd_ctl_open_hw(snd_ctl_t **handlep, snd_config_t *conf)
{
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_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)
int snd_ctl_open(snd_ctl_t **ctlp, char *name)
{
char *str;
int err;
snd_config_t *ctl_conf, *conf;
assert(handlep && name);
snd_config_t *ctl_conf, *conf, *type_conf;
snd_config_iterator_t i;
char *lib = NULL, *open = NULL;
int (*open_func)(snd_ctl_t **ctlp, char *name, snd_config_t *conf);
void *h;
assert(ctlp && name);
err = snd_config_update();
if (err < 0)
return err;
err = snd_config_searchv(snd_config, &ctl_conf, "ctl", name, 0);
if (err < 0) {
int idx = snd_card_get_index(name);
if (idx < 0)
return idx;
return snd_ctl_hw_open(handlep, idx);
}
if (err < 0)
return err;
if (snd_config_type(ctl_conf) != SND_CONFIG_TYPE_COMPOUND)
return -EINVAL;
err = snd_config_search(ctl_conf, "type", &conf);
@ -256,10 +173,37 @@ int snd_ctl_open(snd_ctl_t **handlep, char *name)
err = snd_config_string_get(conf, &str);
if (err < 0)
return err;
if (strcmp(str, "hw") == 0)
return _snd_ctl_open_hw(handlep, ctl_conf);
else if (strcmp(str, "client") == 0)
return _snd_ctl_open_client(handlep, ctl_conf);
else
err = snd_config_searchv(snd_config, &type_conf, "ctltype", str, 0);
if (err < 0)
return err;
snd_config_foreach(i, type_conf) {
snd_config_t *n = snd_config_entry(i);
if (strcmp(n->id, "comment") == 0)
continue;
if (strcmp(n->id, "lib") == 0) {
err = snd_config_string_get(n, &lib);
if (err < 0)
return -EINVAL;
continue;
}
if (strcmp(n->id, "open") == 0) {
err = snd_config_string_get(n, &open);
if (err < 0)
return -EINVAL;
continue;
return -EINVAL;
}
}
if (!open)
return -EINVAL;
if (!lib)
lib = "libasound.so";
h = dlopen(lib, RTLD_NOW);
if (!h)
return -ENOENT;
open_func = dlsym(h, open);
dlclose(h);
if (!open_func)
return -ENXIO;
return open_func(ctlp, name, ctl_conf);
}

View file

@ -1,433 +0,0 @@
/*
* 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;
}

View file

@ -147,7 +147,7 @@ struct snd_ctl_ops snd_ctl_hw_ops = {
read: snd_ctl_hw_read,
};
int snd_ctl_hw_open(snd_ctl_t **handle, int card)
int snd_ctl_hw_open(snd_ctl_t **handle, char *name, int card)
{
int fd, ver;
char filename[32];
@ -185,6 +185,9 @@ int snd_ctl_hw_open(snd_ctl_t **handle, int card)
}
hw->card = card;
hw->fd = fd;
if (name)
ctl->name = strdup(name);
ctl->type = SND_CTL_TYPE_HW;
ctl->ops = &snd_ctl_hw_ops;
ctl->private = hw;
INIT_LIST_HEAD(&ctl->hlist);
@ -192,3 +195,34 @@ int snd_ctl_hw_open(snd_ctl_t **handle, int card)
return 0;
}
int _snd_ctl_hw_open(snd_ctl_t **handlep, char *name, snd_config_t *conf)
{
snd_config_iterator_t i;
long card = -1;
char *str;
int err;
snd_config_foreach(i, conf) {
snd_config_t *n = snd_config_entry(i);
if (strcmp(n->id, "comment") == 0)
continue;
if (strcmp(n->id, "type") == 0)
continue;
if (strcmp(n->id, "card") == 0) {
err = snd_config_integer_get(n, &card);
if (err < 0) {
err = snd_config_string_get(n, &str);
if (err < 0)
return -EINVAL;
card = snd_card_get_index(str);
if (card < 0)
return card;
}
continue;
}
return -EINVAL;
}
if (card < 0)
return -EINVAL;
return snd_ctl_hw_open(handlep, name, card);
}

View file

@ -40,6 +40,7 @@ struct snd_ctl_ops {
struct snd_ctl {
char *name;
snd_ctl_type_t type;
struct snd_ctl_ops *ops;
void *private;

512
src/control/control_shm.c Normal file
View file

@ -0,0 +1,512 @@
/*
* 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);
}

View file

@ -3,7 +3,7 @@ EXTRA_LTLIBRARIES = libpcm.la
libpcm_la_SOURCES = pcm.c pcm_hw.c pcm_plugin.c pcm_linear.c pcm_route.c \
pcm_mulaw.c pcm_alaw.c pcm_adpcm.c pcm_rate.c pcm_plug.c \
pcm_misc.c pcm_mmap.c pcm_multi.c pcm_client.c pcm_file.c \
pcm_misc.c pcm_mmap.c pcm_multi.c pcm_shm.c pcm_file.c \
pcm_share.c
noinst_HEADERS = pcm_local.h pcm_plugin.h

View file

@ -30,18 +30,6 @@
#include "pcm_local.h"
#include "list.h"
int snd_pcm_init(snd_pcm_t *pcm)
{
int err;
err = snd_pcm_mmap_status(pcm, NULL);
if (err < 0)
return err;
err = snd_pcm_mmap_control(pcm, NULL);
if (err < 0)
return err;
return 0;
}
snd_pcm_type_t snd_pcm_type(snd_pcm_t *pcm)
{
assert(pcm);
@ -59,16 +47,8 @@ int snd_pcm_close(snd_pcm_t *pcm)
int ret = 0;
int err;
assert(pcm);
if (pcm->mmap_status) {
if ((err = snd_pcm_munmap_status(pcm)) < 0)
ret = err;
}
if (pcm->mmap_control) {
if ((err = snd_pcm_munmap_control(pcm)) < 0)
ret = err;
}
if (pcm->mmap_data) {
if ((err = snd_pcm_munmap_data(pcm)) < 0)
if (pcm->mmap_info) {
if ((err = snd_pcm_munmap(pcm)) < 0)
ret = err;
}
if ((err = pcm->ops->close(pcm->op_arg)) < 0)
@ -156,12 +136,21 @@ int snd_pcm_params(snd_pcm_t *pcm, snd_pcm_params_t *params)
{
int err;
snd_pcm_setup_t setup;
int mmap = 0;
assert(pcm && params);
assert(!pcm->mmap_data);
if (pcm->mmap_info) {
mmap = 1;
err = snd_pcm_munmap(pcm);
if (err < 0)
return err;
}
if ((err = pcm->ops->params(pcm->op_arg, params)) < 0)
return err;
pcm->valid_setup = 0;
return snd_pcm_setup(pcm, &setup);
err = snd_pcm_setup(pcm, &setup);
if (pcm->mmap_auto || mmap)
snd_pcm_mmap(pcm);
return err;
}
int snd_pcm_status(snd_pcm_t *pcm, snd_pcm_status_t *status)
@ -233,7 +222,7 @@ ssize_t snd_pcm_writei(snd_pcm_t *pcm, const void *buffer, size_t size)
assert(size == 0 || buffer);
assert(pcm->valid_setup);
assert(pcm->setup.xfer_mode == SND_PCM_XFER_INTERLEAVED);
assert(!pcm->mmap_data);
assert(!pcm->mmap_info || pcm->mmap_auto);
return _snd_pcm_writei(pcm, buffer, size);
}
@ -243,7 +232,7 @@ ssize_t snd_pcm_writen(snd_pcm_t *pcm, void **bufs, size_t size)
assert(size == 0 || bufs);
assert(pcm->valid_setup);
assert(pcm->setup.xfer_mode == SND_PCM_XFER_NONINTERLEAVED);
assert(!pcm->mmap_data);
assert(!pcm->mmap_info || pcm->mmap_auto);
return _snd_pcm_writen(pcm, bufs, size);
}
@ -253,7 +242,7 @@ ssize_t snd_pcm_readi(snd_pcm_t *pcm, void *buffer, size_t size)
assert(size == 0 || buffer);
assert(pcm->valid_setup);
assert(pcm->setup.xfer_mode == SND_PCM_XFER_INTERLEAVED);
assert(!pcm->mmap_data);
assert(!pcm->mmap_info || pcm->mmap_auto);
return _snd_pcm_readi(pcm, buffer, size);
}
@ -263,7 +252,7 @@ ssize_t snd_pcm_readn(snd_pcm_t *pcm, void **bufs, size_t size)
assert(size == 0 || bufs);
assert(pcm->valid_setup);
assert(pcm->setup.xfer_mode == SND_PCM_XFER_NONINTERLEAVED);
assert(!pcm->mmap_data);
assert(!pcm->mmap_info || pcm->mmap_auto);
return _snd_pcm_readn(pcm, bufs, size);
}
@ -331,7 +320,7 @@ int snd_pcm_unlink(snd_pcm_t *pcm)
int snd_pcm_poll_descriptor(snd_pcm_t *pcm)
{
assert(pcm);
return pcm->fast_ops->poll_descriptor(pcm->fast_op_arg);
return pcm->poll_fd;
}
int snd_pcm_channels_mask(snd_pcm_t *pcm, bitset_t *cmask)
@ -547,62 +536,87 @@ int snd_pcm_open(snd_pcm_t **pcmp, char *name,
if (err < 0)
return err;
err = snd_config_searchv(snd_config, &pcm_conf, "pcm", name, 0);
if (err < 0)
if (err < 0) {
ERR("Unknown PCM %s", name);
return err;
if (snd_config_type(pcm_conf) != SND_CONFIG_TYPE_COMPOUND)
}
if (snd_config_type(pcm_conf) != SND_CONFIG_TYPE_COMPOUND) {
ERR("Invalid type for PCM definition");
return -EINVAL;
}
err = snd_config_search(pcm_conf, "stream", &conf);
if (err >= 0) {
err = snd_config_string_get(conf, &str);
if (err < 0)
if (err < 0) {
ERR("Invalid type for stream");
return err;
}
if (strcmp(str, "playback") == 0) {
if (stream != SND_PCM_STREAM_PLAYBACK)
return -EINVAL;
} else if (strcmp(str, "capture") == 0) {
if (stream != SND_PCM_STREAM_CAPTURE)
return -EINVAL;
} else
} else {
ERR("Invalid value for stream");
return -EINVAL;
}
}
err = snd_config_search(pcm_conf, "type", &conf);
if (err < 0)
if (err < 0) {
ERR("type is not defined");
return err;
}
err = snd_config_string_get(conf, &str);
if (err < 0)
if (err < 0) {
ERR("Invalid type for type");
return err;
}
err = snd_config_searchv(snd_config, &type_conf, "pcmtype", str, 0);
if (err < 0)
if (err < 0) {
ERR("Unknown PCM type %s", str);
return err;
}
snd_config_foreach(i, type_conf) {
snd_config_t *n = snd_config_entry(i);
if (strcmp(n->id, "comment") == 0)
continue;
if (strcmp(n->id, "lib") == 0) {
err = snd_config_string_get(n, &lib);
if (err < 0)
if (err < 0) {
ERR("Invalid type for lib");
return -EINVAL;
}
continue;
}
if (strcmp(n->id, "open") == 0) {
err = snd_config_string_get(n, &open);
if (err < 0)
if (err < 0) {
ERR("Invalid type for open");
return -EINVAL;
}
continue;
ERR("Unknown field: %s", n->id);
return -EINVAL;
}
}
if (!open)
if (!open) {
ERR("open is not defined");
return -EINVAL;
}
if (!lib)
lib = "libasound.so";
h = dlopen(lib, RTLD_NOW);
if (!h)
if (!h) {
ERR("Cannot open shared library %s", lib);
return -ENOENT;
}
open_func = dlsym(h, open);
dlclose(h);
if (!open_func)
if (!open_func) {
ERR("symbol %s is not defined inside %s", open, lib);
return -ENXIO;
}
return open_func(pcmp, name, pcm_conf, stream, mode);
}
@ -634,23 +648,11 @@ int snd_pcm_wait(snd_pcm_t *pcm, int timeout)
{
struct pollfd pfd;
int err;
#if 0
size_t bavail, aavail;
struct timeval before, after, diff;
bavail = snd_pcm_avail_update(pcm);
gettimeofday(&before, 0);
#endif
pfd.fd = snd_pcm_poll_descriptor(pcm);
pfd.events = pcm->stream == SND_PCM_STREAM_PLAYBACK ? POLLOUT : POLLIN;
err = poll(&pfd, 1, timeout);
if (err < 0)
return err;
#if 0
aavail = snd_pcm_avail_update(pcm);
gettimeofday(&after, 0);
timersub(&after, &before, &diff);
fprintf(stderr, "%s %ld.%06ld: get=%d (%d-%d)\n", pcm->stream == SND_PCM_STREAM_PLAYBACK ? "playback" : "capture", diff.tv_sec, diff.tv_usec, aavail - bavail, aavail, bavail);
#endif
return 0;
}
@ -1044,7 +1046,7 @@ ssize_t snd_pcm_write_areas(snd_pcm_t *pcm, snd_pcm_channel_area_t *areas,
return err;
}
void snd_pcm_error_default(const char *file, int line, const char *function, const char *fmt, ...)
void snd_pcm_error(const char *file, int line, const char *function, const char *fmt, ...)
{
va_list arg;
va_start(arg, fmt);
@ -1053,5 +1055,3 @@ void snd_pcm_error_default(const char *file, int line, const char *function, con
putc('\n', stderr);
va_end(arg);
}
void (*snd_pcm_error)(const char *file, int line, const char *function, const char *fmt, ...) = snd_pcm_error_default;

View file

@ -377,11 +377,6 @@ static int snd_pcm_adpcm_params(snd_pcm_t *pcm, snd_pcm_params_t * params)
params->fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
return -EINVAL;
}
if (slave->mmap_data) {
err = snd_pcm_munmap_data(slave);
if (err < 0)
return err;
}
adpcm->cformat = params->format.sfmt;
adpcm->cxfer_mode = params->xfer_mode;
adpcm->cmmap_shape = params->mmap_shape;
@ -392,10 +387,6 @@ static int snd_pcm_adpcm_params(snd_pcm_t *pcm, snd_pcm_params_t * params)
params->format.sfmt = adpcm->cformat;
params->xfer_mode = adpcm->cxfer_mode;
params->mmap_shape = adpcm->cmmap_shape;
if (slave->valid_setup) {
int r = snd_pcm_mmap_data(slave, NULL);
assert(r >= 0);
}
return err;
}
@ -533,7 +524,7 @@ static void snd_pcm_adpcm_dump(snd_pcm_t *pcm, FILE *fp)
snd_pcm_dump(adpcm->plug.slave, fp);
}
struct snd_pcm_ops snd_pcm_adpcm_ops = {
snd_pcm_ops_t snd_pcm_adpcm_ops = {
close: snd_pcm_adpcm_close,
info: snd_pcm_plugin_info,
params_info: snd_pcm_adpcm_params_info,
@ -545,20 +536,15 @@ struct snd_pcm_ops snd_pcm_adpcm_ops = {
dump: snd_pcm_adpcm_dump,
nonblock: snd_pcm_plugin_nonblock,
async: snd_pcm_plugin_async,
mmap_status: snd_pcm_plugin_mmap_status,
mmap_control: snd_pcm_plugin_mmap_control,
mmap_data: snd_pcm_plugin_mmap_data,
munmap_status: snd_pcm_plugin_munmap_status,
munmap_control: snd_pcm_plugin_munmap_control,
munmap_data: snd_pcm_plugin_munmap_data,
mmap: snd_pcm_plugin_mmap,
munmap: snd_pcm_plugin_munmap,
};
int snd_pcm_adpcm_open(snd_pcm_t **handlep, char *name, int sformat, snd_pcm_t *slave, int close_slave)
int snd_pcm_adpcm_open(snd_pcm_t **pcmp, char *name, int sformat, snd_pcm_t *slave, int close_slave)
{
snd_pcm_t *handle;
snd_pcm_t *pcm;
snd_pcm_adpcm_t *adpcm;
int err;
assert(handlep && slave);
assert(pcmp && slave);
if (snd_pcm_format_linear(sformat) != 1 &&
sformat != SND_PCM_SFMT_IMA_ADPCM)
return -EINVAL;
@ -573,27 +559,25 @@ int snd_pcm_adpcm_open(snd_pcm_t **handlep, char *name, int sformat, snd_pcm_t *
adpcm->plug.slave = slave;
adpcm->plug.close_slave = close_slave;
handle = calloc(1, sizeof(snd_pcm_t));
if (!handle) {
pcm = calloc(1, sizeof(snd_pcm_t));
if (!pcm) {
free(adpcm);
return -ENOMEM;
}
if (name)
handle->name = strdup(name);
handle->type = SND_PCM_TYPE_ADPCM;
handle->stream = slave->stream;
handle->ops = &snd_pcm_adpcm_ops;
handle->op_arg = handle;
handle->fast_ops = &snd_pcm_plugin_fast_ops;
handle->fast_op_arg = handle;
handle->mode = slave->mode;
handle->private = adpcm;
err = snd_pcm_init(handle);
if (err < 0) {
snd_pcm_close(handle);
return err;
}
*handlep = handle;
pcm->name = strdup(name);
pcm->type = SND_PCM_TYPE_ADPCM;
pcm->stream = slave->stream;
pcm->mode = slave->mode;
pcm->ops = &snd_pcm_adpcm_ops;
pcm->op_arg = pcm;
pcm->fast_ops = &snd_pcm_plugin_fast_ops;
pcm->fast_op_arg = pcm;
pcm->private = adpcm;
pcm->poll_fd = slave->poll_fd;
pcm->hw_ptr = &adpcm->plug.hw_ptr;
pcm->appl_ptr = &adpcm->plug.appl_ptr;
*pcmp = pcm;
return 0;
}

View file

@ -259,11 +259,6 @@ static int snd_pcm_alaw_params(snd_pcm_t *pcm, snd_pcm_params_t * params)
params->fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
return -EINVAL;
}
if (slave->mmap_data) {
err = snd_pcm_munmap_data(slave);
if (err < 0)
return err;
}
alaw->cformat = params->format.sfmt;
alaw->cxfer_mode = params->xfer_mode;
alaw->cmmap_shape = params->mmap_shape;
@ -274,10 +269,6 @@ static int snd_pcm_alaw_params(snd_pcm_t *pcm, snd_pcm_params_t * params)
params->format.sfmt = alaw->cformat;
params->xfer_mode = alaw->cxfer_mode;
params->mmap_shape = alaw->cmmap_shape;
if (slave->valid_setup) {
int r = snd_pcm_mmap_data(slave, NULL);
assert(r >= 0);
}
return err;
}
@ -401,7 +392,7 @@ static void snd_pcm_alaw_dump(snd_pcm_t *pcm, FILE *fp)
snd_pcm_dump(alaw->plug.slave, fp);
}
struct snd_pcm_ops snd_pcm_alaw_ops = {
snd_pcm_ops_t snd_pcm_alaw_ops = {
close: snd_pcm_plugin_close,
info: snd_pcm_plugin_info,
params_info: snd_pcm_alaw_params_info,
@ -413,20 +404,15 @@ struct snd_pcm_ops snd_pcm_alaw_ops = {
dump: snd_pcm_alaw_dump,
nonblock: snd_pcm_plugin_nonblock,
async: snd_pcm_plugin_async,
mmap_status: snd_pcm_plugin_mmap_status,
mmap_control: snd_pcm_plugin_mmap_control,
mmap_data: snd_pcm_plugin_mmap_data,
munmap_status: snd_pcm_plugin_munmap_status,
munmap_control: snd_pcm_plugin_munmap_control,
munmap_data: snd_pcm_plugin_munmap_data,
mmap: snd_pcm_plugin_mmap,
munmap: snd_pcm_plugin_munmap,
};
int snd_pcm_alaw_open(snd_pcm_t **handlep, char *name, int sformat, snd_pcm_t *slave, int close_slave)
int snd_pcm_alaw_open(snd_pcm_t **pcmp, char *name, int sformat, snd_pcm_t *slave, int close_slave)
{
snd_pcm_t *handle;
snd_pcm_t *pcm;
snd_pcm_alaw_t *alaw;
int err;
assert(handlep && slave);
assert(pcmp && slave);
if (snd_pcm_format_linear(sformat) != 1 &&
sformat != SND_PCM_SFMT_A_LAW)
return -EINVAL;
@ -440,27 +426,25 @@ int snd_pcm_alaw_open(snd_pcm_t **handlep, char *name, int sformat, snd_pcm_t *s
alaw->plug.slave = slave;
alaw->plug.close_slave = close_slave;
handle = calloc(1, sizeof(snd_pcm_t));
if (!handle) {
pcm = calloc(1, sizeof(snd_pcm_t));
if (!pcm) {
free(alaw);
return -ENOMEM;
}
if (name)
handle->name = strdup(name);
handle->type = SND_PCM_TYPE_ALAW;
handle->stream = slave->stream;
handle->ops = &snd_pcm_alaw_ops;
handle->op_arg = handle;
handle->fast_ops = &snd_pcm_plugin_fast_ops;
handle->fast_op_arg = handle;
handle->mode = slave->mode;
handle->private = alaw;
err = snd_pcm_init(handle);
if (err < 0) {
snd_pcm_close(handle);
return err;
}
*handlep = handle;
pcm->name = strdup(name);
pcm->type = SND_PCM_TYPE_ALAW;
pcm->stream = slave->stream;
pcm->mode = slave->mode;
pcm->ops = &snd_pcm_alaw_ops;
pcm->op_arg = pcm;
pcm->fast_ops = &snd_pcm_plugin_fast_ops;
pcm->fast_op_arg = pcm;
pcm->private = alaw;
pcm->poll_fd = slave->poll_fd;
pcm->hw_ptr = &alaw->plug.hw_ptr;
pcm->appl_ptr = &alaw->plug.appl_ptr;
*pcmp = pcm;
return 0;
}

View file

@ -1,857 +0,0 @@
/*
* 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);
}
}

View file

@ -219,7 +219,7 @@ static ssize_t snd_pcm_file_readn(snd_pcm_t *pcm, void **bufs, size_t size)
static ssize_t snd_pcm_file_mmap_forward(snd_pcm_t *pcm, size_t size)
{
snd_pcm_file_t *file = pcm->private;
size_t ofs = pcm->mmap_control->appl_ptr % pcm->setup.buffer_size;
size_t ofs = snd_pcm_mmap_offset(pcm);
ssize_t n = snd_pcm_mmap_forward(file->slave, size);
size_t xfer = 0;
if (n <= 0)
@ -244,60 +244,28 @@ static ssize_t snd_pcm_file_avail_update(snd_pcm_t *pcm)
return snd_pcm_avail_update(file->slave);
}
static int snd_pcm_file_mmap_status(snd_pcm_t *pcm)
static int snd_pcm_file_mmap(snd_pcm_t *pcm)
{
snd_pcm_file_t *file = pcm->private;
int err = snd_pcm_mmap_status(file->slave, &pcm->mmap_status);
int err = snd_pcm_mmap(file->slave);
if (err < 0)
return err;
pcm->mmap_status = file->slave->mmap_status;
pcm->mmap_info_count = file->slave->mmap_info_count;
pcm->mmap_info = file->slave->mmap_info;
return 0;
}
static int snd_pcm_file_mmap_control(snd_pcm_t *pcm)
static int snd_pcm_file_munmap(snd_pcm_t *pcm)
{
snd_pcm_file_t *file = pcm->private;
int err = snd_pcm_mmap_control(file->slave, &pcm->mmap_control);
int err = snd_pcm_munmap(file->slave);
if (err < 0)
return err;
pcm->mmap_control = file->slave->mmap_control;
pcm->mmap_info_count = 0;
pcm->mmap_info = 0;
return 0;
}
static int snd_pcm_file_mmap_data(snd_pcm_t *pcm)
{
snd_pcm_file_t *file = pcm->private;
int err = snd_pcm_mmap_data(file->slave, &pcm->mmap_data);
if (err < 0)
return err;
pcm->mmap_data = file->slave->mmap_data;
return 0;
}
static int snd_pcm_file_munmap_status(snd_pcm_t *pcm)
{
snd_pcm_file_t *file = pcm->private;
return snd_pcm_munmap_status(file->slave);
}
static int snd_pcm_file_munmap_control(snd_pcm_t *pcm)
{
snd_pcm_file_t *file = pcm->private;
return snd_pcm_munmap_control(file->slave);
}
static int snd_pcm_file_munmap_data(snd_pcm_t *pcm)
{
snd_pcm_file_t *file = pcm->private;
return snd_pcm_munmap_data(file->slave);
}
static int snd_pcm_file_poll_descriptor(snd_pcm_t *pcm)
{
snd_pcm_file_t *file = pcm->private;
return snd_pcm_poll_descriptor(file->slave);
}
static int snd_pcm_file_channels_mask(snd_pcm_t *pcm, bitset_t *cmask)
{
snd_pcm_file_t *file = pcm->private;
@ -337,7 +305,7 @@ static void snd_pcm_file_dump(snd_pcm_t *pcm, FILE *fp)
snd_pcm_dump(file->slave, fp);
}
struct snd_pcm_ops snd_pcm_file_ops = {
snd_pcm_ops_t snd_pcm_file_ops = {
close: snd_pcm_file_close,
info: snd_pcm_file_info,
params_info: snd_pcm_file_params_info,
@ -349,15 +317,11 @@ struct snd_pcm_ops snd_pcm_file_ops = {
dump: snd_pcm_file_dump,
nonblock: snd_pcm_file_nonblock,
async: snd_pcm_file_async,
mmap_status: snd_pcm_file_mmap_status,
mmap_control: snd_pcm_file_mmap_control,
mmap_data: snd_pcm_file_mmap_data,
munmap_status: snd_pcm_file_munmap_status,
munmap_control: snd_pcm_file_munmap_control,
munmap_data: snd_pcm_file_munmap_data,
mmap: snd_pcm_file_mmap,
munmap: snd_pcm_file_munmap,
};
struct snd_pcm_fast_ops snd_pcm_file_fast_ops = {
snd_pcm_fast_ops_t snd_pcm_file_fast_ops = {
status: snd_pcm_file_status,
state: snd_pcm_file_state,
delay: snd_pcm_file_delay,
@ -371,18 +335,16 @@ struct snd_pcm_fast_ops snd_pcm_file_fast_ops = {
writen: snd_pcm_file_writen,
readi: snd_pcm_file_readi,
readn: snd_pcm_file_readn,
poll_descriptor: snd_pcm_file_poll_descriptor,
channels_mask: snd_pcm_file_channels_mask,
avail_update: snd_pcm_file_avail_update,
mmap_forward: snd_pcm_file_mmap_forward,
};
int snd_pcm_file_open(snd_pcm_t **handlep, char *name, char *fname, int fd, snd_pcm_t *slave, int close_slave)
int snd_pcm_file_open(snd_pcm_t **pcmp, char *name, char *fname, int fd, snd_pcm_t *slave, int close_slave)
{
snd_pcm_t *handle;
snd_pcm_t *pcm;
snd_pcm_file_t *file;
int err;
assert(handlep && slave);
assert(pcmp && slave);
if (fname) {
fd = open(fname, O_WRONLY|O_CREAT, 0666);
if (fd < 0)
@ -397,27 +359,25 @@ int snd_pcm_file_open(snd_pcm_t **handlep, char *name, char *fname, int fd, snd_
file->slave = slave;
file->close_slave = close_slave;
handle = calloc(1, sizeof(snd_pcm_t));
if (!handle) {
pcm = calloc(1, sizeof(snd_pcm_t));
if (!pcm) {
free(file);
return -ENOMEM;
}
if (name)
handle->name = strdup(name);
handle->type = SND_PCM_TYPE_FILE;
handle->stream = slave->stream;
handle->ops = &snd_pcm_file_ops;
handle->op_arg = handle;
handle->fast_ops = &snd_pcm_file_fast_ops;
handle->fast_op_arg = handle;
handle->mode = slave->mode;
handle->private = file;
err = snd_pcm_init(handle);
if (err < 0) {
snd_pcm_close(handle);
return err;
}
*handlep = handle;
pcm->name = strdup(name);
pcm->type = SND_PCM_TYPE_FILE;
pcm->stream = slave->stream;
pcm->mode = slave->mode;
pcm->ops = &snd_pcm_file_ops;
pcm->op_arg = pcm;
pcm->fast_ops = &snd_pcm_file_fast_ops;
pcm->fast_op_arg = pcm;
pcm->private = file;
pcm->poll_fd = slave->poll_fd;
pcm->hw_ptr = slave->hw_ptr;
pcm->appl_ptr = slave->appl_ptr;
*pcmp = pcm;
return 0;
}

View file

@ -37,25 +37,14 @@
typedef struct {
int fd;
int card, device, subdevice;
int mmap_emulation;
volatile snd_pcm_mmap_status_t *mmap_status;
snd_pcm_mmap_control_t *mmap_control;
} snd_pcm_hw_t;
#define SND_FILE_PCM_STREAM_PLAYBACK "/dev/snd/pcmC%iD%ip"
#define SND_FILE_PCM_STREAM_CAPTURE "/dev/snd/pcmC%iD%ic"
#define SND_PCM_VERSION_MAX SND_PROTOCOL_VERSION(2, 0, 0)
static int snd_pcm_hw_close(snd_pcm_t *pcm)
{
snd_pcm_hw_t *hw = pcm->private;
int fd = hw->fd;
free(hw);
if (close(fd)) {
ERR("close failed\n");
return -errno;
}
return 0;
}
static int snd_pcm_hw_nonblock(snd_pcm_t *pcm, int nonblock)
{
long flags;
@ -158,9 +147,7 @@ static int snd_pcm_hw_setup(snd_pcm_t *pcm, snd_pcm_setup_t * setup)
setup->mmap_shape = SND_PCM_MMAP_INTERLEAVED;
else
setup->mmap_shape = SND_PCM_MMAP_NONINTERLEAVED;
hw->mmap_emulation = 1;
} else
hw->mmap_emulation = 0;
}
return 0;
}
@ -194,19 +181,21 @@ static int snd_pcm_hw_channel_setup(snd_pcm_t *pcm, snd_pcm_channel_setup_t * se
ERR("SND_PCM_IOCTL_CHANNEL_SETUP failed");
return -errno;
}
if (hw->mmap_emulation) {
if (pcm->setup.mmap_shape == SND_PCM_MMAP_INTERLEAVED) {
setup->running_area.addr = pcm->mmap_data;
if (!pcm->mmap_info)
return 0;
if (pcm->setup.mmap_shape == SND_PCM_MMAP_UNSPECIFIED) {
if (pcm->setup.xfer_mode == SND_PCM_XFER_INTERLEAVED) {
setup->running_area.addr = pcm->mmap_info->addr;
setup->running_area.first = setup->channel * pcm->bits_per_sample;
setup->running_area.step = pcm->bits_per_frame;
} else {
setup->running_area.addr = pcm->mmap_data + setup->channel * pcm->setup.buffer_size * pcm->bits_per_sample / 8;
setup->running_area.addr = pcm->mmap_info->addr + setup->channel * pcm->setup.buffer_size * pcm->bits_per_sample / 8;
setup->running_area.first = 0;
setup->running_area.step = pcm->bits_per_sample;
}
setup->stopped_area = setup->running_area;
} else {
setup->running_area.addr = (char *)pcm->mmap_data + (long)setup->running_area.addr;
setup->running_area.addr = pcm->mmap_info->addr + (long)setup->running_area.addr;
setup->stopped_area.addr = setup->running_area.addr;
}
return 0;
@ -225,7 +214,8 @@ static int snd_pcm_hw_status(snd_pcm_t *pcm, snd_pcm_status_t * status)
static int snd_pcm_hw_state(snd_pcm_t *pcm)
{
return pcm->mmap_status->state;
snd_pcm_hw_t *hw = pcm->private;
return hw->mmap_status->state;
}
static int snd_pcm_hw_delay(snd_pcm_t *pcm, ssize_t *delayp)
@ -378,7 +368,8 @@ static int snd_pcm_hw_mmap_status(snd_pcm_t *pcm)
ERR("status mmap failed");
return -errno;
}
pcm->mmap_status = ptr;
hw->mmap_status = ptr;
pcm->hw_ptr = &hw->mmap_status->hw_ptr;
return 0;
}
@ -392,36 +383,50 @@ static int snd_pcm_hw_mmap_control(snd_pcm_t *pcm)
ERR("control mmap failed");
return -errno;
}
pcm->mmap_control = ptr;
hw->mmap_control = ptr;
pcm->appl_ptr = &hw->mmap_control->appl_ptr;
return 0;
}
static int snd_pcm_hw_mmap_data(snd_pcm_t *pcm)
static int snd_pcm_hw_mmap(snd_pcm_t *pcm)
{
snd_pcm_hw_t *hw = pcm->private;
void *ptr;
if (hw->mmap_emulation) {
ptr = malloc(snd_pcm_frames_to_bytes(pcm, pcm->setup.buffer_size));
if (!ptr)
pcm->mmap_info = calloc(1, sizeof(*pcm->mmap_info));
if (!pcm->mmap_info)
return -ENOMEM;
pcm->mmap_info_count = 1;
if (pcm->setup.mmap_shape == SND_PCM_MMAP_UNSPECIFIED) {
pcm->mmap_info->type = SND_PCM_MMAP_USER;
pcm->mmap_info->size = snd_pcm_frames_to_bytes(pcm, pcm->setup.buffer_size);
pcm->mmap_info->addr = valloc(pcm->mmap_info->size);
if (!pcm->mmap_info->addr) {
free(pcm->mmap_info);
pcm->mmap_info = 0;
return -ENOMEM;
}
} else {
int prot;
prot = PROT_WRITE | PROT_READ;
ptr = mmap(NULL, pcm->setup.mmap_bytes,
prot, MAP_FILE|MAP_SHARED,
hw->fd, SND_PCM_MMAP_OFFSET_DATA);
if (ptr == MAP_FAILED || ptr == NULL) {
pcm->mmap_info->type = SND_PCM_MMAP_KERNEL;
pcm->mmap_info->size = pcm->setup.mmap_bytes;
pcm->mmap_info->addr = mmap(NULL, pcm->setup.mmap_bytes,
PROT_WRITE | PROT_READ,
MAP_FILE|MAP_SHARED,
hw->fd, SND_PCM_MMAP_OFFSET_DATA);
if (pcm->mmap_info->addr == MAP_FAILED ||
pcm->mmap_info->addr == NULL) {
ERR("data mmap failed");
free(pcm->mmap_info);
pcm->mmap_info = 0;
return -errno;
}
pcm->mmap_info->u.kernel.fd = hw->fd;
}
pcm->mmap_data = ptr;
return 0;
}
static int snd_pcm_hw_munmap_status(snd_pcm_t *pcm)
{
if (munmap((void*)pcm->mmap_status, sizeof(*pcm->mmap_status)) < 0) {
snd_pcm_hw_t *hw = pcm->private;
if (munmap((void*)hw->mmap_status, sizeof(*hw->mmap_status)) < 0) {
ERR("status munmap failed");
return -errno;
}
@ -430,30 +435,46 @@ static int snd_pcm_hw_munmap_status(snd_pcm_t *pcm)
static int snd_pcm_hw_munmap_control(snd_pcm_t *pcm)
{
if (munmap(pcm->mmap_control, sizeof(*pcm->mmap_control)) < 0) {
snd_pcm_hw_t *hw = pcm->private;
if (munmap(hw->mmap_control, sizeof(*hw->mmap_control)) < 0) {
ERR("control munmap failed");
return -errno;
}
return 0;
}
static int snd_pcm_hw_munmap_data(snd_pcm_t *pcm)
static int snd_pcm_hw_munmap(snd_pcm_t *pcm)
{
snd_pcm_hw_t *hw = pcm->private;
if (hw->mmap_emulation)
free(pcm->mmap_data);
if (pcm->setup.mmap_shape == SND_PCM_MMAP_UNSPECIFIED)
free(pcm->mmap_info->addr);
else
if (munmap(pcm->mmap_data, pcm->setup.mmap_bytes) < 0) {
if (munmap(pcm->mmap_info->addr, pcm->mmap_info->size) < 0) {
ERR("data munmap failed");
return -errno;
}
pcm->mmap_info_count = 0;
free(pcm->mmap_info);
pcm->mmap_info = 0;
return 0;
}
static 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;
}
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)
{
snd_pcm_hw_t *hw = pcm->private;
if (hw->mmap_emulation && pcm->stream == SND_PCM_STREAM_PLAYBACK)
if (pcm->setup.mmap_shape == SND_PCM_MMAP_UNSPECIFIED && pcm->stream == SND_PCM_STREAM_PLAYBACK)
return snd_pcm_write_mmap(pcm, size);
snd_pcm_mmap_appl_forward(pcm, size);
return size;
@ -461,7 +482,6 @@ static ssize_t snd_pcm_hw_mmap_forward(snd_pcm_t *pcm, size_t size)
static ssize_t snd_pcm_hw_avail_update(snd_pcm_t *pcm)
{
snd_pcm_hw_t *hw = pcm->private;
size_t avail;
ssize_t err;
if (pcm->setup.ready_mode == SND_PCM_READY_ASAP ||
@ -475,7 +495,7 @@ static ssize_t snd_pcm_hw_avail_update(snd_pcm_t *pcm)
avail = snd_pcm_mmap_playback_avail(pcm);
} else {
avail = snd_pcm_mmap_capture_avail(pcm);
if (avail > 0 && hw->mmap_emulation) {
if (avail > 0 && pcm->setup.mmap_shape == SND_PCM_MMAP_UNSPECIFIED) {
err = snd_pcm_read_mmap(pcm, avail);
if (err < 0)
return err;
@ -488,12 +508,6 @@ static ssize_t snd_pcm_hw_avail_update(snd_pcm_t *pcm)
return avail;
}
static int snd_pcm_hw_poll_descriptor(snd_pcm_t *pcm)
{
snd_pcm_hw_t *hw = pcm->private;
return hw->fd;
}
static int snd_pcm_hw_channels_mask(snd_pcm_t *pcm ATTRIBUTE_UNUSED,
bitset_t *cmask ATTRIBUTE_UNUSED)
{
@ -514,7 +528,7 @@ static void snd_pcm_hw_dump(snd_pcm_t *pcm, FILE *fp)
}
}
struct snd_pcm_ops snd_pcm_hw_ops = {
snd_pcm_ops_t snd_pcm_hw_ops = {
close: snd_pcm_hw_close,
info: snd_pcm_hw_info,
params_info: snd_pcm_hw_params_info,
@ -526,15 +540,11 @@ struct snd_pcm_ops snd_pcm_hw_ops = {
dump: snd_pcm_hw_dump,
nonblock: snd_pcm_hw_nonblock,
async: snd_pcm_hw_async,
mmap_status: snd_pcm_hw_mmap_status,
mmap_control: snd_pcm_hw_mmap_control,
mmap_data: snd_pcm_hw_mmap_data,
munmap_status: snd_pcm_hw_munmap_status,
munmap_control: snd_pcm_hw_munmap_control,
munmap_data: snd_pcm_hw_munmap_data,
mmap: snd_pcm_hw_mmap,
munmap: snd_pcm_hw_munmap,
};
struct snd_pcm_fast_ops snd_pcm_hw_fast_ops = {
snd_pcm_fast_ops_t snd_pcm_hw_fast_ops = {
status: snd_pcm_hw_status,
state: snd_pcm_hw_state,
delay: snd_pcm_hw_delay,
@ -548,13 +558,12 @@ struct snd_pcm_fast_ops snd_pcm_hw_fast_ops = {
writen: snd_pcm_hw_writen,
readi: snd_pcm_hw_readi,
readn: snd_pcm_hw_readn,
poll_descriptor: snd_pcm_hw_poll_descriptor,
channels_mask: snd_pcm_hw_channels_mask,
avail_update: snd_pcm_hw_avail_update,
mmap_forward: snd_pcm_hw_mmap_forward,
};
int snd_pcm_hw_open_subdevice(snd_pcm_t **handlep, int card, int device, int subdevice, int stream, int mode)
int snd_pcm_hw_open_subdevice(snd_pcm_t **pcmp, int card, int device, int subdevice, int stream, int mode)
{
char filename[32];
char *filefmt;
@ -564,12 +573,12 @@ int snd_pcm_hw_open_subdevice(snd_pcm_t **handlep, int card, int device, int sub
snd_pcm_info_t info;
int fmode;
snd_ctl_t *ctl;
snd_pcm_t *handle;
snd_pcm_hw_t *hw;
snd_pcm_t *pcm = NULL;
snd_pcm_hw_t *hw = NULL;
assert(handlep);
assert(pcmp);
if ((ret = snd_ctl_hw_open(&ctl, card)) < 0)
if ((ret = snd_ctl_hw_open(&ctl, NULL, card)) < 0)
return ret;
switch (stream) {
@ -582,37 +591,35 @@ int snd_pcm_hw_open_subdevice(snd_pcm_t **handlep, int card, int device, int sub
default:
assert(0);
}
if ((ret = snd_ctl_pcm_prefer_subdevice(ctl, subdevice)) < 0)
goto __end;
ret = snd_ctl_pcm_prefer_subdevice(ctl, subdevice);
snd_ctl_close(ctl);
if (ret < 0)
return ret;
sprintf(filename, filefmt, card, device);
__again:
if (attempt++ > 3) {
ret = -EBUSY;
goto __end;
}
if (attempt++ > 3)
return -EBUSY;
fmode = O_RDWR;
if (mode & SND_PCM_NONBLOCK)
fmode |= O_NONBLOCK;
if (mode & SND_PCM_ASYNC)
fmode |= O_ASYNC;
if ((fd = open(filename, fmode)) < 0) {
ret = -errno;
goto __end;
}
if ((fd = open(filename, fmode)) < 0)
return -errno;
if (ioctl(fd, SND_PCM_IOCTL_PVERSION, &ver) < 0) {
ret = -errno;
goto __end;
goto _err;
}
if (SND_PROTOCOL_INCOMPATIBLE(ver, SND_PCM_VERSION_MAX)) {
ret = -SND_ERROR_INCOMPATIBLE_VERSION;
goto __end;
goto _err;
}
if (subdevice >= 0) {
memset(&info, 0, sizeof(info));
if (ioctl(fd, SND_PCM_IOCTL_INFO, &info) < 0) {
ret = -errno;
goto __end;
goto _err;
}
if (info.subdevice != subdevice) {
close(fd);
@ -622,54 +629,61 @@ int snd_pcm_hw_open_subdevice(snd_pcm_t **handlep, int card, int device, int sub
hw = calloc(1, sizeof(snd_pcm_hw_t));
if (!hw) {
ret = -ENOMEM;
goto __end;
goto _err;
}
hw->card = card;
hw->device = device;
hw->subdevice = subdevice;
hw->fd = fd;
handle = calloc(1, sizeof(snd_pcm_t));
if (!handle) {
free(hw);
pcm = calloc(1, sizeof(snd_pcm_t));
if (!pcm) {
ret = -ENOMEM;
goto __end;
goto _err;
}
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);
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;
}

View file

@ -114,11 +114,6 @@ static int snd_pcm_linear_params(snd_pcm_t *pcm, snd_pcm_params_t * params)
params->fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
return -EINVAL;
}
if (slave->mmap_data) {
err = snd_pcm_munmap_data(slave);
if (err < 0)
return err;
}
linear->cformat = params->format.sfmt;
linear->cxfer_mode = params->xfer_mode;
linear->cmmap_shape = params->mmap_shape;
@ -129,10 +124,6 @@ static int snd_pcm_linear_params(snd_pcm_t *pcm, snd_pcm_params_t * params)
params->format.sfmt = linear->cformat;
params->xfer_mode = linear->cxfer_mode;
params->mmap_shape = linear->cmmap_shape;
if (slave->valid_setup) {
int r = snd_pcm_mmap_data(slave, NULL);
assert(r >= 0);
}
return err;
}
@ -244,7 +235,7 @@ static void snd_pcm_linear_dump(snd_pcm_t *pcm, FILE *fp)
snd_pcm_dump(linear->plug.slave, fp);
}
struct snd_pcm_ops snd_pcm_linear_ops = {
snd_pcm_ops_t snd_pcm_linear_ops = {
close: snd_pcm_plugin_close,
info: snd_pcm_plugin_info,
params_info: snd_pcm_linear_params_info,
@ -256,20 +247,15 @@ struct snd_pcm_ops snd_pcm_linear_ops = {
dump: snd_pcm_linear_dump,
nonblock: snd_pcm_plugin_nonblock,
async: snd_pcm_plugin_async,
mmap_status: snd_pcm_plugin_mmap_status,
mmap_control: snd_pcm_plugin_mmap_control,
mmap_data: snd_pcm_plugin_mmap_data,
munmap_status: snd_pcm_plugin_munmap_status,
munmap_control: snd_pcm_plugin_munmap_control,
munmap_data: snd_pcm_plugin_munmap_data,
mmap: snd_pcm_plugin_mmap,
munmap: snd_pcm_plugin_munmap,
};
int snd_pcm_linear_open(snd_pcm_t **handlep, char *name, int sformat, snd_pcm_t *slave, int close_slave)
int snd_pcm_linear_open(snd_pcm_t **pcmp, char *name, int sformat, snd_pcm_t *slave, int close_slave)
{
snd_pcm_t *handle;
snd_pcm_t *pcm;
snd_pcm_linear_t *linear;
int err;
assert(handlep && slave);
assert(pcmp && slave);
if (snd_pcm_format_linear(sformat) != 1)
return -EINVAL;
linear = calloc(1, sizeof(snd_pcm_linear_t));
@ -282,27 +268,25 @@ int snd_pcm_linear_open(snd_pcm_t **handlep, char *name, int sformat, snd_pcm_t
linear->plug.slave = slave;
linear->plug.close_slave = close_slave;
handle = calloc(1, sizeof(snd_pcm_t));
if (!handle) {
pcm = calloc(1, sizeof(snd_pcm_t));
if (!pcm) {
free(linear);
return -ENOMEM;
}
if (name)
handle->name = strdup(name);
handle->type = SND_PCM_TYPE_LINEAR;
handle->stream = slave->stream;
handle->ops = &snd_pcm_linear_ops;
handle->op_arg = handle;
handle->fast_ops = &snd_pcm_plugin_fast_ops;
handle->fast_op_arg = handle;
handle->mode = slave->mode;
handle->private = linear;
err = snd_pcm_init(handle);
if (err < 0) {
snd_pcm_close(handle);
return err;
}
*handlep = handle;
pcm->name = strdup(name);
pcm->type = SND_PCM_TYPE_LINEAR;
pcm->stream = slave->stream;
pcm->mode = slave->mode;
pcm->ops = &snd_pcm_linear_ops;
pcm->op_arg = pcm;
pcm->fast_ops = &snd_pcm_plugin_fast_ops;
pcm->fast_op_arg = pcm;
pcm->private = linear;
pcm->poll_fd = slave->poll_fd;
pcm->hw_ptr = &linear->plug.hw_ptr;
pcm->appl_ptr = &linear->plug.appl_ptr;
*pcmp = pcm;
return 0;
}

View file

@ -32,7 +32,7 @@
#define ERR(args...) snd_pcm_error(__FILE__, __LINE__, __FUNCTION__, ##args)
#endif
struct snd_pcm_ops {
typedef struct {
int (*close)(snd_pcm_t *pcm);
int (*nonblock)(snd_pcm_t *pcm, int nonblock);
int (*async)(snd_pcm_t *pcm, int sig, pid_t pid);
@ -44,15 +44,11 @@ struct snd_pcm_ops {
int (*channel_params)(snd_pcm_t *pcm, snd_pcm_channel_params_t *params);
int (*channel_setup)(snd_pcm_t *pcm, snd_pcm_channel_setup_t *setup);
void (*dump)(snd_pcm_t *pcm, FILE *fp);
int (*mmap_status)(snd_pcm_t *pcm);
int (*mmap_control)(snd_pcm_t *pcm);
int (*mmap_data)(snd_pcm_t *pcm);
int (*munmap_status)(snd_pcm_t *pcm);
int (*munmap_control)(snd_pcm_t *pcm);
int (*munmap_data)(snd_pcm_t *pcm);
};
int (*mmap)(snd_pcm_t *pcm);
int (*munmap)(snd_pcm_t *pcm);
} snd_pcm_ops_t;
struct snd_pcm_fast_ops {
typedef struct {
int (*status)(snd_pcm_t *pcm, snd_pcm_status_t *status);
int (*prepare)(snd_pcm_t *pcm);
int (*start)(snd_pcm_t *pcm);
@ -66,43 +62,55 @@ struct snd_pcm_fast_ops {
ssize_t (*writen)(snd_pcm_t *pcm, void **bufs, size_t size);
ssize_t (*readi)(snd_pcm_t *pcm, void *buffer, size_t size);
ssize_t (*readn)(snd_pcm_t *pcm, void **bufs, size_t size);
int (*poll_descriptor)(snd_pcm_t *pcm);
int (*channels_mask)(snd_pcm_t *pcm, bitset_t *cmask);
ssize_t (*avail_update)(snd_pcm_t *pcm);
ssize_t (*mmap_forward)(snd_pcm_t *pcm, size_t size);
};
} snd_pcm_fast_ops_t;
typedef struct {
unsigned int index;
enum { SND_PCM_MMAP_KERNEL, SND_PCM_MMAP_USER } type;
void *addr;
size_t size;
union {
struct {
int shmid;
} user;
struct {
int fd;
} kernel;
} u;
} snd_pcm_mmap_info_t;
struct snd_pcm {
char *name;
snd_pcm_type_t type;
int stream;
int mode;
int poll_fd;
int valid_setup;
snd_pcm_setup_t setup;
size_t bits_per_sample;
size_t bits_per_frame;
volatile snd_pcm_mmap_status_t *mmap_status;
snd_pcm_mmap_control_t *mmap_control;
void *mmap_data;
size_t *appl_ptr;
volatile size_t *hw_ptr;
int mmap_auto;
size_t mmap_info_count;
snd_pcm_mmap_info_t *mmap_info;
snd_pcm_channel_area_t *running_areas;
snd_pcm_channel_area_t *stopped_areas;
struct snd_pcm_ops *ops;
struct snd_pcm_fast_ops *fast_ops;
snd_pcm_ops_t *ops;
snd_pcm_fast_ops_t *fast_ops;
snd_pcm_t *op_arg;
snd_pcm_t *fast_op_arg;
void *private;
};
int snd_pcm_init(snd_pcm_t *pcm);
void snd_pcm_areas_from_buf(snd_pcm_t *pcm, snd_pcm_channel_area_t *areas, void *buf);
void snd_pcm_areas_from_bufs(snd_pcm_t *pcm, snd_pcm_channel_area_t *areas, void **bufs);
int snd_pcm_mmap_status(snd_pcm_t *pcm, volatile snd_pcm_mmap_status_t **status);
int snd_pcm_mmap_control(snd_pcm_t *pcm, snd_pcm_mmap_control_t **control);
int snd_pcm_mmap_data(snd_pcm_t *pcm, void **buffer);
int snd_pcm_munmap_status(snd_pcm_t *pcm);
int snd_pcm_munmap_control(snd_pcm_t *pcm);
int snd_pcm_munmap_data(snd_pcm_t *pcm);
int snd_pcm_mmap(snd_pcm_t *pcm);
int snd_pcm_munmap(snd_pcm_t *pcm);
int snd_pcm_mmap_ready(snd_pcm_t *pcm);
ssize_t snd_pcm_mmap_appl_ptr(snd_pcm_t *pcm, off_t offset);
void snd_pcm_mmap_appl_backward(snd_pcm_t *pcm, size_t frames);
@ -130,7 +138,7 @@ ssize_t snd_pcm_write_mmap(snd_pcm_t *pcm, size_t size);
static inline size_t snd_pcm_mmap_playback_avail(snd_pcm_t *pcm)
{
ssize_t avail;
avail = pcm->mmap_status->hw_ptr + pcm->setup.buffer_size - pcm->mmap_control->appl_ptr;
avail = *pcm->hw_ptr + pcm->setup.buffer_size - *pcm->appl_ptr;
if (avail < 0)
avail += pcm->setup.boundary;
return avail;
@ -139,7 +147,7 @@ static inline size_t snd_pcm_mmap_playback_avail(snd_pcm_t *pcm)
static inline size_t snd_pcm_mmap_capture_avail(snd_pcm_t *pcm)
{
ssize_t avail;
avail = pcm->mmap_status->hw_ptr - pcm->mmap_control->appl_ptr;
avail = *pcm->hw_ptr - *pcm->appl_ptr;
if (avail < 0)
avail += pcm->setup.boundary;
return avail;
@ -156,7 +164,7 @@ static inline size_t snd_pcm_mmap_avail(snd_pcm_t *pcm)
static inline ssize_t snd_pcm_mmap_playback_hw_avail(snd_pcm_t *pcm)
{
ssize_t avail;
avail = pcm->mmap_status->hw_ptr + pcm->setup.buffer_size - pcm->mmap_control->appl_ptr;
avail = *pcm->hw_ptr + pcm->setup.buffer_size - *pcm->appl_ptr;
if (avail < 0)
avail += pcm->setup.boundary;
return pcm->setup.buffer_size - avail;
@ -165,7 +173,7 @@ static inline ssize_t snd_pcm_mmap_playback_hw_avail(snd_pcm_t *pcm)
static inline ssize_t snd_pcm_mmap_capture_hw_avail(snd_pcm_t *pcm)
{
ssize_t avail;
avail = pcm->mmap_status->hw_ptr - pcm->mmap_control->appl_ptr;
avail = *pcm->hw_ptr - *pcm->appl_ptr;
if (avail < 0)
avail += pcm->setup.boundary;
return pcm->setup.buffer_size - avail;

View file

@ -36,12 +36,11 @@ snd_pcm_channel_area_t *snd_pcm_mmap_areas(snd_pcm_t *pcm)
size_t snd_pcm_mmap_playback_xfer(snd_pcm_t *pcm, size_t frames)
{
snd_pcm_mmap_control_t *control = pcm->mmap_control;
size_t cont;
size_t avail = snd_pcm_mmap_playback_avail(pcm);
if (avail < frames)
frames = avail;
cont = pcm->setup.buffer_size - control->appl_ptr % pcm->setup.buffer_size;
cont = pcm->setup.buffer_size - *pcm->appl_ptr % pcm->setup.buffer_size;
if (cont < frames)
frames = cont;
return frames;
@ -49,12 +48,11 @@ size_t snd_pcm_mmap_playback_xfer(snd_pcm_t *pcm, size_t frames)
size_t snd_pcm_mmap_capture_xfer(snd_pcm_t *pcm, size_t frames)
{
snd_pcm_mmap_control_t *control = pcm->mmap_control;
size_t cont;
size_t avail = snd_pcm_mmap_capture_avail(pcm);
if (avail < frames)
frames = avail;
cont = pcm->setup.buffer_size - control->appl_ptr % pcm->setup.buffer_size;
cont = pcm->setup.buffer_size - *pcm->appl_ptr % pcm->setup.buffer_size;
if (cont < frames)
frames = cont;
return frames;
@ -63,7 +61,6 @@ size_t snd_pcm_mmap_capture_xfer(snd_pcm_t *pcm, size_t frames)
size_t snd_pcm_mmap_xfer(snd_pcm_t *pcm, size_t frames)
{
assert(pcm);
assert(pcm->mmap_status && pcm->mmap_control);
if (pcm->stream == SND_PCM_STREAM_PLAYBACK)
return snd_pcm_mmap_playback_xfer(pcm, frames);
else
@ -73,51 +70,49 @@ size_t snd_pcm_mmap_xfer(snd_pcm_t *pcm, size_t frames)
size_t snd_pcm_mmap_offset(snd_pcm_t *pcm)
{
assert(pcm);
assert(pcm->mmap_control);
return pcm->mmap_control->appl_ptr % pcm->setup.buffer_size;
return *pcm->appl_ptr % pcm->setup.buffer_size;
}
size_t snd_pcm_mmap_hw_offset(snd_pcm_t *pcm)
{
assert(pcm);
assert(pcm->mmap_status);
return pcm->mmap_status->hw_ptr % pcm->setup.buffer_size;
return *pcm->hw_ptr % pcm->setup.buffer_size;
}
void snd_pcm_mmap_appl_backward(snd_pcm_t *pcm, size_t frames)
{
ssize_t appl_ptr = pcm->mmap_control->appl_ptr;
ssize_t appl_ptr = *pcm->appl_ptr;
appl_ptr -= frames;
if (appl_ptr < 0)
appl_ptr += pcm->setup.boundary;
pcm->mmap_control->appl_ptr = appl_ptr;
*pcm->appl_ptr = appl_ptr;
}
void snd_pcm_mmap_appl_forward(snd_pcm_t *pcm, size_t frames)
{
size_t appl_ptr = pcm->mmap_control->appl_ptr;
size_t appl_ptr = *pcm->appl_ptr;
appl_ptr += frames;
if (appl_ptr >= pcm->setup.boundary)
appl_ptr -= pcm->setup.boundary;
pcm->mmap_control->appl_ptr = appl_ptr;
*pcm->appl_ptr = appl_ptr;
}
void snd_pcm_mmap_hw_backward(snd_pcm_t *pcm, size_t frames)
{
ssize_t hw_ptr = pcm->mmap_status->hw_ptr;
ssize_t hw_ptr = *pcm->hw_ptr;
hw_ptr -= frames;
if (hw_ptr < 0)
hw_ptr += pcm->setup.boundary;
pcm->mmap_status->hw_ptr = hw_ptr;
*pcm->hw_ptr = hw_ptr;
}
void snd_pcm_mmap_hw_forward(snd_pcm_t *pcm, size_t frames)
{
size_t hw_ptr = pcm->mmap_status->hw_ptr;
size_t hw_ptr = *pcm->hw_ptr;
hw_ptr += frames;
if (hw_ptr >= pcm->setup.boundary)
hw_ptr -= pcm->setup.boundary;
pcm->mmap_status->hw_ptr = hw_ptr;
*pcm->hw_ptr = hw_ptr;
}
ssize_t snd_pcm_mmap_write_areas(snd_pcm_t *pcm,
@ -216,32 +211,6 @@ ssize_t snd_pcm_mmap_readn(snd_pcm_t *pcm, void **bufs, size_t size)
snd_pcm_mmap_read_areas);
}
int snd_pcm_mmap_status(snd_pcm_t *pcm, volatile snd_pcm_mmap_status_t **status)
{
int err;
assert(pcm);
if (!pcm->mmap_status) {
if ((err = pcm->ops->mmap_status(pcm->op_arg)) < 0)
return err;
}
if (status)
*status = pcm->mmap_status;
return 0;
}
int snd_pcm_mmap_control(snd_pcm_t *pcm, snd_pcm_mmap_control_t **control)
{
int err;
assert(pcm);
if (!pcm->mmap_control) {
if ((err = pcm->ops->mmap_control(pcm->op_arg)) < 0)
return err;
}
if (control)
*control = pcm->mmap_control;
return 0;
}
int snd_pcm_mmap_get_areas(snd_pcm_t *pcm, snd_pcm_channel_area_t *stopped_areas, snd_pcm_channel_area_t *running_areas)
{
snd_pcm_channel_setup_t setup;
@ -249,7 +218,7 @@ int snd_pcm_mmap_get_areas(snd_pcm_t *pcm, snd_pcm_channel_area_t *stopped_areas
unsigned int channel;
int err;
assert(pcm);
assert(pcm->mmap_data);
assert(pcm->mmap_info);
if (!pcm->running_areas) {
r = calloc(pcm->setup.format.channels, sizeof(*r));
s = calloc(pcm->setup.format.channels, sizeof(*s));
@ -274,75 +243,36 @@ int snd_pcm_mmap_get_areas(snd_pcm_t *pcm, snd_pcm_channel_area_t *stopped_areas
return 0;
}
int snd_pcm_mmap_data(snd_pcm_t *pcm, void **data)
int snd_pcm_mmap(snd_pcm_t *pcm)
{
int err;
assert(pcm);
assert(pcm->valid_setup);
if (pcm->mmap_data) {
if (data)
*data = pcm->mmap_data;
if (pcm->mmap_info)
return 0;
}
if ((err = pcm->ops->mmap_data(pcm->op_arg)) < 0)
if ((err = pcm->ops->mmap(pcm->op_arg)) < 0)
return err;
if (data)
*data = pcm->mmap_data;
err = snd_pcm_mmap_get_areas(pcm, NULL, NULL);
if (err < 0)
return err;
return 0;
}
int snd_pcm_munmap_status(snd_pcm_t *pcm)
int snd_pcm_munmap(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 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;

View file

@ -276,11 +276,6 @@ static int snd_pcm_mulaw_params(snd_pcm_t *pcm, snd_pcm_params_t * params)
params->fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
return -EINVAL;
}
if (slave->mmap_data) {
err = snd_pcm_munmap_data(slave);
if (err < 0)
return err;
}
mulaw->cformat = params->format.sfmt;
mulaw->cxfer_mode = params->xfer_mode;
mulaw->cmmap_shape = params->mmap_shape;
@ -291,10 +286,6 @@ static int snd_pcm_mulaw_params(snd_pcm_t *pcm, snd_pcm_params_t * params)
params->format.sfmt = mulaw->cformat;
params->xfer_mode = mulaw->cxfer_mode;
params->mmap_shape = mulaw->cmmap_shape;
if (slave->valid_setup) {
int r = snd_pcm_mmap_data(slave, NULL);
assert(r >= 0);
}
return err;
}
@ -418,7 +409,7 @@ static void snd_pcm_mulaw_dump(snd_pcm_t *pcm, FILE *fp)
snd_pcm_dump(mulaw->plug.slave, fp);
}
struct snd_pcm_ops snd_pcm_mulaw_ops = {
snd_pcm_ops_t snd_pcm_mulaw_ops = {
close: snd_pcm_plugin_close,
info: snd_pcm_plugin_info,
params_info: snd_pcm_mulaw_params_info,
@ -430,20 +421,15 @@ struct snd_pcm_ops snd_pcm_mulaw_ops = {
dump: snd_pcm_mulaw_dump,
nonblock: snd_pcm_plugin_nonblock,
async: snd_pcm_plugin_async,
mmap_status: snd_pcm_plugin_mmap_status,
mmap_control: snd_pcm_plugin_mmap_control,
mmap_data: snd_pcm_plugin_mmap_data,
munmap_status: snd_pcm_plugin_munmap_status,
munmap_control: snd_pcm_plugin_munmap_control,
munmap_data: snd_pcm_plugin_munmap_data,
mmap: snd_pcm_plugin_mmap,
munmap: snd_pcm_plugin_munmap,
};
int snd_pcm_mulaw_open(snd_pcm_t **handlep, char *name, int sformat, snd_pcm_t *slave, int close_slave)
int snd_pcm_mulaw_open(snd_pcm_t **pcmp, char *name, int sformat, snd_pcm_t *slave, int close_slave)
{
snd_pcm_t *handle;
snd_pcm_t *pcm;
snd_pcm_mulaw_t *mulaw;
int err;
assert(handlep && slave);
assert(pcmp && slave);
if (snd_pcm_format_linear(sformat) != 1 &&
sformat != SND_PCM_SFMT_MU_LAW)
return -EINVAL;
@ -457,27 +443,25 @@ int snd_pcm_mulaw_open(snd_pcm_t **handlep, char *name, int sformat, snd_pcm_t *
mulaw->plug.slave = slave;
mulaw->plug.close_slave = close_slave;
handle = calloc(1, sizeof(snd_pcm_t));
if (!handle) {
pcm = calloc(1, sizeof(snd_pcm_t));
if (!pcm) {
free(mulaw);
return -ENOMEM;
}
if (name)
handle->name = strdup(name);
handle->type = SND_PCM_TYPE_MULAW;
handle->stream = slave->stream;
handle->ops = &snd_pcm_mulaw_ops;
handle->op_arg = handle;
handle->fast_ops = &snd_pcm_plugin_fast_ops;
handle->fast_op_arg = handle;
handle->mode = slave->mode;
handle->private = mulaw;
err = snd_pcm_init(handle);
if (err < 0) {
snd_pcm_close(handle);
return err;
}
*handlep = handle;
pcm->name = strdup(name);
pcm->type = SND_PCM_TYPE_MULAW;
pcm->stream = slave->stream;
pcm->mode = slave->mode;
pcm->ops = &snd_pcm_mulaw_ops;
pcm->op_arg = pcm;
pcm->fast_ops = &snd_pcm_plugin_fast_ops;
pcm->fast_op_arg = pcm;
pcm->private = mulaw;
pcm->poll_fd = slave->poll_fd;
pcm->hw_ptr = &mulaw->plug.hw_ptr;
pcm->appl_ptr = &mulaw->plug.appl_ptr;
*pcmp = pcm;
return 0;
}

View file

@ -152,6 +152,60 @@ static int snd_pcm_multi_params_info(snd_pcm_t *pcm, snd_pcm_params_info_t *info
return 0;
}
static int snd_pcm_multi_mmap(snd_pcm_t *pcm)
{
snd_pcm_multi_t *multi = pcm->private;
unsigned int i;
size_t count = 0;
for (i = 0; i < multi->slaves_count; ++i) {
snd_pcm_t *slave = multi->slaves[i].pcm;
snd_pcm_setup_t *setup;
int err = snd_pcm_mmap(slave);
if (err < 0)
return err;
count += slave->mmap_info_count;
setup = &slave->setup;
if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
snd_pcm_channel_area_t r[setup->format.channels];
snd_pcm_channel_area_t s[setup->format.channels];
err = snd_pcm_mmap_get_areas(slave, s, r);
if (err < 0)
return err;
err = snd_pcm_areas_silence(s, 0, setup->format.channels, setup->buffer_size, setup->format.sfmt);
if (err < 0)
return err;
err = snd_pcm_areas_silence(r, 0, setup->format.channels, setup->buffer_size, setup->format.sfmt);
if (err < 0)
return err;
}
}
pcm->mmap_info_count = count;
pcm->mmap_info = malloc(count * sizeof(*pcm->mmap_info));
count = 0;
for (i = 0; i < multi->slaves_count; ++i) {
snd_pcm_t *slave = multi->slaves[i].pcm;
memcpy(&pcm->mmap_info[count], slave->mmap_info, slave->mmap_info_count * sizeof(*pcm->mmap_info));
count += slave->mmap_info_count;
}
return 0;
}
static int snd_pcm_multi_munmap(snd_pcm_t *pcm)
{
snd_pcm_multi_t *multi = pcm->private;
unsigned int i;
for (i = 0; i < multi->slaves_count; ++i) {
snd_pcm_t *slave = multi->slaves[i].pcm;
int err = snd_pcm_munmap(slave);
if (err < 0)
return err;
}
pcm->mmap_info_count = 0;
free(pcm->mmap_info);
pcm->mmap_info = 0;
return 0;
}
static int snd_pcm_multi_params(snd_pcm_t *pcm, snd_pcm_params_t *params)
{
snd_pcm_multi_t *multi = pcm->private;
@ -166,11 +220,6 @@ static int snd_pcm_multi_params(snd_pcm_t *pcm, snd_pcm_params_t *params)
p = *params;
for (i = 0; i < multi->slaves_count; ++i) {
snd_pcm_t *slave = multi->slaves[i].pcm;
if (slave->mmap_data) {
err = snd_pcm_munmap_data(slave);
if (err < 0)
return err;
}
p.format.channels = multi->slaves[i].channels_count;
err = snd_pcm_params(slave, &p);
if (err < 0) {
@ -179,14 +228,6 @@ static int snd_pcm_multi_params(snd_pcm_t *pcm, snd_pcm_params_t *params)
break;
}
}
for (i = 0; i < multi->slaves_count; ++i) {
snd_pcm_t *slave = multi->slaves[i].pcm;
snd_pcm_mmap_data(slave, NULL);
if (pcm->stream == SND_PCM_STREAM_PLAYBACK &&
err == 0)
snd_pcm_areas_silence(snd_pcm_mmap_areas(slave), 0, slave->setup.format.channels,
slave->setup.buffer_size, slave->setup.format.sfmt);
}
if (err == 0)
multi->xfer_mode = params->xfer_mode;
return err;
@ -346,73 +387,6 @@ static ssize_t snd_pcm_multi_rewind(snd_pcm_t *pcm, size_t frames)
return frames;
}
static int snd_pcm_multi_mmap_status(snd_pcm_t *pcm)
{
snd_pcm_multi_t *multi = pcm->private;
pcm->mmap_status = multi->slaves[0].pcm->mmap_status;
return 0;
}
static int snd_pcm_multi_mmap_control(snd_pcm_t *pcm)
{
snd_pcm_multi_t *multi = pcm->private;
pcm->mmap_control = multi->slaves[0].pcm->mmap_control;
return 0;
}
static int snd_pcm_multi_mmap_data(snd_pcm_t *pcm)
{
snd_pcm_multi_t *multi = pcm->private;
unsigned int i;
for (i = 0; i < multi->slaves_count; ++i) {
snd_pcm_t *slave = multi->slaves[i].pcm;
int err = snd_pcm_mmap_data(slave, 0);
snd_pcm_setup_t *setup;
if (err < 0)
return err;
setup = &slave->setup;
if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
snd_pcm_channel_area_t r[setup->format.channels];
snd_pcm_channel_area_t s[setup->format.channels];
err = snd_pcm_mmap_get_areas(slave, s, r);
if (err < 0)
return err;
err = snd_pcm_areas_silence(s, 0, setup->format.channels, setup->buffer_size, setup->format.sfmt);
if (err < 0)
return err;
err = snd_pcm_areas_silence(r, 0, setup->format.channels, setup->buffer_size, setup->format.sfmt);
if (err < 0)
return err;
}
}
pcm->mmap_data = multi->slaves[0].pcm->mmap_data;
return 0;
}
static int snd_pcm_multi_munmap_status(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
{
return 0;
}
static int snd_pcm_multi_munmap_control(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
{
return 0;
}
static int snd_pcm_multi_munmap_data(snd_pcm_t *pcm)
{
snd_pcm_multi_t *multi = pcm->private;
unsigned int i;
int ret = 0;
for (i = 0; i < multi->slaves_count; ++i) {
snd_pcm_t *slave = multi->slaves[i].pcm;
int err = snd_pcm_munmap_data(slave);
if (err < 0)
ret = err;
}
return ret;
}
static ssize_t snd_pcm_multi_mmap_forward(snd_pcm_t *pcm, size_t size)
{
snd_pcm_multi_t *multi = pcm->private;
@ -500,7 +474,7 @@ static void snd_pcm_multi_dump(snd_pcm_t *pcm, FILE *fp)
}
}
struct snd_pcm_ops snd_pcm_multi_ops = {
snd_pcm_ops_t snd_pcm_multi_ops = {
close: snd_pcm_multi_close,
info: snd_pcm_multi_info,
params_info: snd_pcm_multi_params_info,
@ -512,15 +486,11 @@ struct snd_pcm_ops snd_pcm_multi_ops = {
dump: snd_pcm_multi_dump,
nonblock: snd_pcm_multi_nonblock,
async: snd_pcm_multi_async,
mmap_status: snd_pcm_multi_mmap_status,
mmap_control: snd_pcm_multi_mmap_control,
mmap_data: snd_pcm_multi_mmap_data,
munmap_status: snd_pcm_multi_munmap_status,
munmap_control: snd_pcm_multi_munmap_control,
munmap_data: snd_pcm_multi_munmap_data,
mmap: snd_pcm_multi_mmap,
munmap: snd_pcm_multi_munmap,
};
struct snd_pcm_fast_ops snd_pcm_multi_fast_ops = {
snd_pcm_fast_ops_t snd_pcm_multi_fast_ops = {
status: snd_pcm_multi_status,
state: snd_pcm_multi_state,
delay: snd_pcm_multi_delay,
@ -534,28 +504,26 @@ struct snd_pcm_fast_ops snd_pcm_multi_fast_ops = {
readi: snd_pcm_mmap_readi,
readn: snd_pcm_mmap_readn,
rewind: snd_pcm_multi_rewind,
poll_descriptor: snd_pcm_multi_poll_descriptor,
channels_mask: snd_pcm_multi_channels_mask,
avail_update: snd_pcm_multi_avail_update,
mmap_forward: snd_pcm_multi_mmap_forward,
};
int snd_pcm_multi_open(snd_pcm_t **handlep, char *name,
int snd_pcm_multi_open(snd_pcm_t **pcmp, char *name,
size_t slaves_count,
snd_pcm_t **slaves_handle, size_t *schannels_count,
snd_pcm_t **slaves_pcm, size_t *schannels_count,
size_t channels_count,
int *sidxs, unsigned int *schannels,
int close_slaves)
{
snd_pcm_t *handle;
snd_pcm_t *pcm;
snd_pcm_multi_t *multi;
unsigned int i;
int err;
int stream;
char slave_map[32][32] = { { 0 } };
assert(handlep);
assert(slaves_count > 0 && slaves_handle && schannels_count);
assert(pcmp);
assert(slaves_count > 0 && slaves_pcm && schannels_count);
assert(channels_count > 0 && sidxs && schannels);
multi = calloc(1, sizeof(snd_pcm_multi_t));
@ -563,7 +531,7 @@ int snd_pcm_multi_open(snd_pcm_t **handlep, char *name,
return -ENOMEM;
}
stream = slaves_handle[0]->stream;
stream = slaves_pcm[0]->stream;
multi->slaves_count = slaves_count;
multi->slaves = calloc(slaves_count, sizeof(*multi->slaves));
@ -571,12 +539,12 @@ int snd_pcm_multi_open(snd_pcm_t **handlep, char *name,
multi->channels = calloc(channels_count, sizeof(*multi->channels));
for (i = 0; i < slaves_count; ++i) {
snd_pcm_multi_slave_t *slave = &multi->slaves[i];
assert(slaves_handle[i]->stream == stream);
slave->pcm = slaves_handle[i];
assert(slaves_pcm[i]->stream == stream);
slave->pcm = slaves_pcm[i];
slave->channels_count = schannels_count[i];
slave->close_slave = close_slaves;
if (i != 0)
snd_pcm_link(slaves_handle[i-1], slaves_handle[i]);
snd_pcm_link(slaves_pcm[i-1], slaves_pcm[i]);
}
for (i = 0; i < channels_count; ++i) {
snd_pcm_multi_channel_t *bind = &multi->channels[i];
@ -591,27 +559,26 @@ int snd_pcm_multi_open(snd_pcm_t **handlep, char *name,
}
multi->channels_count = channels_count;
handle = calloc(1, sizeof(snd_pcm_t));
if (!handle) {
pcm = calloc(1, sizeof(snd_pcm_t));
if (!pcm) {
free(multi);
return -ENOMEM;
}
if (name)
handle->name = strdup(name);
handle->type = SND_PCM_TYPE_MULTI;
handle->stream = stream;
handle->mode = multi->slaves[0].pcm->mode;
handle->ops = &snd_pcm_multi_ops;
handle->op_arg = handle;
handle->fast_ops = &snd_pcm_multi_fast_ops;
handle->fast_op_arg = handle;
handle->private = multi;
err = snd_pcm_init(handle);
if (err < 0) {
snd_pcm_close(handle);
return err;
}
*handlep = handle;
pcm->name = strdup(name);
pcm->type = SND_PCM_TYPE_MULTI;
pcm->stream = stream;
pcm->mode = multi->slaves[0].pcm->mode;
pcm->mmap_auto = 1;
pcm->ops = &snd_pcm_multi_ops;
pcm->op_arg = pcm;
pcm->fast_ops = &snd_pcm_multi_fast_ops;
pcm->fast_op_arg = pcm;
pcm->private = multi;
pcm->poll_fd = multi->slaves[0].pcm->poll_fd;
pcm->hw_ptr = multi->slaves[0].pcm->hw_ptr;
pcm->appl_ptr = multi->slaves[0].pcm->appl_ptr;
*pcmp = pcm;
return 0;
}

View file

@ -323,6 +323,7 @@ static int snd_pcm_plug_change_rate(snd_pcm_t *pcm, snd_pcm_t **new, snd_pcm_for
err = snd_pcm_rate_open(new, NULL, slv->sfmt, slv->rate, plug->slave, plug->slave != plug->req_slave);
if (err < 0)
return err;
(*new)->mmap_auto = 1;
slv->rate = clt->rate;
if (snd_pcm_format_linear(clt->sfmt))
slv->sfmt = clt->sfmt;
@ -387,6 +388,7 @@ static int snd_pcm_plug_change_channels(snd_pcm_t *pcm, snd_pcm_t **new, snd_pcm
err = snd_pcm_route_open(new, NULL, slv->sfmt, slv->channels, ttable, tt_ssize, tt_cused, tt_sused, plug->slave, plug->slave != plug->req_slave);
if (err < 0)
return err;
(*new)->mmap_auto = 1;
slv->channels = clt->channels;
if (snd_pcm_format_linear(clt->sfmt))
slv->sfmt = clt->sfmt;
@ -397,7 +399,7 @@ static int snd_pcm_plug_change_format(snd_pcm_t *pcm, snd_pcm_t **new, snd_pcm_f
{
snd_pcm_plug_t *plug = pcm->private;
int err, cfmt;
int (*f)(snd_pcm_t **handle, char *name, int sformat, snd_pcm_t *slave, int close_slave);
int (*f)(snd_pcm_t **pcm, char *name, int sformat, snd_pcm_t *slave, int close_slave);
if (snd_pcm_format_linear(slv->sfmt)) {
/* Conversion is done in another plugin */
if (clt->sfmt == slv->sfmt ||
@ -451,6 +453,7 @@ static int snd_pcm_plug_change_format(snd_pcm_t *pcm, snd_pcm_t **new, snd_pcm_f
err = f(new, NULL, slv->sfmt, plug->slave, plug->slave != plug->req_slave);
if (err < 0)
return err;
(*new)->mmap_auto = 1;
slv->sfmt = cfmt;
return 1;
}
@ -489,6 +492,7 @@ static int snd_pcm_plug_insert_plugins(snd_pcm_t *pcm,
}
k++;
}
plug->slave->mmap_auto = 0;
assert(0);
return 0;
}
@ -563,15 +567,16 @@ static int snd_pcm_plug_params(snd_pcm_t *pcm, snd_pcm_params_t *params)
return err;
err = snd_pcm_params(plug->slave, params);
if (err < 0)
if (err < 0) {
snd_pcm_plug_clear(pcm);
else {
assert(slave->setup.format.sfmt == slave_format->sfmt);
assert(slave->setup.format.channels == slave_format->channels);
assert(slave->setup.format.rate == slave_format->rate);
return err;
}
return err;
assert(slave->setup.format.sfmt == slave_format->sfmt);
assert(slave->setup.format.channels == slave_format->channels);
assert(slave->setup.format.rate == slave_format->rate);
pcm->hw_ptr = slave->hw_ptr;
pcm->appl_ptr = slave->appl_ptr;
return 0;
}
static int snd_pcm_plug_setup(snd_pcm_t *pcm, snd_pcm_setup_t *setup)
@ -598,53 +603,27 @@ static int snd_pcm_plug_channel_setup(snd_pcm_t *pcm, snd_pcm_channel_setup_t *s
return snd_pcm_channel_setup(plug->slave, setup);
}
static int snd_pcm_plug_mmap_status(snd_pcm_t *pcm)
static int snd_pcm_plug_mmap(snd_pcm_t *pcm)
{
snd_pcm_plug_t *plug = pcm->private;
int err = snd_pcm_mmap_status(plug->slave, NULL);
int err = snd_pcm_mmap(plug->slave);
if (err < 0)
return err;
pcm->mmap_status = plug->slave->mmap_status;
pcm->mmap_info_count = plug->slave->mmap_info_count;
pcm->mmap_info = plug->slave->mmap_info;
return 0;
}
static int snd_pcm_plug_mmap_control(snd_pcm_t *pcm)
static int snd_pcm_plug_munmap(snd_pcm_t *pcm)
{
snd_pcm_plug_t *plug = pcm->private;
int err = snd_pcm_mmap_control(plug->slave, NULL);
int err = snd_pcm_munmap(plug->slave);
if (err < 0)
return err;
pcm->mmap_control = plug->slave->mmap_control;
pcm->mmap_info_count = 0;
pcm->mmap_info = 0;
return 0;
}
static int snd_pcm_plug_mmap_data(snd_pcm_t *pcm)
{
snd_pcm_plug_t *plug = pcm->private;
int err = snd_pcm_mmap_data(plug->slave, NULL);
if (err < 0)
return err;
pcm->mmap_data = plug->slave->mmap_data;
return 0;
}
static int snd_pcm_plug_munmap_status(snd_pcm_t *pcm)
{
snd_pcm_plug_t *plug = pcm->private;
return snd_pcm_munmap_status(plug->slave);
}
static int snd_pcm_plug_munmap_control(snd_pcm_t *pcm)
{
snd_pcm_plug_t *plug = pcm->private;
return snd_pcm_munmap_control(plug->slave);
}
static int snd_pcm_plug_munmap_data(snd_pcm_t *pcm)
{
snd_pcm_plug_t *plug = pcm->private;
return snd_pcm_munmap_data(plug->slave);
}
static void snd_pcm_plug_dump(snd_pcm_t *pcm, FILE *fp)
{
@ -653,7 +632,7 @@ static void snd_pcm_plug_dump(snd_pcm_t *pcm, FILE *fp)
snd_pcm_dump(plug->slave, fp);
}
struct snd_pcm_ops snd_pcm_plug_ops = {
snd_pcm_ops_t snd_pcm_plug_ops = {
close: snd_pcm_plug_close,
info: snd_pcm_plug_info,
params_info: snd_pcm_plug_params_info,
@ -665,25 +644,20 @@ struct snd_pcm_ops snd_pcm_plug_ops = {
dump: snd_pcm_plug_dump,
nonblock: snd_pcm_plug_nonblock,
async: snd_pcm_plug_async,
mmap_status: snd_pcm_plug_mmap_status,
mmap_control: snd_pcm_plug_mmap_control,
mmap_data: snd_pcm_plug_mmap_data,
munmap_status: snd_pcm_plug_munmap_status,
munmap_control: snd_pcm_plug_munmap_control,
munmap_data: snd_pcm_plug_munmap_data,
mmap: snd_pcm_plug_mmap,
munmap: snd_pcm_plug_munmap,
};
int snd_pcm_plug_open(snd_pcm_t **handlep,
int snd_pcm_plug_open(snd_pcm_t **pcmp,
char *name,
ttable_entry_t *ttable,
unsigned int tt_ssize,
unsigned int tt_cused, unsigned int tt_sused,
snd_pcm_t *slave, int close_slave)
{
snd_pcm_t *handle;
snd_pcm_t *pcm;
snd_pcm_plug_t *plug;
int err;
assert(handlep && slave);
assert(pcmp && slave);
plug = calloc(1, sizeof(snd_pcm_plug_t));
if (!plug)
return -ENOMEM;
@ -694,44 +668,42 @@ int snd_pcm_plug_open(snd_pcm_t **handlep,
plug->tt_cused = tt_cused;
plug->tt_sused = tt_sused;
handle = calloc(1, sizeof(snd_pcm_t));
if (!handle) {
pcm = calloc(1, sizeof(snd_pcm_t));
if (!pcm) {
free(plug);
return -ENOMEM;
}
if (name)
handle->name = strdup(name);
handle->type = SND_PCM_TYPE_PLUG;
handle->stream = slave->stream;
handle->ops = &snd_pcm_plug_ops;
handle->op_arg = handle;
handle->fast_ops = slave->fast_ops;
handle->fast_op_arg = slave->fast_op_arg;
handle->mode = slave->mode;
handle->private = plug;
err = snd_pcm_init(handle);
if (err < 0) {
snd_pcm_close(handle);
return err;
}
*handlep = handle;
pcm->name = strdup(name);
pcm->type = SND_PCM_TYPE_PLUG;
pcm->stream = slave->stream;
pcm->mode = slave->mode;
pcm->ops = &snd_pcm_plug_ops;
pcm->op_arg = pcm;
pcm->fast_ops = slave->fast_ops;
pcm->fast_op_arg = slave->fast_op_arg;
pcm->private = plug;
pcm->poll_fd = slave->poll_fd;
pcm->hw_ptr = slave->hw_ptr;
pcm->appl_ptr = slave->appl_ptr;
*pcmp = pcm;
return 0;
}
int snd_pcm_plug_open_subdevice(snd_pcm_t **handlep, int card, int device, int subdevice, int stream, int mode)
int snd_pcm_plug_open_subdevice(snd_pcm_t **pcmp, int card, int device, int subdevice, int stream, int mode)
{
snd_pcm_t *slave;
int err;
err = snd_pcm_hw_open_subdevice(&slave, card, device, subdevice, stream, mode);
if (err < 0)
return err;
return snd_pcm_plug_open(handlep, NULL, 0, 0, 0, 0, slave, 1);
return snd_pcm_plug_open(pcmp, NULL, 0, 0, 0, 0, slave, 1);
}
int snd_pcm_plug_open_device(snd_pcm_t **handlep, int card, int device, int stream, int mode)
int snd_pcm_plug_open_device(snd_pcm_t **pcmp, int card, int device, int stream, int mode)
{
return snd_pcm_plug_open_subdevice(handlep, card, device, -1, stream, mode);
return snd_pcm_plug_open_subdevice(pcmp, card, device, -1, stream, mode);
}
#define MAX_CHANNELS 32

View file

@ -70,12 +70,14 @@ int snd_pcm_plugin_channel_setup(snd_pcm_t *pcm, snd_pcm_channel_setup_t * setup
err = snd_pcm_channel_setup(plugin->slave, setup);
if (err < 0)
return err;
if (!pcm->mmap_info)
return 0;
if (pcm->setup.mmap_shape == SND_PCM_MMAP_INTERLEAVED) {
setup->running_area.addr = pcm->mmap_data;
setup->running_area.addr = pcm->mmap_info->addr;
setup->running_area.first = setup->channel * pcm->bits_per_sample;
setup->running_area.step = pcm->bits_per_frame;
} else {
setup->running_area.addr = pcm->mmap_data + setup->channel * pcm->setup.buffer_size * pcm->bits_per_sample / 8;
setup->running_area.addr = pcm->mmap_info->addr + setup->channel * pcm->setup.buffer_size * pcm->bits_per_sample / 8;
setup->running_area.first = 0;
setup->running_area.step = pcm->bits_per_sample;
}
@ -118,8 +120,8 @@ int snd_pcm_plugin_prepare(snd_pcm_t *pcm)
int err = snd_pcm_prepare(plugin->slave);
if (err < 0)
return err;
plugin->mmap_status.hw_ptr = 0;
plugin->mmap_control.appl_ptr = 0;
plugin->hw_ptr = 0;
plugin->appl_ptr = 0;
if (plugin->init) {
err = plugin->init(pcm);
if (err < 0)
@ -276,7 +278,7 @@ ssize_t snd_pcm_plugin_avail_update(snd_pcm_t *pcm)
if (slave_size <= 0)
return slave_size;
if (pcm->stream == SND_PCM_STREAM_PLAYBACK ||
!pcm->mmap_data)
!pcm->mmap_info)
return plugin->client_frames ?
plugin->client_frames(pcm, slave_size) : slave_size;
client_xfer = snd_pcm_mmap_capture_avail(pcm);
@ -301,42 +303,39 @@ ssize_t snd_pcm_plugin_avail_update(snd_pcm_t *pcm)
return err;
}
int snd_pcm_plugin_mmap_status(snd_pcm_t *pcm)
int snd_pcm_plugin_mmap(snd_pcm_t *pcm)
{
snd_pcm_plugin_t *plugin = pcm->private;
pcm->mmap_status = &plugin->mmap_status;
return 0;
}
int snd_pcm_plugin_mmap_control(snd_pcm_t *pcm)
{
snd_pcm_plugin_t *plugin = pcm->private;
pcm->mmap_control = &plugin->mmap_control;
return 0;
}
int snd_pcm_plugin_mmap_data(snd_pcm_t *pcm)
{
void *ptr = malloc(snd_pcm_frames_to_bytes(pcm, pcm->setup.buffer_size));
if (!ptr)
snd_pcm_t *slave = plugin->slave;
int err = snd_pcm_mmap(slave);
if (err < 0)
return err;
pcm->mmap_info = calloc(1, sizeof(*pcm->mmap_info));
if (!pcm->mmap_info)
return -ENOMEM;
pcm->mmap_data = ptr;
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_status(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
int snd_pcm_plugin_munmap(snd_pcm_t *pcm)
{
return 0;
}
int snd_pcm_plugin_munmap_control(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
{
return 0;
}
int snd_pcm_plugin_munmap_data(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
{
free(pcm->mmap_data);
snd_pcm_plugin_t *plugin = pcm->private;
snd_pcm_t *slave = plugin->slave;
int err = snd_pcm_munmap(slave);
if (err < 0)
return err;
free(pcm->mmap_info->addr);
free(pcm->mmap_info);
pcm->mmap_info_count = 0;
pcm->mmap_info = 0;
return 0;
}
@ -392,7 +391,7 @@ int getput_index(int format)
return width * 4 + endian * 2 + sign;
}
struct snd_pcm_fast_ops snd_pcm_plugin_fast_ops = {
snd_pcm_fast_ops_t snd_pcm_plugin_fast_ops = {
status: snd_pcm_plugin_status,
state: snd_pcm_plugin_state,
delay: snd_pcm_plugin_delay,
@ -406,7 +405,6 @@ struct snd_pcm_fast_ops snd_pcm_plugin_fast_ops = {
writen: snd_pcm_plugin_writen,
readi: snd_pcm_plugin_readi,
readn: snd_pcm_plugin_readn,
poll_descriptor: snd_pcm_plugin_poll_descriptor,
channels_mask: snd_pcm_plugin_channels_mask,
avail_update: snd_pcm_plugin_avail_update,
mmap_forward: snd_pcm_plugin_mmap_forward,

View file

@ -26,8 +26,7 @@ typedef struct {
snd_pcm_xfer_areas_func_t write;
size_t (*client_frames)(snd_pcm_t *pcm, size_t frames);
int (*init)(snd_pcm_t *pcm);
snd_pcm_mmap_control_t mmap_control;
snd_pcm_mmap_status_t mmap_status;
size_t appl_ptr, hw_ptr;
} snd_pcm_plugin_t;
int snd_pcm_plugin_close(snd_pcm_t *pcm);
@ -54,10 +53,10 @@ ssize_t snd_pcm_plugin_mmap_forward(snd_pcm_t *pcm, size_t size);
ssize_t snd_pcm_plugin_avail_update(snd_pcm_t *pcm);
int snd_pcm_plugin_mmap_status(snd_pcm_t *pcm);
int snd_pcm_plugin_mmap_control(snd_pcm_t *pcm);
int snd_pcm_plugin_mmap_data(snd_pcm_t *pcm);
int snd_pcm_plugin_mmap(snd_pcm_t *pcm);
int snd_pcm_plugin_munmap_status(snd_pcm_t *pcm);
int snd_pcm_plugin_munmap_control(snd_pcm_t *pcm);
int snd_pcm_plugin_munmap_data(snd_pcm_t *pcm);
int snd_pcm_plugin_munmap(snd_pcm_t *pcm);
int snd_pcm_plugin_poll_descriptor(snd_pcm_t *pcm);
int snd_pcm_plugin_channels_mask(snd_pcm_t *pcm, bitset_t *cmask);
int getput_index(int format);
@ -71,7 +70,7 @@ int conv_index(int src_format, int dst_format);
SND_PCM_FMT_S32_LE | SND_PCM_FMT_S32_BE | \
SND_PCM_FMT_U32_LE | SND_PCM_FMT_U32_BE)
extern struct snd_pcm_fast_ops snd_pcm_plugin_fast_ops;
extern snd_pcm_fast_ops_t snd_pcm_plugin_fast_ops;
#define muldiv64(a,b,d) (((int64_t)(a) * (b) + (b) / 2) / (d))
@ -88,19 +87,19 @@ typedef int ttable_entry_t;
#define FULL ROUTE_PLUGIN_RESOLUTION
#endif
int snd_pcm_linear_open(snd_pcm_t **handlep, char *name, int sformat, snd_pcm_t *slave, int close_slave);
int snd_pcm_mulaw_open(snd_pcm_t **handlep, char *name, int sformat, snd_pcm_t *slave, int close_slave);
int snd_pcm_alaw_open(snd_pcm_t **handlep, char *name, int sformat, snd_pcm_t *slave, int close_slave);
int snd_pcm_adpcm_open(snd_pcm_t **handlep, char *name, int sformat, snd_pcm_t *slave, int close_slave);
int snd_pcm_linear_open(snd_pcm_t **pcmp, char *name, int sformat, snd_pcm_t *slave, int close_slave);
int snd_pcm_mulaw_open(snd_pcm_t **pcmp, char *name, int sformat, snd_pcm_t *slave, int close_slave);
int snd_pcm_alaw_open(snd_pcm_t **pcmp, char *name, int sformat, snd_pcm_t *slave, int close_slave);
int snd_pcm_adpcm_open(snd_pcm_t **pcmp, char *name, int sformat, snd_pcm_t *slave, int close_slave);
int snd_pcm_route_load_ttable(snd_config_t *tt, ttable_entry_t *ttable,
unsigned int tt_csize, unsigned int tt_ssize,
unsigned int *tt_cused, unsigned int *tt_sused,
int schannels);
int snd_pcm_route_open(snd_pcm_t **handlep, char *name,
int snd_pcm_route_open(snd_pcm_t **pcmp, char *name,
int sformat, unsigned int schannels,
ttable_entry_t *ttable,
unsigned int tt_ssize,
unsigned int tt_cused, unsigned int tt_sused,
snd_pcm_t *slave, int close_slave);
int snd_pcm_rate_open(snd_pcm_t **handlep, char *name, int sformat, int srate, snd_pcm_t *slave, int close_slave);
int snd_pcm_rate_open(snd_pcm_t **pcmp, char *name, int sformat, int srate, snd_pcm_t *slave, int close_slave);

View file

@ -326,12 +326,6 @@ static int snd_pcm_rate_params(snd_pcm_t *pcm, snd_pcm_params_t * params)
return err;
}
if (slave->mmap_data) {
err = snd_pcm_munmap_data(slave);
if (err < 0)
return err;
}
if (rate->req_srate - slave_info.min_rate < slave_info.max_rate - rate->req_srate)
srate = slave_info.min_rate;
else
@ -349,10 +343,6 @@ static int snd_pcm_rate_params(snd_pcm_t *pcm, snd_pcm_params_t * params)
err = snd_pcm_params(slave, &slave_params);
params->fail_mask = slave_params.fail_mask;
params->fail_reason = slave_params.fail_reason;
if (slave->valid_setup) {
int r = snd_pcm_mmap_data(slave, NULL);
assert(r >= 0);
}
return err;
}
@ -565,7 +555,7 @@ static void snd_pcm_rate_dump(snd_pcm_t *pcm, FILE *fp)
snd_pcm_dump(rate->plug.slave, fp);
}
struct snd_pcm_ops snd_pcm_rate_ops = {
snd_pcm_ops_t snd_pcm_rate_ops = {
close: snd_pcm_rate_close,
info: snd_pcm_plugin_info,
params_info: snd_pcm_rate_params_info,
@ -577,20 +567,15 @@ struct snd_pcm_ops snd_pcm_rate_ops = {
dump: snd_pcm_rate_dump,
nonblock: snd_pcm_plugin_nonblock,
async: snd_pcm_plugin_async,
mmap_status: snd_pcm_plugin_mmap_status,
mmap_control: snd_pcm_plugin_mmap_control,
mmap_data: snd_pcm_plugin_mmap_data,
munmap_status: snd_pcm_plugin_munmap_status,
munmap_control: snd_pcm_plugin_munmap_control,
munmap_data: snd_pcm_plugin_munmap_data,
mmap: snd_pcm_plugin_mmap,
munmap: snd_pcm_plugin_munmap,
};
int snd_pcm_rate_open(snd_pcm_t **handlep, char *name, int sformat, int srate, snd_pcm_t *slave, int close_slave)
int snd_pcm_rate_open(snd_pcm_t **pcmp, char *name, int sformat, int srate, snd_pcm_t *slave, int close_slave)
{
snd_pcm_t *handle;
snd_pcm_t *pcm;
snd_pcm_rate_t *rate;
int err;
assert(handlep && slave);
assert(pcmp && slave);
if (sformat >= 0 && snd_pcm_format_linear(sformat) != 1)
return -EINVAL;
rate = calloc(1, sizeof(snd_pcm_rate_t));
@ -606,27 +591,25 @@ int snd_pcm_rate_open(snd_pcm_t **handlep, char *name, int sformat, int srate, s
rate->plug.slave = slave;
rate->plug.close_slave = close_slave;
handle = calloc(1, sizeof(snd_pcm_t));
if (!handle) {
pcm = calloc(1, sizeof(snd_pcm_t));
if (!pcm) {
free(rate);
return -ENOMEM;
}
if (name)
handle->name = strdup(name);
handle->type = SND_PCM_TYPE_RATE;
handle->stream = slave->stream;
handle->ops = &snd_pcm_rate_ops;
handle->op_arg = handle;
handle->fast_ops = &snd_pcm_plugin_fast_ops;
handle->fast_op_arg = handle;
handle->mode = slave->mode;
handle->private = rate;
err = snd_pcm_init(handle);
if (err < 0) {
snd_pcm_close(handle);
return err;
}
*handlep = handle;
pcm->name = strdup(name);
pcm->type = SND_PCM_TYPE_RATE;
pcm->stream = slave->stream;
pcm->mode = slave->mode;
pcm->ops = &snd_pcm_rate_ops;
pcm->op_arg = pcm;
pcm->fast_ops = &snd_pcm_plugin_fast_ops;
pcm->fast_op_arg = pcm;
pcm->private = rate;
pcm->poll_fd = slave->poll_fd;
pcm->hw_ptr = &rate->plug.hw_ptr;
pcm->appl_ptr = &rate->plug.appl_ptr;
*pcmp = pcm;
return 0;
}

View file

@ -484,11 +484,6 @@ static int snd_pcm_route_params(snd_pcm_t *pcm, snd_pcm_params_t * params)
params->fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
return -EINVAL;
}
if (slave->mmap_data) {
err = snd_pcm_munmap_data(slave);
if (err < 0)
return err;
}
route->cformat = params->format.sfmt;
route->cchannels = params->format.channels;
route->cxfer_mode = params->xfer_mode;
@ -504,10 +499,6 @@ static int snd_pcm_route_params(snd_pcm_t *pcm, snd_pcm_params_t * params)
params->format.channels = route->cchannels;
params->xfer_mode = route->cxfer_mode;
params->mmap_shape = route->cmmap_shape;
if (slave->valid_setup) {
int r = snd_pcm_mmap_data(slave, NULL);
assert(r >= 0);
}
return err;
}
@ -599,12 +590,14 @@ static int snd_pcm_route_channel_setup(snd_pcm_t *pcm, snd_pcm_channel_setup_t *
if (err < 0)
return err;
#endif
if (!pcm->mmap_info)
return 0;
if (pcm->setup.mmap_shape == SND_PCM_MMAP_INTERLEAVED) {
setup->running_area.addr = pcm->mmap_data;
setup->running_area.addr = pcm->mmap_info->addr;
setup->running_area.first = setup->channel * pcm->bits_per_sample;
setup->running_area.step = pcm->bits_per_frame;
} else {
setup->running_area.addr = pcm->mmap_data + setup->channel * pcm->setup.buffer_size * pcm->bits_per_sample / 8;
setup->running_area.addr = pcm->mmap_info->addr + setup->channel * pcm->setup.buffer_size * pcm->bits_per_sample / 8;
setup->running_area.first = 0;
setup->running_area.step = pcm->bits_per_sample;
}
@ -684,7 +677,7 @@ static void snd_pcm_route_dump(snd_pcm_t *pcm, FILE *fp)
snd_pcm_dump(route->plug.slave, fp);
}
struct snd_pcm_ops snd_pcm_route_ops = {
snd_pcm_ops_t snd_pcm_route_ops = {
close: snd_pcm_route_close,
info: snd_pcm_plugin_info,
params_info: snd_pcm_route_params_info,
@ -696,12 +689,8 @@ struct snd_pcm_ops snd_pcm_route_ops = {
dump: snd_pcm_route_dump,
nonblock: snd_pcm_plugin_nonblock,
async: snd_pcm_plugin_async,
mmap_status: snd_pcm_plugin_mmap_status,
mmap_control: snd_pcm_plugin_mmap_control,
mmap_data: snd_pcm_plugin_mmap_data,
munmap_status: snd_pcm_plugin_munmap_status,
munmap_control: snd_pcm_plugin_munmap_control,
munmap_data: snd_pcm_plugin_munmap_data,
mmap: snd_pcm_plugin_mmap,
munmap: snd_pcm_plugin_munmap,
};
int route_load_ttable(route_params_t *params, int stream,
@ -776,17 +765,17 @@ int route_load_ttable(route_params_t *params, int stream,
}
int snd_pcm_route_open(snd_pcm_t **handlep, char *name,
int snd_pcm_route_open(snd_pcm_t **pcmp, char *name,
int sformat, unsigned int schannels,
ttable_entry_t *ttable,
unsigned int tt_ssize,
unsigned int tt_cused, unsigned int tt_sused,
snd_pcm_t *slave, int close_slave)
{
snd_pcm_t *handle;
snd_pcm_t *pcm;
snd_pcm_route_t *route;
int err;
assert(handlep && slave && ttable);
assert(pcmp && slave && ttable);
if (sformat >= 0 && snd_pcm_format_linear(sformat) != 1)
return -EINVAL;
route = calloc(1, sizeof(snd_pcm_route_t));
@ -800,32 +789,30 @@ int snd_pcm_route_open(snd_pcm_t **handlep, char *name,
route->plug.slave = slave;
route->plug.close_slave = close_slave;
handle = calloc(1, sizeof(snd_pcm_t));
if (!handle) {
pcm = calloc(1, sizeof(snd_pcm_t));
if (!pcm) {
free(route);
return -ENOMEM;
}
if (name)
handle->name = strdup(name);
handle->type = SND_PCM_TYPE_ROUTE;
handle->stream = slave->stream;
handle->ops = &snd_pcm_route_ops;
handle->op_arg = handle;
handle->fast_ops = &snd_pcm_plugin_fast_ops;
handle->fast_op_arg = handle;
handle->mode = slave->mode;
handle->private = route;
err = snd_pcm_init(handle);
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;
}
err = route_load_ttable(&route->params, handle->stream, tt_ssize, ttable, tt_cused, tt_sused);
if (err < 0) {
snd_pcm_close(handle);
return err;
}
*handlep = handle;
*pcmp = pcm;
return 0;
}

View file

@ -42,6 +42,7 @@ typedef struct {
size_t channels_count;
size_t open_count;
size_t setup_count;
size_t mmap_count;
size_t prepared_count;
size_t running_count;
size_t safety_threshold;
@ -61,8 +62,9 @@ typedef struct {
pid_t async_pid;
struct timeval trigger_time;
size_t draining_silence;
snd_pcm_mmap_control_t mmap_control;
snd_pcm_mmap_status_t mmap_status;
int state;
size_t hw_ptr;
size_t appl_ptr;
int ready;
int client_socket;
int slave_socket;
@ -79,7 +81,7 @@ static void snd_pcm_share_interrupt(snd_pcm_share_slave_t *slave)
snd_pcm_share_t *share = list_entry(i, snd_pcm_share_t, list);
snd_pcm_t *pcm = share->pcm;
int ready;
switch (share->mmap_status.state) {
switch (share->state) {
case SND_PCM_STATE_DRAINING:
if (pcm->stream == SND_PCM_STREAM_CAPTURE)
ready = 1;
@ -146,7 +148,7 @@ static void snd_pcm_share_stop(snd_pcm_t *pcm, int state)
{
snd_pcm_share_t *share = pcm->private;
snd_pcm_share_slave_t *slave = share->slave;
share->mmap_status.state = state;
share->state = state;
gettimeofday(&share->trigger_time, 0);
slave->prepared_count--;
slave->running_count--;
@ -160,8 +162,8 @@ static void snd_pcm_share_stop(snd_pcm_t *pcm, int state)
pcm->setup.format.channels, pcm->setup.buffer_size,
pcm->setup.format.sfmt);
}
share->mmap_status.hw_ptr = slave->pcm->mmap_status->hw_ptr;
pcm->mmap_status = &share->mmap_status;
share->hw_ptr = *slave->pcm->hw_ptr;
pcm->hw_ptr = &share->hw_ptr;
}
/* Warning: take the mutex before to call this */
@ -182,11 +184,11 @@ static void snd_pcm_share_slave_forward(snd_pcm_share_slave_t *slave)
buffer_size = slave->pcm->setup.buffer_size;
min_frames = buffer_size;
max_frames = 0;
slave_appl_ptr = slave->pcm->mmap_control->appl_ptr;
slave_appl_ptr = *slave->pcm->appl_ptr;
for (i = slave->clients.next; i != &slave->clients; i = i->next) {
snd_pcm_share_t *share = list_entry(i, snd_pcm_share_t, list);
snd_pcm_t *pcm = share->pcm;
switch (share->mmap_status.state) {
switch (share->state) {
case SND_PCM_STATE_RUNNING:
break;
case SND_PCM_STATE_DRAINING:
@ -220,7 +222,7 @@ static void snd_pcm_share_slave_forward(snd_pcm_share_slave_t *slave)
default:
continue;
}
frames = share->mmap_control.appl_ptr - slave_appl_ptr;
frames = share->appl_ptr - slave_appl_ptr;
if (frames > (ssize_t)buffer_size)
frames -= pcm->setup.boundary;
else if (frames < -(ssize_t)pcm->setup.buffer_size)
@ -262,7 +264,7 @@ static int snd_pcm_share_close(snd_pcm_t *pcm)
snd_pcm_share_t *share = pcm->private;
snd_pcm_share_slave_t *slave = share->slave;
int err = 0;
if (share->mmap_status.state == SND_PCM_STATE_RUNNING) {
if (share->state == SND_PCM_STATE_RUNNING) {
if (pcm->mode & SND_PCM_NONBLOCK)
snd_pcm_drop(pcm);
else
@ -276,11 +278,14 @@ static int snd_pcm_share_close(snd_pcm_t *pcm)
pthread_kill(slave->thread, SIGTERM);
err = snd_pcm_close(slave->pcm);
list_del(&slave->list);
pthread_mutex_unlock(&slave->mutex);
pthread_mutex_destroy(&slave->mutex);
free(slave);
list_del(&share->list);
} else {
list_del(&share->list);
pthread_mutex_unlock(&slave->mutex);
}
list_del(&share->list);
pthread_mutex_unlock(&slave->mutex);
close(share->client_socket);
close(share->slave_socket);
free(share->slave_channels);
@ -358,6 +363,64 @@ static int snd_pcm_share_params_info(snd_pcm_t *pcm, snd_pcm_params_info_t *info
return err;
}
static int snd_pcm_share_mmap(snd_pcm_t *pcm)
{
snd_pcm_share_t *share = pcm->private;
snd_pcm_share_slave_t *slave = share->slave;
snd_pcm_mmap_info_t *i;
int err;
pthread_mutex_lock(&slave->mutex);
if (slave->mmap_count == 0) {
err = snd_pcm_mmap(slave->pcm);
if (err < 0) {
pthread_mutex_unlock(&slave->mutex);
return err;
}
if (slave->pcm->stream == SND_PCM_STREAM_PLAYBACK)
snd_pcm_areas_silence(slave->pcm->running_areas, 0, slave->pcm->setup.format.channels, slave->pcm->setup.buffer_size, slave->pcm->setup.format.sfmt);
slave->mmap_count++;
}
pthread_mutex_unlock(&slave->mutex);
pcm->mmap_info_count = slave->pcm->mmap_info_count + 1;
pcm->mmap_info = malloc(pcm->mmap_info_count * sizeof(*pcm->mmap_info));
if (!pcm->mmap_info)
return -ENOMEM;
memcpy(pcm->mmap_info, slave->pcm->mmap_info, slave->pcm->mmap_info_count * sizeof(*pcm->mmap_info));
i = &pcm->mmap_info[slave->pcm->mmap_info_count];
i->type = SND_PCM_MMAP_USER;
i->size = snd_pcm_frames_to_bytes(pcm, pcm->setup.buffer_size);
share->stopped_data = malloc(i->size);
if (share->stopped_data == 0) {
free(pcm->mmap_info);
pcm->mmap_info = 0;
return -ENOMEM;
}
i->addr = share->stopped_data;
return 0;
}
static int snd_pcm_share_munmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
{
snd_pcm_share_t *share = pcm->private;
snd_pcm_share_slave_t *slave = share->slave;
int err;
pthread_mutex_lock(&slave->mutex);
slave->mmap_count--;
if (slave->mmap_count == 0) {
err = snd_pcm_munmap(slave->pcm);
if (err < 0) {
pthread_mutex_unlock(&slave->mutex);
return err;
}
}
pthread_mutex_unlock(&slave->mutex);
free(pcm->mmap_info);
pcm->mmap_info_count = 0;
pcm->mmap_info = 0;
free(share->stopped_data);
return 0;
}
static int snd_pcm_share_params(snd_pcm_t *pcm, snd_pcm_params_t *params)
{
snd_pcm_share_t *share = pcm->private;
@ -367,7 +430,7 @@ static int snd_pcm_share_params(snd_pcm_t *pcm, snd_pcm_params_t *params)
if (channels != share->channels_count) {
params->fail_mask = SND_PCM_PARAMS_CHANNELS;
params->fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
ERR("channels requested (%d) differs from configuration (%d)", channels, share->channels_count);
ERR("channels requested (%d) differs from configuration (%ld)", channels, (long)share->channels_count);
return -EINVAL;
}
share->xfer_mode = params->xfer_mode;
@ -387,22 +450,14 @@ static int snd_pcm_share_params(snd_pcm_t *pcm, snd_pcm_params_t *params)
}
} else {
snd_pcm_params_t sp = *params;
if (slave->pcm->mmap_data) {
err = snd_pcm_munmap_data(slave->pcm);
if (err < 0)
goto _end;
}
sp.xfer_mode = SND_PCM_XFER_UNSPECIFIED;
sp.xrun_mode = SND_PCM_XRUN_NONE;
sp.format.channels = slave->channels_count;
err = snd_pcm_params(slave->pcm, &sp);
snd_pcm_mmap_data(slave->pcm, NULL);
if (err < 0)
goto _end;
if (slave->pcm->stream == SND_PCM_STREAM_PLAYBACK)
snd_pcm_areas_silence(slave->pcm->running_areas, 0, slave->pcm->setup.format.channels, slave->pcm->setup.buffer_size, slave->pcm->setup.format.sfmt);
}
share->mmap_status.state = SND_PCM_STATE_SETUP;
share->state = SND_PCM_STATE_SETUP;
slave->setup_count++;
_end:
pthread_mutex_unlock(&slave->mutex);
@ -437,13 +492,13 @@ static int snd_pcm_share_status(snd_pcm_t *pcm, snd_pcm_status_t *status)
pthread_mutex_lock(&slave->mutex);
if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
status->avail = snd_pcm_mmap_playback_avail(pcm);
if (share->mmap_status.state != SND_PCM_STATE_RUNNING &&
share->mmap_status.state != SND_PCM_STATE_DRAINING)
if (share->state != SND_PCM_STATE_RUNNING &&
share->state != SND_PCM_STATE_DRAINING)
goto _notrunning;
d = pcm->setup.buffer_size - status->avail;
} else {
status->avail = snd_pcm_mmap_capture_avail(pcm);
if (share->mmap_status.state != SND_PCM_STATE_RUNNING)
if (share->state != SND_PCM_STATE_RUNNING)
goto _notrunning;
d = status->avail;
}
@ -452,7 +507,7 @@ static int snd_pcm_share_status(snd_pcm_t *pcm, snd_pcm_status_t *status)
goto _end;
_notrunning:
status->delay = sd + d;
status->state = share->mmap_status.state;
status->state = share->state;
status->trigger_time = share->trigger_time;
_end:
pthread_mutex_unlock(&slave->mutex);
@ -462,7 +517,7 @@ static int snd_pcm_share_status(snd_pcm_t *pcm, snd_pcm_status_t *status)
static int snd_pcm_share_state(snd_pcm_t *pcm)
{
snd_pcm_share_t *share = pcm->private;
return share->mmap_status.state;
return share->state;
}
static int snd_pcm_share_delay(snd_pcm_t *pcm, ssize_t *delayp)
@ -472,7 +527,7 @@ static int snd_pcm_share_delay(snd_pcm_t *pcm, ssize_t *delayp)
int err = 0;
ssize_t sd;
pthread_mutex_lock(&slave->mutex);
switch (share->mmap_status.state) {
switch (share->state) {
case SND_PCM_STATE_XRUN:
err = -EPIPE;
goto _end;
@ -507,7 +562,7 @@ static ssize_t snd_pcm_share_avail_update(snd_pcm_t *pcm)
for (i = slave->clients.next; i != &slave->clients; i = i->next) {
snd_pcm_share_t *share = list_entry(i, snd_pcm_share_t, list);
snd_pcm_t *pcm = share->pcm;
if (share->mmap_status.state == SND_PCM_STATE_RUNNING &&
if (share->state == SND_PCM_STATE_RUNNING &&
pcm->setup.xrun_mode != SND_PCM_XRUN_NONE)
snd_pcm_share_stop(pcm, SND_PCM_STATE_XRUN);
}
@ -521,16 +576,16 @@ static ssize_t snd_pcm_share_avail_update(snd_pcm_t *pcm)
return ret;
}
static ssize_t snd_pcm_share_mmap_forward(snd_pcm_t *pcm, size_t size)
/* Call it with mutex held */
static ssize_t _snd_pcm_share_mmap_forward(snd_pcm_t *pcm, size_t size)
{
snd_pcm_share_t *share = pcm->private;
snd_pcm_share_slave_t *slave = share->slave;
ssize_t ret = 0;
ssize_t frames;
pthread_mutex_lock(&slave->mutex);
if (pcm->stream == SND_PCM_STREAM_PLAYBACK &&
share->mmap_status.state == SND_PCM_STATE_RUNNING) {
frames = slave->pcm->mmap_control->appl_ptr - share->mmap_control.appl_ptr;
share->state == SND_PCM_STATE_RUNNING) {
frames = *slave->pcm->appl_ptr - share->appl_ptr;
if (frames > (ssize_t)pcm->setup.buffer_size)
frames -= pcm->setup.boundary;
else if (frames < -(ssize_t)pcm->setup.buffer_size)
@ -538,19 +593,27 @@ static ssize_t snd_pcm_share_mmap_forward(snd_pcm_t *pcm, size_t size)
if (frames > 0) {
/* Latecomer PCM */
ret = snd_pcm_rewind(slave->pcm, frames);
if (ret < 0) {
pthread_mutex_unlock(&slave->mutex);
if (ret < 0)
return ret;
}
size += ret;
}
}
snd_pcm_mmap_appl_forward(pcm, size);
snd_pcm_share_slave_forward(share->slave);
pthread_mutex_unlock(&slave->mutex);
return size;
}
static ssize_t snd_pcm_share_mmap_forward(snd_pcm_t *pcm, size_t size)
{
snd_pcm_share_t *share = pcm->private;
snd_pcm_share_slave_t *slave = share->slave;
ssize_t ret;
pthread_mutex_lock(&slave->mutex);
ret = _snd_pcm_share_mmap_forward(pcm, size);
pthread_mutex_unlock(&slave->mutex);
return ret;
}
static int snd_pcm_share_prepare(snd_pcm_t *pcm)
{
snd_pcm_share_t *share = pcm->private;
@ -563,9 +626,9 @@ static int snd_pcm_share_prepare(snd_pcm_t *pcm)
goto _end;
}
slave->prepared_count++;
share->mmap_status.hw_ptr = 0;
share->mmap_control.appl_ptr = 0;
share->mmap_status.state = SND_PCM_STATE_PREPARED;
share->hw_ptr = 0;
share->appl_ptr = 0;
share->state = SND_PCM_STATE_PREPARED;
_end:
pthread_mutex_unlock(&slave->mutex);
return err;
@ -576,10 +639,10 @@ static int snd_pcm_share_start(snd_pcm_t *pcm)
snd_pcm_share_t *share = pcm->private;
snd_pcm_share_slave_t *slave = share->slave;
int err = 0;
if (share->mmap_status.state != SND_PCM_STATE_PREPARED)
if (share->state != SND_PCM_STATE_PREPARED)
return -EBADFD;
pthread_mutex_lock(&slave->mutex);
share->mmap_status.state = SND_PCM_STATE_RUNNING;
share->state = SND_PCM_STATE_RUNNING;
if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
size_t hw_avail = snd_pcm_mmap_playback_hw_avail(pcm);
if (hw_avail == 0) {
@ -595,15 +658,15 @@ static int snd_pcm_share_start(snd_pcm_t *pcm)
if (err < 0)
goto _end;
}
assert(share->mmap_status.hw_ptr == 0);
/* Use the same mmap_status of slave */
pcm->mmap_status = slave->pcm->mmap_status;
share->mmap_control.appl_ptr = slave->pcm->mmap_control->appl_ptr;
assert(share->hw_ptr == 0);
/* Share the same hw_ptr of slave */
pcm->hw_ptr = slave->pcm->hw_ptr;
share->appl_ptr = *slave->pcm->appl_ptr;
snd_pcm_areas_copy(pcm->stopped_areas, 0,
pcm->running_areas, snd_pcm_mmap_offset(pcm),
pcm->setup.format.channels, hw_avail,
pcm->setup.format.sfmt);
snd_pcm_mmap_forward(pcm, pcm->setup.buffer_size);
_snd_pcm_share_mmap_forward(pcm, pcm->setup.buffer_size);
}
if (slave->running_count == 0) {
err = snd_pcm_start(slave->pcm);
@ -623,7 +686,7 @@ static int snd_pcm_share_drop(snd_pcm_t *pcm)
snd_pcm_share_slave_t *slave = share->slave;
int err = 0;
pthread_mutex_lock(&slave->mutex);
switch (share->mmap_status.state) {
switch (share->state) {
case SND_PCM_STATE_OPEN:
err = -EBADFD;
goto _end;
@ -631,7 +694,7 @@ static int snd_pcm_share_drop(snd_pcm_t *pcm)
goto _end;
case SND_PCM_STATE_DRAINING:
if (pcm->stream == SND_PCM_STREAM_CAPTURE) {
share->mmap_status.state = SND_PCM_STATE_SETUP;
share->state = SND_PCM_STATE_SETUP;
break;
}
/* Fall through */
@ -640,7 +703,7 @@ static int snd_pcm_share_drop(snd_pcm_t *pcm)
break;
case SND_PCM_STATE_PREPARED:
case SND_PCM_STATE_XRUN:
share->mmap_status.state = SND_PCM_STATE_SETUP;
share->state = SND_PCM_STATE_SETUP;
break;
}
@ -659,7 +722,7 @@ static int snd_pcm_share_drop(snd_pcm_t *pcm)
pcm->setup.buffer_size, pcm->setup.format.sfmt);
snd_pcm_mmap_forward(pcm, pcm->setup.buffer_size);
}
share->mmap_control.appl_ptr = share->mmap_status.hw_ptr = 0;
share->appl_ptr = share->hw_ptr = 0;
_end:
pthread_mutex_unlock(&slave->mutex);
return err;
@ -671,29 +734,29 @@ static int snd_pcm_share_drain(snd_pcm_t *pcm)
snd_pcm_share_slave_t *slave = share->slave;
int err = 0;
pthread_mutex_lock(&slave->mutex);
switch (share->mmap_status.state) {
switch (share->state) {
case SND_PCM_STATE_OPEN:
err = -EBADFD;
goto _end;
case SND_PCM_STATE_PREPARED:
share->mmap_status.state = SND_PCM_STATE_SETUP;
share->state = SND_PCM_STATE_SETUP;
break;
case SND_PCM_STATE_SETUP:
case SND_PCM_STATE_DRAINING:
goto _end;
case SND_PCM_STATE_XRUN:
if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
share->mmap_status.state = SND_PCM_STATE_SETUP;
share->state = SND_PCM_STATE_SETUP;
break;
}
/* Fall through */
case SND_PCM_STATE_RUNNING:
if (snd_pcm_mmap_avail(pcm) <= 0) {
share->mmap_status.state = SND_PCM_STATE_SETUP;
share->state = SND_PCM_STATE_SETUP;
break;
}
share->draining_silence = 0;
share->mmap_status.state = SND_PCM_STATE_DRAINING;
share->state = SND_PCM_STATE_DRAINING;
break;
}
_end:
@ -742,7 +805,26 @@ static int snd_pcm_share_channel_setup(snd_pcm_t *pcm, snd_pcm_channel_setup_t *
setup->channel = c;
err = snd_pcm_channel_setup(slave->pcm, setup);
setup->channel = channel;
return err;
if (err < 0)
return err;
if (!pcm->mmap_info)
return 0;
switch (pcm->setup.mmap_shape) {
case SND_PCM_MMAP_INTERLEAVED:
case SND_PCM_MMAP_COMPLEX:
setup->stopped_area.addr = share->stopped_data;
setup->stopped_area.first = channel * pcm->bits_per_sample;
setup->stopped_area.step = pcm->bits_per_frame;
break;
case SND_PCM_MMAP_NONINTERLEAVED:
setup->stopped_area.addr = share->stopped_data + c * pcm->setup.buffer_size * pcm->bits_per_sample / 8;
setup->stopped_area.first = 0;
setup->stopped_area.step = pcm->bits_per_sample;
break;
default:
assert(0);
}
return 0;
}
static ssize_t snd_pcm_share_rewind(snd_pcm_t *pcm, size_t frames)
@ -751,7 +833,7 @@ static ssize_t snd_pcm_share_rewind(snd_pcm_t *pcm, size_t frames)
snd_pcm_share_slave_t *slave = share->slave;
int ret = -EBADFD;
ssize_t n;
switch (share->mmap_status.state) {
switch (share->state) {
case SND_PCM_STATE_RUNNING:
break;
case SND_PCM_STATE_PREPARED:
@ -774,7 +856,7 @@ static ssize_t snd_pcm_share_rewind(snd_pcm_t *pcm, size_t frames)
n = frames;
frames -= n;
}
if (share->mmap_status.state == SND_PCM_STATE_RUNNING &&
if (share->state == SND_PCM_STATE_RUNNING &&
frames > 0) {
pthread_mutex_lock(&slave->mutex);
ret = snd_pcm_rewind(slave->pcm, frames);
@ -793,43 +875,6 @@ static ssize_t snd_pcm_share_rewind(snd_pcm_t *pcm, size_t frames)
return ret;
}
static int snd_pcm_share_mmap_status(snd_pcm_t *pcm)
{
snd_pcm_share_t *share = pcm->private;
pcm->mmap_status = &share->mmap_status;
return 0;
}
static int snd_pcm_share_mmap_control(snd_pcm_t *pcm)
{
snd_pcm_share_t *share = pcm->private;
pcm->mmap_control = &share->mmap_control;
return 0;
}
static int snd_pcm_share_mmap_data(snd_pcm_t *pcm)
{
snd_pcm_share_t *share = pcm->private;
snd_pcm_share_slave_t *slave = share->slave;
pcm->mmap_data = slave->pcm->mmap_data;
return 0;
}
static int snd_pcm_share_munmap_status(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
{
return 0;
}
static int snd_pcm_share_munmap_control(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
{
return 0;
}
static int snd_pcm_share_munmap_data(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
{
return 0;
}
static int snd_pcm_share_channels_mask(snd_pcm_t *pcm, bitset_t *cmask)
{
snd_pcm_share_t *share = pcm->private;
@ -869,7 +914,7 @@ static void snd_pcm_share_dump(snd_pcm_t *pcm, FILE *fp)
snd_pcm_dump(slave->pcm, fp);
}
struct snd_pcm_ops snd_pcm_share_ops = {
snd_pcm_ops_t snd_pcm_share_ops = {
close: snd_pcm_share_close,
info: snd_pcm_share_info,
params_info: snd_pcm_share_params_info,
@ -881,15 +926,11 @@ struct snd_pcm_ops snd_pcm_share_ops = {
dump: snd_pcm_share_dump,
nonblock: snd_pcm_share_nonblock,
async: snd_pcm_share_async,
mmap_status: snd_pcm_share_mmap_status,
mmap_control: snd_pcm_share_mmap_control,
mmap_data: snd_pcm_share_mmap_data,
munmap_status: snd_pcm_share_munmap_status,
munmap_control: snd_pcm_share_munmap_control,
munmap_data: snd_pcm_share_munmap_data,
mmap: snd_pcm_share_mmap,
munmap: snd_pcm_share_munmap,
};
struct snd_pcm_fast_ops snd_pcm_share_fast_ops = {
snd_pcm_fast_ops_t snd_pcm_share_fast_ops = {
status: snd_pcm_share_status,
state: snd_pcm_share_state,
delay: snd_pcm_share_delay,
@ -903,18 +944,17 @@ struct snd_pcm_fast_ops snd_pcm_share_fast_ops = {
readi: snd_pcm_mmap_readi,
readn: snd_pcm_mmap_readn,
rewind: snd_pcm_share_rewind,
poll_descriptor: snd_pcm_share_poll_descriptor,
channels_mask: snd_pcm_share_channels_mask,
avail_update: snd_pcm_share_avail_update,
mmap_forward: snd_pcm_share_mmap_forward,
};
int snd_pcm_share_open(snd_pcm_t **handlep, char *name, char *sname,
int snd_pcm_share_open(snd_pcm_t **pcmp, char *name, char *sname,
size_t schannels_count,
size_t channels_count, int *channels_map,
int stream, int mode)
{
snd_pcm_t *handle;
snd_pcm_t *pcm;
snd_pcm_share_t *share;
int err;
struct list_head *i;
@ -923,7 +963,7 @@ int snd_pcm_share_open(snd_pcm_t **handlep, char *name, char *sname,
snd_pcm_share_slave_t *slave = NULL;
int sd[2];
assert(handlep);
assert(pcmp);
assert(channels_count > 0 && sname && channels_map);
for (k = 0; k < channels_count; ++k) {
@ -951,8 +991,8 @@ int snd_pcm_share_open(snd_pcm_t **handlep, char *name, char *sname,
}
memcpy(share->slave_channels, channels_map, channels_count * sizeof(*share->slave_channels));
handle = calloc(1, sizeof(snd_pcm_t));
if (!handle) {
pcm = calloc(1, sizeof(snd_pcm_t));
if (!pcm) {
free(share->slave_channels);
free(share);
return -ENOMEM;
@ -976,7 +1016,7 @@ int snd_pcm_share_open(snd_pcm_t **handlep, char *name, char *sname,
}
if (err < 0) {
err = -errno;
free(handle);
free(pcm);
free(share->slave_channels);
free(share);
return err;
@ -997,7 +1037,7 @@ int snd_pcm_share_open(snd_pcm_t **handlep, char *name, char *sname,
pthread_mutex_unlock(&slaves_mutex);
close(sd[0]);
close(sd[1]);
free(handle);
free(pcm);
free(share->slave_channels);
free(share);
return err;
@ -1008,7 +1048,7 @@ int snd_pcm_share_open(snd_pcm_t **handlep, char *name, char *sname,
snd_pcm_close(spcm);
close(sd[0]);
close(sd[1]);
free(handle);
free(pcm);
free(share->slave_channels);
free(share);
return err;
@ -1031,28 +1071,27 @@ int snd_pcm_share_open(snd_pcm_t **handlep, char *name, char *sname,
pthread_mutex_unlock(&slave->mutex);
share->slave = slave;
share->pcm = handle;
share->pcm = pcm;
share->client_socket = sd[0];
share->slave_socket = sd[1];
share->async_sig = SIGIO;
share->async_pid = getpid();
if (name)
handle->name = strdup(name);
handle->type = SND_PCM_TYPE_SHARE;
handle->stream = stream;
handle->mode = mode;
handle->ops = &snd_pcm_share_ops;
handle->op_arg = handle;
handle->fast_ops = &snd_pcm_share_fast_ops;
handle->fast_op_arg = handle;
handle->private = share;
err = snd_pcm_init(handle);
if (err < 0) {
snd_pcm_close(handle);
return err;
}
*handlep = handle;
pcm->name = strdup(name);
pcm->type = SND_PCM_TYPE_SHARE;
pcm->stream = stream;
pcm->mode = mode;
pcm->mmap_auto = 1;
pcm->ops = &snd_pcm_share_ops;
pcm->op_arg = pcm;
pcm->fast_ops = &snd_pcm_share_fast_ops;
pcm->fast_op_arg = pcm;
pcm->private = share;
pcm->poll_fd = share->client_socket;
pcm->hw_ptr = &share->hw_ptr;
pcm->appl_ptr = &share->appl_ptr;
*pcmp = pcm;
return 0;
}
@ -1104,11 +1143,11 @@ int _snd_pcm_share_open(snd_pcm_t **pcmp, char *name, snd_config_t *conf,
return -EINVAL;
}
if (!sname) {
ERR("Missing sname");
ERR("sname is not defined");
return -EINVAL;
}
if (!binding) {
ERR("Missing binding");
ERR("binding is not defined");
return -EINVAL;
}
snd_config_foreach(i, binding) {