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