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