Annotation of src/usr.bin/aucat/dev.c, Revision 1.14
1.14 ! ratchov 1: /* $OpenBSD: dev.c,v 1.13 2008/11/09 16:26:07 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.3 ratchov 230: if (dev_mix) {
231: /*
232: * generate EOF on all inputs (but not the device), and
233: * put the mixer in ``autoquit'' state, so once buffers
234: * are drained the mixer will terminate and shutdown the
235: * write-end of the device
236: *
237: * NOTE: since file_eof() can destroy the file and
238: * reorder the file_list, we have to restart the loop
239: * after each call to file_eof()
240: */
241: restart:
242: LIST_FOREACH(f, &file_list, entry) {
243: if (f != dev_file && f->rproc) {
244: file_eof(f);
245: goto restart;
246: }
247: }
248: if (dev_mix)
249: dev_mix->u.mix.flags |= MIX_AUTOQUIT;
250:
251: /*
252: * wait play chain to terminate
253: */
254: while (dev_file->wproc != NULL) {
255: if (!file_poll())
256: break;
257: }
258: dev_mix = 0;
1.1 ratchov 259: }
1.3 ratchov 260: if (dev_sub) {
261: /*
262: * same as above, but for the record chain: generate eof
263: * on the read-end of the device and wait record buffers
264: * to desappear. We must stop the device first, because
265: * play-end will underrun (and xrun correction code will
266: * insert silence on the record-end of the device)
267: */
268: dev_stop();
269: file_eof(dev_file);
270: if (dev_sub)
271: dev_sub->u.sub.flags |= SUB_AUTOQUIT;
272: for (;;) {
273: if (!file_poll())
274: break;
275: }
276: dev_sub = NULL;
1.1 ratchov 277: }
278: }
279:
280: /*
281: * start the (paused) device. By default it's paused
282: */
283: void
284: dev_start(void)
285: {
286: if (dev_mix)
287: dev_mix->u.mix.flags |= MIX_DROP;
288: if (dev_sub)
289: dev_sub->u.sub.flags |= SUB_DROP;
1.3 ratchov 290: dev_file->ops->start(dev_file);
1.1 ratchov 291: }
292:
293: /*
294: * pause the device
295: */
296: void
297: dev_stop(void)
298: {
1.3 ratchov 299: dev_file->ops->stop(dev_file);
1.1 ratchov 300: if (dev_mix)
301: dev_mix->u.mix.flags &= ~MIX_DROP;
302: if (dev_sub)
303: dev_sub->u.sub.flags &= ~SUB_DROP;
304: }
305:
306: /*
1.14 ! ratchov 307: * find the end points connected to the mix/sub
! 308: */
! 309: int
! 310: dev_getep(struct abuf **sibuf, struct abuf **sobuf)
! 311: {
! 312: struct abuf *ibuf, *obuf;
! 313:
! 314: if (sibuf) {
! 315: ibuf = *sibuf;
! 316: for (;;) {
! 317: if (!ibuf || !ibuf->rproc) {
! 318: DPRINTF("dev_getep: reader desappeared\n");
! 319: return 0;
! 320: }
! 321: if (ibuf->rproc == dev_mix)
! 322: break;
! 323: ibuf = LIST_FIRST(&ibuf->rproc->obuflist);
! 324: }
! 325: }
! 326: if (sobuf) {
! 327: obuf = *sobuf;
! 328: for (;;) {
! 329: if (!obuf || !obuf->wproc) {
! 330: DPRINTF("dev_getep: writer desappeared\n");
! 331: return 0;
! 332: }
! 333: if (obuf->wproc == dev_sub)
! 334: break;
! 335: obuf = LIST_FIRST(&obuf->wproc->ibuflist);
! 336: }
! 337: }
! 338: return 1;
! 339: }
! 340:
! 341: /*
1.3 ratchov 342: * sync play buffer to rec buffer (for instance when one of
343: * them underruns/overruns)
1.1 ratchov 344: */
345: void
1.3 ratchov 346: dev_sync(struct abuf *ibuf, struct abuf *obuf)
1.1 ratchov 347: {
1.3 ratchov 348: struct abuf *pbuf, *rbuf;
349: int delta;
350:
351: if (!dev_mix || !dev_sub)
352: return;
353: pbuf = LIST_FIRST(&dev_mix->obuflist);
354: if (!pbuf)
355: return;
356: rbuf = LIST_FIRST(&dev_sub->ibuflist);
357: if (!rbuf)
358: return;
1.14 ! ratchov 359: if (!dev_getep(&ibuf, &obuf))
! 360: return;
1.3 ratchov 361:
362: /*
363: * calculate delta, the number of frames the play chain is ahead
364: * of the record chain. It's necessary to schedule silences (or
365: * drops) in order to start playback and record in sync.
366: */
367: delta =
368: rbuf->bpf * (pbuf->abspos + pbuf->used) -
369: pbuf->bpf * rbuf->abspos;
370: delta /= pbuf->bpf * rbuf->bpf;
371: DPRINTF("dev_sync: delta = %d, ppos = %u, pused = %u, rpos = %u\n",
372: delta, pbuf->abspos, pbuf->used, rbuf->abspos);
373:
374: if (delta > 0) {
375: /*
376: * if the play chain is ahead (most cases) drop some of
377: * the recorded input, to get both in sync
378: */
379: obuf->drop += delta * obuf->bpf;
380: abuf_ipos(obuf, -delta);
381: } else if (delta < 0) {
382: /*
383: * if record chain is ahead (should never happen,
384: * right?) then insert silence to play
385: */
386: ibuf->silence += -delta * ibuf->bpf;
387: abuf_opos(ibuf, delta);
388: } else
389: DPRINTF("dev_sync: nothing to do\n");
1.1 ratchov 390: }
391:
392: /*
393: * attach the given input and output buffers to the mixer and the
394: * multiplexer respectively. The operation is done synchronously, so
395: * both buffers enter in sync. If buffers do not match play
396: * and rec
397: */
398: void
399: dev_attach(char *name,
1.10 ratchov 400: struct abuf *ibuf, struct aparams *sipar, unsigned underrun,
401: struct abuf *obuf, struct aparams *sopar, unsigned overrun)
1.1 ratchov 402: {
403: struct abuf *pbuf = NULL, *rbuf = NULL;
1.12 ratchov 404: struct aparams ipar, opar;
1.1 ratchov 405: struct aproc *conv;
1.3 ratchov 406: unsigned nfr;
1.1 ratchov 407:
408: if (ibuf) {
1.12 ratchov 409: ipar = *sipar;
1.1 ratchov 410: pbuf = LIST_FIRST(&dev_mix->obuflist);
1.10 ratchov 411: if (!aparams_eqenc(&ipar, &dev_opar)) {
1.3 ratchov 412: nfr = (dev_bufsz + 3) / 4 + dev_round - 1;
413: nfr -= nfr % dev_round;
1.10 ratchov 414: conv = dec_new(name, &ipar);
415: ipar.bps = dev_opar.bps;
416: ipar.bits = dev_opar.bits;
417: ipar.sig = dev_opar.sig;
418: ipar.le = dev_opar.le;
419: ipar.msb = dev_opar.msb;
1.9 ratchov 420: aproc_setin(conv, ibuf);
1.10 ratchov 421: ibuf = abuf_new(nfr, &ipar);
1.9 ratchov 422: aproc_setout(conv, ibuf);
1.8 ratchov 423: }
1.10 ratchov 424: if (!aparams_subset(&ipar, &dev_opar)) {
1.7 ratchov 425: nfr = (dev_bufsz + 3) / 4 + dev_round - 1;
426: nfr -= nfr % dev_round;
1.10 ratchov 427: conv = cmap_new(name, &ipar, &dev_opar);
428: ipar.cmin = dev_opar.cmin;
429: ipar.cmax = dev_opar.cmax;
1.7 ratchov 430: aproc_setin(conv, ibuf);
1.10 ratchov 431: ibuf = abuf_new(nfr, &ipar);
1.7 ratchov 432: aproc_setout(conv, ibuf);
1.6 ratchov 433: }
1.10 ratchov 434: if (!aparams_eqrate(&ipar, &dev_opar)) {
1.5 ratchov 435: nfr = (dev_bufsz + 3) / 4 + dev_round - 1;
436: nfr -= nfr % dev_round;
1.10 ratchov 437: conv = resamp_new(name, &ipar, &dev_opar);
438: ipar.rate = dev_opar.rate;
1.5 ratchov 439: aproc_setin(conv, ibuf);
1.10 ratchov 440: ibuf = abuf_new(nfr, &ipar);
1.5 ratchov 441: aproc_setout(conv, ibuf);
1.1 ratchov 442: }
443: aproc_setin(dev_mix, ibuf);
1.3 ratchov 444: abuf_opos(ibuf, -dev_mix->u.mix.lat);
1.1 ratchov 445: ibuf->xrun = underrun;
446: }
447: if (obuf) {
1.12 ratchov 448: opar = *sopar;
1.1 ratchov 449: rbuf = LIST_FIRST(&dev_sub->ibuflist);
1.10 ratchov 450: if (!aparams_eqenc(&opar, &dev_ipar)) {
1.3 ratchov 451: nfr = (dev_bufsz + 3) / 4 + dev_round - 1;
452: nfr -= nfr % dev_round;
1.10 ratchov 453: conv = enc_new(name, &opar);
454: opar.bps = dev_ipar.bps;
455: opar.bits = dev_ipar.bits;
456: opar.sig = dev_ipar.sig;
457: opar.le = dev_ipar.le;
458: opar.msb = dev_ipar.msb;
1.9 ratchov 459: aproc_setout(conv, obuf);
1.10 ratchov 460: obuf = abuf_new(nfr, &opar);
1.9 ratchov 461: aproc_setin(conv, obuf);
1.8 ratchov 462: }
1.10 ratchov 463: if (!aparams_subset(&opar, &dev_ipar)) {
1.7 ratchov 464: nfr = (dev_bufsz + 3) / 4 + dev_round - 1;
465: nfr -= nfr % dev_round;
1.10 ratchov 466: conv = cmap_new(name, &dev_ipar, &opar);
467: opar.cmin = dev_ipar.cmin;
468: opar.cmax = dev_ipar.cmax;
1.7 ratchov 469: aproc_setout(conv, obuf);
1.10 ratchov 470: obuf = abuf_new(nfr, &opar);
1.7 ratchov 471: aproc_setin(conv, obuf);
1.6 ratchov 472: }
1.10 ratchov 473: if (!aparams_eqrate(&opar, &dev_ipar)) {
1.5 ratchov 474: nfr = (dev_bufsz + 3) / 4 + dev_round - 1;
475: nfr -= nfr % dev_round;
1.10 ratchov 476: conv = resamp_new(name, &dev_ipar, &opar);
477: opar.rate = dev_ipar.rate;
1.1 ratchov 478: aproc_setout(conv, obuf);
1.10 ratchov 479: obuf = abuf_new(nfr, &opar);
1.1 ratchov 480: aproc_setin(conv, obuf);
481: }
482: aproc_setout(dev_sub, obuf);
1.3 ratchov 483: abuf_ipos(obuf, -dev_sub->u.sub.lat);
1.1 ratchov 484: obuf->xrun = overrun;
485: }
486:
487: /*
1.3 ratchov 488: * sync play to record
1.1 ratchov 489: */
490: if (ibuf && obuf) {
1.3 ratchov 491: ibuf->duplex = obuf;
492: obuf->duplex = ibuf;
493: dev_sync(ibuf, obuf);
1.13 ratchov 494: }
1.14 ! ratchov 495: }
! 496:
! 497: /*
! 498: * change the playback volume of the fiven stream
! 499: */
! 500: void
! 501: dev_setvol(struct abuf *ibuf, int vol)
! 502: {
! 503: if (!dev_getep(&ibuf, NULL))
! 504: return;
! 505: fprintf(stderr, "vol = %d\n", vol);
! 506: ibuf->mixvol = vol;
1.13 ratchov 507: }
508:
509: /*
510: * clear buffers of the play and record chains so that when the device
511: * is started, playback and record start in sync
512: */
513: void
514: dev_clear(void)
515: {
516: struct abuf *buf;
517:
518: if (dev_mix) {
519: if (!LIST_EMPTY(&dev_mix->ibuflist)) {
520: fprintf(stderr, "dev_clear: mixer not idle\n");
521: abort();
522: }
523: buf = LIST_FIRST(&dev_mix->obuflist);
524: while (buf) {
525: abuf_clear(buf);
526: buf = LIST_FIRST(&buf->rproc->obuflist);
527: }
528: mix_clear(dev_mix);
529: }
530: if (dev_sub) {
531: if (!LIST_EMPTY(&dev_sub->obuflist)) {
532: fprintf(stderr, "dev_suspend: demux not idle\n");
533: abort();
534: }
535: buf = LIST_FIRST(&dev_sub->ibuflist);
536: while (buf) {
537: abuf_clear(buf);
538: buf = LIST_FIRST(&buf->wproc->ibuflist);
539: }
540: sub_clear(dev_sub);
1.1 ratchov 541: }
542: }