Annotation of src/usr.bin/aucat/sock.c, Revision 1.45
1.45 ! ratchov 1: /* $OpenBSD: sock.c,v 1.44 2010/04/22 17:43:30 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:
1.44 ratchov 18: #include <sys/types.h>
19: #include <sys/socket.h>
20: #include <unistd.h>
1.1 ratchov 21: #include <stdio.h>
22: #include <stdlib.h>
23: #include <string.h>
1.20 ratchov 24:
25: #include "abuf.h"
1.1 ratchov 26: #include "aproc.h"
1.20 ratchov 27: #include "conf.h"
1.1 ratchov 28: #include "dev.h"
1.19 ratchov 29: #include "midi.h"
30: #include "opt.h"
1.20 ratchov 31: #include "sock.h"
1.37 ratchov 32: #ifdef DEBUG
33: #include "dbg.h"
34: #endif
1.1 ratchov 35:
1.42 ratchov 36: void sock_attach(struct sock *, int);
1.1 ratchov 37: int sock_read(struct sock *);
38: int sock_write(struct sock *);
39: int sock_execmsg(struct sock *);
40: void sock_reset(struct sock *);
1.44 ratchov 41: void sock_close(struct file *);
1.1 ratchov 42:
43: struct fileops sock_ops = {
44: "sock",
45: sizeof(struct sock),
1.44 ratchov 46: sock_close,
1.1 ratchov 47: pipe_read,
48: pipe_write,
49: NULL, /* start */
50: NULL, /* stop */
51: pipe_nfds,
52: pipe_pollfd,
53: pipe_revents
54: };
1.30 ratchov 55:
1.37 ratchov 56: #ifdef DEBUG
57: void
58: sock_dbg(struct sock *f)
59: {
1.42 ratchov 60: static char *pstates[] = { "hel", "ini", "sta", "rdy", "run", "mid" };
1.37 ratchov 61: static char *rstates[] = { "rdat", "rmsg", "rret" };
62: static char *wstates[] = { "widl", "wmsg", "wdat" };
63:
1.42 ratchov 64: if (f->slot >= 0 && APROC_OK(dev_midi)) {
1.37 ratchov 65: dbg_puts(dev_midi->u.ctl.slot[f->slot].name);
66: dbg_putu(dev_midi->u.ctl.slot[f->slot].unit);
67: } else
68: dbg_puts(f->pipe.file.name);
69: dbg_puts("/");
70: dbg_puts(pstates[f->pstate]);
71: dbg_puts("|");
72: dbg_puts(rstates[f->rstate]);
73: dbg_puts("|");
74: dbg_puts(wstates[f->wstate]);
75: }
76: #endif
1.1 ratchov 77:
1.34 ratchov 78: void sock_setvol(void *, unsigned);
1.35 ratchov 79: void sock_startreq(void *);
1.42 ratchov 80: void sock_stopreq(void *);
81: void sock_locreq(void *, unsigned);
1.34 ratchov 82:
83: struct ctl_ops ctl_sockops = {
84: sock_setvol,
1.42 ratchov 85: sock_startreq,
86: sock_stopreq,
87: sock_locreq
1.34 ratchov 88: };
89:
1.44 ratchov 90: unsigned sock_sesrefs = 0; /* connections to the session */
91: uid_t sock_sesuid; /* owner of the session */
92:
93: void
94: sock_close(struct file *f)
95: {
96: sock_sesrefs--;
97: pipe_close(f);
98: }
99:
1.1 ratchov 100: void
101: rsock_done(struct aproc *p)
102: {
103: struct sock *f = (struct sock *)p->u.io.file;
104:
1.11 ratchov 105: if (f == NULL)
106: return;
1.1 ratchov 107: sock_reset(f);
108: f->pipe.file.rproc = NULL;
109: if (f->pipe.file.wproc) {
1.34 ratchov 110: if (f->slot >= 0)
1.24 ratchov 111: ctl_slotdel(dev_midi, f->slot);
1.1 ratchov 112: aproc_del(f->pipe.file.wproc);
113: file_del(&f->pipe.file);
114: }
1.11 ratchov 115: p->u.io.file = NULL;
1.1 ratchov 116: }
117:
118: int
119: rsock_in(struct aproc *p, struct abuf *ibuf_dummy)
120: {
121: struct sock *f = (struct sock *)p->u.io.file;
122: struct abuf *obuf;
123:
124: if (!sock_read(f))
125: return 0;
1.45 ! ratchov 126: obuf = LIST_FIRST(&p->outs);
1.34 ratchov 127: if (obuf && f->pstate >= SOCK_RUN) {
1.1 ratchov 128: if (!abuf_flush(obuf))
129: return 0;
130: }
131: return 1;
132: }
133:
134: int
135: rsock_out(struct aproc *p, struct abuf *obuf)
136: {
137: struct sock *f = (struct sock *)p->u.io.file;
138:
1.19 ratchov 139: if (f->pipe.file.state & FILE_RINUSE)
1.1 ratchov 140: return 0;
141:
1.12 ratchov 142: /*
1.20 ratchov 143: * When calling sock_read(), we may receive a ``STOP'' command,
1.1 ratchov 144: * and detach ``obuf''. In this case, there's no more caller and
1.20 ratchov 145: * we'll stop processing further messages, resulting in a deadlock.
1.1 ratchov 146: * The solution is to iterate over sock_read() in order to
147: * consume all messages().
148: */
149: for (;;) {
150: if (!sock_read(f))
1.12 ratchov 151: return 0;
1.1 ratchov 152: }
153: return 1;
154: }
155:
156: void
157: rsock_eof(struct aproc *p, struct abuf *ibuf_dummy)
158: {
159: aproc_del(p);
160: }
161:
162: void
163: rsock_hup(struct aproc *p, struct abuf *ibuf)
164: {
165: aproc_del(p);
166: }
167:
168: void
169: rsock_opos(struct aproc *p, struct abuf *obuf, int delta)
170: {
171: struct sock *f = (struct sock *)p->u.io.file;
172:
1.42 ratchov 173: if (f->mode & AMSG_RECMASK)
1.14 ratchov 174: return;
175:
176: f->delta += delta;
1.37 ratchov 177: #ifdef DEBUG
178: if (debug_level >= 4) {
179: aproc_dbg(p);
180: dbg_puts(": moved to delta = ");
181: dbg_puti(f->delta);
182: dbg_puts("\n");
183: }
184: #endif
1.14 ratchov 185: f->tickpending++;
1.1 ratchov 186: for (;;) {
187: if (!sock_write(f))
188: break;
189: }
190: }
191:
192: struct aproc_ops rsock_ops = {
193: "rsock",
194: rsock_in,
195: rsock_out,
196: rsock_eof,
197: rsock_hup,
198: NULL, /* newin */
199: NULL, /* newout */
200: NULL, /* ipos */
201: rsock_opos,
202: rsock_done
203: };
204:
205: void
206: wsock_done(struct aproc *p)
207: {
208: struct sock *f = (struct sock *)p->u.io.file;
209:
1.11 ratchov 210: if (f == NULL)
211: return;
1.1 ratchov 212: sock_reset(f);
213: f->pipe.file.wproc = NULL;
214: if (f->pipe.file.rproc) {
1.34 ratchov 215: if (f->slot >= 0)
1.24 ratchov 216: ctl_slotdel(dev_midi, f->slot);
1.1 ratchov 217: aproc_del(f->pipe.file.rproc);
218: file_del(&f->pipe.file);
219: }
1.11 ratchov 220: p->u.io.file = NULL;
1.1 ratchov 221: }
222:
223: int
224: wsock_in(struct aproc *p, struct abuf *ibuf)
225: {
226: struct sock *f = (struct sock *)p->u.io.file;
227:
1.19 ratchov 228: if (f->pipe.file.state & FILE_WINUSE)
1.1 ratchov 229: return 0;
230: /*
1.20 ratchov 231: * See remark in rsock_out().
1.1 ratchov 232: */
233: for (;;) {
234: if (!sock_write(f))
235: return 0;
236: }
237: return 1;
238: }
239:
240: int
241: wsock_out(struct aproc *p, struct abuf *obuf_dummy)
242: {
1.45 ! ratchov 243: struct abuf *ibuf = LIST_FIRST(&p->ins);
1.1 ratchov 244: struct sock *f = (struct sock *)p->u.io.file;
245:
246: if (ibuf) {
247: if (!abuf_fill(ibuf))
248: return 0;
249: }
250: if (!sock_write(f))
251: return 0;
252: return 1;
253: }
254:
255: void
256: wsock_eof(struct aproc *p, struct abuf *obuf)
257: {
258: aproc_del(p);
259: }
260:
261: void
262: wsock_hup(struct aproc *p, struct abuf *obuf_dummy)
263: {
264: aproc_del(p);
265: }
266:
267: void
268: wsock_ipos(struct aproc *p, struct abuf *obuf, int delta)
269: {
270: struct sock *f = (struct sock *)p->u.io.file;
271:
1.42 ratchov 272: if (!(f->mode & AMSG_RECMASK))
1.14 ratchov 273: return;
1.1 ratchov 274:
1.14 ratchov 275: f->delta += delta;
1.37 ratchov 276: #ifdef DEBUG
277: if (debug_level >= 4) {
278: aproc_dbg(p);
279: dbg_puts(": moved to delta = ");
280: dbg_puti(f->delta);
281: dbg_puts("\n");
282: }
283: #endif
1.33 ratchov 284: f->tickpending++;
1.1 ratchov 285: for (;;) {
286: if (!sock_write(f))
287: break;
288: }
289: }
290:
291: struct aproc_ops wsock_ops = {
292: "wsock",
293: wsock_in,
294: wsock_out,
295: wsock_eof,
296: wsock_hup,
297: NULL, /* newin */
298: NULL, /* newout */
299: wsock_ipos,
300: NULL, /* opos */
301: wsock_done
302: };
303:
304: /*
1.20 ratchov 305: * Initialise socket in the SOCK_HELLO state with default
306: * parameters.
1.1 ratchov 307: */
308: struct sock *
1.19 ratchov 309: sock_new(struct fileops *ops, int fd)
1.1 ratchov 310: {
311: struct aproc *rproc, *wproc;
312: struct sock *f;
1.44 ratchov 313: uid_t uid, gid;
314:
315: /*
316: * ensure that all connections belong to the same user,
317: * for privacy reasons.
318: *
319: * XXX: is there a portable way of doing this ?
320: */
321: if (getpeereid(fd, &uid, &gid) < 0) {
322: close(fd);
323: return NULL;
324: }
325: if (sock_sesrefs == 0) {
326: /* start a new session */
327: sock_sesuid = uid;
328: } else if (uid != sock_sesuid) {
329: /* session owned by another user, drop connection */
330: close(fd);
331: return NULL;
332: }
333: sock_sesrefs++;
1.1 ratchov 334:
1.19 ratchov 335: f = (struct sock *)pipe_new(ops, fd, "sock");
1.13 ratchov 336: if (f == NULL)
337: return NULL;
1.18 ratchov 338: f->pstate = SOCK_HELLO;
1.1 ratchov 339: f->mode = 0;
1.19 ratchov 340: f->opt = opt_byname("default");
341: if (f->opt) {
1.42 ratchov 342: if (f->opt->mode & MODE_RECMASK)
1.19 ratchov 343: f->wpar = f->opt->wpar;
1.42 ratchov 344: if (f->opt->mode & MODE_PLAY)
1.19 ratchov 345: f->rpar = f->opt->rpar;
1.1 ratchov 346: }
347: f->xrun = AMSG_IGNORE;
1.10 ratchov 348: f->bufsz = dev_bufsz;
1.1 ratchov 349: f->round = dev_round;
1.14 ratchov 350: f->delta = 0;
351: f->tickpending = 0;
1.42 ratchov 352: f->startpending = 0;
1.25 ratchov 353: f->vol = f->lastvol = MIDI_MAXCTL;
1.24 ratchov 354: f->slot = -1;
1.1 ratchov 355:
1.19 ratchov 356: wproc = aproc_new(&wsock_ops, f->pipe.file.name);
1.1 ratchov 357: wproc->u.io.file = &f->pipe.file;
1.42 ratchov 358: wproc->u.io.partial = 0;
1.1 ratchov 359: f->pipe.file.wproc = wproc;
360: f->wstate = SOCK_WIDLE;
361: f->wtodo = 0xdeadbeef;
362:
1.19 ratchov 363: rproc = aproc_new(&rsock_ops, f->pipe.file.name);
1.1 ratchov 364: rproc->u.io.file = &f->pipe.file;
1.42 ratchov 365: rproc->u.io.partial = 0;
1.1 ratchov 366: f->pipe.file.rproc = rproc;
367: f->rstate = SOCK_RMSG;
368: f->rtodo = sizeof(struct amsg);
369: return f;
370: }
371:
372: /*
1.20 ratchov 373: * Free buffers.
1.1 ratchov 374: */
375: void
376: sock_freebuf(struct sock *f)
377: {
378: struct abuf *rbuf, *wbuf;
1.12 ratchov 379:
1.1 ratchov 380: f->pstate = SOCK_INIT;
1.37 ratchov 381: #ifdef DEBUG
382: if (debug_level >= 3) {
383: sock_dbg(f);
384: dbg_puts(": freeing buffers\n");
385: }
386: #endif
1.45 ! ratchov 387: wbuf = LIST_FIRST(&f->pipe.file.wproc->ins);
! 388: rbuf = LIST_FIRST(&f->pipe.file.rproc->outs);
1.35 ratchov 389: if (rbuf || wbuf)
390: ctl_slotstop(dev_midi, f->slot);
1.1 ratchov 391: if (rbuf)
392: abuf_eof(rbuf);
393: if (wbuf)
394: abuf_hup(wbuf);
1.32 ratchov 395: f->tickpending = 0;
1.42 ratchov 396: f->startpending = 0;
1.1 ratchov 397: }
398:
399: /*
1.20 ratchov 400: * Allocate buffers, so client can start filling write-end.
1.1 ratchov 401: */
402: void
403: sock_allocbuf(struct sock *f)
404: {
405: struct abuf *rbuf = NULL, *wbuf = NULL;
406:
1.42 ratchov 407: f->pstate = SOCK_START;
1.1 ratchov 408: if (f->mode & AMSG_PLAY) {
1.10 ratchov 409: rbuf = abuf_new(f->bufsz, &f->rpar);
1.1 ratchov 410: aproc_setout(f->pipe.file.rproc, rbuf);
1.42 ratchov 411: if (!ABUF_WOK(rbuf) || (f->pipe.file.state & FILE_EOF))
412: f->pstate = SOCK_READY;
1.1 ratchov 413: }
1.42 ratchov 414: if (f->mode & AMSG_RECMASK) {
1.10 ratchov 415: wbuf = abuf_new(f->bufsz, &f->wpar);
1.1 ratchov 416: aproc_setin(f->pipe.file.wproc, wbuf);
1.42 ratchov 417: f->walign = f->round;
1.1 ratchov 418: }
1.14 ratchov 419: f->delta = 0;
1.42 ratchov 420: f->wmax = 0;
421: f->rmax = f->bufsz;
1.14 ratchov 422: f->tickpending = 0;
1.42 ratchov 423: f->startpending = 0;
1.37 ratchov 424: #ifdef DEBUG
425: if (debug_level >= 3) {
426: sock_dbg(f);
427: dbg_puts(": allocating ");
428: dbg_putu(f->bufsz);
1.42 ratchov 429: dbg_puts(" fr buffers, rmax = ");
430: dbg_putu(f->rmax);
431: dbg_puts("\n");
1.37 ratchov 432: }
433: #endif
1.42 ratchov 434: if (f->mode & AMSG_PLAY) {
435: f->pstate = SOCK_START;
436: } else {
437: f->pstate = SOCK_READY;
438: if (ctl_slotstart(dev_midi, f->slot))
439: (void)sock_attach(f, 0);
440: }
1.1 ratchov 441: }
442:
443: /*
1.25 ratchov 444: * Set volume. Callback invoked when volume is modified externally
1.3 ratchov 445: */
446: void
1.25 ratchov 447: sock_setvol(void *arg, unsigned vol)
1.3 ratchov 448: {
1.25 ratchov 449: struct sock *f = (struct sock *)arg;
1.3 ratchov 450: struct abuf *rbuf;
1.12 ratchov 451:
1.3 ratchov 452: f->vol = vol;
1.45 ! ratchov 453: rbuf = LIST_FIRST(&f->pipe.file.rproc->outs);
1.3 ratchov 454: if (!rbuf) {
1.37 ratchov 455: #ifdef DEBUG
456: if (debug_level >= 3) {
457: sock_dbg(f);
458: dbg_puts(": no read buffer to set volume yet\n");
459: }
460: #endif
1.3 ratchov 461: return;
462: }
1.25 ratchov 463: dev_setvol(rbuf, MIDI_TO_ADATA(vol));
1.3 ratchov 464: }
465:
466: /*
1.35 ratchov 467: * Attach the stream. Callback invoked when MMC start
468: */
469: void
470: sock_startreq(void *arg)
471: {
472: struct sock *f = (struct sock *)arg;
473:
1.37 ratchov 474: #ifdef DEBUG
1.42 ratchov 475: if (f->pstate != SOCK_READY) {
1.37 ratchov 476: sock_dbg(f);
1.42 ratchov 477: dbg_puts(": not in READY state\n");
1.37 ratchov 478: dbg_panic();
479: }
480: #endif
1.35 ratchov 481: (void)sock_attach(f, 0);
482: }
483:
484: /*
1.42 ratchov 485: * Callback invoked by MMC stop
486: */
487: void
488: sock_stopreq(void *arg)
489: {
490: #ifdef DEBUG
491: struct sock *f = (struct sock *)arg;
492:
493: if (debug_level >= 3) {
494: sock_dbg(f);
495: dbg_puts(": ignored STOP signal\n");
496: }
497: #endif
498: }
499:
500: /*
501: * Callback invoked by MMC relocate, ignored
502: */
503: void
504: sock_locreq(void *arg, unsigned mmcpos)
505: {
506: #ifdef DEBUG
507: struct sock *f = (struct sock *)arg;
508:
509: if (debug_level >= 3) {
510: sock_dbg(f);
511: dbg_puts(": ignored RELOCATE signal\n");
512: }
513: #endif
514: }
515:
516: /*
1.20 ratchov 517: * Attach play and/or record buffers to dev_mix and/or dev_sub.
1.1 ratchov 518: */
1.42 ratchov 519: void
1.1 ratchov 520: sock_attach(struct sock *f, int force)
521: {
522: struct abuf *rbuf, *wbuf;
523:
1.45 ! ratchov 524: rbuf = LIST_FIRST(&f->pipe.file.rproc->outs);
! 525: wbuf = LIST_FIRST(&f->pipe.file.wproc->ins);
1.1 ratchov 526:
527: /*
1.20 ratchov 528: * If in SOCK_START state, dont attach until
529: * the buffer isn't completely filled.
1.1 ratchov 530: */
531: if (!force && rbuf && ABUF_WOK(rbuf))
1.42 ratchov 532: return;
1.12 ratchov 533:
1.42 ratchov 534: /*
535: * get the current position, the origin is when
536: * the first sample is played/recorded
537: */
538: f->delta = dev_getpos() * (int)f->round / (int)dev_round;
539: f->startpending = 1;
540: f->pstate = SOCK_RUN;
1.37 ratchov 541: #ifdef DEBUG
542: if (debug_level >= 3) {
543: sock_dbg(f);
1.42 ratchov 544: dbg_puts(": attaching at ");
545: dbg_puti(f->delta);
546: dbg_puts("\n");
1.37 ratchov 547: }
548: #endif
1.1 ratchov 549: /*
1.42 ratchov 550: * We dont check whether the device is dying,
551: * because dev_xxx() functions are supposed to
552: * work (i.e., not to crash)
1.1 ratchov 553: */
1.42 ratchov 554: dev_attach(f->pipe.file.name, f->mode,
1.43 ratchov 555: rbuf, &f->rpar,
556: f->opt->join ? f->opt->rpar.cmax - f->opt->rpar.cmin + 1 : 0,
557: wbuf, &f->wpar,
558: f->opt->join ? f->opt->wpar.cmax - f->opt->wpar.cmin + 1 : 0,
559: f->xrun, f->opt->maxweight);
1.3 ratchov 560: if (f->mode & AMSG_PLAY)
1.25 ratchov 561: dev_setvol(rbuf, MIDI_TO_ADATA(f->vol));
1.3 ratchov 562:
1.1 ratchov 563: /*
1.20 ratchov 564: * Send the initial position, if needed.
1.1 ratchov 565: */
566: for (;;) {
567: if (!sock_write(f))
568: break;
569: }
570: }
571:
572: void
573: sock_reset(struct sock *f)
574: {
575: switch (f->pstate) {
576: case SOCK_START:
1.42 ratchov 577: case SOCK_READY:
1.35 ratchov 578: if (ctl_slotstart(dev_midi, f->slot)) {
579: (void)sock_attach(f, 1);
580: f->pstate = SOCK_RUN;
581: }
1.1 ratchov 582: /* PASSTHROUGH */
583: case SOCK_RUN:
584: sock_freebuf(f);
585: f->pstate = SOCK_INIT;
586: /* PASSTHROUGH */
587: case SOCK_INIT:
588: /* nothing yet */
589: break;
590: }
591: }
592:
593: /*
1.20 ratchov 594: * Read a message from the file descriptor, return 1 if done, 0
595: * otherwise. The message is stored in f->rmsg.
1.1 ratchov 596: */
597: int
598: sock_rmsg(struct sock *f)
599: {
600: unsigned count;
601: unsigned char *data;
602:
603: while (f->rtodo > 0) {
604: if (!(f->pipe.file.state & FILE_ROK)) {
1.37 ratchov 605: #ifdef DEBUG
606: if (debug_level >= 4) {
607: sock_dbg(f);
608: dbg_puts(": reading message blocked, ");
609: dbg_putu(f->rtodo);
610: dbg_puts(" bytes remaining\n");
611: }
612: #endif
1.1 ratchov 613: return 0;
614: }
615: data = (unsigned char *)&f->rmsg;
616: data += sizeof(struct amsg) - f->rtodo;
617: count = file_read(&f->pipe.file, data, f->rtodo);
618: if (count == 0)
619: return 0;
620: f->rtodo -= count;
621: }
1.37 ratchov 622: #ifdef DEBUG
623: if (debug_level >= 4) {
624: sock_dbg(f);
625: dbg_puts(": read full message\n");
626: }
627: #endif
1.1 ratchov 628: return 1;
629: }
630:
631: /*
1.20 ratchov 632: * Write a message to the file descriptor, return 1 if done, 0
1.1 ratchov 633: * otherwise. The "m" argument is f->rmsg or f->wmsg, and the "ptodo"
634: * points to the f->rtodo or f->wtodo respectively.
635: */
636: int
637: sock_wmsg(struct sock *f, struct amsg *m, unsigned *ptodo)
638: {
639: unsigned count;
640: unsigned char *data;
641:
642: while (*ptodo > 0) {
643: if (!(f->pipe.file.state & FILE_WOK)) {
1.37 ratchov 644: #ifdef DEBUG
645: if (debug_level >= 4) {
646: sock_dbg(f);
647: dbg_puts(": writing message blocked, ");
648: dbg_putu(*ptodo);
649: dbg_puts(" bytes remaining\n");
650: }
651: #endif
1.1 ratchov 652: return 0;
653: }
654: data = (unsigned char *)m;
655: data += sizeof(struct amsg) - *ptodo;
656: count = file_write(&f->pipe.file, data, *ptodo);
657: if (count == 0)
658: return 0;
659: *ptodo -= count;
660: }
1.37 ratchov 661: #ifdef DEBUG
662: if (debug_level >= 4) {
663: sock_dbg(f);
664: dbg_puts(": wrote full message\n");
665: }
666: #endif
1.1 ratchov 667: return 1;
668: }
669:
670: /*
1.20 ratchov 671: * Read data chunk from the file descriptor, return 1 if at least one
1.1 ratchov 672: * byte was read, 0 if the file blocked.
673: */
674: int
675: sock_rdata(struct sock *f)
676: {
677: struct aproc *p;
678: struct abuf *obuf;
1.42 ratchov 679: unsigned n;
1.1 ratchov 680:
1.37 ratchov 681: #ifdef DEBUG
682: if (f->pstate != SOCK_MIDI && f->rtodo == 0) {
683: sock_dbg(f);
684: dbg_puts(": data block already read\n");
685: dbg_panic();
686: }
687: #endif
1.1 ratchov 688: p = f->pipe.file.rproc;
1.45 ! ratchov 689: obuf = LIST_FIRST(&p->outs);
1.19 ratchov 690: if (obuf == NULL)
691: return 0;
1.42 ratchov 692: if (!ABUF_WOK(obuf) || !(f->pipe.file.state & FILE_ROK))
1.41 ratchov 693: return 0;
1.42 ratchov 694: if (f->pstate == SOCK_MIDI) {
695: if (!rfile_do(p, obuf->len, NULL))
696: return 0;
697: } else {
698: if (!rfile_do(p, f->rtodo, &n))
699: return 0;
1.19 ratchov 700: f->rtodo -= n;
1.42 ratchov 701: if (f->pstate == SOCK_START) {
702: if (!ABUF_WOK(obuf) || (f->pipe.file.state & FILE_EOF))
703: f->pstate = SOCK_READY;
704: }
705: }
1.1 ratchov 706: return 1;
707: }
708:
709: /*
1.20 ratchov 710: * Write data chunk to the file descriptor, return 1 if at least one
1.1 ratchov 711: * byte was written, 0 if the file blocked.
712: */
713: int
714: sock_wdata(struct sock *f)
715: {
716: struct aproc *p;
717: struct abuf *ibuf;
1.42 ratchov 718: unsigned n;
1.1 ratchov 719:
1.37 ratchov 720: #ifdef DEBUG
721: if (f->pstate != SOCK_MIDI && f->wtodo == 0) {
722: sock_dbg(f);
723: dbg_puts(": attempted to write zero-sized data block\n");
724: dbg_panic();
725: }
726: #endif
1.1 ratchov 727: if (!(f->pipe.file.state & FILE_WOK))
728: return 0;
729: p = f->pipe.file.wproc;
1.45 ! ratchov 730: ibuf = LIST_FIRST(&p->ins);
1.42 ratchov 731: #ifdef DEBUG
732: if (f->pstate != SOCK_MIDI && ibuf == NULL) {
733: sock_dbg(f);
734: dbg_puts(": attempted to write on detached buffer\n");
735: dbg_panic();
736: }
737: #endif
738: if (ibuf == NULL)
739: return 0;
740: if (!ABUF_ROK(ibuf))
741: return 0;
742: if (f->pstate == SOCK_MIDI) {
743: if (!wfile_do(p, ibuf->len, NULL))
1.1 ratchov 744: return 0;
745: } else {
1.42 ratchov 746: if (!wfile_do(p, f->wtodo, &n))
1.1 ratchov 747: return 0;
748: f->wtodo -= n;
1.12 ratchov 749: }
1.1 ratchov 750: return 1;
751: }
752:
753: int
754: sock_setpar(struct sock *f)
755: {
756: struct amsg_par *p = &f->rmsg.u.par;
1.9 ratchov 757: unsigned min, max, rate;
1.12 ratchov 758:
1.1 ratchov 759: if (AMSG_ISSET(p->bits)) {
760: if (p->bits < BITS_MIN || p->bits > BITS_MAX) {
1.37 ratchov 761: #ifdef DEBUG
762: if (debug_level >= 1) {
763: sock_dbg(f);
764: dbg_puts(": ");
765: dbg_putu(p->bits);
766: dbg_puts(": bits out of bounds\n");
767: }
768: #endif
1.1 ratchov 769: return 0;
770: }
771: if (AMSG_ISSET(p->bps)) {
772: if (p->bps < ((p->bits + 7) / 8) || p->bps > 4) {
1.37 ratchov 773: #ifdef DEBUG
774: if (debug_level >= 1) {
775: sock_dbg(f);
776: dbg_puts(": ");
777: dbg_putu(p->bps);
778: dbg_puts(": wrong bytes per sample\n");
779: }
780: #endif
1.1 ratchov 781: return 0;
782: }
783: } else
784: p->bps = APARAMS_BPS(p->bits);
785: f->rpar.bits = f->wpar.bits = p->bits;
786: f->rpar.bps = f->wpar.bps = p->bps;
1.37 ratchov 787: #ifdef DEBUG
788: if (debug_level >= 3) {
789: sock_dbg(f);
790: dbg_puts(": using ");
791: dbg_putu(p->bits);
792: dbg_puts("bits, ");
793: dbg_putu(p->bps);
794: dbg_puts(" bytes per sample\n");
795: }
796: #endif
1.1 ratchov 797: }
798: if (AMSG_ISSET(p->sig))
799: f->rpar.sig = f->wpar.sig = p->sig ? 1 : 0;
800: if (AMSG_ISSET(p->le))
801: f->rpar.le = f->wpar.le = p->le ? 1 : 0;
802: if (AMSG_ISSET(p->msb))
803: f->rpar.msb = f->wpar.msb = p->msb ? 1 : 0;
1.42 ratchov 804: if (AMSG_ISSET(p->rchan) && (f->mode & AMSG_RECMASK)) {
1.1 ratchov 805: if (p->rchan < 1)
806: p->rchan = 1;
1.6 ratchov 807: if (p->rchan > NCHAN_MAX)
808: p->rchan = NCHAN_MAX;
1.19 ratchov 809: f->wpar.cmin = f->opt->wpar.cmin;
810: f->wpar.cmax = f->opt->wpar.cmin + p->rchan - 1;
811: if (f->wpar.cmax > f->opt->wpar.cmax)
812: f->wpar.cmax = f->opt->wpar.cmax;
1.37 ratchov 813: #ifdef DEBUG
814: if (debug_level >= 3) {
815: sock_dbg(f);
816: dbg_puts(": using recording channels ");
817: dbg_putu(f->wpar.cmin);
818: dbg_puts("..");
819: dbg_putu(f->wpar.cmax);
820: dbg_puts("\n");
821: }
822: #endif
1.1 ratchov 823: }
824: if (AMSG_ISSET(p->pchan) && (f->mode & AMSG_PLAY)) {
825: if (p->pchan < 1)
826: p->pchan = 1;
1.6 ratchov 827: if (p->pchan > NCHAN_MAX)
828: p->pchan = NCHAN_MAX;
1.19 ratchov 829: f->rpar.cmin = f->opt->rpar.cmin;
830: f->rpar.cmax = f->opt->rpar.cmin + p->pchan - 1;
831: if (f->rpar.cmax > f->opt->rpar.cmax)
832: f->rpar.cmax = f->opt->rpar.cmax;
1.37 ratchov 833: #ifdef DEBUG
834: if (debug_level >= 3) {
835: sock_dbg(f);
836: dbg_puts(": using playback channels ");
837: dbg_putu(f->rpar.cmin);
838: dbg_puts("..");
839: dbg_putu(f->rpar.cmax);
840: dbg_puts("\n");
841: }
842: #endif
1.1 ratchov 843: }
844: if (AMSG_ISSET(p->rate)) {
845: if (p->rate < RATE_MIN)
846: p->rate = RATE_MIN;
847: if (p->rate > RATE_MAX)
848: p->rate = RATE_MAX;
1.9 ratchov 849: f->round = dev_roundof(p->rate);
1.1 ratchov 850: f->rpar.rate = f->wpar.rate = p->rate;
1.10 ratchov 851: if (!AMSG_ISSET(p->appbufsz)) {
852: p->appbufsz = dev_bufsz / dev_round * f->round;
1.37 ratchov 853: #ifdef DEBUG
854: if (debug_level >= 3) {
855: sock_dbg(f);
856: dbg_puts(": using ");
857: dbg_putu(p->appbufsz);
858: dbg_puts(" fr app buffer size\n");
859: }
860: #endif
861: }
862: #ifdef DEBUG
863: if (debug_level >= 3) {
864: sock_dbg(f);
865: dbg_puts(": using ");
866: dbg_putu(p->rate);
867: dbg_puts("Hz sample rate, ");
868: dbg_putu(f->round);
869: dbg_puts(" fr block size\n");
1.10 ratchov 870: }
1.37 ratchov 871: #endif
1.1 ratchov 872: }
873: if (AMSG_ISSET(p->xrun)) {
874: if (p->xrun != AMSG_IGNORE &&
875: p->xrun != AMSG_SYNC &&
876: p->xrun != AMSG_ERROR) {
1.37 ratchov 877: #ifdef DEBUG
878: if (debug_level >= 1) {
879: sock_dbg(f);
880: dbg_puts(": ");
881: dbg_putx(p->xrun);
882: dbg_puts(": bad xrun policy\n");
883: }
884: #endif
1.1 ratchov 885: return 0;
886: }
887: f->xrun = p->xrun;
1.35 ratchov 888: if (f->opt->mmc && f->xrun == AMSG_IGNORE)
889: f->xrun = AMSG_SYNC;
1.37 ratchov 890: #ifdef DEBUG
891: if (debug_level >= 3) {
892: sock_dbg(f);
893: dbg_puts(": using 0x");
894: dbg_putx(f->xrun);
895: dbg_puts(" xrun policy\n");
896: }
897: #endif
1.1 ratchov 898: }
899: if (AMSG_ISSET(p->bufsz)) {
1.10 ratchov 900: /*
901: * XXX: bufsz will become read-only, but for now
902: * allow old library to properly work
903: */
1.37 ratchov 904: #ifdef DEBUG
905: if (debug_level >= 1) {
906: sock_dbg(f);
907: dbg_puts(": legacy client using ");
908: dbg_putx(p->bufsz);
909: dbg_puts("fr total buffer size\n");
910: }
911: #endif
1.10 ratchov 912: min = (dev_bufsz / dev_round) * f->round;
913: if (p->bufsz < min)
914: p->bufsz = min;
915: p->appbufsz = p->bufsz - min;
916: }
917: if (AMSG_ISSET(p->appbufsz)) {
1.9 ratchov 918: rate = (f->mode & AMSG_PLAY) ? f->rpar.rate : f->wpar.rate;
1.42 ratchov 919: min = 1;
920: max = 1 + rate / dev_round;
1.9 ratchov 921: min *= f->round;
922: max *= f->round;
1.10 ratchov 923: p->appbufsz += f->round - 1;
924: p->appbufsz -= p->appbufsz % f->round;
925: if (p->appbufsz < min)
926: p->appbufsz = min;
927: if (p->appbufsz > max)
928: p->appbufsz = max;
929: f->bufsz = p->appbufsz;
1.37 ratchov 930: #ifdef DEBUG
931: if (debug_level >= 3) {
932: sock_dbg(f);
933: dbg_puts(": using ");
934: dbg_putu(f->bufsz);
935: dbg_puts(" buffer size\n");
936: }
937: #endif
938: }
939: #ifdef DEBUG
940: if (debug_level >= 2) {
1.42 ratchov 941: if (f->slot >= 0 && dev_midi) {
1.37 ratchov 942: dbg_puts(dev_midi->u.ctl.slot[f->slot].name);
943: dbg_putu(dev_midi->u.ctl.slot[f->slot].unit);
944: } else
945: dbg_puts(f->pipe.file.name);
946: dbg_puts(": buffer size = ");
947: dbg_putu(f->bufsz);
948: if (f->mode & AMSG_PLAY) {
949: dbg_puts(", play = ");
950: aparams_dbg(&f->rpar);
951: }
1.42 ratchov 952: if (f->mode & AMSG_RECMASK) {
1.37 ratchov 953: dbg_puts(", rec:");
954: aparams_dbg(&f->wpar);
955: }
956: dbg_puts("\n");
1.1 ratchov 957: }
1.37 ratchov 958: #endif
1.1 ratchov 959: return 1;
960: }
961:
1.19 ratchov 962: /*
963: * allocate buffers, so client can start filling write-end.
964: */
965: void
966: sock_midiattach(struct sock *f, unsigned mode)
967: {
968: struct abuf *rbuf = NULL, *wbuf = NULL;
969:
970: if (mode & AMSG_MIDIOUT) {
1.22 ratchov 971: rbuf = abuf_new(MIDI_BUFSZ, &aparams_none);
1.19 ratchov 972: aproc_setout(f->pipe.file.rproc, rbuf);
973: }
974: if (mode & AMSG_MIDIIN) {
1.22 ratchov 975: wbuf = abuf_new(MIDI_BUFSZ, &aparams_none);
1.19 ratchov 976: aproc_setin(f->pipe.file.wproc, wbuf);
977: }
1.23 ratchov 978: dev_midiattach(rbuf, wbuf);
1.19 ratchov 979: }
980:
1.17 ratchov 981: int
982: sock_hello(struct sock *f)
983: {
984: struct amsg_hello *p = &f->rmsg.u.hello;
985:
1.37 ratchov 986: #ifdef DEBUG
987: if (debug_level >= 3) {
988: sock_dbg(f);
989: dbg_puts(": hello from <");
990: dbg_puts(p->who);
991: dbg_puts(">, proto = ");
992: dbg_putx(p->proto);
993: dbg_puts(", ver ");
994: dbg_putu(p->version);
995: dbg_puts("\n");
996: }
997: #endif
1.33 ratchov 998: if (p->version != AMSG_VERSION) {
1.37 ratchov 999: #ifdef DEBUG
1000: if (debug_level >= 1) {
1001: sock_dbg(f);
1002: dbg_puts(": ");
1003: dbg_putu(p->version);
1004: dbg_puts(": bad version\n");
1005: }
1006: #endif
1.33 ratchov 1007: return 0;
1008: }
1009: /*
1010: * XXX : dev_midi can no longer be NULL, right ?
1011: */
1.42 ratchov 1012: if (APROC_OK(dev_midi) && (p->proto & (AMSG_MIDIIN | AMSG_MIDIOUT))) {
1.19 ratchov 1013: if (p->proto & ~(AMSG_MIDIIN | AMSG_MIDIOUT)) {
1.37 ratchov 1014: #ifdef DEBUG
1015: if (debug_level >= 1) {
1016: sock_dbg(f);
1017: dbg_puts(": ");
1018: dbg_putx(p->proto);
1019: dbg_puts(": bad hello protocol\n");
1020: }
1021: #endif
1.19 ratchov 1022: return 0;
1023: }
1024: f->mode = p->proto;
1025: f->pstate = SOCK_MIDI;
1026: sock_midiattach(f, p->proto);
1027: return 1;
1028: }
1029: f->opt = opt_byname(p->opt);
1030: if (f->opt == NULL)
1031: return 0;
1.42 ratchov 1032: if (f->opt->mode & MODE_RECMASK)
1.19 ratchov 1033: f->wpar = f->opt->wpar;
1.42 ratchov 1034: if (f->opt->mode & MODE_PLAY)
1.19 ratchov 1035: f->rpar = f->opt->rpar;
1.35 ratchov 1036: if (f->opt->mmc)
1037: f->xrun = AMSG_SYNC;
1.18 ratchov 1038: if ((p->proto & ~(AMSG_PLAY | AMSG_REC)) != 0 ||
1039: (p->proto & (AMSG_PLAY | AMSG_REC)) == 0) {
1.37 ratchov 1040: #ifdef DEBUG
1041: if (debug_level >= 1) {
1042: sock_dbg(f);
1043: dbg_puts(": ");
1044: dbg_putx(p->proto);
1045: dbg_puts(": unsupported hello protocol\n");
1046: }
1047: #endif
1.17 ratchov 1048: return 0;
1049: }
1.18 ratchov 1050: f->mode = 0;
1051: if (p->proto & AMSG_PLAY) {
1.42 ratchov 1052: if (!APROC_OK(dev_mix) || !(f->opt->mode & MODE_PLAY)) {
1.37 ratchov 1053: #ifdef DEBUG
1054: if (debug_level >= 1) {
1055: sock_dbg(f);
1056: dbg_puts(": playback not available\n");
1057: }
1058: #endif
1.18 ratchov 1059: return 0;
1060: }
1061: f->mode |= AMSG_PLAY;
1.17 ratchov 1062: }
1.18 ratchov 1063: if (p->proto & AMSG_REC) {
1.42 ratchov 1064: if (!(APROC_OK(dev_sub) && (f->opt->mode & MODE_REC)) &&
1065: !(APROC_OK(dev_submon) && (f->opt->mode & MODE_MON))) {
1.37 ratchov 1066: #ifdef DEBUG
1067: if (debug_level >= 1) {
1068: sock_dbg(f);
1069: dbg_puts(": recording not available\n");
1070: }
1071: #endif
1.18 ratchov 1072: return 0;
1073: }
1.42 ratchov 1074: f->mode |= (f->opt->mode & MODE_MON) ? AMSG_MON : AMSG_REC;
1.17 ratchov 1075: }
1.42 ratchov 1076: if (APROC_OK(dev_midi)) {
1.35 ratchov 1077: f->slot = ctl_slotnew(dev_midi,
1078: p->who, &ctl_sockops, f,
1079: f->opt->mmc);
1.24 ratchov 1080: if (f->slot < 0) {
1.37 ratchov 1081: #ifdef DEBUG
1082: if (debug_level >= 1) {
1083: sock_dbg(f);
1084: dbg_puts(": out of mixer slots\n");
1085: }
1086: #endif
1.24 ratchov 1087: return 0;
1088: }
1089: }
1.18 ratchov 1090: f->pstate = SOCK_INIT;
1.17 ratchov 1091: return 1;
1092: }
1093:
1.1 ratchov 1094: /*
1.20 ratchov 1095: * Execute message in f->rmsg and change the state accordingly; return 1
1.1 ratchov 1096: * on success, and 0 on failure, in which case the socket is destroyed.
1097: */
1098: int
1099: sock_execmsg(struct sock *f)
1100: {
1101: struct amsg *m = &f->rmsg;
1.42 ratchov 1102: struct abuf *obuf;
1.1 ratchov 1103:
1104: switch (m->cmd) {
1105: case AMSG_DATA:
1.37 ratchov 1106: #ifdef DEBUG
1107: if (debug_level >= 4) {
1108: sock_dbg(f);
1109: dbg_puts(": DATA message\n");
1110: }
1111: #endif
1.42 ratchov 1112: if (f->pstate != SOCK_RUN && f->pstate != SOCK_START &&
1113: f->pstate != SOCK_READY) {
1.37 ratchov 1114: #ifdef DEBUG
1115: if (debug_level >= 1) {
1116: sock_dbg(f);
1117: dbg_puts(": DATA, bad state\n");
1118: }
1119: #endif
1.8 ratchov 1120: aproc_del(f->pipe.file.rproc);
1121: return 0;
1122: }
1123: if (!(f->mode & AMSG_PLAY)) {
1.37 ratchov 1124: #ifdef DEBUG
1125: if (debug_level >= 1) {
1126: sock_dbg(f);
1127: dbg_puts(": DATA not allowed in record-only mode\n");
1128: }
1129: #endif
1.1 ratchov 1130: aproc_del(f->pipe.file.rproc);
1131: return 0;
1132: }
1.45 ! ratchov 1133: obuf = LIST_FIRST(&f->pipe.file.rproc->outs);
1.42 ratchov 1134: if (f->pstate == SOCK_START && !ABUF_WOK(obuf)) {
1.37 ratchov 1135: #ifdef DEBUG
1136: if (debug_level >= 1) {
1137: sock_dbg(f);
1138: dbg_puts(": DATA client violates flow control\n");
1139: }
1140: #endif
1.34 ratchov 1141: aproc_del(f->pipe.file.rproc);
1142: return 0;
1143: }
1.42 ratchov 1144: if (m->u.data.size % obuf->bpf != 0) {
1145: #ifdef DEBUG
1146: if (debug_level >= 1) {
1147: sock_dbg(f);
1148: dbg_puts(": unaligned data chunk\n");
1149: }
1150: #endif
1151: aproc_del(f->pipe.file.rproc);
1152: return 0;
1153: }
1.1 ratchov 1154: f->rstate = SOCK_RDATA;
1.42 ratchov 1155: f->rtodo = m->u.data.size / obuf->bpf;
1156: #ifdef DEBUG
1157: if (f->rtodo > f->rmax && debug_level >= 2) {
1158: sock_dbg(f);
1159: dbg_puts(": received past current position, rtodo = ");
1160: dbg_putu(f->rtodo);
1161: dbg_puts(", rmax = ");
1162: dbg_putu(f->rmax);
1163: dbg_puts("\n");
1164: aproc_del(f->pipe.file.rproc);
1165: return 0;
1166: }
1167: #endif
1168: f->rmax -= f->rtodo;
1.1 ratchov 1169: if (f->rtodo == 0) {
1.37 ratchov 1170: #ifdef DEBUG
1171: if (debug_level >= 1) {
1172: sock_dbg(f);
1173: dbg_puts(": zero-length data chunk\n");
1174: }
1175: #endif
1.1 ratchov 1176: aproc_del(f->pipe.file.rproc);
1177: return 0;
1178: }
1179: break;
1180: case AMSG_START:
1.37 ratchov 1181: #ifdef DEBUG
1182: if (debug_level >= 3) {
1183: sock_dbg(f);
1184: dbg_puts(": START message\n");
1185: }
1186: #endif
1.1 ratchov 1187: if (f->pstate != SOCK_INIT) {
1.37 ratchov 1188: #ifdef DEBUG
1189: if (debug_level >= 1) {
1190: sock_dbg(f);
1191: dbg_puts(": START, bad state\n");
1192: }
1193: #endif
1.1 ratchov 1194: aproc_del(f->pipe.file.rproc);
1195: return 0;
1196: }
1197: sock_allocbuf(f);
1198: f->rstate = SOCK_RMSG;
1199: f->rtodo = sizeof(struct amsg);
1200: break;
1201: case AMSG_STOP:
1.37 ratchov 1202: #ifdef DEBUG
1203: if (debug_level >= 3) {
1204: sock_dbg(f);
1205: dbg_puts(": STOP message\n");
1206: }
1207: #endif
1.42 ratchov 1208: if (f->pstate != SOCK_RUN &&
1209: f->pstate != SOCK_START && f->pstate != SOCK_READY) {
1.37 ratchov 1210: #ifdef DEBUG
1211: if (debug_level >= 1) {
1212: sock_dbg(f);
1213: dbg_puts(": STOP, bad state\n");
1214: }
1215: #endif
1.1 ratchov 1216: aproc_del(f->pipe.file.rproc);
1217: return 0;
1.42 ratchov 1218: /*
1219: * XXX: device could have desappeared at this point,
1220: * see how this is fixed in wav.c
1221: */
1.1 ratchov 1222: }
1.42 ratchov 1223: if ((f->pstate == SOCK_START || f->pstate == SOCK_READY) &&
1.35 ratchov 1224: ctl_slotstart(dev_midi, f->slot))
1.1 ratchov 1225: (void)sock_attach(f, 1);
1.42 ratchov 1226: if (f->wstate != SOCK_WDATA || f->wtodo == 0)
1227: sock_freebuf(f);
1228: else
1229: f->pstate = SOCK_STOP;
1.1 ratchov 1230: AMSG_INIT(m);
1231: m->cmd = AMSG_ACK;
1232: f->rstate = SOCK_RRET;
1233: f->rtodo = sizeof(struct amsg);
1234: break;
1235: case AMSG_SETPAR:
1.37 ratchov 1236: #ifdef DEBUG
1237: if (debug_level >= 3) {
1238: sock_dbg(f);
1239: dbg_puts(": SETPAR message\n");
1240: }
1241: #endif
1.1 ratchov 1242: if (f->pstate != SOCK_INIT) {
1.37 ratchov 1243: #ifdef DEBUG
1244: if (debug_level >= 1) {
1245: sock_dbg(f);
1246: dbg_puts(": SETPAR, bad state\n");
1247: }
1248: #endif
1.1 ratchov 1249: aproc_del(f->pipe.file.rproc);
1250: return 0;
1251: }
1252: if (!sock_setpar(f)) {
1253: aproc_del(f->pipe.file.rproc);
1254: return 0;
1255: }
1256: f->rtodo = sizeof(struct amsg);
1257: f->rstate = SOCK_RMSG;
1258: break;
1259: case AMSG_GETPAR:
1.37 ratchov 1260: #ifdef DEBUG
1261: if (debug_level >= 3) {
1262: sock_dbg(f);
1263: dbg_puts(": GETPAR message\n");
1264: }
1265: #endif
1.1 ratchov 1266: if (f->pstate != SOCK_INIT) {
1.37 ratchov 1267: #ifdef DEBUG
1268: if (debug_level >= 1) {
1269: sock_dbg(f);
1270: dbg_puts(": GETPAR, bad state\n");
1271: }
1272: #endif
1.1 ratchov 1273: aproc_del(f->pipe.file.rproc);
1274: return 0;
1275: }
1276: AMSG_INIT(m);
1277: m->cmd = AMSG_GETPAR;
1.18 ratchov 1278: m->u.par.legacy_mode = f->mode;
1.42 ratchov 1279: if (f->mode & AMSG_PLAY) {
1280: m->u.par.bits = f->rpar.bits;
1281: m->u.par.bps = f->rpar.bps;
1282: m->u.par.sig = f->rpar.sig;
1283: m->u.par.le = f->rpar.le;
1284: m->u.par.msb = f->rpar.msb;
1285: m->u.par.rate = f->rpar.rate;
1286: m->u.par.pchan = f->rpar.cmax - f->rpar.cmin + 1;
1287: }
1288: if (f->mode & AMSG_RECMASK) {
1289: m->u.par.bits = f->wpar.bits;
1290: m->u.par.bps = f->wpar.bps;
1291: m->u.par.sig = f->wpar.sig;
1292: m->u.par.le = f->wpar.le;
1293: m->u.par.msb = f->wpar.msb;
1294: m->u.par.rate = f->wpar.rate;
1295: m->u.par.rchan = f->wpar.cmax - f->wpar.cmin + 1;
1296: }
1.10 ratchov 1297: m->u.par.appbufsz = f->bufsz;
1.12 ratchov 1298: m->u.par.bufsz =
1.10 ratchov 1299: f->bufsz + (dev_bufsz / dev_round) * f->round;
1.1 ratchov 1300: m->u.par.round = f->round;
1301: f->rstate = SOCK_RRET;
1302: f->rtodo = sizeof(struct amsg);
1303: break;
1304: case AMSG_GETCAP:
1.37 ratchov 1305: #ifdef DEBUG
1306: if (debug_level >= 3) {
1307: sock_dbg(f);
1308: dbg_puts(": GETCAP message\n");
1309: }
1310: #endif
1.1 ratchov 1311: if (f->pstate != SOCK_INIT) {
1.37 ratchov 1312: #ifdef DEBUG
1313: if (debug_level >= 1) {
1314: sock_dbg(f);
1315: dbg_puts(": GETCAP, bad state\n");
1316: }
1317: #endif
1.1 ratchov 1318: aproc_del(f->pipe.file.rproc);
1319: return 0;
1320: }
1321: AMSG_INIT(m);
1322: m->cmd = AMSG_GETCAP;
1323: m->u.cap.rate = dev_rate;
1.42 ratchov 1324: m->u.cap.pchan = (f->opt->mode & MODE_PLAY) ?
1.19 ratchov 1325: (f->opt->rpar.cmax - f->opt->rpar.cmin + 1) : 0;
1.42 ratchov 1326: m->u.cap.rchan = (f->opt->mode & (MODE_PLAY | MODE_REC)) ?
1.19 ratchov 1327: (f->opt->wpar.cmax - f->opt->wpar.cmin + 1) : 0;
1.1 ratchov 1328: m->u.cap.bits = sizeof(short) * 8;
1329: m->u.cap.bps = sizeof(short);
1330: f->rstate = SOCK_RRET;
1331: f->rtodo = sizeof(struct amsg);
1.3 ratchov 1332: break;
1333: case AMSG_SETVOL:
1.37 ratchov 1334: #ifdef DEBUG
1335: if (debug_level >= 3) {
1336: sock_dbg(f);
1337: dbg_puts(": SETVOL message\n");
1338: }
1339: #endif
1.42 ratchov 1340: if (f->pstate != SOCK_RUN && f->pstate != SOCK_START &&
1341: f->pstate != SOCK_INIT && f->pstate != SOCK_READY) {
1.37 ratchov 1342: #ifdef DEBUG
1343: if (debug_level >= 1) {
1344: sock_dbg(f);
1345: dbg_puts(": SETVOL, bad state\n");
1346: }
1347: #endif
1.3 ratchov 1348: aproc_del(f->pipe.file.rproc);
1349: return 0;
1350: }
1351: if (m->u.vol.ctl > MIDI_MAXCTL) {
1.37 ratchov 1352: #ifdef DEBUG
1353: if (debug_level >= 1) {
1354: sock_dbg(f);
1355: dbg_puts(": SETVOL, volume out of range\n");
1356: }
1357: #endif
1.3 ratchov 1358: aproc_del(f->pipe.file.rproc);
1359: return 0;
1360: }
1.25 ratchov 1361: sock_setvol(f, m->u.vol.ctl);
1.34 ratchov 1362: if (f->slot >= 0)
1.24 ratchov 1363: ctl_slotvol(dev_midi, f->slot, m->u.vol.ctl);
1.3 ratchov 1364: f->rtodo = sizeof(struct amsg);
1365: f->rstate = SOCK_RMSG;
1.17 ratchov 1366: break;
1367: case AMSG_HELLO:
1.37 ratchov 1368: #ifdef DEBUG
1369: if (debug_level >= 3) {
1370: sock_dbg(f);
1371: dbg_puts(": HELLO message\n");
1372: }
1373: #endif
1.18 ratchov 1374: if (f->pstate != SOCK_HELLO) {
1.37 ratchov 1375: #ifdef DEBUG
1376: if (debug_level >= 1) {
1377: sock_dbg(f);
1378: dbg_puts(": HELLO, bad state\n");
1379: }
1380: #endif
1.17 ratchov 1381: aproc_del(f->pipe.file.rproc);
1382: return 0;
1383: }
1384: if (!sock_hello(f)) {
1385: aproc_del(f->pipe.file.rproc);
1386: return 0;
1387: }
1388: AMSG_INIT(m);
1389: m->cmd = AMSG_ACK;
1390: f->rstate = SOCK_RRET;
1391: f->rtodo = sizeof(struct amsg);
1.1 ratchov 1392: break;
1.28 ratchov 1393: case AMSG_BYE:
1.37 ratchov 1394: #ifdef DEBUG
1395: if (debug_level >= 3) {
1396: sock_dbg(f);
1397: dbg_puts(": BYE message\n");
1398: }
1399: #endif
1.29 ratchov 1400: if (f->pstate != SOCK_INIT) {
1.37 ratchov 1401: #ifdef DEBUG
1402: if (debug_level >= 1) {
1403: sock_dbg(f);
1404: dbg_puts(": BYE, bad state\n");
1405: }
1406: #endif
1.29 ratchov 1407: }
1.28 ratchov 1408: aproc_del(f->pipe.file.rproc);
1409: return 0;
1.1 ratchov 1410: default:
1.37 ratchov 1411: #ifdef DEBUG
1412: if (debug_level >= 1) {
1413: sock_dbg(f);
1414: dbg_puts(": unknown command in message\n");
1415: }
1416: #endif
1.1 ratchov 1417: aproc_del(f->pipe.file.rproc);
1418: return 0;
1419: }
1420: if (f->rstate == SOCK_RRET) {
1421: if (f->wstate != SOCK_WIDLE ||
1422: !sock_wmsg(f, &f->rmsg, &f->rtodo))
1423: return 0;
1.37 ratchov 1424: #ifdef DEBUG
1425: if (debug_level >= 3) {
1426: sock_dbg(f);
1427: dbg_puts(": RRET done\n");
1428: }
1429: #endif
1.19 ratchov 1430: if (f->pstate == SOCK_MIDI && (f->mode & AMSG_MIDIOUT)) {
1431: f->rstate = SOCK_RDATA;
1432: f->rtodo = 0;
1433: } else {
1434: f->rstate = SOCK_RMSG;
1435: f->rtodo = sizeof(struct amsg);
1436: }
1.1 ratchov 1437: }
1438: return 1;
1439: }
1440:
1441: /*
1.20 ratchov 1442: * Create a new data/pos message.
1.1 ratchov 1443: */
1444: int
1445: sock_buildmsg(struct sock *f)
1446: {
1447: struct aproc *p;
1448: struct abuf *ibuf;
1.42 ratchov 1449: unsigned size, max;
1.12 ratchov 1450:
1.19 ratchov 1451: if (f->pstate == SOCK_MIDI) {
1.37 ratchov 1452: #ifdef DEBUG
1453: if (debug_level >= 3) {
1454: sock_dbg(f);
1455: dbg_puts(": switching to MIDI mode\n");
1456: }
1457: #endif
1.19 ratchov 1458: f->wstate = SOCK_WDATA;
1459: f->wtodo = 0;
1460: return 1;
1461: }
1462:
1.1 ratchov 1463: /*
1.20 ratchov 1464: * If pos changed, build a MOVE message.
1.1 ratchov 1465: */
1.42 ratchov 1466: if ((f->tickpending && f->delta > 0) || f->startpending) {
1.37 ratchov 1467: #ifdef DEBUG
1468: if (debug_level >= 4) {
1469: sock_dbg(f);
1470: dbg_puts(": building POS message, delta = ");
1471: dbg_puti(f->delta);
1472: dbg_puts("\n");
1473: }
1474: #endif
1.42 ratchov 1475: f->wmax += f->delta;
1476: if (f->delta > 0)
1477: f->rmax += f->delta;
1.1 ratchov 1478: AMSG_INIT(&f->wmsg);
1479: f->wmsg.cmd = AMSG_MOVE;
1.14 ratchov 1480: f->wmsg.u.ts.delta = f->delta;
1.1 ratchov 1481: f->wtodo = sizeof(struct amsg);
1482: f->wstate = SOCK_WMSG;
1.14 ratchov 1483: f->delta = 0;
1484: f->tickpending = 0;
1.42 ratchov 1485: f->startpending = 0;
1.25 ratchov 1486: return 1;
1487: }
1488:
1489: /*
1490: * if volume changed build a SETVOL message
1491: */
1.27 ratchov 1492: if (f->pstate >= SOCK_START && f->vol != f->lastvol) {
1.37 ratchov 1493: #ifdef DEBUG
1494: if (debug_level >= 4) {
1495: sock_dbg(f);
1496: dbg_puts(": building SETVOL message, vol = ");
1497: dbg_puti(f->vol);
1498: dbg_puts("\n");
1499: }
1500: #endif
1.25 ratchov 1501: AMSG_INIT(&f->wmsg);
1502: f->wmsg.cmd = AMSG_SETVOL;
1503: f->wmsg.u.vol.ctl = f->vol;
1504: f->wtodo = sizeof(struct amsg);
1505: f->wstate = SOCK_WMSG;
1506: f->lastvol = f->vol;
1.1 ratchov 1507: return 1;
1508: }
1509:
1510: /*
1.20 ratchov 1511: * If data available, build a DATA message.
1.1 ratchov 1512: */
1513: p = f->pipe.file.wproc;
1.45 ! ratchov 1514: ibuf = LIST_FIRST(&p->ins);
1.1 ratchov 1515: if (ibuf && ABUF_ROK(ibuf)) {
1.42 ratchov 1516: #ifdef DEBUG
1517: if (ibuf->used > f->wmax && debug_level >= 3) {
1518: sock_dbg(f);
1519: dbg_puts(": attempt to send past current position\n");
1520: }
1521: #endif
1522: max = AMSG_DATAMAX / ibuf->bpf;
1523: size = ibuf->used;
1.39 ratchov 1524: if (size > f->walign)
1525: size = f->walign;
1.42 ratchov 1526: if (size > f->wmax)
1527: size = f->wmax;
1528: if (size > max)
1529: size = max;
1530: if (size == 0)
1531: return 0;
1.39 ratchov 1532: f->walign -= size;
1.42 ratchov 1533: f->wmax -= size;
1.39 ratchov 1534: if (f->walign == 0)
1.42 ratchov 1535: f->walign = f->round;
1.1 ratchov 1536: AMSG_INIT(&f->wmsg);
1537: f->wmsg.cmd = AMSG_DATA;
1.42 ratchov 1538: f->wmsg.u.data.size = size * ibuf->bpf;
1.1 ratchov 1539: f->wtodo = sizeof(struct amsg);
1540: f->wstate = SOCK_WMSG;
1541: return 1;
1542: }
1.37 ratchov 1543: #ifdef DEBUG
1544: if (debug_level >= 4) {
1545: sock_dbg(f);
1546: dbg_puts(": no messages to build anymore, idling...\n");
1547: }
1548: #endif
1.1 ratchov 1549: f->wstate = SOCK_WIDLE;
1550: return 0;
1551: }
1552:
1553: /*
1.20 ratchov 1554: * Read from the socket file descriptor, fill input buffer and update
1.1 ratchov 1555: * the state. Return 1 if at least one message or 1 data byte was
1556: * processed, 0 if something blocked.
1557: */
1558: int
1559: sock_read(struct sock *f)
1560: {
1.37 ratchov 1561: #ifdef DEBUG
1562: if (debug_level >= 4) {
1563: sock_dbg(f);
1.39 ratchov 1564: dbg_puts(": reading ");
1.37 ratchov 1565: dbg_putu(f->rtodo);
1.39 ratchov 1566: dbg_puts(" todo\n");
1.37 ratchov 1567: }
1568: #endif
1.1 ratchov 1569: switch (f->rstate) {
1570: case SOCK_RMSG:
1571: if (!sock_rmsg(f))
1572: return 0;
1573: if (!sock_execmsg(f))
1574: return 0;
1575: break;
1576: case SOCK_RDATA:
1577: if (!sock_rdata(f))
1578: return 0;
1.19 ratchov 1579: if (f->pstate != SOCK_MIDI && f->rtodo == 0) {
1.1 ratchov 1580: f->rstate = SOCK_RMSG;
1581: f->rtodo = sizeof(struct amsg);
1582: }
1.35 ratchov 1583: /*
1.42 ratchov 1584: * XXX: sock_attach() may not start if there's not enough
1585: * samples queues, if so ctl_slotstart() will trigger
1586: * other streams, but this one won't start.
1.35 ratchov 1587: */
1.42 ratchov 1588: if (f->pstate == SOCK_READY && ctl_slotstart(dev_midi, f->slot))
1.1 ratchov 1589: (void)sock_attach(f, 0);
1590: break;
1591: case SOCK_RRET:
1.37 ratchov 1592: #ifdef DEBUG
1593: if (debug_level >= 4) {
1594: sock_dbg(f);
1595: dbg_puts(": blocked by pending RRET message\n");
1596: }
1597: #endif
1.1 ratchov 1598: return 0;
1599: }
1600: return 1;
1601: }
1602:
1603: /*
1.20 ratchov 1604: * Process messages to return.
1.1 ratchov 1605: */
1606: int
1607: sock_return(struct sock *f)
1608: {
1609: struct aproc *rp;
1610:
1611: while (f->rstate == SOCK_RRET) {
1612: if (!sock_wmsg(f, &f->rmsg, &f->rtodo))
1613: return 0;
1.37 ratchov 1614: #ifdef DEBUG
1615: if (debug_level >= 4) {
1616: sock_dbg(f);
1617: dbg_puts(": sent RRET message\n");
1618: }
1619: #endif
1.19 ratchov 1620: if (f->pstate == SOCK_MIDI && (f->mode & AMSG_MIDIOUT)) {
1621: f->rstate = SOCK_RDATA;
1622: f->rtodo = 0;
1623: } else {
1624: f->rstate = SOCK_RMSG;
1625: f->rtodo = sizeof(struct amsg);
1626: }
1627: if (f->pipe.file.state & FILE_RINUSE)
1628: break;
1629: f->pipe.file.state |= FILE_RINUSE;
1.1 ratchov 1630: for (;;) {
1631: /*
1632: * in() may trigger rsock_done and destroy the
1.20 ratchov 1633: * wsock.
1.1 ratchov 1634: */
1635: rp = f->pipe.file.rproc;
1636: if (!rp || !rp->ops->in(rp, NULL))
1637: break;
1638: }
1.19 ratchov 1639: f->pipe.file.state &= ~FILE_RINUSE;
1.1 ratchov 1640: if (f->pipe.file.wproc == NULL)
1641: return 0;
1642: }
1643: return 1;
1644: }
1645:
1646: /*
1.20 ratchov 1647: * Write messages and data on the socket file descriptor. Return 1 if
1.1 ratchov 1648: * at least one message or one data byte was processed, 0 if something
1649: * blocked.
1650: */
1651: int
1652: sock_write(struct sock *f)
1653: {
1.37 ratchov 1654: #ifdef DEBUG
1655: if (debug_level >= 4) {
1656: sock_dbg(f);
1.39 ratchov 1657: dbg_puts(": writing ");
1.37 ratchov 1658: dbg_putu(f->wtodo);
1.39 ratchov 1659: dbg_puts(" todo\n");
1.37 ratchov 1660: }
1661: #endif
1.1 ratchov 1662: switch (f->wstate) {
1663: case SOCK_WMSG:
1664: if (!sock_wmsg(f, &f->wmsg, &f->wtodo))
1665: return 0;
1666: if (f->wmsg.cmd != AMSG_DATA) {
1667: f->wstate = SOCK_WIDLE;
1668: f->wtodo = 0xdeadbeef;
1669: break;
1670: }
1.42 ratchov 1671: /*
1672: * XXX: why not set f->wtodo in sock_wmsg() ?
1673: */
1.1 ratchov 1674: f->wstate = SOCK_WDATA;
1.42 ratchov 1675: f->wtodo = f->wmsg.u.data.size /
1.45 ! ratchov 1676: LIST_FIRST(&f->pipe.file.wproc->ins)->bpf;
1.1 ratchov 1677: /* PASSTHROUGH */
1678: case SOCK_WDATA:
1679: if (!sock_wdata(f))
1680: return 0;
1.19 ratchov 1681: if (f->pstate == SOCK_MIDI || f->wtodo > 0)
1.1 ratchov 1682: break;
1683: f->wstate = SOCK_WIDLE;
1684: f->wtodo = 0xdeadbeef;
1.42 ratchov 1685: if (f->pstate == SOCK_STOP)
1686: sock_freebuf(f);
1.1 ratchov 1687: /* PASSTHROUGH */
1688: case SOCK_WIDLE:
1689: if (!sock_return(f))
1690: return 0;
1691: if (!sock_buildmsg(f))
1692: return 0;
1693: break;
1.37 ratchov 1694: #ifdef DEBUG
1695: default:
1696: sock_dbg(f);
1697: dbg_puts(": bad writing end state\n");
1698: dbg_panic();
1699: #endif
1.1 ratchov 1700: }
1701: return 1;
1702: }