mirror of
https://github.com/alsa-project/alsa-lib.git
synced 2025-10-29 05:40:25 -04:00
Fixed mmap wrt shm. Renamed pcm_client, control_client to shm. More error messages. Implemented asoundrc as documented.
This commit is contained in:
parent
dcc88ffaa7
commit
e5e1ca14d4
30 changed files with 1642 additions and 2555 deletions
1
TODO
1
TODO
|
|
@ -1,3 +1,2 @@
|
|||
H solve multi/server mmap'ing problem
|
||||
M add abstraction layer to timer, rawmidi, hwdep, seq
|
||||
L move OSS emulation to user space? (pseudo device driver and daemon)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
512
src/control/control_shm.c
Normal 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);
|
||||
}
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
112
src/pcm/pcm.c
112
src/pcm/pcm.c
|
|
@ -30,18 +30,6 @@
|
|||
#include "pcm_local.h"
|
||||
#include "list.h"
|
||||
|
||||
int snd_pcm_init(snd_pcm_t *pcm)
|
||||
{
|
||||
int err;
|
||||
err = snd_pcm_mmap_status(pcm, NULL);
|
||||
if (err < 0)
|
||||
return err;
|
||||
err = snd_pcm_mmap_control(pcm, NULL);
|
||||
if (err < 0)
|
||||
return err;
|
||||
return 0;
|
||||
}
|
||||
|
||||
snd_pcm_type_t snd_pcm_type(snd_pcm_t *pcm)
|
||||
{
|
||||
assert(pcm);
|
||||
|
|
@ -59,16 +47,8 @@ int snd_pcm_close(snd_pcm_t *pcm)
|
|||
int ret = 0;
|
||||
int err;
|
||||
assert(pcm);
|
||||
if (pcm->mmap_status) {
|
||||
if ((err = snd_pcm_munmap_status(pcm)) < 0)
|
||||
ret = err;
|
||||
}
|
||||
if (pcm->mmap_control) {
|
||||
if ((err = snd_pcm_munmap_control(pcm)) < 0)
|
||||
ret = err;
|
||||
}
|
||||
if (pcm->mmap_data) {
|
||||
if ((err = snd_pcm_munmap_data(pcm)) < 0)
|
||||
if (pcm->mmap_info) {
|
||||
if ((err = snd_pcm_munmap(pcm)) < 0)
|
||||
ret = err;
|
||||
}
|
||||
if ((err = pcm->ops->close(pcm->op_arg)) < 0)
|
||||
|
|
@ -156,12 +136,21 @@ int snd_pcm_params(snd_pcm_t *pcm, snd_pcm_params_t *params)
|
|||
{
|
||||
int err;
|
||||
snd_pcm_setup_t setup;
|
||||
int mmap = 0;
|
||||
assert(pcm && params);
|
||||
assert(!pcm->mmap_data);
|
||||
if (pcm->mmap_info) {
|
||||
mmap = 1;
|
||||
err = snd_pcm_munmap(pcm);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
if ((err = pcm->ops->params(pcm->op_arg, params)) < 0)
|
||||
return err;
|
||||
pcm->valid_setup = 0;
|
||||
return snd_pcm_setup(pcm, &setup);
|
||||
err = snd_pcm_setup(pcm, &setup);
|
||||
if (pcm->mmap_auto || mmap)
|
||||
snd_pcm_mmap(pcm);
|
||||
return err;
|
||||
}
|
||||
|
||||
int snd_pcm_status(snd_pcm_t *pcm, snd_pcm_status_t *status)
|
||||
|
|
@ -233,7 +222,7 @@ ssize_t snd_pcm_writei(snd_pcm_t *pcm, const void *buffer, size_t size)
|
|||
assert(size == 0 || buffer);
|
||||
assert(pcm->valid_setup);
|
||||
assert(pcm->setup.xfer_mode == SND_PCM_XFER_INTERLEAVED);
|
||||
assert(!pcm->mmap_data);
|
||||
assert(!pcm->mmap_info || pcm->mmap_auto);
|
||||
return _snd_pcm_writei(pcm, buffer, size);
|
||||
}
|
||||
|
||||
|
|
@ -243,7 +232,7 @@ ssize_t snd_pcm_writen(snd_pcm_t *pcm, void **bufs, size_t size)
|
|||
assert(size == 0 || bufs);
|
||||
assert(pcm->valid_setup);
|
||||
assert(pcm->setup.xfer_mode == SND_PCM_XFER_NONINTERLEAVED);
|
||||
assert(!pcm->mmap_data);
|
||||
assert(!pcm->mmap_info || pcm->mmap_auto);
|
||||
return _snd_pcm_writen(pcm, bufs, size);
|
||||
}
|
||||
|
||||
|
|
@ -253,7 +242,7 @@ ssize_t snd_pcm_readi(snd_pcm_t *pcm, void *buffer, size_t size)
|
|||
assert(size == 0 || buffer);
|
||||
assert(pcm->valid_setup);
|
||||
assert(pcm->setup.xfer_mode == SND_PCM_XFER_INTERLEAVED);
|
||||
assert(!pcm->mmap_data);
|
||||
assert(!pcm->mmap_info || pcm->mmap_auto);
|
||||
return _snd_pcm_readi(pcm, buffer, size);
|
||||
}
|
||||
|
||||
|
|
@ -263,7 +252,7 @@ ssize_t snd_pcm_readn(snd_pcm_t *pcm, void **bufs, size_t size)
|
|||
assert(size == 0 || bufs);
|
||||
assert(pcm->valid_setup);
|
||||
assert(pcm->setup.xfer_mode == SND_PCM_XFER_NONINTERLEAVED);
|
||||
assert(!pcm->mmap_data);
|
||||
assert(!pcm->mmap_info || pcm->mmap_auto);
|
||||
return _snd_pcm_readn(pcm, bufs, size);
|
||||
}
|
||||
|
||||
|
|
@ -331,7 +320,7 @@ int snd_pcm_unlink(snd_pcm_t *pcm)
|
|||
int snd_pcm_poll_descriptor(snd_pcm_t *pcm)
|
||||
{
|
||||
assert(pcm);
|
||||
return pcm->fast_ops->poll_descriptor(pcm->fast_op_arg);
|
||||
return pcm->poll_fd;
|
||||
}
|
||||
|
||||
int snd_pcm_channels_mask(snd_pcm_t *pcm, bitset_t *cmask)
|
||||
|
|
@ -547,62 +536,87 @@ int snd_pcm_open(snd_pcm_t **pcmp, char *name,
|
|||
if (err < 0)
|
||||
return err;
|
||||
err = snd_config_searchv(snd_config, &pcm_conf, "pcm", name, 0);
|
||||
if (err < 0)
|
||||
if (err < 0) {
|
||||
ERR("Unknown PCM %s", name);
|
||||
return err;
|
||||
if (snd_config_type(pcm_conf) != SND_CONFIG_TYPE_COMPOUND)
|
||||
}
|
||||
if (snd_config_type(pcm_conf) != SND_CONFIG_TYPE_COMPOUND) {
|
||||
ERR("Invalid type for PCM definition");
|
||||
return -EINVAL;
|
||||
}
|
||||
err = snd_config_search(pcm_conf, "stream", &conf);
|
||||
if (err >= 0) {
|
||||
err = snd_config_string_get(conf, &str);
|
||||
if (err < 0)
|
||||
if (err < 0) {
|
||||
ERR("Invalid type for stream");
|
||||
return err;
|
||||
}
|
||||
if (strcmp(str, "playback") == 0) {
|
||||
if (stream != SND_PCM_STREAM_PLAYBACK)
|
||||
return -EINVAL;
|
||||
} else if (strcmp(str, "capture") == 0) {
|
||||
if (stream != SND_PCM_STREAM_CAPTURE)
|
||||
return -EINVAL;
|
||||
} else
|
||||
} else {
|
||||
ERR("Invalid value for stream");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
err = snd_config_search(pcm_conf, "type", &conf);
|
||||
if (err < 0)
|
||||
if (err < 0) {
|
||||
ERR("type is not defined");
|
||||
return err;
|
||||
}
|
||||
err = snd_config_string_get(conf, &str);
|
||||
if (err < 0)
|
||||
if (err < 0) {
|
||||
ERR("Invalid type for type");
|
||||
return err;
|
||||
}
|
||||
err = snd_config_searchv(snd_config, &type_conf, "pcmtype", str, 0);
|
||||
if (err < 0)
|
||||
if (err < 0) {
|
||||
ERR("Unknown PCM type %s", str);
|
||||
return err;
|
||||
}
|
||||
snd_config_foreach(i, type_conf) {
|
||||
snd_config_t *n = snd_config_entry(i);
|
||||
if (strcmp(n->id, "comment") == 0)
|
||||
continue;
|
||||
if (strcmp(n->id, "lib") == 0) {
|
||||
err = snd_config_string_get(n, &lib);
|
||||
if (err < 0)
|
||||
if (err < 0) {
|
||||
ERR("Invalid type for lib");
|
||||
return -EINVAL;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (strcmp(n->id, "open") == 0) {
|
||||
err = snd_config_string_get(n, &open);
|
||||
if (err < 0)
|
||||
if (err < 0) {
|
||||
ERR("Invalid type for open");
|
||||
return -EINVAL;
|
||||
}
|
||||
continue;
|
||||
ERR("Unknown field: %s", n->id);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
if (!open)
|
||||
if (!open) {
|
||||
ERR("open is not defined");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (!lib)
|
||||
lib = "libasound.so";
|
||||
h = dlopen(lib, RTLD_NOW);
|
||||
if (!h)
|
||||
if (!h) {
|
||||
ERR("Cannot open shared library %s", lib);
|
||||
return -ENOENT;
|
||||
}
|
||||
open_func = dlsym(h, open);
|
||||
dlclose(h);
|
||||
if (!open_func)
|
||||
if (!open_func) {
|
||||
ERR("symbol %s is not defined inside %s", open, lib);
|
||||
return -ENXIO;
|
||||
}
|
||||
return open_func(pcmp, name, pcm_conf, stream, mode);
|
||||
}
|
||||
|
||||
|
|
@ -634,23 +648,11 @@ int snd_pcm_wait(snd_pcm_t *pcm, int timeout)
|
|||
{
|
||||
struct pollfd pfd;
|
||||
int err;
|
||||
#if 0
|
||||
size_t bavail, aavail;
|
||||
struct timeval before, after, diff;
|
||||
bavail = snd_pcm_avail_update(pcm);
|
||||
gettimeofday(&before, 0);
|
||||
#endif
|
||||
pfd.fd = snd_pcm_poll_descriptor(pcm);
|
||||
pfd.events = pcm->stream == SND_PCM_STREAM_PLAYBACK ? POLLOUT : POLLIN;
|
||||
err = poll(&pfd, 1, timeout);
|
||||
if (err < 0)
|
||||
return err;
|
||||
#if 0
|
||||
aavail = snd_pcm_avail_update(pcm);
|
||||
gettimeofday(&after, 0);
|
||||
timersub(&after, &before, &diff);
|
||||
fprintf(stderr, "%s %ld.%06ld: get=%d (%d-%d)\n", pcm->stream == SND_PCM_STREAM_PLAYBACK ? "playback" : "capture", diff.tv_sec, diff.tv_usec, aavail - bavail, aavail, bavail);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1044,7 +1046,7 @@ ssize_t snd_pcm_write_areas(snd_pcm_t *pcm, snd_pcm_channel_area_t *areas,
|
|||
return err;
|
||||
}
|
||||
|
||||
void snd_pcm_error_default(const char *file, int line, const char *function, const char *fmt, ...)
|
||||
void snd_pcm_error(const char *file, int line, const char *function, const char *fmt, ...)
|
||||
{
|
||||
va_list arg;
|
||||
va_start(arg, fmt);
|
||||
|
|
@ -1053,5 +1055,3 @@ void snd_pcm_error_default(const char *file, int line, const char *function, con
|
|||
putc('\n', stderr);
|
||||
va_end(arg);
|
||||
}
|
||||
|
||||
void (*snd_pcm_error)(const char *file, int line, const char *function, const char *fmt, ...) = snd_pcm_error_default;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
226
src/pcm/pcm_hw.c
226
src/pcm/pcm_hw.c
|
|
@ -37,25 +37,14 @@
|
|||
typedef struct {
|
||||
int fd;
|
||||
int card, device, subdevice;
|
||||
int mmap_emulation;
|
||||
volatile snd_pcm_mmap_status_t *mmap_status;
|
||||
snd_pcm_mmap_control_t *mmap_control;
|
||||
} snd_pcm_hw_t;
|
||||
|
||||
#define SND_FILE_PCM_STREAM_PLAYBACK "/dev/snd/pcmC%iD%ip"
|
||||
#define SND_FILE_PCM_STREAM_CAPTURE "/dev/snd/pcmC%iD%ic"
|
||||
#define SND_PCM_VERSION_MAX SND_PROTOCOL_VERSION(2, 0, 0)
|
||||
|
||||
static int snd_pcm_hw_close(snd_pcm_t *pcm)
|
||||
{
|
||||
snd_pcm_hw_t *hw = pcm->private;
|
||||
int fd = hw->fd;
|
||||
free(hw);
|
||||
if (close(fd)) {
|
||||
ERR("close failed\n");
|
||||
return -errno;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_pcm_hw_nonblock(snd_pcm_t *pcm, int nonblock)
|
||||
{
|
||||
long flags;
|
||||
|
|
@ -158,9 +147,7 @@ static int snd_pcm_hw_setup(snd_pcm_t *pcm, snd_pcm_setup_t * setup)
|
|||
setup->mmap_shape = SND_PCM_MMAP_INTERLEAVED;
|
||||
else
|
||||
setup->mmap_shape = SND_PCM_MMAP_NONINTERLEAVED;
|
||||
hw->mmap_emulation = 1;
|
||||
} else
|
||||
hw->mmap_emulation = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -194,19 +181,21 @@ static int snd_pcm_hw_channel_setup(snd_pcm_t *pcm, snd_pcm_channel_setup_t * se
|
|||
ERR("SND_PCM_IOCTL_CHANNEL_SETUP failed");
|
||||
return -errno;
|
||||
}
|
||||
if (hw->mmap_emulation) {
|
||||
if (pcm->setup.mmap_shape == SND_PCM_MMAP_INTERLEAVED) {
|
||||
setup->running_area.addr = pcm->mmap_data;
|
||||
if (!pcm->mmap_info)
|
||||
return 0;
|
||||
if (pcm->setup.mmap_shape == SND_PCM_MMAP_UNSPECIFIED) {
|
||||
if (pcm->setup.xfer_mode == SND_PCM_XFER_INTERLEAVED) {
|
||||
setup->running_area.addr = pcm->mmap_info->addr;
|
||||
setup->running_area.first = setup->channel * pcm->bits_per_sample;
|
||||
setup->running_area.step = pcm->bits_per_frame;
|
||||
} else {
|
||||
setup->running_area.addr = pcm->mmap_data + setup->channel * pcm->setup.buffer_size * pcm->bits_per_sample / 8;
|
||||
setup->running_area.addr = pcm->mmap_info->addr + setup->channel * pcm->setup.buffer_size * pcm->bits_per_sample / 8;
|
||||
setup->running_area.first = 0;
|
||||
setup->running_area.step = pcm->bits_per_sample;
|
||||
}
|
||||
setup->stopped_area = setup->running_area;
|
||||
} else {
|
||||
setup->running_area.addr = (char *)pcm->mmap_data + (long)setup->running_area.addr;
|
||||
setup->running_area.addr = pcm->mmap_info->addr + (long)setup->running_area.addr;
|
||||
setup->stopped_area.addr = setup->running_area.addr;
|
||||
}
|
||||
return 0;
|
||||
|
|
@ -225,7 +214,8 @@ static int snd_pcm_hw_status(snd_pcm_t *pcm, snd_pcm_status_t * status)
|
|||
|
||||
static int snd_pcm_hw_state(snd_pcm_t *pcm)
|
||||
{
|
||||
return pcm->mmap_status->state;
|
||||
snd_pcm_hw_t *hw = pcm->private;
|
||||
return hw->mmap_status->state;
|
||||
}
|
||||
|
||||
static int snd_pcm_hw_delay(snd_pcm_t *pcm, ssize_t *delayp)
|
||||
|
|
@ -378,7 +368,8 @@ static int snd_pcm_hw_mmap_status(snd_pcm_t *pcm)
|
|||
ERR("status mmap failed");
|
||||
return -errno;
|
||||
}
|
||||
pcm->mmap_status = ptr;
|
||||
hw->mmap_status = ptr;
|
||||
pcm->hw_ptr = &hw->mmap_status->hw_ptr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -392,36 +383,50 @@ static int snd_pcm_hw_mmap_control(snd_pcm_t *pcm)
|
|||
ERR("control mmap failed");
|
||||
return -errno;
|
||||
}
|
||||
pcm->mmap_control = ptr;
|
||||
hw->mmap_control = ptr;
|
||||
pcm->appl_ptr = &hw->mmap_control->appl_ptr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_pcm_hw_mmap_data(snd_pcm_t *pcm)
|
||||
static int snd_pcm_hw_mmap(snd_pcm_t *pcm)
|
||||
{
|
||||
snd_pcm_hw_t *hw = pcm->private;
|
||||
void *ptr;
|
||||
if (hw->mmap_emulation) {
|
||||
ptr = malloc(snd_pcm_frames_to_bytes(pcm, pcm->setup.buffer_size));
|
||||
if (!ptr)
|
||||
pcm->mmap_info = calloc(1, sizeof(*pcm->mmap_info));
|
||||
if (!pcm->mmap_info)
|
||||
return -ENOMEM;
|
||||
pcm->mmap_info_count = 1;
|
||||
if (pcm->setup.mmap_shape == SND_PCM_MMAP_UNSPECIFIED) {
|
||||
pcm->mmap_info->type = SND_PCM_MMAP_USER;
|
||||
pcm->mmap_info->size = snd_pcm_frames_to_bytes(pcm, pcm->setup.buffer_size);
|
||||
pcm->mmap_info->addr = valloc(pcm->mmap_info->size);
|
||||
if (!pcm->mmap_info->addr) {
|
||||
free(pcm->mmap_info);
|
||||
pcm->mmap_info = 0;
|
||||
return -ENOMEM;
|
||||
}
|
||||
} else {
|
||||
int prot;
|
||||
prot = PROT_WRITE | PROT_READ;
|
||||
ptr = mmap(NULL, pcm->setup.mmap_bytes,
|
||||
prot, MAP_FILE|MAP_SHARED,
|
||||
hw->fd, SND_PCM_MMAP_OFFSET_DATA);
|
||||
if (ptr == MAP_FAILED || ptr == NULL) {
|
||||
pcm->mmap_info->type = SND_PCM_MMAP_KERNEL;
|
||||
pcm->mmap_info->size = pcm->setup.mmap_bytes;
|
||||
pcm->mmap_info->addr = mmap(NULL, pcm->setup.mmap_bytes,
|
||||
PROT_WRITE | PROT_READ,
|
||||
MAP_FILE|MAP_SHARED,
|
||||
hw->fd, SND_PCM_MMAP_OFFSET_DATA);
|
||||
if (pcm->mmap_info->addr == MAP_FAILED ||
|
||||
pcm->mmap_info->addr == NULL) {
|
||||
ERR("data mmap failed");
|
||||
free(pcm->mmap_info);
|
||||
pcm->mmap_info = 0;
|
||||
return -errno;
|
||||
}
|
||||
pcm->mmap_info->u.kernel.fd = hw->fd;
|
||||
}
|
||||
pcm->mmap_data = ptr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_pcm_hw_munmap_status(snd_pcm_t *pcm)
|
||||
{
|
||||
if (munmap((void*)pcm->mmap_status, sizeof(*pcm->mmap_status)) < 0) {
|
||||
snd_pcm_hw_t *hw = pcm->private;
|
||||
if (munmap((void*)hw->mmap_status, sizeof(*hw->mmap_status)) < 0) {
|
||||
ERR("status munmap failed");
|
||||
return -errno;
|
||||
}
|
||||
|
|
@ -430,30 +435,46 @@ static int snd_pcm_hw_munmap_status(snd_pcm_t *pcm)
|
|||
|
||||
static int snd_pcm_hw_munmap_control(snd_pcm_t *pcm)
|
||||
{
|
||||
if (munmap(pcm->mmap_control, sizeof(*pcm->mmap_control)) < 0) {
|
||||
snd_pcm_hw_t *hw = pcm->private;
|
||||
if (munmap(hw->mmap_control, sizeof(*hw->mmap_control)) < 0) {
|
||||
ERR("control munmap failed");
|
||||
return -errno;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_pcm_hw_munmap_data(snd_pcm_t *pcm)
|
||||
static int snd_pcm_hw_munmap(snd_pcm_t *pcm)
|
||||
{
|
||||
snd_pcm_hw_t *hw = pcm->private;
|
||||
if (hw->mmap_emulation)
|
||||
free(pcm->mmap_data);
|
||||
if (pcm->setup.mmap_shape == SND_PCM_MMAP_UNSPECIFIED)
|
||||
free(pcm->mmap_info->addr);
|
||||
else
|
||||
if (munmap(pcm->mmap_data, pcm->setup.mmap_bytes) < 0) {
|
||||
if (munmap(pcm->mmap_info->addr, pcm->mmap_info->size) < 0) {
|
||||
ERR("data munmap failed");
|
||||
return -errno;
|
||||
}
|
||||
pcm->mmap_info_count = 0;
|
||||
free(pcm->mmap_info);
|
||||
pcm->mmap_info = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static 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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue