Annotation of src/usr.bin/aucat/dev.c, Revision 1.66
1.66 ! ratchov 1: /* $OpenBSD: dev.c,v 1.65 2011/05/26 07:18:40 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.51 ratchov 17: /*
18: * Device abstraction module
19: *
20: * This module exposes a ``enhanced device'' that uses aproc
21: * structures framework; it does conversions on the fly and can
22: * handle multiple streams. The enhanced device starts and stops
23: * automatically, when streams are attached, and provides
24: * primitives for MIDI control
25: *
26: * From the main loop, the device is used as follows:
27: *
1.57 ratchov 28: * 1. create the device using dev_new_xxx()
1.51 ratchov 29: * 2. call dev_run() in the event loop
1.57 ratchov 30: * 3. destroy the device using dev_del()
1.51 ratchov 31: * 4. continue running the event loop to drain
32: *
33: * The device is used as follows from aproc context:
34: *
35: * 1. open the device with dev_ref()
36: * 2. negociate parameters (mode, rate, ...)
37: * 3. create your stream (ie allocate and fill abufs)
38: * 4. attach your stream atomically:
39: * - first call dev_wakeup() to ensure device is not suspended
40: * - possibly fetch dynamic parameters (eg. dev_getpos())
41: * - attach your buffers with dev_attach()
42: * 5. close your stream, ie abuf_eof() or abuf_hup()
43: * 6. close the device with dev_unref()
44: *
45: * The device has the following states:
46: *
47: * CLOSED sio_open() is not called, it's not ready and
48: * no streams can be attached; dev_ref() must
49: * be called to open the device
50: *
51: * INIT device is opened, processing chain is ready, but
52: * DMA is not started yet. Streams can attach,
53: * in which case device will automatically switch
54: * to the START state
55: *
56: * START at least one stream is attached, play buffers
57: * are primed (if necessary) DMA is ready and
58: * will start immeadiately (next cycle)
59: *
60: * RUN DMA is started. New streams can attach. If the
61: * device is idle (all streams are closed and
62: * finished draining), then the device
63: * automatically switches to INIT or CLOSED
64: */
65: /*
66: * TODO:
67: *
68: * priming buffer is not ok, because it will insert silence and
69: * break synchronization to other programs.
70: *
71: * priming buffer in server mode is required, because f->bufsz may
72: * be smaller than the server buffer and may cause underrun in the
73: * dev_bufsz part of the buffer, in turn causing apps to break. It
74: * doesn't hurt because we care only in synchronization between
75: * clients.
76: *
77: * Priming is not required in non-server mode, because streams
78: * actually start when they are in the READY state, and their
79: * buffer is large enough to never cause underruns of dev_bufsz.
80: *
81: * Fix sock.c to allocate dev_bufsz, but to use only appbufsz --
82: * or whatever -- but to avoid underruns in dev_bufsz. Then remove
83: * this ugly hack.
84: *
85: */
1.1 ratchov 86: #include <stdio.h>
87: #include <stdlib.h>
88: #include <unistd.h>
89:
90: #include "abuf.h"
91: #include "aproc.h"
1.27 ratchov 92: #include "conf.h"
93: #include "dev.h"
1.3 ratchov 94: #include "pipe.h"
1.38 ratchov 95: #include "miofile.h"
1.42 ratchov 96: #include "siofile.h"
1.28 ratchov 97: #include "midi.h"
1.46 ratchov 98: #include "opt.h"
1.39 ratchov 99: #ifdef DEBUG
100: #include "dbg.h"
101: #endif
1.1 ratchov 102:
1.57 ratchov 103: int dev_open(struct dev *);
104: void dev_close(struct dev *);
105: void dev_start(struct dev *);
106: void dev_stop(struct dev *);
107: void dev_clear(struct dev *);
1.66 ! ratchov 108: int devctl_open(struct dev *, struct devctl *);
1.57 ratchov 109:
110: struct dev *dev_list = NULL;
1.38 ratchov 111:
112: /*
1.51 ratchov 113: * Create a sndio device
1.28 ratchov 114: */
1.57 ratchov 115: struct dev *
116: dev_new_sio(char *path,
117: unsigned mode, struct aparams *dipar, struct aparams *dopar,
1.65 ratchov 118: unsigned bufsz, unsigned round, unsigned hold, unsigned autovol)
1.57 ratchov 119: {
120: struct dev *d;
121:
122: d = malloc(sizeof(struct dev));
123: if (d == NULL) {
124: perror("malloc");
125: exit(1);
126: }
1.66 ! ratchov 127: d->ctl_list = NULL;
1.57 ratchov 128: d->path = path;
129: d->reqmode = mode;
1.51 ratchov 130: if (mode & MODE_PLAY)
1.57 ratchov 131: d->reqopar = *dopar;
1.51 ratchov 132: if (mode & MODE_RECMASK)
1.57 ratchov 133: d->reqipar = *dipar;
134: d->reqbufsz = bufsz;
135: d->reqround = round;
136: d->hold = hold;
1.65 ratchov 137: d->autovol = autovol;
1.57 ratchov 138: d->pstate = DEV_CLOSED;
139: d->next = dev_list;
140: dev_list = d;
141: if (d->hold && !dev_open(d)) {
142: dev_del(d);
143: return NULL;
144: }
145: return d;
1.28 ratchov 146: }
1.24 ratchov 147:
148: /*
1.51 ratchov 149: * Create a loopback synchronous device
1.24 ratchov 150: */
1.57 ratchov 151: struct dev *
152: dev_new_loop(struct aparams *dipar, struct aparams *dopar, unsigned bufsz)
1.24 ratchov 153: {
154: struct aparams par;
155: unsigned cmin, cmax, rate;
1.57 ratchov 156: struct dev *d;
1.24 ratchov 157:
1.57 ratchov 158: d = malloc(sizeof(struct dev));
159: if (d == NULL) {
160: perror("malloc");
161: exit(1);
162: }
1.66 ! ratchov 163: d->ctl_list = NULL;
1.24 ratchov 164: cmin = (dipar->cmin < dopar->cmin) ? dipar->cmin : dopar->cmin;
165: cmax = (dipar->cmax > dopar->cmax) ? dipar->cmax : dopar->cmax;
166: rate = (dipar->rate > dopar->rate) ? dipar->rate : dopar->rate;
167: aparams_init(&par, cmin, cmax, rate);
1.57 ratchov 168: d->reqipar = par;
169: d->reqopar = par;
170: d->rate = rate;
171: d->reqround = (bufsz + 1) / 2;
172: d->reqbufsz = d->reqround * 2;
1.64 ratchov 173: d->reqmode = MODE_PLAY | MODE_REC | MODE_LOOP | MODE_MIDIMASK;
1.57 ratchov 174: d->pstate = DEV_CLOSED;
175: d->hold = 0;
1.62 ratchov 176: d->path = "loop";
1.57 ratchov 177: d->next = dev_list;
178: dev_list = d;
179: return d;
1.24 ratchov 180: }
1.1 ratchov 181:
1.51 ratchov 182: /*
183: * Create a MIDI thru box device
184: */
1.57 ratchov 185: struct dev *
1.66 ! ratchov 186: dev_new_thru(int hold)
1.1 ratchov 187: {
1.57 ratchov 188: struct dev *d;
189:
190: d = malloc(sizeof(struct dev));
191: if (d == NULL) {
192: perror("malloc");
193: exit(1);
194: }
1.66 ! ratchov 195: d->ctl_list = NULL;
1.64 ratchov 196: d->reqmode = MODE_MIDIMASK;
1.57 ratchov 197: d->pstate = DEV_CLOSED;
1.66 ! ratchov 198: d->hold = hold;
1.62 ratchov 199: d->path = "midithru";
1.57 ratchov 200: d->next = dev_list;
201: dev_list = d;
202: return d;
1.1 ratchov 203: }
204:
205: /*
1.66 ! ratchov 206: * Add a MIDI port to the device
! 207: */
! 208: int
! 209: devctl_add(struct dev *d, char *name, unsigned mode)
! 210: {
! 211: struct devctl *c;
! 212:
! 213: c = malloc(sizeof(struct devctl));
! 214: if (c == NULL) {
! 215: perror("malloc");
! 216: exit(1);
! 217: }
! 218: c->path = name;
! 219: c->mode = mode;
! 220: c->next = d->ctl_list;
! 221: d->ctl_list = c;
! 222: if (d->pstate != DEV_CLOSED) {
! 223: if (!devctl_open(d, c))
! 224: return 0;
! 225: }
! 226: return 1;
! 227: }
! 228:
! 229: /*
! 230: * Open a MIDI device and connect it to the thru box
! 231: */
! 232: int
! 233: devctl_open(struct dev *d, struct devctl *c)
! 234: {
! 235: struct file *f;
! 236: struct abuf *rbuf = NULL, *wbuf = NULL;
! 237: struct aproc *rproc, *wproc;
! 238:
! 239: f = (struct file *)miofile_new(&miofile_ops, c->path, c->mode);
! 240: if (f == NULL)
! 241: return 0;
! 242: if (c->mode & MODE_MIDIIN) {
! 243: rproc = rfile_new(f);
! 244: rbuf = abuf_new(MIDI_BUFSZ, &aparams_none);
! 245: aproc_setout(rproc, rbuf);
! 246: }
! 247: if (c->mode & MODE_MIDIOUT) {
! 248: wproc = wfile_new(f);
! 249: wbuf = abuf_new(MIDI_BUFSZ, &aparams_none);
! 250: aproc_setin(wproc, wbuf);
! 251: }
! 252: dev_midiattach(d, rbuf, wbuf);
! 253: return 1;
! 254: }
! 255:
! 256: /*
1.51 ratchov 257: * Open the device with the dev_reqxxx capabilities. Setup a mixer, demuxer,
258: * monitor, midi control, and any necessary conversions.
1.1 ratchov 259: */
1.26 ratchov 260: int
1.57 ratchov 261: dev_open(struct dev *d)
1.1 ratchov 262: {
1.23 ratchov 263: struct file *f;
1.66 ! ratchov 264: struct devctl *c;
1.51 ratchov 265: struct aparams par;
1.1 ratchov 266: struct aproc *conv;
267: struct abuf *buf;
1.51 ratchov 268: unsigned siomode;
269:
1.57 ratchov 270: d->mode = d->reqmode;
271: d->round = d->reqround;
272: d->bufsz = d->reqbufsz;
273: d->ipar = d->reqipar;
274: d->opar = d->reqopar;
275: d->rec = NULL;
276: d->play = NULL;
277: d->mon = NULL;
1.61 jakemsr 278: d->mix = NULL;
279: d->sub = NULL;
1.57 ratchov 280: d->submon = NULL;
1.61 jakemsr 281: d->midi = NULL;
1.57 ratchov 282: d->rate = 0;
1.36 ratchov 283:
1.3 ratchov 284: /*
1.51 ratchov 285: * If needed, open the device (ie create dev_rec and dev_play)
1.3 ratchov 286: */
1.57 ratchov 287: if ((d->mode & (MODE_PLAY | MODE_REC)) && !(d->mode & MODE_LOOP)) {
288: siomode = d->mode & (MODE_PLAY | MODE_REC);
1.51 ratchov 289: f = (struct file *)siofile_new(&siofile_ops,
1.57 ratchov 290: d->path,
1.51 ratchov 291: &siomode,
1.57 ratchov 292: &d->ipar,
293: &d->opar,
294: &d->bufsz,
295: &d->round);
1.51 ratchov 296: if (f == NULL) {
1.39 ratchov 297: #ifdef DEBUG
1.51 ratchov 298: if (debug_level >= 1) {
1.62 ratchov 299: dbg_puts(d->path);
1.51 ratchov 300: dbg_puts(": failed to open audio device\n");
301: }
302: #endif
303: return 0;
1.39 ratchov 304: }
1.51 ratchov 305: if (!(siomode & MODE_PLAY))
1.57 ratchov 306: d->mode &= ~(MODE_PLAY | MODE_MON);
1.51 ratchov 307: if (!(siomode & MODE_REC))
1.57 ratchov 308: d->mode &= ~MODE_REC;
309: if ((d->mode & (MODE_PLAY | MODE_REC)) == 0) {
1.51 ratchov 310: #ifdef DEBUG
311: if (debug_level >= 1) {
1.62 ratchov 312: dbg_puts(d->path);
1.51 ratchov 313: dbg_puts(": mode not supported by device\n");
314: }
1.39 ratchov 315: #endif
1.51 ratchov 316: return 0;
317: }
1.57 ratchov 318: d->rate = d->mode & MODE_REC ? d->ipar.rate : d->opar.rate;
1.39 ratchov 319: #ifdef DEBUG
320: if (debug_level >= 2) {
1.57 ratchov 321: if (d->mode & MODE_REC) {
1.62 ratchov 322: dbg_puts(d->path);
323: dbg_puts(": recording ");
1.57 ratchov 324: aparams_dbg(&d->ipar);
1.51 ratchov 325: dbg_puts("\n");
326: }
1.57 ratchov 327: if (d->mode & MODE_PLAY) {
1.62 ratchov 328: dbg_puts(d->path);
329: dbg_puts(": playing ");
1.57 ratchov 330: aparams_dbg(&d->opar);
1.51 ratchov 331: dbg_puts("\n");
332: }
1.39 ratchov 333: }
334: #endif
1.57 ratchov 335: if (d->mode & MODE_REC) {
336: d->rec = rsio_new(f);
337: d->rec->refs++;
338: }
339: if (d->mode & MODE_PLAY) {
340: d->play = wsio_new(f);
341: d->play->refs++;
1.51 ratchov 342: }
1.3 ratchov 343: }
1.11 ratchov 344:
345: /*
1.51 ratchov 346: * Create the midi control end, or a simple thru box
347: * if there's no device
348: */
1.64 ratchov 349: if (d->mode & MODE_MIDIMASK) {
350: d->midi = (d->mode & (MODE_PLAY | MODE_RECMASK)) ?
351: ctl_new("ctl", d) : thru_new("thru");
352: d->midi->refs++;
353: }
1.51 ratchov 354:
355: /*
356: * Create mixer, demuxer and monitor
1.1 ratchov 357: */
1.57 ratchov 358: if (d->mode & MODE_PLAY) {
1.65 ratchov 359: d->mix = mix_new("play", d->bufsz, d->round, d->autovol);
1.57 ratchov 360: d->mix->refs++;
361: d->mix->u.mix.ctl = d->midi;
362: }
363: if (d->mode & MODE_REC) {
364: d->sub = sub_new("rec", d->bufsz, d->round);
365: d->sub->refs++;
1.51 ratchov 366: /*
367: * If not playing, use the record end as clock source
368: */
1.57 ratchov 369: if (!(d->mode & MODE_PLAY))
370: d->sub->u.sub.ctl = d->midi;
1.51 ratchov 371: }
1.57 ratchov 372: if (d->mode & MODE_LOOP) {
1.51 ratchov 373: /*
374: * connect mixer out to demuxer in
375: */
1.57 ratchov 376: buf = abuf_new(d->bufsz, &d->opar);
377: aproc_setout(d->mix, buf);
378: aproc_setin(d->sub, buf);
379:
380: d->mix->flags |= APROC_QUIT;
381: d->sub->flags |= APROC_QUIT;
382: d->rate = d->opar.rate;
1.51 ratchov 383: }
1.57 ratchov 384: if (d->rec) {
385: aparams_init(&par, d->ipar.cmin, d->ipar.cmax, d->rate);
1.51 ratchov 386:
1.1 ratchov 387: /*
1.51 ratchov 388: * Create device <-> demuxer buffer
1.1 ratchov 389: */
1.57 ratchov 390: buf = abuf_new(d->bufsz, &d->ipar);
391: aproc_setout(d->rec, buf);
1.1 ratchov 392:
393: /*
1.51 ratchov 394: * Insert a converter, if needed.
1.1 ratchov 395: */
1.57 ratchov 396: if (!aparams_eqenc(&d->ipar, &par)) {
397: conv = dec_new("rec", &d->ipar);
1.1 ratchov 398: aproc_setin(conv, buf);
1.57 ratchov 399: buf = abuf_new(d->round, &par);
1.1 ratchov 400: aproc_setout(conv, buf);
401: }
1.57 ratchov 402: d->ipar = par;
403: aproc_setin(d->sub, buf);
1.1 ratchov 404: }
1.57 ratchov 405: if (d->play) {
406: aparams_init(&par, d->opar.cmin, d->opar.cmax, d->rate);
1.1 ratchov 407:
408: /*
1.51 ratchov 409: * Create device <-> mixer buffer
1.1 ratchov 410: */
1.57 ratchov 411: buf = abuf_new(d->bufsz, &d->opar);
412: aproc_setin(d->play, buf);
1.25 ratchov 413:
1.1 ratchov 414: /*
1.27 ratchov 415: * Append a converter, if needed.
1.1 ratchov 416: */
1.57 ratchov 417: if (!aparams_eqenc(&par, &d->opar)) {
418: conv = enc_new("play", &d->opar);
1.1 ratchov 419: aproc_setout(conv, buf);
1.57 ratchov 420: buf = abuf_new(d->round, &par);
1.1 ratchov 421: aproc_setin(conv, buf);
422: }
1.57 ratchov 423: d->opar = par;
424: aproc_setout(d->mix, buf);
1.1 ratchov 425: }
1.57 ratchov 426: if (d->mode & MODE_MON) {
427: d->mon = mon_new("mon", d->bufsz);
428: d->mon->refs++;
429: buf = abuf_new(d->bufsz, &d->opar);
430: aproc_setout(d->mon, buf);
1.46 ratchov 431:
432: /*
433: * Append a "sub" to which clients will connect.
434: */
1.57 ratchov 435: d->submon = sub_new("mon", d->bufsz, d->round);
436: d->submon->refs++;
437: aproc_setin(d->submon, buf);
1.46 ratchov 438:
439: /*
1.51 ratchov 440: * Attach to the mixer
1.46 ratchov 441: */
1.57 ratchov 442: d->mix->u.mix.mon = d->mon;
443: d->mon->refs++;
1.46 ratchov 444: }
1.39 ratchov 445: #ifdef DEBUG
1.51 ratchov 446: if (debug_level >= 2) {
1.57 ratchov 447: if (d->mode & (MODE_PLAY | MODE_RECMASK)) {
1.62 ratchov 448: dbg_puts(d->path);
449: dbg_puts(": block size is ");
1.57 ratchov 450: dbg_putu(d->round);
1.51 ratchov 451: dbg_puts(" frames, using ");
1.57 ratchov 452: dbg_putu(d->bufsz / d->round);
1.51 ratchov 453: dbg_puts(" blocks\n");
454: }
1.39 ratchov 455: }
456: #endif
1.57 ratchov 457: d->pstate = DEV_INIT;
1.66 ! ratchov 458: for (c = d->ctl_list; c != NULL; c = c->next) {
! 459: if (!devctl_open(d, c)) {
! 460: #ifdef DEBUG
! 461: if (debug_level >= 1) {
! 462: dbg_puts(c->path);
! 463: dbg_puts(": couldn't open MIDI port\n");
! 464: }
! 465: #endif
! 466: dev_close(d);
! 467: return 0;
! 468: }
! 469: }
1.26 ratchov 470: return 1;
1.1 ratchov 471: }
472:
473: /*
1.27 ratchov 474: * Cleanly stop and drain everything and close the device
475: * once both play chain and record chain are gone.
1.1 ratchov 476: */
477: void
1.57 ratchov 478: dev_close(struct dev *d)
1.1 ratchov 479: {
480: struct file *f;
481:
1.50 ratchov 482: /*
483: * if the device is starting, ensure it actually starts
484: * so buffers are drained, else clear any buffers
485: */
1.57 ratchov 486: switch (d->pstate) {
1.50 ratchov 487: case DEV_START:
488: #ifdef DEBUG
489: if (debug_level >= 3)
490: dbg_puts("draining device\n");
491: #endif
1.57 ratchov 492: dev_start(d);
1.50 ratchov 493: break;
494: case DEV_INIT:
495: #ifdef DEBUG
496: if (debug_level >= 3)
497: dbg_puts("flushing device\n");
498: #endif
1.57 ratchov 499: dev_clear(d);
1.50 ratchov 500: break;
501: }
1.39 ratchov 502: #ifdef DEBUG
503: if (debug_level >= 2)
1.51 ratchov 504: dbg_puts("closing device\n");
1.39 ratchov 505: #endif
1.51 ratchov 506:
1.57 ratchov 507: if (d->mix) {
1.3 ratchov 508: /*
1.32 ratchov 509: * Put the mixer in ``autoquit'' state and generate
510: * EOF on all inputs connected it. Once buffers are
511: * drained the mixer will terminate and shutdown the
512: * device.
1.3 ratchov 513: *
514: * NOTE: since file_eof() can destroy the file and
515: * reorder the file_list, we have to restart the loop
1.27 ratchov 516: * after each call to file_eof().
1.3 ratchov 517: */
1.57 ratchov 518: if (APROC_OK(d->mix))
519: mix_quit(d->mix);
1.51 ratchov 520:
521: /*
522: * XXX: handle this in mix_done()
523: */
1.57 ratchov 524: if (APROC_OK(d->mix->u.mix.mon)) {
525: d->mix->u.mix.mon->refs--;
526: aproc_del(d->mix->u.mix.mon);
527: d->mix->u.mix.mon = NULL;
1.46 ratchov 528: }
1.32 ratchov 529: restart_mix:
1.3 ratchov 530: LIST_FOREACH(f, &file_list, entry) {
1.32 ratchov 531: if (f->rproc != NULL &&
1.57 ratchov 532: aproc_depend(d->mix, f->rproc)) {
1.3 ratchov 533: file_eof(f);
1.32 ratchov 534: goto restart_mix;
1.3 ratchov 535: }
536: }
1.59 ratchov 537: } else if (d->sub) {
1.3 ratchov 538: /*
1.32 ratchov 539: * Same as above, but since there's no mixer,
540: * we generate EOF on the record-end of the
541: * device.
542: */
543: restart_sub:
544: LIST_FOREACH(f, &file_list, entry) {
545: if (f->rproc != NULL &&
1.59 ratchov 546: aproc_depend(d->sub, f->rproc)) {
1.32 ratchov 547: file_eof(f);
548: goto restart_sub;
1.59 ratchov 549: }
550: }
551: } else if (d->submon) {
552: /*
553: * Same as above
554: */
555: restart_submon:
556: LIST_FOREACH(f, &file_list, entry) {
557: if (f->rproc != NULL &&
558: aproc_depend(d->submon, f->rproc)) {
559: file_eof(f);
560: goto restart_submon;
1.23 ratchov 561: }
1.32 ratchov 562: }
563: }
1.57 ratchov 564: if (d->midi) {
565: d->midi->flags |= APROC_QUIT;
566: if (LIST_EMPTY(&d->midi->ins))
567: aproc_del(d->midi);
1.36 ratchov 568: restart_midi:
569: LIST_FOREACH(f, &file_list, entry) {
570: if (f->rproc &&
1.57 ratchov 571: aproc_depend(d->midi, f->rproc)) {
1.36 ratchov 572: file_eof(f);
573: goto restart_midi;
574: }
575: }
576: }
1.57 ratchov 577: if (d->mix) {
578: if (--d->mix->refs == 0 && (d->mix->flags & APROC_ZOMB))
579: aproc_del(d->mix);
580: d->mix = NULL;
581: }
582: if (d->play) {
583: if (--d->play->refs == 0 && (d->play->flags & APROC_ZOMB))
584: aproc_del(d->play);
585: d->play = NULL;
586: }
587: if (d->sub) {
588: if (--d->sub->refs == 0 && (d->sub->flags & APROC_ZOMB))
589: aproc_del(d->sub);
590: d->sub = NULL;
591: }
592: if (d->rec) {
593: if (--d->rec->refs == 0 && (d->rec->flags & APROC_ZOMB))
594: aproc_del(d->rec);
595: d->rec = NULL;
596: }
597: if (d->submon) {
598: if (--d->submon->refs == 0 && (d->submon->flags & APROC_ZOMB))
599: aproc_del(d->submon);
600: d->submon = NULL;
601: }
602: if (d->mon) {
603: if (--d->mon->refs == 0 && (d->mon->flags & APROC_ZOMB))
604: aproc_del(d->mon);
605: d->mon = NULL;
606: }
607: if (d->midi) {
608: if (--d->midi->refs == 0 && (d->midi->flags & APROC_ZOMB))
609: aproc_del(d->midi);
610: d->midi = NULL;
1.32 ratchov 611: }
1.57 ratchov 612: d->pstate = DEV_CLOSED;
1.51 ratchov 613: }
614:
615: /*
1.60 ratchov 616: * Unless the device is already in process of closing, request it to close
617: */
618: void
619: dev_drain(struct dev *d)
620: {
621: if (d->pstate != DEV_CLOSED)
622: dev_close(d);
623: }
624:
625: /*
1.51 ratchov 626: * Free the device
627: */
628: void
1.57 ratchov 629: dev_del(struct dev *d)
1.51 ratchov 630: {
1.57 ratchov 631: struct dev **p;
632:
1.60 ratchov 633: dev_drain(d);
1.57 ratchov 634: for (p = &dev_list; *p != d; p = &(*p)->next) {
635: #ifdef DEBUG
636: if (*p == NULL) {
637: dbg_puts("device to delete not on the list\n");
638: dbg_panic();
639: }
640: #endif
641: }
642: *p = d->next;
643: free(d);
1.51 ratchov 644: }
645:
646: /*
647: * Attach a bi-directional MIDI stream to the MIDI device
648: */
649: void
1.57 ratchov 650: dev_midiattach(struct dev *d, struct abuf *ibuf, struct abuf *obuf)
1.51 ratchov 651: {
652: if (ibuf)
1.57 ratchov 653: aproc_setin(d->midi, ibuf);
1.51 ratchov 654: if (obuf) {
1.57 ratchov 655: aproc_setout(d->midi, obuf);
1.51 ratchov 656: if (ibuf) {
657: ibuf->duplex = obuf;
658: obuf->duplex = ibuf;
659: }
1.1 ratchov 660: }
661: }
662:
1.51 ratchov 663: unsigned
1.57 ratchov 664: dev_roundof(struct dev *d, unsigned newrate)
1.51 ratchov 665: {
1.57 ratchov 666: return (d->round * newrate + d->rate / 2) / d->rate;
1.51 ratchov 667: }
668:
1.1 ratchov 669: /*
1.27 ratchov 670: * Start the (paused) device. By default it's paused.
1.1 ratchov 671: */
672: void
1.57 ratchov 673: dev_start(struct dev *d)
1.1 ratchov 674: {
1.22 ratchov 675: struct file *f;
676:
1.46 ratchov 677: #ifdef DEBUG
678: if (debug_level >= 2)
1.51 ratchov 679: dbg_puts("starting device\n");
1.46 ratchov 680: #endif
1.57 ratchov 681: d->pstate = DEV_RUN;
682: if (d->mode & MODE_LOOP)
1.52 ratchov 683: return;
1.57 ratchov 684: if (APROC_OK(d->mix))
685: d->mix->flags |= APROC_DROP;
686: if (APROC_OK(d->sub))
687: d->sub->flags |= APROC_DROP;
688: if (APROC_OK(d->submon))
689: d->submon->flags |= APROC_DROP;
690: if (APROC_OK(d->play) && d->play->u.io.file) {
691: f = d->play->u.io.file;
1.22 ratchov 692: f->ops->start(f);
1.57 ratchov 693: } else if (APROC_OK(d->rec) && d->rec->u.io.file) {
694: f = d->rec->u.io.file;
1.22 ratchov 695: f->ops->start(f);
696: }
1.1 ratchov 697: }
698:
699: /*
1.46 ratchov 700: * Pause the device. This may trigger context switches,
701: * so it shouldn't be called from aproc methods
1.1 ratchov 702: */
703: void
1.57 ratchov 704: dev_stop(struct dev *d)
1.1 ratchov 705: {
1.22 ratchov 706: struct file *f;
707:
1.52 ratchov 708: #ifdef DEBUG
709: if (debug_level >= 2)
1.57 ratchov 710: dbg_puts("device stopped\n");
1.52 ratchov 711: #endif
1.57 ratchov 712: d->pstate = DEV_INIT;
713: if (d->mode & MODE_LOOP)
1.52 ratchov 714: return;
1.57 ratchov 715: if (APROC_OK(d->play) && d->play->u.io.file) {
716: f = d->play->u.io.file;
1.22 ratchov 717: f->ops->stop(f);
1.57 ratchov 718: } else if (APROC_OK(d->rec) && d->rec->u.io.file) {
719: f = d->rec->u.io.file;
1.22 ratchov 720: f->ops->stop(f);
721: }
1.57 ratchov 722: if (APROC_OK(d->mix))
723: d->mix->flags &= ~APROC_DROP;
724: if (APROC_OK(d->sub))
725: d->sub->flags &= ~APROC_DROP;
726: if (APROC_OK(d->submon))
727: d->submon->flags &= ~APROC_DROP;
1.51 ratchov 728: }
729:
730: int
1.57 ratchov 731: dev_ref(struct dev *d)
1.51 ratchov 732: {
733: #ifdef DEBUG
734: if (debug_level >= 3)
735: dbg_puts("device requested\n");
736: #endif
1.57 ratchov 737: if (d->pstate == DEV_CLOSED && !dev_open(d)) {
738: if (d->hold)
739: dev_del(d);
1.51 ratchov 740: return 0;
1.57 ratchov 741: }
742: d->refcnt++;
1.51 ratchov 743: return 1;
744: }
745:
746: void
1.57 ratchov 747: dev_unref(struct dev *d)
1.51 ratchov 748: {
749: #ifdef DEBUG
750: if (debug_level >= 3)
751: dbg_puts("device released\n");
752: #endif
1.57 ratchov 753: d->refcnt--;
754: if (d->refcnt == 0 && d->pstate == DEV_INIT && !d->hold)
755: dev_close(d);
1.51 ratchov 756: }
757:
758: /*
759: * There are actions (like start/stop/close ... ) that may trigger aproc
760: * operations, a thus cannot be started from aproc context.
761: * To avoid problems, aprocs only change the s!tate of the device,
762: * and actual operations are triggered from the main loop,
763: * outside the aproc code path.
764: *
765: * The following routine invokes pending actions, returns 0
766: * on fatal error
767: */
768: int
1.57 ratchov 769: dev_run(struct dev *d)
1.51 ratchov 770: {
1.57 ratchov 771: if (d->pstate == DEV_CLOSED)
1.51 ratchov 772: return 1;
773: /*
774: * check if device isn't gone
775: */
1.57 ratchov 776: if (((d->mode & MODE_PLAY) && !APROC_OK(d->mix)) ||
777: ((d->mode & MODE_REC) && !APROC_OK(d->sub)) ||
778: ((d->mode & MODE_MON) && !APROC_OK(d->submon))) {
1.51 ratchov 779: #ifdef DEBUG
780: if (debug_level >= 1)
781: dbg_puts("device disappeared\n");
782: #endif
1.57 ratchov 783: if (d->hold) {
784: dev_del(d);
785: return 0;
786: }
787: dev_close(d);
788: return 1;
1.51 ratchov 789: }
1.57 ratchov 790: switch (d->pstate) {
1.51 ratchov 791: case DEV_INIT:
792: /* nothing */
793: break;
794: case DEV_START:
1.57 ratchov 795: dev_start(d);
1.51 ratchov 796: /* PASSTHROUGH */
797: case DEV_RUN:
798: /*
799: * if the device is not used, then stop it
800: */
1.57 ratchov 801: if ((!APROC_OK(d->mix) ||
802: d->mix->u.mix.idle > 2 * d->bufsz) &&
803: (!APROC_OK(d->sub) ||
804: d->sub->u.sub.idle > 2 * d->bufsz) &&
805: (!APROC_OK(d->submon) ||
806: d->submon->u.sub.idle > 2 * d->bufsz) &&
807: (!APROC_OK(d->midi) ||
808: d->midi->u.ctl.tstate != CTL_RUN)) {
1.51 ratchov 809: #ifdef DEBUG
810: if (debug_level >= 3)
811: dbg_puts("device idle, suspending\n");
1.46 ratchov 812: #endif
1.57 ratchov 813: dev_stop(d);
814: if (d->refcnt == 0 && !d->hold)
815: dev_close(d);
1.58 ratchov 816: else
1.57 ratchov 817: dev_clear(d);
1.51 ratchov 818: }
819: break;
820: }
821: return 1;
822: }
823:
824: /*
1.58 ratchov 825: * If the device is paused, then resume it.
1.51 ratchov 826: * This routine can be called from aproc context.
827: */
828: void
1.57 ratchov 829: dev_wakeup(struct dev *d)
1.51 ratchov 830: {
1.57 ratchov 831: if (d->pstate == DEV_INIT)
832: d->pstate = DEV_START;
1.1 ratchov 833: }
834:
835: /*
1.27 ratchov 836: * Find the end points connected to the mix/sub.
1.14 ratchov 837: */
838: int
1.57 ratchov 839: dev_getep(struct dev *d,
840: unsigned mode, struct abuf **sibuf, struct abuf **sobuf)
1.14 ratchov 841: {
842: struct abuf *ibuf, *obuf;
843:
1.46 ratchov 844: if (mode & MODE_PLAY) {
1.57 ratchov 845: if (!APROC_OK(d->mix))
1.46 ratchov 846: return 0;
1.14 ratchov 847: ibuf = *sibuf;
848: for (;;) {
849: if (!ibuf || !ibuf->rproc) {
1.39 ratchov 850: #ifdef DEBUG
851: if (debug_level >= 3) {
852: abuf_dbg(*sibuf);
853: dbg_puts(": not connected to device\n");
854: }
855: #endif
1.14 ratchov 856: return 0;
857: }
1.57 ratchov 858: if (ibuf->rproc == d->mix)
1.14 ratchov 859: break;
1.49 ratchov 860: ibuf = LIST_FIRST(&ibuf->rproc->outs);
1.14 ratchov 861: }
1.21 ratchov 862: *sibuf = ibuf;
1.14 ratchov 863: }
1.46 ratchov 864: if (mode & MODE_REC) {
1.57 ratchov 865: if (!APROC_OK(d->sub))
1.46 ratchov 866: return 0;
1.14 ratchov 867: obuf = *sobuf;
868: for (;;) {
869: if (!obuf || !obuf->wproc) {
1.39 ratchov 870: #ifdef DEBUG
871: if (debug_level >= 3) {
872: abuf_dbg(*sobuf);
873: dbg_puts(": not connected to device\n");
874: }
875: #endif
1.14 ratchov 876: return 0;
877: }
1.57 ratchov 878: if (obuf->wproc == d->sub)
1.14 ratchov 879: break;
1.49 ratchov 880: obuf = LIST_FIRST(&obuf->wproc->ins);
1.14 ratchov 881: }
1.21 ratchov 882: *sobuf = obuf;
1.14 ratchov 883: }
1.46 ratchov 884: if (mode & MODE_MON) {
1.57 ratchov 885: if (!APROC_OK(d->submon))
1.46 ratchov 886: return 0;
887: obuf = *sobuf;
888: for (;;) {
889: if (!obuf || !obuf->wproc) {
890: #ifdef DEBUG
891: if (debug_level >= 3) {
892: abuf_dbg(*sobuf);
893: dbg_puts(": not connected to device\n");
894: }
895: #endif
896: return 0;
897: }
1.57 ratchov 898: if (obuf->wproc == d->submon)
1.46 ratchov 899: break;
1.49 ratchov 900: obuf = LIST_FIRST(&obuf->wproc->ins);
1.46 ratchov 901: }
902: *sobuf = obuf;
903: }
1.14 ratchov 904: return 1;
905: }
906:
907: /*
1.27 ratchov 908: * Sync play buffer to rec buffer (for instance when one of
909: * them underruns/overruns).
1.1 ratchov 910: */
911: void
1.57 ratchov 912: dev_sync(struct dev *d, unsigned mode, struct abuf *ibuf, struct abuf *obuf)
1.1 ratchov 913: {
1.53 ratchov 914: int delta, offs;
1.57 ratchov 915: struct abuf *mbuf = NULL;
1.3 ratchov 916:
1.57 ratchov 917: if (!dev_getep(d, mode, &ibuf, &obuf))
1.3 ratchov 918: return;
919: /*
1.27 ratchov 920: * Calculate delta, the number of frames the play chain is ahead
1.3 ratchov 921: * of the record chain. It's necessary to schedule silences (or
922: * drops) in order to start playback and record in sync.
923: */
1.53 ratchov 924: offs = 0;
925: delta = 0;
1.57 ratchov 926: if (APROC_OK(d->mix)) {
927: mbuf = LIST_FIRST(&d->mix->outs);
1.53 ratchov 928: offs += mbuf->w.mix.todo;
1.57 ratchov 929: delta += d->mix->u.mix.lat;
1.53 ratchov 930: }
1.57 ratchov 931: if (APROC_OK(d->sub))
932: delta += d->sub->u.sub.lat;
1.39 ratchov 933: #ifdef DEBUG
934: if (debug_level >= 3) {
1.53 ratchov 935: dbg_puts("syncing device");
1.57 ratchov 936: if (APROC_OK(d->mix)) {
1.51 ratchov 937: dbg_puts(", ");
1.57 ratchov 938: aproc_dbg(d->mix);
1.53 ratchov 939: dbg_puts(": todo = ");
940: dbg_putu(mbuf->w.mix.todo);
941: dbg_puts(": lat = ");
1.57 ratchov 942: dbg_putu(d->mix->u.mix.lat);
1.46 ratchov 943: }
1.57 ratchov 944: if (APROC_OK(d->sub)) {
1.51 ratchov 945: dbg_puts(", ");
1.57 ratchov 946: aproc_dbg(d->sub);
1.53 ratchov 947: dbg_puts(": lat = ");
1.57 ratchov 948: dbg_putu(d->sub->u.sub.lat);
1.46 ratchov 949: }
1.39 ratchov 950: dbg_puts("\n");
951: }
952: #endif
1.53 ratchov 953: if (mode & MODE_PLAY)
954: mix_drop(ibuf, -offs);
955: if (mode & MODE_RECMASK)
956: sub_silence(obuf, -(offs + delta));
1.36 ratchov 957: }
958:
959: /*
960: * return the current latency (in frames), ie the latency that
961: * a stream would have if dev_attach() is called on it.
962: */
963: int
1.57 ratchov 964: dev_getpos(struct dev *d)
1.36 ratchov 965: {
1.53 ratchov 966: struct abuf *mbuf = NULL;
1.36 ratchov 967:
1.57 ratchov 968: if (APROC_OK(d->mix)) {
969: mbuf = LIST_FIRST(&d->mix->outs);
970: return -(mbuf->w.mix.todo + d->mix->u.mix.lat);
1.54 ratchov 971: } else
972: return 0;
1.1 ratchov 973: }
974:
975: /*
1.27 ratchov 976: * Attach the given input and output buffers to the mixer and the
1.1 ratchov 977: * multiplexer respectively. The operation is done synchronously, so
978: * both buffers enter in sync. If buffers do not match play
1.27 ratchov 979: * and rec.
1.1 ratchov 980: */
981: void
1.57 ratchov 982: dev_attach(struct dev *d, char *name, unsigned mode,
1.48 ratchov 983: struct abuf *ibuf, struct aparams *sipar, unsigned inch,
984: struct abuf *obuf, struct aparams *sopar, unsigned onch,
1.46 ratchov 985: unsigned xrun, int vol)
1.1 ratchov 986: {
987: struct abuf *pbuf = NULL, *rbuf = NULL;
1.12 ratchov 988: struct aparams ipar, opar;
1.1 ratchov 989: struct aproc *conv;
1.48 ratchov 990: unsigned round, nblk, nch;
1.20 ratchov 991:
1.46 ratchov 992: #ifdef DEBUG
1.57 ratchov 993: if ((!APROC_OK(d->mix) && (mode & MODE_PLAY)) ||
994: (!APROC_OK(d->sub) && (mode & MODE_REC)) ||
995: (!APROC_OK(d->submon) && (mode & MODE_MON))) {
1.46 ratchov 996: dbg_puts("mode beyond device mode, not attaching\n");
997: return;
998: }
999: #endif
1000: if (mode & MODE_PLAY) {
1.12 ratchov 1001: ipar = *sipar;
1.57 ratchov 1002: pbuf = LIST_FIRST(&d->mix->outs);
1003: nblk = (d->bufsz / d->round + 3) / 4;
1004: round = dev_roundof(d, ipar.rate);
1.48 ratchov 1005: nch = ipar.cmax - ipar.cmin + 1;
1.57 ratchov 1006: if (!aparams_eqenc(&ipar, &d->opar)) {
1.10 ratchov 1007: conv = dec_new(name, &ipar);
1.57 ratchov 1008: ipar.bps = d->opar.bps;
1009: ipar.bits = d->opar.bits;
1010: ipar.sig = d->opar.sig;
1011: ipar.le = d->opar.le;
1012: ipar.msb = d->opar.msb;
1.25 ratchov 1013: aproc_setin(conv, ibuf);
1.20 ratchov 1014: ibuf = abuf_new(nblk * round, &ipar);
1.9 ratchov 1015: aproc_setout(conv, ibuf);
1.8 ratchov 1016: }
1.48 ratchov 1017: if (inch > 0 && nch >= inch * 2) {
1018: conv = join_new(name);
1019: aproc_setin(conv, ibuf);
1020: ipar.cmax = ipar.cmin + inch - 1;
1021: ibuf = abuf_new(nblk * round, &ipar);
1022: aproc_setout(conv, ibuf);
1023: }
1.57 ratchov 1024: if (!aparams_eqrate(&ipar, &d->opar)) {
1025: conv = resamp_new(name, round, d->round);
1026: ipar.rate = d->opar.rate;
1027: round = d->round;
1.5 ratchov 1028: aproc_setin(conv, ibuf);
1.20 ratchov 1029: ibuf = abuf_new(nblk * round, &ipar);
1.5 ratchov 1030: aproc_setout(conv, ibuf);
1.1 ratchov 1031: }
1.48 ratchov 1032: if (inch > 0 && nch * 2 <= inch) {
1033: conv = join_new(name);
1034: aproc_setin(conv, ibuf);
1035: ipar.cmax = ipar.cmin + inch - 1;
1036: ibuf = abuf_new(nblk * round, &ipar);
1037: aproc_setout(conv, ibuf);
1038: }
1.57 ratchov 1039: aproc_setin(d->mix, ibuf);
1.46 ratchov 1040: ibuf->r.mix.xrun = xrun;
1.31 ratchov 1041: ibuf->r.mix.maxweight = vol;
1.57 ratchov 1042: mix_setmaster(d->mix);
1.1 ratchov 1043: }
1.46 ratchov 1044: if (mode & MODE_REC) {
1.12 ratchov 1045: opar = *sopar;
1.57 ratchov 1046: rbuf = LIST_FIRST(&d->sub->ins);
1047: round = dev_roundof(d, opar.rate);
1048: nblk = (d->bufsz / d->round + 3) / 4;
1.48 ratchov 1049: nch = opar.cmax - opar.cmin + 1;
1.57 ratchov 1050: if (!aparams_eqenc(&opar, &d->ipar)) {
1.10 ratchov 1051: conv = enc_new(name, &opar);
1.57 ratchov 1052: opar.bps = d->ipar.bps;
1053: opar.bits = d->ipar.bits;
1054: opar.sig = d->ipar.sig;
1055: opar.le = d->ipar.le;
1056: opar.msb = d->ipar.msb;
1.9 ratchov 1057: aproc_setout(conv, obuf);
1.20 ratchov 1058: obuf = abuf_new(nblk * round, &opar);
1.9 ratchov 1059: aproc_setin(conv, obuf);
1.8 ratchov 1060: }
1.48 ratchov 1061: if (onch > 0 && nch >= onch * 2) {
1062: conv = join_new(name);
1063: aproc_setout(conv, obuf);
1064: opar.cmax = opar.cmin + onch - 1;
1065: obuf = abuf_new(nblk * round, &opar);
1066: aproc_setin(conv, obuf);
1067: }
1.57 ratchov 1068: if (!aparams_eqrate(&opar, &d->ipar)) {
1069: conv = resamp_new(name, d->round, round);
1070: opar.rate = d->ipar.rate;
1071: round = d->round;
1.1 ratchov 1072: aproc_setout(conv, obuf);
1.20 ratchov 1073: obuf = abuf_new(nblk * round, &opar);
1.1 ratchov 1074: aproc_setin(conv, obuf);
1075: }
1.48 ratchov 1076: if (onch > 0 && nch * 2 <= onch) {
1077: conv = join_new(name);
1078: aproc_setout(conv, obuf);
1079: opar.cmax = opar.cmin + onch - 1;
1080: obuf = abuf_new(nblk * round, &opar);
1081: aproc_setin(conv, obuf);
1082: }
1.57 ratchov 1083: aproc_setout(d->sub, obuf);
1.46 ratchov 1084: obuf->w.sub.xrun = xrun;
1085: }
1086: if (mode & MODE_MON) {
1087: opar = *sopar;
1.57 ratchov 1088: rbuf = LIST_FIRST(&d->submon->ins);
1089: round = dev_roundof(d, opar.rate);
1090: nblk = (d->bufsz / d->round + 3) / 4;
1.48 ratchov 1091: nch = opar.cmax - opar.cmin + 1;
1.57 ratchov 1092: if (!aparams_eqenc(&opar, &d->opar)) {
1.46 ratchov 1093: conv = enc_new(name, &opar);
1.57 ratchov 1094: opar.bps = d->opar.bps;
1095: opar.bits = d->opar.bits;
1096: opar.sig = d->opar.sig;
1097: opar.le = d->opar.le;
1098: opar.msb = d->opar.msb;
1.46 ratchov 1099: aproc_setout(conv, obuf);
1100: obuf = abuf_new(nblk * round, &opar);
1101: aproc_setin(conv, obuf);
1102: }
1.48 ratchov 1103: if (onch > 0 && nch >= onch * 2) {
1104: conv = join_new(name);
1105: aproc_setout(conv, obuf);
1106: opar.cmax = opar.cmin + onch - 1;
1107: obuf = abuf_new(nblk * round, &opar);
1108: aproc_setin(conv, obuf);
1109: }
1.57 ratchov 1110: if (!aparams_eqrate(&opar, &d->opar)) {
1111: conv = resamp_new(name, d->round, round);
1112: opar.rate = d->opar.rate;
1113: round = d->round;
1.46 ratchov 1114: aproc_setout(conv, obuf);
1.48 ratchov 1115: obuf = abuf_new(nblk * round, &opar);
1116: aproc_setin(conv, obuf);
1117: }
1118: if (onch > 0 && nch * 2 <= onch) {
1119: conv = join_new(name);
1120: aproc_setout(conv, obuf);
1121: opar.cmax = opar.cmin + onch - 1;
1.46 ratchov 1122: obuf = abuf_new(nblk * round, &opar);
1123: aproc_setin(conv, obuf);
1124: }
1.57 ratchov 1125: aproc_setout(d->submon, obuf);
1.46 ratchov 1126: obuf->w.sub.xrun = xrun;
1.1 ratchov 1127: }
1128:
1129: /*
1.27 ratchov 1130: * Sync play to record.
1.1 ratchov 1131: */
1.46 ratchov 1132: if ((mode & MODE_PLAY) && (mode & MODE_RECMASK)) {
1.3 ratchov 1133: ibuf->duplex = obuf;
1134: obuf->duplex = ibuf;
1.13 ratchov 1135: }
1.57 ratchov 1136: dev_sync(d, mode, ibuf, obuf);
1.14 ratchov 1137: }
1138:
1139: /*
1.27 ratchov 1140: * Change the playback volume of the given stream.
1.14 ratchov 1141: */
1142: void
1.57 ratchov 1143: dev_setvol(struct dev *d, struct abuf *ibuf, int vol)
1.14 ratchov 1144: {
1.39 ratchov 1145: #ifdef DEBUG
1146: if (debug_level >= 3) {
1147: abuf_dbg(ibuf);
1148: dbg_puts(": setting volume to ");
1149: dbg_putu(vol);
1150: dbg_puts("\n");
1151: }
1152: #endif
1.57 ratchov 1153: if (!dev_getep(d, MODE_PLAY, &ibuf, NULL)) {
1.14 ratchov 1154: return;
1.16 ratchov 1155: }
1.31 ratchov 1156: ibuf->r.mix.vol = vol;
1.13 ratchov 1157: }
1158:
1159: /*
1.27 ratchov 1160: * Clear buffers of the play and record chains so that when the device
1161: * is started, playback and record start in sync.
1.13 ratchov 1162: */
1163: void
1.57 ratchov 1164: dev_clear(struct dev *d)
1.13 ratchov 1165: {
1166: struct abuf *buf;
1167:
1.57 ratchov 1168: if (APROC_OK(d->mix)) {
1.39 ratchov 1169: #ifdef DEBUG
1.57 ratchov 1170: if (!LIST_EMPTY(&d->mix->ins)) {
1.39 ratchov 1171: dbg_puts("play end not idle, can't clear device\n");
1172: dbg_panic();
1173: }
1174: #endif
1.57 ratchov 1175: buf = LIST_FIRST(&d->mix->outs);
1.13 ratchov 1176: while (buf) {
1177: abuf_clear(buf);
1.49 ratchov 1178: buf = LIST_FIRST(&buf->rproc->outs);
1.13 ratchov 1179: }
1.57 ratchov 1180: mix_clear(d->mix);
1.13 ratchov 1181: }
1.57 ratchov 1182: if (APROC_OK(d->sub)) {
1.39 ratchov 1183: #ifdef DEBUG
1.57 ratchov 1184: if (!LIST_EMPTY(&d->sub->outs)) {
1.39 ratchov 1185: dbg_puts("record end not idle, can't clear device\n");
1186: dbg_panic();
1187: }
1188: #endif
1.57 ratchov 1189: buf = LIST_FIRST(&d->sub->ins);
1.13 ratchov 1190: while (buf) {
1191: abuf_clear(buf);
1.49 ratchov 1192: buf = LIST_FIRST(&buf->wproc->ins);
1.13 ratchov 1193: }
1.57 ratchov 1194: sub_clear(d->sub);
1.40 ratchov 1195: }
1.57 ratchov 1196: if (APROC_OK(d->submon)) {
1.46 ratchov 1197: #ifdef DEBUG
1.57 ratchov 1198: if (!LIST_EMPTY(&d->submon->outs)) {
1.46 ratchov 1199: dbg_puts("monitoring end not idle, can't clear device\n");
1200: dbg_panic();
1201: }
1202: #endif
1.57 ratchov 1203: buf = LIST_FIRST(&d->submon->ins);
1.46 ratchov 1204: while (buf) {
1205: abuf_clear(buf);
1.49 ratchov 1206: buf = LIST_FIRST(&buf->wproc->ins);
1.46 ratchov 1207: }
1.57 ratchov 1208: sub_clear(d->submon);
1209: mon_clear(d->mon);
1.1 ratchov 1210: }
1211: }