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