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