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