Annotation of src/usr.bin/aucat/dev.c, Revision 1.47
1.47 ! ratchov 1: /* $OpenBSD: dev.c,v 1.46 2010/04/06 20:07:01 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.27 ratchov 17:
1.1 ratchov 18: #include <stdio.h>
19: #include <stdlib.h>
20: #include <unistd.h>
21:
22: #include "abuf.h"
23: #include "aproc.h"
1.27 ratchov 24: #include "conf.h"
25: #include "dev.h"
1.3 ratchov 26: #include "pipe.h"
1.38 ratchov 27: #include "miofile.h"
1.42 ratchov 28: #include "siofile.h"
1.28 ratchov 29: #include "midi.h"
1.46 ratchov 30: #include "opt.h"
1.39 ratchov 31: #ifdef DEBUG
32: #include "dbg.h"
33: #endif
1.1 ratchov 34:
1.46 ratchov 35: unsigned dev_pstate;
1.3 ratchov 36: unsigned dev_bufsz, dev_round, dev_rate;
1.1 ratchov 37: struct aparams dev_ipar, dev_opar;
1.46 ratchov 38: struct aproc *dev_mix, *dev_sub, *dev_rec, *dev_play, *dev_submon, *dev_mon;
1.28 ratchov 39: struct aproc *dev_midi;
40:
41: /*
42: * Create a MIDI thru box as the MIDI end of the device
43: */
44: void
45: dev_thruinit(void)
46: {
47: dev_midi = thru_new("thru");
48: dev_midi->refs++;
49: }
50:
51: /*
1.38 ratchov 52: * Open a MIDI device and connect it to the thru box
53: */
54: int
55: dev_thruadd(char *name, int in, int out)
56: {
57: struct file *f;
58: struct abuf *rbuf = NULL, *wbuf = NULL;
59: struct aproc *rproc, *wproc;
60:
61: f = (struct file *)miofile_new(&miofile_ops, name, in, out);
62: if (f == NULL)
63: return 0;
64: if (in) {
65: rproc = rfile_new(f);
66: rbuf = abuf_new(MIDI_BUFSZ, &aparams_none);
67: aproc_setout(rproc, rbuf);
68: }
69: if (out) {
70: wproc = wfile_new(f);
71: wbuf = abuf_new(MIDI_BUFSZ, &aparams_none);
72: aproc_setin(wproc, wbuf);
73: }
74: dev_midiattach(rbuf, wbuf);
75: return 1;
76: }
77:
78: /*
1.28 ratchov 79: * Attach a bi-directional MIDI stream to the MIDI device
80: */
81: void
82: dev_midiattach(struct abuf *ibuf, struct abuf *obuf)
83: {
84: if (ibuf)
85: aproc_setin(dev_midi, ibuf);
86: if (obuf) {
87: aproc_setout(dev_midi, obuf);
88: if (ibuf) {
89: ibuf->duplex = obuf;
90: obuf->duplex = ibuf;
91: }
92: }
93: }
1.24 ratchov 94:
95: /*
1.27 ratchov 96: * Same as dev_init(), but create a fake device that records what is
97: * played.
1.24 ratchov 98: */
99: void
100: dev_loopinit(struct aparams *dipar, struct aparams *dopar, unsigned bufsz)
101: {
102: struct abuf *buf;
103: struct aparams par;
104: unsigned cmin, cmax, rate;
105:
1.46 ratchov 106: /*
107: * in principle we don't need control, but the start-stop mechanism
108: * depend on it and it's simpler to reuse this mechanism rather than
109: * dealing with lots of special cases
110: */
111: dev_midi = ctl_new("ctl");
112: dev_midi->refs++;
113:
1.24 ratchov 114: cmin = (dipar->cmin < dopar->cmin) ? dipar->cmin : dopar->cmin;
115: cmax = (dipar->cmax > dopar->cmax) ? dipar->cmax : dopar->cmax;
116: rate = (dipar->rate > dopar->rate) ? dipar->rate : dopar->rate;
117: aparams_init(&par, cmin, cmax, rate);
118: dev_ipar = par;
119: dev_opar = par;
120: dev_round = (bufsz + 1) / 2;
121: dev_bufsz = dev_round * 2;
1.25 ratchov 122: dev_rate = rate;
1.24 ratchov 123: dev_rec = NULL;
124: dev_play = NULL;
1.46 ratchov 125: dev_mon = NULL;
126: dev_submon = NULL;
127: dev_pstate = DEV_INIT;
1.25 ratchov 128:
1.24 ratchov 129: buf = abuf_new(dev_bufsz, &par);
1.46 ratchov 130: dev_mix = mix_new("mix", dev_bufsz, 1, NULL);
1.24 ratchov 131: dev_mix->refs++;
1.46 ratchov 132: dev_sub = sub_new("sub", dev_bufsz, 1, NULL);
1.24 ratchov 133: dev_sub->refs++;
134: aproc_setout(dev_mix, buf);
135: aproc_setin(dev_sub, buf);
136:
1.36 ratchov 137: dev_mix->flags |= APROC_QUIT;
138: dev_sub->flags |= APROC_QUIT;
1.24 ratchov 139:
140: *dipar = dev_ipar;
141: *dopar = dev_opar;
142: }
1.1 ratchov 143:
1.20 ratchov 144: unsigned
145: dev_roundof(unsigned newrate)
1.1 ratchov 146: {
1.20 ratchov 147: return (dev_round * newrate + dev_rate / 2) / dev_rate;
1.1 ratchov 148: }
149:
150: /*
1.27 ratchov 151: * Open the device with the given hardware parameters and create a mixer
1.1 ratchov 152: * and a multiplexer connected to it with all necessary conversions
1.27 ratchov 153: * setup.
1.1 ratchov 154: */
1.26 ratchov 155: int
1.46 ratchov 156: dev_init(char *devpath, unsigned mode,
1.36 ratchov 157: struct aparams *dipar, struct aparams *dopar, unsigned bufsz, unsigned round)
1.1 ratchov 158: {
1.23 ratchov 159: struct file *f;
1.1 ratchov 160: struct aparams ipar, opar;
161: struct aproc *conv;
162: struct abuf *buf;
1.25 ratchov 163:
1.36 ratchov 164: dev_midi = ctl_new("ctl");
165: dev_midi->refs++;
166:
1.3 ratchov 167: /*
1.27 ratchov 168: * Ask for 1/4 of the buffer for the kernel ring and
169: * limit the block size to 1/4 of the requested buffer.
1.3 ratchov 170: */
1.36 ratchov 171: dev_round = round;
1.46 ratchov 172: dev_bufsz = bufsz;
1.42 ratchov 173: f = (struct file *)siofile_new(&siofile_ops, devpath,
1.46 ratchov 174: mode & (MODE_PLAY | MODE_REC), dipar, dopar,
175: &dev_bufsz, &dev_round);
1.23 ratchov 176: if (f == NULL)
1.26 ratchov 177: return 0;
1.46 ratchov 178: if (mode & MODE_REC) {
1.39 ratchov 179: #ifdef DEBUG
180: if (debug_level >= 2) {
181: dbg_puts("hw recording ");
182: aparams_dbg(dipar);
183: dbg_puts("\n");
184: }
185: #endif
1.20 ratchov 186: dev_rate = dipar->rate;
1.3 ratchov 187: }
1.46 ratchov 188: if (mode & MODE_PLAY) {
1.39 ratchov 189: #ifdef DEBUG
190: if (debug_level >= 2) {
191: dbg_puts("hw playing ");
192: aparams_dbg(dopar);
193: dbg_puts("\n");
194: }
195: #endif
1.20 ratchov 196: dev_rate = dopar->rate;
1.3 ratchov 197: }
1.11 ratchov 198:
199: /*
1.27 ratchov 200: * Create record chain.
1.1 ratchov 201: */
1.46 ratchov 202: if (mode & MODE_REC) {
1.1 ratchov 203: aparams_init(&ipar, dipar->cmin, dipar->cmax, dipar->rate);
204: /*
1.27 ratchov 205: * Create the read end.
1.1 ratchov 206: */
1.46 ratchov 207: dev_rec = rsio_new(f);
1.22 ratchov 208: dev_rec->refs++;
1.46 ratchov 209: buf = abuf_new(dev_bufsz, dipar);
1.1 ratchov 210: aproc_setout(dev_rec, buf);
211:
212: /*
1.27 ratchov 213: * Append a converter, if needed.
1.1 ratchov 214: */
1.4 ratchov 215: if (!aparams_eqenc(dipar, &ipar)) {
1.30 ratchov 216: conv = dec_new("rec", dipar);
1.1 ratchov 217: aproc_setin(conv, buf);
1.46 ratchov 218: buf = abuf_new(dev_round, &ipar);
1.1 ratchov 219: aproc_setout(conv, buf);
220: }
221: dev_ipar = ipar;
222:
223: /*
1.27 ratchov 224: * Append a "sub" to which clients will connect.
1.36 ratchov 225: * Link it to the controller only in record-only mode
1.1 ratchov 226: */
1.46 ratchov 227: dev_sub = sub_new("rec", dev_bufsz, dev_round,
228: dopar ? NULL : dev_midi);
1.22 ratchov 229: dev_sub->refs++;
1.1 ratchov 230: aproc_setin(dev_sub, buf);
231: } else {
232: dev_rec = NULL;
233: dev_sub = NULL;
234: }
235:
236: /*
1.27 ratchov 237: * Create play chain.
1.1 ratchov 238: */
1.46 ratchov 239: if (mode & MODE_PLAY) {
1.1 ratchov 240: aparams_init(&opar, dopar->cmin, dopar->cmax, dopar->rate);
241: /*
1.27 ratchov 242: * Create the write end.
1.1 ratchov 243: */
1.46 ratchov 244: dev_play = wsio_new(f);
1.22 ratchov 245: dev_play->refs++;
1.46 ratchov 246: buf = abuf_new(dev_bufsz, dopar);
1.1 ratchov 247: aproc_setin(dev_play, buf);
1.25 ratchov 248:
1.1 ratchov 249: /*
1.27 ratchov 250: * Append a converter, if needed.
1.1 ratchov 251: */
1.4 ratchov 252: if (!aparams_eqenc(&opar, dopar)) {
1.30 ratchov 253: conv = enc_new("play", dopar);
1.1 ratchov 254: aproc_setout(conv, buf);
1.46 ratchov 255: buf = abuf_new(dev_round, &opar);
1.1 ratchov 256: aproc_setin(conv, buf);
257: }
258: dev_opar = opar;
259:
260: /*
1.27 ratchov 261: * Append a "mix" to which clients will connect.
1.1 ratchov 262: */
1.46 ratchov 263: dev_mix = mix_new("play", dev_bufsz, dev_round, dev_midi);
1.22 ratchov 264: dev_mix->refs++;
1.1 ratchov 265: aproc_setout(dev_mix, buf);
266: } else {
267: dev_play = NULL;
268: dev_mix = NULL;
269: }
1.46 ratchov 270:
271: /*
272: * Create monitoring chain
273: */
274: if (mode & MODE_MON) {
275: dev_mon = mon_new("mon", dev_bufsz);
276: dev_mon->refs++;
277: buf = abuf_new(dev_bufsz, &dev_opar);
278: aproc_setout(dev_mon, buf);
279:
280: /*
281: * Append a "sub" to which clients will connect.
282: * Link it to the controller only in record-only mode
283: */
284: dev_submon = sub_new("mon", dev_bufsz, dev_round, NULL);
285: dev_submon->refs++;
286: aproc_setin(dev_submon, buf);
287:
288: /*
289: * Attack to the mixer
290: */
291: dev_mix->u.mix.mon = dev_mon;
292: dev_mon->refs++;
293: } else {
294: dev_submon = NULL;
295: if (APROC_OK(dev_mix))
296: dev_mix->u.mix.mon = NULL;
297: }
298:
1.39 ratchov 299: #ifdef DEBUG
300: if (debug_level >= 2) {
301: dbg_puts("device block size is ");
302: dbg_putu(dev_round);
303: dbg_puts(" frames, using ");
304: dbg_putu(dev_bufsz / dev_round);
305: dbg_puts(" blocks\n");
306: }
307: #endif
1.46 ratchov 308: dev_pstate = DEV_INIT;
1.26 ratchov 309: return 1;
1.1 ratchov 310: }
311:
312: /*
1.27 ratchov 313: * Cleanly stop and drain everything and close the device
314: * once both play chain and record chain are gone.
1.1 ratchov 315: */
316: void
317: dev_done(void)
318: {
319: struct file *f;
320:
1.39 ratchov 321: #ifdef DEBUG
322: if (debug_level >= 2)
323: dbg_puts("closing audio device\n");
324: #endif
1.3 ratchov 325: if (dev_mix) {
326: /*
1.32 ratchov 327: * Put the mixer in ``autoquit'' state and generate
328: * EOF on all inputs connected it. Once buffers are
329: * drained the mixer will terminate and shutdown the
330: * device.
1.3 ratchov 331: *
332: * NOTE: since file_eof() can destroy the file and
333: * reorder the file_list, we have to restart the loop
1.27 ratchov 334: * after each call to file_eof().
1.3 ratchov 335: */
1.36 ratchov 336: dev_mix->flags |= APROC_QUIT;
1.46 ratchov 337: if (APROC_OK(dev_mix->u.mix.mon)) {
338: dev_mix->u.mix.mon->refs--;
339: aproc_del(dev_mix->u.mix.mon);
340: dev_mix->u.mix.mon = NULL;
341: }
1.32 ratchov 342: restart_mix:
1.3 ratchov 343: LIST_FOREACH(f, &file_list, entry) {
1.32 ratchov 344: if (f->rproc != NULL &&
345: aproc_depend(dev_mix, f->rproc)) {
1.3 ratchov 346: file_eof(f);
1.32 ratchov 347: goto restart_mix;
1.3 ratchov 348: }
349: }
1.46 ratchov 350: } else if (dev_sub || dev_submon) {
1.3 ratchov 351: /*
1.32 ratchov 352: * Same as above, but since there's no mixer,
353: * we generate EOF on the record-end of the
354: * device.
355: */
356: restart_sub:
357: LIST_FOREACH(f, &file_list, entry) {
358: if (f->rproc != NULL &&
1.46 ratchov 359: (aproc_depend(dev_sub, f->rproc) ||
360: aproc_depend(dev_submon, f->rproc))) {
1.32 ratchov 361: file_eof(f);
362: goto restart_sub;
1.23 ratchov 363: }
1.32 ratchov 364: }
365: }
1.36 ratchov 366: if (dev_midi) {
367: dev_midi->flags |= APROC_QUIT;
1.43 ratchov 368: if (LIST_EMPTY(&dev_midi->ibuflist))
369: aproc_del(dev_midi);
1.36 ratchov 370: restart_midi:
371: LIST_FOREACH(f, &file_list, entry) {
372: if (f->rproc &&
373: aproc_depend(dev_midi, f->rproc)) {
374: file_eof(f);
375: goto restart_midi;
376: }
377: }
378: }
1.32 ratchov 379: if (dev_mix) {
1.46 ratchov 380: if (--dev_mix->refs == 0 && (dev_mix->flags & APROC_ZOMB))
1.32 ratchov 381: aproc_del(dev_mix);
382: dev_mix = NULL;
383: }
384: if (dev_play) {
1.46 ratchov 385: if (--dev_play->refs == 0 && (dev_play->flags & APROC_ZOMB))
1.23 ratchov 386: aproc_del(dev_play);
1.32 ratchov 387: dev_play = NULL;
1.1 ratchov 388: }
1.3 ratchov 389: if (dev_sub) {
1.46 ratchov 390: if (--dev_sub->refs == 0 && (dev_sub->flags & APROC_ZOMB))
1.32 ratchov 391: aproc_del(dev_sub);
1.22 ratchov 392: dev_sub = NULL;
1.32 ratchov 393: }
394: if (dev_rec) {
1.46 ratchov 395: if (--dev_rec->refs == 0 && (dev_rec->flags & APROC_ZOMB))
1.23 ratchov 396: aproc_del(dev_rec);
1.32 ratchov 397: dev_rec = NULL;
1.34 ratchov 398: }
1.46 ratchov 399: if (dev_submon) {
400: if (--dev_submon->refs == 0 && (dev_submon->flags & APROC_ZOMB))
401: aproc_del(dev_submon);
402: dev_submon = NULL;
403: }
404: if (dev_mon) {
405: if (--dev_mon->refs == 0 && (dev_mon->flags & APROC_ZOMB))
406: aproc_del(dev_mon);
407: dev_mon = NULL;
408: }
1.34 ratchov 409: if (dev_midi) {
1.46 ratchov 410: if (--dev_midi->refs == 0 && (dev_midi->flags & APROC_ZOMB))
1.34 ratchov 411: aproc_del(dev_midi);
412: dev_midi = NULL;
1.32 ratchov 413: }
414: for (;;) {
415: if (!file_poll())
416: break;
1.1 ratchov 417: }
418: }
419:
420: /*
1.27 ratchov 421: * Start the (paused) device. By default it's paused.
1.1 ratchov 422: */
423: void
424: dev_start(void)
425: {
1.22 ratchov 426: struct file *f;
427:
1.46 ratchov 428: #ifdef DEBUG
429: if (debug_level >= 2)
430: dbg_puts("starting audio device\n");
431: #endif
432: if (APROC_OK(dev_mix))
1.36 ratchov 433: dev_mix->flags |= APROC_DROP;
1.46 ratchov 434: if (APROC_OK(dev_sub))
1.36 ratchov 435: dev_sub->flags |= APROC_DROP;
1.46 ratchov 436: if (APROC_OK(dev_submon))
437: dev_submon->flags |= APROC_DROP;
438: if (APROC_OK(dev_play) && dev_play->u.io.file) {
1.22 ratchov 439: f = dev_play->u.io.file;
440: f->ops->start(f);
1.46 ratchov 441: } else if (APROC_OK(dev_rec) && dev_rec->u.io.file) {
1.22 ratchov 442: f = dev_rec->u.io.file;
443: f->ops->start(f);
444: }
1.1 ratchov 445: }
446:
447: /*
1.46 ratchov 448: * Pause the device. This may trigger context switches,
449: * so it shouldn't be called from aproc methods
1.1 ratchov 450: */
451: void
452: dev_stop(void)
453: {
1.22 ratchov 454: struct file *f;
455:
1.46 ratchov 456: if (APROC_OK(dev_play) && dev_play->u.io.file) {
1.22 ratchov 457: f = dev_play->u.io.file;
458: f->ops->stop(f);
1.46 ratchov 459: } else if (APROC_OK(dev_rec) && dev_rec->u.io.file) {
1.22 ratchov 460: f = dev_rec->u.io.file;
461: f->ops->stop(f);
462: }
1.46 ratchov 463: if (APROC_OK(dev_mix))
1.36 ratchov 464: dev_mix->flags &= ~APROC_DROP;
1.46 ratchov 465: if (APROC_OK(dev_sub))
1.36 ratchov 466: dev_sub->flags &= ~APROC_DROP;
1.46 ratchov 467: if (APROC_OK(dev_submon))
468: dev_submon->flags &= ~APROC_DROP;
469: #ifdef DEBUG
470: if (debug_level >= 2)
471: dbg_puts("audio device stopped\n");
472: #endif
1.1 ratchov 473: }
474:
475: /*
1.27 ratchov 476: * Find the end points connected to the mix/sub.
1.14 ratchov 477: */
478: int
1.46 ratchov 479: dev_getep(unsigned mode, struct abuf **sibuf, struct abuf **sobuf)
1.14 ratchov 480: {
481: struct abuf *ibuf, *obuf;
482:
1.46 ratchov 483: if (mode & MODE_PLAY) {
484: if (!APROC_OK(dev_mix))
485: return 0;
1.14 ratchov 486: ibuf = *sibuf;
487: for (;;) {
488: if (!ibuf || !ibuf->rproc) {
1.39 ratchov 489: #ifdef DEBUG
490: if (debug_level >= 3) {
491: abuf_dbg(*sibuf);
492: dbg_puts(": not connected to device\n");
493: }
494: #endif
1.14 ratchov 495: return 0;
496: }
497: if (ibuf->rproc == dev_mix)
498: break;
499: ibuf = LIST_FIRST(&ibuf->rproc->obuflist);
500: }
1.21 ratchov 501: *sibuf = ibuf;
1.14 ratchov 502: }
1.46 ratchov 503: if (mode & MODE_REC) {
504: if (!APROC_OK(dev_sub))
505: return 0;
1.14 ratchov 506: obuf = *sobuf;
507: for (;;) {
508: if (!obuf || !obuf->wproc) {
1.39 ratchov 509: #ifdef DEBUG
510: if (debug_level >= 3) {
511: abuf_dbg(*sobuf);
512: dbg_puts(": not connected to device\n");
513: }
514: #endif
1.14 ratchov 515: return 0;
516: }
517: if (obuf->wproc == dev_sub)
518: break;
519: obuf = LIST_FIRST(&obuf->wproc->ibuflist);
520: }
1.21 ratchov 521: *sobuf = obuf;
1.14 ratchov 522: }
1.46 ratchov 523: if (mode & MODE_MON) {
524: if (!APROC_OK(dev_submon))
525: return 0;
526: obuf = *sobuf;
527: for (;;) {
528: if (!obuf || !obuf->wproc) {
529: #ifdef DEBUG
530: if (debug_level >= 3) {
531: abuf_dbg(*sobuf);
532: dbg_puts(": not connected to device\n");
533: }
534: #endif
535: return 0;
536: }
537: if (obuf->wproc == dev_submon)
538: break;
539: obuf = LIST_FIRST(&obuf->wproc->ibuflist);
540: }
541: *sobuf = obuf;
542: }
1.14 ratchov 543: return 1;
544: }
545:
546: /*
1.27 ratchov 547: * Sync play buffer to rec buffer (for instance when one of
548: * them underruns/overruns).
1.1 ratchov 549: */
550: void
1.46 ratchov 551: dev_sync(unsigned mode, struct abuf *ibuf, struct abuf *obuf)
1.1 ratchov 552: {
1.3 ratchov 553: int delta;
554:
1.46 ratchov 555: if (!dev_getep(mode, &ibuf, &obuf))
1.3 ratchov 556: return;
557: /*
1.27 ratchov 558: * Calculate delta, the number of frames the play chain is ahead
1.3 ratchov 559: * of the record chain. It's necessary to schedule silences (or
560: * drops) in order to start playback and record in sync.
561: */
1.46 ratchov 562: if (APROC_OK(dev_mix) && APROC_OK(dev_sub)) {
563: delta = dev_mix->u.mix.abspos - dev_sub->u.sub.abspos;
564: } else if (APROC_OK(dev_mix)) {
565: delta = dev_mix->u.mix.lat;
566: } else
567: delta = 0;
1.39 ratchov 568: #ifdef DEBUG
569: if (debug_level >= 3) {
570: dbg_puts("syncing device, delta = ");
571: dbg_putu(delta);
1.46 ratchov 572: dbg_puts(" ");
573: if (APROC_OK(dev_mix)) {
574: aproc_dbg(dev_mix);
575: dbg_puts(": abspos = ");
576: dbg_putu(dev_mix->u.mix.abspos);
577: }
578: if (APROC_OK(dev_sub)) {
579: aproc_dbg(dev_sub);
580: dbg_puts(": abspos = ");
581: dbg_putu(dev_sub->u.sub.abspos);
582: }
1.39 ratchov 583: dbg_puts("\n");
584: }
585: #endif
1.3 ratchov 586: if (delta > 0) {
587: /*
1.37 ratchov 588: * The play chain is ahead (most cases) drop some of
1.27 ratchov 589: * the recorded input, to get both in sync.
1.3 ratchov 590: */
1.46 ratchov 591: if (mode & MODE_RECMASK)
592: sub_silence(obuf, -delta);
1.3 ratchov 593: } else if (delta < 0) {
594: /*
1.37 ratchov 595: * The record chain is ahead (should never happen,
1.27 ratchov 596: * right?) then insert silence to play.
1.3 ratchov 597: */
1.46 ratchov 598: if (mode & MODE_PLAY)
599: mix_drop(ibuf, delta);
1.30 ratchov 600: }
1.36 ratchov 601: }
602:
603: /*
604: * return the current latency (in frames), ie the latency that
605: * a stream would have if dev_attach() is called on it.
606: */
607: int
608: dev_getpos(void)
609: {
610: struct abuf *pbuf = NULL, *rbuf = NULL;
611: int plat = 0, rlat = 0;
612: int delta;
613:
1.46 ratchov 614: if (APROC_OK(dev_mix)) {
1.36 ratchov 615: pbuf = LIST_FIRST(&dev_mix->obuflist);
616: if (!pbuf)
617: return 0;
618: plat = -dev_mix->u.mix.lat;
619: }
1.46 ratchov 620: if (APROC_OK(dev_sub)) {
1.36 ratchov 621: rbuf = LIST_FIRST(&dev_sub->ibuflist);
622: if (!rbuf)
623: return 0;
624: rlat = -dev_sub->u.sub.lat;
625: }
1.46 ratchov 626: if (APROC_OK(dev_mix) && APROC_OK(dev_sub)) {
627: delta = dev_mix->u.mix.abspos - dev_sub->u.sub.abspos;
1.36 ratchov 628: if (delta > 0)
629: rlat -= delta;
630: else if (delta < 0)
631: plat += delta;
1.39 ratchov 632: #ifdef DEBUG
633: if (rlat != plat) {
634: dbg_puts("dev_getpos: play/rec out of sync: plat = ");
635: dbg_puti(plat);
636: dbg_puts(", rlat = ");
637: dbg_puti(rlat);
638: dbg_puts("\n");
639: }
640: #endif
1.36 ratchov 641: }
1.46 ratchov 642: return APROC_OK(dev_mix) ? plat : rlat;
1.1 ratchov 643: }
644:
645: /*
1.27 ratchov 646: * Attach the given input and output buffers to the mixer and the
1.1 ratchov 647: * multiplexer respectively. The operation is done synchronously, so
648: * both buffers enter in sync. If buffers do not match play
1.27 ratchov 649: * and rec.
1.1 ratchov 650: */
651: void
1.46 ratchov 652: dev_attach(char *name, unsigned mode,
653: struct abuf *ibuf, struct aparams *sipar,
654: struct abuf *obuf, struct aparams *sopar,
655: unsigned xrun, int vol)
1.1 ratchov 656: {
657: struct abuf *pbuf = NULL, *rbuf = NULL;
1.12 ratchov 658: struct aparams ipar, opar;
1.1 ratchov 659: struct aproc *conv;
1.20 ratchov 660: unsigned round, nblk;
661:
1.46 ratchov 662: #ifdef DEBUG
663: if ((!APROC_OK(dev_mix) && (mode & MODE_PLAY)) ||
664: (!APROC_OK(dev_sub) && (mode & MODE_REC)) ||
665: (!APROC_OK(dev_submon) && (mode & MODE_MON))) {
666: dbg_puts("mode beyond device mode, not attaching\n");
667: return;
668: }
669: #endif
670: if (mode & MODE_PLAY) {
1.12 ratchov 671: ipar = *sipar;
1.20 ratchov 672: pbuf = LIST_FIRST(&dev_mix->obuflist);
673: nblk = (dev_bufsz / dev_round + 3) / 4;
674: round = dev_roundof(ipar.rate);
1.10 ratchov 675: if (!aparams_eqenc(&ipar, &dev_opar)) {
676: conv = dec_new(name, &ipar);
677: ipar.bps = dev_opar.bps;
678: ipar.bits = dev_opar.bits;
679: ipar.sig = dev_opar.sig;
680: ipar.le = dev_opar.le;
681: ipar.msb = dev_opar.msb;
1.25 ratchov 682: aproc_setin(conv, ibuf);
1.20 ratchov 683: ibuf = abuf_new(nblk * round, &ipar);
1.9 ratchov 684: aproc_setout(conv, ibuf);
1.8 ratchov 685: }
1.10 ratchov 686: if (!aparams_eqrate(&ipar, &dev_opar)) {
1.20 ratchov 687: conv = resamp_new(name, round, dev_round);
1.10 ratchov 688: ipar.rate = dev_opar.rate;
1.20 ratchov 689: round = dev_round;
1.5 ratchov 690: aproc_setin(conv, ibuf);
1.20 ratchov 691: ibuf = abuf_new(nblk * round, &ipar);
1.5 ratchov 692: aproc_setout(conv, ibuf);
1.1 ratchov 693: }
694: aproc_setin(dev_mix, ibuf);
1.46 ratchov 695: ibuf->r.mix.xrun = xrun;
1.31 ratchov 696: ibuf->r.mix.maxweight = vol;
1.18 ratchov 697: mix_setmaster(dev_mix);
1.1 ratchov 698: }
1.46 ratchov 699: if (mode & MODE_REC) {
1.12 ratchov 700: opar = *sopar;
1.1 ratchov 701: rbuf = LIST_FIRST(&dev_sub->ibuflist);
1.20 ratchov 702: round = dev_roundof(opar.rate);
703: nblk = (dev_bufsz / dev_round + 3) / 4;
1.10 ratchov 704: if (!aparams_eqenc(&opar, &dev_ipar)) {
705: conv = enc_new(name, &opar);
706: opar.bps = dev_ipar.bps;
707: opar.bits = dev_ipar.bits;
708: opar.sig = dev_ipar.sig;
709: opar.le = dev_ipar.le;
710: opar.msb = dev_ipar.msb;
1.9 ratchov 711: aproc_setout(conv, obuf);
1.20 ratchov 712: obuf = abuf_new(nblk * round, &opar);
1.9 ratchov 713: aproc_setin(conv, obuf);
1.8 ratchov 714: }
1.10 ratchov 715: if (!aparams_eqrate(&opar, &dev_ipar)) {
1.20 ratchov 716: conv = resamp_new(name, dev_round, round);
1.10 ratchov 717: opar.rate = dev_ipar.rate;
1.20 ratchov 718: round = dev_round;
1.1 ratchov 719: aproc_setout(conv, obuf);
1.20 ratchov 720: obuf = abuf_new(nblk * round, &opar);
1.1 ratchov 721: aproc_setin(conv, obuf);
722: }
723: aproc_setout(dev_sub, obuf);
1.46 ratchov 724: obuf->w.sub.xrun = xrun;
725: }
726: if (mode & MODE_MON) {
727: opar = *sopar;
728: rbuf = LIST_FIRST(&dev_submon->ibuflist);
729: round = dev_roundof(opar.rate);
730: nblk = (dev_bufsz / dev_round + 3) / 4;
731: if (!aparams_eqenc(&opar, &dev_opar)) {
732: conv = enc_new(name, &opar);
733: opar.bps = dev_opar.bps;
734: opar.bits = dev_opar.bits;
735: opar.sig = dev_opar.sig;
736: opar.le = dev_opar.le;
737: opar.msb = dev_opar.msb;
738: aproc_setout(conv, obuf);
739: obuf = abuf_new(nblk * round, &opar);
740: aproc_setin(conv, obuf);
741: }
742: if (!aparams_eqrate(&opar, &dev_opar)) {
743: conv = resamp_new(name, dev_round, round);
744: opar.rate = dev_opar.rate;
745: round = dev_round;
746: aproc_setout(conv, obuf);
747: obuf = abuf_new(nblk * round, &opar);
748: aproc_setin(conv, obuf);
749: }
750: aproc_setout(dev_submon, obuf);
751: obuf->w.sub.xrun = xrun;
1.1 ratchov 752: }
753:
754: /*
1.27 ratchov 755: * Sync play to record.
1.1 ratchov 756: */
1.46 ratchov 757: if ((mode & MODE_PLAY) && (mode & MODE_RECMASK)) {
1.3 ratchov 758: ibuf->duplex = obuf;
759: obuf->duplex = ibuf;
1.13 ratchov 760: }
1.46 ratchov 761: dev_sync(mode, ibuf, obuf);
762:
763: /*
764: * Start device if not already started
765: */
766: if (dev_pstate == DEV_INIT)
767: dev_pstate = DEV_START;
1.14 ratchov 768: }
769:
770: /*
1.27 ratchov 771: * Change the playback volume of the given stream.
1.14 ratchov 772: */
773: void
774: dev_setvol(struct abuf *ibuf, int vol)
775: {
1.39 ratchov 776: #ifdef DEBUG
777: if (debug_level >= 3) {
778: abuf_dbg(ibuf);
779: dbg_puts(": setting volume to ");
780: dbg_putu(vol);
781: dbg_puts("\n");
782: }
783: #endif
1.46 ratchov 784: if (!dev_getep(MODE_PLAY, &ibuf, NULL)) {
1.14 ratchov 785: return;
1.16 ratchov 786: }
1.31 ratchov 787: ibuf->r.mix.vol = vol;
1.13 ratchov 788: }
789:
790: /*
1.27 ratchov 791: * Clear buffers of the play and record chains so that when the device
792: * is started, playback and record start in sync.
1.13 ratchov 793: */
794: void
795: dev_clear(void)
796: {
797: struct abuf *buf;
798:
1.46 ratchov 799: if (APROC_OK(dev_mix)) {
1.39 ratchov 800: #ifdef DEBUG
801: if (!LIST_EMPTY(&dev_mix->ibuflist)) {
802: dbg_puts("play end not idle, can't clear device\n");
803: dbg_panic();
804: }
805: #endif
1.13 ratchov 806: buf = LIST_FIRST(&dev_mix->obuflist);
807: while (buf) {
808: abuf_clear(buf);
809: buf = LIST_FIRST(&buf->rproc->obuflist);
810: }
811: mix_clear(dev_mix);
812: }
1.46 ratchov 813: if (APROC_OK(dev_sub)) {
1.39 ratchov 814: #ifdef DEBUG
815: if (!LIST_EMPTY(&dev_sub->obuflist)) {
816: dbg_puts("record end not idle, can't clear device\n");
817: dbg_panic();
818: }
819: #endif
1.13 ratchov 820: buf = LIST_FIRST(&dev_sub->ibuflist);
821: while (buf) {
822: abuf_clear(buf);
823: buf = LIST_FIRST(&buf->wproc->ibuflist);
824: }
825: sub_clear(dev_sub);
1.40 ratchov 826: }
1.46 ratchov 827: if (APROC_OK(dev_submon)) {
828: #ifdef DEBUG
829: dbg_puts("clearing monitor\n");
830: if (!LIST_EMPTY(&dev_submon->obuflist)) {
831: dbg_puts("monitoring end not idle, can't clear device\n");
832: dbg_panic();
833: }
834: #endif
835: buf = LIST_FIRST(&dev_submon->ibuflist);
836: while (buf) {
837: abuf_clear(buf);
838: buf = LIST_FIRST(&buf->wproc->ibuflist);
839: }
840: sub_clear(dev_submon);
841: mon_clear(dev_mon);
842: }
1.40 ratchov 843: }
844:
845: /*
846: * Fill with silence play buffers and schedule the same amount of recorded
847: * samples to drop
848: */
849: void
850: dev_prime(void)
851: {
1.46 ratchov 852: if (APROC_OK(dev_mix)) {
1.40 ratchov 853: #ifdef DEBUG
854: if (!LIST_EMPTY(&dev_mix->ibuflist)) {
855: dbg_puts("play end not idle, can't prime device\n");
856: dbg_panic();
857: }
858: #endif
859: mix_prime(dev_mix);
1.1 ratchov 860: }
861: }