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