Annotation of src/usr.bin/aucat/dev.c, Revision 1.83
1.83 ! ratchov 1: /* $OpenBSD$ */
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: */
1.51 ratchov 17: /*
18: * Device abstraction module
19: *
20: * This module exposes a ``enhanced device'' that uses aproc
21: * structures framework; it does conversions on the fly and can
22: * handle multiple streams. The enhanced device starts and stops
23: * automatically, when streams are attached, and provides
24: * primitives for MIDI control
25: *
26: * From the main loop, the device is used as follows:
27: *
1.57 ratchov 28: * 1. create the device using dev_new_xxx()
1.51 ratchov 29: * 2. call dev_run() in the event loop
1.57 ratchov 30: * 3. destroy the device using dev_del()
1.51 ratchov 31: * 4. continue running the event loop to drain
32: *
33: * The device is used as follows from aproc context:
34: *
35: * 1. open the device with dev_ref()
36: * 2. negociate parameters (mode, rate, ...)
37: * 3. create your stream (ie allocate and fill abufs)
38: * 4. attach your stream atomically:
39: * - first call dev_wakeup() to ensure device is not suspended
40: * - possibly fetch dynamic parameters (eg. dev_getpos())
41: * - attach your buffers with dev_attach()
42: * 5. close your stream, ie abuf_eof() or abuf_hup()
43: * 6. close the device with dev_unref()
44: *
45: * The device has the following states:
46: *
47: * CLOSED sio_open() is not called, it's not ready and
48: * no streams can be attached; dev_ref() must
49: * be called to open the device
50: *
51: * INIT device is opened, processing chain is ready, but
52: * DMA is not started yet. Streams can attach,
53: * in which case device will automatically switch
54: * to the START state
55: *
56: * START at least one stream is attached, play buffers
57: * are primed (if necessary) DMA is ready and
58: * will start immeadiately (next cycle)
59: *
60: * RUN DMA is started. New streams can attach. If the
61: * device is idle (all streams are closed and
62: * finished draining), then the device
63: * automatically switches to INIT or CLOSED
64: */
1.1 ratchov 65: #include <stdio.h>
66: #include <stdlib.h>
1.71 ratchov 67: #include <string.h>
1.1 ratchov 68: #include <unistd.h>
69:
70: #include "abuf.h"
71: #include "aproc.h"
1.27 ratchov 72: #include "conf.h"
73: #include "dev.h"
1.3 ratchov 74: #include "pipe.h"
1.38 ratchov 75: #include "miofile.h"
1.42 ratchov 76: #include "siofile.h"
1.28 ratchov 77: #include "midi.h"
1.39 ratchov 78: #ifdef DEBUG
79: #include "dbg.h"
80: #endif
1.1 ratchov 81:
1.57 ratchov 82: int dev_open(struct dev *);
83: void dev_close(struct dev *);
84: void dev_start(struct dev *);
85: void dev_stop(struct dev *);
86: void dev_clear(struct dev *);
1.71 ratchov 87: void dev_onmove(void *, int);
1.66 ratchov 88: int devctl_open(struct dev *, struct devctl *);
1.57 ratchov 89:
90: struct dev *dev_list = NULL;
1.79 ratchov 91: unsigned int dev_sndnum = 0, dev_thrnum = 0;
1.68 ratchov 92:
93: #ifdef DEBUG
94: void
95: dev_dbg(struct dev *d)
96: {
97: if (d->num >= DEV_NMAX) {
98: dbg_puts("thr");
99: dbg_putu(d->num - DEV_NMAX);
100: } else {
101: dbg_puts("snd");
102: dbg_putu(d->num);
103: }
104: }
105: #endif
1.38 ratchov 106:
107: /*
1.51 ratchov 108: * Create a sndio device
1.28 ratchov 109: */
1.57 ratchov 110: struct dev *
1.79 ratchov 111: dev_new(char *path, unsigned int mode, unsigned int bufsz, unsigned int round,
112: unsigned int hold, unsigned int autovol)
1.57 ratchov 113: {
114: struct dev *d;
1.79 ratchov 115: unsigned int *pnum, i;
1.57 ratchov 116:
1.68 ratchov 117: pnum = (mode & MODE_THRU) ? &dev_thrnum : &dev_sndnum;
118: if (*pnum == DEV_NMAX) {
119: #ifdef DEBUG
120: if (debug_level >= 1)
121: dbg_puts("too many devices\n");
122: #endif
123: return NULL;
1.78 ratchov 124: }
125: d = malloc(sizeof(struct dev));
126: if (d == NULL) {
127: perror("malloc");
128: exit(1);
1.68 ratchov 129: }
130: d->num = (*pnum)++;
131: if (mode & MODE_THRU)
132: d->num += DEV_NMAX;
1.66 ratchov 133: d->ctl_list = NULL;
1.57 ratchov 134: d->path = path;
135: d->reqmode = mode;
1.67 ratchov 136: aparams_init(&d->reqopar, NCHAN_MAX, 0, 0);
137: aparams_init(&d->reqipar, NCHAN_MAX, 0, 0);
1.57 ratchov 138: d->reqbufsz = bufsz;
139: d->reqround = round;
140: d->hold = hold;
1.65 ratchov 141: d->autovol = autovol;
1.67 ratchov 142: d->autostart = 0;
1.72 ratchov 143: d->refcnt = 0;
1.57 ratchov 144: d->pstate = DEV_CLOSED;
1.71 ratchov 145: d->serial = 0;
146: for (i = 0; i < CTL_NSLOT; i++) {
147: d->slot[i].unit = i;
148: d->slot[i].ops = NULL;
149: d->slot[i].vol = MIDI_MAXCTL;
150: d->slot[i].tstate = CTL_OFF;
151: d->slot[i].serial = d->serial++;
152: d->slot[i].name[0] = '\0';
153: }
1.77 ratchov 154: d->master = MIDI_MAXCTL;
1.71 ratchov 155: d->origin = 0;
156: d->tstate = CTL_STOP;
1.57 ratchov 157: d->next = dev_list;
1.68 ratchov 158: dev_list = d;
1.57 ratchov 159: return d;
1.28 ratchov 160: }
1.24 ratchov 161:
162: /*
1.67 ratchov 163: * adjust device parameters and mode
1.24 ratchov 164: */
1.67 ratchov 165: void
1.79 ratchov 166: dev_adjpar(struct dev *d, unsigned int mode,
1.67 ratchov 167: struct aparams *ipar, struct aparams *opar)
1.24 ratchov 168: {
1.67 ratchov 169: d->reqmode |= (mode | MODE_MIDIMASK);
170: if (mode & MODE_REC)
171: aparams_grow(&d->reqipar, ipar);
172: if (mode & MODE_PLAY)
173: aparams_grow(&d->reqopar, opar);
1.24 ratchov 174: }
1.1 ratchov 175:
1.51 ratchov 176: /*
1.67 ratchov 177: * Initialize the device with the current parameters
1.51 ratchov 178: */
1.67 ratchov 179: int
180: dev_init(struct dev *d)
1.1 ratchov 181: {
1.67 ratchov 182: if ((d->reqmode & (MODE_AUDIOMASK | MODE_MIDIMASK)) == 0) {
183: #ifdef DEBUG
1.68 ratchov 184: dev_dbg(d);
1.67 ratchov 185: dbg_puts(": has no streams, skipped\n");
186: #endif
187: return 1;
188: }
189: if (d->hold && d->pstate == DEV_CLOSED && !dev_open(d)) {
190: dev_del(d);
191: return 0;
1.57 ratchov 192: }
1.67 ratchov 193: return 1;
1.1 ratchov 194: }
195:
196: /*
1.66 ratchov 197: * Add a MIDI port to the device
198: */
199: int
1.79 ratchov 200: devctl_add(struct dev *d, char *path, unsigned int mode)
1.66 ratchov 201: {
202: struct devctl *c;
203:
204: c = malloc(sizeof(struct devctl));
205: if (c == NULL) {
206: perror("malloc");
207: exit(1);
208: }
1.68 ratchov 209: c->path = path;
1.66 ratchov 210: c->mode = mode;
211: c->next = d->ctl_list;
212: d->ctl_list = c;
1.67 ratchov 213: if (d->pstate != DEV_CLOSED && !devctl_open(d, c))
214: return 0;
1.66 ratchov 215: return 1;
216: }
217:
218: /*
219: * Open a MIDI device and connect it to the thru box
220: */
221: int
222: devctl_open(struct dev *d, struct devctl *c)
223: {
224: struct file *f;
225: struct abuf *rbuf = NULL, *wbuf = NULL;
226: struct aproc *rproc, *wproc;
227:
228: f = (struct file *)miofile_new(&miofile_ops, c->path, c->mode);
229: if (f == NULL)
230: return 0;
231: if (c->mode & MODE_MIDIIN) {
232: rproc = rfile_new(f);
233: rbuf = abuf_new(MIDI_BUFSZ, &aparams_none);
234: aproc_setout(rproc, rbuf);
235: }
236: if (c->mode & MODE_MIDIOUT) {
237: wproc = wfile_new(f);
238: wbuf = abuf_new(MIDI_BUFSZ, &aparams_none);
239: aproc_setin(wproc, wbuf);
240: }
241: dev_midiattach(d, rbuf, wbuf);
242: return 1;
243: }
244:
245: /*
1.51 ratchov 246: * Open the device with the dev_reqxxx capabilities. Setup a mixer, demuxer,
247: * monitor, midi control, and any necessary conversions.
1.1 ratchov 248: */
1.26 ratchov 249: int
1.57 ratchov 250: dev_open(struct dev *d)
1.1 ratchov 251: {
1.23 ratchov 252: struct file *f;
1.66 ratchov 253: struct devctl *c;
1.51 ratchov 254: struct aparams par;
1.1 ratchov 255: struct aproc *conv;
256: struct abuf *buf;
1.79 ratchov 257: unsigned int siomode, cmin, cmax, rate;
1.51 ratchov 258:
1.57 ratchov 259: d->mode = d->reqmode;
260: d->round = d->reqround;
261: d->bufsz = d->reqbufsz;
262: d->ipar = d->reqipar;
263: d->opar = d->reqopar;
264: d->rec = NULL;
265: d->play = NULL;
266: d->mon = NULL;
1.61 jakemsr 267: d->mix = NULL;
268: d->sub = NULL;
1.57 ratchov 269: d->submon = NULL;
1.61 jakemsr 270: d->midi = NULL;
1.57 ratchov 271: d->rate = 0;
1.36 ratchov 272:
1.67 ratchov 273: if (d->opar.cmin > d->opar.cmax) {
274: d->opar.cmin = 0;
275: d->opar.cmax = 1;
276: }
277: if (d->ipar.cmin > d->ipar.cmax) {
278: d->ipar.cmin = 0;
279: d->ipar.cmax = 1;
280: }
281: if (d->opar.rate > d->ipar.rate)
282: d->ipar.rate = d->opar.rate;
283: else
284: d->opar.rate = d->ipar.rate;
285: if (d->opar.rate == 0)
1.76 ratchov 286: d->opar.rate = d->ipar.rate = 48000; /* XXX */
1.67 ratchov 287:
288: if (d->mode & MODE_THRU)
289: d->mode &= ~MODE_AUDIOMASK;
290:
1.3 ratchov 291: /*
1.51 ratchov 292: * If needed, open the device (ie create dev_rec and dev_play)
1.3 ratchov 293: */
1.57 ratchov 294: if ((d->mode & (MODE_PLAY | MODE_REC)) && !(d->mode & MODE_LOOP)) {
295: siomode = d->mode & (MODE_PLAY | MODE_REC);
1.51 ratchov 296: f = (struct file *)siofile_new(&siofile_ops,
1.57 ratchov 297: d->path,
1.51 ratchov 298: &siomode,
1.57 ratchov 299: &d->ipar,
300: &d->opar,
301: &d->bufsz,
302: &d->round);
1.51 ratchov 303: if (f == NULL) {
1.39 ratchov 304: #ifdef DEBUG
1.51 ratchov 305: if (debug_level >= 1) {
1.68 ratchov 306: dev_dbg(d);
307: dbg_puts(": ");
1.62 ratchov 308: dbg_puts(d->path);
1.51 ratchov 309: dbg_puts(": failed to open audio device\n");
310: }
311: #endif
312: return 0;
1.39 ratchov 313: }
1.51 ratchov 314: if (!(siomode & MODE_PLAY))
1.57 ratchov 315: d->mode &= ~(MODE_PLAY | MODE_MON);
1.51 ratchov 316: if (!(siomode & MODE_REC))
1.57 ratchov 317: d->mode &= ~MODE_REC;
318: if ((d->mode & (MODE_PLAY | MODE_REC)) == 0) {
1.51 ratchov 319: #ifdef DEBUG
320: if (debug_level >= 1) {
1.68 ratchov 321: dev_dbg(d);
1.51 ratchov 322: dbg_puts(": mode not supported by device\n");
323: }
1.39 ratchov 324: #endif
1.51 ratchov 325: return 0;
326: }
1.57 ratchov 327: d->rate = d->mode & MODE_REC ? d->ipar.rate : d->opar.rate;
1.67 ratchov 328: if (d->mode & MODE_REC) {
329: d->rec = rsio_new(f);
330: d->rec->refs++;
331: }
332: if (d->mode & MODE_PLAY) {
333: d->play = wsio_new(f);
334: d->play->refs++;
335: }
336: }
337: if (d->mode & MODE_LOOP) {
338: if (d->mode & MODE_MON) {
1.39 ratchov 339: #ifdef DEBUG
1.67 ratchov 340: if (debug_level >= 1) {
341: dbg_puts("monitoring not allowed "
342: "in loopback mode\n");
1.51 ratchov 343: }
1.67 ratchov 344: #endif
345: return 0;
346: }
347: if ((d->mode & MODE_PLAYREC) != MODE_PLAYREC) {
348: #ifdef DEBUG
349: if (debug_level >= 1) {
350: dbg_puts("both play and record streams "
351: "required in loopback mode\n");
1.51 ratchov 352: }
1.67 ratchov 353: #endif
354: return 0;
1.39 ratchov 355: }
1.67 ratchov 356: if (d->ctl_list) {
357: #ifdef DEBUG
358: if (debug_level >= 1) {
359: dbg_puts("MIDI control not allowed "
360: "in loopback mode\n");
361: }
1.39 ratchov 362: #endif
1.67 ratchov 363: return 0;
364: }
365: cmin = (d->ipar.cmin < d->opar.cmin) ?
366: d->ipar.cmin : d->opar.cmin;
367: cmax = (d->ipar.cmax > d->opar.cmax) ?
368: d->ipar.cmax : d->opar.cmax;
369: rate = (d->ipar.rate > d->opar.rate) ?
370: d->ipar.rate : d->opar.rate;
371: aparams_init(&par, cmin, cmax, rate);
372: d->ipar = par;
373: d->opar = par;
374: d->rate = rate;
1.81 ratchov 375: /*
376: * block sizes in the resampling code are limited to
377: * 2^15, so use 1/15 of the rate, since all standard
378: * sample rates are multiple of 15
379: */
380: d->round = rate / 15;
1.67 ratchov 381: d->bufsz = 2 * d->round;
382: }
383: #ifdef DEBUG
384: if (debug_level >= 2) {
1.57 ratchov 385: if (d->mode & MODE_REC) {
1.68 ratchov 386: dev_dbg(d);
1.67 ratchov 387: dbg_puts(": recording ");
388: aparams_dbg(&d->ipar);
389: dbg_puts("\n");
1.57 ratchov 390: }
391: if (d->mode & MODE_PLAY) {
1.68 ratchov 392: dev_dbg(d);
1.67 ratchov 393: dbg_puts(": playing ");
394: aparams_dbg(&d->opar);
395: dbg_puts("\n");
1.51 ratchov 396: }
1.3 ratchov 397: }
1.67 ratchov 398: #endif
1.11 ratchov 399: /*
1.51 ratchov 400: * Create the midi control end, or a simple thru box
401: * if there's no device
402: */
1.64 ratchov 403: if (d->mode & MODE_MIDIMASK) {
1.73 ratchov 404: d->midi = midi_new("midi", (d->mode & MODE_THRU) ? NULL : d);
1.64 ratchov 405: d->midi->refs++;
406: }
1.51 ratchov 407:
408: /*
409: * Create mixer, demuxer and monitor
1.1 ratchov 410: */
1.57 ratchov 411: if (d->mode & MODE_PLAY) {
1.77 ratchov 412: d->mix = mix_new("play", d->bufsz, d->round,
413: d->autovol, MIDI_TO_ADATA(d->master));
1.57 ratchov 414: d->mix->refs++;
415: }
416: if (d->mode & MODE_REC) {
417: d->sub = sub_new("rec", d->bufsz, d->round);
418: d->sub->refs++;
1.51 ratchov 419: }
1.57 ratchov 420: if (d->mode & MODE_LOOP) {
1.51 ratchov 421: /*
422: * connect mixer out to demuxer in
423: */
1.57 ratchov 424: buf = abuf_new(d->bufsz, &d->opar);
425: aproc_setout(d->mix, buf);
426: aproc_setin(d->sub, buf);
427:
428: d->mix->flags |= APROC_QUIT;
429: d->sub->flags |= APROC_QUIT;
1.51 ratchov 430: }
1.57 ratchov 431: if (d->rec) {
432: aparams_init(&par, d->ipar.cmin, d->ipar.cmax, d->rate);
1.51 ratchov 433:
1.1 ratchov 434: /*
1.51 ratchov 435: * Create device <-> demuxer buffer
1.1 ratchov 436: */
1.57 ratchov 437: buf = abuf_new(d->bufsz, &d->ipar);
438: aproc_setout(d->rec, buf);
1.1 ratchov 439:
440: /*
1.51 ratchov 441: * Insert a converter, if needed.
1.1 ratchov 442: */
1.57 ratchov 443: if (!aparams_eqenc(&d->ipar, &par)) {
444: conv = dec_new("rec", &d->ipar);
1.1 ratchov 445: aproc_setin(conv, buf);
1.57 ratchov 446: buf = abuf_new(d->round, &par);
1.1 ratchov 447: aproc_setout(conv, buf);
448: }
1.57 ratchov 449: d->ipar = par;
450: aproc_setin(d->sub, buf);
1.1 ratchov 451: }
1.57 ratchov 452: if (d->play) {
453: aparams_init(&par, d->opar.cmin, d->opar.cmax, d->rate);
1.1 ratchov 454:
455: /*
1.51 ratchov 456: * Create device <-> mixer buffer
1.1 ratchov 457: */
1.57 ratchov 458: buf = abuf_new(d->bufsz, &d->opar);
459: aproc_setin(d->play, buf);
1.25 ratchov 460:
1.1 ratchov 461: /*
1.27 ratchov 462: * Append a converter, if needed.
1.1 ratchov 463: */
1.57 ratchov 464: if (!aparams_eqenc(&par, &d->opar)) {
465: conv = enc_new("play", &d->opar);
1.1 ratchov 466: aproc_setout(conv, buf);
1.57 ratchov 467: buf = abuf_new(d->round, &par);
1.1 ratchov 468: aproc_setin(conv, buf);
469: }
1.57 ratchov 470: d->opar = par;
471: aproc_setout(d->mix, buf);
1.1 ratchov 472: }
1.57 ratchov 473: if (d->mode & MODE_MON) {
474: d->mon = mon_new("mon", d->bufsz);
475: d->mon->refs++;
476: buf = abuf_new(d->bufsz, &d->opar);
477: aproc_setout(d->mon, buf);
1.46 ratchov 478:
479: /*
480: * Append a "sub" to which clients will connect.
481: */
1.57 ratchov 482: d->submon = sub_new("mon", d->bufsz, d->round);
483: d->submon->refs++;
484: aproc_setin(d->submon, buf);
1.46 ratchov 485:
486: /*
1.51 ratchov 487: * Attach to the mixer
1.46 ratchov 488: */
1.57 ratchov 489: d->mix->u.mix.mon = d->mon;
490: d->mon->refs++;
1.46 ratchov 491: }
1.39 ratchov 492: #ifdef DEBUG
1.51 ratchov 493: if (debug_level >= 2) {
1.57 ratchov 494: if (d->mode & (MODE_PLAY | MODE_RECMASK)) {
1.68 ratchov 495: dev_dbg(d);
1.62 ratchov 496: dbg_puts(": block size is ");
1.57 ratchov 497: dbg_putu(d->round);
1.51 ratchov 498: dbg_puts(" frames, using ");
1.57 ratchov 499: dbg_putu(d->bufsz / d->round);
1.51 ratchov 500: dbg_puts(" blocks\n");
501: }
1.39 ratchov 502: }
503: #endif
1.57 ratchov 504: d->pstate = DEV_INIT;
1.66 ratchov 505: for (c = d->ctl_list; c != NULL; c = c->next) {
506: if (!devctl_open(d, c)) {
507: #ifdef DEBUG
508: if (debug_level >= 1) {
509: dbg_puts(c->path);
510: dbg_puts(": couldn't open MIDI port\n");
511: }
512: #endif
513: dev_close(d);
514: return 0;
515: }
516: }
1.26 ratchov 517: return 1;
1.1 ratchov 518: }
519:
520: /*
1.27 ratchov 521: * Cleanly stop and drain everything and close the device
522: * once both play chain and record chain are gone.
1.1 ratchov 523: */
524: void
1.57 ratchov 525: dev_close(struct dev *d)
1.1 ratchov 526: {
527: struct file *f;
528:
1.50 ratchov 529: /*
530: * if the device is starting, ensure it actually starts
531: * so buffers are drained, else clear any buffers
532: */
1.57 ratchov 533: switch (d->pstate) {
1.50 ratchov 534: case DEV_START:
535: #ifdef DEBUG
1.69 ratchov 536: if (debug_level >= 3) {
537: dev_dbg(d);
538: dbg_puts(": draining device\n");
539: }
1.50 ratchov 540: #endif
1.57 ratchov 541: dev_start(d);
1.50 ratchov 542: break;
543: case DEV_INIT:
544: #ifdef DEBUG
1.69 ratchov 545: if (debug_level >= 3) {
546: dev_dbg(d);
547: dbg_puts(": flushing device\n");
548: }
1.50 ratchov 549: #endif
1.57 ratchov 550: dev_clear(d);
1.50 ratchov 551: break;
552: }
1.39 ratchov 553: #ifdef DEBUG
1.69 ratchov 554: if (debug_level >= 2) {
555: dev_dbg(d);
556: dbg_puts(": closing device\n");
557: }
1.39 ratchov 558: #endif
1.70 ratchov 559: d->pstate = DEV_CLOSED;
1.57 ratchov 560: if (d->mix) {
1.3 ratchov 561: /*
1.32 ratchov 562: * Put the mixer in ``autoquit'' state and generate
563: * EOF on all inputs connected it. Once buffers are
564: * drained the mixer will terminate and shutdown the
565: * device.
1.3 ratchov 566: *
567: * NOTE: since file_eof() can destroy the file and
568: * reorder the file_list, we have to restart the loop
1.27 ratchov 569: * after each call to file_eof().
1.3 ratchov 570: */
1.57 ratchov 571: if (APROC_OK(d->mix))
572: mix_quit(d->mix);
1.51 ratchov 573:
574: /*
575: * XXX: handle this in mix_done()
576: */
1.57 ratchov 577: if (APROC_OK(d->mix->u.mix.mon)) {
578: d->mix->u.mix.mon->refs--;
579: aproc_del(d->mix->u.mix.mon);
580: d->mix->u.mix.mon = NULL;
1.46 ratchov 581: }
1.32 ratchov 582: restart_mix:
1.3 ratchov 583: LIST_FOREACH(f, &file_list, entry) {
1.32 ratchov 584: if (f->rproc != NULL &&
1.57 ratchov 585: aproc_depend(d->mix, f->rproc)) {
1.3 ratchov 586: file_eof(f);
1.32 ratchov 587: goto restart_mix;
1.3 ratchov 588: }
589: }
1.59 ratchov 590: } else if (d->sub) {
1.3 ratchov 591: /*
1.32 ratchov 592: * Same as above, but since there's no mixer,
593: * we generate EOF on the record-end of the
594: * device.
595: */
596: restart_sub:
597: LIST_FOREACH(f, &file_list, entry) {
598: if (f->rproc != NULL &&
1.59 ratchov 599: aproc_depend(d->sub, f->rproc)) {
1.32 ratchov 600: file_eof(f);
601: goto restart_sub;
1.59 ratchov 602: }
603: }
604: } else if (d->submon) {
605: /*
606: * Same as above
607: */
608: restart_submon:
609: LIST_FOREACH(f, &file_list, entry) {
610: if (f->rproc != NULL &&
611: aproc_depend(d->submon, f->rproc)) {
612: file_eof(f);
613: goto restart_submon;
1.23 ratchov 614: }
1.32 ratchov 615: }
616: }
1.57 ratchov 617: if (d->midi) {
618: d->midi->flags |= APROC_QUIT;
619: if (LIST_EMPTY(&d->midi->ins))
620: aproc_del(d->midi);
1.36 ratchov 621: restart_midi:
622: LIST_FOREACH(f, &file_list, entry) {
623: if (f->rproc &&
1.57 ratchov 624: aproc_depend(d->midi, f->rproc)) {
1.36 ratchov 625: file_eof(f);
626: goto restart_midi;
627: }
628: }
629: }
1.57 ratchov 630: if (d->mix) {
631: if (--d->mix->refs == 0 && (d->mix->flags & APROC_ZOMB))
632: aproc_del(d->mix);
633: d->mix = NULL;
634: }
635: if (d->play) {
636: if (--d->play->refs == 0 && (d->play->flags & APROC_ZOMB))
637: aproc_del(d->play);
638: d->play = NULL;
639: }
640: if (d->sub) {
641: if (--d->sub->refs == 0 && (d->sub->flags & APROC_ZOMB))
642: aproc_del(d->sub);
643: d->sub = NULL;
644: }
645: if (d->rec) {
646: if (--d->rec->refs == 0 && (d->rec->flags & APROC_ZOMB))
647: aproc_del(d->rec);
648: d->rec = NULL;
649: }
650: if (d->submon) {
651: if (--d->submon->refs == 0 && (d->submon->flags & APROC_ZOMB))
652: aproc_del(d->submon);
653: d->submon = NULL;
654: }
655: if (d->mon) {
656: if (--d->mon->refs == 0 && (d->mon->flags & APROC_ZOMB))
657: aproc_del(d->mon);
658: d->mon = NULL;
659: }
660: if (d->midi) {
661: if (--d->midi->refs == 0 && (d->midi->flags & APROC_ZOMB))
662: aproc_del(d->midi);
663: d->midi = NULL;
1.32 ratchov 664: }
1.51 ratchov 665: }
666:
667: /*
1.60 ratchov 668: * Unless the device is already in process of closing, request it to close
669: */
670: void
671: dev_drain(struct dev *d)
672: {
1.79 ratchov 673: unsigned int i;
1.71 ratchov 674: struct ctl_slot *s;
675:
676: for (i = 0, s = d->slot; i < CTL_NSLOT; i++, s++) {
677: if (s->ops)
678: s->ops->quit(s->arg);
679: }
1.60 ratchov 680: if (d->pstate != DEV_CLOSED)
681: dev_close(d);
682: }
683:
684: /*
1.51 ratchov 685: * Free the device
686: */
687: void
1.57 ratchov 688: dev_del(struct dev *d)
1.51 ratchov 689: {
1.57 ratchov 690: struct dev **p;
691:
1.60 ratchov 692: dev_drain(d);
1.57 ratchov 693: for (p = &dev_list; *p != d; p = &(*p)->next) {
694: #ifdef DEBUG
695: if (*p == NULL) {
696: dbg_puts("device to delete not on the list\n");
697: dbg_panic();
698: }
699: #endif
700: }
701: *p = d->next;
702: free(d);
1.51 ratchov 703: }
704:
705: /*
706: * Attach a bi-directional MIDI stream to the MIDI device
707: */
708: void
1.57 ratchov 709: dev_midiattach(struct dev *d, struct abuf *ibuf, struct abuf *obuf)
1.51 ratchov 710: {
711: if (ibuf)
1.57 ratchov 712: aproc_setin(d->midi, ibuf);
1.51 ratchov 713: if (obuf) {
1.57 ratchov 714: aproc_setout(d->midi, obuf);
1.51 ratchov 715: if (ibuf) {
716: ibuf->duplex = obuf;
717: obuf->duplex = ibuf;
718: }
1.1 ratchov 719: }
720: }
721:
1.79 ratchov 722: unsigned int
723: dev_roundof(struct dev *d, unsigned int newrate)
1.51 ratchov 724: {
1.57 ratchov 725: return (d->round * newrate + d->rate / 2) / d->rate;
1.51 ratchov 726: }
727:
1.1 ratchov 728: /*
1.27 ratchov 729: * Start the (paused) device. By default it's paused.
1.1 ratchov 730: */
731: void
1.57 ratchov 732: dev_start(struct dev *d)
1.1 ratchov 733: {
1.22 ratchov 734: struct file *f;
735:
1.46 ratchov 736: #ifdef DEBUG
737: if (debug_level >= 2)
1.51 ratchov 738: dbg_puts("starting device\n");
1.46 ratchov 739: #endif
1.57 ratchov 740: d->pstate = DEV_RUN;
741: if (d->mode & MODE_LOOP)
1.52 ratchov 742: return;
1.57 ratchov 743: if (APROC_OK(d->mix))
744: d->mix->flags |= APROC_DROP;
745: if (APROC_OK(d->sub))
746: d->sub->flags |= APROC_DROP;
747: if (APROC_OK(d->submon))
748: d->submon->flags |= APROC_DROP;
749: if (APROC_OK(d->play) && d->play->u.io.file) {
750: f = d->play->u.io.file;
1.71 ratchov 751: f->ops->start(f, dev_onmove, d);
1.57 ratchov 752: } else if (APROC_OK(d->rec) && d->rec->u.io.file) {
753: f = d->rec->u.io.file;
1.71 ratchov 754: f->ops->start(f, dev_onmove, d);
1.22 ratchov 755: }
1.1 ratchov 756: }
757:
758: /*
1.46 ratchov 759: * Pause the device. This may trigger context switches,
760: * so it shouldn't be called from aproc methods
1.1 ratchov 761: */
762: void
1.57 ratchov 763: dev_stop(struct dev *d)
1.1 ratchov 764: {
1.22 ratchov 765: struct file *f;
766:
1.52 ratchov 767: #ifdef DEBUG
1.69 ratchov 768: if (debug_level >= 2) {
769: dev_dbg(d);
770: dbg_puts(": device stopped\n");
771: }
1.52 ratchov 772: #endif
1.57 ratchov 773: d->pstate = DEV_INIT;
774: if (d->mode & MODE_LOOP)
1.52 ratchov 775: return;
1.57 ratchov 776: if (APROC_OK(d->play) && d->play->u.io.file) {
777: f = d->play->u.io.file;
1.22 ratchov 778: f->ops->stop(f);
1.57 ratchov 779: } else if (APROC_OK(d->rec) && d->rec->u.io.file) {
780: f = d->rec->u.io.file;
1.22 ratchov 781: f->ops->stop(f);
782: }
1.57 ratchov 783: if (APROC_OK(d->mix))
784: d->mix->flags &= ~APROC_DROP;
785: if (APROC_OK(d->sub))
786: d->sub->flags &= ~APROC_DROP;
787: if (APROC_OK(d->submon))
788: d->submon->flags &= ~APROC_DROP;
1.51 ratchov 789: }
790:
791: int
1.57 ratchov 792: dev_ref(struct dev *d)
1.51 ratchov 793: {
794: #ifdef DEBUG
1.69 ratchov 795: if (debug_level >= 3) {
796: dev_dbg(d);
797: dbg_puts(": device requested\n");
798: }
1.51 ratchov 799: #endif
1.57 ratchov 800: if (d->pstate == DEV_CLOSED && !dev_open(d)) {
801: if (d->hold)
802: dev_del(d);
1.51 ratchov 803: return 0;
1.57 ratchov 804: }
805: d->refcnt++;
1.51 ratchov 806: return 1;
807: }
808:
809: void
1.57 ratchov 810: dev_unref(struct dev *d)
1.51 ratchov 811: {
812: #ifdef DEBUG
1.69 ratchov 813: if (debug_level >= 3) {
814: dev_dbg(d);
815: dbg_puts(": device released\n");
816: }
1.51 ratchov 817: #endif
1.57 ratchov 818: d->refcnt--;
819: if (d->refcnt == 0 && d->pstate == DEV_INIT && !d->hold)
820: dev_close(d);
1.51 ratchov 821: }
822:
823: /*
824: * There are actions (like start/stop/close ... ) that may trigger aproc
825: * operations, a thus cannot be started from aproc context.
826: * To avoid problems, aprocs only change the s!tate of the device,
827: * and actual operations are triggered from the main loop,
828: * outside the aproc code path.
829: *
830: * The following routine invokes pending actions, returns 0
831: * on fatal error
832: */
833: int
1.57 ratchov 834: dev_run(struct dev *d)
1.51 ratchov 835: {
1.57 ratchov 836: if (d->pstate == DEV_CLOSED)
1.51 ratchov 837: return 1;
838: /*
839: * check if device isn't gone
840: */
1.57 ratchov 841: if (((d->mode & MODE_PLAY) && !APROC_OK(d->mix)) ||
842: ((d->mode & MODE_REC) && !APROC_OK(d->sub)) ||
843: ((d->mode & MODE_MON) && !APROC_OK(d->submon))) {
1.51 ratchov 844: #ifdef DEBUG
1.74 ratchov 845: if (debug_level >= 2) {
1.69 ratchov 846: dev_dbg(d);
847: dbg_puts(": device disappeared\n");
848: }
1.51 ratchov 849: #endif
1.57 ratchov 850: if (d->hold) {
851: dev_del(d);
852: return 0;
853: }
854: dev_close(d);
855: return 1;
1.51 ratchov 856: }
1.57 ratchov 857: switch (d->pstate) {
1.51 ratchov 858: case DEV_INIT:
859: /* nothing */
860: break;
861: case DEV_START:
1.57 ratchov 862: dev_start(d);
1.51 ratchov 863: /* PASSTHROUGH */
864: case DEV_RUN:
865: /*
866: * if the device is not used, then stop it
867: */
1.57 ratchov 868: if ((!APROC_OK(d->mix) ||
869: d->mix->u.mix.idle > 2 * d->bufsz) &&
870: (!APROC_OK(d->sub) ||
871: d->sub->u.sub.idle > 2 * d->bufsz) &&
872: (!APROC_OK(d->submon) ||
873: d->submon->u.sub.idle > 2 * d->bufsz) &&
874: (!APROC_OK(d->midi) ||
1.71 ratchov 875: d->tstate != CTL_RUN)) {
1.51 ratchov 876: #ifdef DEBUG
1.69 ratchov 877: if (debug_level >= 3) {
878: dev_dbg(d);
879: dbg_puts(": device idle, suspending\n");
880: }
1.46 ratchov 881: #endif
1.57 ratchov 882: dev_stop(d);
883: if (d->refcnt == 0 && !d->hold)
884: dev_close(d);
1.58 ratchov 885: else
1.57 ratchov 886: dev_clear(d);
1.51 ratchov 887: }
888: break;
889: }
890: return 1;
891: }
892:
893: /*
1.58 ratchov 894: * If the device is paused, then resume it.
1.51 ratchov 895: * This routine can be called from aproc context.
896: */
897: void
1.57 ratchov 898: dev_wakeup(struct dev *d)
1.51 ratchov 899: {
1.57 ratchov 900: if (d->pstate == DEV_INIT)
901: d->pstate = DEV_START;
1.1 ratchov 902: }
903:
904: /*
1.27 ratchov 905: * Find the end points connected to the mix/sub.
1.14 ratchov 906: */
907: int
1.57 ratchov 908: dev_getep(struct dev *d,
1.79 ratchov 909: unsigned int mode, struct abuf **sibuf, struct abuf **sobuf)
1.14 ratchov 910: {
911: struct abuf *ibuf, *obuf;
912:
1.46 ratchov 913: if (mode & MODE_PLAY) {
1.57 ratchov 914: if (!APROC_OK(d->mix))
1.46 ratchov 915: return 0;
1.14 ratchov 916: ibuf = *sibuf;
917: for (;;) {
918: if (!ibuf || !ibuf->rproc) {
1.39 ratchov 919: #ifdef DEBUG
920: if (debug_level >= 3) {
921: abuf_dbg(*sibuf);
922: dbg_puts(": not connected to device\n");
923: }
924: #endif
1.14 ratchov 925: return 0;
926: }
1.57 ratchov 927: if (ibuf->rproc == d->mix)
1.14 ratchov 928: break;
1.49 ratchov 929: ibuf = LIST_FIRST(&ibuf->rproc->outs);
1.14 ratchov 930: }
1.21 ratchov 931: *sibuf = ibuf;
1.14 ratchov 932: }
1.46 ratchov 933: if (mode & MODE_REC) {
1.57 ratchov 934: if (!APROC_OK(d->sub))
1.46 ratchov 935: return 0;
1.14 ratchov 936: obuf = *sobuf;
937: for (;;) {
938: if (!obuf || !obuf->wproc) {
1.39 ratchov 939: #ifdef DEBUG
940: if (debug_level >= 3) {
941: abuf_dbg(*sobuf);
942: dbg_puts(": not connected to device\n");
943: }
944: #endif
1.14 ratchov 945: return 0;
946: }
1.57 ratchov 947: if (obuf->wproc == d->sub)
1.14 ratchov 948: break;
1.49 ratchov 949: obuf = LIST_FIRST(&obuf->wproc->ins);
1.14 ratchov 950: }
1.21 ratchov 951: *sobuf = obuf;
1.14 ratchov 952: }
1.46 ratchov 953: if (mode & MODE_MON) {
1.57 ratchov 954: if (!APROC_OK(d->submon))
1.46 ratchov 955: return 0;
956: obuf = *sobuf;
957: for (;;) {
958: if (!obuf || !obuf->wproc) {
959: #ifdef DEBUG
960: if (debug_level >= 3) {
961: abuf_dbg(*sobuf);
962: dbg_puts(": not connected to device\n");
963: }
964: #endif
965: return 0;
966: }
1.57 ratchov 967: if (obuf->wproc == d->submon)
1.46 ratchov 968: break;
1.49 ratchov 969: obuf = LIST_FIRST(&obuf->wproc->ins);
1.46 ratchov 970: }
971: *sobuf = obuf;
972: }
1.14 ratchov 973: return 1;
974: }
975:
976: /*
1.27 ratchov 977: * Sync play buffer to rec buffer (for instance when one of
978: * them underruns/overruns).
1.1 ratchov 979: */
980: void
1.79 ratchov 981: dev_sync(struct dev *d, unsigned int mode,
982: struct abuf *ibuf, struct abuf *obuf)
1.1 ratchov 983: {
1.53 ratchov 984: int delta, offs;
1.57 ratchov 985: struct abuf *mbuf = NULL;
1.3 ratchov 986:
1.57 ratchov 987: if (!dev_getep(d, mode, &ibuf, &obuf))
1.3 ratchov 988: return;
989: /*
1.27 ratchov 990: * Calculate delta, the number of frames the play chain is ahead
1.3 ratchov 991: * of the record chain. It's necessary to schedule silences (or
992: * drops) in order to start playback and record in sync.
993: */
1.53 ratchov 994: offs = 0;
995: delta = 0;
1.57 ratchov 996: if (APROC_OK(d->mix)) {
997: mbuf = LIST_FIRST(&d->mix->outs);
1.53 ratchov 998: offs += mbuf->w.mix.todo;
1.57 ratchov 999: delta += d->mix->u.mix.lat;
1.53 ratchov 1000: }
1.57 ratchov 1001: if (APROC_OK(d->sub))
1002: delta += d->sub->u.sub.lat;
1.39 ratchov 1003: #ifdef DEBUG
1004: if (debug_level >= 3) {
1.69 ratchov 1005: dev_dbg(d);
1006: dbg_puts(": syncing device");
1.57 ratchov 1007: if (APROC_OK(d->mix)) {
1.51 ratchov 1008: dbg_puts(", ");
1.57 ratchov 1009: aproc_dbg(d->mix);
1.53 ratchov 1010: dbg_puts(": todo = ");
1011: dbg_putu(mbuf->w.mix.todo);
1012: dbg_puts(": lat = ");
1.57 ratchov 1013: dbg_putu(d->mix->u.mix.lat);
1.46 ratchov 1014: }
1.57 ratchov 1015: if (APROC_OK(d->sub)) {
1.51 ratchov 1016: dbg_puts(", ");
1.57 ratchov 1017: aproc_dbg(d->sub);
1.53 ratchov 1018: dbg_puts(": lat = ");
1.57 ratchov 1019: dbg_putu(d->sub->u.sub.lat);
1.46 ratchov 1020: }
1.39 ratchov 1021: dbg_puts("\n");
1022: }
1023: #endif
1.53 ratchov 1024: if (mode & MODE_PLAY)
1025: mix_drop(ibuf, -offs);
1026: if (mode & MODE_RECMASK)
1027: sub_silence(obuf, -(offs + delta));
1.36 ratchov 1028: }
1029:
1030: /*
1031: * return the current latency (in frames), ie the latency that
1032: * a stream would have if dev_attach() is called on it.
1.71 ratchov 1033: *
1.79 ratchov 1034: * XXX: return a "unsigned int", since result is always positive, isn't it?
1.36 ratchov 1035: */
1036: int
1.57 ratchov 1037: dev_getpos(struct dev *d)
1.36 ratchov 1038: {
1.53 ratchov 1039: struct abuf *mbuf = NULL;
1.36 ratchov 1040:
1.57 ratchov 1041: if (APROC_OK(d->mix)) {
1042: mbuf = LIST_FIRST(&d->mix->outs);
1043: return -(mbuf->w.mix.todo + d->mix->u.mix.lat);
1.54 ratchov 1044: } else
1045: return 0;
1.1 ratchov 1046: }
1047:
1048: /*
1.27 ratchov 1049: * Attach the given input and output buffers to the mixer and the
1.1 ratchov 1050: * multiplexer respectively. The operation is done synchronously, so
1051: * both buffers enter in sync. If buffers do not match play
1.27 ratchov 1052: * and rec.
1.1 ratchov 1053: */
1054: void
1.79 ratchov 1055: dev_attach(struct dev *d, char *name, unsigned int mode,
1056: struct abuf *ibuf, struct aparams *sipar, unsigned int inch,
1057: struct abuf *obuf, struct aparams *sopar, unsigned int onch,
1058: unsigned int xrun, int vol)
1.1 ratchov 1059: {
1.12 ratchov 1060: struct aparams ipar, opar;
1.1 ratchov 1061: struct aproc *conv;
1.79 ratchov 1062: unsigned int round, nblk, nch;
1.20 ratchov 1063:
1.46 ratchov 1064: #ifdef DEBUG
1.57 ratchov 1065: if ((!APROC_OK(d->mix) && (mode & MODE_PLAY)) ||
1066: (!APROC_OK(d->sub) && (mode & MODE_REC)) ||
1067: (!APROC_OK(d->submon) && (mode & MODE_MON))) {
1.69 ratchov 1068: dev_dbg(d);
1069: dbg_puts(": mode beyond device mode, not attaching\n");
1.46 ratchov 1070: return;
1071: }
1072: #endif
1073: if (mode & MODE_PLAY) {
1.12 ratchov 1074: ipar = *sipar;
1.57 ratchov 1075: nblk = (d->bufsz / d->round + 3) / 4;
1076: round = dev_roundof(d, ipar.rate);
1.48 ratchov 1077: nch = ipar.cmax - ipar.cmin + 1;
1.57 ratchov 1078: if (!aparams_eqenc(&ipar, &d->opar)) {
1.10 ratchov 1079: conv = dec_new(name, &ipar);
1.57 ratchov 1080: ipar.bps = d->opar.bps;
1081: ipar.bits = d->opar.bits;
1082: ipar.sig = d->opar.sig;
1083: ipar.le = d->opar.le;
1084: ipar.msb = d->opar.msb;
1.25 ratchov 1085: aproc_setin(conv, ibuf);
1.20 ratchov 1086: ibuf = abuf_new(nblk * round, &ipar);
1.9 ratchov 1087: aproc_setout(conv, ibuf);
1.8 ratchov 1088: }
1.48 ratchov 1089: if (inch > 0 && nch >= inch * 2) {
1090: conv = join_new(name);
1091: aproc_setin(conv, ibuf);
1092: ipar.cmax = ipar.cmin + inch - 1;
1093: ibuf = abuf_new(nblk * round, &ipar);
1094: aproc_setout(conv, ibuf);
1095: }
1.57 ratchov 1096: if (!aparams_eqrate(&ipar, &d->opar)) {
1097: conv = resamp_new(name, round, d->round);
1098: ipar.rate = d->opar.rate;
1099: round = d->round;
1.5 ratchov 1100: aproc_setin(conv, ibuf);
1.20 ratchov 1101: ibuf = abuf_new(nblk * round, &ipar);
1.5 ratchov 1102: aproc_setout(conv, ibuf);
1.1 ratchov 1103: }
1.48 ratchov 1104: if (inch > 0 && nch * 2 <= inch) {
1105: conv = join_new(name);
1106: aproc_setin(conv, ibuf);
1107: ipar.cmax = ipar.cmin + inch - 1;
1108: ibuf = abuf_new(nblk * round, &ipar);
1109: aproc_setout(conv, ibuf);
1110: }
1.57 ratchov 1111: aproc_setin(d->mix, ibuf);
1.46 ratchov 1112: ibuf->r.mix.xrun = xrun;
1.31 ratchov 1113: ibuf->r.mix.maxweight = vol;
1.57 ratchov 1114: mix_setmaster(d->mix);
1.1 ratchov 1115: }
1.46 ratchov 1116: if (mode & MODE_REC) {
1.12 ratchov 1117: opar = *sopar;
1.57 ratchov 1118: round = dev_roundof(d, opar.rate);
1119: nblk = (d->bufsz / d->round + 3) / 4;
1.48 ratchov 1120: nch = opar.cmax - opar.cmin + 1;
1.57 ratchov 1121: if (!aparams_eqenc(&opar, &d->ipar)) {
1.10 ratchov 1122: conv = enc_new(name, &opar);
1.57 ratchov 1123: opar.bps = d->ipar.bps;
1124: opar.bits = d->ipar.bits;
1125: opar.sig = d->ipar.sig;
1126: opar.le = d->ipar.le;
1127: opar.msb = d->ipar.msb;
1.9 ratchov 1128: aproc_setout(conv, obuf);
1.20 ratchov 1129: obuf = abuf_new(nblk * round, &opar);
1.9 ratchov 1130: aproc_setin(conv, obuf);
1.8 ratchov 1131: }
1.48 ratchov 1132: if (onch > 0 && nch >= onch * 2) {
1133: conv = join_new(name);
1134: aproc_setout(conv, obuf);
1135: opar.cmax = opar.cmin + onch - 1;
1136: obuf = abuf_new(nblk * round, &opar);
1137: aproc_setin(conv, obuf);
1138: }
1.57 ratchov 1139: if (!aparams_eqrate(&opar, &d->ipar)) {
1140: conv = resamp_new(name, d->round, round);
1141: opar.rate = d->ipar.rate;
1142: round = d->round;
1.1 ratchov 1143: aproc_setout(conv, obuf);
1.20 ratchov 1144: obuf = abuf_new(nblk * round, &opar);
1.1 ratchov 1145: aproc_setin(conv, obuf);
1146: }
1.48 ratchov 1147: if (onch > 0 && nch * 2 <= onch) {
1148: conv = join_new(name);
1149: aproc_setout(conv, obuf);
1150: opar.cmax = opar.cmin + onch - 1;
1151: obuf = abuf_new(nblk * round, &opar);
1152: aproc_setin(conv, obuf);
1153: }
1.57 ratchov 1154: aproc_setout(d->sub, obuf);
1.46 ratchov 1155: obuf->w.sub.xrun = xrun;
1156: }
1157: if (mode & MODE_MON) {
1158: opar = *sopar;
1.57 ratchov 1159: round = dev_roundof(d, opar.rate);
1160: nblk = (d->bufsz / d->round + 3) / 4;
1.48 ratchov 1161: nch = opar.cmax - opar.cmin + 1;
1.57 ratchov 1162: if (!aparams_eqenc(&opar, &d->opar)) {
1.46 ratchov 1163: conv = enc_new(name, &opar);
1.57 ratchov 1164: opar.bps = d->opar.bps;
1165: opar.bits = d->opar.bits;
1166: opar.sig = d->opar.sig;
1167: opar.le = d->opar.le;
1168: opar.msb = d->opar.msb;
1.46 ratchov 1169: aproc_setout(conv, obuf);
1170: obuf = abuf_new(nblk * round, &opar);
1171: aproc_setin(conv, obuf);
1172: }
1.48 ratchov 1173: if (onch > 0 && nch >= onch * 2) {
1174: conv = join_new(name);
1175: aproc_setout(conv, obuf);
1176: opar.cmax = opar.cmin + onch - 1;
1177: obuf = abuf_new(nblk * round, &opar);
1178: aproc_setin(conv, obuf);
1179: }
1.57 ratchov 1180: if (!aparams_eqrate(&opar, &d->opar)) {
1181: conv = resamp_new(name, d->round, round);
1182: opar.rate = d->opar.rate;
1183: round = d->round;
1.46 ratchov 1184: aproc_setout(conv, obuf);
1.48 ratchov 1185: obuf = abuf_new(nblk * round, &opar);
1186: aproc_setin(conv, obuf);
1187: }
1188: if (onch > 0 && nch * 2 <= onch) {
1189: conv = join_new(name);
1190: aproc_setout(conv, obuf);
1191: opar.cmax = opar.cmin + onch - 1;
1.46 ratchov 1192: obuf = abuf_new(nblk * round, &opar);
1193: aproc_setin(conv, obuf);
1194: }
1.57 ratchov 1195: aproc_setout(d->submon, obuf);
1.46 ratchov 1196: obuf->w.sub.xrun = xrun;
1.1 ratchov 1197: }
1198:
1199: /*
1.27 ratchov 1200: * Sync play to record.
1.1 ratchov 1201: */
1.46 ratchov 1202: if ((mode & MODE_PLAY) && (mode & MODE_RECMASK)) {
1.3 ratchov 1203: ibuf->duplex = obuf;
1204: obuf->duplex = ibuf;
1.13 ratchov 1205: }
1.57 ratchov 1206: dev_sync(d, mode, ibuf, obuf);
1.14 ratchov 1207: }
1208:
1209: /*
1.27 ratchov 1210: * Change the playback volume of the given stream.
1.14 ratchov 1211: */
1212: void
1.57 ratchov 1213: dev_setvol(struct dev *d, struct abuf *ibuf, int vol)
1.14 ratchov 1214: {
1.39 ratchov 1215: #ifdef DEBUG
1216: if (debug_level >= 3) {
1217: abuf_dbg(ibuf);
1218: dbg_puts(": setting volume to ");
1219: dbg_putu(vol);
1220: dbg_puts("\n");
1221: }
1222: #endif
1.57 ratchov 1223: if (!dev_getep(d, MODE_PLAY, &ibuf, NULL)) {
1.14 ratchov 1224: return;
1.16 ratchov 1225: }
1.31 ratchov 1226: ibuf->r.mix.vol = vol;
1.13 ratchov 1227: }
1228:
1229: /*
1.27 ratchov 1230: * Clear buffers of the play and record chains so that when the device
1231: * is started, playback and record start in sync.
1.13 ratchov 1232: */
1233: void
1.57 ratchov 1234: dev_clear(struct dev *d)
1.13 ratchov 1235: {
1236: struct abuf *buf;
1237:
1.57 ratchov 1238: if (APROC_OK(d->mix)) {
1.39 ratchov 1239: #ifdef DEBUG
1.57 ratchov 1240: if (!LIST_EMPTY(&d->mix->ins)) {
1.69 ratchov 1241: dev_dbg(d);
1242: dbg_puts(": play end not idle, can't clear device\n");
1.39 ratchov 1243: dbg_panic();
1244: }
1245: #endif
1.57 ratchov 1246: buf = LIST_FIRST(&d->mix->outs);
1.13 ratchov 1247: while (buf) {
1248: abuf_clear(buf);
1.49 ratchov 1249: buf = LIST_FIRST(&buf->rproc->outs);
1.13 ratchov 1250: }
1.57 ratchov 1251: mix_clear(d->mix);
1.13 ratchov 1252: }
1.57 ratchov 1253: if (APROC_OK(d->sub)) {
1.39 ratchov 1254: #ifdef DEBUG
1.57 ratchov 1255: if (!LIST_EMPTY(&d->sub->outs)) {
1.69 ratchov 1256: dev_dbg(d);
1257: dbg_puts(": record end not idle, can't clear device\n");
1.39 ratchov 1258: dbg_panic();
1259: }
1260: #endif
1.57 ratchov 1261: buf = LIST_FIRST(&d->sub->ins);
1.13 ratchov 1262: while (buf) {
1263: abuf_clear(buf);
1.49 ratchov 1264: buf = LIST_FIRST(&buf->wproc->ins);
1.13 ratchov 1265: }
1.57 ratchov 1266: sub_clear(d->sub);
1.40 ratchov 1267: }
1.57 ratchov 1268: if (APROC_OK(d->submon)) {
1.46 ratchov 1269: #ifdef DEBUG
1.57 ratchov 1270: if (!LIST_EMPTY(&d->submon->outs)) {
1.69 ratchov 1271: dev_dbg(d);
1272: dbg_puts(": monitoring end not idle, can't clear device\n");
1.46 ratchov 1273: dbg_panic();
1274: }
1275: #endif
1.57 ratchov 1276: buf = LIST_FIRST(&d->submon->ins);
1.46 ratchov 1277: while (buf) {
1278: abuf_clear(buf);
1.49 ratchov 1279: buf = LIST_FIRST(&buf->wproc->ins);
1.46 ratchov 1280: }
1.57 ratchov 1281: sub_clear(d->submon);
1282: mon_clear(d->mon);
1.1 ratchov 1283: }
1.71 ratchov 1284: }
1285:
1286: #ifdef DEBUG
1287: void
1288: dev_slotdbg(struct dev *d, int slot)
1289: {
1290: struct ctl_slot *s;
1291:
1292: if (slot < 0) {
1293: dbg_puts("none");
1294: } else {
1295: s = d->slot + slot;
1296: dbg_puts(s->name);
1297: dbg_putu(s->unit);
1298: dbg_puts("(");
1299: dbg_putu(s->vol);
1300: dbg_puts(")/");
1301: switch (s->tstate) {
1302: case CTL_OFF:
1303: dbg_puts("off");
1304: break;
1305: case CTL_RUN:
1306: dbg_puts("run");
1307: break;
1308: case CTL_START:
1309: dbg_puts("sta");
1310: break;
1311: case CTL_STOP:
1312: dbg_puts("stp");
1313: break;
1314: default:
1315: dbg_puts("unk");
1316: break;
1317: }
1318: }
1319: }
1320: #endif
1321:
1322: /*
1323: * find the best matching free slot index (ie midi channel).
1324: * return -1, if there are no free slots anymore
1325: */
1326: int
1327: dev_mkslot(struct dev *d, char *who)
1328: {
1329: char *s;
1330: struct ctl_slot *slot;
1331: char name[CTL_NAMEMAX];
1.79 ratchov 1332: unsigned int i, unit, umap = 0;
1333: unsigned int ser, bestser, bestidx;
1.71 ratchov 1334:
1335: /*
1336: * create a ``valid'' control name (lowcase, remove [^a-z], trucate)
1337: */
1338: for (i = 0, s = who; ; s++) {
1339: if (i == CTL_NAMEMAX - 1 || *s == '\0') {
1340: name[i] = '\0';
1341: break;
1342: } else if (*s >= 'A' && *s <= 'Z') {
1343: name[i++] = *s + 'a' - 'A';
1344: } else if (*s >= 'a' && *s <= 'z')
1345: name[i++] = *s;
1346: }
1347: if (i == 0)
1348: strlcpy(name, "noname", CTL_NAMEMAX);
1349:
1350: /*
1351: * find the instance number of the control name
1352: */
1353: for (i = 0, slot = d->slot; i < CTL_NSLOT; i++, slot++) {
1354: if (slot->ops == NULL)
1355: continue;
1356: if (strcmp(slot->name, name) == 0)
1.80 ratchov 1357: umap |= (1 << slot->unit);
1.71 ratchov 1358: }
1359: for (unit = 0; ; unit++) {
1360: if (unit == CTL_NSLOT) {
1361: #ifdef DEBUG
1362: if (debug_level >= 1) {
1363: dbg_puts(name);
1364: dbg_puts(": too many instances\n");
1365: }
1366: #endif
1367: return -1;
1368: }
1369: if ((umap & (1 << unit)) == 0)
1370: break;
1371: }
1372:
1373: /*
1374: * find a free controller slot with the same name/unit
1375: */
1376: for (i = 0, slot = d->slot; i < CTL_NSLOT; i++, slot++) {
1377: if (slot->ops == NULL &&
1378: strcmp(slot->name, name) == 0 &&
1379: slot->unit == unit) {
1380: #ifdef DEBUG
1381: if (debug_level >= 3) {
1382: dbg_puts(name);
1383: dbg_putu(unit);
1384: dbg_puts(": found slot ");
1385: dbg_putu(i);
1386: dbg_puts("\n");
1387: }
1388: #endif
1389: return i;
1390: }
1391: }
1392:
1393: /*
1394: * couldn't find a matching slot, pick oldest free slot
1395: * and set its name/unit
1396: */
1397: bestser = 0;
1398: bestidx = CTL_NSLOT;
1399: for (i = 0, slot = d->slot; i < CTL_NSLOT; i++, slot++) {
1400: if (slot->ops != NULL)
1401: continue;
1402: ser = d->serial - slot->serial;
1403: if (ser > bestser) {
1404: bestser = ser;
1405: bestidx = i;
1406: }
1407: }
1408: if (bestidx == CTL_NSLOT) {
1409: #ifdef DEBUG
1410: if (debug_level >= 1) {
1411: dbg_puts(name);
1412: dbg_putu(unit);
1413: dbg_puts(": out of mixer slots\n");
1414: }
1415: #endif
1416: return -1;
1417: }
1418: slot = d->slot + bestidx;
1419: if (slot->name[0] != '\0')
1420: slot->vol = MIDI_MAXCTL;
1421: strlcpy(slot->name, name, CTL_NAMEMAX);
1422: slot->serial = d->serial++;
1423: slot->unit = unit;
1424: #ifdef DEBUG
1425: if (debug_level >= 3) {
1426: dbg_puts(name);
1427: dbg_putu(unit);
1428: dbg_puts(": overwritten slot ");
1429: dbg_putu(bestidx);
1430: dbg_puts("\n");
1431: }
1432: #endif
1433: return bestidx;
1434: }
1435:
1436: /*
1437: * allocate a new slot and register the given call-backs
1438: */
1439: int
1440: dev_slotnew(struct dev *d, char *who, struct ctl_ops *ops, void *arg, int mmc)
1441: {
1442: int slot;
1443: struct ctl_slot *s;
1444:
1445: slot = dev_mkslot(d, who);
1446: if (slot < 0)
1447: return -1;
1448:
1449: s = d->slot + slot;
1450: s->ops = ops;
1451: s->arg = arg;
1452: s->tstate = mmc ? CTL_STOP : CTL_OFF;
1453: s->ops->vol(s->arg, s->vol);
1454:
1455: if (APROC_OK(d->midi)) {
1.73 ratchov 1456: midi_send_slot(d->midi, slot);
1457: midi_send_vol(d->midi, slot, s->vol);
1458: midi_flush(d->midi);
1.71 ratchov 1459: } else {
1460: #ifdef DEBUG
1461: if (debug_level >= 2) {
1462: dev_slotdbg(d, slot);
1463: dbg_puts(": MIDI control not available\n");
1464: }
1465: #endif
1466: }
1467: return slot;
1468: }
1469:
1470: /*
1471: * release the given slot
1472: */
1473: void
1474: dev_slotdel(struct dev *d, int slot)
1475: {
1476: struct ctl_slot *s;
1477:
1478: s = d->slot + slot;
1479: s->ops = NULL;
1480: }
1481:
1482: /*
1483: * notifty the mixer that volume changed, called by whom allocad the slot using
1484: * ctl_slotnew(). Note: it doesn't make sens to call this from within the
1485: * call-back.
1486: *
1487: * XXX: set actual volume here and use only this interface. Now, this
1488: * can work because all streams have a slot
1489: */
1490: void
1.79 ratchov 1491: dev_slotvol(struct dev *d, int slot, unsigned int vol)
1.71 ratchov 1492: {
1493: #ifdef DEBUG
1494: if (debug_level >= 3) {
1495: dev_slotdbg(d, slot);
1496: dbg_puts(": changing volume to ");
1497: dbg_putu(vol);
1498: dbg_puts("\n");
1499: }
1500: #endif
1501: d->slot[slot].vol = vol;
1.73 ratchov 1502: if (APROC_OK(d->midi)) {
1503: midi_send_vol(d->midi, slot, vol);
1504: midi_flush(d->midi);
1.71 ratchov 1505: }
1506: }
1507:
1508: /*
1509: * check that all clients controlled by MMC are ready to start,
1510: * if so, start them all but the caller
1511: */
1512: int
1513: dev_try(struct dev *d, int slot)
1514: {
1.79 ratchov 1515: unsigned int i;
1.71 ratchov 1516: struct ctl_slot *s;
1517:
1518: if (d->tstate != CTL_START) {
1519: #ifdef DEBUG
1520: if (debug_level >= 3) {
1521: dev_slotdbg(d, slot);
1522: dbg_puts(": server not started, delayd\n");
1523: }
1524: #endif
1525: return 0;
1526: }
1527: for (i = 0, s = d->slot; i < CTL_NSLOT; i++, s++) {
1528: if (!s->ops || i == slot)
1529: continue;
1530: if (s->tstate != CTL_OFF && s->tstate != CTL_START) {
1531: #ifdef DEBUG
1532: if (debug_level >= 3) {
1533: dev_slotdbg(d, i);
1534: dbg_puts(": not ready, server delayed\n");
1535: }
1536: #endif
1537: return 0;
1538: }
1539: }
1540: for (i = 0, s = d->slot; i < CTL_NSLOT; i++, s++) {
1541: if (!s->ops || i == slot)
1542: continue;
1543: if (s->tstate == CTL_START) {
1544: #ifdef DEBUG
1545: if (debug_level >= 3) {
1546: dev_slotdbg(d, i);
1547: dbg_puts(": started\n");
1548: }
1549: #endif
1550: s->tstate = CTL_RUN;
1551: s->ops->start(s->arg);
1552: }
1553: }
1554: if (slot >= 0)
1555: d->slot[slot].tstate = CTL_RUN;
1556: d->tstate = CTL_RUN;
1.73 ratchov 1557: if (APROC_OK(d->midi)) {
1558: midi_send_full(d->midi,
1559: d->origin, d->rate, d->round, dev_getpos(d));
1560: midi_flush(d->midi);
1561: }
1.71 ratchov 1562: dev_wakeup(d);
1563: return 1;
1564: }
1565:
1566: /*
1567: * notify the MMC layer that the stream is attempting
1568: * to start. If other streams are not ready, 0 is returned meaning
1569: * that the stream should wait. If other streams are ready, they
1570: * are started, and the caller should start immediately.
1571: */
1572: int
1573: dev_slotstart(struct dev *d, int slot)
1574: {
1575: struct ctl_slot *s = d->slot + slot;
1576:
1577: if (s->tstate == CTL_OFF || d->tstate == CTL_OFF)
1578: return 1;
1579:
1580: /*
1581: * if the server already started (the client missed the
1582: * start rendez-vous) or the server is stopped, then
1583: * tag the client as ``wanting to start''
1584: */
1585: s->tstate = CTL_START;
1586: return dev_try(d, slot);
1587: }
1588:
1589: /*
1590: * notify the MMC layer that the stream no longer is trying to
1591: * start (or that it just stopped), meaning that its ``start'' call-back
1592: * shouldn't be called anymore
1593: */
1594: void
1595: dev_slotstop(struct dev *d, int slot)
1596: {
1597: struct ctl_slot *s = d->slot + slot;
1598:
1599: /*
1600: * tag the stream as not trying to start,
1601: * unless MMC is turned off
1602: */
1603: if (s->tstate != CTL_OFF)
1604: s->tstate = CTL_STOP;
1605: }
1606:
1607: /*
1608: * start all slots simultaneously
1609: */
1610: void
1611: dev_mmcstart(struct dev *d)
1612: {
1613: if (d->tstate == CTL_STOP) {
1614: d->tstate = CTL_START;
1615: (void)dev_try(d, -1);
1616: #ifdef DEBUG
1617: } else {
1618: if (debug_level >= 3) {
1619: dev_dbg(d);
1620: dbg_puts(": ignoring mmc start\n");
1621: }
1622: #endif
1623: }
1624: }
1625:
1626: /*
1627: * stop all slots simultaneously
1628: */
1629: void
1630: dev_mmcstop(struct dev *d)
1631: {
1.79 ratchov 1632: unsigned int i;
1.71 ratchov 1633: struct ctl_slot *s;
1634:
1635: switch (d->tstate) {
1636: case CTL_START:
1637: d->tstate = CTL_STOP;
1638: return;
1639: case CTL_RUN:
1640: d->tstate = CTL_STOP;
1641: break;
1642: default:
1643: #ifdef DEBUG
1644: if (debug_level >= 3) {
1645: dev_dbg(d);
1646: dbg_puts(": ignored mmc stop\n");
1647: }
1648: #endif
1649: return;
1650: }
1651: for (i = 0, s = d->slot; i < CTL_NSLOT; i++, s++) {
1652: if (!s->ops)
1653: continue;
1654: if (s->tstate == CTL_RUN) {
1655: #ifdef DEBUG
1656: if (debug_level >= 3) {
1657: dev_slotdbg(d, i);
1658: dbg_puts(": requested to stop\n");
1659: }
1660: #endif
1661: s->ops->stop(s->arg);
1662: }
1663: }
1664: }
1665:
1666: /*
1667: * relocate all slots simultaneously
1668: */
1669: void
1.79 ratchov 1670: dev_loc(struct dev *d, unsigned int origin)
1.71 ratchov 1671: {
1.79 ratchov 1672: unsigned int i;
1.71 ratchov 1673: struct ctl_slot *s;
1674:
1675: #ifdef DEBUG
1676: if (debug_level >= 2) {
1677: dbg_puts("server relocated to ");
1678: dbg_putu(origin);
1679: dbg_puts("\n");
1680: }
1681: #endif
1682: if (d->tstate == CTL_RUN)
1683: dev_mmcstop(d);
1684: d->origin = origin;
1685: for (i = 0, s = d->slot; i < CTL_NSLOT; i++, s++) {
1686: if (!s->ops)
1687: continue;
1688: s->ops->loc(s->arg, d->origin);
1689: }
1690: if (d->tstate == CTL_RUN)
1691: dev_mmcstart(d);
1692: }
1693:
1694: /*
1695: * called at every clock tick by the mixer, delta is positive, unless
1696: * there's an overrun/underrun
1697: */
1698: void
1699: dev_onmove(void *arg, int delta)
1700: {
1701: struct dev *d = (struct dev *)arg;
1702:
1703: /*
1704: * don't send ticks before the start signal
1705: */
1706: if (d->tstate != CTL_RUN)
1707: return;
1.73 ratchov 1708: if (APROC_OK(d->midi)) {
1709: midi_send_qfr(d->midi, d->rate, delta);
1.77 ratchov 1710: midi_flush(d->midi);
1711: }
1712: }
1713:
1714: void
1.79 ratchov 1715: dev_master(struct dev *d, unsigned int master)
1.77 ratchov 1716: {
1717: #ifdef DEBUG
1718: if (debug_level >= 3) {
1719: dev_dbg(d);
1720: dbg_puts(": changing master volume to ");
1721: dbg_putu(master);
1722: dbg_puts("\n");
1723: }
1724: #endif
1725: d->master = master;
1726: if (APROC_OK(d->mix)) {
1727: d->mix->u.mix.master = MIDI_TO_ADATA(master);
1728: mix_setmaster(d->mix);
1.73 ratchov 1729: }
1.1 ratchov 1730: }