Annotation of src/usr.bin/aucat/sock.c, Revision 1.29
1.29 ! ratchov 1: /* $OpenBSD: sock.c,v 1.28 2009/08/28 06:37:06 ratchov Exp $ */
1.1 ratchov 2: /*
3: * Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org>
4: *
5: * Permission to use, copy, modify, and distribute this software for any
6: * purpose with or without fee is hereby granted, provided that the above
7: * copyright notice and this permission notice appear in all copies.
8: *
9: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16: */
17: /*
18: * TODO:
19: *
20: * change f->bufsz to contain only socket-side buffer,
21: * because it's less error prone
22: */
23:
24: #include <stdio.h>
25: #include <stdlib.h>
26: #include <string.h>
1.20 ratchov 27:
28: #include "abuf.h"
1.1 ratchov 29: #include "aproc.h"
1.20 ratchov 30: #include "conf.h"
1.1 ratchov 31: #include "dev.h"
1.19 ratchov 32: #include "midi.h"
33: #include "opt.h"
1.20 ratchov 34: #include "sock.h"
1.1 ratchov 35:
36: int sock_attach(struct sock *, int);
37: int sock_read(struct sock *);
38: int sock_write(struct sock *);
39: int sock_execmsg(struct sock *);
40: void sock_reset(struct sock *);
41:
42: struct fileops sock_ops = {
43: "sock",
44: sizeof(struct sock),
45: pipe_close,
46: pipe_read,
47: pipe_write,
48: NULL, /* start */
49: NULL, /* stop */
50: pipe_nfds,
51: pipe_pollfd,
52: pipe_revents
53: };
54:
55: void
56: rsock_done(struct aproc *p)
57: {
58: struct sock *f = (struct sock *)p->u.io.file;
59:
1.11 ratchov 60: if (f == NULL)
61: return;
1.1 ratchov 62: sock_reset(f);
63: f->pipe.file.rproc = NULL;
64: if (f->pipe.file.wproc) {
1.24 ratchov 65: if (dev_midi && f->slot >= 0)
66: ctl_slotdel(dev_midi, f->slot);
1.1 ratchov 67: aproc_del(f->pipe.file.wproc);
68: file_del(&f->pipe.file);
69: }
1.11 ratchov 70: p->u.io.file = NULL;
1.1 ratchov 71: }
72:
73: int
74: rsock_in(struct aproc *p, struct abuf *ibuf_dummy)
75: {
76: struct sock *f = (struct sock *)p->u.io.file;
77: struct abuf *obuf;
78:
79: if (!sock_read(f))
80: return 0;
81: obuf = LIST_FIRST(&p->obuflist);
82: if (obuf) {
83: if (!abuf_flush(obuf))
84: return 0;
85: }
86: return 1;
87: }
88:
89: int
90: rsock_out(struct aproc *p, struct abuf *obuf)
91: {
92: struct sock *f = (struct sock *)p->u.io.file;
93:
1.19 ratchov 94: if (f->pipe.file.state & FILE_RINUSE)
1.1 ratchov 95: return 0;
96:
1.12 ratchov 97: /*
1.20 ratchov 98: * When calling sock_read(), we may receive a ``STOP'' command,
1.1 ratchov 99: * and detach ``obuf''. In this case, there's no more caller and
1.20 ratchov 100: * we'll stop processing further messages, resulting in a deadlock.
1.1 ratchov 101: * The solution is to iterate over sock_read() in order to
102: * consume all messages().
103: */
104: for (;;) {
105: if (!sock_read(f))
1.12 ratchov 106: return 0;
1.1 ratchov 107: }
108: return 1;
109: }
110:
111: void
112: rsock_eof(struct aproc *p, struct abuf *ibuf_dummy)
113: {
114: aproc_del(p);
115: }
116:
117: void
118: rsock_hup(struct aproc *p, struct abuf *ibuf)
119: {
120: aproc_del(p);
121: }
122:
123: void
124: rsock_opos(struct aproc *p, struct abuf *obuf, int delta)
125: {
126: struct sock *f = (struct sock *)p->u.io.file;
127:
1.15 ratchov 128: if (f->mode & AMSG_REC)
1.14 ratchov 129: return;
130:
131: f->delta += delta;
1.1 ratchov 132: /*
1.16 jakemsr 133: * Negative deltas are xrun notifications for internal uses
134: * only. Don't generate a packet for this, the client will be
1.1 ratchov 135: * notified later.
136: */
1.14 ratchov 137: if (delta < 0)
1.1 ratchov 138: return;
1.14 ratchov 139: f->tickpending++;
1.1 ratchov 140: for (;;) {
141: if (!sock_write(f))
142: break;
143: }
144: }
145:
146: struct aproc_ops rsock_ops = {
147: "rsock",
148: rsock_in,
149: rsock_out,
150: rsock_eof,
151: rsock_hup,
152: NULL, /* newin */
153: NULL, /* newout */
154: NULL, /* ipos */
155: rsock_opos,
156: rsock_done
157: };
158:
159: void
160: wsock_done(struct aproc *p)
161: {
162: struct sock *f = (struct sock *)p->u.io.file;
163:
1.11 ratchov 164: if (f == NULL)
165: return;
1.1 ratchov 166: sock_reset(f);
167: f->pipe.file.wproc = NULL;
168: if (f->pipe.file.rproc) {
1.24 ratchov 169: if (dev_midi && f->slot >= 0)
170: ctl_slotdel(dev_midi, f->slot);
1.1 ratchov 171: aproc_del(f->pipe.file.rproc);
172: file_del(&f->pipe.file);
173: }
1.11 ratchov 174: p->u.io.file = NULL;
1.1 ratchov 175: }
176:
177: int
178: wsock_in(struct aproc *p, struct abuf *ibuf)
179: {
180: struct sock *f = (struct sock *)p->u.io.file;
181:
1.19 ratchov 182: if (f->pipe.file.state & FILE_WINUSE)
1.1 ratchov 183: return 0;
184: /*
1.20 ratchov 185: * See remark in rsock_out().
1.1 ratchov 186: */
187: for (;;) {
188: if (!sock_write(f))
189: return 0;
190: }
191: return 1;
192: }
193:
194: int
195: wsock_out(struct aproc *p, struct abuf *obuf_dummy)
196: {
197: struct abuf *ibuf = LIST_FIRST(&p->ibuflist);
198: struct sock *f = (struct sock *)p->u.io.file;
199:
200: if (ibuf) {
201: if (!abuf_fill(ibuf))
202: return 0;
203: }
204: if (!sock_write(f))
205: return 0;
206: return 1;
207: }
208:
209: void
210: wsock_eof(struct aproc *p, struct abuf *obuf)
211: {
212: aproc_del(p);
213: }
214:
215: void
216: wsock_hup(struct aproc *p, struct abuf *obuf_dummy)
217: {
218: aproc_del(p);
219: }
220:
221: void
222: wsock_ipos(struct aproc *p, struct abuf *obuf, int delta)
223: {
224: struct sock *f = (struct sock *)p->u.io.file;
225:
1.14 ratchov 226: if (!(f->mode & AMSG_REC))
227: return;
1.1 ratchov 228:
1.14 ratchov 229: f->delta += delta;
1.1 ratchov 230: /*
1.16 jakemsr 231: * Negative deltas are xrun notifications for internal uses
232: * only. Don't generate a packet for this, the client will be
1.1 ratchov 233: * notified later.
234: */
1.14 ratchov 235: if (delta < 0)
1.1 ratchov 236: return;
1.14 ratchov 237: f->tickpending++;
1.1 ratchov 238: for (;;) {
239: if (!sock_write(f))
240: break;
241: }
242: }
243:
244: struct aproc_ops wsock_ops = {
245: "wsock",
246: wsock_in,
247: wsock_out,
248: wsock_eof,
249: wsock_hup,
250: NULL, /* newin */
251: NULL, /* newout */
252: wsock_ipos,
253: NULL, /* opos */
254: wsock_done
255: };
256:
257: /*
1.20 ratchov 258: * Initialise socket in the SOCK_HELLO state with default
259: * parameters.
1.1 ratchov 260: */
261: struct sock *
1.19 ratchov 262: sock_new(struct fileops *ops, int fd)
1.1 ratchov 263: {
264: struct aproc *rproc, *wproc;
265: struct sock *f;
266:
1.19 ratchov 267: f = (struct sock *)pipe_new(ops, fd, "sock");
1.13 ratchov 268: if (f == NULL)
269: return NULL;
1.18 ratchov 270: f->pstate = SOCK_HELLO;
1.1 ratchov 271: f->mode = 0;
1.19 ratchov 272: f->opt = opt_byname("default");
273: if (f->opt) {
274: if (dev_rec)
275: f->wpar = f->opt->wpar;
276: if (dev_play)
277: f->rpar = f->opt->rpar;
1.1 ratchov 278: }
279: f->xrun = AMSG_IGNORE;
1.10 ratchov 280: f->bufsz = dev_bufsz;
1.1 ratchov 281: f->round = dev_round;
1.14 ratchov 282: f->delta = 0;
283: f->tickpending = 0;
1.25 ratchov 284: f->vol = f->lastvol = MIDI_MAXCTL;
1.24 ratchov 285: f->slot = -1;
1.1 ratchov 286:
1.19 ratchov 287: wproc = aproc_new(&wsock_ops, f->pipe.file.name);
1.1 ratchov 288: wproc->u.io.file = &f->pipe.file;
289: f->pipe.file.wproc = wproc;
290: f->wstate = SOCK_WIDLE;
291: f->wtodo = 0xdeadbeef;
292:
1.19 ratchov 293: rproc = aproc_new(&rsock_ops, f->pipe.file.name);
1.1 ratchov 294: rproc->u.io.file = &f->pipe.file;
295: f->pipe.file.rproc = rproc;
296: f->rstate = SOCK_RMSG;
297: f->rtodo = sizeof(struct amsg);
298: return f;
299: }
300:
301: /*
1.20 ratchov 302: * Free buffers.
1.1 ratchov 303: */
304: void
305: sock_freebuf(struct sock *f)
306: {
307: struct abuf *rbuf, *wbuf;
1.12 ratchov 308:
1.1 ratchov 309: f->pstate = SOCK_INIT;
310: rbuf = LIST_FIRST(&f->pipe.file.rproc->obuflist);
311: if (rbuf)
312: abuf_eof(rbuf);
313: wbuf = LIST_FIRST(&f->pipe.file.wproc->ibuflist);
314: if (wbuf)
315: abuf_hup(wbuf);
316: }
317:
318: /*
1.20 ratchov 319: * Allocate buffers, so client can start filling write-end.
1.1 ratchov 320: */
321: void
322: sock_allocbuf(struct sock *f)
323: {
324: struct abuf *rbuf = NULL, *wbuf = NULL;
325:
326: if (f->mode & AMSG_PLAY) {
1.10 ratchov 327: rbuf = abuf_new(f->bufsz, &f->rpar);
1.1 ratchov 328: aproc_setout(f->pipe.file.rproc, rbuf);
329: }
330: if (f->mode & AMSG_REC) {
1.10 ratchov 331: wbuf = abuf_new(f->bufsz, &f->wpar);
1.1 ratchov 332: aproc_setin(f->pipe.file.wproc, wbuf);
333: }
1.14 ratchov 334: f->delta = 0;
335: f->tickpending = 0;
1.1 ratchov 336: f->pstate = SOCK_START;
337: if (!(f->mode & AMSG_PLAY))
338: (void)sock_attach(f, 0);
339: }
340:
341: /*
1.25 ratchov 342: * Set volume. Callback invoked when volume is modified externally
1.3 ratchov 343: */
344: void
1.25 ratchov 345: sock_setvol(void *arg, unsigned vol)
1.3 ratchov 346: {
1.25 ratchov 347: struct sock *f = (struct sock *)arg;
1.3 ratchov 348: struct abuf *rbuf;
1.12 ratchov 349:
1.3 ratchov 350: f->vol = vol;
1.12 ratchov 351: rbuf = LIST_FIRST(&f->pipe.file.rproc->obuflist);
1.3 ratchov 352: if (!rbuf) {
353: return;
354: }
1.25 ratchov 355: dev_setvol(rbuf, MIDI_TO_ADATA(vol));
1.3 ratchov 356: }
357:
358: /*
1.20 ratchov 359: * Attach play and/or record buffers to dev_mix and/or dev_sub.
1.1 ratchov 360: */
361: int
362: sock_attach(struct sock *f, int force)
363: {
364: struct abuf *rbuf, *wbuf;
365:
366: rbuf = LIST_FIRST(&f->pipe.file.rproc->obuflist);
367: wbuf = LIST_FIRST(&f->pipe.file.wproc->ibuflist);
368:
369: /*
1.20 ratchov 370: * If in SOCK_START state, dont attach until
371: * the buffer isn't completely filled.
1.1 ratchov 372: */
373: if (!force && rbuf && ABUF_WOK(rbuf))
374: return 0;
1.12 ratchov 375:
1.1 ratchov 376: f->pstate = SOCK_RUN;
377:
378: /*
1.20 ratchov 379: * Attach them to the device.
1.1 ratchov 380: */
381: dev_attach(f->pipe.file.name,
382: (f->mode & AMSG_PLAY) ? rbuf : NULL, &f->rpar, f->xrun,
1.4 ratchov 383: (f->mode & AMSG_REC) ? wbuf : NULL, &f->wpar, f->xrun,
1.19 ratchov 384: f->opt->maxweight);
1.3 ratchov 385: if (f->mode & AMSG_PLAY)
1.25 ratchov 386: dev_setvol(rbuf, MIDI_TO_ADATA(f->vol));
1.3 ratchov 387:
1.1 ratchov 388: /*
1.20 ratchov 389: * Send the initial position, if needed.
1.1 ratchov 390: */
391: for (;;) {
392: if (!sock_write(f))
393: break;
394: }
395: return 1;
396: }
397:
398: void
399: sock_reset(struct sock *f)
400: {
401: switch (f->pstate) {
402: case SOCK_START:
403: (void)sock_attach(f, 1);
404: f->pstate = SOCK_RUN;
405: /* PASSTHROUGH */
406: case SOCK_RUN:
407: sock_freebuf(f);
408: f->pstate = SOCK_INIT;
409: /* PASSTHROUGH */
410: case SOCK_INIT:
411: /* nothing yet */
412: break;
413: }
414: }
415:
416: /*
1.20 ratchov 417: * Read a message from the file descriptor, return 1 if done, 0
418: * otherwise. The message is stored in f->rmsg.
1.1 ratchov 419: */
420: int
421: sock_rmsg(struct sock *f)
422: {
423: unsigned count;
424: unsigned char *data;
425:
426: while (f->rtodo > 0) {
427: if (!(f->pipe.file.state & FILE_ROK)) {
428: return 0;
429: }
430: data = (unsigned char *)&f->rmsg;
431: data += sizeof(struct amsg) - f->rtodo;
432: count = file_read(&f->pipe.file, data, f->rtodo);
433: if (count == 0)
434: return 0;
435: f->rtodo -= count;
436: }
437: return 1;
438: }
439:
440: /*
1.20 ratchov 441: * Write a message to the file descriptor, return 1 if done, 0
1.1 ratchov 442: * otherwise. The "m" argument is f->rmsg or f->wmsg, and the "ptodo"
443: * points to the f->rtodo or f->wtodo respectively.
444: */
445: int
446: sock_wmsg(struct sock *f, struct amsg *m, unsigned *ptodo)
447: {
448: unsigned count;
449: unsigned char *data;
450:
451: while (*ptodo > 0) {
452: if (!(f->pipe.file.state & FILE_WOK)) {
453: return 0;
454: }
455: data = (unsigned char *)m;
456: data += sizeof(struct amsg) - *ptodo;
457: count = file_write(&f->pipe.file, data, *ptodo);
458: if (count == 0)
459: return 0;
460: *ptodo -= count;
461: }
462: return 1;
463: }
464:
465: /*
1.20 ratchov 466: * Read data chunk from the file descriptor, return 1 if at least one
1.1 ratchov 467: * byte was read, 0 if the file blocked.
468: */
469: int
470: sock_rdata(struct sock *f)
471: {
472: struct aproc *p;
473: struct abuf *obuf;
474: unsigned char *data;
475: unsigned count, n;
476:
477: p = f->pipe.file.rproc;
478: obuf = LIST_FIRST(&p->obuflist);
1.19 ratchov 479: if (obuf == NULL)
480: return 0;
1.1 ratchov 481: if (ABUF_FULL(obuf) || !(f->pipe.file.state & FILE_ROK))
482: return 0;
483: data = abuf_wgetblk(obuf, &count, 0);
1.19 ratchov 484: if (f->pstate != SOCK_MIDI && count > f->rtodo)
1.1 ratchov 485: count = f->rtodo;
486: n = file_read(&f->pipe.file, data, count);
487: if (n == 0)
488: return 0;
489: abuf_wcommit(obuf, n);
1.19 ratchov 490: if (f->pstate != SOCK_MIDI)
491: f->rtodo -= n;
1.1 ratchov 492: return 1;
493: }
494:
495: /*
1.20 ratchov 496: * Write data chunk to the file descriptor, return 1 if at least one
1.1 ratchov 497: * byte was written, 0 if the file blocked.
498: */
499: int
500: sock_wdata(struct sock *f)
501: {
502: struct aproc *p;
503: struct abuf *ibuf;
504: unsigned char *data;
505: unsigned count, n;
506: #define ZERO_MAX 0x1000
507: static char zero[ZERO_MAX];
508:
509: if (!(f->pipe.file.state & FILE_WOK))
510: return 0;
511: p = f->pipe.file.wproc;
512: ibuf = LIST_FIRST(&p->ibuflist);
513: if (ibuf) {
514: if (ABUF_EMPTY(ibuf))
515: return 0;
516: data = abuf_rgetblk(ibuf, &count, 0);
1.19 ratchov 517: if (f->pstate != SOCK_MIDI && count > f->wtodo)
1.1 ratchov 518: count = f->wtodo;
519: n = file_write(&f->pipe.file, data, count);
520: if (n == 0)
521: return 0;
522: abuf_rdiscard(ibuf, n);
1.19 ratchov 523: if (f->pstate != SOCK_MIDI)
524: f->wtodo -= n;
1.1 ratchov 525: } else {
1.19 ratchov 526: if (f->pstate == SOCK_MIDI)
527: return 0;
1.1 ratchov 528: /*
1.20 ratchov 529: * There's no dev_detach() routine yet,
1.1 ratchov 530: * so now we abruptly destroy the buffer.
531: * Until we implement dev_detach, complete
532: * the packet with zeros...
533: */
534: count = ZERO_MAX;
535: if (count > f->wtodo)
536: count = f->wtodo;
537: n = file_write(&f->pipe.file, zero, count);
538: if (n == 0)
539: return 0;
540: f->wtodo -= n;
1.12 ratchov 541: }
1.1 ratchov 542: return 1;
543: }
544:
545: int
546: sock_setpar(struct sock *f)
547: {
548: struct amsg_par *p = &f->rmsg.u.par;
1.9 ratchov 549: unsigned min, max, rate;
1.12 ratchov 550:
1.18 ratchov 551: if (AMSG_ISSET(p->legacy_mode)) {
552: /*
1.29 ! ratchov 553: * allow old clients that don't support HELLO to work
! 554: * XXX: remove this.
1.18 ratchov 555: */
556: if ((p->legacy_mode & ~(AMSG_PLAY | AMSG_REC)) ||
557: (p->legacy_mode == 0)) {
1.1 ratchov 558: return 0;
559: }
560: f->mode = 0;
1.18 ratchov 561: if ((p->legacy_mode & AMSG_PLAY) && dev_mix)
1.1 ratchov 562: f->mode |= AMSG_PLAY;
1.18 ratchov 563: if ((p->legacy_mode & AMSG_REC) && dev_sub)
1.1 ratchov 564: f->mode |= AMSG_REC;
565: }
566: if (AMSG_ISSET(p->bits)) {
567: if (p->bits < BITS_MIN || p->bits > BITS_MAX) {
568: return 0;
569: }
570: if (AMSG_ISSET(p->bps)) {
571: if (p->bps < ((p->bits + 7) / 8) || p->bps > 4) {
572: return 0;
573: }
574: } else
575: p->bps = APARAMS_BPS(p->bits);
576: f->rpar.bits = f->wpar.bits = p->bits;
577: f->rpar.bps = f->wpar.bps = p->bps;
578: }
579: if (AMSG_ISSET(p->sig))
580: f->rpar.sig = f->wpar.sig = p->sig ? 1 : 0;
581: if (AMSG_ISSET(p->le))
582: f->rpar.le = f->wpar.le = p->le ? 1 : 0;
583: if (AMSG_ISSET(p->msb))
584: f->rpar.msb = f->wpar.msb = p->msb ? 1 : 0;
585: if (AMSG_ISSET(p->rchan) && (f->mode & AMSG_REC)) {
586: if (p->rchan < 1)
587: p->rchan = 1;
1.6 ratchov 588: if (p->rchan > NCHAN_MAX)
589: p->rchan = NCHAN_MAX;
1.19 ratchov 590: f->wpar.cmin = f->opt->wpar.cmin;
591: f->wpar.cmax = f->opt->wpar.cmin + p->rchan - 1;
592: if (f->wpar.cmax > f->opt->wpar.cmax)
593: f->wpar.cmax = f->opt->wpar.cmax;
1.1 ratchov 594: }
595: if (AMSG_ISSET(p->pchan) && (f->mode & AMSG_PLAY)) {
596: if (p->pchan < 1)
597: p->pchan = 1;
1.6 ratchov 598: if (p->pchan > NCHAN_MAX)
599: p->pchan = NCHAN_MAX;
1.19 ratchov 600: f->rpar.cmin = f->opt->rpar.cmin;
601: f->rpar.cmax = f->opt->rpar.cmin + p->pchan - 1;
602: if (f->rpar.cmax > f->opt->rpar.cmax)
603: f->rpar.cmax = f->opt->rpar.cmax;
1.1 ratchov 604: }
605: if (AMSG_ISSET(p->rate)) {
606: if (p->rate < RATE_MIN)
607: p->rate = RATE_MIN;
608: if (p->rate > RATE_MAX)
609: p->rate = RATE_MAX;
1.9 ratchov 610: f->round = dev_roundof(p->rate);
1.1 ratchov 611: f->rpar.rate = f->wpar.rate = p->rate;
1.10 ratchov 612: if (!AMSG_ISSET(p->appbufsz)) {
613: p->appbufsz = dev_bufsz / dev_round * f->round;
614: }
1.1 ratchov 615: }
616: if (AMSG_ISSET(p->xrun)) {
617: if (p->xrun != AMSG_IGNORE &&
618: p->xrun != AMSG_SYNC &&
619: p->xrun != AMSG_ERROR) {
620: return 0;
621: }
622: f->xrun = p->xrun;
623: }
624: if (AMSG_ISSET(p->bufsz)) {
1.10 ratchov 625: /*
626: * XXX: bufsz will become read-only, but for now
627: * allow old library to properly work
628: */
629: min = (dev_bufsz / dev_round) * f->round;
630: if (p->bufsz < min)
631: p->bufsz = min;
632: p->appbufsz = p->bufsz - min;
633: }
634: if (AMSG_ISSET(p->appbufsz)) {
1.9 ratchov 635: rate = (f->mode & AMSG_PLAY) ? f->rpar.rate : f->wpar.rate;
1.10 ratchov 636: min = 1;
637: max = 1 + rate / dev_round;
1.9 ratchov 638: min *= f->round;
639: max *= f->round;
1.10 ratchov 640: p->appbufsz += f->round - 1;
641: p->appbufsz -= p->appbufsz % f->round;
642: if (p->appbufsz < min)
643: p->appbufsz = min;
644: if (p->appbufsz > max)
645: p->appbufsz = max;
646: f->bufsz = p->appbufsz;
1.1 ratchov 647: }
648: return 1;
649: }
650:
1.19 ratchov 651: /*
652: * allocate buffers, so client can start filling write-end.
653: */
654: void
655: sock_midiattach(struct sock *f, unsigned mode)
656: {
657: struct abuf *rbuf = NULL, *wbuf = NULL;
658:
659: if (mode & AMSG_MIDIOUT) {
1.22 ratchov 660: rbuf = abuf_new(MIDI_BUFSZ, &aparams_none);
1.19 ratchov 661: aproc_setout(f->pipe.file.rproc, rbuf);
662: }
663: if (mode & AMSG_MIDIIN) {
1.22 ratchov 664: wbuf = abuf_new(MIDI_BUFSZ, &aparams_none);
1.19 ratchov 665: aproc_setin(f->pipe.file.wproc, wbuf);
666: }
1.23 ratchov 667: dev_midiattach(rbuf, wbuf);
1.19 ratchov 668: }
669:
1.17 ratchov 670: int
671: sock_hello(struct sock *f)
672: {
673: struct amsg_hello *p = &f->rmsg.u.hello;
674:
1.29 ! ratchov 675: /* XXX : set file name to p->who */
! 676: /* XXX : dev_midi can no longer be NULL, right ? */
1.19 ratchov 677:
1.23 ratchov 678: if (dev_midi && (p->proto & (AMSG_MIDIIN | AMSG_MIDIOUT))) {
1.19 ratchov 679: if (p->proto & ~(AMSG_MIDIIN | AMSG_MIDIOUT)) {
680: return 0;
681: }
682: f->mode = p->proto;
683: f->pstate = SOCK_MIDI;
684: sock_midiattach(f, p->proto);
685: return 1;
686: }
687: f->opt = opt_byname(p->opt);
688: if (f->opt == NULL)
689: return 0;
690: if (dev_rec)
691: f->wpar = f->opt->wpar;
692: if (dev_play)
693: f->rpar = f->opt->rpar;
1.18 ratchov 694: if ((p->proto & ~(AMSG_PLAY | AMSG_REC)) != 0 ||
695: (p->proto & (AMSG_PLAY | AMSG_REC)) == 0) {
1.17 ratchov 696: return 0;
697: }
1.18 ratchov 698: f->mode = 0;
699: if (p->proto & AMSG_PLAY) {
700: if (!dev_mix) {
701: return 0;
702: }
703: f->mode |= AMSG_PLAY;
1.17 ratchov 704: }
1.18 ratchov 705: if (p->proto & AMSG_REC) {
706: if (!dev_sub) {
707: return 0;
708: }
709: f->mode |= AMSG_REC;
1.17 ratchov 710: }
1.24 ratchov 711: if (dev_midi) {
1.25 ratchov 712: f->slot = ctl_slotnew(dev_midi, p->who, sock_setvol, f);
1.24 ratchov 713: if (f->slot < 0) {
714: return 0;
715: }
716: }
1.18 ratchov 717: f->pstate = SOCK_INIT;
1.17 ratchov 718: return 1;
719: }
720:
1.1 ratchov 721: /*
1.20 ratchov 722: * Execute message in f->rmsg and change the state accordingly; return 1
1.1 ratchov 723: * on success, and 0 on failure, in which case the socket is destroyed.
724: */
725: int
726: sock_execmsg(struct sock *f)
727: {
728: struct amsg *m = &f->rmsg;
729:
1.18 ratchov 730: /*
1.19 ratchov 731: * XXX: allow old clients to work without hello on the default socket
1.18 ratchov 732: */
1.19 ratchov 733: if (f->pstate == SOCK_HELLO && m->cmd != AMSG_HELLO && f->opt != NULL) {
1.18 ratchov 734: f->pstate = SOCK_INIT;
735: }
736:
1.1 ratchov 737: switch (m->cmd) {
738: case AMSG_DATA:
739: if (f->pstate != SOCK_RUN && f->pstate != SOCK_START) {
1.8 ratchov 740: aproc_del(f->pipe.file.rproc);
741: return 0;
742: }
743: if (!(f->mode & AMSG_PLAY)) {
1.1 ratchov 744: aproc_del(f->pipe.file.rproc);
745: return 0;
746: }
747: f->rstate = SOCK_RDATA;
748: f->rtodo = m->u.data.size;
749: if (f->rtodo == 0) {
750: aproc_del(f->pipe.file.rproc);
751: return 0;
752: }
753: break;
754: case AMSG_START:
755: if (f->pstate != SOCK_INIT) {
756: aproc_del(f->pipe.file.rproc);
757: return 0;
758: }
759: sock_allocbuf(f);
760: f->rstate = SOCK_RMSG;
761: f->rtodo = sizeof(struct amsg);
762: break;
763: case AMSG_STOP:
764: if (f->pstate != SOCK_RUN && f->pstate != SOCK_START) {
765: aproc_del(f->pipe.file.rproc);
766: return 0;
767: }
768: if (f->pstate == SOCK_START)
769: (void)sock_attach(f, 1);
770: sock_freebuf(f);
771: AMSG_INIT(m);
772: m->cmd = AMSG_ACK;
773: f->rstate = SOCK_RRET;
774: f->rtodo = sizeof(struct amsg);
775: break;
776: case AMSG_SETPAR:
777: if (f->pstate != SOCK_INIT) {
778: aproc_del(f->pipe.file.rproc);
779: return 0;
780: }
781: if (!sock_setpar(f)) {
782: aproc_del(f->pipe.file.rproc);
783: return 0;
784: }
785: f->rtodo = sizeof(struct amsg);
786: f->rstate = SOCK_RMSG;
787: break;
788: case AMSG_GETPAR:
789: if (f->pstate != SOCK_INIT) {
790: aproc_del(f->pipe.file.rproc);
791: return 0;
792: }
793: AMSG_INIT(m);
794: m->cmd = AMSG_GETPAR;
1.18 ratchov 795: m->u.par.legacy_mode = f->mode;
1.1 ratchov 796: m->u.par.bits = f->rpar.bits;
797: m->u.par.bps = f->rpar.bps;
798: m->u.par.sig = f->rpar.sig;
799: m->u.par.le = f->rpar.le;
800: m->u.par.msb = f->rpar.msb;
801: m->u.par.rate = f->rpar.rate;
802: m->u.par.rchan = f->wpar.cmax - f->wpar.cmin + 1;
803: m->u.par.pchan = f->rpar.cmax - f->rpar.cmin + 1;
1.10 ratchov 804: m->u.par.appbufsz = f->bufsz;
1.12 ratchov 805: m->u.par.bufsz =
1.10 ratchov 806: f->bufsz + (dev_bufsz / dev_round) * f->round;
1.1 ratchov 807: m->u.par.round = f->round;
808: f->rstate = SOCK_RRET;
809: f->rtodo = sizeof(struct amsg);
810: break;
811: case AMSG_GETCAP:
812: if (f->pstate != SOCK_INIT) {
813: aproc_del(f->pipe.file.rproc);
814: return 0;
815: }
816: AMSG_INIT(m);
817: m->cmd = AMSG_GETCAP;
818: m->u.cap.rate = dev_rate;
1.6 ratchov 819: m->u.cap.pchan = dev_mix ?
1.19 ratchov 820: (f->opt->rpar.cmax - f->opt->rpar.cmin + 1) : 0;
1.6 ratchov 821: m->u.cap.rchan = dev_sub ?
1.19 ratchov 822: (f->opt->wpar.cmax - f->opt->wpar.cmin + 1) : 0;
1.1 ratchov 823: m->u.cap.bits = sizeof(short) * 8;
824: m->u.cap.bps = sizeof(short);
825: f->rstate = SOCK_RRET;
826: f->rtodo = sizeof(struct amsg);
1.3 ratchov 827: break;
828: case AMSG_SETVOL:
829: if (f->pstate != SOCK_RUN &&
830: f->pstate != SOCK_START && f->pstate != SOCK_INIT) {
831: aproc_del(f->pipe.file.rproc);
832: return 0;
833: }
834: if (m->u.vol.ctl > MIDI_MAXCTL) {
835: aproc_del(f->pipe.file.rproc);
836: return 0;
837: }
1.25 ratchov 838: sock_setvol(f, m->u.vol.ctl);
1.24 ratchov 839: if (dev_midi && f->slot >= 0)
840: ctl_slotvol(dev_midi, f->slot, m->u.vol.ctl);
1.3 ratchov 841: f->rtodo = sizeof(struct amsg);
842: f->rstate = SOCK_RMSG;
1.17 ratchov 843: break;
844: case AMSG_HELLO:
1.18 ratchov 845: if (f->pstate != SOCK_HELLO) {
1.17 ratchov 846: aproc_del(f->pipe.file.rproc);
847: return 0;
848: }
849: if (!sock_hello(f)) {
850: aproc_del(f->pipe.file.rproc);
851: return 0;
852: }
853: AMSG_INIT(m);
854: m->cmd = AMSG_ACK;
855: f->rstate = SOCK_RRET;
856: f->rtodo = sizeof(struct amsg);
1.1 ratchov 857: break;
1.28 ratchov 858: case AMSG_BYE:
1.29 ! ratchov 859: if (f->pstate != SOCK_INIT) {
! 860: }
1.28 ratchov 861: aproc_del(f->pipe.file.rproc);
862: return 0;
1.1 ratchov 863: default:
864: aproc_del(f->pipe.file.rproc);
865: return 0;
866: }
867: if (f->rstate == SOCK_RRET) {
868: if (f->wstate != SOCK_WIDLE ||
869: !sock_wmsg(f, &f->rmsg, &f->rtodo))
870: return 0;
1.19 ratchov 871: if (f->pstate == SOCK_MIDI && (f->mode & AMSG_MIDIOUT)) {
872: f->rstate = SOCK_RDATA;
873: f->rtodo = 0;
874: } else {
875: f->rstate = SOCK_RMSG;
876: f->rtodo = sizeof(struct amsg);
877: }
1.1 ratchov 878: }
879: return 1;
880: }
881:
882: /*
1.20 ratchov 883: * Create a new data/pos message.
1.1 ratchov 884: */
885: int
886: sock_buildmsg(struct sock *f)
887: {
888: struct aproc *p;
889: struct abuf *ibuf;
1.12 ratchov 890:
1.19 ratchov 891: if (f->pstate == SOCK_MIDI) {
892: f->wstate = SOCK_WDATA;
893: f->wtodo = 0;
894: return 1;
895: }
896:
1.1 ratchov 897: /*
1.20 ratchov 898: * If pos changed, build a MOVE message.
1.1 ratchov 899: */
1.14 ratchov 900: if (f->tickpending && f->delta >= 0) {
1.1 ratchov 901: AMSG_INIT(&f->wmsg);
902: f->wmsg.cmd = AMSG_MOVE;
1.14 ratchov 903: f->wmsg.u.ts.delta = f->delta;
1.1 ratchov 904: f->wtodo = sizeof(struct amsg);
905: f->wstate = SOCK_WMSG;
1.14 ratchov 906: f->delta = 0;
907: f->tickpending = 0;
1.25 ratchov 908: return 1;
909: }
910:
911: /*
912: * if volume changed build a SETVOL message
913: */
1.27 ratchov 914: if (f->pstate >= SOCK_START && f->vol != f->lastvol) {
1.25 ratchov 915: AMSG_INIT(&f->wmsg);
916: f->wmsg.cmd = AMSG_SETVOL;
917: f->wmsg.u.vol.ctl = f->vol;
918: f->wtodo = sizeof(struct amsg);
919: f->wstate = SOCK_WMSG;
920: f->lastvol = f->vol;
1.1 ratchov 921: return 1;
922: }
923:
924: /*
1.20 ratchov 925: * If data available, build a DATA message.
1.1 ratchov 926: */
927: p = f->pipe.file.wproc;
928: ibuf = LIST_FIRST(&p->ibuflist);
929: if (ibuf && ABUF_ROK(ibuf)) {
930: AMSG_INIT(&f->wmsg);
931: f->wmsg.cmd = AMSG_DATA;
932: f->wmsg.u.data.size = ibuf->used - (ibuf->used % ibuf->bpf);
933: if (f->wmsg.u.data.size > AMSG_DATAMAX)
934: f->wmsg.u.data.size =
935: AMSG_DATAMAX - (AMSG_DATAMAX % ibuf->bpf);
936: f->wtodo = sizeof(struct amsg);
937: f->wstate = SOCK_WMSG;
938: return 1;
939: }
940: f->wstate = SOCK_WIDLE;
941: return 0;
942: }
943:
944: /*
1.20 ratchov 945: * Read from the socket file descriptor, fill input buffer and update
1.1 ratchov 946: * the state. Return 1 if at least one message or 1 data byte was
947: * processed, 0 if something blocked.
948: */
949: int
950: sock_read(struct sock *f)
951: {
952: switch (f->rstate) {
953: case SOCK_RMSG:
954: if (!sock_rmsg(f))
955: return 0;
956: if (!sock_execmsg(f))
957: return 0;
958: break;
959: case SOCK_RDATA:
960: if (!sock_rdata(f))
961: return 0;
1.19 ratchov 962: if (f->pstate != SOCK_MIDI && f->rtodo == 0) {
1.1 ratchov 963: f->rstate = SOCK_RMSG;
964: f->rtodo = sizeof(struct amsg);
965: }
966: if (f->pstate == SOCK_START)
967: (void)sock_attach(f, 0);
968: break;
969: case SOCK_RRET:
970: return 0;
971: }
972: return 1;
973: }
974:
975: /*
1.20 ratchov 976: * Process messages to return.
1.1 ratchov 977: */
978: int
979: sock_return(struct sock *f)
980: {
981: struct aproc *rp;
982:
983: while (f->rstate == SOCK_RRET) {
984: if (!sock_wmsg(f, &f->rmsg, &f->rtodo))
985: return 0;
1.19 ratchov 986: if (f->pstate == SOCK_MIDI && (f->mode & AMSG_MIDIOUT)) {
987: f->rstate = SOCK_RDATA;
988: f->rtodo = 0;
989: } else {
990: f->rstate = SOCK_RMSG;
991: f->rtodo = sizeof(struct amsg);
992: }
993: if (f->pipe.file.state & FILE_RINUSE)
994: break;
995: f->pipe.file.state |= FILE_RINUSE;
1.1 ratchov 996: for (;;) {
997: /*
998: * in() may trigger rsock_done and destroy the
1.20 ratchov 999: * wsock.
1.1 ratchov 1000: */
1001: rp = f->pipe.file.rproc;
1002: if (!rp || !rp->ops->in(rp, NULL))
1003: break;
1004: }
1.19 ratchov 1005: f->pipe.file.state &= ~FILE_RINUSE;
1.1 ratchov 1006: if (f->pipe.file.wproc == NULL)
1007: return 0;
1008: }
1009: return 1;
1010: }
1011:
1012: /*
1.20 ratchov 1013: * Write messages and data on the socket file descriptor. Return 1 if
1.1 ratchov 1014: * at least one message or one data byte was processed, 0 if something
1015: * blocked.
1016: */
1017: int
1018: sock_write(struct sock *f)
1019: {
1020: switch (f->wstate) {
1021: case SOCK_WMSG:
1022: if (!sock_wmsg(f, &f->wmsg, &f->wtodo))
1023: return 0;
1024: if (f->wmsg.cmd != AMSG_DATA) {
1025: f->wstate = SOCK_WIDLE;
1026: f->wtodo = 0xdeadbeef;
1027: break;
1028: }
1029: f->wstate = SOCK_WDATA;
1030: f->wtodo = f->wmsg.u.data.size;
1031: /* PASSTHROUGH */
1032: case SOCK_WDATA:
1033: if (!sock_wdata(f))
1034: return 0;
1.19 ratchov 1035: if (f->pstate == SOCK_MIDI || f->wtodo > 0)
1.1 ratchov 1036: break;
1037: f->wstate = SOCK_WIDLE;
1038: f->wtodo = 0xdeadbeef;
1039: /* PASSTHROUGH */
1040: case SOCK_WIDLE:
1041: if (!sock_return(f))
1042: return 0;
1043: if (!sock_buildmsg(f))
1044: return 0;
1045: break;
1046: }
1047: return 1;
1048: }