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