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