Annotation of src/usr.bin/aucat/dev.c, Revision 1.42
1.42 ! ratchov 1: /* $OpenBSD: dev.c,v 1.41 2010/01/12 21:39:39 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;
338: restart_midi:
339: LIST_FOREACH(f, &file_list, entry) {
340: if (f->rproc &&
341: aproc_depend(dev_midi, f->rproc)) {
342: file_eof(f);
343: goto restart_midi;
344: }
345: }
346: }
1.32 ratchov 347: if (dev_mix) {
348: dev_mix->refs--;
1.36 ratchov 349: if (dev_mix->flags & APROC_ZOMB)
1.32 ratchov 350: aproc_del(dev_mix);
351: dev_mix = NULL;
352: }
353: if (dev_play) {
354: dev_play->refs--;
1.36 ratchov 355: if (dev_play->flags & APROC_ZOMB)
1.23 ratchov 356: aproc_del(dev_play);
1.32 ratchov 357: dev_play = NULL;
1.1 ratchov 358: }
1.3 ratchov 359: if (dev_sub) {
1.22 ratchov 360: dev_sub->refs--;
1.36 ratchov 361: if (dev_sub->flags & APROC_ZOMB)
1.32 ratchov 362: aproc_del(dev_sub);
1.22 ratchov 363: dev_sub = NULL;
1.32 ratchov 364: }
365: if (dev_rec) {
366: dev_rec->refs--;
1.36 ratchov 367: if (dev_rec->flags & APROC_ZOMB)
1.23 ratchov 368: aproc_del(dev_rec);
1.32 ratchov 369: dev_rec = NULL;
1.34 ratchov 370: }
371: if (dev_midi) {
372: dev_midi->refs--;
1.36 ratchov 373: if (dev_midi->flags & APROC_ZOMB)
1.34 ratchov 374: aproc_del(dev_midi);
375: dev_midi = NULL;
1.32 ratchov 376: }
377: for (;;) {
378: if (!file_poll())
379: break;
1.1 ratchov 380: }
381: }
382:
383: /*
1.27 ratchov 384: * Start the (paused) device. By default it's paused.
1.1 ratchov 385: */
386: void
387: dev_start(void)
388: {
1.22 ratchov 389: struct file *f;
390:
1.1 ratchov 391: if (dev_mix)
1.36 ratchov 392: dev_mix->flags |= APROC_DROP;
1.1 ratchov 393: if (dev_sub)
1.36 ratchov 394: dev_sub->flags |= APROC_DROP;
1.22 ratchov 395: if (dev_play && dev_play->u.io.file) {
396: f = dev_play->u.io.file;
397: f->ops->start(f);
398: } else if (dev_rec && dev_rec->u.io.file) {
399: f = dev_rec->u.io.file;
400: f->ops->start(f);
401: }
1.1 ratchov 402: }
403:
404: /*
1.27 ratchov 405: * Pause the device.
1.1 ratchov 406: */
407: void
408: dev_stop(void)
409: {
1.22 ratchov 410: struct file *f;
411:
412: if (dev_play && dev_play->u.io.file) {
413: f = dev_play->u.io.file;
414: f->ops->stop(f);
415: } else if (dev_rec && dev_rec->u.io.file) {
416: f = dev_rec->u.io.file;
417: f->ops->stop(f);
418: }
1.1 ratchov 419: if (dev_mix)
1.36 ratchov 420: dev_mix->flags &= ~APROC_DROP;
1.1 ratchov 421: if (dev_sub)
1.36 ratchov 422: dev_sub->flags &= ~APROC_DROP;
1.1 ratchov 423: }
424:
425: /*
1.27 ratchov 426: * Find the end points connected to the mix/sub.
1.14 ratchov 427: */
428: int
429: dev_getep(struct abuf **sibuf, struct abuf **sobuf)
430: {
431: struct abuf *ibuf, *obuf;
432:
1.37 ratchov 433: if (sibuf && *sibuf) {
1.14 ratchov 434: ibuf = *sibuf;
435: for (;;) {
436: if (!ibuf || !ibuf->rproc) {
1.39 ratchov 437: #ifdef DEBUG
438: if (debug_level >= 3) {
439: abuf_dbg(*sibuf);
440: dbg_puts(": not connected to device\n");
441: }
442: #endif
1.14 ratchov 443: return 0;
444: }
445: if (ibuf->rproc == dev_mix)
446: break;
447: ibuf = LIST_FIRST(&ibuf->rproc->obuflist);
448: }
1.21 ratchov 449: *sibuf = ibuf;
1.14 ratchov 450: }
1.37 ratchov 451: if (sobuf && *sobuf) {
1.14 ratchov 452: obuf = *sobuf;
453: for (;;) {
454: if (!obuf || !obuf->wproc) {
1.39 ratchov 455: #ifdef DEBUG
456: if (debug_level >= 3) {
457: abuf_dbg(*sobuf);
458: dbg_puts(": not connected to device\n");
459: }
460: #endif
1.14 ratchov 461: return 0;
462: }
463: if (obuf->wproc == dev_sub)
464: break;
465: obuf = LIST_FIRST(&obuf->wproc->ibuflist);
466: }
1.21 ratchov 467: *sobuf = obuf;
1.14 ratchov 468: }
469: return 1;
470: }
471:
472: /*
1.27 ratchov 473: * Sync play buffer to rec buffer (for instance when one of
474: * them underruns/overruns).
1.1 ratchov 475: */
476: void
1.3 ratchov 477: dev_sync(struct abuf *ibuf, struct abuf *obuf)
1.1 ratchov 478: {
1.3 ratchov 479: struct abuf *pbuf, *rbuf;
480: int delta;
481:
482: if (!dev_mix || !dev_sub)
483: return;
484: pbuf = LIST_FIRST(&dev_mix->obuflist);
485: if (!pbuf)
486: return;
487: rbuf = LIST_FIRST(&dev_sub->ibuflist);
488: if (!rbuf)
489: return;
1.14 ratchov 490: if (!dev_getep(&ibuf, &obuf))
491: return;
1.3 ratchov 492:
493: /*
1.27 ratchov 494: * Calculate delta, the number of frames the play chain is ahead
1.3 ratchov 495: * of the record chain. It's necessary to schedule silences (or
496: * drops) in order to start playback and record in sync.
497: */
1.25 ratchov 498: delta =
499: rbuf->bpf * (pbuf->abspos + pbuf->used) -
1.3 ratchov 500: pbuf->bpf * rbuf->abspos;
501: delta /= pbuf->bpf * rbuf->bpf;
1.39 ratchov 502: #ifdef DEBUG
503: if (debug_level >= 3) {
504: dbg_puts("syncing device, delta = ");
505: dbg_putu(delta);
506: dbg_puts(": ");
507: abuf_dbg(pbuf);
508: dbg_puts(" abspos = ");
509: dbg_putu(pbuf->abspos);
510: dbg_puts(" used = ");
511: dbg_putu(pbuf->used);
512: dbg_puts(" <---> ");
513: abuf_dbg(rbuf);
514: dbg_puts(" abspos = ");
515: dbg_putu(rbuf->abspos);
516: dbg_puts("\n");
517: }
518: #endif
1.3 ratchov 519: if (delta > 0) {
520: /*
1.37 ratchov 521: * The play chain is ahead (most cases) drop some of
1.27 ratchov 522: * the recorded input, to get both in sync.
1.3 ratchov 523: */
1.37 ratchov 524: if (obuf) {
525: obuf->drop += delta * obuf->bpf;
526: abuf_ipos(obuf, -delta);
527: }
1.3 ratchov 528: } else if (delta < 0) {
529: /*
1.37 ratchov 530: * The record chain is ahead (should never happen,
1.27 ratchov 531: * right?) then insert silence to play.
1.3 ratchov 532: */
1.37 ratchov 533: if (ibuf) {
534: ibuf->silence += -delta * ibuf->bpf;
535: abuf_opos(ibuf, delta);
536: }
1.30 ratchov 537: }
1.36 ratchov 538: }
539:
540: /*
541: * return the current latency (in frames), ie the latency that
542: * a stream would have if dev_attach() is called on it.
543: */
544: int
545: dev_getpos(void)
546: {
547: struct abuf *pbuf = NULL, *rbuf = NULL;
548: int plat = 0, rlat = 0;
549: int delta;
550:
551: if (dev_mix) {
552: pbuf = LIST_FIRST(&dev_mix->obuflist);
553: if (!pbuf)
554: return 0;
555: plat = -dev_mix->u.mix.lat;
556: }
557: if (dev_sub) {
558: rbuf = LIST_FIRST(&dev_sub->ibuflist);
559: if (!rbuf)
560: return 0;
561: rlat = -dev_sub->u.sub.lat;
562: }
563: if (dev_mix && dev_sub) {
564: delta =
565: rbuf->bpf * (pbuf->abspos + pbuf->used) -
566: pbuf->bpf * rbuf->abspos;
567: delta /= pbuf->bpf * rbuf->bpf;
568: if (delta > 0)
569: rlat -= delta;
570: else if (delta < 0)
571: plat += delta;
1.39 ratchov 572: #ifdef DEBUG
573: if (rlat != plat) {
574: dbg_puts("dev_getpos: play/rec out of sync: plat = ");
575: dbg_puti(plat);
576: dbg_puts(", rlat = ");
577: dbg_puti(rlat);
578: dbg_puts("\n");
579: }
580: #endif
1.36 ratchov 581: }
582: return dev_mix ? plat : rlat;
1.1 ratchov 583: }
584:
585: /*
1.27 ratchov 586: * Attach the given input and output buffers to the mixer and the
1.1 ratchov 587: * multiplexer respectively. The operation is done synchronously, so
588: * both buffers enter in sync. If buffers do not match play
1.27 ratchov 589: * and rec.
1.1 ratchov 590: */
591: void
1.25 ratchov 592: dev_attach(char *name,
593: struct abuf *ibuf, struct aparams *sipar, unsigned underrun,
1.18 ratchov 594: struct abuf *obuf, struct aparams *sopar, unsigned overrun, int vol)
1.1 ratchov 595: {
596: struct abuf *pbuf = NULL, *rbuf = NULL;
1.12 ratchov 597: struct aparams ipar, opar;
1.1 ratchov 598: struct aproc *conv;
1.20 ratchov 599: unsigned round, nblk;
600:
1.1 ratchov 601: if (ibuf) {
1.12 ratchov 602: ipar = *sipar;
1.20 ratchov 603: pbuf = LIST_FIRST(&dev_mix->obuflist);
604: nblk = (dev_bufsz / dev_round + 3) / 4;
605: round = dev_roundof(ipar.rate);
1.10 ratchov 606: if (!aparams_eqenc(&ipar, &dev_opar)) {
607: conv = dec_new(name, &ipar);
608: ipar.bps = dev_opar.bps;
609: ipar.bits = dev_opar.bits;
610: ipar.sig = dev_opar.sig;
611: ipar.le = dev_opar.le;
612: ipar.msb = dev_opar.msb;
1.25 ratchov 613: aproc_setin(conv, ibuf);
1.20 ratchov 614: ibuf = abuf_new(nblk * round, &ipar);
1.9 ratchov 615: aproc_setout(conv, ibuf);
1.8 ratchov 616: }
1.10 ratchov 617: if (!aparams_subset(&ipar, &dev_opar)) {
618: conv = cmap_new(name, &ipar, &dev_opar);
619: ipar.cmin = dev_opar.cmin;
620: ipar.cmax = dev_opar.cmax;
1.7 ratchov 621: aproc_setin(conv, ibuf);
1.20 ratchov 622: ibuf = abuf_new(nblk * round, &ipar);
1.7 ratchov 623: aproc_setout(conv, ibuf);
1.6 ratchov 624: }
1.10 ratchov 625: if (!aparams_eqrate(&ipar, &dev_opar)) {
1.20 ratchov 626: conv = resamp_new(name, round, dev_round);
1.10 ratchov 627: ipar.rate = dev_opar.rate;
1.20 ratchov 628: round = dev_round;
1.5 ratchov 629: aproc_setin(conv, ibuf);
1.20 ratchov 630: ibuf = abuf_new(nblk * round, &ipar);
1.5 ratchov 631: aproc_setout(conv, ibuf);
1.1 ratchov 632: }
633: aproc_setin(dev_mix, ibuf);
1.41 ratchov 634: if (dev_mix->u.mix.lat > 0)
635: abuf_opos(ibuf, -dev_mix->u.mix.lat);
1.31 ratchov 636: ibuf->r.mix.xrun = underrun;
637: ibuf->r.mix.maxweight = vol;
1.18 ratchov 638: mix_setmaster(dev_mix);
1.1 ratchov 639: }
640: if (obuf) {
1.12 ratchov 641: opar = *sopar;
1.1 ratchov 642: rbuf = LIST_FIRST(&dev_sub->ibuflist);
1.20 ratchov 643: round = dev_roundof(opar.rate);
644: nblk = (dev_bufsz / dev_round + 3) / 4;
1.10 ratchov 645: if (!aparams_eqenc(&opar, &dev_ipar)) {
646: conv = enc_new(name, &opar);
647: opar.bps = dev_ipar.bps;
648: opar.bits = dev_ipar.bits;
649: opar.sig = dev_ipar.sig;
650: opar.le = dev_ipar.le;
651: opar.msb = dev_ipar.msb;
1.9 ratchov 652: aproc_setout(conv, obuf);
1.20 ratchov 653: obuf = abuf_new(nblk * round, &opar);
1.9 ratchov 654: aproc_setin(conv, obuf);
1.8 ratchov 655: }
1.10 ratchov 656: if (!aparams_subset(&opar, &dev_ipar)) {
657: conv = cmap_new(name, &dev_ipar, &opar);
658: opar.cmin = dev_ipar.cmin;
659: opar.cmax = dev_ipar.cmax;
1.7 ratchov 660: aproc_setout(conv, obuf);
1.20 ratchov 661: obuf = abuf_new(nblk * round, &opar);
1.7 ratchov 662: aproc_setin(conv, obuf);
1.6 ratchov 663: }
1.10 ratchov 664: if (!aparams_eqrate(&opar, &dev_ipar)) {
1.20 ratchov 665: conv = resamp_new(name, dev_round, round);
1.10 ratchov 666: opar.rate = dev_ipar.rate;
1.20 ratchov 667: round = dev_round;
1.1 ratchov 668: aproc_setout(conv, obuf);
1.20 ratchov 669: obuf = abuf_new(nblk * round, &opar);
1.1 ratchov 670: aproc_setin(conv, obuf);
671: }
672: aproc_setout(dev_sub, obuf);
1.41 ratchov 673: if (dev_sub->u.sub.lat > 0)
674: abuf_ipos(obuf, -dev_sub->u.sub.lat);
1.31 ratchov 675: obuf->w.sub.xrun = overrun;
1.1 ratchov 676: }
677:
678: /*
1.27 ratchov 679: * Sync play to record.
1.1 ratchov 680: */
681: if (ibuf && obuf) {
1.3 ratchov 682: ibuf->duplex = obuf;
683: obuf->duplex = ibuf;
1.13 ratchov 684: }
1.37 ratchov 685: dev_sync(ibuf, obuf);
1.14 ratchov 686: }
687:
688: /*
1.27 ratchov 689: * Change the playback volume of the given stream.
1.14 ratchov 690: */
691: void
692: dev_setvol(struct abuf *ibuf, int vol)
693: {
1.39 ratchov 694: #ifdef DEBUG
695: if (debug_level >= 3) {
696: abuf_dbg(ibuf);
697: dbg_puts(": setting volume to ");
698: dbg_putu(vol);
699: dbg_puts("\n");
700: }
701: #endif
1.16 ratchov 702: if (!dev_getep(&ibuf, NULL)) {
1.14 ratchov 703: return;
1.16 ratchov 704: }
1.31 ratchov 705: ibuf->r.mix.vol = vol;
1.13 ratchov 706: }
707:
708: /*
1.27 ratchov 709: * Clear buffers of the play and record chains so that when the device
710: * is started, playback and record start in sync.
1.13 ratchov 711: */
712: void
713: dev_clear(void)
714: {
715: struct abuf *buf;
716:
717: if (dev_mix) {
1.39 ratchov 718: #ifdef DEBUG
719: if (!LIST_EMPTY(&dev_mix->ibuflist)) {
720: dbg_puts("play end not idle, can't clear device\n");
721: dbg_panic();
722: }
723: #endif
1.13 ratchov 724: buf = LIST_FIRST(&dev_mix->obuflist);
725: while (buf) {
726: abuf_clear(buf);
727: buf = LIST_FIRST(&buf->rproc->obuflist);
728: }
729: mix_clear(dev_mix);
730: }
731: if (dev_sub) {
1.39 ratchov 732: #ifdef DEBUG
733: if (!LIST_EMPTY(&dev_sub->obuflist)) {
734: dbg_puts("record end not idle, can't clear device\n");
735: dbg_panic();
736: }
737: #endif
1.13 ratchov 738: buf = LIST_FIRST(&dev_sub->ibuflist);
739: while (buf) {
740: abuf_clear(buf);
741: buf = LIST_FIRST(&buf->wproc->ibuflist);
742: }
743: sub_clear(dev_sub);
1.40 ratchov 744: }
745: }
746:
747: /*
748: * Fill with silence play buffers and schedule the same amount of recorded
749: * samples to drop
750: */
751: void
752: dev_prime(void)
753: {
754: if (dev_mix) {
755: #ifdef DEBUG
756: if (!LIST_EMPTY(&dev_mix->ibuflist)) {
757: dbg_puts("play end not idle, can't prime device\n");
758: dbg_panic();
759: }
760: #endif
761: mix_prime(dev_mix);
1.1 ratchov 762: }
763: }