From 936815ff03d11be294089d294e53c4ee1714b051 Mon Sep 17 00:00:00 2001 From: Alexandre Ratchov Date: Tue, 12 Apr 2011 09:30:40 +0200 Subject: [PATCH] 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) --- libsndio/Makefile.in | 5 +- libsndio/aucat.c | 343 ++++++++++++++++++++++++++++++ libsndio/aucat.h | 31 +++ libsndio/sio_aucat.c | 493 +++++++++++-------------------------------- 4 files changed, 496 insertions(+), 376 deletions(-) create mode 100644 libsndio/aucat.c create mode 100644 libsndio/aucat.h diff --git a/libsndio/Makefile.in b/libsndio/Makefile.in index fabfb9c..6ba5f1e 100644 --- a/libsndio/Makefile.in +++ b/libsndio/Makefile.in @@ -98,7 +98,7 @@ clean: # 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 \ -getpeereid.o issetugid.o strlcpy.o strtonum.o +aucat.o getpeereid.o issetugid.o strlcpy.o strtonum.o .c.o: ${CC} ${CFLAGS} ${SO_CFLAGS} ${INCLUDE} ${DEFS} -o $@ -c $< @@ -124,8 +124,9 @@ strlcpy.o: ../bsd-compat/strlcpy.c 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_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 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 diff --git a/libsndio/aucat.c b/libsndio/aucat.c new file mode 100644 index 0000000..da33c8c --- /dev/null +++ b/libsndio/aucat.c @@ -0,0 +1,343 @@ +/* $OpenBSD$ */ +/* + * Copyright (c) 2008 Alexandre Ratchov + * + * 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 +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#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; +} diff --git a/libsndio/aucat.h b/libsndio/aucat.h new file mode 100644 index 0000000..a959090 --- /dev/null +++ b/libsndio/aucat.h @@ -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) */ diff --git a/libsndio/sio_aucat.c b/libsndio/sio_aucat.c index b4bad5b..7517b62 100644 --- a/libsndio/sio_aucat.c +++ b/libsndio/sio_aucat.c @@ -27,7 +27,7 @@ #include #include -#include "amsg.h" +#include "aucat.h" #include "sio_priv.h" #ifdef COMPAT_STRLCPY #include "bsd-compat.h" @@ -35,18 +35,15 @@ struct sio_aucat_hdl { struct sio_hdl sio; - int fd; /* socket */ - 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 */ + struct aucat aucat; unsigned rbpf, wbpf; /* read and write bytes-per-frame */ int maxwrite; /* latency constraint */ int events; /* events the user requested */ unsigned curvol, reqvol; /* current and requested volume */ int delta; /* some of received deltas */ +#define STATE_INIT 0 +#define STATE_RUN 1 + int pstate; }; static void sio_aucat_close(struct sio_hdl *); @@ -79,239 +76,97 @@ static struct sio_ops sio_aucat_ops = { 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 */ static int sio_aucat_runmsg(struct sio_aucat_hdl *hdl) { - if (!sio_aucat_rmsg(hdl)) + if (!aucat_rmsg(&hdl->aucat, &hdl->sio.eof)) return 0; - switch (hdl->rmsg.cmd) { + switch (hdl->aucat.rmsg.cmd) { case AMSG_DATA: - if (hdl->rmsg.u.data.size == 0 || - hdl->rmsg.u.data.size % hdl->rbpf) { + if (hdl->aucat.rmsg.u.data.size == 0 || + hdl->aucat.rmsg.u.data.size % hdl->rbpf) { DPRINTF("sio_aucat_runmsg: bad data message\n"); hdl->sio.eof = 1; return 0; } - hdl->rstate = STATE_DATA; - hdl->rtodo = hdl->rmsg.u.data.size; - break; + return 1; 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", - hdl->rmsg.u.ts.delta, hdl->maxwrite); - hdl->delta = hdl->rmsg.u.ts.delta; - hdl->rstate = STATE_MSG; - hdl->rtodo = sizeof(struct amsg); + hdl->aucat.rmsg.u.ts.delta, hdl->maxwrite); + hdl->delta = hdl->aucat.rmsg.u.ts.delta; break; case AMSG_MOVE: - hdl->maxwrite += hdl->rmsg.u.ts.delta * hdl->wbpf; - hdl->delta += hdl->rmsg.u.ts.delta; + hdl->maxwrite += hdl->aucat.rmsg.u.ts.delta * hdl->wbpf; + hdl->delta += hdl->aucat.rmsg.u.ts.delta; 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) { sio_onmove_cb(&hdl->sio, hdl->delta); hdl->delta = 0; } - hdl->rstate = STATE_MSG; - hdl->rtodo = sizeof(struct amsg); break; 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); - hdl->rstate = STATE_MSG; - hdl->rtodo = sizeof(struct amsg); break; - case AMSG_GETPAR: - case AMSG_ACK: - hdl->rstate = STATE_IDLE; - hdl->rtodo = 0xdeadbeef; + case AMSG_STOP: + hdl->pstate = STATE_INIT; break; default: - DPRINTF("sio_aucat_runmsg: unknown message\n"); + DPRINTF("sio_aucat_runmsg: unhandled message %u\n", hdl->aucat.rmsg.cmd); hdl->sio.eof = 1; return 0; } + hdl->aucat.rstate = STATE_RMSG; + hdl->aucat.rtodo = sizeof(struct amsg); 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 * 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 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)); if (hdl == 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); - - 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->reqvol = SIO_MAXVOL; - - /* - * 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; - } + hdl->pstate = STATE_INIT; return (struct sio_hdl *)hdl; - bad_connect: - while (close(s) < 0 && errno == EINTR) - ; /* retry */ - bad_free: - free(hdl); - return NULL; } static void sio_aucat_close(struct sio_hdl *sh) { struct sio_aucat_hdl *hdl = (struct sio_aucat_hdl *)sh; - char dummy[1]; if (!hdl->sio.eof && hdl->sio.started) (void)sio_aucat_stop(&hdl->sio); - if (!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 */ + aucat_close(&hdl->aucat, hdl->sio.eof); free(hdl); } @@ -332,18 +187,19 @@ sio_aucat_start(struct sio_hdl *sh) hdl->delta = 0; DPRINTF("aucat: start, maxwrite = %d\n", hdl->maxwrite); - AMSG_INIT(&hdl->wmsg); - hdl->wmsg.cmd = AMSG_START; - hdl->wtodo = sizeof(struct amsg); - if (!sio_aucat_wmsg(hdl)) + AMSG_INIT(&hdl->aucat.wmsg); + hdl->aucat.wmsg.cmd = AMSG_START; + hdl->aucat.wtodo = sizeof(struct amsg); + if (!aucat_wmsg(&hdl->aucat, &hdl->sio.eof)) return 0; - hdl->rstate = STATE_MSG; - hdl->rtodo = sizeof(struct amsg); - if (fcntl(hdl->fd, F_SETFL, O_NONBLOCK) < 0) { + hdl->aucat.rstate = STATE_RMSG; + hdl->aucat.rtodo = sizeof(struct amsg); + if (fcntl(hdl->aucat.fd, F_SETFL, O_NONBLOCK) < 0) { DPERROR("sio_aucat_start: fcntl(0)"); hdl->sio.eof = 1; return 0; } + hdl->pstate = STATE_RUN; return 1; } @@ -355,7 +211,7 @@ sio_aucat_stop(struct sio_hdl *sh) struct sio_aucat_hdl *hdl = (struct sio_aucat_hdl *)sh; 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)"); hdl->sio.eof = 1; return 0; @@ -364,19 +220,14 @@ sio_aucat_stop(struct sio_hdl *sh) /* * complete message or data block in progress */ - if (hdl->wstate == STATE_MSG) { - if (!sio_aucat_wmsg(hdl)) + if (hdl->aucat.wstate == STATE_WMSG) { + if (!aucat_wmsg(&hdl->aucat, &hdl->sio.eof)) 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) { - hdl->maxwrite = hdl->wtodo; - while (hdl->wstate != STATE_IDLE) { - count = hdl->wtodo; + if (hdl->aucat.wstate == STATE_WDATA) { + hdl->maxwrite = hdl->aucat.wtodo; + while (hdl->aucat.wstate != STATE_WIDLE) { + count = hdl->aucat.wtodo; if (count > ZERO_MAX) count = ZERO_MAX; n = sio_aucat_write(&hdl->sio, zero, count); @@ -388,26 +239,22 @@ sio_aucat_stop(struct sio_hdl *sh) /* * send stop message */ - AMSG_INIT(&hdl->wmsg); - hdl->wmsg.cmd = AMSG_STOP; - hdl->wtodo = sizeof(struct amsg); - if (!sio_aucat_wmsg(hdl)) + AMSG_INIT(&hdl->aucat.wmsg); + hdl->aucat.wmsg.cmd = AMSG_STOP; + hdl->aucat.wtodo = sizeof(struct amsg); + if (!aucat_wmsg(&hdl->aucat, &hdl->sio.eof)) return 0; - if (hdl->rstate == STATE_IDLE) { - hdl->rstate = STATE_MSG; - hdl->rtodo = sizeof(struct amsg); - } /* * wait for the STOP ACK */ - while (hdl->rstate != STATE_IDLE) { - switch (hdl->rstate) { - case STATE_MSG: + while (hdl->pstate != STATE_INIT) { + switch (hdl->aucat.rstate) { + case STATE_RMSG: if (!sio_aucat_runmsg(hdl)) return 0; break; - case STATE_DATA: + case STATE_RDATA: if (!sio_aucat_read(&hdl->sio, zero, ZERO_MAX)) return 0; 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; - AMSG_INIT(&hdl->wmsg); - hdl->wmsg.cmd = AMSG_SETPAR; - hdl->wmsg.u.par.bits = par->bits; - hdl->wmsg.u.par.bps = par->bps; - hdl->wmsg.u.par.sig = par->sig; - hdl->wmsg.u.par.le = par->le; - hdl->wmsg.u.par.msb = par->msb; - hdl->wmsg.u.par.rate = par->rate; - hdl->wmsg.u.par.appbufsz = par->appbufsz; - hdl->wmsg.u.par.xrun = par->xrun; + AMSG_INIT(&hdl->aucat.wmsg); + hdl->aucat.wmsg.cmd = AMSG_SETPAR; + hdl->aucat.wmsg.u.par.bits = par->bits; + hdl->aucat.wmsg.u.par.bps = par->bps; + hdl->aucat.wmsg.u.par.sig = par->sig; + hdl->aucat.wmsg.u.par.le = par->le; + hdl->aucat.wmsg.u.par.msb = par->msb; + hdl->aucat.wmsg.u.par.rate = par->rate; + hdl->aucat.wmsg.u.par.appbufsz = par->appbufsz; + hdl->aucat.wmsg.u.par.xrun = par->xrun; 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) - hdl->wmsg.u.par.pchan = par->pchan; - hdl->wtodo = sizeof(struct amsg); - if (!sio_aucat_wmsg(hdl)) + hdl->aucat.wmsg.u.par.pchan = par->pchan; + hdl->aucat.wtodo = sizeof(struct amsg); + if (!aucat_wmsg(&hdl->aucat, &hdl->sio.eof)) return 0; 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; - AMSG_INIT(&hdl->wmsg); - hdl->wmsg.cmd = AMSG_GETPAR; - hdl->wtodo = sizeof(struct amsg); - if (!sio_aucat_wmsg(hdl)) + AMSG_INIT(&hdl->aucat.wmsg); + hdl->aucat.wmsg.cmd = AMSG_GETPAR; + hdl->aucat.wtodo = sizeof(struct amsg); + if (!aucat_wmsg(&hdl->aucat, &hdl->sio.eof)) return 0; - hdl->rtodo = sizeof(struct amsg); - if (!sio_aucat_rmsg(hdl)) + hdl->aucat.rtodo = sizeof(struct amsg); + if (!aucat_rmsg(&hdl->aucat, &hdl->sio.eof)) return 0; - if (hdl->rmsg.cmd != AMSG_GETPAR) { + if (hdl->aucat.rmsg.cmd != AMSG_GETPAR) { DPRINTF("sio_aucat_getpar: protocol err\n"); hdl->sio.eof = 1; return 0; } - par->bits = hdl->rmsg.u.par.bits; - par->bps = hdl->rmsg.u.par.bps; - par->sig = hdl->rmsg.u.par.sig; - par->le = hdl->rmsg.u.par.le; - par->msb = hdl->rmsg.u.par.msb; - par->rate = hdl->rmsg.u.par.rate; - par->bufsz = hdl->rmsg.u.par.bufsz; - par->appbufsz = hdl->rmsg.u.par.appbufsz; - par->xrun = hdl->rmsg.u.par.xrun; - par->round = hdl->rmsg.u.par.round; + par->bits = hdl->aucat.rmsg.u.par.bits; + par->bps = hdl->aucat.rmsg.u.par.bps; + par->sig = hdl->aucat.rmsg.u.par.sig; + par->le = hdl->aucat.rmsg.u.par.le; + par->msb = hdl->aucat.rmsg.u.par.msb; + par->rate = hdl->aucat.rmsg.u.par.rate; + par->bufsz = hdl->aucat.rmsg.u.par.bufsz; + par->appbufsz = hdl->aucat.rmsg.u.par.appbufsz; + par->xrun = hdl->aucat.rmsg.u.par.xrun; + par->round = hdl->aucat.rmsg.u.par.round; 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) - par->rchan = hdl->rmsg.u.par.rchan; + par->rchan = hdl->aucat.rmsg.u.par.rchan; 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; static unsigned rates[] = { 8000, 11025, 12000 }; - AMSG_INIT(&hdl->wmsg); - hdl->wmsg.cmd = AMSG_GETCAP; - hdl->wtodo = sizeof(struct amsg); - if (!sio_aucat_wmsg(hdl)) + AMSG_INIT(&hdl->aucat.wmsg); + hdl->aucat.wmsg.cmd = AMSG_GETCAP; + hdl->aucat.wtodo = sizeof(struct amsg); + if (!aucat_wmsg(&hdl->aucat, &hdl->sio.eof)) return 0; - hdl->rtodo = sizeof(struct amsg); - if (!sio_aucat_rmsg(hdl)) + hdl->aucat.rtodo = sizeof(struct amsg); + if (!aucat_rmsg(&hdl->aucat, &hdl->sio.eof)) return 0; - if (hdl->rmsg.cmd != AMSG_GETCAP) { + if (hdl->aucat.rmsg.cmd != AMSG_GETCAP) { DPRINTF("sio_aucat_getcap: protocol err\n"); hdl->sio.eof = 1; return 0; @@ -568,127 +415,30 @@ static size_t sio_aucat_read(struct sio_hdl *sh, void *buf, size_t len) { struct sio_aucat_hdl *hdl = (struct sio_aucat_hdl *)sh; - ssize_t n; - while (hdl->rstate != STATE_DATA) { - switch (hdl->rstate) { - 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; + while (hdl->aucat.rstate == STATE_RMSG) { + if (!sio_aucat_runmsg(hdl)) return 0; - } } - if (len > hdl->rtodo) - 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; + return aucat_rdata(&hdl->aucat, buf, len, &hdl->sio.eof); } static size_t sio_aucat_write(struct sio_hdl *sh, const void *buf, size_t len) { struct sio_aucat_hdl *hdl = (struct sio_aucat_hdl *)sh; - ssize_t n; + size_t n; - while (hdl->wstate != STATE_DATA) { - switch (hdl->wstate) { - 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; + while (hdl->aucat.wstate == STATE_WIDLE) { + if (!sio_aucat_buildmsg(hdl)) break; - default: - DPRINTF("sio_aucat_write: bad state\n"); - abort(); - } } - if (hdl->maxwrite <= 0) + if (len <= 0 || hdl->maxwrite <= 0) return 0; if (len > hdl->maxwrite) len = hdl->maxwrite; - if (len > hdl->wtodo) - 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; - } + n = aucat_wdata(&hdl->aucat, buf, len, hdl->wbpf, &hdl->sio.eof); 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; } @@ -706,12 +456,7 @@ sio_aucat_pollfd(struct sio_hdl *sh, struct pollfd *pfd, int events) hdl->events = events; if (hdl->maxwrite <= 0) events &= ~POLLOUT; - if (hdl->rstate == STATE_MSG) - events |= POLLIN; - pfd->fd = hdl->fd; - pfd->events = events; - DPRINTF("aucat: pollfd: %x -> %x\n", hdl->events, pfd->events); - return 1; + return aucat_pollfd(&hdl->aucat, pfd, events); } static int @@ -721,12 +466,12 @@ sio_aucat_revents(struct sio_hdl *sh, struct pollfd *pfd) int revents = pfd->revents; if (revents & POLLIN) { - while (hdl->rstate == STATE_MSG) { - if (!sio_aucat_runmsg(hdl)) { - revents &= ~POLLIN; + while (hdl->aucat.rstate == STATE_RMSG) { + if (!sio_aucat_runmsg(hdl)) break; - } } + if (hdl->aucat.rstate != STATE_RDATA) + revents &= ~POLLIN; } if (revents & POLLOUT) { if (hdl->maxwrite <= 0) @@ -734,7 +479,7 @@ sio_aucat_revents(struct sio_hdl *sh, struct pollfd *pfd) } if (hdl->sio.eof) return POLLHUP; - DPRINTF("aucat: revents: %x\n", revents & hdl->events); + DPRINTF("sio_aucat_revents: %x\n", revents & hdl->events); return revents & (hdl->events | POLLHUP); }