Annotation of src/usr.bin/aucat/sock.c, Revision 1.24
1.24 ! ratchov 1: /* $OpenBSD: sock.c,v 1.23 2009/08/19 05:54: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.3 ratchov 304: f->vol = ADATA_UNIT;
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.20 ratchov 366: * Set volume.
1.3 ratchov 367: */
368: void
369: sock_setvol(struct sock *f, int vol)
370: {
371: struct abuf *rbuf;
1.12 ratchov 372:
1.3 ratchov 373: f->vol = vol;
1.12 ratchov 374: rbuf = LIST_FIRST(&f->pipe.file.rproc->obuflist);
1.3 ratchov 375: if (!rbuf) {
376: DPRINTF("sock_setvol: no read buffer yet\n");
377: return;
378: }
379: dev_setvol(rbuf, vol);
380: }
381:
382: /*
1.20 ratchov 383: * Attach play and/or record buffers to dev_mix and/or dev_sub.
1.1 ratchov 384: */
385: int
386: sock_attach(struct sock *f, int force)
387: {
388: struct abuf *rbuf, *wbuf;
389:
390: rbuf = LIST_FIRST(&f->pipe.file.rproc->obuflist);
391: wbuf = LIST_FIRST(&f->pipe.file.wproc->ibuflist);
392:
393: /*
1.20 ratchov 394: * If in SOCK_START state, dont attach until
395: * the buffer isn't completely filled.
1.1 ratchov 396: */
397: if (!force && rbuf && ABUF_WOK(rbuf))
398: return 0;
1.12 ratchov 399:
1.1 ratchov 400: DPRINTF("sock_attach: %p\n", f);
401: f->pstate = SOCK_RUN;
402:
403: /*
1.20 ratchov 404: * Attach them to the device.
1.1 ratchov 405: */
406: dev_attach(f->pipe.file.name,
407: (f->mode & AMSG_PLAY) ? rbuf : NULL, &f->rpar, f->xrun,
1.4 ratchov 408: (f->mode & AMSG_REC) ? wbuf : NULL, &f->wpar, f->xrun,
1.19 ratchov 409: f->opt->maxweight);
1.3 ratchov 410: if (f->mode & AMSG_PLAY)
411: dev_setvol(rbuf, f->vol);
412:
1.1 ratchov 413: /*
1.20 ratchov 414: * Send the initial position, if needed.
1.1 ratchov 415: */
416: for (;;) {
417: if (!sock_write(f))
418: break;
419: }
420: return 1;
421: }
422:
423: void
424: sock_reset(struct sock *f)
425: {
426: switch (f->pstate) {
427: case SOCK_START:
428: (void)sock_attach(f, 1);
429: f->pstate = SOCK_RUN;
430: /* PASSTHROUGH */
431: case SOCK_RUN:
432: sock_freebuf(f);
433: f->pstate = SOCK_INIT;
434: /* PASSTHROUGH */
435: case SOCK_INIT:
436: /* nothing yet */
437: break;
438: }
439: }
440:
441: /*
1.20 ratchov 442: * Read a message from the file descriptor, return 1 if done, 0
443: * otherwise. The message is stored in f->rmsg.
1.1 ratchov 444: */
445: int
446: sock_rmsg(struct sock *f)
447: {
448: unsigned count;
449: unsigned char *data;
450:
451: while (f->rtodo > 0) {
452: if (!(f->pipe.file.state & FILE_ROK)) {
453: DPRINTFN(4, "sock_rmsg: blk, rtodo = %u\n", f->rtodo);
454: return 0;
455: }
456: data = (unsigned char *)&f->rmsg;
457: data += sizeof(struct amsg) - f->rtodo;
458: count = file_read(&f->pipe.file, data, f->rtodo);
459: if (count == 0)
460: return 0;
461: f->rtodo -= count;
462: }
463: DPRINTFN(4, "sock_rmsg: %p: done\n", f);
464: return 1;
465: }
466:
467: /*
1.20 ratchov 468: * Write a message to the file descriptor, return 1 if done, 0
1.1 ratchov 469: * otherwise. The "m" argument is f->rmsg or f->wmsg, and the "ptodo"
470: * points to the f->rtodo or f->wtodo respectively.
471: */
472: int
473: sock_wmsg(struct sock *f, struct amsg *m, unsigned *ptodo)
474: {
475: unsigned count;
476: unsigned char *data;
477:
478: while (*ptodo > 0) {
479: if (!(f->pipe.file.state & FILE_WOK)) {
480: DPRINTFN(4, "sock_wmsg: blk, *ptodo = %u\n", *ptodo);
481: return 0;
482: }
483: data = (unsigned char *)m;
484: data += sizeof(struct amsg) - *ptodo;
485: count = file_write(&f->pipe.file, data, *ptodo);
486: if (count == 0)
487: return 0;
488: *ptodo -= count;
489: }
490: DPRINTFN(4, "sock_wmsg: %p: done\n", f);
491: return 1;
492: }
493:
494: /*
1.20 ratchov 495: * Read data chunk from the file descriptor, return 1 if at least one
1.1 ratchov 496: * byte was read, 0 if the file blocked.
497: */
498: int
499: sock_rdata(struct sock *f)
500: {
501: struct aproc *p;
502: struct abuf *obuf;
503: unsigned char *data;
504: unsigned count, n;
505:
506: #ifdef DEBUG
1.19 ratchov 507: if (f->pstate != SOCK_MIDI && f->rtodo == 0) {
1.1 ratchov 508: fprintf(stderr, "sock_rdata: bad call: zero arg\n");
509: abort();
510: }
511: #endif
512: p = f->pipe.file.rproc;
513: obuf = LIST_FIRST(&p->obuflist);
1.19 ratchov 514: if (obuf == NULL)
515: return 0;
1.1 ratchov 516: if (ABUF_FULL(obuf) || !(f->pipe.file.state & FILE_ROK))
517: return 0;
518: data = abuf_wgetblk(obuf, &count, 0);
1.19 ratchov 519: if (f->pstate != SOCK_MIDI && count > f->rtodo)
1.1 ratchov 520: count = f->rtodo;
521: n = file_read(&f->pipe.file, data, count);
522: if (n == 0)
523: return 0;
524: abuf_wcommit(obuf, n);
1.19 ratchov 525: if (f->pstate != SOCK_MIDI)
526: f->rtodo -= n;
1.1 ratchov 527: return 1;
528: }
529:
530: /*
1.20 ratchov 531: * Write data chunk to the file descriptor, return 1 if at least one
1.1 ratchov 532: * byte was written, 0 if the file blocked.
533: */
534: int
535: sock_wdata(struct sock *f)
536: {
537: struct aproc *p;
538: struct abuf *ibuf;
539: unsigned char *data;
540: unsigned count, n;
541: #define ZERO_MAX 0x1000
542: static char zero[ZERO_MAX];
543:
544: #ifdef DEBUG
1.19 ratchov 545: if (f->pstate != SOCK_MIDI && f->wtodo == 0) {
1.1 ratchov 546: fprintf(stderr, "sock_wdata: bad call: zero arg\n");
547: abort();
548: }
549: #endif
550: if (!(f->pipe.file.state & FILE_WOK))
551: return 0;
552: p = f->pipe.file.wproc;
553: ibuf = LIST_FIRST(&p->ibuflist);
554: if (ibuf) {
555: if (ABUF_EMPTY(ibuf))
556: return 0;
557: data = abuf_rgetblk(ibuf, &count, 0);
1.19 ratchov 558: if (f->pstate != SOCK_MIDI && count > f->wtodo)
1.1 ratchov 559: count = f->wtodo;
560: n = file_write(&f->pipe.file, data, count);
561: if (n == 0)
562: return 0;
563: abuf_rdiscard(ibuf, n);
1.19 ratchov 564: if (f->pstate != SOCK_MIDI)
565: f->wtodo -= n;
1.1 ratchov 566: } else {
1.19 ratchov 567: if (f->pstate == SOCK_MIDI)
568: return 0;
1.1 ratchov 569: /*
1.20 ratchov 570: * There's no dev_detach() routine yet,
1.1 ratchov 571: * so now we abruptly destroy the buffer.
572: * Until we implement dev_detach, complete
573: * the packet with zeros...
574: */
575: count = ZERO_MAX;
576: if (count > f->wtodo)
577: count = f->wtodo;
578: n = file_write(&f->pipe.file, zero, count);
579: if (n == 0)
580: return 0;
581: f->wtodo -= n;
1.12 ratchov 582: }
1.1 ratchov 583: return 1;
584: }
585:
586: int
587: sock_setpar(struct sock *f)
588: {
589: struct amsg_par *p = &f->rmsg.u.par;
1.9 ratchov 590: unsigned min, max, rate;
1.12 ratchov 591:
1.18 ratchov 592: if (AMSG_ISSET(p->legacy_mode)) {
593: /*
594: * XXX: allow old clients that don't support HELLO
595: * to work
596: */
597: if ((p->legacy_mode & ~(AMSG_PLAY | AMSG_REC)) ||
598: (p->legacy_mode == 0)) {
599: DPRINTF("sock_setpar: bad mode %x\n", p->legacy_mode);
1.1 ratchov 600: return 0;
601: }
602: f->mode = 0;
1.18 ratchov 603: if ((p->legacy_mode & AMSG_PLAY) && dev_mix)
1.1 ratchov 604: f->mode |= AMSG_PLAY;
1.18 ratchov 605: if ((p->legacy_mode & AMSG_REC) && dev_sub)
1.1 ratchov 606: f->mode |= AMSG_REC;
607: DPRINTF("sock_setpar: mode -> %x\n", f->mode);
608: }
609: if (AMSG_ISSET(p->bits)) {
610: if (p->bits < BITS_MIN || p->bits > BITS_MAX) {
611: DPRINTF("sock_setpar: bits out of bounds\n");
612: return 0;
613: }
614: if (AMSG_ISSET(p->bps)) {
615: if (p->bps < ((p->bits + 7) / 8) || p->bps > 4) {
616: DPRINTF("sock_setpar: bps out of bounds\n");
617: return 0;
618: }
619: } else
620: p->bps = APARAMS_BPS(p->bits);
621: f->rpar.bits = f->wpar.bits = p->bits;
622: f->rpar.bps = f->wpar.bps = p->bps;
623: DPRINTF("sock_setpar: bits/bps -> %u/%u\n", p->bits, p->bps);
624: }
625: if (AMSG_ISSET(p->sig))
626: f->rpar.sig = f->wpar.sig = p->sig ? 1 : 0;
627: if (AMSG_ISSET(p->le))
628: f->rpar.le = f->wpar.le = p->le ? 1 : 0;
629: if (AMSG_ISSET(p->msb))
630: f->rpar.msb = f->wpar.msb = p->msb ? 1 : 0;
631: if (AMSG_ISSET(p->rchan) && (f->mode & AMSG_REC)) {
632: if (p->rchan < 1)
633: p->rchan = 1;
1.6 ratchov 634: if (p->rchan > NCHAN_MAX)
635: p->rchan = NCHAN_MAX;
1.19 ratchov 636: f->wpar.cmin = f->opt->wpar.cmin;
637: f->wpar.cmax = f->opt->wpar.cmin + p->rchan - 1;
638: if (f->wpar.cmax > f->opt->wpar.cmax)
639: f->wpar.cmax = f->opt->wpar.cmax;
1.6 ratchov 640: DPRINTF("sock_setpar: rchan -> %u:%u\n",
641: f->wpar.cmin, f->wpar.cmax);
1.1 ratchov 642: }
643: if (AMSG_ISSET(p->pchan) && (f->mode & AMSG_PLAY)) {
644: if (p->pchan < 1)
645: p->pchan = 1;
1.6 ratchov 646: if (p->pchan > NCHAN_MAX)
647: p->pchan = NCHAN_MAX;
1.19 ratchov 648: f->rpar.cmin = f->opt->rpar.cmin;
649: f->rpar.cmax = f->opt->rpar.cmin + p->pchan - 1;
650: if (f->rpar.cmax > f->opt->rpar.cmax)
651: f->rpar.cmax = f->opt->rpar.cmax;
1.6 ratchov 652: DPRINTF("sock_setpar: pchan -> %u:%u\n",
653: f->rpar.cmin, f->rpar.cmax);
1.1 ratchov 654: }
655: if (AMSG_ISSET(p->rate)) {
656: if (p->rate < RATE_MIN)
657: p->rate = RATE_MIN;
658: if (p->rate > RATE_MAX)
659: p->rate = RATE_MAX;
1.9 ratchov 660: f->round = dev_roundof(p->rate);
1.1 ratchov 661: f->rpar.rate = f->wpar.rate = p->rate;
1.10 ratchov 662: if (!AMSG_ISSET(p->appbufsz)) {
663: p->appbufsz = dev_bufsz / dev_round * f->round;
664: DPRINTF("sock_setpar: appbufsz -> %u\n", p->appbufsz);
665: }
1.9 ratchov 666: DPRINTF("sock_setpar: rate -> %u, round -> %u\n",
667: p->rate, f->round);
1.1 ratchov 668: }
669: if (AMSG_ISSET(p->xrun)) {
670: if (p->xrun != AMSG_IGNORE &&
671: p->xrun != AMSG_SYNC &&
672: p->xrun != AMSG_ERROR) {
673: DPRINTF("sock_setpar: bad xrun: %u\n", p->xrun);
674: return 0;
675: }
676: f->xrun = p->xrun;
677: DPRINTF("sock_setpar: xrun -> %u\n", f->xrun);
678: }
679: if (AMSG_ISSET(p->bufsz)) {
1.10 ratchov 680: /*
681: * XXX: bufsz will become read-only, but for now
682: * allow old library to properly work
683: */
684: DPRINTF("sock_setpar: bufsz: %u\n", p->bufsz);
685: min = (dev_bufsz / dev_round) * f->round;
686: if (p->bufsz < min)
687: p->bufsz = min;
688: p->appbufsz = p->bufsz - min;
689: }
690: if (AMSG_ISSET(p->appbufsz)) {
1.9 ratchov 691: rate = (f->mode & AMSG_PLAY) ? f->rpar.rate : f->wpar.rate;
1.10 ratchov 692: min = 1;
693: max = 1 + rate / dev_round;
1.9 ratchov 694: min *= f->round;
695: max *= f->round;
1.10 ratchov 696: p->appbufsz += f->round - 1;
697: p->appbufsz -= p->appbufsz % f->round;
698: if (p->appbufsz < min)
699: p->appbufsz = min;
700: if (p->appbufsz > max)
701: p->appbufsz = max;
702: f->bufsz = p->appbufsz;
1.1 ratchov 703: DPRINTF("sock_setpar: bufsz -> %u\n", f->bufsz);
704: }
1.5 ratchov 705: #ifdef DEBUG
1.1 ratchov 706: if (debug_level > 0) {
707: fprintf(stderr, "sock_setpar: %p: rpar=", f);
708: aparams_print(&f->rpar);
709: fprintf(stderr, ", wpar=");
710: aparams_print(&f->wpar);
711: fprintf(stderr, ", mode=%u, bufsz=%u\n", f->mode, f->bufsz);
712: }
1.5 ratchov 713: #endif
1.1 ratchov 714: return 1;
715: }
716:
1.19 ratchov 717: /*
718: * allocate buffers, so client can start filling write-end.
719: */
720: void
721: sock_midiattach(struct sock *f, unsigned mode)
722: {
723: struct abuf *rbuf = NULL, *wbuf = NULL;
724:
725: if (mode & AMSG_MIDIOUT) {
1.22 ratchov 726: rbuf = abuf_new(MIDI_BUFSZ, &aparams_none);
1.19 ratchov 727: aproc_setout(f->pipe.file.rproc, rbuf);
728: }
729: if (mode & AMSG_MIDIIN) {
1.22 ratchov 730: wbuf = abuf_new(MIDI_BUFSZ, &aparams_none);
1.19 ratchov 731: aproc_setin(f->pipe.file.wproc, wbuf);
732: }
1.23 ratchov 733: dev_midiattach(rbuf, wbuf);
1.19 ratchov 734: }
735:
1.17 ratchov 736: int
737: sock_hello(struct sock *f)
738: {
739: struct amsg_hello *p = &f->rmsg.u.hello;
740:
1.19 ratchov 741: DPRINTF("sock_hello: from <%s>, mode = %x\n", p->who, p->proto);
742:
1.23 ratchov 743: if (dev_midi && (p->proto & (AMSG_MIDIIN | AMSG_MIDIOUT))) {
1.19 ratchov 744: if (p->proto & ~(AMSG_MIDIIN | AMSG_MIDIOUT)) {
745: DPRINTF("sock_hello: %x: bad proto\n", p->proto);
746: return 0;
747: }
748: f->mode = p->proto;
749: f->pstate = SOCK_MIDI;
750: sock_midiattach(f, p->proto);
751: return 1;
752: }
753: f->opt = opt_byname(p->opt);
754: if (f->opt == NULL)
755: return 0;
756: if (dev_rec)
757: f->wpar = f->opt->wpar;
758: if (dev_play)
759: f->rpar = f->opt->rpar;
1.18 ratchov 760: if ((p->proto & ~(AMSG_PLAY | AMSG_REC)) != 0 ||
761: (p->proto & (AMSG_PLAY | AMSG_REC)) == 0) {
762: DPRINTF("sock_hello: %x: unsupported proto\n", p->proto);
1.17 ratchov 763: return 0;
764: }
1.18 ratchov 765: f->mode = 0;
766: if (p->proto & AMSG_PLAY) {
767: if (!dev_mix) {
768: DPRINTF("sock_hello: playback not supported\n");
769: return 0;
770: }
771: f->mode |= AMSG_PLAY;
1.17 ratchov 772: }
1.18 ratchov 773: if (p->proto & AMSG_REC) {
774: if (!dev_sub) {
775: DPRINTF("sock_hello: recording not supported\n");
776: return 0;
777: }
778: f->mode |= AMSG_REC;
1.17 ratchov 779: }
1.24 ! ratchov 780: if (dev_midi) {
! 781: f->slot = ctl_slotnew(dev_midi, p->who, f->pipe.file.rproc);
! 782: if (f->slot < 0) {
! 783: DPRINTF("sock_hello: out of mixer slots\n");
! 784: return 0;
! 785: }
! 786: if (f->mode & AMSG_PLAY)
! 787: ctl_slotvol(dev_midi, f->slot, MIDI_MAXCTL);
! 788: }
1.18 ratchov 789: f->pstate = SOCK_INIT;
1.17 ratchov 790: return 1;
791: }
792:
1.1 ratchov 793: /*
1.20 ratchov 794: * Execute message in f->rmsg and change the state accordingly; return 1
1.1 ratchov 795: * on success, and 0 on failure, in which case the socket is destroyed.
796: */
797: int
798: sock_execmsg(struct sock *f)
799: {
800: struct amsg *m = &f->rmsg;
801:
1.18 ratchov 802: /*
1.19 ratchov 803: * XXX: allow old clients to work without hello on the default socket
1.18 ratchov 804: */
1.19 ratchov 805: if (f->pstate == SOCK_HELLO && m->cmd != AMSG_HELLO && f->opt != NULL) {
1.18 ratchov 806: DPRINTF("sock_execmsg: legacy client\n");
807: f->pstate = SOCK_INIT;
808: }
809:
1.1 ratchov 810: switch (m->cmd) {
811: case AMSG_DATA:
812: DPRINTFN(4, "sock_execmsg: %p: DATA\n", f);
813: if (f->pstate != SOCK_RUN && f->pstate != SOCK_START) {
814: DPRINTF("sock_execmsg: %p: DATA, bad state\n", f);
1.8 ratchov 815: aproc_del(f->pipe.file.rproc);
816: return 0;
817: }
818: if (!(f->mode & AMSG_PLAY)) {
819: DPRINTF("sock_execmsg: %p: DATA, not allowed\n", f);
1.1 ratchov 820: aproc_del(f->pipe.file.rproc);
821: return 0;
822: }
823: f->rstate = SOCK_RDATA;
824: f->rtodo = m->u.data.size;
825: if (f->rtodo == 0) {
826: DPRINTF("sock_execmsg: zero-length data chunk\n");
827: aproc_del(f->pipe.file.rproc);
828: return 0;
829: }
830: break;
831: case AMSG_START:
832: DPRINTFN(2, "sock_execmsg: %p: START\n", f);
833: if (f->pstate != SOCK_INIT) {
834: DPRINTF("sock_execmsg: %p: START, bad state\n", f);
835: aproc_del(f->pipe.file.rproc);
836: return 0;
837: }
838: sock_allocbuf(f);
839: f->rstate = SOCK_RMSG;
840: f->rtodo = sizeof(struct amsg);
841: break;
842: case AMSG_STOP:
843: DPRINTFN(2, "sock_execmsg: %p: STOP\n", f);
844: if (f->pstate != SOCK_RUN && f->pstate != SOCK_START) {
845: DPRINTF("sock_execmsg: %p: STOP, bad state\n", f);
846: aproc_del(f->pipe.file.rproc);
847: return 0;
848: }
849: if (f->pstate == SOCK_START)
850: (void)sock_attach(f, 1);
851: sock_freebuf(f);
852: AMSG_INIT(m);
853: m->cmd = AMSG_ACK;
854: f->rstate = SOCK_RRET;
855: f->rtodo = sizeof(struct amsg);
856: break;
857: case AMSG_SETPAR:
858: DPRINTFN(2, "sock_execmsg: %p: SETPAR\n", f);
859: if (f->pstate != SOCK_INIT) {
860: DPRINTF("sock_execmsg: %p: SETPAR, bad state\n", f);
861: aproc_del(f->pipe.file.rproc);
862: return 0;
863: }
864: if (!sock_setpar(f)) {
865: aproc_del(f->pipe.file.rproc);
866: return 0;
867: }
868: f->rtodo = sizeof(struct amsg);
869: f->rstate = SOCK_RMSG;
870: break;
871: case AMSG_GETPAR:
872: DPRINTFN(2, "sock_execmsg: %p: GETPAR\n", f);
873: if (f->pstate != SOCK_INIT) {
874: DPRINTF("sock_execmsg: %p: GETPAR, bad state\n", f);
875: aproc_del(f->pipe.file.rproc);
876: return 0;
877: }
878: AMSG_INIT(m);
879: m->cmd = AMSG_GETPAR;
1.18 ratchov 880: m->u.par.legacy_mode = f->mode;
1.1 ratchov 881: m->u.par.bits = f->rpar.bits;
882: m->u.par.bps = f->rpar.bps;
883: m->u.par.sig = f->rpar.sig;
884: m->u.par.le = f->rpar.le;
885: m->u.par.msb = f->rpar.msb;
886: m->u.par.rate = f->rpar.rate;
887: m->u.par.rchan = f->wpar.cmax - f->wpar.cmin + 1;
888: m->u.par.pchan = f->rpar.cmax - f->rpar.cmin + 1;
1.10 ratchov 889: m->u.par.appbufsz = f->bufsz;
1.12 ratchov 890: m->u.par.bufsz =
1.10 ratchov 891: f->bufsz + (dev_bufsz / dev_round) * f->round;
1.1 ratchov 892: m->u.par.round = f->round;
893: f->rstate = SOCK_RRET;
894: f->rtodo = sizeof(struct amsg);
895: break;
896: case AMSG_GETCAP:
897: DPRINTFN(2, "sock_execmsg: %p: GETCAP\n", f);
898: if (f->pstate != SOCK_INIT) {
899: DPRINTF("sock_execmsg: %p: GETCAP, bad state\n", f);
900: aproc_del(f->pipe.file.rproc);
901: return 0;
902: }
903: AMSG_INIT(m);
904: m->cmd = AMSG_GETCAP;
905: m->u.cap.rate = dev_rate;
1.6 ratchov 906: m->u.cap.pchan = dev_mix ?
1.19 ratchov 907: (f->opt->rpar.cmax - f->opt->rpar.cmin + 1) : 0;
1.6 ratchov 908: m->u.cap.rchan = dev_sub ?
1.19 ratchov 909: (f->opt->wpar.cmax - f->opt->wpar.cmin + 1) : 0;
1.1 ratchov 910: m->u.cap.bits = sizeof(short) * 8;
911: m->u.cap.bps = sizeof(short);
912: f->rstate = SOCK_RRET;
913: f->rtodo = sizeof(struct amsg);
1.3 ratchov 914: break;
915: case AMSG_SETVOL:
916: DPRINTFN(2, "sock_execmsg: %p: SETVOL\n", f);
917: if (f->pstate != SOCK_RUN &&
918: f->pstate != SOCK_START && f->pstate != SOCK_INIT) {
919: DPRINTF("sock_execmsg: %p: SETVOL, bad state\n", f);
920: aproc_del(f->pipe.file.rproc);
921: return 0;
922: }
923: if (m->u.vol.ctl > MIDI_MAXCTL) {
924: DPRINTF("sock_execmsg: %p: SETVOL, out of range\n", f);
925: aproc_del(f->pipe.file.rproc);
926: return 0;
927: }
928: DPRINTF("sock_execmsg: SETVOL %u\n", m->u.vol.ctl);
929: sock_setvol(f, MIDI_TO_ADATA(m->u.vol.ctl));
1.24 ! ratchov 930: if (dev_midi && f->slot >= 0)
! 931: ctl_slotvol(dev_midi, f->slot, m->u.vol.ctl);
1.3 ratchov 932: f->rtodo = sizeof(struct amsg);
933: f->rstate = SOCK_RMSG;
1.17 ratchov 934: break;
935: case AMSG_HELLO:
936: DPRINTFN(2, "sock_execmsg: %p: HELLO\n", f);
1.18 ratchov 937: if (f->pstate != SOCK_HELLO) {
1.17 ratchov 938: DPRINTF("sock_execmsg: %p: HELLO, bad state\n", f);
939: aproc_del(f->pipe.file.rproc);
940: return 0;
941: }
942: if (!sock_hello(f)) {
943: aproc_del(f->pipe.file.rproc);
944: return 0;
945: }
946: AMSG_INIT(m);
947: m->cmd = AMSG_ACK;
948: f->rstate = SOCK_RRET;
949: f->rtodo = sizeof(struct amsg);
1.1 ratchov 950: break;
951: default:
952: DPRINTF("sock_execmsg: %p bogus command\n", f);
953: aproc_del(f->pipe.file.rproc);
954: return 0;
955: }
956: if (f->rstate == SOCK_RRET) {
957: if (f->wstate != SOCK_WIDLE ||
958: !sock_wmsg(f, &f->rmsg, &f->rtodo))
959: return 0;
960: DPRINTF("sock_execmsg: %p RRET done\n", f);
1.19 ratchov 961: if (f->pstate == SOCK_MIDI && (f->mode & AMSG_MIDIOUT)) {
962: f->rstate = SOCK_RDATA;
963: f->rtodo = 0;
964: } else {
965: f->rstate = SOCK_RMSG;
966: f->rtodo = sizeof(struct amsg);
967: }
1.1 ratchov 968: }
969: return 1;
970: }
971:
972: /*
1.20 ratchov 973: * Create a new data/pos message.
1.1 ratchov 974: */
975: int
976: sock_buildmsg(struct sock *f)
977: {
978: struct aproc *p;
979: struct abuf *ibuf;
1.12 ratchov 980:
1.19 ratchov 981: if (f->pstate == SOCK_MIDI) {
982: DPRINTFN(4, "sock_buildmsg: %p: switched to midi\n", f);
983: f->wstate = SOCK_WDATA;
984: f->wtodo = 0;
985: return 1;
986: }
987:
1.1 ratchov 988: /*
1.20 ratchov 989: * If pos changed, build a MOVE message.
1.1 ratchov 990: */
1.14 ratchov 991: if (f->tickpending && f->delta >= 0) {
992: DPRINTFN(4, "sock_buildmsg: %p: POS: %d\n", f, f->delta);
1.1 ratchov 993: AMSG_INIT(&f->wmsg);
994: f->wmsg.cmd = AMSG_MOVE;
1.14 ratchov 995: f->wmsg.u.ts.delta = f->delta;
1.1 ratchov 996: f->wtodo = sizeof(struct amsg);
997: f->wstate = SOCK_WMSG;
1.14 ratchov 998: f->delta = 0;
999: f->tickpending = 0;
1.1 ratchov 1000: return 1;
1001: }
1002:
1003: /*
1.20 ratchov 1004: * If data available, build a DATA message.
1.1 ratchov 1005: */
1006: p = f->pipe.file.wproc;
1007: ibuf = LIST_FIRST(&p->ibuflist);
1008: if (ibuf && ABUF_ROK(ibuf)) {
1009: AMSG_INIT(&f->wmsg);
1010: f->wmsg.cmd = AMSG_DATA;
1011: f->wmsg.u.data.size = ibuf->used - (ibuf->used % ibuf->bpf);
1012: if (f->wmsg.u.data.size > AMSG_DATAMAX)
1013: f->wmsg.u.data.size =
1014: AMSG_DATAMAX - (AMSG_DATAMAX % ibuf->bpf);
1015: f->wtodo = sizeof(struct amsg);
1016: f->wstate = SOCK_WMSG;
1017: return 1;
1018: }
1019:
1020: DPRINTFN(4, "sock_buildmsg: %p: idling...\n", f);
1021: f->wstate = SOCK_WIDLE;
1022: return 0;
1023: }
1024:
1025: /*
1.20 ratchov 1026: * Read from the socket file descriptor, fill input buffer and update
1.1 ratchov 1027: * the state. Return 1 if at least one message or 1 data byte was
1028: * processed, 0 if something blocked.
1029: */
1030: int
1031: sock_read(struct sock *f)
1032: {
1033: DPRINTFN(4, "sock_read: %p; rstate = %u, rtodo = %u\n",
1034: f, f->rstate, f->rtodo);
1035:
1036: switch (f->rstate) {
1037: case SOCK_RMSG:
1038: if (!sock_rmsg(f))
1039: return 0;
1040: if (!sock_execmsg(f))
1041: return 0;
1042: break;
1043: case SOCK_RDATA:
1044: if (!sock_rdata(f))
1045: return 0;
1.19 ratchov 1046: if (f->pstate != SOCK_MIDI && f->rtodo == 0) {
1.1 ratchov 1047: f->rstate = SOCK_RMSG;
1048: f->rtodo = sizeof(struct amsg);
1049: }
1050: if (f->pstate == SOCK_START)
1051: (void)sock_attach(f, 0);
1052: break;
1053: case SOCK_RRET:
1054: DPRINTF("sock_read: %p: blocked in RRET\n", f);
1055: return 0;
1056: }
1057: DPRINTFN(4, "sock_read: %p: done, rstate = %u\n", f, f->rstate);
1058: return 1;
1059: }
1060:
1061: /*
1.20 ratchov 1062: * Process messages to return.
1.1 ratchov 1063: */
1064: int
1065: sock_return(struct sock *f)
1066: {
1067: struct aproc *rp;
1068:
1069: while (f->rstate == SOCK_RRET) {
1070: if (!sock_wmsg(f, &f->rmsg, &f->rtodo))
1071: return 0;
1072: DPRINTF("sock_return: %p: done\n", f);
1.19 ratchov 1073: if (f->pstate == SOCK_MIDI && (f->mode & AMSG_MIDIOUT)) {
1074: f->rstate = SOCK_RDATA;
1075: f->rtodo = 0;
1076: } else {
1077: f->rstate = SOCK_RMSG;
1078: f->rtodo = sizeof(struct amsg);
1079: }
1080: if (f->pipe.file.state & FILE_RINUSE)
1081: break;
1082: f->pipe.file.state |= FILE_RINUSE;
1.1 ratchov 1083: for (;;) {
1084: /*
1085: * in() may trigger rsock_done and destroy the
1.20 ratchov 1086: * wsock.
1.1 ratchov 1087: */
1088: rp = f->pipe.file.rproc;
1089: if (!rp || !rp->ops->in(rp, NULL))
1090: break;
1091: }
1.19 ratchov 1092: f->pipe.file.state &= ~FILE_RINUSE;
1.1 ratchov 1093: if (f->pipe.file.wproc == NULL)
1094: return 0;
1095: }
1096: return 1;
1097: }
1098:
1099: /*
1.20 ratchov 1100: * Write messages and data on the socket file descriptor. Return 1 if
1.1 ratchov 1101: * at least one message or one data byte was processed, 0 if something
1102: * blocked.
1103: */
1104: int
1105: sock_write(struct sock *f)
1106: {
1107: DPRINTFN(4, "sock_write: %p: wstate = %u, wtodo = %u\n",
1108: f, f->wstate, f->wtodo);
1109:
1110: switch (f->wstate) {
1111: case SOCK_WMSG:
1112: if (!sock_wmsg(f, &f->wmsg, &f->wtodo))
1113: return 0;
1114: if (f->wmsg.cmd != AMSG_DATA) {
1115: f->wstate = SOCK_WIDLE;
1116: f->wtodo = 0xdeadbeef;
1117: break;
1118: }
1119: f->wstate = SOCK_WDATA;
1120: f->wtodo = f->wmsg.u.data.size;
1121: /* PASSTHROUGH */
1122: case SOCK_WDATA:
1123: if (!sock_wdata(f))
1124: return 0;
1.19 ratchov 1125: if (f->pstate == SOCK_MIDI || f->wtodo > 0)
1.1 ratchov 1126: break;
1127: f->wstate = SOCK_WIDLE;
1128: f->wtodo = 0xdeadbeef;
1129: /* PASSTHROUGH */
1130: case SOCK_WIDLE:
1131: if (!sock_return(f))
1132: return 0;
1133: if (!sock_buildmsg(f))
1134: return 0;
1135: break;
1136: default:
1137: fprintf(stderr, "sock_write: unknown state\n");
1138: abort();
1139: }
1140: return 1;
1141: }