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