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