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