summaryrefslogtreecommitdiff
path: root/usr.bin/aucat/sock.c
diff options
context:
space:
mode:
authorAlexandre Ratchov <ratchov@cvs.openbsd.org>2009-07-25 08:44:28 +0000
committerAlexandre Ratchov <ratchov@cvs.openbsd.org>2009-07-25 08:44:28 +0000
commit0844fac57a53bca70c73354af3517b8bea149328 (patch)
tree38194a88aaef0f05f48c3bc6df1dec993ead1163 /usr.bin/aucat/sock.c
parent8c4eca591954bdaedc99cf39f7f3f83fdc5ae579 (diff)
Currently midi capable programs can control midi hardware, but
cannot cooperate with other programs. The aim of this change is to allow any program to send midi data to other programs as they were midi hardware. For instance, this change should solve the longstanding problem of using a midi sequencer with software synthesizers. More precisely: - new midicat(1) utility (actually hardlink to aucat(1)). it creates software midi thru boxes, allowing programs to send midi messages to other programs as they were midi(4) hardware. - new midi api in libsndio (see mio_open(3)), to access midi(4) devices and midicat(1) sockets in a uniform way. - new device naming scheme <service>:<unit>[.<option>], common to audio and midi. - new sndio(7) manual describing concepts and naming The current audio device naming still works, but people having scripts or configuration files containing device names could read the sndio(7) man page and slowly start updating device names. discussed with jakemsr@ and deraadt@, help form jmc@
Diffstat (limited to 'usr.bin/aucat/sock.c')
-rw-r--r--usr.bin/aucat/sock.c157
1 files changed, 114 insertions, 43 deletions
diff --git a/usr.bin/aucat/sock.c b/usr.bin/aucat/sock.c
index 07ef03af278..f94be462b18 100644
--- a/usr.bin/aucat/sock.c
+++ b/usr.bin/aucat/sock.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sock.c,v 1.18 2009/05/16 12:20:31 ratchov Exp $ */
+/* $OpenBSD: sock.c,v 1.19 2009/07/25 08:44:27 ratchov Exp $ */
/*
* Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org>
*
@@ -29,6 +29,8 @@
#include "sock.h"
#include "dev.h"
#include "conf.h"
+#include "midi.h"
+#include "opt.h"
int sock_attach(struct sock *, int);
int sock_read(struct sock *);
@@ -89,7 +91,7 @@ rsock_out(struct aproc *p, struct abuf *obuf)
{
struct sock *f = (struct sock *)p->u.io.file;
- if (f->pipe.file.refs > 0)
+ if (f->pipe.file.state & FILE_RINUSE)
return 0;
DPRINTFN(4, "rsock_out: %p\n", f);
@@ -183,11 +185,10 @@ wsock_in(struct aproc *p, struct abuf *ibuf)
{
struct sock *f = (struct sock *)p->u.io.file;
- if (f->pipe.file.refs > 0)
+ if (f->pipe.file.state & FILE_WINUSE)
return 0;
DPRINTFN(4, "wsock_in: %p\n", f);
-
/*
* see remark in rsock_out()
*/
@@ -273,40 +274,37 @@ struct aproc_ops wsock_ops = {
* parameters
*/
struct sock *
-sock_new(struct fileops *ops, int fd, char *name,
- struct aparams *wpar, struct aparams *rpar, int maxweight)
+sock_new(struct fileops *ops, int fd)
{
struct aproc *rproc, *wproc;
struct sock *f;
- f = (struct sock *)pipe_new(ops, fd, name);
+ f = (struct sock *)pipe_new(ops, fd, "sock");
if (f == NULL)
return NULL;
f->pstate = SOCK_HELLO;
f->mode = 0;
- if (dev_rec) {
- f->templ_wpar = *wpar;
- f->wpar = f->templ_wpar;
- }
- if (dev_play) {
- f->templ_rpar = *rpar;
- f->rpar = f->templ_rpar;
+ f->opt = opt_byname("default");
+ if (f->opt) {
+ if (dev_rec)
+ f->wpar = f->opt->wpar;
+ if (dev_play)
+ f->rpar = f->opt->rpar;
}
f->xrun = AMSG_IGNORE;
f->bufsz = dev_bufsz;
f->round = dev_round;
f->delta = 0;
f->tickpending = 0;
- f->maxweight = maxweight;
f->vol = ADATA_UNIT;
- wproc = aproc_new(&wsock_ops, name);
+ wproc = aproc_new(&wsock_ops, f->pipe.file.name);
wproc->u.io.file = &f->pipe.file;
f->pipe.file.wproc = wproc;
f->wstate = SOCK_WIDLE;
f->wtodo = 0xdeadbeef;
- rproc = aproc_new(&rsock_ops, name);
+ rproc = aproc_new(&rsock_ops, f->pipe.file.name);
rproc->u.io.file = &f->pipe.file;
f->pipe.file.rproc = rproc;
f->rstate = SOCK_RMSG;
@@ -402,7 +400,7 @@ sock_attach(struct sock *f, int force)
dev_attach(f->pipe.file.name,
(f->mode & AMSG_PLAY) ? rbuf : NULL, &f->rpar, f->xrun,
(f->mode & AMSG_REC) ? wbuf : NULL, &f->wpar, f->xrun,
- f->maxweight);
+ f->opt->maxweight);
if (f->mode & AMSG_PLAY)
dev_setvol(rbuf, f->vol);
@@ -500,23 +498,26 @@ sock_rdata(struct sock *f)
unsigned count, n;
#ifdef DEBUG
- if (f->rtodo == 0) {
+ if (f->pstate != SOCK_MIDI && f->rtodo == 0) {
fprintf(stderr, "sock_rdata: bad call: zero arg\n");
abort();
}
#endif
p = f->pipe.file.rproc;
obuf = LIST_FIRST(&p->obuflist);
+ if (obuf == NULL)
+ return 0;
if (ABUF_FULL(obuf) || !(f->pipe.file.state & FILE_ROK))
return 0;
data = abuf_wgetblk(obuf, &count, 0);
- if (count > f->rtodo)
+ if (f->pstate != SOCK_MIDI && count > f->rtodo)
count = f->rtodo;
n = file_read(&f->pipe.file, data, count);
if (n == 0)
return 0;
abuf_wcommit(obuf, n);
- f->rtodo -= n;
+ if (f->pstate != SOCK_MIDI)
+ f->rtodo -= n;
return 1;
}
@@ -535,7 +536,7 @@ sock_wdata(struct sock *f)
static char zero[ZERO_MAX];
#ifdef DEBUG
- if (f->wtodo == 0) {
+ if (f->pstate != SOCK_MIDI && f->wtodo == 0) {
fprintf(stderr, "sock_wdata: bad call: zero arg\n");
abort();
}
@@ -548,14 +549,17 @@ sock_wdata(struct sock *f)
if (ABUF_EMPTY(ibuf))
return 0;
data = abuf_rgetblk(ibuf, &count, 0);
- if (count > f->wtodo)
+ if (f->pstate != SOCK_MIDI && count > f->wtodo)
count = f->wtodo;
n = file_write(&f->pipe.file, data, count);
if (n == 0)
return 0;
abuf_rdiscard(ibuf, n);
- f->wtodo -= n;
+ if (f->pstate != SOCK_MIDI)
+ f->wtodo -= n;
} else {
+ if (f->pstate == SOCK_MIDI)
+ return 0;
/*
* there's no dev_detach() routine yet,
* so now we abruptly destroy the buffer.
@@ -623,10 +627,10 @@ sock_setpar(struct sock *f)
p->rchan = 1;
if (p->rchan > NCHAN_MAX)
p->rchan = NCHAN_MAX;
- f->wpar.cmin = f->templ_wpar.cmin;
- f->wpar.cmax = f->templ_wpar.cmin + p->rchan - 1;
- if (f->wpar.cmax > f->templ_wpar.cmax)
- f->wpar.cmax = f->templ_wpar.cmax;
+ f->wpar.cmin = f->opt->wpar.cmin;
+ f->wpar.cmax = f->opt->wpar.cmin + p->rchan - 1;
+ if (f->wpar.cmax > f->opt->wpar.cmax)
+ f->wpar.cmax = f->opt->wpar.cmax;
DPRINTF("sock_setpar: rchan -> %u:%u\n",
f->wpar.cmin, f->wpar.cmax);
}
@@ -635,10 +639,10 @@ sock_setpar(struct sock *f)
p->pchan = 1;
if (p->pchan > NCHAN_MAX)
p->pchan = NCHAN_MAX;
- f->rpar.cmin = f->templ_rpar.cmin;
- f->rpar.cmax = f->templ_rpar.cmin + p->pchan - 1;
- if (f->rpar.cmax > f->templ_rpar.cmax)
- f->rpar.cmax = f->templ_rpar.cmax;
+ f->rpar.cmin = f->opt->rpar.cmin;
+ f->rpar.cmax = f->opt->rpar.cmin + p->pchan - 1;
+ if (f->rpar.cmax > f->opt->rpar.cmax)
+ f->rpar.cmax = f->opt->rpar.cmax;
DPRINTF("sock_setpar: pchan -> %u:%u\n",
f->rpar.cmin, f->rpar.cmax);
}
@@ -704,12 +708,58 @@ sock_setpar(struct sock *f)
return 1;
}
+/*
+ * allocate buffers, so client can start filling write-end.
+ */
+void
+sock_midiattach(struct sock *f, unsigned mode)
+{
+ struct abuf *rbuf = NULL, *wbuf = NULL;
+ struct aparams dummy;
+
+ memset(&dummy, 0, sizeof(dummy));
+ dummy.bps = 1;
+
+ if (mode & AMSG_MIDIOUT) {
+ rbuf = abuf_new(3125, &dummy);
+ aproc_setout(f->pipe.file.rproc, rbuf);
+ aproc_setin(thrubox, rbuf);
+ }
+ if (mode & AMSG_MIDIIN) {
+ wbuf = abuf_new(3125, &dummy);
+ aproc_setin(f->pipe.file.wproc, wbuf);
+ aproc_setout(thrubox, wbuf);
+ if (mode & AMSG_MIDIOUT) {
+ rbuf->duplex = wbuf;
+ wbuf->duplex = rbuf;
+ }
+ }
+}
+
int
sock_hello(struct sock *f)
{
struct amsg_hello *p = &f->rmsg.u.hello;
- DPRINTF("sock_hello: from <%s>\n", p->who);
+ DPRINTF("sock_hello: from <%s>, mode = %x\n", p->who, p->proto);
+
+ if (thrubox && (p->proto & (AMSG_MIDIIN | AMSG_MIDIOUT))) {
+ if (p->proto & ~(AMSG_MIDIIN | AMSG_MIDIOUT)) {
+ DPRINTF("sock_hello: %x: bad proto\n", p->proto);
+ return 0;
+ }
+ f->mode = p->proto;
+ f->pstate = SOCK_MIDI;
+ sock_midiattach(f, p->proto);
+ return 1;
+ }
+ f->opt = opt_byname(p->opt);
+ if (f->opt == NULL)
+ return 0;
+ if (dev_rec)
+ f->wpar = f->opt->wpar;
+ if (dev_play)
+ f->rpar = f->opt->rpar;
if ((p->proto & ~(AMSG_PLAY | AMSG_REC)) != 0 ||
(p->proto & (AMSG_PLAY | AMSG_REC)) == 0) {
DPRINTF("sock_hello: %x: unsupported proto\n", p->proto);
@@ -744,9 +794,9 @@ sock_execmsg(struct sock *f)
struct amsg *m = &f->rmsg;
/*
- * XXX: allow old clients to work without hello
+ * XXX: allow old clients to work without hello on the default socket
*/
- if (f->pstate == SOCK_HELLO && m->cmd != AMSG_HELLO) {
+ if (f->pstate == SOCK_HELLO && m->cmd != AMSG_HELLO && f->opt != NULL) {
DPRINTF("sock_execmsg: legacy client\n");
f->pstate = SOCK_INIT;
}
@@ -848,9 +898,9 @@ sock_execmsg(struct sock *f)
m->cmd = AMSG_GETCAP;
m->u.cap.rate = dev_rate;
m->u.cap.pchan = dev_mix ?
- (f->templ_rpar.cmax - f->templ_rpar.cmin + 1) : 0;
+ (f->opt->rpar.cmax - f->opt->rpar.cmin + 1) : 0;
m->u.cap.rchan = dev_sub ?
- (f->templ_wpar.cmax - f->templ_wpar.cmin + 1) : 0;
+ (f->opt->wpar.cmax - f->opt->wpar.cmin + 1) : 0;
m->u.cap.bits = sizeof(short) * 8;
m->u.cap.bps = sizeof(short);
f->rstate = SOCK_RRET;
@@ -900,8 +950,13 @@ sock_execmsg(struct sock *f)
!sock_wmsg(f, &f->rmsg, &f->rtodo))
return 0;
DPRINTF("sock_execmsg: %p RRET done\n", f);
- f->rtodo = sizeof(struct amsg);
- f->rstate = SOCK_RMSG;
+ if (f->pstate == SOCK_MIDI && (f->mode & AMSG_MIDIOUT)) {
+ f->rstate = SOCK_RDATA;
+ f->rtodo = 0;
+ } else {
+ f->rstate = SOCK_RMSG;
+ f->rtodo = sizeof(struct amsg);
+ }
}
return 1;
}
@@ -915,6 +970,13 @@ sock_buildmsg(struct sock *f)
struct aproc *p;
struct abuf *ibuf;
+ if (f->pstate == SOCK_MIDI) {
+ DPRINTFN(4, "sock_buildmsg: %p: switched to midi\n", f);
+ f->wstate = SOCK_WDATA;
+ f->wtodo = 0;
+ return 1;
+ }
+
/*
* if pos changed, build a MOVE message
*/
@@ -973,7 +1035,7 @@ sock_read(struct sock *f)
case SOCK_RDATA:
if (!sock_rdata(f))
return 0;
- if (f->rtodo == 0) {
+ if (f->pstate != SOCK_MIDI && f->rtodo == 0) {
f->rstate = SOCK_RMSG;
f->rtodo = sizeof(struct amsg);
}
@@ -1000,8 +1062,16 @@ sock_return(struct sock *f)
if (!sock_wmsg(f, &f->rmsg, &f->rtodo))
return 0;
DPRINTF("sock_return: %p: done\n", f);
- f->rstate = SOCK_RMSG;
- f->rtodo = sizeof(struct amsg);
+ if (f->pstate == SOCK_MIDI && (f->mode & AMSG_MIDIOUT)) {
+ f->rstate = SOCK_RDATA;
+ f->rtodo = 0;
+ } else {
+ f->rstate = SOCK_RMSG;
+ f->rtodo = sizeof(struct amsg);
+ }
+ if (f->pipe.file.state & FILE_RINUSE)
+ break;
+ f->pipe.file.state |= FILE_RINUSE;
for (;;) {
/*
* in() may trigger rsock_done and destroy the
@@ -1011,6 +1081,7 @@ sock_return(struct sock *f)
if (!rp || !rp->ops->in(rp, NULL))
break;
}
+ f->pipe.file.state &= ~FILE_RINUSE;
if (f->pipe.file.wproc == NULL)
return 0;
}
@@ -1043,7 +1114,7 @@ sock_write(struct sock *f)
case SOCK_WDATA:
if (!sock_wdata(f))
return 0;
- if (f->wtodo > 0)
+ if (f->pstate == SOCK_MIDI || f->wtodo > 0)
break;
f->wstate = SOCK_WIDLE;
f->wtodo = 0xdeadbeef;