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