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