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