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