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