mirror of
https://github.com/ericonr/sndio.git
synced 2024-02-18 04:45:21 -06:00
put aucat protocol client code into a separate file, so it can
be used by both midi and audio backends (and other aucat backends in the futur)
This commit is contained in:
parent
4c12f59a6b
commit
936815ff03
@ -98,7 +98,7 @@ clean:
|
|||||||
# loader to determine dependencies in a single pass
|
# loader to determine dependencies in a single pass
|
||||||
#
|
#
|
||||||
OBJS = mio.o mio_rmidi.o mio_thru.o sio.o sio_alsa.o sio_aucat.o sio_sun.o \
|
OBJS = mio.o mio_rmidi.o mio_thru.o sio.o sio_alsa.o sio_aucat.o sio_sun.o \
|
||||||
getpeereid.o issetugid.o strlcpy.o strtonum.o
|
aucat.o getpeereid.o issetugid.o strlcpy.o strtonum.o
|
||||||
|
|
||||||
.c.o:
|
.c.o:
|
||||||
${CC} ${CFLAGS} ${SO_CFLAGS} ${INCLUDE} ${DEFS} -o $@ -c $<
|
${CC} ${CFLAGS} ${SO_CFLAGS} ${INCLUDE} ${DEFS} -o $@ -c $<
|
||||||
@ -124,8 +124,9 @@ strlcpy.o: ../bsd-compat/strlcpy.c
|
|||||||
strtonum.o: ../bsd-compat/strtonum.c
|
strtonum.o: ../bsd-compat/strtonum.c
|
||||||
${CC} ${CFLAGS} ${SO_CFLAGS} ${INCLUDE} ${DEFS} -c -o strtonum.o ../bsd-compat/strtonum.c
|
${CC} ${CFLAGS} ${SO_CFLAGS} ${INCLUDE} ${DEFS} -c -o strtonum.o ../bsd-compat/strtonum.c
|
||||||
|
|
||||||
|
aucat.o: aucat.c aucat.h sio_priv.h
|
||||||
sio_alsa.o: sio_alsa.c sio_priv.h sndio.h
|
sio_alsa.o: sio_alsa.c sio_priv.h sndio.h
|
||||||
sio_aucat.o: sio_aucat.c ../aucat/amsg.h ../aucat/conf.h sio_priv.h \
|
sio_aucat.o: sio_aucat.c aucat.h ../aucat/amsg.h ../aucat/conf.h sio_priv.h \
|
||||||
sndio.h ../bsd-compat/bsd-compat.h
|
sndio.h ../bsd-compat/bsd-compat.h
|
||||||
mio.o: mio.c mio_priv.h sndio.h ../bsd-compat/bsd-compat.h
|
mio.o: mio.c mio_priv.h sndio.h ../bsd-compat/bsd-compat.h
|
||||||
mio_rmidi.o: mio_rmidi.c mio_priv.h sndio.h
|
mio_rmidi.o: mio_rmidi.c mio_priv.h sndio.h
|
||||||
|
343
libsndio/aucat.c
Normal file
343
libsndio/aucat.c
Normal file
@ -0,0 +1,343 @@
|
|||||||
|
/* $OpenBSD$ */
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/un.h>
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <poll.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "aucat.h"
|
||||||
|
#ifdef COMPAT_STRLCPY
|
||||||
|
#include "bsd-compat.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int aucat_debug = 0;
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
#define DPRINTF(...) \
|
||||||
|
do { \
|
||||||
|
if (aucat_debug > 0) \
|
||||||
|
fprintf(stderr, __VA_ARGS__); \
|
||||||
|
} while(0)
|
||||||
|
#define DPERROR(s) \
|
||||||
|
do { \
|
||||||
|
if (aucat_debug > 0) \
|
||||||
|
perror(s); \
|
||||||
|
} while(0)
|
||||||
|
#else
|
||||||
|
#define DPRINTF(...) do {} while(0)
|
||||||
|
#define DPERROR(s) do {} while(0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* read a message, return 0 if not completed
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
aucat_rmsg(struct aucat *hdl, int *eof)
|
||||||
|
{
|
||||||
|
ssize_t n;
|
||||||
|
unsigned char *data;
|
||||||
|
|
||||||
|
if (hdl->rstate != STATE_RMSG) {
|
||||||
|
DPRINTF("aucat_rmsg: bad state\n");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
while (hdl->rtodo > 0) {
|
||||||
|
data = (unsigned char *)&hdl->rmsg;
|
||||||
|
data += sizeof(struct amsg) - hdl->rtodo;
|
||||||
|
while ((n = read(hdl->fd, data, hdl->rtodo)) < 0) {
|
||||||
|
if (errno == EINTR)
|
||||||
|
continue;
|
||||||
|
if (errno != EAGAIN) {
|
||||||
|
*eof = 1;
|
||||||
|
DPERROR("aucat_rmsg: read");
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (n == 0) {
|
||||||
|
DPRINTF("aucat_rmsg: eof\n");
|
||||||
|
*eof = 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
hdl->rtodo -= n;
|
||||||
|
}
|
||||||
|
if (hdl->rmsg.cmd == AMSG_DATA) {
|
||||||
|
hdl->rtodo = hdl->rmsg.u.data.size;
|
||||||
|
hdl->rstate = STATE_RDATA;
|
||||||
|
} else {
|
||||||
|
hdl->rtodo = sizeof(struct amsg);
|
||||||
|
hdl->rstate = STATE_RMSG;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* write a message, return 0 if not completed
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
aucat_wmsg(struct aucat *hdl, int *eof)
|
||||||
|
{
|
||||||
|
ssize_t n;
|
||||||
|
unsigned char *data;
|
||||||
|
|
||||||
|
if (hdl->wstate == STATE_WIDLE)
|
||||||
|
hdl->wstate = STATE_WMSG;
|
||||||
|
hdl->wtodo = sizeof(struct amsg);
|
||||||
|
if (hdl->wstate != STATE_WMSG) {
|
||||||
|
DPRINTF("aucat_wmsg: bad state\n");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
while (hdl->wtodo > 0) {
|
||||||
|
data = (unsigned char *)&hdl->wmsg;
|
||||||
|
data += sizeof(struct amsg) - hdl->wtodo;
|
||||||
|
while ((n = write(hdl->fd, data, hdl->wtodo)) < 0) {
|
||||||
|
if (errno == EINTR)
|
||||||
|
continue;
|
||||||
|
if (errno != EAGAIN) {
|
||||||
|
*eof = 1;
|
||||||
|
DPERROR("aucat_wmsg: write");
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
hdl->wtodo -= n;
|
||||||
|
}
|
||||||
|
if (hdl->wmsg.cmd == AMSG_DATA) {
|
||||||
|
hdl->wtodo = hdl->wmsg.u.data.size;
|
||||||
|
hdl->wstate = STATE_WDATA;
|
||||||
|
} else {
|
||||||
|
hdl->wtodo = 0xdeadbeef;
|
||||||
|
hdl->wstate = STATE_WIDLE;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t
|
||||||
|
aucat_rdata(struct aucat *hdl, void *buf, size_t len, int *eof)
|
||||||
|
{
|
||||||
|
ssize_t n;
|
||||||
|
|
||||||
|
if (hdl->rstate != STATE_RDATA) {
|
||||||
|
DPRINTF("aucat_rdata: bad state\n");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
if (len > hdl->rtodo)
|
||||||
|
len = hdl->rtodo;
|
||||||
|
while ((n = read(hdl->fd, buf, len)) < 0) {
|
||||||
|
if (errno == EINTR)
|
||||||
|
continue;
|
||||||
|
if (errno != EAGAIN) {
|
||||||
|
*eof = 1;
|
||||||
|
DPERROR("aucat_rdata: read");
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (n == 0) {
|
||||||
|
DPRINTF("aucat_rdata: eof\n");
|
||||||
|
*eof = 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
hdl->rtodo -= n;
|
||||||
|
if (hdl->rtodo == 0) {
|
||||||
|
hdl->rstate = STATE_RMSG;
|
||||||
|
hdl->rtodo = sizeof(struct amsg);
|
||||||
|
}
|
||||||
|
DPRINTF("aucat_rdata: read: n = %zd\n", n);
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t
|
||||||
|
aucat_wdata(struct aucat *hdl, const void *buf, size_t len, unsigned wbpf, int *eof)
|
||||||
|
{
|
||||||
|
ssize_t n;
|
||||||
|
|
||||||
|
switch (hdl->wstate) {
|
||||||
|
case STATE_WIDLE:
|
||||||
|
if (len > AMSG_DATAMAX)
|
||||||
|
len = AMSG_DATAMAX;
|
||||||
|
len -= len % wbpf;
|
||||||
|
if (len == 0)
|
||||||
|
len = wbpf;
|
||||||
|
hdl->wmsg.cmd = AMSG_DATA;
|
||||||
|
hdl->wmsg.u.data.size = len;
|
||||||
|
hdl->wtodo = sizeof(struct amsg);
|
||||||
|
hdl->wstate = STATE_WMSG;
|
||||||
|
/* FALLTHROUGH */
|
||||||
|
case STATE_WMSG:
|
||||||
|
if (!aucat_wmsg(hdl, eof))
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (len > hdl->wtodo)
|
||||||
|
len = hdl->wtodo;
|
||||||
|
if (len == 0) {
|
||||||
|
DPRINTF("aucat_wdata: len == 0\n");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
while ((n = write(hdl->fd, buf, len)) < 0) {
|
||||||
|
if (errno == EINTR)
|
||||||
|
continue;
|
||||||
|
if (errno != EAGAIN) {
|
||||||
|
*eof = 1;
|
||||||
|
DPERROR("aucat_wdata: write");
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
DPRINTF("aucat_wdata: write: n = %zd\n", n);
|
||||||
|
hdl->wtodo -= n;
|
||||||
|
if (hdl->wtodo == 0) {
|
||||||
|
hdl->wstate = STATE_WIDLE;
|
||||||
|
hdl->wtodo = 0xdeadbeef;
|
||||||
|
}
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
aucat_open(struct aucat *hdl, const char *str, char *sock, unsigned mode, int nbio)
|
||||||
|
{
|
||||||
|
extern char *__progname;
|
||||||
|
int s, eof;
|
||||||
|
char unit[4], *sep, *opt, *debug;
|
||||||
|
struct sockaddr_un ca;
|
||||||
|
socklen_t len = sizeof(struct sockaddr_un);
|
||||||
|
uid_t uid;
|
||||||
|
|
||||||
|
debug = getenv("AUCAT_DEBUG");
|
||||||
|
if (debug)
|
||||||
|
sscanf(debug, "%u", &aucat_debug);
|
||||||
|
|
||||||
|
sep = strchr(str, '.');
|
||||||
|
if (sep == NULL) {
|
||||||
|
opt = "default";
|
||||||
|
strlcpy(unit, str, sizeof(unit));
|
||||||
|
} else {
|
||||||
|
opt = sep + 1;
|
||||||
|
if (sep - str >= sizeof(unit)) {
|
||||||
|
DPRINTF("aucat_init: %s: too long\n", str);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
strlcpy(unit, str, opt - str);
|
||||||
|
}
|
||||||
|
DPRINTF("aucat_init: trying %s -> %s.%s\n", str, unit, opt);
|
||||||
|
uid = geteuid();
|
||||||
|
if (strchr(str, '/') != NULL)
|
||||||
|
return NULL;
|
||||||
|
snprintf(ca.sun_path, sizeof(ca.sun_path),
|
||||||
|
"/tmp/aucat-%u/%s%s", uid, sock, unit);
|
||||||
|
ca.sun_family = AF_UNIX;
|
||||||
|
|
||||||
|
s = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||||
|
if (s < 0)
|
||||||
|
goto bad_free;
|
||||||
|
while (connect(s, (struct sockaddr *)&ca, len) < 0) {
|
||||||
|
if (errno == EINTR)
|
||||||
|
continue;
|
||||||
|
DPERROR("aucat_init: connect");
|
||||||
|
/* try shared server */
|
||||||
|
snprintf(ca.sun_path, sizeof(ca.sun_path),
|
||||||
|
"/tmp/aucat/%s%s", sock, unit);
|
||||||
|
while (connect(s, (struct sockaddr *)&ca, len) < 0) {
|
||||||
|
if (errno == EINTR)
|
||||||
|
continue;
|
||||||
|
DPERROR("aucat_init: connect");
|
||||||
|
goto bad_connect;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (fcntl(s, F_SETFD, FD_CLOEXEC) < 0) {
|
||||||
|
DPERROR("FD_CLOEXEC");
|
||||||
|
goto bad_connect;
|
||||||
|
}
|
||||||
|
hdl->fd = s;
|
||||||
|
hdl->rstate = STATE_RMSG;
|
||||||
|
hdl->rtodo = sizeof(struct amsg);
|
||||||
|
hdl->wstate = STATE_WIDLE;
|
||||||
|
hdl->wtodo = 0xdeadbeef;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* say hello to server
|
||||||
|
*/
|
||||||
|
AMSG_INIT(&hdl->wmsg);
|
||||||
|
hdl->wmsg.cmd = AMSG_HELLO;
|
||||||
|
hdl->wmsg.u.hello.version = AMSG_VERSION;
|
||||||
|
hdl->wmsg.u.hello.mode = mode;
|
||||||
|
strlcpy(hdl->wmsg.u.hello.who, __progname,
|
||||||
|
sizeof(hdl->wmsg.u.hello.who));
|
||||||
|
strlcpy(hdl->wmsg.u.hello.opt, opt,
|
||||||
|
sizeof(hdl->wmsg.u.hello.opt));
|
||||||
|
hdl->wtodo = sizeof(struct amsg);
|
||||||
|
if (!aucat_wmsg(hdl, &eof))
|
||||||
|
goto bad_connect;
|
||||||
|
hdl->rtodo = sizeof(struct amsg);
|
||||||
|
if (!aucat_rmsg(hdl, &eof)) {
|
||||||
|
DPRINTF("aucat_init: mode refused\n");
|
||||||
|
goto bad_connect;
|
||||||
|
}
|
||||||
|
if (hdl->rmsg.cmd != AMSG_ACK) {
|
||||||
|
DPRINTF("aucat_init: protocol err\n");
|
||||||
|
goto bad_connect;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
bad_connect:
|
||||||
|
while (close(s) < 0 && errno == EINTR)
|
||||||
|
; /* retry */
|
||||||
|
bad_free:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
aucat_close(struct aucat *hdl, int eof)
|
||||||
|
{
|
||||||
|
char dummy[1];
|
||||||
|
|
||||||
|
if (!eof) {
|
||||||
|
AMSG_INIT(&hdl->wmsg);
|
||||||
|
hdl->wmsg.cmd = AMSG_BYE;
|
||||||
|
hdl->wtodo = sizeof(struct amsg);
|
||||||
|
if (!aucat_wmsg(hdl, &eof))
|
||||||
|
goto bad_close;
|
||||||
|
while (read(hdl->fd, dummy, 1) < 0 && errno == EINTR)
|
||||||
|
; /* nothing */
|
||||||
|
}
|
||||||
|
bad_close:
|
||||||
|
while (close(hdl->fd) < 0 && errno == EINTR)
|
||||||
|
; /* nothing */
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
aucat_pollfd(struct aucat *hdl, struct pollfd *pfd, int events)
|
||||||
|
{
|
||||||
|
if (hdl->rstate == STATE_RMSG)
|
||||||
|
events |= POLLIN;
|
||||||
|
pfd->fd = hdl->fd;
|
||||||
|
pfd->events = events;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
aucat_revents(struct aucat *hdl, struct pollfd *pfd)
|
||||||
|
{
|
||||||
|
int revents = pfd->revents;
|
||||||
|
|
||||||
|
DPRINTF("aucat_revents: revents: %x\n", revents);
|
||||||
|
return revents;
|
||||||
|
}
|
31
libsndio/aucat.h
Normal file
31
libsndio/aucat.h
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
#ifndef AUCAT_H
|
||||||
|
#define AUCAT_H
|
||||||
|
|
||||||
|
#include "amsg.h"
|
||||||
|
|
||||||
|
struct sio_hdl;
|
||||||
|
struct mio_hdl;
|
||||||
|
|
||||||
|
struct aucat {
|
||||||
|
int fd; /* socket */
|
||||||
|
struct amsg rmsg, wmsg; /* temporary messages */
|
||||||
|
size_t wtodo, rtodo; /* bytes to complete the packet */
|
||||||
|
#define STATE_RMSG 0 /* message being received */
|
||||||
|
#define STATE_RDATA 1 /* data being received */
|
||||||
|
unsigned rstate; /* one of above */
|
||||||
|
#define STATE_WIDLE 2 /* nothing to do */
|
||||||
|
#define STATE_WMSG 3 /* message being transferred */
|
||||||
|
#define STATE_WDATA 4 /* data being transferred */
|
||||||
|
unsigned wstate; /* one of above */
|
||||||
|
};
|
||||||
|
|
||||||
|
int aucat_rmsg(struct aucat *, int *);
|
||||||
|
int aucat_wmsg(struct aucat *, int *);
|
||||||
|
size_t aucat_rdata(struct aucat *, void *, size_t, int *);
|
||||||
|
size_t aucat_wdata(struct aucat *, const void *, size_t, unsigned, int *);
|
||||||
|
int aucat_open(struct aucat *, const char *, char *, unsigned, int);
|
||||||
|
void aucat_close(struct aucat *, int);
|
||||||
|
int aucat_pollfd(struct aucat *, struct pollfd *, int);
|
||||||
|
int aucat_revents(struct aucat *, struct pollfd *);
|
||||||
|
|
||||||
|
#endif /* !defined(AUCAT_H) */
|
@ -27,7 +27,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "amsg.h"
|
#include "aucat.h"
|
||||||
#include "sio_priv.h"
|
#include "sio_priv.h"
|
||||||
#ifdef COMPAT_STRLCPY
|
#ifdef COMPAT_STRLCPY
|
||||||
#include "bsd-compat.h"
|
#include "bsd-compat.h"
|
||||||
@ -35,18 +35,15 @@
|
|||||||
|
|
||||||
struct sio_aucat_hdl {
|
struct sio_aucat_hdl {
|
||||||
struct sio_hdl sio;
|
struct sio_hdl sio;
|
||||||
int fd; /* socket */
|
struct aucat aucat;
|
||||||
struct amsg rmsg, wmsg; /* temporary messages */
|
|
||||||
size_t wtodo, rtodo; /* bytes to complete the packet */
|
|
||||||
#define STATE_IDLE 0 /* nothing to do */
|
|
||||||
#define STATE_MSG 1 /* message being transferred */
|
|
||||||
#define STATE_DATA 2 /* data being transferred */
|
|
||||||
unsigned rstate, wstate; /* one of above */
|
|
||||||
unsigned rbpf, wbpf; /* read and write bytes-per-frame */
|
unsigned rbpf, wbpf; /* read and write bytes-per-frame */
|
||||||
int maxwrite; /* latency constraint */
|
int maxwrite; /* latency constraint */
|
||||||
int events; /* events the user requested */
|
int events; /* events the user requested */
|
||||||
unsigned curvol, reqvol; /* current and requested volume */
|
unsigned curvol, reqvol; /* current and requested volume */
|
||||||
int delta; /* some of received deltas */
|
int delta; /* some of received deltas */
|
||||||
|
#define STATE_INIT 0
|
||||||
|
#define STATE_RUN 1
|
||||||
|
int pstate;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void sio_aucat_close(struct sio_hdl *);
|
static void sio_aucat_close(struct sio_hdl *);
|
||||||
@ -79,239 +76,97 @@ static struct sio_ops sio_aucat_ops = {
|
|||||||
sio_aucat_getvol
|
sio_aucat_getvol
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
|
||||||
* read a message, return 0 if blocked
|
|
||||||
*/
|
|
||||||
static int
|
|
||||||
sio_aucat_rmsg(struct sio_aucat_hdl *hdl)
|
|
||||||
{
|
|
||||||
ssize_t n;
|
|
||||||
unsigned char *data;
|
|
||||||
|
|
||||||
while (hdl->rtodo > 0) {
|
|
||||||
data = (unsigned char *)&hdl->rmsg;
|
|
||||||
data += sizeof(struct amsg) - hdl->rtodo;
|
|
||||||
while ((n = read(hdl->fd, data, hdl->rtodo)) < 0) {
|
|
||||||
if (errno == EINTR)
|
|
||||||
continue;
|
|
||||||
if (errno != EAGAIN) {
|
|
||||||
hdl->sio.eof = 1;
|
|
||||||
DPERROR("sio_aucat_rmsg: read");
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (n == 0) {
|
|
||||||
DPRINTF("sio_aucat_rmsg: eof\n");
|
|
||||||
hdl->sio.eof = 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
hdl->rtodo -= n;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* write a message, return 0 if blocked
|
|
||||||
*/
|
|
||||||
static int
|
|
||||||
sio_aucat_wmsg(struct sio_aucat_hdl *hdl)
|
|
||||||
{
|
|
||||||
ssize_t n;
|
|
||||||
unsigned char *data;
|
|
||||||
|
|
||||||
while (hdl->wtodo > 0) {
|
|
||||||
data = (unsigned char *)&hdl->wmsg;
|
|
||||||
data += sizeof(struct amsg) - hdl->wtodo;
|
|
||||||
while ((n = write(hdl->fd, data, hdl->wtodo)) < 0) {
|
|
||||||
if (errno == EINTR)
|
|
||||||
continue;
|
|
||||||
if (errno != EAGAIN) {
|
|
||||||
hdl->sio.eof = 1;
|
|
||||||
DPERROR("sio_aucat_wmsg: write");
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
hdl->wtodo -= n;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* execute the next message, return 0 if blocked
|
* execute the next message, return 0 if blocked
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
sio_aucat_runmsg(struct sio_aucat_hdl *hdl)
|
sio_aucat_runmsg(struct sio_aucat_hdl *hdl)
|
||||||
{
|
{
|
||||||
if (!sio_aucat_rmsg(hdl))
|
if (!aucat_rmsg(&hdl->aucat, &hdl->sio.eof))
|
||||||
return 0;
|
return 0;
|
||||||
switch (hdl->rmsg.cmd) {
|
switch (hdl->aucat.rmsg.cmd) {
|
||||||
case AMSG_DATA:
|
case AMSG_DATA:
|
||||||
if (hdl->rmsg.u.data.size == 0 ||
|
if (hdl->aucat.rmsg.u.data.size == 0 ||
|
||||||
hdl->rmsg.u.data.size % hdl->rbpf) {
|
hdl->aucat.rmsg.u.data.size % hdl->rbpf) {
|
||||||
DPRINTF("sio_aucat_runmsg: bad data message\n");
|
DPRINTF("sio_aucat_runmsg: bad data message\n");
|
||||||
hdl->sio.eof = 1;
|
hdl->sio.eof = 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
hdl->rstate = STATE_DATA;
|
return 1;
|
||||||
hdl->rtodo = hdl->rmsg.u.data.size;
|
|
||||||
break;
|
|
||||||
case AMSG_POS:
|
case AMSG_POS:
|
||||||
hdl->maxwrite += hdl->rmsg.u.ts.delta * (int)hdl->wbpf;
|
hdl->maxwrite += hdl->aucat.rmsg.u.ts.delta * (int)hdl->wbpf;
|
||||||
DPRINTF("aucat: pos = %d, maxwrite = %d\n",
|
DPRINTF("aucat: pos = %d, maxwrite = %d\n",
|
||||||
hdl->rmsg.u.ts.delta, hdl->maxwrite);
|
hdl->aucat.rmsg.u.ts.delta, hdl->maxwrite);
|
||||||
hdl->delta = hdl->rmsg.u.ts.delta;
|
hdl->delta = hdl->aucat.rmsg.u.ts.delta;
|
||||||
hdl->rstate = STATE_MSG;
|
|
||||||
hdl->rtodo = sizeof(struct amsg);
|
|
||||||
break;
|
break;
|
||||||
case AMSG_MOVE:
|
case AMSG_MOVE:
|
||||||
hdl->maxwrite += hdl->rmsg.u.ts.delta * hdl->wbpf;
|
hdl->maxwrite += hdl->aucat.rmsg.u.ts.delta * hdl->wbpf;
|
||||||
hdl->delta += hdl->rmsg.u.ts.delta;
|
hdl->delta += hdl->aucat.rmsg.u.ts.delta;
|
||||||
DPRINTF("aucat: move = %d, delta = %d, maxwrite = %d\n",
|
DPRINTF("aucat: move = %d, delta = %d, maxwrite = %d\n",
|
||||||
hdl->rmsg.u.ts.delta, hdl->delta, hdl->maxwrite);
|
hdl->aucat.rmsg.u.ts.delta, hdl->delta, hdl->maxwrite);
|
||||||
if (hdl->delta >= 0) {
|
if (hdl->delta >= 0) {
|
||||||
sio_onmove_cb(&hdl->sio, hdl->delta);
|
sio_onmove_cb(&hdl->sio, hdl->delta);
|
||||||
hdl->delta = 0;
|
hdl->delta = 0;
|
||||||
}
|
}
|
||||||
hdl->rstate = STATE_MSG;
|
|
||||||
hdl->rtodo = sizeof(struct amsg);
|
|
||||||
break;
|
break;
|
||||||
case AMSG_SETVOL:
|
case AMSG_SETVOL:
|
||||||
hdl->curvol = hdl->reqvol = hdl->rmsg.u.vol.ctl;
|
hdl->curvol = hdl->reqvol = hdl->aucat.rmsg.u.vol.ctl;
|
||||||
sio_onvol_cb(&hdl->sio, hdl->curvol);
|
sio_onvol_cb(&hdl->sio, hdl->curvol);
|
||||||
hdl->rstate = STATE_MSG;
|
|
||||||
hdl->rtodo = sizeof(struct amsg);
|
|
||||||
break;
|
break;
|
||||||
case AMSG_GETPAR:
|
case AMSG_STOP:
|
||||||
case AMSG_ACK:
|
hdl->pstate = STATE_INIT;
|
||||||
hdl->rstate = STATE_IDLE;
|
|
||||||
hdl->rtodo = 0xdeadbeef;
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
DPRINTF("sio_aucat_runmsg: unknown message\n");
|
DPRINTF("sio_aucat_runmsg: unhandled message %u\n", hdl->aucat.rmsg.cmd);
|
||||||
hdl->sio.eof = 1;
|
hdl->sio.eof = 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
hdl->aucat.rstate = STATE_RMSG;
|
||||||
|
hdl->aucat.rtodo = sizeof(struct amsg);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
sio_aucat_buildmsg(struct sio_aucat_hdl *hdl)
|
||||||
|
{
|
||||||
|
if (hdl->curvol != hdl->reqvol) {
|
||||||
|
hdl->aucat.wstate = STATE_WMSG;
|
||||||
|
hdl->aucat.wtodo = sizeof(struct amsg);
|
||||||
|
hdl->aucat.wmsg.cmd = AMSG_SETVOL;
|
||||||
|
hdl->aucat.wmsg.u.vol.ctl = hdl->reqvol;
|
||||||
|
hdl->curvol = hdl->reqvol;
|
||||||
|
return aucat_wmsg(&hdl->aucat, &hdl->sio.eof);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
struct sio_hdl *
|
struct sio_hdl *
|
||||||
sio_aucat_open(const char *str, unsigned mode, int nbio)
|
sio_aucat_open(const char *str, unsigned mode, int nbio)
|
||||||
{
|
{
|
||||||
extern char *__progname;
|
|
||||||
int s;
|
|
||||||
char unit[4], *sep, *opt;
|
|
||||||
struct sio_aucat_hdl *hdl;
|
struct sio_aucat_hdl *hdl;
|
||||||
struct sockaddr_un ca;
|
|
||||||
socklen_t len = sizeof(struct sockaddr_un);
|
|
||||||
uid_t uid;
|
|
||||||
|
|
||||||
sep = strchr(str, '.');
|
|
||||||
if (sep == NULL) {
|
|
||||||
opt = "default";
|
|
||||||
strlcpy(unit, str, sizeof(unit));
|
|
||||||
} else {
|
|
||||||
opt = sep + 1;
|
|
||||||
if (sep - str >= sizeof(unit)) {
|
|
||||||
DPRINTF("sio_open_aucat: %s: too long\n", str);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
strlcpy(unit, str, opt - str);
|
|
||||||
}
|
|
||||||
DPRINTF("sio_open_aucat: trying %s -> %s.%s\n", str, unit, opt);
|
|
||||||
uid = geteuid();
|
|
||||||
if (strchr(str, '/') != NULL)
|
|
||||||
return NULL;
|
|
||||||
snprintf(ca.sun_path, sizeof(ca.sun_path),
|
|
||||||
"/tmp/aucat-%u/softaudio%s", uid, unit);
|
|
||||||
ca.sun_family = AF_UNIX;
|
|
||||||
|
|
||||||
hdl = malloc(sizeof(struct sio_aucat_hdl));
|
hdl = malloc(sizeof(struct sio_aucat_hdl));
|
||||||
if (hdl == NULL)
|
if (hdl == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
if (!aucat_open(&hdl->aucat, str, "softaudio", mode, nbio)) {
|
||||||
|
free(hdl);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
sio_create(&hdl->sio, &sio_aucat_ops, mode, nbio);
|
sio_create(&hdl->sio, &sio_aucat_ops, mode, nbio);
|
||||||
|
|
||||||
s = socket(AF_UNIX, SOCK_STREAM, 0);
|
|
||||||
if (s < 0)
|
|
||||||
goto bad_free;
|
|
||||||
while (connect(s, (struct sockaddr *)&ca, len) < 0) {
|
|
||||||
if (errno == EINTR)
|
|
||||||
continue;
|
|
||||||
DPERROR("sio_open_aucat: connect");
|
|
||||||
/* try shared server */
|
|
||||||
snprintf(ca.sun_path, sizeof(ca.sun_path),
|
|
||||||
"/tmp/aucat/softaudio%s", unit);
|
|
||||||
while (connect(s, (struct sockaddr *)&ca, len) < 0) {
|
|
||||||
if (errno == EINTR)
|
|
||||||
continue;
|
|
||||||
DPERROR("sio_open_aucat: connect");
|
|
||||||
goto bad_connect;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (fcntl(s, F_SETFD, FD_CLOEXEC) < 0) {
|
|
||||||
DPERROR("FD_CLOEXEC");
|
|
||||||
goto bad_connect;
|
|
||||||
}
|
|
||||||
hdl->fd = s;
|
|
||||||
hdl->rstate = STATE_IDLE;
|
|
||||||
hdl->rtodo = 0xdeadbeef;
|
|
||||||
hdl->wstate = STATE_IDLE;
|
|
||||||
hdl->wtodo = 0xdeadbeef;
|
|
||||||
hdl->curvol = SIO_MAXVOL;
|
hdl->curvol = SIO_MAXVOL;
|
||||||
hdl->reqvol = SIO_MAXVOL;
|
hdl->reqvol = SIO_MAXVOL;
|
||||||
|
hdl->pstate = STATE_INIT;
|
||||||
/*
|
|
||||||
* say hello to server
|
|
||||||
*/
|
|
||||||
AMSG_INIT(&hdl->wmsg);
|
|
||||||
hdl->wmsg.cmd = AMSG_HELLO;
|
|
||||||
hdl->wmsg.u.hello.version = AMSG_VERSION;
|
|
||||||
hdl->wmsg.u.hello.mode = mode;
|
|
||||||
strlcpy(hdl->wmsg.u.hello.who, __progname,
|
|
||||||
sizeof(hdl->wmsg.u.hello.who));
|
|
||||||
strlcpy(hdl->wmsg.u.hello.opt, opt,
|
|
||||||
sizeof(hdl->wmsg.u.hello.opt));
|
|
||||||
hdl->wtodo = sizeof(struct amsg);
|
|
||||||
if (!sio_aucat_wmsg(hdl))
|
|
||||||
goto bad_connect;
|
|
||||||
hdl->rtodo = sizeof(struct amsg);
|
|
||||||
if (!sio_aucat_rmsg(hdl)) {
|
|
||||||
DPRINTF("sio_open_aucat: mode refused\n");
|
|
||||||
goto bad_connect;
|
|
||||||
}
|
|
||||||
if (hdl->rmsg.cmd != AMSG_ACK) {
|
|
||||||
DPRINTF("sio_open_aucat: protocol err\n");
|
|
||||||
goto bad_connect;
|
|
||||||
}
|
|
||||||
return (struct sio_hdl *)hdl;
|
return (struct sio_hdl *)hdl;
|
||||||
bad_connect:
|
|
||||||
while (close(s) < 0 && errno == EINTR)
|
|
||||||
; /* retry */
|
|
||||||
bad_free:
|
|
||||||
free(hdl);
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
sio_aucat_close(struct sio_hdl *sh)
|
sio_aucat_close(struct sio_hdl *sh)
|
||||||
{
|
{
|
||||||
struct sio_aucat_hdl *hdl = (struct sio_aucat_hdl *)sh;
|
struct sio_aucat_hdl *hdl = (struct sio_aucat_hdl *)sh;
|
||||||
char dummy[1];
|
|
||||||
|
|
||||||
if (!hdl->sio.eof && hdl->sio.started)
|
if (!hdl->sio.eof && hdl->sio.started)
|
||||||
(void)sio_aucat_stop(&hdl->sio);
|
(void)sio_aucat_stop(&hdl->sio);
|
||||||
if (!hdl->sio.eof) {
|
aucat_close(&hdl->aucat, hdl->sio.eof);
|
||||||
AMSG_INIT(&hdl->wmsg);
|
|
||||||
hdl->wmsg.cmd = AMSG_BYE;
|
|
||||||
hdl->wtodo = sizeof(struct amsg);
|
|
||||||
if (!sio_aucat_wmsg(hdl))
|
|
||||||
goto bad_close;
|
|
||||||
while (read(hdl->fd, dummy, 1) < 0 && errno == EINTR)
|
|
||||||
; /* nothing */
|
|
||||||
}
|
|
||||||
bad_close:
|
|
||||||
while (close(hdl->fd) < 0 && errno == EINTR)
|
|
||||||
; /* nothing */
|
|
||||||
free(hdl);
|
free(hdl);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -332,18 +187,19 @@ sio_aucat_start(struct sio_hdl *sh)
|
|||||||
hdl->delta = 0;
|
hdl->delta = 0;
|
||||||
DPRINTF("aucat: start, maxwrite = %d\n", hdl->maxwrite);
|
DPRINTF("aucat: start, maxwrite = %d\n", hdl->maxwrite);
|
||||||
|
|
||||||
AMSG_INIT(&hdl->wmsg);
|
AMSG_INIT(&hdl->aucat.wmsg);
|
||||||
hdl->wmsg.cmd = AMSG_START;
|
hdl->aucat.wmsg.cmd = AMSG_START;
|
||||||
hdl->wtodo = sizeof(struct amsg);
|
hdl->aucat.wtodo = sizeof(struct amsg);
|
||||||
if (!sio_aucat_wmsg(hdl))
|
if (!aucat_wmsg(&hdl->aucat, &hdl->sio.eof))
|
||||||
return 0;
|
return 0;
|
||||||
hdl->rstate = STATE_MSG;
|
hdl->aucat.rstate = STATE_RMSG;
|
||||||
hdl->rtodo = sizeof(struct amsg);
|
hdl->aucat.rtodo = sizeof(struct amsg);
|
||||||
if (fcntl(hdl->fd, F_SETFL, O_NONBLOCK) < 0) {
|
if (fcntl(hdl->aucat.fd, F_SETFL, O_NONBLOCK) < 0) {
|
||||||
DPERROR("sio_aucat_start: fcntl(0)");
|
DPERROR("sio_aucat_start: fcntl(0)");
|
||||||
hdl->sio.eof = 1;
|
hdl->sio.eof = 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
hdl->pstate = STATE_RUN;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -355,7 +211,7 @@ sio_aucat_stop(struct sio_hdl *sh)
|
|||||||
struct sio_aucat_hdl *hdl = (struct sio_aucat_hdl *)sh;
|
struct sio_aucat_hdl *hdl = (struct sio_aucat_hdl *)sh;
|
||||||
unsigned n, count;
|
unsigned n, count;
|
||||||
|
|
||||||
if (fcntl(hdl->fd, F_SETFL, 0) < 0) {
|
if (fcntl(hdl->aucat.fd, F_SETFL, 0) < 0) {
|
||||||
DPERROR("sio_aucat_stop: fcntl(0)");
|
DPERROR("sio_aucat_stop: fcntl(0)");
|
||||||
hdl->sio.eof = 1;
|
hdl->sio.eof = 1;
|
||||||
return 0;
|
return 0;
|
||||||
@ -364,19 +220,14 @@ sio_aucat_stop(struct sio_hdl *sh)
|
|||||||
/*
|
/*
|
||||||
* complete message or data block in progress
|
* complete message or data block in progress
|
||||||
*/
|
*/
|
||||||
if (hdl->wstate == STATE_MSG) {
|
if (hdl->aucat.wstate == STATE_WMSG) {
|
||||||
if (!sio_aucat_wmsg(hdl))
|
if (!aucat_wmsg(&hdl->aucat, &hdl->sio.eof))
|
||||||
return 0;
|
return 0;
|
||||||
if (hdl->wmsg.cmd == AMSG_DATA) {
|
|
||||||
hdl->wstate = STATE_DATA;
|
|
||||||
hdl->wtodo = hdl->wmsg.u.data.size;
|
|
||||||
} else
|
|
||||||
hdl->wstate = STATE_IDLE;
|
|
||||||
}
|
}
|
||||||
if (hdl->wstate == STATE_DATA) {
|
if (hdl->aucat.wstate == STATE_WDATA) {
|
||||||
hdl->maxwrite = hdl->wtodo;
|
hdl->maxwrite = hdl->aucat.wtodo;
|
||||||
while (hdl->wstate != STATE_IDLE) {
|
while (hdl->aucat.wstate != STATE_WIDLE) {
|
||||||
count = hdl->wtodo;
|
count = hdl->aucat.wtodo;
|
||||||
if (count > ZERO_MAX)
|
if (count > ZERO_MAX)
|
||||||
count = ZERO_MAX;
|
count = ZERO_MAX;
|
||||||
n = sio_aucat_write(&hdl->sio, zero, count);
|
n = sio_aucat_write(&hdl->sio, zero, count);
|
||||||
@ -388,26 +239,22 @@ sio_aucat_stop(struct sio_hdl *sh)
|
|||||||
/*
|
/*
|
||||||
* send stop message
|
* send stop message
|
||||||
*/
|
*/
|
||||||
AMSG_INIT(&hdl->wmsg);
|
AMSG_INIT(&hdl->aucat.wmsg);
|
||||||
hdl->wmsg.cmd = AMSG_STOP;
|
hdl->aucat.wmsg.cmd = AMSG_STOP;
|
||||||
hdl->wtodo = sizeof(struct amsg);
|
hdl->aucat.wtodo = sizeof(struct amsg);
|
||||||
if (!sio_aucat_wmsg(hdl))
|
if (!aucat_wmsg(&hdl->aucat, &hdl->sio.eof))
|
||||||
return 0;
|
return 0;
|
||||||
if (hdl->rstate == STATE_IDLE) {
|
|
||||||
hdl->rstate = STATE_MSG;
|
|
||||||
hdl->rtodo = sizeof(struct amsg);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* wait for the STOP ACK
|
* wait for the STOP ACK
|
||||||
*/
|
*/
|
||||||
while (hdl->rstate != STATE_IDLE) {
|
while (hdl->pstate != STATE_INIT) {
|
||||||
switch (hdl->rstate) {
|
switch (hdl->aucat.rstate) {
|
||||||
case STATE_MSG:
|
case STATE_RMSG:
|
||||||
if (!sio_aucat_runmsg(hdl))
|
if (!sio_aucat_runmsg(hdl))
|
||||||
return 0;
|
return 0;
|
||||||
break;
|
break;
|
||||||
case STATE_DATA:
|
case STATE_RDATA:
|
||||||
if (!sio_aucat_read(&hdl->sio, zero, ZERO_MAX))
|
if (!sio_aucat_read(&hdl->sio, zero, ZERO_MAX))
|
||||||
return 0;
|
return 0;
|
||||||
break;
|
break;
|
||||||
@ -421,22 +268,22 @@ sio_aucat_setpar(struct sio_hdl *sh, struct sio_par *par)
|
|||||||
{
|
{
|
||||||
struct sio_aucat_hdl *hdl = (struct sio_aucat_hdl *)sh;
|
struct sio_aucat_hdl *hdl = (struct sio_aucat_hdl *)sh;
|
||||||
|
|
||||||
AMSG_INIT(&hdl->wmsg);
|
AMSG_INIT(&hdl->aucat.wmsg);
|
||||||
hdl->wmsg.cmd = AMSG_SETPAR;
|
hdl->aucat.wmsg.cmd = AMSG_SETPAR;
|
||||||
hdl->wmsg.u.par.bits = par->bits;
|
hdl->aucat.wmsg.u.par.bits = par->bits;
|
||||||
hdl->wmsg.u.par.bps = par->bps;
|
hdl->aucat.wmsg.u.par.bps = par->bps;
|
||||||
hdl->wmsg.u.par.sig = par->sig;
|
hdl->aucat.wmsg.u.par.sig = par->sig;
|
||||||
hdl->wmsg.u.par.le = par->le;
|
hdl->aucat.wmsg.u.par.le = par->le;
|
||||||
hdl->wmsg.u.par.msb = par->msb;
|
hdl->aucat.wmsg.u.par.msb = par->msb;
|
||||||
hdl->wmsg.u.par.rate = par->rate;
|
hdl->aucat.wmsg.u.par.rate = par->rate;
|
||||||
hdl->wmsg.u.par.appbufsz = par->appbufsz;
|
hdl->aucat.wmsg.u.par.appbufsz = par->appbufsz;
|
||||||
hdl->wmsg.u.par.xrun = par->xrun;
|
hdl->aucat.wmsg.u.par.xrun = par->xrun;
|
||||||
if (hdl->sio.mode & SIO_REC)
|
if (hdl->sio.mode & SIO_REC)
|
||||||
hdl->wmsg.u.par.rchan = par->rchan;
|
hdl->aucat.wmsg.u.par.rchan = par->rchan;
|
||||||
if (hdl->sio.mode & SIO_PLAY)
|
if (hdl->sio.mode & SIO_PLAY)
|
||||||
hdl->wmsg.u.par.pchan = par->pchan;
|
hdl->aucat.wmsg.u.par.pchan = par->pchan;
|
||||||
hdl->wtodo = sizeof(struct amsg);
|
hdl->aucat.wtodo = sizeof(struct amsg);
|
||||||
if (!sio_aucat_wmsg(hdl))
|
if (!aucat_wmsg(&hdl->aucat, &hdl->sio.eof))
|
||||||
return 0;
|
return 0;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -446,33 +293,33 @@ sio_aucat_getpar(struct sio_hdl *sh, struct sio_par *par)
|
|||||||
{
|
{
|
||||||
struct sio_aucat_hdl *hdl = (struct sio_aucat_hdl *)sh;
|
struct sio_aucat_hdl *hdl = (struct sio_aucat_hdl *)sh;
|
||||||
|
|
||||||
AMSG_INIT(&hdl->wmsg);
|
AMSG_INIT(&hdl->aucat.wmsg);
|
||||||
hdl->wmsg.cmd = AMSG_GETPAR;
|
hdl->aucat.wmsg.cmd = AMSG_GETPAR;
|
||||||
hdl->wtodo = sizeof(struct amsg);
|
hdl->aucat.wtodo = sizeof(struct amsg);
|
||||||
if (!sio_aucat_wmsg(hdl))
|
if (!aucat_wmsg(&hdl->aucat, &hdl->sio.eof))
|
||||||
return 0;
|
return 0;
|
||||||
hdl->rtodo = sizeof(struct amsg);
|
hdl->aucat.rtodo = sizeof(struct amsg);
|
||||||
if (!sio_aucat_rmsg(hdl))
|
if (!aucat_rmsg(&hdl->aucat, &hdl->sio.eof))
|
||||||
return 0;
|
return 0;
|
||||||
if (hdl->rmsg.cmd != AMSG_GETPAR) {
|
if (hdl->aucat.rmsg.cmd != AMSG_GETPAR) {
|
||||||
DPRINTF("sio_aucat_getpar: protocol err\n");
|
DPRINTF("sio_aucat_getpar: protocol err\n");
|
||||||
hdl->sio.eof = 1;
|
hdl->sio.eof = 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
par->bits = hdl->rmsg.u.par.bits;
|
par->bits = hdl->aucat.rmsg.u.par.bits;
|
||||||
par->bps = hdl->rmsg.u.par.bps;
|
par->bps = hdl->aucat.rmsg.u.par.bps;
|
||||||
par->sig = hdl->rmsg.u.par.sig;
|
par->sig = hdl->aucat.rmsg.u.par.sig;
|
||||||
par->le = hdl->rmsg.u.par.le;
|
par->le = hdl->aucat.rmsg.u.par.le;
|
||||||
par->msb = hdl->rmsg.u.par.msb;
|
par->msb = hdl->aucat.rmsg.u.par.msb;
|
||||||
par->rate = hdl->rmsg.u.par.rate;
|
par->rate = hdl->aucat.rmsg.u.par.rate;
|
||||||
par->bufsz = hdl->rmsg.u.par.bufsz;
|
par->bufsz = hdl->aucat.rmsg.u.par.bufsz;
|
||||||
par->appbufsz = hdl->rmsg.u.par.appbufsz;
|
par->appbufsz = hdl->aucat.rmsg.u.par.appbufsz;
|
||||||
par->xrun = hdl->rmsg.u.par.xrun;
|
par->xrun = hdl->aucat.rmsg.u.par.xrun;
|
||||||
par->round = hdl->rmsg.u.par.round;
|
par->round = hdl->aucat.rmsg.u.par.round;
|
||||||
if (hdl->sio.mode & SIO_PLAY)
|
if (hdl->sio.mode & SIO_PLAY)
|
||||||
par->pchan = hdl->rmsg.u.par.pchan;
|
par->pchan = hdl->aucat.rmsg.u.par.pchan;
|
||||||
if (hdl->sio.mode & SIO_REC)
|
if (hdl->sio.mode & SIO_REC)
|
||||||
par->rchan = hdl->rmsg.u.par.rchan;
|
par->rchan = hdl->aucat.rmsg.u.par.rchan;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -483,15 +330,15 @@ sio_aucat_getcap(struct sio_hdl *sh, struct sio_cap *cap)
|
|||||||
unsigned i, bps, le, sig, chan, rindex, rmult;
|
unsigned i, bps, le, sig, chan, rindex, rmult;
|
||||||
static unsigned rates[] = { 8000, 11025, 12000 };
|
static unsigned rates[] = { 8000, 11025, 12000 };
|
||||||
|
|
||||||
AMSG_INIT(&hdl->wmsg);
|
AMSG_INIT(&hdl->aucat.wmsg);
|
||||||
hdl->wmsg.cmd = AMSG_GETCAP;
|
hdl->aucat.wmsg.cmd = AMSG_GETCAP;
|
||||||
hdl->wtodo = sizeof(struct amsg);
|
hdl->aucat.wtodo = sizeof(struct amsg);
|
||||||
if (!sio_aucat_wmsg(hdl))
|
if (!aucat_wmsg(&hdl->aucat, &hdl->sio.eof))
|
||||||
return 0;
|
return 0;
|
||||||
hdl->rtodo = sizeof(struct amsg);
|
hdl->aucat.rtodo = sizeof(struct amsg);
|
||||||
if (!sio_aucat_rmsg(hdl))
|
if (!aucat_rmsg(&hdl->aucat, &hdl->sio.eof))
|
||||||
return 0;
|
return 0;
|
||||||
if (hdl->rmsg.cmd != AMSG_GETCAP) {
|
if (hdl->aucat.rmsg.cmd != AMSG_GETCAP) {
|
||||||
DPRINTF("sio_aucat_getcap: protocol err\n");
|
DPRINTF("sio_aucat_getcap: protocol err\n");
|
||||||
hdl->sio.eof = 1;
|
hdl->sio.eof = 1;
|
||||||
return 0;
|
return 0;
|
||||||
@ -568,127 +415,30 @@ static size_t
|
|||||||
sio_aucat_read(struct sio_hdl *sh, void *buf, size_t len)
|
sio_aucat_read(struct sio_hdl *sh, void *buf, size_t len)
|
||||||
{
|
{
|
||||||
struct sio_aucat_hdl *hdl = (struct sio_aucat_hdl *)sh;
|
struct sio_aucat_hdl *hdl = (struct sio_aucat_hdl *)sh;
|
||||||
ssize_t n;
|
|
||||||
|
|
||||||
while (hdl->rstate != STATE_DATA) {
|
while (hdl->aucat.rstate == STATE_RMSG) {
|
||||||
switch (hdl->rstate) {
|
if (!sio_aucat_runmsg(hdl))
|
||||||
case STATE_MSG:
|
|
||||||
if (!sio_aucat_runmsg(hdl))
|
|
||||||
return 0;
|
|
||||||
break;
|
|
||||||
case STATE_IDLE:
|
|
||||||
DPRINTF("sio_aucat_read: unexpected idle state\n");
|
|
||||||
hdl->sio.eof = 1;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (len > hdl->rtodo)
|
return aucat_rdata(&hdl->aucat, buf, len, &hdl->sio.eof);
|
||||||
len = hdl->rtodo;
|
|
||||||
while ((n = read(hdl->fd, buf, len)) < 0) {
|
|
||||||
if (errno == EINTR)
|
|
||||||
continue;
|
|
||||||
if (errno != EAGAIN) {
|
|
||||||
hdl->sio.eof = 1;
|
|
||||||
DPERROR("sio_aucat_read: read");
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (n == 0) {
|
|
||||||
DPRINTF("sio_aucat_read: eof\n");
|
|
||||||
hdl->sio.eof = 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
hdl->rtodo -= n;
|
|
||||||
if (hdl->rtodo == 0) {
|
|
||||||
hdl->rstate = STATE_MSG;
|
|
||||||
hdl->rtodo = sizeof(struct amsg);
|
|
||||||
}
|
|
||||||
DPRINTF("aucat: read: n = %zd\n", n);
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
sio_aucat_buildmsg(struct sio_aucat_hdl *hdl, size_t len)
|
|
||||||
{
|
|
||||||
unsigned sz;
|
|
||||||
|
|
||||||
if (hdl->curvol != hdl->reqvol) {
|
|
||||||
hdl->wstate = STATE_MSG;
|
|
||||||
hdl->wtodo = sizeof(struct amsg);
|
|
||||||
hdl->wmsg.cmd = AMSG_SETVOL;
|
|
||||||
hdl->wmsg.u.vol.ctl = hdl->reqvol;
|
|
||||||
hdl->curvol = hdl->reqvol;
|
|
||||||
return 1;
|
|
||||||
} else if (len > 0 && hdl->maxwrite > 0) {
|
|
||||||
sz = len;
|
|
||||||
if (sz > AMSG_DATAMAX)
|
|
||||||
sz = AMSG_DATAMAX;
|
|
||||||
if (sz > hdl->maxwrite)
|
|
||||||
sz = hdl->maxwrite;
|
|
||||||
sz -= sz % hdl->wbpf;
|
|
||||||
if (sz == 0)
|
|
||||||
sz = hdl->wbpf;
|
|
||||||
hdl->wstate = STATE_MSG;
|
|
||||||
hdl->wtodo = sizeof(struct amsg);
|
|
||||||
hdl->wmsg.cmd = AMSG_DATA;
|
|
||||||
hdl->wmsg.u.data.size = sz;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t
|
static size_t
|
||||||
sio_aucat_write(struct sio_hdl *sh, const void *buf, size_t len)
|
sio_aucat_write(struct sio_hdl *sh, const void *buf, size_t len)
|
||||||
{
|
{
|
||||||
struct sio_aucat_hdl *hdl = (struct sio_aucat_hdl *)sh;
|
struct sio_aucat_hdl *hdl = (struct sio_aucat_hdl *)sh;
|
||||||
ssize_t n;
|
size_t n;
|
||||||
|
|
||||||
while (hdl->wstate != STATE_DATA) {
|
while (hdl->aucat.wstate == STATE_WIDLE) {
|
||||||
switch (hdl->wstate) {
|
if (!sio_aucat_buildmsg(hdl))
|
||||||
case STATE_IDLE:
|
|
||||||
if (!sio_aucat_buildmsg(hdl, len))
|
|
||||||
return 0;
|
|
||||||
/* PASSTHROUGH */
|
|
||||||
case STATE_MSG:
|
|
||||||
if (!sio_aucat_wmsg(hdl))
|
|
||||||
return 0;
|
|
||||||
if (hdl->wmsg.cmd == AMSG_DATA) {
|
|
||||||
hdl->wstate = STATE_DATA;
|
|
||||||
hdl->wtodo = hdl->wmsg.u.data.size;
|
|
||||||
} else
|
|
||||||
hdl->wstate = STATE_IDLE;
|
|
||||||
break;
|
break;
|
||||||
default:
|
|
||||||
DPRINTF("sio_aucat_write: bad state\n");
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (hdl->maxwrite <= 0)
|
if (len <= 0 || hdl->maxwrite <= 0)
|
||||||
return 0;
|
return 0;
|
||||||
if (len > hdl->maxwrite)
|
if (len > hdl->maxwrite)
|
||||||
len = hdl->maxwrite;
|
len = hdl->maxwrite;
|
||||||
if (len > hdl->wtodo)
|
n = aucat_wdata(&hdl->aucat, buf, len, hdl->wbpf, &hdl->sio.eof);
|
||||||
len = hdl->wtodo;
|
|
||||||
if (len == 0) {
|
|
||||||
DPRINTF("sio_aucat_write: len == 0\n");
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
while ((n = write(hdl->fd, buf, len)) < 0) {
|
|
||||||
if (errno == EINTR)
|
|
||||||
continue;
|
|
||||||
if (errno != EAGAIN) {
|
|
||||||
hdl->sio.eof = 1;
|
|
||||||
DPERROR("sio_aucat_write: write");
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
hdl->maxwrite -= n;
|
hdl->maxwrite -= n;
|
||||||
DPRINTF("aucat: write: n = %zd, maxwrite = %d\n", n, hdl->maxwrite);
|
|
||||||
hdl->wtodo -= n;
|
|
||||||
if (hdl->wtodo == 0) {
|
|
||||||
hdl->wstate = STATE_IDLE;
|
|
||||||
hdl->wtodo = 0xdeadbeef;
|
|
||||||
}
|
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -706,12 +456,7 @@ sio_aucat_pollfd(struct sio_hdl *sh, struct pollfd *pfd, int events)
|
|||||||
hdl->events = events;
|
hdl->events = events;
|
||||||
if (hdl->maxwrite <= 0)
|
if (hdl->maxwrite <= 0)
|
||||||
events &= ~POLLOUT;
|
events &= ~POLLOUT;
|
||||||
if (hdl->rstate == STATE_MSG)
|
return aucat_pollfd(&hdl->aucat, pfd, events);
|
||||||
events |= POLLIN;
|
|
||||||
pfd->fd = hdl->fd;
|
|
||||||
pfd->events = events;
|
|
||||||
DPRINTF("aucat: pollfd: %x -> %x\n", hdl->events, pfd->events);
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@ -721,12 +466,12 @@ sio_aucat_revents(struct sio_hdl *sh, struct pollfd *pfd)
|
|||||||
int revents = pfd->revents;
|
int revents = pfd->revents;
|
||||||
|
|
||||||
if (revents & POLLIN) {
|
if (revents & POLLIN) {
|
||||||
while (hdl->rstate == STATE_MSG) {
|
while (hdl->aucat.rstate == STATE_RMSG) {
|
||||||
if (!sio_aucat_runmsg(hdl)) {
|
if (!sio_aucat_runmsg(hdl))
|
||||||
revents &= ~POLLIN;
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
if (hdl->aucat.rstate != STATE_RDATA)
|
||||||
|
revents &= ~POLLIN;
|
||||||
}
|
}
|
||||||
if (revents & POLLOUT) {
|
if (revents & POLLOUT) {
|
||||||
if (hdl->maxwrite <= 0)
|
if (hdl->maxwrite <= 0)
|
||||||
@ -734,7 +479,7 @@ sio_aucat_revents(struct sio_hdl *sh, struct pollfd *pfd)
|
|||||||
}
|
}
|
||||||
if (hdl->sio.eof)
|
if (hdl->sio.eof)
|
||||||
return POLLHUP;
|
return POLLHUP;
|
||||||
DPRINTF("aucat: revents: %x\n", revents & hdl->events);
|
DPRINTF("sio_aucat_revents: %x\n", revents & hdl->events);
|
||||||
return revents & (hdl->events | POLLHUP);
|
return revents & (hdl->events | POLLHUP);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user