Annotation of src/usr.bin/aucat/sock.c, Revision 1.50
1.50 ! ratchov 1: /* $OpenBSD: sock.c,v 1.49 2010/06/05 12:45:48 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;
1.50 ! ratchov 412: unsigned bufsz;
1.1 ratchov 413:
1.50 ! ratchov 414: bufsz = f->bufsz + f->dev->bufsz / f->dev->round * f->round;
1.42 ratchov 415: f->pstate = SOCK_START;
1.1 ratchov 416: if (f->mode & AMSG_PLAY) {
1.50 ! ratchov 417: rbuf = abuf_new(bufsz, &f->rpar);
1.1 ratchov 418: aproc_setout(f->pipe.file.rproc, rbuf);
1.42 ratchov 419: if (!ABUF_WOK(rbuf) || (f->pipe.file.state & FILE_EOF))
420: f->pstate = SOCK_READY;
1.50 ! ratchov 421: f->rmax = bufsz * aparams_bpf(&f->rpar);
1.1 ratchov 422: }
1.42 ratchov 423: if (f->mode & AMSG_RECMASK) {
1.50 ! ratchov 424: wbuf = abuf_new(bufsz, &f->wpar);
1.1 ratchov 425: aproc_setin(f->pipe.file.wproc, wbuf);
1.42 ratchov 426: f->walign = f->round;
1.50 ! ratchov 427: f->wmax = 0;
1.1 ratchov 428: }
1.14 ratchov 429: f->delta = 0;
1.49 ratchov 430: f->startpos = 0;
1.14 ratchov 431: f->tickpending = 0;
1.42 ratchov 432: f->startpending = 0;
1.37 ratchov 433: #ifdef DEBUG
434: if (debug_level >= 3) {
435: sock_dbg(f);
436: dbg_puts(": allocating ");
437: dbg_putu(f->bufsz);
1.50 ! ratchov 438: dbg_puts("/");
! 439: dbg_putu(bufsz);
1.42 ratchov 440: dbg_puts(" fr buffers, rmax = ");
441: dbg_putu(f->rmax);
442: dbg_puts("\n");
1.37 ratchov 443: }
444: #endif
1.42 ratchov 445: if (f->mode & AMSG_PLAY) {
446: f->pstate = SOCK_START;
447: } else {
448: f->pstate = SOCK_READY;
1.48 ratchov 449: if (ctl_slotstart(f->dev->midi, f->slot))
1.42 ratchov 450: (void)sock_attach(f, 0);
451: }
1.1 ratchov 452: }
453:
454: /*
1.25 ratchov 455: * Set volume. Callback invoked when volume is modified externally
1.3 ratchov 456: */
457: void
1.25 ratchov 458: sock_setvol(void *arg, unsigned vol)
1.3 ratchov 459: {
1.25 ratchov 460: struct sock *f = (struct sock *)arg;
1.3 ratchov 461: struct abuf *rbuf;
1.12 ratchov 462:
1.3 ratchov 463: f->vol = vol;
1.45 ratchov 464: rbuf = LIST_FIRST(&f->pipe.file.rproc->outs);
1.3 ratchov 465: if (!rbuf) {
1.37 ratchov 466: #ifdef DEBUG
467: if (debug_level >= 3) {
468: sock_dbg(f);
469: dbg_puts(": no read buffer to set volume yet\n");
470: }
471: #endif
1.3 ratchov 472: return;
473: }
1.48 ratchov 474: dev_setvol(f->dev, rbuf, MIDI_TO_ADATA(vol));
1.3 ratchov 475: }
476:
477: /*
1.35 ratchov 478: * Attach the stream. Callback invoked when MMC start
479: */
480: void
481: sock_startreq(void *arg)
482: {
483: struct sock *f = (struct sock *)arg;
484:
1.37 ratchov 485: #ifdef DEBUG
1.42 ratchov 486: if (f->pstate != SOCK_READY) {
1.37 ratchov 487: sock_dbg(f);
1.42 ratchov 488: dbg_puts(": not in READY state\n");
1.37 ratchov 489: dbg_panic();
490: }
491: #endif
1.35 ratchov 492: (void)sock_attach(f, 0);
493: }
494:
495: /*
1.42 ratchov 496: * Callback invoked by MMC stop
497: */
498: void
499: sock_stopreq(void *arg)
500: {
501: #ifdef DEBUG
502: struct sock *f = (struct sock *)arg;
503:
504: if (debug_level >= 3) {
505: sock_dbg(f);
506: dbg_puts(": ignored STOP signal\n");
507: }
508: #endif
509: }
510:
511: /*
512: * Callback invoked by MMC relocate, ignored
513: */
514: void
515: sock_locreq(void *arg, unsigned mmcpos)
516: {
517: #ifdef DEBUG
518: struct sock *f = (struct sock *)arg;
519:
520: if (debug_level >= 3) {
521: sock_dbg(f);
522: dbg_puts(": ignored RELOCATE signal\n");
523: }
524: #endif
525: }
526:
527: /*
1.48 ratchov 528: * Callback invoked when slot is gone
529: */
530: void
531: sock_quitreq(void *arg)
532: {
533: struct sock *f = (struct sock *)arg;
534:
535: #ifdef DEBUG
536: if (debug_level >= 3) {
537: sock_dbg(f);
538: dbg_puts(": slot gone\n");
539: }
540: #endif
541: file_close(&f->pipe.file);
542: }
543:
544: /*
545: * Attach play and/or record buffers to dev->mix and/or dev->sub.
1.1 ratchov 546: */
1.42 ratchov 547: void
1.1 ratchov 548: sock_attach(struct sock *f, int force)
549: {
550: struct abuf *rbuf, *wbuf;
551:
1.45 ratchov 552: rbuf = LIST_FIRST(&f->pipe.file.rproc->outs);
553: wbuf = LIST_FIRST(&f->pipe.file.wproc->ins);
1.1 ratchov 554:
555: /*
1.20 ratchov 556: * If in SOCK_START state, dont attach until
557: * the buffer isn't completely filled.
1.1 ratchov 558: */
559: if (!force && rbuf && ABUF_WOK(rbuf))
1.42 ratchov 560: return;
1.12 ratchov 561:
1.42 ratchov 562: /*
1.46 ratchov 563: * start the device (dev_getpos() and dev_attach() must
564: * be called on a started device
565: */
1.48 ratchov 566: dev_wakeup(f->dev);
1.46 ratchov 567:
568: /*
1.42 ratchov 569: * get the current position, the origin is when
570: * the first sample is played/recorded
571: */
1.49 ratchov 572: f->startpos = dev_getpos(f->dev) * (int)f->round / (int)f->dev->round;
1.42 ratchov 573: f->startpending = 1;
574: f->pstate = SOCK_RUN;
1.37 ratchov 575: #ifdef DEBUG
576: if (debug_level >= 3) {
577: sock_dbg(f);
1.42 ratchov 578: dbg_puts(": attaching at ");
1.49 ratchov 579: dbg_puti(f->startpos);
1.42 ratchov 580: dbg_puts("\n");
1.37 ratchov 581: }
582: #endif
1.1 ratchov 583: /*
1.42 ratchov 584: * We dont check whether the device is dying,
585: * because dev_xxx() functions are supposed to
586: * work (i.e., not to crash)
1.1 ratchov 587: */
1.48 ratchov 588: dev_attach(f->dev, f->pipe.file.name, f->mode,
1.43 ratchov 589: rbuf, &f->rpar,
590: f->opt->join ? f->opt->rpar.cmax - f->opt->rpar.cmin + 1 : 0,
591: wbuf, &f->wpar,
592: f->opt->join ? f->opt->wpar.cmax - f->opt->wpar.cmin + 1 : 0,
593: f->xrun, f->opt->maxweight);
1.3 ratchov 594: if (f->mode & AMSG_PLAY)
1.48 ratchov 595: dev_setvol(f->dev, rbuf, MIDI_TO_ADATA(f->vol));
1.3 ratchov 596:
1.1 ratchov 597: /*
1.20 ratchov 598: * Send the initial position, if needed.
1.1 ratchov 599: */
600: for (;;) {
601: if (!sock_write(f))
602: break;
603: }
604: }
605:
606: void
607: sock_reset(struct sock *f)
608: {
609: switch (f->pstate) {
610: case SOCK_START:
1.42 ratchov 611: case SOCK_READY:
1.48 ratchov 612: if (ctl_slotstart(f->dev->midi, f->slot)) {
1.35 ratchov 613: (void)sock_attach(f, 1);
614: f->pstate = SOCK_RUN;
615: }
1.1 ratchov 616: /* PASSTHROUGH */
617: case SOCK_RUN:
618: sock_freebuf(f);
619: f->pstate = SOCK_INIT;
620: /* PASSTHROUGH */
621: case SOCK_INIT:
622: /* nothing yet */
623: break;
624: }
625: }
626:
627: /*
1.20 ratchov 628: * Read a message from the file descriptor, return 1 if done, 0
629: * otherwise. The message is stored in f->rmsg.
1.1 ratchov 630: */
631: int
632: sock_rmsg(struct sock *f)
633: {
634: unsigned count;
635: unsigned char *data;
636:
637: while (f->rtodo > 0) {
638: if (!(f->pipe.file.state & FILE_ROK)) {
1.37 ratchov 639: #ifdef DEBUG
640: if (debug_level >= 4) {
641: sock_dbg(f);
642: dbg_puts(": reading message blocked, ");
643: dbg_putu(f->rtodo);
644: dbg_puts(" bytes remaining\n");
645: }
646: #endif
1.1 ratchov 647: return 0;
648: }
649: data = (unsigned char *)&f->rmsg;
650: data += sizeof(struct amsg) - f->rtodo;
651: count = file_read(&f->pipe.file, data, f->rtodo);
652: if (count == 0)
653: return 0;
654: f->rtodo -= count;
655: }
1.37 ratchov 656: #ifdef DEBUG
657: if (debug_level >= 4) {
658: sock_dbg(f);
659: dbg_puts(": read full message\n");
660: }
661: #endif
1.1 ratchov 662: return 1;
663: }
664:
665: /*
1.20 ratchov 666: * Write a message to the file descriptor, return 1 if done, 0
1.1 ratchov 667: * otherwise. The "m" argument is f->rmsg or f->wmsg, and the "ptodo"
668: * points to the f->rtodo or f->wtodo respectively.
669: */
670: int
671: sock_wmsg(struct sock *f, struct amsg *m, unsigned *ptodo)
672: {
673: unsigned count;
674: unsigned char *data;
675:
676: while (*ptodo > 0) {
677: if (!(f->pipe.file.state & FILE_WOK)) {
1.37 ratchov 678: #ifdef DEBUG
679: if (debug_level >= 4) {
680: sock_dbg(f);
681: dbg_puts(": writing message blocked, ");
682: dbg_putu(*ptodo);
683: dbg_puts(" bytes remaining\n");
684: }
685: #endif
1.1 ratchov 686: return 0;
687: }
688: data = (unsigned char *)m;
689: data += sizeof(struct amsg) - *ptodo;
690: count = file_write(&f->pipe.file, data, *ptodo);
691: if (count == 0)
692: return 0;
693: *ptodo -= count;
694: }
1.37 ratchov 695: #ifdef DEBUG
696: if (debug_level >= 4) {
697: sock_dbg(f);
698: dbg_puts(": wrote full message\n");
699: }
700: #endif
1.1 ratchov 701: return 1;
702: }
703:
704: /*
1.20 ratchov 705: * Read data chunk from the file descriptor, return 1 if at least one
1.1 ratchov 706: * byte was read, 0 if the file blocked.
707: */
708: int
709: sock_rdata(struct sock *f)
710: {
711: struct aproc *p;
712: struct abuf *obuf;
1.42 ratchov 713: unsigned n;
1.1 ratchov 714:
1.37 ratchov 715: #ifdef DEBUG
716: if (f->pstate != SOCK_MIDI && f->rtodo == 0) {
717: sock_dbg(f);
718: dbg_puts(": data block already read\n");
719: dbg_panic();
720: }
721: #endif
1.1 ratchov 722: p = f->pipe.file.rproc;
1.45 ratchov 723: obuf = LIST_FIRST(&p->outs);
1.19 ratchov 724: if (obuf == NULL)
725: return 0;
1.42 ratchov 726: if (!ABUF_WOK(obuf) || !(f->pipe.file.state & FILE_ROK))
1.41 ratchov 727: return 0;
1.42 ratchov 728: if (f->pstate == SOCK_MIDI) {
729: if (!rfile_do(p, obuf->len, NULL))
730: return 0;
731: } else {
732: if (!rfile_do(p, f->rtodo, &n))
733: return 0;
1.19 ratchov 734: f->rtodo -= n;
1.42 ratchov 735: if (f->pstate == SOCK_START) {
736: if (!ABUF_WOK(obuf) || (f->pipe.file.state & FILE_EOF))
737: f->pstate = SOCK_READY;
738: }
739: }
1.1 ratchov 740: return 1;
741: }
742:
743: /*
1.20 ratchov 744: * Write data chunk to the file descriptor, return 1 if at least one
1.1 ratchov 745: * byte was written, 0 if the file blocked.
746: */
747: int
748: sock_wdata(struct sock *f)
749: {
750: struct aproc *p;
751: struct abuf *ibuf;
1.42 ratchov 752: unsigned n;
1.1 ratchov 753:
1.37 ratchov 754: #ifdef DEBUG
755: if (f->pstate != SOCK_MIDI && f->wtodo == 0) {
756: sock_dbg(f);
757: dbg_puts(": attempted to write zero-sized data block\n");
758: dbg_panic();
759: }
760: #endif
1.1 ratchov 761: if (!(f->pipe.file.state & FILE_WOK))
762: return 0;
763: p = f->pipe.file.wproc;
1.45 ratchov 764: ibuf = LIST_FIRST(&p->ins);
1.42 ratchov 765: #ifdef DEBUG
766: if (f->pstate != SOCK_MIDI && ibuf == NULL) {
767: sock_dbg(f);
768: dbg_puts(": attempted to write on detached buffer\n");
769: dbg_panic();
770: }
771: #endif
772: if (ibuf == NULL)
773: return 0;
774: if (!ABUF_ROK(ibuf))
775: return 0;
776: if (f->pstate == SOCK_MIDI) {
777: if (!wfile_do(p, ibuf->len, NULL))
1.1 ratchov 778: return 0;
779: } else {
1.42 ratchov 780: if (!wfile_do(p, f->wtodo, &n))
1.1 ratchov 781: return 0;
782: f->wtodo -= n;
1.12 ratchov 783: }
1.1 ratchov 784: return 1;
785: }
786:
787: int
788: sock_setpar(struct sock *f)
789: {
790: struct amsg_par *p = &f->rmsg.u.par;
1.9 ratchov 791: unsigned min, max, rate;
1.12 ratchov 792:
1.1 ratchov 793: if (AMSG_ISSET(p->bits)) {
794: if (p->bits < BITS_MIN || p->bits > BITS_MAX) {
1.37 ratchov 795: #ifdef DEBUG
796: if (debug_level >= 1) {
797: sock_dbg(f);
798: dbg_puts(": ");
799: dbg_putu(p->bits);
800: dbg_puts(": bits out of bounds\n");
801: }
802: #endif
1.1 ratchov 803: return 0;
804: }
805: if (AMSG_ISSET(p->bps)) {
806: if (p->bps < ((p->bits + 7) / 8) || p->bps > 4) {
1.37 ratchov 807: #ifdef DEBUG
808: if (debug_level >= 1) {
809: sock_dbg(f);
810: dbg_puts(": ");
811: dbg_putu(p->bps);
812: dbg_puts(": wrong bytes per sample\n");
813: }
814: #endif
1.1 ratchov 815: return 0;
816: }
817: } else
818: p->bps = APARAMS_BPS(p->bits);
819: f->rpar.bits = f->wpar.bits = p->bits;
820: f->rpar.bps = f->wpar.bps = p->bps;
1.37 ratchov 821: #ifdef DEBUG
822: if (debug_level >= 3) {
823: sock_dbg(f);
824: dbg_puts(": using ");
825: dbg_putu(p->bits);
826: dbg_puts("bits, ");
827: dbg_putu(p->bps);
828: dbg_puts(" bytes per sample\n");
829: }
830: #endif
1.1 ratchov 831: }
832: if (AMSG_ISSET(p->sig))
833: f->rpar.sig = f->wpar.sig = p->sig ? 1 : 0;
834: if (AMSG_ISSET(p->le))
835: f->rpar.le = f->wpar.le = p->le ? 1 : 0;
836: if (AMSG_ISSET(p->msb))
837: f->rpar.msb = f->wpar.msb = p->msb ? 1 : 0;
1.42 ratchov 838: if (AMSG_ISSET(p->rchan) && (f->mode & AMSG_RECMASK)) {
1.1 ratchov 839: if (p->rchan < 1)
840: p->rchan = 1;
1.6 ratchov 841: if (p->rchan > NCHAN_MAX)
842: p->rchan = NCHAN_MAX;
1.19 ratchov 843: f->wpar.cmin = f->opt->wpar.cmin;
844: f->wpar.cmax = f->opt->wpar.cmin + p->rchan - 1;
845: if (f->wpar.cmax > f->opt->wpar.cmax)
846: f->wpar.cmax = f->opt->wpar.cmax;
1.37 ratchov 847: #ifdef DEBUG
848: if (debug_level >= 3) {
849: sock_dbg(f);
850: dbg_puts(": using recording channels ");
851: dbg_putu(f->wpar.cmin);
852: dbg_puts("..");
853: dbg_putu(f->wpar.cmax);
854: dbg_puts("\n");
855: }
856: #endif
1.1 ratchov 857: }
858: if (AMSG_ISSET(p->pchan) && (f->mode & AMSG_PLAY)) {
859: if (p->pchan < 1)
860: p->pchan = 1;
1.6 ratchov 861: if (p->pchan > NCHAN_MAX)
862: p->pchan = NCHAN_MAX;
1.19 ratchov 863: f->rpar.cmin = f->opt->rpar.cmin;
864: f->rpar.cmax = f->opt->rpar.cmin + p->pchan - 1;
865: if (f->rpar.cmax > f->opt->rpar.cmax)
866: f->rpar.cmax = f->opt->rpar.cmax;
1.37 ratchov 867: #ifdef DEBUG
868: if (debug_level >= 3) {
869: sock_dbg(f);
870: dbg_puts(": using playback channels ");
871: dbg_putu(f->rpar.cmin);
872: dbg_puts("..");
873: dbg_putu(f->rpar.cmax);
874: dbg_puts("\n");
875: }
876: #endif
1.1 ratchov 877: }
878: if (AMSG_ISSET(p->rate)) {
879: if (p->rate < RATE_MIN)
880: p->rate = RATE_MIN;
881: if (p->rate > RATE_MAX)
882: p->rate = RATE_MAX;
1.48 ratchov 883: f->round = dev_roundof(f->dev, p->rate);
1.1 ratchov 884: f->rpar.rate = f->wpar.rate = p->rate;
1.10 ratchov 885: if (!AMSG_ISSET(p->appbufsz)) {
1.48 ratchov 886: p->appbufsz = f->dev->bufsz / f->dev->round * f->round;
1.37 ratchov 887: #ifdef DEBUG
888: if (debug_level >= 3) {
889: sock_dbg(f);
890: dbg_puts(": using ");
891: dbg_putu(p->appbufsz);
892: dbg_puts(" fr app buffer size\n");
893: }
894: #endif
895: }
896: #ifdef DEBUG
897: if (debug_level >= 3) {
898: sock_dbg(f);
899: dbg_puts(": using ");
900: dbg_putu(p->rate);
901: dbg_puts("Hz sample rate, ");
902: dbg_putu(f->round);
903: dbg_puts(" fr block size\n");
1.10 ratchov 904: }
1.37 ratchov 905: #endif
1.1 ratchov 906: }
907: if (AMSG_ISSET(p->xrun)) {
908: if (p->xrun != AMSG_IGNORE &&
909: p->xrun != AMSG_SYNC &&
910: p->xrun != AMSG_ERROR) {
1.37 ratchov 911: #ifdef DEBUG
912: if (debug_level >= 1) {
913: sock_dbg(f);
914: dbg_puts(": ");
915: dbg_putx(p->xrun);
916: dbg_puts(": bad xrun policy\n");
917: }
918: #endif
1.1 ratchov 919: return 0;
920: }
921: f->xrun = p->xrun;
1.35 ratchov 922: if (f->opt->mmc && f->xrun == AMSG_IGNORE)
923: f->xrun = AMSG_SYNC;
1.37 ratchov 924: #ifdef DEBUG
925: if (debug_level >= 3) {
926: sock_dbg(f);
927: dbg_puts(": using 0x");
928: dbg_putx(f->xrun);
929: dbg_puts(" xrun policy\n");
930: }
931: #endif
1.1 ratchov 932: }
1.10 ratchov 933: if (AMSG_ISSET(p->appbufsz)) {
1.9 ratchov 934: rate = (f->mode & AMSG_PLAY) ? f->rpar.rate : f->wpar.rate;
1.42 ratchov 935: min = 1;
1.48 ratchov 936: max = 1 + rate / f->dev->round;
1.9 ratchov 937: min *= f->round;
938: max *= f->round;
1.10 ratchov 939: p->appbufsz += f->round - 1;
940: p->appbufsz -= p->appbufsz % f->round;
941: if (p->appbufsz < min)
942: p->appbufsz = min;
943: if (p->appbufsz > max)
944: p->appbufsz = max;
945: f->bufsz = p->appbufsz;
1.37 ratchov 946: #ifdef DEBUG
947: if (debug_level >= 3) {
948: sock_dbg(f);
949: dbg_puts(": using ");
950: dbg_putu(f->bufsz);
951: dbg_puts(" buffer size\n");
952: }
953: #endif
954: }
955: #ifdef DEBUG
956: if (debug_level >= 2) {
1.48 ratchov 957: if (APROC_OK(f->dev->midi)) {
958: dbg_puts(f->dev->midi->u.ctl.slot[f->slot].name);
959: dbg_putu(f->dev->midi->u.ctl.slot[f->slot].unit);
1.37 ratchov 960: } else
961: dbg_puts(f->pipe.file.name);
962: dbg_puts(": buffer size = ");
963: dbg_putu(f->bufsz);
964: if (f->mode & AMSG_PLAY) {
965: dbg_puts(", play = ");
966: aparams_dbg(&f->rpar);
967: }
1.42 ratchov 968: if (f->mode & AMSG_RECMASK) {
1.37 ratchov 969: dbg_puts(", rec:");
970: aparams_dbg(&f->wpar);
971: }
972: dbg_puts("\n");
1.1 ratchov 973: }
1.37 ratchov 974: #endif
1.1 ratchov 975: return 1;
976: }
977:
1.19 ratchov 978: /*
979: * allocate buffers, so client can start filling write-end.
980: */
981: void
982: sock_midiattach(struct sock *f, unsigned mode)
983: {
984: struct abuf *rbuf = NULL, *wbuf = NULL;
985:
986: if (mode & AMSG_MIDIOUT) {
1.22 ratchov 987: rbuf = abuf_new(MIDI_BUFSZ, &aparams_none);
1.19 ratchov 988: aproc_setout(f->pipe.file.rproc, rbuf);
989: }
990: if (mode & AMSG_MIDIIN) {
1.22 ratchov 991: wbuf = abuf_new(MIDI_BUFSZ, &aparams_none);
1.19 ratchov 992: aproc_setin(f->pipe.file.wproc, wbuf);
993: }
1.48 ratchov 994: dev_midiattach(f->dev, rbuf, wbuf);
1.19 ratchov 995: }
996:
1.17 ratchov 997: int
998: sock_hello(struct sock *f)
999: {
1000: struct amsg_hello *p = &f->rmsg.u.hello;
1001:
1.37 ratchov 1002: #ifdef DEBUG
1003: if (debug_level >= 3) {
1004: sock_dbg(f);
1005: dbg_puts(": hello from <");
1006: dbg_puts(p->who);
1007: dbg_puts(">, proto = ");
1008: dbg_putx(p->proto);
1009: dbg_puts(", ver ");
1010: dbg_putu(p->version);
1011: dbg_puts("\n");
1012: }
1013: #endif
1.33 ratchov 1014: if (p->version != AMSG_VERSION) {
1.37 ratchov 1015: #ifdef DEBUG
1016: if (debug_level >= 1) {
1017: sock_dbg(f);
1018: dbg_puts(": ");
1019: dbg_putu(p->version);
1020: dbg_puts(": bad version\n");
1021: }
1022: #endif
1.33 ratchov 1023: return 0;
1024: }
1.48 ratchov 1025: f->opt = opt_byname(p->opt);
1026: if (f->opt == NULL)
1027: return 0;
1028: if (!dev_ref(f->opt->dev))
1029: return 0;
1030: f->dev = f->opt->dev;
1031:
1032: if (APROC_OK(f->dev->midi) && (p->proto & (AMSG_MIDIIN | AMSG_MIDIOUT))) {
1.19 ratchov 1033: if (p->proto & ~(AMSG_MIDIIN | AMSG_MIDIOUT)) {
1.37 ratchov 1034: #ifdef DEBUG
1035: if (debug_level >= 1) {
1036: sock_dbg(f);
1037: dbg_puts(": ");
1038: dbg_putx(p->proto);
1039: dbg_puts(": bad hello protocol\n");
1040: }
1041: #endif
1.19 ratchov 1042: return 0;
1043: }
1044: f->mode = p->proto;
1045: f->pstate = SOCK_MIDI;
1046: sock_midiattach(f, p->proto);
1047: return 1;
1048: }
1.42 ratchov 1049: if (f->opt->mode & MODE_RECMASK)
1.19 ratchov 1050: f->wpar = f->opt->wpar;
1.42 ratchov 1051: if (f->opt->mode & MODE_PLAY)
1.19 ratchov 1052: f->rpar = f->opt->rpar;
1.35 ratchov 1053: if (f->opt->mmc)
1054: f->xrun = AMSG_SYNC;
1.48 ratchov 1055: f->bufsz = f->dev->bufsz;
1056: f->round = f->dev->round;
1.18 ratchov 1057: if ((p->proto & ~(AMSG_PLAY | AMSG_REC)) != 0 ||
1058: (p->proto & (AMSG_PLAY | AMSG_REC)) == 0) {
1.37 ratchov 1059: #ifdef DEBUG
1060: if (debug_level >= 1) {
1061: sock_dbg(f);
1062: dbg_puts(": ");
1063: dbg_putx(p->proto);
1064: dbg_puts(": unsupported hello protocol\n");
1065: }
1066: #endif
1.17 ratchov 1067: return 0;
1068: }
1.18 ratchov 1069: f->mode = 0;
1070: if (p->proto & AMSG_PLAY) {
1.48 ratchov 1071: if (!APROC_OK(f->dev->mix) || !(f->opt->mode & MODE_PLAY)) {
1.37 ratchov 1072: #ifdef DEBUG
1073: if (debug_level >= 1) {
1074: sock_dbg(f);
1075: dbg_puts(": playback not available\n");
1076: }
1077: #endif
1.18 ratchov 1078: return 0;
1079: }
1080: f->mode |= AMSG_PLAY;
1.17 ratchov 1081: }
1.18 ratchov 1082: if (p->proto & AMSG_REC) {
1.48 ratchov 1083: if (!(APROC_OK(f->dev->sub) && (f->opt->mode & MODE_REC)) &&
1084: !(APROC_OK(f->dev->submon) && (f->opt->mode & MODE_MON))) {
1.37 ratchov 1085: #ifdef DEBUG
1086: if (debug_level >= 1) {
1087: sock_dbg(f);
1088: dbg_puts(": recording not available\n");
1089: }
1090: #endif
1.18 ratchov 1091: return 0;
1092: }
1.42 ratchov 1093: f->mode |= (f->opt->mode & MODE_MON) ? AMSG_MON : AMSG_REC;
1.17 ratchov 1094: }
1.48 ratchov 1095: if (APROC_OK(f->dev->midi)) {
1096: f->slot = ctl_slotnew(f->dev->midi,
1.35 ratchov 1097: p->who, &ctl_sockops, f,
1098: f->opt->mmc);
1.24 ratchov 1099: if (f->slot < 0) {
1.37 ratchov 1100: #ifdef DEBUG
1101: if (debug_level >= 1) {
1102: sock_dbg(f);
1103: dbg_puts(": out of mixer slots\n");
1104: }
1105: #endif
1.24 ratchov 1106: return 0;
1107: }
1108: }
1.18 ratchov 1109: f->pstate = SOCK_INIT;
1.17 ratchov 1110: return 1;
1111: }
1112:
1.1 ratchov 1113: /*
1.20 ratchov 1114: * Execute message in f->rmsg and change the state accordingly; return 1
1.1 ratchov 1115: * on success, and 0 on failure, in which case the socket is destroyed.
1116: */
1117: int
1118: sock_execmsg(struct sock *f)
1119: {
1120: struct amsg *m = &f->rmsg;
1.42 ratchov 1121: struct abuf *obuf;
1.1 ratchov 1122:
1123: switch (m->cmd) {
1124: case AMSG_DATA:
1.37 ratchov 1125: #ifdef DEBUG
1126: if (debug_level >= 4) {
1127: sock_dbg(f);
1128: dbg_puts(": DATA message\n");
1129: }
1130: #endif
1.42 ratchov 1131: if (f->pstate != SOCK_RUN && f->pstate != SOCK_START &&
1132: f->pstate != SOCK_READY) {
1.37 ratchov 1133: #ifdef DEBUG
1134: if (debug_level >= 1) {
1135: sock_dbg(f);
1136: dbg_puts(": DATA, bad state\n");
1137: }
1138: #endif
1.8 ratchov 1139: aproc_del(f->pipe.file.rproc);
1140: return 0;
1141: }
1142: if (!(f->mode & AMSG_PLAY)) {
1.37 ratchov 1143: #ifdef DEBUG
1144: if (debug_level >= 1) {
1145: sock_dbg(f);
1146: dbg_puts(": DATA not allowed in record-only mode\n");
1147: }
1148: #endif
1.1 ratchov 1149: aproc_del(f->pipe.file.rproc);
1150: return 0;
1151: }
1.45 ratchov 1152: obuf = LIST_FIRST(&f->pipe.file.rproc->outs);
1.42 ratchov 1153: if (f->pstate == SOCK_START && !ABUF_WOK(obuf)) {
1.37 ratchov 1154: #ifdef DEBUG
1155: if (debug_level >= 1) {
1156: sock_dbg(f);
1157: dbg_puts(": DATA client violates flow control\n");
1158: }
1159: #endif
1.34 ratchov 1160: aproc_del(f->pipe.file.rproc);
1161: return 0;
1162: }
1.42 ratchov 1163: if (m->u.data.size % obuf->bpf != 0) {
1164: #ifdef DEBUG
1165: if (debug_level >= 1) {
1166: sock_dbg(f);
1167: dbg_puts(": unaligned data chunk\n");
1168: }
1169: #endif
1170: aproc_del(f->pipe.file.rproc);
1171: return 0;
1172: }
1.1 ratchov 1173: f->rstate = SOCK_RDATA;
1.42 ratchov 1174: f->rtodo = m->u.data.size / obuf->bpf;
1175: #ifdef DEBUG
1176: if (f->rtodo > f->rmax && debug_level >= 2) {
1177: sock_dbg(f);
1178: dbg_puts(": received past current position, rtodo = ");
1179: dbg_putu(f->rtodo);
1180: dbg_puts(", rmax = ");
1181: dbg_putu(f->rmax);
1182: dbg_puts("\n");
1183: aproc_del(f->pipe.file.rproc);
1184: return 0;
1185: }
1186: #endif
1187: f->rmax -= f->rtodo;
1.1 ratchov 1188: if (f->rtodo == 0) {
1.37 ratchov 1189: #ifdef DEBUG
1190: if (debug_level >= 1) {
1191: sock_dbg(f);
1192: dbg_puts(": zero-length data chunk\n");
1193: }
1194: #endif
1.1 ratchov 1195: aproc_del(f->pipe.file.rproc);
1196: return 0;
1197: }
1198: break;
1199: case AMSG_START:
1.37 ratchov 1200: #ifdef DEBUG
1201: if (debug_level >= 3) {
1202: sock_dbg(f);
1203: dbg_puts(": START message\n");
1204: }
1205: #endif
1.1 ratchov 1206: if (f->pstate != SOCK_INIT) {
1.37 ratchov 1207: #ifdef DEBUG
1208: if (debug_level >= 1) {
1209: sock_dbg(f);
1210: dbg_puts(": START, bad state\n");
1211: }
1212: #endif
1.1 ratchov 1213: aproc_del(f->pipe.file.rproc);
1214: return 0;
1215: }
1216: sock_allocbuf(f);
1217: f->rstate = SOCK_RMSG;
1218: f->rtodo = sizeof(struct amsg);
1219: break;
1220: case AMSG_STOP:
1.37 ratchov 1221: #ifdef DEBUG
1222: if (debug_level >= 3) {
1223: sock_dbg(f);
1224: dbg_puts(": STOP message\n");
1225: }
1226: #endif
1.42 ratchov 1227: if (f->pstate != SOCK_RUN &&
1228: f->pstate != SOCK_START && f->pstate != SOCK_READY) {
1.37 ratchov 1229: #ifdef DEBUG
1230: if (debug_level >= 1) {
1231: sock_dbg(f);
1232: dbg_puts(": STOP, bad state\n");
1233: }
1234: #endif
1.1 ratchov 1235: aproc_del(f->pipe.file.rproc);
1236: return 0;
1.42 ratchov 1237: /*
1238: * XXX: device could have desappeared at this point,
1239: * see how this is fixed in wav.c
1240: */
1.1 ratchov 1241: }
1.42 ratchov 1242: if ((f->pstate == SOCK_START || f->pstate == SOCK_READY) &&
1.48 ratchov 1243: ctl_slotstart(f->dev->midi, f->slot))
1.1 ratchov 1244: (void)sock_attach(f, 1);
1.42 ratchov 1245: if (f->wstate != SOCK_WDATA || f->wtodo == 0)
1246: sock_freebuf(f);
1247: else
1248: f->pstate = SOCK_STOP;
1.1 ratchov 1249: AMSG_INIT(m);
1250: m->cmd = AMSG_ACK;
1251: f->rstate = SOCK_RRET;
1252: f->rtodo = sizeof(struct amsg);
1253: break;
1254: case AMSG_SETPAR:
1.37 ratchov 1255: #ifdef DEBUG
1256: if (debug_level >= 3) {
1257: sock_dbg(f);
1258: dbg_puts(": SETPAR message\n");
1259: }
1260: #endif
1.1 ratchov 1261: if (f->pstate != SOCK_INIT) {
1.37 ratchov 1262: #ifdef DEBUG
1263: if (debug_level >= 1) {
1264: sock_dbg(f);
1265: dbg_puts(": SETPAR, bad state\n");
1266: }
1267: #endif
1.1 ratchov 1268: aproc_del(f->pipe.file.rproc);
1269: return 0;
1270: }
1271: if (!sock_setpar(f)) {
1272: aproc_del(f->pipe.file.rproc);
1273: return 0;
1274: }
1275: f->rtodo = sizeof(struct amsg);
1276: f->rstate = SOCK_RMSG;
1277: break;
1278: case AMSG_GETPAR:
1.37 ratchov 1279: #ifdef DEBUG
1280: if (debug_level >= 3) {
1281: sock_dbg(f);
1282: dbg_puts(": GETPAR message\n");
1283: }
1284: #endif
1.1 ratchov 1285: if (f->pstate != SOCK_INIT) {
1.37 ratchov 1286: #ifdef DEBUG
1287: if (debug_level >= 1) {
1288: sock_dbg(f);
1289: dbg_puts(": GETPAR, bad state\n");
1290: }
1291: #endif
1.1 ratchov 1292: aproc_del(f->pipe.file.rproc);
1293: return 0;
1294: }
1295: AMSG_INIT(m);
1296: m->cmd = AMSG_GETPAR;
1.18 ratchov 1297: m->u.par.legacy_mode = f->mode;
1.42 ratchov 1298: if (f->mode & AMSG_PLAY) {
1299: m->u.par.bits = f->rpar.bits;
1300: m->u.par.bps = f->rpar.bps;
1301: m->u.par.sig = f->rpar.sig;
1302: m->u.par.le = f->rpar.le;
1303: m->u.par.msb = f->rpar.msb;
1304: m->u.par.rate = f->rpar.rate;
1305: m->u.par.pchan = f->rpar.cmax - f->rpar.cmin + 1;
1306: }
1307: if (f->mode & AMSG_RECMASK) {
1308: m->u.par.bits = f->wpar.bits;
1309: m->u.par.bps = f->wpar.bps;
1310: m->u.par.sig = f->wpar.sig;
1311: m->u.par.le = f->wpar.le;
1312: m->u.par.msb = f->wpar.msb;
1313: m->u.par.rate = f->wpar.rate;
1314: m->u.par.rchan = f->wpar.cmax - f->wpar.cmin + 1;
1315: }
1.10 ratchov 1316: m->u.par.appbufsz = f->bufsz;
1.12 ratchov 1317: m->u.par.bufsz =
1.48 ratchov 1318: f->bufsz + (f->dev->bufsz / f->dev->round) * f->round;
1.1 ratchov 1319: m->u.par.round = f->round;
1320: f->rstate = SOCK_RRET;
1321: f->rtodo = sizeof(struct amsg);
1322: break;
1323: case AMSG_GETCAP:
1.37 ratchov 1324: #ifdef DEBUG
1325: if (debug_level >= 3) {
1326: sock_dbg(f);
1327: dbg_puts(": GETCAP message\n");
1328: }
1329: #endif
1.1 ratchov 1330: if (f->pstate != SOCK_INIT) {
1.37 ratchov 1331: #ifdef DEBUG
1332: if (debug_level >= 1) {
1333: sock_dbg(f);
1334: dbg_puts(": GETCAP, bad state\n");
1335: }
1336: #endif
1.1 ratchov 1337: aproc_del(f->pipe.file.rproc);
1338: return 0;
1339: }
1340: AMSG_INIT(m);
1341: m->cmd = AMSG_GETCAP;
1.48 ratchov 1342: m->u.cap.rate = f->dev->rate;
1.42 ratchov 1343: m->u.cap.pchan = (f->opt->mode & MODE_PLAY) ?
1.19 ratchov 1344: (f->opt->rpar.cmax - f->opt->rpar.cmin + 1) : 0;
1.42 ratchov 1345: m->u.cap.rchan = (f->opt->mode & (MODE_PLAY | MODE_REC)) ?
1.19 ratchov 1346: (f->opt->wpar.cmax - f->opt->wpar.cmin + 1) : 0;
1.1 ratchov 1347: m->u.cap.bits = sizeof(short) * 8;
1348: m->u.cap.bps = sizeof(short);
1349: f->rstate = SOCK_RRET;
1350: f->rtodo = sizeof(struct amsg);
1.3 ratchov 1351: break;
1352: case AMSG_SETVOL:
1.37 ratchov 1353: #ifdef DEBUG
1354: if (debug_level >= 3) {
1355: sock_dbg(f);
1356: dbg_puts(": SETVOL message\n");
1357: }
1358: #endif
1.42 ratchov 1359: if (f->pstate != SOCK_RUN && f->pstate != SOCK_START &&
1360: f->pstate != SOCK_INIT && f->pstate != SOCK_READY) {
1.37 ratchov 1361: #ifdef DEBUG
1362: if (debug_level >= 1) {
1363: sock_dbg(f);
1364: dbg_puts(": SETVOL, bad state\n");
1365: }
1366: #endif
1.3 ratchov 1367: aproc_del(f->pipe.file.rproc);
1368: return 0;
1369: }
1370: if (m->u.vol.ctl > MIDI_MAXCTL) {
1.37 ratchov 1371: #ifdef DEBUG
1372: if (debug_level >= 1) {
1373: sock_dbg(f);
1374: dbg_puts(": SETVOL, volume out of range\n");
1375: }
1376: #endif
1.3 ratchov 1377: aproc_del(f->pipe.file.rproc);
1378: return 0;
1379: }
1.25 ratchov 1380: sock_setvol(f, m->u.vol.ctl);
1.34 ratchov 1381: if (f->slot >= 0)
1.48 ratchov 1382: ctl_slotvol(f->dev->midi, f->slot, m->u.vol.ctl);
1.3 ratchov 1383: f->rtodo = sizeof(struct amsg);
1384: f->rstate = SOCK_RMSG;
1.17 ratchov 1385: break;
1386: case AMSG_HELLO:
1.37 ratchov 1387: #ifdef DEBUG
1388: if (debug_level >= 3) {
1389: sock_dbg(f);
1390: dbg_puts(": HELLO message\n");
1391: }
1392: #endif
1.18 ratchov 1393: if (f->pstate != SOCK_HELLO) {
1.37 ratchov 1394: #ifdef DEBUG
1395: if (debug_level >= 1) {
1396: sock_dbg(f);
1397: dbg_puts(": HELLO, bad state\n");
1398: }
1399: #endif
1.17 ratchov 1400: aproc_del(f->pipe.file.rproc);
1401: return 0;
1402: }
1403: if (!sock_hello(f)) {
1404: aproc_del(f->pipe.file.rproc);
1405: return 0;
1406: }
1407: AMSG_INIT(m);
1408: m->cmd = AMSG_ACK;
1409: f->rstate = SOCK_RRET;
1410: f->rtodo = sizeof(struct amsg);
1.1 ratchov 1411: break;
1.28 ratchov 1412: case AMSG_BYE:
1.37 ratchov 1413: #ifdef DEBUG
1414: if (debug_level >= 3) {
1415: sock_dbg(f);
1416: dbg_puts(": BYE message\n");
1417: }
1418: #endif
1.29 ratchov 1419: if (f->pstate != SOCK_INIT) {
1.37 ratchov 1420: #ifdef DEBUG
1421: if (debug_level >= 1) {
1422: sock_dbg(f);
1423: dbg_puts(": BYE, bad state\n");
1424: }
1425: #endif
1.29 ratchov 1426: }
1.28 ratchov 1427: aproc_del(f->pipe.file.rproc);
1428: return 0;
1.1 ratchov 1429: default:
1.37 ratchov 1430: #ifdef DEBUG
1431: if (debug_level >= 1) {
1432: sock_dbg(f);
1433: dbg_puts(": unknown command in message\n");
1434: }
1435: #endif
1.1 ratchov 1436: aproc_del(f->pipe.file.rproc);
1437: return 0;
1438: }
1439: if (f->rstate == SOCK_RRET) {
1440: if (f->wstate != SOCK_WIDLE ||
1441: !sock_wmsg(f, &f->rmsg, &f->rtodo))
1442: return 0;
1.37 ratchov 1443: #ifdef DEBUG
1444: if (debug_level >= 3) {
1445: sock_dbg(f);
1446: dbg_puts(": RRET done\n");
1447: }
1448: #endif
1.19 ratchov 1449: if (f->pstate == SOCK_MIDI && (f->mode & AMSG_MIDIOUT)) {
1450: f->rstate = SOCK_RDATA;
1451: f->rtodo = 0;
1452: } else {
1453: f->rstate = SOCK_RMSG;
1454: f->rtodo = sizeof(struct amsg);
1455: }
1.1 ratchov 1456: }
1457: return 1;
1458: }
1459:
1460: /*
1.20 ratchov 1461: * Create a new data/pos message.
1.1 ratchov 1462: */
1463: int
1464: sock_buildmsg(struct sock *f)
1465: {
1466: struct aproc *p;
1467: struct abuf *ibuf;
1.42 ratchov 1468: unsigned size, max;
1.12 ratchov 1469:
1.19 ratchov 1470: if (f->pstate == SOCK_MIDI) {
1.37 ratchov 1471: #ifdef DEBUG
1472: if (debug_level >= 3) {
1473: sock_dbg(f);
1474: dbg_puts(": switching to MIDI mode\n");
1475: }
1476: #endif
1.19 ratchov 1477: f->wstate = SOCK_WDATA;
1478: f->wtodo = 0;
1479: return 1;
1480: }
1481:
1.1 ratchov 1482: /*
1.49 ratchov 1483: * Send initial position
1484: */
1485: if (f->startpending) {
1486: #ifdef DEBUG
1487: if (debug_level >= 4) {
1488: sock_dbg(f);
1489: dbg_puts(": building POS message, pos = ");
1490: dbg_puti(f->startpos);
1491: dbg_puts("\n");
1492: }
1493: #endif
1494: AMSG_INIT(&f->wmsg);
1495: f->wmsg.cmd = AMSG_POS;
1496: f->wmsg.u.ts.delta = f->startpos;
1.50 ! ratchov 1497: f->rmax += f->startpos;
1.49 ratchov 1498: f->wtodo = sizeof(struct amsg);
1499: f->wstate = SOCK_WMSG;
1500: f->startpending = 0;
1501: return 1;
1502: }
1503:
1504: /*
1.20 ratchov 1505: * If pos changed, build a MOVE message.
1.1 ratchov 1506: */
1.49 ratchov 1507: if (f->tickpending) {
1.37 ratchov 1508: #ifdef DEBUG
1509: if (debug_level >= 4) {
1510: sock_dbg(f);
1.49 ratchov 1511: dbg_puts(": building MOVE message, delta = ");
1.37 ratchov 1512: dbg_puti(f->delta);
1513: dbg_puts("\n");
1514: }
1515: #endif
1.42 ratchov 1516: f->wmax += f->delta;
1.49 ratchov 1517: f->rmax += f->delta;
1.1 ratchov 1518: AMSG_INIT(&f->wmsg);
1519: f->wmsg.cmd = AMSG_MOVE;
1.14 ratchov 1520: f->wmsg.u.ts.delta = f->delta;
1.1 ratchov 1521: f->wtodo = sizeof(struct amsg);
1522: f->wstate = SOCK_WMSG;
1.14 ratchov 1523: f->delta = 0;
1524: f->tickpending = 0;
1.25 ratchov 1525: return 1;
1526: }
1527:
1528: /*
1529: * if volume changed build a SETVOL message
1530: */
1.27 ratchov 1531: if (f->pstate >= SOCK_START && f->vol != f->lastvol) {
1.37 ratchov 1532: #ifdef DEBUG
1533: if (debug_level >= 4) {
1534: sock_dbg(f);
1535: dbg_puts(": building SETVOL message, vol = ");
1536: dbg_puti(f->vol);
1537: dbg_puts("\n");
1538: }
1539: #endif
1.25 ratchov 1540: AMSG_INIT(&f->wmsg);
1541: f->wmsg.cmd = AMSG_SETVOL;
1542: f->wmsg.u.vol.ctl = f->vol;
1543: f->wtodo = sizeof(struct amsg);
1544: f->wstate = SOCK_WMSG;
1545: f->lastvol = f->vol;
1.1 ratchov 1546: return 1;
1547: }
1548:
1549: /*
1.20 ratchov 1550: * If data available, build a DATA message.
1.1 ratchov 1551: */
1552: p = f->pipe.file.wproc;
1.45 ratchov 1553: ibuf = LIST_FIRST(&p->ins);
1.1 ratchov 1554: if (ibuf && ABUF_ROK(ibuf)) {
1.42 ratchov 1555: #ifdef DEBUG
1556: if (ibuf->used > f->wmax && debug_level >= 3) {
1557: sock_dbg(f);
1.46 ratchov 1558: dbg_puts(": attempt to send past current position: used = ");
1559: dbg_putu(ibuf->used);
1560: dbg_puts(" wmax = ");
1561: dbg_putu(f->wmax);
1562: dbg_puts("\n");
1.42 ratchov 1563: }
1564: #endif
1565: max = AMSG_DATAMAX / ibuf->bpf;
1566: size = ibuf->used;
1.39 ratchov 1567: if (size > f->walign)
1568: size = f->walign;
1.42 ratchov 1569: if (size > f->wmax)
1570: size = f->wmax;
1571: if (size > max)
1572: size = max;
1573: if (size == 0)
1574: return 0;
1.39 ratchov 1575: f->walign -= size;
1.42 ratchov 1576: f->wmax -= size;
1.39 ratchov 1577: if (f->walign == 0)
1.42 ratchov 1578: f->walign = f->round;
1.1 ratchov 1579: AMSG_INIT(&f->wmsg);
1580: f->wmsg.cmd = AMSG_DATA;
1.42 ratchov 1581: f->wmsg.u.data.size = size * ibuf->bpf;
1.1 ratchov 1582: f->wtodo = sizeof(struct amsg);
1583: f->wstate = SOCK_WMSG;
1584: return 1;
1585: }
1.37 ratchov 1586: #ifdef DEBUG
1587: if (debug_level >= 4) {
1588: sock_dbg(f);
1589: dbg_puts(": no messages to build anymore, idling...\n");
1590: }
1591: #endif
1.1 ratchov 1592: f->wstate = SOCK_WIDLE;
1593: return 0;
1594: }
1595:
1596: /*
1.20 ratchov 1597: * Read from the socket file descriptor, fill input buffer and update
1.1 ratchov 1598: * the state. Return 1 if at least one message or 1 data byte was
1599: * processed, 0 if something blocked.
1600: */
1601: int
1602: sock_read(struct sock *f)
1603: {
1.37 ratchov 1604: #ifdef DEBUG
1605: if (debug_level >= 4) {
1606: sock_dbg(f);
1.39 ratchov 1607: dbg_puts(": reading ");
1.37 ratchov 1608: dbg_putu(f->rtodo);
1.39 ratchov 1609: dbg_puts(" todo\n");
1.37 ratchov 1610: }
1611: #endif
1.1 ratchov 1612: switch (f->rstate) {
1613: case SOCK_RMSG:
1614: if (!sock_rmsg(f))
1615: return 0;
1616: if (!sock_execmsg(f))
1617: return 0;
1618: break;
1619: case SOCK_RDATA:
1620: if (!sock_rdata(f))
1621: return 0;
1.19 ratchov 1622: if (f->pstate != SOCK_MIDI && f->rtodo == 0) {
1.1 ratchov 1623: f->rstate = SOCK_RMSG;
1624: f->rtodo = sizeof(struct amsg);
1625: }
1.35 ratchov 1626: /*
1.42 ratchov 1627: * XXX: sock_attach() may not start if there's not enough
1628: * samples queues, if so ctl_slotstart() will trigger
1629: * other streams, but this one won't start.
1.35 ratchov 1630: */
1.48 ratchov 1631: if (f->pstate == SOCK_READY && ctl_slotstart(f->dev->midi, f->slot))
1.1 ratchov 1632: (void)sock_attach(f, 0);
1633: break;
1634: case SOCK_RRET:
1.37 ratchov 1635: #ifdef DEBUG
1636: if (debug_level >= 4) {
1637: sock_dbg(f);
1638: dbg_puts(": blocked by pending RRET message\n");
1639: }
1640: #endif
1.1 ratchov 1641: return 0;
1642: }
1643: return 1;
1644: }
1645:
1646: /*
1.20 ratchov 1647: * Process messages to return.
1.1 ratchov 1648: */
1649: int
1650: sock_return(struct sock *f)
1651: {
1652: struct aproc *rp;
1653:
1654: while (f->rstate == SOCK_RRET) {
1655: if (!sock_wmsg(f, &f->rmsg, &f->rtodo))
1656: return 0;
1.37 ratchov 1657: #ifdef DEBUG
1658: if (debug_level >= 4) {
1659: sock_dbg(f);
1660: dbg_puts(": sent RRET message\n");
1661: }
1662: #endif
1.19 ratchov 1663: if (f->pstate == SOCK_MIDI && (f->mode & AMSG_MIDIOUT)) {
1664: f->rstate = SOCK_RDATA;
1665: f->rtodo = 0;
1666: } else {
1667: f->rstate = SOCK_RMSG;
1668: f->rtodo = sizeof(struct amsg);
1669: }
1670: if (f->pipe.file.state & FILE_RINUSE)
1671: break;
1672: f->pipe.file.state |= FILE_RINUSE;
1.1 ratchov 1673: for (;;) {
1674: /*
1675: * in() may trigger rsock_done and destroy the
1.20 ratchov 1676: * wsock.
1.1 ratchov 1677: */
1678: rp = f->pipe.file.rproc;
1679: if (!rp || !rp->ops->in(rp, NULL))
1680: break;
1681: }
1.19 ratchov 1682: f->pipe.file.state &= ~FILE_RINUSE;
1.1 ratchov 1683: if (f->pipe.file.wproc == NULL)
1684: return 0;
1685: }
1686: return 1;
1687: }
1688:
1689: /*
1.20 ratchov 1690: * Write messages and data on the socket file descriptor. Return 1 if
1.1 ratchov 1691: * at least one message or one data byte was processed, 0 if something
1692: * blocked.
1693: */
1694: int
1695: sock_write(struct sock *f)
1696: {
1.37 ratchov 1697: #ifdef DEBUG
1698: if (debug_level >= 4) {
1699: sock_dbg(f);
1.39 ratchov 1700: dbg_puts(": writing ");
1.37 ratchov 1701: dbg_putu(f->wtodo);
1.39 ratchov 1702: dbg_puts(" todo\n");
1.37 ratchov 1703: }
1704: #endif
1.1 ratchov 1705: switch (f->wstate) {
1706: case SOCK_WMSG:
1707: if (!sock_wmsg(f, &f->wmsg, &f->wtodo))
1708: return 0;
1709: if (f->wmsg.cmd != AMSG_DATA) {
1710: f->wstate = SOCK_WIDLE;
1711: f->wtodo = 0xdeadbeef;
1712: break;
1713: }
1.42 ratchov 1714: /*
1715: * XXX: why not set f->wtodo in sock_wmsg() ?
1716: */
1.1 ratchov 1717: f->wstate = SOCK_WDATA;
1.42 ratchov 1718: f->wtodo = f->wmsg.u.data.size /
1.45 ratchov 1719: LIST_FIRST(&f->pipe.file.wproc->ins)->bpf;
1.1 ratchov 1720: /* PASSTHROUGH */
1721: case SOCK_WDATA:
1722: if (!sock_wdata(f))
1723: return 0;
1.19 ratchov 1724: if (f->pstate == SOCK_MIDI || f->wtodo > 0)
1.1 ratchov 1725: break;
1726: f->wstate = SOCK_WIDLE;
1727: f->wtodo = 0xdeadbeef;
1.42 ratchov 1728: if (f->pstate == SOCK_STOP)
1729: sock_freebuf(f);
1.1 ratchov 1730: /* PASSTHROUGH */
1731: case SOCK_WIDLE:
1732: if (!sock_return(f))
1733: return 0;
1734: if (!sock_buildmsg(f))
1735: return 0;
1736: break;
1.37 ratchov 1737: #ifdef DEBUG
1738: default:
1739: sock_dbg(f);
1740: dbg_puts(": bad writing end state\n");
1741: dbg_panic();
1742: #endif
1.1 ratchov 1743: }
1744: return 1;
1745: }